仮想と物理とエトセトラ

xRや物理とかごった煮の備忘録的技術ブログ

簡易翻訳機を作ってみる その3 HoloLens2からDeepLのWebAPIをつかう

今回は下記の続きで、WebAPIをHoloLens2アプリからたたくことで、翻訳できるようにします。

xr-physics-work-etc.hatenablog.com

1. 準備

前回試したWebAPIをC#からHTTPリクエストすることで使用し、翻訳結果を受け取ります。
今回はHTTPリクエストはUnityWebRequest、レスポンスで得られるJsonを解釈するためにはJsonUtilityを使用しました。

docs.unity3d.com

docs.unity3d.com

  • Translator.cs
クリックで展開
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.Events;

namespace SimplifiedTranslator
{
    /// <summary>
    /// 応答用構造体
    /// </summary>
    [System.Serializable]
    public struct translate_results
    {
        public translate_result[] translations;
    }

    /// <summary>
    /// 翻訳結果取得用構造体
    /// </summary>
    [System.Serializable]
    public struct translate_result
    {
        public string detected_source_language;
        public string text;
    }
    
    /// <summary>
    /// 変換後用UnityEvent
    /// </summary>
    [System.Serializable]
    public class TranslatedEvent :UnityEvent<string>
    {

    }

    public class Translator : MonoBehaviour
    {
        /// <summary>
        /// 変換前テキスト
        /// </summary>
        private string pre_conversion_text;

        /// <summary>
        /// 変換対象
        /// </summary>
        private string target_lang;
        
        /// <summary>
        /// 変換後テキスト
        /// </summary>
        private string converted_text;

        /// <summary>
        /// deepLのAutherntication Key
        /// </summary>
        [SerializeField]
        private string deepl_auth_key;

        /// <summary>
        /// deepl API用のURL
        /// </summary>
        [SerializeField]
        private string url = "https://api-free.deepl.com/v2/translate";

        /// <summary>
        /// 変換完了後に発火するEvent
        /// </summary>
        public TranslatedEvent Finish_translate_event = new TranslatedEvent();
        
        public void GetTranslatorResult(string pre_conversion_text, string target_lang)
        {
            this.pre_conversion_text = pre_conversion_text;
            this.target_lang = target_lang;
            StartCoroutine("GetTranslatorResultCoroutine");
        }
        
        /// <summary>
        /// 変換結果取得処理
        /// </summary>
        /// <param name="pre_conversion_text"></param>
        /// <param name="target_lang"></param>
        /// <returns></returns>
        private IEnumerator GetTranslatorResultCoroutine()
        {
            // リクエストを作成
            WWWForm form = new WWWForm();
            form.AddField("auth_key", this.deepl_auth_key);
            form.AddField("text", this.pre_conversion_text);
            form.AddField("target_lang", this.target_lang);

            UnityWebRequest webRequest = UnityWebRequest.Post(this.url, form);

            yield return webRequest.SendWebRequest();

            if (webRequest.isNetworkError || webRequest.isHttpError)
            {
                // エラーの場合はエラー出力
                Debug.Log(webRequest.error);
            }
            else
            {
                // 応答から翻訳結果を取得
                string result = webRequest.downloadHandler.text;
                Debug.Log($"response:{result}");
                translate_results results = JsonUtility.FromJson<translate_results>(result);
                this.converted_text = results.translations[0].text;
                Finish_translate_event.Invoke(this.converted_text);
                Debug.Log($"result:{this.converted_text}");
            }
        }
    }
}

Translator::GetTranslatorResult(string pre_conversion_text, string target_lang)を実行することで、リクエストを実施でき、Translator::Finish_translate_eventにstringを引数とするイベントを登録することで、結果を取得することができます。

Scene上に空のTranslatorGmeObjectを作成し、Translator.csをアタッチします。
Deepl auth keyには、前回取得したDeepLの認証キーを入力します。
f:id:napo909:20211017142921p:plain

次に、動作確認のためのスクリプトを作成しました。
変換対象をENに限定し、InputFileldの内容を入力として、TextMeshProに結果を返す方針としました。

  • TranslateTest.cs
クリックで展開
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using SimplifiedTranslator;
using TMPro;

public class TranslateTest : MonoBehaviour
{
    [SerializeField]
    TMP_InputField inputField;

    [SerializeField]
    TextMeshPro result;

    [SerializeField]
    Translator translator;


    // Start is called before the first frame update
    void Start()
    {
        translator.Finish_translate_event.AddListener(ShowTranslateResult);
    }

    // Update is called once per frame
    void Update()
    {

    }

    public void StartTranslate()
    {
        Debug.Log("Start Translate");
        translator.GetTranslatorResult(inputField.text, "EN");
    }

    public void ShowTranslateResult(string translated_text)
    {
        result.SetText(translated_text);
    }
}

次に、空のTranslateResultGameObjectを作成し、TranslateTest.csをアタッチし、下画像のようにScene上にTextMeshProのInputfiled, ラベル用のテキスト、MRTKのボタンを構成します。
f:id:napo909:20211017143146p:plain
f:id:napo909:20211017143216p:plain

作成した各要素をTranslateTestコンポーネントに設定します。
f:id:napo909:20211017143249p:plain

ボタンのOnClick()には、変換開始するためのTranslateTest::StartTranslateを設定します。
f:id:napo909:20211017143430p:plain

これでボタンを押すとInputFiledに入力された文字列を、英語に変換しTextラベルに出力することができます。
なお、日本語を変換する際はInputfieldに日本語表示をできるように設定する必要があります。
設定に必要なFontAssetは、下記を参考に作成できます。

bluebirdofoz.hatenablog.com

2. 動作確認

準備が終わったら、アプリをHoloLensにデプロイします。
アプリを起動すると、先ほど用意したInputFieldに文字を入れてボタンを押すことで英語への翻訳結果を取得できます。

システムキーボードの音声入力で、簡易的に音声入力での翻訳もできるでしょう。
これで、簡単な翻訳機の入り口ができました。