diff --git a/src/workers/pyodide_worker.js b/src/workers/pyodide_worker.js index 2aa8e8cd19776941ac8db9e328092864d10c5d25..be7dd4918bed5d8620b961f92f5c0232c8579475 100644 --- a/src/workers/pyodide_worker.js +++ b/src/workers/pyodide_worker.js @@ -202,123 +202,122 @@ self.onmessage = async (event) => { // --- Vérification du seuil et notification --- -let pendingWords = {}; // Stocker temporairement les mots en attente d'ajout +let pendingWords = {}; // Stocke temporairement les mots en attente d'ajout +let attemptedWords = {}; // Stocke les mots déjà tentés (ajout réussi ou non) let addWordTimeout = null; // Timer pour regrouper les ajouts async function checkThreshold(lang) { await stoplistsReady; // Attendre que les stoplists soient chargées - + if (!autoAddEnabled || !isAuthenticated) { log("[Worker] Auto-Add désactivé ou utilisateur non connecté."); - } else if (!trackedLanguages.includes(lang)) { + return; + } + if (!trackedLanguages.includes(lang)) { log(`[Worker] La langue '${lang}' n'est pas suivie.`); - } else { - log(`[Worker] Vérification des fréquences pour la langue '${lang}'...`); - - const stoplist = stoplistsByLang[lang] || new Set(); - const shouldFilterStopwords = stoplist.size > 0 && !includeStopwords; - - log(`[Worker] Stoplist pour '${lang}' : ${shouldFilterStopwords ? "Appliquée" : "Non appliquée"}`); - - const wordsFrequencies = storedFrequencies[lang] || {}; - const notifiedSet = new Set(notifiedWords[lang] || []); - - // Filtrer les mots qui dépassent le seuil - const exceededWords = Object.entries(wordsFrequencies) - .filter(([word, count]) => count >= userThreshold && !notifiedSet.has(word)) - .map(([word]) => word); - - if (exceededWords.length === 0) { - log(`[Worker] Aucun mot dépassant le seuil pour '${lang}'.`); - } else { - // Filtrer selon la stoplist si nécessaire - const finalWords = shouldFilterStopwords - ? exceededWords.filter(word => { - const isInStoplist = stoplist.has(word); - if (isInStoplist) log(`[Worker] Mot "${word}" exclu (stoplist)`); - return !isInStoplist; - }) - : exceededWords; - - if (finalWords.length === 0) { - log(`[Worker] Tous les mots dépassant le seuil pour '${lang}' sont dans la stoplist.`); - } else { - // Ajouter les mots aux sets et logs - notifiedWords[lang] = notifiedSet; - finalWords.forEach(word => notifiedSet.add(word)); - - log("Mots dépassant le seuil :", finalWords); - self.postMessage({ type: "threshold-exceeded", wordsAboveThreshold: { [lang]: finalWords } }); - - // Ajout aux mots en attente pour un envoi groupé - if (!pendingWords[lang]) pendingWords[lang] = []; - pendingWords[lang].push(...finalWords); - - // Regrouper les ajouts en une seule tâche différée - if (!addWordTimeout) { - addWordTimeout = setTimeout(processPendingWords, 3000); - } - } - } + return; } -} -/** - * Traite les ajouts groupés - */ -async function processPendingWords() { - log("Traitement des mots à ajouter en lot..."); + log(`[Worker] Vérification des fréquences pour la langue '${lang}'...`); + const stoplist = stoplistsByLang[lang] || new Set(); + const shouldFilterStopwords = stoplist.size > 0 && !includeStopwords; - for (const lang in pendingWords) { - const words = pendingWords[lang]; - for (const word of words) { - await addWordToLexicon(lang, word); + log(`[Worker] Stoplist pour '${lang}' : ${shouldFilterStopwords ? "Appliquée" : "Non appliquée"}`); + + const wordsFrequencies = storedFrequencies[lang] || {}; + const notifiedSet = new Set(notifiedWords[lang] || []); + + // Filtrer les mots qui dépassent le seuil + const exceededWords = Object.entries(wordsFrequencies) + .filter(([word, count]) => count >= userThreshold && !notifiedSet.has(word)) + .map(([word]) => word); + + if (exceededWords.length === 0) { + log(`[Worker] Aucun mot dépassant le seuil pour '${lang}'.`); + return; + } + + // Exclure les stopwords et les mots déjà tentés + const finalWords = exceededWords.filter(word => { + if (shouldFilterStopwords && stoplist.has(word)) { + log(`[Worker] Mot "${word}" exclu (stoplist)`); + return false; } + if (attemptedWords[lang]?.has(word)) { + log(`[Worker] Mot "${word}" déjà tenté, on l'ignore.`); + return false; + } + return true; + }); + + if (finalWords.length === 0) { + log(`[Worker] Aucun mot à ajouter après filtrage.`); + return; } - // Réinitialiser la file d'attente et le timeout - pendingWords = {}; - addWordTimeout = null; + // Ajouter à notifiedWords pour éviter de les re-traiter immédiatement + notifiedWords[lang] = notifiedWords[lang] || new Set(); + finalWords.forEach(word => notifiedWords[lang].add(word)); + + log("Mots dépassant le seuil et à ajouter :", finalWords); + self.postMessage({ type: "threshold-exceeded", wordsAboveThreshold: { [lang]: finalWords } }); + + // Ajout aux mots en attente pour un envoi groupé + pendingWords[lang] = pendingWords[lang] || []; + pendingWords[lang].push(...finalWords); + + // Initialiser attemptedWords si nécessaire + attemptedWords[lang] = attemptedWords[lang] || new Set(); + + // Regrouper les ajouts en une seule tâche différée + if (!addWordTimeout) { + addWordTimeout = setTimeout(() => { + addWordTimeout = null; + processPendingWords(); + }, 3000); + } } /** - * Ajoute un mot au lexique - * @param {string} lang - La langue du mot. - * @param {string} word - Le mot à ajouter. + * Traite les ajouts groupés */ -async function addWordToLexicon(lang, word) { +async function processPendingWords() { + log("Traitement des mots en attente d'ajout..."); + if (!authToken) { - log("Impossible d'ajouter le mot : Aucun token d’authentification."); + log("Impossible d'ajouter les mots : Aucun token d'authentification."); return; } - log(`Tentative d'ajout du mot '${word}' pour la langue '${lang}'`); - // Trouver les lexiques correspondant à la langue détectée - const targetLexicons = userLexicons - .filter(lexicon => lexicon.language === lang && lexicon.category === "User") - .map(lexicon => lexicon.id); + for (const lang in pendingWords) { + const words = [...new Set(pendingWords[lang])]; + if (words.length === 0) continue; + + log(`Envoi des mots '${words.join(", ")}' pour la langue '${lang}'`); - if (targetLexicons.length === 0) { - log(`Aucun lexique trouvé pour la langue '${lang}'. Impossible d'ajouter '${word}'.`); - return; - } + // Récupérer les lexiques pour la langue + const targetLexicons = userLexicons + .filter(lexicon => lexicon.language === lang && lexicon.category === "User") + .map(lexicon => lexicon.id); - try { - log(`Envoi de '${word}' aux lexiques ${targetLexicons}...`); - await AddWord(authToken, word, targetLexicons); - // Notifier le background de l'ajout réussi - self.postMessage({ type: "word-added", word, language: lang, lexicons: targetLexicons }); - } catch (error) { - console.error(`Erreur lors de l'ajout du mot '${word}':`, error); + if (targetLexicons.length === 0) { + log(`⚠Aucun lexique trouvé pour la langue '${lang}', envoi annulé.`); + continue; + } + + await autoAddWord(lang, authToken, words, targetLexicons); } } -async function AddWord(authToken, selectedWord, lexiconIds, force = false) { +/** + * Envoi des mots à l'API en évitant les doublons + */ +async function autoAddWord(lang, authToken, wordsArray, lexiconIds, force = false) { if (!authToken) { console.error("Aucun token d’authentification fourni."); return; } - if (!selectedWord) { + if (!Array.isArray(wordsArray) || wordsArray.length === 0) { console.error("Aucun mot spécifié pour l’ajout."); return; } @@ -327,32 +326,58 @@ async function AddWord(authToken, selectedWord, lexiconIds, force = false) { return; } - const url = "https://babalex.lezinter.net/api/entry/create"; - const body = { - graphy: selectedWord, - force, - target_lex: lexiconIds - }; - - log("Envoi de la requête API AddWord :", body); - - try { - const response = await fetch(url, { - method: "POST", - headers: { - "Content-Type": "application/json", - "Authorization": `Bearer ${authToken}` - }, - body: JSON.stringify(body) - }); - log(`Mot '${selectedWord}' ajouté avec succès aux lexiques ${lexiconIds}`); - - if (!response.ok) { - throw new Error(`Erreur API (${response.status}): ${response.statusText}`); + const url = "https://babalex.lezinter.net/api/entry/create"; + + for (const word of wordsArray) { + // 🔹 Vérifier et initialiser attemptedWords[lang] + if (!attemptedWords[lang]) attemptedWords[lang] = new Set(); + + // 🔹 Si le mot a déjà été tenté, on ne le retente pas + if (attemptedWords[lang].has(word)) { + log(`[Worker] Mot '${word}' déjà tenté, on l'ignore.`); + continue; + } + + // 🔹 Ajouter immédiatement le mot à attemptedWords + attemptedWords[lang].add(word); + log(`[Worker] Liste des mots tentés pour '${lang}':`, Array.from(attemptedWords[lang])); + + const body = { + graphy: word, + force, + target_lex: lexiconIds + }; + + log("🚀 Envoi de la requête API autoAddWord :", body); + + try { + await new Promise(resolve => setTimeout(resolve, 3000)); // espacer les requêtes + const response = await fetch(url, { + method: "POST", + headers: { + "Content-Type": "application/json", + "Authorization": `Bearer ${authToken}` + }, + body: JSON.stringify(body) + }); + + if (!response.ok) { + throw new Error(`Erreur API (${response.status}): ${response.statusText}`); + } + + log(`Mot '${word}' ajouté avec succès aux lexiques ${lexiconIds}`); + attemptedWords[word] = "success"; // Marquer comme ajouté avec succès + + } catch (error) { + console.error(`Erreur lors de l'ajout du mot '${word}':`, error); + attemptedWords[word] = "failed"; // Marquer comme échec pour éviter la répétition + log(attemptedWords) + // Réessayer après 24H + setTimeout(() => { + delete attemptedWords[word]; // On retente après 24h + }, 24 * 60 * 60 * 1000); + } - - return await response.json(); - } catch (error) { - console.error(`Erreur lors de l'ajout du mot '${selectedWord}':`, error); } } + \ No newline at end of file