GoogleアシスタントアプリDialogflow用Inline EditorテンプレートプログラムV2版

# 1. はじめに
Alexaだとか、Clovaだとかを開発していると、ついついGoogleアシスタントのロジックってどうだっけ？？となることがありました。
今回は、自分自身への備忘録をかねて、DialogflowのInline Editorで使える、テンプレートプログラムをお伝えしたいと思います。

## 1-1. この記事を読んでできること
- **テンプレートプログラムを用いて、Googleアシスタント V2のテンプレートプログラムをコピペできるようになる。**

## 1-2. 前提条件
- Dialogflowの使い方を理解していること。

# 2. テンプレートプログラムV2版
- 動作検証をおこないました。（2018年11月時点）
- 見本となるテンプレートですので、お好きに書き替えてお使いください。

```javascript:index.js
// REFERENCE
// https://developers.google.com/actions/reference/nodejs/lib-v1-migration#new_frameworks_system


/**
 * 厳密モード有効
 * @author zono_0
 */ 
'use strict';


/**
 * モジュール参照
 * @author zono_0
 */ 
const functions = require('firebase-functions');

const {
  dialogflow,
  // BasicCard,
  // BrowseCarousel,
  // BrowseCarouselItem,
  // Button,
  // Carousel,
  // Image,
  // LinkOutSuggestion,
  // List,
  // MediaObject,
  Suggestions,
  SimpleResponse,
} = require('actions-on-google');

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


/**
 * ウェルカム応答
 * @author zono_0
 */ 
const welcomeResponse = (conv) => {
  const speechText = 'サンプルアプリへようこそ。聞き取りづらい言葉をおっしゃってください。';
  const repronptText = '聞き取りづらい言葉をおっしゃってください。';
  const suggestions = ['はい', 'いいえ', '終了'];

  conv.data.repronptText = repronptText;
  conv.data.fallbackCount = 0;

  conv.ask(new SimpleResponse({
    speech: speechText,
    text: speechText,
  }));

  conv.add(new Suggestions(suggestions));
};


/**
 * 聞き直し応答
 * @author zono_0
 */ 
const fallbackResponse = (conv) => {
  let fallbackCount = conv.data.fallbackCount || 0;
  const repronptText = conv.data.repronptText;

  const fallbackMessages = [
    '今、なんておっしゃいましたか？',
    `ちょっと分かりませんでした。${repronptText}`,
    'すみません。 お役に立てそうにありません。'
  ];

  const speechText = fallbackMessages[fallbackCount];

  fallbackCount += 1;
  conv.data.fallbackCount = fallbackCount;

  if (fallbackCount === 3) {
    conv.close(new SimpleResponse({
      speech: speechText,
      text: speechText,
    }));
  } else {
    conv.ask(new SimpleResponse({
      speech: speechText,
      text: speechText,
    }));
  }
};


/**
 * イエス応答
 * @author zono_0
 */ 
const yesResponse = (conv, {yesValue}) => {
  const speechText = `<speak>今、<break time="0.5s"/>${yesValue}とおっしゃいましたね。</speak>`;

  conv.close(speechText);
};


/**
 * ノー応答
 * @author zono_0
 */ 
const noResponse = (conv, {noValue}) => {
  const speechText = `<speak>もしかして、<break time="0.5s"/>${noValue}とおっしゃいましたね。</speak>`;

  conv.close(speechText);
};


/**
 * ヘルプ応答
 * @author zono_0
 */ 
const helpResponse = (conv, {helpValue}) => {
  const repronptText = conv.data.repronptText;

  const helpText = 'このアプリはサンプル用の音声アプリです。聞き取りづらい言葉を聞き取れるか確認します。';
  const speechText = repronptText;

  conv.data.fallbackCount = 0;

  conv.ask(new SimpleResponse({
    speech: helpText + speechText,
    text: helpText + speechText,
  }));
};


/**
 * 終了応答
 * CancelIntentからの呼び出し時はBasicCardなどのGUI表示は利用しないこと！
 * @author zono_0
 */ 
const stopResponse = (conv, {cancelValue}) => {
  const speechText = '終了を受け付けました。ご利用ありがとうございます。';

  conv.data.fallbackCount = 0;

  conv.close(speechText);
};


/**
 * Default Welcome Intent
 * @author zono_0
 */ 
app.intent('Default Welcome Intent', conv => {
  welcomeResponse(conv);
});


/**
 * 暗黙的呼び出し
 * @author zono_0
 */ 
app.intent('ImplicitInvocationIntent', conv => {
  welcomeResponse(conv);
});


/**
 * Default Fallback Intent
 * @author zono_0
 */ 
app.intent('Default Fallback Intent', conv => {
  fallbackResponse(conv);
});


/**
 * YesIntent
 * @author zono_0
 */ 
app.intent('YesIntent', (conv, {yesValue}) => {
  yesResponse(conv, {yesValue});
});


/**
 * NoIntent
 * @author zono_0
 */ 
app.intent('NoIntent', (conv, {noValue}) => {
  noResponse(conv, {noValue});
});


/**
 * Help Intent
 * @author zono_0
 */ 
app.intent('HelpIntent', (conv, {helpValue}) => {
  helpResponse(conv, {helpValue});
});


/**
 * CancelIntent
 * @author zono_0
 */ 
app.intent('CancelIntent', (conv, {cancelValue}) => {
  stopResponse(conv, {cancelValue});
});


/**
 * StoplIntent
 * @author zono_0
 */ 
app.intent('StoplIntent', (conv, {cancelValue}) => {
  stopResponse(conv, {cancelValue});
});


/**
 * メインロジック開始
 * @author zono_0
 */ 
exports.dialogflowFirebaseFulfillment = functions.https.onRequest(app);

```

# 3. おわりに
いかがだったでしょうか？ご参考になりましたでしょうか？
もっとよい書き方などがありましたら、コメント頂けると幸いです。
（私の方でも、少しずつブラッシュアップできれたと思っています。）

2018/11/16 TAKAHIRO NISHIZONO