1
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

1時間で作るgoogle homeアプリ(社内勉強会向け)

Last updated at Posted at 2019-05-04
1 / 19

actions on googleとdialogflow(とその裏側で動くfirebase functions)で作る簡単なクイズアプリの作り方です。
社内の勉強会(1時間)向けなのですが、せっかくなので公開します。
口頭で説明しながらとなるのでけっこうざっくりです。


actions on google -1/3-

  • 右上のGO TO ACTIONS CONSOLE押す
  • Add Import/Project押す

2/3

Project Name language countory Genre
任意 Japanese Japanese 任意

3/3

  1. Invacation -> Display Name入力(アプリ名)
  2. Build -> Actions -> Custom intent -> BUILD

dialog flow -Entitys-

  1. CREATE ENTITYを押す
  2. Entity name = answers
  3. Valueとsynonymを2,3入力

Intents

4つ作ります

インテント名 用途 サンプルフレーズ
QuizIntent 出題 「ではクイズです。パンはパンでも・・・」
AnswerIntent 解答 「正解!正解は・・・」
FinishIntent 終了 「遊んでくれてありがとう。またね」
HelpIntent 使い方 「このクイズはほにゃほにゃ

QuizIntent

  • Output Contexts

  • QuizIntent-followup, lifespan:1

  • Training phrases

  • クイズはじめる

  • スタート

  • 問題出して

  • Fulfillment

  • Enable webhook call for this intent


Contextsについて

ざっくり言うとIntent同士をつなぐためのものです。
例えばQuizIntent-followup という名前のContextを Input Contextsとして設定したIntentがある場合、このContextを含んでいる場合しか呼ばれません。
こんかいはQuizIntentでOutputにQuizIntent-followup を設定するのでQuizIntent経由でしかAnswerIntentが呼ばれなくなります。
(不正解の場合にもAnswerIntentを呼びたいため、この仕組みを使っています)


AnswerIntent

  • Input Contexts

  • QuizIntent-followup

  • Output Contexts

  • QuizIntent-followup, lifespan:1

  • Training phrases

  • 鰺(=@answers)

  • くじら(=@answers)かな

  • 亀(=@sys.any)

  • Fulfillment

  •  [x] Enable webhook call for this intent


@sys.anyとは

なんにでも合致してしまうジョーカー的なEntityです。
間違って使うとなんでも拾ってしまいます。
利用については推奨ではないみたいです。
今回はcontextで絞りをかけたインテントにて使っています。
これができるのがghomeアプリの強みだと思ってる。


FinishIntent

  • Training phrases

  • やめる

  • 終わる

  • 終了

  • Responses

  • 遊んでくれてありがとう。また遊んでね

  • また遊んでね。bye

  • Set this intent as end of conversation

  • [x]


HelpIntent

  • Training phrases

  • 使い方

  • ヘルプ

  • どうやるの?

  • Responses

  • 「スタート」というとクイズがはじまるので・・


Export and Import (Dialogflow)

DialogflowのIntentsやEntitiysについてはImport(Restore or Import)で複製も可能です。
ただし、fullfillmentのスクリプトは復元されません。


fullfillment

QuizIntentとAnswerIntentは単純なやりとりではないため、バックエンドにnodejsを用います。
DialogFlowにはInline Editorがついており、nodejsのコードを書けるようになっているため今回はこれを使います。
fullfillment(左ナビ)を選択し、Inline EditorをEnableにします。


サンプルコード

index.js
'use strict';
 
const functions = require('firebase-functions');
const { dialogflow, SimpleResponse } = require('actions-on-google');

//mp3
const drumrole_mp3 = "https://s3-ap-northeast-1.amazonaws.com/xxxxxxxx/quiz/drum-japanese.mp3";
const question_mp3 = "https://s3-ap-northeast-1.amazonaws.com/xxxxxxxx/quiz/question.mp3";
const correct_mp3 = "https://s3-ap-northeast-1.amazonaws.com/xxxxxxxx/quiz/correct.mp3";
const incorrect_mp3 = "https://s3-ap-northeast-1.amazonaws.com/xxxxxxxxx/quiz/incorrect.mp3";

const app = dialogflow({ debug: true });

const Quizzes = {
    "鯵": { 
      "q": "魚へんに<emphasis level='moderate'><sub alias='惨状のさん'>参</sub></emphasis>を書いて何という魚?",
      "a": "あじ"
    },
    "鯨": {
      "q": "魚へんに<emphasis level='moderate'><sub alias='京都のきょう'>京</sub></emphasis>を書いて何という魚?",
      "a": "くじら"
    },
    "鯱": {
      "q": "魚へんに<emphasis level='moderate'><sub alias='とら'>虎</sub></emphasis>を書いて何という魚?",
      "a": "しゃち"
    },
    "鯰": {
      "q": "魚へんに<emphasis level='moderate'><sub alias='念仏のねん'>念</sub></emphasis>を書いて何という魚?",
      "a": "なまず" 
    },
    "鯖": {
      "q": "魚へんに<emphasis level='moderate'><sub alias='あおの旧字体'>青の旧字体</sub></emphasis>を書いて何という魚?",
      "a": "さば" 
    }
};
var quizzes = Object.assign({}, Quizzes);

app.intent('QuizIntent', (conv) => {
   console.log(quizzes);

    if (Object.keys(quizzes).length < 1){
      conv.close("あれ?もう出す問題がなくなっちゃいました。ごめんなさい。またやってね!");
      return true;
    }
    
    //quizを選択
    let keys = Object.keys(quizzes);
    let choice = Math.floor( Math.random() * keys.length);
    let q = quizzes[keys[choice]];
    q.k = keys[choice];
    //set data
    conv.data.current = q;
    conv.ask(new SimpleResponse({
      text: q.q,
      speech: `<speak><audio src="${question_mp3}" />${q.q}</speak>`
    }));
});

app.intent('AnswerIntent', (conv, params) => {
    let q = conv.data.current;
    let collect = false;
    console.log(conv.input.raw);
    if (conv.parameters.answers !== ''){
      console.log(`answers is ${conv.parameters.answers}`);
      if (conv.parameters.answers == q.k){
        collect = true;
      }
    }
    if (conv.parameters.any !== ''){
      console.log(`answers is ${conv.parameters.any}`);
    }
    
    let prize = [
      "すごい!","素晴らしい!","アメージング!","天才!","この、イケメン!"   
    ];
    let p = prize[Math.floor( Math.random() * prize.length)];
    if (collect){
      conv.ask(new SimpleResponse({
        text: `正解!答えは、${q.a}でした。${p}。次の問題もやりますか?はい、かいいえで答えてね。`,
        speech: 
          `<speak><audio src="${drumrole_mp3}" /><audio src="${correct_mp3}" />
           <prosody rate="110%" pitch="+10%">正解!</prosody><break time="500ms"/>
           答えは、、${q.a}でした。<break time="200ms"/>
           <prosody rate="110%" pitch="+10%">${p}</prosody>
           次の問題もやりますか?<break time="500ms"/>
           はい、かいいえで答えてね。</speak>`
       }));
    }else{
      conv.ask(new SimpleResponse({
        text: `残念!答えは、${q.a}でした。次の問題もやりますか?はい、かいいえで答えてね。`,
        speech: 
          `<speak><audio src="${drumrole_mp3}" /><audio src="${incorrect_mp3}" />
           <prosody rate="105%" pitch="+5%">残念!</prosody><break time="500ms"/>
           答えは、、${q.a}でした。
           次の問題もやりますか?<break time="500ms"/>
           はい、かいいえで答えてね。</speak>`
       }));
    }
    //今の問題は使用済みに
    delete quizzes[q.k];
    //clear 
    conv.data.current = {};
});
  
exports.dialogflowFirebaseFulfillment = functions.https.onRequest(app);


SSML

Speech Synthesis Markup Language
しゃべらせ方をコントロールするためのマークアップ言語。
<speak></speak>で囲んだ中で、等のタグで声の協調等ができます。


デバッグ

出来たらテスト。
プロジェクトのgoogleアカウントと同じアカウントであればテストバージョンのアプリが使用可能になっています。
アルファ版のリリースで他ユーザーもテスト可能になる。

  1. シミュレーター
  2. 実機
  • スマホ with google assistant
  • google home

公開申請

必要なこと

  • Overviewを埋める
  • Description
  • Sample invocations
  • ロゴ2種(192x192,1920x1080)を登録
  • Contact detailsを入力
  • プライバシーポリシーを作成(こういうので十分)

その他

  • 各フレーズはEntityにしてしまったほうが管理が楽です
  • たとえばFinishIntentで$finishphrasesを設定
  • Valueには「終わる」、「やめる」、「終了」など
  • FinishIntentのTraning phrasesには「終わる(=@finishphrases)」
  • https://github.com/ikegam1/ghome-aroundfish-quiz が今回のコードです
1
5
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
1
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?