付記(問題点サマリ)
- 最近判明した接続/入出力の問題は
WRAPPER-DEV-LOG.md(2025-09-02)に詳細を記録。- 要点:
- REST→Backend の WebSocket ハンドシェイク遅延/失敗は、接続先不一致や IPv6/IPv4 の食い違いが主因。GUI でレコーダー接続先を自動的に
127.0.0.1へフォールバックするよう修正済みだが、CLI などから利用する場合はWRAPPER_BACKEND_*(特にWRAPPER_BACKEND_CONNECT_HOST=127.0.0.1)を明示設定すること。- FFmpeg 書き込み失敗は raw PCM を送っていたことが原因。修正済み(コンテナ付き送信、
.rawは WAV 化)。- OpenAI Whisper API 互換:
modelは必須だが無視。response_format=json|text|srt|vtt|verbose_json対応、エラーは OpenAI 風 JSON。
本リポジトリは upstream(whisperlivekit)を直接改変せず、GUI と API のラッパーとして外側から統合・拡張します。変更は本書・開発ログ・wrapper/ 配下に限定します。
- 目的: 既存の
whisperlivekit.basic_serverをラッパー独自のランチャー経由で安全に起動・制御し、GUI(録音・可視化)と、Whisper API 互換 REST を提供する。 - 非目的: Whisper 推論アルゴリズムの改良・精度改善、upstream コードの直接編集。
- 必須: Python 3.11+,
ffmpeg, ネットワークアクセス - 対応OS: Windows / macOS / Linux
- セキュリティ: 既定は
127.0.0.1バインド。外部公開はユーザー操作で明示的に有効化(0.0.0.0)。 - 改変方針: upstream は読み取り専用。呼び出しは import またはサブプロセス。
-
ローカルでリアルタイム音声→文字起こしを試す(GUI から Start/録音/表示/自動保存)。
- 録音停止のたびにトランスクリプトをタイムスタンプ付きテキストファイルとして指定フォルダに自動保存。
-
既存アプリから OpenAI Whisper API 互換 REST を呼ぶ(
POST /v1/audio/transcriptions)。 -
モデル/VAD のダウンロード・管理(GUIの Model Manager)。
- API 起動時、必要な Whisper/VAD/話者分離モデルがローカルに無ければ自動でダウンロードし、設定画面から確認・削除できる。
-
Whisperモデルは SimulStreaming 用と Faster Whisper 用に区分して一覧表示し、モデル名からバックエンド名を省いた。既存のダウンロード済みモデルはそのまま利用できるが、他バックエンドを使う場合は各バックエンド用モデルを追加取得する。
-
モデル選択欄の右側で使用するバックエンドを直接選択できるようになった。SimulStreaming を選択した場合は商用利用に別途許諾が必要である旨の注意書きを表示する。
-
Faster Whisper バックエンドのモデル取得時は、ダウンロードしたスナップショットのパスを
latestファイルに記録し、起動時はこれを参照してモデルを特定する。latestやsnapshotsが見つからない場合は.binファイル探索にフォールバックし、手動配置モデルも読み込める。 -
未ダウンロードのモデルを指定した場合でも、キャッシュディレクトリが存在しないことによるエラーは発生せず、必要に応じて自動ダウンロード処理に委ねられる。特に Faster Whisper バックエンドでは、モデルが未取得の場合でもモデル名を
--modelとして渡すことでInvalid model sizeエラーを避けてダウンロードにフォールバックする。
-
GUI 層(Tkinter):
wrapper/cli/main.py→wrapper/app/gui.py- Start/Stop で 2 プロセス起動/停止
- Backend:
python -m wrapper.app.backend_launcher(内部でwhisperlivekit.basic_serverを起動)- 起動時に
torch.hub.loadをラップしてtrust_repo=Trueを既定化(Silero VAD 初回ダウンロードの互換性確保)
- 起動時に
- API:
uvicorn wrapper.api.server:app
- Backend:
- 録音パイプライン: 生PCM → FFmpeg で
audio/webm(Opus) へ変換 → WebSocket/asrへストリーミング - Web UI(upstream)をブラウザで開く導線あり
- ヘッダー右上に CUDA/FFmpeg の利用可否を表示し、最右にライセンスボタンを配置
- Start/Stop で 2 プロセス起動/停止
-
Start/Stop API ボタンはヘッダー(タイトル右側)に配置。メインの2カラム設定画面はヘッダー左端の折りたたみボタンで表示/非表示を切替でき、状態は保存・復元される
- Start ボタン押下後はモデルのダウンロードおよびロード完了までアニメーション付きで「起動中」を表示し、Stop ボタン押下時も完全に停止するまで「停止中」を表示する
- 起動時のウィンドウサイズ: 高さは折りたたみ状態に応じて自動調整(未折りたたみ時は左カラムの自然高さに合わせた最大高、折りたたみ時はその状態の自然高)。横幅は初期算出幅の 1.2 倍で表示
- バックエンド起動直後は Tk の
afterで API 起動を遅延させるため、GUI スレッドをブロックしない。backend/api プロセスの終了コードを 1 秒間隔で監視し、異常終了時はログに exit code を追記してステータス・ボタンを即座に「停止」状態へ戻す。
-
右カラムを Endpoints / Recorder / Logs の三段構成とし、ログ欄は Recorder の下部に配置。ステータス表示と進捗バーを廃止し、ログ欄は最低4行を維持しつつトランスクリプト欄と柔軟に高さを分配。トランスクリプト表示欄の縦幅は従来比でおよそ 2/3 に調整
- ウィンドウ拡大後に左右カラムが伸びても、縮小時に高さがウィンドウに追随して UI 全体が常に表示されるよう ScrollableFrame を改修。ウィンドウ最大高さは左カラムの自然高さに合わせて制限
- 以前の「ウィンドウ/ペインの最小サイズ固定」は撤廃し、自由なリサイズとスクロールで運用(小画面でのはみ出しを解消)
- 旧レイアウト(下部パネルにログを表示)は廃止し、環境変数での切替は不可
- GUIセクション(スクロール領域)はウィンドウ高さに追従し、はみ出す分はスクロールで閲覧可能(固定的な最小高さの強制は行わない)
-
API 層(FastAPI):
wrapper/api/server.pyPOST /v1/audio/transcriptions: 入力形式を判定し、16kHz/mono の wav/raw はそのまま、その他は FFmpeg で 16kHz/mono PCM 化 → backend/asrへWS中継 → テキスト連結返却- 依存:
- upstream パッケージ
whisperlivekit(モデル推論・WSサーバ・Web UI 等) ffmpeg(GUI録音のエンコード/REST入力のデコード)
- GUI:
python -m wrapper.cli.main - WebSocket(upstream 提供):
ws://<backend_host>:<backend_port>/asr- GUI の Recorder は
audio/webm(Opus) を送信(raw PCM では送らない)。サーバ側で s16le/16kHz/mono に復号され処理される。 - バインドホストが
0.0.0.0でもレコーダーは自動的に127.0.0.1へ接続し、外部公開時でもローカル収録が失敗しない。 - 録音停止時は「空バイト(b"")」を送信して EOF を明示。
- GUI の Recorder は
- REST API(Wrapper):
POST http://<api_host>:<api_port>/v1/audio/transcriptions- multipart フォーム:
file=@sample.wav,model=whisper-1 - 音声形式: 16kHz モノラル (wav/raw) を推奨。これらは再変換せずに処理され、その他の形式は ffmpeg により変換される。
- APIキー(任意):
X-API-Key: <key>またはAuthorization: Bearer <key> WRAPPER_REQUIRE_API_KEY=1を設定した場合、/v1/audio/transcriptionsだけでなく/openapi.json/docs/redocなどのドキュメント系エンドポイントも同じヘッダーが必須となる(未設定または誤ったキーは 401 応答)。- レスポンス例:
{ "text": "...", "model": "whisper-1" }
- multipart フォーム:
- Backend 起動:
python -m wrapper.app.backend_launcher --host 127.0.0.1 --port 8000 [...options] - Wrapper API 起動:
WRAPPER_BACKEND_HOST=127.0.0.1 WRAPPER_BACKEND_PORT=8000 uvicorn wrapper.api.server:app --host 127.0.0.1 --port 8001 - GUI から Start / 録音 / 可視化 / 保存
- 主要環境変数(GUI→APIへ引継ぎ)
WRAPPER_BACKEND_HOST/WRAPPER_BACKEND_PORTWRAPPER_BACKEND_SSL=1(wss 接続を指定)WRAPPER_REQUIRE_API_KEY=1,WRAPPER_API_KEY=<key>
- 既定のキャッシュルートは常に
~/.cache/WhisperLiveKitWrapperを基点とし、 Windows Store 版 Python が指すLocalCache\Local\wrapper\WhisperLiveKit\Cacheのような長大パスは自動的にフォールバックされる。 - フォールバック時は旧ディレクトリに存在するモデル/VAD キャッシュを新ディ
レクトリへ自動移行する。移行元は
WRAPPER_CACHE_MIGRATED_FROM環境変数でロ グに残るため、不要になった旧ディレクトリを手動で削除できる。 - Hugging Face (
HF_HOME/HUGGINGFACE_HUB_CACHE) およびTORCH_HOMEのキャッシュ も同様に短いパスへ統一され、既存内容は移行される。上書きしたい場合は各環 境変数を明示設定する。WRAPPER_WARMUP_FILE=<path>(Faster Whisper ウォームアップ用音声ファイル。未指定の場合はラッパー同梱のwrapper/assets/warmup/whisper_warmup_jfk.wavを使用)WRAPPER_BACKEND_QUEUE_TIMEOUT_SEC(バックエンドジョブの待機上限秒。未設定または0/負値では無制限に待機し、GUI 既定は0に設定される)
- GUI・CLI・バックエンドはいずれも
platformdirs.user_cache_path("WhisperLiveKit", "wrapper")を基点とするhf-cache(Hugging Face)とtorch-hubディレクトリを既定の保存先として利用する。アプリ本体が読み取り専用でもユーザー領域に展開されるため、MSIX として配布し てもモデルのダウンロード先と読み込み元が一致する。 - 環境変数で保存先を上書きできる。
WRAPPER_CACHE_DIR=<base>を指定すると<base>/hf-cache,<base>/torch-hubをまとめて利用する。- より細かく制御したい場合は
WRAPPER_HF_CACHE_DIR/WRAPPER_TORCH_CACHE_DIRを直接指定できる。既にHUGGINGFACE_HUB_CACHE/HF_HOME/TORCH_HOMEが設定されている場合はその値を尊重し、ラッパー内部の参照も同じディレクトリに揃え る。
- 起動時に
HUGGINGFACE_HUB_CACHE,HF_HOME,TORCH_HOME,HF_HUB_DISABLE_SYMLINKSが未設定なら自動的に補完し、GUI でのモデル ダウンロード・バックエンド起動・CLI からの操作が同じキャッシュを使う。HF_HUB_DISABLE_SYMLINKS=1とsnapshot_download(..., local_dir_use_symlinks=False)の併用により、MSIX/Windows のシンボリックリンク制限下でも確実に物理ファイルが 配置される。 preflight.materialize_speechbrain_filesは pyannote/speechbrain キャッシュに残る欠損や壊れたシンボリックリンクを検出し、ラッパー管理 の Hugging Face キャッシュから必要ファイルをコピーして実体化する。バックエンドは常に存在するパスのみを参照するため、パッケージ 配布時の読み込みエラーを防げる。- CLI (
python -m wrapper.cli.model_manager_cli) も上記環境変数を読み取り、GUI と同じ場所にモデルを配置・削除する。 - Faster Whisper バックエンドのウォームアップ用音声
wrapper/assets/warmup/whisper_warmup_jfk.wavをリポジトリに同梱し、パッケージング時 に MSIX のアプリデータへコピーする。GUI 初期化時に同梱ファイルのパスを解決して--warmup-fileに渡すため、起動時に GitHub へアクセス する必要がなくなる。必要に応じてWRAPPER_WARMUP_FILEで別ファイルに差し替え可能。
- バックエンド/API の標準出力と標準エラーはGUIのログ欄と同時にターミナルにも表示される。
PYTHONUNBUFFERED=1と-uオプションによりバッファリングを無効化し、macOSでログが出力されない問題を解消。 - backend/api プロセスの
poll()を GUI が定期監視し、異常終了を検知した場合は exit code をログに追記して即座に停止処理を走らせる。 - FFmpeg が無い:
500 ffmpeg_not_found(API)、GUIログに表示 - GUI から Start API を実行した際に FFmpeg が見つからない場合、警告ダイアログを表示して起動を中止する
- 音声変換失敗:
400 ffmpeg_failed(API) - WS 側の終了: サーバは結果送信後に
{ "type": "ready_to_stop" }を返す。GUI は受信スレッドで反映。
- デフォルトはローカルバインド。外部公開する場合は TLS/認証/ファイアウォール等を考慮。
- Wrapper API は任意で API キーを要求可能(GUI で設定)。API キーを有効化すると OpenAPI/Swagger/Redoc も同じヘッダーが必要になり、認証無しでは参照できない。
- 低遅延の逐次文字起こし(数百ms〜程度のバッファリング)
- モデル・HW に依存。高負荷の場合は
tiny/base/smallを推奨。
- バイナリ配布(PyInstaller等)検討
- API 認証/ダッシュボードの拡充
- upstream 提案は
WRAPPER-DEV-LOG.mdにパッチ案として記録
- 症状: 「Error writing to FFmpeg: Connection lost」等。
- 原因: サーバ側 FFmpeg は
-i pipe:0でヘッダから入力形式を自動判定。raw PCM を送ると判別不可で失敗。 - 対応: GUI は FFmpeg で
audio/webm(Opus) にエンコードして送信(本リポで実装済)。録音停止時は空バイトで EOF を明示。- 参照:
wrapper/app/gui.py:_recording_worker
- 参照:
- 症状: GUI 起動時(Start API)に「Cannot start due to missing dependencies: Diart backend requires diart.」が表示される。
- 前提: 話者分離(Diarization)を有効化し、バックエンドに
diartを選択している場合にチェックが走る。 - 原因: 実行中の Python 環境に
diart(および関連依存pyannote.audio,rx)がインストールされていない、または別環境に入っている。 - 解決手順:
-
- 現在GUIを起動している Python を特定する。
- 例:
which python(Windowsはwhere python)、python -V
-
- 同じ Python でモジュールを確認する。
- 例:
python -c "import diart, pkgutil; print('diart OK')"
-
- 未導入ならインストール(CPU/AMD環境の例):
pip install -r wrapper/requirements-cpu-amd.txt- または最小構成:
pip install diart pyannote.audio rx
-
- それでも失敗する場合は、仮想環境の混在を疑い、GUI と同じ環境で再度インストールする(
python -m pip install ...形式を推奨)。
- それでも失敗する場合は、仮想環境の混在を疑い、GUI と同じ環境で再度インストールする(
-
- 備考:
wrapper/requirements-cpu-amd.txtにはdiart,pyannote.audio,rxを含めています。NVIDIA 環境ではwrapper/requirements-nvidia.txtを使用してください。diartのモデル取得には Hugging Face のネットワークアクセスが必要です(初回のみ)。
- 症状: バックエンド起動時に
FileNotFoundError: ... speechbrain\hyperparams.yamlが表示される。 - 原因: Windows 環境では
pyannote.audioが必要とするhyperparams.yamlやcustom.pyへのシンボリックリンク作成に失敗する場合がある。 - 対応: 起動時にこれらファイルの存在を確認し、ラッパーの Model Manager で
speechbrain/spkrec-ecapa-voxcelebを取得して必要ファイルをコピーするよう修正済み(不足分は Hub から直接取得)。シンボリックリンクは使用しない。
- CPU/AMD 環境:
pip install -r wrapper/requirements-cpu-amd.txt - NVIDIA 環境:
pip install -r wrapper/requirements-nvidia.txt - 追加オプション(任意):
- VAD 有効時の
torchaudioは Torch のバージョンに揃えてください(GUIが不足時に案内を表示)。 - Sortformer バックエンドを使う場合は CUDA + NVIDIA NeMo が必要です。
- VAD 有効時の
- 本リポは upstream をサブモジュールとして参照します(ローカル改変なし)。
- 初回/取得後は以下を実行:
git submodule update --init --recursive
- 配置パス:
submodules/WhisperLiveKit- ランチャー
wrapper/app/backend_launcher.pyがsys.pathに上記パスを自動追加します。 - そのため
pip install whisperlivekitは不要です(requirements からも除外済み)。 - サブモジュールを更新する場合:
git -C submodules/WhisperLiveKit pullまたはgit submodule update --remote --merge
- ランチャー
- GUI:
wrapper/app/gui.py(エントリ:python -m wrapper.cli.main) - API:
wrapper/api/server.py - 設定テンプレート:
wrapper/config/ - ライセンス一覧:
wrapper/licenses.json - ウォームアップ音声:
wrapper/assets/warmup/whisper_warmup_jfk.wav(Faster Whisper 起動時の既定ウォームアップに利用)
python wrapper/scripts/full_stack_integration_test.py: GUI の「Start API」と同等の経路をスタブ環境で再現し、GUI から管理できるすべてのモデル種別(Whisper 各バックエンド、VAD、セグメンテーション、埋め込み)のダウンロード状態を検証してから REST 経路を確認する統合テスト。
本仕様書と WRAPPER-DEV-LOG.md は、仕様変更・意思決定に合わせて更新します。
- 処理中インジケータ: 録音開始後からバックエンド側での最終処理が完了するまで、録音開始ボタンの右側にスピナーを表示します。
- 再開時の確認: 処理が継続中(停止後の後処理を含む)に「Start Recording」を押すと確認ダイアログを表示し、同意した場合は現在の処理を中止して新しいセッションをクリーンに開始します。