会議や取材の録音を、聞き直しながら手で打ち直す。あの時間が、何より惜しい。しかもクラウドの文字起こしは、音声をどこかへアップロードするのが気になる場面もある。録音から Word 出力まで、手元だけで完結させる。
目次
このガイドで作るもの
マイク録音や音声ファイルを Whisper でローカル文字起こしし、そのまま Word(.docx) に書き出す Windows デスクトップアプリ(CustomTkinter 製)。ネット接続なしで動き、結果はアプリ上で編集してから保存できる。
構成は役割ごとに分けてある。文字起こしは transcriber/whisper_engine.py、録音は audio/recorder.py、Word出力は exporter/docx_writer.py、画面は gui/app.py。
手起こしの時間は、どこへ消えているのか
例えば1時間の会議録音を手で起こすと、再生時間の何倍もかかる。タイピングが速くても、実際の作業は「数秒聞く→止める→打つ→聞き逃して巻き戻す」の繰り返しで、再生1に対して作業3〜5倍は珍しくない。夕方の1時間会議が、翌日の午前を丸ごと食う計算だ。
文字起こしサービスを使えば時間は解決するが、今度は「音声を外部にアップロードする」ことが引っかかる場面が出てくる。社外秘の会議、取材相手との約束、家族の記録。内容がセンシティブなほど、時間の問題とプライバシーの問題が同時に立ちはだかる。このアプリは、その2つを一度に潰すための道具だ。

設計の起点:Whisper をローカルで動かす
精度とプライバシーを両立させるため、文字起こしは Whisper をローカル実行にした。クラウドに音声を送らずに済む。日本語なら small 以上が精度・速度のバランスが良く、GPU が無くても small で実用になる。モデルは初回使用時に自動ダウンロードされる。
モデルサイズの選び方
Whisper には大きさ違いのモデルが用意されている。パラメータ数と必要メモリは公式READMEの公表値だ。
| モデル | パラメータ | 必要VRAMの目安 | 向き |
|---|---|---|---|
tiny |
3,900万 | 約1GB | まず動かす・速度最優先 |
base |
7,400万 | 約1GB | 短いメモの下書き |
small |
2億4,400万 | 約2GB | 日本語の実用ライン(このアプリの既定) |
medium |
7億6,900万 | 約5GB | 精度重視・GPUがあるなら |
large |
15億5,000万 | 約10GB | 最高精度・GPU前提 |
迷ったら small から。日本語は tiny/base だと誤変換が目立ち、medium 以上を CPU で回すと待ち時間が実用の線を超えやすい。small で全体を起こし、精度が足りない箇所だけアプリ上の編集で直す運用が現実的だ。
入れられる音声の形式
mp3 / wav / m4a など、一般的な音声はほぼそのまま入る。変換を裏で担っているのは ffmpeg で、Whisper は音声の読み込みに内部で ffmpeg を使う。「ファイルを読み込めない」系のエラーが出たら、まず ffmpeg が入っているかを疑うと早い(無ければ「Windows で ffmpeg を入れる手順」をAIに聞けば数分で済む)。スマホの録音(m4a)をそのまま投げ込めるのは、この仕組みのおかげだ。
クラウド型サービスとの使い分け
ローカル実行が常に正解というわけでもないので、線引きを書いておく。
- ローカル(このアプリ)が向く … 外に出せない音声・毎月大量に起こす・ネットの無い環境。回数無制限でランニングコストがかからないのは、量が増えるほど効く。
- クラウド型が向く … 非力なパソコンしか無い・話者の自動分離など高度な機能が欲しい・たまにしか使わない。処理を向こうのサーバーが担うぶん、手元の性能を問わない。
判断軸は「音声を外に出せるか」と「月に何時間ぶん起こすか」の2つ。出せない音声が1本でもあるなら、ローカルの選択肢を手元に持っておく価値がある。両方使い分ける形に落ち着く人も多い。
作り方の要点
1. ローカル Whisper で文字起こしする
モデルを読み込み、日本語指定で transcribe する。download_root を渡せばモデルの保存先を制御できる。
# transcriber/whisper_engine.py
import whisper
model = whisper.load_model("small", download_root=MODELS_DIR) # 初回に自動DL
result = model.transcribe(
audio_path, language="ja", verbose=False,
condition_on_previous_text=False, # ← 幻聴対策(後述)
no_speech_threshold=0.6,
logprob_threshold=-1.0,
compression_ratio_threshold=2.4,
)
2. ハルシネーション(幻聴)対策
ここが地味に効く本題だ。Whisper は無音や短い音声で「ご視聴ありがとうございました」のような幻聴文を生成することがある。知らないと「謎の一文が混入する」と延々悩むことになる。対策は二段構え。
① パラメータで抑える(上のコード):condition_on_previous_text=False で直前テキストへの依存を切り、no_speech_threshold / logprob_threshold を調整する。
② セグメント単位で無音を捨てる:各セグメントの no_speech_prob(無音である確率)を見て、無音らしいものを結果から落とす。閾値 0.7 の調整方向も知っておくと迷わない。幻聴が残るなら閾値を下げて厳しくし、実際の発言まで消えるなら上げて緩める。会議のような「静かな間が多い録音」ほど幻聴は出やすいので、素材によってはここを触る価値がある。調整するときは同じ音声で before/after を見比べるのが確実だ。
# 無音由来の幻聴セグメントを no_speech_prob で落とす
parts = [
seg["text"] for seg in result["segments"]
if seg.get("no_speech_prob", 0) < 0.7
]
text = "".join(parts) if parts else result["text"]
3. 重い処理は別スレッドへ逃がす
文字起こしは時間がかかる。メインスレッドで走らせると GUI が固まる。別スレッドで実行し、UI更新はメインスレッドへ戻す(CustomTkinter/tkinter は after でマーシャリングする)。「固まらない」ことは、それだけで品質になる。
# gui/app.py — 重い transcribe は別スレッド、UI更新はメインへ戻す
def run():
text = engine.transcribe(path)
self.after(0, lambda: self._show_result(text)) # メインスレッドで反映
threading.Thread(target=run, daemon=True).start()
4. 入力デバイスは「選べる」ようにする
環境によっては既定の入力がミックス出力等になっていて、録音すると無音になる。sounddevice で入力可能なデバイスを列挙し、ユーザーが選べるドロップダウンを用意する。
# audio/recorder.py — 入力可能なデバイスだけ列挙して選ばせる
import sounddevice as sd
def get_input_devices():
return [
{"index": i, "name": d["name"]}
for i, d in enumerate(sd.query_devices())
if d["max_input_channels"] > 0 # 入力チャンネルがあるものだけ
]
# 選択したデバイスで録音(16kHz / mono)
stream = sd.InputStream(samplerate=16000, channels=1, dtype="float32",
device=device_index, callback=audio_callback)
5. 結果を編集してから Word へ
文字起こしは完璧ではない。結果をアプリ上で直してから python-docx で .docx に書き出す。日本語が化けないよう、東アジアフォントを明示設定するのがコツだ。
# exporter/docx_writer.py — 日本語フォントを東アジア設定して .docx 出力
from docx import Document
from docx.oxml.ns import qn
doc = Document()
font = doc.styles['Normal'].font
font.name = font_name
font._element.get_or_add_rPr().get_or_add_rFonts().set(qn('w:eastAsia'), font_name)
for line in text.split("\n"):
doc.add_paragraph(line)
doc.save(output_path)
6. 精度の半分は「録音の質」で決まる
モデルをいくら大きくしても、元の音が悪ければ結果は崩れる。録音側で効く工夫は素朴だ。マイクを話者に近づける(会議ならテーブル中央へ)、エアコンや換気扇から離す、複数人が同時に話す時間を減らす。コードで samplerate=16000, channels=1(16kHz・モノラル)にしているのは、Whisper が内部で16kHzに変換して処理するためで、最初からこの形式で録れば無駄がない。高音質48kHzステレオで録っても、精度は上がらずファイルだけ重くなる。
7. 起こした後は、AIチャットに整形させる
Whisper の出力は「話し言葉がそのまま文字になった」状態だ。えー、あのー、が混ざり、句読点も話し言葉のリズムで付く。ここからの整形は、AIチャットの得意分野になる。出力テキストを Claude や ChatGPT に貼り、「会議の議事録として整形してください。発言の要旨を保ち、フィラー(えー、あのー)を除去、決定事項とTODOを最後にまとめて」と頼めば、読める議事録まで一気に進む。ローカルWhisperで起こし、チャットAIで整える。この二段構えが、実務で一番速い組み合わせだ(機密の音声は起こすまでをローカルで完結させ、整形に出すテキストの中身は自分で判断する)。
つまずきと対策
- 謎の一文が混入する:無音区間の幻聴。パラメータ調整+
no_speech_probでのセグメント除去で抑える。 - 録音が無音になる:入力デバイスの取り違え。デバイス選択UIで明示的に選ばせる。
- GUIが固まる:重い transcribe をメインスレッドで実行している。別スレッド+
afterでUIへ戻す。
使用ライブラリと順守メモ
- openai-whisper … MIT ライセンス(コード・モデル重みとも)。モデルは初回に公式から各自ダウンロードされる。
- その他の依存(CustomTkinter/sounddevice/soundfile/pydub/python-docx)は MIT・BSD 系、torch は BSD-3。
- 録音・文字起こしする音声は、自身が権利を持つ、または録音・利用の同意を得たものに限ること(会議・通話の録音は相手の同意や各地域の法令に注意)。
- 本アプリはローカル処理のため音声を外部送信しないが、出力した文書の取り扱いは利用者の責任で行う。
まとめ
土台は4つ。① ローカルWhisperで精度とプライバシーを両立、② 幻聴はパラメータ+セグメント除去で抑える、③ 重い処理は別スレッド+afterでUIへ戻す、④ 入力デバイスは選ばせる。これらは音声を扱うデスクトップアプリの共通の足場として、そのまま使える。録音の質と後工程の整形まで含めて1本の流れにすれば、手起こしの時間は道具に置き換わる。
この制作で使ったもの PR
🖥 サーバ/ドメイン
🤖 使ったAIツール(公式)
📚 技術書(Amazon)
👉 関連: 開発実例:Voice Docs Converter ・ ほかのアプリの作り方



