Criar seu app da Web (Dialogflow)

Um app da Web é a IU para uma ação que usa a tela interativa. É possível usar tecnologias da Web existentes (HTML, CSS e JavaScript) para projetar e desenvolver seu app da Web. Na maioria das vezes, a tela interativa é capaz de renderizar conteúdo da Web como um navegador, mas há algumas restrições para a privacidade e a segurança do usuário. Antes de começar a projetar a interface, considere os princípios de design descritos na seção Design guidelines.

O HTML e o JavaScript do seu app da Web fazem o seguinte:

  • Registra as callbacks do evento da tela interativa.
  • Inicialize a biblioteca JavaScript de tela interativa.
  • Forneça uma lógica personalizada para atualizar seu app da Web com base no estado.

Esta página aborda as maneiras recomendadas de criar seu app da Web, como ativar a comunicação entre o app da Web e o fulfillment e as diretrizes e restrições gerais.

Embora você possa usar qualquer método para criar sua interface, o Google recomenda usar as seguintes bibliotecas:

Arquitetura

O Google recomenda o uso de uma arquitetura de aplicativo de página única. Essa abordagem permite um desempenho ideal e oferece suporte à experiência do usuário conversacional contínua. A tela interativa pode ser usada com frameworks de front-end, como Vue, Angular e React, que ajudam no gerenciamento do estado.

Arquivo HTML

O arquivo HTML define a aparência da interface. Esse arquivo também carrega a biblioteca JavaScript de tela interativa, que permite a comunicação entre seu app da Web e a ação de conversa.

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>Immersive Canvas Sample</title>
    <!-- Disable favicon requests -->
    <link rel="shortcut icon" type="image/x-icon" href="data:image/x-icon;,">
    <!-- Load Interactive Canvas JavaScript -->
    <script src="https://www.gstatic.com/assistant/df-asdk/interactivecanvas/api/interactive_canvas.min.js"></script>
    <!-- Load PixiJS for graphics rendering -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/pixi.js/4.8.7/pixi.min.js"></script>
    <!-- Load Stats.js for fps monitoring -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/stats.js/r16/Stats.min.js"></script>
    <!-- Load custom CSS -->
    <link rel="stylesheet" href="css/main.css">
  </head>
  <body>
    <div id="view" class="view">
      <div class="debug">
        <div class="stats"></div>
        <div class="logs"></div>
      </div>
    </div>
    <!-- Load custom JavaScript after elements are on page -->
    <script src="js/main.js"></script>
    <script src="js/log.js"></script>
  </body>
</html>

Comunicação entre o fulfillment e o app da Web

Agora que você criou o app da Web e o fulfillment e carregou na biblioteca de tela interativa no arquivo do app da Web, é necessário definir como o app da Web e o fulfillment interagem. Para fazer isso, modifique os arquivos que contêm a lógica do app da Web.

action.js

Esse arquivo contém o código para definir callbacks e invocar métodos usando interactiveCanvas. Os callbacks permitem que seu app da Web responda a informações ou solicitações da ação de conversa. Os métodos oferecem uma maneira de enviar informações ou solicitações para a ação de conversa.

Adicione interactiveCanvas.ready(callbacks); ao arquivo HTML para inicializar e registrar callbacks:

//action.js
class Action {
  constructor(scene) {
    this.canvas = window.interactiveCanvas;
    this.scene = scene;
    const that = this;
    this.commands = {
      TINT: function(data) {
        that.scene.sprite.tint = data.tint;
      },
      SPIN: function(data) {
        that.scene.sprite.spin = data.spin;
      },
      RESTART_GAME: function(data) {
        that.scene.button.texture = that.scene.button.textureButton;
        that.scene.sprite.spin = true;
        that.scene.sprite.tint = 0x0000FF; // blue
        that.scene.sprite.rotation = 0;
      },
    };
  }

  /**
   * Register all callbacks used by Interactive Canvas
   * executed during scene creation time.
   *
   */
  setCallbacks() {
    const that = this;
    // declare interactive canvas callbacks
    const callbacks = {
      onUpdate(data) {
        try {
          that.commands[data.command.toUpperCase()](data);
        } catch (e) {
          // do nothing, when no command is sent or found
        }
      },
    };
    // called by the Interactive Canvas web app once web app has loaded to
    // register callbacks
    this.canvas.ready(callbacks);
  }
}

main.js

Esse arquivo constrói a cena para seu app da Web. Neste exemplo, ele também processa os casos de sucesso e falha da promessa retornada com sendTextQuery(). Confira um trecho de main.js:

// main.js
const view = document.getElementById('view');
// initialize rendering and set correct sizing
this.renderer = PIXI.autoDetectRenderer({
  transparent: true,
  antialias: true,
  resolution: this.radio,
  width: view.clientWidth,
  height: view.clientHeight,
});
view.appendChild(this.element);

// center stage and normalize scaling for all resolutions
this.stage = new PIXI.Container();
this.stage.position.set(view.clientWidth / 2, view.clientHeight / 2);
this.stage.scale.set(Math.max(this.renderer.width,
    this.renderer.height) / 1024);

// load a sprite from a svg file
this.sprite = PIXI.Sprite.from('triangle.svg');
this.sprite.anchor.set(0.5);
this.sprite.tint = 0x00FF00; // green
this.sprite.spin = true;
this.stage.addChild(this.sprite);

// toggle spin on touch events of the triangle
this.sprite.interactive = true;
this.sprite.buttonMode = true;
this.sprite.on('pointerdown', () => {
  this.sprite.spin = !this.sprite.spin;
});

Suporte a interações por toque

Sua ação de tela interativa pode responder ao toque do usuário e às entradas vocais. De acordo com as diretrizes de design da tela interativa, você precisa desenvolver a ação para priorizar a voz. Alguns smart displays são compatíveis com interações por toque.

O suporte a toque é semelhante ao suporte a respostas conversacionais. No entanto, em vez de uma resposta vocal do usuário, o JavaScript do lado do cliente procura interações de toque e as usa para mudar elementos no app da Web.

Veja um exemplo disso na amostra, que usa a biblioteca Pixi.js:

...
this.sprite = PIXI.Sprite.from('triangle.svg');
...
this.sprite.interactive = true; // Enables interaction events
this.sprite.buttonMode = true; // Changes `cursor` property to `pointer` for PointerEvent
this.sprite.on('pointerdown', () => {
  this.sprite.spin = !this.sprite.spin;
});
...

Nesse caso, o valor da variável spin é enviado pela API interactiveCanvas como um callback update. O fulfillment tem uma lógica que aciona uma intent com base no valor de spin.

...
app.intent('pause', (conv) => {
  conv.ask(`Ok, I paused spinning. What else?`);
  conv.ask(new HtmlResponse({
    data: {
      spin: false,
    },
  }));
});
...

Adicionar mais recursos

Agora que você aprendeu o básico, pode melhorar e personalizar sua ação com APIs específicas para a tela. Esta seção explica como implementar essas APIs na ação de tela interativa.

sendTextQuery()

O método sendTextQuery() envia consultas de texto para a ação de conversa para invocar uma intent de forma programática. Esse exemplo usa sendTextQuery() para reiniciar o jogo de rotação triangular quando o usuário clica em um botão. Quando o usuário clica no botão "Reiniciar jogo", sendTextQuery() chama a intent Restart game e retorna uma promessa. Essa promessa vai resultar em SUCCESS se a intent for acionada e BLOCKED se não for. O snippet a seguir aciona a intent e processa os casos de sucesso e falha da promessa:

//main.js
...
that.action.canvas.sendTextQuery('Restart game')
    .then((res) => {
      if (res.toUpperCase() === 'SUCCESS') {
        console.log(`Request in flight: ${res}`);
        that.button.texture = that.button.textureButtonDisabled;
        that.sprite.spin = false;
      } else {
        console.log(`Request in flight: ${res}`);
      }
    });
...

Se a promessa resultar em SUCCESS, a intent Restart game enviará um HtmlResponse ao seu app da Web:

//index.js
...
app.intent('restart game', (conv) => {
  conv.ask(new HtmlResponse({
    data: {
      command: 'RESTART_GAME',
    },
...

Esse HtmlResponse aciona o callback onUpdate(), que executa o código no snippet RESTART_GAME abaixo:

//action.js
...
RESTART_GAME: function(data) {
  that.scene.button.texture = that.scene.button.textureButton;
  that.scene.sprite.spin = true;
  that.scene.sprite.tint = 0x0000FF; // blue
  that.scene.sprite.rotation = 0;
},
...

OnTtsMark()

O callback OnTtsMark() é chamado quando você inclui uma tag <mark> com um nome exclusivo na resposta SSML para o usuário. Nos trechos a seguir do exemplo do Snowman, OnTtsMark() sincroniza a animação do app da Web com a saída de TTS correspondente. Quando a Ação disser ao usuário Desculpe, você perdeu, o app da Web soletra a palavra correta e mostra as letras para o usuário.

A intent Game Over Reveal Word inclui uma marca personalizada na resposta ao usuário que ele perdeu o jogo:

//index.js
...
app.intent('Game Over Reveal Word', (conv, {word}) => {
  conv.ask(`<speak>Sorry, you lost.<mark name="REVEAL_WORD"/> The word is ${word}.` +
    `${PLAY_AGAIN_INSTRUCTIONS}</speak>`);
  conv.ask(new HtmlResponse());
});
...

O snippet de código a seguir registra o callback OnTtsMark(), verifica o nome da marca e executa a função revealCorrectWord(), que atualiza o app da Web:

//action.js
...
setCallbacks() {
  const that = this;
  // declare assistant canvas action callbacks
  const callbacks = {
    onTtsMark(markName) {
      if (markName === 'REVEAL_WORD') {
        // display the correct word to the user
        that.revealCorrectWord();
      }
    },
...

Restrições

Considere as seguintes restrições ao desenvolver seu app da Web:

  • Sem cookies
  • Sem armazenamento local
  • Sem geolocalização
  • Sem uso da câmera
  • Sem pop-ups
  • Ficar abaixo do limite de 200 MB de memória
  • O cabeçalho de terceiros ocupa a parte superior da tela
  • Não é possível aplicar estilos aos vídeos
  • Somente um elemento de mídia pode ser usado por vez
  • Nenhum vídeo HLS
  • Nenhum banco de dados Web SQL
  • Sem suporte para a interface SpeechRecognition da API Web Speech.
  • Sem gravação de áudio ou vídeo
  • A configuração de modo escuro não se aplica

Compartilhamento de recursos entre origens

Como os apps da Web de tela interativa são hospedados em um iframe e a origem está definida como nula, ative o compartilhamento de recursos entre origens (CORS, na sigla em inglês) para os servidores da Web e recursos de armazenamento. Isso permite que seus recursos aceitem solicitações de origens nulas.