
Google hackathon, dan semua yang Anda butuhkan untuk mulai mengembangkan aplikasi Anda untuk asisten.
Google telah menyelenggarakan hackathon yang didedikasikan untuk teknologi Actions On Google. Ini adalah kesempatan yang baik untuk mendapatkan pengalaman dan berpikir tentang bagaimana memulai membuat antarmuka pengguna percakapan (CUI) untuk aplikasi kita. Oleh karena itu, kami membentuk tim yang terdiri dari dua pengembang Android: shipa_o , raenardev dan desainer comradeguest, dan pergi untuk berpartisipasi.
Apa itu Tindakan Di Google?
Actions On Google (AoG) adalah cara untuk menambahkan tindakan Anda ke asisten.
Anda dapat melakukan ini menggunakan 4 alat:
Di hackathon, kami membuat keterampilan - aplikasi yang memperluas kemampuan asisten, jadi kami akan berhenti di situ.
Setelah banding, “Oke Google. Saya ingin berbicara dengan ${_}
", asisten membuka keterampilan yang digunakan pengguna untuk melakukan dialog:

Bagaimana cara menulis suatu keterampilan?
Anda membutuhkan dua keterampilan:
- Pemahaman tentang Antarmuka Pengguna Percakapan (CUI), kemampuan untuk mendesainnya;
- Kemampuan untuk bekerja dengan Natural Language Processing (NLP), misalnya, Dialogflow.
Tahap 1: Desain
Agar keahlian Anda memiliki lawan bicara protein, lebih baik untuk memikirkan masa depan sekarang. Permintaan adalah permintaan yang mempertimbangkan konteks penggunaan. Antarmuka dialog akan digunakan ketika dimungkinkan untuk berbicara dengan suara keras dan berinteraksi dengan perangkat dengan suara yang lebih nyaman dan cepat daripada dengan tangan, mata, dan bagian tubuh lainnya.
Antarmuka suara adalah serial. Jika mungkin untuk menunjukkan seluruh bentuk menempatkan pesanan pada grafik, dan orang itu sendiri akan memilih apa yang akan dilihat pada awalnya dan kemudian apa, maka Anda hanya dapat mengajukan pertanyaan satu per satu dengan suara. Untuk menghasilkan aplikasi yang populer dan mudah, temukan persimpangan antara kebutuhan pengguna dan kemampuan untuk menggunakan antarmuka suara (atau ketidakmampuan untuk menggunakan yang lain).
Hal pertama yang terlintas dalam pikiran adalah asisten suara untuk orang buta, yang membantu menyelesaikan masalah sehari-hari. Misalnya, memesan di toko, menelepon taksi, menelepon kerabat. Yang kedua adalah buku resep berbicara untuk ibu rumah tangga dengan tangan di tepung. Ketiga, gim di mana Anda perlu menjelaskan sesuatu.
Kami memutuskan untuk memulai dengan yang sederhana dan mengembangkan robot yang memberi nasihat kepada orang-orang tentang film yang bagus. Kami mengalahkan ketidaksempurnaan synthesizer suara: asisten kami bahkan tidak berpura-pura menjadi seorang pria dan menekankan kepribadian elektroniknya yang jelas dalam segala hal.
Google telah menulis panduan yang sangat baik tentang bagaimana mengembangkan antarmuka interaktif. Dan kita akan berbicara tentang bagaimana kita mendesain pembicaraan pertama kita.
1. Doa
Pertama, Anda perlu memanggil asisten. Panggilannya bisa eksplisit (Invisit Invocation) dan tidak langsung (Invicit Invocation). Orang-orang akan menggunakan perawatan eksplisit ketika mereka sudah mengetahui aplikasi tersebut. Secara tidak langsung, Asisten Google dapat merekomendasikan aplikasi yang sesuai dalam situasi tertentu. Pilihan yang dipilih dengan benar untuk banding tidak langsung - seperti kata kunci yang tepat dalam iklan kontekstual, hanya lebih "manusiawi".
Penting bahwa panggilan tidak langsung tidak terlalu umum. Seperti kata kunci umum dalam iklan kontekstual, mereka hanya mencegah Anda menemukan aplikasi yang tepat dan menurunkan peringkat aplikasi dalam penerbitan Asisten.
Panggilan dapat berisi tautan dalam ke fitur asisten suara individual. Sebagai contoh, biasanya robot film kami memulai komunikasi dengan fakta bahwa ia menawarkan seseorang untuk memilih genre. Tetapi jika dia dipanggil pada permohonan tidak langsung, "Saya ingin melihat komedi lucu," masuk akal untuk memulai dialog dengan tawaran film yang dijamin bagus dari genre yang disebutkan.
2. Salam pertama
Salam pertama adalah apa yang diberitahukan aplikasi kepada orang tersebut segera setelah panggilan.
Pertama, Anda perlu memberi tahu pengguna bahwa asisten sudah ada di sini:
Hai, bentuk protein kehidupan. Saya robot film Merah yang bergairah. Tujuan dari keberadaan saya adalah untuk memberi saran pada film-film biologis tentang film-film yang bagus.
Dan kemudian - sarankan apa yang harus dilakukan selanjutnya. Robot kami sedang mencari film berdasarkan genre, jadi kami sarankan dengan permintaan apa seseorang dapat melangkah lebih jauh:
Apa yang ingin Anda lihat: mungkin komedi, aksi, atau horor?
Pengguna baru dan berpengalaman dapat disambut dengan berbagai cara. Jika seseorang berbicara dengan asisten Anda untuk pertama kalinya, Anda dapat berbicara sedikit tentang diri Anda. Jika bukan yang pertama - salam panjang akan mengganggunya. Karena itu, Anda dapat segera memulai bisnis:
3. Percakapan manusia
Ajari asisten Anda untuk memahami ucapan alami dan teruskan percakapan. Cara termudah untuk melakukan ini adalah berkomunikasi dengan orang-orang dari audiens target bahkan sebelum pengembangan dimulai. Selain itu, ini diinginkan secara verbal, dan tidak secara tertulis, karena pidato sehari-hari tertulis lebih jarang daripada lisan. Mainkan peran robot, dan minta lawan bicara untuk membayangkan bahwa dia menggunakan aplikasi masa depan Anda. Rekam semua dialog pada perekam, lalu dekripsi. Ini akan membantu Anda merancang diagram percakapan umum dan menemukan di mana cabang dapat muncul.
Tahap 2: Pengembangan
Ada beberapa cara untuk mengembangkan tindakan Anda untuk asisten:
- Dengan Dialogflow.
- Dengan Tindakan di Google SDK.
- Teks dapat diproses secara mandiri - misalnya, jika Anda memiliki solusi sendiri untuk memproses bahasa alami (NLP - Pemrosesan Bahasa Alami).
Berikut ini adalah interaksi asisten dengan keahlian Anda.
Dialognya terlihat seperti ini:
Asisten menerjemahkan pidato ke dalam teks dan mengirimkannya ke tindakan Anda.
Teks diproses dengan salah satu cara di atas. Dalam diagram ini, melalui Dialogflow.
Dialogflow mendefinisikan niat (maksud khusus pengguna) dan menerima
dari entitas itu (parameter).
(Opsional) Dialogflow dapat memanggil webhook yang sesuai, memproses data di backend dan mendapatkan respons.
Dialogflow membentuk jawabannya.
Asisten menyuarakan jawabannya, menyalakan mikrofon dan mendengarkan apa yang akan dikatakan pengguna.

Diagram aksi asisten
Dialogflow
Kami tidak akan merinci dasar-dasar Dialogflow - Google merilis video tutorial yang bagus.
- Maksud - tentang mengenali niat, bagaimana tepatnya Dialogflow memahami apa yang diminta pengguna atau tindakan apa yang ingin ia lakukan.
- Entitas - tentang pengenalan parameter di dalam frasa. Misalnya, dalam hal merekomendasikan film, ini adalah genre yang spesifik.
- Kontrol Dialog - tentang mekanisme konteks (tentangnya di bawah) dan pemenuhan: tentang cara memproses permintaan pengguna itu sendiri dengan mengakses backend Anda, dan bagaimana mengembalikan sesuatu yang lebih menarik daripada respons teks.
Kami berasumsi bahwa Anda telah menonton video dan menemukan konsol Dialogflow. Mari kita lihat masalah yang muncul di masing-masing bagian dalam proses implementasi, dan apa yang menarik dapat dicatat.
Ingat juga aturan untuk membangun dialog yang baik ketika Anda beralih ke implementasi - ini akan memengaruhi banyak niat, sekumpulan entitas dan penggunaannya dalam jawaban, penggunaan konteks, dan yang lainnya.
Maksud
Ada rekomendasi - untuk membuat salam yang lebih rinci untuk pengguna baru, dan sisanya untuk membuatnya lebih ringkas. Bagaimana cara mengimplementasikannya?
Di konsol Dialogflow, logika ini tidak dapat ditentukan. Hal ini dapat dilakukan di dalam pemenuhan niat selamat datang. Dengan kata lain, Anda harus melakukan ini dengan tangan Anda.
Ini juga berlaku untuk penanganan kesalahan. Misalnya, untuk pertama kalinya Anda bisa bertanya lagi, dan kedua kalinya Anda bisa memberi tahu tanggapan seperti apa yang Anda harapkan dari pengguna.
Anda tidak akan melakukan ini melalui tanggapan - jawaban acak akan dipilih. Anda dapat melakukannya melalui pemenuhan atau sedikit lebih rumit dengan mengikatnya ke konteks (lebih lanjut tentang itu di bawah).
Entitas
"Izinkan ekspansi otomatis" dan sys
Jika frasa serupa dalam struktur, maka ketika "Izinkan ekspansi otomatis" dihidupkan sebagai entitas yang diakui, sesuatu mungkin masuk ke yang masih tidak dapat diproses dengan laba.
Misalnya, aplikasi Anda mengenali frasa "Sarankan saya sesuatu dari <genre>" untuk kiat film. Jika Anda mengatakan "Beri tahu saya sesuatu dari makanan", maka sebagai "genre" parameter Anda tidak akan mendapatkan apa yang Anda harapkan. Ini masuk akal jika rangkaian genre Anda secara konstan diperbarui di backend, dan respons pengguna diproses di sana, tetapi Anda tidak punya waktu untuk memperbarui entitas.
Solusi lain adalah dengan menggunakan sys.Any. Dalam hal ini, ia akan menyampaikan semua yang ada setelah desain yang diharapkan, yang mungkin merupakan keseluruhan proposal. Ini memberi lebih banyak peluang daripada ekspansi otomatis, tetapi ada lebih banyak kerugian juga.
Singular dan jamak, kasus, jenis kelamin
Mari kita datang dengan contoh sederhana. Kami akan berbicara tentang buah favorit Anda, dan aplikasi akan menjawab betapa kerennya buah-buah itu. Dalam contoh di bawah ini, P adalah pengguna, A adalah tindakan kami.
P: Nanas adalah yang paling enak.
A: Ya, nanas adalah buah paling keren!
Dalam contoh ini, kita memiliki entitas: Nanas
Tetapi bagaimana jika pengguna mengatakan "Nanas"? Kami dapat menambahkan sinonim.
P: Saya suka nanas.
A: Ya, nanas adalah buah paling keren!
Default adalah bentuk referensi - yaitu itu adalah bentuk aslinya, bukan sinonimnya. Itu sebabnya aplikasi itu tidak mengatakan, “Ya, nanas adalah buah yang paling keren!”
Juga patut dipertimbangkan ketika menulis jawaban. Jika kita memiliki jawaban “Ya, $ buah adalah yang paling keren!”, Maka kita akan mendapatkan yang berikut:
P: Saya suka nanas.
A: Ya, nanas adalah yang paling keren!
Dan jangan lupa tentang kasus:
P: Saya ingin drama
A: Ini adalah drama keren ...
Oleh karena itu, Anda harus menuliskan nilai awal entitas dan jawaban dalam bentuk yang konsisten. Sebagai contoh, kita dapat melakukan semua bentuk entitas asli untuk buah-buahan dalam bentuk jamak, dan sinonim dalam bentuk apa pun.
Kami akan membuat genre dalam bahasa Rusia dalam kasus nominatif, tetapi dalam jumlah berapa pun (drama, kengerian).
Ketika kami sampai pada jawaban, kami tidak akan menulis, "Ya, $ buah adalah buah yang paling keren!" dan "Ya, $ buah adalah yang paling keren!" - Buah selalu dalam bentuk jamak.
Dalam kasus bahasa Rusia, ada baiknya melangkah lebih jauh dan berpikir tentang bagaimana menulis jawaban yang disepakati - kami tidak hanya memiliki kasus (drama / drama), tetapi juga gender (drama / barat).
P: Saya ingin orang barat
A: Ini barat keren ...
P: Saya ingin orang barat
A: Barat? Ok, ini filmnya keren ...
Tapi bagaimana cara mengembalikan bentuk entitas yang dikatakan pengguna?
Dalam hal genre, sinonim untuk "fiksi ilmiah" bisa jadi "alien." Kemudian, jika pengguna mengatakan "alien", "fiksi ilmiah" akan kembali sebagai parameter.
Jika kita ingin mendapatkan entitas dalam bentuk di mana pengguna berkata, maka ada baiknya memilih nilai $ entity.original

Tetapi kemudian mungkin ada masalah dengan ketidakkonsistenan jumlah dan (terutama) ketidakkonsistenan kasus. Apakah ini benar-benar perlu? Jika demikian, buat entitas untuk tunggal, jamak, dan kasing. Respons juga harus konsisten dengan bentuk entitas yang mereka gunakan.
Konteks
Mungkin dengan ini masalah yang paling.
Konteks input
Ini adalah konteks di mana niat tertentu terikat. Beberapa niat dapat merespons frasa yang sama, dan yang dengan konteks input aktif kemungkinan besar akan berfungsi.
Jadi, misalnya, Anda dapat melampirkan jawaban ya / tidak untuk pertanyaan tertentu, yang dilakukan dengan menggunakan niat tindak lanjut dalam Dialogflow
Konteks keluaran
Ini adalah konteks yang diaktifkan ketika niat dipicu. Ini adalah bagaimana konteks diaktifkan di konsol Dialogflow (ini juga dapat dilakukan dalam pemenuhan). Kami menunjukkan jumlah putaran dialog di mana dialog akan aktif, dan setelah mengatur ulang penghitung atau setelah 20 menit, dialog akan dinonaktifkan. Ini berarti bahwa data di dalam konteks ini tidak akan lagi tersedia dan niat yang inputnya tidak akan berfungsi.
Trik lain terkait dengan hal yang sama: Anda dapat mengaktifkan konteks dengan satu maksud dan menonaktifkannya secara manual dengan yang lain, cukup dengan menempatkannya sebagai konteks output untuk maksud kedua dengan jumlah jawaban 0.
Jika Anda tidak ingin menulis kode dalam pemenuhan, maka dengan cara ini Anda dapat menerapkan logika yang menarik, misalnya, menggunakan konteks sebagai penghitung, menerapkan penanganan kesalahan ketika asisten tidak memahami pengguna.
Kiat dialogog
Tidak perlu me-restart halaman dengan asisten preview - ketika Anda telah membuat perubahan pada agen dialogflow, Anda bisa menunggu sampai pelatihannya selesai dan segera mengulangi frase yang tidak dikenal dalam simulator. Dialogflow dapat dianggap sebagai backend yang diacu oleh asisten.
Gunakan agen prebuilt - di sana Anda dapat melihat bagaimana menerapkan skenario khas.
Hati-hati dengan bagian Obrolan Kecil. Penggunaannya tidak mematikan mikrofon di akhir percakapan, dan jawaban seperti itu biasanya tidak mengandung ajakan bertindak. Anda tidak mengarahkan pengguna ke putaran dialog berikutnya, dan tidak sepenuhnya jelas baginya apa yang harus dikatakan lebih lanjut. Dengan probabilitas tinggi, karena ini, Anda mungkin tidak lulus ulasan. Lebih baik membuat maksud terpisah untuk ini jika Anda bisa memasukkannya ke dalam dialog.
Jangan mengedit maksud yang sama secara bersamaan. Sekarang pekerjaan simultan dari beberapa orang tidak didukung - tidak diketahui perubahan siapa yang akan ditimpa.
Jika perlu untuk memparalelkan pekerjaan dengan niat, itu dapat dilakukan dalam proyek yang terpisah, dan kemudian hanya memilih yang diperlukan dan mentransfernya. Juga mengimpor dan mengekspor entitas dalam json / xml dan impor / ekspor untuk maksud.
Segera ada baiknya mempertimbangkan bahwa Anda menulis tindakan untuk bahasa tertentu. Menulis jawaban dalam bahasa Rusia memiliki nuansa tambahan. Jadi pelokalan tindakan tampaknya lebih menantang daripada dengan aplikasi mobile GUI.
Pertimbangkan aturan desain antarmuka suara - mereka tidak hanya memengaruhi set replika, tetapi juga struktur secara keseluruhan. Anda sedang membangun dialog, jadi setiap jawaban harus meninggalkan ajakan untuk bertindak sehingga pengguna mengerti apa yang harus dikatakan.
Setelah semuanya siap, dan Anda mulai menguji, jangan takut untuk meninggalkan cabang-cabang individu dari dialog atau formulir pertanyaan. Mungkin pada tahap pengujian Anda akan memahami cara menghubungkan maksud dan apa yang hilang untuk kemudahan penggunaan.
Koneksi server
Untuk menghubungkan server Anda harus menggunakan pemenuhan. Ada dua opsi untuk ini:
- Klien webhook . Banyak bahasa yang didukung.
- Editor Inline pada Fungsi Cloud untuk Firebase (node.js).
Mari kita pertimbangkan yang paling sederhana - Editor Inline.
Kami tidak berpura-pura menjadi ahli dalam node.js; memperbaiki kesalahan dalam komentar dipersilahkan.
Penting untuk memperhatikan versi API Dialogflow.
Versi terbaru v2. Semua yang ditulis untuk versi v1 tidak berfungsi dengannya.
Baca lebih lanjut tentang migrasi di sini .
Tautan yang bermanfaat:
Parsing templat standar
Ketika Anda membuka bagian Pemenuhan, kode berikut ini ditampilkan di file / tab `index.js`: 'use strict'; const functions = require('firebase-functions'); const {WebhookClient} = require('dialogflow-fulfillment'); const {Card, Suggestion} = require('dialogflow-fulfillment'); process.env.DEBUG = 'dialogflow:debug'; // enables lib debugging statements exports.dialogflowFirebaseFulfillment = functions.https.onRequest((request, response) => { const agent = new WebhookClient({ request, response }); console.log('Dialogflow Request headers: ' + JSON.stringify(request.headers)); console.log('Dialogflow Request body: ' + JSON.stringify(request.body)); function welcome(agent) { agent.add(`Welcome to my agent!`); } function fallback(agent) { agent.add(`I didn't understand`); agent.add(`I'm sorry, can you try again?`); } // // Uncomment and edit to make your own intent handler // // uncomment `intentMap.set('your intent name here', yourFunctionHandler);` // // below to get this function to be run when a Dialogflow intent is matched // function yourFunctionHandler(agent) { // agent.add(`This message is from Dialogflow's Cloud Functions for Firebase editor!`); // agent.add(new Card({ // title: `Title: this is a card title`, // imageUrl: 'https://developers.google.com/actions/images/badges/XPM_BADGING_GoogleAssistant_VER.png', // text: `This is the body text of a card. You can even use line\n breaks and emoji! `, // buttonText: 'This is a button', // buttonUrl: 'https://assistant.google.com/' // }) // ); // agent.add(new Suggestion(`Quick Reply`)); // agent.add(new Suggestion(`Suggestion`)); // agent.setContext({ name: 'weather', lifespan: 2, parameters: { city: 'Rome' }}); // } // // Uncomment and edit to make your own Google Assistant intent handler // // uncomment `intentMap.set('your intent name here', googleAssistantHandler);` // // below to get this function to be run when a Dialogflow intent is matched // function googleAssistantHandler(agent) { // let conv = agent.conv(); // Get Actions on Google library conv instance // conv.ask('Hello from the Actions on Google client library!') // Use Actions on Google library // agent.add(conv); // Add Actions on Google library responses to your agent's response // } // // See https://github.com/dialogflow/dialogflow-fulfillment-nodejs/tree/master/samples/actions-on-google // // for a complete Dialogflow fulfillment library Actions on Google client library v2 integration sample // Run the proper function handler based on the matched Dialogflow intent name let intentMap = new Map(); intentMap.set('Default Welcome Intent', welcome); intentMap.set('Default Fallback Intent', fallback); // intentMap.set('your intent name here', yourFunctionHandler); // intentMap.set('your intent name here', googleAssistantHandler); agent.handleRequest(intentMap); });
Dan dependensi seperti itu di file / tab `package.json`: { "name": "dialogflowFirebaseFulfillment", "description": "This is the default fulfillment for a Dialogflow agents using Cloud Functions for Firebase", "version": "0.0.1", "private": true, "license": "Apache Version 2.0", "author": "Google Inc.", "engines": { "node": "~6.0" }, "scripts": { "start": "firebase serve --only functions:dialogflowFirebaseFulfillment", "deploy": "firebase deploy --only functions:dialogflowFirebaseFulfillment" }, "dependencies": { "actions-on-google": "2.0.0-alpha.4", "firebase-admin": "^4.2.1", "firebase-functions": "^0.5.7", "dialogflow": "^0.1.0", "dialogflow-fulfillment": "0.3.0-beta.3" } }
Pertama-tama, perbarui dependensi alfa dan beta ke yang stabil terbaru.
Ini adalah versi terbaru saat ini. { "dependencies": { "actions-on-google": "^2.2.0", "firebase-admin": "^5.2.1", "firebase-functions": "^0.6.2", "dialogflow": "^0.6.0", "dialogflow-fulfillment": "^0.5.0" } }
Dan sekarang mari kita melihat lebih dekat pada kode.
Di atas selesai mengimpor dependensi // Cloud Functions Firebase library const functions = require('firebase-functions'); // const {WebhookClient} = require('dialogflow-fulfillment'); // const {Card, Suggestion} = require('dialogflow-fulfillment');
Seluruh poin pemenuhan adalah mengganti callback-a `dialogflowFirebaseFulfillment` exports.dialogflowFirebaseFulfillment = functions.https.onRequest((request, response) => { console.log('Dialogflow Request headers: ' + JSON.stringify(request.headers)); console.log('Dialogflow Request body: ' + JSON.stringify(request.body)); // . const agent = new WebhookClient({ request, response }); // let result = request.body.queryResult; // action entities https://dialogflow.com/docs/actions-and-parameters let action = result.action; let parameters = result.parameters; // https://dialogflow.com/docs/contexts let outputContexts = result.outputContexts; // let intentRequest = request.body.originalDetectIntentRequest; });
Panggilan balik ini akan dipanggil untuk maksud yang Anda aktifkan untuk pemenuhan.
Sekarang tentukan kembali jawaban untuk niat exports.dialogflowFirebaseFulfillment = functions.https.onRequest((request, response) => { const agent = new WebhookClient({ request, response }); function welcome(agent) { // agent.add(`Welcome to my agent!`); } function fallback(agent) { agent.add(`I didn't understand`); agent.add(`I'm sorry, can you try again?`); } // , : // key - intent-. // value - , . let intentMap = new Map(); intentMap.set('Default Welcome Intent', welcome); intentMap.set('Default Fallback Intent', fallback); agent.handleRequest(intentMap); });
Pada saat yang sama, kode tersebut sepenuhnya menggantikan respons maksud dari bagian Responses.
Respons akan dipanggil hanya jika panggilan balik gagal, sehingga Anda dapat melakukan penanganan kesalahan di sana.
Kami menghapus fungsi pemrosesan maksud dari callback.
Fungsi selamat datang dan mundur ada di penutupan .
Untuk menghapusnya dari callback, Anda harus menambahkan transfer konteks fungsi dan parameter melalui `bind` exports.dialogflowFirebaseFulfillment = functions.https.onRequest((request, response) => { const agent = new WebhookClient({ request, response }); let intentMap = new Map(); // set Map. intentMap .set('Default Welcome Intent', welcome.bind(this, agent)) .set('Default Fallback Intent', fallback.bind(this, agent)); agent.handleRequest(intentMap); }); function welcome(agent) { agent.add(`Welcome to my agent!`); } function fallback(agent) { // 2 add agent.add([ `I didn't understand`, `I'm sorry, can you try again?` ]); }
, , Google Assistant. , .