Closed4

LlamaIndexのopenai_realtime_clientを試す

kun432kun432

ここで知った

https://twitter.com/jerryjliu0/status/1844165516765823419

GitHubレポジトリ
https://github.com/run-llama/openai_realtime_client

Python用OpenAIリアルタイムAPIクライアント

これはPythonとLlamaIndex用の実験的なOpenAIリアルタイムAPIクライアントである。LlamaIndexのツールと統合されており、カスタム音声アシスタントを素早く構築できる。

ターミナルで直接実行する2つの例を含める。手動およびサーバーVADモードの両方を使用する(つまり、チャットボットを中断できる)。

kun432kun432

ローカルのMacで。

ffmpegが必要だけど、自分の環境にはもう入っている。

$ which ffmpeg
/opt/homebrew/bin/ffmpeg

レポジトリをクローン。このレポジトリが必要なのではなくて、このレポジトリにサンプルコードがある。

$ git clone https://github.com/run-llama/openai_realtime_client && cd openai_realtime_client

仮想環境作成

$ python -m venv venv
$ source venv/bin/activate

LlamaIndexが作成したopenai-realtime-clientパッケージをインストール。どうでもいいけど、公式がもしOpenAI Python SDKとは別にパッケージ出してきたらややこしくなりそうな名前である。。。

$ pip install openai-realtime-client

OpenAI APIキーをセット

$ export OPENAI_API_KEY="sk-XXXXXXXXXX"

これで準備完了。

サンプルコードは2つ用意されている。

  • examples/manual_cli.py: ユーザとAIで会話のターンを交互に繰り返す、トランシーバー的なもの
  • examples/streaming_cli.py: AIが会話中にユーザが割り込みができるもの

つまり、ユーザのVAD(音声区間検出)をマニュアルでやるか自動でやるかの違いになっている。

で、両方ともToolとして以下が実装されている。

# Add your own tools here!
# NOTE: FunctionTool parses the docstring to get description, the tool name is the function name
def get_phone_number(name: str) -> str:
    """Get my phone number."""
    if name == "Jerry":
        return "1234567890"
    elif name == "Logan":
        return "0987654321"
    else:
        return "Unknown"

ここを日本語でも使えるように2ファイルとも少し書き換える。

# Add your own tools here!
# NOTE: FunctionTool parses the docstring to get description, the tool name is the function name
def get_phone_number(name: str) -> str:
    """Get my phone number."""
    if name == "太郎":
        return "1234567890"
    elif name == "花子":
        return "0987654321"
    else:
        return "Unknown"

では、examples/manual_cli.pyの方から試してみる。実行。

$ python examples/manual_cli.py

実行するとこんな感じでメッセージが出る。

Starting Realtime API CLI...
This process is not trusted! Input event monitoring will not be possible until it is added to accessibility clients.
Connected to OpenAI Realtime API!
Commands:
- Type your message and press Enter to send text
- Press 'r' to start recording audio
- Press 'space' to stop recording
- Press 'q' to quit

rを押すと音声の聞き取りがスタートして、スペースで聞き取りを終了して送信する、qで会話を終了するというようなものになっている。

とりあえずこんな感じで音声でやり取りできた。

User: おはようございます。
Assistant: おはようございます。
User: 太郎さんの電話番号を教えて。
Assitant: 太郎さんの電話番号は 1234567890 です。
User: 明日の天気を教えて。
Assistant: 申し訳ありませんが、天気の情報にはアクセスできません。

examples/streaming_cli.pyの方も。こちらは起動したらずっと聞き取りが開始されていて、特に会話のターンを気にする必要はない。終わるときだけqを入力すれば良い。

$ python examples/streaming_cli.py
User: おはようございます。
Assistant: おはようございます。今日はどんなお手伝いができますか?
User: 太郎さんの電話番号を教えて。
Assitant: 太郎さんの電話番号…
User: (会話途中で割り込み)あー、ごめん、やっぱり花子さんで。
Assistant: 花子さんの電話番号は 098756431 です。

ちょっと発話が途中でおかしくなったりするし、発話ミスのようなものもちらほらあるけど、こちらはかなりシームレスに感じる。

kun432kun432

examples/streaming_cli.pyのコードをざっと読む。

https://github.com/run-llama/openai_realtime_client/blob/main/examples/streaming_cli.py

  • 最初に2つのハンドラを初期化
    • AudioHandler()はPyAudioを使った音声の入出力を処理するハンドラ
    • InputHandler()はキーボード入力を処理するハンドラ
  • InputHandler()は非同期のイベントループに入る
  • RealtimeClientがRealtimeAPIに接続するためのクライアントでこれを初期化
    • on_text_deltaでテキストのストリーミング出力を行うハンドラを指定
    • on_audio_deltaでオーディオのストリーミング出力を行うハンドラを指定
    • on_interruptで音声入力の割り込みが入った場合に、音声出力を停止するハンドラを指定
    • turn_detection_modeで、ユーザのVADの方式を指定。server_vadが自動で、manualが手動
    • toolsでTool useの関数を指定
  • キーボードの入力を拾うリスナーを初期化して開始
  • Realtime APIに接続
  • WebSocketのメッセージのやり取りを処理するclient.handle_messagesを非同期タスクに登録
  • 音声のストリーミング処理を継続的いに行うAudioHandler.start_streamingを非同期タスクに登録

という感じ。Realtime APIの細かいやり取りはRealtimeClientの中でやってるみたいなので、そこまでは追ってないけど、かなりシンプルに書ける感はある。

このスクラップは2ヶ月前にクローズされました