72 Commits

Author SHA1 Message Date
ageerle
3c175ba28d chore: sync pending project changes 2026-08-04 15:23:19 +08:00
ageerle
e34592c3d4 release: prepare v3.1.0 2026-08-04 15:18:57 +08:00
ageerle
fd044a4752 docs: align README badges in one row 2026-07-30 00:22:22 +08:00
ageerle
6e264ad500 feat: streamline workflow orchestration and chat routing
Add Zhipu web search integration, remove obsolete workflow nodes and resume handling, and separate model, agent, and workflow chat execution.
2026-07-30 00:15:44 +08:00
ageerle
83fd1ee983 fix: 移除FastJson 1.2.83严重安全漏洞,替换为Jackson
- 移除FastJson 1.2.83依赖(存在严重RCE漏洞CVE-2022-25845等)
- 替换为Spring Boot内置的Jackson 2.18.2
- 修改6个Java文件的JSON处理逻辑
- 所有模块编译验证通过

修改文件:
1. pom.xml - 移除fastjson依赖定义
2. ruoyi-common-chat/pom.xml - 替换为jackson-databind
3. QwenFileUploadUtils.java - 千问文件上传JSON解析
4. ChatRequest.java - 移除FastJson注解
5. MailSendNode.java - 邮件节点JSON处理
6. SwitcherNode.java - 条件分支JSON处理
7. AbstractAuthWeChatEnterpriseRequest.java - 企业微信登录
8. AuthDingTalkV2Request.java - 钉钉登录

安全提升:消除FastJson反序列化RCE漏洞攻击面

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-29 14:59:20 +08:00
ageerle
7640de34e5 Merge pull request #318 from ageerle/feat/register-default-role-and-misc
feat: 注册默认角色绑定 + 短剧流式超时兜底 + trace 测试适配
2026-07-28 11:25:37 +08:00
ageerle
77846601ee test(retrieval): 适配 KnowledgeRetrievalServiceImpl 新增 trace 依赖
构造测试实例时补上 TraceRecordService 与 TraceProperties 两个新参数,
修复编译/构造失败。

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-28 11:22:26 +08:00
ageerle
b80dc6e23f fix(shortdrama): 流式生成增加首 token 90 秒超时兜底
部分聚合站对 stream=true 既不返回内容也不报错,外层 30 分钟总超时
才会失败,前端会长时间卡死。90 秒内未收到任何 token 时快速失败,
提示更换模型或使用同步生成。收到首 token 后取消兜底计时。

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-28 11:22:19 +08:00
ageerle
176cc67a5c feat(register): 新用户注册成功后绑定默认角色并补齐缺失菜单权限
- SysRegisterService: 注册成功后读取 sys.register.defaultRoleId 配置,
  为新用户绑定默认角色;未配置则静默跳过,不影响注册流程
- SysUserServiceImpl.registerUser: insert 后回写 userId 主键,
  供调用方绑定默认角色或登录使用
- SQL: 修正 知识管理 父菜单 perms(knowledge:info:list -> system:info:list),
  新增 system:session:* / system:attach:* / system:fragment:* 菜单,
  新建 普通用户 角色(租户 000000,data_scope=5 仅本人)及角色-菜单关联,
  写入 sys.register.defaultRoleId 配置项

解决注册用户无默认角色导致无权限访问 AI 对话界面、以及菜单权限标识
与控制器不一致无法授权的问题。

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-28 11:22:12 +08:00
ageerle
afaa86ef6e Merge branch 'fix/sse-session-trace-cleanup' 2026-07-23 15:38:50 +08:00
ageerle
d1a820728f fix(sse): SSE 改为按会话隔离 + 修 trace 租户 bug + 清理冗余
SSE 串台修复:
- SseEmitterManager 新增按 sessionId 维度的 connect/sendEvent/disconnect,
  每个会话一个 SSE 连接,替代原 userId+token 维度(同用户多会话串台)
- SseMessageDto 增加 sessionId + eventDto 字段,跨实例按会话路由
- SseTopicListener 优先按 sessionId 路由,回退原 userId/群发逻辑
- SseMessageUtils 增加 sessionId 重载,对话链路全部切换
- ChatServiceFacade / MyMcpClientListener / WorkflowStarter 切到 sessionId
- 通知/全局 /sse 端点保留 userId 模式(通知按用户)

trace 租户 bug 修复:
- trace_run / trace_node 加入 tenant.excludes,监控表跨租户全局可见,
  绕过异步线程租户上下文不传播导致 node 查不到的问题

冗余清理:
- 删除零使用的 @TraceNode 注解 + TraceNodeAspect 切面 + 对应单测
- TraceProperties 删除 recordDetail/maxInputLength/maxOutputLength
  (仅对已删切面生效,编程式埋点用 RagTracePayloadBuilder 不受影响)
- TracePayloadUtils 删除 input/output/asString 方法
- TraceConstants 删除无引用的 NODE_METHOD/HTTP/DB/CACHE/TASK/STREAM
- TraceContext 删除预留的 copyNodeStack
- TraceNodeVo 删除未用的 children 字段
- TraceRecordServiceImpl.getDetail 删除重复 enrich
- application.yml 删除 trace.payload 无效配置项
- RagTraceNodeTypes 删除无引用的 NODE_STREAM

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-23 15:35:10 +08:00
ageerle
11bb1dba0f Merge PR #308: 通用链路追踪模块与 RAG 对话全链路埋点 2026-07-23 15:10:40 +08:00
Obltv
345d2819d8 fix: 修复链路追踪输出记录及关闭追踪时的额外开销 2026-07-23 14:52:19 +08:00
Obltv
36e3cf8c52 fix: 修复链路追踪输出记录及关闭追踪时的额外开销 2026-07-23 14:45:43 +08:00
Obltv
06ff95cdc3 Merge upstream/main into feature/common-trace-rag-chat 2026-07-23 14:30:38 +08:00
ageerle
9adeee6c83 fix(short-drama): 修复角色形象跨分镜不一致
1. findRefImageIndex 补上 appearance 参数,与 findStoryboardReferenceImages
   的调用对齐。之前多形象角色(换装/青年老年)的 @imageN 绑定查的是
   默认形象 URL,和实际参考图列表对不上,导致 prompt 里没有 @imageN 标记
2. buildEnrichedVideoPrompt 角色段追加 visualDescription,
   文字 prompt 也承载外貌信息(发型/服装/体态),不能全靠参考图

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-21 16:06:06 +08:00
ageerle
e42d35f3bf fix: 工作流实体保留字转义 + 千问向量模型厂商映射
1. WorkflowRuntimeNode/WorkflowRuntime: input/output/status 字段加反引号,
   修复 MySQL 8.0 保留字导致 MyBatis-Plus SQL 解析异常 (#307)
2. EmbeddingModelFactory: 新增 providerCode→BeanName 映射,
   qianwen→alibailian,修复千问向量模型找不到 Bean 的问题 (#301)

Closes #307 #301

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-21 15:43:36 +08:00
ageerle
a69d1f51b9 feat: 打通 thinking 流式链路 + SqlAgent 表白名单校验
1. OllamaServiceImpl 补 .think() + .returnThinking(),对齐其他 provider (#306)
2. ChatServiceFacade.createCombinedHandler 新增 onPartialThinking,
   reasoning 内容经 SseMessageUtils.sendReasoning 流式推到前端 (#303)
3. SqlAgent 系统提示词追加无表时禁止执行 SQL 的规则 (#279)
4. ExecuteSqlQueryTool 代码层硬拦截:空白名单直接拒绝,
   有白名单则校验 SQL 中 FROM/JOIN 引用的表名 (#279)

Closes #303 #306 #279

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-21 15:31:32 +08:00
ageerle
911ae6cb1f fix: 修复 issue IJX5VV/IJPYWL/IHPUDA
- IJX5VV: 补全工作流 9 个节点消息模板 sys_config 配置(SQL 脚本合并重命名时遗失),
  附幂等增量脚本;此前节点执行会抛「请先配置该节点的响应模板」
- IJPYWL: 向量模型未配置维度时,Milvus/Qdrant 回退默认 1024,避免 Integer 拆箱 NPE
- IHPUDA: chat_provider.provider_icon 由 varchar(255) 加宽至 varchar(1000),
  容纳 minio 私有桶签名 URL,附增量脚本

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-21 15:28:28 +08:00
ageerle
9a2f326e42 fix(rag): 合并后修正-升级脚本兼容 MySQL 8、重解析按 docId 清理旧向量
1. 升级脚本 2026-07-20-knowledge-fragment-fid.sql 使用了 MySQL 8 不支持的
   ADD COLUMN IF NOT EXISTS(MariaDB 语法),在存量库执行会直接语法报错。
   改为与脚本内索引守卫一致的 information_schema 判断 + PREPARE 方式,保持幂等。

2. parse() 重新解析时按 fragment.fid 删除旧向量:存量数据的 fid 为迁移脚本
   回填的 MD5 值,与向量库中实际存储的随机 fid 不一致,首次重解析无法命中
   旧向量,导致新旧向量重复累积。改为写入新向量前先按 docId 清理(三种
   向量库策略均支持),写入失败时仍补偿删除新 fid。

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-21 14:33:28 +08:00
ageerle@163.com
46a8d6b552 Merge pull request #315 from MuSan-Li/update/2026-07-19-fixes
修复RAG相关逻辑优化:统一文档切割配置、向量数据生命周期、
统一检索服务(阈值/重排/缓存)、按知识库路由向量库、重新解析支持
2026-07-21 14:33:11 +08:00
evo
cf5423f69f fix(rag): 统一文档切割配置并支持重新解析 2026-07-21 12:18:19 +08:00
evo
177375a7b7 docs(rag): 更新完整修复与验收报告 2026-07-21 09:35:56 +08:00
evo
016bdbdd94 test(rag): 增加三向量库 Docker 生命周期测试 2026-07-21 09:35:56 +08:00
evo
41e0dcb528 chore(rag): 对齐默认向量配置并启用测试 2026-07-21 09:35:56 +08:00
evo
787e447d09 fix(aiflow): 接入统一知识库检索服务 2026-07-21 09:35:33 +08:00
evo
9c092ae3bb fix(chat): 统一单轮检索并完善多库上下文 2026-07-21 09:35:26 +08:00
evo
42bc8fea95 fix(rag): 完善向量路由批量写入与数据生命周期 2026-07-21 09:35:18 +08:00
evo
c4fc1e6fcf fix(rag): 隔离模型实例并修正缓存刷新 2026-07-21 09:35:07 +08:00
evo
6f6d0893ec fix(rag): 统一检索阈值重排降级与缓存语义 2026-07-21 09:34:56 +08:00
evo
a6a55202a3 fix(rag): 修复文本分片边界与字面量分隔符 2026-07-21 09:34:47 +08:00
ageerle@163.com
24bee53f9e feat: 新增 ChitChatAgent 闲聊兜底子 Agent 并接入 supervisor
简单任务无专业子 Agent 可用时由闲聊 Agent 兜底,避免 supervisor 空转返回空内容;通过 supervisorContext 约束仅在问候/闲聊场景路由到该 Agent。

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-20 16:08:48 +08:00
evo
afc9d3d17d fix: 修复本地启动、数据库初始化与构建问题 (#314)
* fix: 修复本地启动、数据库初始化与构建问题

* fix: 修复pr的一些问题提交
2026-07-19 13:42:43 +08:00
evo
97ce15d116 fix: 修复pr的一些问题提交 2026-07-19 13:30:09 +08:00
evo
879fe48945 fix: 修复本地启动、数据库初始化与构建问题 2026-07-19 12:20:22 +08:00
ageerle@163.com
5d834d924a feat: 编程助手按聊天模型过滤并补充 MCP 工具 thinking 事件,README 补充 copilot/uniapp 仓库
- CodingController.models 按 category=chat 过滤,编程对话只展示聊天模型
- 各 MCP 文件/命令工具在执行前推送 thinking 提示事件
- README/README_EN 项目源码表新增 ruoyi-copilot、ruoyi-uniapp 三端链接

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-17 14:47:18 +08:00
ageerle@163.com
fece90b307 feat: 新增短剧音频/编码模块、MCP 文件工具与 WebSocket 支持
- 短剧: 新增 ShortDramaAudio 实体/Mapper/BO/VO,扩展 ShortDramaServiceImpl
  合成逻辑与 FfmpegFilterGraphBuilder 滤镜图
- MCP: 新增 WriteFileTool/DeleteFileTool/ExecuteCommandTool,重构
  EditFileTool/ReadFileTool/ListDirectoryTool
- 编码: 新增 coding 模块(CodingAgent/WorkspaceService/SSE 事件通道)
- Atlas: 新增音频生成实现,扩展音视频/媒体实体与预测服务
- WebSocket: 新增公众号聊天 WebSocket 处理器与握手拦截
- 忽略 logs/ 目录,避免合成产物入库

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-17 11:52:53 +08:00
ageerle@163.com
06d110ed16 @docs: 修正 snailjob 注释里失效的 ry_job.sql 引用
实际建表脚本在 docs/script/sql/ruoyi-ai-v3_mysql8.sql(sj_ 前缀表),仓库中并无 ry_job.sql。
关联 issue #311。

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-15 18:25:55 +08:00
ageerle@163.com
dfcadda2bb @style: 修正 QdrantVectorStoreStrategy 缩进为空格
createSchema 调用与文件其余代码保持 4 空格缩进统一,避免 checkstyle/spotless 报错。

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-15 18:00:07 +08:00
Jack Jiang
3c9546ded9 fix: 修复 Qdrant 初始化创建集合问题 (#298) 2026-07-15 17:58:12 +08:00
Octopus
a3d82e092e Refresh MiniMax models and protocol support (#313)
Co-authored-by: octo-patch <266937838+octo-patch@users.noreply.github.com>
2026-07-15 17:43:51 +08:00
ageerle@163.com
96a1b741df fix: 兼容 Atlas 预测结果查询 404,避免前端轮询刷屏
Atlas /model/prediction/{id} 对已过期或不存在的任务返回 404
(常见于更换 API Key 后残留的旧任务)。原实现直接抛异常,前端
轮询反复触发错误提示。改为 404 时返回 status=failed 的响应,
让上层走正常失败分支落库,前端识别后终止轮询。

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-15 11:17:20 +08:00
ageerle@163.com
e7b7d1d084 更新README.md
Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-15 10:52:15 +08:00
ageerle@163.com
efc30c3ac8 docs: README 新增短剧服务 ruoyi-drama 源码链接
Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-14 22:30:10 +08:00
ageerle@163.com
2ae13aafd4 feat: 新增短剧/媒体生成能力并脱敏数据库脚本
- 新增音频/视频/图片生成服务与 Atlas、OpenAI 实现
- 新增短剧脚本生成、分镜与 ffmpeg 合成模块
- 新增 Coze/Dify 聊天 provider 及 Agent 配置
- 脱敏 SQL 脚本:移除真实 DeepSeek API Key,掩码 COS 桶名
- 清理过期的 SQL update 脚本与 chat 文档

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-14 21:49:03 +08:00
Obltv
e925050207 feat: 新增通用链路追踪模块与 RAG 对话全链路埋点
- 新增 ruoyi-common-trace 模块:TraceContext 上下文、TraceNodeAspect 注解切面、数据库双表持久化
- ChatServiceFacade / KnowledgeRetrievalServiceImpl 完成 RAG 对话 retrieval → rerank → llm-call 全链路采集
- 新增 TraceController 提供列表/详情/节点查询 API 及数据统计
- 支持 trace.enabled 开关、payload 长度截断、错误安全降级
- TraceNodeTemplate 模板封装标准节点生命周期,减少重复样板代码
2026-06-16 10:14:35 +08:00
ageerle@163.com
7aa67cfc2f docs: 移除赞助商区块引用样式及多余换行
- 去掉 blockquote 引用块样式消除左侧竖线
- 去掉多余 <br> 避免链接文字断行

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-10 18:19:04 +08:00
ageerle@163.com
6d38e2bf25 docs: 赞助商图片改用本地路径并新增火山引擎 CodingPlan
- Atlas Cloud 图片从远程链接改为 docs/image/sponsor/ 本地路径
- 新增火山引擎 CodingPlan 开发者计划赞助商(中英文 README 同步)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-10 18:14:46 +08:00
ageerle@163.com
8ed5e61f63 docs: 添加微信技术交流群二维码
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-05 10:25:18 +08:00
ageerle@163.com
c3c89f8cc8 docs: 调整中文版赞助商图标大小
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-02 11:44:42 +08:00
ageerle@163.com
a3a6bdbc55 docs: 调整英文版赞助商图标大小与中文版一致
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-02 11:43:37 +08:00
ageerle@163.com
07d9fc1f45 docs: 同步英文版 README 与中文版保持一致
- 移除英文版 Quick Start/Live Demo 章节
- 移除 Ecosystem Partners 章节,合并到 Sponsors
- 更新赞助商格式为图片横幅样式
- 社区交流改为微信/QQ 二维码(替换 Telegram)
- 移除 Acknowledgments 中的 Spring AI Alibaba Copilot
- 修复 Technical Architecture 多余空行
- 更新文档链接域名(pandarobot -> ruoyiai)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-02 11:38:48 +08:00
ageerle@163.com
73a60e3591 docs: 更新 Atlas Cloud 赞助链接添加推荐参数
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-21 14:37:14 +08:00
ageerle@163.com
c79848c654 feat: 替换 PPIO 为 Atlas Cloud 并增强知识库功能
- 将 PPIO 服务提供商替换为 Atlas Cloud
- 更新 README 赞助商信息
- 删除 PPIOEmbeddingProvider 和相关测试
- 知识库新增重排序、混合检索、相似度阈值等字段
- 更新 SQL 初始化脚本

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-21 11:18:59 +08:00
ageerle@163.com
ec092a11c3 docs: 添加 web coding 快速部署说明
在 README 中新增使用 web coding 急速部署的章节,包含在线体验链接和部署截图展示

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-30 17:45:16 +08:00
ageerle
9a7b727413 Merge pull request #293 from RobustH/main
升级RAG模块
2026-04-23 09:15:02 +08:00
RobustH
b8d16b7669 feat(rag): 对接用户端用户知识库对话,集成知识库配置应用 2026-04-23 00:52:53 +08:00
RobustH
058a4aee2a feat(rag): 新增测试配置应用的功能 2026-04-21 22:54:11 +08:00
RobustH
1b50c7f9f1 fix(rag): 修复合并重复,重排模型新增硅基流动供应商 2026-04-21 22:41:00 +08:00
RobustH
e7f53fd55f Merge remote-tracking branch 'origin/main'
# Conflicts:
#	ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/domain/bo/knowledge/KnowledgeInfoBo.java
#	ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/domain/entity/knowledge/KnowledgeInfo.java
#	ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/domain/vo/knowledge/KnowledgeInfoVo.java
#	ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/service/chat/impl/ChatServiceFacade.java
2026-04-21 21:41:51 +08:00
ageerle
07bdc5e585 Merge pull request #292 from yangzhen233/feature/rerank-model
Feature/rerank model
2026-04-20 21:06:27 +08:00
yangzhen
e1b8a5f011 新增千问3重排序模型,并附带新增sql文件 2026-04-20 16:07:02 +08:00
杨振
80ca76ea37 添加重排序功能 2026-04-20 01:02:09 +08:00
wangle
2c6ff66830 fix: 修正application.yml演示模式message缩进
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-19 13:42:39 +08:00
wangle
4f79a66559 feat: 添加小米MiMo、DeepSeek、自定义厂商等provider支持
- 新增小米MiMo服务实现类(MiMoServiceImpl)
- ChatModeType添加XIAOMI枚举
- 更新SQL初始化脚本,新增多家厂商(provider)和模型数据
- 添加2026-04-19数据库更新脚本
- application.yml演示模式排除路径增加attach/fragment/info接口
- 删除独立的minimax_provider.sql(数据已合并到主SQL)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-19 13:42:05 +08:00
wangle
22883b4334 Merge branch pr-280: 添加MiniMax作为LLM提供商
解决冲突:
- README: 保留Qdrant向量库信息 + 合并MiniMax模型接入
- pom.xml: 保留spring-boot-starter-test + 添加MiniMax测试依赖
- ChatModeType: 保留CUSTOM_API + 新增MINIMAX枚举
- MinimaxServiceImpl: 保留MyChatModelListener监听器

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-19 11:47:04 +08:00
RobustH
ccbf5c9520 feat(rag): 知识库检索测试新增混合检索 2026-04-14 23:18:29 +08:00
RobustH
1208c46cca feat(rag): 集成硅基流动、阿里百炼重排模型并全方位增强检索测试体验 2026-04-14 01:40:28 +08:00
RobustH
06a63c377e feat: 新增检索测试相关接口
- 实现向量 L2 归一化,统一 Milvus/Qdrant/Weaviate 检索评分为 [0, 1] 空间
2026-04-13 23:33:56 +08:00
RobustH
0fa25032a3 feat(knowledge): 优化知识库文件状态枚举为"未解析,解析中,解析成功,解析失败",支持异步线程池解析文档 2026-04-13 00:15:01 +08:00
RobustH
28ad29d6ed feat(knowledge): 完善知识库及附件统计功能并修复分块数统计问题 2026-04-12 18:38:32 +08:00
octopus
5d14eb20af feat: add MiniMax as first-class LLM provider
Add MiniMax AI as the 7th LLM provider, supporting chat (M2.7, M2.5,
M2.5-highspeed) and embedding (embo-01) models via OpenAI-compatible API.

Changes:
- Add MINIMAX enum to ChatModeType
- Add MinimaxServiceImpl chat provider (OpenAI-compat streaming)
- Add MinimaxEmbeddingProvider for vector embeddings
- Add SQL migration for provider and model registration
- Add 14 unit tests + 3 integration tests
- Update README/README_EN with MiniMax in provider list
2026-03-21 16:14:19 +08:00
355 changed files with 23908 additions and 3419 deletions

107
.github/workflows/publish-images.yml vendored Normal file
View File

@@ -0,0 +1,107 @@
name: Publish Docker Images
on:
push:
tags:
- 'v*.*.*'
concurrency:
group: publish-images-${{ github.ref_name }}
cancel-in-progress: false
env:
REGISTRY: ghcr.io
IMAGE_OWNER: ${{ github.repository_owner }}
RELEASE_TAG: ${{ github.ref_name }}
jobs:
publish:
name: Publish ${{ matrix.image }}
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
attestations: write
id-token: write
strategy:
fail-fast: false
matrix:
include:
- image: ruoyi-ai-backend
source: local
context: .
dockerfile: docs/docker/ruoyi-ai/Dockerfile.backend
- image: ruoyi-ai-mysql
source: local
context: .
dockerfile: docs/docker/ruoyi-ai/Dockerfile.mysql
- image: ruoyi-ai-admin
source: admin
context: build/ruoyi-admin
dockerfile: build/ruoyi-admin/apps/web-antd/Dockerfile
- image: ruoyi-ai-web
source: web
context: build/ruoyi-web
dockerfile: build/ruoyi-web/Dockerfile.frontend
steps:
- name: Checkout backend repository
uses: actions/checkout@v6
with:
ref: ${{ env.RELEASE_TAG }}
fetch-depth: 1
- name: Checkout admin repository
if: matrix.source == 'admin'
uses: actions/checkout@v6
with:
repository: ${{ github.repository_owner }}/ruoyi-admin
ref: ${{ env.RELEASE_TAG }}
path: build/ruoyi-admin
fetch-depth: 1
- name: Checkout web repository
if: matrix.source == 'web'
uses: actions/checkout@v6
with:
repository: ${{ github.repository_owner }}/ruoyi-web
ref: ${{ env.RELEASE_TAG }}
path: build/ruoyi-web
fetch-depth: 1
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to GHCR
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract Docker metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_OWNER }}/${{ matrix.image }}
tags: |
type=raw,value=${{ env.RELEASE_TAG }}
type=raw,value=latest
labels: |
org.opencontainers.image.source=https://github.com/${{ github.repository }}
org.opencontainers.image.version=${{ env.RELEASE_TAG }}
- name: Build and push image
uses: docker/build-push-action@v6
with:
context: ${{ matrix.context }}
file: ${{ matrix.dockerfile }}
platforms: linux/amd64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha,scope=${{ matrix.image }}
cache-to: type=gha,mode=max,scope=${{ matrix.image }}
provenance: true
sbom: true

5
.gitignore vendored
View File

@@ -23,6 +23,9 @@ target/
.idea .idea
.claude .claude
.github .github
!.github/
!.github/workflows/
!.github/workflows/**
*.iws *.iws
*.iml *.iml
*.ipr *.ipr
@@ -45,6 +48,7 @@ nbdist/
*.xml.versionsBackup *.xml.versionsBackup
*.swp *.swp
data/ data/
logs/
!*/build/*.java !*/build/*.java
!*/build/*.html !*/build/*.html
@@ -52,3 +56,4 @@ data/
.flattened-pom.xml .flattened-pom.xml
/.claude/settings.local.json /.claude/settings.local.json
/docs/docker/milvus/volumes/

272
README.md
View File

@@ -2,11 +2,7 @@
<div align="center"> <div align="center">
[![Contributors][contributors-shield]][contributors-url] [![Contributors][contributors-shield]][contributors-url] [![Forks][forks-shield]][forks-url] [![Stargazers][stars-shield]][stars-url] [![Issues][issues-shield]][issues-url] [![MIT License][license-shield]][license-url]
[![Forks][forks-shield]][forks-url]
[![Stargazers][stars-shield]][stars-url]
[![Issues][issues-shield]][issues-url]
[![MIT License][license-shield]][license-url]
<p align="center"> <p align="center">
@@ -17,226 +13,235 @@
<img src="docs/image/logo.png" alt="RuoYi AI Logo" width="120" height="120"> <img src="docs/image/logo.png" alt="RuoYi AI Logo" width="120" height="120">
### 企业级AI助手平台 ### Enterprise-Grade AI Assistant Platform
*开箱即用的全栈AI平台支持多智能体协同、Supervisor模式编排、多种决策模式、RAG技术和流程编排能力* *An out-of-the-box full-stack AI platform supporting multi-agent collaboration, Supervisor mode orchestration, and multiple decision models, with advanced RAG technology and visual workflow orchestration capabilities*
**[English](README_EN.md)** | **[📖 使用文档](https://doc.pandarobot.chat)** | **[中文](README_ZH.md)** | **[📖 Documentation](https://doc.ruoyiai.chat/)** |
**[🚀 在线体验](https://web.pandarobot.chat)** | **[🐛 问题反馈](https://github.com/ageerle/ruoyi-ai/issues)** | **[💡 功能建议](https://github.com/ageerle/ruoyi-ai/issues)** **[🚀 Live Demo](https://web.ruoyiai.chat/)** | **[🐛 Report Issues](https://github.com/ageerle/ruoyi-ai/issues)** | **[💡 Feature Requests](https://github.com/ageerle/ruoyi-ai/issues)**
</div> </div>
## ✨ 核心亮点
| 模块 | 现有能力
|:----------:|---
| **模型管理** | 多模型接入(OpenAI/DeepSeek/通义/智谱/MiniMax)、多模态理解、Coze/DIFY/FastGPT平台集成
| **知识管理** | 本地RAG + 向量库(Milvus/Weaviate/Qdrant) + 文档解析
| **工具管理** | Mcp协议集成、Skills能力 + 可扩展工具生态
| **流程编排** | 可视化工作流设计器、节点拖拽编排、SSE流式执行,目前已经支持模型调用,邮件发送,人工审核等节点
| **多智能体** | 基于Langchain4j的Agent框架、Supervisor模式编排,支持多种决策模型
## 🚀 快速体验 ## ✨ Core Features
### 在线演示 | Module | Current Capabilities |
|:---:|---|
| **Model Management** | Multi-model integration (DeepSeek/Zhipu/MIMO/Bailian/OpenAI), multi-modal understanding, Coze/DIFY/FastGPT/RAGFlow platform integration |
| **Knowledge Management** | Local RAG + Vector DB (Milvus/Weaviate/Qdrant) + Document parsing |
| **Tool Management** | MCP protocol integration, Skills capability + Extensible tool ecosystem |
| **Workflow Orchestration** | Visual workflow designer, drag-and-drop node orchestration, SSE streaming execution, currently supports model calls, email sending, manual review, and other nodes |
| **Multi-Agent** | Agent framework based on Langchain4j, Supervisor mode orchestration, supports multiple decision models, can flexibly combine tools and skills |
| 平台 | 地址 | 账号 | ### Project Repositories
|:------:|---|---|
| 用户端 | [web.pandarobot.chat](https://web.pandarobot.chat) | admin / admin123 |
| 管理后台 | [admin.pandarobot.chat](https://admin.pandarobot.chat) | admin / admin123 |
### 项目源码 | Module | GitHub Repository | Gitee Repository | GitCode Repository |
| 项目模块 | GitHub 仓库 | Gitee 仓库 | GitCode 仓库 |
|----------|-------------------------------------------------------|------------------------------------------------------|--------------------------------------------------------| |----------|-------------------------------------------------------|------------------------------------------------------|--------------------------------------------------------|
| 🔧 后端服务 | [ruoyi-ai](https://github.com/ageerle/ruoyi-ai) | [ruoyi-ai](https://gitee.com/ageerle/ruoyi-ai) | [ruoyi-ai](https://gitcode.com/ageerle/ruoyi-ai) | | 🔧 Backend | [ruoyi-ai](https://github.com/ageerle/ruoyi-ai) | [ruoyi-ai](https://gitee.com/ageerle/ruoyi-ai) | [ruoyi-ai](https://gitcode.com/ageerle/ruoyi-ai) |
| 🎨 用户前端 | [ruoyi-web](https://github.com/ageerle/ruoyi-web) | [ruoyi-web](https://gitee.com/ageerle/ruoyi-web) | [ruoyi-web](https://gitcode.com/ageerle/ruoyi-web) | | 🎨 User Frontend | [ruoyi-web](https://github.com/ageerle/ruoyi-web) | [ruoyi-web](https://gitee.com/ageerle/ruoyi-web) | [ruoyi-web](https://gitcode.com/ageerle/ruoyi-web) |
| 🛠️ 管理后台 | [ruoyi-admin](https://github.com/ageerle/ruoyi-admin) | [ruoyi-admin](https://gitee.com/ageerle/ruoyi-admin) | [ruoyi-admin](https://gitcode.com/ageerle/ruoyi-admin) | | 🛠️ Admin Panel | [ruoyi-admin](https://github.com/ageerle/ruoyi-admin) | [ruoyi-admin](https://gitee.com/ageerle/ruoyi-admin) | [ruoyi-admin](https://gitcode.com/ageerle/ruoyi-admin) |
| 🎬 Drama | [ruoyi-drama](https://github.com/ageerle/ruoyi-drama) | [ruoyi-drama](https://gitee.com/ageerle/ruoyi-drama) | [ruoyi-drama](https://gitcode.com/ageerle/ruoyi-drama) |
| 🤖 Copilot | [ruoyi-copilot](https://github.com/ageerle/ruoyi-copilot) | [ruoyi-copilot](https://gitee.com/ageerle/ruoyi-copilot) | [ruoyi-copilot](https://gitcode.com/ageerle/ruoyi-copilot) |
| 📱 Mini-App | [ruoyi-uniapp](https://github.com/ageerle/ruoyi-uniapp) | [ruoyi-uniapp](https://gitee.com/ageerle/ruoyi-uniapp) | [ruoyi-uniapp](https://gitcode.com/ageerle/ruoyi-uniapp) |
### 合作项目 ### Partner Projects
| 项目名称 | GitHub 仓库 | Gitee 仓库 | Project Name | GitHub Repository | Gitee Repository |
|----------------|-------------------------------------------------------|------------------------------------------------------| |----------------|-------------------------------------------------------|------------------------------------------------------|
| element-plus-x | [element-plus-x](https://github.com/element-plus-x/Element-Plus-X) | [element-plus-x](https://gitee.com/he-jiayue/element-plus-x) | | element-plus-x | [element-plus-x](https://github.com/element-plus-x/Element-Plus-X) | [element-plus-x](https://gitee.com/he-jiayue/element-plus-x) |
## 🛠️ 技术架构 ## 🛠️ Technical Architecture
### 核心框架 ### Core Framework
- **后端架构**Spring Boot 3.5.8 + Langchain4j - **Backend**: Spring Boot 3.5.8 + Langchain4j
- **数据存储**MySQL 8.0 + Redis + 向量数据库(Milvus/Weaviate/Qdrant - **Data Storage**: MySQL 8.0 + Redis + Vector Databases (Milvus/Weaviate/Qdrant)
- **前端技术**Vue 3 + Vben Admin + element-plus-x - **Frontend**: Vue 3 + Vben Admin + element-plus-x
- **安全认证**Sa-Token + JWT 双重保障 - **Security**: Sa-Token + JWT dual-layer security
- **Document Processing**: PDF, Word, Excel parsing, intelligent image analysis
- **Real-time Communication**: WebSocket real-time communication, SSE streaming response
- **System Monitoring**: Comprehensive logging system, performance monitoring, service health checks
## 🐳 Docker Deployment
- **文档处理**PDF、Word、Excel 解析,图像智能分析 This project provides two Docker deployment methods:
- **实时通信**WebSocket 实时通信SSE 流式响应
- **系统监控**:完善的日志体系、性能监控、服务健康检查
## 🐳 Docker 部署 ### Method 1: One-click Start All Services (Recommended)
本项目提供两种 Docker 部署方式: Use `docker-compose-all.yaml` to start all services at once (including backend, admin panel, user frontend, and dependencies):
### 方式一:一键启动所有服务(推荐)
使用 `docker-compose-all.yaml` 可以一键启动所有服务(包括后端、管理端、用户端及依赖服务):
```bash ```bash
# 克隆仓库 # Clone the repository
git clone https://github.com/ageerle/ruoyi-ai.git git clone https://github.com/ageerle/ruoyi-ai.git
cd ruoyi-ai cd ruoyi-ai
# 启动所有服务(从镜像仓库拉取预构建镜像) # Start all services (pull pre-built images from GHCR)
docker-compose -f docker-compose-all.yaml up -d docker compose -f docs/docker/ruoyi-ai/docker-compose-all.yaml up -d
# 查看服务状态 # Check service status
docker-compose -f docker-compose-all.yaml ps docker compose -f docs/docker/ruoyi-ai/docker-compose-all.yaml ps
# 访问服务 # Access services
# 管理端: http://localhost:25666 (admin / admin123) # Admin Panel: http://localhost:25666 (admin / admin123)
# 用户端: http://localhost:25137 # User Frontend: http://localhost:25137
# 后端API: http://localhost:26039 # Backend API: http://localhost:26039
``` ```
### 方式二:分步部署(源码编译) ### Method 2: Step-by-step Deployment (Source Build)
如果您需要从源码构建后端服务,请按照以下步骤操作: If you need to build backend services from source, follow these steps:
#### 第一步:部署后端服务 #### Step 1: Deploy Backend Service
```bash ```bash
# 进入后端项目目录 # Enter backend project directory
cd ruoyi-ai cd ruoyi-ai
# 启动后端服务(源码编译构建) # Start backend service (build from source)
docker-compose up -d --build docker-compose up -d --build
# 等待后端服务启动完成 # Wait for backend service to start
docker-compose logs -f backend docker-compose logs -f backend
``` ```
#### 第二步:部署管理端 #### Step 2: Deploy Admin Panel
```bash ```bash
# 进入管理端项目目录 # Enter admin panel project directory
cd ruoyi-admin cd ruoyi-admin
# 构建并启动管理端 # Build and start admin panel
docker-compose up -d --build docker-compose up -d --build
# 访问管理端 # Access admin panel
# 地址: http://localhost:5666 # URL: http://localhost:5666
``` ```
#### 第三步:部署用户端(可选) #### Step 3: Deploy User Frontend (Optional)
```bash ```bash
# 进入用户端项目目录 # Enter user frontend project directory
cd ruoyi-web cd ruoyi-web
# 构建并启动用户端 # Build and start user frontend
docker-compose up -d --build docker-compose up -d --build
# 访问用户端 # Access user frontend
# 地址: http://localhost:5137 # URL: http://localhost:5137
``` ```
### 服务端口说明 ### Service Ports
| 服务 | 一键启动端口 | 分步部署端口 | 说明 | | Service | One-click Port | Step-by-step Port | Description |
|------|-------------|-------------|------| |------|-------------|-------------|------|
| 管理端 | 25666 | 5666 | 管理后台访问地址 | | Admin Panel | 25666 | 5666 | Admin backend access |
| 用户端 | 25137 | 5137 | 用户前端访问地址 | | User Frontend | 25137 | 5137 | User frontend access |
| 后端服务 | 26039 | 6039 | 后端 API 服务 | | Backend Service | 26039 | 6039 | Backend API service |
| MySQL | 23306 | 23306 | 数据库服务 | | MySQL | 23306 | 23306 | Database service |
| Redis | 26379 | 6379 | 缓存服务 | | Redis | 26379 | 6379 | Cache service |
| Weaviate | 28080 | 28080 | 向量数据库 | | Weaviate | 28080 | 28080 | Vector database |
| MinIO API | 29000 | 9000 | 对象存储 API | | MinIO API | 29000 | 9000 | Object storage API |
| MinIO Console | 29090 | 9090 | 对象存储控制台 | | MinIO Console | 29090 | 9090 | Object storage console |
### 镜像仓库 ### Image Registry
所有镜像托管在阿里云容器镜像服务: Application images are published to GitHub Container Registry (GHCR) by GitHub Actions when a release tag such as `v3.1.0` is pushed:
``` ```
crpi-31mraxd99y2gqdgr.cn-beijing.personal.cr.aliyuncs.com/ruoyi_ai ghcr.io/ageerle/ruoyi-ai-backend:v3.1.0
ghcr.io/ageerle/ruoyi-ai-mysql:v3.1.0
ghcr.io/ageerle/ruoyi-ai-admin:v3.1.0
ghcr.io/ageerle/ruoyi-ai-web:v3.1.0
``` ```
可用镜像: The Compose file defaults to `latest`. To pin a release, create `docs/docker/ruoyi-ai/.env` with `RUIYI_VERSION=v3.1.0`.
- `mysql:v3` - MySQL 数据库(包含初始化 SQL
- `redis:6.2` - Redis 缓存
- `weaviate:1.30.0` - 向量数据库
- `minio:latest` - 对象存储
- `ruoyi-ai-backend:latest` - 后端服务
- `ruoyi-ai-admin:latest` - 管理端前端
- `ruoyi-ai-web:latest` - 用户端前端
### 常用命令 After the first workflow run, set the four GHCR packages to `Public` in GitHub so deployment servers can pull them without logging in.
The same release tag must exist in `ageerle/ruoyi-admin` and `ageerle/ruoyi-web`; the publish workflow checks out those repositories at the backend release tag before building their images.
### Common Commands
```bash ```bash
# 停止所有服务 # Stop all services
docker-compose -f docker-compose-all.yaml down docker compose -f docs/docker/ruoyi-ai/docker-compose-all.yaml down
# 查看服务日志 # View service logs
docker-compose -f docker-compose-all.yaml logs -f [服务名] docker compose -f docs/docker/ruoyi-ai/docker-compose-all.yaml logs -f [service-name]
# 重启某个服务 # Restart a service
docker-compose -f docker-compose-all.yaml restart [服务名] docker compose -f docs/docker/ruoyi-ai/docker-compose-all.yaml restart [service-name]
``` ```
## 📚 使用文档 ## 📚 Documentation
想要深入了解安装部署、功能配置和二次开发? Want to learn more about installation, deployment, configuration, and secondary development?
**👉 [完整使用文档](https://doc.pandarobot.chat)** **👉 [Complete Documentation](https://doc.ruoyiai.chat/)**
## 🤝 参与贡献 ## 🤝 Contributing
我们热烈欢迎社区贡献!无论您是资深开发者还是初学者,都可以为项目贡献力量 💪 We warmly welcome community contributions! Whether you are a seasoned developer or just getting started, you can contribute to the project 💪
### 贡献方式 ### How to Contribute
1. **Fork** 项目到您的账户 1. **Fork** the project to your account
2. **创建分支** (`git checkout -b feature/新功能名称`) 2. **Create a branch** (`git checkout -b feature/new-feature-name`)
3. **提交代码** (`git commit -m '添加某某功能'`) 3. **Commit your changes** (`git commit -m 'Add new feature'`)
4. **推送分支** (`git push origin feature/新功能名称`) 4. **Push to the branch** (`git push origin feature/new-feature-name`)
5. **发起 Pull Request** 5. **Create a Pull Request**
> 💡 **小贴士**:建议将 PR 提交到 GitHub我们会自动同步到其他代码托管平台 > 💡 **Tip**: We recommend submitting PRs to GitHub, we will automatically sync to other code hosting platforms
## 📄 开源协议 ## 📄 License
本项目采用 **MIT 开源协议**,详情请查看 [LICENSE](LICENSE) 文件。 This project is licensed under the **MIT License**. See the [LICENSE](LICENSE) file for details.
## 🙏 特别鸣谢 ## 🙏 Acknowledgments
感谢以下优秀的开源项目为本项目提供支持: Thanks to the following excellent open-source projects for their support:
- [Spring AI Alibaba Copilot](https://github.com/spring-ai-alibaba/copilot) - 基于spring-ai-alibaba - [Langchain4j](https://github.com/langchain4j/langchain4j) - Powerful Java LLM development framework
的智能编码助手 - [RuoYi-Vue-Plus](https://gitee.com/dromara/RuoYi-Vue-Plus) - Mature enterprise-level rapid development framework
- [Langchain4j](https://github.com/langchain4j/langchain4j) - 强大的 Java LLM 开发框架 - [Vben Admin](https://github.com/vbenjs/vue-vben-admin) - Modern Vue admin template
- [RuoYi-Vue-Plus](https://gitee.com/dromara/RuoYi-Vue-Plus) - 成熟的企业级快速开发框架
- [Vben Admin](https://github.com/vbenjs/vue-vben-admin) - 现代化的 Vue 后台管理模板
## 🌐 生态伙伴 ## 💎 Sponsors
- [PPIO 派欧云](https://ppinfra.com/user/register?invited_by=P8QTUY&utm_source=github_ruoyi-ai) - 提供高性价比的 GPU **Thanks to the following sponsors for supporting this project:**
算力和模型 API 服务
- [优云智算](https://www.compshare.cn/?ytag=GPU_YY-gh_ruoyi) - 万卡RTX40系GPU+海内外主流模型API服务秒级响应按量计费新客免费用。
## 💬 社区交流 <a href="https://www.atlascloud.ai?ref=89F97E">
<img src="docs/image/sponsor/atlascloud_banner.png" alt="Atlas Cloud" width="160" height="80">
</a>
[Visit Atlas Cloud](https://www.atlascloud.ai?ref=89F97E&utm_source=github&utm_campaign=ruoyi-drama) · [Coding Plan Promotion](https://www.atlascloud.ai/console/coding-plan)
A full-modal AI inference platform that gives developers a unified AI API, supporting video generation, image generation, and LLMs. Connect once to access **300+ curated models**.
<a href="https://www.volcengine.com/activity/codingplan?utm_campaign=hw&utm_content=hw&utm_medium=devrel_tool_web&utm_source=OWO&utm_term=ageerle-ruoyi-ai">
<img src="docs/image/sponsor/huoshan.png" alt="Volcengine CodingPlan" width="160" height="80">
</a>
[Sign up to claim 25 million tokens — go now](https://www.volcengine.com/activity/ai618?utm_campaign=hw&utm_content=hw&utm_medium=devrel_tool_web&utm_source=OWO&utm_term=ageerle-ruoyi-ai)
Enjoy ByteDance's in-house Doubao models plus full-power open-source SOTA models, covering text, VLM, and image generation — all modalities in one stop: Seed-2.1, Seedream-5.0, GLM-5.2, DeepSeek, and more. Not just for coding — it can also tackle complex long-horizon Agent tasks!
## 💬 Community Chat
<div align="center"> <div align="center">
<table> <table>
<tr> <tr>
<td align="center"> <td align="center">
<img src="docs/image/wx.png" alt="微信二维码" width="200" height="200"><br> <img src="docs/image/wx.png" alt="WeChat QR Code" width="200" height="200"><br>
<strong>扫码添加作者微信</strong><br> <strong>Scan to add author on WeChat</strong><br>
<em>邀请进群学习</em> <em>Join group for learning</em>
</td> </td>
<td align="center"> <td align="center">
<img src="docs/image/qq.png" alt="QQ群二维码" width="200" height="200"><br> <img src="docs/image/wx06.png" alt="WeChat QR Code" width="200" height="200"><br>
<strong>QQ技术交流群</strong><br> <strong>WeChat Tech Exchange Group</strong><br>
<em>技术讨论</em> <em>Technical discussion</em>
</td>
<td align="center">
<img src="docs/image/qq.png" alt="QQ Group QR Code" width="200" height="200"><br>
<strong>QQ Tech Exchange Group</strong><br>
<em>Technical discussion</em>
</td> </td>
</tr> </tr>
@@ -245,11 +250,12 @@ docker-compose -f docker-compose-all.yaml restart [服务名]
</div> </div>
--- ---
<div align="center"> <div align="center">
**[点个Star支持一下](https://github.com/ageerle/ruoyi-ai)** • **[ Fork 开始贡献](https://github.com/ageerle/ruoyi-ai/fork)** • **[📚 English](README_EN.md)** • **[📖 查看完整文档](https://doc.pandarobot.chat)** **[⭐ Star to Support](https://github.com/ageerle/ruoyi-ai)** • **[Fork to Contribute](https://github.com/ageerle/ruoyi-ai/fork)** • **[📚 中文](README_ZH.md)** • **[📖 Complete Documentation](https://doc.ruoyiai.chat/)**
*用 ❤️ 打造,由 RuoYi AI 开源社区维护* *Built with ❤️, maintained by the RuoYi AI open-source community*
</div> </div>

View File

@@ -1,266 +0,0 @@
# RuoYi AI
<div align="center">
[![Contributors][contributors-shield]][contributors-url]
[![Forks][forks-shield]][forks-url]
[![Stargazers][stars-shield]][stars-url]
[![Issues][issues-shield]][issues-url]
[![MIT License][license-shield]][license-url]
<p align="center">
<a href="https://trendshift.io/repositories/13209">
<img src="https://trendshift.io/api/badge/repositories/13209" alt="GitHub Trending">
</a>
</p>
<img src="docs/image/logo.png" alt="RuoYi AI Logo" width="120" height="120">
### Enterprise-Grade AI Assistant Platform
*An out-of-the-box full-stack AI platform supporting multi-agent collaboration, Supervisor mode orchestration, and multiple decision models, with advanced RAG technology and visual workflow orchestration capabilities*
**[中文](README.md)** | **[📖 Documentation](https://doc.pandarobot.chat)** |
**[🚀 Live Demo](https://web.pandarobot.chat)** | **[🐛 Report Issues](https://github.com/ageerle/ruoyi-ai/issues)** | **[💡 Feature Requests](https://github.com/ageerle/ruoyi-ai/issues)**
</div>
## ✨ Core Features
| Module | Current Capabilities |
|:---:|---|
| **Model Management** | Multi-model integration (OpenAI/DeepSeek/Tongyi/Zhipu/MiniMax), multi-modal understanding, Coze/DIFY/FastGPT platform integration |
| **Knowledge Base** | Local RAG + Vector DB (Milvus/Weaviate/Qdrant) + Document parsing |
| **Tool Management** | MCP protocol integration, Skills capability + Extensible tool ecosystem |
| **Workflow Orchestration** | Visual workflow designer, drag-and-drop node orchestration, SSE streaming execution, currently supports model calls, email sending, manual review nodes |
| **Multi-Agent** | Agent framework based on Langchain4j, Supervisor mode orchestration, supports multiple decision models |
## 🚀 Quick Start
### Live Demo
| Platform | URL | Account |
|:------:|---|---|
| User Frontend | [web.pandarobot.chat](https://web.pandarobot.chat) | admin / admin123 |
| Admin Panel | [admin.pandarobot.chat](https://admin.pandarobot.chat) | admin / admin123 |
### Project Repositories
| Module | GitHub Repository | Gitee Repository | GitCode Repository |
|----------|-------------------------------------------------------|------------------------------------------------------|--------------------------------------------------------|
| 🔧 Backend | [ruoyi-ai](https://github.com/ageerle/ruoyi-ai) | [ruoyi-ai](https://gitee.com/ageerle/ruoyi-ai) | [ruoyi-ai](https://gitcode.com/ageerle/ruoyi-ai) |
| 🎨 User Frontend | [ruoyi-web](https://github.com/ageerle/ruoyi-web) | [ruoyi-web](https://gitee.com/ageerle/ruoyi-web) | [ruoyi-web](https://gitcode.com/ageerle/ruoyi-web) |
| 🛠️ Admin Panel | [ruoyi-admin](https://github.com/ageerle/ruoyi-admin) | [ruoyi-admin](https://gitee.com/ageerle/ruoyi-admin) | [ruoyi-admin](https://gitcode.com/ageerle/ruoyi-admin) |
### Partner Projects
| Project Name | GitHub Repository | Gitee Repository |
|----------------|-------------------------------------------------------|------------------------------------------------------|
| element-plus-x | [element-plus-x](https://github.com/element-plus-x/Element-Plus-X) | [element-plus-x](https://gitee.com/he-jiayue/element-plus-x) |
## 🛠️ Technical Architecture
### Core Framework
- **Backend**: Spring Boot 3.5.8 + Langchain4j
- **Data Storage**: MySQL 8.0 + Redis + Vector Databases (Milvus/Weaviate/Qdrant)
- **Frontend**: Vue 3 + Vben Admin + element-plus-x
- **Security**: Sa-Token + JWT dual-layer security
- **Document Processing**: PDF, Word, Excel parsing, intelligent image analysis
- **Real-time Communication**: WebSocket real-time communication, SSE streaming response
- **System Monitoring**: Comprehensive logging system, performance monitoring, service health checks
## 🐳 Docker Deployment
This project provides two Docker deployment methods:
### Method 1: One-click Start All Services (Recommended)
Use `docker-compose-all.yaml` to start all services at once (including backend, admin panel, user frontend, and dependencies):
```bash
# Clone the repository
git clone https://github.com/ageerle/ruoyi-ai.git
cd ruoyi-ai
# Start all services (pull pre-built images from registry)
docker-compose -f docker-compose-all.yaml up -d
# Check service status
docker-compose -f docker-compose-all.yaml ps
# Access services
# Admin Panel: http://localhost:25666 (admin / admin123)
# User Frontend: http://localhost:25137
# Backend API: http://localhost:26039
```
### Method 2: Step-by-step Deployment (Source Build)
If you need to build backend services from source, follow these steps:
#### Step 1: Deploy Backend Service
```bash
# Enter backend project directory
cd ruoyi-ai
# Start backend service (build from source)
docker-compose up -d --build
# Wait for backend service to start
docker-compose logs -f backend
```
#### Step 2: Deploy Admin Panel
```bash
# Enter admin panel project directory
cd ruoyi-admin
# Build and start admin panel
docker-compose up -d --build
# Access admin panel
# URL: http://localhost:5666
```
#### Step 3: Deploy User Frontend (Optional)
```bash
# Enter user frontend project directory
cd ruoyi-web
# Build and start user frontend
docker-compose up -d --build
# Access user frontend
# URL: http://localhost:5137
```
### Service Ports
| Service | One-click Port | Step-by-step Port | Description |
|------|-------------|-------------|------|
| Admin Panel | 25666 | 5666 | Admin backend access |
| User Frontend | 25137 | 5137 | User frontend access |
| Backend Service | 26039 | 6039 | Backend API service |
| MySQL | 23306 | 23306 | Database service |
| Redis | 26379 | 6379 | Cache service |
| Weaviate | 28080 | 28080 | Vector database |
| MinIO API | 29000 | 9000 | Object storage API |
| MinIO Console | 29090 | 9090 | Object storage console |
### Image Registry
All images are hosted on Alibaba Cloud Container Registry:
```
crpi-31mraxd99y2gqdgr.cn-beijing.personal.cr.aliyuncs.com/ruoyi_ai
```
Available images:
- `mysql:v3` - MySQL database (includes initialization SQL)
- `redis:6.2` - Redis cache
- `weaviate:1.30.0` - Vector database
- `minio:latest` - Object storage
- `ruoyi-ai-backend:latest` - Backend service
- `ruoyi-ai-admin:latest` - Admin frontend
- `ruoyi-ai-web:latest` - User frontend
### Common Commands
```bash
# Stop all services
docker-compose -f docker-compose-all.yaml down
# View service logs
docker-compose -f docker-compose-all.yaml logs -f [service-name]
# Restart a service
docker-compose -f docker-compose-all.yaml restart [service-name]
```
## 📚 Documentation
Want to learn more about installation, deployment, configuration, and secondary development?
**👉 [Complete Documentation](https://doc.pandarobot.chat)**
## 🤝 Contributing
We warmly welcome community contributions! Whether you are a seasoned developer or just getting started, you can contribute to the project 💪
### How to Contribute
1. **Fork** the project to your account
2. **Create a branch** (`git checkout -b feature/new-feature-name`)
3. **Commit your changes** (`git commit -m 'Add new feature'`)
4. **Push to the branch** (`git push origin feature/new-feature-name`)
5. **Create a Pull Request**
> 💡 **Tip**: We recommend submitting PRs to GitHub, we will automatically sync to other code hosting platforms
## 📄 License
This project is licensed under the **MIT License**. See the [LICENSE](LICENSE) file for details.
## 🙏 Acknowledgments
Thanks to the following excellent open-source projects for their support:
- [Spring AI Alibaba Copilot](https://github.com/spring-ai-alibaba/copilot) - Intelligent coding assistant based on spring-ai-alibaba
- [Langchain4j](https://github.com/langchain4j/langchain4j) - Powerful Java LLM development framework
- [RuoYi-Vue-Plus](https://gitee.com/dromara/RuoYi-Vue-Plus) - Mature enterprise-level rapid development framework
- [Vben Admin](https://github.com/vbenjs/vue-vben-admin) - Modern Vue admin template
## 🌐 Ecosystem Partners
- [PPIO Cloud](https://ppinfra.com/user/register?invited_by=P8QTUY&utm_source=github_ruoyi-ai) - Provides cost-effective GPU computing and model API services
- [Youyun Intelligent Computing](https://www.compshare.cn/?ytag=GPU_YY-gh_ruoyi) - Thousands of RTX40 series GPUs + mainstream models API services, second-level response, pay-per-use, free for new customers.
## 💬 Community Chat
<div align="center">
**[📱 Join Telegram Group](
https://t.me/+LqooQAc5HxRmYmE1)**
</div>
---
<div align="center">
**[⭐ Star to Support](https://github.com/ageerle/ruoyi-ai)** • **[Fork to Contribute](https://github.com/ageerle/ruoyi-ai/fork)** • **[📚 中文](README.md)** • **[📖 Complete Documentation](https://doc.pandarobot.chat)**
*Built with ❤️, maintained by the RuoYi AI open-source community*
</div>
<!-- Badge Links -->
[contributors-shield]: https://img.shields.io/github/contributors/ageerle/ruoyi-ai.svg?style=flat-square
[contributors-url]: https://github.com/ageerle/ruoyi-ai/graphs/contributors
[forks-shield]: https://img.shields.io/github/forks/ageerle/ruoyi-ai.svg?style=flat-square
[forks-url]: https://github.com/ageerle/ruoyi-ai/network/members
[stars-shield]: https://img.shields.io/github/stars/ageerle/ruoyi-ai.svg?style=flat-square
[stars-url]: https://github.com/ageerle/ruoyi-ai/stargazers
[issues-shield]: https://img.shields.io/github/issues/ageerle/ruoyi-ai.svg?style=flat-square
[issues-url]: https://github.com/ageerle/ruoyi-ai/issues
[license-shield]: https://img.shields.io/github/license/ageerle/ruoyi-ai.svg?style=flat-square
[license-url]: https://github.com/ageerle/ruoyi-ai/blob/main/LICENSE

282
README_ZH.md Normal file
View File

@@ -0,0 +1,282 @@
# RuoYi AI
<div align="center">
[![Contributors][contributors-shield]][contributors-url] [![Forks][forks-shield]][forks-url] [![Stargazers][stars-shield]][stars-url] [![Issues][issues-shield]][issues-url] [![MIT License][license-shield]][license-url]
<p align="center">
<a href="https://trendshift.io/repositories/13209">
<img src="https://trendshift.io/api/badge/repositories/13209" alt="GitHub Trending">
</a>
</p>
<img src="docs/image/logo.png" alt="RuoYi AI Logo" width="120" height="120">
### 企业级AI助手平台
*开箱即用的全栈AI平台支持多智能体协同、Supervisor模式编排、多种决策模式、RAG技术和流程编排能力*
**[English](README.md)** | **[📖 使用文档](https://doc.ruoyiai.chat/)** |
**[🚀 在线体验](https://web.ruoyiai.chat/)** | **[🐛 问题反馈](https://github.com/ageerle/ruoyi-ai/issues)** | **[💡 功能建议](https://github.com/ageerle/ruoyi-ai/issues)**
</div>
## ✨ 核心亮点
| 模块 | 现有能力
|:---------:|---
| **模型管理** | 多模型接入(DeepSeek/智谱/MIMO/百炼/OpenAI)、多模态理解、Coze/DIFY/FastGPT/RAGFlow平台集成
| **知识管理** | 本地RAG + 向量库(Milvus/Weaviate/Qdrant) + 文档解析
| **工具管理** | Mcp协议集成、Skills能力 + 可扩展工具生态
| **流程编排** | 可视化工作流设计器、节点拖拽编排、SSE流式执行,目前已经支持模型调用,邮件发送,人工审核等节点
| **智能体管理** | 基于Langchain4j的Agent框架、Supervisor模式编排,支持多种决策模型,可以灵活搭配工具,skills
### 项目源码
| 项目模块 | GitHub 仓库 | Gitee 仓库 | GitCode 仓库 |
|----------|-------------------------------------------------------|------------------------------------------------------|--------------------------------------------------------|
| 🔧 后端服务 | [ruoyi-ai](https://github.com/ageerle/ruoyi-ai) | [ruoyi-ai](https://gitee.com/ageerle/ruoyi-ai) | [ruoyi-ai](https://gitcode.com/ageerle/ruoyi-ai) |
| 🎨 用户前端 | [ruoyi-web](https://github.com/ageerle/ruoyi-web) | [ruoyi-web](https://gitee.com/ageerle/ruoyi-web) | [ruoyi-web](https://gitcode.com/ageerle/ruoyi-web) |
| 🛠️ 管理后台 | [ruoyi-admin](https://github.com/ageerle/ruoyi-admin) | [ruoyi-admin](https://gitee.com/ageerle/ruoyi-admin) | [ruoyi-admin](https://gitcode.com/ageerle/ruoyi-admin) |
| 🎬 短剧平台 | [ruoyi-drama](https://github.com/ageerle/ruoyi-drama) | [ruoyi-drama](https://gitee.com/ageerle/ruoyi-drama) | [ruoyi-drama](https://gitcode.com/ageerle/ruoyi-drama) |
| 🤖 编程助手 | [ruoyi-copilot](https://github.com/ageerle/ruoyi-copilot) | [ruoyi-copilot](https://gitee.com/ageerle/ruoyi-copilot) | [ruoyi-copilot](https://gitcode.com/ageerle/ruoyi-copilot) |
| 📱 小程序端 | [ruoyi-uniapp](https://github.com/ageerle/ruoyi-uniapp) | [ruoyi-uniapp](https://gitee.com/ageerle/ruoyi-uniapp) | [ruoyi-uniapp](https://gitcode.com/ageerle/ruoyi-uniapp) |
### 合作项目
| 项目名称 | GitHub 仓库 | Gitee 仓库
|----------------|-------------------------------------------------------|------------------------------------------------------|
| element-plus-x | [element-plus-x](https://github.com/element-plus-x/Element-Plus-X) | [element-plus-x](https://gitee.com/he-jiayue/element-plus-x) |
## 🛠️ 技术架构
### 核心框架
- **后端架构**Spring Boot 3.5.8 + Langchain4j
- **数据存储**MySQL 8.0 + Redis + 向量数据库Milvus/Weaviate/Qdrant
- **前端技术**Vue 3 + Vben Admin + element-plus-x
- **安全认证**Sa-Token + JWT 双重保障
- **文档处理**PDF、Word、Excel 解析,图像智能分析
- **实时通信**WebSocket 实时通信SSE 流式响应
- **系统监控**:完善的日志体系、性能监控、服务健康检查
## 🐳 Docker 部署
本项目提供两种 Docker 部署方式:
### 方式一:一键启动所有服务(推荐)
使用 `docker-compose-all.yaml` 可以一键启动所有服务(包括后端、管理端、用户端及依赖服务):
```bash
# 克隆仓库
git clone https://github.com/ageerle/ruoyi-ai.git
cd ruoyi-ai
# 启动所有服务(从 GHCR 拉取预构建镜像)
docker compose -f docs/docker/ruoyi-ai/docker-compose-all.yaml up -d
# 查看服务状态
docker compose -f docs/docker/ruoyi-ai/docker-compose-all.yaml ps
# 访问服务
# 管理端: http://localhost:25666 (admin / admin123)
# 用户端: http://localhost:25137
# 后端API: http://localhost:26039
```
### 方式二:分步部署(源码编译)
如果您需要从源码构建后端服务,请按照以下步骤操作:
#### 第一步:部署后端服务
```bash
# 进入后端项目目录
cd ruoyi-ai
# 启动后端服务(源码编译构建)
docker-compose up -d --build
# 等待后端服务启动完成
docker-compose logs -f backend
```
#### 第二步:部署管理端
```bash
# 进入管理端项目目录
cd ruoyi-admin
# 构建并启动管理端
docker-compose up -d --build
# 访问管理端
# 地址: http://localhost:5666
```
#### 第三步:部署用户端(可选)
```bash
# 进入用户端项目目录
cd ruoyi-web
# 构建并启动用户端
docker-compose up -d --build
# 访问用户端
# 地址: http://localhost:5137
```
### 服务端口说明
| 服务 | 一键启动端口 | 分步部署端口 | 说明 |
|------|-------------|-------------|------|
| 管理端 | 25666 | 5666 | 管理后台访问地址 |
| 用户端 | 25137 | 5137 | 用户前端访问地址 |
| 后端服务 | 26039 | 6039 | 后端 API 服务 |
| MySQL | 23306 | 23306 | 数据库服务 |
| Redis | 26379 | 6379 | 缓存服务 |
| Weaviate | 28080 | 28080 | 向量数据库 |
| MinIO API | 29000 | 9000 | 对象存储 API |
| MinIO Console | 29090 | 9090 | 对象存储控制台 |
### 镜像仓库
每次推送类似 `v3.1.0` 的版本标签后GitHub Actions 会自动构建并发布应用镜像到 GitHub Container RegistryGHCR
```
ghcr.io/ageerle/ruoyi-ai-backend:v3.1.0
ghcr.io/ageerle/ruoyi-ai-mysql:v3.1.0
ghcr.io/ageerle/ruoyi-ai-admin:v3.1.0
ghcr.io/ageerle/ruoyi-ai-web:v3.1.0
```
Compose 默认使用 `latest`。如需固定版本,可在 `docs/docker/ruoyi-ai/.env` 中设置 `RUIYI_VERSION=v3.1.0`
首次工作流运行完成后,请在 GitHub 的 Packages 设置中将这四个 GHCR 镜像设为 `Public`,用户服务器才能免登录拉取。
管理端 `ageerle/ruoyi-admin` 和用户端 `ageerle/ruoyi-web` 也必须存在同名版本标签;发布工作流会使用后端发布标签检出这两个仓库后再构建镜像。
### 常用命令
```bash
# 停止所有服务
docker compose -f docs/docker/ruoyi-ai/docker-compose-all.yaml down
# 查看服务日志
docker compose -f docs/docker/ruoyi-ai/docker-compose-all.yaml logs -f [服务名]
# 重启某个服务
docker compose -f docs/docker/ruoyi-ai/docker-compose-all.yaml restart [服务名]
```
## 📚 使用文档
想要深入了解安装部署、功能配置和二次开发?
**👉 [完整使用文档](https://doc.ruoyiai.chat/)**
## 🤝 参与贡献
我们热烈欢迎社区贡献!无论您是资深开发者还是初学者,都可以为项目贡献力量 💪
### 贡献方式
1. **Fork** 项目到您的账户
2. **创建分支** (`git checkout -b feature/新功能名称`)
3. **提交代码** (`git commit -m '添加某某功能'`)
4. **推送分支** (`git push origin feature/新功能名称`)
5. **发起 Pull Request**
> 💡 **小贴士**:建议将 PR 提交到 GitHub我们会自动同步到其他代码托管平台
## 📄 开源协议
本项目采用 **MIT 开源协议**,详情请查看 [LICENSE](LICENSE) 文件。
## 🙏 特别鸣谢
感谢以下优秀的开源项目为本项目提供支持:
- [Langchain4j](https://github.com/langchain4j/langchain4j) - 强大的 Java LLM 开发框架
- [RuoYi-Vue-Plus](https://gitee.com/dromara/RuoYi-Vue-Plus) - 成熟的企业级快速开发框架
- [Vben Admin](https://github.com/vbenjs/vue-vben-admin) - 现代化的 Vue 后台管理模板
## 💎 赞助商
**感谢以下赞助商对本项目的支持:**
<a href="https://www.atlascloud.ai?ref=89F97E">
<img src="docs/image/sponsor/atlascloud_banner.png" alt="Atlas Cloud" width="160" height="80">
</a>
[访问Atlas Cloud官网](https://www.atlascloud.ai?ref=89F97E&utm_source=github&utm_campaign=ruoyi-drama) · [编程计划优惠](https://www.atlascloud.ai/console/coding-plan)
全模态 AI 推理平台,为开发者提供统一的 AI API支持视频生成、图像生成和大语言模型。一次接入即可访问 **300+ 精选模型**
<a href="https://www.volcengine.com/activity/codingplan?utm_campaign=hw&utm_content=hw&utm_medium=devrel_tool_web&utm_source=OWO&utm_term=ageerle-ruoyi-ai">
<img src="docs/image/sponsor/huoshan.png" alt="火山引擎 CodingPlan" width="160" height="80">
</a>
[注册即领2500万Tokens立即前往](https://www.volcengine.com/activity/ai618?utm_campaign=hw&utm_content=hw&utm_medium=devrel_tool_web&utm_source=OWO&utm_term=ageerle-ruoyi-ai)
享字节自研豆包模型+满血版开源 SOTA模型覆盖文本、VLM、图像生成全模态一站配齐Seed-2.1、Seedream-5.0、GLM-5.2、DeepSeek等。不止编程、更能解决 Agent 复杂长程任务!
## 💬 社区交流
<div align="center">
<table>
<tr>
<td align="center">
<img src="docs/image/wx.png" alt="微信二维码" width="200" height="200"><br>
<strong>扫码添加作者微信</strong><br>
<em>邀请进群学习</em>
</td>
<td align="center">
<img src="docs/image/wx06.png" alt="微信二维码" width="200" height="200"><br>
<strong>微信技术交流群</strong><br>
<em>技术讨论</em>
</td>
<td align="center">
<img src="docs/image/qq.png" alt="QQ群二维码" width="200" height="200"><br>
<strong>QQ技术交流群</strong><br>
<em>技术讨论</em>
</td>
</tr>
</table>
</div>
---
<div align="center">
**[⭐ 点个Star支持一下](https://github.com/ageerle/ruoyi-ai)** • **[ Fork 开始贡献](https://github.com/ageerle/ruoyi-ai/fork)** • **[📚 English](README.md)** • **[📖 查看完整文档](https://doc.ruoyiai.chat/)**
*用 ❤️ 打造,由 RuoYi AI 开源社区维护*
</div>
<!-- Badge Links -->
[contributors-shield]: https://img.shields.io/github/contributors/ageerle/ruoyi-ai.svg?style=flat-square
[contributors-url]: https://github.com/ageerle/ruoyi-ai/graphs/contributors
[forks-shield]: https://img.shields.io/github/forks/ageerle/ruoyi-ai.svg?style=flat-square
[forks-url]: https://github.com/ageerle/ruoyi-ai/network/members
[stars-shield]: https://img.shields.io/github/stars/ageerle/ruoyi-ai.svg?style=flat-square
[stars-url]: https://github.com/ageerle/ruoyi-ai/stargazers
[issues-shield]: https://img.shields.io/github/issues/ageerle/ruoyi-ai.svg?style=flat-square
[issues-url]: https://github.com/ageerle/ruoyi-ai/issues
[license-shield]: https://img.shields.io/github/license/ageerle/ruoyi-ai.svg?style=flat-square
[license-url]: https://github.com/ageerle/ruoyi-ai/blob/main/LICENSE

View File

@@ -1,8 +1,6 @@
version: '3.5'
services: services:
etcd: etcd:
container_name: milvus-etcd container_name: ruoyi-rag-milvus-etcd
image: quay.io/coreos/etcd:v3.5.18 image: quay.io/coreos/etcd:v3.5.18
environment: environment:
- ETCD_AUTO_COMPACTION_MODE=revision - ETCD_AUTO_COMPACTION_MODE=revision
@@ -19,14 +17,11 @@ services:
retries: 3 retries: 3
minio: minio:
container_name: milvus-minio container_name: ruoyi-rag-milvus-minio
image: minio/minio:RELEASE.2023-03-20T20-16-18Z image: minio/minio:RELEASE.2023-03-20T20-16-18Z
environment: environment:
MINIO_ACCESS_KEY: minioadmin MINIO_ACCESS_KEY: minioadmin
MINIO_SECRET_KEY: minioadmin MINIO_SECRET_KEY: minioadmin
ports:
- "9001:9001"
- "9000:9000"
volumes: volumes:
- ${DOCKER_VOLUME_DIRECTORY:-.}/volumes/minio:/minio_data - ${DOCKER_VOLUME_DIRECTORY:-.}/volumes/minio:/minio_data
command: minio server /minio_data --console-address ":9001" command: minio server /minio_data --console-address ":9001"
@@ -37,7 +32,7 @@ services:
retries: 3 retries: 3
standalone: standalone:
container_name: milvus-standalone container_name: ruoyi-rag-milvus
image: milvusdb/milvus:v2.5.7 image: milvusdb/milvus:v2.5.7
command: ["milvus", "run", "standalone"] command: ["milvus", "run", "standalone"]
security_opt: security_opt:
@@ -61,7 +56,7 @@ services:
- "minio" - "minio"
attu: attu:
container_name: attu container_name: ruoyi-rag-attu
image: zilliz/attu:v2.5.7 image: zilliz/attu:v2.5.7
environment: environment:
MILVUS_URL: milvus-standalone:19530 MILVUS_URL: milvus-standalone:19530
@@ -72,4 +67,4 @@ services:
networks: networks:
default: default:
name: milvus name: ruoyi-rag-milvus

View File

@@ -1,12 +1,20 @@
--- ---
services: services:
qdrant: qdrant:
image: qdrant/qdrant:latest container_name: ruoyi-rag-qdrant
image: qdrant/qdrant:v1.17.0
ports: ports:
- 6333:6333 - 6333:6333
- 6334:6334 - 6334:6334
volumes: volumes:
- qdrant_data:/qdrant/storage - qdrant_data:/qdrant/storage
healthcheck:
test: ["CMD-SHELL", "bash -c 'exec 3<>/dev/tcp/127.0.0.1/6333 && printf \"GET /healthz HTTP/1.1\\r\\nHost: localhost\\r\\nConnection: close\\r\\n\\r\\n\" >&3 && grep -q \"200 OK\" <&3'"]
interval: 10s
timeout: 5s
retries: 12
start_period: 10s
restart: unless-stopped
volumes: volumes:
qdrant_data: qdrant_data:
... ...

View File

@@ -0,0 +1,6 @@
# GitHub Container Registry namespace owner.
# For the upstream project this is ageerle; change it when using a fork.
IMAGE_OWNER=ageerle
# Use latest for convenience, or pin a release such as v3.1.0.
RUIYI_VERSION=latest

View File

@@ -20,6 +20,22 @@ RUN mvn clean package -Pprod -DskipTests
# 最终运行镜像 # 最终运行镜像
FROM eclipse-temurin:17-jre-alpine FROM eclipse-temurin:17-jre-alpine
RUN set -eux; \
apk add --no-cache ffmpeg; \
for filter in scale pad fps setsar format tpad trim settb setpts xfade \
aresample aformat apad atrim asetpts anullsrc concat acrossfade; do \
ffmpeg -hide_banner -filters 2>/dev/null | grep -Eq "[[:space:]]${filter}[[:space:]]"; \
done; \
ffmpeg -hide_banner -h filter=xfade 2>&1 | grep -q dissolve; \
ffmpeg -hide_banner -h filter=xfade 2>&1 | grep -q fadeblack; \
ffmpeg -hide_banner -h filter=xfade 2>&1 | grep -q slideleft; \
ffmpeg -hide_banner -encoders 2>/dev/null | grep -Eq '[[:space:]]libx264[[:space:]]'; \
ffmpeg -hide_banner -encoders 2>/dev/null | grep -Eq '[[:space:]]aac[[:space:]]'; \
ffprobe -hide_banner -version >/dev/null
ENV FFMPEG_PATH=/usr/bin/ffmpeg \
FFPROBE_PATH=/usr/bin/ffprobe
# 设置工作目录 # 设置工作目录
WORKDIR /app WORKDIR /app
@@ -27,10 +43,10 @@ WORKDIR /app
COPY --from=builder /build/ruoyi-admin/target/ruoyi-admin.jar ./ruoyi-admin.jar COPY --from=builder /build/ruoyi-admin/target/ruoyi-admin.jar ./ruoyi-admin.jar
# 创建日志目录 # 创建日志目录
RUN mkdir -p /ruoyi/server/logs RUN mkdir -p /ruoyi/server/logs /ruoyi/server/temp
# 暴露端口 # 暴露端口
EXPOSE 6039 EXPOSE 6039
# 启动命令 # 启动命令
ENTRYPOINT ["java", "-jar", "ruoyi-admin.jar", "--spring.profiles.active=prod"] ENTRYPOINT ["java", "-Djava.io.tmpdir=/ruoyi/server/temp", "-jar", "ruoyi-admin.jar", "--spring.profiles.active=prod"]

View File

@@ -1,16 +1,14 @@
# 基于官方MySQL 8.0镜像构建自定义镜像 # 基于官方MySQL 8.0镜像构建自定义镜像
# 构建命令: docker build -t registry.cn-hangzhou.aliyuncs.com/ruoyi-ai/mysql:v3 -f Dockerfile.mysql . # 构建命令: docker build -t registry.cn-hangzhou.aliyuncs.com/ruoyi-ai/mysql:v3 -f Dockerfile.mysql .
FROM mysql:8.0.33 FROM mysql:8.0
# 设置时区 # 设置时区
ENV TZ=Asia/Shanghai ENV TZ=Asia/Shanghai
# 复制初始化脚本和SQL文件到镜像中 # MySQL 官方入口会按文件名顺序执行初始化目录中的 SQL。
COPY docs/script/docker/mysql/init/init-db.sh /docker-entrypoint-initdb.d/init-db.sh # ruoyi-ai.sql 会导入 MYSQL_DATABASEsnail_job_mysql.sql 会自行创建并切换数据库。
COPY docs/script/sql/ruoyi-ai-v3_mysql8.sql /docker-entrypoint-initdb.d/ruoyi-ai-v3_mysql8.sql COPY docs/script/sql/ruoyi-ai.sql /docker-entrypoint-initdb.d/01-ruoyi-ai.sql
COPY docs/script/sql/snail_job_mysql.sql /docker-entrypoint-initdb.d/02-snail-job.sql
# 设置脚本可执行权限
RUN chmod +x /docker-entrypoint-initdb.d/init-db.sh
# MySQL启动参数 # MySQL启动参数
CMD ["--default-authentication-plugin=mysql_native_password", \ CMD ["--default-authentication-plugin=mysql_native_password", \

View File

@@ -10,15 +10,13 @@
# - RuoYi-Admin (管理端前端) # - RuoYi-Admin (管理端前端)
# - RuoYi-Web (用户端前端) # - RuoYi-Web (用户端前端)
# #
# 镜像仓库地址: crpi-31mraxd99y2gqdgr.cn-beijing.personal.cr.aliyuncs.com/ruoyi_ai # 镜像仓库地址: ghcr.io/ageerle
version: '3.8'
services: services:
# ==================== MySQL 数据库 ==================== # ==================== MySQL 数据库 ====================
mysql: mysql:
# 阿里云镜像地址包含初始化SQL # GHCR 镜像包含初始化SQL
image: crpi-31mraxd99y2gqdgr.cn-beijing.personal.cr.aliyuncs.com/ruoyi_ai/mysql:v3 image: ghcr.io/${IMAGE_OWNER:-ageerle}/ruoyi-ai-mysql:${RUIYI_VERSION:-latest}
container_name: ruoyi-ai-mysql container_name: ruoyi-ai-mysql
restart: always restart: always
ports: ports:
@@ -30,7 +28,10 @@ services:
volumes: volumes:
- mysql-data:/var/lib/mysql - mysql-data:/var/lib/mysql
healthcheck: healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-proot"] # Force TCP: during first-time initialization MySQL exposes a temporary
# socket-only server. A socket ping would mark the service healthy before
# the real network listener (used by the backend) is ready.
test: ["CMD", "mysqladmin", "ping", "--protocol=tcp", "-h", "127.0.0.1", "-u", "root", "-proot"]
interval: 15s interval: 15s
timeout: 10s timeout: 10s
retries: 10 retries: 10
@@ -40,7 +41,7 @@ services:
# ==================== Redis 缓存 ==================== # ==================== Redis 缓存 ====================
redis: redis:
image: crpi-31mraxd99y2gqdgr.cn-beijing.personal.cr.aliyuncs.com/ruoyi_ai/redis:6.2 image: redis:6.2
container_name: ruoyi-ai-redis container_name: ruoyi-ai-redis
restart: always restart: always
ports: ports:
@@ -58,7 +59,7 @@ services:
# ==================== Weaviate 向量数据库 ==================== # ==================== Weaviate 向量数据库 ====================
weaviate: weaviate:
image: crpi-31mraxd99y2gqdgr.cn-beijing.personal.cr.aliyuncs.com/ruoyi_ai/weaviate:1.30.0 image: semitechnologies/weaviate:1.30.0
container_name: ruoyi-ai-weaviate container_name: ruoyi-ai-weaviate
restart: always restart: always
ports: ports:
@@ -77,7 +78,7 @@ services:
# ==================== MinIO 对象存储 ==================== # ==================== MinIO 对象存储 ====================
minio: minio:
image: crpi-31mraxd99y2gqdgr.cn-beijing.personal.cr.aliyuncs.com/ruoyi_ai/minio:latest image: minio/minio:latest
container_name: ruoyi-ai-minio container_name: ruoyi-ai-minio
restart: always restart: always
ports: ports:
@@ -94,7 +95,7 @@ services:
# ==================== RuoYi-AI 后端服务 ==================== # ==================== RuoYi-AI 后端服务 ====================
backend: backend:
image: crpi-31mraxd99y2gqdgr.cn-beijing.personal.cr.aliyuncs.com/ruoyi_ai/ruoyi-ai-backend:latest image: ghcr.io/${IMAGE_OWNER:-ageerle}/ruoyi-ai-backend:${RUIYI_VERSION:-latest}
container_name: ruoyi-ai-backend container_name: ruoyi-ai-backend
restart: always restart: always
ports: ports:
@@ -128,7 +129,7 @@ services:
# ==================== RuoYi-AI 管理端前端 ==================== # ==================== RuoYi-AI 管理端前端 ====================
admin-frontend: admin-frontend:
image: crpi-31mraxd99y2gqdgr.cn-beijing.personal.cr.aliyuncs.com/ruoyi_ai/ruoyi-ai-admin:latest image: ghcr.io/${IMAGE_OWNER:-ageerle}/ruoyi-ai-admin:${RUIYI_VERSION:-latest}
container_name: ruoyi-ai-admin container_name: ruoyi-ai-admin
restart: always restart: always
ports: ports:
@@ -153,7 +154,7 @@ services:
# ==================== RuoYi-AI 用户端前端 ==================== # ==================== RuoYi-AI 用户端前端 ====================
web-frontend: web-frontend:
image: crpi-31mraxd99y2gqdgr.cn-beijing.personal.cr.aliyuncs.com/ruoyi_ai/ruoyi-ai-web:latest image: ghcr.io/${IMAGE_OWNER:-ageerle}/ruoyi-ai-web:${RUIYI_VERSION:-latest}
container_name: ruoyi-ai-web container_name: ruoyi-ai-web
restart: always restart: always
ports: ports:

View File

@@ -21,8 +21,8 @@ services:
MYSQL_DATABASE: ruoyi-ai-agent MYSQL_DATABASE: ruoyi-ai-agent
TZ: Asia/Shanghai TZ: Asia/Shanghai
volumes: volumes:
- ./docs/script/docker/mysql/init/init-db.sh:/docker-entrypoint-initdb.d/init-db.sh:ro - ../../script/sql/ruoyi-ai.sql:/docker-entrypoint-initdb.d/01-ruoyi-ai.sql:ro
- ./docs/script/sql/ruoyi-ai-v3_mysql8.sql:/docker-entrypoint-initdb.d/ruoyi-ai-v3_mysql8.sql:ro - ../../script/sql/snail_job_mysql.sql:/docker-entrypoint-initdb.d/02-snail-job.sql:ro
- mysql-data:/var/lib/mysql - mysql-data:/var/lib/mysql
command: command:
--default-authentication-plugin=mysql_native_password --default-authentication-plugin=mysql_native_password
@@ -32,7 +32,9 @@ services:
--lower_case_table_names=1 --lower_case_table_names=1
--skip-ssl --skip-ssl
healthcheck: healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-proot"] # Do not let the socket-only initialization server satisfy the check.
# The backend connects over TCP and must wait for that listener.
test: ["CMD", "mysqladmin", "ping", "--protocol=tcp", "-h", "127.0.0.1", "-u", "root", "-proot"]
interval: 15s interval: 15s
timeout: 10s timeout: 10s
retries: 10 retries: 10

View File

@@ -5,12 +5,12 @@ services:
- --host - --host
- 0.0.0.0 - 0.0.0.0
- --port - --port
- '6038' - '8080'
- --scheme - --scheme
- http - http
image: semitechnologies/weaviate:1.19.7 image: semitechnologies/weaviate:1.30.0
ports: ports:
- 6038:6038 - 28080:8080
- 50051:50051 - 50051:50051
volumes: volumes:
- weaviate_data:/var/lib/weaviate - weaviate_data:/var/lib/weaviate

BIN
docs/image/01.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 298 KiB

BIN
docs/image/02.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 185 KiB

BIN
docs/image/03.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 316 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

BIN
docs/image/wx06.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

View File

@@ -1,10 +0,0 @@
#!/bin/bash
# 数据库初始化脚本
# 使用 --force 参数确保即使出错也继续执行
echo "开始初始化数据库..."
# 使用 --force 参数忽略错误继续执行
mysql -uroot -proot ruoyi-ai-agent --force < /docker-entrypoint-initdb.d/ruoyi-ai-v3_mysql8.sql
echo "数据库初始化完成"

View File

@@ -0,0 +1,86 @@
[CmdletBinding()]
param(
[switch]$Force
)
$ErrorActionPreference = 'Stop'
function Find-Executable([string]$Name) {
$command = Get-Command $Name -ErrorAction SilentlyContinue
if ($command) {
return $command.Source
}
$roots = @(
(Join-Path $env:LOCALAPPDATA 'Microsoft\WinGet\Packages'),
(Join-Path $env:USERPROFILE 'scoop\apps\ffmpeg'),
'C:\ProgramData\chocolatey\bin',
'C:\ffmpeg'
)
foreach ($root in $roots) {
if (-not (Test-Path $root)) { continue }
$match = Get-ChildItem -Path $root -Filter "$Name.exe" -Recurse -ErrorAction SilentlyContinue |
Select-Object -First 1 -ExpandProperty FullName
if ($match) { return $match }
}
return $null
}
$ffmpeg = Find-Executable 'ffmpeg'
$ffprobe = Find-Executable 'ffprobe'
if ($Force -or -not $ffmpeg -or -not $ffprobe) {
$winget = Get-Command winget -ErrorAction SilentlyContinue
if (-not $winget) {
throw '未找到 winget。请先从 Microsoft Store 安装“应用安装程序”,或使用项目 Dockerfile 运行后端。'
}
Write-Host '正在通过 winget 安装 FFmpeg...' -ForegroundColor Cyan
& winget install --id Gyan.FFmpeg --exact --source winget `
--accept-package-agreements --accept-source-agreements
if ($LASTEXITCODE -ne 0) {
throw "winget 安装失败,退出码: $LASTEXITCODE"
}
$ffmpeg = Find-Executable 'ffmpeg'
$ffprobe = Find-Executable 'ffprobe'
}
if (-not $ffmpeg -or -not $ffprobe) {
throw 'FFmpeg 已安装但未能定位 ffmpeg.exe 或 ffprobe.exe。请重新打开 PowerShell 后再次运行脚本。'
}
$binDirectory = Split-Path -Parent $ffmpeg
[Environment]::SetEnvironmentVariable('FFMPEG_PATH', $ffmpeg, 'User')
[Environment]::SetEnvironmentVariable('FFPROBE_PATH', $ffprobe, 'User')
$userPath = [Environment]::GetEnvironmentVariable('Path', 'User')
$pathParts = @($userPath -split ';' | Where-Object { $_ })
if ($pathParts -notcontains $binDirectory) {
$newPath = (@($pathParts) + $binDirectory) -join ';'
[Environment]::SetEnvironmentVariable('Path', $newPath, 'User')
}
$env:FFMPEG_PATH = $ffmpeg
$env:FFPROBE_PATH = $ffprobe
if (($env:Path -split ';') -notcontains $binDirectory) {
$env:Path = "$binDirectory;$env:Path"
}
Write-Host "ffmpeg: $ffmpeg" -ForegroundColor Green
Write-Host "ffprobe: $ffprobe" -ForegroundColor Green
& $ffmpeg -hide_banner -version | Select-Object -First 1
& $ffprobe -hide_banner -version | Select-Object -First 1
$encoders = & $ffmpeg -hide_banner -encoders 2>&1 | Out-String
if ($encoders -notmatch '\blibx264\b') {
throw '当前 FFmpeg 不包含 libx264 编码器,无法满足短剧合成配置。'
}
if ($encoders -notmatch '\baac\b') {
throw '当前 FFmpeg 不包含 AAC 编码器,无法满足短剧合成配置。'
}
Write-Host ''
Write-Host '安装与配置完成。请完全重启 IntelliJ IDEA 和 ruoyi-ai 后端服务。' -ForegroundColor Yellow
Write-Host '重启后Spring 将从 FFMPEG_PATH 和 FFPROBE_PATH 读取绝对路径。'

View File

@@ -1,23 +0,0 @@
-- ----------------------------
-- Add MiniMax provider
-- ----------------------------
INSERT INTO `chat_provider` (`id`, `provider_name`, `provider_code`, `provider_icon`, `provider_desc`, `api_host`, `status`, `sort_order`, `create_dept`, `create_time`, `create_by`, `update_by`, `update_time`, `remark`, `version`, `del_flag`, `update_ip`, `tenant_id`)
VALUES (2010000000000000001, 'MiniMax', 'minimax', NULL, 'MiniMax大模型服务支持M2.7、M2.5等模型', 'https://api.minimax.io/v1', '0', 6, NULL, NOW(), '1', '1', NOW(), 'MiniMax厂商', NULL, '0', NULL, 0);
-- ----------------------------
-- Add MiniMax chat models
-- ----------------------------
INSERT INTO `chat_model` (`id`, `category`, `model_name`, `provider_code`, `model_describe`, `model_dimension`, `model_show`, `api_host`, `api_key`, `create_dept`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`, `tenant_id`)
VALUES (2010000000000000002, 'chat', 'MiniMax-M2.7', 'minimax', 'MiniMax-M2.7', NULL, 'Y', 'https://api.minimax.io/v1', '', NULL, 1, NOW(), 1, NOW(), 'MiniMax最新旗舰模型M2.7支持1M上下文窗口', 0);
INSERT INTO `chat_model` (`id`, `category`, `model_name`, `provider_code`, `model_describe`, `model_dimension`, `model_show`, `api_host`, `api_key`, `create_dept`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`, `tenant_id`)
VALUES (2010000000000000003, 'chat', 'MiniMax-M2.5', 'minimax', 'MiniMax-M2.5', NULL, 'Y', 'https://api.minimax.io/v1', '', NULL, 1, NOW(), 1, NOW(), 'MiniMax M2.5模型204K上下文窗口', 0);
INSERT INTO `chat_model` (`id`, `category`, `model_name`, `provider_code`, `model_describe`, `model_dimension`, `model_show`, `api_host`, `api_key`, `create_dept`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`, `tenant_id`)
VALUES (2010000000000000004, 'chat', 'MiniMax-M2.5-highspeed', 'minimax', 'MiniMax-M2.5-highspeed', NULL, 'Y', 'https://api.minimax.io/v1', '', NULL, 1, NOW(), 1, NOW(), 'MiniMax M2.5高速版204K上下文窗口更低延迟', 0);
-- ----------------------------
-- Add MiniMax embedding model
-- ----------------------------
INSERT INTO `chat_model` (`id`, `category`, `model_name`, `provider_code`, `model_describe`, `model_dimension`, `model_show`, `api_host`, `api_key`, `create_dept`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`, `tenant_id`)
VALUES (2010000000000000005, 'vector', 'embo-01', 'minimax', 'embo-01', 1536, 'N', 'https://api.minimax.io/v1', '', NULL, 1, NOW(), 1, NOW(), 'MiniMax embo-01嵌入模型1536维度', 0);

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,58 @@
-- RAG metadata migration (MySQL 8). Safe to execute repeatedly.
-- 注意MySQL 8 不支持 ALTER TABLE ... ADD COLUMN IF NOT EXISTS仅 MariaDB 支持),
-- 因此列的增量添加统一用 information_schema 守卫 + PREPARE 实现幂等。
SET @add_file_hash_col = IF(EXISTS(
SELECT 1 FROM information_schema.columns WHERE table_schema = DATABASE()
AND table_name = 'knowledge_attach' AND column_name = 'file_hash'),
'SELECT 1',
'ALTER TABLE `knowledge_attach` ADD COLUMN `file_hash` varchar(64) NULL DEFAULT NULL COMMENT ''文件SHA-256摘要'' AFTER `doc_id`');
PREPARE stmt FROM @add_file_hash_col; EXECUTE stmt; DEALLOCATE PREPARE stmt;
ALTER TABLE `knowledge_attach`
MODIFY COLUMN `doc_id` varchar(32) NULL DEFAULT NULL COMMENT '文档ID';
SET @add_file_hash = IF(EXISTS(
SELECT 1 FROM information_schema.statistics WHERE table_schema = DATABASE()
AND table_name = 'knowledge_attach' AND index_name = 'uk_knowledge_file_hash'),
'SELECT 1', 'ALTER TABLE `knowledge_attach` ADD UNIQUE INDEX `uk_knowledge_file_hash` (`knowledge_id`, `file_hash`)');
PREPARE stmt FROM @add_file_hash; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @add_fid_col = IF(EXISTS(
SELECT 1 FROM information_schema.columns WHERE table_schema = DATABASE()
AND table_name = 'knowledge_fragment' AND column_name = 'fid'),
'SELECT 1',
'ALTER TABLE `knowledge_fragment` ADD COLUMN `fid` varchar(32) NULL DEFAULT NULL COMMENT ''向量库片段ID'' AFTER `id`');
PREPARE stmt FROM @add_fid_col; EXECUTE stmt; DEALLOCATE PREPARE stmt;
ALTER TABLE `knowledge_fragment`
MODIFY COLUMN `doc_id` varchar(32) NULL DEFAULT NULL COMMENT '文档ID';
UPDATE `knowledge_fragment`
SET `fid` = LOWER(MD5(CONCAT('knowledge_fragment:', `id`)))
WHERE `fid` IS NULL OR `fid` = '';
SET @drop_idx_fid = IF(EXISTS(
SELECT 1 FROM information_schema.statistics WHERE table_schema = DATABASE()
AND table_name = 'knowledge_fragment' AND index_name = 'idx_fid'),
'ALTER TABLE `knowledge_fragment` DROP INDEX `idx_fid`', 'SELECT 1');
PREPARE stmt FROM @drop_idx_fid; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @add_uk_fid = IF(EXISTS(
SELECT 1 FROM information_schema.statistics WHERE table_schema = DATABASE()
AND table_name = 'knowledge_fragment' AND index_name = 'uk_fid'),
'SELECT 1', 'ALTER TABLE `knowledge_fragment` ADD UNIQUE INDEX `uk_fid` (`fid`)');
PREPARE stmt FROM @add_uk_fid; EXECUTE stmt; DEALLOCATE PREPARE stmt;
ALTER TABLE `knowledge_fragment` MODIFY COLUMN `fid` varchar(32) NOT NULL COMMENT '向量库片段ID';
SET @add_tenant_user = IF(EXISTS(
SELECT 1 FROM information_schema.statistics WHERE table_schema = DATABASE()
AND table_name = 'knowledge_info' AND index_name = 'idx_tenant_user'),
'SELECT 1', 'ALTER TABLE `knowledge_info` ADD INDEX `idx_tenant_user` (`tenant_id`, `user_id`)');
PREPARE stmt FROM @add_tenant_user; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @add_tenant_share = IF(EXISTS(
SELECT 1 FROM information_schema.statistics WHERE table_schema = DATABASE()
AND table_name = 'knowledge_info' AND index_name = 'idx_tenant_share'),
'SELECT 1', 'ALTER TABLE `knowledge_info` ADD INDEX `idx_tenant_share` (`tenant_id`, `share`)');
PREPARE stmt FROM @add_tenant_share; EXECUTE stmt; DEALLOCATE PREPARE stmt;

View File

@@ -0,0 +1,7 @@
-- 加宽 chat_provider.provider_icon 字段 (对应 issue IHPUDA)
-- 背景:文件系统使用 minio 私有桶时,厂商图标存的是带签名的临时访问 URL
-- 长度常超过 255导致「Data too long for column 'provider_icon'」。
-- MODIFY COLUMN 可重复执行。
ALTER TABLE `chat_provider`
MODIFY COLUMN `provider_icon` varchar(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '厂商图标';

View File

@@ -0,0 +1,33 @@
-- 补充工作流节点消息模板配置 (对应 issue IJX5VV)
-- 背景NodeMessageTemplateEnum 依赖以下 7 个 sys_config 键,缺失时
-- WorkflowMessageUtil.getNodeMessageTemplate 会抛出「请先配置该节点的响应模板」。
-- 这批配置在历史提交 20d531c0 中存在SQL 脚本合并重命名时遗失,此处恢复。
-- 幂等:按 config_key + tenant_id 判重,可重复执行。
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`)
SELECT 2027192921483309058, '000000', 'HTTP请求节点响应模板', 'node.httpRequest.template', '✅ HTTP请求节点结束响应 - ', 'Y', 103, 1, '2026-02-27 09:23:51', 1, '2026-02-27 09:31:41', NULL
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_config` WHERE `config_key` = 'node.httpRequest.template' AND `tenant_id` = '000000');
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`)
SELECT 2027193296990957569, '000000', '文生图节点响应模板', 'node.image.template', '🎨 文生图节点:结束响应 - 图片URL: ', 'Y', 103, 1, '2026-02-27 09:25:20', 1, '2026-02-27 09:31:52', NULL
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_config` WHERE `config_key` = 'node.image.template' AND `tenant_id` = '000000');
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`)
SELECT 2027193820393959425, '000000', '发送邮箱节点响应模板', 'node.mailsend.template', '📧 发送邮箱节点:结束响应 - ', 'Y', 103, 1, '2026-02-27 09:27:25', 1, '2026-02-27 09:32:05', NULL
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_config` WHERE `config_key` = 'node.mailsend.template' AND `tenant_id` = '000000');
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`)
SELECT 2027194134438277122, '000000', '结束节点响应模板', 'node.end.template', '🔚 流程已执行完毕,如果您有其他需求,请随时重新发起请求。', 'Y', 103, 1, '2026-02-27 09:28:40', 1, '2026-02-27 09:32:53', NULL
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_config` WHERE `config_key` = 'node.end.template' AND `tenant_id` = '000000');
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`)
SELECT 2027208880369647617, '000000', '条件分支节点响应模板', 'node.switch.template', '🔀 条件分支节点:触发 -> 跳转到节点 ', 'Y', 103, 1, '2026-02-27 10:27:15', 1, '2026-02-27 10:35:54', NULL
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_config` WHERE `config_key` = 'node.switch.template' AND `tenant_id` = '000000');
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`)
SELECT 2027213914603995137, '000000', '大模型回答节点响应模板', 'node.llmAnswer.template', '🤖 LLM 节点 生成回答:', 'Y', 103, 1, '2026-02-27 10:47:16', 1, '2026-02-27 10:52:40', NULL
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_config` WHERE `config_key` = 'node.llmAnswer.template' AND `tenant_id` = '000000');
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`)
SELECT 2027217577397391361, '000000', '工作流异常响应模板', 'node.exception.template', '🛑 工作流发生异常:', 'N', 103, 1, '2026-02-27 11:01:49', 1, '2026-02-27 11:02:01', NULL
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_config` WHERE `config_key` = 'node.exception.template' AND `tenant_id` = '000000');

View File

@@ -0,0 +1,119 @@
-- 注册链路修复:补齐缺失的菜单权限标识 + 新建注册默认角色
-- 关联问题:
-- #3 注册用户无默认角色 -> 无权限访问 AI 对话界面
-- #4 sys_menu 缺 system:session:* / system:attach:* / system:fragment:*
-- 且 知识管理 父菜单 perms 为 knowledge:info:list与控制器
-- KnowledgeInfoController 用的 system:info:list 对不上,:list 无法授权。
-- 本脚本幂等可重复执行INSERT IGNORE + UPDATE 天然幂等)。
-- 新增 menu_id / role_id / config_id 统一使用 2099010100000000xxx 段,
-- 与现有 snowflake id2xxxxxxxxxxxxxxxxx不冲突。
-- ============================================================
-- 1. 修正 知识管理 父菜单权限标识knowledge:info:list -> system:info:list
-- ============================================================
UPDATE `sys_menu`
SET `perms` = 'system:info:list'
WHERE `menu_id` = 2006681261898813441 AND `perms` = 'knowledge:info:list';
-- ============================================================
-- 2. 新增 会话管理 菜单组system:session:*
-- 父菜单=对话管理(2000209300188356609)。
-- 管理端暂无 chat/session 页面,故 C 菜单设为隐藏(visible=1)
-- 权限标识仍可在角色管理中授权给用户端使用。
-- ============================================================
INSERT IGNORE INTO `sys_menu` VALUES
(2099010100000000001, '会话管理', 2000209300188356609, 6, 'session', NULL, NULL, 1, 0, 'C', '1', '0', 'system:session:list', '#', 103, 1, '2026-07-24 00:00:00', NULL, NULL, '会话管理菜单'),
(2099010100000000002, '会话管理查询', 2099010100000000001, 1, '#', '', NULL, 1, 0, 'F', '0', '0', 'system:session:query', '#', 103, 1, '2026-07-24 00:00:00', NULL, NULL, ''),
(2099010100000000003, '会话管理新增', 2099010100000000001, 2, '#', '', NULL, 1, 0, 'F', '0', '0', 'system:session:add', '#', 103, 1, '2026-07-24 00:00:00', NULL, NULL, ''),
(2099010100000000004, '会话管理修改', 2099010100000000001, 3, '#', '', NULL, 1, 0, 'F', '0', '0', 'system:session:edit', '#', 103, 1, '2026-07-24 00:00:00', NULL, NULL, ''),
(2099010100000000005, '会话管理删除', 2099010100000000001, 4, '#', '', NULL, 1, 0, 'F', '0', '0', 'system:session:remove', '#', 103, 1, '2026-07-24 00:00:00', NULL, NULL, ''),
(2099010100000000006, '会话管理导出', 2099010100000000001, 5, '#', '', NULL, 1, 0, 'F', '0', '0', 'system:session:export', '#', 103, 1, '2026-07-24 00:00:00', NULL, NULL, '');
-- ============================================================
-- 3. 新增 知识附件 菜单组system:attach:*
-- 父菜单=对话管理(2000209300188356609),组件对应管理端 knowledge/attach/index。
-- ============================================================
INSERT IGNORE INTO `sys_menu` VALUES
(2099010100000000010, '知识附件', 2000209300188356609, 7, 'attach', 'knowledge/attach/index', NULL, 1, 0, 'C', '0', '0', 'system:attach:list', 'ant-design:paper-clip-outlined', 103, 1, '2026-07-24 00:00:00', NULL, NULL, '知识附件菜单'),
(2099010100000000011, '知识附件查询', 2099010100000000010, 1, '#', '', NULL, 1, 0, 'F', '0', '0', 'system:attach:query', '#', 103, 1, '2026-07-24 00:00:00', NULL, NULL, ''),
(2099010100000000012, '知识附件新增', 2099010100000000010, 2, '#', '', NULL, 1, 0, 'F', '0', '0', 'system:attach:add', '#', 103, 1, '2026-07-24 00:00:00', NULL, NULL, ''),
(2099010100000000013, '知识附件修改', 2099010100000000010, 3, '#', '', NULL, 1, 0, 'F', '0', '0', 'system:attach:edit', '#', 103, 1, '2026-07-24 00:00:00', NULL, NULL, ''),
(2099010100000000014, '知识附件删除', 2099010100000000010, 4, '#', '', NULL, 1, 0, 'F', '0', '0', 'system:attach:remove', '#', 103, 1, '2026-07-24 00:00:00', NULL, NULL, ''),
(2099010100000000015, '知识附件导出', 2099010100000000010, 5, '#', '', NULL, 1, 0, 'F', '0', '0', 'system:attach:export', '#', 103, 1, '2026-07-24 00:00:00', NULL, NULL, '');
-- ============================================================
-- 4. 新增 知识片段 菜单组system:fragment:*
-- 父菜单=对话管理(2000209300188356609),组件对应管理端 knowledge/fragment/index。
-- ============================================================
INSERT IGNORE INTO `sys_menu` VALUES
(2099010100000000020, '知识片段', 2000209300188356609, 8, 'fragment', 'knowledge/fragment/index', NULL, 1, 0, 'C', '0', '0', 'system:fragment:list', 'ant-design:file-text-outlined', 103, 1, '2026-07-24 00:00:00', NULL, NULL, '知识片段菜单'),
(2099010100000000021, '知识片段查询', 2099010100000000020, 1, '#', '', NULL, 1, 0, 'F', '0', '0', 'system:fragment:query', '#', 103, 1, '2026-07-24 00:00:00', NULL, NULL, ''),
(2099010100000000022, '知识片段新增', 2099010100000000020, 2, '#', '', NULL, 1, 0, 'F', '0', '0', 'system:fragment:add', '#', 103, 1, '2026-07-24 00:00:00', NULL, NULL, ''),
(2099010100000000023, '知识片段修改', 2099010100000000020, 3, '#', '', NULL, 1, 0, 'F', '0', '0', 'system:fragment:edit', '#', 103, 1, '2026-07-24 00:00:00', NULL, NULL, ''),
(2099010100000000024, '知识片段删除', 2099010100000000020, 4, '#', '', NULL, 1, 0, 'F', '0', '0', 'system:fragment:remove', '#', 103, 1, '2026-07-24 00:00:00', NULL, NULL, ''),
(2099010100000000025, '知识片段导出', 2099010100000000020, 5, '#', '', NULL, 1, 0, 'F', '0', '0', 'system:fragment:export', '#', 103, 1, '2026-07-24 00:00:00', NULL, NULL, '');
-- ============================================================
-- 5. 新建 普通用户 角色(租户 000000data_scope=5 仅本人)
-- ============================================================
INSERT IGNORE INTO `sys_role` VALUES
(2099010100000000030, '000000', '普通用户', 'user', 2, '5', 1, 1, '0', '0', 103, 1, '2026-07-24 00:00:00', NULL, NULL, '注册用户默认角色');
-- ============================================================
-- 6. 角色-菜单关联:普通用户 拥有用户端 AI 对话所需权限
-- 会话管理(001-006) + 聊天消息(2000210914680823809 及 810-814)
-- + 知识管理(2006681261898813441 及 442-446)
-- + 知识附件(010-015) + 知识片段(020-025)
-- ============================================================
INSERT IGNORE INTO `sys_role_menu` (`role_id`, `menu_id`) VALUES
-- 会话管理
(2099010100000000030, 2099010100000000001),
(2099010100000000030, 2099010100000000002),
(2099010100000000030, 2099010100000000003),
(2099010100000000030, 2099010100000000004),
(2099010100000000030, 2099010100000000005),
(2099010100000000030, 2099010100000000006),
-- 聊天消息
(2099010100000000030, 2000210914680823809),
(2099010100000000030, 2000210914680823810),
(2099010100000000030, 2000210914680823811),
(2099010100000000030, 2000210914680823812),
(2099010100000000030, 2000210914680823813),
(2099010100000000030, 2000210914680823814),
-- 知识管理
(2099010100000000030, 2006681261898813441),
(2099010100000000030, 2006681261898813442),
(2099010100000000030, 2006681261898813443),
(2099010100000000030, 2006681261898813444),
(2099010100000000030, 2006681261898813445),
(2099010100000000030, 2006681261898813446),
-- 知识附件
(2099010100000000030, 2099010100000000010),
(2099010100000000030, 2099010100000000011),
(2099010100000000030, 2099010100000000012),
(2099010100000000030, 2099010100000000013),
(2099010100000000030, 2099010100000000014),
(2099010100000000030, 2099010100000000015),
-- 知识片段
(2099010100000000030, 2099010100000000020),
(2099010100000000030, 2099010100000000021),
(2099010100000000030, 2099010100000000022),
(2099010100000000030, 2099010100000000023),
(2099010100000000030, 2099010100000000024),
(2099010100000000030, 2099010100000000025);
-- ============================================================
-- 7. 注册默认角色配置项 sys.register.defaultRoleId
-- 后端 SysRegisterService 注册成功后读取此配置为新用户绑定角色;
-- 值为空字符串时不绑定(保留旧行为)。
-- ============================================================
INSERT IGNORE INTO `sys_config` VALUES
(2099010100000000031, '000000', '注册-默认角色ID', 'sys.register.defaultRoleId', '2099010100000000030', 'Y', 103, 1, '2026-07-24 00:00:00', NULL, NULL, '新注册用户绑定的默认角色ID留空则不绑定');
-- ============================================================
-- 8. 前置条件(运营项,默认不执行):开启用户注册
-- sys.account.registerUser 默认 false后端 AuthController.register
-- 会据此返回「当前系统没有开启注册功能」。若要开放注册,取消注释执行。
-- ============================================================
-- UPDATE `sys_config` SET `config_value` = 'true'
-- WHERE `config_key` = 'sys.account.registerUser' AND `tenant_id` = '000000';

View File

@@ -0,0 +1,39 @@
-- 一次性补全工作流节点消息模板配置 (NodeMessageTemplateEnum 全部 8 个键)
-- 背景:节点执行时 WorkflowMessageUtil.getNodeMessageTemplate 从 sys_config 读取展示模板,
-- 历史库中这批配置缺失, 导致运行工作流抛「请先配置该节点的响应模板」。
-- 其中前 7 个见 2026-07-21-sys-config-node-template.sql,
-- Google Search 为此前从未入库的节点模板。
-- 说明:代码已增加内置默认模板兜底, 本脚本为可选, 执行后模板可在 系统管理-配置管理 中自定义。
-- 幂等:按 config_key + tenant_id 判重, 可重复执行。
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`)
SELECT 2027192921483309058, '000000', 'HTTP请求节点响应模板', 'node.httpRequest.template', '✅ HTTP请求节点结束响应 - ', 'Y', 103, 1, '2026-02-27 09:23:51', 1, '2026-02-27 09:31:41', NULL
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_config` WHERE `config_key` = 'node.httpRequest.template' AND `tenant_id` = '000000');
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`)
SELECT 2027193296990957569, '000000', '文生图节点响应模板', 'node.image.template', '🎨 文生图节点:结束响应 - 图片URL: ', 'Y', 103, 1, '2026-02-27 09:25:20', 1, '2026-02-27 09:31:52', NULL
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_config` WHERE `config_key` = 'node.image.template' AND `tenant_id` = '000000');
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`)
SELECT 2027193820393959425, '000000', '发送邮箱节点响应模板', 'node.mailsend.template', '📧 发送邮箱节点:结束响应 - ', 'Y', 103, 1, '2026-02-27 09:27:25', 1, '2026-02-27 09:32:05', NULL
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_config` WHERE `config_key` = 'node.mailsend.template' AND `tenant_id` = '000000');
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`)
SELECT 2027194134438277122, '000000', '结束节点响应模板', 'node.end.template', '🔚 流程已执行完毕,如果您有其他需求,请随时重新发起请求。', 'Y', 103, 1, '2026-02-27 09:28:40', 1, '2026-02-27 09:32:53', NULL
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_config` WHERE `config_key` = 'node.end.template' AND `tenant_id` = '000000');
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`)
SELECT 2027208880369647617, '000000', '条件分支节点响应模板', 'node.switch.template', '🔀 条件分支节点:触发 -> 跳转到节点 ', 'Y', 103, 1, '2026-02-27 10:27:15', 1, '2026-02-27 10:35:54', NULL
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_config` WHERE `config_key` = 'node.switch.template' AND `tenant_id` = '000000');
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`)
SELECT 2027213914603995137, '000000', '大模型回答节点响应模板', 'node.llmAnswer.template', '🤖 LLM 节点 生成回答:', 'Y', 103, 1, '2026-02-27 10:47:16', 1, '2026-02-27 10:52:40', NULL
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_config` WHERE `config_key` = 'node.llmAnswer.template' AND `tenant_id` = '000000');
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`)
SELECT 2027217577397391361, '000000', '工作流异常响应模板', 'node.exception.template', '🛑 工作流发生异常:', 'N', 103, 1, '2026-02-27 11:01:49', 1, '2026-02-27 11:02:01', NULL
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_config` WHERE `config_key` = 'node.exception.template' AND `tenant_id` = '000000');
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`)
SELECT 2084157200000000003, '000000', '网络搜索节点响应模板', 'node.googleSearch.template', '🔍 网络搜索节点处理完成:', 'Y', 103, 1, '2026-07-29 19:40:00', 1, '2026-07-29 19:40:00', NULL
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_config` WHERE `config_key` = 'node.googleSearch.template' AND `tenant_id` = '000000');

View File

@@ -0,0 +1,66 @@
-- 智谱 Web Search 工作流扩展节点
-- 内部组件名继续使用 Google以兼容现有前端组件和已保存流程。
UPDATE `t_workflow_component`
SET `title` = '网络搜索',
`remark` = '调用智谱 Web Search 检索互联网信息',
`display_order` = 40,
`is_enable` = 1,
`is_deleted` = 0,
`update_time` = NOW()
WHERE `name` = 'Google'
AND `tenant_id` = '000000';
INSERT INTO `t_workflow_component`
(`uuid`, `name`, `title`, `remark`, `display_order`, `is_enable`,
`create_time`, `update_time`, `is_deleted`, `tenant_id`)
SELECT
'a7f8c2d44e5b4c83a9d6f103c2b47e18',
'Google',
'网络搜索',
'调用智谱 Web Search 检索互联网信息',
40,
1,
NOW(),
NOW(),
0,
'000000'
FROM DUAL
WHERE NOT EXISTS (
SELECT 1
FROM `t_workflow_component`
WHERE `name` = 'Google'
AND `tenant_id` = '000000'
);
UPDATE `sys_config`
SET `config_name` = '网络搜索节点响应模板',
`config_value` = '🔍 网络搜索节点处理完成:',
`update_time` = NOW()
WHERE `config_key` = 'node.googleSearch.template'
AND `tenant_id` = '000000';
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`)
SELECT
2084157200000000003,
'000000',
'网络搜索节点响应模板',
'node.googleSearch.template',
'🔍 网络搜索节点处理完成:',
'Y',
103,
1,
NOW(),
1,
NOW(),
'智谱 Web Search 工作流扩展节点'
FROM DUAL
WHERE NOT EXISTS (
SELECT 1
FROM `sys_config`
WHERE `config_key` = 'node.googleSearch.template'
AND `tenant_id` = '000000'
);

View File

@@ -0,0 +1,128 @@
-- 链路追踪运行记录表
CREATE TABLE IF NOT EXISTS `trace_run` (
`id` bigint NOT NULL COMMENT '主键',
`trace_id` varchar(64) NOT NULL COMMENT '链路ID',
`trace_name` varchar(128) NOT NULL COMMENT '链路名称',
`business_type` varchar(64) NOT NULL COMMENT '业务类型',
`business_id` varchar(128) DEFAULT NULL COMMENT '业务ID',
`user_id` bigint DEFAULT NULL COMMENT '用户ID',
`tenant_id` varchar(20) DEFAULT '000000' COMMENT '租户编号',
`status` varchar(32) NOT NULL COMMENT '状态',
`start_time` datetime NOT NULL COMMENT '开始时间',
`end_time` datetime DEFAULT NULL COMMENT '结束时间',
`duration_ms` bigint DEFAULT NULL COMMENT '耗时毫秒',
`error_message` varchar(1000) DEFAULT NULL COMMENT '错误摘要',
`metadata` text DEFAULT NULL COMMENT '元数据JSON',
`create_dept` bigint DEFAULT NULL COMMENT '创建部门',
`create_by` bigint DEFAULT NULL COMMENT '创建者',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`update_by` bigint DEFAULT NULL COMMENT '更新者',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
`del_flag` char(1) DEFAULT '0' COMMENT '删除标志0代表存在 2代表删除',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE KEY `uk_trace_run_trace_id` (`trace_id`) USING BTREE,
KEY `idx_trace_run_business` (`business_type`, `business_id`) USING BTREE,
KEY `idx_trace_run_status_time` (`status`, `start_time`) USING BTREE,
KEY `idx_trace_run_tenant_time` (`tenant_id`, `start_time`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='链路追踪运行记录表' ROW_FORMAT=DYNAMIC;
-- 链路追踪节点记录表
CREATE TABLE IF NOT EXISTS `trace_node` (
`id` bigint NOT NULL COMMENT '主键',
`trace_id` varchar(64) NOT NULL COMMENT '链路ID',
`node_id` varchar(64) NOT NULL COMMENT '节点ID',
`tenant_id` varchar(20) DEFAULT '000000' COMMENT '租户编号',
`parent_node_id` varchar(64) DEFAULT NULL COMMENT '父节点ID',
`node_name` varchar(128) NOT NULL COMMENT '节点名称',
`node_type` varchar(64) NOT NULL COMMENT '节点类型',
`depth` int DEFAULT 0 COMMENT '节点深度',
`sort_order` int DEFAULT 0 COMMENT '排序',
`class_name` varchar(255) DEFAULT NULL COMMENT '类名',
`method_name` varchar(128) DEFAULT NULL COMMENT '方法名',
`status` varchar(32) NOT NULL COMMENT '状态',
`start_time` datetime NOT NULL COMMENT '开始时间',
`end_time` datetime DEFAULT NULL COMMENT '结束时间',
`duration_ms` bigint DEFAULT NULL COMMENT '耗时毫秒',
`error_message` varchar(1000) DEFAULT NULL COMMENT '错误摘要',
`input_payload` text DEFAULT NULL COMMENT '输入JSON',
`output_payload` text DEFAULT NULL COMMENT '输出JSON',
`metadata` text DEFAULT NULL COMMENT '元数据JSON',
`create_dept` bigint DEFAULT NULL COMMENT '创建部门',
`create_by` bigint DEFAULT NULL COMMENT '创建者',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`update_by` bigint DEFAULT NULL COMMENT '更新者',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
`del_flag` char(1) DEFAULT '0' COMMENT '删除标志0代表存在 2代表删除',
PRIMARY KEY (`id`) USING BTREE,
KEY `idx_trace_node_trace_id` (`trace_id`) USING BTREE,
KEY `idx_trace_node_parent` (`trace_id`, `parent_node_id`) USING BTREE,
KEY `idx_trace_node_time` (`trace_id`, `start_time`) USING BTREE,
KEY `idx_trace_node_tenant_time` (`tenant_id`, `start_time`) USING BTREE,
KEY `idx_trace_node_type_status` (`node_type`, `status`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='链路追踪节点记录表' ROW_FORMAT=DYNAMIC;
-- 兼容已存在的旧 trace 表CREATE TABLE IF NOT EXISTS 不会给旧表补新字段
SET @trace_run_add_tenant_sql = (
SELECT IF(COUNT(*) = 0,
'ALTER TABLE `trace_run` ADD COLUMN `tenant_id` varchar(20) DEFAULT ''000000'' COMMENT ''租户编号'' AFTER `user_id`',
'SELECT 1'
)
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'trace_run'
AND COLUMN_NAME = 'tenant_id'
);
PREPARE trace_run_add_tenant_stmt FROM @trace_run_add_tenant_sql;
EXECUTE trace_run_add_tenant_stmt;
DEALLOCATE PREPARE trace_run_add_tenant_stmt;
SET @trace_run_add_tenant_idx_sql = (
SELECT IF(COUNT(*) = 0,
'ALTER TABLE `trace_run` ADD INDEX `idx_trace_run_tenant_time` (`tenant_id`, `start_time`) USING BTREE',
'SELECT 1'
)
FROM information_schema.STATISTICS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'trace_run'
AND INDEX_NAME = 'idx_trace_run_tenant_time'
);
PREPARE trace_run_add_tenant_idx_stmt FROM @trace_run_add_tenant_idx_sql;
EXECUTE trace_run_add_tenant_idx_stmt;
DEALLOCATE PREPARE trace_run_add_tenant_idx_stmt;
SET @trace_node_add_tenant_sql = (
SELECT IF(COUNT(*) = 0,
'ALTER TABLE `trace_node` ADD COLUMN `tenant_id` varchar(20) DEFAULT ''000000'' COMMENT ''租户编号'' AFTER `node_id`',
'SELECT 1'
)
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'trace_node'
AND COLUMN_NAME = 'tenant_id'
);
PREPARE trace_node_add_tenant_stmt FROM @trace_node_add_tenant_sql;
EXECUTE trace_node_add_tenant_stmt;
DEALLOCATE PREPARE trace_node_add_tenant_stmt;
SET @trace_node_add_tenant_idx_sql = (
SELECT IF(COUNT(*) = 0,
'ALTER TABLE `trace_node` ADD INDEX `idx_trace_node_tenant_time` (`tenant_id`, `start_time`) USING BTREE',
'SELECT 1'
)
FROM information_schema.STATISTICS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'trace_node'
AND INDEX_NAME = 'idx_trace_node_tenant_time'
);
PREPARE trace_node_add_tenant_idx_stmt FROM @trace_node_add_tenant_idx_sql;
EXECUTE trace_node_add_tenant_idx_stmt;
DEALLOCATE PREPARE trace_node_add_tenant_idx_stmt;
-- 链路追踪监控菜单 & 按钮权限
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`, `remark`)
SELECT (SELECT COALESCE(MAX(`menu_id`), 0) + 1 FROM (SELECT `menu_id` FROM `sys_menu`) t), '链路追踪', 2, 7, 'trace', 'monitor/trace/index', '', 1, 0, 'C', '0', '0', 'monitor:trace:list', 'tabler:route', 103, 1, NOW(), '链路追踪监控菜单';
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`, `remark`)
SELECT (SELECT COALESCE(MAX(`menu_id`), 0) + 1 FROM (SELECT `menu_id` FROM `sys_menu`) t), '链路追踪查询', (SELECT `menu_id` FROM `sys_menu` WHERE `perms` = 'monitor:trace:list' AND `menu_type` = 'C' LIMIT 1), 1, '#', '', '', 1, 0, 'F', '0', '0', 'monitor:trace:query', '#', 103, 1, NOW(), '';

47
pom.xml
View File

@@ -13,7 +13,7 @@
<description>全栈式AI开发平台</description> <description>全栈式AI开发平台</description>
<properties> <properties>
<revision>3.0.0</revision> <revision>3.1.0</revision>
<spring-boot.version>3.5.8</spring-boot.version> <spring-boot.version>3.5.8</spring-boot.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
@@ -43,8 +43,6 @@
<aws.sdk.version>2.28.22</aws.sdk.version> <aws.sdk.version>2.28.22</aws.sdk.version>
<!-- SMS 配置 --> <!-- SMS 配置 -->
<sms4j.version>3.3.5</sms4j.version> <sms4j.version>3.3.5</sms4j.version>
<!-- 限制框架中的fastjson版本 -->
<fastjson.version>1.2.83</fastjson.version>
<!-- 面向运行时的D-ORM依赖 --> <!-- 面向运行时的D-ORM依赖 -->
<anyline.version>8.7.2-20250603</anyline.version> <anyline.version>8.7.2-20250603</anyline.version>
<!-- 工作流配置 --> <!-- 工作流配置 -->
@@ -54,18 +52,25 @@
<!-- Jackson XML --> <!-- Jackson XML -->
<jackson-dataformat-xml.version>2.18.2</jackson-dataformat-xml.version> <jackson-dataformat-xml.version>2.18.2</jackson-dataformat-xml.version>
<!-- AI 相关依赖 --> <!-- AI 相关依赖 -->
<langchain4j.version>1.13.0</langchain4j.version>
<langchain4j.community.version>1.13.0-beta23</langchain4j.community.version> <langchain4j.version>1.17.2</langchain4j.version>
<langgraph4j.version>1.5.3</langgraph4j.version> <langchain4j.beta.version>1.17.2-beta27</langchain4j.beta.version>
<langchain4j.community.version>1.17.0-beta27</langchain4j.community.version>
<langgraph4j.version>1.8.20</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.2.7</dify.version>
<coze.version>0.4.2</coze.version>
<!-- 智谱官方 Java SDK -->
<zai-sdk.version>0.3.5</zai-sdk.version>
<!-- gRPC 版本 - 解决 Milvus SDK 依赖冲突 --> <!-- gRPC 版本 - 解决 Milvus SDK 依赖冲突 -->
<grpc.version>1.62.2</grpc.version> <grpc.version>1.62.2</grpc.version>
<!-- Apache Commons Compress - 用于POI处理ZIP格式 --> <!-- Apache Commons Compress - 用于POI处理ZIP格式 -->
<commons-compress.version>1.27.1</commons-compress.version> <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>
<javassist.version>3.30.2-GA</javassist.version>
<jsoup.version>1.21.2</jsoup.version> <jsoup.version>1.21.2</jsoup.version>
<knife4j.version>4.4.0</knife4j.version> <knife4j.version>4.4.0</knife4j.version>
<swagger-annotations.version>2.2.8</swagger-annotations.version> <swagger-annotations.version>2.2.8</swagger-annotations.version>
@@ -79,7 +84,7 @@
<maven-surefire-plugin.version>3.5.3</maven-surefire-plugin.version> <maven-surefire-plugin.version>3.5.3</maven-surefire-plugin.version>
<flatten-maven-plugin.version>1.3.0</flatten-maven-plugin.version> <flatten-maven-plugin.version>1.3.0</flatten-maven-plugin.version>
<!-- 打包默认跳过测试 --> <!-- 打包默认跳过测试 -->
<skipTests>true</skipTests> <skipTests>false</skipTests>
</properties> </properties>
<profiles> <profiles>
@@ -342,6 +347,12 @@
<groupId>me.zhyd.oauth</groupId> <groupId>me.zhyd.oauth</groupId>
<artifactId>JustAuth</artifactId> <artifactId>JustAuth</artifactId>
<version>${justauth.version}</version> <version>${justauth.version}</version>
<exclusions>
<exclusion>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</exclusion>
</exclusions>
</dependency> </dependency>
<!-- 离线IP地址定位库 ip2region --> <!-- 离线IP地址定位库 ip2region -->
@@ -351,12 +362,6 @@
<version>${ip2region.version}</version> <version>${ip2region.version}</version>
</dependency> </dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
<dependency> <dependency>
<groupId>org.ruoyi</groupId> <groupId>org.ruoyi</groupId>
<artifactId>ruoyi-system</artifactId> <artifactId>ruoyi-system</artifactId>
@@ -499,20 +504,8 @@
<resources> <resources>
<resource> <resource>
<directory>src/main/resources</directory> <directory>src/main/resources</directory>
<!-- 关闭过滤 -->
<filtering>false</filtering> <filtering>false</filtering>
</resource> </resource>
<resource>
<directory>src/main/resources</directory>
<!-- 引入所有 匹配文件进行过滤 -->
<includes>
<include>application*</include>
<include>bootstrap*</include>
<include>banner*</include>
</includes>
<!-- 启用过滤 即该资源中的变量将会被过滤器中的值替换 -->
<filtering>true</filtering>
</resource>
</resources> </resources>
</build> </build>

View File

@@ -1,31 +1,59 @@
# 贝尔实验室 Spring 官方推荐镜像 JDK下载地址 https://bell-sw.com/pages/downloads/ # FFmpeg-enabled variant of ruoyi-admin/Dockerfile.
FROM bellsoft/liberica-openjdk-rocky:17.0.16-cds FROM bellsoft/liberica-openjdk-rocky:17.0.16-cds
#FROM bellsoft/liberica-openjdk-rocky:21.0.8-cds
#FROM findepi/graalvm:java17-native
LABEL maintainer="Lion Li" LABEL maintainer="Lion Li"
# Rocky base repositories do not provide the full codec build. RPM Fusion Free
# supplies ffmpeg with libx264, while the checks below prevent a reduced build
# from reaching production unnoticed.
RUN set -eux; \
dnf -y install dnf-plugins-core epel-release; \
. /etc/os-release; \
rocky_major="${VERSION_ID%%.*}"; \
if [ "${rocky_major}" -ge 9 ]; then \
dnf config-manager --set-enabled crb; \
else \
dnf config-manager --set-enabled powertools; \
fi; \
dnf -y install "https://mirrors.rpmfusion.org/free/el/rpmfusion-free-release-${rocky_major}.noarch.rpm"; \
dnf -y install ffmpeg; \
for filter in scale pad fps setsar format tpad trim settb setpts xfade \
aresample aformat apad atrim asetpts anullsrc concat acrossfade; do \
ffmpeg -hide_banner -filters 2>/dev/null | grep -Eq "[[:space:]]${filter}[[:space:]]"; \
done; \
ffmpeg -hide_banner -h filter=xfade 2>&1 | grep -q dissolve; \
ffmpeg -hide_banner -h filter=xfade 2>&1 | grep -q fadeblack; \
ffmpeg -hide_banner -h filter=xfade 2>&1 | grep -q slideleft; \
ffmpeg -hide_banner -encoders 2>/dev/null | grep -Eq '[[:space:]]libx264[[:space:]]'; \
ffmpeg -hide_banner -encoders 2>/dev/null | grep -Eq '[[:space:]]aac[[:space:]]'; \
ffprobe -hide_banner -version >/dev/null; \
dnf clean all; \
rm -rf /var/cache/dnf
RUN mkdir -p /ruoyi/server/logs \ RUN mkdir -p /ruoyi/server/logs \
/ruoyi/server/temp \ /ruoyi/server/temp \
/ruoyi/skywalking/agent /ruoyi/skywalking/agent
WORKDIR /ruoyi/server WORKDIR /ruoyi/server
ENV SERVER_PORT=8080 SNAIL_PORT=28080 LANG=C.UTF-8 LC_ALL=C.UTF-8 JAVA_OPTS="" ENV SERVER_PORT=8080 \
SNAIL_PORT=28080 \
LANG=C.UTF-8 \
LC_ALL=C.UTF-8 \
JAVA_OPTS="" \
FFMPEG_PATH=/usr/bin/ffmpeg \
FFPROBE_PATH=/usr/bin/ffprobe
EXPOSE ${SERVER_PORT} EXPOSE ${SERVER_PORT}
# 暴露 snail job 客户端端口 用于定时任务调度中心通信
EXPOSE ${SNAIL_PORT} EXPOSE ${SNAIL_PORT}
ADD ./target/ruoyi-admin.jar ./app.jar ADD ./target/ruoyi-admin.jar ./app.jar
SHELL ["/bin/bash", "-c"] SHELL ["/bin/bash", "-c"]
ENTRYPOINT java -Djava.security.egd=file:/dev/./urandom -Dserver.port=${SERVER_PORT} \ ENTRYPOINT java -Djava.security.egd=file:/dev/./urandom \
-Djava.io.tmpdir=/ruoyi/server/temp \
-Dserver.port=${SERVER_PORT} \
-Dsnail-job.port=${SNAIL_PORT} \ -Dsnail-job.port=${SNAIL_PORT} \
# 应用名称 如果想区分集群节点监控 改成不同的名称即可
#-Dskywalking.agent.service_name=ruoyi-server \
#-javaagent:/ruoyi/skywalking/agent/skywalking-agent.jar \
-XX:+HeapDumpOnOutOfMemoryError -XX:+UseZGC ${JAVA_OPTS} \ -XX:+HeapDumpOnOutOfMemoryError -XX:+UseZGC ${JAVA_OPTS} \
-jar app.jar -jar app.jar

View File

@@ -8,8 +8,8 @@ spring.boot.admin.client:
metadata: metadata:
username: ${spring.boot.admin.client.username} username: ${spring.boot.admin.client.username}
userpassword: ${spring.boot.admin.client.password} userpassword: ${spring.boot.admin.client.password}
username: @monitor.username@ username: ${MONITOR_USERNAME:ruoyi}
password: @monitor.password@ password: ${MONITOR_PASSWORD:123456}
--- # mcp配置信息 --- # mcp配置信息
mcp: mcp:
@@ -27,12 +27,12 @@ snail-job:
enabled: false enabled: false
# 需要在 SnailJob 后台组管理创建对应名称的组,然后创建任务的时候选择对应的组,才能正确分派任务 # 需要在 SnailJob 后台组管理创建对应名称的组,然后创建任务的时候选择对应的组,才能正确分派任务
group: "ruoyi_group" group: "ruoyi_group"
# SnailJob 接入验证令牌 详见 script/sql/ry_job.sql `sj_group_config` 表 # SnailJob 接入验证令牌 详见 docs/script/sql/ruoyi-ai-v3_mysql8.sql `sj_group_config` 表
token: "SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT" token: "SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT"
server: server:
host: 127.0.0.1 host: 127.0.0.1
port: 17888 port: 17888
# 命名空间UUID 详见 script/sql/ry_job.sql `sj_namespace`表`unique_id`字段 # 命名空间UUID 详见 docs/script/sql/ruoyi-ai-v3_mysql8.sql `sj_namespace`表`unique_id`字段
namespace: ${spring.profiles.active} namespace: ${spring.profiles.active}
# 随主应用端口漂移 # 随主应用端口漂移
port: 2${server.port} port: 2${server.port}

View File

@@ -9,8 +9,8 @@ spring.boot.admin.client:
metadata: metadata:
username: ${spring.boot.admin.client.username} username: ${spring.boot.admin.client.username}
userpassword: ${spring.boot.admin.client.password} userpassword: ${spring.boot.admin.client.password}
username: @monitor.username@ username: ${MONITOR_USERNAME:ruoyi}
password: @monitor.password@ password: ${MONITOR_PASSWORD:123456}
--- # mcp配置信息 --- # mcp配置信息
mcp: mcp:
@@ -28,12 +28,12 @@ snail-job:
enabled: false enabled: false
# 需要在 SnailJob 后台组管理创建对应名称的组,然后创建任务的时候选择对应的组,才能正确分派任务 # 需要在 SnailJob 后台组管理创建对应名称的组,然后创建任务的时候选择对应的组,才能正确分派任务
group: "ruoyi_group" group: "ruoyi_group"
# SnailJob 接入验证令牌 详见 script/sql/ry_job.sql `sj_group_config` 表 # SnailJob 接入验证令牌 详见 docs/script/sql/ruoyi-ai-v3_mysql8.sql `sj_group_config` 表
token: "SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT" token: "SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT"
server: server:
host: 127.0.0.1 host: 127.0.0.1
port: 17888 port: 17888
# 命名空间UUID 详见 script/sql/ry_job.sql `sj_namespace`表`unique_id`字段 # 命名空间UUID 详见 docs/script/sql/ruoyi-ai-v3_mysql8.sql `sj_namespace`表`unique_id`字段
namespace: ${spring.profiles.active} namespace: ${spring.profiles.active}
# 随主应用端口漂移 # 随主应用端口漂移
port: 2${server.port} port: 2${server.port}

View File

@@ -20,6 +20,10 @@ server:
# 阻塞任务线程池, 当执行类似servlet请求阻塞操作, undertow会从这个线程池中取得线程,它的值设置取决于系统的负载 # 阻塞任务线程池, 当执行类似servlet请求阻塞操作, undertow会从这个线程池中取得线程,它的值设置取决于系统的负载
worker: 256 worker: 256
--- # 小程序对话 WebSocket 兜底默认模型(前端未传 model 且无智能体绑定时使用)
chat:
default-model: deepseek-v4-flash
captcha: captcha:
# 是否启用验证码校验 # 是否启用验证码校验
enable: false enable: false
@@ -35,7 +39,7 @@ captcha:
# 日志配置 # 日志配置
logging: logging:
level: level:
org.ruoyi: @logging.level@ org.ruoyi: ${LOGGING_LEVEL_ORG_RUOYI:info}
org.springframework: warn org.springframework: warn
org.mybatis.spring.mapper: error org.mybatis.spring.mapper: error
org.apache.fury: warn org.apache.fury: warn
@@ -75,7 +79,7 @@ spring:
# 国际化资源文件路径 # 国际化资源文件路径
basename: i18n/messages basename: i18n/messages
profiles: profiles:
active: @profiles.active@ active: ${SPRING_PROFILES_ACTIVE:dev}
# 文件上传 # 文件上传
servlet: servlet:
multipart: multipart:
@@ -125,6 +129,7 @@ security:
- /*/api-docs/** - /*/api-docs/**
- /warm-flow-ui/config - /warm-flow-ui/config
- /workflow/run - /workflow/run
- /coding/**
# 多租户配置 # 多租户配置
tenant: tenant:
# 是否开启 # 是否开启
@@ -141,6 +146,9 @@ tenant:
- sys_client - sys_client
- sys_oss_config - sys_oss_config
- flow_spel - flow_spel
# 链路追踪监控表:运维需跨租户全局查看,且 trace_node 在异步线程写入、租户上下文不传播,故排除租户过滤
- trace_run
- trace_node
# MyBatisPlus配置 # MyBatisPlus配置
# https://baomidou.com/config/ # https://baomidou.com/config/
@@ -227,6 +235,15 @@ xss:
excludeUrls: excludeUrls:
- /system/notice - /system/notice
--- # 链路追踪配置
trace:
# 是否启用链路追踪,默认 true
# 关闭后所有埋点代码会直接透传业务逻辑,不写库、不创建上下文,零性能开销
enabled: true
payload:
# 错误信息最大字符长度(格式: "异常类名: 异常消息"),超过部分会被截断丢弃
max-error-length: 1000
--- # 分布式锁 lock4j 全局配置 --- # 分布式锁 lock4j 全局配置
lock4j: lock4j:
# 获取分布式锁超时时间,默认为 3000 毫秒 # 获取分布式锁超时时间,默认为 3000 毫秒
@@ -265,7 +282,7 @@ demo:
# 是否开启演示模式(开启后所有写操作将被拦截) # 是否开启演示模式(开启后所有写操作将被拦截)
enabled: false enabled: false
# 提示消息 # 提示消息
message: "演示模式,不允许进行写操作" message: "演示模式,不允许操作"
# 排除的路径(这些路径不受演示模式限制) # 排除的路径(这些路径不受演示模式限制)
excludes: excludes:
- /login - /login
@@ -276,7 +293,9 @@ demo:
- /chat/send - /chat/send
- /system/session/** - /system/session/**
- /system/message/** - /system/message/**
- /system/attach/**
- /system/fragment/**
- /system/info/**
--- # warm-flow工作流配置 --- # warm-flow工作流配置
warm-flow: warm-flow:
# 是否开启工作流默认true # 是否开启工作流默认true
@@ -294,11 +313,12 @@ warm-flow:
vector-store: vector-store:
# 向量存储类型 可选(weaviate/milvus/qdrant) # 向量存储类型 可选(weaviate/milvus/qdrant)
# 如需修改向量库类型,请修改此配置值! # 如需修改向量库类型,请修改此配置值!
type: milvus # 注意:需与 docker-compose 实际部署的向量库保持一致(当前 compose 内置 weaviate映射端口 28080
type: weaviate
# Weaviate配置 # Weaviate配置
weaviate: weaviate:
protocol: http protocol: http
host: 127.0.0.1:6038 host: 127.0.0.1:28080
classname: LocalKnowledge classname: LocalKnowledge
# Milvus配置 # Milvus配置
milvus: milvus:
@@ -311,3 +331,48 @@ vector-store:
collectionname: LocalKnowledge collectionname: LocalKnowledge
api-key: api-key:
use-tls: false use-tls: false
# 流程编排扩展节点
workflow:
web-search:
zhipu:
# 推荐通过环境变量注入;为空时回退到模型管理中的 zhipu 厂商密钥
api-key: ${ZAI_API_KEY:}
base-url: ${ZHIPU_WEB_SEARCH_BASE_URL:https://open.bigmodel.cn/api/paas/v4/}
connect-timeout: ${ZHIPU_WEB_SEARCH_CONNECT_TIMEOUT:10}
read-timeout: ${ZHIPU_WEB_SEARCH_READ_TIMEOUT:30}
# 短剧成片合成
short-drama:
composition:
ffmpeg-path: ${FFMPEG_PATH:ffmpeg}
ffprobe-path: ${FFPROBE_PATH:ffprobe}
fps: ${SHORT_DRAMA_COMPOSITION_FPS:30}
audio-sample-rate: ${SHORT_DRAMA_COMPOSITION_AUDIO_SAMPLE_RATE:48000}
video-codec: ${SHORT_DRAMA_COMPOSITION_VIDEO_CODEC:libx264}
audio-codec: ${SHORT_DRAMA_COMPOSITION_AUDIO_CODEC:aac}
preset: ${SHORT_DRAMA_COMPOSITION_PRESET:medium}
crf: ${SHORT_DRAMA_COMPOSITION_CRF:20}
audio-bitrate: ${SHORT_DRAMA_COMPOSITION_AUDIO_BITRATE:192k}
max-clips: ${SHORT_DRAMA_COMPOSITION_MAX_CLIPS:100}
max-transition-seconds: ${SHORT_DRAMA_COMPOSITION_MAX_TRANSITION_SECONDS:2.0}
minimum-output-bytes: ${SHORT_DRAMA_COMPOSITION_MINIMUM_OUTPUT_BYTES:1024}
max-process-output-bytes: ${SHORT_DRAMA_COMPOSITION_MAX_PROCESS_OUTPUT_BYTES:1048576}
max-source-bytes: ${SHORT_DRAMA_COMPOSITION_MAX_SOURCE_BYTES:536870912}
max-total-source-bytes: ${SHORT_DRAMA_COMPOSITION_MAX_TOTAL_SOURCE_BYTES:2147483648}
probe-timeout: ${SHORT_DRAMA_COMPOSITION_PROBE_TIMEOUT:30s}
process-timeout: ${SHORT_DRAMA_COMPOSITION_PROCESS_TIMEOUT:30m}
job-stale-after: ${SHORT_DRAMA_COMPOSITION_JOB_STALE_AFTER:45m}
watermark-font-file: ${SHORT_DRAMA_COMPOSITION_WATERMARK_FONT_FILE:}
worker-core-size: ${SHORT_DRAMA_COMPOSITION_WORKER_CORE_SIZE:1}
worker-max-size: ${SHORT_DRAMA_COMPOSITION_WORKER_MAX_SIZE:2}
worker-queue-capacity: ${SHORT_DRAMA_COMPOSITION_WORKER_QUEUE_CAPACITY:8}
storage-mode: ${SHORT_DRAMA_COMPOSITION_STORAGE_MODE:local}
local-output-directory: ${SHORT_DRAMA_COMPOSITION_LOCAL_OUTPUT_DIRECTORY:logs/short-drama-compositions}
download:
connect-timeout: ${SHORT_DRAMA_DOWNLOAD_CONNECT_TIMEOUT:30s}
call-timeout: ${SHORT_DRAMA_DOWNLOAD_CALL_TIMEOUT:10m}
max-redirects: ${SHORT_DRAMA_DOWNLOAD_MAX_REDIRECTS:5}
# 生产环境建议配置为视频供应商或 OSS/CDN 域名,多个值用逗号分隔。
allowed-hosts: ${SHORT_DRAMA_DOWNLOAD_ALLOWED_HOSTS:}
fake-ip-allowed-hosts: ${SHORT_DRAMA_DOWNLOAD_FAKE_IP_ALLOWED_HOSTS:atlas-media.oss-us-west-1.aliyuncs.com}

View File

@@ -35,6 +35,7 @@
<module>ruoyi-common-tenant</module> <module>ruoyi-common-tenant</module>
<module>ruoyi-common-websocket</module> <module>ruoyi-common-websocket</module>
<module>ruoyi-common-sse</module> <module>ruoyi-common-sse</module>
<module>ruoyi-common-trace</module>
</modules> </modules>
<artifactId>ruoyi-common</artifactId> <artifactId>ruoyi-common</artifactId>

View File

@@ -14,7 +14,7 @@
</description> </description>
<properties> <properties>
<revision>3.0.0</revision> <revision>3.1.0</revision>
</properties> </properties>
<dependencyManagement> <dependencyManagement>
@@ -186,6 +186,13 @@
<version>${revision}</version> <version>${revision}</version>
</dependency> </dependency>
<!-- 链路追踪模块 -->
<dependency>
<groupId>org.ruoyi</groupId>
<artifactId>ruoyi-common-trace</artifactId>
<version>${revision}</version>
</dependency>
</dependencies> </dependencies>
</dependencyManagement> </dependencyManagement>

View File

@@ -38,8 +38,8 @@
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.alibaba</groupId> <groupId>com.fasterxml.jackson.core</groupId>
<artifactId>fastjson</artifactId> <artifactId>jackson-databind</artifactId>
</dependency> </dependency>
<dependency> <dependency>

View File

@@ -1,10 +1,12 @@
package org.ruoyi.common.chat.domain.bo.chat; package org.ruoyi.common.chat.domain.bo.chat;
import io.github.linpeilie.annotations.AutoMapper; import io.github.linpeilie.annotations.AutoMapper;
import jakarta.validation.constraints.NotBlank;
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.entity.chat.ChatModel; import org.ruoyi.common.chat.entity.chat.ChatModel;
import org.ruoyi.common.core.validate.AddGroup;
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;
@@ -28,16 +30,19 @@ public class ChatModelBo extends BaseEntity {
/** /**
* 模型分类 * 模型分类
*/ */
@NotBlank(message = "模型分类不能为空", groups = { AddGroup.class, EditGroup.class })
private String category; private String category;
/** /**
* 模型名称 * 模型名称
*/ */
@NotBlank(message = "模型名称不能为空", groups = { AddGroup.class, EditGroup.class })
private String modelName; private String modelName;
/** /**
* 模型供应商 * 模型供应商
*/ */
@NotBlank(message = "模型供应商不能为空", groups = { AddGroup.class, EditGroup.class })
private String providerCode; private String providerCode;
/** /**

View File

@@ -0,0 +1,30 @@
package org.ruoyi.common.chat.domain.bo.chat;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.ruoyi.common.mybatis.core.domain.BaseEntity;
/**
* 按厂商批量更新密钥业务对象
*
* @author ageerle
* @date 2025-12-14
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class ModelBatchKeyBo extends BaseEntity {
/**
* 模型供应商
*/
@NotBlank(message = "厂商编码不能为空")
private String providerCode;
/**
* 密钥
*/
@NotBlank(message = "密钥不能为空")
private String apiKey;
}

View File

@@ -1,6 +1,5 @@
package org.ruoyi.common.chat.domain.dto.request; package org.ruoyi.common.chat.domain.dto.request;
import com.alibaba.fastjson.annotation.JSONField;
import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import dev.langchain4j.data.message.ChatMessage; import dev.langchain4j.data.message.ChatMessage;
@@ -21,9 +20,18 @@ import java.util.List;
@Data @Data
public class ChatRequest { public class ChatRequest {
@NotEmpty(message = "传入的模型不能为空") /**
* 模型名称。
* 智能体模式下可缺省:传 agentId 时后端按智能体绑定的模型解析,此字段仅作回退。
*/
private String model; private String model;
/**
* 智能体ID。传入时后端按智能体配置解析模型/工具/技能/知识库/提示词/是否深度思考。
*/
@JsonSerialize(using = ToStringSerializer.class)
private Long agentId;
/** /**
* 对话消息 * 对话消息
*/ */
@@ -35,16 +43,6 @@ public class ChatRequest {
*/ */
private WorkFlowRunner workFlowRunner; private WorkFlowRunner workFlowRunner;
/**
* 人机交互信息体
*/
private ReSumeRunner reSumeRunner;
/**
* 是否为人机交互用户继续输入
*/
private Boolean isResume = false;
/** /**
* 是否启用工作流 * 是否启用工作流
*/ */
@@ -54,7 +52,6 @@ public class ChatRequest {
* 会话id * 会话id
*/ */
@JsonSerialize(using = ToStringSerializer.class) @JsonSerialize(using = ToStringSerializer.class)
@JSONField(serializeUsing = String.class)
private Long sessionId; private Long sessionId;
/** /**
@@ -71,7 +68,6 @@ public class ChatRequest {
* 对话id(每个聊天窗口都不一样) * 对话id(每个聊天窗口都不一样)
*/ */
@JsonSerialize(using = ToStringSerializer.class) @JsonSerialize(using = ToStringSerializer.class)
@JSONField(serializeUsing = String.class)
private Long uuid; private Long uuid;
/** /**

View File

@@ -1,19 +0,0 @@
package org.ruoyi.common.chat.domain.dto.request;
import lombok.Data;
/**
* 人机交互输入信息
*/
@Data
public class ReSumeRunner {
/**
* 运行节点UUID
*/
private String runtimeUuid;
/**
* 人机交互用户输入信息
*/
private String feedbackContent;
}

View File

@@ -0,0 +1,44 @@
package org.ruoyi.common.chat.entity.audio;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Builder;
import lombok.Data;
import org.ruoyi.common.chat.domain.vo.chat.ChatModelVo;
/**
* Text-to-speech context.
*/
@Data
@Builder
public class AudioContext {
@NotNull(message = "模型配置不能为空")
private ChatModelVo chatModelVo;
@NotBlank(message = "输入文本不能为空")
private String input;
private String voice;
private String responseFormat;
private Double speed;
private String instructions;
/** Atlas seed-audio 参考资源:[{speaker, audioUrl, audioData, imageData}]speaker 为音色名 */
private java.util.List<java.util.Map<String, String>> references;
/** Atlas seed-audio 采样率 */
private Integer sampleRate;
/** Atlas seed-audio 音调调整 (-12~12) */
private Integer pitchRate;
/** Atlas seed-audio 语速调整 (-50~100) */
private Integer speechRate;
/** Atlas seed-audio 响度调整 (-50~100) */
private Integer loudnessRate;
}

View File

@@ -42,4 +42,9 @@ public class ImageContext {
@Min(value = 0, message = "随机数种子不能小于0") @Min(value = 0, message = "随机数种子不能小于0")
@Max(value = 2147483647, message = "随机数种子不能大于2147483647") @Max(value = 2147483647, message = "随机数种子不能大于2147483647")
private Integer seed; private Integer seed;
/**
* 参考图 URL图生图用
*/
private String image;
} }

View File

@@ -0,0 +1,31 @@
package org.ruoyi.common.chat.entity.media;
import lombok.Builder;
import lombok.Data;
/**
* Unified media generation response.
*/
@Data
@Builder
public class MediaGenerationResponse {
private String type;
private String mimeType;
private String url;
private String b64Json;
private String dataUrl;
private String id;
private String status;
private String rawResponse;
/** 末帧图片 URLAtlas return_last_frame=true 时返回,用于下一镜首帧承接) */
private String lastFrameUrl;
}

View File

@@ -0,0 +1,47 @@
package org.ruoyi.common.chat.entity.video;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Builder;
import lombok.Data;
import org.ruoyi.common.chat.domain.vo.chat.ChatModelVo;
/**
* Text-to-video context.
*/
@Data
@Builder
public class VideoContext {
@NotNull(message = "模型配置不能为空")
private ChatModelVo chatModelVo;
@NotBlank(message = "提示词不能为空")
private String prompt;
private String size;
private Integer seconds;
private String quality;
/** 参考图 URL图生视频模式单图 */
private String imageUrl;
/** 多参考图 URL多参考图生视频模式配合 @imageN prompt 使用) */
private java.util.List<String> referenceImages;
/** 参考音频 URL 列表(对白口型对齐模式) */
private java.util.List<String> referenceAudios;
/** 是否让模型生成同步音频(环境音/动效) */
private Boolean generateAudio;
/** 是否要求返回末帧,用于下一镜首帧承接 */
private Boolean returnLastFrame;
/** 上一镜末帧 URL同场景连续镜头首帧承接用作为额外参考图传入 */
private String lastFrameUrl;
private String videoId;
}

View File

@@ -54,7 +54,6 @@ public enum ErrorEnum {
A_WF_RUNTIME_NOT_FOUND("A00045", "工作流运行时数据找不到"), A_WF_RUNTIME_NOT_FOUND("A00045", "工作流运行时数据找不到"),
A_SEARCH_QUERY_IS_EMPTY("A00046", "搜索内容不能为空"), A_SEARCH_QUERY_IS_EMPTY("A00046", "搜索内容不能为空"),
A_WF_COMPONENT_NOT_FOUND("A00047", "工作流基础组件找不到"), A_WF_COMPONENT_NOT_FOUND("A00047", "工作流基础组件找不到"),
A_WF_RESUME_FAIL("A00048", "工作流恢复执行时失败"),
A_MAIL_SENDER_EMPTY("A00049", "邮件发送人不能为空"), A_MAIL_SENDER_EMPTY("A00049", "邮件发送人不能为空"),
A_MAIL_SENDER_CONFIG_ERROR("A00050", "邮件发送人配置错误"), A_MAIL_SENDER_CONFIG_ERROR("A00050", "邮件发送人配置错误"),
A_MAIL_RECEIVER_EMPTY("A00051", "邮件接收人不能为空"), A_MAIL_RECEIVER_EMPTY("A00051", "邮件接收人不能为空"),

View File

@@ -0,0 +1,40 @@
package org.ruoyi.common.chat.factory;
import org.ruoyi.common.chat.service.audio.IAudioGenerationService;
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;
/**
* Text-to-speech service factory.
*/
@Component
public class AudioServiceFactory implements ApplicationContextAware {
private final Map<String, IAudioGenerationService> audioServiceMap = new ConcurrentHashMap<>();
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
Map<String, IAudioGenerationService> serviceMap = applicationContext.getBeansOfType(IAudioGenerationService.class);
for (IAudioGenerationService service : serviceMap.values()) {
if (service != null) {
audioServiceMap.put(service.getProviderName(), service);
}
}
}
public IAudioGenerationService getOriginalService(String providerCode) {
IAudioGenerationService service = audioServiceMap.get(providerCode);
if (service == null && "custom_api".equals(providerCode)) {
service = audioServiceMap.get("openai");
}
if (service == null) {
throw new IllegalArgumentException("不支持的语音模型供应商: " + providerCode);
}
return service;
}
}

View File

@@ -37,6 +37,9 @@ public class ImageServiceFactory implements ApplicationContextAware {
*/ */
public IImageGenerationService getOriginalService(String category) { public IImageGenerationService getOriginalService(String category) {
IImageGenerationService service = imageSerivceMap.get(category); IImageGenerationService service = imageSerivceMap.get(category);
if (service == null && "custom_api".equals(category)) {
service = imageSerivceMap.get("openai");
}
if (service == null) { if (service == null) {
throw new IllegalArgumentException("不支持的模型类别: " + category); throw new IllegalArgumentException("不支持的模型类别: " + category);
} }

Some files were not shown because too many files have changed in this diff Show More