OpenAIのWhisperとChatGPTのAPIでGoogle Colab上で簡易なボイスボットを作る

こんにちは、AIチームの友松です。2023年3月1日にOpenAIより待望のWhisperとChatGPTのAPIが公開されました。

WhisperはOpenAIが作成した音声認識モデルで多言語の認識や翻訳、プロンプトによる制御ができることが特徴になっています。

ChatGPTは対話形式の大規模言語モデルで非常に質の高い応答をすることから世の中的にかなりの話題になっています。GPT-3.5シリーズのモデルにRLHF(人間のフィードバックによる強化学習)をすることによって、大規模言語モデルの出力の調整を行っています。筆者もChatGPTが出た当初裏側に人間のオペレータが大量に待ち構えて応答を行っているのではないかと疑うくらいの衝撃でした。

RLHFに関しては本ブログでも取り上げているのでこちらの記事も合わせて御覧ください。

今回は同時に発表されたこれら2つのモデルにアクセスできるAPIを組み合わせて簡易的なボイスボット(音声入力によるチャットボット)の構築をGoogle Colab上で行います。

※本記事は2023年3月2日に動作確認を行いました。

1. ライブラリのインストール

Google Colabのセルで下記を実行し必要なライブラリをインストールします。

!pip install openai

2. Google Colabでマイクから取得した音声をWhisperで音声認識する

まずはGoogle Colab上でマイクから拾った音声をWhisperのAPIに投げて音声認識する部分についてのコードです。

Google Colabでマイクから拾った音声をファイルに保存するコードはESPNetのサンプルコードを参照させていただきました。

speech_to_text関数を起動するとマイクから拾った音声を一定時間収録しファイルとして保存します。

保存した音声をOpenAIのWhisperのAPIに投げることで認識結果をjson形式で取得することができます。この結果の認識テキストのみを取り出し返却しています。

Whisper APIに関する公式のドキュメントはこちらになります。また公式のサンプルコードもこちらにあります。今回は試せていないですが、音声認識を行う際にpromptを使って認識結果に影響を与えたり、翻訳をすることもできます。

openai.api_keyにはご自身で取得したAPI KEYをご入力ください。

from IPython.display import Javascript
from google.colab import output
from base64 import b64decode
import openai

openai.api_key = 'YOUR_OPEN_AI_API_KEY'

RECORD = """
  const sleep = time => new Promise(resolve => setTimeout(resolve, time))
  const b2text = blob => new Promise(resolve => {
    const reader = new FileReader()
    reader.onloadend = e => resolve(e.srcElement.result)
    reader.readAsDataURL(blob)
  })
  var record = time => new Promise(async resolve => {
    stream = await navigator.mediaDevices.getUserMedia({ audio: true })
    recorder = new MediaRecorder(stream)
    chunks = []
    recorder.ondataavailable = e => chunks.push(e.data)
    recorder.start()
    await sleep(time)
    recorder.onstop = async ()=>{
      blob = new Blob(chunks)
      text = await b2text(blob)
      resolve(text)
    }
    recorder.stop()
  })
"""

def speech_to_text(model='whisper-1', language='ja', second=5):
  filename='tmp.wav'
  display(Javascript(RECORD))
  s = output.eval_js('record(%d)' % (second * 1000))
  b = b64decode(s.split(',')[1])

  with open(filename, 'wb+') as fw:
    fw.write(b)

  with open(filename, "rb") as fr:
    transcription = openai.Audio.transcribe(
        model=model, 
        file=fr, 
        language=language
    )
    return transcription['text']
Whisperによる音声認識のデモ

動画では「OpenAIのWhisperによる音声認識のテストです」と話すとしっかりテキスト化されていることがわかります。

3. 音声認識結果をChatGPT APIと接続しボイスボットを作成する

ChatGPT APIに関する公式のドキュメントはこちらになります。また、サンプルコードはこちらになります。

ChatGPTの入力プロンプト(messages)はrolecontentで構成される辞書のリストで構成されます。roleは[system, assistant, user]のいずれかが入り、systemはアシスタントの動作の設定として機能します。userに、利用者の発話を格納することで、assistantの発話を取得するというのが一般的な使い方と思われます。

また、やりとりの履歴をmessagesに追加していくことで、過去の文脈を引き継ぎながら対話を進めることができます。

以下のサンプルで、タスク指向対話でよく取り上げられるレストラン対話を行ってみたいと思います。

systemのpromptとして 「あなたはオペレータの振る舞いをするボットです。レストラン予約を完遂してください。エリア(渋谷、新宿、代々木)、料理(ラーメン、焼き肉、中華)、日付、時間を聞いて予約を確定してください。」という文章を与えて、user「こんにちは」と話しかけた想定で会話がスタートします。

userの発話をspeech_to_textによって取得し、assistantの発話を得るというやり取りの繰り返しを行い、userの「おしまい」という発話を検知すると終了するようなボイスボットのデモを行います。

# 初期のプロンプト
messages = [
  {"role": "system", "content": "あなたはオペレータの振る舞いをするボットです。レストラン予約を完遂してください。エリア(渋谷、新宿、代々木)、料理(ラーメン、焼き肉、中華)、日付、時間を聞いて予約を確定してください。"},
  {"role": "user", "content": "こんにちは"},
]

while True:
  completion = openai.ChatCompletion.create(
    model="gpt-3.5-turbo", 
    messages=messages
  )

  bot_speech = completion.choices[0].message.content
  print(f"assistant: {bot_speech}\n")

  while True:
    user_speech = speech_to_text()
    if user_speech != '':
      break
  print(f"user: {user_speech}")

  messages.extend([
      {"role": "assistant", "content": bot_speech},
      {"role": "user", "content": user_speech}
  ])
  
  if user_speech == 'おしまい':
    break

WhisperとChatGPTによるボイスボットのデモ

今まではこのようなレストラン予約を行うタスク指向型対話を構築するためにはヒアリングするためのスロットを設計し対話シナリオを構築し...といった労力がとてつもなかったのですが、ChatGPTではちょっとしたプロンプトしか与えていないのにできてしまうのに驚きました...

4. おわりに

OpenAIのChatのUIから試せるChatGPTは多くのユーザが日々使っておりレスポンス速度が非常に問題になると考えていましたが、まだ早期だからなのか、API利用において高速化したのかは定かではないですが、ボイスボットとして利用してもレスポンス時間はさほど気にならない速度で応答を返してくれました。

今回は簡易的なボイスボットの作成だったので、音声も固定長の秒数で切った結果を音声認識に投げていたので、音声入力が間に合わなくなってしまう場合もありましたが、こちらは適切な発話区間検出を入れることでより良いインタラクションになります。

また、今回はサボってしまいましたが、ボットの発話を音声合成にかければ音声同士のインタラクションも可能になります。

APIの利用金額はWhisperは0.006$/min(秒単位の四捨五入)、ChatGPTは0.002$/1k tokensで使うことができます。(個人的にはChatGPTがtext-davinci-003の10分の1の金額で使えることが驚きました)。金額の詳細はこちら

また、このAPIの入力が学習に使われてしまうことが、製品への組み込みに障壁になりうる大きなポイントでしたが、こちらもデフォルトでオプトアウトされるように変更がされました。詳細はこちらを御覧ください。

今後はGPT-4の登場も噂され、ますます目が話せないです。

参考

以下は実装時に参考にさせていただいた記事です。

PICK UP

TAG