• Nenhum resultado encontrado

Tutorial - Alexa Skills

N/A
N/A
Protected

Academic year: 2021

Share "Tutorial - Alexa Skills"

Copied!
50
0
0

Texto

(1)

   

Tutorial - Alexa Skills 

04/06/2020 

 

PET - Tecnologia em Eletrônica e Computação 

 

 

Itajubá, Minas Gerais 

 

(2)

Visão geral

Objetivos

O que é Alexa?

O que são Alexa Skills?

Por que desenvolver uma skill para Alexa?

Facilidade de acesso 4 

Velocidade e eficiência 4 

Que tipo de skill pode-se criar?

Skills de Casa Inteligente 4 

Skills de Flash Briefing 4 

Skills de Vídeo 5 

Skills de Música 5 

Funcionamento de uma skill

Passos para se construir uma skill

Passo 1: Design 6 

Passo 2: Construção 7 

Passo 3: Teste 7 

Passo 4: Certificação e Lançamento 7 

Alguns conceitos de JavaScript

Output 9 

Var, let e const 9 

Função 10 

Array 11 

Objeto 14 

Factory functions 16 

Como funciona uma Alexa Skill 19 

Desenvolvendo uma Skill - Quiz de Eletrônica Analógica 21 

Registro 21  Conhecendo a interface 21  Fase de desenvolvimento 25  Fase de teste 48 

 

 

(3)

Visão geral 

Neste documento, irá ser apresentado o que é uma Alexa Skill, qual a necessidade        de desenvolver aplicações de voz, além de um tutorial básico para o desenvolvimento        deste tipo de aplicação, de forma simples. 

Objetivos 

1. Contextualização da necessidade e viabilidade de aplicações com foco na voz.  2. Apresentação da interface de desenvolvimento. 

3. Apresentação de alguns conceitos de JavaScript, que serão necessários para a  implementação das atividades. 

4. Desenvolvimento, do zero, de uma Alexa Skill. 

(4)

O que é Alexa? 

Alexa é o serviço de voz baseado em nuvem desenvolvido pela Amazon (Alexa Voice        Service) e está disponível em diversos de dispositivos também da Amazon e de terceiros.        Com a Alexa pode-se criar experiências de interação com uma máquina de maneira mais        natural e intuitiva, até mesmo de uma forma mais “humana” do que as interações        convencionais que temos com celulares e computadores.  

Através do Alexa Voice Service (AVS) a Amazon simplificou o desenvolvimento de        serviços de voz para os desenvolvedores por meio de abstrações e de funções Lambda.  

Para o desenvolvimento de Alexa Skills, a própria Amazon oferece uma coleção de        ferramentas, APIs (interface de programação de aplicações), soluções de referência e        documentação, tanto online quanto offline. 

 

O que são Alexa Skills? 

Skills (“habilidades” do inglês) são como aplicativos para Alexa que fornecem novos        conteúdos para os clientes aproveitando da melhor maneira os recursos da AVS        disponíveis. As skills permitem que os usuários utilizem suas vozes para realizar tarefas        diárias como verificar notícias, ouvir músicas, jogar um jogo. Empresas e indivíduos podem        desenvolver skills e publicá-las na Alexa Skill Store. 

O Alexa Skills Kit (ASK) fornece APIs e ferramentas que você pode usar para criar        skills para Alexa. 

 

Por que desenvolver uma skill para Alexa? 

À medida em que os serviços de voz estão ficando cada vez mais populares, como        Alexa, Siri, Google Assistant, os consumidores utilizam mais e mais interfaces de usuário de        voz (voice user interfaces - VUIs) para jogar, receber notícias e controlar um crescente        número de dispositivos domésticos inteligentes. 

 

(5)

Facilidade de acesso 

As VUIs são naturais, conversacionais e voltadas completamente para o usuário.  Uma experiência de voz permite que os usuários expressem suas intenções de        maneiras variadas. Ela deve ser rica e flexível, por isso desenvolver para voz é        completamente diferente do que criar interfaces de usuário gráficas (GUIs) para Web ou        dispositivos móveis. 

Quanto mais fácil for utilizar uma skill, mais velocidade e eficiência ela oferecerá.

 

Velocidade e eficiência 

Como a utilização da voz é muito mais natural e intuitiva, e consequentemente mais        rápida e eficiente, as skills da alexa utilizam dessa vantagem para tornar as tarefas        mundanas ou habituais ainda mais rápidas. 

 

Que tipo de skill pode-se criar? 

O ASK permite a criação de diversos tipos de skill, oferecendo quatro modelos de        interação pré-definidos, ou pode-se criar uma skill inteiramente personalizada. os modelos        pré-construídos incluem solicitações e enunciados pré-definidos para acelerar a        construção. 

Abaixo estão quatro exemplos de skills: 

Skills de Casa Inteligente 

Utilize a API para skills de Smart Home para criar uma skill de casa inteligente. Esse        tipo de skill controla dispositivos domésticos inteligentes, como câmeras, luzes,        termostatos e smart TVs. A Smart Home Skill API oferece menos controle sobre a        experiência do usuário, porém simplifica seu desenvolvimento, pois não é necessário a        criação da VUI por conta própria. 

Skills de Flash Briefing 

Use a API para skills de Flash Briefing para fornecer aos seus clientes notícias e        outros conteúdos curtos. Como desenvolvedor de skills, você define os feed do conteúdo        para o flash briefing solicitado, podendo conter conteúdo de áudio reproduzido para o        usuário ou conteúdo de texto lido para o usuário. 

(6)

Skills de Vídeo 

Utilize a API de skills de vídeo para fornecer conteúdo de vídeo, como programas de        TV e filmes. Como desenvolvedor você define as solicitações que as skills podem        manipular, tais como pesquisar e reproduzir conteúdos de vídeos ou como os resultados        da pesquisa são exibidos nos dispositivos. 

Skills de Música 

Use a API de skills de música para fornecer conteúdo de áudio, como músicas, listas        de reprodução ou estações de rádio. Essa API processa palavras que um usuário pode        utilizar para solicitar e controlar um conteúdo de áudio. Tais palavras se transformam em        solicitações e são enviadas para a sua skills, onde ela é processada e respondida        adequadamente. 

Simples funcionamento de uma skill 

A seguir, observe um fluxograma que demonstra de forma simples como Alexa        funciona. 

  Fonte: Site da Amazon​1 

1​ Disponível em: 

<​https://developer.amazon.com/pt-BR/alexa/alexa-skills-kit/get-deeper/tutorials-code-samples/build-an-engagi ng-alexa-skill/module-1​>  

(7)

 

Vocabulário:  1 - Áudio 

2 - Reconhecimento de fala 

Entendimento da Linguagem Natural  Texto para Fala 

3 - Intenção  Função Lambda  Resposta  4 - Visual    Explicação do fluxograma: 

1 - Para iniciar a skill, o usuário diz: “Alexa, abra (nome da skill)”. 

2 - O dispositivo envia o enunciado para o serviço Alexa na nuvem onde o enunciado é        processado através de reconhecimento automático de fala, para a conversão em texto e        compreensão de linguagem natural para reconhecer a intenção de texto. 

3 - A Alexa envia uma solicitação JavaScript Object Notation (JSON) para processar a        intenção de uma função do AWS Lambda na nuvem. A função Lambda age em um        back-end e executa o código para processar a intenção. 

 

Passos para se construir uma skill 

Passo 1: Design 

Comece projetando o modelo de interação de voz da sua skill. Como projetar para        voz é diferente do que projetar para dispositivos móveis ou baseado em web, deve-se        pensar em todas as maneiras diferentes nas quais um usuário pode interagir com a skill.        Para fornecer uma experiência de voz fluida e natural, é importante criar scripts e        representar as diferentes formas que um usuário pode falar com a Alexa. 

Pode-se também construir skills multimodais, oferecendo experiência de voz e        visual, porém será necessário pensar em diferentes fluxos de navegação. 

(8)

 

Passo 2: Construção 

Quando seu modelo de interação estiver pronto, crie os enunciados, intenções e        variáveis (slots) no Console do Portal dos Desenvolvedores de Alexa. 

O modelo de interação é salvo no formato JSON e você pode editar o modelo com        qualquer ferramenta de edição. Depois que seu modelo de interação JSON estiver pronto,        crie a função backend Lambda no AWS Management Console. 

Selecione a linguagem de programação de sua escolha e o kit de desenvolvimento        de software ASK (SDK) correspondente e comece a codifica sua skill. O Lambda suporta as        linguagens de programação Java, Go, PowerShell, Node.js, C# Python e Ruby. 

Você pode criar e hospedar a maioria das skills gratuitamente com o AWS Lambda,        que é gratuito para o primeiro milhão de chamadas por mês . Quando a função backend        do Lambda estiver pronta, integre a função à sua skill e teste-a no console do        desenvolvedor da Alexa. 

Passo 3: Teste 

O console de desenvolvedor da AWS possui um simulador de Alexa integrado, que é  semelhante ao teste em um dispositivo habilitado para Alexa. 

Depois de testar a sua skill com o simulador, recomenda-se que colete feedback de  usuários para resolver problemas e fazer melhorias antes de enviar sua skill para a 

certificação. 

Passo 4: Certificação e Lançamento 

Depois de testar sua skill, envie-a para certificação. Uma vez que sua skill passar  pela certificação, ela será publicada na Alexa Skill Store para que qualquer pessoa possa  descobri-la e usá-la. 

       

(9)

Alguns conceitos de JavaScript 

 

Para o desenvolvimento de uma Alexa Skill é necessário o conhecimento de alguns        conceitos de NodeJs, uma vez que nesse tutorial será utilizado esse ambiente de execução        de JavaScript. Vale ressaltar que é possível criar uma aplicação Alexa utilizando outras        linguagens de programação, porém neste documento, iremos focar nesta linguagem. 

Os códigos que serão apresentados abaixo poderão ser testados diretamente no        navegador que você utiliza, sem a necessidade da instalação de nenhuma ferramenta, uma        vez que JavaScript foi inicialmente criada para rodar no navegador. Para isso, basta        pressionar a tecla F12, que um console será aberto, como na imagem a seguir 

Sempre que um bloco de código é executado neste console, o determinado        “comando”, que pode ser uma atribuição de uma variável, fica armazenada na sessão atual        do navegador. Se desejar redefinir uma ​const, ​por exemplo, você deverá simplesmente              recarregar a página, que o cache é limpado automaticamente.  

Caso prefira, os códigos também poderão ser testados através de qualquer        compilador online de JavaScript, como por exemplo o Repl.it, disponível no seguinte        endereço ​https://repl.it/languages/nodejs 

(10)

Output 

Para observar a saída dos testes a seguir utilizaremos a função log do objeto        console, que permite o envio de dados para o console do navegador. Se você ainda não        sabe que é objeto e/ou função, não se preocupe, porque isso isso será abordado        posteriormente. Portanto, a linha de código ficará da seguinte maneira: 

 

console​.log(​"Olá Mundo"​);

 

Var, let e const 

Primeiramente, se você vem de uma linguagem tipada, como Java e C++, essa        poderá ser a principal “estranheza”, já que JavaScript possui tipagem dinâmica, ou seja o        próprio JS define que tipo de variável você está trabalhando no momento, em tempo de        execução. Desse modo, não é necessário a utilização de palavras chave como ​int e char na                definição de uma variável. Observe no código abaixo, que é possível até mesmo alterar o        tipo de uma variável, depois de definida, sem nenhum tipo de erro. 

  let​ a = ​2​; console​.log(a); a = ​"agora eh um texto"​; console​.log(a);   

Para a definição de variáveis, existem três palavras chave da linguagem: ​var​, ​let ​e            const​. As palavras var e let são utilizadas para variáveis que podem sofrer modificações ao        longo da execução do programa. Já const não sofre alteração, uma vez definido seu        conteúdo, deve permanecer o mesmo até o final da execução da aplicação. A diferença        entre var e let é o escopo, ou seja, onde ela é “visível”, para ser lida e/ou modificada. Var,        tem escopo global, ou seja, uma vez definida, pode ser acessada em qualquer lugar do        código; já let possui escopo de bloco, ou seja, somente é visível no lugar em foi declarada,        seja uma condição, função ou laço de repetição. Agora teste o seguinte código em seu        console: 

 

const​ constante = [​1​,​2​,​3​,​4​]; constante.push(​5​);

(11)

console​.log(constante);

 

Observou que interessante? Constante é uma const, e mesmo assim, foi possível        “modificar” seu conteúdo utilizando a função push(), disponível nos arrays. A explicação        disso é que na realidade, a variável não foi alterada, pois quando ela foi declarada, o motor        de JavaScript automaticamente reservou, em um endereço específico, um espaço de        memória para o array, e esse endereço de fato não foi alterado. 

 

Função 

Como utilizado anteriormente, a partir da palavra push(), uma função é um bloco de        construção, fundamental para um desenvolvedor JavaScript. Ela pode ser definida como        um conjunto de instruções, que executa uma determinada tarefa e retorna ou não algum        dado. Para usar uma função, é necessário defini-la e depois chamá-la. Vamos ver isso a        partir de um exemplo:    function​ ​soma​ (​a, b​) { return​ a + b; } console​.log(soma(​2​,​2​)); 

 

Nesse exemplo, declaramos uma função chamada “soma”, que recebe dois        parâmetros e retorna a soma deles. Que pode ser visualizada a partir da chamada da        função utilizando o console.log, onde foi definindo ​a e ​b, ​valendo 2. Partindo do mesmo                    exemplo anterior, teste o seguinte bloco de código: 

  function​ ​soma​(​a, b​) { ​return​ a+b; } console​.log(soma(​2​));  

Agora, analisando o exemplo acima, é possível observar que, mesmo chamando a        função com apenas um argumento, ou seja: 2, a função foi executada normalmente,        porém retornando um resultado indesejado: ​NaN​. Mesmo assim, é possível chegar em        uma conclusão importante: uma mesma função pode receber, ou não, os argumentos que        foram definidos, ou seja, não é necessário criar uma nova função, para realizar uma        mesma tarefa que necessite de menos argumentos, basta determinar a lógica para tal,        diretamente no interior do bloco da função. Neste caso, obtivemos como retorno a palavra       

(12)

NaN - “Not a Number” -, porque o motor de execução JavaScript está realizando a soma de        2 + Undefined, ou seja, de um número com algo indefinido. 

Dessa maneira, ao utilizar uma função, chamando-a com menos argumentos, os        argumentos utilizados serão sempre, contabilizados da esquerda para a direita. Assim, no        exemplo acima, quando foi chamado a função passando 2 como parâmetro, a variável que        recebeu como atribuição esse valor, foi ​a​. 

Uma função muito utilizada dentro do JavaScript, é a famosa ​callback. ​Uma Função            que é passada, ou não, como argumento para outra função, e é chamada após o        acontecimento de algum evento. O exemplo a seguir utiliza-se de recursos de manipulação        da DOM, não sendo foco neste tutorial, mas a partir dele é possível consolidar essa ideia        de callback, uma vez que a função, que possui apenas um console.log() em seu escopo, é        chamada apenas quando existe um clique - um evento - dentro da página do navegador        em que você estiver.  

Depois de executar no console o bloco de código a seguir , clique em qualquer        região da página, fora do console, para observar a saída do algoritmo. 

 

document​.getElementsByTagName(​'body'​)[​0​].onclick = ​function​ (​e​) {

console​.log(​'A callback foi chamada.'​); } 

 

Array 

Agora será definido o conceito de Array, já utilizado anteriormente, porém não        explicitado como é seu funcionamento. Esse objeto é definido por um par de colchetes, de        modo que é possível utilizá-lo como uma lista de elementos; e diferentemente de outras        linguagens, não é necessário explicitar seu tamanho, isso é feito dinamicamente. Outra        coisa interessante é que, é possível atribuir mais de um tipo de dado para um mesmo        array, mas tenha cuidado com isso, como a linguagem possui tipagem dinâmica, misturar        tipos pode ser um problema, já que a ​engine ​não deve acusar nenhum erro e facilmente              você pode se perder em seu código. 

 

let​ array = [​1​,​2​,​"ola"​];

console​.log(array); 

 

Um array pode ser percorrido, utilizando a estrutura de colchetes, a partir de um        índice, que vai de zero até o tamanho do array menos um. Por exemplo, tendo em vista        que já foi declarado a variável array no exemplo anterior, execute a seguinte linha de        código. Onde obteremos, como resposta, a palavra “olá”. 

(13)

console​.log(array[​2​]); 

 

Os arrays possuem uma série de funções pré-definidas, que podem ajudar muito a        manipular esse tipo de dado. Veremos algumas das principais a seguir, mas tenha em        mente que existem diversas outras, que podem ser encontradas na documentação do        JavaScript, caso você deseje aprofundar-se no assunto. Todos os métodos a seguir,        percorrem o array, a fim de realizar algum tipo de manipulação sobre ele. 

● forEach: Os principais argumentos que este método recebe é: valorAtual, ou seja,        elemento atual durante a iteração no array; além do indiceAtual, que representa o        índice do valorAtual dentro do vetor. Além disso, essa função não possui nenhum        retorno. Esse método chama uma ​callback​, para cada elemento percorrido. Observe        o exemplo a seguir, onde é chamada a callback imprimeElemento para cada        elemento do vetor: 

 

let​ carros = [​"carro1"​, ​"carro2"​, ​"carro3"​];

function​ ​imprimeElemento​(​valorAtual, indice​) { ​console​.log(indice, valorAtual);

}

carros.forEach(imprimeElemento);

 

Observe que, para este exemplo, não foi necessário a utilização dos parênteses, a        fim de chamar a função callback imprimeElemento, uma vez que internamente, a função        forEach já os passa automaticamente. 

● map: Esse método recebe basicamente os mesmo argumentos do método anterior,        com a diferença que agora ele retorna um novo array, modificado ou não. Assim, ao        utilizar a função map(), é possível alterar o conteúdo de um vetor de maneira        simples, sem perder o valor da variável utilizada para chamá-la. Observe o exemplo        abaixo, onde um novo vetor é criado, adicionando sobrenome aos valores do array        inicial. 

(14)

const​ nomeSemSobrenome = [​"João"​, ​"Maria"​];

function​ ​adicionaSobrenome​(​nomeAtual​) { ​return​ ​`${nomeAtual} Silva`;

}

const​ nomeComSobrenome = nomeSemSobrenome.map(adicionaSobrenome);

console​.log(nomeComSobrenome);

 

Observe que a função callback, no caso acima, possui apenas um argumento. Isso        não gera problema algum para o compilador JavaScript, uma vez que ele identifica que os        outros argumentos não estão sendo utilizados no momento. Observe também, que no        retorno da função foi utilizado uma estrutura que utiliza acentos graves (` `) - em vez de        aspas simples ou duplas -, denominada template literal. Através desse tipo de definição de        string, ​é possível “embutir” variáveis dentro da ​string de maneira simples, sem necessitar da          utilização de operadores de concatenação. Além disso, a partir dessa estrutura, é possível        declarar uma ​string ​que ocupe multi-linhas.  

Análise o exemplo abaixo, onde foi declarado ​strings ​utilizando os três tipos                possíveis, com aspas simples, duplas e acentos graves, além da utilização da interpolação        de uma string dentro de outra, fazendo-se uso dos ​placeholders ${expressão}​: 

 

const​ cumprimento1 = ​'Bom dia!'​;

const​ cumprimento2 = ​"Boa tarde!"​;

const​ frase = ​`${cumprimento1} ${cumprimento2}

Boa noite!`​;

console​.log(frase);

 

● filter: Recebe basicamente os mesmo argumentos do método anterior, também        retornando um novo array. Nesse caso, a tarefa da callback é selecionar, ou melhor,        filtrar, os elementos que estarão presentes no novo ​array​. 

     

(15)

const​ notas = [​6.7​, ​5.9​, ​7.4​, ​2.5​];

function​ ​notasMaioresOuIguaisA6​ (​nota​) { ​if​(nota >= ​6​) ​return​ nota

}

const notasAprovadas = notas.filter(notasMaioresOuIguaisA6)

console​.log(notasAprovadas)

 

● reduce:   O método ​reduce ​funciona de maneira diferente dos anteriores. Nesse caso,          ele literalmente retorna um array reduzido - como o próprio nome já diz -, em um        único elemento apenas. Os principais argumentos passados para sua ​callback ​são,          acumulador e valorAtual. O acumulador representa o último valor retornado pela        callback, ​já o valorAtual representa o elemento que está sendo processado no array,            no momento. No exemplo abaixo é realizado a soma de todos os elementos do        vetor, utilizando-se desse recurso. 

 

const​ valores = [​1​, ​2, ​ ​3​, ​4​, ​5​, ​6​, ​7​, 8​ ​, ​9​, ​10​];

function​ ​somaTudo​ (​acumulador, valorAtual​) { ​return​ acumulador + valorAtual;

}

const soma = valores.reduce(somaTudo)

console​.log(soma)

 

Além desses métodos exemplificados anteriormente, existem diversos outros        interessantes que podem ser usados para a manipulação de um ​array, ​como por exemplo              o método push(elemento), que insere um novo elemento ao final do vetor. 

 

Objeto 

Se você já possui conhecimento de alguma linguagem OO, esse conceito já deve        estar bem consolidado; porém se você nunca ouviu falar do que venha a ser um ​Objeto ​em          uma linguagem de programação, vale a pena defini-lo rapidamente aqui, focando é claro,        em JavaScript.  

Essa estrutura pode ser definida como a representação de algum modelo maior. De        modo a utilizar-se em sua declaração, dados e funções, onde os dados são chamados        atributos e as funções são chamadas de métodos. Por exemplo, se desejássemos criar um       

(16)

Objeto​, que seja um número complexo, composto por sua parte real e por sua parte        imaginária: facilmente podemos representar isso utilizando a notação de objeto, definido        como atributo duas variáveis:        parteReal e parteImaginaria. Além disso, nessa        representação de um número complexo, poderia também, ser definido métodos, para que        seja possível manipular esse tipo de número, como por exemplo, realizar a conversão da        forma retangular para a forma polar.  

 

const​ numeroComplexo = { parteReal: ​5.0​,

parteImaginaria: ​5.0​,

formaRetangular: ​function​() {

console.log(`${this .parteReal} + i${this.parteImaginaria}`); },

formaPolar: ​function​() {

​let​ modulo = ​Math​.sqrt(Math​ ​.pow(​this​.parteReal,​2​) +

Math​.pow(​this​.parteImaginaria, ​2​));

​let​ angulo = ​Math.atan(​ ​this​.parteImaginaria / ​this​.parteReal) *

57.2958​;

​console​.log(​`Módulo: ${modulo}, Ângulo: ${angulo}`​); }

}

numeroComplexo.formaRetangular(); numeroComplexo.formaPolar();

 

No exemplo acima, foi criado um objeto, chamado numeroComplexo. Essa é a        maneira de se declarar um objeto literal dentro da linguagem JavaScript, utilizando-se do        par de chaves { }. Dentro do objeto, as linhas de declaração de atributos e métodos devem        ser separadas por vírgula (,). Nesse caso, foi utilizado um segundo objeto embutido da        linguagem, o Math, a fim de utilizar-se de seus métodos para cálculo de raiz quadrada e        potenciação. Para o cálculo do ângulo polar, o arco tangente foi multiplicado por 57.2958,        uma vez que esse método retorna o ângulo em radianos e foi realizado a conversão para        graus. Outra coisa importante para se destacar no exemplo acima, é que não foi utilizado        as palavras chaves ​private​, ​public ​e ​protected​, disponível em outras linguagens orientadas a                  objeto, uma vez que elas não existem em JavaScript, levando a conclusão que os atributos        e métodos declarados dentro de um objeto, de certa forma, possuem acesso público.        Desse modo, os atributos: parteReal e parteImaginaria, podem ser modificados de fora do        objeto, simplesmente utilizando-se de: 

 

(17)

 

Para acessar os atributos e métodos de um objeto, internamente, utiliza-se da        palavra reservada ​this, ​para explicitar o escopo você está trabalhando.  

Para utilizar-se de qualquer objeto literal criado, basta seguir a seguinte        nomenclatura: nome do objeto + notação ponto + nome do atributo ou método.  

Se você reparou bem na estrutura criada anteriormente, os atributos parteReal e        parteImaginaria foram definidos diretamente dentro do objeto, mas e se desejássemos        aproveitar esse código, criado diversos números complexos diferentes? A resposta para        essa pergunta está nas ​factory functions​. 

Factory functions 

Um função fábrica, traduzindo literalmente para o português, representa uma        função que tenha como principal objetivo, retornar um objeto. Isso mesmo, é possível        retornar um objeto a partir de uma função, assim como enviar uma função como        parâmetro para outra função, como já visto anteriormente na sessão de funções. Dessa        maneira, é plausível a ideia de reaproveitamento de código, tendo em vista que será        necessário apenas uma função, para criar diversos objetos diferentes, através da        modificação dos argumentos recebidos. A função factory a seguir, é responsável pela        criação de um mesmo objeto número complexo - representado no item anterior-. 

 

const​ criaNumeroComplexo = (​parteReal, parteImaginaria​) => { ​return​ {

parteReal: parteReal,

parteImaginaria: parteImaginaria, formaRetangular() {

​console​.log(​`${this​ ​.parteReal} + i${​this​.parteImaginaria}`​); },

formaPolar() {

​let​ modulo = ​Math​.sqrt(Math​ ​.pow(​this​.parteReal,​2​) +

Math​.pow(​this​.parteImaginaria, ​2​));

​let​ angulo = ​Math.atan(​ ​this​.parteImaginaria / ​this​.parteReal) *

57.2958​;

​console​.log(​`Módulo: ${modulo}, Ângulo: ${angulo}`​); }

} }

(18)

const​ complexo2 = criaNumeroComplexo(​3​,​3​); complexo1.formaRetangular();

complexo2.formaRetangular();

   

Nesse exemplo, é possível se deparar com algumas “estranhezas”, se comparado ao        exemplo da sessão de Objetos. Primeiramente, para a declaração da função factory        criaNumeroComplexo, a palavra chave ​function, ​foi omitida. Esse tipo de declaração de                função chama-se ​arrow function, ​de modo que a função é atribuída para uma variável e sua                estrutura é a seguinte:  

 

   

Se a função criada não receber nenhum parâmetro, esse argumento pode ser nulo,        fazendo com que a estrutura acima se reduza a: 

 

  Outro item interessante com a respeito as arrows functions é que elas possuem        return ​implícito, se o par de chaves { }, não for utilizado, fazendo com que seja possível a        criação de funções inline. 

Voltando ao exemplo da função factory, observa-se também que, na declaração dos        métodos internos do objeto de retorno, a palavra chave ​function ​também foi omitida,              sendo isso possível, devido a novas versões do JavaScript. Outra simplificação no código        que poderia ser realizada, é na declaração dos atributos parteReal e parteImaginaria, uma        vez que os argumentos recebidos pela função possuem o mesmo nome que os atributos,        ficando da seguinte maneira: 

(19)

const​ criaNumeroComplexo = (​parteReal, parteImaginaria​) => { ​return​ {

parteReal,

parteImaginaria, formaRetangular() {

​console​.log(​`${this​ ​.parteReal} + i${​this​.parteImaginaria}`​); },

formaPolar() {

​let​ modulo = ​Math​.sqrt(Math​ ​.pow(​this​.parteReal,​2​) +

Math​.pow(​this​.parteImaginaria, ​2​));

​let​ angulo = ​Math.atan(​ ​this​.parteImaginaria / ​this​.parteReal) *

57.2958​;

​console​.log(​`Módulo: ${modulo}, Ângulo: ${angulo}`​); }

} }

const​ complexo1 = criaNumeroComplexo(​5​,​5​);

const​ complexo2 = criaNumeroComplexo(​3​,​3​); complexo1.formaRetangular();

complexo2.formaRetangular();

 

(20)

Como funciona, detalhadamente, uma Alexa Skill  

Uma skill de Alexa possui tanto um modelo de interação (interface de usuário de        voz) como uma lógica de aplicativo. Quando um usuário fala, a Alexa faz o processamento        desta fala em seu contexto de modelação de interação para determinar qual solicitação o        usuário requeriu.  

O processamento é iniciado, assim que o usuário diz a palavra “Alexa” , que é uma        palavra de ativação, e a partir desse momento o dispositivo começa a capturar tudo o que        o usuário estiver falando.  

Uma vez capturado o áudio, ele é enviado para o Alexa Voice Service (AVS), e tudo        aquilo que foi dito após a palavra Alexa é chamada de User’s Utterance, expressão do        usuário, e esse áudio é encaminhado para o AVS onde será gerenciado pelo componente        Speech Platform, em seguida encaminhado para o Automatic Recognition Speed (ASR) que        converterá o áudio em texto, nesta parte podemos notar que o AVS usa muito Machine        Learning, muita inteligência artificial.  

Após convertido em texto, o ASR devolve para o Speech Platform, onde ele enviará o        arquivo para um outro componente o Natural Language Understanding (NLU), e lá é feito a        compressão da requisição feita pelo usuário, uma vez entendido, o NLU transforma o texto        em uma Intent e devolve para o Speech Platform.  

Agora que o Speech Platform sabe qual é a intenção ele procurará dentro do        catálogo de todas Skills se alguma delas pode realizar essa intenção, se for encontrada        alguma Skill que possa realizar, ela será acionada e processará a Intent, devolvendo uma        diretiva para o Speech Platform.  

Mas ainda precisamos converter o arquivo em texto para áudio novamente, e para        isso o componente Text To Speech (TTS) fará a conversão e devolverá para o Speech        Platform e finalmente o áudio será enviado para o dispositivo. 

(21)

  Fonte: Site da Amazon​2 

Dentre todos componentes citados acima, neste tutorial vamos focar apenas no  componente das Skills. 

   

Fonte: Site da Amazon​2 

   

2​ Disponível em: < ​https://developer.amazon.com/pt-BR/alexa​ > 

   

(22)

 

Desenvolvendo uma Skill - Quiz de Eletrônica Analógica 

Registro 

Para começar o processo de desenvolvimento de uma Alexa Skill, é necessário        possuir uma conta na Amazon Developer. Se você ainda não possui uma conta, ​       clique aqui    para se registrar, o processo é rápido e totalmente gratuito. 

Conhecendo a interface  

Já possuindo sua conta de desenvolvedor na Amazon, vá para o console de        desenvolvimento Alexa, ​clicando aqui​. Você irá se deparar com a seguinte tela. 

   

Nesse ponto, para começar o projeto de uma aplicação Alexa, pressione o botão        Create Skill e você será enviado para a próxima tela, onde é possível escolher o nome        desejado para sua Skill, além da linguagem padrão de desenvolvimento. Nas opções        abaixo, designadas para a escolha de um modelo, você poderá começar o        desenvolvimento a partir de um projeto customizado, onde você construirá todas as        interações de sua Skill ou um projeto pré-construído, se desejar implementar uma Skill que        esteja dentro de uma das categorias disponíveis, possuindo assim, uma série de intenções        e sentenças prontas que poderão ser utilizadas como auxílio de desenvolvimento. Na série        de opções de escolha para hospedagem do backend da Skill, você pode poderá escolher       

(23)

para a Alexa hospedar para você, utilizando o nível gratuito do AWS, com disponibilização        de uma AWS Lambda, com 5GB de armazenamento e 15GB de transferência de dados        mensal, de modo que é possível escolher entre os ambientes do NodeJs ou Python; ou        você poderá hospedar em um servidor próprio, opção utilizada quando a aplicação possui        alta taxa de armazenamento e transferência de dados, ou seja, uma aplicação que já esteja        em fase de produção. Na imagem abaixo é possível observar essa tela explicada        anteriormente. 

 

   

Ao definir o nome para sua Skill e algumas das configurações iniciais, você será        enviado para a próxima fase de configuração. Agora, é necessário escolher o template base        que você utilizará para o desenvolvimento de seu projeto. Nesse ponto, é possível escolher       

(24)

criar uma Skill a partir de algumas já desenvolvidas, e que podem ser utilizadas como base        para uma aplicação maior. Se a opção desejada não estiver disponível na lista, é possível        importar uma skill, a partir de repositório público do GitHub. 

 

   

Após definir o template base, você será enviado para a página principal do console        de desenvolvimento Alexa, onde é possível identificar vários pontos importantes, como por        exemplo, alguns recursos disponibilizados que ajudam na construção de uma Alexa Skill,        como tutoriais em vídeo; além da documentação oficial, fórum e relatório de atualizações        recentes. Na barra lateral à direita, é mostrado as etapas que seu projeto deve seguir para        enfim realizar as simulações, em um simulador, em um dispositivo echo ou até mesmo em        um smartphone. Na barra lateral à esquerda, os principais itens são: 

Interaction Model:​ Responsáveis pela interação da Skill 

○ Definir o nome de invocação da Skill - que pode ser diferente do nome da        Skill -. Através da aba ​Invocation​. 

Criação e gerenciamento de intenções, a partir da aba ​Intents. ​Note que para              qualquer Skill criada, irá existir algumas intenções em ​Built-In Intents, ​que são              padrão e necessárias para o funcionamento correto da aplicação. 

Criação e gerenciamento de ​Slot Types, ​ou seja, novos tipos de dados, que                  possivelmente não estão presentes de forma padrão. 

○ Possibilidade de desenvolvimento do modelo de interações a partir de um        JSON, a partir da aba ​JSON Editor​. 

Interfaces: ​Controle das diversas interfaces possíveis para o projeto, como interface        de áudio e vídeo. 

(25)

Endpoint​: Serviço de hospedagem do back-end em um web server, para que a Alexa        Skill possa enviar requisições HTTP e consequentemente obter respostas. 

Observando agora a barra de menu superior, é possível definir o funcionamento        dos seguinte itens: 

Build: ​A partir dessa opção - que já inicializa selecionada, por padrão - é possível          realizar as construções explicitadas no item anterior. 

Code: ​Nessa opção é possível, a partir da ferramenta de edição do console de        desenvolvimento, programar o backend da Skill, a fim de receber/responder as        requisições. 

Test: ​Opção utilizada para testar a Skill, através do simulador Alexa. Nesse ponto é        interessante explicitar também que, é possível realizar o teste das Skills através dos        dispositivos que estejam vinculados a sua conta de desenvolvimento, como por        exemplo Echo Dot ou até mesmo um dispositivo celular, a partir do aplicativo        Amazon Alexa. 

Distribution: ​Opção utilizada para definir algumas informações e configurações de        distribuição para a Skill que está sendo desenvolvida. Normalmente essa etapa é        realizada na etapa final de construção da aplicação. Nesta aba, estão disponíveis        customizações que aparecerão para sua skill na Alexa Skills Store, por exemplo.  Certification: ​Nesta opção, é possível realizar as validações necessárias para a       

disponibilização de uma Skill. Assim, é realizado a certificação e se esta etapa for        aprovada pela Amazon, a publicação da Skill.  

Analytics: ​A partir dessa opção, é possível visualizar alguns dados quantitativos          referentes à utilização da Skill, como por exemplo a quantidade e quais ​Intents        foram chamadas. 

A imagem abaixo exemplifica essa janela principal de desenvolvimento. 

(26)

Fase de desenvolvimento  

Neste item será desenvolvido uma Skill responsável por realizar perguntas e        respostas de um determinado assunto. Desse modo, iremos construir do zero, um Quiz -        jogo de perguntas e respostas -, com o tema: eletrônica analógica. 

Para isso, abra a página do console de desenvolvimento Alexa, ​       clicando aqui​  , ou    através do link ​     https://developer.amazon.com/alexa/console/ask​. Nessa página, clique no          botão ​Create Skill. ​Em ​Skill name, ​escreva Quiz de Eletrônica Analógica; em ​Default Language​,                      selecione Portuguese (BR), se já não estiver marcado; selecione o modelo ​Custom ​e o            método de hospedagem do backend como sendo ​Alexa-Hosted (Node.js). ​As imagens a                seguir exemplificam esse passos iniciais. 

 

(27)

  Feito isso, clique no botão ​Create Skill, ​localizado no canto superior direito. Na               

próxima tela, deixe selecionado o template padrão, para uma ​Hello World Skill, ​e clique no                  botão ​Continue with template, ​como na imagem abaixo. 

  Nesse ponto a Skill inicial está sendo criada, sendo necessário alguns minutos para

       

a conclusão. 

Com o projeto inicial da Skill criado, primeiramente vamos definir o nome de        invocação para Skill, para isso, selecione o item ​Invocation, ​disponível no menu lateral                esquerdo. No campo ​Skill Invocation Name, ​escreva: quiz de eletrônica analógica, esse será                  o nome utilizado todas as vezes que desejarmos chamar a Skill através da Alexa. Feito isso,        clique no botão ​Save Model ​e após, no botão ​Build Model, ​para que a alteração seja salva e o                            modelo seja reconstruído; lembre-se sempre se clicar nesses botões ao realizar alguma        alteração em sua Skill. 

Agora é necessário criarmos as intenções que serão utilizadas pela nossa Skill, além        de apagar a intenção ​HelloWorldIntent, ​já que não a utilizaremos. Para deletar essa ​intent​,                  simplesmente clique a lixeira, em seu lado direito, como na imagem a seguir:  

(28)

 

Uma janela de confirmação irá aparecer, clique em ​Delete Intent. ​Após isso, é hora                  de criarmos as ​intents ​que serão úteis em nossa aplicação. Clique no botão ​Add, ​na frente                    no nome ​intents (4). ​Escreva no campo ​Create custom intent ​o nome: QuizIntent. Essa                            intenção será responsável por gerenciar as perguntas do Quiz. Clique no botão ​Create        custom intent​. Essa etapa é representada na imagem a seguir: 

   

Após criada a ​intent​, devemos definir quais expressões irão chamar essa intenção.        Como essa será a nossa intent principal, devemos utilizar frases que serão responsáveis        por iniciar o jogo. Assim, no campo ​Sample Utterances​, escreva as seguintes sentenças,              sempre pressionando a tecla Enter, após a inserção de cada uma delas:  

● começar quiz  ● começar jogo  ● jogar 

(29)

Desse modo, sua tela deve se semelhante com a seguinte: 

  Feito isso, clique em ​Save Model e a seguir em ​Build Model. ​Agora vamos criar a                            intenção responsável por gerenciar as respostas das perguntas do quiz. Assim, realizando        os mesmos passos anteriores, crie uma intent, com o nome: AnswerIntent. Após isso, ainda        não defina nenhuma sentença, pois será necessário a criação de um novo tipo de variável,        um novo ​Slot Type. ​Para isso, clique no item ​Add, ​em frente ao item de menu ​Slot Type​,                          disponível no menu lateral esquerdo. Escreva: AnswerSlot, como nome do ​Slot Type. ​Após,            clique no botão​ Create custom slot type​.​ ​Como na imagem abaixo: 

  Esse passo de criação de um ​Slot Type ​customizado é importante, uma vez que não               

existe um slot padrão que possua os valores que iremos utilizar para as respostas das        perguntas do quiz. Utilizaremos as letras a,b e c, como respostas das questões, e para isso,        é necessário que a Alexa reconheça quando estamos trabalhando com esses valores,        através desse slot criado. É importante ressaltar que, sempre que existir na biblioteca       

(30)

padrão, os Slots que irão ser utilizados, como por exemplo de datas, opte por eles, já que        eles possuem maior compatibilidade. Em ​Slot Values​, escreva os seguintes valores, seguidos              pelo pressionamento da tecla Enter do teclado, para que o valor seja inserido :  

● a.  ● b.  ● c. 

Os valores de seu AnswerSlot, deve ser semelhante a este: 

  Observe que foi necessário um ponto (.), ao final de cada valor. Isso é necessário        para que a Alexa reconheça que estamos trabalhando com letras e não palavras, já que ela        poderia entender B como sendo Be, por exemplo. 

Agora que já possuímos o ​Slot Type ​customizado, é necessário retornar à                AnswerIntent, clicando sobre ela , no menu lateral esquerdo. Crie as seguintes expressões: 

● {answer} 

● alternativa {answer} 

Sempre que desejarmos trabalhar com valores ditos variáveis, aqui chamados de        slots​, devemos utilizar o par de chaves, delimitando o ​slot​. Quando um ​slot ​é digitado, uma             

(31)

janela é mostrada, para que seja criado um novo ​slot ​ou utilizado um já existente. Para a                primeira expressão criada, devemos criar o ​slot ​answer, já que ele ainda não foi definido. Já              para a segunda expressão cadastrada, não é necessário. Após o cadastro das sentenças,        sua tela deve estar assim: 

  Embaixo das ​utterances, ​estão os slot cadastrados na ​intent. ​Nesse caso temos o slot                    answer. Como na imagem a seguir. 

 

Agora que já possuímos as expressões e o ​slot ​em nossa ​intent​, demos definir qual é              o tipo do ​slot ​criado. Nesse caso, o ​slot ​answer é do tipo AnswerSlot, criado anteriormente.                        Para isso selecione o ​Slot Type ​para o ​slot, ​na caixa de seleção à direita do nome do ​slot.                            Essa etapa é representada pela imagem a seguir. 

(32)

  Feito isso, clique nos botões ​Save Model ​e ​Build Model.  

O próximo passo é definir uma ​intent ​responsável por gerenciar a troca de              perguntas, para que a Alexa reconheça quando desejarmos ir para a próxima pergunta do        quiz. Para isso, Clique em ​Add, ​em ​Intents, ​para uma nova intenção ser criada. Escreva:                  NextQuestionIntent, como sendo o nome da ​Intent ​e clique no botão ​Create custom intent​.                      Como na imagem abaixo. 

  As expressões que iremos criar para a ​intent​ são as seguintes: 

● próxima pergunta  ● próxima 

● próximo 

(33)

  Após, clique no botão Save Model e Build Model. 

Com a fase de construção da Skill concluído, deve-se agora, programar o backend        da Skill, para que seja possível receber e responder as requisições. Assim, selecione o item        de menu ​Code, ​disponível na barra de menu superior. 

Com a janela do código aberto, primeiramente devemos apagar o objeto        HelloWorldIntentHandler, já que esta Intent não existem mais. O bloco de código a ser        deletado é o seguinte:    const​ HelloWorldIntentHandler = { canHandle(handlerInput) { return​ Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest' && Alexa.getIntentName(handlerInput.requestEnvelope) === 'HelloWorldIntent'​; }, handle(handlerInput) {

const​ speakOutput = ​'Hello World!'​;

return​ handlerInput.responseBuilder

.speak(speakOutput)

//.reprompt('add a reprompt if you want to keep the session open for the user to respond')

(34)

.getResponse(); }

};

 

Após deletado esse bloco de código, é necessário apagar também, a chamada desse        objeto na exportação do ​handler, ​ao final do código. Desse modo, localize a linha que                possua o nome do objeto deletado anteriormente e, exclua essa linha. Feito isso, clique no        botão ​Save ​e depois ​Deploy, ​para que o código seja salvo e compilado. Agora, esse bloco de                código deve parecer-se com o seguinte. 

  exports.handler = Alexa.SkillBuilders.custom() .addRequestHandlers( LaunchRequestHandler, HelpIntentHandler, CancelAndStopIntentHandler, SessionEndedRequestHandler,

IntentReflectorHandler, ​// make sure IntentReflectorHandler is last so it doesn't override your custom intent handlers

) .addErrorHandlers( ErrorHandler, ) .lambda();   

Sempre que um novo ​Handler​, ou seja, um objeto que gerencie uma ​Intent​, for        criado, ele deverá ser adicionado no método ​addRequestHandlers, ​já que é a partir deste,                que a Alexa encontra os ​handlers​, agindo assim, como um ponto de entrada para a Skill. 

Antes de criarmos os ​handlers ​para as ​intents ​definidas anteriormente, vamos criar                        um novo arquivo, onde colocaremos as perguntas do nosso quiz e, utilizando o sistema de        módulos do Node.js, importaremos para o index.js, ou seja, para nosso arquivo principal.        Desse modo, na lateral esquerda da página, clique com o botão direito do mouse em cima        da pasta ​lambda​, e selecione ​Create File. ​Crie o arquivo questions.js, como na imagem                abaixo. 

(35)

   

No arquivo de questões, copie o código a seguir:   

const​ questions = [ {

question: ​'Quantos diodos possui um retificador em ponte? Letra a, 1. Letra b, 2. Letra c, 4.'​,

answer: ​'c'​,

answerSpeech: ​'Um retificador em ponte possui 4 diodos.'

}, {

question: ​'Qual a principal forma de atuação do diodo Zéner? Letra a, de forma direta. Letra b, de forma reversa. Letra c, de forma polar.'​,

answer: ​'b'​,

answerSpeech: ​'A principal forma de atuação do diodo Zéner é de forma reversa.'

}, {

question: ​'Como é construído um diodo? Letra a, a partir da junção JK. Letra b, a partir da junção PN. Letra c, a partir da junção S R.'​,

answer: ​'b'​ ,

(36)

de um semicondutor do tipo P com um semicondutor do tipo N.'

}, {

question: ​'Qual a mínima tensão nominal, para um diodo de silício polarizado diretamente, necessária para reduzir a região de depleção do diodo e, fazê-lo começar a conduzir corrente elétrica de fato? Letra a, 0.8 Volts. Letra b, 0.6 Volts. Letra c, 0.7 Volts.'​,

answer: ​'c'​ ,

answerSpeech: ​'É necessário uma tensão nominal de no mínimo 0.7 Volts para um diodo de silício e de no mínimo 0.3 Volts para um diodo de

germânio.'

}, {

question: ​'Qual a frequência na carga, para um retificador de onda completa? Letra a, a mesma frequência de entrada. Letra b, duas vezes a frequência de entrada. Letra c, três vezes a frequência de entrada.'​,

answer: ​'b'​ ,

answerSpeech: ​'A frequência na carga, para um retificador de onda completa é duas vezes a frequência de entrada.'

}, {

question: ​`Qual a tensão de pico na carga, para um retificador de onda completa em ponte? Supondo uma tensão de pico do secundário do transformador com sendo V secundário?

Letra a, V secundário, menos a queda de tensão de quatro diodos. Letra b, V secundário, menos a queda de tensão de 1 diodo. Letra c, V secundário, menos a queda de tensão de dois diodos.`​,

answer: ​'c'​ ,

answerSpeech: ​'A tensão de pico na carga, para um retificador de onda completa em ponte, é V secundário menos a queda de tensão de dois diodos. Já que tanto no semi-ciclo positivo, quanto negativo, dois dos quatro diodos, estão sempre conduzindo.'

}, ]

const​ amount = questions.length

(37)

questions, amount } 

 

Após isso, salve e compile novamente. 

No código apresentado para o arquivo de questões, foi definido um array questions,        de objetos, de modo que cada objeto possui três atributos: a pergunta que a Alexa irá        realizar, a resposta para a pergunta e a fala que a Alexa irá realizar após o respondimento        da questão pelo usuário. Também foi definido uma constante amount que armazena o        tamanho do array de perguntas. Esse array possui apenas seis perguntas a título de        simplificação, já que poderia apresentar uma quantidade qualquer de questões. Desse        modo, foi utilizado o module.exports, para exportar um objeto que possui o array de        questões e o tamanho do array, como atributos, a fim de importarmos esse módulo no        arquivo principal, o index.js. 

Voltando para o arquivo index.js, iremos realizar a importação do arquivo        questions.js, utilizando o ​require ​e o operador ​destructuring, ​disponível a partir da versão                      2016 do JavaScript, logo abaixo da linha: ​const Alexa = require('ask-sdk-core'); 

 

const {questions,amount} = require('./questions');

O operador ​destructuring ​é definido por esse par de chaves, de modo que a partir              dele é possível desestruturar o objeto importado através do require(‘.questions’), e desse        modo, recuperar as constantes questions e amount do arquivo requerido, para que seja        possível utilizá-las no arquivo atual.  

Agora, vamos criar uma função responsável por embaralhar o nosso array de        perguntas. Para que todas as vezes que o usuário abra a Skill, as questões sejam realizadas        em ordens diferentes. Em baixo da linha de código definida anteriormente, crie a seguinte        função, que simplesmente recebe um array e o embaralha: 

 

function​ ​shuffle​(​array​) {

let​ aux1, aux2;

for​(​let​ i = amount​-1​; i > ​0​; i--) {

aux1 = ​Math​.floor(​Math​.random() * (i+​1​)); aux2 = array[i];

array[i] = array[aux1]; array[aux1] = aux2;

(38)

} } 

 

Após isso, salve e compile novamente. 

Devemos agora, declarar três variáveis que serão utilizadas. Uma variável        responsável por definir a quantidade de perguntas que desejamos que seja realizada, em        cada vez que a Skill for aberta. Uma segunda variável, responsável por armazenar o índice        no array da pergunta que está sendo realizada, para que seja possível iterar sobre ele. E        uma terceira variável, para que seja possível contabilizar a quantidade de perguntas que o        usuário acertou. Assim, logo abaixo da função definida anteriormente, declare as seguintes        constantes:    const​ amountQuestions = ​3​; let​ idCurrentQuestion = ​0​; let​ score = ​0​;   

Salve e compile o código. 

Agora, vamos modificar algumas linhas nos handlers que já estão criados, para que        a Alexa fale as frases em português. No ​LaunchRequestHandler​, intent utilizada quando a        Skill é inicializada, substitua o código, para o seguinte: 

  const​ LaunchRequestHandler = { canHandle(handlerInput) { return​ Alexa.getRequestType(handlerInput.requestEnvelope) === 'LaunchRequest'​; }, handle(handlerInput) {

const​ speakOutput = ​`Bem vindo ao quiz de eletrônica analógica. Você

será submetido à ${amountQuestions} perguntas. Para começar o jogo você pode dizer coisas como: começar jogo, jogar e começar quiz.`​;

shuffle(questions); return​ handlerInput.responseBuilder .speak(speakOutput) .reprompt(speakOutput) .getResponse(); } };   

(39)

Dentro um objeto handler, como o LaunchRequestHandler por exemplo, possuímos        dois métodos: canHandle() e o handle(). O método canHandle() é responsável por definir        quando o método handle() será executado; nesse caso, dentro do método canHandle(), é        definido para que o método handle(), seja executado somente se o ​intent ​que estiver            fazendo a requisição, for do tipo LaunchRequest. O método handle() que de fato a        manipulação desejada pela intenção. Dentro do método handle(), existe uma constante        com o nome de speakOutput que, utilizando-se de template string, é declarado uma frase        para que Alexa diga. Também nesse método é chamada a função shuffle(), passando o        array de perguntas - para que ele seja embaralhado ao iniciar da Skill -. Ao retorno do        método handle(), existem três funções disponíveis no ​respondeBuilder: ​a função speak, para                que a Alexa, fale a frase definida anteriormente; a função reprompt(), para que a sessão        continue aberta, esperando uma resposta do usuário; e a função getResponse(), para uma        resposta em JSON, seja gerada. 

No handler da ​Intent ​Help, é necessário alterar somente a constante speakOutput,              para que seja uma frase em português. Em HelpIntentHandler, localize a linha dessa        variável e substitua-a pela seguinte: 

 

const​ speakOutput = ​'Como posso te ajudar?'​; 

   

Já no handler da ​Intent ​CancelAndStop, também é necessário alterar somente a                constante speakOutput, substitua-a pela seguinte: 

 

const​ speakOutput = ​'Tchau. Até mais!'​; 

 

Para os ​handlers ​IntentReflectorHandler e ErrorHandler, também altere a constante            speakOutput, substituindo-as respectivamente pelas seguintes: 

 

IntentReflectorHandler : 

const​ speakOutput = ​`Você acabou de chamar a intent ${intentName}`​; 

 

ErrorHandler: 

const​ speakOutput = ​`Me Desculpe, Eu tive problemas para fazer o que você

pediu. Por favor, tente novamente.`​; 

 

Clique nos botões de ​Salve ​e ​Deploy​. 

A partir de agora, iremos implementar os ​handlers ​para as nossas Intents                customizadas. O primeiro deles será o handler para a intenção QuizIntent. Logo abaixo do        handler LaunchRequestHandler, cole o seguinte código: 

(40)

const​ QuizIntentHandler = { canHandle(handlerInput) {

return​ handlerInput.requestEnvelope.request.type === ​'IntentRequest'

&& handlerInput.requestEnvelope.request.intent.name ===

'QuizIntent'​; },

handle(handlerInput) {

const​ speechText = questions[idCurrentQuestion].question;

return​ handlerInput.responseBuilder .speak(speechText) .reprompt(speechText) .getResponse(); } };   

Salve e compile o código. 

Esse handle é responsável por “pegar” a questão disponível na posição        idCurrentQuestion, no array de perguntas, e armazená-la na constante speechText, na qual        a Alexa perguntará para o usuário. O método repromt garante que a sessão permanecerá        aberta até o usuário responder a pergunta. 

O próximo handle é responsável por gerenciar a Intent de resposta das questões, o        AnswerIntent. Ou seja, quando a Intent que será chamada quando o usuário responder a        pergunta disponibilizada pelo handle da Intent QuizIntent. Desse modo, copie o seguinte        bloco de código logo abaixo do handler construído anteriormente. 

 

const​ AnswerIntentHandler = {

canHandle(handlerInput) {

return​ handlerInput.requestEnvelope.request.type === ​'IntentRequest'

&& (handlerInput.requestEnvelope.request.intent.name ===

'AnswerIntent'​); },

handle(handlerInput) {

// armazena os slots que vieram junto com a requisição

const​ slot = handlerInput.requestEnvelope.request.intent.slots;

// pega o valor do slot com nome 'answer', do objeto slot

const​ answerSlot = slot[​'answer'​].value.toLowerCase();

let​ speechText = ​''​;

(41)

para ir para a proxima pergunta. Se já foi atingido, fala para ver o rendimento

let​ speechNext = (idCurrentQuestion + ​1​ < amountQuestions) ? ​'Vá para a próxima pergunta dizendo: próxima.'​ : ​'Você respondeu todas as perguntas disponíveis. Descubra seu rendimento dizendo: próximo.'​;

// se a resposta da questão for igual ao valor que o usuário falou

if​(answerSlot === questions[idCurrentQuestion].answer){ speechText = ​`Isso mesmo!

${questions[idCurrentQuestion].answerSpeech} ${speechNext}`​; score++

}

else​ {

speechText = ​`Resposta incorreta.

${questions[idCurrentQuestion].answerSpeech} ${speechNext}`​; } return​ handlerInput.responseBuilder .speak(speechText) .reprompt() .getResponse(); } };   

Salve e compile o código. 

O próximo e último handle, diz respeito à Intent NextQuestionIntent, para o        gerenciamento da próxima pergunta ou para o término do jogo. Copie o seguinte bloco de        código logo abaixo do handle anterior: 

 

const​ NextQuestionIntentHandler = {

canHandle(handlerInput) {

return​ handlerInput.requestEnvelope.request.type === ​'IntentRequest'

&& (handlerInput.requestEnvelope.request.intent.name ===

'NextQuestionIntent'​); },

handle(handlerInput) {

idCurrentQuestion++ ​// aumenta índice, para ir para a próxima pergunta

if​(idCurrentQuestion < amountQuestions) ​// se ainda não atingiu a quantidade de perguntas, chama o handle QuizIntentHandler, para refazer o

(42)

ciclo

return​ QuizIntentHandler.handle(handlerInput);

else​ {

idCurrentQuestion = ​0​; ​// zera o índice, para um possível próximo jogo

const​ scorePorcent = (score/amountQuestions) * ​100​; ​// calcula a quantidade de acertos em porcentagem

score = ​0​; ​// zera a pontuação atual, para um possível próximo jogo

shuffle(questions); ​// embaralha o array de perguntas, para um possível próximo jogo

let​ speechResult = ​''​;

if​(scorePorcent > ​60​ && scorePorcent < ​80​)

speechResult = ​`Você atingiu a porcentagem de acerto entre 60 e 80 por cento.`​;

else​ ​if​(scorePorcent > ​80​)

speechResult = ​'Parabéns! Você obteve um rendimento igual ou superior à 80 por cento.'​;

else

speechResult = ​'Infelizmente você não chegou aos 60 por cento de acerto.'​;

return​ handlerInput.responseBuilder

.speak(​`${speechResult} Espero você em outro momento para jogarmos novamente! Até mais!`​)

.getResponse(); } } };  

Por fim, é necessário inserir os ​handles ​que foram adicionados ao código, no              addRequestHandlers​, como feito anteriormente com a ​Intent ​HelloWorld. Vá para o final do              arquivo e localize o exports.handle. Adicione as linhas faltantes, para que esse bloco de        código fique da seguinte forma: 

  exports.handler = Alexa.SkillBuilders.custom() .addRequestHandlers( LaunchRequestHandler, QuizIntentHandler, AnswerIntentHandler, NextQuestionIntentHandler,

(43)

HelpIntentHandler,

CancelAndStopIntentHandler, SessionEndedRequestHandler,

IntentReflectorHandler, ​// make sure IntentReflectorHandler is last so it doesn't override your custom intent handlers

) .addErrorHandlers( ErrorHandler, ) .lambda();   

Salve e faça o Deploy da aplicação.  

Pronto! Feito todos esses passos, nosso Quiz de Eletrônica Analógica está concluído.        Se você apresentar algum erro durante a fase de teste, volte ao código apresentado a        seguir e verifique se seu index.js ficou semelhante ao apresentado, após todas as etapas:   

// This sample demonstrates handling intents from an Alexa skill using the Alexa Skills Kit SDK (v2).

// Please visit https://alexa.design/cookbook for additional examples on implementing slots, dialog management,

// session persistence, api calls, and more.

const​ Alexa = ​require​(​'ask-sdk-core'​);

const​ {questions,amount} = ​require​(​'./questions'​);

function​ ​shuffle​(​array​) {

let​ aux1, aux2;

for​(​let​ i = amount​-1​; i > ​0​; i--) {

aux1 = ​Math​.floor(​Math​.random() * (i+​1​)); aux2 = array[i]; array[i] = array[aux1]; array[aux1] = aux2; } } const​ amountQuestions = ​3​; let​ idCurrentQuestion = ​0​; let​ score = ​0​; const​ LaunchRequestHandler = { canHandle(handlerInput) { return​ Alexa.getRequestType(handlerInput.requestEnvelope) ===

(44)

'LaunchRequest'​; },

handle(handlerInput) {

const​ speakOutput = ​`Bem vindo ao quiz de eletrônica analógica. Você

será submetido à ${amountQuestions} perguntas. Para começar o jogo você pode dizer coisas como: começar jogo, jogar e começar quiz.`​;

shuffle(questions); return​ handlerInput.responseBuilder .speak(speakOutput) .reprompt(speakOutput) .getResponse(); } }; const​ QuizIntentHandler = { canHandle(handlerInput) {

return​ handlerInput.requestEnvelope.request.type === ​'IntentRequest'

&& handlerInput.requestEnvelope.request.intent.name ===

'QuizIntent'​; },

handle(handlerInput) {

const​ speechText = questions[idCurrentQuestion].question;

return​ handlerInput.responseBuilder .speak(speechText) .reprompt(speechText) .getResponse(); } }; const​ AnswerIntentHandler = { canHandle(handlerInput) {

return​ handlerInput.requestEnvelope.request.type === ​'IntentRequest'

&& (handlerInput.requestEnvelope.request.intent.name ===

'AnswerIntent'​); },

handle(handlerInput) {

// armazena os slots que vieram junto com a requisição

const​ slot = handlerInput.requestEnvelope.request.intent.slots;

// pega o valor do slot com nome 'answer', do objeto slot

const​ answerSlot = slot[​'answer'​].value.toLowerCase();

let​ speechText = ​''​;

(45)

// Se o valor de perguntas amountQuestions não foi atingido, fala para ir para a proxima pergunta. Se já foi atingido, fala para ver o rendimento

let​ speechNext = (idCurrentQuestion + ​1​ < amountQuestions) ? ​'Vá para a próxima pergunta dizendo: próxima.'​ : ​'Você respondeu todas as perguntas disponíveis. Descubra seu rendimento dizendo: próximo.'​;

// se a resposta da questão for igual ao valor que o usuário falou

if​(answerSlot === questions[idCurrentQuestion].answer){ speechText = ​`Isso mesmo!

${questions[idCurrentQuestion].answerSpeech} ${speechNext}`​; score++

}

else​ {

speechText = ​`Resposta incorreta.

${questions[idCurrentQuestion].answerSpeech} ${speechNext}`​; } return​ handlerInput.responseBuilder .speak(speechText) .reprompt() .getResponse(); } }; const​ NextQuestionIntentHandler = { canHandle(handlerInput) {

return​ handlerInput.requestEnvelope.request.type === ​'IntentRequest'

&& (handlerInput.requestEnvelope.request.intent.name ===

'NextQuestionIntent'​); },

handle(handlerInput) {

idCurrentQuestion++ ​// aumenta indice, para ir para a próxima pergunta

if​(idCurrentQuestion < amountQuestions) ​// se ainda não atingiu a quantidade de perguntas, chama o handle QuizIntentHandler, para refazer o ciclo

return​ QuizIntentHandler.handle(handlerInput);

else​ {

idCurrentQuestion = ​0​; ​// zera o indice, para um possível próximo jogo

const​ scorePorcent = (score/amountQuestions) * ​100​; ​// calcula a quantidade de acertos em porcentagem

Referências

Documentos relacionados

das provas, ainda que de posse de documento oficial de licença para o respectivo porte; fizer uso ou portar, mesmo que desligados, durante o período de realização das provas,

Seguindo a mesma tendência, os clientes heavy users de mobile também mais que dobraram em 2020, e os clientes heavy users do internet banking também cresceram significativamente.

A) é base de uma teoria da reprodução e manutenção social, como para Émile Durkheim. B) limita-se ao período da infância, sendo a fase adulta de seres já socializados.

Este exemplo vai servir como uma regra para todos os outros dias da semana.Para você deve saber qual desses anjos está presidindo as horas, porque as operações planetários

A Pró-Reitoria de Assuntos Estudantis, por intermédio da Divisão Multidisciplinar de Assistência ao Estudante (DIMAE/PROAES) torna público o lançamento do presente edital

Milevo - Fotos, vídeos, mapas, comentários e os melhores destinos na opinião de quem viaja... Cabo de

Nessa toada, é legítima a expectativa do consumidor de que, uma vez prevista no contrato a cobertura para determinada patologia ou procedimento, nela esteja incluído o custeio

17 CORTE IDH. Caso Castañeda Gutman vs.. restrição ao lançamento de uma candidatura a cargo político pode demandar o enfrentamento de temas de ordem histórica, social e política