Mates 6.º

Probar voz

Voz MiniMax M3 body { font-family: system-ui, sans-serif; max-width: 720px; margin: 40px auto; padding: 20px; color: #222; } button { font-size: 16px; padding: 12px 18px; margin: 6px 4px; border-radius: 10px; border: 1px solid #888; background: #f4f4f4; cursor: pointer; } button:hover { background: #e0e0e0; } button:disabled { opacity: 0.4; cursor: not-allowed; } textarea { width: 100%; min-height: 120px; font-size: 16px; padding: 10px; border-radius: 8px; border: 1px solid #888; box-sizing: border-box; font-family: inherit; resize: vertical; } #status { color: #555; font-size: 14px; margin: 8px 0; min-height: 1.2em; } .ok { color: #1a7a1a; } .err { color: #b00020; } .info { color: #0a5fbe; } .row { margin: 16px 0; } label { font-weight: 600; display: block; margin-bottom: 6px; } .help { color: #666; font-size: 13px; }

🎙️ Voz MiniMax M3

Esta página prueba el micrófono (STT) y la voz (TTS) de tu navegador. Chrome y Edge funcionan. Firefox NO tiene STT. Safari solo TTS.

Listo.
Cargando voces…
Diagnóstico:
  • STT disponible: ?
  • TTS disponible: ?
  • Voces en español: ?
  • Voces totales: ?
(function(){ const $ = id => document.getElementById(id); const texto = $(‘texto’); const status = $(‘status’); const btnHablar = $(‘btnHablar’); const btnLeer = $(‘btnLeer’); const btnParar = $(‘btnParar’); const btnProbar = $(‘btnProbar’); const selVoces = $(‘voces’); const vocesInfo = $(‘vocesInfo’); function setStatus(msg, cls) { status.textContent = msg; status.className = cls || ”; } // Diagnóstico inicial $(‘d_stt’).textContent = !!(window.SpeechRecognition || window.webkitSpeechRecognition) ? ‘SÍ’ : ‘NO’; $(‘d_tts’).textContent = ‘speechSynthesis’ in window ? ‘SÍ’ : ‘NO’; // ===== STT ===== const SR = window.SpeechRecognition || window.webkitSpeechRecognition; let recognition = null; if (SR) { recognition = new SR(); recognition.lang = ‘es-ES’; recognition.interimResults = false; recognition.maxAlternatives = 1; recognition.continuous = false; recognition.onresult = e => { const t = e.results[0][0].transcript; texto.value = (texto.value + ‘ ‘ + t).trim(); setStatus(‘Te he oído: “‘ + t + ‘”‘, ‘ok’); btnLeer.disabled = false; }; recognition.onerror = e => setStatus(‘Error STT: ‘ + e.error + ‘ — si es “not-allowed”, revisa los permisos del micrófono.’, ‘err’); recognition.onend = () => { btnHablar.disabled = false; btnHablar.textContent = ‘🎤 Hablar (STT)’; }; btnHablar.addEventListener(‘click’, () => { if (btnHablar.disabled) return; btnHablar.disabled = true; btnHablar.textContent = ‘🎤 Escuchando…’; setStatus(‘Te escucho. Habla ahora.’, ‘info’); try { recognition.start(); } catch (e) { setStatus(‘No se pudo iniciar STT: ‘ + e.message, ‘err’); btnHablar.disabled = false; } }); } else { btnHablar.disabled = true; btnHablar.title = ‘Tu navegador no soporta STT. Usa Chrome o Edge.’; } // ===== TTS ===== let voices = []; let voicesReady = false; let voicesReadyResolve = null; const voicesReadyPromise = new Promise(r => { voicesReadyResolve = r; }); function loadVoices() { return new Promise(resolve => { const v = speechSynthesis.getVoices(); if (v && v.length > 0) { voices = v; resolve(v); return; } // Algunos navegadores tardan; esperar al evento const onChange = () => { speechSynthesis.removeEventListener(‘onvoiceschanged’, onChange); const v2 = speechSynthesis.getVoices(); voices = v2 || []; resolve(v2 || []); }; speechSynthesis.addEventListener(‘voiceschanged’, onChange); // Timeout de seguridad: 1.5s setTimeout(() => { speechSynthesis.removeEventListener(‘onvoiceschanged’, onChange); const v3 = speechSynthesis.getVoices(); voices = v3 || []; resolve(v3 || []); }, 1500); }); } // Orden: voces en español primero, luego el resto function sortedVoices() { const es = voices.filter(v => /^es/i.test(v.lang)); const others = voices.filter(v => !/^es/i.test(v.lang)); return […es, …others]; } // Seleccionar voz por defecto inteligente function pickBestVoice() { const sv = sortedVoices(); if (!sv.length) return null; // Preferir voces Microsoft en español, luego Google, luego la primera es const preferNames = [‘Elvira’, ‘Helena’, ‘Laura’, ‘Paloma’, ‘Monica’, ‘Microsoft’]; for (const name of preferNames) { const found = sv.find(v => v.name.toLowerCase().includes(name.toLowerCase())); if (found) return found; } return sv[0]; } function refreshVocesUI() { const sv = sortedVoices(); selVoces.innerHTML = ”; if (!sv.length) { selVoces.innerHTML = ‘(sin voces disponibles — el TTS puede no funcionar)’; $(‘d_es’).textContent = ‘0’; $(‘d_total’).textContent = ‘0’; return; } sv.forEach((v, i) => { const opt = document.createElement(‘option’); opt.value = i; opt.textContent = `${v.name} (${v.lang})${v.default ? ‘ — predeterminada’ : ”}`; selVoces.appendChild(opt); }); // Marcar la mejor por defecto const best = pickBestVoice(); if (best) { const idx = sv.indexOf(best); if (idx >= 0) selVoces.value = idx; vocesInfo.textContent = `Mejor: ${best.name} (${best.lang})`; } const esCount = voices.filter(v => /^es/i.test(v.lang)).length; $(‘d_es’).textContent = esCount; $(‘d_total’).textContent = voices.length; } // Cargar voces al inicio y al evento loadVoices().then(() => { voicesReady = true; voicesReadyResolve(); refreshVocesUI(); }); // Re-cargar si el navegador las entrega tarde if (speechSynthesis.onvoiceschanged !== undefined) { speechSynthesis.onvoiceschanged = () => loadVoices().then(refreshVocesUI); } // Función hablar robusta function hablar(textoALeer) { if (!(‘speechSynthesis’ in window)) { setStatus(‘Tu navegador no soporta TTS.’, ‘err’); return; } if (!textoALeer || !textoALeer.trim()) { setStatus(‘No hay texto para leer.’, ‘err’); return; } // Cancelar lo que esté sonando try { speechSynthesis.cancel(); } catch (e) {} const u = new SpeechSynthesisUtterance(textoALeer); const sv = sortedVoices(); const idx = parseInt(selVoces.value || ‘0’, 10); if (sv[idx]) { u.voice = sv[idx]; u.lang = sv[idx].lang; } else { u.lang = ‘es-ES’; } u.rate = 0.95; // un pelín más lento, mejor para TEA u.pitch = 1.0; u.volume = 1.0; u.onstart = () => { btnParar.disabled = false; setStatus(‘Hablando…’, ‘ok’); }; u.onend = () => { btnParar.disabled = true; setStatus(‘Terminado.’, ‘ok’); }; u.onerror = e => { btnParar.disabled = true; setStatus(‘Error TTS: ‘ + (e.error || ‘desconocido’) + ‘ — prueba otra voz del desplegable.’, ‘err’); }; // Truco: algunos navegadores necesitan un pequeño delay tras cancel() setTimeout(() => { try { speechSynthesis.speak(u); } catch (e) { setStatus(‘No se pudo hablar: ‘ + e.message, ‘err’); } }, 100); } btnLeer.addEventListener(‘click’, () => hablar(texto.value)); btnParar.addEventListener(‘click’, () => { try { speechSynthesis.cancel(); } catch (e) {} btnParar.disabled = true; setStatus(‘Parado.’); }); btnProbar.addEventListener(‘click’, () => hablar(‘Hola Jordi. Soy la IA MiniMax M3. Pulsa hablar y dime tu respuesta.’)); texto.addEventListener(‘input’, () => { btnLeer.disabled = !texto.value.trim(); }); })();