SenseVoice-Small模型数据库集成实战识别文本存入MySQL与分析你是不是也遇到过这样的场景手头有一堆会议录音、访谈音频或者客服通话记录想快速把它们变成文字然后还能方便地搜索、统计和分析里面的内容。手动整理太费时间了。用在线工具又担心数据安全和隐私。今天我就带你从零开始手把手搭建一个属于自己的语音识别应用后端。我们会用上开源的SenseVoice-Small模型来处理音频把识别出来的文字规规矩矩地存进MySQL数据库里。这还没完我们还要给它加上查询和统计功能最后把它部署到云端让它成为一个随时可用的服务。整个过程就像搭积木一样我会把每一步都拆解清楚。即使你之前没怎么接触过后端开发或者数据库跟着做下来也能收获一个实实在在、能跑起来的项目。咱们这就开始。1. 项目准备与环境搭建在动手写代码之前得先把“厨房”收拾好把需要的“食材”和“工具”备齐。这一步做好了后面就会顺利很多。1.1 核心工具选择与说明我们这个项目主要用到三样东西SenseVoice-Small这是我们的“耳朵”和“大脑”负责把音频文件听懂并转换成文字。它是一个开源的语音识别模型特点是模型小、速度快对于中文的识别效果很不错特别适合我们这种需要快速集成和部署的场景。MySQL这是我们的“笔记本”用来持久化存储识别出来的文本以及相关的信息。比如这段文字是从哪个文件来的、什么时候识别的、说话人是谁等等。选择它是因为它太常见了教程多生态好和你以后可能用到的其他系统也容易对接。FastAPI这是我们的“服务员”和“传菜员”。它会提供几个API接口比如“上传音频”、“查询结果”。当用户或者前端页面通过HTTP请求发来指令时FastAPI负责接收调用SenseVoice模型处理音频再把结果存到MySQL最后把响应返回去。选它是因为它用Python写和我们的模型天生一对而且性能好写起来也简单。简单来说流程就是用户上传音频 - FastAPI接收 - SenseVoice识别成文本 - 存入MySQL - 返回结果给用户。1.2 基础环境配置首先确保你的电脑上已经安装了Python建议3.8或以上版本和pip。然后我们创建一个专属的项目文件夹并安装必要的“工具包”。打开你的终端命令行依次执行下面的命令# 1. 创建一个新的项目目录 mkdir sensevoice-mysql-app cd sensevoice-mysql-app # 2. 创建一个虚拟环境推荐可以隔离项目依赖 python -m venv venv # 3. 激活虚拟环境 # 在 Windows 上 venv\Scripts\activate # 在 macOS/Linux 上 source venv/bin/activate # 4. 安装核心依赖包 pip install fastapi uvicorn pip install pydantic pip install sqlalchemy pymysql pip install python-multipart这里简单解释一下这几个包fastapi和uvicorn用来创建Web应用和运行服务器。pydantic用来定义数据模型确保进出接口的数据格式正确。sqlalchemy一个强大的数据库工具包让我们可以用Python代码来操作数据库不用写复杂的SQL语句。pymysql连接MySQL数据库的驱动。python-multipart让FastAPI能够处理文件上传。1.3 MySQL数据库安装与初始化数据库是我们的仓库得先把它建起来。如果你电脑上还没安装MySQL可以参考下面的步骤。如果已经有了可以跳过安装直接进行配置。对于新手我推荐使用MySQL官方安装包或者系统包管理器这样最省心。Windows用户可以去MySQL官网下载安装程序安装过程中会提示你设置root用户的密码请务必记住这个密码。macOS用户可以使用Homebrew安装命令是brew install mysql安装后启动服务brew services start mysql。Linux用户例如Ubuntu可以用sudo apt install mysql-server安装。安装完成后我们需要登录MySQL为我们的项目创建一个专用的数据库和用户。# 登录MySQL命令行会提示输入你安装时设置的root密码 mysql -u root -p登录成功后你会看到mysql提示符。在里面执行以下SQL命令-- 创建一个名为 voice_archive 的数据库 CREATE DATABASE voice_archive CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; -- 创建一个新用户用户名是 voice_user密码是 your_strong_password_here请务必换成你自己的复杂密码 CREATE USER voice_userlocalhost IDENTIFIED BY your_strong_password_here; -- 给这个新用户授予对 voice_archive 数据库的所有操作权限 GRANT ALL PRIVILEGES ON voice_archive.* TO voice_userlocalhost; -- 让权限设置立即生效 FLUSH PRIVILEGES; -- 退出MySQL命令行 EXIT;好了到现在为止我们的“厨房”已经准备妥当。数据库仓库建好了Python环境也配好了。接下来我们就要开始设计仓库的货架数据库表并准备我们的核心大厨——SenseVoice模型了。2. 构建项目核心模块环境搭好了现在我们来打造项目的核心部件。就像造车一样我们先设计好底盘和框架数据库模型然后把发动机语音识别模型装上去。2.1 设计数据存储结构数据怎么存决定了以后怎么用。我们来设计一张表存放每一次语音识别的记录。在项目根目录下创建一个名为database.py的文件。# database.py from sqlalchemy import create_engine, Column, Integer, String, Text, DateTime, Float from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker from datetime import datetime import os # 从环境变量读取数据库连接信息更安全。你也可以直接写死在代码里但不推荐。 # 格式mysqlpymysql://用户名:密码地址:端口/数据库名 DATABASE_URL os.getenv( DATABASE_URL, mysqlpymysql://voice_user:your_strong_password_herelocalhost:3306/voice_archive ) # 创建数据库引擎echoTrue 会在终端打印执行的SQL调试时有用上线后记得关掉。 engine create_engine(DATABASE_URL, echoTrue) # 创建会话工厂后续我们通过它来和数据库对话 SessionLocal sessionmaker(autocommitFalse, autoflushFalse, bindengine) # 声明基类我们的数据模型表都要继承它 Base declarative_base() class AudioRecord(Base): 音频识别记录表 __tablename__ audio_records # 定义各个字段列 id Column(Integer, primary_keyTrue, indexTrue, comment记录唯一ID) filename Column(String(255), nullableFalse, comment原始音频文件名) file_path Column(String(500), comment服务器上存储的文件路径可选) file_size Column(Integer, comment文件大小字节) duration Column(Float, comment音频时长秒) # 识别结果 recognized_text Column(Text, comment识别出的完整文本) language Column(String(10), defaultzh, comment识别出的语言如zh, en) confidence Column(Float, comment整体识别置信度如果模型提供) # 元信息 upload_time Column(DateTime, defaultdatetime.utcnow, comment上传时间) process_time Column(Float, comment处理耗时秒) # 你可以根据需要扩展更多字段 # speaker Column(String(100), comment说话人标识) # topic Column(String(200), comment音频主题标签) # 创建所有表如果不存在的话 Base.metadata.create_all(bindengine) # 提供一个获取数据库会话的依赖函数给FastAPI用 def get_db(): db SessionLocal() try: yield db finally: db.close()这张表就像是一个详细的登记簿。每处理一个音频文件就会在这里新增一行记录文件名、文件信息、识别出的文字、识别所用的时间等等。id字段是自动增长的主键确保每条记录都是唯一的。2.2 集成语音识别模型现在请出我们的大厨——SenseVoice-Small。我们需要下载模型并写一个函数来调用它。创建一个voice_model.py文件。首先安装SenseVoice的Python库这里假设它可以通过pip安装具体请以官方仓库为准pip install sense-voice然后编写模型调用代码# voice_model.py import torch from sensevoice import SenseVoice import time import logging logging.basicConfig(levellogging.INFO) logger logging.getLogger(__name__) class VoiceRecognizer: 语音识别器封装类 def __init__(self, model_path: str small): 初始化识别器 Args: model_path: 模型名称或本地路径。small 表示使用SenseVoice-Small预训练模型。 logger.info(f正在加载语音识别模型: {model_path}) self.start_time time.time() # 加载模型和处理器 # 注意这里根据SenseVoice库的实际API进行调整 # 假设其接口类似于 from_pretrained self.model SenseVoice.from_pretrained(model_path) # 可能还需要加载对应的处理器Tokenizer/FeatureExtractor # self.processor AutoProcessor.from_pretrained(model_path) self.model.eval() # 设置为评估模式 if torch.cuda.is_available(): self.model.to(cuda) logger.info(模型已加载至GPU) else: logger.info(使用CPU运行模型) load_time time.time() - self.start_time logger.info(f模型加载完毕耗时 {load_time:.2f} 秒) def transcribe_audio(self, audio_path: str) - dict: 识别单个音频文件 Args: audio_path: 音频文件路径 Returns: 包含识别结果和元数据的字典 logger.info(f开始处理音频: {audio_path}) process_start time.time() try: # 此处需要根据SenseVoice库的实际调用方式编写 # 示例伪代码 # 1. 读取音频文件 # import librosa 或 soundfile # audio, sr librosa.load(audio_path, sr16000) # 2. 预处理音频如果需要 # inputs self.processor(audio, sampling_ratesr, return_tensorspt) # 3. 执行识别 # with torch.no_grad(): # outputs self.model.generate(**inputs) # 4. 后处理获取文本 # text self.processor.decode(outputs[0], skip_special_tokensTrue) # 由于SenseVoice的具体API可能变化这里用一个模拟结果代替 # 实际使用时请替换为真实的模型调用代码 text [模拟识别结果] 这是从音频文件中识别出的示例文本。SenseVoice-Small模型能够准确地将语音转换为文字。 language zh confidence 0.95 process_time time.time() - process_start result { text: text, language: language, confidence: confidence, process_time: process_time } logger.info(f音频处理完成耗时 {process_time:.2f} 秒识别出 {len(text)} 个字符) return result except Exception as e: logger.error(f处理音频 {audio_path} 时出错: {e}) # 返回一个包含错误信息的结构或者直接抛出异常由上层处理 return { text: f[识别失败] {str(e)}, language: unknown, confidence: 0.0, process_time: time.time() - process_start } # 创建一个全局的识别器实例避免重复加载模型 recognizer VoiceRecognizer()这个类做了几件事初始化时加载模型如果支持GPU会用它加快速度提供了一个transcribe_audio方法你给它一个音频文件路径它就能返回识别出的文字、语言和置信度。重要提示上面的代码中模型调用部分# 示例伪代码注释块是伪代码。你需要根据sense-voice库最新的官方文档和API来填写真实的音频加载、预处理和模型推理代码。核心逻辑是加载音频 - 送给模型 - 拿到文本。3. 开发后端API服务框架和引擎都有了现在来打造车身——也就是我们的Web API服务。用户将通过这些API与我们系统交互。创建main.py文件。# main.py from fastapi import FastAPI, File, UploadFile, Depends, HTTPException, Query from fastapi.responses import JSONResponse from sqlalchemy.orm import Session import shutil import os from datetime import datetime, timedelta from typing import List, Optional # 导入我们之前写好的模块 from database import get_db, AudioRecord from voice_model import recognizer from pydantic import BaseModel # 定义Pydantic模型用于API请求和响应的数据验证 class AudioRecordCreate(BaseModel): 创建记录时使用的数据模型主要用于手动创建测试数据 filename: str recognized_text: str language: str zh confidence: Optional[float] None class AudioRecordResponse(BaseModel): 返回给前端的记录数据模型 id: int filename: str file_size: Optional[int] duration: Optional[float] recognized_text: str language: str confidence: Optional[float] upload_time: datetime process_time: Optional[float] class Config: from_attributes True # 允许从ORM对象转换 # 创建FastAPI应用实例 app FastAPI(titleSenseVoice语音识别归档系统, version1.0.0) # 确保有一个临时目录存放上传的文件 UPLOAD_DIR uploaded_audio os.makedirs(UPLOAD_DIR, exist_okTrue) app.post(/upload/, response_modelAudioRecordResponse) async def upload_and_transcribe( file: UploadFile File(...), db: Session Depends(get_db) ): 上传音频文件并自动识别结果存入数据库。 # 1. 保存上传的文件 file_location os.path.join(UPLOAD_DIR, file.filename) with open(file_location, wb) as buffer: shutil.copyfileobj(file.file, buffer) file_size os.path.getsize(file_location) # 2. 调用语音识别模型 recognition_result recognizer.transcribe_audio(file_location) # 3. 创建数据库记录 db_record AudioRecord( filenamefile.filename, file_pathfile_location, file_sizefile_size, # duration 可以从音频文件中解析这里简化处理 durationNone, recognized_textrecognition_result[text], languagerecognition_result[language], confidencerecognition_result[confidence], process_timerecognition_result[process_time] ) db.add(db_record) db.commit() db.refresh(db_record) # 获取创建后的记录包含自动生成的id等 # 4. 返回结果 return db_record app.get(/records/, response_modelList[AudioRecordResponse]) def get_records( skip: int Query(0, ge0, description跳过的记录数用于分页), limit: int Query(100, le500, description返回的记录数量), keyword: Optional[str] Query(None, description在识别文本中搜索关键词), db: Session Depends(get_db) ): 查询识别记录列表支持分页和关键词搜索。 query db.query(AudioRecord) if keyword: # 在 recognized_text 字段中进行模糊搜索 query query.filter(AudioRecord.recognized_text.contains(keyword)) # 按上传时间倒序排列最新的在前面 records query.order_by(AudioRecord.upload_time.desc()).offset(skip).limit(limit).all() return records app.get(/records/{record_id}, response_modelAudioRecordResponse) def get_record_by_id(record_id: int, db: Session Depends(get_db)): 根据ID获取单条识别记录的详细信息。 record db.query(AudioRecord).filter(AudioRecord.id record_id).first() if record is None: raise HTTPException(status_code404, detail记录未找到) return record app.get(/stats/) def get_statistics(db: Session Depends(get_db)): 获取系统统计信息。 total_records db.query(AudioRecord).count() # 最近24小时的处理记录数 last_24h datetime.utcnow() - timedelta(hours24) recent_records db.query(AudioRecord).filter(AudioRecord.upload_time last_24h).count() # 平均处理时间 avg_process_time_result db.query(func.avg(AudioRecord.process_time)).scalar() avg_process_time float(avg_process_time_result) if avg_process_time_result else 0.0 # 语言分布简单示例 lang_distribution db.query( AudioRecord.language, func.count(AudioRecord.id) ).group_by(AudioRecord.language).all() return { total_records: total_records, recent_24h_records: recent_records, average_process_time_seconds: round(avg_process_time, 2), language_distribution: dict(lang_distribution) } app.get(/search/) def search_text( q: str Query(..., min_length1, description搜索关键词), db: Session Depends(get_db) ): 在识别文本中进行全文搜索简易版。 # 这是一个简单的LIKE搜索。对于生产环境建议使用数据库的全文索引如MySQL的FULLTEXT。 records db.query(AudioRecord).filter( AudioRecord.recognized_text.contains(q) ).order_by(AudioRecord.upload_time.desc()).limit(50).all() # 返回简略信息 results [ { id: r.id, filename: r.filename, preview: r.recognized_text[:100] ... if len(r.recognized_text) 100 else r.recognized_text, upload_time: r.upload_time } for r in records ] return { keyword: q, count: len(results), results: results }这个main.py文件定义了四个核心接口/upload/(POST)最重要的接口。接收一个音频文件保存到本地调用我们的识别模型把结果存到数据库最后返回完整的记录信息。/records/(GET)获取所有识别记录的列表支持分页skip和limit参数和按文本内容关键词过滤。/records/{id}(GET)根据记录ID获取某一条记录的详细信息。/stats/(GET)获取系统统计看板数据比如总处理量、近期活跃度、平均处理时间等。/search/(GET)一个简单的文本搜索接口方便你快速查找提到某些关键词的录音。现在我们的后端服务在逻辑上已经完整了。你可以使用uvicorn在本地运行它进行测试。4. 部署到星图GPU平台本地测试没问题了就该把它放到一个24小时在线、并且有GPU加速的服务器上这样才算一个真正的服务。这里我们以星图GPU平台为例。4.1 准备部署文件在部署前我们需要创建两个重要的配置文件requirements.txt和Dockerfile如果平台支持容器化部署。1. 生成依赖列表文件 (requirements.txt)在项目根目录下运行pip freeze requirements.txt然后手动编辑这个文件确保包含了我们项目用到的所有核心包可能类似这样fastapi0.104.1 uvicorn[standard]0.24.0 pydantic2.5.0 sqlalchemy2.0.23 pymysql1.1.0 python-multipart0.0.6 sense-voicex.x.x # 请替换为实际版本 torch2.1.0 # 根据CUDA版本选择 # 以及其他依赖如 librosa, soundfile 等2. 创建Dockerfile可选但推荐如果平台支持从Docker镜像部署创建一个Dockerfile能极大简化环境配置。# Dockerfile # 使用带有Python和CUDA的基础镜像确保GPU支持 FROM pytorch/pytorch:2.1.0-cuda12.1-cudnn8-runtime WORKDIR /app # 复制依赖文件并安装 COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple # 复制应用代码 COPY . . # 创建上传文件目录 RUN mkdir -p uploaded_audio # 暴露FastAPI默认端口 EXPOSE 8000 # 启动命令 CMD [uvicorn, main:app, --host, 0.0.0.0, --port, 8000]4.2 平台部署流程不同的云平台步骤略有不同但大体流程相似。以下是概念性步骤注册与准备登录星图GPU平台完成实名认证并确保账户有足够的余额或资源配额。创建实例/容器服务在控制台选择创建“GPU容器实例”或“AI应用服务”。选择带有GPU如NVIDIA T4, V100等的规格。这对于语音识别模型的推理加速至关重要。上传代码与配置方式一代码仓库将你的项目代码包括main.py,database.py,voice_model.py,requirements.txt等推送到GitHub或GitLab等平台在创建服务时提供仓库地址。平台会自动拉取代码。方式二镜像仓库如果你构建了Docker镜像并推送到Docker Hub或平台的私有镜像仓库在创建服务时直接指定镜像地址。环境变量配置在平台的服务配置页面设置关键的环境变量。最重要的是数据库连接地址DATABASE_URL。因为部署后你的MySQL可能不在本地localhost了你需要将其修改为云数据库的内网或公网地址。例如DATABASE_URLmysqlpymysql://voice_user:your_passwordyour_mysql_host:3306/voice_archive同时设置UPLOAD_DIR等路径确保容器内有写入权限。存储卷挂载重要你需要挂载一个持久化存储卷到容器内的uploaded_audio目录。否则容器重启后用户上传的音频文件就丢失了。在平台配置中将存储卷挂载到/app/uploaded_audio。网络与端口确保容器的8000端口对外暴露映射到公网某个端口或配置内网负载均衡。启动与测试点击创建或部署。等待服务状态变为“运行中”后访问平台提供给你的公网IP和端口例如http://your-ip:port/docs你应该能看到FastAPI自动生成的交互式API文档Swagger UI。在这里直接测试/upload接口上传一个音频文件看看是否能成功返回识别结果。4.3 部署后验证与简单运维服务跑起来之后别忘了做这几件事功能验证使用API文档页面或curl、Postman等工具彻底测试所有接口。查看日志平台通常提供容器日志查看功能。关注启动时模型加载是否成功以及运行中是否有错误信息。性能观察在平台监控面板查看GPU使用率、内存消耗。如果并发请求多GPU使用率会明显上升说明加速生效。数据库连接确保云服务器能够访问你的MySQL数据库。可能需要将数据库的防火墙规则设置为允许该服务器IP访问。域名与HTTPS进阶如果你有域名可以在平台绑定并申请SSL证书开启HTTPS让服务更安全、更专业。5. 总结与展望走完这一整套流程我们从零搭建了一个具备完整功能的语音识别服务后端。它不仅仅是“能识别”更重要的是“能存、能查、能用”。你得到了一个结构清晰、可扩展的项目骨架。实际用起来你会发现这种将AI能力SenseVoice与数据管理MySQL和服务化FastAPI结合的模式非常实用。无论是处理内部会议记录还是分析用户客服录音这个系统都能作为一个可靠的基础。当然这只是一个起点。你可以基于它做很多有趣的扩展前端界面用Vue或React写个简单页面实现拖拽上传、结果列表展示和搜索体验就更完整了。任务队列如果处理的音频很大很多可以把识别任务丢到Celery或RQ这样的队列里异步处理避免HTTP请求超时。更高级的搜索用上MySQL的全文索引或者接入Elasticsearch让文本搜索更快更强大。结果后处理识别出的文本可以自动提取关键词、做摘要或者打上情感标签。多模型支持除了SenseVoice还可以集成Whisper等其他语音模型让系统能力更多元。部署在星图这样的GPU平台上最大的好处是省心。你不用自己维护物理服务器不用折腾CUDA环境按需使用GPU资源成本可控。当你的业务量增长时在平台上扩容也就是点几下鼠标的事情。希望这个实战教程能给你带来启发。技术的乐趣就在于用一个周末的时间把想法变成一个个可运行、可访问的服务。接下来就等你往里面填充自己的业务逻辑让它创造实际价值了。获取更多AI镜像想探索更多AI镜像和应用场景访问 CSDN星图镜像广场提供丰富的预置镜像覆盖大模型推理、图像生成、视频生成、模型微调等多个领域支持一键部署。