seo-generator-server/lib/Main.js

1021 lines
42 KiB
JavaScript

// ========================================
// MAIN MODULAIRE - PIPELINE ARCHITECTURALE MODERNE
// Responsabilité: Orchestration workflow avec architecture modulaire complète
// Usage: node main_modulaire.js [rowNumber] [stackType]
// ========================================
const { logSh } = require('./ErrorReporting');
const { tracer } = require('./trace');
// Imports pipeline de base
const { readInstructionsData, selectPersonalityWithAI, getPersonalities } = require('./BrainConfig');
const { extractElements, buildSmartHierarchy } = require('./ElementExtraction');
const { generateMissingKeywords } = require('./MissingKeywords');
// ContentGeneration.js supprimé - Utiliser generateSimple depuis selective-enhancement
const { generateSimple } = require('./selective-enhancement/SelectiveUtils');
const { injectGeneratedContent } = require('./ContentAssembly');
const { saveGeneratedArticleOrganic } = require('./ArticleStorage');
// Imports modules modulaires
const { applySelectiveLayer } = require('./selective-enhancement/SelectiveCore');
const {
applyPredefinedStack,
applyAdaptiveLayers,
getAvailableStacks
} = require('./selective-enhancement/SelectiveLayers');
const {
applyAdversarialLayer
} = require('./adversarial-generation/AdversarialCore');
const {
applyPredefinedStack: applyAdversarialStack
} = require('./adversarial-generation/AdversarialLayers');
const {
applyHumanSimulationLayer
} = require('./human-simulation/HumanSimulationCore');
const {
applyPredefinedSimulation,
getAvailableSimulationStacks,
recommendSimulationStack
} = require('./human-simulation/HumanSimulationLayers');
const {
applyPatternBreakingLayer
} = require('./pattern-breaking/PatternBreakingCore');
const {
applyPatternBreakingStack,
recommendPatternBreakingStack,
listAvailableStacks: listPatternBreakingStacks
} = require('./pattern-breaking/PatternBreakingLayers');
/**
* WORKFLOW MODULAIRE AVEC DONNÉES FOURNIES (COMPATIBILITÉ MAKE.COM/DIGITAL OCEAN)
*/
async function handleModularWorkflowWithData(data, config = {}) {
return await tracer.run('Main.handleModularWorkflowWithData()', async () => {
const {
selectiveStack = 'standardEnhancement',
adversarialMode = 'light',
humanSimulationMode = 'none',
patternBreakingMode = 'none',
saveIntermediateSteps = false,
source = 'compatibility_mode'
} = config;
await tracer.annotate({
modularWorkflow: true,
compatibilityMode: true,
selectiveStack,
adversarialMode,
humanSimulationMode,
patternBreakingMode,
source
});
const startTime = Date.now();
logSh(`🚀 WORKFLOW MODULAIRE COMPATIBILITÉ DÉMARRÉ`, 'INFO');
logSh(` 📊 Source: ${source} | Selective: ${selectiveStack} | Adversarial: ${adversarialMode}`, 'INFO');
try {
// Utiliser les données fournies directement (skippping phases 1-4)
const csvData = data.csvData;
const xmlTemplate = data.xmlTemplate;
// Décoder XML si nécessaire
let xmlString = xmlTemplate;
if (xmlTemplate && !xmlTemplate.startsWith('<?xml') && !xmlTemplate.startsWith('<')) {
xmlString = Buffer.from(xmlTemplate, 'base64').toString('utf8');
}
csvData.xmlTemplate = xmlString;
// ========================================
// PHASE 2-4: EXTRACTION ÉLÉMENTS (SIMPLIFIÉ)
// ========================================
logSh(`📝 PHASE 2-4: Extraction éléments et préparation`, 'INFO');
const elements = await extractElements(xmlString, csvData);
const finalElements = await generateMissingKeywords(elements, csvData);
// S'assurer que finalElements est un array
const elementsArray = Array.isArray(finalElements) ? finalElements :
(finalElements && typeof finalElements === 'object') ? Object.values(finalElements) : [];
const hierarchy = await buildSmartHierarchy(elementsArray);
logSh(`${Object.keys(hierarchy).length} sections hiérarchisées`, 'DEBUG');
// ========================================
// PHASE 5-8B: WORKFLOW MODULAIRE COMPLET
// ========================================
// Continuer avec le workflow modulaire normal
const generationResult = await generateSimple(hierarchy, csvData);
const generatedContent = generationResult.content || generationResult;
logSh(`${Object.keys(generatedContent).length} éléments générés`, 'DEBUG');
// Appliquer toutes les couches modulaires comme dans le workflow normal
let finalContent = generatedContent;
let versionHistory = [];
let parentArticleId = null;
// SELECTIVE ENHANCEMENT
logSh(`🔧 PHASE 6: Selective Enhancement Modulaire (${selectiveStack})`, 'INFO');
let selectiveResult;
if (selectiveStack === 'adaptive') {
selectiveResult = await applyAdaptiveLayers(finalContent, {
maxIntensity: 1.1,
analysisThreshold: 0.3,
csvData
});
} else {
selectiveResult = await applyPredefinedStack(finalContent, selectiveStack, {
csvData,
analysisMode: true
});
}
finalContent = selectiveResult.content;
logSh(` ✅ Selective: ${selectiveResult.stats.elementsEnhanced || selectiveResult.stats.totalModifications || 0} améliorations`, 'INFO');
// ADVERSARIAL ENHANCEMENT
if (adversarialMode !== 'none') {
logSh(`🎯 PHASE 7: Adversarial Enhancement (${adversarialMode})`, 'INFO');
let adversarialResult;
if (adversarialMode === 'adaptive') {
adversarialResult = await applyAdversarialLayer(finalContent, {
detectorTarget: 'general',
method: 'hybrid',
intensity: 0.8,
analysisMode: true
});
} else {
const stackMapping = {
light: 'lightDefense',
standard: 'standardDefense',
heavy: 'heavyDefense'
};
adversarialResult = await applyAdversarialStack(finalContent, stackMapping[adversarialMode], {
csvData
});
}
if (adversarialResult && !adversarialResult.fallback) {
finalContent = adversarialResult.content;
logSh(` ✅ Adversarial: ${adversarialResult.stats.elementsModified || 0} modifications`, 'INFO');
}
}
// HUMAN SIMULATION & PATTERN BREAKING (si demandés)
// ... Implémentations similaires au workflow complet
// ASSEMBLAGE FINAL
logSh(`🔗 PHASE 9: Assemblage et stockage final`, 'INFO');
const assembledContent = await injectGeneratedContent(xmlString, finalContent, finalElements);
const storageResult = await saveGeneratedArticleOrganic({ generatedTexts: finalContent }, csvData, {
version: '1.0',
stage: 'final_version',
source,
stageDescription: `Version finale compatibility mode`,
useVersionedSheet: false
});
logSh(` ✅ Stocké: ${storageResult.textLength} caractères`, 'DEBUG');
// RÉSUMÉ FINAL
const totalDuration = Date.now() - startTime;
const finalStats = {
source,
selectiveStack,
adversarialMode,
totalDuration,
elementsGenerated: Object.keys(generatedContent).length,
finalLength: storageResult.textLength,
personality: csvData.personality?.nom || 'Unknown'
};
logSh(`✅ WORKFLOW MODULAIRE COMPATIBILITÉ TERMINÉ (${totalDuration}ms)`, 'INFO');
await tracer.event('Workflow modulaire compatibilité terminé', finalStats);
return {
success: true,
stats: finalStats,
content: finalContent,
assembledContent,
storageResult,
xmlContent: assembledContent,
generatedTexts: finalContent,
elementsGenerated: finalElements.length,
personality: csvData.personality?.nom || 'Unknown',
csvData,
timestamp: new Date().toISOString(),
// Compatibilité avec l'ancien format de réponse
antiDetectionLevel: 'Selective_Enhancement',
llmsUsed: ['claude', 'openai', 'gemini', 'mistral'],
enhancementApplied: true,
workflowVersion: '2.0-Modular'
};
} catch (error) {
const duration = Date.now() - startTime;
logSh(`❌ WORKFLOW MODULAIRE COMPATIBILITÉ ÉCHOUÉ après ${duration}ms: ${error.message}`, 'ERROR');
logSh(`Stack trace: ${error.stack}`, 'ERROR');
await tracer.event('Workflow modulaire compatibilité échoué', {
error: error.message,
duration,
source
});
throw error;
}
}, { data, config });
}
/**
* WORKFLOW MODULAIRE PRINCIPAL
*/
async function handleModularWorkflow(config = {}) {
return await tracer.run('MainModulaire.handleModularWorkflow()', async () => {
const {
rowNumber = 2,
selectiveStack = 'standardEnhancement', // lightEnhancement, standardEnhancement, fullEnhancement, personalityFocus, fluidityFocus, adaptive
adversarialMode = 'light', // none, light, standard, heavy, adaptive
humanSimulationMode = 'none', // none, lightSimulation, standardSimulation, heavySimulation, adaptiveSimulation, personalityFocus, temporalFocus
patternBreakingMode = 'none', // none, lightPatternBreaking, standardPatternBreaking, heavyPatternBreaking, adaptivePatternBreaking, syntaxFocus, connectorsFocus
saveIntermediateSteps = true, // 🆕 NOUVELLE OPTION: Sauvegarder chaque étape
source = 'main_modulaire'
} = config;
await tracer.annotate({
modularWorkflow: true,
rowNumber,
selectiveStack,
adversarialMode,
humanSimulationMode,
patternBreakingMode,
source
});
const startTime = Date.now();
logSh(`🚀 WORKFLOW MODULAIRE DÉMARRÉ`, 'INFO');
logSh(` 📊 Ligne: ${rowNumber} | Selective: ${selectiveStack} | Adversarial: ${adversarialMode} | Human: ${humanSimulationMode} | Pattern: ${patternBreakingMode}`, 'INFO');
try {
// ========================================
// PHASE 1: PRÉPARATION DONNÉES
// ========================================
logSh(`📋 PHASE 1: Préparation données`, 'INFO');
const csvData = await readInstructionsData(rowNumber);
if (!csvData) {
throw new Error(`Impossible de lire les données ligne ${rowNumber}`);
}
const personalities = await getPersonalities();
const selectedPersonality = await selectPersonalityWithAI(
csvData.mc0,
csvData.t0,
personalities
);
csvData.personality = selectedPersonality;
logSh(` ✅ Données: ${csvData.mc0} | Personnalité: ${selectedPersonality.nom}`, 'DEBUG');
// ========================================
// PHASE 2: EXTRACTION ÉLÉMENTS
// ========================================
logSh(`📝 PHASE 2: Extraction éléments XML`, 'INFO');
const elements = await extractElements(csvData.xmlTemplate, csvData);
logSh(`${elements.length} éléments extraits`, 'DEBUG');
// ========================================
// PHASE 3: GÉNÉRATION MOTS-CLÉS MANQUANTS
// ========================================
logSh(`🔍 PHASE 3: Génération mots-clés manquants`, 'INFO');
const finalElements = await generateMissingKeywords(elements, csvData);
logSh(` ✅ Mots-clés complétés`, 'DEBUG');
// ========================================
// PHASE 4: CONSTRUCTION HIÉRARCHIE
// ========================================
logSh(`🏗️ PHASE 4: Construction hiérarchie`, 'INFO');
const hierarchy = await buildSmartHierarchy(finalElements);
logSh(`${Object.keys(hierarchy).length} sections hiérarchisées`, 'DEBUG');
// ========================================
// PHASE 5: GÉNÉRATION CONTENU DE BASE
// ========================================
logSh(`💫 PHASE 5: Génération contenu de base`, 'INFO');
const generatedContent = await generateSimple(hierarchy, csvData);
logSh(`${Object.keys(generatedContent).length} éléments générés`, 'DEBUG');
// 🆕 SAUVEGARDE ÉTAPE 1: Génération initiale
let parentArticleId = null;
let versionHistory = [];
if (saveIntermediateSteps) {
logSh(`💾 SAUVEGARDE v1.0: Génération initiale`, 'INFO');
const xmlString = csvData.xmlTemplate.startsWith('<?xml') ? csvData.xmlTemplate : Buffer.from(csvData.xmlTemplate, 'base64').toString('utf8');
const initialAssembledContent = await injectGeneratedContent(xmlString, generatedContent, finalElements);
const initialStorage = await saveGeneratedArticleOrganic({ generatedTexts: generatedContent }, csvData, {
version: 'v1.0',
stage: 'initial_generation',
source: `${source}_initial`,
stageDescription: 'Génération de contenu de base sans améliorations',
useVersionedSheet: true // 🆕 Utiliser Generated_Articles_Versioned
});
parentArticleId = initialStorage.articleId;
versionHistory.push({
version: 'v1.0',
stage: 'initial_generation',
articleId: initialStorage.articleId,
length: initialStorage.textLength,
wordCount: initialStorage.wordCount
});
logSh(` ✅ Sauvé v1.0 - ID: ${parentArticleId}`, 'DEBUG');
}
// ========================================
// PHASE 6: SELECTIVE ENHANCEMENT MODULAIRE
// ========================================
logSh(`🔧 PHASE 6: Selective Enhancement Modulaire (${selectiveStack})`, 'INFO');
let selectiveResult;
switch (selectiveStack) {
case 'adaptive':
selectiveResult = await applyAdaptiveLayers(generatedContent, {
maxIntensity: 1.1,
analysisThreshold: 0.3,
csvData
});
break;
case 'technical':
case 'transitions':
case 'style':
selectiveResult = await applySelectiveLayer(generatedContent, {
layerType: selectiveStack,
llmProvider: 'auto',
intensity: 1.0,
csvData
});
break;
default:
// Stack prédéfini
selectiveResult = await applyPredefinedStack(generatedContent, selectiveStack, {
csvData,
analysisMode: true
});
}
const enhancedContent = selectiveResult.content;
logSh(` ✅ Selective: ${selectiveResult.stats.elementsEnhanced || selectiveResult.stats.totalModifications || 0} améliorations`, 'INFO');
// 🆕 SAUVEGARDE ÉTAPE 2: Selective Enhancement
if (saveIntermediateSteps) {
logSh(`💾 SAUVEGARDE v1.1: Selective Enhancement`, 'INFO');
const xmlString = csvData.xmlTemplate.startsWith('<?xml') ? csvData.xmlTemplate : Buffer.from(csvData.xmlTemplate, 'base64').toString('utf8');
const selectiveAssembledContent = await injectGeneratedContent(xmlString, enhancedContent, finalElements);
const selectiveStorage = await saveGeneratedArticleOrganic({ generatedTexts: enhancedContent }, csvData, {
version: 'v1.1',
stage: 'selective_enhancement',
source: `${source}_selective_${selectiveStack}`,
stageDescription: `Amélioration selective (${selectiveStack}) - ${selectiveResult.stats.elementsEnhanced || selectiveResult.stats.totalModifications || 0} modifications`,
parentArticleId: parentArticleId,
useVersionedSheet: true // 🆕 Utiliser Generated_Articles_Versioned
});
versionHistory.push({
version: 'v1.1',
stage: 'selective_enhancement',
articleId: selectiveStorage.articleId,
length: selectiveStorage.textLength,
wordCount: selectiveStorage.wordCount,
modifications: selectiveResult.stats.elementsEnhanced || selectiveResult.stats.totalModifications || 0
});
logSh(` ✅ Sauvé v1.1 - ID: ${selectiveStorage.articleId}`, 'DEBUG');
}
// ========================================
// PHASE 7: ADVERSARIAL ENHANCEMENT (OPTIONNEL)
// ========================================
let finalContent = enhancedContent;
let adversarialStats = null;
if (adversarialMode !== 'none') {
logSh(`🎯 PHASE 7: Adversarial Enhancement (${adversarialMode})`, 'INFO');
let adversarialResult;
switch (adversarialMode) {
case 'adaptive':
// Utiliser adversarial adaptatif
adversarialResult = await applyAdversarialLayer(enhancedContent, {
detectorTarget: 'general',
method: 'hybrid',
intensity: 0.8,
analysisMode: true
});
break;
case 'light':
case 'standard':
case 'heavy':
// Utiliser stack adversarial prédéfini
const stackMapping = {
light: 'lightDefense',
standard: 'standardDefense',
heavy: 'heavyDefense'
};
adversarialResult = await applyAdversarialStack(enhancedContent, stackMapping[adversarialMode], {
csvData
});
break;
}
if (adversarialResult && !adversarialResult.fallback) {
finalContent = adversarialResult.content;
adversarialStats = adversarialResult.stats;
logSh(` ✅ Adversarial: ${adversarialStats.elementsModified || adversarialStats.totalModifications || 0} modifications`, 'INFO');
// 🆕 SAUVEGARDE ÉTAPE 3: Adversarial Enhancement
if (saveIntermediateSteps) {
logSh(`💾 SAUVEGARDE v1.2: Adversarial Enhancement`, 'INFO');
const xmlString = csvData.xmlTemplate.startsWith('<?xml') ? csvData.xmlTemplate : Buffer.from(csvData.xmlTemplate, 'base64').toString('utf8');
const adversarialAssembledContent = await injectGeneratedContent(xmlString, finalContent, finalElements);
const adversarialStorage = await saveGeneratedArticleOrganic({ generatedTexts: finalContent }, csvData, {
version: 'v1.2',
stage: 'adversarial_enhancement',
source: `${source}_adversarial_${adversarialMode}`,
stageDescription: `Amélioration adversarial (${adversarialMode}) - ${adversarialStats.elementsModified || adversarialStats.totalModifications || 0} modifications`,
parentArticleId: parentArticleId,
useVersionedSheet: true // 🆕 Utiliser Generated_Articles_Versioned
});
versionHistory.push({
version: 'v1.2',
stage: 'adversarial_enhancement',
articleId: adversarialStorage.articleId,
length: adversarialStorage.textLength,
wordCount: adversarialStorage.wordCount,
modifications: adversarialStats.elementsModified || adversarialStats.totalModifications || 0
});
logSh(` ✅ Sauvé v1.2 - ID: ${adversarialStorage.articleId}`, 'DEBUG');
}
} else {
logSh(` ⚠️ Adversarial fallback: contenu selective préservé`, 'WARNING');
}
}
// ========================================
// PHASE 8: HUMAN SIMULATION (NIVEAU 5)
// ========================================
let humanSimulationStats = null;
if (humanSimulationMode !== 'none') {
logSh(`🧠 PHASE 8: Human Simulation (${humanSimulationMode})`, 'INFO');
let humanSimulationResult;
try {
// Calculer éléments pour simulation fatigue
const totalElements = Object.keys(finalContent).length;
const elementIndex = Math.floor(totalElements * 0.6); // Position simulée milieu-fin pour fatigue
// Configuration simulation
const simulationConfig = {
elementIndex,
totalElements,
currentHour: new Date().getHours(),
csvData,
source: `human_simulation_${humanSimulationMode}`
};
// Application selon mode
switch (humanSimulationMode) {
case 'adaptiveSimulation':
// Recommandation automatique si adaptive
const context = {
contentLength: Object.values(finalContent).join('').length,
personality: csvData.personality?.nom,
hour: new Date().getHours(),
goal: 'adaptive'
};
const recommendedStack = recommendSimulationStack(context);
logSh(` 🤖 Recommandation adaptive: ${recommendedStack}`, 'DEBUG');
humanSimulationResult = await applyPredefinedSimulation(finalContent, recommendedStack, simulationConfig);
break;
case 'lightSimulation':
case 'standardSimulation':
case 'heavySimulation':
case 'personalityFocus':
case 'temporalFocus':
// Stack prédéfini
humanSimulationResult = await applyPredefinedSimulation(finalContent, humanSimulationMode, simulationConfig);
break;
default:
// Mode custom ou direct
humanSimulationResult = await applyHumanSimulationLayer(finalContent, simulationConfig);
}
// Vérification résultat
if (humanSimulationResult && !humanSimulationResult.fallback) {
finalContent = humanSimulationResult.content;
humanSimulationStats = humanSimulationResult.stats;
logSh(` ✅ Human Simulation: ${humanSimulationStats.totalModifications || 0} modifications`, 'INFO');
logSh(` 🎯 Score qualité: ${humanSimulationResult.qualityScore?.toFixed(2) || 'N/A'}`, 'INFO');
// 🆕 SAUVEGARDE ÉTAPE 4: Human Simulation
if (saveIntermediateSteps) {
logSh(`💾 SAUVEGARDE v1.3: Human Simulation`, 'INFO');
const xmlString = csvData.xmlTemplate.startsWith('<?xml') ? csvData.xmlTemplate : Buffer.from(csvData.xmlTemplate, 'base64').toString('utf8');
const humanAssembledContent = await injectGeneratedContent(xmlString, finalContent, finalElements);
const humanStorage = await saveGeneratedArticleOrganic({ generatedTexts: finalContent }, csvData, {
version: 'v1.3',
stage: 'human_simulation',
source: `${source}_human_${humanSimulationMode}`,
stageDescription: `Simulation humaine (${humanSimulationMode}) - ${humanSimulationStats.totalModifications || 0} modifications`,
parentArticleId: parentArticleId,
useVersionedSheet: true // 🆕 Utiliser Generated_Articles_Versioned
});
versionHistory.push({
version: 'v1.3',
stage: 'human_simulation',
articleId: humanStorage.articleId,
length: humanStorage.textLength,
wordCount: humanStorage.wordCount,
modifications: humanSimulationStats.totalModifications || 0,
qualityScore: humanSimulationResult.qualityScore
});
logSh(` ✅ Sauvé v1.3 - ID: ${humanStorage.articleId}`, 'DEBUG');
}
} else {
logSh(` ⚠️ Human Simulation fallback: contenu précédent préservé`, 'WARNING');
}
} catch (humanSimulationError) {
logSh(` ❌ Erreur Human Simulation: ${humanSimulationError.message}`, 'ERROR');
logSh(` 🔄 Fallback: contenu adversarial préservé`, 'INFO');
}
}
// ========================================
// PHASE 8B: PATTERN BREAKING (NIVEAU 2)
// ========================================
let patternBreakingStats = null;
if (patternBreakingMode !== 'none') {
logSh(`🔧 PHASE 8B: Pattern Breaking (${patternBreakingMode})`, 'INFO');
let patternBreakingResult;
try {
// Configuration Pattern Breaking
const patternConfig = {
csvData,
source: `pattern_breaking_${patternBreakingMode}`,
personality: csvData.personality
};
// Application selon mode
switch (patternBreakingMode) {
case 'adaptivePatternBreaking':
// Recommandation automatique si adaptive
const patternContext = {
contentLength: Object.values(finalContent).join('').length,
critical: false,
preserveQuality: true
};
const recommendedPattern = recommendPatternBreakingStack(Object.values(finalContent).join(' '), patternContext);
logSh(` 🤖 Recommandation Pattern Breaking: ${recommendedPattern.recommendedStack}`, 'DEBUG');
patternBreakingResult = await applyPatternBreakingStack(recommendedPattern.recommendedStack, finalContent, patternConfig);
break;
case 'lightPatternBreaking':
case 'standardPatternBreaking':
case 'heavyPatternBreaking':
case 'syntaxFocus':
case 'connectorsFocus':
// Stack prédéfini
patternBreakingResult = await applyPatternBreakingStack(patternBreakingMode, finalContent, patternConfig);
break;
default:
// Mode custom ou direct
patternBreakingResult = await applyPatternBreakingLayer(finalContent, patternConfig);
}
// Vérification résultat
if (patternBreakingResult && !patternBreakingResult.fallback) {
finalContent = patternBreakingResult.content;
patternBreakingStats = patternBreakingResult.stats;
logSh(` ✅ Pattern Breaking: ${patternBreakingStats.totalModifications || 0} modifications`, 'INFO');
logSh(` 🎯 Patterns détectés: ${patternBreakingStats.patternsDetected || 0}`, 'INFO');
// 🆕 SAUVEGARDE ÉTAPE 5: Pattern Breaking
if (saveIntermediateSteps) {
logSh(`💾 SAUVEGARDE v1.4: Pattern Breaking`, 'INFO');
const xmlString = csvData.xmlTemplate.startsWith('<?xml') ? csvData.xmlTemplate : Buffer.from(csvData.xmlTemplate, 'base64').toString('utf8');
const patternAssembledContent = await injectGeneratedContent(xmlString, finalContent, finalElements);
const patternStorage = await saveGeneratedArticleOrganic({ generatedTexts: finalContent }, csvData, {
version: 'v1.4',
stage: 'pattern_breaking',
source: `${source}_pattern_${patternBreakingMode}`,
stageDescription: `Pattern Breaking (${patternBreakingMode}) - ${patternBreakingStats.totalModifications || 0} modifications`,
parentArticleId: parentArticleId,
useVersionedSheet: true // 🆕 Utiliser Generated_Articles_Versioned
});
versionHistory.push({
version: 'v1.4',
stage: 'pattern_breaking',
articleId: patternStorage.articleId,
length: patternStorage.textLength,
wordCount: patternStorage.wordCount,
modifications: patternBreakingStats.totalModifications || 0,
patternsDetected: patternBreakingStats.patternsDetected || 0
});
logSh(` ✅ Sauvé v1.4 - ID: ${patternStorage.articleId}`, 'DEBUG');
}
} else {
logSh(` ⚠️ Pattern Breaking fallback: contenu précédent préservé`, 'WARNING');
}
} catch (patternBreakingError) {
logSh(` ❌ Erreur Pattern Breaking: ${patternBreakingError.message}`, 'ERROR');
logSh(` 🔄 Fallback: contenu précédent préservé`, 'INFO');
}
}
// ========================================
// PHASE 9: ASSEMBLAGE ET STOCKAGE FINAL
// ========================================
logSh(`🔗 PHASE 9: Assemblage et stockage final`, 'INFO');
// D'abord récupérer le XML décodé et les finalElements
const xmlString = csvData.xmlTemplate.startsWith('<?xml') ? csvData.xmlTemplate : Buffer.from(csvData.xmlTemplate, 'base64').toString('utf8');
const assembledContent = await injectGeneratedContent(xmlString, finalContent, finalElements);
// 🆕 SAUVEGARDE VERSION FINALE
const finalSourceTag = `${source}_${selectiveStack}${adversarialMode !== 'none' ? `_${adversarialMode}` : ''}${humanSimulationMode !== 'none' ? `_${humanSimulationMode}` : ''}${patternBreakingMode !== 'none' ? `_${patternBreakingMode}` : ''}`;
const storageResult = await saveGeneratedArticleOrganic({ generatedTexts: finalContent }, csvData, {
version: saveIntermediateSteps ? 'v2.0' : '1.0',
stage: 'final_version',
source: finalSourceTag,
stageDescription: `Version finale complète avec toutes améliorations`,
parentArticleId: parentArticleId,
versionHistory: saveIntermediateSteps ? versionHistory : undefined,
useVersionedSheet: false // 🆕 Version finale → Generated_Articles (comme avant)
});
// Ajouter la version finale à l'historique
if (saveIntermediateSteps) {
versionHistory.push({
version: 'v2.0',
stage: 'final_version',
articleId: storageResult.articleId,
length: storageResult.textLength,
wordCount: storageResult.wordCount
});
logSh(`💾 SAUVEGARDE v2.0: Version finale`, 'INFO');
logSh(` 📋 Historique complet: ${versionHistory.length} versions`, 'INFO');
}
logSh(` ✅ Stocké: ${storageResult.textLength} caractères`, 'DEBUG');
// ========================================
// RÉSUMÉ FINAL
// ========================================
const totalDuration = Date.now() - startTime;
const finalStats = {
rowNumber,
selectiveStack,
adversarialMode,
humanSimulationMode,
patternBreakingMode,
totalDuration,
elementsGenerated: Object.keys(generatedContent).length,
selectiveEnhancements: selectiveResult.stats.elementsEnhanced || selectiveResult.stats.totalModifications || 0,
adversarialModifications: adversarialStats?.elementsModified || adversarialStats?.totalModifications || 0,
humanSimulationModifications: humanSimulationStats?.totalModifications || 0,
patternBreakingModifications: patternBreakingStats?.totalModifications || 0,
finalLength: storageResult.textLength,
personality: selectedPersonality.nom,
source,
versionHistory: saveIntermediateSteps ? versionHistory : undefined,
parentArticleId: parentArticleId
};
logSh(`✅ WORKFLOW MODULAIRE TERMINÉ (${totalDuration}ms)`, 'INFO');
logSh(` 📊 ${finalStats.elementsGenerated} générés | ${finalStats.selectiveEnhancements} selective | ${finalStats.adversarialModifications} adversarial | ${finalStats.humanSimulationModifications} humain | ${finalStats.patternBreakingModifications} pattern`, 'INFO');
logSh(` 🎭 Personnalité: ${finalStats.personality} | Taille finale: ${finalStats.finalLength} chars`, 'INFO');
await tracer.event('Workflow modulaire terminé', finalStats);
return {
success: true,
stats: finalStats,
content: finalContent,
assembledContent,
storageResult,
selectiveResult,
adversarialResult: adversarialStats ? { stats: adversarialStats } : null,
humanSimulationResult: humanSimulationStats ? { stats: humanSimulationStats } : null,
patternBreakingResult: patternBreakingStats ? { stats: patternBreakingStats } : null
};
} catch (error) {
const duration = Date.now() - startTime;
logSh(`❌ WORKFLOW MODULAIRE ÉCHOUÉ après ${duration}ms: ${error.message}`, 'ERROR');
logSh(`Stack trace: ${error.stack}`, 'ERROR');
await tracer.event('Workflow modulaire échoué', {
error: error.message,
duration,
rowNumber,
selectiveStack,
adversarialMode,
humanSimulationMode,
patternBreakingMode
});
throw error;
}
}, { config });
}
/**
* BENCHMARK COMPARATIF STACKS
*/
async function benchmarkStacks(rowNumber = 2) {
console.log('\n⚡ === BENCHMARK STACKS MODULAIRES ===\n');
const stacks = getAvailableStacks();
const adversarialModes = ['none', 'light', 'standard'];
const humanSimulationModes = ['none', 'lightSimulation', 'standardSimulation'];
const patternBreakingModes = ['none', 'lightPatternBreaking', 'standardPatternBreaking'];
const results = [];
for (const stack of stacks.slice(0, 2)) { // Tester 2 stacks principaux
for (const advMode of adversarialModes.slice(0, 2)) { // 2 modes adversarial
for (const humanMode of humanSimulationModes.slice(0, 2)) { // 2 modes human simulation
for (const patternMode of patternBreakingModes.slice(0, 2)) { // 2 modes pattern breaking
console.log(`🧪 Test: ${stack.name} + adversarial ${advMode} + human ${humanMode} + pattern ${patternMode}`);
try {
const startTime = Date.now();
const result = await handleModularWorkflow({
rowNumber,
selectiveStack: stack.name,
adversarialMode: advMode,
humanSimulationMode: humanMode,
patternBreakingMode: patternMode,
source: 'benchmark'
});
const duration = Date.now() - startTime;
results.push({
stack: stack.name,
adversarial: advMode,
humanSimulation: humanMode,
patternBreaking: patternMode,
duration,
success: true,
selectiveEnhancements: result.stats.selectiveEnhancements,
adversarialModifications: result.stats.adversarialModifications,
humanSimulationModifications: result.stats.humanSimulationModifications,
patternBreakingModifications: result.stats.patternBreakingModifications,
finalLength: result.stats.finalLength
});
console.log(`${duration}ms | ${result.stats.selectiveEnhancements} selective | ${result.stats.adversarialModifications} adversarial | ${result.stats.humanSimulationModifications} humain | ${result.stats.patternBreakingModifications} pattern`);
} catch (error) {
results.push({
stack: stack.name,
adversarial: advMode,
humanSimulation: humanMode,
patternBreaking: patternMode,
success: false,
error: error.message
});
console.log(` ❌ Échoué: ${error.message}`);
}
}
}
}
}
// Résumé benchmark
console.log('\n📊 RÉSUMÉ BENCHMARK:');
const successful = results.filter(r => r.success);
if (successful.length > 0) {
const avgDuration = successful.reduce((sum, r) => sum + r.duration, 0) / successful.length;
const bestPerf = successful.reduce((best, r) => r.duration < best.duration ? r : best);
const mostEnhancements = successful.reduce((best, r) => {
const rTotal = r.selectiveEnhancements + r.adversarialModifications + (r.humanSimulationModifications || 0) + (r.patternBreakingModifications || 0);
const bestTotal = best.selectiveEnhancements + best.adversarialModifications + (best.humanSimulationModifications || 0) + (best.patternBreakingModifications || 0);
return rTotal > bestTotal ? r : best;
});
console.log(` ⚡ Durée moyenne: ${avgDuration.toFixed(0)}ms`);
console.log(` 🏆 Meilleure perf: ${bestPerf.stack} + ${bestPerf.adversarial} + ${bestPerf.humanSimulation} + ${bestPerf.patternBreaking} (${bestPerf.duration}ms)`);
console.log(` 🔥 Plus d'améliorations: ${mostEnhancements.stack} + ${mostEnhancements.adversarial} + ${mostEnhancements.humanSimulation} + ${mostEnhancements.patternBreaking} (${mostEnhancements.selectiveEnhancements + mostEnhancements.adversarialModifications + (mostEnhancements.humanSimulationModifications || 0) + (mostEnhancements.patternBreakingModifications || 0)})`);
}
return results;
}
/**
* INTERFACE LIGNE DE COMMANDE
*/
async function main() {
const args = process.argv.slice(2);
const command = args[0] || 'workflow';
try {
switch (command) {
case 'workflow':
const rowNumber = parseInt(args[1]) || 2;
const selectiveStack = args[2] || 'standardEnhancement';
const adversarialMode = args[3] || 'light';
const humanSimulationMode = args[4] || 'none';
const patternBreakingMode = args[5] || 'none';
console.log(`\n🚀 Exécution workflow modulaire:`);
console.log(` 📊 Ligne: ${rowNumber}`);
console.log(` 🔧 Stack selective: ${selectiveStack}`);
console.log(` 🎯 Mode adversarial: ${adversarialMode}`);
console.log(` 🧠 Mode human simulation: ${humanSimulationMode}`);
console.log(` 🔧 Mode pattern breaking: ${patternBreakingMode}`);
const result = await handleModularWorkflow({
rowNumber,
selectiveStack,
adversarialMode,
humanSimulationMode,
patternBreakingMode,
source: 'cli'
});
console.log('\n✅ WORKFLOW MODULAIRE RÉUSSI');
console.log(`📈 Stats: ${JSON.stringify(result.stats, null, 2)}`);
break;
case 'benchmark':
const benchRowNumber = parseInt(args[1]) || 2;
console.log(`\n⚡ Benchmark stacks (ligne ${benchRowNumber})`);
const benchResults = await benchmarkStacks(benchRowNumber);
console.log('\n📊 Résultats complets:');
console.table(benchResults);
break;
case 'stacks':
console.log('\n📦 STACKS SELECTIVE DISPONIBLES:');
const availableStacks = getAvailableStacks();
availableStacks.forEach(stack => {
console.log(`\n 🔧 ${stack.name}:`);
console.log(` 📝 ${stack.description}`);
console.log(` 📊 ${stack.layersCount} couches`);
console.log(` 🎯 Couches: ${stack.layers ? stack.layers.map(l => `${l.type}(${l.llm})`).join(' → ') : 'N/A'}`);
});
console.log('\n🎯 MODES ADVERSARIAL DISPONIBLES:');
console.log(' - none: Pas d\'adversarial');
console.log(' - light: Défense légère');
console.log(' - standard: Défense standard');
console.log(' - heavy: Défense intensive');
console.log(' - adaptive: Adaptatif intelligent');
console.log('\n🧠 MODES HUMAN SIMULATION DISPONIBLES:');
const humanStacks = getAvailableSimulationStacks();
humanStacks.forEach(stack => {
console.log(`\n 🎭 ${stack.name}:`);
console.log(` 📝 ${stack.description}`);
console.log(` 📊 ${stack.layersCount} couches`);
console.log(`${stack.expectedImpact.modificationsPerElement} modifs | ${stack.expectedImpact.detectionReduction} anti-détection`);
});
break;
case 'help':
default:
console.log('\n🔧 === MAIN MODULAIRE - USAGE ===');
console.log('\nCommandes disponibles:');
console.log(' workflow [ligne] [stack] [adversarial] [human] - Exécuter workflow complet');
console.log(' benchmark [ligne] - Benchmark stacks');
console.log(' stacks - Lister stacks disponibles');
console.log(' help - Afficher cette aide');
console.log('\nExemples:');
console.log(' node main_modulaire.js workflow 2 standardEnhancement light standardSimulation');
console.log(' node main_modulaire.js workflow 3 adaptive standard heavySimulation');
console.log(' node main_modulaire.js workflow 2 fullEnhancement none personalityFocus');
console.log(' node main_modulaire.js benchmark 2');
console.log(' node main_modulaire.js stacks');
break;
}
} catch (error) {
console.error('\n❌ ERREUR MAIN MODULAIRE:', error.message);
console.error(error.stack);
process.exit(1);
}
}
// Export pour usage programmatique (compatibilité avec l'ancien Main.js)
module.exports = {
// ✨ NOUVEAU: Interface modulaire principale
handleModularWorkflow,
benchmarkStacks,
// 🔄 COMPATIBILITÉ: Alias pour l'ancien handleFullWorkflow
handleFullWorkflow: (data) => {
// Mapper l'ancien format vers le nouveau format modulaire
const config = {
rowNumber: data.rowNumber,
source: data.source || 'compatibility_mode',
selectiveStack: 'standardEnhancement', // Configuration par défaut
adversarialMode: 'light',
humanSimulationMode: 'none',
patternBreakingMode: 'none',
saveIntermediateSteps: false
};
// Si des données CSV sont fournies directement (Make.com style)
if (data.csvData && data.xmlTemplate) {
return handleModularWorkflowWithData(data, config);
}
// Sinon utiliser le workflow normal
return handleModularWorkflow(config);
},
// 🔄 COMPATIBILITÉ: Autres exports utilisés par l'ancien système
testMainWorkflow: () => {
return handleModularWorkflow({
rowNumber: 2,
selectiveStack: 'standardEnhancement',
source: 'test_main_nodejs'
});
},
launchLogViewer: () => {
// La fonction launchLogViewer est maintenant intégrée dans handleModularWorkflow
console.log('✅ Log viewer sera lancé automatiquement avec le workflow');
}
};
// Exécution CLI si appelé directement
if (require.main === module) {
main().catch(error => {
console.error('❌ ERREUR FATALE:', error.message);
process.exit(1);
});
}