mirror of
https://github.com/xinnan-tech/xiaozhi-esp32-server.git
synced 2026-07-23 23:53:55 +08:00
feat: 增加asr,tts文件上报功能
This commit is contained in:
+35
@@ -0,0 +1,35 @@
|
||||
package xiaozhi.modules.agent.controller;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.validation.Valid;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import xiaozhi.common.utils.Result;
|
||||
import xiaozhi.modules.agent.dto.AgentChatHistoryReportDTO;
|
||||
import xiaozhi.modules.agent.service.biz.AgentChatHistoryBizService;
|
||||
|
||||
@Tag(name = "智能体聊天历史管理")
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/agent/chat-history")
|
||||
public class AgentChatHistoryController {
|
||||
private final AgentChatHistoryBizService agentChatHistoryBizService;
|
||||
|
||||
/**
|
||||
* 小智服务聊天上报请求
|
||||
* <p>
|
||||
* 小智服务聊天上报请求,包含Base64编码的音频数据和相关信息。
|
||||
*
|
||||
* @param request 包含上传文件及相关信息的请求对象
|
||||
*/
|
||||
@Operation(summary = "小智服务聊天上报请求")
|
||||
@PostMapping("/report")
|
||||
public Result<Boolean> uploadFile(@Valid @RequestBody AgentChatHistoryReportDTO request) {
|
||||
Boolean result = agentChatHistoryBizService.report(request);
|
||||
return new Result<Boolean>().ok(result);
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package xiaozhi.modules.agent.dao;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
import xiaozhi.common.dao.BaseDao;
|
||||
import xiaozhi.modules.agent.entity.AgentEntity;
|
||||
|
||||
@@ -15,4 +16,16 @@ public interface AgentDao extends BaseDao<AgentEntity> {
|
||||
* @return 设备数量
|
||||
*/
|
||||
Integer getDeviceCountByAgentId(@Param("agentId") String agentId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据设备MAC地址查询对应设备的默认智能体信息
|
||||
*
|
||||
* @param macAddress 设备MAC地址
|
||||
* @return 默认智能体信息
|
||||
*/
|
||||
@Select(" SELECT a.* FROM ai_device d " +
|
||||
" LEFT JOIN ai_agent a ON d.agent_id = a.id " +
|
||||
" WHERE d.mac_address = #{macAddress} " +
|
||||
" ORDER BY d.id DESC LIMIT 1")
|
||||
AgentEntity getDefaultAgentByMacAddress(@Param("macAddress") String macAddress);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
package xiaozhi.modules.agent.dao;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import xiaozhi.modules.agent.entity.AgentChatHistoryEntity;
|
||||
|
||||
/**
|
||||
* {@link AgentChatHistoryEntity} 智能体聊天历史记录Dao对象
|
||||
*
|
||||
* @author Goody
|
||||
* @version 1.0, 2025/4/30
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Mapper
|
||||
public interface AiAgentChatHistoryDao extends BaseMapper<AgentChatHistoryEntity> {
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
package xiaozhi.modules.agent.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 小智设备聊天上报请求
|
||||
*
|
||||
* @author Haotian
|
||||
* @version 1.0, 2025/5/8
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "小智设备聊天上报请求")
|
||||
public class AgentChatHistoryReportDTO {
|
||||
@Schema(description = "MAC地址", example = "00:11:22:33:44:55")
|
||||
@NotBlank
|
||||
private String macAddress;
|
||||
@Schema(description = "会话ID", example = "79578c31-f1fb-426a-900e-1e934215f05a")
|
||||
@NotBlank
|
||||
private String sessionId;
|
||||
@Schema(description = "排序值(与session_id对应)", example = "1745566378")
|
||||
@NotNull
|
||||
private Long sort;
|
||||
@Schema(description = "消息类型: 1-用户, 2-智能体", example = "1")
|
||||
@NotNull
|
||||
private Byte chatType;
|
||||
@Schema(description = "聊天内容", example = "你好呀")
|
||||
@NotBlank
|
||||
private String content;
|
||||
@Schema(description = "文件数据(Base64编码)", example = "")
|
||||
private String fileBase64;
|
||||
@Schema(description = "文件扩展名(如wav、mp3等)", example = "wav")
|
||||
private String fileExtension;
|
||||
}
|
||||
+92
@@ -0,0 +1,92 @@
|
||||
package xiaozhi.modules.agent.entity;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* 智能体聊天记录表
|
||||
*
|
||||
* @author Goody
|
||||
* @version 1.0, 2025/4/30
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@TableName(value = "ai_agent_chat_history")
|
||||
public class AgentChatHistoryEntity {
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* MAC地址
|
||||
*/
|
||||
@TableField(value = "mac_address")
|
||||
private String macAddress;
|
||||
|
||||
/**
|
||||
* 智能体id
|
||||
*/
|
||||
@TableField(value = "agent_id")
|
||||
private String agentId;
|
||||
|
||||
/**
|
||||
* 会话ID
|
||||
*/
|
||||
@TableField(value = "session_id")
|
||||
private String sessionId;
|
||||
|
||||
/**
|
||||
* 排序值(与session_id对应),使用时间戳,方便排序
|
||||
*/
|
||||
@TableField(value = "sort")
|
||||
private Long sort;
|
||||
|
||||
/**
|
||||
* 消息类型: 1-用户, 2-智能体
|
||||
*/
|
||||
@TableField(value = "chat_type")
|
||||
private Byte chatType;
|
||||
|
||||
/**
|
||||
* 聊天内容
|
||||
*/
|
||||
@TableField(value = "content")
|
||||
private String content;
|
||||
|
||||
/**
|
||||
* 音频base64数据
|
||||
*/
|
||||
@TableField(value = "audio")
|
||||
private String audio;
|
||||
|
||||
/**
|
||||
* 音频URL
|
||||
*/
|
||||
@TableField(value = "audio_url")
|
||||
private String audioUrl;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@TableField(value = "created_at")
|
||||
private Date createdAt;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
@TableField(value = "updated_at")
|
||||
private Date updatedAt;
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
package xiaozhi.modules.agent.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import xiaozhi.modules.agent.entity.AgentChatHistoryEntity;
|
||||
|
||||
/**
|
||||
* 智能体聊天记录表处理service
|
||||
*
|
||||
* @author Goody
|
||||
* @version 1.0, 2025/4/30
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public interface AgentChatHistoryService extends IService<AgentChatHistoryEntity> {
|
||||
}
|
||||
@@ -42,4 +42,12 @@ public interface AgentService extends BaseService<AgentEntity> {
|
||||
* @return 设备数量
|
||||
*/
|
||||
Integer getDeviceCountByAgentId(String agentId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据设备MAC地址查询对应设备的默认智能体信息
|
||||
*
|
||||
* @param macAddress 设备MAC地址
|
||||
* @return 默认智能体信息,不存在时返回null
|
||||
*/
|
||||
AgentEntity getDefaultAgentByMacAddress(String macAddress);
|
||||
}
|
||||
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
package xiaozhi.modules.agent.service.biz;
|
||||
|
||||
import xiaozhi.modules.agent.dto.AgentChatHistoryReportDTO;
|
||||
|
||||
/**
|
||||
* 智能体聊天历史业务逻辑层
|
||||
*
|
||||
* @author Goody
|
||||
* @version 1.0, 2025/4/30
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public interface AgentChatHistoryBizService {
|
||||
|
||||
/**
|
||||
* 聊天上报方法
|
||||
*
|
||||
* @param agentChatHistoryReportDTO 包含聊天上报所需信息的输入对象
|
||||
* 例如:设备MAC地址、文件类型、内容等
|
||||
* @return 上传结果,true表示成功,false表示失败
|
||||
*/
|
||||
Boolean report(AgentChatHistoryReportDTO agentChatHistoryReportDTO);
|
||||
}
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
package xiaozhi.modules.agent.service.biz.impl;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import xiaozhi.modules.agent.dto.AgentChatHistoryReportDTO;
|
||||
import xiaozhi.modules.agent.entity.AgentEntity;
|
||||
import xiaozhi.modules.agent.entity.AgentChatHistoryEntity;
|
||||
import xiaozhi.modules.agent.service.AgentChatHistoryService;
|
||||
import xiaozhi.modules.agent.service.AgentService;
|
||||
import xiaozhi.modules.agent.service.biz.AgentChatHistoryBizService;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* {@link AgentChatHistoryBizService} impl
|
||||
*
|
||||
* @author Goody
|
||||
* @version 1.0, 2025/4/30
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class AgentChatHistoryBizServiceImpl implements AgentChatHistoryBizService {
|
||||
private final AgentService agentService;
|
||||
private final AgentChatHistoryService agentChatHistoryService;
|
||||
|
||||
/**
|
||||
* 处理聊天记录上报,包括文件上传和相关信息记录
|
||||
*
|
||||
* @param report 包含聊天上报所需信息的输入对象
|
||||
* @return 上传结果,true表示成功,false表示失败
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean report(AgentChatHistoryReportDTO report) {
|
||||
final String macAddress = report.getMacAddress();
|
||||
final Byte chatType = report.getChatType();
|
||||
log.info("小智设备聊天上报请求: macAddress={}, type={}", macAddress, chatType);
|
||||
|
||||
// 1. 上传音频文件
|
||||
final String uploadUrl = this.upload(report);
|
||||
|
||||
// 2. 组装上报数据
|
||||
// 2.1 根据设备MAC地址查询对应的默认智能体,判断是否需要上报
|
||||
AgentEntity agentEntity = agentService.getDefaultAgentByMacAddress(macAddress);
|
||||
if (agentEntity == null) {
|
||||
return false;
|
||||
}
|
||||
final String agentId = agentEntity.getId();
|
||||
log.info("设备 {} 对应智能体 {} 上报", macAddress, agentEntity.getId());
|
||||
|
||||
// 2.2 构建聊天记录实体
|
||||
final AgentChatHistoryEntity entity = AgentChatHistoryEntity.builder()
|
||||
.macAddress(macAddress)
|
||||
.agentId(agentId)
|
||||
.sessionId(report.getSessionId())
|
||||
.sort(report.getSort())
|
||||
.chatType(report.getChatType())
|
||||
.content(report.getContent())
|
||||
.audio(report.getFileBase64())
|
||||
.audioUrl(uploadUrl)
|
||||
.build();
|
||||
|
||||
// 3. 保存数据
|
||||
agentChatHistoryService.save(entity);
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传文件
|
||||
*
|
||||
* @param report 上报文件数据
|
||||
* @return 上传文件url
|
||||
*/
|
||||
@Nullable
|
||||
private String upload(AgentChatHistoryReportDTO report) {
|
||||
// TODO(haotian): 2025/4/30 根据需要自定义完成上传生成url即可
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
package xiaozhi.modules.agent.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import org.springframework.stereotype.Service;
|
||||
import xiaozhi.modules.agent.dao.AiAgentChatHistoryDao;
|
||||
import xiaozhi.modules.agent.entity.AgentChatHistoryEntity;
|
||||
import xiaozhi.modules.agent.service.AgentChatHistoryService;
|
||||
|
||||
/**
|
||||
* 智能体聊天记录表处理service {@link AgentChatHistoryService} impl
|
||||
*
|
||||
* @author Goody
|
||||
* @version 1.0, 2025/4/30
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Service
|
||||
public class AgentChatHistoryServiceImpl extends ServiceImpl<AiAgentChatHistoryDao, AgentChatHistoryEntity> implements AgentChatHistoryService {
|
||||
|
||||
}
|
||||
+9
-1
@@ -130,4 +130,12 @@ public class AgentServiceImpl extends BaseServiceImpl<AgentDao, AgentEntity> imp
|
||||
|
||||
return deviceCount != null ? deviceCount : 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public AgentEntity getDefaultAgentByMacAddress(String macAddress) {
|
||||
if (StringUtils.isEmpty(macAddress)) {
|
||||
return null;
|
||||
}
|
||||
return agentDao.getDefaultAgentByMacAddress(macAddress);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,6 +84,7 @@ public class ShiroConfig {
|
||||
filterMap.put("/user/register", "anon");
|
||||
// 将config路径使用server服务过滤器
|
||||
filterMap.put("/config/**", "server");
|
||||
filterMap.put("/agent/chat-history/report", "server");
|
||||
filterMap.put("/**", "oauth2");
|
||||
shiroFilter.setFilterChainDefinitionMap(filterMap);
|
||||
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
-- 初始化智能体聊天记录
|
||||
DROP TABLE IF EXISTS ai_agent_chat_history;
|
||||
CREATE TABLE ai_agent_chat_history
|
||||
(
|
||||
id BIGINT AUTO_INCREMENT COMMENT '主键ID'
|
||||
PRIMARY KEY,
|
||||
mac_address VARCHAR(50) COMMENT 'MAC地址',
|
||||
agent_id BIGINT DEFAULT 0 COMMENT '智能体id',
|
||||
session_id VARCHAR(50) COMMENT '会话ID',
|
||||
sort BIGINT COMMENT '排序值(与session_id对应),使用时间戳,方便排序',
|
||||
chat_type TINYINT(3) COMMENT '消息类型: 1-用户, 2-智能体',
|
||||
content VARCHAR(1024) COMMENT '聊天内容',
|
||||
audio text COMMENT '音频base64数据',
|
||||
audio_url VARCHAR(256) COMMENT '音频URL',
|
||||
created_at DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) NOT NULL COMMENT '创建时间',
|
||||
updated_at DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) NOT NULL ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
|
||||
INDEX idx_mac_session (mac_address, sort)
|
||||
) COMMENT '智能体聊天记录表';
|
||||
@@ -0,0 +1,24 @@
|
||||
<?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="xiaozhi.modules.agent.dao.AiAgentChatHistoryDao">
|
||||
<resultMap id="BaseResultMap" type="xiaozhi.modules.agent.entity.AgentChatHistoryEntity">
|
||||
<!--@mbg.generated-->
|
||||
<!--@Table ai_agent_chat_history-->
|
||||
<id column="id" jdbcType="BIGINT" property="id" />
|
||||
<result column="mac_address" jdbcType="VARCHAR" property="macAddress" />
|
||||
<result column="agent_id" jdbcType="VARCHAR" property="agentId" />
|
||||
<result column="session_id" jdbcType="VARCHAR" property="sessionId" />
|
||||
<result column="sort" jdbcType="BIGINT" property="sort" />
|
||||
<result column="chat_type" jdbcType="TINYINT" property="chatType" />
|
||||
<result column="content" jdbcType="VARCHAR" property="content" />
|
||||
<result column="audio" jdbcType="LONGVARCHAR" property="audio" />
|
||||
<result column="audio_url" jdbcType="VARCHAR" property="audioUrl" />
|
||||
<result column="created_at" jdbcType="TIMESTAMP" property="createdAt" />
|
||||
<result column="updated_at" jdbcType="TIMESTAMP" property="updatedAt" />
|
||||
</resultMap>
|
||||
<sql id="Base_Column_List">
|
||||
<!--@mbg.generated-->
|
||||
id, mac_address, agent_id, session_id, sort, chat_type, content, audio, audio_url,
|
||||
created_at, updated_at
|
||||
</sql>
|
||||
</mapper>
|
||||
Reference in New Issue
Block a user