实战whisper第二天:直播语音转字幕(全部代码和详细部署步骤)

直播语音实时转字幕:

基于Whisper的实时直播语音转录或翻译是一项使用OpenAI的Whisper模型实现的技术,它能够实时将直播中的语音内容转录成文本,甚至翻译成另一种语言。这一过程大致分为三个步骤:捕获直播音频流、语音识别(转录)以及翻译(如果需要)。下面详细解释其原理和意义。

原理

  1. 捕获直播音频流: 首先,需要从直播源捕获音频流。这通常通过软件工具实现,如ffmpegstreamlink,它们可以接入直播平台(如Twitch、YouTube等)的直播流,并提取音频数据。

  2. 语音识别(转录): 捕获到的音频流被送入Whisper模型进行语音识别。Whisper是OpenAI开发的一款强大的语音识别模型,它能够准确地将语音转换成文本。该模型训练于多种语言的大量数据集上,因此具有高度的准确性和多语言识别能力。

  3. 翻译(可选): 如果需要将转录的文本翻译成另一种语言,可以进一步使用机器翻译模型(如OpenAI的GPT、Google Translate等)对转录文本进行翻译。

意义

  1. 提高可及性: 通过实时转录直播语音,听障人士和不懂直播原语言的观众也能够理解内容,大大提高了直播内容的可及性。

  2. 内容归档与搜索: 转录生成的文本可以作为直播内容的归档,便于未来搜索和回顾。相比视频数据,文本更容易被搜索引擎索引,从而提高内容的发现性。

  3. 多语言翻译: 实时翻译可以让不同语言的观众理解和享受直播内容,促进跨语言、跨文化的交流。

  4. 学习和教育: 对于教育直播,实时转录和翻译能够帮助学生更好地理解教学内容,尤其是对于非母语学习者。

  5. 内容审核: 转录文本还可以用于自动内容审核,帮助直播平台监控和管理不适宜的内容。 

一、部署 

下载stream-translator

GitHub - fortypercnt/stream-translator

实战whisper语音识别第一天,部署服务器,可远程访问,实时语音转文字(全部代码和详细部署步骤)-CSDN博客

如果在之前的文章,实战whisper语音识别第一天,部署服务器,配置过环境,可跳过下面安装。

git clone https://github.com/fortypercnt/stream-translator.git
pip install -r requirements.txt 

模型下载: 

large-v3模型:https://huggingface.co/Systran/faster-whisper-large-v3/tree/main
large-v2模型:https://huggingface.co/guillaumekln/faster-whisper-large-v2/tree/main
large-v2模型:https://huggingface.co/guillaumekln/faster-whisper-large-v1/tree/main
medium模型:https://huggingface.co/guillaumekln/faster-whisper-medium/tree/main
small模型:https://huggingface.co/guillaumekln/faster-whisper-small/tree/main
base模型:https://huggingface.co/guillaumekln/faster-whisper-base/tree/main
tiny模型:https://huggingface.co/guillaumekln/faster-whisper-tiny/tree/main

经测试large-v3模型需要10G显存以上。显存不够的可以用小模型。

使用方法:

python translator.py 直播链接

这个translator.py是进行实时翻译,不想翻译可运行下面代码

二、代码

translator1.py:

import argparse
import sys
import signal
from datetime import datetimeimport ffmpeg
import numpy as np
import whisper
from whisper.audio import SAMPLE_RATEclass RingBuffer:def __init__(self, size):self.size = sizeself.data = []self.full = Falseself.cur = 0def append(self, x):if self.size <= 0:returnif self.full:self.data[self.cur] = xself.cur = (self.cur + 1) % self.sizeelse:self.data.append(x)if len(self.data) == self.size:self.full = Truedef get_all(self):all_data = []for i in range(len(self.data)):idx = (i + self.cur) % self.sizeall_data.append(self.data[idx])return all_datadef clear(self):self.data = []self.full = Falseself.cur = 0def open_stream(stream, direct_url, preferred_quality):if direct_url:try:process = (ffmpeg.input(stream, loglevel="panic").output("pipe:", format="s16le", acodec="pcm_s16le", ac=1, ar=SAMPLE_RATE).run_async(pipe_stdout=True))except ffmpeg.Error as e:raise RuntimeError(f"Failed to load audio: {e.stderr.decode()}") from ereturn process, Noneimport streamlinkimport subprocessimport threadingstream_options = streamlink.streams(stream)if not stream_options:print("No playable streams found on this URL:", stream)sys.exit(0)option = Nonefor quality in [preferred_quality, 'audio_only', 'audio_mp4a', 'audio_opus', 'best']:if quality in stream_options:option = qualitybreakif option is None:# Fallbackoption = next(iter(stream_options.values()))def writer(streamlink_proc, ffmpeg_proc):while (not streamlink_proc.poll()) and (not ffmpeg_proc.poll()):try:chunk = streamlink_proc.stdout.read(1024)ffmpeg_proc.stdin.write(chunk)except (BrokenPipeError, OSError):passcmd = ['streamlink', stream, option, "-O"]streamlink_process = subprocess.Popen(cmd, stdout=subprocess.PIPE)try:ffmpeg_process = (ffmpeg.input("pipe:", loglevel="panic").output("pipe:", format="s16le", acodec="pcm_s16le", ac=1, ar=SAMPLE_RATE).run_async(pipe_stdin=True, pipe_stdout=True))except ffmpeg.Error as e:raise RuntimeError(f"Failed to load audio: {e.stderr.decode()}") from ethread = threading.Thread(target=writer, args=(streamlink_process, ffmpeg_process))thread.start()return ffmpeg_process, streamlink_processdef main(url, model="large-v3", interval=5, preferred_quality="audio_only", direct_url=False, **decode_options):print("Loading model...")model = whisper.load_model(model)print("Opening stream...")ffmpeg_process, _ = open_stream(url, direct_url, preferred_quality)def handler(signum, frame):ffmpeg_process.kill()sys.exit(0)signal.signal(signal.SIGINT, handler)n_bytes = interval * SAMPLE_RATE * 2  # Factor 2 comes from reading the int16 stream as bytesaudio_buffer = RingBuffer(1)  # No need for a history buffer since we're just doing real-time transcriptiontry:while True:in_bytes = ffmpeg_process.stdout.read(n_bytes)if not in_bytes:breakaudio = np.frombuffer(in_bytes, np.int16).flatten().astype(np.float32) / 32768.0audio_buffer.append(audio)result = model.transcribe(np.concatenate(audio_buffer.get_all()), **decode_options)print(f'{datetime.now().strftime("%H:%M:%S")} {result["text"]}')audio_buffer.clear()  # Clear the buffer after each transcriptionfinally:ffmpeg_process.kill()def cli():parser = argparse.ArgumentParser(description="Real-time audio transcription from streams.")parser.add_argument('URL', type=str, help='Stream website and channel name, e.g. twitch.tv/forsen')parser.add_argument('--model', type=str, default='large-v3', help='Whisper model for transcription.')parser.add_argument('--interval', type=int, default=5, help='Interval between transcription in seconds.')parser.add_argument('--preferred_quality', type=str, default='audio_only', help='Preferred stream quality.')parser.add_argument('--direct_url', action='store_true', help='Pass the URL directly to ffmpeg.')args = parser.parse_args().__dict__url = args.pop("URL")main(url, **args)if __name__ == '__main__':cli()
python translator1.py https://www.huya.com/kpl

虎牙kpl的直播,文字转录:

还有繁体字,修改代码,繁体转简体:

pip install opencc-python-reimplemented

 translator2.py:

import argparse
import sys
import signal
from datetime import datetimeimport ffmpeg
import numpy as np
import whisper
from whisper.audio import SAMPLE_RATE
import openccclass RingBuffer:def __init__(self, size):self.size = sizeself.data = []self.full = Falseself.cur = 0def append(self, x):if self.size <= 0:returnif self.full:self.data[self.cur] = xself.cur = (self.cur + 1) % self.sizeelse:self.data.append(x)if len(self.data) == self.size:self.full = Truedef get_all(self):all_data = []for i in range(len(self.data)):idx = (i + self.cur) % self.sizeall_data.append(self.data[idx])return all_datadef clear(self):self.data = []self.full = Falseself.cur = 0def open_stream(stream, direct_url, preferred_quality):if direct_url:try:process = (ffmpeg.input(stream, loglevel="panic").output("pipe:", format="s16le", acodec="pcm_s16le", ac=1, ar=SAMPLE_RATE).run_async(pipe_stdout=True))except ffmpeg.Error as e:raise RuntimeError(f"Failed to load audio: {e.stderr.decode()}") from ereturn process, Noneimport streamlinkimport subprocessimport threadingstream_options = streamlink.streams(stream)if not stream_options:print("No playable streams found on this URL:", stream)sys.exit(0)option = Nonefor quality in [preferred_quality, 'audio_only', 'audio_mp4a', 'audio_opus', 'best']:if quality in stream_options:option = qualitybreakif option is None:# Fallbackoption = next(iter(stream_options.values()))def writer(streamlink_proc, ffmpeg_proc):while (not streamlink_proc.poll()) and (not ffmpeg_proc.poll()):try:chunk = streamlink_proc.stdout.read(1024)ffmpeg_proc.stdin.write(chunk)except (BrokenPipeError, OSError):passcmd = ['streamlink', stream, option, "-O"]streamlink_process = subprocess.Popen(cmd, stdout=subprocess.PIPE)try:ffmpeg_process = (ffmpeg.input("pipe:", loglevel="panic").output("pipe:", format="s16le", acodec="pcm_s16le", ac=1, ar=SAMPLE_RATE).run_async(pipe_stdin=True, pipe_stdout=True))except ffmpeg.Error as e:raise RuntimeError(f"Failed to load audio: {e.stderr.decode()}") from ethread = threading.Thread(target=writer, args=(streamlink_process, ffmpeg_process))thread.start()return ffmpeg_process, streamlink_processdef main(url, model="large-v3", interval=5, preferred_quality="audio_only", direct_url=False, **decode_options):print("Loading model...")model = whisper.load_model(model)print("Opening stream...")ffmpeg_process, _ = open_stream(url, direct_url, preferred_quality)converter = opencc.OpenCC('t2s')  # 创建繁体转简体的转换器def handler(signum, frame):ffmpeg_process.kill()sys.exit(0)signal.signal(signal.SIGINT, handler)n_bytes = interval * SAMPLE_RATE * 2  # Factor 2 comes from reading the int16 stream as bytesaudio_buffer = RingBuffer(1)try:while True:in_bytes = ffmpeg_process.stdout.read(n_bytes)if not in_bytes:breakaudio = np.frombuffer(in_bytes, np.int16).flatten().astype(np.float32) / 32768.0audio_buffer.append(audio)result = model.transcribe(np.concatenate(audio_buffer.get_all()), **decode_options)result_text = converter.convert(result["text"])  # 将繁体转换为简体print(f'{datetime.now().strftime("%H:%M:%S")} {result_text}')audio_buffer.clear()finally:ffmpeg_process.kill()def cli():parser = argparse.ArgumentParser(description="Real-time audio transcription from streams.")parser.add_argument('URL', type=str, help='Stream website and channel name, e.g. twitch.tv/forsen')parser.add_argument('--model', type=str, default='large-v3', help='Whisper model for transcription.')parser.add_argument('--interval', type=int, default=5, help='Interval between transcription in seconds.')parser.add_argument('--preferred_quality', type=str, default='audio_only', help='Preferred stream quality.')parser.add_argument('--direct_url', action='store_true', help='Pass the URL directly to ffmpeg.')args = parser.parse_args().__dict__url = args.pop("URL")main(url, **args)if __name__ == '__main__':cli()
python translator2.py https://www.huya.com/kpl

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/760821.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

在线教育话术(1W字精选)

产品结构图 Nginx实现代理 问&#xff1a;我们在本机的host文件中配置了域名映射&#xff0c;都是同一个服务器。我们只需要输入对应的域名就可以到对应的界面&#xff0c;这是怎么实现的&#xff1f; 答&#xff1a;主要就是通过Nginx反向代理来实现的&#xff0c;Nginx会先…

2024-03-20 作业

作业要求&#xff1a; 1> 创建一个工人信息库&#xff0c;包含工号&#xff08;主键&#xff09;、姓名、年龄、薪资。 2> 添加三条工人信息&#xff08;可以完整信息&#xff0c;也可以非完整信息&#xff09; 3> 修改某一个工人的薪资&#xff08;确定的一个&#x…

电影aac是什么意思?如何播放、转换、编辑aac?

"电影AAC"这个术语可能是指电影中的音频编码格式。AAC&#xff08;Advanced Audio Coding&#xff09;是一种常见的音频编码格式&#xff0c;通常用于压缩音频文件&#xff0c;以在保持高质量的同时减小文件大小。在电影中&#xff0c;AAC格式的音频通常用于提供高质…

Java学习笔记NO.25

T2.编写程序实现乐手弹奏乐器。乐手可以弹奏不同的乐器从而发出不同的声音。可以弹奏的乐器包括二胡、钢琴和琵琶。要求&#xff1a; (1)定义乐器类Instrument&#xff0c;包括方法makeSound() (2)定义乐器类的子类&#xff1a;二胡Erhu、钢琴Piano和小提琴Violin (3)定义乐手类…

H12-811题库(带解析,亲测高分可以通过)

大家可以直接点赞关注后&#xff0c;加作者微信&#xff08;备注“CSDN”&#xff09;就可以获取&#xff0c;微信在文章最后&#xff01; 808、[单选题]某公司网管要进行网络规划的时候&#xff0c;能够要让PC1访问PC2的数据包从G0/0/0口走(图上G0/0/2)。PC2访问PC1的数据包从…

浅谈RPC的理解

浅谈RPC的理解 前言RPC体系Dubbo架构最后 前言 本文中部分知识涉及Dubbo&#xff0c;需要对Dubbo有一定的理解&#xff0c;且对源码有一定了解 如果不了解&#xff0c;可以参考学习我之前的文章&#xff1a; 浅谈Spring整合Dubbo源码&#xff08;Service和Reference注解部分&am…

网络世界的城关——网卡

网络世界的城关——网卡 网卡到底是什么&#xff1f;网卡的功能网卡的真面目网卡的组成网卡的种类1.基于网络连接方式分类2.基于总线接口类型分类3.基于接口类型的分类4.基于传输速度的分类5.基于应用领域的分类 网卡到底是什么&#xff1f; 网卡我们可以这样通俗地理解&#x…

游戏平台出海运营有难度吗?

随着全球互联网的飞速发展&#xff0c;游戏产业已经成为了文化娱乐领域的重要支柱。在这个背景下&#xff0c;越来越多的游戏平台开始寻求出海运营&#xff0c;以拓展海外市场&#xff0c;实现更大的商业价值。然而&#xff0c;游戏平台出海运营并非易事&#xff0c;其中涉及到…

‍Java OCR技术全面解析:六大解决方案比较

博主猫头虎的技术世界 &#x1f31f; 欢迎来到猫头虎的博客 — 探索技术的无限可能&#xff01; 专栏链接&#xff1a; &#x1f517; 精选专栏&#xff1a; 《面试题大全》 — 面试准备的宝典&#xff01;《IDEA开发秘籍》 — 提升你的IDEA技能&#xff01;《100天精通鸿蒙》 …

个人可以做知识付费网站吗

个人可以做知识付费网站吗 个人能够做学问付费网站吗&#xff1f;答案是肯定的&#xff01;如今个人做学问付费网站并不需求太多的资金和技术支持&#xff0c;我们只需求购置一台效劳器或虚拟主机&#xff0c;然后在该主机空间上搭建一个WordPress网站&#xff0c;最后运用带有…

【C语言】数9的个数

编写程序数一下 1到 100 的所有整数中出现多少个数字9 1&#xff0c;首先产生1~100的数字。然猴设法得到数9个数&#xff0c;例如个位&#xff1a;19%109&#xff0c;十位&#xff1a;91/109。 2&#xff0c;每次得到数九的时候&#xff0c;就用一个变量来进行计数。 代码如…

【极简无废话】open3d可视化torch、numpy点云

建议直接看文档&#xff0c;很多都代码老了&#xff0c;注意把代码版本调整到你使用的open3d的版本&#xff1a; https://www.open3d.org/docs/release/tutorial/visualization/visualization.html 请注意open3d应该已经不支持centos了&#xff01; 从其他格式转换成open3d…

MySQL 索引的10 个核心要点

文章目录 &#x1f349;1. 索引底层采用什么数据结构&#xff1f;为什么不用hash&#x1f349;2. B树与B树区别&#xff1f;为何用B树&#xff1f;&#x1f349;3. 自增主键理解&#xff1f;&#x1f349;4. 为什么自增主键不连续&#x1f349;5. Innodb为什么推荐用自增ID&…

ISP技术综述

原文来自技术前沿&#xff1a;ISP芯片终极进化——VP芯片&#xff08;AI视觉处理器&#xff09; 目录 1.计算机视觉的定义 2.与计算机视觉密切相关的概念与计算机视觉密切相关的概念有机器视觉&#xff0c;图像处理与分析&#xff0c;图像和视频理解。 3.计算机视觉的应用 …

RIPGeo代码理解(四)model.py( RIPGeo的核心源代码)

​ 代码链接:RIPGeo代码实现 ├── lib # 包含模型(model)实现文件 │ |── layers.py # 注意力机制的代码。 │ |── model.py # TrustGeo的核心源代码。 │ |── sublayers.py # layer.py的支持文件。 │ |── utils.…

六种GPU虚拟化:除了直通、全虚拟化 (vGPU)还有谁?

在大类上计算虚拟化技术有这3种&#xff1a; 软件模拟、直通独占(如网卡独占、显卡独占)、直通共享&#xff08;如vCPU 、vGPU&#xff09;。但对于显卡GPU而言我总结细化出至少这6种分类&#xff1a; 第一种、软件模拟&#xff08;eg sGPU&#xff09;, 又叫半虚拟化。第二种…

RIPGeo代码理解(三)layers.py(注意力机制的代码)

代码链接:RIPGeo代码实现 ├── lib # 包含模型(model)实现文件 │ |── layers.py # 注意力机制的代码。 │ |── model.py # TrustGeo的核心源代码。 │ |── sublayers.py # layer.py的支持文件。 │ |── utils.py #…

STM32CubeMX学习笔记23---FreeRTOS(任务的挂起与恢复)

1、硬件设置 本实验通过freertos创建两个任务来分别控制LED2和LED3的亮灭&#xff0c;需要用到的硬件资源 LED2和LED3指示灯串口 2、STM32CubeMX设置 根据上一章的步骤创建两个任务&#xff1a;STM32CubeMX学习笔记22---FreeRTOS&#xff08;任务创建和删除&#xff09;-CS…

FPGA - SPI总线介绍以及通用接口模块设计

一&#xff0c;SPI总线 1&#xff0c;SPI总线概述 SPI&#xff0c;是英语Serial Peripheral interface的缩写&#xff0c;顾名思义就是串行外围设备接口。串行外设接口总线(SPI)&#xff0c;是一种高速的&#xff0c;全双工&#xff0c;同步的通信总线&#xff0c;并且在芯片的…

【C++】为什么vector的地址与首元素地址不同?

文章目录 一、问题发现&#xff1a;二、结果分析三、问题解析 一、问题发现&#xff1a; &vector和&vector[0]得到的两个地址居然不相同&#xff0c;对数组array取变量名地址和取首元素地址的结果是相同的。这是为啥呢&#xff1f; 使用下面代码进行验证&#xff1a;…