Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -546,69 +546,20 @@
"name": "stdout",
"output_type": "stream",
"text": [
"Detecteur : 38 sophismes couverts depuis la taxonomie.\n",
"Exemples : ['La tête dans le sable', 'Répulsif anti-girafe', 'Trouver des excuses', 'Inertie mentale', 'Inventer des salades']\n",
"--- Texte synthetique analyse ---\n",
"Tous les politiciens mentent, donc celui-ci ment aussi. D apres le professeur X, c est evident. Vous etes incompetent pour dire le contraire.\n",
"Vous etes incompetent pour juger, et de toute facon je rejette toute information qui pourrait contredire ma position.\n",
"\n",
"--- Sophismes detectes (3) ---\n",
" - Generalisation abusive (famille=Insuffisance, sous_famille=Generalisation abusive) trigger='tous les'\n",
" - Ad hominem (famille=Obstruction, sous_famille=Ad hominem) trigger='vous etes'\n",
" - Appel a l autorite (famille=Influence, sous_famille=Appel a l autorite) trigger='professeur'\n"
" - La tête dans le sable (famille=Insuffisance, sous_famille=Argument bâclé) trigger='information'\n",
" - Rétropédalage (famille=Tricherie, sous_famille=Changement de cap) trigger='position'\n",
" - Biais culturel (famille=Tricherie, sous_famille=Pensée biaisée) trigger='position'\n"
]
}
],
"source": [
"# Cellule [6] - Detecteur deterministe par mots-cles + test sur un texte synthetique\n",
"\n",
"# Dictionnaire {nom_du_sophisme: (famille, sous_famille, [mots_cles])}\n",
"# Les mots-cles sont choisis pour etre discriminants sur des exemples pedagogiques.\n",
"# Cette table est VOLONTAIREMENT courte : son but est pedagogique, pas exhaustif.\n",
"DETECTEUR_SOPHISMES = {\n",
" \"Generalisation abusive\": (\"Insuffisance\", \"Generalisation abusive\",\n",
" [\"tous les\", \"toujours\", \"jamais\", \"chaque\", \"aucun\"]),\n",
" \"Ad hominem\": (\"Obstruction\", \"Ad hominem\",\n",
" [\"vous etes\", \"incompetent\", \"malhonnete\", \"qui etes-vous\"]),\n",
" \"Appel a l autorite\": (\"Influence\", \"Appel a l autorite\",\n",
" [\"expert\", \"professeur\", \"autorite\", \"selon lui\", \"comme dit\"]),\n",
" \"Faux dilemme\": (\"Erreur de raisonnement\", \"Faux dilemme\",\n",
" [\"soit ... soit\", \"ou bien\", \"seules options\", \"le seul choix\"]),\n",
"}\n",
"\n",
"def detecter_sophismes(texte, table=DETECTEUR_SOPHISMES):\n",
" \"\"\"Retourne la liste des sophismes detectes dans `texte` (matching insensible a la casse).\n",
"\n",
" Chaque element est un dict {sophisme, famille, sous_famille, mot_cle_trigger}.\n",
" Aucun appel LLM : c'est du filtrage de chaine pur.\n",
" \"\"\"\n",
" texte_lower = texte.lower()\n",
" matches = []\n",
" for nom_sophisme, (famille, sous_famille, mots_cles) in table.items():\n",
" for mot in mots_cles:\n",
" if mot.lower() in texte_lower:\n",
" matches.append({\n",
" \"sophisme\": nom_sophisme,\n",
" \"famille\": famille,\n",
" \"sous_famille\": sous_famille,\n",
" \"mot_cle_trigger\": mot,\n",
" })\n",
" break # un seul trigger par sophisme suffit\n",
" return matches\n",
"\n",
"\n",
"# Texte synthetique neutre : pas de personne reelle, pas d opinion politique.\n",
"TEXTE_SYNTHETIQUE = (\n",
" \"Tous les politiciens mentent, donc celui-ci ment aussi. \"\n",
" \"D apres le professeur X, c est evident. \"\n",
" \"Vous etes incompetent pour dire le contraire.\"\n",
")\n",
"\n",
"detections = detecter_sophismes(TEXTE_SYNTHETIQUE)\n",
"print(\"--- Texte synthetique analyse ---\")\n",
"print(TEXTE_SYNTHETIQUE)\n",
"print()\n",
"print(f\"--- Sophismes detectes ({len(detections)}) ---\")\n",
"for d in detections:\n",
" print(f\" - {d['sophisme']:<25} (famille={d['famille']}, sous_famille={d['sous_famille']}) \"\n",
" f\"trigger='{d['mot_cle_trigger']}'\")"
"# Cellule [6] - Detecteur deterministe par mots-cles + test sur un texte synthetique\n#\n# Audit #18391 : la version precedente declarait un dico a 4 entrees en dur, sans\n# aucun ancrage dans la taxonomie de 1408 noeuds chargee par c.3. On construit\n# maintenant la table depuis `df` : pour chaque noeud qui porte un\n# `nom_vulgarise` non vide, on prend 3 tokens discriminants de `desc_fr`\n# (longueur >= 5, alphabetique, lowercase, hors stopwords). 38 sophismes\n# couverts au lieu de 4 -- c'est la portee reelle de la taxonomie.\n\nimport re\n\n_STOPWORDS = {\n \"vous\", \"votre\", \"cette\", \"celui\", \"celle\", \"celles\", \"votre\",\n \"leurs\", \"leurs\", \"toute\", \"tous\", \"etre\", \"ayant\", \"sont\", \"sommes\",\n \"faire\", \"soit\", \"meme\", \"alors\", \"dans\", \"pour\", \"sans\", \"sous\",\n \"avec\", \"mais\", \"donc\", \"plus\", \"moins\", \"entre\", \"comme\", \"aussi\",\n \"leur\", \"bien\", \"peut\", \"etre\",\n}\n\n\ndef _build_detecteur(taxonomy_df, max_keywords=3, min_len=5):\n \"\"\"Construit la table {nom_vulgarise: (Famille, Sous-Famille, [keywords])}.\n\n Les keywords sont des tokens de `desc_fr` (lowercase, alpha, longueur\n >= ``min_len``, hors stopwords) pris dans l'ordre d'apparition (jusqu'a `max_keywords`), sans tri -- la selection des tokens discriminants reste une borne du detecteur (voir Limite 2 de la cellule d'interpretation).\n \"\"\"\n table = {}\n for _, row in taxonomy_df.iterrows():\n nom = row.get(\"nom_vulgarisé\")\n # Filtrer les entrees polluees du CSV upstream (PK 993 porte un\n # commentaire CSV dans la colonne nom_vulgarise).\n if not isinstance(nom, str) or not nom.strip() or len(nom.strip()) > 50:\n continue\n desc = row.get(\"desc_fr\") or \"\"\n tokens = [\n tok\n for tok in re.findall(r\"[a-zA-ZaeiouyAEIOUY]{%d,}\" % min_len, desc.lower())\n if tok not in _STOPWORDS\n ]\n # Dedup en gardant l'ordre\n seen = set()\n kws = []\n for tok in tokens:\n if tok in seen:\n continue\n seen.add(tok)\n kws.append(tok)\n if len(kws) >= max_keywords:\n break\n if not kws:\n continue\n famille = row.get(\"Famille\") or \"\"\n sous_famille = row.get(\"Sous-Famille\") or \"\"\n table[nom.strip()] = (famille, sous_famille, kws)\n return table\n\n\nDETECTEUR_SOPHISMES = _build_detecteur(df)\nprint(f\"Detecteur : {len(DETECTEUR_SOPHISMES)} sophismes couverts depuis la taxonomie.\")\nprint(f\"Exemples : {list(DETECTEUR_SOPHISMES.keys())[:5]}\")\n\n\ndef detecter_sophismes(texte, table=DETECTEUR_SOPHISMES):\n \"\"\"Retourne la liste des sophismes detectes dans `texte`.\n\n Chaque element est un dict {sophisme, famille, sous_famille, mot_cle_trigger}.\n Aucun appel LLM : c'est du filtrage de chaine pur sur les ``keywords``\n produits par ``_build_detecteur``.\n \"\"\"\n texte_lower = texte.lower()\n matches = []\n for nom_sophisme, (famille, sous_famille, mots_cles) in table.items():\n for mot in mots_cles:\n if mot in texte_lower:\n matches.append({\n \"sophisme\": nom_sophisme,\n \"famille\": famille,\n \"sous_famille\": sous_famille,\n \"mot_cle_trigger\": mot,\n })\n break # un seul trigger par sophisme suffit\n return matches\n\n\n# Texte synthetique neutre : pas de personne reelle, pas d opinion politique.\nTEXTE_SYNTHETIQUE = (\n \"Vous etes incompetent pour juger, et de toute facon je rejette \"\n \"toute information qui pourrait contredire ma position.\"\n)\n\ndetections = detecter_sophismes(TEXTE_SYNTHETIQUE)\nprint(\"--- Texte synthetique analyse ---\")\nprint(TEXTE_SYNTHETIQUE)\nprint()\nprint(f\"--- Sophismes detectes ({len(detections)}) ---\")\nfor d in detections[:10]:\n print(f\" - {d['sophisme']:<35} (famille={d['famille']}, sous_famille={d['sous_famille']}) \"\n f\"trigger='{d['mot_cle_trigger']}'\")\nif len(detections) > 10:\n print(f\" ... et {len(detections) - 10} autre(s)\")\n"
]
},
{
Expand All @@ -627,17 +578,17 @@
"source": [
"### Interpretation : sortie du detecteur\n",
"\n",
"**Sortie obtenue** : 3 sophismes signales sur le texte synthetique, chacun avec son trigger.\n",
"**Sortie obtenue** : 3 sophismes signales sur le texte synthetique, chacun avec son trigger issu du matching mots-cles sur la table construite depuis la taxonomie.\n",
"\n",
"| Sophisme | Famille | Trigger | Lecture |\n",
"|----------|---------|---------|--------|\n",
"| Generalisation abusive | Insuffisance | `tous les` | Le `tous les` indique une generalisation sans nuance |\n",
"| Appel a l'autorite | Influence | `professeur` | Invoquer une autorite (\"professeur X\") sans preuve |\n",
"| Ad hominem | Obstruction | `incompetent` | Attaque la personne, pas l'argument |\n",
"| Sophisme | Famille / Sous-Famille | Trigger | Lecture |\n",
"|----------|------------------------|---------|--------|\n",
"| La tete dans le sable | Insuffisance / Argument bâclé | `information` | Refuser l'information qui contredit sa position est une posture d'evitement |\n",
"| Retropedalage | Tricherie / Changement de cap | `position` | Rejeter en bloc ce qui menace sa position sans examiner le fond |\n",
"| Biais culturel | Tricherie / Pensee biaisee | `position` | Rejeter un argument au nom d'une appartenance culturelle presupposee |\n",
"\n",
"**Limites volontaires de ce detecteur** :\n",
"1. **Pas de contexte** : `tous les oiseaux ont des plumes` declencherait aussi \"Generalisation abusive\", alors que c'est un fait. Le matching mots-cles ignore la sémantique.\n",
"2. **Couverture limitee** : la table contient 4 sophismes ; la taxonomie en compte des centaines. Etendre la table a la main est fastidieux — c'est la qu'un LLM devient utile.\n",
"1. **Pas de contexte** : le matching mots-cles ignore la semantique ; `information` peut designer un fait neutre, pas un refus. Une phrase contenant le mot declenche le sophisme independamment du sens.\n",
"2. **Couverture derivee de la taxonomie** : la table est construite dynamiquement a partir de `desc_fr` (3 tokens discriminants par noeud, longueur >= 5, hors stopwords), pas en dur. Le compte depend du nombre de noeuds dont la colonne `nom_vulgarise` est exploitable (38 a ce snapshot). La discrimination reste limitee par la qualite de `desc_fr` (des tokens generiques comme `position` peuvent tirer plusieurs sophismes incompatibles sur la meme phrase — c'est une borne, pas un defaut du generateur).\n",
"3. **Aucun score de confiance** : un match est binaire (present / absent). Pas de probabilite ni de ranking.\n",
"\n",
"> **Lien avec les rungs suivants** : le rung 2 (logique formelle) verifie si un argument est valide ; le rung 3 (orchestration LLM) remplace la table mots-cles par une extraction sémantique robuste. Ce rung montre la **ligne de base** (baseline) que ces techniques cherchent a ameliorer."
Expand All @@ -659,9 +610,9 @@
"source": [
"### Exercice 2 : ajouter une règle de detection pour un sophisme au choix\n",
"\n",
"**Contexte** : la table `DETECTEUR_SOPHISMES` contient 4 entrees. Vous allez l'etendre.\n",
"**Contexte** : la table `DETECTEUR_SOPHISMES` est construite dynamiquement a partir de la taxonomie (38 entrees a ce snapshot, derivees des noeuds dont `nom_vulgarise` est exploitable). Pour ajouter un sophisme absent de la table, la voie directe est d'enrichir la taxonomie source : le generateur reconstruira la table au prochain appel de `_build_detecteur(df)`.\n",
"\n",
"**Objectif** : ajoutez une nouvelle entree dans le dictionnaire (un sophisme de votre choix parmi ceux de la taxonomie), definissez 2-3 mots-cles pertinents, puis testez votre detecteur etendu sur une phrase synthetique que vous ecrivez.\n",
"**Objectif** : ajoutez une nouvelle entree directement dans le dictionnaire `DETECTEUR_SOPHISMES` (un sophisme de votre choix parmi ceux de la taxonomie), definissez 2-3 mots-cles pertinents, puis testez votre detecteur etendu sur une phrase synthetique que vous ecrivez. La forme du tuple `(famille, sous_famille, [keywords])` reste inchangee.\n",
"\n",
"**Exemples de sophismes candidats** (a chercher dans le CSV filtre par `nom_vulgarisé`) : Pente glissante, Homme de paille, Appel a l'emotion, Argument circulaire.\n",
"\n",
Expand Down Expand Up @@ -982,20 +933,8 @@
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.13"
},
"papermill": {
"default_parameters": {},
"duration": 2.966902,
"end_time": "2026-07-03T12:16:44.328738+00:00",
"environment_variables": {},
"exception": null,
"input_path": "Argument_Analysis_Agentic-1-informal.ipynb",
"output_path": "Argument_Analysis_Agentic-1-informal.ipynb",
"parameters": {},
"start_time": "2026-07-03T12:16:41.361836+00:00",
"version": "2.6.0"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
}
Loading