🚀 Auto-deploy: Camila atualizado em 03/06/2026 10:44:31

This commit is contained in:
2026-06-03 10:44:31 +00:00
parent e41e3b6cbf
commit 0f3bf4c2dd
+39 -31
View File
@@ -775,27 +775,14 @@ const initApp = () => {
// TTS — Speech Synthesis nativa (voz do navegador)
// ==========================================================================
let cachedVoices = [];
let currentSpeakingBtn = null;
const loadVoices = () => {
const voices = window.speechSynthesis.getVoices();
if (voices.length > 0) {
cachedVoices = voices;
console.log('Vozes pt-BR disponíveis:', cachedVoices.filter(v => v.lang.startsWith('pt')).map(v => v.name));
} else {
window.speechSynthesis.addEventListener('voiceschanged', () => {
cachedVoices = window.speechSynthesis.getVoices();
console.log('Vozes pt-BR disponíveis:', cachedVoices.filter(v => v.lang.startsWith('pt')).map(v => v.name));
}, { once: true });
}
};
loadVoices();
// Selecionar melhor voz pt-BR disponível no dispositivo
// Selecionar melhor voz pt-BR disponível no dispositivo de forma dinâmica
const getBestVoice = () => {
const ptBR = cachedVoices.filter(v => v.lang === 'pt-BR' || v.lang === 'pt_BR');
const voices = window.speechSynthesis.getVoices();
const ptBR = voices.filter(v => v.lang === 'pt-BR' || v.lang === 'pt_BR');
if (ptBR.length === 0) {
const pt = cachedVoices.filter(v => v.lang.startsWith('pt'));
const pt = voices.filter(v => v.lang.startsWith('pt'));
return pt[0] || null;
}
@@ -819,19 +806,34 @@ const initApp = () => {
return ptBR[0];
};
const resetSpeakBtnState = (btn) => {
if (btn) {
btn.classList.remove('speaking');
const span = btn.querySelector('span');
if (span) span.textContent = 'Ouvir';
}
};
// Falar texto com TTS nativa
const speakText = (text, btn) => {
// Se já está falando, parar
if (window.speechSynthesis.speaking) {
if (!text) return;
// Se clicar no botão que já está ativamente falando, parar a reprodução
if (window.speechSynthesis.speaking && currentSpeakingBtn === btn) {
window.speechSynthesis.cancel();
if (btn) {
btn.classList.remove('speaking');
const span = btn.querySelector('span');
if (span) span.textContent = 'Ouvir';
}
resetSpeakBtnState(btn);
currentSpeakingBtn = null;
return;
}
// Se houver outra fala em andamento ou fila travada, limpa tudo e reseta o botão antigo
window.speechSynthesis.cancel();
if (currentSpeakingBtn) {
resetSpeakBtnState(currentSpeakingBtn);
}
currentSpeakingBtn = btn;
// Limpar markdown antes de falar
const clean = text
.replace(/```[\s\S]*?```/g, '')
@@ -842,7 +844,10 @@ const initApp = () => {
.replace(/\s{2,}/g, ' ')
.trim();
if (!clean) return;
if (!clean) {
currentSpeakingBtn = null;
return;
}
const utterance = new SpeechSynthesisUtterance(clean);
utterance.lang = 'pt-BR';
@@ -860,14 +865,17 @@ const initApp = () => {
}
};
utterance.onend = utterance.onerror = () => {
if (btn) {
btn.classList.remove('speaking');
const span = btn.querySelector('span');
if (span) span.textContent = 'Ouvir';
const handleStop = (event) => {
console.log('TTS finalizado ou com erro:', event.type);
if (currentSpeakingBtn === btn) {
resetSpeakBtnState(btn);
currentSpeakingBtn = null;
}
};
utterance.onend = handleStop;
utterance.onerror = handleStop;
window.speechSynthesis.speak(utterance);
};