はじめに
こんにちは。デバイスソリューション部 XRチームの道下です。
前年のアドベントカレンダーではARDK Lightship VPSを試すという記事を書きました。
私は毎年その一年で行った中で一番興味があるものを記事にしています。
今年は去年末にOpenAIからChatGPTが公開され、X(旧Twitter)ニュースサイトなどがAIで溢れた一年だという印象です。また、XRにおいてもMagic Leap 2やQuest3などのハードウェアが公開、発売され大いに盛り上がったと思っています。
というわけで今年はXR×AIでChatGPTとQuest3を組み合わせて音声、画像入力でコミュニケーションをする方法について書きます。
最終的な構成
操作者は音声入力と画像入力ができます。
音声入力はQuest3のマイクを通して認識し、テキストに変換され、入力されます。
画像入力は別のAndroid端末で撮影したカメラ画像が入力されます。
その後ChatGPT APIを通じて、入力に対した結果を表示します。
まずはテキスト入力の場合に使用する音声→テキスト変換の実装をします
音声をテキストに変換する
Quest3でできる音声認識を探したところ、MetaのボイスSDKチュートリアルが転がっていたので、ドキュメント通りに実装します。
以下にスクショ付きで詳しく記述されているので説明は割愛します。
チュートリアル - ボイスSDKを使って基本的な音声入力を受け取る | Oculus開発者
動作確認する
話した内容がテキストで確認できます。Wit.aiはMetaのサービスである事と結構認識精度がが良かったので採用しました。
(この時コロナに掛かっていたので、「まだ喉痛いです」的なことを言ってます…
ChatGPT APIの実装
次にChatGPTにテキスト送り、応答を受け取る実装をします
以下の記事を参考にさせていただきました
まずは動作確認。
問題なさそうです。
次はChatGPT APIのリクエストとレスポンスを理解していきます。
リクエスト
OpenAI APIへ以下の形式でリクエストします
{
"model": "gpt-3.5-turbo",
"messages": [
{
"role": "system",
"content": "語尾に「にゃ」をつけて"
},
{
"role": "user",
"content": "好きな魚料理を1つ教えて"
}
]
}
modelにChatGPTでどのモデルを使用するかを決めています。”gpt-4”, “gpt-4 turbo”などに変更することもできます。
"role": "system"ではChatGPTの人格について設定しています。この例では"語尾に「にゃ」をつけて"なので回答+「にゃ」がついたテキストが返ってくるようになります。
"role": "user",ではChatGPTに入力するテキストを設定しています。このテキストを変更することで問う内容が変わります。
レスポンス
以下の形式で返ってきます。
{
"id": "chatcmpl-8SLORP8afxX5H0ub66Vapwv8hWB6B",
"object": "chat.completion",
"created": 1701766111,
"model": "gpt-3.5-turbo-0613",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "好きな魚料理は、さばの味噌煮にゃ。さばの身がふっくらとしていて、味噌の風味がしっかりと絡んでいて美味しいにゃ!"
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 40,
"completion_tokens": 71,
"total_tokens": 111
},
"system_fingerprint": null
}
"role": "assistant"はChatGPTからの回答です。会話内容をユーザーに表示する場合はこの値を使えば良さそうです。
形式についてはOpenAIのドキュメントにも記載があります。
https://platform.openai.com/docs/guides/text-generation/chat-completions-api
別の言葉でリクエストしてみる
実際にsystemとuserを以下の値に変更してみます。
- system:”関西弁で30文字以内で話して”
- user:”大阪で有名な観光地はどこ"
ちゃんと関西弁になっていて親しみやすくなりましたね。次はこの応答テキストを音声に変換します。
テキストを音声に変換する
音声変換Azure AI Serviceの音声サービスを使用します。音声サービスでは音声⇄テキストの変換に対応しています。
サービスを新規作成しておきます。
Unityから呼び出す
Speech SDK for Unityをインストールします。以下のページからunitypackageを取得してプロジェクトにインポートします。
Speech SDK のインストール - Azure AI services | Microsoft Learn
テキストを音声サービスを使って再生するコードは以下です。
YourSubscriptionKey、YourServiceRegionは自身のものに置き換えてください。
using UnityEngine;
using Microsoft.CognitiveServices.Speech;
using Cysharp.Threading.Tasks;
public class TextToSpeechManager : MonoBehaviour
{
private string YourSubscriptionKey = "YourSubscriptionKey";
private string YourServiceRegion = "YourServiceRegion";
/// <summary>
/// テキストを音声で再生します
/// </summary>
/// <param name="speechText"></param>
/// <returns></returns>
public async UniTask PlaySpeakAsync(string speechText)
{
var speechConfig = SpeechConfig.FromSubscription(YourSubscriptionKey, YourServiceRegion);
// 日本語
speechConfig.SpeechSynthesisVoiceName = "ja-JP-MayuNeural";
speechConfig.SpeechSynthesisLanguage = "ja-JP";
using (var speechSynthesizer = new SpeechSynthesizer(speechConfig))
{
var speechSynthesisResult = await speechSynthesizer.SpeakTextAsync(speechText);
switch (speechSynthesisResult.Reason)
{
case ResultReason.SynthesizingAudioCompleted:
Debug.Log($"SynthesizingAudioCompleted : {speechText}");
break;
case ResultReason.Canceled:
var cancellation = SpeechSynthesisCancellationDetails.FromResult(speechSynthesisResult);
Debug.Log($"CANCELED: Reason={cancellation.Reason}");
if (cancellation.Reason == CancellationReason.Error)
{
Debug.Log($"CANCELED: ErrorCode={cancellation.ErrorCode}");
Debug.Log($"CANCELED: ErrorDetails=[{cancellation.ErrorDetails}]");
}
break;
default:
break;
}
}
}
}
SpeechSynthesisVoiceNameは再生する音声を設定します。SpeechSynthesisLanguageは再生する音声の言語を設定します。
Azure AI Serviceの音声サービスには言語ごとに数は異なりますが、複数の音声が登録されています。音声はSpeech Studioから確認することが出来ます。
音声を決めたら、サンプルコードを開き、SpeechSynthesisVoiceNameの文字列をコピーしてUnityのコードに貼り付けるなどして音声を設定します。
Quest3で動作テスト
一通り実装が終わったらQuest3で動作確認します
※音が出るため音量注意
東京タワー前駅とか架空の駅を返してきましたが、リアルに会話しているようでいい感じですね。
テキスト入力はここまでです。以降は画像入力について書きます。
ChatGPTに画像を入力する
GPT-4はテキスト入力以外に画像入力も対応しているので試してみます。
リクエストには入力したい画像のURLもしくはBase64エンコードした画像を追加します。試しにWikipediaにあるコロッセオのURLを使い、どのくらい認識できるか確認します。
「この画像に何が見えますか。」と聞いたところ結構詳しく説明してくれますね。コロッセオや観光客、天気なども認識しています。
リクエストはテキスト入力と多少異なるので見ていきます。
リクエスト
画像入力は以下の形式でリクエストします。
{
"model": "gpt-4-vision-preview",
"messages": [
{
"role": "user",
"content": [
{
"type": "text",
"text": "この画像に何が見えますか。"
},
{
"type": "image_url",
"image_url": "<https://upload.wikimedia.org/wikipedia/commons/a/a3/0_Colosseum_-_Rome_111001_%281%29.JPG>"
}
]
}
],
"max_tokens": 1000
}
image_url”に画像のURLを設定します。Base64エンコードした画像でリクエストする場合は以下のフォーマットにする必要があります。
data:image/jpeg;base64,{base64_image}
形式はテキスト入力と同様にOpenAIのドキュメントに記載があります。
https://platform.openai.com/docs/guides/vision
撮影した画像を使用する
最後にカメラで撮影した画像を入力してみます。ただQuest3のパススルー映像へは現状アクセスできないようになっているようです。
ユーザーの物理環境の画像や動画に、アプリからアクセスすることはできません。その代わり、アプリでは特殊なパススルーレイヤーを作成します。このレイヤーが、XRコンポジターにより実際のパススルー表示に置き換えられます
Passthrough API Overview | Oculus Developers
そのため、今回は別のAndroid端末で撮影した画像をQuest3で取得するようにしました。動画ではキーボード、ラズパイ、光造形用レジン液を認識させてみました。
おわりに
今回はChatGPTとQuest3を組み合わせてコミュニケーションをしました。様々なサービスを使っているためコストはかかります(特に画像入力)が、体験として非常に良いと思いました。今後もXRに関する記事を書いていきたいと思っております。
最後まで読んでいただきありがとうございました。
ネクストスケープでは共に働く仲間を絶賛募集中です。
ご興味ある方は下記のURLからお気軽に。