Unverified Commit 1b04382a authored by zxhlyh's avatar zxhlyh Committed by GitHub

fix: chat agent mode content copy (#2418)

parent 71e5828d
import type { FC } from 'react' import type { FC } from 'react'
import { memo } from 'react'
import type { import type {
ChatItem, ChatItem,
VisionFile, VisionFile,
} from '../../types' } from '../../types'
import { useChatContext } from '../context'
import { Markdown } from '@/app/components/base/markdown' import { Markdown } from '@/app/components/base/markdown'
import Thought from '@/app/components/app/chat/thought' import Thought from '@/app/components/app/chat/thought'
import ImageGallery from '@/app/components/base/image-gallery' import ImageGallery from '@/app/components/base/image-gallery'
import type { Emoji } from '@/app/components/tools/types'
type AgentContentProps = { type AgentContentProps = {
item: ChatItem item: ChatItem
responsing?: boolean
allToolIcons?: Record<string, string | Emoji>
} }
const AgentContent: FC<AgentContentProps> = ({ const AgentContent: FC<AgentContentProps> = ({
item, item,
}) => { responsing,
const {
allToolIcons, allToolIcons,
isResponsing, }) => {
} = useChatContext()
const { const {
annotation, annotation,
agent_thoughts, agent_thoughts,
...@@ -45,7 +46,7 @@ const AgentContent: FC<AgentContentProps> = ({ ...@@ -45,7 +46,7 @@ const AgentContent: FC<AgentContentProps> = ({
<Thought <Thought
thought={thought} thought={thought}
allToolIcons={allToolIcons || {}} allToolIcons={allToolIcons || {}}
isFinished={!!thought.observation || !isResponsing} isFinished={!!thought.observation || !responsing}
/> />
)} )}
...@@ -58,4 +59,4 @@ const AgentContent: FC<AgentContentProps> = ({ ...@@ -58,4 +59,4 @@ const AgentContent: FC<AgentContentProps> = ({
) )
} }
export default AgentContent export default memo(AgentContent)
import type { FC } from 'react' import type { FC } from 'react'
import { memo } from 'react'
import type { ChatItem } from '../../types' import type { ChatItem } from '../../types'
import { Markdown } from '@/app/components/base/markdown' import { Markdown } from '@/app/components/base/markdown'
...@@ -19,4 +20,4 @@ const BasicContent: FC<BasicContentProps> = ({ ...@@ -19,4 +20,4 @@ const BasicContent: FC<BasicContentProps> = ({
return <Markdown content={content} /> return <Markdown content={content} />
} }
export default BasicContent export default memo(BasicContent)
import type { FC } from 'react' import type {
FC,
ReactNode,
} from 'react'
import { memo } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import type { ChatItem } from '../../types' import type {
import { useChatContext } from '../context' ChatConfig,
import { useCurrentAnswerIsResponsing } from '../hooks' ChatItem,
} from '../../types'
import Operation from './operation' import Operation from './operation'
import AgentContent from './agent-content' import AgentContent from './agent-content'
import BasicContent from './basic-content' import BasicContent from './basic-content'
...@@ -12,23 +17,27 @@ import { AnswerTriangle } from '@/app/components/base/icons/src/vender/solid/gen ...@@ -12,23 +17,27 @@ import { AnswerTriangle } from '@/app/components/base/icons/src/vender/solid/gen
import LoadingAnim from '@/app/components/app/chat/loading-anim' import LoadingAnim from '@/app/components/app/chat/loading-anim'
import Citation from '@/app/components/app/chat/citation' import Citation from '@/app/components/app/chat/citation'
import { EditTitle } from '@/app/components/app/annotation/edit-annotation-modal/edit-item' import { EditTitle } from '@/app/components/app/annotation/edit-annotation-modal/edit-item'
import type { Emoji } from '@/app/components/tools/types'
type AnswerProps = { type AnswerProps = {
item: ChatItem item: ChatItem
question: string question: string
index: number index: number
config?: ChatConfig
answerIcon?: ReactNode
responsing?: boolean
allToolIcons?: Record<string, string | Emoji>
} }
const Answer: FC<AnswerProps> = ({ const Answer: FC<AnswerProps> = ({
item, item,
question, question,
index, index,
}) => {
const { t } = useTranslation()
const {
config, config,
answerIcon, answerIcon,
} = useChatContext() responsing,
const responsing = useCurrentAnswerIsResponsing(item.id) allToolIcons,
}) => {
const { t } = useTranslation()
const { const {
content, content,
citation, citation,
...@@ -83,7 +92,11 @@ const Answer: FC<AnswerProps> = ({ ...@@ -83,7 +92,11 @@ const Answer: FC<AnswerProps> = ({
} }
{ {
hasAgentThoughts && ( hasAgentThoughts && (
<AgentContent item={item} /> <AgentContent
item={item}
responsing={responsing}
allToolIcons={allToolIcons}
/>
) )
} }
{ {
...@@ -108,4 +121,4 @@ const Answer: FC<AnswerProps> = ({ ...@@ -108,4 +121,4 @@ const Answer: FC<AnswerProps> = ({
) )
} }
export default Answer export default memo(Answer)
import type { FC } from 'react' import type { FC } from 'react'
import { memo } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import type { ChatItem } from '../../types' import type { ChatItem } from '../../types'
import { formatNumber } from '@/utils/format' import { formatNumber } from '@/utils/format'
...@@ -42,4 +43,4 @@ const More: FC<MoreProps> = ({ ...@@ -42,4 +43,4 @@ const More: FC<MoreProps> = ({
) )
} }
export default More export default memo(More)
import type { FC } from 'react' import type { FC } from 'react'
import { useState } from 'react' import {
memo,
useMemo,
useState,
} from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import type { ChatItem } from '../../types' import type { ChatItem } from '../../types'
import { useCurrentAnswerIsResponsing } from '../hooks'
import { useChatContext } from '../context' import { useChatContext } from '../context'
import CopyBtn from '@/app/components/app/chat/copy-btn' import CopyBtn from '@/app/components/app/chat/copy-btn'
import { MessageFast } from '@/app/components/base/icons/src/vender/solid/communication' import { MessageFast } from '@/app/components/base/icons/src/vender/solid/communication'
...@@ -34,17 +37,24 @@ const Operation: FC<OperationProps> = ({ ...@@ -34,17 +37,24 @@ const Operation: FC<OperationProps> = ({
onFeedback, onFeedback,
} = useChatContext() } = useChatContext()
const [isShowReplyModal, setIsShowReplyModal] = useState(false) const [isShowReplyModal, setIsShowReplyModal] = useState(false)
const responsing = useCurrentAnswerIsResponsing(item.id)
const { const {
id, id,
isOpeningStatement, isOpeningStatement,
content, content: messageContent,
annotation, annotation,
feedback, feedback,
agent_thoughts,
} = item } = item
const hasAnnotation = !!annotation?.id const hasAnnotation = !!annotation?.id
const [localFeedback, setLocalFeedback] = useState(feedback) const [localFeedback, setLocalFeedback] = useState(feedback)
const content = useMemo(() => {
if (agent_thoughts?.length)
return agent_thoughts.reduce((acc, cur) => acc + cur.thought, '')
return messageContent
}, [agent_thoughts, messageContent])
const handleFeedback = async (rating: 'like' | 'dislike' | null) => { const handleFeedback = async (rating: 'like' | 'dislike' | null) => {
if (!config?.supportFeedback || !onFeedback) if (!config?.supportFeedback || !onFeedback)
return return
...@@ -56,7 +66,7 @@ const Operation: FC<OperationProps> = ({ ...@@ -56,7 +66,7 @@ const Operation: FC<OperationProps> = ({
return ( return (
<div className='absolute top-[-14px] right-[-14px] flex justify-end gap-1'> <div className='absolute top-[-14px] right-[-14px] flex justify-end gap-1'>
{ {
!isOpeningStatement && !responsing && ( !isOpeningStatement && (
<CopyBtn <CopyBtn
value={content} value={content}
className='hidden group-hover:block' className='hidden group-hover:block'
...@@ -159,4 +169,4 @@ const Operation: FC<OperationProps> = ({ ...@@ -159,4 +169,4 @@ const Operation: FC<OperationProps> = ({
) )
} }
export default Operation export default memo(Operation)
import type { FC } from 'react' import type { FC } from 'react'
import { memo } from 'react'
import type { ChatItem } from '../../types' import type { ChatItem } from '../../types'
import { useChatContext } from '../context' import { useChatContext } from '../context'
...@@ -32,4 +33,4 @@ const SuggestedQuestions: FC<SuggestedQuestionsProps> = ({ ...@@ -32,4 +33,4 @@ const SuggestedQuestions: FC<SuggestedQuestionsProps> = ({
) )
} }
export default SuggestedQuestions export default memo(SuggestedQuestions)
import type { FC } from 'react' import type { FC } from 'react'
import { import {
memo,
useRef, useRef,
useState, useState,
} from 'react' } from 'react'
...@@ -126,9 +127,10 @@ const ChatInput: FC<ChatInputProps> = ({ ...@@ -126,9 +127,10 @@ const ChatInput: FC<ChatInputProps> = ({
) )
return ( return (
<div className='relative'>
<div <div
className={` className={`
relative p-[5.5px] max-h-[150px] bg-white border-[1.5px] border-gray-200 rounded-xl overflow-y-auto p-[5.5px] max-h-[150px] bg-white border-[1.5px] border-gray-200 rounded-xl overflow-y-auto
${isDragActive && 'border-primary-600'} ${isDragActive && 'border-primary-600'}
`} `}
> >
...@@ -219,7 +221,8 @@ const ChatInput: FC<ChatInputProps> = ({ ...@@ -219,7 +221,8 @@ const ChatInput: FC<ChatInputProps> = ({
) )
} }
</div> </div>
</div>
) )
} }
export default ChatInput export default memo(ChatInput)
...@@ -14,7 +14,6 @@ import type { ...@@ -14,7 +14,6 @@ import type {
PromptVariable, PromptVariable,
VisionFile, VisionFile,
} from '../types' } from '../types'
import { useChatContext } from './context'
import { TransferMethod } from '@/types/app' import { TransferMethod } from '@/types/app'
import { useToastContext } from '@/app/components/base/toast' import { useToastContext } from '@/app/components/base/toast'
import { ssePost } from '@/service/base' import { ssePost } from '@/service/base'
...@@ -507,14 +506,3 @@ export const useChat = ( ...@@ -507,14 +506,3 @@ export const useChat = (
handleAnnotationRemoved, handleAnnotationRemoved,
} }
} }
export const useCurrentAnswerIsResponsing = (answerId: string) => {
const {
isResponsing,
chatList,
} = useChatContext()
const isLast = answerId === chatList[chatList.length - 1]?.id
return isLast && isResponsing
}
...@@ -140,12 +140,17 @@ const Chat: FC<ChatProps> = ({ ...@@ -140,12 +140,17 @@ const Chat: FC<ChatProps> = ({
{ {
chatList.map((item, index) => { chatList.map((item, index) => {
if (item.isAnswer) { if (item.isAnswer) {
const isLast = item.id === chatList[chatList.length - 1]?.id
return ( return (
<Answer <Answer
key={item.id} key={item.id}
item={item} item={item}
question={chatList[index - 1]?.content} question={chatList[index - 1]?.content}
index={index} index={index}
config={config}
answerIcon={answerIcon}
responsing={isLast && isResponsing}
allToolIcons={allToolIcons}
/> />
) )
} }
...@@ -153,6 +158,9 @@ const Chat: FC<ChatProps> = ({ ...@@ -153,6 +158,9 @@ const Chat: FC<ChatProps> = ({
<Question <Question
key={item.id} key={item.id}
item={item} item={item}
showPromptLog={showPromptLog}
questionIcon={questionIcon}
isResponsing={isResponsing}
/> />
) )
}) })
......
import type { FC } from 'react' import type {
import { useRef } from 'react' FC,
ReactNode,
} from 'react'
import {
memo,
useRef,
} from 'react'
import type { ChatItem } from '../types' import type { ChatItem } from '../types'
import { useChatContext } from './context'
import { QuestionTriangle } from '@/app/components/base/icons/src/vender/solid/general' import { QuestionTriangle } from '@/app/components/base/icons/src/vender/solid/general'
import { User } from '@/app/components/base/icons/src/public/avatar' import { User } from '@/app/components/base/icons/src/public/avatar'
import Log from '@/app/components/app/chat/log' import Log from '@/app/components/app/chat/log'
...@@ -10,16 +15,17 @@ import ImageGallery from '@/app/components/base/image-gallery' ...@@ -10,16 +15,17 @@ import ImageGallery from '@/app/components/base/image-gallery'
type QuestionProps = { type QuestionProps = {
item: ChatItem item: ChatItem
showPromptLog?: boolean
questionIcon?: ReactNode
isResponsing?: boolean
} }
const Question: FC<QuestionProps> = ({ const Question: FC<QuestionProps> = ({
item, item,
}) => {
const ref = useRef(null)
const {
showPromptLog, showPromptLog,
isResponsing, isResponsing,
questionIcon, questionIcon,
} = useChatContext() }) => {
const ref = useRef(null)
const { const {
content, content,
message_files, message_files,
...@@ -59,4 +65,4 @@ const Question: FC<QuestionProps> = ({ ...@@ -59,4 +65,4 @@ const Question: FC<QuestionProps> = ({
) )
} }
export default Question export default memo(Question)
import type { FC } from 'react' import type { FC } from 'react'
import { memo } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import type { OnSend } from '../types' import type { OnSend } from '../types'
import { Star04 } from '@/app/components/base/icons/src/vender/solid/shapes' import { Star04 } from '@/app/components/base/icons/src/vender/solid/shapes'
...@@ -51,4 +52,4 @@ const TryToAsk: FC<TryToAskProps> = ({ ...@@ -51,4 +52,4 @@ const TryToAsk: FC<TryToAskProps> = ({
) )
} }
export default TryToAsk export default memo(TryToAsk)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment