FlutterアプリでDialogflow APIを使う(dialogflow_flutter)
以前ご紹介した音声チャットボットアプリでは、全てのユーザ発話を応答生成サーバに送ってボットの応答を得ていました。実用的な応答を得るためには、会話の流れを制御する必要性も出てきます。
もちろん、クライアントアプリ側で制御しても良いのですが、メンテナンスが大変なのでDialogflowを使うことにします。
必要なのは、① Dialogflowを呼び出すクライアントアプリ、② 会話を制御するDialogflowエージェント、③ Dialogflowからのwebhookを受け取るサーバ、④応答生成サーバ の、4つとなります。
実は、この構成については既に以下の記事で書いています。
この時には、以下の構成の、
<LINE> ー <Dialogflow> ー <heroku> ー <VPS>
<heroku>をChaliceを使って<Lambda>に置き換えました。また、別の記事で<VPS>をSAMを使って<Lambda>に置き換えました。
従って今は、以下のようになっています。
①<LINE> ー② <Dialogflow> ー ③<Lambda> ー ④<Lambda>
今回は、<LINE>をflutteアプリに置き換えていきます。
DialogflowはGoogleのAIスピーカと繋ぐためにも使っていたのですが、先日のGoogleからの発表で、これが2023年6月には使えなくなるそうです。
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"];
}
}