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")

この記事が気に入ったらサポートをしてみませんか?