// Configuration globale let apiUrl = "http://localhost:8000"; // État de l'application const appState = { currentTab: "sentiment", apiConnected: false, textgenResults: {} // Pour stocker les textes originaux des résultats textgen }; // Initialisation de l'application document.addEventListener("DOMContentLoaded", function () { initializeApp(); }); function initializeApp() { setupEventListeners(); checkApiStatus(); loadExamplesData(); } function setupEventListeners() { // Navigation entre les onglets document.querySelectorAll(".nav-tab").forEach((tab) => { tab.addEventListener("click", (e) => { const tabName = e.currentTarget.dataset.tab; switchTab(tabName); }); }); // Changement d'URL API document.getElementById("apiUrl").addEventListener("change", function () { apiUrl = this.value; checkApiStatus(); }); // Soumission des formulaires setupFormHandlers(); } function setupFormHandlers() { // Empêcher la soumission par défaut de tous les formulaires document.querySelectorAll("form").forEach((form) => { form.addEventListener("submit", (e) => { e.preventDefault(); }); }); } // Fonctions de gestion du Markdown function renderMarkdown(text) { try { // Configuration de marked pour la sécurité et les fonctionnalités if (typeof marked !== "undefined") { marked.setOptions({ breaks: true, // Convertir les retours à la ligne en
gfm: true, // GitHub Flavored Markdown sanitize: false, // Permet le HTML (attention à la sécurité) smartLists: true, smartypants: true }); return marked.parse(text); } else { console.warn("Marked.js non disponible, affichage du texte brut"); return escapeHtml(text).replace(/\n/g, "
"); } } catch (error) { console.error("Erreur lors du rendu Markdown:", error); return escapeHtml(text).replace(/\n/g, "
"); } } function escapeHtml(text) { const div = document.createElement("div"); div.textContent = text; return div.innerHTML; } function toggleMarkdownView(containerId, text) { const container = document.getElementById(containerId); // Chercher dans le container principal ou dans un élément de génération const textElement = container.querySelector(".text-content") || container.querySelector(".generation-text"); const toggleButton = container.querySelector(".markdown-toggle"); if (!textElement || !toggleButton) { console.warn("Éléments non trouvés pour le toggle Markdown:", containerId); return; } const isMarkdownView = toggleButton.dataset.view === "markdown"; if (isMarkdownView) { // Passer en vue texte brut textElement.innerHTML = escapeHtml(text).replace(/\n/g, "
"); textElement.classList.remove("markdown-content"); textElement.classList.add("raw-text"); toggleButton.innerHTML = "📝 Vue Markdown"; toggleButton.dataset.view = "raw"; } else { // Passer en vue Markdown textElement.innerHTML = renderMarkdown(text); textElement.classList.remove("raw-text"); textElement.classList.add("markdown-content"); toggleButton.innerHTML = "📄 Texte brut"; toggleButton.dataset.view = "markdown"; } } // Nouvelle fonction pour gérer les toggles via data-attributes function handleMarkdownToggle(button) { const resultId = button.dataset.resultId; const isMain = button.dataset.isMain === "true"; const genIndex = button.dataset.genIndex; if (!resultId || !appState.textgenResults[resultId]) { console.warn("Données du résultat textgen non trouvées"); return; } // Récupérer le texte original let originalText; if (isMain) { originalText = appState.textgenResults[resultId].mainText; } else if (genIndex !== undefined) { originalText = appState.textgenResults[resultId].generations[parseInt(genIndex)]; } else { console.warn("Type de texte non identifié"); return; } // Trouver le container et l'élément de texte const container = button.closest(".textgen-output, .generation-item"); if (!container) { console.warn("Container non trouvé"); return; } const textElement = container.querySelector(".text-content, .generation-text"); if (!textElement) { console.warn("Élément de texte non trouvé"); return; } const isMarkdownView = button.dataset.view === "markdown"; if (isMarkdownView) { // Passer en vue texte brut textElement.innerHTML = escapeHtml(originalText).replace(/\n/g, "
"); textElement.classList.remove("markdown-content"); textElement.classList.add("raw-text"); button.innerHTML = "📝 Vue Markdown"; button.dataset.view = "raw"; } else { // Passer en vue Markdown textElement.innerHTML = renderMarkdown(originalText); textElement.classList.remove("raw-text"); textElement.classList.add("markdown-content"); button.innerHTML = "📄 Texte brut"; button.dataset.view = "markdown"; } } function decodeHtml(html) { const txt = document.createElement("textarea"); txt.innerHTML = html; return txt.value; } // Navigation function switchTab(tabName) { // Mise à jour de l'état appState.currentTab = tabName; // Mise à jour des onglets document.querySelectorAll(".nav-tab").forEach((tab) => { tab.classList.remove("active"); }); document.querySelector(`[data-tab="${tabName}"]`).classList.add("active"); // Mise à jour du contenu document.querySelectorAll(".tab-content").forEach((content) => { content.classList.remove("active"); }); document.getElementById(tabName).classList.add("active"); } // Vérification du statut de l'API async function checkApiStatus() { const statusElement = document.getElementById("apiStatus"); const indicator = statusElement.querySelector(".status-indicator"); const statusText = statusElement.querySelector("span"); const testButton = document.querySelector("button[onclick='checkApiStatus()']"); // Feedback visuel pendant le test if (testButton) { testButton.disabled = true; testButton.innerHTML = 'Test en cours...'; testButton.classList.add("loading"); } // Indicateur de chargement indicator.className = "status-indicator loading"; statusText.textContent = "Test de connexion..."; try { const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), 5000); const response = await fetch(`${apiUrl}/health`, { method: "GET", signal: controller.signal }); clearTimeout(timeoutId); if (response.ok) { const healthData = await response.json(); appState.apiConnected = true; indicator.className = "status-indicator online"; statusText.textContent = "API Connectée"; // Notification de succès showNotification("✅ Connexion API établie avec succès!", "success"); // Afficher les détails de l'API showApiDetails(healthData); } else { throw new Error(`Erreur HTTP ${response.status}`); } } catch (error) { appState.apiConnected = false; indicator.className = "status-indicator offline"; statusText.textContent = "API Déconnectée"; let errorMessage = "❌ Impossible de se connecter à l'API"; if (error.name === "AbortError") { errorMessage += " (Timeout)"; } else if (error.message.includes("fetch")) { errorMessage += " (Serveur inaccessible)"; } else { errorMessage += ` (${error.message})`; } showNotification(errorMessage, "error"); console.warn("Erreur de connexion API:", error.message); } finally { // Restaurer le bouton if (testButton) { testButton.disabled = false; testButton.innerHTML = '🔄Tester la connexion'; testButton.classList.remove("loading"); } } } // Système de notifications function showNotification(message, type = "info", duration = 5000) { // Créer le conteneur de notifications s'il n'existe pas let notificationContainer = document.getElementById("notification-container"); if (!notificationContainer) { notificationContainer = document.createElement("div"); notificationContainer.id = "notification-container"; notificationContainer.className = "notification-container"; document.body.appendChild(notificationContainer); } // Créer la notification const notification = document.createElement("div"); notification.className = `notification notification-${type}`; notification.innerHTML = `
${message}
`; // Ajouter l'animation d'entrée notification.style.transform = "translateX(100%)"; notification.style.opacity = "0"; notificationContainer.appendChild(notification); // Animation d'entrée setTimeout(() => { notification.style.transform = "translateX(0)"; notification.style.opacity = "1"; }, 10); // Suppression automatique if (duration > 0) { setTimeout(() => { if (notification.parentElement) { notification.style.transform = "translateX(100%)"; notification.style.opacity = "0"; setTimeout(() => notification.remove(), 300); } }, duration); } } // Affichage des détails de l'API function showApiDetails(healthData) { const existingDetails = document.getElementById("api-details"); if (existingDetails) { existingDetails.remove(); } const configSection = document.querySelector(".config-section .config-card"); const detailsDiv = document.createElement("div"); detailsDiv.id = "api-details"; detailsDiv.className = "api-details"; detailsDiv.innerHTML = `

📊 Détails de l'API

Statut: ✅ ${healthData.status || "healthy"}
Pipelines chargés: ${healthData.pipelines_loaded || 0}
Pipelines disponibles: ${(healthData.available_pipelines || []).join(", ") || "Aucun"}
`; configSection.appendChild(detailsDiv); } async function makeApiRequest(endpoint, data) { if (!appState.apiConnected) { throw new Error("API non connectée. Vérifiez la configuration."); } try { const response = await fetch(`${apiUrl}${endpoint}`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(data) }); const result = await response.json(); if (!response.ok) { throw new Error(result.detail || `Erreur ${response.status}`); } return result; } catch (error) { if (error.name === "TypeError" && error.message.includes("fetch")) { throw new Error("Impossible de contacter l'API. Vérifiez que le serveur est démarré."); } throw error; } } // Gestion de l'affichage des résultats améliorée function showLoading(containerId) { const container = document.getElementById(containerId); container.innerHTML = `

🔄 Traitement en cours...

Analyse de votre texte par l'IA

`; container.classList.add("show"); } function showResult(containerId, data, isError = false) { const container = document.getElementById(containerId); const headerClass = isError ? "error" : "success"; const icon = isError ? "❌" : "✅"; const title = isError ? "Erreur" : "Résultat"; let formattedContent; if (isError) { formattedContent = formatErrorResult(data); } else { formattedContent = formatResult(data, containerId); } // Ajouter un timestamp const timestamp = new Date().toLocaleTimeString("fr-FR"); container.innerHTML = `
${icon}
${title} ${timestamp}
${formattedContent}
`; container.classList.add("show"); // Ajouter les event listeners pour les boutons markdown-toggle setupMarkdownToggleListeners(container); // Animation d'entrée const resultCard = container.querySelector(".result-card"); resultCard.style.transform = "translateY(20px)"; resultCard.style.opacity = "0"; setTimeout(() => { resultCard.style.transform = "translateY(0)"; resultCard.style.opacity = "1"; }, 10); } // Fonction pour configurer les event listeners des boutons markdown function setupMarkdownToggleListeners(container) { // Event listeners pour les boutons markdown toggle const toggleButtons = container.querySelectorAll(".markdown-toggle"); toggleButtons.forEach((button) => { button.removeEventListener("click", handleMarkdownToggleClick); button.addEventListener("click", handleMarkdownToggleClick); }); // Event listeners pour les boutons de copie const copyButtons = container.querySelectorAll(".copy-text-btn"); copyButtons.forEach((button) => { button.removeEventListener("click", handleCopyTextClick); button.addEventListener("click", handleCopyTextClick); }); } // Event handler pour les clics sur les boutons markdown toggle function handleMarkdownToggleClick(event) { event.preventDefault(); handleMarkdownToggle(event.target); } // Event handler pour les clics sur les boutons de copie function handleCopyTextClick(event) { event.preventDefault(); const textToCopy = decodeHtml(event.target.dataset.text); copyToClipboard(textToCopy); } function formatErrorResult(error) { let errorMessage = "Une erreur inattendue s'est produite"; let suggestions = []; if (typeof error === "object" && error.error) { errorMessage = error.error; // Suggestions basées sur le type d'erreur if (errorMessage.includes("API non connectée")) { suggestions.push("Vérifiez que le serveur API est démarré"); suggestions.push("Testez la connexion avec le bouton 'Tester la connexion'"); } else if (errorMessage.includes("requis")) { suggestions.push("Assurez-vous que tous les champs obligatoires sont remplis"); } else if (errorMessage.includes("MASK")) { suggestions.push("Utilisez [MASK] dans votre texte pour le fill-mask"); } else if (errorMessage.includes("CUDA out of memory") || errorMessage.includes("mémoire")) { suggestions.push("🔧 Essayez un modèle plus petit (GPT-2 au lieu de GPT-2 Medium)"); suggestions.push("📉 Réduisez le nombre de tokens à générer"); suggestions.push("🔢 Réduisez le nombre de séquences à générer"); suggestions.push("💻 Le modèle utilisera automatiquement le CPU si le GPU manque de mémoire"); } else if (errorMessage.includes("model") || errorMessage.includes("modèle")) { suggestions.push("Essayez avec le modèle par défaut"); suggestions.push("Vérifiez que le nom du modèle est correct"); } } let suggestionsHtml = ""; if (suggestions.length > 0) { suggestionsHtml = `

💡 Suggestions:

`; } return `
Message d'erreur:

${errorMessage}

${suggestionsHtml}
`; } function formatResult(data, containerId) { const type = containerId.replace("Result", ""); switch (type) { case "sentiment": return formatSentimentResult(data); case "ner": return formatNerResult(data); case "qa": return formatQaResult(data); case "fillmask": return formatFillmaskResult(data); case "moderation": return formatModerationResult(data); case "textgen": return formatTextgenResult(data); case "batch": return formatBatchResult(data); default: return `
${JSON.stringify(data, null, 2)}
`; } } function formatSentimentResult(data) { const sentiment = data.sentiment || data.label; const confidence = data.confidence || data.score; const badgeClass = sentiment?.toLowerCase() === "positive" ? "positive" : sentiment?.toLowerCase() === "negative" ? "negative" : "neutral"; // Calcul de la barre de progression pour la confiance const confidencePercent = confidence ? (confidence * 100).toFixed(1) : 0; const progressColor = confidencePercent > 80 ? "var(--success-500)" : confidencePercent > 60 ? "var(--warning-500)" : "var(--error-500)"; return `
Sentiment détecté: ${sentiment || "Non déterminé"}
Niveau de confiance: ${confidencePercent}%
${getSentimentInterpretation(sentiment, confidence)}
🔍 Détails techniques
${JSON.stringify(data, null, 2)}
`; } function formatNerResult(data) { let entitiesHtml = ""; let entitiesStats = {}; if (data.entities && data.entities.length > 0) { // Compter les entités par type data.entities.forEach((entity) => { const label = entity.label; entitiesStats[label] = (entitiesStats[label] || 0) + 1; }); entitiesHtml = data.entities .map((entity, index) => { const label = entity.label?.toLowerCase() || "misc"; const confidence = entity.confidence ? (entity.confidence * 100).toFixed(1) : null; return `
${entity.text} ${entity.label} ${confidence ? `${confidence}%` : ""}
`; }) .join(""); } else { entitiesHtml = `
🔍 Aucune entité nommée détectée dans ce texte
`; } // Statistiques des entités const statsHtml = Object.keys(entitiesStats).length > 0 ? `

📊 Statistiques des entités:

${Object.entries(entitiesStats) .map( ([type, count]) => `
${type} ${count}
` ) .join("")}
` : ""; return `

🏷️ Entités détectées:

${entitiesHtml}
${statsHtml}
🔍 Détails techniques
${JSON.stringify(data, null, 2)}
`; } function formatQaResult(data) { const confidence = data.confidence ? (data.confidence * 100).toFixed(1) : null; const progressColor = confidence > 80 ? "var(--success-500)" : confidence > 60 ? "var(--warning-500)" : "var(--error-500)"; return `

❓ Question:

${data.question}

💡 Réponse:

${data.answer || "Aucune réponse trouvée dans le contexte fourni"}
${ confidence ? `
Fiabilité de la réponse: ${confidence}%
` : "" }
🔍 Détails techniques
${JSON.stringify(data, null, 2)}
`; } function formatFillmaskResult(data) { let predictionsHtml = ""; if (data.predictions && data.predictions.length > 0) { predictionsHtml = data.predictions .map((pred, index) => { const score = pred.score ? (pred.score * 100).toFixed(1) : null; const rankClass = index === 0 ? "rank-first" : index === 1 ? "rank-second" : "rank-other"; return `
#${index + 1}
${pred.token || pred.token_str} ${score ? `${score}%` : ""}
${ score ? `
` : "" }
`; }) .join(""); } else { predictionsHtml = `
🔍 Aucune prédiction disponible
`; } return `

🎭 Mots prédits pour remplacer [MASK]:

${predictionsHtml}
🔍 Détails techniques
${JSON.stringify(data, null, 2)}
`; } function formatModerationResult(data) { const flagged = data.flagged; const badgeClass = flagged ? "negative" : "positive"; const status = flagged ? "CONTENU SIGNALÉ" : "CONTENU APPROPRIÉ"; const icon = flagged ? "⚠️" : "✅"; let categoriesHtml = ""; if (data.categories) { const categories = Object.entries(data.categories); if (categories.length > 0) { categoriesHtml = `

📋 Détails de l'analyse:

${categories .map(([key, value]) => { let displayKey = key; let displayValue = value; if (key === "toxic_score") { displayKey = "Score de toxicité"; displayValue = typeof value === "number" ? `${(value * 100).toFixed(1)}%` : value; } else if (key === "is_modified") { displayKey = "Contenu modifié"; displayValue = value ? "Oui" : "Non"; } else if (key === "words_replaced") { displayKey = "Mots remplacés"; } else if (key === "restored_text") { displayKey = "Texte restauré"; } return `
${displayKey}: ${displayValue}
`; }) .join("")}
`; } } return `
${icon} ${status}
${categoriesHtml}
🔍 Détails techniques
${JSON.stringify(data, null, 2)}
`; } function formatTextgenResult(data) { const generatedText = data.generated_text || "Aucun texte généré"; const prompt = data.prompt || ""; const systemPrompt = data.system_prompt || ""; const parameters = data.parameters || {}; const generations = data.generations || []; // Créer un ID unique pour ce résultat const resultId = "textgen_result_" + Date.now() + "_" + Math.random().toString(36).substr(2, 9); // Stocker les données dans l'état global appState.textgenResults[resultId] = { mainText: generatedText, generations: generations.map((gen) => gen.text || gen.continuation || "") }; // Formatage du system prompt s'il existe const systemPromptHtml = systemPrompt ? `

🤖 Prompt System:

${systemPrompt}
` : ""; // Formatage des paramètres utilisés const parametersHtml = Object.keys(parameters).length > 0 ? `

⚙️ Paramètres utilisés:

Tokens max: ${parameters.max_new_tokens || "N/A"}
Séquences: ${parameters.num_sequences || "N/A"}
Température: ${parameters.temperature || "N/A"}
Échantillonnage: ${parameters.do_sample ? "✅" : "❌"}
` : ""; // Formatage des générations multiples const generationsHtml = generations.length > 1 ? `

🎯 Générations alternatives (${generations.length}):

${generations .map((gen, index) => { const genText = gen.text || gen.continuation || "Aucun texte"; const genId = `${resultId}_generation_${index}`; return `
Génération ${index + 1}
${renderMarkdown(genText)}
`; }) .join("")}
` : ""; return `
${systemPromptHtml}

📝 Prompt initial:

${prompt}
${parametersHtml}

✨ Texte généré:

${renderMarkdown(generatedText)}
${generationsHtml}
🔍 Détails techniques
${JSON.stringify(data, null, 2)}
`; } function formatBatchResult(data) { if (!data.results || data.results.length === 0) { return "Aucun résultat"; } const resultsHtml = data.results .map((result, index) => { return `
Résultat ${index + 1}
${JSON.stringify(result, null, 2)}
`; }) .join(""); return `
Résumé: ${data.processed_count} traités, ${data.failed_count} échecs
${resultsHtml}
`; } // Fonctions de traitement pour chaque endpoint async function analyzeSentiment(event) { event.preventDefault(); showLoading("sentimentResult"); const text = document.getElementById("sentimentText").value.trim(); const model = document.getElementById("sentimentModel").value; if (!text) { showResult("sentimentResult", { error: "Le texte est requis" }, true); return; } try { const data = { text }; if (model) data.model_name = model; const result = await makeApiRequest("/sentiment", data); showResult("sentimentResult", result); } catch (error) { showResult("sentimentResult", { error: error.message }, true); } } async function analyzeNER(event) { event.preventDefault(); showLoading("nerResult"); const text = document.getElementById("nerText").value.trim(); const model = document.getElementById("nerModel").value; if (!text) { showResult("nerResult", { error: "Le texte est requis" }, true); return; } try { const data = { text }; if (model) data.model_name = model; const result = await makeApiRequest("/ner", data); showResult("nerResult", result); } catch (error) { showResult("nerResult", { error: error.message }, true); } } async function answerQuestion(event) { event.preventDefault(); showLoading("qaResult"); const question = document.getElementById("qaQuestion").value.trim(); const context = document.getElementById("qaContext").value.trim(); const model = document.getElementById("qaModel").value; if (!question || !context) { showResult("qaResult", { error: "La question et le contexte sont requis" }, true); return; } try { const data = { question, context }; if (model) data.model_name = model; const result = await makeApiRequest("/qa", data); showResult("qaResult", result); } catch (error) { showResult("qaResult", { error: error.message }, true); } } async function fillMask(event) { event.preventDefault(); showLoading("fillmaskResult"); const text = document.getElementById("fillmaskText").value.trim(); const model = document.getElementById("fillmaskModel").value; if (!text) { showResult("fillmaskResult", { error: "Le texte est requis" }, true); return; } if (!text.includes("[MASK]")) { showResult("fillmaskResult", { error: "Le texte doit contenir [MASK]" }, true); return; } try { const data = { text }; if (model) data.model_name = model; const result = await makeApiRequest("/fillmask", data); showResult("fillmaskResult", result); } catch (error) { showResult("fillmaskResult", { error: error.message }, true); } } async function moderateContent(event) { event.preventDefault(); showLoading("moderationResult"); const text = document.getElementById("moderationText").value.trim(); const model = document.getElementById("moderationModel").value; if (!text) { showResult("moderationResult", { error: "Le texte est requis" }, true); return; } try { const data = { text }; if (model) data.model_name = model; const result = await makeApiRequest("/moderation", data); showResult("moderationResult", result); } catch (error) { showResult("moderationResult", { error: error.message }, true); } } async function generateText(event) { event.preventDefault(); showLoading("textgenResult"); const text = document.getElementById("textgenPrompt").value.trim(); const systemPrompt = document.getElementById("textgenSystemPrompt").value.trim(); const model = document.getElementById("textgenModel").value; const maxNewTokens = parseInt(document.getElementById("maxNewTokens").value) || 500; const numReturnSequences = parseInt(document.getElementById("numReturnSequences").value) || 1; const temperature = parseFloat(document.getElementById("temperature").value) || 1.0; const doSample = document.getElementById("doSample").checked; if (!text) { showResult("textgenResult", { error: "Le prompt est requis" }, true); return; } // Validate parameters if (maxNewTokens < 1 || maxNewTokens > 2048) { showResult("textgenResult", { error: "Le nombre de tokens doit être entre 1 et 2048" }, true); return; } if (numReturnSequences < 1 || numReturnSequences > 5) { showResult("textgenResult", { error: "Le nombre de séquences doit être entre 1 et 5" }, true); return; } if (temperature < 0.1 || temperature > 2.0) { showResult("textgenResult", { error: "La température doit être entre 0.1 et 2.0" }, true); return; } try { const data = { text, max_new_tokens: maxNewTokens, num_return_sequences: numReturnSequences, temperature: temperature, do_sample: doSample }; // Add system prompt if provided if (systemPrompt) { data.system_prompt = systemPrompt; } if (model) { data.model_name = model; } const result = await makeApiRequest("/textgen", data); showResult("textgenResult", result); } catch (error) { showResult("textgenResult", { error: error.message }, true); } } async function processBatch() { showLoading("batchResult"); const type = document.getElementById("batchType").value; const textsInput = document.getElementById("batchTexts").value.trim(); if (!textsInput) { showResult("batchResult", { error: "Les textes sont requis" }, true); return; } const texts = textsInput .split("\n") .filter((line) => line.trim()) .map((line) => line.trim()); if (texts.length === 0) { showResult("batchResult", { error: "Aucun texte valide fourni" }, true); return; } try { const data = { texts }; const result = await makeApiRequest(`/${type}/batch`, data); showResult("batchResult", result); } catch (error) { showResult("batchResult", { error: error.message }, true); } } // Exemples prédéfinis (en anglais pour optimiser la compatibilité avec les modèles) const examples = { sentiment: "I love this project! It's really well designed and useful for testing NLP APIs.", ner: "Apple Inc. is an American multinational technology company headquartered in Cupertino, California. Tim Cook is the current CEO of Apple.", qa: { question: "What is the capital of France?", context: "France is a country located in Western Europe. Paris is the capital and largest city of France. The city is famous for the Eiffel Tower and the Louvre Museum." }, fillmask: "The capital of France is [MASK].", moderation: "This project is fantastic! Thank you for this excellent work.", textgen: { prompt: "Generate 10 ideas of what to build with a rapsberry pi", systemPrompt: "You are a helpful AI assistant. Format your responses using complex Markdown (Title, lists etc..). Be clear and structured." }, batch: `I love this product! This is really terrible. Not bad at all. Excellent work! I hate all of this.` }; function loadExample(type) { const example = examples[type]; if (!example) return; switch (type) { case "sentiment": document.getElementById("sentimentText").value = example; break; case "ner": document.getElementById("nerText").value = example; break; case "qa": document.getElementById("qaQuestion").value = example.question; document.getElementById("qaContext").value = example.context; break; case "fillmask": document.getElementById("fillmaskText").value = example; break; case "moderation": document.getElementById("moderationText").value = example; break; case "textgen": if (typeof example === "object") { document.getElementById("textgenPrompt").value = example.prompt; document.getElementById("textgenSystemPrompt").value = example.systemPrompt; } else { document.getElementById("textgenPrompt").value = example; } break; case "batch": document.getElementById("batchTexts").value = example; break; } } function loadExamplesData() { // Cette fonction peut être étendue pour charger des exemples depuis une source externe console.log("Exemples chargés"); } // Fonctions utilitaires pour l'UX function getSentimentInterpretation(sentiment, confidence) { const confidenceLevel = confidence > 0.8 ? "très élevée" : confidence > 0.6 ? "élevée" : confidence > 0.4 ? "modérée" : "faible"; let interpretation = ""; if (sentiment?.toLowerCase() === "positive") { interpretation = `😊 Le texte exprime un sentiment positif avec une confiance ${confidenceLevel}.`; } else if (sentiment?.toLowerCase() === "negative") { interpretation = `😔 Le texte exprime un sentiment négatif avec une confiance ${confidenceLevel}.`; } else { interpretation = `😐 Le sentiment du texte est neutre avec une confiance ${confidenceLevel}.`; } return `
${interpretation}
`; } function copyToClipboard(text) { navigator.clipboard .writeText(text) .then(() => { showNotification("📋 Texte copié dans le presse-papiers!", "success", 2000); }) .catch(() => { showNotification("❌ Impossible de copier le texte", "error", 2000); }); } function copyResultToClipboard(containerId) { const container = document.getElementById(containerId); const resultData = container.querySelector(".result-json"); if (resultData) { copyToClipboard(resultData.textContent); } } function toggleResultDetails(containerId) { const container = document.getElementById(containerId); const details = container.querySelector(".result-details"); if (details) { details.open = !details.open; } } function regenerateText() { const currentPrompt = document.getElementById("textgenPrompt").value; if (currentPrompt) { const form = document.querySelector("#textgen form"); const event = new Event("submit"); generateText(event); } } // Amélioration des fonctions de traitement avec feedback async function analyzeSentiment(event) { event.preventDefault(); showLoading("sentimentResult"); const text = document.getElementById("sentimentText").value.trim(); const model = document.getElementById("sentimentModel").value; if (!text) { showResult("sentimentResult", { error: "Le texte est requis pour l'analyse de sentiment" }, true); return; } try { showNotification("🔄 Analyse de sentiment en cours...", "info", 2000); const data = { text }; if (model) data.model_name = model; const result = await makeApiRequest("/sentiment", data); showResult("sentimentResult", result); showNotification("✅ Analyse de sentiment terminée!", "success", 3000); } catch (error) { showResult("sentimentResult", { error: error.message }, true); showNotification("❌ Erreur lors de l'analyse de sentiment", "error", 4000); } } async function analyzeNER(event) { event.preventDefault(); showLoading("nerResult"); const text = document.getElementById("nerText").value.trim(); const model = document.getElementById("nerModel").value; if (!text) { showResult("nerResult", { error: "Le texte est requis pour la reconnaissance d'entités" }, true); return; } try { showNotification("🔄 Reconnaissance d'entités en cours...", "info", 2000); const data = { text }; if (model) data.model_name = model; const result = await makeApiRequest("/ner", data); showResult("nerResult", result); const entityCount = result.entities ? result.entities.length : 0; showNotification(`✅ ${entityCount} entité(s) détectée(s)!`, "success", 3000); } catch (error) { showResult("nerResult", { error: error.message }, true); showNotification("❌ Erreur lors de la reconnaissance d'entités", "error", 4000); } } async function answerQuestion(event) { event.preventDefault(); showLoading("qaResult"); const question = document.getElementById("qaQuestion").value.trim(); const context = document.getElementById("qaContext").value.trim(); const model = document.getElementById("qaModel").value; if (!question || !context) { showResult("qaResult", { error: "La question et le contexte sont requis" }, true); return; } try { showNotification("🔄 Recherche de réponse en cours...", "info", 2000); const data = { question, context }; if (model) data.model_name = model; const result = await makeApiRequest("/qa", data); showResult("qaResult", result); showNotification("✅ Réponse trouvée!", "success", 3000); } catch (error) { showResult("qaResult", { error: error.message }, true); showNotification("❌ Erreur lors de la recherche de réponse", "error", 4000); } }