בניית בוטים קוליים ל-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: Building a chat application
  • יצירת פרויקט Flutter
  • הגדרת ההגדרות וההרשאות
  • הוספת יחסי התלות
  • קישור לחשבון השירות.
  • הפעלת האפליקציה במכשיר וירטואלי או במכשיר פיזי
  1. Flutter: Building the chat interface with Speech to Text support
  • יצירת ממשק הצ'אט
  • קישור לממשק הצ'אט
  • שילוב חבילת Dialogflow gRPC באפליקציה
  1. Dialogflow: Modeling the Dialogflow agent
  • הגדרת כוונות הפעולה לשיחת היכרות ולחזרה למצב ראשוני
  • שימוש במאגר ידע של שאלות נפוצות

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

  • ניסיון בסיסי ב-Dart/Flutter
  • ניסיון בסיסי ב-Google Cloud Platform
  • ניסיון בסיסי ב-Dialogflow ES

מה תפַתחו

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

מה תלמדו

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

הדרישות

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

הגדרת סביבת הפיתוח של Flutter

  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 שהוא Global כדי להשתמש במאגר הידע של השאלות הנפוצות).
  3. מציינים שם לסוכן yourname-dialogflow (צריך להשתמש בשם שלכם)
  4. בוחרים באפשרות English - en כשפת ברירת המחדל.
  5. כאזור זמן שמוגדר כברירת מחדל, בוחרים את אזור הזמן שהכי קרוב למיקום שלכם.
  6. לא בוחרים באפשרות Mega Agent. (התכונה הזו מאפשרת ליצור סוכן ראשי שיכול לתאם בין סוכני משנה. אנחנו לא צריכים את זה עכשיו).
  7. לוחצים על יצירה.

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

הגדרת Dialogflow

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

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

  1. מזינים את התיאור הבא של הסוכן: Dialogflow FAQ Chatbot
  2. מפעילים את האפשרות הפעלת תכונות בטא.

Dialogflow Essentials V2Beta1

  1. לוחצים על הכרטיסייה Speech (דיבור) ומוודאים שהתיבה Auto Speech Adaptation (התאמה אוטומטית של דיבור) פעילה.
  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, לוחצים על המשך ואז על סיום.
  2. לוחצים על flutter_dialogflow חשבון שירות, לוחצים על הכרטיסייה מפתחות ואז על הוספת מפתח > יצירת מפתח חדש.

יצירת מפתח

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

מפתח JSON

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

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

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

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

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

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

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

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

  1. ספריית מקליט האודיו sound_stream שבה נשתמש דורשת minSdk של 21 לפחות. לכן נשנה את זה ב-android/app/build.gradle בבלוק defaultConfig. (הערה: יש 2 קבצים בשם build.gradle בתיקיית Android, אבל הקובץ בתיקיית האפליקציה הוא הקובץ הנכון).
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. יש כמה קובצי AndroidManifest.xml בפרויקט Flutter, אבל צריך את הקובץ שנמצא בתיקייה הראשית. אפשר להוסיף את השורות ישירות בתוך תגי המניפסט.
<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. לוחצים על Tools> AVD Manager (כלים > מנהל מכשירים וירטואליים). (או בוחרים באפשרות AVD Manager מסרגל הכלים העליון, באיור שלמטה היא מסומנת בוורוד)

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

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

ניהול מכשירי AVD

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

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

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

אפליקציה שבלונית

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

אפשרויות AVD

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

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

הקוד הראשון

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

4. ‫Flutter: בניית ממשק הצ'אט עם תמיכה ב-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 את Widget build. הפונקציה הזו יוצרת את הממשק של הצ'אטבוט, שכולל:

  • 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 או על לחצן השליחה, שאילתת הטקסט נרשמת בכרטיסייה Run ב-Android Studio. כשמקישים על לחצן המיקרופון ומפסיקים אותו, זרם האודיו מתועד בכרטיסייה Run (הפעלה).

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

מצוין, עכשיו אפשר לשלב את האפליקציה עם 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 עם הרשאה לפרויקט בענן שלכם באמצעות חשבון השירות. (חשוב לוודא שקובץ credentials.json נמצא בתיקייה assets!)

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

ביצוע קריאה ל-detectIntent

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

setState(() {
 _messages.insert(0, message);
});
  1. עכשיו, ממש מתחת לקוד הקודם, נבצע את הקריאה detectIntent, נעביר את הטקסט מהקלט ואת languageCode. ‫– התוצאה (בתוך 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. מפעילים את המכשיר הווירטואלי ובודקים את הקריאה לזיהוי כוונות. סוג: hi. צריכה להופיע הודעת הפתיחה שמוגדרת כברירת מחדל. אם תקלידו משהו אחר, תקבלו את תשובת ברירת המחדל.

ביצוע שיחה ל-streamingDetectIntent

  1. עכשיו מחפשים את השיטה handleStream(). כאן מתרחש הקסם של סטרימינג אודיו. קודם, מיד מתחת למשימה הראשונה, יוצרים קובץ שמע InputConfigV2beta1 עם biasList כדי להטות את תבנית הקול. מכיוון שאנחנו משתמשים בטלפון (מכשיר וירטואלי), הערך של sampleHertz יהיה 16000 והקידוד יהיה Linear 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. לאחר מכן, נפעיל את השיטה 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');
});

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

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

5. ‫Dialogflow: מידול של סוכן Dialogflow

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

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

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

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

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

מידע נוסף על כוונות ב-Dialogflow

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

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

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

משתמש

Agent

שלום

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

"מה תרצה לדעת?"

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

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

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

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

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

  1. לוחצים על Intents > Default Fallback 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 יציע שאלות בעצמו.

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

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

תוצאה

6. מזל טוב

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

מה נכלל

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

מה השלב הבא?

נהניתם מה-Code Lab הזה? כדאי להכיר: מעבדות Dialogflow מעולות

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