Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  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 { ChatItem, 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. type DebugWithSingleModelProps = {
  26. checkCanSend?: () => boolean
  27. }
  28. export type DebugWithSingleModelRefType = {
  29. handleRestart: () => void
  30. }
  31. const DebugWithSingleModel = forwardRef<DebugWithSingleModelRefType, DebugWithSingleModelProps>(({
  32. checkCanSend,
  33. }, ref) => {
  34. const { userProfile } = useAppContext()
  35. const {
  36. modelConfig,
  37. appId,
  38. inputs,
  39. visionConfig,
  40. collectionList,
  41. completionParams,
  42. } = useDebugConfigurationContext()
  43. const { textGenerationModelList } = useProviderContext()
  44. const config = useConfigFromDebugContext()
  45. const {
  46. chatList,
  47. chatListRef,
  48. isResponding,
  49. handleSend,
  50. suggestedQuestions,
  51. handleStop,
  52. handleUpdateChatList,
  53. handleRestart,
  54. handleAnnotationAdded,
  55. handleAnnotationEdited,
  56. handleAnnotationRemoved,
  57. } = useChat(
  58. config,
  59. {
  60. inputs,
  61. promptVariables: modelConfig.configs.prompt_variables,
  62. },
  63. [],
  64. taskId => stopChatMessageResponding(appId, taskId),
  65. )
  66. useFormattingChangedSubscription(chatList)
  67. const doSend: OnSend = useCallback((message, files, last_answer) => {
  68. if (checkCanSend && !checkCanSend())
  69. return
  70. const currentProvider = textGenerationModelList.find(item => item.provider === modelConfig.provider)
  71. const currentModel = currentProvider?.models.find(model => model.model === modelConfig.model_id)
  72. const supportVision = currentModel?.features?.includes(ModelFeatureEnum.vision)
  73. const configData = {
  74. ...config,
  75. model: {
  76. provider: modelConfig.provider,
  77. name: modelConfig.model_id,
  78. mode: modelConfig.mode,
  79. completion_params: completionParams,
  80. },
  81. }
  82. const data: any = {
  83. query: message,
  84. inputs,
  85. model_config: configData,
  86. parent_message_id: last_answer?.id || chatListRef.current.at(-1)?.id || null,
  87. }
  88. if (visionConfig.enabled && files?.length && supportVision)
  89. data.files = files
  90. handleSend(
  91. `apps/${appId}/chat-messages`,
  92. data,
  93. {
  94. onGetConversationMessages: (conversationId, getAbortController) => fetchConversationMessages(appId, conversationId, getAbortController),
  95. onGetSuggestedQuestions: (responseItemId, getAbortController) => fetchSuggestedQuestions(appId, responseItemId, getAbortController),
  96. },
  97. )
  98. }, [chatListRef, appId, checkCanSend, completionParams, config, handleSend, inputs, modelConfig, textGenerationModelList, visionConfig.enabled])
  99. const doRegenerate = useCallback((chatItem: ChatItem) => {
  100. const index = chatList.findIndex(item => item.id === chatItem.id)
  101. if (index === -1)
  102. return
  103. const prevMessages = chatList.slice(0, index)
  104. const question = prevMessages.pop()
  105. const lastAnswer = prevMessages.at(-1)
  106. if (!question)
  107. return
  108. handleUpdateChatList(prevMessages)
  109. doSend(question.content, question.message_files, (!lastAnswer || lastAnswer.isOpeningStatement) ? undefined : lastAnswer)
  110. }, [chatList, handleUpdateChatList, doSend])
  111. const allToolIcons = useMemo(() => {
  112. const icons: Record<string, any> = {}
  113. modelConfig.agentConfig.tools?.forEach((item: any) => {
  114. icons[item.tool_name] = collectionList.find((collection: any) => collection.id === item.provider_id)?.icon
  115. })
  116. return icons
  117. }, [collectionList, modelConfig.agentConfig.tools])
  118. useImperativeHandle(ref, () => {
  119. return {
  120. handleRestart,
  121. }
  122. }, [handleRestart])
  123. return (
  124. <Chat
  125. config={config}
  126. chatList={chatList}
  127. isResponding={isResponding}
  128. chatContainerClassName='p-6'
  129. chatFooterClassName='px-6 pt-10 pb-4'
  130. suggestedQuestions={suggestedQuestions}
  131. onSend={doSend}
  132. onRegenerate={doRegenerate}
  133. onStopResponding={handleStop}
  134. showPromptLog
  135. questionIcon={<Avatar name={userProfile.name} size={40} />}
  136. allToolIcons={allToolIcons}
  137. onAnnotationEdited={handleAnnotationEdited}
  138. onAnnotationAdded={handleAnnotationAdded}
  139. onAnnotationRemoved={handleAnnotationRemoved}
  140. noSpacing
  141. />
  142. )
  143. })
  144. DebugWithSingleModel.displayName = 'DebugWithSingleModel'
  145. export default memo(DebugWithSingleModel)