From 7e59b188fb37d48d39e8c35b8bbced3836f4dd6d Mon Sep 17 00:00:00 2001 From: wujingjing <gersonwu@qq.com> Date: 星期二, 11 二月 2025 16:30:42 +0800 Subject: [PATCH] python code node --- vite.config.ts | 2 src/components/input/codeEditor/types.ts | 3 package-lock.json | 23 ++++ src/components/vue-flow/VueFlowHelper.ts | 103 ++++++++++++++------ src/components/input/codeEditor/useEditorExtensions.ts | 15 ++ package.json | 1 src/components/vue-flow/ui/nodes/PythonCodeNode.vue | 118 +++++++++++++++++++++++ src/components/vue-flow/ui/VueFlowConfig.ts | 10 ++ src/components/vue-flow/MainCanvas.vue | 4 src/components/vue-flow/vueFlowEnum.ts | 4 10 files changed, 249 insertions(+), 34 deletions(-) diff --git a/package-lock.json b/package-lock.json index f5902da..af0981f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,6 +14,7 @@ "@antv/g6": "^5.0.27", "@codemirror/lang-javascript": "^6.2.2", "@codemirror/lang-json": "^6.0.1", + "@codemirror/lang-python": "^6.1.7", "@codemirror/lang-sql": "^6.7.1", "@codemirror/lang-xml": "^6.1.0", "@codemirror/state": "6.x", @@ -605,6 +606,18 @@ "dependencies": { "@codemirror/language": "^6.0.0", "@lezer/json": "^1.0.0" + } + }, + "node_modules/@codemirror/lang-python": { + "version": "6.1.7", + "resolved": "https://registry.npmmirror.com/@codemirror/lang-python/-/lang-python-6.1.7.tgz", + "integrity": "sha512-mZnFTsL4lW5p9ch8uKNKeRU3xGGxr1QpESLilfON2E3fQzOa/OygEMkaDvERvXDJWJA9U9oN/D4w0ZuUzNO4+g==", + "dependencies": { + "@codemirror/autocomplete": "^6.3.2", + "@codemirror/language": "^6.8.0", + "@codemirror/state": "^6.0.0", + "@lezer/common": "^1.2.1", + "@lezer/python": "^1.1.4" } }, "node_modules/@codemirror/lang-sql": { @@ -1548,6 +1561,16 @@ "@lezer/common": "^1.0.0" } }, + "node_modules/@lezer/python": { + "version": "1.1.15", + "resolved": "https://registry.npmmirror.com/@lezer/python/-/python-1.1.15.tgz", + "integrity": "sha512-aVQ43m2zk4FZYedCqL0KHPEUsqZOrmAvRhkhHlVPnDD1HODDyyQv5BRIuod4DadkgBEZd53vQOtXTonNbEgjrQ==", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, "node_modules/@lezer/xml": { "version": "1.0.5", "resolved": "https://registry.npmmirror.com/@lezer/xml/-/xml-1.0.5.tgz", diff --git a/package.json b/package.json index 830099d..a1b8af9 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "@antv/g6": "^5.0.27", "@codemirror/lang-javascript": "^6.2.2", "@codemirror/lang-json": "^6.0.1", + "@codemirror/lang-python": "^6.1.7", "@codemirror/lang-sql": "^6.7.1", "@codemirror/lang-xml": "^6.1.0", "@codemirror/state": "6.x", diff --git a/src/components/input/codeEditor/types.ts b/src/components/input/codeEditor/types.ts index 24df406..7d6188e 100644 --- a/src/components/input/codeEditor/types.ts +++ b/src/components/input/codeEditor/types.ts @@ -1,5 +1,6 @@ -export type TextType = 'text' | 'javascript'; +export type TextType = 'text' | 'javascript' |'python'; export const textTypeMap = { text: '鏂囨湰', javascript: 'JavaScript', + python:'Python' }; \ No newline at end of file diff --git a/src/components/input/codeEditor/useEditorExtensions.ts b/src/components/input/codeEditor/useEditorExtensions.ts index 27a7db2..46914fc 100644 --- a/src/components/input/codeEditor/useEditorExtensions.ts +++ b/src/components/input/codeEditor/useEditorExtensions.ts @@ -1,4 +1,6 @@ import { javascript } from '@codemirror/lang-javascript'; +import { python } from '@codemirror/lang-python'; + import { vscodeDark } from '@uiw/codemirror-theme-vscode'; import type { Ref } from 'vue'; import { computed, ref } from 'vue'; @@ -9,10 +11,21 @@ }; export const useEditorExtensions = (options: UseEditorExtensionsOptions) => { const javascriptHighlight = javascript(); + const pythonHighlight = python(); const { activeHighlight } = options; const editorExtensions = computed(() => { - return activeHighlight.value !== 'text' ? [javascriptHighlight, vscodeDark] : []; + switch (activeHighlight.value) { + case 'text': + return []; + case 'javascript': + return [javascriptHighlight, vscodeDark]; + case 'python': + return [pythonHighlight, vscodeDark]; + + default: + return []; + } }); return { diff --git a/src/components/vue-flow/MainCanvas.vue b/src/components/vue-flow/MainCanvas.vue index 7ad78d8..1edec66 100644 --- a/src/components/vue-flow/MainCanvas.vue +++ b/src/components/vue-flow/MainCanvas.vue @@ -29,6 +29,9 @@ <template #node-code="codeNodeProps"> <CodeNode v-bind="codeNodeProps" :isViewMode="isViewMode" /> </template> + <template #node-python_code="pythonCodeNodeProps"> + <PythonCodeNode v-bind="pythonCodeNodeProps" :isViewMode="isViewMode" /> + </template> <template #node-text_resource="textResourceNodeProps"> <TextResourceNode v-bind="textResourceNodeProps" :isViewMode="isViewMode" /> </template> @@ -60,6 +63,7 @@ import AgentNode from './ui/nodes/AgentNode.vue'; import AnalysisNode from './ui/nodes/AnalysisNode.vue'; import CodeNode from './ui/nodes/CodeNode.vue'; +import PythonCodeNode from './ui/nodes/PythonCodeNode.vue'; import ConditionNode from './ui/nodes/ConditionNode.vue'; import EndNode from './ui/nodes/EndNode.vue'; import FuncNode from './ui/nodes/FuncNode.vue'; diff --git a/src/components/vue-flow/VueFlowHelper.ts b/src/components/vue-flow/VueFlowHelper.ts index 9b05a81..b178d2c 100644 --- a/src/components/vue-flow/VueFlowHelper.ts +++ b/src/components/vue-flow/VueFlowHelper.ts @@ -66,7 +66,6 @@ description: '璋冪敤澶фā鍨嬪洖绛旂敤鎴烽棶棰樻垨鑰呭鐞嗕换鍔°��', }; data[VueFlowConstant.GROUP_PARAMS_KEY] = [ - { name: '妯″瀷璁剧疆', @@ -88,37 +87,37 @@ }, { name: '杈撳嚭鍙傛暟鍚�', - [VueFlowConstant.PARAMS_KEY]: [{ key: 'key', type: 'input', value: '' }], + [VueFlowConstant.PARAMS_KEY]: [{ key: 'key', type: 'input', value: '' }], }, ]; break; - case NodeType.Analysis: - data = { - ...data, - description: '', - }; - data[VueFlowConstant.GROUP_PARAMS_KEY] = [ - { - name: '鍒嗘瀽璁剧疆', - - [VueFlowConstant.PARAMS_KEY]: [ - { - key: 'llm_model', - label: '妯″瀷', - type: 'llm_model', - value: '', - required: true, - placeholder: '璇烽�夋嫨妯″瀷', - }, - { key: 'temperature', label: '娓╁害', type: 'slide', scope: [0, 2], step: 0.1, value: 0.6 }, - ], - }, - { - name: '鎻愮ず璇�', - [VueFlowConstant.PARAMS_KEY]: [{ key: 'prompt', label: '', type: 'textarea', value: '' }], - }, - ]; - break; + case NodeType.Analysis: + data = { + ...data, + description: '', + }; + data[VueFlowConstant.GROUP_PARAMS_KEY] = [ + { + name: '鍒嗘瀽璁剧疆', + + [VueFlowConstant.PARAMS_KEY]: [ + { + key: 'llm_model', + label: '妯″瀷', + type: 'llm_model', + value: '', + required: true, + placeholder: '璇烽�夋嫨妯″瀷', + }, + { key: 'temperature', label: '娓╁害', type: 'slide', scope: [0, 2], step: 0.1, value: 0.6 }, + ], + }, + { + name: '鎻愮ず璇�', + [VueFlowConstant.PARAMS_KEY]: [{ key: 'prompt', label: '', type: 'textarea', value: '' }], + }, + ]; + break; case NodeType.Code: data = { ...data, @@ -163,6 +162,50 @@ { key: 'result1', type: 'string' }, { key: 'result2', type: 'string' }, ], + }, + ], + }, + ], + }; + break; + + case NodeType.PythonCode: + data = { + ...data, + description: '鑷畾涔夐渶瑕佹墽琛岀殑python浠g爜銆�', + [VueFlowConstant.GROUP_PARAMS_KEY]: [ + { + name: '鍏ュ弬', + [VueFlowConstant.PARAMS_KEY]: [ + { + key: 'code_input', + type: 'code_input', + required: true, + value: { type: 'input', label: '', value: '' }, + }, + ], + }, + { + name: '鍑哄弬', + [VueFlowConstant.PARAMS_KEY]: [ + { + key: 'code_output', + type: 'code_output', + required: true, + value: { type: 'input', label: '', value: '' }, + }, + ], + }, + { + name: '鎵ц浠g爜', + [VueFlowConstant.PARAMS_KEY]: [ + { + key: 'code', + type: 'code', + required: true, + value: 'const main = (arg1, arg2) =>{\n return {\n result1: arg1,\n result2: arg2\n }\n}', + language: ['python'], + defaultLanguage: 'python', }, ], }, @@ -291,8 +334,6 @@ return val; }; - - static getHandleId = (node: any, handleType: HandleType, order?: number) => { const orderSuffix = order == undefined ? '' : `__${order + ''}`; diff --git a/src/components/vue-flow/ui/VueFlowConfig.ts b/src/components/vue-flow/ui/VueFlowConfig.ts index ce38640..fc21621 100644 --- a/src/components/vue-flow/ui/VueFlowConfig.ts +++ b/src/components/vue-flow/ui/VueFlowConfig.ts @@ -85,6 +85,16 @@ }, ], [ + NodeType.PythonCode, + { + type: NodeType.PythonCode, + title: nodeTypeMap[NodeType.PythonCode], + icon: 'didaima', + fontSize: '18', + class: 'bg-[#0062be] !p-1', + }, + ], + [ NodeType.TextResource, { type: NodeType.TextResource, diff --git a/src/components/vue-flow/ui/nodes/PythonCodeNode.vue b/src/components/vue-flow/ui/nodes/PythonCodeNode.vue new file mode 100644 index 0000000..8647a82 --- /dev/null +++ b/src/components/vue-flow/ui/nodes/PythonCodeNode.vue @@ -0,0 +1,118 @@ +<template> + <NodeBasicLayout + v-model:title="data.title" + :type="NodeType.PythonCode" + :showOffset="false" + :description="data.description" + :isViewMode="isViewMode" + > + <Handle :id="targetHandleId" type="target" :position="Position.Left" /> + <FieldLayout :title="codeInput.name"> + <!-- codeInput.params[0].value --> + <el-input filterable class="w-[120px] flex-0" v-model="codeInput.params[0].value.value" placeholder="鍙傛暟鍚�" :readonly="isViewMode"></el-input> + </FieldLayout> + + <FieldLayout :title="codeOutput.name"> + <!-- codeOutput.params[0].value --> + <el-input filterable class="w-[120px] flex-0" v-model="codeOutput.params[0].value.value" placeholder="鍙傛暟鍚�" :readonly="isViewMode"></el-input> + </FieldLayout> + + <FieldLayout :title="codeStr.name"> + <CodeEditor + :title="codeStr.name" + :language="codeLanguage" + v-model:defaultLanguage="codeStr.params[0].defaultLanguage" + v-model:editValue="codeStr.params[0].value" + :disabled="isViewMode" + /> + <template #right> + <el-select :disabled="isViewMode" size="small" class="w-[100px]" v-model="codeStr.params[0].defaultLanguage"> + <el-option v-for="item in codeLanguage" :key="item" :value="item" :label="textTypeMap[item]"></el-option> + </el-select> + </template> + </FieldLayout> + <Handle :id="sourceHandleId" type="source" :position="Position.Right" /> + </NodeBasicLayout> +</template> + +<script lang="ts" setup> +import type { NodeProps } from '@vue-flow/core'; +import { Handle, Position, useNode } from '@vue-flow/core'; +import { ref } from 'vue'; +import { VueFlowHelper } from '../../VueFlowHelper'; +import { NodeType, ParameterType, parameterTypeMap } from '../../vueFlowEnum'; +import CodeEditor from '/@/components/input/codeEditor/index.vue'; +// import CodeEditDialog from './components/CodeEditDlg.vue'; +import FieldLayout from './components/FieldLayout.vue'; +import NodeBasicLayout from './components/NodeBasicLayout.vue'; +import type { LLMNodeData, LLMNodeEvents } from './index'; +import { textTypeMap } from '/@/components/input/codeEditor/types'; +defineProps< + NodeProps<LLMNodeData, LLMNodeEvents> & { + isViewMode?: boolean; + } +>(); +const node = useNode(); +const targetHandleId = ref(VueFlowHelper.getHandleId(node.node, 'target')); +const sourceHandleId = ref(VueFlowHelper.getHandleId(node.node, 'source')); +const data = ref(node.node.data); +const codeInput = ref(VueFlowHelper.getGroupParam(data.value, 0)); +const codeStr = ref(VueFlowHelper.getGroupParam(data.value, 2)); +const codeOutput = ref(VueFlowHelper.getGroupParam(data.value, 1)); + +const codeLanguage = ref(VueFlowHelper.getConfigValue(codeStr.value.params[0], 'language', ['text', 'javascript'])); + +// defaultLanguage 涓嶅瓨鍦紝璁剧疆榛樿鍊� +!codeStr.value.params[0].defaultLanguage && (codeStr.value.params[0].defaultLanguage = 'javascript'); + +const getInputEmptyItem = () => { + return { + key: '', + type: 'input', + label: '', + value: '', + }; +}; + +const getOutputEmptyItem = () => { + return { + key: '', + type: ParameterType.String, + }; +}; +const delInputVarItem = (index) => { + if (!codeInput.value.params[0].value || codeInput.value.params[0].value.length === 0) { + return; + } + // if (codeInput.value.params[0].value?.length === 1) { + // codeInput.value.params[0].value = getEmptyItem(); + // return; + // } + codeInput.value.params[0].value.splice(index, 1); +}; + +const addInputVarItem = () => { + if (!codeInput.value.params[0].value || codeInput.value.params[0].value.length === 0) { + codeInput.value.params[0].value = []; + } + codeInput.value.params[0].value.push(getInputEmptyItem()); +}; + +const delOutputVarItem = (index) => { + if (!codeOutput.value.params[0].value || codeOutput.value.params[0].value.length === 0) { + return; + } + // if (codeOutput.value.params[0].value?.length === 1) { + // codeOutput.value.params[0].value = getOutputEmptyItem(); + // return; + // } + codeOutput.value.params[0].value.splice(index, 1); +}; + +const addOutputVarItem = () => { + if (!codeOutput.value.params[0].value || codeOutput.value.params[0].value.length === 0) { + codeOutput.value.params[0].value = []; + } + codeOutput.value.params[0].value.push(getOutputEmptyItem()); +}; +</script> diff --git a/src/components/vue-flow/vueFlowEnum.ts b/src/components/vue-flow/vueFlowEnum.ts index ec1799e..c1f636a 100644 --- a/src/components/vue-flow/vueFlowEnum.ts +++ b/src/components/vue-flow/vueFlowEnum.ts @@ -20,6 +20,8 @@ Agent = 'agent', Func = 'func', Code = 'code', + PythonCode = 'python_code', + TextResource = 'text_resource', Analysis = 'analysis', } @@ -34,6 +36,8 @@ [NodeType.Agent]: '浠g悊', [NodeType.Func]: '鎵ц鍔熻兘', [NodeType.Code]: '浠g爜', + [NodeType.PythonCode]: 'python浠g爜', + [NodeType.TextResource]: '鏂囨湰璧勬簮', [NodeType.Analysis]: '鍒嗘瀽', }; diff --git a/vite.config.ts b/vite.config.ts index fa15255..a568226 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -45,7 +45,7 @@ host: '0.0.0.0', port: env.VITE_PORT as unknown as number, open: JSON.parse(env.VITE_OPEN), - hmr: true, + hmr: false, proxy: { '/gitee': { target: 'https://gitee.com', -- Gitblit v1.9.3