# aigc_flow_plugin **Repository Path**: binghuan/aigc_flow_plugin ## Basic Information - **Project Name**: aigc_flow_plugin - **Description**: 用于开发测试编排的自定义插件 - **Primary Language**: JavaScript - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2024-09-13 - **Last Updated**: 2024-10-10 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 介绍 packages 下存放插件代码。base 为提供的测试使用的基类,提供内置方法。 用户自己开发插件请在 packages 文件夹下新建一个文件夹,名称即为插件名称,需要保持唯一,可以添加自己固定的前缀避免和其他人开发的插件名称重复。 用户可以直接复制 myPlugin 文件夹内容进行快速开发。 插件执行结束必须退出,不允许保留后台进程。插件最大执行时间长度为30秒,超过30秒会强制退出。 # 插件配置 每个插件下面都必须有package.json文件。 文件中的"name"由英文和下划线组成,是组件的唯一标识,不允许重复,最好添加特殊前缀。 "version": 版本号 "description": 组件描述 "author": 组件开发者,方便联系开发者反馈bug等。H3C内部人员请认真填写。 "homepage": 组件详细使用说明页面地址 config-> title:String 为组件的中文名称,用于显示在编排画布左侧。 config-> keepFiles:Array 为组件更新时需要保留的文件,例如组件中使用sqlite3进行数据存储,更新时不希望丢失,可以按照如下配置。 >"keepFiles": ["word.db","subFolder/test.txt"]

文件列表中的内容可以使用相对路径'./'开头,也可以不添加路径标识,默认以插件根目录开始。记住,不要使用绝对路径('/')开头。 config-> applyMaxTime: Boolean 是否允许插件申请延长运行时间,默认不允许申请。 默认为false。 > 当插件主要为定时任务中使用的时候,配置 applyMaxTime为true,可以申请插件执行时间,申请时间最长为10分钟。
调用this.applyMaxTime() 方法可以获得10s的时间。需要每隔10s调用一次该方法申请延长时间。最多申请10分钟。 config-> renderType 为组件结果的默认渲染类型。当该组件为工作流最后一个组件时会使用该 渲染类型渲染结果。默认为text类型。 > 渲染类型有如下几种 * text 按照markdown文档渲染 * html 返回的html结构代码会按照html进行渲染 * file 把返回的文本内容写入txt文件,渲染出一个下载链接 * image 可以返回图片url地址、base64编码,渲染成图片 * qrcode 可以把返回的文本内容进行编码,显示二维码 ``` "config": { "title": "自定义组件中文名称", } ``` > author和homepage为非必填项,其他均为必填项。
config-> renderType 和config-> keepFiles 为非必填项,其他均为必填项。 # 插件依赖安装 在 packages/pluginname 文件夹下运行`npm install axios -s`命令安装依赖。 > 注意:请确保安装的依赖能够在 linux 环境运行,否则请在 linux 环境下运行程序代码,安装插件依赖并且运行打包命令 # 调试插件 在根目录下运行`npm run dev pluginName`命令调试插件。 # 插件界面配置 每个插件都会显示在编排画布左侧,可以拖拽进去。界面通过 json 配置文件生成。配置文件为 config.js。 该方法接收一个参数,内容为预设的配置。 * getTokenSelect:Function 该函数返回密钥选择的下拉框配置 * aiChatInput:List 该数组为配置大模型的输入框,可以下拉选择大模型 ## json 结构示例 以系统自带的大模型会话组件为例: ```js const AiQAModule = { name: "AI对话", flowType: "AiQA", logo: "ai", intro: "基本大模型对话链,基于大模型和提示词实现标准化输出。", description: "可以调用通用AI大模型和用户自由会话,也可以根据提示词进行内容创作,你可以编写提示词prompt来让AiQA满足你的设计。", inputs: [ aiChatParamHandle, // 使用参数链的大模型输入框,不使用参数链可以直接使用aiChatInput { type: "paramLinkHandle", label: "提示词", key: "prompt", paramsLinkType: "text", list: [ { tips: "使用用户输入请输入:{input}", label: "提示词", required: true, type: "textareaParam", key: "prompt", placeholder: "使用用户输入请输入:{input}", value: "{input}", }, ], }, { label: "输出是否转为对象", type: "el-switch", key: "transObject", value: false, inline: true, props: { activeText: "是", inactiveText: "否", }, }, { label: "", tips: "默认为字符串,如果选择了“输出转为对象”,则会输出JSON对象,转换JSON是吧仍旧输出字符串。", type: "outputValKey", required: true, key: "output_key", value: "result", }, { type: "linkHandle", label: "", }, ], }; ``` ## json 结构说明 - name: 插件名称,用于显示在编排画布左侧。 - flowType: 插件类型,用于区分插件,是插件的唯一标识,不允许重复。 - logo: 插件图标,无需填写,使用插件中的logo.png。 - intro: 插件简介,用于显示在编排画布左侧。 - description: 插件描述,用于显示在编排画布左侧。 - width: 插件宽度,数字,默认为 400。 - inputs: 插件输入框,用于配置插件的输入参数。 - --------| vif: 是否显示该表单项,true 显示,false 不显示,也可以是函数 - --------| type: 输入框类型,目前支持以下类型:原生 dom 标签,element-plus 标签,paramLinkHandle(参数链),vue3 render 函数 - --------| label: 输入框名称 - --------| tips: 输入框提示信息,可以是字符串,也可以是函数 - --------| required: 是否必填 - --------| key: 变量名,必填,key 不能重复 - --------| value: 默认值,可以是字符串、数字、对象等,也可以是函数,函数返回结果当作默认值 - --------| inline: 使用行内表单样式 - --------| props: 传递给组件的属性,和时间侦听,例如:以 on 开头的是事件侦听(onClick,onDblClick),其他为属性传递 - --------| selectOptions: 选择框选项,例如:select 等的选择框选项,`{"label": "mysql","value": "mysql"}`。也可以是一个对象,可以定义接口,从接口动态获取选项: ``` selectOptions:{ url: '/flow/query_model_list', method: 'get', params: {}, data: {}, proxy: false, //是否走后端代理,如果前端调用跨域就配置为true走后端代理 func: (res: any) => { function transfer(item: any) { let result: any = { label: item.model_name, value: item.model_value, } return result } return res.map((item: any) => transfer(item)) }//对返回数据进行格式化处理 } ``` - --------| list: type 为 paramLinkHandle 或者 group 时,渲染为分组,list 中的内容和上面的字段一样,为表单项的配置。 - --------| paramsLinkType: 参数链的参数类型,可选项有 llm,database,text ### inputs 里面的输入框分为以下几种类型: ### 带分组的输入,可以通过分组来展开、收起。例如: ```js { "name": "SQL执行器", "flowType": "SqlExecutor", "logo": "textextra", "description":"", "inputs":[ { "label": "数据库配置", "type": "group", "list": [ { "label": "数据库类型", "type": "select", "key": "dbType", "value": "mysql", "selectOptions": [ { "label": "mysql", "value": "mysql" }, { "label": "postgresql", "value": "postgresql" } ] } ] } ] } ``` ### 带参数链的输入,可以通过参数链来传递参数。例如: ```js { type: 'paramLinkHandle', label: '数据库配置参数,类型:database', key: 'databaseParams', paramsLinkType: 'database',//有llm,text,database 三种类型 list: [ { label: '数据库配置', type: 'group', list: databaseInput }, ] } ``` ### 链接点(handle) 用于链接流程执行逻辑的点。卡片右侧点为 source(链输出),左侧为 target(链输入)。 链接点的 type 有三种:linkHandle、sourceLinkHandle、targetLinkHandle。 ```js // 下面为简易方法,可以直接在所侧和右侧各生成一个链接点,分别为sourceLinkHandle / targetLinkHandle { type: "linkHandle", label: "",//如果label为 ['链输出-提取成功', '链输入']则显示自定义的提示,否则显示默认的提示 // key: ['sourceLinkHandle', 'targetLinkHandle'] //key如果不传即为默认值, }, {//在卡片左侧生成一个链接点 type: "targetLinkHandle", label: "链输入", key: "targetLinkHandle", required: false, }, {//在卡片有边生成一个链接点 label: "链输出-执行失败", key: "sql_error", type: "sourceLinkHandle", required: false, handleStyle: 'error',// 链接点样式,可选值:error、other、default三种,当右侧链接点有多个时,可以使用这些用于显示不同颜色,做个区分,默认是default }, ``` ### type函数 * form 为当前表单的实例, * input 当前的输入框配置 * flowId 当前流程的 id * ElPlus 为 element-plus 的实例,用于渲染 element-plus 的组件,例如:h(ElPlus.ElInput,{value:form.input}) * h vue3的render函数,用于渲染自定义的组件,例如: ``` type: ({ form, input, flowId ,ElPlus},h:function)=>h('div',{},()=>[h('div',{},'自定义内容'),h(ElPlus.ElInput,{value:form.input})]) ``` ### props 函数参数 onClick({ formRef, paramFormRef, paramForm, form }: any, e: Event) form 为当前表单的实例,paramForm 为参数表单的实例,paramFormRef 为参数表单的 ref,formRef 为当前表单的 ref。 ### tips 函数参数 form 为当前表单的实例, ``` tips: (form: any) => { if (form.search_type === 'news' || form.search_type === 'webpage') { return "结果数量小于3条可以开启输出详情,使用模型整理摘要。" } else { return undefined } }, ``` ### vif 函数参数 data 为当前表单的实例, ``` vif: function (data: any) { return (data.search_type === 'news' || data.search_type === 'webpage') && data.result_count < 3 }, ``` ## 内置配置 aiChatInput: 大模型输入框,包括模型选择、温度、是否流式等。index.js 中可以通过 this.formData 获取这些配置,字段包括:model:String,temperature:Number,topP:Number,stream:Boolean aiChatParamHandle: 使用参数链的大模型输入框,允许使用大模型的参数链来传递大模型参数。 密钥选择: 密钥选择框,用于选择密钥。 # 插件打包 如果需要打包的插件需要依赖其他插件,必须在打包前进入插件目录,运行`npm install`命令安装依赖。 在根目录下运行`npm run build pluginName pluginName1`命令打包插件。 pluginName 可以传递多个,用空格隔开。如果不传递则打包 packages 下面所有插件。 > 注意:请确保打包的插件能够在 linux 环境运行,否则请在 linux 环境下运行程序代码,安装插件依赖并且运行打包命令 # 文件系统权限 插件不允许后台运行,执行结束就会完全终止进程。插件运行过程中对插件自身文件夹具有读取和写入的权限。文件夹以外内容没有权限。 ## 文件路径 所有文件操作使用的路径都必须使用绝对路径,不能使用相对路径。例如:`fs.readFileSync('./path/to/file')`是不允许的。因为该路径会指向服务的跟路径而不是当前代码执行路径,需要使用绝对路径:`fs.readFileSync(path.resolve(__dirname, './path/to/file') )` ## 读取 ## 写入 # 模板变量替换 formData 中存放用户在界面上输入的信息,中间可能存在模板变量,变量只能是 params 中的变量,在需要的时候请手动调用方法将模板变量替换为真实变量值。 formatVariable(variable:String, isJson:Boolean) 函数用于将模板变量替换为真实变量值。 variable 为需要替换的变量,isJson 为 true 表示返回的是 json 格式,false 表示返回的是字符串格式。 isJson 为 true 时,会对输入的 variable 字符串转为 json 对象。 例如`params={"weather":{wind:"strong",temp:"warm"},city:'beijing'}'}` 替换规则为: - `variable = "{{params.weather}}"` 结果为 json`{"wind":"strong","temp":"warm"}` - `variable = "2{{params.weather}}1"` 结果为 json 格式的字符串`"2{\"wind\":\"strong\",\"temp\":\"warm\"}1"` - `variable = "{{params.weather.wind}}"` 结果为字符串`"strong"` - `variable = "{{params.weather.wind}}{{params.city}}"` 结果为字符串`"strongbeijing"` - `variable = "{\"{{params.city}}\":\"{{params.weather}}\"}"` 结果为 json:`{"beijing":{"wind":"strong","temp":"warm"}}` 具体为: - `{{` 表示变量开始,`}}` 表示变量结束。 - 变量为字符串,且只有模板变量,则直接返回变量值。 - 变量为字符串,除了变量还有其他字符串则返回字符串。 - 变量为 json 格式字符串,返回 json 格式字符串。key 中的变量始终替换为字符串,value 中的变量按照前三条规则替换。 # 结果返回类型 ## 流式返回 outputLog(mes:String) 方法是streamOutput的封装,等价于`streamOutput(MessageType.LOG, mes)`。 streamOutput(messageType:MessageType, mes:String)函数,用于流式返回结果。 MessageType 在base目录下,类型有:LOG,ERROR,NODE_RESULT,FINAL_RESULT,NODE_PARAMS等。如下: ```javascript const MessageType = { /** * 执行日志 */ LOG: 'log', /** * 节点执行错误 */ ERROR: 'error', /** * 节点执行结果 */ NODE_RESULT: 'node_result', /** * 节点执行参数,输入参数,替换变量以后的参数 * 方便查看过程数据判断错误位置等 */ NODE_PARAMS: 'node_params', /** * 节点流式执行结果 * 如果是最后一个节点,且直接输出流式接口数据,可以使用这个方法提高输出效率 */ NODE_STREAM_RESULT: 'node_stream_result', /** * 流程正常执行结束的最终返回值 */ FINAL_RESULT: 'final_result', /** * 节点执行的过程数据 */ NODE_PROCESS_DATA: 'node_process_data', /** * 指定一个handleKey,用于查找下一个需要运行的插件 * 多数插件就一个sourceHandle,写死即可 * 如果有失败连线,可以在系统内判断 */ NEXT_NODE_HANDLE: 'next_node_handle', } ``` ## 执行完一次返回 直接在 execute 函数执行结束前使用 return 返回结果。 虽然流式返回也可以,但是依然建议return返回方式保留。 # 内部方法 ## 替换变量 formatVariable(variable:String, isJson:Boolean) 函数用于将模板变量替换为真实变量值。 variable 为需要替换的变量,isJson 为 true 表示返回的是 json 格式,false 表示返回的是字符串格式。 > 替换规则,1、{变量名}用于把模板变量转为字符串放到相应位置
2、{{变量名}} 在isJson为false时和1一样
3、{{变量名}} 在isJson为true时会优先把字符串转为json对象,再对其key和value进行替换,无法转换为json时,如果除了模板变量没有其他字符,则直接返回变量,否则和1一样。 例如: ```javascript let params = { 'weather': 'warm', 'city': 'beijing', 'rain': { date:'2024/09/09', rain:'heavy' } } let variable = '{{weather}}' let variable1 = '今天温度:{{weather}}' let variable2 = '今天温度:{weather}' let variable3 = '{{rain}}' let variable4 = '今天温度:{{rain}}' let variable5 = '今天温度:{rain}' formatVariable(variable) == 'warm' formatVariable(variable1) == '今天温度:warm' formatVariable(variable2) == '今天温度:warm' formatVariable(variable3, true) == { date:'2024/09/09', rain:'heavy' } formatVariable(variable4, true) == '今天温度:{\"date\":\"2024/09/09\",\"rain\":\"heavy\"}' formatVariable(variable5, true) == '今天温度:{\"date\":\"2024/09/09\",\"rain\":\"heavy\"}' formatVariable('{\"to\":\"trval\",\"rain\":\"{{rain}}\"}', true) == {to:'trval','rain':{'date':'2024/09/09','rain':'heavy'}} ``` ## 操作共享缓存 getSharedStorage(key:String) 根据 key 获取共享缓存 setSharedStorage(key:String, value:[String, Number, Object, Array]) 根据 key 设置共享缓存 getSharedStorageKeys() 获取所有共享缓存的 key ## 获取参数链数据 getLinkedParam(paramHandleKey:String) 根据参数链的 key 获取参数 getLinkedParams() 获取所有参数链数据链接的数据 ## 调用大模型 callLLM(options) 调用大模型 options结构为:{model:'模型id', prompt:'提示词',message:[{role:'bot',content:'内容'},{role:'user',content:''}],temperature:0.5,topP:0.5} >message存在时prompt无效
# 常见错误 ## ERR_WORKER_OUT_OF_MEMORY Worker terminated due to reaching memory limit: JS heap out of memory js代码占用内存超过限制,一般插件内存占用不得超过200M ## Access to this API has been restricted 文件读写权限不足,可能是插件读取或者写入插件文件夹以外的内容导致。 请检查文件读取时是否使用绝对路径。