Tạo Bot Voice cho Android thông qua Dialogflow Essentials & Xoè

1. Trước khi bắt đầu

Trong lớp học lập trình này, bạn sẽ tìm hiểu cách tích hợp một bot giọng nói và văn bản Dialogflow Essentials (ES) đơn giản vào một ứng dụng Flutter. Dialogflow ES là một bộ phát triển để tạo giao diện người dùng trò chuyện. Do đó, bot trò chuyện, bot thoại, cổng điện thoại. Bạn có thể tạo tất cả bằng cùng một công cụ và thậm chí bạn có thể hỗ trợ nhiều kênh bằng hơn 20 ngôn ngữ khác nhau. Dialogflow tích hợp với nhiều nền tảng trò chuyện phổ biến như Trợ lý Google, Slack và Facebook Messenger. Nếu muốn tạo tác nhân cho một trong các nền tảng này, bạn nên sử dụng một trong nhiều lựa chọn tích hợp. Tuy nhiên, để tạo một chatbot cho thiết bị di động, bạn sẽ phải tạo một chế độ tích hợp tuỳ chỉnh. Bạn sẽ tạo ý định bằng cách chỉ định các cụm từ huấn luyện để huấn luyện một mô hình học máy cơ bản.

Phòng thí nghiệm này được sắp xếp để phản ánh trải nghiệm chung của các nhà phát triển trên đám mây:

  1. Thiết lập môi trường
  • Dialogflow: Tạo một nhân viên hỗ trợ Dialogflow ES mới
  • Dialogflow: Định cấu hình Dialogflow
  • Google Cloud: Tạo tài khoản dịch vụ
  1. Flutter: Xây dựng ứng dụng nhắn tin
  • Tạo một dự án Flutter
  • Định cấu hình các chế độ cài đặt và quyền
  • Thêm phần phụ thuộc
  • Liên kết với tài khoản dịch vụ.
  • Chạy ứng dụng trên thiết bị ảo hoặc thiết bị thực
  1. Flutter: Xây dựng giao diện trò chuyện có hỗ trợ tính năng Chuyển lời nói thành văn bản
  • Tạo giao diện trò chuyện
  • Liên kết giao diện trò chuyện
  • Tích hợp gói gRPC của Dialogflow vào ứng dụng
  1. Dialogflow: Lập mô hình nhân viên hỗ trợ Dialogflow
  • Định cấu hình phần chào mừng & ý định dự phòng
  • Tận dụng cơ sở kiến thức về Câu hỏi thường gặp

Điều kiện tiên quyết

  • Trải nghiệm cơ bản với Dart/Flutter
  • Kinh nghiệm cơ bản về Google Cloud Platform
  • Kinh nghiệm cơ bản về Dialogflow ES

Sản phẩm bạn sẽ tạo ra

Lớp học lập trình này sẽ hướng dẫn bạn cách tạo một bot Câu hỏi thường gặp trên thiết bị di động. Bot này có thể trả lời các câu hỏi phổ biến nhất về công cụ Dialogflow. Người dùng cuối có thể tương tác với giao diện văn bản hoặc phát trực tuyến giọng nói qua micrô tích hợp trên thiết bị di động để nhận câu trả lời.

Kiến thức bạn sẽ học được

  • Cách tạo bot trò chuyện bằng Dialogflow Essentials
  • Cách tích hợp Dialogflow vào một ứng dụng Flutter với gói gRPC của Dialogflow
  • Cách phát hiện ý định văn bản bằng Dialogflow
  • Cách truyền trực tuyến giọng nói qua micrô tới Dialogflow
  • Cách sử dụng trình kết nối cơ sở tri thức để nhập Câu hỏi thường gặp công khai
  • Thử nghiệm bot trò chuyện thông qua giao diện văn bản và giọng nói trong thiết bị thực hoặc ảo

Bạn cần có

  • Bạn cần có một địa chỉ Google Identity / Gmail để tạo nhân viên hỗ trợ Dialogflow.
  • Bạn cần có quyền truy cập vào Google Cloud Platform để tải tài khoản dịch vụ xuống
  • Môi trường dành cho nhà phát triển Flutter

Thiết lập môi trường dành cho nhà phát triển Flutter

  1. Chọn hệ điều hành mà bạn đang cài đặt Flutter.
  1. Bạn có thể tạo ứng dụng bằng Flutter bằng cách sử dụng bất kỳ trình chỉnh sửa văn bản nào kết hợp với các công cụ dòng lệnh của chúng tôi. Tuy nhiên, hội thảo này sẽ sử dụng Android Studio. Các trình bổ trợ Flutter và Dart dành cho Android Studio giúp bạn hoàn thành mã, làm nổi bật cú pháp, hỗ trợ chỉnh sửa tiện ích, chạy và hỗ trợ gỡ lỗi và nhiều tính năng khác. Làm theo các bước trên https://flutter.dev/docs/get-started/editor

2. Thiết lập môi trường

Dialogflow: Tạo một nhân viên hỗ trợ Dialogflow ES mới

  1. Mở
  2. Trên thanh bên trái, bên dưới biểu trưng, hãy chọn "Create New Agent" (Tạo nhân viên hỗ trợ mới) trong trình đơn thả xuống. (Lưu ý: Đừng nhấp vào trình đơn thả xuống có nội dung "Toàn cầu". Chúng tôi cần một phiên bản của Dialogflow là Toàn cầu để tận dụng cơ sở kiến thức về Câu hỏi thường gặp.)
  3. Chỉ định tên nhân viên hỗ trợ yourname-dialogflow (hãy dùng tên của chính bạn)
  4. Làm ngôn ngữ mặc định, hãy chọn Tiếng Anh – en.
  5. Làm múi giờ mặc định, chọn múi giờ gần bạn nhất.
  6. Không chọn Mega Agent. (Với tính năng này, bạn có thể tạo một tác nhân tổng quát để điều phối các tác nhân "phụ". Hiện tại, chúng tôi không cần công cụ này.)
  7. Nhấp vào Tạo.

Màn hình Create new project (Tạo dự án mới)

Định cấu hình Dialogflow

  1. Nhấp vào biểu tượng bánh răng trong trình đơn bên trái, bên cạnh tên dự án.

Trình đơn thả xuống Tạo dự án mới

  1. Nhập nội dung mô tả về nhân viên hỗ trợ sau: Dialogflow Câu hỏi thường gặp về Chatbot
  2. Bật các tính năng thử nghiệm, lật nút chuyển.

Dialogflow Essentials phiên bản 2Beta1

  1. Nhấp vào thẻ Giọng nói và đảm bảo rằng hộp Tự động điều chỉnh lời nói đang hoạt động.
  2. Nếu muốn, bạn cũng có thể bật nút chuyển đầu tiên. Thao tác này sẽ giúp cải thiện Mô hình lời nói, nhưng bạn chỉ dùng được nút này khi nâng cấp bản dùng thử Dialogflow.
  3. Nhấp vào Lưu

Google Cloud: Đăng ký tài khoản dịch vụ

Sau khi tạo nhân viên hỗ trợ trong Dialogflow, bạn sẽ cần tạo một dự án Google Cloud trong bảng điều khiển Google Cloud.

  1. Mở Google Cloud Console:
  2. Hãy đảm bảo rằng bạn đã đăng nhập bằng cùng một Tài khoản Google như trên Dialogflow và chọn dự án: yourname-dialogflow trong thanh màu xanh dương trên cùng.
  3. Tiếp theo, tìm kiếm Dialogflow API trên thanh công cụ trên cùng và nhấp vào kết quả Dialogflow API trong trình đơn thả xuống.

Bật API Dialogflow

  1. Nhấp vào nút Quản lý màu xanh dương rồi nhấp vào Thông tin xác thực trong thanh trình đơn bên trái. (Khi chưa bật Dialogflow, trước tiên hãy nhấn vào Bật)

Bảng điều khiển GCP về thông tin đăng nhập

  1. Nhấp vào Tạo thông tin xác thực (ở đầu màn hình) rồi chọn Tài khoản dịch vụ.

Tạo thông tin đăng nhập

  1. Chỉ định tên tài khoản dịch vụ: flutter_dialogflow, mã và nội dung mô tả, rồi nhấn vào Tạo.

Tạo một tài khoản dịch vụ

  1. Ở bước 2, bạn sẽ cần chọn vai trò: Dialogflow API Admin, nhấp vào Tiếp tục rồi nhấp vào Xong.
  2. Nhấp vào tài khoản dịch vụ flutter_dialogflow, nhấp vào thẻ Khoá rồi nhấn vào Thêm khoá > Tạo khoá mới

Tạo khoá

  1. Tạo một khoá JSON. Hãy đổi tên tệp đó thành credentials.json rồi lưu trữ ở vị trí an toàn trong ổ đĩa cứng của bạn. Chúng tôi sẽ sử dụng sau.

Khoá JSON

Tuyệt vời! Mọi công cụ mà chúng tôi cần đều đã được thiết lập chính xác. Giờ đây, chúng ta có thể bắt đầu bằng việc tích hợp Dialogflow vào ứng dụng của mình!

3. Flutter: Xây dựng ứng dụng Chat

Tạo ứng dụng Boilerplate

  1. Mở Android Studio rồi chọn Bắt đầu một dự án Flutter mới.
  2. Chọn loại dự án là Flutter Application (Ứng dụng Flutter). Sau đó, nhấp vào Tiếp theo.
  3. Xác minh rằng đường dẫn Flutter SDK chỉ định vị trí của SDK (chọn Cài đặt SDK... nếu trường văn bản trống).
  4. Nhập tên dự án (ví dụ: flutter_dialogflow_agent). Sau đó, hãy nhấp vào Tiếp theo.
  5. Sửa đổi tên gói rồi nhấp vào Finish (Hoàn tất).

Tạo ứng dụng Flutter mới

Thao tác này sẽ tạo một ứng dụng mẫu có Thành phần Material.

Chờ Android Studio cài đặt SDK và tạo dự án.

Cài đặt và Sự cho phép

  1. Thư viện trình ghi âm sound_stream mà chúng ta sẽ sử dụng cần có minSdk tối thiểu là 21. Vì vậy, hãy thay đổi chế độ này trong android/app/build.gradle trong khối defaultConfig. (Lưu ý: có 2 tệp build.gradle trong thư mục android, nhưng tệp trong thư mục ứng dụng mới là tệp đúng.)
defaultConfig {
   applicationId "com.myname.flutter_dialogflow_agent"
   minSdkVersion 21
   targetSdkVersion 30
   versionCode flutterVersionCode.toInteger()
   versionName flutterVersionName
}
  1. Để cấp quyền truy cập vào micrô cũng như cho phép ứng dụng liên hệ với nhân viên hỗ trợ Dialogflow chạy trên đám mây, chúng ta phải thêm quyền INTERNET và RECORD_AUDIO vào tệp app/src/main/AndroidManifest.xml. Có nhiều tệp AndroidManifest.xml trong dự án Flutter, nhưng bạn sẽ cần tệp đó trong thư mục chính. Bạn có thể thêm các dòng ngay bên trong thẻ tệp kê khai.
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.RECORD_AUDIO" />

Thêm phần phụ thuộc

Chúng ta sẽ sử dụng các gói sound_stream, rxdartdialogflow_grpc.

  1. Thêm phần phụ thuộc 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. Thêm phần phụ thuộc 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. Thêm phần phụ thuộc 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!

Đang tải thông tin về dự án trên Google Cloud và tài khoản dịch vụ

  1. Trong dự án của bạn, hãy tạo một thư mục rồi đặt tên cho thư mục này: assets.
  2. Chuyển tệp credentials.json mà bạn đã tải xuống từ bảng điều khiển Google Cloud vào thư mục Asset (tài sản).
  3. Mở pubspec.yaml rồi thêm tài khoản dịch vụ vào khối Flutter.
flutter:
  uses-material-design: true
  assets:
    - assets/credentials.json

Chạy ứng dụng trên một thiết bị thực

Khi có thiết bị Android, bạn có thể cắm điện thoại qua cáp USB và gỡ lỗi trên thiết bị. Làm theo các bước này để thiết lập chế độ này qua màn hình Tuỳ chọn cho nhà phát triển trên thiết bị Android.

Chạy ứng dụng trên thiết bị ảo

Trong trường hợp bạn muốn chạy ứng dụng trên thiết bị ảo, hãy làm theo các bước sau:

  1. Nhấp vào Tools> (Công cụ) Trình quản lý thiết bị ảo Android. (Hoặc chọn Trình quản lý thiết bị ảo Android trong thanh công cụ trên cùng, được đánh dấu màu hồng trong hình bên dưới)

Thanh công cụ trên cùng của Android Studio

  1. Chúng ta sẽ tạo một thiết bị Android mục tiêu để có thể kiểm thử ứng dụng mà không cần thiết bị thực. Để biết thông tin chi tiết, hãy xem bài viết Quản lý AVD. Sau khi chọn một thiết bị ảo mới, bạn có thể nhấp đúp vào thiết bị đó để khởi động.

Quản lý AVD

Thiết bị ảo

  1. Trên thanh công cụ chính của Android Studio, hãy chọn một thiết bị Android làm mục tiêu thông qua trình đơn thả xuống và nhớ chọn main.dart. Sau đó, nhấn nút Run (Chạy) (hình tam giác màu xanh lục).

Ở cuối IDE, bạn sẽ thấy nhật ký trong bảng điều khiển. Bạn sẽ thấy rằng công cụ này đang cài đặt Android và ứng dụng Flutter ban đầu của bạn. Quá trình này sẽ mất ít phút vì khi thiết bị ảo đã sẵn sàng, việc thực hiện thay đổi sẽ cực nhanh. Khi bạn hoàn tất, ứng dụng Flutter ban đầu sẽ mở ra.

Ứng dụng tạo sẵn

  1. Hãy bật micrô cho ứng dụng chatbot. Nhấp vào nút options (tuỳ chọn) của thiết bị ảo để mở các tuỳ chọn. Trong thẻ Micrô, hãy bật cả 3 nút chuyển.

Tuỳ chọn AVD

  1. Hãy dùng thử tính năng Tải lại nóng để chứng minh tốc độ thực hiện thay đổi.

Trong lib/main.dart, hãy thay đổi tiêu đề MyHomePage trong lớp MyApp thành: Flutter Dialogflow Agent. Và thay đổi primarySwatch thành Colors.cam.

Đoạn mã đầu tiên

Lưu tệp hoặc nhấp vào biểu tượng chốt trong Thanh công cụ Android Studio. Bạn sẽ thấy nội dung thay đổi được thực hiện trực tiếp trong thiết bị ảo.

4. Flutter: Xây dựng giao diện Chat có hỗ trợ STT

Tạo giao diện trò chuyện

  1. Tạo một tệp Flutter tiện ích mới trong thư mục lib. (nhấp chuột phải vào thư mục lib, New > Flutter Widget > Stateful widget) để gọi tệp này: chat.dart

Dán mã sau vào tệp này. Tệp phi tiêu này tạo giao diện trò chuyện. Dialogflow sẽ chưa hoạt động. Đây chỉ là bố cục của tất cả các thành phần và tích hợp thành phần micrô để cho phép truyền trực tuyến. Các nhận xét trong tệp sẽ chỉ ra mà sau này chúng ta sẽ tích hợp 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),
      ),
    );
  }
}

Tìm kiếm trong tệp chat.dart cho Bản dựng tiện ích. Thao tác này sẽ xây dựng giao diện chatbot, trong đó có:

  • ListView chứa tất cả hộp chú giải trò chuyện từ người dùng và bot trò chuyện. Ứng dụng này sử dụng lớp ChatMessage để tạo tin nhắn trò chuyện có hình đại diện và văn bản.
  • TextField để nhập truy vấn văn bản
  • IconButton có biểu tượng gửi, để gửi truy vấn bằng văn bản đến Dialogflow
  • IconButton có micrô để gửi luồng âm thanh đến Dialogflow. Nút này thay đổi trạng thái sau khi được nhấn.

Liên kết giao diện trò chuyện

  1. Mở main.dart và thay đổi Widget build để chỉ tạo thực thể cho giao diện Chat(). Bạn có thể xoá tất cả các mã minh hoạ khác.
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. Chạy ứng dụng. (Nếu ứng dụng được khởi động trước đó. Dừng thiết bị ảo rồi chạy lại main.dart). Khi bạn chạy ứng dụng bằng giao diện trò chuyện lần đầu tiên. Bạn sẽ thấy một cửa sổ bật lên yêu cầu cấp quyền, hỏi xem bạn có muốn cho phép sử dụng micrô không. Nhấp vào: Trong khi dùng ứng dụng.

Quyền

  1. Chơi với vùng văn bản và các nút. Khi nhập một truy vấn văn bản rồi nhấn Enter hoặc nhấn vào nút gửi, bạn sẽ thấy truy vấn văn bản đó được ghi lại trong thẻ Run (Chạy) của Android Studio. Khi nhấn vào nút micrô và dừng nút đó, bạn sẽ thấy luồng âm thanh được ghi lại trong thẻ Run (Chạy).

Nhật ký luồng âm thanh

Tuyệt vời! Giờ đây, chúng tôi đã sẵn sàng tích hợp ứng dụng này với Dialogflow!

Tích hợp ứng dụng Flutter với Dialogflow_gRPC

  1. Mở chat.dart rồi thêm các lệnh nhập sau:
import 'package:dialogflow_grpc/dialogflow_grpc.dart';
import 'package:dialogflow_grpc/generated/google/cloud/dialogflow/v2beta1/session.pb.dart';
  1. Ở đầu tệp, ngay bên dưới // TODO DialogflowGrpcV2Beta1 class instance, hãy thêm dòng sau để lưu giữ phiên bản của lớp Dialogflow:
DialogflowGrpcV2Beta1 dialogflow;
  1. Tìm phương thức initPlugin() và thêm mã sau vào ngay bên dưới nhận xét TODO:
    // Get a Service account
    final serviceAccount = ServiceAccount.fromString(
        '${(await rootBundle.loadString('assets/credentials.json'))}');
    // Create a DialogflowGrpc Instance
    dialogflow = DialogflowGrpcV2Beta1.viaServiceAccount(serviceAccount);

Thao tác này sẽ tạo một phiên bản Dialogflow được uỷ quyền cho dự án Google Cloud của bạn bằng tài khoản dịch vụ. (Hãy đảm bảo rằng bạn có tệp credentials.json trong thư mục Asset (tài sản)!)

Xin nhắc lại, để minh hoạ cách làm việc với Dialogflow gRPC, điều này chấp nhận được, nhưng đối với các ứng dụng chính thức, bạn không nên lưu trữ tệp Credential.json trong thư mục assets, vì tệp này không được coi là an toàn.

Thực hiện một lệnh gọi detectedIntent

  1. Giờ hãy tìm phương thức handleSubmitted(), đây là nơi tuyệt vời. Ngay bên dưới nhận xét TODO, hãy thêm mã sau.Mã này sẽ thêm thông báo đã nhập của người dùng vào ListView:
ChatMessage message = ChatMessage(
 text: text,
 name: "You",
 type: true,
);

setState(() {
 _messages.insert(0, message);
});
  1. Bây giờ, ngay bên dưới đoạn mã trước đó, chúng ta sẽ thực hiện lệnh gọivnIntent, chuyển văn bản từ dữ liệu đầu vào và một đoạn mã languageCode. – Kết quả (trong vòng data.queryResult.fulfillment) sẽ được in trong 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. Khởi động thiết bị ảo và kiểm thử lệnh gọi phát hiện ý định. Loại: hi. AI sẽ chào bạn bằng tin nhắn chào mừng mặc định. Khi bạn nhập nội dung khác, chế độ dự phòng mặc định sẽ được trả về.

Thực hiện lệnh gọi StreamingDetectIntent

  1. Giờ hãy tìm phương thức handleStream(), đây là nơi kỳ diệu trong việc truyền phát âm thanh. Trước tiên, ngay trong TODO đầu tiên, hãy tạo âm thanh InputConfigV2beta1 với biasList để thiên vị mẫu giọng nói. Vì chúng ta đang sử dụng điện thoại (thiết bị ảo), sampleHertz sẽ là 16000 và mã hoá sẽ là Linear 16. Điều này tuỳ thuộc vào phần cứng trên máy / micrô mà bạn đang sử dụng. Đối với micrô Macbook nội bộ của tôi, 16000 là tốt. (Xem thông tin về gói 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. Tiếp theo, chúng ta sẽ gọi phương thức streamingDetectIntent trên đối tượng dialogflow, đối tượng này lưu giữ phiên Dialogflow của chúng ta:
final responseStream = dialogflow.streamingDetectIntent(config, _audioStream);
  1. Với responseStream, cuối cùng chúng ta có thể nghe bản chép lời đến, truy vấn người dùng đã phát hiện và phản hồi ý định khớp đã phát hiện được. Chúng ta sẽ in nội dung này trong ChatMessage trên màn hình:
// 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');
});

Vậy là xong, hãy khởi động ứng dụng của bạn rồi kiểm tra ứng dụng trên thiết bị ảo, nhấn vào nút micrô rồi Nói: "Xin chào".

Thao tác này sẽ kích hoạt ý định chào mừng mặc định của Dialogflow. Kết quả sẽ được in trên màn hình. Giờ đây, khi Flutter hoạt động hiệu quả với công cụ tích hợp Dialogflow, chúng ta có thể bắt đầu thực hiện cuộc trò chuyện với bot trò chuyện.

5. Dialogflow: Lập mô hình cho nhân viên hỗ trợ dự án Dialogflow

Dialogflow Essentials là một bộ công cụ phát triển dùng để tạo giao diện người dùng trò chuyện. Do đó, bot trò chuyện, bot thoại, cổng điện thoại. Bạn có thể tạo tất cả bằng cùng một công cụ và thậm chí bạn có thể hỗ trợ nhiều kênh bằng hơn 20 ngôn ngữ khác nhau. Các nhà thiết kế trải nghiệm người dùng của Dialogflow (nhà lập mô hình tác nhân, nhà ngôn ngữ học) hoặc nhà phát triển tạo ra ý định bằng cách chỉ định các cụm từ huấn luyện để huấn luyện một mô hình học máy cơ bản.

Mỗi ý định sẽ phân loại ý định của người dùng. Đối với mỗi tác nhân Dialogflow ES, bạn có thể xác định nhiều ý định, trong đó các ý định kết hợp có thể xử lý một cuộc trò chuyện hoàn chỉnh. Mỗi ý định có thể chứa các tham số và phản hồi.

Việc so khớp ý định còn được gọi là phân loại ý định hoặc so khớp ý định. Đây là khái niệm chính trong Dialogflow ES. Sau khi được so khớp, ý định có thể trả về phản hồi, thu thập các thông số (trích xuất thực thể) hoặc kích hoạt mã webhook (phương thức thực hiện), chẳng hạn như để tìm nạp dữ liệu từ cơ sở dữ liệu.

Khi người dùng cuối viết hoặc nói điều gì đó trong bot trò chuyện (còn gọi là biểu cảm hoặc cách phát âm của người dùng), Dialogflow ES sẽ so khớp biểu thức đó với ý định tốt nhất của nhân viên hỗ trợ Dialogflow, dựa trên các cụm từ huấn luyện. Mô hình học máy chuyên sâu Dialogflow ES được huấn luyện dựa trên các cụm từ huấn luyện đó.

Dialogflow ES hoạt động theo một khái niệm gọi là ngữ cảnh. Tương tự như con người, Dialogflow ES có thể ghi nhớ bối cảnh khi thực hiện lượt thứ 2 và thứ 3. Đây là cách Gemini có thể theo dõi những câu nói trước đây của người dùng.

Dưới đây là thông tin khác về ý định Dialogflow.

Sửa đổi ý định chào mừng mặc định

Khi bạn tạo một nhân viên hỗ trợ Dialogflow mới, 2 ý định mặc định sẽ được tạo tự động. Ý định chào mừng mặc định là quy trình đầu tiên bạn thực hiện khi bắt đầu cuộc trò chuyện với nhân viên hỗ trợ. Ý định dự phòng mặc định là luồng bạn sẽ nhận được khi tác nhân không thể hiểu ý định của bạn hoặc không thể so khớp một ý định với ý định bạn vừa nói.

Dưới đây là tin nhắn chào mừng của Ý định chào mừng mặc định:

User

Nhân viên hỗ trợ

Chào bạn

"Xin chào! Tôi là bot Câu hỏi thường gặp về Dialogflow, tôi có thể trả lời các câu hỏi về Dialogflow."

"Bạn muốn biết điều gì?"

  1. Nhấp vào Ý định > Ý định chào mừng mặc định
  2. Di chuyển xuống phần Câu trả lời.
  3. Xoá tất cả câu trả lời dạng văn bản.
  4. Trong thẻ mặc định, hãy tạo 2 phản hồi sau:
  • Xin chào! Tôi là bot câu hỏi thường gặp về Dialogflow, tôi có thể trả lời các câu hỏi về Dialogflow. Bạn muốn biết điều gì?
  • Xin chào, tôi là bot câu hỏi thường gặp về Dialogflow, bạn có câu hỏi về Dialogflow không? Tôi có thể giúp gì cho bạn?

Cấu hình sẽ tương tự như ảnh chụp màn hình này.

Chỉnh sửa ý định chào mừng mặc định

  1. Nhấp vào Lưu
  2. Hãy kiểm thử ý định này. Trước tiên, chúng ta có thể kiểm tra công cụ này trong Dialogflow Simulator.Type: Hello. Trình duyệt sẽ trả về một trong các thông báo sau:
  • Xin chào! Tôi là bot câu hỏi thường gặp về Dialogflow, tôi có thể trả lời các câu hỏi về Dialogflow. Bạn muốn biết điều gì?
  • Xin chào, tôi là bot câu hỏi thường gặp về Dialogflow, bạn có câu hỏi về Dialogflow không? Tôi có thể giúp gì cho bạn?

Sửa đổi ý định dự phòng mặc định

  1. Nhấp vào Ý định > Ý định dự phòng mặc định
  2. Di chuyển xuống phần Câu trả lời.
  3. Xoá tất cả câu trả lời dạng văn bản.
  4. Trong thẻ mặc định, hãy tạo phản hồi sau:
  • Rất tiếc, tôi không biết câu trả lời cho câu hỏi này. Bạn đã kiểm tra trang web của chúng tôi chưa? http://www.dialogflow.com?
  1. Nhấp vào Lưu

Kết nối với cơ sở kiến thức trực tuyến

Trình kết nối tri thức bổ sung cho ý định đã xác định. Dịch vụ này phân tích cú pháp tài liệu kiến thức để tìm câu trả lời tự động. (ví dụ: Câu hỏi thường gặp hoặc bài viết từ tệp CSV, trang web trực tuyến hoặc thậm chí là tệp PDF!) Để định cấu hình chúng, bạn xác định một hoặc nhiều cơ sở kiến thức, là tập hợp các tài liệu kiến thức.

Đọc thêm về Trình kết nối tri thức.

Hãy thử xem.

  1. Chọn Kiến thức (thử nghiệm) trong trình đơn.

Cơ sở kiến thức

  1. Nhấp vào nút màu xanh dương bên phải: Tạo Cơ sở kiến thức
  2. Nhập làm tên Cơ sở kiến thức; Câu hỏi thường gặp về Dialogflow rồi nhấn vào lưu.
  3. Nhấp vào đường liên kết Tạo tài khoản đầu tiên

Cơ sở kiến thức đầu tiên

  1. Một cửa sổ sẽ mở ra.

Sử dụng cấu hình sau:

Tên tài liệu: DialogflowFAQ Loại kiến thức: FAQ Loại Mime: text/html

  1. URL nơi chúng tôi tải dữ liệu từ đó là:

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

  1. Nhấp vào Tạo

Một cơ sở kiến thức đã được tạo:

Cơ sở kiến thức đã được tạo

  1. Di chuyển xuống mục Câu trả lời rồi nhấp vào Thêm câu trả lời

Tạo các câu trả lời sau rồi nhấp vào lưu.

$Knowledge.Answer[1]
  1. Nhấp vào Xem chi tiết

Xem thông tin chi tiết

  1. Chọn Bật tự động tải lại để tự động tìm nạp các thay đổi khi trang web Câu hỏi thường gặp được cập nhật và nhấp vào lưu.

Thao tác này sẽ hiển thị tất cả Câu hỏi thường gặp mà bạn đã triển khai trong Dialogflow.Rất dễ dàng!

Xin lưu ý rằng bạn cũng có thể trỏ đến một trang web HTML trực tuyến có phần Câu hỏi thường gặp để nhập Câu hỏi thường gặp vào nhân viên hỗ trợ của mình. Thậm chí, bạn có thể tải một tệp PDF có một đoạn văn bản lên và Dialogflow sẽ đưa ra các câu hỏi.

Giờ đây, câu hỏi thường gặp sẽ được coi là "thông tin bổ sung" để thêm vào nhân viên hỗ trợ, bên cạnh các luồng ý định. Các câu hỏi thường gặp trong Cơ sở kiến thức không thể giúp huấn luyện mô hình. Vì vậy, việc đặt câu hỏi theo cách hoàn toàn khác có thể không phù hợp vì không sử dụng công nghệ Hiểu ngôn ngữ tự nhiên (mô hình máy học). Đây là lý do đôi khi bạn nên chuyển đổi Câu hỏi thường gặp thành ý định.

  1. Kiểm tra các câu hỏi trong trình mô phỏng ở bên phải.
  2. Khi các bước này hoạt động xong, hãy quay lại ứng dụng Flutter của bạn để thử nghiệm bot trò chuyện và thoại của bạn với nội dung mới này! Đặt các câu hỏi mà bạn đã tải vào Dialogflow.

Kết quả

6. Xin chúc mừng

Xin chúc mừng! Bạn đã tạo thành công ứng dụng Flutter đầu tiên của mình có tích hợp bot trò chuyện của Dialogflow. Tốt lắm!

Nội dung đã đề cập

  • Cách tạo bot trò chuyện bằng Dialogflow Essentials
  • Cách tích hợp Dialogflow vào một ứng dụng Flutter
  • Cách phát hiện ý định văn bản bằng Dialogflow
  • Cách truyền trực tuyến giọng nói qua micrô tới Dialogflow
  • Cách sử dụng trình kết nối cơ sở tri thức

Tiếp theo là gì?

Bạn thích lớp học lập trình này? Hãy khám phá các phòng thí nghiệm thú vị này về Dialogflow!

Bạn có quan tâm đến cách tôi đã tạo gói gRPC của Dialogflow cho Dart/Flutter không?