办学质量监测教学评价系统
Albert
2025-05-13 3666157d14201d39a0e61588582fee97fac95ad1
.gitignore
@@ -13,6 +13,8 @@
ruoyi-modules/ruoyi-generator/src/main/resources/vm/vben5
README.md
######################################################################
# IDE
README.md
@@ -59,24 +59,16 @@
### ç³»ç»Ÿä½“验
- ç”¨æˆ·ç«¯ï¼šhttps://web.pandarobot.chat
- ç®¡ç†ç«¯ï¼šhttps://admin.pandarobot.chat
  ç”¨æˆ·å: admin å¯†ç ï¼šadmin123
- ç”¨æˆ·å: admin å¯†ç ï¼šadmin123
### æºç åœ°å€
[1]gitee
- å‰ç«¯æœåŠ¡-用户端: https://gitee.com/ageerle/ruoyi-web
- å‰ç«¯æœåŠ¡-管理端: https://gitee.com/ageerle/ruoyi-admin
- å‰ç«¯æœåŠ¡-小程序端: https://gitee.com/ageerle/ruoyi-uniapp
- åŽç«¯æœåŠ¡ï¼šhttps://gitee.com/ageerle/ruoyi-ai
[2]github
[1]github
- å‰ç«¯æœåŠ¡-用户端: https://github.com/ageerle/ruoyi-web
- å‰ç«¯æœåŠ¡-管理端: https://github.com/ageerle/ruoyi-admin
- å‰ç«¯æœåŠ¡-小程序端: https://github.com/ageerle/ruoyi-uniapp
- åŽç«¯æœåŠ¡ï¼šhttps://github.com/ageerle/ruoyi-ai
[3]gitcode
[2]gitcode
- å‰ç«¯æœåŠ¡-用户端:https://gitcode.com/ageerle/ruoyi-web
- å‰ç«¯æœåŠ¡-管理端:  https://gitcode.com/ageerle/ruoyi-admin
- å‰ç«¯æœåŠ¡-小程序端:  https://gitcode.com/ageerle/ruoyi-uniapp
@@ -86,27 +78,25 @@
- é…å¥—文档: https://doc.pandarobot.chat
- é¡¹ç›®éƒ¨ç½²æ–‡æ¡£ï¼šhttps://doc.pandarobot.chat/guide/introduction/
### æ ¸å¿ƒåŠŸèƒ½
1. å…¨å¥—开源系统:提供完整的前端应用、后台管理以及小程序应用,基于MIT协议,开箱即用。
2. æœ¬åœ°RAG方案:集成Milvus/Weaviate向量库、本地向量化模型与Ollama,实现本地化RAG。
3. ä¸°å¯Œæ’件功能:支持联网、SQL查询插件及Text2API插件,扩展系统能力与应用场景。
4. å†…ç½®SSE、websocket等网络协议,支持对接多种大语言模型,同时还集成了MidJourney和DALLE AI绘画功能。
5. å¼ºå¤§çš„多媒体功能:支持AI翻译、PPT制作、语音克隆和翻唱等。
6. æ‰©å±•功能:支持将大模型接入个人或企业微信。
7. æ”¯ä»˜åŠŸèƒ½ï¼šæ”¯æŒæ˜“æ”¯ä»˜ã€å¾®ä¿¡æ”¯ä»˜ç­‰å¤šç§æ”¯ä»˜æ–¹å¼ã€‚
### æ ¸å¿ƒåŠŸèƒ½ä¸ŽæŠ€æœ¯äº®ç‚¹
#### 1. å…¨æ ˆå¼å¼€æºç³»ç»Ÿ
- å…¨å¥—开源系统:提供完整的前端应用、后台管理以及小程序应用,基于MIT协议,开箱即用。
#### 2. æœ¬åœ°åŒ– RAG æ–¹æ¡ˆ
-  åŸºäºŽ **Langchain4j** æ¡†æž¶ï¼Œæ”¯æŒ Milvus/Weaviate/Qdrant å‘量库,结合 BGE-large-zh-v1.5 æœ¬åœ°å‘量化模型 å®žçŽ°é«˜æ•ˆæ–‡æ¡£æ£€ç´¢ä¸ŽçŸ¥è¯†åº“æž„å»ºã€‚
-  æ”¯æŒ æœ¬åœ° LLM æŽ¥å…¥ï¼Œç»“合私有知识库实现安全可控的问答系统,避免依赖云端服务的隐私风险。
#### 3. å¤šæ¨¡æ€ AI å¼•擎与工具集成
-  æ™ºèƒ½å¯¹è¯ï¼šæ”¯æŒ OpenAI GPT-4、Azure、ChatGLM ç­‰ä¸»æµæ¨¡åž‹ï¼Œå†…ç½® SSE/WebSocket åè®®å®žçŽ°ä½Žå»¶è¿Ÿäº¤äº’ï¼Œå…¼å®¹ **扣子**、**DIFY** ç­‰å¹³å° API è°ƒç”¨ã€‚
-  **Spring AI MCP** æ”¯æŒï¼šé€šè¿‡æ³¨è§£å¿«é€Ÿå®šä¹‰æœ¬åœ°å·¥å…·ï¼Œæ”¯æŒè°ƒç”¨ MCP å¹¿åœº çš„æµ·é‡ MCP Server æœåŠ¡ï¼Œæ‰©å±•æ¨¡åž‹èƒ½åŠ›è¾¹ç•Œã€‚
#### 4. ä¼ä¸šçº§æ‰©å±•与商业化支持
-  å³æ—¶é€šè®¯é›†æˆï¼šæ”¯æŒå¯¹æŽ¥ä¸ªäººå¾®ä¿¡ã€ä¼ä¸šå¾®ä¿¡åŠå¾®ä¿¡å…¬ä¼—号,实现消息自动回复、用户管理与智能客服。
-  æ”¯ä»˜ç³»ç»Ÿï¼šé›†æˆæ˜“支付、微信支付、Stripe å›½é™…信用卡支付,满足商业化场景需求。
#### 5. å¤šåª’体处理与创新功能
 -  AI ç»˜ç”»ï¼šé›†æˆ DALL·E-3、MidJourney、Stable Diffusion,支持文生图、图生图及风格化创作,适用于营销素材生成与创意设计。
 -  PPT åˆ¶ä½œï¼šæ ¹æ®æ–‡æœ¬è¾“入自动生成结构化幻灯片,支持自定义模板(需要使用三方平台 å¦‚:文多多)。
### é¡¹ç›®æ¼”示
#### mcp支持
### å¦‚何使用
1. ruoyi-admin\src\main\resources\application.yml中mcp.client.enabled改为true
2. application.yml中配置openai api-key(用于推理使用那个工具,并构建工具所需参数)
3. å¯åЍ[ruoyi-mcp-server]
4. [mcp-server.json]中配置fileSystem.command(npx本地安装路径)
5. æŒ‡å®šfileSystem操作目录(本地必须存在指定的目录)
6. é…ç½®search1api.env.SEARCH1API_KEY ç”³è¯·åœ°å€ï¼šhttps://www.search1api.com/
7. è¯¦æƒ…教程:https://blog.csdn.net/weixin_42416319/article/details/147385808
<div style="display: flex; flex-wrap: wrap; gap: 20px; justify-content: center;">
  <img src="image/mcp-01.png" alt="drawing" style="width: 600px; height: 300px; border: 2px solid #ddd; border-radius: 8px; box-shadow: 0 4px 8px rgba(0,0,0,0.1);"/>
  <img src="image/mcp-02.png" alt="drawing" style="width: 600px; height: 300px; border: 2px solid #ddd; border-radius: 8px; box-shadow: 0 4px 8px rgba(0,0,0,0.1);"/>
@@ -121,7 +111,6 @@
  <img src="image/04.png" alt="drawing" style="width: 600px; height: 300px; border: 2px solid #ddd; border-radius: 8px; box-shadow: 0 4px 8px rgba(0,0,0,0.1);"/>
  <img src="image/05.png" alt="drawing" style="width: 600px; height: 300px; border: 2px solid #ddd; border-radius: 8px; box-shadow: 0 4px 8px rgba(0,0,0,0.1);"/>
</div>
#### ç”¨æˆ·ç«¯
<div style="display: flex; flex-wrap: wrap; gap: 20px; justify-content: center;">
@@ -204,7 +193,6 @@
### æ³¨æ„äº‹é¡¹
- vben模板
    Q:vben5 çš„æ¨¡æ¿é»˜è®¤æ˜¯æ²¡æœ‰çš„吗?
  
    A:vben模板是收费的 è¯·è”ç³»vben-vue-plus作者获取。
@@ -212,7 +200,6 @@
### ç‰ˆæœ¬æŽ§åˆ¶
该项目使用Git进行版本管理。您可以在repository参看当前可用版本。
### ç‰ˆæƒè¯´æ˜Ž
@@ -251,7 +238,7 @@
#### é¡¹ç›®æ–‡æ¡£
1. é¡¹ç›®æ–‡æ¡£åŸºäºŽvitepress构建
2. æŒ‰ç…§[如何参与开源项目](#如何参与开源项目)拉取 https://github.com/ageerle/ruoyi-doc
2. æŒ‰ç…§[如何参与开源项目](#如何参与开源项目)拉取https://github.com/ageerle/ruoyi-doc
3. å®‰è£…依赖:npm install
4. å¯åŠ¨é¡¹ç›®ï¼šnpm run docs:dev
5. ä¸»é¡µè·¯å¾„:docs/guide/introduction/index.md
@@ -277,11 +264,15 @@
[license-url]: https://github.com/ageerle/ruoyi-ai/blob/master/LICENSE.txt
[linkedin-shield]: https://img.shields.io/badge/-LinkedIn-black.svg?style=flat-square&logo=linkedin&colorB=555
## ðŸŒ¿ ç¬¬ä¸‰æ–¹ç”Ÿæ€
- [PPIO æ´¾æ¬§äº‘:一键调用高性价比的开源模型 API å’Œ GPU å®¹å™¨](https://ppinfra.com/user/register?invited_by=P8QTUY&utm_source=github_ruoyi-ai)
### é™„:技术讨论群
#### å…¨é¢å¼€æ”¾ï¼Œæ¬¢è¿ŽåŠ å…¥
#### è¿›ç¾¤å­¦ä¹ 
🏠 wx:ruoyi-ai(加人备注:ruoyi-ai)
 <img src="image/小助手wx.png" alt="drawing" style="width: 400px; height: 400px; border: 2px solid #ddd; border-radius: 8px; box-shadow: 0 4px 8px rgba(0,0,0,0.1);"/>
🏠 qq:1603234088 ï¼ˆåŠ äººå¤‡æ³¨ï¼šruoyi-ai)
@@ -290,11 +281,4 @@
<div style="display: flex; flex-wrap: wrap; gap: 20px; justify-content: center;">
  <img src="image/QQ区-官方交流1群.png" alt="drawing" style="width: 400px; height: 400px; border: 2px solid #ddd; border-radius: 8px; box-shadow: 0 4px 8px rgba(0,0,0,0.1);"/>
</div>
👏👏👏 ruoyi-ai官方交流4群(微信区):
<div style="display: flex; flex-wrap: wrap; gap: 20px; justify-content: center;">
  <img src="image/WX区-官方交流4群.jpg" alt="drawing" style="width: 400px; height: 400px; border: 2px solid #ddd; border-radius: 8px; box-shadow: 0 4px 8px rgba(0,0,0,0.1);"/>
</div>
image/СÖúÊÖwx.png
ruoyi-admin/src/main/resources/application.yml
@@ -226,7 +226,7 @@
    # æ ‡é¢˜
    title: '标题:RuoYi-Vue-Plus多租户管理系统_接口文档'
    # æè¿°
    description: '描述:用于管理集团旗下公司的人员信息,具体包括XXX,XXX模块...'
    description: ' ç”¨äºŽç®¡ç†é›†å›¢æ——下公司的人员信息,具体包括XXX,XXX模块...'
    # ç‰ˆæœ¬
    version: '版本号: ${ruoyi.version}'
    # ä½œè€…信息
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/config/LocalCache.java
@@ -6,7 +6,6 @@
import lombok.extern.slf4j.Slf4j;
/**
 * æè¿°ï¼š
 *
 * @author https:www.unfbx.com
 * @date 2023-03-10
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/constant/OpenAIConst.java
@@ -1,7 +1,6 @@
package org.ruoyi.common.chat.constant;
/**
 * æè¿°ï¼š
 *
 * @author https:www.unfbx.com
 * @since  2023-03-06
@@ -10,6 +9,8 @@
    public final static String OPENAI_HOST = "https://api.openai.com/";
    public final static String apiUrl = "v1/chat/completions";
    public final static int SUCCEED_CODE = 200;
}
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/billing/BillingUsage.java
@@ -8,7 +8,7 @@
import java.util.List;
/**
 * æè¿°ï¼šé‡‘额消耗信息
 * é‡‘额消耗信息
 *
 * @author https:www.unfbx.com
 * @since 2023-04-08
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/billing/CreditGrantsResponse.java
@@ -8,7 +8,7 @@
import java.math.BigDecimal;
/**
 * æè¿°ï¼šä½™é¢æŸ¥è¯¢æŽ¥å£è¿”回值
 * ä½™é¢æŸ¥è¯¢æŽ¥å£è¿”回值
 *
 * @author https:www.unfbx.com
 * @since 2023-03-18
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/billing/DailyCost.java
@@ -7,7 +7,7 @@
import java.util.List;
/**
 * æè¿°ï¼šé‡‘额消耗列表
 * é‡‘额消耗列表
 *
 * @author https:www.unfbx.com
 * @since 2023-04-08
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/billing/Datum.java
@@ -7,7 +7,6 @@
import java.math.BigDecimal;
/**
 * æè¿°ï¼š
 *
 * @author https:www.unfbx.com
 * @since 2023-03-18
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/billing/Grants.java
@@ -7,7 +7,6 @@
import java.util.List;
/**
 * æè¿°ï¼š
 *
 * @author https:www.unfbx.com
 * @since 2023-03-18
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/billing/LineItem.java
@@ -6,7 +6,7 @@
import java.math.BigDecimal;
/**
 * æè¿°ï¼šé‡‘额消耗列表
 * é‡‘额消耗列表
 *
 * @author https:www.unfbx.com
 * @since 2023-04-08
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/billing/Plan.java
@@ -4,7 +4,6 @@
import lombok.Data;
/**
 * æè¿°ï¼š
 *
 * @author https:www.unfbx.com
 * @since  2023-04-08
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/billing/Subscription.java
@@ -4,7 +4,7 @@
import lombok.Data;
/**
 * æè¿°ï¼šè´¦æˆ·ä¿¡æ¯
 * è´¦æˆ·ä¿¡æ¯
 *
 * @author https:www.unfbx.com
 * @since  2023-04-08
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/chat/BaseChatCompletion.java
@@ -13,7 +13,7 @@
import static org.ruoyi.common.chat.entity.chat.BaseChatCompletion.Model.GPT_3_5_TURBO;
/**
 * æè¿°ï¼š chat模型基础类
 * chat模型基础类
 *
 * @author https:www.unfbx.com
 * @since 1.1.2
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/chat/BaseMessage.java
@@ -12,7 +12,6 @@
import java.util.List;
/**
 * æè¿°ï¼š
 *
 * @author https:www.unfbx.com
 * @since 1.1.2
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/chat/ChatChoice.java
@@ -7,7 +7,6 @@
import java.io.Serializable;
/**
 * æè¿°ï¼š
 *
 * @author https:www.unfbx.com
 * @since 2023-03-02
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/chat/ChatCompletion.java
@@ -12,7 +12,7 @@
import java.util.List;
/**
 * æè¿°ï¼š chat模型参数
 * chat模型参数
 *
 * @author https:www.unfbx.com
 * 2023-03-02
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/chat/ChatCompletionResponse.java
@@ -8,7 +8,7 @@
import java.util.List;
/**
 * æè¿°ï¼š chat答案类
 * chat答案类
 *
 * @author https:www.unfbx.com
 * 2023-03-02
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/chat/ChatCompletionWithPicture.java
@@ -11,7 +11,7 @@
import java.util.List;
/**
 * æè¿°ï¼š chat模型附带图片的参数
 *  ï¼š chat模型附带图片的参数
 *
 * @author https:www.unfbx.com
 * @since 1.1.2
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/chat/Content.java
@@ -6,7 +6,6 @@
import lombok.extern.slf4j.Slf4j;
/**
 * æè¿°ï¼š
 *
 * @author https://www.unfbx.com
 * @since 1.1.2
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/chat/FunctionCall.java
@@ -6,7 +6,7 @@
import lombok.NoArgsConstructor;
/**
 * æè¿°ï¼šå‡½æ•°è°ƒç”¨è¿”回值
 * å‡½æ•°è°ƒç”¨è¿”回值
 *
 * @author https://www.unfbx.com
 * @since 2023-06-14
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/chat/Functions.java
@@ -6,7 +6,7 @@
import java.io.Serializable;
/**
 * æè¿°ï¼šæ–¹æ³•参数实体类,实例数据如下
 * æ–¹æ³•参数实体类,实例数据如下
 * <pre>
 *     {
 *          "name": "get_current_weather",
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/chat/ImageUrl.java
@@ -8,7 +8,6 @@
import lombok.extern.slf4j.Slf4j;
/**
 * æè¿°ï¼š
 *
 * @author https://www.unfbx.com
 * 2023-11-10
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/chat/Message.java
@@ -10,7 +10,7 @@
import java.util.List;
/**
 * æè¿°ï¼š
 *
 *
 * @author https:www.unfbx.com
 * @since 2023-03-02
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/chat/MessagePicture.java
@@ -10,8 +10,6 @@
import java.util.List;
/**
 * æè¿°ï¼š
 *
 * @author https:www.unfbx.com
 * @since 2023-03-02
 */
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/chat/Parameters.java
@@ -6,7 +6,7 @@
import java.io.Serializable;
import java.util.List;
/**
 * æè¿°ï¼šæ–¹æ³•参数类,扩展参数可以继承Parameters自己实现
 *  æ–¹æ³•参数类,扩展参数可以继承Parameters自己实现
 * å‚考:
 * <pre>
 * {
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/common/Choice.java
@@ -7,7 +7,6 @@
import java.io.Serializable;
/**
 * æè¿°ï¼š
 *
 * @author https:www.unfbx.com
 *  2023-02-15
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/common/DeleteResponse.java
@@ -6,7 +6,7 @@
import java.io.Serializable;
/**
 * æè¿°ï¼š
 *
 *
 * @author https:www.unfbx.com
 *  2023-02-15
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/common/OpenAiResponse.java
@@ -6,7 +6,7 @@
import java.io.Serializable;
import java.util.List;
/**
 * æè¿°ï¼š
 *
 *
 * @author https:www.unfbx.com
 *  2023-02-15
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/common/Usage.java
@@ -7,7 +7,7 @@
import java.io.Serializable;
/**
 * æè¿°ï¼š
 *
 *
 * @author https:www.unfbx.com
 *  2023-02-15
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/completions/Completion.java
@@ -10,7 +10,7 @@
import java.util.Map;
/**
 * æè¿°ï¼š é—®é¢˜ç±»
 *   é—®é¢˜ç±»
 *
 * @author https:www.unfbx.com
 * 2023-02-11
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/completions/CompletionResponse.java
@@ -9,7 +9,7 @@
import java.io.Serializable;
/**
 * æè¿°ï¼š ç­”案类
 *   ç­”案类
 *
 * @author https:www.unfbx.com
 *  2023-02-11
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/edits/Edit.java
@@ -7,7 +7,7 @@
import java.io.Serializable;
/**
 * æè¿°ï¼š
 *
 *
 * @author https:www.unfbx.com
 *  2023-02-15
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/edits/EditResponse.java
@@ -9,7 +9,7 @@
import java.io.Serializable;
/**
 * æè¿°ï¼š
 *
 *
 * @author https:www.unfbx.com
 *  2023-02-15
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/embeddings/Embedding.java
@@ -9,7 +9,7 @@
import java.util.Objects;
/**
 * æè¿°ï¼š
 *
 *
 * @author https:www.unfbx.com
 *  2023-02-15
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/embeddings/EmbeddingResponse.java
@@ -8,7 +8,7 @@
import java.util.List;
/**
 * æè¿°ï¼š
 *
 *
 * @author https:www.unfbx.com
 *  2023-02-15
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/engines/Engine.java
@@ -6,7 +6,7 @@
import java.io.Serializable;
/**
 * æè¿°ï¼š
 *
 *
 * @author https:www.unfbx.com
 *  2023-02-15
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/files/File.java
@@ -6,7 +6,7 @@
import java.io.Serializable;
/**
 * æè¿°ï¼š
 *
 *
 * @author https:www.unfbx.com
 *  2023-02-15
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/files/UploadFileResponse.java
@@ -6,7 +6,7 @@
import java.io.Serializable;
/**
 * æè¿°ï¼š
 *
 *
 * @author https:www.unfbx.com
 *  2023-02-15
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/images/Image.java
@@ -11,7 +11,7 @@
import java.io.Serializable;
/**
 * æè¿°ï¼š
 *
 *
 * @author https:www.unfbx.com
 * 2023-02-15
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/images/ImageEdit.java
@@ -11,7 +11,7 @@
import java.util.Objects;
/**
 * æè¿°ï¼š
 *
 *
 * @author https:www.unfbx.com
 *  2023-02-15
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/images/ImageResponse.java
@@ -7,7 +7,7 @@
import java.util.List;
/**
 * æè¿°ï¼š
 *
 *
 * @author https:www.unfbx.com
 *  2023-02-15
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/images/ImageVariations.java
@@ -12,7 +12,7 @@
import java.util.Objects;
/**
 * æè¿°ï¼š
 *
 *
 * @author https:www.unfbx.com
 *  2023-02-15
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/images/Item.java
@@ -7,7 +7,7 @@
import java.io.Serializable;
/**
 * æè¿°ï¼š
 *
 *
 * @author https:www.unfbx.com
 *  2023-02-15
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/images/ResponseFormat.java
@@ -6,7 +6,7 @@
import java.io.Serializable;
/**
 * æè¿°ï¼š
 *
 *
 * @author https:www.unfbx.com
 *  2023-02-15
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/images/SizeEnum.java
@@ -6,7 +6,7 @@
import java.io.Serializable;
/**
 * æè¿°ï¼š
 *
 *
 * @author https:www.unfbx.com
 *  2023-02-15
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/models/Model.java
@@ -8,7 +8,7 @@
import java.util.List;
/**
 * æè¿°ï¼š
 *
 *
 * @author https:www.unfbx.com
 *  2023-02-15
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/models/ModelResponse.java
@@ -7,7 +7,7 @@
import java.util.List;
/**
 * æè¿°ï¼š
 *
 *
 * @author https:www.unfbx.com
 *  2023-02-15
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/models/Permission.java
@@ -7,7 +7,7 @@
import java.io.Serializable;
/**
 * æè¿°ï¼š
 *
 *
 * @author https:www.unfbx.com
 * 2023-02-15
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/moderations/Categories.java
@@ -7,7 +7,7 @@
import java.io.Serializable;
/**
 * æè¿°ï¼š
 *
 *
 * @author https:www.unfbx.com
 *  2023-02-15
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/moderations/CategoryScores.java
@@ -8,7 +8,7 @@
import java.math.BigDecimal;
/**
 * æè¿°ï¼š
 *
 *
 * @author https:www.unfbx.com
 *  2023-02-15
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/moderations/Moderation.java
@@ -10,7 +10,7 @@
import java.util.Objects;
/**
 * æè¿°ï¼šæ–‡æœ¬å®¡æ ¸ï¼Œæ•æ„Ÿè¯é‰´åˆ«
 *  æ–‡æœ¬å®¡æ ¸ï¼Œæ•æ„Ÿè¯é‰´åˆ«
 *
 * @author https:www.unfbx.com
 *  2023-02-15
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/moderations/ModerationResponse.java
@@ -7,7 +7,7 @@
import java.util.List;
/**
 * æè¿°ï¼š
 *
 *
 * @author https:www.unfbx.com
 *  2023-02-15
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/moderations/Result.java
@@ -7,7 +7,7 @@
import java.io.Serializable;
/**
 * æè¿°ï¼š
 *
 *
 * @author https:www.unfbx.com
 *  2023-02-15
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/whisper/Whisper.java
@@ -7,7 +7,7 @@
import java.io.Serializable;
/**
 * æè¿°ï¼šè¯­éŸ³è½¬æ–‡å­—
 *  è¯­éŸ³è½¬æ–‡å­—
 *
 * @author https:www.unfbx.com
 * @since 2023-03-02
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/entity/whisper/WhisperResponse.java
@@ -6,7 +6,7 @@
import java.io.Serializable;
/**
 * æè¿°ï¼š
 *
 *
 * @author https:www.unfbx.com
 * @since 2023-03-02
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/listener/WebSocketEventListener.java
@@ -16,7 +16,7 @@
import java.util.Objects;
/**
 * æè¿°ï¼šOpenAI流式输出Socket接收
 *  OpenAI流式输出Socket接收
 *
 * @author https:www.unfbx.com
 * @date 2023-03-23
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/openai/OpenAiApi.java
@@ -40,7 +40,7 @@
import java.util.Map;
/**
 * æè¿°ï¼š open ai官方api接口
 *   open ai官方api接口
 *
 * @author https:www.unfbx.com
 * 2023-02-15
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/openai/OpenAiClient.java
@@ -56,7 +56,7 @@
/**
 * æè¿°ï¼š open ai å®¢æˆ·ç«¯
 *   open ai å®¢æˆ·ç«¯
 *
 * @author https:www.unfbx.com
 * @since 2023-02-11
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/openai/OpenAiStreamClient.java
@@ -53,7 +53,7 @@
import java.util.concurrent.TimeUnit;
/**
 * æè¿°ï¼š open ai å®¢æˆ·ç«¯
 *   open ai å®¢æˆ·ç«¯
 *
 * @author https:www.unfbx.com
 * 2023-02-28
@@ -70,6 +70,11 @@
     * è‡ªå®šä¹‰api host使用builder的方式构造client
     */
    private String apiHost;
    /**
     * è‡ªå®šä¹‰url å…¼å®¹å¤šä¸ªå¹³å°
     */
    private String apiUrl;
    /**
     * è‡ªå®šä¹‰çš„okHttpClient
@@ -112,6 +117,11 @@
        }
        apiHost = builder.apiHost;
        if (StrUtil.isBlank(builder.apiUrl)) {
            builder.apiUrl = OpenAIConst.apiUrl;
        }
        apiUrl = builder.apiUrl;
        if (Objects.isNull(builder.keyStrategy)) {
            builder.keyStrategy = new KeyRandomStrategy();
        }
@@ -136,12 +146,12 @@
        }
        okHttpClient = builder.okHttpClient;
        this.openAiApi = new Retrofit.Builder()
            .baseUrl(apiHost)
            .client(okHttpClient)
            .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
            .addConverterFactory(JacksonConverterFactory.create())
            .build().create(OpenAiApi.class);
//        this.openAiApi = new Retrofit.Builder()
//            .baseUrl(apiHost)
//            .client(okHttpClient)
//            .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
//            .addConverterFactory(JacksonConverterFactory.create())
//            .build().create(OpenAiApi.class);
    }
    /**
@@ -180,7 +190,7 @@
            ObjectMapper mapper = new ObjectMapper();
            String requestBody = mapper.writeValueAsString(chatCompletion);
            Request request = new Request.Builder()
                .url(this.apiHost + "v1/chat/completions")
                .url(this.apiHost)
                .post(RequestBody.create(MediaType.parse(ContentType.JSON.getValue()), requestBody))
                .build();
            factory.newEventSource(request, eventSourceListener);
@@ -334,7 +344,6 @@
        BillingUsage billingUsage = billingUsage(start.toInstant().atZone(ZoneId.systemDefault()).toLocalDate(), end.toInstant().atZone(ZoneId.systemDefault()).toLocalDate());
        double totalUsage = billingUsage.getTotalUsage().doubleValue() / 100;
        System.out.println(totalUsage);
        Subscription subscription = subscription();
        KeyInfo keyInfo = new KeyInfo();
        String start_key = key.substring(0, 6);
@@ -611,6 +620,8 @@
         */
        private String apiHost;
        private String apiUrl;
        /**
         * è‡ªå®šä¹‰OkhttpClient
         */
@@ -645,6 +656,16 @@
            return this;
        }
        /**
         * @param val è‡ªå®šä¹‰è¯·æ±‚后缀
         * @return Builder
         * @see OpenAIConst
         */
        public Builder apiUrl(String val) {
            apiUrl = val;
            return this;
        }
        public Builder keyStrategy(KeyStrategyFunction val) {
            keyStrategy = val;
            return this;
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/openai/TestOpenAIAPI.java
@@ -21,7 +21,7 @@
            .build();
        try (Response response = client.newCall(request).execute()) {
            System.out.println(response.body().string());
        }
    }
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/openai/exception/CommonError.java
@@ -1,7 +1,7 @@
package org.ruoyi.common.chat.openai.exception;
/**
 * æè¿°ï¼š é”™è¯¯
 *   é”™è¯¯
 *
 * @author https:www.unfbx.com
 *  2023-02-11
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/openai/exception/IError.java
@@ -1,6 +1,6 @@
package org.ruoyi.common.chat.openai.exception;
/**
 * æè¿°ï¼š
 *
 *
 * @author https:www.unfbx.com
 *  2023-02-11
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/openai/function/KeyRandomStrategy.java
@@ -5,7 +5,7 @@
import java.util.List;
/**
 * æè¿°ï¼šéšæœºç­–ç•¥
 *  éšæœºç­–ç•¥
 *
 * @author https:www.unfbx.com
 * @since 2023-04-03
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/openai/function/KeyStrategyFunction.java
@@ -3,7 +3,7 @@
import java.util.function.Function;
/**
 * æè¿°ï¼škey çš„获取策略
 *  key çš„获取策略
 * jdk默认实现
 * @see Function
 *
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/openai/interceptor/DefaultOpenAiAuthInterceptor.java
@@ -9,7 +9,7 @@
import java.util.Map;
/**
 * æè¿°ï¼šè¯·æ±‚增加header apikey
 *  è¯·æ±‚增加header apikey
 *
 * @author https:www.unfbx.com
 * @since 2023-03-23
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/openai/interceptor/DynamicKeyOpenAiAuthInterceptor.java
@@ -16,7 +16,7 @@
import java.util.stream.Collectors;
/**
 * æè¿°ï¼šåŠ¨æ€å¤„ç†key的鉴权拦截器
 *  åŠ¨æ€å¤„ç†key的鉴权拦截器
 *
 * @author https:www.unfbx.com
 * @since 2023-04-25
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/openai/interceptor/OpenAILogger.java
@@ -4,7 +4,7 @@
import okhttp3.logging.HttpLoggingInterceptor;
/**
 * æè¿°ï¼š æ—¥å¿—
 *   æ—¥å¿—
 *
 * @author https:www.unfbx.com
 * 2023-02-28
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/openai/interceptor/OpenAiResponseInterceptor.java
@@ -13,7 +13,7 @@
import java.util.Objects;
/**
 * æè¿°ï¼šopenai è¿”回值处理Interceptor
 *  openai è¿”回值处理Interceptor
 *
 * @author https:www.unfbx.com
 * @since  2023-03-23
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/plugin/CmdReq.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/plugin/CmdResp.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/plugin/SqlPlugin.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/plugin/SqlReq.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/plugin/SqlResp.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/request/ChatRequest.java
@@ -7,7 +7,7 @@
import java.util.List;
/**
 * æè¿°ï¼šå¯¹è¯è¯·æ±‚对象
 *  å¯¹è¯è¯·æ±‚对象
 *
 * @author ageerle
 * @sine 2023-04-08
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/request/Dall3Request.java
@@ -4,7 +4,7 @@
import lombok.Data;
/**
 * æè¿°ï¼š
 *
 *
 * @author https:www.unfbx.com
 * @sine 2023-04-08
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/sse/ConsoleEventSourceListener.java
@@ -10,7 +10,7 @@
import java.util.Objects;
/**
 * æè¿°ï¼š sse
 *   sse
 *
 * @author https:www.unfbx.com
 * 2023-02-28
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/sse/DefaultPluginListener.java
@@ -8,7 +8,7 @@
import org.ruoyi.common.chat.openai.plugin.PluginAbstract;
/**
 * æè¿°ï¼š æ’件开发返回信息收集sse监听器
 *   æ’件开发返回信息收集sse监听器
 *
 * @author https:www.unfbx.com
 * 2023-08-18
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/sse/PluginListener.java
@@ -19,7 +19,7 @@
import java.util.Objects;
/**
 * æè¿°ï¼š æ’件开发返回信息收集sse监听器
 *   æ’件开发返回信息收集sse监听器
 *
 * @author https:www.unfbx.com
 * 2023-08-18
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/utils/TikTokensUtil.java
@@ -15,7 +15,7 @@
import java.util.*;
/**
 * æè¿°ï¼štoken计算工具类
 *  token计算工具类
 *
 * @author https:www.unfbx.com
 * @since 2023-04-04
ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/event/ConfigChangeEvent.java
@@ -3,7 +3,7 @@
import org.springframework.context.ApplicationEvent;
/**
 * æè¿°ï¼šå®šä¹‰ä¸€ä¸ªäº‹ä»¶ç±»ï¼Œç”¨äºŽé€šçŸ¥é…ç½®å˜åŒ–
 *  å®šä¹‰ä¸€ä¸ªäº‹ä»¶ç±»ï¼Œç”¨äºŽé€šçŸ¥é…ç½®å˜åŒ–
 *
 * @author ageerle@163.com
 * date 2024/5/19
ruoyi-common/ruoyi-common-live/live-chat-clients/live-chat-client-douyu/src/test/java/tech/ordinaryroad/live/chat/client/douyu/client/ChatChoice.java
@@ -7,7 +7,7 @@
import java.io.Serializable;
/**
 * æè¿°ï¼š
 *
 *
 * @author https:www.unfbx.com
 * @since 2023-03-02
ruoyi-common/ruoyi-common-live/live-chat-clients/live-chat-client-douyu/src/test/java/tech/ordinaryroad/live/chat/client/douyu/client/ChatCompletionResponse.java
@@ -7,7 +7,7 @@
import java.util.List;
/**
 * æè¿°ï¼š chat答案类
 *   chat答案类
 *
 * @author https:www.unfbx.com
 * 2023-03-02
ruoyi-common/ruoyi-common-live/live-chat-clients/live-chat-client-douyu/src/test/java/tech/ordinaryroad/live/chat/client/douyu/client/DouyuLiveChatClientTest.java
@@ -45,11 +45,7 @@
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.IOException;
import java.util.Objects;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
@@ -95,12 +91,9 @@
                    .build();
            long startTime = System.currentTimeMillis(); // èŽ·å–å¼€å§‹æ—¶é—´çš„æ¯«ç§’æ•°
            System.out.println("执行前.......");
            Thread.sleep(3000);
            System.out.println("执行后.......");
            long endTime = System.currentTimeMillis(); // èŽ·å–ç»“æŸæ—¶é—´çš„æ¯«ç§’æ•°
            long timeDiff = endTime - startTime; // è®¡ç®—æ—¶é—´å·®
            System.out.println("执行时间 " + timeDiff / 1000 + " ç§’。");
            try (Response response = okClient.newCall(request).execute()) {
                if (response.body() != null) {
ruoyi-common/ruoyi-common-live/live-chat-clients/live-chat-client-douyu/src/test/java/tech/ordinaryroad/live/chat/client/douyu/client/Message.java
@@ -9,7 +9,7 @@
import java.io.Serializable;
/**
 * æè¿°ï¼š
 *
 *
 * @author https:www.unfbx.com
 * @since 2023-03-02
ruoyi-common/ruoyi-common-live/live-chat-clients/live-chat-client-douyu/src/test/java/tech/ordinaryroad/live/chat/client/douyu/client/Usage.java
@@ -7,7 +7,7 @@
import java.io.Serializable;
/**
 * æè¿°ï¼š
 *
 *
 * @author https:www.unfbx.com
 *  2023-02-15
ruoyi-common/ruoyi-common-live/live-chat-clients/live-chat-client-douyu/src/test/java/tech/ordinaryroad/live/chat/client/douyu/util/DouyuCodecUtilTest.java
@@ -48,7 +48,6 @@
        Map<String, Object> stringObjectMap = DouyuCodecUtil.parseDouyuSttStringToMap(mapkb);
        assertNotNull(stringObjectMap);
        stringObjectMap.forEach((string, o) -> {
            System.out.println(string);
        });
    }
@@ -58,7 +57,6 @@
        Map<String, Object> stringObjectMap = DouyuCodecUtil.parseDouyuSttStringToMap(pdrinfo);
        assertNotNull(stringObjectMap);
        stringObjectMap.forEach((string, o) -> {
            System.out.println(string);
        });
    }
@@ -78,7 +76,6 @@
                }});
            }});
        }});
        System.out.println(douyuSttString);
        assertEquals("key1@=value1/key2@=2/key3@=11@AA=11@AS12@AA=12@AS@S22@AA=22@AS21@AA=21@AS@S/".length(), douyuSttString.length());
    }
@@ -87,8 +84,6 @@
        String mapkb = "type@=mapkb/pk_time@=600/teams@=team@AA=5@ASres@AA=1@ASsc@AA=660000@ASbf@AA=0@AS@Steam@AA=6@ASres@AA=2@ASsc@AA=600000@ASbf@AA=0@AS@Steam@AA=4@ASres@AA=3@ASsc@AA=456000@ASbf@AA=0@AS@Steam@AA=2@ASres@AA=4@ASsc@AA=302000@ASbf@AA=0@AS@Steam@AA=3@ASres@AA=5@ASsc@AA=100000@ASbf@AA=0@AS@Steam@AA=1@ASres@AA=6@ASsc@AA=200@ASbf@AA=0@AS@S/";
        IDouyuMsg iDouyuMsg = DouyuCodecUtil.parseDouyuSttString(mapkb, DouyuCodecUtil.MSG_TYPE_RECEIVE);
        String douyuSttString = DouyuCodecUtil.toDouyuSttString(iDouyuMsg);
        System.out.println(mapkb);
        System.out.println(douyuSttString);
        assertEquals(mapkb.length(), douyuSttString.length());
        IDouyuMsg douyuSttStringMsg = DouyuCodecUtil.parseDouyuSttString(douyuSttString, DouyuCodecUtil.MSG_TYPE_RECEIVE);
        assertNotNull(douyuSttStringMsg);
@@ -97,6 +92,5 @@
    @Test
    void unescape() {
        String unescape = DouyuCodecUtil.unescape("team@AA=5@ASres@AA=1@ASsc@AA=660000@ASbf@AA=0@AS@Steam@AA=6@ASres@AA=2@ASsc@AA=600000@ASbf@AA=0@AS@Steam@AA=4@ASres@AA=3@ASsc@AA=456000@ASbf@AA=0@AS@Steam@AA=2@ASres@AA=4@ASsc@AA=302000@ASbf@AA=0@AS@Steam@AA=3@ASres@AA=5@ASsc@AA=100000@ASbf@AA=0@AS@Steam@AA=1@ASres@AA=6@ASsc@AA=200@ASbf@AA=0@AS@S");
        System.out.println(unescape);
    }
}
}
ruoyi-common/ruoyi-common-live/live-chat-clients/live-chat-client-huya/src/test/java/tech/ordinaryroad/live/chat/client/huya/util/HuyaCodecUtilTest.java
@@ -26,7 +26,6 @@
        ConnectParaInfo wsConnectParaInfo = ConnectParaInfo.newWSConnectParaInfo(ver, exp, appSrc);
        byte[] byteArray = wsConnectParaInfo.toByteArray();
        String s = HuyaCodecUtil.ab2str(byteArray);
        System.out.println(s);
    }
    @Test
@@ -36,7 +35,6 @@
        String s = HuyaCodecUtil.ab2str(byteArray);
        String btoa = HuyaCodecUtil.btoa(s);
        System.out.println(btoa);
    }
    @Test
@@ -67,7 +65,6 @@
        LiveLaunchReq liveLaunchReq = new LiveLaunchReq();
        liveLaunchReq = wupReq.getUniAttribute().getByClass("tReq", liveLaunchReq);
        UserId tId = liveLaunchReq.getTId();
        System.out.println(wupReq.getTarsServantRequest().getVersion());
    }
    @Test
@@ -96,4 +93,4 @@
        UserId tId = getLivingInfoReq.getTId();
    }
}
}
ruoyi-common/ruoyi-common-live/live-chat-clients/live-chat-client-kuaishou/src/test/java/tech/ordinaryroad/live/chat/client/kuaishou/api/KuaishouApisTest.java
@@ -28,13 +28,5 @@
    @Test
    void sendComment() {
        System.out.println(KuaishouApis.sendComment(System.getenv("cookie"),
                "3x6pb6bcmjrarvs",
                KuaishouApis.SendCommentRequest
                        .builder()
                        .liveStreamId("XKLoBv2mAEo")
                        .content("666666a")
                        .build()
        ));
    }
}
}
ruoyi-common/ruoyi-common-pay/src/main/java/org/ruoyi/common/listener/ConfigChangeListener.java
@@ -10,7 +10,7 @@
import org.springframework.stereotype.Component;
/**
 * æè¿°ï¼šåˆ›å»ºä¸€ä¸ªç›‘听器,用于处理配置变化事件
 *  åˆ›å»ºä¸€ä¸ªç›‘听器,用于处理配置变化事件
 *
 * @author ageerle@163.com
 * date 2024/5/19
ruoyi-common/ruoyi-common-wechat/src/main/java/org/ruoyi/common/wechat/itchat4j/client/SingleHttpClient.java
@@ -84,7 +84,6 @@
            if (params != null) {
                String paramStr = EntityUtils.toString(new UrlEncodedFormEntity(params, Consts.UTF_8));
                httpGet = new HttpGet(url + "?" + paramStr);
//                System.out.println(url + "?" + paramStr);
            } else {
                httpGet = new HttpGet(url);
            }
ruoyi-common/ruoyi-common-wechat/src/main/java/org/ruoyi/common/wechat/itchat4j/utils/tools/CommonTools.java
@@ -292,9 +292,6 @@
         sb.append(content.substring(lastStart));
      }
      if (sb.length() != 0) {
         System.out.println(EmojiParser.parseToUnicode(sb.toString()));
         System.out.println(EmojiParser.parseToAliases(EmojiParser.parseToUnicode(sb.toString())));
         System.out.println(EmojiParser.removeAllEmojis(sb.toString()));
      }
   }
ruoyi-common/ruoyi-common-wechat/src/main/java/org/ruoyi/common/wechat/web/utils/MD5Util.java
@@ -61,7 +61,6 @@
   }
   public static void main(String[] args) {
      System.out.println(MD5Encrypt("wxwobot"));
   }
ruoyi-modules-api/ruoyi-chat-api/pom.xml
@@ -71,6 +71,18 @@
            <artifactId>spring-ai-starter-model-openai</artifactId>
        </dependency>
        <dependency>
            <groupId>io.github.imfangs</groupId>
            <artifactId>dify-java-client</artifactId>
            <version>1.0.7</version>
        </dependency>
        <dependency>
            <groupId>com.coze</groupId>
            <artifactId>coze-api</artifactId>
            <version>0.3.1</version>
        </dependency>
    </dependencies>
</project>
ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/ChatModel.java
@@ -1,6 +1,7 @@
package org.ruoyi.domain;
import com.alibaba.excel.annotation.ExcelProperty;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
@@ -46,7 +47,7 @@
    /**
     * æ¨¡åž‹ä»·æ ¼
     */
    private Long modelPrice;
    private Double modelPrice;
    /**
     * è®¡è´¹ç±»åž‹
@@ -68,6 +69,7 @@
     */
    private String apiHost;
    /**
     * å¯†é’¥
     */
ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/bo/ChatModelBo.java
@@ -1,5 +1,6 @@
package org.ruoyi.domain.bo;
import com.alibaba.excel.annotation.ExcelProperty;
import org.ruoyi.common.core.validate.AddGroup;
import org.ruoyi.common.core.validate.EditGroup;
import org.ruoyi.domain.ChatModel;
@@ -48,7 +49,7 @@
     * æ¨¡åž‹ä»·æ ¼
     */
    @NotNull(message = "模型价格不能为空", groups = { AddGroup.class, EditGroup.class })
    private Long modelPrice;
    private Double modelPrice;
    /**
     * è®¡è´¹ç±»åž‹
@@ -79,6 +80,7 @@
    @NotBlank(message = "密钥不能为空", groups = { AddGroup.class, EditGroup.class })
    private String apiKey;
    /**
     * å¤‡æ³¨
     */
ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/request/TranslationRequest.java
@@ -3,7 +3,7 @@
import lombok.Data;
/**
 * æè¿°ï¼šç¿»è¯‘请求对象
 *  ç¿»è¯‘请求对象
 *
 * @author ageerle@163.com
 * date 2025/1/13
ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/vo/ChatModelVo.java
@@ -56,7 +56,7 @@
     * æ¨¡åž‹ä»·æ ¼
     */
    @ExcelProperty(value = "模型价格")
    private Long modelPrice;
    private Double modelPrice;
    /**
     * è®¡è´¹ç±»åž‹
@@ -93,6 +93,5 @@
     */
    @ExcelProperty(value = "备注")
    private String remark;
}
ruoyi-modules-api/ruoyi-knowledge-api/pom.xml
@@ -103,6 +103,18 @@
            <version>1.19.6</version>
        </dependency>
        <dependency>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j-document-parser-apache-tika</artifactId>
        </dependency>
        <!-- ruoyi-knowledge-api/pom.xml -->
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.17.0</version>
        </dependency>
    </dependencies>
</project>
ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/chain/loader/ExcelFileLoader.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,41 @@
package org.ruoyi.chain.loader;
import dev.langchain4j.data.document.Document;
import dev.langchain4j.data.document.parser.apache.tika.ApacheTikaDocumentParser;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.ruoyi.chain.split.TextSplitter;
import org.ruoyi.common.core.exception.UtilException;
import org.springframework.stereotype.Component;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
@Component
@AllArgsConstructor
@Slf4j
public class ExcelFileLoader implements ResourceLoader {
    private final TextSplitter textSplitter;
    private static final int DEFAULT_BUFFER_SIZE = 8192;
    @Override
    public String getContent(InputStream inputStream) {
        // ä½¿ç”¨å¸¦ç¼“冲的输入流包装(保持原流不自动关闭)
        try (InputStream bufferedStream = new BufferedInputStream(inputStream, DEFAULT_BUFFER_SIZE)) {
            ApacheTikaDocumentParser apacheTikaDocumentParser = new ApacheTikaDocumentParser();
            Document document = apacheTikaDocumentParser.parse(bufferedStream);
            return document.text();
        } catch (IOException e) {
            String errorMsg = "Excel文件流读取失败";
            throw new UtilException(errorMsg, e);
        } catch (RuntimeException e) {
            String errorMsg = "Excel内容解析异常";
            throw new UtilException(errorMsg, e);
        }
    }
    @Override
    public List<String> getChunkList(String content, String kid) {
        return textSplitter.split(content, kid);
    }
}
ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/chain/loader/ResourceLoaderFactory.java
@@ -1,10 +1,7 @@
package org.ruoyi.chain.loader;
import lombok.AllArgsConstructor;
import org.ruoyi.chain.split.CharacterTextSplitter;
import org.ruoyi.chain.split.CodeTextSplitter;
import org.ruoyi.chain.split.MarkdownTextSplitter;
import org.ruoyi.chain.split.TokenTextSplitter;
import org.ruoyi.chain.split.*;
import org.ruoyi.constant.FileType;
import org.springframework.stereotype.Component;
@@ -16,6 +13,8 @@
    private final CodeTextSplitter codeTextSplitter;
    private final MarkdownTextSplitter markdownTextSplitter;
    private final TokenTextSplitter tokenTextSplitter;
    private final ExcelTextSplitter excelTextSplitter;
    public ResourceLoader getLoaderByFileType(String fileType){
        if (FileType.isTextFile(fileType)){
            return new TextFileLoader(characterTextSplitter);
@@ -25,6 +24,8 @@
            return new PdfFileLoader(characterTextSplitter);
        } else if (FileType.isMdFile(fileType)) {
            return new MarkDownFileLoader(markdownTextSplitter);
        }else if (FileType.isExcel(fileType)) {
            return new ExcelFileLoader(excelTextSplitter);
        }else if (FileType.isCodeFile(fileType)) {
            return new CodeFileLoader(codeTextSplitter);
        }else {
ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/chain/split/ExcelTextSplitter.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,17 @@
package org.ruoyi.chain.split;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
@AllArgsConstructor
@Slf4j
public class ExcelTextSplitter implements TextSplitter{
    @Override
    public List<String> split(String content, String kid) {
        return null;
    }
}
ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/constant/FileType.java
@@ -7,6 +7,8 @@
    public static final String DOC = "doc";
    public static final String DOCX = "docx";
    public static final String PDF = "pdf";
    public static final String XLS = "xls";
    public static final String XLSX = "xlsx";
    public static final String LOG = "log";
    public static final String XML = "xml";
@@ -88,4 +90,13 @@
        }
    }
    public static boolean isExcel(String type){
        if (type.equalsIgnoreCase(XLS) || type.equalsIgnoreCase(XLSX)){
            return true;
        }
        else {
            return false;
        }
    }
}
ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/service/impl/VectorStoreServiceImpl.java
@@ -11,6 +11,7 @@
import dev.langchain4j.store.embedding.EmbeddingStore;
import dev.langchain4j.store.embedding.filter.Filter;
import dev.langchain4j.store.embedding.filter.comparison.IsEqualTo;
import dev.langchain4j.store.embedding.inmemory.InMemoryEmbeddingStore;
import dev.langchain4j.store.embedding.milvus.MilvusEmbeddingStore;
import dev.langchain4j.store.embedding.qdrant.QdrantEmbeddingStore;
import dev.langchain4j.store.embedding.weaviate.WeaviateEmbeddingStore;
@@ -39,11 +40,11 @@
    private final ConfigService configService;
    Map<String,EmbeddingStore<TextSegment>> storeMap;
    Map<String,EmbeddingStore<TextSegment>> storeMap = new HashMap<>();
    @Override
    public void createSchema(String kid,String modelName) {
        EmbeddingStore<TextSegment> embeddingStore = WeaviateEmbeddingStore.builder().build();
        EmbeddingStore<TextSegment> embeddingStore;
        switch (modelName) {
            case "weaviate" -> {
                String protocol = configService.getConfigValue("weaviate", "protocol");
@@ -78,6 +79,10 @@
                        .collectionName(collectionName)
                        .build();
            }
            default -> {
                //使用内存
                embeddingStore = new InMemoryEmbeddingStore<>();
            }
        }
        storeMap.put(kid,embeddingStore);
    }
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/bo/SysUserPasswordBo.java
@@ -7,7 +7,7 @@
/**
 * æè¿°ï¼šç”¨æˆ·å¯†ç ä¿®æ”¹bo
 *  ç”¨æˆ·å¯†ç ä¿®æ”¹bo
 *
 * @author ageerle@163.com
 * date 2025/3/9
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/controller/chat/ChatController.java
@@ -28,7 +28,7 @@
/**
 * æè¿°ï¼šèŠå¤©ç®¡ç†
 *  èŠå¤©ç®¡ç†
 *
 * @author ageerle@163.com
 * @date 2023-03-01
@@ -70,8 +70,7 @@
    @PostMapping("/audio")
    @ResponseBody
    public WhisperResponse audio(@RequestParam("file") MultipartFile file) {
        WhisperResponse whisperResponse = sseService.speechToTextTranscriptionsV2(file);
        return whisperResponse;
        return sseService.speechToTextTranscriptionsV2(file);
    }
    /**
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/domain/bo/GenerateLuma.java
@@ -3,7 +3,7 @@
import lombok.Data;
/**
 * æè¿°ï¼šæ–‡ç”Ÿè§†é¢‘请求对象
 *  æ–‡ç”Ÿè§†é¢‘请求对象
 *
 * @author ageerle@163.com
 * date 2024/6/27
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/domain/bo/GenerateLyric.java
@@ -3,7 +3,7 @@
import lombok.Data;
/**
 * æè¿°ï¼šç”Ÿæˆæ­Œè¯
 *  ç”Ÿæˆæ­Œè¯
 *
 * @author ageerle@163.com
 * date 2024/6/27
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/enums/ChatModeType.java
@@ -6,6 +6,8 @@
public enum ChatModeType {
    OLLAMA("ollama", "本地部署模型"),
    CHAT("chat", "中转模型"),
    DIFY("dify", "DIFY"),
    COZE("coze", "扣子"),
    VECTOR("vector", "知识库向量模型");
    private final String code;
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/enums/DisplayType.java
@@ -3,7 +3,7 @@
import lombok.Getter;
/**
 * æè¿°ï¼šæ˜¯å¦æ˜¾ç¤º
 *  æ˜¯å¦æ˜¾ç¤º
 *
 * @author ageerle@163.com
 * date 2025/4/10
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/factory/ChatServiceFactory.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,43 @@
package org.ruoyi.chat.factory;
import org.ruoyi.chat.service.chat.IChatService;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
 * èŠå¤©æœåŠ¡å·¥åŽ‚ç±»
 *
 * @author ageerle@163.com
 * date 2025/5/10
 */
@Component
public class ChatServiceFactory  implements ApplicationContextAware {
    private final Map<String, IChatService> chatServiceMap = new ConcurrentHashMap<>();
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        // åˆå§‹åŒ–时收集所有IChatService的实现
        Map<String, IChatService> serviceMap = applicationContext.getBeansOfType(IChatService.class);
        for (IChatService service : serviceMap.values()) {
            if (service != null) {
                chatServiceMap.put(service.getCategory(), service);
            }
        }
    }
    /**
     * æ ¹æ®æ¨¡åž‹ç±»åˆ«èŽ·å–å¯¹åº”çš„èŠå¤©æœåŠ¡å®žçŽ°
     */
    public IChatService getChatService(String category) {
        IChatService service = chatServiceMap.get(category);
        if (service == null) {
            throw new IllegalArgumentException("不支持的模型类别: " + category);
        }
        return service;
    }
}
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/listener/SSEEventSourceListener.java
@@ -24,7 +24,7 @@
import java.util.Objects;
/**
 * æè¿°ï¼šOpenAIEventSourceListener
 *  OpenAIEventSourceListener
 *
 * @author https:www.unfbx.com
 * @date 2023-02-22
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/IChatService.java
@@ -16,6 +16,8 @@
     * @param chatRequest è¯·æ±‚对象
     */
    SseEmitter chat(ChatRequest chatRequest,SseEmitter emitter);
    /**
     * èŽ·å–æ­¤æœåŠ¡æ”¯æŒçš„æ¨¡åž‹ç±»åˆ«
     */
    String getCategory();
}
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/UserModelService.java
@@ -1,26 +1,16 @@
package org.ruoyi.chat.service.chat;
import cn.dev33.satoken.stp.StpUtil;
import lombok.RequiredArgsConstructor;
import org.ruoyi.chat.enums.DisplayType;
import org.ruoyi.chat.enums.UserGradeType;
import org.ruoyi.common.satoken.utils.LoginHelper;
import org.ruoyi.domain.bo.ChatModelBo;
import org.ruoyi.domain.bo.ChatPackagePlanBo;
import org.ruoyi.domain.vo.ChatModelVo;
import org.ruoyi.domain.vo.ChatPackagePlanVo;
import org.ruoyi.service.IChatModelService;
import org.ruoyi.service.IChatPackagePlanService;
import org.ruoyi.system.domain.vo.SysUserVo;
import org.ruoyi.system.service.ISysUserService;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
 * æè¿°ï¼šç”¨æˆ·æ¨¡åž‹ä¿¡æ¯
 * ç”¨æˆ·æ¨¡åž‹ä¿¡æ¯
 *
 * @author ageerle@163.com
 * date 2025/4/10
@@ -32,30 +22,9 @@
    private final IChatModelService chatModelService;
    private final ISysUserService userService;
    private final IChatPackagePlanService packagePlanService;
    public List<ChatModelVo> modelList(ChatModelBo bo) {
        bo.setModelShow(DisplayType.VISIBLE.getCode());
        List<ChatModelVo> chatModelList = chatModelService.queryList(bo);
        ChatPackagePlanBo sysPackagePlanBo = new ChatPackagePlanBo();
        if (StpUtil.isLogin()) {
            Long userId = LoginHelper.getLoginUser().getUserId();
            SysUserVo sysUserVo = userService.selectUserById(userId);
            if (UserGradeType.UNPAID.getCode().equals(sysUserVo.getUserGrade())){
                sysPackagePlanBo.setName("Free");
                ChatPackagePlanVo chatPackagePlanVo = packagePlanService.queryList(sysPackagePlanBo).get(0);
                List<String> array = new ArrayList<>(Arrays.asList(chatPackagePlanVo.getPlanDetail().split(",")));
                chatModelList.removeIf(model -> !array.contains(model.getModelName()));
            }
        }else {
            sysPackagePlanBo.setName("Visitor");
            ChatPackagePlanVo sysPackagePlanVo = packagePlanService.queryList(sysPackagePlanBo).get(0);
            List<String> array = new ArrayList<>(Arrays.asList(sysPackagePlanVo.getPlanDetail().split(",")));
            chatModelList.removeIf(model -> !array.contains(model.getModelName()));
        }
        return new ArrayList<>(chatModelList);
        return chatModelService.queryList(bo);
    }
}
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/CozeServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,81 @@
package org.ruoyi.chat.service.chat.impl;
import com.coze.openapi.client.chat.CreateChatReq;
import com.coze.openapi.client.chat.model.ChatEvent;
import com.coze.openapi.client.chat.model.ChatEventType;
import com.coze.openapi.client.connversations.message.model.Message;
import com.coze.openapi.service.auth.TokenAuth;
import com.coze.openapi.service.config.Consts;
import com.coze.openapi.service.service.CozeAPI;
import io.reactivex.Flowable;
import lombok.extern.slf4j.Slf4j;
import org.ruoyi.chat.enums.ChatModeType;
import org.ruoyi.chat.service.chat.IChatService;
import org.ruoyi.common.chat.request.ChatRequest;
import org.ruoyi.domain.vo.ChatModelVo;
import org.ruoyi.service.IChatModelService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import java.util.Collections;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
 * æ‰£å­èŠå¤©ç®¡ç†
 *
 * @author ageer
 */
@Service
@Slf4j
public class CozeServiceImpl implements IChatService {
    @Autowired
    private IChatModelService chatModelService;
    @Override
    public SseEmitter chat(ChatRequest chatRequest, SseEmitter emitter) {
        ChatModelVo chatModelVo = chatModelService.selectModelByName(chatRequest.getModel());
        TokenAuth authCli = new TokenAuth(chatModelVo.getApiKey());
        CozeAPI coze =
                new CozeAPI.Builder()
                        .baseURL(chatModelVo.getApiHost())
                        .auth(authCli)
                        .readTimeout(10000)
                        .build();
        CreateChatReq req =
                CreateChatReq.builder()
                        .botID(chatModelVo.getModelName())
                        .userID(chatRequest.getUserId().toString())
                        .messages(Collections.singletonList(Message.buildUserQuestionText("What can you do?")))
                        .build();
        Flowable<ChatEvent> resp = coze.chat().stream(req);
        ExecutorService executor = Executors.newFixedThreadPool(10);
        executor.submit(() -> {
            resp.blockingForEach(
                    event -> {
                        if (ChatEventType.CONVERSATION_MESSAGE_DELTA.equals(event.getEvent())) {
                            emitter.send(event.getMessage().getContent());
                            log.info("coze: {}", event.getMessage().getContent());
                        }
                        if (ChatEventType.CONVERSATION_CHAT_COMPLETED.equals(event.getEvent())) {
                            emitter.complete();
                            log.info("Token usage: {}", event.getChat().getUsage().getTokenCount());
                        }
                    }
            );
            coze.shutdownExecutor();
        });
        return emitter;
    }
    @Override
    public String getCategory() {
        return ChatModeType.COZE.getCode();
    }
}
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/DifyServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,96 @@
package org.ruoyi.chat.service.chat.impl;
import io.github.imfangs.dify.client.DifyClient;
import io.github.imfangs.dify.client.DifyClientFactory;
import io.github.imfangs.dify.client.callback.ChatStreamCallback;
import io.github.imfangs.dify.client.enums.ResponseMode;
import io.github.imfangs.dify.client.event.ErrorEvent;
import io.github.imfangs.dify.client.event.MessageEndEvent;
import io.github.imfangs.dify.client.event.MessageEvent;
import io.github.imfangs.dify.client.model.DifyConfig;
import io.github.imfangs.dify.client.model.chat.ChatMessage;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.ruoyi.chat.enums.ChatModeType;
import org.ruoyi.chat.service.chat.IChatService;
import org.ruoyi.common.chat.request.ChatRequest;
import org.ruoyi.domain.vo.ChatModelVo;
import org.ruoyi.service.IChatModelService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
/**
 * dify èŠå¤©ç®¡ç†
 *
 * @author ageer
 */
@Service
@Slf4j
public class DifyServiceImpl implements IChatService {
    @Autowired
    private IChatModelService chatModelService;
    @Override
    public SseEmitter chat(ChatRequest chatRequest, SseEmitter emitter) {
        ChatModelVo chatModelVo = chatModelService.selectModelByName(chatRequest.getModel());
        // ä½¿ç”¨è‡ªå®šä¹‰é…ç½®åˆ›å»ºå®¢æˆ·ç«¯
        DifyConfig config = DifyConfig.builder()
                .baseUrl(chatModelVo.getApiHost())
                .apiKey(chatModelVo.getApiKey())
                .connectTimeout(5000)
                .readTimeout(60000)
                .writeTimeout(30000)
                .build();
        DifyClient chatClient = DifyClientFactory.createClient(config);
        // åˆ›å»ºèŠå¤©æ¶ˆæ¯
        ChatMessage message = ChatMessage.builder()
                .query(chatRequest.getPrompt())
                .user(chatRequest.getUserId().toString())
                .responseMode(ResponseMode.STREAMING)
                .build();
        // å‘送流式消息
        try {
            chatClient.sendChatMessageStream(message, new ChatStreamCallback() {
                @SneakyThrows
                @Override
                public void onMessage(MessageEvent event) {
                    emitter.send(event.getAnswer());
                    log.info("收到消息片段: {}", event.getAnswer());
                }
                @Override
                public void onMessageEnd(MessageEndEvent event) {
                    emitter.complete();
                    log.info("消息结束,完整消息ID: {}", event.getMessageId());
                }
                @Override
                public void onError(ErrorEvent event) {
                    System.err.println("错误: " + event.getMessage());
                }
                @Override
                public void onException(Throwable throwable) {
                    System.err.println("异常: " + throwable.getMessage());
                }
            });
        } catch (Exception e) {
            log.error("dify请求失败:{}", e.getMessage());
        }
        return emitter;
    }
    @Override
    public String getCategory() {
        return ChatModeType.DIFY.getCode();
    }
}
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/OllamaServiceImpl.java
@@ -7,6 +7,8 @@
import io.github.ollama4j.models.chat.OllamaChatRequestModel;
import io.github.ollama4j.models.generate.OllamaStreamHandler;
import lombok.extern.slf4j.Slf4j;
import org.ruoyi.chat.enums.ChatModeType;
import org.ruoyi.chat.service.chat.IChatService;
import org.ruoyi.chat.util.SSEUtil;
import org.ruoyi.common.chat.entity.chat.Message;
import org.ruoyi.common.chat.request.ChatRequest;
@@ -22,14 +24,18 @@
import java.util.concurrent.CompletableFuture;
/**
 * @author ageer
 */
@Service
@Slf4j
public class OllamaServiceImpl  {
public class OllamaServiceImpl implements IChatService {
   @Autowired
   private  IChatModelService chatModelService;
    @Autowired
    private IChatModelService chatModelService;
    public SseEmitter chat(ChatRequest chatRequest,SseEmitter emitter) {
    @Override
    public SseEmitter chat(ChatRequest chatRequest, SseEmitter emitter) {
        ChatModelVo chatModelVo = chatModelService.selectModelByName(chatRequest.getModel());
        String host = chatModelVo.getApiHost();
        List<Message> msgList = chatRequest.getMessages();
@@ -56,7 +62,6 @@
                OllamaStreamHandler streamHandler = (s) -> {
                    String substr = s.substring(response.length());
                    response.append(substr);
                    System.out.println(substr);
                    try {
                        emitter.send(substr);
                    } catch (IOException e) {
@@ -73,4 +78,8 @@
        return emitter;
    }
    @Override
    public String getCategory() {
        return ChatModeType.OLLAMA.getCode();
    }
}
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/OpenAIServiceImpl.java
@@ -3,6 +3,7 @@
import io.modelcontextprotocol.client.McpSyncClient;
import lombok.extern.slf4j.Slf4j;
import org.ruoyi.chat.config.ChatConfig;
import org.ruoyi.chat.enums.ChatModeType;
import org.ruoyi.chat.listener.SSEEventSourceListener;
import org.ruoyi.chat.service.chat.IChatService;
import org.ruoyi.common.chat.entity.chat.ChatCompletion;
@@ -21,15 +22,15 @@
import java.util.List;
/**
 * @author ageer
 */
@Service
@Slf4j
public class OpenAIServiceImpl implements IChatService {
    @Autowired
    private IChatModelService chatModelService;
    private OpenAiStreamClient openAiStreamClient;
    @Value("${spring.ai.mcp.client.enabled}")
    private Boolean enabled;
@@ -47,7 +48,7 @@
    @Override
    public SseEmitter chat(ChatRequest chatRequest,SseEmitter emitter) {
        ChatModelVo chatModelVo = chatModelService.selectModelByName(chatRequest.getModel());
        openAiStreamClient = ChatConfig.createOpenAiStreamClient(chatModelVo.getApiHost(), chatModelVo.getApiKey());
        OpenAiStreamClient openAiStreamClient = ChatConfig.createOpenAiStreamClient(chatModelVo.getApiHost(), chatModelVo.getApiKey());
        List<Message> messages = chatRequest.getMessages();
        if (enabled) {
            String toolString = mcpChat(chatRequest.getPrompt());
@@ -69,4 +70,9 @@
        return this.chatClient.prompt(prompt).call().content();
    }
    @Override
    public String getCategory() {
        return ChatModeType.CHAT.getCode();
    }
}
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/SseServiceImpl.java
@@ -8,7 +8,9 @@
import lombok.extern.slf4j.Slf4j;
import okhttp3.ResponseBody;
import org.ruoyi.chat.enums.ChatModeType;
import org.ruoyi.chat.factory.ChatServiceFactory;
import org.ruoyi.chat.service.chat.IChatCostService;
import org.ruoyi.chat.service.chat.IChatService;
import org.ruoyi.chat.service.chat.ISseService;
import org.ruoyi.chat.util.IpUtil;
import org.ruoyi.chat.util.SSEUtil;
@@ -61,9 +63,7 @@
    private final IChatModelService chatModelService;
    private final OpenAIServiceImpl openAIService;
    private final OllamaServiceImpl ollamaService;
    private final ChatServiceFactory chatServiceFactory;
    private final IChatSessionService chatSessionService;
@@ -95,7 +95,8 @@
                chatCostService.deductToken(chatRequest);
            }
            // æ ¹æ®æ¨¡åž‹åˆ†ç±»è°ƒç”¨ä¸åŒçš„处理逻辑
            switchModelAndHandle(chatRequest,sseEmitter);
            IChatService chatService = chatServiceFactory.getChatService(chatModelVo.getCategory());
            chatService.chat(chatRequest, sseEmitter);
        } catch (Exception e) {
            log.error(e.getMessage(),e);
            SSEUtil.sendErrorEvent(sseEmitter,e.getMessage());
@@ -147,17 +148,6 @@
            }
    }
    /**
     *  æ ¹æ®æ¨¡åž‹åç§°å‰ç¼€è°ƒç”¨ä¸åŒçš„处理逻辑
     */
    private void switchModelAndHandle(ChatRequest chatRequest,SseEmitter emitter) {
        // è°ƒç”¨ollama中部署的本地模型
        if (ChatModeType.OLLAMA.getCode().equals(chatModelVo.getCategory())) {
            ollamaService.chat(chatRequest,emitter);
        } else {
            openAIService.chat(chatRequest,emitter);
        }
    }
    /**
     *  æž„建消息列表
ruoyi-modules/ruoyi-wechat/src/main/java/org/ruoyi/service/VxLoginService.java
@@ -26,7 +26,7 @@
import java.util.UUID;
/**
 * æè¿°ï¼šå¾®ä¿¡å…¬ä¼—号登录
 *  å¾®ä¿¡å…¬ä¼—号登录
 *
 * @author ageerle@163.com
 * date 2025/4/30
script/sql/update/20250509.sql
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,4 @@
ALTER TABLE `chat_model`
    ADD COLUMN `api_url` varchar(50) NULL COMMENT '请求后缀' AFTER `api_key`;
INSERT INTO `chat_config` (`id`, `category`, `config_name`, `config_value`, `config_dict`, `create_dept`, `create_time`, `create_by`, `update_by`, `update_time`, `remark`, `version`, `del_flag`, `update_ip`, `tenant_id`) VALUES (1779450794872414211, 'chat', 'apiUrl', 'v1/chat/completions', 'API è¯·æ±‚后缀', 103, '2024-04-14 18:05:05', '1', '1', '2025-04-23 22:29:04', NULL, NULL, '0', NULL, 0);