feat: 增加asr,tts文件上报功能

This commit is contained in:
goodyhao
2025-04-30 17:56:52 +08:00
parent 4f829017ed
commit 48f8c6c5b7
21 changed files with 706 additions and 6 deletions
@@ -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> {
}
@@ -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;
}
@@ -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;
}
@@ -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);
}
@@ -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);
}
@@ -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;
}
}
@@ -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 {
}
@@ -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>