🗽

OpenAIChatCompletionAPIとSpeechRecognitionAPIと組み合わせてChatGPTと音声で会話する

2023/05/16に公開

概要

WebSpeechAPIを試しましたが思いのほかSpeechRecognitionAPIの精度が良く何かできないかなと思い、ChatGPTと組み合わせて音声で会話をするアプリをサクッと作ってみました。
https://zenn.dev/micronn/articles/b654ceca1bdf13

作ったもの

テキストを入力しなくても、音声入力をオンにして話すだけでChatGPTからの返信が表示され音声で読み上げられます。

使った技術

  • OpenAIChatCompletionAPI
  • React
  • SpeechRecognitionAPI
  • VOICEVOX

手順

1. Reactの環境をセットアップ

create-react-appを利用しました。Reactを実行できる環境であれば何でもOKです。

npx create-react-app chat-with-chatgpt --template typescript

2. SpeechRecognitionAPIを用いて音声入力を実装

https://github.com/JamesBrill/react-speech-recognition
Reactで扱いやすいようにラッパーライブラリを利用します。
SpeechRecognition.startListening()で音声入力開始、音声入力中はlisteningがtrueとなりSpeechRecognition.stopListening()で音声入力終了するとlisteningがfalseとなります。
本来はuseSpeechRecognitionから識別した音声の値を取得して使うのですが、今回は音声認識が完了したタイミングでリクエストを行いたかったためcallbackを定義できるcommandsで実装しています。

import SpeechRecognition, {
  useSpeechRecognition,
} from 'react-speech-recognition'
const { listening } = useSpeechRecognition({
    commands: [
    {
        command: '*',
        callback: async (command) => {
          if (command) {
            setMessages((prevState) => [
              ...prevState,
              { isMe: true, message: command },
            ])
            await sendChatGPT(command)
          }
        },
      },
    ],
  })
  const onStart = async () => {
    setIsChecked(true)
    await SpeechRecognition.startListening()
  }
  const onEnd = async () => {
    setIsChecked(false)
    await SpeechRecognition.stopListening()
  }

3. OpenAIのChatCompletionAPIを用いてレスポンスを取得

APIはgpt-3.5-turboモデルを利用します。

Most capable GPT-3.5 model and optimized for chat at 1/10th the cost of text-davinci-003. Will be updated with our latest model iteration.

OpenAIよりAPIKeyを発行しOrganizationIDと一緒に環境変数へ指定します。

.env
REACT_APP_OPENAI_ORGANIZATION_ID=xxxxxxxxxx
REACT_APP_OPENAI_API_KEY=xxxxxxxxxx

OpenAIAPIへのアクセスするためのライブラリを導入

yarn add openai

Authenticationに従ってAPIKeyとOrganizationIDを設定します。
Configの指定が完了したら次はChatCompletionAPIのリクエストを行います。createChatCompletionメソッドで、モデル名、最大トークン数と一緒に2で音声入力したテキストデータをリクエスト含めます。

import { Configuration, OpenAIApi } from 'openai'
const sendChatGPT = async (question: string) => {
setIsLoading(true)
const configuration = new Configuration({
  organization: process.env.REACT_APP_OPENAI_ORGANIZATION_ID,
  apiKey: process.env.REACT_APP_OPENAI_API_KEY,
})
const openai = new OpenAIApi(configuration)
const completion = await openai.createChatCompletion({
  model: 'gpt-3.5-turbo',
  max_tokens: 400,
  messages: [
    { role: 'user', content: question ?? '' },
  ],
})
setIsLoading(false)
const text = completion.data.choices[0].message?.content
(一部略)
}

4. VOICEVOXを用いてテキストを音声に変換

WebSpeechAPI試しておきながらSpeechSynthesisAPIではないんかいとつっこまれてしまいそうですがVOICEVOXでは簡単に美ボイスを利用できたのでついつい。
https://voicevox.hiroshiba.jp/
https://github.com/VOICEVOX/voicevox
ダウンロードするとアプリケーションが立ち上がります。GUIと一緒にAPIも提供されており、今回はAPIを使います。

http://localhost:50021/docs へアクセスしてAPIドキュメントを確認します。今回は/audio_query/synthesisを利用してwavファイルを取得します。

ChatCompletionAPIから返却されたテキストで音声合成用クエリを作成し、クエリを用いて音声合成を行います。

const sendChatGPT = async (question: string) => {
(一部省略)
  const query = await createQuery(text) <-- ChatCompletionAPIから返却されたテキスト
  const voice = await createVoice(query)
  const audio = new Audio(voice ? window.URL.createObjectURL(voice) : '')
  await audio.play()
  audio.onended = () => onStart()
}
const createQuery = async (text = '') => {
  const res = await axios.post(
  `http://localhost:50021/audio_query?speaker=8&text=${text}`,
  )
  return res.data
}
const createVoice = async (query: string) => {
  const res = await axios.post(
    'http://localhost:50021/synthesis?speaker=8',
    query,
    { responseType: 'blob' },
  )
  return res.data
}

5. 実際に動かしてみる

音声入力を開始すると初回のみ、マイクの使用許可を求められます。「許可する」をクリックすると音声入力可能となります。

ブラウザのマイクに向かって話すとテキストに変換され表示されます。

話した内容がリクエストされOpenAIのChatCompletionAPIがレスポンスを返します。返却されたテキストはVOICEVOXで音声に変換され読み上げられます。読み上げが完了後再度音声入力が可能となります。
APIリクエストで数秒時間がかかってしまうもののたった4ステップでChatGPTと会話することができました🎉

余談

ChatCompletionAPIの設定せずそのまま利用していたので、会話の文脈はガン無視です。。

assistant前の会話を含めたりプロンプトを工夫することで会話の質は高められそうですね
https://qiita.com/sakasegawa/items/db2cff79bd14faf2c8e0
https://prompt.quel.jp/

Discussion