feat:数据库持久化

This commit is contained in:
Ttt
2026-03-13 22:56:19 +08:00
parent d00e3ce11e
commit fa93d4ffe0
13 changed files with 215 additions and 12 deletions

14
pom.xml
View File

@@ -29,7 +29,7 @@
<encoding>UTF-8</encoding>
<guava.version>16.0.1</guava.version>
<mybatis-spring-boot.version>2.3.1</mybatis-spring-boot.version>
<mybatis-plus-spring-boot.version>3.5.14</mybatis-plus-spring-boot.version>
<mybatis-plus-spring-boot.version>3.5.5</mybatis-plus-spring-boot.version>
<mysql.version>8.0.33</mysql.version>
<lombok.version>1.18.30</lombok.version>
<spring-data-redis.version>3.23.6</spring-data-redis.version>
@@ -118,6 +118,11 @@
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
<version>${mybatis-plus-spring-boot.version}</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
@@ -141,6 +146,13 @@
<version>3.15.0</version>
</dependency>
<!-- JSON -->
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
<version>2.0.51</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>

View File

@@ -1,8 +1,8 @@
spring:
datasource:
url: jdbc:mysql://rm-bp15t34gqx62jm069ro.mysql.rds.aliyuncs.com:3306/xservice-ai-center?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&allowMultiQueries=true
url: jdbc:mysql://120.27.153.87:3306/xe-service-ai?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&allowMultiQueries=true
username: root
password: xb#UWqnhH24&XpX
password: sdkljfikdfn@123
driver-class-name: com.mysql.cj.jdbc.Driver
ai:

View File

@@ -5,6 +5,11 @@ spring:
profiles:
active: local
cloud:
nacos:
config:
import-check:
enabled: false
server:
port: 38020
@@ -14,4 +19,9 @@ server:
charset: UTF-8
enabled: true
force: true
mybatis:
mapper-locations:
- classpath*:mapper/*/*.xml
configuration:
map-underscore-to-camel-case: true

View File

@@ -9,7 +9,9 @@ import com.xiang.xservice.ai.core.enums.ModelStrategyEnum;
import com.xiang.xservice.ai.core.enums.ModelTypeEnum;
import com.xiang.xservice.ai.core.handler.MyStreamingHandler;
import com.xiang.xservice.ai.core.route.TaskRouter;
import com.xiang.xservice.ai.core.storage.DbPersistentStore;
import com.xiang.xservice.ai.core.storage.MemoryPersistentStore;
import com.xiang.xservice.ai.repository.manage.IAiSimpleChatMessageManage;
import dev.langchain4j.data.message.SystemMessage;
import dev.langchain4j.data.message.UserMessage;
import dev.langchain4j.memory.chat.ChatMemoryProvider;
@@ -26,12 +28,13 @@ public class SimpleChatAgent implements BaseAgent {
private final TaskRouter router;
private final OpenAIBaseConfig openAIBaseConfig;
private final IAiSimpleChatMessageManage aiSimpleChatMessageManage;
@Override
public void chat(ModelTypeEnum modelType, Long id, String message) {
MemoryPersistentStore store = new MemoryPersistentStore();
DbPersistentStore store = new DbPersistentStore(aiSimpleChatMessageManage);
ChatMemoryProvider chatMemoryProvider = memoryId -> MessageWindowChatMemory.builder()
.id(memoryId)

View File

@@ -3,7 +3,6 @@ package com.xiang.xservice.ai.core.handler;
import dev.langchain4j.model.StreamingResponseHandler;
import dev.langchain4j.model.chat.response.ChatResponse;
import dev.langchain4j.model.chat.response.StreamingChatResponseHandler;
import org.checkerframework.checker.units.qual.C;
import org.springframework.stereotype.Component;
@Component

View File

@@ -3,15 +3,12 @@ package com.xiang.xservice.ai.core.route;
import com.xiang.xservice.ai.core.entity.ModelConfig;
import com.xiang.xservice.ai.core.enums.ModelStrategyEnum;
import com.xiang.xservice.ai.core.provider.BaseProvider;
import dev.langchain4j.model.chat.ChatModel;
import dev.langchain4j.model.chat.StreamingChatModel;
import org.checkerframework.checker.units.qual.C;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Component
public class TaskRouter {

View File

@@ -1,23 +1,97 @@
package com.xiang.xservice.ai.core.storage;
import dev.langchain4j.data.message.ChatMessage;
import com.alibaba.fastjson2.JSON;
import com.google.common.collect.Lists;
import com.xiang.xservice.ai.pojo.entity.AiSimpleChatMessageDO;
import com.xiang.xservice.ai.repository.manage.IAiSimpleChatMessageManage;
import dev.langchain4j.data.message.*;
import dev.langchain4j.store.memory.chat.ChatMemoryStore;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.util.List;
/**
* 数据库持久化
*/
@RequiredArgsConstructor
public class DbPersistentStore implements ChatMemoryStore {
private final IAiSimpleChatMessageManage aiSimpleChatMessageManage;
@Override
public List<ChatMessage> getMessages(Object memoryId) {
return List.of();
List<AiSimpleChatMessageDO> msg = aiSimpleChatMessageManage.getMsgByMemoryId((Long) memoryId);
if (CollectionUtils.isEmpty(msg)) {
return Lists.newArrayList();
}
List<ChatMessage> result = Lists.newArrayList();
for (AiSimpleChatMessageDO chatMessageDO : msg) {
String role = chatMessageDO.getRole();
switch (role) {
case "SYSTEM":
result.add(SystemMessage.from(chatMessageDO.getMessage()));
break;
case "USER":
result.add(UserMessage.from(chatMessageDO.getMessage()));
break;
case "AI":
result.add(AiMessage.from(chatMessageDO.getMessage()));
break;
default:
break;
}
}
return result;
}
@Override
public void updateMessages(Object memoryId, List<ChatMessage> list) {
List<AiSimpleChatMessageDO> result = Lists.newArrayList();
for (ChatMessage chatMessage : list) {
StringBuilder str = new StringBuilder();
String type = "";
if (chatMessage instanceof SystemMessage systemMessage) {
str = new StringBuilder(systemMessage.text());
type = "SYSTEM";
}
if (chatMessage instanceof UserMessage userMessage) {
for (Content content : userMessage.contents()) {
if (content instanceof TextContent textContent) {
str.append(textContent.text());
type = "USER";
}
}
}
if (chatMessage instanceof AiMessage aiMessage) {
str = new StringBuilder(aiMessage.text());
type = "AI";
}
AiSimpleChatMessageDO message = AiSimpleChatMessageDO.builder()
.userId(1L)
.memoryId((Long) memoryId)
.message(str.toString())
.createTime(LocalDateTime.now())
.delFlag(0)
.role(type)
.build();
result.add(message);
}
aiSimpleChatMessageManage.saveBatch(result);
}
@Override
public void deleteMessages(Object memoryId) {
aiSimpleChatMessageManage.deleteByMemoryId((Long) memoryId);
}
}

View File

@@ -8,9 +8,12 @@ import dev.langchain4j.store.memory.chat.ChatMemoryStore;
import java.util.List;
import java.util.Map;
/**
* 内存持久化
*/
public class MemoryPersistentStore implements ChatMemoryStore {
private static Map<Long, List<ChatMessage>> MAP = Maps.newHashMap();
private final static Map<Long, List<ChatMessage>> MAP = Maps.newHashMap();
@Override

View File

@@ -0,0 +1,24 @@
package com.xiang.xservice.ai.pojo.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;
@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("ai_simple_chat_message")
@Builder
public class AiSimpleChatMessageDO {
private Long id;
private Long userId;
private Long memoryId;
private String role;
private String message;
private LocalDateTime createTime;
private Integer delFlag;
}

View File

@@ -0,0 +1,26 @@
package com.xiang.xservice.ai.repository.manage;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xiang.xservice.ai.pojo.entity.AiSimpleChatMessageDO;
import com.xiang.xservice.ai.repository.mapper.IAiSimpleChatMessageMapper;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class AiSimpleChatMessageManageImpl extends ServiceImpl<IAiSimpleChatMessageMapper, AiSimpleChatMessageDO> implements IAiSimpleChatMessageManage {
@Override
public List<AiSimpleChatMessageDO> getMsgByMemoryId(Long memoryId) {
LambdaQueryWrapper<AiSimpleChatMessageDO> lambdaQueryWrapper = Wrappers.lambdaQuery();
lambdaQueryWrapper.eq(AiSimpleChatMessageDO::getMemoryId, memoryId);
lambdaQueryWrapper.eq(AiSimpleChatMessageDO::getDelFlag, 0);
return baseMapper.selectList(lambdaQueryWrapper);
}
@Override
public boolean deleteByMemoryId(Long memoryId) {
return baseMapper.deleteByMemoryId(memoryId) > 0;
}
}

View File

@@ -0,0 +1,11 @@
package com.xiang.xservice.ai.repository.manage;
import com.baomidou.mybatisplus.extension.service.IService;
import com.xiang.xservice.ai.pojo.entity.AiSimpleChatMessageDO;
import java.util.List;
public interface IAiSimpleChatMessageManage extends IService<AiSimpleChatMessageDO> {
List<AiSimpleChatMessageDO> getMsgByMemoryId(Long memoryId);
boolean deleteByMemoryId(Long memoryId);
}

View File

@@ -0,0 +1,14 @@
package com.xiang.xservice.ai.repository.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.xiang.xservice.ai.pojo.entity.AiSimpleChatMessageDO;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;
@Mapper
@Repository
public interface IAiSimpleChatMessageMapper extends BaseMapper<AiSimpleChatMessageDO> {
int deleteByMemoryId(@Param("id") Long memoryId);
}

View File

@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xiang.dao.AiSimpleChatMessageMapper">
<resultMap id="BaseResultMap" type="com.xiang.xservice.ai.pojo.entity.AiSimpleChatMessageDO">
<result column="id" property="id"/>
<result column="memory_id" property="memoryId"/>
<result column="role" property="role"/>
<result column="message" property="message"/>
<result column="create_time" property="createTime"/>
<result column="user_id" property="userId"/>
<result column="del_flag" property="delFlag"/>
</resultMap>
<sql id="Base_Column_List">
id,
memory_id,
role,
message,
create_time,
user_id,
del_flag
</sql>
<update id="deleteByMemoryId">
update ai_simple_chat_message set del_flag = 1 where memory_id = #{id}
</update>
</mapper>