diff --git a/README.md b/README.md index cb2bc533..ab58ac7a 100644 --- a/README.md +++ b/README.md @@ -18,19 +18,20 @@ RuoYi AI Logo - - ### 企业级AI助手平台 *开箱即用的智能AI平台,深度集成 FastGPT、扣子(Coze)、DIFY 等主流AI平台,提供先进的RAG技术、知识图谱、数字人和AI流程编排能力* -**[🇺🇸 English](README_EN.md)** | **[📖 使用文档](https://doc.pandarobot.chat)** | **[🚀 在线体验](https://web.pandarobot.chat)** | **[🐛 问题反馈](https://github.com/ageerle/ruoyi-ai/issues)** | **[💡 功能建议](https://github.com/ageerle/ruoyi-ai/issues)** +**[🇺🇸 English](README_EN.md)** | **[📖 使用文档](https://doc.pandarobot.chat)** | * +*[🚀 在线体验](https://web.pandarobot.chat)** | **[🐛 问题反馈](https://github.com/ageerle/ruoyi-ai/issues)** | * +*[💡 功能建议](https://github.com/ageerle/ruoyi-ai/issues)** ## ✨ 核心亮点 ### 智能AI引擎 + - **多模型接入**:支持 OpenAI GPT-4、Azure、ChatGLM、通义千问、智谱AI 等主流模型 - **AI平台集成**:深度集成 **FastGPT**、**扣子(Coze)**、**DIFY** 等主流AI应用平台 - **Spring AI MCP 集成**:基于模型上下文协议,打造可扩展的AI工具生态系统 @@ -38,60 +39,64 @@ - **AI 编程助手**:内置智能代码分析和项目脚手架生成能力 ### AI平台生态集成 + - **FastGPT 深度集成**:原生支持 FastGPT API,包括知识库检索、工作流编排和上下文管理 - **扣子(Coze) 官方SDK**:集成字节跳动扣子平台官方SDK,支持Bot对话和流式响应 - **DIFY 完整兼容**:使用 DIFY Java Client,支持应用编排、工作流和知识库管理 - **统一聊天接口**:提供统一的聊天服务接口,支持多平台无缝切换和负载均衡 ### 本地化RAG方案 + - **私有知识库**:基于 Langchain4j 框架 + BGE-large-zh-v1.5 中文向量模型 - **多种向量库**:支持 Milvus、Weaviate、Qdrant 等主流向量数据库 - **数据安全可控**:支持完全本地部署,保护企业数据隐私 - **灵活模型部署**:兼容 Ollama、vLLM 等本地推理框架 ### AI创作工具 + - **AI 绘画创作**:深度集成 DALL·E-3、MidJourney、Stable Diffusion - **智能PPT生成**:一键将文本内容转换为精美演示文稿 - **多模态理解**:支持文本、图片、文档等多种格式的智能处理 ### 知识图谱与智能编排 + - **知识图谱构建**:自动从文档和对话中提取实体关系,构建可视化知识网络 - **AI 流程编排**:可视化工作流设计器,支持复杂AI任务的编排和自动化执行 - **数字人交互**:集成数字人形象,提供更自然的人机交互体验 - **智能推理引擎**:基于知识图谱的智能推理和问答能力 - - ## 🚀 快速体验 ### 在线演示 + - **用户端体验**:[web.pandarobot.chat](https://web.pandarobot.chat) (账号:admin 密码:admin123) - **管理后台**:[admin.pandarobot.chat](https://admin.pandarobot.chat) (账号:admin 密码:admin123) ### 项目源码 -| 项目模块 | 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) | + +| 项目模块 | 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) | ### 合作项目 -| 项目介绍 | GitHub 仓库 | Gitee 仓库 | -|:--------:|:----------:|:----------:| + +| 项目介绍 | GitHub 仓库 | Gitee 仓库 | +|:-----:|:----------------------------------------------------------------------:|:----------------------------------------------------------------:| | 前端简化版 | [ruoyi-element-ai](https://github.com/element-plus-x/ruoyi-element-ai) | [ruoyi-element-ai](https://gitee.com/he-jiayue/ruoyi-element-ai) | - - - ## 🛠️ 技术架构 ### 核心框架 + - **后端架构**:Spring Boot 3.4 + Spring AI + Langchain4j - **数据存储**:MySQL 8.0 + Redis + 向量数据库(Milvus/Weaviate/Qdrant) - **前端技术**:Vue 3 + Vben Admin + Naive UI - **安全认证**:Sa-Token + JWT 双重保障 ### 系统组件 + - **文档处理**:PDF、Word、Excel 解析,图像智能分析 - **实时通信**:WebSocket 实时通信,SSE 流式响应 - **系统监控**:完善的日志体系、性能监控、服务健康检查 @@ -107,6 +112,7 @@ 我们热烈欢迎社区贡献!无论您是资深开发者还是初学者,都可以为项目贡献力量 💪 ### 贡献方式 + 1. **Fork** 项目到您的账户 2. **创建分支** (`git checkout -b feature/新功能名称`) 3. **提交代码** (`git commit -m '添加某某功能'`) @@ -123,7 +129,8 @@ 感谢以下优秀的开源项目为本项目提供支持: -- [Spring AI Alibaba Copilot](https://github.com/springaialibaba/spring-ai-alibaba-copilot) - 基于spring-ai-alibaba 的智能编码助手 +- [Spring AI Alibaba Copilot](https://github.com/springaialibaba/spring-ai-alibaba-copilot) - 基于spring-ai-alibaba + 的智能编码助手 - [Spring AI](https://spring.io/projects/spring-ai) - Spring 官方 AI 集成框架 - [Langchain4j](https://github.com/langchain4j/langchain4j) - 强大的 Java LLM 开发框架 - [RuoYi-Vue-Plus](https://gitee.com/dromara/RuoYi-Vue-Plus) - 成熟的企业级快速开发框架 @@ -132,7 +139,8 @@ ## 🌐 生态伙伴 -- [PPIO 派欧云](https://ppinfra.com/user/register?invited_by=P8QTUY&utm_source=github_ruoyi-ai) - 提供高性价比的 GPU 算力和模型 API 服务 +- [PPIO 派欧云](https://ppinfra.com/user/register?invited_by=P8QTUY&utm_source=github_ruoyi-ai) - 提供高性价比的 GPU + 算力和模型 API 服务 - [优云智算](https://www.compshare.cn/?ytag=GPU_YY-gh_ruoyi) - 万卡RTX40系GPU+海内外主流模型API服务,秒级响应,按量计费,新客免费用。 - [胜算云](https://www.shengsuanyun.com/?from=CH_3WG71ZOS) - AI模型算力聚合超市云服务。 @@ -162,20 +170,32 @@
-**[⭐ 点个Star支持一下](https://github.com/ageerle/ruoyi-ai)** • **[🍴 Fork 开始贡献](https://github.com/ageerle/ruoyi-ai/fork)** • **[📚 English](README_EN.md)** • **[📖 查看完整文档](https://doc.pandarobot.chat)** +**[⭐ 点个Star支持一下](https://github.com/ageerle/ruoyi-ai)** • * +*[🍴 Fork 开始贡献](https://github.com/ageerle/ruoyi-ai/fork)** • **[📚 English](README_EN.md)** • * +*[📖 查看完整文档](https://doc.pandarobot.chat)** *用 ❤️ 打造,由 RuoYi AI 开源社区维护*
+ [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 diff --git a/README_EN.md b/README_EN.md index 64613d06..a7b727f4 100644 --- a/README_EN.md +++ b/README_EN.md @@ -1,4 +1,3 @@ - # RuoYi AI
@@ -13,16 +12,19 @@ ### Enterprise-Grade AI Assistant Platform -*Production-ready AI platform with deep integration of FastGPT, Coze, DIFY, featuring advanced RAG technology, knowledge graphs, digital humans, and AI workflow orchestration* +*Production-ready AI platform with deep integration of FastGPT, Coze, DIFY, featuring advanced RAG technology, knowledge +graphs, digital humans, and AI workflow orchestration* -**[📖 中文文档](README.md)** | **[📚 Documentation](https://doc.pandarobot.chat)** | **[🚀 Live Demo](https://web.pandarobot.chat)** | **[🐛 Report Bug](https://github.com/ageerle/ruoyi-ai/issues)** | **[💡 Request Feature](https://github.com/ageerle/ruoyi-ai/issues)** +**[📖 中文文档](README.md)** | **[📚 Documentation](https://doc.pandarobot.chat)** | * +*[🚀 Live Demo](https://web.pandarobot.chat)** | **[🐛 Report Bug](https://github.com/ageerle/ruoyi-ai/issues)** | * +*[💡 Request Feature](https://github.com/ageerle/ruoyi-ai/issues)**
- ## ✨ Key Features ### 🤖 Advanced AI Engine + - **Multi-Model Support**: OpenAI GPT-4, Azure, ChatGLM, Qwen, ZhipuAI - **AI Platform Integration**: Deep integration with **FastGPT**, **Coze**, **DIFY** and other leading AI platforms - **Spring AI MCP Integration**: Extensible tool ecosystem with Model Context Protocol @@ -30,58 +32,69 @@ - **AI Copilot**: Intelligent code analysis and project scaffolding ### 🌟 AI Platform Ecosystem -- **FastGPT Deep Integration**: Native FastGPT API support with knowledge base retrieval, workflow orchestration and context management -- **Coze Official SDK**: Integration with ByteDance Coze platform official SDK, supporting Bot conversations and streaming responses + +- **FastGPT Deep Integration**: Native FastGPT API support with knowledge base retrieval, workflow orchestration and + context management +- **Coze Official SDK**: Integration with ByteDance Coze platform official SDK, supporting Bot conversations and + streaming responses - **DIFY Full Compatibility**: Using DIFY Java Client for app orchestration, workflows and knowledge base management -- **Unified Chat Interface**: Standardized chat service interface supporting seamless platform switching and load balancing +- **Unified Chat Interface**: Standardized chat service interface supporting seamless platform switching and load + balancing ### 🧠 Enterprise RAG Solution + - **Local Knowledge Base**: Langchain4j + BGE-large-zh-v1.5 embeddings - **Vector Database Support**: Milvus, Weaviate, Qdrant - **Privacy-First**: On-premise deployment with local LLM support - **Ollama & vLLM Compatible**: Flexible model deployment options ### 🎨 Creative AI Tools + - **AI Art Generation**: DALL·E-3, MidJourney, Stable Diffusion integration - **PPT Creation**: Automated slide generation from text input - **Multi-Modal Processing**: Text, image, and document understanding ### 🧩 Knowledge Graph & Intelligent Orchestration -- **Knowledge Graph Construction**: Automatically extract entities and relationships from documents and conversations to build visual knowledge networks -- **AI Workflow Orchestration**: Visual workflow designer supporting complex AI task orchestration and automated execution + +- **Knowledge Graph Construction**: Automatically extract entities and relationships from documents and conversations to + build visual knowledge networks +- **AI Workflow Orchestration**: Visual workflow designer supporting complex AI task orchestration and automated + execution - **Digital Human Interaction**: Integrated digital human avatars for more natural human-computer interaction - **Intelligent Reasoning Engine**: Knowledge graph-based intelligent reasoning and Q&A capabilities - - ## 🚀 Quick Start ### Live Demo + - **User Portal**: [web.pandarobot.chat](https://web.pandarobot.chat) (demo/demo123) - **Admin Panel**: [admin.pandarobot.chat](https://admin.pandarobot.chat) (admin/admin123) ### Source Code -| Component | GitHub | Gitee | GitCode | -|-----------|--------|-------|---------| -| Backend API | [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) | + +| Component | GitHub | Gitee | GitCode | +|----------------|-------------------------------------------------------|------------------------------------------------------|--------------------------------------------------------| +| Backend API | [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 Frontend | [ruoyi-admin](https://github.com/ageerle/ruoyi-admin) | [ruoyi-admin](https://gitee.com/ageerle/ruoyi-admin) | [ruoyi-admin](https://gitcode.com/ageerle/ruoyi-admin) | ### Collaborative Projects -| Project Description | GitHub Repository | Gitee Repository | -|:-------------------:|:-----------------:|:----------------:| -| Simplified Frontend | [ruoyi-element-ai](https://github.com/element-plus-x/ruoyi-element-ai) | [ruoyi-element-ai](https://gitee.com/he-jiayue/ruoyi-element-ai) | +| Project Description | GitHub Repository | Gitee Repository | +|:-------------------:|:----------------------------------------------------------------------:|:----------------------------------------------------------------:| +| Simplified Frontend | [ruoyi-element-ai](https://github.com/element-plus-x/ruoyi-element-ai) | [ruoyi-element-ai](https://gitee.com/he-jiayue/ruoyi-element-ai) | ## 🛠️ Tech Stack ### Core Framework + - **Backend**: Spring Boot 3.4, Spring AI, Langchain4j - **Database**: MySQL 8.0, Redis, Vector Databases (Milvus/Weaviate/Qdrant) - **Frontend**: Vue 3, Vben Admin, Naive UI - **Authentication**: Sa-Token, JWT ### System Components + - **File Processing**: PDF, Word, Excel parsing, intelligent image analysis - **Real-time Communication**: WebSocket real-time communication, SSE streaming - **System Monitoring**: Comprehensive logging, performance monitoring, health checks @@ -94,9 +107,11 @@ For detailed setup, configuration, and development guides, visit our comprehensi ## 🤝 Contributing -We welcome contributions from developers of all skill levels! Whether you're fixing bugs, adding features, or improving documentation, your help is appreciated. +We welcome contributions from developers of all skill levels! Whether you're fixing bugs, adding features, or improving +documentation, your help is appreciated. ### How to Contribute + 1. Fork the repository 2. Create your feature branch (`git checkout -b feature/amazing-feature`) 3. Commit your changes (`git commit -m 'Add amazing feature'`) @@ -109,12 +124,12 @@ We welcome contributions from developers of all skill levels! Whether you're fix This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. - ## 🙏 Acknowledgments Special thanks to these amazing open source projects: -- [Spring AI Alibaba Copilot](https://github.com/springaialibaba/spring-ai-alibaba-copilot) - Intelligent coding assistant based on spring-ai-alibaba with MCP protocol integration for project analysis and code generation +- [Spring AI Alibaba Copilot](https://github.com/springaialibaba/spring-ai-alibaba-copilot) - Intelligent coding + assistant based on spring-ai-alibaba with MCP protocol integration for project analysis and code generation - [Spring AI](https://spring.io/projects/spring-ai) - Spring's AI integration framework - [Langchain4j](https://github.com/langchain4j/langchain4j) - Java LLM framework - [RuoYi-Vue-Plus](https://gitee.com/dromara/RuoYi-Vue-Plus) - Enterprise development framework @@ -123,7 +138,8 @@ Special thanks to these amazing open source projects: ## 🌐 Ecosystem Partners -- [PPIO Cloud](https://ppinfra.com/user/register?invited_by=P8QTUY&utm_source=github_ruoyi-ai) - Cost-effective GPU containers and model APIs +- [PPIO Cloud](https://ppinfra.com/user/register?invited_by=P8QTUY&utm_source=github_ruoyi-ai) - Cost-effective GPU + containers and model APIs ## 💬 Community @@ -150,22 +166,33 @@ Special thanks to these amazing open source projects:
-**[⭐ Star this repo](https://github.com/ageerle/ruoyi-ai)** • **[🍴 Fork it](https://github.com/ageerle/ruoyi-ai/fork)** • **[📖 中文文档](README.md)** • **[📚 Documentation](https://doc.pandarobot.chat)** +**[⭐ Star this repo](https://github.com/ageerle/ruoyi-ai)** • **[🍴 Fork it](https://github.com/ageerle/ruoyi-ai/fork) +** • **[📖 中文文档](README.md)** • **[📚 Documentation](https://doc.pandarobot.chat)** *Built with ❤️ by the RuoYi AI community*
+ [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 diff --git a/docs/RuoYi-AI 后端部署教程(Docker 部署版).md b/docs/RuoYi-AI 后端部署教程(Docker 部署版).md index 09acee57..fa87d09a 100644 --- a/docs/RuoYi-AI 后端部署教程(Docker 部署版).md +++ b/docs/RuoYi-AI 后端部署教程(Docker 部署版).md @@ -78,7 +78,7 @@ mkdir logs minio minio-config mysql redis weaviate - `Dockerfile` > 📂 这些文件在项目目录 `/script/deploy/deploy` 下。 -> 上传后请检查文件路径是否与上方目录结构一致。 +> 上传后请检查文件路径是否与上方目录结构一致。 ------ @@ -88,7 +88,7 @@ mkdir logs minio minio-config mysql redis weaviate 2. 选择 **Maven 构建配置**,勾选 `prod` 环境,取消 `dev` 环境 3. 点击 `package` 进行打包 4. **注意:** 在构建前请将 `application-prod.yml` 拖入 - `ruoyi-admin/src/main/resources` 目录中 + `ruoyi-admin/src/main/resources` 目录中 构建完成后会在: @@ -103,7 +103,7 @@ ruoyi-admin/target/ruoyi-admin.jar ### 五、上传 Jar 包至服务器 将生成的 `ruoyi-admin.jar` 上传到服务器 `/ruoyi-ai/deploy` 目录下。 - 确保与 `Dockerfile` 同目录。 +确保与 `Dockerfile` 同目录。 ------ @@ -194,13 +194,13 @@ source /docker-entrypoint-initdb.d/ruoyi-ai.sql; ### 九、常用 Docker 命令 -| 功能 | 命令 | -| ----------------- | --------------------------------- | -| 查看容器状态 | `docker ps -a` | -| 查看日志 | `docker logs -f <容器名>` | -| 停止服务 | `docker compose down` | -| 重启服务 | `docker compose restart` | -| 重新构建镜像 | `docker compose build --no-cache` | +| 功能 | 命令 | +|-----------|-----------------------------------| +| 查看容器状态 | `docker ps -a` | +| 查看日志 | `docker logs -f <容器名>` | +| 停止服务 | `docker compose down` | +| 重启服务 | `docker compose restart` | +| 重新构建镜像 | `docker compose build --no-cache` | | 清理无用镜像/容器 | `docker system prune -a` | ------ diff --git a/docs/工作流模块说明.md b/docs/工作流模块说明.md index 8d2f4396..f51e3fe4 100644 --- a/docs/工作流模块说明.md +++ b/docs/工作流模块说明.md @@ -2,7 +2,8 @@ ## 概述 -Ruoyi-AI 工作流模块是一个基于 LangGraph4j 的智能工作流引擎,支持可视化工作流设计、AI 模型集成、条件分支、人机交互等高级功能。该模块采用微服务架构,提供完整的 RESTful API 和流式响应支持。 +Ruoyi-AI 工作流模块是一个基于 LangGraph4j 的智能工作流引擎,支持可视化工作流设计、AI 模型集成、条件分支、人机交互等高级功能。该模块采用微服务架构,提供完整的 +RESTful API 和流式响应支持。 ## 模块架构 @@ -48,12 +49,14 @@ ruoyi-ai/ ### 1. 工作流管理 #### 1.1 工作流定义 + - **创建工作流**: 支持自定义标题、描述、公开性设置 - **编辑工作流**: 可视化节点编辑、连接线配置 - **版本控制**: 支持工作流的版本管理和回滚 - **权限管理**: 支持公开/私有工作流设置 #### 1.2 工作流执行 + - **流式执行**: 基于 SSE 的实时流式响应 - **状态管理**: 完整的执行状态跟踪 - **错误处理**: 详细的错误信息和异常处理 @@ -62,26 +65,31 @@ ruoyi-ai/ ### 2. 节点类型 #### 2.1 基础节点 + - **Start**: 开始节点,定义工作流入口 - **End**: 结束节点,定义工作流出口 #### 2.2 AI 模型节点 + - **Answer**: 大语言模型问答节点 - **Dalle3**: DALL-E 3 图像生成 - **Tongyiwanx**: 通义万相图像生成 - **Classifier**: 内容分类节点 #### 2.3 数据处理节点 + - **DocumentExtractor**: 文档信息提取 - **KeywordExtractor**: 关键词提取 - **FaqExtractor**: 常见问题提取 - **KnowledgeRetrieval**: 知识库检索 #### 2.4 控制流节点 + - **Switcher**: 条件分支节点 - **HumanFeedback**: 人机交互节点 #### 2.5 外部集成节点 + - **Google**: Google 搜索集成 - **MailSend**: 邮件发送 - **HttpRequest**: HTTP 请求 @@ -90,6 +98,7 @@ ruoyi-ai/ ### 3. 数据流管理 #### 3.1 输入输出定义 + ```java // 节点输入输出数据结构 public class NodeIOData { @@ -108,6 +117,7 @@ public enum WfIODataTypeEnum { ``` #### 3.2 参数引用 + - **节点间引用**: 支持上游节点输出作为下游节点输入 - **参数映射**: 自动处理参数名称映射 - **类型转换**: 自动进行数据类型转换 @@ -117,6 +127,7 @@ public enum WfIODataTypeEnum { ### 1. 核心表结构 #### 1.1 工作流定义表 (t_workflow) + ```sql CREATE TABLE t_workflow ( id BIGINT AUTO_INCREMENT PRIMARY KEY, @@ -133,6 +144,7 @@ CREATE TABLE t_workflow ( ``` #### 1.2 工作流节点表 (t_workflow_node) + ```sql CREATE TABLE t_workflow_node ( id BIGINT AUTO_INCREMENT PRIMARY KEY, @@ -153,6 +165,7 @@ CREATE TABLE t_workflow_node ( ``` #### 1.3 工作流边表 (t_workflow_edge) + ```sql CREATE TABLE t_workflow_edge ( id BIGINT AUTO_INCREMENT PRIMARY KEY, @@ -168,6 +181,7 @@ CREATE TABLE t_workflow_edge ( ``` #### 1.4 工作流运行时表 (t_workflow_runtime) + ```sql CREATE TABLE t_workflow_runtime ( id BIGINT AUTO_INCREMENT PRIMARY KEY, @@ -185,6 +199,7 @@ CREATE TABLE t_workflow_runtime ( ``` #### 1.5 工作流组件表 (t_workflow_component) + ```sql CREATE TABLE t_workflow_component ( id BIGINT AUTO_INCREMENT PRIMARY KEY, @@ -205,6 +220,7 @@ CREATE TABLE t_workflow_component ( ### 1. 工作流管理接口 #### 1.1 基础操作 + ```http # 创建工作流 POST /workflow/add @@ -232,6 +248,7 @@ POST /workflow/enable/{uuid}?enable=true ``` #### 1.2 搜索和查询 + ```http # 搜索我的工作流 GET /workflow/mine/search?keyword=关键词&isPublic=true¤tPage=1&pageSize=10 @@ -246,6 +263,7 @@ GET /workflow/public/component/list ### 2. 工作流执行接口 #### 2.1 流式执行 + ```http # 流式执行工作流 POST /workflow/run @@ -266,6 +284,7 @@ Accept: text/event-stream ``` #### 2.2 运行时管理 + ```http # 恢复中断的工作流 POST /workflow/runtime/resume/{runtimeUuid} @@ -287,6 +306,7 @@ POST /workflow/runtime/clear?wfUuid=工作流UUID ### 3. 管理端接口 #### 3.1 工作流管理 + ```http # 搜索所有工作流 POST /admin/workflow/search @@ -306,6 +326,7 @@ POST /admin/workflow/enable?uuid=工作流UUID&isEnable=true ### 1. 工作流引擎 (WorkflowEngine) 工作流引擎是整个模块的核心,负责: + - 工作流图的构建和编译 - 节点执行调度 - 状态管理和持久化 @@ -399,7 +420,6 @@ public class WorkflowGraphBuilder { 4. **状态更新**: 实时更新节点和工作流状态 5. **错误处理**: 捕获并处理执行过程中的错误 - ## 扩展开发 ### 1. 自定义节点开发 diff --git a/pom.xml b/pom.xml index 3bbcab6d..8439bf77 100644 --- a/pom.xml +++ b/pom.xml @@ -1,6 +1,6 @@ - 4.0.0 diff --git a/ruoyi-admin/pom.xml b/ruoyi-admin/pom.xml index 95898d4d..07143c31 100644 --- a/ruoyi-admin/pom.xml +++ b/ruoyi-admin/pom.xml @@ -1,6 +1,6 @@ - ruoyi-ai diff --git a/ruoyi-admin/src/main/java/org/ruoyi/controller/AuthController.java b/ruoyi-admin/src/main/java/org/ruoyi/controller/AuthController.java index e9884c62..56fe0fa2 100644 --- a/ruoyi-admin/src/main/java/org/ruoyi/controller/AuthController.java +++ b/ruoyi-admin/src/main/java/org/ruoyi/controller/AuthController.java @@ -81,6 +81,7 @@ public class AuthController { /** * 访客登录 + * * @param loginBody 登录信息 * @return token信息 */ @@ -119,7 +120,7 @@ public class AuthController { */ @PostMapping("/register") public R register(@Validated @RequestBody RegisterBody user, HttpServletRequest request) { - String domainName = request.getServerName(); + String domainName = request.getServerName(); user.setDomainName(domainName); registerService.register(user); return R.ok(); diff --git a/ruoyi-admin/src/main/java/org/ruoyi/controller/IndexController.java b/ruoyi-admin/src/main/java/org/ruoyi/controller/IndexController.java index 4fdbc979..513dbb6b 100644 --- a/ruoyi-admin/src/main/java/org/ruoyi/controller/IndexController.java +++ b/ruoyi-admin/src/main/java/org/ruoyi/controller/IndexController.java @@ -22,5 +22,4 @@ public class IndexController { } - } diff --git a/ruoyi-admin/src/main/resources/application-dev.yml b/ruoyi-admin/src/main/resources/application-dev.yml index fe414118..e952157f 100644 --- a/ruoyi-admin/src/main/resources/application-dev.yml +++ b/ruoyi-admin/src/main/resources/application-dev.yml @@ -1,4 +1,3 @@ - --- # 数据源配置 spring: datasource: diff --git a/ruoyi-admin/src/main/resources/logback-plus.xml b/ruoyi-admin/src/main/resources/logback-plus.xml index 40fa33b7..18ab7cdd 100644 --- a/ruoyi-admin/src/main/resources/logback-plus.xml +++ b/ruoyi-admin/src/main/resources/logback-plus.xml @@ -98,32 +98,32 @@ - - - - - - - - + + + + + + + + - - - - - - - - + + + + + + + + - - - - - + + + + + diff --git a/ruoyi-common/pom.xml b/ruoyi-common/pom.xml index 3c7018bf..acd01511 100644 --- a/ruoyi-common/pom.xml +++ b/ruoyi-common/pom.xml @@ -1,6 +1,6 @@ - 4.0.0 diff --git a/ruoyi-common/ruoyi-common-bom/pom.xml b/ruoyi-common/ruoyi-common-bom/pom.xml index 0094d7e7..dd0b8f1d 100644 --- a/ruoyi-common/ruoyi-common-bom/pom.xml +++ b/ruoyi-common/ruoyi-common-bom/pom.xml @@ -1,6 +1,6 @@ - 4.0.0 diff --git a/ruoyi-common/ruoyi-common-chat/pom.xml b/ruoyi-common/ruoyi-common-chat/pom.xml index b701e53b..1463203f 100644 --- a/ruoyi-common/ruoyi-common-chat/pom.xml +++ b/ruoyi-common/ruoyi-common-chat/pom.xml @@ -1,6 +1,6 @@ - org.ruoyi diff --git a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/config/LocalCache.java b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/config/LocalCache.java index c8d05595..3fe71588 100644 --- a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/config/LocalCache.java +++ b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/config/LocalCache.java @@ -6,7 +6,6 @@ import cn.hutool.core.date.DateUnit; import lombok.extern.slf4j.Slf4j; /** - * * @author https:www.unfbx.com * @date 2023-03-10 */ @@ -16,16 +15,14 @@ public class LocalCache { * 缓存时长 */ public static final long TIMEOUT = 30 * DateUnit.MINUTE.getMillis(); - /** - * 清理间隔 - */ - private static final long CLEAN_TIMEOUT = 30 * DateUnit.MINUTE.getMillis(); - /** * 缓存对象 */ public static final TimedCache CACHE = CacheUtil.newTimedCache(TIMEOUT); - + /** + * 清理间隔 + */ + private static final long CLEAN_TIMEOUT = 30 * DateUnit.MINUTE.getMillis(); static { //启动定时任务 diff --git a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/config/WebSocketConfig.java b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/config/WebSocketConfig.java index f9242c66..9e3f35ed 100644 --- a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/config/WebSocketConfig.java +++ b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/config/WebSocketConfig.java @@ -39,10 +39,10 @@ public class WebSocketConfig { } // 返回一个WebSocketConfigurer对象,用于配置WebSocket return registry -> registry - // 添加WebSocket处理程序和拦截器到指定路径,设置允许的跨域来源 - .addHandler(webSocketHandler, webSocketProperties.getPath()) - .addInterceptors(handshakeInterceptor) - .setAllowedOrigins(webSocketProperties.getAllowedOrigins()); + // 添加WebSocket处理程序和拦截器到指定路径,设置允许的跨域来源 + .addHandler(webSocketHandler, webSocketProperties.getPath()) + .addInterceptors(handshakeInterceptor) + .setAllowedOrigins(webSocketProperties.getAllowedOrigins()); } @Bean diff --git a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/config/properties/WebSocketProperties.java b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/config/properties/WebSocketProperties.java index 7567fc9e..c5106c2b 100644 --- a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/config/properties/WebSocketProperties.java +++ b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/config/properties/WebSocketProperties.java @@ -23,7 +23,7 @@ public class WebSocketProperties { private String path; /** - * 设置访问源地址 + * 设置访问源地址 */ private String allowedOrigins; } diff --git a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/constant/OpenAIConst.java b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/constant/OpenAIConst.java index 4c673740..77c6a485 100644 --- a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/constant/OpenAIConst.java +++ b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/constant/OpenAIConst.java @@ -1,9 +1,8 @@ package org.ruoyi.common.chat.constant; /** - * * @author https:www.unfbx.com - * @since 2023-03-06 + * @since 2023-03-06 */ public class OpenAIConst { diff --git a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/billing/Datum.java b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/billing/Datum.java index ed4b5aec..9aeb7ca4 100644 --- a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/billing/Datum.java +++ b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/billing/Datum.java @@ -7,7 +7,6 @@ import lombok.Data; import java.math.BigDecimal; /** - * * @author https:www.unfbx.com * @since 2023-03-18 */ diff --git a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/billing/Grants.java b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/billing/Grants.java index 25445fcc..0cc034e8 100644 --- a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/billing/Grants.java +++ b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/billing/Grants.java @@ -7,7 +7,6 @@ import lombok.Data; import java.util.List; /** - * * @author https:www.unfbx.com * @since 2023-03-18 */ diff --git a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/billing/Plan.java b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/billing/Plan.java index 5f7e6468..f1940139 100644 --- a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/billing/Plan.java +++ b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/billing/Plan.java @@ -4,9 +4,8 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import lombok.Data; /** - * * @author https:www.unfbx.com - * @since 2023-04-08 + * @since 2023-04-08 */ @Data @JsonIgnoreProperties(ignoreUnknown = true) diff --git a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/billing/Subscription.java b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/billing/Subscription.java index 53619864..eb970a30 100644 --- a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/billing/Subscription.java +++ b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/billing/Subscription.java @@ -7,7 +7,7 @@ import lombok.Data; * 账户信息 * * @author https:www.unfbx.com - * @since 2023-04-08 + * @since 2023-04-08 */ @Data public class Subscription { diff --git a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/chat/BaseMessage.java b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/chat/BaseMessage.java index cf100792..983602f0 100644 --- a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/chat/BaseMessage.java +++ b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/chat/BaseMessage.java @@ -12,7 +12,6 @@ import java.io.Serializable; import java.util.List; /** - * * @author https:www.unfbx.com * @since 1.1.2 * 2023-03-02 @@ -34,6 +33,7 @@ public class BaseMessage implements Serializable { /** * The tool calls generated by the model, such as function calls. + * * @since 1.1.2 */ @JsonProperty("tool_calls") diff --git a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/chat/ChatChoice.java b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/chat/ChatChoice.java index d0c3f140..8340482c 100644 --- a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/chat/ChatChoice.java +++ b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/chat/ChatChoice.java @@ -7,7 +7,6 @@ import lombok.Data; import java.io.Serializable; /** - * * @author https:www.unfbx.com * @since 2023-03-02 */ diff --git a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/chat/ChatCompletionWithPicture.java b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/chat/ChatCompletionWithPicture.java index bc4c5782..64e84406 100644 --- a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/chat/ChatCompletionWithPicture.java +++ b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/chat/ChatCompletionWithPicture.java @@ -11,7 +11,7 @@ import java.io.Serializable; import java.util.List; /** - * : chat模型附带图片的参数 + * : chat模型附带图片的参数 * * @author https:www.unfbx.com * @since 1.1.2 diff --git a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/chat/Content.java b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/chat/Content.java index 0abe01f7..ecffd20d 100644 --- a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/chat/Content.java +++ b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/chat/Content.java @@ -6,7 +6,6 @@ import lombok.*; import lombok.extern.slf4j.Slf4j; /** - * * @author https://www.unfbx.com * @since 1.1.2 * 2023-11-10 diff --git a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/chat/FastGPTAnswerResponse.java b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/chat/FastGPTAnswerResponse.java index 856bec81..1673ca52 100644 --- a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/chat/FastGPTAnswerResponse.java +++ b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/chat/FastGPTAnswerResponse.java @@ -4,6 +4,7 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import lombok.Data; import java.util.List; + @Data @JsonIgnoreProperties(ignoreUnknown = true) public class FastGPTAnswerResponse { diff --git a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/chat/Functions.java b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/chat/Functions.java index b65e0f4a..8b726a6f 100644 --- a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/chat/Functions.java +++ b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/chat/Functions.java @@ -24,8 +24,9 @@ import java.io.Serializable; * }, * } * + * * @author https:www.unfbx.com - * @since 2023-06-14 + * @since 2023-06-14 */ @Data @Builder diff --git a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/chat/ImageUrl.java b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/chat/ImageUrl.java index 749b9c97..a15f7e24 100644 --- a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/chat/ImageUrl.java +++ b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/chat/ImageUrl.java @@ -8,7 +8,6 @@ import lombok.NoArgsConstructor; import lombok.extern.slf4j.Slf4j; /** - * * @author https://www.unfbx.com * 2023-11-10 */ diff --git a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/chat/Message.java b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/chat/Message.java index 40ef481f..d49279f8 100644 --- a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/chat/Message.java +++ b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/chat/Message.java @@ -10,8 +10,6 @@ import java.io.Serializable; import java.util.List; /** - * - * * @author https:www.unfbx.com * @since 2023-03-02 */ @@ -24,10 +22,6 @@ public class Message extends BaseMessage implements Serializable { @JsonProperty("reasoning_content") private String reasoningContent; - public static Builder builder() { - return new Builder(); - } - /** * 构造函数 * @@ -57,6 +51,10 @@ public class Message extends BaseMessage implements Serializable { super.setToolCallId(builder.toolCallId); } + public static Builder builder() { + return new Builder(); + } + public static final class Builder { private String role; private String content; diff --git a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/chat/MessagePicture.java b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/chat/MessagePicture.java index db7d77c4..69fb9be1 100644 --- a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/chat/MessagePicture.java +++ b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/chat/MessagePicture.java @@ -25,10 +25,6 @@ public class MessagePicture extends BaseMessage implements Serializable { private List content; - public static Builder builder() { - return new Builder(); - } - /** * 构造函数 * @@ -58,6 +54,10 @@ public class MessagePicture extends BaseMessage implements Serializable { super.setToolCallId(builder.toolCallId); } + public static Builder builder() { + return new Builder(); + } + public static final class Builder { private String role; private List content; diff --git a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/chat/Parameters.java b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/chat/Parameters.java index 7a015357..abd16ac5 100644 --- a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/chat/Parameters.java +++ b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/chat/Parameters.java @@ -5,8 +5,9 @@ import lombok.Data; import java.io.Serializable; import java.util.List; + /** - * 方法参数类,扩展参数可以继承Parameters自己实现 + * 方法参数类,扩展参数可以继承Parameters自己实现 * 参考: *
  * {
@@ -21,8 +22,9 @@ import java.util.List;
  *     "required": ["location"]
  * }
  * 
+ * * @author https:www.unfbx.com - * @since 2023-06-14 + * @since 2023-06-14 */ @Data @Builder diff --git a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/common/Choice.java b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/common/Choice.java index cc747f14..4e4f6482 100644 --- a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/common/Choice.java +++ b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/common/Choice.java @@ -7,9 +7,8 @@ import lombok.Data; import java.io.Serializable; /** - * * @author https:www.unfbx.com - * 2023-02-15 + * 2023-02-15 */ @Data @JsonIgnoreProperties(ignoreUnknown = true) diff --git a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/common/DeleteResponse.java b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/common/DeleteResponse.java index 7c2238ed..1f11fea3 100644 --- a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/common/DeleteResponse.java +++ b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/common/DeleteResponse.java @@ -6,10 +6,8 @@ import lombok.Data; import java.io.Serializable; /** - * - * * @author https:www.unfbx.com - * 2023-02-15 + * 2023-02-15 */ @Data @JsonIgnoreProperties(ignoreUnknown = true) diff --git a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/common/OpenAiResponse.java b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/common/OpenAiResponse.java index 15dc7bc5..20e5f21c 100644 --- a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/common/OpenAiResponse.java +++ b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/common/OpenAiResponse.java @@ -5,11 +5,10 @@ import lombok.Data; import java.io.Serializable; import java.util.List; + /** - * - * * @author https:www.unfbx.com - * 2023-02-15 + * 2023-02-15 */ @Data @JsonIgnoreProperties(ignoreUnknown = true) diff --git a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/common/Usage.java b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/common/Usage.java index 188d2d4a..9a3e9ecb 100644 --- a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/common/Usage.java +++ b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/common/Usage.java @@ -7,10 +7,8 @@ import lombok.Data; import java.io.Serializable; /** - * - * * @author https:www.unfbx.com - * 2023-02-15 + * 2023-02-15 */ @Data @JsonIgnoreProperties(ignoreUnknown = true) diff --git a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/completions/Completion.java b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/completions/Completion.java index 64057967..267a8510 100644 --- a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/completions/Completion.java +++ b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/completions/Completion.java @@ -10,7 +10,7 @@ import java.util.List; import java.util.Map; /** - * 问题类 + * 问题类 * * @author https:www.unfbx.com * 2023-02-11 @@ -101,7 +101,8 @@ public class Completion implements Serializable { /** * 获取当前参数的tokens数 - * @return token数量 + * + * @return token数量 */ // public long tokens() { // if (StrUtil.isBlank(this.prompt) || StrUtil.isBlank(this.model)) { diff --git a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/completions/CompletionResponse.java b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/completions/CompletionResponse.java index 78e14a22..53651fc1 100644 --- a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/completions/CompletionResponse.java +++ b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/completions/CompletionResponse.java @@ -9,10 +9,10 @@ import org.ruoyi.common.chat.entity.common.Usage; import java.io.Serializable; /** - * 答案类 + * 答案类 * * @author https:www.unfbx.com - * 2023-02-11 + * 2023-02-11 */ @Data @JsonIgnoreProperties(ignoreUnknown = true) diff --git a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/edits/Edit.java b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/edits/Edit.java index 662c0bc2..d7669c39 100644 --- a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/edits/Edit.java +++ b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/edits/Edit.java @@ -7,10 +7,8 @@ import lombok.extern.slf4j.Slf4j; import java.io.Serializable; /** - * - * * @author https:www.unfbx.com - * 2023-02-15 + * 2023-02-15 */ @Getter @Builder @@ -35,7 +33,7 @@ public class Edit implements Serializable { /** * 使用什么取样温度,0到2之间。较高的值(如0.8)将使输出更加随机,而较低的值(如0.2)将使输出更加集中和确定。 - * + *

* We generally recommend altering this or but not both.top_p */ @Builder.Default @@ -43,7 +41,7 @@ public class Edit implements Serializable { /** * 使用温度采样的替代方法称为核心采样,其中模型考虑具有top_p概率质量的令牌的结果。因此,0.1 意味着只考虑包含前 10% 概率质量的代币。 - * + *

* 我们通常建议更改此设置,但不要同时更改两者。temperature */ @JsonProperty("top_p") @@ -90,6 +88,7 @@ public class Edit implements Serializable { public void setInstruction(String instruction) { this.instruction = instruction; } + @Getter @AllArgsConstructor public enum Model { diff --git a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/edits/EditResponse.java b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/edits/EditResponse.java index 07917614..9c0adf70 100644 --- a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/edits/EditResponse.java +++ b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/edits/EditResponse.java @@ -9,10 +9,8 @@ import org.ruoyi.common.chat.entity.common.Usage; import java.io.Serializable; /** - * - * * @author https:www.unfbx.com - * 2023-02-15 + * 2023-02-15 */ @Data @JsonIgnoreProperties(ignoreUnknown = true) diff --git a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/embeddings/Embedding.java b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/embeddings/Embedding.java index d176e2ab..c07bbf1d 100644 --- a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/embeddings/Embedding.java +++ b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/embeddings/Embedding.java @@ -9,10 +9,8 @@ import java.util.List; import java.util.Objects; /** - * - * * @author https:www.unfbx.com - * 2023-02-15 + * 2023-02-15 */ @Getter @Slf4j diff --git a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/embeddings/EmbeddingResponse.java b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/embeddings/EmbeddingResponse.java index ad48b2a1..9b157bd2 100644 --- a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/embeddings/EmbeddingResponse.java +++ b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/embeddings/EmbeddingResponse.java @@ -8,10 +8,8 @@ import java.io.Serializable; import java.util.List; /** - * - * * @author https:www.unfbx.com - * 2023-02-15 + * 2023-02-15 */ @Data @JsonIgnoreProperties(ignoreUnknown = true) diff --git a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/engines/Engine.java b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/engines/Engine.java index 72b28c4b..9a2113bb 100644 --- a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/engines/Engine.java +++ b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/engines/Engine.java @@ -6,10 +6,8 @@ import lombok.Data; import java.io.Serializable; /** - * - * * @author https:www.unfbx.com - * 2023-02-15 + * 2023-02-15 */ @Data @JsonIgnoreProperties(ignoreUnknown = true) diff --git a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/files/File.java b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/files/File.java index 06be2403..6e932d01 100644 --- a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/files/File.java +++ b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/files/File.java @@ -6,10 +6,8 @@ import lombok.Data; import java.io.Serializable; /** - * - * * @author https:www.unfbx.com - * 2023-02-15 + * 2023-02-15 */ @Data @JsonIgnoreProperties(ignoreUnknown = true) diff --git a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/files/UploadFileResponse.java b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/files/UploadFileResponse.java index c3e87cc7..385b951c 100644 --- a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/files/UploadFileResponse.java +++ b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/files/UploadFileResponse.java @@ -6,10 +6,8 @@ import lombok.Data; import java.io.Serializable; /** - * - * * @author https:www.unfbx.com - * 2023-02-15 + * 2023-02-15 */ @Data @JsonIgnoreProperties(ignoreUnknown = true) diff --git a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/fineTune/FineTune.java b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/fineTune/FineTune.java index 26ad2f1d..096caa42 100644 --- a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/fineTune/FineTune.java +++ b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/fineTune/FineTune.java @@ -30,6 +30,7 @@ public class FineTune implements Serializable { private String validationFile; /** * 参考 + * * @see Model */ private String model; @@ -101,7 +102,7 @@ public class FineTune implements Serializable { } public void setSuffix(String suffix) { - if(Objects.nonNull(suffix) && !"".equals(suffix) && suffix.length() > 40){ + if (Objects.nonNull(suffix) && !"".equals(suffix) && suffix.length() > 40) { log.error("后缀长度不能大于40"); throw new BaseException(CommonError.PARAM_ERROR.msg()); } diff --git a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/images/Image.java b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/images/Image.java index 84f60ffb..ba830bbe 100644 --- a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/images/Image.java +++ b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/images/Image.java @@ -11,8 +11,6 @@ import lombok.extern.slf4j.Slf4j; import java.io.Serializable; /** - * - * * @author https:www.unfbx.com * 2023-02-15 */ diff --git a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/images/ImageEdit.java b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/images/ImageEdit.java index 32ee3675..5a781bf3 100644 --- a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/images/ImageEdit.java +++ b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/images/ImageEdit.java @@ -11,10 +11,8 @@ import java.io.Serializable; import java.util.Objects; /** - * - * * @author https:www.unfbx.com - * 2023-02-15 + * 2023-02-15 */ @Getter @Slf4j @@ -48,11 +46,11 @@ public class ImageEdit implements Serializable { private String user; public ImageEdit setN(Integer n) { - if(n < 1){ + if (n < 1) { log.warn("n最小值1"); n = 1; } - if(n > 10){ + if (n > 10) { log.warn("n最大值10"); n = 10; } @@ -61,11 +59,11 @@ public class ImageEdit implements Serializable { } public ImageEdit setPrompt(String prompt) { - if(Objects.isNull(prompt) || "".equals(prompt)){ + if (Objects.isNull(prompt) || "".equals(prompt)) { log.error("参数异常"); throw new BaseException(CommonError.PARAM_ERROR.msg()); } - if(prompt.length() > 1000){ + if (prompt.length() > 1000) { log.error("长度超过1000"); throw new BaseException(CommonError.PARAM_ERROR.msg()); } @@ -74,7 +72,7 @@ public class ImageEdit implements Serializable { } public ImageEdit setSize(SizeEnum size) { - if(Objects.isNull(size)){ + if (Objects.isNull(size)) { size = SizeEnum.size_512; } this.size = size.getName(); @@ -82,7 +80,7 @@ public class ImageEdit implements Serializable { } public ImageEdit setResponseFormat(ResponseFormat responseFormat) { - if(Objects.isNull(responseFormat)){ + if (Objects.isNull(responseFormat)) { responseFormat = ResponseFormat.URL; } this.responseFormat = responseFormat.getName(); diff --git a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/images/ImageResponse.java b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/images/ImageResponse.java index 7ad84150..000767af 100644 --- a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/images/ImageResponse.java +++ b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/images/ImageResponse.java @@ -7,10 +7,8 @@ import java.io.Serializable; import java.util.List; /** - * - * * @author https:www.unfbx.com - * 2023-02-15 + * 2023-02-15 */ @Data @JsonIgnoreProperties(ignoreUnknown = true) diff --git a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/images/ImageVariations.java b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/images/ImageVariations.java index 03ea00f1..a36b8b88 100644 --- a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/images/ImageVariations.java +++ b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/images/ImageVariations.java @@ -12,10 +12,8 @@ import java.io.Serializable; import java.util.Objects; /** - * - * * @author https:www.unfbx.com - * 2023-02-15 + * 2023-02-15 */ @Getter @Slf4j diff --git a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/images/Item.java b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/images/Item.java index 58f7ca06..625290fa 100644 --- a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/images/Item.java +++ b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/images/Item.java @@ -7,10 +7,8 @@ import lombok.Data; import java.io.Serializable; /** - * - * * @author https:www.unfbx.com - * 2023-02-15 + * 2023-02-15 */ @Data @JsonIgnoreProperties(ignoreUnknown = true) diff --git a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/images/ResponseFormat.java b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/images/ResponseFormat.java index 5a9e1e2d..9f2dcce9 100644 --- a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/images/ResponseFormat.java +++ b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/images/ResponseFormat.java @@ -6,10 +6,8 @@ import lombok.Getter; import java.io.Serializable; /** - * - * * @author https:www.unfbx.com - * 2023-02-15 + * 2023-02-15 */ @AllArgsConstructor @Getter diff --git a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/images/SizeEnum.java b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/images/SizeEnum.java index fe2997ea..3c8f34c3 100644 --- a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/images/SizeEnum.java +++ b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/images/SizeEnum.java @@ -6,10 +6,8 @@ import lombok.Getter; import java.io.Serializable; /** - * - * * @author https:www.unfbx.com - * 2023-02-15 + * 2023-02-15 */ @Getter @AllArgsConstructor diff --git a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/models/LocalModelsSearchResponse.java b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/models/LocalModelsSearchResponse.java index 12025d5c..e0d68cac 100644 --- a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/models/LocalModelsSearchResponse.java +++ b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/models/LocalModelsSearchResponse.java @@ -1,4 +1,5 @@ package org.ruoyi.common.chat.entity.models; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; @@ -13,8 +14,8 @@ public class LocalModelsSearchResponse { private List>> topKEmbeddings; // 处理三层嵌套数组 // 默认构造函数 - public LocalModelsSearchResponse() {} - + public LocalModelsSearchResponse() { + } } diff --git a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/models/Model.java b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/models/Model.java index bfedf88d..80a22dc0 100644 --- a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/models/Model.java +++ b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/models/Model.java @@ -8,10 +8,8 @@ import java.io.Serializable; import java.util.List; /** - * - * * @author https:www.unfbx.com - * 2023-02-15 + * 2023-02-15 */ @Data @JsonIgnoreProperties(ignoreUnknown = true) diff --git a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/models/ModelResponse.java b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/models/ModelResponse.java index f78cf84d..2c14bb70 100644 --- a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/models/ModelResponse.java +++ b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/models/ModelResponse.java @@ -7,10 +7,8 @@ import java.io.Serializable; import java.util.List; /** - * - * * @author https:www.unfbx.com - * 2023-02-15 + * 2023-02-15 */ @Data @JsonIgnoreProperties(ignoreUnknown = true) diff --git a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/models/Permission.java b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/models/Permission.java index 8b15a0a6..f54a8ef7 100644 --- a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/models/Permission.java +++ b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/models/Permission.java @@ -7,8 +7,6 @@ import lombok.Data; import java.io.Serializable; /** - * - * * @author https:www.unfbx.com * 2023-02-15 */ diff --git a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/moderations/Categories.java b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/moderations/Categories.java index 69d9add7..65d566fb 100644 --- a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/moderations/Categories.java +++ b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/moderations/Categories.java @@ -7,10 +7,8 @@ import lombok.Data; import java.io.Serializable; /** - * - * * @author https:www.unfbx.com - * 2023-02-15 + * 2023-02-15 */ @Data @JsonIgnoreProperties(ignoreUnknown = true) diff --git a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/moderations/CategoryScores.java b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/moderations/CategoryScores.java index 13f9ed0b..f78066b9 100644 --- a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/moderations/CategoryScores.java +++ b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/moderations/CategoryScores.java @@ -8,10 +8,8 @@ import java.io.Serializable; import java.math.BigDecimal; /** - * - * * @author https:www.unfbx.com - * 2023-02-15 + * 2023-02-15 */ @Data @JsonIgnoreProperties(ignoreUnknown = true) diff --git a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/moderations/Moderation.java b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/moderations/Moderation.java index f6831f74..bd42e75f 100644 --- a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/moderations/Moderation.java +++ b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/moderations/Moderation.java @@ -10,10 +10,10 @@ import java.util.List; import java.util.Objects; /** - * 文本审核,敏感词鉴别 + * 文本审核,敏感词鉴别 * * @author https:www.unfbx.com - * 2023-02-15 + * 2023-02-15 */ @Getter @Builder diff --git a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/moderations/ModerationResponse.java b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/moderations/ModerationResponse.java index b1a3dd21..a2c2e667 100644 --- a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/moderations/ModerationResponse.java +++ b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/moderations/ModerationResponse.java @@ -7,10 +7,8 @@ import java.io.Serializable; import java.util.List; /** - * - * * @author https:www.unfbx.com - * 2023-02-15 + * 2023-02-15 */ @Data @JsonIgnoreProperties(ignoreUnknown = true) diff --git a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/moderations/Result.java b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/moderations/Result.java index a42682a3..b73f12fa 100644 --- a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/moderations/Result.java +++ b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/moderations/Result.java @@ -7,10 +7,8 @@ import lombok.Data; import java.io.Serializable; /** - * - * * @author https:www.unfbx.com - * 2023-02-15 + * 2023-02-15 */ @Data @JsonIgnoreProperties(ignoreUnknown = true) diff --git a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/whisper/Whisper.java b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/whisper/Whisper.java index 7de6ca57..ea5f3e92 100644 --- a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/whisper/Whisper.java +++ b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/whisper/Whisper.java @@ -7,7 +7,7 @@ import lombok.Getter; import java.io.Serializable; /** - * 语音转文字 + * 语音转文字 * * @author https:www.unfbx.com * @since 2023-03-02 diff --git a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/whisper/WhisperResponse.java b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/whisper/WhisperResponse.java index d80900fa..03afa121 100644 --- a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/whisper/WhisperResponse.java +++ b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/whisper/WhisperResponse.java @@ -6,8 +6,6 @@ import lombok.Data; import java.io.Serializable; /** - * - * * @author https:www.unfbx.com * @since 2023-03-02 */ diff --git a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/handler/PlusWebSocketHandler.java b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/handler/PlusWebSocketHandler.java index 5f94b47b..90d6f11e 100644 --- a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/handler/PlusWebSocketHandler.java +++ b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/handler/PlusWebSocketHandler.java @@ -47,7 +47,7 @@ public class PlusWebSocketHandler extends AbstractWebSocketHandler { if (StrUtil.isNotBlank(messageContext)) { messages = JSONUtil.toList(messageContext, Message.class); // 上下文长度 - int contextSize=10; + int contextSize = 10; if (messages.size() >= contextSize) { messages = messages.subList(1, contextSize); } @@ -58,13 +58,13 @@ public class PlusWebSocketHandler extends AbstractWebSocketHandler { messages.add(currentMessage); } ChatCompletion chatCompletion = ChatCompletion - .builder() - .model("gpt-4o-mini") - .messages(messages) - .temperature(0.2) - .stream(true) - .build(); - OpenAiStreamClient openAiStreamClient=(OpenAiStreamClient) SpringUtils.context().getBean("openAiStreamClient"); + .builder() + .model("gpt-4o-mini") + .messages(messages) + .temperature(0.2) + .stream(true) + .build(); + OpenAiStreamClient openAiStreamClient = (OpenAiStreamClient) SpringUtils.context().getBean("openAiStreamClient"); openAiStreamClient.streamChatCompletion(chatCompletion, eventSourceListener); LocalCache.CACHE.put(session.getId(), JSONUtil.toJsonStr(messages), LocalCache.TIMEOUT); } diff --git a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/listener/WebSocketEventListener.java b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/listener/WebSocketEventListener.java index 9e5f5e06..7421e0d5 100644 --- a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/listener/WebSocketEventListener.java +++ b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/listener/WebSocketEventListener.java @@ -14,7 +14,7 @@ import org.springframework.web.socket.WebSocketSession; import java.util.Objects; /** - * OpenAI流式输出Socket接收 + * OpenAI流式输出Socket接收 * * @author https:www.unfbx.com * @date 2023-03-23 @@ -22,12 +22,11 @@ import java.util.Objects; @Slf4j public class WebSocketEventListener extends EventSourceListener { - private WebSocketSession session; - /** * 消息结束标识 */ private final String msgEnd = "[DONE]"; + private WebSocketSession session; public WebSocketEventListener(WebSocketSession session) { this.session = session; @@ -59,8 +58,8 @@ public class WebSocketEventListener extends EventSourceListener { String delta = ""; try { delta = mapper.writeValueAsString(completionResponse.getChoices().get(0).getDelta()); - }catch (Exception e){ - log.error("转换失败{}",e.getMessage()); + } catch (Exception e) { + log.error("转换失败{}", e.getMessage()); } session.sendMessage(new TextMessage(delta)); } diff --git a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/openai/OpenAiApi.java b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/openai/OpenAiApi.java index ba6fa9ed..1d494b09 100644 --- a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/openai/OpenAiApi.java +++ b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/openai/OpenAiApi.java @@ -40,7 +40,7 @@ import java.time.LocalDate; import java.util.Map; /** - * open ai官方api接口 + * open ai官方api接口 * * @author https:www.unfbx.com * 2023-02-15 @@ -58,7 +58,7 @@ public interface OpenAiApi { /** * models 返回的数据id * - * @param id 模型主键 + * @param id 模型主键 * @return Single Model */ @GET("v1/models/{id}") @@ -317,7 +317,7 @@ public interface OpenAiApi { /** * 账户信息查询:里面包含总金额(美元)等信息 * - * @return 账户信息 + * @return 账户信息 */ @GET("v1/dashboard/billing/subscription") Single subscription(); diff --git a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/openai/OpenAiClient.java b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/openai/OpenAiClient.java index 9deb0675..21b1061c 100644 --- a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/openai/OpenAiClient.java +++ b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/openai/OpenAiClient.java @@ -56,7 +56,7 @@ import java.util.concurrent.TimeUnit; /** - * open ai 客户端 + * open ai 客户端 * * @author https:www.unfbx.com * @since 2023-02-11 @@ -100,15 +100,6 @@ public class OpenAiClient { @Getter private OpenAiAuthInterceptor authInterceptor; - /** - * 构造器 - * - * @return OpenAiClient.Builder - */ - public static Builder builder() { - return new Builder(); - } - /** * 构造 * @@ -156,6 +147,14 @@ public class OpenAiClient { .build().create(OpenAiApi.class); } + /** + * 构造器 + * + * @return OpenAiClient.Builder + */ + public static Builder builder() { + return new Builder(); + } /** * 创建默认OkHttpClient @@ -681,7 +680,7 @@ public class OpenAiClient { RequestBody fileBody = RequestBody.create(MediaType.parse("multipart/form-data"), file); MultipartBody.Part multipartBody = MultipartBody.Part.createFormData("file", file.getName(), fileBody); //自定义参数 - Map requestBodyMap = new HashMap<>(5,1L); + Map requestBodyMap = new HashMap<>(5, 1L); if (StrUtil.isNotBlank(translations.getModel())) { requestBodyMap.put(Translations.Fields.model, RequestBody.create(MediaType.parse("multipart/form-data"), translations.getModel())); @@ -812,6 +811,7 @@ public class OpenAiClient { Single subscription = this.openAiApi.subscription(); return subscription.blockingGet(); } + /** * 账户调用接口消耗金额信息查询 * 最多查询100天 @@ -833,7 +833,6 @@ public class OpenAiClient { private @NotNull List apiKey; /** * api请求地址,结尾处有斜杠 - * */ private String apiHost; /** diff --git a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/openai/OpenAiStreamClient.java b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/openai/OpenAiStreamClient.java index f5117364..04613ac8 100644 --- a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/openai/OpenAiStreamClient.java +++ b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/openai/OpenAiStreamClient.java @@ -52,7 +52,7 @@ import java.util.*; import java.util.concurrent.TimeUnit; /** - * open ai 客户端 + * open ai 客户端 * * @author https:www.unfbx.com * 2023-02-28 @@ -63,31 +63,27 @@ import java.util.concurrent.TimeUnit; @Setter public class OpenAiStreamClient { + private static final String DONE_SIGNAL = "[DONE]"; @NotNull private List apiKey; /** * 自定义api host使用builder的方式构造client */ private String apiHost; - /** * 自定义url 兼容多个平台 */ private String apiUrl; - /** * 自定义的okHttpClient * 如果不自定义 ,就是用sdk默认的OkHttpClient实例 */ private OkHttpClient okHttpClient; - /** * api key的获取策略 */ private KeyStrategyFunction, String> keyStrategy; - private OpenAiApi openAiApi; - /** * 自定义鉴权处理拦截器
* 可以不设置,默认实现:DefaultOpenAiAuthInterceptor
@@ -98,8 +94,6 @@ public class OpenAiStreamClient { */ private OpenAiAuthInterceptor authInterceptor; - private static final String DONE_SIGNAL = "[DONE]"; - /** * 构造实例对象 * @@ -139,9 +133,9 @@ public class OpenAiStreamClient { } else { //自定义的okhttpClient 需要增加api keys builder.okHttpClient = builder.okHttpClient - .newBuilder() - .addInterceptor(authInterceptor) - .build(); + .newBuilder() + .addInterceptor(authInterceptor) + .build(); } okHttpClient = builder.okHttpClient; if (apiHost.endsWith("/")) { @@ -155,6 +149,15 @@ public class OpenAiStreamClient { } + /** + * 构造 + * + * @return Builder + */ + public static Builder builder() { + return new Builder(); + } + /** * 创建默认的OkHttpClient */ @@ -165,16 +168,15 @@ public class OpenAiStreamClient { this.authInterceptor.setApiKey(this.apiKey); this.authInterceptor.setKeyStrategy(this.keyStrategy); OkHttpClient okHttpClient = new OkHttpClient - .Builder() - .addInterceptor(this.authInterceptor) - .connectTimeout(10, TimeUnit.SECONDS) - .writeTimeout(50, TimeUnit.SECONDS) - .readTimeout(50, TimeUnit.SECONDS) - .build(); + .Builder() + .addInterceptor(this.authInterceptor) + .connectTimeout(10, TimeUnit.SECONDS) + .writeTimeout(50, TimeUnit.SECONDS) + .readTimeout(50, TimeUnit.SECONDS) + .build(); return okHttpClient; } - /** * 流式输出,最新版的GPT-3.5 chat completion 更加贴近官方网站的问答模型 * @@ -191,9 +193,9 @@ public class OpenAiStreamClient { ObjectMapper mapper = new ObjectMapper(); String requestBody = mapper.writeValueAsString(chatCompletion); Request request = new Request.Builder() - .url(this.apiHost) - .post(RequestBody.create(MediaType.parse(ContentType.JSON.getValue()), requestBody)) - .build(); + .url(this.apiHost) + .post(RequestBody.create(MediaType.parse(ContentType.JSON.getValue()), requestBody)) + .build(); factory.newEventSource(request, eventSourceListener); } catch (Exception e) { log.error("请求参数解析异常:{}", e.getMessage()); @@ -238,7 +240,6 @@ public class OpenAiStreamClient { this.streamChatCompletion(chatCompletion, pluginEventSourceListener); } - /** * 插件问答简易版 * 默认取messages最后一个元素构建插件对话 @@ -255,7 +256,6 @@ public class OpenAiStreamClient { this.streamChatCompletionWithPlugin(chatCompletion, eventSourceListener, pluginEventSourceListener, plugin); } - /** * 插件问答简易版 * 默认取messages最后一个元素构建插件对话 @@ -287,7 +287,6 @@ public class OpenAiStreamClient { this.streamChatCompletionWithPlugin(chatCompletion, eventSourceListener, plugin); } - /** * 根据描述生成图片 * @@ -457,6 +456,7 @@ public class OpenAiStreamClient { Transcriptions transcriptions = Transcriptions.builder().build(); return this.speechToTextTranscriptions(file, transcriptions); } + /** * 文本转语音(异步) * @@ -475,12 +475,12 @@ public class OpenAiStreamClient { * @param textToSpeech 参数 * @since 1.1.3 */ - public ResponseBody textToSpeech(TextToSpeech textToSpeech){ + public ResponseBody textToSpeech(TextToSpeech textToSpeech) { try { Call responseBody = this.openAiApi.textToSpeech(textToSpeech); return responseBody.execute().body(); } catch (IOException e) { - throw new BaseException("文本转语音(同步)失败: "+e.getMessage()); + throw new BaseException("文本转语音(同步)失败: " + e.getMessage()); } } @@ -508,13 +508,13 @@ public class OpenAiStreamClient { // 创建请求对象 Request request = new Request.Builder() - .url(url) - .build(); + .url(url) + .build(); // 发送请求并处理响应 try { return client.newCall(request).execute().body(); } catch (IOException e) { - throw new BaseException("语音克隆失败!{}",e.getMessage()); + throw new BaseException("语音克隆失败!{}", e.getMessage()); } } @@ -602,16 +602,6 @@ public class OpenAiStreamClient { return this.chatCompletionWithPlugin(chatCompletion, plugin); } - - /** - * 构造 - * - * @return Builder - */ - public static Builder builder() { - return new Builder(); - } - public static final class Builder { private @NotNull List apiKey; /** diff --git a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/openai/TestOpenAIAPI.java b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/openai/TestOpenAIAPI.java index 3df000d8..cbf3486a 100644 --- a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/openai/TestOpenAIAPI.java +++ b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/openai/TestOpenAIAPI.java @@ -6,27 +6,27 @@ import java.io.IOException; public class TestOpenAIAPI { - private final OkHttpClient client = new OkHttpClient(); private static final String API_KEY = "sk-Waea254YSRYVg4FZVCz2CDz73B22xRpmKpJ41kbczVgpPxvg"; private static final String URL = "https://api.gptgod.online/v1/chat/completions"; - - public void getChatGptResponse(String prompt) throws IOException { - RequestBody body = RequestBody.create(MediaType.get("application/json; charset=utf-8"), - "{\"model\": \"gpt-3.5-turbo\", \"messages\": [{\"role\": \"system\", \"content\": \"You are a helpful assistant.\"}, {\"role\": \"user\", \"content\": \"" + prompt + "\"}]}"); - - Request request = new Request.Builder() - .url(URL) - .post(body) - .addHeader("Authorization", "Bearer " + API_KEY) - .build(); - - try (Response response = client.newCall(request).execute()) { - - } - } + private final OkHttpClient client = new OkHttpClient(); public static void main(String[] args) throws IOException { TestOpenAIAPI api = new TestOpenAIAPI(); api.getChatGptResponse("Hello, how are you?"); } + + public void getChatGptResponse(String prompt) throws IOException { + RequestBody body = RequestBody.create(MediaType.get("application/json; charset=utf-8"), + "{\"model\": \"gpt-3.5-turbo\", \"messages\": [{\"role\": \"system\", \"content\": \"You are a helpful assistant.\"}, {\"role\": \"user\", \"content\": \"" + prompt + "\"}]}"); + + Request request = new Request.Builder() + .url(URL) + .post(body) + .addHeader("Authorization", "Bearer " + API_KEY) + .build(); + + try (Response response = client.newCall(request).execute()) { + + } + } } diff --git a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/openai/exception/CommonError.java b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/openai/exception/CommonError.java index e7cae02e..1d409e78 100644 --- a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/openai/exception/CommonError.java +++ b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/openai/exception/CommonError.java @@ -1,10 +1,10 @@ package org.ruoyi.common.chat.openai.exception; /** - * 错误 + * 错误 * * @author https:www.unfbx.com - * 2023-02-11 + * 2023-02-11 */ public enum CommonError implements IError { MESSAGE_NOT_NUL(500, "Message 不能为空"), @@ -15,7 +15,7 @@ public enum CommonError implements IError { RETRY_ERROR(502, "请求异常,请重试~"), //官方的错误码列表:https://platform.openai.com/docs/guides/error-codes/api-errors OPENAI_AUTHENTICATION_ERROR(401, "身份验证无效/提供的 API 密钥不正确/您必须是组织的成员才能使用 API"), - OPENAI_LIMIT_ERROR(429 , "达到请求的速率限制/您超出了当前配额,请检查您的计划和帐单详细信息/发动机当前过载,请稍后重试"), + OPENAI_LIMIT_ERROR(429, "达到请求的速率限制/您超出了当前配额,请检查您的计划和帐单详细信息/发动机当前过载,请稍后重试"), OPENAI_SERVER_ERROR(500, "服务器在处理您的请求时出错"), ; diff --git a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/openai/exception/IError.java b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/openai/exception/IError.java index 0e17a63a..ee4f44a4 100644 --- a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/openai/exception/IError.java +++ b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/openai/exception/IError.java @@ -1,9 +1,8 @@ package org.ruoyi.common.chat.openai.exception; + /** - * - * * @author https:www.unfbx.com - * 2023-02-11 + * 2023-02-11 */ public interface IError { String msg(); diff --git a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/openai/function/KeyRandomStrategy.java b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/openai/function/KeyRandomStrategy.java index e4945d63..e3c507f1 100644 --- a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/openai/function/KeyRandomStrategy.java +++ b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/openai/function/KeyRandomStrategy.java @@ -5,7 +5,7 @@ import cn.hutool.core.util.RandomUtil; import java.util.List; /** - * 随机策略 + * 随机策略 * * @author https:www.unfbx.com * @since 2023-04-03 diff --git a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/openai/function/KeyStrategyFunction.java b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/openai/function/KeyStrategyFunction.java index c446414b..5de0eee3 100644 --- a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/openai/function/KeyStrategyFunction.java +++ b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/openai/function/KeyStrategyFunction.java @@ -3,11 +3,11 @@ package org.ruoyi.common.chat.openai.function; import java.util.function.Function; /** - * key 的获取策略 + * key 的获取策略 * jdk默认实现 - * @see Function * * @author https:www.unfbx.com + * @see Function * @since 2023-04-03 */ @FunctionalInterface diff --git a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/openai/interceptor/DefaultOpenAiAuthInterceptor.java b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/openai/interceptor/DefaultOpenAiAuthInterceptor.java index 1165bc28..24771215 100644 --- a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/openai/interceptor/DefaultOpenAiAuthInterceptor.java +++ b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/openai/interceptor/DefaultOpenAiAuthInterceptor.java @@ -9,7 +9,7 @@ import java.util.List; import java.util.Map; /** - * 请求增加header apikey + * 请求增加header apikey * * @author https:www.unfbx.com * @since 2023-03-23 diff --git a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/openai/interceptor/DynamicKeyOpenAiAuthInterceptor.java b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/openai/interceptor/DynamicKeyOpenAiAuthInterceptor.java index 6fd892a5..94edda51 100644 --- a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/openai/interceptor/DynamicKeyOpenAiAuthInterceptor.java +++ b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/openai/interceptor/DynamicKeyOpenAiAuthInterceptor.java @@ -16,7 +16,7 @@ import java.util.Objects; import java.util.stream.Collectors; /** - * 动态处理key的鉴权拦截器 + * 动态处理key的鉴权拦截器 * * @author https:www.unfbx.com * @since 2023-04-25 @@ -35,7 +35,6 @@ public class DynamicKeyOpenAiAuthInterceptor extends OpenAiAuthInterceptor { /** * 请求头处理 - * */ public DynamicKeyOpenAiAuthInterceptor() { this.setWarringConfig(null); diff --git a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/openai/interceptor/OpenAILogger.java b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/openai/interceptor/OpenAILogger.java index dc32a69b..7eafa6cc 100644 --- a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/openai/interceptor/OpenAILogger.java +++ b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/openai/interceptor/OpenAILogger.java @@ -4,7 +4,7 @@ import lombok.extern.slf4j.Slf4j; import okhttp3.logging.HttpLoggingInterceptor; /** - * 日志 + * 日志 * * @author https:www.unfbx.com * 2023-02-28 diff --git a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/openai/interceptor/OpenAiResponseInterceptor.java b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/openai/interceptor/OpenAiResponseInterceptor.java index 936bcab7..8aee3507 100644 --- a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/openai/interceptor/OpenAiResponseInterceptor.java +++ b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/openai/interceptor/OpenAiResponseInterceptor.java @@ -13,10 +13,10 @@ import java.io.IOException; import java.util.Objects; /** - * openai 返回值处理Interceptor + * openai 返回值处理Interceptor * * @author https:www.unfbx.com - * @since 2023-03-23 + * @since 2023-03-23 */ @Slf4j public class OpenAiResponseInterceptor implements Interceptor { diff --git a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/openai/plugin/PluginAbstract.java b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/openai/plugin/PluginAbstract.java index ddb2045e..da122db8 100644 --- a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/openai/plugin/PluginAbstract.java +++ b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/openai/plugin/PluginAbstract.java @@ -69,6 +69,10 @@ public abstract class PluginAbstract { setParameters(); } + public abstract T func(R args); + + public abstract String content(T t); + @Data public static class Arg { private String name; @@ -81,8 +85,4 @@ public abstract class PluginAbstract { @JsonIgnore private boolean required; } - - public abstract T func(R args); - - public abstract String content(T t); } diff --git a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/request/ChatRequest.java b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/request/ChatRequest.java index ba351cf7..e0b9bf44 100644 --- a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/request/ChatRequest.java +++ b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/request/ChatRequest.java @@ -7,7 +7,7 @@ import org.ruoyi.common.chat.entity.chat.Message; import java.util.List; /** - * 对话请求对象 + * 对话请求对象 * * @author ageerle * @sine 2023-04-08 diff --git a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/request/Dall3Request.java b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/request/Dall3Request.java index 727fbf33..afc72ab7 100644 --- a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/request/Dall3Request.java +++ b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/request/Dall3Request.java @@ -4,8 +4,6 @@ import jakarta.validation.constraints.NotEmpty; import lombok.Data; /** - * - * * @author https:www.unfbx.com * @sine 2023-04-08 */ @@ -18,15 +16,21 @@ public class Dall3Request { @NotEmpty(message = "提示词不能为空") private String prompt; - /** 图片大小 */ + /** + * 图片大小 + */ @NotEmpty(message = "图片大小不能为空") - private String size ; + private String size; - /** 图片质量 */ + /** + * 图片质量 + */ @NotEmpty(message = "图片质量不能为空") private String quality; - /** 图片风格 */ + /** + * 图片风格 + */ @NotEmpty(message = "图片风格不能为空") private String style; diff --git a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/sse/ConsoleEventSourceListener.java b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/sse/ConsoleEventSourceListener.java index 4202e81e..445f82eb 100644 --- a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/sse/ConsoleEventSourceListener.java +++ b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/sse/ConsoleEventSourceListener.java @@ -10,7 +10,7 @@ import okhttp3.sse.EventSourceListener; import java.util.Objects; /** - * sse + * sse * * @author https:www.unfbx.com * 2023-02-28 @@ -39,7 +39,7 @@ public class ConsoleEventSourceListener extends EventSourceListener { @SneakyThrows @Override public void onFailure(EventSource eventSource, Throwable t, Response response) { - if(Objects.isNull(response)){ + if (Objects.isNull(response)) { log.error("OpenAI sse连接异常:{}", t); eventSource.cancel(); return; diff --git a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/sse/DefaultPluginListener.java b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/sse/DefaultPluginListener.java index 100bea56..b03a170f 100644 --- a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/sse/DefaultPluginListener.java +++ b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/sse/DefaultPluginListener.java @@ -7,7 +7,7 @@ import org.ruoyi.common.chat.openai.OpenAiStreamClient; import org.ruoyi.common.chat.openai.plugin.PluginAbstract; /** - * 插件开发返回信息收集sse监听器 + * 插件开发返回信息收集sse监听器 * * @author https:www.unfbx.com * 2023-08-18 diff --git a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/sse/PluginListener.java b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/sse/PluginListener.java index f1bfa44b..a23522ad 100644 --- a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/sse/PluginListener.java +++ b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/sse/PluginListener.java @@ -19,7 +19,7 @@ import org.ruoyi.common.chat.openai.plugin.PluginParam; import java.util.Objects; /** - * 插件开发返回信息收集sse监听器 + * 插件开发返回信息收集sse监听器 * * @author https:www.unfbx.com * 2023-08-18 @@ -30,21 +30,10 @@ public abstract class PluginListener extends EventSour * openAi插件构建的参数 */ private String arguments = ""; - - /** - * 获取openAi插件构建的参数 - * - * @return arguments - */ - private String getArguments() { - return this.arguments; - } - private OpenAiStreamClient client; private EventSourceListener eventSourceListener; private PluginAbstract plugin; private ChatCompletion chatCompletion; - /** * 构造方法必备四个元素 * @@ -60,6 +49,15 @@ public abstract class PluginListener extends EventSour this.chatCompletion = chatCompletion; } + /** + * 获取openAi插件构建的参数 + * + * @return arguments + */ + private String getArguments() { + return this.arguments; + } + /** * sse关闭后处理,第二次请求方法 */ diff --git a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/utils/TikTokensUtil.java b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/utils/TikTokensUtil.java index dff3e05f..e71e4e63 100644 --- a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/utils/TikTokensUtil.java +++ b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/utils/TikTokensUtil.java @@ -15,7 +15,7 @@ import org.ruoyi.common.chat.entity.chat.Message; import java.util.*; /** - * token计算工具类 + * token计算工具类 * * @author https:www.unfbx.com * @since 2023-04-04 @@ -152,7 +152,7 @@ public class TikTokensUtil { } Encoding enc = getEncoding(modelName); if (Objects.isNull(enc)) { - log.warn("[{}]模型不存在或者暂不支持计算tokens,直接返回tokens==0",modelName); + log.warn("[{}]模型不存在或者暂不支持计算tokens,直接返回tokens==0", modelName); return new ArrayList<>(); } return enc.encode(text); @@ -184,25 +184,25 @@ public class TikTokensUtil { int tokensPerMessage = 0; int tokensPerName = 0; if (modelName.equals(ChatCompletion.Model.GPT_3_5_TURBO_0613.getName()) - || modelName.equals(ChatCompletion.Model.GPT_3_5_TURBO_16K_0613.getName()) - || modelName.equals(ChatCompletion.Model.GPT_4_0613.getName()) - || modelName.equals(ChatCompletion.Model.GPT_4_32K_0613.getName()) - || modelName.equals(ChatCompletion.Model.GPT_4_1106_PREVIEW.getName()) - || modelName.equals(ChatCompletion.Model.GPT_4_VISION_PREVIEW.getName()) + || modelName.equals(ChatCompletion.Model.GPT_3_5_TURBO_16K_0613.getName()) + || modelName.equals(ChatCompletion.Model.GPT_4_0613.getName()) + || modelName.equals(ChatCompletion.Model.GPT_4_32K_0613.getName()) + || modelName.equals(ChatCompletion.Model.GPT_4_1106_PREVIEW.getName()) + || modelName.equals(ChatCompletion.Model.GPT_4_VISION_PREVIEW.getName()) ) { tokensPerMessage = 3; tokensPerName = 1; - }else if(modelName.contains(ChatCompletion.Model.GPT_3_5_TURBO.getName())){ + } else if (modelName.contains(ChatCompletion.Model.GPT_3_5_TURBO.getName())) { //"gpt-3.5-turbo" in model: log.warn("Warning: gpt-3.5-turbo may update over time. Returning num tokens assuming gpt-3.5-turbo-0613."); tokensPerMessage = 3; tokensPerName = 1; - }else if(modelName.contains(ChatCompletion.Model.GPT_4.getName())){ + } else if (modelName.contains(ChatCompletion.Model.GPT_4.getName())) { log.warn("Warning: gpt-4 may update over time. Returning num tokens assuming gpt-4-0613."); tokensPerMessage = 3; tokensPerName = 1; - }else { - log.warn("不支持的model {} 按gpt4计算tokens",modelName); + } else { + log.warn("不支持的model {} 按gpt4计算tokens", modelName); tokensPerMessage = 3; tokensPerName = 1; } diff --git a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/utils/WebSocketUtils.java b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/utils/WebSocketUtils.java index 43cc6e89..8957cbe0 100644 --- a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/utils/WebSocketUtils.java +++ b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/utils/WebSocketUtils.java @@ -70,7 +70,7 @@ public class WebSocketUtils { broadcastMessage.setSessionKeys(unsentSessionKeys); RedisUtils.publish(WEB_SOCKET_TOPIC, broadcastMessage, consumer -> { log.info(" WebSocket发送主题订阅消息topic:{} session keys:{} message:{}", - WEB_SOCKET_TOPIC, unsentSessionKeys, webSocketMessage.getMessage()); + WEB_SOCKET_TOPIC, unsentSessionKeys, webSocketMessage.getMessage()); }); } } diff --git a/ruoyi-common/ruoyi-common-core/pom.xml b/ruoyi-common/ruoyi-common-core/pom.xml index ee4bd63e..83e28b9e 100644 --- a/ruoyi-common/ruoyi-common-core/pom.xml +++ b/ruoyi-common/ruoyi-common-core/pom.xml @@ -1,6 +1,6 @@ - org.ruoyi diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/config/AsyncConfig.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/config/AsyncConfig.java index 2751d5b6..eb0a4ba3 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/config/AsyncConfig.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/config/AsyncConfig.java @@ -43,7 +43,7 @@ public class AsyncConfig implements AsyncConfigurer { throwable.printStackTrace(); StringBuilder sb = new StringBuilder(); sb.append("Exception message - ").append(throwable.getMessage()) - .append(", Method name - ").append(method.getName()); + .append(", Method name - ").append(method.getName()); if (ArrayUtil.isNotEmpty(objects)) { sb.append(", Parameter value - ").append(Arrays.toString(objects)); } diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/config/RuoYiConfig.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/config/RuoYiConfig.java index f671848a..305ef836 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/config/RuoYiConfig.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/config/RuoYiConfig.java @@ -16,31 +16,27 @@ import org.springframework.stereotype.Component; @ConfigurationProperties(prefix = "ruoyi") public class RuoYiConfig { - /** - * 项目名称 - */ - private String name; - - /** - * 版本 - */ - private String version; - - /** - * 版权年份 - */ - private String copyrightYear; - - /** - * 实例演示开关 - */ - private boolean demoEnabled; - /** * 获取地址开关 */ @Getter private static boolean addressEnabled; + /** + * 项目名称 + */ + private String name; + /** + * 版本 + */ + private String version; + /** + * 版权年份 + */ + private String copyrightYear; + /** + * 实例演示开关 + */ + private boolean demoEnabled; public void setAddressEnabled(boolean addressEnabled) { RuoYiConfig.addressEnabled = addressEnabled; diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/config/ThreadPoolConfig.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/config/ThreadPoolConfig.java index 24838a55..22b5733f 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/config/ThreadPoolConfig.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/config/ThreadPoolConfig.java @@ -48,8 +48,8 @@ public class ThreadPoolConfig { public ScheduledExecutorService scheduledExecutorService() { log.info("====创建定时任务线程池===="); return new ScheduledThreadPoolExecutor(core, - new BasicThreadFactory.Builder().namingPattern("schedule-pool-%d").daemon(true).build(), - new ThreadPoolExecutor.CallerRunsPolicy()) { + new BasicThreadFactory.Builder().namingPattern("schedule-pool-%d").daemon(true).build(), + new ThreadPoolExecutor.CallerRunsPolicy()) { @Override protected void afterExecute(Runnable r, Throwable t) { super.afterExecute(r, t); diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/domain/R.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/domain/R.java index b3856dbc..37b7e994 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/domain/R.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/domain/R.java @@ -16,19 +16,16 @@ import java.io.Serializable; @NoArgsConstructor public class R implements Serializable { - @Serial - private static final long serialVersionUID = 1L; - /** * 成功 */ public static final int SUCCESS = 200; - /** * 失败 */ public static final int FAIL = 500; - + @Serial + private static final long serialVersionUID = 1L; private int code; private String msg; @@ -84,7 +81,7 @@ public class R implements Serializable { /** * 返回警告消息 * - * @param msg 返回内容 + * @param msg 返回内容 * @param data 数据对象 * @return 警告消息 */ diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/domain/model/LoginBody.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/domain/model/LoginBody.java index 9a91d081..115f8cbe 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/domain/model/LoginBody.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/domain/model/LoginBody.java @@ -21,7 +21,7 @@ public class LoginBody { * 用户名 */ @NotBlank(message = "{user.username.not.blank}") - // @Length(min = UserConstants.USERNAME_MIN_LENGTH, max = UserConstants.USERNAME_MAX_LENGTH, message = "{user.username.length.valid}") + // @Length(min = UserConstants.USERNAME_MIN_LENGTH, max = UserConstants.USERNAME_MAX_LENGTH, message = "{user.username.length.valid}") private String username; /** diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/event/ConfigChangeEvent.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/event/ConfigChangeEvent.java index 816668a4..e653dab2 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/event/ConfigChangeEvent.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/event/ConfigChangeEvent.java @@ -3,7 +3,7 @@ package org.ruoyi.common.core.event; import org.springframework.context.ApplicationEvent; /** - * 定义一个事件类,用于通知配置变化 + * 定义一个事件类,用于通知配置变化 * * @author ageerle@163.com * date 2024/5/19 diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/exception/AuthException.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/exception/AuthException.java index 433c49c0..b45bfe47 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/exception/AuthException.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/exception/AuthException.java @@ -1,6 +1,6 @@ package org.ruoyi.common.core.exception; -public class AuthException extends RuntimeException{ +public class AuthException extends RuntimeException { private static final long serialVersionUID = 1L; diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/exception/ServiceException.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/exception/ServiceException.java index ec2a6148..0a47100f 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/exception/ServiceException.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/exception/ServiceException.java @@ -46,22 +46,22 @@ public final class ServiceException extends RuntimeException { return detailMessage; } + public ServiceException setDetailMessage(String detailMessage) { + this.detailMessage = detailMessage; + return this; + } + @Override public String getMessage() { return message; } - public Integer getCode() { - return code; - } - public ServiceException setMessage(String message) { this.message = message; return this; } - public ServiceException setDetailMessage(String detailMessage) { - this.detailMessage = detailMessage; - return this; + public Integer getCode() { + return code; } } diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/manager/ShutdownManager.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/manager/ShutdownManager.java index 7018edf5..b125e9ec 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/manager/ShutdownManager.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/manager/ShutdownManager.java @@ -1,7 +1,6 @@ package org.ruoyi.common.core.manager; import jakarta.annotation.PreDestroy; -import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.ruoyi.common.core.utils.Threads; import org.springframework.beans.factory.annotation.Autowired; diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/service/BaseContext.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/service/BaseContext.java index 27af6ba0..589f86b7 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/service/BaseContext.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/service/BaseContext.java @@ -7,19 +7,20 @@ package org.ruoyi.common.core.service; public class BaseContext { private static ThreadLocal threadLocal = new ThreadLocal<>(); + /** + * @description: 获取值 + * @author: yzm + **/ + public static String getCurrentToken() { + return threadLocal.get(); + } + /** * @description: 设置值 * @author: yzm * @param: [token] 线程token **/ - public static void setCurrentToken(String token){ + public static void setCurrentToken(String token) { threadLocal.set(token); } - /** - * @description: 获取值 - * @author: yzm - **/ - public static String getCurrentToken(){ - return threadLocal.get(); - } } \ No newline at end of file diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/service/ConfigService.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/service/ConfigService.java index 675b662c..e66cbb38 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/service/ConfigService.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/service/ConfigService.java @@ -13,8 +13,7 @@ public interface ConfigService { * @param configKey * @return */ - String getConfigValue(String category,String configKey); - + String getConfigValue(String category, String configKey); } diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/utils/DateUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/utils/DateUtils.java index 75a954c9..9b81e2cd 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/utils/DateUtils.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/utils/DateUtils.java @@ -29,9 +29,9 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils { public static final String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss"; private static final String[] PARSE_PATTERNS = { - "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM", - "yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM", - "yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM"}; + "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM", + "yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM", + "yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM"}; /** * 获取当前Date型日期 diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/utils/ObjectUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/utils/ObjectUtils.java index 7f7d5910..3be45b72 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/utils/ObjectUtils.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/utils/ObjectUtils.java @@ -17,7 +17,7 @@ public class ObjectUtils extends ObjectUtil { /** * 如果对象不为空,则获取对象中的某个字段 ObjectUtils.notNullGetter(user, User::getName); * - * @param obj 对象 + * @param obj 对象 * @param func 获取方法 * @return 对象字段 */ diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/utils/OkHttpUtil.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/utils/OkHttpUtil.java index 9bc4cfce..5b1dd633 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/utils/OkHttpUtil.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/utils/OkHttpUtil.java @@ -12,17 +12,16 @@ import java.util.concurrent.TimeUnit; @Component public class OkHttpUtil { + private final OkHttpClient client = new OkHttpClient.Builder() + .connectTimeout(3000, TimeUnit.SECONDS) + .writeTimeout(3000, TimeUnit.SECONDS) + .readTimeout(3000, TimeUnit.SECONDS) + .build(); @Setter private String apiHost; @Setter private String apiKey; - private final OkHttpClient client = new OkHttpClient.Builder() - .connectTimeout(3000, TimeUnit.SECONDS) - .writeTimeout(3000, TimeUnit.SECONDS) - .readTimeout(3000, TimeUnit.SECONDS) - .build(); - public String executeRequest(Request request) { try (Response response = client.newCall(request).execute()) { if (!response.isSuccessful()) { @@ -40,16 +39,16 @@ public class OkHttpUtil { MediaType JSON = MediaType.get("application/json; charset=utf-8"); RequestBody body = RequestBody.create(json, JSON); return new Request.Builder() - .url(apiHost + url) - .post(body) - .header("Authorization", apiKey) - .build(); + .url(apiHost + url) + .post(body) + .header("Authorization", apiKey) + .build(); } public Request createGetRequest(String url) { return new Request.Builder() - .url(apiHost + url) - .header("Authorization", apiKey) - .build(); + .url(apiHost + url) + .header("Authorization", apiKey) + .build(); } } diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/utils/StreamUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/utils/StreamUtils.java index 8ed09913..98fa4119 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/utils/StreamUtils.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/utils/StreamUtils.java @@ -126,8 +126,8 @@ public class StreamUtils { return MapUtil.newHashMap(); } return collection - .stream() - .collect(Collectors.groupingBy(key, LinkedHashMap::new, Collectors.toList())); + .stream() + .collect(Collectors.groupingBy(key, LinkedHashMap::new, Collectors.toList())); } /** @@ -147,8 +147,8 @@ public class StreamUtils { return MapUtil.newHashMap(); } return collection - .stream() - .collect(Collectors.groupingBy(key1, LinkedHashMap::new, Collectors.groupingBy(key2, LinkedHashMap::new, Collectors.toList()))); + .stream() + .collect(Collectors.groupingBy(key1, LinkedHashMap::new, Collectors.groupingBy(key2, LinkedHashMap::new, Collectors.toList()))); } /** @@ -168,8 +168,8 @@ public class StreamUtils { return MapUtil.newHashMap(); } return collection - .stream() - .collect(Collectors.groupingBy(key1, LinkedHashMap::new, Collectors.toMap(key2, Function.identity(), (l, r) -> l))); + .stream() + .collect(Collectors.groupingBy(key1, LinkedHashMap::new, Collectors.toMap(key2, Function.identity(), (l, r) -> l))); } /** @@ -187,11 +187,11 @@ public class StreamUtils { return CollUtil.newArrayList(); } return collection - .stream() - .map(function) - .filter(Objects::nonNull) - // 注意此处不要使用 .toList() 新语法 因为返回的是不可变List 会导致序列化问题 - .collect(Collectors.toList()); + .stream() + .map(function) + .filter(Objects::nonNull) + // 注意此处不要使用 .toList() 新语法 因为返回的是不可变List 会导致序列化问题 + .collect(Collectors.toList()); } /** @@ -209,10 +209,10 @@ public class StreamUtils { return CollUtil.newHashSet(); } return collection - .stream() - .map(function) - .filter(Objects::nonNull) - .collect(Collectors.toSet()); + .stream() + .map(function) + .filter(Objects::nonNull) + .collect(Collectors.toSet()); } diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/utils/StringUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/utils/StringUtils.java index 847dd107..99412e15 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/utils/StringUtils.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/utils/StringUtils.java @@ -312,10 +312,10 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils { return new ArrayList<>(0); } return StrUtil.split(str, separator) - .stream() - .filter(Objects::nonNull) - .map(mapper) - .collect(Collectors.toList()); + .stream() + .filter(Objects::nonNull) + .map(mapper) + .collect(Collectors.toList()); } } diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/utils/file/MimeTypeUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/utils/file/MimeTypeUtils.java index c82aebec..7830478c 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/utils/file/MimeTypeUtils.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/utils/file/MimeTypeUtils.java @@ -21,7 +21,7 @@ public class MimeTypeUtils { public static final String[] FLASH_EXTENSION = {"swf", "flv"}; public static final String[] MEDIA_EXTENSION = {"swf", "flv", "mp3", "wav", "wma", "wmv", "mid", "avi", "mpg", - "asf", "rm", "rmvb"}; + "asf", "rm", "rmvb"}; public static final String[] VIDEO_EXTENSION = {"mp4", "avi", "rmvb"}; /** diff --git a/ruoyi-common/ruoyi-common-doc/pom.xml b/ruoyi-common/ruoyi-common-doc/pom.xml index 0d227fbd..122f6ae5 100644 --- a/ruoyi-common/ruoyi-common-doc/pom.xml +++ b/ruoyi-common/ruoyi-common-doc/pom.xml @@ -1,6 +1,6 @@ - org.ruoyi diff --git a/ruoyi-common/ruoyi-common-doc/src/main/java/org/ruoyi/common/doc/config/properties/SpringDocProperties.java b/ruoyi-common/ruoyi-common-doc/src/main/java/org/ruoyi/common/doc/config/properties/SpringDocProperties.java index 66f80c70..0a0638fc 100644 --- a/ruoyi-common/ruoyi-common-doc/src/main/java/org/ruoyi/common/doc/config/properties/SpringDocProperties.java +++ b/ruoyi-common/ruoyi-common-doc/src/main/java/org/ruoyi/common/doc/config/properties/SpringDocProperties.java @@ -56,7 +56,7 @@ public class SpringDocProperties { *

* * @see io.swagger.v3.oas.models.info.Info - * + *

* 为了 springboot 自动生产配置提示信息,所以这里复制一个类出来 */ @Data diff --git a/ruoyi-common/ruoyi-common-encrypt/pom.xml b/ruoyi-common/ruoyi-common-encrypt/pom.xml index 28608bd5..7a54d79f 100644 --- a/ruoyi-common/ruoyi-common-encrypt/pom.xml +++ b/ruoyi-common/ruoyi-common-encrypt/pom.xml @@ -1,6 +1,6 @@ - org.ruoyi diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/ruoyi/common/encrypt/core/EncryptorManager.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/ruoyi/common/encrypt/core/EncryptorManager.java index b7a09b5c..359a49c0 100644 --- a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/ruoyi/common/encrypt/core/EncryptorManager.java +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/ruoyi/common/encrypt/core/EncryptorManager.java @@ -37,8 +37,8 @@ public class EncryptorManager { return fieldCache.computeIfAbsent(sourceClazz, clazz -> { Field[] declaredFields = clazz.getDeclaredFields(); Set fieldSet = Arrays.stream(declaredFields).filter(field -> - field.isAnnotationPresent(EncryptField.class) && field.getType() == String.class) - .collect(Collectors.toSet()); + field.isAnnotationPresent(EncryptField.class) && field.getType() == String.class) + .collect(Collectors.toSet()); for (Field field : fieldSet) { field.setAccessible(true); } diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/ruoyi/common/encrypt/core/IEncryptor.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/ruoyi/common/encrypt/core/IEncryptor.java index de3e451d..217903ba 100644 --- a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/ruoyi/common/encrypt/core/IEncryptor.java +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/ruoyi/common/encrypt/core/IEncryptor.java @@ -28,7 +28,7 @@ public interface IEncryptor { /** * 解密 * - * @param value 待加密字符串 + * @param value 待加密字符串 * @return 解密后的字符串 */ String decrypt(String value); diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/ruoyi/common/encrypt/core/encryptor/AesEncryptor.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/ruoyi/common/encrypt/core/encryptor/AesEncryptor.java index a0c4d386..c6ddafba 100644 --- a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/ruoyi/common/encrypt/core/encryptor/AesEncryptor.java +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/ruoyi/common/encrypt/core/encryptor/AesEncryptor.java @@ -60,7 +60,7 @@ public class AesEncryptor extends AbstractEncryptor { /** * 解密 * - * @param value 待加密字符串 + * @param value 待加密字符串 */ @Override public String decrypt(String value) { diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/ruoyi/common/encrypt/core/encryptor/Base64Encryptor.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/ruoyi/common/encrypt/core/encryptor/Base64Encryptor.java index fde6f808..cad8ca1f 100644 --- a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/ruoyi/common/encrypt/core/encryptor/Base64Encryptor.java +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/ruoyi/common/encrypt/core/encryptor/Base64Encryptor.java @@ -39,7 +39,7 @@ public class Base64Encryptor extends AbstractEncryptor { /** * 解密 * - * @param value 待加密字符串 + * @param value 待加密字符串 */ @Override public String decrypt(String value) { diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/ruoyi/common/encrypt/core/encryptor/RsaEncryptor.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/ruoyi/common/encrypt/core/encryptor/RsaEncryptor.java index 1fa774fd..1e289ea2 100644 --- a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/ruoyi/common/encrypt/core/encryptor/RsaEncryptor.java +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/ruoyi/common/encrypt/core/encryptor/RsaEncryptor.java @@ -56,7 +56,7 @@ public class RsaEncryptor extends AbstractEncryptor { /** * 解密 * - * @param value 待加密字符串 + * @param value 待加密字符串 */ @Override public String decrypt(String value) { diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/ruoyi/common/encrypt/core/encryptor/Sm2Encryptor.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/ruoyi/common/encrypt/core/encryptor/Sm2Encryptor.java index 08a4b40c..6704c876 100644 --- a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/ruoyi/common/encrypt/core/encryptor/Sm2Encryptor.java +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/ruoyi/common/encrypt/core/encryptor/Sm2Encryptor.java @@ -55,7 +55,7 @@ public class Sm2Encryptor extends AbstractEncryptor { /** * 解密 * - * @param value 待加密字符串 + * @param value 待加密字符串 */ @Override public String decrypt(String value) { diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/ruoyi/common/encrypt/core/encryptor/Sm4Encryptor.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/ruoyi/common/encrypt/core/encryptor/Sm4Encryptor.java index 975ff421..244f5f25 100644 --- a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/ruoyi/common/encrypt/core/encryptor/Sm4Encryptor.java +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/ruoyi/common/encrypt/core/encryptor/Sm4Encryptor.java @@ -58,7 +58,7 @@ public class Sm4Encryptor extends AbstractEncryptor { /** * 解密 * - * @param value 待加密字符串 + * @param value 待加密字符串 */ @Override public String decrypt(String value) { diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/ruoyi/common/encrypt/interceptor/MybatisDecryptInterceptor.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/ruoyi/common/encrypt/interceptor/MybatisDecryptInterceptor.java index 99b99986..eb8a7df4 100644 --- a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/ruoyi/common/encrypt/interceptor/MybatisDecryptInterceptor.java +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/ruoyi/common/encrypt/interceptor/MybatisDecryptInterceptor.java @@ -26,9 +26,9 @@ import java.util.*; */ @Slf4j @Intercepts({@Signature( - type = ResultSetHandler.class, - method = "handleResultSets", - args = {Statement.class}) + type = ResultSetHandler.class, + method = "handleResultSets", + args = {Statement.class}) }) @AllArgsConstructor public class MybatisDecryptInterceptor implements Interceptor { @@ -61,7 +61,7 @@ public class MybatisDecryptInterceptor implements Interceptor { return; } if (sourceObject instanceof List list) { - if(CollUtil.isEmpty(list)) { + if (CollUtil.isEmpty(list)) { return; } // 判断第一个元素是否含有注解。如果没有直接返回,提高效率 diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/ruoyi/common/encrypt/interceptor/MybatisEncryptInterceptor.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/ruoyi/common/encrypt/interceptor/MybatisEncryptInterceptor.java index eacd31ee..8a1caf92 100644 --- a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/ruoyi/common/encrypt/interceptor/MybatisEncryptInterceptor.java +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/ruoyi/common/encrypt/interceptor/MybatisEncryptInterceptor.java @@ -29,9 +29,9 @@ import java.util.*; */ @Slf4j @Intercepts({@Signature( - type = ParameterHandler.class, - method = "setParameters", - args = {PreparedStatement.class}) + type = ParameterHandler.class, + method = "setParameters", + args = {PreparedStatement.class}) }) @AllArgsConstructor public class MybatisEncryptInterceptor implements Interceptor { @@ -70,7 +70,7 @@ public class MybatisEncryptInterceptor implements Interceptor { return; } if (sourceObject instanceof List list) { - if(CollUtil.isEmpty(list)) { + if (CollUtil.isEmpty(list)) { return; } // 判断第一个元素是否含有注解。如果没有直接返回,提高效率 diff --git a/ruoyi-common/ruoyi-common-excel/pom.xml b/ruoyi-common/ruoyi-common-excel/pom.xml index 0de9c8f3..e66596c3 100644 --- a/ruoyi-common/ruoyi-common-excel/pom.xml +++ b/ruoyi-common/ruoyi-common-excel/pom.xml @@ -1,6 +1,6 @@ - org.ruoyi diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/org/ruoyi/common/excel/annotation/CellMerge.java b/ruoyi-common/ruoyi-common-excel/src/main/java/org/ruoyi/common/excel/annotation/CellMerge.java index 5a6cf9b1..871e8fc0 100644 --- a/ruoyi-common/ruoyi-common-excel/src/main/java/org/ruoyi/common/excel/annotation/CellMerge.java +++ b/ruoyi-common/ruoyi-common-excel/src/main/java/org/ruoyi/common/excel/annotation/CellMerge.java @@ -6,7 +6,7 @@ import java.lang.annotation.*; /** * excel 列单元格合并(合并列相同项) - * + *

* 需搭配 {@link CellMergeStrategy} 策略使用 * * @author Lion Li @@ -16,9 +16,9 @@ import java.lang.annotation.*; @Inherited public @interface CellMerge { - /** - * col index - */ - int index() default -1; + /** + * col index + */ + int index() default -1; } diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/org/ruoyi/common/excel/core/CellMergeStrategy.java b/ruoyi-common/ruoyi-common-excel/src/main/java/org/ruoyi/common/excel/core/CellMergeStrategy.java index fa324970..d367b988 100644 --- a/ruoyi-common/ruoyi-common-excel/src/main/java/org/ruoyi/common/excel/core/CellMergeStrategy.java +++ b/ruoyi-common/ruoyi-common-excel/src/main/java/org/ruoyi/common/excel/core/CellMergeStrategy.java @@ -28,8 +28,8 @@ import java.util.Map; @Slf4j public class CellMergeStrategy extends AbstractMergeStrategy { - private final List list; - private final boolean hasTitle; + private final List list; + private final boolean hasTitle; private int rowIndex; public CellMergeStrategy(List list, boolean hasTitle) { @@ -40,83 +40,83 @@ public class CellMergeStrategy extends AbstractMergeStrategy { } @Override - protected void merge(Sheet sheet, Cell cell, Head head, Integer relativeRowIndex) { - List cellList = handle(list, hasTitle); - // judge the list is not null - if (CollUtil.isNotEmpty(cellList)) { - // the judge is necessary - if (cell.getRowIndex() == rowIndex && cell.getColumnIndex() == 0) { - for (CellRangeAddress item : cellList) { - sheet.addMergedRegion(item); - } - } - } - } + protected void merge(Sheet sheet, Cell cell, Head head, Integer relativeRowIndex) { + List cellList = handle(list, hasTitle); + // judge the list is not null + if (CollUtil.isNotEmpty(cellList)) { + // the judge is necessary + if (cell.getRowIndex() == rowIndex && cell.getColumnIndex() == 0) { + for (CellRangeAddress item : cellList) { + sheet.addMergedRegion(item); + } + } + } + } - @SneakyThrows - private List handle(List list, boolean hasTitle) { - List cellList = new ArrayList<>(); - if (CollUtil.isEmpty(list)) { - return cellList; - } + @SneakyThrows + private List handle(List list, boolean hasTitle) { + List cellList = new ArrayList<>(); + if (CollUtil.isEmpty(list)) { + return cellList; + } Field[] fields = ReflectUtils.getFields(list.get(0).getClass(), field -> !"serialVersionUID".equals(field.getName())); - // 有注解的字段 - List mergeFields = new ArrayList<>(); - List mergeFieldsIndex = new ArrayList<>(); - for (int i = 0; i < fields.length; i++) { - Field field = fields[i]; - if (field.isAnnotationPresent(CellMerge.class)) { - CellMerge cm = field.getAnnotation(CellMerge.class); + // 有注解的字段 + List mergeFields = new ArrayList<>(); + List mergeFieldsIndex = new ArrayList<>(); + for (int i = 0; i < fields.length; i++) { + Field field = fields[i]; + if (field.isAnnotationPresent(CellMerge.class)) { + CellMerge cm = field.getAnnotation(CellMerge.class); mergeFields.add(field); mergeFieldsIndex.add(cm.index() == -1 ? i : cm.index()); if (hasTitle) { ExcelProperty property = field.getAnnotation(ExcelProperty.class); rowIndex = Math.max(rowIndex, property.value().length); } - } - } + } + } - Map map = new HashMap<>(); - // 生成两两合并单元格 - for (int i = 0; i < list.size(); i++) { - for (int j = 0; j < mergeFields.size(); j++) { - Field field = mergeFields.get(j); + Map map = new HashMap<>(); + // 生成两两合并单元格 + for (int i = 0; i < list.size(); i++) { + for (int j = 0; j < mergeFields.size(); j++) { + Field field = mergeFields.get(j); Object val = ReflectUtils.invokeGetter(list.get(i), field.getName()); - int colNum = mergeFieldsIndex.get(j); - if (!map.containsKey(field)) { - map.put(field, new RepeatCell(val, i)); - } else { - RepeatCell repeatCell = map.get(field); - Object cellValue = repeatCell.getValue(); - if (cellValue == null || "".equals(cellValue)) { - // 空值跳过不合并 - continue; - } - if (!cellValue.equals(val)) { - if (i - repeatCell.getCurrent() > 1) { - cellList.add(new CellRangeAddress(repeatCell.getCurrent() + rowIndex, i + rowIndex - 1, colNum, colNum)); - } - map.put(field, new RepeatCell(val, i)); - } else if (i == list.size() - 1) { - if (i > repeatCell.getCurrent()) { - cellList.add(new CellRangeAddress(repeatCell.getCurrent() + rowIndex, i + rowIndex, colNum, colNum)); - } - } - } - } - } - return cellList; - } + int colNum = mergeFieldsIndex.get(j); + if (!map.containsKey(field)) { + map.put(field, new RepeatCell(val, i)); + } else { + RepeatCell repeatCell = map.get(field); + Object cellValue = repeatCell.getValue(); + if (cellValue == null || "".equals(cellValue)) { + // 空值跳过不合并 + continue; + } + if (!cellValue.equals(val)) { + if (i - repeatCell.getCurrent() > 1) { + cellList.add(new CellRangeAddress(repeatCell.getCurrent() + rowIndex, i + rowIndex - 1, colNum, colNum)); + } + map.put(field, new RepeatCell(val, i)); + } else if (i == list.size() - 1) { + if (i > repeatCell.getCurrent()) { + cellList.add(new CellRangeAddress(repeatCell.getCurrent() + rowIndex, i + rowIndex, colNum, colNum)); + } + } + } + } + } + return cellList; + } - @Data - @AllArgsConstructor - static class RepeatCell { + @Data + @AllArgsConstructor + static class RepeatCell { - private Object value; + private Object value; - private int current; + private int current; - } + } } diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/org/ruoyi/common/excel/core/DefaultExcelListener.java b/ruoyi-common/ruoyi-common-excel/src/main/java/org/ruoyi/common/excel/core/DefaultExcelListener.java index 6733068b..c77c57fb 100644 --- a/ruoyi-common/ruoyi-common-excel/src/main/java/org/ruoyi/common/excel/core/DefaultExcelListener.java +++ b/ruoyi-common/ruoyi-common-excel/src/main/java/org/ruoyi/common/excel/core/DefaultExcelListener.java @@ -60,7 +60,7 @@ public class DefaultExcelListener extends AnalysisEventListener implements Integer rowIndex = excelDataConvertException.getRowIndex(); Integer columnIndex = excelDataConvertException.getColumnIndex(); errMsg = StrUtil.format("第{}行-第{}列-表头{}: 解析异常
", - rowIndex + 1, columnIndex + 1, headMap.get(columnIndex)); + rowIndex + 1, columnIndex + 1, headMap.get(columnIndex)); if (log.isDebugEnabled()) { log.error(errMsg); } diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/org/ruoyi/common/excel/utils/ExcelUtil.java b/ruoyi-common/ruoyi-common-excel/src/main/java/org/ruoyi/common/excel/utils/ExcelUtil.java index abe7726e..be50d8b6 100644 --- a/ruoyi-common/ruoyi-common-excel/src/main/java/org/ruoyi/common/excel/utils/ExcelUtil.java +++ b/ruoyi-common/ruoyi-common-excel/src/main/java/org/ruoyi/common/excel/utils/ExcelUtil.java @@ -135,12 +135,12 @@ public class ExcelUtil { */ public static void exportExcel(List list, String sheetName, Class clazz, boolean merge, OutputStream os) { ExcelWriterSheetBuilder builder = EasyExcel.write(os, clazz) - .autoCloseStream(false) - // 自动适配 - .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()) - // 大数值自动转换 防止失真 - .registerConverter(new ExcelBigNumberConvert()) - .sheet(sheetName); + .autoCloseStream(false) + // 自动适配 + .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()) + // 大数值自动转换 防止失真 + .registerConverter(new ExcelBigNumberConvert()) + .sheet(sheetName); if (merge) { // 合并处理器 builder.registerWriteHandler(new CellMergeStrategy(list, true)); @@ -180,11 +180,11 @@ public class ExcelUtil { public static void exportTemplate(List data, String templatePath, OutputStream os) { ClassPathResource templateResource = new ClassPathResource(templatePath); ExcelWriter excelWriter = EasyExcel.write(os) - .withTemplate(templateResource.getStream()) - .autoCloseStream(false) - // 大数值自动转换 防止失真 - .registerConverter(new ExcelBigNumberConvert()) - .build(); + .withTemplate(templateResource.getStream()) + .autoCloseStream(false) + // 大数值自动转换 防止失真 + .registerConverter(new ExcelBigNumberConvert()) + .build(); WriteSheet writeSheet = EasyExcel.writerSheet().build(); if (CollUtil.isEmpty(data)) { throw new IllegalArgumentException("数据为空"); @@ -228,11 +228,11 @@ public class ExcelUtil { public static void exportTemplateMultiList(Map data, String templatePath, OutputStream os) { ClassPathResource templateResource = new ClassPathResource(templatePath); ExcelWriter excelWriter = EasyExcel.write(os) - .withTemplate(templateResource.getStream()) - .autoCloseStream(false) - // 大数值自动转换 防止失真 - .registerConverter(new ExcelBigNumberConvert()) - .build(); + .withTemplate(templateResource.getStream()) + .autoCloseStream(false) + // 大数值自动转换 防止失真 + .registerConverter(new ExcelBigNumberConvert()) + .build(); WriteSheet writeSheet = EasyExcel.writerSheet().build(); if (CollUtil.isEmpty(data)) { throw new IllegalArgumentException("数据为空"); diff --git a/ruoyi-common/ruoyi-common-idempotent/pom.xml b/ruoyi-common/ruoyi-common-idempotent/pom.xml index f9d8e956..a5562697 100644 --- a/ruoyi-common/ruoyi-common-idempotent/pom.xml +++ b/ruoyi-common/ruoyi-common-idempotent/pom.xml @@ -1,6 +1,6 @@ - org.ruoyi diff --git a/ruoyi-common/ruoyi-common-idempotent/src/main/java/org/ruoyi/common/idempotent/aspectj/RepeatSubmitAspect.java b/ruoyi-common/ruoyi-common-idempotent/src/main/java/org/ruoyi/common/idempotent/aspectj/RepeatSubmitAspect.java index cb45eacf..15402698 100644 --- a/ruoyi-common/ruoyi-common-idempotent/src/main/java/org/ruoyi/common/idempotent/aspectj/RepeatSubmitAspect.java +++ b/ruoyi-common/ruoyi-common-idempotent/src/main/java/org/ruoyi/common/idempotent/aspectj/RepeatSubmitAspect.java @@ -146,7 +146,7 @@ public class RepeatSubmitAspect { } } return o instanceof MultipartFile || o instanceof HttpServletRequest || o instanceof HttpServletResponse - || o instanceof BindingResult; + || o instanceof BindingResult; } } diff --git a/ruoyi-common/ruoyi-common-json/pom.xml b/ruoyi-common/ruoyi-common-json/pom.xml index c4a00a0a..0f26aa28 100644 --- a/ruoyi-common/ruoyi-common-json/pom.xml +++ b/ruoyi-common/ruoyi-common-json/pom.xml @@ -1,6 +1,6 @@ - org.ruoyi diff --git a/ruoyi-common/ruoyi-common-json/src/main/java/org/ruoyi/common/json/handler/BigNumberSerializer.java b/ruoyi-common/ruoyi-common-json/src/main/java/org/ruoyi/common/json/handler/BigNumberSerializer.java index 071a7dc3..9d20d4b7 100644 --- a/ruoyi-common/ruoyi-common-json/src/main/java/org/ruoyi/common/json/handler/BigNumberSerializer.java +++ b/ruoyi-common/ruoyi-common-json/src/main/java/org/ruoyi/common/json/handler/BigNumberSerializer.java @@ -15,17 +15,16 @@ import java.io.IOException; @JacksonStdImpl public class BigNumberSerializer extends NumberSerializer { + /** + * 提供实例 + */ + public static final BigNumberSerializer INSTANCE = new BigNumberSerializer(Number.class); /** * 根据 JS Number.MAX_SAFE_INTEGER 与 Number.MIN_SAFE_INTEGER 得来 */ private static final long MAX_SAFE_INTEGER = 9007199254740991L; private static final long MIN_SAFE_INTEGER = -9007199254740991L; - /** - * 提供实例 - */ - public static final BigNumberSerializer INSTANCE = new BigNumberSerializer(Number.class); - public BigNumberSerializer(Class rawType) { super(rawType); } diff --git a/ruoyi-common/ruoyi-common-log/pom.xml b/ruoyi-common/ruoyi-common-log/pom.xml index b26144d0..d8ddca6a 100644 --- a/ruoyi-common/ruoyi-common-log/pom.xml +++ b/ruoyi-common/ruoyi-common-log/pom.xml @@ -1,6 +1,6 @@ - org.ruoyi diff --git a/ruoyi-common/ruoyi-common-log/src/main/java/org/ruoyi/common/log/aspect/LogAspect.java b/ruoyi-common/ruoyi-common-log/src/main/java/org/ruoyi/common/log/aspect/LogAspect.java index 63bcefcf..5d21389c 100644 --- a/ruoyi-common/ruoyi-common-log/src/main/java/org/ruoyi/common/log/aspect/LogAspect.java +++ b/ruoyi-common/ruoyi-common-log/src/main/java/org/ruoyi/common/log/aspect/LogAspect.java @@ -42,7 +42,7 @@ public class LogAspect { /** * 排除敏感属性字段 */ - public static final String[] EXCLUDE_PROPERTIES = { "password", "oldPassword", "newPassword", "confirmPassword" }; + public static final String[] EXCLUDE_PROPERTIES = {"password", "oldPassword", "newPassword", "confirmPassword"}; /** @@ -216,6 +216,6 @@ public class LogAspect { } } return o instanceof MultipartFile || o instanceof HttpServletRequest || o instanceof HttpServletResponse - || o instanceof BindingResult; + || o instanceof BindingResult; } } diff --git a/ruoyi-common/ruoyi-common-mail/pom.xml b/ruoyi-common/ruoyi-common-mail/pom.xml index a1453420..d00826e1 100644 --- a/ruoyi-common/ruoyi-common-mail/pom.xml +++ b/ruoyi-common/ruoyi-common-mail/pom.xml @@ -1,6 +1,6 @@ - org.ruoyi diff --git a/ruoyi-common/ruoyi-common-mail/src/main/java/org/ruoyi/common/mail/config/MailConfig.java b/ruoyi-common/ruoyi-common-mail/src/main/java/org/ruoyi/common/mail/config/MailConfig.java index 04979d0c..01ce24e7 100644 --- a/ruoyi-common/ruoyi-common-mail/src/main/java/org/ruoyi/common/mail/config/MailConfig.java +++ b/ruoyi-common/ruoyi-common-mail/src/main/java/org/ruoyi/common/mail/config/MailConfig.java @@ -44,7 +44,7 @@ public class MailConfig { account.setConnectionTimeout(0); } - public String getKey(String key){ + public String getKey(String key) { return configService.getConfigValue("mail", key); } } diff --git a/ruoyi-common/ruoyi-common-mail/src/main/java/org/ruoyi/common/mail/utils/Mail.java b/ruoyi-common/ruoyi-common-mail/src/main/java/org/ruoyi/common/mail/utils/Mail.java index 00d3341b..89fd8e07 100644 --- a/ruoyi-common/ruoyi-common-mail/src/main/java/org/ruoyi/common/mail/utils/Mail.java +++ b/ruoyi-common/ruoyi-common-mail/src/main/java/org/ruoyi/common/mail/utils/Mail.java @@ -36,6 +36,10 @@ public class Mail implements Builder { * 邮箱帐户信息以及一些客户端配置信息 */ private final MailAccount mailAccount; + /** + * 正文、附件和图片的混合部分 + */ + private final Multipart multipart = new MimeMultipart(); /** * 收件人列表 */ @@ -64,10 +68,6 @@ public class Mail implements Builder { * 是否为HTML */ private boolean isHtml; - /** - * 正文、附件和图片的混合部分 - */ - private final Multipart multipart = new MimeMultipart(); /** * 是否使用全局会话,默认为false */ @@ -78,6 +78,25 @@ public class Mail implements Builder { */ private PrintStream debugOutput; + /** + * 构造,使用全局邮件帐户 + */ + public Mail() { + this(GlobalMailAccount.INSTANCE.getAccount()); + } + + /** + * 构造 + * + * @param mailAccount 邮件帐户,如果为null使用默认配置文件的全局邮件配置 + */ + public Mail(MailAccount mailAccount) { + mailAccount = (null != mailAccount) ? mailAccount : GlobalMailAccount.INSTANCE.getAccount(); + this.mailAccount = mailAccount.defaultIfEmpty(); + } + + // --------------------------------------------------------------- Constructor start + /** * 创建邮件客户端 * @@ -96,25 +115,6 @@ public class Mail implements Builder { public static Mail create() { return new Mail(); } - - // --------------------------------------------------------------- Constructor start - - /** - * 构造,使用全局邮件帐户 - */ - public Mail() { - this(GlobalMailAccount.INSTANCE.getAccount()); - } - - /** - * 构造 - * - * @param mailAccount 邮件帐户,如果为null使用默认配置文件的全局邮件配置 - */ - public Mail(MailAccount mailAccount) { - mailAccount = (null != mailAccount) ? mailAccount : GlobalMailAccount.INSTANCE.getAccount(); - this.mailAccount = mailAccount.defaultIfEmpty(); - } // --------------------------------------------------------------- Constructor end // --------------------------------------------------------------- Getters and Setters start diff --git a/ruoyi-common/ruoyi-common-mail/src/main/java/org/ruoyi/common/mail/utils/MailAccount.java b/ruoyi-common/ruoyi-common-mail/src/main/java/org/ruoyi/common/mail/utils/MailAccount.java index 96a1f813..192b6be6 100644 --- a/ruoyi-common/ruoyi-common-mail/src/main/java/org/ruoyi/common/mail/utils/MailAccount.java +++ b/ruoyi-common/ruoyi-common-mail/src/main/java/org/ruoyi/common/mail/utils/MailAccount.java @@ -18,9 +18,9 @@ import java.util.Properties; * @author Luxiaolei */ public class MailAccount implements Serializable { + public static final String[] MAIL_SETTING_PATHS = new String[]{"config/mail.setting", "config/mailAccount.setting", "mail.setting"}; @Serial private static final long serialVersionUID = -6937313421815719204L; - private static final String MAIL_PROTOCOL = "mail.transport.protocol"; private static final String SMTP_HOST = "mail.smtp.host"; private static final String SMTP_PORT = "mail.smtp.port"; @@ -28,7 +28,6 @@ public class MailAccount implements Serializable { private static final String SMTP_TIMEOUT = "mail.smtp.timeout"; private static final String SMTP_CONNECTION_TIMEOUT = "mail.smtp.connectiontimeout"; private static final String SMTP_WRITE_TIMEOUT = "mail.smtp.writetimeout"; - // SSL private static final String STARTTLS_ENABLE = "mail.smtp.starttls.enable"; private static final String SSL_ENABLE = "mail.smtp.ssl.enable"; @@ -36,17 +35,16 @@ public class MailAccount implements Serializable { private static final String SOCKET_FACTORY = "mail.smtp.socketFactory.class"; private static final String SOCKET_FACTORY_FALLBACK = "mail.smtp.socketFactory.fallback"; private static final String SOCKET_FACTORY_PORT = "smtp.socketFactory.port"; - - // System Properties - private static final String SPLIT_LONG_PARAMS = "mail.mime.splitlongparameters"; //private static final String ENCODE_FILE_NAME = "mail.mime.encodefilename"; //private static final String CHARSET = "mail.mime.charset"; - + // System Properties + private static final String SPLIT_LONG_PARAMS = "mail.mime.splitlongparameters"; // 其他 private static final String MAIL_DEBUG = "mail.debug"; - - public static final String[] MAIL_SETTING_PATHS = new String[]{"config/mail.setting", "config/mailAccount.setting", "mail.setting"}; - + /** + * 自定义的其他属性,此自定义属性会覆盖默认属性 + */ + private final Map customProperty = new HashMap<>(); /** * SMTP服务器域名 */ @@ -71,7 +69,6 @@ public class MailAccount implements Serializable { * 发送方,遵循RFC-822标准 */ private String from; - /** * 是否打开调试模式,调试模式会显示与邮件服务器通信过程,默认不开启 */ @@ -88,7 +85,6 @@ public class MailAccount implements Serializable { * 对于文件名是否使用{@link #charset}编码,默认为 {@code true} */ private boolean encodefilename = true; - /** * 使用 STARTTLS安全连接,STARTTLS是对纯文本通信协议的扩展。它将纯文本连接升级为加密连接(TLS或SSL), 而不是使用一个单独的加密通信端口。 */ @@ -97,12 +93,10 @@ public class MailAccount implements Serializable { * 使用 SSL安全连接 */ private Boolean sslEnable; - /** * SSL协议,多个协议用空格分隔 */ private String sslProtocols; - /** * 指定实现javax.net.SocketFactory接口的类的名称,这个类将被用于创建SMTP的套接字 */ @@ -115,7 +109,6 @@ public class MailAccount implements Serializable { * 指定的端口连接到在使用指定的套接字工厂。如果没有设置,将使用默认端口 */ private int socketFactoryPort = 465; - /** * SMTP超时时长,单位毫秒,缺省值不超时 */ @@ -129,11 +122,6 @@ public class MailAccount implements Serializable { */ private long writeTimeout; - /** - * 自定义的其他属性,此自定义属性会覆盖默认属性 - */ - private final Map customProperty = new HashMap<>(); - // -------------------------------------------------------------- Constructor start /** @@ -654,6 +642,6 @@ public class MailAccount implements Serializable { @Override public String toString() { return "MailAccount [host=" + host + ", port=" + port + ", auth=" + auth + ", user=" + user + ", pass=" + (StrUtil.isEmpty(this.pass) ? "" : "******") + ", from=" + from + ", startttlsEnable=" - + starttlsEnable + ", socketFactoryClass=" + socketFactoryClass + ", socketFactoryFallback=" + socketFactoryFallback + ", socketFactoryPort=" + socketFactoryPort + "]"; + + starttlsEnable + ", socketFactoryClass=" + socketFactoryClass + ", socketFactoryFallback=" + socketFactoryFallback + ", socketFactoryPort=" + socketFactoryPort + "]"; } } diff --git a/ruoyi-common/ruoyi-common-mail/src/main/java/org/ruoyi/common/mail/utils/MailUtils.java b/ruoyi-common/ruoyi-common-mail/src/main/java/org/ruoyi/common/mail/utils/MailUtils.java index eaa8bc0a..adfcfd7b 100644 --- a/ruoyi-common/ruoyi-common-mail/src/main/java/org/ruoyi/common/mail/utils/MailUtils.java +++ b/ruoyi-common/ruoyi-common-mail/src/main/java/org/ruoyi/common/mail/utils/MailUtils.java @@ -389,7 +389,7 @@ public class MailUtils { } return isSingleton ? Session.getDefaultInstance(mailAccount.getSmtpProps(), authenticator) // - : Session.getInstance(mailAccount.getSmtpProps(), authenticator); + : Session.getInstance(mailAccount.getSmtpProps(), authenticator); } // ------------------------------------------------------------------------------------------------------------------------ Private method start diff --git a/ruoyi-common/ruoyi-common-mybatis/pom.xml b/ruoyi-common/ruoyi-common-mybatis/pom.xml index 138732c5..893ec9fb 100644 --- a/ruoyi-common/ruoyi-common-mybatis/pom.xml +++ b/ruoyi-common/ruoyi-common-mybatis/pom.xml @@ -1,6 +1,6 @@ - org.ruoyi diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/core/page/PageQuery.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/core/page/PageQuery.java index a388cb4a..97b5f8d3 100644 --- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/core/page/PageQuery.java +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/core/page/PageQuery.java @@ -23,38 +23,37 @@ import java.util.List; @Data public class PageQuery implements Serializable { + /** + * 当前记录起始索引 默认值 + */ + public static final int DEFAULT_PAGE_NUM = 1; + /** + * 每页显示记录数 默认值 默认查全部 + */ + public static final int DEFAULT_PAGE_SIZE = Integer.MAX_VALUE; @Serial private static final long serialVersionUID = 1L; - /** * 分页大小 */ private Integer pageSize; - /** * 当前页数 */ private Integer pageNum; - /** * 排序列 */ private String orderByColumn; - /** * 排序的方向desc或者asc */ private String isAsc; - /** - * 当前记录起始索引 默认值 - */ - public static final int DEFAULT_PAGE_NUM = 1; - - /** - * 每页显示记录数 默认值 默认查全部 - */ - public static final int DEFAULT_PAGE_SIZE = Integer.MAX_VALUE; + public PageQuery(Integer pageSize, Integer pageNum) { + this.pageSize = pageSize; + this.pageNum = pageNum; + } /** * 构建分页对象 @@ -75,7 +74,7 @@ public class PageQuery implements Serializable { /** * 构建排序 - * + *

* 支持的用法如下: * {isAsc:"asc",orderByColumn:"id"} order by id asc * {isAsc:"asc",orderByColumn:"id,createTime"} order by id asc,create_time asc @@ -119,9 +118,4 @@ public class PageQuery implements Serializable { return (pageNum - 1) * pageSize; } - public PageQuery(Integer pageSize, Integer pageNum) { - this.pageSize = pageSize; - this.pageNum = pageNum; - } - } diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/handler/PlusDataPermissionHandler.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/handler/PlusDataPermissionHandler.java index df7a46cb..2300fb0e 100644 --- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/handler/PlusDataPermissionHandler.java +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/handler/PlusDataPermissionHandler.java @@ -145,7 +145,7 @@ public class PlusDataPermissionHandler { } // 包含权限标识符 这直接跳过 if (StringUtils.isNotBlank(dataColumn.permission()) && - CollUtil.contains(user.getMenuPermission(), dataColumn.permission()) + CollUtil.contains(user.getMenuPermission(), dataColumn.permission()) ) { ignoreMap.put(dataColumn, Boolean.TRUE); continue; @@ -187,7 +187,7 @@ public class PlusDataPermissionHandler { } // 忽略数据权限 防止spel表达式内有其他sql查询导致死循环调用 String sql = DataPermissionHelper.ignore(() -> - parser.parseExpression(type.getSqlTemplate(), parserContext).getValue(context, String.class) + parser.parseExpression(type.getSqlTemplate(), parserContext).getValue(context, String.class) ); // 解析sql模板并填充 conditions.add(joinStr + sql); diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/helper/DataBaseHelper.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/helper/DataBaseHelper.java index ae85c380..74243594 100644 --- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/helper/DataBaseHelper.java +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/helper/DataBaseHelper.java @@ -92,7 +92,7 @@ public class DataBaseHelper { DatabaseMetaData metaData = conn.getMetaData(); String catalog = conn.getCatalog(); String schema = conn.getSchema(); - + // 获取所有表名 try (var resultSet = metaData.getTables(catalog, schema, "%", new String[]{"TABLE"})) { while (resultSet.next()) { @@ -115,12 +115,12 @@ public class DataBaseHelper { public static List> getTableColumnInfo(String tableName) { DataSource dataSource = DS.determineDataSource(); List> columns = new ArrayList<>(); - + try (Connection conn = dataSource.getConnection()) { DatabaseMetaData metaData = conn.getMetaData(); String catalog = conn.getCatalog(); String schema = conn.getSchema(); - + // 获取表字段信息 try (ResultSet resultSet = metaData.getColumns(catalog, schema, tableName, "%")) { while (resultSet.next()) { @@ -131,33 +131,33 @@ public class DataBaseHelper { column.put("columnSize", resultSet.getInt("COLUMN_SIZE")); column.put("isNullable", "YES".equals(resultSet.getString("IS_NULLABLE"))); column.put("ordinalPosition", resultSet.getInt("ORDINAL_POSITION")); - + // 设置默认值 String defaultValue = resultSet.getString("COLUMN_DEF"); column.put("columnDefault", defaultValue); - + columns.add(column); } } - + // 获取主键信息 try (ResultSet pkResultSet = metaData.getPrimaryKeys(catalog, schema, tableName)) { List primaryKeys = new ArrayList<>(); while (pkResultSet.next()) { primaryKeys.add(pkResultSet.getString("COLUMN_NAME")); } - + // 标记主键字段 for (Map column : columns) { String columnName = (String) column.get("columnName"); column.put("isPrimaryKey", primaryKeys.contains(columnName)); } } - + } catch (SQLException e) { throw new ServiceException("获取表字段信息失败: " + e.getMessage()); } - + return columns; } } diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/helper/DataPermissionHelper.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/helper/DataPermissionHelper.java index 3d8f99c8..9d093ab2 100644 --- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/helper/DataPermissionHelper.java +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/helper/DataPermissionHelper.java @@ -44,7 +44,7 @@ public class DataPermissionHelper { /** * 设置当前执行mapper权限注解 * - * @param dataPermission 数据权限注解 + * @param dataPermission 数据权限注解 */ public static void setPermission(DataPermission dataPermission) { PERMISSION_CACHE.set(dataPermission); @@ -130,10 +130,10 @@ public class DataPermissionHelper { IgnoreStrategy ignoreStrategy = getIgnoreStrategy(); if (ObjectUtil.isNotNull(ignoreStrategy)) { boolean noOtherIgnoreStrategy = !Boolean.TRUE.equals(ignoreStrategy.getDynamicTableName()) - && !Boolean.TRUE.equals(ignoreStrategy.getBlockAttack()) - && !Boolean.TRUE.equals(ignoreStrategy.getIllegalSql()) - && !Boolean.TRUE.equals(ignoreStrategy.getTenantLine()) - && CollectionUtil.isEmpty(ignoreStrategy.getOthers()); + && !Boolean.TRUE.equals(ignoreStrategy.getBlockAttack()) + && !Boolean.TRUE.equals(ignoreStrategy.getIllegalSql()) + && !Boolean.TRUE.equals(ignoreStrategy.getTenantLine()) + && CollectionUtil.isEmpty(ignoreStrategy.getOthers()); Stack reentrantStack = REENTRANT_IGNORE.get(); boolean empty = reentrantStack.isEmpty() || reentrantStack.pop() == 1; if (noOtherIgnoreStrategy && empty) { diff --git a/ruoyi-common/ruoyi-common-oss/pom.xml b/ruoyi-common/ruoyi-common-oss/pom.xml index 716b1fad..b42fda3f 100644 --- a/ruoyi-common/ruoyi-common-oss/pom.xml +++ b/ruoyi-common/ruoyi-common-oss/pom.xml @@ -1,6 +1,6 @@ - org.ruoyi diff --git a/ruoyi-common/ruoyi-common-oss/src/main/java/org/ruoyi/common/oss/constant/OssConstant.java b/ruoyi-common/ruoyi-common-oss/src/main/java/org/ruoyi/common/oss/constant/OssConstant.java index f79a5a63..5efc8c1b 100644 --- a/ruoyi-common/ruoyi-common-oss/src/main/java/org/ruoyi/common/oss/constant/OssConstant.java +++ b/ruoyi-common/ruoyi-common-oss/src/main/java/org/ruoyi/common/oss/constant/OssConstant.java @@ -28,7 +28,7 @@ public interface OssConstant { /** * 云服务商 */ - String[] CLOUD_SERVICE = new String[] {"aliyun", "qcloud", "qiniu", "obs"}; + String[] CLOUD_SERVICE = new String[]{"aliyun", "qcloud", "qiniu", "obs"}; /** * https 状态 diff --git a/ruoyi-common/ruoyi-common-oss/src/main/java/org/ruoyi/common/oss/core/OssClient.java b/ruoyi-common/ruoyi-common-oss/src/main/java/org/ruoyi/common/oss/core/OssClient.java index a870add1..af1c2af9 100644 --- a/ruoyi-common/ruoyi-common-oss/src/main/java/org/ruoyi/common/oss/core/OssClient.java +++ b/ruoyi-common/ruoyi-common-oss/src/main/java/org/ruoyi/common/oss/core/OssClient.java @@ -47,7 +47,7 @@ public class OssClient { this.properties = ossProperties; try { AwsClientBuilder.EndpointConfiguration endpointConfig = - new AwsClientBuilder.EndpointConfiguration(properties.getEndpoint(), properties.getRegion()); + new AwsClientBuilder.EndpointConfiguration(properties.getEndpoint(), properties.getRegion()); AWSCredentials credentials = new BasicAWSCredentials(properties.getAccessKey(), properties.getSecretKey()); AWSCredentialsProvider credentialsProvider = new AWSStaticCredentialsProvider(credentials); @@ -58,10 +58,10 @@ public class OssClient { clientConfig.setProtocol(Protocol.HTTP); } AmazonS3ClientBuilder build = AmazonS3Client.builder() - .withEndpointConfiguration(endpointConfig) - .withClientConfiguration(clientConfig) - .withCredentials(credentialsProvider) - .disableChunkedEncoding(); + .withEndpointConfiguration(endpointConfig) + .withClientConfiguration(clientConfig) + .withCredentials(credentialsProvider) + .disableChunkedEncoding(); if (!StringUtils.containsAny(properties.getEndpoint(), OssConstant.CLOUD_SERVICE)) { // minio 使用https限制使用域名访问 需要此配置 站点填域名 build.enablePathStyleAccess(); @@ -77,6 +77,36 @@ public class OssClient { } } + private static String getPolicy(String bucketName, PolicyType policyType) { + StringBuilder builder = new StringBuilder(); + builder.append("{\n\"Statement\": [\n{\n\"Action\": [\n"); + builder.append(switch (policyType) { + case WRITE -> "\"s3:GetBucketLocation\",\n\"s3:ListBucketMultipartUploads\"\n"; + case READ_WRITE -> "\"s3:GetBucketLocation\",\n\"s3:ListBucket\",\n\"s3:ListBucketMultipartUploads\"\n"; + default -> "\"s3:GetBucketLocation\"\n"; + }); + builder.append("],\n\"Effect\": \"Allow\",\n\"Principal\": \"*\",\n\"Resource\": \"arn:aws:s3:::"); + builder.append(bucketName); + builder.append("\"\n},\n"); + if (policyType == PolicyType.READ) { + builder.append("{\n\"Action\": [\n\"s3:ListBucket\"\n],\n\"Effect\": \"Deny\",\n\"Principal\": \"*\",\n\"Resource\": \"arn:aws:s3:::"); + builder.append(bucketName); + builder.append("\"\n},\n"); + } + builder.append("{\n\"Action\": "); + builder.append(switch (policyType) { + case WRITE -> + "[\n\"s3:AbortMultipartUpload\",\n\"s3:DeleteObject\",\n\"s3:ListMultipartUploadParts\",\n\"s3:PutObject\"\n],\n"; + case READ_WRITE -> + "[\n\"s3:AbortMultipartUpload\",\n\"s3:DeleteObject\",\n\"s3:GetObject\",\n\"s3:ListMultipartUploadParts\",\n\"s3:PutObject\"\n],\n"; + default -> "\"s3:GetObject\",\n"; + }); + builder.append("\"Effect\": \"Allow\",\n\"Principal\": \"*\",\n\"Resource\": \"arn:aws:s3:::"); + builder.append(bucketName); + builder.append("/*\"\n}\n],\n\"Version\": \"2012-10-17\"\n}\n"); + return builder.toString(); + } + public void createBucket() { try { String bucketName = properties.getBucketName(); @@ -178,7 +208,6 @@ public class OssClient { return path + suffix; } - public String getConfigKey() { return configKey; } @@ -191,9 +220,9 @@ public class OssClient { */ public String getPrivateUrl(String objectKey, Integer second) { GeneratePresignedUrlRequest generatePresignedUrlRequest = - new GeneratePresignedUrlRequest(properties.getBucketName(), objectKey) - .withMethod(HttpMethod.GET) - .withExpiration(new Date(System.currentTimeMillis() + 1000L * second)); + new GeneratePresignedUrlRequest(properties.getBucketName(), objectKey) + .withMethod(HttpMethod.GET) + .withExpiration(new Date(System.currentTimeMillis() + 1000L * second)); URL url = client.generatePresignedUrl(generatePresignedUrlRequest); return url.toString(); } @@ -214,32 +243,4 @@ public class OssClient { return AccessPolicyType.getByType(properties.getAccessPolicy()); } - private static String getPolicy(String bucketName, PolicyType policyType) { - StringBuilder builder = new StringBuilder(); - builder.append("{\n\"Statement\": [\n{\n\"Action\": [\n"); - builder.append(switch (policyType) { - case WRITE -> "\"s3:GetBucketLocation\",\n\"s3:ListBucketMultipartUploads\"\n"; - case READ_WRITE -> "\"s3:GetBucketLocation\",\n\"s3:ListBucket\",\n\"s3:ListBucketMultipartUploads\"\n"; - default -> "\"s3:GetBucketLocation\"\n"; - }); - builder.append("],\n\"Effect\": \"Allow\",\n\"Principal\": \"*\",\n\"Resource\": \"arn:aws:s3:::"); - builder.append(bucketName); - builder.append("\"\n},\n"); - if (policyType == PolicyType.READ) { - builder.append("{\n\"Action\": [\n\"s3:ListBucket\"\n],\n\"Effect\": \"Deny\",\n\"Principal\": \"*\",\n\"Resource\": \"arn:aws:s3:::"); - builder.append(bucketName); - builder.append("\"\n},\n"); - } - builder.append("{\n\"Action\": "); - builder.append(switch (policyType) { - case WRITE -> "[\n\"s3:AbortMultipartUpload\",\n\"s3:DeleteObject\",\n\"s3:ListMultipartUploadParts\",\n\"s3:PutObject\"\n],\n"; - case READ_WRITE -> "[\n\"s3:AbortMultipartUpload\",\n\"s3:DeleteObject\",\n\"s3:GetObject\",\n\"s3:ListMultipartUploadParts\",\n\"s3:PutObject\"\n],\n"; - default -> "\"s3:GetObject\",\n"; - }); - builder.append("\"Effect\": \"Allow\",\n\"Principal\": \"*\",\n\"Resource\": \"arn:aws:s3:::"); - builder.append(bucketName); - builder.append("/*\"\n}\n],\n\"Version\": \"2012-10-17\"\n}\n"); - return builder.toString(); - } - } diff --git a/ruoyi-common/ruoyi-common-oss/src/main/java/org/ruoyi/common/oss/enumd/AccessPolicyType.java b/ruoyi-common/ruoyi-common-oss/src/main/java/org/ruoyi/common/oss/enumd/AccessPolicyType.java index cd440696..68515131 100644 --- a/ruoyi-common/ruoyi-common-oss/src/main/java/org/ruoyi/common/oss/enumd/AccessPolicyType.java +++ b/ruoyi-common/ruoyi-common-oss/src/main/java/org/ruoyi/common/oss/enumd/AccessPolicyType.java @@ -26,7 +26,7 @@ public enum AccessPolicyType { /** * custom */ - CUSTOM("2",CannedAccessControlList.PublicRead, PolicyType.READ); + CUSTOM("2", CannedAccessControlList.PublicRead, PolicyType.READ); /** * 桶 权限类型 diff --git a/ruoyi-common/ruoyi-common-pay/pom.xml b/ruoyi-common/ruoyi-common-pay/pom.xml index d4e2cd94..6a160051 100644 --- a/ruoyi-common/ruoyi-common-pay/pom.xml +++ b/ruoyi-common/ruoyi-common-pay/pom.xml @@ -1,6 +1,6 @@ - 4.0.0 diff --git a/ruoyi-common/ruoyi-common-pay/src/main/java/org/ruoyi/common/config/PayConfig.java b/ruoyi-common/ruoyi-common-pay/src/main/java/org/ruoyi/common/config/PayConfig.java index a5c92c3b..51127ec5 100644 --- a/ruoyi-common/ruoyi-common-pay/src/main/java/org/ruoyi/common/config/PayConfig.java +++ b/ruoyi-common/ruoyi-common-pay/src/main/java/org/ruoyi/common/config/PayConfig.java @@ -13,7 +13,7 @@ public class PayConfig { /** * 商户ID */ - private String pid; + private String pid; /** * 接口地址 @@ -23,7 +23,7 @@ public class PayConfig { /** * 私钥 */ - private String key ; + private String key; /** * 服务器异步通知地址 diff --git a/ruoyi-common/ruoyi-common-pay/src/main/java/org/ruoyi/common/config/PayInit.java b/ruoyi-common/ruoyi-common-pay/src/main/java/org/ruoyi/common/config/PayInit.java index 4c9c8865..f358c233 100644 --- a/ruoyi-common/ruoyi-common-pay/src/main/java/org/ruoyi/common/config/PayInit.java +++ b/ruoyi-common/ruoyi-common-pay/src/main/java/org/ruoyi/common/config/PayInit.java @@ -40,7 +40,7 @@ public class PayInit { payConfig.setReturn_url(getKey("return_url")); } - public String getKey(String key){ + public String getKey(String key) { return configService.getConfigValue("pay", key); } diff --git a/ruoyi-common/ruoyi-common-pay/src/main/java/org/ruoyi/common/service/PayService.java b/ruoyi-common/ruoyi-common-pay/src/main/java/org/ruoyi/common/service/PayService.java index f11ed6e4..24490fbc 100644 --- a/ruoyi-common/ruoyi-common-pay/src/main/java/org/ruoyi/common/service/PayService.java +++ b/ruoyi-common/ruoyi-common-pay/src/main/java/org/ruoyi/common/service/PayService.java @@ -11,12 +11,12 @@ public interface PayService { /** * 获取支付地址 * - * @Date 2023/7/3 * @param orderNo * @param name * @param money * @param clientIp * @return String + * @Date 2023/7/3 **/ String getPayUrl(String orderNo, String name, double money, String clientIp); diff --git a/ruoyi-common/ruoyi-common-pay/src/main/java/org/ruoyi/common/service/impl/PayServiceImpl.java b/ruoyi-common/ruoyi-common-pay/src/main/java/org/ruoyi/common/service/impl/PayServiceImpl.java index e020d258..9d259690 100644 --- a/ruoyi-common/ruoyi-common-pay/src/main/java/org/ruoyi/common/service/impl/PayServiceImpl.java +++ b/ruoyi-common/ruoyi-common-pay/src/main/java/org/ruoyi/common/service/impl/PayServiceImpl.java @@ -14,6 +14,7 @@ import java.util.Map; /** * 支付服务 + * * @author Admin */ @Service @@ -28,8 +29,8 @@ public class PayServiceImpl implements PayService { String out_trade_no = orderNo, sign = ""; //封装请求参数 String mdString = "clientip=" + clientIp + "&device=" + payConfig.getDevice() + "&money=" + money + "&name=" + name + "&" + - "notify_url=" + payConfig.getNotify_url() + "&out_trade_no=" + out_trade_no + "&pid=" + payConfig.getPid() + "&return_url=" + payConfig.getReturn_url() + - "&type=" + payConfig.getType() + payConfig.getKey(); + "notify_url=" + payConfig.getNotify_url() + "&out_trade_no=" + out_trade_no + "&pid=" + payConfig.getPid() + "&return_url=" + payConfig.getReturn_url() + + "&type=" + payConfig.getType() + payConfig.getKey(); sign = MD5Util.GetMD5Code(mdString); Map map = new HashMap<>(10); map.put("clientip", clientIp); @@ -44,7 +45,7 @@ public class PayServiceImpl implements PayService { map.put("type", payConfig.getType()); map.put("sign", sign); String body = HttpUtil.post(payConfig.getPayUrl(), map); - log.info("支付返回信息:{},配置信息: {}",body,payConfig); + log.info("支付返回信息:{},配置信息: {}", body, payConfig); JSONObject jsonObject = new JSONObject(body); return (String) jsonObject.get("qrcode"); } diff --git a/ruoyi-common/ruoyi-common-pay/src/main/java/org/ruoyi/common/utils/MD5Util.java b/ruoyi-common/ruoyi-common-pay/src/main/java/org/ruoyi/common/utils/MD5Util.java index 3aec5f28..f602c91a 100644 --- a/ruoyi-common/ruoyi-common-pay/src/main/java/org/ruoyi/common/utils/MD5Util.java +++ b/ruoyi-common/ruoyi-common-pay/src/main/java/org/ruoyi/common/utils/MD5Util.java @@ -17,8 +17,8 @@ public class MD5Util { /** * 全局数组 */ - public final static String[] strDigits = { "0", "1", "2", "3", "4", "5", - "6", "7", "8", "9", "a", "b", "c", "d", "e", "f" }; + public final static String[] strDigits = {"0", "1", "2", "3", "4", "5", + "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"}; public MD5Util() { } @@ -26,9 +26,9 @@ public class MD5Util { /** * 返回形式为数字跟字符串 * - * @Date 2023/7/3 * @param bByte * @return String + * @Date 2023/7/3 **/ public static String byteToArrayString(byte bByte) { int iRet = bByte; @@ -43,9 +43,9 @@ public class MD5Util { /** * 转换字节数组为16进制字串 * - * @Date 2023/7/3 * @param bByte * @return String + * @Date 2023/7/3 **/ public static String byteToString(byte[] bByte) { StringBuffer sBuffer = new StringBuffer(); @@ -58,9 +58,9 @@ public class MD5Util { /** * 生成md5代码 * - * @Date 2023/7/3 * @param strObj * @return String + * @Date 2023/7/3 **/ public static String GetMD5Code(String strObj) { String resultString = null; diff --git a/ruoyi-common/ruoyi-common-ratelimiter/pom.xml b/ruoyi-common/ruoyi-common-ratelimiter/pom.xml index cc327952..77eb2196 100644 --- a/ruoyi-common/ruoyi-common-ratelimiter/pom.xml +++ b/ruoyi-common/ruoyi-common-ratelimiter/pom.xml @@ -1,6 +1,6 @@ - org.ruoyi diff --git a/ruoyi-common/ruoyi-common-ratelimiter/src/main/java/org/ruoyi/common/ratelimiter/aspectj/RateLimiterAspect.java b/ruoyi-common/ruoyi-common-ratelimiter/src/main/java/org/ruoyi/common/ratelimiter/aspectj/RateLimiterAspect.java index fc776163..08da5e75 100644 --- a/ruoyi-common/ruoyi-common-ratelimiter/src/main/java/org/ruoyi/common/ratelimiter/aspectj/RateLimiterAspect.java +++ b/ruoyi-common/ruoyi-common-ratelimiter/src/main/java/org/ruoyi/common/ratelimiter/aspectj/RateLimiterAspect.java @@ -103,7 +103,7 @@ public class RateLimiterAspect { try { Expression expression; if (StringUtils.startsWith(key, parserContext.getExpressionPrefix()) - && StringUtils.endsWith(key, parserContext.getExpressionSuffix())) { + && StringUtils.endsWith(key, parserContext.getExpressionSuffix())) { expression = parser.parseExpression(key, parserContext); } else { expression = parser.parseExpression(key); diff --git a/ruoyi-common/ruoyi-common-redis/pom.xml b/ruoyi-common/ruoyi-common-redis/pom.xml index a3c2fe6a..9576b890 100644 --- a/ruoyi-common/ruoyi-common-redis/pom.xml +++ b/ruoyi-common/ruoyi-common-redis/pom.xml @@ -1,6 +1,6 @@ - org.ruoyi diff --git a/ruoyi-common/ruoyi-common-redis/src/main/java/org/ruoyi/common/redis/config/RedisConfig.java b/ruoyi-common/ruoyi-common-redis/src/main/java/org/ruoyi/common/redis/config/RedisConfig.java index 6ac81665..e9e91586 100644 --- a/ruoyi-common/ruoyi-common-redis/src/main/java/org/ruoyi/common/redis/config/RedisConfig.java +++ b/ruoyi-common/ruoyi-common-redis/src/main/java/org/ruoyi/common/redis/config/RedisConfig.java @@ -36,37 +36,37 @@ public class RedisConfig { public RedissonAutoConfigurationCustomizer redissonCustomizer() { return config -> { config.setThreads(redissonProperties.getThreads()) - .setNettyThreads(redissonProperties.getNettyThreads()) - .setCodec(new JsonJacksonCodec(objectMapper)); + .setNettyThreads(redissonProperties.getNettyThreads()) + .setCodec(new JsonJacksonCodec(objectMapper)); RedissonProperties.SingleServerConfig singleServerConfig = redissonProperties.getSingleServerConfig(); if (ObjectUtil.isNotNull(singleServerConfig)) { // 使用单机模式 config.useSingleServer() - //设置redis key前缀 - .setNameMapper(new KeyPrefixHandler(redissonProperties.getKeyPrefix())) - .setTimeout(singleServerConfig.getTimeout()) - .setClientName(singleServerConfig.getClientName()) - .setIdleConnectionTimeout(singleServerConfig.getIdleConnectionTimeout()) - .setSubscriptionConnectionPoolSize(singleServerConfig.getSubscriptionConnectionPoolSize()) - .setConnectionMinimumIdleSize(singleServerConfig.getConnectionMinimumIdleSize()) - .setConnectionPoolSize(singleServerConfig.getConnectionPoolSize()); + //设置redis key前缀 + .setNameMapper(new KeyPrefixHandler(redissonProperties.getKeyPrefix())) + .setTimeout(singleServerConfig.getTimeout()) + .setClientName(singleServerConfig.getClientName()) + .setIdleConnectionTimeout(singleServerConfig.getIdleConnectionTimeout()) + .setSubscriptionConnectionPoolSize(singleServerConfig.getSubscriptionConnectionPoolSize()) + .setConnectionMinimumIdleSize(singleServerConfig.getConnectionMinimumIdleSize()) + .setConnectionPoolSize(singleServerConfig.getConnectionPoolSize()); } // 集群配置方式 参考下方注释 RedissonProperties.ClusterServersConfig clusterServersConfig = redissonProperties.getClusterServersConfig(); if (ObjectUtil.isNotNull(clusterServersConfig)) { config.useClusterServers() - //设置redis key前缀 - .setNameMapper(new KeyPrefixHandler(redissonProperties.getKeyPrefix())) - .setTimeout(clusterServersConfig.getTimeout()) - .setClientName(clusterServersConfig.getClientName()) - .setIdleConnectionTimeout(clusterServersConfig.getIdleConnectionTimeout()) - .setSubscriptionConnectionPoolSize(clusterServersConfig.getSubscriptionConnectionPoolSize()) - .setMasterConnectionMinimumIdleSize(clusterServersConfig.getMasterConnectionMinimumIdleSize()) - .setMasterConnectionPoolSize(clusterServersConfig.getMasterConnectionPoolSize()) - .setSlaveConnectionMinimumIdleSize(clusterServersConfig.getSlaveConnectionMinimumIdleSize()) - .setSlaveConnectionPoolSize(clusterServersConfig.getSlaveConnectionPoolSize()) - .setReadMode(clusterServersConfig.getReadMode()) - .setSubscriptionMode(clusterServersConfig.getSubscriptionMode()); + //设置redis key前缀 + .setNameMapper(new KeyPrefixHandler(redissonProperties.getKeyPrefix())) + .setTimeout(clusterServersConfig.getTimeout()) + .setClientName(clusterServersConfig.getClientName()) + .setIdleConnectionTimeout(clusterServersConfig.getIdleConnectionTimeout()) + .setSubscriptionConnectionPoolSize(clusterServersConfig.getSubscriptionConnectionPoolSize()) + .setMasterConnectionMinimumIdleSize(clusterServersConfig.getMasterConnectionMinimumIdleSize()) + .setMasterConnectionPoolSize(clusterServersConfig.getMasterConnectionPoolSize()) + .setSlaveConnectionMinimumIdleSize(clusterServersConfig.getSlaveConnectionMinimumIdleSize()) + .setSlaveConnectionPoolSize(clusterServersConfig.getSlaveConnectionPoolSize()) + .setReadMode(clusterServersConfig.getReadMode()) + .setSubscriptionMode(clusterServersConfig.getSubscriptionMode()); } log.info("初始化 redis 配置"); }; diff --git a/ruoyi-common/ruoyi-common-redis/src/main/java/org/ruoyi/common/redis/manager/PlusSpringCacheManager.java b/ruoyi-common/ruoyi-common-redis/src/main/java/org/ruoyi/common/redis/manager/PlusSpringCacheManager.java index 800a8a71..30db2c08 100644 --- a/ruoyi-common/ruoyi-common-redis/src/main/java/org/ruoyi/common/redis/manager/PlusSpringCacheManager.java +++ b/ruoyi-common/ruoyi-common-redis/src/main/java/org/ruoyi/common/redis/manager/PlusSpringCacheManager.java @@ -1,12 +1,12 @@ /** * Copyright (c) 2013-2021 Nikita Koksharov - * + *

* Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

* Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -45,14 +45,11 @@ import java.util.concurrent.ConcurrentMap; @SuppressWarnings("unchecked") public class PlusSpringCacheManager implements CacheManager { - private boolean dynamic = true; - - private boolean allowNullValues = true; - - private boolean transactionAware = true; - Map configMap = new ConcurrentHashMap<>(); ConcurrentMap instanceMap = new ConcurrentHashMap<>(); + private boolean dynamic = true; + private boolean allowNullValues = true; + private boolean transactionAware = true; /** * Creates CacheManager supplied by Redisson instance @@ -84,25 +81,6 @@ public class PlusSpringCacheManager implements CacheManager { this.transactionAware = transactionAware; } - /** - * Defines 'fixed' cache names. - * A new cache instance will not be created in dynamic for non-defined names. - *

- * `null` parameter setups dynamic mode - * - * @param names of caches - */ - public void setCacheNames(Collection names) { - if (names != null) { - for (String name : names) { - getCache(name); - } - dynamic = false; - } else { - dynamic = true; - } - } - /** * Set cache config mapped by cache name * @@ -187,5 +165,24 @@ public class PlusSpringCacheManager implements CacheManager { return Collections.unmodifiableSet(configMap.keySet()); } + /** + * Defines 'fixed' cache names. + * A new cache instance will not be created in dynamic for non-defined names. + *

+ * `null` parameter setups dynamic mode + * + * @param names of caches + */ + public void setCacheNames(Collection names) { + if (names != null) { + for (String name : names) { + getCache(name); + } + dynamic = false; + } else { + dynamic = true; + } + } + } diff --git a/ruoyi-common/ruoyi-common-satoken/pom.xml b/ruoyi-common/ruoyi-common-satoken/pom.xml index 9883296f..42dbba34 100644 --- a/ruoyi-common/ruoyi-common-satoken/pom.xml +++ b/ruoyi-common/ruoyi-common-satoken/pom.xml @@ -1,6 +1,6 @@ - org.ruoyi diff --git a/ruoyi-common/ruoyi-common-satoken/src/main/java/org/ruoyi/common/satoken/listener/UserActionListener.java b/ruoyi-common/ruoyi-common-satoken/src/main/java/org/ruoyi/common/satoken/listener/UserActionListener.java index 02f1ad6a..58e236d5 100644 --- a/ruoyi-common/ruoyi-common-satoken/src/main/java/org/ruoyi/common/satoken/listener/UserActionListener.java +++ b/ruoyi-common/ruoyi-common-satoken/src/main/java/org/ruoyi/common/satoken/listener/UserActionListener.java @@ -42,14 +42,14 @@ public class UserActionListener implements SaTokenListener { LoginUser user = LoginHelper.getLoginUser(); UserOnlineDTO dto = new UserOnlineDTO(); dto.setIpaddr(ip); - // dto.setLoginLocation(AddressUtils.getRealAddressByIP(ip)); + // dto.setLoginLocation(AddressUtils.getRealAddressByIP(ip)); dto.setBrowser(userAgent.getBrowser().getName()); dto.setOs(userAgent.getOs().getName()); dto.setLoginTime(System.currentTimeMillis()); dto.setTokenId(tokenValue); dto.setUserName(user.getUsername()); dto.setDeptName(user.getDeptName()); - if(tokenConfig.getTimeout() == -1) { + if (tokenConfig.getTimeout() == -1) { RedisUtils.setCacheObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue, dto); } else { RedisUtils.setCacheObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue, dto, Duration.ofSeconds(tokenConfig.getTimeout())); diff --git a/ruoyi-common/ruoyi-common-satoken/src/main/java/org/ruoyi/common/satoken/utils/LoginHelper.java b/ruoyi-common/ruoyi-common-satoken/src/main/java/org/ruoyi/common/satoken/utils/LoginHelper.java index b562ba8a..e34e892a 100644 --- a/ruoyi-common/ruoyi-common-satoken/src/main/java/org/ruoyi/common/satoken/utils/LoginHelper.java +++ b/ruoyi-common/ruoyi-common-satoken/src/main/java/org/ruoyi/common/satoken/utils/LoginHelper.java @@ -63,8 +63,8 @@ public class LoginHelper { model.setDevice(deviceType.getDevice()); } StpUtil.login(loginUser.getLoginId(), - model.setExtra(TENANT_KEY, loginUser.getTenantId()) - .setExtra(USER_KEY, loginUser.getUserId())); + model.setExtra(TENANT_KEY, loginUser.getTenantId()) + .setExtra(USER_KEY, loginUser.getUserId())); StpUtil.getTokenSession().set(LOGIN_USER_KEY, loginUser); } @@ -78,9 +78,10 @@ public class LoginHelper { } SaSession tokenSession = StpUtil.getTokenSession(); if (tokenSession != null) { - loginUser = (LoginUser) tokenSession.get(LOGIN_USER_KEY); + loginUser = (LoginUser) tokenSession.get(LOGIN_USER_KEY); SaHolder.getStorage().set(LOGIN_USER_KEY, loginUser); - }; + } + ; return loginUser; } diff --git a/ruoyi-common/ruoyi-common-security/pom.xml b/ruoyi-common/ruoyi-common-security/pom.xml index c22b3278..75007964 100644 --- a/ruoyi-common/ruoyi-common-security/pom.xml +++ b/ruoyi-common/ruoyi-common-security/pom.xml @@ -1,6 +1,6 @@ - org.ruoyi diff --git a/ruoyi-common/ruoyi-common-security/src/main/java/org/ruoyi/common/security/config/SecurityConfig.java b/ruoyi-common/ruoyi-common-security/src/main/java/org/ruoyi/common/security/config/SecurityConfig.java index 339ecc68..a318e840 100644 --- a/ruoyi-common/ruoyi-common-security/src/main/java/org/ruoyi/common/security/config/SecurityConfig.java +++ b/ruoyi-common/ruoyi-common-security/src/main/java/org/ruoyi/common/security/config/SecurityConfig.java @@ -34,26 +34,26 @@ public class SecurityConfig implements WebMvcConfigurer { public void addInterceptors(InterceptorRegistry registry) { // 注册路由拦截器,自定义验证规则 registry.addInterceptor(new SaInterceptor(handler -> { - AllUrlHandler allUrlHandler = SpringUtils.getBean(AllUrlHandler.class); - // 登录验证 -- 排除多个路径 - SaRouter - // 获取所有的 - .match(allUrlHandler.getUrls()) - // 对未排除的路径进行检查 - .check(() -> { - // 检查是否登录 是否有token - StpUtil.checkLogin(); + AllUrlHandler allUrlHandler = SpringUtils.getBean(AllUrlHandler.class); + // 登录验证 -- 排除多个路径 + SaRouter + // 获取所有的 + .match(allUrlHandler.getUrls()) + // 对未排除的路径进行检查 + .check(() -> { + // 检查是否登录 是否有token + StpUtil.checkLogin(); - // 有效率影响 用于临时测试 - // if (log.isDebugEnabled()) { - // log.debug("剩余有效时间: {}", StpUtil.getTokenTimeout()); - // log.debug("临时有效时间: {}", StpUtil.getTokenActivityTimeout()); - // } + // 有效率影响 用于临时测试 + // if (log.isDebugEnabled()) { + // log.debug("剩余有效时间: {}", StpUtil.getTokenTimeout()); + // log.debug("临时有效时间: {}", StpUtil.getTokenActivityTimeout()); + // } - }); - })).addPathPatterns("/**") - // 排除不需要拦截的路径 - .excludePathPatterns(securityProperties.getExcludes()); + }); + })).addPathPatterns("/**") + // 排除不需要拦截的路径 + .excludePathPatterns(securityProperties.getExcludes()); } } diff --git a/ruoyi-common/ruoyi-common-security/src/main/java/org/ruoyi/common/security/handler/GlobalExceptionHandler.java b/ruoyi-common/ruoyi-common-security/src/main/java/org/ruoyi/common/security/handler/GlobalExceptionHandler.java index d5445691..4a13a850 100644 --- a/ruoyi-common/ruoyi-common-security/src/main/java/org/ruoyi/common/security/handler/GlobalExceptionHandler.java +++ b/ruoyi-common/ruoyi-common-security/src/main/java/org/ruoyi/common/security/handler/GlobalExceptionHandler.java @@ -64,7 +64,7 @@ public class GlobalExceptionHandler { */ @ExceptionHandler(HttpRequestMethodNotSupportedException.class) public R handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException e, - HttpServletRequest request) { + HttpServletRequest request) { String requestURI = request.getRequestURI(); log.error("请求地址'{}',不支持'{}'请求", requestURI, e.getMethod()); return R.fail(e.getMessage()); diff --git a/ruoyi-common/ruoyi-common-sensitive/pom.xml b/ruoyi-common/ruoyi-common-sensitive/pom.xml index 6f91ae83..4b65a44d 100644 --- a/ruoyi-common/ruoyi-common-sensitive/pom.xml +++ b/ruoyi-common/ruoyi-common-sensitive/pom.xml @@ -1,6 +1,6 @@ - org.ruoyi diff --git a/ruoyi-common/ruoyi-common-sms/pom.xml b/ruoyi-common/ruoyi-common-sms/pom.xml index 1a0ccdc8..7a6769ca 100644 --- a/ruoyi-common/ruoyi-common-sms/pom.xml +++ b/ruoyi-common/ruoyi-common-sms/pom.xml @@ -1,6 +1,6 @@ - org.ruoyi diff --git a/ruoyi-common/ruoyi-common-sms/src/main/java/org/ruoyi/common/sms/core/AliyunSmsTemplate.java b/ruoyi-common/ruoyi-common-sms/src/main/java/org/ruoyi/common/sms/core/AliyunSmsTemplate.java index 68b2cd2d..56cd0044 100644 --- a/ruoyi-common/ruoyi-common-sms/src/main/java/org/ruoyi/common/sms/core/AliyunSmsTemplate.java +++ b/ruoyi-common/ruoyi-common-sms/src/main/java/org/ruoyi/common/sms/core/AliyunSmsTemplate.java @@ -29,12 +29,12 @@ public class AliyunSmsTemplate implements SmsTemplate { public AliyunSmsTemplate(SmsProperties smsProperties) { this.properties = smsProperties; Config config = new Config() - // 您的AccessKey ID - .setAccessKeyId(smsProperties.getAccessKeyId()) - // 您的AccessKey Secret - .setAccessKeySecret(smsProperties.getAccessKeySecret()) - // 访问的域名 - .setEndpoint(smsProperties.getEndpoint()); + // 您的AccessKey ID + .setAccessKeyId(smsProperties.getAccessKeyId()) + // 您的AccessKey Secret + .setAccessKeySecret(smsProperties.getAccessKeySecret()) + // 访问的域名 + .setEndpoint(smsProperties.getEndpoint()); this.client = new Client(config); } @@ -47,17 +47,17 @@ public class AliyunSmsTemplate implements SmsTemplate { throw new SmsException("模板ID不能为空"); } SendSmsRequest req = new SendSmsRequest() - .setPhoneNumbers(phones) - .setSignName(properties.getSignName()) - .setTemplateCode(templateId) - .setTemplateParam(JsonUtils.toJsonString(param)); + .setPhoneNumbers(phones) + .setSignName(properties.getSignName()) + .setTemplateCode(templateId) + .setTemplateParam(JsonUtils.toJsonString(param)); try { SendSmsResponse resp = client.sendSms(req); return SmsResult.builder() - .isSuccess("OK".equals(resp.getBody().getCode())) - .message(resp.getBody().getMessage()) - .response(JsonUtils.toJsonString(resp)) - .build(); + .isSuccess("OK".equals(resp.getBody().getCode())) + .message(resp.getBody().getMessage()) + .response(JsonUtils.toJsonString(resp)) + .build(); } catch (Exception e) { throw new SmsException(e.getMessage()); } diff --git a/ruoyi-common/ruoyi-common-sms/src/main/java/org/ruoyi/common/sms/core/TencentSmsTemplate.java b/ruoyi-common/ruoyi-common-sms/src/main/java/org/ruoyi/common/sms/core/TencentSmsTemplate.java index 4c2d642d..d434b6a1 100644 --- a/ruoyi-common/ruoyi-common-sms/src/main/java/org/ruoyi/common/sms/core/TencentSmsTemplate.java +++ b/ruoyi-common/ruoyi-common-sms/src/main/java/org/ruoyi/common/sms/core/TencentSmsTemplate.java @@ -64,9 +64,9 @@ public class TencentSmsTemplate implements SmsTemplate { try { SendSmsResponse resp = client.SendSms(req); SmsResult.SmsResultBuilder builder = SmsResult.builder() - .isSuccess(true) - .message("send success") - .response(JsonUtils.toJsonString(resp)); + .isSuccess(true) + .message("send success") + .response(JsonUtils.toJsonString(resp)); for (SendStatus sendStatus : resp.getSendStatusSet()) { if (!"Ok".equals(sendStatus.getCode())) { builder.isSuccess(false).message(sendStatus.getMessage()); diff --git a/ruoyi-common/ruoyi-common-tenant/pom.xml b/ruoyi-common/ruoyi-common-tenant/pom.xml index 22e4ff0b..7b8b9519 100644 --- a/ruoyi-common/ruoyi-common-tenant/pom.xml +++ b/ruoyi-common/ruoyi-common-tenant/pom.xml @@ -1,6 +1,6 @@ - org.ruoyi diff --git a/ruoyi-common/ruoyi-common-tenant/src/main/java/org/ruoyi/common/tenant/handle/PlusTenantLineHandler.java b/ruoyi-common/ruoyi-common-tenant/src/main/java/org/ruoyi/common/tenant/handle/PlusTenantLineHandler.java index 2f627a6f..6c3ad003 100644 --- a/ruoyi-common/ruoyi-common-tenant/src/main/java/org/ruoyi/common/tenant/handle/PlusTenantLineHandler.java +++ b/ruoyi-common/ruoyi-common-tenant/src/main/java/org/ruoyi/common/tenant/handle/PlusTenantLineHandler.java @@ -47,8 +47,8 @@ public class PlusTenantLineHandler implements TenantLineHandler { List excludes = tenantProperties.getExcludes(); // 非业务表 List tables = ListUtil.toList( - "gen_table", - "gen_table_column" + "gen_table", + "gen_table_column" ); tables.addAll(excludes); return tables.contains(tableName); diff --git a/ruoyi-common/ruoyi-common-tenant/src/main/java/org/ruoyi/common/tenant/helper/TenantHelper.java b/ruoyi-common/ruoyi-common-tenant/src/main/java/org/ruoyi/common/tenant/helper/TenantHelper.java index dc72b87e..a10b4dde 100644 --- a/ruoyi-common/ruoyi-common-tenant/src/main/java/org/ruoyi/common/tenant/helper/TenantHelper.java +++ b/ruoyi-common/ruoyi-common-tenant/src/main/java/org/ruoyi/common/tenant/helper/TenantHelper.java @@ -79,21 +79,6 @@ public class TenantHelper { } } - /** - * 设置动态租户(一直有效 需要手动清理) - *

- * 如果为非web环境 那么只在当前线程内生效 - */ - public static void setDynamic(String tenantId) { - if (!SpringMVCUtil.isWeb()) { - TEMP_DYNAMIC_TENANT.set(tenantId); - return; - } - String cacheKey = DYNAMIC_TENANT_KEY + ":" + LoginHelper.getUserId(); - RedisUtils.setCacheObject(cacheKey, tenantId); - SaHolder.getStorage().set(cacheKey, tenantId); - } - /** * 设置动态租户(一直有效 需要手动清理) *

@@ -134,6 +119,21 @@ public class TenantHelper { return tenantId; } + /** + * 设置动态租户(一直有效 需要手动清理) + *

+ * 如果为非web环境 那么只在当前线程内生效 + */ + public static void setDynamic(String tenantId) { + if (!SpringMVCUtil.isWeb()) { + TEMP_DYNAMIC_TENANT.set(tenantId); + return; + } + String cacheKey = DYNAMIC_TENANT_KEY + ":" + LoginHelper.getUserId(); + RedisUtils.setCacheObject(cacheKey, tenantId); + SaHolder.getStorage().set(cacheKey, tenantId); + } + /** * 清除动态租户 */ diff --git a/ruoyi-common/ruoyi-common-translation/pom.xml b/ruoyi-common/ruoyi-common-translation/pom.xml index eebe383f..e9c5f932 100644 --- a/ruoyi-common/ruoyi-common-translation/pom.xml +++ b/ruoyi-common/ruoyi-common-translation/pom.xml @@ -1,6 +1,6 @@ - org.ruoyi diff --git a/ruoyi-common/ruoyi-common-translation/src/main/java/org/ruoyi/common/translation/config/TranslationConfig.java b/ruoyi-common/ruoyi-common-translation/src/main/java/org/ruoyi/common/translation/config/TranslationConfig.java index bc564138..6f15922a 100644 --- a/ruoyi-common/ruoyi-common-translation/src/main/java/org/ruoyi/common/translation/config/TranslationConfig.java +++ b/ruoyi-common/ruoyi-common-translation/src/main/java/org/ruoyi/common/translation/config/TranslationConfig.java @@ -43,8 +43,8 @@ public class TranslationConfig { TranslationHandler.TRANSLATION_MAPPER.putAll(map); // 设置 Bean 序列化修改器 objectMapper.setSerializerFactory( - objectMapper.getSerializerFactory() - .withSerializerModifier(new TranslationBeanSerializerModifier())); + objectMapper.getSerializerFactory() + .withSerializerModifier(new TranslationBeanSerializerModifier())); } } diff --git a/ruoyi-common/ruoyi-common-web/pom.xml b/ruoyi-common/ruoyi-common-web/pom.xml index 97b9351c..468a141d 100644 --- a/ruoyi-common/ruoyi-common-web/pom.xml +++ b/ruoyi-common/ruoyi-common-web/pom.xml @@ -1,6 +1,6 @@ - org.ruoyi @@ -47,7 +47,6 @@ - org.springframework.boot spring-boot-starter-actuator diff --git a/ruoyi-common/ruoyi-common-web/src/main/java/org/ruoyi/common/web/config/ResourcesConfig.java b/ruoyi-common/ruoyi-common-web/src/main/java/org/ruoyi/common/web/config/ResourcesConfig.java index 37072b54..4cc3725e 100644 --- a/ruoyi-common/ruoyi-common-web/src/main/java/org/ruoyi/common/web/config/ResourcesConfig.java +++ b/ruoyi-common/ruoyi-common-web/src/main/java/org/ruoyi/common/web/config/ResourcesConfig.java @@ -34,20 +34,20 @@ public class ResourcesConfig implements WebMvcConfigurer { registry.addInterceptor(demoModeInterceptor) .addPathPatterns("/**") // 拦截所有路径 .excludePathPatterns( - // 排除静态资源 - "/css/**", - "/js/**", - "/images/**", - "/fonts/**", - "/favicon.ico", - // 排除错误页面 - "/error", - // 排除API文档 - "/*/api-docs/**", - "/swagger-ui/**", - "/webjars/**", - // 排除监控端点 - "/actuator/**" + // 排除静态资源 + "/css/**", + "/js/**", + "/images/**", + "/fonts/**", + "/favicon.ico", + // 排除错误页面 + "/error", + // 排除API文档 + "/*/api-docs/**", + "/swagger-ui/**", + "/webjars/**", + // 排除监控端点 + "/actuator/**" ); } } diff --git a/ruoyi-common/ruoyi-common-web/src/main/java/org/ruoyi/common/web/filter/RepeatableFilter.java b/ruoyi-common/ruoyi-common-web/src/main/java/org/ruoyi/common/web/filter/RepeatableFilter.java index ca68db44..471f5c99 100644 --- a/ruoyi-common/ruoyi-common-web/src/main/java/org/ruoyi/common/web/filter/RepeatableFilter.java +++ b/ruoyi-common/ruoyi-common-web/src/main/java/org/ruoyi/common/web/filter/RepeatableFilter.java @@ -20,10 +20,10 @@ public class RepeatableFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) - throws IOException, ServletException { + throws IOException, ServletException { ServletRequest requestWrapper = null; if (request instanceof HttpServletRequest - && StringUtils.startsWithIgnoreCase(request.getContentType(), MediaType.APPLICATION_JSON_VALUE)) { + && StringUtils.startsWithIgnoreCase(request.getContentType(), MediaType.APPLICATION_JSON_VALUE)) { requestWrapper = new RepeatedlyRequestWrapper((HttpServletRequest) request, response); } if (null == requestWrapper) { diff --git a/ruoyi-common/ruoyi-common-web/src/main/java/org/ruoyi/common/web/filter/XssFilter.java b/ruoyi-common/ruoyi-common-web/src/main/java/org/ruoyi/common/web/filter/XssFilter.java index edb604b8..4a0136dd 100644 --- a/ruoyi-common/ruoyi-common-web/src/main/java/org/ruoyi/common/web/filter/XssFilter.java +++ b/ruoyi-common/ruoyi-common-web/src/main/java/org/ruoyi/common/web/filter/XssFilter.java @@ -34,7 +34,7 @@ public class XssFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) - throws IOException, ServletException { + throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request; HttpServletResponse resp = (HttpServletResponse) response; if (handleExcludeURL(req, resp)) { diff --git a/ruoyi-common/ruoyi-common-web/src/main/java/org/ruoyi/common/web/interceptor/DemoModeInterceptor.java b/ruoyi-common/ruoyi-common-web/src/main/java/org/ruoyi/common/web/interceptor/DemoModeInterceptor.java index ded366f2..9d6051c5 100644 --- a/ruoyi-common/ruoyi-common-web/src/main/java/org/ruoyi/common/web/interceptor/DemoModeInterceptor.java +++ b/ruoyi-common/ruoyi-common-web/src/main/java/org/ruoyi/common/web/interceptor/DemoModeInterceptor.java @@ -51,9 +51,9 @@ public class DemoModeInterceptor implements HandlerInterceptor { */ private boolean isEditOperation(String method) { return "POST".equalsIgnoreCase(method) - || "PUT".equalsIgnoreCase(method) - || "DELETE".equalsIgnoreCase(method) - || "PATCH".equalsIgnoreCase(method); + || "PUT".equalsIgnoreCase(method) + || "DELETE".equalsIgnoreCase(method) + || "PATCH".equalsIgnoreCase(method); } /** diff --git a/ruoyi-common/ruoyi-common-web/src/main/java/org/ruoyi/common/web/interceptor/PlusWebInvokeTimeInterceptor.java b/ruoyi-common/ruoyi-common-web/src/main/java/org/ruoyi/common/web/interceptor/PlusWebInvokeTimeInterceptor.java index 11d87342..6a866566 100644 --- a/ruoyi-common/ruoyi-common-web/src/main/java/org/ruoyi/common/web/interceptor/PlusWebInvokeTimeInterceptor.java +++ b/ruoyi-common/ruoyi-common-web/src/main/java/org/ruoyi/common/web/interceptor/PlusWebInvokeTimeInterceptor.java @@ -32,8 +32,8 @@ public class PlusWebInvokeTimeInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String url = request.getMethod() + " " + request.getRequestURI(); - String domainName = request.getServerName(); - log.info("域名信息:{}",domainName); + String domainName = request.getServerName(); + log.info("域名信息:{}", domainName); // 打印请求参数 if (isJsonRequest(request)) { String jsonParam = ""; diff --git a/ruoyi-common/ruoyi-common-web/src/main/java/org/ruoyi/common/web/utils/UnsignedMathGenerator.java b/ruoyi-common/ruoyi-common-web/src/main/java/org/ruoyi/common/web/utils/UnsignedMathGenerator.java index 28e0d26e..ceea2971 100644 --- a/ruoyi-common/ruoyi-common-web/src/main/java/org/ruoyi/common/web/utils/UnsignedMathGenerator.java +++ b/ruoyi-common/ruoyi-common-web/src/main/java/org/ruoyi/common/web/utils/UnsignedMathGenerator.java @@ -46,8 +46,8 @@ public class UnsignedMathGenerator implements CodeGenerator { final int limit = getLimit(); int a = RandomUtil.randomInt(limit); int b = RandomUtil.randomInt(limit); - String max = Integer.toString(Math.max(a,b)); - String min = Integer.toString(Math.min(a,b)); + String max = Integer.toString(Math.max(a, b)); + String min = Integer.toString(Math.min(a, b)); max = StringUtils.rightPad(max, this.numberLength, CharUtil.SPACE); min = StringUtils.rightPad(min, this.numberLength, CharUtil.SPACE); diff --git a/ruoyi-extend/pom.xml b/ruoyi-extend/pom.xml index 3538eb94..2e393b6f 100644 --- a/ruoyi-extend/pom.xml +++ b/ruoyi-extend/pom.xml @@ -1,6 +1,6 @@ - 4.0.0 diff --git a/ruoyi-extend/ruoyi-ai-copilot/pom.xml b/ruoyi-extend/ruoyi-ai-copilot/pom.xml index ed17dad6..d36f23a0 100644 --- a/ruoyi-extend/ruoyi-ai-copilot/pom.xml +++ b/ruoyi-extend/ruoyi-ai-copilot/pom.xml @@ -1,6 +1,6 @@ - 4.0.0 diff --git a/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/CopilotApplication.java b/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/CopilotApplication.java index 18c8a89d..86000eeb 100644 --- a/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/CopilotApplication.java +++ b/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/CopilotApplication.java @@ -1,5 +1,7 @@ package com.example.demo; +import com.example.demo.config.AppProperties; +import com.example.demo.util.BrowserUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -11,9 +13,6 @@ import org.springframework.context.annotation.EnableAspectJAutoProxy; import org.springframework.context.event.EventListener; import org.springframework.core.env.Environment; -import com.example.demo.config.AppProperties; -import com.example.demo.util.BrowserUtil; - /** * 主要功能: * 1. 文件读取、写入、编辑 diff --git a/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/config/AppProperties.java b/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/config/AppProperties.java index 9c473f65..36155a2b 100644 --- a/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/config/AppProperties.java +++ b/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/config/AppProperties.java @@ -17,17 +17,46 @@ public class AppProperties { private Browser browser = new Browser(); // Getters and Setters - public Workspace getWorkspace() { return workspace; } - public void setWorkspace(Workspace workspace) { this.workspace = workspace; } + public Workspace getWorkspace() { + return workspace; + } - public Security getSecurity() { return security; } - public void setSecurity(Security security) { this.security = security; } + public void setWorkspace(Workspace workspace) { + this.workspace = workspace; + } - public Tools getTools() { return tools; } - public void setTools(Tools tools) { this.tools = tools; } + public Security getSecurity() { + return security; + } - public Browser getBrowser() { return browser; } - public void setBrowser(Browser browser) { this.browser = browser; } + public void setSecurity(Security security) { + this.security = security; + } + + public Tools getTools() { + return tools; + } + + public void setTools(Tools tools) { + this.tools = tools; + } + + public Browser getBrowser() { + return browser; + } + + public void setBrowser(Browser browser) { + this.browser = browser; + } + + /** + * 审批模式 + */ + public enum ApprovalMode { + DEFAULT, // 默认模式,危险操作需要确认 + AUTO_EDIT, // 自动编辑模式,文件编辑不需要确认 + YOLO // 完全自动模式,所有操作都不需要确认 + } /** * 工作空间配置 @@ -37,22 +66,35 @@ public class AppProperties { private String rootDirectory = Paths.get(System.getProperty("user.dir"), "workspace").toString(); private long maxFileSize = 10485760L; // 10MB private List allowedExtensions = List.of( - ".txt", ".md", ".java", ".js", ".ts", ".json", ".xml", - ".yml", ".yaml", ".properties", ".html", ".css", ".sql" + ".txt", ".md", ".java", ".js", ".ts", ".json", ".xml", + ".yml", ".yaml", ".properties", ".html", ".css", ".sql" ); // Getters and Setters - public String getRootDirectory() { return rootDirectory; } - public void setRootDirectory(String rootDirectory) { + public String getRootDirectory() { + return rootDirectory; + } + + public void setRootDirectory(String rootDirectory) { // 确保设置的路径也是跨平台兼容的 this.rootDirectory = Paths.get(rootDirectory).toString(); } - - public long getMaxFileSize() { return maxFileSize; } - public void setMaxFileSize(long maxFileSize) { this.maxFileSize = maxFileSize; } - - public List getAllowedExtensions() { return allowedExtensions; } - public void setAllowedExtensions(List allowedExtensions) { this.allowedExtensions = allowedExtensions; } + + public long getMaxFileSize() { + return maxFileSize; + } + + public void setMaxFileSize(long maxFileSize) { + this.maxFileSize = maxFileSize; + } + + public List getAllowedExtensions() { + return allowedExtensions; + } + + public void setAllowedExtensions(List allowedExtensions) { + this.allowedExtensions = allowedExtensions; + } } /** @@ -63,11 +105,21 @@ public class AppProperties { private List dangerousCommands = List.of("rm", "del", "format", "fdisk", "mkfs"); // Getters and Setters - public ApprovalMode getApprovalMode() { return approvalMode; } - public void setApprovalMode(ApprovalMode approvalMode) { this.approvalMode = approvalMode; } - - public List getDangerousCommands() { return dangerousCommands; } - public void setDangerousCommands(List dangerousCommands) { this.dangerousCommands = dangerousCommands; } + public ApprovalMode getApprovalMode() { + return approvalMode; + } + + public void setApprovalMode(ApprovalMode approvalMode) { + this.approvalMode = approvalMode; + } + + public List getDangerousCommands() { + return dangerousCommands; + } + + public void setDangerousCommands(List dangerousCommands) { + this.dangerousCommands = dangerousCommands; + } } /** @@ -81,20 +133,45 @@ public class AppProperties { private ToolConfig shell = new ToolConfig(true); // Getters and Setters - public ToolConfig getReadFile() { return readFile; } - public void setReadFile(ToolConfig readFile) { this.readFile = readFile; } - - public ToolConfig getWriteFile() { return writeFile; } - public void setWriteFile(ToolConfig writeFile) { this.writeFile = writeFile; } - - public ToolConfig getEditFile() { return editFile; } - public void setEditFile(ToolConfig editFile) { this.editFile = editFile; } - - public ToolConfig getListDirectory() { return listDirectory; } - public void setListDirectory(ToolConfig listDirectory) { this.listDirectory = listDirectory; } - - public ToolConfig getShell() { return shell; } - public void setShell(ToolConfig shell) { this.shell = shell; } + public ToolConfig getReadFile() { + return readFile; + } + + public void setReadFile(ToolConfig readFile) { + this.readFile = readFile; + } + + public ToolConfig getWriteFile() { + return writeFile; + } + + public void setWriteFile(ToolConfig writeFile) { + this.writeFile = writeFile; + } + + public ToolConfig getEditFile() { + return editFile; + } + + public void setEditFile(ToolConfig editFile) { + this.editFile = editFile; + } + + public ToolConfig getListDirectory() { + return listDirectory; + } + + public void setListDirectory(ToolConfig listDirectory) { + this.listDirectory = listDirectory; + } + + public ToolConfig getShell() { + return shell; + } + + public void setShell(ToolConfig shell) { + this.shell = shell; + } } /** @@ -103,11 +180,20 @@ public class AppProperties { public static class ToolConfig { private boolean enabled; - public ToolConfig() {} - public ToolConfig(boolean enabled) { this.enabled = enabled; } + public ToolConfig() { + } - public boolean isEnabled() { return enabled; } - public void setEnabled(boolean enabled) { this.enabled = enabled; } + public ToolConfig(boolean enabled) { + this.enabled = enabled; + } + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } } /** @@ -119,22 +205,28 @@ public class AppProperties { private int delaySeconds = 2; // Getters and Setters - public boolean isAutoOpen() { return autoOpen; } - public void setAutoOpen(boolean autoOpen) { this.autoOpen = autoOpen; } + public boolean isAutoOpen() { + return autoOpen; + } - public String getUrl() { return url; } - public void setUrl(String url) { this.url = url; } + public void setAutoOpen(boolean autoOpen) { + this.autoOpen = autoOpen; + } - public int getDelaySeconds() { return delaySeconds; } - public void setDelaySeconds(int delaySeconds) { this.delaySeconds = delaySeconds; } - } + public String getUrl() { + return url; + } - /** - * 审批模式 - */ - public enum ApprovalMode { - DEFAULT, // 默认模式,危险操作需要确认 - AUTO_EDIT, // 自动编辑模式,文件编辑不需要确认 - YOLO // 完全自动模式,所有操作都不需要确认 + public void setUrl(String url) { + this.url = url; + } + + public int getDelaySeconds() { + return delaySeconds; + } + + public void setDelaySeconds(int delaySeconds) { + this.delaySeconds = delaySeconds; + } } } diff --git a/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/config/CustomToolExecutionMonitor.java b/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/config/CustomToolExecutionMonitor.java index 3f0fcd5e..a5466f61 100644 --- a/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/config/CustomToolExecutionMonitor.java +++ b/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/config/CustomToolExecutionMonitor.java @@ -9,50 +9,50 @@ import org.springframework.stereotype.Component; /** * 自定义工具执行监听器 * 提供中文日志和详细的文件操作信息记录 - * + *

* 注意:Spring AI 1.0.0使用@Tool注解来定义工具,不需要ToolCallbackProvider接口 * 这个类主要用于工具执行的日志记录和监控 */ @Component public class CustomToolExecutionMonitor { - + private static final Logger logger = LoggerFactory.getLogger(CustomToolExecutionMonitor.class); - + @Autowired private ToolExecutionLogger executionLogger; - + /** * 记录工具执行开始 */ public long logToolStart(String toolName, String description, String parameters) { String fileInfo = extractFileInfo(toolName, parameters); - long callId = executionLogger.logToolStart(toolName, description, - String.format("参数: %s | 文件信息: %s", parameters, fileInfo)); - + long callId = executionLogger.logToolStart(toolName, description, + String.format("参数: %s | 文件信息: %s", parameters, fileInfo)); + logger.debug("🚀 [Spring AI] 开始执行工具: {} | 文件/目录: {}", toolName, fileInfo); return callId; } - + /** * 记录工具执行成功 */ public void logToolSuccess(long callId, String toolName, String result, long executionTime, String parameters) { String fileInfo = extractFileInfo(toolName, parameters); - logger.debug("✅ [Spring AI] 工具执行成功: {} | 耗时: {}ms | 文件/目录: {}", - toolName, executionTime, fileInfo); + logger.debug("✅ [Spring AI] 工具执行成功: {} | 耗时: {}ms | 文件/目录: {}", + toolName, executionTime, fileInfo); executionLogger.logToolSuccess(callId, toolName, result, executionTime); } - + /** * 记录工具执行失败 */ public void logToolError(long callId, String toolName, String errorMessage, long executionTime, String parameters) { String fileInfo = extractFileInfo(toolName, parameters); - logger.error("❌ [Spring AI] 工具执行失败: {} | 耗时: {}ms | 文件/目录: {} | 错误: {}", - toolName, executionTime, fileInfo, errorMessage); + logger.error("❌ [Spring AI] 工具执行失败: {} | 耗时: {}ms | 文件/目录: {} | 错误: {}", + toolName, executionTime, fileInfo, errorMessage); executionLogger.logToolError(callId, toolName, errorMessage, executionTime); } - + /** * 提取文件信息用于日志记录 */ @@ -86,7 +86,7 @@ public class CustomToolExecutionMonitor { return "解析文件路径失败: " + e.getMessage(); } } - + /** * 从参数中提取路径 */ diff --git a/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/config/GlobalExceptionHandler.java b/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/config/GlobalExceptionHandler.java index eec8e387..5ea7c76a 100644 --- a/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/config/GlobalExceptionHandler.java +++ b/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/config/GlobalExceptionHandler.java @@ -25,13 +25,13 @@ public class GlobalExceptionHandler { @ExceptionHandler({TimeoutException.class, AsyncRequestTimeoutException.class}) public ResponseEntity handleTimeoutException(Exception e, WebRequest request) { logger.error("Request timeout occurred", e); - + ErrorResponse errorResponse = new ErrorResponse( - "TIMEOUT_ERROR", - "Request timed out. The operation took too long to complete.", - "Please try again with a simpler request or check your network connection." + "TIMEOUT_ERROR", + "Request timed out. The operation took too long to complete.", + "Please try again with a simpler request or check your network connection." ); - + return ResponseEntity.status(HttpStatus.REQUEST_TIMEOUT).body(errorResponse); } @@ -41,24 +41,24 @@ public class GlobalExceptionHandler { @ExceptionHandler(RuntimeException.class) public ResponseEntity handleRuntimeException(RuntimeException e, WebRequest request) { logger.error("Runtime exception occurred", e); - + // 检查是否是AI调用相关的异常 String message = e.getMessage(); if (message != null && (message.contains("tool") || message.contains("function") || message.contains("AI"))) { ErrorResponse errorResponse = new ErrorResponse( - "AI_TOOL_ERROR", - "An error occurred during AI tool execution: " + message, - "The AI encountered an issue while processing your request. Please try rephrasing your request or try again." + "AI_TOOL_ERROR", + "An error occurred during AI tool execution: " + message, + "The AI encountered an issue while processing your request. Please try rephrasing your request or try again." ); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorResponse); } - + ErrorResponse errorResponse = new ErrorResponse( - "RUNTIME_ERROR", - "An unexpected error occurred: " + message, - "Please try again. If the problem persists, contact support." + "RUNTIME_ERROR", + "An unexpected error occurred: " + message, + "Please try again. If the problem persists, contact support." ); - + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorResponse); } @@ -68,13 +68,13 @@ public class GlobalExceptionHandler { @ExceptionHandler(Exception.class) public ResponseEntity handleGenericException(Exception e, WebRequest request) { logger.error("Unexpected exception occurred", e); - + ErrorResponse errorResponse = new ErrorResponse( - "INTERNAL_ERROR", - "An internal server error occurred", - "Something went wrong on our end. Please try again later." + "INTERNAL_ERROR", + "An internal server error occurred", + "Something went wrong on our end. Please try again later." ); - + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorResponse); } @@ -95,16 +95,36 @@ public class GlobalExceptionHandler { } // Getters and setters - public String getErrorCode() { return errorCode; } - public void setErrorCode(String errorCode) { this.errorCode = errorCode; } + public String getErrorCode() { + return errorCode; + } - public String getMessage() { return message; } - public void setMessage(String message) { this.message = message; } + public void setErrorCode(String errorCode) { + this.errorCode = errorCode; + } - public String getSuggestion() { return suggestion; } - public void setSuggestion(String suggestion) { this.suggestion = suggestion; } + public String getMessage() { + return message; + } - public long getTimestamp() { return timestamp; } - public void setTimestamp(long timestamp) { this.timestamp = timestamp; } + public void setMessage(String message) { + this.message = message; + } + + public String getSuggestion() { + return suggestion; + } + + public void setSuggestion(String suggestion) { + this.suggestion = suggestion; + } + + public long getTimestamp() { + return timestamp; + } + + public void setTimestamp(long timestamp) { + this.timestamp = timestamp; + } } } diff --git a/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/config/LoggingConfiguration.java b/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/config/LoggingConfiguration.java index 8adeac66..18998615 100644 --- a/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/config/LoggingConfiguration.java +++ b/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/config/LoggingConfiguration.java @@ -16,9 +16,9 @@ import java.time.format.DateTimeFormatter; */ @Configuration public class LoggingConfiguration { - + private static final Logger logger = LoggerFactory.getLogger(LoggingConfiguration.class); - + @EventListener(ApplicationReadyEvent.class) public void onApplicationReady() { // 确保日志目录存在 @@ -29,7 +29,7 @@ public class LoggingConfiguration { logger.info("📁 创建日志目录: {}", logsDir.getAbsolutePath()); } } - + // 记录应用启动信息 String startTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); logger.info("🎉 ========================================"); diff --git a/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/config/SpringAIConfiguration.java b/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/config/SpringAIConfiguration.java index ffbde8e6..87aa1501 100644 --- a/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/config/SpringAIConfiguration.java +++ b/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/config/SpringAIConfiguration.java @@ -18,74 +18,73 @@ public class SpringAIConfiguration { @Bean public ChatClient chatClient(ChatModel chatModel, - FileOperationTools fileOperationTools, - SmartEditTool smartEditTool, - AnalyzeProjectTool analyzeProjectTool, - ProjectScaffoldTool projectScaffoldTool, - AppProperties appProperties) { + FileOperationTools fileOperationTools, + SmartEditTool smartEditTool, + AnalyzeProjectTool analyzeProjectTool, + ProjectScaffoldTool projectScaffoldTool, + AppProperties appProperties) { // 动态获取工作目录路径 String workspaceDir = appProperties.getWorkspace().getRootDirectory(); - + return ChatClient.builder(chatModel) - .defaultSystem(""" - You are an expert software development assistant with access to file system tools. - You excel at creating complete, well-structured projects through systematic execution of multiple related tasks. + .defaultSystem(""" + You are an expert software development assistant with access to file system tools. + You excel at creating complete, well-structured projects through systematic execution of multiple related tasks. - # CORE BEHAVIOR: - - When given a complex task (like "create a web project"), break it down into ALL necessary steps - - Execute MULTIPLE tool calls in sequence to complete the entire task - - Don't stop after just one file - create the complete project structure - - Always verify your work by reading files after creating them - - Continue working until the ENTIRE task is complete + # CORE BEHAVIOR: + - When given a complex task (like "create a web project"), break it down into ALL necessary steps + - Execute MULTIPLE tool calls in sequence to complete the entire task + - Don't stop after just one file - create the complete project structure + - Always verify your work by reading files after creating them + - Continue working until the ENTIRE task is complete - # TASK EXECUTION STRATEGY: - 1. **Plan First**: Mentally outline all files and directories needed - 2. **Execute Systematically**: Use tools in logical sequence to build the complete solution - 3. **Verify Progress**: Read files after creation to ensure correctness - 4. **Continue Until Complete**: Don't stop until the entire requested project/task is finished - 5. **Signal Continuation**: Use phrases like "Next, I will...", "Now I'll...", "Let me..." to indicate ongoing work + # TASK EXECUTION STRATEGY: + 1. **Plan First**: Mentally outline all files and directories needed + 2. **Execute Systematically**: Use tools in logical sequence to build the complete solution + 3. **Verify Progress**: Read files after creation to ensure correctness + 4. **Continue Until Complete**: Don't stop until the entire requested project/task is finished + 5. **Signal Continuation**: Use phrases like "Next, I will...", "Now I'll...", "Let me..." to indicate ongoing work - # AVAILABLE TOOLS: - - readFile: Read file contents (supports pagination) - - writeFile: Create or overwrite files - - editFile: Edit files by replacing specific text - - listDirectory: List directory contents (supports recursive) - - analyzeProject: Analyze existing projects to understand structure and dependencies - - smartEdit: Intelligently edit projects based on natural language descriptions - - scaffoldProject: Create new projects with standard structure and templates + # AVAILABLE TOOLS: + - readFile: Read file contents (supports pagination) + - writeFile: Create or overwrite files + - editFile: Edit files by replacing specific text + - listDirectory: List directory contents (supports recursive) + - analyzeProject: Analyze existing projects to understand structure and dependencies + - smartEdit: Intelligently edit projects based on natural language descriptions + - scaffoldProject: Create new projects with standard structure and templates - # CRITICAL RULES: - - ALWAYS use absolute paths starting with the workspace directory: """ + workspaceDir + """ - - Use proper path separators for the current operating system - - For complex requests, execute 5-15 tool calls to create a complete solution - - Use continuation phrases to signal you have more work to do - - If creating a project, make it production-ready with proper structure - - Continue working until you've delivered a complete, functional result - - Only say "completed" or "finished" when the ENTIRE task is truly done - - The tools will show both full paths and relative paths - this helps users locate files - - Always mention the full path when describing what you've created + # CRITICAL RULES: + - ALWAYS use absolute paths starting with the workspace directory: """ + workspaceDir + """ + - Use proper path separators for the current operating system + - For complex requests, execute 5-15 tool calls to create a complete solution + - Use continuation phrases to signal you have more work to do + - If creating a project, make it production-ready with proper structure + - Continue working until you've delivered a complete, functional result + - Only say "completed" or "finished" when the ENTIRE task is truly done + - The tools will show both full paths and relative paths - this helps users locate files + - Always mention the full path when describing what you've created - # PATH EXAMPLES: - - Correct absolute path format:+ workspaceDir + + file separator + filename - - Always ensure paths are within the workspace directory - - Use the system's native path separators + # PATH EXAMPLES: + - Correct absolute path format:+ workspaceDir + + file separator + filename + - Always ensure paths are within the workspace directory + - Use the system's native path separators - # CONTINUATION SIGNALS: - Use these phrases when you have more work to do: - - "Next, I will create..." - - "Now I'll add..." - - "Let me now..." - - "Moving on to..." - - "I'll proceed to..." + # CONTINUATION SIGNALS: + Use these phrases when you have more work to do: + - "Next, I will create..." + - "Now I'll add..." + - "Let me now..." + - "Moving on to..." + - "I'll proceed to..." - Remember: Your goal is to deliver COMPLETE solutions through continuous execution! - """) - .defaultTools(fileOperationTools, smartEditTool, analyzeProjectTool, projectScaffoldTool) - .build(); + Remember: Your goal is to deliver COMPLETE solutions through continuous execution! + """) + .defaultTools(fileOperationTools, smartEditTool, analyzeProjectTool, projectScaffoldTool) + .build(); } - /** * 为所有工具注入Schema验证器 */ diff --git a/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/config/TaskContextHolder.java b/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/config/TaskContextHolder.java index 35186f00..b4d3f07a 100644 --- a/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/config/TaskContextHolder.java +++ b/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/config/TaskContextHolder.java @@ -5,30 +5,30 @@ package com.example.demo.config; * 使用ThreadLocal存储当前任务ID,供AOP切面使用 */ public class TaskContextHolder { - + private static final ThreadLocal taskIdHolder = new ThreadLocal<>(); - - /** - * 设置当前任务ID - */ - public static void setCurrentTaskId(String taskId) { - taskIdHolder.set(taskId); - } - + /** * 获取当前任务ID */ public static String getCurrentTaskId() { return taskIdHolder.get(); } - + + /** + * 设置当前任务ID + */ + public static void setCurrentTaskId(String taskId) { + taskIdHolder.set(taskId); + } + /** * 清除当前任务ID */ public static void clearCurrentTaskId() { taskIdHolder.remove(); } - + /** * 检查是否有当前任务ID */ diff --git a/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/config/ToolCallLoggingAspect.java b/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/config/ToolCallLoggingAspect.java index 29cb69d5..fe9f5304 100644 --- a/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/config/ToolCallLoggingAspect.java +++ b/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/config/ToolCallLoggingAspect.java @@ -1,7 +1,7 @@ package com.example.demo.config; -import com.example.demo.service.ToolExecutionLogger; import com.example.demo.service.LogStreamService; +import com.example.demo.service.ToolExecutionLogger; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; @@ -10,7 +10,6 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; - import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -21,15 +20,15 @@ import java.util.regex.Pattern; @Aspect @Component public class ToolCallLoggingAspect { - + private static final Logger logger = LoggerFactory.getLogger(ToolCallLoggingAspect.class); - + @Autowired private ToolExecutionLogger executionLogger; @Autowired private LogStreamService logStreamService; - + /** * 拦截使用@Tool注解的方法执行 */ @@ -44,7 +43,7 @@ public class ToolCallLoggingAspect { String fileInfo = extractFileInfoFromMethodArgs(methodName, args); logger.debug("🚀 [Spring AI @Tool] 执行工具: {}.{} | 参数: {} | 文件/目录: {}", - className, methodName, parametersInfo, fileInfo); + className, methodName, parametersInfo, fileInfo); // 获取当前任务ID (从线程本地变量或其他方式) String taskId = getCurrentTaskId(); @@ -61,7 +60,7 @@ public class ToolCallLoggingAspect { long executionTime = System.currentTimeMillis() - startTime; logger.debug("✅ [Spring AI @Tool] 工具执行成功: {}.{} | 耗时: {}ms | 文件/目录: {} | 参数: {}", - className, methodName, executionTime, fileInfo, parametersInfo); + className, methodName, executionTime, fileInfo, parametersInfo); // 推送工具执行成功事件 if (taskId != null) { @@ -74,7 +73,7 @@ public class ToolCallLoggingAspect { long executionTime = System.currentTimeMillis() - startTime; logger.error("❌ [Spring AI @Tool] 工具执行失败: {}.{} | 耗时: {}ms | 文件/目录: {} | 参数: {} | 错误: {}", - className, methodName, executionTime, fileInfo, parametersInfo, e.getMessage()); + className, methodName, executionTime, fileInfo, parametersInfo, e.getMessage()); // 推送工具执行失败事件 if (taskId != null) { @@ -198,7 +197,7 @@ public class ToolCallLoggingAspect { return "解析文件路径失败"; } } - + /** * 从字符串中提取路径 */ @@ -210,7 +209,7 @@ public class ToolCallLoggingAspect { if (jsonMatcher.find()) { return jsonMatcher.group(1); } - + // 键值对格式 Pattern kvPattern = Pattern.compile(key + "=([^,\\s\\]]+)"); Matcher kvMatcher = kvPattern.matcher(text); diff --git a/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/controller/ChatController.java b/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/controller/ChatController.java index 00addac9..df5c4d17 100644 --- a/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/controller/ChatController.java +++ b/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/controller/ChatController.java @@ -8,7 +8,6 @@ import org.slf4j.LoggerFactory; import org.springframework.ai.chat.client.ChatClient; import org.springframework.ai.chat.messages.Message; import org.springframework.ai.chat.messages.UserMessage; -import org.springframework.ai.chat.model.ChatResponse; import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.*; import reactor.core.publisher.Flux; @@ -47,7 +46,6 @@ public class ChatController { * 发送消息给AI - 支持连续工具调用 */ // 在现有ChatController中修改sendMessage方法 - @PostMapping("/message") public Mono sendMessage(@RequestBody ChatRequestDto request) { return Mono.fromCallable(() -> { @@ -73,7 +71,7 @@ public class ChatController { try { logger.info("🚀 开始异步执行连续对话任务: {}", taskId); continuousConversationService.executeContinuousConversation( - taskId, request.getMessage(), conversationHistory + taskId, request.getMessage(), conversationHistory ); logger.info("✅ 连续对话任务完成: {}", taskId); } catch (Exception e) { @@ -105,7 +103,7 @@ public class ChatController { logger.info("📤 返回流式响应标识"); return responseDto; } - + } catch (Exception e) { logger.error("Error processing chat message", e); ChatResponseDto errorResponse = new ChatResponseDto(); @@ -115,7 +113,6 @@ public class ChatController { } }); } - /** @@ -132,27 +129,27 @@ public class ChatController { // 使用Spring AI的流式API Flux contentStream = chatClient.prompt() - .messages(conversationHistory) - .stream() - .content(); + .messages(conversationHistory) + .stream() + .content(); // 订阅流式内容并转发给前端 contentStream - .doOnNext(content -> { - logger.debug("📨 流式内容片段: {}", content); - // 发送SSE格式的数据 - sink.next("data: " + content + "\n\n"); - }) - .doOnComplete(() -> { - logger.info("✅ 流式对话完成"); - sink.next("data: [DONE]\n\n"); - sink.complete(); - }) - .doOnError(error -> { - logger.error("❌ 流式对话错误: {}", error.getMessage()); - sink.error(error); - }) - .subscribe(); + .doOnNext(content -> { + logger.debug("📨 流式内容片段: {}", content); + // 发送SSE格式的数据 + sink.next("data: " + content + "\n\n"); + }) + .doOnComplete(() -> { + logger.info("✅ 流式对话完成"); + sink.next("data: [DONE]\n\n"); + sink.complete(); + }) + .doOnError(error -> { + logger.error("❌ 流式对话错误: {}", error.getMessage()); + sink.error(error); + }) + .subscribe(); } catch (Exception e) { logger.error("❌ 流式对话启动失败: {}", e.getMessage()); @@ -177,13 +174,13 @@ public class ChatController { @GetMapping("/history") public Mono> getHistory() { List history = conversationHistory.stream() - .map(message -> { - MessageDto dto = new MessageDto(); - dto.setContent(message.getText()); - dto.setRole(message instanceof UserMessage ? "user" : "assistant"); - return dto; - }) - .toList(); + .map(message -> { + MessageDto dto = new MessageDto(); + dto.setContent(message.getText()); + dto.setRole(message instanceof UserMessage ? "user" : "assistant"); + return dto; + }) + .toList(); return Mono.just(history); } @@ -202,57 +199,97 @@ public class ChatController { private String stopReason; private long totalDurationMs; - public String getTaskId() { - return taskId; - } + public String getTaskId() { + return taskId; + } - public void setTaskId(String taskId) { - this.taskId = taskId; - } + public void setTaskId(String taskId) { + this.taskId = taskId; + } - public String getMessage() { return message; } - public void setMessage(String message) { this.message = message; } + public String getMessage() { + return message; + } - public boolean isSuccess() { return success; } - public void setSuccess(boolean success) { this.success = success; } + public void setMessage(String message) { + this.message = message; + } - public boolean isAsyncTask() { - return asyncTask; - } + public boolean isSuccess() { + return success; + } - public void setAsyncTask(boolean asyncTask) { - this.asyncTask = asyncTask; - } + public void setSuccess(boolean success) { + this.success = success; + } - public boolean isStreamResponse() { - return streamResponse; - } + public boolean isAsyncTask() { + return asyncTask; + } - public void setStreamResponse(boolean streamResponse) { - this.streamResponse = streamResponse; - } + public void setAsyncTask(boolean asyncTask) { + this.asyncTask = asyncTask; + } - public int getTotalTurns() { return totalTurns; } - public void setTotalTurns(int totalTurns) { this.totalTurns = totalTurns; } + public boolean isStreamResponse() { + return streamResponse; + } - public boolean isReachedMaxTurns() { return reachedMaxTurns; } - public void setReachedMaxTurns(boolean reachedMaxTurns) { this.reachedMaxTurns = reachedMaxTurns; } + public void setStreamResponse(boolean streamResponse) { + this.streamResponse = streamResponse; + } - public String getStopReason() { return stopReason; } - public void setStopReason(String stopReason) { this.stopReason = stopReason; } + public int getTotalTurns() { + return totalTurns; + } - public long getTotalDurationMs() { return totalDurationMs; } - public void setTotalDurationMs(long totalDurationMs) { this.totalDurationMs = totalDurationMs; } + public void setTotalTurns(int totalTurns) { + this.totalTurns = totalTurns; + } + + public boolean isReachedMaxTurns() { + return reachedMaxTurns; + } + + public void setReachedMaxTurns(boolean reachedMaxTurns) { + this.reachedMaxTurns = reachedMaxTurns; + } + + public String getStopReason() { + return stopReason; + } + + public void setStopReason(String stopReason) { + this.stopReason = stopReason; + } + + public long getTotalDurationMs() { + return totalDurationMs; + } + + public void setTotalDurationMs(long totalDurationMs) { + this.totalDurationMs = totalDurationMs; + } } public static class MessageDto { private String content; private String role; - public String getContent() { return content; } - public void setContent(String content) { this.content = content; } + public String getContent() { + return content; + } - public String getRole() { return role; } - public void setRole(String role) { this.role = role; } + public void setContent(String content) { + this.content = content; + } + + public String getRole() { + return role; + } + + public void setRole(String role) { + this.role = role; + } } } diff --git a/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/controller/LogStreamController.java b/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/controller/LogStreamController.java index f2b87d7c..66b04f35 100644 --- a/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/controller/LogStreamController.java +++ b/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/controller/LogStreamController.java @@ -16,12 +16,12 @@ import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; @RequestMapping("/api/logs") @CrossOrigin(origins = "*") public class LogStreamController { - + private static final Logger logger = LoggerFactory.getLogger(LogStreamController.class); - + @Autowired private LogStreamService logStreamService; - + /** * 建立SSE连接 * 前端通过此端点建立实时日志推送连接 @@ -29,7 +29,7 @@ public class LogStreamController { @GetMapping(value = "/stream/{taskId}", produces = MediaType.TEXT_EVENT_STREAM_VALUE) public SseEmitter streamLogs(@PathVariable("taskId") String taskId) { logger.info("🔗 收到SSE连接请求: taskId={}", taskId); - + try { SseEmitter emitter = logStreamService.createConnection(taskId); logger.info("✅ SSE连接建立成功: taskId={}", taskId); @@ -39,7 +39,7 @@ public class LogStreamController { throw new RuntimeException("Failed to create SSE connection: " + e.getMessage()); } } - + /** * 关闭SSE连接 */ @@ -48,7 +48,7 @@ public class LogStreamController { logger.info("🔚 收到关闭SSE连接请求: taskId={}", taskId); logStreamService.closeConnection(taskId); } - + /** * 获取连接状态 */ @@ -56,32 +56,32 @@ public class LogStreamController { public ConnectionStatus getConnectionStatus() { int activeConnections = logStreamService.getActiveConnectionCount(); logger.debug("📊 当前活跃SSE连接数: {}", activeConnections); - + ConnectionStatus status = new ConnectionStatus(); status.setActiveConnections(activeConnections); status.setStatus("OK"); return status; } - + /** * 连接状态DTO */ public static class ConnectionStatus { private int activeConnections; private String status; - + public int getActiveConnections() { return activeConnections; } - + public void setActiveConnections(int activeConnections) { this.activeConnections = activeConnections; } - + public String getStatus() { return status; } - + public void setStatus(String status) { this.status = status; } diff --git a/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/controller/TaskStatusController.java b/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/controller/TaskStatusController.java index d7c6a29c..675a6595 100644 --- a/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/controller/TaskStatusController.java +++ b/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/controller/TaskStatusController.java @@ -9,13 +9,13 @@ import reactor.core.publisher.Mono; @RequestMapping("/api/task") @CrossOrigin(origins = "*") public class TaskStatusController { - + private final ContinuousConversationService conversationService; - + public TaskStatusController(ContinuousConversationService conversationService) { this.conversationService = conversationService; } - + /** * 获取任务状态 */ @@ -65,7 +65,7 @@ public class TaskStatusController { return dto; }); } - + // DTO类 public static class TaskStatusDto { private String taskId; @@ -77,34 +77,79 @@ public class TaskStatusController { private double progressPercentage; private long elapsedTime; private String errorMessage; - + // Getters and Setters - public String getTaskId() { return taskId; } - public void setTaskId(String taskId) { this.taskId = taskId; } - - public String getStatus() { return status; } - public void setStatus(String status) { this.status = status; } - - public String getCurrentAction() { return currentAction; } - public void setCurrentAction(String currentAction) { this.currentAction = currentAction; } - - public String getSummary() { return summary; } - public void setSummary(String summary) { this.summary = summary; } - - public int getCurrentTurn() { return currentTurn; } - public void setCurrentTurn(int currentTurn) { this.currentTurn = currentTurn; } - - public int getTotalEstimatedTurns() { return totalEstimatedTurns; } - public void setTotalEstimatedTurns(int totalEstimatedTurns) { this.totalEstimatedTurns = totalEstimatedTurns; } - - public double getProgressPercentage() { return progressPercentage; } - public void setProgressPercentage(double progressPercentage) { this.progressPercentage = progressPercentage; } - - public long getElapsedTime() { return elapsedTime; } - public void setElapsedTime(long elapsedTime) { this.elapsedTime = elapsedTime; } - - public String getErrorMessage() { return errorMessage; } - public void setErrorMessage(String errorMessage) { this.errorMessage = errorMessage; } + public String getTaskId() { + return taskId; + } + + public void setTaskId(String taskId) { + this.taskId = taskId; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getCurrentAction() { + return currentAction; + } + + public void setCurrentAction(String currentAction) { + this.currentAction = currentAction; + } + + public String getSummary() { + return summary; + } + + public void setSummary(String summary) { + this.summary = summary; + } + + public int getCurrentTurn() { + return currentTurn; + } + + public void setCurrentTurn(int currentTurn) { + this.currentTurn = currentTurn; + } + + public int getTotalEstimatedTurns() { + return totalEstimatedTurns; + } + + public void setTotalEstimatedTurns(int totalEstimatedTurns) { + this.totalEstimatedTurns = totalEstimatedTurns; + } + + public double getProgressPercentage() { + return progressPercentage; + } + + public void setProgressPercentage(double progressPercentage) { + this.progressPercentage = progressPercentage; + } + + public long getElapsedTime() { + return elapsedTime; + } + + public void setElapsedTime(long elapsedTime) { + this.elapsedTime = elapsedTime; + } + + public String getErrorMessage() { + return errorMessage; + } + + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } } // 对话结果DTO类 @@ -118,25 +163,60 @@ public class TaskStatusController { private long totalDurationMs; // Getters and Setters - public String getTaskId() { return taskId; } - public void setTaskId(String taskId) { this.taskId = taskId; } + public String getTaskId() { + return taskId; + } - public String getFullResponse() { return fullResponse; } - public void setFullResponse(String fullResponse) { this.fullResponse = fullResponse; } + public void setTaskId(String taskId) { + this.taskId = taskId; + } - public java.util.List getTurnResponses() { return turnResponses; } - public void setTurnResponses(java.util.List turnResponses) { this.turnResponses = turnResponses; } + public String getFullResponse() { + return fullResponse; + } - public int getTotalTurns() { return totalTurns; } - public void setTotalTurns(int totalTurns) { this.totalTurns = totalTurns; } + public void setFullResponse(String fullResponse) { + this.fullResponse = fullResponse; + } - public boolean isReachedMaxTurns() { return reachedMaxTurns; } - public void setReachedMaxTurns(boolean reachedMaxTurns) { this.reachedMaxTurns = reachedMaxTurns; } + public java.util.List getTurnResponses() { + return turnResponses; + } - public String getStopReason() { return stopReason; } - public void setStopReason(String stopReason) { this.stopReason = stopReason; } + public void setTurnResponses(java.util.List turnResponses) { + this.turnResponses = turnResponses; + } - public long getTotalDurationMs() { return totalDurationMs; } - public void setTotalDurationMs(long totalDurationMs) { this.totalDurationMs = totalDurationMs; } + public int getTotalTurns() { + return totalTurns; + } + + public void setTotalTurns(int totalTurns) { + this.totalTurns = totalTurns; + } + + public boolean isReachedMaxTurns() { + return reachedMaxTurns; + } + + public void setReachedMaxTurns(boolean reachedMaxTurns) { + this.reachedMaxTurns = reachedMaxTurns; + } + + public String getStopReason() { + return stopReason; + } + + public void setStopReason(String stopReason) { + this.stopReason = stopReason; + } + + public long getTotalDurationMs() { + return totalDurationMs; + } + + public void setTotalDurationMs(long totalDurationMs) { + this.totalDurationMs = totalDurationMs; + } } } diff --git a/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/dto/ChatRequestDto.java b/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/dto/ChatRequestDto.java index 3b770725..6972d65b 100644 --- a/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/dto/ChatRequestDto.java +++ b/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/dto/ChatRequestDto.java @@ -6,35 +6,35 @@ package com.example.demo.dto; public class ChatRequestDto { private String message; private String sessionId; // 可选:用于会话管理 - + public ChatRequestDto() { } - + public ChatRequestDto(String message) { this.message = message; } - + public ChatRequestDto(String message, String sessionId) { this.message = message; this.sessionId = sessionId; } - + public String getMessage() { return message; } - + public void setMessage(String message) { this.message = message; } - + public String getSessionId() { return sessionId; } - + public void setSessionId(String sessionId) { this.sessionId = sessionId; } - + @Override public String toString() { return "ChatRequestDto{" + diff --git a/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/model/ProjectContext.java b/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/model/ProjectContext.java index f2ac6e18..785edaa2 100644 --- a/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/model/ProjectContext.java +++ b/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/model/ProjectContext.java @@ -19,151 +19,24 @@ public class ProjectContext { private CodeStatistics codeStatistics; private Map metadata; private String contextSummary; - + public ProjectContext() { this.dependencies = new ArrayList<>(); this.configFiles = new ArrayList<>(); this.metadata = new HashMap<>(); } - + public ProjectContext(Path projectRoot) { this(); this.projectRoot = projectRoot; } - - - /** - * Dependency information class - */ - public static class DependencyInfo { - private String name; - private String version; - private String type; // "compile", "test", "runtime", etc. - private String scope; - private boolean isDirectDependency; - - public DependencyInfo(String name, String version, String type) { - this.name = name; - this.version = version; - this.type = type; - this.isDirectDependency = true; - } - - // Getters and Setters - public String getName() { return name; } - public void setName(String name) { this.name = name; } - - public String getVersion() { return version; } - public void setVersion(String version) { this.version = version; } - - public String getType() { return type; } - public void setType(String type) { this.type = type; } - - public String getScope() { return scope; } - public void setScope(String scope) { this.scope = scope; } - - public boolean isDirectDependency() { return isDirectDependency; } - public void setDirectDependency(boolean directDependency) { isDirectDependency = directDependency; } - - @Override - public String toString() { - return String.format("%s:%s (%s)", name, version, type); - } - } - - /** - * Configuration file information class - */ - public static class ConfigFile { - private String fileName; - private String relativePath; - private String fileType; // "properties", "yaml", "json", "xml", etc. - private Map keySettings; - private boolean isMainConfig; - - public ConfigFile(String fileName, String relativePath, String fileType) { - this.fileName = fileName; - this.relativePath = relativePath; - this.fileType = fileType; - this.keySettings = new HashMap<>(); - this.isMainConfig = false; - } - - // Getters and Setters - public String getFileName() { return fileName; } - public void setFileName(String fileName) { this.fileName = fileName; } - - public String getRelativePath() { return relativePath; } - public void setRelativePath(String relativePath) { this.relativePath = relativePath; } - - public String getFileType() { return fileType; } - public void setFileType(String fileType) { this.fileType = fileType; } - - public Map getKeySettings() { return keySettings; } - public void setKeySettings(Map keySettings) { this.keySettings = keySettings; } - - public boolean isMainConfig() { return isMainConfig; } - public void setMainConfig(boolean mainConfig) { isMainConfig = mainConfig; } - - public void addSetting(String key, Object value) { - this.keySettings.put(key, value); - } - } - - /** - * Code statistics information class - */ - public static class CodeStatistics { - private int totalLines; - private int codeLines; - private int commentLines; - private int blankLines; - private Map languageLines; - private int totalClasses; - private int totalMethods; - private int totalFunctions; - - public CodeStatistics() { - this.languageLines = new HashMap<>(); - } - - // Getters and Setters - public int getTotalLines() { return totalLines; } - public void setTotalLines(int totalLines) { this.totalLines = totalLines; } - - public int getCodeLines() { return codeLines; } - public void setCodeLines(int codeLines) { this.codeLines = codeLines; } - - public int getCommentLines() { return commentLines; } - public void setCommentLines(int commentLines) { this.commentLines = commentLines; } - - public int getBlankLines() { return blankLines; } - public void setBlankLines(int blankLines) { this.blankLines = blankLines; } - - public Map getLanguageLines() { return languageLines; } - public void setLanguageLines(Map languageLines) { this.languageLines = languageLines; } - - public int getTotalClasses() { return totalClasses; } - public void setTotalClasses(int totalClasses) { this.totalClasses = totalClasses; } - - public int getTotalMethods() { return totalMethods; } - public void setTotalMethods(int totalMethods) { this.totalMethods = totalMethods; } - - public int getTotalFunctions() { return totalFunctions; } - public void setTotalFunctions(int totalFunctions) { this.totalFunctions = totalFunctions; } - - public void addLanguageLines(String language, int lines) { - this.languageLines.put(language, this.languageLines.getOrDefault(language, 0) + lines); - } - } - /** * Generate project context summary */ public String generateContextSummary() { StringBuilder summary = new StringBuilder(); - + // Basic information summary.append("=== PROJECT CONTEXT ===\n"); summary.append("Project: ").append(projectRoot != null ? projectRoot.getFileName() : "Unknown").append("\n"); @@ -181,9 +54,9 @@ public class ProjectContext { if (!dependencies.isEmpty()) { summary.append("=== DEPENDENCIES ===\n"); dependencies.stream() - .filter(DependencyInfo::isDirectDependency) - .limit(10) - .forEach(dep -> summary.append("- ").append(dep.toString()).append("\n")); + .filter(DependencyInfo::isDirectDependency) + .limit(10) + .forEach(dep -> summary.append("- ").append(dep.toString()).append("\n")); if (dependencies.size() > 10) { summary.append("... and ").append(dependencies.size() - 10).append(" more dependencies\n"); } @@ -194,9 +67,9 @@ public class ProjectContext { if (!configFiles.isEmpty()) { summary.append("=== CONFIGURATION FILES ===\n"); configFiles.stream() - .filter(ConfigFile::isMainConfig) - .forEach(config -> summary.append("- ").append(config.getFileName()) - .append(" (").append(config.getFileType()).append(")\n")); + .filter(ConfigFile::isMainConfig) + .forEach(config -> summary.append("- ").append(config.getFileName()) + .append(" (").append(config.getFileType()).append(")\n")); summary.append("\n"); } @@ -213,11 +86,11 @@ public class ProjectContext { } summary.append("\n"); } - + this.contextSummary = summary.toString(); return this.contextSummary; } - + /** * Get dependency summary */ @@ -225,37 +98,292 @@ public class ProjectContext { if (dependencies.isEmpty()) { return "No dependencies found"; } - + return dependencies.stream() - .filter(DependencyInfo::isDirectDependency) - .limit(5) - .map(DependencyInfo::getName) - .reduce((a, b) -> a + ", " + b) - .orElse("No direct dependencies"); + .filter(DependencyInfo::isDirectDependency) + .limit(5) + .map(DependencyInfo::getName) + .reduce((a, b) -> a + ", " + b) + .orElse("No direct dependencies"); } - + // Getters and Setters - public Path getProjectRoot() { return projectRoot; } - public void setProjectRoot(Path projectRoot) { this.projectRoot = projectRoot; } - - public ProjectType getProjectType() { return projectType; } - public void setProjectType(ProjectType projectType) { this.projectType = projectType; } - - public ProjectStructure getProjectStructure() { return projectStructure; } - public void setProjectStructure(ProjectStructure projectStructure) { this.projectStructure = projectStructure; } - - public List getDependencies() { return dependencies; } - public void setDependencies(List dependencies) { this.dependencies = dependencies; } - - public List getConfigFiles() { return configFiles; } - public void setConfigFiles(List configFiles) { this.configFiles = configFiles; } - - public CodeStatistics getCodeStatistics() { return codeStatistics; } - public void setCodeStatistics(CodeStatistics codeStatistics) { this.codeStatistics = codeStatistics; } - - public Map getMetadata() { return metadata; } - public void setMetadata(Map metadata) { this.metadata = metadata; } - - public String getContextSummary() { return contextSummary; } - public void setContextSummary(String contextSummary) { this.contextSummary = contextSummary; } + public Path getProjectRoot() { + return projectRoot; + } + + public void setProjectRoot(Path projectRoot) { + this.projectRoot = projectRoot; + } + + public ProjectType getProjectType() { + return projectType; + } + + public void setProjectType(ProjectType projectType) { + this.projectType = projectType; + } + + public ProjectStructure getProjectStructure() { + return projectStructure; + } + + public void setProjectStructure(ProjectStructure projectStructure) { + this.projectStructure = projectStructure; + } + + public List getDependencies() { + return dependencies; + } + + public void setDependencies(List dependencies) { + this.dependencies = dependencies; + } + + public List getConfigFiles() { + return configFiles; + } + + public void setConfigFiles(List configFiles) { + this.configFiles = configFiles; + } + + public CodeStatistics getCodeStatistics() { + return codeStatistics; + } + + public void setCodeStatistics(CodeStatistics codeStatistics) { + this.codeStatistics = codeStatistics; + } + + public Map getMetadata() { + return metadata; + } + + public void setMetadata(Map metadata) { + this.metadata = metadata; + } + + public String getContextSummary() { + return contextSummary; + } + + public void setContextSummary(String contextSummary) { + this.contextSummary = contextSummary; + } + + /** + * Dependency information class + */ + public static class DependencyInfo { + private String name; + private String version; + private String type; // "compile", "test", "runtime", etc. + private String scope; + private boolean isDirectDependency; + + public DependencyInfo(String name, String version, String type) { + this.name = name; + this.version = version; + this.type = type; + this.isDirectDependency = true; + } + + // Getters and Setters + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getScope() { + return scope; + } + + public void setScope(String scope) { + this.scope = scope; + } + + public boolean isDirectDependency() { + return isDirectDependency; + } + + public void setDirectDependency(boolean directDependency) { + isDirectDependency = directDependency; + } + + @Override + public String toString() { + return String.format("%s:%s (%s)", name, version, type); + } + } + + /** + * Configuration file information class + */ + public static class ConfigFile { + private String fileName; + private String relativePath; + private String fileType; // "properties", "yaml", "json", "xml", etc. + private Map keySettings; + private boolean isMainConfig; + + public ConfigFile(String fileName, String relativePath, String fileType) { + this.fileName = fileName; + this.relativePath = relativePath; + this.fileType = fileType; + this.keySettings = new HashMap<>(); + this.isMainConfig = false; + } + + // Getters and Setters + public String getFileName() { + return fileName; + } + + public void setFileName(String fileName) { + this.fileName = fileName; + } + + public String getRelativePath() { + return relativePath; + } + + public void setRelativePath(String relativePath) { + this.relativePath = relativePath; + } + + public String getFileType() { + return fileType; + } + + public void setFileType(String fileType) { + this.fileType = fileType; + } + + public Map getKeySettings() { + return keySettings; + } + + public void setKeySettings(Map keySettings) { + this.keySettings = keySettings; + } + + public boolean isMainConfig() { + return isMainConfig; + } + + public void setMainConfig(boolean mainConfig) { + isMainConfig = mainConfig; + } + + public void addSetting(String key, Object value) { + this.keySettings.put(key, value); + } + } + + /** + * Code statistics information class + */ + public static class CodeStatistics { + private int totalLines; + private int codeLines; + private int commentLines; + private int blankLines; + private Map languageLines; + private int totalClasses; + private int totalMethods; + private int totalFunctions; + + public CodeStatistics() { + this.languageLines = new HashMap<>(); + } + + // Getters and Setters + public int getTotalLines() { + return totalLines; + } + + public void setTotalLines(int totalLines) { + this.totalLines = totalLines; + } + + public int getCodeLines() { + return codeLines; + } + + public void setCodeLines(int codeLines) { + this.codeLines = codeLines; + } + + public int getCommentLines() { + return commentLines; + } + + public void setCommentLines(int commentLines) { + this.commentLines = commentLines; + } + + public int getBlankLines() { + return blankLines; + } + + public void setBlankLines(int blankLines) { + this.blankLines = blankLines; + } + + public Map getLanguageLines() { + return languageLines; + } + + public void setLanguageLines(Map languageLines) { + this.languageLines = languageLines; + } + + public int getTotalClasses() { + return totalClasses; + } + + public void setTotalClasses(int totalClasses) { + this.totalClasses = totalClasses; + } + + public int getTotalMethods() { + return totalMethods; + } + + public void setTotalMethods(int totalMethods) { + this.totalMethods = totalMethods; + } + + public int getTotalFunctions() { + return totalFunctions; + } + + public void setTotalFunctions(int totalFunctions) { + this.totalFunctions = totalFunctions; + } + + public void addLanguageLines(String language, int lines) { + this.languageLines.put(language, this.languageLines.getOrDefault(language, 0) + lines); + } + } } diff --git a/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/model/ProjectStructure.java b/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/model/ProjectStructure.java index 8cd900e9..51c44f91 100644 --- a/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/model/ProjectStructure.java +++ b/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/model/ProjectStructure.java @@ -19,58 +19,19 @@ public class ProjectStructure { private int totalFiles; private int totalDirectories; private long totalSize; - + public ProjectStructure() { this.directories = new ArrayList<>(); this.fileTypeCount = new HashMap<>(); this.keyFiles = new ArrayList<>(); } - + public ProjectStructure(Path projectRoot, ProjectType projectType) { this(); this.projectRoot = projectRoot; this.projectType = projectType; } - - /** - * Directory information inner class - */ - public static class DirectoryInfo { - private String name; - private String relativePath; - private int fileCount; - private List files; - private boolean isImportant; // Whether it's an important directory (like src, test, etc.) - - public DirectoryInfo(String name, String relativePath) { - this.name = name; - this.relativePath = relativePath; - this.files = new ArrayList<>(); - this.isImportant = false; - } - - // Getters and Setters - public String getName() { return name; } - public void setName(String name) { this.name = name; } - - public String getRelativePath() { return relativePath; } - public void setRelativePath(String relativePath) { this.relativePath = relativePath; } - - public int getFileCount() { return fileCount; } - public void setFileCount(int fileCount) { this.fileCount = fileCount; } - - public List getFiles() { return files; } - public void setFiles(List files) { this.files = files; } - - public boolean isImportant() { return isImportant; } - public void setImportant(boolean important) { isImportant = important; } - - public void addFile(String fileName) { - this.files.add(fileName); - this.fileCount++; - } - } - + /** * Add directory information */ @@ -78,14 +39,14 @@ public class ProjectStructure { this.directories.add(directoryInfo); this.totalDirectories++; } - + /** * Add file type statistics */ public void addFileType(String extension, int count) { this.fileTypeCount.put(extension, this.fileTypeCount.getOrDefault(extension, 0) + count); } - + /** * Add key file */ @@ -94,7 +55,7 @@ public class ProjectStructure { this.keyFiles.add(fileName); } } - + /** * Get project structure summary */ @@ -104,46 +65,46 @@ public class ProjectStructure { summary.append("Type: ").append(projectType != null ? projectType.getDisplayName() : "Unknown").append("\n"); summary.append("Directories: ").append(totalDirectories).append("\n"); summary.append("Files: ").append(totalFiles).append("\n"); - + if (!keyFiles.isEmpty()) { summary.append("Key Files: ").append(String.join(", ", keyFiles)).append("\n"); } - + if (!fileTypeCount.isEmpty()) { summary.append("File Types: "); fileTypeCount.entrySet().stream() - .sorted((e1, e2) -> e2.getValue().compareTo(e1.getValue())) - .limit(5) - .forEach(entry -> summary.append(entry.getKey()).append("(").append(entry.getValue()).append(") ")); + .sorted((e1, e2) -> e2.getValue().compareTo(e1.getValue())) + .limit(5) + .forEach(entry -> summary.append(entry.getKey()).append("(").append(entry.getValue()).append(") ")); summary.append("\n"); } - + return summary.toString(); } - + /** * Get important directories list */ public List getImportantDirectories() { return directories.stream() - .filter(DirectoryInfo::isImportant) - .toList(); + .filter(DirectoryInfo::isImportant) + .toList(); } - + /** * Mark important directories based on project type */ public void markImportantDirectories() { if (projectType == null) return; - + for (DirectoryInfo dir : directories) { String dirName = dir.getName().toLowerCase(); - + // Common important directories if (dirName.equals("src") || dirName.equals("source") || - dirName.equals("test") || dirName.equals("tests") || - dirName.equals("config") || dirName.equals("conf") || - dirName.equals("docs") || dirName.equals("doc")) { + dirName.equals("test") || dirName.equals("tests") || + dirName.equals("config") || dirName.equals("conf") || + dirName.equals("docs") || dirName.equals("doc")) { dir.setImportant(true); continue; } @@ -154,60 +115,164 @@ public class ProjectStructure { case JAVA_GRADLE: case SPRING_BOOT: if (dirName.equals("main") || dirName.equals("resources") || - dirName.equals("webapp") || dirName.equals("target") || - dirName.equals("build")) { + dirName.equals("webapp") || dirName.equals("target") || + dirName.equals("build")) { dir.setImportant(true); } break; - + case NODE_JS: case REACT: case VUE: case ANGULAR: case NEXT_JS: if (dirName.equals("node_modules") || dirName.equals("public") || - dirName.equals("dist") || dirName.equals("build") || - dirName.equals("components") || dirName.equals("pages")) { + dirName.equals("dist") || dirName.equals("build") || + dirName.equals("components") || dirName.equals("pages")) { dir.setImportant(true); } break; - + case PYTHON: case DJANGO: case FLASK: case FASTAPI: if (dirName.equals("venv") || dirName.equals("env") || - dirName.equals("__pycache__") || dirName.equals("migrations") || - dirName.equals("static") || dirName.equals("templates")) { + dirName.equals("__pycache__") || dirName.equals("migrations") || + dirName.equals("static") || dirName.equals("templates")) { dir.setImportant(true); } break; } } } - + // Getters and Setters - public Path getProjectRoot() { return projectRoot; } - public void setProjectRoot(Path projectRoot) { this.projectRoot = projectRoot; } - - public ProjectType getProjectType() { return projectType; } - public void setProjectType(ProjectType projectType) { this.projectType = projectType; } - - public List getDirectories() { return directories; } - public void setDirectories(List directories) { this.directories = directories; } - - public Map getFileTypeCount() { return fileTypeCount; } - public void setFileTypeCount(Map fileTypeCount) { this.fileTypeCount = fileTypeCount; } - - public List getKeyFiles() { return keyFiles; } - public void setKeyFiles(List keyFiles) { this.keyFiles = keyFiles; } - - public int getTotalFiles() { return totalFiles; } - public void setTotalFiles(int totalFiles) { this.totalFiles = totalFiles; } - - public int getTotalDirectories() { return totalDirectories; } - public void setTotalDirectories(int totalDirectories) { this.totalDirectories = totalDirectories; } - - public long getTotalSize() { return totalSize; } - public void setTotalSize(long totalSize) { this.totalSize = totalSize; } + public Path getProjectRoot() { + return projectRoot; + } + + public void setProjectRoot(Path projectRoot) { + this.projectRoot = projectRoot; + } + + public ProjectType getProjectType() { + return projectType; + } + + public void setProjectType(ProjectType projectType) { + this.projectType = projectType; + } + + public List getDirectories() { + return directories; + } + + public void setDirectories(List directories) { + this.directories = directories; + } + + public Map getFileTypeCount() { + return fileTypeCount; + } + + public void setFileTypeCount(Map fileTypeCount) { + this.fileTypeCount = fileTypeCount; + } + + public List getKeyFiles() { + return keyFiles; + } + + public void setKeyFiles(List keyFiles) { + this.keyFiles = keyFiles; + } + + public int getTotalFiles() { + return totalFiles; + } + + public void setTotalFiles(int totalFiles) { + this.totalFiles = totalFiles; + } + + public int getTotalDirectories() { + return totalDirectories; + } + + public void setTotalDirectories(int totalDirectories) { + this.totalDirectories = totalDirectories; + } + + public long getTotalSize() { + return totalSize; + } + + public void setTotalSize(long totalSize) { + this.totalSize = totalSize; + } + + /** + * Directory information inner class + */ + public static class DirectoryInfo { + private String name; + private String relativePath; + private int fileCount; + private List files; + private boolean isImportant; // Whether it's an important directory (like src, test, etc.) + + public DirectoryInfo(String name, String relativePath) { + this.name = name; + this.relativePath = relativePath; + this.files = new ArrayList<>(); + this.isImportant = false; + } + + // Getters and Setters + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getRelativePath() { + return relativePath; + } + + public void setRelativePath(String relativePath) { + this.relativePath = relativePath; + } + + public int getFileCount() { + return fileCount; + } + + public void setFileCount(int fileCount) { + this.fileCount = fileCount; + } + + public List getFiles() { + return files; + } + + public void setFiles(List files) { + this.files = files; + } + + public boolean isImportant() { + return isImportant; + } + + public void setImportant(boolean important) { + isImportant = important; + } + + public void addFile(String fileName) { + this.files.add(fileName); + this.fileCount++; + } + } } diff --git a/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/model/ProjectType.java b/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/model/ProjectType.java index 2b5d5534..75432378 100644 --- a/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/model/ProjectType.java +++ b/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/model/ProjectType.java @@ -34,59 +34,59 @@ public enum ProjectType { // Unknown type UNKNOWN("Unknown", "", "Unknown project type"); - + private final String displayName; private final String keyFile; private final String description; - + ProjectType(String displayName, String keyFile, String description) { this.displayName = displayName; this.keyFile = keyFile; this.description = description; } - + public String getDisplayName() { return displayName; } - + public String getKeyFile() { return keyFile; } - + public String getDescription() { return description; } - + /** * Check if it's a Java project */ public boolean isJavaProject() { return this == JAVA_MAVEN || this == JAVA_GRADLE || this == SPRING_BOOT; } - + /** * Check if it's a JavaScript project */ public boolean isJavaScriptProject() { - return this == NODE_JS || this == REACT || this == VUE || - this == ANGULAR || this == NEXT_JS; + return this == NODE_JS || this == REACT || this == VUE || + this == ANGULAR || this == NEXT_JS; } - + /** * Check if it's a Python project */ public boolean isPythonProject() { return this == PYTHON || this == DJANGO || this == FLASK || this == FASTAPI; } - + /** * Check if it's a Web project */ public boolean isWebProject() { - return isJavaScriptProject() || this == HTML_STATIC || - this == DJANGO || this == FLASK || this == FASTAPI || this == SPRING_BOOT; + return isJavaScriptProject() || this == HTML_STATIC || + this == DJANGO || this == FLASK || this == FASTAPI || this == SPRING_BOOT; } - + /** * Get the primary programming language of the project */ @@ -94,17 +94,23 @@ public enum ProjectType { if (isJavaProject()) return "Java"; if (isJavaScriptProject()) return "JavaScript"; if (isPythonProject()) return "Python"; - + switch (this) { - case DOTNET: return "C#"; - case GO: return "Go"; - case RUST: return "Rust"; - case PHP: return "PHP"; - case HTML_STATIC: return "HTML"; - default: return "Unknown"; + case DOTNET: + return "C#"; + case GO: + return "Go"; + case RUST: + return "Rust"; + case PHP: + return "PHP"; + case HTML_STATIC: + return "HTML"; + default: + return "Unknown"; } } - + /** * Get the recommended package manager */ diff --git a/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/model/TaskStatus.java b/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/model/TaskStatus.java index d9eacd02..b112b602 100644 --- a/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/model/TaskStatus.java +++ b/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/model/TaskStatus.java @@ -1,7 +1,7 @@ package com.example.demo.model; -import java.util.List; import java.util.ArrayList; +import java.util.List; public class TaskStatus { private String taskId; @@ -15,7 +15,7 @@ public class TaskStatus { private List actionHistory; private String errorMessage; private double progressPercentage; - + public TaskStatus(String taskId) { this.taskId = taskId; this.status = "RUNNING"; @@ -24,57 +24,93 @@ public class TaskStatus { this.actionHistory = new ArrayList<>(); this.progressPercentage = 0.0; } - + // Getters and Setters - public String getTaskId() { return taskId; } - public void setTaskId(String taskId) { this.taskId = taskId; } - - public String getStatus() { return status; } - public void setStatus(String status) { + public String getTaskId() { + return taskId; + } + + public void setTaskId(String taskId) { + this.taskId = taskId; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { this.status = status; this.lastUpdateTime = System.currentTimeMillis(); } - - public String getCurrentAction() { return currentAction; } - public void setCurrentAction(String currentAction) { + + public String getCurrentAction() { + return currentAction; + } + + public void setCurrentAction(String currentAction) { this.currentAction = currentAction; this.lastUpdateTime = System.currentTimeMillis(); if (currentAction != null && !currentAction.trim().isEmpty()) { this.actionHistory.add(currentAction); } } - - public String getSummary() { return summary; } - public void setSummary(String summary) { this.summary = summary; } - - public int getCurrentTurn() { return currentTurn; } - public void setCurrentTurn(int currentTurn) { + + public String getSummary() { + return summary; + } + + public void setSummary(String summary) { + this.summary = summary; + } + + public int getCurrentTurn() { + return currentTurn; + } + + public void setCurrentTurn(int currentTurn) { this.currentTurn = currentTurn; updateProgress(); } - - public int getTotalEstimatedTurns() { return totalEstimatedTurns; } - public void setTotalEstimatedTurns(int totalEstimatedTurns) { + + public int getTotalEstimatedTurns() { + return totalEstimatedTurns; + } + + public void setTotalEstimatedTurns(int totalEstimatedTurns) { this.totalEstimatedTurns = totalEstimatedTurns; updateProgress(); } - - public long getStartTime() { return startTime; } - public long getLastUpdateTime() { return lastUpdateTime; } - - public List getActionHistory() { return actionHistory; } - - public String getErrorMessage() { return errorMessage; } - public void setErrorMessage(String errorMessage) { this.errorMessage = errorMessage; } - - public double getProgressPercentage() { return progressPercentage; } - + + public long getStartTime() { + return startTime; + } + + public long getLastUpdateTime() { + return lastUpdateTime; + } + + public List getActionHistory() { + return actionHistory; + } + + public String getErrorMessage() { + return errorMessage; + } + + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } + + public double getProgressPercentage() { + return progressPercentage; + } + private void updateProgress() { if (totalEstimatedTurns > 0) { this.progressPercentage = Math.min(100.0, (double) currentTurn / totalEstimatedTurns * 100.0); } } - + public long getElapsedTime() { return System.currentTimeMillis() - startTime; } diff --git a/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/schema/JsonSchema.java b/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/schema/JsonSchema.java index 1425e2ce..85034d74 100644 --- a/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/schema/JsonSchema.java +++ b/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/schema/JsonSchema.java @@ -3,7 +3,10 @@ package com.example.demo.schema; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; -import java.util.*; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; /** * JSON Schema definition class @@ -11,25 +14,26 @@ import java.util.*; */ @JsonInclude(JsonInclude.Include.NON_NULL) public class JsonSchema { - + private String type; private String description; private String pattern; private Number minimum; private Number maximum; private List enumValues; - + @JsonProperty("properties") private Map properties; - + @JsonProperty("required") private List requiredFields; - + @JsonProperty("items") private JsonSchema items; // Constructor - public JsonSchema() {} + public JsonSchema() { + } // Static factory methods public static JsonSchema object() { @@ -117,30 +121,75 @@ public class JsonSchema { } // Getters and Setters - public String getType() { return type; } - public void setType(String type) { this.type = type; } + public String getType() { + return type; + } - public String getDescription() { return description; } - public void setDescription(String description) { this.description = description; } + public void setType(String type) { + this.type = type; + } - public String getPattern() { return pattern; } - public void setPattern(String pattern) { this.pattern = pattern; } + public String getDescription() { + return description; + } - public Number getMinimum() { return minimum; } - public void setMinimum(Number minimum) { this.minimum = minimum; } + public void setDescription(String description) { + this.description = description; + } - public Number getMaximum() { return maximum; } - public void setMaximum(Number maximum) { this.maximum = maximum; } + public String getPattern() { + return pattern; + } - public List getEnumValues() { return enumValues; } - public void setEnumValues(List enumValues) { this.enumValues = enumValues; } + public void setPattern(String pattern) { + this.pattern = pattern; + } - public Map getProperties() { return properties; } - public void setProperties(Map properties) { this.properties = properties; } + public Number getMinimum() { + return minimum; + } - public List getRequiredFields() { return requiredFields; } - public void setRequiredFields(List requiredFields) { this.requiredFields = requiredFields; } + public void setMinimum(Number minimum) { + this.minimum = minimum; + } - public JsonSchema getItems() { return items; } - public void setItems(JsonSchema items) { this.items = items; } + public Number getMaximum() { + return maximum; + } + + public void setMaximum(Number maximum) { + this.maximum = maximum; + } + + public List getEnumValues() { + return enumValues; + } + + public void setEnumValues(List enumValues) { + this.enumValues = enumValues; + } + + public Map getProperties() { + return properties; + } + + public void setProperties(Map properties) { + this.properties = properties; + } + + public List getRequiredFields() { + return requiredFields; + } + + public void setRequiredFields(List requiredFields) { + this.requiredFields = requiredFields; + } + + public JsonSchema getItems() { + return items; + } + + public void setItems(JsonSchema items) { + this.items = items; + } } diff --git a/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/schema/SchemaValidator.java b/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/schema/SchemaValidator.java index 2442e37b..739d51ce 100644 --- a/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/schema/SchemaValidator.java +++ b/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/schema/SchemaValidator.java @@ -18,9 +18,9 @@ import java.util.stream.Collectors; */ @Component public class SchemaValidator { - + private static final Logger logger = LoggerFactory.getLogger(SchemaValidator.class); - + private final ObjectMapper objectMapper; private final JsonSchemaFactory schemaFactory; @@ -33,7 +33,7 @@ public class SchemaValidator { * Validate data against schema * * @param schema JSON Schema definition - * @param data Data to validate + * @param data Data to validate * @return Validation error message, null means validation passed */ public String validate(JsonSchema schema, Object data) { @@ -58,12 +58,12 @@ public class SchemaValidator { return null; // Validation passed } else { String errorMessage = errors.stream() - .map(ValidationMessage::getMessage) - .collect(Collectors.joining("; ")); + .map(ValidationMessage::getMessage) + .collect(Collectors.joining("; ")); logger.warn("Schema validation failed: {}", errorMessage); return errorMessage; } - + } catch (Exception e) { String errorMessage = "Schema validation error: " + e.getMessage(); logger.error(errorMessage, e); @@ -94,10 +94,10 @@ public class SchemaValidator { if (!(data instanceof java.util.Map)) { return "Expected object type for required field validation"; } - + @SuppressWarnings("unchecked") java.util.Map dataMap = (java.util.Map) data; - + for (String requiredField : schema.getRequiredFields()) { if (!dataMap.containsKey(requiredField) || dataMap.get(requiredField) == null) { return "Missing required field: " + requiredField; @@ -123,12 +123,12 @@ public class SchemaValidator { if (expectedType.equals(actualType)) { return true; } - + // Number type compatibility if ("number".equals(expectedType) && "integer".equals(actualType)) { return true; } - + return false; } } diff --git a/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/service/ContinuousConversationService.java b/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/service/ContinuousConversationService.java index 38e2b6bc..97a00f8c 100644 --- a/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/service/ContinuousConversationService.java +++ b/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/service/ContinuousConversationService.java @@ -26,47 +26,40 @@ import java.util.concurrent.ConcurrentHashMap; public class ContinuousConversationService { private static final Logger logger = LoggerFactory.getLogger(ContinuousConversationService.class); - - private final ChatClient chatClient; - private final NextSpeakerService nextSpeakerService; - - @Autowired - private LogStreamService logStreamService; - // 最大轮数限制,防止无限循环 private static final int MAX_TURNS = 20; - // 单轮对话超时时间(毫秒) private static final long TURN_TIMEOUT_MS = 60_000; // 60秒 - // 总对话超时时间(毫秒) private static final long TOTAL_TIMEOUT_MS = 10 * 60_000; // 10分钟 - // 继续对话的提示语 private static final String[] CONTINUE_PROMPTS = { - "Continue with the next steps to complete the task.", - "Please proceed with the remaining work.", - "What's the next step? Please continue.", - "Keep going with the task.", - "Continue the implementation." + "Continue with the next steps to complete the task.", + "Please proceed with the remaining work.", + "What's the next step? Please continue.", + "Keep going with the task.", + "Continue the implementation." }; - - // 在现有的ContinuousConversationService中添加以下改进 - + private final ChatClient chatClient; + private final NextSpeakerService nextSpeakerService; // 添加依赖注入 private final TaskSummaryService taskSummaryService; + + // 在现有的ContinuousConversationService中添加以下改进 private final Map taskStatusMap = new ConcurrentHashMap<>(); private final Map conversationResults = new ConcurrentHashMap<>(); - + @Autowired + private LogStreamService logStreamService; + // 修改构造函数 - public ContinuousConversationService(ChatClient chatClient, - NextSpeakerService nextSpeakerService, - TaskSummaryService taskSummaryService) { + public ContinuousConversationService(ChatClient chatClient, + NextSpeakerService nextSpeakerService, + TaskSummaryService taskSummaryService) { this.chatClient = chatClient; this.nextSpeakerService = nextSpeakerService; this.taskSummaryService = taskSummaryService; } - + // 添加任务状态管理方法 public TaskStatus getTaskStatus(String taskId) { return taskStatusMap.get(taskId); @@ -81,7 +74,7 @@ public class ContinuousConversationService { private void storeConversationResult(String taskId, ConversationResult result) { conversationResults.put(taskId, result); } - + public String startTask(String initialMessage) { String taskId = UUID.randomUUID().toString(); TaskStatus status = new TaskStatus(taskId); @@ -108,37 +101,37 @@ public class ContinuousConversationService { // 明确的简单对话模式 - 不需要工具 String[] simplePatterns = { - "你好", "hello", "hi", "嗨", "哈喽", - "谢谢", "thank you", "thanks", "感谢", - "再见", "goodbye", "bye", "拜拜", - "好的", "ok", "okay", "行", "可以", - "不用了", "算了", "没事", "不需要", - "怎么样", "如何", "什么意思", "是什么", - "介绍一下", "解释一下", "说明一下" + "你好", "hello", "hi", "嗨", "哈喽", + "谢谢", "thank you", "thanks", "感谢", + "再见", "goodbye", "bye", "拜拜", + "好的", "ok", "okay", "行", "可以", + "不用了", "算了", "没事", "不需要", + "怎么样", "如何", "什么意思", "是什么", + "介绍一下", "解释一下", "说明一下" }; // 检查是否是简单问候或确认 for (String pattern : simplePatterns) { if (lowerMessage.equals(pattern) || - (lowerMessage.length() <= 10 && lowerMessage.contains(pattern))) { + (lowerMessage.length() <= 10 && lowerMessage.contains(pattern))) { return false; } } // 明确需要工具的关键词 String[] toolRequiredPatterns = { - "创建", "create", "新建", "生成", "建立", - "编辑", "edit", "修改", "更新", "改变", - "删除", "delete", "移除", "清除", - "文件", "file", "目录", "folder", "项目", "project", - "代码", "code", "程序", "script", "函数", "function", - "分析", "analyze", "检查", "查看", "读取", "read", - "写入", "write", "保存", "save", - "搜索", "search", "查找", "find", - "下载", "download", "获取", "fetch", - "安装", "install", "配置", "config", - "运行", "run", "执行", "execute", - "测试", "test", "调试", "debug" + "创建", "create", "新建", "生成", "建立", + "编辑", "edit", "修改", "更新", "改变", + "删除", "delete", "移除", "清除", + "文件", "file", "目录", "folder", "项目", "project", + "代码", "code", "程序", "script", "函数", "function", + "分析", "analyze", "检查", "查看", "读取", "read", + "写入", "write", "保存", "save", + "搜索", "search", "查找", "find", + "下载", "download", "获取", "fetch", + "安装", "install", "配置", "config", + "运行", "run", "执行", "execute", + "测试", "test", "调试", "debug" }; // 检查是否包含工具相关关键词 @@ -156,9 +149,9 @@ public class ContinuousConversationService { // 包含路径、URL、代码片段等的消息 if (lowerMessage.contains("/") || lowerMessage.contains("\\") || - lowerMessage.contains("http") || lowerMessage.contains("www") || - lowerMessage.contains("{") || lowerMessage.contains("}") || - lowerMessage.contains("<") || lowerMessage.contains(">")) { + lowerMessage.contains("http") || lowerMessage.contains("www") || + lowerMessage.contains("{") || lowerMessage.contains("}") || + lowerMessage.contains("<") || lowerMessage.contains(">")) { return true; } @@ -166,7 +159,7 @@ public class ContinuousConversationService { // 这样可以避免不必要的工具准备状态显示 return false; } - + // 修改executeContinuousConversation方法 public ConversationResult executeContinuousConversation(String taskId, String initialMessage, List conversationHistory) { TaskStatus taskStatus = taskStatusMap.get(taskId); @@ -239,7 +232,7 @@ public class ContinuousConversationService { // 更新任务状态 - 显示当前响应的简短摘要 String responseSummary = responseText.length() > 100 ? - responseText.substring(0, 100) + "..." : responseText; + responseText.substring(0, 100) + "..." : responseText; taskStatus.setCurrentAction(String.format("第 %d 轮完成: %s", turnCount, responseSummary)); } @@ -280,24 +273,24 @@ public class ContinuousConversationService { long totalDuration = System.currentTimeMillis() - conversationStartTime; logger.info("Continuous conversation completed after {} turns in {}ms. Stop reason: {}", - turnCount, totalDuration, stopReason); + turnCount, totalDuration, stopReason); // 创建结果对象 ConversationResult result = new ConversationResult( - fullResponse.toString(), - turnResponses, - workingHistory, - turnCount, - turnCount >= MAX_TURNS, - stopReason, - totalDuration + fullResponse.toString(), + turnResponses, + workingHistory, + turnCount, + turnCount >= MAX_TURNS, + stopReason, + totalDuration ); // 更新任务状态为完成 taskStatus.setStatus("COMPLETED"); taskStatus.setCurrentAction("对话完成"); String summary = String.format("对话完成,共 %d 轮,耗时 %.1f 秒", - turnCount, totalDuration / 1000.0); + turnCount, totalDuration / 1000.0); if (stopReason != null) { summary += ",停止原因: " + stopReason; } @@ -334,9 +327,9 @@ public class ContinuousConversationService { // 调用AI(这里可以添加超时控制,但Spring AI目前不直接支持) ChatResponse response = chatClient.prompt() - .messages(conversationHistory) - .call() - .chatResponse(); + .messages(conversationHistory) + .call() + .chatResponse(); // 处理响应 Generation generation = response.getResult(); @@ -345,7 +338,7 @@ public class ContinuousConversationService { long turnDuration = System.currentTimeMillis() - turnStartTime; logger.debug("Turn {} completed in {}ms, response length: {} characters", - turnNumber, turnDuration, responseText != null ? responseText.length() : 0); + turnNumber, turnDuration, responseText != null ? responseText.length() : 0); return new TurnResult(true, responseText, null); @@ -393,7 +386,7 @@ public class ContinuousConversationService { // 只有在不确定的情况下才使用智能判断服务(包含LLM调用) try { NextSpeakerService.NextSpeakerResponse nextSpeaker = - nextSpeakerService.checkNextSpeaker(conversationHistory); + nextSpeakerService.checkNextSpeaker(conversationHistory); long duration = System.currentTimeMillis() - startTime; logger.debug("Next speaker check completed in {}ms, result: {}", duration, nextSpeaker); @@ -417,25 +410,25 @@ public class ContinuousConversationService { // 如果是前几轮且包含工具调用成功的标志,很可能需要继续 if (turnCount <= 10) { String[] toolCallIndicators = { - "successfully created", - "successfully updated", - "file created", - "file updated", - "✅", - "created file", - "updated file", - "next, i'll", - "now i'll", - "let me create", - "let me edit" + "successfully created", + "successfully updated", + "file created", + "file updated", + "✅", + "created file", + "updated file", + "next, i'll", + "now i'll", + "let me create", + "let me edit" }; for (String indicator : toolCallIndicators) { if (lowerResponse.contains(indicator)) { // 但如果同时包含明确的完成信号,则不继续 String[] completionSignals = { - "all files created", "project complete", "setup complete", - "everything is ready", "task completed", "all done" + "all files created", "project complete", "setup complete", + "everything is ready", "task completed", "all done" }; boolean hasCompletionSignal = false; @@ -478,9 +471,17 @@ public class ContinuousConversationService { this.errorMessage = errorMessage; } - public boolean isSuccess() { return success; } - public String getResponse() { return response; } - public String getErrorMessage() { return errorMessage; } + public boolean isSuccess() { + return success; + } + + public String getResponse() { + return response; + } + + public String getErrorMessage() { + return errorMessage; + } } /** @@ -496,8 +497,8 @@ public class ContinuousConversationService { private final long totalDurationMs; public ConversationResult(String fullResponse, List turnResponses, - List finalHistory, int totalTurns, boolean reachedMaxTurns, - String stopReason, long totalDurationMs) { + List finalHistory, int totalTurns, boolean reachedMaxTurns, + String stopReason, long totalDurationMs) { this.fullResponse = fullResponse; this.turnResponses = turnResponses; this.finalHistory = finalHistory; @@ -507,12 +508,32 @@ public class ContinuousConversationService { this.totalDurationMs = totalDurationMs; } - public String getFullResponse() { return fullResponse; } - public List getTurnResponses() { return turnResponses; } - public List getFinalHistory() { return finalHistory; } - public int getTotalTurns() { return totalTurns; } - public boolean isReachedMaxTurns() { return reachedMaxTurns; } - public String getStopReason() { return stopReason; } - public long getTotalDurationMs() { return totalDurationMs; } + public String getFullResponse() { + return fullResponse; + } + + public List getTurnResponses() { + return turnResponses; + } + + public List getFinalHistory() { + return finalHistory; + } + + public int getTotalTurns() { + return totalTurns; + } + + public boolean isReachedMaxTurns() { + return reachedMaxTurns; + } + + public String getStopReason() { + return stopReason; + } + + public long getTotalDurationMs() { + return totalDurationMs; + } } } diff --git a/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/service/LogEvent.java b/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/service/LogEvent.java index d0103984..80e640a9 100644 --- a/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/service/LogEvent.java +++ b/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/service/LogEvent.java @@ -7,22 +7,23 @@ import com.fasterxml.jackson.annotation.JsonInclude; */ @JsonInclude(JsonInclude.Include.NON_NULL) public class LogEvent { - + private String type; private String taskId; private String message; private String timestamp; - + // Constructors - public LogEvent() {} - + public LogEvent() { + } + public LogEvent(String type, String taskId, String message, String timestamp) { this.type = type; this.taskId = taskId; this.message = message; this.timestamp = timestamp; } - + // Static factory methods public static LogEvent createConnectionEvent(String taskId) { LogEvent event = new LogEvent(); @@ -30,43 +31,43 @@ public class LogEvent { event.setTaskId(taskId); event.setMessage("SSE连接已建立"); event.setTimestamp(java.time.LocalDateTime.now().format( - java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))); + java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))); return event; } - + // Getters and Setters public String getType() { return type; } - + public void setType(String type) { this.type = type; } - + public String getTaskId() { return taskId; } - + public void setTaskId(String taskId) { this.taskId = taskId; } - + public String getMessage() { return message; } - + public void setMessage(String message) { this.message = message; } - + public String getTimestamp() { return timestamp; } - + public void setTimestamp(String timestamp) { this.timestamp = timestamp; } - + @Override public String toString() { return "LogEvent{" + diff --git a/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/service/LogStreamService.java b/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/service/LogStreamService.java index 598ac390..36f654f3 100644 --- a/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/service/LogStreamService.java +++ b/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/service/LogStreamService.java @@ -18,49 +18,49 @@ import java.util.concurrent.ConcurrentHashMap; */ @Service public class LogStreamService { - + private static final Logger logger = LoggerFactory.getLogger(LogStreamService.class); private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); - + // 活跃的SSE连接 taskId -> SseEmitter private final Map activeConnections = new ConcurrentHashMap<>(); - + // JSON序列化器 private final ObjectMapper objectMapper = new ObjectMapper(); - + /** * 建立SSE连接 */ public SseEmitter createConnection(String taskId) { logger.info("🔗 建立SSE连接: taskId={}", taskId); - + SseEmitter emitter = new SseEmitter(0L); // 无超时 - + // 设置连接事件处理 emitter.onCompletion(() -> { logger.info("✅ SSE连接完成: taskId={}", taskId); activeConnections.remove(taskId); }); - + emitter.onTimeout(() -> { logger.warn("⏰ SSE连接超时: taskId={}", taskId); activeConnections.remove(taskId); }); - + emitter.onError((ex) -> { logger.error("❌ SSE连接错误: taskId={}, error={}", taskId, ex.getMessage()); activeConnections.remove(taskId); }); - + // 保存连接 activeConnections.put(taskId, emitter); - + // 发送连接成功消息 sendLogEvent(taskId, LogEvent.createConnectionEvent(taskId)); - + return emitter; } - + /** * 关闭SSE连接 */ @@ -75,7 +75,7 @@ public class LogStreamService { } } } - + /** * 推送工具开始执行事件 */ @@ -89,10 +89,10 @@ public class LogStreamService { event.setTimestamp(LocalDateTime.now().format(formatter)); event.setIcon(getToolIcon(toolName)); event.setStatus("RUNNING"); - + sendLogEvent(taskId, event); } - + /** * 推送工具执行成功事件 */ @@ -107,10 +107,10 @@ public class LogStreamService { event.setIcon(getToolIcon(toolName)); event.setStatus("SUCCESS"); event.setExecutionTime(executionTime); - + sendLogEvent(taskId, event); } - + /** * 推送工具执行失败事件 */ @@ -125,10 +125,10 @@ public class LogStreamService { event.setIcon("❌"); event.setStatus("ERROR"); event.setExecutionTime(executionTime); - + sendLogEvent(taskId, event); } - + /** * 推送任务完成事件 */ @@ -138,9 +138,9 @@ public class LogStreamService { event.setTaskId(taskId); event.setMessage("任务执行完成"); event.setTimestamp(LocalDateTime.now().format(formatter)); - + sendLogEvent(taskId, event); - + // 延迟关闭连接 new Thread(() -> { try { @@ -151,7 +151,7 @@ public class LogStreamService { } }).start(); } - + /** * 发送日志事件到前端 */ @@ -161,11 +161,11 @@ public class LogStreamService { try { String jsonData = objectMapper.writeValueAsString(event); logger.info("📤 准备推送日志事件: taskId={}, type={}, data={}", taskId, - event instanceof LogEvent ? ((LogEvent) event).getType() : "unknown", jsonData); + event instanceof LogEvent ? ((LogEvent) event).getType() : "unknown", jsonData); emitter.send(SseEmitter.event() - .name("log") - .data(jsonData)); + .name("log") + .data(jsonData)); logger.info("✅ 日志事件推送成功: taskId={}", taskId); } catch (IOException e) { @@ -176,23 +176,31 @@ public class LogStreamService { logger.warn("⚠️ 未找到SSE连接: taskId={}, 无法推送事件", taskId); } } - + /** * 获取工具图标 */ private String getToolIcon(String toolName) { switch (toolName) { - case "readFile": return "📖"; - case "writeFile": return "✏️"; - case "editFile": return "📝"; - case "listDirectory": return "📁"; - case "analyzeProject": return "🔍"; - case "scaffoldProject": return "🏗️"; - case "smartEdit": return "🧠"; - default: return "⚙️"; + case "readFile": + return "📖"; + case "writeFile": + return "✏️"; + case "editFile": + return "📝"; + case "listDirectory": + return "📁"; + case "analyzeProject": + return "🔍"; + case "scaffoldProject": + return "🏗️"; + case "smartEdit": + return "🧠"; + default: + return "⚙️"; } } - + /** * 获取活跃连接数 */ diff --git a/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/service/NextSpeakerService.java b/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/service/NextSpeakerService.java index 704f45ba..ae340ee7 100644 --- a/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/service/NextSpeakerService.java +++ b/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/service/NextSpeakerService.java @@ -22,7 +22,32 @@ import java.util.List; public class NextSpeakerService { private static final Logger logger = LoggerFactory.getLogger(NextSpeakerService.class); - + private static final String CHECK_PROMPT = """ + Analyze *only* the content and structure of your immediately preceding response (your last turn in the conversation history). + Based *strictly* on that response, determine who should logically speak next: the 'user' or the 'model' (you). + + **Decision Rules (apply in order):** + 1. **Model Continues:** If your last response explicitly states an immediate next action *you* intend to take + (e.g., "Next, I will...", "Now I'll process...", "Moving on to analyze...", "Let me create...", "I'll now...", + indicates an intended tool call that didn't execute), OR if the response seems clearly incomplete + (cut off mid-thought without a natural conclusion), then the **'model'** should speak next. + 2. **Question to User:** If your last response ends with a direct question specifically addressed *to the user*, + then the **'user'** should speak next. + 3. **Waiting for User:** If your last response completed a thought, statement, or task *and* does not meet + the criteria for Rule 1 (Model Continues) or Rule 2 (Question to User), it implies a pause expecting + user input or reaction. In this case, the **'user'** should speak next. + + **Output Format:** + Respond *only* in JSON format. Do not include any text outside the JSON structure. + """; + // 简化版本的检查提示,用于减少LLM调用开销 + private static final String SIMPLIFIED_CHECK_PROMPT = """ + Based on your last response, who should speak next: 'user' or 'model'? + Rules: If you stated a next action or response is incomplete -> 'model'. + If you asked user a question -> 'user'. + If task completed -> 'user'. + Respond in JSON: {"next_speaker": "user/model", "reasoning": "brief reason"} + """; private final ChatModel chatModel; private final ObjectMapper objectMapper; @@ -31,34 +56,6 @@ public class NextSpeakerService { this.objectMapper = new ObjectMapper(); } - private static final String CHECK_PROMPT = """ - Analyze *only* the content and structure of your immediately preceding response (your last turn in the conversation history). - Based *strictly* on that response, determine who should logically speak next: the 'user' or the 'model' (you). - - **Decision Rules (apply in order):** - 1. **Model Continues:** If your last response explicitly states an immediate next action *you* intend to take - (e.g., "Next, I will...", "Now I'll process...", "Moving on to analyze...", "Let me create...", "I'll now...", - indicates an intended tool call that didn't execute), OR if the response seems clearly incomplete - (cut off mid-thought without a natural conclusion), then the **'model'** should speak next. - 2. **Question to User:** If your last response ends with a direct question specifically addressed *to the user*, - then the **'user'** should speak next. - 3. **Waiting for User:** If your last response completed a thought, statement, or task *and* does not meet - the criteria for Rule 1 (Model Continues) or Rule 2 (Question to User), it implies a pause expecting - user input or reaction. In this case, the **'user'** should speak next. - - **Output Format:** - Respond *only* in JSON format. Do not include any text outside the JSON structure. - """; - - // 简化版本的检查提示,用于减少LLM调用开销 - private static final String SIMPLIFIED_CHECK_PROMPT = """ - Based on your last response, who should speak next: 'user' or 'model'? - Rules: If you stated a next action or response is incomplete -> 'model'. - If you asked user a question -> 'user'. - If task completed -> 'user'. - Respond in JSON: {"next_speaker": "user/model", "reasoning": "brief reason"} - """; - /** * 判断下一步应该由谁发言 - 优化版本,添加快速路径 */ @@ -115,15 +112,15 @@ public class NextSpeakerService { // 明确的停止信号 - 直接返回user String[] definiteStopSignals = { - "task completed successfully", - "all files created successfully", - "project setup complete", - "website is ready", - "application is ready", - "everything is ready", - "setup is complete", - "all tasks completed", - "work is complete" + "task completed successfully", + "all files created successfully", + "project setup complete", + "website is ready", + "application is ready", + "everything is ready", + "setup is complete", + "all tasks completed", + "work is complete" }; for (String signal : definiteStopSignals) { @@ -134,17 +131,17 @@ public class NextSpeakerService { // 明确的继续信号 - 直接返回model String[] definiteContinueSignals = { - "next, i will", - "now i will", - "let me create", - "let me edit", - "let me update", - "i'll create", - "i'll edit", - "i'll update", - "moving on to", - "proceeding to", - "next step is to" + "next, i will", + "now i will", + "let me create", + "let me edit", + "let me update", + "i'll create", + "i'll edit", + "i'll update", + "moving on to", + "proceeding to", + "next step is to" }; for (String signal : definiteContinueSignals) { @@ -205,8 +202,8 @@ public class NextSpeakerService { */ private boolean containsCompletionSignal(String lowerContent) { String[] completionSignals = { - "all done", "complete", "finished", "ready", "that's it", - "we're done", "task complete", "project complete" + "all done", "complete", "finished", "ready", "that's it", + "we're done", "task complete", "project complete" }; for (String signal : completionSignals) { @@ -222,15 +219,15 @@ public class NextSpeakerService { */ private boolean containsUserQuestion(String lowerContent) { String[] userQuestionPatterns = { - "what would you like", - "what do you want", - "would you like me to", - "do you want me to", - "should i", - "would you prefer", - "any preferences", - "what's next", - "what should i do next" + "what would you like", + "what do you want", + "would you like me to", + "do you want me to", + "should i", + "would you prefer", + "any preferences", + "what's next", + "what should i do next" }; for (String pattern : userQuestionPatterns) { @@ -250,39 +247,39 @@ public class NextSpeakerService { // 创建用于判断的对话历史 - 简化版本 List checkMessages = recentHistory.stream() - .map(msg -> { - if (msg instanceof UserMessage) { - // 截断过长的用户消息 - String text = msg.getText(); - if (text.length() > 500) { - text = text.substring(0, 500) + "..."; + .map(msg -> { + if (msg instanceof UserMessage) { + // 截断过长的用户消息 + String text = msg.getText(); + if (text.length() > 500) { + text = text.substring(0, 500) + "..."; + } + return new UserMessage(text); + } else if (msg instanceof AssistantMessage) { + // 截断过长的助手消息 + String text = msg.getText(); + if (text.length() > 500) { + text = text.substring(0, 500) + "..."; + } + return new AssistantMessage(text); } - return new UserMessage(text); - } else if (msg instanceof AssistantMessage) { - // 截断过长的助手消息 - String text = msg.getText(); - if (text.length() > 500) { - text = text.substring(0, 500) + "..."; - } - return new AssistantMessage(text); - } - return msg; - }) - .collect(java.util.stream.Collectors.toList()); + return msg; + }) + .collect(java.util.stream.Collectors.toList()); // 添加简化的检查提示 checkMessages.add(new UserMessage(SIMPLIFIED_CHECK_PROMPT)); // 使用输出转换器 BeanOutputConverter outputConverter = - new BeanOutputConverter<>(NextSpeakerResponse.class); + new BeanOutputConverter<>(NextSpeakerResponse.class); // 调用LLM - 这里可以考虑添加超时,但Spring AI目前不直接支持 ChatResponse response = ChatClient.create(chatModel) - .prompt() - .messages(checkMessages) - .call() - .chatResponse(); + .prompt() + .messages(checkMessages) + .call() + .chatResponse(); long duration = System.currentTimeMillis() - startTime; logger.debug("LLM check completed in {}ms", duration); @@ -318,8 +315,8 @@ public class NextSpeakerService { private NextSpeakerResponse parseManually(String responseText) { try { // 简单的手动解析 - if (responseText.toLowerCase().contains("\"next_speaker\"") && - responseText.toLowerCase().contains("\"model\"")) { + if (responseText.toLowerCase().contains("\"next_speaker\"") && + responseText.toLowerCase().contains("\"model\"")) { return new NextSpeakerResponse("model", "Parsed manually - model should continue"); } return new NextSpeakerResponse("user", "Parsed manually - user should speak"); @@ -340,13 +337,13 @@ public class NextSpeakerService { // 优先检查明确的停止指示词 - 扩展版本 String[] stopIndicators = { - "completed", "finished", "done", "ready", "all set", "task complete", - "project complete", "successfully created all", "that's it", "we're done", - "everything is ready", "all files created", "project is ready", - "task completed successfully", "all tasks completed", "work is complete", - "implementation complete", "setup complete", "configuration complete", - "files have been created", "project has been set up", "website is ready", - "application is ready", "all necessary files", "setup is complete" + "completed", "finished", "done", "ready", "all set", "task complete", + "project complete", "successfully created all", "that's it", "we're done", + "everything is ready", "all files created", "project is ready", + "task completed successfully", "all tasks completed", "work is complete", + "implementation complete", "setup complete", "configuration complete", + "files have been created", "project has been set up", "website is ready", + "application is ready", "all necessary files", "setup is complete" }; // 检查停止指示词 @@ -365,14 +362,14 @@ public class NextSpeakerService { // 扩展的继续指示词 String[] continueIndicators = { - "next, i", "now i", "let me", "i'll", "i will", "moving on", - "proceeding", "continuing", "then i", "after that", "following this", - "now let's", "let's now", "i need to", "i should", "i'm going to", - "next step", "continuing with", "moving to", "proceeding to", - "now creating", "now editing", "now updating", "now modifying", - "let me create", "let me edit", "let me update", "let me modify", - "i'll create", "i'll edit", "i'll update", "i'll modify", - "creating the", "editing the", "updating the", "modifying the" + "next, i", "now i", "let me", "i'll", "i will", "moving on", + "proceeding", "continuing", "then i", "after that", "following this", + "now let's", "let's now", "i need to", "i should", "i'm going to", + "next step", "continuing with", "moving to", "proceeding to", + "now creating", "now editing", "now updating", "now modifying", + "let me create", "let me edit", "let me update", "let me modify", + "i'll create", "i'll edit", "i'll update", "i'll modify", + "creating the", "editing the", "updating the", "modifying the" }; // 检查继续指示词 @@ -406,25 +403,25 @@ public class NextSpeakerService { // 工具调用成功的典型模式 String[] toolSuccessPatterns = { - "successfully created", - "successfully updated", - "successfully modified", - "successfully edited", - "file created", - "file updated", - "file modified", - "file edited", - "created file", - "updated file", - "modified file", - "edited file", - "✅", // 成功标记 - "file has been created", - "file has been updated", - "file has been modified", - "content has been", - "successfully wrote", - "successfully saved" + "successfully created", + "successfully updated", + "successfully modified", + "successfully edited", + "file created", + "file updated", + "file modified", + "file edited", + "created file", + "updated file", + "modified file", + "edited file", + "✅", // 成功标记 + "file has been created", + "file has been updated", + "file has been modified", + "content has been", + "successfully wrote", + "successfully saved" }; for (String pattern : toolSuccessPatterns) { @@ -441,16 +438,16 @@ public class NextSpeakerService { */ private boolean containsFileOperationIntent(String lowerResponse) { String[] fileOperationIntents = { - "create a", "create the", "creating a", "creating the", - "edit a", "edit the", "editing a", "editing the", - "update a", "update the", "updating a", "updating the", - "modify a", "modify the", "modifying a", "modifying the", - "write a", "write the", "writing a", "writing the", - "generate a", "generate the", "generating a", "generating the", - "add to", "adding to", "append to", "appending to", - "need to create", "need to edit", "need to update", "need to modify", - "will create", "will edit", "will update", "will modify", - "going to create", "going to edit", "going to update", "going to modify" + "create a", "create the", "creating a", "creating the", + "edit a", "edit the", "editing a", "editing the", + "update a", "update the", "updating a", "updating the", + "modify a", "modify the", "modifying a", "modifying the", + "write a", "write the", "writing a", "writing the", + "generate a", "generate the", "generating a", "generating the", + "add to", "adding to", "append to", "appending to", + "need to create", "need to edit", "need to update", "need to modify", + "will create", "will edit", "will update", "will modify", + "going to create", "going to edit", "going to update", "going to modify" }; for (String intent : fileOperationIntents) { @@ -468,11 +465,12 @@ public class NextSpeakerService { public static class NextSpeakerResponse { @JsonProperty("next_speaker") private String nextSpeaker; - + @JsonProperty("reasoning") private String reasoning; - public NextSpeakerResponse() {} + public NextSpeakerResponse() { + } public NextSpeakerResponse(String nextSpeaker, String reasoning) { this.nextSpeaker = nextSpeaker; diff --git a/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/service/ProjectContextAnalyzer.java b/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/service/ProjectContextAnalyzer.java index 7172d42d..1a059ad5 100644 --- a/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/service/ProjectContextAnalyzer.java +++ b/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/service/ProjectContextAnalyzer.java @@ -22,98 +22,99 @@ import java.util.stream.Stream; */ @Service public class ProjectContextAnalyzer { - + private static final Logger logger = LoggerFactory.getLogger(ProjectContextAnalyzer.class); - + @Autowired public ProjectTypeDetector projectTypeDetector; @Autowired public ProjectDiscoveryService projectDiscoveryService; - + /** * 分析项目并生成完整上下文 + * * @param projectRoot 项目根目录 * @return 项目上下文信息 */ public ProjectContext analyzeProject(Path projectRoot) { logger.info("Starting comprehensive project analysis for: {}", projectRoot); - + ProjectContext context = new ProjectContext(projectRoot); - + try { // 1. 检测项目类型 ProjectType projectType = projectTypeDetector.detectProjectType(projectRoot); context.setProjectType(projectType); logger.debug("Detected project type: {}", projectType); - + // 2. 分析项目结构 ProjectStructure structure = projectDiscoveryService.analyzeProjectStructure(projectRoot); context.setProjectStructure(structure); - logger.debug("Analyzed project structure with {} directories", - structure.getDirectories().size()); - + logger.debug("Analyzed project structure with {} directories", + structure.getDirectories().size()); + // 3. 分析依赖关系 - List dependencies = - projectDiscoveryService.analyzeDependencies(projectRoot); + List dependencies = + projectDiscoveryService.analyzeDependencies(projectRoot); context.setDependencies(dependencies); logger.debug("Found {} dependencies", dependencies.size()); - + // 4. 查找配置文件 - List configFiles = - projectDiscoveryService.findConfigurationFiles(projectRoot); + List configFiles = + projectDiscoveryService.findConfigurationFiles(projectRoot); context.setConfigFiles(configFiles); logger.debug("Found {} configuration files", configFiles.size()); - + // 5. 分析代码统计 ProjectContext.CodeStatistics codeStats = analyzeCodeStatistics(projectRoot, projectType); context.setCodeStatistics(codeStats); logger.debug("Code statistics: {} total lines", codeStats.getTotalLines()); - + // 6. 收集项目元数据 Map metadata = collectProjectMetadata(projectRoot, projectType); context.setMetadata(metadata); - + // 7. 生成上下文摘要 String summary = context.generateContextSummary(); logger.debug("Generated context summary with {} characters", summary.length()); - + logger.info("Project analysis completed successfully for: {}", projectRoot); return context; - + } catch (Exception e) { logger.error("Error during project analysis for: " + projectRoot, e); // 返回部分分析结果 return context; } } - + /** * 分析代码统计信息 */ private ProjectContext.CodeStatistics analyzeCodeStatistics(Path projectRoot, ProjectType projectType) { logger.debug("Analyzing code statistics for: {}", projectRoot); - + ProjectContext.CodeStatistics stats = new ProjectContext.CodeStatistics(); - + try { analyzeCodeInDirectory(projectRoot, stats, projectType, 0, 3); } catch (Exception e) { logger.warn("Error analyzing code statistics", e); } - + return stats; } - + /** * 递归分析目录中的代码 */ - private void analyzeCodeInDirectory(Path directory, ProjectContext.CodeStatistics stats, - ProjectType projectType, int currentDepth, int maxDepth) { + private void analyzeCodeInDirectory(Path directory, ProjectContext.CodeStatistics stats, + ProjectType projectType, int currentDepth, int maxDepth) { if (currentDepth > maxDepth) { return; } - + try (Stream paths = Files.list(directory)) { paths.forEach(path -> { try { @@ -134,26 +135,26 @@ public class ProjectContextAnalyzer { logger.warn("Error listing directory: " + directory, e); } } - + /** * 分析单个代码文件 */ private void analyzeCodeFile(Path filePath, ProjectContext.CodeStatistics stats, ProjectType projectType) { String fileName = filePath.getFileName().toString(); String extension = getFileExtension(fileName).toLowerCase(); - + // 只分析代码文件 if (!isCodeFile(extension, projectType)) { return; } - + try { List lines = Files.readAllLines(filePath); int totalLines = lines.size(); int codeLines = 0; int commentLines = 0; int blankLines = 0; - + for (String line : lines) { String trimmedLine = line.trim(); if (trimmedLine.isEmpty()) { @@ -164,17 +165,17 @@ public class ProjectContextAnalyzer { codeLines++; } } - + // 更新统计信息 stats.setTotalLines(stats.getTotalLines() + totalLines); stats.setCodeLines(stats.getCodeLines() + codeLines); stats.setCommentLines(stats.getCommentLines() + commentLines); stats.setBlankLines(stats.getBlankLines() + blankLines); - + // 按语言统计 String language = getLanguageByExtension(extension); stats.addLanguageLines(language, totalLines); - + // 分析类和方法(简单实现) if (extension.equals(".java")) { analyzeJavaFile(lines, stats); @@ -183,12 +184,12 @@ public class ProjectContextAnalyzer { } else if (extension.equals(".py")) { analyzePythonFile(lines, stats); } - + } catch (IOException e) { logger.warn("Error reading file for code analysis: " + filePath, e); } } - + /** * 分析Java文件 */ @@ -203,21 +204,21 @@ public class ProjectContextAnalyzer { } } } - + /** * 分析JavaScript文件 */ private void analyzeJavaScriptFile(List lines, ProjectContext.CodeStatistics stats) { for (String line : lines) { String trimmedLine = line.trim(); - if (trimmedLine.matches(".*\\bfunction\\s+\\w+.*") || - trimmedLine.matches(".*\\w+\\s*:\\s*function.*") || - trimmedLine.matches(".*\\w+\\s*=\\s*\\(.*\\)\\s*=>.*")) { + if (trimmedLine.matches(".*\\bfunction\\s+\\w+.*") || + trimmedLine.matches(".*\\w+\\s*:\\s*function.*") || + trimmedLine.matches(".*\\w+\\s*=\\s*\\(.*\\)\\s*=>.*")) { stats.setTotalFunctions(stats.getTotalFunctions() + 1); } } } - + /** * 分析Python文件 */ @@ -232,76 +233,76 @@ public class ProjectContextAnalyzer { } } } - + /** * 收集项目元数据 */ private Map collectProjectMetadata(Path projectRoot, ProjectType projectType) { Map metadata = new HashMap<>(); - + metadata.put("projectName", projectRoot.getFileName().toString()); metadata.put("projectType", projectType.name()); metadata.put("primaryLanguage", projectType.getPrimaryLanguage()); metadata.put("packageManager", projectType.getPackageManager()); metadata.put("analysisTimestamp", System.currentTimeMillis()); - + // 检查版本控制 if (Files.exists(projectRoot.resolve(".git"))) { metadata.put("versionControl", "Git"); } - + // 检查CI/CD配置 if (Files.exists(projectRoot.resolve(".github"))) { metadata.put("cicd", "GitHub Actions"); } else if (Files.exists(projectRoot.resolve(".gitlab-ci.yml"))) { metadata.put("cicd", "GitLab CI"); } - + // 检查Docker支持 if (Files.exists(projectRoot.resolve("Dockerfile"))) { metadata.put("containerization", "Docker"); } - + return metadata; } - + /** * 生成编辑上下文 */ public String buildEditContext(Path projectRoot, String editDescription) { logger.debug("Building edit context for: {}", projectRoot); - + ProjectContext context = analyzeProject(projectRoot); - + StringBuilder contextBuilder = new StringBuilder(); contextBuilder.append("=== EDIT CONTEXT ===\n"); contextBuilder.append("Edit Request: ").append(editDescription).append("\n\n"); contextBuilder.append(context.generateContextSummary()); - + return contextBuilder.toString(); } - + // 辅助方法 private boolean shouldSkipDirectory(String dirName) { - return dirName.equals(".git") || dirName.equals("node_modules") || - dirName.equals("target") || dirName.equals("build") || - dirName.equals("dist") || dirName.equals("__pycache__") || - dirName.startsWith("."); + return dirName.equals(".git") || dirName.equals("node_modules") || + dirName.equals("target") || dirName.equals("build") || + dirName.equals("dist") || dirName.equals("__pycache__") || + dirName.startsWith("."); } - + private String getFileExtension(String fileName) { int lastDot = fileName.lastIndexOf('.'); return lastDot > 0 ? fileName.substring(lastDot) : ""; } - + private boolean isCodeFile(String extension, ProjectType projectType) { return extension.equals(".java") || extension.equals(".js") || extension.equals(".ts") || - extension.equals(".py") || extension.equals(".html") || extension.equals(".css") || - extension.equals(".jsx") || extension.equals(".tsx") || extension.equals(".vue") || - extension.equals(".go") || extension.equals(".rs") || extension.equals(".php") || - extension.equals(".cs") || extension.equals(".cpp") || extension.equals(".c"); + extension.equals(".py") || extension.equals(".html") || extension.equals(".css") || + extension.equals(".jsx") || extension.equals(".tsx") || extension.equals(".vue") || + extension.equals(".go") || extension.equals(".rs") || extension.equals(".php") || + extension.equals(".cs") || extension.equals(".cpp") || extension.equals(".c"); } - + private boolean isCommentLine(String line, String extension) { switch (extension) { case ".java": @@ -319,21 +320,35 @@ public class ProjectContextAnalyzer { return line.startsWith("#") || line.startsWith("//"); } } - + private String getLanguageByExtension(String extension) { switch (extension) { - case ".java": return "Java"; - case ".js": case ".jsx": return "JavaScript"; - case ".ts": case ".tsx": return "TypeScript"; - case ".py": return "Python"; - case ".html": return "HTML"; - case ".css": return "CSS"; - case ".vue": return "Vue"; - case ".go": return "Go"; - case ".rs": return "Rust"; - case ".php": return "PHP"; - case ".cs": return "C#"; - default: return "Other"; + case ".java": + return "Java"; + case ".js": + case ".jsx": + return "JavaScript"; + case ".ts": + case ".tsx": + return "TypeScript"; + case ".py": + return "Python"; + case ".html": + return "HTML"; + case ".css": + return "CSS"; + case ".vue": + return "Vue"; + case ".go": + return "Go"; + case ".rs": + return "Rust"; + case ".php": + return "PHP"; + case ".cs": + return "C#"; + default: + return "Other"; } } } diff --git a/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/service/ProjectDiscoveryService.java b/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/service/ProjectDiscoveryService.java index 02de56de..ee320d5d 100644 --- a/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/service/ProjectDiscoveryService.java +++ b/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/service/ProjectDiscoveryService.java @@ -23,84 +23,83 @@ import java.util.stream.Stream; */ @Service public class ProjectDiscoveryService { - + private static final Logger logger = LoggerFactory.getLogger(ProjectDiscoveryService.class); - + private final ObjectMapper objectMapper = new ObjectMapper(); @Autowired private ProjectTypeDetector projectTypeDetector; - - private final ObjectMapper objectMapper = new ObjectMapper(); - + /** * 分析项目结构 + * * @param projectRoot 项目根目录 * @return 项目结构信息 */ public ProjectStructure analyzeProjectStructure(Path projectRoot) { logger.debug("Analyzing project structure for: {}", projectRoot); - + ProjectType projectType = projectTypeDetector.detectProjectType(projectRoot); ProjectStructure structure = new ProjectStructure(projectRoot, projectType); - + try { analyzeDirectoryStructure(projectRoot, structure, 0, 3); // 最大深度3层 structure.markImportantDirectories(); - + logger.info("Project structure analysis completed for: {}", projectRoot); return structure; - + } catch (IOException e) { logger.error("Error analyzing project structure for: " + projectRoot, e); return structure; // 返回部分分析结果 } } - + /** * 递归分析目录结构 */ - private void analyzeDirectoryStructure(Path currentPath, ProjectStructure structure, - int currentDepth, int maxDepth) throws IOException { + private void analyzeDirectoryStructure(Path currentPath, ProjectStructure structure, + int currentDepth, int maxDepth) throws IOException { if (currentDepth > maxDepth) { return; } - + try (Stream paths = Files.list(currentPath)) { paths.forEach(path -> { try { if (Files.isDirectory(path)) { String dirName = path.getFileName().toString(); String relativePath = structure.getProjectRoot().relativize(path).toString(); - + // 跳过常见的忽略目录 if (shouldIgnoreDirectory(dirName)) { return; } - - ProjectStructure.DirectoryInfo dirInfo = - new ProjectStructure.DirectoryInfo(dirName, relativePath); - + + ProjectStructure.DirectoryInfo dirInfo = + new ProjectStructure.DirectoryInfo(dirName, relativePath); + // 分析目录中的文件 analyzeDirectoryFiles(path, dirInfo); structure.addDirectory(dirInfo); - + // 递归分析子目录 if (currentDepth < maxDepth) { analyzeDirectoryStructure(path, structure, currentDepth + 1, maxDepth); } - + } else if (Files.isRegularFile(path)) { // 处理根目录下的文件 String fileName = path.getFileName().toString(); String extension = getFileExtension(fileName); - + structure.addFileType(extension, 1); structure.setTotalFiles(structure.getTotalFiles() + 1); - + // 检查是否为关键文件 if (isKeyFile(fileName, structure.getProjectType())) { structure.addKeyFile(fileName); } - + // 累计文件大小 try { structure.setTotalSize(structure.getTotalSize() + Files.size(path)); @@ -114,31 +113,31 @@ public class ProjectDiscoveryService { }); } } - + /** * 分析目录中的文件 */ private void analyzeDirectoryFiles(Path directory, ProjectStructure.DirectoryInfo dirInfo) { try (Stream files = Files.list(directory)) { files.filter(Files::isRegularFile) - .forEach(file -> { - String fileName = file.getFileName().toString(); - dirInfo.addFile(fileName); - }); + .forEach(file -> { + String fileName = file.getFileName().toString(); + dirInfo.addFile(fileName); + }); } catch (IOException e) { logger.warn("Error analyzing files in directory: {}", directory); } } - + /** * 分析项目依赖 */ public List analyzeDependencies(Path projectRoot) { logger.debug("Analyzing dependencies for: {}", projectRoot); - + List dependencies = new ArrayList<>(); ProjectType projectType = projectTypeDetector.detectProjectType(projectRoot); - + try { switch (projectType) { case JAVA_MAVEN: @@ -164,95 +163,95 @@ public class ProjectDiscoveryService { } catch (Exception e) { logger.error("Error analyzing dependencies for: " + projectRoot, e); } - + logger.info("Found {} dependencies for project: {}", dependencies.size(), projectRoot); return dependencies; } - + /** * 分析Maven依赖 */ private List analyzeMavenDependencies(Path projectRoot) { List dependencies = new ArrayList<>(); Path pomFile = projectRoot.resolve("pom.xml"); - + if (!Files.exists(pomFile)) { return dependencies; } - + try { String pomContent = Files.readString(pomFile); // 简单的XML解析 - 在实际项目中应该使用专门的XML解析器 if (pomContent.contains("spring-boot-starter-web")) { dependencies.add(new ProjectContext.DependencyInfo( - "spring-boot-starter-web", "auto", "compile")); + "spring-boot-starter-web", "auto", "compile")); } if (pomContent.contains("spring-boot-starter-data-jpa")) { dependencies.add(new ProjectContext.DependencyInfo( - "spring-boot-starter-data-jpa", "auto", "compile")); + "spring-boot-starter-data-jpa", "auto", "compile")); } if (pomContent.contains("spring-boot-starter-test")) { dependencies.add(new ProjectContext.DependencyInfo( - "spring-boot-starter-test", "auto", "test")); + "spring-boot-starter-test", "auto", "test")); } // 可以添加更多依赖检测逻辑 - + } catch (IOException e) { logger.warn("Error reading pom.xml", e); } - + return dependencies; } - + /** * 分析NPM依赖 */ private List analyzeNpmDependencies(Path projectRoot) { List dependencies = new ArrayList<>(); Path packageJsonPath = projectRoot.resolve("package.json"); - + if (!Files.exists(packageJsonPath)) { return dependencies; } - + try { String content = Files.readString(packageJsonPath); JsonNode packageJson = objectMapper.readTree(content); - + // 分析生产依赖 JsonNode deps = packageJson.get("dependencies"); if (deps != null) { deps.fields().forEachRemaining(entry -> { dependencies.add(new ProjectContext.DependencyInfo( - entry.getKey(), entry.getValue().asText(), "production")); + entry.getKey(), entry.getValue().asText(), "production")); }); } - + // 分析开发依赖 JsonNode devDeps = packageJson.get("devDependencies"); if (devDeps != null) { devDeps.fields().forEachRemaining(entry -> { ProjectContext.DependencyInfo depInfo = new ProjectContext.DependencyInfo( - entry.getKey(), entry.getValue().asText(), "development"); + entry.getKey(), entry.getValue().asText(), "development"); depInfo.setDirectDependency(true); dependencies.add(depInfo); }); } - + } catch (IOException e) { logger.warn("Error reading package.json", e); } - + return dependencies; } - + /** * 分析Python依赖 */ private List analyzePythonDependencies(Path projectRoot) { List dependencies = new ArrayList<>(); Path requirementsFile = projectRoot.resolve("requirements.txt"); - + if (Files.exists(requirementsFile)) { try { List lines = Files.readAllLines(requirementsFile); @@ -269,26 +268,26 @@ public class ProjectDiscoveryService { logger.warn("Error reading requirements.txt", e); } } - + return dependencies; } - + /** * 查找配置文件 */ public List findConfigurationFiles(Path projectRoot) { logger.debug("Finding configuration files for: {}", projectRoot); - + List configFiles = new ArrayList<>(); ProjectType projectType = projectTypeDetector.detectProjectType(projectRoot); - + try { // 通用配置文件 addConfigFileIfExists(configFiles, projectRoot, "application.properties", "properties"); addConfigFileIfExists(configFiles, projectRoot, "application.yml", "yaml"); addConfigFileIfExists(configFiles, projectRoot, "application.yaml", "yaml"); addConfigFileIfExists(configFiles, projectRoot, "config.json", "json"); - + // 项目类型特定的配置文件 switch (projectType) { case JAVA_MAVEN: @@ -311,47 +310,47 @@ public class ProjectDiscoveryService { addConfigFileIfExists(configFiles, projectRoot, "setup.py", "python"); break; } - + } catch (Exception e) { logger.error("Error finding configuration files for: " + projectRoot, e); } - + logger.info("Found {} configuration files for project: {}", configFiles.size(), projectRoot); return configFiles; } - + /** * 添加配置文件(如果存在) */ - private void addConfigFileIfExists(List configFiles, - Path projectRoot, String fileName, String fileType) { + private void addConfigFileIfExists(List configFiles, + Path projectRoot, String fileName, String fileType) { Path configPath = projectRoot.resolve(fileName); if (Files.exists(configPath)) { String relativePath = projectRoot.relativize(configPath).toString(); - ProjectContext.ConfigFile configFile = - new ProjectContext.ConfigFile(fileName, relativePath, fileType); - + ProjectContext.ConfigFile configFile = + new ProjectContext.ConfigFile(fileName, relativePath, fileType); + // 标记主要配置文件 - if (fileName.equals("pom.xml") || fileName.equals("package.json") || - fileName.startsWith("application.")) { + if (fileName.equals("pom.xml") || fileName.equals("package.json") || + fileName.startsWith("application.")) { configFile.setMainConfig(true); } - + configFiles.add(configFile); } } - + /** * 检查是否应该忽略目录 */ private boolean shouldIgnoreDirectory(String dirName) { - return dirName.equals(".git") || dirName.equals(".svn") || - dirName.equals("node_modules") || dirName.equals("target") || - dirName.equals("build") || dirName.equals("dist") || - dirName.equals("__pycache__") || dirName.equals(".idea") || - dirName.equals(".vscode") || dirName.startsWith("."); + return dirName.equals(".git") || dirName.equals(".svn") || + dirName.equals("node_modules") || dirName.equals("target") || + dirName.equals("build") || dirName.equals("dist") || + dirName.equals("__pycache__") || dirName.equals(".idea") || + dirName.equals(".vscode") || dirName.startsWith("."); } - + /** * 获取文件扩展名 */ @@ -359,17 +358,17 @@ public class ProjectDiscoveryService { int lastDot = fileName.lastIndexOf('.'); return lastDot > 0 ? fileName.substring(lastDot) : ""; } - + /** * 检查是否为关键文件 */ private boolean isKeyFile(String fileName, ProjectType projectType) { // 通用关键文件 - if (fileName.equals("README.md") || fileName.equals("LICENSE") || - fileName.equals("Dockerfile") || fileName.equals(".gitignore")) { + if (fileName.equals("README.md") || fileName.equals("LICENSE") || + fileName.equals("Dockerfile") || fileName.equals(".gitignore")) { return true; } - + // 项目类型特定的关键文件 if (projectType != null) { String keyFile = projectType.getKeyFile(); @@ -377,7 +376,7 @@ public class ProjectDiscoveryService { return fileName.equals(keyFile) || fileName.matches(keyFile); } } - + return false; } } diff --git a/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/service/ProjectTemplateExtensions.java b/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/service/ProjectTemplateExtensions.java index 632af03f..5a9e754e 100644 --- a/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/service/ProjectTemplateExtensions.java +++ b/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/service/ProjectTemplateExtensions.java @@ -11,443 +11,443 @@ import java.util.Map; */ @Service public class ProjectTemplateExtensions { - + /** * 生成README.md内容 */ public String generateReadmeContent(Map variables) { return String.format(""" - # %s - - %s - - ## 🚀 Getting Started - - ### Prerequisites - - - Java 17 or higher (for Java projects) - - Node.js 16+ (for JavaScript projects) - - Python 3.8+ (for Python projects) - - ### Installation - - 1. Clone the repository: - ```bash - git clone - cd %s - ``` - - 2. Install dependencies: - ```bash - # For Java Maven projects - mvn clean install - - # For Node.js projects - npm install - - # For Python projects - pip install -r requirements.txt - ``` - - 3. Run the application: - ```bash - # For Java Maven projects - mvn spring-boot:run - - # For Node.js projects - npm start - - # For Python projects - python main.py - ``` - - ## 📁 Project Structure - - ``` - %s/ - ├── src/ # Source code - ├── test/ # Test files - ├── docs/ # Documentation - ├── README.md # This file - └── ... - ``` - - ## 🛠️ Development - - ### Running Tests - - ```bash - # For Java projects - mvn test - - # For Node.js projects - npm test - - # For Python projects - python -m pytest - ``` - - ### Building - - ```bash - # For Java projects - mvn clean package - - # For Node.js projects - npm run build - - # For Python projects - python setup.py build - ``` - - ## 📝 Features - - - Feature 1: Description - - Feature 2: Description - - Feature 3: Description - - ## 🤝 Contributing - - 1. Fork the project - 2. Create your feature branch (`git checkout -b feature/AmazingFeature`) - 3. Commit your changes (`git commit -m 'Add some AmazingFeature'`) - 4. Push to the branch (`git push origin feature/AmazingFeature`) - 5. Open a Pull Request - - ## 📄 License - - This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. - - ## 👥 Authors - - - **%s** - *Initial work* - [%s](mailto:%s) - - ## 🙏 Acknowledgments - - - Hat tip to anyone whose code was used - - Inspiration - - etc - - --- - - Created with ❤️ by %s - """, - variables.get("PROJECT_NAME_PASCAL"), - variables.get("DESCRIPTION"), - variables.get("PROJECT_NAME"), - variables.get("PROJECT_NAME"), - variables.get("AUTHOR"), - variables.get("AUTHOR"), - variables.get("EMAIL"), - variables.get("AUTHOR") + # %s + + %s + + ## 🚀 Getting Started + + ### Prerequisites + + - Java 17 or higher (for Java projects) + - Node.js 16+ (for JavaScript projects) + - Python 3.8+ (for Python projects) + + ### Installation + + 1. Clone the repository: + ```bash + git clone + cd %s + ``` + + 2. Install dependencies: + ```bash + # For Java Maven projects + mvn clean install + + # For Node.js projects + npm install + + # For Python projects + pip install -r requirements.txt + ``` + + 3. Run the application: + ```bash + # For Java Maven projects + mvn spring-boot:run + + # For Node.js projects + npm start + + # For Python projects + python main.py + ``` + + ## 📁 Project Structure + + ``` + %s/ + ├── src/ # Source code + ├── test/ # Test files + ├── docs/ # Documentation + ├── README.md # This file + └── ... + ``` + + ## 🛠️ Development + + ### Running Tests + + ```bash + # For Java projects + mvn test + + # For Node.js projects + npm test + + # For Python projects + python -m pytest + ``` + + ### Building + + ```bash + # For Java projects + mvn clean package + + # For Node.js projects + npm run build + + # For Python projects + python setup.py build + ``` + + ## 📝 Features + + - Feature 1: Description + - Feature 2: Description + - Feature 3: Description + + ## 🤝 Contributing + + 1. Fork the project + 2. Create your feature branch (`git checkout -b feature/AmazingFeature`) + 3. Commit your changes (`git commit -m 'Add some AmazingFeature'`) + 4. Push to the branch (`git push origin feature/AmazingFeature`) + 5. Open a Pull Request + + ## 📄 License + + This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. + + ## 👥 Authors + + - **%s** - *Initial work* - [%s](mailto:%s) + + ## 🙏 Acknowledgments + + - Hat tip to anyone whose code was used + - Inspiration + - etc + + --- + + Created with ❤️ by %s + """, + variables.get("PROJECT_NAME_PASCAL"), + variables.get("DESCRIPTION"), + variables.get("PROJECT_NAME"), + variables.get("PROJECT_NAME"), + variables.get("AUTHOR"), + variables.get("AUTHOR"), + variables.get("EMAIL"), + variables.get("AUTHOR") ); } - + /** * 生成.gitignore内容 */ public String generateGitignoreContent(ProjectType projectType) { StringBuilder gitignore = new StringBuilder(); - + // 通用忽略规则 gitignore.append(""" - # General - .DS_Store - .DS_Store? - ._* - .Spotlight-V100 - .Trashes - ehthumbs.db - Thumbs.db - - # IDE - .idea/ - .vscode/ - *.swp - *.swo - *~ - - # Logs - logs - *.log - npm-debug.log* - yarn-debug.log* - yarn-error.log* - - # Runtime data - pids - *.pid - *.seed - *.pid.lock - - # Coverage directory used by tools like istanbul - coverage/ - - # Dependency directories - node_modules/ - - """); - + # General + .DS_Store + .DS_Store? + ._* + .Spotlight-V100 + .Trashes + ehthumbs.db + Thumbs.db + + # IDE + .idea/ + .vscode/ + *.swp + *.swo + *~ + + # Logs + logs + *.log + npm-debug.log* + yarn-debug.log* + yarn-error.log* + + # Runtime data + pids + *.pid + *.seed + *.pid.lock + + # Coverage directory used by tools like istanbul + coverage/ + + # Dependency directories + node_modules/ + + """); + // 项目类型特定的忽略规则 switch (projectType) { case JAVA_MAVEN: case JAVA_GRADLE: case SPRING_BOOT: gitignore.append(""" - # Java - *.class - *.jar - *.war - *.ear - *.nar - hs_err_pid* - - # Maven - target/ - pom.xml.tag - pom.xml.releaseBackup - pom.xml.versionsBackup - pom.xml.next - release.properties - dependency-reduced-pom.xml - buildNumber.properties - .mvn/timing.properties - .mvn/wrapper/maven-wrapper.jar - - # Gradle - .gradle - build/ - !gradle/wrapper/gradle-wrapper.jar - !**/src/main/**/build/ - !**/src/test/**/build/ - - # Spring Boot - spring-boot-*.log - - """); + # Java + *.class + *.jar + *.war + *.ear + *.nar + hs_err_pid* + + # Maven + target/ + pom.xml.tag + pom.xml.releaseBackup + pom.xml.versionsBackup + pom.xml.next + release.properties + dependency-reduced-pom.xml + buildNumber.properties + .mvn/timing.properties + .mvn/wrapper/maven-wrapper.jar + + # Gradle + .gradle + build/ + !gradle/wrapper/gradle-wrapper.jar + !**/src/main/**/build/ + !**/src/test/**/build/ + + # Spring Boot + spring-boot-*.log + + """); break; - + case NODE_JS: case REACT: case VUE: case ANGULAR: case NEXT_JS: gitignore.append(""" - # Node.js - node_modules/ - npm-debug.log* - yarn-debug.log* - yarn-error.log* - lerna-debug.log* - - # Runtime data - pids - *.pid - *.seed - *.pid.lock - - # Coverage directory used by tools like istanbul - coverage/ - *.lcov - - # nyc test coverage - .nyc_output - - # Grunt intermediate storage - .grunt - - # Bower dependency directory - bower_components - - # node-waf configuration - .lock-wscript - - # Compiled binary addons - build/Release - - # Dependency directories - node_modules/ - jspm_packages/ - - # Optional npm cache directory - .npm - - # Optional eslint cache - .eslintcache - - # Microbundle cache - .rpt2_cache/ - .rts2_cache_cjs/ - .rts2_cache_es/ - .rts2_cache_umd/ - - # Optional REPL history - .node_repl_history - - # Output of 'npm pack' - *.tgz - - # Yarn Integrity file - .yarn-integrity - - # dotenv environment variables file - .env - .env.test - .env.local - .env.development.local - .env.test.local - .env.production.local - - # parcel-bundler cache - .cache - .parcel-cache - - # Next.js build output - .next - out - - # Nuxt.js build / generate output - .nuxt - dist - - # Gatsby files - .cache/ - public - - # Storybook build outputs - .out - .storybook-out - - # Temporary folders - tmp/ - temp/ - - """); + # Node.js + node_modules/ + npm-debug.log* + yarn-debug.log* + yarn-error.log* + lerna-debug.log* + + # Runtime data + pids + *.pid + *.seed + *.pid.lock + + # Coverage directory used by tools like istanbul + coverage/ + *.lcov + + # nyc test coverage + .nyc_output + + # Grunt intermediate storage + .grunt + + # Bower dependency directory + bower_components + + # node-waf configuration + .lock-wscript + + # Compiled binary addons + build/Release + + # Dependency directories + node_modules/ + jspm_packages/ + + # Optional npm cache directory + .npm + + # Optional eslint cache + .eslintcache + + # Microbundle cache + .rpt2_cache/ + .rts2_cache_cjs/ + .rts2_cache_es/ + .rts2_cache_umd/ + + # Optional REPL history + .node_repl_history + + # Output of 'npm pack' + *.tgz + + # Yarn Integrity file + .yarn-integrity + + # dotenv environment variables file + .env + .env.test + .env.local + .env.development.local + .env.test.local + .env.production.local + + # parcel-bundler cache + .cache + .parcel-cache + + # Next.js build output + .next + out + + # Nuxt.js build / generate output + .nuxt + dist + + # Gatsby files + .cache/ + public + + # Storybook build outputs + .out + .storybook-out + + # Temporary folders + tmp/ + temp/ + + """); break; - + case PYTHON: case DJANGO: case FLASK: case FASTAPI: gitignore.append(""" - # Python - __pycache__/ - *.py[cod] - *$py.class - - # C extensions - *.so - - # Distribution / packaging - .Python - build/ - develop-eggs/ - dist/ - downloads/ - eggs/ - .eggs/ - lib/ - lib64/ - parts/ - sdist/ - var/ - wheels/ - *.egg-info/ - .installed.cfg - *.egg - MANIFEST - - # PyInstaller - *.manifest - *.spec - - # Installer logs - pip-log.txt - pip-delete-this-directory.txt - - # Unit test / coverage reports - htmlcov/ - .tox/ - .nox/ - .coverage - .coverage.* - .cache - nosetests.xml - coverage.xml - *.cover - .hypothesis/ - .pytest_cache/ - - # Translations - *.mo - *.pot - - # Django stuff: - *.log - local_settings.py - db.sqlite3 - - # Flask stuff: - instance/ - .webassets-cache - - # Scrapy stuff: - .scrapy - - # Sphinx documentation - docs/_build/ - - # PyBuilder - target/ - - # Jupyter Notebook - .ipynb_checkpoints - - # IPython - profile_default/ - ipython_config.py - - # pyenv - .python-version - - # celery beat schedule file - celerybeat-schedule - - # SageMath parsed files - *.sage.py - - # Environments - .env - .venv - env/ - venv/ - ENV/ - env.bak/ - venv.bak/ - - # Spyder project settings - .spyderproject - .spyproject - - # Rope project settings - .ropeproject - - # mkdocs documentation - /site - - # mypy - .mypy_cache/ - .dmypy.json - dmypy.json - - """); + # Python + __pycache__/ + *.py[cod] + *$py.class + + # C extensions + *.so + + # Distribution / packaging + .Python + build/ + develop-eggs/ + dist/ + downloads/ + eggs/ + .eggs/ + lib/ + lib64/ + parts/ + sdist/ + var/ + wheels/ + *.egg-info/ + .installed.cfg + *.egg + MANIFEST + + # PyInstaller + *.manifest + *.spec + + # Installer logs + pip-log.txt + pip-delete-this-directory.txt + + # Unit test / coverage reports + htmlcov/ + .tox/ + .nox/ + .coverage + .coverage.* + .cache + nosetests.xml + coverage.xml + *.cover + .hypothesis/ + .pytest_cache/ + + # Translations + *.mo + *.pot + + # Django stuff: + *.log + local_settings.py + db.sqlite3 + + # Flask stuff: + instance/ + .webassets-cache + + # Scrapy stuff: + .scrapy + + # Sphinx documentation + docs/_build/ + + # PyBuilder + target/ + + # Jupyter Notebook + .ipynb_checkpoints + + # IPython + profile_default/ + ipython_config.py + + # pyenv + .python-version + + # celery beat schedule file + celerybeat-schedule + + # SageMath parsed files + *.sage.py + + # Environments + .env + .venv + env/ + venv/ + ENV/ + env.bak/ + venv.bak/ + + # Spyder project settings + .spyderproject + .spyproject + + # Rope project settings + .ropeproject + + # mkdocs documentation + /site + + # mypy + .mypy_cache/ + .dmypy.json + dmypy.json + + """); break; - + default: // 基本忽略规则已经添加 break; } - + return gitignore.toString(); } } diff --git a/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/service/ProjectTemplateService.java b/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/service/ProjectTemplateService.java index f47f92ac..3653876a 100644 --- a/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/service/ProjectTemplateService.java +++ b/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/service/ProjectTemplateService.java @@ -1,6 +1,5 @@ package com.example.demo.service; -import com.example.demo.model.ProjectType; import org.springframework.stereotype.Service; import java.util.Map; @@ -11,369 +10,369 @@ import java.util.Map; */ @Service public class ProjectTemplateService { - + /** * 生成Maven pom.xml */ public String generatePomXml(Map variables) { return String.format(""" - - - 4.0.0 - - com.example - %s - %s - jar - - %s - %s - - - 17 - 17 - UTF-8 - - - - - junit - junit - 4.13.2 - test - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.11.0 - - 17 - 17 - - - - - - """, - variables.get("PROJECT_NAME"), - variables.get("VERSION"), - variables.get("PROJECT_NAME_PASCAL"), - variables.get("DESCRIPTION") + + + 4.0.0 + + com.example + %s + %s + jar + + %s + %s + + + 17 + 17 + UTF-8 + + + + + junit + junit + 4.13.2 + test + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.11.0 + + 17 + 17 + + + + + + """, + variables.get("PROJECT_NAME"), + variables.get("VERSION"), + variables.get("PROJECT_NAME_PASCAL"), + variables.get("DESCRIPTION") ); } - + /** * 生成Spring Boot pom.xml */ public String generateSpringBootPomXml(Map variables) { return String.format(""" - - - 4.0.0 - - - org.springframework.boot - spring-boot-starter-parent - 3.2.1 - - - - com.example - %s - %s - jar - - %s - %s - - - 17 - - - - - org.springframework.boot - spring-boot-starter-web - - - - org.springframework.boot - spring-boot-starter-test - test - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - - """, - variables.get("PROJECT_NAME"), - variables.get("VERSION"), - variables.get("PROJECT_NAME_PASCAL"), - variables.get("DESCRIPTION") + + + 4.0.0 + + + org.springframework.boot + spring-boot-starter-parent + 3.2.1 + + + + com.example + %s + %s + jar + + %s + %s + + + 17 + + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + """, + variables.get("PROJECT_NAME"), + variables.get("VERSION"), + variables.get("PROJECT_NAME_PASCAL"), + variables.get("DESCRIPTION") ); } - + /** * 生成Java主类 */ public String generateJavaMainClass(Map variables) { return String.format(""" - package com.example.%s; - - /** - * Main application class for %s - * - * @author %s - */ - public class Application { - - public static void main(String[] args) { - System.out.println("Hello from %s!"); - System.out.println("Application started successfully."); - } - - /** - * Get application name - * @return application name - */ - public String getApplicationName() { - return "%s"; - } - } - """, - variables.get("PROJECT_NAME").toLowerCase(), - variables.get("PROJECT_NAME_PASCAL"), - variables.get("AUTHOR"), - variables.get("PROJECT_NAME_PASCAL"), - variables.get("PROJECT_NAME_PASCAL") + package com.example.%s; + + /** + * Main application class for %s + * + * @author %s + */ + public class Application { + + public static void main(String[] args) { + System.out.println("Hello from %s!"); + System.out.println("Application started successfully."); + } + + /** + * Get application name + * @return application name + */ + public String getApplicationName() { + return "%s"; + } + } + """, + variables.get("PROJECT_NAME").toLowerCase(), + variables.get("PROJECT_NAME_PASCAL"), + variables.get("AUTHOR"), + variables.get("PROJECT_NAME_PASCAL"), + variables.get("PROJECT_NAME_PASCAL") ); } - + /** * 生成Spring Boot主类 */ public String generateSpringBootMainClass(Map variables) { return String.format(""" - package com.example.%s; - - import org.springframework.boot.SpringApplication; - import org.springframework.boot.autoconfigure.SpringBootApplication; - - /** - * Spring Boot main application class for %s - * - * @author %s - */ - @SpringBootApplication - public class Application { - - public static void main(String[] args) { - SpringApplication.run(Application.class, args); - } - } - """, - variables.get("PROJECT_NAME").toLowerCase(), - variables.get("PROJECT_NAME_PASCAL"), - variables.get("AUTHOR") + package com.example.%s; + + import org.springframework.boot.SpringApplication; + import org.springframework.boot.autoconfigure.SpringBootApplication; + + /** + * Spring Boot main application class for %s + * + * @author %s + */ + @SpringBootApplication + public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + } + """, + variables.get("PROJECT_NAME").toLowerCase(), + variables.get("PROJECT_NAME_PASCAL"), + variables.get("AUTHOR") ); } - + /** * 生成Spring Boot Controller */ public String generateSpringBootController(Map variables) { return String.format(""" - package com.example.%s.controller; - - import org.springframework.web.bind.annotation.GetMapping; - import org.springframework.web.bind.annotation.RestController; - - /** - * Hello controller for %s - * - * @author %s - */ - @RestController - public class HelloController { - - @GetMapping("/") - public String hello() { - return "Hello from %s!"; - } - - @GetMapping("/health") - public String health() { - return "OK"; - } - } - """, - variables.get("PROJECT_NAME").toLowerCase(), - variables.get("PROJECT_NAME_PASCAL"), - variables.get("AUTHOR"), - variables.get("PROJECT_NAME_PASCAL") + package com.example.%s.controller; + + import org.springframework.web.bind.annotation.GetMapping; + import org.springframework.web.bind.annotation.RestController; + + /** + * Hello controller for %s + * + * @author %s + */ + @RestController + public class HelloController { + + @GetMapping("/") + public String hello() { + return "Hello from %s!"; + } + + @GetMapping("/health") + public String health() { + return "OK"; + } + } + """, + variables.get("PROJECT_NAME").toLowerCase(), + variables.get("PROJECT_NAME_PASCAL"), + variables.get("AUTHOR"), + variables.get("PROJECT_NAME_PASCAL") ); } - + /** * 生成Java测试类 */ public String generateJavaTestClass(Map variables) { return String.format(""" - package com.example.%s; - - import org.junit.Test; - import static org.junit.Assert.*; - - /** - * Test class for %s Application - * - * @author %s - */ - public class ApplicationTest { - - @Test - public void testApplicationName() { - Application app = new Application(); - assertEquals("%s", app.getApplicationName()); - } - - @Test - public void testApplicationCreation() { - Application app = new Application(); - assertNotNull(app); - } - } - """, - variables.get("PROJECT_NAME").toLowerCase(), - variables.get("PROJECT_NAME_PASCAL"), - variables.get("AUTHOR"), - variables.get("PROJECT_NAME_PASCAL") + package com.example.%s; + + import org.junit.Test; + import static org.junit.Assert.*; + + /** + * Test class for %s Application + * + * @author %s + */ + public class ApplicationTest { + + @Test + public void testApplicationName() { + Application app = new Application(); + assertEquals("%s", app.getApplicationName()); + } + + @Test + public void testApplicationCreation() { + Application app = new Application(); + assertNotNull(app); + } + } + """, + variables.get("PROJECT_NAME").toLowerCase(), + variables.get("PROJECT_NAME_PASCAL"), + variables.get("AUTHOR"), + variables.get("PROJECT_NAME_PASCAL") ); } - + /** * 生成application.yml */ public String generateApplicationYml(Map variables) { return String.format(""" - # Application configuration for %s - server: - port: 8080 - servlet: - context-path: / - - spring: - application: - name: %s - profiles: - active: dev - - # Logging configuration - logging: - level: - com.example.%s: DEBUG - org.springframework: INFO - pattern: - console: "%%d{yyyy-MM-dd HH:mm:ss} - %%msg%%n" - - # Management endpoints - management: - endpoints: - web: - exposure: - include: health,info - endpoint: - health: - show-details: when-authorized - """, - variables.get("PROJECT_NAME_PASCAL"), - variables.get("PROJECT_NAME"), - variables.get("PROJECT_NAME").toLowerCase() + # Application configuration for %s + server: + port: 8080 + servlet: + context-path: / + + spring: + application: + name: %s + profiles: + active: dev + + # Logging configuration + logging: + level: + com.example.%s: DEBUG + org.springframework: INFO + pattern: + console: "%%d{yyyy-MM-dd HH:mm:ss} - %%msg%%n" + + # Management endpoints + management: + endpoints: + web: + exposure: + include: health,info + endpoint: + health: + show-details: when-authorized + """, + variables.get("PROJECT_NAME_PASCAL"), + variables.get("PROJECT_NAME"), + variables.get("PROJECT_NAME").toLowerCase() ); } - + /** * 生成package.json */ public String generatePackageJson(Map variables) { return String.format(""" - { - "name": "%s", - "version": "%s", - "description": "%s", - "main": "index.js", - "scripts": { - "start": "node index.js", - "test": "echo \\"Error: no test specified\\" && exit 1", - "dev": "node index.js" - }, - "keywords": [ - "nodejs", - "%s" - ], - "author": "%s <%s>", - "license": "MIT", - "dependencies": {}, - "devDependencies": {} - } - """, - variables.get("PROJECT_NAME"), - variables.get("VERSION"), - variables.get("DESCRIPTION"), - variables.get("PROJECT_NAME"), - variables.get("AUTHOR"), - variables.get("EMAIL") + { + "name": "%s", + "version": "%s", + "description": "%s", + "main": "index.js", + "scripts": { + "start": "node index.js", + "test": "echo \\"Error: no test specified\\" && exit 1", + "dev": "node index.js" + }, + "keywords": [ + "nodejs", + "%s" + ], + "author": "%s <%s>", + "license": "MIT", + "dependencies": {}, + "devDependencies": {} + } + """, + variables.get("PROJECT_NAME"), + variables.get("VERSION"), + variables.get("DESCRIPTION"), + variables.get("PROJECT_NAME"), + variables.get("AUTHOR"), + variables.get("EMAIL") ); } - + /** * 生成Node.js主文件 */ public String generateNodeJsMainFile(Map variables) { return String.format(""" - /** - * Main application file for %s - * - * @author %s - */ - - console.log('Hello from %s!'); - console.log('Node.js application started successfully.'); - - // Simple HTTP server example - const http = require('http'); - - const server = http.createServer((req, res) => { - res.writeHead(200, { 'Content-Type': 'text/plain' }); - res.end('Hello from %s!\\n'); - }); - - const PORT = process.env.PORT || 3000; - server.listen(PORT, () => { - console.log(`Server running on port ${PORT}`); - }); - """, - variables.get("PROJECT_NAME_PASCAL"), - variables.get("AUTHOR"), - variables.get("PROJECT_NAME_PASCAL"), - variables.get("PROJECT_NAME_PASCAL") + /** + * Main application file for %s + * + * @author %s + */ + + console.log('Hello from %s!'); + console.log('Node.js application started successfully.'); + + // Simple HTTP server example + const http = require('http'); + + const server = http.createServer((req, res) => { + res.writeHead(200, { 'Content-Type': 'text/plain' }); + res.end('Hello from %s!\\n'); + }); + + const PORT = process.env.PORT || 3000; + server.listen(PORT, () => { + console.log(`Server running on port ${PORT}`); + }); + """, + variables.get("PROJECT_NAME_PASCAL"), + variables.get("AUTHOR"), + variables.get("PROJECT_NAME_PASCAL"), + variables.get("PROJECT_NAME_PASCAL") ); } @@ -382,34 +381,34 @@ public class ProjectTemplateService { */ public String generateReactAppJs(Map variables) { return String.format(""" - import React from 'react'; - import './App.css'; + import React from 'react'; + import './App.css'; - /** - * Main App component for %s - * - * @author %s - */ - function App() { - return ( -
-
-

Welcome to %s

-

%s

-

- Edit src/App.js and save to reload. -

-
-
- ); - } + /** + * Main App component for %s + * + * @author %s + */ + function App() { + return ( +
+
+

Welcome to %s

+

%s

+

+ Edit src/App.js and save to reload. +

+
+
+ ); + } - export default App; - """, - variables.get("PROJECT_NAME_PASCAL"), - variables.get("AUTHOR"), - variables.get("PROJECT_NAME_PASCAL"), - variables.get("DESCRIPTION") + export default App; + """, + variables.get("PROJECT_NAME_PASCAL"), + variables.get("AUTHOR"), + variables.get("PROJECT_NAME_PASCAL"), + variables.get("DESCRIPTION") ); } @@ -418,24 +417,24 @@ public class ProjectTemplateService { */ public String generateReactIndexHtml(Map variables) { return String.format(""" - - - - - - %s - - - - - -
- - - """, - variables.get("PROJECT_NAME_PASCAL"), - variables.get("DESCRIPTION"), - variables.get("AUTHOR") + + + + + + %s + + + + + +
+ + + """, + variables.get("PROJECT_NAME_PASCAL"), + variables.get("DESCRIPTION"), + variables.get("AUTHOR") ); } @@ -444,29 +443,29 @@ public class ProjectTemplateService { */ public String generatePythonMainFile(Map variables) { return String.format(""" - #!/usr/bin/env python3 - \"\"\" - Main application file for %s + #!/usr/bin/env python3 + \"\"\" + Main application file for %s - Author: %s - \"\"\" + Author: %s + \"\"\" - def main(): - \"\"\"Main function\"\"\" - print("Hello from %s!") - print("Python application started successfully.") + def main(): + \"\"\"Main function\"\"\" + print("Hello from %s!") + print("Python application started successfully.") - def get_application_name(): - \"\"\"Get application name\"\"\" - return "%s" + def get_application_name(): + \"\"\"Get application name\"\"\" + return "%s" - if __name__ == "__main__": - main() - """, - variables.get("PROJECT_NAME_PASCAL"), - variables.get("AUTHOR"), - variables.get("PROJECT_NAME_PASCAL"), - variables.get("PROJECT_NAME_PASCAL") + if __name__ == "__main__": + main() + """, + variables.get("PROJECT_NAME_PASCAL"), + variables.get("AUTHOR"), + variables.get("PROJECT_NAME_PASCAL"), + variables.get("PROJECT_NAME_PASCAL") ); } @@ -475,14 +474,14 @@ public class ProjectTemplateService { */ public String generateRequirementsTxt(Map variables) { return """ - # Python dependencies for """ + variables.get("PROJECT_NAME") + """ - # Add your dependencies here + # Python dependencies for """ + variables.get("PROJECT_NAME") + """ + # Add your dependencies here - # Example dependencies: - # requests>=2.28.0 - # flask>=2.3.0 - # pytest>=7.0.0 - """; + # Example dependencies: + # requests>=2.28.0 + # flask>=2.3.0 + # pytest>=7.0.0 + """; } /** @@ -490,53 +489,53 @@ public class ProjectTemplateService { */ public String generateStaticIndexHtml(Map variables) { return String.format(""" - - - - - - %s - - - - - -
-

Welcome to %s

-
+ + + + + + %s + + + + + +
+

Welcome to %s

+
-
-
-

About

-

%s

-
+
+
+

About

+

%s

+
-
-

Features

-
    -
  • Modern HTML5 structure
  • -
  • Responsive design
  • -
  • Clean CSS styling
  • -
  • JavaScript functionality
  • -
-
-
+
+

Features

+
    +
  • Modern HTML5 structure
  • +
  • Responsive design
  • +
  • Clean CSS styling
  • +
  • JavaScript functionality
  • +
+
+
-
-

© %s %s. All rights reserved.

-
+
+

© %s %s. All rights reserved.

+
- - - - """, - variables.get("PROJECT_NAME_PASCAL"), - variables.get("DESCRIPTION"), - variables.get("AUTHOR"), - variables.get("PROJECT_NAME_PASCAL"), - variables.get("DESCRIPTION"), - variables.get("CURRENT_YEAR"), - variables.get("AUTHOR") + + + + """, + variables.get("PROJECT_NAME_PASCAL"), + variables.get("DESCRIPTION"), + variables.get("AUTHOR"), + variables.get("PROJECT_NAME_PASCAL"), + variables.get("DESCRIPTION"), + variables.get("CURRENT_YEAR"), + variables.get("AUTHOR") ); } @@ -545,77 +544,77 @@ public class ProjectTemplateService { */ public String generateBasicCss(Map variables) { return String.format(""" - /* CSS styles for %s */ + /* CSS styles for %s */ - * { - margin: 0; - padding: 0; - box-sizing: border-box; - } + * { + margin: 0; + padding: 0; + box-sizing: border-box; + } - body { - font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; - line-height: 1.6; - color: #333; - background-color: #f4f4f4; - } + body { + font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; + line-height: 1.6; + color: #333; + background-color: #f4f4f4; + } - header { - background: #35424a; - color: white; - padding: 1rem 0; - text-align: center; - } + header { + background: #35424a; + color: white; + padding: 1rem 0; + text-align: center; + } - header h1 { - margin: 0; - } + header h1 { + margin: 0; + } - main { - max-width: 800px; - margin: 2rem auto; - padding: 0 1rem; - background: white; - border-radius: 8px; - box-shadow: 0 2px 5px rgba(0,0,0,0.1); - } + main { + max-width: 800px; + margin: 2rem auto; + padding: 0 1rem; + background: white; + border-radius: 8px; + box-shadow: 0 2px 5px rgba(0,0,0,0.1); + } - section { - padding: 2rem; - } + section { + padding: 2rem; + } - h2 { - color: #35424a; - margin-bottom: 1rem; - } + h2 { + color: #35424a; + margin-bottom: 1rem; + } - ul { - margin-left: 2rem; - } + ul { + margin-left: 2rem; + } - li { - margin-bottom: 0.5rem; - } + li { + margin-bottom: 0.5rem; + } - footer { - text-align: center; - padding: 1rem; - background: #35424a; - color: white; - margin-top: 2rem; - } + footer { + text-align: center; + padding: 1rem; + background: #35424a; + color: white; + margin-top: 2rem; + } - @media (max-width: 768px) { - main { - margin: 1rem; - } + @media (max-width: 768px) { + main { + margin: 1rem; + } - section { - padding: 1rem; - } - } - """, - variables.get("PROJECT_NAME_PASCAL") + section { + padding: 1rem; + } + } + """, + variables.get("PROJECT_NAME_PASCAL") ); } @@ -624,59 +623,59 @@ public class ProjectTemplateService { */ public String generateBasicJs(Map variables) { return String.format(""" - /** - * JavaScript functionality for %s - * - * @author %s - */ + /** + * JavaScript functionality for %s + * + * @author %s + */ - // Wait for DOM to be fully loaded - document.addEventListener('DOMContentLoaded', function() { - console.log('%s application loaded successfully!'); + // Wait for DOM to be fully loaded + document.addEventListener('DOMContentLoaded', function() { + console.log('%s application loaded successfully!'); - // Add click event to header - const header = document.querySelector('header h1'); - if (header) { - header.addEventListener('click', function() { - alert('Welcome to %s!'); - }); - } + // Add click event to header + const header = document.querySelector('header h1'); + if (header) { + header.addEventListener('click', function() { + alert('Welcome to %s!'); + }); + } - // Add smooth scrolling for anchor links - const links = document.querySelectorAll('a[href^="#"]'); - links.forEach(link => { - link.addEventListener('click', function(e) { - e.preventDefault(); - const target = document.querySelector(this.getAttribute('href')); - if (target) { - target.scrollIntoView({ - behavior: 'smooth' + // Add smooth scrolling for anchor links + const links = document.querySelectorAll('a[href^="#"]'); + links.forEach(link => { + link.addEventListener('click', function(e) { + e.preventDefault(); + const target = document.querySelector(this.getAttribute('href')); + if (target) { + target.scrollIntoView({ + behavior: 'smooth' + }); + } + }); }); + }); + + /** + * Utility function to get application name + */ + function getApplicationName() { + return '%s'; } - }); - }); - }); - /** - * Utility function to get application name - */ - function getApplicationName() { - return '%s'; - } - - /** - * Utility function to show notification - */ - function showNotification(message) { - console.log('Notification:', message); - // You can implement a proper notification system here - } - """, - variables.get("PROJECT_NAME_PASCAL"), - variables.get("AUTHOR"), - variables.get("PROJECT_NAME_PASCAL"), - variables.get("PROJECT_NAME_PASCAL"), - variables.get("PROJECT_NAME_PASCAL") + /** + * Utility function to show notification + */ + function showNotification(message) { + console.log('Notification:', message); + // You can implement a proper notification system here + } + """, + variables.get("PROJECT_NAME_PASCAL"), + variables.get("AUTHOR"), + variables.get("PROJECT_NAME_PASCAL"), + variables.get("PROJECT_NAME_PASCAL"), + variables.get("PROJECT_NAME_PASCAL") ); } } diff --git a/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/service/ProjectTypeDetector.java b/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/service/ProjectTypeDetector.java index 59bf3b6b..4d5107fa 100644 --- a/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/service/ProjectTypeDetector.java +++ b/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/service/ProjectTypeDetector.java @@ -19,12 +19,13 @@ import java.util.stream.Stream; */ @Component public class ProjectTypeDetector { - + private static final Logger logger = LoggerFactory.getLogger(ProjectTypeDetector.class); private final ObjectMapper objectMapper = new ObjectMapper(); - + /** * 检测项目类型 + * * @param projectRoot 项目根目录 * @return 检测到的项目类型 */ @@ -33,33 +34,33 @@ public class ProjectTypeDetector { logger.warn("Project root does not exist or is not a directory: {}", projectRoot); return ProjectType.UNKNOWN; } - + try { logger.debug("Detecting project type for: {}", projectRoot); - + // 按优先级检测项目类型 ProjectType detectedType = detectByKeyFiles(projectRoot); if (detectedType != ProjectType.UNKNOWN) { logger.info("Detected project type: {} for {}", detectedType, projectRoot); return detectedType; } - + // 如果关键文件检测失败,尝试基于目录结构检测 detectedType = detectByDirectoryStructure(projectRoot); if (detectedType != ProjectType.UNKNOWN) { logger.info("Detected project type by structure: {} for {}", detectedType, projectRoot); return detectedType; } - + logger.info("Could not determine project type for: {}", projectRoot); return ProjectType.UNKNOWN; - + } catch (Exception e) { logger.error("Error detecting project type for: " + projectRoot, e); return ProjectType.UNKNOWN; } } - + /** * 基于关键文件检测项目类型 */ @@ -72,56 +73,56 @@ public class ProjectTypeDetector { } return ProjectType.JAVA_MAVEN; } - + // Java Gradle项目 - if (Files.exists(projectRoot.resolve("build.gradle")) || - Files.exists(projectRoot.resolve("build.gradle.kts"))) { + if (Files.exists(projectRoot.resolve("build.gradle")) || + Files.exists(projectRoot.resolve("build.gradle.kts"))) { return ProjectType.JAVA_GRADLE; } - + // Node.js项目 if (Files.exists(projectRoot.resolve("package.json"))) { return analyzeNodeJsProject(projectRoot); } - + // Python项目 if (Files.exists(projectRoot.resolve("requirements.txt")) || - Files.exists(projectRoot.resolve("setup.py")) || - Files.exists(projectRoot.resolve("pyproject.toml"))) { + Files.exists(projectRoot.resolve("setup.py")) || + Files.exists(projectRoot.resolve("pyproject.toml"))) { return analyzePythonProject(projectRoot); } - + // .NET项目 try (Stream files = Files.list(projectRoot)) { - if (files.anyMatch(path -> path.toString().endsWith(".csproj") || - path.toString().endsWith(".sln"))) { + if (files.anyMatch(path -> path.toString().endsWith(".csproj") || + path.toString().endsWith(".sln"))) { return ProjectType.DOTNET; } } - + // Go项目 if (Files.exists(projectRoot.resolve("go.mod"))) { return ProjectType.GO; } - + // Rust项目 if (Files.exists(projectRoot.resolve("Cargo.toml"))) { return ProjectType.RUST; } - + // PHP项目 if (Files.exists(projectRoot.resolve("composer.json"))) { return ProjectType.PHP; } - + // 静态HTML项目 if (Files.exists(projectRoot.resolve("index.html"))) { return ProjectType.HTML_STATIC; } - + return ProjectType.UNKNOWN; } - + /** * 检查是否为Spring Boot项目 */ @@ -131,16 +132,16 @@ public class ProjectTypeDetector { if (!Files.exists(pomFile)) { return false; } - + String pomContent = Files.readString(pomFile); - return pomContent.contains("spring-boot-starter") || - pomContent.contains("org.springframework.boot"); + return pomContent.contains("spring-boot-starter") || + pomContent.contains("org.springframework.boot"); } catch (IOException e) { logger.warn("Error reading pom.xml for Spring Boot detection", e); return false; } } - + /** * 分析Node.js项目类型 */ @@ -149,36 +150,36 @@ public class ProjectTypeDetector { Path packageJsonPath = projectRoot.resolve("package.json"); String content = Files.readString(packageJsonPath); JsonNode packageJson = objectMapper.readTree(content); - + // 检查依赖来确定具体的框架类型 JsonNode dependencies = packageJson.get("dependencies"); JsonNode devDependencies = packageJson.get("devDependencies"); - + if (hasDependency(dependencies, "react") || hasDependency(devDependencies, "react")) { return ProjectType.REACT; } - + if (hasDependency(dependencies, "vue") || hasDependency(devDependencies, "vue")) { return ProjectType.VUE; } - - if (hasDependency(dependencies, "@angular/core") || - hasDependency(devDependencies, "@angular/cli")) { + + if (hasDependency(dependencies, "@angular/core") || + hasDependency(devDependencies, "@angular/cli")) { return ProjectType.ANGULAR; } - + if (hasDependency(dependencies, "next") || hasDependency(devDependencies, "next")) { return ProjectType.NEXT_JS; } - + return ProjectType.NODE_JS; - + } catch (IOException e) { logger.warn("Error analyzing package.json", e); return ProjectType.NODE_JS; } } - + /** * 分析Python项目类型 */ @@ -187,13 +188,13 @@ public class ProjectTypeDetector { if (Files.exists(projectRoot.resolve("manage.py"))) { return ProjectType.DJANGO; } - + // 检查Flask项目 - if (Files.exists(projectRoot.resolve("app.py")) || - Files.exists(projectRoot.resolve("application.py"))) { + if (Files.exists(projectRoot.resolve("app.py")) || + Files.exists(projectRoot.resolve("application.py"))) { return ProjectType.FLASK; } - + // 检查FastAPI项目 if (Files.exists(projectRoot.resolve("main.py"))) { try { @@ -205,54 +206,54 @@ public class ProjectTypeDetector { logger.warn("Error reading main.py for FastAPI detection", e); } } - + return ProjectType.PYTHON; } - + /** * 基于目录结构检测项目类型 */ private ProjectType detectByDirectoryStructure(Path projectRoot) { try { List directories = Files.list(projectRoot) - .filter(Files::isDirectory) - .map(path -> path.getFileName().toString().toLowerCase()) - .toList(); - + .filter(Files::isDirectory) + .map(path -> path.getFileName().toString().toLowerCase()) + .toList(); + // Java项目特征目录 - if (directories.contains("src") && - (directories.contains("target") || directories.contains("build"))) { + if (directories.contains("src") && + (directories.contains("target") || directories.contains("build"))) { return ProjectType.JAVA_MAVEN; // 默认为Maven } - + // Node.js项目特征目录 - if (directories.contains("node_modules") || - directories.contains("public") || - directories.contains("dist")) { + if (directories.contains("node_modules") || + directories.contains("public") || + directories.contains("dist")) { return ProjectType.NODE_JS; } - + // Python项目特征目录 - if (directories.contains("venv") || - directories.contains("env") || - directories.contains("__pycache__")) { + if (directories.contains("venv") || + directories.contains("env") || + directories.contains("__pycache__")) { return ProjectType.PYTHON; } - + } catch (IOException e) { logger.warn("Error analyzing directory structure", e); } - + return ProjectType.UNKNOWN; } - + /** * 检查是否存在特定依赖 */ private boolean hasDependency(JsonNode dependencies, String dependencyName) { return dependencies != null && dependencies.has(dependencyName); } - + /** * 获取项目类型的详细信息 */ @@ -261,7 +262,7 @@ public class ProjectTypeDetector { details.append("Project Type: ").append(projectType.getDisplayName()).append("\n"); details.append("Primary Language: ").append(projectType.getPrimaryLanguage()).append("\n"); details.append("Package Manager: ").append(projectType.getPackageManager()).append("\n"); - + // 添加特定项目类型的详细信息 switch (projectType) { case SPRING_BOOT: @@ -278,7 +279,7 @@ public class ProjectTypeDetector { break; // 可以添加更多项目类型的详细信息 } - + return details.toString(); } } diff --git a/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/service/TaskSummaryService.java b/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/service/TaskSummaryService.java index 72df9575..4e1b1882 100644 --- a/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/service/TaskSummaryService.java +++ b/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/service/TaskSummaryService.java @@ -1,32 +1,33 @@ package com.example.demo.service; -import org.springframework.stereotype.Service; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.regex.Pattern; +import org.springframework.stereotype.Service; + import java.util.regex.Matcher; +import java.util.regex.Pattern; @Service public class TaskSummaryService { - + private static final Logger logger = LoggerFactory.getLogger(TaskSummaryService.class); private static final Pattern[] ACTION_PATTERNS = { - Pattern.compile("(?i)creating?\\s+(?:a\\s+)?(?:new\\s+)?(.{1,50}?)(?:\\s+file|\\s+directory|\\s+project)?", Pattern.CASE_INSENSITIVE), - Pattern.compile("(?i)writing?\\s+(?:to\\s+)?(.{1,50}?)(?:\\s+file)?", Pattern.CASE_INSENSITIVE), - Pattern.compile("(?i)reading?\\s+(?:from\\s+)?(.{1,50}?)(?:\\s+file)?", Pattern.CASE_INSENSITIVE), - Pattern.compile("(?i)editing?\\s+(.{1,50}?)(?:\\s+file)?", Pattern.CASE_INSENSITIVE), - Pattern.compile("(?i)listing?\\s+(?:the\\s+)?(.{1,50}?)(?:\\s+directory)?", Pattern.CASE_INSENSITIVE), - Pattern.compile("(?i)analyzing?\\s+(.{1,50}?)", Pattern.CASE_INSENSITIVE), - Pattern.compile("(?i)generating?\\s+(.{1,50}?)", Pattern.CASE_INSENSITIVE), - Pattern.compile("(?i)building?\\s+(.{1,50}?)", Pattern.CASE_INSENSITIVE) + Pattern.compile("(?i)creating?\\s+(?:a\\s+)?(?:new\\s+)?(.{1,50}?)(?:\\s+file|\\s+directory|\\s+project)?", Pattern.CASE_INSENSITIVE), + Pattern.compile("(?i)writing?\\s+(?:to\\s+)?(.{1,50}?)(?:\\s+file)?", Pattern.CASE_INSENSITIVE), + Pattern.compile("(?i)reading?\\s+(?:from\\s+)?(.{1,50}?)(?:\\s+file)?", Pattern.CASE_INSENSITIVE), + Pattern.compile("(?i)editing?\\s+(.{1,50}?)(?:\\s+file)?", Pattern.CASE_INSENSITIVE), + Pattern.compile("(?i)listing?\\s+(?:the\\s+)?(.{1,50}?)(?:\\s+directory)?", Pattern.CASE_INSENSITIVE), + Pattern.compile("(?i)analyzing?\\s+(.{1,50}?)", Pattern.CASE_INSENSITIVE), + Pattern.compile("(?i)generating?\\s+(.{1,50}?)", Pattern.CASE_INSENSITIVE), + Pattern.compile("(?i)building?\\s+(.{1,50}?)", Pattern.CASE_INSENSITIVE) }; - + private static final String[] ACTION_VERBS = { - "创建", "写入", "读取", "编辑", "列出", "分析", "生成", "构建", - "creating", "writing", "reading", "editing", "listing", "analyzing", "generating", "building" + "创建", "写入", "读取", "编辑", "列出", "分析", "生成", "构建", + "creating", "writing", "reading", "editing", "listing", "analyzing", "generating", "building" }; - + /** * 从AI响应中提取任务摘要 */ @@ -34,10 +35,10 @@ public class TaskSummaryService { if (aiResponse == null || aiResponse.trim().isEmpty()) { return "处理中..."; } - + // 清理响应文本 String cleanResponse = aiResponse.replaceAll("```[\\s\\S]*?```", "").trim(); - + // 尝试匹配具体操作 for (Pattern pattern : ACTION_PATTERNS) { Matcher matcher = pattern.matcher(cleanResponse); @@ -49,7 +50,7 @@ public class TaskSummaryService { return action; } } - + // 查找动作词汇 String lowerResponse = cleanResponse.toLowerCase(); for (String verb : ACTION_VERBS) { @@ -67,24 +68,24 @@ public class TaskSummaryService { } } } - + // 如果没有找到具体操作,返回通用描述 if (cleanResponse.length() > 60) { return cleanResponse.substring(0, 57) + "..."; } - + return cleanResponse.isEmpty() ? "处理中..." : cleanResponse; } - + /** * 估算任务复杂度和预期轮数 */ public int estimateTaskComplexity(String initialMessage) { if (initialMessage == null) return 1; - + String lowerMessage = initialMessage.toLowerCase(); int complexity = 1; - + // 基于关键词估算复杂度 if (lowerMessage.contains("project") || lowerMessage.contains("项目")) complexity += 3; if (lowerMessage.contains("complete") || lowerMessage.contains("完整")) complexity += 2; @@ -92,24 +93,24 @@ public class TaskSummaryService { if (lowerMessage.contains("full-stack") || lowerMessage.contains("全栈")) complexity += 4; if (lowerMessage.contains("website") || lowerMessage.contains("网站")) complexity += 2; if (lowerMessage.contains("api") || lowerMessage.contains("接口")) complexity += 2; - + // 基于文件操作数量估算 long fileOperations = lowerMessage.chars() - .mapToObj(c -> String.valueOf((char) c)) - .filter(s -> s.matches(".*(?:create|write|edit|file|directory).*")) - .count(); - + .mapToObj(c -> String.valueOf((char) c)) + .filter(s -> s.matches(".*(?:create|write|edit|file|directory).*")) + .count(); + complexity += (int) Math.min(fileOperations / 2, 5); - + return Math.min(complexity, 15); // 最大15轮 } - + /** * 生成当前状态的用户友好描述 */ public String generateStatusDescription(String status, String currentAction, int currentTurn, int totalTurns) { StringBuilder desc = new StringBuilder(); - + switch (status) { case "RUNNING": if (currentAction != null && !currentAction.trim().isEmpty()) { @@ -117,27 +118,27 @@ public class TaskSummaryService { } else { desc.append("🤔 AI正在思考..."); } - + if (totalTurns > 1) { desc.append(String.format(" (第%d/%d轮)", currentTurn, totalTurns)); } break; - + case "COMPLETED": desc.append("✅ 任务完成"); if (totalTurns > 1) { desc.append(String.format(" (共%d轮)", currentTurn)); } break; - + case "ERROR": desc.append("❌ 执行出错"); break; - + default: desc.append("⏳ 处理中..."); } - + return desc.toString(); } } \ No newline at end of file diff --git a/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/service/ToolExecutionLogger.java b/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/service/ToolExecutionLogger.java index d065144e..4d26cc20 100644 --- a/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/service/ToolExecutionLogger.java +++ b/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/service/ToolExecutionLogger.java @@ -16,45 +16,45 @@ import java.util.concurrent.atomic.AtomicLong; */ @Service public class ToolExecutionLogger { - + private static final Logger logger = LoggerFactory.getLogger(ToolExecutionLogger.class); private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); - + // 工具调用计数器 private final AtomicLong callCounter = new AtomicLong(0); - + // 工具执行统计 private final Map toolStats = new ConcurrentHashMap<>(); - + /** * 记录工具调用开始 */ public long logToolStart(String toolName, String description, Object parameters) { long callId = callCounter.incrementAndGet(); String timestamp = LocalDateTime.now().format(formatter); - + logger.info("🚀 [工具调用-{}] 开始执行工具: {}", callId, toolName); logger.info("📝 [工具调用-{}] 工具描述: {}", callId, description); logger.info("⚙️ [工具调用-{}] 调用参数: {}", callId, formatParameters(parameters)); logger.info("🕐 [工具调用-{}] 开始时间: {}", callId, timestamp); - + // 更新统计信息 toolStats.computeIfAbsent(toolName, k -> new ToolStats()).incrementCalls(); - + return callId; } - + /** * 记录工具调用成功 */ public void logToolSuccess(long callId, String toolName, String result, long executionTimeMs) { String timestamp = LocalDateTime.now().format(formatter); - + logger.info("✅ [工具调用-{}] 工具执行成功: {}", callId, toolName); logger.info("📊 [工具调用-{}] 执行结果: {}", callId, truncateResult(result)); logger.info("⏱️ [工具调用-{}] 执行耗时: {}ms", callId, executionTimeMs); logger.info("🕐 [工具调用-{}] 完成时间: {}", callId, timestamp); - + // 更新统计信息 ToolStats stats = toolStats.get(toolName); if (stats != null) { @@ -62,18 +62,18 @@ public class ToolExecutionLogger { stats.addExecutionTime(executionTimeMs); } } - + /** * 记录工具调用失败 */ public void logToolError(long callId, String toolName, String error, long executionTimeMs) { String timestamp = LocalDateTime.now().format(formatter); - + logger.error("❌ [工具调用-{}] 工具执行失败: {}", callId, toolName); logger.error("🚨 [工具调用-{}] 错误信息: {}", callId, error); logger.error("⏱️ [工具调用-{}] 执行耗时: {}ms", callId, executionTimeMs); logger.error("🕐 [工具调用-{}] 失败时间: {}", callId, timestamp); - + // 更新统计信息 ToolStats stats = toolStats.get(toolName); if (stats != null) { @@ -81,48 +81,48 @@ public class ToolExecutionLogger { stats.addExecutionTime(executionTimeMs); } } - + /** * 记录工具调用的详细步骤 */ public void logToolStep(long callId, String toolName, String step, String details) { logger.debug("🔄 [工具调用-{}] [{}] 执行步骤: {} - {}", callId, toolName, step, details); } - + /** * 记录文件操作 */ public void logFileOperation(long callId, String operation, String filePath, String details) { logger.info("📁 [工具调用-{}] 文件操作: {} - 文件: {} - 详情: {}", callId, operation, filePath, details); } - + /** * 记录项目分析 */ public void logProjectAnalysis(long callId, String projectPath, String projectType, String details) { logger.info("🔍 [工具调用-{}] 项目分析: 路径={}, 类型={}, 详情={}", callId, projectPath, projectType, details); } - + /** * 记录项目创建 */ public void logProjectCreation(long callId, String projectName, String projectType, String projectPath) { logger.info("🏗️ [工具调用-{}] 项目创建: 名称={}, 类型={}, 路径={}", callId, projectName, projectType, projectPath); } - + /** * 获取工具执行统计 */ public void logToolStatistics() { logger.info("📈 ========== 工具执行统计 =========="); toolStats.forEach((toolName, stats) -> { - logger.info("🔧 工具: {} | 调用次数: {} | 成功: {} | 失败: {} | 平均耗时: {}ms", - toolName, stats.getTotalCalls(), stats.getSuccessCount(), - stats.getErrorCount(), stats.getAverageExecutionTime()); + logger.info("🔧 工具: {} | 调用次数: {} | 成功: {} | 失败: {} | 平均耗时: {}ms", + toolName, stats.getTotalCalls(), stats.getSuccessCount(), + stats.getErrorCount(), stats.getAverageExecutionTime()); }); logger.info("📈 ================================"); } - + /** * 格式化参数显示 */ @@ -133,7 +133,7 @@ public class ToolExecutionLogger { String paramStr = parameters.toString(); return paramStr.length() > 200 ? paramStr.substring(0, 200) + "..." : paramStr; } - + /** * 截断结果显示 */ @@ -143,7 +143,7 @@ public class ToolExecutionLogger { } return result.length() > 300 ? result.substring(0, 300) + "..." : result; } - + /** * 工具统计信息内部类 */ @@ -152,17 +152,37 @@ public class ToolExecutionLogger { private long successCount = 0; private long errorCount = 0; private long totalExecutionTime = 0; - - public void incrementCalls() { totalCalls++; } - public void incrementSuccess() { successCount++; } - public void incrementError() { errorCount++; } - public void addExecutionTime(long time) { totalExecutionTime += time; } - - public long getTotalCalls() { return totalCalls; } - public long getSuccessCount() { return successCount; } - public long getErrorCount() { return errorCount; } - public long getAverageExecutionTime() { - return totalCalls > 0 ? totalExecutionTime / totalCalls : 0; + + public void incrementCalls() { + totalCalls++; + } + + public void incrementSuccess() { + successCount++; + } + + public void incrementError() { + errorCount++; + } + + public void addExecutionTime(long time) { + totalExecutionTime += time; + } + + public long getTotalCalls() { + return totalCalls; + } + + public long getSuccessCount() { + return successCount; + } + + public long getErrorCount() { + return errorCount; + } + + public long getAverageExecutionTime() { + return totalCalls > 0 ? totalExecutionTime / totalCalls : 0; } } } diff --git a/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/service/ToolLogEvent.java b/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/service/ToolLogEvent.java index 8e32dd0a..bf0c1c61 100644 --- a/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/service/ToolLogEvent.java +++ b/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/service/ToolLogEvent.java @@ -8,77 +8,77 @@ import com.fasterxml.jackson.annotation.JsonInclude; */ @JsonInclude(JsonInclude.Include.NON_NULL) public class ToolLogEvent extends LogEvent { - + private String toolName; private String filePath; private String icon; private String status; // RUNNING, SUCCESS, ERROR private Long executionTime; // 执行时间(毫秒) private String summary; // 操作摘要 - + // Constructors public ToolLogEvent() { super(); } - - public ToolLogEvent(String type, String taskId, String toolName, String filePath, - String message, String timestamp, String icon, String status) { + + public ToolLogEvent(String type, String taskId, String toolName, String filePath, + String message, String timestamp, String icon, String status) { super(type, taskId, message, timestamp); this.toolName = toolName; this.filePath = filePath; this.icon = icon; this.status = status; } - + // Getters and Setters public String getToolName() { return toolName; } - + public void setToolName(String toolName) { this.toolName = toolName; } - + public String getFilePath() { return filePath; } - + public void setFilePath(String filePath) { this.filePath = filePath; } - + public String getIcon() { return icon; } - + public void setIcon(String icon) { this.icon = icon; } - + public String getStatus() { return status; } - + public void setStatus(String status) { this.status = status; } - + public Long getExecutionTime() { return executionTime; } - + public void setExecutionTime(Long executionTime) { this.executionTime = executionTime; } - + public String getSummary() { return summary; } - + public void setSummary(String summary) { this.summary = summary; } - + @Override public String toString() { return "ToolLogEvent{" + diff --git a/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/tools/AnalyzeProjectTool.java b/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/tools/AnalyzeProjectTool.java index 5aa0cb89..e36803af 100644 --- a/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/tools/AnalyzeProjectTool.java +++ b/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/tools/AnalyzeProjectTool.java @@ -23,130 +23,76 @@ import java.util.concurrent.CompletableFuture; */ @Component public class AnalyzeProjectTool extends BaseTool { - + private static final Logger logger = LoggerFactory.getLogger(AnalyzeProjectTool.class); - - @Autowired - private ProjectContextAnalyzer projectContextAnalyzer; - private final String rootDirectory; private final AppProperties appProperties; - + @Autowired + private ProjectContextAnalyzer projectContextAnalyzer; + public AnalyzeProjectTool(AppProperties appProperties) { super( - "analyze_project", - "AnalyzeProject", - "Analyze an existing project to understand its structure, type, dependencies, and configuration. " + - "Provides comprehensive project information that can be used for intelligent editing and refactoring.", - createSchema() + "analyze_project", + "AnalyzeProject", + "Analyze an existing project to understand its structure, type, dependencies, and configuration. " + + "Provides comprehensive project information that can be used for intelligent editing and refactoring.", + createSchema() ); this.appProperties = appProperties; this.rootDirectory = appProperties.getWorkspace().getRootDirectory(); } - + private static JsonSchema createSchema() { return JsonSchema.object() - .addProperty("project_path", JsonSchema.string( - "Absolute path to the project root directory to analyze. " + - "Must be within the workspace directory." - )) - .addProperty("analysis_depth", JsonSchema.string( - "Analysis depth: 'basic', 'detailed', or 'comprehensive'. " + - "Default: 'detailed'. " + - "- basic: Project type and structure only\n" + - "- detailed: Includes dependencies and configuration\n" + - "- comprehensive: Full analysis including code statistics" - )) - .addProperty("include_code_stats", JsonSchema.bool( - "Whether to include detailed code statistics (lines of code, classes, methods, etc.). " + - "Default: true for detailed/comprehensive analysis" - )) - .addProperty("output_format", JsonSchema.string( - "Output format: 'summary', 'detailed', or 'json'. Default: 'detailed'" - )) - .required("project_path"); + .addProperty("project_path", JsonSchema.string( + "Absolute path to the project root directory to analyze. " + + "Must be within the workspace directory." + )) + .addProperty("analysis_depth", JsonSchema.string( + "Analysis depth: 'basic', 'detailed', or 'comprehensive'. " + + "Default: 'detailed'. " + + "- basic: Project type and structure only\n" + + "- detailed: Includes dependencies and configuration\n" + + "- comprehensive: Full analysis including code statistics" + )) + .addProperty("include_code_stats", JsonSchema.bool( + "Whether to include detailed code statistics (lines of code, classes, methods, etc.). " + + "Default: true for detailed/comprehensive analysis" + )) + .addProperty("output_format", JsonSchema.string( + "Output format: 'summary', 'detailed', or 'json'. Default: 'detailed'" + )) + .required("project_path"); } - - public enum AnalysisDepth { - BASIC("basic", "Basic project type and structure analysis"), - DETAILED("detailed", "Detailed analysis including dependencies and configuration"), - COMPREHENSIVE("comprehensive", "Comprehensive analysis with full code statistics"); - - private final String value; - private final String description; - - AnalysisDepth(String value, String description) { - this.value = value; - this.description = description; - } - - public static AnalysisDepth fromString(String value) { - for (AnalysisDepth depth : values()) { - if (depth.value.equals(value)) { - return depth; - } - } - return DETAILED; // default - } - - public String getValue() { return value; } - public String getDescription() { return description; } - } - - public enum OutputFormat { - SUMMARY("summary", "Brief summary of key project information"), - DETAILED("detailed", "Detailed human-readable analysis report"), - JSON("json", "Structured JSON output for programmatic use"); - - private final String value; - private final String description; - - OutputFormat(String value, String description) { - this.value = value; - this.description = description; - } - - public static OutputFormat fromString(String value) { - for (OutputFormat format : values()) { - if (format.value.equals(value)) { - return format; - } - } - return DETAILED; // default - } - - public String getValue() { return value; } - public String getDescription() { return description; } - } - + @Override public String validateToolParams(AnalyzeProjectParams params) { String baseValidation = super.validateToolParams(params); if (baseValidation != null) { return baseValidation; } - + if (params.projectPath == null || params.projectPath.trim().isEmpty()) { return "Project path cannot be empty"; } - + Path projectPath = Paths.get(params.projectPath); if (!projectPath.isAbsolute()) { return "Project path must be absolute: " + params.projectPath; } - + if (!Files.exists(projectPath)) { return "Project path does not exist: " + params.projectPath; } - + if (!Files.isDirectory(projectPath)) { return "Project path must be a directory: " + params.projectPath; } - + if (!isWithinWorkspace(projectPath)) { return "Project path must be within the workspace directory: " + params.projectPath; } - + return null; } @@ -188,34 +134,34 @@ public class AnalyzeProjectTool extends BaseTool { try { logger.info("Starting project analysis for: {}", params.projectPath); - + Path projectPath = Paths.get(params.projectPath); AnalysisDepth depth = AnalysisDepth.fromString(params.analysisDepth); OutputFormat format = OutputFormat.fromString(params.outputFormat); - + // 执行项目分析 ProjectContext context = analyzeProject(projectPath, depth, params); - + // 生成输出 String output = generateOutput(context, format, depth); String summary = generateSummary(context); - + logger.info("Project analysis completed for: {}", params.projectPath); return ToolResult.success(summary, output); - + } catch (Exception e) { logger.error("Error during project analysis", e); return ToolResult.error("Project analysis failed: " + e.getMessage()); } }); } - + /** * 执行项目分析 */ private ProjectContext analyzeProject(Path projectPath, AnalysisDepth depth, AnalyzeProjectParams params) { logger.debug("Analyzing project with depth: {}", depth); - + switch (depth) { case BASIC: return analyzeBasic(projectPath); @@ -227,7 +173,7 @@ public class AnalyzeProjectTool extends BaseTool output.append(" - ").append(config.getFileName()).append("\n")); + .filter(ProjectContext.ConfigFile::isMainConfig) + .forEach(config -> output.append(" - ").append(config.getFileName()).append("\n")); } - + return output.toString(); } - + /** * 生成详细输出 */ private String generateDetailedOutput(ProjectContext context, AnalysisDepth depth) { StringBuilder output = new StringBuilder(); - + output.append("📊 COMPREHENSIVE PROJECT ANALYSIS\n"); - output.append("=" .repeat(60)).append("\n\n"); - + output.append("=".repeat(60)).append("\n\n"); + // 使用项目上下文的摘要生成功能 output.append(context.generateContextSummary()); - + // 添加分析深度特定的信息 if (depth == AnalysisDepth.COMPREHENSIVE) { output.append("\n=== DETAILED INSIGHTS ===\n"); output.append(generateProjectInsights(context)); } - + return output.toString(); } - + /** * 生成JSON输出 */ @@ -357,7 +303,7 @@ public class AnalyzeProjectTool extends BaseTool { - + protected final Logger logger = LoggerFactory.getLogger(getClass()); - + protected final String name; protected final String displayName; protected final String description; protected final JsonSchema parameterSchema; protected final boolean isOutputMarkdown; protected final boolean canUpdateOutput; - + protected SchemaValidator schemaValidator; public BaseTool(String name, String displayName, String description, JsonSchema parameterSchema) { @@ -30,7 +29,7 @@ public abstract class BaseTool

{ } public BaseTool(String name, String displayName, String description, JsonSchema parameterSchema, - boolean isOutputMarkdown, boolean canUpdateOutput) { + boolean isOutputMarkdown, boolean canUpdateOutput) { this.name = name; this.displayName = displayName; this.description = description; @@ -57,7 +56,7 @@ public abstract class BaseTool

{ logger.warn("Schema validator or parameter schema is null, skipping validation"); return null; } - + try { return schemaValidator.validate(parameterSchema, params); } catch (Exception e) { @@ -95,12 +94,29 @@ public abstract class BaseTool

{ } // Getters - public String getName() { return name; } - public String getDisplayName() { return displayName; } - public String getDescription() { return description; } - public JsonSchema getParameterSchema() { return parameterSchema; } - public boolean isOutputMarkdown() { return isOutputMarkdown; } - public boolean canUpdateOutput() { return canUpdateOutput; } + public String getName() { + return name; + } + + public String getDisplayName() { + return displayName; + } + + public String getDescription() { + return description; + } + + public JsonSchema getParameterSchema() { + return parameterSchema; + } + + public boolean isOutputMarkdown() { + return isOutputMarkdown; + } + + public boolean canUpdateOutput() { + return canUpdateOutput; + } @Override public String toString() { diff --git a/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/tools/EditFileTool.java b/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/tools/EditFileTool.java index 9cc2be1f..5a06f18e 100644 --- a/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/tools/EditFileTool.java +++ b/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/tools/EditFileTool.java @@ -37,13 +37,13 @@ public class EditFileTool extends BaseTool { public EditFileTool(AppProperties appProperties) { super( - "edit_file", - "EditFile", - "Edits a file by replacing specified text with new text. " + - "Shows a diff of the changes before applying them. " + - "Supports both exact string matching and line-based editing. " + - "Use absolute paths within the workspace directory.", - createSchema() + "edit_file", + "EditFile", + "Edits a file by replacing specified text with new text. " + + "Shows a diff of the changes before applying them. " + + "Supports both exact string matching and line-based editing. " + + "Use absolute paths within the workspace directory.", + createSchema() ); this.appProperties = appProperties; this.rootDirectory = appProperties.getWorkspace().getRootDirectory(); @@ -59,25 +59,25 @@ public class EditFileTool extends BaseTool { private static JsonSchema createSchema() { return JsonSchema.object() - .addProperty("file_path", JsonSchema.string( - "MUST be an absolute path to the file to edit. Path must be within the workspace directory (" + - getWorkspaceBasePath() + "). " + - getPathExample("project/src/main.java") + ". " + - "Relative paths are NOT allowed." - )) - .addProperty("old_str", JsonSchema.string( - "The exact string to find and replace. Must match exactly including whitespace and newlines." - )) - .addProperty("new_str", JsonSchema.string( - "The new string to replace the old string with. Can be empty to delete the old string." - )) - .addProperty("start_line", JsonSchema.integer( - "Optional: 1-based line number where the old_str starts. Helps with disambiguation." - ).minimum(1)) - .addProperty("end_line", JsonSchema.integer( - "Optional: 1-based line number where the old_str ends. Must be >= start_line." - ).minimum(1)) - .required("file_path", "old_str", "new_str"); + .addProperty("file_path", JsonSchema.string( + "MUST be an absolute path to the file to edit. Path must be within the workspace directory (" + + getWorkspaceBasePath() + "). " + + getPathExample("project/src/main.java") + ". " + + "Relative paths are NOT allowed." + )) + .addProperty("old_str", JsonSchema.string( + "The exact string to find and replace. Must match exactly including whitespace and newlines." + )) + .addProperty("new_str", JsonSchema.string( + "The new string to replace the old string with. Can be empty to delete the old string." + )) + .addProperty("start_line", JsonSchema.integer( + "Optional: 1-based line number where the old_str starts. Helps with disambiguation." + ).minimum(1)) + .addProperty("end_line", JsonSchema.integer( + "Optional: 1-based line number where the old_str ends. Must be >= start_line." + ).minimum(1)) + .required("file_path", "old_str", "new_str"); } @Override @@ -101,7 +101,7 @@ public class EditFileTool extends BaseTool { } Path filePath = Paths.get(params.filePath); - + // Validate if it's an absolute path if (!filePath.isAbsolute()) { return "File path must be absolute: " + params.filePath; @@ -126,31 +126,31 @@ public class EditFileTool extends BaseTool { public CompletableFuture shouldConfirmExecute(EditFileParams params) { // Decide whether confirmation is needed based on configuration if (appProperties.getSecurity().getApprovalMode() == AppProperties.ApprovalMode.AUTO_EDIT || - appProperties.getSecurity().getApprovalMode() == AppProperties.ApprovalMode.YOLO) { + appProperties.getSecurity().getApprovalMode() == AppProperties.ApprovalMode.YOLO) { return CompletableFuture.completedFuture(null); } return CompletableFuture.supplyAsync(() -> { try { Path filePath = Paths.get(params.filePath); - + if (!Files.exists(filePath)) { return null; // 文件不存在,无法预览差异 } - + String currentContent = Files.readString(filePath, StandardCharsets.UTF_8); String newContent = performEdit(currentContent, params); - + if (newContent == null) { return null; // Edit failed, cannot preview differences } - + // 生成差异显示 String diff = generateDiff(filePath.getFileName().toString(), currentContent, newContent); String title = "Confirm Edit: " + getRelativePath(filePath); - + return ToolConfirmationDetails.edit(title, filePath.getFileName().toString(), diff); - + } catch (IOException e) { logger.warn("Could not read file for edit preview: " + params.filePath, e); return null; @@ -164,9 +164,9 @@ public class EditFileTool extends BaseTool { @Tool(name = "edit_file", description = "Edits a file by replacing specified text with new text") public String editFile(String filePath, String oldStr, String newStr, Integer startLine, Integer endLine) { long callId = executionLogger.logToolStart("edit_file", "编辑文件内容", - String.format("文件=%s, 替换文本长度=%d->%d, 行号范围=%s-%s", - filePath, oldStr != null ? oldStr.length() : 0, - newStr != null ? newStr.length() : 0, startLine, endLine)); + String.format("文件=%s, 替换文本长度=%d->%d, 行号范围=%s-%s", + filePath, oldStr != null ? oldStr.length() : 0, + newStr != null ? newStr.length() : 0, startLine, endLine)); long startTime = System.currentTimeMillis(); try { @@ -188,7 +188,7 @@ public class EditFileTool extends BaseTool { } String editDetails = startLine != null && endLine != null ? - String.format("行号范围编辑: %d-%d行", startLine, endLine) : "字符串替换编辑"; + String.format("行号范围编辑: %d-%d行", startLine, endLine) : "字符串替换编辑"; executionLogger.logFileOperation(callId, "编辑文件", filePath, editDetails); // Execute the tool @@ -217,7 +217,7 @@ public class EditFileTool extends BaseTool { return CompletableFuture.supplyAsync(() -> { try { Path filePath = Paths.get(params.filePath); - + // Check if file exists if (!Files.exists(filePath)) { return ToolResult.error("File not found: " + params.filePath); @@ -230,26 +230,26 @@ public class EditFileTool extends BaseTool { // 读取原始内容 String originalContent = Files.readString(filePath, StandardCharsets.UTF_8); - + // 执行编辑 String newContent = performEdit(originalContent, params); if (newContent == null) { return ToolResult.error("Could not find the specified text to replace in file: " + params.filePath); } - + // 创建备份 if (shouldCreateBackup()) { createBackup(filePath, originalContent); } - + // Write new content Files.writeString(filePath, newContent, StandardCharsets.UTF_8); - + // Generate differences and results String diff = generateDiff(filePath.getFileName().toString(), originalContent, newContent); String relativePath = getRelativePath(filePath); String successMessage = String.format("Successfully edited file: %s", params.filePath); - + return ToolResult.success(successMessage, new FileDiff(diff, filePath.getFileName().toString())); } catch (IOException e) { @@ -276,13 +276,13 @@ public class EditFileTool extends BaseTool { if (!content.contains(params.oldStr)) { return null; // Cannot find string to replace } - + // Only replace the first match to avoid unexpected multiple replacements int index = content.indexOf(params.oldStr); if (index == -1) { return null; } - + return content.substring(0, index) + params.newStr + content.substring(index + params.oldStr.length()); } @@ -302,7 +302,7 @@ public class EditFileTool extends BaseTool { } targetContent.append(lines[i]); } - + // 检查是否匹配 if (!targetContent.toString().equals(params.oldStr)) { return null; // 指定行范围的内容与old_str不匹配 @@ -316,17 +316,17 @@ public class EditFileTool extends BaseTool { if (i > 0) result.append("\n"); result.append(lines[i]); } - + // 添加新内容 if (params.startLine > 1) result.append("\n"); result.append(params.newStr); - + // 添加后面的行 for (int i = params.endLine; i < lines.length; i++) { result.append("\n"); result.append(lines[i]); } - + return result.toString(); } @@ -334,16 +334,16 @@ public class EditFileTool extends BaseTool { try { List oldLines = Arrays.asList(oldContent.split("\n")); List newLines = Arrays.asList(newContent.split("\n")); - + Patch patch = DiffUtils.diff(oldLines, newLines); List unifiedDiff = UnifiedDiffUtils.generateUnifiedDiff( - fileName + " (Original)", - fileName + " (Edited)", - oldLines, - patch, - 3 // context lines + fileName + " (Original)", + fileName + " (Edited)", + oldLines, + patch, + 3 // context lines ); - + return String.join("\n", unifiedDiff); } catch (Exception e) { logger.warn("Could not generate diff", e); @@ -355,7 +355,7 @@ public class EditFileTool extends BaseTool { String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss")); String backupFileName = filePath.getFileName().toString() + ".backup." + timestamp; Path backupPath = filePath.getParent().resolve(backupFileName); - + Files.writeString(backupPath, content, StandardCharsets.UTF_8); logger.info("Created backup: {}", backupPath); } @@ -390,21 +390,22 @@ public class EditFileTool extends BaseTool { public static class EditFileParams { @JsonProperty("file_path") private String filePath; - + @JsonProperty("old_str") private String oldStr; - + @JsonProperty("new_str") private String newStr; - + @JsonProperty("start_line") private Integer startLine; - + @JsonProperty("end_line") private Integer endLine; // 构造器 - public EditFileParams() {} + public EditFileParams() { + } public EditFileParams(String filePath, String oldStr, String newStr) { this.filePath = filePath; @@ -413,28 +414,53 @@ public class EditFileTool extends BaseTool { } // Getters and Setters - public String getFilePath() { return filePath; } - public void setFilePath(String filePath) { this.filePath = filePath; } + public String getFilePath() { + return filePath; + } - public String getOldStr() { return oldStr; } - public void setOldStr(String oldStr) { this.oldStr = oldStr; } + public void setFilePath(String filePath) { + this.filePath = filePath; + } - public String getNewStr() { return newStr; } - public void setNewStr(String newStr) { this.newStr = newStr; } + public String getOldStr() { + return oldStr; + } - public Integer getStartLine() { return startLine; } - public void setStartLine(Integer startLine) { this.startLine = startLine; } + public void setOldStr(String oldStr) { + this.oldStr = oldStr; + } - public Integer getEndLine() { return endLine; } - public void setEndLine(Integer endLine) { this.endLine = endLine; } + public String getNewStr() { + return newStr; + } + + public void setNewStr(String newStr) { + this.newStr = newStr; + } + + public Integer getStartLine() { + return startLine; + } + + public void setStartLine(Integer startLine) { + this.startLine = startLine; + } + + public Integer getEndLine() { + return endLine; + } + + public void setEndLine(Integer endLine) { + this.endLine = endLine; + } @Override public String toString() { - return String.format("EditFileParams{path='%s', oldStrLength=%d, newStrLength=%d, lines=%s-%s}", - filePath, - oldStr != null ? oldStr.length() : 0, - newStr != null ? newStr.length() : 0, - startLine, endLine); + return String.format("EditFileParams{path='%s', oldStrLength=%d, newStrLength=%d, lines=%s-%s}", + filePath, + oldStr != null ? oldStr.length() : 0, + newStr != null ? newStr.length() : 0, + startLine, endLine); } } } diff --git a/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/tools/FileOperationTools.java b/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/tools/FileOperationTools.java index ff0d0359..217f09a0 100644 --- a/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/tools/FileOperationTools.java +++ b/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/tools/FileOperationTools.java @@ -2,7 +2,6 @@ package com.example.demo.tools; import com.example.demo.config.AppProperties; import com.example.demo.utils.PathUtils; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.ai.tool.annotation.Tool; @@ -26,7 +25,7 @@ import java.util.stream.Stream; public class FileOperationTools { private static final Logger logger = LoggerFactory.getLogger(FileOperationTools.class); - + private final String rootDirectory; private final AppProperties appProperties; @@ -71,14 +70,14 @@ public class FileOperationTools { long fileSize = Files.size(filePath); if (fileSize > appProperties.getWorkspace().getMaxFileSize()) { return "Error: File too large: " + fileSize + " bytes. Maximum allowed: " + - appProperties.getWorkspace().getMaxFileSize() + " bytes"; + appProperties.getWorkspace().getMaxFileSize() + " bytes"; } // 检查文件扩展名 String fileName = filePath.getFileName().toString(); if (!isAllowedFileType(fileName)) { return "Error: File type not allowed: " + fileName + - ". Allowed extensions: " + appProperties.getWorkspace().getAllowedExtensions(); + ". Allowed extensions: " + appProperties.getWorkspace().getAllowedExtensions(); } // 读取文件 @@ -92,12 +91,12 @@ public class FileOperationTools { long duration = System.currentTimeMillis() - startTime; logger.error("Error reading file: {} (duration: {}ms)", absolutePath, duration, e); return String.format("❌ Error reading file: %s\n⏱️ Duration: %dms\n🔍 Details: %s", - absolutePath, duration, e.getMessage()); + absolutePath, duration, e.getMessage()); } catch (Exception e) { long duration = System.currentTimeMillis() - startTime; logger.error("Unexpected error reading file: {} (duration: {}ms)", absolutePath, duration, e); return String.format("❌ Unexpected error reading file: %s\n⏱️ Duration: %dms\n🔍 Details: %s", - absolutePath, duration, e.getMessage()); + absolutePath, duration, e.getMessage()); } finally { long duration = System.currentTimeMillis() - startTime; logger.debug("Completed readFile operation for: {} (duration: {}ms)", absolutePath, duration); @@ -123,42 +122,42 @@ public class FileOperationTools { // 验证内容大小 byte[] contentBytes = content.getBytes(StandardCharsets.UTF_8); if (contentBytes.length > appProperties.getWorkspace().getMaxFileSize()) { - return "Error: Content too large: " + contentBytes.length + " bytes. Maximum allowed: " + - appProperties.getWorkspace().getMaxFileSize() + " bytes"; + return "Error: Content too large: " + contentBytes.length + " bytes. Maximum allowed: " + + appProperties.getWorkspace().getMaxFileSize() + " bytes"; } Path path = Paths.get(filePath); boolean isNewFile = !Files.exists(path); - + // 确保父目录存在 Files.createDirectories(path.getParent()); - + // 写入文件 Files.writeString(path, content, StandardCharsets.UTF_8, - StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING); - + StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING); + long lineCount = content.lines().count(); String absolutePath = path.toAbsolutePath().toString(); String relativePath = getRelativePath(path); if (isNewFile) { return String.format("Successfully created file:\n📁 Full path: %s\n📂 Relative path: %s\n📊 Stats: %d lines, %d bytes", - absolutePath, relativePath, lineCount, contentBytes.length); + absolutePath, relativePath, lineCount, contentBytes.length); } else { return String.format("Successfully wrote to file:\n📁 Full path: %s\n📂 Relative path: %s\n📊 Stats: %d lines, %d bytes", - absolutePath, relativePath, lineCount, contentBytes.length); + absolutePath, relativePath, lineCount, contentBytes.length); } } catch (IOException e) { long duration = System.currentTimeMillis() - startTime; logger.error("Error writing file: {} (duration: {}ms)", filePath, duration, e); return String.format("❌ Error writing file: %s\n⏱️ Duration: %dms\n🔍 Details: %s", - filePath, duration, e.getMessage()); + filePath, duration, e.getMessage()); } catch (Exception e) { long duration = System.currentTimeMillis() - startTime; logger.error("Unexpected error writing file: {} (duration: {}ms)", filePath, duration, e); return String.format("❌ Unexpected error writing file: %s\n⏱️ Duration: %dms\n🔍 Details: %s", - filePath, duration, e.getMessage()); + filePath, duration, e.getMessage()); } finally { long duration = System.currentTimeMillis() - startTime; logger.debug("Completed writeFile operation for: {} (duration: {}ms)", filePath, duration); @@ -167,13 +166,13 @@ public class FileOperationTools { @Tool(description = "Edit a file by replacing specific text content.") public String editFile( - @ToolParam(description = "The absolute path to the file to edit. Must be within the workspace directory.") + @ToolParam(description = "The absolute path to the file to edit. Must be within the workspace directory.") String filePath, - @ToolParam(description = "The text to find and replace in the file") + @ToolParam(description = "The text to find and replace in the file") String oldText, - @ToolParam(description = "The new text to replace the old text with") + @ToolParam(description = "The new text to replace the old text with") String newText) { - + try { // 验证路径 String validationError = validatePath(filePath); @@ -182,7 +181,7 @@ public class FileOperationTools { } Path path = Paths.get(filePath); - + // 检查文件是否存在 if (!Files.exists(path)) { return "Error: File not found: " + filePath; @@ -195,21 +194,21 @@ public class FileOperationTools { // 读取原始内容 String originalContent = Files.readString(path, StandardCharsets.UTF_8); - + // 执行替换 if (!originalContent.contains(oldText)) { return "Error: Could not find the specified text to replace in file: " + filePath; } - + String newContent = originalContent.replace(oldText, newText); - + // 写入新内容 Files.writeString(path, newContent, StandardCharsets.UTF_8); String absolutePath = path.toAbsolutePath().toString(); String relativePath = getRelativePath(path); return String.format("Successfully edited file:\n📁 Full path: %s\n📂 Relative path: %s\n✏️ Replaced text successfully", - absolutePath, relativePath); + absolutePath, relativePath); } catch (IOException e) { logger.error("Error editing file: " + filePath, e); @@ -222,11 +221,11 @@ public class FileOperationTools { @Tool(description = "List the contents of a directory.") public String listDirectory( - @ToolParam(description = "The absolute path to the directory to list. Must be within the workspace directory.") + @ToolParam(description = "The absolute path to the directory to list. Must be within the workspace directory.") String directoryPath, - @ToolParam(description = "Whether to list contents recursively", required = false) + @ToolParam(description = "Whether to list contents recursively", required = false) Boolean recursive) { - + try { // 验证路径 String validationError = validatePath(directoryPath); @@ -235,7 +234,7 @@ public class FileOperationTools { } Path path = Paths.get(directoryPath); - + // 检查目录是否存在 if (!Files.exists(path)) { return "Error: Directory not found: " + directoryPath; @@ -272,7 +271,7 @@ public class FileOperationTools { } Path filePath = Paths.get(path); - + // 验证是否为绝对路径 if (!filePath.isAbsolute()) { return "Path must be absolute: " + path; @@ -306,7 +305,7 @@ public class FileOperationTools { private boolean isAllowedFileType(String fileName) { List allowedExtensions = appProperties.getWorkspace().getAllowedExtensions(); return allowedExtensions.stream() - .anyMatch(ext -> fileName.toLowerCase().endsWith(ext.toLowerCase())); + .anyMatch(ext -> fileName.toLowerCase().endsWith(ext.toLowerCase())); } private String getRelativePath(Path path) { @@ -325,7 +324,7 @@ public class FileOperationTools { long lineCount = content.lines().count(); return String.format("📁 Full path: %s\n📂 Relative path: %s\n📊 Stats: %d lines, %d bytes\n\n📄 Content:\n%s", - absolutePath, relativePath, lineCount, content.getBytes(StandardCharsets.UTF_8).length, content); + absolutePath, relativePath, lineCount, content.getBytes(StandardCharsets.UTF_8).length, content); } private String readFileWithPagination(Path filePath, int offset, int limit) throws IOException { @@ -342,7 +341,7 @@ public class FileOperationTools { String absolutePath = filePath.toAbsolutePath().toString(); String relativePath = getRelativePath(filePath); return String.format("📁 Full path: %s\n📂 Relative path: %s\n📊 Showing lines %d-%d of %d total\n\n📄 Content:\n%s", - absolutePath, relativePath, offset + 1, endIndex, allLines.size(), content); + absolutePath, relativePath, offset + 1, endIndex, allLines.size(), content); } private String listDirectorySimple(Path path, String absolutePath, String relativePath) throws IOException { @@ -379,30 +378,30 @@ public class FileOperationTools { try (Stream entries = Files.walk(path)) { entries.sorted() - .forEach(entry -> { - if (!entry.equals(path)) { - String entryAbsolutePath = entry.toAbsolutePath().toString(); - String entryRelativePath = getRelativePath(entry); + .forEach(entry -> { + if (!entry.equals(path)) { + String entryAbsolutePath = entry.toAbsolutePath().toString(); + String entryRelativePath = getRelativePath(entry); - // 计算缩进级别 - int depth = entry.getNameCount() - path.getNameCount(); - String indent = " ".repeat(depth); + // 计算缩进级别 + int depth = entry.getNameCount() - path.getNameCount(); + String indent = " ".repeat(depth); - if (Files.isDirectory(entry)) { - result.append(indent).append("📁 ").append(entryRelativePath).append("/\n"); - result.append(indent).append(" └─ ").append(entryAbsolutePath).append("\n"); - } else { - try { - long size = Files.size(entry); - result.append(indent).append("📄 ").append(entryRelativePath).append(" (").append(size).append(" bytes)\n"); - result.append(indent).append(" └─ ").append(entryAbsolutePath).append("\n"); - } catch (IOException e) { - result.append(indent).append("📄 ").append(entryRelativePath).append(" (size unknown)\n"); + if (Files.isDirectory(entry)) { + result.append(indent).append("📁 ").append(entryRelativePath).append("/\n"); result.append(indent).append(" └─ ").append(entryAbsolutePath).append("\n"); + } else { + try { + long size = Files.size(entry); + result.append(indent).append("📄 ").append(entryRelativePath).append(" (").append(size).append(" bytes)\n"); + result.append(indent).append(" └─ ").append(entryAbsolutePath).append("\n"); + } catch (IOException e) { + result.append(indent).append("📄 ").append(entryRelativePath).append(" (size unknown)\n"); + result.append(indent).append(" └─ ").append(entryAbsolutePath).append("\n"); + } } } - } - }); + }); } return result.toString(); diff --git a/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/tools/ListDirectoryTool.java b/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/tools/ListDirectoryTool.java index b76ab64c..2d9b5cd2 100644 --- a/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/tools/ListDirectoryTool.java +++ b/ruoyi-extend/ruoyi-ai-copilot/src/main/java/com/example/demo/tools/ListDirectoryTool.java @@ -31,13 +31,13 @@ public class ListDirectoryTool extends BaseTool

-
-

🤖 SpringAI Alibaba 编码助手

-

AI助手将分析您的需求,制定执行计划,并逐步完成任务

-
+
+
+

🤖 SpringAI Alibaba 编码助手

+

AI助手将分析您的需求,制定执行计划,并逐步完成任务

+
-
-
-
-
-
-
Assistant
-
- 👋 Hello! I'm your AI file operations assistant. I can help you: -

- 📁 Read files - View file contents with pagination support -
✏️ Write files - Create new files or overwrite existing ones -
🔧 Edit files - Make precise edits with diff preview -
📋 List directories - Browse directory structure -

- Try asking me to create a simple project, read a file, or explore the workspace! -

- Workspace: /workspace -
+
+
+
+
+
+
Assistant
+
+ 👋 Hello! I'm your AI file operations assistant. I can help you: +

+ 📁 Read files - View file contents with pagination support +
✏️ Write files - Create new files or overwrite existing ones +
🔧 Edit files - Make precise edits with diff preview +
📋 List directories - Browse directory structure +

+ Try asking me to create a simple project, read a file, or explore the workspace! +

+ Workspace: /workspace
+
-
-
🤔 AI is thinking...
+
+
🤔 AI is thinking...
+
+ +
+ + + +
+
+ +