wujingjing
2025-02-11 7e59b188fb37d48d39e8c35b8bbced3836f4dd6d
python code node
已修改9个文件
已添加1个文件
283 ■■■■ 文件已修改
package-lock.json 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
package.json 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/input/codeEditor/types.ts 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/input/codeEditor/useEditorExtensions.ts 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/vue-flow/MainCanvas.vue 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/vue-flow/VueFlowHelper.ts 103 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/vue-flow/ui/VueFlowConfig.ts 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/vue-flow/ui/nodes/PythonCodeNode.vue 118 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/vue-flow/vueFlowEnum.ts 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
vite.config.ts 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
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",
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",
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'
};
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 {
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';
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代码。',
                    [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: '执行代码',
                            [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 + ''}`;
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,
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>
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]: '代理',
    [NodeType.Func]: '执行功能',
    [NodeType.Code]: '代码',
    [NodeType.PythonCode]: 'python代码',
    [NodeType.TextResource]: '文本资源',
    [NodeType.Analysis]: '分析',
};
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',