123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203 |
- import type {
- FC,
- ReactNode,
- } from 'react'
- import { memo, useEffect, useRef, useState } from 'react'
- import { useTranslation } from 'react-i18next'
- import type {
- ChatConfig,
- ChatItem,
- } from '../../types'
- import { useChatContext } from '../context'
- import Operation from './operation'
- import AgentContent from './agent-content'
- import BasicContent from './basic-content'
- import SuggestedQuestions from './suggested-questions'
- import More from './more'
- import WorkflowProcess from './workflow-process'
- import { AnswerTriangle } from '@/app/components/base/icons/src/vender/solid/general'
- import { MessageFast } from '@/app/components/base/icons/src/vender/solid/communication'
- import LoadingAnim from '@/app/components/base/chat/chat/loading-anim'
- import Citation from '@/app/components/base/chat/chat/citation'
- import { EditTitle } from '@/app/components/app/annotation/edit-annotation-modal/edit-item'
- import type { Emoji } from '@/app/components/tools/types'
- import type { AppData } from '@/models/share'
- type AnswerProps = {
- item: ChatItem
- question: string
- index: number
- config?: ChatConfig
- answerIcon?: ReactNode
- responding?: boolean
- allToolIcons?: Record<string, string | Emoji>
- showPromptLog?: boolean
- chatAnswerContainerInner?: string
- hideProcessDetail?: boolean
- appData?: AppData
- }
- const Answer: FC<AnswerProps> = ({
- item,
- question,
- index,
- config,
- answerIcon,
- responding,
- allToolIcons,
- showPromptLog,
- chatAnswerContainerInner,
- hideProcessDetail,
- appData,
- }) => {
- const { t } = useTranslation()
- const {
- content,
- citation,
- agent_thoughts,
- more,
- annotation,
- workflowProcess,
- } = item
- const hasAgentThoughts = !!agent_thoughts?.length
- const [containerWidth] = useState(0)
- const [contentWidth, setContentWidth] = useState(0)
- const containerRef = useRef<HTMLDivElement>(null)
- const contentRef = useRef<HTMLDivElement>(null)
- const {
- config: chatContextConfig,
- } = useChatContext()
- const voiceRef = useRef(chatContextConfig?.text_to_speech?.voice)
- const getContentWidth = () => {
- if (contentRef.current)
- setContentWidth(contentRef.current?.clientWidth)
- }
- useEffect(() => {
- voiceRef.current = chatContextConfig?.text_to_speech?.voice
- }
- , [chatContextConfig?.text_to_speech?.voice])
- useEffect(() => {
- if (!responding)
- getContentWidth()
- }, [responding])
- return (
- <div className='flex mb-2 last:mb-0'>
- <div className='shrink-0 relative w-10 h-10'>
- {
- answerIcon || (
- <div className='flex items-center justify-center w-full h-full rounded-full bg-[#d5f5f6] border-[0.5px] border-black/5 text-xl'>
- 🤖
- </div>
- )
- }
- {
- responding && (
- <div className='absolute -top-[3px] -left-[3px] pl-[6px] flex items-center w-4 h-4 bg-white rounded-full shadow-xs border-[0.5px] border-gray-50'>
- <LoadingAnim type='avatar' />
- </div>
- )
- }
- </div>
- <div className='chat-answer-container group grow w-0 ml-4' ref={containerRef}>
- <div className={`group relative pr-10 ${chatAnswerContainerInner}`}>
- <AnswerTriangle className='absolute -left-2 top-0 w-2 h-3 text-gray-100' />
- <div
- ref={contentRef}
- className={`
- relative inline-block px-4 py-3 max-w-full bg-gray-100 rounded-b-2xl rounded-tr-2xl text-sm text-gray-900
- ${workflowProcess && 'w-full'}
- `}
- >
- {annotation?.id && (
- <div
- className='absolute -top-3.5 -right-3.5 box-border flex items-center justify-center h-7 w-7 p-0.5 rounded-lg bg-white cursor-pointer text-[#444CE7] shadow-md group-hover:hidden'
- >
- <div className='p-1 rounded-lg bg-[#EEF4FF] '>
- <MessageFast className='w-4 h-4' />
- </div>
- </div>
- )}
- {
- !responding && (
- <Operation
- hasWorkflowProcess={!!workflowProcess}
- maxSize={containerWidth - contentWidth - 4}
- contentWidth={contentWidth}
- item={item}
- question={question}
- index={index}
- showPromptLog={showPromptLog}
- />
- )
- }
- {/** Render the normal steps */}
- {
- workflowProcess && !hideProcessDetail && (
- <WorkflowProcess
- data={workflowProcess}
- item={item}
- hideInfo
- hideProcessDetail={hideProcessDetail}
- />
- )
- }
- {/** Hide workflow steps by it's settings in siteInfo */}
- {
- workflowProcess && hideProcessDetail && appData && appData.site.show_workflow_steps && (
- <WorkflowProcess
- data={workflowProcess}
- item={item}
- hideInfo
- hideProcessDetail={hideProcessDetail}
- />
- )
- }
- {
- responding && !content && !hasAgentThoughts && (
- <div className='flex items-center justify-center w-6 h-5'>
- <LoadingAnim type='text' />
- </div>
- )
- }
- {
- content && !hasAgentThoughts && (
- <BasicContent item={item} />
- )
- }
- {
- hasAgentThoughts && (
- <AgentContent
- item={item}
- responding={responding}
- allToolIcons={allToolIcons}
- />
- )
- }
- {
- annotation?.id && annotation.authorName && (
- <EditTitle
- className='mt-1'
- title={t('appAnnotation.editBy', { author: annotation.authorName })}
- />
- )
- }
- <SuggestedQuestions item={item} />
- {
- !!citation?.length && !responding && (
- <Citation data={citation} showHitInfo={config?.supportCitationHitInfo} />
- )
- }
- </div>
- </div>
- <More more={more} />
- </div>
- </div>
- )
- }
- export default memo(Answer)
|