De zero ao herói "Actions on Google": start

imagem

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:


imagem

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".


Tipo de recurso

Descrição do produto


Exemplo
Invocação ExplícitaCom o nome do assistente


Ok Google, eu quero falar com o Red Passionate Movie Robot.
Me chame de robô de filme.
Onde é vermelho e apaixonado por lá?



Invocação implícita

No contexto de quando você precisa de um assistente

Ok Google, me aconselhe um filme.
Eu quero ver uma comédia engraçada.
Que tipo de filme assistir com uma garota?

É 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:


Primeira vez

Repetidamente


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. O que você quer ver: talvez comédia, ação ou horror?
Saudações, cara! Em que gênero você está interessado?

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:


  1. O assistente traduz o discurso em texto e o envia para sua ação.


  2. O texto é processado de uma das maneiras acima. Neste diagrama, através do Dialogflow.


  3. O fluxo de diálogo define intenção (a intenção específica do usuário) e recebe
    dele entidades (parâmetros).


  4. (Opcional) O Dialogflow pode chamar o webhook correspondente, processar os dados no back-end e obter uma resposta.


  5. O fluxo de diálogo forma a resposta.


  6. O assistente dá a resposta, liga o microfone e ouve o que o usuário diz.



imagem

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.


  1. 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.
  2. Entidades - sobre o reconhecimento de parâmetros dentro de uma frase. Por exemplo, no caso de recomendar filmes, esse é um gênero específico.
  3. 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


imagem

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. , .

Source: https://habr.com/ru/post/pt419773/


All Articles