From 35d2f9988245e8c425b373a11ecd5111532fa1d3 Mon Sep 17 00:00:00 2001 From: hhd <17835559578@163.com> Date: Wed, 12 Mar 2025 13:10:32 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E3=80=91=E4=BC=98=E5=8C=96pom=EF=BC=8C=E7=9B=B4?= =?UTF-8?q?=E6=8E=A5=E5=BC=95=E5=85=A5=E6=9C=AC=E9=A1=B9=E7=9B=AE=E5=8C=85?= =?UTF-8?q?=EF=BC=8C=E4=BC=98=E5=8C=96=E5=89=8D=E7=AB=AF=E8=BF=90=E8=A1=8C?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=EF=BC=8C=E5=88=A4=E6=96=AD=E8=BF=90=E8=A1=8C?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=E5=85=A5=E5=8F=82=E5=92=8C=E8=BF=94=E5=9B=9E?= =?UTF-8?q?=E5=8F=82=E6=95=B0=E5=8F=82=E6=95=B0=E7=B1=BB=E5=9E=8B=E5=B9=B6?= =?UTF-8?q?=E4=B8=94=E8=BD=AC=E4=B8=BA=E5=AF=B9=E5=BA=94=E7=B1=BB=E5=9E=8B?= =?UTF-8?q?=E8=BE=93=E5=85=A5=E6=88=96=E8=80=85=E8=BE=93=E5=87=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tinyflow-java-demo/pom.xml | 10 +- .../src/main/resources/static/workflow.html | 103 ++++++++++++++++-- 2 files changed, 104 insertions(+), 9 deletions(-) diff --git a/tinyflow-java-demo/pom.xml b/tinyflow-java-demo/pom.xml index 0a91f10..490f4de 100644 --- a/tinyflow-java-demo/pom.xml +++ b/tinyflow-java-demo/pom.xml @@ -38,10 +38,16 @@ lombok provided + + + + + + dev.tinyflow - tinyflow-java - 0.0.1 + tinyflow-java-core + 0.0.2 com.agentsflex diff --git a/tinyflow-java-demo/src/main/resources/static/workflow.html b/tinyflow-java-demo/src/main/resources/static/workflow.html index f7ff355..2b12b3e 100644 --- a/tinyflow-java-demo/src/main/resources/static/workflow.html +++ b/tinyflow-java-demo/src/main/resources/static/workflow.html @@ -83,7 +83,40 @@ if (paramArr[i].type === 'startNode') { var params = paramArr[i].data.parameters; for (var key in params) { - paramsObj[params[key].name] = document.getElementById(key).value; + var param = params[key]; + var element = document.getElementById(key); + if (!element) { + console.error('未找到元素:', key); + continue; + } + var value; + switch (param.dataType) { + case 'Boolean': + // 假设使用checkbox,获取checked属性 + value = element.checked; + break; + case 'Number': + // 转换为数字,无效值转为NaN + value = Number(element.value); + break; + case 'File': + // 获取文件对象 + value = element.files[0] || null; + break; + case 'Object': + case 'Array': + // 尝试解析JSON + try { + value = JSON.parse(element.value); + } catch (e) { + console.error(`参数“${param.name}”的JSON解析失败:`, e); + value = element.value; // 保留原始值或根据需求处理 + } + break; + default: // String及其他未指定类型 + value = element.value; + } + paramsObj[param.name] = value; } break; } @@ -176,15 +209,71 @@ }); } function showResult(result) { - var resultText = document.getElementById('resultText'); - resultText.innerHTML = ''; // 清空之前的文本 - for (var key in result) { - var div = document.createElement('div'); - div.textContent = `${key}: ${result[key]}`; - resultText.appendChild(div); + const resultText = document.getElementById('resultText'); + resultText.innerHTML = ''; // 清空容器 + + // 类型检查增强 + if (!isValidInput(result)) { + resultText.innerHTML = '
错误:参数必须是对象或数组
'; + return; } + + // 安全遍历自身可枚举属性 + Object.keys(result).forEach(key => { + try { + const div = document.createElement('div'); + div.innerHTML = ` + ${escapeHtml(key)}: + ${formatValue(result[key])} + `; + resultText.appendChild(div); + } catch (e) { + console.error(`渲染属性 ${key} 时出错:`, e); + } + }); } + // 类型校验函数 + const isValidInput = (input) => { + const type = Object.prototype.toString.call(input); + return type === '[object Object]' || type === '[object Array]'; + }; + + // 值格式化函数(核心改进) + const formatValue = (value) => { + if (value === null) return 'null'; + if (value === undefined) return 'undefined'; + + switch (typeof value) { + case 'object': + // 处理特殊对象类型 + if (Array.isArray(value)) { + return `[ ${value.map(item => formatValue(item)).join(', ')} ]`; + } else if (value instanceof Date) { + return ``; + } + // 简单对象处理(限制递归深度可在此添加) + return `{ ${Object.keys(value).map(k => + `${k}: ${formatValue(value[k])}` + ).join(', ')} }`; + case 'string': + return `"${escapeHtml(value)}"`; + case 'number': + return `${value}`; + case 'boolean': + return `${value.toString()}`; + default: + return escapeHtml(String(value)); + } + }; + + // HTML转义防止XSS + const escapeHtml = (str) => { + const div = document.createElement('div'); + div.textContent = str; + return div.innerHTML; + }; + function load() { // 使用方法 id = getQueryParam('id'); -- Gitee From e49bb5d8cf26611eb036be4e92a20a8a0355dc48 Mon Sep 17 00:00:00 2001 From: Hhd <17835559578@163.com> Date: Sat, 15 Mar 2025 12:44:21 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E3=80=91=E6=9B=B4=E6=96=B0=E5=89=8D=E5=90=8E=E7=AB=AF?= =?UTF-8?q?=E4=BA=A4=E4=BA=92=E6=96=B9=E5=BC=8F=EF=BC=8C=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E8=BF=94=E5=9B=9E=E5=80=BC=E5=B1=95=E7=A4=BA=EF=BC=9B=E8=A7=A3?= =?UTF-8?q?=E5=86=B3Tinyflow=E7=94=B1=E4=BA=8E=E5=8A=A0=E8=BD=BD=E5=B7=A5?= =?UTF-8?q?=E4=BD=9C=E6=B5=81=E6=97=B6=E5=B7=B2=E7=BB=8Fpars=E6=A8=A1?= =?UTF-8?q?=E5=9E=8B=E8=8A=82=E7=82=B9=E4=BA=86=EF=BC=8C=E5=AF=BC=E8=87=B4?= =?UTF-8?q?setLlmProvider=E6=97=A0=E6=95=88=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/dev/tinyflow/core/Tinyflow.java | 5 +++ tinyflow-java-demo/pom.xml | 5 +++ .../java/com/tinyflow/demo/common/Result.java | 22 ---------- .../demo/controller/WorkFlowController.java | 41 ++++++++++++++++++- .../src/main/resources/static/workflow.html | 11 ++++- 5 files changed, 60 insertions(+), 24 deletions(-) delete mode 100644 tinyflow-java-demo/src/main/java/com/tinyflow/demo/common/Result.java diff --git a/tinyflow-java-core/src/main/java/dev/tinyflow/core/Tinyflow.java b/tinyflow-java-core/src/main/java/dev/tinyflow/core/Tinyflow.java index 66ffc1d..1a0e3a7 100644 --- a/tinyflow-java-core/src/main/java/dev/tinyflow/core/Tinyflow.java +++ b/tinyflow-java-core/src/main/java/dev/tinyflow/core/Tinyflow.java @@ -27,6 +27,11 @@ public class Tinyflow { private Chain chain; private LlmProvider llmProvider; + public Tinyflow(LlmProvider llmProvider, String flowData) { + setLlmProvider(llmProvider); + this.data = flowData; + this.chain = ChainParser.parse(this); + } public Tinyflow(String flowData) { this.data = flowData; diff --git a/tinyflow-java-demo/pom.xml b/tinyflow-java-demo/pom.xml index 490f4de..b8bedd4 100644 --- a/tinyflow-java-demo/pom.xml +++ b/tinyflow-java-demo/pom.xml @@ -54,6 +54,11 @@ agents-flex-bom 1.0.0-rc.6
+ + com.squareup.okhttp3 + okhttp + 4.12.0 + diff --git a/tinyflow-java-demo/src/main/java/com/tinyflow/demo/common/Result.java b/tinyflow-java-demo/src/main/java/com/tinyflow/demo/common/Result.java deleted file mode 100644 index 95708ba..0000000 --- a/tinyflow-java-demo/src/main/java/com/tinyflow/demo/common/Result.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.tinyflow.demo.common; - -public class Result { - - private final Integer code; - private final String msg; - private final Object data; - - public Result(int code, String msg, Object data) { - this.code = code; - this.msg = msg; - this.data = data; - } - - public static Result success(Object data) { - return new Result(200, "成功", data); - } - - public static Result success() { - return success(null); - } -} diff --git a/tinyflow-java-demo/src/main/java/com/tinyflow/demo/controller/WorkFlowController.java b/tinyflow-java-demo/src/main/java/com/tinyflow/demo/controller/WorkFlowController.java index 51b2158..edea0aa 100644 --- a/tinyflow-java-demo/src/main/java/com/tinyflow/demo/controller/WorkFlowController.java +++ b/tinyflow-java-demo/src/main/java/com/tinyflow/demo/controller/WorkFlowController.java @@ -1,5 +1,10 @@ package com.tinyflow.demo.controller; +import com.agentsflex.llm.openai.OpenAILlm; +import com.agentsflex.llm.openai.OpenAILlmConfig; +import com.agentsflex.llm.qwen.QwenLlm; +import com.agentsflex.llm.qwen.QwenLlmConfig; +import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.tinyflow.demo.service.IWorkFlowService; import dev.tinyflow.core.Tinyflow; @@ -41,10 +46,44 @@ public class WorkFlowController { @PostMapping("/workflow/exe") public ResponseEntity> exe(@RequestBody JSONObject wf) { - Tinyflow tinyflow = new Tinyflow(wf.getJSONObject("data").toJSONString()); + Tinyflow tinyflow = parseFlowParam(wf.getJSONObject("data").toJSONString()); Map variables = wf.getJSONObject("param").getInnerMap(); Map result = tinyflow.executeForResult(variables); return new ResponseEntity<>(result, HttpStatus.OK); } + private Tinyflow parseFlowParam(String graph) { + JSONObject json = JSONObject.parseObject(graph); + JSONArray nodeArr = json.getJSONArray("nodes"); + for (int i = 0; i < nodeArr.size(); i++) { + JSONObject node = nodeArr.getJSONObject(i); + if (node.getString("type").equals("llmNode")) { + node.getJSONObject("data").put("topK", 10); + node.getJSONObject("data").put("topP", 0.8); + node.getJSONObject("data").put("temperature", 0.8); + node.getJSONObject("data").put("maxTokens", 2048); + } + } + Tinyflow tinyflow = null; + for (int i = 0; i < nodeArr.size(); i++) { + JSONObject node = nodeArr.getJSONObject(i); + switch (node.getString("type")) { + case "llmNode": + JSONObject data = node.getJSONObject("data"); + QwenLlmConfig qwenLlmConfig = new QwenLlmConfig(); + // 千问apikey + qwenLlmConfig.setApiKey("sk-xxxxxxxxxxx"); + qwenLlmConfig.setModel("qwen-plus"); + tinyflow = new Tinyflow(id -> new QwenLlm(qwenLlmConfig), json.toJSONString()); + break; + case "zsk": + + break; + default: + break; + } + } + return tinyflow; + } + } diff --git a/tinyflow-java-demo/src/main/resources/static/workflow.html b/tinyflow-java-demo/src/main/resources/static/workflow.html index 2b12b3e..98aa842 100644 --- a/tinyflow-java-demo/src/main/resources/static/workflow.html +++ b/tinyflow-java-demo/src/main/resources/static/workflow.html @@ -176,7 +176,16 @@ .then(wf => { tinyflow = new Tinyflow.Tinyflow({ element: '#app', - data: JSON.parse(wf.graph) + data: JSON.parse(wf.graph), + provider: { + llm: () => [ + { + value: 'llm', + label: 'llm', + } + ], + knowledge: () => [] + } }); }) .catch(error => { -- Gitee