Merge pull request #48 from sebdraven/BartM82-patch-22

Bart m82 patch 22
Этот коммит содержится в:
Sebastien Larinier 2025-07-15 09:46:07 +02:00 коммит произвёл GitHub
родитель e48458be5f fcc339a157
Коммит 6d08c55e51
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
11 изменённых файлов: 2333 добавлений и 1 удалений

Просмотреть файл

@ -7,7 +7,7 @@ tags: [LMI,désinformation,guide,plugin]
## La V1 du Détecteur de Manipulation Cognitive 🧠 Plugin DIMA est disponible ## La V1 du Détecteur de Manipulation Cognitive 🧠 Plugin DIMA est disponible
[Téléchargez et installez le plugin Chrome ici :](https://github.com/M82-project/DIMA/tree/main/plugin/plugin_chrome/fichiers%20%C3%A0%20t%C3%A9l%C3%A9charger) [Téléchargez et installez le plugin Chrome ici :](/files/Plugin-dima-V1)
L'index [DIMA](https://m82-project.org/ressources/framework_dima_presentation/) est un outil de détection automatique des techniques cognitives dans les contenus web. Basé sur [la matrice DIMA](https://github.com/M82-project/DIMA) développée par le M82 project, il analyse en temps réel les pages que vous visitez pour identifier les tentatives de manipulation de l'information. L'index [DIMA](https://m82-project.org/ressources/framework_dima_presentation/) est un outil de détection automatique des techniques cognitives dans les contenus web. Basé sur [la matrice DIMA](https://github.com/M82-project/DIMA) développée par le M82 project, il analyse en temps réel les pages que vous visitez pour identifier les tentatives de manipulation de l'information.

283
static/files/Plugin-dima-V1/Data/keywords.js Обычный файл
Просмотреть файл

@ -0,0 +1,283 @@
// DIMA Enhanced Keywords Database
// Enhanced keyword patterns for manipulation technique detection
// ===== DÉTECTION DE TYPES DE PAGES AMÉLIORÉE =====
const PAGE_TYPE_PATTERNS = {
news: {
domains: ['bfmtv.com', 'lefigaro.fr', 'lemonde.fr', 'liberation.fr', 'franceinfo.fr', 'rfi.fr', 'euronews.com', 'cnn.com', 'bbc.com', 'reuters.com', 'france24.com'],
urls: ['news', 'article', 'actualit', 'info', 'breaking', 'flash'],
selectors: ['.article', '.news-article', '[class*="news"]', '[class*="article"]'],
meta: ['article:section', 'article:tag'],
weight_adjustments: {
'TE0500': 1.5, // Clickbait très grave en news
'TE0132': 1.4, // Biais négativité suspect
'TE0221': 1.6, // Stéréotypes inacceptables
'TE0501': 1.3 // FOMO suspect en news
}
},
blog: {
domains: ['medium.com', 'substack.com', 'wordpress.com', 'blogspot.com', 'ghost.io'],
urls: ['blog', 'post', 'article'],
selectors: ['.post', '.blog-post', '[class*="blog"]', '.entry'],
meta: ['article:author'],
weight_adjustments: {
'TE0212': 0.8, // Anecdotes plus normales
'TE0314': 0.9, // Suggestions plus acceptables
'TE0261': 0.7, // Biais rétrospectif courant
'TE0321': 1.1 // Biais confirmation suspect
}
},
social: {
domains: ['facebook.com', 'twitter.com', 'instagram.com', 'linkedin.com', 'tiktok.com', 'youtube.com', 'reddit.com', 'discord.com', 'telegram.org'],
urls: ['social', 'post', 'status', 'tweet', 'story'],
selectors: ['.post', '.tweet', '.story', '[data-testid*="tweet"]', '[role="article"]'],
meta: ['twitter:card', 'og:type'],
weight_adjustments: {
'TE0132': 0.9, // Négativité plus courante
'TE0131': 0.8, // Bizarrerie normale
'TE0501': 1.3, // FOMO plus manipulatoire
'TE0221': 1.7, // Stéréotypes très graves
'TE0251': 1.2 // Faux consensus suspect
}
},
commerce: {
domains: ['amazon.com', 'aliexpress.com', 'cdiscount.com', 'fnac.com', 'darty.com', 'leclerc.com', 'carrefour.fr', 'shopify.com'],
urls: ['shop', 'buy', 'product', 'store', 'cart', 'checkout', 'commerce', 'vente'],
selectors: ['.product', '.shop', '.store', '[class*="price"]', '.add-to-cart'],
meta: ['product:price', 'product:availability'],
weight_adjustments: {
'TE0501': 0.8, // FOMO plus normale en commerce
'TE0141': 0.7, // Effet Restorff marketing normal
'TE0143': 0.6, // Comparaisons normales
'TE0422': 1.2, // Fausse autorité problématique
'TE0411': 1.1 // Excès confiance suspect
}
},
educational: {
domains: ['wikipedia.org', 'edu', 'ac.uk', 'universalis.fr', 'larousse.fr', 'coursera.com', 'edx.org', 'khanacademy.org'],
urls: ['learn', 'course', 'education', 'wiki', 'tutorial', 'lesson', 'formation'],
selectors: ['.course', '.lesson', '.wiki-content', '.educational'],
meta: ['article:section'],
weight_adjustments: {
'TE0221': 1.8, // Stéréotypes très graves en éducation
'TE0422': 0.8, // Autorité plus normale
'TE0212': 0.7, // Exemples pédagogiques normaux
'TE0241': 0.8 // Simplifications parfois nécessaires
}
},
health: {
domains: ['ameli.fr', 'who.int', 'doctissimo.fr', 'vidal.fr', 'pasteur.fr', 'has-sante.fr', 'webmd.com', 'mayoclinic.org'],
urls: ['health', 'medical', 'sante', 'medecin', 'doctor', 'hospital', 'clinic'],
selectors: ['.health-content', '.medical', '[class*="health"]'],
meta: ['article:section'],
weight_adjustments: {
'TE0422': 0.7, // Autorité médicale légitime
'TE0212': 1.4, // Preuves anecdotiques dangereuses
'TE0221': 1.9, // Stéréotypes très graves
'TE0500': 1.6, // Clickbait santé très dangereux
'TE0501': 1.5 // FOMO santé dangereux
}
},
political: {
domains: ['gouvernement.fr', 'elysee.fr', 'assemblee-nationale.fr', 'senat.fr', 'service-public.fr'],
urls: ['politique', 'political', 'election', 'vote', 'government','gouv', 'gov', 'ministre'],
selectors: ['.political', '.government', '[class*="politic"]'],
meta: ['article:section'],
weight_adjustments: {
'TE0221': 2.0, // Stéréotypes très graves en politique
'TE0132': 1.3, // Biais négativité suspect
'TE0251': 1.5, // Faux consensus très suspect
'TE0321': 1.4, // Biais confirmation dangereux
'TE0422': 1.2 // Fausse autorité problématique
}
},
financial: {
domains: ['banque-france.fr', 'amf-france.org', 'boursorama.com', 'lesechos.fr', 'bloomberg.com', 'reuters.com'],
urls: ['finance', 'investment', 'bourse', 'crypto', 'trading', 'bank', 'credit'],
selectors: ['.financial', '.investment', '[class*="finance"]', '.trading'],
meta: ['article:section'],
weight_adjustments: {
'TE0501': 1.6, // FOMO financier très dangereux
'TE0422': 1.3, // Fausse autorité financière grave
'TE0411': 1.4, // Excès confiance dangereux
'TE0500': 1.5, // Clickbait financier dangereux
'TE0212': 1.3 // Preuves anecdotiques suspectes
}
},
gaming: {
domains: ['steam.com', 'epicgames.com', 'twitch.tv', 'gamepass.com', 'ign.com', 'gamespot.com'],
urls: ['game', 'gaming', 'jeux', 'play', 'stream'],
selectors: ['.game', '.gaming', '[class*="game"]', '.player'],
meta: ['og:type'],
weight_adjustments: {
'TE0501': 0.9, // FOMO plus normal en gaming
'TE0141': 0.8, // Unicité marketing normale
'TE0131': 0.7, // Bizarrerie plus normale
'TE0421': 1.2 // Coûts irrécupérables suspect (microtransactions)
}
},
dating: {
domains: ['tinder.com', 'meetic.fr', 'adopteunmec.com', 'badoo.com', 'bumble.com'],
urls: ['dating', 'rencontre', 'love', 'flirt'],
selectors: ['.profile', '.dating', '[class*="match"]', '.member'],
meta: ['og:type'],
weight_adjustments: {
'TE0501': 1.4, // FOMO émotionnel suspect
'TE0221': 1.8, // Stéréotypes graves
'TE0131': 1.1, // Bizarrerie suspecte
'TE0251': 1.3, // Faux consensus suspect
'TE0422': 1.2 // Fausse autorité suspecte
}
},
conspiracy: {
domains: ['4chan.org', 'infowars.com', 'breitbart.com'],
urls: ['conspiracy', 'complot', 'truth', 'expose', 'reveal', 'secret'],
selectors: ['.conspiracy', '.truth', '[class*="expose"]'],
meta: [],
weight_adjustments: {
'TE0221': 2.5, // Stéréotypes extrêmement graves
'TE0132': 1.8, // Biais négativité très suspect
'TE0500': 1.9, // Clickbait très dangereux
'TE0212': 1.7, // Preuves anecdotiques très suspectes
'TE0251': 1.8, // Faux consensus très dangereux
'TE0321': 1.6 // Biais confirmation très dangereux
}
}
};
// ===== BASE DE DONNÉES DES MOTS-CLÉS AMÉLIORÉS =====
const DIMA_ENHANCED_KEYWORDS = {
"TE0111": {
core: ["exemple", "cas", "témoignage", "example", "case", "testimony"],
variants: {
formal: ["illustration", "démonstration", "spécimen"],
informal: ["histoire", "vécu", "expérience"],
intensity: {
weak: ["petit exemple", "simple cas"],
strong: ["exemple frappant", "cas édifiant", "témoignage bouleversant"]
}
},
patterns: [
/(?:par\s+exemple|for\s+example|comme\s+dans\s+le\s+cas)/i,
/(?:prenons\s+l'exemple|take\s+the\s+example)/i
]
},
"TE0500": {
core: ["secret", "choquant", "incroyable", "shocking", "amazing"],
variants: {
clickbait_formulas: [
"vous ne croirez pas", "ce qui arrive ensuite", "you won't believe",
"what happens next", "les experts détestent", "un truc simple",
"cette astuce", "révélation choc", "doctors hate this"
],
emotional_hooks: [
"ça va vous surprendre", "préparez-vous", "attention",
"exclusif", "urgent", "will shock you", "prepare yourself"
],
curiosity_gaps: [
"la raison va vous étonner", "voici pourquoi", "découvrez comment",
"la vérité sur", "the reason will amaze you", "here's why"
]
},
patterns: [
/\d+\s+(?:choses|façons|méthodes|secrets|things|ways|methods)\s+(?:que|pour|de|to|that)/i,
/(?:voici|découvrez|here's|discover)\s+(?:comment|pourquoi|ce que|how|why|what)/i,
/(?:cette|cette|this)\s+\w+\s+va\s+vous\s+(?:\w+|will)/i,
/(?:shocking|amazing|incredible)\s+(?:secret|truth|fact)/i
]
},
"TE0132": {
core: ["catastrophe", "panique", "chaos", "disaster", "danger", "menace", "threat", "risque", "risk", "grave", "serious", "crise", "crisis"],
variants: {
intensity: {
weak: ["problème", "difficulté", "souci", "issue", "concern"],
strong: ["catastrophe majeure", "crise grave", "danger mortel", "major catastrophe", "deadly danger"]
},
temporal: ["imminent", "proche", "bientôt", "soon", "approaching"]
},
patterns: [
/(?:alerte|alert|warning|attention)\s+(?:rouge|red|maximum)/i,
/(?:situation|crisis|problem)\s+(?:critique|critical|dramatique|dramatic)/i
]
},
"TE0501": {
core: ["ne ratez pas", "don't miss", "dernière chance", "last chance", "limité", "limited", "exclusif", "exclusive"],
variants: {
urgency: ["dépêchez-vous", "hurry up", "vite", "quickly", "maintenant ou jamais", "now or never"],
scarcity: ["stock limité", "places limitées", "limited stock", "limited seats", "offre limitée"]
},
patterns: [
/(?:seulement|only)\s+\d+\s+(?:jours?|heures?|minutes?|days?|hours?|minutes?)/i,
/(?:expire|ends?)\s+(?:bientôt|soon|today|demain|tomorrow)/i
]
}
};
// ===== PATTERNS CONTEXTUELS ÉTENDUS =====
const CONTEXT_PATTERNS = {
urgency: {
patterns: [
/(?:urgent|rapidement|vite|immédiatement|maintenant|now|quickly|immediately)/i,
/(?:dernière\s+chance|temps\s+limité|offre\s+limitée|last\s+chance|limited\s+time)/i,
/(?:dépêchez-vous|ne\s+ratez\s+pas|hurry|don't\s+miss)/i,
/(?:avant\s+qu'il\s+soit\s+trop\s+tard|before\s+it's\s+too\s+late)/i
],
boost: 1.3,
techniques: ['TE0501', 'TE0500']
},
authority: {
patterns: [
/(?:selon\s+(?:les\s+)?(?:experts?|spécialistes?|docteurs?|doctors?|experts?))/i,
/(?:étude\s+(?:révèle|montre|démontre|shows?|reveals?))/i,
/(?:recherche\s+(?:scientifique|universitaire|scientific|university))/i,
/(?:professeur|université|institut|laboratory)/i
],
boost: 1.4,
techniques: ['TE0422', 'TE0212']
},
social_proof: {
patterns: [
/(?:\d+(?:\.\d+)?[km]?\s+personnes?\s+(?:utilisent|font|pensent|people\s+(?:use|do|think)))/i,
/(?:tout\s+le\s+monde|la\s+plupart\s+des\s+gens|everyone|most\s+people)/i,
/(?:viral|tendance|populaire|trending|popular)/i,
/(?:millions\s+de|thousands\s+of|des\s+milliers)/i
],
boost: 1.2,
techniques: ['TE0251', 'TE0221']
},
fear: {
patterns: [
/(?:attention|danger|risque|warning|risk|threat)/i,
/(?:peur|fear|afraid|effrayant|scary)/i,
/(?:catastrophe|disaster|tragédie|tragedy)/i
],
boost: 1.4,
techniques: ['TE0132', 'TE0500']
},
conspiracy: {
patterns: [
/(?:ils\s+(?:ne\s+veulent\s+pas|cachent)|they\s+(?:don't\s+want|hide))/i,
/(?:vérité\s+cachée|hidden\s+truth|secret\s+agenda)/i,
/(?:complot|conspiracy|manipulation\s+des\s+masses)/i,
/(?:révélation|expose|dévoile|reveals?)/i
],
boost: 1.6,
techniques: ['TE0500', 'TE0221', 'TE0132']
}
};
// Make keywords and patterns available globally for Chrome extension
window.DIMA_ENHANCED_KEYWORDS = DIMA_ENHANCED_KEYWORDS;
window.CONTEXT_PATTERNS = CONTEXT_PATTERNS;

Просмотреть файл

@ -0,0 +1,922 @@
// DIMA Techniques Database
// Complete database of manipulation techniques and tactics
const DIMA_TECHNIQUES = [
// PHASE DETECTER - TACTIQUES
{
index: "TA0011",
nom: "Information préexistante",
phase: "Detect",
description: "Exploitation d'informations déjà connues ou familières",
mots_cles: [
"déjà",
"connu",
"already",
"known",
"familier",
"familiar",
"habituel",
"usual",
"précédemment",
"previously",
],
weight: 1.1,
type: "tactic",
},
{
index: "TA0012",
nom: "Information à exposition répétée",
phase: "Detect",
description:
"Répétition d'informations pour créer une familiarité artificielle",
mots_cles: [
"encore",
"again",
"répéter",
"repeat",
"redire",
"retell",
"rappel",
"reminder",
"à nouveau",
"once again",
],
weight: 1.2,
type: "tactic",
},
{
index: "TA0013",
nom: "Information clivante",
phase: "Detect",
description:
"Utilisation d'informations polarisantes pour attirer l'attention",
mots_cles: [
"polémique",
"controversial",
"scandaleux",
"outrageous",
"choquant",
"shocking",
"divise",
"divides",
"clivant",
],
weight: 1.4,
type: "tactic",
},
{
index: "TA0014",
nom: "Écart à la norme",
phase: "Detect",
description: "Mise en avant d'éléments sortant de l'ordinaire",
mots_cles: [
"inhabituel",
"unusual",
"anormal",
"abnormal",
"exception",
"extraordinary",
"hors norme",
"atypique",
],
weight: 1.3,
type: "tactic",
},
{
index: "TA0015",
nom: "Détail signifiant",
phase: "Detect",
description:
"Focus sur des détails pour donner une impression de précision",
mots_cles: [
"précisément",
"exactly",
"détail",
"detail",
"spécifiquement",
"specifically",
"en particulier",
"particularly",
],
weight: 1.1,
type: "tactic",
},
// PHASE DETECTER - TECHNIQUES
{
index: "TE0111",
nom: "Heuristique de disponibilité",
phase: "Detect",
description: "Surreprésentation d'exemples facilement mémorisables",
mots_cles: [
"récent",
"disponible",
"recently",
"exemple",
"example",
"cas",
"case",
"témoignage",
"testimony",
],
weight: 1.0,
type: "technique",
tactic: "TA0011",
},
{
index: "TE0112",
nom: "Effet de simple exposition",
phase: "Detect",
description: "Répétition pour créer une familiarité artificielle",
mots_cles: [
"encore",
"again",
"toujours",
"always",
"répétition",
"repetition",
"familier",
"familiar",
],
weight: 1.2,
type: "technique",
tactic: "TA0011",
},
{
index: "TE0121",
nom: "Illusion de la fréquence",
phase: "Detect",
description: "Impression exagérée de fréquence d'un phénomène",
mots_cles: [
"partout",
"everywhere",
"de plus en plus",
"more and more",
"fréquent",
"frequent",
"épidémie",
"epidemic",
],
weight: 1.1,
type: "technique",
tactic: "TA0012",
},
{
index: "TE0122",
nom: "Effet de contexte",
phase: "Detect",
description: "Utilisation du contexte pour influencer la perception",
mots_cles: [
"similaire",
"same as",
"cela rappelle",
"déjà vu",
"par ailleurs",
"contexte",
],
weight: 0.9,
type: "technique",
tactic: "TA0012",
},
{
index: "TE0131",
nom: "Effet de bizarrerie",
phase: "Detect",
description:
"Mise en avant d'éléments inhabituels pour attirer l'attention",
mots_cles: [
"étrange",
"strange",
"bizarre",
"weird",
"incroyable",
"incredible",
"choquant",
"shocking",
"inhabituel",
"unusual",
],
weight: 1.3,
type: "technique",
tactic: "TA0013",
},
{
index: "TE0132",
nom: "Biais de négativité",
phase: "Detect",
description: "Accent mis sur les aspects négatifs pour capter l'attention",
mots_cles: [
"catastrophe",
"chaos",
"disaster",
"danger",
"menace",
"threat",
"risque",
"risk",
"grave",
"serious",
"crise",
"crisis",
],
weight: 1.4,
type: "technique",
tactic: "TA0013",
},
{
index: "TE0141",
nom: "Effet von Restorff",
phase: "Detect",
description: "Mise en avant de l'unicité pour marquer les esprits",
mots_cles: [
"unique",
"seul",
"only",
"exclusif",
"exclusive",
"spécial",
"special",
"exceptionnel",
"exceptional",
"rare",
],
weight: 1.1,
type: "technique",
tactic: "TA0014",
},
{
index: "TE0142",
nom: "Biais d'ancrage",
phase: "Detect",
description: "Première information comme point de référence",
mots_cles: [
"première fois",
"first time",
"jamais vu",
"never seen",
"inédit",
"unprecedented",
"révélation",
"revelation",
],
weight: 1.2,
type: "technique",
tactic: "TA0015",
},
{
index: "TE0143",
nom: "Effet de contraste",
phase: "Detect",
description: "Comparaisons pour influencer la perception relative",
mots_cles: [
"par rapport à",
"compare with",
"différence",
"difference",
"comparaison",
"delta",
"distinction",
],
weight: 0.8,
type: "technique",
tactic: "TA0015",
},
{
index: "TE0500",
nom: "Clickbait",
phase: "Detect",
description: "Titres accrocheurs pour générer des clics",
mots_cles: [
"vous ne croirez pas",
"you won't believe",
"ce qui arrive ensuite",
"what happens next",
"secret",
"shocking",
"mind-blowing",
"amazing",
],
weight: 1.5,
type: "technique",
tactic: "TA0013",
},
// PHASE INFORMER - TACTIQUES
{
index: "TA0021",
nom: "Création d'un motif",
phase: "Informer",
description: "Construction artificielle de patterns ou de tendances",
mots_cles: [
"motif",
"pattern",
"tendance",
"trend",
"récurrent",
"recurrent",
"régulier",
"regular",
"systématique",
],
weight: 1.3,
type: "tactic",
},
{
index: "TA0022",
nom: "Généralisation et renforcement de stéréotypes",
phase: "Informer",
description: "Utilisation et amplification de clichés pour simplifier",
mots_cles: [
"stéréotype",
"stereotype",
"cliché",
"caricature",
"généralement",
"generally",
"typique",
"typical",
],
weight: 1.6,
type: "tactic",
},
{
index: "TA0023",
nom: "Supériorité familière",
phase: "Informer",
description: "Valorisation de ce qui est connu et familier",
mots_cles: [
"mieux",
"better",
"supérieur",
"superior",
"préférable",
"preferable",
"notre",
"our",
"familier",
"familiar",
],
weight: 1.2,
type: "tactic",
},
{
index: "TA0024",
nom: "Simplification",
phase: "Informer",
description: "Réduction excessive de la complexité",
mots_cles: [
"simple",
"simple",
"facile",
"easy",
"évident",
"obvious",
"clair",
"clear",
"suffit",
"enough",
],
weight: 1.3,
type: "tactic",
},
{
index: "TA0025",
nom: "Auto-référence",
phase: "Informer",
description:
"Utilisation de références internes pour créer une cohérence artificielle",
mots_cles: [
"comme nous",
"like us",
"notre",
"our",
"nous-mêmes",
"ourselves",
"chez nous",
"among us",
],
weight: 1.2,
type: "tactic",
},
{
index: "TA0026",
nom: "Projection temporelle",
phase: "Informer",
description: "Manipulation de la perception du temps",
mots_cles: [
"bientôt",
"soon",
"déjà",
"already",
"encore",
"still",
"toujours",
"always",
"jamais",
"never",
],
weight: 1.1,
type: "tactic",
},
// PHASE INFORMER - TECHNIQUES
{
index: "TE0211",
nom: "Corrélation illusoire",
phase: "Informer",
description: "Présentation de corrélations trompeuses",
mots_cles: [
"corrélation",
"similaire",
"pareil",
"comparaison",
"lien",
"relation",
],
weight: 1.3,
type: "technique",
tactic: "TA0021",
},
{
index: "TE0212",
nom: "Biais de la preuve anecdotique",
phase: "Informer",
description: "Généralisation basée sur des cas particuliers",
mots_cles: [
"cette histoire démontre",
"anecdote",
"exemple",
"illustration",
"selon une étude",
"un témoignage",
"un témoin",
],
weight: 1.4,
type: "technique",
tactic: "TA0021",
},
{
index: "TE0213",
nom: "Illusion des séries",
phase: "Informer",
description: "Perception de motifs dans des données aléatoires",
mots_cles: [
"coïncidences",
"motif",
"données démontrent",
"statistiques",
"tendance",
],
weight: 1.1,
type: "technique",
tactic: "TA0021",
},
{
index: "TE0221",
nom: "Stéréotypes",
phase: "Informer",
description: "Généralisation excessive de groupes",
mots_cles: [
"stéréotype",
"les étrangers",
"les immigrants",
"all the",
"toujours",
"always",
"jamais",
"never",
"en général",
"in general",
"les français",
"americans",
],
weight: 1.6,
type: "technique",
tactic: "TA0022",
},
{
index: "TE0231",
nom: "Biais d'homogénéité",
phase: "Informer",
description: "Perception que tous les membres d'un groupe sont similaires",
mots_cles: [
"tous les",
"Homogène",
"tous pareil",
"toutes choses égales par ailleurs",
],
weight: 1.2,
type: "technique",
tactic: "TA0022",
},
{
index: "TE0232",
nom: "Biais de la route connue",
phase: "Informer",
description: "Préférence pour les solutions familières",
mots_cles: [
"comme avant",
"habitude",
"habituel",
"conserver",
"rassurant",
],
weight: 0.9,
type: "technique",
tactic: "TA0023",
},
{
index: "TE0241",
nom: "Simplification excessive",
phase: "Informer",
description: "Réduction de problèmes complexes à des solutions simples",
mots_cles: [
"simple",
"évident",
"obvious",
"clair",
"clear",
"facile",
"easy",
"suffit de",
"just need to",
"solution",
],
weight: 1.3,
type: "technique",
tactic: "TA0024",
},
{
index: "TE0251",
nom: "Faux consensus",
phase: "Informer",
description: "Illusion d'un accord général inexistant",
mots_cles: [
"tout le monde",
"consensus",
"convergence",
"everyone",
"la plupart",
"most people",
"nous pensons",
"we think",
"accord",
],
weight: 1.4,
type: "technique",
tactic: "TA0025",
},
{
index: "TE0261",
nom: "Biais rétrospectif",
phase: "Informer",
description: "Illusion d'avoir prévu un événement après coup",
mots_cles: [
"j'avais dit",
"nous étions prévenus",
"on le savait",
"i told you",
"prévisible",
"predictable",
"on aurait dû",
"should have",
"signes",
"signs",
],
weight: 1.1,
type: "technique",
tactic: "TA0026",
},
// PHASE MEMORISER - TACTIQUES
{
index: "TA0031",
nom: "Renforcement indirect",
phase: "Mémoriser",
description:
"Consolidation subtile d'informations par répétition indirecte",
mots_cles: [
"renforce",
"reinforces",
"confirme",
"confirms",
"soutient",
"supports",
"appuie",
"backs",
],
weight: 1.2,
type: "tactic",
},
{
index: "TA0032",
nom: "Renforcement pré-existant",
phase: "Mémoriser",
description: "Activation de croyances déjà établies",
mots_cles: [
"comme prévu",
"as expected",
"j'avais raison",
"I was right",
"évident",
"obvious",
"logique",
"logical",
],
weight: 1.3,
type: "tactic",
},
{
index: "TA0033",
nom: "Exposition de contenus",
phase: "Mémoriser",
description: "Présentation répétée de contenus pour ancrage mémoriel",
mots_cles: [
"exposition",
"exposure",
"présentation",
"presentation",
"affichage",
"display",
"montrer",
"show",
],
weight: 1.1,
type: "tactic",
},
// PHASE MEMORISER - TECHNIQUES
{
index: "TE0312",
nom: "Biais de la confusion des sources",
phase: "Mémoriser",
description: "Difficulté à distinguer les sources d'information",
mots_cles: [
"des sources affirment",
"sources confirment",
"rien ne démontre",
"hasard ?",
"les faits",
],
weight: 1.2,
type: "technique",
tactic: "TA0031",
},
{
index: "TE0313",
nom: "Effet d'espacement",
phase: "Mémoriser",
description: "Répétition espacée pour renforcer la mémorisation",
mots_cles: [
"comme déjà",
"dans un article précédent",
"rappelons",
"comme nous l'avons vu",
],
weight: 1.0,
type: "technique",
tactic: "TA0033",
},
{
index: "TE0314",
nom: "Effet de suggestion",
phase: "Mémoriser",
description: "Implantation d'idées par suggestion indirecte",
mots_cles: [
"et si",
"cela évoque",
"évoquer",
"image",
"imaginez",
"supposons",
],
weight: 1.1,
type: "technique",
tactic: "TA0031",
},
{
index: "TE0321",
nom: "Biais de confirmation",
phase: "Mémoriser",
description: "Recherche d'informations confirmant les croyances existantes",
mots_cles: [
"confirme",
"cela démontre",
"démontrer",
"confirms",
"prouve",
"proves",
"comme prévu",
"as expected",
"j'avais raison",
"i was right",
"évident",
"obvious",
],
weight: 1.5,
type: "technique",
tactic: "TA0032",
},
{
index: "TE0331",
nom: "Effet de récence",
phase: "Mémoriser",
description: "Surpondération des informations récentes",
mots_cles: [
"récent",
"recent",
"nouveauté",
"dernier",
"last",
"nouveau",
"new",
"frais",
"fresh",
"actuel",
"current",
],
weight: 1.1,
type: "technique",
tactic: "TA0033",
},
{
index: "TE0333",
nom: "Effet de primauté",
phase: "Mémoriser",
description: "Surpondération des premières informations reçues",
mots_cles: [
"premier",
"first",
"initial",
"début",
"beginning",
"origine",
"origin",
"primordial",
],
weight: 1.0,
type: "technique",
tactic: "TA0033",
},
// PHASE AGIR - TACTIQUES
{
index: "TA0041",
nom: "Valorisation individuelle",
phase: "Act",
description: "Mise en avant des bénéfices personnels pour motiver l'action",
mots_cles: [
"vous bénéficiez",
"you benefit",
"votre avantage",
"your advantage",
"pour vous",
"for you",
"personnel",
"personal",
],
weight: 1.3,
type: "tactic",
},
{
index: "TA0042",
nom: "Renforcement escalatoire",
phase: "Act",
description: "Augmentation progressive de l'engagement demandé",
mots_cles: [
"progressivement",
"progressively",
"étape par étape",
"step by step",
"graduellement",
"gradually",
"petit à petit",
],
weight: 1.4,
type: "tactic",
},
{
index: "TA0043",
nom: "Ozaekomi waza (contrôle par immobilisation)",
phase: "Act",
description: "Blocage des alternatives pour forcer une décision",
mots_cles: [
"seule option",
"only option",
"pas le choix",
"no choice",
"obligé",
"forced",
"contrainte",
"constraint",
],
weight: 1.5,
type: "tactic",
},
// PHASE AGIR - TECHNIQUES
{
index: "TE0411",
nom: "Excès de confiance",
phase: "Act",
description: "Surestimation de ses propres capacités ou connaissances",
mots_cles: [
"confiant",
"confident",
"sûr",
"sure",
"certain",
"capable",
"expert",
"maîtrise",
"mastery",
],
weight: 1.2,
type: "technique",
tactic: "TA0041",
},
{
index: "TE0421",
nom: "Coûts irrécupérables",
phase: "Act",
description: "Persistance dans une voie du fait d'investissements passés",
mots_cles: [
"continuer",
"continue",
"persister",
"persist",
"investir plus",
"invest more",
"ne pas abandonner",
"don't give up",
],
weight: 1.1,
type: "technique",
tactic: "TA0042",
},
{
index: "TE0422",
nom: "Biais d'autorité",
phase: "Act",
description: "Influence excessive des figures d'autorité",
mots_cles: [
"autorité",
"authority",
"expert",
"spécialiste",
"specialist",
"professeur",
"professor",
"docteur",
"doctor",
"officiel",
],
weight: 1.3,
type: "technique",
tactic: "TA0041",
},
{
index: "TE0432",
nom: "Biais du statu quo",
phase: "Act",
description: "Préférence pour maintenir l'état actuel",
mots_cles: [
"rester",
"stay",
"maintenir",
"maintain",
"ne pas changer",
"don't change",
"status quo",
"comme ça",
"as is",
],
weight: 1.0,
type: "technique",
tactic: "TA0043",
},
{
index: "TE0501",
nom: "FOMO",
phase: "Act",
description: "Peur de rater une opportunité",
mots_cles: [
"ne ratez pas",
"don't miss",
"dernière chance",
"last chance",
"limité",
"limited",
"exclusif",
"exclusive",
"hurry",
"urgent",
],
weight: 1.4,
type: "technique",
tactic: "TA0041",
},
];
// Make DIMA_TECHNIQUES available globally for Chrome extension
window.DIMA_TECHNIQUES = DIMA_TECHNIQUES;

Двоичные данные
static/files/Plugin-dima-V1/M82-logo-128.png Обычный файл

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 332 KiB

Двоичные данные
static/files/Plugin-dima-V1/M82-logo-16.png Обычный файл

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 332 KiB

Двоичные данные
static/files/Plugin-dima-V1/M82-logo-48.png Обычный файл

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 332 KiB

146
static/files/Plugin-dima-V1/content.js Обычный файл
Просмотреть файл

@ -0,0 +1,146 @@
// Plugin DIMA - content.js - Version finale consolidée
// Détection de manipulation cognitive - M82 Project
// Version: 3.0 Refactored with ContentExtractor
// Note: All dependencies are loaded via manifest.json in correct order
// ===== CLASSE PRINCIPALE DIMA =====
class DIMAAnalyzer {
constructor() {
this.analysisResults = null;
this.cache = new Map();
this.settings = {
maxContentLength: 5000,
minKeywordLength: 3,
analysisDelay: 2000,
debugMode: false,
enhancedKeywords: true,
}; // Initialize ContentExtractor with settings
this.contentExtractor = new window.ContentExtractor(this.settings);
this.pageType = this.contentExtractor.detectPageType();
// Initialize TechniqueAnalyzer with dependencies
this.techniqueAnalyzer = new window.TechniqueAnalyzer(
this.settings,
window.DIMA_ENHANCED_KEYWORDS,
window.CONTEXT_PATTERNS,
window.DIMA_TECHNIQUES,
this.pageType
);
// Initialize UIManager
this.uiManager = new window.UIManager(this.settings);
this.uiManager.setPageType(this.pageType);
this.init();
}
init() {
this.log("Initialisation DIMA avec mots-clés améliorés...");
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", () => {
this.delayedInit();
});
} else {
this.delayedInit();
}
}
delayedInit() {
setTimeout(() => {
try {
this.analyzeCurrentPage();
} catch (error) {
console.error("DIMA: Erreur lors de l'analyse:", error);
}
}, this.settings.analysisDelay);
}
log(message, data = null) {
if (this.settings.debugMode) {
console.log(`DIMA: ${message}`, data || "");
}
}
analyzeCurrentPage() {
try {
this.log("Analyse de la page...");
const cacheKey = window.location.href + document.title;
if (this.cache.has(cacheKey)) {
this.analysisResults = this.cache.get(cacheKey);
this.uiManager.createButton(this.analysisResults);
return;
}
const title = this.contentExtractor.extractTitle();
const content = this.contentExtractor.extractContent();
this.log("Titre extrait:", title);
this.log("Contenu extrait:", `${content.length} caractères`);
this.analysisResults = this.techniqueAnalyzer.performAnalysis(
title,
content
);
this.cache.set(cacheKey, this.analysisResults);
this.log("Analyse terminée, score:", this.analysisResults.globalScore);
this.uiManager.createButton(this.analysisResults);
} catch (error) {
console.error("DIMA: Erreur dans analyzeCurrentPage:", error);
}
}
}
// ===== INITIALISATION ET STYLES =====
// CSS pour les animations
const style = document.createElement("style");
style.textContent = `
@keyframes dimaFadeIn {
from { opacity: 0; transform: scale(0.9); }
to { opacity: 1; transform: scale(1); }
}
#dima-btn {
animation: dimaFadeIn 0.5s ease-out;
}
`;
document.head.appendChild(style);
// Initialisation sécurisée avec gestion d'erreurs améliorée
console.log("DIMA: Script chargé - Version complète avec mots-clés améliorés");
// Vérifier que toutes les dépendances sont chargées
function checkDependencies() {
return (
window.DIMA_TECHNIQUES &&
window.DIMA_ENHANCED_KEYWORDS &&
window.CONTEXT_PATTERNS &&
window.ContentExtractor &&
window.TechniqueAnalyzer &&
window.UIManager
);
}
// Initialiser avec retry si nécessaire
function initializeDIMA() {
if (!checkDependencies()) {
console.log("DIMA: Attente du chargement des dépendances...");
setTimeout(initializeDIMA, 100);
return;
}
try {
const analyzer = new DIMAAnalyzer();
console.log(
`DIMA: Analyseur initialisé pour page de type: ${analyzer.pageType}`
);
} catch (error) {
console.error("DIMA: Erreur d'initialisation critique:", error);
}
}
// Démarrer l'initialisation
initializeDIMA();

34
static/files/Plugin-dima-V1/manifest.json Обычный файл
Просмотреть файл

@ -0,0 +1,34 @@
{
"manifest_version": 3,
"name": "Analyseur DIMA - M82 Project",
"version": "1.1",
"description": "Plugin d'analyse de manipulation cognitive selon la matrice DIMA par M82 Project",
"permissions": ["activeTab", "storage"],
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": [
"data/techniques.js",
"data/keywords.js",
"modules/contentExtractor.js",
"modules/techniqueAnalyzer.js",
"modules/uiManager.js",
"content.js"
]
}
],
"action": {
"default_title": "Analyse DIMA - M82 Project"
},
"icons": {
"16": "M82-logo-16.png",
"48": "M82-logo-48.png",
"128": "M82-logo-128.png"
},
"web_accessible_resources": [
{
"resources": ["M82-logo-16.png"],
"matches": ["<all_urls>"]
}
]
}

Просмотреть файл

@ -0,0 +1,184 @@
// Content Extractor Module
// Responsible for extracting and cleaning content from web pages
class ContentExtractor {
constructor(settings) {
this.settings = settings || {
maxContentLength: 5000,
minKeywordLength: 3,
debugMode: false,
};
}
log(message, data = null) {
if (this.settings.debugMode) {
console.log(`ContentExtractor: ${message}`, data || "");
}
}
extractTitle() {
const titleSources = [
() => document.title,
() => document.querySelector('meta[property="og:title"]')?.content,
() => document.querySelector('meta[name="twitter:title"]')?.content,
() => document.querySelector("h1")?.textContent?.trim(),
() =>
document
.querySelector('.title, .headline, [class*="title"]')
?.textContent?.trim(),
];
return titleSources
.map((fn) => fn())
.filter(Boolean)
.join(" ")
.substring(0, 500)
.trim();
}
extractContent() {
this.log("Début extraction de contenu...");
const extractedTexts = new Set();
let content = "";
// Sélecteurs prioritaires pour le contenu principal
const contentSelectors = [
"article",
'[role="main"]',
"main",
".article-content, .post-content, .entry-content",
".content, .story-body, .article-body",
"#article-body, .post-body, .text-content",
];
// Extraction du contenu principal
for (const selector of contentSelectors) {
const elements = document.querySelectorAll(selector);
if (elements.length > 0) {
this.log(`Contenu trouvé avec: ${selector}`);
content += this.extractTextFromElements(elements, extractedTexts);
if (content.length > 1000) break;
}
}
// Fallback si contenu insuffisant
if (content.length < 300) {
this.log("Contenu insuffisant, utilisation de fallbacks...");
const fallbackSelectors = [
"p, h1, h2, h3, h4, h5, h6",
".text, .description, .summary",
'[class*="content"], [class*="text"]',
"blockquote, figcaption",
];
for (const selector of fallbackSelectors) {
const elements = document.querySelectorAll(selector);
content += this.extractTextFromElements(elements, extractedTexts, 30);
if (content.length > 1500) break;
}
}
// Dernier recours
if (content.length < 200) {
this.log("Dernier recours - texte visible");
const bodyText = this.cleanText(document.body.innerText);
content = bodyText.substring(0, this.settings.maxContentLength);
}
const finalContent = content
.substring(0, this.settings.maxContentLength)
.trim();
this.log(`Extraction terminée: ${finalContent.length} caractères`);
return finalContent;
}
extractTextFromElements(elements, extractedTexts, maxElements = 100) {
let text = "";
const elementsArray = Array.from(elements).slice(0, maxElements);
for (const element of elementsArray) {
if (this.shouldSkipElement(element)) continue;
const elementText = this.cleanText(
element.textContent || element.innerText
);
if (
elementText &&
elementText.length > 15 &&
!extractedTexts.has(elementText)
) {
extractedTexts.add(elementText);
text += elementText + " ";
if (text.length > this.settings.maxContentLength) break;
}
}
return text;
}
shouldSkipElement(element) {
const skipClasses = [
"nav",
"menu",
"footer",
"header",
"sidebar",
"ad",
"advertisement",
"social",
"share",
];
const skipIds = ["nav", "menu", "footer", "header", "sidebar", "comments"];
const className = element.className?.toLowerCase() || "";
const id = element.id?.toLowerCase() || "";
return (
skipClasses.some((skip) => className.includes(skip)) ||
skipIds.some((skip) => id.includes(skip)) ||
element.getAttribute("aria-hidden") === "true" ||
getComputedStyle(element).display === "none"
);
}
cleanText(text) {
if (!text) return "";
return text
.replace(/\s+/g, " ")
.replace(/[\r\n\t]/g, " ")
.replace(/[^\w\s\.,!?;:()\-'"%àâäéèêëïîôöùûüÿç]/gi, "")
.trim();
}
detectPageType() {
const url = window.location.href.toLowerCase();
if (
url.includes("news") ||
url.includes("article") ||
url.includes("actualit")
)
return "news";
if (url.includes("blog")) return "blog";
if (
url.includes("facebook") ||
url.includes("twitter") ||
url.includes("instagram")
)
return "social";
if (
url.includes("shop") ||
url.includes("buy") ||
url.includes("product") ||
url.includes("commerce")
)
return "commerce";
return "general";
}
}
// Make ContentExtractor available globally for Chrome extension
window.ContentExtractor = ContentExtractor;

Просмотреть файл

@ -0,0 +1,473 @@
// Technique Analyzer Module
// Responsible for analyzing manipulation techniques in text
class TechniqueAnalyzer {
constructor(
settings,
enhancedKeywords,
contextPatterns,
techniques,
pageType = "general"
) {
this.settings = settings || {
enhancedKeywords: true,
minKeywordLength: 3,
debugMode: false,
};
this.enhancedKeywords = enhancedKeywords;
this.contextPatterns = contextPatterns;
this.techniques = techniques;
this.pageType = pageType;
}
log(message, data = null) {
if (this.settings.debugMode) {
console.log(`TechniqueAnalyzer: ${message}`, data || "");
}
}
performAnalysis(title, content) {
const fullText = (title + " " + content).toLowerCase();
const detected = [];
let totalScore = 0;
const phaseScores = {};
this.log("Analyse du texte...", fullText.substring(0, 200));
// Analyser SEULEMENT les techniques (TE), pas les tactiques (TA)
const techniques = this.techniques.filter(
(item) => item.type === "technique"
);
for (const technique of techniques) {
const analysis = this.analyzeTechnique(technique, fullText);
if (analysis.score > 0) {
detected.push(analysis);
totalScore += analysis.weightedScore;
// Calcul par phase
if (!phaseScores[technique.phase]) {
phaseScores[technique.phase] = 0;
}
phaseScores[technique.phase] += analysis.weightedScore;
this.log(`Technique détectée: ${technique.index} (${analysis.score})`);
}
}
// Score global avec normalisation améliorée
const globalScore = Math.min(Math.round(totalScore * 3), 100);
return {
globalScore,
detectedTechniques: detected.sort(
(a, b) => b.weightedScore - a.weightedScore
),
phaseScores,
riskLevel: this.calculateRiskLevel(globalScore),
riskColor: this.getColor(globalScore),
url: window.location.href,
title: title.substring(0, 200),
contentLength: content.length,
analyzedText: fullText.length,
timestamp: new Date().toISOString(),
};
}
analyzeTechnique(technique, fullText) {
// Utiliser le système amélioré si disponible et activé
if (
this.settings.enhancedKeywords &&
this.enhancedKeywords[technique.index]
) {
return this.analyzeEnhancedTechnique(technique, fullText);
}
// Fallback vers l'ancienne méthode
return this.analyzeBasicTechnique(technique, fullText);
}
analyzeEnhancedTechnique(technique, fullText) {
const enhancedData = this.enhancedKeywords[technique.index];
const results = {
matches: [],
score: 0,
contextBoosts: [],
};
// 1. Analyse des mots-clés de base
if (enhancedData.core) {
const coreMatches = this.findKeywordMatches(
fullText,
enhancedData.core,
1.0
);
results.matches.push(...coreMatches);
}
// 2. Analyse des variantes
if (enhancedData.variants) {
for (const [category, variants] of Object.entries(
enhancedData.variants
)) {
if (Array.isArray(variants)) {
const weight = this.getVariantWeight(category);
const variantMatches = this.findKeywordMatches(
fullText,
variants,
weight
);
results.matches.push(
...variantMatches.map((m) => ({ ...m, category }))
);
} else if (typeof variants === "object") {
// Variantes avec sous-catégories (ex: intensity.strong)
for (const [subcat, subvariants] of Object.entries(variants)) {
const weight = this.getIntensityWeight(subcat);
const subMatches = this.findKeywordMatches(
fullText,
subvariants,
weight
);
results.matches.push(
...subMatches.map((m) => ({
...m,
category: `${category}.${subcat}`,
}))
);
}
}
}
}
// 3. Analyse des patterns regex
if (enhancedData.patterns) {
for (const pattern of enhancedData.patterns) {
const patternMatches = this.findPatternMatches(fullText, pattern);
results.matches.push(...patternMatches);
}
}
// 4. Analyse contextuelle
const contextBoosts = this.analyzeContext(fullText, technique.index);
results.contextBoosts = contextBoosts;
// 5. Calcul du score
results.score = results.matches.reduce(
(sum, match) => sum + match.weight,
0
);
// 6. Application des boosts contextuels
let finalScore = results.score;
for (const boost of contextBoosts) {
finalScore *= boost.boost;
}
// 7. Pondération contextuelle et dynamique
let contextualWeight = this.calculateContextualWeight(
technique,
this.pageType
);
let dynamicWeight = this.calculateDynamicWeight(technique, finalScore);
const totalWeight =
(technique.weight || 1.0) * contextualWeight * dynamicWeight;
const weightedScore = finalScore * totalWeight;
const confidence = Math.min(
Math.round(results.score * 15 + results.matches.length * 10),
100
);
return {
index: technique.index,
nom: technique.nom,
phase: technique.phase,
description: technique.description || "",
score: Math.round(finalScore),
weightedScore,
finalWeight: totalWeight,
contextualWeight,
dynamicWeight,
confidence,
matchedKeywords: this.formatEnhancedMatches(results.matches),
enhancedAnalysis: {
coreMatches: results.matches.filter((m) => m.type === "core").length,
variantMatches: results.matches.filter((m) => m.type === "variant")
.length,
patternMatches: results.matches.filter((m) => m.type === "pattern")
.length,
contextBoosts: results.contextBoosts,
},
};
}
analyzeBasicTechnique(technique, fullText) {
let score = 0;
const matchedKeywords = [];
for (const keyword of technique.mots_cles) {
if (keyword.length < this.settings.minKeywordLength) continue;
const keywordLower = keyword.toLowerCase();
const matches = this.findKeywordMatches(fullText, [keywordLower], 1.0);
if (matches.length > 0) {
score += matches.length;
matchedKeywords.push({
keyword,
count: matches.length,
type: "basic",
});
}
}
// Pondération contextuelle et dynamique
let contextualWeight = this.calculateContextualWeight(
technique,
this.pageType
);
let dynamicWeight = this.calculateDynamicWeight(technique, score);
const finalWeight =
(technique.weight || 1.0) * contextualWeight * dynamicWeight;
const weightedScore = score * finalWeight;
const confidence = Math.min(
Math.round(score * 15 + weightedScore * 5),
100
);
return {
index: technique.index,
nom: technique.nom,
phase: technique.phase,
description: technique.description || "",
score,
weightedScore,
finalWeight,
contextualWeight,
dynamicWeight,
confidence,
matchedKeywords,
};
}
findKeywordMatches(text, keywords, weight = 1.0) {
const matches = [];
for (const keyword of keywords) {
const keywordLower = keyword.toLowerCase();
let regex;
if (keywordLower.includes(" ")) {
// Expression avec espaces
regex = new RegExp(this.escapeRegex(keywordLower), "gi");
} else {
// Mot simple avec frontières
regex = new RegExp(
"\\b" + this.escapeRegex(keywordLower) + "\\b",
"gi"
);
}
let match;
while ((match = regex.exec(text)) !== null) {
matches.push({
type: "core",
keyword: keyword,
position: match.index,
weight: weight,
});
}
}
return matches;
}
findPatternMatches(text, pattern) {
const matches = [];
let match;
// Réinitialiser le regex pour éviter les problèmes de state
pattern.lastIndex = 0;
while ((match = pattern.exec(text)) !== null) {
matches.push({
type: "pattern",
keyword: match[0],
position: match.index,
weight: 1.5, // Les patterns ont un poids plus élevé
});
// Éviter les boucles infinies
if (!pattern.global) break;
}
return matches;
}
analyzeContext(text, techniqueId) {
const boosts = [];
for (const [contextType, contextData] of Object.entries(
this.contextPatterns
)) {
if (contextData.techniques.includes(techniqueId)) {
for (const pattern of contextData.patterns) {
if (pattern.test(text)) {
boosts.push({
type: contextType,
boost: contextData.boost,
pattern: pattern.source,
});
}
}
}
}
return boosts;
}
getVariantWeight(category) {
const weights = {
formal: 0.9,
informal: 1.1,
clickbait_formulas: 1.6,
emotional_hooks: 1.4,
curiosity_gaps: 1.5,
urgency: 1.3,
scarcity: 1.4,
temporal: 1.2,
};
return weights[category] || 1.0;
}
getIntensityWeight(intensity) {
const weights = {
weak: 0.7,
strong: 1.5,
};
return weights[intensity] || 1.0;
}
formatEnhancedMatches(matches) {
const grouped = {};
for (const match of matches) {
const key = match.keyword;
if (!grouped[key]) {
grouped[key] = {
keyword: key,
count: 0,
type: match.type,
category: match.category,
totalWeight: 0,
};
}
grouped[key].count++;
grouped[key].totalWeight += match.weight;
}
return Object.values(grouped);
}
escapeRegex(string) {
return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
calculateRiskLevel(score) {
if (score < 15) return "Faible";
if (score < 30) return "Modéré";
if (score < 50) return "Élevé";
if (score < 75) return "Très Élevé";
return "Critique";
}
calculateContextualWeight(technique, pageType) {
let contextualWeight = 1.0;
switch (pageType) {
case "news":
if (technique.index === "TE0500") contextualWeight = 1.4;
if (technique.index === "TE0132") contextualWeight = 1.3;
if (technique.index === "TE0221") contextualWeight = 1.5;
if (technique.index === "TE0212") contextualWeight = 1.3;
if (technique.index === "TE0261") contextualWeight = 0.8;
break;
case "social":
if (technique.index === "TE0132") contextualWeight = 0.9;
if (technique.index === "TE0131") contextualWeight = 0.8;
if (technique.index === "TE0501") contextualWeight = 1.3;
if (technique.index === "TE0221") contextualWeight = 1.6;
if (technique.index === "TE0251") contextualWeight = 1.2;
break;
case "commerce":
if (technique.index === "TE0501") contextualWeight = 0.9;
if (technique.index === "TE0141") contextualWeight = 0.8;
if (technique.index === "TE0143") contextualWeight = 0.7;
if (technique.index === "TE0422") contextualWeight = 1.2;
if (technique.index === "TE0411") contextualWeight = 1.1;
break;
case "blog":
if (technique.index === "TE0212") contextualWeight = 0.8;
if (technique.index === "TE0314") contextualWeight = 0.9;
if (technique.index === "TE0261") contextualWeight = 0.7;
if (technique.index === "TE0321") contextualWeight = 1.1;
break;
}
this.log(
`Poids contextuel pour ${technique.index} sur ${pageType}: ${contextualWeight}`
);
return contextualWeight;
}
calculateDynamicWeight(technique, occurrences) {
let dynamicWeight = 1.0;
// Plus une technique apparaît, plus elle devient suspecte
if (occurrences >= 10) {
dynamicWeight = 1.4;
} else if (occurrences >= 7) {
dynamicWeight = 1.3;
} else if (occurrences >= 5) {
dynamicWeight = 1.2;
} else if (occurrences >= 3) {
dynamicWeight = 1.1;
}
// Cas spéciaux : certaines techniques sont plus graves même avec peu d'occurrences
const criticalTechniques = ["TE0221", "TE0500", "TE0132", "TE0501"];
if (criticalTechniques.includes(technique.index) && occurrences >= 2) {
dynamicWeight *= 1.1;
}
// Réduire le poids si technique très fréquente mais bénigne
const benignTechniques = ["TE0143", "TE0232", "TE0333"];
if (benignTechniques.includes(technique.index) && occurrences >= 5) {
dynamicWeight *= 0.9;
}
this.log(
`Poids dynamique pour ${technique.index} (${occurrences} occ.): ${dynamicWeight}`
);
return dynamicWeight;
}
getColor(score) {
if (score < 15) return "#27ae60"; // Vert
if (score < 30) return "#f39c12"; // Orange clair
if (score < 50) return "#e67e22"; // Orange
if (score < 75) return "#d35400"; // Rouge-orange
return "#c0392b"; // Rouge foncé
}
}
// Make TechniqueAnalyzer available globally for Chrome extension
window.TechniqueAnalyzer = TechniqueAnalyzer;

Просмотреть файл

@ -0,0 +1,290 @@
// UI Manager Module
// Responsible for creating and managing the user interface elements
class UIManager {
constructor(settings) {
this.settings = settings || {
debugMode: false,
};
this.buttonCreated = false;
this.analysisResults = null;
this.pageType = 'general';
}
log(message, data = null) {
if (this.settings.debugMode) {
console.log(`UIManager: ${message}`, data || "");
}
}
setPageType(pageType) {
this.pageType = pageType;
}
createButton(analysisResults = null) {
if (analysisResults) {
this.analysisResults = analysisResults;
}
if (!this.analysisResults) {
console.error('DIMA: Aucun résultat d\'analyse disponible pour créer le bouton');
return;
}
try {
// Supprimer bouton existant
document.getElementById('dima-btn')?.remove();
if (this.buttonCreated) return;
const button = document.createElement('div');
button.id = 'dima-btn';
button.innerHTML = `
<div style="display: flex; align-items: center; gap: 8px;">
🧠
<span style="font-weight: bold;">${this.analysisResults.globalScore}</span>
<span style="font-size: 0.8em; opacity: 0.9;">${this.analysisResults.riskLevel}</span>
</div>
`;
button.style.cssText = `
position: fixed !important;
top: 20px !important;
right: 20px !important;
z-index: 999999 !important;
background: linear-gradient(135deg, ${this.analysisResults.riskColor}, ${this.adjustColor(this.analysisResults.riskColor, -20)}) !important;
color: white !important;
padding: 12px 16px !important;
border-radius: 25px !important;
cursor: pointer !important;
font-family: 'Segoe UI', Arial, sans-serif !important;
font-size: 14px !important;
box-shadow: 0 4px 15px rgba(0,0,0,0.2), 0 2px 5px rgba(0,0,0,0.1) !important;
border: 2px solid rgba(255,255,255,0.2) !important;
user-select: none !important;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1) !important;
backdrop-filter: blur(10px) !important;
`;
button.title = this.generateTooltip();
// Événements
button.addEventListener('click', () => this.showModal());
button.addEventListener('mouseenter', () => {
button.style.transform = 'scale(1.05) translateY(-2px)';
button.style.boxShadow = '0 6px 20px rgba(0,0,0,0.3), 0 4px 8px rgba(0,0,0,0.2)';
});
button.addEventListener('mouseleave', () => {
button.style.transform = 'scale(1) translateY(0)';
button.style.boxShadow = '0 4px 15px rgba(0,0,0,0.2), 0 2px 5px rgba(0,0,0,0.1)';
});
document.body?.appendChild(button);
this.buttonCreated = true;
this.log('Bouton créé avec succès');
} catch (error) {
console.error('DIMA: Erreur création bouton:', error);
}
}
adjustColor(color, amount) {
const num = parseInt(color.replace("#", ""), 16);
const amt = Math.round(2.55 * amount);
const R = (num >> 16) + amt;
const G = (num >> 8 & 0x00FF) + amt;
const B = (num & 0x0000FF) + amt;
return "#" + (0x1000000 + (R < 255 ? R < 1 ? 0 : R : 255) * 0x10000 +
(G < 255 ? G < 1 ? 0 : G : 255) * 0x100 +
(B < 255 ? B < 1 ? 0 : B : 255)).toString(16).slice(1);
}
generateTooltip() {
const techniques = this.analysisResults.detectedTechniques.slice(0, 3);
return `DIMA Score: ${this.analysisResults.globalScore} (${this.analysisResults.riskLevel})
${this.analysisResults.detectedTechniques.length} techniques détectées
${techniques.map(t => `${t.nom}`).join('\n')}
Contenu: ${this.analysisResults.contentLength} caractères`;
}
showModal() {
try {
this.log('Affichage du modal');
document.getElementById('dima-modal')?.remove();
const modal = document.createElement('div');
modal.id = 'dima-modal';
modal.style.cssText = `
position: fixed !important;
top: 0 !important;
left: 0 !important;
width: 100% !important;
height: 100% !important;
background: rgba(0,0,0,0.75) !important;
backdrop-filter: blur(5px) !important;
z-index: 9999999 !important;
display: flex !important;
align-items: center !important;
justify-content: center !important;
font-family: 'Segoe UI', Arial, sans-serif !important;
animation: fadeIn 0.3s ease-out !important;
`;
// Récupérer l'URL du logo
const logoUrl = chrome.runtime.getURL('M82-logo-16.png');
modal.innerHTML = `
<div style="background: white; padding: 30px; border-radius: 20px; max-width: 900px; max-height: 90vh; overflow-y: auto; margin: 20px; box-shadow: 0 25px 50px rgba(0,0,0,0.3); animation: slideIn 0.3s ease-out;">
<!-- En-tête -->
<div style="text-align: center; margin-bottom: 25px; padding-bottom: 20px; border-bottom: 2px solid #f0f0f0;">
<div style="display: flex; align-items: center; justify-content: center; gap: 12px; margin-bottom: 10px;">
<img src="${logoUrl}"
style="width: 24px; height: 24px;"
alt="M82 Project"
onerror="this.style.display='none'">
<h2 style="color: #2c3e50; margin: 0; font-size: 1.8em;">Analyse DIMA</h2>
</div>
<p style="color: #7f8c8d; margin: 0; font-size: 0.95em;">
Détection de techniques de manipulation cognitive par
<a href="https://m82-project.org/" target="_blank"
style="color: #3498db; text-decoration: none; font-weight: 500;">M82 Project</a>
</p>
</div>
<!-- Métriques principales -->
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 15px; margin-bottom: 25px;">
<div style="background: linear-gradient(135deg, ${this.analysisResults.riskColor}, ${this.adjustColor(this.analysisResults.riskColor, -15)}); color: white; padding: 20px; border-radius: 12px; text-align: center; box-shadow: 0 4px 15px rgba(0,0,0,0.1);">
<div style="font-size: 2.2em; font-weight: bold; margin-bottom: 5px;">${this.analysisResults.globalScore}</div>
<div style="font-size: 0.9em; opacity: 0.9;">Score Global</div>
</div>
<div style="background: #f8f9fa; padding: 20px; border-radius: 12px; text-align: center; border: 1px solid #e9ecef;">
<div style="font-size: 2.2em; font-weight: bold; color: #3498db; margin-bottom: 5px;">${this.analysisResults.detectedTechniques.length}</div>
<div style="color: #7f8c8d; font-size: 0.9em;">Techniques</div>
</div>
<div style="background: #f8f9fa; padding: 20px; border-radius: 12px; text-align: center; border: 1px solid #e9ecef;">
<div style="font-size: 1.4em; font-weight: bold; color: ${this.analysisResults.riskColor}; margin-bottom: 5px;">${this.analysisResults.riskLevel}</div>
<div style="color: #7f8c8d; font-size: 0.9em;">Niveau Risque</div>
</div>
<div style="background: #f8f9fa; padding: 20px; border-radius: 12px; text-align: center; border: 1px solid #e9ecef;">
<div style="font-size: 1.6em; font-weight: bold; color: #17a2b8; margin-bottom: 5px;">${this.analysisResults.contentLength}</div>
<div style="color: #7f8c8d; font-size: 0.9em;">Caractères</div>
</div>
</div>
<!-- Informations sur la page -->
<div style="background: #f8f9fa; padding: 20px; border-radius: 12px; margin-bottom: 25px; border: 1px solid #e9ecef;">
<h4 style="margin: 0 0 10px 0; color: #2c3e50; font-size: 1.1em;">📄 Page analysée</h4>
<div style="font-weight: 500; margin-bottom: 8px; line-height: 1.4;">${this.analysisResults.title}</div>
<div style="color: #666; font-size: 0.9em; word-break: break-all; margin-bottom: 8px;">${this.analysisResults.url}</div>
<div style="color: #888; font-size: 0.85em;">
Analysé le ${new Date(this.analysisResults.timestamp).toLocaleString('fr-FR')}
${this.analysisResults.analyzedText} caractères traités Type: ${this.pageType}
</div>
</div>
<!-- Message si aucune technique -->
${this.analysisResults.detectedTechniques.length === 0 ? `
<div style="background: linear-gradient(135deg, #d4edda, #c3e6cb); color: #155724; padding: 25px; border-radius: 12px; text-align: center; border: 1px solid #c3e6cb;">
<div style="font-size: 2em; margin-bottom: 10px;"></div>
<div style="font-size: 1.2em; font-weight: bold; margin-bottom: 8px;">Aucune manipulation détectée</div>
<div style="font-size: 0.95em; opacity: 0.8;">Le contenu analysé semble exempt de techniques de manipulation cognitive manifestes</div>
</div>
` : `
<div style="background: linear-gradient(135deg, #fff3cd, #ffeaa7); padding: 20px; border-radius: 12px; border: 1px solid #ffeaa7;">
<h4 style="margin: 0 0 20px 0; color: #856404; font-size: 1.2em;"> Techniques de manipulation détectées</h4>
<div style="display: grid; gap: 12px;">
${this.analysisResults.detectedTechniques.slice(0, 8).map(technique => `
<div style="background: white; padding: 16px; border-radius: 10px; border-left: 4px solid #e67e22; box-shadow: 0 2px 8px rgba(0,0,0,0.08);">
<div style="display: flex; justify-content: between; align-items: start; margin-bottom: 8px;">
<div style="flex: 1;">
<div style="font-weight: bold; color: #2c3e50; margin-bottom: 4px; font-size: 1.05em;">
${technique.phase === 'Detect' ? '👁️' : technique.phase === 'Informer' ? '📢' : technique.phase === 'Mémoriser' ? '🧠' : '⚡'} ${technique.index}: ${technique.nom}
</div>
${technique.tactic ? `<div style="font-size: 0.75em; color: #7f8c8d; margin-bottom: 8px;">↳ Tactique: ${technique.tactic}</div>` : ''}
${technique.description ? `<div style="color: #666; font-size: 0.9em; margin-bottom: 8px; line-height: 1.4;">${technique.description}</div>` : ''}
</div>
<span style="background: #27ae60; color: white; padding: 4px 8px; border-radius: 12px; font-size: 0.8em; font-weight: bold; margin-left: 15px;">
${technique.confidence}%
</span>
</div>
<div style="display: flex; justify-content: between; align-items: center; margin-bottom: 8px;">
<span style="background: #e67e22; color: white; padding: 3px 8px; border-radius: 6px; font-size: 0.8em; font-weight: 500;">
${technique.phase}
</span>
<div style="text-align: right; font-size: 0.75em; color: #7f8c8d;">
<div>Score pondéré: ${technique.weightedScore?.toFixed(1) || technique.score}</div>
</div>
</div>
${technique.matchedKeywords?.length > 0 ? `
<div style="margin-top: 10px;">
<div style="font-size: 0.85em; color: #666; margin-bottom: 6px; font-weight: 500;">
🔍 Mots-clés détectés:
</div>
<div style="display: flex; flex-wrap: wrap; gap: 4px;">
${technique.matchedKeywords.slice(0, 4).map(keyword =>
`<span style="background: #e9ecef; color: #495057; padding: 2px 6px; border-radius: 4px; font-size: 0.75em;">
${keyword.keyword} ${(keyword.count > 1) ? `(×${keyword.count})` : ''}
</span>`
).join('')}
${technique.matchedKeywords.length > 4 ?
`<span style="color: #999; font-size: 0.75em; padding: 2px 4px;">+${technique.matchedKeywords.length - 4} autres...</span>`
: ''
}
</div>
</div>
` : ''}
</div>
`).join('')}
</div>
</div>
`}
<!-- Actions -->
<div style="text-align: center; margin-top: 25px; padding-top: 20px; border-top: 1px solid #e9ecef;">
<div style="display: flex; gap: 15px; justify-content: center; flex-wrap: wrap;">
<button onclick="document.getElementById('dima-modal').remove()"
style="background: #3498db; color: white; border: none; padding: 12px 24px; border-radius: 8px; cursor: pointer; font-size: 16px; font-weight: 500; transition: background 0.3s;">
Fermer
</button>
<button onclick="window.open('https://diod.m82-project.org/', '_blank')"
style="background: #95a5a6; color: white; border: none; padding: 12px 24px; border-radius: 8px; cursor: pointer; font-size: 16px; font-weight: 500; transition: background 0.3s;">
En savoir plus
</button>
</div>
</div>
<style>
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
@keyframes slideIn {
from { transform: translateY(30px); opacity: 0; }
to { transform: translateY(0); opacity: 1; }
}
#dima-modal button:hover {
transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
}
</style>
</div>
`;
modal.addEventListener('click', (e) => {
if (e.target === modal) modal.remove();
});
document.body.appendChild(modal);
this.log('Modal affiché');
} catch (error) {
console.error('DIMA: Erreur modal:', error);
}
}
}
// Make UIManager available globally for Chrome extension
window.UIManager = UIManager;