2016年7月14日木曜日

Chromeとnode.jsでりんなと会話する

Chromeの音声認識と合成音声、それにnode.jsのモジュールであるsocket.ioを使って、マイクロソフトのAIりんなとTwitterを介して会話してみる。ツイートとりんなからのリプライの取得にはTwitterのAPIでできるが、ここではnode.jsでTwitter APIを利用できるtwitを使う。大まかな流れとしては、Chromeで自分の発音を音声認識してテキストに変換し、それをsocket.ioでnode.jsサーバに送る。node.jsサーバからりんなにツイートし、りんならリプライがきたらそれを受け取り、socket.ioでChromeに送る。Chromeはりんなのリプライを受け取ったら、音声合成の機能で再生する。以下、次の手順で進める。

1.Twitter APIの利用設定

2.node.jsと必要なモジュールのインストール

3.サーバサイドのコーディング
・りんなのツイートを取得してブラウザへ送信する
・ブラウザから受信したテキストをツイートする

4.クライアントサイドのコーディング
・サーバから受信したツイートを音声再生する
・音声認識でツイート内容とテキストにしてサーバに送信する

5.りんなと会話

Twitter APIの利用設定

ツイートとツイートの取得にはnode.jsのモジュールであるtwitを利用するが、このモジュールはTwitter APIを使用しているので、Twitter APIの使用申請をする必要がある。Twitterのアカウントを作成したら、電話番号を登録しておく(電話番号を登録しておかないとAPIの申請はできない)。申請はTwitterの開発者向けのページから行う。ページを開いたら、「Manage Your Apps」、「Create New App」の順で進めていくと申請ができる。申請が完了したら、「Keys and Access Tokens」、「Create my access token」の順でメニューを開き、APIキーとトークンを取得する。

後で必要になるので以下の4つをメモしておく。
・Consumer Key (API Key)
・Consumer Secret (API Secret)
・Access Token
・Access Token Secret

node.jsと必要なモジュールのインストール

ubuntuの場合の手順は以下の通り。

node.jsに加えてモジュールのインストールに使うnpmもインストールする。


インストールするとnode.jsのコマンド名はデフォルトではnodejsになっているので、シンボリックリンクを作成してnodeで実行できるようにする。


socket.ioとtwitのインストール。


サーバサイドのコーディング

サーバサイドで行うことは主に以下の2つ。

①りんなのツイートを取得してブラウザへ送信する
②ブラウザから受信したテキストをツイートする

socket.ioとtwitを組み合わせて使うことになるが、socket.ioについてはsocket.ioでブラウザ双方向通信をするで説明しているので、twitの部分だけここでは記述する。①のコードは以下のようになる。
// twitモジュールの読み込み
var Twit = require('twit');

// Twitter API申請時に取得した4つのトークンを設定する
var tw = new Twit({
  consumer_key: 'xxxxxxxxxx',
  consumer_secret: 'xxxxxxxxxx',
  access_token: 'xxxxxxxxxx',
  access_token_secret: 'xxxxxxxxxx',
  timeout_ms:           60*1000,
});

// りんなのユーザIDを設定
var targetID = '3274075003';
// 自分のユーザID
var myID = '';

// followに取得したいユーザのIDを指定する
var stream = tw.stream('statuses/filter', {'follow': targetID} );
stream.on('tweet', function ( data ) {
  // 結果(data)はJSON形式
  // りんなからのリプライにしぼる
  if( data['user']['id_str'] === targetID && data['in_reply_to_user_id_str'] === myID ) {
    // @スクリーンネームを取り除く
    var message = data['text'];
    while( message.indexOf('@') != -1 ) {
      message = message.substr( message.indexOf(' ') );
    }
    console.log( message );

    // ここでsocket.ioでブラウザにりんなのツイート(message)を送る
  }
});

上記で設定しているユーザIDはstring型を使う。TwitterのIDについてはTwitterの開発者向けサイトを参照。

②のコードは以下のようになる。socket.ioでChromeからツイートするテキストを受け取ったら、twitでツイートする。りんな向けのツイートなので、@ms_rinnaではじめる。
// ここでsocket.ioでブラウザからツイートするテキスト(message)を受け取る

// statusにツイートするメッセージを指定する
tw.post('statuses/update', { status: '@ms_rinna ' + message }, function( err, data, response ) {
  console.log(data)
});


クライアントサイドのコーディング

クライアントサイドで行うことは主に以下の2つ。

①サーバから受信したツイートを音声再生する
②音声認識でツイート内容をテキストにしてサーバに送信する

socket.ioとWeb Speech APIを組み合わせる。①はsocket.ioとChromeの合成音声によるテキスト読み上げ機能(SpeechSynthesis)を使う。SpeechSynthesisについてはブラウザの音声合成でテキスト読み上げを行う。②はsocket.ioとChromeの音声認識(SpeechRecognition)を使う。SpeechRecognitionについてはChromeの音声認識を使う

全体のコード

上記を元にして作ったデモをgithubで公開。りんなと会話するには以下の箇所を変更する。

server.jsの変更

Twitter APIの4つのトークンとりんなのIDを設定
// Twitter APIの4つのトークンを設定
var tw = new Twit({
  consumer_key:         '',
  consumer_secret:      '',
  access_token:         '',
  access_token_secret:  '',
  timeout_ms:           60*1000,  // optional HTTP request timeout to apply to all requests.
});

// りんなのIDを設定
var targetID = '3274075003';

index.htmlの変更

Web Speech APIに日本語を設定し、女子高生っぽい声になるように速度と音程を少し上げる。
var options = {
  // Voice:0-19
  voice: 11,
  // Language
  lang: 'ja-JP',
  // Volume: 0-1.0
  volume: 1.0,
  // Rate: 0.1-10.0
  rate: 1.2,
  // Pitch: 0-2.0
  pitch: 1.3
};
var speechSynth = new SpeechSynth( options );

var speechRec = new SpeechRec( 'ja-JP' );

りんなと会話してみる

server.js、speech.js、index.htmlをnode.jsサーバにコピーして、以下のコマンドで実行する。


Chromeでサーバ(サーバのIPアドレス:9001)にアクセスすると、Tweetというボタン、自分のユーザ名、りんなのプロフィールが表示される。ツイートするときは、ボタンを押してからマイクに向かって話す。話した内容が認識されると、りんなにツイートされる。りんなからリプライがあれば、自動的にChromeで再生・表示される。

結果は以下の通り。合成音声は棒読みに近いので不自然な感じはあるものの、会話はできる。

既知の問題

  • socket.ioによるブラウザとサーバ間の接続が2つ以上になってしまい、りんなの同じツイートが複数回再生・表示されてしまうことがある。
  • 音声認識が途中で止まってしまうことがある。この場合はボタンをを2回押して音声認識を再開できる。

0 件のコメント:

コメントを投稿