index.tsx 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. import {
  2. forwardRef,
  3. memo,
  4. useCallback,
  5. useImperativeHandle,
  6. useMemo,
  7. } from 'react'
  8. import {
  9. useConfigFromDebugContext,
  10. useFormattingChangedSubscription,
  11. } from '../hooks'
  12. import Chat from '@/app/components/base/chat/chat'
  13. import { useChat } from '@/app/components/base/chat/chat/hooks'
  14. import { useDebugConfigurationContext } from '@/context/debug-configuration'
  15. import type { ChatConfig, ChatItem, ChatItemInTree, OnSend } from '@/app/components/base/chat/types'
  16. import { useProviderContext } from '@/context/provider-context'
  17. import {
  18. fetchConversationMessages,
  19. fetchSuggestedQuestions,
  20. stopChatMessageResponding,
  21. } from '@/service/debug'
  22. import Avatar from '@/app/components/base/avatar'
  23. import { useAppContext } from '@/context/app-context'
  24. import { ModelFeatureEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
  25. import { useStore as useAppStore } from '@/app/components/app/store'
  26. import { useFeatures } from '@/app/components/base/features/hooks'
  27. import { getLastAnswer, isValidGeneratedAnswer } from '@/app/components/base/chat/utils'
  28. import type { InputForm } from '@/app/components/base/chat/chat/type'
  29. import { canFindTool } from '@/utils'
  30. type DebugWithSingleModelProps = {
  31. checkCanSend?: () => boolean
  32. }
  33. export type DebugWithSingleModelRefType = {
  34. handleRestart: () => void
  35. }
  36. const DebugWithSingleModel = forwardRef<DebugWithSingleModelRefType, DebugWithSingleModelProps>(({
  37. checkCanSend,
  38. }, ref) => {
  39. const { userProfile } = useAppContext()
  40. const {
  41. modelConfig,
  42. appId,
  43. inputs,
  44. collectionList,
  45. completionParams,
  46. // isShowVisionConfig,
  47. } = useDebugConfigurationContext()
  48. const { textGenerationModelList } = useProviderContext()
  49. const features = useFeatures(s => s.features)
  50. const configTemplate = useConfigFromDebugContext()
  51. const config = useMemo(() => {
  52. return {
  53. ...configTemplate,
  54. more_like_this: features.moreLikeThis,
  55. opening_statement: features.opening?.enabled ? (features.opening?.opening_statement || '') : '',
  56. suggested_questions: features.opening?.enabled ? (features.opening?.suggested_questions || []) : [],
  57. sensitive_word_avoidance: features.moderation,
  58. speech_to_text: features.speech2text,
  59. text_to_speech: features.text2speech,
  60. file_upload: features.file,
  61. suggested_questions_after_answer: features.suggested,
  62. retriever_resource: features.citation,
  63. annotation_reply: features.annotationReply,
  64. } as ChatConfig
  65. }, [configTemplate, features])
  66. const inputsForm = useMemo(() => {
  67. return modelConfig.configs.prompt_variables.filter(item => item.type !== 'api').map(item => ({ ...item, label: item.name, variable: item.key })) as InputForm[]
  68. }, [modelConfig.configs.prompt_variables])
  69. const {
  70. chatList,
  71. setTargetMessageId,
  72. isResponding,
  73. handleSend,
  74. suggestedQuestions,
  75. handleStop,
  76. handleRestart,
  77. handleAnnotationAdded,
  78. handleAnnotationEdited,
  79. handleAnnotationRemoved,
  80. } = useChat(
  81. config,
  82. {
  83. inputs,
  84. inputsForm,
  85. },
  86. [],
  87. taskId => stopChatMessageResponding(appId, taskId),
  88. )
  89. useFormattingChangedSubscription(chatList)
  90. const doSend: OnSend = useCallback((message, files, isRegenerate = false, parentAnswer: ChatItem | null = null) => {
  91. if (checkCanSend && !checkCanSend())
  92. return
  93. const currentProvider = textGenerationModelList.find(item => item.provider === modelConfig.provider)
  94. const currentModel = currentProvider?.models.find(model => model.model === modelConfig.model_id)
  95. const supportVision = currentModel?.features?.includes(ModelFeatureEnum.vision)
  96. const configData = {
  97. ...config,
  98. model: {
  99. provider: modelConfig.provider,
  100. name: modelConfig.model_id,
  101. mode: modelConfig.mode,
  102. completion_params: completionParams,
  103. },
  104. }
  105. const data: any = {
  106. query: message,
  107. inputs,
  108. model_config: configData,
  109. parent_message_id: (isRegenerate ? parentAnswer?.id : getLastAnswer(chatList)?.id) || null,
  110. }
  111. if ((config.file_upload as any)?.enabled && files?.length && supportVision)
  112. data.files = files
  113. handleSend(
  114. `apps/${appId}/chat-messages`,
  115. data,
  116. {
  117. onGetConversationMessages: (conversationId, getAbortController) => fetchConversationMessages(appId, conversationId, getAbortController),
  118. onGetSuggestedQuestions: (responseItemId, getAbortController) => fetchSuggestedQuestions(appId, responseItemId, getAbortController),
  119. },
  120. )
  121. }, [appId, chatList, checkCanSend, completionParams, config, handleSend, inputs, modelConfig.mode, modelConfig.model_id, modelConfig.provider, textGenerationModelList])
  122. const doRegenerate = useCallback((chatItem: ChatItemInTree) => {
  123. const question = chatList.find(item => item.id === chatItem.parentMessageId)!
  124. const parentAnswer = chatList.find(item => item.id === question.parentMessageId)
  125. doSend(question.content, question.message_files, true, isValidGeneratedAnswer(parentAnswer) ? parentAnswer : null)
  126. }, [chatList, doSend])
  127. const allToolIcons = useMemo(() => {
  128. const icons: Record<string, any> = {}
  129. modelConfig.agentConfig.tools?.forEach((item: any) => {
  130. icons[item.tool_name] = collectionList.find((collection: any) => canFindTool(collection.id, item.provider_id))?.icon
  131. })
  132. return icons
  133. }, [collectionList, modelConfig.agentConfig.tools])
  134. useImperativeHandle(ref, () => {
  135. return {
  136. handleRestart,
  137. }
  138. }, [handleRestart])
  139. const setShowAppConfigureFeaturesModal = useAppStore(s => s.setShowAppConfigureFeaturesModal)
  140. return (
  141. <Chat
  142. config={config}
  143. chatList={chatList}
  144. isResponding={isResponding}
  145. chatContainerClassName='px-3 pt-6'
  146. chatFooterClassName='px-3 pt-10 pb-0'
  147. showFeatureBar
  148. showFileUpload={false}
  149. onFeatureBarClick={setShowAppConfigureFeaturesModal}
  150. suggestedQuestions={suggestedQuestions}
  151. onSend={doSend}
  152. inputs={inputs}
  153. inputsForm={inputsForm}
  154. onRegenerate={doRegenerate}
  155. switchSibling={siblingMessageId => setTargetMessageId(siblingMessageId)}
  156. onStopResponding={handleStop}
  157. showPromptLog
  158. questionIcon={<Avatar avatar={userProfile.avatar_url} name={userProfile.name} size={40} />}
  159. allToolIcons={allToolIcons}
  160. onAnnotationEdited={handleAnnotationEdited}
  161. onAnnotationAdded={handleAnnotationAdded}
  162. onAnnotationRemoved={handleAnnotationRemoved}
  163. noSpacing
  164. />
  165. )
  166. })
  167. DebugWithSingleModel.displayName = 'DebugWithSingleModel'
  168. export default memo(DebugWithSingleModel)