OllamaとWhisperでローカル音声文字起こし・要約パイプラインを構築する方法|会議録をローカルLLMで議事録に自動変換する手順

宮崎智広 この記事の監修:宮崎智広(Linux実務・教育歴20年以上・受講者3,100名超)
HOMELinux技術 リナックスマスター.JP(Linuxマスター.JP)ローカルLLM > OllamaとWhisperでローカル音声文字起こし・要約パイプラインを構築する方法|会議録をローカルLLMで議事録に自動変換する手順
「会議の録音ファイルが増えるばかりで、議事録の作成に毎回1時間以上かかっている」
「音声認識サービスのAPIに機密情報が含まれる会議音声を送るのはセキュリティ上リスクがある」

そんな悩みを抱えるインフラ担当者・情シス担当者は多いはずだ。この記事では、オープンソースの音声認識ライブラリ「faster-whisper」とOllamaを組み合わせ、会議録音ファイルを完全ローカル環境で文字起こしし、さらにローカルLLMで議事録フォーマットに自動変換するパイプラインをUbuntu Server上に構築する手順を解説する。
外部APIへの通信はゼロ。完成後は引数に音声ファイルを渡すだけで、決定事項・アクションアイテム・次回議題を整理したテキスト議事録が自動生成される。

この記事のポイント

・faster-whisperとOllamaを組み合わせると音声→文字起こし→要約が完全ローカルで完結する
・pip install faster-whisper+ffmpegで日本語会議音声の文字起こし精度は実用レベルに達する
・Pythonスクリプト1本でバッチ処理に対応し、cronで定期自動実行にも組み込める
・GPUなしのCPU環境でも動作する(60分音声の文字起こしは5~8分程度が目安)


OllamaとWhisperでローカル音声文字起こし・要約パイプラインを構築する方法|会議録をローカルLLMで議事録に自動変換する手順

「このままじゃマズい」と感じていませんか?
参考書を開く気力もない、同年代に取り残される不安——
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら

会議音声をローカルで処理することの業務的メリット

企業の会議録音には、顧客名・取引金額・未発表の製品情報など、社外に出せないデータが含まれることが多い。クラウドの音声認識APIやAIサービスに音声ファイルを送ると、サービス利用規約によってはデータがモデルの再学習に使われる可能性があり、情報セキュリティ部門の承認が取れないケースも少なくない。

社内でChatGPTが使えないときの代替手段|機密データを守るローカルLLMという選択肢でも解説しているように、クラウドAI利用が制限される環境では「ローカル音声認識+ローカルLLM」の組み合わせが現実解になる。

ローカル処理に切り替えた場合のメリットを整理する。

・データが外部サーバーに送出されない(情報漏えいリスクがない)
・API従量課金が発生しない(月額費用を実質ゼロにできる)
・ネットワーク断・速度低下に左右されず、社内LAN内だけで完結する
・音声ファイルの保存場所・保持期間を自社でコントロールできる

現場で聞いた話では、クラウドASRサービスの月額費用が80万円を超えていた会社がローカル処理に切り替え、ランニングコストを電気代のみに圧縮できたというケースがある。議事録作成工数の削減と組み合わせると、費用対効果は非常に高い。

パイプラインの全体構成とコンポーネントの役割分担

このパイプラインは2つのオープンソースコンポーネントで構成する。

faster-whisper: OpenAIが公開したWhisperモデルをCTranslate2エンジンで高速・省メモリ化した実装。音声ファイルをテキストに変換し、タイムスタンプ付きで出力する
Ollama: 文字起こし済みテキストをプロンプトに組み込み、議事録フォーマット(決定事項・アクションアイテム・次回議題)への変換を担当する

処理フローは以下のとおりだ。

音声ファイル(mp4/m4a/wav)→ ffmpegで音声抽出 → faster-whisperで文字起こし → テキスト保存 → OllamaのAPIで要約・整形 → 議事録テキスト出力

Ollamaのセットアップがまだの場合は、Ubuntu ServerでローカルLLMを構築する方法|Ollamaで機密データを外に出さず業務AIを動かす完全ガイドを先に参照してほしい。Ollamaの導入・起動確認まで完了していることを前提として進める。

要約に使うモデルは、日本語テキストを長いコンテキストで処理する場合でも安定している Llama3.3 または Mistral を推奨する。モデルの選定についてはローカルLLMのモデルを比較する方法|Llama3.3・Mistral・Gemma・Phi-4をUbuntuで使い分けるポイントが参考になる。

環境構築|Pythonとfaster-whisperのインストール手順

1. 動作環境の確認

Ubuntu 22.04/24.04 LTS、Python 3.10以上で動作確認済みだ。まずPythonとffmpegのバージョンを確認する。

# Pythonバージョン確認(3.10以上が必要) $ python3 --version Python 3.10.12 # ffmpegの確認(mp4/m4aなど各形式の音声変換に必要) $ ffmpeg -version | head -1 ffmpeg version 4.4.2-0ubuntu0.22.04.1

ffmpegが入っていない場合は先にインストールする。

$ sudo apt update && sudo apt install -y ffmpeg

2. Python仮想環境の作成

プロジェクト用のディレクトリを作成し、仮想環境を構成する。システム全体のPython環境を汚さないために仮想環境の使用を推奨する。

# プロジェクトディレクトリの作成 $ mkdir -p ~/whisper-pipeline && cd ~/whisper-pipeline # 仮想環境を作成して有効化 $ python3 -m venv venv $ source venv/bin/activate (venv) $

3. faster-whisperのインストール

(venv) $ pip install faster-whisper requests ... Successfully installed faster-whisper-1.0.3 requests-2.32.3

インストール後に動作確認する。

(venv) $ python3 -c "from faster_whisper import WhisperModel; print('faster-whisper OK')" faster-whisper OK

faster-whisperで音声ファイルを文字起こしする手順

1. Whisperモデルのサイズと日本語精度

faster-whisperが対応するモデルサイズはtiny・base・small・medium・large-v3の5種類だ。日本語会議録音の文字起こしには以下の基準でモデルを選ぶ。

・tiny/base: 処理が速いがビジネス日本語の認識精度が低い。テスト用途向け
・small: 日常会話なら実用的。専門用語・固有名詞が多い会議録音では誤認識が目立つ
・medium: ビジネス会議に対応できる精度。RAMまたはVRAM 5GB程度が必要
・large-v3: 最高精度。専門用語・多人数会議でも安定。RAM 10GB以上を推奨

まずmediumから試して、精度が足りなければlarge-v3に切り替えるのが現実的な進め方だ。compute_type="int8"を指定するとRAM使用量を約半分に削減できる。

2. 文字起こしスクリプトの作成

~/whisper-pipeline/transcribe.py を以下の内容で作成する。

from faster_whisper import WhisperModel import sys, pathlib def transcribe(audio_path: str, model_size: str = "medium") -> str: model = WhisperModel(model_size, device="cpu", compute_type="int8") segments, info = model.transcribe(audio_path, language="ja", beam_size=5) print(f"検出言語: {info.language} 確度: {info.language_probability:.2f}") lines = [] for seg in segments: mm = int(seg.start // 60) ss = int(seg.start % 60) lines.append(f"[{mm:02d}:{ss:02d}] {seg.text.strip()}") return "\n".join(lines) if __name__ == "__main__": if len(sys.argv) < 2: print("使い方: python3 transcribe.py <音声ファイル> [モデルサイズ]") sys.exit(1) audio = sys.argv[1] size = sys.argv[2] if len(sys.argv) > 2 else "medium" text = transcribe(audio, size) out = pathlib.Path(audio).stem + "_transcript.txt" pathlib.Path(out).write_text(text, encoding="utf-8") print(f"保存完了: {out}")

3. 実行と出力サンプル

(venv) $ python3 transcribe.py meeting_20260724.m4a medium 検出言語: ja 確度: 0.99 保存完了: meeting_20260724_transcript.txt (venv) $ head -6 meeting_20260724_transcript.txt [00:00] それでは本日の定例会議を始めます。 [00:05] まずアジェンダの確認をお願いします。 [00:12] 先週のタスク進捗から報告します。 [00:18] 第3四半期のサーバー更新スケジュールについて確認したいと思います。 [00:25] はい、ベンダーの選定が先週完了しました。 [00:31] 見積もりの金額は予算内に収まっています。

初回実行時はモデルファイルのダウンロードが走るため5~10分かかる。2回目以降はキャッシュを使うため即座に処理が始まる。

OllamaのAPIで文字起こしテキストを要約・議事録化する手順

1. プロンプト設計と注意点

文字起こしテキストをOllamaに渡して議事録形式に変換させる。60分の会議録音だと文字起こし結果が6,000字を超えることが多い。デフォルトのコンテキストウィンドウ(4,096トークン)では収まらないため、num_ctxオプションで拡張する必要がある。

また、要約の創造性は不要なので temperature は0.2に下げる。事実の整理が目的のため、高い値を設定すると誤要約が増える。

2. curlによる疎通確認

Pythonスクリプトを書く前に、curlでOllamaが応答することを確認しておくと原因切り分けが楽になる。

# テスト用プロンプトでOllamaの疎通確認 $ curl -s http://localhost:11434/api/generate \ -d '{"model":"llama3.3:70b-instruct-q4_0","prompt":"こんにちは","stream":false}' \ | python3 -c "import sys,json; print(json.load(sys.stdin)['response'])" こんにちは。何かお手伝いできることはありますか?

レスポンスが返ってこない場合は systemctl status ollama でサービス状態を確認する。

3. Pythonからの要約呼び出し実装

import requests OLLAMA_URL = "http://localhost:11434/api/generate" def summarize(transcript: str, model: str = "llama3.3:70b-instruct-q4_0") -> str: prompt = f"""以下の会議の文字起こしを議事録としてまとめてください。 出力は以下の形式でお願いします。 # 決定事項 (箇条書き) # アクションアイテム (担当者・期限付きで箇条書き) # 次回議題 (箇条書き) --- 文字起こし --- {transcript} """ payload = { "model": model, "prompt": prompt, "stream": False, "options": { "num_ctx": 16384, "temperature": 0.2 } } resp = requests.post(OLLAMA_URL, json=payload, timeout=300) resp.raise_for_status() return resp.json()["response"]

PythonパイプラインスクリプトでWhisper→Ollama連携を自動化する手順

1. 統合スクリプト minutes.py の作成

文字起こしと要約を1コマンドで完結させる統合スクリプトを作成する。~/whisper-pipeline/minutes.py として保存する。

#!/usr/bin/env python3 """音声ファイルから議事録を生成するパイプライン 使い方: python3 minutes.py <音声ファイル> [--model <モデル名>] [--whisper <サイズ>] """ import argparse, pathlib, requests from faster_whisper import WhisperModel OLLAMA_URL = "http://localhost:11434/api/generate" PROMPT_TMPL = """以下の会議文字起こしを議事録としてまとめてください。 # 決定事項 # アクションアイテム(担当者・期限) # 次回議題 --- 文字起こし --- {text}""" def transcribe(audio: str, whisper_size: str) -> str: model = WhisperModel(whisper_size, device="cpu", compute_type="int8") segs, info = model.transcribe(audio, language="ja", beam_size=5) print(f" [whisper] 言語={info.language} 確度={info.language_probability:.2f}") return "\n".join( f"[{int(s.start//60):02d}:{int(s.start%60):02d}] {s.text.strip()}" for s in segs ) def summarize(text: str, model: str) -> str: r = requests.post(OLLAMA_URL, json={ "model": model, "prompt": PROMPT_TMPL.format(text=text), "stream": False, "options": {"num_ctx": 16384, "temperature": 0.2} }, timeout=300) r.raise_for_status() return r.json()["response"] def main(): ap = argparse.ArgumentParser() ap.add_argument("audio") ap.add_argument("--model", default="llama3.3:70b-instruct-q4_0") ap.add_argument("--whisper", default="medium") args = ap.parse_args() stem = pathlib.Path(args.audio).stem print(f"[1/2] 文字起こし開始: {args.audio}") transcript = transcribe(args.audio, args.whisper) tr_path = stem + "_transcript.txt" pathlib.Path(tr_path).write_text(transcript, encoding="utf-8") print(f" -> {tr_path} 保存完了") print(f"[2/2] 要約開始 (model={args.model})") minutes = summarize(transcript, args.model) min_path = stem + "_minutes.txt" pathlib.Path(min_path).write_text(minutes, encoding="utf-8") print(f" -> {min_path} 保存完了") if __name__ == "__main__": main()

2. 実行例と出力確認

(venv) $ python3 minutes.py meeting_20260724.m4a \ --model llama3.3:70b-instruct-q4_0 --whisper medium [1/2] 文字起こし開始: meeting_20260724.m4a [whisper] 言語=ja 確度=0.99 -> meeting_20260724_transcript.txt 保存完了 [2/2] 要約開始 (model=llama3.3:70b-instruct-q4_0) -> meeting_20260724_minutes.txt 保存完了 (venv) $ cat meeting_20260724_minutes.txt # 決定事項 - 第3四半期のサーバー更新は8月中旬に実施する - ベンダーはA社に決定した # アクションアイテム - 田中(インフラ): 更新手順書の作成(7/31まで) - 鈴木(情シス): 現行サーバーのバックアップ確認(8/1まで) # 次回議題 - 更新手順書のレビュー - 本番切り替え日程の最終確認

3. 複数ファイルのバッチ処理

ディレクトリ内の音声ファイルを一括処理する場合はシェルのforループを使う。

# /recordings/ 内のm4aファイルを全件処理 (venv) $ for f in /recordings/*.m4a; do echo "--- 処理中: $f ---" python3 ~/whisper-pipeline/minutes.py "$f" \ --model llama3.3:70b-instruct-q4_0 --whisper medium done

実行時に起きやすいトラブルと対処法

1. 文字起こし中にKilledと表示されて強制終了される

RAM不足が原因だ。mediumモデルはRAMを4~5GB消費する。空きメモリを確認し、不要なプロセスを停止してから再実行する。

# メモリの空き確認 $ free -h total used free Mem: 16Gi 11Gi 4.8Gi # 解決策1: smallモデルに変更(RAM約2GB・速度向上) (venv) $ python3 minutes.py meeting.m4a --whisper small # 解決策2: スワップ領域を追加する(large-v3使用時など) $ sudo fallocate -l 8G /swapfile $ sudo chmod 600 /swapfile $ sudo mkswap /swapfile && sudo swapon /swapfile

2. 日本語の固有名詞・社名が誤認識される

Whisperは一般的な日本語には強いが、社名・製品名・部門名などは誤認識しやすい。initial_prompt引数に頻出する固有名詞を渡すと精度が改善する。

transcribe.py の model.transcribe 呼び出しに引数を追加する形だ。

# initial_promptに社名・製品名・人名を渡す例 segments, info = model.transcribe( audio_path, language="ja", beam_size=5, initial_prompt="株式会社イーネットマーキュリー、Ubuntu Server、Ollama、田中部長、鈴木さん" )

3. 長い会議録音でOllamaがレスポンスを返さない

90分を超える会議録音は文字起こし結果が1万字を超えることがある。num_ctx=16384でも収まらない場合は、ffmpegで音声を30分ごとに分割してそれぞれ処理し、最後にまとめる方法が有効だ。

# 音声を30分(1800秒)ずつに分割する例 $ ffmpeg -i meeting_90min.m4a -f segment -segment_time 1800 \ -c copy meeting_part%02d.m4a # 分割後のファイルを確認 $ ls -lh meeting_part*.m4a -rw-r--r-- 1 user user 28M meeting_part00.m4a -rw-r--r-- 1 user user 27M meeting_part01.m4a -rw-r--r-- 1 user user 15M meeting_part02.m4a

4. m4aやmp4ファイルが読み込めないエラーが出る

ffmpegが未インストールの場合に起きる。以下で確認・インストールする。

# ffmpegの確認 $ ffmpeg -version | head -1 # コマンドが見つからない場合はインストールする $ sudo apt install -y ffmpeg $ ffmpeg -version | head -1 ffmpeg version 4.4.2-0ubuntu0.22.04.1

まとめ

faster-whisperとOllamaを組み合わせた、ローカル完結の音声議事録自動生成パイプラインを構築した。処理の全ステップをまとめる。
ステップ コマンド・処理 ポイント
環境構築 pip install faster-whisper requests 仮想環境で依存を分離する
音声前処理(長時間録音) ffmpeg -i input.mp4 -f segment -segment_time 1800 out%02d.m4a 90分超の録音は30分単位で分割する
文字起こし python3 transcribe.py meeting.m4a medium 日本語はmedium以上推奨・int8でRAM節約
要約・議事録化 python3 minutes.py meeting.m4a --model llama3.3:70b-instruct-q4_0 num_ctx=16384・temperature=0.2で精度確保
バッチ処理 for f in /recordings/*.m4a; do python3 minutes.py "$f"; done forループで複数ファイルを連続処理する
固有名詞対策 model.transcribe(audio, initial_prompt="社名リスト") 社名・人名をプロンプトに渡すと精度が向上する

GPUなしのCPU環境(Intel Core i7相当)で60分録音をmediumモデルで処理した場合、文字起こしに5~8分、Ollamaによる要約に2~4分程度が目安だ。処理時間が許容できない場合は、GPU対応マシンに移行するかlarge-v3からsmallへモデルを下げて速度と精度のバランスを調整する。

20年以上Linuxサーバーを運用してきた経験から言うと、このパイプラインが特に効果を発揮するのは週次定例会議のような「定型の会議を大量にこなす」環境だ。一度セットアップしてcronに組み込めば、録音ファイルの置き場所を決めるだけで議事録が自動生成される仕組みが完成する。

ローカル音声認識とLLMパイプラインを2日間のハンズオンで体験する

Whisper・Ollama・Pythonを組み合わせたパイプライン構築を、実機環境で手を動かして習得したい方向けに、「ローカルAIマスターセミナー」を開催しています。
少人数(最大8名)ZOOMハンズオン形式で実施しています。

>> ローカルAIマスターセミナーの詳細を確認する
ローカルLLMの構築・運用に関する関連記事もあわせて参考にしてください。

Ubuntu ServerでローカルLLMを構築する方法|Ollamaで機密データを外に出さず業務AIを動かす完全ガイド
社内でChatGPTが使えないときの代替手段|機密データを守るローカルLLMという選択肢
ローカルLLMのモデルを比較する方法|Llama3.3・Mistral・Gemma・Phi-4をUbuntuで使い分けるポイント

無料メルマガで学習を続ける

Linuxの実践スキルをメールで毎週お届け。
登録は30秒、解除もいつでも可。

登録無料・いつでも解除できます

暗記不要・1時間後にはサーバーが動く

3,100名以上が実践した「型」を無料で公開中

プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。

姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら

Linux無料マニュアル(図解60P) 名前とメールで30秒登録
宮崎 智広

この記事を書いた人

宮崎 智広(みやざき ともひろ)

株式会社イーネットマーキュリー代表。現役のLinuxサーバー管理者として20年以上の実務経験を持ち、これまでに累計3,100名以上のエンジニアを指導してきたLinux教育のプロフェッショナル。「現場で本当に使える技術」を体系的に伝えることをモットーに、実践型のLinuxセミナーの開催や無料マニュアルの配布を通じてLinux人材の育成に取り組んでいる。

趣味は、キャンプにカメラ、トラウト釣り。好きな食べ物は、ラーメンにお酒。休肝日が作れない、酒量を減らせないのが悩み。最近、ドラマ「フライトエンジェル」を観て涙腺が崩壊しました。