Этот коммит содержится в:
BartM82 2025-06-27 22:48:21 +02:00 коммит произвёл GitHub
родитель 494bff77d2
Коммит 9168e24519
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194

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

@ -1,266 +1,411 @@
// Base de données DIMA bilingue Français-Anglais // Plugin DIMA - Version simplifiée et robuste
const DIMA_TECHNIQUES = [ const DIMA_TECHNIQUES = [
// PHASE DETECTER
{ {
index: "TE011", index: "TE0111",
nom: "Heuristique de disponibilité / Availability Heuristic", nom: "Heuristique de disponibilité",
description: "Biais cognitif basé sur un exemple récent facilement accessible",
phase: "Detect", phase: "Detect",
mots_cles: ["récent", "recently", "exemple", "example", "cas", "case", "histoire vraie", "true story"] mots_cles: ["récent", "recently", "exemple", "example", "cas", "case", "témoignage", "testimony"]
}, },
{ {
index: "TE013", index: "TE0112",
nom: "Biais de négativité / Negativity Bias", nom: "Effet de simple exposition",
description: "Tendance à accorder plus d'attention aux expériences négatives",
phase: "Detect", phase: "Detect",
mots_cles: ["catastrophe", "danger", "menace", "threat", "risque", "risk", "grave", "serious", "dramatique", "dramatic", "terrible", "crisis", "alarming"] mots_cles: ["encore", "again", "toujours", "always", "répétition", "repetition", "familier", "familiar"]
}, },
{ {
index: "TE014", index: "TE0121",
nom: "Effet von Restorff / Von Restorff Effect", nom: "Illusion de la fréquence",
description: "Un objet qui se détache des autres est plus susceptible d'être retenu", phase: "Detect",
phase: "Detect", mots_cles: ["partout", "everywhere", "de plus en plus", "more and more", "fréquent", "frequent", "épidémie", "epidemic"]
mots_cles: ["unique", "seul", "only", "exclusif", "exclusive", "différent", "different", "spécial", "special", "exceptionnel", "exceptional", "rare"]
}, },
{ {
index: "TE050", index: "TE0131",
nom: "Clickbait / Appât à clics", nom: "Effet de bizarrerie",
description: "Titres sensationnalistes conçus pour attirer les clics",
phase: "Detect", phase: "Detect",
mots_cles: ["vous ne croirez pas", "you won't believe", "ce qui arrive ensuite", "what happens next", "secret", "astuce", "trick", "révélé", "revealed", "shocking", "mind-blowing", "choc", "incroyable", "incredible"] mots_cles: ["étrange", "strange", "bizarre", "weird", "incroyable", "incredible", "choquant", "shocking", "inhabituel", "unusual"]
}, },
{ {
index: "TE022", index: "TE0132",
nom: "Stéréotype / Stereotype", nom: "Biais de négativité",
description: "Généralisation simpliste sur un groupe", phase: "Detect",
mots_cles: ["catastrophe", "disaster", "danger", "menace", "threat", "risque", "risk", "grave", "serious", "crise", "crisis"]
},
{
index: "TE0141",
nom: "Effet von Restorff",
phase: "Detect",
mots_cles: ["unique", "seul", "only", "exclusif", "exclusive", "spécial", "special", "exceptionnel", "exceptional", "rare"]
},
{
index: "TE0142",
nom: "Biais d'ancrage",
phase: "Detect",
mots_cles: ["première fois", "first time", "jamais vu", "never seen", "inédit", "unprecedented", "révélation", "revelation"]
},
{
index: "TE0500",
nom: "Clickbait",
phase: "Detect",
mots_cles: ["vous ne croirez pas", "you won't believe", "ce qui arrive ensuite", "what happens next", "secret", "shocking", "mind-blowing", "amazing"]
},
// PHASE INFORMER
{
index: "TE0221",
nom: "Stéréotypes",
phase: "Informer", phase: "Informer",
mots_cles: ["tous les", "all the", "les français", "americans", "les jeunes", "young people", "en général", "in general", "toujours", "always", "jamais", "never", "everyone", "nobody"] mots_cles: ["tous les", "all the", "toujours", "always", "jamais", "never", "en général", "in general", "les français", "americans"]
}, },
{ {
index: "TE024", index: "TE0241",
nom: "Simplification excessive / Oversimplification", nom: "Simplification excessive",
description: "Réduction d'une situation complexe à des termes simples", phase: "Informer",
mots_cles: ["simple", "évident", "obvious", "clair", "clear", "facile", "easy", "suffit de", "just need to", "solution"]
},
{
index: "TE0251",
nom: "Faux consensus",
phase: "Informer", phase: "Informer",
mots_cles: ["simple", "évident", "obvious", "clair", "clear", "facile", "easy", "suffit de", "just need to", "il n'y a qu'à", "all you have to", "solution", "simply"] mots_cles: ["tout le monde", "everyone", "la plupart", "most people", "nous pensons", "we think", "consensus", "accord"]
}, },
{ {
index: "TE031", index: "TE0261",
nom: "Biais de confirmation / Confirmation Bias", nom: "Biais rétrospectif",
description: "Privilégier les informations qui confirment ses croyances", phase: "Informer",
mots_cles: ["j'avais dit", "i told you", "prévisible", "predictable", "on aurait dû", "should have", "signes", "signs"]
},
// PHASE MEMORISER
{
index: "TE0321",
nom: "Biais de confirmation",
phase: "Mémoriser", phase: "Mémoriser",
mots_cles: ["confirme", "confirms", "prouve", "proves", "démontre", "demonstrates", "comme prévu", "as expected", "j'avais raison", "i was right", "évident", "obvious", "validates"] mots_cles: ["confirme", "confirms", "prouve", "proves", "comme prévu", "as expected", "j'avais raison", "i was right", "évident", "obvious"]
}, },
{ {
index: "TE051", index: "TE0331",
nom: "FOMO - Fear of Missing Out", nom: "Effet de récence",
description: "Peur de rater quelque chose d'important", phase: "Mémoriser",
mots_cles: ["récent", "recent", "dernier", "last", "nouveau", "new", "frais", "fresh", "actuel", "current"]
},
{
index: "TE0333",
nom: "Effet de primauté",
phase: "Mémoriser",
mots_cles: ["premier", "first", "initial", "début", "beginning", "origine", "origin", "primordial"]
},
// PHASE AGIR
{
index: "TE0411",
nom: "Excès de confiance",
phase: "Act", phase: "Act",
mots_cles: ["ne ratez pas", "don't miss", "dernière chance", "last chance", "limité", "limited", "exclusif", "exclusive", "bientôt fini", "ending soon", "hurry", "while supplies last"] mots_cles: ["confiant", "confident", "sûr", "sure", "certain", "capable", "expert", "maîtrise", "mastery"]
},
{
index: "TE0421",
nom: "Coûts irrécupérables",
phase: "Act",
mots_cles: ["continuer", "continue", "persister", "persist", "investir plus", "invest more", "ne pas abandonner", "don't give up"]
},
{
index: "TE0422",
nom: "Biais d'autorité",
phase: "Act",
mots_cles: ["autorité", "authority", "expert", "spécialiste", "specialist", "professeur", "professor", "docteur", "doctor", "officiel"]
},
{
index: "TE0432",
nom: "Biais du statu quo",
phase: "Act",
mots_cles: ["rester", "stay", "maintenir", "maintain", "ne pas changer", "don't change", "status quo", "comme ça", "as is"]
},
{
index: "TE0501",
nom: "FOMO",
phase: "Act",
mots_cles: ["ne ratez pas", "don't miss", "dernière chance", "last chance", "limité", "limited", "exclusif", "exclusive", "hurry"]
} }
]; ];
class DIMAAnalyzer { class DIMAAnalyzer {
constructor() { constructor() {
this.analysisResults = null; this.analysisResults = null;
this.buttonCreated = false;
this.init(); this.init();
} }
init() { init() {
console.log('DIMA: Initialisation...');
// Attendre que la page soit prête
if (document.readyState === 'loading') { if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', () => { document.addEventListener('DOMContentLoaded', () => {
setTimeout(() => this.analyzeCurrentPage(), 1000); this.delayedInit();
}); });
} else { } else {
setTimeout(() => this.analyzeCurrentPage(), 1000); this.delayedInit();
} }
} }
delayedInit() {
// Attendre un peu plus pour que la page soit complètement chargée
setTimeout(() => {
try {
this.analyzeCurrentPage();
} catch (error) {
console.error('DIMA: Erreur lors de l\'analyse:', error);
}
}, 3000);
}
analyzeCurrentPage() { analyzeCurrentPage() {
try { try {
console.log('DIMA: Analyse de la page...');
const title = document.title || ''; const title = document.title || '';
const paragraphs = Array.from(document.querySelectorAll('p, article p, .content p, .article p, h1, h2')) const textElements = document.querySelectorAll('p, h1, h2, h3, article, .content, .article-content');
.slice(0, 8) let content = '';
.map(p => p.textContent || p.innerText || '')
.join(' ') // Extraire le texte de manière sécurisée
.substring(0, 1500); for (let i = 0; i < Math.min(textElements.length, 10); i++) {
const element = textElements[i];
this.analysisResults = this.performDIMAAnalysis(title, paragraphs); if (element && element.textContent) {
this.createFloatingButton(); content += element.textContent + ' ';
}
}
content = content.substring(0, 1500);
console.log('DIMA: Texte extrait:', content.length, 'caractères');
this.analysisResults = this.performAnalysis(title, content);
console.log('DIMA: Analyse terminée, score:', this.analysisResults.globalScore);
this.createButton();
} catch (error) { } catch (error) {
console.log('DIMA: Erreur lors de l\'analyse de la page:', error); console.error('DIMA: Erreur dans analyzeCurrentPage:', error);
} }
} }
performDIMAAnalysis(title, content) { performAnalysis(title, content) {
const text = (title + ' ' + content).toLowerCase(); const fullText = (title + ' ' + content).toLowerCase();
const detectedTechniques = []; const detected = [];
const phaseScores = { let totalScore = 0;
'Detect': 0,
'Informer': 0, console.log('DIMA: Analyse du texte...');
'Mémoriser': 0,
'Act': 0
};
DIMA_TECHNIQUES.forEach(technique => { DIMA_TECHNIQUES.forEach(technique => {
let score = 0; let score = 0;
technique.mots_cles.forEach(motCle => { const matchedKeywords = [];
try {
const escapedMotCle = motCle.toLowerCase().replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); technique.mots_cles.forEach(keyword => {
const regex = new RegExp('\\b' + escapedMotCle + '\\b', 'gi'); if (fullText.includes(keyword.toLowerCase())) {
const matches = text.match(regex); score++;
if (matches) { matchedKeywords.push(keyword);
score += matches.length;
}
} catch (e) {
if (text.includes(motCle.toLowerCase())) {
score += 1;
}
} }
}); });
if (score > 0) { if (score > 0) {
detectedTechniques.push({ detected.push({
...technique, index: technique.index,
nom: technique.nom,
phase: technique.phase,
score: score, score: score,
confidence: Math.min(score * 20, 100) confidence: Math.min(score * 20, 100),
matchedKeywords: matchedKeywords
}); });
phaseScores[technique.phase] += score; totalScore += score;
} }
}); });
const totalScore = Object.values(phaseScores).reduce((a, b) => a + b, 0);
const globalScore = Math.min(totalScore * 4, 100); const globalScore = Math.min(totalScore * 4, 100);
return { const result = {
globalScore, globalScore: globalScore,
detectedTechniques, detectedTechniques: detected,
phaseScores, riskLevel: globalScore < 25 ? 'Faible' : globalScore < 50 ? 'Modéré' : globalScore < 75 ? 'Élevé' : 'Critique',
riskLevel: globalScore < 25 ? 'Faible' : globalScore < 50 ? 'Modéré' : 'Élevé',
analyzedAt: new Date().toISOString(),
url: window.location.href, url: window.location.href,
title: title title: title
}; };
console.log('DIMA: Résultats:', result);
return result;
} }
createFloatingButton() { createButton() {
const existing = document.getElementById('dima-floating-btn'); try {
if (existing) { // Supprimer l'ancien bouton s'il existe
existing.remove(); const existing = document.getElementById('dima-btn');
} if (existing) {
existing.remove();
}
const button = document.createElement('div'); if (this.buttonCreated) {
button.id = 'dima-floating-btn'; console.log('DIMA: Bouton déjà créé');
return;
const scoreColor = this.getScoreColor(this.analysisResults.globalScore); }
button.style.cssText = ` const button = document.createElement('div');
position: fixed !important; button.id = 'dima-btn';
top: 20px !important; button.innerHTML = `🧠 ${this.analysisResults.globalScore}`;
right: 20px !important;
z-index: 999999 !important; // Style du bouton
background: linear-gradient(135deg, ${scoreColor}, #c0392b) !important; button.style.cssText = `
color: white !important; position: fixed !important;
padding: 12px 16px !important; top: 20px !important;
border-radius: 25px !important; right: 20px !important;
cursor: pointer !important; z-index: 999999 !important;
box-shadow: 0 4px 15px rgba(0,0,0,0.2) !important; background: ${this.getColor(this.analysisResults.globalScore)} !important;
font-family: 'Segoe UI', Arial, sans-serif !important; color: white !important;
font-size: 14px !important; padding: 12px 16px !important;
font-weight: 600 !important; border-radius: 20px !important;
transition: all 0.2s !important; cursor: pointer !important;
user-select: none !important; font-family: Arial, sans-serif !important;
border: 2px solid rgba(255,255,255,0.2) !important; font-size: 14px !important;
text-align: center !important; font-weight: bold !important;
min-width: 80px !important; box-shadow: 0 4px 12px rgba(0,0,0,0.3) !important;
`; border: 2px solid rgba(255,255,255,0.3) !important;
user-select: none !important;
button.innerHTML = `🧠 DIMA: ${this.analysisResults.globalScore}<br><small style="font-size: 10px;">${this.analysisResults.riskLevel}</small>`; transition: transform 0.2s !important;
`;
button.addEventListener('click', () => this.showResults());
button.title = 'Cliquez pour voir l\'analyse DIMA détaillée'; button.title = `DIMA Score: ${this.analysisResults.globalScore} - ${this.analysisResults.detectedTechniques.length} techniques détectées`;
if (document.body) { // Events
document.body.appendChild(button); button.addEventListener('click', () => {
this.showModal();
});
button.addEventListener('mouseenter', () => {
button.style.transform = 'scale(1.05)';
});
button.addEventListener('mouseleave', () => {
button.style.transform = 'scale(1)';
});
// Ajouter le bouton au DOM
if (document.body) {
document.body.appendChild(button);
this.buttonCreated = true;
console.log('DIMA: Bouton créé avec succès');
} else {
console.error('DIMA: document.body non disponible');
}
} catch (error) {
console.error('DIMA: Erreur lors de la création du bouton:', error);
} }
} }
getScoreColor(score) { getColor(score) {
if (score < 25) return '#27ae60'; if (score < 25) return '#27ae60';
if (score < 50) return '#f39c12'; if (score < 50) return '#f39c12';
if (score < 75) return '#e67e22';
return '#e74c3c'; return '#e74c3c';
} }
showResults() { showModal() {
const existing = document.getElementById('dima-modal'); try {
if (existing) existing.remove(); console.log('DIMA: Affichage du modal');
// Supprimer modal existant
const existing = document.getElementById('dima-modal');
if (existing) {
existing.remove();
}
const modal = document.createElement('div'); const modal = document.createElement('div');
modal.id = 'dima-modal'; modal.id = 'dima-modal';
modal.style.cssText = ` modal.style.cssText = `
position: fixed !important; position: fixed !important;
top: 0 !important; top: 0 !important;
left: 0 !important; left: 0 !important;
width: 100% !important; width: 100% !important;
height: 100% !important; height: 100% !important;
background: rgba(0,0,0,0.8) !important; background: rgba(0,0,0,0.8) !important;
z-index: 10000000 !important; z-index: 9999999 !important;
display: flex !important; display: flex !important;
align-items: center !important; align-items: center !important;
justify-content: center !important; justify-content: center !important;
font-family: 'Segoe UI', Arial, sans-serif !important; font-family: Arial, sans-serif !important;
padding: 20px !important; `;
box-sizing: border-box !important;
`; modal.innerHTML = `
<div style="background: white; padding: 30px; border-radius: 15px; max-width: 600px; max-height: 80vh; overflow-y: auto; margin: 20px; box-shadow: 0 20px 40px rgba(0,0,0,0.3);">
modal.innerHTML = ` <div style="text-align: center; margin-bottom: 20px;">
<div style="background: white; border-radius: 15px; padding: 30px; max-width: 600px; max-height: 80vh; overflow-y: auto; box-shadow: 0 20px 40px rgba(0,0,0,0.3);"> <h2 style="color: #2c3e50; margin: 0 0 10px 0;">🧠 Analyse DIMA</h2>
<div style="text-align: center; margin-bottom: 20px;"> <p style="color: #7f8c8d; margin: 0;">Détection de manipulation cognitive</p>
<h2 style="color: #2c3e50; margin: 0 0 10px 0;">🧠 Analyse DIMA</h2>
<p style="color: #7f8c8d; margin: 0;">Détection de manipulation cognitive</p>
</div>
<div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 15px; margin-bottom: 20px;">
<div style="background: #f8f9fa; padding: 15px; border-radius: 8px; text-align: center;">
<div style="font-size: 1.8em; font-weight: bold; color: ${this.getScoreColor(this.analysisResults.globalScore)};">${this.analysisResults.globalScore}</div>
<div style="color: #7f8c8d; font-size: 0.9em;">Score</div>
</div> </div>
<div style="background: #f8f9fa; padding: 15px; border-radius: 8px; text-align: center;">
<div style="font-size: 1.8em; font-weight: bold; color: #3498db;">${this.analysisResults.detectedTechniques.length}</div> <div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 15px; margin-bottom: 20px;">
<div style="color: #7f8c8d; font-size: 0.9em;">Techniques</div> <div style="background: #f8f9fa; padding: 15px; border-radius: 8px; text-align: center;">
<div style="font-size: 2em; font-weight: bold; color: ${this.getColor(this.analysisResults.globalScore)};">${this.analysisResults.globalScore}</div>
<div style="color: #7f8c8d; font-size: 0.9em;">Score</div>
</div>
<div style="background: #f8f9fa; padding: 15px; border-radius: 8px; text-align: center;">
<div style="font-size: 2em; font-weight: bold; color: #3498db;">${this.analysisResults.detectedTechniques.length}</div>
<div style="color: #7f8c8d; font-size: 0.9em;">Techniques</div>
</div>
<div style="background: #f8f9fa; padding: 15px; border-radius: 8px; text-align: center;">
<div style="font-size: 1.2em; font-weight: bold; color: ${this.getColor(this.analysisResults.globalScore)};">${this.analysisResults.riskLevel}</div>
<div style="color: #7f8c8d; font-size: 0.9em;">Risque</div>
</div>
</div> </div>
<div style="background: #f8f9fa; padding: 15px; border-radius: 8px; text-align: center;">
<div style="font-size: 1.2em; font-weight: bold; color: ${this.getScoreColor(this.analysisResults.globalScore)};">${this.analysisResults.riskLevel}</div> <div style="background: #f8f9fa; padding: 15px; border-radius: 8px; margin-bottom: 20px;">
<div style="color: #7f8c8d; font-size: 0.9em;">Risque</div> <strong>Page analysée:</strong><br>
${this.analysisResults.title}<br>
<small style="color: #666; word-break: break-all;">${this.analysisResults.url}</small>
</div>
${this.generateTechniquesFound()}
<div style="text-align: center; margin-top: 20px;">
<button onclick="document.getElementById('dima-modal').remove()"
style="background: #3498db; color: white; border: none; padding: 12px 24px; border-radius: 6px; cursor: pointer; font-size: 16px;">
Fermer
</button>
</div> </div>
</div> </div>
`;
${this.generateTechniquesFound()}
// Event pour fermer en cliquant à l'extérieur
<div style="text-align: center; margin-top: 20px;"> modal.addEventListener('click', (e) => {
<button onclick="this.closest('#dima-modal').remove()" style="background: #3498db; color: white; border: none; padding: 10px 20px; border-radius: 5px; cursor: pointer;">Fermer</button> if (e.target === modal) {
</div> modal.remove();
</div> }
`; });
modal.addEventListener('click', (e) => { document.body.appendChild(modal);
if (e.target === modal) modal.remove(); console.log('DIMA: Modal affiché');
});
} catch (error) {
document.body.appendChild(modal); console.error('DIMA: Erreur lors de l\'affichage du modal:', error);
}
} }
generateTechniquesFound() { generateTechniquesFound() {
if (this.analysisResults.detectedTechniques.length === 0) { if (this.analysisResults.detectedTechniques.length === 0) {
return `<div style="background: #d4edda; color: #155724; padding: 15px; border-radius: 8px; text-align: center;">✅ Aucune manipulation détectée</div>`; return `
<div style="background: #d4edda; color: #155724; padding: 15px; border-radius: 8px; text-align: center;">
Aucune manipulation détectée
</div>
`;
} }
return ` return `
<div style="background: #f8d7da; color: #721c24; padding: 15px; border-radius: 8px;"> <div style="background: #fff3cd; color: #856404; padding: 15px; border-radius: 8px;">
<h4 style="margin: 0 0 10px 0;"> Techniques détectées :</h4> <h4 style="margin: 0 0 15px 0;"> Techniques détectées:</h4>
${this.analysisResults.detectedTechniques.map(t => ` ${this.analysisResults.detectedTechniques.map(technique => `
<div style="background: white; padding: 10px; margin: 5px 0; border-radius: 5px; border-left: 3px solid #e74c3c;"> <div style="background: white; padding: 10px; margin: 8px 0; border-radius: 5px; border-left: 3px solid #ffc107;">
<strong>${t.index}:</strong> ${t.nom}<br> <strong>${technique.index}:</strong> ${technique.nom}<br>
<small>Confiance: ${t.confidence}%</small> <small>Phase: ${technique.phase} | Confiance: ${technique.confidence}%</small>
${technique.matchedKeywords.length > 0 ? `<br><small style="color: #666;">Mots-clés: ${technique.matchedKeywords.slice(0, 3).join(', ')}${technique.matchedKeywords.length > 3 ? '...' : ''}</small>` : ''}
</div> </div>
`).join('')} `).join('')}
</div> </div>
@ -268,9 +413,11 @@ class DIMAAnalyzer {
} }
} }
// Initialiser l'analyseur // Initialisation sécurisée
console.log('DIMA: Script chargé');
try { try {
new DIMAAnalyzer(); new DIMAAnalyzer();
} catch (error) { } catch (error) {
console.log('DIMA: Erreur d\'initialisation:', error); console.error('DIMA: Erreur d\'initialisation:', error);
} }