Added plan.md with complete architecture for format-agnostic content generation: - Support for Markdown, HTML, Plain Text, JSON formats - New FormatExporter module with neutral data structure - Integration strategy with existing ContentAssembly and ArticleStorage - Bonus features: SEO metadata generation, readability scoring, WordPress Gutenberg format - Implementation roadmap with 4 phases (6h total estimated) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
408 lines
14 KiB
JavaScript
408 lines
14 KiB
JavaScript
// ========================================
|
|
// ORCHESTRATEUR CONTENU ADVERSARIAL - NIVEAU 3
|
|
// Responsabilité: Pipeline complet de génération anti-détection
|
|
// Architecture: 4 étapes adversariales séparées et modulaires
|
|
// ========================================
|
|
|
|
const { logSh } = require('../ErrorReporting');
|
|
const { tracer } = require('../trace');
|
|
|
|
// Importation des 4 étapes adversariales
|
|
const { generateInitialContentAdversarial } = require('./AdversarialInitialGeneration');
|
|
const { enhanceTechnicalTermsAdversarial } = require('./AdversarialTechnicalEnhancement');
|
|
const { enhanceTransitionsAdversarial } = require('./AdversarialTransitionEnhancement');
|
|
const { applyPersonalityStyleAdversarial } = require('./AdversarialStyleEnhancement');
|
|
|
|
// Importation du moteur adversarial
|
|
const { createAdversarialPrompt, getSupportedDetectors, analyzePromptEffectiveness } = require('./AdversarialPromptEngine');
|
|
const { DetectorStrategyManager } = require('./DetectorStrategies');
|
|
|
|
/**
|
|
* MAIN ENTRY POINT - PIPELINE ADVERSARIAL COMPLET
|
|
* Input: { hierarchy, csvData, adversarialConfig, context }
|
|
* Output: { content, stats, debug, adversarialMetrics }
|
|
*/
|
|
async function generateWithAdversarialContext(input) {
|
|
return await tracer.run('ContentGenerationAdversarial.generateWithAdversarialContext()', async () => {
|
|
const { hierarchy, csvData, adversarialConfig = {}, context = {} } = input;
|
|
|
|
// Configuration adversariale par défaut
|
|
const config = {
|
|
detectorTarget: adversarialConfig.detectorTarget || 'general',
|
|
intensity: adversarialConfig.intensity || 1.0,
|
|
enableAdaptiveStrategy: adversarialConfig.enableAdaptiveStrategy !== false,
|
|
contextualMode: adversarialConfig.contextualMode !== false,
|
|
enableAllSteps: adversarialConfig.enableAllSteps !== false,
|
|
// Configuration par étape
|
|
steps: {
|
|
initial: adversarialConfig.steps?.initial !== false,
|
|
technical: adversarialConfig.steps?.technical !== false,
|
|
transitions: adversarialConfig.steps?.transitions !== false,
|
|
style: adversarialConfig.steps?.style !== false
|
|
},
|
|
...adversarialConfig
|
|
};
|
|
|
|
await tracer.annotate({
|
|
adversarialPipeline: true,
|
|
detectorTarget: config.detectorTarget,
|
|
intensity: config.intensity,
|
|
enabledSteps: Object.keys(config.steps).filter(k => config.steps[k]),
|
|
elementsCount: Object.keys(hierarchy).length,
|
|
mc0: csvData.mc0
|
|
});
|
|
|
|
const startTime = Date.now();
|
|
logSh(`🎯 PIPELINE ADVERSARIAL NIVEAU 3: Anti-détection ${config.detectorTarget}`, 'INFO');
|
|
logSh(` 🎚️ Intensité: ${config.intensity.toFixed(2)} | Étapes: ${Object.keys(config.steps).filter(k => config.steps[k]).join(', ')}`, 'INFO');
|
|
|
|
// Initialiser manager détecteur global
|
|
const detectorManager = new DetectorStrategyManager(config.detectorTarget);
|
|
|
|
try {
|
|
let currentContent = {};
|
|
let pipelineStats = {
|
|
steps: {},
|
|
totalDuration: 0,
|
|
elementsProcessed: 0,
|
|
adversarialMetrics: {
|
|
promptsGenerated: 0,
|
|
detectorTarget: config.detectorTarget,
|
|
averageIntensity: config.intensity,
|
|
effectivenessScore: 0
|
|
}
|
|
};
|
|
|
|
// ========================================
|
|
// ÉTAPE 1: GÉNÉRATION INITIALE ADVERSARIALE
|
|
// ========================================
|
|
if (config.steps.initial) {
|
|
logSh(`🎯 ÉTAPE 1/4: Génération initiale adversariale`, 'INFO');
|
|
|
|
const step1Result = await generateInitialContentAdversarial({
|
|
hierarchy,
|
|
csvData,
|
|
context,
|
|
adversarialConfig: config
|
|
});
|
|
|
|
currentContent = step1Result.content;
|
|
pipelineStats.steps.initial = step1Result.stats;
|
|
pipelineStats.adversarialMetrics.promptsGenerated += Object.keys(currentContent).length;
|
|
|
|
logSh(`✅ ÉTAPE 1/4: ${step1Result.stats.generated} éléments générés (${step1Result.stats.duration}ms)`, 'INFO');
|
|
} else {
|
|
logSh(`⏭️ ÉTAPE 1/4: Ignorée (configuration)`, 'INFO');
|
|
}
|
|
|
|
// ========================================
|
|
// ÉTAPE 2: ENHANCEMENT TECHNIQUE ADVERSARIAL
|
|
// ========================================
|
|
if (config.steps.technical && Object.keys(currentContent).length > 0) {
|
|
logSh(`🎯 ÉTAPE 2/4: Enhancement technique adversarial`, 'INFO');
|
|
|
|
const step2Result = await enhanceTechnicalTermsAdversarial({
|
|
content: currentContent,
|
|
csvData,
|
|
context,
|
|
adversarialConfig: config
|
|
});
|
|
|
|
currentContent = step2Result.content;
|
|
pipelineStats.steps.technical = step2Result.stats;
|
|
pipelineStats.adversarialMetrics.promptsGenerated += step2Result.stats.enhanced;
|
|
|
|
logSh(`✅ ÉTAPE 2/4: ${step2Result.stats.enhanced} éléments améliorés (${step2Result.stats.duration}ms)`, 'INFO');
|
|
} else {
|
|
logSh(`⏭️ ÉTAPE 2/4: Ignorée (configuration ou pas de contenu)`, 'INFO');
|
|
}
|
|
|
|
// ========================================
|
|
// ÉTAPE 3: ENHANCEMENT TRANSITIONS ADVERSARIAL
|
|
// ========================================
|
|
if (config.steps.transitions && Object.keys(currentContent).length > 0) {
|
|
logSh(`🎯 ÉTAPE 3/4: Enhancement transitions adversarial`, 'INFO');
|
|
|
|
const step3Result = await enhanceTransitionsAdversarial({
|
|
content: currentContent,
|
|
csvData,
|
|
context,
|
|
adversarialConfig: config
|
|
});
|
|
|
|
currentContent = step3Result.content;
|
|
pipelineStats.steps.transitions = step3Result.stats;
|
|
pipelineStats.adversarialMetrics.promptsGenerated += step3Result.stats.enhanced;
|
|
|
|
logSh(`✅ ÉTAPE 3/4: ${step3Result.stats.enhanced} éléments fluidifiés (${step3Result.stats.duration}ms)`, 'INFO');
|
|
} else {
|
|
logSh(`⏭️ ÉTAPE 3/4: Ignorée (configuration ou pas de contenu)`, 'INFO');
|
|
}
|
|
|
|
// ========================================
|
|
// ÉTAPE 4: ENHANCEMENT STYLE ADVERSARIAL
|
|
// ========================================
|
|
if (config.steps.style && Object.keys(currentContent).length > 0 && csvData.personality) {
|
|
logSh(`🎯 ÉTAPE 4/4: Enhancement style adversarial`, 'INFO');
|
|
|
|
const step4Result = await applyPersonalityStyleAdversarial({
|
|
content: currentContent,
|
|
csvData,
|
|
context,
|
|
adversarialConfig: config
|
|
});
|
|
|
|
currentContent = step4Result.content;
|
|
pipelineStats.steps.style = step4Result.stats;
|
|
pipelineStats.adversarialMetrics.promptsGenerated += step4Result.stats.enhanced;
|
|
|
|
logSh(`✅ ÉTAPE 4/4: ${step4Result.stats.enhanced} éléments stylisés (${step4Result.stats.duration}ms)`, 'INFO');
|
|
} else {
|
|
logSh(`⏭️ ÉTAPE 4/4: Ignorée (configuration, pas de contenu ou pas de personnalité)`, 'INFO');
|
|
}
|
|
|
|
// ========================================
|
|
// FINALISATION PIPELINE
|
|
// ========================================
|
|
const totalDuration = Date.now() - startTime;
|
|
pipelineStats.totalDuration = totalDuration;
|
|
pipelineStats.elementsProcessed = Object.keys(currentContent).length;
|
|
|
|
// Calculer score d'efficacité adversarial
|
|
pipelineStats.adversarialMetrics.effectivenessScore = calculateAdversarialEffectiveness(
|
|
pipelineStats,
|
|
config,
|
|
currentContent
|
|
);
|
|
|
|
logSh(`🎯 PIPELINE ADVERSARIAL TERMINÉ: ${pipelineStats.elementsProcessed} éléments (${totalDuration}ms)`, 'INFO');
|
|
logSh(` 📊 Score efficacité: ${pipelineStats.adversarialMetrics.effectivenessScore.toFixed(2)}%`, 'INFO');
|
|
|
|
await tracer.event(`Pipeline adversarial terminé`, {
|
|
...pipelineStats,
|
|
detectorTarget: config.detectorTarget,
|
|
intensity: config.intensity
|
|
});
|
|
|
|
return {
|
|
content: currentContent,
|
|
stats: pipelineStats,
|
|
debug: {
|
|
adversarialPipeline: true,
|
|
detectorTarget: config.detectorTarget,
|
|
intensity: config.intensity,
|
|
stepsExecuted: Object.keys(config.steps).filter(k => config.steps[k]),
|
|
detectorManager: detectorManager.getStrategyInfo()
|
|
},
|
|
adversarialMetrics: pipelineStats.adversarialMetrics
|
|
};
|
|
|
|
} catch (error) {
|
|
const duration = Date.now() - startTime;
|
|
logSh(`❌ PIPELINE ADVERSARIAL ÉCHOUÉ après ${duration}ms: ${error.message}`, 'ERROR');
|
|
throw new Error(`AdversarialContentGeneration failed: ${error.message}`);
|
|
}
|
|
}, input);
|
|
}
|
|
|
|
/**
|
|
* MODE SIMPLE ADVERSARIAL (équivalent à generateSimple mais adversarial)
|
|
*/
|
|
async function generateSimpleAdversarial(hierarchy, csvData, adversarialConfig = {}) {
|
|
return await generateWithAdversarialContext({
|
|
hierarchy,
|
|
csvData,
|
|
adversarialConfig: {
|
|
detectorTarget: 'general',
|
|
intensity: 0.8,
|
|
enableAllSteps: false,
|
|
steps: {
|
|
initial: true,
|
|
technical: false,
|
|
transitions: false,
|
|
style: true
|
|
},
|
|
...adversarialConfig
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* MODE AVANCÉ ADVERSARIAL (configuration personnalisée)
|
|
*/
|
|
async function generateAdvancedAdversarial(hierarchy, csvData, options = {}) {
|
|
const {
|
|
detectorTarget = 'general',
|
|
intensity = 1.0,
|
|
technical = true,
|
|
transitions = true,
|
|
style = true,
|
|
...otherConfig
|
|
} = options;
|
|
|
|
return await generateWithAdversarialContext({
|
|
hierarchy,
|
|
csvData,
|
|
adversarialConfig: {
|
|
detectorTarget,
|
|
intensity,
|
|
enableAdaptiveStrategy: true,
|
|
contextualMode: true,
|
|
steps: {
|
|
initial: true,
|
|
technical,
|
|
transitions,
|
|
style
|
|
},
|
|
...otherConfig
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* DIAGNOSTIC PIPELINE ADVERSARIAL
|
|
*/
|
|
async function diagnosticAdversarialPipeline(hierarchy, csvData, detectorTargets = ['general', 'gptZero', 'originality']) {
|
|
logSh(`🔬 DIAGNOSTIC ADVERSARIAL: Testing ${detectorTargets.length} détecteurs`, 'INFO');
|
|
|
|
const results = {};
|
|
|
|
for (const target of detectorTargets) {
|
|
try {
|
|
logSh(` 🎯 Test détecteur: ${target}`, 'DEBUG');
|
|
|
|
const result = await generateWithAdversarialContext({
|
|
hierarchy,
|
|
csvData,
|
|
adversarialConfig: {
|
|
detectorTarget: target,
|
|
intensity: 1.0,
|
|
enableAllSteps: true
|
|
}
|
|
});
|
|
|
|
results[target] = {
|
|
success: true,
|
|
content: result.content,
|
|
stats: result.stats,
|
|
effectivenessScore: result.adversarialMetrics.effectivenessScore
|
|
};
|
|
|
|
logSh(` ✅ ${target}: Score ${result.adversarialMetrics.effectivenessScore.toFixed(2)}%`, 'DEBUG');
|
|
|
|
} catch (error) {
|
|
results[target] = {
|
|
success: false,
|
|
error: error.message,
|
|
effectivenessScore: 0
|
|
};
|
|
|
|
logSh(` ❌ ${target}: Échec - ${error.message}`, 'ERROR');
|
|
}
|
|
}
|
|
|
|
return results;
|
|
}
|
|
|
|
// ============= HELPER FUNCTIONS =============
|
|
|
|
/**
|
|
* Calculer efficacité adversariale
|
|
*/
|
|
function calculateAdversarialEffectiveness(pipelineStats, config, content) {
|
|
let effectiveness = 0;
|
|
|
|
// Base score selon intensité
|
|
effectiveness += config.intensity * 30;
|
|
|
|
// Bonus selon nombre d'étapes
|
|
const stepsExecuted = Object.keys(config.steps).filter(k => config.steps[k]).length;
|
|
effectiveness += stepsExecuted * 10;
|
|
|
|
// Bonus selon prompts adversariaux générés
|
|
const promptRatio = pipelineStats.adversarialMetrics.promptsGenerated / Math.max(1, pipelineStats.elementsProcessed);
|
|
effectiveness += promptRatio * 20;
|
|
|
|
// Analyse contenu si disponible
|
|
if (Object.keys(content).length > 0) {
|
|
const contentSample = Object.values(content).join(' ').substring(0, 1000);
|
|
const diversityScore = analyzeDiversityScore(contentSample);
|
|
effectiveness += diversityScore * 0.3;
|
|
}
|
|
|
|
return Math.min(100, Math.max(0, effectiveness));
|
|
}
|
|
|
|
/**
|
|
* Analyser score de diversité
|
|
*/
|
|
function analyzeDiversityScore(content) {
|
|
if (!content || typeof content !== 'string') return 0;
|
|
|
|
const words = content.split(/\s+/).filter(w => w.length > 2);
|
|
if (words.length === 0) return 0;
|
|
|
|
const uniqueWords = [...new Set(words.map(w => w.toLowerCase()))];
|
|
const diversityRatio = uniqueWords.length / words.length;
|
|
|
|
return diversityRatio * 100;
|
|
}
|
|
|
|
/**
|
|
* Obtenir informations détecteurs supportés
|
|
*/
|
|
function getAdversarialDetectorInfo() {
|
|
return getSupportedDetectors();
|
|
}
|
|
|
|
/**
|
|
* Comparer efficacité de différents détecteurs
|
|
*/
|
|
async function compareAdversarialStrategies(hierarchy, csvData, detectorTargets = ['general', 'gptZero', 'originality', 'winston']) {
|
|
const results = await diagnosticAdversarialPipeline(hierarchy, csvData, detectorTargets);
|
|
|
|
const comparison = {
|
|
bestStrategy: null,
|
|
bestScore: 0,
|
|
strategies: [],
|
|
averageScore: 0
|
|
};
|
|
|
|
let totalScore = 0;
|
|
let successCount = 0;
|
|
|
|
detectorTargets.forEach(target => {
|
|
const result = results[target];
|
|
if (result.success) {
|
|
const strategyInfo = {
|
|
detector: target,
|
|
effectivenessScore: result.effectivenessScore,
|
|
duration: result.stats.totalDuration,
|
|
elementsProcessed: result.stats.elementsProcessed
|
|
};
|
|
|
|
comparison.strategies.push(strategyInfo);
|
|
totalScore += result.effectivenessScore;
|
|
successCount++;
|
|
|
|
if (result.effectivenessScore > comparison.bestScore) {
|
|
comparison.bestStrategy = target;
|
|
comparison.bestScore = result.effectivenessScore;
|
|
}
|
|
}
|
|
});
|
|
|
|
comparison.averageScore = successCount > 0 ? totalScore / successCount : 0;
|
|
|
|
return comparison;
|
|
}
|
|
|
|
module.exports = {
|
|
generateWithAdversarialContext, // ← MAIN ENTRY POINT
|
|
generateSimpleAdversarial,
|
|
generateAdvancedAdversarial,
|
|
diagnosticAdversarialPipeline,
|
|
compareAdversarialStrategies,
|
|
getAdversarialDetectorInfo,
|
|
calculateAdversarialEffectiveness
|
|
}; |