index.tsx 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. import type {
  2. FC,
  3. ReactNode,
  4. } from 'react'
  5. import { memo, useEffect, useRef, useState } from 'react'
  6. import { useTranslation } from 'react-i18next'
  7. import type {
  8. ChatConfig,
  9. ChatItem,
  10. } from '../../types'
  11. import Operation from './operation'
  12. import AgentContent from './agent-content'
  13. import BasicContent from './basic-content'
  14. import SuggestedQuestions from './suggested-questions'
  15. import More from './more'
  16. import WorkflowProcess from './workflow-process'
  17. import { AnswerTriangle } from '@/app/components/base/icons/src/vender/solid/general'
  18. import { MessageFast } from '@/app/components/base/icons/src/vender/solid/communication'
  19. import LoadingAnim from '@/app/components/base/chat/chat/loading-anim'
  20. import Citation from '@/app/components/base/chat/chat/citation'
  21. import { EditTitle } from '@/app/components/app/annotation/edit-annotation-modal/edit-item'
  22. import type { Emoji } from '@/app/components/tools/types'
  23. import type { AppData } from '@/models/share'
  24. type AnswerProps = {
  25. item: ChatItem
  26. question: string
  27. index: number
  28. config?: ChatConfig
  29. answerIcon?: ReactNode
  30. responding?: boolean
  31. allToolIcons?: Record<string, string | Emoji>
  32. showPromptLog?: boolean
  33. chatAnswerContainerInner?: string
  34. hideProcessDetail?: boolean
  35. appData?: AppData
  36. }
  37. const Answer: FC<AnswerProps> = ({
  38. item,
  39. question,
  40. index,
  41. config,
  42. answerIcon,
  43. responding,
  44. allToolIcons,
  45. showPromptLog,
  46. chatAnswerContainerInner,
  47. hideProcessDetail,
  48. appData,
  49. }) => {
  50. const { t } = useTranslation()
  51. const {
  52. content,
  53. citation,
  54. agent_thoughts,
  55. more,
  56. annotation,
  57. workflowProcess,
  58. } = item
  59. const hasAgentThoughts = !!agent_thoughts?.length
  60. const [containerWidth, setContainerWidth] = useState(0)
  61. const [contentWidth, setContentWidth] = useState(0)
  62. const containerRef = useRef<HTMLDivElement>(null)
  63. const contentRef = useRef<HTMLDivElement>(null)
  64. const getContainerWidth = () => {
  65. if (containerRef.current)
  66. setContainerWidth(containerRef.current?.clientWidth + 16)
  67. }
  68. const getContentWidth = () => {
  69. if (contentRef.current)
  70. setContentWidth(contentRef.current?.clientWidth)
  71. }
  72. useEffect(() => {
  73. getContainerWidth()
  74. }, [])
  75. useEffect(() => {
  76. if (!responding)
  77. getContentWidth()
  78. }, [responding])
  79. return (
  80. <div className='flex mb-2 last:mb-0'>
  81. <div className='shrink-0 relative w-10 h-10'>
  82. {
  83. answerIcon || (
  84. <div className='flex items-center justify-center w-full h-full rounded-full bg-[#d5f5f6] border-[0.5px] border-black/5 text-xl'>
  85. 🤖
  86. </div>
  87. )
  88. }
  89. {
  90. responding && (
  91. <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'>
  92. <LoadingAnim type='avatar' />
  93. </div>
  94. )
  95. }
  96. </div>
  97. <div className='chat-answer-container group grow w-0 ml-4' ref={containerRef}>
  98. <div className={`group relative pr-10 ${chatAnswerContainerInner}`}>
  99. <AnswerTriangle className='absolute -left-2 top-0 w-2 h-3 text-gray-100' />
  100. <div
  101. ref={contentRef}
  102. className={`
  103. relative inline-block px-4 py-3 max-w-full bg-gray-100 rounded-b-2xl rounded-tr-2xl text-sm text-gray-900
  104. ${workflowProcess && 'w-full'}
  105. `}
  106. >
  107. {annotation?.id && (
  108. <div
  109. 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'
  110. >
  111. <div className='p-1 rounded-lg bg-[#EEF4FF] '>
  112. <MessageFast className='w-4 h-4' />
  113. </div>
  114. </div>
  115. )}
  116. {
  117. !responding && (
  118. <Operation
  119. hasWorkflowProcess={!!workflowProcess}
  120. maxSize={containerWidth - contentWidth - 4}
  121. contentWidth={contentWidth}
  122. item={item}
  123. question={question}
  124. index={index}
  125. showPromptLog={showPromptLog}
  126. />
  127. )
  128. }
  129. {/** Render the normal steps */}
  130. {
  131. workflowProcess && !hideProcessDetail && (
  132. <WorkflowProcess
  133. data={workflowProcess}
  134. item={item}
  135. hideInfo
  136. hideProcessDetail={hideProcessDetail}
  137. />
  138. )
  139. }
  140. {/** Hide workflow steps by it's settings in siteInfo */}
  141. {
  142. workflowProcess && hideProcessDetail && appData && appData.site.show_workflow_steps && (
  143. <WorkflowProcess
  144. data={workflowProcess}
  145. item={item}
  146. hideInfo
  147. hideProcessDetail={hideProcessDetail}
  148. />
  149. )
  150. }
  151. {
  152. responding && !content && !hasAgentThoughts && (
  153. <div className='flex items-center justify-center w-6 h-5'>
  154. <LoadingAnim type='text' />
  155. </div>
  156. )
  157. }
  158. {
  159. content && !hasAgentThoughts && (
  160. <BasicContent item={item} />
  161. )
  162. }
  163. {
  164. hasAgentThoughts && (
  165. <AgentContent
  166. item={item}
  167. responding={responding}
  168. allToolIcons={allToolIcons}
  169. />
  170. )
  171. }
  172. {
  173. annotation?.id && annotation.authorName && (
  174. <EditTitle
  175. className='mt-1'
  176. title={t('appAnnotation.editBy', { author: annotation.authorName })}
  177. />
  178. )
  179. }
  180. <SuggestedQuestions item={item} />
  181. {
  182. !!citation?.length && !responding && (
  183. <Citation data={citation} showHitInfo={config?.supportCitationHitInfo} />
  184. )
  185. }
  186. </div>
  187. </div>
  188. <More more={more} />
  189. </div>
  190. </div>
  191. )
  192. }
  193. export default memo(Answer)