Spaces:
Runtime error
Runtime error
| <html> | |
| <head> | |
| <title>Kokoro TTS - rapide FR/EN</title> | |
| <style> | |
| body { font-family: sans-serif; max-width: 600px; margin: auto; padding: 2rem; } | |
| textarea, select, input, button { width: 100%; margin: 0.5rem 0; padding: 0.5rem; } | |
| audio { width: 100%; margin-top: 1rem; } | |
| .status { margin-top: 1rem; color: gray; } | |
| </style> | |
| </head> | |
| <body> | |
| <h1>🗣️ Kokoro TTS (ultra rapide)</h1> | |
| <textarea id="text" rows="4">Bonjour, ceci est un test de Kokoro. La synthèse est très rapide et naturelle.</textarea> | |
| <select id="voice"></select> | |
| <select id="lang"> | |
| <option value="fr">Français</option> | |
| <option value="en">Anglais</option> | |
| </select> | |
| <input type="range" id="speed" min="0.5" max="1.5" step="0.05" value="1.0"> | |
| <span>Vitesse: <span id="speedVal">1.0</span></span> | |
| <button id="generate">🎤 Générer</button> | |
| <audio id="audio" controls></audio> | |
| <div id="status" class="status"></div> | |
| <script> | |
| const voiceSelect = document.getElementById('voice'); | |
| const textarea = document.getElementById('text'); | |
| const langSelect = document.getElementById('lang'); | |
| const speedSlider = document.getElementById('speed'); | |
| const speedVal = document.getElementById('speedVal'); | |
| const generateBtn = document.getElementById('generate'); | |
| const audioPlayer = document.getElementById('audio'); | |
| const statusDiv = document.getElementById('status'); | |
| speedSlider.oninput = () => speedVal.innerText = speedSlider.value; | |
| async function loadVoices() { | |
| const res = await fetch('/voices'); | |
| const data = await res.json(); | |
| const allVoices = [...data.builtin, ...data.cloned]; | |
| voiceSelect.innerHTML = allVoices.map(v => `<option value="${v}">${v}</option>`).join(''); | |
| } | |
| generateBtn.onclick = async () => { | |
| const text = textarea.value.trim(); | |
| const voice = voiceSelect.value; | |
| const lang = langSelect.value; | |
| const speed = parseFloat(speedSlider.value); | |
| if (!text) return; | |
| statusDiv.innerText = '⏳ Génération en cours...'; | |
| try { | |
| const response = await fetch('/tts', { | |
| method: 'POST', | |
| headers: { 'Content-Type': 'application/json' }, | |
| body: JSON.stringify({ text, voice, speed, lang }) | |
| }); | |
| if (response.ok) { | |
| const blob = await response.blob(); | |
| const url = URL.createObjectURL(blob); | |
| audioPlayer.src = url; | |
| audioPlayer.play(); | |
| statusDiv.innerText = '✅ Audio prêt'; | |
| } else { | |
| const err = await response.text(); | |
| statusDiv.innerText = `❌ Erreur: ${err}`; | |
| } | |
| } catch(e) { | |
| statusDiv.innerText = `❌ ${e.message}`; | |
| } | |
| }; | |
| loadVoices(); | |
| </script> | |
| </body> | |
| </html> | |