LoginSignup
8
7

More than 5 years have passed since last update.

続、developerWorks記事「Watson×Unity!初心者でもできる、VR 空間で Unity ちゃんとおしゃべりアプリ!」を試してみる

Last updated at Posted at 2018-04-21

IBM の developerWorks サイトの記事 Watson×Unity!初心者でもできる、VR 空間で Unity ちゃんとおしゃべりアプリ! を現時点(2018年4月15日)の最新環境(バージョン)で試してみました。

前回 に引き続き、残りの API 用サンプルコードも修正したので、一応公開します。

Text to Speech を試してみよう

IBM Cloud (Bluemix) のダッシュボードからText to Speechのサービスを作成して、"TTS_unity-chan_test" など適当な名前に変更し、以下のように「資格情報」を作成して表示しておきます。

image.png

参照: Text To Speech APIの日本語説明ページ

そして Unity に戻って2つめのサンプルコード SampleTextToSpeech.cs をコピペするのですが、やはり今回も「資格情報」を設定するコードを追加します。肝心の ToSpeech 関数も引数が変更されているようなので、これも前回と同様に修正 (OnFail関数の定義と指定) してあげます。

結果として、修正済みのコードは以下になりました。

SampleTextToSpeech.cs
//SampleTextToSpeech.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using IBM.Watson.DeveloperCloud.Services.TextToSpeech.v1;
using IBM.Watson.DeveloperCloud.Connection;
using IBM.Watson.DeveloperCloud.Utilities;

public class SampleTextToSpeech : MonoBehaviour
{

    //TextToSpeech m_TextToSpeech = new TextToSpeech();
    TextToSpeech m_TextToSpeech;
    string m_TestString = "おはようございます。漢字も読めます。";

    // Use this for initialization
    void Start()
    {
        string cre_id = "b2xxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxb6";                  // 資格情報より
        string cre_pw = "2xxxxxxxxxxu";                                          // 資格情報より
        string cre_url = "https://stream.watsonplatform.net/text-to-speech/api"; // 資格情報より
        Credentials credentials = new Credentials(cre_id, cre_pw, cre_url);
        m_TextToSpeech = new TextToSpeech(credentials);
        m_TextToSpeech.Voice = VoiceType.ja_JP_Emi;
        //m_TextToSpeech.ToSpeech(m_TestString, HandleToSpeechCallback);
        m_TextToSpeech.ToSpeech(HandleToSpeechCallback, OnFail, m_TestString);
    }

    //void HandleToSpeechCallback(AudioClip clip)
    void HandleToSpeechCallback(AudioClip clip, Dictionary<string, object> customData)
    {
        PlayClip(clip);
    }

    private void PlayClip(AudioClip clip)
    {
        if (Application.isPlaying && clip != null)
        {
            GameObject audioObject = new GameObject("AudioObject");
            AudioSource source = audioObject.AddComponent<AudioSource>();
            source.spatialBlend = 0.0f;
            source.loop = false;
            source.clip = clip;
            source.Play();

            GameObject.Destroy(audioObject, clip.length);
        }
    }
    private void OnFail(RESTConnector.Error error, Dictionary<string, object> customData)
    {
        Debug.Log("SampleTextToSpeech.OnFail() Error received: " + error.ToString());
    }

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

}

これで Unity ちゃんがちゃんと喋ってくれましたが、思ってたよりも落ち着いた女性の声で違和感がw

さて、次に進みましょう。

Conversation Service を試してみよう

えーと、実は私は Conversation (Watson Assistant) は以前から使用していますので、手抜きして、過去に作成した会話データを流用しちゃいますね。皆さんは元ページをみて会話データを作成してみてください。

作成した会話データの Workspace ID を表示しておきます。

image.png

また Speech To Text などと同様に、「資格情報」を表示しておきます。

image.png

参照: Conversation APIの日本語説明ページ

そして Unity に戻り、3つめのサンプルコード SampleConversation.cs を修正していきましょう。実は今回の3つのAPIの中で、これが一番大変でした…

やはり今回も「資格情報」を設定するコードを追加します。肝心の ToSpeech 関数も引数が変更されているようなので、これも前回と同様に修正してあげます。

で、Conversation なのですが、名称が変わったことで

  • IBM.Watson.DeveloperCloud.Services.Conversation.v1
  • IBM.Watson.DeveloperCloud.Services.Assistant.v1

の2種類のAPIがあるようなんですよ。たぶん後者に移行中?困ったことにSDKドキュメントですら更新途中で整合性が無いように見受けられ… サンプルに従ってもうまく動作せず困惑。

一番面倒だったのが Message に渡す Delegation 関数である OnMessage 関数のところ。関数の定義は新しくなっているんですが、現在のバージョンで実行してみると、過渡期だからなのか渡される値が違う。MessageResponse の代わりに Dictionary オブジェクトが第一引数に渡され、あれ君は customData では?と混乱する謎動作。

仕方ないので今回は動作にあわせ、元ページと同じ処理するコードを書いてみました。ダーティハックって感じで、これいつまで通用するんでしょうね… 近い将来、移行が落ち着いたころにもう一回フォローできると良いのですが。

というわけで、以下がとりあえず動作する、修正後のコードになります。

SampleConversation.cs
//SampleConversation.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using IBM.Watson.DeveloperCloud.Services.Conversation.v1;
using IBM.Watson.DeveloperCloud.Connection;
using IBM.Watson.DeveloperCloud.Utilities;

public class SampleConversation : MonoBehaviour
{

    //private Conversation m_Conversation = new Conversation();
    private Conversation m_Conversation;
    private string m_WorkspaceID = "8cxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx79"; //各自変更してください
    private string m_Input = "おはよう";

    // Use this for initialization
    void Start()
    {
        string cre_id = "50xxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx22";                  // 資格情報より
        string cre_pw = "pxxxxxxxxxxx";                                          // 資格情報より
        string cre_url = "https://gateway.watsonplatform.net/conversation/api";  // 資格情報より
        Credentials credentials = new Credentials(cre_id, cre_pw, cre_url);
        m_Conversation = new Conversation(credentials);
        Debug.Log("User: " + m_Input);
        //m_Conversation.Message(OnMessage, m_WorkspaceID, m_Input);
        m_Conversation.VersionDate = "2017-05-26";
        m_Conversation.Message(OnMessage, OnFail, m_WorkspaceID, m_Input);
    }

    //void OnMessage(MessageResponse resp, string customData)
    void OnMessage(object resp, Dictionary<string, object> customData)
    {
        /*
        foreach (Intent mi in resp.intents)
            Debug.Log("intent: " + mi.intent + ", confidence: " + mi.confidence);

        Debug.Log("response: " + resp.output.text.[0]);
        */
        if (resp is Dictionary<string, object>)
        {
            Dictionary<string, object> dic_resp = (Dictionary<string, object>)resp;

            foreach (object o in (List<object>)dic_resp["intents"])
            {
                Dictionary<string, object> dic_intent = (Dictionary<string, object>)o;
                Debug.Log("intent: " + dic_intent["intent"] + ", confidence: " + dic_intent["confidence"]);
            }

            Dictionary<string, object> dic_output = (Dictionary<string, object>)dic_resp["output"];
            string res = "";
            foreach (object o in (List<object>)dic_output["text"])
            {
                res += o.ToString();
            }
            Debug.Log("response: " + res);
        }

    }
    private void OnFail(RESTConnector.Error error, Dictionary<string, object> customData)
    {
        Debug.Log("SampleConversation.OnFail() Error received: " + error.ToString());
    }

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

実行してみて、やりとりが Unity のコンソールに表示されることを確認します。

image.png

あ、忘れてました。いざ実行したら「VersionDate が null なので "2017-05-26" を設定せよ」とエラー表示されたので、生成した m_Conversation インスタンスに素直に代入したらエラー消えました。ここの詳細は追っていませんが、ちょっと不思議な感じですね。

というわけで

前回 は Speech To Text だけでしたが、今回は Text To Speech と Conversation のサンプルも修正してみました。全ての API のコード修正部分をまとめたので、後は 元の解説ページ に従って進めていただければ良いとおもいます。

単なるバージョン違いかと思ったら

  • 認証情報の簡易ツールが無いのでコードで設定してあげないと駄目
  • 処理関数の順番が変わっており、エラー時に呼ばれる OnFail 関数を追加してあげないと駄目
  • Conversation はライブラリ移行中のためか違う形式の値を渡してきて、変換が必要

などなど、わりと苦労がありました。

ま、でも楽しかったのでモーマンタイですw

なお私が修正で加えたコードの著作権は放棄しますので、サンプルコードの扱いは元の developerWorks 記事 と同じでかまいません。

ではでは。

8
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
7