智能客服
This commit is contained in:
3
pom.xml
3
pom.xml
@@ -44,11 +44,10 @@
|
|||||||
<artifactId>spring-boot-starter-data-redis</artifactId>
|
<artifactId>spring-boot-starter-data-redis</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- mybatis -->
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.baomidou</groupId>
|
<groupId>com.baomidou</groupId>
|
||||||
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
|
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
|
||||||
<version>3.5.5</version>
|
<version>3.5.10.1</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.baomidou</groupId>
|
<groupId>com.baomidou</groupId>
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
package com.ai.app;
|
package com.ai.app;
|
||||||
|
|
||||||
|
import org.mybatis.spring.annotation.MapperScan;
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
|
@MapperScan(basePackages = "com.ai.app.mapper")
|
||||||
public class SpringAiAppApplication {
|
public class SpringAiAppApplication {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.ai.app.config;
|
package com.ai.app.config;
|
||||||
|
|
||||||
import com.ai.app.constant.SystemConstants;
|
import com.ai.app.constant.SystemConstants;
|
||||||
|
import com.ai.app.tools.CourseTools;
|
||||||
import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatModel;
|
import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatModel;
|
||||||
import org.springframework.ai.chat.client.ChatClient;
|
import org.springframework.ai.chat.client.ChatClient;
|
||||||
import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
|
import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
|
||||||
@@ -78,7 +79,7 @@ public class AIConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* dashScopeChatClient对话客户端
|
* 游戏对话客户端
|
||||||
*
|
*
|
||||||
* @param dashScopeChatModel 千问max大模型
|
* @param dashScopeChatModel 千问max大模型
|
||||||
* @param simpleLoggerAdvisor 日志Advisor
|
* @param simpleLoggerAdvisor 日志Advisor
|
||||||
@@ -101,6 +102,32 @@ public class AIConfig {
|
|||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 智能客服chat client
|
||||||
|
*
|
||||||
|
* @param dashScopeChatModel 千问模型
|
||||||
|
* @param simpleLoggerAdvisor 日志增强
|
||||||
|
* @param messageChatMemoryAdvisor 对话记忆
|
||||||
|
* @return: org.springframework.ai.chat.client.ChatClient
|
||||||
|
* @author kai.liu
|
||||||
|
* @date: 2025/9/4 14:35
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public ChatClient serviceDashScopeChatClient(DashScopeChatModel dashScopeChatModel,
|
||||||
|
SimpleLoggerAdvisor simpleLoggerAdvisor,
|
||||||
|
MessageChatMemoryAdvisor messageChatMemoryAdvisor,
|
||||||
|
CourseTools courseTools) {
|
||||||
|
return ChatClient
|
||||||
|
//模型
|
||||||
|
.builder(dashScopeChatModel)
|
||||||
|
//系统提示词
|
||||||
|
.defaultSystem(SystemConstants.SERVICE_SYSTEM_PROMPT)
|
||||||
|
//环绕增强
|
||||||
|
.defaultAdvisors(simpleLoggerAdvisor, messageChatMemoryAdvisor)
|
||||||
|
.defaultTools(courseTools)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* deepseek 对话客户端
|
* deepseek 对话客户端
|
||||||
* 响应太慢,不建议使用
|
* 响应太慢,不建议使用
|
||||||
|
|||||||
@@ -1,41 +0,0 @@
|
|||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
package com.ai.app.controller;
|
package com.ai.app.controller;
|
||||||
|
|
||||||
import com.ai.app.constant.ChatTypeEnum;
|
import com.ai.app.constant.ChatTypeEnum;
|
||||||
import com.ai.app.constant.SystemConstants;
|
|
||||||
import com.ai.app.dto.MessageDTO;
|
import com.ai.app.dto.MessageDTO;
|
||||||
import com.ai.app.service.ChatHistoryService;
|
import com.ai.app.service.ChatHistoryService;
|
||||||
import org.springframework.ai.chat.client.ChatClient;
|
import org.springframework.ai.chat.client.ChatClient;
|
||||||
@@ -37,6 +36,10 @@ public class DashScopeController {
|
|||||||
@Qualifier("gameDashScopeChatClient")
|
@Qualifier("gameDashScopeChatClient")
|
||||||
private ChatClient gameDashScopeChatClient;
|
private ChatClient gameDashScopeChatClient;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
@Qualifier("serviceDashScopeChatClient")
|
||||||
|
private ChatClient serviceDashScopeChatClient;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private ChatHistoryService chatHistoryService;
|
private ChatHistoryService chatHistoryService;
|
||||||
|
|
||||||
@@ -107,4 +110,23 @@ public class DashScopeController {
|
|||||||
.advisors(a -> a.param(ChatMemory.CONVERSATION_ID, chatId))
|
.advisors(a -> a.param(ChatMemory.CONVERSATION_ID, chatId))
|
||||||
.stream().content();
|
.stream().content();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* it培训机构智能客服
|
||||||
|
*
|
||||||
|
* @param prompt 用户提示词
|
||||||
|
* @param chatId 对话ID
|
||||||
|
* @return: reactor.core.publisher.Flux<java.lang.String>
|
||||||
|
* @author kai.liu
|
||||||
|
* @date: 2025/9/4 14:51
|
||||||
|
*/
|
||||||
|
@RequestMapping(value = "/service", produces = "text/stream;charset=UTF-8")
|
||||||
|
public Flux<String> service(String prompt, String chatId) {
|
||||||
|
chatHistoryService.saveHistoryChatId(ChatTypeEnum.CHAT_PDF.type, chatId);
|
||||||
|
return serviceDashScopeChatClient
|
||||||
|
.prompt()
|
||||||
|
.user(prompt)
|
||||||
|
.advisors(a -> a.param(ChatMemory.CONVERSATION_ID, chatId))
|
||||||
|
.stream().content();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
59
src/main/java/com/ai/app/entity/Course.java
Normal file
59
src/main/java/com/ai/app/entity/Course.java
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
package com.ai.app.entity;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 学科表
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author huge
|
||||||
|
* @since 2025-03-08
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = false)
|
||||||
|
@Accessors(chain = true)
|
||||||
|
@TableName("course")
|
||||||
|
public class Course implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 主键
|
||||||
|
*/
|
||||||
|
@TableId(value = "id", type = IdType.AUTO)
|
||||||
|
private Integer id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 学科名称
|
||||||
|
*/
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 学历背景要求:0-无,1-初中,2-高中、3-大专、4-本科以上
|
||||||
|
*/
|
||||||
|
private Integer edu;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 课程类型:编程、设计、自媒体、其它
|
||||||
|
*/
|
||||||
|
private String type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 课程价格
|
||||||
|
*/
|
||||||
|
private Long price;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 学习时长,单位: 天
|
||||||
|
*/
|
||||||
|
private Integer duration;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
56
src/main/java/com/ai/app/entity/CourseReservation.java
Normal file
56
src/main/java/com/ai/app/entity/CourseReservation.java
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
package com.ai.app.entity;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
*
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author huge
|
||||||
|
* @since 2025-03-08
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = false)
|
||||||
|
@Accessors(chain = true)
|
||||||
|
@TableName("course_reservation")
|
||||||
|
public class CourseReservation implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@TableId(value = "id", type = IdType.AUTO)
|
||||||
|
private Integer id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 预约课程
|
||||||
|
*/
|
||||||
|
private String course;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 学生姓名
|
||||||
|
*/
|
||||||
|
private String studentName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 联系方式
|
||||||
|
*/
|
||||||
|
private String contactInfo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 预约校区
|
||||||
|
*/
|
||||||
|
private String school;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 备注
|
||||||
|
*/
|
||||||
|
private String remark;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
37
src/main/java/com/ai/app/entity/Msg.java
Normal file
37
src/main/java/com/ai/app/entity/Msg.java
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
package com.ai.app.entity;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import org.springframework.ai.chat.messages.*;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
@Data
|
||||||
|
public class Msg {
|
||||||
|
MessageType messageType;
|
||||||
|
String text;
|
||||||
|
Map<String, Object> metadata;
|
||||||
|
List<AssistantMessage.ToolCall> toolCalls;
|
||||||
|
|
||||||
|
public Msg(Message message) {
|
||||||
|
this.messageType = message.getMessageType();
|
||||||
|
this.text = message.getText();
|
||||||
|
this.metadata = message.getMetadata();
|
||||||
|
if (message instanceof AssistantMessage am) {
|
||||||
|
this.toolCalls = am.getToolCalls();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Message toMessage() {
|
||||||
|
return switch (messageType) {
|
||||||
|
case SYSTEM -> new SystemMessage(text);
|
||||||
|
case USER -> UserMessage.builder().text(text).media(List.of()).metadata(metadata).build();
|
||||||
|
case ASSISTANT -> new AssistantMessage(text, metadata, toolCalls, List.of());
|
||||||
|
default -> throw new IllegalArgumentException("Unsupported message type: " + messageType);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
44
src/main/java/com/ai/app/entity/School.java
Normal file
44
src/main/java/com/ai/app/entity/School.java
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
package com.ai.app.entity;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 校区表
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author huge
|
||||||
|
* @since 2025-03-08
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = false)
|
||||||
|
@Accessors(chain = true)
|
||||||
|
@TableName("school")
|
||||||
|
public class School implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 主键
|
||||||
|
*/
|
||||||
|
@TableId(value = "id", type = IdType.AUTO)
|
||||||
|
private Integer id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校区名称
|
||||||
|
*/
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校区所在城市
|
||||||
|
*/
|
||||||
|
private String city;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
16
src/main/java/com/ai/app/mapper/CourseMapper.java
Normal file
16
src/main/java/com/ai/app/mapper/CourseMapper.java
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
package com.ai.app.mapper;
|
||||||
|
|
||||||
|
import com.ai.app.entity.Course;
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 学科表 Mapper 接口
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author huge
|
||||||
|
* @since 2025-03-08
|
||||||
|
*/
|
||||||
|
public interface CourseMapper extends BaseMapper<Course> {
|
||||||
|
|
||||||
|
}
|
||||||
17
src/main/java/com/ai/app/mapper/CourseReservationMapper.java
Normal file
17
src/main/java/com/ai/app/mapper/CourseReservationMapper.java
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
package com.ai.app.mapper;
|
||||||
|
|
||||||
|
|
||||||
|
import com.ai.app.entity.CourseReservation;
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* Mapper 接口
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author huge
|
||||||
|
* @since 2025-03-08
|
||||||
|
*/
|
||||||
|
public interface CourseReservationMapper extends BaseMapper<CourseReservation> {
|
||||||
|
|
||||||
|
}
|
||||||
16
src/main/java/com/ai/app/mapper/SchoolMapper.java
Normal file
16
src/main/java/com/ai/app/mapper/SchoolMapper.java
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
package com.ai.app.mapper;
|
||||||
|
|
||||||
|
import com.ai.app.entity.School;
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 校区表 Mapper 接口
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author huge
|
||||||
|
* @since 2025-03-08
|
||||||
|
*/
|
||||||
|
public interface SchoolMapper extends BaseMapper<School> {
|
||||||
|
|
||||||
|
}
|
||||||
24
src/main/java/com/ai/app/query/CourseQuery.java
Normal file
24
src/main/java/com/ai/app/query/CourseQuery.java
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
package com.ai.app.query;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import org.springframework.ai.tool.annotation.ToolParam;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class CourseQuery {
|
||||||
|
@ToolParam(required = false, description = "课程类型:编程、设计、自媒体、其它")
|
||||||
|
private String type;
|
||||||
|
@ToolParam(required = false, description = "学历要求:0-无、1-初中、2-高中、3-大专、4-本科及本科以上")
|
||||||
|
private Integer edu;
|
||||||
|
@ToolParam(required = false, description = "排序方式")
|
||||||
|
private List<Sort> sorts;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public static class Sort {
|
||||||
|
@ToolParam(required = false, description = "排序字段: price或duration")
|
||||||
|
private String field;
|
||||||
|
@ToolParam(required = false, description = "是否是升序: true/false")
|
||||||
|
private Boolean asc;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package com.ai.app.service;
|
||||||
|
|
||||||
|
import com.ai.app.entity.CourseReservation;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 服务类
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author huge
|
||||||
|
* @since 2025-03-08
|
||||||
|
*/
|
||||||
|
public interface ICourseReservationService extends IService<CourseReservation> {
|
||||||
|
|
||||||
|
}
|
||||||
16
src/main/java/com/ai/app/service/ICourseService.java
Normal file
16
src/main/java/com/ai/app/service/ICourseService.java
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
package com.ai.app.service;
|
||||||
|
|
||||||
|
import com.ai.app.entity.Course;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 学科表 服务类
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author huge
|
||||||
|
* @since 2025-03-08
|
||||||
|
*/
|
||||||
|
public interface ICourseService extends IService<Course> {
|
||||||
|
|
||||||
|
}
|
||||||
16
src/main/java/com/ai/app/service/ISchoolService.java
Normal file
16
src/main/java/com/ai/app/service/ISchoolService.java
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
package com.ai.app.service;
|
||||||
|
|
||||||
|
import com.ai.app.entity.School;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 校区表 服务类
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author huge
|
||||||
|
* @since 2025-03-08
|
||||||
|
*/
|
||||||
|
public interface ISchoolService extends IService<School> {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -7,7 +7,9 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @describe
|
* @describe
|
||||||
@@ -18,10 +20,11 @@ import java.util.List;
|
|||||||
@Service
|
@Service
|
||||||
public class ChatHistoryServiceImpl implements ChatHistoryService {
|
public class ChatHistoryServiceImpl implements ChatHistoryService {
|
||||||
|
|
||||||
@Autowired
|
/*@Autowired
|
||||||
private RedisTemplateService redisTemplateService;
|
private RedisTemplateService redisTemplateService;*/
|
||||||
|
|
||||||
|
private final Map<String,List<String>> chatStore = new HashMap<>();
|
||||||
|
|
||||||
public static final String CHAT_TYPE_KEY = "ai:history:type:";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 保存会话ID
|
* 保存会话ID
|
||||||
@@ -34,18 +37,11 @@ public class ChatHistoryServiceImpl implements ChatHistoryService {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void saveHistoryChatId(String type, String chatId) {
|
public void saveHistoryChatId(String type, String chatId) {
|
||||||
String key = CHAT_TYPE_KEY + type;
|
List<String> chatIds = chatStore.computeIfAbsent(type, k -> new ArrayList<>());
|
||||||
List<String> chatIds;
|
|
||||||
if (redisTemplateService.hasKey(key)) {
|
|
||||||
chatIds = (List<String>) redisTemplateService.get(key);
|
|
||||||
} else {
|
|
||||||
chatIds = new ArrayList<>();
|
|
||||||
}
|
|
||||||
if (chatIds.contains(chatId)) {
|
if (chatIds.contains(chatId)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
chatIds.add(chatId);
|
chatIds.add(chatId);
|
||||||
redisTemplateService.set(key, chatIds);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -58,10 +54,6 @@ public class ChatHistoryServiceImpl implements ChatHistoryService {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public List<String> getHistoryChatIds(String type) {
|
public List<String> getHistoryChatIds(String type) {
|
||||||
String key = CHAT_TYPE_KEY + type;
|
return chatStore.getOrDefault(type, List.of());
|
||||||
if (redisTemplateService.hasKey(key)) {
|
|
||||||
return (List<String>) redisTemplateService.get(key);
|
|
||||||
}
|
|
||||||
return List.of();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package com.ai.app.service.impl;
|
||||||
|
|
||||||
|
import com.ai.app.entity.CourseReservation;
|
||||||
|
import com.ai.app.mapper.CourseReservationMapper;
|
||||||
|
import com.ai.app.service.ICourseReservationService;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 服务实现类
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author huge
|
||||||
|
* @since 2025-03-08
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class CourseReservationServiceImpl extends ServiceImpl<CourseReservationMapper, CourseReservation> implements ICourseReservationService {
|
||||||
|
|
||||||
|
}
|
||||||
20
src/main/java/com/ai/app/service/impl/CourseServiceImpl.java
Normal file
20
src/main/java/com/ai/app/service/impl/CourseServiceImpl.java
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
package com.ai.app.service.impl;
|
||||||
|
|
||||||
|
import com.ai.app.entity.Course;
|
||||||
|
import com.ai.app.mapper.CourseMapper;
|
||||||
|
import com.ai.app.service.ICourseService;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 学科表 服务实现类
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author huge
|
||||||
|
* @since 2025-03-08
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class CourseServiceImpl extends ServiceImpl<CourseMapper, Course> implements ICourseService {
|
||||||
|
|
||||||
|
}
|
||||||
21
src/main/java/com/ai/app/service/impl/SchoolServiceImpl.java
Normal file
21
src/main/java/com/ai/app/service/impl/SchoolServiceImpl.java
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
package com.ai.app.service.impl;
|
||||||
|
|
||||||
|
|
||||||
|
import com.ai.app.entity.School;
|
||||||
|
import com.ai.app.mapper.SchoolMapper;
|
||||||
|
import com.ai.app.service.ISchoolService;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 校区表 服务实现类
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author huge
|
||||||
|
* @since 2025-03-08
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class SchoolServiceImpl extends ServiceImpl<SchoolMapper, School> implements ISchoolService {
|
||||||
|
|
||||||
|
}
|
||||||
64
src/main/java/com/ai/app/tools/CourseTools.java
Normal file
64
src/main/java/com/ai/app/tools/CourseTools.java
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
package com.ai.app.tools;
|
||||||
|
|
||||||
|
import com.ai.app.entity.Course;
|
||||||
|
import com.ai.app.entity.CourseReservation;
|
||||||
|
import com.ai.app.entity.School;
|
||||||
|
import com.ai.app.query.CourseQuery;
|
||||||
|
import com.ai.app.service.ICourseReservationService;
|
||||||
|
import com.ai.app.service.ICourseService;
|
||||||
|
import com.ai.app.service.ISchoolService;
|
||||||
|
import com.baomidou.mybatisplus.extension.conditions.query.QueryChainWrapper;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.ai.tool.annotation.Tool;
|
||||||
|
import org.springframework.ai.tool.annotation.ToolParam;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Component
|
||||||
|
public class CourseTools {
|
||||||
|
|
||||||
|
private final ICourseService courseService;
|
||||||
|
private final ISchoolService schoolService;
|
||||||
|
private final ICourseReservationService reservationService;
|
||||||
|
|
||||||
|
@Tool(description = "根据条件查询课程")
|
||||||
|
public List<Course> queryCourse(@ToolParam(description = "查询的条件", required = false) CourseQuery query) {
|
||||||
|
if (query == null) {
|
||||||
|
return courseService.list();
|
||||||
|
}
|
||||||
|
QueryChainWrapper<Course> wrapper = courseService.query()
|
||||||
|
.eq(query.getType() != null, "type", query.getType()) // type = '编程'
|
||||||
|
.le(query.getEdu() != null, "edu", query.getEdu());// edu <= 2
|
||||||
|
if (query.getSorts() != null && !query.getSorts().isEmpty()) {
|
||||||
|
for (CourseQuery.Sort sort : query.getSorts()) {
|
||||||
|
wrapper.orderBy(true, sort.getAsc(), sort.getField());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return wrapper.list();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Tool(description = "查询所有校区")
|
||||||
|
public List<School> querySchool() {
|
||||||
|
return schoolService.list();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Tool(description = "生成预约单,返回预约单号")
|
||||||
|
public Integer createCourseReservation(
|
||||||
|
@ToolParam(description = "预约课程") String course,
|
||||||
|
@ToolParam(description = "预约校区") String school,
|
||||||
|
@ToolParam(description = "学生姓名") String studentName,
|
||||||
|
@ToolParam(description = "联系电话") String contactInfo,
|
||||||
|
@ToolParam(description = "备注", required = false) String remark) {
|
||||||
|
CourseReservation reservation = new CourseReservation();
|
||||||
|
reservation.setCourse(course);
|
||||||
|
reservation.setSchool(school);
|
||||||
|
reservation.setStudentName(studentName);
|
||||||
|
reservation.setContactInfo(contactInfo);
|
||||||
|
reservation.setRemark(remark);
|
||||||
|
reservationService.save(reservation);
|
||||||
|
|
||||||
|
return reservation.getId();
|
||||||
|
}
|
||||||
|
}
|
||||||
27
src/main/java/com/ai/app/vo/MessageVO.java
Normal file
27
src/main/java/com/ai/app/vo/MessageVO.java
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
package com.ai.app.vo;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import org.springframework.ai.chat.messages.Message;
|
||||||
|
|
||||||
|
@NoArgsConstructor
|
||||||
|
@Data
|
||||||
|
public class MessageVO {
|
||||||
|
private String role;
|
||||||
|
private String content;
|
||||||
|
|
||||||
|
public MessageVO(Message message) {
|
||||||
|
switch (message.getMessageType()) {
|
||||||
|
case USER:
|
||||||
|
role = "user";
|
||||||
|
break;
|
||||||
|
case ASSISTANT:
|
||||||
|
role = "assistant";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
role = "";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
this.content = message.getText();
|
||||||
|
}
|
||||||
|
}
|
||||||
24
src/main/java/com/ai/app/vo/Result.java
Normal file
24
src/main/java/com/ai/app/vo/Result.java
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
package com.ai.app.vo;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class Result {
|
||||||
|
private Integer ok;
|
||||||
|
private String msg;
|
||||||
|
|
||||||
|
private Result(Integer ok, String msg) {
|
||||||
|
this.ok = ok;
|
||||||
|
this.msg = msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Result ok() {
|
||||||
|
return new Result(1, "ok");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Result fail(String msg) {
|
||||||
|
return new Result(0, msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -45,7 +45,7 @@ spring:
|
|||||||
options:
|
options:
|
||||||
model: deepseek-reasoner
|
model: deepseek-reasoner
|
||||||
dashscope:
|
dashscope:
|
||||||
api-key: ${DASHSCOPE_API_KEY}
|
api-key: ${DASH_SCOPE_API_KEY}
|
||||||
chat:
|
chat:
|
||||||
options:
|
options:
|
||||||
model: qwen-max
|
model: qwen-max
|
||||||
|
|||||||
Reference in New Issue
Block a user