| | |
| | | <scope>compile</scope> |
| | | </dependency> |
| | | |
| | | <dependency> |
| | | <groupId>cn.hutool</groupId> |
| | | <artifactId>hutool-http</artifactId> |
| | | <scope>compile</scope> |
| | | </dependency> |
| | | |
| | | <dependency> |
| | | <groupId>cn.hutool</groupId> |
| | | <artifactId>hutool-json</artifactId> |
| | | <scope>compile</scope> |
| | | </dependency> |
| | | </dependencies> |
| | | |
| | | </project> |
| New file |
| | |
| | | package tech.aiflowy.common.ai.util; |
| | | import cn.hutool.core.util.ObjectUtil; |
| | | import cn.hutool.http.*; |
| | | import cn.hutool.json.JSONObject; |
| | | import cn.hutool.json.JSONUtil; |
| | | |
| | | import java.util.*; |
| | | |
| | | public class PluginHttpClient { |
| | | |
| | | private static final int TIMEOUT = 10_000; |
| | | |
| | | /** |
| | | * 发送插件请求,支持 path/query/body/header 四种参数类型 |
| | | * |
| | | * @param url API 地址 |
| | | * @param method HTTP 方法(GET, POST, PUT, DELETE) |
| | | * @param headers 默认请求头 |
| | | * @param pluginParams 插件参数定义列表 |
| | | * @return JSON 格式的响应结果 |
| | | */ |
| | | public static JSONObject sendRequest(String url, String method, Map<String, Object> headers, List<PluginParam> pluginParams) { |
| | | // 替换 URL 中的路径变量 |
| | | String processedUrl = replacePathVariables(url, pluginParams); |
| | | |
| | | // 设置请求方法 |
| | | Method httpMethod = Method.valueOf(method.toUpperCase()); |
| | | HttpRequest request = HttpRequest.of(processedUrl).method(httpMethod); |
| | | |
| | | // 处理请求头 |
| | | if (ObjectUtil.isNotEmpty(headers)) { |
| | | for (Map.Entry<String, Object> entry : headers.entrySet()) { |
| | | request.header(entry.getKey(), entry.getValue().toString()); |
| | | } |
| | | } |
| | | |
| | | // 分类参数 |
| | | Map<String, Object> queryParams = new HashMap<>(); |
| | | Map<String, Object> bodyParams = new HashMap<>(); |
| | | |
| | | for (PluginParam param : pluginParams) { |
| | | if (!param.isEnabled()) continue; |
| | | |
| | | String paramName = param.getName(); |
| | | Object paramValue = param.getDefaultValue(); |
| | | |
| | | if ("Query".equalsIgnoreCase(param.getMethod())) { |
| | | queryParams.put(paramName, paramValue); |
| | | } else if ("Body".equalsIgnoreCase(param.getMethod())) { |
| | | bodyParams.put(paramName, paramValue); |
| | | } else if ("Header".equalsIgnoreCase(param.getMethod())) { |
| | | request.header(paramName, paramValue.toString()); |
| | | } |
| | | } |
| | | |
| | | // 添加 Query 参数 |
| | | if (!queryParams.isEmpty()) { |
| | | request.form(queryParams); // GET 请求会自动转为 query string |
| | | } |
| | | |
| | | // 添加 Body 参数 |
| | | if (!bodyParams.isEmpty() && (httpMethod == Method.POST || httpMethod == Method.PUT)) { |
| | | request.body(JSONUtil.toJsonStr(bodyParams)); |
| | | request.header(Header.CONTENT_TYPE, ContentType.JSON.getValue()); |
| | | } |
| | | |
| | | // 执行请求 |
| | | HttpResponse response = request.timeout(TIMEOUT).execute(); |
| | | return JSONUtil.parseObj(response.body()); |
| | | } |
| | | |
| | | /** |
| | | * 替换 URL 中的路径变量 {xxx} |
| | | */ |
| | | private static String replacePathVariables(String url, List<PluginParam> pluginParams) { |
| | | String result = url; |
| | | |
| | | // 提取 path 类型的参数 |
| | | Map<String, Object> pathParams = new HashMap<>(); |
| | | for (PluginParam param : pluginParams) { |
| | | if ("path".equalsIgnoreCase(param.getMethod())) { |
| | | pathParams.put(param.getName(), param.getDefaultValue()); |
| | | } |
| | | } |
| | | |
| | | // 替换 URL 中的路径变量 |
| | | for (Map.Entry<String, Object> entry : pathParams.entrySet()) { |
| | | result = result.replaceAll("\\{" + entry.getKey() + "\\}", entry.getValue().toString()); |
| | | } |
| | | |
| | | return result; |
| | | } |
| | | } |
| New file |
| | |
| | | package tech.aiflowy.common.ai.util; |
| | | |
| | | public class PluginParam { |
| | | private String name; |
| | | private String description; |
| | | private String type; |
| | | private String method; // Query / Body / Header / PathVariable 等 |
| | | private Object defaultValue; |
| | | private boolean required; |
| | | private boolean enabled; |
| | | private String key; |
| | | |
| | | public String getName() { |
| | | return name; |
| | | } |
| | | |
| | | public void setName(String name) { |
| | | this.name = name; |
| | | } |
| | | |
| | | public String getDescription() { |
| | | return description; |
| | | } |
| | | |
| | | public void setDescription(String description) { |
| | | this.description = description; |
| | | } |
| | | |
| | | public String getType() { |
| | | return type; |
| | | } |
| | | |
| | | public void setType(String type) { |
| | | this.type = type; |
| | | } |
| | | |
| | | public String getMethod() { |
| | | return method; |
| | | } |
| | | |
| | | public void setMethod(String method) { |
| | | this.method = method; |
| | | } |
| | | |
| | | public Object getDefaultValue() { |
| | | return defaultValue; |
| | | } |
| | | |
| | | public void setDefaultValue(Object defaultValue) { |
| | | this.defaultValue = defaultValue; |
| | | } |
| | | |
| | | public boolean isRequired() { |
| | | return required; |
| | | } |
| | | |
| | | public void setRequired(boolean required) { |
| | | this.required = required; |
| | | } |
| | | |
| | | public boolean isEnabled() { |
| | | return enabled; |
| | | } |
| | | |
| | | public void setEnabled(boolean enabled) { |
| | | this.enabled = enabled; |
| | | } |
| | | |
| | | public String getKey() { |
| | | return key; |
| | | } |
| | | |
| | | public void setKey(String key) { |
| | | this.key = key; |
| | | } |
| | | } |
| | |
| | | <artifactId>aiflowy-common-file-storage</artifactId> |
| | | <version>1.0.0-alpha.1</version> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>cn.hutool</groupId> |
| | | <artifactId>hutool-core</artifactId> |
| | | </dependency> |
| | | </dependencies> |
| | | </project> |
| | |
| | | private AiPluginsService aiPluginsService; |
| | | @Resource |
| | | private AiBotPluginsService aiBotPluginsService; |
| | | @Resource |
| | | private AiPluginToolService aiPluginToolService; |
| | | |
| | | @PostMapping("updateOptions") |
| | | public Result updateOptions(@JsonBody("id") BigInteger id, @JsonBody("options") Map<String, Object> options) { |
| | |
| | | HumanMessage humanMessage = new HumanMessage(prompt); |
| | | |
| | | // 添加插件相关的function calling |
| | | appendPluginFunctions(botId, humanMessage); |
| | | appendPluginToolFunction(botId, humanMessage); |
| | | |
| | | //添加工作流相关的 Function Calling |
| | | appendWorkflowFunctions(botId, humanMessage); |
| | | // appendWorkflowFunctions(botId, humanMessage); |
| | | |
| | | //添加知识库相关的 Function Calling |
| | | appendKnowledgeFunctions(botId, humanMessage); |
| | |
| | | function_call(aiMessageResponse, emitter, needClose, historiesPrompt, llm, prompt, false); |
| | | } catch (Exception e) { |
| | | emitter.completeWithError(e); |
| | | } |
| | | } |
| | | |
| | | if (needClose[0]) { |
| | | System.out.println("function chat complete"); |
| | |
| | | HumanMessage humanMessage = new HumanMessage(); |
| | | |
| | | // 添加插件、工作流、知识库相关的 Function Calling |
| | | appendPluginFunctions(botId, humanMessage); |
| | | appendPluginToolFunction(botId, humanMessage); |
| | | // appendPluginFunctions(botId, humanMessage); |
| | | appendWorkflowFunctions(botId, humanMessage); |
| | | appendKnowledgeFunctions(botId, humanMessage); |
| | | |
| | |
| | | MySseEmitter emitter = new MySseEmitter((long) (1000 * 60 * 2)); |
| | | final Boolean[] needClose = {true}; |
| | | |
| | | // if (humanMessage.getFunctions() != null && !humanMessage.getFunctions().isEmpty()) { |
| | | if (humanMessage.getFunctions() != null && !humanMessage.getFunctions().isEmpty()) { |
| | | try { |
| | | AiMessageResponse aiMessageResponse = llm.chat(historiesPrompt); |
| | |
| | | } |
| | | } |
| | | |
| | | private void appendPluginFunctions(BigInteger botId, HumanMessage humanMessage) { |
| | | // private void appendPluginFunctions(BigInteger botId, HumanMessage humanMessage) { |
| | | // QueryWrapper queryWrapper = QueryWrapper.create().eq(AiBotPlugins::getBotId, botId); |
| | | // List<AiBotPlugins> aiBotPlugins = aiBotPluginsService.getMapper().selectListWithRelationsByQuery(queryWrapper); |
| | | // if (cn.hutool.core.collection.CollectionUtil.isNotEmpty(aiBotPlugins)) { |
| | | // for (AiBotPlugins aiBotPlugin : aiBotPlugins) { |
| | | // Function function = aiBotPlugin.getAiPlugins().toFunction(); |
| | | // humanMessage.addFunction(function); |
| | | // } |
| | | // } |
| | | // } |
| | | private void appendPluginToolFunction(BigInteger botId, HumanMessage humanMessage) { |
| | | QueryWrapper queryWrapper = QueryWrapper.create().eq(AiBotPlugins::getBotId, botId); |
| | | List<AiBotPlugins> aiBotPlugins = aiBotPluginsService.getMapper().selectListWithRelationsByQuery(queryWrapper); |
| | | if (cn.hutool.core.collection.CollectionUtil.isNotEmpty(aiBotPlugins)) { |
| | | for (AiBotPlugins aiBotPlugin : aiBotPlugins) { |
| | | Function function = aiBotPlugin.getAiPlugins().toFunction(); |
| | | humanMessage.addFunction(function); |
| | | // 根据插件iD查询该插件下面有哪些插件工具,转换成Function |
| | | for (AiBotPlugins aiBotPlugin: aiBotPlugins){ |
| | | BigInteger pluginId = aiBotPlugin.getPluginId(); |
| | | QueryWrapper queryTool = QueryWrapper.create() |
| | | .select("*") |
| | | .from("tb_ai_plugin_tool") |
| | | .where("plugin_id = ?", pluginId); |
| | | List<AiPluginTool> aiPluginTools = aiPluginToolService.getMapper().selectListWithRelationsByQuery(queryTool); |
| | | for (AiPluginTool item: aiPluginTools){ |
| | | humanMessage.addFunction(item.toFunction()); |
| | | } |
| | | |
| | | } |
| | | |
| | | } |
| | | } |
| | |
| | | import tech.aiflowy.common.web.jsonbody.JsonBody; |
| | | |
| | | import javax.annotation.Resource; |
| | | import java.math.BigInteger; |
| | | |
| | | /** |
| | | * 控制层。 |
| | |
| | | |
| | | // 插件工具修改页面查询 |
| | | @PostMapping("/tool/search") |
| | | public Result searchPlugin(@JsonBody(value = "aiPluginToolId", required = true) String aiPluginToolId){ |
| | | public Result searchPlugin(@JsonBody(value = "aiPluginToolId", required = true) BigInteger aiPluginToolId){ |
| | | return aiPluginToolService.searchPlugin(aiPluginToolId); |
| | | } |
| | | |
| New file |
| | |
| | | package tech.aiflowy.ai.entity; |
| | | |
| | | |
| | | import com.mybatisflex.annotation.RelationOneToOne; |
| | | import com.mybatisflex.annotation.Table; |
| | | |
| | | @Table("tb_ai_bot_plugins") |
| | | public class AiBotPluginTool { |
| | | |
| | | @RelationOneToOne(selfField = "pluginId", targetField = "id") |
| | | private AiPluginTool aiPluginTool; |
| | | |
| | | public AiPluginTool getAiPluginTool() { |
| | | return aiPluginTool; |
| | | } |
| | | |
| | | public void setAiPluginTool(AiPluginTool aiPluginTool) { |
| | | this.aiPluginTool = aiPluginTool; |
| | | } |
| | | } |
| | |
| | | public class AiBotPlugins extends AiBotPluginsBase { |
| | | |
| | | @RelationOneToOne(selfField = "pluginId", targetField = "id") |
| | | private AiPlugins aiPlugins; |
| | | private AiPlugin aiPlugin; |
| | | |
| | | public AiPlugins getAiPlugins() { |
| | | return aiPlugins; |
| | | public AiPlugin getAiPlugin() { |
| | | return aiPlugin; |
| | | } |
| | | |
| | | public void setAiPlugins(AiPlugins aiPlugins) { |
| | | this.aiPlugins = aiPlugins; |
| | | public void setAiPlugin(AiPlugin aiPlugin) { |
| | | this.aiPlugin = aiPlugin; |
| | | } |
| | | } |
| | |
| | | @Table("tb_ai_plugin") |
| | | public class AiPlugin extends AiPluginBase { |
| | | |
| | | |
| | | public String getTitle() { |
| | | return this.getName(); |
| | | } |
| | | |
| | | } |
| New file |
| | |
| | | package tech.aiflowy.ai.entity; |
| | | |
| | | import cn.hutool.core.util.StrUtil; |
| | | import cn.hutool.json.JSONObject; |
| | | import com.agentsflex.core.llm.functions.BaseFunction; |
| | | import com.agentsflex.core.llm.functions.Function; |
| | | import com.agentsflex.core.llm.functions.Parameter; |
| | | import com.fasterxml.jackson.core.JsonProcessingException; |
| | | import com.fasterxml.jackson.core.type.TypeReference; |
| | | import com.fasterxml.jackson.databind.ObjectMapper; |
| | | import com.mybatisflex.core.query.QueryWrapper; |
| | | import tech.aiflowy.ai.mapper.AiPluginMapper; |
| | | import tech.aiflowy.ai.service.AiPluginToolService; |
| | | import tech.aiflowy.common.ai.util.PluginHttpClient; |
| | | import tech.aiflowy.common.ai.util.PluginParam; |
| | | import tech.aiflowy.common.domain.Result; |
| | | import tech.aiflowy.common.util.SpringContextUtil; |
| | | |
| | | import java.math.BigInteger; |
| | | import java.util.ArrayList; |
| | | import java.util.HashMap; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | |
| | | public class AiPluginFunction implements Function { |
| | | |
| | | // 插件工具id |
| | | private BigInteger pluginToolId; |
| | | private String name; |
| | | private String description; |
| | | private Parameter[] parameters; |
| | | |
| | | public AiPluginFunction() { |
| | | |
| | | } |
| | | |
| | | public AiPluginFunction(AiPluginTool aiPluginTool) { |
| | | this.name = aiPluginTool.getName(); |
| | | this.description = aiPluginTool.getDescription(); |
| | | this.pluginToolId = aiPluginTool.getId(); |
| | | this.parameters = getDefaultParameters(); |
| | | } |
| | | |
| | | public BigInteger getPluginToolId() { |
| | | return pluginToolId; |
| | | } |
| | | |
| | | public void setPluginToolId(BigInteger pluginToolId) { |
| | | this.pluginToolId = pluginToolId; |
| | | } |
| | | |
| | | public void setName(String name) { |
| | | this.name = name; |
| | | } |
| | | |
| | | public void setDescription(String description) { |
| | | this.description = description; |
| | | } |
| | | |
| | | public void setParameters(Parameter[] parameters) { |
| | | this.parameters = parameters; |
| | | } |
| | | |
| | | private AiPlugin getAiPlugin(BigInteger pluginId) { |
| | | QueryWrapper queryWrapper = QueryWrapper.create() |
| | | .select("*") |
| | | .from("tb_ai_plugin") |
| | | .where("id = ?", pluginId); |
| | | AiPluginMapper aiPluginMapper = SpringContextUtil.getBean(AiPluginMapper.class); |
| | | AiPlugin aiPlugin1 = aiPluginMapper.selectOneByQuery(queryWrapper); |
| | | return aiPlugin1; |
| | | } |
| | | |
| | | private Parameter[] getDefaultParameters() { |
| | | AiPluginToolService pluginToolService = SpringContextUtil.getBean(AiPluginToolService.class); |
| | | QueryWrapper queryAiPluginToolWrapper = QueryWrapper.create() |
| | | .select("*") |
| | | .from("tb_ai_plugin_tool") |
| | | .where("id = ? ", this.pluginToolId); |
| | | AiPluginTool aiPluginTool = pluginToolService.getMapper().selectOneByQuery(queryAiPluginToolWrapper); |
| | | List<Map<String, Object>> dataList = getDataList(aiPluginTool.getInputData()); |
| | | Parameter[] params = new Parameter[dataList.size()]; |
| | | for (int i = 0; i < dataList.size(); i++) { |
| | | Map<String, Object> item = dataList.get(i); |
| | | Parameter parameter = new Parameter(); |
| | | parameter.setName((String) item.get("name")); |
| | | parameter.setDescription((String) item.get("description")); |
| | | parameter.setRequired((boolean) item.get("required")); |
| | | parameter.setType((String) item.get("type")); |
| | | params[i] = parameter; |
| | | } |
| | | return params; |
| | | } |
| | | |
| | | // 转换输入参数 |
| | | private List<Map<String, Object>> getDataList(String jsonArray){ |
| | | List<Map<String, Object>> dataList; |
| | | try { |
| | | dataList = new ObjectMapper().readValue( |
| | | jsonArray, |
| | | new TypeReference<List<Map<String, Object>>>(){} |
| | | ); |
| | | } catch (JsonProcessingException e) { |
| | | throw new RuntimeException(e); |
| | | } |
| | | return dataList; |
| | | } |
| | | |
| | | |
| | | @Override |
| | | public String getName() { |
| | | return name; |
| | | } |
| | | |
| | | @Override |
| | | public String getDescription() { |
| | | return description; |
| | | } |
| | | |
| | | @Override |
| | | public Parameter[] getParameters() { |
| | | return parameters; |
| | | } |
| | | |
| | | @Override |
| | | public Object invoke(Map<String, Object> argsMap) { |
| | | AiPluginToolService pluginToolService = SpringContextUtil.getBean(AiPluginToolService.class); |
| | | QueryWrapper queryAiPluginToolWrapper = QueryWrapper.create() |
| | | .select("*") |
| | | .from("tb_ai_plugin_tool") |
| | | .where("id = ? ", this.pluginToolId); |
| | | AiPluginTool aiPluginTool = pluginToolService.getMapper().selectOneByQuery(queryAiPluginToolWrapper); |
| | | String method = aiPluginTool.getRequestMethod().toUpperCase(); |
| | | AiPlugin aiPlugin = getAiPlugin(aiPluginTool.getPluginId()); |
| | | |
| | | String url; |
| | | if (!StrUtil.isEmpty(aiPluginTool.getBasePath())) { |
| | | url = aiPlugin.getBaseUrl()+aiPluginTool.getBasePath(); |
| | | } else { |
| | | url = aiPlugin.getBaseUrl()+"/"+aiPluginTool.getName(); |
| | | } |
| | | |
| | | List<Map<String, Object>> headers = getDataList(aiPlugin.getHeaders()); |
| | | Map<String, Object> headersMap = new HashMap<>(); |
| | | for (Map<String, Object> header : headers) { |
| | | headersMap.put((String) header.get("label"), header.get("value")); |
| | | } |
| | | |
| | | List<PluginParam> params = new ArrayList<>(); |
| | | List<Map<String, Object>> dataList = getDataList(aiPluginTool.getInputData()); |
| | | |
| | | // 遍历插件工具定义的参数列表 |
| | | for (Map<String, Object> paramDef : dataList) { |
| | | String paramName = (String) paramDef.get("name"); |
| | | |
| | | // 检查大模型返回的参数中是否包含当前参数 |
| | | if (argsMap != null && argsMap.containsKey(paramName)) { |
| | | PluginParam pluginParam = new PluginParam(); |
| | | pluginParam.setName(paramName); |
| | | pluginParam.setDescription((String) paramDef.get("description")); |
| | | pluginParam.setRequired((boolean) paramDef.get("required")); |
| | | pluginParam.setType((String) paramDef.get("type")); |
| | | pluginParam.setMethod((String) paramDef.get("method")); |
| | | pluginParam.setEnabled((boolean) paramDef.get("enabled")); |
| | | // 使用大模型返回的值,而不是默认值 |
| | | pluginParam.setDefaultValue(argsMap.get(paramName)); |
| | | |
| | | params.add(pluginParam); |
| | | } else if ((boolean) paramDef.get("required")) { |
| | | // 如果是必填参数但大模型没有返回,使用默认值或抛出异常 |
| | | PluginParam pluginParam = new PluginParam(); |
| | | pluginParam.setName(paramName); |
| | | pluginParam.setDescription((String) paramDef.get("description")); |
| | | pluginParam.setRequired(true); |
| | | pluginParam.setMethod((String) paramDef.get("method")); |
| | | pluginParam.setEnabled((boolean) paramDef.get("enabled")); |
| | | pluginParam.setType((String) paramDef.get("type")); |
| | | pluginParam.setDefaultValue(paramDef.get("defaultValue")); |
| | | params.add(pluginParam); |
| | | } |
| | | } |
| | | |
| | | JSONObject result = PluginHttpClient.sendRequest(url, method, headersMap, params); |
| | | return result; |
| | | } |
| | | } |
| | |
| | | package tech.aiflowy.ai.entity; |
| | | |
| | | import com.agentsflex.core.llm.functions.Function; |
| | | import com.mybatisflex.annotation.Table; |
| | | import tech.aiflowy.ai.entity.base.AiPluginToolBase; |
| | | |
| | |
| | | */ |
| | | @Table("tb_ai_plugin_tool") |
| | | public class AiPluginTool extends AiPluginToolBase { |
| | | |
| | | |
| | | |
| | | public Function toFunction() { |
| | | return new AiPluginFunction(this); |
| | | } |
| | | } |
| | |
| | | import com.mybatisflex.annotation.Id; |
| | | import com.mybatisflex.annotation.KeyType; |
| | | import java.io.Serializable; |
| | | import java.math.BigInteger; |
| | | import java.util.Date; |
| | | |
| | | |
| | |
| | | * 插件id |
| | | */ |
| | | @Id(keyType = KeyType.Generator, value = "snowFlakeId", comment = "插件id") |
| | | private Long id; |
| | | private BigInteger id; |
| | | |
| | | /** |
| | | * 图标地址 |
| | |
| | | @Column(comment = "创建时间") |
| | | private Date created; |
| | | |
| | | public Long getId() { |
| | | public BigInteger getId() { |
| | | return id; |
| | | } |
| | | |
| | | public void setId(Long id) { |
| | | public void setId(BigInteger id) { |
| | | this.id = id; |
| | | } |
| | | |
| | |
| | | import com.mybatisflex.annotation.KeyType; |
| | | |
| | | import java.io.Serializable; |
| | | import java.math.BigInteger; |
| | | import java.util.Date; |
| | | |
| | | |
| | |
| | | * 插件工具id |
| | | */ |
| | | @Id(keyType = KeyType.Generator, value = "snowFlakeId", comment = "插件工具id") |
| | | private Long id; |
| | | private BigInteger id; |
| | | |
| | | /** |
| | | * 插件id |
| | | */ |
| | | @Column(comment = "插件id") |
| | | private Long pluginId; |
| | | private BigInteger pluginId; |
| | | |
| | | /** |
| | | * 名称 |
| | |
| | | @Column(comment = "调试状态【0失败 1成功】") |
| | | private int debugStatus; |
| | | |
| | | public Long getId() { |
| | | public BigInteger getId() { |
| | | return id; |
| | | } |
| | | |
| | | public void setId(Long id) { |
| | | public void setId(BigInteger id) { |
| | | this.id = id; |
| | | } |
| | | |
| | | public Long getPluginId() { |
| | | public BigInteger getPluginId() { |
| | | return pluginId; |
| | | } |
| | | |
| | | public void setPluginId(Long pluginId) { |
| | | public void setPluginId(BigInteger pluginId) { |
| | | this.pluginId = pluginId; |
| | | } |
| | | |
| | |
| | | import tech.aiflowy.ai.entity.AiPluginTool; |
| | | import tech.aiflowy.common.domain.Result; |
| | | |
| | | import java.math.BigInteger; |
| | | |
| | | /** |
| | | * 服务层。 |
| | | * |
| | |
| | | |
| | | Result savePluginTool(AiPluginTool aiPluginTool); |
| | | |
| | | Result searchPlugin(String aiPluginToolId); |
| | | Result searchPlugin(BigInteger aiPluginToolId); |
| | | |
| | | Result updatePlugin(AiPluginTool aiPluginTool); |
| | | } |
| | |
| | | import tech.aiflowy.common.domain.Result; |
| | | |
| | | import javax.annotation.Resource; |
| | | import java.math.BigInteger; |
| | | import java.util.Date; |
| | | import java.util.HashMap; |
| | | import java.util.List; |
| | |
| | | } |
| | | |
| | | @Override |
| | | public Result searchPlugin(String aiPluginToolId) { |
| | | public Result searchPlugin(BigInteger aiPluginToolId) { |
| | | //查询当前插件工具 |
| | | QueryWrapper queryAiPluginToolWrapper = QueryWrapper.create() |
| | | .select("*") |
| | |
| | | // 查询当前的插件信息 |
| | | QueryWrapper queryAiPluginWrapper = QueryWrapper.create() |
| | | .select("*") |
| | | .from("tb_ai_plugin"); |
| | | .from("tb_ai_plugin") |
| | | .where("id = ?", aiPluginTool.getPluginId()); |
| | | AiPlugin aiPlugin = aiPluginMapper.selectOneByQuery(queryAiPluginWrapper); |
| | | Map<String, Object> result = new HashMap<>(); |
| | | result.put("data", aiPluginTool); |
| | |
| | | }) |
| | | |
| | | export const useAxios = makeUseAxios({ |
| | | // @ts-ignore |
| | | cache: axiosCache, |
| | | defaultOptions: { |
| | | useCache: false, |
| | |
| | | botId: params.id, |
| | | sessionId: getSessionId() |
| | | }); |
| | | console.log('pluginResult') |
| | | console.log(pluginResult) |
| | | useEffect(() => { |
| | | setChats(messageResult?.data) |
| | | }, [messageResult]); |
| | |
| | | children: |
| | | <div> |
| | | {pluginResult?.data?.map((item: any) => { |
| | | return <ListItem key={item.id} title={item.aiPlugins.title} |
| | | description={item.aiPlugins.description} |
| | | return <ListItem key={item.id} title={item.aiPlugin.name} |
| | | description={item.aiPlugin.description} |
| | | onButtonClick={() => { |
| | | Modal.confirm({ |
| | | title: '确定要删除该插件吗?', |
| | |
| | | Radio, |
| | | Row, |
| | | Select, |
| | | Space, Spin |
| | | Space, Spin, Tooltip |
| | | } from 'antd'; |
| | | import {usePage, usePostManual} from "../../../hooks/useApis.ts"; |
| | | import SearchForm from "../../../components/AntdCrud/SearchForm.tsx"; |
| | |
| | | name: item.name, |
| | | description: item.description, |
| | | baseUrl: item.baseUrl, |
| | | headers: JSON.parse(item.headers), |
| | | headers: item.headers?JSON.parse(item.headers):[], |
| | | authData: item.authData, |
| | | authType: item.authType, |
| | | position: item.position, |
| | |
| | | avatar={<Avatar src={item.icon || "/favicon.png"} />} |
| | | title={item.name} |
| | | description={ |
| | | <> |
| | | <p>{item.description}</p> |
| | | </> |
| | | <Tooltip title={item.description}> |
| | | <div style={{ |
| | | display: '-webkit-box', |
| | | WebkitLineClamp: 1, // 限制显示行数 |
| | | WebkitBoxOrient: 'vertical', |
| | | overflow: 'hidden', |
| | | textOverflow: 'ellipsis', |
| | | }}> |
| | | {item.description} |
| | | </div> |
| | | </Tooltip> |
| | | } |
| | | /> |
| | | </Card> |
| | |
| | | <Space key={key} style={{ display: 'flex', marginBottom: 8 }} align="baseline"> |
| | | <Form.Item |
| | | {...restField} |
| | | name={[name, 'first']} |
| | | rules={[{ required: true, message: 'Missing first name' }]} |
| | | name={[name, 'label']} |
| | | rules={[{ required: true, message: 'Missing label ' }]} |
| | | > |
| | | <Input placeholder="Headers Name" /> |
| | | </Form.Item> |
| | | <Form.Item |
| | | {...restField} |
| | | name={[name, 'last']} |
| | | rules={[{ required: true, message: 'Missing last name' }]} |
| | | name={[name, 'value']} |
| | | rules={[{ required: true, message: 'Missing value' }]} |
| | | > |
| | | <Input placeholder="Headers value" /> |
| | | </Form.Item> |
| | |
| | | import React, {useEffect, useState} from 'react'; |
| | | import {Button, Form, FormProps, Input, message, Modal, Space, Table, TableProps, Tag} from 'antd'; |
| | | import {Button, Form, FormProps, Input, message, Modal, Space, Table, TableProps, Tooltip} from 'antd'; |
| | | import {useLocation, useNavigate} from "react-router-dom"; |
| | | import {useLayout} from "../../../hooks/useLayout.tsx"; |
| | | import {useBreadcrumbRightEl} from "../../../hooks/useBreadcrumbRightEl.tsx"; |
| | | import {EditOutlined, PlusOutlined, RestOutlined} from "@ant-design/icons"; |
| | | import {ArrowLeftOutlined, EditOutlined, PlusOutlined, RestOutlined} from "@ant-design/icons"; |
| | | import TextArea from "antd/es/input/TextArea"; |
| | | import {usePage, usePostManual} from "../../../hooks/useApis.ts"; |
| | | import {convertDatetimeUtil} from "../../../libs/changeDatetimeUtil.tsx"; |
| | |
| | | |
| | | // 控制创建工具模态框的显示与隐藏 |
| | | const [isAddPluginToolModalOpen, setAddPluginToolIsOpen] = React.useState(false); |
| | | useBreadcrumbRightEl(<Button type={"primary"} onClick={() => { |
| | | setAddPluginToolIsOpen(true); |
| | | }}> |
| | | <PlusOutlined/>创建工具</Button>) |
| | | useBreadcrumbRightEl( |
| | | <div style={{display: 'flex', justifyContent: 'space-between', alignItems: 'center', gap: 16}}> |
| | | <div> |
| | | <Button onClick={() => navigate(-1)} icon={<ArrowLeftOutlined />}>返回</Button> |
| | | {/* 其他内容 */} |
| | | </div> |
| | | <div> |
| | | <Button type={"primary"} onClick={() => { |
| | | setAddPluginToolIsOpen(true); |
| | | }}> |
| | | <PlusOutlined/>创建工具</Button> |
| | | </div> |
| | | </div> |
| | | ) |
| | | |
| | | const { |
| | | loading, |
| | | result, |
| | |
| | | key: 'name', |
| | | }, |
| | | { |
| | | title: '输入参数', |
| | | dataIndex: 'inputParams', |
| | | key: 'inputParams', |
| | | title: '工具描述', |
| | | dataIndex: 'description', |
| | | key: 'description', |
| | | ellipsis: true, // 超出显示省略号 |
| | | render: (text: string) => ( |
| | | <Tooltip title={text}> |
| | | <span>{text}</span> |
| | | </Tooltip> |
| | | ), |
| | | }, |
| | | { |
| | | title: '调试状态', |
| | | dataIndex: 'debugStatus', |
| | | key: 'debugStatus', |
| | | render: (item: number) =>{ |
| | | if (item === 0){ |
| | | return <Tag color="error">失败</Tag> |
| | | } else if(item === 1){ |
| | | return <Tag color="success">成功</Tag> |
| | | } |
| | | |
| | | } |
| | | }, |
| | | // { |
| | | // title: '输入参数', |
| | | // dataIndex: 'inputParams', |
| | | // key: 'inputParams', |
| | | // }, |
| | | // { |
| | | // title: '调试状态', |
| | | // dataIndex: 'debugStatus', |
| | | // key: 'debugStatus', |
| | | // render: (item: number) =>{ |
| | | // if (item === 0){ |
| | | // return <Tag color="error">失败</Tag> |
| | | // } else if(item === 1){ |
| | | // return <Tag color="success">成功</Tag> |
| | | // } |
| | | // |
| | | // } |
| | | // }, |
| | | { |
| | | title: '创建时间', |
| | | dataIndex: 'created', |
| | |
| | | navigate('/ai/pluginToolEdit', { |
| | | state: { |
| | | id: record.id, |
| | | pluginId: id, |
| | | // 插件名称 |
| | | pluginTitle:pluginTitle, |
| | | // 插件工具名称 |
| | |
| | | import React, {useEffect, useState} from 'react'; |
| | | import {useLayout} from "../../../hooks/useLayout.tsx"; |
| | | import {useLocation} from "react-router-dom"; |
| | | import {useLocation, useNavigate} from "react-router-dom"; |
| | | import {Button, Collapse, Form, Input, message, Select, Space, Spin, Switch, Table} from "antd"; |
| | | import {usePost, usePostManual} from "../../../hooks/useApis.ts"; |
| | | import './less/pluginToolEdit.less' |
| | | import {DeleteOutlined, EditOutlined, PlusOutlined} from "@ant-design/icons"; |
| | | import {ArrowLeftOutlined, DeleteOutlined, EditOutlined, PlusOutlined} from "@ant-design/icons"; |
| | | import TextArea from "antd/es/input/TextArea"; |
| | | import {useBreadcrumbRightEl} from "../../../hooks/useBreadcrumbRightEl.tsx"; |
| | | |
| | | interface inputDataParameter { |
| | | key: string; |
| | |
| | | required: boolean; |
| | | enabled: boolean; |
| | | } |
| | | |
| | | |
| | | const PluginToolEdit: React.FC = () => { |
| | | const navigate = useNavigate(); |
| | | |
| | | useBreadcrumbRightEl( |
| | | <div> |
| | | <div> |
| | | <button onClick={() => navigate(-1)}>返回</button> |
| | | {/* 其他内容 */} |
| | | </div> |
| | | </div> |
| | | ) |
| | | const { setOptions } = useLayout(); |
| | | const location = useLocation(); |
| | | const { id, pluginTitle, pluginToolTitle } = location.state || {}; |
| | |
| | | const [isEditOutput, setIsEditOutput] = useState(false); |
| | | const [formInput] = Form.useForm(); |
| | | const [formOutput] = Form.useForm(); |
| | | |
| | | useBreadcrumbRightEl( |
| | | <div style={{display: 'flex', justifyContent: 'space-between', alignItems: 'center', gap: 16}}> |
| | | <div> |
| | | <Button onClick={() => navigate(-1)} icon={<ArrowLeftOutlined />}>返回</Button> |
| | | {/* 其他内容 */} |
| | | </div> |
| | | </div> |
| | | ) |
| | | const [editStates, setEditStates] = useState({ |
| | | '1': false, |
| | | '2': false, |
| | |
| | | breadcrumbs: [ |
| | | { title: '首页' }, |
| | | { title: '插件', href: `/ai/plugin` }, |
| | | { title: pluginTitle, href: `/ai/plugin` }, |
| | | { title: pluginToolTitle, href: `/ai/pluginTool` }, |
| | | { title: pluginTitle}, |
| | | { title: pluginToolTitle}, |
| | | { title: '修改' }, |
| | | ], |
| | | }); |
| | |
| | | <commonmark.version>0.18.0</commonmark.version> |
| | | <jsoup.version>1.16.1</jsoup.version> |
| | | <commons-io.version>2.18.0</commons-io.version> |
| | | <hutool-http.version>5.8.28</hutool-http.version> |
| | | <hutool-json.version>5.8.32</hutool-json.version> |
| | | </properties> |
| | | <dependencyManagement> |
| | | <dependencies> |
| | |
| | | </dependency> |
| | | |
| | | <dependency> |
| | | <groupId>cn.hutool</groupId> |
| | | <artifactId>hutool-http</artifactId> |
| | | <version>${hutool-http.version}</version> |
| | | </dependency> |
| | | |
| | | <dependency> |
| | | <groupId>cn.hutool</groupId> |
| | | <artifactId>hutool-json</artifactId> |
| | | <version>${hutool-json.version}</version> |
| | | </dependency> |
| | | |
| | | <dependency> |
| | | <groupId>com.google.zxing</groupId> |
| | | <artifactId>core</artifactId> |
| | | <version>3.5.3</version> |