Ações no Google: escrevendo um aplicativo simples para o Google Assistant no Dialogflow e Cloud Functions for Firebase

No final do mês passado, o Google Assistant foi lançado oficialmente em russo, então é hora de descobrir como criar seus próprios aplicativos ( ações ) para o Assistant na pilha de tecnologia padrão do Google. Neste artigo, consideraremos a criação de uma ação no Actions no Google , analisaremos o processo de extração de entidades e intenções de frases no Dialogflow , aprenderemos a escrever manipuladores para obter informações extraídas e trabalhar com uma rede no Cloud Functions for Firebase .


Fig. 1. Arquitetura de aplicativo para o Assistant.

O desenvolvimento do Assistant começou a se desenvolver há relativamente pouco tempo, portanto a rede possui poucos materiais e o número de ferramentas e tecnologias usadas aumenta significativamente o limite de entrada. Este artigo, embora não resolva, mas pelo menos contribui para a solução desses problemas. Vamos começar com a arquitetura do aplicativo para o Assistant (Fig. 1), implementada na pilha de tecnologia padrão do Google:

  • O Actions no Google é uma plataforma para a criação de aplicativos para o Google Assistant.
  • Dialogflow - mecanismo NLU (Natural Language Understanding), responsável pelo processamento de idiomas naturais e diálogos de design.
  • Cloud Functions for Firebase (por conveniência, usaremos a abreviação Firebase Functions) - funções da nuvem para processar lógica complexa de interação do usuário e para trabalhar com serviços de terceiros. As funções do Firebase e o Dialogflow interagem via webhook, portanto, tecnicamente, qualquer outra solução de servidor pode ser usada. Entretanto, o Firebase Functions é uma boa alternativa e, às vezes, um substituto para seu próprio back-end. Ele permite que você crie e execute serviços na infraestrutura do Google, sem se preocupar com a alocação, dimensionamento ou gerenciamento de servidores. Por um lado, isso permite que você se concentre no componente de produto do desenvolvimento e na funcionalidade do serviço, sem perder tempo em tarefas e administração de infraestrutura. Por outro lado, por outro lado, a delegação implica um enfraquecimento do controle sobre a situação.

O artigo enfoca o aspecto técnico do desenvolvimento; o custo do uso dos serviços listados não será analisado.


Fig. 2. Interação dos componentes do Google Assistant (com base no material: Página inicial do Google e Workshop do assistente do Google ).

Dentro da pilha descrita, a lógica da ação se parece com a seguinte (Fig. 2):

  • O usuário acessa o aplicativo Google Assistant e inicia uma conversa com uma ação específica.
  • O Assistente do Google, por meio de Ações no Google, procura cada frase do usuário em um formato de texto no Dialogflow, além de fornecer informações sobre o próprio usuário (mediante solicitação prévia e com o consentimento do usuário) e a conversa atual .
  • O Dialogflow processa a frase recebida, extrai dela as informações necessárias e, com base no ML, toma decisões sobre qual resposta será gerada.
  • Em alguns casos, o Dialogflow pode delegar a formação de uma resposta no servidor no Firebase Functions, que, por sua vez, pode usar serviços de terceiros para obter as informações necessárias para a resposta.
  • Depois que a resposta é formada, o Dialogflow a retorna para Ações no Google, de onde entra no aplicativo Google Assistant.

Idéia


Nossa ação determinará por frase que tipo de gifs o usuário deseja ver e, em seguida, ele os procurará por meio da API GIPHY e os retornará ao usuário na forma de cartões. Ao implementar a ação, analisaremos a solução das seguintes tarefas:

  1. Configure e vincule ações no Google, Dialogflow e Firebase Functions.
  2. Extraia palavras-chave de frases do usuário (Dialogflow).
  3. Caixa de diálogo de script (fluxo de diálogo).
  4. Trabalhar com o contexto de diálogo (Dialogflow).
  5. Criando e conectando um webhook para gerar uma resposta a uma frase do usuário (Dialogflow, Firebase Function).
  6. Exibir carrossel de cartões na interface (Firebase Functions).
  7. Download de informações de um serviço de terceiros (Firebase Functions).

Configuração inicial



Fig. 3. Criando um agente do Dialogflow.

Primeiro de tudo, precisamos de uma conta do Google. Vamos começar criando um projeto no Dialogflow, para isso, no console, clique no botão Criar agente e preencha os campos obrigatórios (Fig. 3):

  • O idioma padrão é "russo - ru".
  • Fuso horário: "(GMT + 3: 00) Europe / Moscow".
  • Google Cloud Project: um novo GCP para o seu agente Dialogflow será criado automaticamente ou você pode escolher um dos projetos existentes do GCP, se houver.

Em seguida, clique no botão Criar no canto superior direito e aguarde o console configurar um novo projeto.


Fig. 4. Intenções padrão.

Por padrão, ao criar um agente do Dialogflow, duas intenções são criadas (Fig. 4):

  • "Intenção de boas-vindas padrão" - é responsável por cumprimentar o usuário;
  • “Intenção de fallback padrão” - processa frases desconhecidas que o Dialogflow não pode atribuir a nenhuma outra intenção.

A criação de diálogos no Dialogflow já foi descrita em detalhes nos artigos aqui , aqui e aqui , portanto, não vou me concentrar no seu princípio de operação.


Fig. 5. Respostas para "Intenção de boas-vindas padrão".

Adicionaremos algumas respostas bem-vindas ao "Objetivo padrão de boas-vindas" que ajudará o usuário a entender para que serve a ação e quais funções ele pode executar. Na seção "Respostas", selecione a guia "Assistente do Google" e, em "Envios de sugestões", escreveremos exemplos de frases para informar ao usuário como se comunicar com a ação (Fig. 5).

A ação pode ser depurada no Assistente do Google, tanto no telefone quanto no emulador oficial. Para abrir o emulador, você precisa acessar a seção "Integrações", no cartão "Google Assistant", clicar no botão "Configurações de integração" e clicar em "Gerenciar o aplicativo Assistant". No telefone e no emulador, a ação pode ser acionada com a frase de código "Ok Google, quero falar com meu aplicativo de teste".

Cenário base: pesquisa GIF


Crie um novo objetivo de pesquisa, que extrairá palavras-chave da frase do usuário e as enviará através do servidor webhook para o Firebase Functions. O servidor, por sua vez, usando a API GIPHY encontrará os gifs correspondentes e retornará o resultado ao usuário na forma de cartões.


Fig. 6. Adicionando frases de treinamento.

Para começar, adicionaremos frases típicas para treinamento na seção Frases de treinamento (Fig. 6):

  • "Eu quero ver girafas dançando."
  • "Encontre o animashki."
  • "Mostre os selos."
  • Mostre-me os gifs.
  • "Encontre-me elefantes animados."
  • "Mostrar gifs de panda."
  • "Gifs com listras de guaxinim."
  • "Você tem selos."
  • "Encontre as quedas engraçadas."


Fig. 7. Extraindo parâmetros do texto.

Para frases adicionadas, observe o parâmetro de pesquisa, que o Dialogflow deve selecionar no texto. Nesse caso, o tipo de parâmetro mais apropriado é @sys.any , pois quase qualquer construção de idioma pode ser usada como parâmetro de consulta de pesquisa. Chamamos esse parâmetro de query e o marcamos como necessário (Fig. 7).


Fig. 8. A lista das principais perguntas.

Na subseção “Prompts”, escreveremos perguntas esclarecedoras que o Dialogflow fará se não conseguir extrair palavras-chave da frase (Fig. 8).

Em seguida, vá até a seção “Processamento” na parte inferior da página (não confunda com a seção com o mesmo nome no menu esquerdo). clique no botão "Ativar preenchimento completo" e ative a configuração "Ativar chamada de webhook para esse objetivo". Isso permitirá que o Dialogflow delegue a formação de uma resposta do Firebase Functions quando atingir a intenção.

Agora vá para a aba “Cumprimento” no menu esquerdo e ative o “Editor embutido”, onde escreveremos a lógica do recém-criado “Objetivo da pesquisa”. Para procurar GIFs por palavras-chave, usaremos a solicitação https://api.giphy.com/v1/gifs/search , que retorna uma lista de objetos encontrados no formato JSON de acordo com a especificação . A resposta recebida do GIPHY será exibida na forma de um carrossel de navegação - um carrossel de cartões com imagens, quando clicadas, uma página da web é aberta. No nosso caso, quando você clica no cartão, o usuário acessa a página de serviço GIPHY com esta animação e uma lista de similares.

O código que implementa a funcionalidade descrita acima é apresentado abaixo.

 'use strict'; const GIPHY_API_KEY = 'API_KEY'; const SEARCH_RESULTS = [ '-,    .', ',   .', ',   !' ]; // Import the Dialogflow module from the Actions on Google client library. const { dialogflow, BrowseCarouselItem, BrowseCarousel, Suggestions, Image } = require('actions-on-google'); // Import the firebase-functions package for deployment. const functions = require('firebase-functions'); // Import the request-promise package for network requests. const request = require('request-promise'); // Instantiate the Dialogflow client. const app = dialogflow({ debug: true }); function getCarouselItems(data) { var carouselItems = []; data.slice(0, 10).forEach(function (gif) { carouselItems.push(new BrowseCarouselItem({ title: gif.title || gif.id, url: gif.url, image: new Image({ url: gif.images.downsized_medium.url, alt: gif.title || gif.id }), })); }); return carouselItems; } function search(conv, query) { // Send the GET request to GIPHY API. return request({ method: 'GET', uri: 'https://api.giphy.com/v1/gifs/search', qs: { 'api_key': GIPHY_API_KEY, 'q': query, 'limit': 10, 'offset': 0, 'lang': 'ru' }, json: true, resolveWithFullResponse: true, }).then(function (responce) { // Handle the API call success. console.log(responce.statusCode + ': ' + responce.statusMessage); console.log(JSON.stringify(responce.body)); // Obtain carousel items from the API call response. var carouselItems = getCarouselItems(responce.body.data); // Validate items count. if (carouselItems.length <= 10 && carouselItems.length >= 2) { conv.data.query = query; conv.data.searchCount = conv.data.searchCount || 0; conv.ask(SEARCH_RESULTS[conv.data.searchCount % SEARCH_RESULTS.length]); conv.data.searchCount++; conv.ask(new BrowseCarousel({ items: carouselItems })); } else { // Show alternative response. conv.ask('      ,   - ?)'); } }).catch(function (error) { // Handle the API call failure. console.log(error); conv.ask(',     .'); }); } // Handle the Dialogflow intent named 'Search Intent'. // The intent collects a parameter named 'query'. app.intent('Search Intent', (conv, { query }) => { return search(conv, query); }); // Set the DialogflowApp object to handle the HTTPS POST request. exports.dialogflowFirebaseFulfillment = functions.https.onRequest(app); 

Dependências
 { "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", "request": "^2.81.0", "request-promise": "^4.2.1" } } 

Como o usuário pode acessar a mesma intenção várias vezes, é recomendável retornar várias respostas a ela. Para fazer isso, usamos o objeto JSON Conversation.data , que mantém seu valor ao acessar a intenção novamente e ao se referir a outros scripts de conversa.


Fig. 9. Inicialização da conversa (à esquerda), refinamento dos parâmetros de pesquisa e exibição posterior dos resultados (no centro), exibição dos resultados da pesquisa para uma nova consulta (à direita)

Nota: para trabalhar com a API de serviços de terceiros por meio do Firebase Functions, é necessário ativar o faturamento; caso contrário, ao tentar trabalhar com a rede, ocorrerá um erro:
"Conta de cobrança não configurada. A rede externa não está acessível e as cotas são severamente limitadas. Configure a conta de cobrança para remover essas restrições. "
Para fazer isso, clique em "Conta paga" no menu à esquerda e selecione Chama (US $ 25 por mês) ou Blaze (pagamento conforme o uso) entre os planos tarifários propostos. Eu escolhi a última opção, porque, como parte do desenvolvimento de um aplicativo de teste, me pareceu mais rentável.

Cenário avançado: paginação


Na maioria dos casos, para uma consulta de pesquisa, o GIPHY encontrará significativamente mais de dez GIFs; portanto, será correto permitir que o usuário veja o resultado inteiro da pesquisa, ou seja, adicione paginação.

No console do Dialogflow, passe o mouse sobre a célula Search Intent. Vários botões aparecerão à direita, clique em "Adicionar intenção de acompanhamento". Isso nos permitirá criar um ramo de conversa seguindo o objetivo da pesquisa. Entre os elementos da lista suspensa, selecionamos "mais" - uma ignição padrão para iniciar a exibição de informações adicionais.


Fig. 10. O contexto da intenção é "Intenção de pesquisa - mais".

Vamos para a intenção recém-criada e fazer alterações na seção "Contexto". Como o usuário pode pedir para mostrar mais GIFs várias vezes seguidas, essa intenção deve poder ser chamada recursivamente. Para isso, no contexto de saída, é necessário registrar a mesma linha que é indicada na entrada (Fig. 10). Na seção "Fullfilment", você também deve ativar a configuração "Ativar chamada de webhook para essa intenção".

Agora vamos retornar ao "preenchimento" no menu lateral, onde inicializamos o manipulador para "Intenção de pesquisa - mais". Também adicionamos o parâmetro offset à função de search , que será usada para paginação na API GIPHY.

 const SEARCH_RESULTS_MORE = [ '   !', ',    .', ',   .  ,    .' ]; function search(conv, query, offset) { // Send the GET request to GIPHY API. return request({ method: 'GET', uri: 'https://api.giphy.com/v1/gifs/search', qs: { 'api_key': GIPHY_API_KEY, 'q': query, 'limit': 10, 'offset': offset, 'lang': 'ru' }, json: true, resolveWithFullResponse: true, }).then(function (responce) { // Handle the API call success. console.log(responce.statusCode + ': ' + responce.statusMessage); console.log(JSON.stringify(responce.body)); // Obtain carousel items from the API call response. var carouselItems = getCarouselItems(responce.body.data); // Validate items count. if (carouselItems.length <= 10 && carouselItems.length >= 2) { conv.data.query = query; conv.data.offset = responce.body.pagination.count + responce.body.pagination.offset; conv.data.paginationCount = conv.data.paginationCount || 0; conv.data.searchCount = conv.data.searchCount || 0; // Show successful response. if (offset == 0) { conv.ask(SEARCH_RESULTS[conv.data.searchCount % SEARCH_RESULTS.length]); conv.data.searchCount++; } else { conv.ask(SEARCH_RESULTS_MORE[conv.data.paginationCount % SEARCH_RESULTS_MORE.length]); conv.data.paginationCount++; } conv.ask(new BrowseCarousel({ items: carouselItems })); conv.ask(new Suggestions('')); } else { // Show alternative response. conv.ask('      ,   - ?)'); } }).catch(function (error) { // Handle the API call failure. console.log(error); conv.ask(',     .'); }); } // Handle the Dialogflow intent named 'Search Intent - more'. app.intent('Search Intent - more', (conv) => { // Load more gifs from the privious search query return search(conv, conv.data.query, conv.data.offset); }); 


Fig. 11. Paginação ao procurar por gifs.

Resultado


O vídeo da ação é apresentado abaixo.



Código do projeto e despejo de assistente disponível no Github .

Instruções para instalar o projeto e importar o dump
  1. Vá para o console do Dialogflow e crie um novo agente ou selecione um existente.
  2. Clique no ícone de configurações, vá para a seção "Exportar e Importar" e clique no botão "Restaurar do ZIP". Selecione o arquivo ZIP no diretório raiz do repositório.
  3. Selecione "Cumprimento" no menu de navegação esquerdo.
  4. Ative a configuração do "Editor embutido".
  5. Copie o conteúdo dos arquivos do diretório de functions para as guias apropriadas no "Cumprimento".
  6. Digite sua chave de acesso à API GIPHY na guia index.js .
  7. Vá para o console do Firebase e altere seu plano para Flame ou Blaze. O trabalho com serviços de terceiros pela rede não está disponível com um plano tarifário gratuito.

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


All Articles