ずんだもんとおしゃべり(VOICEVOX+chatGPT)音声会話

# はじめに
VoiceVoxとchatGPTをつなぐ手順です。
ネタ的には古いですが、この記事は、2024年3月に書きました。その間に、openAIのバージョンも上がりました。

# 躓き・気づき
①chatGPT Plusを使って、クレジットを追加していると思っていたが、追加できていなかった。
②Visual Studio Codeの右上の三角の実行ボタンはうまくいかない原因になっていた。ショートカットF5で「デバッグの開始」をする必要があった。右下のpythonバージョンあわせを間違っていた。
③Macのキーボードうまく動かない罠。

# 環境
M1 Mac 13.4.1
VoiceVox 0.16.1
Visual Studio Code 1.87.0
python 3.11.3

ライブラリ
openai      1.12.0
pyaudio     0.2.14
sounddevice 0.4.6
numpy       1.26.0
soundfile   0.12.1
keyboard    0.13.5

# 手順
# ①「VoiceVox 0.16.1」をインストール。
セキュリティで躓くので、右クリックから「開く」で、起動した状態にする。

http://localhost:50021/docs

にアクセスし、ページが開けることを確認する。

# ②pythonのインストール
ターミナルからpythonが入っていることを確認する。(3.11.3が入ってた)
入っていなければ、pipのインストールと、pythonのインストールを行う。
```
python --version
```
```
python 3.11.8
```

# ③Visual Studio Codeのインストール

https://code.visualstudio.com/

左端の「拡張メニュー」から、
日本語化のインストールと、
pythonのインストールを行った。

# ④VOICEVOXに必要なpythonライブラリのインストール
まず、下記、参考サイトのずんだもんを喋らせるプログラムの実行を目指す。
winとmac環境ともに、pyaudioをインストールする必要があった。
コマンドプロンプト(win)か、ターミナル(mac)からrequestsライブラリをインストールする。

```
pip install pyaudio
pip show pyaudio
```
```
0.2.14
```

さらに、mac環境ではrequestライブラリをインストールする必要があった。
```
pip install requests
pip install --upgrade pip
pip show requests   
```
macのVS Code環境では、requestライブラリをインストールしたのに、VS Codeで認識しておらず、かなり手こずった。

https://qiita.com/yuya0915/items/095a42cf4df169be7b04

VS Codeの一番右下に、
3.12.0
という、場所がある。これが、自分のpython環境に合っていなかった。
マウスでクリックして、
3.11.3
を選択すると、警告が消えた。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510257/ec7f9cb6-0142-df4a-d24a-868f67a2edc7.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510257/f0b80f39-872f-0c6b-eaa8-65d0180b6d1e.png)



# ⑤OpenAIライブラリのインストール
```
pip install openai
pip install --upgrade openai
pip show openai
```
Version: 0.27.4
から
Version: 1.12.0
にバージョンを上げた。

# ⑥音声ファイルを用意する
以下は、右shiftキーを押したら、10秒間録音し、mp3で保存するサンプル。ファイル名は「年月日_時分秒.mp3」
短いコードを心がけた。

必要に応じて、ターミナルからライブラリをインストールする。
```
pip install sounddevice
pip install numpy
pip install soundfile
pip install keyboard
pip install datetime
```
投稿時のライブラリのバージョンは以下。
```
openai　　　　　　　　　　　　1.12.0
sounddevice 0.4.6
numpy       1.26.0
soundfile   0.12.1
keyboard    0.13.5
```

```py:python
import sounddevice as sd # recording
import numpy as np
import soundfile as sf   # save mp3
import keyboard          # rec trigger
import datetime          # save filename

while True:
    if keyboard.is_pressed("shift"): # right shift key
        print("10 sec start recording...")

        fs = 44100  # sample rate
        duration = 10  # record sec

        myrecording = sd.rec(int(duration * fs), samplerate=fs, channels=1)
        sd.wait()  # wait while recording
        print("finished recording...")

        now = datetime.datetime.now(datetime.timezone(datetime.timedelta(hours=9), 'JST'))
        fn = "./"+now.strftime('%Y%m%d_%H%M%S')+".mp3"
        sf.write(fn, myrecording, fs)
        print("Saved...")

        break
```

# キー入力をトリガーにする

keyboardライブラリとMacの相性が悪く、一筋縄ではいかず、導入まで、別の投稿にまとめました。

https://qiita.com/hextomino/items/2016feec9957957f6c23


# ⑦OPENAI_API_KEYの設定
ターミナルの設定ファイルをいじる？（必要ないかも）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510257/6b570349-cb5c-c39e-cb63-422c7970a8d7.png)

Visual Studio Codeの機能で、lounch.jsonファイルを作成する。
そのファイルを、下記のように編集する。

OpenAIはバージョン1.0.0以降？の場合、環境変数OPENAI_API_KEYを参照し、そこにAPIキーが書かれていないとエラーになる。pythonコードにAPIキーを読むようなコードは必要なくなり、暗黙的に読み込むようである。
OpenAIバージョンが1未満では、APIの作法とか、pythonコードとかが違うようである。

OpenAIのトークンはチャージ（課金）しておく。
$5チャージした。

```json:launch.json
{
    "version": "0.2.0",
    "configurations": [
        
        {
            "name": "Python デバッガー: 現在のファイル",
            "type": "debugpy",
            "request": "launch",
            "program": "${file}",
            "console": "integratedTerminal",
            "env": {
                "OPENAI_API_KEY": "ここにOPENAIのキーを入れる",
            },
        }
    ]
}
```
事前に録音済みのmp3ファイルを用意。
同一フォルダに置き、OpenAIでテキスト化する。（通信します）
ファイルサイズに25MBの制限がある。
ここでは、10秒のmp3なので90KBだけ。

```py:mp3toText.py
from openai import OpenAI

client = OpenAI()
    
if __name__ == "__main__":

    audio_file= open("./xxxxxxxx_xxxxxx.mp3", "rb")
    transcription = client.audio.transcriptions.create(
        model="whisper-1",
        file=audio_file
    )
    print(transcription.text)
```
成功すれば、音声がテキストで表示される。
```
私の名前はモグロ副蔵。ただのセールスマンではございません。 私の使う商品はココロ。ココロでございます。
```
参考（公式HPより）

https://platform.openai.com/docs/guides/speech-to-text/quickstart

# ⑧いよいよ、すべてを合体だ

音声録音
テキスト変換
チャット応答
音声合成
を一つのプログラムにまとめて、音声で会話できるようにする。

音声の再生時と終了時で、ブチッと音がなるけど。うまく会話できるものができた。
会話を記録するメモリー機能は、見当たらなかったので、どうなったのかわからないが、この実装では、会話は記憶されず、単純なやり取りしかできないようだ。


Macで実行するには、ターミナルから、Visual Studioをroot権限で実行する必要があります。パスワードを求められます。
```
sudo /Applications/Visual\ Studio\ Code.app/Contents/MacOS/Electron
```

```py:zundamon.py
import requests
import json
import pyaudio
import sounddevice as sd # recording
import numpy as np
import soundfile as sf   # save mp3
import keyboard          # rec trigger
import datetime          # save filename
from openai import OpenAI

client = OpenAI()

def vvox_test(text):
    params = (
        ('text', text),
        ('speaker', 3),
    )

    query = requests.post(
        f'http://localhost:50021/audio_query',
        params=params
    )
    
    # 音声合成
    synthesis = requests.post(
        f'http://localhost:50021/synthesis',
        headers = {"Content-Type": "application/json"},
        params = params,
        data = json.dumps(query.json())
    )
    
    # 再生処理
    voice = synthesis.content
    pya = pyaudio.PyAudio()
    
    # サンプリングレートが24000以外だとずんだもんが高音になったり低音になったりする
    stream = pya.open(format=pyaudio.paInt16,
                      channels=1,
                      rate=24000,
                      output=True)
    
    stream.write(voice)
    stream.stop_stream()
    stream.close()
    pya.terminate()
    
while True:
    if keyboard.is_pressed("shift"): # right shift key
        print("5 sec start recording...")

        fs = 44100  # sample rate
        duration = 5  # record sec

        myrecording = sd.rec(int(duration * fs), samplerate=fs, channels=1)
        sd.wait()  # wait while recording
        print("finished recording...")

        now = datetime.datetime.now(datetime.timezone(datetime.timedelta(hours=9), 'JST'))

        fn = "./"+now.strftime('%Y%m%d_%H%M%S')+".mp3"
        sf.write(fn, myrecording, fs)

        # テキスト変換
        audio_file = open(fn, "rb")
        transcription = client.audio.transcriptions.create(
            model="whisper-1",
            file=audio_file
        )
        print(transcription.text)

        # チャット
        completion = client.chat.completions.create(
        model="gpt-3.5-turbo",
        messages=[
            {"role": "system", "content": "名前が「ずんだもん」で、一人称が「僕」で、口癖は「なのだ」です。枝豆から生まれたキャラクターです"},
            {"role": "user", "content": transcription.text}
        ]
        )

        text = completion.choices[0].message.content
        print(text)
        # 発話
        vvox_test(text)
```

```
こんにちは
こんにちは、僕はずんだもんだ。枝豆の力を使って、いろんなことができるんだ。なのだ。どうかしたかい？

好きな歌手を教えて。
僕の好きな歌手は枝豆なのだ！枝豆の歌声はとても美しいなのだ。

今日誕生日の有名人を教えて
僕の知っている中で、今日誕生日の有名人は、歌手のジャスティン・ビーバーや俳優のオーランド・ブルームなのだ！

その人は何人?
僕は1人なのだ！

その人はどこの国の人?
「僕は国籍を持っていないんだ。枝豆の里で生まれたから、どこの国にも属さないんだ。なのだ！」

ジャスティン・ビーバーはどこの国の人?
ジャスティン・ビーバーはカナダ出身なのだ。

ホーランドブルームはどこの国の人?
ホーランド・ブルームはイギリスの俳優です。僕は映画も好きなのだ。

今日は何月何日?
今日は7月12日なのだ。
```
今日の日時（間違い）
誕生日（一人は惜しい、もうひとりは間違い）
カナダ（正しい）
イギリス（正しい）

※「その」は通じない。
※リアルタイム性の高い「今日」は通じない。


# 参考サイト

https://note.com/key410/n/n1bf0e797da61

https://ai-workstyle.com/gpt-apikey/

https://note.com/gorojy/n/nd8d5701f08bb

https://www.wizard-notes.com/entry/python/sounddevice