8 Commits

Author SHA1 Message Date
ageer
4d8eb1850f feat: 附件上传逻辑调整 2025-04-22 21:43:40 +08:00
ageer
5aaa3a5662 fix: 1. 修复No static resource tool/gen/list. 2. 修复新增数据库校验异常 2025-04-22 21:24:00 +08:00
ageerle
8fec96f5b2 feat: 默认关闭mcp功能 2025-04-22 18:01:40 +08:00
ageerle
15c306eca2 fix: 根据不同的模型构建对话客户端 2025-04-22 11:28:10 +08:00
ageerle
620ea1fc76 fix: 系统提示词非必填 2025-04-22 11:06:38 +08:00
ageerle
c5c375dc6d fix: 扣费时无法获取用户id 2025-04-22 10:43:54 +08:00
ageerle
1b793e822a fix: 扣费时无法获取用户id 2025-04-22 10:40:36 +08:00
ageerle
6281840f36 fix: 修复后台管理系统登录异常 2025-04-22 09:12:56 +08:00
10 changed files with 35 additions and 33 deletions

View File

@@ -42,12 +42,6 @@
<artifactId>mssql-jdbc</artifactId> <artifactId>mssql-jdbc</artifactId>
</dependency> </dependency>
<!-- demo模块 -->
<!-- <dependency>-->
<!-- <groupId>org.ruoyi</groupId>-->
<!-- <artifactId>ruoyi-demo</artifactId>-->
<!-- </dependency>-->
<dependency> <dependency>
<groupId>org.ruoyi</groupId> <groupId>org.ruoyi</groupId>
<artifactId>ruoyi-system</artifactId> <artifactId>ruoyi-system</artifactId>
@@ -58,6 +52,12 @@
<artifactId>ruoyi-chat</artifactId> <artifactId>ruoyi-chat</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.ruoyi</groupId>
<artifactId>ruoyi-generator</artifactId>
</dependency>
</dependencies> </dependencies>
<build> <build>

View File

@@ -63,6 +63,8 @@ public class AuthController {
body.getUsername(), body.getPassword(), body.getUsername(), body.getPassword(),
body.getCode(), body.getUuid()); body.getCode(), body.getUuid());
loginVo.setToken(token); loginVo.setToken(token);
// 兼容后台管理登录
loginVo.setAccess_token(token);
loginVo.setUserInfo(LoginHelper.getLoginUser()); loginVo.setUserInfo(LoginHelper.getLoginUser());
return R.ok(loginVo); return R.ok(loginVo);
} }

View File

@@ -327,7 +327,7 @@ spring:
base-url: https://api.pandarobot.chat/ base-url: https://api.pandarobot.chat/
mcp: mcp:
client: client:
enabled: true enabled: false
name: ruoyi-ai-mcp name: ruoyi-ai-mcp
sse: sse:
connections: connections:

View File

@@ -65,7 +65,6 @@ public class ChatModelBo extends BaseEntity {
/** /**
* 系统提示词 * 系统提示词
*/ */
@NotBlank(message = "系统提示词不能为空", groups = { AddGroup.class, EditGroup.class })
private String systemPrompt; private String systemPrompt;
/** /**

View File

@@ -21,7 +21,7 @@ import jakarta.validation.constraints.*;
public class KnowledgeInfoBo extends BaseEntity { public class KnowledgeInfoBo extends BaseEntity {
/** /**
* * 主键
*/ */
@NotNull(message = "不能为空", groups = { EditGroup.class }) @NotNull(message = "不能为空", groups = { EditGroup.class })
private Long id; private Long id;
@@ -29,13 +29,13 @@ public class KnowledgeInfoBo extends BaseEntity {
/** /**
* 知识库ID * 知识库ID
*/ */
@NotBlank(message = "知识库ID不能为空", groups = { AddGroup.class, EditGroup.class }) @NotBlank(message = "知识库ID不能为空", groups = {EditGroup.class })
private String kid; private String kid;
/** /**
* 用户ID * 用户ID
*/ */
@NotNull(message = "用户ID不能为空", groups = { AddGroup.class, EditGroup.class }) @NotNull(message = "用户ID不能为空", groups = {EditGroup.class })
private Long uid; private Long uid;
/** /**
@@ -53,25 +53,21 @@ public class KnowledgeInfoBo extends BaseEntity {
/** /**
* 描述 * 描述
*/ */
@NotBlank(message = "描述不能为空", groups = { AddGroup.class, EditGroup.class })
private String description; private String description;
/** /**
* 知识分隔符 * 知识分隔符
*/ */
@NotBlank(message = "知识分隔符不能为空", groups = { AddGroup.class, EditGroup.class })
private String knowledgeSeparator; private String knowledgeSeparator;
/** /**
* 提问分隔符 * 提问分隔符
*/ */
@NotBlank(message = "提问分隔符不能为空", groups = { AddGroup.class, EditGroup.class })
private String questionSeparator; private String questionSeparator;
/** /**
* 重叠字符数 * 重叠字符数
*/ */
@NotNull(message = "重叠字符数不能为空", groups = { AddGroup.class, EditGroup.class })
private Long overlapChar; private Long overlapChar;
/** /**
@@ -101,8 +97,6 @@ public class KnowledgeInfoBo extends BaseEntity {
/** /**
* 备注 * 备注
*/ */
@NotBlank(message = "备注不能为空", groups = { AddGroup.class, EditGroup.class })
private String remark; private String remark;
} }

View File

@@ -54,8 +54,14 @@ public class ChatCostServiceImpl implements IChatCostService {
ChatMessageBo chatMessageBo = new ChatMessageBo(); ChatMessageBo chatMessageBo = new ChatMessageBo();
Object userId = LocalCache.CACHE.get("userId");
if(userId!=null){
chatMessageBo.setUserId((Long) userId);
}else {
chatMessageBo.setUserId(getUserId());
}
// 计算总token数 // 计算总token数
ChatToken chatToken = chatTokenService.queryByUserId(getUserId(), modelName); ChatToken chatToken = chatTokenService.queryByUserId(chatMessageBo.getUserId(), modelName);
if (chatToken == null) { if (chatToken == null) {
chatToken = new ChatToken(); chatToken = new ChatToken();
chatToken.setToken(0); chatToken.setToken(0);
@@ -69,17 +75,17 @@ public class ChatCostServiceImpl implements IChatCostService {
if (token2 > 0) { if (token2 > 0) {
// 保存剩余tokens // 保存剩余tokens
chatToken.setModelName(modelName); chatToken.setModelName(modelName);
chatToken.setUserId(getUserId()); chatToken.setUserId(chatMessageBo.getUserId());
chatToken.setToken(token2); chatToken.setToken(token2);
chatTokenService.editToken(chatToken); chatTokenService.editToken(chatToken);
} else { } else {
chatTokenService.resetToken(getUserId(), modelName); chatTokenService.resetToken(chatMessageBo.getUserId(), modelName);
} }
ChatModelVo chatModelVo = chatModelService.selectModelByName(modelName); ChatModelVo chatModelVo = chatModelService.selectModelByName(modelName);
double cost = chatModelVo.getModelPrice(); double cost = chatModelVo.getModelPrice();
if (BillingType.TIMES.getCode().equals(chatModelVo.getModelType())) { if (BillingType.TIMES.getCode().equals(chatModelVo.getModelType())) {
// 按次数扣费 // 按次数扣费
deductUserBalance(getUserId(), cost); deductUserBalance(chatMessageBo.getUserId(), cost);
chatMessageBo.setDeductCost(cost); chatMessageBo.setDeductCost(cost);
}else { }else {
// 按token扣费 // 按token扣费
@@ -89,7 +95,7 @@ public class ChatCostServiceImpl implements IChatCostService {
} }
chatMessageBo.setContent(chatRequest.getPrompt()); chatMessageBo.setContent(chatRequest.getPrompt());
} else { } else {
deductUserBalance(getUserId(), 0.0); deductUserBalance(chatMessageBo.getUserId(), 0.0);
chatMessageBo.setDeductCost(0d); chatMessageBo.setDeductCost(0d);
chatMessageBo.setRemark("不满1kToken,计入下一次!"); chatMessageBo.setRemark("不满1kToken,计入下一次!");
chatToken.setToken(totalTokens); chatToken.setToken(totalTokens);
@@ -97,12 +103,6 @@ public class ChatCostServiceImpl implements IChatCostService {
chatToken.setUserId(chatMessageBo.getUserId()); chatToken.setUserId(chatMessageBo.getUserId());
chatTokenService.editToken(chatToken); chatTokenService.editToken(chatToken);
} }
Object userId = LocalCache.CACHE.get("userId");
if(userId!=null){
chatMessageBo.setUserId((Long) userId);
}else {
chatMessageBo.setUserId(getUserId());
}
// 保存消息记录 // 保存消息记录
chatMessageService.insertByBo(chatMessageBo); chatMessageService.insertByBo(chatMessageBo);
} }

View File

@@ -2,12 +2,15 @@ package org.ruoyi.chat.service.chat.impl;
import io.modelcontextprotocol.client.McpSyncClient; import io.modelcontextprotocol.client.McpSyncClient;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.ruoyi.chat.config.ChatConfig;
import org.ruoyi.chat.listener.SSEEventSourceListener; import org.ruoyi.chat.listener.SSEEventSourceListener;
import org.ruoyi.chat.service.chat.IChatService; import org.ruoyi.chat.service.chat.IChatService;
import org.ruoyi.common.chat.entity.chat.ChatCompletion; import org.ruoyi.common.chat.entity.chat.ChatCompletion;
import org.ruoyi.common.chat.entity.chat.Message; import org.ruoyi.common.chat.entity.chat.Message;
import org.ruoyi.common.chat.openai.OpenAiStreamClient; import org.ruoyi.common.chat.openai.OpenAiStreamClient;
import org.ruoyi.common.chat.request.ChatRequest; import org.ruoyi.common.chat.request.ChatRequest;
import org.ruoyi.domain.vo.ChatModelVo;
import org.ruoyi.service.IChatModelService;
import org.springframework.ai.chat.client.ChatClient; import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.mcp.SyncMcpToolCallbackProvider; import org.springframework.ai.mcp.SyncMcpToolCallbackProvider;
import org.springframework.ai.openai.OpenAiChatOptions; import org.springframework.ai.openai.OpenAiChatOptions;
@@ -22,6 +25,8 @@ import java.util.List;
public class OpenAIServiceImpl implements IChatService { public class OpenAIServiceImpl implements IChatService {
@Autowired @Autowired
private IChatModelService chatModelService;
private OpenAiStreamClient openAiStreamClient; private OpenAiStreamClient openAiStreamClient;
private final ChatClient chatClient; private final ChatClient chatClient;
@@ -36,6 +41,8 @@ public class OpenAIServiceImpl implements IChatService {
@Override @Override
public SseEmitter chat(ChatRequest chatRequest,SseEmitter emitter) { public SseEmitter chat(ChatRequest chatRequest,SseEmitter emitter) {
ChatModelVo chatModelVo = chatModelService.selectModelByName(chatRequest.getModel());
openAiStreamClient = ChatConfig.createOpenAiStreamClient(chatModelVo.getApiHost(), chatModelVo.getApiKey());
String toolString = mcpChat(chatRequest.getPrompt()); String toolString = mcpChat(chatRequest.getPrompt());
Message userMessage = Message.builder().content("工具返回信息:"+toolString).role(Message.Role.USER).build(); Message userMessage = Message.builder().content("工具返回信息:"+toolString).role(Message.Role.USER).build();
List<Message> messages = chatRequest.getMessages(); List<Message> messages = chatRequest.getMessages();

View File

@@ -71,9 +71,9 @@ public class SseServiceImpl implements ISseService {
@Override @Override
public SseEmitter sseChat(ChatRequest chatRequest, HttpServletRequest request) { public SseEmitter sseChat(ChatRequest chatRequest, HttpServletRequest request) {
SseEmitter sseEmitter = new SseEmitter(); SseEmitter sseEmitter = new SseEmitter(0L);
try { try {
// 构建消息列表增加联网、知识库等内容 // 构建消息列表
buildChatMessageList(chatRequest); buildChatMessageList(chatRequest);
if (!StpUtil.isLogin()) { if (!StpUtil.isLogin()) {
// 未登录用户限制对话次数 // 未登录用户限制对话次数
@@ -145,7 +145,7 @@ public class SseServiceImpl implements ISseService {
if(StringUtils.isEmpty(sysPrompt)){ if(StringUtils.isEmpty(sysPrompt)){
sysPrompt ="你是一个由RuoYI-AI开发的人工智能助手名字叫熊猫助手。你擅长中英文对话能够理解并处理各种问题提供安全、有帮助、准确的回答。" + sysPrompt ="你是一个由RuoYI-AI开发的人工智能助手名字叫熊猫助手。你擅长中英文对话能够理解并处理各种问题提供安全、有帮助、准确的回答。" +
"当前时间:"+ DateUtils.getDate()+ "当前时间:"+ DateUtils.getDate()+
"#注意:回复之前注意结合上下文内容。 "; "#注意:回复之前注意结合上下文和工具返回内容。";
} }
// 设置系统默认提示词 // 设置系统默认提示词

View File

@@ -53,7 +53,7 @@ public class OpenAiVectorizationImpl implements VectorizationService {
ChatModelVo chatModelVo = chatModelService.selectModelByName(knowledgeInfoVo.getVectorModel()); ChatModelVo chatModelVo = chatModelService.selectModelByName(knowledgeInfoVo.getVectorModel());
String apiHost= chatModelVo.getApiHost(); String apiHost= chatModelVo.getApiHost();
String apiKey= chatModelVo.getApiKey(); String apiKey= chatModelVo.getApiKey();
openAiStreamClient = chatConfig.createOpenAiStreamClient(apiHost,apiKey); openAiStreamClient = ChatConfig.createOpenAiStreamClient(apiHost,apiKey);
Embedding embedding = buildEmbedding(chunkList, knowledgeInfoVo); Embedding embedding = buildEmbedding(chunkList, knowledgeInfoVo);
EmbeddingResponse embeddings = openAiStreamClient.embeddings(embedding); EmbeddingResponse embeddings = openAiStreamClient.embeddings(embedding);
// 处理 OpenAI 返回的嵌入数据 // 处理 OpenAI 返回的嵌入数据

View File

@@ -1,4 +1,4 @@
INSERT INTO `chat_model` (`id`, `tenant_id`, `category`, `model_name`, `model_describe`, `model_price`, `model_type`, `model_show`, `system_prompt`, `api_host`, `api_key`, `create_dept`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (1907575746601119746, '000000', 'vector', 'text-embedding-3-small', 'text-embedding-3-small', 0, '2', '0', NULL, 'https://api.pandarobot.chat/', 'sk-cdBlIaZcufccm2RaDe547cBd054d49C7B0782eCa72A0052b', 103, 1, '2025-04-03 07:27:54', 1, '2025-04-03 07:27:54', 'text-embedding-3-small'); INSERT INTO `chat_model` (`id`, `tenant_id`, `category`, `model_name`, `model_describe`, `model_price`, `model_type`, `model_show`, `system_prompt`, `api_host`, `api_key`, `create_dept`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (1907575746601119746, '000000', 'vector', 'text-embedding-3-small', 'text-embedding-3-small', 0, '2', '0', NULL, 'https://api.pandarobot.chat/', 'sk-cdBlIaZcufccm2RaDe547cBd054d49C7B0782eCa72A0052b', 103, 1, '2025-04-03 07:27:54', 1, '2025-04-03 07:27:54', 'text-embedding-3-small');
INSERT INTO `chat_model` (`id`, `tenant_id`, `category`, `model_name`, `model_describe`, `model_price`, `model_type`, `model_show`, `system_prompt`, `api_host`, `api_key`, `create_dept`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (1907576007017066497, '000000', 'vector', 'quentinz/bge-large-zh-v1.5', 'bge-large-zh-v1.5', 0, '2', '0', NULL, 'https://api.pandarobot.chat/', 'cdBlIaZcufccm2RaDe547cBd054d49C7B0782eCa72A0052b', 103, 1, '2025-04-03 07:28:56', 1, '2025-04-03 07:28:56', 'bge-large-zh-v1.5'); INSERT INTO `chat_model` (`id`, `tenant_id`, `category`, `model_name`, `model_describe`, `model_price`, `model_type`, `model_show`, `system_prompt`, `api_host`, `api_key`, `create_dept`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (1907576007017066497, '000000', 'vector', 'quentinz/bge-large-zh-v1.5', 'bge-large-zh-v1.5', 0, '2', '0', NULL, 'http://127.0.0.1:11434/', 'cdBlIaZcufccm2RaDe547cBd054d49C7B0782eCa72A0052b', 103, 1, '2025-04-03 07:28:56', 1, '2025-04-03 07:28:56', 'bge-large-zh-v1.5');
INSERT INTO `chat_model` (`id`, `tenant_id`, `category`, `model_name`, `model_describe`, `model_price`, `model_type`, `model_show`, `system_prompt`, `api_host`, `api_key`, `create_dept`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (1907576806191362049, '000000', 'vector', 'nomic-embed-text', 'nomic-embed-text', 0, '2', '0', NULL, 'http://127.0.0.1:11434/', 'nomic-embed-text', 103, 1, '2025-04-03 07:32:06', 1, '2025-04-03 07:32:06', 'nomic-embed-text'); INSERT INTO `chat_model` (`id`, `tenant_id`, `category`, `model_name`, `model_describe`, `model_price`, `model_type`, `model_show`, `system_prompt`, `api_host`, `api_key`, `create_dept`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (1907576806191362049, '000000', 'vector', 'nomic-embed-text', 'nomic-embed-text', 0, '2', '0', NULL, 'http://127.0.0.1:11434/', 'nomic-embed-text', 103, 1, '2025-04-03 07:32:06', 1, '2025-04-03 07:32:06', 'nomic-embed-text');
INSERT INTO `chat_model` (`id`, `tenant_id`, `category`, `model_name`, `model_describe`, `model_price`, `model_type`, `model_show`, `system_prompt`, `api_host`, `api_key`, `create_dept`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (1907577073490161665, '000000', 'vector', 'snowflake-arctic-embed', 'snowflake-arctic-embed', 0, '2', '0', NULL, 'http://127.0.0.1:11434/', 'snowflake-arctic-embed', 103, 1, '2025-04-03 07:33:10', 1, '2025-04-03 07:33:10', 'snowflake-arctic-embed'); INSERT INTO `chat_model` (`id`, `tenant_id`, `category`, `model_name`, `model_describe`, `model_price`, `model_type`, `model_show`, `system_prompt`, `api_host`, `api_key`, `create_dept`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (1907577073490161665, '000000', 'vector', 'snowflake-arctic-embed', 'snowflake-arctic-embed', 0, '2', '0', NULL, 'http://127.0.0.1:11434/', 'snowflake-arctic-embed', 103, 1, '2025-04-03 07:33:10', 1, '2025-04-03 07:33:10', 'snowflake-arctic-embed');