diff --git a/translations/pt-PT/5-retail/lessons/2-check-stock-device/wio-terminal-object-detector.md b/translations/pt-PT/5-retail/lessons/2-check-stock-device/wio-terminal-object-detector.md new file mode 100644 index 000000000..9d5e4d02d --- /dev/null +++ b/translations/pt-PT/5-retail/lessons/2-check-stock-device/wio-terminal-object-detector.md @@ -0,0 +1,105 @@ +# Chame o seu detetor de objetos a partir do seu dispositivo IoT - Wio Terminal + +Depois de publicar o seu detetor de objetos, ele pode ser utilizado a partir do seu dispositivo IoT. + +## Copie o projeto do classificador de imagens + +A maior parte do seu detetor de stock é semelhante ao classificador de imagens que criou numa lição anterior. + +### Tarefa - copiar o projeto do classificador de imagens + +1. Ligue a sua ArduCam ao Wio Terminal, seguindo os passos da [lição 2 do projeto de manufatura](../../../4-manufacturing/lessons/2-check-fruit-from-device/wio-terminal-camera.md#task---connect-the-camera). + + Também pode querer fixar a câmara numa posição estável, por exemplo, pendurando o cabo sobre uma caixa ou lata, ou fixando a câmara a uma caixa com fita adesiva de dupla face. + +1. Crie um novo projeto Wio Terminal utilizando o PlatformIO. Dê o nome de `stock-counter` a este projeto. + +1. Replique os passos da [lição 2 do projeto de manufatura](../../../4-manufacturing/lessons/2-check-fruit-from-device/README.md#task---capture-an-image-using-an-iot-device) para capturar imagens com a câmara. + +1. Replique os passos da [lição 2 do projeto de manufatura](../../../4-manufacturing/lessons/2-check-fruit-from-device/README.md#task---classify-images-from-your-iot-device) para chamar o classificador de imagens. A maior parte deste código será reutilizada para detetar objetos. + +## Alterar o código de um classificador para um detetor de imagens + +O código que utilizou para classificar imagens é muito semelhante ao código para detetar objetos. A principal diferença é o URL que é chamado, obtido do Custom Vision, e os resultados da chamada. + +### Tarefa - alterar o código de um classificador para um detetor de imagens + +1. Adicione a seguinte diretiva de inclusão ao topo do ficheiro `main.cpp`: + + ```cpp + #include + ``` + +1. Renomeie a função `classifyImage` para `detectStock`, tanto o nome da função como a chamada na função `buttonPressed`. + +1. Acima da função `detectStock`, declare um limiar para filtrar quaisquer deteções com baixa probabilidade: + + ```cpp + const float threshold = 0.3f; + ``` + + Ao contrário de um classificador de imagens que retorna apenas um resultado por etiqueta, o detetor de objetos retornará múltiplos resultados, por isso é necessário filtrar os que têm baixa probabilidade. + +1. Acima da função `detectStock`, declare uma função para processar as previsões: + + ```cpp + void processPredictions(std::vector &predictions) + { + for(JsonVariant prediction : predictions) + { + String tag = prediction["tagName"].as(); + float probability = prediction["probability"].as(); + + char buff[32]; + sprintf(buff, "%s:\t%.2f%%", tag.c_str(), probability * 100.0); + Serial.println(buff); + } + } + ``` + + Esta função recebe uma lista de previsões e imprime-as no monitor serial. + +1. Na função `detectStock`, substitua o conteúdo do ciclo `for` que percorre as previsões pelo seguinte: + + ```cpp + std::vector passed_predictions; + + for(JsonVariant prediction : predictions) + { + float probability = prediction["probability"].as(); + if (probability > threshold) + { + passed_predictions.push_back(prediction); + } + } + + processPredictions(passed_predictions); + ``` + + Este ciclo percorre as previsões, comparando a probabilidade com o limiar. Todas as previsões com uma probabilidade superior ao limiar são adicionadas a uma `list` e passadas para a função `processPredictions`. + +1. Carregue e execute o seu código. Aponte a câmara para objetos numa prateleira e pressione o botão C. Verá a saída no monitor serial: + + ```output + Connecting to WiFi.. + Connected! + Image captured + Image read to buffer with length 17416 + tomato paste: 35.84% + tomato paste: 35.87% + tomato paste: 34.11% + tomato paste: 35.16% + ``` + + > 💁 Pode ser necessário ajustar o `threshold` para um valor apropriado às suas imagens. + + Poderá ver a imagem capturada e estes valores no separador **Predictions** no Custom Vision. + + ![4 latas de polpa de tomate numa prateleira com previsões para as 4 deteções de 35.8%, 33.5%, 25.7% e 16.6%](../../../../../translated_images/pt-PT/custom-vision-stock-prediction.942266ab1bcca3410ecdf23643b9f5f570cfab2345235074e24c51f285777613.png) + +> 💁 Pode encontrar este código na pasta [code-detect/wio-terminal](../../../../../5-retail/lessons/2-check-stock-device/code-detect/wio-terminal). + +😀 O seu programa de contagem de stock foi um sucesso! + +**Aviso Legal**: +Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, é importante notar que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes do uso desta tradução. \ No newline at end of file diff --git a/translations/pt-PT/6-consumer/README.md b/translations/pt-PT/6-consumer/README.md new file mode 100644 index 000000000..9e12a510b --- /dev/null +++ b/translations/pt-PT/6-consumer/README.md @@ -0,0 +1,25 @@ +# IoT para Consumidores - criar um assistente de voz inteligente + +Os alimentos foram cultivados, transportados para uma fábrica de processamento, classificados pela qualidade, vendidos na loja e agora é hora de cozinhar! Um dos elementos essenciais de qualquer cozinha é um temporizador. Inicialmente, estes começaram como ampulhetas - a comida estava pronta quando toda a areia escorria para o bulbo inferior. Depois passaram a ser mecânicos, e mais tarde elétricos. + +As versões mais recentes agora fazem parte dos nossos dispositivos inteligentes. Em cozinhas de casas por todo o mundo, ouve-se cozinheiros a gritar "Hey Siri - define um temporizador de 10 minutos", ou "Alexa - cancela o temporizador do pão". Já não é necessário voltar à cozinha para verificar o temporizador, pode fazê-lo a partir do telemóvel ou simplesmente chamando do outro lado da sala. + +Nestes 4 módulos, vais aprender a criar um temporizador inteligente, utilizando IA para reconhecer a tua voz, compreender o que estás a pedir e responder com informações sobre o temporizador. Também vais adicionar suporte para múltiplos idiomas. + +> ⚠️ Trabalhar com dados de voz e microfone utiliza muita memória, o que significa que é fácil atingir os limites em microcontroladores. O projeto aqui contorna estas questões, mas tem em atenção que os laboratórios com o Wio Terminal são complexos e podem demorar mais tempo do que outros laboratórios deste currículo. + +> 💁 Estas lições utilizam alguns recursos na cloud. Se não completares todas as lições deste projeto, certifica-te de que [limpas o teu projeto](../clean-up.md). + +## Tópicos + +1. [Reconhecer fala com um dispositivo IoT](./lessons/1-speech-recognition/README.md) +1. [Compreender linguagem](./lessons/2-language-understanding/README.md) +1. [Definir um temporizador e fornecer feedback falado](./lessons/3-spoken-feedback/README.md) +1. [Suportar múltiplos idiomas](./lessons/4-multiple-language-support/README.md) + +## Créditos + +Todas as lições foram escritas com ♥️ por [Jim Bennett](https://GitHub.com/JimBobBennett) + +**Aviso Legal**: +Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos pela precisão, esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes do uso desta tradução. \ No newline at end of file diff --git a/translations/pt-PT/6-consumer/lessons/1-speech-recognition/README.md b/translations/pt-PT/6-consumer/lessons/1-speech-recognition/README.md new file mode 100644 index 000000000..15669c085 --- /dev/null +++ b/translations/pt-PT/6-consumer/lessons/1-speech-recognition/README.md @@ -0,0 +1,224 @@ +# Reconhecer fala com um dispositivo IoT + +![Uma visão geral ilustrada desta lição](../../../../../translated_images/pt-PT/lesson-21.e34de51354d6606fb5ee08d8c89d0222eea0a2a7aaf744a8805ae847c4f69dc4.jpg) + +> Ilustração por [Nitya Narasimhan](https://github.com/nitya). Clique na imagem para uma versão maior. + +Este vídeo oferece uma visão geral do serviço de fala do Azure, um tópico que será abordado nesta lição: + +[![Como começar a usar seu recurso de Fala dos Serviços Cognitivos do canal do YouTube da Microsoft Azure](https://img.youtube.com/vi/iW0Fw0l3mrA/0.jpg)](https://www.youtube.com/watch?v=iW0Fw0l3mrA) + +> 🎥 Clique na imagem acima para assistir ao vídeo + +## Questionário pré-aula + +[Questionário pré-aula](https://black-meadow-040d15503.1.azurestaticapps.net/quiz/41) + +## Introdução + +'Alexa, define um temporizador de 12 minutos' + +'Alexa, qual o status do temporizador?' + +'Alexa, define um temporizador de 8 minutos chamado cozer brócolos a vapor' + +Os dispositivos inteligentes estão a tornar-se cada vez mais comuns. Não apenas como colunas inteligentes como HomePods, Echos e Google Homes, mas também integrados nos nossos telemóveis, relógios, e até em luminárias e termostatos. + +> 💁 Tenho pelo menos 19 dispositivos na minha casa com assistentes de voz, e isso são apenas os que conheço! + +O controlo por voz aumenta a acessibilidade, permitindo que pessoas com mobilidade limitada interajam com dispositivos. Seja uma deficiência permanente, como nascer sem braços, ou uma deficiência temporária, como braços partidos, ou até mesmo ter as mãos ocupadas com compras ou crianças pequenas, poder controlar a nossa casa com a voz em vez das mãos abre um mundo de possibilidades. Gritar 'Hey Siri, fecha a porta da garagem' enquanto lida com uma troca de fralda e uma criança irrequieta pode ser uma pequena, mas eficaz, melhoria na vida. + +Um dos usos mais populares para assistentes de voz é definir temporizadores, especialmente na cozinha. Poder definir múltiplos temporizadores apenas com a voz é uma grande ajuda - não é necessário parar de amassar massa, mexer sopa ou limpar as mãos sujas de recheio de bolinhos para usar um temporizador físico. + +Nesta lição, aprenderá a integrar reconhecimento de voz em dispositivos IoT. Aprenderá sobre microfones como sensores, como capturar áudio de um microfone ligado a um dispositivo IoT e como usar IA para converter o que é ouvido em texto. Ao longo deste projeto, construirá um temporizador de cozinha inteligente, capaz de definir temporizadores usando a sua voz em vários idiomas. + +Nesta lição, abordaremos: + +* [Microfones](../../../../../6-consumer/lessons/1-speech-recognition) +* [Capturar áudio do seu dispositivo IoT](../../../../../6-consumer/lessons/1-speech-recognition) +* [Fala para texto](../../../../../6-consumer/lessons/1-speech-recognition) +* [Converter fala em texto](../../../../../6-consumer/lessons/1-speech-recognition) + +## Microfones + +Os microfones são sensores analógicos que convertem ondas sonoras em sinais elétricos. Vibrações no ar fazem com que componentes no microfone se movam ligeiramente, causando pequenas alterações nos sinais elétricos. Estas alterações são então amplificadas para gerar uma saída elétrica. + +### Tipos de microfones + +Os microfones existem em vários tipos: + +* Dinâmico - Microfones dinâmicos têm um íman ligado a um diafragma móvel que se move numa bobina de fio, criando uma corrente elétrica. Isto é o oposto da maioria das colunas, que usam uma corrente elétrica para mover um íman numa bobina de fio, movendo um diafragma para criar som. Isso significa que colunas podem ser usadas como microfones dinâmicos, e microfones dinâmicos podem ser usados como colunas. Em dispositivos como interfones, onde o utilizador está a ouvir ou a falar, mas não ambos ao mesmo tempo, um único dispositivo pode atuar como coluna e microfone. + + Microfones dinâmicos não precisam de energia para funcionar, o sinal elétrico é criado inteiramente pelo microfone. + + ![Patti Smith a cantar num microfone Shure SM58 (tipo cardioide dinâmico)](../../../../../translated_images/pt-PT/dynamic-mic.8babac890a2d80dfb0874b5bf37d4b851fe2aeb9da6fd72945746176978bf3bb.jpg) + +* Fita - Microfones de fita são semelhantes aos dinâmicos, exceto que têm uma fita metálica em vez de um diafragma. Esta fita move-se num campo magnético, gerando uma corrente elétrica. Tal como os microfones dinâmicos, os de fita não precisam de energia para funcionar. + + ![Edmund Lowe, ator americano, em pé junto a um microfone de rádio (etiquetado para a rede azul da NBC), segurando um guião, 1942](../../../../../translated_images/pt-PT/ribbon-mic.eacc8e092c7441ca.webp) + +* Condensador - Microfones de condensador têm um diafragma metálico fino e uma placa metálica fixa. A eletricidade é aplicada a ambos e, à medida que o diafragma vibra, a carga estática entre as placas muda, gerando um sinal. Microfones de condensador precisam de energia para funcionar - chamada de *Phantom power*. + + ![Microfone de condensador de pequeno diafragma C451B da AKG Acoustics](../../../../../translated_images/pt-PT/condenser-mic.6f6ed5b76ca19e0ec3fd0c544601542d4479a6cb7565db336de49fbbf69f623e.jpg) + +* MEMS - Microfones de sistemas microeletromecânicos, ou MEMS, são microfones num chip. Eles têm um diafragma sensível à pressão gravado num chip de silício e funcionam de forma semelhante a um microfone de condensador. Estes microfones podem ser minúsculos e integrados em circuitos. + + ![Um microfone MEMS numa placa de circuito](../../../../../translated_images/pt-PT/mems-microphone.80574019e1f5e4d9ee72fed720ecd25a39fc2969c91355d17ebb24ba4159e4c4.png) + + Na imagem acima, o chip etiquetado como **LEFT** é um microfone MEMS, com um diafragma minúsculo com menos de um milímetro de largura. + +✅ Faça uma pesquisa: Que microfones tem à sua volta - seja no seu computador, telemóvel, auscultadores ou noutros dispositivos? Que tipo de microfones são? + +### Áudio digital + +O áudio é um sinal analógico que transporta informações muito detalhadas. Para converter este sinal em digital, o áudio precisa de ser amostrado milhares de vezes por segundo. + +> 🎓 Amostragem é o processo de converter o sinal de áudio num valor digital que representa o sinal naquele momento específico. + +![Um gráfico de linha mostrando um sinal, com pontos discretos em intervalos fixos](../../../../../translated_images/pt-PT/sampling.6f4fadb3f2d9dfe7.webp) + +O áudio digital é amostrado usando Modulação por Código de Pulso, ou PCM. O PCM envolve a leitura da voltagem do sinal e a seleção do valor discreto mais próximo dessa voltagem usando um tamanho definido. + +> 💁 Pode pensar no PCM como a versão de sensor da modulação por largura de pulso, ou PWM (PWM foi abordado na [lição 3 do projeto introdutório](../../../1-getting-started/lessons/3-sensors-and-actuators/README.md#pulse-width-modulation)). O PCM envolve converter um sinal analógico em digital, enquanto o PWM converte um sinal digital em analógico. + +Por exemplo, a maioria dos serviços de streaming de música oferece áudio de 16 bits ou 24 bits. Isso significa que convertem a voltagem num valor que cabe num número inteiro de 16 bits ou 24 bits. O áudio de 16 bits ajusta o valor num intervalo de -32.768 a 32.767, enquanto o de 24 bits está no intervalo de -8.388.608 a 8.388.607. Quanto mais bits, mais próximo o som amostrado estará do que os nossos ouvidos realmente ouvem. + +> 💁 Talvez já tenha ouvido falar de áudio de 8 bits, frequentemente referido como LoFi. Este é o áudio amostrado usando apenas 8 bits, ou seja, -128 a 127. O áudio dos primeiros computadores era limitado a 8 bits devido a restrições de hardware, sendo frequentemente associado a jogos retro. + +Estas amostras são feitas milhares de vezes por segundo, usando taxas de amostragem bem definidas, medidas em KHz (milhares de leituras por segundo). Os serviços de streaming de música usam 48KHz para a maioria dos áudios, mas alguns áudios 'sem perdas' usam até 96KHz ou mesmo 192KHz. Quanto maior a taxa de amostragem, mais próximo o áudio estará do original, até certo ponto. Há debate sobre se os humanos conseguem perceber a diferença acima de 48KHz. + +✅ Faça uma pesquisa: Se usa um serviço de streaming de música, qual a taxa de amostragem e tamanho que ele utiliza? Se usa CDs, qual a taxa de amostragem e tamanho do áudio em CD? + +Existem vários formatos diferentes para dados de áudio. Provavelmente já ouviu falar de ficheiros mp3 - dados de áudio comprimidos para serem menores sem perder qualidade. O áudio não comprimido é frequentemente armazenado como um ficheiro WAV - este é um ficheiro com 44 bytes de informações de cabeçalho, seguido por dados de áudio brutos. O cabeçalho contém informações como a taxa de amostragem (por exemplo, 16000 para 16KHz), tamanho da amostra (16 para 16 bits) e o número de canais. Após o cabeçalho, o ficheiro WAV contém os dados de áudio brutos. + +> 🎓 Canais referem-se a quantos fluxos de áudio diferentes compõem o áudio. Por exemplo, para áudio estéreo com esquerda e direita, haveria 2 canais. Para som surround 7.1 num sistema de cinema em casa, seriam 8. + +### Tamanho dos dados de áudio + +Os dados de áudio são relativamente grandes. Por exemplo, capturar áudio não comprimido de 16 bits a 16KHz (uma taxa suficiente para uso com modelos de reconhecimento de fala) consome 32KB de dados por segundo de áudio: + +* 16 bits significam 2 bytes por amostra (1 byte equivale a 8 bits). +* 16KHz são 16.000 amostras por segundo. +* 16.000 x 2 bytes = 32.000 bytes por segundo. + +Isto pode parecer uma pequena quantidade de dados, mas se estiver a usar um microcontrolador com memória limitada, pode ser muito. Por exemplo, o Wio Terminal tem 192KB de memória, que precisa de armazenar o código do programa e variáveis. Mesmo que o código do programa fosse minúsculo, não poderia capturar mais de 5 segundos de áudio. + +Os microcontroladores podem aceder a armazenamento adicional, como cartões SD ou memória flash. Ao construir um dispositivo IoT que captura áudio, precisará garantir não apenas que tem armazenamento adicional, mas que o seu código grava o áudio capturado diretamente nesse armazenamento. Quando enviar para a nuvem, deve transmitir do armazenamento para a solicitação web. Assim, evita esgotar a memória ao tentar armazenar todo o bloco de dados de áudio na memória de uma só vez. + +## Capturar áudio do seu dispositivo IoT + +O seu dispositivo IoT pode ser ligado a um microfone para capturar áudio, pronto para conversão em texto. Também pode ser ligado a colunas para reproduzir áudio. Em lições futuras, isso será usado para fornecer feedback de áudio, mas é útil configurar as colunas agora para testar o microfone. + +### Tarefa - configurar o microfone e as colunas + +Siga o guia relevante para configurar o microfone e as colunas para o seu dispositivo IoT: + +* [Arduino - Wio Terminal](wio-terminal-microphone.md) +* [Computador de placa única - Raspberry Pi](pi-microphone.md) +* [Computador de placa única - Dispositivo virtual](virtual-device-microphone.md) + +### Tarefa - capturar áudio + +Siga o guia relevante para capturar áudio no seu dispositivo IoT: + +* [Arduino - Wio Terminal](wio-terminal-audio.md) +* [Computador de placa única - Raspberry Pi](pi-audio.md) +* [Computador de placa única - Dispositivo virtual](virtual-device-audio.md) + +## Fala para texto + +Fala para texto, ou reconhecimento de fala, envolve o uso de IA para converter palavras num sinal de áudio em texto. + +### Modelos de reconhecimento de fala + +Para converter fala em texto, amostras do sinal de áudio são agrupadas e alimentadas num modelo de aprendizagem automática baseado numa Rede Neural Recorrente (RNN). Este é um tipo de modelo de aprendizagem automática que pode usar dados anteriores para tomar decisões sobre dados recebidos. Por exemplo, a RNN pode detetar um bloco de amostras de áudio como o som 'Hel', e quando recebe outro que parece ser o som 'lo', pode combinar isso com o som anterior, descobrir que 'Hello' é uma palavra válida e selecionar isso como o resultado. + +Os modelos de ML sempre aceitam dados do mesmo tamanho a cada vez. O classificador de imagens que construiu numa lição anterior redimensiona imagens para um tamanho fixo antes de processá-las. O mesmo acontece com os modelos de fala, que precisam processar blocos de áudio de tamanho fixo. Os modelos de fala precisam ser capazes de combinar as saídas de várias previsões para obter a resposta, permitindo distinguir entre 'Hi' e 'Highway', ou 'flock' e 'floccinaucinihilipilification'. + +Os modelos de fala também são avançados o suficiente para entender o contexto e podem corrigir as palavras detetadas à medida que mais sons são processados. Por exemplo, se disser "Fui às lojas para comprar duas bananas e uma maçã também", usaria três palavras que soam iguais, mas são escritas de forma diferente - to, two e too. Os modelos de fala conseguem entender o contexto e usar a grafia apropriada da palavra. +💁 Alguns serviços de voz permitem personalização para funcionar melhor em ambientes ruidosos, como fábricas, ou com palavras específicas de setores, como nomes químicos. Estas personalizações são treinadas fornecendo áudio de exemplo e uma transcrição, e funcionam através de aprendizagem por transferência, da mesma forma que treinaste um classificador de imagens usando apenas algumas imagens numa lição anterior. +### Privacidade + +Ao utilizar a conversão de voz para texto num dispositivo IoT de consumo, a privacidade é extremamente importante. Estes dispositivos ouvem continuamente o áudio, e como consumidor, não quer que tudo o que diz seja enviado para a cloud e convertido em texto. Não só isso consome muita largura de banda da Internet, como também tem enormes implicações para a privacidade, especialmente quando alguns fabricantes de dispositivos inteligentes selecionam aleatoriamente áudios para [serem validados por humanos em relação ao texto gerado, para ajudar a melhorar o modelo](https://www.theverge.com/2019/4/10/18305378/amazon-alexa-ai-voice-assistant-annotation-listen-private-recordings). + +Quer que o seu dispositivo inteligente envie áudio para a cloud apenas quando o está a utilizar, e não quando ouve sons na sua casa, que podem incluir reuniões privadas ou interações íntimas. A maioria dos dispositivos inteligentes funciona com uma *palavra de ativação*, uma frase-chave como "Alexa", "Hey Siri" ou "OK Google", que faz com que o dispositivo 'acorde' e ouça o que está a dizer até detetar uma pausa no discurso, indicando que terminou de falar com o dispositivo. + +> 🎓 A deteção de palavras de ativação também é conhecida como *Keyword spotting* ou *Keyword recognition*. + +Estas palavras de ativação são detetadas no dispositivo, e não na cloud. Estes dispositivos inteligentes possuem pequenos modelos de IA que funcionam no próprio dispositivo, ouvindo a palavra de ativação, e quando esta é detetada, começam a transmitir o áudio para a cloud para reconhecimento. Estes modelos são muito especializados e apenas ouvem a palavra de ativação. + +> 💁 Algumas empresas de tecnologia estão a adicionar mais privacidade aos seus dispositivos, realizando parte da conversão de voz para texto no próprio dispositivo. A Apple anunciou que, como parte das atualizações do iOS e macOS de 2021, suportará a conversão de voz para texto no dispositivo, sendo capaz de lidar com muitos pedidos sem necessidade de usar a cloud. Isto é possível graças aos processadores potentes nos seus dispositivos, que conseguem executar modelos de ML. + +✅ Quais acha que são as implicações éticas e de privacidade de armazenar o áudio enviado para a cloud? Este áudio deve ser armazenado e, se sim, como? Considera que o uso de gravações para aplicação da lei é uma boa troca pela perda de privacidade? + +A deteção de palavras de ativação geralmente utiliza uma técnica conhecida como TinyML, que consiste em converter modelos de ML para que possam ser executados em microcontroladores. Estes modelos são pequenos em tamanho e consomem muito pouca energia para funcionar. + +Para evitar a complexidade de treinar e usar um modelo de palavra de ativação, o temporizador inteligente que está a construir nesta lição usará um botão para ativar o reconhecimento de voz. + +> 💁 Se quiser experimentar criar um modelo de deteção de palavras de ativação para executar no Wio Terminal ou Raspberry Pi, veja este [tutorial de resposta à sua voz da Edge Impulse](https://docs.edgeimpulse.com/docs/responding-to-your-voice). Se quiser usar o seu computador para isso, pode experimentar o [guia rápido de início com palavras-chave personalizadas na documentação da Microsoft](https://docs.microsoft.com/azure/cognitive-services/speech-service/keyword-recognition-overview?WT.mc_id=academic-17441-jabenn). + +## Converter voz em texto + +![Logótipo dos serviços de voz](../../../../../translated_images/pt-PT/azure-speech-logo.a1f08c4befb0159f2cb5d692d3baf5b599e7b44759d316da907bda1508f46a4a.png) + +Tal como na classificação de imagens num projeto anterior, existem serviços de IA pré-construídos que podem receber áudio como ficheiro e convertê-lo em texto. Um desses serviços é o Speech Service, parte dos Cognitive Services, serviços de IA pré-construídos que pode usar nas suas aplicações. + +### Tarefa - configurar um recurso de IA de voz + +1. Crie um Grupo de Recursos para este projeto chamado `smart-timer`. + +1. Use o seguinte comando para criar um recurso de voz gratuito: + + ```sh + az cognitiveservices account create --name smart-timer \ + --resource-group smart-timer \ + --kind SpeechServices \ + --sku F0 \ + --yes \ + --location + ``` + + Substitua `` pela localização que utilizou ao criar o Grupo de Recursos. + +1. Vai precisar de uma chave de API para aceder ao recurso de voz a partir do seu código. Execute o seguinte comando para obter a chave: + + ```sh + az cognitiveservices account keys list --name smart-timer \ + --resource-group smart-timer \ + --output table + ``` + + Guarde uma cópia de uma das chaves. + +### Tarefa - converter voz em texto + +Siga o guia relevante para converter voz em texto no seu dispositivo IoT: + +* [Arduino - Wio Terminal](wio-terminal-speech-to-text.md) +* [Computador de placa única - Raspberry Pi](pi-speech-to-text.md) +* [Computador de placa única - Dispositivo virtual](virtual-device-speech-to-text.md) + +--- + +## 🚀 Desafio + +O reconhecimento de voz existe há muito tempo e está continuamente a melhorar. Pesquise as capacidades atuais e compare como estas evoluíram ao longo do tempo, incluindo a precisão das transcrições feitas por máquinas em comparação com as feitas por humanos. + +O que acha que o futuro reserva para o reconhecimento de voz? + +## Questionário pós-aula + +[Questionário pós-aula](https://black-meadow-040d15503.1.azurestaticapps.net/quiz/42) + +## Revisão e Autoestudo + +* Leia sobre os diferentes tipos de microfones e como funcionam no [artigo sobre a diferença entre microfones dinâmicos e condensadores no Musician's HQ](https://musicianshq.com/whats-the-difference-between-dynamic-and-condenser-microphones/). +* Leia mais sobre o serviço de voz dos Cognitive Services na [documentação do serviço de voz na Microsoft Docs](https://docs.microsoft.com/azure/cognitive-services/speech-service/?WT.mc_id=academic-17441-jabenn). +* Leia sobre deteção de palavras-chave na [documentação de reconhecimento de palavras-chave na Microsoft Docs](https://docs.microsoft.com/azure/cognitive-services/speech-service/keyword-recognition-overview?WT.mc_id=academic-17441-jabenn). + +## Tarefa + +[](assignment.md) + +**Aviso Legal**: +Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, é importante notar que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes do uso desta tradução. \ No newline at end of file diff --git a/translations/pt-PT/6-consumer/lessons/1-speech-recognition/assignment.md b/translations/pt-PT/6-consumer/lessons/1-speech-recognition/assignment.md new file mode 100644 index 000000000..612168df4 --- /dev/null +++ b/translations/pt-PT/6-consumer/lessons/1-speech-recognition/assignment.md @@ -0,0 +1,10 @@ +## Instruções + +## Rubrica + +| Critérios | Exemplar | Adequado | Necessita de Melhorias | +| --------- | --------- | -------- | ---------------------- | +| | | | | + +**Aviso Legal**: +Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original no seu idioma nativo deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se uma tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas resultantes do uso desta tradução. \ No newline at end of file diff --git a/translations/pt-PT/6-consumer/lessons/1-speech-recognition/pi-audio.md b/translations/pt-PT/6-consumer/lessons/1-speech-recognition/pi-audio.md new file mode 100644 index 000000000..255d1dea4 --- /dev/null +++ b/translations/pt-PT/6-consumer/lessons/1-speech-recognition/pi-audio.md @@ -0,0 +1,216 @@ +# Capturar áudio - Raspberry Pi + +Nesta parte da lição, vais escrever código para capturar áudio no teu Raspberry Pi. A captura de áudio será controlada por um botão. + +## Hardware + +O Raspberry Pi precisa de um botão para controlar a captura de áudio. + +O botão que vais usar é um botão Grove. Este é um sensor digital que liga ou desliga um sinal. Estes botões podem ser configurados para enviar um sinal alto quando o botão é pressionado, e baixo quando não é, ou baixo quando pressionado e alto quando não é. + +Se estiveres a usar um ReSpeaker 2-Mics Pi HAT como microfone, não é necessário conectar um botão, pois este HAT já tem um botão integrado. Podes passar para a próxima secção. + +### Conectar o botão + +O botão pode ser conectado ao Grove Base Hat. + +#### Tarefa - conectar o botão + +![Um botão Grove](../../../../../translated_images/pt-PT/grove-button.a70cfbb809a8563681003250cf5b06d68cdcc68624f9e2f493d5a534ae2da1e5.png) + +1. Insere uma extremidade de um cabo Grove na entrada do módulo do botão. Só encaixará de uma forma. + +1. Com o Raspberry Pi desligado, conecta a outra extremidade do cabo Grove à entrada digital marcada como **D5** no Grove Base Hat conectado ao Pi. Esta entrada é a segunda da esquerda, na fila de entradas ao lado dos pinos GPIO. + +![O botão Grove conectado à entrada D5](../../../../../translated_images/pt-PT/pi-button.c7a1a4f55943341ce1baf1057658e9a205804d4131d258e820c93f951df0abf3.png) + +## Capturar áudio + +Podes capturar áudio do microfone usando código em Python. + +### Tarefa - capturar áudio + +1. Liga o Pi e espera que ele inicie. + +1. Abre o VS Code, diretamente no Pi ou conecta-te através da extensão Remote SSH. + +1. O pacote PyAudio Pip tem funções para gravar e reproduzir áudio. Este pacote depende de algumas bibliotecas de áudio que precisam de ser instaladas primeiro. Executa os seguintes comandos no terminal para instalá-las: + + ```sh + sudo apt update + sudo apt install libportaudio0 libportaudio2 libportaudiocpp0 portaudio19-dev libasound2-plugins --yes + ``` + +1. Instala o pacote PyAudio Pip. + + ```sh + pip3 install pyaudio + ``` + +1. Cria uma nova pasta chamada `smart-timer` e adiciona um ficheiro chamado `app.py` a esta pasta. + +1. Adiciona as seguintes importações ao topo deste ficheiro: + + ```python + import io + import pyaudio + import time + import wave + + from grove.factory import Factory + ``` + + Isto importa o módulo `pyaudio`, alguns módulos padrão do Python para lidar com ficheiros WAV, e o módulo `grove.factory` para importar uma `Factory` que cria uma classe de botão. + +1. Abaixo disso, adiciona código para criar um botão Grove. + + Se estiveres a usar o ReSpeaker 2-Mics Pi HAT, usa o seguinte código: + + ```python + # The button on the ReSpeaker 2-Mics Pi HAT + button = Factory.getButton("GPIO-LOW", 17) + ``` + + Isto cria um botão na porta **D17**, a porta à qual o botão no ReSpeaker 2-Mics Pi HAT está conectado. Este botão está configurado para enviar um sinal baixo quando pressionado. + + Se não estiveres a usar o ReSpeaker 2-Mics Pi HAT e estiveres a usar um botão Grove conectado ao Base Hat, usa este código: + + ```python + button = Factory.getButton("GPIO-HIGH", 5) + ``` + + Isto cria um botão na porta **D5**, configurado para enviar um sinal alto quando pressionado. + +1. Abaixo disso, cria uma instância da classe PyAudio para lidar com áudio: + + ```python + audio = pyaudio.PyAudio() + ``` + +1. Declara o número da placa de hardware para o microfone e altifalante. Este será o número da placa que encontraste ao executar `arecord -l` e `aplay -l` anteriormente nesta lição. + + ```python + microphone_card_number = + speaker_card_number = + ``` + + Substitui `` pelo número da placa do teu microfone. + + Substitui `` pelo número da placa do teu altifalante, o mesmo número que configuraste no ficheiro `alsa.conf`. + +1. Abaixo disso, declara a taxa de amostragem a usar para a captura e reprodução de áudio. Poderás precisar de alterar isto dependendo do hardware que estás a usar. + + ```python + rate = 48000 #48KHz + ``` + + Se obtiveres erros de taxa de amostragem ao executar este código mais tarde, altera este valor para `44100` ou `16000`. Quanto maior o valor, melhor a qualidade do som. + +1. Abaixo disso, cria uma nova função chamada `capture_audio`. Esta será chamada para capturar áudio do microfone: + + ```python + def capture_audio(): + ``` + +1. Dentro desta função, adiciona o seguinte para capturar o áudio: + + ```python + stream = audio.open(format = pyaudio.paInt16, + rate = rate, + channels = 1, + input_device_index = microphone_card_number, + input = True, + frames_per_buffer = 4096) + + frames = [] + + while button.is_pressed(): + frames.append(stream.read(4096)) + + stream.stop_stream() + stream.close() + ``` + + Este código abre um fluxo de entrada de áudio usando o objeto PyAudio. Este fluxo capturará áudio do microfone a 16KHz, capturando-o em buffers de 4096 bytes. + + O código então entra num loop enquanto o botão Grove está pressionado, lendo estes buffers de 4096 bytes para um array a cada vez. + + > 💁 Podes ler mais sobre as opções passadas ao método `open` na [documentação do PyAudio](https://people.csail.mit.edu/hubert/pyaudio/docs/). + + Quando o botão é solto, o fluxo é parado e fechado. + +1. Adiciona o seguinte ao final desta função: + + ```python + wav_buffer = io.BytesIO() + with wave.open(wav_buffer, 'wb') as wavefile: + wavefile.setnchannels(1) + wavefile.setsampwidth(audio.get_sample_size(pyaudio.paInt16)) + wavefile.setframerate(rate) + wavefile.writeframes(b''.join(frames)) + wav_buffer.seek(0) + + return wav_buffer + ``` + + Este código cria um buffer binário e escreve todo o áudio capturado nele como um [ficheiro WAV](https://wikipedia.org/wiki/WAV). Este é um formato padrão para escrever áudio não comprimido num ficheiro. Este buffer é então retornado. + +1. Adiciona a seguinte função `play_audio` para reproduzir o buffer de áudio: + + ```python + def play_audio(buffer): + stream = audio.open(format = pyaudio.paInt16, + rate = rate, + channels = 1, + output_device_index = speaker_card_number, + output = True) + + with wave.open(buffer, 'rb') as wf: + data = wf.readframes(4096) + + while len(data) > 0: + stream.write(data) + data = wf.readframes(4096) + + stream.close() + ``` + + Esta função abre outro fluxo de áudio, desta vez para saída - para reproduzir o áudio. Usa as mesmas configurações do fluxo de entrada. O buffer é então aberto como um ficheiro WAV e escrito no fluxo de saída em blocos de 4096 bytes, reproduzindo o áudio. O fluxo é então fechado. + +1. Adiciona o seguinte código abaixo da função `capture_audio` para entrar num loop até que o botão seja pressionado. Quando o botão é pressionado, o áudio é capturado e depois reproduzido. + + ```python + while True: + while not button.is_pressed(): + time.sleep(.1) + + buffer = capture_audio() + play_audio(buffer) + ``` + +1. Executa o código. Pressiona o botão e fala no microfone. Solta o botão quando terminares e ouvirás a gravação. + + Poderás ver alguns erros ALSA quando a instância PyAudio é criada. Isto deve-se à configuração no Pi para dispositivos de áudio que não tens. Podes ignorar estes erros. + + ```output + pi@raspberrypi:~/smart-timer $ python3 app.py + ALSA lib pcm.c:2565:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.front + ALSA lib pcm.c:2565:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.rear + ALSA lib pcm.c:2565:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.center_lfe + ALSA lib pcm.c:2565:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.side + ``` + + Se obtiveres o seguinte erro: + + ```output + OSError: [Errno -9997] Invalid sample rate + ``` + + então altera o `rate` para 44100 ou 16000. + +> 💁 Podes encontrar este código na pasta [code-record/pi](../../../../../6-consumer/lessons/1-speech-recognition/code-record/pi). + +😀 O teu programa de gravação de áudio foi um sucesso! + +**Aviso Legal**: +Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, é importante notar que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes da utilização desta tradução. \ No newline at end of file diff --git a/translations/pt-PT/6-consumer/lessons/1-speech-recognition/pi-microphone.md b/translations/pt-PT/6-consumer/lessons/1-speech-recognition/pi-microphone.md new file mode 100644 index 000000000..020f1be17 --- /dev/null +++ b/translations/pt-PT/6-consumer/lessons/1-speech-recognition/pi-microphone.md @@ -0,0 +1,146 @@ +# Configurar o microfone e os altifalantes - Raspberry Pi + +Nesta parte da lição, irá adicionar um microfone e altifalantes ao seu Raspberry Pi. + +## Hardware + +O Raspberry Pi necessita de um microfone. + +O Pi não tem um microfone integrado, por isso será necessário adicionar um microfone externo. Existem várias formas de fazer isto: + +* Microfone USB +* Auscultadores USB +* Altifalante com microfone integrado USB +* Adaptador de áudio USB e microfone com ficha de 3,5mm +* [ReSpeaker 2-Mics Pi HAT](https://www.seeedstudio.com/ReSpeaker-2-Mics-Pi-HAT.html) + +> 💁 Nem todos os microfones Bluetooth são suportados no Raspberry Pi, por isso, se tiver um microfone ou auscultadores Bluetooth, pode ter problemas ao emparelhar ou capturar áudio. + +Os Raspberry Pis vêm com uma entrada de auscultadores de 3,5mm. Pode utilizá-la para ligar auscultadores, um headset ou um altifalante. Também pode adicionar altifalantes utilizando: + +* Áudio HDMI através de um monitor ou TV +* Altifalantes USB +* Auscultadores USB +* Altifalante com microfone integrado USB +* [ReSpeaker 2-Mics Pi HAT](https://www.seeedstudio.com/ReSpeaker-2-Mics-Pi-HAT.html) com um altifalante ligado, quer à entrada de 3,5mm ou à porta JST + +## Ligar e configurar o microfone e os altifalantes + +O microfone e os altifalantes precisam de ser ligados e configurados. + +### Tarefa - ligar e configurar o microfone + +1. Ligue o microfone utilizando o método apropriado. Por exemplo, ligue-o a uma das portas USB. + +1. Se estiver a utilizar o ReSpeaker 2-Mics Pi HAT, pode remover o Grove base hat e encaixar o ReSpeaker hat no seu lugar. + + ![Um Raspberry Pi com um ReSpeaker hat](../../../../../translated_images/pt-PT/pi-respeaker-hat.f00fabe7dd039a93e2e0aa0fc946c9af0c6a9eb17c32fa1ca097fb4e384f69f0.png) + + Irá precisar de um botão Grove mais tarde nesta lição, mas um está integrado neste hat, por isso o Grove base hat não é necessário. + + Depois de encaixar o hat, será necessário instalar alguns drivers. Consulte as [instruções de introdução da Seeed](https://wiki.seeedstudio.com/ReSpeaker_2_Mics_Pi_HAT_Raspberry/#getting-started) para instruções de instalação dos drivers. + + > ⚠️ As instruções utilizam `git` para clonar um repositório. Se não tiver o `git` instalado no seu Pi, pode instalá-lo executando o seguinte comando: + > + > ```sh + > sudo apt install git --yes + > ``` + +1. Execute o seguinte comando no Terminal, quer no Pi ou ligado através do VS Code e uma sessão remota SSH, para ver informações sobre o microfone ligado: + + ```sh + arecord -l + ``` + + Irá ver uma lista de microfones ligados. Será algo como o seguinte: + + ```output + pi@raspberrypi:~ $ arecord -l + **** List of CAPTURE Hardware Devices **** + card 1: M0 [eMeet M0], device 0: USB Audio [USB Audio] + Subdevices: 1/1 + Subdevice #0: subdevice #0 + ``` + + Assumindo que tem apenas um microfone, deverá ver apenas uma entrada. A configuração de microfones pode ser complicada no Linux, por isso é mais fácil utilizar apenas um microfone e desligar quaisquer outros. + + Anote o número da placa, pois irá precisar dele mais tarde. No exemplo acima, o número da placa é 1. + +### Tarefa - ligar e configurar os altifalantes + +1. Ligue os altifalantes utilizando o método apropriado. + +1. Execute o seguinte comando no Terminal, quer no Pi ou ligado através do VS Code e uma sessão remota SSH, para ver informações sobre os altifalantes ligados: + + ```sh + aplay -l + ``` + + Irá ver uma lista de altifalantes ligados. Será algo como o seguinte: + + ```output + pi@raspberrypi:~ $ aplay -l + **** List of PLAYBACK Hardware Devices **** + card 0: Headphones [bcm2835 Headphones], device 0: bcm2835 Headphones [bcm2835 Headphones] + Subdevices: 8/8 + Subdevice #0: subdevice #0 + Subdevice #1: subdevice #1 + Subdevice #2: subdevice #2 + Subdevice #3: subdevice #3 + Subdevice #4: subdevice #4 + Subdevice #5: subdevice #5 + Subdevice #6: subdevice #6 + Subdevice #7: subdevice #7 + card 1: M0 [eMeet M0], device 0: USB Audio [USB Audio] + Subdevices: 1/1 + Subdevice #0: subdevice #0 + ``` + + Irá sempre ver `card 0: Headphones`, pois esta é a entrada de auscultadores integrada. Se tiver adicionado altifalantes adicionais, como um altifalante USB, verá esta entrada listada também. + +1. Se estiver a utilizar um altifalante adicional, e não um altifalante ou auscultadores ligados à entrada de auscultadores integrada, será necessário configurá-lo como padrão. Para isso, execute o seguinte comando: + + ```sh + sudo nano /usr/share/alsa/alsa.conf + ``` + + Isto irá abrir um ficheiro de configuração no `nano`, um editor de texto baseado no terminal. Desça utilizando as teclas de seta no teclado até encontrar a seguinte linha: + + ```output + defaults.pcm.card 0 + ``` + + Altere o valor de `0` para o número da placa que deseja utilizar da lista que apareceu na chamada ao `aplay -l`. Por exemplo, no exemplo acima há uma segunda placa de som chamada `card 1: M0 [eMeet M0], device 0: USB Audio [USB Audio]`, utilizando a placa 1. Para utilizar esta, eu atualizaria a linha para: + + ```output + defaults.pcm.card 1 + ``` + + Defina este valor para o número da placa apropriado. Pode navegar até ao número utilizando as teclas de seta no teclado, depois apagar e digitar o novo número como faria normalmente ao editar ficheiros de texto. + +1. Guarde as alterações e feche o ficheiro pressionando `Ctrl+x`. Pressione `y` para guardar o ficheiro e depois `return` para selecionar o nome do ficheiro. + +### Tarefa - testar o microfone e os altifalantes + +1. Execute o seguinte comando para gravar 5 segundos de áudio através do microfone: + + ```sh + arecord --format=S16_LE --duration=5 --rate=16000 --file-type=wav out.wav + ``` + + Enquanto este comando estiver a ser executado, faça algum ruído no microfone, como falar, cantar, fazer beatbox, tocar um instrumento ou o que preferir. + +1. Após 5 segundos, a gravação irá parar. Execute o seguinte comando para reproduzir o áudio: + + ```sh + aplay --format=S16_LE --rate=16000 out.wav + ``` + + Irá ouvir o áudio a ser reproduzido através dos altifalantes. Ajuste o volume de saída no altifalante conforme necessário. + +1. Se precisar de ajustar o volume da entrada de microfone integrada ou ajustar o ganho do microfone, pode utilizar a ferramenta `alsamixer`. Pode ler mais sobre esta ferramenta na [página man do alsamixer no Linux](https://linux.die.net/man/1/alsamixer). + +1. Se obtiver erros ao reproduzir o áudio, verifique a placa que definiu como `defaults.pcm.card` no ficheiro `alsa.conf`. + +**Aviso Legal**: +Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, é importante notar que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes do uso desta tradução. \ No newline at end of file diff --git a/translations/pt-PT/6-consumer/lessons/1-speech-recognition/pi-speech-to-text.md b/translations/pt-PT/6-consumer/lessons/1-speech-recognition/pi-speech-to-text.md new file mode 100644 index 000000000..3d52b55d9 --- /dev/null +++ b/translations/pt-PT/6-consumer/lessons/1-speech-recognition/pi-speech-to-text.md @@ -0,0 +1,115 @@ +# Conversão de fala para texto - Raspberry Pi + +Nesta parte da lição, vais escrever código para converter a fala captada no áudio em texto, utilizando o serviço de fala. + +## Enviar o áudio para o serviço de fala + +O áudio pode ser enviado para o serviço de fala utilizando a API REST. Para usar o serviço de fala, primeiro precisas de solicitar um token de acesso e, em seguida, usar esse token para aceder à API REST. Estes tokens de acesso expiram após 10 minutos, por isso o teu código deve solicitá-los regularmente para garantir que estão sempre atualizados. + +### Tarefa - obter um token de acesso + +1. Abre o projeto `smart-timer` no teu Raspberry Pi. + +1. Remove a função `play_audio`. Esta já não é necessária, pois não queres que o temporizador inteligente repita o que disseste. + +1. Adiciona a seguinte importação no início do ficheiro `app.py`: + + ```python + import requests + ``` + +1. Adiciona o seguinte código acima do ciclo `while True` para declarar algumas definições para o serviço de fala: + + ```python + speech_api_key = '' + location = '' + language = '' + ``` + + Substitui `` pela chave da API do teu recurso do serviço de fala. Substitui `` pela localização que utilizaste ao criar o recurso do serviço de fala. + + Substitui `` pelo nome do local para o idioma em que vais falar, por exemplo, `en-GB` para inglês ou `zn-HK` para cantonês. Podes encontrar uma lista dos idiomas suportados e os respetivos nomes de local na [documentação de suporte a idiomas e vozes nos Microsoft Docs](https://docs.microsoft.com/azure/cognitive-services/speech-service/language-support?WT.mc_id=academic-17441-jabenn#speech-to-text). + +1. Abaixo disto, adiciona a seguinte função para obter um token de acesso: + + ```python + def get_access_token(): + headers = { + 'Ocp-Apim-Subscription-Key': speech_api_key + } + + token_endpoint = f'https://{location}.api.cognitive.microsoft.com/sts/v1.0/issuetoken' + response = requests.post(token_endpoint, headers=headers) + return str(response.text) + ``` + + Esta função chama um endpoint de emissão de tokens, passando a chave da API como um cabeçalho. Esta chamada retorna um token de acesso que pode ser usado para chamar os serviços de fala. + +1. A seguir, declara uma função para converter a fala captada no áudio em texto utilizando a API REST: + + ```python + def convert_speech_to_text(buffer): + ``` + +1. Dentro desta função, configura o URL da API REST e os cabeçalhos: + + ```python + url = f'https://{location}.stt.speech.microsoft.com/speech/recognition/conversation/cognitiveservices/v1' + + headers = { + 'Authorization': 'Bearer ' + get_access_token(), + 'Content-Type': f'audio/wav; codecs=audio/pcm; samplerate={rate}', + 'Accept': 'application/json;text/xml' + } + + params = { + 'language': language + } + ``` + + Isto constrói um URL utilizando a localização do recurso dos serviços de fala. Em seguida, preenche os cabeçalhos com o token de acesso da função `get_access_token`, bem como a taxa de amostragem usada para capturar o áudio. Por fim, define alguns parâmetros a serem passados com o URL, contendo o idioma do áudio. + +1. Abaixo disto, adiciona o seguinte código para chamar a API REST e obter o texto de volta: + + ```python + response = requests.post(url, headers=headers, params=params, data=buffer) + response_json = response.json() + + if response_json['RecognitionStatus'] == 'Success': + return response_json['DisplayText'] + else: + return '' + ``` + + Esta chamada utiliza o URL e decodifica o valor JSON que vem na resposta. O valor `RecognitionStatus` na resposta indica se a chamada conseguiu extrair com sucesso a fala em texto e, se for `Success`, o texto é retornado pela função; caso contrário, é retornada uma string vazia. + +1. Acima do ciclo `while True:`, define uma função para processar o texto retornado pelo serviço de conversão de fala para texto. Esta função, por agora, apenas imprimirá o texto no terminal. + + ```python + def process_text(text): + print(text) + ``` + +1. Por fim, substitui a chamada para `play_audio` no ciclo `while True` por uma chamada para a função `convert_speech_to_text`, passando o texto para a função `process_text`: + + ```python + text = convert_speech_to_text(buffer) + process_text(text) + ``` + +1. Executa o código. Pressiona o botão e fala para o microfone. Solta o botão quando terminares, e o áudio será convertido em texto e impresso no terminal. + + ```output + pi@raspberrypi:~/smart-timer $ python3 app.py + Hello world. + Welcome to IoT for beginners. + ``` + + Experimenta diferentes tipos de frases, incluindo frases onde as palavras têm o mesmo som, mas significados diferentes. Por exemplo, se estiveres a falar em inglês, diz "I want to buy two bananas and an apple too" e repara como ele utiliza corretamente "to", "two" e "too" com base no contexto da palavra, e não apenas no som. + +> 💁 Podes encontrar este código na pasta [code-speech-to-text/pi](../../../../../6-consumer/lessons/1-speech-recognition/code-speech-to-text/pi). + +😀 O teu programa de conversão de fala para texto foi um sucesso! + +**Aviso Legal**: +Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos pela precisão, esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes do uso desta tradução. \ No newline at end of file diff --git a/translations/pt-PT/6-consumer/lessons/1-speech-recognition/virtual-device-audio.md b/translations/pt-PT/6-consumer/lessons/1-speech-recognition/virtual-device-audio.md new file mode 100644 index 000000000..0061ef4c6 --- /dev/null +++ b/translations/pt-PT/6-consumer/lessons/1-speech-recognition/virtual-device-audio.md @@ -0,0 +1,6 @@ +# Capturar áudio - Dispositivo IoT Virtual + +As bibliotecas Python que irá utilizar mais tarde nesta lição para converter fala em texto têm captura de áudio integrada no Windows, macOS e Linux. Não precisa fazer nada aqui. + +**Aviso Legal**: +Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, é importante notar que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes do uso desta tradução. \ No newline at end of file diff --git a/translations/pt-PT/6-consumer/lessons/1-speech-recognition/virtual-device-microphone.md b/translations/pt-PT/6-consumer/lessons/1-speech-recognition/virtual-device-microphone.md new file mode 100644 index 000000000..b8b91aef5 --- /dev/null +++ b/translations/pt-PT/6-consumer/lessons/1-speech-recognition/virtual-device-microphone.md @@ -0,0 +1,15 @@ +# Configure o seu microfone e altifalantes - Hardware Virtual IoT + +O hardware virtual IoT utilizará um microfone e altifalantes ligados ao seu computador. + +Se o seu computador não tiver um microfone e altifalantes integrados, será necessário ligar estes dispositivos utilizando o hardware da sua escolha, como por exemplo: + +* Microfone USB +* Altifalantes USB +* Altifalantes integrados no monitor e ligados via HDMI +* Auriculares Bluetooth + +Consulte as instruções do fabricante do seu hardware para instalar e configurar estes dispositivos. + +**Aviso Legal**: +Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, é importante notar que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes do uso desta tradução. \ No newline at end of file diff --git a/translations/pt-PT/6-consumer/lessons/1-speech-recognition/virtual-device-speech-to-text.md b/translations/pt-PT/6-consumer/lessons/1-speech-recognition/virtual-device-speech-to-text.md new file mode 100644 index 000000000..763a236c1 --- /dev/null +++ b/translations/pt-PT/6-consumer/lessons/1-speech-recognition/virtual-device-speech-to-text.md @@ -0,0 +1,102 @@ +# Conversão de fala para texto - Dispositivo IoT virtual + +Nesta parte da lição, vais escrever código para converter fala captada pelo teu microfone em texto, utilizando o serviço de fala. + +## Converter fala em texto + +No Windows, Linux e macOS, o SDK Python dos serviços de fala pode ser usado para ouvir o teu microfone e converter qualquer fala detetada em texto. Ele escuta continuamente, detetando os níveis de áudio e enviando a fala para conversão em texto quando o nível de áudio diminui, como no final de um bloco de fala. + +### Tarefa - converter fala em texto + +1. Cria uma nova aplicação Python no teu computador numa pasta chamada `smart-timer` com um único ficheiro chamado `app.py` e um ambiente virtual Python. + +1. Instala o pacote Pip para os serviços de fala. Certifica-te de que estás a instalar isto a partir de um terminal com o ambiente virtual ativado. + + ```sh + pip install azure-cognitiveservices-speech + ``` + + > ⚠️ Se receberes o seguinte erro: + > + > ```output + > ERROR: Could not find a version that satisfies the requirement azure-cognitiveservices-speech (from versions: none) + > ERROR: No matching distribution found for azure-cognitiveservices-speech + > ``` + > + > Terás de atualizar o Pip. Faz isso com o seguinte comando e tenta instalar o pacote novamente: + > + > ```sh + > pip install --upgrade pip + > ``` + +1. Adiciona as seguintes importações ao ficheiro `app.py`: + + ```python + import requests + import time + from azure.cognitiveservices.speech import SpeechConfig, SpeechRecognizer + ``` + + Isto importa algumas classes usadas para reconhecer fala. + +1. Adiciona o seguinte código para declarar algumas configurações: + + ```python + speech_api_key = '' + location = '' + language = '' + + recognizer_config = SpeechConfig(subscription=speech_api_key, + region=location, + speech_recognition_language=language) + ``` + + Substitui `` pela chave API do teu serviço de fala. Substitui `` pela localização que usaste ao criar o recurso do serviço de fala. + + Substitui `` pelo nome do local para o idioma em que vais falar, por exemplo, `en-GB` para inglês ou `zn-HK` para cantonês. Podes encontrar uma lista dos idiomas suportados e os respetivos nomes de local na [documentação de suporte a idiomas e vozes nos documentos da Microsoft](https://docs.microsoft.com/azure/cognitive-services/speech-service/language-support?WT.mc_id=academic-17441-jabenn#speech-to-text). + + Esta configuração é então usada para criar um objeto `SpeechConfig` que será utilizado para configurar os serviços de fala. + +1. Adiciona o seguinte código para criar um reconhecedor de fala: + + ```python + recognizer = SpeechRecognizer(speech_config=recognizer_config) + ``` + +1. O reconhecedor de fala funciona numa thread em segundo plano, ouvindo o áudio e convertendo qualquer fala em texto. Podes obter o texto utilizando uma função de callback - uma função que defines e passas ao reconhecedor. Sempre que uma fala é detetada, o callback é chamado. Adiciona o seguinte código para definir um callback e passá-lo ao reconhecedor, bem como definir uma função para processar o texto, escrevendo-o na consola: + + ```python + def process_text(text): + print(text) + + def recognized(args): + process_text(args.result.text) + + recognizer.recognized.connect(recognized) + ``` + +1. O reconhecedor só começa a ouvir quando o inicias explicitamente. Adiciona o seguinte código para iniciar o reconhecimento. Isto funciona em segundo plano, por isso a tua aplicação também precisará de um loop infinito que dorme para manter a aplicação em execução. + + ```python + recognizer.start_continuous_recognition() + + while True: + time.sleep(1) + ``` + +1. Executa esta aplicação. Fala no teu microfone e o áudio convertido em texto será exibido na consola. + + ```output + (.venv) ➜ smart-timer python3 app.py + Hello world. + Welcome to IoT for beginners. + ``` + + Experimenta diferentes tipos de frases, juntamente com frases onde as palavras soam iguais, mas têm significados diferentes. Por exemplo, se estiveres a falar em inglês, diz "I want to buy two bananas and an apple too" e repara como ele usa corretamente "to", "two" e "too" com base no contexto da palavra, e não apenas no som. + +> 💁 Podes encontrar este código na pasta [code-speech-to-text/virtual-iot-device](../../../../../6-consumer/lessons/1-speech-recognition/code-speech-to-text/virtual-iot-device). + +😀 O teu programa de conversão de fala para texto foi um sucesso! + +**Aviso Legal**: +Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, tenha em atenção que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes da utilização desta tradução. \ No newline at end of file diff --git a/translations/pt-PT/6-consumer/lessons/1-speech-recognition/wio-terminal-audio.md b/translations/pt-PT/6-consumer/lessons/1-speech-recognition/wio-terminal-audio.md new file mode 100644 index 000000000..2947fb17b --- /dev/null +++ b/translations/pt-PT/6-consumer/lessons/1-speech-recognition/wio-terminal-audio.md @@ -0,0 +1,537 @@ +# Capturar áudio - Wio Terminal + +Nesta parte da lição, vais escrever código para capturar áudio no teu Wio Terminal. A captura de áudio será controlada por um dos botões na parte superior do Wio Terminal. + +## Programar o dispositivo para capturar áudio + +Podes capturar áudio do microfone usando código em C++. O Wio Terminal tem apenas 192KB de RAM, o que não é suficiente para capturar mais do que alguns segundos de áudio. No entanto, possui 4MB de memória flash, que pode ser utilizada para guardar o áudio capturado. + +O microfone integrado captura um sinal analógico, que é convertido num sinal digital que o Wio Terminal pode usar. Ao capturar áudio, os dados precisam de ser capturados no momento certo - por exemplo, para capturar áudio a 16KHz, o áudio precisa de ser capturado exatamente 16.000 vezes por segundo, com intervalos iguais entre cada amostra. Em vez de usar o teu código para fazer isso, podes usar o controlador de acesso direto à memória (DMAC). Este é um circuito que pode capturar um sinal de algum lugar e gravá-lo na memória, sem interromper o código que está a ser executado no processador. + +✅ Lê mais sobre DMA na [página de acesso direto à memória na Wikipedia](https://wikipedia.org/wiki/Direct_memory_access). + +![O áudio do microfone vai para um ADC e depois para o DMAC. Este escreve para um buffer. Quando este buffer está cheio, é processado e o DMAC escreve para um segundo buffer](../../../../../translated_images/pt-PT/dmac-adc-buffers.4509aee49145c90bc2e1be472b8ed2ddfcb2b6a81ad3e559114aca55f5fff759.png) + +O DMAC pode capturar áudio do ADC em intervalos fixos, como 16.000 vezes por segundo para áudio a 16KHz. Ele pode gravar esses dados capturados num buffer de memória pré-alocado e, quando este está cheio, disponibilizá-lo para o teu código processar. Usar esta memória pode atrasar a captura de áudio, mas podes configurar múltiplos buffers. O DMAC escreve no buffer 1 e, quando este está cheio, notifica o teu código para processar o buffer 1, enquanto o DMAC escreve no buffer 2. Quando o buffer 2 está cheio, notifica o teu código e volta a escrever no buffer 1. Desta forma, desde que processe cada buffer em menos tempo do que leva para encher um, não perderás nenhum dado. + +Depois de cada buffer ser capturado, pode ser gravado na memória flash. A memória flash precisa de ser escrita usando endereços definidos, especificando onde escrever e o tamanho a escrever, semelhante à atualização de um array de bytes na memória. A memória flash tem granularidade, o que significa que as operações de apagar e escrever dependem não apenas de serem de um tamanho fixo, mas também de estarem alinhadas a esse tamanho. Por exemplo, se a granularidade for de 4096 bytes e pedires para apagar no endereço 4200, pode apagar todos os dados do endereço 4096 até 8192. Isto significa que, ao escrever os dados de áudio na memória flash, tem de ser em blocos do tamanho correto. + +### Tarefa - configurar a memória flash + +1. Cria um novo projeto Wio Terminal usando o PlatformIO. Chama este projeto `smart-timer`. Adiciona código na função `setup` para configurar a porta serial. + +1. Adiciona as seguintes dependências de biblioteca ao ficheiro `platformio.ini` para fornecer acesso à memória flash: + + ```ini + lib_deps = + seeed-studio/Seeed Arduino FS @ 2.1.1 + seeed-studio/Seeed Arduino SFUD @ 2.0.2 + ``` + +1. Abre o ficheiro `main.cpp` e adiciona a seguinte diretiva de inclusão para a biblioteca de memória flash no topo do ficheiro: + + ```cpp + #include + #include + ``` + + > 🎓 SFUD significa Serial Flash Universal Driver, e é uma biblioteca projetada para funcionar com todos os chips de memória flash. + +1. Na função `setup`, adiciona o seguinte código para configurar a biblioteca de armazenamento flash: + + ```cpp + while (!(sfud_init() == SFUD_SUCCESS)) + ; + + sfud_qspi_fast_read_enable(sfud_get_device(SFUD_W25Q32_DEVICE_INDEX), 2); + ``` + + Este código faz um loop até que a biblioteca SFUD seja inicializada e, em seguida, ativa leituras rápidas. A memória flash integrada pode ser acessada usando uma Queued Serial Peripheral Interface (QSPI), um tipo de controlador SPI que permite acesso contínuo através de uma fila com uso mínimo do processador. Isto torna mais rápido ler e escrever na memória flash. + +1. Cria um novo ficheiro na pasta `src` chamado `flash_writer.h`. + +1. Adiciona o seguinte ao topo deste ficheiro: + + ```cpp + #pragma once + + #include + #include + ``` + + Isto inclui alguns ficheiros de cabeçalho necessários, incluindo o ficheiro de cabeçalho da biblioteca SFUD para interagir com a memória flash. + +1. Define uma classe neste novo ficheiro de cabeçalho chamada `FlashWriter`: + + ```cpp + class FlashWriter + { + public: + + private: + }; + ``` + +1. Na secção `private`, adiciona o seguinte código: + + ```cpp + byte *_sfudBuffer; + size_t _sfudBufferSize; + size_t _sfudBufferPos; + size_t _sfudBufferWritePos; + + const sfud_flash *_flash; + ``` + + Isto define alguns campos para o buffer a ser usado para armazenar dados antes de escrevê-los na memória flash. Há um array de bytes, `_sfudBuffer`, para escrever dados, e quando este está cheio, os dados são escritos na memória flash. O campo `_sfudBufferPos` armazena a localização atual para escrever neste buffer, e `_sfudBufferWritePos` armazena a localização na memória flash para escrever. `_flash` é um ponteiro para a memória flash onde os dados serão escritos - alguns microcontroladores têm múltiplos chips de memória flash. + +1. Adiciona o seguinte método à secção `public` para inicializar esta classe: + + ```cpp + void init() + { + _flash = sfud_get_device_table() + 0; + _sfudBufferSize = _flash->chip.erase_gran; + _sfudBuffer = new byte[_sfudBufferSize]; + _sfudBufferPos = 0; + _sfudBufferWritePos = 0; + } + ``` + + Isto configura a memória flash no Wio Terminal para escrever e define os buffers com base no tamanho de granularidade da memória flash. Isto está num método `init`, em vez de um construtor, pois precisa de ser chamado após a memória flash ser configurada na função `setup`. + +1. Adiciona o seguinte código à secção `public`: + + ```cpp + void writeSfudBuffer(byte b) + { + _sfudBuffer[_sfudBufferPos++] = b; + if (_sfudBufferPos == _sfudBufferSize) + { + sfud_erase_write(_flash, _sfudBufferWritePos, _sfudBufferSize, _sfudBuffer); + _sfudBufferWritePos += _sfudBufferSize; + _sfudBufferPos = 0; + } + } + + void writeSfudBuffer(byte *b, size_t len) + { + for (size_t i = 0; i < len; ++i) + { + writeSfudBuffer(b[i]); + } + } + + void flushSfudBuffer() + { + if (_sfudBufferPos > 0) + { + sfud_erase_write(_flash, _sfudBufferWritePos, _sfudBufferSize, _sfudBuffer); + _sfudBufferWritePos += _sfudBufferSize; + _sfudBufferPos = 0; + } + } + ``` + + Este código define métodos para escrever bytes no sistema de armazenamento flash. Funciona escrevendo num buffer em memória que tem o tamanho correto para a memória flash e, quando este está cheio, é escrito na memória flash, apagando quaisquer dados existentes nesse local. Também há um método `flushSfudBuffer` para escrever um buffer incompleto, já que os dados capturados não serão múltiplos exatos do tamanho de granularidade, então a parte final dos dados precisa de ser escrita. + + > 💁 A parte final dos dados escreverá dados adicionais indesejados, mas isto não é um problema, pois apenas os dados necessários serão lidos. + +### Tarefa - configurar a captura de áudio + +1. Cria um novo ficheiro na pasta `src` chamado `config.h`. + +1. Adiciona o seguinte ao topo deste ficheiro: + + ```cpp + #pragma once + + #define RATE 16000 + #define SAMPLE_LENGTH_SECONDS 4 + #define SAMPLES RATE * SAMPLE_LENGTH_SECONDS + #define BUFFER_SIZE (SAMPLES * 2) + 44 + #define ADC_BUF_LEN 1600 + ``` + + Este código configura algumas constantes para a captura de áudio. + + | Constante | Valor | Descrição | + | --------------------- | -----: | - | + | RATE | 16000 | A taxa de amostragem para o áudio. 16.000 é 16KHz | + | SAMPLE_LENGTH_SECONDS | 4 | A duração do áudio a capturar. Está definida para 4 segundos. Para gravar áudio mais longo, aumenta este valor. | + | SAMPLES | 64000 | O número total de amostras de áudio que serão capturadas. Definido como a taxa de amostragem * o número de segundos | + | BUFFER_SIZE | 128044 | O tamanho do buffer de áudio a capturar. O áudio será capturado como um ficheiro WAV, que tem 44 bytes de cabeçalho, seguido de 128.000 bytes de dados de áudio (cada amostra tem 2 bytes) | + | ADC_BUF_LEN | 1600 | O tamanho dos buffers a usar para capturar áudio do DMAC | + + > 💁 Se achares que 4 segundos é muito curto para solicitar um temporizador, podes aumentar o valor de `SAMPLE_LENGTH_SECONDS`, e todos os outros valores serão recalculados. + +1. Cria um novo ficheiro na pasta `src` chamado `mic.h`. + +1. Adiciona o seguinte ao topo deste ficheiro: + + ```cpp + #pragma once + + #include + + #include "config.h" + #include "flash_writer.h" + ``` + + Isto inclui alguns ficheiros de cabeçalho necessários, incluindo os ficheiros `config.h` e `FlashWriter`. + +1. Adiciona o seguinte para definir uma classe `Mic` que pode capturar do microfone: + + ```cpp + class Mic + { + public: + Mic() + { + _isRecording = false; + _isRecordingReady = false; + } + + void startRecording() + { + _isRecording = true; + _isRecordingReady = false; + } + + bool isRecording() + { + return _isRecording; + } + + bool isRecordingReady() + { + return _isRecordingReady; + } + + private: + volatile bool _isRecording; + volatile bool _isRecordingReady; + FlashWriter _writer; + }; + + Mic mic; + ``` + + Esta classe atualmente tem apenas alguns campos para rastrear se a gravação foi iniciada e se uma gravação está pronta para ser usada. Quando o DMAC é configurado, ele escreve continuamente em buffers de memória, então o campo `_isRecording` determina se estes devem ser processados ou ignorados. O campo `_isRecordingReady` será definido quando os 4 segundos necessários de áudio forem capturados. O campo `_writer` é usado para guardar os dados de áudio na memória flash. + + Uma variável global é então declarada para uma instância da classe `Mic`. + +1. Adiciona o seguinte código à secção `private` da classe `Mic`: + + ```cpp + typedef struct + { + uint16_t btctrl; + uint16_t btcnt; + uint32_t srcaddr; + uint32_t dstaddr; + uint32_t descaddr; + } dmacdescriptor; + + // Globals - DMA and ADC + volatile dmacdescriptor _wrb[DMAC_CH_NUM] __attribute__((aligned(16))); + dmacdescriptor _descriptor_section[DMAC_CH_NUM] __attribute__((aligned(16))); + dmacdescriptor _descriptor __attribute__((aligned(16))); + + void configureDmaAdc() + { + // Configure DMA to sample from ADC at a regular interval (triggered by timer/counter) + DMAC->BASEADDR.reg = (uint32_t)_descriptor_section; // Specify the location of the descriptors + DMAC->WRBADDR.reg = (uint32_t)_wrb; // Specify the location of the write back descriptors + DMAC->CTRL.reg = DMAC_CTRL_DMAENABLE | DMAC_CTRL_LVLEN(0xf); // Enable the DMAC peripheral + DMAC->Channel[1].CHCTRLA.reg = DMAC_CHCTRLA_TRIGSRC(TC5_DMAC_ID_OVF) | // Set DMAC to trigger on TC5 timer overflow + DMAC_CHCTRLA_TRIGACT_BURST; // DMAC burst transfer + + _descriptor.descaddr = (uint32_t)&_descriptor_section[1]; // Set up a circular descriptor + _descriptor.srcaddr = (uint32_t)&ADC1->RESULT.reg; // Take the result from the ADC0 RESULT register + _descriptor.dstaddr = (uint32_t)_adc_buf_0 + sizeof(uint16_t) * ADC_BUF_LEN; // Place it in the adc_buf_0 array + _descriptor.btcnt = ADC_BUF_LEN; // Beat count + _descriptor.btctrl = DMAC_BTCTRL_BEATSIZE_HWORD | // Beat size is HWORD (16-bits) + DMAC_BTCTRL_DSTINC | // Increment the destination address + DMAC_BTCTRL_VALID | // Descriptor is valid + DMAC_BTCTRL_BLOCKACT_SUSPEND; // Suspend DMAC channel 0 after block transfer + memcpy(&_descriptor_section[0], &_descriptor, sizeof(_descriptor)); // Copy the descriptor to the descriptor section + + _descriptor.descaddr = (uint32_t)&_descriptor_section[0]; // Set up a circular descriptor + _descriptor.srcaddr = (uint32_t)&ADC1->RESULT.reg; // Take the result from the ADC0 RESULT register + _descriptor.dstaddr = (uint32_t)_adc_buf_1 + sizeof(uint16_t) * ADC_BUF_LEN; // Place it in the adc_buf_1 array + _descriptor.btcnt = ADC_BUF_LEN; // Beat count + _descriptor.btctrl = DMAC_BTCTRL_BEATSIZE_HWORD | // Beat size is HWORD (16-bits) + DMAC_BTCTRL_DSTINC | // Increment the destination address + DMAC_BTCTRL_VALID | // Descriptor is valid + DMAC_BTCTRL_BLOCKACT_SUSPEND; // Suspend DMAC channel 0 after block transfer + memcpy(&_descriptor_section[1], &_descriptor, sizeof(_descriptor)); // Copy the descriptor to the descriptor section + + // Configure NVIC + NVIC_SetPriority(DMAC_1_IRQn, 0); // Set the Nested Vector Interrupt Controller (NVIC) priority for DMAC1 to 0 (highest) + NVIC_EnableIRQ(DMAC_1_IRQn); // Connect DMAC1 to Nested Vector Interrupt Controller (NVIC) + + // Activate the suspend (SUSP) interrupt on DMAC channel 1 + DMAC->Channel[1].CHINTENSET.reg = DMAC_CHINTENSET_SUSP; + + // Configure ADC + ADC1->INPUTCTRL.bit.MUXPOS = ADC_INPUTCTRL_MUXPOS_AIN12_Val; // Set the analog input to ADC0/AIN2 (PB08 - A4 on Metro M4) + while (ADC1->SYNCBUSY.bit.INPUTCTRL) + ; // Wait for synchronization + ADC1->SAMPCTRL.bit.SAMPLEN = 0x00; // Set max Sampling Time Length to half divided ADC clock pulse (2.66us) + while (ADC1->SYNCBUSY.bit.SAMPCTRL) + ; // Wait for synchronization + ADC1->CTRLA.reg = ADC_CTRLA_PRESCALER_DIV128; // Divide Clock ADC GCLK by 128 (48MHz/128 = 375kHz) + ADC1->CTRLB.reg = ADC_CTRLB_RESSEL_12BIT | // Set ADC resolution to 12 bits + ADC_CTRLB_FREERUN; // Set ADC to free run mode + while (ADC1->SYNCBUSY.bit.CTRLB) + ; // Wait for synchronization + ADC1->CTRLA.bit.ENABLE = 1; // Enable the ADC + while (ADC1->SYNCBUSY.bit.ENABLE) + ; // Wait for synchronization + ADC1->SWTRIG.bit.START = 1; // Initiate a software trigger to start an ADC conversion + while (ADC1->SYNCBUSY.bit.SWTRIG) + ; // Wait for synchronization + + // Enable DMA channel 1 + DMAC->Channel[1].CHCTRLA.bit.ENABLE = 1; + + // Configure Timer/Counter 5 + GCLK->PCHCTRL[TC5_GCLK_ID].reg = GCLK_PCHCTRL_CHEN | // Enable peripheral channel for TC5 + GCLK_PCHCTRL_GEN_GCLK1; // Connect generic clock 0 at 48MHz + + TC5->COUNT16.WAVE.reg = TC_WAVE_WAVEGEN_MFRQ; // Set TC5 to Match Frequency (MFRQ) mode + TC5->COUNT16.CC[0].reg = 3000 - 1; // Set the trigger to 16 kHz: (4Mhz / 16000) - 1 + while (TC5->COUNT16.SYNCBUSY.bit.CC0) + ; // Wait for synchronization + + // Start Timer/Counter 5 + TC5->COUNT16.CTRLA.bit.ENABLE = 1; // Enable the TC5 timer + while (TC5->COUNT16.SYNCBUSY.bit.ENABLE) + ; // Wait for synchronization + } + + uint16_t _adc_buf_0[ADC_BUF_LEN]; + uint16_t _adc_buf_1[ADC_BUF_LEN]; + ``` + + Este código define um método `configureDmaAdc` que configura o DMAC, conectando-o ao ADC e configurando-o para preencher dois buffers alternados, `_adc_buf_0` e `_adc_buf_1`. + + > 💁 Uma das desvantagens do desenvolvimento para microcontroladores é a complexidade do código necessário para interagir com o hardware, já que o teu código funciona a um nível muito baixo, interagindo diretamente com o hardware. Este código é mais complexo do que o que escreverias para um computador de placa única ou um computador desktop, pois não há sistema operativo para ajudar. Existem algumas bibliotecas disponíveis que podem simplificar isto, mas ainda há muita complexidade. + +1. Abaixo disto, adiciona o seguinte código: + + ```cpp + // WAV files have a header. This struct defines that header + struct wavFileHeader + { + char riff[4]; /* "RIFF" */ + long flength; /* file length in bytes */ + char wave[4]; /* "WAVE" */ + char fmt[4]; /* "fmt " */ + long chunk_size; /* size of FMT chunk in bytes (usually 16) */ + short format_tag; /* 1=PCM, 257=Mu-Law, 258=A-Law, 259=ADPCM */ + short num_chans; /* 1=mono, 2=stereo */ + long srate; /* Sampling rate in samples per second */ + long bytes_per_sec; /* bytes per second = srate*bytes_per_samp */ + short bytes_per_samp; /* 2=16-bit mono, 4=16-bit stereo */ + short bits_per_samp; /* Number of bits per sample */ + char data[4]; /* "data" */ + long dlength; /* data length in bytes (filelength - 44) */ + }; + + void initBufferHeader() + { + wavFileHeader wavh; + + strncpy(wavh.riff, "RIFF", 4); + strncpy(wavh.wave, "WAVE", 4); + strncpy(wavh.fmt, "fmt ", 4); + strncpy(wavh.data, "data", 4); + + wavh.chunk_size = 16; + wavh.format_tag = 1; // PCM + wavh.num_chans = 1; // mono + wavh.srate = RATE; + wavh.bytes_per_sec = (RATE * 1 * 16 * 1) / 8; + wavh.bytes_per_samp = 2; + wavh.bits_per_samp = 16; + wavh.dlength = RATE * 2 * 1 * 16 / 2; + wavh.flength = wavh.dlength + 44; + + _writer.writeSfudBuffer((byte *)&wavh, 44); + } + ``` + + Este código define o cabeçalho WAV como uma estrutura que ocupa 44 bytes de memória. Escreve detalhes sobre a taxa, tamanho e número de canais do ficheiro de áudio. Este cabeçalho é então escrito na memória flash. + +1. Abaixo deste código, adiciona o seguinte para declarar um método a ser chamado quando os buffers de áudio estiverem prontos para serem processados: + + ```cpp + void audioCallback(uint16_t *buf, uint32_t buf_len) + { + static uint32_t idx = 44; + + if (_isRecording) + { + for (uint32_t i = 0; i < buf_len; i++) + { + int16_t audio_value = ((int16_t)buf[i] - 2048) * 16; + + _writer.writeSfudBuffer(audio_value & 0xFF); + _writer.writeSfudBuffer((audio_value >> 8) & 0xFF); + } + + idx += buf_len; + + if (idx >= BUFFER_SIZE) + { + _writer.flushSfudBuffer(); + idx = 44; + _isRecording = false; + _isRecordingReady = true; + } + } + } + ``` + + Os buffers de áudio são arrays de inteiros de 16 bits contendo o áudio do ADC. O ADC retorna valores sem sinal de 12 bits (0-1023), então estes precisam de ser convertidos para valores de 16 bits com sinal e depois convertidos em 2 bytes para serem armazenados como dados binários brutos. + + Estes bytes são escritos nos buffers de memória flash. A escrita começa no índice 44 - este é o deslocamento dos 44 bytes escritos como cabeçalho do ficheiro WAV. Assim que todos os bytes necessários para a duração de áudio requerida forem capturados, os dados restantes são escritos na memória flash. + +1. Na secção `public` da classe `Mic`, adiciona o seguinte código: + + ```cpp + void dmaHandler() + { + static uint8_t count = 0; + + if (DMAC->Channel[1].CHINTFLAG.bit.SUSP) + { + DMAC->Channel[1].CHCTRLB.reg = DMAC_CHCTRLB_CMD_RESUME; + DMAC->Channel[1].CHINTFLAG.bit.SUSP = 1; + + if (count) + { + audioCallback(_adc_buf_0, ADC_BUF_LEN); + } + else + { + audioCallback(_adc_buf_1, ADC_BUF_LEN); + } + + count = (count + 1) % 2; + } + } + ``` + + Este código será chamado pelo DMAC para informar o teu código que os buffers estão prontos para serem processados. Verifica se há dados para processar e chama o método `audioCallback` com o buffer relevante. + +1. Fora da classe, após a declaração `Mic mic;`, adiciona o seguinte código: + + ```cpp + void DMAC_1_Handler() + { + mic.dmaHandler(); + } + ``` + + O `DMAC_1_Handler` será chamado pelo DMAC quando os buffers estiverem prontos para serem processados. Esta função é encontrada pelo nome, então só precisa de existir para ser chamada. + +1. Adiciona os seguintes dois métodos à secção `public` da classe `Mic`: + + ```cpp + void init() + { + analogReference(AR_INTERNAL2V23); + + _writer.init(); + + initBufferHeader(); + configureDmaAdc(); + } + + void reset() + { + _isRecordingReady = false; + _isRecording = false; + + _writer.reset(); + + initBufferHeader(); + } + ``` + + O método `init` contém código para inicializar a classe `Mic`. Este método define a voltagem correta para o pino do microfone, configura o gravador de memória flash, escreve o cabeçalho do ficheiro WAV e configura o DMAC. O método `reset` reinicia a memória flash e reescreve o cabeçalho após o áudio ter sido capturado e utilizado. + +### Tarefa - capturar áudio + +1. No ficheiro `main.cpp`, adiciona uma diretiva de inclusão para o ficheiro de cabeçalho `mic.h`: + + ```cpp + #include "mic.h" + ``` + +1. Na função `setup`, inicializa o botão C. A captura de áudio começará quando este botão for pressionado e continuará por 4 segundos: + + ```cpp + pinMode(WIO_KEY_C, INPUT_PULLUP); + ``` + +1. Abaixo disto, inicializa o microfone e imprime na consola que o áudio está pronto para ser capturado: + + ```cpp + mic.init(); + + Serial.println("Ready."); + ``` + +1. Acima da função `loop`, define uma função para processar o áudio capturado. Por enquanto, esta não faz nada, mas mais tarde nesta lição enviará o discurso para ser convertido em texto: + + ```cpp + void processAudio() + { + + } + ``` + +1. Adiciona o seguinte à função `loop`: + + ```cpp + void loop() + { + if (digitalRead(WIO_KEY_C) == LOW && !mic.isRecording()) + { + Serial.println("Starting recording..."); + mic.startRecording(); + } + + if (!mic.isRecording() && mic.isRecordingReady()) + { + Serial.println("Finished recording"); + + processAudio(); + + mic.reset(); + } + } + ``` + + Este código verifica o botão C e, se este for pressionado e a gravação ainda não tiver começado, o campo `_isRecording` da classe `Mic` é definido como verdadeiro. Isto fará com que o método `audioCallback` da classe `Mic` armazene áudio até que 4 segundos sejam capturados. Assim que 4 segundos de áudio forem capturados, o campo `_isRecording` é definido como falso e o campo `_isRecordingReady` é definido como verdadeiro. Isto é então verificado na função `loop` e, quando verdadeiro, a função `processAudio` é chamada e a classe `Mic` é reiniciada. + +1. Compila este código, carrega-o no teu Wio Terminal e testa-o através do monitor serial. Pressiona o botão C (o botão do lado esquerdo, mais próximo do interruptor de energia) e fala. Serão capturados 4 segundos de áudio. + + ```output + --- Available filters and text transformations: colorize, debug, default, direct, hexlify, log2file, nocontrol, printable, send_on_enter, time + --- More details at http://bit.ly/pio-monitor-filters + --- Miniterm on /dev/cu.usbmodem1101 9600,8,N,1 --- + --- Quit: Ctrl+C | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H --- + Ready. + Starting recording... + Finished recording + ``` +💁 Pode encontrar este código na pasta [code-record/wio-terminal](../../../../../6-consumer/lessons/1-speech-recognition/code-record/wio-terminal). +😀 O teu programa de gravação de áudio foi um sucesso! + +**Aviso Legal**: +Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, é importante notar que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes do uso desta tradução. \ No newline at end of file diff --git a/translations/pt-PT/6-consumer/lessons/1-speech-recognition/wio-terminal-microphone.md b/translations/pt-PT/6-consumer/lessons/1-speech-recognition/wio-terminal-microphone.md new file mode 100644 index 000000000..6e56cc455 --- /dev/null +++ b/translations/pt-PT/6-consumer/lessons/1-speech-recognition/wio-terminal-microphone.md @@ -0,0 +1,78 @@ +# Configure o seu microfone e altifalantes - Wio Terminal + +Nesta parte da lição, irá adicionar altifalantes ao seu Wio Terminal. O Wio Terminal já possui um microfone incorporado, que pode ser utilizado para captar voz. + +## Hardware + +O Wio Terminal já tem um microfone integrado, que pode ser usado para captar áudio para reconhecimento de voz. + +![O microfone no Wio Terminal](../../../../../translated_images/pt-PT/wio-mic.3f8c843dbe8ad917.webp) + +Para adicionar um altifalante, pode usar o [ReSpeaker 2-Mics Pi Hat](https://www.seeedstudio.com/ReSpeaker-2-Mics-Pi-HAT.html). Este é um módulo externo que contém 2 microfones MEMS, bem como um conector para altifalantes e uma entrada para auscultadores. + +![O ReSpeaker 2-Mics Pi Hat](../../../../../translated_images/pt-PT/respeaker.f5d19d1c6b14ab16.webp) + +Será necessário adicionar auscultadores, um altifalante com ficha de 3,5mm ou um altifalante com ligação JST, como o [Mono Enclosed Speaker - 2W 6 Ohm](https://www.seeedstudio.com/Mono-Enclosed-Speaker-2W-6-Ohm-p-2832.html). + +Para ligar o ReSpeaker 2-Mics Pi Hat, irá precisar de cabos de ligação de 40 pinos (também conhecidos como macho-macho). + +> 💁 Se estiver confortável com soldadura, pode usar o [40 Pin Raspberry Pi Hat Adapter Board For Wio Terminal](https://www.seeedstudio.com/40-Pin-Raspberry-Pi-Hat-Adapter-Board-For-Wio-Terminal-p-4730.html) para conectar o ReSpeaker. + +Também irá precisar de um cartão SD para descarregar e reproduzir áudio. O Wio Terminal suporta apenas cartões SD até 16GB de capacidade, e estes devem estar formatados em FAT32 ou exFAT. + +### Tarefa - ligar o ReSpeaker Pi Hat + +1. Com o Wio Terminal desligado, conecte o ReSpeaker 2-Mics Pi Hat ao Wio Terminal usando os cabos de ligação e os conectores GPIO na parte traseira do Wio Terminal: + + Os pinos devem ser conectados desta forma: + + ![Um diagrama de pinos](../../../../../translated_images/pt-PT/wio-respeaker-wiring-0.767f80aa65081038.webp) + +1. Posicione o ReSpeaker e o Wio Terminal com os conectores GPIO voltados para cima e do lado esquerdo. + +1. Comece pelo conector no canto superior esquerdo do GPIO do ReSpeaker. Ligue um cabo de ligação do conector superior esquerdo do ReSpeaker ao conector superior esquerdo do Wio Terminal. + +1. Repita este processo ao longo dos conectores GPIO do lado esquerdo. Certifique-se de que os pinos estão bem encaixados. + + ![Um ReSpeaker com os pinos do lado esquerdo ligados aos pinos do lado esquerdo do Wio Terminal](../../../../../translated_images/pt-PT/wio-respeaker-wiring-1.8d894727f2ba2400.webp) + + ![Um ReSpeaker com os pinos do lado esquerdo ligados aos pinos do lado esquerdo do Wio Terminal](../../../../../translated_images/pt-PT/wio-respeaker-wiring-2.329e1cbd306e754f.webp) + + > 💁 Se os seus cabos de ligação estiverem agrupados em fitas, mantenha-os juntos - isso facilita garantir que todos os cabos estão conectados na ordem correta. + +1. Repita o processo usando os conectores GPIO do lado direito do ReSpeaker e do Wio Terminal. Estes cabos devem passar por cima dos cabos já conectados. + + ![Um ReSpeaker com os pinos do lado direito ligados aos pinos do lado direito do Wio Terminal](../../../../../translated_images/pt-PT/wio-respeaker-wiring-3.75b0be447e2fa930.webp) + + ![Um ReSpeaker com os pinos do lado direito ligados aos pinos do lado direito do Wio Terminal](../../../../../translated_images/pt-PT/wio-respeaker-wiring-4.aa9cd434d8779437.webp) + + > 💁 Se os seus cabos de ligação estiverem agrupados em fitas, divida-os em duas fitas. Passe uma fita de cada lado dos cabos já existentes. + + > 💁 Pode usar fita adesiva para segurar os pinos em bloco e evitar que se soltem enquanto os conecta. + > + > ![Os pinos fixados com fita adesiva](../../../../../translated_images/pt-PT/wio-respeaker-wiring-5.af117c20acf622f3.webp) + +1. Será necessário adicionar um altifalante. + + * Se estiver a usar um altifalante com cabo JST, conecte-o à porta JST no ReSpeaker. + + ![Um altifalante conectado ao ReSpeaker com um cabo JST](../../../../../translated_images/pt-PT/respeaker-jst-speaker.a441d177809df945.webp) + + * Se estiver a usar um altifalante com ficha de 3,5mm ou auscultadores, insira-os na entrada de 3,5mm. + + ![Um altifalante conectado ao ReSpeaker através da entrada de 3,5mm](../../../../../translated_images/pt-PT/respeaker-35mm-speaker.ad79ef4f128c7751.webp) + +### Tarefa - configurar o cartão SD + +1. Conecte o cartão SD ao seu computador, usando um leitor externo caso não tenha uma entrada para cartões SD. + +1. Formate o cartão SD utilizando a ferramenta apropriada no seu computador, certificando-se de que usa o sistema de ficheiros FAT32 ou exFAT. + +1. Insira o cartão SD na entrada de cartões SD no lado esquerdo do Wio Terminal, logo abaixo do botão de ligar/desligar. Certifique-se de que o cartão está completamente inserido e faz um clique - pode precisar de uma ferramenta fina ou outro cartão SD para ajudar a empurrá-lo completamente. + + ![Inserir o cartão SD na entrada de cartões SD abaixo do botão de ligar/desligar](../../../../../translated_images/pt-PT/wio-sd-card.acdcbe322fa4ee7f.webp) + + > 💁 Para ejetar o cartão SD, precisa de empurrá-lo ligeiramente e ele será ejetado. Será necessário usar uma ferramenta fina, como uma chave de fendas de cabeça plana ou outro cartão SD. + +**Aviso Legal**: +Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, tenha em atenção que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes da utilização desta tradução. \ No newline at end of file diff --git a/translations/pt-PT/6-consumer/lessons/1-speech-recognition/wio-terminal-speech-to-text.md b/translations/pt-PT/6-consumer/lessons/1-speech-recognition/wio-terminal-speech-to-text.md new file mode 100644 index 000000000..b92cf8feb --- /dev/null +++ b/translations/pt-PT/6-consumer/lessons/1-speech-recognition/wio-terminal-speech-to-text.md @@ -0,0 +1,533 @@ +# Fala para texto - Wio Terminal + +Nesta parte da lição, vais escrever código para converter fala captada no áudio em texto utilizando o serviço de fala. + +## Enviar o áudio para o serviço de fala + +O áudio pode ser enviado para o serviço de fala utilizando a API REST. Para usar o serviço de fala, primeiro precisas de solicitar um token de acesso e, em seguida, usar esse token para aceder à API REST. Estes tokens de acesso expiram após 10 minutos, por isso o teu código deve solicitá-los regularmente para garantir que estão sempre atualizados. + +### Tarefa - obter um token de acesso + +1. Abre o projeto `smart-timer` caso ainda não esteja aberto. + +1. Adiciona as seguintes dependências de biblioteca ao ficheiro `platformio.ini` para aceder ao WiFi e manipular JSON: + + ```ini + seeed-studio/Seeed Arduino rpcWiFi @ 1.0.5 + seeed-studio/Seeed Arduino rpcUnified @ 2.1.3 + seeed-studio/Seeed_Arduino_mbedtls @ 3.0.1 + seeed-studio/Seeed Arduino RTC @ 2.0.0 + bblanchon/ArduinoJson @ 6.17.3 + ``` + +1. Adiciona o seguinte código ao ficheiro de cabeçalho `config.h`: + + ```cpp + const char *SSID = ""; + const char *PASSWORD = ""; + + const char *SPEECH_API_KEY = ""; + const char *SPEECH_LOCATION = ""; + const char *LANGUAGE = ""; + + const char *TOKEN_URL = "https://%s.api.cognitive.microsoft.com/sts/v1.0/issuetoken"; + ``` + + Substitui `` e `` pelos valores relevantes para o teu WiFi. + + Substitui `` pela chave de API do recurso do serviço de fala. Substitui `` pela localização que utilizaste ao criar o recurso do serviço de fala. + + Substitui `` pelo nome do local para o idioma em que vais falar, por exemplo, `en-GB` para inglês ou `zn-HK` para cantonês. Podes encontrar uma lista dos idiomas suportados e os seus nomes de local na [documentação de suporte de idiomas e vozes nos Microsoft Docs](https://docs.microsoft.com/azure/cognitive-services/speech-service/language-support?WT.mc_id=academic-17441-jabenn#speech-to-text). + + A constante `TOKEN_URL` é o URL do emissor de tokens sem a localização. Este será combinado com a localização mais tarde para obter o URL completo. + +1. Tal como na conexão ao Custom Vision, vais precisar de usar uma conexão HTTPS para ligar ao serviço emissor de tokens. No final do ficheiro `config.h`, adiciona o seguinte código: + + ```cpp + const char *TOKEN_CERTIFICATE = + "-----BEGIN CERTIFICATE-----\r\n" + "MIIF8zCCBNugAwIBAgIQAueRcfuAIek/4tmDg0xQwDANBgkqhkiG9w0BAQwFADBh\r\n" + "MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\r\n" + "d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH\r\n" + "MjAeFw0yMDA3MjkxMjMwMDBaFw0yNDA2MjcyMzU5NTlaMFkxCzAJBgNVBAYTAlVT\r\n" + "MR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKjAoBgNVBAMTIU1pY3Jv\r\n" + "c29mdCBBenVyZSBUTFMgSXNzdWluZyBDQSAwNjCCAiIwDQYJKoZIhvcNAQEBBQAD\r\n" + "ggIPADCCAgoCggIBALVGARl56bx3KBUSGuPc4H5uoNFkFH4e7pvTCxRi4j/+z+Xb\r\n" + "wjEz+5CipDOqjx9/jWjskL5dk7PaQkzItidsAAnDCW1leZBOIi68Lff1bjTeZgMY\r\n" + "iwdRd3Y39b/lcGpiuP2d23W95YHkMMT8IlWosYIX0f4kYb62rphyfnAjYb/4Od99\r\n" + "ThnhlAxGtfvSbXcBVIKCYfZgqRvV+5lReUnd1aNjRYVzPOoifgSx2fRyy1+pO1Uz\r\n" + "aMMNnIOE71bVYW0A1hr19w7kOb0KkJXoALTDDj1ukUEDqQuBfBxReL5mXiu1O7WG\r\n" + "0vltg0VZ/SZzctBsdBlx1BkmWYBW261KZgBivrql5ELTKKd8qgtHcLQA5fl6JB0Q\r\n" + "gs5XDaWehN86Gps5JW8ArjGtjcWAIP+X8CQaWfaCnuRm6Bk/03PQWhgdi84qwA0s\r\n" + "sRfFJwHUPTNSnE8EiGVk2frt0u8PG1pwSQsFuNJfcYIHEv1vOzP7uEOuDydsmCjh\r\n" + "lxuoK2n5/2aVR3BMTu+p4+gl8alXoBycyLmj3J/PUgqD8SL5fTCUegGsdia/Sa60\r\n" + "N2oV7vQ17wjMN+LXa2rjj/b4ZlZgXVojDmAjDwIRdDUujQu0RVsJqFLMzSIHpp2C\r\n" + "Zp7mIoLrySay2YYBu7SiNwL95X6He2kS8eefBBHjzwW/9FxGqry57i71c2cDAgMB\r\n" + "AAGjggGtMIIBqTAdBgNVHQ4EFgQU1cFnOsKjnfR3UltZEjgp5lVou6UwHwYDVR0j\r\n" + "BBgwFoAUTiJUIBiV5uNu5g/6+rkS7QYXjzkwDgYDVR0PAQH/BAQDAgGGMB0GA1Ud\r\n" + "JQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjASBgNVHRMBAf8ECDAGAQH/AgEAMHYG\r\n" + "CCsGAQUFBwEBBGowaDAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQu\r\n" + "Y29tMEAGCCsGAQUFBzAChjRodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGln\r\n" + "aUNlcnRHbG9iYWxSb290RzIuY3J0MHsGA1UdHwR0MHIwN6A1oDOGMWh0dHA6Ly9j\r\n" + "cmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RHMi5jcmwwN6A1oDOG\r\n" + "MWh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RHMi5j\r\n" + "cmwwHQYDVR0gBBYwFDAIBgZngQwBAgEwCAYGZ4EMAQICMBAGCSsGAQQBgjcVAQQD\r\n" + "AgEAMA0GCSqGSIb3DQEBDAUAA4IBAQB2oWc93fB8esci/8esixj++N22meiGDjgF\r\n" + "+rA2LUK5IOQOgcUSTGKSqF9lYfAxPjrqPjDCUPHCURv+26ad5P/BYtXtbmtxJWu+\r\n" + "cS5BhMDPPeG3oPZwXRHBJFAkY4O4AF7RIAAUW6EzDflUoDHKv83zOiPfYGcpHc9s\r\n" + "kxAInCedk7QSgXvMARjjOqdakor21DTmNIUotxo8kHv5hwRlGhBJwps6fEVi1Bt0\r\n" + "trpM/3wYxlr473WSPUFZPgP1j519kLpWOJ8z09wxay+Br29irPcBYv0GMXlHqThy\r\n" + "8y4m/HyTQeI2IMvMrQnwqPpY+rLIXyviI2vLoI+4xKE4Rn38ZZ8m\r\n" + "-----END CERTIFICATE-----\r\n"; + ``` + + Este é o mesmo certificado que utilizaste ao conectar ao Custom Vision. + +1. Adiciona um include para o ficheiro de cabeçalho do WiFi e o ficheiro de cabeçalho de configuração no topo do ficheiro `main.cpp`: + + ```cpp + #include + + #include "config.h" + ``` + +1. Adiciona código para conectar ao WiFi em `main.cpp` acima da função `setup`: + + ```cpp + void connectWiFi() + { + while (WiFi.status() != WL_CONNECTED) + { + Serial.println("Connecting to WiFi.."); + WiFi.begin(SSID, PASSWORD); + delay(500); + } + + Serial.println("Connected!"); + } + ``` + +1. Chama esta função a partir da função `setup` após a conexão serial ter sido estabelecida: + + ```cpp + connectWiFi(); + ``` + +1. Cria um novo ficheiro de cabeçalho na pasta `src` chamado `speech_to_text.h`. Neste ficheiro de cabeçalho, adiciona o seguinte código: + + ```cpp + #pragma once + + #include + #include + #include + #include + + #include "config.h" + #include "mic.h" + + class SpeechToText + { + public: + + private: + + }; + + SpeechToText speechToText; + ``` + + Isto inclui alguns ficheiros de cabeçalho necessários para uma conexão HTTP, configuração e o ficheiro de cabeçalho `mic.h`, e define uma classe chamada `SpeechToText`, antes de declarar uma instância dessa classe que pode ser usada mais tarde. + +1. Adiciona os seguintes 2 campos à secção `private` desta classe: + + ```cpp + WiFiClientSecure _token_client; + String _access_token; + ``` + + O `_token_client` é um cliente WiFi que usa HTTPS e será usado para obter o token de acesso. Este token será então armazenado em `_access_token`. + +1. Adiciona o seguinte método à secção `private`: + + ```cpp + String getAccessToken() + { + char url[128]; + sprintf(url, TOKEN_URL, SPEECH_LOCATION); + + HTTPClient httpClient; + httpClient.begin(_token_client, url); + + httpClient.addHeader("Ocp-Apim-Subscription-Key", SPEECH_API_KEY); + int httpResultCode = httpClient.POST("{}"); + + if (httpResultCode != 200) + { + Serial.println("Error getting access token, trying again..."); + delay(10000); + return getAccessToken(); + } + + Serial.println("Got access token."); + String result = httpClient.getString(); + + httpClient.end(); + + return result; + } + ``` + + Este código constrói o URL para a API do emissor de tokens usando a localização do recurso de fala. Em seguida, cria um `HTTPClient` para fazer a solicitação web, configurando-o para usar o cliente WiFi configurado com o certificado dos endpoints de token. Define a chave de API como um cabeçalho para a chamada. Faz uma solicitação POST para obter o certificado, tentando novamente se ocorrerem erros. Finalmente, o token de acesso é retornado. + +1. Na secção `public`, adiciona um método para obter o token de acesso. Este será necessário em lições posteriores para converter texto em fala. + + ```cpp + String AccessToken() + { + return _access_token; + } + ``` + +1. Na secção `public`, adiciona um método `init` que configura o cliente de token: + + ```cpp + void init() + { + _token_client.setCACert(TOKEN_CERTIFICATE); + _access_token = getAccessToken(); + } + ``` + + Isto define o certificado no cliente WiFi e, em seguida, obtém o token de acesso. + +1. Em `main.cpp`, adiciona este novo ficheiro de cabeçalho às diretivas de inclusão: + + ```cpp + #include "speech_to_text.h" + ``` + +1. Inicializa a classe `SpeechToText` no final da função `setup`, após a chamada `mic.init`, mas antes de `Ready` ser escrito no monitor serial: + + ```cpp + speechToText.init(); + ``` + +### Tarefa - ler áudio da memória flash + +1. Numa parte anterior desta lição, o áudio foi gravado na memória flash. Este áudio precisará de ser enviado para a API REST do Speech Services, por isso precisa de ser lido da memória flash. Não pode ser carregado num buffer em memória, pois seria demasiado grande. A classe `HTTPClient` que faz chamadas REST pode transmitir dados usando um Arduino Stream - uma classe que pode carregar dados em pequenos blocos, enviando os blocos um de cada vez como parte da solicitação. Sempre que chamas `read` num stream, ele retorna o próximo bloco de dados. Um stream Arduino pode ser criado para ler da memória flash. Cria um novo ficheiro chamado `flash_stream.h` na pasta `src` e adiciona o seguinte código: + + ```cpp + #pragma once + + #include + #include + #include + + #include "config.h" + + class FlashStream : public Stream + { + public: + virtual size_t write(uint8_t val) + { + } + + virtual int available() + { + } + + virtual int read() + { + } + + virtual int peek() + { + } + private: + + }; + ``` + + Isto declara a classe `FlashStream`, derivada da classe `Stream` do Arduino. Esta é uma classe abstrata - classes derivadas têm de implementar alguns métodos antes que a classe possa ser instanciada, e esses métodos são definidos nesta classe. + + ✅ Lê mais sobre Streams do Arduino na [documentação de Streams do Arduino](https://www.arduino.cc/reference/en/language/functions/communication/stream/) + +1. Adiciona os seguintes campos à secção `private`: + + ```cpp + size_t _pos; + size_t _flash_address; + const sfud_flash *_flash; + + byte _buffer[HTTP_TCP_BUFFER_SIZE]; + ``` + + Isto define um buffer temporário para armazenar dados lidos da memória flash, juntamente com campos para armazenar a posição atual ao ler do buffer, o endereço atual para ler da memória flash e o dispositivo de memória flash. + +1. Na secção `private`, adiciona o seguinte método: + + ```cpp + void populateBuffer() + { + sfud_read(_flash, _flash_address, HTTP_TCP_BUFFER_SIZE, _buffer); + _flash_address += HTTP_TCP_BUFFER_SIZE; + _pos = 0; + } + ``` + + Este código lê da memória flash no endereço atual e armazena os dados num buffer. Em seguida, incrementa o endereço, para que a próxima chamada leia o próximo bloco de memória. O buffer é dimensionado com base no maior bloco que o `HTTPClient` enviará para a API REST de uma só vez. + + > 💁 Apagar memória flash tem de ser feito usando o tamanho do grão, ler, por outro lado, não. + +1. Na secção `public` desta classe, adiciona um construtor: + + ```cpp + FlashStream() + { + _pos = 0; + _flash_address = 0; + _flash = sfud_get_device_table() + 0; + + populateBuffer(); + } + ``` + + Este construtor configura todos os campos para começar a ler do início do bloco de memória flash e carrega o primeiro bloco de dados no buffer. + +1. Implementa o método `write`. Este stream apenas lerá dados, por isso pode não fazer nada e retornar 0: + + ```cpp + virtual size_t write(uint8_t val) + { + return 0; + } + ``` + +1. Implementa o método `peek`. Este retorna os dados na posição atual sem mover o stream. Chamar `peek` várias vezes sempre retornará os mesmos dados enquanto nenhum dado for lido do stream. + + ```cpp + virtual int peek() + { + return _buffer[_pos]; + } + ``` + +1. Implementa a função `available`. Esta retorna quantos bytes podem ser lidos do stream ou -1 se o stream estiver completo. Para esta classe, o máximo disponível será no máximo o tamanho do bloco do HTTPClient. Quando este stream é usado no cliente HTTP, ele chama esta função para ver quantos dados estão disponíveis e, em seguida, solicita essa quantidade de dados para enviar para a API REST. Não queremos que cada bloco seja maior do que o tamanho do bloco do cliente HTTP, por isso, se mais do que isso estiver disponível, o tamanho do bloco é retornado. Se menos, então o que está disponível é retornado. Uma vez que todos os dados tenham sido transmitidos, -1 é retornado. + + ```cpp + virtual int available() + { + int remaining = BUFFER_SIZE - ((_flash_address - HTTP_TCP_BUFFER_SIZE) + _pos); + int bytes_available = min(HTTP_TCP_BUFFER_SIZE, remaining); + + if (bytes_available == 0) + { + bytes_available = -1; + } + + return bytes_available; + } + ``` + +1. Implementa o método `read` para retornar o próximo byte do buffer, incrementando a posição. Se a posição exceder o tamanho do buffer, ele preenche o buffer com o próximo bloco da memória flash e redefine a posição. + + ```cpp + virtual int read() + { + int retVal = _buffer[_pos++]; + + if (_pos == HTTP_TCP_BUFFER_SIZE) + { + populateBuffer(); + } + + return retVal; + } + ``` + +1. No ficheiro de cabeçalho `speech_to_text.h`, adiciona uma diretiva de inclusão para este novo ficheiro de cabeçalho: + + ```cpp + #include "flash_stream.h" + ``` + +### Tarefa - converter a fala em texto + +1. A fala pode ser convertida em texto enviando o áudio para o Serviço de Fala através de uma API REST. Esta API REST tem um certificado diferente do emissor de tokens, por isso adiciona o seguinte código ao ficheiro de cabeçalho `config.h` para definir este certificado: + + ```cpp + const char *SPEECH_CERTIFICATE = + "-----BEGIN CERTIFICATE-----\r\n" + "MIIF8zCCBNugAwIBAgIQCq+mxcpjxFFB6jvh98dTFzANBgkqhkiG9w0BAQwFADBh\r\n" + "MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\r\n" + "d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH\r\n" + "MjAeFw0yMDA3MjkxMjMwMDBaFw0yNDA2MjcyMzU5NTlaMFkxCzAJBgNVBAYTAlVT\r\n" + "MR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKjAoBgNVBAMTIU1pY3Jv\r\n" + "c29mdCBBenVyZSBUTFMgSXNzdWluZyBDQSAwMTCCAiIwDQYJKoZIhvcNAQEBBQAD\r\n" + "ggIPADCCAgoCggIBAMedcDrkXufP7pxVm1FHLDNA9IjwHaMoaY8arqqZ4Gff4xyr\r\n" + "RygnavXL7g12MPAx8Q6Dd9hfBzrfWxkF0Br2wIvlvkzW01naNVSkHp+OS3hL3W6n\r\n" + "l/jYvZnVeJXjtsKYcXIf/6WtspcF5awlQ9LZJcjwaH7KoZuK+THpXCMtzD8XNVdm\r\n" + "GW/JI0C/7U/E7evXn9XDio8SYkGSM63aLO5BtLCv092+1d4GGBSQYolRq+7Pd1kR\r\n" + "EkWBPm0ywZ2Vb8GIS5DLrjelEkBnKCyy3B0yQud9dpVsiUeE7F5sY8Me96WVxQcb\r\n" + "OyYdEY/j/9UpDlOG+vA+YgOvBhkKEjiqygVpP8EZoMMijephzg43b5Qi9r5UrvYo\r\n" + "o19oR/8pf4HJNDPF0/FJwFVMW8PmCBLGstin3NE1+NeWTkGt0TzpHjgKyfaDP2tO\r\n" + "4bCk1G7pP2kDFT7SYfc8xbgCkFQ2UCEXsaH/f5YmpLn4YPiNFCeeIida7xnfTvc4\r\n" + "7IxyVccHHq1FzGygOqemrxEETKh8hvDR6eBdrBwmCHVgZrnAqnn93JtGyPLi6+cj\r\n" + "WGVGtMZHwzVvX1HvSFG771sskcEjJxiQNQDQRWHEh3NxvNb7kFlAXnVdRkkvhjpR\r\n" + "GchFhTAzqmwltdWhWDEyCMKC2x/mSZvZtlZGY+g37Y72qHzidwtyW7rBetZJAgMB\r\n" + "AAGjggGtMIIBqTAdBgNVHQ4EFgQUDyBd16FXlduSzyvQx8J3BM5ygHYwHwYDVR0j\r\n" + "BBgwFoAUTiJUIBiV5uNu5g/6+rkS7QYXjzkwDgYDVR0PAQH/BAQDAgGGMB0GA1Ud\r\n" + "JQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjASBgNVHRMBAf8ECDAGAQH/AgEAMHYG\r\n" + "CCsGAQUFBwEBBGowaDAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQu\r\n" + "Y29tMEAGCCsGAQUFBzAChjRodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGln\r\n" + "aUNlcnRHbG9iYWxSb290RzIuY3J0MHsGA1UdHwR0MHIwN6A1oDOGMWh0dHA6Ly9j\r\n" + "cmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RHMi5jcmwwN6A1oDOG\r\n" + "MWh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RHMi5j\r\n" + "cmwwHQYDVR0gBBYwFDAIBgZngQwBAgEwCAYGZ4EMAQICMBAGCSsGAQQBgjcVAQQD\r\n" + "AgEAMA0GCSqGSIb3DQEBDAUAA4IBAQAlFvNh7QgXVLAZSsNR2XRmIn9iS8OHFCBA\r\n" + "WxKJoi8YYQafpMTkMqeuzoL3HWb1pYEipsDkhiMnrpfeYZEA7Lz7yqEEtfgHcEBs\r\n" + "K9KcStQGGZRfmWU07hPXHnFz+5gTXqzCE2PBMlRgVUYJiA25mJPXfB00gDvGhtYa\r\n" + "+mENwM9Bq1B9YYLyLjRtUz8cyGsdyTIG/bBM/Q9jcV8JGqMU/UjAdh1pFyTnnHEl\r\n" + "Y59Npi7F87ZqYYJEHJM2LGD+le8VsHjgeWX2CJQko7klXvcizuZvUEDTjHaQcs2J\r\n" + "+kPgfyMIOY1DMJ21NxOJ2xPRC/wAh/hzSBRVtoAnyuxtkZ4VjIOh\r\n" + "-----END CERTIFICATE-----\r\n"; + ``` + +1. Adiciona uma constante a este ficheiro para o URL de fala sem a localização. Este será combinado com a localização e o idioma mais tarde para obter o URL completo. + + ```cpp + const char *SPEECH_URL = "https://%s.stt.speech.microsoft.com/speech/recognition/conversation/cognitiveservices/v1?language=%s"; + ``` + +1. No ficheiro de cabeçalho `speech_to_text.h`, na secção `private` da classe `SpeechToText`, define um campo para um cliente WiFi usando o certificado de fala: + + ```cpp + WiFiClientSecure _speech_client; + ``` + +1. No método `init`, define o certificado neste cliente WiFi: + + ```cpp + _speech_client.setCACert(SPEECH_CERTIFICATE); + ``` + +1. Adiciona o seguinte código à secção `public` da classe `SpeechToText` para definir um método para converter fala em texto: + + ```cpp + String convertSpeechToText() + { + + } + ``` + +1. Adiciona o seguinte código a este método para criar um cliente HTTP usando o cliente WiFi configurado com o certificado de fala e usando o URL de fala definido com a localização e o idioma: + + ```cpp + char url[128]; + sprintf(url, SPEECH_URL, SPEECH_LOCATION, LANGUAGE); + + HTTPClient httpClient; + httpClient.begin(_speech_client, url); + ``` + +1. Alguns cabeçalhos precisam de ser definidos na conexão: + + ```cpp + httpClient.addHeader("Authorization", String("Bearer ") + _access_token); + httpClient.addHeader("Content-Type", String("audio/wav; codecs=audio/pcm; samplerate=") + String(RATE)); + httpClient.addHeader("Accept", "application/json;text/xml"); + ``` + + Isto define cabeçalhos para a autorização usando o token de acesso, o formato de áudio usando a taxa de amostragem e define que o cliente espera o resultado como JSON. + +1. Após isto, adiciona o seguinte código para fazer a chamada à API REST: + + ```cpp + Serial.println("Sending speech..."); + + FlashStream stream; + int httpResponseCode = httpClient.sendRequest("POST", &stream, BUFFER_SIZE); + + Serial.println("Speech sent!"); + ``` + + Isto cria um `FlashStream` e usa-o para transmitir dados para a API REST. + +1. Abaixo disto, adiciona o seguinte código: + + ```cpp + String text = ""; + + if (httpResponseCode == 200) + { + String result = httpClient.getString(); + Serial.println(result); + + DynamicJsonDocument doc(1024); + deserializeJson(doc, result.c_str()); + + JsonObject obj = doc.as(); + text = obj["DisplayText"].as(); + } + else if (httpResponseCode == 401) + { + Serial.println("Access token expired, trying again with a new token"); + _access_token = getAccessToken(); + return convertSpeechToText(); + } + else + { + Serial.print("Failed to convert text to speech - error "); + Serial.println(httpResponseCode); + } + ``` + + Este código verifica o código de resposta. + + Se for 200, o código para sucesso, então o resultado é recuperado, decodificado de JSON, e a propriedade `DisplayText` é definida na variável `text`. Esta é a propriedade onde a versão em texto da fala é retornada. + + Se o código de resposta for 401, então o token de acesso expirou (estes tokens só duram 10 minutos). Um novo token de acesso é solicitado e a chamada é feita novamente. + + Caso contrário, um erro é enviado ao monitor serial e o `text` é deixado em branco. + +1. Adiciona o seguinte código ao final deste método para fechar o cliente HTTP e retornar o texto: + + ```cpp + httpClient.end(); + + return text; + ``` + +1. Em `main.cpp`, chama este novo método `convertSpeechToText` na função `processAudio`, depois regista a fala no monitor serial: + + ```cpp + String text = speechToText.convertSpeechToText(); + Serial.println(text); + ``` + +1. Compila este código, carrega-o no teu Wio Terminal e testa-o através do monitor serial. Assim que vires `Ready` no monitor serial, pressiona o botão C (o que está do lado esquerdo, mais próximo do interruptor de energia) e fala. Serão capturados 4 segundos de áudio, que serão convertidos em texto. + + ```output + --- Available filters and text transformations: colorize, debug, default, direct, hexlify, log2file, nocontrol, printable, send_on_enter, time + --- More details at http://bit.ly/pio-monitor-filters + --- Miniterm on /dev/cu.usbmodem1101 9600,8,N,1 --- + --- Quit: Ctrl+C | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H --- + Connecting to WiFi.. + Connected! + Got access token. + Ready. + Starting recording... + Finished recording + Sending speech... + Speech sent! + {"RecognitionStatus":"Success","DisplayText":"Set a 2 minute and 27 second timer.","Offset":4700000,"Duration":35300000} + Set a 2 minute and 27 second timer. + ``` + +> 💁 Podes encontrar este código na pasta [code-speech-to-text/wio-terminal](../../../../../6-consumer/lessons/1-speech-recognition/code-speech-to-text/wio-terminal). + +😀 O teu programa de fala para texto foi um sucesso! + +**Aviso Legal**: +Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, é importante notar que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes do uso desta tradução. \ No newline at end of file diff --git a/translations/pt-PT/6-consumer/lessons/2-language-understanding/README.md b/translations/pt-PT/6-consumer/lessons/2-language-understanding/README.md new file mode 100644 index 000000000..21da63980 --- /dev/null +++ b/translations/pt-PT/6-consumer/lessons/2-language-understanding/README.md @@ -0,0 +1,563 @@ +# Compreender a linguagem + +![Uma visão geral ilustrada desta lição](../../../../../translated_images/pt-PT/lesson-22.6148ea28500d9e00c396aaa2649935fb6641362c8f03d8e5e90a676977ab01dd.jpg) + +> Ilustração por [Nitya Narasimhan](https://github.com/nitya). Clique na imagem para uma versão maior. + +## Questionário pré-aula + +[Questionário pré-aula](https://black-meadow-040d15503.1.azurestaticapps.net/quiz/43) + +## Introdução + +Na última lição, converteste fala em texto. Para que isso seja usado para programar um temporizador inteligente, o teu código precisará de compreender o que foi dito. Poderias assumir que o utilizador dirá uma frase fixa, como "Definir um temporizador de 3 minutos", e analisar essa expressão para determinar a duração do temporizador. No entanto, isso não é muito prático para o utilizador. Se um utilizador disser "Definir um temporizador para 3 minutos", tu ou eu entenderíamos o que ele quer dizer, mas o teu código não, pois estaria à espera de uma frase fixa. + +É aqui que entra a compreensão da linguagem, utilizando modelos de IA para interpretar texto e devolver os detalhes necessários. Por exemplo, ser capaz de interpretar tanto "Definir um temporizador de 3 minutos" como "Definir um temporizador para 3 minutos" e compreender que é necessário um temporizador de 3 minutos. + +Nesta lição, vais aprender sobre modelos de compreensão da linguagem, como criá-los, treiná-los e utilizá-los no teu código. + +Nesta lição, abordaremos: + +* [Compreensão da linguagem](../../../../../6-consumer/lessons/2-language-understanding) +* [Criar um modelo de compreensão da linguagem](../../../../../6-consumer/lessons/2-language-understanding) +* [Intenções e entidades](../../../../../6-consumer/lessons/2-language-understanding) +* [Utilizar o modelo de compreensão da linguagem](../../../../../6-consumer/lessons/2-language-understanding) + +## Compreensão da linguagem + +Os humanos utilizam a linguagem para comunicar há centenas de milhares de anos. Comunicamos com palavras, sons ou ações e entendemos o que é dito, tanto o significado das palavras, sons ou ações, como também o seu contexto. Entendemos sinceridade e sarcasmo, permitindo que as mesmas palavras tenham significados diferentes dependendo do tom da nossa voz. + +✅ Pensa em algumas das conversas que tiveste recentemente. Quanto dessa conversa seria difícil para um computador entender porque necessita de contexto? + +A compreensão da linguagem, também chamada de compreensão de linguagem natural, faz parte de um campo da inteligência artificial chamado processamento de linguagem natural (ou NLP) e lida com a compreensão de leitura, tentando entender os detalhes das palavras ou frases. Se utilizas um assistente de voz como Alexa ou Siri, já utilizaste serviços de compreensão da linguagem. Estes são os serviços de IA nos bastidores que convertem "Alexa, toca o último álbum da Taylor Swift" na minha filha a dançar pela sala ao som das suas músicas favoritas. + +> 💁 Os computadores, apesar de todos os seus avanços, ainda têm um longo caminho a percorrer para realmente entender texto. Quando nos referimos à compreensão da linguagem com computadores, não queremos dizer algo remotamente tão avançado quanto a comunicação humana. Em vez disso, referimo-nos a pegar em algumas palavras e extrair detalhes importantes. + +Como humanos, entendemos a linguagem sem realmente pensar sobre isso. Se eu pedisse a outro humano para "tocar o último álbum da Taylor Swift", ele saberia instintivamente o que eu quis dizer. Para um computador, isso é mais difícil. Ele teria que pegar nas palavras, convertidas de fala para texto, e determinar as seguintes informações: + +* É necessário tocar música +* A música é da artista Taylor Swift +* A música específica é um álbum inteiro com várias faixas em ordem +* Taylor Swift tem muitos álbuns, então eles precisam ser ordenados cronologicamente e o mais recentemente publicado é o que é necessário + +✅ Pensa em algumas outras frases que disseste ao fazer pedidos, como encomendar café ou pedir a um familiar para te passar algo. Tenta dividi-las nas informações que um computador precisaria extrair para entender a frase. + +Os modelos de compreensão da linguagem são modelos de IA que são treinados para extrair certos detalhes da linguagem e, em seguida, são treinados para tarefas específicas usando aprendizagem por transferência, da mesma forma que treinaste um modelo de Visão Personalizada usando um pequeno conjunto de imagens. Podes pegar num modelo e treiná-lo usando o texto que queres que ele entenda. + +## Criar um modelo de compreensão da linguagem + +![O logótipo do LUIS](../../../../../translated_images/pt-PT/luis-logo.5cb4f3e88c020ee6df4f614e8831f4a4b6809a7247bf52085fb48d629ef9be52.png) + +Podes criar modelos de compreensão da linguagem usando o LUIS, um serviço de compreensão da linguagem da Microsoft que faz parte dos Serviços Cognitivos. + +### Tarefa - criar um recurso de autoria + +Para usar o LUIS, precisas de criar um recurso de autoria. + +1. Usa o seguinte comando para criar um recurso de autoria no teu grupo de recursos `smart-timer`: + + ```python + az cognitiveservices account create --name smart-timer-luis-authoring \ + --resource-group smart-timer \ + --kind LUIS.Authoring \ + --sku F0 \ + --yes \ + --location + ``` + + Substitui `` pela localização que utilizaste ao criar o Grupo de Recursos. + + > ⚠️ O LUIS não está disponível em todas as regiões, então, se receberes o seguinte erro: + > + > ```output + > InvalidApiSetId: The account type 'LUIS.Authoring' is either invalid or unavailable in given region. + > ``` + > + > escolhe uma região diferente. + + Isto criará um recurso de autoria do LUIS na camada gratuita. + +### Tarefa - criar uma aplicação de compreensão da linguagem + +1. Abre o portal do LUIS em [luis.ai](https://luis.ai?WT.mc_id=academic-17441-jabenn) no teu navegador e inicia sessão com a mesma conta que tens usado para o Azure. + +1. Segue as instruções no diálogo para selecionar a tua subscrição do Azure e, em seguida, seleciona o recurso `smart-timer-luis-authoring` que acabaste de criar. + +1. Na lista *Aplicações de Conversação*, seleciona o botão **Nova aplicação** para criar uma nova aplicação. Nomeia a nova aplicação como `smart-timer` e define a *Cultura* para a tua língua. + + > 💁 Há um campo para um recurso de previsão. Podes criar um segundo recurso apenas para previsão, mas o recurso de autoria gratuito permite 1.000 previsões por mês, o que deve ser suficiente para desenvolvimento, então podes deixar este campo em branco. + +1. Lê o guia que aparece assim que crias a aplicação para entender os passos que precisas de seguir para treinar o modelo de compreensão da linguagem. Fecha este guia quando terminares. + +## Intenções e entidades + +A compreensão da linguagem baseia-se em *intenções* e *entidades*. Intenções são o objetivo das palavras, por exemplo, tocar música, definir um temporizador ou encomendar comida. Entidades são aquilo a que a intenção se refere, como o álbum, a duração do temporizador ou o tipo de comida. Cada frase que o modelo interpreta deve ter pelo menos uma intenção e, opcionalmente, uma ou mais entidades. + +Alguns exemplos: + +| Frase | Intenção | Entidades | +| -------------------------------------------------- | ---------------- | ------------------------------------------ | +| "Tocar o último álbum da Taylor Swift" | *tocar música* | *o último álbum da Taylor Swift* | +| "Definir um temporizador de 3 minutos" | *definir temporizador* | *3 minutos* | +| "Cancelar o meu temporizador" | *cancelar temporizador* | Nenhuma | +| "Encomendar 3 pizzas grandes de ananás e uma salada caesar" | *encomendar comida* | *3 pizzas grandes de ananás*, *salada caesar* | + +✅ Com as frases que pensaste anteriormente, qual seria a intenção e as entidades dessa frase? + +Para treinar o LUIS, primeiro defines as entidades. Estas podem ser uma lista fixa de termos ou aprendidas a partir do texto. Por exemplo, poderias fornecer uma lista fixa de alimentos disponíveis no teu menu, com variações (ou sinónimos) de cada palavra, como *beringela* e *aubergine* como variações de *beringela*. O LUIS também tem entidades pré-construídas que podem ser usadas, como números e localizações. + +Para definir um temporizador, poderias ter uma entidade usando as entidades pré-construídas de número para o tempo e outra para as unidades, como minutos e segundos. Cada unidade teria múltiplas variações para cobrir as formas singular e plural - como minuto e minutos. + +Depois de definir as entidades, crias intenções. Estas são aprendidas pelo modelo com base em frases de exemplo que forneces (conhecidas como enunciados). Por exemplo, para uma intenção *definir temporizador*, poderias fornecer as seguintes frases: + +* `definir um temporizador de 1 segundo` +* `definir um temporizador para 1 minuto e 12 segundos` +* `definir um temporizador para 3 minutos` +* `definir um temporizador de 9 minutos e 30 segundos` + +Depois, indicas ao LUIS quais partes dessas frases correspondem às entidades: + +![A frase definir um temporizador para 1 minuto e 12 segundos dividida em entidades](../../../../../translated_images/pt-PT/sentence-as-intent-entities.301401696f992259.webp) + +A frase `definir um temporizador para 1 minuto e 12 segundos` tem a intenção de `definir temporizador`. Também tem 2 entidades com 2 valores cada: + +| | tempo | unidade | +| ---------- | ---: | --------- | +| 1 minuto | 1 | minuto | +| 12 segundos | 12 | segundo | + +Para treinar um bom modelo, precisas de uma variedade de frases de exemplo diferentes para cobrir as muitas formas como alguém pode pedir a mesma coisa. + +> 💁 Como acontece com qualquer modelo de IA, quanto mais dados e mais precisos forem os dados que usares para treinar, melhor será o modelo. + +✅ Pensa nas diferentes formas como poderias pedir a mesma coisa e esperar que um humano entendesse. + +### Tarefa - adicionar entidades aos modelos de compreensão da linguagem + +Para o temporizador, precisas de adicionar 2 entidades - uma para a unidade de tempo (minutos ou segundos) e outra para o número de minutos ou segundos. + +Podes encontrar instruções para usar o portal do LUIS na [Documentação de Introdução: Criar a tua aplicação no portal do LUIS na Microsoft Docs](https://docs.microsoft.com/azure/cognitive-services/luis/luis-get-started-create-app?WT.mc_id=academic-17441-jabenn). + +1. No portal do LUIS, seleciona o separador *Entidades* e adiciona a entidade pré-construída *número* selecionando o botão **Adicionar entidade pré-construída** e, em seguida, selecionando *número* da lista. + +1. Cria uma nova entidade para a unidade de tempo usando o botão **Criar**. Nomeia a entidade como `unidade de tempo` e define o tipo como *Lista*. Adiciona valores para `minuto` e `segundo` à lista de *Valores normalizados*, adicionando as formas singular e plural à lista de *sinónimos*. Pressiona `enter` após adicionar cada sinónimo para o adicionar à lista. + + | Valor normalizado | Sinónimos | + | ----------------- | ---------------- | + | minuto | minuto, minutos | + | segundo | segundo, segundos | + +### Tarefa - adicionar intenções aos modelos de compreensão da linguagem + +1. No separador *Intenções*, seleciona o botão **Criar** para criar uma nova intenção. Nomeia esta intenção como `definir temporizador`. + +1. Nos exemplos, insere diferentes formas de definir um temporizador usando minutos, segundos e minutos e segundos combinados. Exemplos podem ser: + + * `definir um temporizador de 1 segundo` + * `definir um temporizador de 4 minutos` + * `definir um temporizador de quatro minutos e seis segundos` + * `definir um temporizador de 9 minutos e 30 segundos` + * `definir um temporizador para 1 minuto e 12 segundos` + * `definir um temporizador para 3 minutos` + * `definir um temporizador para 3 minutos e 1 segundo` + * `definir um temporizador para três minutos e um segundo` + * `definir um temporizador para 1 minuto e 1 segundo` + * `definir um temporizador para 30 segundos` + * `definir um temporizador para 1 segundo` + + Mistura números como palavras e números para que o modelo aprenda a lidar com ambos. + +1. À medida que inseres cada exemplo, o LUIS começará a detetar entidades e sublinhará e etiquetará qualquer uma que encontrar. + + ![Os exemplos com os números e unidades de tempo sublinhados pelo LUIS](../../../../../translated_images/pt-PT/luis-intent-examples.25716580b2d2723cf1bafdf277d015c7f046d8cfa20f27bddf3a0873ec45fab7.png) + +### Tarefa - treinar e testar o modelo + +1. Depois de configurar as entidades e intenções, podes treinar o modelo usando o botão **Treinar** no menu superior. Seleciona este botão e o modelo deve treinar em alguns segundos. O botão ficará desativado enquanto treina e será reativado quando terminar. + +1. Seleciona o botão **Testar** no menu superior para testar o modelo de compreensão da linguagem. Insere texto como `definir um temporizador para 5 minutos e 4 segundos` e pressiona enter. A frase aparecerá numa caixa abaixo da caixa de texto onde a escreveste e, abaixo disso, estará a *intenção principal*, ou seja, a intenção detetada com a maior probabilidade. Esta deve ser `definir temporizador`. O nome da intenção será seguido pela probabilidade de que a intenção detetada seja a correta. + +1. Seleciona a opção **Inspecionar** para ver uma análise detalhada dos resultados. Verás a intenção com maior pontuação e a sua probabilidade percentual, juntamente com listas das entidades detetadas. + +1. Fecha o painel *Testar* quando terminares de testar. + +### Tarefa - publicar o modelo + +Para usar este modelo no código, precisas de publicá-lo. Ao publicar no LUIS, podes publicar num ambiente de teste ou num ambiente de produção para um lançamento completo. Nesta lição, um ambiente de teste é suficiente. + +1. No portal do LUIS, seleciona o botão **Publicar** no menu superior. + +1. Certifica-te de que o *Slot de teste* está selecionado e, em seguida, seleciona **Concluído**. Verás uma notificação quando a aplicação for publicada. + +1. Podes testar isto usando curl. Para construir o comando curl, precisas de três valores - o endpoint, o ID da aplicação (App ID) e uma chave de API. Estes podem ser acessados na aba **GERIR** que pode ser selecionada no menu superior. + + 1. Na secção *Configurações*, copia o App ID +1. Na secção *Azure Resources*, selecione *Authoring Resource* e copie a *Primary Key* e o *Endpoint URL*. + +1. Execute o seguinte comando curl no seu prompt de comando ou terminal: + + ```sh + curl "/luis/prediction/v3.0/apps//slots/staging/predict" \ + --request GET \ + --get \ + --data "subscription-key=" \ + --data "verbose=false" \ + --data "show-all-intents=true" \ + --data-urlencode "query=" + ``` + + Substitua `` pelo Endpoint URL da secção *Azure Resources*. + + Substitua `` pelo App ID da secção *Settings*. + + Substitua `` pela Primary Key da secção *Azure Resources*. + + Substitua `` pela frase que deseja testar. + +1. O resultado desta chamada será um documento JSON que detalha a consulta, a intenção principal e uma lista de entidades divididas por tipo. + + ```JSON + { + "query": "set a timer for 45 minutes and 12 seconds", + "prediction": { + "topIntent": "set timer", + "intents": { + "set timer": { + "score": 0.97031575 + }, + "None": { + "score": 0.02205793 + } + }, + "entities": { + "number": [ + 45, + 12 + ], + "time-unit": [ + [ + "minute" + ], + [ + "second" + ] + ] + } + } + } + ``` + + O JSON acima foi gerado ao consultar com `set a timer for 45 minutes and 12 seconds`: + + * A intenção principal foi `set timer` com uma probabilidade de 97%. + * Foram detetadas duas entidades do tipo *number*, `45` e `12`. + * Foram detetadas duas entidades do tipo *time-unit*, `minute` e `second`. + +## Utilizar o modelo de compreensão de linguagem + +Depois de publicado, o modelo LUIS pode ser chamado a partir de código. Em lições anteriores, utilizou um IoT Hub para gerir a comunicação com serviços na nuvem, enviando telemetria e ouvindo comandos. Este processo é muito assíncrono - uma vez enviada a telemetria, o código não espera por uma resposta, e se o serviço na nuvem estiver indisponível, não será informado. + +Para um temporizador inteligente, queremos uma resposta imediata, para que possamos informar o utilizador que o temporizador foi configurado ou alertá-lo de que os serviços na nuvem estão indisponíveis. Para isso, o dispositivo IoT chamará diretamente um endpoint web, em vez de depender de um IoT Hub. + +Em vez de chamar o LUIS diretamente do dispositivo IoT, pode usar código serverless com um tipo diferente de trigger - um trigger HTTP. Isto permite que a sua aplicação de funções ouça pedidos REST e responda a eles. Esta função será um endpoint REST que o seu dispositivo pode chamar. + +> 💁 Embora seja possível chamar o LUIS diretamente do dispositivo IoT, é preferível usar algo como código serverless. Desta forma, quando quiser alterar a aplicação LUIS que está a chamar, por exemplo, ao treinar um modelo melhor ou um modelo numa língua diferente, só precisará de atualizar o código na nuvem, sem ter de reimplementar o código em milhares ou milhões de dispositivos IoT. + +### Tarefa - criar uma aplicação de funções serverless + +1. Crie uma aplicação de funções Azure chamada `smart-timer-trigger` e abra-a no VS Code. + +1. Adicione um trigger HTTP a esta aplicação chamado `speech-trigger` usando o seguinte comando no terminal do VS Code: + + ```sh + func new --name text-to-timer --template "HTTP trigger" + ``` + + Isto criará um trigger HTTP chamado `text-to-timer`. + +1. Teste o trigger HTTP executando a aplicação de funções. Quando esta for executada, verá o endpoint listado na saída: + + ```output + Functions: + + text-to-timer: [GET,POST] http://localhost:7071/api/text-to-timer + ``` + + Teste isto carregando o URL [http://localhost:7071/api/text-to-timer](http://localhost:7071/api/text-to-timer) no seu navegador. + + ```output + This HTTP triggered function executed successfully. Pass a name in the query string or in the request body for a personalized response. + ``` + +### Tarefa - utilizar o modelo de compreensão de linguagem + +1. O SDK para LUIS está disponível através de um pacote Pip. Adicione a seguinte linha ao ficheiro `requirements.txt` para adicionar a dependência deste pacote: + + ```sh + azure-cognitiveservices-language-luis + ``` + +1. Certifique-se de que o terminal do VS Code tem o ambiente virtual ativado e execute o seguinte comando para instalar os pacotes Pip: + + ```sh + pip install -r requirements.txt + ``` + + > 💁 Se encontrar erros, pode ser necessário atualizar o pip com o seguinte comando: + > + > ```sh + > pip install --upgrade pip + > ``` + +1. Adicione novas entradas ao ficheiro `local.settings.json` para a sua LUIS API Key, Endpoint URL e App ID da aba **MANAGE** do portal LUIS: + + ```JSON + "LUIS_KEY": "", + "LUIS_ENDPOINT_URL": "", + "LUIS_APP_ID": "" + ``` + + Substitua `` pelo Endpoint URL da secção *Azure Resources* da aba **MANAGE**. Este será `https://.api.cognitive.microsoft.com/`. + + Substitua `` pelo App ID da secção *Settings* da aba **MANAGE**. + + Substitua `` pela Primary Key da secção *Azure Resources* da aba **MANAGE**. + +1. Adicione as seguintes importações ao ficheiro `__init__.py`: + + ```python + import json + import os + from azure.cognitiveservices.language.luis.runtime import LUISRuntimeClient + from msrest.authentication import CognitiveServicesCredentials + ``` + + Isto importa algumas bibliotecas do sistema, bem como as bibliotecas para interagir com o LUIS. + +1. Apague o conteúdo do método `main` e adicione o seguinte código: + + ```python + luis_key = os.environ['LUIS_KEY'] + endpoint_url = os.environ['LUIS_ENDPOINT_URL'] + app_id = os.environ['LUIS_APP_ID'] + + credentials = CognitiveServicesCredentials(luis_key) + client = LUISRuntimeClient(endpoint=endpoint_url, credentials=credentials) + ``` + + Este código carrega os valores que adicionou ao ficheiro `local.settings.json` para a sua aplicação LUIS, cria um objeto de credenciais com a sua API key e, em seguida, cria um cliente LUIS para interagir com a sua aplicação LUIS. + +1. Este trigger HTTP será chamado passando o texto a ser compreendido como JSON, com o texto numa propriedade chamada `text`. O seguinte código extrai o valor do corpo do pedido HTTP e regista-o no console. Adicione este código à função `main`: + + ```python + req_body = req.get_json() + text = req_body['text'] + logging.info(f'Request - {text}') + ``` + +1. As previsões são solicitadas ao LUIS enviando um pedido de previsão - um documento JSON contendo o texto a prever. Crie este pedido com o seguinte código: + + ```python + prediction_request = { 'query' : text } + ``` + +1. Este pedido pode então ser enviado ao LUIS, utilizando o slot de staging para o qual a sua aplicação foi publicada: + + ```python + prediction_response = client.prediction.get_slot_prediction(app_id, 'Staging', prediction_request) + ``` + +1. A resposta de previsão contém a intenção principal - a intenção com a maior pontuação de previsão, juntamente com as entidades. Se a intenção principal for `set timer`, então as entidades podem ser lidas para obter o tempo necessário para o temporizador: + + ```python + if prediction_response.prediction.top_intent == 'set timer': + numbers = prediction_response.prediction.entities['number'] + time_units = prediction_response.prediction.entities['time unit'] + total_seconds = 0 + ``` + + As entidades do tipo `number` serão um array de números. Por exemplo, se disser *"Set a four minute 17 second timer."*, o array `number` conterá 2 inteiros - 4 e 17. + + As entidades do tipo `time unit` serão um array de arrays de strings, com cada unidade de tempo como um array de strings dentro do array. Por exemplo, se disser *"Set a four minute 17 second timer."*, o array `time unit` conterá 2 arrays com valores únicos - `['minute']` e `['second']`. + + A versão JSON destas entidades para *"Set a four minute 17 second timer."* é: + + ```json + { + "number": [4, 17], + "time unit": [ + ["minute"], + ["second"] + ] + } + ``` + + Este código também define uma contagem para o tempo total do temporizador em segundos. Este será preenchido pelos valores das entidades. + +1. As entidades não estão ligadas, mas podemos fazer algumas suposições sobre elas. Estarão na ordem em que foram ditas, então a posição no array pode ser usada para determinar qual número corresponde a qual unidade de tempo. Por exemplo: + + * *"Set a 30 second timer"* - terá um número, `30`, e uma unidade de tempo, `second`, então o único número corresponderá à única unidade de tempo. + * *"Set a 2 minute and 30 second timer"* - terá dois números, `2` e `30`, e duas unidades de tempo, `minute` e `second`, então o primeiro número será para a primeira unidade de tempo (2 minutos) e o segundo número para a segunda unidade de tempo (30 segundos). + + O seguinte código obtém a contagem de itens nas entidades do tipo número e usa isso para extrair o primeiro item de cada array, depois o segundo e assim por diante. Adicione isto dentro do bloco `if`. + + ```python + for i in range(0, len(numbers)): + number = numbers[i] + time_unit = time_units[i][0] + ``` + + Para *"Set a four minute 17 second timer."*, este código fará duas iterações, dando os seguintes valores: + + | contagem de loop | `number` | `time_unit` | + | ----------------: | -------: | ----------- | + | 0 | 4 | minute | + | 1 | 17 | second | + +1. Dentro deste loop, use o número e a unidade de tempo para calcular o tempo total do temporizador, adicionando 60 segundos para cada minuto e o número de segundos para quaisquer segundos. + + ```python + if time_unit == 'minute': + total_seconds += number * 60 + else: + total_seconds += number + ``` + +1. Fora deste loop pelas entidades, registe o tempo total do temporizador: + + ```python + logging.info(f'Timer required for {total_seconds} seconds') + ``` + +1. O número de segundos precisa de ser retornado pela função como uma resposta HTTP. No final do bloco `if`, adicione o seguinte: + + ```python + payload = { + 'seconds': total_seconds + } + return func.HttpResponse(json.dumps(payload), status_code=200) + ``` + + Este código cria um payload contendo o número total de segundos para o temporizador, converte-o numa string JSON e retorna-o como um resultado HTTP com um código de status 200, o que significa que a chamada foi bem-sucedida. + +1. Finalmente, fora do bloco `if`, trate o caso em que a intenção não foi reconhecida retornando um código de erro: + + ```python + return func.HttpResponse(status_code=404) + ``` + + 404 é o código de status para *não encontrado*. + +1. Execute a aplicação de funções e teste-a usando curl. + + ```sh + curl --request POST 'http://localhost:7071/api/text-to-timer' \ + --header 'Content-Type: application/json' \ + --include \ + --data '{"text":""}' + ``` + + Substitua `` pelo texto do seu pedido, por exemplo `set a 2 minutes 27 second timer`. + + Verá a seguinte saída da aplicação de funções: + + ```output + Functions: + + text-to-timer: [GET,POST] http://localhost:7071/api/text-to-timer + + For detailed output, run func with --verbose flag. + [2021-06-26T19:45:14.502Z] Worker process started and initialized. + [2021-06-26T19:45:19.338Z] Host lock lease acquired by instance ID '000000000000000000000000951CAE4E'. + [2021-06-26T19:45:52.059Z] Executing 'Functions.text-to-timer' (Reason='This function was programmatically called via the host APIs.', Id=f68bfb90-30e4-47a5-99da-126b66218e81) + [2021-06-26T19:45:53.577Z] Timer required for 147 seconds + [2021-06-26T19:45:53.746Z] Executed 'Functions.text-to-timer' (Succeeded, Id=f68bfb90-30e4-47a5-99da-126b66218e81, Duration=1750ms) + ``` + + A chamada ao curl retornará o seguinte: + + ```output + HTTP/1.1 200 OK + Date: Tue, 29 Jun 2021 01:14:11 GMT + Content-Type: text/plain; charset=utf-8 + Server: Kestrel + Transfer-Encoding: chunked + + {"seconds": 147} + ``` + + O número de segundos para o temporizador estará no valor `"seconds"`. + +> 💁 Pode encontrar este código na pasta [code/functions](../../../../../6-consumer/lessons/2-language-understanding/code/functions). + +### Tarefa - tornar a sua função acessível ao seu dispositivo IoT + +1. Para que o seu dispositivo IoT chame o seu endpoint REST, precisará de saber o URL. Quando o acedeu anteriormente, utilizou `localhost`, que é um atalho para aceder a endpoints REST na sua máquina local. Para permitir que o dispositivo IoT aceda, precisará de publicar na nuvem ou obter o endereço IP para aceder localmente. + + > ⚠️ Se estiver a usar um Wio Terminal, é mais fácil executar a aplicação de funções localmente, pois haverá uma dependência de bibliotecas que significa que não poderá implementar a aplicação de funções da mesma forma que fez anteriormente. Execute a aplicação de funções localmente e aceda-a através do endereço IP do seu computador. Se quiser implementar na nuvem, informações serão fornecidas numa lição posterior sobre como fazê-lo. + + * Publique a aplicação de funções - siga as instruções das lições anteriores para publicar a sua aplicação de funções na nuvem. Uma vez publicada, o URL será `https://.azurewebsites.net/api/text-to-timer`, onde `` será o nome da sua aplicação de funções. Certifique-se também de publicar as suas configurações locais. + + Ao trabalhar com triggers HTTP, estes são protegidos por padrão com uma chave de aplicação de funções. Para obter esta chave, execute o seguinte comando: + + ```sh + az functionapp keys list --resource-group smart-timer \ + --name + ``` + + Copie o valor da entrada `default` da secção `functionKeys`. + + ```output + { + "functionKeys": { + "default": "sQO1LQaeK9N1qYD6SXeb/TctCmwQEkToLJU6Dw8TthNeUH8VA45hlA==" + }, + "masterKey": "RSKOAIlyvvQEQt9dfpabJT018scaLpQu9p1poHIMCxx5LYrIQZyQ/g==", + "systemKeys": {} + } + ``` + + Esta chave precisará de ser adicionada como um parâmetro de consulta ao URL, então o URL final será `https://.azurewebsites.net/api/text-to-timer?code=`, onde `` será o nome da sua aplicação de funções e `` será a sua chave de função padrão. + + > 💁 Pode alterar o tipo de autorização do trigger HTTP usando a configuração `authlevel` no ficheiro `function.json`. Pode ler mais sobre isto na [secção de configuração da documentação do trigger HTTP das Azure Functions nos documentos da Microsoft](https://docs.microsoft.com/azure/azure-functions/functions-bindings-http-webhook-trigger?WT.mc_id=academic-17441-jabenn&tabs=python#configuration). + + * Execute a aplicação de funções localmente e aceda usando o endereço IP - pode obter o endereço IP do seu computador na rede local e usá-lo para construir o URL. + + Encontre o seu endereço IP: + + * No Windows 10, siga o [guia para encontrar o seu endereço IP](https://support.microsoft.com/windows/find-your-ip-address-f21a9bbc-c582-55cd-35e0-73431160a1b9?WT.mc_id=academic-17441-jabenn). + * No macOS, siga o [guia para encontrar o endereço IP num Mac](https://www.hellotech.com/guide/for/how-to-find-ip-address-on-mac). + * No Linux, siga a secção sobre encontrar o endereço IP privado no [guia para encontrar o endereço IP no Linux](https://opensource.com/article/18/5/how-find-ip-address-linux). + + Uma vez que tenha o seu endereço IP, poderá aceder à função em `http://`. + +:7071/api/text-to-timer`, onde `` será o endereço IP, por exemplo, `http://192.168.1.10:7071/api/text-to-timer`. + + > 💁 Note que isto utiliza a porta 7071, por isso, após o endereço IP, será necessário incluir `:7071`. + + > 💁 Isto só funcionará se o seu dispositivo IoT estiver na mesma rede que o seu computador. + +1. Teste o endpoint acedendo a ele utilizando o curl. + +--- + +## 🚀 Desafio + +Existem várias formas de pedir a mesma coisa, como configurar um temporizador. Pense em diferentes maneiras de fazer isso e use-as como exemplos na sua aplicação LUIS. Teste estas formas para ver como o seu modelo lida com múltiplas maneiras de solicitar um temporizador. + +## Questionário pós-aula + +[Questionário pós-aula](https://black-meadow-040d15503.1.azurestaticapps.net/quiz/44) + +## Revisão e Estudo Individual + +* Leia mais sobre o LUIS e as suas capacidades na [página de documentação do Language Understanding (LUIS) na Microsoft Docs](https://docs.microsoft.com/azure/cognitive-services/luis/?WT.mc_id=academic-17441-jabenn) +* Leia mais sobre compreensão de linguagem na [página de compreensão de linguagem natural na Wikipédia](https://wikipedia.org/wiki/Natural-language_understanding) +* Leia mais sobre triggers HTTP na [documentação de triggers HTTP do Azure Functions na Microsoft Docs](https://docs.microsoft.com/azure/azure-functions/functions-bindings-http-webhook-trigger?WT.mc_id=academic-17441-jabenn&tabs=python) + +## Tarefa + +[Cancelar o temporizador](assignment.md) + +**Aviso Legal**: +Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos pela precisão, tenha em atenção que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se uma tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes da utilização desta tradução. \ No newline at end of file diff --git a/translations/pt-PT/6-consumer/lessons/2-language-understanding/assignment.md b/translations/pt-PT/6-consumer/lessons/2-language-understanding/assignment.md new file mode 100644 index 000000000..4e31f092a --- /dev/null +++ b/translations/pt-PT/6-consumer/lessons/2-language-understanding/assignment.md @@ -0,0 +1,17 @@ +# Cancelar o temporizador + +## Instruções + +Até agora nesta lição, treinaste um modelo para compreender como definir um temporizador. Outra funcionalidade útil é cancelar um temporizador - talvez o teu pão já esteja pronto e possa ser retirado do forno antes que o temporizador termine. + +Adiciona uma nova intenção à tua aplicação LUIS para cancelar o temporizador. Não será necessário usar entidades, mas precisarás de algumas frases de exemplo. Trata disso no teu código serverless se for a intenção principal, registando que a intenção foi reconhecida e devolvendo uma resposta apropriada. + +## Critérios de Avaliação + +| Critério | Exemplar | Adequado | Precisa de Melhorias | +| -------- | --------- | -------- | -------------------- | +| Adicionar a intenção de cancelar o temporizador à aplicação LUIS | Conseguiu adicionar a intenção e treinar o modelo | Conseguiu adicionar a intenção, mas não treinar o modelo | Não conseguiu adicionar a intenção nem treinar o modelo | +| Tratar a intenção na aplicação serverless | Conseguiu detetar a intenção como a principal e registá-la | Conseguiu detetar a intenção como a principal | Não conseguiu detetar a intenção como a principal | + +**Aviso Legal**: +Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos pela precisão, esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes do uso desta tradução. \ No newline at end of file diff --git a/translations/pt-PT/6-consumer/lessons/3-spoken-feedback/README.md b/translations/pt-PT/6-consumer/lessons/3-spoken-feedback/README.md new file mode 100644 index 000000000..74bfc9f38 --- /dev/null +++ b/translations/pt-PT/6-consumer/lessons/3-spoken-feedback/README.md @@ -0,0 +1,131 @@ +# Definir um temporizador e fornecer feedback falado + +![Uma visão geral ilustrada desta lição](../../../../../translated_images/pt-PT/lesson-23.f38483e1d4df4828990d3f02d60e46c978b075d384ae7cb4f7bab738e107c850.jpg) + +> Ilustração por [Nitya Narasimhan](https://github.com/nitya). Clique na imagem para uma versão maior. + +## Questionário pré-aula + +[Questionário pré-aula](https://black-meadow-040d15503.1.azurestaticapps.net/quiz/45) + +## Introdução + +Assistentes inteligentes não são dispositivos de comunicação unidirecional. Você fala com eles, e eles respondem: + +"Alexa, define um temporizador de 3 minutos" + +"Ok, o seu temporizador foi definido para 3 minutos" + +Nas últimas 2 lições, aprendeste como transformar fala em texto e, em seguida, extrair um pedido de temporizador desse texto. Nesta lição, vais aprender como definir o temporizador no dispositivo IoT, responder ao utilizador com palavras faladas confirmando o temporizador e alertá-lo quando o temporizador terminar. + +Nesta lição, vamos abordar: + +* [Texto para fala](../../../../../6-consumer/lessons/3-spoken-feedback) +* [Definir o temporizador](../../../../../6-consumer/lessons/3-spoken-feedback) +* [Converter texto em fala](../../../../../6-consumer/lessons/3-spoken-feedback) + +## Texto para fala + +Texto para fala, como o nome sugere, é o processo de converter texto em áudio que contém as palavras faladas. O princípio básico é decompor as palavras do texto nos seus sons constituintes (conhecidos como fonemas) e juntar áudio para esses sons, seja usando áudio pré-gravado ou áudio gerado por modelos de IA. + +![As três etapas típicas dos sistemas de texto para fala](../../../../../translated_images/pt-PT/tts-overview.193843cf3f5ee09f.webp) + +Os sistemas de texto para fala geralmente têm 3 etapas: + +* Análise de texto +* Análise linguística +* Geração de forma de onda + +### Análise de texto + +A análise de texto envolve pegar no texto fornecido e convertê-lo em palavras que podem ser usadas para gerar fala. Por exemplo, se converteres "Olá mundo", não há necessidade de análise de texto, as duas palavras podem ser convertidas diretamente em fala. Se tiveres "1234", no entanto, isso pode precisar ser convertido em "Mil duzentos e trinta e quatro" ou "Um, dois, três, quatro", dependendo do contexto. Para "Eu tenho 1234 maçãs", seria "Mil duzentos e trinta e quatro", mas para "A criança contou 1234", seria "Um, dois, três, quatro". + +As palavras criadas variam não apenas para o idioma, mas também para o local desse idioma. Por exemplo, em inglês americano, 120 seria "One hundred twenty", enquanto em inglês britânico seria "One hundred and twenty", com o uso de "and" após os cem. + +✅ Alguns outros exemplos que requerem análise de texto incluem "in" como forma abreviada de polegada e "st" como forma abreviada de santo ou rua. Consegues pensar em outros exemplos no teu idioma de palavras que são ambíguas sem contexto? + +Depois de definidas as palavras, elas são enviadas para análise linguística. + +### Análise linguística + +A análise linguística decompõe as palavras em fonemas. Os fonemas baseiam-se não apenas nas letras usadas, mas também nas outras letras da palavra. Por exemplo, em inglês, o som 'a' em 'car' e 'care' é diferente. O idioma inglês tem 44 fonemas diferentes para as 26 letras do alfabeto, alguns compartilhados por letras diferentes, como o mesmo fonema usado no início de 'circle' e 'serpent'. + +✅ Faz uma pesquisa: Quais são os fonemas do teu idioma? + +Depois de as palavras serem convertidas em fonemas, esses fonemas precisam de dados adicionais para suportar a entoação, ajustando o tom ou a duração dependendo do contexto. Um exemplo é que, em inglês, o aumento de tom pode ser usado para transformar uma frase numa pergunta, com o tom elevado na última palavra a implicar uma pergunta. + +Por exemplo - a frase "You have an apple" é uma afirmação dizendo que tens uma maçã. Se o tom subir no final, aumentando na palavra "apple", torna-se a pergunta "You have an apple?", perguntando se tens uma maçã. A análise linguística precisa usar o ponto de interrogação no final para decidir aumentar o tom. + +Depois de os fonemas serem gerados, eles podem ser enviados para geração de forma de onda para produzir o áudio. + +### Geração de forma de onda + +Os primeiros sistemas eletrónicos de texto para fala usavam gravações únicas de áudio para cada fonema, levando a vozes muito monótonas e robóticas. A análise linguística produzia fonemas, que eram carregados de uma base de dados de sons e unidos para criar o áudio. + +✅ Faz uma pesquisa: Encontra algumas gravações de áudio de sistemas de síntese de fala antigos. Compara com a síntese de fala moderna, como a usada em assistentes inteligentes. + +A geração de forma de onda mais moderna usa modelos de ML construídos com aprendizagem profunda (redes neurais muito grandes que funcionam de forma semelhante aos neurónios no cérebro) para produzir vozes mais naturais que podem ser indistinguíveis das humanas. + +> 💁 Alguns desses modelos de ML podem ser re-treinados usando aprendizagem por transferência para soar como pessoas reais. Isso significa que usar a voz como um sistema de segurança, algo que os bancos estão a tentar cada vez mais, já não é uma boa ideia, pois qualquer pessoa com uma gravação de alguns minutos da tua voz pode imitar-te. + +Esses grandes modelos de ML estão a ser treinados para combinar todas as três etapas em sintetizadores de fala de ponta a ponta. + +## Definir o temporizador + +Para definir o temporizador, o teu dispositivo IoT precisa chamar o endpoint REST que criaste usando código serverless e, em seguida, usar o número de segundos resultante para definir um temporizador. + +### Tarefa - chamar a função serverless para obter o tempo do temporizador + +Segue o guia relevante para chamar o endpoint REST a partir do teu dispositivo IoT e definir um temporizador para o tempo necessário: + +* [Arduino - Wio Terminal](wio-terminal-set-timer.md) +* [Computador de placa única - Raspberry Pi/Dispositivo IoT virtual](single-board-computer-set-timer.md) + +## Converter texto em fala + +O mesmo serviço de fala que usaste para converter fala em texto pode ser usado para converter texto de volta em fala, e isso pode ser reproduzido através de um altifalante no teu dispositivo IoT. O texto a ser convertido é enviado para o serviço de fala, juntamente com o tipo de áudio necessário (como a taxa de amostragem), e dados binários contendo o áudio são retornados. + +Quando envias esta solicitação, usas *Speech Synthesis Markup Language* (SSML), uma linguagem de marcação baseada em XML para aplicações de síntese de fala. Isto define não apenas o texto a ser convertido, mas também o idioma do texto, a voz a ser usada e pode até ser usado para definir velocidade, volume e tom para algumas ou todas as palavras no texto. + +Por exemplo, este SSML define um pedido para converter o texto "O teu temporizador de 3 minutos e 5 segundos foi definido" em fala usando uma voz em inglês britânico chamada `en-GB-MiaNeural` + +```xml + + + Your 3 minute 5 second time has been set + + +``` + +> 💁 A maioria dos sistemas de texto para fala tem várias vozes para diferentes idiomas, com sotaques relevantes, como uma voz em inglês britânico com sotaque inglês e uma voz em inglês da Nova Zelândia com sotaque neozelandês. + +### Tarefa - converter texto em fala + +Segue o guia relevante para converter texto em fala usando o teu dispositivo IoT: + +* [Arduino - Wio Terminal](wio-terminal-text-to-speech.md) +* [Computador de placa única - Raspberry Pi](pi-text-to-speech.md) +* [Computador de placa única - Dispositivo virtual](virtual-device-text-to-speech.md) + +--- + +## 🚀 Desafio + +O SSML tem formas de alterar como as palavras são faladas, como adicionar ênfase a certas palavras, adicionar pausas ou alterar o tom. Experimenta algumas dessas opções, enviando diferentes SSML a partir do teu dispositivo IoT e comparando os resultados. Podes ler mais sobre SSML, incluindo como alterar a forma como as palavras são faladas, na [especificação Speech Synthesis Markup Language (SSML) Version 1.1 do World Wide Web Consortium](https://www.w3.org/TR/speech-synthesis11/). + +## Questionário pós-aula + +[Questionário pós-aula](https://black-meadow-040d15503.1.azurestaticapps.net/quiz/46) + +## Revisão e Autoestudo + +* Lê mais sobre síntese de fala na [página de síntese de fala na Wikipédia](https://wikipedia.org/wiki/Speech_synthesis) +* Lê mais sobre como criminosos estão a usar síntese de fala para roubar na [notícia sobre vozes falsas 'ajudam cibercriminosos a roubar dinheiro' na BBC](https://www.bbc.com/news/technology-48908736) +* Aprende mais sobre os riscos para atores de voz devido a versões sintetizadas das suas vozes no [artigo sobre como esta ação judicial do TikTok está a destacar como a IA está a prejudicar atores de voz no Vice](https://www.vice.com/en/article/z3xqwj/this-tiktok-lawsuit-is-highlighting-how-ai-is-screwing-over-voice-actors) + +## Tarefa + +[Cancelar o temporizador](assignment.md) + +**Aviso Legal**: +Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, é importante notar que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes do uso desta tradução. \ No newline at end of file diff --git a/translations/pt-PT/6-consumer/lessons/3-spoken-feedback/assignment.md b/translations/pt-PT/6-consumer/lessons/3-spoken-feedback/assignment.md new file mode 100644 index 000000000..4933028ca --- /dev/null +++ b/translations/pt-PT/6-consumer/lessons/3-spoken-feedback/assignment.md @@ -0,0 +1,15 @@ +# Cancelar o temporizador + +## Instruções + +Na tarefa da última lição, adicionaste uma intenção de cancelar temporizador ao LUIS. Para esta tarefa, precisas de tratar esta intenção no código serverless, enviar um comando para o dispositivo IoT e, em seguida, cancelar o temporizador. + +## Critérios de Avaliação + +| Critério | Exemplar | Adequado | Necessita de Melhorias | +| -------- | --------- | -------- | ---------------------- | +| Tratar a intenção no código serverless e enviar um comando | Conseguiu tratar a intenção e enviar um comando para o dispositivo | Conseguiu tratar a intenção, mas não conseguiu enviar o comando para o dispositivo | Não conseguiu tratar a intenção | +| Cancelar o temporizador no dispositivo | Conseguiu receber o comando e cancelar o temporizador | Conseguiu receber o comando, mas não cancelar o temporizador | Não conseguiu receber o comando | + +**Aviso Legal**: +Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, é importante notar que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes do uso desta tradução. \ No newline at end of file diff --git a/translations/pt-PT/6-consumer/lessons/3-spoken-feedback/pi-text-to-speech.md b/translations/pt-PT/6-consumer/lessons/3-spoken-feedback/pi-text-to-speech.md new file mode 100644 index 000000000..e101be840 --- /dev/null +++ b/translations/pt-PT/6-consumer/lessons/3-spoken-feedback/pi-text-to-speech.md @@ -0,0 +1,145 @@ +# Texto para fala - Raspberry Pi + +Nesta parte da lição, vais escrever código para converter texto em fala utilizando o serviço de fala. + +## Converter texto em fala utilizando o serviço de fala + +O texto pode ser enviado ao serviço de fala através da API REST para obter a fala como um ficheiro de áudio que pode ser reproduzido no teu dispositivo IoT. Ao solicitar a fala, precisas de indicar a voz a ser utilizada, uma vez que a fala pode ser gerada com uma variedade de vozes diferentes. + +Cada idioma suporta uma gama de vozes distintas, e podes fazer uma solicitação REST ao serviço de fala para obter a lista de vozes suportadas para cada idioma. + +### Tarefa - obter uma voz + +1. Abre o projeto `smart-timer` no VS Code. + +1. Adiciona o seguinte código acima da função `say` para solicitar a lista de vozes para um idioma: + + ```python + def get_voice(): + url = f'https://{location}.tts.speech.microsoft.com/cognitiveservices/voices/list' + + headers = { + 'Authorization': 'Bearer ' + get_access_token() + } + + response = requests.get(url, headers=headers) + voices_json = json.loads(response.text) + + first_voice = next(x for x in voices_json if x['Locale'].lower() == language.lower() and x['VoiceType'] == 'Neural') + return first_voice['ShortName'] + + voice = get_voice() + print(f'Using voice {voice}') + ``` + + Este código define uma função chamada `get_voice` que utiliza o serviço de fala para obter uma lista de vozes. Em seguida, encontra a primeira voz que corresponde ao idioma que está a ser utilizado. + + Esta função é chamada para armazenar a primeira voz, e o nome da voz é impresso na consola. Esta voz pode ser solicitada uma vez e o valor utilizado em cada chamada para converter texto em fala. + + > 💁 Podes obter a lista completa de vozes suportadas na [documentação de suporte de idiomas e vozes no Microsoft Docs](https://docs.microsoft.com/azure/cognitive-services/speech-service/language-support?WT.mc_id=academic-17441-jabenn#text-to-speech). Se quiseres utilizar uma voz específica, podes remover esta função e definir diretamente o nome da voz a partir desta documentação. Por exemplo: + > + > ```python + > voice = 'hi-IN-SwaraNeural' + > ``` + +### Tarefa - converter texto em fala + +1. Abaixo disto, define uma constante para o formato de áudio a ser obtido dos serviços de fala. Quando solicitas áudio, podes fazê-lo em vários formatos diferentes. + + ```python + playback_format = 'riff-48khz-16bit-mono-pcm' + ``` + + O formato que podes utilizar depende do teu hardware. Se obtiveres erros de `Invalid sample rate` ao reproduzir o áudio, altera isto para outro valor. Podes encontrar a lista de valores suportados na [documentação da API REST de texto para fala no Microsoft Docs](https://docs.microsoft.com/azure/cognitive-services/speech-service/rest-text-to-speech?WT.mc_id=academic-17441-jabenn#audio-outputs). Vais precisar de utilizar áudio no formato `riff`, e os valores a experimentar são `riff-16khz-16bit-mono-pcm`, `riff-24khz-16bit-mono-pcm` e `riff-48khz-16bit-mono-pcm`. + +1. Abaixo disto, declara uma função chamada `get_speech` que irá converter o texto em fala utilizando a API REST do serviço de fala: + + ```python + def get_speech(text): + ``` + +1. Na função `get_speech`, define o URL a ser chamado e os cabeçalhos a serem enviados: + + ```python + url = f'https://{location}.tts.speech.microsoft.com/cognitiveservices/v1' + + headers = { + 'Authorization': 'Bearer ' + get_access_token(), + 'Content-Type': 'application/ssml+xml', + 'X-Microsoft-OutputFormat': playback_format + } + ``` + + Isto define os cabeçalhos para utilizar um token de acesso gerado, define o conteúdo como SSML e especifica o formato de áudio necessário. + +1. Abaixo disto, define o SSML a ser enviado à API REST: + + ```python + ssml = f'' + ssml += f'' + ssml += text + ssml += '' + ssml += '' + ``` + + Este SSML define o idioma e a voz a ser utilizada, juntamente com o texto a ser convertido. + +1. Finalmente, adiciona código nesta função para fazer a solicitação REST e retornar os dados binários de áudio: + + ```python + response = requests.post(url, headers=headers, data=ssml.encode('utf-8')) + return io.BytesIO(response.content) + ``` + +### Tarefa - reproduzir o áudio + +1. Abaixo da função `get_speech`, define uma nova função para reproduzir o áudio retornado pela chamada à API REST: + + ```python + def play_speech(speech): + ``` + +1. O `speech` passado para esta função será os dados binários de áudio retornados pela API REST. Utiliza o seguinte código para abrir isto como um ficheiro wave e passá-lo para o PyAudio para reproduzir o áudio: + + ```python + def play_speech(speech): + with wave.open(speech, 'rb') as wave_file: + stream = audio.open(format=audio.get_format_from_width(wave_file.getsampwidth()), + channels=wave_file.getnchannels(), + rate=wave_file.getframerate(), + output_device_index=speaker_card_number, + output=True) + + data = wave_file.readframes(4096) + + while len(data) > 0: + stream.write(data) + data = wave_file.readframes(4096) + + stream.stop_stream() + stream.close() + ``` + + Este código utiliza um stream do PyAudio, tal como na captura de áudio. A diferença aqui é que o stream é configurado como um stream de saída, e os dados são lidos a partir dos dados de áudio e enviados para o stream. + + Em vez de definir diretamente os detalhes do stream, como a taxa de amostragem, estes são lidos a partir dos dados de áudio. + +1. Substitui o conteúdo da função `say` pelo seguinte: + + ```python + speech = get_speech(text) + play_speech(speech) + ``` + + Este código converte o texto em fala como dados binários de áudio e reproduz o áudio. + +1. Executa a aplicação e certifica-te de que a aplicação de função também está a ser executada. Define alguns temporizadores e vais ouvir uma resposta falada a dizer que o teu temporizador foi definido, e outra resposta falada quando o temporizador terminar. + + Se obtiveres erros de `Invalid sample rate`, altera o `playback_format` conforme descrito acima. + +> 💁 Podes encontrar este código na pasta [code-spoken-response/pi](../../../../../6-consumer/lessons/3-spoken-feedback/code-spoken-response/pi). + +😀 O teu programa de temporizador foi um sucesso! + +**Aviso Legal**: +Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes do uso desta tradução. \ No newline at end of file diff --git a/translations/pt-PT/6-consumer/lessons/3-spoken-feedback/single-board-computer-set-timer.md b/translations/pt-PT/6-consumer/lessons/3-spoken-feedback/single-board-computer-set-timer.md new file mode 100644 index 000000000..4ebe630b7 --- /dev/null +++ b/translations/pt-PT/6-consumer/lessons/3-spoken-feedback/single-board-computer-set-timer.md @@ -0,0 +1,129 @@ +# Definir um temporizador - Hardware IoT Virtual e Raspberry Pi + +Nesta parte da lição, irá chamar o seu código serverless para interpretar o discurso e definir um temporizador no seu dispositivo IoT virtual ou Raspberry Pi com base nos resultados. + +## Definir um temporizador + +O texto que é retornado da chamada de reconhecimento de fala precisa ser enviado para o seu código serverless para ser processado pelo LUIS, obtendo o número de segundos para o temporizador. Este número de segundos pode ser usado para definir um temporizador. + +Os temporizadores podem ser definidos utilizando a classe `threading.Timer` do Python. Esta classe recebe um tempo de atraso e uma função, e após o tempo de atraso, a função é executada. + +### Tarefa - enviar o texto para a função serverless + +1. Abra o projeto `smart-timer` no VS Code e certifique-se de que o ambiente virtual está carregado no terminal, caso esteja a usar um dispositivo IoT virtual. + +1. Acima da função `process_text`, declare uma função chamada `get_timer_time` para chamar o endpoint REST que criou: + + ```python + def get_timer_time(text): + ``` + +1. Adicione o seguinte código a esta função para definir o URL a ser chamado: + + ```python + url = '' + ``` + + Substitua `` pelo URL do seu endpoint REST que criou na última lição, seja no seu computador ou na nuvem. + +1. Adicione o seguinte código para definir o texto como uma propriedade passada como JSON na chamada: + + ```python + body = { + 'text': text + } + + response = requests.post(url, json=body) + ``` + +1. Abaixo disso, recupere os `seconds` do payload da resposta, retornando 0 se a chamada falhar: + + ```python + if response.status_code != 200: + return 0 + + payload = response.json() + return payload['seconds'] + ``` + + Chamadas HTTP bem-sucedidas retornam um código de status na faixa dos 200, e o seu código serverless retorna 200 se o texto foi processado e reconhecido como a intenção de definir um temporizador. + +### Tarefa - definir um temporizador numa thread em segundo plano + +1. Adicione a seguinte instrução de importação no início do ficheiro para importar a biblioteca threading do Python: + + ```python + import threading + ``` + +1. Acima da função `process_text`, adicione uma função para falar uma resposta. Por agora, esta apenas escreverá no console, mas mais tarde nesta lição, esta função irá falar o texto. + + ```python + def say(text): + print(text) + ``` + +1. Abaixo disso, adicione uma função que será chamada por um temporizador para anunciar que o temporizador terminou: + + ```python + def announce_timer(minutes, seconds): + announcement = 'Times up on your ' + if minutes > 0: + announcement += f'{minutes} minute ' + if seconds > 0: + announcement += f'{seconds} second ' + announcement += 'timer.' + say(announcement) + ``` + + Esta função recebe o número de minutos e segundos do temporizador e constrói uma frase para dizer que o temporizador terminou. Verifica o número de minutos e segundos e só inclui cada unidade de tempo se tiver um valor. Por exemplo, se o número de minutos for 0, apenas os segundos são incluídos na mensagem. Esta frase é então enviada para a função `say`. + +1. Abaixo disso, adicione a seguinte função `create_timer` para criar um temporizador: + + ```python + def create_timer(total_seconds): + minutes, seconds = divmod(total_seconds, 60) + threading.Timer(total_seconds, announce_timer, args=[minutes, seconds]).start() + ``` + + Esta função recebe o número total de segundos para o temporizador que será enviado no comando e converte este valor em minutos e segundos. Em seguida, cria e inicia um objeto de temporizador utilizando o número total de segundos, passando a função `announce_timer` e uma lista contendo os minutos e segundos. Quando o temporizador expira, ele chama a função `announce_timer` e passa o conteúdo desta lista como parâmetros - assim, o primeiro item da lista é passado como o parâmetro `minutes` e o segundo item como o parâmetro `seconds`. + +1. No final da função `create_timer`, adicione algum código para construir uma mensagem a ser falada ao utilizador para anunciar que o temporizador está a iniciar: + + ```python + announcement = '' + if minutes > 0: + announcement += f'{minutes} minute ' + if seconds > 0: + announcement += f'{seconds} second ' + announcement += 'timer started.' + say(announcement) + ``` + + Novamente, isto apenas inclui a unidade de tempo que tem um valor. Esta frase é então enviada para a função `say`. + +1. Adicione o seguinte ao final da função `process_text` para obter o tempo do temporizador a partir do texto e, em seguida, criar o temporizador: + + ```python + seconds = get_timer_time(text) + if seconds > 0: + create_timer(seconds) + ``` + + O temporizador só é criado se o número de segundos for maior que 0. + +1. Execute a aplicação e certifique-se de que a aplicação de função também está em execução. Defina alguns temporizadores e o output mostrará o temporizador a ser definido e, em seguida, mostrará quando ele expira: + + ```output + pi@raspberrypi:~/smart-timer $ python3 app.py + Set a two minute 27 second timer. + 2 minute 27 second timer started. + Times up on your 2 minute 27 second timer. + ``` + +> 💁 Pode encontrar este código na pasta [code-timer/pi](../../../../../6-consumer/lessons/3-spoken-feedback/code-timer/pi) ou [code-timer/virtual-iot-device](../../../../../6-consumer/lessons/3-spoken-feedback/code-timer/virtual-iot-device). + +😀 O seu programa de temporizador foi um sucesso! + +**Aviso Legal**: +Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, é importante notar que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes do uso desta tradução. \ No newline at end of file diff --git a/translations/pt-PT/6-consumer/lessons/3-spoken-feedback/virtual-device-text-to-speech.md b/translations/pt-PT/6-consumer/lessons/3-spoken-feedback/virtual-device-text-to-speech.md new file mode 100644 index 000000000..d2e9e9201 --- /dev/null +++ b/translations/pt-PT/6-consumer/lessons/3-spoken-feedback/virtual-device-text-to-speech.md @@ -0,0 +1,77 @@ +# Texto para fala - Dispositivo Virtual IoT + +Nesta parte da lição, vais escrever código para converter texto em fala utilizando o serviço de fala. + +## Converter texto em fala + +O SDK dos serviços de fala que utilizaste na última lição para converter fala em texto pode ser usado para converter texto de volta em fala. Ao solicitar a fala, precisas de fornecer a voz a ser utilizada, uma vez que a fala pode ser gerada usando uma variedade de vozes diferentes. + +Cada idioma suporta uma gama de vozes diferentes, e podes obter a lista de vozes suportadas para cada idioma através do SDK dos serviços de fala. + +### Tarefa - converter texto em fala + +1. Abre o projeto `smart-timer` no VS Code e certifica-te de que o ambiente virtual está carregado no terminal. + +1. Importa o `SpeechSynthesizer` do pacote `azure.cognitiveservices.speech` adicionando-o às importações existentes: + + ```python + from azure.cognitiveservices.speech import SpeechConfig, SpeechRecognizer, SpeechSynthesizer + ``` + +1. Acima da função `say`, cria uma configuração de fala para usar com o sintetizador de fala: + + ```python + speech_config = SpeechConfig(subscription=speech_api_key, + region=location) + speech_config.speech_synthesis_language = language + speech_synthesizer = SpeechSynthesizer(speech_config=speech_config) + ``` + + Isto utiliza a mesma chave de API, localização e idioma que foram usados pelo reconhecedor. + +1. Abaixo disso, adiciona o seguinte código para obter uma voz e defini-la na configuração de fala: + + ```python + voices = speech_synthesizer.get_voices_async().get().voices + first_voice = next(x for x in voices if x.locale.lower() == language.lower()) + speech_config.speech_synthesis_voice_name = first_voice.short_name + ``` + + Isto obtém uma lista de todas as vozes disponíveis e, em seguida, encontra a primeira voz que corresponde ao idioma que está a ser utilizado. + + > 💁 Podes obter a lista completa de vozes suportadas na [documentação de suporte de idiomas e vozes no Microsoft Docs](https://docs.microsoft.com/azure/cognitive-services/speech-service/language-support?WT.mc_id=academic-17441-jabenn#text-to-speech). Se quiseres usar uma voz específica, podes remover esta função e definir diretamente o nome da voz a partir desta documentação. Por exemplo: + > + > ```python + > speech_config.speech_synthesis_voice_name = 'hi-IN-SwaraNeural' + > ``` + +1. Atualiza o conteúdo da função `say` para gerar SSML para a resposta: + + ```python + ssml = f'' + ssml += f'' + ssml += text + ssml += '' + ssml += '' + ``` + +1. Abaixo disso, para o reconhecimento de fala, fala o SSML e, em seguida, reinicia o reconhecimento: + + ```python + recognizer.stop_continuous_recognition() + speech_synthesizer.speak_ssml(ssml) + recognizer.start_continuous_recognition() + ``` + + O reconhecimento é interrompido enquanto o texto é falado para evitar que o anúncio do início do temporizador seja detetado, enviado para o LUIS e possivelmente interpretado como um pedido para definir um novo temporizador. + + > 💁 Podes testar isto comentando as linhas para parar e reiniciar o reconhecimento. Define um temporizador e podes verificar que o anúncio define um novo temporizador, o que causa um novo anúncio, levando a um novo temporizador, e assim sucessivamente para sempre! + +1. Executa a aplicação e certifica-te de que a aplicação de funções também está a funcionar. Define alguns temporizadores e vais ouvir uma resposta falada a dizer que o teu temporizador foi definido, seguida de outra resposta falada quando o temporizador terminar. + +> 💁 Podes encontrar este código na pasta [code-spoken-response/virtual-iot-device](../../../../../6-consumer/lessons/3-spoken-feedback/code-spoken-response/virtual-iot-device). + +😀 O teu programa de temporizador foi um sucesso! + +**Aviso Legal**: +Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes do uso desta tradução. \ No newline at end of file diff --git a/translations/pt-PT/6-consumer/lessons/3-spoken-feedback/wio-terminal-set-timer.md b/translations/pt-PT/6-consumer/lessons/3-spoken-feedback/wio-terminal-set-timer.md new file mode 100644 index 000000000..dc118b742 --- /dev/null +++ b/translations/pt-PT/6-consumer/lessons/3-spoken-feedback/wio-terminal-set-timer.md @@ -0,0 +1,290 @@ +# Definir um temporizador - Wio Terminal + +Nesta parte da lição, irá chamar o seu código serverless para interpretar a fala e definir um temporizador no seu Wio Terminal com base nos resultados. + +## Definir um temporizador + +O texto que retorna da chamada de conversão de fala para texto precisa ser enviado para o seu código serverless para ser processado pelo LUIS, que devolverá o número de segundos para o temporizador. Este número de segundos pode ser usado para definir um temporizador. + +Microcontroladores não têm suporte nativo para múltiplas threads no Arduino, por isso não existem classes padrão de temporizador como as que pode encontrar ao programar em Python ou outras linguagens de alto nível. Em vez disso, pode usar bibliotecas de temporizador que funcionam medindo o tempo decorrido na função `loop` e chamando funções quando o tempo termina. + +### Tarefa - enviar o texto para a função serverless + +1. Abra o projeto `smart-timer` no VS Code, caso ainda não esteja aberto. + +1. Abra o ficheiro de cabeçalho `config.h` e adicione o URL para a sua aplicação de função: + + ```cpp + const char *TEXT_TO_TIMER_FUNCTION_URL = ""; + ``` + + Substitua `` pelo URL da sua aplicação de função que obteve no último passo da última lição, apontando para o endereço IP da sua máquina local que está a executar a aplicação de função. + +1. Crie um novo ficheiro na pasta `src` chamado `language_understanding.h`. Este será usado para definir uma classe que enviará a fala reconhecida para a sua aplicação de função para ser convertida em segundos usando o LUIS. + +1. Adicione o seguinte ao topo deste ficheiro: + + ```cpp + #pragma once + + #include + #include + #include + #include + + #include "config.h" + ``` + + Isto inclui alguns ficheiros de cabeçalho necessários. + +1. Defina uma classe chamada `LanguageUnderstanding` e declare uma instância desta classe: + + ```cpp + class LanguageUnderstanding + { + public: + private: + }; + + LanguageUnderstanding languageUnderstanding; + ``` + +1. Para chamar a sua aplicação de funções, precisa de declarar um cliente WiFi. Adicione o seguinte à secção `private` da classe: + + ```cpp + WiFiClient _client; + ``` + +1. Na secção `public`, declare um método chamado `GetTimerDuration` para chamar a aplicação de funções: + + ```cpp + int GetTimerDuration(String text) + { + } + ``` + +1. No método `GetTimerDuration`, adicione o seguinte código para construir o JSON a ser enviado para a aplicação de funções: + + ```cpp + DynamicJsonDocument doc(1024); + doc["text"] = text; + + String body; + serializeJson(doc, body); + ``` + + Isto converte o texto passado para o método `GetTimerDuration` no seguinte JSON: + + ```json + { + "text" : "" + } + ``` + + onde `` é o texto passado para a função. + +1. Abaixo disto, adicione o seguinte código para fazer a chamada à aplicação de funções: + + ```cpp + HTTPClient httpClient; + httpClient.begin(_client, TEXT_TO_TIMER_FUNCTION_URL); + + int httpResponseCode = httpClient.POST(body); + ``` + + Isto faz uma requisição POST para a aplicação de funções, passando o corpo JSON e obtendo o código de resposta. + +1. Adicione o seguinte código abaixo disto: + + ```cpp + int seconds = 0; + if (httpResponseCode == 200) + { + String result = httpClient.getString(); + Serial.println(result); + + DynamicJsonDocument doc(1024); + deserializeJson(doc, result.c_str()); + + JsonObject obj = doc.as(); + seconds = obj["seconds"].as(); + } + else + { + Serial.print("Failed to understand text - error "); + Serial.println(httpResponseCode); + } + ``` + + Este código verifica o código de resposta. Se for 200 (sucesso), o número de segundos para o temporizador é recuperado do corpo da resposta. Caso contrário, um erro é enviado para o monitor serial e o número de segundos é definido como 0. + +1. Adicione o seguinte código ao final deste método para fechar a conexão HTTP e retornar o número de segundos: + + ```cpp + httpClient.end(); + + return seconds; + ``` + +1. No ficheiro `main.cpp`, inclua este novo cabeçalho: + + ```cpp + #include "speech_to_text.h" + ``` + +1. No final da função `processAudio`, chame o método `GetTimerDuration` para obter a duração do temporizador: + + ```cpp + int total_seconds = languageUnderstanding.GetTimerDuration(text); + ``` + + Isto converte o texto da chamada para a classe `SpeechToText` no número de segundos para o temporizador. + +### Tarefa - definir um temporizador + +O número de segundos pode ser usado para definir um temporizador. + +1. Adicione a seguinte dependência de biblioteca ao ficheiro `platformio.ini` para adicionar uma biblioteca para definir um temporizador: + + ```ini + contrem/arduino-timer @ 2.3.0 + ``` + +1. Adicione uma diretiva de inclusão para esta biblioteca no ficheiro `main.cpp`: + + ```cpp + #include + ``` + +1. Acima da função `processAudio`, adicione o seguinte código: + + ```cpp + auto timer = timer_create_default(); + ``` + + Este código declara um temporizador chamado `timer`. + +1. Abaixo disto, adicione o seguinte código: + + ```cpp + void say(String text) + { + Serial.print("Saying "); + Serial.println(text); + } + ``` + + Esta função `say` eventualmente converterá texto em fala, mas por agora apenas escreverá o texto passado no monitor serial. + +1. Abaixo da função `say`, adicione o seguinte código: + + ```cpp + bool timerExpired(void *announcement) + { + say((char *)announcement); + return false; + } + ``` + + Esta é uma função de callback que será chamada quando um temporizador expirar. É passada uma mensagem para ser dita quando o temporizador expirar. Os temporizadores podem repetir, e isto pode ser controlado pelo valor de retorno deste callback - este retorna `false`, para indicar que o temporizador não deve ser executado novamente. + +1. Adicione o seguinte código ao final da função `processAudio`: + + ```cpp + if (total_seconds == 0) + { + return; + } + + int minutes = total_seconds / 60; + int seconds = total_seconds % 60; + ``` + + Este código verifica o número total de segundos e, se for 0, retorna da chamada da função para que nenhum temporizador seja definido. Em seguida, converte o número total de segundos em minutos e segundos. + +1. Abaixo deste código, adicione o seguinte para criar uma mensagem a ser dita quando o temporizador for iniciado: + + ```cpp + String begin_message; + if (minutes > 0) + { + begin_message += minutes; + begin_message += " minute "; + } + if (seconds > 0) + { + begin_message += seconds; + begin_message += " second "; + } + + begin_message += "timer started."; + ``` + +1. Abaixo disto, adicione um código semelhante para criar uma mensagem a ser dita quando o temporizador expirar: + + ```cpp + String end_message("Times up on your "); + if (minutes > 0) + { + end_message += minutes; + end_message += " minute "; + } + if (seconds > 0) + { + end_message += seconds; + end_message += " second "; + } + + end_message += "timer."; + ``` + +1. Depois disto, diga a mensagem de início do temporizador: + + ```cpp + say(begin_message); + ``` + +1. No final desta função, inicie o temporizador: + + ```cpp + timer.in(total_seconds * 1000, timerExpired, (void *)(end_message.c_str())); + ``` + + Isto ativa o temporizador. O temporizador é definido usando milissegundos, então o número total de segundos é multiplicado por 1.000 para converter em milissegundos. A função `timerExpired` é passada como o callback, e a `end_message` é passada como um argumento para o callback. Este callback apenas aceita argumentos `void *`, então a string é convertida apropriadamente. + +1. Finalmente, o temporizador precisa de "ticar", e isto é feito na função `loop`. Adicione o seguinte código ao final da função `loop`: + + ```cpp + timer.tick(); + ``` + +1. Compile este código, carregue-o no seu Wio Terminal e teste-o através do monitor serial. Assim que vir `Ready` no monitor serial, pressione o botão C (o que está do lado esquerdo, mais próximo do interruptor de energia) e fale. Serão capturados 4 segundos de áudio, convertidos em texto, enviados para a sua aplicação de função e um temporizador será definido. Certifique-se de que a sua aplicação de função está a ser executada localmente. + + Verá quando o temporizador começa e quando termina. + + ```output + --- Available filters and text transformations: colorize, debug, default, direct, hexlify, log2file, nocontrol, printable, send_on_enter, time + --- More details at http://bit.ly/pio-monitor-filters + --- Miniterm on /dev/cu.usbmodem1101 9600,8,N,1 --- + --- Quit: Ctrl+C | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H --- + Connecting to WiFi.. + Connected! + Got access token. + Ready. + Starting recording... + Finished recording + Sending speech... + Speech sent! + {"RecognitionStatus":"Success","DisplayText":"Set a 2 minute and 27 second timer.","Offset":4700000,"Duration":35300000} + Set a 2 minute and 27 second timer. + {"seconds": 147} + 2 minute 27 second timer started. + Times up on your 2 minute 27 second timer. + ``` + +> 💁 Pode encontrar este código na pasta [code-timer/wio-terminal](../../../../../6-consumer/lessons/3-spoken-feedback/code-timer/wio-terminal). + +😀 O seu programa de temporizador foi um sucesso! + +**Aviso Legal**: +Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos pela precisão, esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes do uso desta tradução. \ No newline at end of file diff --git a/translations/pt-PT/6-consumer/lessons/3-spoken-feedback/wio-terminal-text-to-speech.md b/translations/pt-PT/6-consumer/lessons/3-spoken-feedback/wio-terminal-text-to-speech.md new file mode 100644 index 000000000..a6d216eaf --- /dev/null +++ b/translations/pt-PT/6-consumer/lessons/3-spoken-feedback/wio-terminal-text-to-speech.md @@ -0,0 +1,520 @@ +# Texto para fala - Wio Terminal + +Nesta parte da lição, irá converter texto em fala para fornecer feedback falado. + +## Texto para fala + +O SDK dos serviços de fala que utilizou na última lição para converter fala em texto pode ser usado para converter texto de volta em fala. + +## Obter uma lista de vozes + +Ao solicitar fala, é necessário fornecer a voz a ser usada, pois a fala pode ser gerada utilizando uma variedade de vozes diferentes. Cada idioma suporta uma gama de vozes distintas, e pode obter a lista de vozes suportadas para cada idioma a partir do SDK dos serviços de fala. Aqui entram as limitações dos microcontroladores - a chamada para obter a lista de vozes suportadas pelos serviços de texto para fala é um documento JSON com mais de 77KB de tamanho, demasiado grande para ser processado pelo Wio Terminal. No momento da escrita, a lista completa contém 215 vozes, cada uma definida por um documento JSON como o seguinte: + +```json +{ + "Name": "Microsoft Server Speech Text to Speech Voice (en-US, AriaNeural)", + "DisplayName": "Aria", + "LocalName": "Aria", + "ShortName": "en-US-AriaNeural", + "Gender": "Female", + "Locale": "en-US", + "StyleList": [ + "chat", + "customerservice", + "narration-professional", + "newscast-casual", + "newscast-formal", + "cheerful", + "empathetic" + ], + "SampleRateHertz": "24000", + "VoiceType": "Neural", + "Status": "GA" +} +``` + +Este JSON é para a voz **Aria**, que tem vários estilos de voz. Tudo o que é necessário ao converter texto em fala é o nome curto, `en-US-AriaNeural`. + +Em vez de descarregar e decodificar esta lista inteira no seu microcontrolador, precisará escrever algum código sem servidor para recuperar a lista de vozes para o idioma que está a usar e chamar isto a partir do seu Wio Terminal. O seu código pode então escolher uma voz apropriada da lista, como a primeira que encontrar. + +### Tarefa - criar uma função sem servidor para obter uma lista de vozes + +1. Abra o seu projeto `smart-timer-trigger` no VS Code e abra o terminal, garantindo que o ambiente virtual está ativado. Caso contrário, encerre e recrie o terminal. + +1. Abra o ficheiro `local.settings.json` e adicione configurações para a chave da API de fala e localização: + + ```json + "SPEECH_KEY": "", + "SPEECH_LOCATION": "" + ``` + + Substitua `` pela chave da API do recurso de serviço de fala. Substitua `` pela localização que utilizou ao criar o recurso de serviço de fala. + +1. Adicione um novo trigger HTTP a esta aplicação chamado `get-voices` usando o seguinte comando dentro do terminal do VS Code na pasta raiz do projeto da aplicação de funções: + + ```sh + func new --name get-voices --template "HTTP trigger" + ``` + + Isto criará um trigger HTTP chamado `get-voices`. + +1. Substitua o conteúdo do ficheiro `__init__.py` na pasta `get-voices` pelo seguinte: + + ```python + import json + import os + import requests + + import azure.functions as func + + def main(req: func.HttpRequest) -> func.HttpResponse: + location = os.environ['SPEECH_LOCATION'] + speech_key = os.environ['SPEECH_KEY'] + + req_body = req.get_json() + language = req_body['language'] + + url = f'https://{location}.tts.speech.microsoft.com/cognitiveservices/voices/list' + + headers = { + 'Ocp-Apim-Subscription-Key': speech_key + } + + response = requests.get(url, headers=headers) + voices_json = json.loads(response.text) + + voices = filter(lambda x: x['Locale'].lower() == language.lower(), voices_json) + voices = map(lambda x: x['ShortName'], voices) + + return func.HttpResponse(json.dumps(list(voices)), status_code=200) + ``` + + Este código faz uma solicitação HTTP ao endpoint para obter as vozes. Esta lista de vozes é um grande bloco de JSON com vozes para todos os idiomas, então as vozes para o idioma passado no corpo da solicitação são filtradas, e o nome curto é extraído e retornado como uma lista JSON. O nome curto é o valor necessário para converter texto em fala, então apenas este valor é retornado. + + > 💁 Pode alterar o filtro conforme necessário para selecionar apenas as vozes que deseja. + + Isto reduz o tamanho dos dados de 77KB (no momento da escrita) para um documento JSON muito menor. Por exemplo, para vozes dos EUA, isto é 408 bytes. + +1. Execute a sua aplicação de funções localmente. Pode então chamá-la usando uma ferramenta como curl da mesma forma que testou o trigger HTTP `text-to-timer`. Certifique-se de passar o seu idioma como um corpo JSON: + + ```json + { + "language":"" + } + ``` + + Substitua `` pelo seu idioma, como `en-GB` ou `zh-CN`. + +> 💁 Pode encontrar este código na pasta [code-spoken-response/functions](../../../../../6-consumer/lessons/3-spoken-feedback/code-spoken-response/functions). + +### Tarefa - recuperar a voz do seu Wio Terminal + +1. Abra o projeto `smart-timer` no VS Code, caso ainda não esteja aberto. + +1. Abra o ficheiro de cabeçalho `config.h` e adicione o URL para a sua aplicação de funções: + + ```cpp + const char *GET_VOICES_FUNCTION_URL = ""; + ``` + + Substitua `` pelo URL do trigger HTTP `get-voices` na sua aplicação de funções. Este será o mesmo valor de `TEXT_TO_TIMER_FUNCTION_URL`, exceto com um nome de função `get-voices` em vez de `text-to-timer`. + +1. Crie um novo ficheiro na pasta `src` chamado `text_to_speech.h`. Este será usado para definir uma classe para converter de texto para fala. + +1. Adicione as seguintes diretivas de inclusão ao topo do novo ficheiro `text_to_speech.h`: + + ```cpp + #pragma once + + #include + #include + #include + #include + #include + #include + #include + + #include "config.h" + #include "speech_to_text.h" + ``` + +1. Adicione o seguinte código abaixo para declarar a classe `TextToSpeech`, juntamente com uma instância que pode ser usada no resto da aplicação: + + ```cpp + class TextToSpeech + { + public: + private: + }; + + TextToSpeech textToSpeech; + ``` + +1. Para chamar a sua aplicação de funções, precisa declarar um cliente WiFi. Adicione o seguinte à seção `private` da classe: + + ```cpp + WiFiClient _client; + ``` + +1. Na seção `private`, adicione um campo para a voz selecionada: + + ```cpp + String _voice; + ``` + +1. Na seção `public`, adicione uma função `init` que irá obter a primeira voz: + + ```cpp + void init() + { + } + ``` + +1. Para obter as vozes, um documento JSON precisa ser enviado à aplicação de funções com o idioma. Adicione o seguinte código à função `init` para criar este documento JSON: + + ```cpp + DynamicJsonDocument doc(1024); + doc["language"] = LANGUAGE; + + String body; + serializeJson(doc, body); + ``` + +1. Em seguida, crie um `HTTPClient` e use-o para chamar a aplicação de funções para obter as vozes, enviando o documento JSON: + + ```cpp + HTTPClient httpClient; + httpClient.begin(_client, GET_VOICES_FUNCTION_URL); + + int httpResponseCode = httpClient.POST(body); + ``` + +1. Abaixo disso, adicione código para verificar o código de resposta e, se for 200 (sucesso), então extraia a lista de vozes, recuperando a primeira da lista: + + ```cpp + if (httpResponseCode == 200) + { + String result = httpClient.getString(); + Serial.println(result); + + DynamicJsonDocument doc(1024); + deserializeJson(doc, result.c_str()); + + JsonArray obj = doc.as(); + _voice = obj[0].as(); + + Serial.print("Using voice "); + Serial.println(_voice); + } + else + { + Serial.print("Failed to get voices - error "); + Serial.println(httpResponseCode); + } + ``` + +1. Após isso, encerre a conexão do cliente HTTP: + + ```cpp + httpClient.end(); + ``` + +1. Abra o ficheiro `main.cpp` e adicione a seguinte diretiva de inclusão no topo para incluir este novo ficheiro de cabeçalho: + + ```cpp + #include "text_to_speech.h" + ``` + +1. Na função `setup`, abaixo da chamada para `speechToText.init();`, adicione o seguinte para inicializar a classe `TextToSpeech`: + + ```cpp + textToSpeech.init(); + ``` + +1. Compile este código, carregue-o no seu Wio Terminal e teste-o através do monitor serial. Certifique-se de que a sua aplicação de funções está em execução. + + Verá a lista de vozes disponíveis retornada pela aplicação de funções, juntamente com a voz selecionada. + + ```output + --- Available filters and text transformations: colorize, debug, default, direct, hexlify, log2file, nocontrol, printable, send_on_enter, time + --- More details at http://bit.ly/pio-monitor-filters + --- Miniterm on /dev/cu.usbmodem1101 9600,8,N,1 --- + --- Quit: Ctrl+C | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H --- + Connecting to WiFi.. + Connected! + Got access token. + ["en-US-JennyNeural", "en-US-JennyMultilingualNeural", "en-US-GuyNeural", "en-US-AriaNeural", "en-US-AmberNeural", "en-US-AnaNeural", "en-US-AshleyNeural", "en-US-BrandonNeural", "en-US-ChristopherNeural", "en-US-CoraNeural", "en-US-ElizabethNeural", "en-US-EricNeural", "en-US-JacobNeural", "en-US-MichelleNeural", "en-US-MonicaNeural", "en-US-AriaRUS", "en-US-BenjaminRUS", "en-US-GuyRUS", "en-US-ZiraRUS"] + Using voice en-US-JennyNeural + Ready. + ``` + +## Converter texto em fala + +Depois de ter uma voz para usar, ela pode ser usada para converter texto em fala. As mesmas limitações de memória com vozes também se aplicam ao converter texto em fala, então precisará gravar a fala num cartão SD pronto para ser reproduzido através do ReSpeaker. + +> 💁 Em lições anteriores deste projeto, utilizou memória flash para armazenar fala capturada do microfone. Esta lição utiliza um cartão SD, pois é mais fácil reproduzir áudio a partir dele usando as bibliotecas de áudio da Seeed. + +Há também outra limitação a considerar, os dados de áudio disponíveis do serviço de fala e os formatos que o Wio Terminal suporta. Ao contrário de computadores completos, as bibliotecas de áudio para microcontroladores podem ser muito limitadas nos formatos de áudio que suportam. Por exemplo, a biblioteca Seeed Arduino Audio que pode reproduzir som através do ReSpeaker só suporta áudio com uma taxa de amostragem de 44.1KHz. Os serviços de fala da Azure podem fornecer áudio em vários formatos, mas nenhum deles utiliza esta taxa de amostragem, fornecendo apenas 8KHz, 16KHz, 24KHz e 48KHz. Isto significa que o áudio precisa ser reamostrado para 44.1KHz, algo que exigiria mais recursos do que o Wio Terminal possui, especialmente memória. + +Quando é necessário manipular dados como este, é frequentemente melhor usar código sem servidor, especialmente se os dados forem obtidos através de uma chamada web. O Wio Terminal pode chamar uma função sem servidor, passando o texto a ser convertido, e a função sem servidor pode tanto chamar o serviço de fala para converter texto em fala, como também reamostrar o áudio para a taxa de amostragem necessária. Pode então retornar o áudio no formato que o Wio Terminal precisa para ser armazenado no cartão SD e reproduzido através do ReSpeaker. + +### Tarefa - criar uma função sem servidor para converter texto em fala + +1. Abra o seu projeto `smart-timer-trigger` no VS Code e abra o terminal, garantindo que o ambiente virtual está ativado. Caso contrário, encerre e recrie o terminal. + +1. Adicione um novo trigger HTTP a esta aplicação chamado `text-to-speech` usando o seguinte comando dentro do terminal do VS Code na pasta raiz do projeto da aplicação de funções: + + ```sh + func new --name text-to-speech --template "HTTP trigger" + ``` + + Isto criará um trigger HTTP chamado `text-to-speech`. + +1. O pacote Pip [librosa](https://librosa.org) tem funções para reamostrar áudio, então adicione-o ao ficheiro `requirements.txt`: + + ```sh + librosa + ``` + + Depois de adicionar isto, instale os pacotes Pip usando o seguinte comando no terminal do VS Code: + + ```sh + pip install -r requirements.txt + ``` + + > ⚠️ Se estiver a usar Linux, incluindo Raspberry Pi OS, pode precisar instalar `libsndfile` com o seguinte comando: + > + > ```sh + > sudo apt update + > sudo apt install libsndfile1-dev + > ``` + +1. Para converter texto em fala, não pode usar diretamente a chave da API de fala, em vez disso, precisa solicitar um token de acesso, usando a chave da API para autenticar a solicitação do token de acesso. Abra o ficheiro `__init__.py` da pasta `text-to-speech` e substitua todo o código nele pelo seguinte: + + ```python + import io + import os + import requests + + import librosa + import soundfile as sf + import azure.functions as func + + location = os.environ['SPEECH_LOCATION'] + speech_key = os.environ['SPEECH_KEY'] + + def get_access_token(): + headers = { + 'Ocp-Apim-Subscription-Key': speech_key + } + + token_endpoint = f'https://{location}.api.cognitive.microsoft.com/sts/v1.0/issuetoken' + response = requests.post(token_endpoint, headers=headers) + return str(response.text) + ``` + + Isto define constantes para a localização e chave de fala que serão lidas das configurações. Em seguida, define a função `get_access_token` que irá recuperar um token de acesso para o serviço de fala. + +1. Abaixo deste código, adicione o seguinte: + + ```python + playback_format = 'riff-48khz-16bit-mono-pcm' + + def main(req: func.HttpRequest) -> func.HttpResponse: + req_body = req.get_json() + language = req_body['language'] + voice = req_body['voice'] + text = req_body['text'] + + url = f'https://{location}.tts.speech.microsoft.com/cognitiveservices/v1' + + headers = { + 'Authorization': 'Bearer ' + get_access_token(), + 'Content-Type': 'application/ssml+xml', + 'X-Microsoft-OutputFormat': playback_format + } + + ssml = f'' + ssml += f'' + ssml += text + ssml += '' + ssml += '' + + response = requests.post(url, headers=headers, data=ssml.encode('utf-8')) + + raw_audio, sample_rate = librosa.load(io.BytesIO(response.content), sr=48000) + resampled = librosa.resample(raw_audio, sample_rate, 44100) + + output_buffer = io.BytesIO() + sf.write(output_buffer, resampled, 44100, 'PCM_16', format='wav') + output_buffer.seek(0) + + return func.HttpResponse(output_buffer.read(), status_code=200) + ``` + + Isto define o trigger HTTP que converte o texto em fala. Extrai o texto a ser convertido, o idioma e a voz do corpo JSON enviado na solicitação, constrói algum SSML para solicitar a fala, e então chama a API REST relevante autenticando usando o token de acesso. Esta chamada à API REST retorna o áudio codificado como um ficheiro WAV mono de 16 bits e 48KHz, definido pelo valor de `playback_format`, que é enviado na chamada à API REST. + + Isto é então reamostrado por `librosa` de uma taxa de amostragem de 48KHz para uma taxa de amostragem de 44.1KHz, e este áudio é guardado num buffer binário que é então retornado. + +1. Execute a sua aplicação de funções localmente ou implemente-a na nuvem. Pode então chamá-la usando uma ferramenta como curl da mesma forma que testou o trigger HTTP `text-to-timer`. Certifique-se de passar o idioma, voz e texto como corpo JSON: + + ```json + { + "language": "", + "voice": "", + "text": "" + } + ``` + + Substitua `` pelo seu idioma, como `en-GB` ou `zh-CN`. Substitua `` pela voz que deseja usar. Substitua `` pelo texto que deseja converter em fala. Pode guardar o resultado num ficheiro e reproduzi-lo com qualquer leitor de áudio que suporte ficheiros WAV. + + Por exemplo, para converter "Hello" em fala usando inglês dos EUA com a voz Jenny Neural, com a aplicação de funções a ser executada localmente, pode usar o seguinte comando curl: + + ```sh + curl -X GET 'http://localhost:7071/api/text-to-speech' \ + -H 'Content-Type: application/json' \ + -o hello.wav \ + -d '{ + "language":"en-US", + "voice": "en-US-JennyNeural", + "text": "Hello" + }' + ``` + + Isto irá guardar o áudio em `hello.wav` no diretório atual. + +> 💁 Pode encontrar este código na pasta [code-spoken-response/functions](../../../../../6-consumer/lessons/3-spoken-feedback/code-spoken-response/functions). + +### Tarefa - recuperar a fala do seu Wio Terminal + +1. Abra o projeto `smart-timer` no VS Code, caso ainda não esteja aberto. + +1. Abra o ficheiro de cabeçalho `config.h` e adicione o URL para a sua aplicação de funções: + + ```cpp + const char *TEXT_TO_SPEECH_FUNCTION_URL = ""; + ``` + + Substitua `` pelo URL do trigger HTTP `text-to-speech` na sua aplicação de funções. Este será o mesmo valor de `TEXT_TO_TIMER_FUNCTION_URL`, exceto com um nome de função `text-to-speech` em vez de `text-to-timer`. + +1. Abra o ficheiro de cabeçalho `text_to_speech.h` e adicione o seguinte método à seção `public` da classe `TextToSpeech`: + + ```cpp + void convertTextToSpeech(String text) + { + } + ``` + +1. Ao método `convertTextToSpeech`, adicione o seguinte código para criar o JSON a ser enviado à aplicação de funções: + + ```cpp + DynamicJsonDocument doc(1024); + doc["language"] = LANGUAGE; + doc["voice"] = _voice; + doc["text"] = text; + + String body; + serializeJson(doc, body); + ``` + + Isto escreve o idioma, voz e texto no documento JSON e, em seguida, serializa-o para uma string. + +1. Abaixo disso, adicione o seguinte código para chamar a aplicação de funções: + + ```cpp + HTTPClient httpClient; + httpClient.begin(_client, TEXT_TO_SPEECH_FUNCTION_URL); + + int httpResponseCode = httpClient.POST(body); + ``` + + Isto cria um `HTTPClient` e faz uma solicitação POST usando o documento JSON ao trigger HTTP de texto para fala. + +1. Se a chamada funcionar, os dados binários brutos retornados pela chamada à aplicação de funções podem ser transmitidos para um ficheiro no cartão SD. Adicione o seguinte código para fazer isso: + + ```cpp + if (httpResponseCode == 200) + { + File wav_file = SD.open("SPEECH.WAV", FILE_WRITE); + httpClient.writeToStream(&wav_file); + wav_file.close(); + } + else + { + Serial.print("Failed to get speech - error "); + Serial.println(httpResponseCode); + } + ``` + + Este código verifica a resposta e, se for 200 (sucesso), os dados binários são transmitidos para um ficheiro na raiz do cartão SD chamado `SPEECH.WAV`. + +1. No final deste método, feche a conexão HTTP: + + ```cpp + httpClient.end(); + ``` + +1. O texto a ser falado pode agora ser convertido em áudio. No ficheiro `main.cpp`, adicione a seguinte linha ao final da função `say` para converter o texto a ser dito em áudio: +### Tarefa - reproduzir áudio no seu Wio Terminal + +**Em breve** + +## Implantar a sua aplicação de funções na nuvem + +O motivo para executar a aplicação de funções localmente é que o pacote `librosa` do Pip no Linux tem uma dependência de uma biblioteca que não está instalada por padrão e precisará ser instalada antes que a aplicação de funções possa ser executada. Aplicações de funções são sem servidor - não há servidores que você possa gerenciar diretamente, então não há como instalar essa biblioteca antecipadamente. + +A maneira de resolver isso é implantar a sua aplicação de funções usando um contêiner Docker. Este contêiner é implantado pela nuvem sempre que é necessário iniciar uma nova instância da sua aplicação de funções (como quando a demanda excede os recursos disponíveis ou se a aplicação de funções não foi usada por um tempo e foi encerrada). + +Você pode encontrar as instruções para configurar uma aplicação de funções e implantá-la via Docker na [documentação sobre criar uma função no Linux usando uma imagem personalizada no Microsoft Docs](https://docs.microsoft.com/azure/azure-functions/functions-create-function-linux-custom-image?WT.mc_id=academic-17441-jabenn&tabs=bash%2Cazurecli&pivots=programming-language-python). + +Depois de implantada, você pode adaptar o código do seu Wio Terminal para acessar essa função: + +1. Adicione o certificado do Azure Functions ao `config.h`: + + ```cpp + const char *FUNCTIONS_CERTIFICATE = + "-----BEGIN CERTIFICATE-----\r\n" + "MIIFWjCCBEKgAwIBAgIQDxSWXyAgaZlP1ceseIlB4jANBgkqhkiG9w0BAQsFADBa\r\n" + "MQswCQYDVQQGEwJJRTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJl\r\n" + "clRydXN0MSIwIAYDVQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTIw\r\n" + "MDcyMTIzMDAwMFoXDTI0MTAwODA3MDAwMFowTzELMAkGA1UEBhMCVVMxHjAcBgNV\r\n" + "BAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEgMB4GA1UEAxMXTWljcm9zb2Z0IFJT\r\n" + "QSBUTFMgQ0EgMDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCqYnfP\r\n" + "mmOyBoTzkDb0mfMUUavqlQo7Rgb9EUEf/lsGWMk4bgj8T0RIzTqk970eouKVuL5R\r\n" + "IMW/snBjXXgMQ8ApzWRJCZbar879BV8rKpHoAW4uGJssnNABf2n17j9TiFy6BWy+\r\n" + "IhVnFILyLNK+W2M3zK9gheiWa2uACKhuvgCca5Vw/OQYErEdG7LBEzFnMzTmJcli\r\n" + "W1iCdXby/vI/OxbfqkKD4zJtm45DJvC9Dh+hpzqvLMiK5uo/+aXSJY+SqhoIEpz+\r\n" + "rErHw+uAlKuHFtEjSeeku8eR3+Z5ND9BSqc6JtLqb0bjOHPm5dSRrgt4nnil75bj\r\n" + "c9j3lWXpBb9PXP9Sp/nPCK+nTQmZwHGjUnqlO9ebAVQD47ZisFonnDAmjrZNVqEX\r\n" + "F3p7laEHrFMxttYuD81BdOzxAbL9Rb/8MeFGQjE2Qx65qgVfhH+RsYuuD9dUw/3w\r\n" + "ZAhq05yO6nk07AM9c+AbNtRoEcdZcLCHfMDcbkXKNs5DJncCqXAN6LhXVERCw/us\r\n" + "G2MmCMLSIx9/kwt8bwhUmitOXc6fpT7SmFvRAtvxg84wUkg4Y/Gx++0j0z6StSeN\r\n" + "0EJz150jaHG6WV4HUqaWTb98Tm90IgXAU4AW2GBOlzFPiU5IY9jt+eXC2Q6yC/Zp\r\n" + "TL1LAcnL3Qa/OgLrHN0wiw1KFGD51WRPQ0Sh7QIDAQABo4IBJTCCASEwHQYDVR0O\r\n" + "BBYEFLV2DDARzseSQk1Mx1wsyKkM6AtkMB8GA1UdIwQYMBaAFOWdWTCCR1jMrPoI\r\n" + "VDaGezq1BE3wMA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYI\r\n" + "KwYBBQUHAwIwEgYDVR0TAQH/BAgwBgEB/wIBADA0BggrBgEFBQcBAQQoMCYwJAYI\r\n" + "KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTA6BgNVHR8EMzAxMC+g\r\n" + "LaArhilodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vT21uaXJvb3QyMDI1LmNybDAq\r\n" + "BgNVHSAEIzAhMAgGBmeBDAECATAIBgZngQwBAgIwCwYJKwYBBAGCNyoBMA0GCSqG\r\n" + "SIb3DQEBCwUAA4IBAQCfK76SZ1vae4qt6P+dTQUO7bYNFUHR5hXcA2D59CJWnEj5\r\n" + "na7aKzyowKvQupW4yMH9fGNxtsh6iJswRqOOfZYC4/giBO/gNsBvwr8uDW7t1nYo\r\n" + "DYGHPpvnpxCM2mYfQFHq576/TmeYu1RZY29C4w8xYBlkAA8mDJfRhMCmehk7cN5F\r\n" + "JtyWRj2cZj/hOoI45TYDBChXpOlLZKIYiG1giY16vhCRi6zmPzEwv+tk156N6cGS\r\n" + "Vm44jTQ/rs1sa0JSYjzUaYngoFdZC4OfxnIkQvUIA4TOFmPzNPEFdjcZsgbeEz4T\r\n" + "cGHTBPK4R28F44qIMCtHRV55VMX53ev6P3hRddJb\r\n" + "-----END CERTIFICATE-----\r\n"; + ``` + +1. Altere todas as inclusões de `` para ``. + +1. Substitua todos os campos `WiFiClient` por `WiFiClientSecure`. + +1. Em cada classe que tenha um campo `WiFiClientSecure`, adicione um construtor e configure o certificado nesse construtor: + + ```cpp + _client.setCACert(FUNCTIONS_CERTIFICATE); + ``` + +**Aviso Legal**: +Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos pela precisão, esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes do uso desta tradução. \ No newline at end of file diff --git a/translations/pt-PT/6-consumer/lessons/4-multiple-language-support/README.md b/translations/pt-PT/6-consumer/lessons/4-multiple-language-support/README.md new file mode 100644 index 000000000..a8255cca8 --- /dev/null +++ b/translations/pt-PT/6-consumer/lessons/4-multiple-language-support/README.md @@ -0,0 +1,177 @@ +# Suporte a múltiplos idiomas + +![Uma visão geral ilustrada desta lição](../../../../../translated_images/pt-PT/lesson-24.4246968ed058510ab275052e87ef9aa89c7b2f938915d103c605c04dc6cd5bb7.jpg) + +> Ilustração por [Nitya Narasimhan](https://github.com/nitya). Clique na imagem para uma versão maior. + +Este vídeo oferece uma visão geral dos serviços de fala do Azure, abordando conversão de fala para texto e texto para fala das lições anteriores, bem como tradução de fala, um tema abordado nesta lição: + +[![Reconhecendo fala com algumas linhas de Python no Microsoft Build 2020](https://img.youtube.com/vi/h6xbpMPSGEA/0.jpg)](https://www.youtube.com/watch?v=h6xbpMPSGEA) + +> 🎥 Clique na imagem acima para assistir ao vídeo + +## Questionário pré-aula + +[Questionário pré-aula](https://black-meadow-040d15503.1.azurestaticapps.net/quiz/47) + +## Introdução + +Nas últimas 3 lições, aprendeste sobre conversão de fala para texto, compreensão de linguagem e conversão de texto para fala, tudo impulsionado por IA. Outra área da comunicação humana em que a IA pode ajudar é a tradução de idiomas - converter de um idioma para outro, como de inglês para francês. + +Nesta lição, vais aprender a usar IA para traduzir texto, permitindo que o teu temporizador inteligente interaja com utilizadores em vários idiomas. + +Nesta lição, vamos abordar: + +* [Traduzir texto](../../../../../6-consumer/lessons/4-multiple-language-support) +* [Serviços de tradução](../../../../../6-consumer/lessons/4-multiple-language-support) +* [Criar um recurso de tradutor](../../../../../6-consumer/lessons/4-multiple-language-support) +* [Suportar múltiplos idiomas em aplicações com traduções](../../../../../6-consumer/lessons/4-multiple-language-support) +* [Traduzir texto usando um serviço de IA](../../../../../6-consumer/lessons/4-multiple-language-support) + +> 🗑 Esta é a última lição deste projeto, então, após completar esta lição e o exercício, não te esqueças de limpar os teus serviços na nuvem. Vais precisar dos serviços para completar o exercício, por isso certifica-te de que o completas primeiro. +> +> Consulta [o guia de limpeza do projeto](../../../clean-up.md) se necessário para instruções sobre como fazer isso. + +## Traduzir texto + +A tradução de texto tem sido um problema de ciência da computação investigado há mais de 70 anos, e só agora, graças aos avanços em IA e poder computacional, está perto de ser resolvido a um ponto em que é quase tão boa quanto tradutores humanos. + +> 💁 As origens podem ser rastreadas ainda mais longe, até [Al-Kindi](https://wikipedia.org/wiki/Al-Kindi), um criptógrafo árabe do século IX que desenvolveu técnicas para tradução de idiomas. + +### Traduções automáticas + +A tradução de texto começou como uma tecnologia conhecida como Tradução Automática (MT), que pode traduzir entre diferentes pares de idiomas. A MT funciona substituindo palavras de um idioma por outro, adicionando técnicas para selecionar as formas corretas de traduzir frases ou partes de frases quando uma simples tradução palavra por palavra não faz sentido. + +> 🎓 Quando tradutores suportam a tradução entre um idioma e outro, estes são conhecidos como *pares de idiomas*. Diferentes ferramentas suportam diferentes pares de idiomas, e estes podem não ser completos. Por exemplo, um tradutor pode suportar inglês para espanhol como um par de idiomas, e espanhol para italiano como outro par, mas não inglês para italiano. + +Por exemplo, traduzir "Hello world" de inglês para francês pode ser feito com uma substituição - "Bonjour" para "Hello" e "le monde" para "world", resultando na tradução correta "Bonjour le monde". + +Substituições não funcionam quando diferentes idiomas usam formas diferentes de dizer a mesma coisa. Por exemplo, a frase em inglês "My name is Jim" traduz-se para "Je m'appelle Jim" em francês - literalmente "Eu chamo-me Jim". "Je" é francês para "Eu", "moi" é "me", mas é concatenado com o verbo porque começa com uma vogal, tornando-se "m'", "appelle" significa "chamar", e "Jim" não é traduzido porque é um nome e não uma palavra que pode ser traduzida. A ordem das palavras também se torna um problema - uma simples substituição de "Je m'appelle Jim" torna-se "I myself call Jim", com uma ordem de palavras diferente do inglês. + +> 💁 Algumas palavras nunca são traduzidas - o meu nome é Jim independentemente do idioma usado para me apresentar. Ao traduzir para idiomas que usam alfabetos diferentes ou letras diferentes para sons diferentes, as palavras podem ser *transliteradas*, ou seja, selecionar letras ou caracteres que reproduzam o som apropriado para soar igual ao nome original. + +Idiomas também são um problema para tradução. Estas são frases que têm um significado compreendido diferente de uma interpretação direta das palavras. Por exemplo, em inglês, o idioma "I've got ants in my pants" não se refere literalmente a ter formigas na roupa, mas sim a estar inquieto. Se traduzires isto para alemão, acabarias por confundir o ouvinte, já que a versão alemã é "Eu tenho abelhas no fundo". + +> 💁 Diferentes locais adicionam complexidades diferentes. Com o idioma "ants in your pants", no inglês americano "pants" refere-se a roupa exterior, enquanto no inglês britânico, "pants" é roupa interior. + +✅ Se falas vários idiomas, pensa em algumas frases que não traduzem diretamente. + +Sistemas de tradução automática dependem de grandes bases de dados de regras que descrevem como traduzir certas frases e idiomas, juntamente com métodos estatísticos para escolher as traduções apropriadas entre as opções possíveis. Estes métodos estatísticos usam enormes bases de dados de obras traduzidas por humanos em vários idiomas para escolher a tradução mais provável, uma técnica chamada *tradução automática estatística*. Muitos destes sistemas usam representações intermediárias do idioma, permitindo que um idioma seja traduzido para o intermediário e, depois, do intermediário para outro idioma. Desta forma, adicionar mais idiomas envolve traduções para e do intermediário, e não para e de todos os outros idiomas. + +### Traduções neurais + +Traduções neurais envolvem usar o poder da IA para traduzir, normalmente traduzindo frases inteiras usando um único modelo. Estes modelos são treinados em enormes conjuntos de dados que foram traduzidos por humanos, como páginas web, livros e documentação das Nações Unidas. + +Modelos de tradução neural são geralmente menores do que modelos de tradução automática, pois não precisam de grandes bases de dados de frases e idiomas. Serviços modernos de IA que fornecem traduções frequentemente misturam várias técnicas, combinando tradução automática estatística e tradução neural. + +Não existe uma tradução 1:1 para qualquer par de idiomas. Diferentes modelos de tradução produzirão resultados ligeiramente diferentes dependendo dos dados usados para treinar o modelo. Traduções nem sempre são simétricas - ou seja, se traduzires uma frase de um idioma para outro e depois de volta para o primeiro idioma, podes obter uma frase ligeiramente diferente como resultado. + +✅ Experimenta diferentes tradutores online, como [Bing Translate](https://www.bing.com/translator), [Google Translate](https://translate.google.com) ou a aplicação de tradução da Apple. Compara as versões traduzidas de algumas frases. Também tenta traduzir numa ferramenta e depois traduzir de volta noutra. + +## Serviços de tradução + +Existem vários serviços de IA que podem ser usados nas tuas aplicações para traduzir fala e texto. + +### Serviço de fala dos serviços cognitivos + +![O logótipo do serviço de fala](../../../../../translated_images/pt-PT/azure-speech-logo.a1f08c4befb0159f2cb5d692d3baf5b599e7b44759d316da907bda1508f46a4a.png) + +O serviço de fala que tens usado nas últimas lições tem capacidades de tradução para reconhecimento de fala. Quando reconheces fala, podes solicitar não apenas o texto da fala no mesmo idioma, mas também noutros idiomas. + +> 💁 Isto está disponível apenas no SDK de fala; a API REST não tem traduções integradas. + +### Serviço de tradutor dos serviços cognitivos + +![O logótipo do serviço de tradutor](../../../../../translated_images/pt-PT/azure-translator-logo.c6ed3a4a433edfd2f11577eca105412c50b8396b194cbbd730723dd1d0793bcd.png) + +O serviço de tradutor é um serviço dedicado de tradução que pode traduzir texto de um idioma para um ou mais idiomas-alvo. Além de traduzir, suporta uma ampla gama de recursos adicionais, incluindo mascarar palavrões. Também permite fornecer uma tradução específica para uma palavra ou frase, para trabalhar com termos que não queres traduzir ou que têm uma tradução bem conhecida. + +Por exemplo, ao traduzir a frase "I have a Raspberry Pi", referindo-se ao computador de placa única, para outro idioma como francês, querias manter o nome "Raspberry Pi" como está e não traduzi-lo, resultando em "J’ai un Raspberry Pi" em vez de "J’ai une pi aux framboises". + +## Criar um recurso de tradutor + +Para esta lição, vais precisar de um recurso de tradutor. Vais usar a API REST para traduzir texto. + +### Tarefa - criar um recurso de tradutor + +1. No teu terminal ou prompt de comando, executa o seguinte comando para criar um recurso de tradutor no teu grupo de recursos `smart-timer`. + + ```sh + az cognitiveservices account create --name smart-timer-translator \ + --resource-group smart-timer \ + --kind TextTranslation \ + --sku F0 \ + --yes \ + --location + ``` + + Substitui `` pela localização que usaste ao criar o grupo de recursos. + +1. Obtém a chave para o serviço de tradutor: + + ```sh + az cognitiveservices account keys list --name smart-timer-translator \ + --resource-group smart-timer \ + --output table + ``` + + Faz uma cópia de uma das chaves. + +## Suportar múltiplos idiomas em aplicações com traduções + +Num mundo ideal, toda a tua aplicação deveria compreender o maior número possível de idiomas diferentes, desde ouvir fala, até compreender linguagem e responder com fala. Isto dá muito trabalho, então os serviços de tradução podem acelerar o tempo de entrega da tua aplicação. + +![Uma arquitetura de temporizador inteligente traduzindo japonês para inglês, processando em inglês e depois traduzindo de volta para japonês](../../../../../translated_images/pt-PT/translated-smart-timer.08ac20057fdc5c37.webp) + +Imagina que estás a construir um temporizador inteligente que usa inglês de ponta a ponta, compreendendo inglês falado e convertendo-o em texto, executando a compreensão de linguagem em inglês, construindo respostas em inglês e respondendo com fala em inglês. Se quisesses adicionar suporte para japonês, poderias começar por traduzir japonês falado para texto em inglês, mantendo o núcleo da aplicação igual, e depois traduzir o texto da resposta para japonês antes de falar a resposta. Isto permitiria adicionar suporte para japonês rapidamente, e poderias expandir para fornecer suporte completo de ponta a ponta em japonês mais tarde. + +> 💁 A desvantagem de depender de tradução automática é que diferentes idiomas e culturas têm formas diferentes de dizer as mesmas coisas, então a tradução pode não corresponder à expressão que estás a esperar. + +Traduções automáticas também abrem possibilidades para aplicações e dispositivos que podem traduzir conteúdo criado pelo utilizador à medida que é criado. A ficção científica regularmente apresenta 'tradutores universais', dispositivos que podem traduzir de idiomas alienígenas para (tipicamente) inglês americano. Estes dispositivos são menos ficção científica e mais realidade científica, se ignorarmos a parte dos alienígenas. Já existem aplicações e dispositivos que fornecem tradução em tempo real de fala e texto escrito, usando combinações de serviços de fala e tradução. + +Um exemplo é a aplicação para telemóvel [Microsoft Translator](https://www.microsoft.com/translator/apps/?WT.mc_id=academic-17441-jabenn), demonstrada neste vídeo: + +[![Funcionalidade ao vivo do Microsoft Translator em ação](https://img.youtube.com/vi/16yAGeP2FuM/0.jpg)](https://www.youtube.com/watch?v=16yAGeP2FuM) + +> 🎥 Clique na imagem acima para assistir ao vídeo + +Imagina ter um dispositivo como este disponível, especialmente ao viajar ou interagir com pessoas cujo idioma não conheces. Ter dispositivos de tradução automáticos em aeroportos ou hospitais proporcionaria melhorias muito necessárias em acessibilidade. + +✅ Faz alguma pesquisa: Existem dispositivos IoT de tradução disponíveis comercialmente? E capacidades de tradução integradas em dispositivos inteligentes? + +> 👽 Embora não existam verdadeiros tradutores universais que nos permitam falar com alienígenas, o [Microsoft Translator suporta Klingon](https://www.microsoft.com/translator/blog/2013/05/14/announcing-klingon-for-bing-translator/?WT.mc_id=academic-17441-jabenn). Qapla’! + +## Traduzir texto usando um serviço de IA + +Podes usar um serviço de IA para adicionar esta capacidade de tradução ao teu temporizador inteligente. + +### Tarefa - traduzir texto usando um serviço de IA + +Segue o guia relevante para converter texto traduzido no teu dispositivo IoT: + +* [Arduino - Wio Terminal](wio-terminal-translate-speech.md) +* [Computador de placa única - Raspberry Pi](pi-translate-speech.md) +* [Computador de placa única - Dispositivo virtual](virtual-device-translate-speech.md) + +--- + +## 🚀 Desafio + +Como podem as traduções automáticas beneficiar outras aplicações IoT além de dispositivos inteligentes? Pensa em diferentes formas de como as traduções podem ajudar, não apenas com palavras faladas, mas também com texto. + +## Questionário pós-aula + +[Questionário pós-aula](https://black-meadow-040d15503.1.azurestaticapps.net/quiz/48) + +## Revisão e Autoestudo + +* Lê mais sobre tradução automática na [página de tradução automática na Wikipedia](https://wikipedia.org/wiki/Machine_translation) +* Lê mais sobre tradução automática neural na [página de tradução automática neural na Wikipedia](https://wikipedia.org/wiki/Neural_machine_translation) +* Consulta a lista de idiomas suportados pelos serviços de fala da Microsoft na [documentação de suporte de idiomas e vozes para o serviço de fala no Microsoft Docs](https://docs.microsoft.com/azure/cognitive-services/speech-service/language-support?WT.mc_id=academic-17441-jabenn) + +## Exercício + +[Constrói um tradutor universal](assignment.md) + +**Aviso Legal**: +Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes do uso desta tradução. \ No newline at end of file diff --git a/translations/pt-PT/6-consumer/lessons/4-multiple-language-support/assignment.md b/translations/pt-PT/6-consumer/lessons/4-multiple-language-support/assignment.md new file mode 100644 index 000000000..7484efa46 --- /dev/null +++ b/translations/pt-PT/6-consumer/lessons/4-multiple-language-support/assignment.md @@ -0,0 +1,20 @@ +# Construir um tradutor universal + +## Instruções + +Um tradutor universal é um dispositivo que pode traduzir entre várias línguas, permitindo que pessoas que falam idiomas diferentes consigam comunicar-se. Use o que aprendeu nas últimas lições para construir um tradutor universal utilizando 2 dispositivos IoT. + +> Se não tiver 2 dispositivos, siga os passos das últimas lições para configurar um dispositivo IoT virtual como um dos dispositivos IoT. + +Deve configurar um dispositivo para um idioma e outro para outro. Cada dispositivo deve aceitar fala, convertê-la em texto, enviá-la para o outro dispositivo através do IoT Hub e de uma aplicação Functions, depois traduzi-la e reproduzir a fala traduzida. + +> 💁 Dica: Ao enviar a fala de um dispositivo para outro, envie também o idioma em que está, facilitando a tradução. Pode até fazer com que cada dispositivo se registe primeiro utilizando o IoT Hub e uma aplicação Functions, passando o idioma que suportam para ser armazenado no Azure Storage. Depois, pode usar uma aplicação Functions para realizar as traduções, enviando o texto traduzido para o dispositivo IoT. + +## Critérios de Avaliação + +| Critério | Exemplar | Adequado | Necessita Melhorias | +| -------- | --------- | -------- | ------------------- | +| Criar um tradutor universal | Conseguiu construir um tradutor universal, convertendo a fala detectada por um dispositivo em fala reproduzida por outro dispositivo num idioma diferente | Conseguiu fazer funcionar alguns componentes, como capturar fala ou traduzir, mas não conseguiu construir a solução completa de ponta a ponta | Não conseguiu construir nenhuma parte de um tradutor universal funcional | + +**Aviso Legal**: +Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos pela precisão, esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes do uso desta tradução. \ No newline at end of file diff --git a/translations/pt-PT/6-consumer/lessons/4-multiple-language-support/pi-translate-speech.md b/translations/pt-PT/6-consumer/lessons/4-multiple-language-support/pi-translate-speech.md new file mode 100644 index 000000000..86c3cb651 --- /dev/null +++ b/translations/pt-PT/6-consumer/lessons/4-multiple-language-support/pi-translate-speech.md @@ -0,0 +1,153 @@ +# Traduzir discurso - Raspberry Pi + +Nesta parte da lição, vais escrever código para traduzir texto utilizando o serviço de tradução. + +## Converter texto em discurso utilizando o serviço de tradução + +A API REST do serviço de discurso não suporta traduções diretas. Em vez disso, podes usar o serviço Translator para traduzir o texto gerado pelo serviço de conversão de discurso para texto e o texto da resposta falada. Este serviço tem uma API REST que podes usar para traduzir o texto. + +### Tarefa - usar o recurso Translator para traduzir texto + +1. O teu temporizador inteligente terá 2 idiomas definidos - o idioma do servidor que foi usado para treinar o LUIS (o mesmo idioma também é usado para construir as mensagens para falar com o utilizador) e o idioma falado pelo utilizador. Atualiza a variável `language` para ser o idioma que será falado pelo utilizador e adiciona uma nova variável chamada `server_language` para o idioma usado para treinar o LUIS: + + ```python + language = '' + server_language = '' + ``` + + Substitui `` pelo nome da localidade do idioma que vais falar, por exemplo, `fr-FR` para francês ou `zn-HK` para cantonês. + + Substitui `` pelo nome da localidade do idioma usado para treinar o LUIS. + + Podes encontrar uma lista dos idiomas suportados e os seus nomes de localidade na [documentação de suporte de idiomas e vozes nos Microsoft Docs](https://docs.microsoft.com/azure/cognitive-services/speech-service/language-support?WT.mc_id=academic-17441-jabenn#speech-to-text). + + > 💁 Se não falas vários idiomas, podes usar um serviço como [Bing Translate](https://www.bing.com/translator) ou [Google Translate](https://translate.google.com) para traduzir do teu idioma preferido para um idioma à tua escolha. Estes serviços podem reproduzir áudio do texto traduzido. + > + > Por exemplo, se treinares o LUIS em inglês, mas quiseres usar francês como idioma do utilizador, podes traduzir frases como "set a 2 minute and 27 second timer" de inglês para francês usando o Bing Translate e, em seguida, usar o botão **Ouvir tradução** para falar a tradução no teu microfone. + > + > ![O botão ouvir tradução no Bing Translate](../../../../../translated_images/pt-PT/bing-translate.348aa796d6efe2a92f41ea74a5cf42bb4c63d6faaa08e7f46924e072a35daa48.png) + +1. Adiciona a chave da API do Translator abaixo da `speech_api_key`: + + ```python + translator_api_key = '' + ``` + + Substitui `` pela chave da API do recurso do serviço Translator. + +1. Acima da função `say`, define uma função `translate_text` que irá traduzir texto do idioma do servidor para o idioma do utilizador: + + ```python + def translate_text(text, from_language, to_language): + ``` + + Os idiomas de origem e destino são passados para esta função - a tua aplicação precisa de converter do idioma do utilizador para o idioma do servidor ao reconhecer discurso e do idioma do servidor para o idioma do utilizador ao fornecer feedback falado. + +1. Dentro desta função, define o URL e os cabeçalhos para a chamada da API REST: + + ```python + url = f'https://api.cognitive.microsofttranslator.com/translate?api-version=3.0' + + headers = { + 'Ocp-Apim-Subscription-Key': translator_api_key, + 'Ocp-Apim-Subscription-Region': location, + 'Content-type': 'application/json' + } + ``` + + O URL desta API não é específico de localização; em vez disso, a localização é passada como um cabeçalho. A chave da API é usada diretamente, por isso, ao contrário do serviço de discurso, não é necessário obter um token de acesso da API emissora de tokens. + +1. Abaixo disso, define os parâmetros e o corpo para a chamada: + + ```python + params = { + 'from': from_language, + 'to': to_language + } + + body = [{ + 'text' : text + }] + ``` + + Os `params` definem os parâmetros a passar para a chamada da API, passando os idiomas de origem e destino. Esta chamada irá traduzir texto no idioma `from` para o idioma `to`. + + O `body` contém o texto a ser traduzido. Este é um array, pois vários blocos de texto podem ser traduzidos na mesma chamada. + +1. Faz a chamada à API REST e obtém a resposta: + + ```python + response = requests.post(url, headers=headers, params=params, json=body) + ``` + + A resposta que retorna é um array JSON, com um item que contém as traduções. Este item tem um array para as traduções de todos os itens passados no corpo. + + ```json + [ + { + "translations": [ + { + "text": "Set a 2 minute 27 second timer.", + "to": "en" + } + ] + } + ] + ``` + +1. Retorna a propriedade `text` da primeira tradução do primeiro item no array: + + ```python + return response.json()[0]['translations'][0]['text'] + ``` + +1. Atualiza o loop `while True` para traduzir o texto da chamada para `convert_speech_to_text` do idioma do utilizador para o idioma do servidor: + + ```python + if len(text) > 0: + print('Original:', text) + text = translate_text(text, language, server_language) + print('Translated:', text) + + message = Message(json.dumps({ 'speech': text })) + device_client.send_message(message) + ``` + + Este código também imprime as versões original e traduzida do texto na consola. + +1. Atualiza a função `say` para traduzir o texto a ser dito do idioma do servidor para o idioma do utilizador: + + ```python + def say(text): + print('Original:', text) + text = translate_text(text, server_language, language) + print('Translated:', text) + speech = get_speech(text) + play_speech(speech) + ``` + + Este código também imprime as versões original e traduzida do texto na consola. + +1. Executa o teu código. Certifica-te de que a tua aplicação de função está a funcionar e solicita um temporizador no idioma do utilizador, seja falando esse idioma tu mesmo ou usando uma aplicação de tradução. + + ```output + pi@raspberrypi:~/smart-timer $ python3 app.py + Connecting + Connected + Using voice fr-FR-DeniseNeural + Original: Définir une minuterie de 2 minutes et 27 secondes. + Translated: Set a timer of 2 minutes and 27 seconds. + Original: 2 minute 27 second timer started. + Translated: 2 minute 27 seconde minute a commencé. + Original: Times up on your 2 minute 27 second timer. + Translated: Chronométrant votre minuterie de 2 minutes 27 secondes. + ``` + + > 💁 Devido às diferentes formas de dizer algo em diferentes idiomas, podes obter traduções que são ligeiramente diferentes dos exemplos que deste ao LUIS. Se for o caso, adiciona mais exemplos ao LUIS, treina novamente e publica o modelo. + +> 💁 Podes encontrar este código na pasta [code/pi](../../../../../6-consumer/lessons/4-multiple-language-support/code/pi). + +😀 O teu programa de temporizador multilingue foi um sucesso! + +**Aviso Legal**: +Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes do uso desta tradução. \ No newline at end of file diff --git a/translations/pt-PT/6-consumer/lessons/4-multiple-language-support/virtual-device-translate-speech.md b/translations/pt-PT/6-consumer/lessons/4-multiple-language-support/virtual-device-translate-speech.md new file mode 100644 index 000000000..72bd2ab9f --- /dev/null +++ b/translations/pt-PT/6-consumer/lessons/4-multiple-language-support/virtual-device-translate-speech.md @@ -0,0 +1,193 @@ +# Traduzir fala - Dispositivo Virtual IoT + +Nesta parte da lição, vais escrever código para traduzir fala ao convertê-la em texto usando o serviço de fala, e depois traduzir o texto usando o serviço Translator antes de gerar uma resposta falada. + +## Usar o serviço de fala para traduzir fala + +O serviço de fala pode captar fala e não só convertê-la em texto na mesma língua, mas também traduzir o resultado para outras línguas. + +### Tarefa - usar o serviço de fala para traduzir fala + +1. Abre o projeto `smart-timer` no VS Code e certifica-te de que o ambiente virtual está carregado no terminal. + +1. Adiciona as seguintes instruções de importação abaixo das importações existentes: + + ```python + from azure.cognitiveservices import speech + from azure.cognitiveservices.speech.translation import SpeechTranslationConfig, TranslationRecognizer + import requests + ``` + + Isto importa classes usadas para traduzir fala e uma biblioteca `requests` que será usada para fazer uma chamada ao serviço Translator mais tarde nesta lição. + +1. O teu temporizador inteligente terá 2 línguas definidas - a língua do servidor que foi usada para treinar o LUIS (a mesma língua também é usada para construir as mensagens para falar com o utilizador) e a língua falada pelo utilizador. Atualiza a variável `language` para ser a língua que será falada pelo utilizador e adiciona uma nova variável chamada `server_language` para a língua usada para treinar o LUIS: + + ```python + language = '' + server_language = '' + ``` + + Substitui `` pelo nome do locale da língua que vais falar, por exemplo, `fr-FR` para Francês ou `zn-HK` para Cantonês. + + Substitui `` pelo nome do locale da língua usada para treinar o LUIS. + + Podes encontrar uma lista das línguas suportadas e os seus nomes de locale na [documentação de suporte de línguas e vozes nos Microsoft docs](https://docs.microsoft.com/azure/cognitive-services/speech-service/language-support?WT.mc_id=academic-17441-jabenn#speech-to-text). + + > 💁 Se não falas várias línguas, podes usar um serviço como [Bing Translate](https://www.bing.com/translator) ou [Google Translate](https://translate.google.com) para traduzir da tua língua preferida para uma língua à tua escolha. Estes serviços podem reproduzir áudio do texto traduzido. Tem em atenção que o reconhecedor de fala ignorará algum áudio reproduzido pelo teu dispositivo, por isso podes precisar de usar um dispositivo adicional para reproduzir o texto traduzido. + > + > Por exemplo, se treinares o LUIS em Inglês, mas quiseres usar Francês como a língua do utilizador, podes traduzir frases como "set a 2 minute and 27 second timer" de Inglês para Francês usando o Bing Translate, e depois usar o botão **Listen translation** para falar a tradução no teu microfone. + > + > ![O botão de ouvir tradução no Bing Translate](../../../../../translated_images/pt-PT/bing-translate.348aa796d6efe2a92f41ea74a5cf42bb4c63d6faaa08e7f46924e072a35daa48.png) + +1. Substitui as declarações `recognizer_config` e `recognizer` pelo seguinte: + + ```python + translation_config = SpeechTranslationConfig(subscription=speech_api_key, + region=location, + speech_recognition_language=language, + target_languages=(language, server_language)) + + recognizer = TranslationRecognizer(translation_config=translation_config) + ``` + + Isto cria uma configuração de tradução para reconhecer fala na língua do utilizador e criar traduções na língua do utilizador e na língua do servidor. Depois usa esta configuração para criar um reconhecedor de tradução - um reconhecedor de fala que pode traduzir o resultado do reconhecimento de fala para várias línguas. + + > 💁 A língua original precisa de ser especificada em `target_languages`, caso contrário não obterás nenhuma tradução. + +1. Atualiza a função `recognized`, substituindo todo o conteúdo da função pelo seguinte: + + ```python + if args.result.reason == speech.ResultReason.TranslatedSpeech: + language_match = next(l for l in args.result.translations if server_language.lower().startswith(l.lower())) + text = args.result.translations[language_match] + if (len(text) > 0): + print(f'Translated text: {text}') + + message = Message(json.dumps({ 'speech': text })) + device_client.send_message(message) + ``` + + Este código verifica se o evento reconhecido foi acionado porque a fala foi traduzida (este evento pode ser acionado em outros momentos, como quando a fala é reconhecida mas não traduzida). Se a fala foi traduzida, encontra a tradução no dicionário `args.result.translations` que corresponde à língua do servidor. + + O dicionário `args.result.translations` é indexado pela parte da língua da configuração do locale, não pela configuração completa. Por exemplo, se pedires uma tradução para `fr-FR` para Francês, o dicionário conterá uma entrada para `fr`, não para `fr-FR`. + + O texto traduzido é então enviado para o IoT Hub. + +1. Executa este código para testar as traduções. Certifica-te de que a tua aplicação de função está a correr e pede um temporizador na língua do utilizador, seja falando essa língua tu mesmo ou usando uma aplicação de tradução. + + ```output + (.venv) ➜ smart-timer python app.py + Connecting + Connected + Translated text: Set a timer of 2 minutes and 27 seconds. + ``` + +## Traduzir texto usando o serviço Translator + +O serviço de fala não suporta tradução de texto de volta para fala, em vez disso podes usar o serviço Translator para traduzir o texto. Este serviço tem uma API REST que podes usar para traduzir o texto. + +### Tarefa - usar o recurso Translator para traduzir texto + +1. Adiciona a chave da API do Translator abaixo da `speech_api_key`: + + ```python + translator_api_key = '' + ``` + + Substitui `` pela chave da API para o recurso do serviço Translator. + +1. Acima da função `say`, define uma função `translate_text` que irá traduzir texto da língua do servidor para a língua do utilizador: + + ```python + def translate_text(text): + ``` + +1. Dentro desta função, define o URL e os cabeçalhos para a chamada da API REST: + + ```python + url = f'https://api.cognitive.microsofttranslator.com/translate?api-version=3.0' + + headers = { + 'Ocp-Apim-Subscription-Key': translator_api_key, + 'Ocp-Apim-Subscription-Region': location, + 'Content-type': 'application/json' + } + ``` + + O URL para esta API não é específico da localização, em vez disso, a localização é passada como um cabeçalho. A chave da API é usada diretamente, por isso, ao contrário do serviço de fala, não há necessidade de obter um token de acesso da API emissora de tokens. + +1. Abaixo disto, define os parâmetros e o corpo para a chamada: + + ```python + params = { + 'from': server_language, + 'to': language + } + + body = [{ + 'text' : text + }] + ``` + + Os `params` definem os parâmetros a passar para a chamada da API, passando as línguas de origem e destino. Esta chamada irá traduzir texto na língua `from` para a língua `to`. + + O `body` contém o texto a traduzir. Isto é um array, pois múltiplos blocos de texto podem ser traduzidos na mesma chamada. + +1. Faz a chamada à API REST e obtém a resposta: + + ```python + response = requests.post(url, headers=headers, params=params, json=body) + ``` + + A resposta que retorna é um array JSON, com um item que contém as traduções. Este item tem um array para traduções de todos os itens passados no corpo. + + ```json + [ + { + "translations": [ + { + "text": "Chronométrant votre minuterie de 2 minutes 27 secondes.", + "to": "fr" + } + ] + } + ] + ``` + +1. Retorna a propriedade `text` da primeira tradução do primeiro item no array: + + ```python + return response.json()[0]['translations'][0]['text'] + ``` + +1. Atualiza a função `say` para traduzir o texto a ser dito antes de o SSML ser gerado: + + ```python + print('Original:', text) + text = translate_text(text) + print('Translated:', text) + ``` + + Este código também imprime as versões original e traduzida do texto na consola. + +1. Executa o teu código. Certifica-te de que a tua aplicação de função está a correr e pede um temporizador na língua do utilizador, seja falando essa língua tu mesmo ou usando uma aplicação de tradução. + + ```output + (.venv) ➜ smart-timer python app.py + Connecting + Connected + Translated text: Set a timer of 2 minutes and 27 seconds. + Original: 2 minute 27 second timer started. + Translated: 2 minute 27 seconde minute a commencé. + Original: Times up on your 2 minute 27 second timer. + Translated: Chronométrant votre minuterie de 2 minutes 27 secondes. + ``` + + > 💁 Devido às diferentes formas de dizer algo em diferentes línguas, podes obter traduções que são ligeiramente diferentes dos exemplos que deste ao LUIS. Se for o caso, adiciona mais exemplos ao LUIS, treina novamente e publica o modelo. + +> 💁 Podes encontrar este código na pasta [code/virtual-iot-device](../../../../../6-consumer/lessons/4-multiple-language-support/code/virtual-iot-device). + +😀 O teu programa de temporizador multilingue foi um sucesso! + +**Aviso Legal**: +Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, é importante notar que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes da utilização desta tradução. \ No newline at end of file diff --git a/translations/pt-PT/6-consumer/lessons/4-multiple-language-support/wio-terminal-translate-speech.md b/translations/pt-PT/6-consumer/lessons/4-multiple-language-support/wio-terminal-translate-speech.md new file mode 100644 index 000000000..27ab17a22 --- /dev/null +++ b/translations/pt-PT/6-consumer/lessons/4-multiple-language-support/wio-terminal-translate-speech.md @@ -0,0 +1,273 @@ +# Traduzir discurso - Wio Terminal + +Nesta parte da lição, vais escrever código para traduzir texto utilizando o serviço de tradução. + +## Converter texto em discurso utilizando o serviço de tradução + +A API REST do serviço de discurso não suporta traduções diretas. Em vez disso, podes usar o serviço Translator para traduzir o texto gerado pelo serviço de discurso para texto, bem como o texto da resposta falada. Este serviço tem uma API REST que podes usar para traduzir o texto, mas para facilitar o uso, será encapsulado num outro trigger HTTP na tua aplicação de funções. + +### Tarefa - criar uma função serverless para traduzir texto + +1. Abre o teu projeto `smart-timer-trigger` no VS Code e abre o terminal, garantindo que o ambiente virtual está ativado. Caso contrário, termina e recria o terminal. + +1. Abre o ficheiro `local.settings.json` e adiciona as definições para a chave da API do Translator e a localização: + + ```json + "TRANSLATOR_KEY": "", + "TRANSLATOR_LOCATION": "" + ``` + + Substitui `` pela chave da API do recurso do serviço Translator. Substitui `` pela localização que utilizaste ao criar o recurso do serviço Translator. + +1. Adiciona um novo trigger HTTP a esta aplicação chamado `translate-text` utilizando o seguinte comando no terminal do VS Code, na pasta raiz do projeto da aplicação de funções: + + ```sh + func new --name translate-text --template "HTTP trigger" + ``` + + Isto criará um trigger HTTP chamado `translate-text`. + +1. Substitui o conteúdo do ficheiro `__init__.py` na pasta `translate-text` pelo seguinte: + + ```python + import logging + import os + import requests + + import azure.functions as func + + location = os.environ['TRANSLATOR_LOCATION'] + translator_key = os.environ['TRANSLATOR_KEY'] + + def main(req: func.HttpRequest) -> func.HttpResponse: + req_body = req.get_json() + from_language = req_body['from_language'] + to_language = req_body['to_language'] + text = req_body['text'] + + logging.info(f'Translating {text} from {from_language} to {to_language}') + + url = f'https://api.cognitive.microsofttranslator.com/translate?api-version=3.0' + + headers = { + 'Ocp-Apim-Subscription-Key': translator_key, + 'Ocp-Apim-Subscription-Region': location, + 'Content-type': 'application/json' + } + + params = { + 'from': from_language, + 'to': to_language + } + + body = [{ + 'text' : text + }] + + response = requests.post(url, headers=headers, params=params, json=body) + return func.HttpResponse(response.json()[0]['translations'][0]['text']) + ``` + + Este código extrai o texto e os idiomas do pedido HTTP. Em seguida, faz um pedido à API REST do Translator, passando os idiomas como parâmetros para o URL e o texto a traduzir como corpo. Finalmente, a tradução é devolvida. + +1. Executa a tua aplicação de funções localmente. Podes então chamá-la utilizando uma ferramenta como o curl, da mesma forma que testaste o trigger HTTP `text-to-timer`. Certifica-te de passar o texto a traduzir e os idiomas como um corpo JSON: + + ```json + { + "text": "Définir une minuterie de 30 secondes", + "from_language": "fr-FR", + "to_language": "en-US" + } + ``` + + Este exemplo traduz *Définir une minuterie de 30 secondes* de francês para inglês dos EUA. Ele retornará *Set a 30-second timer*. + +> 💁 Podes encontrar este código na pasta [code/functions](../../../../../6-consumer/lessons/4-multiple-language-support/code/functions). + +### Tarefa - usar a função Translator para traduzir texto + +1. Abre o projeto `smart-timer` no VS Code, caso ainda não esteja aberto. + +1. O teu temporizador inteligente terá 2 idiomas definidos - o idioma do servidor que foi usado para treinar o LUIS (o mesmo idioma também é usado para construir as mensagens para falar com o utilizador) e o idioma falado pelo utilizador. Atualiza a constante `LANGUAGE` no ficheiro de cabeçalho `config.h` para ser o idioma que será falado pelo utilizador e adiciona uma nova constante chamada `SERVER_LANGUAGE` para o idioma usado para treinar o LUIS: + + ```cpp + const char *LANGUAGE = ""; + const char *SERVER_LANGUAGE = ""; + ``` + + Substitui `` pelo nome do locale do idioma que vais falar, por exemplo, `fr-FR` para francês ou `zn-HK` para cantonês. + + Substitui `` pelo nome do locale do idioma usado para treinar o LUIS. + + Podes encontrar uma lista dos idiomas suportados e os seus nomes de locale na [documentação de suporte a idiomas e vozes nos Microsoft docs](https://docs.microsoft.com/azure/cognitive-services/speech-service/language-support?WT.mc_id=academic-17441-jabenn#speech-to-text). + + > 💁 Se não falas vários idiomas, podes usar um serviço como o [Bing Translate](https://www.bing.com/translator) ou o [Google Translate](https://translate.google.com) para traduzir do teu idioma preferido para um idioma à tua escolha. Estes serviços podem reproduzir áudio do texto traduzido. + > + > Por exemplo, se treinares o LUIS em inglês, mas quiseres usar francês como idioma do utilizador, podes traduzir frases como "set a 2 minute and 27 second timer" de inglês para francês usando o Bing Translate e, em seguida, usar o botão **Ouvir tradução** para falar a tradução no teu microfone. + > + > ![O botão ouvir tradução no Bing Translate](../../../../../translated_images/pt-PT/bing-translate.348aa796d6efe2a92f41ea74a5cf42bb4c63d6faaa08e7f46924e072a35daa48.png) + +1. Adiciona a chave da API do Translator e a localização abaixo de `SPEECH_LOCATION`: + + ```cpp + const char *TRANSLATOR_API_KEY = ""; + const char *TRANSLATOR_LOCATION = ""; + ``` + + Substitui `` pela chave da API do recurso do serviço Translator. Substitui `` pela localização que utilizaste ao criar o recurso do serviço Translator. + +1. Adiciona o URL do trigger do Translator abaixo de `VOICE_URL`: + + ```cpp + const char *TRANSLATE_FUNCTION_URL = ""; + ``` + + Substitui `` pelo URL do trigger HTTP `translate-text` na tua aplicação de funções. Este será o mesmo valor de `TEXT_TO_TIMER_FUNCTION_URL`, exceto com o nome da função `translate-text` em vez de `text-to-timer`. + +1. Adiciona um novo ficheiro à pasta `src` chamado `text_translator.h`. + +1. Este novo ficheiro de cabeçalho `text_translator.h` conterá uma classe para traduzir texto. Adiciona o seguinte a este ficheiro para declarar esta classe: + + ```cpp + #pragma once + + #include + #include + #include + #include + + #include "config.h" + + class TextTranslator + { + public: + private: + WiFiClient _client; + }; + + TextTranslator textTranslator; + ``` + + Isto declara a classe `TextTranslator`, juntamente com uma instância desta classe. A classe tem um único campo para o cliente WiFi. + +1. Na secção `public` desta classe, adiciona um método para traduzir texto: + + ```cpp + String translateText(String text, String from_language, String to_language) + { + } + ``` + + Este método recebe o idioma de origem e o idioma de destino. Ao lidar com discurso, o discurso será traduzido do idioma do utilizador para o idioma do servidor LUIS, e ao dar respostas, será traduzido do idioma do servidor LUIS para o idioma do utilizador. + +1. Neste método, adiciona código para construir um corpo JSON contendo o texto a traduzir e os idiomas: + + ```cpp + DynamicJsonDocument doc(1024); + doc["text"] = text; + doc["from_language"] = from_language; + doc["to_language"] = to_language; + + String body; + serializeJson(doc, body); + + Serial.print("Translating "); + Serial.print(text); + Serial.print(" from "); + Serial.print(from_language); + Serial.print(" to "); + Serial.print(to_language); + ``` + +1. Abaixo disso, adiciona o seguinte código para enviar o corpo para a aplicação de funções serverless: + + ```cpp + HTTPClient httpClient; + httpClient.begin(_client, TRANSLATE_FUNCTION_URL); + + int httpResponseCode = httpClient.POST(body); + ``` + +1. Em seguida, adiciona código para obter a resposta: + + ```cpp + String translated_text = ""; + + if (httpResponseCode == 200) + { + translated_text = httpClient.getString(); + Serial.print("Translated: "); + Serial.println(translated_text); + } + else + { + Serial.print("Failed to translate text - error "); + Serial.println(httpResponseCode); + } + ``` + +1. Finalmente, adiciona código para fechar a conexão e devolver o texto traduzido: + + ```cpp + httpClient.end(); + + return translated_text; + ``` + +### Tarefa - traduzir o discurso reconhecido e as respostas + +1. Abre o ficheiro `main.cpp`. + +1. Adiciona uma diretiva de inclusão no topo do ficheiro para o ficheiro de cabeçalho da classe `TextTranslator`: + + ```cpp + #include "text_translator.h" + ``` + +1. O texto que é dito quando um temporizador é definido ou expira precisa de ser traduzido. Para isso, adiciona o seguinte como a primeira linha da função `say`: + + ```cpp + text = textTranslator.translateText(text, LANGUAGE, SERVER_LANGUAGE); + ``` + + Isto traduzirá o texto para o idioma do utilizador. + +1. Na função `processAudio`, o texto é recuperado do áudio capturado com a chamada `String text = speechToText.convertSpeechToText();`. Após esta chamada, traduz o texto: + + ```cpp + String text = speechToText.convertSpeechToText(); + text = textTranslator.translateText(text, LANGUAGE, SERVER_LANGUAGE); + ``` + + Isto traduzirá o texto do idioma do utilizador para o idioma usado no servidor. + +1. Compila este código, carrega-o no teu Wio Terminal e testa-o através do monitor serial. Assim que vires `Ready` no monitor serial, pressiona o botão C (o do lado esquerdo, mais próximo do interruptor de energia) e fala. Certifica-te de que a tua aplicação de funções está em execução e pede um temporizador no idioma do utilizador, seja falando esse idioma ou usando uma aplicação de tradução. + + ```output + Connecting to WiFi.. + Connected! + Got access token. + Ready. + Starting recording... + Finished recording + Sending speech... + Speech sent! + {"RecognitionStatus":"Success","DisplayText":"Définir une minuterie de 2 minutes 27 secondes.","Offset":9600000,"Duration":40400000} + Translating Définir une minuterie de 2 minutes 27 secondes. from fr-FR to en-US + Translated: Set a timer of 2 minutes 27 seconds. + Set a timer of 2 minutes 27 seconds. + {"seconds": 147} + Translating 2 minute 27 second timer started. from en-US to fr-FR + Translated: 2 minute 27 seconde minute a commencé. + 2 minute 27 seconde minute a commencé. + Translating Times up on your 2 minute 27 second timer. from en-US to fr-FR + Translated: Chronométrant votre minuterie de 2 minutes 27 secondes. + Chronométrant votre minuterie de 2 minutes 27 secondes. + ``` + +> 💁 Podes encontrar este código na pasta [code/wio-terminal](../../../../../6-consumer/lessons/4-multiple-language-support/code/wio-terminal). + +😀 O teu programa de temporizador multilingue foi um sucesso! + +**Aviso Legal**: +Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, tenha em atenção que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes da utilização desta tradução. \ No newline at end of file diff --git a/translations/pt-PT/CODE_OF_CONDUCT.md b/translations/pt-PT/CODE_OF_CONDUCT.md new file mode 100644 index 000000000..84daa79b4 --- /dev/null +++ b/translations/pt-PT/CODE_OF_CONDUCT.md @@ -0,0 +1,12 @@ +# Código de Conduta de Código Aberto da Microsoft + +Este projeto adotou o [Código de Conduta de Código Aberto da Microsoft](https://opensource.microsoft.com/codeofconduct/). + +Recursos: + +- [Código de Conduta de Código Aberto da Microsoft](https://opensource.microsoft.com/codeofconduct/) +- [FAQ do Código de Conduta da Microsoft](https://opensource.microsoft.com/codeofconduct/faq/) +- Contacte [opencode@microsoft.com](mailto:opencode@microsoft.com) para questões ou preocupações + +**Aviso Legal**: +Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original no seu idioma nativo deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se uma tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas resultantes do uso desta tradução. \ No newline at end of file diff --git a/translations/pt-PT/CONTRIBUTING.md b/translations/pt-PT/CONTRIBUTING.md new file mode 100644 index 000000000..c6c1261e3 --- /dev/null +++ b/translations/pt-PT/CONTRIBUTING.md @@ -0,0 +1,14 @@ +# Contribuir + +Este projeto acolhe contribuições e sugestões. A maioria das contribuições requer que concorde com um Acordo de Licença de Contribuidor (CLA), declarando que tem o direito de, e realmente concede-nos, os direitos para usar a sua contribuição. Para mais detalhes, visite https://cla.microsoft.com. + +> Importante: ao traduzir texto neste repositório, certifique-se de que não utiliza tradução automática. Vamos verificar as traduções através da comunidade, por isso, só se ofereça para traduzir em línguas nas quais é proficiente. + +Quando submeter um pull request, um CLA-bot determinará automaticamente se precisa de fornecer um CLA e decorará o PR de forma apropriada (por exemplo, etiqueta, comentário). Basta seguir as instruções fornecidas pelo bot. Só precisará de fazer isto uma vez em todos os repositórios que utilizam o nosso CLA. + +Este projeto adotou o [Código de Conduta de Código Aberto da Microsoft](https://opensource.microsoft.com/codeofconduct/). +Para mais informações, leia as [Perguntas Frequentes sobre o Código de Conduta](https://opensource.microsoft.com/codeofconduct/faq/) +ou contacte [opencode@microsoft.com](mailto:opencode@microsoft.com) para quaisquer questões ou comentários adicionais. + +**Aviso Legal**: +Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos pela precisão, esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes do uso desta tradução. \ No newline at end of file diff --git a/translations/pt-PT/README.md b/translations/pt-PT/README.md new file mode 100644 index 000000000..738d8d5b7 --- /dev/null +++ b/translations/pt-PT/README.md @@ -0,0 +1,213 @@ +[![GitHub license](https://img.shields.io/github/license/microsoft/IoT-For-Beginners.svg)](https://github.com/microsoft/IoT-For-Beginners/blob/master/LICENSE) +[![GitHub contributors](https://img.shields.io/github/contributors/microsoft/IoT-For-Beginners.svg)](https://GitHub.com/microsoft/IoT-For-Beginners/graphs/contributors/) +[![GitHub issues](https://img.shields.io/github/issues/microsoft/IoT-For-Beginners.svg)](https://GitHub.com/microsoft/IoT-For-Beginners/issues/) +[![GitHub pull-requests](https://img.shields.io/github/issues-pr/microsoft/IoT-For-Beginners.svg)](https://GitHub.com/microsoft/IoT-For-Beginners/pulls/) +[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com) + +[![GitHub watchers](https://img.shields.io/github/watchers/microsoft/IoT-For-Beginners.svg?style=social&label=Watch)](https://GitHub.com/microsoft/IoT-For-Beginners/watchers/) +[![GitHub forks](https://img.shields.io/github/forks/microsoft/IoT-For-Beginners.svg?style=social&label=Fork)](https://GitHub.com/microsoft/IoT-For-Beginners/network/) +[![GitHub stars](https://img.shields.io/github/stars/microsoft/IoT-For-Beginners.svg?style=social&label=Star)](https://GitHub.com/microsoft/IoT-For-Beginners/stargazers/) + +### Junte-se à Comunidade Azure AI Foundry + +Se ficar preso ou tiver alguma dúvida sobre como construir aplicações de IA. Junte-se a outros aprendizes e desenvolvedores experientes em discussões sobre MCP. É uma comunidade de apoio onde as perguntas são bem-vindas e o conhecimento é compartilhado livremente. + +[![Microsoft Foundry Discord](https://dcbadge.limes.pink/api/server/nTYy5BXMWG)](https://discord.gg/nTYy5BXMWG) + +Se tiver feedback sobre o produto ou encontrar erros durante a construção, visite: + +[![Microsoft Foundry Developer Forum](https://img.shields.io/badge/GitHub-Microsoft_Foundry_Developer_Forum-blue?style=for-the-badge&logo=github&color=000000&logoColor=fff)](https://aka.ms/foundry/forum) + +Siga estes passos para começar a usar estes recursos: +1. **Faça um Fork do Repositório**: Clique [![GitHub forks](https://img.shields.io/github/forks/microsoft/IoT-For-Beginners.svg?style=social&label=Fork)](https://GitHub.com/microsoft/IoT-For-Beginners/fork) +2. **Clone o Repositório**: `git clone https://github.com/microsoft/IoT-For-Beginners.git` +3. [**Junte-se ao Microsoft Foundry Discord e conheça especialistas e outros desenvolvedores**](https://discord.com/invite/ByRwuEEgH4) + + +### 🌐 Suporte Multilíngue + +#### Suportado via GitHub Action (Automatizado e Sempre Atualizado) + + +[Árabe](../ar/README.md) | [Bengali](../bn/README.md) | [Búlgaro](../bg/README.md) | [Birmanês (Myanmar)](../my/README.md) | [Chinês (Simplificado)](../zh-CN/README.md) | [Chinês (Tradicional, Hong Kong)](../zh-HK/README.md) | [Chinês (Tradicional, Macau)](../zh-MO/README.md) | [Chinês (Tradicional, Taiwan)](../zh-TW/README.md) | [Croata](../hr/README.md) | [Checo](../cs/README.md) | [Dinamarquês](../da/README.md) | [Holandês](../nl/README.md) | [Estónio](../et/README.md) | [Finlandês](../fi/README.md) | [Francês](../fr/README.md) | [Alemão](../de/README.md) | [Grego](../el/README.md) | [Hebraico](../he/README.md) | [Hindi](../hi/README.md) | [Húngaro](../hu/README.md) | [Indonésio](../id/README.md) | [Italiano](../it/README.md) | [Japonês](../ja/README.md) | [Kannada](../kn/README.md) | [Coreano](../ko/README.md) | [Lituano](../lt/README.md) | [Malaio](../ms/README.md) | [Malayalam](../ml/README.md) | [Marati](../mr/README.md) | [Nepalês](../ne/README.md) | [Pidgin Nigeriano](../pcm/README.md) | [Norueguês](../no/README.md) | [Persa (Farsi)](../fa/README.md) | [Polaco](../pl/README.md) | [Português (Brasil)](../pt-BR/README.md) | [Português (Portugal)](./README.md) | [Punjabi (Gurmukhi)](../pa/README.md) | [Romeno](../ro/README.md) | [Russo](../ru/README.md) | [Sérvio (Cirílico)](../sr/README.md) | [Eslovaco](../sk/README.md) | [Esloveno](../sl/README.md) | [Espanhol](../es/README.md) | [Suaíli](../sw/README.md) | [Sueco](../sv/README.md) | [Tagalo (Filipino)](../tl/README.md) | [Tamil](../ta/README.md) | [Telugu](../te/README.md) | [Tailandês](../th/README.md) | [Turco](../tr/README.md) | [Ucraniano](../uk/README.md) | [Urdu](../ur/README.md) | [Vietnamita](../vi/README.md) + +> **Prefere Clonar Localmente?** + +> Este repositório inclui traduções para mais de 50 línguas, o que aumenta significativamente o tamanho de download. Para clonar sem as traduções, use checkout esparso: +> ```bash +> git clone --filter=blob:none --sparse https://github.com/microsoft/IoT-For-Beginners.git +> cd IoT-For-Beginners +> git sparse-checkout set --no-cone '/*' '!translations' '!translated_images' +> ``` +> Isto dá-lhe tudo o que precisa para completar o curso com um download muito mais rápido. + + +# IoT para Iniciantes - Um Currículo + +Os Advocates do Azure Cloud na Microsoft têm o prazer de oferecer um currículo de 12 semanas e 24 lições totalmente focado nos fundamentos de IoT. Cada lição inclui questionários antes e depois da aula, instruções escritas para completar a lição, uma solução, uma tarefa e muito mais. A nossa pedagogia baseada em projetos permite que aprenda enquanto constrói, uma forma comprovada para que novas competências sejam assimiladas. + +Os projetos cobrem a jornada dos alimentos desde a quinta até à mesa. Isso inclui agricultura, logística, fabrico, retalho e consumidor — todas áreas industriais populares para dispositivos IoT. + +![Um roteiro do curso mostrando 24 lições que cobrem introdução, agricultura, transporte, processamento, retalho e cozinha](../../translated_images/pt-PT/Roadmap.bb1dec285dda0eda.webp) + +> Esquema desenhado por [Nitya Narasimhan](https://github.com/nitya). Clique na imagem para uma versão maior. + +**Um grande obrigado aos nossos autores [Jen Fox](https://github.com/jenfoxbot), [Jen Looper](https://github.com/jlooper), [Jim Bennett](https://github.com/jimbobbennett), e ao nosso artista dos esboços [Nitya Narasimhan](https://github.com/nitya).** + +**Obrigado também à nossa equipa de [Microsoft Learn Student Ambassadors](https://studentambassadors.microsoft.com?WT.mc_id=academic-17441-jabenn) que têm revisto e traduzido este currículo - [Aditya Garg](https://github.com/AdityaGarg00), [Anurag Sharma](https://github.com/Anurag-0-1-A), [Arpita Das](https://github.com/Arpiiitaaa), [Aryan Jain](https://www.linkedin.com/in/aryan-jain-47a4a1145/), [Bhavesh Suneja](https://github.com/EliteWarrior315), [Faith Hunja](https://faithhunja.github.io/), [Lateefah Bello](https://www.linkedin.com/in/lateefah-bello/), [Manvi Jha](https://github.com/Severus-Matthew), [Mireille Tan](https://www.linkedin.com/in/mireille-tan-a4834819a/), [Mohammad Iftekher (Iftu) Ebne Jalal](https://github.com/Iftu119), [Mohammad Zulfikar](https://github.com/mohzulfikar), [Priyanshu Srivastav](https://www.linkedin.com/in/priyanshu-srivastav-b067241ba), [Thanmai Gowducheruvu](https://github.com/innovation-platform), e [Zina Kamel](https://www.linkedin.com/in/zina-kamel/).** + +Conheça a equipa! + +[![Promo video](../../images/IOT.gif)](https://youtu.be/-wippUJRi5k) + +**Gif por** [Mohit Jaisal](https://linkedin.com/in/mohitjaisal) + +> 🎥 Clique na imagem acima para ver um vídeo sobre o projeto! + +> **Professores**, incluímos [algumas sugestões](for-teachers.md) sobre como usar este currículo. Se quiserem criar as vossas próprias lições, também incluímos um [modelo de lição](lesson-template/README.md). + +> **[Estudantes](https://aka.ms/student-page)**, para usar este currículo individualmente, façam fork do repositório completo e completem os exercícios por conta própria, começando por um questionário pré-aula, depois lendo a aula e completando as restantes atividades. Tentem criar os projetos compreendendo as lições em vez de copiar o código da solução; no entanto esse código está disponível nas pastas /solutions em cada lição orientada por projetos. Outra ideia seria formar um grupo de estudo com amigos e percorrerem o conteúdo juntos. Para estudo adicional, recomendamos [Microsoft Learn](https://docs.microsoft.com/users/jimbobbennett/collections/ke2ehd351jopwr?WT.mc_id=academic-17441-jabenn). + +Para uma visão geral em vídeo deste curso, veja este vídeo: + +[![Promo video](https://img.youtube.com/vi/bccEMm8gRuc/0.jpg)](https://youtube.com/watch?v=bccEMm8gRuc "Promo video") + +> 🎥 Clique na imagem acima para ver um vídeo sobre o projeto! + +## Pedagogia + +Escolhemos dois princípios pedagógicos ao construir este currículo: garantir que é baseado em projetos e que inclua questionários frequentes. Ao fim desta série, os alunos terão construído um sistema de monitorização e rega de plantas, um rastreador de veículos, uma instalação de fábrica inteligente para rastrear e verificar alimentos, um temporizador de cozinha controlado por voz, e terão aprendido os fundamentos da Internet das Coisas incluindo como escrever código para dispositivos, conectar à cloud, analisar telemetria e executar IA na edge. + +Ao garantir que o conteúdo está alinhado com projetos, o processo torna-se mais envolvente para os alunos e a retenção dos conceitos é aumentada. + +Além disso, um questionário de baixo risco antes da aula define a intenção do aluno para aprender um tópico, enquanto um segundo questionário após a aula assegura maior retenção. Este currículo foi desenhado para ser flexível e divertido podendo ser feito na totalidade ou em partes. Os projetos começam pequenos e tornam-se progressivamente mais complexos até ao fim do ciclo de 12 semanas. + +Cada projeto baseia-se em hardware do mundo real disponível para os alunos e entusiastas. Cada projeto explora o domínio específico, fornecendo conhecimento de fundo relevante. Para ser um desenvolvedor bem sucedido é útil compreender o domínio onde se resolvem problemas; ao fornecer este conhecimento de fundo, os alunos são capazes de pensar nas suas soluções e aprendizagens IoT no contexto do tipo de problema real que poderão ser desafiados a resolver como desenvolvedores IoT. Os alunos aprendem o ‘porquê’ das soluções que estão a construir e ganham uma apreciação do utilizador final. + +## Hardware + +Temos duas opções de hardware IoT para usar nos projetos, dependendo de preferência pessoal, conhecimento ou preferências de linguagem de programação, objetivos de aprendizagem e disponibilidade. Também fornecemos uma versão de ‘hardware virtual’ para quem não tem acesso a hardware, ou quer aprender mais antes de se comprometer a comprar. Pode ler mais e encontrar uma ‘lista de compras’ na [página de hardware](./hardware.md), incluindo links para comprar kits completos dos nossos amigos da Seeed Studio. +> 💁 Encontre as nossas orientações para o [Código de Conduta](CODE_OF_CONDUCT.md), [Contribuições](CONTRIBUTING.md), e [Traduções](TRANSLATIONS.md). Aguardamos o seu feedback construtivo! +> +> 🔧 Está com problemas? Consulte o nosso [Guia de Resolução de Problemas](TROUBLESHOOTING.md) para soluções às questões mais comuns. + +## Cada lição inclui: + +- sketchnote +- vídeo suplementar opcional +- quiz de aquecimento pré-lição +- lição escrita +- para lições baseadas em projetos, guias passo a passo sobre como construir o projeto +- verificações de conhecimento +- um desafio +- leitura suplementar +- tarefa +- [quiz pós-lição](https://ff-quizzes.netlify.app/en/) + +> **Uma nota sobre os quizzes**: Todos os quizzes estão contidos na pasta quiz-app, totalizando 48 quizzes com três perguntas cada. Eles estão ligados dentro das lições, mas a aplicação do quiz pode ser executada localmente ou implantada no Azure; siga as instruções na pasta `quiz-app`. Estão sendo gradualmente localizados. + +## Lições + +| | Nome do Projeto | Conceitos Ensinados | Objetivos de Aprendizagem | Lição Ligada | +| :---: | :--------------------------------------------: | :-------------------------------------------------------------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | :-------------------------------------------------------------------------------------------------------------------------------: | +| 01 | [Início rápido](./1-getting-started/README.md) | Introdução ao IoT | Aprenda os princípios básicos do IoT e os blocos básicos de construção das soluções IoT como sensores e serviços na nuvem enquanto configura o seu primeiro dispositivo IoT | [Introdução ao IoT](./1-getting-started/lessons/1-introduction-to-iot/README.md) | +| 02 | [Início rápido](./1-getting-started/README.md) | Uma exploração mais profunda do IoT | Aprenda mais sobre os componentes de um sistema IoT, assim como microcontroladores e computadores de placa única | [Uma exploração mais profunda do IoT](./1-getting-started/lessons/2-deeper-dive/README.md) | +| 03 | [Início rápido](./1-getting-started/README.md) | Interagir com o mundo físico com sensores e atuadores | Aprenda sobre sensores para recolher dados do mundo físico, e atuadores para enviar feedback, enquanto constrói uma luz de presença | [Interagir com o mundo físico com sensores e atuadores](./1-getting-started/lessons/3-sensors-and-actuators/README.md) | +| 04 | [Início rápido](./1-getting-started/README.md) | Ligue o seu dispositivo à Internet | Aprenda como ligar um dispositivo IoT à Internet para enviar e receber mensagens conectando a sua luz de presença a um broker MQTT | [Ligue o seu dispositivo à Internet](./1-getting-started/lessons/4-connect-internet/README.md) | +| 05 | [Fazenda](./2-farm/README.md) | Prever o crescimento da planta | Aprenda a prever o crescimento de plantas usando dados de temperatura capturados por um dispositivo IoT | [Prever o crescimento da planta](./2-farm/lessons/1-predict-plant-growth/README.md) | +| 06 | [Fazenda](./2-farm/README.md) | Detetar a humidade do solo | Aprenda a detetar a humidade do solo e calibrar um sensor de humidade do solo | [Detetar a humidade do solo](./2-farm/lessons/2-detect-soil-moisture/README.md) | +| 07 | [Fazenda](./2-farm/README.md) | Regar as plantas de forma automatizada | Aprenda a automatizar e temporizar a rega usando um relé e MQTT | [Regar as plantas de forma automatizada](./2-farm/lessons/3-automated-plant-watering/README.md) | +| 08 | [Fazenda](./2-farm/README.md) | Migrar a sua planta para a nuvem | Aprenda sobre a nuvem e serviços IoT hospedados na nuvem e como ligar a sua planta a um destes em vez de a um broker público MQTT | [Migrar a sua planta para a nuvem](./2-farm/lessons/4-migrate-your-plant-to-the-cloud/README.md) | +| 09 | [Fazenda](./2-farm/README.md) | Migrar a lógica da aplicação para a nuvem | Saiba como pode escrever lógica de aplicação na nuvem que responde a mensagens IoT | [Migrar a lógica da aplicação para a nuvem](./2-farm/lessons/5-migrate-application-to-the-cloud/README.md) | +| 10 | [Fazenda](./2-farm/README.md) | Mantenha a sua planta segura | Aprenda sobre segurança no IoT e como manter a sua planta segura com chaves e certificados | [Mantenha a sua planta segura](./2-farm/lessons/6-keep-your-plant-secure/README.md) | +| 11 | [Transportes](./3-transport/README.md) | Rastreio de localização | Aprenda sobre o rastreio da localização GPS para dispositivos IoT | [Rastreio de localização](./3-transport/lessons/1-location-tracking/README.md) | +| 12 | [Transportes](./3-transport/README.md) | Armazenar dados de localização | Aprenda a armazenar dados IoT para serem visualizados ou analisados mais tarde | [Armazenar dados de localização](./3-transport/lessons/2-store-location-data/README.md) | +| 13 | [Transportes](./3-transport/README.md) | Visualizar dados de localização | Aprenda a visualizar dados de localização num mapa e como os mapas representam o mundo 3D real em 2 dimensões | [Visualizar dados de localização](./3-transport/lessons/3-visualize-location-data/README.md) | +| 14 | [Transportes](./3-transport/README.md) | Geofences | Aprenda sobre geofences, e como podem ser usadas para alertar quando veículos na cadeia de fornecimento estão perto do seu destino | [Geofences](./3-transport/lessons/4-geofences/README.md) | +| 15 | [Manufatura](./4-manufacturing/README.md) | Treinar um detector de qualidade de fruta | Aprenda a treinar um classificador de imagens na nuvem para detetar a qualidade de fruta | [Treinar um detector de qualidade de fruta](./4-manufacturing/lessons/1-train-fruit-detector/README.md) | +| 16 | [Manufatura](./4-manufacturing/README.md) | Verificar a qualidade da fruta a partir de um dispositivo IoT | Aprenda a usar o seu detector de qualidade de fruta a partir de um dispositivo IoT | [Verificar a qualidade da fruta a partir de um dispositivo IoT](./4-manufacturing/lessons/2-check-fruit-from-device/README.md) | +| 17 | [Manufatura](./4-manufacturing/README.md) | Executar o seu detector de fruta na borda | Aprenda a executar o seu detector de fruta num dispositivo IoT na borda | [Executar o seu detector de fruta na borda](./4-manufacturing/lessons/3-run-fruit-detector-edge/README.md) | +| 18 | [Manufatura](./4-manufacturing/README.md) | Disparar a deteção de qualidade da fruta a partir de um sensor | Aprenda a disparar a deteção de qualidade da fruta a partir de um sensor | [Disparar a deteção de qualidade da fruta a partir de um sensor](./4-manufacturing/lessons/4-trigger-fruit-detector/README.md) | +| 19 | [Retalho](./5-retail/README.md) | Treinar um detector de stock | Aprenda a usar deteção de objetos para treinar um detector de stock para contar stock numa loja | [Treinar um detector de stock](./5-retail/lessons/1-train-stock-detector/README.md) | +| 20 | [Retalho](./5-retail/README.md) | Verificar stock a partir de um dispositivo IoT | Aprenda a verificar stock a partir de um dispositivo IoT usando um modelo de deteção de objetos | [Verificar stock a partir de um dispositivo IoT](./5-retail/lessons/2-check-stock-device/README.md) | +| 21 | [Consumidor](./6-consumer/README.md) | Reconhecer fala com um dispositivo IoT | Aprenda a reconhecer fala a partir de um dispositivo IoT para construir um temporizador inteligente | [Reconhecer fala com um dispositivo IoT](./6-consumer/lessons/1-speech-recognition/README.md) | +| 22 | [Consumidor](./6-consumer/README.md) | Compreender a linguagem | Aprenda a compreender frases faladas a um dispositivo IoT | [Compreender a linguagem](./6-consumer/lessons/2-language-understanding/README.md) | +| 23 | [Consumidor](./6-consumer/README.md) | Definir um temporizador e fornecer feedback falado | Aprenda a definir um temporizador num dispositivo IoT e fornecer feedback falado quando o temporizador é definido e quando termina | [Definir um temporizador e fornecer feedback falado](./6-consumer/lessons/3-spoken-feedback/README.md) | +| 24 | [Consumidor](./6-consumer/README.md) | Suportar múltiplas línguas | Aprenda a suportar múltiplas línguas, tanto as que lhe são faladas como as respostas do seu temporizador inteligente | [Suportar múltiplas línguas](./6-consumer/lessons/4-multiple-language-support/README.md) | + +## Acesso offline + +Pode executar esta documentação offline usando o [Docsify](https://docsify.js.org/#/). Faça fork deste repositório, [instale o Docsify](https://docsify.js.org/#/quickstart) na sua máquina local e, na pasta raiz deste repositório, digite `docsify serve`. O website será servido na porta 3000 no seu localhost: `localhost:3000`. + +## Quiz + +Obrigado à comunidade por hospedar o quiz interativo que testa o seu conhecimento em cada capítulo. Teste o seu conhecimento [aqui](https://ff-quizzes.netlify.app/en/) + +### PDF + +Pode gerar um PDF deste conteúdo para acesso offline, se necessário. Para tal, certifique-se que tem o [npm instalado](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm) e execute os seguintes comandos na pasta raiz deste repositório: + +```sh +npm i +npm run convert +``` + +### Apresentações + +Existem apresentações para algumas das lições na pasta [slides](../../slides). + + +## Outros Currículos + +A nossa equipa produz outros currículos! Veja: + + +### LangChain +[![LangChain4j para Iniciantes](https://img.shields.io/badge/LangChain4j%20for%20Beginners-22C55E?style=for-the-badge&&labelColor=E5E7EB&color=0553D6)](https://aka.ms/langchain4j-for-beginners) +[![LangChain.js para Iniciantes](https://img.shields.io/badge/LangChain.js%20for%20Beginners-22C55E?style=for-the-badge&labelColor=E5E7EB&color=0553D6)](https://aka.ms/langchainjs-for-beginners?WT.mc_id=m365-94501-dwahlin) + +--- + +### Azure / Edge / MCP / Agentes +[![AZD para Iniciantes](https://img.shields.io/badge/AZD%20for%20Beginners-0078D4?style=for-the-badge&labelColor=E5E7EB&color=0078D4)](https://github.com/microsoft/AZD-for-beginners?WT.mc_id=academic-105485-koreyst) +[![Edge AI para Iniciantes](https://img.shields.io/badge/Edge%20AI%20for%20Beginners-00B8E4?style=for-the-badge&labelColor=E5E7EB&color=00B8E4)](https://github.com/microsoft/edgeai-for-beginners?WT.mc_id=academic-105485-koreyst) +[![MCP para Iniciantes](https://img.shields.io/badge/MCP%20for%20Beginners-009688?style=for-the-badge&labelColor=E5E7EB&color=009688)](https://github.com/microsoft/mcp-for-beginners?WT.mc_id=academic-105485-koreyst) +[![Agentes de IA para Iniciantes](https://img.shields.io/badge/AI%20Agents%20for%20Beginners-00C49A?style=for-the-badge&labelColor=E5E7EB&color=00C49A)](https://github.com/microsoft/ai-agents-for-beginners?WT.mc_id=academic-105485-koreyst) + +--- + +### Série de IA Generativa +[![IA Generativa para Iniciantes](https://img.shields.io/badge/Generative%20AI%20for%20Beginners-8B5CF6?style=for-the-badge&labelColor=E5E7EB&color=8B5CF6)](https://github.com/microsoft/generative-ai-for-beginners?WT.mc_id=academic-105485-koreyst) +[![IA Generativa (.NET)](https://img.shields.io/badge/Generative%20AI%20(.NET)-9333EA?style=for-the-badge&labelColor=E5E7EB&color=9333EA)](https://github.com/microsoft/Generative-AI-for-beginners-dotnet?WT.mc_id=academic-105485-koreyst) +[![IA Generativa (Java)](https://img.shields.io/badge/Generative%20AI%20(Java)-C084FC?style=for-the-badge&labelColor=E5E7EB&color=C084FC)](https://github.com/microsoft/generative-ai-for-beginners-java?WT.mc_id=academic-105485-koreyst) +[![IA Generativa (JavaScript)](https://img.shields.io/badge/Generative%20AI%20(JavaScript)-E879F9?style=for-the-badge&labelColor=E5E7EB&color=E879F9)](https://github.com/microsoft/generative-ai-with-javascript?WT.mc_id=academic-105485-koreyst) + +--- + +### Aprendizagem Fundamental +[![ML para Iniciantes](https://img.shields.io/badge/ML%20for%20Beginners-22C55E?style=for-the-badge&labelColor=E5E7EB&color=22C55E)](https://aka.ms/ml-beginners?WT.mc_id=academic-105485-koreyst) +[![Ciência de Dados para Iniciantes](https://img.shields.io/badge/Data%20Science%20for%20Beginners-84CC16?style=for-the-badge&labelColor=E5E7EB&color=84CC16)](https://aka.ms/datascience-beginners?WT.mc_id=academic-105485-koreyst) +[![IA para Iniciantes](https://img.shields.io/badge/AI%20for%20Beginners-A3E635?style=for-the-badge&labelColor=E5E7EB&color=A3E635)](https://aka.ms/ai-beginners?WT.mc_id=academic-105485-koreyst) +[![Cibersegurança para Iniciantes](https://img.shields.io/badge/Cybersecurity%20for%20Beginners-F97316?style=for-the-badge&labelColor=E5E7EB&color=F97316)](https://github.com/microsoft/Security-101?WT.mc_id=academic-96948-sayoung) +[![Desenvolvimento Web para Iniciantes](https://img.shields.io/badge/Web%20Dev%20for%20Beginners-EC4899?style=for-the-badge&labelColor=E5E7EB&color=EC4899)](https://aka.ms/webdev-beginners?WT.mc_id=academic-105485-koreyst) +[![IoT para Iniciantes](https://img.shields.io/badge/IoT%20for%20Beginners-14B8A6?style=for-the-badge&labelColor=E5E7EB&color=14B8A6)](https://aka.ms/iot-beginners?WT.mc_id=academic-105485-koreyst) +[![Desenvolvimento XR para Iniciantes](https://img.shields.io/badge/XR%20Development%20for%20Beginners-38BDF8?style=for-the-badge&labelColor=E5E7EB&color=38BDF8)](https://github.com/microsoft/xr-development-for-beginners?WT.mc_id=academic-105485-koreyst) + +--- + +### Série Copilot +[![Copilot para Programação Emparelhada com IA](https://img.shields.io/badge/Copilot%20for%20AI%20Paired%20Programming-FACC15?style=for-the-badge&labelColor=E5E7EB&color=FACC15)](https://aka.ms/GitHubCopilotAI?WT.mc_id=academic-105485-koreyst) +[![Copilot para C#/.NET](https://img.shields.io/badge/Copilot%20for%20C%23/.NET-FBBF24?style=for-the-badge&labelColor=E5E7EB&color=FBBF24)](https://github.com/microsoft/mastering-github-copilot-for-dotnet-csharp-developers?WT.mc_id=academic-105485-koreyst) +[![Aventuras Copilot](https://img.shields.io/badge/Copilot%20Adventure-FDE68A?style=for-the-badge&labelColor=E5E7EB&color=FDE68A)](https://github.com/microsoft/CopilotAdventures?WT.mc_id=academic-105485-koreyst) + + +## Atribuições das imagens + +Pode encontrar todas as atribuições das imagens usadas neste currículo, onde necessário, em [Atribuições](./attributions.md). + +--- + + +**Aviso legal**: +Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos pela precisão, por favor, tenha em conta que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autorizada. Para informações críticas, recomenda-se a tradução profissional por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações erradas resultantes do uso desta tradução. + \ No newline at end of file diff --git a/translations/pt-PT/SECURITY.md b/translations/pt-PT/SECURITY.md new file mode 100644 index 000000000..c2cbd67f2 --- /dev/null +++ b/translations/pt-PT/SECURITY.md @@ -0,0 +1,40 @@ +# Segurança + +A Microsoft leva a segurança dos seus produtos e serviços de software muito a sério, incluindo todos os repositórios de código fonte geridos através das nossas organizações no GitHub, que incluem [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin) e [as nossas organizações no GitHub](https://opensource.microsoft.com/). + +Se acredita ter encontrado uma vulnerabilidade de segurança em qualquer repositório pertencente à Microsoft que se enquadre na [definição de vulnerabilidade de segurança da Microsoft](https://docs.microsoft.com/en-us/previous-versions/tn-archive/cc751383(v=technet.10)), por favor reporte-a conforme descrito abaixo. + +## Reportar Problemas de Segurança + +**Por favor, não reporte vulnerabilidades de segurança através de issues públicas no GitHub.** + +Em vez disso, reporte-as ao Microsoft Security Response Center (MSRC) em [https://msrc.microsoft.com/create-report](https://msrc.microsoft.com/create-report). + +Se preferir enviar sem iniciar sessão, envie um email para [secure@microsoft.com](mailto:secure@microsoft.com). Se possível, encripte a sua mensagem com a nossa chave PGP; pode descarregá-la na [página da chave PGP do Microsoft Security Response Center](https://www.microsoft.com/en-us/msrc/pgp-key-msrc). + +Deverá receber uma resposta dentro de 24 horas. Se, por algum motivo, não receber, por favor envie um email de seguimento para garantir que recebemos a sua mensagem original. Informações adicionais podem ser encontradas em [microsoft.com/msrc](https://www.microsoft.com/msrc). + +Por favor, inclua as informações solicitadas abaixo (tanto quanto possível) para nos ajudar a compreender melhor a natureza e o alcance do possível problema: + + * Tipo de problema (ex.: buffer overflow, SQL injection, cross-site scripting, etc.) + * Caminhos completos dos ficheiros fonte relacionados com a manifestação do problema + * A localização do código fonte afetado (tag/branch/commit ou URL direto) + * Qualquer configuração especial necessária para reproduzir o problema + * Instruções passo-a-passo para reproduzir o problema + * Código de prova de conceito ou de exploração (se possível) + * Impacto do problema, incluindo como um atacante poderia explorar o problema + +Estas informações ajudarão a agilizar a triagem do seu relatório. + +Se estiver a reportar para um programa de recompensas por bugs, relatórios mais completos podem contribuir para uma recompensa maior. Por favor, visite a página do [Programa de Recompensas por Bugs da Microsoft](https://microsoft.com/msrc/bounty) para mais detalhes sobre os nossos programas ativos. + +## Idiomas Preferidos + +Preferimos que todas as comunicações sejam feitas em inglês. + +## Política + +A Microsoft segue o princípio de [Divulgação Coordenada de Vulnerabilidades](https://www.microsoft.com/en-us/msrc/cvd). + +**Aviso Legal**: +Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, é importante notar que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes do uso desta tradução. \ No newline at end of file diff --git a/translations/pt-PT/SUPPORT.md b/translations/pt-PT/SUPPORT.md new file mode 100644 index 000000000..4a9b6fe6b --- /dev/null +++ b/translations/pt-PT/SUPPORT.md @@ -0,0 +1,14 @@ +# Suporte + +## Como reportar problemas e obter ajuda + +Este projeto utiliza o GitHub Issues para acompanhar erros e pedidos de funcionalidades. Antes de criar novos problemas, procure pelos problemas existentes para evitar duplicações. Para novos problemas, reporte o seu erro ou pedido de funcionalidade como um novo Issue. + +Para obter ajuda e esclarecer dúvidas sobre o uso deste projeto, entre em contacto connosco criando um Issue neste repositório. + +## Política de Suporte da Microsoft + +O suporte para este **PROJETO ou PRODUTO** está limitado aos recursos listados acima. + +**Aviso Legal**: +Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, é importante notar que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes da utilização desta tradução. \ No newline at end of file diff --git a/translations/pt-PT/TROUBLESHOOTING.md b/translations/pt-PT/TROUBLESHOOTING.md new file mode 100644 index 000000000..e83a95df2 --- /dev/null +++ b/translations/pt-PT/TROUBLESHOOTING.md @@ -0,0 +1,756 @@ +# Guia de Resolução de Problemas + +Este guia ajuda a resolver problemas comuns ao trabalhar com o currículo IoT for Beginners. Os problemas estão organizados por categoria para facilitar a navegação. + +## Índice + +- [Problemas de Instalação](../..) + - [Instalação do Python](../..) + - [VS Code e Extensões](../..) + - [PlatformIO (Wio Terminal)](../..) + - [Bibliotecas Grove](../..) +- [Problemas de Hardware](../..) + - [Raspberry Pi](../..) + - [Wio Terminal](../..) + - [Dispositivo Virtual (CounterFit)](../..) +- [Problemas de Conectividade](../..) + - [Conexão WiFi](../..) + - [Serviços Cloud](../..) + - [MQTT](../..) +- [Problemas com Sensores e Atuadores](../..) + - [Sensores Grove](../..) + - [Câmara](../..) + - [Microfone e Coluna](../..) +- [Problemas no Ambiente de Desenvolvimento](../..) + - [VS Code](../..) + - [Ambientes Virtuais Python](../..) + - [Dependências](../..) +- [Problemas de Performance](../..) +- [Mensagens de Erro Comuns](../..) +- [Obter Ajuda](../..) + +--- + +## Problemas de Instalação + +### Instalação do Python + +#### Problema: Versão do Python demasiado antiga +**Erro:** `Python 3.6 ou superior é obrigatório` + +**Solução:** +1. Faça o download do Python 3 mais recente em [python.org](https://www.python.org/downloads/) +2. Durante a instalação no Windows, selecione "Add Python to PATH" +3. Verifique a instalação: + ```bash + python3 --version + ``` + +#### Problema: Múltiplas versões do Python causam conflitos +**Sintomas:** Versão errada do Python é executada, pacotes instalados em local errado + +**Solução:** +- **Windows:** Use `py -3` em vez de `python` para chamar explicitamente o Python 3 +- **macOS/Linux:** Use `python3` em vez de `python` +- Crie e use sempre ambientes virtuais para projetos + +#### Problema: Comando pip não encontrado +**Erro:** `'pip' não é reconhecido como um comando interno ou externo` + +**Solução:** +1. Tente `pip3` em vez de `pip` +2. Ou use `python -m pip` ou `python3 -m pip` +3. Certifique-se que o Python está adicionado ao PATH (reinstale o Python e selecione a opção) + +### VS Code e Extensões + +#### Problema: Extensão Pylance não funciona +**Sintomas:** Sem IntelliSense Python, sem autocompletar ou verificação de tipos + +**Solução:** +1. Abra a Paleta de Comandos do VS Code (`Ctrl+Shift+P` ou `Cmd+Shift+P`) +2. Execute "Python: Select Interpreter" +3. Escolha o interpretador Python correto (ambiente virtual se estiver a usar) +4. Recarregue a janela do VS Code + +#### Problema: VS Code não detecta ambiente virtual +**Sintomas:** Interpretador Python errado selecionado + +**Solução:** +1. Certifique-se que ativou o ambiente virtual no terminal +2. Abra a Paleta de Comandos e execute "Python: Select Interpreter" +3. Selecione o interpretador da pasta `.venv` +4. Verifique se a barra de estado (canto inferior esquerdo) mostra a versão correta do Python + +### PlatformIO (Wio Terminal) + +#### Problema: Instalação do PlatformIO falha +**Erro:** Vários erros durante a instalação do PlatformIO + +**Solução:** +1. Certifique-se que o VS Code está atualizado +2. Instale a extensão C/C++ primeiro +3. Reinicie o VS Code após instalar o PlatformIO +4. Verifique a sua ligação à internet (PlatformIO descarrega ficheiros grandes) + +#### Problema: Placa não detectada pelo PlatformIO +**Sintomas:** Não consegue fazer upload do código para o Wio Terminal + +**Solução:** +1. Use um cabo USB diferente (alguns cabos são só para carregamento) +2. Verifique o Gestor de Dispositivos (Windows) ou `ls /dev/tty*` (macOS/Linux) +3. Instale ou atualize os drivers USB +4. Experimente uma porta USB diferente +5. Deslize o interruptor de alimentação do Wio Terminal duas vezes rapidamente para entrar no modo bootloader + +#### Problema: Erros de compilação no PlatformIO +**Erro:** `fatal error: Arduino.h: No such file or directory` + +**Solução:** +1. Apague a pasta `.pio` no seu projeto +2. Execute "PlatformIO: Rebuild" na Paleta de Comandos +3. Certifique-se que o `platformio.ini` tem a configuração correta da placa: + ```ini + [env:seeed_wio_terminal] + platform = atmelsam + board = seeed_wio_terminal + framework = arduino + ``` + +### Bibliotecas Grove + +#### Problema: Falha na importação da biblioteca Grove no Raspberry Pi +**Erro:** `ModuleNotFoundError: No module named 'grove'` + +**Solução:** +1. Reinstale as bibliotecas Grove: + ```bash + cd ~ + git clone https://github.com/Seeed-Studio/grove.py + cd grove.py + sudo pip3 install . + ``` +2. Se estiver a usar ambiente virtual, pode precisar de instalar globalmente ou copiar as bibliotecas +3. Verifique se o I2C está ativado: `sudo raspi-config nonint do_i2c 0` + +#### Problema: Sensor Grove não é detectado +**Erro:** `IOError: [Errno 121] Remote I/O error` + +**Solução:** +1. Verifique as ligações físicas (certifique-se que o cabo Grove está totalmente inserido) +2. Verifique se o sensor está ligado à porta correta (analógica, digital, I2C, UART) +3. Execute `i2cdetect -y 1` para ver se o dispositivo aparece no barramento I2C +4. Experimente um cabo Grove diferente +5. Certifique-se que o Grove Base Hat está devidamente encaixado nos pinos GPIO do Raspberry Pi + +--- + +## Problemas de Hardware + +### Raspberry Pi + +#### Problema: Raspberry Pi não arranca +**Sintomas:** Sem imagem, sem LED ativo, ou ecrã arco-íris + +**Solução:** +1. **Verifique a alimentação:** Use a fonte oficial 5V 3A USB-C para Pi 4 +2. **Problemas com o cartão SD:** + - Reformatar cartão SD e reinstalar Raspberry Pi OS + - Experimente um cartão SD diferente (use marcas recomendadas) + - Certifique-se que o cartão SD está corretamente inserido +3. **Verifique ligação HDMI:** Experimente ambas as portas HDMI no Pi 4, use a porta HDMI mais próxima da alimentação + +#### Problema: Não consegue conectar via SSH ao Raspberry Pi +**Sintomas:** Conexão recusada ou timeout + +**Solução:** +1. Ative o SSH: + - Ao gravar o cartão SD com o Raspberry Pi Imager, configure o SSH nas opções avançadas + - Ou crie um ficheiro vazio chamado `ssh` (sem extensão) na partição de boot +2. Encontre o IP do Pi: + - Verifique os dispositivos conectados no seu router + - Use `ping raspberrypi.local` (se o mDNS funcionar) + - Use ferramentas de scanner de rede como `nmap` ou Angry IP Scanner +3. Verifique a rede: + - Certifique-se que o Pi está na mesma rede que o seu computador + - Experimente ligação por ethernet em vez de WiFi +4. Verifique o nome de utilizador/senha (padrão: utilizador `pi`, senha `raspberry`) + +#### Problema: Grove Base Hat não é reconhecido +**Sintomas:** Sensores não funcionam, erros I2C + +**Solução:** +1. Certifique-se que o Base Hat está corretamente encaixado em todos os pinos GPIO +2. Verifique existência de pinos tortos no Pi ou Base Hat +3. Ative a interface I2C: + ```bash + sudo raspi-config nonint do_i2c 0 + sudo reboot + ``` +4. Verifique se o I2C está a funcionar: `i2cdetect -y 1` + +#### Problema: Raspberry Pi lento +**Sintomas:** Interface lenta, resposta demorada + +**Solução:** +1. Verifique a velocidade do cartão SD (use Classe 10 ou superior, ou SSD via USB) +2. Liberte espaço em disco: `df -h` para verificar, apague ficheiros desnecessários +3. Reduza a memória GPU em `raspi-config` se não estiver a usar a câmara/ecrã intensivamente +4. Feche aplicações desnecessárias +5. Considere atualizar para Pi 4 com mais RAM se estiver a usar Pi 3 ou anterior + +### Wio Terminal + +#### Problema: Ecrã do Wio Terminal fica negro +**Sintomas:** Sem saída no ecrã depois de carregar código + +**Solução:** +1. Verifique se o código inicializa o ecrã (biblioteca TFT_eSPI) +2. Atualize o firmware do Wio Terminal a partir de [Seeed Wiki](https://wiki.seeedstudio.com/Wio-Terminal-Getting-Started/) +3. Adicione código de inicialização do ecrã: + ```cpp + #include + TFT_eSPI tft; + tft.begin(); + tft.fillScreen(TFT_BLACK); + ``` +4. Experimente carregar sketch de exemplo do PlatformIO para testar hardware + +#### Problema: WiFi não funciona no Wio Terminal +**Sintomas:** Incapaz de conectar ao WiFi, erros de rede + +**Solução:** +1. **Atualize o firmware WiFi:** Siga o [guia de atualização do firmware WiFi do Wio Terminal](https://wiki.seeedstudio.com/Wio-Terminal-Network-Overview/) +2. **Verifique credenciais WiFi:** Certifique-se que SSID e senha estão corretos +3. **Banda WiFi:** Wio Terminal suporta apenas WiFi 2.4GHz (não 5GHz) +4. **Força do sinal:** Aproxime-se do router +5. **Configurações do router:** Algumas redes empresariais/WPA-Enterprise podem não funcionar + +#### Problema: Wio Terminal não é reconhecido pelo computador +**Sintomas:** Dispositivo USB não detectado + +**Solução:** +1. **Experimente cabo USB diferente:** Use cabo de dados, não cabo só para carregamento +2. **Entre em modo bootloader:** Deslize o interruptor de alimentação para baixo duas vezes rapidamente + - O LED azul deve piscar, o dispositivo aparece como "Arduino" no Gestor de Dispositivos +3. **Instale drivers (Windows):** + - Transfira e instale o [driver USB Seeed](https://wiki.seeedstudio.com/Driver_for_Seeeduino/) +4. **Experimente porta USB diferente:** Evite hubs USB, use ligação direta +5. **Atualize drivers USB do sistema** + +#### Problema: Sensores não funcionam no Wio Terminal +**Sintomas:** Sensores Grove não retornam dados + +**Solução:** +1. Verifique ligações dos cabos Grove +2. Confirme que está a usar a porta Grove correta (esquerda ou direita) +3. Inclua as bibliotecas corretas para o sensor +4. Verifique as necessidades de alimentação do sensor +5. Teste o sensor com código de exemplo da biblioteca + +### Dispositivo Virtual (CounterFit) + +#### Problema: Aplicação CounterFit não arranca +**Erro:** Vários erros Python ao iniciar o CounterFit + +**Solução:** +1. Assegure que o ambiente virtual está ativado +2. Instale/reinstale o CounterFit: + ```bash + pip install CounterFit + ``` +3. Verifique que a porta 5000 não está já em uso: + - Windows: `netstat -ano | findstr :5000` + - macOS/Linux: `lsof -i :5000` +4. Termine o processo a usar a porta 5000 ou use porta diferente: + ```bash + counterfit --port 5001 + ``` + +#### Problema: Não consegue conectar ao CounterFit a partir do código +**Erro:** Conexão recusada ou timeout + +**Solução:** +1. Verifique que o CounterFit está a correr: abra o browser em `http://127.0.0.1:5000` +2. Confirme que o URL de conexão no código corresponde ao endereço do CounterFit +3. Certifique-se que o firewall não bloqueia a conexão +4. Tente reiniciar tanto a aplicação CounterFit como o seu código + +#### Problema: Sensores não aparecem no CounterFit +**Sintomas:** Sensores criados não aparecem na interface do CounterFit + +**Solução:** +1. Crie os sensores na interface do CounterFit antes de executar o código +2. Atualize a página do browser +3. Verifique se o tipo do sensor coincide com o esperado pelo código +4. Limpe a cache do navegador + +--- + +## Problemas de Conectividade + +### Conexão WiFi + +#### Problema: Dispositivo não conecta ao WiFi +**Sintomas:** Timeout na ligação, autenticação falhada + +**Solução:** +1. **Verifique SSID e senha:** Confirme que as credenciais estão corretas +2. **Banda WiFi:** A maioria dos dispositivos IoT suporta apenas 2.4GHz (não 5GHz) +3. **Configurações do router:** + - Desative isolamento AP se estiver ativo + - Use segurança WPA2-PSK (evite WPA3, WEP ou redes abertas) + - Certifique-se que o DHCP está ativo +4. **Redes ocultas:** Se o SSID está oculto, pode precisar de configurar explicitamente +5. **Força do sinal:** Aproxime o dispositivo do router +6. **Interferências:** Outros dispositivos, micro-ondas ou paredes podem interferir + +#### Problema: Conexão WiFi cai frequentemente +**Sintomas:** Conectividade intermitente + +**Solução:** +1. Verifique estabilidade do router e considere reiniciar +2. Atualize o firmware do dispositivo +3. Use IP estático em vez de DHCP +4. Reduza distância ao router ou adicione repetidor WiFi +5. Verifique interferência de outros dispositivos +6. Confirme que a alimentação é adequada (especialmente para Raspberry Pi) + +### Serviços Cloud + +#### Problema: Não consegue conectar ao Azure IoT Hub +**Erro:** Autenticação falhou, conexão recusada + +**Solução:** +1. **Verifique credenciais:** + - Confirme que a string de conexão está correta + - Assegure que não existem espaços ou quebras de linha extras na string +2. **Verifique registo do dispositivo:** O dispositivo deve estar registado no IoT Hub +3. **Firewall/proxy:** Garanta que as portas MQTT (8883) ou HTTPS (443) estão liberadas para saída +4. **Região do IoT Hub:** Confirme que o IoT Hub está ativo e não numa região diferente causando latência +5. **Limites de quota:** Verifique se os limites do nível gratuito não foram ultrapassados +6. **Teste a conexão:** + ```bash + az iot hub device-identity show-connection-string --hub-name YourIoTHub --device-id YourDevice + ``` + +#### Problema: Azure Functions não disparam +**Sintomas:** Mensagens enviadas mas função não executa + +**Solução:** +1. Verifique que a App Function está ativa (não parada) +2. Confirme a string de conexão nas configurações da App Function +3. Verifique os logs da função no Portal Azure +4. Assegure que o ponto final compatível com Event Hub está configurado corretamente +5. Confirme que o formato da mensagem corresponde às expectativas da função +6. Verifique o plano de serviço da App Function (consumo vs. dedicado) + +### MQTT +#### Problema: Falha na ligação MQTT +**Erro:** Conexão recusada, autenticação falhou + +**Solução:** +1. **Endereço do broker:** Verifique se o URL/IP do broker está correto +2. **Porta:** Verifique o número da porta (1883 para não encriptado, 8883 para TLS) +3. **Autenticação:** Verifique o nome de utilizador/senha se necessário +4. **TLS/SSL:** Assegure que os certificados são válidos e confiáveis +5. **Firewall:** Confirme que a porta não está bloqueada +6. **Teste com cliente MQTT:** Use MQTT Explorer ou mosquitto_pub/sub para testar + +#### Problema: Mensagens MQTT não recebidas +**Sintomas:** Mensagens publicadas mas não recebidas pelos subscritores + +**Solução:** +1. **Nomes dos tópicos:** Verifique se o tópico do subscritor coincide exatamente com o do publicador +2. **Nível QoS:** Experimente QoS 1 ou 2 em vez de 0 +3. **Curingas:** Confirme que os curingas de tópico são usados corretamente (`+` para nível único, `#` para múltiplos níveis) +4. **Mensagens retidas:** O publicador pode definir flag de retenção para manter a última mensagem +5. **Tempo de ligação:** Garanta que o subscritor se liga antes de as mensagens serem publicadas + +--- + +## Problemas com Sensores e Atuadores + +### Sensores Grove + +#### Problema: Sensor devolve valores incorretos +**Sintomas:** Leituras são 0, -1, ou valores sem sentido + +**Solução:** +1. **Verificar ligações:** Assegure que o sensor está corretamente ligado +2. **Porta correta:** Verifique se o sensor está na porta certa: + - Sensores analógicos → Portas analógicas (A0, A2, A4) + - Sensores digitais → Portas digitais (D5, D16, D18, etc.) + - Sensores I2C → Portas I2C +3. **Calibração:** Alguns sensores necessitam de calibração (humidade do solo, luz) +4. **Reiniciar energia:** Desligar e ligar novamente o sensor +5. **Folha de dados do sensor:** Consultar especificações e requisitos do sensor + +#### Problema: Sensor capacitivo de humidade do solo sempre indica húmido +**Sintomas:** Sensor indica humidade alta mesmo quando está seco + +**Solução:** +1. **Necessidade de calibração:** Sensores de solo precisam de calibração: + - Medir valor no ar (base seca) + - Medir valor na água (base húmida) + - Mapear leituras entre estes valores +2. **Verificar revestimento do sensor:** Sensores de humidade podem degradar se o revestimento estiver danificado +3. **Posicionamento:** Assegure que o sensor está totalmente inserido no solo + +#### Problema: Leituras incorretas do sensor de temperatura/humidade +**Sintomas:** DHT11/DHT22 mostra temperatura ou humidade erradas + +**Solução:** +1. **Posicionamento do sensor:** Evite luz solar direta, fontes de calor ou correntes de ar +2. **Tempo de aquecimento:** Deixe o sensor estabilizar 2 segundos após ligar antes de ler +3. **Frequência de leitura:** Sensores DHT precisam de tempo entre leituras (mínimo 2 segundos) +4. **Verificar condensação:** Pode afetar as leituras +5. **Qualidade do sensor:** DHT11 é menos preciso que DHT22 + +### Câmara + +#### Problema: Câmara não detetada no Raspberry Pi +**Erro:** `mmal: mmal_vc_component_create: failed to create component 'vc.ril.camera'` + +**Solução:** +1. **Ativar interface da câmera:** + ```bash + sudo raspi-config + ``` + Vá a Interface Options → Camera → Enable +2. **Verificar cabo plano:** Assegure que o cabo da câmera está bem inserido + - Lado azul para as portas USB no Pi Zero + - Lado azul afastado das portas USB no Pi 4 +3. **Atualizar firmware:** + ```bash + sudo apt update + sudo apt full-upgrade + sudo reboot + ``` +4. **Testar câmera:** + ```bash + raspistill -o test.jpg + ``` + + +#### Problema: Imagens da câmera com má qualidade +**Sintomas:** Imagens desfocadas, escuras ou lavadas + +**Solução:** +1. **Foco:** Remova filme protetor da lente, ajuste foco se possível +2. **Iluminação:** Assegure iluminação adequada +3. **Configurações da câmera:** Ajuste exposição, ISO, balanço de brancos no código +4. **Estabilidade:** Mantenha a câmera fixa, use tripé se necessário +5. **Resolução:** Não ultrapasse a resolução máxima da câmara + +### Microfone e Altifalante + +#### Problema: Sem entrada/saída de áudio +**Sintomas:** Microfone não grava, altifalante não reproduz + +**Solução:** +1. **Verificar ligações:** Confirme que dispositivos de áudio estão corretamente ligados +2. **Testar hardware:** + - Altifalante: `speaker-test -t wav -c 2` + - Microfone: `arecord -l` para listar, `arecord test.wav` para gravar +3. **Configurações de volume:** Verifique e ajuste volume: + ```bash + alsamixer + ``` +4. **Selecionar dispositivo de áudio:** Especificar o dispositivo correto no código +5. **Problemas de driver:** Atualizar ALSA ou reinstalar drivers de áudio + +#### Problema: ReSpeaker hat não funciona +**Sintomas:** Dispositivo de áudio não detetado + +**Solução:** +1. **Instalar drivers:** + ```bash + git clone https://github.com/HinTak/seeed-voicecard + cd seeed-voicecard + sudo ./install.sh + sudo reboot + ``` +2. **Verificar instalação:** `arecord -l` deve listar ReSpeaker +3. **Atualizar firmware:** Algumas versões do Pi OS precisam de atualização dos drivers +4. **Verificar ligação:** Assegurar que a hat está bem conectada aos pinos GPIO + +--- + +## Problemas no Ambiente de Desenvolvimento + +### VS Code + +#### Problema: Terminal não ativa ambiente virtual automaticamente +**Sintomas:** Terminal abre mas venv não está ativado + +**Solução:** +1. **Definir interpretador Python:** Command Palette → "Python: Select Interpreter" → Escolher venv +2. **Reiniciar VS Code** após selecionar interpretador +3. **Verificar configurações:** No `settings.json`, adicionar: + ```json + "python.terminal.activateEnvironment": true + ``` + + +#### Problema: Código não corre no dispositivo +**Sintomas:** Código corre mas nada acontece no dispositivo + +**Solução:** +1. **Verificar se código está salvo** (verificar ponto na tab do arquivo) +2. **Verificar qual Python está a correr:** `which python` ou `where python` +3. **Para Wio Terminal:** Assegurar que código foi carregado via PlatformIO (clicar botão upload) +4. **Para Raspberry Pi:** Aceder por SSH e correr o código lá +5. **Verificar janela de saída** para erros + +#### Problema: IntelliSense não mostra funções da biblioteca +**Sintomas:** Sem autocomplete para módulos importados + +**Solução:** +1. Garantir que biblioteca está instalada no ambiente atual +2. Recarregar janela do VS Code +3. Confirmar que interpretador Python está correto +4. Instalar type stubs se disponíveis: `pip install types-` + +### Ambientes Virtuais Python + +#### Problema: Não é possível criar ambiente virtual +**Erro:** `The virtual environment was not created successfully` + +**Solução:** +1. **Instalar módulo venv:** + - Ubuntu/Debian: `sudo apt install python3-venv` + - macOS: Deve estar incluído com Python + - Windows: Reinstalar Python com todos os componentes +2. **Verificar instalação do Python:** Confirmar que Python está corretamente instalado +3. **Usar caminho completo:** Tentar `python3 -m venv .venv` com chamada explícita ao python3 + +#### Problema: Pacotes instalados na localização errada +**Sintomas:** Erro de importação após instalar pacote + +**Solução:** +1. **Confirmar que venv está ativado:** Prompt deve mostrar `(.venv)` +2. **Verificar localização do pip:** `which pip` deve apontar para `.venv/bin/pip` +3. **Reinstalar no venv:** Ativar venv, depois `pip install ` +4. **Não usar sudo com pip** no ambiente virtual + +#### Problema: Ambiente virtual não é portátil +**Sintomas:** Venv não funciona após mover ou noutro computador + +**Solução:** +1. **Não mover venvs:** Apague e crie novamente no novo local +2. **Usar requirements.txt:** + ```bash + pip freeze > requirements.txt + pip install -r requirements.txt + ``` +3. **Recriar venv:** + ```bash + python3 -m venv .venv + source .venv/bin/activate # ou activate.bat no Windows + pip install -r requirements.txt + ``` + + +### Dependências + +#### Problema: Falha na instalação do pacote +**Erro:** Vários erros de pip durante instalação + +**Solução:** +1. **Atualizar pip:** + ```bash + pip install --upgrade pip + ``` +2. **Instalar ferramentas de compilação:** + - Ubuntu/Debian: `sudo apt install build-essential python3-dev` + - macOS: `xcode-select --install` + - Windows: Instalar Visual Studio Build Tools +3. **Verificar ligação à internet** +4. **Tentar outro índice de pacote:** `pip install --index-url https://pypi.org/simple/ ` +5. **Instalar versão específica:** `pip install ==` + +#### Problema: Conflitos de dependências +**Erro:** `ERROR: pip's dependency resolver does not currently take into account all the packages that are installed` + +**Solução:** +1. **Usar ambiente virtual novo** para cada projeto +2. **Atualizar pacotes:** `pip install --upgrade ` +3. **Verificar requisitos:** Usar `pip check` para encontrar conflitos +4. **Instalar versões compatíveis:** Especificar intervalos de versão em requirements.txt + +--- + +## Problemas de Performance + +### Problema: Código corre lentamente +**Sintomas:** Atrasos, timeouts, comportamento não responsivo + +**Solução:** +1. **Reduzir frequência de leitura dos sensores:** Não ler sensores com muita frequência +2. **Otimizar loops:** Evitar busy-waiting, usar sleep() ou delays +3. **Problemas de memória:** + - Fechar aplicações desnecessárias + - Libertar espaço de armazenamento + - Monitorizar com `top` ou `htop` no Pi +4. **Velocidade do cartão SD:** Usar cartão SD mais rápido ou SSD para Raspberry Pi +5. **Atrasos na rede:** Usar operações assíncronas para chamadas de rede + +### Problema: Erros de falta de memória +**Erro:** `MemoryError` ou sistema bloqueado + +**Solução:** +1. **Para Raspberry Pi:** + - Fechar aplicações desnecessárias + - Aumentar espaço de swap + - Usar sistema operativo mais leve (versão Lite) + - Atualizar RAM (Pi 4 tem opções de 2/4/8GB) +2. **Para Wio Terminal:** + - Reduzir tamanhos de buffer + - Usar imagens menores + - Otimizar uso de strings + - Verificar fugas de memória (memória não libertada) + +### Problema: Perda ou corrupção de dados +**Sintomas:** Mensagens em falta, ficheiros corrompidos + +**Solução:** +1. **Problemas com cartão SD:** + - Usar cartões SD de qualidade (evitar baratos/falsificados) + - Fazer backups regulares + - Desligar sem riscos (não desligar energia abruptamente) +2. **Overflow de buffer:** Aumentar tamanhos de buffer no código +3. **Confiabilidade da rede:** Implementar lógica de retentativa e tratamento de erros +4. **Qualidade de Serviço:** Usar MQTT QoS 1 ou 2 para mensagens importantes + +--- + +## Mensagens Comuns de Erro + +### `ModuleNotFoundError: No module named 'X'` +**Causa:** Pacote não instalado ou ambiente virtual não ativado + +**Solução:** +```bash +pip install X +``` + +Assegure que o ambiente virtual está ativado primeiro. + +### `Permission denied` no Linux/macOS +**Causa:** Necessário permissões elevadas ou problema de permissões de ficheiro + +**Solução:** +- Para operações do sistema: Usar `sudo` +- Para pip: NÃO use sudo com venv, ative venv primeiro +- Para porta serial: Adicione utilizador ao grupo dialout: `sudo usermod -a -G dialout $USER`, depois logout/login + +### `OSError: [Errno 98] Address already in use` +**Causa:** Porta já está a ser usada por outro processo + +**Solução:** +1. Encontrar processo que usa a porta: `lsof -i :` ou `netstat -ano | findstr :` +2. Matar processo ou usar porta diferente no código + +### `SSL: CERTIFICATE_VERIFY_FAILED` +**Causa:** Falha na validação do certificado SSL + +**Solução:** +1. Atualizar certificados: `pip install --upgrade certifi` +2. Verificar se hora do sistema está correta: `date` +3. Apenas para desenvolvimento (não produção): Desativar verificação no código + +### `IndentationError: unexpected indent` +**Causa:** Problemas de indentação Python (mistura de tabs/espaços) + +**Solução:** +1. Usar indentação consistente (4 espaços é padrão Python) +2. Configurar editor para usar espaços em vez de tabs +3. VS Code: Definir `"editor.insertSpaces": true` e `"editor.tabSize": 4` + +### `UnicodeDecodeError` ou `UnicodeEncodeError` +**Causa:** Problemas de codificação de caracteres + +**Solução:** +```python +# Ao ler ficheiros +with open('file.txt', 'r', encoding='utf-8') as f: + content = f.read() + +# Ao escrever ficheiros +with open('file.txt', 'w', encoding='utf-8') as f: + f.write(content) +``` + +--- + +## Obter Ajuda + +Se já tentou estes passos de resolução e ainda tem problemas: + +### 1. Verificar Recursos Existentes +- **Documentação:** Revise o [README](README.md) e as instruções das aulas +- **Guias de hardware:** Consulte [hardware.md](hardware.md) para informações específicas de hardware +- **Wiki Seeed Studio:** [Seeed Studio Wiki](https://wiki.seeedstudio.com/) para componentes Grove + +### 2. Pesquisar Problemas Similares +- **GitHub Issues:** Pesquise [problemas existentes](https://github.com/microsoft/IoT-For-Beginners/issues) +- **Stack Overflow:** Pesquise mensagens de erro +- **Fóruns de dispositivos:** Consulte fóruns Raspberry Pi ou Arduino + +### 3. Criar um Issue no GitHub +Se não encontrar solução: +1. Vá a [GitHub Issues](https://github.com/microsoft/IoT-For-Beginners/issues) +2. Clique em "New Issue" +3. Forneça: + - Descrição clara do problema + - Passos para reproduzir + - Mensagens de erro (texto completo) + - Versões de hardware/software + - O que já tentou + - Capturas de ecrã se relevante + +### 4. Junte-se à Comunidade +- **Discord:** [Microsoft Foundry Discord](https://discord.gg/nTYy5BXMWG) +- **Microsoft Learn:** [Microsoft Learn IoT](https://docs.microsoft.com/learn/browse/?products=azure-iot) + +### 5. Forneça Bons Relatórios de Erros +Um bom relatório de erros inclui: +- **Ambiente:** SO, versão do Python, hardware utilizado +- **Passos para reproduzir:** Passos exatos que causam o problema +- **Comportamento esperado:** O que deveria acontecer +- **Comportamento real:** O que realmente acontece +- **Mensagens de erro:** Texto completo do erro, não capturas de ecrã +- **Código:** Exemplo mínimo de código que reproduz o problema + +--- + +## Dicas para Prevenção + +### Boas Práticas Gerais +1. **Faça backups:** Backups regulares dos cartões SD/código que funciona +2. **Documente alterações:** Anote o que funciona nos comentários +3. **Controle de versão:** Use git para registar alterações no código +4. **Teste incrementalmente:** Teste alterações pequenas antes de combinar +5. **Leia as mensagens de erro:** Elas normalmente indicam exatamente o que está errado +6. **Atualize regularmente:** Mantenha o software/firmware atualizado +7. **Use componentes de qualidade:** Evite cabos/fonte de alimentação baratos +8. **Energia estável:** Use fonte de alimentação apropriada (especialmente no Pi) + +### Fluxo de Trabalho de Desenvolvimento +1. **Comece simples:** Inicie com código de exemplo que funcione +2. **Uma alteração de cada vez:** É mais fácil encontrar o que causa problema +3. **Teste frequentemente:** Detecte problemas cedo +4. **Mantenha organizado:** Organize ficheiros e código de forma lógica +5. **Comente o código:** O futuro você irá agradecer + +--- + +*Este guia de resolução de problemas é mantido pela comunidade. Se encontrar uma solução para um problema não listado aqui, por favor considere [contribuir](CONTRIBUTING.md) para ajudar outros!* + +--- + + +**Aviso Legal**: +Este documento foi traduzido utilizando o serviço de tradução automática [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos por garantir a precisão, por favor esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original no seu idioma nativo deve ser considerado a fonte autorizada. Para informações críticas, recomenda-se a tradução feita por um profissional humano. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes do uso desta tradução. + \ No newline at end of file diff --git a/translations/pt-PT/attributions.md b/translations/pt-PT/attributions.md new file mode 100644 index 000000000..c354f7cba --- /dev/null +++ b/translations/pt-PT/attributions.md @@ -0,0 +1,43 @@ +# Atribuições de imagens + +* Bananas por abderraouf omara do [Noun Project](https://thenounproject.com) +* Cérebro por Icon Market do [Noun Project](https://thenounproject.com) +* Transmissão por RomStu do [Noun Project](https://thenounproject.com) +* Botão por Dan Hetteix do [Noun Project](https://thenounproject.com) +* Microfone condensador de diafragma pequeno C451B por AKG Acoustics. [Harumphy](https://en.wikipedia.org/wiki/User:Harumphy) em [en.wikipedia](https://en.wikipedia.org/) / [Creative Commons Attribution-Share Alike 3.0 Unported](https://creativecommons.org/licenses/by-sa/3.0/deed.en) +* Calendário por Alice-vector do [Noun Project](https://thenounproject.com) +* Certificado por alimasykurm do [Noun Project](https://thenounproject.com) +* Chip por Astatine Lab do [Noun Project](https://thenounproject.com) +* Nuvem por Debi Alpa Nugraha do [Noun Project](https://thenounproject.com) +* Contentor por ProSymbols do [Noun Project](https://thenounproject.com) +* CPU por Icon Lauk do [Noun Project](https://thenounproject.com) +* Base de dados por Icons Bazaar do [Noun Project](https://thenounproject.com) +* Dial por Jamie Dickinson do [Noun Project](https://thenounproject.com) +* GPS por mim studio do [Noun Project](https://thenounproject.com) +* Aquecedor por Pascal Heß do [Noun Project](https://thenounproject.com) +* Ideia por Pause08 do [Noun Project](https://thenounproject.com) +* IoT por Adrien Coquet do [Noun Project](https://thenounproject.com) +* LED por abderraouf omara do [Noun Project](https://thenounproject.com) +* LDR por Eucalyp do [Noun Project](https://thenounproject.com) +* Lâmpada por Maxim Kulikov do [Noun Project](https://thenounproject.com) +* Microcontrolador por Template do [Noun Project](https://thenounproject.com) +* Telemóvel por Alice-vector do [Noun Project](https://thenounproject.com) +* Motor por Bakunetsu Kaito do [Noun Project](https://thenounproject.com) +* Patti Smith a cantar num microfone Shure SM58 (tipo cardioide dinâmico). Beni Köhler / [Creative Commons Attribution-Share Alike 3.0 Unported](https://creativecommons.org/licenses/by-sa/3.0/deed.en) +* Planta por Alex Muravev do [Noun Project](https://thenounproject.com) +* Célula vegetal por Léa Lortal do [Noun Project](https://thenounproject.com) +* Sonda por Adnen Kadri do [Noun Project](https://thenounproject.com) +* RAM por Atif Arshad do [Noun Project](https://thenounproject.com) +* Raspberry Pi 4. Michael Henzler / [Wikimedia Commons](https://commons.wikimedia.org/wiki/Main_Page) / [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/) +* Gravação por Aybige Speaker do [Noun Project](https://thenounproject.com) +* Satélite por Noura Mbarki do [Noun Project](https://thenounproject.com) +* Sensor inteligente por Andrei Yushchenko do [Noun Project](https://thenounproject.com) +* Altifalante por Gregor Cresnar do [Noun Project](https://thenounproject.com) +* Interruptor por Chattapat do [Noun Project](https://thenounproject.com) +* Temperatura por Vectors Market do [Noun Project](https://thenounproject.com) +* Tomate por parkjisun do Noun Project do [Noun Project](https://thenounproject.com) +* Regador por Daria Moskvina do [Noun Project](https://thenounproject.com) +* Clima por Adrien Coquet do [Noun Project](https://thenounproject.com) + +**Aviso Legal**: +Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos pela precisão, esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes do uso desta tradução. \ No newline at end of file diff --git a/translations/pt-PT/clean-up.md b/translations/pt-PT/clean-up.md new file mode 100644 index 000000000..8f614ae58 --- /dev/null +++ b/translations/pt-PT/clean-up.md @@ -0,0 +1,44 @@ +# Limpe o seu projeto + +Depois de concluir cada projeto, é uma boa prática eliminar os seus recursos na cloud. + +Nas lições de cada projeto, pode ter criado alguns dos seguintes recursos: + +* Um Grupo de Recursos +* Um IoT Hub +* Registos de dispositivos IoT +* Uma Conta de Armazenamento +* Uma App de Funções +* Uma conta do Azure Maps +* Um projeto de visão personalizada +* Um Registo de Contentores do Azure +* Um recurso de serviços cognitivos + +A maioria destes recursos não terá custos - ou são completamente gratuitos, ou está a utilizar um nível gratuito. Para serviços que exigem um nível pago, terá estado a utilizá-los num nível incluído na quota gratuita, ou que custará apenas alguns cêntimos. + +Mesmo com custos relativamente baixos, vale a pena eliminar estes recursos quando terminar. Por exemplo, só pode ter um IoT Hub a utilizar o nível gratuito, por isso, se quiser criar outro, terá de usar um nível pago. + +Todos os seus serviços foram criados dentro de Grupos de Recursos, o que facilita a gestão. Pode eliminar o Grupo de Recursos, e todos os serviços nesse Grupo de Recursos serão eliminados juntamente com ele. + +Para eliminar o Grupo de Recursos, execute o seguinte comando no seu terminal ou prompt de comando: + +```sh +az group delete --name +``` + +Substitua `` pelo nome do Grupo de Recursos que deseja eliminar. + +Aparecerá uma confirmação: + +```output +Are you sure you want to perform this operation? (y/n): +``` + +Digite `y` para confirmar e eliminar o Grupo de Recursos. + +A eliminação de todos os serviços pode demorar algum tempo. + +> 💁 Pode ler mais sobre como eliminar grupos de recursos na [documentação sobre eliminação de grupos de recursos e recursos do Azure Resource Manager no Microsoft Docs](https://docs.microsoft.com/azure/azure-resource-manager/management/delete-resource-group?WT.mc_id=academic-17441-jabenn&tabs=azure-cli) + +**Aviso Legal**: +Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes do uso desta tradução. \ No newline at end of file diff --git a/translations/pt-PT/docs/_sidebar.md b/translations/pt-PT/docs/_sidebar.md new file mode 100644 index 000000000..11a52620a --- /dev/null +++ b/translations/pt-PT/docs/_sidebar.md @@ -0,0 +1,40 @@ +- Introdução + - [1](../1-getting-started/lessons/1-introduction-to-iot/README.md) + - [2](../1-getting-started/lessons/2-deeper-dive/README.md) + - [3](../1-getting-started/lessons/3-sensors-and-actuators/README.md) + - [4](../1-getting-started/lessons/4-connect-internet/README.md) + +- Agricultura + - [5](../2-farm/lessons/1-predict-plant-growth/README.md) + - [6](../2-farm/lessons/2-detect-soil-moisture/README.md) + - [7](../2-farm/lessons/3-automated-plant-watering/README.md) + - [8](../2-farm/lessons/4-migrate-your-plant-to-the-cloud/README.md) + - [9](../2-farm/lessons/5-migrate-application-to-the-cloud/README.md) + - [10](../2-farm/lessons/6-keep-your-plant-secure/README.md) + + +- Transporte + - [11](../3-transport/lessons/1-location-tracking/README.md) + - [12](../3-transport/lessons/2-store-location-data/README.md) + - [13](../3-transport/lessons/3-visualize-location-data/README.md) + - [14](../3-transport/lessons/4-geofences/README.md) + +- Fabricação + - [15](../4-manufacturing/lessons/1-train-fruit-detector/README.md) + - [16](../4-manufacturing/lessons/2-check-fruit-from-device/README.md) + - [17](../4-manufacturing/lessons/3-run-fruit-detector-edge/README.md) + - [18](../4-manufacturing/lessons/4-trigger-fruit-detector/README.md) + + +- Retalho + - [19](../5-retail/lessons/1-train-stock-detector/README.md) + - [20](../5-retail/lessons/2-check-stock-device/README.md) + +- Consumidor + - [21](../6-consumer/lessons/1-speech-recognition/README.md) + - [22](../6-consumer/lessons/2-language-understanding/README.md) + - [23](../6-consumer/lessons/3-spoken-feedback/README.md) + - [24](../6-consumer/lessons/4-multiple-language-support/README.md) + +**Aviso Legal**: +Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos pela precisão, esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes do uso desta tradução. \ No newline at end of file diff --git a/translations/pt-PT/docs/troubleshooting.md b/translations/pt-PT/docs/troubleshooting.md new file mode 100644 index 000000000..260f15360 --- /dev/null +++ b/translations/pt-PT/docs/troubleshooting.md @@ -0,0 +1,89 @@ +# Guia de Resolução de Problemas do Raspberry Pi + +Este guia fornece soluções para problemas comuns encontrados ao executar projetos de IoT em dispositivos Raspberry Pi. +É destinado a iniciantes que seguem o currículo IoT-For-Beginners, mas também é útil para desenvolvimento geral em Pi. + +--- + +## 1. Erros de Instalação e Dependências + +### ❗ `ModuleNotFoundError: No module named 'xyz'` +Isto acontece quando os módulos Python necessários não estão instalados. + +**Solução** +```bash +pip3 install + + Permission denied when running scripts + +Often caused by accessing GPIO, I2C or system hardware without elevated privileges. +Quick fix: +sudo python3 script.py + +Recommended fix (no sudo needed every time): +sudo usermod -aG gpio,i2c,spi $USER +sudo reboot + +2. GPIO / I2C / SPI Not Working +❗ RuntimeError: No access to GPIO + +Add user to GPIO group: +sudo usermod -aG gpio $USER +sudo reboot + +❗ I2C / SPI devices not detected + +Enable interfaces: +sudo raspi-config +→ Interface Options +→ Enable I2C / Enable SPI + +Check if I2C device appears: +i2cdetect -y 1 + +3. Camera / Video Issues +❗ Camera not detected or fails to start + +Enable camera interface: +sudo raspi-config +→ Interface Options → Camera → Enable +sudo reboot + +Check if camera is visible: +vcgencmd get_camera + +4. Wi-Fi / SSH / Connectivity Problems +| Problem | Fix | +| -------------------------------- | --------------------------------------------- | +| SSH connection refused | `sudo raspi-config → Interface Options → SSH` | +| Device not showing on network | Check IP using: `hostname -I` | +| Slow Wi-Fi / unstable connection | Prefer 2.4 GHz band, update OS | +| Unable to access Pi headless | Add `ssh` file to boot partition | + + +5. Performance Issues +Raspberry Pi running slow / laggy + +Close unused applications + +Reduce background services + +Use Lite OS if no desktop needed + +Ensure sufficient power supply (5V/3A or better) + +Check CPU load: +top +htop + +Storage issues: +sudo apt autoremove +sudo apt clean +df -h + +--- + + +**Aviso Legal**: +Este documento foi traduzido utilizando o serviço de tradução automática [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que as traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritativa. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes da utilização desta tradução. + \ No newline at end of file diff --git a/translations/pt-PT/for-teachers.md b/translations/pt-PT/for-teachers.md new file mode 100644 index 000000000..12d04cf4a --- /dev/null +++ b/translations/pt-PT/for-teachers.md @@ -0,0 +1,30 @@ +# Para Educadores + +Gostaria de usar este currículo na sua sala de aula? Fique à vontade! + +Na verdade, pode utilizá-lo diretamente no GitHub, através do GitHub Classroom. + +Para isso, faça um fork deste repositório. Vai precisar criar um repositório para cada aula, então será necessário extrair cada pasta para um repositório separado. Dessa forma, [GitHub Classroom](https://classroom.github.com/classrooms) poderá identificar cada aula individualmente. + +Estas [instruções completas](https://github.blog/2020-03-18-set-up-your-digital-classroom-with-github-classroom/) irão ajudá-lo a configurar a sua sala de aula. + +## Modelo de aprendizagem recomendado + +Pode ler mais sobre um modelo de aprendizagem recomendado para ensinar este currículo no nosso [Guia de modelo de aprendizagem recomendado](recommended-learning-model.md). + +## Utilizar o repositório como está + +Se preferir usar este repositório no formato atual, sem utilizar o GitHub Classroom, isso também é possível. Será necessário comunicar aos seus alunos qual aula devem trabalhar juntos. + +Num formato online (Zoom, Teams ou outro), pode criar salas de grupo para os questionários e orientar os alunos para ajudá-los a se prepararem para aprender. Depois, convide os alunos para os questionários e peça que enviem as respostas como 'issues' num horário específico. Pode fazer o mesmo com os trabalhos, caso queira que os alunos trabalhem colaborativamente de forma aberta. + +Se preferir um formato mais privado, peça aos seus alunos para fazerem fork do currículo, aula por aula, para os seus próprios repositórios privados no GitHub, e concederem-lhe acesso. Assim, poderão completar os questionários e trabalhos de forma privada e enviá-los para si através de issues no repositório da sua sala de aula. + +Existem várias formas de fazer isto funcionar num formato de sala de aula online. Por favor, informe-nos sobre o que funciona melhor para si! + +## Por favor, partilhe a sua opinião! + +Queremos que este currículo funcione para si e para os seus alunos. Por favor, envie-nos o seu [feedback](https://forms.microsoft.com/Pages/ResponsePage.aspx?id=v4j5cvGGr0GRqy180BHbR2humCsRZhxNuI79cm6n0hRUQzRVVU9VVlU5UlFLWTRLWlkyQUxORTg5WS4u). + +**Aviso Legal**: +Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes do uso desta tradução. \ No newline at end of file diff --git a/translations/pt-PT/hardware.md b/translations/pt-PT/hardware.md new file mode 100644 index 000000000..e53fcff03 --- /dev/null +++ b/translations/pt-PT/hardware.md @@ -0,0 +1,110 @@ +# Hardware + +O **T** em IoT significa **Things** (Coisas) e refere-se a dispositivos que interagem com o mundo à nossa volta. Cada projeto é baseado em hardware real disponível para estudantes e entusiastas. Temos duas opções de hardware IoT para usar, dependendo da preferência pessoal, conhecimento ou preferência de linguagem de programação, objetivos de aprendizagem e disponibilidade. Também fornecemos uma versão de 'hardware virtual' para aqueles que não têm acesso ao hardware ou que desejam aprender mais antes de fazer uma compra. + +> 💁 Não é necessário comprar nenhum hardware IoT para concluir os exercícios. Pode fazer tudo utilizando hardware IoT virtual. + +As opções de hardware físico são Arduino ou Raspberry Pi. Cada plataforma tem as suas vantagens e desvantagens, que são abordadas numa das lições iniciais. Se ainda não decidiu qual plataforma de hardware usar, pode consultar [a lição dois do primeiro projeto](./1-getting-started/lessons/2-deeper-dive/README.md) para decidir qual a plataforma de hardware que mais lhe interessa aprender. + +O hardware específico foi escolhido para reduzir a complexidade das lições e exercícios. Embora outros hardwares possam funcionar, não podemos garantir que todos os exercícios serão suportados no seu dispositivo sem hardware adicional. Por exemplo, muitos dispositivos Arduino não têm WiFi, que é necessário para se conectar à nuvem - o terminal Wio foi escolhido porque já tem WiFi integrado. + +Também precisará de alguns itens não técnicos, como terra ou uma planta em vaso, e frutas ou vegetais. + +## Comprar os kits + +![O logótipo da Seeed Studios](../../translated_images/pt-PT/seeed-logo.74732b6b482b6e8e.webp) + +A Seeed Studios gentilmente disponibilizou todo o hardware em kits fáceis de adquirir: + +### Arduino - Wio Terminal + +**[IoT para principiantes com Seeed e Microsoft - Kit Inicial Wio Terminal](https://www.seeedstudio.com/IoT-for-beginners-with-Seeed-and-Microsoft-Wio-Terminal-Starter-Kit-p-5006.html)** + +[![O kit de hardware Wio Terminal](../../translated_images/pt-PT/wio-hardware-kit.4c70c48b85e4283a.webp)](https://www.seeedstudio.com/IoT-for-beginners-with-Seeed-and-Microsoft-Wio-Terminal-Starter-Kit-p-5006.html) + +### Raspberry Pi + +**[IoT para principiantes com Seeed e Microsoft - Kit Inicial Raspberry Pi 4](https://www.seeedstudio.com/IoT-for-beginners-with-Seeed-and-Microsoft-Raspberry-Pi-Starter-Kit-p-5004.html)** + +[![O kit de hardware Raspberry Pi Terminal](../../translated_images/pt-PT/pi-hardware-kit.26dbadaedb7dd44c73b0131d5d68ea29472ed0a9744f90d5866c6d82f2d16380.png)](https://www.seeedstudio.com/IoT-for-beginners-with-Seeed-and-Microsoft-Raspberry-Pi-Starter-Kit-p-5004.html) + +## Arduino + +Todo o código para dispositivos Arduino está em C++. Para concluir todos os exercícios, precisará do seguinte: + +### Hardware Arduino + +* [Wio Terminal](https://www.seeedstudio.com/Wio-Terminal-p-4509.html) +* *Opcional* - Cabo USB-C ou adaptador USB-A para USB-C. O terminal Wio tem uma porta USB-C e vem com um cabo USB-C para USB-A. Se o seu PC ou Mac tiver apenas portas USB-C, precisará de um cabo USB-C ou de um adaptador USB-A para USB-C. + +### Sensores e atuadores específicos do Arduino + +Estes são específicos para o dispositivo Arduino Wio Terminal e não são relevantes para o uso do Raspberry Pi. + +* [ArduCam Mini 2MP Plus - OV2640](https://www.arducam.com/product/arducam-2mp-spi-camera-b0067-arduino/) +* [ReSpeaker 2-Mics Pi HAT](https://www.seeedstudio.com/ReSpeaker-2-Mics-Pi-HAT.html) +* [Cabos jumper para breadboard](https://www.seeedstudio.com/Breadboard-Jumper-Wire-Pack-241mm-200mm-160mm-117m-p-234.html) +* Auscultadores ou outra coluna com uma entrada de 3,5 mm, ou uma coluna JST, como: + * [Coluna Mono Enclosed - 2W 6 Ohm](https://www.seeedstudio.com/Mono-Enclosed-Speaker-2W-6-Ohm-p-2832.html) +* Cartão microSD de 16GB ou menos, juntamente com um conector para usar o cartão SD no seu computador, caso não tenha um integrado. **NOTA** - o terminal Wio suporta apenas cartões SD até 16GB, não suporta capacidades superiores. + +## Raspberry Pi + +Todo o código para dispositivos Raspberry Pi está em Python. Para concluir todos os exercícios, precisará do seguinte: + +### Hardware Raspberry Pi + +* [Raspberry Pi](https://www.raspberrypi.org/products/raspberry-pi-4-model-b/) + > 💁 Versões a partir do Pi 2B devem funcionar com os exercícios destas lições. Se planeia executar o VS Code diretamente no Pi, então um Pi 4 com 2GB ou mais de RAM é necessário. Se vai aceder ao Pi remotamente, qualquer Pi 2B ou superior funcionará. +* Cartão microSD (Pode adquirir kits Raspberry Pi que já incluem um cartão microSD), juntamente com um conector para usar o cartão SD no seu computador, caso não tenha um integrado. +* Fonte de alimentação USB (Pode adquirir kits Raspberry Pi 4 que já incluem uma fonte de alimentação). Se estiver a usar um Raspberry Pi 4, precisará de uma fonte de alimentação USB-C; dispositivos anteriores precisam de uma fonte de alimentação micro-USB. + +### Sensores e atuadores específicos do Raspberry Pi + +Estes são específicos para o uso do Raspberry Pi e não são relevantes para o dispositivo Arduino. + +* [Grove Pi base hat](https://www.seeedstudio.com/Grove-Base-Hat-for-Raspberry-Pi.html) +* [Módulo de câmara Raspberry Pi](https://www.raspberrypi.org/products/camera-module-v2/) +* Microfone e coluna: + + Use uma das seguintes opções (ou equivalente): + * Qualquer microfone USB com qualquer coluna USB, ou coluna com cabo jack de 3,5 mm, ou saída de áudio HDMI se o seu Raspberry Pi estiver ligado a um monitor ou TV com colunas + * Qualquer headset USB com microfone integrado + * [ReSpeaker 2-Mics Pi HAT](https://www.seeedstudio.com/ReSpeaker-2-Mics-Pi-HAT.html) com + * Auscultadores ou outra coluna com uma entrada de 3,5 mm, ou uma coluna JST, como: + * [Coluna Mono Enclosed - 2W 6 Ohm](https://www.seeedstudio.com/Mono-Enclosed-Speaker-2W-6-Ohm-p-2832.html) + * [Speakerphone USB](https://www.amazon.com/USB-Speakerphone-Conference-Business-Microphones/dp/B07Q3D7F8S/ref=sr_1_1?dchild=1&keywords=m0&qid=1614647389&sr=8-1) +* [Sensor de luz Grove](https://www.seeedstudio.com/Grove-Light-Sensor-v1-2-LS06-S-phototransistor.html) +* [Botão Grove](https://www.seeedstudio.com/Grove-Button.html) + +## Sensores e atuadores + +A maioria dos sensores e atuadores necessários são usados tanto nos percursos de aprendizagem do Arduino como do Raspberry Pi: + +* [LED Grove](https://www.seeedstudio.com/Grove-LED-Pack-p-4364.html) x 2 +* [Sensor de humidade e temperatura Grove](https://www.seeedstudio.com/Grove-Temperature-Humidity-Sensor-DHT11.html) +* [Sensor de humidade do solo capacitivo Grove](https://www.seeedstudio.com/Grove-Capacitive-Moisture-Sensor-Corrosion-Resistant.html) +* [Relé Grove](https://www.seeedstudio.com/Grove-Relay.html) +* [GPS Grove (Air530)](https://www.seeedstudio.com/Grove-GPS-Air530-p-4584.html) +* [Sensor de distância Time of Flight Grove](https://www.seeedstudio.com/Grove-Time-of-Flight-Distance-Sensor-VL53L0X.html) + +## Hardware opcional + +As lições sobre rega automatizada funcionam utilizando um relé. Como opção, pode ligar este relé a uma bomba de água alimentada por USB utilizando o hardware listado abaixo. + +* [Bomba de água 6V](https://www.seeedstudio.com/6V-Mini-Water-Pump-p-1945.html) +* [Terminal USB](https://www.adafruit.com/product/3628) +* Tubos de silicone +* Fios vermelho e preto +* Pequena chave de fendas de cabeça plana + +## Hardware virtual + +A opção de hardware virtual fornecerá simuladores para os sensores e atuadores, implementados em Python. Dependendo da disponibilidade do seu hardware, pode executar isto no seu dispositivo de desenvolvimento normal, como um Mac, PC, ou executá-lo num Raspberry Pi e simular apenas o hardware que não possui. Por exemplo, se tiver a câmara Raspberry Pi mas não os sensores Grove, poderá executar o código do dispositivo virtual no seu Pi e simular os sensores Grove, mas usar uma câmara física. + +O hardware virtual usará o [projeto CounterFit](https://github.com/CounterFit-IoT/CounterFit). + +Para concluir estas lições, precisará de uma webcam, microfone e saída de áudio, como colunas ou auscultadores. Estes podem ser integrados ou externos e precisam de estar configurados para funcionar com o seu sistema operativo e disponíveis para uso em todas as aplicações. + +**Aviso Legal**: +Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, é importante notar que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes do uso desta tradução. \ No newline at end of file diff --git a/translations/pt-PT/images/README.md b/translations/pt-PT/images/README.md new file mode 100644 index 000000000..bd45a93ef --- /dev/null +++ b/translations/pt-PT/images/README.md @@ -0,0 +1,10 @@ +# Imagens + +As imagens na pasta [icons](../../../images/icons) são do [Noun Project](https://thenounproject.com) e requerem atribuição. Cada imagem indica a atribuição necessária. Estas imagens devem ser usadas em qualquer diagrama que precise delas para manter a consistência visual. + +O ficheiro [Diagrams.sketch](../../../images/Diagrams.sketch) é um documento do [Sketch](https://www.sketch.com) que contém todos os diagramas utilizados nas lições e projetos. Se estiveres envolvido numa tradução, por favor traduz também estes diagramas, copiando e atualizando o documento ou fornecendo uma lista das palavras que precisas traduzir como um problema no GitHub. + +O resto das imagens são utilizadas ao longo das lições e projetos. + +**Aviso Legal**: +Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos pela precisão, esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes do uso desta tradução. \ No newline at end of file diff --git a/translations/pt-PT/lesson-template/README.md b/translations/pt-PT/lesson-template/README.md new file mode 100644 index 000000000..556ff3b42 --- /dev/null +++ b/translations/pt-PT/lesson-template/README.md @@ -0,0 +1,54 @@ +# [Tópico da Aula] + +![Incorporar um vídeo aqui](../../../lesson-template/video-url) + +## [Questionário pré-aula](../../../lesson-template/quiz-url) + +[Descreva o que iremos aprender] + +### Introdução + +Descreva o que será abordado + +> Notas + +### Pré-requisitos + +Quais etapas devem ter sido concluídas antes desta aula? + +### Preparação + +Passos preparatórios para iniciar esta aula + +--- + +[Avance pelo conteúdo em blocos] + +## [Tópico 1] + +### Tarefa: + +Trabalhem juntos para melhorar progressivamente a base de código e construir o projeto com código compartilhado: + +```html +code blocks +``` + +✅ Verificação de Conhecimento - aproveite este momento para expandir o conhecimento dos alunos com perguntas abertas + +## [Tópico 2] + +## [Tópico 3] + +🚀 Desafio: Adicione um desafio para os alunos trabalharem colaborativamente em sala de aula para melhorar o projeto + +Opcional: adicione uma captura de ecrã da interface do utilizador da aula concluída, se for apropriado + +## [Questionário pós-aula](../../../lesson-template/quiz-url) + +## Revisão & Estudo Individual + +**Entrega do Trabalho [MM/AA]**: [Nome do Trabalho](assignment.md) + +**Aviso Legal**: +Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos pela precisão, esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes do uso desta tradução. \ No newline at end of file diff --git a/translations/pt-PT/lesson-template/assignment.md b/translations/pt-PT/lesson-template/assignment.md new file mode 100644 index 000000000..97c80e4aa --- /dev/null +++ b/translations/pt-PT/lesson-template/assignment.md @@ -0,0 +1,12 @@ +# [Nome da Tarefa] + +## Instruções + +## Rubrica + +| Critérios | Exemplar | Adequado | Necessita de Melhorias | +| --------- | --------- | -------- | ---------------------- | +| | | | | + +**Aviso Legal**: +Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, é importante notar que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes do uso desta tradução. \ No newline at end of file diff --git a/translations/pt-PT/quiz-app/README.md b/translations/pt-PT/quiz-app/README.md new file mode 100644 index 000000000..c46f58340 --- /dev/null +++ b/translations/pt-PT/quiz-app/README.md @@ -0,0 +1,116 @@ +# Questionários + +Estes questionários são os questionários pré e pós-aula para o currículo de IoT para Iniciantes em https://aka.ms/iot-beginners + +## Configuração do projeto + +``` +npm install +``` + +### Compila e recarrega automaticamente para desenvolvimento + +``` +npm run serve +``` + +### Compila e minimiza para produção + +``` +npm run build +``` + +### Verifica e corrige ficheiros + +``` +npm run lint +``` + +### Personalizar configuração + +Consulte [Referência de Configuração](https://cli.vuejs.org/config/). + +Créditos: Agradecimentos à versão original desta aplicação de questionários: https://github.com/arpan45/simple-quiz-vue + +## Implementação no Azure + +Aqui está um guia passo a passo para ajudá-lo a começar: + +1. Faça um fork de um repositório GitHub +Certifique-se de que o código da sua aplicação web estático está no seu repositório GitHub. Faça um fork deste repositório. + +2. Crie uma Aplicação Web Estática no Azure +- Crie uma [conta Azure](http://azure.microsoft.com) +- Acesse o [portal Azure](https://portal.azure.com) +- Clique em “Criar um recurso” e procure por “Aplicação Web Estática”. +- Clique em “Criar”. + +3. Configure a Aplicação Web Estática +- Básico: + - Subscrição: Selecione a sua subscrição Azure. + - Grupo de Recursos: Crie um novo grupo de recursos ou utilize um existente. + - Nome: Forneça um nome para a sua aplicação web estática. + - Região: Escolha a região mais próxima dos seus utilizadores. + +- #### Detalhes de Implementação: + - Fonte: Selecione “GitHub”. + - Conta GitHub: Autorize o Azure a aceder à sua conta GitHub. + - Organização: Selecione a sua organização GitHub. + - Repositório: Escolha o repositório que contém a sua aplicação web estática. + - Branch: Selecione a branch da qual deseja implementar. + +- #### Detalhes de Construção: + - Predefinições de Construção: Escolha o framework com o qual a sua aplicação foi construída (por exemplo, React, Angular, Vue, etc.). + - Localização da Aplicação: Especifique a pasta que contém o código da sua aplicação (por exemplo, / se estiver na raiz). + - Localização da API: Caso tenha uma API, especifique a sua localização (opcional). + - Localização de Saída: Especifique a pasta onde a saída da construção é gerada (por exemplo, build ou dist). + +4. Rever e Criar +Revise as suas configurações e clique em “Criar”. O Azure configurará os recursos necessários e criará um workflow de GitHub Actions no seu repositório. + +5. Workflow de GitHub Actions +O Azure criará automaticamente um ficheiro de workflow de GitHub Actions no seu repositório (.github/workflows/azure-static-web-apps-.yml). Este workflow irá gerir o processo de construção e implementação. + +6. Monitorizar a Implementação +Acesse o separador “Actions” no seu repositório GitHub. +Deverá ver um workflow em execução. Este workflow irá construir e implementar a sua aplicação web estática no Azure. +Assim que o workflow for concluído, a sua aplicação estará ativa no URL fornecido pelo Azure. + +### Exemplo de Ficheiro de Workflow + +Aqui está um exemplo de como o ficheiro de workflow de GitHub Actions pode parecer: +name: Azure Static Web Apps CI/CD +``` +on: + push: + branches: + - main + pull_request: + types: [opened, synchronize, reopened, closed] + branches: + - main + +jobs: + build_and_deploy_job: + runs-on: ubuntu-latest + name: Build and Deploy Job + steps: + - uses: actions/checkout@v2 + - name: Build And Deploy + id: builddeploy + uses: Azure/static-web-apps-deploy@v1 + with: + azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN }} + repo_token: ${{ secrets.GITHUB_TOKEN }} + action: "upload" + app_location: "quiz-app" #App source code path + api_location: ""API source code path optional + output_location: "dist" #Built app content directory - optional +``` + +### Recursos Adicionais +- [Documentação de Aplicações Web Estáticas no Azure](https://learn.microsoft.com/azure/static-web-apps/getting-started) +- [Documentação de GitHub Actions](https://docs.github.com/actions/use-cases-and-examples/deploying/deploying-to-azure-static-web-app) + +**Aviso Legal**: +Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, é importante notar que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes da utilização desta tradução. \ No newline at end of file diff --git a/translations/pt-PT/recommended-learning-model.md b/translations/pt-PT/recommended-learning-model.md new file mode 100644 index 000000000..f88490620 --- /dev/null +++ b/translations/pt-PT/recommended-learning-model.md @@ -0,0 +1,44 @@ +# Modelo de aprendizagem recomendado + +Para obter os resultados de aprendizagem mais eficazes, **recomendamos uma abordagem de “Modelo Invertido"**, semelhante aos laboratórios de ciências: os alunos trabalham em projetos durante o horário de aula, com oportunidades para discussões, perguntas e respostas, e assistência nos projetos, enquanto os elementos teóricos são realizados como leituras prévias no seu próprio tempo. + +## Por que Aprendizagem Invertida? + +1. Este método de ensino envolve uma variedade de métodos de aprendizagem – visual, auditivo, prático, resolução de problemas, etc.[[1]](../..) +2. As salas de aula invertidas demonstraram aumentar o foco, o envolvimento, a motivação, a autonomia, a retenção de conhecimento e a comunicação (tanto entre professor e aluno quanto entre os próprios alunos).[[2,3]](../..) +3. Como instrutores, podem dedicar mais tempo aos alunos que têm dificuldades, enquanto permitem que os alunos mais avançados trabalhem de forma independente e progridam no seu próprio ritmo.[[4]](../..) + +Também recomendamos que os instrutores assumam o papel de **“Co-Facilitador"**, aprendendo junto com os alunos e apoiando-os enquanto exploram questões e ideias impulsionadas pelos seus próprios interesses e perceções. + +Não há uma “forma certa" de fazer as coisas aqui. Por vezes, não terão todas as respostas. Alguns alunos podem não concluir todos os projetos. O vosso objetivo é ajudar os alunos a encontrar, de forma orgânica, maneiras de resolver problemas que podem ser mais lúdicas, colaborativas ou autodirigidas do que inicialmente esperavam. + +## Dicas úteis para facilitação: + +* Reflitam sobre o que observam, façam perguntas e partilhem observações. +* Usem frases como “Reparei que..." e “Pergunto-me se..." +* Conectem alunos que estão com dificuldades com aqueles que já encontraram soluções. +* Apontem para componentes e partes ou façam sugestões sobre diferentes abordagens a tentar, caso um aluno esteja bloqueado. Peçam ao aluno para alterar uma coisa de cada vez e observar o que acontece. +* Reconheçam a frustração e valorizem o esforço. +* Evitem construir ou programar pelos alunos, exceto quando precisarem de assistência física. + +## Linguagem de facilitação sugerida: + +* “Pergunta a dois colegas antes de me perguntares a mim." +* “Tenta mais dois minutos..." +* “Vamos fazer uma pausa nisto. Talvez possas ajudar outros alunos com as ligações elétricas, já que já descobriste como fazê-las?" +* “Pergunto-me se outro aluno teve o mesmo problema. Vamos verificar!" +* “Comprometeste-te mesmo com isto e conseguiste resolver! Posso enviar outros alunos para te pedirem ajuda com isto?" +* “Isso é estranho, também não faz sentido para mim. Talvez possamos perguntar a outro aluno, ou, se descobrires, podes partilhar com a turma?" + +## Referências + +[1] [An empirical study on the effectiveness of College English Reading classroom teaching in the flipped classroom paradigm (researchgate.net)](https://www.researchgate.net/publication/322264495_An_empirical_study_on_the_effectiveness_of_College_English_Reading_classroom_teaching_in_the_flipped_classroom_paradigm). Acedido em 21/04/21. + +[2] [Flipped Classroom adapted to the ARCS Model of Motivation and applied to a Physics Course (ejmste.com)](https://www.ejmste.com/article/flipped-classroom-adapted-to-the-arcs-model-of-motivation-and-applied-to-a-physics-course-4562). Acedido em 21/04/21. + +[3] [How Does Flipping Classroom Foster the STEM Education: A Case Study of the FPD Model | SpringerLink](https://link.springer.com/article/10.1007/s10758-020-09443-9). Acedido em 21/04/21. + +[4] [An Introduction to Flipped Learning | Lesley University](https://lesley.edu/article/an-introduction-to-flipped-learning#:~:text=An%20Introduction%20to%20Flipped%20Learning.%20Flipped%20learning%20is,advancements%20in%20the%20modern%20classroom%20is%20flipped%20learning.). Acedido em 21/04/21. + +**Aviso Legal**: +Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos pela precisão, esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes do uso desta tradução. \ No newline at end of file