faster-whisper + Ollamaで作る完全ローカル会議文字起こしツール
はじめに
会議の文字起こしや議事録作成は、多くのビジネスシーンで必要とされる作業です。しかし、クラウドベースの文字起こしサービスには以下のような課題があります。
- 機密性の高い会議内容を外部サービスに送信することへの懸念
- 音声データの送受信にかかる時間とコスト
- インターネット接続に依存する制約
- 継続的なAPI利用料の発生
これらの課題を解決するため、完全ローカル環境で動作する会議文字起こしツールを開発しました。faster-whisperによる高精度な日本語文字起こしと、OllamaによるローカルLLMを活用した議事録自動生成を、すべてローカル環境で実現しています。
本記事では、このツールの技術的な実装と工夫点について解説します。
コンソール動作イメージ

システム概要
本ツールは以下の3つの主要機能を提供します。
- マイク録音機能
- faster-whisperによる文字起こし(日本語特化モデル対応)
- Ollamaによる議事録自動生成(RAG対応)
技術スタック
- 音声録音: sounddevice
- 文字起こし: faster-whisper (CTranslate2ベース高速実装)
- 日本語特化モデル: Kotoba Whisper V1.0
- 議事録生成: Ollama (qwen2.5:7b, llama3.1:8b等)
- RAG: Ollama Embeddings (mxbai-embed-large)
- パッケージ管理: uv
- コード品質: ruff + mypy + pytest
アーキテクチャ
完全ローカル実行の利点
1. プライバシーとセキュリティの確保
すべての処理がローカル環境で完結するため、機密性の高い会議内容を外部に送信する必要がありません。企業の経営会議や顧客情報を含む打ち合わせなど、セキュリティが重視される場面でも安心して利用できます。
2. コストゼロでの運用
クラウドサービスと異なり、API利用料やデータ転送料は一切発生しません。初期セットアップ後は、CPU/メモリリソースのみで無制限に利用できます。
一般的なクラウド文字起こしサービスでは、1時間の音声で数百円から数千円のコストがかかります。頻繁に会議を行う組織では、年間で数十万円のコスト削減につながります。
3. オフライン環境での利用
インターネット接続が不安定な環境や、セキュリティポリシーでクラウドサービスが利用できない環境でも動作します。また、ネットワーク遅延による待ち時間もありません。
4. データの永続的な保持
生成したデータはすべてローカルに保存されるため、サービス終了やアカウント削除によるデータ消失のリスクがありません。長期的なアーカイブにも適しています。
faster-whisperの採用理由
OpenAI Whisperとの比較
OpenAIが提供するWhisperは優れた音声認識モデルですが、オリジナル実装はPythonベースで処理速度に課題があります。faster-whisperは、CTranslate2を用いてWhisperモデルを最適化した実装で、以下の特徴があります。
- オリジナルWhisperと比較して最大4倍の高速化
- int8量子化によりメモリ使用量を大幅に削減
- CPU環境でも実用的な速度で動作
- GPU環境ではさらに高速化
実装例
from faster_whisper import WhisperModel
class Transcriber:
def __init__(self, model_name: str = "medium", device: str = "cpu", compute_type: str = "int8"):
self.model = WhisperModel(model_name, device=device, compute_type=compute_type)
def transcribe(
self,
audio_path: Path,
language: str = "ja",
beam_size: int = 5,
vad_filter: bool = True,
) -> tuple[str, list[Segment]]:
segments_generator, info = self.model.transcribe(
str(audio_path),
language=language,
beam_size=beam_size,
vad_filter=vad_filter,
)
segments = []
for seg in segments_generator:
segment = Segment(start=seg.start, end=seg.end, text=seg.text.strip())
segments.append(segment)
full_text = "".join([s.text for s in segments])
return full_text, segments
VAD(Voice Activity Detection)の活用
VADフィルターを有効にすることで、無音部分を自動的にスキップし、処理時間を短縮できます。会議の開始前や休憩時間などの無音部分が多い録音でも、効率的に文字起こしを行えます。
vad_parameters = {
"threshold": 0.5, # 音声判定の閾値
"min_speech_duration_ms": 250, # 最小音声長
"min_silence_duration_ms": 2000, # セグメント分割の無音長
}
日本語特化モデル Kotoba Whisper V1.0
OpenAI Whisper large-v3との比較
本ツールでは、日本語に特化したKotoba Whisper V1.0をサポートしています。これはOpenAI Whisper large-v3をベースに、日本語ASR用に蒸留・チューニングされたモデルです。
主な改善点は以下の通りです。
- 元のlarge-v3より最大6.3倍高速
- CER(文字誤り率)とWER(単語誤り率)が改善
- 日本語の話し言葉により強い
モデル選択の実装
JAPANESE_MODELS = {
"small": "small", # 軽量(メモリ: ~1GB)
"medium": "medium", # バランス型(メモリ: ~2GB)
"large-v3": "large-v3", # 高精度(メモリ: ~4GB、完走重視ならこれ)
"large-v3-ja": "kotoba-tech/kotoba-whisper-v1.0-faster", # 日本語特化(CTranslate2版)
}
# ユーザーが選択したモデル名を実際のモデルIDにマッピング
actual_model = JAPANESE_MODELS.get(model_name, model_name)
self.model = WhisperModel(actual_model, device=device, compute_type=compute_type)
faster-whisperはCTranslate2形式のモデルを必要とします。kotoba-tech/kotoba-whisper-v1.0 はHuggingFace Transformers形式のため model.bin が含まれず、faster-whisperでは直接ロードできません。日本語特化モデルを使う場合はCTranslate2変換済みの kotoba-tech/kotoba-whisper-v1.0-faster を指定してください。
実機検証では、Kotoba系(v1.0-faster と v2.0-faster の双方)で音声の途中停止が起きました。途中で停止すると後半の発話が欠落するため、完走の安定性を優先する場合は large-v3 の利用をおすすめします。詳しい計測値は後述の「実機計測結果」を参照してください。
Ollamaによる議事録自動生成
Ollamaの選定理由
議事録生成にOllamaを採用した理由は以下の通りです。
- 完全ローカルで動作するLLMランタイム
- 多様なモデルをワンコマンドでダウンロード可能
- GPU不要でCPU環境でも実用的な速度
- APIがシンプルで統合が容易
推奨モデル
本ツールでは以下のモデルを推奨しています。
| モデル | サイズ | メモリ | 日本語精度 | 特徴 |
|---|---|---|---|---|
| qwen2.5:7b | 4.7GB | ~8GB | 非常に高い | 最推奨。日本語の議事録が自然 |
| llama3.1:8b | 4.7GB | ~8GB | 高い | バランス型。英語も得意 |
| gemma2:9b | 5.4GB | ~10GB | 高い | Google製。高速 |
qwen2.5:7bは多言語対応で日本語の精度が特に高く、議事録作成に最適です。
プロンプトの工夫点
システムプロンプトの設計
議事録生成において、適切なシステムプロンプトの設計が品質を大きく左右します。本ツールでは以下の工夫を行っています。
DEFAULT_SYSTEM_PROMPT = """あなたは優秀な日本語の議事録作成アシスタントです。
会議の文字起こしテキストから、読みやすく整理された議事録を作成してください。
以下の形式で出力してください:
# 議事録
## 📅 会議情報
- 日時: {datetime}
- 参加者: (推測される場合は記載)
## 📋 議題・トピック
会議で話し合われた主要なトピックを箇条書きで記載
## 💬 議論の要約
各トピックについて、どのような議論が行われたかを簡潔にまとめる
## ✅決定事項
会議で決まったことを箇条書きで記載
## 📝 アクションアイテム
- [ ] タスク内容(担当者、期限)
## 📌 その他・メモ
補足事項や次回の予定など
---
注意事項:
- 日本語の自然な文章で書いてください
- 話し言葉を書き言葉に整えてください
- 重要なポイントは太字や箇条書きで強調してください
- 不明確な部分は推測せず、「(不明)」と記載してください
"""
プロンプト設計のポイント
-
明確な出力形式の指定
議事録の構造を明示的に指定することで、一貫性のある出力が得られます。セクションごとに役割を明確にすることで、LLMが何を抽出すべきか理解しやすくなります。
-
具体的な注意事項の列挙
「話し言葉を書き言葉に整える」「不明確な部分は推測しない」など、具体的な指示を与えることで、品質が向上します。
-
動的な情報の埋め込み
日時などの動的な情報は、実行時にプロンプトに埋め込みます。
current_datetime = datetime.now().strftime("%Y年%m月%d日 %H:%M") system_prompt = self.system_prompt.replace("{datetime}", current_datetime) -
temperatureパラメータの調整
議事録作成では正確性が重要なため、temperatureを低めに設定します。
response = ollama.chat( model=self.model, messages=[ {"role": "system", "content": system_prompt}, {"role": "user", "content": user_prompt}, ], options={ "temperature": 0.3, # 創造性を抑えて正確性重視 "num_predict": 2048, # 最大出力トークン数 }, )
プロンプトの改善提案
現在のプロンプトをさらに改善する場合、以下のような方向性が考えられます。
-
ドメイン特化のカスタマイズ
業種や会議の種類に応じてプロンプトをカスタマイズできるようにします。例えば、技術会議では技術的な詳細を重視し、営業会議では数値や期限を強調するなどです。
PROMPTS = { "technical": "技術的な議論の詳細を重視し、決定された技術スタックや設計方針を明確に記載してください。", "business": "数値目標、期限、担当者を明確に記載してください。", "brainstorming": "アイデアの多様性を保ちながら、カテゴリごとに整理してください。", } -
Few-shot学習の活用
良い議事録の例をプロンプトに含めることで、より品質の高い出力が得られます。
example = """ 【良い例】 ## 決定事項 - 新機能のリリース日を2024年12月15日に決定 - 担当者:田中さん(バックエンド)、佐藤さん(フロントエンド) - 予算:50万円 """ system_prompt += f"\n\n{example}" -
後処理による品質向上
LLMの出力後に、特定のフォーマット要件をチェックし、必要に応じて再生成や修正を行います。
def validate_minutes(minutes: str) -> bool: required_sections = ["会議情報", "議題", "決定事項"] return all(section in minutes for section in required_sections) if not validate_minutes(minutes): # 再生成や警告 pass
RAG機能による知識参照
RAGの必要性
会議では、プロジェクト固有の用語や略語、組織内の情報が頻繁に登場します。これらをLLMが正しく理解し、議事録に反映させるため、RAG(Retrieval-Augmented Generation)機能を実装しました。
アーキテクチャ
class KnowledgeBase:
def __init__(
self,
knowledge_dir: Path | None = None,
cache_dir: Path | None = None,
embed_model: str = "mxbai-embed-large",
):
self.knowledge_dir = knowledge_dir or Path("data/knowledge")
self.cache_dir = cache_dir or Path(".rag_cache")
self.embed_model = embed_model
self.knowledge_chunks: list[dict[str, str]] = []
self.embeddings: list[list[float]] = []
self.load_knowledge()
ナレッジベースの構成
data/knowledgeディレクトリに配置したMarkdownファイルが自動的に読み込まれます。
# プロジェクト情報
## 社内プロジェクト
- Project Alpha: 新製品開発プロジェクト。2025年Q2リリース予定
- Project Beta: 既存システムのリニューアル
## 技術用語
- RAG: Retrieval-Augmented Generation(検索拡張生成)
- LLM: Large Language Model(大規模言語モデル)
## チーム構成
- 開発チーム: 田中さん、佐藤さん
- 企画チーム: 鈴木さん、高橋さん
埋め込みとキャッシング
ナレッジベースの埋め込みは初回実行時に生成され、キャッシュとして保存されます。2回目以降はキャッシュから読み込まれるため、高速に起動できます。
def load_knowledge(self) -> None:
cache_file = self.cache_dir / "embeddings.json"
cache_data = {}
# 既存のキャッシュを読み込み
if cache_file.exists():
with open(cache_file, encoding="utf-8") as f:
cache_data = json.load(f)
# ファイルハッシュでキャッシュの有効性を確認
for md_file in md_files:
file_hash = self._compute_file_hash(md_file)
if file_name in cache_data and cache_data[file_name].get("hash") == file_hash:
# キャッシュから復元
cached_chunks = cache_data[file_name]["chunks"]
all_chunks.extend(cached_chunks)
else:
# 新規生成
content = md_file.read_text(encoding="utf-8")
chunks = self._split_into_chunks(content, file_name)
for chunk in chunks:
embedding = self._get_embedding(chunk["content"])
chunk["embedding"] = embedding
類似度検索
文字起こしテキストに関連する知識をコサイン類似度で検索し、上位3件をプロンプトに追加します。
def search(self, query: str, top_k: int = 3, threshold: float = 0.5) -> str:
# クエリの埋め込みを取得
query_embedding = self._get_embedding(query)
# 各チャンクとの類似度を計算
similarities = []
for i, chunk_embedding in enumerate(self.embeddings):
similarity = self._cosine_similarity(query_embedding, chunk_embedding)
if similarity >= threshold:
similarities.append((i, similarity))
# 上位k件を取得
similarities.sort(key=lambda x: x[1], reverse=True)
results = []
for i, _ in similarities[:top_k]:
chunk = self.knowledge_chunks[i]
results.append(f"**{chunk['title']}** (出典: {chunk['source']})\n{chunk['content']}")
return "\n\n---\n\n".join(results)
議事録生成への統合
RAGで取得した知識は、システムプロンプトに追加されます。
def generate(self, transcript: str, meeting_title: str | None = None) -> str:
system_prompt = self.DEFAULT_SYSTEM_PROMPT
# RAGで関連知識を検索
if self.knowledge_base:
relevant_knowledge = self.knowledge_base.search(transcript, top_k=3)
if relevant_knowledge:
system_prompt += "\n\n【参考情報】\n以下の情報を参考にしてください:\n\n"
system_prompt += relevant_knowledge
# LLM実行
response = ollama.chat(
model=self.model,
messages=[
{"role": "system", "content": system_prompt},
{"role": "user", "content": f"【文字起こし】\n{transcript}"},
],
)
return response["message"]["content"]
開発環境の構築
uvによる高速なパッケージ管理
本プロジェクトでは、Rust製の高速パッケージマネージャーuvを採用しています。pipやpoetryと比較して、依存関係の解決とインストールが大幅に高速化されます。
# uvのインストール
curl -LsSf https://astral.sh/uv/install.sh | sh
# プロジェクトのセットアップ
git clone https://github.com/okamyuji/meeting-transcriber.git
cd meeting-transcriber
uv sync
pyproject.tomlで依存関係を管理します。
[project]
name = "meeting-transcriber"
version = "0.1.0"
requires-python = ">=3.11"
dependencies = [
"faster-whisper>=1.0.0",
"sounddevice>=0.4.6",
"numpy>=1.26.0",
"ollama>=0.1.0",
"tqdm>=4.66.0",
"python-dotenv>=1.0.0",
]
[project.optional-dependencies]
dev = [
"ruff>=0.1.0",
"mypy>=1.7.0",
"pytest>=7.4.0",
"pytest-cov>=4.1.0",
"pre-commit>=3.5.0",
]
コード品質管理
ruffとmypyを使用したコード品質管理を行っています。
# Ruffでリント&フォーマット
uv run ruff check app/ main.py --fix
uv run ruff format app/ main.py
# mypyで型チェック
uv run mypy app/ main.py
pre-commitフックを設定することで、コミット時に自動的にチェックが実行されます。
# .pre-commit-config.yaml
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.1.6
hooks:
- id: ruff
args: [--fix]
- id: ruff-format
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.7.1
hooks:
- id: mypy
additional_dependencies: [types-all]
テスト
pytestによる包括的なテストを実装しています。
# すべてのテストを実行
uv run pytest
# カバレッジレポート付き
uv run pytest --cov=app --cov-report=html
主要なモジュールのテストカバレッジは90%以上を維持しています。
実装の詳細
メインCLI
ユーザーインターフェースはシンプルなCLIで提供します。
def print_menu() -> str:
menu = """
【メニュー】
1. 🎙️ 録音 → 文字起こし → 議事録作成(フルワークフロー)
2. 📁 既存の音声ファイルから文字起こし&議事録作成
3. 📝 既存の文字起こしから議事録作成
4. 🎤 録音のみ(テスト用)
5. 🔧 設定(モデル選択など)
6. ❌ 終了
番号を選択してください: """
return input(menu).strip()
フルワークフローの実装
録音から議事録作成までを一気通貫で処理します。
def full_workflow(
recorder: AudioRecorder,
transcriber: Transcriber,
minutes_gen: MinutesGenerator | None = None,
) -> None:
# 会議情報の入力
meeting_title = input("📋 会議タイトル(省略可): ").strip()
additional_context = input("👥 参加者情報など(省略可): ").strip()
# ステップ1: 録音
audio_path = recorder.record_and_save()
# ステップ2: 文字起こし
full_text, segments = transcriber.transcribe(audio_path)
transcript_path = transcriber.save_transcript(full_text, segments)
# ステップ3: 議事録作成
if minutes_gen:
minutes, minutes_path = minutes_gen.generate_and_save(
full_text,
meeting_title=meeting_title if meeting_title else None,
additional_context=additional_context if additional_context else None,
)
logger.info(f"📁 音声ファイル: {audio_path}")
logger.info(f"📄 文字起こし: {transcript_path}")
logger.info(f"📝 議事録: {minutes_path}")
進捗表示
tqdmを使用して、文字起こしと議事録生成の進捗をわかりやすく表示します。
from tqdm import tqdm
# 文字起こしの進捗表示
pbar = tqdm(
total=int(duration) if duration else None,
desc="📝 文字起こし中",
unit="秒",
bar_format="{l_bar}{bar}| {n_fmt}/{total_fmt} [{elapsed}<{remaining}]",
)
for seg in segments_generator:
segment = Segment(start=seg.start, end=seg.end, text=seg.text.strip())
segments.append(segment)
pbar.update(int(seg.end) - pbar.n)
エラーハンドリング
各ステップで適切なエラーハンドリングを行い、ユーザーにわかりやすいメッセージを表示します。
try:
audio_path = recorder.record_and_save()
except Exception as e:
logger.error(f"❌ 録音エラー: {e}")
return
try:
full_text, segments = transcriber.transcribe(audio_path)
transcript_path = transcriber.save_transcript(full_text, segments)
except Exception as e:
logger.error(f"❌ 文字起こしエラー: {e}")
return
性能と処理時間
文字起こしの処理時間
CPUの性能により異なりますが、一般的な目安は以下の通りです。
| 音声長 | small | medium | large-v3 | large-v3-ja |
|---|---|---|---|---|
| 5分 | 約30秒 | 約1分 | 約2分 | 約1.5分 |
| 10分 | 約1分 | 約2分 | 約5分 | 約3分 |
| 30分 | 約3分 | 約6分 | 約15分 | 約10分 |
| 60分 | 約6分 | 約12分 | 約30分 | 約20分 |
large-v3-jaは、large-v3と同等の精度で日本語の処理が高速化されています。
メモリ要件
各モデルのメモリ要件は以下の通りです。
| モデル | メモリ使用量 | 推奨環境 |
|---|---|---|
| small | 約1GB | 低スペックPC |
| medium | 約2GB | 標準PC |
| large-v3 | 約4GB | 高スペックPC |
| large-v3-ja | 約4GB | 高スペックPC |
int8量子化により、オリジナルWhisperと比較してメモリ使用量が約1/4に削減されています。
議事録生成の処理時間
LLMモデルと文字起こしの長さにより異なりますが、一般的な30分の会議(文字起こし約5,000文字)で、qwen2.5:7bを使用した場合、約30秒から1分で議事録が生成されます。
実機計測結果
piroryさんからいただいた指摘を確認するため、macOSのApple Silicon環境で6分6秒(386秒)の音声ファイルを題材に各モデルを実測しました。faster-whisperは1.2.1、デバイスはCPU、compute_type はint8を使用しています。
| モデルID | ロード | 文字起こし | 音声カバー率 | セグメント数 | 出力文字数 | 完走 |
|---|---|---|---|---|---|---|
kotoba-tech/kotoba-whisper-v1.0 |
失敗 | - | - | - | - | ロード不可 |
kotoba-tech/kotoba-whisper-v1.0-faster |
約128秒 | 約60秒 | 11.5%(44.5/386秒) | 8 | 70 | 途中停止 |
kotoba-tech/kotoba-whisper-v2.0-faster |
約123秒 | 約56秒 | 4.0%(15.6/386秒) | 8 | 72 | 途中停止 |
large-v3 |
約244秒 | 約347秒 | 100.0%(387/386秒) | 167 | 1,899 | 完走 |
音声カバー率は「最後のセグメントの終端時刻 ÷ 音声長」で算出しています。Kotoba系はロードできてもVADまたはモデル側の都合で前半数十秒で停止しました。large-v3 は最後まで処理が進み、固有名詞も正しく拾えています。文字起こしの内容を比較しても、large-v3 は話の内容を最後まで出力でき、Kotoba系は冒頭付近で止まりました。
なお、kotoba-tech/kotoba-whisper-v1.0 はHuggingFace Transformers形式で公開されているため、faster-whisperからは model.bin が見つからずロードに失敗します。CTranslate2版である kotoba-tech/kotoba-whisper-v1.0-faster を指定する必要があります。
使用例
基本的な使い方
# アプリケーションを起動
uv run python main.py
# メニューから1を選択(フルワークフロー)
【メニュー】
1. 🎙️ 録音 → 文字起こし → 議事録作成(フルワークフロー)
番号を選択してください: 1
# 会議情報を入力
📋 会議タイトル(省略可): 週次定例会議
👥 参加者情報など(省略可): 田中、佐藤、鈴木
# Enterキーで録音開始
🎙️ 録音を開始します。Enterキーを押すと停止します...
# 会議終了後、Enterキーで録音停止
録音を停止しました。
# 自動的に文字起こしと議事録が生成される
📝 文字起こし中 |████████████████████| 100%
🤖 議事録生成中 |████████████████████| 100%
✨ すべての処理が完了しました!
📁 音声ファイル: data/audio/recording_20241130_143000.wav
📄 文字起こし: data/transcripts/transcript_20241130_143000.txt
📝 議事録: data/transcripts/minutes_20241130_143000.md
既存の音声ファイルからの処理
# メニューから2を選択
番号を選択してください: 2
# 音声ファイルのパスを入力
音声ファイルのパスを入力: data/audio/meeting.wav
# 会議情報を入力
📋 会議タイトル(省略可): 企画会議
👥 参加者情報など(省略可):
# 自動的に処理される
📝 文字起こし中 |████████████████████| 100%
🤖 議事録生成中 |████████████████████| 100%
✨ すべての処理が完了しました!
クラウドサービスとの比較
主要な文字起こしサービスとの違い
| 項目 | 本ツール | Whisper API | Google Cloud Speech | Amazon Transcribe |
|---|---|---|---|---|
| 実行環境 | ローカル | クラウド | クラウド | クラウド |
| プライバシー | 完全保護 | APIに送信 | APIに送信 | APIに送信 |
| コスト | 無料 | 従量課金 | 従量課金 | 従量課金 |
| インターネット | 不要 | 必須 | 必須 | 必須 |
| 日本語精度 | 高い(Kotoba) | 高い | 高い | 中程度 |
| カスタマイズ | 容易 | 制限あり | 制限あり | 制限あり |
コスト比較
1時間の音声を月100回処理する場合のコスト試算です。
| サービス | 月額コスト(概算) | 年間コスト |
|---|---|---|
| 本ツール | 0円 | 0円 |
| Whisper API | 約6,000円 | 約72,000円 |
| Google Cloud Speech | 約12,000円 | 約144,000円 |
| Amazon Transcribe | 約15,000円 | 約180,000円 |
頻繁に会議を行う組織では、年間で数万円から数十万円のコスト削減が期待できます。
トラブルシューティング
録音ができない
macOSの場合、システム環境設定でマイクへのアクセス許可を与える必要があります。
システム環境設定 → セキュリティとプライバシー → プライバシー → マイク
Ollamaに接続できない
Ollamaが起動していることを確認してください。
# Ollamaの起動確認
ollama list
# モデルのダウンロード
ollama pull qwen2.5:7b
ollama pull mxbai-embed-large
文字起こしが音声の途中で止まる
kotoba-tech/kotoba-whisper-v1.0-faster や kotoba-tech/kotoba-whisper-v2.0-faster を選んだとき、音声の冒頭付近で出力が打ち切られることがあります。手元の検証でも同じ症状が再現しました。途中停止が発生する場合は、まず以下を試してください。
-
large-v3-ja(Kotoba系)からlarge-v3へ切り替えます。実機検証ではlarge-v3だけが約6分の音声を最後まで文字起こしできました -
vad_filter=Falseに変更します。VADの閾値判定で無音と誤判定されている可能性があります - それでも改善しない場合は、
beam_sizeを 1 に下げ、condition_on_previous_text=Falseを試します
精度が許容範囲なら medium でも完走しやすい傾向があります。
kotoba-tech/kotoba-whisper-v1.0 を指定するとロードに失敗する
kotoba-tech/kotoba-whisper-v1.0 はHuggingFace Transformers形式で配布されており、model.bin を含みません。faster-whisperはCTranslate2形式を要求するため、Unable to open file 'model.bin' というエラーで失敗します。CTranslate2へ変換済みの kotoba-tech/kotoba-whisper-v1.0-faster を指定してください。
メモリ不足エラー
モデルサイズを小さくしてください。
# メニューから5を選択し、smallまたはmediumを選択
5. 🔧 設定(モデル選択など)
最低メモリ要件は以下の通りです。
- small: 4GB RAM
- medium: 8GB RAM
- large-v3: 16GB RAM
今後の改善案
1. リアルタイム文字起こし
現在はオフライン処理のみですが、リアルタイムで文字起こしを行う機能の追加を検討しています。faster-whisperのストリーミングAPIを活用することで実現可能です。
2. 話者分離
複数の話者を自動的に識別し、発言者ごとに文字起こしを行う機能の追加を検討しています。pyannoteなどのライブラリを統合することで実現できます。
3. 多言語対応の強化
現在は日本語に特化していますが、英語や中国語など、他の言語への対応も検討しています。
4. Web UIの提供
現在はCLIのみですが、Streamlitなどを使用したWeb UIの提供も検討しています。
5. カスタムプロンプトの保存
ユーザーが独自に作成したプロンプトを保存し、再利用できる機能の追加を検討しています。
まとめ
完全ローカル環境で動作する会議文字起こしツールを開発しました。faster-whisperによる高精度な日本語文字起こしと、OllamaによるローカルLLMを活用した議事録自動生成を実現しています。
主な特徴は以下の通りです。
- 完全ローカル実行によるプライバシー保護とコストゼロ
- faster-whisperによる日本語文字起こし(音声によっては
large-v3の方が安定するため、「実機計測結果」も併せて参照してください) - Ollamaによる柔軟な議事録自動生成
- RAG機能によるナレッジベース参照
- uvとruffによる高速で堅牢な開発環境
クラウドサービスと比較して、プライバシー、コスト、オフライン利用の面で優位性があり、企業や組織での活用に適しています。
ソースコードはGitHubで公開していますので、ぜひお試しください。また、改善提案やフィードバックもお待ちしています。
Discussion
便利なコードをありがとうございます。
気になった点として
"large-v3-ja": "kotoba-tech/kotoba-whisper-v1.0-faster"
にしないと、モデルがダウンロードされませんでした。また、large-v3なら
音声ファイルを最後まで文字起こしできましたが、kotoba-whisper-v1.0-fasterだと
途中で停止してしまうことが多いようです。2.0も出ているみたいですが
2.0でも同様でした。文字起こしの制度もこちらの環境、音声ファイルではkotoba-whisperの方が
イマイチな結果になっていました。
piroryさん、ご指摘いただき誠にありがとうございます。
お知らせいただいた挙動を確認するため、手元のMacで
kotoba-whisper-v1.0とv1.0-faster、v2.0-faster、比較用のlarge-v3を順番に試したところ、ご指摘どおりの結果になりました。kotoba-tech/kotoba-whisper-v1.0はHuggingFace Transformers形式のため、faster-whisperからはmodel.binが見つからずロードに失敗しましたkotoba-tech/kotoba-whisper-v1.0-fasterとkotoba-tech/kotoba-whisper-v2.0-fasterはロードできても、約6分の音声の前半数十秒で文字起こしが停止しましたlarge-v3だけが最後まで完走し、固有名詞も含めて精度も安定していました再現できましたので、本記事を以下のように更新しました。
JAPANESE_MODELSのサンプル値をCTranslate2形式のkotoba-tech/kotoba-whisper-v1.0-fasterに差し替えましたlarge-v3を試す案内を追記しました正確な情報を共有いただき、本当に助かりました。引き続きどうぞよろしくお願いいたします。