darkmaria / static /js /main.js
Docfile's picture
Upload main.js
21e127e verified
document.addEventListener('DOMContentLoaded', function() {
// DOM Elements
const ttsForm = document.getElementById('ttsForm');
const podcastForm = document.getElementById('podcastForm');
const textInput = document.getElementById('textInput');
const scenarioInput = document.getElementById('scenarioInput');
const voiceSelect = document.getElementById('voiceSelect');
const generateBtn = document.getElementById('generateBtn');
const generatePodcastBtn = document.getElementById('generatePodcastBtn');
const audioCard = document.getElementById('audioCard');
const audioPlayer = document.getElementById('audioPlayer');
const downloadBtn = document.getElementById('downloadBtn');
const newGenerationBtn = document.getElementById('newGenerationBtn');
const loadingIndicator = document.getElementById('loadingIndicator');
const progressBar = document.getElementById('progressBar');
const progressBarInner = progressBar.querySelector('.progress-bar');
const progressText = document.getElementById('progressText');
const errorAlert = document.getElementById('errorAlert');
const errorMessage = document.getElementById('errorMessage');
// Current audio file information
let currentAudioUrl = null;
let currentAudioFilename = null;
// Populate the example scenario
const exampleScenario = {
"title": "Le management participatif",
"language": "fr-FR",
"characters": [
{
"name": "Manager",
"voice": "Kore",
"text": "Bonjour Sophie. J'aimerais avoir ton avis sur le nouveau planning que nous voulons mettre en place."
},
{
"name": "Sophie",
"voice": "Puck",
"text": "Bonjour ! Merci de me demander. Je pense que ce nouveau planning pourrait être bénéfique, mais nous devons ajuster les horaires de l'équipe technique."
},
{
"name": "Manager",
"voice": "Kore",
"text": "Bonne remarque. Peux-tu organiser une réunion avec eux pour en discuter ?"
},
{
"name": "Sophie",
"voice": "Puck",
"text": "Avec plaisir. Je les réunis demain matin."
}
]
};
scenarioInput.value = JSON.stringify(exampleScenario, null, 2);
// Form submission handler for simple TTS
ttsForm.addEventListener('submit', async function(e) {
e.preventDefault();
const text = textInput.value.trim();
const voice = voiceSelect.value;
// Validation
if (!text) {
showError('Veuillez entrer du texte à convertir en parole.');
return;
}
// Show loading state
setLoadingState(true);
try {
// Call API to generate speech
const response = await fetch('/generate', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
text: text,
voice: voice
})
});
const data = await response.json();
if (!response.ok) {
throw new Error(data.error || 'Échec de génération de la parole');
}
// Process successful response
currentAudioUrl = data.audioUrl;
currentAudioFilename = currentAudioUrl.split('/').pop();
// Setup audio player
audioPlayer.src = currentAudioUrl;
audioPlayer.load();
// Show audio card
audioCard.classList.remove('d-none');
audioCard.classList.add('fade-in');
// Auto-play the audio
try {
await audioPlayer.play();
} catch (playError) {
console.log('Lecture automatique empêchée par le navigateur.', playError);
}
} catch (error) {
showError(error.message || 'Une erreur inattendue est survenue. Veuillez réessayer.');
} finally {
setLoadingState(false);
}
});
// Form submission handler for podcast generation
podcastForm.addEventListener('submit', async function(e) {
e.preventDefault();
let scenarioText = scenarioInput.value.trim();
// Validation
if (!scenarioText) {
showError('Veuillez entrer un scénario JSON.');
return;
}
let scenario;
try {
scenario = JSON.parse(scenarioText);
// Additional validation for required fields
if (!scenario.characters || !Array.isArray(scenario.characters) || scenario.characters.length === 0) {
throw new Error('Le scénario doit contenir un tableau "characters" avec au moins un personnage.');
}
for (const character of scenario.characters) {
if (!character.name || !character.voice || !character.text) {
throw new Error('Chaque personnage doit avoir un nom, une voix et du texte.');
}
}
} catch (error) {
showError(`Erreur dans le format JSON: ${error.message}`);
return;
}
// Show loading state with progress bar
setLoadingState(true, true);
try {
// Call API to start podcast generation in the background
const response = await fetch('/generate-podcast', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(scenario)
});
const data = await response.json();
if (!response.ok) {
throw new Error(data.error || 'Échec de démarrage de la génération du podcast');
}
// Start polling for podcast status
const statusPoller = setInterval(async () => {
try {
const statusResponse = await fetch('/podcast-status');
const statusData = await statusResponse.json();
if (statusData.status === 'in_progress') {
// Update progress bar
updateProgress(
statusData.current,
statusData.total,
statusData.message || 'Génération en cours...'
);
} else if (statusData.status === 'complete') {
// Podcast is complete
clearInterval(statusPoller);
// Process successful response
if (statusData.audioUrl) {
currentAudioUrl = statusData.audioUrl;
currentAudioFilename = currentAudioUrl.split('/').pop();
// Setup audio player
audioPlayer.src = currentAudioUrl;
audioPlayer.load();
// Show audio card
audioCard.classList.remove('d-none');
audioCard.classList.add('fade-in');
// Auto-play the audio
try {
await audioPlayer.play();
} catch (playError) {
console.log('Lecture automatique empêchée par le navigateur.', playError);
}
// Turn off loading state
setLoadingState(false);
} else {
throw new Error('Podcast généré mais URL audio manquante');
}
} else if (statusData.status === 'error' || statusData.message.startsWith('Erreur')) {
// Error occurred
clearInterval(statusPoller);
throw new Error(statusData.message || 'Erreur pendant la génération du podcast');
}
} catch (pollError) {
clearInterval(statusPoller);
throw pollError;
}
}, 1000);
} catch (error) {
showError(error.message || 'Une erreur inattendue est survenue. Veuillez réessayer.');
setLoadingState(false);
}
});
// Download button handler
downloadBtn.addEventListener('click', function() {
if (currentAudioUrl) {
const downloadLink = document.createElement('a');
downloadLink.href = `/download/${currentAudioFilename}`;
downloadLink.download = 'gemini_podcast.wav';
document.body.appendChild(downloadLink);
downloadLink.click();
document.body.removeChild(downloadLink);
}
});
// New generation button handler
newGenerationBtn.addEventListener('click', function() {
// Reset UI for a new generation
audioCard.classList.add('d-none');
errorAlert.classList.add('d-none');
// Check which tab is currently active
const activeTabPane = document.querySelector('.tab-pane.active');
if (activeTabPane.id === 'simple-tts') {
textInput.focus();
} else {
scenarioInput.focus();
}
});
// Helper function to show error messages
function showError(message) {
errorMessage.textContent = message;
errorAlert.classList.remove('d-none');
// Auto-hide error after 8 seconds
setTimeout(() => {
errorAlert.classList.add('d-none');
}, 8000);
}
// Helper function to set loading state
function setLoadingState(isLoading, withProgress = false) {
if (isLoading) {
generateBtn.disabled = true;
generatePodcastBtn.disabled = true;
loadingIndicator.classList.remove('d-none');
errorAlert.classList.add('d-none');
if (withProgress) {
progressBar.classList.remove('d-none');
progressText.classList.remove('d-none');
updateProgress(0, 100, 'Préparation du podcast...');
} else {
progressBar.classList.add('d-none');
progressText.classList.add('d-none');
}
} else {
generateBtn.disabled = false;
generatePodcastBtn.disabled = false;
loadingIndicator.classList.add('d-none');
progressBar.classList.add('d-none');
progressText.classList.add('d-none');
}
}
// Helper function to update progress bar
function updateProgress(current, total, message) {
const percentage = Math.min(100, Math.max(0, Math.round((current / total) * 100)));
progressBarInner.style.width = `${percentage}%`;
progressBarInner.setAttribute('aria-valuenow', percentage);
progressText.textContent = message || `Progression: ${percentage}%`;
}
// Add event listener for when audio playback is complete
audioPlayer.addEventListener('ended', function() {
console.log('Audio playback completed');
});
});