Todas as atividades
Quiz e Avaliação

Conjunto de Fala

Versão em série do Falar as Palavras: o aprendiz responde múltiplos prompts em sequência usando reconhecimento de voz. Ideal para prática oral extensiva.

Conhecimento e compreensão voz fala série speech

Experimente

Leia cada termo em voz alta quando o microfone aparecer:

1 / 4
1 Avaliação formativa

Código-fonte

PHP

Dados de exemplo

Termos pra ler em voz alta, um por vez.

1 <?php
2 $termos = ['maçã', 'banana', 'laranja'];
3 $total = count($termos);
4 ?>

Estrutura da atividade

Contador no topo e os termos empilhados, todos menos o primeiro nascem ocultos.

1 <div class="questao" data-tipo="conjunto-fala" data-total="<?= $total ?>">
2
3 <div class="questao-cabecalho">
4 <p>Diga cada termo em voz alta quando o microfone aparecer:</p>
5 <span><span class="questao-atual">1</span> / <?= $total ?></span>
6 </div>
7
8 <?php foreach ($termos as $qi => $termo): ?>
9 <div class="questao-item<?= $qi > 0 ? ' oculto' : '' ?>" data-qi="<?= $qi ?>">
10 <p class="questao-termo"><?= htmlspecialchars($termo) ?></p>
11 <button type="button" class="questao-mic" data-resposta="<?= htmlspecialchars($termo) ?>">
12 Falar
13 </button>
14 <p class="questao-feedback" hidden></p>
15 </div>
16 <?php endforeach; ?>

Botão único de avançar

Fora do laço de termos — sempre a última coisa do card, some de novo a cada clique.

1 <button type="button" class="questao-proximo" hidden>Próxima →</button>
2
3 <div class="questao-resultado" hidden>
4 <p class="questao-placar"><span class="questao-acertos">0</span> / <?= $total ?> termos reconhecidos</p>
5 <button type="button" class="questao-reiniciar">Recomeçar atividade</button>
6 </div>
7
8 </div>
CSS

Card e cabeçalho

Contêiner da atividade e a linha com instrução + contador "1 / N".

1 .questao[data-tipo="conjunto-fala"] {
2 max-width: 420px;
3 padding: 24px;
4 border: 1px solid #e2e8f0;
5 border-radius: 16px;
6 background: #fff;
7 font-family: sans-serif;
8 }
9
10 .questao-cabecalho {
11 display: flex;
12 align-items: center;
13 justify-content: space-between;
14 margin-bottom: 20px;
15 font-size: 14px;
16 color: #64748b;
17 }
18
19 .questao-cabecalho span:last-child {
20 padding: 4px 10px;
21 border-radius: 999px;
22 background: #f1f5f9;
23 font-size: 12px;
24 flex-shrink: 0;
25 }

Termo ativo

.oculto tira o termo da tela — só um fica visível por vez.

1 .questao-item.oculto {
2 display: none;
3 }
4
5 .questao-termo {
6 margin: 0 0 16px;
7 font-weight: 600;
8 font-size: 18px;
9 color: #0f172a;
10 }

Botão do microfone

Cor por classe (.ouvindo/.acerto/.erro) — o clique já é a tentativa e a correção.

1 .questao-mic {
2 padding: 12px 24px;
3 border: 2px solid #6366f1;
4 border-radius: 999px;
5 background: rgba(99, 102, 241, .1);
6 color: #4338ca;
7 font: inherit;
8 font-weight: 600;
9 cursor: pointer;
10 }
11
12 .questao-mic:disabled { cursor: not-allowed; }
13 .questao-mic.ouvindo { border-color: #dc2626; background: rgba(220, 38, 38, .1); color: #b91c1c; }
14 .questao-mic.acerto { border-color: #16a34a; background: rgba(22, 163, 74, .1); color: #15803d; }
15 .questao-mic.erro { border-color: #dc2626; background: rgba(220, 38, 38, .1); color: #b91c1c; }

Feedback e navegação

Mensagem de acerto/erro por termo, e os botões de avançar/reiniciar.

1 .questao-feedback {
2 margin-top: 16px;
3 padding: 10px 14px;
4 border-radius: 10px;
5 font-size: 14px;
6 }
7
8 .questao-feedback.acerto { background: #dcfce7; color: #14532d; }
9 .questao-feedback.erro { background: #fee2e2; color: #7f1d1d; }
10
11 .questao-proximo,
12 .questao-reiniciar {
13 width: 100%;
14 margin-top: 16px;
15 padding: 12px 16px;
16 border: none;
17 border-radius: 10px;
18 background: #4f46e5;
19 color: #fff;
20 font: inherit;
21 font-weight: 600;
22 cursor: pointer;
23 }
24
25 .questao-reiniciar { background: #e5e7eb; color: #1f2937; margin-top: 12px; }

Resultado final

Placar centralizado, escondido até o último termo ser reconhecido.

1 .questao-resultado {
2 padding: 16px;
3 border-radius: 10px;
4 background: #eef2ff;
5 text-align: center;
6 }
7
8 .questao-placar {
9 margin: 0;
10 font-size: 22px;
11 font-weight: 700;
12 color: #4338ca;
13 }
JavaScript

Encontrar os elementos da atividade

Contador, placar e o botão único de avançar — compartilhados por todos os termos.

1 document.addEventListener('DOMContentLoaded', function () {
2 document.querySelectorAll('.questao[data-tipo="conjunto-fala"]').forEach(function (questao) {
3 var total = parseInt(questao.dataset.total, 10);
4 var acertos = 0;
5 var atualEl = questao.querySelector('.questao-atual');
6 var proximo = questao.querySelector('.questao-proximo');
7 var resultado = questao.querySelector('.questao-resultado');
8 var acertosEl = questao.querySelector('.questao-acertos');

Verificar suporte do navegador

Só o Chrome e outros baseados em Chromium implementam o reconhecimento de voz.

1 var Reconhecimento = window.SpeechRecognition || window.webkitSpeechRecognition;
2 if (!Reconhecimento) {
3 questao.querySelectorAll('.questao-mic').forEach(function (mic) { mic.disabled = true; });
4 return;
5 }

Comparar a transcrição com o termo esperado

Normaliza maiúsculas, acentos e pontuação — a API costuma devolver "Maçã." em vez de "maçã".

1 function normalizar(texto) {
2 return texto
3 .toLowerCase()
4 .normalize('NFD').replace(/\p{Diacritic}/gu, '')
5 .replace(/[^\p{L}\p{N}\s]/gu, '')
6 .trim();
7 }

Revelar o botão de avançar

Rotula pro termo atual ("Próxima →" ou "Ver resultado" no último).

1 function revelarProximo(qi) {
2 proximo.textContent = qi < total - 1 ? 'Próxima →' : 'Ver resultado';
3 proximo.dataset.qi = qi;
4 proximo.hidden = false;
5 }

Reconhecer cada termo

Um microfone por item — clicar já é a tentativa e a correção, no mesmo gesto.

1 questao.querySelectorAll('.questao-item').forEach(function (item) {
2 var qi = parseInt(item.dataset.qi, 10);
3 var mic = item.querySelector('.questao-mic');
4 var fb = item.querySelector('.questao-feedback');
5 var esperado = mic.dataset.resposta;
6
7 mic.addEventListener('click', function () {
8 var recognition = new Reconhecimento();
9 recognition.lang = 'pt-BR';
10
11 recognition.onstart = function () { mic.classList.add('ouvindo'); };
12
13 recognition.onresult = function (evento) {
14 var transcricao = evento.results[0][0].transcript;
15 var correta = normalizar(transcricao) === normalizar(esperado);
16
17 mic.classList.remove('ouvindo');
18 mic.classList.add(correta ? 'acerto' : 'erro');
19 mic.disabled = true;
20 if (correta) acertos++;
21
22 fb.className = 'questao-feedback ' + (correta ? 'acerto' : 'erro');
23 fb.textContent = correta
24 ? 'Reconhecido! Você disse: "' + transcricao + '".'
25 : 'Não reconheci. Você disse: "' + transcricao + '".';
26 fb.hidden = false;
27
28 revelarProximo(qi);
29 };
30
31 recognition.onerror = function () { mic.classList.remove('ouvindo'); };
32
33 recognition.start();
34 });
35 });

Avançar pro próximo termo ou pro resultado

Um único botão pra atividade inteira — o clique já o esconde de novo.

1 proximo.addEventListener('click', function () {
2 var qi = parseInt(proximo.dataset.qi, 10);
3 proximo.hidden = true;
4 questao.querySelector('.questao-item[data-qi="' + qi + '"]').classList.add('oculto');
5
6 if (qi === total - 1) {
7 resultado.hidden = false;
8 acertosEl.textContent = acertos;
9 } else {
10 questao.querySelector('.questao-item[data-qi="' + (qi + 1) + '"]').classList.remove('oculto');
11 atualEl.textContent = qi + 2;
12 }
13 });

Reiniciar

Zera o placar, volta pro primeiro termo e libera todos os microfones.

1 questao.querySelector('.questao-reiniciar').addEventListener('click', function () {
2 acertos = 0;
3 atualEl.textContent = 1;
4 resultado.hidden = true;
5
6 questao.querySelectorAll('.questao-item').forEach(function (item, i) {
7 item.classList.toggle('oculto', i !== 0);
8 });
9 questao.querySelectorAll('.questao-mic').forEach(function (mic) {
10 mic.disabled = false;
11 mic.classList.remove('acerto', 'erro');
12 });
13 questao.querySelectorAll('.questao-feedback').forEach(function (fb) { fb.hidden = true; });
14 });