Watson Speech to Text /Text To Speech を使用して ChatGPT へ音声入力し、音声出力で回答を得る

#### はじめに

話題のChatGPTで音声入出力する拡張機能を見かけて、IBM Cloud Watson Speech to Text, Text to Speech サービスだとどのように実装できるかを確認してみました。

コード作成はPython で、Web検索、 Git検索、 ChatGPT に質問、実機でデバッグ等々を行い、動いたので記録として記事にします。

---
#### 環境

・ChatGPT -> "gpt-3.5-turbo" モデルを使用。
　　　　　　　  OpenAI のAPI key 取得 (無料範囲内で使用しています)

・IBM Cloud の使用サービス
  　Watson Speech to Text : ライトプラン(無料範囲内) のサービスを作成しAPI keyとURLを取得
  　Watson Text to Speech : ライトプラン(無料範囲内) のサービスを作成しAPI keyとURLを取得

・実行環境
　　Local Mac OS: Jupyter notebook を使用 (python 3.11)


---

#### Python コード

Jupyter notebook での実行のため、行を開けています。
Web アプリケーションには Gradio ライブラリを使用しています。
コード下はChatGPT により生成されたコードの説明文です。



```python
!pip install gradio pydub openai ibm-watson playsound PyObjC
```

>このコードはPythonで実行されるプログラムの一部で、必要なパッケージをインストールするために使用されます。
>具体的には、以下のパッケージをインストールしています。
　　Gradio: Pythonで作成されたWebインターフェースを作成するためのパッケージ
　　Pydub: 音声ファイルを編集するためのパッケージ
　　OpenAI: 自然言語処理に使用されるAPIを提供する企業
　　IBM Watson: IBMが提供する自然言語処理に使用されるAPI
　　Playsound: 簡単な音声再生を行うためのパッケージ
　　PyObjC: PythonからObjective-Cのフレームワークを使用するためのパッケージ
>これらのパッケージは、プログラム内で使用されるために必要です。ここでは、各パッケージのインストールコマンドをまとめて実行しています。インストールされたパッケージは、プログラム内で import 文を使用して呼び出すことができます。


```python
import openai
import gradio as gr
from IPython.display import Audio
from pydub import AudioSegment
import ibm_watson
from ibm_watson import SpeechToTextV1
from ibm_cloud_sdk_core.authenticators import IAMAuthenticator
from ibm_watson import TextToSpeechV1
from playsound import playsound
```

> このコードは、PythonのプログラムでOpenAI、IBM Watson、Gradio、Pydub、playsoundなどのパッケージを使用するために、必要なライブラリをインポートするために使用されます。
具体的には、以下のようにライブラリをインポートしています。
　　openai: OpenAIのAPIを使用するためのライブラリ
　　gradio: Pythonで作成されたWebインターフェースを作成するためのライブラリ
　　IPython.display: IPython環境で音声を再生するためのライブラリ
　　pydub: 音声ファイルを編集するためのライブラリ
　　ibm_watson: IBM WatsonのAPIを使用するためのライブラリ
　　playsound: 簡単な音声再生を行うためのライブラリ

>これらのライブラリは、プログラム内で使用されるために必要です。ここでは、各ライブラリをインポートして、プログラム内で使用できるようにしています。プログラム内では、これらのライブラリを使用して、音声認識、音声合成、音声の再生などの機能を実装することができます。


```python
openai.api_key = "<OpenAPI の API key>"
```

> このコードは、OpenAI APIの認証に必要なAPIキーを設定しています。
OpenAI APIを使用するには、APIキーが必要です。APIキーを取得するには、OpenAIのWebサイトで登録し、APIキーを発行する必要があります。APIキーを取得すると、そのキーを使用してOpenAI APIを呼び出すことができます。
このプログラムでは、APIキーを"<OpenAPI の API key>"の部分に設定しています。実際のAPIキーが設定された場合は、"<OpenAPI の API key>"の部分は実際のAPIキーに置き換えられます。このAPIキーを使用することで、OpenAI APIを使用するための認証が行われます。


```python
class ChatGPT:
    def __init__(self, system_setting):
        self.system = {"role": "system", "content": system_setting}
        self.input_conversation = [self.system]
        self.logs = []

    def generate_message(self, input_text):
        self.input_conversation.append({"role": "user", "content": input_text})
        result = openai.ChatCompletion.create(
            model="gpt-3.5-turbo", messages=self.input_conversation
        )
        self.logs.append(result)
        self.input_conversation.append(
            {"role": "assistant", "content": result.choices[0].message.content}
        )
        print(self.input_conversation) 
        
        return self.input_conversation[-2]["content"], self.input_conversation[-1]["content"]
```

> このコードは、ChatGPTというクラスを定義しています。このクラスは、OpenAIのGPT-3を使用してチャットボットを作成するために使用されます。
>__init__メソッドは、クラスのコンストラクタで、system_settingを引数として受け取り、self.system、self.input_conversation、self.logsを初期化します。self.systemは、システムの設定を表し、self.input_conversationは、会話のログを格納するリストです。self.logsは、OpenAIからの返答を格納するリストです。
>generate_messageメソッドは、ユーザーからの入力テキストを受け取り、OpenAI APIを使用して応答を生成します。self.input_conversationに入力テキストを追加し、OpenAI APIを使用して応答を生成し、その結果をログに追加します。次に、会話のログを更新し、最後に、最新の2つの会話メッセージをタプルで返します。最新の2つの会話メッセージは、self.input_conversationから取得されます。
> このクラスは、チャットボットのコア機能を提供し、ユーザーとの対話を可能にするために使用されます。


```python
# 音声ファイルをWatson STT のAPIに送信して文字起こしする関数を定義
def watsontest(audio):
    authenticator = IAMAuthenticator('<Watson STT のAPI key>')
    speech_to_text = SpeechToTextV1(
        authenticator=authenticator
    )
    speech_to_text.set_service_url('https://api.jp-tok.speech-to-text.watson.cloud.ibm.com/instances/xxxxxxx)

    authenticator2 = IAMAuthenticator('<Watson TTS のAPI key>)
    text_to_speech = TextToSpeechV1(
        authenticator=authenticator2
    )
    text_to_speech.set_service_url('https://api.jp-tok.text-to-speech.watson.cloud.ibm.com/instances/xxxxxxx')

    with open(audio, 'rb') as audio_file:
      audio_data = AudioSegment.from_file(audio, format="mp3").export(format="mp3").read()
      result = speech_to_text.recognize(audio=audio_data, content_type='audio/mp3', timestamps=True, model='ja-JP_Telephony').get_result() 

    print(f"result: {result}")
    transcript = result['results'][0]['alternatives'][0]['transcript']
    print(f"あなた: {transcript}")

    response = api.generate_message(transcript)
    print(f"response: {response}")
    
    chat_gpt_response = response[1]
    print(f"ChatGPTの返答: {chat_gpt_response}")
    
    with open('test_sound.mp3', 'wb') as audio_file:
        audio_file.write(text_to_speech.synthesize(chat_gpt_response, voice='ja-JP_EmiV3Voice', accept='audio/mp3').get_result().content)

    sound = AudioSegment.from_mp3("test_sound.mp3")
    sound2 = sound.speedup(playback_speed=1.2)
    sound2.export("test_sound.mp3", format="mp3")

    return "test_sound.mp3", chat_gpt_response
```

> このコードは、Watson Speech to TextとWatson Text to Speechを使用して、音声ファイルをテキストに変換し、OpenAIのGPT-3を使用して応答を生成し、それを音声に変換する関数watsontestを定義しています。
watsontest関数は、引数としてaudioを受け取り、IBM CloudのWatson Speech to Text APIとWatson Text to Speech APIを使用して音声をテキストに変換し、それをOpenAIのGPT-3に渡して、応答を生成します。生成された応答は、Watson Text to Speech APIを使用して音声に変換され、test_sound.mp3というファイルに保存されます。また、変換された音声は、再生速度を1.2倍に変更した後、戻り値としてtest_sound.mp3と応答文のタプルで返されます。
具体的には、関数内で、authenticatorとspeech_to_textを定義し、Watson Speech to TextのAPIキーを使用して認証を行います。次に、authenticator2とtext_to_speechを定義し、Watson Text to SpeechのAPIキーを使用して認証を行います。audioファイルを開き、AudioSegmentを使用して、音声ファイルを読み込み、音声ファイルをmp3形式に変換します。次に、speech_to_text.recognize()メソッドを使用して、音声ファイルをテキストに変換します。変換されたテキストは、OpenAIのapiを使用して、応答を生成します。生成された応答は、text_to_speech.synthesize()メソッドを使用して、音声に変換されます。最後に、変換された音声ファイルは、再生速度を1.2倍に変更し、戻り値として返されます。

```python
api = ChatGPT(
    system_setting="30文字以内で回答してください。"
)
```

> このコードは、ChatGPTというクラスからapiというインスタンスを作成しています。このインスタンスは、システムの設定として"30文字以内で回答してください。"を持ちます。ChatGPTクラスはOpenAI APIを使用して、自然言語処理を用いた会話を生成するためのクラスであり、このインスタンスは、そのクラスを使用してユーザーからの入力に対して応答を生成するために使用されます。

```python
audio_input = gr.Audio(source="microphone", type="filepath")
interface = gr.Interface(
    fn=watsontest, inputs=audio_input, outputs=[gr.Audio(), "text"]
)
interface.launch(debug=True)
```

>このコードは、音声を入力として受け取り、watsontest関数を使用して、ChatGPTを介して自然言語での応答を生成し、音声ファイルとテキスト形式で出力するGradioのインターフェースを作成します。
具体的には、gr.Audio関数を使用して、入力の音声ファイルを受け取るaudio_inputを作成します。次に、gr.Interface関数を使用して、watsontest関数を呼び出すインターフェースを作成します。このインターフェースは、audio_inputを入力とし、gr.Audio()と"text"の2つの出力を持ちます。gr.Audio()は、ChatGPTが生成した応答の音声ファイルを出力するために使用されます。"text"は、ChatGPTが生成した応答のテキスト形式の出力を表します。
最後に、interface.launch(debug=True)を使用して、Gradioインターフェースを起動します。debug=Trueを指定することで、インターフェースをデバッグモードで起動します。


----

上記コードを実行すると、UI が出力します。


![図1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/517421/b5a0c2f4-50e9-698a-7bd5-3b4458c16674.png)

左側が input、右側が outputです。output には 音声とtext で出力しています。
(所々のデバッグ用にメッセージを出力しているため、画面下で標準出力が見えています。)

上は以下のやりとりです。

　**あなた(入力) -> 「テストです」** 
　**ChatGPTの返答(出力) -> 「OK。」**





---

#### おわりに

Watson STT は **"ja-JP_Telephony"** という次世代モデルを使用しました。
前世代の **"ja-JP_NarrowbandModel"** は非推奨とのことです。

・前世代の言語とモデル
https://cloud.ibm.com/docs/speech-to-text?topic=speech-to-text-models&locale=ja



ChatGPT or 他の大規模言語モデルもカスタマイズできたらより使える場面が増えそうと思いつついます。
<font color="lightgray">(Fine Tuning をがんばればよいのかな...)</font>



[参考]
・[IBM Cloud : Watson Speech to Text](https://cloud.ibm.com/docs/speech-to-text?topic=speech-to-text-gettingStarted&locale=ja)

・[IBM Cloud : Watson Text to Speech](https://cloud.ibm.com/docs/text-to-speech?topic=text-to-speech-gettingStarted)