これまでWhisperで音声文字起こし(p917)ローカルLLM(p911)を作ってきました。今回はその集大成として、「マイクで話す→AIが考える→声で返してくれる」音声アシスタントを、全部Macの中だけ(完全ローカル)で作ります。クラウドのAIには一切送りません。

🎙 この記事でわかること
音声認識(Whisper)+ローカルLLM+音声合成(VOICEVOX)を1つのアプリに統合する方法
・ローカルLLMは Ollama+Qwen2.5、音声合成は無料の VOICEVOX を使用
・使うモデル・バージョン・設定値・コードを再現できるよう解説
・つまずき(マイク権限・聞き取り精度・返答の長さ・VOICEVOX導入)と対処。完全ローカルなので無料・オフライン・プライバシー安心

作るもの:声で話せるローカルAIアシスタント

スポンサーリンク

完成したのがこの「声で話せるAIアシスタント」。マイクに話しかけると、AIが考えて声で返事してくれます。下は「あなたは何ができるの?」と聞いたときの画面です。

声で話せるAIアシスタントの画面(質問と返答)
話しかけた内容が文字起こしされ、AIが返答(この文章をVOICEVOXが声で読み上げる)。Whisper=small・LLM=qwen2.5:3b・VOICEVOX ON

ポイントは3つのAIをつなげていること。しかも全部手元で動くので――

  • プライバシー安心:声も文章もPCの外に出ない
  • 無料・無制限:APIの利用料がかからない
  • オフラインOK:ネットに繋がっていなくても動く(機内モードでも)

全体構成:話す→文字→AI→声、の流れ

やっていることはシンプルで、4つの部品を順番につなぐだけです。

図解:声で話せるAIアシスタントの流れ(すべてMacローカル) マイク/録音音声(WAV) Whisper音声→文字 ローカルLLMOllama+Qwen2.5返答を生成 VOICEVOX文字→音声 スピーカー再生🔊 ① マイクで録音(記事の実演では“録音WAV”を入力にして再現性を確保)→ ② Whisperで文字起こし → ③ ローカルLLMが短く返答 → ④ VOICEVOXで読み上げWAVを合成して再生。ネットには一切送らない。
4つの部品(録音→Whisper→ローカルLLM→VOICEVOX)を数珠つなぎにするだけ。全部Macの中で完結する

用意するもの(モデル・ツール)

使う部品は次のとおり。p917のWhisperとp911のローカルLLMを再利用しています。

役割使うもの
音声→文字(音声認識)OpenAI Whisper(モデル=small・日本語)
頭脳(返答生成)Ollama + Qwen2.5 3B(日本語が自然で軽量)
文字→音声(音声合成)VOICEVOX ENGINE 0.25.2(無料・ローカル・自然な日本語)
画面(GUI)・録音PySide6 / sounddevice
# ライブラリ
pip install openai-whisper sounddevice soundfile requests PySide6
# ローカルLLM(Ollama)と日本語が得意なモデル
brew install ollama   # 未導入なら
ollama pull qwen2.5:3b
# VOICEVOX ENGINE(音声合成)… 公式GitHubからmac版をダウンロードして起動
#   VOICEVOX/voicevox_engine のリリースから macos-arm64 を取得・展開し
./run --host 127.0.0.1 --port 50021   # これで音声合成サーバが立つ

※ VOICEVOXのエンジンは約1.8GBと大きめ(音声モデルや辞書を同梱するため)。起動すると 127.0.0.1:50021 でHTTP APIが使えるようになります。

実装①:音声→文字(Whisper)

まず“耳”の部分。p917で使ったWhisperで、録音した音声(WAV)を文字にします。たった数行です。

import whisper
model = whisper.load_model("small")   # 日本語は small が精度と速度のバランス良し

def transcribe(wav_path):
    r = model.transcribe(wav_path, language="ja", fp16=False)
    return r["text"].strip()

録音は sounddevice でマイクから取り込みます。ただし今回の実演では、再現性のために“短い録音WAV”を入力に使います(誰がやっても同じ結果になり、マイクに向かって話す必要もないため)。実際に使うときは、アプリの「🎤話す」ボタンでマイク録音します。

🧭 よくある誤解:「音声認識にはどのLLMが強い?」
音声認識(音声→文字)を担うのは Whisper で、ローカルLLM(このあと出てくる Qwen2.5 や、別記事の Ministral 3)ではありません。LLMは“聞き取ったあとのテキスト”を理解して返答する担当で、そもそも音声を直接は扱いません。役割がきっぱり分かれているので、「音声認識にどのLLMが有利か」という比較は当てはまりません
聞き取りの精度を上げたいWhisperのモデルを大きくする(base → small → medium…)
返答の自然さ・賢さを上げたいLLMを変える(速く自然な会話なら Qwen2.5、道具を使う複雑な操作なら Ministral 3 など)

実装②:ローカルLLMで返答(Ollama+Qwen2.5)

次に“頭脳”。文字起こしした文章をOllamaのローカルLLMに投げて、返答を作ります。声で読み上げるので、返答は短くなるようにシステムプロンプトと num_predict(最大長)で抑えるのがコツです。

import requests
SYSTEM = "音声で会話する日本語アシスタント。返答は必ず1〜2文・60文字以内。やさしい話し言葉で。"

def ask(history):   # history: [{role, content}, ...](会話の文脈を保持)
    r = requests.post("http://127.0.0.1:11434/api/chat", json={
        "model": "qwen2.5:3b", "messages": history, "stream": False,
        "options": {"temperature": 0.5, "num_predict": 120}})
    return r.json()["message"]["content"].strip()
💡 モデル選びが効いた
最初は別の3Bモデルで試したら、返答が長すぎたり「today」など英語が混じって不自然でした。Qwen2.5 3Bに変えたら、短く自然な日本語で返してくれるように。音声で聞くと差がはっきり出ます。

実装③:文字→音声(VOICEVOX)

最後に“口”。AIの返答テキストをVOICEVOXで読み上げWAVにします。VOICEVOXは2段階(①読み方の情報を作る→②音声を合成)で、HTTP経由で呼びます。

import requests
VV = "http://127.0.0.1:50021"

def synthesize(text, out_path, speaker=3):   # speaker=3: ずんだもん(ノーマル)
    q = requests.post(f"{VV}/audio_query", params={"text": text, "speaker": speaker})
    wav = requests.post(f"{VV}/synthesis", params={"speaker": speaker}, json=q.json())
    open(out_path, "wb").write(wav.content)   # → これを再生すれば声が出る

話者(声)はVOICEVOXにたくさん用意されていて、ずんだもん・四国めたんなどから選べます。アプリでは声を切り替えられるようにしました。

動かす:話す→返ってくる

この3つをPySide6のGUIにまとめ、録音→文字起こし→返答→読み上げを一気に流します。処理には少し時間がかかるので、p935と同じく状態インジケータ(待機=緑/処理中=オレンジ)を付けました。

まず起動画面。Whisper・LLM・VOICEVOXが揃うと「準備OK」になります。

アプリの起動画面(準備OK)
起動画面。「話す」ボタン・WAV読み込み・声の選択(ずんだもん等)・会話クリア。下に緑の「待機中」

話しかける(今回は録音WAVを入力)と、まず文字起こしが表示され、インジケータがオレンジの「考え中…」に。

文字起こし後、AIが考え中の画面
「こんにちは、あなたは何ができるのか教えて」を聞き取り→AIが考え中(オレンジ表示)

数秒でAIが返答し、それをVOICEVOXが声で読み上げます。インジケータは「話しています🔊」→「待機中(緑)」に戻ります。

AIが返答した画面
「私は質問に答えることや手伝うことができますよ。何かお手伝いできることがありますか?」と返答=これを声で再生

つまずきポイントと対処

  • マイク権限(macOS):マイク録音には「システム設定 > プライバシーとセキュリティ > マイク」でアプリの許可が必要(p935のアクセシビリティ同様、最初の関門)。※今回の実演は録音WAV入力なので権限不要。
  • 聞き取りの精度:Whisperのbaseだと「エーアイ」を「偉愛」と誤認識し、AIが的外れな返答に。→ smallに上げたら正しく聞き取れました。日本語は small 以上が安心です。
  • 返答が長い・英語が混じる:声で聞くと長い返答はつらい。→ num_predict で長さを制限「1〜2文で」システムプロンプト日本語が得意なQwen2.5に変更で解決。
  • VOICEVOXの導入:エンジンが約1.8GBと大きい。DL後、macOSのGatekeeperで実行がブロックされることがある(xattr -dr com.apple.quarantine で解除)。起動後 127.0.0.1:50021 が応答すればOK。
  • 応答速度:話し終わってから声が返るまで数秒(Whisper+LLM+音声合成の合計)。モデルは初回だけ読み込みが遅いので、起動時にウォームアップしておくと体感が良くなります。

まとめ:全部ローカルで完結する良さ

音声認識・ローカルLLM・音声合成を数珠つなぎにするだけで、声で会話できるAIアシスタントが完全ローカルで作れました。クラウドの音声アシスタントほど賢くはなくても、無料・オフライン・プライバシー安心で、ちょっとした会話や質問には十分実用的です。

  • Whisper(small)で音声→文字、Ollama+Qwen2.5で短い返答、VOICEVOXで自然な読み上げ
  • 声も文章もPCの外に出ないので、プライバシーが気になる用途にも安心
  • Whisper(p917)ローカルLLM(p911)で作った部品が、こうして1つの“話せるAI”に集約できた

「自分のパソコンの中だけで動く音声アシスタント」は、作ってみると想像以上に楽しいです。声の種類を変えたり、返答のキャラを変えたりと、カスタマイズの余地もたくさんあります。

それでは、今回はここまで。最後までありがとうございました😊