feat(chat): 实现联网搜索与对话管理功能

- 新增 OkHttp 客户端配置及依赖
- 添加 SearXNG 搜索引擎集成配置
- 创建基础分页查询类 BasePageQuery
- 实现网络搜索增强顾问 NetworkSearchAdvisor
- 增加聊天历史消息和对话的分页查询接口
- 添加对话摘要重命名与删除功能
- 配置 MyBatis Plus 分页插件支持
- 引入 Jsoup用于网页内容解析
- 新增 Hutool 工具库依赖
- 实现搜索结果内容抓取服务
- 添加搜索结果 DTO 和相关服务接口
- 扩展响应码枚举支持对话不存在情况
- 新增多个 VO 类用于请求和响应数据传输
This commit is contained in:
2025-11-03 22:08:26 +08:00
parent 59eb69747b
commit fdab553ba1
25 changed files with 1076 additions and 7 deletions

View File

@@ -1,23 +1,36 @@
package com.hanserwei.airobot.service.impl;
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.hanserwei.airobot.domain.dos.ChatDO;
import com.hanserwei.airobot.domain.dos.ChatMessageDO;
import com.hanserwei.airobot.domain.mapper.ChatMapper;
import com.hanserwei.airobot.model.vo.chat.NewChatReqVO;
import com.hanserwei.airobot.model.vo.chat.NewChatRspVO;
import com.hanserwei.airobot.domain.mapper.ChatMessageMapper;
import com.hanserwei.airobot.enums.ResponseCodeEnum;
import com.hanserwei.airobot.exception.BizException;
import com.hanserwei.airobot.model.vo.chat.*;
import com.hanserwei.airobot.service.ChatService;
import com.hanserwei.airobot.utils.PageResponse;
import com.hanserwei.airobot.utils.Response;
import com.hanserwei.airobot.utils.StringUtil;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.util.Comparator;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
@Service
public class ChatServiceImpl implements ChatService {
@Resource
private ChatMapper chatMapper;
@Resource
private ChatMessageMapper chatMessageMapper;
@Override
public Response<NewChatRspVO> newChat(NewChatReqVO newChatReqVO) {
@@ -42,4 +55,100 @@ public class ChatServiceImpl implements ChatService {
.summary(summary)
.build());
}
@Override
public PageResponse<FindChatHistoryMessagePageListRspVO> findChatHistoryMessagePageList(FindChatHistoryMessagePageListReqVO findChatHistoryMessagePageListReqVO) {
// 获取当前页、以及每页需要展示的数据数量
Long current = findChatHistoryMessagePageListReqVO.getCurrent();
Long size = findChatHistoryMessagePageListReqVO.getSize();
String chatId = findChatHistoryMessagePageListReqVO.getChatId();
// 执行分页查询
Page<ChatMessageDO> chatMessageDOPage = chatMessageMapper.selectPageList(current, size, chatId);
List<ChatMessageDO> chatMessageDOS = chatMessageDOPage.getRecords();
// DO 转 VO
List<FindChatHistoryMessagePageListRspVO> vos = null;
if (CollUtil.isNotEmpty(chatMessageDOS)) {
vos = chatMessageDOS.stream()
.map(chatMessageDO -> FindChatHistoryMessagePageListRspVO.builder() // 构建返参 VO 实体类
.id(chatMessageDO.getId())
.chatId(chatMessageDO.getChatUuid())
.content(chatMessageDO.getContent())
.role(chatMessageDO.getRole())
.createTime(chatMessageDO.getCreateTime())
.build())
// 升序排序
.sorted(Comparator.comparing(FindChatHistoryMessagePageListRspVO::getCreateTime))
.collect(Collectors.toList());
}
return PageResponse.success(chatMessageDOPage, vos);
}
@Override
public PageResponse<FindChatHistoryPageListRspVO> findChatHistoryPageList(FindChatHistoryPageListReqVO findChatHistoryPageListReqVO) {
// 获取当前页、以及每页需要展示的数据数量
Long current = findChatHistoryPageListReqVO.getCurrent();
Long size = findChatHistoryPageListReqVO.getSize();
// 执行分页查询
Page<ChatDO> chatDOPage = chatMapper.selectPageList(current, size);
// 获取查询结果
List<ChatDO> chatDOS = chatDOPage.getRecords();
// DO 转 VO
List<FindChatHistoryPageListRspVO> vos = null;
if (CollUtil.isNotEmpty(chatDOS)) {
vos = chatDOS.stream()
.map(chatDO -> FindChatHistoryPageListRspVO.builder() // 构建返参 VO
.id(chatDO.getId())
.uuid(chatDO.getUuid())
.summary(chatDO.getSummary())
.updateTime(chatDO.getUpdateTime())
.build())
.collect(Collectors.toList());
}
return PageResponse.success(chatDOPage, vos);
}
@Override
public Response<?> renameChatSummary(RenameChatReqVO renameChatReqVO) {
// 对话 ID
Long chatId = renameChatReqVO.getId();
// 摘要
String summary = renameChatReqVO.getSummary();
// 根据主键 ID 更新摘要
chatMapper.updateById(ChatDO.builder()
.id(chatId)
.summary(summary)
.build());
return Response.success();
}
@Override
@Transactional(rollbackFor = Exception.class)
public Response<?> deleteChat(DeleteChatReqVO deleteChatReqVO) {
// 对话 UUID
String uuid = deleteChatReqVO.getUuid();
// 删除对话
int count = chatMapper.delete(Wrappers.<ChatDO>lambdaQuery()
.eq(ChatDO::getUuid, uuid));
// 如果删除操作影响的行数为 0说明想要删除的对话不存在
if (count == 0) {
throw new BizException(ResponseCodeEnum.CHAT_NOT_EXISTED);
}
// 批量删除对话下的所有消息
chatMessageMapper.delete(Wrappers.<ChatMessageDO>lambdaQuery()
.eq(ChatMessageDO::getChatUuid, uuid));
return Response.success();
}
}