Node-REDを使ってAlexaスキルを創る
この記事は ADVENTARの 「するめごはんのVUI・スマートスピーカー Advent Calendar 2018」 の10日目の記事です。
以前、Alexaスキルを作るツールとしてNOIDについてこのアドベントカレンダーで触れました
今回は同じくツールとしてNode-REDを使って挨拶スキルを作ります。
作り方
作り方と言っても、Qiitaや個人ブログ等に情報はあふれていると思います。
今回は以下の本に従ってみます。
スマートスピーカーアプリ開発入門 3大スマートスピーカー Amazon Echo Google Home LINE Clova対応
1.まずはNode-REDのアカウントを作成
2.次にIBM Cloudのアカウント作成
https://www.ibm.com/cloud-computing/jp/ja/lite-account/
ライトで大丈夫です。
3.IBM Cloudにログイン
ここで、アカウントIDはメールアドレスでログインできます。
4.何も考えないと一部英語になる
本の通りに進めていけば問題ないですが、何も考えないでポチポチやっていくと、画面の一部が英語になります。
が、特に躓くような英単語はないと思います。
5.作成できる画面
商業誌の内容をそのままは書けないのですが、以下のような画面になります。
話しかけられたら、インテントの種類を判別して起動時はLaunchRequestなのでそのまま挨拶をする。 それ以外はインテントの場合分けをswitchをかませて対応を分岐させ、応答を返したらHttpのResponseにつないであげます。
6.Alexa Consoleもほぼ通常通り
Node-REDで作成したインテント名で、挨拶のためのインテントを作成してあげます。
ただし、エンドポイントはLambdaではないので、Node-REDで作成したURLをWebhookとして指定します。
7.後は話しかけるだけ
きちんと動きます。
もし、「応答に時間がかかっている」というエラーになった場合は、Node-REDの画面で、線がすべて結びきれているか確認してみましょう。 JSONの作成はできていても、レスポンスを返すようになっていない場合があります。
まとめ
Node-REDでもスキル作成はできますし、本を参考にすれば、Node-REDもAlexaも初体験だったとしても、ぜいぜい2~3時間で作成できると思います。
※Amazonアカウント作成で躓く場合は別
Alexaのスキルをつくることに特化するならNOIDの方が断然楽だと思います。 ただ、Webhookとして、もっと汎用的にいろいろなことをやりたいとなると、Node-REDは選択肢の1つにはなるのではないでしょうか。
今回は以上です。
AMAZON.SearchQueryでビルドが通らない場合のTips
この記事は ADVENTARの 「するめごはんのVUI・スマートスピーカー Advent Calendar 2018」 の9日目の記事です。
みなさん、SearchQuery使ってますか?
これを使うとユーザーから何かしら話しかけられ、他のIntentに分類できなかった場合、 このSearchQueryが実装されているIntentに割り振られます。
つまり、自由な単語・発話をSearchQueryに対応させたいという発想になりますが、ビルドが通らない場合あります。 今回はそれを 無理やり通す 方法について記載します。
もちろん、各自の自己責任にて。
一般的?の実装方法
SearchQueryはこの「なんでも該当」という強さから、一般的に他の単語と組み合わせて実装します。
例えば以下のように。
●●●と、サーチクエリ と話しかけれた際の●●の部分に用います。
ビルドに通らない場合
ただ、上記のような、「●●とサーチクエリ」のようにやりたくはなく、SearchQueryのみで実装したい場合、ビルドが通らない場合があります。
エラーメッセージは
Sample utterance "{searchQuerySlot} " in intent "SearchQueryIntent" must include a carrier phrase. Sample intent utterances with phrase types cannot consist of only slots.エラーコード: MissingCarrierPhraseWithPhraseSlot
自由度が高すぎて制御されているのではないかと考えています。 なので通常は他の具体的な話しかけ方と組みあわせて使うべきなのでしょう。
それでもビルドしたい場合
他のフレーズは一切いれず、何がなんでもSearchQueryのみ実装して、想定していないユーザーの発話はすべてここに集約したいという場合も存在します。
その場合、以下のようにするとビルドに通ります。
さて、どうやったでしょうか。
答えは 半角スペース + SearchQuery です。
こうすると他のIntentやSlotに割り振られない場合、このように作成したSearchQueryに無理やり分類させることができます。
ご利用は自己責任で
おそらくこれは、不具合に近いバグのような気がします。 仕様といえば仕様なのでしょうが。。。
ともあれ、ユーザーかどのように話しかけられたのかを丸々取得したい等の場合は、このような技で切り抜けることが一応できます。
実際には他のフレーズを組み合わせるべきだとは思いますが、このようなやり方も可能ではあるということを記載してみました。
本日は以上です。
技術書典5にて「スマートスピーカーを遊びたおす本」を執筆し、反響があった話
この記事は ADVENTARの 「するめごはんのVUI・スマートスピーカー Advent Calendar 2018」 の8日目の記事です。
今回は技術書典5にむけて 「スマートスピーカーを遊びたおす本」 を執筆・編集し、頒布後に反響があった話について記載します。
■当日、僕が頒布した本「スマートスピーカーを遊びたおす本」
この本の概要は以下に記載のクラスメソッド社のDevelopersIOに掲載されているので、そちらをご確認ください。
というわけで、僕が記載した章の技術的な話。
本の内容の技術的な話
僕の担当箇所はたまたま1章になりましたが、Echo Spot対応のスキル「ヒロインの告白」の制作プロセスの話です。
本の内容をすべてブログに載せてしまうと、お金を払ってくれた方に申し訳ないので一部のみ記載します。
DynamoDBにputする関数は事前に作成してしまう
僕はDynamoDBにデータを格納する際の形式は自分で決めたい派です。
このアドベントカレンダーの3日目
でも取り上げましたが、SDKをいじるくらい自分で操りたい人です。
なので、今ではPut用のfunctionは共通化して作成してしまっています。
//DynamoDBにputする関数 function putDynamo(params) { console.log("=== putDynamo function ===" + params); docClient.put(params, function (err, data) { console.log("=== put ==="); if (err) { console.log(err); } else { console.log(data); } }); }
2回目以降の起動ユーザーは説明文を省くように実装する
上記のDynamoDBへのPutのfunctionをもちいて、LaunchRequestでの2回目以降の起動ユーザーは、スキルの説明をカットして、告白しても良いかどうかのみを結城琴葉ちゃんが話しかけるようにしています。
これはVUIのデザイン・設計として非常に重要だと僕は考えていて、2回目以降のユーザーは説明文をいちいち聞くのは極めて不快です。
もちろん、スキルの特性にもよりますが、このスキルは告白に対する受け答えをするスキルなので、複雑な操作は不要だと感じています。
また、2回目以降のユーザーでも初回起動時の説明文が流れるように「ヘルプ」では初回起動時のメッセージを流すようにしています。
ちなみに、ここでは余談ですが、僕がスキルを創るときは、ユーザーとVUIアプリケーションの対話の状況によって、「ヘルプ」のメッセージを変更するように実装しています。
// スタート音声 const kotoha_start_01 = '<audio src=\"https://hogehoge/kotoha_start_01.mp3\" />'; const kotoha_start_existuser = '<audio src=\"https://hogehoge/kotoha_start_existuser.mp3\" />'; //中略 const LaunchRequestHandler = { canHandle(handlerInput) { return handlerInput.requestEnvelope.request.type === 'LaunchRequest'; }, async handle(handlerInput) { // Amazonから提供されているTemplate 6を使用 if (supportsDisplay(handlerInput)){ const myImage1 = new Alexa.ImageHelper() .addImageInstance(DisplayImg1.url) // 結城琴葉の画像 .getImage(); const myImage2 = new Alexa.ImageHelper() .addImageInstance(DisplayImg2.url) // 今回はDisplayImg1.urlと同じ .getImage(); const primaryText = new Alexa.RichTextContentHelper() .withPrimaryText('') // 文字を出力させたくなかったのでこの記載 .getTextContent(); handlerInput.responseBuilder.addRenderTemplateDirective({ type: 'BodyTemplate6', token: 'string', backButton: 'HIDDEN', backgroundImage: myImage2, image: myImage1, title: "", textContent: primaryText }); } // 起動時メッセージを一旦、2回目以降の起動ユーザー用に代入 // 初回起動ユーザーで初期化するか迷いましたが、2回目以降のユーザー用に代入 let kotoha_start = kotoha_start_existuser; try{ // DynamoDBにあるテーブルに対して、既に存在するuserIdかどうか検索を実行 const queryItems = await docClient.query({ TableName: "kotohaTable", KeyConditionExpression: "#userId = :userId", ExpressionAttributeNames: {"#userId": "userId"}, ExpressionAttributeValues: {":userId": json_userId} // JSONからuserIdを事前取得しておいた値 }).promise(); try{ // 検索した結果、Items[0]にuserIdが入っているかログ出力を兼ねて確認 console.log("queryItems.Items[0].userId: " + queryItems.Items[0].userId); } catch (err){ // 検索した結果がゼロ件ならばログを出力できず、ここのcatchに分岐 // ここに流れてきた場合は、再生するmp3へのリンクを初回起動のユーザーとして再度代入 kotoha_start = kotoha_start_01; console.log("user Nothing"); // DynamoDBに存在しないuserIdだったため、格納する処理をここから記載 var item = { // JSONから取得しているuserIdをDynamoDBのuserIdとして格納する userId: json_userId }; // DynamoDBに格納する情報をparamsとしてまとめる var params = { TableName: kotohaTable, Item: item }; // DynamoDBに格納する // 本来はここでもエラー処理を入れているが割愛 await putDynamo(params); } } catch(err){ // エラー時の処理を入れているが割愛 } // sessionAttributesに起動後状態に移ったことを示す var sessionAttribute = ''; sessionAttribute = { "STATE": "after_start" }; handlerInput.attributesManager.setSessionAttributes(sessionAttribute); // 起動時の「スマートマキアート」の後に0.7秒の間を開けてから、起動メッセージを流す speechText = kotoha_smartmacchiato + '<break time="0.7s"/>' + kotoha_start; // 再生する内容はmp3のみであるため、speakもrepromtもspeakタグでくくっておく return handlerInput.responseBuilder .speak('<speak>' + speechText + '</speak>') .reprompt('<speak>' + speechText + '</speak>') .withShouldEndSession(false) //セッションを切らないことを明示する .getResponse(); } };
■各方面での反響
1.委託先のCOMIC ZIN 秋葉原店でド正面に平積み
BOOTHさん、とらのあなさん、ZINさんに売れ残った分を委託しておりますが、特にZINさんの扱いがすごすぎまして、秋葉原店の技術書典コーナーにないので店員さんに確認したら、まさかの入り口から入ってド正面のド真ん中に平積みしてもらっていました。
逆に気づかなかったという。。
2.クラスメソッド社のせーのさんが記事にしてくれた
日ごろ、非常に、大変、ものすごく、お世話になっているクラスメソッド社の清野さん(せーのさん)にDevelopersIOの記事として掲載いただけました。
非常にありがたいことです。
■VUIをトータルに勉強できる本「スマートスピーカーを遊びたおす本」を読んでみた。 #Alexa
3.この本をきっかけに商業誌の執筆依頼が出版社から頂く
この本をきっかけに、某スマートスピーカーおよび関連技術に関する商業誌の執筆依頼がきて、契約しました。
4.イベントでめっちゃ感謝された
先日の某イベントに参加していたら、この本と千代田まどか様(ちょまど)のファンの方から熱烈にお礼を伝えていただきました。
その人はGoogle Homeユーザーのようですが、著者としてもそういった声をいただけるのはうれしい限りです。
■アウトプットはいいぞ
というわけで、アウトプットをし続けていると、いろんな人が自分を観てくれます。 もちろんたまにはディスられます。
それでも、アウトプットをし続けることで、多くの人が応援してくれます。
みなさんもブログやイベントの登壇などでアウトプットをしてみてはいかがでしょうか。
以上です。
Alexaが240秒再生可能になったので約4分間告白され続けるスキルを創った
この記事は ADVENTARの 「するめごはんのVUI・スマートスピーカー Advent Calendar 2018」 の7日目の記事です。
Alexaのオーディオファイルの再生時間が90秒から240秒に延びた
この記事を書いている今日、つまり12月6日の Alexa Dev Summit TokyoのAlexaスキルのクイズでオーディオ再生が4分まで対応できるようになった旨が出題されました。
■Alexa Dev Summit TokyoのAlexaスキル https://www.amazon.co.jp/Amazon-Alexa-Dev-Summit-Tokyo/dp/B07KGH1VJ1/
また、smartioさんのツイートでも同様の報告がありました。
mp3のSSMLでの再生時間制限って90秒以内だったはずなのに…。
— smartio (スマートスピーカー楽しいよ) (@smartiolife) 2018年12月5日
いつの間に、こうなった!?https://t.co/VN46XhfBWD
早速、約240秒告白されてみる
とのことなので、早速240秒、つまり4分間何かしらを流そうかと思い、考えた結果、やはり?もってる音声ファイルとしてAlexaスキル ヒロインの告白のうちの告白セリフを連結して3分58秒にしました。
実機テスト通りましたので録画・公開してみました。 なお、何も考えないで動くことのみを目的としたため、結城琴葉ちゃんの表示が遅れたりしています。
ソースコード
たいして何もしてないので、今まで通りです。
とりあえず、LaunchRequestだけ作成して、実機で動くかのみ確かめました。
'use strict'; const Alexa = require('ask-sdk'); //20種類の告白セリフを結合したファイル const kotoha_20 = '<audio src=\"https://s3-XXXXXXXXXXXXXXXXXX.mp3\" />'; //画像 const DisplayImg1 = { title: '結城琴葉', url: 'https://s3-ap-XXXXXXXXXXXXXXXXXXXXX.png' }; const DisplayImg2 = { title: '結城琴葉', url: 'https://s3-ap-XXXXXXXXXXXXXXXXXXXXX.png' }; const LaunchRequestHandler = { canHandle(handlerInput) { return handlerInput.requestEnvelope.request.type === 'LaunchRequest'; }, async handle(handlerInput) { // Template 6 if (supportsDisplay(handlerInput)){ const myImage1 = new Alexa.ImageHelper() .addImageInstance(DisplayImg1.url) .getImage(); const myImage2 = new Alexa.ImageHelper() .addImageInstance(DisplayImg2.url) .getImage(); const primaryText = new Alexa.RichTextContentHelper() .withPrimaryText('') .getTextContent(); handlerInput.responseBuilder.addRenderTemplateDirective({ type: 'BodyTemplate6', token: 'string', backButton: 'HIDDEN', backgroundImage: myImage2, image: myImage1, title: "", textContent: primaryText }); } /////////////////////////////////////////// var hoge = 'さぁ、付き合いますか!?'; /////////////////////////////////////////// let speechText = '<break time="0.7s"/>' + kotoha_20; return handlerInput.responseBuilder .speak('<speak>' + kotoha_20 + '</speak>') .reprompt('<speak>' + kotoha_20 + '</speak>') .withShouldEndSession(false) //本来きちんと対応する .getResponse(); } }; // returns true if the skill is running on a device with a display (show|spot) function supportsDisplay(handlerInput) { var hasDisplay = handlerInput.requestEnvelope.context && handlerInput.requestEnvelope.context.System && handlerInput.requestEnvelope.context.System.device && handlerInput.requestEnvelope.context.System.device.supportedInterfaces && handlerInput.requestEnvelope.context.System.device.supportedInterfaces.Display; console.log("Supported Interfaces are" + JSON.stringify(handlerInput.requestEnvelope.context.System.device.supportedInterfaces)); return hasDisplay; } // LaunchRequestHnadlerより後に書く必要あり exports.handler = Alexa.SkillBuilders.standard() .addRequestHandlers(LaunchRequestHandler) .lambda();
これによりどうなるか
僕個人ですと、もっとキャラクターの表現がしやすくなりますし、ポッドキャストに近いこともできることになります。
90秒は結構厳しかったので、今回の対応はうれしい限りです。
が、4分間告白され続け、終わった後8秒間返答しないと repromptで再度4分間告白される動きを上記のコードだとしてしまいます。
いずれにしろ、この長くなったからといって、やみくもに長いのはユーザーからすると鬱陶しいので、それこそVUIデザインの話になるかと思います。 スキルの特性によって適宜利用していきましょう。
以上
IT業界の光闇のGoogle版
この記事は ADVENTARの 「するめごはんのVUI・スマートスピーカー Advent Calendar 2018」 の6日目の記事です。
先日、このアドベントカレンダーの2日目の記事として、Alexaスキル「IT業界の光闇」について触れました。
■二番目に作成そしてVUILTで初登壇することになった「IT業界の光闇」 https://qiita.com/surumegohan/items/854a8f9cc7f79adf266c
今回は、このスキルのActions on Google版を公開し、今のUIだとどうなっているか記載します。
ログインから
まずは https://dialogflow.com/ を開いて、SIGN UP FOR FREEをポチ。
Googleアカウントでのサインインを求められます。
アカウントアクセスが求められるので、利用するGoogleアカウントで、各種リクエストを許可するか問われます。
Dialogflowに入ると・・
2018年5月に「IT業界の光闇」は作成しましたが、2018年12月5日現在だとこのようなUIになっているようです。
Intentは基本的にAlexaと同じにしています。
Delault-Welcome Intent
とりあえず「ほげほげ」と入力していた痕跡があります。
そして、Responsesも「こんにちは!」だけだったみたいです。
EndIntent
Alexaのストップのように作成していました。
・おしまい ・ストップ ・やめて ・とめて
などが定義されています。
HikariIntent
IT業界の光の話をするためのHikariIntentは以下のようになっています。 これはAlexa版とほとんど同じです。
1.光の話をお願い 2.光にして 3.光 4.光の話で 5.光がいい
などとユーザーが「光の話」を聴きたいときに話しかけるであろうフレーズを書いていきます。
闇の話も同じようなものなので省略します。
hikariIntentの画面の下の方にスクロールしていき、FulfillmentがEnableであることを確認します。 作成時からかなり時間が経っているのでEnableになっていない場合はここで、トグルをオンにします。
fullfillment
fullfillmentをNode.jsのインラインエディタとして扱っています。
ちなみに、このfullfillmentの最終更新日は以下のようです。
書いてあるソースコード
ここで記載しているソースコードは以下のようになっています。
なかなか香ばしい光と闇の話が盛り込まれていますね。
// See https://github.com/dialogflow/dialogflow-fulfillment-nodejs // for Dialogflow fulfillment library docs, samples, and to report issues 'use strict'; const functions = require('firebase-functions'); const { dialogflow } = require('actions-on-google'); const app = dialogflow(); process.env.DEBUG = 'dialogflow:debug'; // enables lib debugging statements var SKILL_NAME = 'IT業界の光闇'; var WELCOME_MESSAGE = 'ようこそ。<break time="800ms"/>IT業界の光と闇の世界へ。このアプリでは、IT業界の光と闇を垣間見ることができます。光と闇。どちらの話を聞きたいですか?<break time="200ms"/>「光」<break time="200ms"/>もしくは「闇」<break time="200ms"/> と話しかけてください。「光」ならIT業界のいい話、<break time="200ms"/> 「闇」ならIT業界のよろしくない話を伝えます。<break time="200ms"/>ヘルプを呼び出したい時は「ヘルプ」<break time="100ms"/> と話しかけてください。終わりたい時は「ストップ」<break time="200ms"/>と話しかけてください。それでは、光と闇。どちらの話を聞きたいですか?'; var HELP_MESSAGE = 'ヘルプですね。<break time="200ms"/>このアプリでは、IT業界の光と闇を垣間見ることができます。<break time="200ms"/> 光<break time="200ms"/>もしくは闇<break time="200ms"/>と話しかけてください。光ならIT業界のいい話、<break time="200ms"/> 闇ならIT業界のよろしくない話を伝えます。 <break time="200ms"/>終わりたい時は「ストップ」<break time="200ms"/>と話しかけてください。 それでは「光」<break time="100ms"/>と「闇」<break time="100ms"/> どちらの話を聞きたいですか?'; var HELP_REPROMPT = 'このアプリでは、IT業界の光と闇を垣間見ることができます。 光、もしくは闇、と話しかけてください。光ならIT業界のいい話、 闇ならIT業界のよろしくない話を伝えます。 終わりたい時は「ストップ」、 と話しかけてください。 それでは「光」、と「闇」、 どちらの話を聞きたいですか?'; var STOP_MESSAGE = 'IT業界に光があらんことを。 <break time="700ms"/>またね。'; var CONTINUE_MESSAGE = '<break time="1000ms"/>続けて、<break time="200ms"/>ほかの話を聞きたい場合は 「光」<break time="200ms"/> もしくは「闇」<break time="200ms"/> と話しかけてください。 <break time="200ms"/>終わりたい時は「ストップ」<break time="200ms"/>、と話しかけてください。 どうしますか?'; var HIKARI_PREFIX = '光の話ですね。<break time="800ms"/>'; var YAMI_PREFIX = '闇の話ですね。<break time="800ms"/>'; var SPEAK_PREFIX = '<speak>'; var SPEAK_SUFFIX = '</speak>'; var hikariData = [ '自分が関わった、システムやサービスが、世の中にでていくのは、いいものだよ。自分が作った、システムやサービスを、使ってくれている人を見かけると、嬉しくなることもあるよ。', 'アイデアを、こうしてスマートスピーカーに、しゃべらせたりできるよ。まぁ、IT業界じゃなくてもできるけどね。', 'カッコイイWebページを、作ることができるよ。パソコンはもちろん、携帯電話でもWebページは大切だからね。', 'リモートワークができるところなら、家で仕事ができることもあるよ。家で集中できるかは別の話だけどね。', 'フレックスタイム制だと、満員電車に乗らなくてもいいこともあるよ。', '飲み物とか、お菓子とか、無料で食べ放題の職場もあるよ。食べ過ぎると、後悔しちゃうけどね。', '音楽を聴きながら、お仕事をしていい職場もあるよ。', '常に新技術に出会えるし、ものづくりは楽しいよ。これが醍醐味さ。', 'いろんな業界の人と、お仕事できることもあるよ。', '実力主義の現場だと、できる人ほどお給料がもらえることもあるよ。', '技術に関する本とか、資格試験の受験にかかるお金が、会社からもらえることもあるよ。資格をとると、お給料があがる会社もあったりするよ。資格だけあっても、技術がないと、意味ないけどね。', '社会に新しいモノ、価値を提供できることもあるよ。このシステム、自分が作ったんだって、ドヤッ、とできるよ。' ]; var yamiData = [ 'お客様の職場に、一人だけで派遣されることもあるよ。孤独感がすごいよ。人によるけどね。', '経験年数をごまかされることがあるよ。嘘は良くないよね。', 'システム障害が発生すると、夜中でも休日でも連絡がきて、対応しないといけないこともあるよ。', '忙しいと、終電での帰宅や、会社に泊まることもあるよ。', 'ローンを組んで自宅を購入しても、転勤しないといけないこともあるよ。', '裁量労働制とは言っても、早朝から呼ばれたりするよ。', '一次請け、二次請け、三次請け、よん、ご、ろく、なな。おっと。誰か来たようだ。', '技術がわからない人に人事評価されることもあるよ。それだと、お給料が、あがりにくいこともあるよ。', 'ゴールデンウイークに、休みがまったくないこともあるよ。年末年始も同じだね。', 'ノー残業デーがあるということは、いつもは忙しいということもあるよ。', 'ストレスが溜まって、病気になってしまう人もいるよ。', 'そうだな。あの話をしよう。いや。やはりこの話は、やめておこう、あまりに闇が深すぎるからね。', 'じゃば、と、じゃばすくりぷと、は、別のプログラム言語だって、わかってくれない人もいるよ。', 'しようしょ。しようしょ、かっこ、いち。しようしょ、かっこ、に。しようしょ、最新版。しようしょ、最終版。しようしょ、ふぃっくす。', 'なるはやで、いいかんじに、やっておいて。って言われることもあるよ。困っちゃうよね。', 'きみ、いちにち何時間働ける?。と聞かれることもあるよ。さぶろく協定とかご存知でしょうか', '年単位や、年度の単位で、残業時間の制限があっても、としが明けたり、年度が替わると突然残業制限の時間がリセットされて、結局、制限がなくなることもあるよ。' ]; app.intent('Default Welcome Intent', conv => { var speechOutput = WELCOME_MESSAGE; conv.ask(SPEAK_PREFIX + speechOutput + SPEAK_SUFFIX); }); app.intent('hikariIntent', conv => { var factArr = hikariData; var factIndex = Math.floor(Math.random() * factArr.length); var randomFact = factArr[factIndex]; var speechOutput = HIKARI_PREFIX + randomFact + CONTINUE_MESSAGE; conv.ask(SPEAK_PREFIX + speechOutput + SPEAK_SUFFIX); }); app.intent('yamiIntent', conv => { var factArr = yamiData; var factIndex = Math.floor(Math.random() * factArr.length); var randomFact = factArr[factIndex]; var speechOutput = YAMI_PREFIX + randomFact + CONTINUE_MESSAGE; conv.ask(SPEAK_PREFIX + speechOutput + SPEAK_SUFFIX); }); app.intent('helpIntent', conv => { var speechOutput = HELP_MESSAGE; conv.ask(SPEAK_PREFIX + speechOutput + SPEAK_SUFFIX); }); app.intent('stopIntent', conv => { var speechOutput = STOP_MESSAGE; conv.close(SPEAK_PREFIX + speechOutput + SPEAK_SUFFIX); }); exports.dialogflowFirebaseFulfillment = functions.https.onRequest(app);
Alexaとの違いとして気をつけるのば、文法面もありますが、<speak>タグの扱いです。
var SPEAK_PREFIX = '<speak>'; var SPEAK_SUFFIX = '</speak>'; conv.ask(SPEAK_PREFIX + speechOutput + SPEAK_SUFFIX);
のように当時の僕は作成しました。
Alexaは<speak>タグを隠蔽してくれますが、Googleさんは明示的に記載する方法があります。 なので、タグを変数化して、光と闇の話題の前後にプレフィックスとサフィックスとして挟むようにしています。
まとめ
テストシミュレーターや、申請の仕方などは他の方ががたくさん書いているので、あえて記載しません。
5月くらいにAlexaで作成した「IT業界の光闇」スキルをGoogle対応し、現在のUIだとこのようになっているようです、というお話でした。
<speak>がAlexaから入ると隠蔽されているので、そこで引っ掛かった当時の記憶が蘇ります。
以上、 ADVENTARの 「するめごはんのVUI・スマートスピーカー Advent Calendar 2018」 の6日目の記事でした。
はてなブログを読み上げるフラッシュブリーフィングスキルを作る
この記事は ADVENTARの 「するめごはんのVUI・スマートスピーカー Advent Calendar 2018」 の5日目の記事です。
今回は少し指向を変えて、カスタムスキルではなく、フラッシュブリーフィングスキルを作成した話です。
僕のはてなブログを読み上げるという、なかなか香ばしいスキルです。
はてなブログを読み上げるスキルの記事をQiitaに載せるというプレイ
フラッシュブリーフィングスキルとは
要するに、 「アレクサ、今日のニュースは?」 と話しかけると流れるニュースのスキルです。
カスタムスキルは 「アレクサ、〇〇を開いて」 などで起動しますが、フラッシュブリーフィングスキルは、一連のニュースとして読み上げるスキルのうちの1つを作成することになります。
フラッシュブリーフィングスキルの作り方
さすがの @zono_0 さんが非常にわかりやすい資料を既に公開していらっしゃるので、これを閲覧すればAPI GateWayで呼び出させるLambdaで作成することができます。
https://qiita.com/zono_0/items/10719a9df59d3af3edd2
とはいえ、毎日流れるニュースがLambdaで決め打ちのコードというのもなかなかしんどいので、今回は僕自身のはてなブログを流すスキルを創った話です。
はてなブログを読み上げるフラッシュブリーフィングスキルの作り方
基本的には、上記の @zono_0 さんの記事の通りです。
違うところを記載していきます。
1.まずはAlexa developer console
まずは、みんな大好きAlexa developer consoleにて「フラッシュブリーフィングスキル」を選択して「スキルを作成」です。
最新のUIに対応するため、適当なスキル名でとりあえず進めます。
2.カスタムエラーメッセージ
エラーメッセージをいれます。 「ほげほげ」の箇所に「現在、このニュースは利用できません」等を書いておけば良いかと思われます。
そして「新しいフィードを追加」をポチります。
3.新しいフィードを追加を押したら各種情報を入力
以下のような画面になるので、必要事項を入れていきます。
するめごはんはてなブログ では、以下のように作成しています。
フィードの箇所に、はてなブログのRSSのURLを記入すれば解決です。
事実上、今回のスキル作成は。ほぼこれだけです。
4.警告がでまくる
警告がものすごくでてきます。
実は読み上げられる文字数の最大値は決められており、4500文字までとなっています。
この文字数に半角英数字なり、記号なり、改行コードなり、等がどのように計算されているのかは僕は確かめてないです。
が、気にせずに「保存」してしまいます。
ちなみに、スキルの説明は最低限だけ記載すればOKです。 何を読み上げる(流す)のかと、ストップで止めることができる旨を書いておけば良いみたいです。
5.Amazon.co.jp alexaにサインイン
ここからは @zono_0 さんの https://qiita.com/zono_0/items/10719a9df59d3af3edd2 とほぼ同じです。
https://alexa.amazon.co.jp/spa/index.html
を開いて、作成したフラッシュブリーフィングスキルの「設定」を押します。
画面が遷移したら「フラッシュニースの管理」を押します。
後は、自分のスキルを「オン」にするようにトグルを押します。
ニュースを流す順番は個々人で好きに調整できます。
公開されると
審査が通過すると、自分のはてなブログを読み上げるスキルが少なくとも日本国内にお届けできます。
実際に自分で試してみると、RSSを取得して読み上げているだけなので、URLなどの記号を丁寧に読み上げてくれる素敵なスキルが公開されます。
はい、5日目の記事は以上です。
NOIDのイベントすごい良いし、NOID自体もすごい良いという話
この記事は ADVENTARの 「するめごはんのVUI・スマートスピーカー Advent Calendar 2018」 の4日目の記事 です。
Qiitaにも投稿しましたが、こちらの方が詳しいです。
技術面以外も触れられるので。
先ほど、NOIDのもくもくイベントに行ってきたのでアドベントカレンダーを急遽NOIDの記事に差し替えました。
さて、先日、Alexaスキルをノンプログラミングで作成、申請できてしまう素敵ツールNOIDのハンズオンに参加してきました。
■NOID スマートスピーカー ハンズオンNIGHT
ここで生まれたスキルが以下です。
なお、スキルの説明文にも記載しましたが、「するめ」はじゃんけんとはまっったく関係ないです。
そして12月3日にNOIDのもくもく会に参加してきたので、アドベントカレンダーの予定を変更して12月4日になってしまったところで、この記事を書いています。
この記事を書いている現在の画面なので、今後変更される可能性が大いにあります。
NOIDとは
NOID(ノイド)は、話題のスマートスピーカー/AIスピーカーの スキル制作ツールです。プログラミング知識がなくても、開発から申請公開まで完了。 無料プランあり。
って、Google検索で表示されます。
Webページが以下のようになっています。
ログインすると以下のような画面になります。 いろんな情報を取得してグラフにしてるっぽいです。
ハンズオンにて じゃんけん のスキルを作成
ハンズオンすごい
ハンズオンがすごくて、何がすごいって、Amazonのアカウント作成から実施しました。
知らないとハマる、AmazonのjpアカウントとAlexaのアカウントを作成して~~~~な、ところからハンズオンして、その場全員がスキルを作成できたという凄さ。
もちろん、NOIDのアカウントも作成して、製作開始。
テキストがじゃんけんだったので、ユニーク性のため、スキルの名称が「するめじゃんけん」という意味不明なワードになってしまったけれども作成しました。
ハンズオンは、その性質上どうしても静かなイベントになりがちな面があります。作業に集中してしまいますから。
けれども、NOIDのイベントはアイリッジ社の岩屋さんのファシリテーターがすごくうまくて、場のつなぎ方、盛り上げ方がとにかく良くてイベント自体が楽しくなります。
そして、やっぱりスマ―スピーカーは知っているけれど自分でスキル・アクションを作成したことがない人が、自分で入力した文字列をスマ―スピーカーが読み上げてくれる最初の感動を届けるイベントとして物凄く良かったです。
Alexaが「こんにちは」と発話する、まさにハローワールドなことをするわけですが、エンジニアではない方もそれがその場で実現できて、会場が
「おおおおお!!!」
とか、拍手がたくさんでたり、みんな笑顔で楽しくワイワイやってました。
あの会場にいるとき、もちろん自分が初めてスキル・アクションを作ったときの喜びを思い出せましたし、何よりエンジニアとしての原点も思い出せました。
僕が人生で初めてプログラムを書いたのは中学時代のHTMLで自作サイトを作成した時。
それから少したって、C言語でprint文でまさしくハローワールドをした時。
あの体験が、NOIDのイベントでは参加者全員が体感してました。
すごく良かった。
アイリッジさん、本当にありがとうございます。
カスタムスキルを作成してみる
NOIDでは以下のように画面をポチポチしてスキルが作成できちゃいます。
フラッシュブリーフィングスキルも作れるらしいですが僕はまだ試してないです。
NOIDはGUIのツールなので、最初は操作がわからないですが、すぐに慣れます。
僕みたいに既にスキル公開している人ではなく、本当にアカウント作成からの人でも作成できました。
以下のように、各ブロックを作成していきます。
直感的に、Alexaが話すセリフ、ユーザーが話しかけてくる(Intentやスロット)の操作が視覚的に非常にわかりやすく構成されています。
一部機能制限がありますが、Alexaが発話する内容をランダムにできます。
ここでは、じゃんけんで、ユーザーが「グー」なら、ランダムで、グー、チョキ、パーが選ばれるように作成できます。
そして、しれっとすごいことしているのですが
mp3ファイルをドラッグ&ドロップするとAlexaに対応したフォーマットに自動変換してアップロードしてくれる!
※90秒や1回の返答に5ファイルまで等の制限には流石にこの時点では未対応
ちなみに、数時間前のNOIDもくもくイベントで気づいたのですが以下の赤線部のようにSSMLにも対応しています。
ちゃんと指定した時間だけ待機してくれました。
申請までできる
スキルを作成したら、申請までNOIDの画面でできちゃいます。 審査を通過するための文言は既に記述されているので、スキル作成が初体験の方でも十分に申請可能です。
テスト手順などの必要事項を入力して保存し、青枠の申請ボタンを押すとAmazon社に審査をだしてくれます。
テストはAlexaのコンソールもしくは実機
テストは既存のテスト画面でそのまま実行します。 けれども、NOIDの性質上、実機で行った方が良いと思われます。
自動生成されているアレコレ
NOIDの画面のみでポチポチできてしまうので、裏で自動的に生成されているアレコレがあります。
例えば赤枠のランダムと思われる文字列のIntentと、CatchAllIntentが生成されています。 ちなみにエンドポイントとしてLambdaが生成されています。
CatchAllIntentの中身
この名称からして、なんでもこのIntent該当させようとしていることが、サンプル発話からよくわかります。
NOIDで審査に申請する場合の注意点
NOIDでスキルを作成し審査に申請する場合、以下の点に注意が必要です。
注意点1 アイコンは自分で用意する
スキルのためのアイコン2種類は自分で用意する必要があります。
注意点2 「NOID」という単語を使用できない
そりゃないよAmazonさんとも思えるレベルだと個人的には思っているのですが、発話メッセージ内部およびスキル説明にNOIDを含めるとリジェクトになります。
例えば、 「このスキルはNOIDで作成しました」 をAlexaから話しかけてくるようにするとリジェクト対象です。
また、スキルストアに表示されるスキルの説明文にNOIDで作成した旨を記載してもリジェクト対象です。
もちろん 「NOIDのハンズオンで作成しました」 でもリジェクト対象です。 音声でも文字でも「NOID」は扱えないです。
なぜこれらを知っているかというと、これすべて僕がリジェクトを頂いた内容だからです。
非エンジニアやVUIの知見が深くない人にはとても良い
スキルを自身で作成できる人なら、NOIDを選ばなくてもASK CLIなりでスキルは作れるでしょう。
けれども、VUIのデザイナさんや、これからスキルを作りたい個人や企業がモックを作成する場合にイメージとして動くモノが作れるので共通認識がしやすくなると思います。
もちろんエンジニアにも良い
VUIの対話モデルが図示されるので、自分で音声でのやりとりをどのように設計しているのか理解がしやすく、対話モデルの可視化としても非常に良いです。
はい、そんなこんなでNOIDはイイ感じです。国産ですし。