【amc】 合并前端代码
parent
ae25db7ad1
commit
569f94280f
@ -0,0 +1,45 @@
|
|||||||
|
import type {NodeDefault} from '../../types'
|
||||||
|
import {BlockEnum} from '../../types'
|
||||||
|
import type {VannaNodeType} from './types'
|
||||||
|
import {ALL_CHAT_AVAILABLE_BLOCKS, ALL_COMPLETION_AVAILABLE_BLOCKS} from '@/app/components/workflow/blocks'
|
||||||
|
import {ReasoningModeType} from "@/app/components/workflow/nodes/parameter-extractor/types";
|
||||||
|
|
||||||
|
const nodeDefault: NodeDefault<VannaNodeType> = {
|
||||||
|
defaultValue: {
|
||||||
|
query: [],
|
||||||
|
model: {
|
||||||
|
provider: '',
|
||||||
|
name: '',
|
||||||
|
mode: 'chat',
|
||||||
|
completion_params: {
|
||||||
|
temperature: 0.7,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
reasoning_mode: ReasoningModeType.prompt,
|
||||||
|
vision: {
|
||||||
|
enabled: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
getAvailablePrevNodes(isChatMode: boolean) {
|
||||||
|
return isChatMode
|
||||||
|
? ALL_CHAT_AVAILABLE_BLOCKS
|
||||||
|
: ALL_COMPLETION_AVAILABLE_BLOCKS.filter(type => type !== BlockEnum.End)
|
||||||
|
},
|
||||||
|
getAvailableNextNodes(isChatMode: boolean) {
|
||||||
|
return isChatMode ? ALL_CHAT_AVAILABLE_BLOCKS : ALL_COMPLETION_AVAILABLE_BLOCKS
|
||||||
|
},
|
||||||
|
checkValid(payload: VannaNodeType) {
|
||||||
|
let isValid = true
|
||||||
|
let errorMessages = ''
|
||||||
|
if (!payload.query || payload.query.length === 0){
|
||||||
|
errorMessages = '输入变量不能为空'
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
isValid,
|
||||||
|
errorMessage: errorMessages,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export default nodeDefault
|
||||||
@ -0,0 +1,35 @@
|
|||||||
|
import type { FC } from 'react'
|
||||||
|
import React from 'react'
|
||||||
|
import type { VannaNodeType } from './types'
|
||||||
|
import type { NodeProps } from '@/app/components/workflow/types'
|
||||||
|
|
||||||
|
import ModelSelector from "@/app/components/header/account-setting/model-provider-page/model-selector";
|
||||||
|
import {
|
||||||
|
useTextGenerationCurrentProviderAndModelAndModelList
|
||||||
|
} from "@/app/components/header/account-setting/model-provider-page/hooks";
|
||||||
|
|
||||||
|
const Node: FC<NodeProps<VannaNodeType>> = ({
|
||||||
|
data,
|
||||||
|
}) => {
|
||||||
|
|
||||||
|
const { provider, name: modelId } = data.model || {}
|
||||||
|
const {
|
||||||
|
textGenerationModelList,
|
||||||
|
} = useTextGenerationCurrentProviderAndModelAndModelList()
|
||||||
|
const hasSetModel = provider && modelId
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='mb-1 space-y-0.5 px-3 py-1'>
|
||||||
|
{hasSetModel && (
|
||||||
|
<ModelSelector
|
||||||
|
defaultModel={{ provider, model: modelId }}
|
||||||
|
modelList={textGenerationModelList}
|
||||||
|
triggerClassName='!h-6 !rounded-md'
|
||||||
|
readonly
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default React.memo(Node)
|
||||||
@ -0,0 +1,155 @@
|
|||||||
|
import React, {FC} from 'react'
|
||||||
|
import {useTranslation} from 'react-i18next'
|
||||||
|
import useConfig from './use-config'
|
||||||
|
import type {VannaNodeType} from './types'
|
||||||
|
import Field from '@/app/components/workflow/nodes/_base/components/field'
|
||||||
|
import {InputVarType, NodePanelProps} from '@/app/components/workflow/types'
|
||||||
|
import ModelParameterModal from "@/app/components/header/account-setting/model-provider-page/model-parameter-modal";
|
||||||
|
import VarReferencePicker from "@/app/components/workflow/nodes/_base/components/variable/var-reference-picker";
|
||||||
|
import BeforeRunForm from "@/app/components/workflow/nodes/_base/components/before-run-form";
|
||||||
|
import ResultPanel from "@/app/components/workflow/run/result-panel";
|
||||||
|
import type {Props as FormProps} from "@/app/components/workflow/nodes/_base/components/before-run-form/form";
|
||||||
|
import {findVariableWhenOnLLMVision} from "@/app/components/workflow/nodes/utils";
|
||||||
|
import Split from "@/app/components/workflow/nodes/_base/components/split";
|
||||||
|
import OutputVars, {VarItem} from "@/app/components/workflow/nodes/_base/components/output-vars";
|
||||||
|
|
||||||
|
const i18nPrefix = 'workflow.nodes.parameterExtractor'
|
||||||
|
|
||||||
|
const Panel: FC<NodePanelProps<VannaNodeType>> = (
|
||||||
|
{
|
||||||
|
id,
|
||||||
|
data,
|
||||||
|
}) => {
|
||||||
|
const {t} = useTranslation()
|
||||||
|
|
||||||
|
const {
|
||||||
|
readOnly,
|
||||||
|
inputs,
|
||||||
|
handleCompletionParamsChange,
|
||||||
|
handleInputVarChange,
|
||||||
|
handleModelChanged,
|
||||||
|
isShowSingleRun,
|
||||||
|
hideSingleRun,
|
||||||
|
handleRun,
|
||||||
|
handleStop,
|
||||||
|
runResult,
|
||||||
|
runningStatus,
|
||||||
|
filterVar,
|
||||||
|
varInputs,
|
||||||
|
inputVarValues,
|
||||||
|
setInputVarValues,
|
||||||
|
isVisionModel,
|
||||||
|
availableVisionVars,
|
||||||
|
visionFiles,
|
||||||
|
setVisionFiles,
|
||||||
|
} = useConfig(id, data)
|
||||||
|
|
||||||
|
const model = inputs.model
|
||||||
|
|
||||||
|
const singleRunForms = (() => {
|
||||||
|
const forms: FormProps[] = []
|
||||||
|
|
||||||
|
forms.push(
|
||||||
|
{
|
||||||
|
label: t('workflow.nodes.llm.singleRun.variable')!,
|
||||||
|
inputs: [{
|
||||||
|
label: t(`${i18nPrefix}.inputVar`)!,
|
||||||
|
variable: 'query',
|
||||||
|
type: InputVarType.paragraph,
|
||||||
|
required: true,
|
||||||
|
}, ...varInputs],
|
||||||
|
values: inputVarValues,
|
||||||
|
onChange: setInputVarValues,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
if (isVisionModel && data.vision?.enabled && data.vision?.configs?.variable_selector) {
|
||||||
|
const currentVariable = findVariableWhenOnLLMVision(data.vision.configs.variable_selector, availableVisionVars)
|
||||||
|
|
||||||
|
forms.push(
|
||||||
|
{
|
||||||
|
label: t('workflow.nodes.llm.vision')!,
|
||||||
|
inputs: [{
|
||||||
|
label: currentVariable?.variable as any,
|
||||||
|
variable: '#files#',
|
||||||
|
type: currentVariable?.formType as any,
|
||||||
|
required: false,
|
||||||
|
}],
|
||||||
|
values: {'#files#': visionFiles},
|
||||||
|
onChange: keyValue => setVisionFiles((keyValue as any)['#files#']),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return forms
|
||||||
|
})()
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='mt-2'>
|
||||||
|
<div className='space-y-4 px-4 pb-4'>
|
||||||
|
<Field
|
||||||
|
title={'模型'}
|
||||||
|
>
|
||||||
|
<ModelParameterModal
|
||||||
|
popupClassName='!w-[387px]'
|
||||||
|
isInWorkflow
|
||||||
|
isAdvancedMode={true}
|
||||||
|
mode={model?.mode}
|
||||||
|
provider={model?.provider}
|
||||||
|
completionParams={model?.completion_params}
|
||||||
|
modelId={model?.name}
|
||||||
|
setModel={handleModelChanged}
|
||||||
|
onCompletionParamsChange={handleCompletionParamsChange}
|
||||||
|
hideDebugWithMultipleModel
|
||||||
|
debugWithMultipleModel={false}
|
||||||
|
readonly={readOnly}
|
||||||
|
/>
|
||||||
|
</Field>
|
||||||
|
|
||||||
|
<Field
|
||||||
|
title={'输入变量'}
|
||||||
|
>
|
||||||
|
<VarReferencePicker
|
||||||
|
readonly={readOnly}
|
||||||
|
nodeId={id}
|
||||||
|
isShowNodeName
|
||||||
|
value={inputs.query || []}
|
||||||
|
onChange={handleInputVarChange}
|
||||||
|
filterVar={filterVar}
|
||||||
|
/>
|
||||||
|
</Field>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<Split />
|
||||||
|
<div>
|
||||||
|
<OutputVars>
|
||||||
|
<VarItem
|
||||||
|
name='output'
|
||||||
|
type='string'
|
||||||
|
description={'查询出结果的数据'}
|
||||||
|
/>
|
||||||
|
<VarItem
|
||||||
|
name='sql'
|
||||||
|
type='string'
|
||||||
|
description={'生成的sql语句'}
|
||||||
|
/>
|
||||||
|
</OutputVars>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{isShowSingleRun && (
|
||||||
|
<BeforeRunForm
|
||||||
|
nodeName={inputs.title}
|
||||||
|
onHide={hideSingleRun}
|
||||||
|
forms={singleRunForms}
|
||||||
|
runningStatus={runningStatus}
|
||||||
|
onRun={handleRun}
|
||||||
|
onStop={handleStop}
|
||||||
|
result={<ResultPanel {...runResult} showSteps={false}/>}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default React.memo(Panel)
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
import type {
|
||||||
|
CommonNodeType,
|
||||||
|
Memory,
|
||||||
|
ModelConfig, ValueSelector,
|
||||||
|
VisionSetting
|
||||||
|
} from '@/app/components/workflow/types'
|
||||||
|
import {Param, ReasoningModeType} from "@/app/components/workflow/nodes/parameter-extractor/types";
|
||||||
|
|
||||||
|
export type VannaNodeType = CommonNodeType & {
|
||||||
|
model: ModelConfig
|
||||||
|
query: ValueSelector
|
||||||
|
instruction: string
|
||||||
|
reasoning_mode: ReasoningModeType
|
||||||
|
parameters: Param[]
|
||||||
|
memory?: Memory
|
||||||
|
vision: {
|
||||||
|
enabled: boolean
|
||||||
|
configs?: VisionSetting
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,162 @@
|
|||||||
|
import type {VannaNodeType} from './types'
|
||||||
|
import useNodeCrud from '@/app/components/workflow/nodes/_base/hooks/use-node-crud'
|
||||||
|
import {
|
||||||
|
useNodesReadOnly,
|
||||||
|
} from '@/app/components/workflow/hooks'
|
||||||
|
import {useCallback, useRef, useState} from "react";
|
||||||
|
import produce from "immer";
|
||||||
|
import {ValueSelector, Var, VarType} from "@/app/components/workflow/types";
|
||||||
|
import useOneStepRun from "@/app/components/workflow/nodes/_base/hooks/use-one-step-run";
|
||||||
|
import useConfigVision from "@/app/components/workflow/hooks/use-config-vision";
|
||||||
|
import useAvailableVarList from "@/app/components/workflow/nodes/_base/hooks/use-available-var-list";
|
||||||
|
|
||||||
|
const useConfig = (id: string, payload: VannaNodeType) => {
|
||||||
|
const {nodesReadOnly: readOnly} = useNodesReadOnly()
|
||||||
|
const {inputs, setInputs} = useNodeCrud<VannaNodeType>(id, payload)
|
||||||
|
const inputRef = useRef(inputs)
|
||||||
|
const [modelChanged, setModelChanged] = useState(false)
|
||||||
|
|
||||||
|
// model
|
||||||
|
const model = inputs.model || {
|
||||||
|
provider: '',
|
||||||
|
name: '',
|
||||||
|
mode: 'chat',
|
||||||
|
completion_params: {
|
||||||
|
temperature: 0.7,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const modelMode = inputs.model?.mode
|
||||||
|
|
||||||
|
// single run
|
||||||
|
const {
|
||||||
|
isShowSingleRun,
|
||||||
|
hideSingleRun,
|
||||||
|
getInputVars,
|
||||||
|
runningStatus,
|
||||||
|
handleRun,
|
||||||
|
handleStop,
|
||||||
|
runInputData,
|
||||||
|
runInputDataRef,
|
||||||
|
setRunInputData,
|
||||||
|
runResult,
|
||||||
|
} = useOneStepRun<VannaNodeType>({
|
||||||
|
id,
|
||||||
|
data: inputs,
|
||||||
|
defaultRunInputData: {
|
||||||
|
'query': '',
|
||||||
|
'#files#': [],
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const {
|
||||||
|
isVisionModel,
|
||||||
|
handleVisionResolutionEnabledChange,
|
||||||
|
handleVisionResolutionChange,
|
||||||
|
handleModelChanged: handleVisionConfigAfterModelChanged,
|
||||||
|
} = useConfigVision(model, {
|
||||||
|
payload: inputs.vision,
|
||||||
|
onChange: (newPayload) => {
|
||||||
|
const newInputs = produce(inputs, (draft) => {
|
||||||
|
draft.vision = newPayload
|
||||||
|
})
|
||||||
|
setInputs(newInputs)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
const filterVisionInputVar = useCallback((varPayload: Var) => {
|
||||||
|
return [VarType.file, VarType.arrayFile].includes(varPayload.type)
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
|
||||||
|
const {
|
||||||
|
availableVars: availableVisionVars,
|
||||||
|
} = useAvailableVarList(id, {
|
||||||
|
onlyLeafNodeVar: false,
|
||||||
|
filterVar: filterVisionInputVar,
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
const handleModelChanged = useCallback((model: { provider: string; modelId: string; mode?: string }) => {
|
||||||
|
const newInputs = produce(inputRef.current, (draft) => {
|
||||||
|
draft.model.provider = model.provider
|
||||||
|
draft.model.name = model.modelId
|
||||||
|
draft.model.mode = model.mode!
|
||||||
|
})
|
||||||
|
setInputs(newInputs)
|
||||||
|
setModelChanged(true)
|
||||||
|
}, [setInputs])
|
||||||
|
|
||||||
|
|
||||||
|
const handleCompletionParamsChange = useCallback((newParams: Record<string, any>) => {
|
||||||
|
debugger
|
||||||
|
const newInputs = produce(inputs, (draft) => {
|
||||||
|
draft.model.completion_params = newParams
|
||||||
|
})
|
||||||
|
setInputs(newInputs)
|
||||||
|
}, [inputs, setInputs])
|
||||||
|
|
||||||
|
const handleInputVarChange = useCallback((newInputVar: ValueSelector | string) => {
|
||||||
|
const newInputs = produce(inputs, (draft) => {
|
||||||
|
draft.query = newInputVar as ValueSelector || []
|
||||||
|
})
|
||||||
|
setInputs(newInputs)
|
||||||
|
}, [inputs, setInputs])
|
||||||
|
|
||||||
|
const filterVar = useCallback((varPayload: Var) => {
|
||||||
|
return [VarType.string].includes(varPayload.type)
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const varInputs = getInputVars([inputs.instruction])
|
||||||
|
const inputVarValues = (() => {
|
||||||
|
const vars: Record<string, any> = {}
|
||||||
|
Object.keys(runInputData)
|
||||||
|
.forEach((key) => {
|
||||||
|
vars[key] = runInputData[key]
|
||||||
|
})
|
||||||
|
return vars
|
||||||
|
})()
|
||||||
|
|
||||||
|
|
||||||
|
const setInputVarValues = useCallback((newPayload: Record<string, any>) => {
|
||||||
|
setRunInputData(newPayload)
|
||||||
|
}, [setRunInputData])
|
||||||
|
|
||||||
|
const visionFiles = runInputData['#files#']
|
||||||
|
const setVisionFiles = useCallback((newFiles: any[]) => {
|
||||||
|
setRunInputData({
|
||||||
|
...runInputDataRef.current,
|
||||||
|
'#files#': newFiles,
|
||||||
|
})
|
||||||
|
}, [runInputDataRef, setRunInputData])
|
||||||
|
|
||||||
|
|
||||||
|
return {
|
||||||
|
readOnly,
|
||||||
|
inputs,
|
||||||
|
filterVar,
|
||||||
|
isShowSingleRun,
|
||||||
|
hideSingleRun,
|
||||||
|
getInputVars,
|
||||||
|
runningStatus,
|
||||||
|
handleRun,
|
||||||
|
handleStop,
|
||||||
|
runInputData,
|
||||||
|
runInputDataRef,
|
||||||
|
setRunInputData,
|
||||||
|
isVisionModel,
|
||||||
|
runResult,
|
||||||
|
varInputs,
|
||||||
|
inputVarValues,
|
||||||
|
setInputVarValues,
|
||||||
|
handleModelChanged,
|
||||||
|
handleInputVarChange,
|
||||||
|
handleCompletionParamsChange,
|
||||||
|
availableVisionVars,
|
||||||
|
visionFiles,
|
||||||
|
setVisionFiles
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default useConfig
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
import type {VannaNodeType} from './types'
|
||||||
|
|
||||||
|
export const checkNodeValid = (payload: VannaNodeType) => {
|
||||||
|
return true
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue