// ======================================== // ADVERSARIAL CORE - MOTEUR MODULAIRE // Responsabilité: Moteur adversarial réutilisable sur tout contenu // Architecture: Couches applicables à la demande // ======================================== const { logSh } = require('../ErrorReporting'); const { tracer } = require('../trace'); const { callLLM } = require('../LLMManager'); // Import stratégies et utilitaires const { DetectorStrategyFactory, selectOptimalStrategy } = require('./DetectorStrategies'); /** * MAIN ENTRY POINT - APPLICATION COUCHE ADVERSARIALE * Input: contenu existant + configuration adversariale * Output: contenu avec couche adversariale appliquée */ async function applyAdversarialLayer(existingContent, config = {}) { return await tracer.run('AdversarialCore.applyAdversarialLayer()', async () => { const { detectorTarget = 'general', intensity = 1.0, method = 'regeneration', // 'regeneration' | 'enhancement' | 'hybrid' preserveStructure = true, csvData = null, context = {} } = config; await tracer.annotate({ adversarialLayer: true, detectorTarget, intensity, method, elementsCount: Object.keys(existingContent).length }); const startTime = Date.now(); logSh(`🎯 APPLICATION COUCHE ADVERSARIALE: ${detectorTarget} (${method})`, 'INFO'); logSh(` 📊 ${Object.keys(existingContent).length} éléments | Intensité: ${intensity}`, 'INFO'); try { // Initialiser stratégie détecteur const strategy = DetectorStrategyFactory.createStrategy(detectorTarget); // Appliquer méthode adversariale choisie let adversarialContent = {}; switch (method) { case 'regeneration': adversarialContent = await applyRegenerationMethod(existingContent, config, strategy); break; case 'enhancement': adversarialContent = await applyEnhancementMethod(existingContent, config, strategy); break; case 'hybrid': adversarialContent = await applyHybridMethod(existingContent, config, strategy); break; default: throw new Error(`Méthode adversariale inconnue: ${method}`); } const duration = Date.now() - startTime; const stats = { elementsProcessed: Object.keys(existingContent).length, elementsModified: countModifiedElements(existingContent, adversarialContent), detectorTarget, intensity, method, duration }; logSh(`✅ COUCHE ADVERSARIALE APPLIQUÉE: ${stats.elementsModified}/${stats.elementsProcessed} modifiés (${duration}ms)`, 'INFO'); await tracer.event('Couche adversariale appliquée', stats); return { content: adversarialContent, stats, original: existingContent, config }; } catch (error) { const duration = Date.now() - startTime; logSh(`❌ COUCHE ADVERSARIALE ÉCHOUÉE après ${duration}ms: ${error.message}`, 'ERROR'); // Fallback: retourner contenu original logSh(`🔄 Fallback: contenu original conservé`, 'WARNING'); return { content: existingContent, stats: { fallback: true, duration }, original: existingContent, config, error: error.message }; } }, { existingContent: Object.keys(existingContent), config }); } /** * MÉTHODE RÉGÉNÉRATION - Réécrire complètement avec prompts adversariaux */ async function applyRegenerationMethod(existingContent, config, strategy) { logSh(`🔄 Méthode régénération adversariale`, 'DEBUG'); const results = {}; const contentEntries = Object.entries(existingContent); // Traiter en chunks pour éviter timeouts const chunks = chunkArray(contentEntries, 4); for (let chunkIndex = 0; chunkIndex < chunks.length; chunkIndex++) { const chunk = chunks[chunkIndex]; logSh(` 📦 Régénération chunk ${chunkIndex + 1}/${chunks.length}: ${chunk.length} éléments`, 'DEBUG'); try { const regenerationPrompt = createRegenerationPrompt(chunk, config, strategy); const response = await callLLM('claude', regenerationPrompt, { temperature: 0.7 + (config.intensity * 0.2), // Température variable selon intensité maxTokens: 2000 * chunk.length }, config.csvData?.personality); const chunkResults = parseRegenerationResponse(response, chunk); Object.assign(results, chunkResults); logSh(` ✅ Chunk ${chunkIndex + 1}: ${Object.keys(chunkResults).length} éléments régénérés`, 'DEBUG'); // Délai entre chunks if (chunkIndex < chunks.length - 1) { await sleep(1500); } } catch (error) { logSh(` ❌ Chunk ${chunkIndex + 1} échoué: ${error.message}`, 'ERROR'); // Fallback: garder contenu original pour ce chunk chunk.forEach(([tag, content]) => { results[tag] = content; }); } } return results; } /** * MÉTHODE ENHANCEMENT - Améliorer sans réécrire complètement */ async function applyEnhancementMethod(existingContent, config, strategy) { logSh(`🔧 Méthode enhancement adversarial`, 'DEBUG'); const results = { ...existingContent }; // Base: contenu original const elementsToEnhance = selectElementsForEnhancement(existingContent, config); if (elementsToEnhance.length === 0) { logSh(` ⏭️ Aucun élément nécessite enhancement`, 'DEBUG'); return results; } logSh(` 📋 ${elementsToEnhance.length} éléments sélectionnés pour enhancement`, 'DEBUG'); const enhancementPrompt = createEnhancementPrompt(elementsToEnhance, config, strategy); try { const response = await callLLM('gpt4', enhancementPrompt, { temperature: 0.5 + (config.intensity * 0.3), maxTokens: 3000 }, config.csvData?.personality); const enhancedResults = parseEnhancementResponse(response, elementsToEnhance); // Appliquer améliorations Object.keys(enhancedResults).forEach(tag => { if (enhancedResults[tag] !== existingContent[tag]) { results[tag] = enhancedResults[tag]; } }); return results; } catch (error) { logSh(`❌ Enhancement échoué: ${error.message}`, 'ERROR'); return results; // Fallback: contenu original } } /** * MÉTHODE HYBRIDE - Combinaison régénération + enhancement */ async function applyHybridMethod(existingContent, config, strategy) { logSh(`⚡ Méthode hybride adversariale`, 'DEBUG'); // 1. Enhancement léger sur tout le contenu const enhancedContent = await applyEnhancementMethod(existingContent, { ...config, intensity: config.intensity * 0.6 // Intensité réduite pour enhancement }, strategy); // 2. Régénération ciblée sur éléments clés const keyElements = selectKeyElementsForRegeneration(enhancedContent, config); if (keyElements.length === 0) { return enhancedContent; } const keyElementsContent = {}; keyElements.forEach(tag => { keyElementsContent[tag] = enhancedContent[tag]; }); const regeneratedElements = await applyRegenerationMethod(keyElementsContent, { ...config, intensity: config.intensity * 1.2 // Intensité augmentée pour régénération }, strategy); // 3. Merger résultats const hybridContent = { ...enhancedContent }; Object.keys(regeneratedElements).forEach(tag => { hybridContent[tag] = regeneratedElements[tag]; }); return hybridContent; } // ============= HELPER FUNCTIONS ============= /** * Créer prompt de régénération adversariale */ function createRegenerationPrompt(chunk, config, strategy) { const { detectorTarget, intensity, csvData } = config; let prompt = `MISSION: Réécris ces contenus pour éviter détection par ${detectorTarget}. TECHNIQUE ANTI-${detectorTarget.toUpperCase()}: ${strategy.getInstructions(intensity).join('\n')} CONTENUS À RÉÉCRIRE: ${chunk.map(([tag, content], i) => `[${i + 1}] TAG: ${tag} ORIGINAL: "${content}"`).join('\n\n')} CONSIGNES: - GARDE exactement le même message et informations factuelles - CHANGE structure, vocabulaire, style pour éviter détection ${detectorTarget} - Intensité adversariale: ${intensity.toFixed(2)} ${csvData?.personality ? `- Style: ${csvData.personality.nom} (${csvData.personality.style})` : ''} IMPORTANT: Réponse DIRECTE par les contenus réécrits, pas d'explication. FORMAT: [1] Contenu réécrit anti-${detectorTarget} [2] Contenu réécrit anti-${detectorTarget} etc...`; return prompt; } /** * Créer prompt d'enhancement adversarial */ function createEnhancementPrompt(elementsToEnhance, config, strategy) { const { detectorTarget, intensity } = config; let prompt = `MISSION: Améliore subtilement ces contenus pour réduire détection ${detectorTarget}. AMÉLIORATIONS CIBLÉES: ${strategy.getEnhancementTips(intensity).join('\n')} ÉLÉMENTS À AMÉLIORER: ${elementsToEnhance.map((element, i) => `[${i + 1}] TAG: ${element.tag} CONTENU: "${element.content}" PROBLÈME: ${element.detectionRisk}`).join('\n\n')} CONSIGNES: - Modifications LÉGÈRES et naturelles - GARDE le fond du message intact - Focus sur réduction détection ${detectorTarget} - Intensité: ${intensity.toFixed(2)} FORMAT: [1] Contenu légèrement amélioré [2] Contenu légèrement amélioré etc...`; return prompt; } /** * Parser réponse régénération */ function parseRegenerationResponse(response, chunk) { const results = {}; const regex = /\[(\d+)\]\s*([^[]*?)(?=\n\[\d+\]|$)/gs; let match; const parsedItems = {}; while ((match = regex.exec(response)) !== null) { const index = parseInt(match[1]) - 1; const content = cleanAdversarialContent(match[2].trim()); if (index >= 0 && index < chunk.length) { parsedItems[index] = content; } } // Mapper aux vrais tags chunk.forEach(([tag, originalContent], index) => { if (parsedItems[index] && parsedItems[index].length > 10) { results[tag] = parsedItems[index]; } else { results[tag] = originalContent; // Fallback logSh(`⚠️ Fallback régénération pour [${tag}]`, 'WARNING'); } }); return results; } /** * Parser réponse enhancement */ function parseEnhancementResponse(response, elementsToEnhance) { const results = {}; const regex = /\[(\d+)\]\s*([^[]*?)(?=\n\[\d+\]|$)/gs; let match; let index = 0; while ((match = regex.exec(response)) && index < elementsToEnhance.length) { let enhancedContent = cleanAdversarialContent(match[2].trim()); const element = elementsToEnhance[index]; if (enhancedContent && enhancedContent.length > 10) { results[element.tag] = enhancedContent; } else { results[element.tag] = element.content; // Fallback } index++; } return results; } /** * Sélectionner éléments pour enhancement */ function selectElementsForEnhancement(existingContent, config) { const elements = []; Object.entries(existingContent).forEach(([tag, content]) => { const detectionRisk = assessDetectionRisk(content, config.detectorTarget); if (detectionRisk.score > 0.6) { // Risque élevé elements.push({ tag, content, detectionRisk: detectionRisk.reasons.join(', '), priority: detectionRisk.score }); } }); // Trier par priorité (risque élevé en premier) elements.sort((a, b) => b.priority - a.priority); return elements; } /** * Sélectionner éléments clés pour régénération (hybride) */ function selectKeyElementsForRegeneration(content, config) { const keyTags = []; Object.keys(content).forEach(tag => { // Éléments clés: titres, intro, premiers paragraphes if (tag.includes('Titre') || tag.includes('H1') || tag.includes('intro') || tag.includes('Introduction') || tag.includes('1')) { keyTags.push(tag); } }); return keyTags.slice(0, 3); // Maximum 3 éléments clés } /** * Évaluer risque de détection */ function assessDetectionRisk(content, detectorTarget) { let score = 0; const reasons = []; // Indicateurs génériques de contenu IA const aiWords = ['optimal', 'comprehensive', 'seamless', 'robust', 'leverage', 'cutting-edge']; const aiCount = aiWords.reduce((count, word) => { return count + (content.toLowerCase().includes(word) ? 1 : 0); }, 0); if (aiCount > 2) { score += 0.4; reasons.push('mots_typiques_ia'); } // Structure trop parfaite const sentences = content.split(/[.!?]+/).filter(s => s.trim().length > 10); if (sentences.length > 2) { const avgLength = sentences.reduce((sum, s) => sum + s.length, 0) / sentences.length; const variance = sentences.reduce((sum, s) => sum + Math.pow(s.length - avgLength, 2), 0) / sentences.length; const uniformity = 1 - (Math.sqrt(variance) / avgLength); if (uniformity > 0.8) { score += 0.3; reasons.push('structure_uniforme'); } } // Spécifique selon détecteur if (detectorTarget === 'gptZero') { // GPTZero détecte la prévisibilité if (content.includes('par ailleurs') && content.includes('en effet')) { score += 0.3; reasons.push('connecteurs_prévisibles'); } } return { score: Math.min(1, score), reasons }; } /** * Nettoyer contenu adversarial généré */ function cleanAdversarialContent(content) { if (!content) return content; // Supprimer préfixes indésirables content = content.replace(/^(voici\s+)?le\s+contenu\s+(réécrit|amélioré)[:\s]*/gi, ''); content = content.replace(/^(bon,?\s*)?(alors,?\s*)?/gi, ''); content = content.replace(/\*\*[^*]+\*\*/g, ''); content = content.replace(/\s{2,}/g, ' '); content = content.trim(); return content; } /** * Compter éléments modifiés */ function countModifiedElements(original, modified) { let count = 0; Object.keys(original).forEach(tag => { if (modified[tag] && modified[tag] !== original[tag]) { count++; } }); return count; } /** * Chunk array utility */ function chunkArray(array, size) { const chunks = []; for (let i = 0; i < array.length; i += size) { chunks.push(array.slice(i, i + size)); } return chunks; } /** * Sleep utility */ function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } module.exports = { applyAdversarialLayer, // ← MAIN ENTRY POINT MODULAIRE applyRegenerationMethod, applyEnhancementMethod, applyHybridMethod, assessDetectionRisk, selectElementsForEnhancement };