FlutterアプリでDialogflow APIを使う(dialogflow_flutter)

以前ご紹介した音声チャットボットアプリでは、全てのユーザ発話を応答生成サーバに送ってボットの応答を得ていました。実用的な応答を得るためには、会話の流れを制御する必要性も出てきます。

もちろん、クライアントアプリ側で制御しても良いのですが、メンテナンスが大変なのでDialogflowを使うことにします。

必要なのは、① Dialogflowを呼び出すクライアントアプリ、② 会話を制御するDialogflowエージェント、③ Dialogflowからのwebhookを受け取るサーバ、④応答生成サーバ の、4つとなります。

実は、この構成については既に以下の記事で書いています。

AWS Lambda のChalice使ってflask APIをデプロイする

前回、Netlifyの記事を書きましたが、今回は、Chaliceです。 接続としては、以下の通りです。 <LINE> ー <Dialogflow> ー <heroku> ー <V […]

この時には、以下の構成の、

<LINE> ー <Dialogflow> ー <heroku> ー <VPS>

<heroku>をChaliceを使って<Lambda>に置き換えました。また、別の記事で<VPS>をSAMを使って<Lambda>に置き換えました。

従って今は、以下のようになっています。

①<LINE> ー② <Dialogflow> ー ③<Lambda> ー ④<Lambda>

今回は、<LINE>をflutteアプリに置き換えていきます。

DialogflowはGoogleのAIスピーカと繋ぐためにも使っていたのですが、先日のGoogleからの発表で、これが2023年6月には使えなくなるそうです。

Conversational Actions sunset overview>

Dialogflowのエージェント作成

Dialogflowで新しいエージェントを作成します。作成時に、使用するGoogle Projectを指定します。もし、既存のGoogleProjectを指定しなければ新しいGoogle Projectが作成されます。

Google project サービスアカウントの作成

GoogleCLoudePlatformにアクセスして、先ほど作成したエージェントに紐づくプロジェクトを選択します。

ナビゲーションメニューの「APIとサービス」から「認証情報」を選択します。

「認証情報を作成」からサービスアカウントを作成します。サービスアカウントを作成する際に、ロールとして「Dialogflow APIクライアント」を選択します。

サービスアカウント作成後、「キー」タグから「鍵を追加」を選択します。キーのタイプは「json」を選択し、作成ボタンを押します。

認証情報(jsonファイル)がダウンロードされますので、これを「dialogflow.json」としておきます。

Flutterプロジェクト

新規でFlutterプロジェクトを作成します。今回は、dialogflow_flutterパッケージを使います。また、メインコードはdialogflow_flutterのサンプルコードを使いますので、bubbleパッケージもインストールしておきます。bubbleはチャットアプリでよく使う「吹き出し」を生成するためのパッケージです。

flutter pub add dialogflow_flutter
flutter pub add bubble

次に、main.dartをdialogflow_flutterのExampleコードと置き換えます。修正箇所にコメントしています。

import 'package:bubble/bubble.dart';
import 'package:dialogflow_flutter/googleAuth.dart';
import 'package:flutter/material.dart';
import 'package:dialogflow_flutter/dialogflowFlutter.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primaryColor: Colors.blue,
        primarySwatch: Colors.blue,
      ),
      home: ChatBotScreen(),
    );
  }
}

class ChatBotScreen extends StatefulWidget {
  @override
  _ChatBotScreenState createState() => _ChatBotScreenState();
}

class _ChatBotScreenState extends State<ChatBotScreen> {
  final messageInsert = TextEditingController();
  List<Map> messsages = [];  //  ※ 修正
  void response(query) async {
    AuthGoogle authGoogle =
        await AuthGoogle(fileJson: "assets/dialogflow.json") // ※ 認証情報のファイル名修正
            .build();
    DialogFlow dialogflow = DialogFlow(authGoogle: authGoogle, language: "ja"); // ※ 日本語に変更
    AIResponse aiResponse = await dialogflow.detectIntent(query);
    setState(() {
      messsages.insert(0, {
        "data": 0,
        "message": aiResponse.getListMessage()![0]["text"]["text"][0].toString() // ※ 修正
      });
    });
  }

  @override
     << 省略 >>
  }

  Widget chat(String message, int data) {
    return Padding(
      padding: EdgeInsets.all(10.0),
      child: Bubble(
          radius: Radius.circular(15.0),
          color: data == 0 ? Colors.blue : Colors.orangeAccent,
          elevation: 0.0,
          alignment: data == 0 ? Alignment.topLeft : Alignment.topRight,
          nip: data == 0 ? BubbleNip.leftBottom : BubbleNip.rightTop,
          child: Padding(
            padding: EdgeInsets.all(2.0),
            child: Row(
              mainAxisSize: MainAxisSize.min,
              children: <Widget>[
                CircleAvatar(
                  backgroundImage: AssetImage(
                      data == 0 ? "assets/bot.png" : "assets/user.png"),
                ),
                SizedBox(
                  width: 10.0,
                ),
                Flexible(
                    child: Text(
                  message,
                  style: TextStyle(
                      color: Colors.white, fontWeight: FontWeight.bold),
                ))
              ],
            ),
          )),
    );
  }
}

ボットとユーザを示すための適当なアイコンイメージをassetsフォルダ内にコピーします。また、先ほどダウンロードしておいたサービスアカウントの認証情報をassetsフォルダにコピーしておきます。

pubspec.yamlのアセット部分を以下のように変更します。

  assets:
    - assets/user.png  //適当なユーザアイコンイメージ
    - assets/bot.png  //適当なボットアイコンイメージ
   
    - assets/dialogflow.json

以上で、dialogflowを使ったチャットボットの完成です。

Dialogflowパラメータの取得

dialogflowでは、検出したインテントごとにaction名を定義したり、場所や数量といったパラメータを設定し、検出することもできます。

エージェント内で設定したアクション名とパラメータ値の基本的な取得方法は以下の通りです。例として、@sys.personを検出して、parameter personに設定した時のコードを以下に記します。これらのパラメータを上手く検出するためには、各インテントのTraining phrasesで例文を入力してトレーニングさせる必要があります。

AIResponse aiResponse = await dialogflow.detectIntent(query);

action = aiResponse.queryResult!.action.toString();

parameters = aiResponse.queryResult!.parameters;
if (parameters != null) {
    if (parameters!["person"] != null) {
         person = parameters!["person"]!["name"];
    }
}