chat-wrapper.tsx 4.3 KB

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