# 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
文件读写权限不足,可能是插件读取或者写入插件文件夹以外的内容导致。
请检查文件读取时是否使用绝对路径。