mirror of
https://gitcode.com/ageerle/ruoyi-ai.git
synced 2026-04-14 20:33:40 +00:00
@@ -3728,3 +3728,26 @@ INSERT INTO `test_tree` VALUES (12, '000000', 10, 108, 3, '子节点88', 0, 103,
|
|||||||
INSERT INTO `test_tree` VALUES (13, '000000', 10, 108, 3, '子节点99', 0, 103, '2026-02-03 05:14:54', 1, NULL, NULL, 0);
|
INSERT INTO `test_tree` VALUES (13, '000000', 10, 108, 3, '子节点99', 0, 103, '2026-02-03 05:14:54', 1, NULL, NULL, 0);
|
||||||
|
|
||||||
SET FOREIGN_KEY_CHECKS = 1;
|
SET FOREIGN_KEY_CHECKS = 1;
|
||||||
|
|
||||||
|
INSERT INTO `t_workflow_component` (`id`, `uuid`, `name`, `title`, `remark`, `display_order`, `is_enable`, `create_time`, `update_time`, `is_deleted`, `tenant_id`) VALUES (17, '5cd68dccbbb411f0bb7840c2ba9a7fbc', 'Start', '开始', '流程由此开始', 0, 1, '2025-11-07 16:32:49', '2025-11-07 16:32:49', 0, '000000');
|
||||||
|
INSERT INTO `t_workflow_component` (`id`, `uuid`, `name`, `title`, `remark`, `display_order`, `is_enable`, `create_time`, `update_time`, `is_deleted`, `tenant_id`) VALUES (18, '5cd6ac69bbb411f0bb7840c2ba9a7fbc', 'End', '结束', '流程由此结束', 0, 1, '2025-11-07 16:32:49', '2025-11-07 16:32:49', 0, '000000');
|
||||||
|
INSERT INTO `t_workflow_component` (`id`, `uuid`, `name`, `title`, `remark`, `display_order`, `is_enable`, `create_time`, `update_time`, `is_deleted`, `tenant_id`) VALUES (19, '5cd6c8eabbb411f0bb7840c2ba9a7fbc', 'Answer', '生成回答', '调用大语言模型回答问题', 0, 1, '2025-11-07 16:32:49', '2025-11-07 16:32:49', 0, '000000');
|
||||||
|
INSERT INTO `t_workflow_component` (`id`, `uuid`, `name`, `title`, `remark`, `display_order`, `is_enable`, `create_time`, `update_time`, `is_deleted`, `tenant_id`) VALUES (20, '0b4369bb60dc46d6bd84ceb4e36184dc', 'KeywordExtractor', '关键词提取', '从文本中提取关键词', 0, 1, '2025-12-26 16:30:05', '2025-12-26 16:30:05', 0, '000000');
|
||||||
|
INSERT INTO `t_workflow_component` (`id`, `uuid`, `name`, `title`, `remark`, `display_order`, `is_enable`, `create_time`, `update_time`, `is_deleted`, `tenant_id`) VALUES (21, 'bb00fc2f52c74fec82ee3f99725b56bb', 'Switcher', '条件分支', '根据条件执行不同分支', 0, 1, '2025-12-26 16:30:46', '2025-12-26 16:30:46', 0, '000000');
|
||||||
|
INSERT INTO `t_workflow_component` (`id`, `uuid`, `name`, `title`, `remark`, `display_order`, `is_enable`, `create_time`, `update_time`, `is_deleted`, `tenant_id`) VALUES (22, 'f37dbcb8f0d5464d90fbb22774490a56', 'HumanFeedback', '人类', '人机沟通', 0, 1, '2025-12-30 17:37:14', '2025-12-30 17:37:14', 0, '000000');
|
||||||
|
INSERT INTO `t_workflow_component` (`id`, `uuid`, `name`, `title`, `remark`, `display_order`, `is_enable`, `create_time`, `update_time`, `is_deleted`, `tenant_id`) VALUES (23, 'af9d6d7b9c9b47f990ad25ec84912b73', 'Tongyiwanx', '阿里图像生成', '使用通义万相生成图像', 0, 1, '2025-12-26 16:32:25', '2025-12-26 16:32:25', 0, '000000');
|
||||||
|
INSERT INTO `t_workflow_component` (`id`, `uuid`, `name`, `title`, `remark`, `display_order`, `is_enable`, `create_time`, `update_time`, `is_deleted`, `tenant_id`) VALUES (24, 'a1e2c9d4b8f04e1a9c3d6f8e2a7b1c9d', 'MailSend', '发送邮箱', '发送邮箱', 0, 1, '2025-12-30 17:37:14', '2025-12-30 17:37:14', 0, '000000');
|
||||||
|
INSERT INTO `t_workflow_component` (`id`, `uuid`, `name`, `title`, `remark`, `display_order`, `is_enable`, `create_time`, `update_time`, `is_deleted`, `tenant_id`) VALUES (25, 'f1e2d3c4b5a67890f1e2d3c4b5a6f1e2', 'HttpRequest', '请求节点', '请求节点', 0, 1, '2025-12-30 17:37:14', '2025-12-30 17:37:14', 0, '000000');
|
||||||
|
INSERT INTO `chat_model` (`id`, `category`, `model_name`, `provider_code`, `model_describe`, `model_price`, `model_type`, `model_show`, `model_free`, `priority`, `api_host`, `api_key`, `create_dept`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`, `tenant_id`) VALUES (2022565766560468994, 'image', 'wan2.5-t2i-preview', 'Tongyiwanx', 'wan2.5-t2i-preview', 1, '1', 'Y', 'Y', 1, 'https://dashscope.aliyuncs.com/api/v1/services/aigc/multimodal-generation/generation', 'skxxxx', 103, 1, '2026-02-14 14:57:11', 1, '2026-02-14 14:57:11', '通义万相文生图', 0);
|
||||||
|
INSERT INTO `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query_param`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_dept`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (2021046920636690433, '流程管理', 0, 0, 'flow', '', NULL, 1, 0, 'M', '0', '0', NULL, 'ph:user-fill', 103, 1, '2026-02-10 10:21:50', 1, '2026-02-10 15:59:28', '');
|
||||||
|
INSERT INTO `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query_param`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_dept`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (2021047050391678978, '工作流编排', 2021046920636690433, 0, 'aiflowengine', 'aiflow/index', NULL, 1, 0, 'C', '0', '0', '', 'ph:user-fill', 103, 1, '2026-02-10 10:22:21', 1, '2026-02-10 16:04:41', '');
|
||||||
|
INSERT INTO `sys_config` (`config_id`, `tenant_id`, `config_name`, `config_key`, `config_value`, `config_type`, `create_dept`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (2027192921483309058, '000000', 'HTTP请求节点响应模板', 'node.httpRequest.template', '✅ HTTP请求节点:结束响应 - ', 'Y', 103, 1, '2026-02-27 09:23:51', 1, '2026-02-27 09:31:41', NULL);
|
||||||
|
INSERT INTO `sys_config` (`config_id`, `tenant_id`, `config_name`, `config_key`, `config_value`, `config_type`, `create_dept`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (2027193296990957569, '000000', '文生图节点响应模板', 'node.image.template', '🎨 文生图节点:结束响应 - 图片URL: ', 'Y', 103, 1, '2026-02-27 09:25:20', 1, '2026-02-27 09:31:52', NULL);
|
||||||
|
INSERT INTO `sys_config` (`config_id`, `tenant_id`, `config_name`, `config_key`, `config_value`, `config_type`, `create_dept`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (2027193820393959425, '000000', '发送邮箱节点响应模板', 'node.mailsend.template', '📧 发送邮箱节点:结束响应 - ', 'Y', 103, 1, '2026-02-27 09:27:25', 1, '2026-02-27 09:32:05', NULL);
|
||||||
|
INSERT INTO `sys_config` (`config_id`, `tenant_id`, `config_name`, `config_key`, `config_value`, `config_type`, `create_dept`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (2027194134438277122, '000000', '结束节点响应模板', 'node.end.template', '🔚 流程已执行完毕,如果您有其他需求,请随时重新发起请求。', 'Y', 103, 1, '2026-02-27 09:28:40', 1, '2026-02-27 09:32:53', NULL);
|
||||||
|
INSERT INTO `sys_config` (`config_id`, `tenant_id`, `config_name`, `config_key`, `config_value`, `config_type`, `create_dept`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (2027206492573335554, '000000', '人机交互节点响应模板', 'node.humanFeedback.template', '👤 人机交互节点:等待用户操作 - ', 'Y', 103, 1, '2026-02-27 10:17:46', 1, '2026-02-27 10:17:46', NULL);
|
||||||
|
INSERT INTO `sys_config` (`config_id`, `tenant_id`, `config_name`, `config_key`, `config_value`, `config_type`, `create_dept`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (2027208880369647617, '000000', '条件分支节点响应模板', 'node.switch.template', '🔀 条件分支节点:触发 -> 跳转到节点 ', 'Y', 103, 1, '2026-02-27 10:27:15', 1, '2026-02-27 10:35:54', NULL);
|
||||||
|
INSERT INTO `sys_config` (`config_id`, `tenant_id`, `config_name`, `config_key`, `config_value`, `config_type`, `create_dept`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (2027213914603995137, '000000', '大模型回答节点响应模板', 'node.llmAnswer.template', '🤖 LLM 节点 生成回答:', 'Y', 103, 1, '2026-02-27 10:47:16', 1, '2026-02-27 10:52:40', NULL);
|
||||||
|
INSERT INTO `sys_config` (`config_id`, `tenant_id`, `config_name`, `config_key`, `config_value`, `config_type`, `create_dept`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (2027214387000066050, '000000', '关键词提取响应模板', 'node.keywordExtractor.template', '🔑 关键词提取节点 处理完成 : ', 'Y', 103, 1, '2026-02-27 10:49:08', 1, '2026-02-27 10:52:08', NULL);
|
||||||
|
INSERT INTO `sys_config` (`config_id`, `tenant_id`, `config_name`, `config_key`, `config_value`, `config_type`, `create_dept`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (2027217577397391361, '000000', '工作流异常响应模板', 'node.exception.template', '🛑 工作流发生异常:', 'N', 103, 1, '2026-02-27 11:01:49', 1, '2026-02-27 11:02:01', NULL);
|
||||||
|
|
||||||
|
|||||||
17
pom.xml
17
pom.xml
@@ -56,11 +56,10 @@
|
|||||||
<!-- AI 相关依赖 -->
|
<!-- AI 相关依赖 -->
|
||||||
<langchain4j.version>1.11.0</langchain4j.version>
|
<langchain4j.version>1.11.0</langchain4j.version>
|
||||||
<langchain4j.community.version>1.11.0-beta19</langchain4j.community.version>
|
<langchain4j.community.version>1.11.0-beta19</langchain4j.community.version>
|
||||||
|
<langchain4j.community.zhipu.ai.version>1.1.0-beta7</langchain4j.community.zhipu.ai.version>
|
||||||
<langgraph4j.version>1.5.3</langgraph4j.version>
|
<langgraph4j.version>1.5.3</langgraph4j.version>
|
||||||
<weaviate.version>1.19.6</weaviate.version>
|
<weaviate.version>1.19.6</weaviate.version>
|
||||||
<dify.version>1.0.7</dify.version>
|
<dify.version>1.0.7</dify.version>
|
||||||
<!-- Apache Commons Compress - 用于POI处理ZIP格式 -->
|
|
||||||
<commons-compress.version>1.27.1</commons-compress.version>
|
|
||||||
|
|
||||||
|
|
||||||
<avatar-generator.version>1.1.0</avatar-generator.version>
|
<avatar-generator.version>1.1.0</avatar-generator.version>
|
||||||
@@ -397,13 +396,6 @@
|
|||||||
<version>${revision}</version>
|
<version>${revision}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- MCP模块 -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.ruoyi</groupId>
|
|
||||||
<artifactId>ruoyi-mcp</artifactId>
|
|
||||||
<version>${revision}</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- 企业微信SDK -->
|
<!-- 企业微信SDK -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.github.binarywang</groupId>
|
<groupId>com.github.binarywang</groupId>
|
||||||
@@ -418,13 +410,6 @@
|
|||||||
<version>${jackson-dataformat-xml.version}</version>
|
<version>${jackson-dataformat-xml.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- Apache Commons Compress - 用于POI处理ZIP格式,解决导出Excel时的NoSuchMethodError -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.commons</groupId>
|
|
||||||
<artifactId>commons-compress</artifactId>
|
|
||||||
<version>${commons-compress.version}</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</dependencyManagement>
|
</dependencyManagement>
|
||||||
|
|
||||||
|
|||||||
@@ -110,12 +110,6 @@
|
|||||||
<artifactId>ruoyi-aiflow</artifactId>
|
<artifactId>ruoyi-aiflow</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- MCP模块 -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.ruoyi</groupId>
|
|
||||||
<artifactId>ruoyi-mcp</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>de.codecentric</groupId>
|
<groupId>de.codecentric</groupId>
|
||||||
<artifactId>spring-boot-admin-starter-client</artifactId>
|
<artifactId>spring-boot-admin-starter-client</artifactId>
|
||||||
|
|||||||
@@ -58,9 +58,16 @@ spring:
|
|||||||
driverClassName: com.mysql.cj.jdbc.Driver
|
driverClassName: com.mysql.cj.jdbc.Driver
|
||||||
# jdbc 所有参数配置参考 https://lionli.blog.csdn.net/article/details/122018562
|
# jdbc 所有参数配置参考 https://lionli.blog.csdn.net/article/details/122018562
|
||||||
# rewriteBatchedStatements=true 批处理优化 大幅提升批量插入更新删除性能(对数据库有性能损耗 使用批量操作应考虑性能问题)
|
# rewriteBatchedStatements=true 批处理优化 大幅提升批量插入更新删除性能(对数据库有性能损耗 使用批量操作应考虑性能问题)
|
||||||
url: jdbc:mysql://127.0.0.1:3306/ruoyi-ai?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
|
url: jdbc:mysql://127.0.0.1:3306/ruoyi_ai_agent?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
|
||||||
username: root
|
username: root
|
||||||
password: root
|
password: root
|
||||||
|
agent:
|
||||||
|
url: jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
|
||||||
|
# url: jdbc:mysql://localhost:3306/agent_db
|
||||||
|
username: root
|
||||||
|
password: root
|
||||||
|
driverClassName: com.mysql.cj.jdbc.Driver
|
||||||
|
|
||||||
hikari:
|
hikari:
|
||||||
# 最大连接池数量
|
# 最大连接池数量
|
||||||
maxPoolSize: 20
|
maxPoolSize: 20
|
||||||
@@ -77,11 +84,7 @@ spring:
|
|||||||
# 多久检查一次连接的活性
|
# 多久检查一次连接的活性
|
||||||
keepaliveTime: 30000
|
keepaliveTime: 30000
|
||||||
|
|
||||||
agent:
|
|
||||||
mysql:
|
|
||||||
url: jdbc:mysql://localhost:3306/ruoyi-ai-agent?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
|
|
||||||
username: root
|
|
||||||
password: root
|
|
||||||
|
|
||||||
--- # 上传文件地址
|
--- # 上传文件地址
|
||||||
sys:
|
sys:
|
||||||
@@ -265,3 +268,4 @@ justauth:
|
|||||||
client-secret: 1f7d08**********5b7**********29e
|
client-secret: 1f7d08**********5b7**********29e
|
||||||
redirect-uri: ${justauth.address}/social-callback?source=gitea
|
redirect-uri: ${justauth.address}/social-callback?source=gitea
|
||||||
|
|
||||||
|
AGENT_ALLOWED_TABLES: "abtest_rule,abtest_project,agent_ban_log,agent_ban_logs,agent_install_sub_task,agent_install_sum_task,agent_install_task"
|
||||||
@@ -216,8 +216,6 @@ springdoc:
|
|||||||
packages-to-scan: org.ruoyi.generator
|
packages-to-scan: org.ruoyi.generator
|
||||||
- group: 5.工作流模块
|
- group: 5.工作流模块
|
||||||
packages-to-scan: org.ruoyi.workflow
|
packages-to-scan: org.ruoyi.workflow
|
||||||
- group: 6.MCP模块
|
|
||||||
packages-to-scan: org.ruoyi.mcp
|
|
||||||
|
|
||||||
# 防止XSS攻击
|
# 防止XSS攻击
|
||||||
xss:
|
xss:
|
||||||
@@ -359,14 +357,3 @@ knowledge:
|
|||||||
cache-enabled: true
|
cache-enabled: true
|
||||||
# 缓存过期时间(分钟)
|
# 缓存过期时间(分钟)
|
||||||
cache-expire-minutes: 60
|
cache-expire-minutes: 60
|
||||||
|
|
||||||
--- # MCP 模块配置
|
|
||||||
app:
|
|
||||||
mcp:
|
|
||||||
client:
|
|
||||||
# 请求超时时间(秒)
|
|
||||||
request-timeout: 30
|
|
||||||
# 连接超时时间(秒)
|
|
||||||
connection-timeout: 10
|
|
||||||
# 最大重试次数
|
|
||||||
max-retries: 3
|
|
||||||
|
|||||||
@@ -62,6 +62,12 @@
|
|||||||
<groupId>org.ruoyi</groupId>
|
<groupId>org.ruoyi</groupId>
|
||||||
<artifactId>ruoyi-common-tenant</artifactId>
|
<artifactId>ruoyi-common-tenant</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.swagger.core.v3</groupId>
|
||||||
|
<artifactId>swagger-annotations</artifactId>
|
||||||
|
<version>${swagger-annotations.version}</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
package org.ruoyi.workflow.base;
|
package org.ruoyi.common.chat.base;
|
||||||
|
|
||||||
import cn.dev33.satoken.stp.StpUtil;
|
import cn.dev33.satoken.stp.StpUtil;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.ruoyi.common.chat.entity.User;
|
||||||
|
import org.ruoyi.common.chat.enums.UserStatusEnum;
|
||||||
import org.ruoyi.common.core.domain.model.LoginUser;
|
import org.ruoyi.common.core.domain.model.LoginUser;
|
||||||
import org.ruoyi.common.core.exception.base.BaseException;
|
import org.ruoyi.common.core.exception.base.BaseException;
|
||||||
import org.ruoyi.common.satoken.utils.LoginHelper;
|
import org.ruoyi.common.satoken.utils.LoginHelper;
|
||||||
import org.ruoyi.workflow.entity.User;
|
|
||||||
import org.ruoyi.workflow.enums.UserStatusEnum;
|
|
||||||
|
|
||||||
import static org.ruoyi.workflow.enums.ErrorEnum.A_USER_NOT_FOUND;
|
import static org.ruoyi.common.chat.enums.ErrorEnum.A_USER_NOT_FOUND;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 线程上下文适配器,统一接入 Sa-Token 登录态。
|
* 线程上下文适配器,统一接入 Sa-Token 登录态。
|
||||||
@@ -1,13 +1,14 @@
|
|||||||
package org.ruoyi.domain.bo.chat;
|
package org.ruoyi.common.chat.domain.bo.chat;
|
||||||
|
|
||||||
import org.ruoyi.common.core.validate.AddGroup;
|
|
||||||
import org.ruoyi.common.core.validate.EditGroup;
|
|
||||||
import org.ruoyi.domain.entity.chat.ChatMessage;
|
|
||||||
import org.ruoyi.common.mybatis.core.domain.BaseEntity;
|
|
||||||
import io.github.linpeilie.annotations.AutoMapper;
|
import io.github.linpeilie.annotations.AutoMapper;
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import jakarta.validation.constraints.*;
|
import org.ruoyi.common.chat.entity.chat.ChatMessage;
|
||||||
|
import org.ruoyi.common.core.validate.AddGroup;
|
||||||
|
import org.ruoyi.common.core.validate.EditGroup;
|
||||||
|
import org.ruoyi.common.mybatis.core.domain.BaseEntity;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 聊天消息业务对象 chat_message
|
* 聊天消息业务对象 chat_message
|
||||||
@@ -4,7 +4,7 @@ import io.github.linpeilie.annotations.AutoMapper;
|
|||||||
import jakarta.validation.constraints.NotNull;
|
import jakarta.validation.constraints.NotNull;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import org.ruoyi.common.chat.domain.entity.chat.ChatModel;
|
import org.ruoyi.common.chat.entity.chat.ChatModel;
|
||||||
import org.ruoyi.common.core.validate.EditGroup;
|
import org.ruoyi.common.core.validate.EditGroup;
|
||||||
import org.ruoyi.common.mybatis.core.domain.BaseEntity;
|
import org.ruoyi.common.mybatis.core.domain.BaseEntity;
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,21 @@ public class ChatRequest {
|
|||||||
@NotEmpty(message = "传入的模型不能为空")
|
@NotEmpty(message = "传入的模型不能为空")
|
||||||
private String model;
|
private String model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 工作流请求体
|
||||||
|
*/
|
||||||
|
private WorkFlowRunner workFlowRunner;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 人机交互信息体
|
||||||
|
*/
|
||||||
|
private ReSumeRunner reSumeRunner;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否启用工作流
|
||||||
|
*/
|
||||||
|
private Boolean enableWorkFlow;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 会话id
|
* 会话id
|
||||||
*/
|
*/
|
||||||
@@ -41,6 +56,11 @@ public class ChatRequest {
|
|||||||
*/
|
*/
|
||||||
private Long uuid;
|
private Long uuid;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否为人机交互用户继续输入
|
||||||
|
*/
|
||||||
|
private Boolean isResume;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 是否启用深度思考
|
* 是否启用深度思考
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package org.ruoyi.common.chat.domain.dto.request;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 人机交互输入信息
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class ReSumeRunner {
|
||||||
|
/**
|
||||||
|
* 运行节点UUID
|
||||||
|
*/
|
||||||
|
private String runtimeUuid;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 人机交互用户输入信息
|
||||||
|
*/
|
||||||
|
private String feedbackContent;
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package org.ruoyi.common.chat.domain.dto.request;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 工作流请求体信息
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class WorkFlowRunner {
|
||||||
|
private List<ObjectNode> inputs;
|
||||||
|
private String uuid;
|
||||||
|
}
|
||||||
@@ -1,18 +1,17 @@
|
|||||||
package org.ruoyi.domain.vo.chat;
|
package org.ruoyi.common.chat.domain.vo.chat;
|
||||||
|
|
||||||
import org.ruoyi.domain.entity.chat.ChatMessage;
|
|
||||||
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
|
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
|
||||||
import cn.idev.excel.annotation.ExcelProperty;
|
import cn.idev.excel.annotation.ExcelProperty;
|
||||||
import org.ruoyi.common.excel.annotation.ExcelDictFormat;
|
|
||||||
import org.ruoyi.common.excel.convert.ExcelDictConvert;
|
|
||||||
import io.github.linpeilie.annotations.AutoMapper;
|
import io.github.linpeilie.annotations.AutoMapper;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import org.ruoyi.common.chat.entity.chat.ChatMessage;
|
||||||
|
import org.ruoyi.common.excel.annotation.ExcelDictFormat;
|
||||||
|
import org.ruoyi.common.excel.convert.ExcelDictConvert;
|
||||||
|
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 聊天消息视图对象 chat_message
|
* 聊天消息视图对象 chat_message
|
||||||
*
|
*
|
||||||
@@ -5,7 +5,7 @@ import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
|
|||||||
import cn.idev.excel.annotation.ExcelProperty;
|
import cn.idev.excel.annotation.ExcelProperty;
|
||||||
import io.github.linpeilie.annotations.AutoMapper;
|
import io.github.linpeilie.annotations.AutoMapper;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import org.ruoyi.common.chat.domain.entity.chat.ChatModel;
|
import org.ruoyi.common.chat.entity.chat.ChatModel;
|
||||||
|
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package org.ruoyi.workflow.entity;
|
package org.ruoyi.common.chat.entity;
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.annotation.IdType;
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
import com.baomidou.mybatisplus.annotation.TableField;
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
package org.ruoyi.workflow.entity;
|
package org.ruoyi.common.chat.entity;
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.annotation.TableField;
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import org.ruoyi.workflow.enums.UserStatusEnum;
|
import org.ruoyi.common.chat.enums.UserStatusEnum;
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package org.ruoyi.common.chat.domain.entity.chat;
|
package org.ruoyi.common.chat.entity.chat;
|
||||||
|
|
||||||
import dev.langchain4j.model.chat.response.StreamingChatResponseHandler;
|
import dev.langchain4j.model.chat.response.StreamingChatResponseHandler;
|
||||||
import jakarta.validation.constraints.NotNull;
|
import jakarta.validation.constraints.NotNull;
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
package org.ruoyi.domain.entity.chat;
|
package org.ruoyi.common.chat.entity.chat;
|
||||||
|
|
||||||
import org.ruoyi.common.tenant.core.TenantEntity;
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
import com.baomidou.mybatisplus.annotation.*;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
|
import org.ruoyi.common.tenant.core.TenantEntity;
|
||||||
|
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package org.ruoyi.common.chat.domain.entity.chat;
|
package org.ruoyi.common.chat.entity.chat;
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.annotation.TableId;
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
package org.ruoyi.common.chat.entity.image;
|
||||||
|
|
||||||
|
import jakarta.validation.constraints.Max;
|
||||||
|
import jakarta.validation.constraints.Min;
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import org.ruoyi.common.chat.domain.vo.chat.ChatModelVo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文生图对话上下文对象
|
||||||
|
*
|
||||||
|
* @author zengxb
|
||||||
|
* @date 2026-02-14
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = false)
|
||||||
|
@Builder
|
||||||
|
public class ImageContext {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 模型管理视图对象
|
||||||
|
*/
|
||||||
|
@NotNull(message = "模型管理视图对象不能为空")
|
||||||
|
private ChatModelVo chatModelVo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提示词
|
||||||
|
*/
|
||||||
|
@NotNull(message = "提示词不能为空")
|
||||||
|
private String prompt;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 图片尺寸大小
|
||||||
|
*/
|
||||||
|
private String size;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 随机数种子
|
||||||
|
*/
|
||||||
|
@Min(value = 0, message = "随机数种子不能小于0")
|
||||||
|
@Max(value = 2147483647, message = "随机数种子不能大于2147483647")
|
||||||
|
private Integer seed;
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package org.ruoyi.workflow.enums;
|
package org.ruoyi.common.chat.enums;
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.annotation.IEnum;
|
import com.baomidou.mybatisplus.annotation.IEnum;
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package org.ruoyi.workflow.enums;
|
package org.ruoyi.common.chat.enums;
|
||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package org.ruoyi.enums;
|
package org.ruoyi.common.chat.enums;
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
@@ -18,6 +18,7 @@ public enum RoleType {
|
|||||||
ASSISTANT("assistant"),
|
ASSISTANT("assistant"),
|
||||||
FUNCTION("function"),
|
FUNCTION("function"),
|
||||||
TOOL("tool"),
|
TOOL("tool"),
|
||||||
|
WORKFLOW("workFlow")
|
||||||
;
|
;
|
||||||
|
|
||||||
private final String name;
|
private final String name;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package org.ruoyi.workflow.enums;
|
package org.ruoyi.common.chat.enums;
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package org.ruoyi.common.chat.factory;
|
package org.ruoyi.common.chat.factory;
|
||||||
|
|
||||||
import org.ruoyi.common.chat.Service.IChatService;
|
import org.ruoyi.common.chat.service.chat.IChatService;
|
||||||
import org.springframework.beans.BeansException;
|
import org.springframework.beans.BeansException;
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.context.ApplicationContextAware;
|
import org.springframework.context.ApplicationContextAware;
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
package org.ruoyi.common.chat.factory;
|
||||||
|
|
||||||
|
import org.ruoyi.common.chat.service.image.IImageGenerationService;
|
||||||
|
import org.springframework.beans.BeansException;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
|
import org.springframework.context.ApplicationContextAware;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文生图服务工厂类
|
||||||
|
*
|
||||||
|
* @author zengxb
|
||||||
|
* @date 2026-02-14
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class ImageServiceFactory implements ApplicationContextAware {
|
||||||
|
|
||||||
|
private final Map<String, IImageGenerationService> imageSerivceMap = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||||
|
// 初始化时收集所有IImageGenerationService的实现
|
||||||
|
Map<String, IImageGenerationService> serviceMap = applicationContext.getBeansOfType(IImageGenerationService.class);
|
||||||
|
for (IImageGenerationService service : serviceMap.values()) {
|
||||||
|
if (service != null ) {
|
||||||
|
imageSerivceMap.put(service.getProviderName(), service);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取原始服务(不包装代理)
|
||||||
|
*/
|
||||||
|
public IImageGenerationService getOriginalService(String category) {
|
||||||
|
IImageGenerationService service = imageSerivceMap.get(category);
|
||||||
|
if (service == null) {
|
||||||
|
throw new IllegalArgumentException("不支持的模型类别: " + category);
|
||||||
|
}
|
||||||
|
return service;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package org.ruoyi.common.chat.Service;
|
package org.ruoyi.common.chat.service.chat;
|
||||||
|
|
||||||
import org.ruoyi.common.chat.domain.bo.chat.ChatModelBo;
|
import org.ruoyi.common.chat.domain.bo.chat.ChatModelBo;
|
||||||
import org.ruoyi.common.chat.domain.vo.chat.ChatModelVo;
|
import org.ruoyi.common.chat.domain.vo.chat.ChatModelVo;
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package org.ruoyi.common.chat.Service;
|
package org.ruoyi.common.chat.service.chat;
|
||||||
|
|
||||||
import jakarta.validation.Valid;
|
import jakarta.validation.Valid;
|
||||||
import org.ruoyi.common.chat.domain.entity.chat.ChatContext;
|
import org.ruoyi.common.chat.entity.chat.ChatContext;
|
||||||
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
|
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
package org.ruoyi.common.chat.service.chatMessage;
|
||||||
|
|
||||||
|
import org.ruoyi.common.chat.domain.bo.chat.ChatMessageBo;
|
||||||
|
import org.ruoyi.common.chat.domain.dto.request.ChatRequest;
|
||||||
|
import org.ruoyi.common.chat.domain.vo.chat.ChatModelVo;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 聊天信息抽象基类 - 保存聊天信息
|
||||||
|
*
|
||||||
|
* @author Zengxb
|
||||||
|
* @date 2026-02-24
|
||||||
|
*/
|
||||||
|
public abstract class AbstractChatMessageService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建日志对象
|
||||||
|
*/
|
||||||
|
Logger log = LoggerFactory.getLogger(AbstractChatMessageService.class);
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IChatMessageService chatMessageService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存聊天信息
|
||||||
|
*/
|
||||||
|
public void saveChatMessage(ChatRequest chatRequest, Long userId, String content, String role, ChatModelVo chatModelVo){
|
||||||
|
try {
|
||||||
|
// 验证必要的上下文信息
|
||||||
|
if (chatRequest == null || userId == null) {
|
||||||
|
log.warn("缺少必要的聊天上下文信息,无法保存消息");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建ChatMessageBo对象
|
||||||
|
ChatMessageBo messageBO = new ChatMessageBo();
|
||||||
|
messageBO.setUserId(userId);
|
||||||
|
messageBO.setSessionId(chatRequest.getSessionId());
|
||||||
|
messageBO.setContent(content);
|
||||||
|
messageBO.setRole(role);
|
||||||
|
messageBO.setModelName(chatRequest.getModel());
|
||||||
|
messageBO.setBillingType(chatModelVo.getModelType());
|
||||||
|
messageBO.setRemark(null);
|
||||||
|
|
||||||
|
chatMessageService.insertByBo(messageBO);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("保存{}聊天消息时出错: {}", getProviderName(), e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取服务提供商名称
|
||||||
|
*/
|
||||||
|
protected String getProviderName(){
|
||||||
|
return "默认工作流大模型";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
package org.ruoyi.service.chat;
|
package org.ruoyi.common.chat.service.chatMessage;
|
||||||
|
|
||||||
|
import org.ruoyi.common.chat.domain.bo.chat.ChatMessageBo;
|
||||||
import org.ruoyi.common.chat.domain.dto.ChatMessageDTO;
|
import org.ruoyi.common.chat.domain.dto.ChatMessageDTO;
|
||||||
|
import org.ruoyi.common.chat.domain.vo.chat.ChatMessageVo;
|
||||||
import org.ruoyi.common.mybatis.core.page.PageQuery;
|
import org.ruoyi.common.mybatis.core.page.PageQuery;
|
||||||
import org.ruoyi.common.mybatis.core.page.TableDataInfo;
|
import org.ruoyi.common.mybatis.core.page.TableDataInfo;
|
||||||
import org.ruoyi.domain.bo.chat.ChatMessageBo;
|
|
||||||
import org.ruoyi.domain.vo.chat.ChatMessageVo;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package org.ruoyi.common.chat.service.image;
|
||||||
|
|
||||||
|
import jakarta.validation.Valid;
|
||||||
|
import org.ruoyi.common.chat.entity.image.ImageContext;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 公共文生图接口
|
||||||
|
*/
|
||||||
|
public interface IImageGenerationService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据文字生成图片
|
||||||
|
*/
|
||||||
|
String generateImage(@Valid ImageContext imageContext);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取服务提供商名称
|
||||||
|
*/
|
||||||
|
String getProviderName();
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package org.ruoyi.common.chat.service.workFlow;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||||
|
import org.ruoyi.common.chat.entity.User;
|
||||||
|
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 工作流启动Service接口
|
||||||
|
*
|
||||||
|
* @author Zengxb
|
||||||
|
* @date 2026-02-24
|
||||||
|
*/
|
||||||
|
public interface IWorkFlowStarterService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 启动工作流
|
||||||
|
* @param user 用户
|
||||||
|
* @param workflowUuid 工作流UUID
|
||||||
|
* @param userInputs 用户输入信息
|
||||||
|
* @return 流式输出结果
|
||||||
|
*/
|
||||||
|
SseEmitter streaming(User user, String workflowUuid, List<ObjectNode> userInputs, Long sessionId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 恢复工作流
|
||||||
|
* @param runtimeUuid 运行时UUID
|
||||||
|
* @param userInput 用户输入
|
||||||
|
* @param sseEmitter SSE连接对象
|
||||||
|
*/
|
||||||
|
void resumeFlow(String runtimeUuid, String userInput, SseEmitter sseEmitter);
|
||||||
|
}
|
||||||
@@ -25,12 +25,6 @@
|
|||||||
<groupId>cn.idev.excel</groupId>
|
<groupId>cn.idev.excel</groupId>
|
||||||
<artifactId>fastexcel</artifactId>
|
<artifactId>fastexcel</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- Apache Commons Compress - 用于POI处理ZIP格式,解决Excel导出时的依赖冲突 -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.commons</groupId>
|
|
||||||
<artifactId>commons-compress</artifactId>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ public class SseEmitterManager {
|
|||||||
emitter.onCompletion(() -> {
|
emitter.onCompletion(() -> {
|
||||||
SseEmitter remove = emitters.remove(token);
|
SseEmitter remove = emitters.remove(token);
|
||||||
if (remove != null) {
|
if (remove != null) {
|
||||||
remove.complete();
|
// remove.complete();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
emitter.onTimeout(() -> {
|
emitter.onTimeout(() -> {
|
||||||
|
|||||||
@@ -6,6 +6,9 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
import org.ruoyi.common.core.utils.SpringUtils;
|
import org.ruoyi.common.core.utils.SpringUtils;
|
||||||
import org.ruoyi.common.sse.core.SseEmitterManager;
|
import org.ruoyi.common.sse.core.SseEmitterManager;
|
||||||
import org.ruoyi.common.sse.dto.SseMessageDto;
|
import org.ruoyi.common.sse.dto.SseMessageDto;
|
||||||
|
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SSE工具类
|
* SSE工具类
|
||||||
|
|||||||
@@ -121,23 +121,16 @@ public class GlobalExceptionHandler {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 拦截未知的运行时异常
|
* 拦截未知的运行时异常
|
||||||
* 注意:对于文件下载/导出等场景,IOException 可能是正常流程的一部分,
|
|
||||||
* 需要排除 export/download 等路径,避免干扰文件导出
|
|
||||||
*/
|
*/
|
||||||
|
@ResponseStatus(org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR)
|
||||||
@ExceptionHandler(IOException.class)
|
@ExceptionHandler(IOException.class)
|
||||||
public R<Void> handleIoException(IOException e, HttpServletRequest request) {
|
public void handleIoException(IOException e, HttpServletRequest request) {
|
||||||
String requestURI = request.getRequestURI();
|
String requestURI = request.getRequestURI();
|
||||||
if (requestURI.contains("sse")) {
|
if (requestURI.contains("sse")) {
|
||||||
// sse 经常性连接中断 例如关闭浏览器 直接屏蔽
|
// sse 经常性连接中断 例如关闭浏览器 直接屏蔽
|
||||||
return null;
|
return;
|
||||||
}
|
|
||||||
// 排除文件下载/导出相关的 IOException,让异常正常传播以便上层处理
|
|
||||||
if (requestURI.contains("/export") || requestURI.contains("/download")) {
|
|
||||||
// 重新抛出,让调用方处理
|
|
||||||
throw new RuntimeException("文件导出/下载IO异常: " + e.getMessage(), e);
|
|
||||||
}
|
}
|
||||||
log.error("请求地址'{}',连接中断", requestURI, e);
|
log.error("请求地址'{}',连接中断", requestURI, e);
|
||||||
return R.fail(e.getMessage());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -153,13 +146,6 @@ public class GlobalExceptionHandler {
|
|||||||
@ExceptionHandler(RuntimeException.class)
|
@ExceptionHandler(RuntimeException.class)
|
||||||
public R<Void> handleRuntimeException(RuntimeException e, HttpServletRequest request) {
|
public R<Void> handleRuntimeException(RuntimeException e, HttpServletRequest request) {
|
||||||
String requestURI = request.getRequestURI();
|
String requestURI = request.getRequestURI();
|
||||||
// 对于文件导出相关异常,不进行封装处理,让原始异常信息传播
|
|
||||||
Throwable cause = e.getCause();
|
|
||||||
if (requestURI.contains("/export") || requestURI.contains("/download")) {
|
|
||||||
log.error("请求地址'{}',文件导出/下载异常.", requestURI, e);
|
|
||||||
// 对于文件导出,直接返回异常信息,不进行额外封装
|
|
||||||
return R.fail(cause != null ? cause.getMessage() : e.getMessage());
|
|
||||||
}
|
|
||||||
log.error("请求地址'{}',发生未知异常.", requestURI, e);
|
log.error("请求地址'{}',发生未知异常.", requestURI, e);
|
||||||
return R.fail(e.getMessage());
|
return R.fail(e.getMessage());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,6 @@
|
|||||||
<module>ruoyi-demo</module>
|
<module>ruoyi-demo</module>
|
||||||
<module>ruoyi-generator</module>
|
<module>ruoyi-generator</module>
|
||||||
<module>ruoyi-job</module>
|
<module>ruoyi-job</module>
|
||||||
<module>ruoyi-mcp</module>
|
|
||||||
<module>ruoyi-system</module>
|
<module>ruoyi-system</module>
|
||||||
<module>ruoyi-wechat</module>
|
<module>ruoyi-wechat</module>
|
||||||
<module>ruoyi-workflow</module>
|
<module>ruoyi-workflow</module>
|
||||||
|
|||||||
@@ -81,12 +81,6 @@
|
|||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>io.swagger.core.v3</groupId>
|
|
||||||
<artifactId>swagger-annotations</artifactId>
|
|
||||||
<version>${swagger-annotations.version}</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.google.api-client</groupId>
|
<groupId>com.google.api-client</groupId>
|
||||||
<artifactId>google-api-client</artifactId>
|
<artifactId>google-api-client</artifactId>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package org.ruoyi.workflow.base;
|
package org.ruoyi.workflow.base;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import org.ruoyi.workflow.enums.ErrorEnum;
|
import org.ruoyi.common.chat.enums.ErrorEnum;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import io.swagger.v3.oas.annotations.Operation;
|
|||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
import jakarta.validation.constraints.Min;
|
import jakarta.validation.constraints.Min;
|
||||||
import jakarta.validation.constraints.NotNull;
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import org.ruoyi.common.chat.base.ThreadContext;
|
||||||
import org.ruoyi.common.core.domain.R;
|
import org.ruoyi.common.core.domain.R;
|
||||||
import org.ruoyi.workflow.base.ThreadContext;
|
|
||||||
import org.ruoyi.workflow.dto.workflow.*;
|
import org.ruoyi.workflow.dto.workflow.*;
|
||||||
import org.ruoyi.workflow.entity.WorkflowComponent;
|
import org.ruoyi.workflow.entity.WorkflowComponent;
|
||||||
import org.ruoyi.workflow.service.WorkflowComponentService;
|
import org.ruoyi.workflow.service.WorkflowComponentService;
|
||||||
@@ -72,7 +72,7 @@ public class WorkflowController {
|
|||||||
@Operation(summary = "流式响应")
|
@Operation(summary = "流式响应")
|
||||||
@PostMapping(value = "/run", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
|
@PostMapping(value = "/run", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
|
||||||
public SseEmitter sseAsk(@RequestBody WorkflowRunReq runReq) {
|
public SseEmitter sseAsk(@RequestBody WorkflowRunReq runReq) {
|
||||||
return workflowStarter.streaming(ThreadContext.getCurrentUser(), runReq.getUuid(), runReq.getInputs());
|
return workflowStarter.streaming(ThreadContext.getCurrentUser(), runReq.getUuid(), runReq.getInputs(),runReq.getSessionId());
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/mine/search")
|
@GetMapping("/mine/search")
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ public class WorkflowRuntimeController {
|
|||||||
@Operation(summary = "接收用户输入以继续执行剩余流程")
|
@Operation(summary = "接收用户输入以继续执行剩余流程")
|
||||||
@PostMapping(value = "/resume/{runtimeUuid}")
|
@PostMapping(value = "/resume/{runtimeUuid}")
|
||||||
public R resume(@PathVariable String runtimeUuid, @RequestBody WorkflowResumeReq resumeReq) {
|
public R resume(@PathVariable String runtimeUuid, @RequestBody WorkflowResumeReq resumeReq) {
|
||||||
workflowStarter.resumeFlow(runtimeUuid, resumeReq.getFeedbackContent());
|
workflowStarter.resumeFlow(runtimeUuid, resumeReq.getFeedbackContent(), resumeReq.getSseEmitter());
|
||||||
return R.ok();
|
return R.ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
package org.ruoyi.workflow.dto.workflow;
|
package org.ruoyi.workflow.dto.workflow;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class WorkflowResumeReq {
|
public class WorkflowResumeReq {
|
||||||
private String feedbackContent;
|
private String feedbackContent;
|
||||||
|
private SseEmitter sseEmitter;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import java.util.List;
|
|||||||
public class WorkflowRunReq {
|
public class WorkflowRunReq {
|
||||||
private List<ObjectNode> inputs;
|
private List<ObjectNode> inputs;
|
||||||
private String uuid;
|
private String uuid;
|
||||||
|
private Long sessionId;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.annotation.TableName;
|
|||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
|
import org.ruoyi.common.chat.entity.BaseEntity;
|
||||||
|
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.annotation.TableName;
|
|||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
|
import org.ruoyi.common.chat.entity.BaseEntity;
|
||||||
|
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.annotation.TableName;
|
|||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
|
import org.ruoyi.common.chat.entity.BaseEntity;
|
||||||
|
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.annotation.TableName;
|
|||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
|
import org.ruoyi.common.chat.entity.BaseEntity;
|
||||||
|
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.annotation.TableName;
|
|||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
|
import org.ruoyi.common.chat.entity.BaseEntity;
|
||||||
|
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.annotation.TableName;
|
|||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
|
import org.ruoyi.common.chat.entity.BaseEntity;
|
||||||
|
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package org.ruoyi.workflow.enums;
|
|||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
import org.ruoyi.common.chat.enums.BaseEnum;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user