mirror of
https://gitcode.com/ageerle/ruoyi-ai.git
synced 2026-04-17 13:53:41 +00:00
Compare commits
8 Commits
f5daa7eb78
...
4d8eb1850f
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4d8eb1850f | ||
|
|
5aaa3a5662 | ||
|
|
8fec96f5b2 | ||
|
|
15c306eca2 | ||
|
|
620ea1fc76 | ||
|
|
c5c375dc6d | ||
|
|
1b793e822a | ||
|
|
6281840f36 |
@@ -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>
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -65,7 +65,6 @@ public class ChatModelBo extends BaseEntity {
|
|||||||
/**
|
/**
|
||||||
* 系统提示词
|
* 系统提示词
|
||||||
*/
|
*/
|
||||||
@NotBlank(message = "系统提示词不能为空", groups = { AddGroup.class, EditGroup.class })
|
|
||||||
private String systemPrompt;
|
private String systemPrompt;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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()+
|
||||||
"#注意:回复之前注意结合上下文内容。 ";
|
"#注意:回复之前注意结合上下文和工具返回内容。";
|
||||||
|
|
||||||
}
|
}
|
||||||
// 设置系统默认提示词
|
// 设置系统默认提示词
|
||||||
|
|||||||
@@ -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 返回的嵌入数据
|
||||||
|
|||||||
@@ -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');
|
||||||
|
|||||||
Reference in New Issue
Block a user