Browse Source

feat: question classify node support use var in instruction (#4710)

Joel 10 tháng trước cách đây
mục cha
commit
a38dfc006e

+ 5 - 1
web/app/components/workflow/nodes/_base/components/variable/utils.ts

@@ -511,7 +511,10 @@ export const getNodeUsedVars = (node: Node): ValueSelector[] => {
       break
     }
     case BlockEnum.QuestionClassifier: {
-      res = [(data as QuestionClassifierNodeType).query_variable_selector]
+      const payload = (data as QuestionClassifierNodeType)
+      res = [payload.query_variable_selector]
+      const varInInstructions = matchNotSystemVars([payload.instruction || ''])
+      res.push(...varInInstructions)
       break
     }
     case BlockEnum.HttpRequest: {
@@ -726,6 +729,7 @@ export const updateNodeVars = (oldNode: Node, oldVarSelector: ValueSelector, new
         const payload = data as QuestionClassifierNodeType
         if (payload.query_variable_selector.join('.') === oldVarSelector.join('.'))
           payload.query_variable_selector = newVarSelector
+        payload.instruction = replaceOldVarInText(payload.instruction, oldVarSelector, newVarSelector)
         break
       }
       case BlockEnum.HttpRequest: {

+ 24 - 13
web/app/components/workflow/nodes/question-classifier/components/advanced-setting.tsx

@@ -2,9 +2,9 @@
 import type { FC } from 'react'
 import React from 'react'
 import { useTranslation } from 'react-i18next'
-import TextEditor from '../../_base/components/editor/text-editor'
 import MemoryConfig from '../../_base/components/memory-config'
-import type { Memory } from '@/app/components/workflow/types'
+import Editor from '@/app/components/workflow/nodes/_base/components/prompt/editor'
+import type { Memory, Node, NodeOutPutVar } from '@/app/components/workflow/types'
 import TooltipPlus from '@/app/components/base/tooltip-plus'
 import { HelpCircle } from '@/app/components/base/icons/src/vender/line/general'
 const i18nPrefix = 'workflow.nodes.questionClassifiers'
@@ -16,6 +16,15 @@ type Props = {
   memory?: Memory
   onMemoryChange: (memory?: Memory) => void
   readonly?: boolean
+  isChatModel: boolean
+  isChatApp: boolean
+  hasSetBlockStatus?: {
+    context: boolean
+    history: boolean
+    query: boolean
+  }
+  nodesOutputVars: NodeOutPutVar[]
+  availableNodes: Node[]
 }
 
 const AdvancedSetting: FC<Props> = ({
@@ -25,13 +34,17 @@ const AdvancedSetting: FC<Props> = ({
   memory,
   onMemoryChange,
   readonly,
+  isChatModel,
+  isChatApp,
+  hasSetBlockStatus,
+  nodesOutputVars,
+  availableNodes,
 }) => {
   const { t } = useTranslation()
 
   return (
     <>
-      <TextEditor
-        isInNode
+      <Editor
         title={
           <div className='flex items-center space-x-1'>
             <span className='uppercase'>{t(`${i18nPrefix}.instruction`)}</span>
@@ -45,15 +58,13 @@ const AdvancedSetting: FC<Props> = ({
         }
         value={instruction}
         onChange={onInstructionChange}
-        minHeight={160}
-        placeholder={t(`${i18nPrefix}.instructionPlaceholder`)!}
-        headerRight={(
-          <div className='flex items-center h-full'>
-            <div className='text-xs font-medium text-gray-500'>{instruction?.length || 0}</div>
-            <div className='mx-3 h-3 w-px bg-gray-200'></div>
-          </div>
-        )}
-        readonly={readonly}
+        readOnly={readonly}
+        isChatModel={isChatModel}
+        isChatApp={isChatApp}
+        isShowContext={false}
+        hasSetBlockStatus={hasSetBlockStatus}
+        nodesOutputVars={nodesOutputVars}
+        availableNodes={availableNodes}
       />
       {!hideMemorySetting && (
         <MemoryConfig

+ 15 - 5
web/app/components/workflow/nodes/question-classifier/panel.tsx

@@ -27,18 +27,23 @@ const Panel: FC<NodePanelProps<QuestionClassifierNodeType>> = ({
     inputs,
     handleModelChanged,
     isChatMode,
+    isChatModel,
     handleCompletionParamsChange,
     handleQueryVarChange,
     handleTopicsChange,
+    hasSetBlockStatus,
+    availableVars,
+    availableNodesWithParent,
     handleInstructionChange,
+    inputVarValues,
+    varInputs,
+    setInputVarValues,
     handleMemoryChange,
     isShowSingleRun,
     hideSingleRun,
     runningStatus,
     handleRun,
     handleStop,
-    query,
-    setQuery,
     runResult,
     filterVar,
   } = useConfig(id, data)
@@ -99,6 +104,11 @@ const Panel: FC<NodePanelProps<QuestionClassifierNodeType>> = ({
             memory={inputs.memory}
             onMemoryChange={handleMemoryChange}
             readonly={readOnly}
+            isChatApp={isChatMode}
+            isChatModel={isChatModel}
+            hasSetBlockStatus={hasSetBlockStatus}
+            nodesOutputVars={availableVars}
+            availableNodes={availableNodesWithParent}
           />
         </Field>
       </div>
@@ -125,9 +135,9 @@ const Panel: FC<NodePanelProps<QuestionClassifierNodeType>> = ({
                 variable: 'query',
                 type: InputVarType.paragraph,
                 required: true,
-              }],
-              values: { query },
-              onChange: keyValue => setQuery((keyValue as any).query),
+              }, ...varInputs],
+              values: inputVarValues,
+              onChange: setInputVarValues,
             },
           ]}
           runningStatus={runningStatus}

+ 43 - 1
web/app/components/workflow/nodes/question-classifier/use-config.ts

@@ -7,11 +7,13 @@ import {
   useWorkflow,
 } from '../../hooks'
 import { useStore } from '../../store'
+import useAvailableVarList from '../_base/hooks/use-available-var-list'
 import type { QuestionClassifierNodeType } from './types'
 import useNodeCrud from '@/app/components/workflow/nodes/_base/hooks/use-node-crud'
 import useOneStepRun from '@/app/components/workflow/nodes/_base/hooks/use-one-step-run'
 import { useModelListAndDefaultModelAndCurrentProviderAndModel } from '@/app/components/header/account-setting/model-provider-page/hooks'
 import { ModelTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
+import { checkHasQueryBlock } from '@/app/components/base/prompt-editor/constants'
 
 const useConfig = (id: string, payload: QuestionClassifierNodeType) => {
   const { nodesReadOnly: readOnly } = useNodesReadOnly()
@@ -67,7 +69,6 @@ const useConfig = (id: string, payload: QuestionClassifierNodeType) => {
       draft.query_variable_selector = newVar as ValueSelector
     })
     setInputs(newInputs)
-    // console.log(newInputs.query_variable_selector)
   }, [inputs, setInputs])
 
   useEffect(() => {
@@ -93,6 +94,24 @@ const useConfig = (id: string, payload: QuestionClassifierNodeType) => {
     setInputs(newInputs)
   }, [inputs, setInputs])
 
+  const filterInputVar = useCallback((varPayload: Var) => {
+    return [VarType.number, VarType.string].includes(varPayload.type)
+  }, [])
+
+  const {
+    availableVars,
+    availableNodesWithParent,
+  } = useAvailableVarList(id, {
+    onlyLeafNodeVar: false,
+    filterVar: filterInputVar,
+  })
+
+  const hasSetBlockStatus = {
+    history: false,
+    query: isChatMode ? checkHasQueryBlock(inputs.instruction) : false,
+    context: false,
+  }
+
   const handleInstructionChange = useCallback((instruction: string) => {
     const newInputs = produce(inputs, (draft) => {
       draft.instruction = instruction
@@ -111,6 +130,7 @@ const useConfig = (id: string, payload: QuestionClassifierNodeType) => {
   const {
     isShowSingleRun,
     hideSingleRun,
+    getInputVars,
     runningStatus,
     handleRun,
     handleStop,
@@ -133,6 +153,22 @@ const useConfig = (id: string, payload: QuestionClassifierNodeType) => {
     })
   }, [runInputData, setRunInputData])
 
+  const varInputs = getInputVars([inputs.instruction])
+  const inputVarValues = (() => {
+    const vars: Record<string, any> = {
+      query,
+    }
+    Object.keys(runInputData)
+      .forEach((key) => {
+        vars[key] = runInputData[key]
+      })
+    return vars
+  })()
+
+  const setInputVarValues = useCallback((newPayload: Record<string, any>) => {
+    setRunInputData(newPayload)
+  }, [setRunInputData])
+
   const filterVar = useCallback((varPayload: Var) => {
     return varPayload.type === VarType.string
   }, [])
@@ -147,7 +183,13 @@ const useConfig = (id: string, payload: QuestionClassifierNodeType) => {
     handleQueryVarChange,
     filterVar,
     handleTopicsChange: handleClassesChange,
+    hasSetBlockStatus,
+    availableVars,
+    availableNodesWithParent,
     handleInstructionChange,
+    varInputs,
+    inputVarValues,
+    setInputVarValues,
     handleMemoryChange,
     isShowSingleRun,
     hideSingleRun,