mirror of
https://github.com/langgenius/dify.git
synced 2024-11-16 11:42:29 +08:00
fix: chat agent mode content copy (#2418)
This commit is contained in:
parent
71e5828d41
commit
1b04382a9b
|
@ -1,23 +1,24 @@
|
|||
import type { FC } from 'react'
|
||||
import { memo } from 'react'
|
||||
import type {
|
||||
ChatItem,
|
||||
VisionFile,
|
||||
} from '../../types'
|
||||
import { useChatContext } from '../context'
|
||||
import { Markdown } from '@/app/components/base/markdown'
|
||||
import Thought from '@/app/components/app/chat/thought'
|
||||
import ImageGallery from '@/app/components/base/image-gallery'
|
||||
import type { Emoji } from '@/app/components/tools/types'
|
||||
|
||||
type AgentContentProps = {
|
||||
item: ChatItem
|
||||
responsing?: boolean
|
||||
allToolIcons?: Record<string, string | Emoji>
|
||||
}
|
||||
const AgentContent: FC<AgentContentProps> = ({
|
||||
item,
|
||||
}) => {
|
||||
const {
|
||||
responsing,
|
||||
allToolIcons,
|
||||
isResponsing,
|
||||
} = useChatContext()
|
||||
}) => {
|
||||
const {
|
||||
annotation,
|
||||
agent_thoughts,
|
||||
|
@ -45,7 +46,7 @@ const AgentContent: FC<AgentContentProps> = ({
|
|||
<Thought
|
||||
thought={thought}
|
||||
allToolIcons={allToolIcons || {}}
|
||||
isFinished={!!thought.observation || !isResponsing}
|
||||
isFinished={!!thought.observation || !responsing}
|
||||
/>
|
||||
)}
|
||||
|
||||
|
@ -58,4 +59,4 @@ const AgentContent: FC<AgentContentProps> = ({
|
|||
)
|
||||
}
|
||||
|
||||
export default AgentContent
|
||||
export default memo(AgentContent)
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import type { FC } from 'react'
|
||||
import { memo } from 'react'
|
||||
import type { ChatItem } from '../../types'
|
||||
import { Markdown } from '@/app/components/base/markdown'
|
||||
|
||||
|
@ -19,4 +20,4 @@ const BasicContent: FC<BasicContentProps> = ({
|
|||
return <Markdown content={content} />
|
||||
}
|
||||
|
||||
export default BasicContent
|
||||
export default memo(BasicContent)
|
||||
|
|
|
@ -1,8 +1,13 @@
|
|||
import type { FC } from 'react'
|
||||
import type {
|
||||
FC,
|
||||
ReactNode,
|
||||
} from 'react'
|
||||
import { memo } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import type { ChatItem } from '../../types'
|
||||
import { useChatContext } from '../context'
|
||||
import { useCurrentAnswerIsResponsing } from '../hooks'
|
||||
import type {
|
||||
ChatConfig,
|
||||
ChatItem,
|
||||
} from '../../types'
|
||||
import Operation from './operation'
|
||||
import AgentContent from './agent-content'
|
||||
import BasicContent from './basic-content'
|
||||
|
@ -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 Citation from '@/app/components/app/chat/citation'
|
||||
import { EditTitle } from '@/app/components/app/annotation/edit-annotation-modal/edit-item'
|
||||
import type { Emoji } from '@/app/components/tools/types'
|
||||
|
||||
type AnswerProps = {
|
||||
item: ChatItem
|
||||
question: string
|
||||
index: number
|
||||
config?: ChatConfig
|
||||
answerIcon?: ReactNode
|
||||
responsing?: boolean
|
||||
allToolIcons?: Record<string, string | Emoji>
|
||||
}
|
||||
const Answer: FC<AnswerProps> = ({
|
||||
item,
|
||||
question,
|
||||
index,
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
const {
|
||||
config,
|
||||
answerIcon,
|
||||
} = useChatContext()
|
||||
const responsing = useCurrentAnswerIsResponsing(item.id)
|
||||
responsing,
|
||||
allToolIcons,
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
const {
|
||||
content,
|
||||
citation,
|
||||
|
@ -83,7 +92,11 @@ const Answer: FC<AnswerProps> = ({
|
|||
}
|
||||
{
|
||||
hasAgentThoughts && (
|
||||
<AgentContent item={item} />
|
||||
<AgentContent
|
||||
item={item}
|
||||
responsing={responsing}
|
||||
allToolIcons={allToolIcons}
|
||||
/>
|
||||
)
|
||||
}
|
||||
{
|
||||
|
@ -108,4 +121,4 @@ const Answer: FC<AnswerProps> = ({
|
|||
)
|
||||
}
|
||||
|
||||
export default Answer
|
||||
export default memo(Answer)
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import type { FC } from 'react'
|
||||
import { memo } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import type { ChatItem } from '../../types'
|
||||
import { formatNumber } from '@/utils/format'
|
||||
|
@ -42,4 +43,4 @@ const More: FC<MoreProps> = ({
|
|||
)
|
||||
}
|
||||
|
||||
export default More
|
||||
export default memo(More)
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
import type { FC } from 'react'
|
||||
import { useState } from 'react'
|
||||
import {
|
||||
memo,
|
||||
useMemo,
|
||||
useState,
|
||||
} from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import type { ChatItem } from '../../types'
|
||||
import { useCurrentAnswerIsResponsing } from '../hooks'
|
||||
import { useChatContext } from '../context'
|
||||
import CopyBtn from '@/app/components/app/chat/copy-btn'
|
||||
import { MessageFast } from '@/app/components/base/icons/src/vender/solid/communication'
|
||||
|
@ -34,17 +37,24 @@ const Operation: FC<OperationProps> = ({
|
|||
onFeedback,
|
||||
} = useChatContext()
|
||||
const [isShowReplyModal, setIsShowReplyModal] = useState(false)
|
||||
const responsing = useCurrentAnswerIsResponsing(item.id)
|
||||
const {
|
||||
id,
|
||||
isOpeningStatement,
|
||||
content,
|
||||
content: messageContent,
|
||||
annotation,
|
||||
feedback,
|
||||
agent_thoughts,
|
||||
} = item
|
||||
const hasAnnotation = !!annotation?.id
|
||||
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) => {
|
||||
if (!config?.supportFeedback || !onFeedback)
|
||||
return
|
||||
|
@ -56,7 +66,7 @@ const Operation: FC<OperationProps> = ({
|
|||
return (
|
||||
<div className='absolute top-[-14px] right-[-14px] flex justify-end gap-1'>
|
||||
{
|
||||
!isOpeningStatement && !responsing && (
|
||||
!isOpeningStatement && (
|
||||
<CopyBtn
|
||||
value={content}
|
||||
className='hidden group-hover:block'
|
||||
|
@ -159,4 +169,4 @@ const Operation: FC<OperationProps> = ({
|
|||
)
|
||||
}
|
||||
|
||||
export default Operation
|
||||
export default memo(Operation)
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import type { FC } from 'react'
|
||||
import { memo } from 'react'
|
||||
import type { ChatItem } from '../../types'
|
||||
import { useChatContext } from '../context'
|
||||
|
||||
|
@ -32,4 +33,4 @@ const SuggestedQuestions: FC<SuggestedQuestionsProps> = ({
|
|||
)
|
||||
}
|
||||
|
||||
export default SuggestedQuestions
|
||||
export default memo(SuggestedQuestions)
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import type { FC } from 'react'
|
||||
import {
|
||||
memo,
|
||||
useRef,
|
||||
useState,
|
||||
} from 'react'
|
||||
|
@ -126,9 +127,10 @@ const ChatInput: FC<ChatInputProps> = ({
|
|||
)
|
||||
|
||||
return (
|
||||
<div className='relative'>
|
||||
<div
|
||||
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'}
|
||||
`}
|
||||
>
|
||||
|
@ -219,7 +221,8 @@ const ChatInput: FC<ChatInputProps> = ({
|
|||
)
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default ChatInput
|
||||
export default memo(ChatInput)
|
||||
|
|
|
@ -14,7 +14,6 @@ import type {
|
|||
PromptVariable,
|
||||
VisionFile,
|
||||
} from '../types'
|
||||
import { useChatContext } from './context'
|
||||
import { TransferMethod } from '@/types/app'
|
||||
import { useToastContext } from '@/app/components/base/toast'
|
||||
import { ssePost } from '@/service/base'
|
||||
|
@ -507,14 +506,3 @@ export const useChat = (
|
|||
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> = ({
|
|||
{
|
||||
chatList.map((item, index) => {
|
||||
if (item.isAnswer) {
|
||||
const isLast = item.id === chatList[chatList.length - 1]?.id
|
||||
return (
|
||||
<Answer
|
||||
key={item.id}
|
||||
item={item}
|
||||
question={chatList[index - 1]?.content}
|
||||
index={index}
|
||||
config={config}
|
||||
answerIcon={answerIcon}
|
||||
responsing={isLast && isResponsing}
|
||||
allToolIcons={allToolIcons}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
@ -153,6 +158,9 @@ const Chat: FC<ChatProps> = ({
|
|||
<Question
|
||||
key={item.id}
|
||||
item={item}
|
||||
showPromptLog={showPromptLog}
|
||||
questionIcon={questionIcon}
|
||||
isResponsing={isResponsing}
|
||||
/>
|
||||
)
|
||||
})
|
||||
|
|
|
@ -1,7 +1,12 @@
|
|||
import type { FC } from 'react'
|
||||
import { useRef } from 'react'
|
||||
import type {
|
||||
FC,
|
||||
ReactNode,
|
||||
} from 'react'
|
||||
import {
|
||||
memo,
|
||||
useRef,
|
||||
} from 'react'
|
||||
import type { ChatItem } from '../types'
|
||||
import { useChatContext } from './context'
|
||||
import { QuestionTriangle } from '@/app/components/base/icons/src/vender/solid/general'
|
||||
import { User } from '@/app/components/base/icons/src/public/avatar'
|
||||
import Log from '@/app/components/app/chat/log'
|
||||
|
@ -10,16 +15,17 @@ import ImageGallery from '@/app/components/base/image-gallery'
|
|||
|
||||
type QuestionProps = {
|
||||
item: ChatItem
|
||||
showPromptLog?: boolean
|
||||
questionIcon?: ReactNode
|
||||
isResponsing?: boolean
|
||||
}
|
||||
const Question: FC<QuestionProps> = ({
|
||||
item,
|
||||
}) => {
|
||||
const ref = useRef(null)
|
||||
const {
|
||||
showPromptLog,
|
||||
isResponsing,
|
||||
questionIcon,
|
||||
} = useChatContext()
|
||||
}) => {
|
||||
const ref = useRef(null)
|
||||
const {
|
||||
content,
|
||||
message_files,
|
||||
|
@ -59,4 +65,4 @@ const Question: FC<QuestionProps> = ({
|
|||
)
|
||||
}
|
||||
|
||||
export default Question
|
||||
export default memo(Question)
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import type { FC } from 'react'
|
||||
import { memo } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import type { OnSend } from '../types'
|
||||
import { Star04 } from '@/app/components/base/icons/src/vender/solid/shapes'
|
||||
|
@ -51,4 +52,4 @@ const TryToAsk: FC<TryToAskProps> = ({
|
|||
)
|
||||
}
|
||||
|
||||
export default TryToAsk
|
||||
export default memo(TryToAsk)
|
||||
|
|
Loading…
Reference in New Issue
Block a user