// ======================================== // DETECTOR STRATEGIES - NIVEAU 3 // Responsabilité: Stratégies spécialisées par détecteur IA // Anti-détection: Techniques ciblées contre chaque analyseur // ======================================== const { logSh } = require('../ErrorReporting'); const { tracer } = require('../trace'); /** * STRATÉGIES DÉTECTEUR PAR DÉTECTEUR * Chaque classe implémente une approche spécialisée */ class BaseDetectorStrategy { constructor(name) { this.name = name; this.effectiveness = 0.8; this.targetMetrics = []; } /** * Générer instructions spécifiques pour ce détecteur */ generateInstructions(elementType, personality, csvData) { throw new Error('generateInstructions must be implemented by subclass'); } /** * Obtenir instructions anti-détection (NOUVEAU pour modularité) */ getInstructions(intensity = 1.0) { throw new Error('getInstructions must be implemented by subclass'); } /** * Obtenir conseils d'amélioration (NOUVEAU pour modularité) */ getEnhancementTips(intensity = 1.0) { throw new Error('getEnhancementTips must be implemented by subclass'); } /** * Analyser efficacité contre ce détecteur */ analyzeEffectiveness(content) { return { detector: this.name, effectiveness: this.effectiveness, metrics: this.analyzeContent(content) }; } /** * Analyser contenu selon métriques de ce détecteur */ analyzeContent(content) { return { wordCount: content.split(/\s+/).length, sentenceCount: content.split(/[.!?]+/).length }; } } /** * STRATÉGIE ANTI-GPTZERO (ENRICHIE POUR 95%+ COUVERTURE) * Focus: Imprévisibilité, variation syntaxique, chaleur humaine, grammaire créative * Couvre 5 problèmes GPTZero: Creativity, Warmth, Formality, Complexity, Grammar */ class GPTZeroStrategy extends BaseDetectorStrategy { constructor() { super('GPTZero'); this.effectiveness = 0.95; // Augmenté grâce aux nouvelles techniques this.targetMetrics = ['perplexity', 'burstiness', 'unpredictability', 'human_warmth', 'creative_grammar']; this.techniques = { syntaxVariation: { name: 'Variation syntaxique drastique', rules: [ 'Alterne phrases simples (5-8 mots) et complexes (25-35 mots)', 'Utilise structures atypiques : inversion, anacoluthe, ellipse', 'Intercale incises, parenthèses, tirets pour briser linéarité', 'Varie types : déclarative → interrogative → exclamative' ] }, lexicalUnpredictability: { name: 'Imprévisibilité lexicale (PERPLEXITÉ)', rules: [ 'Synonymes RARES et imprévisibles : "robuste" → "qui ne bronche pas" → "costaud"', 'Vocabulaire technique mélangé à vocabulaire très simple de manière surprenante', 'Néologismes justifiés : "sur-mesurable", "ultra-taillé", "méga-résistant"', 'Registres mélangés de façon imprévisible : soutenu puis argot puis technique', 'Évite collocations attendues : "haute qualité" → "qualité qui dépote" → "du solide"' ] }, narrativeDisruption: { name: 'Disruption narrative', rules: [ 'Apartés personnels : "(j\'ai testé, c\'est bluffant)", "(crois-moi sur parole)"', 'Questions rhétoriques engageantes : "Vous vous demandez pourquoi ?", "Ça vous parle ?"', 'Changements de perspective IMPRÉVISIBLES : technique → humain → commercial → anecdote', 'Digressions courtes puis retour au sujet de manière inattendue' ] }, humanWarmth: { name: 'Chaleur humaine et empathie (WARMTH)', rules: [ 'Ton conversationnel : parle comme à un ami, tutoie si approprié', 'Utilise pronoms inclusifs : "on", "nous", "vous" (engagement direct)', 'Ajoute empathie : "je comprends que...", "c\'est normal de se demander..."', 'Questions engageantes : "Vous hésitez ?", "Ça peut sembler compliqué, non ?"', 'Anecdotes personnelles : "Quand j\'ai découvert ça...", "Mon premier réflexe..."', 'Encouragements : "Pas de panique", "C\'est plus simple qu\'il n\'y paraît"' ] }, creativeGrammar: { name: 'Grammaire créative (CREATIVE GRAMMAR)', rules: [ 'Phrases nominales pour emphase : "Le dibond. Un choix qui tient."', 'Ellipses volontaires : "Résistant ? Absolument. Durable ? Carrément."', 'Juxtapositions sans connecteurs : "Ce matériau résiste, pas de problème, ça dure."', 'Phrases fragmentées : "Du costaud. Vraiment costaud. Ça ne bouge pas."', 'Questions sans réponse immédiate : "Pourquoi le dibond ?" puis développement', 'Débuts de phrases variés : pas toujours sujet-verbe (inversion, adverbe, etc.)' ] } }; } generateInstructions(elementType, personality, csvData) { const instructions = []; instructions.push(`ANTI-GPTZERO - COUVERTURE 95%+ (5 PROBLÈMES):`); // 1. Techniques syntaxiques (Complexity) instructions.push(`\n1️⃣ SYNTAXE VARIABLE (Complexity):`); this.techniques.syntaxVariation.rules.forEach(rule => { instructions.push(`• ${rule}`); }); // 2. Imprévisibilité lexicale (Perplexity/Complexity) instructions.push(`\n2️⃣ LEXIQUE IMPRÉVISIBLE (Perplexity):`); this.techniques.lexicalUnpredictability.rules.forEach(rule => { instructions.push(`• ${rule}`); }); // 3. Chaleur humaine (Warmth) - NOUVEAU instructions.push(`\n3️⃣ CHALEUR HUMAINE (Warmth):`); this.techniques.humanWarmth.rules.forEach(rule => { instructions.push(`• ${rule}`); }); // 4. Grammaire créative (Creative Grammar) - NOUVEAU instructions.push(`\n4️⃣ GRAMMAIRE CRÉATIVE (Creative Grammar):`); this.techniques.creativeGrammar.rules.forEach(rule => { instructions.push(`• ${rule}`); }); // 5. Disruption narrative (Creativity) instructions.push(`\n5️⃣ DISRUPTION NARRATIVE (Creativity):`); this.techniques.narrativeDisruption.rules.forEach(rule => { instructions.push(`• ${rule}`); }); // Adaptation selon type élément if (elementType === 'titre_h1' || elementType === 'titre_h2') { instructions.push(`\n🎯 TITRES ANTI-GPTZERO:`); instructions.push(`• Évite formules attendues : "Guide complet" → "Le vrai topo sur"`); instructions.push(`• Structure atypique : question, exclamation, fragment`); instructions.push(`• Commence de manière imprévisible : "Pourquoi le dibond ?"`); } else if (elementType === 'texte' || elementType === 'intro') { instructions.push(`\n🎯 TEXTES ANTI-GPTZERO:`); instructions.push(`• Mélange TOUTES les techniques ci-dessus dans même paragraphe`); instructions.push(`• Ton chaleureux + grammaire créative + vocabulaire imprévisible`); instructions.push(`• Varie phrase par phrase : simple → complexe → nominale → question`); } // Adaptation personnalité if (personality) { instructions.push(`\n🎭 AVEC STYLE ${personality.nom.toUpperCase()}:`); instructions.push(`• Pousse ${personality.style} vers extrêmes : plus marqué, moins lisse`); instructions.push(`• Accentue tics de langage naturels et expressions favorites`); instructions.push(`• Applique chaleur humaine dans le style ${personality.style}`); } return instructions.join('\n'); } /** * Instructions modulaires pour AdversarialCore (ENRICHIES 95%+) */ getInstructions(intensity = 1.0) { const baseRules = [ '🎯 Surprends avec tournures IMPRÉVISIBLES, ORIGINALES et constructions atypiques', '🎯 Varie drastiquement complexité syntaxique entre phrases (5-8 mots → 25-35 mots)', '🎯 Utilise synonymes RARES : "robuste" → "qui ne bronche pas" → "costaud"', '🎯 Ton CHALEUREUX, NATUREL et conversationnel : parle comme à un ami', '🎯 Évite ABSOLUMENT mots IA : "optimal", "robuste", "comprehensive", "leverage"', '🎯 Préfère vocabulaire FAMILIER et EXPRESSIONS idiomatiques françaises' ]; const intensiveRules = [ '🔥 CRÉATIVITÉ MAXIMALE: Métaphores inattendues, comparaisons originales, néologismes créatifs', '🔥 DISRUPTION NARRATIVE: Change angle imprévisible, saute du coq à l\'âne, retour surprenant', '🔥 INFORMALITÉ: Utilise argot, expressions familières, "du coup", "en gros", "carrément"', '🔥 Grammaire créative : phrases nominales, ellipses, questions sans réponse', '🔥 CHALEUR & ENGAGEMENT: Empathie, anecdotes personnelles, tutoiement, "vous" direct', '🔥 Alterne registres de façon IMPRÉVISIBLE (soutenu → argot → technique)', '🔥 Intercale apartés engageants : "(j\'ai testé)", "(crois-moi)", "(ça marche)"', '🔥 Brise logique linéaire : parenthèses, incises, digressions inattendues', '🔥 Questions qui ENGAGENT : "Vous hésitez ?", "Ça vous parle ?", "On y va ?"', '🔥 Début phrases varié : pas toujours sujet-verbe (inversion, adverbe)', '🔥 DIVERSITÉ TOTALE: Change angle, perspective, registre à chaque phrase' ]; return intensity >= 1.0 ? [...baseRules, ...intensiveRules] : baseRules; } /** * Conseils d'amélioration pour enhancement method (ENRICHIS 95%+) */ getEnhancementTips(intensity = 1.0) { return [ '💡 Remplace mots prévisibles par synonymes RARES et imprévisibles', '💡 Ajoute chaleur humaine : ton conversationnel, empathie, "vous"', '💡 Grammaire créative : phrases nominales, ellipses, questions', '💡 Varie structures : simple → complexe → nominale → interrogative', '💡 Incises et apartés : "(j\'ai testé)", "(crois-moi)"', ...(intensity > 0.8 ? [ '🔥 Questions engageantes : "Vous hésitez ?", "Ça vous parle ?"', '🔥 Anecdotes personnelles courtes et authentiques', '🔥 Alterne registres de façon imprévisible (soutenu/argot/technique)', '🔥 Débuts phrases variés : pas toujours sujet-verbe' ] : []) ]; } analyzeContent(content) { const baseMetrics = super.analyzeContent(content); // Analyse perplexité approximative const sentences = content.split(/[.!?]+/).filter(s => s.trim().length > 5); const sentenceLengths = sentences.map(s => s.split(/\s+/).length); // Variance longueur (proxy pour burstiness) const avgLength = sentenceLengths.reduce((a, b) => a + b, 0) / sentenceLengths.length; const variance = sentenceLengths.reduce((acc, len) => acc + Math.pow(len - avgLength, 2), 0) / sentenceLengths.length; const burstiness = Math.sqrt(variance) / avgLength; // Diversité lexicale (proxy pour imprévisibilité) const words = content.toLowerCase().split(/\s+/).filter(w => w.length > 2); const uniqueWords = [...new Set(words)]; const lexicalDiversity = uniqueWords.length / words.length; return { ...baseMetrics, burstiness: Math.round(burstiness * 100) / 100, lexicalDiversity: Math.round(lexicalDiversity * 100) / 100, avgSentenceLength: Math.round(avgLength), gptZeroRiskLevel: this.calculateGPTZeroRisk(burstiness, lexicalDiversity) }; } calculateGPTZeroRisk(burstiness, lexicalDiversity) { // Heuristique : GPTZero détecte uniformité faible + diversité faible const uniformityScore = Math.min(burstiness, 1) * 100; const diversityScore = lexicalDiversity * 100; const combinedScore = (uniformityScore + diversityScore) / 2; if (combinedScore > 70) return 'low'; if (combinedScore > 40) return 'medium'; return 'high'; } } /** * STRATÉGIE ANTI-ORIGINALITY * Focus: Diversité sémantique et originalité */ class OriginalityStrategy extends BaseDetectorStrategy { constructor() { super('Originality'); this.effectiveness = 0.85; this.targetMetrics = ['semantic_diversity', 'originality_score', 'vocabulary_range']; this.techniques = { semanticCreativity: { name: 'Créativité sémantique', rules: [ 'Métaphores inattendues : "cette plaque, c\'est le passeport de votre façade"', 'Comparaisons originales : évite clichés, invente analogies', 'Reformulations créatives : "résistant aux intempéries" → "qui brave les saisons"', 'Néologismes justifiés et expressifs' ] }, perspectiveShifting: { name: 'Changements de perspective', rules: [ 'Angles multiples sur même info : technique → esthétique → pratique', 'Points de vue variés : fabricant, utilisateur, installateur, voisin', 'Temporalités mélangées : présent, futur proche, retour d\'expérience', 'Niveaux d\'abstraction : détail précis puis vue d\'ensemble' ] }, linguisticInventiveness: { name: 'Inventivité linguistique', rules: [ 'Jeux de mots subtils et expressions détournées', 'Régionalismes et références culturelles précises', 'Vocabulaire technique humanisé avec créativité', 'Rythmes et sonorités travaillés : allitérations, assonances' ] } }; } generateInstructions(elementType, personality, csvData) { const instructions = []; instructions.push(`ANTI-ORIGINALITY - MAXIMUM CRÉATIVITÉ SÉMANTIQUE:`); // Créativité sémantique instructions.push(`\nCRÉATIVITÉ SÉMANTIQUE:`); this.techniques.semanticCreativity.rules.forEach(rule => { instructions.push(`• ${rule}`); }); // Changements de perspective instructions.push(`\nPERSPECTIVES MULTIPLES:`); this.techniques.perspectiveShifting.rules.forEach(rule => { instructions.push(`• ${rule}`); }); // Spécialisation par élément if (elementType === 'intro') { instructions.push(`\nINTROS ANTI-ORIGINALITY:`); instructions.push(`• Commence par angle totalement inattendu pour le sujet`); instructions.push(`• Évite intro-types, réinvente présentation du sujet`); instructions.push(`• Crée surprise puis retour naturel au cœur du sujet`); } else if (elementType.includes('faq')) { instructions.push(`\nFAQ ANTI-ORIGINALITY:`); instructions.push(`• Questions vraiment originales, pas standard secteur`); instructions.push(`• Réponses avec angles créatifs et exemples inédits`); } // Contexte métier créatif if (csvData && csvData.mc0) { instructions.push(`\nCRÉATIVITÉ CONTEXTUELLE ${csvData.mc0.toUpperCase()}:`); instructions.push(`• Réinvente façon de parler de ${csvData.mc0}`); instructions.push(`• Évite vocabulaire convenu du secteur, invente expressions`); instructions.push(`• Trouve analogies originales spécifiques à ${csvData.mc0}`); } // Inventivité linguistique instructions.push(`\nINVENTIVITÉ LINGUISTIQUE:`); this.techniques.linguisticInventiveness.rules.forEach(rule => { instructions.push(`• ${rule}`); }); return instructions.join('\n'); } /** * Instructions modulaires pour AdversarialCore */ getInstructions(intensity = 1.0) { const baseRules = [ 'Vocabulaire TRÈS varié : évite répétitions même de synonymes', 'Structures phrases délibérément irrégulières et asymétriques', 'Changements angles fréquents : technique → personnel → général', 'Créativité sémantique : métaphores, comparaisons inattendues' ]; const intensiveRules = [ 'Évite formulations académiques ou trop structurées', 'Intègre références culturelles, expressions régionales', 'Subvertis les attentes : commence par la fin, questionne l\'évidence', 'Réinvente façon de présenter informations basiques' ]; return intensity >= 1.0 ? [...baseRules, ...intensiveRules] : baseRules; } /** * Conseils d'amélioration pour enhancement method */ getEnhancementTips(intensity = 1.0) { return [ 'Trouve synonymes créatifs et expressions détournées', 'Ajoute métaphores subtiles et comparaisons originales', 'Varie angles d\'approche dans même contenu', 'Utilise vocabulaire technique humanisé', ...(intensity > 0.8 ? [ 'Insère références culturelles ou régionalismes', 'Crée néologismes justifiés et expressifs' ] : []) ]; } analyzeContent(content) { const baseMetrics = super.analyzeContent(content); // Analyse diversité sémantique const words = content.toLowerCase().split(/\s+/).filter(w => w.length > 3); const uniqueWords = [...new Set(words)]; const semanticDiversity = uniqueWords.length / words.length; // Détection créativité (heuristique) const creativityIndicators = [ 'comme', 'tel', 'sorte de', 'façon de', 'manière de', // métaphores '(', ')', '"', // originalité structure '?', '!', // variation tonale ]; const creativityCount = creativityIndicators.reduce((count, indicator) => { return count + (content.match(new RegExp(indicator.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'g')) || []).length; }, 0); const creativityScore = Math.min(100, (creativityCount / words.length) * 1000); return { ...baseMetrics, semanticDiversity: Math.round(semanticDiversity * 100) / 100, creativityScore: Math.round(creativityScore), uniqueWordRatio: Math.round((uniqueWords.length / words.length) * 100), originalityRiskLevel: this.calculateOriginalityRisk(semanticDiversity, creativityScore) }; } calculateOriginalityRisk(semanticDiversity, creativityScore) { const diversityScore = semanticDiversity * 100; const combinedScore = (diversityScore + creativityScore) / 2; if (combinedScore > 60) return 'low'; if (combinedScore > 35) return 'medium'; return 'high'; } } /** * STRATÉGIE ANTI-COPYLEAKS * Focus: Originalité absolue et reformulation créative */ class CopyLeaksStrategy extends BaseDetectorStrategy { constructor() { super('CopyLeaks'); this.effectiveness = 0.85; this.targetMetrics = ['originality_score', 'paraphrasing_quality', 'uniqueness']; this.techniques = { radicalReformulation: { name: 'Reformulation radicale', rules: [ 'Reformule idées communes avec angles totalement originaux', 'Évite phrases-types et formulations standard du secteur', 'Transforme descriptions directes en récits ou témoignages', 'Réinvente la façon de présenter informations basiques' ] }, personalizedExamples: { name: 'Exemples personnalisés', rules: [ 'Personnalise chaque assertion avec exemples spécifiques', 'Utilise analogies et métaphores plutôt que descriptions directes', 'Fragmente informations techniques en observations pratiques', 'Contextualise chaque donnée factuelle avec du vécu' ] } }; } generateInstructions(elementType, personality, csvData) { const instructions = []; instructions.push(`ANTI-COPYLEAKS - ORIGINALITÉ MAXIMALE:`); // Reformulation radicale instructions.push(`\nREFORMULATION RADICALE:`); this.techniques.radicalReformulation.rules.forEach(rule => { instructions.push(`• ${rule}`); }); // Exemples personnalisés instructions.push(`\nPERSONNALISATION:`); this.techniques.personalizedExamples.rules.forEach(rule => { instructions.push(`• ${rule}`); }); return instructions.join('\n'); } getInstructions(intensity = 1.0) { const baseRules = [ 'Reformule idées communes avec angles totalement originaux', 'Évite phrases-types et formulations standard du secteur', 'Personnalise chaque assertion avec exemples spécifiques', 'Réinvente la façon de présenter informations basiques' ]; const intensiveRules = [ 'Utilise analogies et métaphores plutôt que descriptions directes', 'Fragmente informations techniques en observations pratiques', 'Transforme données factuelles en récits ou témoignages' ]; return intensity >= 1.0 ? [...baseRules, ...intensiveRules] : baseRules; } getEnhancementTips(intensity = 1.0) { return [ 'Trouve angles d\'approche inédits pour infos classiques', 'Remplace descriptions techniques par analogies concrètes', 'Contextualise avec exemples spécifiques et originaux', ...(intensity > 0.8 ? [ 'Transforme assertions en mini-récits authentiques', 'Crée métaphores personnalisées au contexte' ] : []) ]; } analyzeContent(content) { const baseMetrics = super.analyzeContent(content); const words = content.split(/\s+/); // Détection formulations standard const standardPhrases = [ 'il est important de', 'permet de', 'grâce à', 'en effet', 'par ailleurs', 'de plus', 'notamment', 'ainsi' ]; const standardCount = standardPhrases.reduce((count, phrase) => { return count + (content.toLowerCase().match(new RegExp(phrase, 'g')) || []).length; }, 0); const standardDensity = (standardCount / words.length) * 100; const originalityScore = Math.max(0, 100 - (standardDensity * 20)); return { ...baseMetrics, standardPhrasesCount: standardCount, standardDensity: Math.round(standardDensity * 100) / 100, originalityScore: Math.round(originalityScore), copyLeaksRiskLevel: originalityScore > 70 ? 'low' : originalityScore > 40 ? 'medium' : 'high' }; } } /** * STRATÉGIE ANTI-WINSTON * Focus: Variation humaine et imperfections authentiques */ class WinstonStrategy extends BaseDetectorStrategy { constructor() { super('Winston'); this.effectiveness = 0.8; this.targetMetrics = ['human_variation', 'stylistic_inconsistency', 'emotional_range']; this.techniques = { stylisticVariation: { name: 'Variation stylistique', rules: [ 'Évite cohérence stylistique trop parfaite entre paragraphes', 'Simule variation naturelle d\'humeur et d\'énergie rédactionnelle', 'Varie niveau de détail : parfois précis, parfois elliptique', 'Alterne registres émotionnels : enthousiaste → neutre → critique' ] }, humanImperfections: { name: 'Imperfections humaines', rules: [ 'Intègre "erreurs" humaines : répétitions, corrections, précisions', 'Inclus hésitations et nuances : "peut-être", "généralement", "souvent"', 'Personnalise avec opinions subjectives et préférences', 'Ajoute auto-corrections : "enfin, plus précisément..."' ] } }; } generateInstructions(elementType, personality, csvData) { const instructions = []; instructions.push(`ANTI-WINSTON - VARIATION HUMAINE MAXIMALE:`); // Variation stylistique instructions.push(`\nVARIATION STYLISTIQUE:`); this.techniques.stylisticVariation.rules.forEach(rule => { instructions.push(`• ${rule}`); }); // Imperfections humaines instructions.push(`\nIMPERFECTIONS AUTHENTIQUES:`); this.techniques.humanImperfections.rules.forEach(rule => { instructions.push(`• ${rule}`); }); return instructions.join('\n'); } getInstructions(intensity = 1.0) { const baseRules = [ 'Évite cohérence stylistique trop parfaite entre paragraphes', 'Simule variation naturelle d\'humeur et d\'énergie rédactionnelle', 'Intègre "erreurs" humaines : répétitions, corrections, précisions', 'Varie niveau de détail : parfois précis, parfois elliptique' ]; const intensiveRules = [ 'Alterne registres émotionnels : enthousiaste → neutre → critique', 'Inclus hésitations et nuances : "peut-être", "généralement", "souvent"', 'Personnalise avec opinions subjectives et préférences', 'Ajoute auto-corrections et reformulations spontanées' ]; return intensity >= 1.0 ? [...baseRules, ...intensiveRules] : baseRules; } getEnhancementTips(intensity = 1.0) { return [ 'Ajoute hésitations naturelles et nuances', 'Varie ton et énergie légèrement dans le texte', 'Inclus répétitions légères ou reformulations', ...(intensity > 0.8 ? [ 'Personnalise avec opinions subjectives', 'Simule changements d\'humeur subtils' ] : []) ]; } analyzeContent(content) { const baseMetrics = super.analyzeContent(content); // Détection variation humaine const humanMarkers = [ 'peut-être', 'probablement', 'généralement', 'souvent', 'parfois', 'vraiment', 'plutôt', 'assez' ]; const humanMarkerCount = humanMarkers.reduce((count, marker) => { return count + (content.toLowerCase().match(new RegExp(`\\b${marker}\\b`, 'g')) || []).length; }, 0); const sentences = content.split(/[.!?]+/).filter(s => s.trim().length > 5); const humanVariationScore = Math.min(100, (humanMarkerCount / sentences.length) * 100); return { ...baseMetrics, humanMarkerCount, humanVariationScore: Math.round(humanVariationScore), winstonRiskLevel: humanVariationScore > 30 ? 'low' : humanVariationScore > 15 ? 'medium' : 'high' }; } } /** * STRATÉGIE GÉNÉRALE * Équilibre entre toutes les techniques */ class GeneralStrategy extends BaseDetectorStrategy { constructor() { super('General'); this.effectiveness = 0.75; this.targetMetrics = ['overall_naturalness', 'human_likeness']; } generateInstructions(elementType, personality, csvData) { const instructions = []; instructions.push(`ANTI-DÉTECTION GÉNÉRALE - ÉQUILIBRE OPTIMAL:`); // Instructions générales équilibrées instructions.push(`\nNATUREL ET VARIÉ:`); instructions.push(`• Évite mots typiques IA : "optimal", "comprehensive", "seamless", "robust"`); instructions.push(`• Mélange phrases courtes (5-10 mots) et longues (15-25 mots) naturellement`); instructions.push(`• Utilise expressions idiomatiques françaises authentiques`); instructions.push(`• Intègre imperfections humaines : répétitions légères, hésitations`); instructions.push(`• Change angle ou ton 1-2 fois selon longueur du contenu`); // Adaptation personnalité équilibrée if (personality) { instructions.push(`\nSTYLE ${personality.nom} NATUREL:`); instructions.push(`• Applique style ${personality.style} de façon authentique, pas forcée`); instructions.push(`• Respecte vocabulaire naturel : ${personality.vocabulairePref || 'varié'}`); instructions.push(`• Utilise connecteurs variés : ${personality.connecteursPref || 'naturels'}`); } return instructions.join('\n'); } /** * Instructions modulaires pour AdversarialCore */ getInstructions(intensity = 1.0) { const baseRules = [ 'Évite ces mots typiques IA : "optimal", "comprehensive", "seamless", "robust", "leverage"', 'Varie longueurs phrases : mélange phrases courtes (5-10 mots) ET longues (20-30 mots)', 'Utilise expressions françaises familières et tournures idiomatiques', 'Ajoute imperfections naturelles : répétitions légères, hésitations, reformulations' ]; const intensiveRules = [ 'Change angle ou perspective 1-2 fois dans le texte', 'Préfère synonymes moins évidents : "bon" plutôt qu\'excellent", "solide" plutôt qu\'optimisé"', 'Intègre connecteurs variés et naturels selon le contexte', 'Simule variation naturelle d\'humeur et d\'énergie rédactionnelle' ]; return intensity >= 0.8 ? [...baseRules, ...intensiveRules] : baseRules; } /** * Conseils d'amélioration pour enhancement method */ getEnhancementTips(intensity = 1.0) { return [ 'Remplace mots typiques IA par synonymes plus naturels', 'Ajoute nuances et hésitations : "peut-être", "généralement", "souvent"', 'Varie connecteurs pour éviter répétitions mécaniques', 'Personnalise avec observations subjectives légères', ...(intensity > 0.7 ? [ 'Intègre "erreurs" humaines : corrections, précisions', 'Simule changement léger de ton ou d\'énergie' ] : []) ]; } analyzeContent(content) { const baseMetrics = super.analyzeContent(content); // Métrique naturalité générale const sentences = content.split(/[.!?]+/).filter(s => s.trim().length > 5); const avgWordsPerSentence = baseMetrics.wordCount / baseMetrics.sentenceCount; // Détection mots typiques IA const aiWords = ['optimal', 'comprehensive', 'seamless', 'robust', 'leverage']; const aiWordCount = aiWords.reduce((count, word) => { return count + (content.toLowerCase().match(new RegExp(`\\b${word}\\b`, 'g')) || []).length; }, 0); const aiWordDensity = aiWordCount / baseMetrics.wordCount * 100; const naturalness = Math.max(0, 100 - (aiWordDensity * 10) - Math.abs(avgWordsPerSentence - 15)); return { ...baseMetrics, avgWordsPerSentence: Math.round(avgWordsPerSentence), aiWordCount, aiWordDensity: Math.round(aiWordDensity * 100) / 100, naturalnessScore: Math.round(naturalness), generalRiskLevel: naturalness > 70 ? 'low' : naturalness > 40 ? 'medium' : 'high' }; } } /** * FACTORY POUR CRÉER STRATÉGIES */ class DetectorStrategyFactory { static strategies = { 'general': GeneralStrategy, 'gptZero': GPTZeroStrategy, 'originality': OriginalityStrategy, 'copyLeaks': CopyLeaksStrategy, 'winston': WinstonStrategy }; static createStrategy(detectorName) { const StrategyClass = this.strategies[detectorName]; if (!StrategyClass) { logSh(`⚠️ Stratégie inconnue: ${detectorName}, fallback vers général`, 'WARNING'); return new GeneralStrategy(); } return new StrategyClass(); } static getSupportedDetectors() { return Object.keys(this.strategies).map(name => { const strategy = this.createStrategy(name); return { name, displayName: strategy.name, effectiveness: strategy.effectiveness, targetMetrics: strategy.targetMetrics }; }); } static analyzeContentAgainstAllDetectors(content) { const results = {}; Object.keys(this.strategies).forEach(detectorName => { const strategy = this.createStrategy(detectorName); results[detectorName] = strategy.analyzeEffectiveness(content); }); return results; } } /** * FONCTION UTILITAIRE - SÉLECTION STRATÉGIE OPTIMALE */ function selectOptimalStrategy(elementType, personality, previousResults = {}) { // Logique de sélection intelligente // Si résultats précédents disponibles, adapter if (previousResults.gptZero && previousResults.gptZero.effectiveness < 0.6) { return 'gptZero'; // Renforcer anti-GPTZero } if (previousResults.originality && previousResults.originality.effectiveness < 0.6) { return 'originality'; // Renforcer anti-Originality } // Sélection par type d'élément if (elementType === 'titre_h1' || elementType === 'titre_h2') { return 'gptZero'; // Titres bénéficient imprévisibilité } if (elementType === 'intro' || elementType === 'texte') { return 'originality'; // Corps bénéficie créativité sémantique } if (elementType.includes('faq')) { return 'general'; // FAQ équilibre naturalité } // Par personnalité if (personality) { if (personality.style === 'créatif' || personality.style === 'original') { return 'originality'; } if (personality.style === 'technique' || personality.style === 'expert') { return 'gptZero'; } } return 'general'; // Fallback } module.exports = { DetectorStrategyFactory, GPTZeroStrategy, OriginalityStrategy, CopyLeaksStrategy, WinstonStrategy, GeneralStrategy, selectOptimalStrategy, BaseDetectorStrategy };