Olá José, tudo bem?
Primeiramente me desculpe pela demora no retorno. :)
Bem, fiz o download do seu projeto e realizei alguns testes baseados no seu feedback. Uma coisa que achei interessante é que a velocidade em que se diz o número importa na maneira como o reconhecimento vai atuar: se vai colocar espaço, se vai escrever o número por extenso ou se vai retornar o número como um número de fato.
Outros pontos que observei foram os seguintes:
- Se o número falado for negativo e dito de forma pausada, a tendência da API é escrever a palavra "menos" ao invés do sinal "-";
- Se o número falado for negativo, estiver entre 1 e 9 e expressado de forma pausada, a tendência do resultado retornado pela transcrição é o texto "menos" concatenado com o nome do número por extenso. Ex: "menos cinco", "menos seis", etc.
- Se o número falado for negativo mas for maior que 9 e também for dito de forma pausada, o resultado tende a ser algo como "menos 50", "menos 12" etc.
- Caso o número seja positivo, estiver entre 1 e 9 e também for dito de forma pausada, o resultado também tende a ser o número por extenso: "cinco", "nove", "três" etc.
- Números positivos ou negativos maiores que 9 sempre foram retornados como números (independente se a fala foi pausada ou rápida);
- Por fim, para os cenários de fala mais rápida e clara, os números foram retornados corretamente (sejam positivos ou negativos).
Levando isso em consideração cheguei à seguinte solução:
recognition.onresult = (evento) => {
const numerosPorExtenso = {
"zero": 0,
"um": 1,
"dois": 2,
"três": 3,
"quatro": 4,
"cinco": 5,
"seis": 6,
"sete": 7,
"oito": 8,
"nove": 9
};
let chute = evento.results[0][0].transcript.toLowerCase().replaceAll(" ", "");
console.log("in: ", chute);
for (let [nome, numero] of Object.entries(numerosPorExtenso)) {
if (chute.includes(nome)) {
chute = chute.replace(nome, numero);
break;
}
}
if (chute.startsWith("menos")) {
chute = chute.replace(/menos/g, "-", chute);
}
console.log("out: ", chute);
exibeChuteNaTela(chute);
verificaValorValido(chute);
};
No evento onresult
criei um objeto que faz o mapeamento dos números por extenso entre 0 e 9 para suas versões numéricas. Assim posso fazer a troca do texto "cinco" pelo valor "5" quando ele for retornado, por exemplo.
Em seguida, normalizei o retorno das informações da propriedade transcript
para que o texto retornado seja sempre em letras minúsculas e com quaisquer espaços removidos. Depois exibo esse dado na tela para saber como o dado veio originalmente:
let chute = evento.results[0][0].transcript.toLowerCase().replaceAll(" ", "");
console.log("in: ", chute);
Depois, com um loop for...of
eu percorro os valores e as propriedades do objeto numerosPorExtenso
para verificar se na transcrição retornada há algum dos números que geralmente são retornados por extenso (nos meus testes, como disse, frequentemente são aqueles entre 0 e 9) e se tiver, eu realizo a substituição pelo valor correto. Ex:
Se o transcript retornar "menos cinco", a variável chute
terá como valor a string menoscinco
(sem espaços) e o trecho chute.includes(nome)
vai verificar que o valor cinco
existe no conteúdo variável chute
o qual levará ao replace()
que trocará cinco
por 5
. Aí, o conteúdo final da variável chute
será menos5
até aqui.
Depois, precisamos apenas nos livrar da palavra menos
, caso esta exista. É o que o trecho chute = chute.replace(/menos/g, "-", chute);
faz resultando no valor -5
que será repassado para a função exibeChuteNaTela(chute);
.
Nos testes que fiz exaustivamente, não houve nenhum resultado definido como "Valor inválido!" quando falei números (mesmo quando ele retornava esse número por extenso). Como em todas as tentativas que fiz ele nunca retornou, por extenso, valores maiores que 9, não me preocupei em validar se ao falar "50" em algum momento ele retornaria "cinquenta" (pois isso nunca aconteceu). Mas nada indica que nunca acontecerá, certo?!
Por hora, essa seria a melhor solução dados os testes e os recursos que temos disponíveis na linguagem e na API em si. O ideal seria que a própria API de SpeechRecognition fornecesse uma configuração em que pudéssemos dizer que, ao detectar números na fala, se ela deve retorná-los como um valor numérico ou por extenso. Contudo, isso não se encontra disponível atualmente (até onde sei).
Faça os testes e me fala depois se deu certo ou se no seu caso deu algum bug ainda.
Espero ter ajudado,
Att.