Skip to content

Commit 2fe9fe0

Browse files
zxhlyhchinnsenn
authored and
chinnsenn
committed
fix: one step run (langgenius#14724)
1 parent f1bb57f commit 2fe9fe0

File tree

10 files changed

+214
-49
lines changed

10 files changed

+214
-49
lines changed

web/app/components/workflow/nodes/_base/components/before-run-form/form-item.tsx

+20-9
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use client'
22
import type { FC } from 'react'
3-
import React, { useCallback } from 'react'
3+
import React, { useCallback, useMemo } from 'react'
44
import { useTranslation } from 'react-i18next'
55
import produce from 'immer'
66
import {
@@ -24,8 +24,9 @@ import { Variable02 } from '@/app/components/base/icons/src/vender/solid/develop
2424
import { BubbleX } from '@/app/components/base/icons/src/vender/line/others'
2525
import { FILE_EXTS } from '@/app/components/base/prompt-editor/constants'
2626
import cn from '@/utils/classnames'
27+
import type { FileEntity } from '@/app/components/base/file-uploader/types'
2728

28-
interface Props {
29+
type Props = {
2930
payload: InputVar
3031
value: any
3132
onChange: (value: any) => void
@@ -94,6 +95,21 @@ const FormItem: FC<Props> = ({
9495
const isArrayLikeType = [InputVarType.contexts, InputVarType.iterator].includes(type)
9596
const isContext = type === InputVarType.contexts
9697
const isIterator = type === InputVarType.iterator
98+
const singleFileValue = useMemo(() => {
99+
if (payload.variable === '#files#')
100+
return value?.[0] || []
101+
102+
return value ? [value] : []
103+
}, [payload.variable, value])
104+
const handleSingleFileChange = useCallback((files: FileEntity[]) => {
105+
if (payload.variable === '#files#')
106+
onChange(files)
107+
else if (files.length)
108+
onChange(files[0])
109+
else
110+
onChange(null)
111+
}, [onChange, payload.variable])
112+
97113
return (
98114
<div className={cn(className)}>
99115
{!isArrayLikeType && (
@@ -161,13 +177,8 @@ const FormItem: FC<Props> = ({
161177
}
162178
{(type === InputVarType.singleFile) && (
163179
<FileUploaderInAttachmentWrapper
164-
value={value ? [value] : []}
165-
onChange={(files) => {
166-
if (files.length)
167-
onChange(files[0])
168-
else
169-
onChange(null)
170-
}}
180+
value={singleFileValue}
181+
onChange={handleSingleFileChange}
171182
fileConfig={{
172183
allowed_file_types: inStepRun
173184
? [

web/app/components/workflow/nodes/_base/components/before-run-form/index.tsx

+4-1
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,11 @@ function formatValue(value: string | any, type: InputVarType) {
5050
if (type === InputVarType.multiFiles)
5151
return getProcessedFiles(value)
5252

53-
if (type === InputVarType.singleFile)
53+
if (type === InputVarType.singleFile) {
54+
if (Array.isArray(value))
55+
return getProcessedFiles(value)
5456
return getProcessedFiles([value])[0]
57+
}
5558

5659
return value
5760
}

web/app/components/workflow/nodes/_base/hooks/use-one-step-run.ts

+8-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useEffect, useState } from 'react'
1+
import { useCallback, useEffect, useRef, useState } from 'react'
22
import { useTranslation } from 'react-i18next'
33
import { unionBy } from 'lodash-es'
44
import produce from 'immer'
@@ -139,6 +139,11 @@ const useOneStepRun = <T>({
139139
const checkValid = checkValidFns[data.type]
140140
const appId = useAppStore.getState().appDetail?.id
141141
const [runInputData, setRunInputData] = useState<Record<string, any>>(defaultRunInputData || {})
142+
const runInputDataRef = useRef(runInputData)
143+
const handleSetRunInputData = useCallback((data: Record<string, any>) => {
144+
runInputDataRef.current = data
145+
setRunInputData(data)
146+
}, [])
142147
const iterationTimes = iteratorInputKey ? runInputData[iteratorInputKey].length : 0
143148
const [runResult, setRunResult] = useState<any>(null)
144149

@@ -421,7 +426,8 @@ const useOneStepRun = <T>({
421426
handleRun,
422427
handleStop,
423428
runInputData,
424-
setRunInputData,
429+
runInputDataRef,
430+
setRunInputData: handleSetRunInputData,
425431
runResult,
426432
iterationRunResult,
427433
}

web/app/components/workflow/nodes/llm/panel.tsx

+6-4
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import MemoryConfig from '../_base/components/memory-config'
55
import VarReferencePicker from '../_base/components/variable/var-reference-picker'
66
import ConfigVision from '../_base/components/config-vision'
77
import useConfig from './use-config'
8+
import { findVariableWhenOnLLMVision } from '../utils'
89
import type { LLMNodeType } from './types'
910
import ConfigPrompt from './components/config-prompt'
1011
import VarList from '@/app/components/workflow/nodes/_base/components/variable/var-list'
@@ -102,15 +103,16 @@ const Panel: FC<NodePanelProps<LLMNodeType>> = ({
102103
)
103104
}
104105

105-
if (isVisionModel) {
106-
const variableName = data.vision.configs?.variable_selector?.[1] || t(`${i18nPrefix}.files`)!
106+
if (isVisionModel && data.vision.enabled && data.vision.configs?.variable_selector) {
107+
const currentVariable = findVariableWhenOnLLMVision(data.vision.configs.variable_selector, availableVars)
108+
107109
forms.push(
108110
{
109111
label: t(`${i18nPrefix}.vision`)!,
110112
inputs: [{
111-
label: variableName!,
113+
label: currentVariable?.variable as any,
112114
variable: '#files#',
113-
type: InputVarType.files,
115+
type: currentVariable?.formType as any,
114116
required: false,
115117
}],
116118
values: { '#files#': visionFiles },

web/app/components/workflow/nodes/llm/use-config.ts

+8-7
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,7 @@ const useConfig = (id: string, payload: LLMNodeType) => {
306306
handleRun,
307307
handleStop,
308308
runInputData,
309+
runInputDataRef,
309310
setRunInputData,
310311
runResult,
311312
toVarInputs,
@@ -331,27 +332,27 @@ const useConfig = (id: string, payload: LLMNodeType) => {
331332
const setInputVarValues = useCallback((newPayload: Record<string, any>) => {
332333
const newVars = {
333334
...newPayload,
334-
'#context#': runInputData['#context#'],
335-
'#files#': runInputData['#files#'],
335+
'#context#': runInputDataRef.current['#context#'],
336+
'#files#': runInputDataRef.current['#files#'],
336337
}
337338
setRunInputData(newVars)
338-
}, [runInputData, setRunInputData])
339+
}, [runInputDataRef, setRunInputData])
339340

340341
const contexts = runInputData['#context#']
341342
const setContexts = useCallback((newContexts: string[]) => {
342343
setRunInputData({
343-
...runInputData,
344+
...runInputDataRef.current,
344345
'#context#': newContexts,
345346
})
346-
}, [runInputData, setRunInputData])
347+
}, [runInputDataRef, setRunInputData])
347348

348349
const visionFiles = runInputData['#files#']
349350
const setVisionFiles = useCallback((newFiles: any[]) => {
350351
setRunInputData({
351-
...runInputData,
352+
...runInputDataRef.current,
352353
'#files#': newFiles,
353354
})
354-
}, [runInputData, setRunInputData])
355+
}, [runInputDataRef, setRunInputData])
355356

356357
const allVarStrArr = (() => {
357358
const arr = isChatModel ? (inputs.prompt_template as PromptItem[]).filter(item => item.edition_type !== EditionType.jinja2).map(item => item.text) : [(inputs.prompt_template as PromptItem).text]

web/app/components/workflow/nodes/parameter-extractor/panel.tsx

+44-12
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import VarReferencePicker from '../_base/components/variable/var-reference-picke
66
import Editor from '../_base/components/prompt/editor'
77
import ResultPanel from '../../run/result-panel'
88
import ConfigVision from '../_base/components/config-vision'
9+
import { findVariableWhenOnLLMVision } from '../utils'
910
import useConfig from './use-config'
1011
import type { ParameterExtractorNodeType } from './types'
1112
import ExtractParameter from './components/extract-parameter/list'
@@ -21,6 +22,7 @@ import Tooltip from '@/app/components/base/tooltip'
2122
import BeforeRunForm from '@/app/components/workflow/nodes/_base/components/before-run-form'
2223
import { VarType } from '@/app/components/workflow/types'
2324
import { FieldCollapse } from '@/app/components/workflow/nodes/_base/components/collapse'
25+
import type { Props as FormProps } from '@/app/components/workflow/nodes/_base/components/before-run-form/form'
2426

2527
const i18nPrefix = 'workflow.nodes.parameterExtractor'
2628
const i18nCommonPrefix = 'workflow.common'
@@ -51,6 +53,7 @@ const Panel: FC<NodePanelProps<ParameterExtractorNodeType>> = ({
5153
handleReasoningModeChange,
5254
availableVars,
5355
availableNodesWithParent,
56+
availableVisionVars,
5457
inputVarValues,
5558
varInputs,
5659
isVisionModel,
@@ -63,10 +66,50 @@ const Panel: FC<NodePanelProps<ParameterExtractorNodeType>> = ({
6366
handleStop,
6467
runResult,
6568
setInputVarValues,
69+
visionFiles,
70+
setVisionFiles,
6671
} = useConfig(id, data)
6772

6873
const model = inputs.model
6974

75+
const singleRunForms = (() => {
76+
const forms: FormProps[] = []
77+
78+
forms.push(
79+
{
80+
label: t('workflow.nodes.llm.singleRun.variable')!,
81+
inputs: [{
82+
label: t(`${i18nPrefix}.inputVar`)!,
83+
variable: 'query',
84+
type: InputVarType.paragraph,
85+
required: true,
86+
}, ...varInputs],
87+
values: inputVarValues,
88+
onChange: setInputVarValues,
89+
},
90+
)
91+
92+
if (isVisionModel && data.vision.enabled && data.vision.configs?.variable_selector) {
93+
const currentVariable = findVariableWhenOnLLMVision(data.vision.configs.variable_selector, availableVisionVars)
94+
95+
forms.push(
96+
{
97+
label: t('workflow.nodes.llm.vision')!,
98+
inputs: [{
99+
label: currentVariable?.variable as any,
100+
variable: '#files#',
101+
type: currentVariable?.formType as any,
102+
required: false,
103+
}],
104+
values: { '#files#': visionFiles },
105+
onChange: keyValue => setVisionFiles((keyValue as any)['#files#']),
106+
},
107+
)
108+
}
109+
110+
return forms
111+
})()
112+
70113
return (
71114
<div className='pt-2'>
72115
<div className='px-4 space-y-4'>
@@ -213,18 +256,7 @@ const Panel: FC<NodePanelProps<ParameterExtractorNodeType>> = ({
213256
<BeforeRunForm
214257
nodeName={inputs.title}
215258
onHide={hideSingleRun}
216-
forms={[
217-
{
218-
inputs: [{
219-
label: t(`${i18nPrefix}.inputVar`)!,
220-
variable: 'query',
221-
type: InputVarType.paragraph,
222-
required: true,
223-
}, ...varInputs],
224-
values: inputVarValues,
225-
onChange: setInputVarValues,
226-
},
227-
]}
259+
forms={singleRunForms}
228260
runningStatus={runningStatus}
229261
onRun={handleRun}
230262
onStop={handleStop}

web/app/components/workflow/nodes/parameter-extractor/use-config.ts

+25-1
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,10 @@ const useConfig = (id: string, payload: ParameterExtractorNodeType) => {
165165
return [VarType.number, VarType.string].includes(varPayload.type)
166166
}, [])
167167

168+
const filterVisionInputVar = useCallback((varPayload: Var) => {
169+
return [VarType.file, VarType.arrayFile].includes(varPayload.type)
170+
}, [])
171+
168172
const {
169173
availableVars,
170174
availableNodesWithParent,
@@ -173,6 +177,13 @@ const useConfig = (id: string, payload: ParameterExtractorNodeType) => {
173177
filterVar: filterInputVar,
174178
})
175179

180+
const {
181+
availableVars: availableVisionVars,
182+
} = useAvailableVarList(id, {
183+
onlyLeafNodeVar: false,
184+
filterVar: filterVisionInputVar,
185+
})
186+
176187
const handleCompletionParamsChange = useCallback((newParams: Record<string, any>) => {
177188
const newInputs = produce(inputs, (draft) => {
178189
draft.model.completion_params = newParams
@@ -223,13 +234,15 @@ const useConfig = (id: string, payload: ParameterExtractorNodeType) => {
223234
handleRun,
224235
handleStop,
225236
runInputData,
237+
runInputDataRef,
226238
setRunInputData,
227239
runResult,
228240
} = useOneStepRun<ParameterExtractorNodeType>({
229241
id,
230242
data: inputs,
231243
defaultRunInputData: {
232-
query: '',
244+
'query': '',
245+
'#files#': [],
233246
},
234247
})
235248

@@ -247,6 +260,14 @@ const useConfig = (id: string, payload: ParameterExtractorNodeType) => {
247260
setRunInputData(newPayload)
248261
}, [setRunInputData])
249262

263+
const visionFiles = runInputData['#files#']
264+
const setVisionFiles = useCallback((newFiles: any[]) => {
265+
setRunInputData({
266+
...runInputDataRef.current,
267+
'#files#': newFiles,
268+
})
269+
}, [runInputDataRef, setRunInputData])
270+
250271
return {
251272
readOnly,
252273
handleInputVarChange,
@@ -264,6 +285,7 @@ const useConfig = (id: string, payload: ParameterExtractorNodeType) => {
264285
hasSetBlockStatus,
265286
availableVars,
266287
availableNodesWithParent,
288+
availableVisionVars,
267289
isSupportFunctionCall,
268290
handleReasoningModeChange,
269291
handleMemoryChange,
@@ -279,6 +301,8 @@ const useConfig = (id: string, payload: ParameterExtractorNodeType) => {
279301
handleStop,
280302
runResult,
281303
setInputVarValues,
304+
visionFiles,
305+
setVisionFiles,
282306
}
283307
}
284308

0 commit comments

Comments
 (0)