Whisper 文字起こしを複数のmodelで選択実行できるようにし 実行形式で配布できるようにしてみた

Whisperの文字起こしのcodeを作ったので実行形式にして、社内で使用したかったのですが、モデルファイルを参照させる方法（パスの指定等）に手間取ったので、記しておきます。

modelは下記を選択できるようにしています。

'base'
'small'
'medium'
'large-v3'
'large-v3-turbo'
'kotoba-tech/kotoba-whisper-v2.0-faster'

#
getattr(sys, 'frozen', False):
sysモジュールはPythonの標準ライブラリの一部で、システムに関する情報を提供します。
sys.frozenは、PyInstallerで生成された実行ファイル内で、スクリプトが実行されている場合にTrueとなる特殊な属性です。

frozen属性が存在するかどうかをgetattr関数で確認し、存在する場合はTrue、存在しない場合はFalseを返します。
これにより、実行ファイルがPyInstallerによって変換されたものかどうかを判別できます。

sys._MEIPASS:
sys._MEIPASSは、PyInstallerで生成された実行ファイルが一時的に解凍される場所を指し示します。PyInstallerは、実行ファイル内に埋め込んだリソースを実行時に一時的なディレクトリに展開します。そのディレクトリがsys._MEIPASSで参照できます。
これを使って、実行ファイルが起動されたときに.onnxモデルなどにアクセスすることができます。


#
~~~python:python.py
import tkinter as tk
from tkinter import filedialog
import pandas as pd
from faster_whisper import WhisperModel
import openpyxl
import sys
import os

print("Python version:", sys.version)
print("Python executable location:", sys.executable)


if getattr(sys, 'frozen', False):
    # PyInstallerで実行されている場合
    application_path = sys._MEIPASS
else:
    # 開発環境（スクリプトがそのまま実行されている場合）
    application_path = os.path.dirname(os.path.abspath(__file__))

CYAN = '\033[36m'
INV = '\033[7m'
END = '\033[0m'                    
print (CYAN + INV + f"application_path:{application_path}"+ END)

model_path = os.path.join(application_path, 'faster_whisper/assets/silero_encoder_v5.onnx')


def transcribe_audio():
    # オーディオファイルのパスを取得
    audio_path = file_path.get()

    # ユーザーが選択したモデルを取得
    selected_model = model_choice.get()

    # ユーザーが入力したパラメータを取得
    min_silence_duration = int(silence_duration_entry.get())  # 無音部分の最小時間（ms）
    beam_size_value = int(beam_size_entry.get())  # Beam size

    # Whisperモデルを選択したモデルに応じてロード
    model = WhisperModel(selected_model, device='cpu')

    GREEN = '\033[32m'#(文字)緑
    INV = '\033[7m'
    END = '\033[0m'                    
    print (GREEN + INV + f"model==:{selected_model}"+ END)
    print (GREEN + INV + f"audio file==:{audio_path}"+ END)    

    # 文字起こしを実行
    vad_parameters = {'min_silence_duration_ms': min_silence_duration}  # 無音部分除去の最小時間を設定

    if selected_model == 'kotoba-tech/kotoba-whisper-v2.0-faster':
        #segments, info = model.transcribe(audio_path, language="ja", chunk_length=15, condition_on_previous_text=False)
        segments, info = model.transcribe(audio_path, chunk_length=15, condition_on_previous_text=False, vad_filter=True, vad_parameters=vad_parameters, temperature=0.0, best_of=5)
    else:
        segments, info = model.transcribe(audio_path, beam_size=beam_size_value, vad_filter=True, vad_parameters=vad_parameters, temperature=0.0, best_of=5)

    # 結果をリストに格納
    results = []
    for segment in segments:
        results.append([segment.start, segment.end, segment.text])
        print(f'[{segment.start:.2f}s - {segment.end:.2f}s] {segment.text}')

    # 結果をDataFrameに変換
    df = pd.DataFrame(results, columns=["Start Time", "End Time", "Text"])

    # エクセルファイル名をオーディオファイル名から取得
    output_file = audio_path.split('/')[-1].split('.')[0] + '_text.xlsx'

    # エクセルファイルに保存
    df.to_excel(output_file, index=False)
    status_label.config(text=f"エクセル出力 完了： {output_file}")

def open_file():
    # ファイルダイアログを開き、ファイルを選択
    file_path_str = filedialog.askopenfilename(filetypes=[("Audio Files", "*.mp3;*.m4a;*.wav")])
    file_path.set(file_path_str)

# GUIの設定
root = tk.Tk()
root.title("文字起こし faster-whisper")

# ファイルパスを格納するためのStringVar
file_path = tk.StringVar()

# モデル選択用のリスト
model_options = ['base', 'small', 'medium', 'large-v3', 'large-v3-turbo', 'kotoba-tech/kotoba-whisper-v2.0-faster']

# モデル選択用の変数
model_choice = tk.StringVar(root)
model_choice.set(model_options[4])  # デフォルトで 'large-v3-turbo' を選択

# GUIウィジェットの配置
tk.Label(root, text="Select Audio File").pack(pady=10)
tk.Entry(root, textvariable=file_path, width=50).pack(pady=5)
tk.Button(root, text="ファイル 選択", command=open_file).pack(pady=5)

# モデル選択メニュー
tk.Label(root, text="Select Whisper Model").pack(pady=10)
model_menu = tk.OptionMenu(root, model_choice, *model_options)
model_menu.pack(pady=5)

# 無音部分の最小時間（ms）を設定するための入力フィールド
tk.Label(root, text="Min Silence Duration (ms)").pack(pady=10)
silence_duration_entry = tk.Entry(root)
silence_duration_entry.insert(0, "5000")  # デフォルト値 5000ms
silence_duration_entry.pack(pady=5)

# Beam size を設定するための入力フィールド
tk.Label(root, text="Beam Size").pack(pady=10)
beam_size_entry = tk.Entry(root)
beam_size_entry.insert(0, "5")  # デフォルト値 5
beam_size_entry.pack(pady=5)

# 文字起こし開始ボタン
tk.Button(root, text="文字起こし 開始", command=transcribe_audio).pack(pady=20)

# 結果表示用のラベル
status_label = tk.Label(root, text="", fg="green")
status_label.pack(pady=10)

# GUI実行
root.mainloop()

~~~

上記のCODEに対して、下記のpyinstallerで実行ファイル作成できます。

~~~
pyinstaller --onefile --add-data "C:\\@@@@@@@@@@@@@@@@" python.py
~~~

上記の"C:\\@@@@@@@@@@@@@@@@"はfaster_whisper\\assets;faster_whisper\\assetsの場所を入力してください。
私の場合は
"C:\\Users\\@@@@@\\@@@@@@@@\\faster-whisper\\Lib\\site-packages\\faster_whisper\\assets;faster_whisper\\assets"

path_to_your_model/silero_encoder_v5.onnx: モデルファイルが存在する場所のパス
faster_whisper/assets: 実行ファイル内の配置先（実行時にアクセスするパス）

![スクリーンショット 2025-01-31 23.04.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/524278/2b5d11be-6e8a-d0b6-f67d-bea1eda2db89.png)
#
起動すると下記GUIになります。
文字起こししたいAUDIO ファイルを選んで、modelを下記から選択して開始をおしてください。

'base'
'small'
'medium'
'large-v3'
'large-v3-turbo'
'kotoba-tech/kotoba-whisper-v2.0-faster'

![スクリーンショット 2025-01-31 23.12.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/524278/09fa43c7-caea-112c-ebd6-8247990004e8.png)

文字起こし完了すると、エクセルファイルで出力します。