Claudeデスクトップ、ChatGPTボイス、Gemini、そして数多くのOllamaフロントエンドを行ったり来たりして2年。ウェイクワードの“よじれ”に疲れました。どのアシスタントも、あなたがずっとそのチームを選び続ける前提で作られています。
そこでBRAGIを作りました。ローカルで動くボイスレイヤーで、ローカルで聞き取り、指定したどのAIにもルーティングします。同じマシン上で動いているAIも含みます。
この記事は販売宣伝ではなく、アーキテクチャの話です。同じようなものを作ろうと考えているなら、v0.2を出荷して学んだことを共有します。
The pipeline
マイク入力
↓
openwakeword(ローカル)—「Hey Jarvis」
↓
faster-whisper medium(ローカル、GPUは任意)
↓
プロバイダー・ルーター(設定UIで宛先を選択)
↓
[クラウド:Claude / OpenAI / Gemini / Grok / Groq / Together / HuggingFace]
[ローカル:Ollama / LM Studio / FREYA / Echo]
↓
TTS(eSpeak free、OpenAI Nova BYOK)
↓
スピーカー出力
音声は一切マシン外に出ません。どのクラウドを選んでいる(または選んでいない)かに関係なく、送られるのは文字起こしテキストのみです。
Wake word
主権型(ソブリン)プロダクトならopenwakewordが正解です。Picovoiceの方が品質は良いですが、有料の商用ライセンスに縛られます。openwakewordはApache 2.0で、CPU上で動きます。
落とし穴:独自のカスタムモデルを学習するには、対象としているどの前処理(preprocessor)バージョンに対しても、特徴次元(feature dimensions)を完全に一致させる必要があります。openwakewordが32×147を期待しているのに、96×103の特徴を持つモデルに手を入れてしまい、半日を無駄にしました。v0.2には標準の「Hey Jarvis」モデルを同梱し、対応するハードウェアを持つユーザー向けにカスタムの「Hey BRAGI」モデルも含めています。
STT
CUDAでのfaster-whisper mediumがベストです。Tinyは実会話には不正確すぎますし、largeは短いボイスコマンドには過剰です。mediumはミッドレンジGPUで約1秒のレイテンシを出し、バイリンガル入力にも最初から対応しています。
重要な点:Whisperは起動時に1回だけインスタンス化し、リクエストごとに作らないこと。最初の推論呼び出しはCUDAをウォームアップするために5〜10秒かかります。毎回のウェイクごとにそれを許容するユーザーはいません。
The router
ここが一番大変でした。各プロバイダーには別々のSDK、別々のストリーミング形式、別々の認証パターンがあります。ルーターはそれらを1つのインターフェースに抽象化します:
class Provider(Protocol):
def name(self) -> str: ...
def is_ready(self) -> bool: ...
async def respond(self, prompt: str, history: list[Message]) -> AsyncIterator[str]: ...
各プロバイダー実装は、それぞれのSDKのクセを自分で処理します。ルーターはユーザー設定、またはボイスコマンド(「BRAGI、Claudeに切り替えて」)に基づいて1つを選び、respond()を呼ぶだけです。
ローカルモデルについては、Ollama(HTTP API)とLM Studio(OpenAI互換のHTTP API)の両方に対応しています。どちらもユーザーのマシン上で動きます。どちらもルーターから見れば同じに見えます。
TTS
eSpeakは無料でオフライン対応、100以上の言語があるため、インストーラーに同梱されています。音はロボットっぽいです。でもそれで問題ありません。プレミアムな音声を望む人はOpenAIのAPIキーを貼り付けてNovaを使えます。
オフラインTTSの品質を上げるためにKokoroも試しました。開発ではうまく動きました。ところが本番ビルドでは、HuggingFaceのデフォルト音声ファイルで404を踏み続けました。デフォルトはeSpeakのまま、Kokoroはベストエフォートで提供しました。
The settings UI
ローカルWeb UI:http://127.0.0.1:7777。プロバイダーを設定し、APIキーを貼り付け、ボイスを選び、ライセンスを管理します。このページはユーザーのマシン上に存在します。アカウントもログインも、クラウドのダッシュボードもありません。
APIキーはローカルのボールト(保管庫)に保存します。APIキーは一度もマシンの外に出ません。このプロダクトは“主権”です。つまり、あらゆるレイヤーでそうでなければならない。
Stack
- Python 3.11
- ウェイク検出用のopenwakeword
- STT用のfaster-whisper
- TTS用のeSpeak / OpenAI Nova
- ローカル設定サーバ用のFastAPI
- 日常利用のためのトレイモードのpythonw.exe
- 同梱(バンドル)用のPyInstaller
- Windowsインストーラー用のNSIS
- 約169MBのインストーラー、Win10/11
What I'd do differently
カスタムのウェイクワード学習は、ドキュメントが言うよりずっと難しい。 openwakewordの前処理はバージョン管理されていて、特徴次元は完全に一致する必要があります。自分で学習したいユーザー向けに、これをドキュメント化します。
PyInstaller + 4GB CUDA torchのビルドは、NSISの2GB単一ファイル上限を超えてしまう。 torchとKokoroは、同梱ではなく初回起動時のダウンロードに移す必要がありました。
埋め込みPythonの
python311._pthデフォルト値を信用しないこと。%APPDATA%\Roaming\Pythonからのユーザーサイト汚染により、インストールが静かに壊れます。必ず-s -Eフラグ付きで起動してください。
What's next
v0.3ではおそらく、より良いKokoroのフォールバック、カスタムウェイクワード学習UI、マルチルームの同時実行性を追加します。アーキテクチャはそれに対応しています。ですがまずv0.2を出荷し、ユーザーが実際に何を求めているのかを確認する必要があります。
見てみたいなら:clintwave84.gumroad.com/l/leetkd
同じようなものを作ったなら、感想を比較しませんか。コメントをどうぞ。特に、クラウド+ローカルにまたがるプロバイダー抽象化を他の人がどう扱っているのかが気になります。
— アイダホの一人の男によって制作。Snake River AI。




