見出し画像

Gemini Code Assistに教わった音声トリガ

 やってみたかったけど、自分に解決に至る知識が無くて、これまで手が出せなかったアイデア。今後はGemini Code Assist(以下GCAと略)に丸投げすればどうにかしてもらえそうです。
 オーバーヘッドスキャナで、折り目のある書類のスキャンをするとき、浮き上がらないよう「両手で押さえたい」のですが、そうするとマウスの左クリックによるスキャン操作がやりにくい。世の中にはフットスイッチ

なる製品があるそうですが、それほど頻繁に使う物でもないし、正直なところ、自宅に物を増やしたくない。
 書類を手で押さえ、マイク入力で指示したときだけマウスの左クリックを代行していくれるユーティティツールは作れないかな?
 GCAに投げてみます。
 今回はまず、音声でイベント起動ができるかどうか確認します。


まず、結果から・・いきなり大成功

(終了はCTRL+Cです)
正直、想像を超えていました。
当方がイメージしていたのは「マイク入力の音量レベルが一定以上になったらイベント実行」というものです。マイクに向かって「わー」とか「キャー」とか叫んでいる自分を想像していました(^_^;)
 音声認識して特定のキーワードを言ったときだけ発動するなら、まわりがうるさい時でもだいじょうぶですね。
 では、どうやって作ったかを次に書きます。

GeminiCodeAssist(GCA)

プロンプト(これだけです)

>音声入力をトリガにしてイベントを起動するPythonのサンプルプログラムください。

コード

import speech_recognition as sr
import time
import threading

class VoiceTrigger:
    def __init__(self, trigger_phrase, callback_function, language="ja-JP"):
        """
        音声入力をトリガーにしてイベントを起動するクラス

        Args:
            trigger_phrase (str): イベントを起動するトリガーとなるフレーズ
            callback_function (function): トリガーが検出されたときに実行する関数
            language (str): 使用する言語(デフォルトは日本語)
        """
        self.recognizer = sr.Recognizer()
        self.microphone = sr.Microphone()
        self.trigger_phrase = trigger_phrase
        self.callback_function = callback_function
        self.language = language
        self.running = False
        self.listening_thread = None

    def listen_for_trigger(self):
        """
        トリガーフレーズの検出を開始する
        """
        with self.microphone as source:
            self.recognizer.adjust_for_ambient_noise(source)  # 周囲の雑音に合わせる
            print(f"トリガーフレーズ '{self.trigger_phrase}' の検出を開始...")

            while self.running:
                try:
                    print("音声入力待ち...")
                    audio = self.recognizer.listen(source, timeout=5)  # 5秒間音声入力を待機

                    print("音声認識中...")
                    text = self.recognizer.recognize_google(audio, language=self.language)
                    print(f"認識された音声: {text}")

                    if self.trigger_phrase in text:
                        print(f"トリガー '{self.trigger_phrase}' が検出されました!")
                        self.callback_function()

                except sr.UnknownValueError:
                    print("音声を認識できませんでした")
                except sr.RequestError as e:
                    print(f"音声認識サービスからの応答がありませんでした: {e}")
                except sr.WaitTimeoutError:
                    print("音声入力がありませんでした。")
                except Exception as e:
                    print(f"予期しないエラーが発生しました: {e}")
                
                time.sleep(0.5) # 少しだけ待機させることでcpu負荷を軽減

    def start_listening(self):
        """
        音声認識をバックグラウンドで開始する
        """
        if self.running:
            print("すでに音声認識が開始されています。")
            return

        self.running = True
        self.listening_thread = threading.Thread(target=self.listen_for_trigger)
        self.listening_thread.daemon = True #メインスレッドが終了するとバックグラウンドスレッドも終了するようにする。
        self.listening_thread.start()

    def stop_listening(self):
        """
        音声認識を停止する
        """
        if not self.running:
            print("音声認識は開始されていません。")
            return

        self.running = False
        if self.listening_thread and self.listening_thread.is_alive():
            self.listening_thread.join() #スレッドが終了するのを待つ
        print("音声認識を停止しました。")



# コールバック関数の例
def my_event():
    print("イベントが起動しました!")
    # ここに実行したい処理を記述
    # 例:ファイルを保存したり、プログラムを実行したり、メッセージを表示したり...

# メイン処理
if __name__ == "__main__":
    # トリガーフレーズとコールバック関数を設定
    trigger_phrase = "スタート"  # "スタート"という言葉をトリガーにする
    voice_trigger = VoiceTrigger(trigger_phrase, my_event)

    # 音声認識を開始
    voice_trigger.start_listening()
    
    try:
        while True:
            time.sleep(1) # プログラムを終了させないように、1秒ごとにチェック
            #ここで他の処理を行うこともできる
    except KeyboardInterrupt:
        print("\nプログラムを終了します...")
        voice_trigger.stop_listening()

解説とポイント


speech_recognition ライブラリの利用:

  • 音声認識を行うために speech_recognition ライブラリを使用します。インストールしていない場合は、pip install SpeechRecognition でインストールしてください。

  • また、PyAudioも必要な場合があります。インストールされていない場合は、pip install pyaudio でインストールしてください。

  1. VoiceTrigger クラス:

    • 音声認識とトリガー検出の処理をカプセル化するクラスです。

    • __init__: コンストラクタ。トリガーフレーズ、コールバック関数、言語を設定します。

    • listen_for_trigger: 音声入力を継続的に監視し、トリガーフレーズが検出されるとコールバック関数を実行します。

      • adjust_for_ambient_noise: 環境のノイズを調整し、認識精度を向上させます。

      • listen: 音声入力を取得します。timeout オプションでタイムアウトを設定できます。

      • recognize_google: Google の音声認識 API を使用して、音声をテキストに変換します。

      • try-except: エラー処理を行い、プログラムが予期せず停止するのを防ぎます。

      • time.sleep(0.5): CPU負荷を軽減するための待機

    • start_listening: 音声認識を別のスレッドでバックグラウンド実行します。

      • threading.Thread: スレッドを生成

      • daemon=True: メインスレッドが終了したときにバックグラウンドスレッドも強制終了する設定

    • stop_listening: 音声認識を停止します。

      • join() : スレッドが終了するまで待機

  2. コールバック関数 (my_event):

    • トリガーフレーズが検出されたときに実行される関数です。

    • 必要に応じて、ここに実行したい処理を記述します。

  3. メイン処理 (if __name__ == "__main__":)

    • VoiceTrigger クラスのインスタンスを作成し、トリガーフレーズとコールバック関数を設定します。

    • start_listening() で音声認識を開始します。

    • try-except と while True: Ctrl + Cでのプログラム停止を可能とし、プログラムが終了しないようにしています。

    • voice_trigger.stop_listening() : プログラムが終了する際に音声認識を停止します。

実行方法:

  1. 上記のコードを voiceswitch.py などのファイル名で保存します。

  2. ターミナルまたはコマンドプロンプトで、python voiceswitch.py と入力して実行します。

  3. マイクへのアクセス許可が求められたら、許可してください。

  4. 「音声入力待ち...」と表示されたら、マイクに向かって「スタート」と話してみてください。

  5. 「イベントが起動しました!」と表示されれば成功です。

改善点:

  • エラーハンドリングの強化: より詳細なエラー処理を追加することで、プログラムの安定性を高めることができます。

  • 言語の変更: VoiceTrigger クラスのコンストラクタで language パラメータを変更することで、他の言語にも対応できます。例: language="en-US" (英語)。

  • トリガーフレーズの複数設定: リストなどで複数のトリガーフレーズを設定し、いずれかが検出された場合にイベントを実行するように変更することもできます。

  • その他処理の追加: プログラムが終了しないようにしているwhile True の中で他の処理を記述することで、より本格的なプログラムとして動作させることも可能です。

  • ノイズキャンセリング: ノイズの多い環境で使う場合、ノイズキャンセリング機能を持ったマイクを使うことで、音声認識の精度を上げることができます。

  • スレッドの安全な終了: 今回はdaemon=Trueを設定しましたが、より複雑なプログラムや、終了処理をしっかり行いたい場合、フラグやイベントを使ってスレッドを安全に終了するようにするべきでしょう。

  • マイクの選択: 複数マイクが接続されている場合、どのマイクを音声入力に使うか選択することが可能です。Microphone.list_microphone_names()でリストを取得して、Microphone(device_index=index)で選択します。

このプログラムが、音声入力をトリガーにしたイベント実行の参考になれば幸いです。

感想

すごい、これはすごい。ゾクゾク来た(^_^;)




いいなと思ったら応援しよう!