mirror of
https://github.com/xinnan-tech/xiaozhi-esp32-server.git
synced 2026-07-21 22:53:56 +08:00
add:声纹识别开启教程
This commit is contained in:
@@ -6,7 +6,7 @@
|
||||
本项目为开源智能硬件项目
|
||||
<a href="https://github.com/78/xiaozhi-esp32">xiaozhi-esp32</a>提供后端服务<br/>
|
||||
根据<a href="https://ccnphfhqs21z.feishu.cn/wiki/M0XiwldO9iJwHikpXD5cEx71nKh">小智通信协议</a>使用Python、Java、Vue实现<br/>
|
||||
帮助您快速搭建小智服务器
|
||||
支持MCP接入点和声纹识别
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
@@ -225,11 +225,12 @@ Websocket接口地址: wss://2662r3426b.vicp.fun/xiaozhi/v1/
|
||||
|
||||
| 功能模块 | 描述 |
|
||||
|:---:|:---|
|
||||
| 核心服务架构 | 基于WebSocket和HTTP服务器,提供完整的控制台管理和认证系统 |
|
||||
| 语音交互系统 | 支持流式ASR(语音识别)、流式TTS(语音合成)、VAD(语音活动检测),支持多语言识别和语音处理 |
|
||||
| 智能对话系统 | 支持多种LLM(大语言模型),实现智能对话 |
|
||||
| 视觉感知系统 | 支持多种VLLM(视觉大模型),实现多模态交互 |
|
||||
| 意图识别系统 | 支持LLM意图识别、Function Call函数调用,提供插件化意图处理机制 |
|
||||
| 核心架构 | 基于WebSocket和HTTP服务器,提供完整的控制台管理和认证系统 |
|
||||
| 语音交互 | 支持流式ASR(语音识别)、流式TTS(语音合成)、VAD(语音活动检测),支持多语言识别和语音处理 |
|
||||
| 声纹识别 | 支持多用户声纹注册、管理和识别,与ASR并行处理,实时识别说话人身份并传递给LLM进行个性化回应 |
|
||||
| 智能对话 | 支持多种LLM(大语言模型),实现智能对话 |
|
||||
| 视觉感知 | 支持多种VLLM(视觉大模型),实现多模态交互 |
|
||||
| 意图识别 | 支持LLM意图识别、Function Call函数调用,提供插件化意图处理机制 |
|
||||
| 记忆系统 | 支持本地短期记忆、mem0ai接口记忆,具备记忆总结功能 |
|
||||
| 工具调用 | 支持客户端IOT协议、客户MCP协议、服务端MCP协议、MCP接入点协议、自定义工具函数 |
|
||||
| 管理后台 | 提供Web管理界面,支持用户管理、系统配置和设备管理 |
|
||||
@@ -308,6 +309,14 @@ Websocket接口地址: wss://2662r3426b.vicp.fun/xiaozhi/v1/
|
||||
|
||||
---
|
||||
|
||||
### Voiceprint 声纹识别
|
||||
|
||||
| 使用方式 | 支持平台 | 免费平台 |
|
||||
|:---:|:---:|:---:|
|
||||
| 本地使用 | 3D-Speaker | 3D-Speaker |
|
||||
|
||||
---
|
||||
|
||||
### Memory 记忆存储
|
||||
|
||||
| 类型 | 平台名称 | 使用方式 | 收费模式 | 备注 |
|
||||
|
||||
+11
-1
@@ -112,7 +112,17 @@ VAD:
|
||||
|
||||
参考教程[视觉模型使用指南](./mcp-vision-integration.md)
|
||||
|
||||
### 10、更多问题,可联系我们反馈 💬
|
||||
### 10、如何开启MCP接入点 🔧
|
||||
|
||||
1、先参考教程[MCP 接入点部署使用指南](./mcp-endpoint-enable.md)
|
||||
|
||||
2、再参考教程[MCP 接入点使用指南](./mcp-endpoint-integration.md)
|
||||
|
||||
### 12、如何开启声纹识别 🔊
|
||||
|
||||
参考教程[声纹识别启用指南](./voiceprint-integration.md)
|
||||
|
||||
### 13、更多问题,可联系我们反馈 💬
|
||||
|
||||
可以在[issues](https://github.com/xinnan-tech/xiaozhi-esp32-server/issues)提交您的问题。
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
# MCP 接入点部署使用指南
|
||||
|
||||
本教程包含2个部分
|
||||
本教程包含3个部分
|
||||
- 1、如何部署MCP接入点这个服务
|
||||
- 1、全模块部署时,怎么配置MCP接入点
|
||||
- 2、单模块部署时,怎么配置MCP接入点
|
||||
- 2、全模块部署时,怎么配置MCP接入点
|
||||
- 3、单模块部署时,怎么配置MCP接入点
|
||||
|
||||
# 1、如何部署MCP接入点这个服务
|
||||
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
# 声纹识别启用指南
|
||||
|
||||
本教程包含2个部分
|
||||
- 1、如何部署声纹识别这个服务
|
||||
- 2、全模块部署时,怎么配置声纹识别接口
|
||||
|
||||
# 1、如何部署声纹识别这个服务
|
||||
|
||||
## 第一步,下载声纹识别项目源码
|
||||
|
||||
浏览器打开[声纹识别项目地址](https://github.com/xinnan-tech/voiceprint-api)
|
||||
|
||||
打开完,找到页面中一个绿色的按钮,写着`Code`的按钮,点开它,然后你就看到`Download ZIP`的按钮。
|
||||
|
||||
点击它,下载本项目源码压缩包。下载到你电脑后,解压它,此时它的名字可能叫`voiceprint-api-main`
|
||||
你需要把它重命名成`voiceprint-api`。
|
||||
|
||||
## 第二步,启动程序
|
||||
这个项目是一个很简单的项目,建议使用docker运行。不过如果你不想使用docker运行,你可以参考[这个页面](https://github.com/xinnan-tech/voiceprint-api/blob/main/README.md)使用源码运行。以下是docker运行的方法
|
||||
|
||||
```
|
||||
# 进入本项目源码根目录
|
||||
cd voiceprint-api
|
||||
|
||||
# 清除缓存
|
||||
docker compose -f docker-compose.yml down
|
||||
docker stop voiceprint-api
|
||||
docker rm voiceprint-api
|
||||
docker rmi ghcr.nju.edu.cn/xinnan-tech/voiceprint-api:latest
|
||||
|
||||
# 启动docker容器
|
||||
docker compose -f docker-compose.yml up -d
|
||||
# 查看日志
|
||||
docker logs -f voiceprint-api
|
||||
```
|
||||
|
||||
此时,日志里会输出类似以下的日志
|
||||
```
|
||||
250711 INFO-🚀 开始: 生产环境服务启动(Uvicorn),监听地址: 0.0.0.0:8005
|
||||
250711 INFO-============================================================
|
||||
250711 INFO-声纹接口地址: http://127.0.0.1:8005/voiceprint/health?key=abcd
|
||||
250711 INFO-============================================================
|
||||
```
|
||||
|
||||
请你把声纹接口地址复制出来:
|
||||
|
||||
由于你是docker部署,切不可直接使用上面的地址!
|
||||
|
||||
由于你是docker部署,切不可直接使用上面的地址!
|
||||
|
||||
由于你是docker部署,切不可直接使用上面的地址!
|
||||
|
||||
你先把地址复制出来,放在一个草稿里,你要知道你的电脑的局域网ip是什么,例如我的电脑局域网ip是`192.168.1.25`,那么
|
||||
原来我的接口地址
|
||||
```
|
||||
http://127.0.0.1:8005/voiceprint/health?key=abcd
|
||||
|
||||
```
|
||||
就要改成
|
||||
```
|
||||
http://192.168.1.25:8005/voiceprint/health?key=abcd
|
||||
```
|
||||
|
||||
改好后,请使用浏览器直接访问`声纹接口地址`。当浏览器出现类似这样的代码,说明是成功了。
|
||||
```
|
||||
{"total_voiceprints":0,"status":"healthy"}
|
||||
```
|
||||
|
||||
请你保留好修改后的`声纹接口地址`,下一步要用到。
|
||||
|
||||
# 2、全模块部署时,怎么配置声纹识别
|
||||
|
||||
## 第一步 配置接口
|
||||
如果你是全模块部署,使用管理员账号,登录智控台,点击顶部`参数字典`,选择`参数管理`功能。
|
||||
|
||||
然后搜索参数`server.voice_print`,此时,它的值应该是`null`值。
|
||||
点击修改按钮,把上一步得来的`声纹接口地址`粘贴到`参数值`里。然后保存。
|
||||
|
||||
如果能保存成功,说明一切顺利,你可以去智能体查看效果了。如果不成功,说明智控台无法访问声纹识别,很大概率是网络防火墙,或者没有填写正确的局域网ip。
|
||||
|
||||
## 第二步 设置智能体记忆模式
|
||||
|
||||
进入你的智能体的角色配置里,将记忆设置成`本地短期记忆`,一定要开启`上报文字+语音`。
|
||||
|
||||
## 第三步 和你的智能体聊天
|
||||
|
||||
将你的设备通电,然后和他用正常的语速和音调聊天。
|
||||
|
||||
## 第四步 设置声纹
|
||||
|
||||
在智控台,`智能体管理`页面,在智能体的面板里,有一个`声纹识别`按钮,点击它。在底部有一个`新增按钮`。就可以对某个人说的话进行声纹注册。
|
||||
在弹出的框里,`描述`这个属性建议填写上,可以是这个人的职业、性格、爱好。方便智能体对说话人进行分析和了解。
|
||||
|
||||
## 第三步 和你的智能体聊天
|
||||
|
||||
将你的设备通电,问它,你知道我是谁吗?如果他能回答得出,说明声纹识别功能正常。
|
||||
+20
-9
@@ -1,19 +1,30 @@
|
||||
package xiaozhi.modules.agent.controller;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.validation.Valid;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import xiaozhi.common.exception.RenException;
|
||||
import xiaozhi.common.utils.Result;
|
||||
import xiaozhi.modules.agent.dto.AgentVoicePrintSaveDTO;
|
||||
import xiaozhi.modules.agent.dto.AgentVoicePrintUpdateDTO;
|
||||
import xiaozhi.modules.agent.service.AgentVoicePrintService;
|
||||
import xiaozhi.modules.agent.vo.AgentVoicePrintVO;
|
||||
import xiaozhi.modules.security.user.SecurityUser;
|
||||
|
||||
import java.util.List;
|
||||
import xiaozhi.modules.sys.service.SysParamsService;
|
||||
|
||||
@Tag(name = "智能体声纹管理")
|
||||
@AllArgsConstructor
|
||||
@@ -21,6 +32,7 @@ import java.util.List;
|
||||
@RequestMapping("/agent/voice-print")
|
||||
public class AgentVoicePrintController {
|
||||
private final AgentVoicePrintService agentVoicePrintService;
|
||||
private final SysParamsService sysParamsService;
|
||||
|
||||
@PostMapping
|
||||
@Operation(summary = "创建智能体的声纹")
|
||||
@@ -62,14 +74,13 @@ public class AgentVoicePrintController {
|
||||
@Operation(summary = "获取用户指定智能体声纹列表")
|
||||
@RequiresPermissions("sys:role:normal")
|
||||
public Result<List<AgentVoicePrintVO>> list(@PathVariable String id) {
|
||||
String voiceprintUrl = sysParamsService.getValue("server.voice_print", true);
|
||||
if (StringUtils.isBlank(voiceprintUrl) || "null".equals(voiceprintUrl)) {
|
||||
throw new RenException("声纹接口未配置,请先在参数配置中配置声纹接口地址(server.voice_print)");
|
||||
}
|
||||
Long userId = SecurityUser.getUserId();
|
||||
List<AgentVoicePrintVO> list = agentVoicePrintService.list(userId, id);
|
||||
return new Result<List<AgentVoicePrintVO>>().ok(list);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package xiaozhi.modules.agent.dao;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
|
||||
import xiaozhi.modules.agent.entity.AgentChatHistoryEntity;
|
||||
import xiaozhi.modules.agent.entity.AgentVoicePrintEntity;
|
||||
|
||||
|
||||
+8
-5
@@ -1,12 +1,15 @@
|
||||
package xiaozhi.modules.agent.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import xiaozhi.common.entity.BaseEntity;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.FieldFill;
|
||||
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.Data;
|
||||
|
||||
/**
|
||||
* 智能体声纹表
|
||||
*
|
||||
|
||||
+4
-7
@@ -1,12 +1,11 @@
|
||||
package xiaozhi.modules.agent.service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import xiaozhi.modules.agent.dto.AgentVoicePrintSaveDTO;
|
||||
import xiaozhi.modules.agent.dto.AgentVoicePrintUpdateDTO;
|
||||
import xiaozhi.modules.agent.vo.AgentVoicePrintVO;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 智能体声纹处理service
|
||||
*
|
||||
@@ -24,7 +23,7 @@ public interface AgentVoicePrintService {
|
||||
/**
|
||||
* 删除智能体的指的声纹
|
||||
*
|
||||
* @param userId 当前登录的用户id
|
||||
* @param userId 当前登录的用户id
|
||||
* @param voicePrintId 声纹id
|
||||
* @return 是否成功 T:成功 F:失败
|
||||
*/
|
||||
@@ -33,7 +32,7 @@ public interface AgentVoicePrintService {
|
||||
/**
|
||||
* 获取指定智能体的所有声纹数据
|
||||
*
|
||||
* @param userId 当前登录的用户id
|
||||
* @param userId 当前登录的用户id
|
||||
* @param agentId 智能体id
|
||||
* @return 声纹数据集合
|
||||
*/
|
||||
@@ -43,11 +42,9 @@ public interface AgentVoicePrintService {
|
||||
* 更新智能体的指的声纹数据
|
||||
*
|
||||
* @param userId 当前登录的用户id
|
||||
* @param dto 修改的声纹的数据
|
||||
* @param dto 修改的声纹的数据
|
||||
* @return 是否成功 T:成功 F:失败
|
||||
*/
|
||||
boolean update(Long userId, AgentVoicePrintUpdateDTO dto);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
-2
@@ -28,7 +28,6 @@ import xiaozhi.modules.agent.service.AgentMcpAccessPointService;
|
||||
import xiaozhi.modules.agent.service.AgentPluginMappingService;
|
||||
import xiaozhi.modules.agent.service.AgentService;
|
||||
import xiaozhi.modules.agent.service.AgentTemplateService;
|
||||
import xiaozhi.modules.agent.service.AgentVoicePrintService;
|
||||
import xiaozhi.modules.agent.vo.AgentVoicePrintVO;
|
||||
import xiaozhi.modules.config.service.ConfigService;
|
||||
import xiaozhi.modules.device.entity.DeviceEntity;
|
||||
@@ -52,7 +51,6 @@ public class ConfigServiceImpl implements ConfigService {
|
||||
private final TimbreService timbreService;
|
||||
private final AgentPluginMappingService agentPluginMappingService;
|
||||
private final AgentMcpAccessPointService agentMcpAccessPointService;
|
||||
private final AgentVoicePrintService agentVoicePrintService;
|
||||
private final AgentVoicePrintDao agentVoicePrintDao;
|
||||
|
||||
@Override
|
||||
|
||||
@@ -42,7 +42,7 @@ nav {
|
||||
}
|
||||
|
||||
.el-message {
|
||||
top: 45px !important;
|
||||
top: 70px !important;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
@@ -64,26 +64,26 @@ export default {
|
||||
if (this.isCDNEnabled) {
|
||||
// 添加全局快捷键Alt+C用于显示缓存查看器
|
||||
document.addEventListener('keydown', this.handleKeyDown);
|
||||
|
||||
|
||||
// 在全局对象上添加缓存检查方法,便于调试
|
||||
window.checkCDNCacheStatus = () => {
|
||||
this.showCacheViewer = true;
|
||||
};
|
||||
|
||||
|
||||
// 在控制台输出提示信息
|
||||
console.info(
|
||||
'%c[小智服务] CDN缓存检查工具已加载',
|
||||
'%c[小智服务] CDN缓存检查工具已加载',
|
||||
'color: #409EFF; font-weight: bold;'
|
||||
);
|
||||
console.info(
|
||||
'按下 Alt+C 组合键或在控制台运行 checkCDNCacheStatus() 可以查看CDN缓存状态'
|
||||
);
|
||||
|
||||
|
||||
// 检查Service Worker状态
|
||||
this.checkServiceWorkerStatus();
|
||||
} else {
|
||||
console.info(
|
||||
'%c[小智服务] CDN模式已禁用,使用本地打包资源',
|
||||
'%c[小智服务] CDN模式已禁用,使用本地打包资源',
|
||||
'color: #67C23A; font-weight: bold;'
|
||||
);
|
||||
}
|
||||
@@ -108,19 +108,19 @@ export default {
|
||||
const registrations = await navigator.serviceWorker.getRegistrations();
|
||||
if (registrations.length > 0) {
|
||||
console.info(
|
||||
'%c[小智服务] Service Worker已注册',
|
||||
'%c[小智服务] Service Worker已注册',
|
||||
'color: #67C23A; font-weight: bold;'
|
||||
);
|
||||
|
||||
|
||||
// 输出缓存状态到控制台
|
||||
setTimeout(async () => {
|
||||
const hasCaches = await logCacheStatus();
|
||||
if (!hasCaches) {
|
||||
console.info(
|
||||
'%c[小智服务] 还未检测到缓存,请刷新页面或等待缓存建立',
|
||||
'%c[小智服务] 还未检测到缓存,请刷新页面或等待缓存建立',
|
||||
'color: #E6A23C; font-weight: bold;'
|
||||
);
|
||||
|
||||
|
||||
// 开发环境下提供额外提示
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
console.info(
|
||||
@@ -136,10 +136,10 @@ export default {
|
||||
}, 2000);
|
||||
} else {
|
||||
console.info(
|
||||
'%c[小智服务] Service Worker未注册,CDN资源可能无法缓存',
|
||||
'%c[小智服务] Service Worker未注册,CDN资源可能无法缓存',
|
||||
'color: #F56C6C; font-weight: bold;'
|
||||
);
|
||||
|
||||
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
console.info(
|
||||
'%c[小智服务] 在开发环境中,这是正常现象',
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<HeaderBar />
|
||||
|
||||
<div class="operation-bar">
|
||||
<h2 class="page-title">声纹设别</h2>
|
||||
<h2 class="page-title">声纹识别</h2>
|
||||
</div>
|
||||
|
||||
<div class="main-wrapper">
|
||||
@@ -19,7 +19,8 @@
|
||||
<el-table-column label="操作" align="center">
|
||||
<template slot-scope="scope">
|
||||
<el-button size="mini" type="text" @click="editVoicePrint(scope.row)">编辑</el-button>
|
||||
<el-button size="mini" type="text" @click="deleteVoicePrint(scope.row.id)">删除</el-button>
|
||||
<el-button size="mini" type="text"
|
||||
@click="deleteVoicePrint(scope.row.id)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
@@ -46,8 +47,8 @@
|
||||
<script>
|
||||
import Api from "@/apis/api";
|
||||
import HeaderBar from "@/components/HeaderBar.vue";
|
||||
import VoicePrintDialog from "@/components/VoicePrintDialog.vue";
|
||||
import VersionFooter from "@/components/VersionFooter.vue";
|
||||
import VoicePrintDialog from "@/components/VoicePrintDialog.vue";
|
||||
export default {
|
||||
components: { HeaderBar, VoicePrintDialog, VersionFooter },
|
||||
data() {
|
||||
|
||||
Reference in New Issue
Block a user