MRが楽しい

MRやVRについて学習したことを書き残す

whisper.unityを使ってQuestで日本語認識を行う

本日はwhisper.unityの環境構築枠です。
whisper.unityを使ってQuestで日本語認識を行う方法です。

whisper.unity

whisper.unityはOpenAI WhisperをUnity上で扱うためのラッパーでリアルタイム音声入力とテキスト変換を統合できます。
クロスプラットフォーム対応の音声認識をすぐに組み込むことができます。
github.com

Quest向けプロジェクトにwhisper.unityを組み込む

今回はMRTKで構築したQuest向けプロジェクトにwhisper.unityを組み込んでみました。

2.MicrophoneサンプルシーンのMicrophoneDemo.csをプロジェクトに合わせて改修しました。
Quest上では性能により文字起こしに時間がかかるため、録音時間の条件を設けて解析中はボタンをロックしています。
・WhisperRecordMicSimpleView.cs

using System.Collections;
using System.Diagnostics;
using UnityEngine;
using Whisper.Utils;
using Microsoft.MixedReality.Toolkit.UI;
using TMPro;
using Whisper;

namespace Chatbot.Whisper.View
{
    /// <summary>
    /// Record audio clip from microphone and make a transcription.
    /// </summary>
    public class WhisperRecordMicSimpleView : MonoBehaviour
    {
        public WhisperManager whisper;
        public MicrophoneRecord microphoneRecord;

        [Header("UI")]
        public Interactable recordButton;
        public ButtonConfigHelper recordButtonText;
        public TMP_InputField segmentMessageText;

        private Coroutine _autoStopCoroutine;
        private const float MaxRecordSeconds = 5f;

        private void Awake()
        {
            microphoneRecord.OnRecordStop += OnRecordStop;
            recordButton.OnClick.AddListener(OnButtonPressed);

            // 無音検出による自動録音停止を有効化
            microphoneRecord.vadStop = true;
        }

        private void OnButtonPressed()
        {
            if (!microphoneRecord.IsRecording)
            {
                microphoneRecord.StartRecord();
                recordButtonText.MainLabelText = "Stop";
                ScheduleAutoStop();
            }
            else
            {
                StopRecording();
            }
        }

        private async void OnRecordStop(AudioChunk recordedAudio)
        {
            // 解析が完了するまではボタンを無効化
            recordButtonText.MainLabelText = "Processing...";
            recordButton.IsEnabled = false;

            CancelAutoStop();

            var sw = new Stopwatch();
            sw.Start();

            var res = await whisper.GetTextAsync(recordedAudio.Data, recordedAudio.Frequency, recordedAudio.Channels);
            if (res == null)
                return;

            var time = sw.ElapsedMilliseconds;
            var rate = recordedAudio.Length / (time * 0.001f);

            var text = res.Result;

            segmentMessageText.text = text;

            // 解析完了後にボタンをRecordにして再度有効化
            recordButtonText.MainLabelText = "Record";
            recordButton.IsEnabled = true;
        }

        private void StopRecording()
        {
            if (!microphoneRecord.IsRecording)
                return;

            CancelAutoStop();
            microphoneRecord.StopRecord();
        }

        private void ScheduleAutoStop()
        {
            CancelAutoStop();
            _autoStopCoroutine = StartCoroutine(AutoStopAfterDelay());
        }

        private void CancelAutoStop()
        {
            if (_autoStopCoroutine == null)
                return;

            StopCoroutine(_autoStopCoroutine);
            _autoStopCoroutine = null;
        }

        private IEnumerator AutoStopAfterDelay()
        {
            yield return new WaitForSeconds(MaxRecordSeconds);
            if (microphoneRecord.IsRecording)
                StopRecording();
        }
    }
}

Whisperを動作させるため、Whispere ManagerとMicrophone Recordのコンポーネントも合わせて追加しておきます。

録音を許可するため、AndroidManifest.xmlに以下のオーディオアクセスの許可を追加して完了です。

<uses-permission android:name="android.permission.RECORD_AUDIO" />


Tips

Whispere ManagerコンポーネントはStreamingAssetsに配置したモデルを参照します。

通常、Android環境はSteamingAssetsがAPK内のzipに格納されるため、実パスではなくURIでのアクセスが必要になります。
しかしWhisper Unity Pluginはプラグイン内部でAndroid用の読み込み処理が実装されているため、特にパス周りを改修しなくてもそのまま利用できます。
https://discussions.unity.com/t/android-streamingassets-file-access/35531/2

実機での動作確認

プロジェクトをQuest3にデプロイしてアプリを実行してみました。

録音を開始して発話すると正常に文字認識できました。
以下のような一センテンスの文字起こしでも10~20秒ほど時間がかかります。