Unity+chatgpt+webglで録音+音声認識を実現

I.はじめに 

        AI 二次彼女のプロジェクトは継続的に更新されており、ウィンドウ側の音声認識および音声合成機能については、前回のブログ記事の Microsoft Azure Voice Service のコード実装で詳しく説明しました。ワンタイムコードと多端末多重化の魅力を実現するためでもあり、すべてのコード実装をWeb API方式に変更しました。しかし、実際のテストを webgl にリリースしたところ、このプロジェクトでは音声認識用にマイクで音声を録音する必要があったため、問題が発見され、リリース時にエンジンがエラーを報告し、unity の公開に失敗しました。情報によると、Unity の内蔵マイク クラスが webgl をサポートしていないことが判明したため、別の解決策を見つける必要がありました。

        また、インターネット上で多くの情報を調べたり、Unity 公式からいくつかの情報を得たりしました。解決策については、Unity の公式ドキュメントを参照してください。このドキュメントには、Unity が *.jslib を展開する方法で js を呼び出す方法が記載されています。 Unity 側メソッド、Unity ドキュメント:

https://docs.unity3d.com/cn/2020.3/Manual/webgl-interactingwithbrowserscripting.html

        私自身の技術力にも限界があるため、既製のソリューションをいくつか見つけて実際にテストを行い、最終的にブロガーが提供するソリューションとソースコードを見つけました。彼のソース コードを私のプロジェクトに統合することで、実際に私の問題は解決されました。webgl に公開した後、録音のためにマイクを呼び出すことができ、Azure の音声認識によってテキストが正しく認識されるようになります。実はこの過程で色々な問題が発生し、時間はかかりましたが、最終的にはすべて解決できました、忘れてしまうのではないかと思い、急いで書類に書いて必要なときに備えて保管しておきました。未来。私が参照したブロガーのソリューションでは、Unity 側で JS コードを呼び出すことに加えて、Unity にデータを返す JS もあります。コード実装の一部はjsで実現されているため、webglリリース後はコードを少し修正したり、jsライブラリを追加したりする必要がありますが、具体的な設定方法は以下を参照してください。

2.WebGL をリリースする

        Unity が webgl プロジェクトの設定を公開します。まず、エンジンが webgl プラットフォームの拡張機能でインストールされていることを確認します。ビルド設定で webgl プラットフォームを切り替えることができない場合は、公式 Web サイトにアクセスしてインストール パッケージをダウンロードし、それからインストールしてください。プラットフォームを切り替えるだけです。公開する前にプロジェクトのパスを確認し、プロジェクトのパスが英語であることを確認してください。そうでない場合は、webgl をエクスポートするときにエラーが報告されます。

        公開設定:

        1. [その他の設定] で、[色空間] を [ガンマ] に変更します。

        

        2. [公開設定] で、[解凍フォールバック] をオンにします。

        

         WebGL を公開するプロセスで他の問題を見つけた場合は、Baidu または他のチャネルにアクセスして自分で検索してください。この分野には多くの情報があり、基本的に関連する問題の解決策を見つけることができます。上記はいくつかの設定上の問題です。リリース中に発生したのでメモしておきます。

3. スクリプトの説明

        このプロジェクトには、Unity 側と JS 側の 2 つのコード部分が含まれます。

        1. Unityターミナルコードの説明

        Unity 側では、公式のソリューションを参照してください。Unity Plugins ファイルの下に *jslib ファイルを作成する必要があります。このライブラリでは、Unity が提供する公式のサンプルに従って js コードを記述し、C# スクリプトでそれを参照します。指定したメソッドにUnity側でjsコードを呼び出します。

        jslib 公式コード例 (このファイルは Plugins フォルダーの下に配置する必要があります)

mergeInto(LibraryManager.library, {

  Hello: function () {
    window.alert("Hello, world!");
  },
});

        C# 側では、公式の例に従って、次のコードを書くことで js メソッドを参照できます

 [DllImport("__Internal")]
    private static extern void Hello();

        上記は C# で js コードを呼び出した例です。録音と録音終了の関数はプロジェクト関数にカプセル化されており、直接呼び出すことができます。必要に応じて、StartRecord() を呼び出して録音を開始し、StopRecord() を呼び出します。 ) 録音を終了します。

    [DllImport("__Internal")]
    private static extern void StartRecord();
    [DllImport("__Internal")]
    private static extern void StopRecord();

      2.jsコードの説明

        ソース コードは js コードを提供します。プロジェクトには記録完了後に js エンドが含まれるため、記録データを使用するために Unity に送り返す必要があるため、上記の機能を実現するには js コードの一部を追加する必要があります。 。関連するコードはソース コードで提供されており、エクスポートされた webgl パッケージ内の対応するコード ファイルを変更するだけで済みます。具体的な変更方法については次項を参照してください。

4. スクリプトの構成

        このセクションでは、エクスポートされた webgl パッケージ内のコード構成の内容について詳しく説明します。

       1.jsスクリプトを追加

        [recorder.wav.min.js] スクリプトを見つけて、出力された webgl パッケージおよびindex.html と同じフォルダーの下の [ルート ディレクトリ] にスクリプトをコピーします。

        

       2.index.htmlを変更する 

        まず、[AddToIndex.js] ファイルを見つけます。後で追加する必要があるコードはすべてこのファイルに含まれているので、直接コピーするだけです。

        ①index.html内の/recorder.wav.min.jsスクリプトを参照

        [AddToIndex.js] ファイルで、「<script src="./recorder.wav.min.js"></script>」をコピーし、index.html に追加して、[recorder.wav.min.js] を引用します。 』の脚本。

 <script src="./recorder.wav.min.js"></script>
    <script>
      var container = document.querySelector("#unity-container");
      var canvas = document.querySelector("#unity-canvas");
      var loadingBar = document.querySelector("#unity-loading-bar");
      var progressBarFull = document.querySelector("#unity-progress-bar-full");
      var fullscreenButton = document.querySelector("#unity-fullscreen-button");
      var warningBanner = document.querySelector("#unity-warning");
    ....

    后续面代码略
</script>

        ②jsの処理コードをindex.htmlにコピーします。

        [AddToIndex.js] の 7 行目から 110 行目のコードを <script> スクリプトにコピーします (コードの「document.body.appendChild(script);」行に直接追加できます)。


document.body.appendChild(script);这行不要拷贝,就是告诉你从哪行开始粘贴

// 全局录音实例
let RecorderIns = null;
      //全局Unity实例   (全局找 unityInstance , 然后等于它就行)
      let UnityIns = null;

      // 初始化 ,   记得调用
      function initRecord(opt = {}) {
        let defaultOpt = {
          serviceCode: "asr_aword",
          audioFormat: "wav",
          sampleRate: 44100,
          sampleBit: 16,
          audioChannels: 1,
          bitRate: 96000,
          audioData: null,
          punctuation: "true",
          model: null,
          intermediateResult: null,
          maxStartSilence: null,
          maxEndSilence: null,
        };

        let options = Object.assign({}, defaultOpt, opt);
        let sampleRate = options.sampleRate;
        let bitRate = options.sampleBit;
        if (RecorderIns) {
          RecorderIns.close();
        }

        RecorderIns = Recorder({
          type: "wav",
          sampleRate: sampleRate,
          bitRate: bitRate,
          onProcess(buffers, powerLevel, bufferDuration, bufferSampleRate) {
            // 60秒时长限制 
            const LEN = 59 * 1000;
            if (bufferDuration > LEN) {
              RecorderIns.recStop();
            }
          },
        });
        RecorderIns.open(
          () => {
            // 打开麦克风授权获得相关资源
            console.log("打开麦克风成功");
          },
          (msg, isUserNotAllow) => {
            // 用户拒绝未授权或不支持
            console.log((isUserNotAllow ? "UserNotAllow," : "") + "无法录音:" + msg);
          }
        );
      }

      // 开始
      function StartRecord() {
        RecorderIns.start();
      }
      // 结束
      function StopRecord() {
        RecorderIns.stop(
          (blob, duration) => {
            console.log(
              blob,
              window.URL.createObjectURL(blob),
              "时长:" + duration + "ms"
            );
            sendWavData(blob)
          },
          (msg) => {
            console.log("录音失败:" + msg);
          }
        );
      }
      
      // 切片像unity发送音频数据
      function sendWavData(blob) {
        var reader = new FileReader();
        reader.onload = function (e) {
          var _value = reader.result;
          var _partLength = 8192;
          var _length = parseInt(_value.length / _partLength);
          if (_length * _partLength < _value.length) _length += 1;
          var _head = "Head|" + _length.toString() + "|" + _value.length.toString() + "|end" ;
          // 发送数据头
          UnityIns.SendMessage("SignalManager", "GetAudioData", _head);
          for (var i = 0; i < _length; i++) {
            var _sendValue = "";
            if (i < _length - 1) {
              _sendValue = _value.substr(i * _partLength, _partLength);
            } else {
              _sendValue = _value.substr(
                i * _partLength,
                _value.length - i * _partLength
              );
            }
            _sendValue = "Part|" + i.toString() + "|" + _sendValue;
            // 发送分片数据
            UnityIns.SendMessage("SignalManager", "GetAudioData", _sendValue);
          }
          _value = null;
        };
        reader.readAsDataURL(blob);
      }

        ③初期化コード

        ここで、インスタンス化コードの追加に注意する必要があります。index.html で UnityInstance のインスタンス化コード ブロックを見つけて、「UnityIns =unityInstance; initRecord();」という 2 行のコードを追加する必要があります (「」に追加できます)。 then((unityInstance) => {" このコードの後に​​)

   script.onload = () => {
        createUnityInstance(canvas, config, (progress) => {
          progressBarFull.style.width = 100 * progress + "%";
        }).then((unityInstance) => {

          UnityIns = unityInstance;//拷贝代码
          initRecord();//拷贝代码

          loadingBar.style.display = "none";
          fullscreenButton.onclick = () => {
            unityInstance.SetFullscreen(1);
          };
        }).catch((message) => {
          alert(message);
        });
      };

        上記のコードを変更すると構成が完了し、webgl プロジェクトをデプロイして効果をテストできます。元の作成者のプロジェクトをテストしたときに問題が発生しました。私のプロジェクトでは録音データを取得して音声認識 API に送信する必要があるため、最初は認識結果に問題があり、不正確であることがわかりました。その後、音声を録音する設定で、サンプリング レートを 44100 に調整したところ、正常に認識されたので、ここに記録しておきます。この修正は、すでに自分のソース コードで行っています。

        5。結論

        今回、Unity の音声認識機能が webgl にリリースできない問題が解決され、無事にこのプロジェクトを webgl にデプロイして利用できるようになりました。現在の解決策ではリリース後にjsコードの処理が必要で比較的面倒ですが、これ以上簡単な解決策は今のところ見つかっていませんので、今後もっと便利な解決策が見つかったら共有したいと思います。

        プロジェクトのソースコードはまだ整理されていません。ソースコードが整理できたらここに追加します。後で追加できるようにスペースを残してください。

AI二次元彼女プロジェクトのソースコード:

Github アドレス: https://github.com/zhangliwei7758/unity-AI-Chat-Toolkit

Gitee アドレス: https://gitee.com/DammonSpace/unity-ai-chat-toolkit

プロジェクトのビデオは私の B ステーションのホームページでご覧いただけます。

【メジャーアップデート -> シンプルなデプロイメント + クロスプラットフォーム】AI二次元ミスシスタープロジェクトを再構築し、新しいUnityツールキットをリリースし、使いやすく+実用的なAIスイート、オープンソースコードがあなたを待っています!

        6. 参考文献

        このソリューションは、多くの大手企業の情報も参照しています。相談および参照用の関連情報ポータルは次のとおりです。      

CSDN ブログ: https://blog.csdn.net/Wenhao_China/article/details/126779212?spm=1001.2014.3001.5502t

CSDN ブログ投稿: https://blog.csdn.net/a987654sd/article/details/105551560

ソリューション作成者のソース コード アドレス:

Github:https://github.com/HiWenHao/UnityWebGLMicrophone

追加資料:

次の 2 つの WebGL 使用マイク ソリューションはまだ検証していないので、参考のためにここにも載せておきます。

解決策 1: https://gitcode.net/mirrors/xiangyuecn/recorder?utm_source=csdn_github_accelerator

解決策 2: https://github.com/tgraupmann/UnityWebGLMicrophone/tree/maste

おすすめ

転載: blog.csdn.net/sinat_28962939/article/details/131868073