new4u's picture
Update app.py
0566672 verified
import torch
import gradio as gr
import yt_dlp as youtube_dl
from transformers import pipeline
from transformers.pipelines.audio_utils import ffmpeg_read
import tempfile
import os
MODEL_NAME = "openai/whisper-large-v3"
BATCH_SIZE = 8
FILE_LIMIT_MB = 100000
YT_LENGTH_LIMIT_S = 360000 # limit to 1 hour YouTube files
device = 0 if torch.cuda.is_available() else "cpu"
pipe = pipeline(
task="automatic-speech-recognition",
model=MODEL_NAME,
chunk_length_s=30,
device=device,
)
all_special_ids = pipe.tokenizer.all_special_ids
transcribe_token_id = all_special_ids[-5]
translate_token_id = all_special_ids[-6]
def transcribe(microphone, file_upload, task):
warn_output = ""
if (microphone is not None) and (file_upload is not None):
warn_output = (
"警告:您已经上传了一个音频文件并使用了麦克录制。 "
"录制文件将被使用上传的音频将被丢弃。"
)
elif (microphone is None) and (file_upload is None):
return "错误: 您必须使用麦克风录制或上传音频文件"
file = microphone if microphone is not None else file_upload
pipe.model.config.forced_decoder_ids = [
[2, transcribe_token_id if task == "transcribe" else translate_token_id]
]
# text = pipe(file, return_timestamps=True)["text"]
text = pipe(file, return_timestamps=True)
# trans to SRT
text = convert_to_srt(text)
return warn_output + text
def _return_yt_html_embed(yt_url):
video_id = yt_url.split("?v=")[-1]
HTML_str = (
f'<center> <iframe width="500" height="320" src="https://www.youtube.com/embed/{video_id}"> </iframe>'
" </center>"
)
return HTML_str
def download_yt_audio(yt_url, filename):
info_loader = youtube_dl.YoutubeDL()
try:
info = info_loader.extract_info(yt_url, download=False)
except youtube_dl.utils.DownloadError as err:
raise gr.Error(str(err))
file_length = info["duration_string"]
file_h_m_s = file_length.split(":")
file_h_m_s = [int(sub_length) for sub_length in file_h_m_s]
if len(file_h_m_s) == 1:
file_h_m_s.insert(0, 0)
if len(file_h_m_s) == 2:
file_h_m_s.insert(0, 0)
file_length_s = file_h_m_s[0] * 3600 + file_h_m_s[1] * 60 + file_h_m_s[2]
if file_length_s > YT_LENGTH_LIMIT_S:
yt_length_limit_hms = time.strftime("%HH:%MM:%SS", time.gmtime(YT_LENGTH_LIMIT_S))
file_length_hms = time.strftime("%HH:%MM:%SS", time.gmtime(file_length_s))
raise gr.Error(f"Maximum YouTube length is {yt_length_limit_hms}, got {file_length_hms} YouTube video.")
ydl_opts = {"outtmpl": filename, "format": "worstvideo[ext=mp4]+bestaudio[ext=m4a]/best[ext=mp4]/best"}
with youtube_dl.YoutubeDL(ydl_opts) as ydl:
try:
ydl.download([yt_url])
except youtube_dl.utils.ExtractorError as err:
raise gr.Error(str(err))
def yt_transcribe(yt_url, task):
html_embed_str = _return_yt_html_embed(yt_url)
with tempfile.TemporaryDirectory() as tmpdirname:
filepath = os.path.join(tmpdirname, "video.mp4")
download_yt_audio(yt_url, filepath)
with open(filepath, "rb") as f:
inputs = f.read()
inputs = ffmpeg_read(inputs, pipe.feature_extractor.sampling_rate)
inputs = {"array": inputs, "sampling_rate": pipe.feature_extractor.sampling_rate}
text = pipe(inputs,return_timestamps=True)
# text = pipe(inputs, batch_size=BATCH_SIZE, generate_kwargs={"language":"zh"}, return_timestamps=True)
# text = pipe(inputs, batch_size=BATCH_SIZE, generate_kwargs={"task": task}, return_timestamps=True)["text"]
# text = pipe("audio.mp3",return_timestamps=True)
#trans to SRT
text= convert_to_srt(text)
return html_embed_str, text
# SRT prepare
# Assuming srt format is a sequence of subtitles with index, time range and text
def convert_to_srt(input):
output = ""
index = 1
for chunk in input["chunks"]:
start, end = chunk["timestamp"]
text = chunk["text"]
if end is None:
end = "None"
# Convert seconds to hours:minutes:seconds,milliseconds format
start = format_time(start)
end = format_time(end)
output += f"{index}\n{start} --> {end}\n{text}\n\n"
index += 1
return output
# Helper function to format time
def format_time(seconds):
if seconds == "None":
return seconds
hours = int(seconds // 3600)
minutes = int((seconds % 3600) // 60)
seconds = int(seconds % 60)
milliseconds = int((seconds % 1) * 1000)
return f"{hours:02}:{minutes:02}:{seconds:02},{milliseconds:03}"
demo = gr.Blocks()
mf_transcribe = gr.Interface(
fn=transcribe,
inputs=[
gr.inputs.Audio(source="microphone", type="filepath", optional=True),
gr.inputs.Audio(source="upload", type="filepath", optional=True),
gr.inputs.Radio(["transcribe", "translate"], label="Task", default="transcribe"),
],
outputs="text",
layout="horizontal",
theme="huggingface",
title="Audio-to-Text-SRT 自动生成字幕",
description=(
"直接在网页录音或上传音频文件,加入Youtube连接,轻松转换为文字和字幕格式! 本演示采用"
f" 模型 [{MODEL_NAME}](https://huggingface.co./{MODEL_NAME}) 和 🤗 Transformers 转换任意长度的"
"音视频文件!使用GPU转换效率会大幅提高,大约每小时 $0.6 约相当于人民币 5 元。 如果您有较长内容,需要更快的转换速度,请私信作者微信 1259388,并备注“语音转文字”"
),
allow_flagging="never",
)
yt_transcribe = gr.Interface(
fn=yt_transcribe,
inputs=[
gr.inputs.Textbox(lines=1, placeholder="Paste the URL to a YouTube video here", label="YouTube URL"),
# gr.inputs.Radio(["转译", "翻译"], label="Task", default="transcribe")
gr.inputs.Radio(["transcribe", "translate"], label="Task", default="transcribe"),
],
outputs=["html", "text"],
layout="horizontal",
theme="huggingface",
title="Audio-to-Text-SRT 自动生成字幕",
description=(
"直接在网页录音或上传音频文件,加入Youtube连接,轻松转换为文字和字幕格式! 本演示采用"
f" 模型 [{MODEL_NAME}](https://huggingface.co./{MODEL_NAME}) 和 🤗 Transformers 转换任意长度的"
"音视频文件!使用GPU转换效率会大幅提高,大约每小时 $0.6 约相当于人民币 5 元。 如果您有较长内容,需要更快的转换速度,请私信作者微信 1259388,并备注“语音转文字”"
),
allow_flagging="never",
)
# # Load the images
# image1 = Image("wechatqrcode.jpg")
# image2 = Image("paypalqrcode.png")
# # Define a function that returns the images and captions
# def display_images():
# return image1, "WeChat Pay", image2, "PayPal"
with demo:
gr.TabbedInterface([mf_transcribe, yt_transcribe], ["转译音频成文字", "YouTube转字幕"])
# Create a gradio interface with no inputs and four outputs
# gr.Interface(display_images, [], [gr.outputs.Image(), gr.outputs.Textbox(), gr.outputs.Image(), gr.outputs.Textbox()], layout="horizontal").launch()
demo.launch(enable_queue=True)