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>
794 lines
35 KiB
JavaScript
794 lines
35 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');
|
|
const { generateSimple } = require('./ContentGeneration');
|
|
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 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
|
|
module.exports = {
|
|
handleModularWorkflow,
|
|
benchmarkStacks
|
|
};
|
|
|
|
// Exécution CLI si appelé directement
|
|
if (require.main === module) {
|
|
main().catch(error => {
|
|
console.error('❌ ERREUR FATALE:', error.message);
|
|
process.exit(1);
|
|
});
|
|
} |