From b5e041a676d907b857d03dfbebc730b24305d979 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pr=C3=A9nom=20Nom?= <adresse@mail.com>
Date: Mon, 24 Feb 2025 18:04:52 +0100
Subject: [PATCH] =?UTF-8?q?am=C3=A9lioration=20r=C3=A9duire=20requ=C3=AAte?=
 =?UTF-8?q?=20ajout=20auto?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 src/workers/pyodide_worker.js | 251 +++++++++++++++++++---------------
 1 file changed, 138 insertions(+), 113 deletions(-)

diff --git a/src/workers/pyodide_worker.js b/src/workers/pyodide_worker.js
index 2aa8e8c..be7dd49 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
-- 
GitLab