chat-wrapper.tsx 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. import { useCallback, useEffect, useMemo } from 'react'
  2. import Chat from '../chat'
  3. import type {
  4. ChatConfig,
  5. OnSend,
  6. } from '../types'
  7. import { useChat } from '../chat/hooks'
  8. import { useChatWithHistoryContext } from './context'
  9. import Header from './header'
  10. import ConfigPanel from './config-panel'
  11. import {
  12. fetchSuggestedQuestions,
  13. getUrl,
  14. stopChatMessageResponding,
  15. } from '@/service/share'
  16. import AnswerIcon from '@/app/components/base/answer-icon'
  17. const ChatWrapper = () => {
  18. const {
  19. appParams,
  20. appPrevChatList,
  21. currentConversationId,
  22. currentConversationItem,
  23. inputsForms,
  24. newConversationInputs,
  25. handleNewConversationCompleted,
  26. isMobile,
  27. isInstalledApp,
  28. appId,
  29. appMeta,
  30. handleFeedback,
  31. currentChatInstanceRef,
  32. appData,
  33. themeBuilder,
  34. } = useChatWithHistoryContext()
  35. const appConfig = useMemo(() => {
  36. const config = appParams || {}
  37. return {
  38. ...config,
  39. supportFeedback: true,
  40. opening_statement: currentConversationId ? currentConversationItem?.introduction : (config as any).opening_statement,
  41. } as ChatConfig
  42. }, [appParams, currentConversationItem?.introduction, currentConversationId])
  43. const {
  44. chatList,
  45. handleSend,
  46. handleStop,
  47. isResponding,
  48. suggestedQuestions,
  49. } = useChat(
  50. appConfig,
  51. {
  52. inputs: (currentConversationId ? currentConversationItem?.inputs : newConversationInputs) as any,
  53. promptVariables: inputsForms,
  54. },
  55. appPrevChatList,
  56. taskId => stopChatMessageResponding('', taskId, isInstalledApp, appId),
  57. )
  58. useEffect(() => {
  59. if (currentChatInstanceRef.current)
  60. currentChatInstanceRef.current.handleStop = handleStop
  61. }, [])
  62. const doSend: OnSend = useCallback((message, files) => {
  63. const data: any = {
  64. query: message,
  65. inputs: currentConversationId ? currentConversationItem?.inputs : newConversationInputs,
  66. conversation_id: currentConversationId,
  67. }
  68. if (appConfig?.file_upload?.image.enabled && files?.length)
  69. data.files = files
  70. handleSend(
  71. getUrl('chat-messages', isInstalledApp, appId || ''),
  72. data,
  73. {
  74. onGetSuggestedQuestions: responseItemId => fetchSuggestedQuestions(responseItemId, isInstalledApp, appId),
  75. onConversationComplete: currentConversationId ? undefined : handleNewConversationCompleted,
  76. isPublicAPI: !isInstalledApp,
  77. },
  78. )
  79. }, [
  80. appConfig,
  81. currentConversationId,
  82. currentConversationItem,
  83. handleSend,
  84. newConversationInputs,
  85. handleNewConversationCompleted,
  86. isInstalledApp,
  87. appId,
  88. ])
  89. const chatNode = useMemo(() => {
  90. if (inputsForms.length) {
  91. return (
  92. <>
  93. <Header
  94. isMobile={isMobile}
  95. title={currentConversationItem?.name || ''}
  96. />
  97. {
  98. !currentConversationId && (
  99. <div className={`mx-auto w-full max-w-[720px] ${isMobile && 'px-4'}`}>
  100. <div className='mb-6' />
  101. <ConfigPanel />
  102. <div
  103. className='my-6 h-[1px]'
  104. style={{ background: 'linear-gradient(90deg, rgba(242, 244, 247, 0.00) 0%, #F2F4F7 49.17%, rgba(242, 244, 247, 0.00) 100%)' }}
  105. />
  106. </div>
  107. )
  108. }
  109. </>
  110. )
  111. }
  112. return (
  113. <Header
  114. isMobile={isMobile}
  115. title={currentConversationItem?.name || ''}
  116. />
  117. )
  118. }, [
  119. currentConversationId,
  120. inputsForms,
  121. currentConversationItem,
  122. isMobile,
  123. ])
  124. const answerIcon = (appData?.site && appData.site.use_icon_as_answer_icon)
  125. ? <AnswerIcon
  126. iconType={appData.site.icon_type}
  127. icon={appData.site.icon}
  128. background={appData.site.icon_background}
  129. imageUrl={appData.site.icon_url}
  130. />
  131. : null
  132. return (
  133. <Chat
  134. appData={appData}
  135. config={appConfig}
  136. chatList={chatList}
  137. isResponding={isResponding}
  138. chatContainerInnerClassName={`mx-auto pt-6 w-full max-w-full ${isMobile && 'px-4'}`}
  139. chatFooterClassName='pb-4'
  140. chatFooterInnerClassName={`mx-auto w-full max-w-full ${isMobile && 'px-4'}`}
  141. onSend={doSend}
  142. onStopResponding={handleStop}
  143. chatNode={chatNode}
  144. allToolIcons={appMeta?.tool_icons || {}}
  145. onFeedback={handleFeedback}
  146. suggestedQuestions={suggestedQuestions}
  147. answerIcon={answerIcon}
  148. hideProcessDetail
  149. themeBuilder={themeBuilder}
  150. />
  151. )
  152. }
  153. export default ChatWrapper