|
|
|
|
|
FONT_URL = 'https://fonts.gstatic.com/s/inter/v13/UcCO3FwrK3iLTeHuS_fvQtMwCp50KnMw2boKoduKmMEVuLyfAZ9hjQ.ttf' |
|
from moviepy.editor import * |
|
import whisper |
|
from cached_path import cached_path |
|
from moviepy.video.tools.subtitles import SubtitlesClip |
|
import torch |
|
import tempfile |
|
import gradio as gr |
|
from pathlib import Path |
|
|
|
mdl = whisper.load_model("base" if torch.cuda.is_available() else 'tiny') |
|
if torch.cuda.is_available(): mdl.to('cuda') |
|
def subtitle(input): |
|
input = str(input) |
|
status = "**Starting...**" |
|
yield status, gr.update() |
|
gr.Info("Transcribing...") |
|
status += "\n\n[1/5] Transcribing... (may take a while)" |
|
yield status, gr.update() |
|
transcript = mdl.transcribe( |
|
word_timestamps=True, |
|
audio=input |
|
) |
|
status += "\n\n[2/5] Processing subtitles..." |
|
yield status, gr.update() |
|
gr.Info("Processing subtitles...") |
|
subs = [] |
|
for segment in transcript['segments']: |
|
for word in segment['words']: |
|
subs.append(((word['start'], word['end'],), word['word'].strip(),)) |
|
status += "\n\n[3/5] Loading video..." |
|
yield status, gr.update() |
|
gr.Info("Loading video...") |
|
print(input) |
|
video = VideoFileClip(Path(input)) |
|
width, height = video.size |
|
generator = lambda txt: TextClip(txt, size=(width * (3 / 4) + 8, None), color='white', stroke_color='black', stroke_width=8, method='caption', fontsize=min(width / 7, height / 7), font=str(cached_path(FONT_URL))) |
|
generator1 = lambda txt: TextClip(txt, size=(width * (3 / 4), None), color='white', method='caption', fontsize=min(width / 7, height / 7), font=str(cached_path(FONT_URL))) |
|
status += "\n\n[4/5] Loading video clip..." |
|
yield status, gr.update() |
|
gr.Info("Loading video clip...") |
|
subtitles = SubtitlesClip(subs, generator) |
|
subtitles2 = SubtitlesClip(subs, generator1) |
|
result_1 = CompositeVideoClip([video, subtitles.set_pos(('center','center'))]) |
|
result = CompositeVideoClip([result_1, subtitles2.set_pos(('center','center'))]) |
|
status += "\n\n[5/5] Writing video... (may take a while)" |
|
yield status, gr.update() |
|
gr.Info("Writing video...") |
|
with tempfile.NamedTemporaryFile(suffix='.mp4', delete=False) as f: |
|
result.write_videofile(f.name, codec='h264_videotoolbox', audio_codec='aac', threads=64) |
|
status += "\n\n**Done!**" |
|
yield status, f.name |
|
return |
|
|
|
with gr.Blocks() as demo: |
|
with gr.Row(): |
|
with gr.Column(scale=3): |
|
gr.Markdown(""" |
|
# AutoSubs |
|
|
|
Automatically add on-screen subtitles to your videos. |
|
|
|
**NOTE:** Uploading copyrighted/NSFW content to this service is strictly prohibited. |
|
|
|
The maximum length of video is 5 minutes. This service probably won't work well on non-English videos. |
|
|
|
Powered by OAI Whisper & MoviePy! |
|
""") |
|
vid_inp = gr.Video(interactive=True, label="Upload or record video", max_length=300) |
|
go_btn = gr.Button("Transcribe!", variant="primary") |
|
with gr.Column(scale=1): |
|
status = gr.Markdown("**Status updates will appear here.**") |
|
vid_out = gr.Video(interactive=False, label="Result") |
|
go_btn.click(subtitle, inputs=[vid_inp], outputs=[status, vid_out]) |
|
demo.queue(api_open=False, default_concurrency_limit=20).launch(show_api=False) |