From 8294e97113484a32e05a693a72e1d390c28d607c Mon Sep 17 00:00:00 2001 From: KVOJJJin Date: Mon, 24 Jun 2024 12:29:14 +0800 Subject: [PATCH] Chore: chat log refactor (#5523) --- web/app/(shareLayout)/chat/[token]/page.tsx | 5 +- .../(shareLayout)/chatbot/[token]/page.tsx | 4 +- .../(shareLayout)/completion/[token]/page.tsx | 7 +- .../(shareLayout)/workflow/[token]/page.tsx | 6 +- web/app/components/app/chat/answer/index.tsx | 428 -------- .../app/chat/icon-component/index.tsx | 43 - web/app/components/app/chat/icons/answer.svg | 3 - .../app/chat/icons/default-avatar.jpg | Bin 2183 -> 0 bytes web/app/components/app/chat/icons/edit.svg | 3 - .../components/app/chat/icons/question.svg | 3 - web/app/components/app/chat/icons/robot.svg | 10 - .../components/app/chat/icons/send-active.svg | 3 - web/app/components/app/chat/icons/send.svg | 3 - web/app/components/app/chat/icons/typing.svg | 19 - web/app/components/app/chat/icons/user.svg | 10 - web/app/components/app/chat/index.tsx | 455 --------- .../components/app/chat/more-info/index.tsx | 23 - .../components/app/chat/operation/index.tsx | 14 - .../components/app/chat/question/index.tsx | 52 - web/app/components/app/chat/style.module.css | 136 --- .../app/chat/thought/style.module.css | 7 - .../debug-with-multiple-model/chat-item.tsx | 4 +- .../debug/debug-with-single-model/index.tsx | 4 +- web/app/components/app/log/list.tsx | 157 ++- .../app/overview/embedded/index.tsx | 2 +- web/app/components/app/store.ts | 2 +- .../app/text-generate/item/index.tsx | 2 +- .../base/agent-log-modal/detail.tsx | 2 +- .../components/base/agent-log-modal/index.tsx | 2 +- .../chat-with-history/config-panel/index.tsx | 4 +- .../chat/chat-with-history/sidebar/index.tsx | 2 +- .../sidebar/rename-modal.tsx} | 0 .../base/chat/chat/answer/agent-content.tsx | 2 +- .../base/chat/chat/answer/index.tsx | 4 +- .../base/chat/chat/answer/operation.tsx | 4 +- .../chat}/chat/citation/index.tsx | 0 .../chat}/chat/citation/popup.tsx | 0 .../chat}/chat/citation/progress-tooltip.tsx | 0 .../chat}/chat/citation/tooltip.tsx | 0 web/app/components/base/chat/chat/index.tsx | 3 + .../chat}/chat/loading-anim/index.tsx | 0 .../chat}/chat/loading-anim/style.module.css | 0 .../{app => base/chat}/chat/log/index.tsx | 2 +- .../{app => base/chat}/chat/thought/index.tsx | 2 +- .../{app => base/chat}/chat/thought/panel.tsx | 0 .../{app => base/chat}/chat/thought/tool.tsx | 0 .../{app => base/chat}/chat/type.ts | 2 +- .../embedded-chatbot/config-panel/index.tsx | 4 +- .../base/chat/embedded-chatbot/header.tsx | 9 +- web/app/components/base/chat/types.ts | 2 +- .../{app/chat => base}/copy-btn/index.tsx | 0 .../chat => base}/copy-btn/style.module.css | 0 web/app/components/base/markdown.tsx | 6 +- .../{app/chat => base}/mermaid/index.tsx | 0 .../base/message-log-modal/index.tsx | 2 +- .../base/prompt-log-modal/index.tsx | 2 +- .../{app/chat => base}/svg/index.tsx | 0 .../{app/chat => base}/svg/style.module.css | 0 .../share/chat/config-scence/index.tsx | 13 - .../share/chat/hooks/use-conversation.ts | 73 -- web/app/components/share/chat/index.tsx | 953 ------------------ .../share/chat/sidebar/app-info/index.tsx | 28 - .../share/chat/sidebar/card.module.css | 3 - .../components/share/chat/sidebar/card.tsx | 19 - .../components/share/chat/sidebar/index.tsx | 167 --- .../share/chat/sidebar/list/index.tsx | 143 --- .../share/chat/sidebar/list/item.tsx | 77 -- .../share/chat/value-panel/index.tsx | 77 -- .../share/chat/value-panel/style.module.css | 3 - .../components/share/chat/welcome/index.tsx | 388 ------- .../share/chat/welcome/massive-component.tsx | 74 -- .../share/chat/welcome/style.module.css | 22 - .../share/chatbot/config-scence/index.tsx | 13 - .../share/chatbot/hooks/use-conversation.ts | 72 -- web/app/components/share/chatbot/index.tsx | 824 --------------- .../share/chatbot/sidebar/app-info/index.tsx | 28 - .../share/chatbot/sidebar/card.module.css | 3 - .../components/share/chatbot/sidebar/card.tsx | 19 - .../share/chatbot/sidebar/index.tsx | 152 --- .../share/chatbot/sidebar/list/index.tsx | 115 --- .../chatbot/sidebar/list/style.module.css | 7 - .../share/chatbot/value-panel/index.tsx | 77 -- .../chatbot/value-panel/style.module.css | 3 - .../share/chatbot/welcome/index.tsx | 389 ------- .../chatbot/welcome/massive-component.tsx | 75 -- .../share/chatbot/welcome/style.module.css | 22 - web/app/components/share/header.tsx | 88 -- .../share/text-generation/result/content.tsx | 2 +- .../share/text-generation/result/header.tsx | 2 +- .../share/text-generation/result/index.tsx | 2 +- web/app/components/tools/utils/index.ts | 2 +- .../workflow/panel/chat-record/index.tsx | 10 +- .../components/workflow/run/output-panel.tsx | 2 +- .../components/workflow/run/result-text.tsx | 2 +- web/service/base.ts | 2 +- web/service/debug.ts | 2 +- web/service/share.ts | 2 +- 97 files changed, 165 insertions(+), 5249 deletions(-) delete mode 100644 web/app/components/app/chat/answer/index.tsx delete mode 100644 web/app/components/app/chat/icon-component/index.tsx delete mode 100644 web/app/components/app/chat/icons/answer.svg delete mode 100644 web/app/components/app/chat/icons/default-avatar.jpg delete mode 100644 web/app/components/app/chat/icons/edit.svg delete mode 100644 web/app/components/app/chat/icons/question.svg delete mode 100644 web/app/components/app/chat/icons/robot.svg delete mode 100644 web/app/components/app/chat/icons/send-active.svg delete mode 100644 web/app/components/app/chat/icons/send.svg delete mode 100644 web/app/components/app/chat/icons/typing.svg delete mode 100644 web/app/components/app/chat/icons/user.svg delete mode 100644 web/app/components/app/chat/index.tsx delete mode 100644 web/app/components/app/chat/more-info/index.tsx delete mode 100644 web/app/components/app/chat/operation/index.tsx delete mode 100644 web/app/components/app/chat/question/index.tsx delete mode 100644 web/app/components/app/chat/style.module.css delete mode 100644 web/app/components/app/chat/thought/style.module.css rename web/app/components/{share/chat/sidebar/rename-modal/index.tsx => base/chat/chat-with-history/sidebar/rename-modal.tsx} (100%) rename web/app/components/{app => base/chat}/chat/citation/index.tsx (100%) rename web/app/components/{app => base/chat}/chat/citation/popup.tsx (100%) rename web/app/components/{app => base/chat}/chat/citation/progress-tooltip.tsx (100%) rename web/app/components/{app => base/chat}/chat/citation/tooltip.tsx (100%) rename web/app/components/{app => base/chat}/chat/loading-anim/index.tsx (100%) rename web/app/components/{app => base/chat}/chat/loading-anim/style.module.css (100%) rename web/app/components/{app => base/chat}/chat/log/index.tsx (95%) rename web/app/components/{app => base/chat}/chat/thought/index.tsx (96%) rename web/app/components/{app => base/chat}/chat/thought/panel.tsx (100%) rename web/app/components/{app => base/chat}/chat/thought/tool.tsx (100%) rename web/app/components/{app => base/chat}/chat/type.ts (95%) rename web/app/components/{app/chat => base}/copy-btn/index.tsx (100%) rename web/app/components/{app/chat => base}/copy-btn/style.module.css (100%) rename web/app/components/{app/chat => base}/mermaid/index.tsx (100%) rename web/app/components/{app/chat => base}/svg/index.tsx (100%) rename web/app/components/{app/chat => base}/svg/style.module.css (100%) delete mode 100644 web/app/components/share/chat/config-scence/index.tsx delete mode 100644 web/app/components/share/chat/hooks/use-conversation.ts delete mode 100644 web/app/components/share/chat/index.tsx delete mode 100644 web/app/components/share/chat/sidebar/app-info/index.tsx delete mode 100644 web/app/components/share/chat/sidebar/card.module.css delete mode 100644 web/app/components/share/chat/sidebar/card.tsx delete mode 100644 web/app/components/share/chat/sidebar/index.tsx delete mode 100644 web/app/components/share/chat/sidebar/list/index.tsx delete mode 100644 web/app/components/share/chat/sidebar/list/item.tsx delete mode 100644 web/app/components/share/chat/value-panel/index.tsx delete mode 100644 web/app/components/share/chat/value-panel/style.module.css delete mode 100644 web/app/components/share/chat/welcome/index.tsx delete mode 100644 web/app/components/share/chat/welcome/massive-component.tsx delete mode 100644 web/app/components/share/chat/welcome/style.module.css delete mode 100644 web/app/components/share/chatbot/config-scence/index.tsx delete mode 100644 web/app/components/share/chatbot/hooks/use-conversation.ts delete mode 100644 web/app/components/share/chatbot/index.tsx delete mode 100644 web/app/components/share/chatbot/sidebar/app-info/index.tsx delete mode 100644 web/app/components/share/chatbot/sidebar/card.module.css delete mode 100644 web/app/components/share/chatbot/sidebar/card.tsx delete mode 100644 web/app/components/share/chatbot/sidebar/index.tsx delete mode 100644 web/app/components/share/chatbot/sidebar/list/index.tsx delete mode 100644 web/app/components/share/chatbot/sidebar/list/style.module.css delete mode 100644 web/app/components/share/chatbot/value-panel/index.tsx delete mode 100644 web/app/components/share/chatbot/value-panel/style.module.css delete mode 100644 web/app/components/share/chatbot/welcome/index.tsx delete mode 100644 web/app/components/share/chatbot/welcome/massive-component.tsx delete mode 100644 web/app/components/share/chatbot/welcome/style.module.css delete mode 100644 web/app/components/share/header.tsx diff --git a/web/app/(shareLayout)/chat/[token]/page.tsx b/web/app/(shareLayout)/chat/[token]/page.tsx index 56b2e0da7d..640c40378f 100644 --- a/web/app/(shareLayout)/chat/[token]/page.tsx +++ b/web/app/(shareLayout)/chat/[token]/page.tsx @@ -1,11 +1,8 @@ 'use client' -import type { FC } from 'react' import React from 'react' - -import type { IMainProps } from '@/app/components/share/chat' import ChatWithHistoryWrap from '@/app/components/base/chat/chat-with-history' -const Chat: FC = () => { +const Chat = () => { return ( ) diff --git a/web/app/(shareLayout)/chatbot/[token]/page.tsx b/web/app/(shareLayout)/chatbot/[token]/page.tsx index b78680c503..1db5c7e458 100644 --- a/web/app/(shareLayout)/chatbot/[token]/page.tsx +++ b/web/app/(shareLayout)/chatbot/[token]/page.tsx @@ -1,14 +1,12 @@ 'use client' -import type { FC } from 'react' import React, { useEffect } from 'react' import cn from 'classnames' -import type { IMainProps } from '@/app/components/share/chat' import EmbeddedChatbot from '@/app/components/base/chat/embedded-chatbot' import Loading from '@/app/components/base/loading' import { fetchSystemFeatures } from '@/service/share' import LogoSite from '@/app/components/base/logo/logo-site' -const Chatbot: FC = () => { +const Chatbot = () => { const [isSSOEnforced, setIsSSOEnforced] = React.useState(true) const [loading, setLoading] = React.useState(true) diff --git a/web/app/(shareLayout)/completion/[token]/page.tsx b/web/app/(shareLayout)/completion/[token]/page.tsx index 28bbfa68da..e8bc9d79f5 100644 --- a/web/app/(shareLayout)/completion/[token]/page.tsx +++ b/web/app/(shareLayout)/completion/[token]/page.tsx @@ -1,13 +1,10 @@ -import type { FC } from 'react' import React from 'react' - -import type { IMainProps } from '@/app/components/share/chat' import Main from '@/app/components/share/text-generation' -const TextGeneration: FC = () => { +const Completion = () => { return (
) } -export default React.memo(TextGeneration) +export default React.memo(Completion) diff --git a/web/app/(shareLayout)/workflow/[token]/page.tsx b/web/app/(shareLayout)/workflow/[token]/page.tsx index c1d7fa13a5..e93bc8c1af 100644 --- a/web/app/(shareLayout)/workflow/[token]/page.tsx +++ b/web/app/(shareLayout)/workflow/[token]/page.tsx @@ -1,13 +1,11 @@ -import type { FC } from 'react' import React from 'react' -import type { IMainProps } from '@/app/components/share/text-generation' import Main from '@/app/components/share/text-generation' -const TextGeneration: FC = () => { +const Workflow = () => { return (
) } -export default React.memo(TextGeneration) +export default React.memo(Workflow) diff --git a/web/app/components/app/chat/answer/index.tsx b/web/app/components/app/chat/answer/index.tsx deleted file mode 100644 index 1ba033911a..0000000000 --- a/web/app/components/app/chat/answer/index.tsx +++ /dev/null @@ -1,428 +0,0 @@ -'use client' -import type { FC, ReactNode } from 'react' -import React, { useEffect, useMemo, useRef, useState } from 'react' -import { useTranslation } from 'react-i18next' -import { UserCircleIcon } from '@heroicons/react/24/solid' -import cn from 'classnames' -import type { CitationItem, DisplayScene, FeedbackFunc, Feedbacktype, IChatItem } from '../type' -import OperationBtn from '../operation' -import LoadingAnim from '../loading-anim' -import { RatingIcon } from '../icon-component' -import s from '../style.module.css' -import MoreInfo from '../more-info' -import CopyBtn from '../copy-btn' -import Thought from '../thought' -import Citation from '../citation' -import AudioBtn from '@/app/components/base/audio-btn' -import { randomString } from '@/utils' -import type { MessageRating } from '@/models/log' -import Tooltip from '@/app/components/base/tooltip' -import { Markdown } from '@/app/components/base/markdown' -import type { DataSet } from '@/models/datasets' -import AnnotationCtrlBtn from '@/app/components/app/configuration/toolbox/annotation/annotation-ctrl-btn' -import EditReplyModal from '@/app/components/app/annotation/edit-annotation-modal' -import { EditTitle } from '@/app/components/app/annotation/edit-annotation-modal/edit-item' -import { MessageFast } from '@/app/components/base/icons/src/vender/solid/communication' -import type { Emoji } from '@/app/components/tools/types' -import type { VisionFile } from '@/types/app' -import ImageGallery from '@/app/components/base/image-gallery' -import Log from '@/app/components/app/chat/log' - -const IconWrapper: FC<{ children: React.ReactNode | string }> = ({ children }) => { - return
- {children} -
-} -export type IAnswerProps = { - item: IChatItem - index: number - feedbackDisabled: boolean - isHideFeedbackEdit: boolean - onQueryChange: (query: string) => void - onFeedback?: FeedbackFunc - displayScene: DisplayScene - isResponding?: boolean - answerIcon?: ReactNode - citation?: CitationItem[] - dataSets?: DataSet[] - isShowCitation?: boolean - isShowCitationHitInfo?: boolean - isShowTextToSpeech?: boolean - // Annotation props - supportAnnotation?: boolean - appId?: string - question: string - onAnnotationEdited?: (question: string, answer: string, index: number) => void - onAnnotationAdded?: (annotationId: string, authorName: string, question: string, answer: string, index: number) => void - onAnnotationRemoved?: (index: number) => void - allToolIcons?: Record - isShowPromptLog?: boolean -} -// The component needs to maintain its own state to control whether to display input component -const Answer: FC = ({ - item, - index, - onQueryChange, - feedbackDisabled = false, - isHideFeedbackEdit = false, - onFeedback, - displayScene = 'web', - isResponding, - answerIcon, - citation, - isShowCitation, - isShowCitationHitInfo = false, - isShowTextToSpeech, - supportAnnotation, - appId, - question, - onAnnotationEdited, - onAnnotationAdded, - onAnnotationRemoved, - allToolIcons, - isShowPromptLog, -}) => { - const { id, content, more, feedback, adminFeedback, annotation, agent_thoughts } = item - const isAgentMode = !!agent_thoughts && agent_thoughts.length > 0 - const hasAnnotation = useMemo(() => !!annotation, [annotation]) - // const [annotation, setAnnotation] = useState(initAnnotation) - // const [inputValue, setInputValue] = useState(initAnnotation?.content ?? '') - const [localAdminFeedback, setLocalAdminFeedback] = useState(adminFeedback) - // const { userProfile } = useContext(AppContext) - const { t } = useTranslation() - - const [isShowReplyModal, setIsShowReplyModal] = useState(false) - - /** - * Render feedback results (distinguish between users and administrators) - * User reviews cannot be cancelled in Console - * @param rating feedback result - * @param isUserFeedback Whether it is user's feedback - * @param isWebScene Whether it is web scene - * @returns comp - */ - const renderFeedbackRating = (rating: MessageRating | undefined, isUserFeedback = true, isWebScene = true) => { - if (!rating) - return null - - const isLike = rating === 'like' - const ratingIconClassname = isLike ? 'text-primary-600 bg-primary-100 hover:bg-primary-200' : 'text-red-600 bg-red-100 hover:bg-red-200' - const UserSymbol = - // The tooltip is always displayed, but the content is different for different scenarios. - return ( - -
{ - const res = await onFeedback?.(id, { rating: null }) - if (res && !isWebScene) - setLocalAdminFeedback({ rating: null }) - }, - } - : {})} - > -
- -
- {!isWebScene && isUserFeedback && UserSymbol} -
-
- ) - } - - /** - * Different scenarios have different operation items. - * @param isWebScene Whether it is web scene - * @returns comp - */ - const renderItemOperation = (isWebScene = true) => { - const userOperation = () => { - return feedback?.rating - ? null - :
- - {OperationBtn({ innerContent: , onClick: () => onFeedback?.(id, { rating: 'like' }) })} - - - {OperationBtn({ innerContent: , onClick: () => onFeedback?.(id, { rating: 'dislike' }) })} - -
- } - - const adminOperation = () => { - return
- {!localAdminFeedback?.rating && <> - - {OperationBtn({ - innerContent: , - onClick: async () => { - const res = await onFeedback?.(id, { rating: 'like' }) - if (res) - setLocalAdminFeedback({ rating: 'like' }) - }, - })} - - - {OperationBtn({ - innerContent: , - onClick: async () => { - const res = await onFeedback?.(id, { rating: 'dislike' }) - if (res) - setLocalAdminFeedback({ rating: 'dislike' }) - }, - })} - - } -
- } - - return ( -
- {isWebScene ? userOperation() : adminOperation()} -
- ) - } - - const getImgs = (list?: VisionFile[]) => { - if (!list) - return [] - return list.filter(file => file.type === 'image' && file.belongs_to === 'assistant') - } - - const agentModeAnswer = ( -
- {agent_thoughts?.map((item, index) => ( -
- {item.thought && ( - - )} - {/* {item.tool} */} - {/* perhaps not use tool */} - {!!item.tool && ( - - )} - - {getImgs(item.message_files).length > 0 && ( - item.url)} /> - )} -
- ))} -
- ) - - const [containerWidth, setContainerWidth] = useState(0) - const [contentWidth, setContentWidth] = useState(0) - const containerRef = useRef(null) - const contentRef = useRef(null) - - const getContainerWidth = () => { - if (containerRef.current) - setContainerWidth(containerRef.current?.clientWidth + 24) - } - const getContentWidth = () => { - if (contentRef.current) - setContentWidth(contentRef.current?.clientWidth) - } - - useEffect(() => { - getContainerWidth() - }, []) - - useEffect(() => { - if (!isResponding) - getContentWidth() - }, [isResponding]) - - const operationWidth = useMemo(() => { - let width = 0 - if (!item.isOpeningStatement) - width += 28 - if (!item.isOpeningStatement && isShowPromptLog) - width += 102 + 8 - if (!item.isOpeningStatement && isShowTextToSpeech) - width += 33 - if (!item.isOpeningStatement && supportAnnotation) - width += 96 + 8 - if (!feedbackDisabled && !item.feedbackDisabled) - width += 60 + 8 - if (!feedbackDisabled && localAdminFeedback?.rating && !item.isOpeningStatement) - width += 60 + 8 - if (!feedbackDisabled && feedback?.rating && !item.isOpeningStatement) - width += 28 + 8 - return width - }, [item.isOpeningStatement, item.feedbackDisabled, isShowPromptLog, isShowTextToSpeech, supportAnnotation, feedbackDisabled, localAdminFeedback?.rating, feedback?.rating]) - - const positionRight = useMemo(() => operationWidth < containerWidth - contentWidth - 4, [operationWidth, containerWidth, contentWidth]) - - return ( - // data-id for debug the item message is right -
-
- { - answerIcon || ( -
- {isResponding - &&
- -
- } -
- ) - } -
-
-
-
- {(isResponding && (isAgentMode ? (!content && (agent_thoughts || []).filter(item => !!item.thought || !!item.tool).length === 0) : !content)) - ? ( -
- -
- ) - : ( -
- {annotation?.logAnnotation && ( -
-
- {isAgentMode - ? (
{agentModeAnswer}
) - : ( - - )} -
- -
- )} -
- {annotation?.logAnnotation - ? ( - - ) - : (isAgentMode - ? agentModeAnswer - : ( - - ))} -
- {(hasAnnotation && !annotation?.logAnnotation) && ( - - )} - {item.isOpeningStatement && item.suggestedQuestions && item.suggestedQuestions.filter(q => !!q && q.trim()).length > 0 && ( -
- {item.suggestedQuestions.filter(q => !!q && q.trim()).map((question, index) => ( -
onQueryChange(question)} - > - {question} -
), - )} -
- )} -
- )} - { - !!citation?.length && isShowCitation && !isResponding && ( - - ) - } -
- {hasAnnotation && ( -
-
- -
-
- )} -
- {!item.isOpeningStatement && ( - - )} - {((isShowPromptLog && !isResponding) || (!item.isOpeningStatement && isShowTextToSpeech)) && ( -
- {isShowPromptLog && !isResponding && ( - - )} - {!item.isOpeningStatement && isShowTextToSpeech && ( - <> -
- - - )} -
- )} - {(!item.isOpeningStatement && supportAnnotation) && ( - onAnnotationAdded?.(id, authorName, question, content, index)} - onEdit={() => setIsShowReplyModal(true)} - onRemoved={() => onAnnotationRemoved!(index)} - /> - )} - - setIsShowReplyModal(false)} - query={question} - answer={content} - onEdited={(editedQuery, editedAnswer) => onAnnotationEdited!(editedQuery, editedAnswer, index)} - onAdded={(annotationId, authorName, editedQuery, editedAnswer) => onAnnotationAdded!(annotationId, authorName, editedQuery, editedAnswer, index)} - appId={appId!} - messageId={id} - annotationId={annotation?.id || ''} - createdAt={annotation?.created_at} - onRemove={() => { }} - /> - - {!feedbackDisabled && !item.feedbackDisabled && renderItemOperation(displayScene !== 'console')} - {/* Admin feedback is displayed only in the background. */} - {!feedbackDisabled && renderFeedbackRating(localAdminFeedback?.rating, false, false)} - {/* User feedback must be displayed */} - {!feedbackDisabled && renderFeedbackRating(feedback?.rating, !isHideFeedbackEdit, displayScene !== 'console')} -
-
- {more && } -
-
-
-
- ) -} -export default React.memo(Answer) diff --git a/web/app/components/app/chat/icon-component/index.tsx b/web/app/components/app/chat/icon-component/index.tsx deleted file mode 100644 index c35fb77855..0000000000 --- a/web/app/components/app/chat/icon-component/index.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import type { FC, SVGProps } from 'react' -import { HandThumbDownIcon, HandThumbUpIcon } from '@heroicons/react/24/outline' - -export const stopIcon = ( - - - -) - -export const OpeningStatementIcon = ({ className }: SVGProps) => ( - - - -) - -export const RatingIcon: FC<{ isLike: boolean }> = ({ isLike }) => { - return isLike ? : -} - -export const EditIcon = ({ className }: SVGProps) => { - return - - -} - -export const EditIconSolid = ({ className }: SVGProps) => { - return - - - -} - -export const TryToAskIcon = ( - - - -) - -export const ReplayIcon = ({ className }: SVGProps) => ( - - - -) diff --git a/web/app/components/app/chat/icons/answer.svg b/web/app/components/app/chat/icons/answer.svg deleted file mode 100644 index e983039306..0000000000 --- a/web/app/components/app/chat/icons/answer.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/web/app/components/app/chat/icons/default-avatar.jpg b/web/app/components/app/chat/icons/default-avatar.jpg deleted file mode 100644 index 396d5dd291b44bc440da35e655774626ce1bae20..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2183 zcmbW1dpy*67stQ9-^?(^ZColeZo6z$YLw_{G2>R`(&Q3P$P|@rz+)uxgs0ag5l@gWAD)E zztA`D(UG@k-xAs}i#AW9jT7jzDYRxB?V3j?-lLUc=<^x0WeRPXMk`;VBg<&>6xuO| zb}yh4D;AvqNG~|pTDf0@7JHs$CenyFYW-Zs4OXfDLKrKrNVU{m6_R}8|2gx#r8V7_ zu#RojVL#RQ^_7(FO6M(2WbLlCYc%WKR~`}8&U|cF?a^;Ns!%OLhU>L^?P$zv1;p%G z;61YPTTv*Zz;6*4y`u4?_~K zQqbJ?=)s-S8cffbilaX37m=ysrYVl*ZC+K$zFQO-IkG9;=&CG~qoL@L+ni()Yd%o% zvnHQe&R&+4=^Ilh6A!WwU<|+tO6W#N=$?G;$wJ^uVIyo%C#K$c!5XQw_I)S z1Z2~8Y6RVt5hU<2wE>~zogfg01G-cY>fi+gcsw`*rN^gX?!Y5suEKPND8Yp$Q>fw& zZ^vXJS~39wyEbSKKk}EC&>rej@0x8%1COglR2)Zc;cDc9H&0qTK1fq3RC0$6;234W zA3AQ}1}I1fHFlCOB)DUWV88AMpUh^grja4g4^=`9gp+E;vOUtZa^r^)W5kL|D3~zp z3DwZ+eWb`TWL&70N%neE z!NIUhD180*HV}?1+uX+0C{}h@}s%j=J}k-0&IZxj?WE2aP&fmv==Lr{$?$M*J9I~ zRzhKPj-q>6>B)1Er=vgRh+urbz81GJEA3QiH!HYcSJ>HX-@!er`-FuqrzdU=Pf}RC z9MMcyzrLjp8sX`BUD}rA&CPW@QAIV&{5>dMJfNE2TmS2GN6O3dB9D#Kr*S8_sg2z4 z7hklONheu~6BuS~N0PY!-e_8;!G6yFs0$hSU; z8rqcK6JtqA9%>znm`_iBXlR}h#Uh=HDSJiEuWpbZa86!TWnR!w815wWHMHCrjkFrv zY>cWZ_Gxx82I17PJ}-y!W7Ex-A|DxvozL5`Bb-{@f}YOp&pdRBskSz7Gmay#by}-# z;J#3xDh$&2G04ke2*dQGk(IAAKC>JD>9Z{S6Ke^1 zLrHXuvT#nLTs@F0Y9wB6^4-Exep0;FUg9!kclBL1nSgd9^OVY=o7)1rPfcVJYUM$LRTv;Exn$M!-o7v3J_wrUk8QOZ9G8#Y)zjTfhM&d$$ z1<^2t>M^pWv(fU%F)C&};H|Khe(wN|9==85XK`F>0hT6NqC&a0OE}~aOjYLsnv?;! z34I56P`X6Zf$}^Fn#EE2NamTmm|~5|Ih;QDgNq%n!j{)>VePUUR5D-FmjCi-i>y^h)bkP=}A~&jR21OCU8Ak1&9yfi68+$)PD$nKMjx- zF31^Roven4k~|0{0fj_)XcDON4d^o6>98DRuByrI zxQ86EdQH;7v_Uo;TDGM`_aI-NR`aA#h3h$an905aGB3}EDU-q_WAbB1?ADuZE5qFS s87)kBr-f92fg@+YmECigj^Xs982;qb2t(s+qc0?Iuye63wWhQG290UxH2?qr diff --git a/web/app/components/app/chat/icons/edit.svg b/web/app/components/app/chat/icons/edit.svg deleted file mode 100644 index a922970b6c..0000000000 --- a/web/app/components/app/chat/icons/edit.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/web/app/components/app/chat/icons/question.svg b/web/app/components/app/chat/icons/question.svg deleted file mode 100644 index 39904f52a5..0000000000 --- a/web/app/components/app/chat/icons/question.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/web/app/components/app/chat/icons/robot.svg b/web/app/components/app/chat/icons/robot.svg deleted file mode 100644 index a50c8886d1..0000000000 --- a/web/app/components/app/chat/icons/robot.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/web/app/components/app/chat/icons/send-active.svg b/web/app/components/app/chat/icons/send-active.svg deleted file mode 100644 index 03d4734bc6..0000000000 --- a/web/app/components/app/chat/icons/send-active.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/web/app/components/app/chat/icons/send.svg b/web/app/components/app/chat/icons/send.svg deleted file mode 100644 index e977ef95bb..0000000000 --- a/web/app/components/app/chat/icons/send.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/web/app/components/app/chat/icons/typing.svg b/web/app/components/app/chat/icons/typing.svg deleted file mode 100644 index 7b28f0ef78..0000000000 --- a/web/app/components/app/chat/icons/typing.svg +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - - - - - - - - - diff --git a/web/app/components/app/chat/icons/user.svg b/web/app/components/app/chat/icons/user.svg deleted file mode 100644 index 556aaf7bfb..0000000000 --- a/web/app/components/app/chat/icons/user.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/web/app/components/app/chat/index.tsx b/web/app/components/app/chat/index.tsx deleted file mode 100644 index d861ddb2de..0000000000 --- a/web/app/components/app/chat/index.tsx +++ /dev/null @@ -1,455 +0,0 @@ -'use client' -import type { FC, ReactNode } from 'react' -import React, { useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react' -import Textarea from 'rc-textarea' -import { useContext } from 'use-context-selector' -import cn from 'classnames' -import Recorder from 'js-audio-recorder' -import { useTranslation } from 'react-i18next' -import s from './style.module.css' -import type { DisplayScene, FeedbackFunc, IChatItem } from './type' -import { TryToAskIcon, stopIcon } from './icon-component' -import Answer from './answer' -import Question from './question' -import TooltipPlus from '@/app/components/base/tooltip-plus' -import { ToastContext } from '@/app/components/base/toast' -import Button from '@/app/components/base/button' -import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints' -import VoiceInput from '@/app/components/base/voice-input' -import { Microphone01 } from '@/app/components/base/icons/src/vender/line/mediaAndDevices' -import { Microphone01 as Microphone01Solid } from '@/app/components/base/icons/src/vender/solid/mediaAndDevices' -import { XCircle } from '@/app/components/base/icons/src/vender/solid/general' -import type { DataSet } from '@/models/datasets' -import ChatImageUploader from '@/app/components/base/image-uploader/chat-image-uploader' -import ImageList from '@/app/components/base/image-uploader/image-list' -import { TransferMethod, type VisionFile, type VisionSettings } from '@/types/app' -import { useClipboardUploader, useDraggableUploader, useImageFiles } from '@/app/components/base/image-uploader/hooks' -import type { Annotation } from '@/models/log' -import type { Emoji } from '@/app/components/tools/types' - -export type IChatProps = { - appId?: string - configElem?: React.ReactNode - chatList: IChatItem[] - onChatListChange?: (chatList: IChatItem[]) => void - controlChatUpdateAllConversation?: number - /** - * Whether to display the editing area and rating status - */ - feedbackDisabled?: boolean - /** - * Whether to display the input area - */ - isHideFeedbackEdit?: boolean - isHideSendInput?: boolean - onFeedback?: FeedbackFunc - checkCanSend?: () => boolean - query?: string - onQueryChange?: (query: string) => void - onSend?: (message: string, files: VisionFile[]) => void - displayScene?: DisplayScene - useCurrentUserAvatar?: boolean - isResponding?: boolean - canStopResponding?: boolean - abortResponding?: () => void - controlClearQuery?: number - controlFocus?: number - isShowSuggestion?: boolean - suggestionList?: string[] - isShowSpeechToText?: boolean - isShowTextToSpeech?: boolean - isShowCitation?: boolean - answerIcon?: ReactNode - isShowConfigElem?: boolean - dataSets?: DataSet[] - isShowCitationHitInfo?: boolean - isShowPromptLog?: boolean - visionConfig?: VisionSettings - supportAnnotation?: boolean - allToolIcons?: Record - customDisclaimer?: string -} - -const Chat: FC = ({ - configElem, - chatList, - query = '', - onQueryChange = () => { }, - feedbackDisabled = false, - isHideFeedbackEdit = false, - isHideSendInput = false, - onFeedback, - checkCanSend, - onSend = () => { }, - displayScene, - useCurrentUserAvatar, - isResponding, - canStopResponding, - abortResponding, - controlClearQuery, - controlFocus, - isShowSuggestion, - suggestionList, - isShowSpeechToText, - isShowTextToSpeech, - isShowCitation, - answerIcon, - isShowConfigElem, - dataSets, - isShowCitationHitInfo, - isShowPromptLog, - visionConfig, - appId, - supportAnnotation, - onChatListChange, - allToolIcons, - customDisclaimer, -}) => { - const { t } = useTranslation() - const { notify } = useContext(ToastContext) - const { - files, - onUpload, - onRemove, - onReUpload, - onImageLinkLoadError, - onImageLinkLoadSuccess, - onClear, - } = useImageFiles() - const { onPaste } = useClipboardUploader({ onUpload, visionConfig, files }) - const { onDragEnter, onDragLeave, onDragOver, onDrop, isDragActive } = useDraggableUploader({ onUpload, files, visionConfig }) - const isUseInputMethod = useRef(false) - - const handleContentChange = (e: React.ChangeEvent) => { - const value = e.target.value - onQueryChange(value) - } - - const logError = (message: string) => { - notify({ type: 'error', message, duration: 3000 }) - } - - const valid = (q?: string) => { - const sendQuery = q || query - if (!sendQuery || sendQuery.trim() === '') { - logError('Message cannot be empty') - return false - } - return true - } - - useEffect(() => { - if (controlClearQuery) - onQueryChange('') - }, [controlClearQuery]) - - const handleSend = (q?: string) => { - if (!valid(q) || (checkCanSend && !checkCanSend())) - return - onSend(q || query, files.filter(file => file.progress !== -1).map(fileItem => ({ - type: 'image', - transfer_method: fileItem.type, - url: fileItem.url, - upload_file_id: fileItem.fileId, - }))) - if (!files.find(item => item.type === TransferMethod.local_file && !item.fileId)) { - if (files.length) - onClear() - if (!isResponding) - onQueryChange('') - } - } - - const handleKeyUp = (e: React.KeyboardEvent) => { - if (e.code === 'Enter') { - e.preventDefault() - // prevent send message when using input method enter - if (!e.shiftKey && !isUseInputMethod.current) - handleSend() - } - } - - const handleKeyDown = (e: React.KeyboardEvent) => { - isUseInputMethod.current = e.nativeEvent.isComposing - if (e.code === 'Enter' && !e.shiftKey) { - onQueryChange(query.replace(/\n$/, '')) - e.preventDefault() - } - } - - const media = useBreakpoints() - const isMobile = media === MediaType.mobile - const sendBtn =
handleSend()}>
- - const suggestionListRef = useRef(null) - const [hasScrollbar, setHasScrollbar] = useState(false) - useLayoutEffect(() => { - if (suggestionListRef.current) { - const listDom = suggestionListRef.current - const hasScrollbar = listDom.scrollWidth > listDom.clientWidth - setHasScrollbar(hasScrollbar) - } - }, [suggestionList]) - - const [voiceInputShow, setVoiceInputShow] = useState(false) - const handleVoiceInputShow = () => { - (Recorder as any).getPermission().then(() => { - setVoiceInputShow(true) - }, () => { - logError(t('common.voiceInput.notAllow')) - }) - } - const handleQueryChangeFromAnswer = useCallback((val: string) => { - onQueryChange(val) - handleSend(val) - }, []) - const handleAnnotationEdited = useCallback((query: string, answer: string, index: number) => { - onChatListChange?.(chatList.map((item, i) => { - if (i === index - 1) { - return { - ...item, - content: query, - } - } - if (i === index) { - return { - ...item, - annotation: { - ...item.annotation, - logAnnotation: { - ...item.annotation?.logAnnotation, - content: answer, - }, - } as any, - } - } - return item - })) - }, [chatList]) - const handleAnnotationAdded = useCallback((annotationId: string, authorName: string, query: string, answer: string, index: number) => { - onChatListChange?.(chatList.map((item, i) => { - if (i === index - 1) { - return { - ...item, - content: query, - } - } - if (i === index) { - const answerItem = { - ...item, - content: item.content, - annotation: { - id: annotationId, - authorName, - logAnnotation: { - content: answer, - account: { - id: '', - name: authorName, - email: '', - }, - }, - } as Annotation, - } - return answerItem - } - return item - })) - }, [chatList]) - const handleAnnotationRemoved = useCallback((index: number) => { - onChatListChange?.(chatList.map((item, i) => { - if (i === index) { - return { - ...item, - content: item.content, - annotation: undefined, - } - } - return item - })) - }, [chatList]) - - return ( -
- {isShowConfigElem && (configElem || null)} - {/* Chat List */} -
- {chatList.map((item, index) => { - if (item.isAnswer) { - const isLast = item.id === chatList[chatList.length - 1].id - const citation = item.citation - return - } - return ( - - ) - })} -
- {!isHideSendInput && ( -
- {/* Thinking is sync and can not be stopped */} - {(isResponding && canStopResponding && ((!!chatList[chatList.length - 1]?.content) || (chatList[chatList.length - 1]?.agent_thoughts && chatList[chatList.length - 1].agent_thoughts!.length > 0))) && ( -
- -
- )} - {isShowSuggestion && ( -
-
-
-
- {TryToAskIcon} - {t('appDebug.feature.suggestedQuestionsAfterAnswer.tryToAsk')} -
-
-
- {/* has scrollbar would hide part of first item */} -
- {suggestionList?.map((item, index) => ( -
- -
- ))} -
-
- )} -
-
- {visionConfig?.enabled && ( - <> -
- = visionConfig.number_limits} - /> -
-
-
- -
- - )} -