今日のつちや

お疲れ様でした

Google HomeでTech系Podcastを聞く(Dialogflow + Cloud Functions編)

こんにちは、@corocnです。 今回は音声認識マンらしく話題のGoogle Homeを触ってみました。

Misoca Advent Calendar 2017 - Qiita の14日目の記事になります。

はじめに

最近は、Google HomeでTech系のPodcastを雑に聞きたいなぁという欲求があって、色々と試しています。

現状考えられるアプローチとして3つありまして

  1. Google Play Musicに音源を放り込む
  2. 専用のストリーミングサービスを作る
  3. Dialogflow + Cloud Functionsで音源を再生する (今回の記事)

1はコレじゃない感、2はそもそもが作り方が謎でして、「キーワードに反応して特定の音源が再生できれば何でもできるやろ」ということで、3番目を試した記事になっています。IFTTTは使いません。

rebuild.fmが聞きたいのが始まりだったのですが、Google Homeで再生可能な音源なら何でも適用できるはず。

既に色んな方がDialogflowの解説記事を出してくれていますが、それらを見た上でハマったポイントも掲載して、初心者向けチュートリアルしてまとめてみました。

Dialogflow

f:id:corocn:20171211215525p:plain

対話ボットを簡単に作成できるサービスになります。 自然言語対話プラットフォーム「API.AI」が、Googleに買収されたことで、名前を変えました。

https://dialogflow.com/

Dialogflowでは、プロジェクトを「Agent」という単位で管理します。以下の機能を使ってボットを作ります。

  • Entities: 会話に含まれるキーワードを定義
  • Intent: 会話の流れを定義
  • Fulfillment: SSML(後述)を生成するサーバーをWebhookで指定
  • Integrations: デプロイ

※ この先、Googleから許可を求められたら内容を確認の上、承諾して進めてください

Agent

左上のCreate new agentから作成できます。

f:id:corocn:20171211213728p:plain

作成画面が出るので、諸々の情報を入力してください。今回はpodcast-playerという名前にしてます。

V2 APIはbetaなので、今回はV1で試します。有効にしないでください。 (´-`).。oO(今度V2 APIの解説も書けたらいいな...)

f:id:corocn:20171211213744p:plain

Entities

Agentの作成ができたところで、Entitiesを定義していきます。

@podcast_name を @action して

という文章で実行する予定ですが、@podcast_name, @actionがEntityになります。それぞれキーワードと言い換え語を入力します。

f:id:corocn:20171211213801p:plain

f:id:corocn:20171211213813p:plain

f:id:corocn:20171211213825p:plain

登録できました。

Intent

Entitiesが定義できたので、Intentを作成します。 ちょっとクセのあるUIですが、

まず「podcast_nameをactionする」と入力して追加

f:id:corocn:20171211213837p:plain 追加された1文のEntityをマウスで範囲選択するとキーワードを適用できます。@podcast_nameでフィルタすると早いですね。@actionも同様です。

f:id:corocn:20171211213855p:plain 紐付けが終わるとUser saysとActionが自動で埋まります。

いくつかパターンを定義していきます。

f:id:corocn:20171211213910p:plain

保存の前にActionを必ず入力してください。 忘れがちですが、入れておかないと今後の処理で困ります。「play.podcast」にでもしておきます。

f:id:corocn:20171211213923p:plain

これで保存して完了です。

Fulfillment

最後にWebhookの設定をしたいのですが、この段階ではレスポンスを返す環境を用意してないので、適当なdummyにしておきましょう。

保存後、先ほど作成したIntentを見ると、ページの下部にFullfillmentの設定が追加されているはずなので、Webhookを有効にしておきましょう。

f:id:corocn:20171211213932p:plain

f:id:corocn:20171211213940p:plain 保存をお忘れなく。

SSML with Cloud Functions

Google HomeはSSML(Speech Synthesis Markup Language)という形式に対応しており、特定のキーワードに反応させて別途用意したサーバーからSSMLを返すことで、任意の発話やアクションを実行することができます。

今回はCloud Functionsを使って、簡易的なレスポンスサーバーを用意して試します。

SSML

詳しい文法は OfficialActions on Google(Google Home)で使用できるSSMLタグのまとめ | KOTODAMA TODAY を見ると良いと思います。

とりあえず凝ったことはせず、固定のURLの音源を再生する方針で進めます。

<speak>
 リビルドエフエムを再生します。
 <audio src="https://hoge/sample.mp3/"/>
</speak>

srcはHTTPSのみ対応しているので注意してください。

上記例では、sampleにしていますが、テスト時はS3とかCloud Storageに雑にファイルを置いて試していました。直リンでやると怒られると思いますので、自分で用意してみてください。

サンプルサーバー

以下をクローンして、functions/index.jsを書き換えます。 https://github.com/actions-on-google/dialogflow-webhook-template-nodejs

'use strict';

process.env.DEBUG = 'actions-on-google:*';
const { DialogflowApp } = require('actions-on-google');
const functions = require('firebase-functions');

exports.yourAction = functions.https.onRequest((request, response) => {
  const app = new DialogflowApp({request, response});
  console.log('Request headers: ' + JSON.stringify(request.headers));
  console.log('Request body: ' + JSON.stringify(request.body));

  // Fulfill action business logic
  function responseHandler (app) {
    // Complete your fulfillment logic and send a response
    app.tell({
      speech: '<speak>リビルドエフエムを再生します。<audio src="https://hoge/sample.mp3"/></speak>',
      displayText: 'さいせい'
    });
  }

  const actionMap = new Map();
  actionMap.set('play.podcast', responseHandler);

  app.handleRequest(actionMap);
});

app.tellのspeechのvalueにSSMLを直接記述できます。

actionMap.setのキーを、Intentで設定したaction名に変更することをお忘れなく。

また、サンプルのmp3は適宜書き換えてください。

Deploy Webhook

firebase へでデプロイします。

firebase-toolsが必要なので、この辺を参考に入れると良いです。 https://firebase.google.com/docs/hosting/deploying?hl=ja

以下のコマンドを順に実行して、deployします。

# functions以下でnpm install or yarn installが必要
$ cd functions
$ yarn install
$ cd ..

# firebaseへログイン
$ firebase login

# firebaseを初期化
$ firebase init

? Which Firebase CLI features do you want to setup for this folder? Press Space to select features, then Enter to confirm your choices.
> ◯ Functions: Configure and deploy Cloud Functions

? Select a default Firebase project for this directory:
> podcast-player

✔  Firebase initialization complete!

# deploy実行
$ firebase deploy --only functions

Function URL (yourAction): https://us-central1-xxxxxxxxxxxxxx.cloudfunctions.net/yourAction

✔  Deploy complete!

最後にfunction URLを教えてもらえるので、コピっておきます。 なお、そのまま叩くと「Action Error: no matching intent handler for: null」というエラーが出ますが、正常です。

Fulfillmentを修正する

ここでDialogflowのFullfillmentへ戻って、dummyのURLを、先ほど生成したFunction URLへ変更しておきましょう。

f:id:corocn:20171211214001p:plain

Integration

さてさて、準備が整ったので、DialogflowのIntegrationsから、Google Assistantを選択してテスト環境へ反映していきましよう!

といっても、Additional triggering intentsで、作成したintentsを選択し、UPDATE DRAFTを押すだけです。

f:id:corocn:20171211214010p:plain

「Actions on Google draft successfully updated」と表示されたら成功です。VISIT CONSOLEからアプリの管理ページへ飛べます。

テストしてみる

諸々準備が終わったので、実際に動かしてみます。

Assistant app

VISIT CONSOLEを押すとAssistant app draftに飛んでくるはずです。

② App InformationのEditを押して、Assistant app nameと、その発音を入力します。 ここで入力した情報を用いて、Google Homeからアプリを呼び出します。

f:id:corocn:20171211214020p:plain

すごく適当ですが、こんな感じです。Pronunciationが他のアプリと被ると怒られます。

保存したら、1個前のページに戻ってください。入力が足りない的なエラーが出ているかもしれませんが、本申請するわけではないので、気にしないでおきましょう。

ページ下部のTEST DRAFTボタンでシミュレーターを起動します。

シミュレーターテスト

少しハマったポイントです。 本来なら、以下のようなやりとりをすると音源が再生されるはずなのですが、現状シミュレーターだと上手く動かないようです。

f:id:corocn:20171211214030p:plain

VALIDATION ERRORSに、 「UnparseableJsonResponseAPI Version 2: Failed to parse JSON response string with 'INVALID_ARGUMENT' error: ": Cannot find field.".」と表示されていました。どうやらV2 APIの形式でリクエストを投げているようで、シミュレーター上でV1 APIで試す方法がわかりませんでした。設定があるのかもしれませんが、よく分からず。

実機テスト

シミュレーターで動かなかったので、実機で動かしてみます。 自身のGoogleアカウントと紐付いている状態ですので、Google Homeから先程作成したテスト用アプリを実際に立ち上げることができます。

注意: 動画を再生すると、あなたのGoogle Homeが反応するかもしれません

上記動画ではs3にテスト用として置いたrebuild.fmのmp3音源を再生しています。 途中に長い無音区間が入っているのは、音声をロードしているためです。サイズが80MBほどあって、完全に読み込むまで再生が始まらないのが微妙ですね。

また、Play Musicのような音楽再生ではないので、1回停止すると再開できません。不便だ。。

まとめ

汎用性のないままこの記事は終わりますが、Dialogflow + Cloud Functionsで特定のURLの音源を再生してみました。

もう少し応用すればいい感じにできるんじゃないかな〜?と思ってますが、シークや途中再生が困難なので、PlayMusicにぶっこんだほうが便利なんじゃないのこれと思っています。

Cloud Functionsでゴニョれるので、なんでもできそうですね。今後も色々試してみようと思います。

GDCR17に参加してペアプロでLifegame作ってきた

こんにちは、@corocn です。 今年もAdvent Calendarの季節になってきました。今回はMisoca Advent Calendar 2017 の記事として書くことにします。

最近は、Teletype for AtomVisual Studio Live Share、AWS Cloud9などが発表されて、ペアプロの高まりを感じている今日このごろです。 今回は、2017/11/18に開催されたCodeRetreat @ 名古屋ギークバーに参加してきましたので、感想をつらつらと書こうかなと思います。

どんなイベント?

Lifegameを題材としたペアプロのイベントです。

実は夏頃にも同様のイベントに参加して、会社の開発ブログに参加報告を書きましたので、ルールなどは下記ブログを参照していただきたいです。

CodeRetreatに参加しました! 〜ペアプロのすゝめ〜 - Misoca開発ブログ

今回は、Global Day of Coderetreat 2017(GDCR2017) に参画していて、世界中で同時開催されるCoderetreatの1つとして開催されたのが特徴でした。

f:id:corocn:20171128212724j:plain

ルール説明中の写真です。

使用言語

私はRubyメインで参加しました。 参加者の使用言語の割合は、C#, Ruby, JavaScriptな感じでしたね。 特異な例としてExcel VBAがありました(後述) Lifegame初めて、ペアプロ初めて、という人が多くて慣れるまで時間がかかるようなイメージでした。

ご飯

会場のAdrianaさんは飯がうまい。スポンサー様ありがとうございます。 f:id:corocn:20171128212904j:plain

Excel VBA での発見

最初に組んだペアに合わせてExcel VBAで書くことになったのですが、これがなかなか面白かったです。 Excel!? VBA!? ウワッっと思うかもしれませんが、実は凄く良かったんですよ。(仕事で使うのはイヤですが)

Lifegameを書く時、私は以下のようなステップで実装することが多いです。

  1. セルのデータ構造を考える
  2. 初期値を適当に入れてみる
  3. 画面に描画する
  4. 次世代を計算するロジックを書く
  5. 計算した次世代を現在の世代として更新する
  6. ループして描画する

で、1セッションが45分なんですけど、初めてLifegameを書く人はルールを把握したいから4のロジックを書きたいのに、3の描画までで終わっちゃう人が多いんですよね。

しかしExcel VBAを使うと、

  1. セルのデータ構造を考える → エクセルのセルをそのままセルとして扱えば良い
  2. 初期値を適当に入れてみる → 黒く塗り潰した部分を生存としてすれば、初期値は塗るだけで良い
  3. 画面に描画する → できてる
  4. 次世代を計算するロジックを書く → ここを考えるだけでいい
  5. 計算した次世代を現在の世代として更新する → 複数シートをバッファとしてスワップすればできる
  6. ループして描画する → ロジックをループさせるだけ

ということで、ロジックを書くことに集中して、ざっくり雰囲気を掴んでもらうことができます。 初期値の設定も楽なので、色んなパターンを試してもらうこともできますね。

ペアの方が諸々初めての方でしたので、これで雰囲気掴んでもらうことができました。 そのペアは次セッションでGoogleのSpredsheetを使って実装していましたが・・・どうなったんだろう。

ツイートしたらお褒めの言葉を頂きました。

まとめ

5セッション脳みそフル回転で、結構ハードで疲れるイベントですが、楽しかったです。 次回はファシリテーションやってみようかなぁ。

明日は@eitoballさんがNGK2017の報告を書いてくれるようです。 参加したかったけど用事で参加できなかったので、楽しみにしています。

氷見で寒ブリを食らう

こんにちは、ころちゃん です。

どうしようもなく、寒ブリが食べたくなったので、寒ブリの聖地、富山/氷見まで行ってきました。 岐阜から富山まで高速で約3時間ぐらいです。意外と近いですね。

道中の、ひるがの高原SAは、ひるがの高原牛乳を使ったソフトクリームが抜群に美味いので、オススメです。 このクソ寒いのにソフトクリームを食べてる人が多くて笑います。

11月下旬なので、雪景色が見えますね。

昼飯

きときと寿司という回転寿司屋があるのですが、新鮮で美味い寿司が安く食べれます。

f:id:corocn:20171125172119j:plain

氷見きときと寿し 氷見本店 (ひみきときとずし) - 島尾/回転寿司 [食べログ]

夕飯

ブリしゃぶで有名なお店に行きました。食べログで雑に選んでます。

f:id:corocn:20171125172344j:plain

ひみ浜 (ひみはま) - 氷見/魚介料理・海鮮料理 [食べログ]

f:id:corocn:20171125172716j:plain

ブリ、ありました。 今回は1万〜1.3万円のコースです。値段は日によって変動するみたいです。

f:id:corocn:20171125173007j:plain

イワシ、バイ貝、イカの黒づくりなど

f:id:corocn:20171125173225j:plain

メインといっても過言ではないレベルの刺し身 この日のブリは11.3kgだったようです。

写真だと大きさが分かりにくいですが、巨大です。 そのへんの居酒屋の刺し身の5倍ぐらい。 左側が背中、右側がお腹だそうです。

f:id:corocn:20171125173648j:plain

塩焼きです。写真がドヘタクソですね。 油がすごいので、大根おろしには醤油をかけず、箸休めとしていただきます。

f:id:corocn:20171125173843j:plain

ぶり大根です。目玉まで、ほぼ全部食べてしまえます。 ブリしゃぶが控えているので、お腹いっぱいにならないよう気をつけて!と言われました。

鰤しゃぶ

本日のメインです。

これを!

f:id:corocn:20171125174152j:plain

これでしゃぶって!

f:id:corocn:20171125174235j:plain

こう!

f:id:corocn:20171125174248j:plain

うますぎる・・・

この後、氷見うどんとデザートのバニラアイスをいただきましたが、 お腹いっぱいで写真撮影を忘れました。

まとめ

氷見のブリは格が違う!

寒ブリのシーズンはこれからですが、美味しくいただけました。 ごちそうさまでした。

Google Home + Google Play Music 音声コマンドの日本語チートシート

ようやくGoogle Homeが日本でも発売されました。 私も買いました。

f:id:corocn:20171010214717j:plain:w400

Google Play Musicのユーザーなので連携をイイ感じにやってもらいたいのですが、 何て喋ったら良いのか分からないので、用途別のコマンドチートシートを作ってみました。

すべて「OK, Google」を先頭に発話します。

したいこと 発話 コメント
楽曲再生 音楽を再生 1曲だけ謎サジェストされる
曲名やプレイリスト名等から再生 <名称> を再生 カテゴリを一緒に言ったほうが認識しやすい
プレイリストを再生 <プレイリスト名>のプレイリストを再生 一番使ってる
アーティスト指定で再生 <アーティスト名>を再生
ラジオミックスを再生 <アーティスト名>のラジオを再生
ステーションを再生 <ステーション名>のステーションを再生 ステーション名なんて覚えられん
ジャンルを再生 - 再生に成功しない...
シャッフル (〜をランダム再生と発話)
ランダム再生を始める ランダム再生 次のトラックからシャッフル再生
止める 停止, 止める
再開する 再生, 再開する
次の曲 次の曲
曲をスキップ
シャッフルせず次へ
前の曲 前の曲
ミュート ミュート
音量を上げる 音量を上げる
音量を下げる 音量を下げる
音量を指定する 音量 <数字> 例: 音量 サン
再生中の曲名を聞く なんて曲? アーティスト名と曲名を教えてくれる
お気に入り 高評価, 高く評価

多分これ以上あると思うけど、日々使いそうなのはこんなところな気がします。 流し聞きすることが多いので、ステーションをもうちっといい感じに選択できるといいですね。(ステーション名なんて覚えれないし・・・)

間違いがあれば @corocn までご連絡くださいまし。

参考: 英語版 Plays incorrect song/playlist/artist/album - Google Home Help

Vue.jsのコードネームが面白い

こんにちは、@corocn です。

Nagoya.js #3もくもく会で、Vue.jsのコードネームが面白いという話で盛り上がってました。

日本のマンガやアニメにちなんだ名前が採用されています。

version code name original
2.5 Level E レベルE
2.4 Kill la Kill キルラキル
2.3 JoJo's Bizarre Adventure ジョジョの奇妙な冒険
2.2 Initial D 頭文字D
2.1 Hunter X Hunter Hunter x Hunter
2.0 Ghost in the Shell 攻殻機動隊
1.0 Evangelion エヴァ
0.12 Dragon Ball ドラゴンボール
0.11 Cowboy Bebop カウボーイビバップ
0.10 Blade Runner ブレードランナー
0.9 Animatrix THE ANIMATRIX

※間違いがあるかも

以下にもまとまっていますね。

https://github.com/egoist/always-bet-on-vue

v2.4はここで予想されているみたい。 アルファベット順なので次は「K」が採用されますが、キルラキルにbetが集まってますね。

f:id:corocn:20170603213111p:plain

個人的に、かずぽん氏がカイジ推しで面白かった。

IPv6/IPoE + DS-Lite で超捗った

こんにちは。

最近、はてブIPv6の記事を見ましたが、タイムリーな話だったので自分のブログにも書きます。

最終的な結果ですが、以下の速度がピークタイムでも安定して出るようになりました。

下り: 40Mbps → 370Mbps

上り: 250Mbps → 270Mbps

blog.amedama.jp

フレッツ遅い

この春引っ越しをしまして、フレッツ光ネクストの隼を使い始めました。 (正確には実家に帰った)

このど田舎にもようやく1Gbpsが来たかーと心踊らせながら回線測定をした結果ですが、 下り: 40Mbps、上り: 250Mbpsと、やはり下りが遅かったです。

一般的なIPv4 PPPoEで接続する場合、プロバイダの終端装置がボトルネックになって速度が低下します。 俗に言う「ピークタイムで遅い」問題はこれです。有名プロバイダを使用すると、当然利用者が多いので、終端装置は混み合います。

IPv4 over IPv6 で終端装置を迂回する

そこで、プロバイダのPPPoE終端を迂回する方法があります。 それがIPv6/IPoEです。IPv6はざっくり2種類ありまして、

前者は、結局IPv4で通信を行うため、終端を迂回できませんので、後者を利用します。

利用するまで

プロバイダは、モニターキャンペーンのお誘いがあったので、ZOOT NATIVEを利用することにしました。

フレッツに申し込む

フレッツ光ネクストフレッツ光ライトが開通している場合はOKです。

プロバイダにIPv6/IPoEの申し込みをする

フレッツ・v6オプションへの加入も同時にしましょう。

対応ルータを用意する

IPv4 over IPv6の方式は、DS-LiteだとかMAP-Eだとか複数存在するので、契約するプロバイダの方式にあったルータを買う必要があります。

ZOOT NATIVE の場合、バッファロー系を買っておけば安定かと思います。

ZOOT NATIVE対応ルーター一覧

私はモニターになる際にWXR-1750DHPを提供いただけましたので、これを使ってます。 お財布に余裕が出てきたら、 WXR-2533DHP2を買おうと思っています。

ルータを設定する

詳しい設定方法は、以下を見ると良いです。

バッファロー製ルーターの設定マニュアル(WXR-1900DHP2/WXR-1750DHPなど)

なお、私の場合は、Internet -> IPv6から、「NDプロキシを使用する」にチェックを入れる必要がありました。

f:id:corocn:20170416001143p:plain

接続確認する

f:id:corocn:20170416001235p:plain

無事接続されました

以下のサイトで、ちゃんとIPv6になっているかのチェックができます。

http://ipv6-test.com/

f:id:corocn:20170416001526p:plain

いい感じ。

f:id:corocn:20170416002002p:plain

Radish Network Speed Testing Ver. 5.2.2 β

速度も十分です。

まとめ

  • 回線をIPv6/IPoE + DSLiteに切り替えました
  • ZOOT NATIVEとバッファローのルータを使用しました
  • 安定した速度が出るようになりました

まだまだ対応ルータの選択肢が少ないのと、自宅サーバを外部に公開することが困難になりますが、 速度で困っている場合は、試してみる価値はあると思います。

React ビギナーズガイド

最近出たReact本、Reactビギナーズガイドを買ってみました。

f:id:corocn:20170324221819j:plain

簡単な感想です。

良いところ

  • React周辺のライブラリやツールを浅く広く扱ってあり、LintやTestまでざっくり把握するのなら良い

悪いところ

  • 内容が少し古め。yarn、webpackは出てこない
  • 4章のJSXまでがとにかく長く感じた。JSXなしの記述で延々説明されてるので、読んでると疲れてくる
  • サンプルコードありきで説明が書かれているので、じっくり読まないと分からないと思う(自分はサンプルコードは落とさず読んだ)

この本の内容が理解できるなら、チュートリアルなどをコツコツ進めて勉強したほうが良い気がする。 星3/5ってところです。

誰か、Reactアンチパターン的な本出してくれないかな。Reactというより、SPAアンチパターン

Reactビギナーズガイド ―コンポーネントベースのフロントエンド開発入門

Reactビギナーズガイド ―コンポーネントベースのフロントエンド開発入門