
Google hackathon, e tudo que você precisa para começar a desenvolver seus aplicativos para um assistente.
O Google organizou um hackathon dedicado à tecnologia Actions On Google. Essa é uma boa oportunidade para adquirir experiência e pensar em como começar a criar a interface do usuário de conversação (CUI) para nossos aplicativos. Portanto, reunimos uma equipe de dois desenvolvedores do Android: shipa_o , raenardev e designer comradeguest, e fomos participar.
O que é ações no Google?
Ações no Google (AoG) é uma maneira de adicionar sua ação ao assistente.
Você pode fazer isso usando 4 ferramentas:
No hackathon, desenvolvemos uma habilidade - um aplicativo que expande os recursos de um assistente, então vamos parar por aí.
Após a apelação, “Ok Google. Quero conversar com ${_}
”, o assistente abre a habilidade com a qual o usuário conduz um diálogo:

Como escrever uma habilidade?
Você precisará de duas habilidades:
- compreensão da interface do usuário conversacional (CUI), a capacidade de projetá-las;
- Capacidade de trabalhar com o Natural Language Processing (NLP), por exemplo, Dialogflow.
Etapa 1: Design
Para que sua habilidade tenha um interlocutor de proteínas, é melhor pensar no futuro agora. Demanda serão aqueles que levarem em conta o contexto de uso. As interfaces de diálogo serão usadas quando for possível falar em voz alta e interagir com dispositivos com voz de maneira mais conveniente e rápida do que com mãos, olhos e outras partes do corpo.
A interface de voz é serial. Se for possível mostrar toda a forma de fazer um pedido em um gráfico, e a própria pessoa escolher o que procurar primeiro e depois o que, então você só poderá fazer perguntas uma após a outra em voz alta. Para criar um aplicativo popular e conveniente, encontre a interseção entre as necessidades do usuário e a capacidade de usar a interface de voz (ou a incapacidade de usar outras pessoas).
A primeira coisa que vem à mente é um assistente de voz para cegos, que ajuda a resolver os problemas do dia a dia. Por exemplo, faça um pedido em uma loja, chame um táxi, ligue para parentes. O segundo é um livro de receitas falante para donas de casa com as mãos na farinha. Terceiro, jogos em que você precisa explicar algo.
Decidimos começar com um simples e desenvolvemos um robô que aconselha as pessoas sobre bons filmes. Vencemos a imperfeição dos sintetizadores de voz: nosso assistente nem mesmo finge ser um homem e enfatiza sua vívida personalidade eletrônica em todos os aspectos.
O Google escreveu excelentes diretrizes sobre como desenvolver interfaces interativas. E falaremos sobre como projetamos nosso primogênito falante.
1. Invocação
Primeiro, você precisa chamar um assistente. A chamada pode ser explícita (chamada explícita) e indireta (chamada implícita). As pessoas usarão tratamento explícito quando já conhecerem o aplicativo. Indiretamente, o Assistente do Google pode recomendar um aplicativo adequado em uma situação específica. As opções escolhidas corretamente para apelo indireto - como as palavras-chave corretas na publicidade contextual, são apenas mais "humanas".
É importante que as chamadas indiretas não sejam muito gerais. Como palavras-chave gerais na publicidade contextual, elas apenas impedem que você encontre o aplicativo certo e diminua a classificação do aplicativo na emissão do Assistente.
As chamadas podem conter um link direto para os recursos individuais do assistente de voz. Por exemplo, geralmente nosso robô-filme começa a se comunicar com o fato de oferecer uma pessoa para escolher um gênero. Mas se ele for chamado para um apelo indireto, "Quero ver uma comédia engraçada", é lógico iniciar um diálogo com a oferta de um bom filme garantido do gênero mencionado.
2. Primeira saudação
A primeira saudação é o que o aplicativo diz à pessoa imediatamente após a ligação.
Primeiro, você precisa informar ao usuário que o assistente já está aqui:
Oi, uma forma de proteína da vida. Eu sou um robô-filme apaixonado por Red. O objetivo da minha existência é aconselhar filmes biológicos sobre bons filmes.
E então - sugira o que fazer a seguir. Nosso robô está procurando filmes por gênero, por isso sugerimos com que solicitação uma pessoa pode ir além:
O que você quer ver: talvez comédia, ação ou horror?
Usuários novos e experientes podem ser recebidos de várias maneiras. Se uma pessoa estiver conversando com seu assistente pela primeira vez, você poderá falar um pouco sobre você. Se não for o primeiro - uma longa saudação vai incomodá-lo. Portanto, você pode começar imediatamente a trabalhar:
3. Conversa humana
Ensine seu assistente a entender a fala natural e manter a conversa em andamento. A maneira mais fácil de fazer isso é se comunicar com as pessoas do público-alvo antes mesmo do início do desenvolvimento. Além disso, é desejável verbalmente, e não por escrito, porque o discurso coloquial escrito é mais escasso que o oral. Desempenhe o papel de robô e peça ao interlocutor para imaginar que ele está usando seu aplicativo futuro. Grave todas as caixas de diálogo no gravador e descriptografe. Isso o ajudará a criar um diagrama de conversação típico e descobrir onde as ramificações podem aparecer.
Etapa 2: Desenvolvimento
Existem várias maneiras de desenvolver sua ação para um assistente:
- Com o Dialogflow.
- Com ações no Google SDK.
- O texto pode ser processado independentemente - por exemplo, se você tiver sua própria solução para o processamento de linguagem natural (PNL - Natural Language Processing).
A seguir, a interação de um assistente com sua habilidade.
A caixa de diálogo é mais ou menos assim:
O assistente traduz o discurso em texto e o envia para sua ação.
O texto é processado de uma das maneiras acima. Neste diagrama, através do Dialogflow.
O fluxo de diálogo define intenção (a intenção específica do usuário) e recebe
dele entidades (parâmetros).
(Opcional) O Dialogflow pode chamar o webhook correspondente, processar os dados no back-end e obter uma resposta.
O fluxo de diálogo forma a resposta.
O assistente dá a resposta, liga o microfone e ouve o que o usuário diz.

Diagrama de ação do assistente
Fluxo de Diálogo
Não detalharemos os conceitos básicos do Dialogflow - o Google lançou bons vídeos tutoriais.
- Intenções - sobre o reconhecimento da intenção, como exatamente o Dialogflow entende o que o usuário pede ou que ação ele deseja executar.
- Entidades - sobre o reconhecimento de parâmetros dentro de uma frase. Por exemplo, no caso de recomendar filmes, esse é um gênero específico.
- Controle de caixa de diálogo - sobre o mecanismo de contexto (sobre ele abaixo) e o cumprimento: sobre como processar a solicitação do usuário acessando seu back-end e como retornar algo mais interessante do que uma resposta de texto.
Assumimos que você já assistiu ao vídeo e descobriu o console do Dialogflow. Vejamos os problemas que surgiram em cada uma das partes do processo de implementação e o que é interessante pode ser observado.
Lembre-se também das regras para criar um bom diálogo ao avançar para a implementação - isso afetará o conjunto de intenções, o conjunto de entidades e seu uso em respostas, o uso de contextos e tudo mais.
Intenções
Existem recomendações - para fazer uma saudação mais detalhada para o novo usuário e para o restante para torná-lo mais conciso. Como implementar isso?
No console do Dialogflow, essa lógica não pode ser determinada. Isso pode ser feito dentro do cumprimento para a intenção de boas-vindas. Em outras palavras, você precisará fazer isso com as mãos.
Isso também se aplica ao tratamento de erros. Por exemplo, pela primeira vez, você pode simplesmente perguntar novamente, e na segunda vez, pode dizer que tipo de resposta espera do usuário.
Você não fará isso por meio de respostas - uma resposta aleatória será selecionada. Você pode fazer isso através da realização ou um pouco mais complicado, vinculando-o ao contexto (mais sobre isso abaixo).
Entidades
"Permitir expansão automatizada" e sys.Any
Se a frase tiver estrutura semelhante, quando "Permitir expansão automatizada" estiver ativada como uma entidade reconhecida, poderá ocorrer algo que ainda não pode ser processado com lucro.
Por exemplo, seu aplicativo reconhece a frase "Sugira-me algo do <gênero>" para obter dicas de filmes. Se você disser “Aconselhe-me algo sobre comida”, como parâmetro “gênero” você não obterá o que esperaria. Isso faz sentido se o conjunto de gêneros você é atualizado dinamicamente constantemente no back-end e a resposta do usuário é processada lá, mas você não tem tempo para atualizar a entidade.
Outra solução é usar o sys.Any. Nesse caso, ele transmitirá tudo o que estava após o design esperado, que pode ser toda a proposta. Isso oferece mais oportunidades do que a expansão automatizada, mas também há mais desvantagens.
Singular e plural, casos, gênero
Vamos criar um exemplo simples. Falaremos sobre suas frutas favoritas e o aplicativo responderá como são legais. Nos exemplos abaixo, P é o usuário, A é a nossa ação.
P: O abacaxi é o mais saboroso.
A: Sim, o abacaxi é a fruta mais legal!
Neste exemplo, temos a entidade: Abacaxis
Mas e se o usuário disser "Abacaxi"? Podemos adicionar um sinônimo.
P: Gostei do abacaxi.
A: Sim, o abacaxi é a fruta mais legal!
O padrão é o formulário de referência - ou seja, é a forma original, não seus sinônimos. É por isso que o aplicativo não diz "Sim, abacaxi é a fruta mais legal!"
Também vale a pena considerar ao escrever respostas. Se tivéssemos a resposta "Sim, $ fruit é o mais legal!", Teríamos o seguinte:
P: Gostei do abacaxi.
A: Sim, o abacaxi é o mais legal!
E não se esqueça dos casos:
P: eu quero drama
A: Aqui está um drama legal ...
Portanto, você deve escrever os valores iniciais da entidade e as respostas de forma consistente. Por exemplo, podemos fazer todas as formas originais de entidade para frutas no plural e sinônimos em qualquer.
Faremos gêneros em russo no caso nominativo, mas em qualquer número (drama, horrores).
Quando chegarmos às respostas, não escreveremos "Sim, $ fruta é a fruta mais legal!" e "Sim, $ fruit é o mais legal!" - os frutos estão sempre no plural.
No caso do idioma russo, vale a pena ir ainda mais longe e pensar em como escrever uma resposta acordada - temos não apenas casos (drama / drama), mas também gênero (drama / western).
P: Eu quero um ocidental
A: Aqui está um ocidental legal ...
P: Eu quero um ocidental
A: Ocidental? Ok, aqui está um filme legal ...
Mas como retornar exatamente o formulário da entidade que o usuário disse?
No caso de gêneros, o sinônimo de "ficção científica" poderia ser "alienígenas". Então, se o usuário dissesse "alienígenas", "ficção científica" retornaria como parâmetro.
Se queremos obter a entidade da forma que o usuário disse, vale a pena escolher o valor de $ entity.original

Mas então pode haver problemas com a inconsistência do número e (especialmente) a inconsistência dos casos. Isso é realmente necessário? Nesse caso, crie uma entidade para singular, plural e maiúsculas e minúsculas. As respostas também devem ser consistentes com o formulário da entidade que eles usam.
Contextos
Talvez com isso a maioria dos problemas.
Contexto de entrada
Este é o contexto ao qual uma intenção específica está vinculada. Várias intenções podem responder à mesma frase, e aquela com o contexto de entrada ativo provavelmente funcionará.
Assim, por exemplo, você pode anexar uma resposta sim / não a uma pergunta específica, o que é feito usando a intenção de acompanhamento no Dialogflow
Contexto de saída
Este é o contexto que é ativado quando a intenção é acionada. É assim que os contextos são ativados no console do Dialogflow (isso também pode ser feito em execução). Indicamos o número de voltas do diálogo durante o qual ele estará ativo e, após redefinir o contador ou após 20 minutos, ele é desativado. Isso significa que os dados nesse contexto não estarão mais disponíveis e as intenções para as quais são inseridos não funcionarão.
Outro truque está ligado ao mesmo: você pode ativar um contexto com uma intenção e desativá-lo manualmente com outra, simplesmente colocando-o como contexto de saída para a segunda intenção com o número de respostas 0.
Se você não deseja escrever código em cumprimento, dessa forma, você pode implementar uma lógica interessante, por exemplo, usando o contexto como um contador, implementar o tratamento de erros quando o assistente não entender o usuário.
Dicas de fluxo de diálogo
Não há necessidade de reiniciar a página com a visualização do assistente - quando você tiver feito alterações no agente de fluxo de diálogo, poderá aguardar a conclusão do treinamento e repetir imediatamente a frase não reconhecida no simulador. O fluxo de diálogo pode ser pensado como um back-end ao qual um assistente se refere.
Use agentes pré-criados - você pode ver como implementar um cenário típico.
Tenha cuidado com a seção de conversas pequenas. Seu uso não desliga o microfone no final da conversa, e essas respostas geralmente não contêm frases de chamariz. Você não direciona o usuário para a próxima rodada de diálogo e não está totalmente claro para ele o que deve ser dito mais adiante. Com uma alta probabilidade, por isso, você não pode passar na revisão. É melhor fazer intenções separadas para isso, se você puder inseri-las na caixa de diálogo.
Não edite a mesma intenção ao mesmo tempo. Agora, o trabalho simultâneo de várias pessoas não é suportado - não se sabe cujas alterações serão substituídas.
Se for necessário paralelizar o trabalho com a intenção, ele pode ser realizado em projetos separados, basta selecionar os necessários e transferi-los. Também importe e exporte entidades no json / xml e importe / exporte para a intenção.
Imediatamente, vale a pena considerar que você escreve uma ação para um idioma específico. Escrever respostas em russo tem nuances adicionais. Portanto, localizar a ação parece ser mais desafiador do que com a GUI do aplicativo móvel.
Considere as regras de design das interfaces de voz - elas afetam não apenas o conjunto de réplicas, mas também a estrutura como um todo. Você está construindo um diálogo, portanto, cada resposta deve deixar um plano de ação para que o usuário entenda o que dizer.
Depois que tudo estiver pronto e você começar a testar, não tenha medo de abandonar ramos individuais do diálogo ou dos formulários de perguntas. Talvez no estágio de teste você entenda como conectar as intenções e o que está faltando para facilitar o uso.
Conexão com o servidor
Para conectar o servidor, você precisa usar o preenchimento. Existem duas opções para isso:
- Cliente Webhook . Muitos idiomas suportados.
- Editor embutido nas funções da nuvem para Firebase (node.js).
Vamos considerar o mais simples - o Editor embutido.
Não pretendemos ser um especialista em node.js; corrigir erros nos comentários é bem-vindo.
É importante prestar atenção à versão da API do Dialogflow.
Versão mais recente v2. Tudo escrito para a versão v1 não funciona com ele.
Leia mais sobre migração aqui .
Links úteis:
Analisar o modelo padrão
Quando você abre a seção Cumprimento, o seguinte código é exibido no arquivo / guia `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); });
E essas dependências no arquivo / guia `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" } }
Primeiro, atualize as dependências alfa e beta para as mais recentes estáveis.
Aqui estão as versões mais recentes no momento. { "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" } }
E agora vamos dar uma olhada no código.
Acima é feito a importação de dependências // Cloud Functions Firebase library const functions = require('firebase-functions'); // const {WebhookClient} = require('dialogflow-fulfillment'); // const {Card, Suggestion} = require('dialogflow-fulfillment');
O ponto principal do cumprimento é substituir o retorno de chamada - um `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; });
Esse retorno de chamada será chamado para as intenções para as quais você ativa o preenchimento completo.
Agora redefina a resposta para a intenção 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); });
Ao mesmo tempo, o código substitui completamente a resposta de intenção da seção Respostas.
As respostas serão chamadas apenas se o retorno de chamada falhar, para que você possa manipular erros lá.
Removemos as funções de processamento de intenção do retorno de chamada.
As funções de boas-vindas e fallback estão no fechamento .
Para removê-los do retorno de chamada, você precisará adicionar a transferência do contexto da função e dos parâmetros via `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. , .