LoginSignup
5
8

More than 3 years have passed since last update.

GASとDialogflowでLINE botを作った話

Posted at

はじめに

GAS(Google Apps Script)でLINEのbotを作り、そのbotが受け取ったメッセージをDialogflowで自然言語解析して応答させてみた、というお話です。

GASでLINEのbotを作る

ひとまずDialogflowはおいておいて、オウム返しするだけのbotを作ります。

環境構築

まずは以下の記事を参考にしつつ、GASのローカル開発環境を構築しました。
Google Apps Script をローカル環境で快適に開発するためのテンプレートを作りました
GAS を npm パッケージ + Webpack + TypeScript で開発する

実装

LINEのbotの実装については非常に多くの情報があるのでここでは深くは触れないことにします。

index.ts
import { reply } from "./reply";

global.doPost = (e: any): void => {
  reply(e);
};
reply.ts
export const reply = (e: any) => {
  const accessToken: string = PropertiesService.getScriptProperties().getProperty(
    "LINE_ACCESS_TOKEN"
  );
  const json = JSON.parse(e.postData.contents).events[0];
  const replyToken: string = json.replyToken;
  const userMessage: string = json.message.text;
  const url: string = "https://api.line.me/v2/bot/message/reply";

  const headers = {
    Authorization: "Bearer " + accessToken,
    "Content-Type": "application/json; charset=UTF-8",
  };

  const postDatas = {
    messages: [
      {
        text: userMessage,
        type: "text",
      },
    ],
    replyToken,
  };

  const options: any = {
    headers,
    method: "POST",
    payload: JSON.stringify(postDatas),
  };

  UrlFetchApp.fetch(url, options);
  return ContentService.createTextOutput(
    JSON.stringify({ content: "post ok" })
  ).setMimeType(ContentService.MimeType.JSON);
};

これをデプロイしてLINEのチャネルのWebhookURLにしてあげればオウム返しbotの完成です。

Dialogflow

ここからが本題

Dialogflowって何?

公式ドキュメント
Dialogflow入門

私の言葉で説明するよりも上記を読んで頂くほうがいいと思いますが、つまりは自然言語の解析をGoogle先生のパワーで簡単にしてくれた優れものという感じです。

実装

まずユーザーに応答するreply関数を修正して、createReply関数によって作られたテキストを応答するようにします。

reply.ts
import { createReply } from "./messages/createReply";

export const reply = (e: any) => {

  // 略

  const postDatas = {
    messages: [
      {
        text: createReply(userMessage),
        type: "text",
      },
    ],
    replyToken,
  };

  // 略

};

次に、リプライの内容を作るcreateReplyを書きます。
私の実装が最適かどうかはさておき、今回はDialogflowというクラスを作り、会話のたびにインスタンスを生成します。Dialogflowの実装は後ほど。

createReply.ts
import { Dialogflow } from "./dialogflow";

export const createReply = (userMessage: string): string => {
  const queryResult = new Dialogflow(userMessage).postQuery();
  const intent: string = queryResult.intent.displayName;

  switch (intent) {
    case "foo":
      return "intentはfooでした";
    case "bar":
      return "intentはbarでした";
    default:
      return userMessage;
  }
};

createReplyは、ユーザーからのメッセージを引数にとり、そのメッセージをDialogflowのAPIに渡してintentを受け取ります。
ここではintentに応じて返答する内容を変えるような関数にしています。

最後にDialogflowクラスを実装します。

dialogflow.ts
const scriptProperties = PropertiesService.getScriptProperties();
const dfUrlFormat: string = scriptProperties.getProperty("DF_URL_FORMAT");

export class Dialogflow {
  private sessionID: string;
  private message: string;

  public constructor(message: string) {
    this.sessionID = Math.random().toString(32).substring(2);
    this.message = message;
  }

  public postQuery() {
    const body: any = {
      queryInput: {
        text: {
          languageCode: "ja",
          text: this.message,
        },
      },
      queryParams: {
        timeZone: "Asia/Tokyo",
      },
    };

    const options: any = {
      contentType: "application/json; charset=utf-8",
      headers: {
        Authorization: "Bearer " + getAccessToken(),
      },
      method: "POST",
      payload: JSON.stringify(body),
    };

    const response = UrlFetchApp.fetch(
      dfUrlFormat.replace(/{{sessionID}}/g, this.sessionID),
      options
    );
    return JSON.parse(response.getContentText()).queryResult;
  }
}

const getAccessToken = () => {
  const jsonKey = JSON.parse(
    scriptProperties.getProperty("GOOGLE_APPLICATION_CREDENTIALS")
  );

  const serverToken = new GSApp.init(
    jsonKey.private_key,
    ["https://www.googleapis.com/auth/cloud-platform"],
    jsonKey.client_email
  );

  const tokens = serverToken
    .addUser(jsonKey.client_email)
    .requestToken()
    .getTokens();
  return tokens[jsonKey.client_email].token;
};

Dialogflowは、エンドユーザーとの会話をセッションと呼んでいます。それぞれのセッションにセッションIDがあり、このIDはAPIの呼び出し元(つまり私たち)の責任で適切に選択しなければなりません。
今回実装したDialogflowクラスはインスタンスごとにセッションIDをランダムに生成します。(だったらSessionというクラス名にすればよかった)

また、postQueryメソッドを持っていて、detectIntentを取得します。
公式リファレンス: Method: projects.agent.sessions.detectIntent

OAuth認証は以下の記事を参考に実装しました。
ここでかなり悩んでいたんですが、先人の偉大な知恵に助けられました。
Hangouts Chatbotをdialogflowを利用してもっとbotらしくする

これでDialogflowによる言語解析をLINEbotが出来上がりました。
Dialogflowで簡単に言語解析を体験できるのでぜひお試しあれ。

おわりに

自然言語解析と聞くと難しそうですがDialogflowを使ってみるとかなり簡単にできますね:grin:

5
8
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
5
8