Compare commits
4 Commits
0efb041c71
...
35c5150a1f
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
35c5150a1f | ||
|
|
a7b245a670 | ||
|
|
df8270676a | ||
|
|
b0e4f5853e |
@@ -1,10 +1,11 @@
|
|||||||
import {type Edge, getIncomers, type Node} from '@xyflow/react'
|
import {type Edge, getIncomers, type Node} from '@xyflow/react'
|
||||||
import type {Option} from 'amis/lib/Schema'
|
import type {Option} from 'amis/lib/Schema'
|
||||||
import {find, has, isEmpty, isEqual, max, min, unique} from 'licia'
|
import {find, has, isEqual, max, min, unique} from 'licia'
|
||||||
import {type DependencyList, type MouseEvent as ReactMouseEvent, useCallback, useRef} from 'react'
|
import {type DependencyList, type MouseEvent as ReactMouseEvent, useCallback, useRef} from 'react'
|
||||||
import Queue from 'yocto-queue'
|
import Queue from 'yocto-queue'
|
||||||
|
import {originTypeMap} from '../../pages/ai/task/InputSchema.tsx'
|
||||||
import {useFlowStore} from './store/FlowStore.ts'
|
import {useFlowStore} from './store/FlowStore.ts'
|
||||||
import type {InputFormOptions, InputFormOptionsGroup} from './types.ts'
|
import {type OutputVariable} from './types.ts'
|
||||||
|
|
||||||
export const getAllIncomerNodeById: (id: string, nodes: Node[], edges: Edge[]) => string[] = (id, nodes, edges) => {
|
export const getAllIncomerNodeById: (id: string, nodes: Node[], edges: Edge[]) => string[] = (id, nodes, edges) => {
|
||||||
let queue = new Queue<Node>()
|
let queue = new Queue<Node>()
|
||||||
@@ -20,36 +21,17 @@ export const getAllIncomerNodeById: (id: string, nodes: Node[], edges: Edge[]) =
|
|||||||
return unique(result, (a, b) => isEqual(a, b))
|
return unique(result, (a, b) => isEqual(a, b))
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getAllIncomerNodeOutputVariables: (id: string, nodes: Node[], edges: Edge[], data: any) => {
|
export const getAllIncomerNodeOutputVariables: (id: string, inputSchema: Record<string, Record<string, any>>, nodes: Node[], edges: Edge[], data: any) => OutputVariable[] = (id, inputSchema, nodes, edges, data) => {
|
||||||
id: string,
|
let inputSchemaVariables: OutputVariable[] = Object.keys(inputSchema).map(key => ({
|
||||||
variable: string
|
group: '流程入参',
|
||||||
}[] = (id, nodes, edges, data) => {
|
name: `${key}${inputSchema[key]?.label ? ` (${inputSchema[key].label})` : ''}`,
|
||||||
let incomerIds = getAllIncomerNodeById(id, nodes, edges)
|
type: originTypeMap[inputSchema[key]?.type ?? ''],
|
||||||
let incomerVariables: { id: string, variable: string }[] = []
|
variable: key,
|
||||||
for (const incomerId of incomerIds) {
|
|
||||||
let nodeData = data[incomerId] ?? {}
|
|
||||||
if (has(nodeData, 'outputs')) {
|
|
||||||
let outputs = nodeData?.outputs ?? []
|
|
||||||
for (const output of Object.keys(outputs)) {
|
|
||||||
incomerVariables.push({
|
|
||||||
id: incomerId,
|
|
||||||
variable: output,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return incomerVariables
|
|
||||||
}
|
|
||||||
|
|
||||||
export const generateAllIncomerOutputVariablesFormOptions: (id: string, inputSchema: Record<string, Record<string, any>>, nodes: Node[], edges: Edge[], data: any) => Option[] = (id, inputSchema, nodes, edges, data) => {
|
|
||||||
let inputSchemaVariables: InputFormOptions[] = Object.keys(inputSchema).map(key => ({
|
|
||||||
label: `${key} (${inputSchema[key]?.label ?? ''})`,
|
|
||||||
value: key,
|
|
||||||
}))
|
}))
|
||||||
|
|
||||||
let currentNode = find(nodes, n => isEqual(id, n.id))
|
let currentNode = find(nodes, n => isEqual(id, n.id))
|
||||||
if (!currentNode) {
|
if (!currentNode) {
|
||||||
return []
|
return inputSchemaVariables
|
||||||
}
|
}
|
||||||
|
|
||||||
let incomerIds = getAllIncomerNodeById(id, nodes, edges)
|
let incomerIds = getAllIncomerNodeById(id, nodes, edges)
|
||||||
@@ -60,7 +42,7 @@ export const generateAllIncomerOutputVariablesFormOptions: (id: string, inputSch
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
let incomerVariables: InputFormOptionsGroup[] = []
|
let incomerVariables: OutputVariable[] = []
|
||||||
for (const incomerId of incomerIds) {
|
for (const incomerId of incomerIds) {
|
||||||
let nodeData = data[incomerId] ?? {}
|
let nodeData = data[incomerId] ?? {}
|
||||||
let group = incomerId
|
let group = incomerId
|
||||||
@@ -68,48 +50,73 @@ export const generateAllIncomerOutputVariablesFormOptions: (id: string, inputSch
|
|||||||
group = `${nodeData.node.name} ${incomerId}`
|
group = `${nodeData.node.name} ${incomerId}`
|
||||||
}
|
}
|
||||||
if (has(nodeData, 'outputs')) {
|
if (has(nodeData, 'outputs')) {
|
||||||
let outputs = nodeData?.outputs ?? []
|
let outputs = nodeData?.outputs ?? {}
|
||||||
|
for (const key of Object.keys(outputs)) {
|
||||||
incomerVariables.push({
|
incomerVariables.push({
|
||||||
group: group,
|
group: group,
|
||||||
variables: Object.keys(outputs).map(key => ({
|
name: key,
|
||||||
value: `${incomerId}.${key}`,
|
type: outputs[key].type,
|
||||||
label: key,
|
variable: `${incomerId}.${key}`,
|
||||||
})),
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let inputVariables = [
|
return [
|
||||||
...(isEmpty(inputSchemaVariables) ? [] : [
|
...inputSchemaVariables,
|
||||||
{
|
|
||||||
group: '流程入参',
|
|
||||||
variables: inputSchemaVariables,
|
|
||||||
},
|
|
||||||
]),
|
|
||||||
...(currentNode.parentId ? [
|
...(currentNode.parentId ? [
|
||||||
{
|
{
|
||||||
group: '循环入参',
|
group: '循环入参',
|
||||||
variables: [
|
name: 'loopIndex (当前迭代索引)',
|
||||||
|
type: 'number',
|
||||||
|
variable: 'loopIndex',
|
||||||
|
} as OutputVariable,
|
||||||
{
|
{
|
||||||
label: 'loopIndex (当前迭代索引)',
|
group: '循环入参',
|
||||||
value: 'loopIndex',
|
name: 'loopItem (当前迭代对象)',
|
||||||
},
|
type: 'object',
|
||||||
{
|
variable: 'loopItem',
|
||||||
label: 'loopItem (当前迭代对象)',
|
} as OutputVariable,
|
||||||
value: 'loopItem',
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
] : []),
|
] : []),
|
||||||
...incomerVariables,
|
...incomerVariables,
|
||||||
]
|
]
|
||||||
|
}
|
||||||
|
|
||||||
return [
|
export const generateAllIncomerOutputVariablesFormOptions: (id: string, inputSchema: Record<string, Record<string, any>>, nodes: Node[], edges: Edge[], data: any) => Option[] = (id, inputSchema, nodes, edges, data) => {
|
||||||
...inputVariables.map(item => ({
|
let optionMap: Record<string, Option[]> = {}
|
||||||
label: item.group,
|
for (const item of getAllIncomerNodeOutputVariables(id, inputSchema, nodes, edges, data)) {
|
||||||
children: item.variables,
|
if (!optionMap[item.group]) {
|
||||||
})),
|
optionMap[item.group] = []
|
||||||
]
|
}
|
||||||
|
optionMap[item.group].push({
|
||||||
|
label: item.name,
|
||||||
|
value: item.variable,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return Object.keys(optionMap)
|
||||||
|
.map(key => ({
|
||||||
|
label: key,
|
||||||
|
children: optionMap[key],
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
export const generateAllIncomerOutputVariablesConditions: (id: string, inputSchema: Record<string, Record<string, any>>, nodes: Node[], edges: Edge[], data: any) => Option[] = (id, inputSchema, nodes, edges, data) => {
|
||||||
|
let optionMap: Record<string, Option[]> = {}
|
||||||
|
for (const item of getAllIncomerNodeOutputVariables(id, inputSchema, nodes, edges, data)) {
|
||||||
|
if (!optionMap[item.group]) {
|
||||||
|
optionMap[item.group] = []
|
||||||
|
}
|
||||||
|
optionMap[item.group].push({
|
||||||
|
label: item.name,
|
||||||
|
type: item.type,
|
||||||
|
name: item.variable,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return Object.keys(optionMap)
|
||||||
|
.map(key => ({
|
||||||
|
label: key,
|
||||||
|
children: optionMap[key],
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
// 处理循环节点的边界问题
|
// 处理循环节点的边界问题
|
||||||
|
|||||||
@@ -15,10 +15,7 @@ const inputSingleVariableChecker: (field: string) => NodeChecker = field => {
|
|||||||
if (has(nodeData, field)) {
|
if (has(nodeData, field)) {
|
||||||
let expression = nodeData?.[field] ?? ''
|
let expression = nodeData?.[field] ?? ''
|
||||||
if (!isEmpty(expression)) {
|
if (!isEmpty(expression)) {
|
||||||
let outputVariables = new Set([
|
let outputVariables = new Set(getAllIncomerNodeOutputVariables(id, inputSchema, nodes, edges, data).map(i => i.variable))
|
||||||
...getAllIncomerNodeOutputVariables(id, nodes, edges, data).map(i => `${i.id}.${i.variable}`),
|
|
||||||
...Object.keys(inputSchema),
|
|
||||||
])
|
|
||||||
if (!outputVariables.has(expression)) {
|
if (!outputVariables.has(expression)) {
|
||||||
return {
|
return {
|
||||||
error: true,
|
error: true,
|
||||||
@@ -36,10 +33,7 @@ const inputMultiVariableChecker: NodeChecker = (id, inputSchema, nodes, edges, d
|
|||||||
if (has(nodeData, 'inputs')) {
|
if (has(nodeData, 'inputs')) {
|
||||||
let inputs = nodeData?.inputs ?? {}
|
let inputs = nodeData?.inputs ?? {}
|
||||||
if (!isEmpty(inputs)) {
|
if (!isEmpty(inputs)) {
|
||||||
let outputVariables = new Set([
|
let outputVariables = new Set(getAllIncomerNodeOutputVariables(id, inputSchema, nodes, edges, data).map(i => i.variable))
|
||||||
...getAllIncomerNodeOutputVariables(id, nodes, edges, data).map(i => `${i.id}.${i.variable}`),
|
|
||||||
...Object.keys(inputSchema),
|
|
||||||
])
|
|
||||||
for (const key of Object.keys(inputs)) {
|
for (const key of Object.keys(inputs)) {
|
||||||
let variable = inputs[key]?.variable ?? ''
|
let variable = inputs[key]?.variable ?? ''
|
||||||
if (!outputVariables.has(variable)) {
|
if (!outputVariables.has(variable)) {
|
||||||
|
|||||||
@@ -1,20 +1,21 @@
|
|||||||
|
import {PlusCircleFilled} from '@ant-design/icons'
|
||||||
|
import {Button, Dropdown} from 'antd'
|
||||||
|
import type {ButtonProps} from 'antd/lib'
|
||||||
import {isEqual, randomId, unique} from 'licia'
|
import {isEqual, randomId, unique} from 'licia'
|
||||||
import {NodeRegistry, NodeRegistryMap} from '../NodeRegistry.tsx'
|
|
||||||
import {commonInfo} from '../../../util/amis.tsx'
|
import {commonInfo} from '../../../util/amis.tsx'
|
||||||
import {checkAddNode} from '../FlowChecker.tsx'
|
import {checkAddNode} from '../FlowChecker.tsx'
|
||||||
import {Button, Dropdown} from 'antd'
|
import {NodeRegistry, NodeRegistryMap} from '../NodeRegistry.tsx'
|
||||||
import {PlusCircleFilled} from '@ant-design/icons'
|
|
||||||
import {useDataStore} from '../store/DataStore.ts'
|
import {useDataStore} from '../store/DataStore.ts'
|
||||||
import {useFlowStore} from '../store/FlowStore.ts'
|
import {useFlowStore} from '../store/FlowStore.ts'
|
||||||
import type {ButtonProps} from 'antd/lib'
|
|
||||||
|
|
||||||
export type AddNodeButtonProps = {
|
export type AddNodeButtonProps = ButtonProps & {
|
||||||
parent?: string
|
parent?: string
|
||||||
} & ButtonProps
|
onlyIcon?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
const AddNodeButton = (props: AddNodeButtonProps) => {
|
const AddNodeButton = (props: AddNodeButtonProps) => {
|
||||||
const {data, setDataById} = useDataStore()
|
const {data, setDataById} = useDataStore()
|
||||||
const {nodes, addNode, edges,} = useFlowStore()
|
const {nodes, addNode, edges} = useFlowStore()
|
||||||
return (
|
return (
|
||||||
<Dropdown
|
<Dropdown
|
||||||
menu={{
|
menu={{
|
||||||
@@ -57,7 +58,7 @@ const AddNodeButton = (props: AddNodeButtonProps) => {
|
|||||||
...(props.parent ? {
|
...(props.parent ? {
|
||||||
parentId: props.parent,
|
parentId: props.parent,
|
||||||
extent: 'parent',
|
extent: 'parent',
|
||||||
} : {})
|
} : {}),
|
||||||
})
|
})
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
@@ -68,7 +69,7 @@ const AddNodeButton = (props: AddNodeButtonProps) => {
|
|||||||
>
|
>
|
||||||
<Button {...props}>
|
<Button {...props}>
|
||||||
<PlusCircleFilled/>
|
<PlusCircleFilled/>
|
||||||
新增节点
|
{props.onlyIcon ? undefined : '新增节点'}
|
||||||
</Button>
|
</Button>
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import {amisRender, commonInfo, horizontalFormOptions} from '../../../util/amis.
|
|||||||
import {generateAllIncomerOutputVariablesFormOptions} from '../Helper.tsx'
|
import {generateAllIncomerOutputVariablesFormOptions} from '../Helper.tsx'
|
||||||
import {useDataStore} from '../store/DataStore.ts'
|
import {useDataStore} from '../store/DataStore.ts'
|
||||||
import {useFlowStore} from '../store/FlowStore.ts'
|
import {useFlowStore} from '../store/FlowStore.ts'
|
||||||
|
import {OutputVariableTypeMap} from '../types.ts'
|
||||||
|
|
||||||
export function inputsFormColumns(
|
export function inputsFormColumns(
|
||||||
nodeId: string,
|
nodeId: string,
|
||||||
@@ -70,24 +71,11 @@ export function outputsFormColumns(editable: boolean = false, required: boolean
|
|||||||
label: '参数',
|
label: '参数',
|
||||||
required: true,
|
required: true,
|
||||||
selectFirst: true,
|
selectFirst: true,
|
||||||
options: [
|
options: Object.keys(OutputVariableTypeMap).map(key => ({
|
||||||
{
|
// @ts-ignore
|
||||||
label: '文本',
|
label: OutputVariableTypeMap[key],
|
||||||
value: 'string',
|
value: key,
|
||||||
},
|
})),
|
||||||
{
|
|
||||||
label: '数字',
|
|
||||||
value: 'number',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '文本数组',
|
|
||||||
value: 'array-string',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '对象数组',
|
|
||||||
value: 'array-object',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,17 +1,52 @@
|
|||||||
import {Background, BackgroundVariant, type NodeProps} from '@xyflow/react'
|
import {Background, BackgroundVariant, type NodeProps} from '@xyflow/react'
|
||||||
import {classnames} from 'amis'
|
import {classnames} from 'amis'
|
||||||
import React from 'react'
|
import React, {useCallback, useEffect} from 'react'
|
||||||
import {flowBackgroundColor, flowDotColor} from '../types.ts'
|
|
||||||
import AmisNode, {nodeClassName, NormalNodeHandler} from './AmisNode.tsx'
|
|
||||||
import AddNodeButton from '../component/AddNodeButton.tsx'
|
import AddNodeButton from '../component/AddNodeButton.tsx'
|
||||||
|
import {useDataStore} from '../store/DataStore.ts'
|
||||||
|
import {flowBackgroundColor, flowDotColor} from '../types.ts'
|
||||||
|
import AmisNode, {nodeClassName, NormalNodeHandler, outputsFormColumns} from './AmisNode.tsx'
|
||||||
|
|
||||||
const LoopNode = (props: NodeProps) => {
|
const LoopNode = (props: NodeProps) => {
|
||||||
|
const {mergeDataById} = useDataStore()
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
mergeDataById(
|
||||||
|
props.id,
|
||||||
|
{
|
||||||
|
outputs: {
|
||||||
|
output: {
|
||||||
|
type: 'array-object',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}, [props.id])
|
||||||
|
|
||||||
|
const columnsSchema = useCallback(() => [
|
||||||
|
{
|
||||||
|
type: 'switch',
|
||||||
|
name: 'failFast',
|
||||||
|
label: '快速失败',
|
||||||
|
description: '执行过程中一旦出现错误,及时中断循环任务的执行',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
disabled: true,
|
||||||
|
type: 'switch',
|
||||||
|
name: 'parallel',
|
||||||
|
label: '并行执行',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'divider',
|
||||||
|
},
|
||||||
|
...outputsFormColumns(false, true),
|
||||||
|
], [props.id])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AmisNode
|
<AmisNode
|
||||||
className={classnames('w-full', 'h-full', nodeClassName('loop'))}
|
className={classnames('w-full', 'h-full', nodeClassName('loop'))}
|
||||||
style={{
|
style={{
|
||||||
minWidth: '350px',
|
minWidth: '350px',
|
||||||
minHeight: '290px'
|
minHeight: '290px',
|
||||||
}}
|
}}
|
||||||
nodeProps={props}
|
nodeProps={props}
|
||||||
extraNodeDescription={
|
extraNodeDescription={
|
||||||
@@ -28,9 +63,10 @@ const LoopNode = (props: NodeProps) => {
|
|||||||
color={flowDotColor}
|
color={flowDotColor}
|
||||||
bgColor={flowBackgroundColor}
|
bgColor={flowBackgroundColor}
|
||||||
/>
|
/>
|
||||||
<AddNodeButton className="mt-2 ml-2" parent={props.id}/>
|
<AddNodeButton className="mt-2 ml-2" parent={props.id} onlyIcon/>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
columnSchema={columnsSchema}
|
||||||
handler={<NormalNodeHandler/>}
|
handler={<NormalNodeHandler/>}
|
||||||
resize={{
|
resize={{
|
||||||
minWidth: 350,
|
minWidth: 350,
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
import {Handle, type NodeProps, Position} from '@xyflow/react'
|
import {Handle, type NodeProps, Position} from '@xyflow/react'
|
||||||
import {Tag} from 'antd'
|
import {Tag} from 'antd'
|
||||||
import React from 'react'
|
import React, {useCallback} from 'react'
|
||||||
|
import {generateAllIncomerOutputVariablesConditions} from '../Helper.tsx'
|
||||||
|
import {useContextStore} from '../store/ContextStore.ts'
|
||||||
|
import {useDataStore} from '../store/DataStore.ts'
|
||||||
|
import {useFlowStore} from '../store/FlowStore.ts'
|
||||||
import AmisNode, {nodeClassName} from './AmisNode.tsx'
|
import AmisNode, {nodeClassName} from './AmisNode.tsx'
|
||||||
|
|
||||||
const cases = [
|
const cases = [
|
||||||
@@ -16,6 +20,25 @@ const cases = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
const SwitchNode = (props: NodeProps) => {
|
const SwitchNode = (props: NodeProps) => {
|
||||||
|
const {getNodes, getEdges} = useFlowStore()
|
||||||
|
const {getData} = useDataStore()
|
||||||
|
const {getInputSchema} = useContextStore()
|
||||||
|
|
||||||
|
const columnsSchema = useCallback(() => [
|
||||||
|
{
|
||||||
|
type: 'condition-builder',
|
||||||
|
name: 'condition',
|
||||||
|
label: '判断条件',
|
||||||
|
fields: generateAllIncomerOutputVariablesConditions(
|
||||||
|
props.id,
|
||||||
|
getInputSchema(),
|
||||||
|
getNodes(),
|
||||||
|
getEdges(),
|
||||||
|
getData(),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
], [props.id])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AmisNode
|
<AmisNode
|
||||||
className={nodeClassName('switch')}
|
className={nodeClassName('switch')}
|
||||||
@@ -29,6 +52,7 @@ const SwitchNode = (props: NodeProps) => {
|
|||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
columnSchema={columnsSchema}
|
||||||
handler={
|
handler={
|
||||||
<>
|
<>
|
||||||
<Handle type="target" position={Position.Left}/>
|
<Handle type="target" position={Position.Left}/>
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import type {Edge, Node} from '@xyflow/react'
|
import type {Edge, Node} from '@xyflow/react'
|
||||||
import type {JSX} from 'react'
|
import type {JSX} from 'react'
|
||||||
|
|
||||||
export const flowBackgroundColor = "#fafafa"
|
export const flowBackgroundColor = '#fafafa'
|
||||||
export const flowDotColor = "#dedede"
|
export const flowDotColor = '#dedede'
|
||||||
|
|
||||||
export type InputFormOptions = {
|
export type InputFormOptions = {
|
||||||
label: string
|
label: string
|
||||||
@@ -29,6 +29,17 @@ export type FlowEditorProps = {
|
|||||||
onGraphDataChange: (graphData: GraphData) => void,
|
onGraphDataChange: (graphData: GraphData) => void,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type OutputVariableType = 'text' | 'boolean' | 'number' | 'object' | 'array-text' | 'array-object'
|
||||||
|
|
||||||
|
export const OutputVariableTypeMap: Record<OutputVariableType, string> = {
|
||||||
|
'text': '文本',
|
||||||
|
'boolean': '布尔值',
|
||||||
|
'number': '数字',
|
||||||
|
'object': '对象',
|
||||||
|
'array-text': '文本数组',
|
||||||
|
'array-object': '对象数组',
|
||||||
|
}
|
||||||
|
|
||||||
export type NodeDefine = {
|
export type NodeDefine = {
|
||||||
key: string,
|
key: string,
|
||||||
group: string,
|
group: string,
|
||||||
@@ -38,3 +49,10 @@ export type NodeDefine = {
|
|||||||
component: any,
|
component: any,
|
||||||
checkers: NodeChecker[],
|
checkers: NodeChecker[],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type OutputVariable = {
|
||||||
|
group: string,
|
||||||
|
name: string | undefined,
|
||||||
|
type: OutputVariableType,
|
||||||
|
variable: string,
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import type {GraphData} from '../components/flow/types.ts'
|
|||||||
|
|
||||||
function Test() {
|
function Test() {
|
||||||
// language=JSON
|
// language=JSON
|
||||||
const [graphData] = useState<GraphData>(JSON.parse('{\n "nodes": [\n {\n "id": "QxNrkChBWQ",\n "type": "loop-node",\n "position": {\n "x": 742,\n "y": 119\n },\n "data": {},\n "measured": {\n "width": 458,\n "height": 368\n },\n "selected": true,\n "dragging": false,\n "width": 458,\n "height": 368,\n "resizing": false\n },\n {\n "id": "MzEitlOusl",\n "type": "llm-node",\n "position": {\n "x": 47,\n "y": 135\n },\n "data": {},\n "measured": {\n "width": 256,\n "height": 110\n },\n "selected": false,\n "dragging": false,\n "extent": "parent",\n "parentId": "QxNrkChBWQ"\n },\n {\n "id": "bivXSpiLaI",\n "type": "code-node",\n "position": {\n "x": 381,\n "y": 181\n },\n "data": {},\n "measured": {\n "width": 256,\n "height": 110\n },\n "selected": false,\n "dragging": false\n }\n ],\n "edges": [],\n "data": {\n "MzEitlOusl": {\n "node": {\n "name": "大模型",\n "description": "使用大模型对话"\n },\n "outputs": {\n "text": {\n "type": "string"\n }\n },\n "model": "qwen3",\n "systemPrompt": "你是个好人",\n "finished": true\n },\n "bivXSpiLaI": {\n "node": {\n "name": "代码执行",\n "description": "执行自定义的处理代码"\n },\n "outputs": {\n "result": {\n "type": "string"\n }\n },\n "type": "javascript",\n "content": "console.log(\'hello\')",\n "inputs": {\n "text": {\n "variable": "MzEitlOusl.text"\n }\n },\n "finished": true\n },\n "QxNrkChBWQ": {\n "node": {\n "name": "循环",\n "description": "实现循环执行流程"\n },\n "finished": true\n }\n }\n}'))
|
const [graphData] = useState<GraphData>(JSON.parse('{\n "nodes": [\n {\n "id": "QxNrkChBWQ",\n "type": "loop-node",\n "position": {\n "x": 742,\n "y": 119\n },\n "data": {},\n "measured": {\n "width": 458,\n "height": 368\n },\n "selected": true,\n "dragging": false,\n "width": 458,\n "height": 368,\n "resizing": false\n },\n {\n "id": "MzEitlOusl",\n "type": "llm-node",\n "position": {\n "x": 47,\n "y": 135\n },\n "data": {},\n "measured": {\n "width": 256,\n "height": 110\n },\n "selected": false,\n "dragging": false,\n "extent": "parent",\n "parentId": "QxNrkChBWQ"\n },\n {\n "id": "bivXSpiLaI",\n "type": "code-node",\n "position": {\n "x": 381,\n "y": 181\n },\n "data": {},\n "measured": {\n "width": 256,\n "height": 110\n },\n "selected": false,\n "dragging": false\n }\n ],\n "edges": [],\n "data": {\n "MzEitlOusl": {\n "node": {\n "name": "大模型",\n "description": "使用大模型对话"\n },\n "outputs": {\n "text": {\n "type": "string"\n }\n },\n "model": "qwen3",\n "systemPrompt": "你是个好人",\n "finished": true\n },\n "bivXSpiLaI": {\n "node": {\n "name": "代码执行",\n "description": "执行自定义的处理代码"\n },\n "outputs": {\n "result": {\n "type": "text"\n }\n },\n "type": "javascript",\n "content": "console.log(\'hello\')",\n "inputs": {\n "text": {\n "variable": "MzEitlOusl.text"\n }\n },\n "finished": true\n },\n "QxNrkChBWQ": {\n "node": {\n "name": "循环",\n "description": "实现循环执行流程"\n },\n "finished": true\n }\n }\n}'))
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="h-screen">
|
<div className="h-screen">
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import type {Schema} from 'amis'
|
import type {Schema} from 'amis'
|
||||||
|
import type {OutputVariableType} from '../../../components/flow/types.ts'
|
||||||
import {commonInfo, formInputFileStaticColumns} from '../../../util/amis.tsx'
|
import {commonInfo, formInputFileStaticColumns} from '../../../util/amis.tsx'
|
||||||
|
|
||||||
export const typeMap: Record<string, string> = {
|
export const typeMap: Record<string, string> = {
|
||||||
@@ -8,6 +9,13 @@ export const typeMap: Record<string, string> = {
|
|||||||
files: '文件',
|
files: '文件',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const originTypeMap: Record<string, OutputVariableType> = {
|
||||||
|
text: 'text',
|
||||||
|
textarea: 'text',
|
||||||
|
number: 'number',
|
||||||
|
files: 'array-text',
|
||||||
|
}
|
||||||
|
|
||||||
export type InputField = {
|
export type InputField = {
|
||||||
type: string
|
type: string
|
||||||
label: string
|
label: string
|
||||||
|
|||||||
@@ -73,8 +73,8 @@ const FlowTaskTemplateEdit: React.FC = () => {
|
|||||||
navigate(-1)
|
navigate(-1)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
]
|
],
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
body: [
|
body: [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -3,7 +3,8 @@ import axios from 'axios'
|
|||||||
import React, {useState} from 'react'
|
import React, {useState} from 'react'
|
||||||
import {useNavigate, useParams} from 'react-router'
|
import {useNavigate, useParams} from 'react-router'
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
import FlowEditor, {type GraphData} from '../../../../components/flow/FlowEditor.tsx'
|
import FlowEditor from '../../../../components/flow/FlowEditor.tsx'
|
||||||
|
import type {GraphData} from '../../../../components/flow/types.ts'
|
||||||
import {commonInfo} from '../../../../util/amis.tsx'
|
import {commonInfo} from '../../../../util/amis.tsx'
|
||||||
|
|
||||||
const FlowTaskTemplateFlowEditDiv = styled.div`
|
const FlowTaskTemplateFlowEditDiv = styled.div`
|
||||||
@@ -19,8 +20,8 @@ const FlowTaskTemplateFlowEdit: React.FC = () => {
|
|||||||
let {data} = await axios.get(
|
let {data} = await axios.get(
|
||||||
`${commonInfo.baseAiUrl}/flow_task/template/detail/${template_id}`,
|
`${commonInfo.baseAiUrl}/flow_task/template/detail/${template_id}`,
|
||||||
{
|
{
|
||||||
headers: commonInfo.authorizationHeaders
|
headers: commonInfo.authorizationHeaders,
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
setInputSchema(data?.data?.inputSchema)
|
setInputSchema(data?.data?.inputSchema)
|
||||||
setGraphData(data?.data?.flowGraph)
|
setGraphData(data?.data?.flowGraph)
|
||||||
@@ -36,11 +37,11 @@ const FlowTaskTemplateFlowEdit: React.FC = () => {
|
|||||||
`${commonInfo.baseAiUrl}/flow_task/template/update_flow_graph`,
|
`${commonInfo.baseAiUrl}/flow_task/template/update_flow_graph`,
|
||||||
{
|
{
|
||||||
id: template_id,
|
id: template_id,
|
||||||
graph: data
|
graph: data,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
headers: commonInfo.authorizationHeaders
|
headers: commonInfo.authorizationHeaders,
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
navigate(-1)
|
navigate(-1)
|
||||||
}}
|
}}
|
||||||
|
|||||||
Reference in New Issue
Block a user