会議や取材の録音を、聞き直しながら手で打ち直す。あの時間がいちばん惜しい。かといってクラウドの文字起こしは、音声をどこかのサーバーへ預けるのが気になる場面もある。だから、Whisper を自分のPCの中だけで走らせて、録音ファイルを放り込めば文字が返ってくるデスクトップアプリを、AIと一緒に作った。名前は Transcription Studio(内部名 transcribe-app、ウィンドウ名「音声文字起こし」)。エンジンは faster-whisper・openai-whisper・OpenAI API の3つを設定で切り替えられて、結果は txt・SRT・VTT・JSON など複数フォーマットで同時に書き出す。この記事では、実際に動かした画面と、その作り方の勘所を正直に見せる。今動くのは Phase 1 の中核までで、波形エディタや話者分離は設計だけ先にある。そこも隠さず書く。
目次
このガイドで作るもの
作るのは、音声・動画ファイルをドラッグ&ドロップすると、ローカルの Whisper で文字起こしして結果を表示・保存するデスクトップアプリだ。画面は左右2ペイン。左が「ここにドロップ」のファイルキュー、右が「文字起こし結果」の表示欄。GUI は Python の PySide6(Qt)で組んだ。下が実際の起動直後の画面だ。

設計の軸は3つに絞った。文字起こしエンジンを差し替えられること、出力フォーマットを選べること、そして処理を手元で完結させること。順番に画面で見ていく。
エンジンを切り替える:faster-whisper / openai-whisper / OpenAI API
文字起こしは「速さ」と「精度」と「手元で動くか」のバランスが案件ごとに変わる。だから1つのエンジンに固定せず、設定ダイアログで選べるようにした。メニューの「ファイル → 設定…」を開くとこうなる。

3つのエンジンは役割が違う。faster-whisper は CTranslate2 で動く既定のローカルエンジンで、GPUが無くてもそこそこ速い。openai-whisper は本家の実装で、比較や検証に使う。OpenAI API は自前のマシンで重いモデルを回したくないときの逃げ道で、こちらだけはネットワークと APIキーが要る。APIキーは設定に平文で置かず、OS の資格情報ストア(keyring)に預ける。コードにも設定ファイルにも鍵を書かない。
出力フォーマットはチェックボックスで複数選べる。plain(素のテキスト)、timestamped(時刻つき)、SRT・VTT(字幕)、speaker(話者ラベル欄)、JSON(機械処理用)。チェックした分だけ、1回の文字起こしで同時に書き出す。字幕が欲しい人はSRT、あとで自分のツールに食わせたい人はJSON、と用途で選べる。
ドロップして、待つだけ:キュー処理と結果表示
使い方は単純だ。左のペインに音声ファイルを落とすと、キューに1行増えて進捗バーが伸び、終わると右に結果が出る。下は、デモ用に用意したサンプル音声(アプリ自身の説明を読み上げた無害な音声)を実際に流した画面だ。

結果欄の上のプルダウンで、複数流したファイルを切り替えて見られる。文字起こしと同時に、設定で選んだフォーマットのファイルが出力フォルダに書き出される。今回は plain・SRT・VTT の3つにチェックを入れていたので、1本のwavから demo_sample.txt・demo_sample.srt・demo_sample.vtt の3ファイルが同時に落ちた。字幕として使いたいなら SRT をそのまま動画編集ソフトへ、下書きにしたいなら txt を、という具合に、後工程に合わせて選べる。画面のテキストはあくまで確認用で、本体は書き出されたファイルのほうだ。この画面を撮ったときの実測では、20秒ほどの読み上げ音声がモデル読み込み込みで15秒足らずで終わった。GPU を使わず CPU だけでこの速さなら、長い会議録でも一晩回す覚悟までは要らない。日本語の句読点の位置も自然で、そのまま議事録の下書きに使える精度だった。
作り方の要点:エンジンとフォーマットを「後から足せる」形にする
いちばん効いた設計判断は、エンジンとフォーマットをレジストリ越しに遅延読み込みにしたことだ。エンジンは名前(”faster-whisper” など)から実装クラスを引く辞書を1枚持っていて、実際に選ばれたときだけ importlib でそのモジュールを読み込む。おかげで、faster-whisper だけ入れておけば openai-whisper(重い torch を連れてくる)を入れなくてもアプリは起動する。使うエンジンのぶんだけ依存が要る、という素直な形になった。フォーマットも同じで、plain/srt/vtt… をそれぞれ独立したクラスにして名前で登録してある。新しい出力形式を足したいときは、1クラス書いて登録するだけで設定のチェックボックスにも増える。
文字起こしは時間がかかるので、UI を固めないために別スレッドへ逃がす。Qt の QThreadPool にジョブを積み、ワーカースレッドがエンジンを呼び、進捗・完了・失敗を Signal でメインスレッドへ戻す。画面側はその通知を受けて進捗バーと結果欄を更新するだけ。だからファイルを何本ドロップしても、UI は固まらずに順番に片づく。
faster-whisper は音声ファイルのパスをそのまま渡せば、内部の PyAV で読み込んでくれる。だから外部の ffmpeg を別途 PATH に通さなくても、wav も mp3 も読める。ここは実装していて助かった部分で、配布のときに「ffmpeg も入れてください」という但し書きを1つ減らせる。なお GUI に使っている PySide6 は LGPLv3 で、アプリを第三者へ配布する場合はライセンス文の同梱など LGPL の条件に従う必要がある(自分の環境で使う分には制約は無い)。処理は最初から最後まで自分のPCの中で完結するので、録音をどこかへ送らずに済む。手元で終わる、というのがこのアプリのいちばんの価値だ。
実際に動かして見えたこと(と、まだ無いもの)
正直に書く。今この記事のスクリーンショットで動いているのは Phase 1 の中核までだ。エンジン切替・多フォーマット出力・ドロップして待つキュー処理は、実際に手元で動く。日本語の読み上げ音声を large-v3-turbo で流したら、句読点を含めてほぼそのまま書き起こせた。ここは想定どおりだった。
カードの説明に書いていた「波形表示と行クリック再生の同期エディタ」「話者分離」「クラッシュ復元つきのプロジェクト保存」は、設計書には起こしてあるが、まだ実装していない(Phase 2 と Phase 3 に置いてある)。設定に speaker フォーマットのチェックはあるが、今は複数話者を聞き分けるところまでは動かない。ここを「できます」と書くのは嘘になるので、はっきり「これから」と書いておく。動くMVPと、これから足す機能を、同じ棚に並べないようにしたい。
手元で終わる文字起こしは、思っていたより気楽だ。
正直なまとめ
文字起こしアプリは世の中に山ほどある。それでも自分で作る意味があるとしたら、私は「エンジンを選べること」と「手元で完結すること」の2点だと考えている。案件によって faster-whisper で十分な日もあれば、API に投げたい日もある。録音を外に出したくない相手の音声もある。その選択を自分のアプリの設定1枚に集約できるのは、既製ツールを乗り換えて回るより楽だった。作りの土台は PySide6 と faster-whisper、あとはエンジンとフォーマットを名前で足せるレジストリ。まずはこの MVP を動かし、波形エディタと話者分離は次の Phase に積む。全部を最初に作ろうとせず、いちばん使う「ドロップして文字にする」を先に固めたのは、今のところ正解だったと思う。
この制作で使ったもの PR
🖥 サーバ/ドメイン
🤖 使ったAIツール(公式)
📚 技術書(Amazon)
👉 関連: 開発実例ギャラリー:Transcription Studio ・ ほかのアプリの作り方 ・ バイブコーディング入門



