first commit
This commit is contained in:
33
.gitignore
vendored
Normal file
33
.gitignore
vendored
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
HELP.md
|
||||||
|
target/
|
||||||
|
.mvn/wrapper/maven-wrapper.jar
|
||||||
|
!**/src/main/**/target/
|
||||||
|
!**/src/test/**/target/
|
||||||
|
|
||||||
|
### STS ###
|
||||||
|
.apt_generated
|
||||||
|
.classpath
|
||||||
|
.factorypath
|
||||||
|
.project
|
||||||
|
.settings
|
||||||
|
.springBeans
|
||||||
|
.sts4-cache
|
||||||
|
|
||||||
|
### IntelliJ IDEA ###
|
||||||
|
.idea
|
||||||
|
*.iws
|
||||||
|
*.iml
|
||||||
|
*.ipr
|
||||||
|
|
||||||
|
### NetBeans ###
|
||||||
|
/nbproject/private/
|
||||||
|
/nbbuild/
|
||||||
|
/dist/
|
||||||
|
/nbdist/
|
||||||
|
/.nb-gradle/
|
||||||
|
build/
|
||||||
|
!**/src/main/**/build/
|
||||||
|
!**/src/test/**/build/
|
||||||
|
|
||||||
|
### VS Code ###
|
||||||
|
.vscode/
|
||||||
104
pom.xml
Normal file
104
pom.xml
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-parent</artifactId>
|
||||||
|
<version>3.5.5</version>
|
||||||
|
<relativePath/> <!-- lookup parent from repository -->
|
||||||
|
</parent>
|
||||||
|
<groupId>com.ai</groupId>
|
||||||
|
<artifactId>spring_ai_app</artifactId>
|
||||||
|
<version>1.0.0</version>
|
||||||
|
<name>spring_ai_app</name>
|
||||||
|
<description>spring_ai_app</description>
|
||||||
|
<properties>
|
||||||
|
<java.version>21</java.version>
|
||||||
|
<!-- spring ai 正式版-->
|
||||||
|
<spring.ai.bom>1.0.1</spring.ai.bom>
|
||||||
|
</properties>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<!-- deepseek模型自动配置-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.ai</groupId>
|
||||||
|
<artifactId>spring-ai-starter-model-deepseek</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-data-redis</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- mybatis -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.baomidou</groupId>
|
||||||
|
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
|
||||||
|
<version>3.5.5</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.baomidou</groupId>
|
||||||
|
<artifactId>mybatis-plus-generator</artifactId>
|
||||||
|
<version>3.5.5</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- 数据库驱动 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>mysql</groupId>
|
||||||
|
<artifactId>mysql-connector-java</artifactId>
|
||||||
|
<version>8.0.17</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok</artifactId>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba</groupId>
|
||||||
|
<artifactId>fastjson</artifactId>
|
||||||
|
<version>1.2.83</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.commons</groupId>
|
||||||
|
<artifactId>commons-lang3</artifactId>
|
||||||
|
<version>3.18.0</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<dependencyManagement>
|
||||||
|
<dependencies>
|
||||||
|
<!-- spring ai 版本管理-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.ai</groupId>
|
||||||
|
<artifactId>spring-ai-bom</artifactId>
|
||||||
|
<version>${spring.ai.bom}</version>
|
||||||
|
<type>pom</type>
|
||||||
|
<scope>import</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</dependencyManagement>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
</project>
|
||||||
13
src/main/java/com/ai/app/SpringAiAppApplication.java
Normal file
13
src/main/java/com/ai/app/SpringAiAppApplication.java
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
package com.ai.app;
|
||||||
|
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
|
||||||
|
@SpringBootApplication
|
||||||
|
public class SpringAiAppApplication {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(SpringAiAppApplication.class, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
79
src/main/java/com/ai/app/config/AIConfig.java
Normal file
79
src/main/java/com/ai/app/config/AIConfig.java
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
package com.ai.app.config;
|
||||||
|
|
||||||
|
import org.springframework.ai.chat.client.ChatClient;
|
||||||
|
import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
|
||||||
|
import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor;
|
||||||
|
import org.springframework.ai.chat.memory.InMemoryChatMemoryRepository;
|
||||||
|
import org.springframework.ai.chat.memory.MessageWindowChatMemory;
|
||||||
|
import org.springframework.ai.deepseek.DeepSeekChatModel;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @describe ai配置类
|
||||||
|
* @Author kai.liu
|
||||||
|
* @Date 2025/8/28 10:02
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
public class AIConfig {
|
||||||
|
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public InMemoryChatMemoryRepository inMemoryChatMemoryRepository() {
|
||||||
|
return new InMemoryChatMemoryRepository();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public MessageWindowChatMemory messageWindowChatMemory(InMemoryChatMemoryRepository inMemoryChatMemoryRepository) {
|
||||||
|
return MessageWindowChatMemory.builder().chatMemoryRepository(inMemoryChatMemoryRepository).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 配置会话记忆环绕增强Advisor
|
||||||
|
*
|
||||||
|
* @param messageWindowChatMemory 消息窗口会话记忆
|
||||||
|
* @return: org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor
|
||||||
|
* @author kai.liu
|
||||||
|
* @date: 2025/8/29 9:05
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public MessageChatMemoryAdvisor messageChatMemoryAdvisor(MessageWindowChatMemory messageWindowChatMemory) {
|
||||||
|
return MessageChatMemoryAdvisor.builder(messageWindowChatMemory).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 配置日志环绕增强Advisor
|
||||||
|
*
|
||||||
|
* @return: org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor
|
||||||
|
* @author kai.liu
|
||||||
|
* @date: 2025/8/29 9:05
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public SimpleLoggerAdvisor simpleLoggerAdvisor() {
|
||||||
|
return new SimpleLoggerAdvisor();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 配置AI对话客户端
|
||||||
|
*
|
||||||
|
* @param deepSeekChatModel deepseek大模型
|
||||||
|
* @param simpleLoggerAdvisor 日志Advisor
|
||||||
|
* @param messageChatMemoryAdvisor 会话记忆Advisor
|
||||||
|
* @return: org.springframework.ai.chat.client.ChatClient
|
||||||
|
* @author kai.liu
|
||||||
|
* @date: 2025/8/29 9:06
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public ChatClient chatClient(DeepSeekChatModel deepSeekChatModel,
|
||||||
|
SimpleLoggerAdvisor simpleLoggerAdvisor,
|
||||||
|
MessageChatMemoryAdvisor messageChatMemoryAdvisor) {
|
||||||
|
return ChatClient
|
||||||
|
//模型
|
||||||
|
.builder(deepSeekChatModel)
|
||||||
|
//系统角色
|
||||||
|
.defaultSystem("你是一个小团团")
|
||||||
|
//环绕增强
|
||||||
|
.defaultAdvisors(simpleLoggerAdvisor, messageChatMemoryAdvisor)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
30
src/main/java/com/ai/app/config/CorsConfig.java
Normal file
30
src/main/java/com/ai/app/config/CorsConfig.java
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
package com.ai.app.config;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.web.servlet.config.annotation.CorsRegistry;
|
||||||
|
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 跨域配置
|
||||||
|
*
|
||||||
|
* @author shiyong
|
||||||
|
* 2022/10/24 16:23
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
public class CorsConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public WebMvcConfigurer corsConfigurer() {
|
||||||
|
return new WebMvcConfigurer() {
|
||||||
|
@Override
|
||||||
|
public void addCorsMappings(CorsRegistry registry) {
|
||||||
|
registry.addMapping("/**")
|
||||||
|
.allowedOrigins("*")
|
||||||
|
.allowedHeaders("*")
|
||||||
|
.allowedMethods("*")
|
||||||
|
.maxAge(3600);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
package com.ai.app.config;
|
||||||
|
|
||||||
|
import com.ai.app.service.AIChatMessageService;
|
||||||
|
import org.springframework.ai.chat.memory.ChatMemoryRepository;
|
||||||
|
import org.springframework.ai.chat.messages.Message;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @describe
|
||||||
|
* @Author kai.liu
|
||||||
|
* @Date 2025/8/29 9:01
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class RedisChatMemoryRepositor implements ChatMemoryRepository {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private AIChatMessageService aiChatMessageService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> findConversationIds() {
|
||||||
|
return aiChatMessageService.getConversationIds();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Message> findByConversationId(String conversationId) {
|
||||||
|
return aiChatMessageService.getMessage(conversationId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void saveAll(String conversationId, List<Message> messages) {
|
||||||
|
aiChatMessageService.saveAll(conversationId, messages);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteByConversationId(String conversationId) {
|
||||||
|
aiChatMessageService.delete(conversationId);
|
||||||
|
}
|
||||||
|
}
|
||||||
40
src/main/java/com/ai/app/config/RedisConfig.java
Normal file
40
src/main/java/com/ai/app/config/RedisConfig.java
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
package com.ai.app.config;
|
||||||
|
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||||
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
|
import org.springframework.data.redis.serializer.StringRedisSerializer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @describe
|
||||||
|
* @Author kai.liu
|
||||||
|
* @Date 2025/9/1 9:33
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
public class RedisConfig {
|
||||||
|
@Bean
|
||||||
|
@ConditionalOnMissingBean(name = "redisTemplate")
|
||||||
|
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
|
||||||
|
RedisTemplate<String, Object> template = new RedisTemplate<>();
|
||||||
|
template.setConnectionFactory(redisConnectionFactory);
|
||||||
|
|
||||||
|
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
|
||||||
|
RedisObjectSerializer redisObjectSerializer = new RedisObjectSerializer();
|
||||||
|
|
||||||
|
// key采用String的序列化方式
|
||||||
|
template.setKeySerializer(stringRedisSerializer);
|
||||||
|
|
||||||
|
// hash的key也采用String的序列化方式
|
||||||
|
template.setHashKeySerializer(stringRedisSerializer);
|
||||||
|
|
||||||
|
// value序列化方式采用字节数组
|
||||||
|
template.setValueSerializer(redisObjectSerializer);
|
||||||
|
|
||||||
|
// hash的value序列化方式采用字节数组
|
||||||
|
template.setHashValueSerializer(redisObjectSerializer);
|
||||||
|
template.afterPropertiesSet();
|
||||||
|
return template;
|
||||||
|
}
|
||||||
|
}
|
||||||
49
src/main/java/com/ai/app/config/RedisObjectSerializer.java
Normal file
49
src/main/java/com/ai/app/config/RedisObjectSerializer.java
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
package com.ai.app.config;
|
||||||
|
|
||||||
|
import org.springframework.core.convert.converter.Converter;
|
||||||
|
import org.springframework.core.serializer.support.DeserializingConverter;
|
||||||
|
import org.springframework.core.serializer.support.SerializingConverter;
|
||||||
|
import org.springframework.data.redis.serializer.RedisSerializer;
|
||||||
|
import org.springframework.data.redis.serializer.SerializationException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自定义Redis序列化类
|
||||||
|
*
|
||||||
|
* @author shiyong
|
||||||
|
* 2020-01-03 18:01
|
||||||
|
*/
|
||||||
|
public class RedisObjectSerializer implements RedisSerializer<Object> {
|
||||||
|
private Converter<Object, byte[]> serializer = new SerializingConverter();
|
||||||
|
private Converter<byte[], Object> deserializer = new DeserializingConverter();
|
||||||
|
static final byte[] EMPTY_ARRAY = new byte[0];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serialize the given object to binary data.
|
||||||
|
*
|
||||||
|
* @param o object to serialize. Can be {@literal null}.
|
||||||
|
* @return the equivalent binary data. Can be {@literal null}.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public byte[] serialize(Object o) throws SerializationException {
|
||||||
|
if (o == null) {
|
||||||
|
return EMPTY_ARRAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
return serializer.convert(o);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deserialize an object from the given binary data.
|
||||||
|
*
|
||||||
|
* @param bytes object binary representation. Can be {@literal null}.
|
||||||
|
* @return the equivalent object instance. Can be {@literal null}.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Object deserialize(byte[] bytes) throws SerializationException {
|
||||||
|
if (bytes == null || bytes.length <= 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return deserializer.convert(bytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
55
src/main/java/com/ai/app/controller/ChatController.java
Normal file
55
src/main/java/com/ai/app/controller/ChatController.java
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
package com.ai.app.controller;
|
||||||
|
|
||||||
|
import com.ai.app.dto.MessageDTO;
|
||||||
|
import com.ai.app.service.AIChatMessageService;
|
||||||
|
import org.springframework.ai.chat.client.ChatClient;
|
||||||
|
import org.springframework.ai.chat.memory.ChatMemory;
|
||||||
|
import org.springframework.ai.chat.memory.InMemoryChatMemoryRepository;
|
||||||
|
import org.springframework.ai.chat.messages.Message;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import reactor.core.publisher.Flux;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @describe AI对话控制器
|
||||||
|
* @Author kai.liu
|
||||||
|
* @Date 2025/8/28 10:06
|
||||||
|
*/
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/ai")
|
||||||
|
public class ChatController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ChatClient chatClient;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private InMemoryChatMemoryRepository inMemoryChatMemoryRepository;
|
||||||
|
|
||||||
|
@RequestMapping(value = "/chat", produces = "text/stream;charset=UTF-8")
|
||||||
|
public Flux<String> chat(String prompt, String chatId) {
|
||||||
|
return chatClient
|
||||||
|
.prompt()
|
||||||
|
.user(prompt)
|
||||||
|
.advisors(a -> a.param(ChatMemory.CONVERSATION_ID, chatId))
|
||||||
|
.stream().content();
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequestMapping("/history/chat")
|
||||||
|
public List<String> history() {
|
||||||
|
return inMemoryChatMemoryRepository.findConversationIds();
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequestMapping("/history/chat/{chatId}")
|
||||||
|
public List<MessageDTO> history(@PathVariable("chatId") String chatId) {
|
||||||
|
List<Message> messages = inMemoryChatMemoryRepository.findByConversationId(chatId);
|
||||||
|
return messages.stream().map(e -> {
|
||||||
|
return new MessageDTO(e.getMessageType().getValue(), e.getText());
|
||||||
|
}).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
}
|
||||||
23
src/main/java/com/ai/app/dto/MessageDTO.java
Normal file
23
src/main/java/com/ai/app/dto/MessageDTO.java
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
package com.ai.app.dto;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.NonNull;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @describe
|
||||||
|
* @Author kai.liu
|
||||||
|
* @Date 2025/8/29 15:09
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class MessageDTO implements Serializable {
|
||||||
|
|
||||||
|
private String role;
|
||||||
|
|
||||||
|
private String content;
|
||||||
|
}
|
||||||
30
src/main/java/com/ai/app/entity/AIChatMessage.java
Normal file
30
src/main/java/com/ai/app/entity/AIChatMessage.java
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
package com.ai.app.entity;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @describe
|
||||||
|
* @Author kai.liu
|
||||||
|
* @Date 2025/8/29 9:20
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@TableName("ai_chat_message")
|
||||||
|
public class AIChatMessage {
|
||||||
|
|
||||||
|
@TableId
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
private String conversationId;
|
||||||
|
|
||||||
|
private String conversationType;
|
||||||
|
|
||||||
|
private String messageType;
|
||||||
|
|
||||||
|
private String message;
|
||||||
|
|
||||||
|
private LocalDateTime createTime;
|
||||||
|
}
|
||||||
29
src/main/java/com/ai/app/mapper/AIChatMessageMapper.java
Normal file
29
src/main/java/com/ai/app/mapper/AIChatMessageMapper.java
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
package com.ai.app.mapper;
|
||||||
|
|
||||||
|
import com.ai.app.entity.AIChatMessage;
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import org.apache.ibatis.annotations.Insert;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
import org.apache.ibatis.annotations.Select;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @describe
|
||||||
|
* @Author kai.liu
|
||||||
|
* @Date 2025/8/29 9:18
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface AIChatMessageMapper extends BaseMapper<AIChatMessage> {
|
||||||
|
|
||||||
|
@Select("SELECT DISTINCT conversation_id FROM ai_chat_message ")
|
||||||
|
List<String> selectConversationIds();
|
||||||
|
|
||||||
|
@Select("SELECT * FROM ai_chat_message WHERE conversation_id = #{conversationId}")
|
||||||
|
List<AIChatMessage> selectByConversationId(String conversationId);
|
||||||
|
|
||||||
|
void batchInsert(List<AIChatMessage> messageList);
|
||||||
|
|
||||||
|
@Select("DELETE FROM ai_chat_message WHERE conversation_id = #{conversationId}")
|
||||||
|
void deleteByConversationId(String conversationId);
|
||||||
|
}
|
||||||
23
src/main/java/com/ai/app/service/AIChatMessageService.java
Normal file
23
src/main/java/com/ai/app/service/AIChatMessageService.java
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
package com.ai.app.service;
|
||||||
|
|
||||||
|
import org.springframework.ai.chat.messages.Message;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @describe
|
||||||
|
* @Author kai.liu
|
||||||
|
* @Date 2025/8/29 9:27
|
||||||
|
*/
|
||||||
|
public interface AIChatMessageService {
|
||||||
|
|
||||||
|
List<String> getConversationIds(String type);
|
||||||
|
|
||||||
|
List<String> getConversationIds();
|
||||||
|
|
||||||
|
List<Message> getMessage(String conversationId);
|
||||||
|
|
||||||
|
void saveAll(String conversationId, List<Message> messages);
|
||||||
|
|
||||||
|
void delete(String conversationId);
|
||||||
|
}
|
||||||
192
src/main/java/com/ai/app/service/RedisTemplateService.java
Normal file
192
src/main/java/com/ai/app/service/RedisTemplateService.java
Normal file
@@ -0,0 +1,192 @@
|
|||||||
|
package com.ai.app.service;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @describe
|
||||||
|
* @Author kai.liu
|
||||||
|
* @Date 2025/9/1 9:28
|
||||||
|
*/
|
||||||
|
public interface RedisTemplateService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 缓存对象信息
|
||||||
|
*
|
||||||
|
* @param key 键
|
||||||
|
* @param value 值
|
||||||
|
* @author 施勇
|
||||||
|
* 2018年12月11日 上午10:54:49
|
||||||
|
*/
|
||||||
|
void set(String key, Object value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 缓存信息,并设置缓存时间
|
||||||
|
*
|
||||||
|
* @param key 键
|
||||||
|
* @param value 值
|
||||||
|
* @param time 时间
|
||||||
|
* @param timeUnit 时间单位
|
||||||
|
* @author 施勇
|
||||||
|
* 2018年12月11日 上午10:54:27
|
||||||
|
*/
|
||||||
|
void set(String key, Object value, long time, TimeUnit timeUnit);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 原子递增1
|
||||||
|
*
|
||||||
|
* @param key 键
|
||||||
|
* @return java.lang.Long
|
||||||
|
*/
|
||||||
|
Long increment(String key);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 原子递增
|
||||||
|
*
|
||||||
|
* @param key 键
|
||||||
|
* @param delta 增量
|
||||||
|
* @return java.lang.Long
|
||||||
|
*/
|
||||||
|
Long increment(String key, Long delta);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 递增
|
||||||
|
*
|
||||||
|
* @param key 键
|
||||||
|
* @param delta 递增因子
|
||||||
|
* @param time 时间
|
||||||
|
* @param timeUnit 时间单位
|
||||||
|
* @return java.lang.Long
|
||||||
|
* @author shiyong
|
||||||
|
* 2022/10/18 14:58
|
||||||
|
*/
|
||||||
|
Long increment(String key, Long delta, long time, TimeUnit timeUnit);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从缓存中获取信息
|
||||||
|
*
|
||||||
|
* @param key 键
|
||||||
|
* @return Object
|
||||||
|
* @author 施勇
|
||||||
|
* 2018年12月11日 上午10:54:10
|
||||||
|
*/
|
||||||
|
Object get(Object key);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从redis中获取key对应的过期时间;
|
||||||
|
* 如果该值有过期时间,就返回相应的过期时间;
|
||||||
|
* 如果该值没有设置过期时间,就返回-1;
|
||||||
|
* 如果没有该值,就返回-2;
|
||||||
|
*/
|
||||||
|
Long getExpire(String key);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置key的失效时间
|
||||||
|
*
|
||||||
|
* @param key 键
|
||||||
|
* @param time 时长
|
||||||
|
* @param timeUnit 时间单位
|
||||||
|
* @return java.lang.Boolean
|
||||||
|
*/
|
||||||
|
Boolean expire(String key, long time, TimeUnit timeUnit);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否存在key
|
||||||
|
*
|
||||||
|
* @param key 键
|
||||||
|
* @return boolean
|
||||||
|
* @author 施勇
|
||||||
|
* 2018年12月11日 上午10:53:54
|
||||||
|
*/
|
||||||
|
boolean hasKey(String key);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除KEY对应的对象
|
||||||
|
*
|
||||||
|
* @param key 键
|
||||||
|
* @author 施勇
|
||||||
|
* 2018年12月24日 下午4:14:26
|
||||||
|
*/
|
||||||
|
void delete(String key);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查找匹配的key
|
||||||
|
*
|
||||||
|
* @param pattern 匹配字符串
|
||||||
|
* @return java.util.Set<java.lang.String>
|
||||||
|
* @author shiyong
|
||||||
|
* 2020/1/3 13:42
|
||||||
|
*/
|
||||||
|
Set<String> getKeys(String pattern);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 在队尾追加元素
|
||||||
|
*
|
||||||
|
* @param key 键
|
||||||
|
* @param value 值
|
||||||
|
* @return 添加后队列的长度
|
||||||
|
*/
|
||||||
|
Long rightPush(String key, Object value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从队首移除元素
|
||||||
|
*
|
||||||
|
* @param key 键
|
||||||
|
* @return 移除的元素
|
||||||
|
*/
|
||||||
|
Object leftPop(String key);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从队首开始取值,获取指定区间
|
||||||
|
*
|
||||||
|
* @param key 键
|
||||||
|
* @param start 开始下标
|
||||||
|
* @param stop 结束下标
|
||||||
|
* @return 区间内的全部值
|
||||||
|
*/
|
||||||
|
List<?> leftRange(String key, long start, long stop);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将值加到集合中
|
||||||
|
*
|
||||||
|
* @param key 键
|
||||||
|
* @param values 值
|
||||||
|
* @return 添加是否成功(1:成功,0:失败)
|
||||||
|
*/
|
||||||
|
Long addToSet(String key, Object... values);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 集合的数量
|
||||||
|
*
|
||||||
|
* @param key 键
|
||||||
|
* @return 集合数量
|
||||||
|
*/
|
||||||
|
Long sizeOfSet(String key);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 集合列表
|
||||||
|
*
|
||||||
|
* @param key 键
|
||||||
|
* @return 集合列表
|
||||||
|
*/
|
||||||
|
Set<Object> getOfSet(String key);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 集合中是否有该值
|
||||||
|
*
|
||||||
|
* @param key 键
|
||||||
|
* @param value 值
|
||||||
|
* @return Boolean
|
||||||
|
*/
|
||||||
|
Boolean hasOfSet(String key, Object value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除集合中值
|
||||||
|
*
|
||||||
|
* @param key 键
|
||||||
|
* @param value 值
|
||||||
|
* @return 删除是否成功(1:成功,0:失败)
|
||||||
|
*/
|
||||||
|
Long removeOfSet(String key, Object value);
|
||||||
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
package com.ai.app.service.impl;
|
||||||
|
|
||||||
|
import com.ai.app.service.AIChatMessageService;
|
||||||
|
import com.ai.app.service.RedisTemplateService;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.ai.chat.messages.Message;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @describe
|
||||||
|
* @Author kai.liu
|
||||||
|
* @Date 2025/8/29 9:27
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
public class AIChatMessageServiceImpl implements AIChatMessageService {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private RedisTemplateService redisTemplateService;
|
||||||
|
|
||||||
|
public static final String AI_MESSAGE_CONVERSATION_ID = "ai:message:conversationId:";
|
||||||
|
public static final String AI_MESSAGE_CONVERSATION_TYPE = "ai:message:conversationType:";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> getConversationIds(String type) {
|
||||||
|
String conversationTypeKey = getConversationTypeKey(type);
|
||||||
|
if (redisTemplateService.hasKey(conversationTypeKey)) {
|
||||||
|
return (List<String>) redisTemplateService.get(conversationTypeKey);
|
||||||
|
}
|
||||||
|
return List.of();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> getConversationIds() {
|
||||||
|
Set<String> keys = redisTemplateService.getKeys(AI_MESSAGE_CONVERSATION_ID);
|
||||||
|
return new ArrayList<>(keys);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Message> getMessage(String conversationId) {
|
||||||
|
String conversationIdKey = getConversationIdKey(conversationId);
|
||||||
|
if (redisTemplateService.hasKey(conversationIdKey)) {
|
||||||
|
return (List<Message>) redisTemplateService.get(conversationIdKey);
|
||||||
|
}
|
||||||
|
return List.of();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void saveAll(String conversationId, List<Message> messages) {
|
||||||
|
String conversationIdKey = getConversationIdKey(conversationId);
|
||||||
|
redisTemplateService.set(conversationIdKey, messages);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void delete(String conversationId) {
|
||||||
|
String conversationIdKey = getConversationIdKey(conversationId);
|
||||||
|
redisTemplateService.delete(conversationIdKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getConversationIdKey(String conversationId) {
|
||||||
|
return AI_MESSAGE_CONVERSATION_ID + conversationId;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getConversationTypeKey(String type) {
|
||||||
|
return AI_MESSAGE_CONVERSATION_TYPE + type;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,256 @@
|
|||||||
|
package com.ai.app.service.impl;
|
||||||
|
|
||||||
|
import com.ai.app.service.RedisTemplateService;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @describe
|
||||||
|
* @Author kai.liu
|
||||||
|
* @Date 2025/9/1 9:28
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
@Slf4j
|
||||||
|
public class RedisTemplateServiceImpl implements RedisTemplateService {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private RedisTemplate<String,Object> redisTemplate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 缓存对象信息
|
||||||
|
* @param key 键
|
||||||
|
* @param value 值
|
||||||
|
* @author 施勇
|
||||||
|
* 2018年12月11日 上午10:54:49
|
||||||
|
*/
|
||||||
|
public void set(String key, Object value) {
|
||||||
|
redisTemplate.opsForValue().set(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 缓存信息,并设置缓存时间
|
||||||
|
* @param key 键
|
||||||
|
* @param value 值
|
||||||
|
* @param time 时间
|
||||||
|
* @param timeUnit 时间单位
|
||||||
|
* @author 施勇
|
||||||
|
* 2018年12月11日 上午10:54:27
|
||||||
|
*/
|
||||||
|
public void set(String key, Object value, long time, TimeUnit timeUnit){
|
||||||
|
if(time>0){
|
||||||
|
redisTemplate.opsForValue().set(key, value, time, timeUnit);
|
||||||
|
}else{
|
||||||
|
set(key, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 原子递增1
|
||||||
|
*
|
||||||
|
* @param key 键
|
||||||
|
* @return java.lang.Long
|
||||||
|
*/
|
||||||
|
public Long increment(String key) {
|
||||||
|
return redisTemplate.opsForValue().increment(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 原子递增
|
||||||
|
*
|
||||||
|
* @param key 键
|
||||||
|
* @param delta 增量
|
||||||
|
* @return java.lang.Long
|
||||||
|
*/
|
||||||
|
public Long increment(String key, Long delta) {
|
||||||
|
if (delta == null || delta < 1) {
|
||||||
|
delta = 1L;
|
||||||
|
}
|
||||||
|
return redisTemplate.opsForValue().increment(key, delta);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 递增
|
||||||
|
*
|
||||||
|
* @param key 键
|
||||||
|
* @param delta 递增因子
|
||||||
|
* @param time 时间
|
||||||
|
* @param timeUnit 时间单位
|
||||||
|
* @return java.lang.Long
|
||||||
|
* @author shiyong
|
||||||
|
* 2022/10/18 14:58
|
||||||
|
*/
|
||||||
|
public Long increment(String key, Long delta, long time, TimeUnit timeUnit) {
|
||||||
|
if (null == delta || delta < 1) {
|
||||||
|
delta = 1L;
|
||||||
|
}
|
||||||
|
Long increment = redisTemplate.opsForValue().increment(key, delta);
|
||||||
|
redisTemplate.expire(key, time, timeUnit);
|
||||||
|
return increment;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从缓存中获取信息
|
||||||
|
* @param key 键
|
||||||
|
* @return Object
|
||||||
|
* @author 施勇
|
||||||
|
* 2018年12月11日 上午10:54:10
|
||||||
|
*/
|
||||||
|
public Object get(Object key) {
|
||||||
|
return key==null?"":redisTemplate.opsForValue().get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从redis中获取key对应的过期时间;
|
||||||
|
* 如果该值有过期时间,就返回相应的过期时间;
|
||||||
|
* 如果该值没有设置过期时间,就返回-1;
|
||||||
|
* 如果没有该值,就返回-2;
|
||||||
|
*/
|
||||||
|
public Long getExpire(String key) {
|
||||||
|
return redisTemplate.opsForValue().getOperations().getExpire(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置key的失效时间
|
||||||
|
*
|
||||||
|
* @param key 键
|
||||||
|
* @param time 时长
|
||||||
|
* @param timeUnit 时间单位
|
||||||
|
* @return java.lang.Boolean
|
||||||
|
*/
|
||||||
|
public Boolean expire(String key, long time, TimeUnit timeUnit) {
|
||||||
|
return redisTemplate.expire(key, time, timeUnit);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否存在key
|
||||||
|
* @param key 键
|
||||||
|
* @return boolean
|
||||||
|
* @author 施勇
|
||||||
|
* 2018年12月11日 上午10:53:54
|
||||||
|
*/
|
||||||
|
public boolean hasKey(String key) {
|
||||||
|
if (null == key || "".equals(key)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Boolean result = redisTemplate.hasKey(key);
|
||||||
|
if (null == result) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除KEY对应的对象
|
||||||
|
* @param key 键
|
||||||
|
* @author 施勇
|
||||||
|
* 2018年12月24日 下午4:14:26
|
||||||
|
*/
|
||||||
|
public void delete(String key){
|
||||||
|
redisTemplate.delete(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查找匹配的key
|
||||||
|
* @param pattern 匹配字符串
|
||||||
|
* @return java.util.Set<java.lang.String>
|
||||||
|
* @author shiyong
|
||||||
|
* 2020/1/3 13:42
|
||||||
|
*/
|
||||||
|
public Set<String> getKeys(String pattern) {
|
||||||
|
return redisTemplate.keys(pattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 在队尾追加元素
|
||||||
|
*
|
||||||
|
* @param key 键
|
||||||
|
* @param value 值
|
||||||
|
* @return 添加后队列的长度
|
||||||
|
*/
|
||||||
|
public Long rightPush(String key, Object value) {
|
||||||
|
return redisTemplate.opsForList().rightPush(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从队首移除元素
|
||||||
|
*
|
||||||
|
* @param key 键
|
||||||
|
* @return 移除的元素
|
||||||
|
*/
|
||||||
|
public Object leftPop(String key) {
|
||||||
|
return redisTemplate.opsForList().leftPop(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从队首开始取值,获取指定区间
|
||||||
|
*
|
||||||
|
* @param key 键
|
||||||
|
* @param start 开始下标
|
||||||
|
* @param stop 结束下标
|
||||||
|
* @return 区间内的全部值
|
||||||
|
*/
|
||||||
|
public List<?> leftRange(String key, long start, long stop) {
|
||||||
|
return redisTemplate.opsForList().range(key, start, stop);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将值加到集合中
|
||||||
|
*
|
||||||
|
* @param key 键
|
||||||
|
* @param values 值
|
||||||
|
* @return 添加是否成功(1:成功,0:失败)
|
||||||
|
*/
|
||||||
|
public Long addToSet(String key, Object... values) {
|
||||||
|
return redisTemplate.opsForSet().add(key, values);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 集合的数量
|
||||||
|
*
|
||||||
|
* @param key 键
|
||||||
|
* @return 集合数量
|
||||||
|
*/
|
||||||
|
public Long sizeOfSet(String key) {
|
||||||
|
return redisTemplate.opsForSet().size(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 集合列表
|
||||||
|
*
|
||||||
|
* @param key 键
|
||||||
|
* @return 集合列表
|
||||||
|
*/
|
||||||
|
public Set<Object> getOfSet(String key) {
|
||||||
|
return redisTemplate.opsForSet().members(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 集合中是否有该值
|
||||||
|
*
|
||||||
|
* @param key 键
|
||||||
|
* @param value 值
|
||||||
|
* @return Boolean
|
||||||
|
*/
|
||||||
|
public Boolean hasOfSet(String key,Object value) {
|
||||||
|
return redisTemplate.opsForSet().isMember(key,value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除集合中值
|
||||||
|
*
|
||||||
|
* @param key 键
|
||||||
|
* @param value 值
|
||||||
|
* @return 删除是否成功(1:成功,0:失败)
|
||||||
|
*/
|
||||||
|
public Long removeOfSet(String key,Object value) {
|
||||||
|
return redisTemplate.opsForSet().remove(key,value);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
0
src/main/resources/application-dev.yml
Normal file
0
src/main/resources/application-dev.yml
Normal file
95
src/main/resources/application.yml
Normal file
95
src/main/resources/application.yml
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
server:
|
||||||
|
port: 8080
|
||||||
|
# servlet:
|
||||||
|
# context-path: /ai
|
||||||
|
tomcat:
|
||||||
|
# 等待队列长度 (所有线程忙碌时,排队等待的连接数, 默认: 100)
|
||||||
|
accept-count: 1000
|
||||||
|
# 最大连接数 (默认: 8192)
|
||||||
|
max-connections: 20000
|
||||||
|
# 连接超时 (接受连接后等待请求数据的最大时间, 默认值通常与系统有关)
|
||||||
|
connection-timeout: 30000
|
||||||
|
threads:
|
||||||
|
# 最大工作线程数 (默认: 200)
|
||||||
|
max: 2000
|
||||||
|
# 最小工作线程数(初始启动的线程数, 默认: 10)
|
||||||
|
min-spare: 200
|
||||||
|
# 限制表单提交(application/x-www-form-urlencoded)的POST请求最大大小 (默认: 2MB)
|
||||||
|
# 这是 Boot 2 中 'server.tomcat.max-http-post-size' 的替代品
|
||||||
|
max-http-form-post-size: 100MB
|
||||||
|
# 限制整个请求体(包括文件上传)的最大大小。超过此限制的请求将被拒绝 (默认: 2MB)
|
||||||
|
max-swallow-size: 100MB
|
||||||
|
# 定义响应的字符编码 (默认: UTF-8)
|
||||||
|
uri-encoding: UTF-8
|
||||||
|
compression:
|
||||||
|
enabled: true
|
||||||
|
http2:
|
||||||
|
enabled: true
|
||||||
|
spring:
|
||||||
|
application:
|
||||||
|
name: spring-ai-app
|
||||||
|
# 指定运行环境
|
||||||
|
profiles:
|
||||||
|
# 指定默认的运行环境为dev,运行时通过--spring.profiles.active参数切换运行环境
|
||||||
|
active: dev
|
||||||
|
main:
|
||||||
|
allow-bean-definition-overriding: true
|
||||||
|
servlet:
|
||||||
|
multipart:
|
||||||
|
max-file-size: 100MB
|
||||||
|
max-request-size: 100MB
|
||||||
|
ai:
|
||||||
|
deepseek:
|
||||||
|
api-key: sk-f970111b34c84a8c812919fb4fad8b65
|
||||||
|
chat:
|
||||||
|
options:
|
||||||
|
model: deepseek-reasoner
|
||||||
|
data:
|
||||||
|
redis:
|
||||||
|
host: 180.76.119.46
|
||||||
|
port: 6379
|
||||||
|
password: qwer@1234
|
||||||
|
database: 0
|
||||||
|
lettuce:
|
||||||
|
pool:
|
||||||
|
max-active: 8
|
||||||
|
max-idle: 8
|
||||||
|
min-idle: 0
|
||||||
|
max-wait: 3000
|
||||||
|
logging:
|
||||||
|
level:
|
||||||
|
org.springframework.ai.chat.client.advisor: debug
|
||||||
|
com.ai.app: debug
|
||||||
|
|
||||||
|
spring.datasource:
|
||||||
|
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||||
|
url: jdbc:mysql://180.76.119.46:3306/spring_ai_app?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&autoReconnect=true&failOverReadOnly=false&useSSL=false&allowMultiQueries=true
|
||||||
|
username: lk
|
||||||
|
password: Qwer@1234
|
||||||
|
type: com.zaxxer.hikari.HikariDataSource
|
||||||
|
# Hikari 连接池配置
|
||||||
|
hikari:
|
||||||
|
# 最小空闲连接数量
|
||||||
|
minimum-idle: 10
|
||||||
|
# 空闲连接存活最大时间,默认600000(10分钟)
|
||||||
|
idle-timeout: 180000
|
||||||
|
# 连接池最大连接数,默认是10
|
||||||
|
maximum-pool-size: 100
|
||||||
|
# 此属性控制从池返回的连接的默认自动提交行为,默认值:true
|
||||||
|
auto-commit: true
|
||||||
|
# 连接池名称
|
||||||
|
pool-name: HikariCP
|
||||||
|
# 此属性控制池中连接的最长生命周期,值0表示无限生命周期,默认1800000即30分钟
|
||||||
|
max-lifetime: 1800000
|
||||||
|
# 数据库连接超时时间,默认30秒,即30000
|
||||||
|
connection-timeout: 30000
|
||||||
|
connection-test-query: SELECT 1
|
||||||
|
mybatis-plus:
|
||||||
|
mapper-locations: classpath:mapper/**/*.xml
|
||||||
|
type-aliases-package: com.ai.app.entity
|
||||||
|
configuration:
|
||||||
|
# 日志打印
|
||||||
|
log-impl: org.apache.ibatis.logging.slf4j.Slf4jImpl
|
||||||
|
# 开启驼峰命名转换,如:Table(create_time) -> Entity(createTime)。
|
||||||
|
# 不需要我们关心怎么进行字段匹配,mybatis会自动识别`大写字母与下划线`
|
||||||
|
map-underscore-to-camel-case: true
|
||||||
13
src/main/resources/mapper/AIChatMessageMapper.xml
Normal file
13
src/main/resources/mapper/AIChatMessageMapper.xml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
<?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.ai.app.mapper.AIChatMessageMapper">
|
||||||
|
<insert id="batchInsert" parameterType="com.ai.app.entity.AIChatMessage">
|
||||||
|
INSERT INTO ai_chat_message (id,conversation_id,conversation_type,message_type,message,create_time)
|
||||||
|
VALUES
|
||||||
|
<foreach collection="messageList" item="message" separator=",">
|
||||||
|
(#{message.id}, #{message.conversationId}, #{message.conversationType}, #{message.messageType},#{message.message}, #{message.createTime})
|
||||||
|
</foreach>
|
||||||
|
</insert>
|
||||||
|
</mapper>
|
||||||
19
src/test/java/com/ai/app/SpringAiAppApplicationTests.java
Normal file
19
src/test/java/com/ai/app/SpringAiAppApplicationTests.java
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
package com.ai.app;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.text.NumberFormat;
|
||||||
|
import java.text.ParseException;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
@SpringBootTest
|
||||||
|
class SpringAiAppApplicationTests {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void contextLoads(){
|
||||||
|
System.out.println(new BigDecimal("-0.25"));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user