当前位置: 首页 > article >正文

Python + WhisperX:解锁语音识别的高效新姿势

大家好,我是烤鸭:

   最近在尝试做视频的质量分析,打算利用asr针对声音判断是否有人声,以及识别出来的文本进行进一步操作。asr看了几个开源的,最终选择了openai的whisper,后来发现性能不行,又换了whisperX。这是一篇实战和代码为主的文章。

引言

OpenAI的Whisper是一款强大的自动语音识别(ASR)模型,它支持多语种识别,包括中文,且经过大量的多语言和多任务监督数据训练,具有出色的鲁棒性和准确性。Python作为一种功能强大的编程语言,其丰富的库和简洁的语法使其成为实现语音识别功能的理想选择。本文将介绍如何利用Python集成Whisper,实现高效的语音识别。

目前一天小千的视频调用,平均时长3分钟。显卡是4090,平均识别耗时30s以内,业务无压力。

Whisper模型简介

Whisper是一个开源的语音识别模型,它基于Transformer架构,通过从网络上收集的680,000小时多语言数据进行训练,能够实现对多种语言的准确识别。此外,该模型对口音、背景噪音和技术语言具有很好的鲁棒性,使得其在实际应用中具有广泛的应用前景。

WhisperX 地址:
https://github.com/m-bain/whisperX

安装环境

linux
显卡是 4090
cuda pytorch
ffmpeg

python 需要的依赖

pip install --no-cache-dir flask -i https://mirrors.aliyun.com/pypi/simple
pip install --no-cache-dir ffmpeg-python -i https://mirrors.aliyun.com/pypi/simple
pip install --no-cache-dir wheel -i https://mirrors.aliyun.com/pypi/simple
pip install --no-cache-dir zhconv -i https://mirrors.aliyun.com/pypi/simple
pip install --no-cache-dir numpy -i https://mirrors.aliyun.com/pypi/simple
pip install --no-cache-dir openai-whisper -i https://mirrors.aliyun.com/pypi/simple
pip install --no-cache-dir kafka-python -i https://mirrors.aliyun.com/pypi/simple
pip install --no-cache-dir fastapi -i https://mirrors.aliyun.com/pypi/simple
pip install --no-cache-dir uvicorn -i https://mirrors.aliyun.com/pypi/simple
pip install --no-cache-dir psutil -i https://mirrors.aliyun.com/pypi/simple
pip install --no-cache-dir gputil -i https://mirrors.aliyun.com/pypi/simple
pip install --no-cache-dir requests -i https://mirrors.aliyun.com/pypi/simple
pip install --no-cache-dir use-nacos -i https://mirrors.aliyun.com/pypi/simple
pip install --no-cache-dir pyyaml -i https://mirrors.aliyun.com/pypi/simple
pip install --no-cache-dir rocketmq-client-python -i https://mirrors.aliyun.com/pypi/simple

预期的功能

我想实现的是单台机器性能打满,并行识别asr,接口可以无限制接收请求,异步返回结果。

接口层

使用的是 fastapi 框架

import concurrent.futures
import os
import timeimport ffmpeg
import platform
import uvicorn
import asyncio
import psutil
from fastapi import FastAPI, BackgroundTasks, HTTPException, status, Query
from fastapi.responses import JSONResponse
import GPUtil
import requests
import jsonfrom dict_time import TimedMap
from parse_video_param import VideoRequest
from parse_video_callback_param import VideoCallbackRequest
from api_result import ApiResult
from whisper_processor import video_process
from whisperX_processor20241119 import video_process_whisperX
from logging_config import KAFKA_LOGGER
from nacos_config20241119 import register_nacosapp = FastAPI()
executor = concurrent.futures.ThreadPoolExecutor(max_workers=1)  # 线程池
# 定义CPU使用率阈值
threshold_cpu_usage = 95  # 例如,你希望CPU使用率不超过95%
threshold_gpu_usage_MB = 2400  # 例如,你希望显存使用大小 MB
timed_map = TimedMap()@app.post("/xxxx-video/whisperx")
async def parse_video(request: VideoRequest, background_tasks: BackgroundTasks):if not request or not request.path:raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="No video URL provided")print(f"parse_video, params:{request}")# 将处理任务添加到后台任务中,以便不阻塞主线程background_tasks.add_task(process_video_whisperx, request, background_tasks)# 立即返回处理中响应,告诉客户端请求已经被接收并正在处理api_result = ApiResult(1, "success", "", "")return JSONResponse(api_result.to_dict(), status_code=status.HTTP_200_OK)
# 异步函数来下载和处理视频
async def process_video_whisperx(request: VideoRequest, background_tasks: BackgroundTasks):def sync_process_video_whisperx(request):text = ''try:# 记录方法耗时start_time_single = time.time()# 下载视频并保存到临时文件url = request.pathchunk_size = request.chunk_size# 如果当前cpu使用率超过80%,就把该数据重新加到任务里# 获取当前CPU使用率cpu_usage = psutil.cpu_percent(interval=1, percpu=False)print(f"当前cpu利用率:{cpu_usage}")KAFKA_LOGGER.info(f"当前cpu利用率:{cpu_usage}")# 获取所有GPU的信息gpus = GPUtil.getGPUs()isGpuSuffiencent = True# 判断CPU使用率是否达到阈值if cpu_usage <= threshold_cpu_usage or isGpuSuffiencent:# 解析音频地址wavPath = getWav(url)print(f"mp3 url={wavPath}")# 不存在再去生成# 异步处理方法,解析音频这块可以忽略,也可以直接用视频地址if(not os.path.exists(wavPath)):(ffmpeg.input(url).output(wavPath, acodec='mp3').global_args('-loglevel', 'quiet').run())# 使用whisper处理音频text = process_audio_with_whisperx(wavPath, chunk_size)end_time_single = time.time()# 创建任务并添加到事件循环中,通知业务方asyncio.run(callback_task(request, text))print(f"视频地址:{url}, 函数执行耗时: {end_time_single - start_time_single}秒")KAFKA_LOGGER.info(f"视频地址:{url}, 函数执行耗时: {end_time_single - start_time_single}秒")# 清理临时文件os.remove(wavPath)else:print(f"当前cpu已超限,该视频重新加入队列:{url}")KAFKA_LOGGER.info(f"当前cpu已超限,该视频重新加入队列:{url}")# 暂停5秒time.sleep(5)# 重新加到队列里# 将处理任务添加到后台任务中,以便不阻塞主线程background_tasks.add_task(process_video_whisperx, request, background_tasks)except Exception as ex:print(f"sync_process_video error: {str(ex)}")KAFKA_LOGGER.error(f"sync_process_video error: {ex}")return textloop = asyncio.get_running_loop()# 使用线程池运行同步函数,避免阻塞异步事件循环return await loop.run_in_executor(executor, sync_process_video_whisperx, request)
# 获取文件路径
def getWav(input_video):try:# 判断系统是windows还是linuxoperating_system = platform.system()# 判断操作系统类型if operating_system == 'Windows':print("当前系统是Windows")audio_path = "C:\\Users\\xxx\\Downloads\\"else :audio_path = "/tmp/"# 从原始路径中获取文件名filename = os.path.basename(input_video)# 生成新文件的完整路径filename_without_extension = os.path.splitext(filename)[0]# 使用ffmpeg-python提取音频new_filename = os.path.join(audio_path, filename_without_extension) + ".mp3"except Exception as ex1:print("getWav ex:", str(ex1))return new_filename
# 音频解析
def process_audio_with_whisperx(audio_file_path: str, chunk_size: int) -> str:text = video_process_whisperX(audio_file_path, chunk_size)return text
# 异步回调
async def callback_task(request: VideoRequest, text: str):# 创建任务并添加到事件循环中task = asyncio.create_task(callback(request, text))# 等待任务完成await task
# 回调请求方法
async def callback(request: VideoRequest, text: str):# 目标URLurl = request.callback_url# JSON格式的参数data = {'id': request.id,'text': text,# 添加更多键值对...}# 设置一些键值对timed_map.set(request.path, json.dumps(data), timeout=1800)# 设置请求头,告诉服务器我们发送的是JSON数据headers = {'Content-Type': 'application/json'}# 设置超时时间,这里设置为5秒timeout = 5.0# 发送POST请求response = requests.post(url, data=json.dumps(data), headers=headers, timeout=timeout)print(f"url:{url},data: {json.dumps(data)},headers:{headers},response:{response}")# 检查请求是否成功if response.status_code == 200:# 请求成功,处理响应内容print("请求成功")print(response.json())  # 如果响应内容是JSON格式,可以直接解析else:# 请求失败,打印错误信息print(f"请求失败,状态码:{response.status_code}")print(response.text)  # 打印响应的文本内容
# 启动应用
if __name__ == "__main__":register_nacos()uvicorn.run(app, host="0.0.0.0", port=5000)    

whisperX

import whisperx
from whisperx.asr import FasterWhisperPipeline
import time
import torch
import gc
import osENV = os.environ.get('ENV', 'development')
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
if ENV == 'production':batch_size = 16compute_type = "float16"model_name = "large-v2"
else:# reduce if low on GPU membatch_size = 4# compute_type = "float16"  # change to "int8" if low on GPU mem (may reduce accuracy)# change to "int8" if low on GPU mem (may reduce accuracy)compute_type = "int8"model_name = "medium"
class WhisperXProcessor:fast_model: FasterWhisperPipelinedef loadModel(self):# 1. Transcribe with original whisper (batched)self.fast_model = whisperx.load_model("medium", device.type, compute_type=compute_type)print("模型加载完成")def asr(self, filePath: str, chunk_size: int):print(f'asr start filePath:{filePath}')start = time.time()audio = whisperx.load_audio(filePath)result = self.fast_model.transcribe(audio, batch_size=batch_size, chunk_size = chunk_size)print(result)end = time.time()print('识别使用的时间:', end - start, 's')torch.cuda.empty_cache()gc.collect()return resultdef video_process_whisperX(audio_path, chunk_size):app = WhisperXProcessor()app.loadModel()text = app.asr(audio_path, chunk_size)return text

结果验证

发送请求

curl -XPOST 'http://localhost:5000/xxxx-video/whisperX' -H 'Content-Type: application/json' -d '{"id":1,"path":"https://vc16-bd1-pl-agv.autohome.com.cn/video-26/0A33363922E51BDE/2025-02-10/FC68CC971BB8B9A46F15C4841F4F2CE2-200-wm.mp4?key=F77E8D3251C4560FA47E36563A5D5668&time=1739187850","callback_url":"http://localhost:8088/xxx/demo/testParseVideo"}'

结果日志,2分钟的视频,大概用了60s。

在这里插入图片描述

文章参考

ASR强力模型「Whisper」:解密Whisper

Python实现语音识别(whisperX)

相关文章:

Python + WhisperX:解锁语音识别的高效新姿势

大家好&#xff0c;我是烤鸭&#xff1a; 最近在尝试做视频的质量分析&#xff0c;打算利用asr针对声音判断是否有人声&#xff0c;以及识别出来的文本进行进一步操作。asr看了几个开源的&#xff0c;最终选择了openai的whisper&#xff0c;后来发现性能不行&#xff0c;又换了…...

redis 缓存击穿问题与解决方案

前言1. 什么是缓存击穿?2. 如何解决缓存击穿?怎么做?方案1: 定时刷新方案2: 自动续期方案3: 定时续期 如何选? 前言 当我们使用redis做缓存的时候,查询流程一般是先查询redis,如果redis未命中,再查询MySQL,将MySQL查询的数据同步到redis(回源),最后返回数据 流程图 为什…...

SAP HCM 批量核算工资报错如何定位错误 (SAT分析错误)

导读 簇目录 (表 RGDIR) 不包含任何记录:今天遇到一个很奇怪的问题&#xff0c;簇目录 (表 RGDIR) 不包含任何记录&#xff0c;而且出现的问题没有具体到员工编号&#xff0c;所以处理问题非常棘手。今天分享下我的处理方式&#xff0c;以便大家遇到这类的问题不知道如何下手。…...

常用共轭先验分布

内容来源 贝叶斯统计&#xff08;第二版&#xff09;中国统计出版社 正态分布的均值 总体分布 N ( θ , σ 2 ) N(\theta,\sigma^2) N(θ,σ2) 先验分布为正态分布 N ( μ , τ 2 ) N(\mu,\tau^2) N(μ,τ2) 样本 x i ( i 1 , 2 , ⋯ , n ) x_i(i1,2,\cdots,n) xi​(i1…...

浅聊MQ之Kafka与RabbitMQ简用

&#xff08;前记&#xff1a;内容有点多&#xff0c;先看目录再挑着看。&#xff09; Kafka与RabbitMQ的使用举例 Kafka的使用举例 安装与启动&#xff1a; 从Apache Kafka官网下载Kafka中间件的运行脚本。解压后&#xff0c;通过命令行启动Zookeeper&#xff08;Kafka的运行…...

服务器被暴力破解的一次小记录

1. 网络架构 家里三台主机&#xff0c;其他一台macmini 启用ollama运行大模型的服务&#xff0c;主机1用来部署一些常用的服务如&#xff1a;mysql, photoprism等&#xff0c;服务器作为网关部署docker, 并且和腾讯云做了内网穿透。服务器部署了1panel用来管理服务并且监控&…...

3. 导入官方dashboard

官方dashboard&#xff1a;https://grafana.com/grafana/dashboards 1. 点击仪表板 - 新建 - 导入 注&#xff1a;有网络的情况想可以使用ID&#xff0c;无网络情况下使用仪表板josn文件 2. 在官方dashboard网页上选择符合你现在数据源的dashboard - 点击进入 3. 下拉网页选…...

国家队出手!DeepSeek上线国家超算互联网平台!

目前,国家超算互联网平台已推出 DeepSeek – R1 模型的 1.5B、7B、8B、14B 版本,后续还会在近期更新 32B、70B 等版本。 DeepSeek太火爆了!在这个春节档,直接成了全民热议的话题。 DeepSeek也毫无悬念地干到了全球增速最快的AI应用。这几天,国内的云计算厂家都在支持Dee…...

第6章 6.4 ASP.NET Core Web API各种技术及选择

6.4.1 控制器父类用哪个 6.2小节和6.3小节所演示的ASP.NET Core Web API 的控制器类都继承自ControllerBase&#xff0c;而6.1中MVC的控制器继承自Controller&#xff0c;Controller又继承自ControllerBase。 所以&#xff0c;一般情况下&#xff0c;编写的WebAPI控制器类继承…...

python导入模块的方式

在python开发中&#xff0c;巧用模块导入可简化开发&#xff0c;提高开发效率。下面简介下模块使用使用事项&#xff1a; 一、模块的使用&#xff1a; 模块 就好⽐是 ⼯具包&#xff0c;要想使⽤这个⼯具包中的⼯具&#xff0c;就需要 使用import导⼊ 这个模块每⼀个以扩展名…...

【Linux】Ubuntu Linux 系统——Node.js 开发环境

ℹ️大家好&#xff0c;我是练小杰&#xff0c;今天星期五了&#xff0c;同时也是2025年的情人节&#xff0c;今晚又是一个人的举个爪子&#xff01;&#xff01; &#x1f642; 本文是有关Linux 操作系统中 Node.js 开发环境基础知识&#xff0c;后续我将添加更多相关知识噢&a…...

使用pyCharm创建Django项目

使用pyCharm创建Django项目 1. 创建Django项目虚拟环境&#xff08;最新版版本的Django) 使用pyCharm的创建项目功能&#xff0c;选择Django,直接创建。 2. 创建Django项目虚拟环境&#xff08;安装特定版本&#xff09; 2.1创建一个基础的python项目 2.2 安装指定版本的D…...

【前端框架】深入Vue 3组件开发:构建高效灵活的前端应用

一、引言 Vue 3作为一款流行的前端框架&#xff0c;其组件化系统是构建大型应用的核心。通过将应用拆分为多个可复用的组件&#xff0c;不仅能提高代码的可维护性与复用性&#xff0c;还能让开发团队进行高效的协作。本文将深入探讨Vue 3组件开发的各个方面&#xff0c;帮助开…...

基于Python flask-sqlalchemy的SQLServer数据库管理平台

适应场景&#xff1a; 主要用于帮助DBA自动化很多日常工作&#xff0c;包括&#xff1a; 数据库状态监控 性能问题诊断 日志分析 自动巡检 问题告警 系统截图&#xff1a; main.py from flask import Blueprint, render_template, request, flash, redirect, url_for f…...

npm运行Vue项目报错 error:0308010c:digital envelope routines::unsupported

大家好&#xff0c;我是 程序员码递夫。 问题 VSCode 运行Vue项目&#xff0c;提示错误&#xff1a; building 2/2 modules 0 activeError: error:0308010c:digital envelope routines::unsupported 解决方法 原因是 npm 高版本(大于17)&#xff0c;对ssl的处理做了改进&…...

计数排序

目录 计数排序原理和步骤&#xff1a; 完整代码实现&#xff1a; 计数排序原理和步骤&#xff1a; 当一段数据比较集中在一个范围&#xff0c;比如 98&#xff0c;95&#xff0c;98&#xff0c;91&#xff0c;90&#xff0c;93&#xff0c;94&#xff0c;97&#xff0c;93&…...

MyBatis拦截器终极指南:从原理到企业级实战

在本篇文章中&#xff0c;我们将深入了解如何编写一个 MyBatis 拦截器&#xff0c;并通过一个示例来展示如何在执行数据库操作&#xff08;如插入或更新&#xff09;时&#xff0c;自动填充某些字段&#xff08;例如 createdBy 和 updatedBy&#xff09;信息。本文将详细讲解拦…...

Pythong 解决Pycharm 运行太慢

Pythong 解决Pycharm 运行太慢 官方给Pycharm自身占用的最大内存设低估了限制,我的Pycharm刚开始默认是256mb。 首先找到自己的Pycharm安装目录 根据合适自己的改 保存&#xff0c;重启Pycharm...

双ESP8266-01S通讯UDP配置

第一台ESP8266(发送命令需要勾---发送新行) ATCWMODE3 ATCWSAP_DEF"CAR_wifi_Master","12345678",5,3 //设置本地wifi名称以及密码 ATCIPSTA_DEF"192.168.4.1" //设置本地IP ATCIFSR …...

Molecular Communication(分子通信)与 Molecular Semantic Communication(分子语义通信)

1. 引言 随着传统无线通信在极端环境&#xff08;如微观生物体内、海洋深处&#xff09;中的局限性凸显&#xff0c;分子通信&#xff08;Molecular Communication, MC&#xff09;成为一种新型通信范式。分子通信通过分子作为信息载体&#xff0c;在纳米尺度上传输信息&#…...

Cookie:网页浏览背后的“小秘密”

在现代互联网的世界里&#xff0c;Cookie 是一个几乎无处不在的概念。它不仅影响着我们的网页浏览体验&#xff0c;还在背后默默地支持着许多网站的功能和服务。本文将带你全面了解 Cookie 的原理、作用、安全性以及如何管理它们。 一、什么是 Cookie&#xff1f; Cookie 是一…...

日语学习-日语知识点小记-构建基础-JLPT-N4N5阶段(6):動詞ない形について句型

日语学习-日语知识点小记-构建基础-JLPT-N4&N5阶段(6):動詞ない形について句型 1、前言(1)情况说明(2)工程师的信仰2、知识点(1)~動詞な形 +なければなりません(2)~動詞な形  + なくてもいいです(3)に まで までに :区別3、单词(1)日语单词…...

华纳云:如何从服务器日志中发现僵尸进程?

在 CentOS 系统中&#xff0c;僵尸进程通常指那些已经完成执行但仍然在进程表中存在的进程。它们没有实际的执行&#xff0c;但仍然占用系统资源&#xff0c;通常会出现在父进程没有及时回收子进程的状态下。虽然僵尸进程本身不消耗 CPU 或内存资源&#xff0c;但它们会占用进程…...

fastadmin 接口请求提示跨域

问题描述 小程序项目&#xff0c;内嵌h5页面&#xff0c;在h5页面调用后端php接口&#xff0c;提示跨域。网上查找解决方案如下&#xff1a; 1&#xff0c;设置header // 在入口文件index.php直接写入直接写入 header("Access-Control-Allow-Origin:*"); header(&q…...

NHANES指标推荐:DDA!

文章题目&#xff1a;Association of dietary decanoic acid intake with diabetes or prediabetes: an analysis from NHANES 2005-2016 DOI&#xff1a;10.3389/fnut.2024.1483045 中文标题&#xff1a;饮食中癸酸摄入量与糖尿病或糖尿病前期的关系&#xff1a;2005-2016 年 …...

用大模型学大模型04-模型与网络

目前已经学完深度学习的数学基础&#xff0c;开始学习各种 模型和网络阶段&#xff0c;给出一个从简单到入门的&#xff0c;层层递进的学习路线。并给出学习每种模型需要的前置知识。增加注意力机制&#xff0c;bert, 大模型&#xff0c;gpt, transformer&#xff0c; MOE等流行…...

PostgreSQL 数据库压力测试指南

一、为什么需要压力测试&#xff1f; 数据库需要进行压力测试的原因主要包括以下几个方面&#xff1a; 性能评估&#xff1a;通过压力测试&#xff0c;可以了解数据库在高负载情况下的性能表现&#xff0c;包括响应时间、吞吐量和资源利用率等。这有助于确定系统的性能瓶颈。 …...

oppo,康冠科技25届春招内推

oppo&#xff0c;康冠科技25届春招内推 ①康冠科技25届春招 【职位】算法、软件、硬件、技术&#xff0c;结构设计&#xff0c;供应链&#xff0c;产品&#xff0c;职能&#xff0c;商务 【一键内推】https://sourl.cn/2Mm9Lk 【内推码】EVBM88 ②OPPO 2025届春招内推 招聘岗位…...

元学习之孪生网络Siamese Network

简介&#xff1a;元学习是一种思想&#xff0c;一般以神经网络作为特征嵌入的工具&#xff0c;实现对数据特征的提取&#xff0c;然后通过构造某种指标以引导优化器对模型参数进行优化。而最小化距离是最常见的学习目标&#xff0c;这就是熟知的度量学习&#xff0c;度量学习里…...

Python----PyQt开发(PyQt高级:组件大小,界面位置,按钮,文本显示,文本输入,字体大小)

一、大小 setMinimumSize(width, height) 描述: 设置控件的最小尺寸。控件不会被缩小到比这个尺寸更小的大小。 参数: width: 最小宽度&#xff08;以像素为单位&#xff09;。 height: 最小高度&#xff08;以像素为单位&#xff09;。 button.setMinimumSize(100, …...