おはようございます。まさきんです。
右の Control キーを押している間だけ録音して、離すと文字にして貼ってくれる。そんな音声入力ツールを、自分の Mac で使っています。文字起こしも文章の整え直しも、Mac の中で動く作りです。
作るときに迷った点・測った数字・うまくいかなかった試みを整理しておきます。改良と計測は、AI(Claude Code)に手伝ってもらいながら進めました。コードは公開していないので、考え方の記録として読んでもらえればと思います。
※記事公開時点の情報です。モデルやライブラリの仕様は、公式の情報でご確認ください。
- 録音キーを押している間だけ録音し、離すと文字にしてカーソル位置へ貼る
- 文字起こしは Whisper large-v3、整形は Qwen3-8B の4bit版。どちらも MLX で動かす
- turbo と Qwen2.5-3B から替えても、遅くなるのは1発話で0.3〜0.8秒ほどだった
- 思考モードは1発話に4〜22秒かかり、同じ音の取り違えもあまり直らず見送った
- 貼り付け先は、録音キーを押した時点の前面アプリに合わせる
どんなツールか
使い方は単純です。テキスト欄にカーソルを置いて、録音キーを押しながら話します。キーを離すと、少し待って文字が貼られます。
録音キーの初期値は、右の Control です。メニューバーに常駐していて、メニューから別のキーに替えられます。状態はアイコンの表示で分かります。
動くのは、Apple Silicon の Mac だけです。文字起こしも整形も MLX で動かしているからです。MLX は、Apple silicon 向けの機械学習のフレームワークです。公式の README に、そう説明されています。
使っている部品は、次のとおりです。
| 役割 | 使っているもの | 補足 |
|---|---|---|
| 文字起こし | mlx-whisper | モデルは whisper-large-v3-mlx |
| 文章の整形 | mlx-lm | モデルは Qwen3-8B の4bit版 |
| 録音 | sounddevice | 16kHz のモノラルで録る |
| 録音キーの検知 | pynput | 右 Control など |
| メニューバー | rumps | 状態をアイコンで出す |
| 実行環境 | uv | Python 3.11〜3.12 |
mlx-whisper は、Whisper を MLX で動かすための部品です。公式の説明では、Whisper は OpenAI のオープンソースの音声認識モデルです。サイズは、約3,900万から約15億パラメータまであるとされています。
処理の流れ
キーを離してから貼られるまでに、次の順で処理が進みます。
- 録音キーを押している間だけ録音する。離したあとも0.3秒は録り続ける
- 無音と、0.4秒より短い録音を捨てる
- Whisper で文字起こしする。用語のヒントを一緒に渡す
- 置換ルールで、表記を直す
- 同じ語の繰り返しや、自信の低い結果を捨てる
- Qwen3 で、フィラーを取って句読点を整える
- もう一度、置換ルールをかける
- クリップボード経由で貼り付ける。元のクリップボードの中身は戻す
途中で捨てる段階を多めに入れたのが、作りの特徴です。Whisper は、無音から文章をでっち上げることがあります。なので、音が小さすぎる録音は文字起こしにかけません。
整形のあとにも、守りがあります。整形の結果が元の文から離れすぎていたら、整形前の文を貼ります。質問の形で話したときに、LLM が答えを書いてしまうことがあるためです。
動かすのに必要なもの
条件は、次のとおりです。手元で動作を確かめたのは、MacBook Pro の1台だけです。
| 項目 | 条件 |
|---|---|
| チップ | Apple Silicon(M1 以降) |
| OS | macOS 14 以降。手元で確かめたのは macOS 26 だけ |
| メモリ | 常駐中に約8GB、ピークは約10GB。24GB 以上が目安 |
| ディスク | モデルで約7.2GB、Python の環境で約1.2GB |
| ネット | 初回のモデル取得だけ。入れたあとは、ネットがなくても起動できる |
| キーボード | 録音キーにできるキー。既定は右 Control |
| マイク | 内蔵・外付け・Bluetooth のどれでもよい |
メモリは実測の値です。16GB の Mac では、他のアプリと合わせて余裕がないかもしれません。
少ないときは、turbo と Qwen2.5-3B に替えると減ります。モデルだけなら概算で約3GBです。そのぶん、精度は下がります。
MacBook の内蔵キーボードには、右 Control がありません。外付けのキーボードを使うか、メニューで別のキーに替えることになります。押している間だけ使うので、単独で押しても何も起きない修飾キーが向いていると思います。
初回だけ、モデルの取得で約7GBの通信が発生します。自宅の回線なら気にならない量です。ただ、外出先のテザリングで始めると通信量が気になるかもしれません。
押すと楽天のログインページが開きます。ログイン後にキャンペーン内容が表示されます。
遅くなった分の実測
モデルを大きくすれば、時間はかかります。どれくらい遅くなるのかを、手元の Mac で測りました。Apple M5 Pro でメモリ48GBの MacBook Pro です。
| 段階 | 替える前 | 替えたあと | 所要の目安 |
|---|---|---|---|
| 文字起こし | whisper-large-v3-turbo | whisper-large-v3 | 0.2〜0.3秒から0.4〜0.7秒 |
| 整形 | Qwen2.5-3B | Qwen3-8B | 0.25秒前後から0.4〜0.6秒 |
合わせると、1回の発話で0.3〜0.8秒ほど遅くなりました。短い発話なら、気になる差ではないと感じています。
長い発話も測りました。25秒話したときは、文字起こしも整形も1.9秒でした。合計は約3.9秒です。長さに比例して伸びますが、待ちきれないほどではありませんでした。
ただ、この表は短い合成音声での測定です。回数も少ないので、参考程度に見てください。
アプリで使っているときに、3.6秒や5.3秒かかった発話もありました。発話の長さだけでは説明できず、原因はまだ調べていません。
文字起こしは turbo から large-v3 へ
turbo は、large-v3 のデコーダーの層を32から4に減らしたモデルです。公式のモデルカードには、ずっと速くなる代わりに品質が少し下がると書かれています。
最初は、速さを優先して turbo を使っていました。ところが、合成音声で試すと製品名のカタカナを同じ音の普通の語に取り違えました。large-v3 では、元の綴りに近い形で出ました。
とはいえ、この確認は短い合成音声3本だけです。実際の声で差が出るかは、まだ確かめ切れていません。所要は少し増えますが、取り違えを減らす側に倒しました。
モデルのサイズと数字の聞き違いは、Whisperは金額の数字を間違えるでも書きました。
整形は Qwen2.5-3B から Qwen3-8B へ
整形の役目は、フィラーを取って句読点を整えることだけです。内容の追加や要約はさせません。プロンプトにも、そう書いています。
ところが、3B のモデルは崩れた入力に言葉を足しました。実際に使っていて出た崩れた文に、「のです」や「にゃあい」を付け足したんですね。「お日に」も、語順ごと「毎日」に作り替えました。
8B にすると、入力をほぼそのまま返すようになりました。フィラーも、3B では「あのー」や「えーと」が残っていました。8B は、「あのー」「えっと」「ですね」「まあ」まで取れました。
Qwen3 は、初期設定だと思考の過程を出力します。整形には要らないので、enable_thinking=False で切っています。モデルカードでは、この指定は思考の動きを厳密に止める切り替えだと説明されていました。
prompt = tokenizer.apply_chat_template(
messages, add_generation_prompt=True, tokenize=False,
enable_thinking=False,
)
出力の長さにも、上限を付けています。入力の文字数の2倍のトークンまでです。整形が暴れても、長々と続かないようにするためです。
思考モードと大きなモデルは見送った
誤変換を直すには、考えさせる手もありそうです。Qwen3 には思考モードがあるので、整形に使えないか試しました。
最初に、8B の思考モードを試しました。1発話あたり6〜20秒、時間が増えました。
さらに、16GB ほどある30Bの思考専用モデルも試しました。こちらは7〜30秒です。長い文では2,500トークン使っても終わらず、英語で考え続けていました。
モデルカードには、思考モード向けの推奨設定があります。Temperature は0.6・TopP は0.95・TopK は20です。貪欲な生成は避けるようにとも書かれています。
念のため、この設定に合わせて取り直しました。各文を2回ずつ試した結果が、次の表です。
| 入力の文(短くしたものを含む) | 直したい箇所 | 結果 | 所要(2回) |
|---|---|---|---|
| 今週の試作について共有します | 試作を施策に | 2回とも直らなかった | 9.2秒、12.1秒 |
| 前年同月費と比較します | 費を比に | 2回とも直らなかった。1回は語を削り、1回は言葉を足した | 20.9秒、22.1秒 |
| 原因を分析して、改善作を検討します | 作を策に | 2回とも直った | 8.1秒、8.6秒 |
| 新商品の試作品が届いたので、来週の会議で確認します | 直さない(正しい文) | 2回ともそのまま | 5.8秒、4.0秒 |
直したい3文のうち、きれいに直ったのは1文だけでした。所要は4〜22秒です。別の文では、入力にあった助詞を1つ落とすこともありました。
思考モードは、待たされるうえに直るとは限りませんでした。数秒から20秒ほど待っても、同じ音の取り違えが残ることがあります。
試験の数は少ないので、傾向として見てください。とはいえ、短い音声入力で数秒から20秒待つのは割に合わないと判断しました。長い発話だけで使う任意のモードも考えられます。ただ、今回の結果では効果に対して時間が見合いませんでした。
整形のプロンプトに、用語と指示を足す方法も試しています。直ったのは、用語に載せた語だけでした。長い文では、別の語に変えてしまうこともありました。
同じ音の取り違えには文脈が効きそうだった
使っていると、「施策」が「試作」と出ることがありました。同じ音の語なので、音だけでは区別できません。前後の話題が分かれば、区別できるはずです。
そこで、直前の発話を Whisper のヒントに足す方法を試しました。合成音声3件のうち、「施策」が「試作」になる例が直りました。所要は0.39秒から0.43秒で、ほとんど変わっていません。
ほかの2件は、足しても足さなくても正しく出ました。つまり、確かめられたのは1件だけです。
この方法は、まだ取り入れていません。実際の声で確かめてからにしたいと考えています。直前の発話を足すと、ヒントの丸写しを捨てる判定にも関わります。そこも含めて見直す予定です。
用語ファイルと置換ルール
固有名詞や専門用語は、音だけだと別の綴りで出ます。そこで、用語ファイルを用意しました。書き方は2通りです。
- 1行に1語だけ書くと、文字起こしのヒントになる
誤 => 正と書くと、文字起こしのあとで置き換える
# 1行1語: 文字起こしのヒントに渡す
Whisper
Qwen
# 左 => 右: 文字起こしのあとで置き換える
ビッグクエリ => BigQuery
ヒントに渡す語は、30語までにしています。上の例は、書き方を見せるためのものです。実際の中身とは違います。
置換ルールで気をつけたのは、普通の語を置き換えないことです。別の用途で作った誤変換の辞書には、普通の語を別の語に替える行がありました。口述に流用すると、普通の文まで壊れます。なので、流用せずに口述用を別で用意しました。
貼り付け先のアプリに合わせる
話し終わるまでに、別のアプリへ切り替えることがあります。そのまま貼ると、切り替えた先に入ってしまいます。録音キーを押したときに入力したかったアプリとは、限りません。
そこで、録音キーを押した時点の前面アプリを覚えておきます。貼る時点で別のアプリが前面なら、覚えていたアプリを前面に出してから貼る作りにしました。
前面のアプリは、lsappinfo で調べています。前面に出すときは、open -b にバンドルIDを渡します。前面になるまでは、0.3秒ほどです。
lsappinfo info -only bundleid "$(lsappinfo front)"
open -b com.apple.TextEdit
ここで一つ、ハマりました。最初は NSWorkspace の frontmostApplication で前面を調べていました。ところが、イベントループを回していないプロセスでは古い値を返し続けるんですね。前面にできているのに、できていないと判定していました。
なので、常に最新を返す lsappinfo に替えました。
もう一つ、打っている最中には切り替えません。打鍵の途中で前面が変わると、打っている文字が別のアプリに入ってしまうからです。入力が0.6秒ほど止まるのを待ちます。待つのは最大2秒で、過ぎたら切り替えます。
アプリが終了していたときや前面にできなかったときは、貼りません。クリップボードに入れて知らせるだけにしています。
制約もあります。
- 見分けるのはアプリ単位。同じアプリの中でタブやペインを替えても見分けない
- 全画面のアプリが別の Space にあると、Space も切り替わる
- 貼ったあとに、前のアプリへは戻さない
つまずいたところ
AirPods を耳に入れていないと無音になる
最初に、録音はできていそうなのに文字が入らない状態になりました。原因は、macOS の既定の入力が AirPods だったことです。耳に入れていなかったので、音が全く届かず音量は0のままでした。
対策は二つです。一つ目は、メニューから入力マイクを固定できるようにしたこと。二つ目は、録音の前に機器の一覧を作り直すことです。
音を扱う部品の PortAudio は、起動したときの機器一覧を持ち続けます。そのままだと、AirPods をつないだあとの既定の入力の変更に追従できません。作り直しの所要は、数ミリ秒でした。
ヒントの丸写しを捨てる判定が、厳しすぎた
ヒントの文をそのまま出力した結果は、貼らずに捨てています。ヒントを渡すと、静かな部分でヒントそのものが出ることがあるからです。以前の記事でも、faster-whisper で静かなクリップにヒントの繰り返しが出ました。
ところが、最初の判定は厳しすぎました。ヒントに含まれる短い語だけを話した、正しい発話まで捨ててしまいます。例えば、「日本語の音声」とだけ話した場合です。
そこで、一致した長さに下限を付けました。ヒントの基本の文は10文字以上、用語つきのヒント全体は24文字以上のときだけ捨てます。
試験で自分のクリップボードを上書きした
貼り付けの試験は、実機のクリップボードに触ります。クリップボードに書き込む関数の差し替えが漏れました。その結果、試験用の文で自分のクリップボードを上書きしてしまいました。元の中身は戻せませんでした。
実機に触る処理を試すときは、呼ばれうる関数を全部差し替えます。試験の前後で、クリップボードの中身が変わっていないことも確かめる。それがこのときの教訓です。
そのほかの制約
- クリップボードの復元はテキストだけ。画像をコピーしていたら失われる
- 文字起こし中に押したキーは無視される。終わってから次を話す
- 10秒ほどの発話で、離してから貼られるまで2秒前後かかる
- 異常終了しても、自動では立ち上がり直さない
向いている人・向いていない人
| 観点 | 向いている人 | 向いていない人 |
|---|---|---|
| Mac | Apple Silicon で、メモリに余裕がある | Intel の Mac や、メモリが少ない |
| 使い方 | 短めの文章を、何度も入力する | 一字一句の正確さが必要な文書を書く |
| 環境 | 初回に約7GBを取得できる | 通信量を常に節約している |
| 姿勢 | 設定ファイルを自分で直すのが苦にならない | そのまま使えるアプリがよい |
誤変換はゼロになりません。なので、貼られた文は一度目で確かめる前提の道具だと思っています。
始める前に確認すること
同じような道具を Mac で試す方向けに、条件をまとめました。
- Apple Silicon(M1 以降)の Mac である
- macOS 14 以降である
- メモリが24GB 以上ある。少ないときは軽いモデルにする
- モデルと環境で約8.4GBぶん、ディスクに空きがある
- 初回に約7GBをダウンロードできる回線がある
- 録音キーに使えるキーがある。無ければ別のキーに替える
- AirPods を使うなら、耳に入れてから話す
特に、メモリとマイクの二つが大事だと思います。この二つは、動かしてから気づくと手戻りが大きいからです。
- 精度を優先するとき:文字起こしは large-v3、整形は Qwen3-8B。待ちは1発話で0.3〜0.8秒ほど増える
- メモリを節約したいとき:turbo と Qwen2.5-3B にする。そのぶん精度は下がる
- 整形が要らないとき:メニューで切る。文字起こしの結果が、置換だけかけて貼られる
よくある質問
Q. Intel の Mac でも動きますか?
動かないと思います。MLX は、公式の README で Apple silicon 向けと説明されています。僕が試したのも、Apple Silicon の Mac だけです。
Q. メモリが16GBの Mac でも使えますか?
常駐中に約8GB、ピークで約10GBを使いました。他のアプリと合わせると、余裕がないかもしれません。軽いモデルの組み合わせにすると、メモリは減ります。そのぶん、精度は下がります。
Q. ネットがなくても使えますか?
入れたあとは、使えます。モデルは取得済みのものだけを使う設定にしていて、通信できない状態での起動も確かめました。ネットが要るのは、初回のモデル取得だけです。
Q. 録音キーは変えられますか?
メニューの「録音キー」から変えられます。選べるのは、Control・Option・Command・Shift の左右と F1〜F20 です。文字が出るキーと Enter と Space は使えません。右 Control・右 Option・F13 以降は、普段のショートカットと重なりにくいと思います。
Q. 整形は切れますか?
切れます。メニューの「整形する」で、入り切りできます。切ると、整形を通さずに、置換ルールだけかけて貼られます。再起動すると、入に戻ります。
Q. 長い文章だと、どれくらい待ちますか?
25秒の発話で、約3.9秒でした。10秒ほどの発話なら、2秒前後です。長さに比例して伸びるので、長く話すほど待ちは増えます。
Q. 別のアプリに切り替えても、ちゃんと貼られますか?
録音キーを押した時点のアプリに貼ります。切り替わっていれば、そのアプリを前面に出してから貼ります。ただ、見分けるのはアプリ単位です。同じアプリの中でタブを替えても、見分けられません。
参考にした公式情報
- MLX(ml-explore 公式リポジトリ)
- Whisper の MLX 版 README(ml-explore 公式リポジトリ)
- openai/whisper-large-v3-turbo モデルカード(OpenAI、Hugging Face)
- mlx-community/whisper-large-v3-mlx(mlx-community、Hugging Face)
- Qwen/Qwen3-8B モデルカード(Qwen、Hugging Face)
- mlx-community/Qwen3-8B-4bit(mlx-community、Hugging Face)
まとめ
Whisper で文字起こしをして、Qwen3 で整える。流れは単純です。ただ、モデルの選び方や貼り付け先の合わせ方で使い心地が大きく変わりました。
結局、効いたのは地味な工夫でした。例えば、大きめのモデルへの変更です。語尾を欠けさせない0.3秒や、押したときのアプリに貼ることも効きました。思考モードのような派手な方法は、待ち時間に見合いませんでした。
まだ試していないことも残っています。直前の発話を文脈に足す方法と、文字起こしと整形の時間を分けて記録することです。音声入力を試したい方は、まず mlx-whisper だけ動かしてみてはいかがでしょうか。
自分の作業をAIに寄せる話は、朝のブリーフィングを自動で作る記事にも書きました。モデルの取得には通信量を使うので、回線に余裕があると始めやすいと思います。
押すと楽天のログインページが開きます。ログイン後にキャンペーン内容が表示されます。
本記事にはアフィリエイト広告を含みます。当サイトのリンクを経由して商品・サービスへお申し込みいただいた場合、提携先企業から成果報酬を受け取ることがあります。 また、運営者は楽天グループに所属する社員であり、紹介プログラムを通じた報酬を受け取る場合があります。記事内容・評価は広告の有無にかかわらず、運営者の実体験と調査に基づき作成していますが、 上記の関係性をご理解のうえお読みください。詳しくは免責事項・アフィリエイト表記をご覧ください。
楽天モバイルの通信エリア・電波状況について気になることがある方は、公式の電波改善・調査依頼フォームからご相談いただけます。