בניית בוטים קוליים ל-Android עם Dialogflow Essentials & רופפים

1. לפני שמתחילים

ב-Codelab הזה תלמדו איך לשלב טקסט ובוט קולי פשוט של Dialogflow Essentials (ES) באפליקציית Flutter. Dialogflow ES היא חבילת פיתוח לפיתוח ממשקי משתמש של שיחות. לדוגמה, צ'אט בוטים, בוטים קוליים, שערים לטלפונים. תוכלו ליצור אותו באמצעות אותו כלי, ואפילו לתמוך בכמה ערוצים ביותר מ-20 שפות שונות. אפליקציית Dialogflow משתלבת עם הרבה פלטפורמות שיחה פופולריות, כמו Google Assistant, Slack ו-Facebook Messenger. אם אתם רוצים לפתח סוכן לאחת מהפלטפורמות האלה, אתם צריכים להשתמש באחת מאפשרויות השילובים הרבות. אבל כדי ליצור צ'אט בוט למכשירים ניידים, תצטרכו ליצור שילוב מותאם אישית. כדי ליצור כוונות, מזינים ביטויים לאימון כדי לאמן מודל בסיסי של למידת מכונה.

שיעור ה-Lab הזה מתוכנן לשקף חוויה נפוצה של מפתחי ענן:

  1. הגדרת סביבה
  • Dialogflow: יצירת נציג Dialogflow ES חדש
  • Dialogflow: הגדרה ב-Dialogflow
  • Google Cloud: יצירת חשבון שירות
  1. Flutter: פיתוח אפליקציה לצ'אט
  • יצירת פרויקט של Flutter
  • קביעת ההגדרות וההרשאות
  • הוספת יחסי התלות
  • קישור לחשבון השירות
  • הרצת האפליקציה במכשיר וירטואלי או במכשיר פיזי
  1. Flutter: פיתוח ממשק הצ'אט עם תמיכה 'המרת דיבור לטקסט'
  • יצירת הממשק של הצ'אט
  • קישור של ממשק הצ'אט
  • שילוב של חבילת Dialogflow gRPC באפליקציה
  1. Dialogflow: בניית מודלים של סוכן Dialogflow
  • הגדרת קבלת הפנים Intents חלופיים
  • שימוש במאגר ידע של שאלות נפוצות

דרישות מוקדמות

  • חוויה בסיסית של הטלת חיצים וכדורים מתנפצים
  • חוויית משתמש בסיסית ב-Google Cloud Platform
  • חוויה בסיסית עם Dialogflow ES

מה תפַתחו

בשיעור הזה תלמדו איך ליצור בוט שאלות נפוצות לנייד, שיכול לענות על השאלות הנפוצות ביותר לגבי הכלי Dialogflow. כדי לקבל תשובות, משתמשי הקצה יכולים לבצע פעולות בממשק הטקסט או לשדר קול באמצעות המיקרופון המובנה במכשיר נייד.

מה תלמדו

  • איך יוצרים צ'אט בוט באמצעות Dialogflow Essentials
  • איך משלבים את Dialogflow באפליקציה Flutter עם חבילת gRPC של Dialogflow
  • איך מזהים כוונות טקסט באמצעות Dialogflow
  • איך לשדר קול דרך המיקרופון ל-Dialogflow
  • איך להשתמש במחבר של מאגר הידע כדי לייבא שאלות נפוצות ציבוריות
  • בדיקת הצ'אט בוט באמצעות ממשק הטקסט והממשק הקולי במכשיר וירטואלי או פיזי

למה תזדקק?

  • כדי ליצור נציג ב-Dialogflow צריך כתובת ב-Google Identity או ב-Gmail.
  • נדרשת גישה ל-Google Cloud Platform כדי להוריד חשבון שירות
  • סביבת Flutter dev

הגדרת הסביבה של Flutter dev

  1. בוחרים את מערכת ההפעלה שבה מתקינים את Flutter.
  1. אתם יכולים לבנות אפליקציות עם Flutter באמצעות כל עורך טקסט בשילוב עם כלי שורת הפקודה שלנו. עם זאת, בסדנה הזאת ייעשה שימוש ב-Android Studio. יישומי הפלאגין Flutter ו-Dart ל-Android Studio מספקים השלמת קוד, הדגשת תחביר, עזרה לעריכת ווידג'טים, הרצה תמיכה בניפוי באגים ועוד. מבצעים את השלבים שמפורטים בכתובת https://flutter.dev/docs/get-started/editor.

2. הגדרת סביבה

Dialogflow: יצירת נציג Dialogflow ES חדש

  1. פותחים את .
  2. בסרגל הימני, מתחת ללוגו, בוחרים באפשרות יצירת נציג חדש בתפריט הנפתח. (שימו לב, אל תלחצו על התפריט הנפתח 'Global', כי אנחנו זקוקים למופע של Dialogflow שהוא גלובלי כדי להשתמש במאגר הידע של שאלות נפוצות).
  3. בחירת שם הנציג yourname-dialogflow (באמצעות השם שלך)
  4. כשפת ברירת המחדל, בוחרים באפשרות אנגלית – en.
  5. כאזור הזמן שמוגדר כברירת מחדל, בוחרים את אזור הזמן הקרוב ביותר אליכם.
  6. לא בוחרים באפשרות Mega Agent. (בעזרת התכונה הזו אפשר ליצור סוכן מקיף שיכול לתזמר בין סוכני "תת". אנחנו לא צריכים את זה עכשיו.)
  7. לוחצים על יצירה.

מסך יצירת פרויקט חדש

הגדרת Dialogflow

  1. בתפריט הימני, לוחצים על סמל גלגל השיניים ליד שם הפרויקט.

יצירת תפריט נפתח חדש לפרויקט

  1. מזינים את תיאור הנציג הבא: Dialogflow questions Chatbot
  2. הפעלת תכונות הבטא, הופכים את המתג.

Dialogflow Essentials V2Beta1

  1. לוחצים על הכרטיסייה דיבור ומוודאים שהתיבה התאמה אוטומטית של דיבור מופעלת.
  2. אפשר גם להחליף את המתג הראשון כדי לשפר את מודל הדיבור, אבל הוא זמין רק כשמשדרגים את תקופת הניסיון של Dialogflow.
  3. לוחצים על שמירה.

Google Cloud: קבלת חשבון שירות

אחרי שיוצרים נציג ב-Dialogflow, צריך ליצור פרויקט ב-Google Cloud במסוף Google Cloud.

  1. פותחים את מסוף Google Cloud:
  2. מוודאים שמחוברים לאותו חשבון Google כמו ב-Dialogflow, ובוחרים את הפרויקט yourname-dialogflow בסרגל הכחול העליון.
  3. לאחר מכן, מחפשים את Dialogflow API בסרגל הכלים העליון ולוחצים על התוצאה של Dialogflow API בתפריט הנפתח.

הפעלת Dialogflow API

  1. לוחצים על לחצן ניהול הכחול ואז על פרטי כניסה בסרגל התפריטים הימני. (כש-Dialogflow לא מופעל עדיין, צריך קודם ללחוץ על הפעלה)

מסוף GCP של פרטי כניסה

  1. לוחצים על Create credentials (בראש המסך) ובוחרים באפשרות Service account (חשבון שירות).

יצירת פרטי כניסה

  1. מציינים שם לחשבון השירות: flutter_dialogflow, מזהה ותיאור, ולוחצים על יצירה.

יצירה של חשבון שירות

  1. בשלב 2, בוחרים את התפקיד: Dialogflow API Admin, לוחצים על Continue (המשך) ואז על Done (סיום).
  2. לוחצים על חשבון השירות flutter_dialogflow, לוחצים על הכרטיסייה מפתחות ואז על הוספת מפתח > יצירת מפתח חדש

יצירת מפתח

  1. יוצרים מפתח JSON. צריך לשנות את השם שלו ל-credentials.json ולאחסן אותו במקום מאובטח בכונן הקשיח. נשתמש בה בהמשך.

מפתח JSON

מעולה, כל הכלים שאנחנו צריכים מוגדרים כראוי. עכשיו אפשר להתחיל בשילוב של Dialogflow באפליקציה שלנו!

3. Flutter: פיתוח האפליקציה ל-Chat

יצירת אפליקציית Boilerplate

  1. פותחים את Android Studio ובוחרים באפשרות התחלת פרויקט חדש של Flutter.
  2. בוחרים את סוג הפרויקט Flutter Application. לאחר מכן לוחצים על 'הבא'.
  3. מוודאים שהנתיב של Flutter SDK מציין את מיקום ה-SDK (יש לבחור באפשרות 'התקנת SDK...' אם שדה הטקסט ריק).
  4. נותנים שם לפרויקט (לדוגמה, flutter_dialogflow_agent). לאחר מכן לוחצים על הבא.
  5. משנים את שם החבילה ולוחצים על סיום.

יצירת אפליקציה חדשה של Flutter

כך ייווצר אפליקציה לדוגמה עם רכיבי Material.

ממתינים עד ש-Android Studio יתקין את ה-SDK ותיצור את הפרויקט.

הגדרות אישורים

  1. ספריית הקלטת האודיו sound_stream שבה נשתמש, מחייבת minSdk של 21 לפחות. בואו נשנה את ההגדרה הזו ב-android/app/build.gradle בבלוק defaultConfig. (שימו לב שבתיקיית Android יש 2 קובצי build.gradle, אבל הקובץ בתיקיית האפליקציה הוא הקובץ הנכון).
defaultConfig {
   applicationId "com.myname.flutter_dialogflow_agent"
   minSdkVersion 21
   targetSdkVersion 30
   versionCode flutterVersionCode.toInteger()
   versionName flutterVersionName
}
  1. כדי לתת הרשאות למיקרופון וגם לאפשר לאפליקציה ליצור קשר עם הנציג של Dialogflow שפועל בענן, נצטרך להוסיף את ההרשאות INTERNET ו-RECORD_AUDIO לקובץ app/src/main/AndroidManifest.xml. בפרויקט Flutter יש כמה קובצי AndroidManifest.xml, אבל יהיה צורך בקובץ שנמצא בתיקייה הראשית. אפשר להוסיף את השורות ישירות בתוך תגי המניפסט.
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.RECORD_AUDIO" />

הוספת יחסי התלות

נשתמש בחבילות sound_stream, rxdart ו-dialogflow_grpc.

  1. הוספת התלות sound_stream
$ flutter pub add sound_stream
Resolving dependencies...
  async 2.8.1 (2.8.2 available)
  characters 1.1.0 (1.2.0 available)
  matcher 0.12.10 (0.12.11 available)
+ sound_stream 0.3.0
  test_api 0.4.2 (0.4.5 available)
  vector_math 2.1.0 (2.1.1 available)
Downloading sound_stream 0.3.0...
Changed 1 dependency!
  1. הוספת התלות dialogflow_grpc
flutter pub add dialogflow_grpc
Resolving dependencies...
+ archive 3.1.5
  async 2.8.1 (2.8.2 available)
  characters 1.1.0 (1.2.0 available)
+ crypto 3.0.1
+ dialogflow_grpc 0.2.9
+ fixnum 1.0.0
+ googleapis_auth 1.1.0
+ grpc 3.0.2
+ http 0.13.4
+ http2 2.0.0
+ http_parser 4.0.0
  matcher 0.12.10 (0.12.11 available)
+ protobuf 2.0.0
  test_api 0.4.2 (0.4.5 available)
+ uuid 3.0.4
  vector_math 2.1.0 (2.1.1 available)
Downloading dialogflow_grpc 0.2.9...
Downloading grpc 3.0.2...
Downloading http 0.13.4...
Downloading archive 3.1.5...
Changed 11 dependencies!
  1. הוספת התלות rxdart
$ flutter pub add rxdart
Resolving dependencies...
  async 2.8.1 (2.8.2 available)
  characters 1.1.0 (1.2.0 available)
  matcher 0.12.10 (0.12.11 available)
+ rxdart 0.27.2
  test_api 0.4.2 (0.4.5 available)
  vector_math 2.1.0 (2.1.1 available)
Downloading rxdart 0.27.2...
Changed 1 dependency!

פרטי חשבון השירות והפרויקט ב-Google Cloud בטעינה

  1. בפרויקט, יוצרים ספרייה ונותנים לה את השם: assets.
  2. מעבירים את הקובץ credentials.json שהורדתם ממסוף Google Cloud אל התיקייה assets.
  3. פותחים את pubspec.yaml ומוסיפים את חשבון השירות לבלוק Flutter.
flutter:
  uses-material-design: true
  assets:
    - assets/credentials.json

הרצת האפליקציה במכשיר פיזי

כשיש לכם מכשיר Android, אתם יכולים לחבר את הטלפון באמצעות כבל USB וניפוי באגים במכשיר. פועלים לפי השלבים האלה כדי להגדיר את התכונה דרך המסך אפשרויות למפתחים במכשיר Android.

הרצת האפליקציה על מכשיר וירטואלי

כדי להפעיל את האפליקציה במכשיר וירטואלי, מבצעים את השלבים הבאים:

  1. לוחצים על כלים > מנהל AVD. (אפשר גם לבחור את מנהל ה-AVD מסרגל הכלים העליון. באיור שלמטה הוא מודגש בורוד)

סרגל הכלים העליון של Android Studio

  1. אנחנו ניצור מכשיר יעד וירטואלי של Android, כדי שנוכל לבדוק את האפליקציה שלנו ללא מכשיר פיזי. מידע נוסף זמין במאמר ניהול קובצי AVD. אחרי שבוחרים מכשיר וירטואלי חדש, אפשר ללחוץ עליו לחיצה כפולה כדי להפעיל אותו.

ניהול פריטי AVD

מכשיר וירטואלי

  1. בסרגל הכלים הראשי של Android Studio, בוחרים מכשיר Android כיעד דרך התפריט הנפתח ומוודאים שהתיבה main.dart מסומנת. לאחר מכן לוחצים על לחצן הפעלה (משולש ירוק).

היומנים יופיעו בחלק התחתון של סביבת הפיתוח המשולבת (IDE) במסוף. תוכלו לראות שהתקנתם את Android ואת אפליקציית Flutter לתחילת הפעולה. זה ייקח דקה, ברגע שהמכשיר הווירטואלי יהיה מוכן, השינויים יהיו מהירים מאוד. בסיום התהליך, תיפתח האפליקציה לתחילת פעולה ב-Flutter.

אפליקציית Boilerplate

  1. נפעיל את המיקרופון לאפליקציית הצ'אט בוט שלנו. לוחצים על הלחצן options (אפשרויות) במכשיר הווירטואלי כדי לפתוח את האפשרויות. בכרטיסייה 'מיקרופון', מפעילים את כל 3 המתגים.

אפשרויות AVD

  1. ננסה את 'טעינה חמה מחדש' כדי להדגים איך אפשר לבצע שינויים במהירות.

ב-lib/main.dart, משנים את הכותרת MyHomePage במחלקה MyApp ל: Flutter Dialogflow Agent. ומשנים את primarySwatch ל-Colors.orange.

קוד ראשון

שומרים את הקובץ או לוחצים על סמל הבורג בסרגל הכלים של Android Studio. השינוי אמור להופיע ישירות במכשיר הווירטואלי.

4. Flutter: פיתוח ממשק Chat בעזרת STT

יצירת הממשק של הצ'אט

  1. יוצרים קובץ ווידג'טFlutter חדש בתיקייה lib. (לוחצים לחיצה ימנית על תיקיית lib, New > Flutter Widget > Stateful widget), קוראים לקובץ הזה: chat.dart

מדביקים את הקוד הבא בקובץ הזה. קובץ ה-Dart הזה יוצר את ממשק הצ'אט. Dialogflow לא פועל עדיין, אלא רק הפריסה של כל הרכיבים והשילוב של רכיב המיקרופון כדי לאפשר סטרימינג. התגובות בקובץ יציינו את השלב שבו נשלב את Dialogflow.

// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:rxdart/rxdart.dart';
import 'package:sound_stream/sound_stream.dart';

// TODO import Dialogflow


class Chat extends StatefulWidget {
  Chat({Key key}) : super(key: key);

  @override
  _ChatState createState() => _ChatState();
}

class _ChatState extends State<Chat> {
  final List<ChatMessage> _messages = <ChatMessage>[];
  final TextEditingController _textController = TextEditingController();

  bool _isRecording = false;

  RecorderStream _recorder = RecorderStream();
  StreamSubscription _recorderStatus;
  StreamSubscription<List<int>> _audioStreamSubscription;
  BehaviorSubject<List<int>> _audioStream;

  // TODO DialogflowGrpc class instance

  @override
  void initState() {
    super.initState();
    initPlugin();
  }

  @override
  void dispose() {
    _recorderStatus?.cancel();
    _audioStreamSubscription?.cancel();
    super.dispose();
  }

  // Platform messages are asynchronous, so we initialize in an async method.
  Future<void> initPlugin() async {
    _recorderStatus = _recorder.status.listen((status) {
      if (mounted)
        setState(() {
          _isRecording = status == SoundStreamStatus.Playing;
        });
    });

    await Future.wait([
      _recorder.initialize()
    ]);



    // TODO Get a Service account

  }

  void stopStream() async {
    await _recorder.stop();
    await _audioStreamSubscription?.cancel();
    await _audioStream?.close();
  }

  void handleSubmitted(text) async {
    print(text);
    _textController.clear();

    //TODO Dialogflow Code

  }

  void handleStream() async {
    _recorder.start();

    _audioStream = BehaviorSubject<List<int>>();
    _audioStreamSubscription = _recorder.audioStream.listen((data) {
      print(data);
      _audioStream.add(data);
    });


    // TODO Create SpeechContexts
    // Create an audio InputConfig

    // TODO Make the streamingDetectIntent call, with the InputConfig and the audioStream
    // TODO Get the transcript and detectedIntent and show on screen

  }

  // The chat interface
  //
  //------------------------------------------------------------------------------------
  @override
  Widget build(BuildContext context) {
    return Column(children: <Widget>[
      Flexible(
          child: ListView.builder(
            padding: EdgeInsets.all(8.0),
            reverse: true,
            itemBuilder: (_, int index) => _messages[index],
            itemCount: _messages.length,
          )),
      Divider(height: 1.0),
      Container(
          decoration: BoxDecoration(color: Theme.of(context).cardColor),
          child: IconTheme(
            data: IconThemeData(color: Theme.of(context).accentColor),
            child: Container(
              margin: const EdgeInsets.symmetric(horizontal: 8.0),
              child: Row(
                children: <Widget>[
                  Flexible(
                    child: TextField(
                      controller: _textController,
                      onSubmitted: handleSubmitted,
                      decoration: InputDecoration.collapsed(hintText: "Send a message"),
                    ),
                  ),
                  Container(
                    margin: EdgeInsets.symmetric(horizontal: 4.0),
                    child: IconButton(
                      icon: Icon(Icons.send),
                      onPressed: () => handleSubmitted(_textController.text),
                    ),
                  ),
                  IconButton(
                    iconSize: 30.0,
                    icon: Icon(_isRecording ? Icons.mic_off : Icons.mic),
                    onPressed: _isRecording ? stopStream : handleStream,
                  ),
                ],
              ),
            ),
          )
      ),
    ]);
  }
}


//------------------------------------------------------------------------------------
// The chat message balloon
//
//------------------------------------------------------------------------------------
class ChatMessage extends StatelessWidget {
  ChatMessage({this.text, this.name, this.type});

  final String text;
  final String name;
  final bool type;

  List<Widget> otherMessage(context) {
    return <Widget>[
      new Container(
        margin: const EdgeInsets.only(right: 16.0),
        child: CircleAvatar(child: new Text('B')),
      ),
      new Expanded(
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: <Widget>[
            Text(this.name,
                style: TextStyle(fontWeight: FontWeight.bold)),
            Container(
              margin: const EdgeInsets.only(top: 5.0),
              child: Text(text),
            ),
          ],
        ),
      ),
    ];
  }

  List<Widget> myMessage(context) {
    return <Widget>[
      Expanded(
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.end,
          children: <Widget>[
            Text(this.name, style: Theme.of(context).textTheme.subtitle1),
            Container(
              margin: const EdgeInsets.only(top: 5.0),
              child: Text(text),
            ),
          ],
        ),
      ),
      Container(
        margin: const EdgeInsets.only(left: 16.0),
        child: CircleAvatar(
            child: Text(
              this.name[0],
              style: TextStyle(fontWeight: FontWeight.bold),
            )),
      ),
    ];
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      margin: const EdgeInsets.symmetric(vertical: 10.0),
      child: Row(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: this.type ? myMessage(context) : otherMessage(context),
      ),
    );
  }
}

חיפוש בקובץ chat.dart בנושא בניית ווידג'ט. המערכת יוצרת את הממשק של הצ'אט בוט, שכולל:

  • ListView מכילה את כל בלוני הצ'אט של המשתמש והצ'אט בוט. הם משתמשים בכיתה ב-ChatMessage, שיוצרת הודעות צ'אט עם דמות וטקסט.
  • TextField להזנת שאילתות טקסט
  • IconButton עם סמל השליחה, לשליחת שאילתות טקסט ל-Dialogflow
  • IconButton עם מיקרופון לשליחת שידורי אודיו ל-Dialogflow, שמשנה את המצב אחרי שלוחצים עליו.

קישור של ממשק הצ'אט

  1. פותחים את main.dart ומשנים את Widget build, כך שהוא רק יוצר את הממשק של Chat(). אפשר להסיר את כל שאר קודי ההדגמה.
import 'package:flutter/material.dart';
import 'chat.dart';

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

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        // This is the theme of your application.
        //
        // Try running your application with "flutter run". You'll see the
        // application has a blue toolbar. Then, without quitting the app, try
        // changing the primarySwatch below to Colors.green and then invoke
        // "hot reload" (press "r" in the console where you ran "flutter run",
        // or simply save your changes to "hot reload" in a Flutter IDE).
        // Notice that the counter didn't reset back to zero; the application
        // is not restarted.
        primarySwatch: Colors.orange,
      ),
      home: MyHomePage(title: 'Flutter Dialogflow Agent'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  // This widget is the home page of your application. It is stateful, meaning
  // that it has a State object (defined below) that contains fields that affect
  // how it looks.

  // This class is the configuration for the state. It holds the values (in this
  // case the title) provided by the parent (in this case the App widget) and
  // used by the build method of the State. Fields in a Widget subclass are
  // always marked "final".

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    // This method is rerun every time setState is called, for instance as done
    // by the _incrementCounter method above.
    //
    // The Flutter framework has been optimized to make rerunning build methods
    // fast, so that you can just rebuild anything that needs updating rather
    // than having to individually change instances of widgets.
    return Scaffold(
      appBar: AppBar(
        // Here we take the value from the MyHomePage object that was created by
        // the App.build method, and use it to set our appbar title.
        title: Text(widget.title),
      ),
      body: Center(
        // Center is a layout widget. It takes a single child and positions it
        // in the middle of the parent.
        child: Chat())
    );
  }
}
  1. מפעילים את האפליקציה. (אם האפליקציה הופעלה לפני כן. מפסיקים את המכשיר הווירטואלי ומפעילים מחדש את Main.dart). כשמריצים את האפליקציה עם ממשק הצ'אט בפעם הראשונה. ייפתח חלון קופץ עם שאלה אם אתם רוצים לאשר את המיקרופון. קליק: בזמן השימוש באפליקציה.

הרשאות

  1. משחקים עם אזור הטקסט והלחצנים. כשמקלידים שאילתת טקסט ומקישים על Enter או מקישים על לחצן השליחה, שאילתת הטקסט מופיעה בכרטיסייה הפעלה ב-Android Studio. כשמקישים על לחצן המיקרופון ומפסיקים אותו, שידור האודיו מופיע בכרטיסייה הפעלה.

היומן של שידור האודיו

מעולה! עכשיו אנחנו מוכנים לשלב את האפליקציה עם Dialogflow!

שילוב אפליקציית Flutter עם Dialogflow_gRPC

  1. פותחים את chat.dart ומוסיפים את פעולות הייבוא הבאות:
import 'package:dialogflow_grpc/dialogflow_grpc.dart';
import 'package:dialogflow_grpc/generated/google/cloud/dialogflow/v2beta1/session.pb.dart';
  1. בחלק העליון של הקובץ, מתחת ל-// TODO DialogflowGrpcV2Beta1 class instance, מוסיפים את השורה הבאה, כדי להחזיק את המכונה של המחלקה של Dialogflow:
DialogflowGrpcV2Beta1 dialogflow;
  1. מחפשים את השיטה initPlugin() ומוסיפים את הקוד הבא, ישירות מתחת לתגובה של TODO:
    // Get a Service account
    final serviceAccount = ServiceAccount.fromString(
        '${(await rootBundle.loadString('assets/credentials.json'))}');
    // Create a DialogflowGrpc Instance
    dialogflow = DialogflowGrpcV2Beta1.viaServiceAccount(serviceAccount);

הפעולה הזו תיצור מכונה של Dialogflow עם הרשאה לפרויקט ב-Google Cloud באמצעות חשבון השירות. (חשוב לוודא שהשדה credentials.json נמצא בתיקייה assets!)

שוב, להדגמה לגבי אופן העבודה עם Dialogflow gRPC זה בסדר, אבל באפליקציות בסביבת ייצור מומלץ לא לאחסן את קובץ Credentials.json בתיקיית הנכסים, כי השימוש הזה לא נחשב מאובטח.

ביצוע קריאה לזיהוי Intent

  1. עכשיו אפשר למצוא את השיטה handleSubmitted(), וכאן נכנס לתמונה הקסם. מתחת לתגובה מסוג TODO, מוסיפים את הקוד הבא.הקוד הזה יוסיף את ההודעה המוקלדת של המשתמש ל-ListView:
ChatMessage message = ChatMessage(
 text: text,
 name: "You",
 type: true,
);

setState(() {
 _messages.insert(0, message);
});
  1. עכשיו, ממש מתחת לקוד הקודם, נבצע את הקריאה של Intent, נעביר את הטקסט מהקלט וקוד שפה. - התוצאה (בתוך data.queryResult.fulfillment) תודפס ב-ListView:
DetectIntentResponse data = await dialogflow.detectIntent(text, 'en-US');
String fulfillmentText = data.queryResult.fulfillmentText;
if(fulfillmentText.isNotEmpty) {
  ChatMessage botMessage = ChatMessage(
    text: fulfillmentText,
    name: "Bot",
    type: false,
  );

  setState(() {
    _messages.insert(0, botMessage);
  });
}
  1. מפעילים את המכשיר הווירטואלי ובודקים את הבקשה לזיהוי Intent. סוג: hi. המשתמש אמור לראות את הודעת הפתיחה שמוגדרת כברירת מחדל. כשמקלידים משהו אחר, הפונקציה מחזירה את ברירת המחדל של החלופה.

ביצוע קריאה של StreamingDetectIntent

  1. עכשיו אפשר למצוא את השיטה handleStream(), וכאן נכנס כל הקסם של סטרימינג של אודיו. ראשונה: במשימה הראשונה לביצוע משימות, יוצרים InputConfigV2beta1 אודיו עם biasList כדי להטות את תבנית הקול. מכיוון שאנחנו משתמשים בטלפון (מכשיר וירטואלי), הדגימה Hertz תהיה 16000 והקידוד יהיה ליניארי 16. הדבר תלוי בחומרה או במיקרופון של המכונה שבהם משתמשים. עבור המיקרופון הפנימי של Macbook, 16000 היה טוב. (מידע נוסף על החבילה https://pub.dev/packages/sound_stream)
var biasList = SpeechContextV2Beta1(
    phrases: [
      'Dialogflow CX',
      'Dialogflow Essentials',
      'Action Builder',
      'HIPAA'
    ],
    boost: 20.0
);

    // See: https://cloud.google.com/dialogflow/es/docs/reference/rpc/google.cloud.dialogflow.v2#google.cloud.dialogflow.v2.InputAudioConfig
var config = InputConfigV2beta1(
    encoding: 'AUDIO_ENCODING_LINEAR_16',
    languageCode: 'en-US',
    sampleRateHertz: 16000,
    singleUtterance: false,
    speechContexts: [biasList]
);
  1. בשלב הבא ניתן לקרוא ל-method streamingDetectIntent באובייקט dialogflow, שבו נמצא הסשן שלנו ב-Dialogflow:
final responseStream = dialogflow.streamingDetectIntent(config, _audioStream);
  1. באמצעות ה-ResponseStream, אנחנו יכולים סוף סוף להאזין לתמליל הנכנס, לשאילתה של המשתמש שזוהתה ולתגובה שזוהתה עם כוונה תואמת. נדפיס את התמונה הזו בChatMessage על המסך:
// Get the transcript and detectedIntent and show on screen
responseStream.listen((data) {
  //print('----');
  setState(() {
    //print(data);
    String transcript = data.recognitionResult.transcript;
    String queryText = data.queryResult.queryText;
    String fulfillmentText = data.queryResult.fulfillmentText;

    if(fulfillmentText.isNotEmpty) {

      ChatMessage message = new ChatMessage(
        text: queryText,
        name: "You",
        type: true,
      );

      ChatMessage botMessage = new ChatMessage(
        text: fulfillmentText,
        name: "Bot",
        type: false,
      );

      _messages.insert(0, message);
      _textController.clear();
      _messages.insert(0, botMessage);

    }
    if(transcript.isNotEmpty) {
      _textController.text = transcript;
    }

  });
},onError: (e){
  //print(e);
},onDone: () {
  //print('done');
});

זהו, מפעילים את האפליקציה ובודקים אותה במכשיר הווירטואלי, לוחצים על לחצן המיקרופון ואומרים: "Hello".

הפעולה הזו תפעיל את כוונת ברירת המחדל למשתמשים חדשים ב-Dialogflow. התוצאות יודפסו על המסך. עכשיו, ש-Flutter עובד מצוין עם השילוב של Dialogflow, אנחנו יכולים להתחיל לעבוד על שיחת הצ'אט בוט שלנו.

5. Dialogflow: יצירת מודלים של הסוכן Dialogflow

Dialogflow Essentials היא חבילת פיתוח לפיתוח ממשקים של שיחות. לדוגמה, צ'אט בוטים, בוטים קוליים, שערים לטלפונים. תוכלו ליצור אותו באמצעות אותו כלי, ואפילו לתמוך בכמה ערוצים ביותר מ-20 שפות שונות. מעצבי חוויית המשתמש של Dialogflow (נציגי בניית מודלים, שפה) או יוצרים כוונות יוצרים כוונות על ידי ציון ביטויי אימון לאימון מודל בסיסי של למידת מכונה.

Intent מסווג את כוונת המשתמש. לכל סוכן Dialogflow ES אפשר להגדיר כמה כוונות, שבהן הכוונות המשולבות יכולות לטפל בשיחה שלמה. כל Intent יכול להכיל פרמטרים ותגובות.

התאמה של כוונת רכישה נקראת גם 'סיווג כוונת רכישה' או 'התאמה של כוונת רכישה'. זהו הקונספט העיקרי ב-Dialogflow ES. לאחר התאמה של Intent, הוא יכול להחזיר תשובה, לאסוף פרמטרים (חילוץ ישויות) או להפעיל קוד webhook (מילוי), לדוגמה, כדי לאחזר נתונים ממסד נתונים.

כשמשתמש קצה כותב או אומר משהו בצ'אט בוט, שנקרא הביטוי או הביטוי של המשתמש, Dialogflow ES מתאים את הביטוי לכוונה הטובה ביותר של הנציג ב-Dialogflow, על סמך הביטויים לאימון. מודל למידת המכונה של Dialogflow ES אומן לפי ביטויי האימון האלה.

Dialogflow ES עובד עם קונספט שנקרא הקשר. בדיוק כמו בן אדם, Dialogflow ES יכול לזכור את ההקשר בפנייה השנייה והשלישית. כך הוא יכול לעקוב אחר ביטויים קודמים של משתמשים.

מידע נוסף על מנגנוני Intent של Dialogflow

שינוי של Intent הודעת הפתיחה שמוגדר כברירת מחדל

כשיוצרים נציג חדש ב-Dialogflow, המערכת יוצרת באופן אוטומטי שני אובייקטים מסוג Intent שמוגדרים כברירת מחדל. ברירת המחדל של כוונת הרכישה היא התהליך הראשון שאליו מגיעים כשמתחילים שיחה עם הנציג. ברירת המחדל של Intent חלופי היא הזרימה שאתם מקבלים ברגע שהנציג לא יכול להבין אתכם או לא יכול להתאים לכוונה למה שאמרתם.

זו הודעת הפתיחה לגבי ברירת המחדל של Intent קבלת הפנים:

משתמש

נציג

שלום

"היי, אני בוט השאלות הנפוצות של Dialogflow. אוכל לענות על שאלות ב-Dialogflow".

"מה ברצונך לדעת?"

  1. לוחצים על Intents > ברירת המחדל של כוונת הרכישה של ה-Intent
  2. גוללים למטה אל תגובות.
  3. ניקוי כל תגובות הטקסט.
  4. בכרטיסיית ברירת המחדל, יוצרים את 2 התגובות הבאות:
  • היי, אני בוט השאלות הנפוצות של Dialogflow. אוכל לענות על שאלות ב-Dialogflow. מה ברצונך לדעת?
  • היי, אני הבוט של השאלות הנפוצות ב-Dialogflow. יש לך שאלות לגבי Dialogflow? איך אפשר לעזור?

ההגדרות האישיות אמורות להיות דומות לצילום המסך הזה.

עריכה של ברירת המחדל של Intent הודעת הפתיחה

  1. לוחצים על שמירה.
  2. בואו נבדוק את הכוונה הזו. קודם כל, אפשר לבדוק את זה ב-Dialogflow Plugin.Type: Hello. אמורה להתקבל אחת מההודעות הבאות:
  • היי, אני בוט השאלות הנפוצות של Dialogflow. אוכל לענות על שאלות ב-Dialogflow. מה ברצונך לדעת?
  • היי, אני הבוט של השאלות הנפוצות ב-Dialogflow. יש לך שאלות לגבי Dialogflow? איך אפשר לעזור?

שינוי ה-Intent המוגדר כברירת מחדל כחלופה

  1. לוחצים על Intents > ברירת מחדל של Intent חלופי
  2. גוללים למטה אל תגובות.
  3. ניקוי כל תגובות הטקסט.
  4. בכרטיסיית ברירת המחדל, יוצרים את התגובה הבאה:
  • לצערי איני יודע את התשובה לשאלה הזו. בדקת את האתר שלנו? http://www.dialogflow.com?
  1. לוחצים על שמירה.

התחברות למאגר ידע אונליין

מחברי ידע משלימים כוונות מוגדרות. הם מנתחים מסמכי ידע כדי למצוא תשובות אוטומטיות. (למשל: שאלות נפוצות או מאמרים מקובצי CSV, אתרים באינטרנט ואפילו קובצי PDF!) כדי להגדיר אותם, צריך להגדיר מאגר ידע אחד או יותר, שהם אוספים של מסמכי ידע.

מידע נוסף על מחברי ידע

בואו ננסה את זה.

  1. בוחרים באפשרות ידע (בטא) בתפריט.

מאגר ידע

  1. לוחצים על הלחצן הכחול הימני: יצירת מאגר ידע
  2. להקליד שם של מאגר ידע. שאלות נפוצות על Dialogflow ולוחצים על שמירה.
  3. לוחצים על יצירת הקישור הראשון.

מאגר הידע – הפריט הראשון

  1. פעולה זו תפתח חלון.

משתמשים בהגדרות הבאות:

שם המסמך: DialogflowFAQ סוג ידע: FAQ סוג Mime: text/html

  1. כתובת ה-URL שממנה אנחנו טוענים את הנתונים היא:

https://www.leeboonstra.dev/faqs/

  1. לחץ על צור.

נוצר מאגר ידע:

נוצר מאגר ידע

  1. גוללים למטה לקטע 'תשובות' ולוחצים על הוספת תשובה.

צריך ליצור את התשובות הבאות וללחוץ על שמירה.

$Knowledge.Answer[1]
  1. לוחצים על הצגת פרטים.

להצגת הפרטים

  1. בוחרים באפשרות הפעלת טעינה אוטומטית מחדש כדי לאחזר באופן אוטומטי שינויים כשדף האינטרנט של השאלות הנפוצות מתעדכן, ולוחצים על שמירה.

כאן יוצגו כל השאלות הנפוצות שהטמעת ב-Dialogflow.זה קל!

לידיעתכם, אתם יכולים גם להפנות לאתר HTML אונליין עם שאלות נפוצות כדי לייבא שאלות נפוצות לנציג שלכם. אפשר אפילו להעלות קובץ PDF עם קטע טקסט, ו-Dialogflow יציג שאלות.

עכשיו צריך להתייחס לשאלות הנפוצות כ'תוספות' שצריך להוסיף לנציגים שלכם, ליד כוונתכם. אי אפשר לאמן את המודל באמצעות שאלות נפוצות של מאגר הידע. לכן, יכול להיות שלא תהיה התאמה אם שואלים שאלות בדרך אחרת לגמרי, כי לא נעשה בהן שימוש ב-Natural Language Understanding (מודלים של למידת מכונה). לכן לפעמים כדאי להמיר את השאלות הנפוצות לכוונות.

  1. בודקים את השאלות בסימולטור שמשמאל.
  2. כשהכול יעבוד, חוזרים לאפליקציית Flutter ובודקים את הצ'אט והבוט הקולי עם התוכן החדש. שואלים את השאלות שהעליתם ל-Dialogflow.

תוצאה

6. מזל טוב

כל הכבוד! יצרת את אפליקציית Flutter הראשונה שלך עם שילוב של צ'אט בוט של Dialogflow.

הנושאים שטיפלנו בהם

  • איך יוצרים צ'אט בוט באמצעות Dialogflow Essentials
  • איך משלבים את Dialogflow באפליקציה של Flutter
  • איך מזהים כוונות טקסט באמצעות Dialogflow
  • איך לשדר קול דרך המיקרופון ל-Dialogflow
  • איך להשתמש במחבר של מאגר הידע

מה השלב הבא?

נהנית משיעור ה-Lab הזה של כתיבת קוד? כדאי לראות את שיעורי ה-Lab המעולים האלה של Dialogflow!

רוצים לדעת איך בניתי את חבילת gRPC של Dialogflow ל-Dart/Flutter?