Spaces:
Running
Running
File size: 3,473 Bytes
fdd0daa | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 | document.addEventListener('DOMContentLoaded', () => {
const textInput = document.getElementById('text-input');
const charCurrent = document.getElementById('char-current');
const voiceSelect = document.getElementById('voice-select');
const generateBtn = document.getElementById('generate-btn');
const btnText = document.querySelector('.btn-text');
const btnLoader = document.querySelector('.btn-loader');
const errorMessage = document.getElementById('error-message');
const errorText = document.getElementById('error-text');
const audioContainer = document.getElementById('audio-container');
const audioPlayer = document.getElementById('audio-player');
const downloadBtn = document.getElementById('download-btn');
const MAX_CHARS = 1000;
// Character counter
textInput.addEventListener('input', () => {
const text = textInput.value;
const length = text.length;
if (length > MAX_CHARS) {
textInput.value = text.substring(0, MAX_CHARS);
charCurrent.textContent = MAX_CHARS;
charCurrent.style.color = 'var(--danger)';
} else {
charCurrent.textContent = length;
charCurrent.style.color = 'var(--text-muted)';
}
});
// Generate Button Click
generateBtn.addEventListener('click', async () => {
const text = textInput.value.trim();
const voice = voiceSelect.value;
if (!text) {
showError("Vui lòng nhập văn bản tiếng Việt.");
textInput.focus();
return;
}
// Hide old errors/audio
errorMessage.classList.add('hidden');
audioContainer.classList.add('hidden');
// Setup Loading State
btnLoader.innerHTML = '<i class="fa-solid fa-spinner fa-spin"></i> Processing...';
setLoading(true);
try {
const response = await fetch('/api/synthesize', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ text, voice })
});
const data = await response.json();
if (!response.ok) {
throw new Error(data.error || 'Failed to generate speech.');
}
// Success
const uniqueUrl = data.audio_url + '?t=' + new Date().getTime(); // Prevent caching
audioPlayer.src = uniqueUrl;
downloadBtn.href = uniqueUrl;
downloadBtn.download = `Vietnamese_TTS_${Date.now()}.mp3`;
audioContainer.classList.remove('hidden');
audioPlayer.play().catch(e => console.log("Auto-play blocked", e));
} catch (error) {
showError(error.message);
} finally {
setLoading(false);
}
});
function setLoading(isLoading) {
if (isLoading) {
generateBtn.disabled = true;
btnText.classList.add('hidden');
btnLoader.classList.remove('hidden');
} else {
generateBtn.disabled = false;
btnText.classList.remove('hidden');
btnLoader.classList.add('hidden');
}
}
function showError(message) {
errorText.textContent = message;
errorMessage.classList.remove('hidden');
}
});
|