OpenAI の各モデルを使って音声でチャットしてみる

# やりたいこと
OpenAI が提供しているモデルに、新しく Text to Speech のモデル (tts-1, tts-1-hd) が追加されました。Input にテキストを入力するとそのテキストを自然なイントネーションで読み上げてくれるものです。
元々あった Speech to Text のモデルである whisper-1 と組み合わせることで GPT のモデルと音声で対話できるなーということでやってみた内容をまとめてみます。

# 環境
* Windows11 Pro
    * WSL2 (Ubuntu22.04)
* Python 3.10.12
* 音声入力のためのマイクが必要です
* 音声出力のためのスピーカーが必要です

:::note warn
OpenAI が提供する API を使うためにはあらかじめクレジットを追加しておく必要があります。無料枠が残っている場合は、その範囲内で利用できます。
:::

# 構成
分かりきっているが構成は以下のような形。「」は音声、"" はテキスト。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1743460/1e655baf-551d-142a-1fb2-9e83b28ec98e.png)

# 実装
## ライブラリ

```requirements.txt
black==23.11.0
openai==1.3.2
pillow==10.1.0
python-dotenv==1.0.0
requests==2.31.0
soundcard==0.4.2
soundfile==0.12.1
```

## コード
コード全体は以下。
Text to Speech の出力や Speech to Text の入力となる音声ファイルはいったん保存するようにしている。
音声の入力や出力には、`soundcard` と `soundfile` を使っている。Text to Speech で使用しているモデルは、`tts-1`。こちらの方がリアルタイムなユースケースに適しているとのこと。`tts-1-hd` は高品質とのことらしいが、品質にはそれほど差を感じなかった。
ユーザからの音声入力は5秒間だけにしているので、その時間内で GPT への質問を喋る必要がある。

```main.py
import os
from pathlib import Path

import soundcard
import soundfile
from dotenv import load_dotenv
from openai import OpenAI

load_dotenv()

ORGANIZATION_ID = os.getenv("ORGANIZATION_ID")
API_KEY = os.getenv("API_KEY")


def record_speech(speech_file_path):
    default_mic = soundcard.default_microphone()
    print("recording the speech...")
    sample_rate = 48000
    recording_time = 5  # [seconds]
    data = default_mic.record(
        samplerate=sample_rate, numframes=recording_time * sample_rate
    )
    soundfile.write(speech_file_path, data, sample_rate)


def play_speech_file(speech_file_path):
    default_speaker = soundcard.default_speaker()

    with default_speaker.player(samplerate=26000) as sp:
        data, _ = soundfile.read(speech_file_path)
        print("playing the speech file...")
        sp.play(data)


def main():
    client = OpenAI(organization=ORGANIZATION_ID, api_key=API_KEY)

    dir_name = "./chat_verbally/audio/"
    if not os.path.exists(dir_name):
        os.makedirs(dir_name)

    speech_file_name = "speech.mp3"
    speech_file_path = Path(dir_name + speech_file_name)

    messages = [
        {
            "role": "system",
            "content": "You are a helpful assistant.",
        }
    ]

    while True:
        key = input("Enter to start recording for 5 seconds, q to exit: ")
        if key == "q":
            break
        elif key == "":
            record_speech(speech_file_path)
            with open(speech_file_path, "rb") as f:
                response = client.audio.transcriptions.create(model="whisper-1", file=f)

            prompt = response.text
            messages.append({"role": "user", "content": prompt})
            print("Q:", prompt)

            response = client.chat.completions.create(
                model="gpt-3.5-turbo-1106",
                messages=messages,
                max_tokens=1000,
            )

            answer = response.choices[0].message.content
            messages.append({"role": "assistant", "content": answer})

            response = client.audio.speech.create(
                model="tts-1", voice="alloy", input=answer
            )
            response.stream_to_file(speech_file_path)

            print("A:", answer)
            play_speech_file(speech_file_path)
        else:
            print("invalid key")


if __name__ == "__main__":
    main()
```

# 実行してみる
`Q:` のところは音声で入力しているが、発話した内容も正確にテキストに変換されている！
また、GPT からの回答も正確に音声に変換されていた！イントネーションは日本語が流暢な外国の方という感じだったが、それはそれで味がある、と思う笑

英語も喋ってみたが発音の問題か、正しく認識されなかった :joy:

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1743460/192266ad-f9eb-7f62-903a-79d74e545647.png)

# ということで
Text to Speech と Speech to Text を使って、GPT と音声でチャットしてみました。今回は単純なチャットだけでしたが、工夫次第では翻訳アプリやメールの読み上げや返信といったこともできそうです。また、Alexa や Google Home などの AI アシスタントと連携させればできる幅も広がりそうです。
記事を書いている 23/11/22 の数日前に ChatGPT のモバイルアプリだと音声入力を行えるようになっていましたし、今後音声の入出力がもっと増えるかもしれません。
今回はとりあえずやってみた系なのでいろいろと改善点がありますが、そこはご容赦ください笑


以上です。