Deno x Dialogflow ハンズオン

v1.0がリリースされ今話題の[Deno（ディーノ）](https://deno.land/)を使って簡単なチャットボットを作ってみませんか？
Dialogflowを使って簡単なチャットボットを作成し、API部分をDenoで作ります。

## 事前準備
* Deno環境構築
* VSCode

GitHubから環境をダウンロードしましょう。

```shell
$ cd ~/Documents
$ git clone https://github.com/gaomar/deno-dialogflowhandson.git
$ code deno-dialogflowhandson
```
## ハンズオン資料
https://katacoda.com/gaomar/scenarios/deno-dialogflow-handson-playground

## ハンズオン動画
[![IMAGE ALT TEXT HERE](http://img.youtube.com/vi/nEWwm4Hw7lI/0.jpg)](http://www.youtube.com/watch?v=nEWwm4Hw7lI)

## 1. Denoに触れてみよう！

### 1-1. Denoを動かしてみよう
VSCodeのターミナルを開いて、下記コマンドを実行してみよう。`Welcome to Deno 🦕`と表示されればOKです。

```shell
$ deno run https://deno.land/std/examples/welcome.ts
```

### 1-2. TypeScriptから動かしてみよう

`hello.ts` ファイルを開いてください。下記プログラムをファイルに反映してみましょう。

```typescript:hello.ts
let myName: string;
myName = '私の名前は「XXX」です。';

console.log(myName);
```

<img width="728" alt="s100.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154355/5a3e9752-ea77-d5c2-c907-af90d744a02a.png">


下記コマンドを実行してみよう。コンパイルされてログが出力されます。

```shell
$ deno run hello.ts
```

![s101](https://raw.githubusercontent.com/gaomar/katacoda-scenarios/master/deno-dialogflow-handson-playground/images/s101.png)

## 2. REST APIを作成しよう
### 2-1. Agentを作成する

[https://dialogflow.cloud.google.com/](https://dialogflow.cloud.google.com/) にアクセスしてください。
［Sign-in with Google］ボタンをクリックします。お持ちのGoogleアカウントでログインしてください。

![s200-1](https://raw.githubusercontent.com/gaomar/katacoda-scenarios/master/deno-dialogflow-handson-playground/images/s200-1.png)

初めてDialogflowをお使いになる方は利用許可してください。

![s101](https://raw.githubusercontent.com/gaomar/katacoda-scenarios/master/dialoflow-linebot-playground/images/s101.png)

Terms of Service部分のチェックを入れてから［ACCEPT］ボタンをクリックします。

![s102](https://raw.githubusercontent.com/gaomar/katacoda-scenarios/master/dialoflow-linebot-playground/images/s102.png)

［CREATE AGENT］ボタンをクリックします。

![s103](https://raw.githubusercontent.com/gaomar/katacoda-scenarios/master/dialoflow-linebot-playground/images/s103.png)

`HelloDeno` と入力し、デフォルト言語を `Japanese - ja` に選択してから［CREATE］ボタンをクリックします。

![s200](https://raw.githubusercontent.com/gaomar/katacoda-scenarios/master/deno-dialogflow-handson-playground/images/s200.png)

### 2-2. オウム返しをしよう
`Default Fallback Intent` をクリックします。

![s201](https://raw.githubusercontent.com/gaomar/katacoda-scenarios/master/deno-dialogflow-handson-playground/images/s201.png)

 `Fulfillment` カテゴリにある 「Enable webhook call for this intent」を有効化にします。
これで応答をWebhook経由で返すことができます。

![s202](https://raw.githubusercontent.com/gaomar/katacoda-scenarios/master/deno-dialogflow-handson-playground/images/s202.png)

左側メニューの `Fulfillment` をクリックします。Webhookカテゴリを有効化にします。（※2つあるので、上側のWebhookを有効化にします）
Webhook URLは下記コマンドで発行されたngrokのURL（https側）を貼り付けてください。

```shell
$ ngrok http --region jp 3000
```

<img width="829" alt="s200.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154355/d12e8a12-3342-da84-a6b5-a947ef3eea96.png">

![s203.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154355/545e88f3-2e85-93c4-662d-1b3ba917796c.png)

`hello.ts` を開いて、下記プログラムをコピペしてください。

```typescript:hello.ts
import { Application, Context } from "https://deno.land/x/abc@v1.0.0-rc10/mod.ts";
const app = new Application();

app.post('/', async (ctx: Context) => {
    const {queryResult} = await (ctx.body());

    let js = {
            fulfillmentText: `Denoから「${queryResult.queryText}」`
    }

    await ctx.json(js);

});

// ポート開く
app.start({port: 3000});
```

下記コマンドを実行します。

```shell
$ deno run --allow-net hello.ts
```

画面右側の `Try it now` 部分に好きな言葉を入力してください。
すると `Denoから「XXXXXX」` と入力した言葉が返ってきます。

![s204](https://raw.githubusercontent.com/gaomar/katacoda-scenarios/master/deno-dialogflow-handson-playground/images/s204.png)

### 2-3. 特定の言葉に反応させよう
新規Intent作成して特定の言葉に反応するAPIも作成しましょう。左側メニューの `Intents` にある［＋］ボタンをクリックしてください。Intent名は `MorningIntent` と入力します。こちらはスペルミスに気をつけてください。 Training phrasesカテゴリ部分に「おはよう」と入力して Enterキーを押して確定してください。
Fulfillmentカテゴリにある `Enable webhook call for this intent` を有効化にしておきます。
設定できたら右上にある［SAVE］をクリックします。

![s205](https://raw.githubusercontent.com/gaomar/katacoda-scenarios/master/deno-dialogflow-handson-playground/images/s205.png)

次にプログラムを編集します。すでに書いているプログラムを消してから、下記プログラムをhello.tsにコピペしてください。

```typescript:hello.ts
import { Application, Context } from "https://deno.land/x/abc@v1.0.0-rc10/mod.ts";
const app = new Application();

app.post('/', async (ctx: Context) => {
    const {queryResult} = await (ctx.body());

    // Intent名取得
    const displayName = queryResult.intent.displayName;
    let js = {};

    // MorningIntentかどうか判別
    if (displayName === 'MorningIntent') {
        js = {
            fulfillmentText: `😃おはようございます😃`
        };
    } else {
        js = {
            fulfillmentText: `Denoから「${queryResult.queryText}」`
        };
    }
    await ctx.json(js);
})

// ポート開く
app.start({port: 3000});
```

Step2-2のプログラムが動いているので、<kbd>Ctrl</kbd>+<kbd>C</kbd>で一度プログラムを止めておきます。



再度コマンドを実行します。

```shell
$ deno run --allow-net hello.ts
```

これでDialogflowの Try it now で「おはよう」と入力すると、Denoを経由して「😃おはようございます😃」と返ってきます。

![s207](https://raw.githubusercontent.com/gaomar/katacoda-scenarios/master/deno-dialogflow-handson-playground/images/s207.png)

### 2-4. パラメーターの受け取り
新規Intentを作成します。［＋］をクリックして、Intent名を `NameIntent` とします。Tranining phrasesに「スタート」と入力してください。

![s208](https://raw.githubusercontent.com/gaomar/katacoda-scenarios/master/deno-dialogflow-handson-playground/images/s208.png)

Action and parametersカテゴリの項目を埋めていきます。

|項目|値|
|:--|:--|
|REQUIRED| チェックを入れる|
|PARAMETER NAME|name|
|ENTITY|@sys.any|
|VALUE|$name|
|PROMPTS| Define prompts をクリック|

![s209](https://raw.githubusercontent.com/gaomar/katacoda-scenarios/master/deno-dialogflow-handson-playground/images/s209.png)

Define promptsをクリックして、「君の名前は？」と入力します。これで「スタート」と入力した後に「君の名前は？」とDialogflow側から聞かれるようになります。

![s210](https://raw.githubusercontent.com/gaomar/katacoda-scenarios/master/deno-dialogflow-handson-playground/images/s210.png)

Fulfillmentカテゴリにある `Enable webhook call for this intent` を有効化にしておきます。
設定できたら右上にある［SAVE］をクリックします。

![s211](https://raw.githubusercontent.com/gaomar/katacoda-scenarios/master/deno-dialogflow-handson-playground/images/s211.png)

下記プログラムを hello.tsファイルにコピペしてください。（※既存のプログラムに上書きします）
`queryResult.parameters.name` にDialogflowから送られてくるパラメーターを取得することができます。

```typescript:hello.ts
import { Application, Context } from "https://deno.land/x/abc@v1.0.0-rc10/mod.ts";
const app = new Application();

app.post('/', async (ctx: Context) => {
    const {queryResult} = await (ctx.body());
    const displayName = queryResult.intent.displayName;
    let js = {};

    if (displayName === 'MorningIntent') {
        js = {
            fulfillmentText: `😃おはようございます😃`
        };
    } else if (displayName === 'NameIntent') {
        js = {
            fulfillmentText: `あなたの名前は「${queryResult.parameters.name}」ですね！`
        };
    } else {
        js = {
            fulfillmentText: `Denoから「${queryResult.queryText}」`
        };
    }
    await ctx.json(js);
});

// ポート開く
app.start({port: 3000});
```

<kbd>Ctrl</kbd>+<kbd>C</kbd>でプログラムを停止してください。

再度コマンドを実行します。

```shell
$ deno run --allow-net hello.ts
```


これで Try it now に「スタート」と入力すると「君の名前は？」と聞き返されるので、名前を入力します。

![s213](https://raw.githubusercontent.com/gaomar/katacoda-scenarios/master/deno-dialogflow-handson-playground/images/s213.png)

### 2-5. Dialogflow Messengerに対応する
Dialogflow Messengerとは運営しているWebサイトに対してチャットボット機能を簡単に導入することができる機能です。
よくあるQ&Aのチャットシステムと考えてもらえれば良いと思います。

左側メニューの `Integrations` をクリックして表示される、 `Dialogflow Messenger` を有効化にします。

![s214](https://raw.githubusercontent.com/gaomar/katacoda-scenarios/master/deno-dialogflow-handson-playground/images/s214.png)

ポップアップが表示されるので、そこに書かれているコードをコピーしておきます。

![s215](https://raw.githubusercontent.com/gaomar/katacoda-scenarios/master/deno-dialogflow-handson-playground/images/s215.png)

コピーしたコードを `public/index.html` の `</body>` タグ直前ぐらいに貼り付けます。

![s216](https://raw.githubusercontent.com/gaomar/katacoda-scenarios/master/deno-dialogflow-handson-playground/images/s216.png)

プログラムを少し改変します。下記コードを `hello.ts` ファイルにコピペします。

```typescript:hello.ts
import { Application, Context } from "https://deno.land/x/abc@v1.0.0-rc10/mod.ts";
const app = new Application();

app.static('/', './public');

// htmlファイルを読み込む
app.get('/', async (ctx: Context) => {
    await ctx.file('./public/index.html');
});

app.post('/', async (ctx: Context) => {
    const {queryResult} = await (ctx.body());
    const displayName = queryResult.intent.displayName;
    let js = {};

    if (displayName === 'MorningIntent') {
        js = {
            fulfillmentText: `😃おはようございます😃`
        };
    } else if (displayName === 'NameIntent') {
        js = {
            fulfillmentText: `あなたの名前は「${queryResult.parameters.name}」ですね！`
        };
    } else {
        js = {
            fulfillmentText: `Denoから「${queryResult.queryText}」`
        };
    }
    await ctx.json(js);
});

// ポート開く
app.start({port: 3000});
```

![s217](https://raw.githubusercontent.com/gaomar/katacoda-scenarios/master/deno-dialogflow-handson-playground/images/s217.png)

<kbd>Ctrl</kbd>+<kbd>C</kbd>でプログラム停止して、再度コマンドを実行します。
今度はhtmlファイルを読み取る必要があるので `--allow-read` の権限を付与して実行しています。

```shell
$ deno run --allow-net --allow-read hello.ts
```

ngrokで発行したURLにアクセスすると画面右下にDialogflowのロゴが表示されるので、クリックすると Try it now と同様に、入力した結果が返ってきます。


![s218](https://raw.githubusercontent.com/gaomar/katacoda-scenarios/master/deno-dialogflow-handson-playground/images/s218.png)

## 3. 楽天APIと連携しよう！
### 3-1. 楽天APIアプリIDを発行する
楽天APIを使って書籍の検索を行います。下記URLをクリックして、お持ちの楽天IDでログインしてください。

[https://webservice.rakuten.co.jp/app/create](https://webservice.rakuten.co.jp/app/create)

アプリ名、アプリURLを入力します。アプリURLはご自身のGitHubのURLでも良いですし、お好きなURLを指定してください。なんでも構いません。
（※すでに登録されている方は発行する必要はありません）

![s300](https://raw.githubusercontent.com/gaomar/katacoda-scenarios/master/deno-dialogflow-handson-playground/images/s300.png)

発行されたアプリID/デベロッパーIDをメモしておきます。

![s301](https://raw.githubusercontent.com/gaomar/katacoda-scenarios/master/deno-dialogflow-handson-playground/images/s301.png)

### 3-2. .envファイルに反映させる
`.env` ファイルを開いて先程発行したアプリIDを貼り付けてください。

![s302](https://raw.githubusercontent.com/gaomar/katacoda-scenarios/master/deno-dialogflow-handson-playground/images/s302.png)

### 3-3. 動作確認

Step2-5のプログラムが動いているので、<kbd>Ctrl</kbd>+<kbd>C</kbd>コマンドで一度プログラムを止めておきます。

下記プログラムを実行します。今回は `--allow-env` 権限を追加しています。 `.env` ファイルの値を読み取るために dotenvのモジュールを使っているためです。

```shell
$ deno run --allow-net --allow-read --allow-env app.ts
```

ngrokで発行したURLにアクセスして、お好きな本のタイトルを入力してみてください。楽天APIを経由して結果が返ってきます。


![s303](https://raw.githubusercontent.com/gaomar/katacoda-scenarios/master/deno-dialogflow-handson-playground/images/s303.png)

## まとめ
Denoを使うと、今までにあったnode_moduleフォルダが無くなり、シンプルな構成で開発できると思います。まだ出たばかりなので、どんどんアップデートされていくことでしょう。
簡単な連携からスタートするのも良いと思いますので、色々試してみてください。