Whisperに関するメモ
※ 2023/12/13時点の内容です
OpenAIのWhisper-V3が出たということでいろいろと試行錯誤した時のメモです。
V3は、OpenAIのAPIがない
OpenAIのペーパーによると、「API経由の場合、最新のモデルはWhisper V2-large」とのこと。ただし、V3のモデル情報を自分のパソコンなどローカル環境にもっていけばV3が使えます。
始めに、音声ファイルの分割
API経由でV2-largeにかける場合、受け付けられるデータサイズは25MBまでだそうで、25MB以上ある音声ファイルはまず分割をする必要があります。
ちなみにV3(をローカルで使う場合)では試していませんが、25MB分を一括で処理するとめちゃくちゃ時間がかかるので、やっぱり分割したほうが得策だと思います。
`pip install pydub` でインストールした後、以下のようなコードで分割しました。
from pydub import AudioSegment
def split_m4a(file_path, interval=60):
interval = interval * 1000 #ミリ秒
# M4Aファイルの読み込み
audio = AudioSegment.from_file(file_path, format="m4a")
# 全体の長さ(ミリ秒)
length_audio = len(audio)
# 分割数を計算
count = math.ceil(length_audio / interval)
# 分割とファイルの保存
for i in range(0, count):
# 分割する部分の開始と終了時間
start = i * interval
end = min(start + interval, length_audio)
# 分割
split_audio = audio[start:end]
# 分割されたオーディオをファイルに保存
split_filename = f'{file_path[:file_path.rfind(".")]}_{i+1}.mp3'
split_audio.export(split_filename, format="mp3")
# ファイル分割
temp_filename = r'recsample.m4a'
split_m4a(temp_filename, 25*60) #25分
V3をローカル環境で使う。
まずはPIP。 `pip install openai-whisper` を実行しましょう。
具体的なコードは以下のとおり。
import whisper
temp_filename = r'recsample.mp3'
#--- whisper-v3実行 ------------------------#
model_size = "large-v3"
model = whisper.load_model(model_size)
response = model.transcribe(temp_filename, language="ja")
#保存
with open('aaaaaaa.txt', 'w', encoding='utf8') as f :
for segment in response['segments']:
f.write("[%.2fs -> %.2fs] %s\n" % (segment['start'], segment['end'], segment['text']))
GPUが入っていない普通のノートパソコンで実行したのですが、めっちゃくちゃ時間がかかります。20分の音声が1時間でも処理しきれません。
良い点・・・精度が高い。文章が区切れ、”何時何分に話したか”も分かる。
悪い点・・・めちゃくちゃ時間がかかる。
V2をAPIで使う。
ココにサンプルコードがあります。
APIを使えば処理は一瞬。めちゃくちゃ早い。ただし、精度はV3より落ちます。どっちを使うか悩ましい。。。
import openai
temp_filename = r'recsample.mp3'
#--- whisper-v2の場合 ---------------------#
model_size = "whisper-1"
with open(temp_filename, "rb") as audio_file:
response = openai.Audio.transcribe(model_size, audio_file)
with open('bbbbbbb.txt', 'w', encoding='utf8') as f :
f.write(response["text"])
良い点・・・早い。一瞬で処理が終わる。
悪い点・・・精度がイマイチ、”何時何分に話したか”が分からない
V3の高速版=faster-whisper
「CTranslate2というAIモデルを高速かつ効率的に動かすモデルを使ってwhisper-v3を動かす」ということができるようなのですが、会社のパソコンではセキュリティの関係かうまく動きませんでした。残念・・・
Google Colaboを使うケースが多いみたいですが、これまた会社パソコンからはアクセスできず。。。
以下の記事が一番わかりやすかったです。
オマケ:YouTube動画のダウンロード
そんなことができるようですが、法的にはグレーな部分があるみたいなので、自己責任で。
pip install yt-dlp
from yt_dlp import YoutubeDL
download_url = '{動画リンク}'
download_options = {
'format': 'best', # 最高画質でダウンロード
'outtmpl': 'C:/temp/%(title)s.%(ext)s', # c:\tempに保存
}
with YoutubeDL(download_options) as ydl:
ydl.download([download_url])
関数化&実装
インプットする音声ファイルはm4aファイルしか受け付けない仕様ですので、適宜修正してくださいませ。
from dotenv import load_dotenv
import openai
from pydub import AudioSegment
import math
import whisper
def transcribe_audio_to_text_v2(fn:str)->str:
#--- whisper-v2の場合 ---------------------#
model_size = "whisper-1"
with open(fn, "rb") as audio_file:
response = openai.Audio.transcribe(model_size, audio_file)
return response["text"]
def transcribe_audio_to_text_v3(fn:str)->str:
#--- whisper-v3実行 ------------------------#
model_size = "large-v3"
model = whisper.load_model(model_size)
response = model.transcribe(fn, language="ja")
#結果表示 & 保存
res = ""
for segment in response['segments']:
res += "[%.2fs -> %.2fs] %s\n" % (segment['start'], segment['end'], segment['text'])
return res
def split_m4a(file_path:str, interval:int=60) -> list :
iv = interval * 1000 #ミリ秒
# M4Aファイルの読み込み
audio = AudioSegment.from_file(file_path, format="m4a")
# 全体の長さ(ミリ秒)
length_audio = len(audio)
# 分割数を計算
count = math.ceil(length_audio / iv)
# 分割とファイルの保存
split_filenames = []
for i in range(0, count):
# 分割する部分の開始と終了時間
start = i * iv
end = min(start + iv, length_audio)
# 分割
split_audio = audio[start:end]
# 分割されたオーディオをファイルに保存
split_filename = f'{file_path[:file_path.rfind(".")]}_{i}.mp3'
split_filenames.append(split_filename)
split_audio.export(split_filename, format="mp3")
return split_filenames
def speech_to_text(fn:str, v:str) :
#APIキー読み込み
load_dotenv()
# ファイル分割
l_files = split_m4a(fn, 25*60)
#出力テキストファイル名
if v == 'V2' :
outfn = f'STT_V2_{fn[:fn.rfind(".")]}.txt'
elif v == 'V3' :
outfn = f'STT_V3_{fn[:fn.rfind(".")]}.txt'
# STT
res_all = ''
for split_filename in l_files :
if v == 'V2' :
res = transcribe_audio_to_text_v2(split_filename)
elif v == 'V3' :
res = transcribe_audio_to_text_v3(split_filename)
res_all += res
with open(outfn, 'w', encoding='utf8') as f : #念のため途中でも保存
f.write(res_all)
with open(outfn, 'w', encoding='utf8') as f :
f.write(res_all)
if __name__ == "__main__":
temp_filename = r'recsamp.m4a'
speech_to_text(temp_filename, "V2")