🌟
SeamlessM4Tで英語のYouTube動画の日本語音声を自動生成する
SeamlessM4Tとは
環境構築
Linux+CUDAな環境が一番楽です。Google Colab Proが良いでしょう。[1]
依存ライブラリ
システム依存については https://huggingface.co/spaces/facebook/seamless_m4t/blob/main/Dockerfile が参考になります。
apt-get update && \
apt-get upgrade -y && \
apt-get install -y --no-install-recommends \
git \
git-lfs \
wget \
curl \
# python build dependencies \
build-essential \
libssl-dev \
zlib1g-dev \
libbz2-dev \
libreadline-dev \
libsqlite3-dev \
libncursesw5-dev \
xz-utils \
tk-dev \
libxml2-dev \
libxmlsec1-dev \
libffi-dev \
liblzma-dev \
# gradio dependencies \
ffmpeg \
# fairseq2 dependencies \
libsndfile-dev && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
pythonパッケージについては
pip install fairseq2 git+https://github.com/facebookresearch/seamless_communication torch torchaudio pytube moviepy pydub
モデルのダウンロード
import torch
from seamless_communication.models.inference.translator import Translator
device = torch.device("cuda:0")
translator = Translator(
model_name_or_card="seamlessM4T_large",
vocoder_name_or_card="vocoder_36langs",
device=device,
dtype=torch.float16
)
ここでseamlessM4T_largeモデルの10GBのダウンロードが発生します
日本語音声生成と動画合成部分
Steve Jobs' 2005 Stanford Commencement Address を読み込みました。
Translatorは数秒の音声しか受け付けてくれないのでファイル分割して最後に結合しています。
import functools
import re
import torch
import torchaudio
from pytube import YouTube
from moviepy.editor import VideoFileClip, AudioFileClip, CompositeAudioClip
from pydub import AudioSegment
from pydub.silence import split_on_silence
from seamless_communication.models.inference.translator import Translator
import functools
import torch
import torchaudio
from pytube import YouTube
from moviepy.editor import VideoFileClip, AudioFileClip, CompositeAudioClip
from pydub import AudioSegment
from pydub.silence import split_on_silence
from seamless_communication.models.inference.translator import Translator
@functools.lru_cache(maxsize=None)
def init_translator():
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
translator = Translator(
model_name_or_card="seamlessM4T_large",
vocoder_name_or_card="vocoder_36langs",
device=device,
dtype=torch.float16
)
return translator
def download_and_convert_video(url: str) -> AudioSegment:
# ビデオをダウンロード
yt = YouTube(url)
video = yt.streams.get_highest_resolution()
video.download(filename='temp_video.mp4')
# mp4をwavに変換
video_clip = VideoFileClip('temp_video.mp4')
audio_clip = video_clip.audio
audio_clip.write_audiofile('output.wav')
# wavファイルを読み込む
audio = AudioSegment.from_wav("output.wav")
# 無音部分で区切る
chunks = split_on_silence(audio,
# 無音部分とみなす閾値(dB)
silence_thresh = audio.dBFS - 14,
# 無音部分の最小長さ(ミリ秒)
min_silence_len = 500,
# 音声チャンクの前後に残す無音の長さ(ミリ秒)
keep_silence = 100
)
# 分割した音声を保存
sample_rate = 22050
combined = AudioSegment.empty()
translator = init_translator()
for i, chunk in enumerate(chunks):
f = f"chunk_{i}.wav"
chunk.export(f, format="wav")
text_out, wav, sr = translator.predict(
input=f,
task_str='S2ST',
tgt_lang='jpn',
src_lang='eng',
ngram_filtering=True,
sample_rate=sample_rate
)
f_jpn = f"chunk_{i}.jpn.wav"
print(text_out)
torchaudio.save(f_jpn, wav[0].cpu(), sr)
audio = AudioSegment.from_wav(f_jpn)
combined += audio
combined.export("combined.jpn.wav", format="wav")
# ビデオとオーディオを読み込む
video = VideoFileClip("temp_video.mp4")
original_audio = video.audio
new_audio = AudioFileClip("combined.jpn.wav")
# original_audioのボリュームを半分にする
original_audio = original_audio.fx(lambda x: x.volumex(0.5))
# オーディオの長さを調整
min_length = min(original_audio.duration, new_audio.duration)
original_audio = original_audio.subclip(0, min_length)
new_audio = new_audio.subclip(0, min_length)
# オーディオをオーバーラップ
combined_audio = CompositeAudioClip([original_audio, new_audio])
# オーディオを置き換える
final_video = video.set_audio(combined_audio)
# 結合したビデオを保存
vid = extract_video_id(url)
output_file = f"{vid}.mp4"
final_video.write_videofile(output_file, codec="libx264", audio_codec="aac")
final_video.close()
return output_file
def extract_video_id(url):
pattern = r'(?:https?:\/\/)?(?:www\.)?youtube\.com\/watch\?v=([a-zA-Z0-9_-]+)'
match = re.search(pattern, url)
if match:
return match.group(1)
return None
url = 'https://www.youtube.com/watch?v=UF8uR6Z6KLc'
assert extract_video_id(url)
result = download_and_convert_video(url)
print(result)
できた!? のか
出力されたmp4をダウンロードして再生すると日本語音声が乗っています。
できてはいない
Discussion