やりたいこと
Macでローカルで文字起こしがしたい
M4Macを手に入れて、Whisperでローカルで文字起こしが出来るようになるかなと思ってやってみたが、PythonのWhisperライブラリではいまいち速度が出ない。 WhisperライブラリはPyTorchベースのため、MacのMetal GPUが活用できないことが原因らしい。
whisper.cppならいけた
whisper.cpp とは? OpenAIが開発した音声認識モデル「Whisper」を、軽量・高速に動作させるためにC/C++で再実装したオープンソースの音声文字起こしエンジン
項目 | 内容 |
---|---|
開発者 | Georgi Gerganov 氏(GitHub) |
元になった技術 | OpenAI Whisper |
特徴 | C/C++で書かれており、ローカルで軽量・高速に動作 |
対応プラットフォーム | macOS(Apple Silicon対応)、Linux、Windows |
利用用途 | 音声→文字のリアルタイム変換(例:議事録、字幕生成、音声コマンド) |
手順(備忘録)
whisper.cpp をクローン
git clone https://github.com/ggml-org/whisper.cpp.git
#作成されたディレクトリに移動
cd whisper.cpp
サブモジュール(外部ライブラリ依存)を取得・初期化
git submodule update --init --recursive
プロジェクトのビルド設定を生成
cmake -DGGML_METAL=ON .
GGML_METAL=ON により、Apple Silicon(M1/M2/M3)のMetal GPU を使う高速化オプションが有効に。
cmake で準備されたMakefileに従ってビルド(コンパイル)
make
Whisperの音声認識モデル large-v3(最も高精度) をダウンロード
bash ./models/download-ggml-model.sh large-v3
もとのディレクトリに戻る
cd ..
これでコマンドからwhisper.cppが使えるように。subprocessモジュールを使ってPythonから実行。
import subprocess
def transcribe(audio_file):
result = subprocess.run(
[
"./whisper.cpp/main",#実行ファイルのパス
"-m", "whisper.cpp/models/ggml-large-v3.bin",
"-f", audio_file,
"-l", "ja",#日本語指定
"--no-timestamps"
],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True
)
return result.stdout
print(transcribe("example.wav"))
whisperAPIと遜色無い精度と速度で文字起こし出来るようになりました!! whisperAPIいいお値段だったのでありがたい!!
以下、streamlitでアプリケーション化。
import streamlit as st
import subprocess
import tempfile
import os
def transcribe_audio(file_path):
"""whisper-cli を使って音声ファイルを文字起こしする関数"""
result = subprocess.run(
[
"whisper.cpp/bin/whisper-cli",
"-m", "whisper.cpp/models/ggml-large-v3.bin",
"-f", file_path,
"-l", "ja",
"--no-timestamps"
],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True
)
return result.stdout
def main():
st.title("Whisper 文字起こしアプリ (ローカル + Metal GPU)")
st.write("音声ファイル (.wav) をアップロードして文字起こしを実行します。")
uploaded_file = st.file_uploader("音声ファイルをアップロード", type=["wav", "mp3", "m4a"])
if uploaded_file is not None:
with tempfile.NamedTemporaryFile(delete=False, suffix=".wav") as tmp:
tmp.write(uploaded_file.read())
tmp_path = tmp.name
st.info("音声を処理中...")
try:
result_text = transcribe_audio(tmp_path)
st.success("文字起こし完了!")
st.text_area("文字起こし結果", value=result_text, height=300)
except Exception as e:
st.error(f"エラーが発生しました: {e}")
finally:
os.remove(tmp_path)
if __name__ == "__main__":
main()