カテゴリー
Uncategorized

「ねえチャッピー」でChatGPTと会話できるようにした話

― 試行錯誤だらけの音声トリガーAI構築記 ―

はじめに:なぜ作ろうと思ったのか

ChatGPTは便利だ。
でも正直に言うと、

  • いちいちキーボードを触るのが面倒
  • 思考の途中で手が止まる
  • 「話しかけられるAI」感が薄い

と感じていた。

特に教育や思考整理で使うなら、
「思いついた瞬間に声で投げたい」

そこで思った。

「ねえチャッピー」って呼びかけたら
勝手にChatGPTが起きてきて、
そのまま会話できたら最高じゃないか?

AlexaやGoogle Assistantみたいな完成品もあるけれど、
今回は チャッピーと連携させたかった。


目標設定

最初から欲張らないことにした。

  • PCはWindows
  • ChatGPTは公式Windowsアプリ
  • 音声は「起動トリガー」だけに使う
  • 重い常時リスニングやクラウド常駐は避ける

つまり、

「ねえチャッピー」
→ 🎤が自動で押される
→ あとはChatGPTに任せる

この一点突破。


全体構成(後から見て「意外と素直」)

仕組みを分解するとこうなる。

① Python:耳の役割

  • 一定時間ごとにマイクを録音
  • 音量が小さすぎるものは無視
  • 音声認識で「ねえチャッピー」を検出
  • 検出したらショートカットキー送信

② AutoHotkey(AHK):指の役割

  • Ctrl + Alt + G を受信
  • ChatGPTアプリを前面に出す
  • 🎤ボタンをクリック

③ ChatGPT:脳の役割

  • 音声モード起動
  • 以降は完全にChatGPT任せ

役割分担すると、
Pythonが「判断」して、AHKが「操作」する構造。


最大の沼:マイク問題

正直、ここが一番時間を食った。

Realtekが全然言うことを聞かない

  • 入力テストの青バーが動かない
  • 音は拾っている「はず」なのに無音扱い
  • ノイズ抑制をONにすると完全沈黙

Realtek Audio Consoleを開いては閉じ、
設定をいじっては再起動……を何度も繰り返した。

結論:Webcamのマイクを使った

最終的に、

「他にマイクがないし、
webcamにマイク付いてるよな?」

と気づいて切り替えたら、
一発で安定

  • 入力レベルが安定
  • ノイズ処理が素直
  • Python側の音量判定も楽

結果的に
“専用マイクがなくてもいける”
という実用的な落としどころになった。


「無音っぽいのでスキップ」が多すぎ問題

次にハマったのがここ。

最初は、

np.abs(audio).mean()

で音量判定していたが、

  • 「ねえ」「ちゃ」みたいな短い発話
  • 語尾だけ入る音声

が平均値だと 小さすぎて無音扱いになる。

解決策:ピーク音量を見る

peak = np.abs(audio).max()

これに変えたら、

  • 短い呼びかけでも拾える
  • 環境音では誤爆しにくい

という、かなり実用的な挙動になった。


UnknownValueErrorは敵じゃなかった

ログに頻繁に出てきた

UnknownValueError()

最初は「壊れた?」と思ったが、
調べるとこれは、

「音は拾ったけど、
言葉として自信を持って判定できない」

という意味。

つまり、

  • 無意味な雑音
  • 中途半端な独り言

に反応していない証拠。

なので例外は握りつぶして、
落ちない設計にした。


完成後の体験:

ラグい

やっぱり製品版のアレクサとかは上手いなと思った。

聞き取りは百発百中とはいかないし、聞き取り、チャッピーの起動、チャッピーからの応答、全てが遅い。

上手く調整すればもっと良くなりそうな気もするけど、まあこれはこれで良いかな。

パイソンのコード

import time
import numpy as np
import sounddevice as sd
from scipy.io.wavfile import write
import speech_recognition as sr
import keyboard

TRIGGERS = [
“ねえチャッピー”, “ねえ ちゃっぴー”, “ねえちゃっぴー”,
“ねえ チャッピー”, “ねえちゃ”, “ねえ ちゃ”,
“ねえ ちゃっていい”
]
COOLDOWN_SEC = 5
DURATION = 4.0
SAMPLE_RATE = 16000

r = sr.Recognizer()
r.energy_threshold = 300
r.dynamic_energy_threshold = False

last = 0

print(“待機中:「ねえチャッピー」と言ってください”)
print(“(終了するには Ctrl+C)”)

while True:
audio = sd.rec(int(DURATION * SAMPLE_RATE),
samplerate=SAMPLE_RATE,
channels=1,
dtype=”int16″)
sd.wait()
write(“temp.wav”, SAMPLE_RATE, audio)

mean = int(np.abs(audio).mean()) peak = int(np.abs(audio).max()) print(f”(level mean={mean} peak={peak})”) # peak判定:短い発話でも拾いやすい if peak < 1000: print(“(小さすぎてスキップ)”) continue with sr.AudioFile(“temp.wav”) as source: data = r.record(source) try: text = r.recognize_google(data, language=”ja-JP”) print(text) now = time.time() if (“ねえ” in text) and any(t in text for t in TRIGGERS) and (now – last) > COOLDOWN_SEC: print(“起動!【キー送信前】”) time.sleep(0.1) keyboard.send(“ctrl+alt+g”) time.sleep(0.1) print(“起動!【キー送信後】”) last = now except Exception as e: print(“(認識エラー)”, repr(e))

AHKのコード

Requires AutoHotkey v2.0

UseHook

^!g:: {
; ChatGPTを前面に
WinActivate(“ahk_exe ChatGPT.exe”)
WinWaitActive(“ahk_exe ChatGPT.exe”, , 1)
Sleep 200

; ChatGPTウィンドウ基準でクリック(安定) CoordMode(“Mouse”, “Window”) Click(1090, 936)

}

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA