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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. import { useCallback, useEffect, useRef, useState } from 'react'
  2. import produce from 'immer'
  3. import type { Memory, MoreInfo, ValueSelector, Var } from '../../types'
  4. import { ChangeType, VarType } from '../../types'
  5. import { useStore } from '../../store'
  6. import {
  7. useIsChatMode,
  8. useNodesReadOnly,
  9. useWorkflow,
  10. } from '../../hooks'
  11. import useConfigVision from '../../hooks/use-config-vision'
  12. import type { Param, ParameterExtractorNodeType, ReasoningModeType } from './types'
  13. import { useModelListAndDefaultModelAndCurrentProviderAndModel, useTextGenerationCurrentProviderAndModelAndModelList } from '@/app/components/header/account-setting/model-provider-page/hooks'
  14. import { ModelTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
  15. import useNodeCrud from '@/app/components/workflow/nodes/_base/hooks/use-node-crud'
  16. import { checkHasQueryBlock } from '@/app/components/base/prompt-editor/constants'
  17. import useAvailableVarList from '@/app/components/workflow/nodes/_base/hooks/use-available-var-list'
  18. import { supportFunctionCall } from '@/utils/tool-call'
  19. import useInspectVarsCrud from '../../hooks/use-inspect-vars-crud'
  20. const useConfig = (id: string, payload: ParameterExtractorNodeType) => {
  21. const {
  22. deleteNodeInspectorVars,
  23. renameInspectVarName,
  24. } = useInspectVarsCrud()
  25. const { nodesReadOnly: readOnly } = useNodesReadOnly()
  26. const { handleOutVarRenameChange } = useWorkflow()
  27. const isChatMode = useIsChatMode()
  28. const defaultConfig = useStore(s => s.nodesDefaultConfigs)[payload.type]
  29. const [defaultRolePrefix, setDefaultRolePrefix] = useState<{ user: string; assistant: string }>({ user: '', assistant: '' })
  30. const { inputs, setInputs: doSetInputs } = useNodeCrud<ParameterExtractorNodeType>(id, payload)
  31. const inputRef = useRef(inputs)
  32. const setInputs = useCallback((newInputs: ParameterExtractorNodeType) => {
  33. if (newInputs.memory && !newInputs.memory.role_prefix) {
  34. const newPayload = produce(newInputs, (draft) => {
  35. draft.memory!.role_prefix = defaultRolePrefix
  36. })
  37. doSetInputs(newPayload)
  38. inputRef.current = newPayload
  39. return
  40. }
  41. doSetInputs(newInputs)
  42. inputRef.current = newInputs
  43. }, [doSetInputs, defaultRolePrefix])
  44. const filterVar = useCallback((varPayload: Var) => {
  45. return [VarType.string].includes(varPayload.type)
  46. }, [])
  47. const handleInputVarChange = useCallback((newInputVar: ValueSelector | string) => {
  48. const newInputs = produce(inputs, (draft) => {
  49. draft.query = newInputVar as ValueSelector || []
  50. })
  51. setInputs(newInputs)
  52. }, [inputs, setInputs])
  53. const handleExactParamsChange = useCallback((newParams: Param[], moreInfo?: MoreInfo) => {
  54. const newInputs = produce(inputs, (draft) => {
  55. draft.parameters = newParams
  56. })
  57. setInputs(newInputs)
  58. if (moreInfo && moreInfo?.type === ChangeType.changeVarName && moreInfo.payload) {
  59. handleOutVarRenameChange(id, [id, moreInfo.payload.beforeKey], [id, moreInfo.payload.afterKey!])
  60. renameInspectVarName(id, moreInfo.payload.beforeKey, moreInfo.payload.afterKey!)
  61. }
  62. else {
  63. deleteNodeInspectorVars(id)
  64. }
  65. }, [deleteNodeInspectorVars, handleOutVarRenameChange, id, inputs, renameInspectVarName, setInputs])
  66. const addExtractParameter = useCallback((payload: Param) => {
  67. const newInputs = produce(inputs, (draft) => {
  68. if (!draft.parameters)
  69. draft.parameters = []
  70. draft.parameters.push(payload)
  71. })
  72. setInputs(newInputs)
  73. deleteNodeInspectorVars(id)
  74. }, [deleteNodeInspectorVars, id, inputs, setInputs])
  75. // model
  76. const model = inputs.model || {
  77. provider: '',
  78. name: '',
  79. mode: 'chat',
  80. completion_params: {
  81. temperature: 0.7,
  82. },
  83. }
  84. const modelMode = inputs.model?.mode
  85. const isChatModel = modelMode === 'chat'
  86. const isCompletionModel = !isChatModel
  87. const {
  88. isVisionModel,
  89. handleVisionResolutionEnabledChange,
  90. handleVisionResolutionChange,
  91. handleModelChanged: handleVisionConfigAfterModelChanged,
  92. } = useConfigVision(model, {
  93. payload: inputs.vision,
  94. onChange: (newPayload) => {
  95. const newInputs = produce(inputs, (draft) => {
  96. draft.vision = newPayload
  97. })
  98. setInputs(newInputs)
  99. },
  100. })
  101. const appendDefaultPromptConfig = useCallback((draft: ParameterExtractorNodeType, defaultConfig: any, _passInIsChatMode?: boolean) => {
  102. const promptTemplates = defaultConfig.prompt_templates
  103. if (!isChatModel) {
  104. setDefaultRolePrefix({
  105. user: promptTemplates.completion_model.conversation_histories_role.user_prefix,
  106. assistant: promptTemplates.completion_model.conversation_histories_role.assistant_prefix,
  107. })
  108. }
  109. }, [isChatModel])
  110. const [modelChanged, setModelChanged] = useState(false)
  111. const {
  112. currentProvider,
  113. currentModel,
  114. } = useModelListAndDefaultModelAndCurrentProviderAndModel(ModelTypeEnum.textGeneration)
  115. const handleModelChanged = useCallback((model: { provider: string; modelId: string; mode?: string }) => {
  116. const newInputs = produce(inputRef.current, (draft) => {
  117. draft.model.provider = model.provider
  118. draft.model.name = model.modelId
  119. draft.model.mode = model.mode!
  120. const isModeChange = model.mode !== inputRef.current.model?.mode
  121. if (isModeChange && defaultConfig && Object.keys(defaultConfig).length > 0)
  122. appendDefaultPromptConfig(draft, defaultConfig, model.mode === 'chat')
  123. })
  124. setInputs(newInputs)
  125. setModelChanged(true)
  126. }, [setInputs, defaultConfig, appendDefaultPromptConfig])
  127. useEffect(() => {
  128. if (currentProvider?.provider && currentModel?.model && !model.provider) {
  129. handleModelChanged({
  130. provider: currentProvider?.provider,
  131. modelId: currentModel?.model,
  132. mode: currentModel?.model_properties?.mode as string,
  133. })
  134. }
  135. }, [model?.provider, currentProvider, currentModel, handleModelChanged])
  136. // change to vision model to set vision enabled, else disabled
  137. useEffect(() => {
  138. if (!modelChanged)
  139. return
  140. setModelChanged(false)
  141. handleVisionConfigAfterModelChanged()
  142. // eslint-disable-next-line react-hooks/exhaustive-deps
  143. }, [isVisionModel, modelChanged])
  144. const {
  145. currentModel: currModel,
  146. } = useTextGenerationCurrentProviderAndModelAndModelList(
  147. {
  148. provider: model.provider,
  149. model: model.name,
  150. },
  151. )
  152. const isSupportFunctionCall = supportFunctionCall(currModel?.features)
  153. const filterInputVar = useCallback((varPayload: Var) => {
  154. return [VarType.number, VarType.string].includes(varPayload.type)
  155. }, [])
  156. const {
  157. availableVars,
  158. availableNodesWithParent,
  159. } = useAvailableVarList(id, {
  160. onlyLeafNodeVar: false,
  161. filterVar: filterInputVar,
  162. })
  163. const handleCompletionParamsChange = useCallback((newParams: Record<string, any>) => {
  164. const newInputs = produce(inputs, (draft) => {
  165. draft.model.completion_params = newParams
  166. })
  167. setInputs(newInputs)
  168. }, [inputs, setInputs])
  169. const handleInstructionChange = useCallback((newInstruction: string) => {
  170. const newInputs = produce(inputs, (draft) => {
  171. draft.instruction = newInstruction
  172. })
  173. setInputs(newInputs)
  174. }, [inputs, setInputs])
  175. const hasSetBlockStatus = {
  176. history: false,
  177. query: isChatMode ? checkHasQueryBlock(inputs.instruction) : false,
  178. context: false,
  179. }
  180. const handleMemoryChange = useCallback((newMemory?: Memory) => {
  181. const newInputs = produce(inputs, (draft) => {
  182. draft.memory = newMemory
  183. })
  184. setInputs(newInputs)
  185. }, [inputs, setInputs])
  186. const handleReasoningModeChange = useCallback((newReasoningMode: ReasoningModeType) => {
  187. const newInputs = produce(inputs, (draft) => {
  188. draft.reasoning_mode = newReasoningMode
  189. })
  190. setInputs(newInputs)
  191. }, [inputs, setInputs])
  192. const handleImportFromTool = useCallback((params: Param[]) => {
  193. const newInputs = produce(inputs, (draft) => {
  194. draft.parameters = params
  195. })
  196. setInputs(newInputs)
  197. }, [inputs, setInputs])
  198. return {
  199. readOnly,
  200. handleInputVarChange,
  201. filterVar,
  202. isChatMode,
  203. inputs,
  204. isChatModel,
  205. isCompletionModel,
  206. handleModelChanged,
  207. handleCompletionParamsChange,
  208. handleImportFromTool,
  209. handleExactParamsChange,
  210. addExtractParameter,
  211. handleInstructionChange,
  212. hasSetBlockStatus,
  213. availableVars,
  214. availableNodesWithParent,
  215. isSupportFunctionCall,
  216. handleReasoningModeChange,
  217. handleMemoryChange,
  218. isVisionModel,
  219. handleVisionResolutionEnabledChange,
  220. handleVisionResolutionChange,
  221. }
  222. }
  223. export default useConfig