Node.js
Dropbox
Watson
ibmcloud
GoogleHome

Google HomeをWatson Text to Speechの声で喋らせる

このエントリーでは、Google HomeをWatson Text to Speechの声で喋らせる方法を紹介します。

はじめに

ちょまどさんのGoogle HomeにVoice Text APIの男性の声でしゃべらせているツイートを拝見して、Node.jsを使用し、Watson Text to Speechの日本語音声でしゃべらせる方法を試してみました。MP3ファイルの格納場所にはDropboxを使用しています。

セットアップ

まず、Watson Text to Speechのサービス資格情報と、Dropbox APIのアクセストークンを確保します。

Watson Text to Speechのセットアップ

Watson Text to SpeechはIBM Cloudから利用出来ます。IBM Cloudのアカウントが無い方は、期間無制限・無料で使用できるIBM Cloudライトアカウントを申し込んでください。

IBM Cloudダッシュボードにログインした後、Text to Speechのカタログ画面から、LiteプランでText to Speechサービスを作成してください。その後、作成したText to Speechサービスの「サービス資格情報」を新規作成します。作成するサービスがWatson ConversationかWatson Text to Speechかの違いだけで、「IBM Cloudの基本 -サービスの作成から資格情報の取得まで-」というエントリーの手順とほぼ同じですのでそちらも参考にされてください。

以下のような形式のサービス資格情報が確認出来ると思います。後で必要になりますので、こちらの情報を手元にコピーしておいてください。

TTSサービス資格情報例
{
  "url": "https://stream.watsonplatform.net/text-to-speech/api",
  "username": "1234a5bc-6789-0123-d456-78e90f123gh4",
  "password": "ABCdefGHI1jk"
}

Dropbox APIアクセストークンの取得

このエントリーではGoogle Homeに喋らせるのに、google-home-notifierを使用するのですが、その際に合成音声のMP3ファイルをGoogle HomeからHTTPアクセス出来る場所に配置する必要があります。今回は、DropboxにMP3ファイルをアップロードして、そのファイルに共有リンクを設定し、その共有リンクをGoogle Homeに渡すという手順で実現します。そのHTTP APIへのアクセスに必要なトークンをDropboxに発行してもらいます。

DropboxのDeveloper向けサイトを開き、「create your app」→「1. Choose an API: Dropbox API」「2. Choose the type of access you need: App folder」「3. Name your app: WatonGoogleHome(任意)」でアプリケーションを作成し、アプリケーション設定画面のGenerated access tokenという箇所の直下の「Generate」ボタンを実行します。そうするとおそらく64文字のアクセストークンが発行されますので、それを手元にコピーしておいてください。

Dropboxアクセストークン例
ARayX1WpPp9t7uN3aDAFBVI_CUwbb7T0eWws4L_txqgR9LpQunZY1EYXGHtDZrl1

Node.jsのセットアップ

今回はNode.jsをクライアント上で動作させ、Watson Text to Speechと連携して任意のテキストを音声合成してMP3ファイルを生成し、そのMP3ファイルをDropboxにアップロードして、その共有リンク情報をGoogle Homeに渡すことで、Google Homeに喋らせます。

Node.js自体のインストール・セットアップ手順は省略します。今回はgoogle-home-notifierとwatson-developer-cloudを使用しますので、パッケージをインストールしておいてください。

$ npm install google-home-notifier
$ npm install watson-developer-cloud

サンプルコード

今回は以下のindex.js、script.txt、sharedlink.conf(全て同じパスに配置)を利用してGoogle Homeを操作します。script.txtは喋らせたい言葉を記述するファイルで、sharedlink.confはDropbox上に配置したファイルを共有リンクのURL情報を保管するファイルです(最初は空ファイルです)。script.txtには仮で「こんにちは、ワトソンです。」と記述していますが、お好きな言葉に変更してください。

index.js
var request = require('request');
var fs = require('fs');

// しゃべらせる言葉はscript.txtに記述する
var script = fs.readFileSync('script.txt','utf-8');

// Google Home
var googlehome = require('google-home-notifier');
var language = 'ja';
var devicename = 'Google-Home';
googlehome.device(devicename, language);

var TextToSpeechV1 = require('watson-developer-cloud/text-to-speech/v1');

// Watson Text to Speech
var textToSpeech = new TextToSpeechV1({
  username: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
  password: 'xxxxxxxxxxxx',
  url: 'https://stream.watsonplatform.net/text-to-speech/api/'
});

var params = {
  text: script,
  voice: 'ja-JP_EmiVoice', // https://www.ibm.com/watson/developercloud/text-to-speech/api/v1/#get_voice
  accept: 'audio/mp3'
};

// Dropbox
var token = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';
var sharedlink = fs.readFileSync('sharedlink.conf','utf-8');
var filename = '/watson.mp3';

/* 関数定義 */
// playSound: Google Homeに任意のURLのMP3ファイルを再生させる
function playSound(sharedlink) {  
  googlehome.play(sharedlink, function(res) {
    console.log(res);
  });
}

// ttsThenUpload: Text to Speechで音声ファイルを取得し、dropboxにアップロードする
function ttsThenUpload() {
  textToSpeech.synthesize(params, function(err, audio) {
    if (err) {
      console.log(err);
      return;
    }
    request.post(
      {
        url: 'https://content.dropboxapi.com/2/files/upload',
        body: audio,
        headers: {
          "Authorization": "Bearer " + token,
          "Dropbox-API-Arg": "{\"path\": \"" + filename + "\" ,\"mode\": \"overwrite\",\"autorename\": false,\"mute\": false}",
          "Content-Type": "application/octet-stream"
        }
      }, (error, response, body) => {
        if (error) {
          console.log(error);
        } else {
          if (process.argv[2] == "--INITIALIZE") {
            getSharedLink();
          } else {
            playSound(sharedlink);
          }
        }
      }
    );
  })
}

// getSheredLink: dropboxの共有リンクを新規作成する
function getSharedLink() {
  request.post(
    {
      url:'https://api.dropboxapi.com/2/sharing/create_shared_link_with_settings',
      body: "{\"path\": \"" + filename + "\" ,\"settings\": {\"requested_visibility\": \"public\"}}",
      headers: {
        "Authorization": "Bearer " + token,
        "Content-Type": "application/json"
      }
    }, (error, response, body) => {
      if (error) {
        console.log(error);
      } else {
        obj = JSON.parse(body);
        if (obj["url"] == undefined ) {
          playSound(sharedlink);
        } else {
          // 共有リンクのオプションを変更する https://www.dropbox.com/ja/help/desktop-web/force-download
          sharedlink = obj["url"].replace('dl=0', 'raw=1');
          fs.writeFileSync('sharedlink.conf', sharedlink);
          playSound(sharedlink);
        }
      }
    }
  );
}

/* メイン処理 */
if (process.argv[2] == "--PLAYONLY") {
  // dropbox上の音声ファイルをGoogle Homeに再生させるだけ
  playSound(sharedlink);
} else {
  // dropbox上の音声ファイルを更新し、Google Homeに再生させる
  ttsThenUpload();
}
script.txt
こんにちは、ワトソンです。
sharedlink.conf
(空ファイル)

index.jsの中で、Text to Speechに接続する情報を指定する箇所(17行目、18行目)と、Dropboxのアクセストークンを設定する箇所(29行目)がありますので、上記で確認したText to Speechのサービス資格情報とDropbox APIアクセストークンの値に変更しておきます。

index.js(修正箇所抜粋)
// Watson Text to Speech
var textToSpeech = new TextToSpeechV1({
  username: '1234a5bc-6789-0123-d456-78e90f123gh4', //←変更
  password: 'ABCdefGHI1jk', //←変更
  url: 'https://stream.watsonplatform.net/text-to-speech/api/'
});

// dropbox
var token = 'ARayX1WpPp9t7uN3aDAFBVI_CUwbb7T0eWws4L_txqgR9LpQunZY1EYXGHtDZrl1'; //←変更

Node.jsアプリケーションの実行

コードの準備が出来ましたのアプリケーションを実行します。なお、初回実行時のみDropbox上にアップロードしたMP3ファイルの共有リンクを新規作成する処理が必要になりますので、初回実行時は引数に「--INITIALIZE」を付けて実行してください。以降は引数を付けることは必須ではありません。

なお、前回実行時と同じ言葉(script.txt)を喋らせるだけであれば、Text to Speechに音声ファイルを新規合成してもらう必要はありませんので、「--PLAYONLY」を付けて実行すると、音声ファイル合成処理はスキップして、Google HomeがDropbox上のMP3ファイルの再生だけをしてくれます(この場合、Dropbox上のMP3ファイルを直接上書きすれば、Text to Speechによる合成音声以外の任意のMP3ファイルをGoogle Homeに再生させることも可能です)。

Node.jsアプリケーションの実行
$ node index.js --INITIALIZE
Device "Google-Home-YRAvyTSkegoQ6JXFnOImsINdl3jiSy4f" at 192.168.0.x:8009
Device notified
$ node index.js
Device "Google-Home-YRAvyTSkegoQ6JXFnOImsINdl3jiSy4f" at 192.168.0.x:8009
Device notified
$ node index.js --PLAYONLY
Device "Google-Home-YRAvyTSkegoQ6JXFnOImsINdl3jiSy4f" at 192.168.0.x:8009
Device notified

以上のように実行することで、Google HomeをWatson Text to Speechの声で喋らせることが出来ました。