news 2026/5/17 7:43:05

CAM++代码实践:将Embedding存入数据库的完整流程

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
CAM++代码实践:将Embedding存入数据库的完整流程

CAM++代码实践:将Embedding存入数据库的完整流程

1. 引言

1.1 业务场景描述

在构建说话人识别系统时,仅完成单次语音比对或特征提取远远不够。实际应用中,我们往往需要建立一个声纹数据库,用于长期存储用户语音的Embedding向量,以便后续进行快速检索、身份验证或聚类分析。

本文基于CAM++ 说话人识别系统(由科哥开发),详细介绍如何将提取出的192维Embedding向量持久化存储到数据库中,并实现“注册-查询-比对”的完整闭环流程。该方案适用于企业级声纹门禁、客服身份核验、个性化语音服务等场景。

1.2 痛点分析

原生CAM++系统虽然支持将Embedding保存为.npy文件,但存在以下问题:

  • 文件管理混乱,难以检索特定用户的声纹
  • 多人并发访问时易发生文件覆盖
  • 缺乏元数据关联(如用户ID、注册时间)
  • 不支持实时相似度搜索

因此,亟需一套工程化方案,将Embedding从本地文件迁移至结构化数据库。

1.3 方案预告

本文将围绕以下核心内容展开:

  • 解析CAM++输出的Embedding格式
  • 设计声纹数据库表结构
  • 实现Python后端自动入库逻辑
  • 提供可运行的集成代码示例
  • 给出性能优化与部署建议

2. 技术方案选型

2.1 数据库类型对比

数据库类型是否适合Embedding存储优势劣势
SQLite✅ 轻量级适用零配置、嵌入式、无需服务端并发能力弱,不适合高并发
MySQL⚠️ 可行但非最优普及率高、事务支持好原生不支持向量索引
PostgreSQL + pgvector✅ 推荐方案支持向量相似度搜索、成熟生态需额外插件
Milvus / Weaviate✅ 高性能向量数据库专为向量设计,支持GPU加速运维复杂,资源消耗大

结论:对于中小规模应用,推荐使用PostgreSQL + pgvector 插件;若追求极简部署,可选用SQLite存储NumPy数组。

2.2 最终技术栈选择

本文采用SQLite + Python Flask + CAM++ WebUI 扩展的轻量组合,原因如下:

  • 与CAM++本地部署环境兼容性高
  • 无需额外安装数据库服务
  • 易于调试和二次开发
  • 满足大多数中小企业需求

3. 实现步骤详解

3.1 环境准备

确保已安装以下依赖:

pip install numpy flask sqlite3 pydub

创建项目目录结构:

/root/speech_campplus_sv_zh-cn_16k/ ├── app.db # SQLite数据库 ├── database.py # 数据库操作模块 ├── routes.py # API路由扩展 ├── outputs/ # 原始输出目录 └── scripts/ └── start_app.sh # 启动脚本(需修改)

3.2 创建声纹数据库表

编写database.py,定义用户声纹表:

import sqlite3 import numpy as np import io def create_connection(): """创建数据库连接""" conn = None try: conn = sqlite3.connect('app.db', check_same_thread=False) return conn except Exception as e: print(e) return conn def create_table(): """创建声纹表""" conn = create_connection() cursor = conn.cursor() cursor.execute(''' CREATE TABLE IF NOT EXISTS speaker_embeddings ( id INTEGER PRIMARY KEY AUTOINCREMENT, user_id TEXT NOT NULL UNIQUE, embedding BLOB NOT NULL, filename TEXT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ) ''') conn.commit() conn.close() def _serialize_array(arr): """将NumPy数组序列化为BLOB""" out = io.BytesIO() np.save(out, arr) return out.getvalue() def _deserialize_array(data): """将BLOB反序列化为NumPy数组""" out = io.BytesIO(data) return np.load(out) class EmbeddingDB: def __init__(self): create_table() def save_embedding(self, user_id: str, embedding: np.ndarray, filename: str = None): conn = create_connection() cursor = conn.cursor() try: blob = _serialize_array(embedding) cursor.execute( "INSERT OR REPLACE INTO speaker_embeddings (user_id, embedding, filename) VALUES (?, ?, ?)", (user_id, blob, filename) ) conn.commit() return True except Exception as e: print(f"保存失败: {e}") return False finally: conn.close() def get_embedding(self, user_id: str) -> np.ndarray: conn = create_connection() cursor = conn.cursor() cursor.execute("SELECT embedding FROM speaker_embeddings WHERE user_id = ?", (user_id,)) row = cursor.fetchone() conn.close() if row: return _deserialize_array(row[0]) return None def list_users(self): conn = create_connection() cursor = conn.cursor() cursor.execute("SELECT user_id, filename, created_at FROM speaker_embeddings") rows = cursor.fetchall() conn.close() return rows

3.3 修改CAM++启动脚本以加载数据库

编辑/root/speech_campplus_sv_zh-cn_16k/scripts/start_app.sh

#!/bin/bash cd /root/speech_campplus_sv_zh-cn_16k # 启动前初始化数据库 python -c "from database import create_table; create_table()" # 原有Gradio启动命令 python app.py --server_port 7860 --server_name 0.0.0.0

3.4 扩展WebUI功能:新增“注册用户”接口

新建routes.py,添加Flask路由:

from flask import Flask, request, jsonify from database import EmbeddingDB import numpy as np import os app = Flask(__name__) db = EmbeddingDB() @app.route('/api/register', methods=['POST']) def register_speaker(): user_id = request.form.get('user_id') audio_file = request.files.get('audio') if not user_id or not audio_file: return jsonify({"error": "缺少参数"}), 400 # 调用CAM++提取Embedding(模拟调用) # 实际应通过subprocess调用CAM++ CLI或API try: # 模拟调用CAM++特征提取并获取.npy路径 output_dir = f"/root/speech_campplus_sv_zh-cn_16k/outputs/outputs_{int(time.time())}" os.makedirs(output_dir, exist_ok=True) npy_path = os.path.join(output_dir, "embedding.npy") # 此处应替换为真实调用CAM++ CLI的逻辑 # 示例:os.system(f"python extract.py --audio {audio_file} --output {npy_path}") # 模拟生成Embedding(测试用) embedding = np.random.rand(192).astype(np.float32) # 保存到数据库 success = db.save_embedding(user_id, embedding, audio_file.filename) if success: return jsonify({"message": f"用户 {user_id} 注册成功", "dimension": len(embedding)}) else: return jsonify({"error": "数据库保存失败"}), 500 except Exception as e: return jsonify({"error": str(e)}), 500 @app.route('/api/verify', methods=['POST']) def verify_speaker(): user_id = request.form.get('user_id') test_audio = request.files.get('audio') if not user_id or not test_audio: return jsonify({"error": "缺少参数"}), 400 # 获取注册用户的Embedding registered_emb = db.get_embedding(user_id) if registered_emb is None: return jsonify({"error": "用户未注册"}), 404 # 提取测试音频Embedding(模拟) test_emb = np.random.rand(192).astype(np.float32) # 替换为真实提取 # 计算余弦相似度 similarity = np.dot(registered_emb, test_emb) / (np.linalg.norm(registered_emb) * np.linalg.norm(test_emb)) threshold = float(request.form.get('threshold', 0.31)) result = "是同一人" if similarity >= threshold else "不是同一人" return jsonify({ "user_id": user_id, "similarity": float(similarity), "threshold": threshold, "result": result }) if __name__ == '__main__': app.run(port=5000, host='0.0.0.0')

3.5 集成到前端页面(可选)

可在CAM++ WebUI中增加两个新Tab:

  • 用户注册:输入user_id,上传音频,点击“注册”
  • 身份验证:选择已注册用户,上传待测音频,返回比对结果

前端可通过fetch调用上述/api/register/api/verify接口。


4. 实践问题与优化

4.1 实际落地难点

问题解决方案
CAM++无标准API接口使用Gradio客户端或封装CLI调用
多进程写入冲突SQLite使用check_same_thread=False+ 连接池
Embedding精度丢失使用float32保存,避免转为字符串
音频预处理不一致统一采样率16kHz、单声道WAV

4.2 性能优化建议

  1. 批量注册加速

    def batch_register(self, user_list: list): conn = create_connection() cursor = conn.cursor() for user_id, emb, fname in user_list: blob = _serialize_array(emb) cursor.execute("INSERT OR REPLACE ...", (user_id, blob, fname)) conn.commit() # 一次提交
  2. 添加索引提升查询速度

    CREATE INDEX IF NOT EXISTS idx_user_id ON speaker_embeddings (user_id);
  3. 定期清理过期数据

    DELETE FROM speaker_embeddings WHERE created_at < datetime('now', '-6 months');
  4. 备份机制

    # 每日备份 cp app.db app.db.bak.$(date +%Y%m%d)

5. 总结

5.1 实践经验总结

通过本次实践,我们实现了从CAM++系统提取的Embedding向量化存储的完整链路:

  • 成功将原本分散的.npy文件整合进SQLite数据库
  • 构建了“注册-存储-查询-比对”的闭环流程
  • 提供了可扩展的API接口,便于后续对接业务系统
  • 保留了原始系统的可视化能力,同时增强了后台管理功能

5.2 最佳实践建议

  1. 保持版权信息:遵循开发者“科哥”的开源协议,在二次开发中保留原始声明。
  2. 优先使用WAV格式:确保输入音频为16kHz、单声道,避免因格式转换导致误差。
  3. 阈值动态调整:根据实际测试集调整相似度阈值,建议初期设为0.5进行严格验证。
  4. 安全防护:对外暴露API时增加身份认证,防止恶意注册或暴力比对。

获取更多AI镜像

想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/11 7:06:00

MinerU2.5-1.2B优化教程:处理复杂版式文档

MinerU2.5-1.2B优化教程&#xff1a;处理复杂版式文档 1. 引言 随着企业数字化转型的加速&#xff0c;非结构化文档&#xff08;如PDF、扫描件、PPT、学术论文&#xff09;的自动化处理需求日益增长。传统OCR技术虽能提取文本&#xff0c;但在理解上下文、识别表格逻辑关系、…

作者头像 李华
网站建设 2026/5/15 23:42:16

OpenCode终极指南:快速上手开源AI编程助手

OpenCode终极指南&#xff1a;快速上手开源AI编程助手 【免费下载链接】opencode 一个专为终端打造的开源AI编程助手&#xff0c;模型灵活可选&#xff0c;可远程驱动。 项目地址: https://gitcode.com/GitHub_Trending/openc/opencode OpenCode是一个专为终端设计的开源…

作者头像 李华
网站建设 2026/5/12 20:40:13

OptiScaler:让所有显卡都能享受DLSS级画质提升的神器

OptiScaler&#xff1a;让所有显卡都能享受DLSS级画质提升的神器 【免费下载链接】OptiScaler DLSS replacement for AMD/Intel/Nvidia cards with multiple upscalers (XeSS/FSR2/DLSS) 项目地址: https://gitcode.com/GitHub_Trending/op/OptiScaler 还在为游戏卡顿而…

作者头像 李华
网站建设 2026/5/17 6:34:18

边缘计算新选择:Qwen1.5-0.5B CPU部署实战案例

边缘计算新选择&#xff1a;Qwen1.5-0.5B CPU部署实战案例 1. 引言 随着AI应用向终端侧延伸&#xff0c;边缘计算场景对模型的轻量化、低延迟和高能效提出了更高要求。传统方案往往依赖多个专用模型协同工作&#xff0c;例如使用BERT类模型做情感分析&#xff0c;再搭配大语言…

作者头像 李华
网站建设 2026/5/9 20:39:14

终极指南:用OpenCore Legacy Patcher完美复活老旧Mac设备

终极指南&#xff1a;用OpenCore Legacy Patcher完美复活老旧Mac设备 【免费下载链接】OpenCore-Legacy-Patcher 体验与之前一样的macOS 项目地址: https://gitcode.com/GitHub_Trending/op/OpenCore-Legacy-Patcher 您的MacBook是否因为系统限制而无法升级最新macOS&am…

作者头像 李华
网站建设 2026/5/16 18:40:10

从单图到批量:利用CV-UNet Universal Matting镜像构建高效抠图工作流

从单图到批量&#xff1a;利用CV-UNet Universal Matting镜像构建高效抠图工作流 1. 背景与需求分析 图像抠图&#xff08;Image Matting&#xff09;作为计算机视觉中的关键任务&#xff0c;广泛应用于电商展示、广告设计、影视后期和AI换背景等场景。传统手动抠图效率低下&…

作者头像 李华