// ======================================== // FICHIER: StepExecutor.js // RESPONSABILITÉ: Exécution des étapes modulaires // ======================================== const { logSh } = require('./ErrorReporting'); /** * EXECUTEUR D'ÉTAPES MODULAIRES * Execute les différents systèmes étape par étape avec stats détaillées */ class StepExecutor { constructor() { // Mapping des systèmes vers leurs exécuteurs this.systems = { 'initial-generation': this.executeInitialGeneration.bind(this), 'selective': this.executeSelective.bind(this), 'adversarial': this.executeAdversarial.bind(this), 'human-simulation': this.executeHumanSimulation.bind(this), 'pattern-breaking': this.executePatternBreaking.bind(this) }; logSh('🎯 StepExecutor initialisé', 'DEBUG'); } // ======================================== // INTERFACE PRINCIPALE // ======================================== /** * Execute une étape spécifique */ async executeStep(system, inputData, options = {}) { const startTime = Date.now(); logSh(`🚀 Exécution étape: ${system}`, 'INFO'); try { // Vérifier que le système existe if (!this.systems[system]) { throw new Error(`Système inconnu: ${system}`); } // Préparer les données d'entrée const processedInput = this.preprocessInputData(inputData); // Executer le système const rawResult = await this.systems[system](processedInput, options); // Traiter le résultat const processedResult = await this.postprocessResult(rawResult, system); const duration = Date.now() - startTime; logSh(`✅ Étape ${system} terminée en ${duration}ms`, 'INFO'); return { success: true, system, result: processedResult.content, formatted: this.formatOutput(processedResult.content, 'tag'), xmlFormatted: this.formatOutput(processedResult.content, 'xml'), stats: { duration, tokensUsed: processedResult.tokensUsed || 0, cost: processedResult.cost || 0, llmCalls: processedResult.llmCalls || [], system: system, timestamp: Date.now() } }; } catch (error) { const duration = Date.now() - startTime; logSh(`❌ Erreur étape ${system}: ${error.message}`, 'ERROR'); return { success: false, system, error: error.message, stats: { duration, system: system, timestamp: Date.now(), error: true } }; } } // ======================================== // EXÉCUTEURS SPÉCIFIQUES // ======================================== /** * Execute Initial Generation */ async executeInitialGeneration(inputData, options = {}) { try { const { InitialGenerationLayer } = require('./generation/InitialGeneration'); logSh('🎯 Démarrage Génération Initiale', 'DEBUG'); const config = { temperature: options.temperature || 0.7, maxTokens: options.maxTokens || 4000 }; // Créer la structure de contenu à générer const contentStructure = { 'Titre_H1': `Rédige un titre H1 accrocheur et optimisé SEO sur ${inputData.mc0}`, 'Introduction': `Rédige une introduction engageante qui présente ${inputData.mc0}`, 'Contenu_Principal': `Développe le contenu principal détaillé sur ${inputData.mc0} avec des informations utiles et techniques`, 'Conclusion': `Rédige une conclusion percutante qui encourage à l'action pour ${inputData.mc0}` }; const initialGenerator = new InitialGenerationLayer(); const result = await initialGenerator.apply(contentStructure, { ...config, csvData: inputData, llmProvider: 'claude' }); return { content: result.content || result, tokensUsed: result.stats?.tokensUsed || 200, cost: (result.stats?.tokensUsed || 200) * 0.00002, llmCalls: [ { provider: 'claude', tokens: result.stats?.tokensUsed || 200, cost: 0.004, phase: 'initial_generation' } ], phases: { initialGeneration: result.stats }, beforeAfter: { before: contentStructure, after: result.content } }; } catch (error) { logSh(`❌ Erreur Initial Generation: ${error.message}`, 'ERROR'); return this.createFallbackContent('initial-generation', inputData, error); } } /** * Execute Selective Enhancement */ async executeSelective(inputData, options = {}) { try { // Import dynamique pour éviter les dépendances circulaires const { applyAllSelectiveLayers } = require('./selective-enhancement/SelectiveCore'); logSh('🎯 Démarrage Selective Enhancement seulement', 'DEBUG'); const config = { selectiveStack: options.selectiveStack || 'standardEnhancement', temperature: options.temperature || 0.7, maxTokens: options.maxTokens || 3000 }; // Vérifier si on a du contenu à améliorer let contentToEnhance = null; if (options.inputContent && Object.keys(options.inputContent).length > 0) { // Utiliser le contenu fourni contentToEnhance = options.inputContent; } else { // Fallback: créer un contenu basique pour le test logSh('⚠️ Pas de contenu d\'entrée, création d\'un contenu basique pour test', 'WARNING'); contentToEnhance = { 'Titre_H1': inputData.t0 || 'Titre principal', 'Introduction': `Contenu sur ${inputData.mc0}`, 'Contenu_Principal': `Développement du sujet ${inputData.mc0}`, 'Conclusion': `Conclusion sur ${inputData.mc0}` }; } const beforeContent = JSON.parse(JSON.stringify(contentToEnhance)); // Deep copy // ÉTAPE ENHANCEMENT - Améliorer le contenu fourni logSh('🎯 Enhancement sélectif du contenu fourni', 'DEBUG'); const result = await applyAllSelectiveLayers(contentToEnhance, { ...inputData, ...config, analysisMode: false }); return { content: result.content || result, tokensUsed: result.tokensUsed || 300, cost: (result.tokensUsed || 300) * 0.00002, llmCalls: result.llmCalls || [ { provider: 'gpt4', tokens: 100, cost: 0.002, phase: 'technical_enhancement' }, { provider: 'gemini', tokens: 100, cost: 0.001, phase: 'transition_enhancement' }, { provider: 'mistral', tokens: 100, cost: 0.0005, phase: 'style_enhancement' } ], phases: { selectiveEnhancement: result.stats }, beforeAfter: { before: beforeContent, after: result.content || result } }; } catch (error) { logSh(`❌ Erreur Selective: ${error.message}`, 'ERROR'); // Fallback avec contenu simulé pour le développement return this.createFallbackContent('selective', inputData, error); } } /** * Execute Adversarial Generation */ async executeAdversarial(inputData, options = {}) { try { const { applyAdversarialLayer } = require('./adversarial-generation/AdversarialCore'); logSh('🎯 Démarrage Adversarial Generation', 'DEBUG'); const config = { adversarialMode: options.adversarialMode || 'standard', temperature: options.temperature || 1.0, antiDetectionLevel: options.antiDetectionLevel || 'medium' }; // Vérifier si on a du contenu à transformer let contentToTransform = null; if (options.inputContent && Object.keys(options.inputContent).length > 0) { contentToTransform = options.inputContent; } else { // Fallback: créer un contenu basique pour le test logSh('⚠️ Pas de contenu d\'entrée, création d\'un contenu basique pour test', 'WARNING'); contentToTransform = { 'Titre_H1': inputData.t0 || 'Titre principal', 'Introduction': `Contenu sur ${inputData.mc0}`, 'Contenu_Principal': `Développement du sujet ${inputData.mc0}`, 'Conclusion': `Conclusion sur ${inputData.mc0}` }; } const beforeContent = JSON.parse(JSON.stringify(contentToTransform)); // Deep copy const result = await applyAdversarialLayer(contentToTransform, { ...config, csvData: inputData, detectorTarget: config.detectorTarget || 'general', intensity: config.intensity || 1.0, method: config.method || 'regeneration' }); return { content: result.content || result, tokensUsed: result.tokensUsed || 200, cost: (result.tokensUsed || 200) * 0.00002, llmCalls: result.llmCalls || [ { provider: 'claude', tokens: 100, cost: 0.002, phase: 'adversarial_generation' }, { provider: 'mistral', tokens: 100, cost: 0.0005, phase: 'adversarial_enhancement' } ], phases: { adversarialGeneration: result.stats }, beforeAfter: { before: beforeContent, after: result.content || result } }; } catch (error) { logSh(`❌ Erreur Adversarial: ${error.message}`, 'ERROR'); return this.createFallbackContent('adversarial', inputData, error); } } /** * Execute Human Simulation */ async executeHumanSimulation(inputData, options = {}) { try { const { applyHumanSimulationLayer } = require('./human-simulation/HumanSimulationCore'); logSh('🎯 Démarrage Human Simulation', 'DEBUG'); const config = { humanSimulationMode: options.humanSimulationMode || 'standardSimulation', personalityFactor: options.personalityFactor || 0.7, fatigueLevel: options.fatigueLevel || 'medium' }; // Vérifier si on a du contenu à humaniser let contentToHumanize = null; if (options.inputContent && Object.keys(options.inputContent).length > 0) { contentToHumanize = options.inputContent; } else { // Fallback: créer un contenu basique pour le test logSh('⚠️ Pas de contenu d\'entrée, création d\'un contenu basique pour test', 'WARNING'); contentToHumanize = { 'Titre_H1': inputData.t0 || 'Titre principal', 'Introduction': `Contenu sur ${inputData.mc0}`, 'Contenu_Principal': `Développement du sujet ${inputData.mc0}`, 'Conclusion': `Conclusion sur ${inputData.mc0}` }; } const beforeContent = JSON.parse(JSON.stringify(contentToHumanize)); // Deep copy const result = await applyHumanSimulationLayer(contentToHumanize, inputData, config); return { content: result.content || result, tokensUsed: result.tokensUsed || 180, cost: (result.tokensUsed || 180) * 0.00002, llmCalls: result.llmCalls || [ { provider: 'gemini', tokens: 90, cost: 0.0009, phase: 'human_simulation' }, { provider: 'claude', tokens: 90, cost: 0.0018, phase: 'personality_application' } ], phases: { humanSimulation: result.stats }, beforeAfter: { before: beforeContent, after: result.content || result } }; } catch (error) { logSh(`❌ Erreur Human Simulation: ${error.message}`, 'ERROR'); return this.createFallbackContent('human-simulation', inputData, error); } } /** * Execute Pattern Breaking */ async executePatternBreaking(inputData, options = {}) { try { const { applyPatternBreakingLayer } = require('./pattern-breaking/PatternBreakingCore'); logSh('🎯 Démarrage Pattern Breaking', 'DEBUG'); const config = { patternBreakingMode: options.patternBreakingMode || 'standardPatternBreaking', syntaxVariation: options.syntaxVariation || 0.6, connectorDiversity: options.connectorDiversity || 0.8 }; // Vérifier si on a du contenu à transformer let contentToTransform = null; if (options.inputContent && Object.keys(options.inputContent).length > 0) { contentToTransform = options.inputContent; } else { // Fallback: créer un contenu basique pour le test logSh('⚠️ Pas de contenu d\'entrée, création d\'un contenu basique pour test', 'WARNING'); contentToTransform = { 'Titre_H1': inputData.t0 || 'Titre principal', 'Introduction': `Contenu sur ${inputData.mc0}`, 'Contenu_Principal': `Développement du sujet ${inputData.mc0}`, 'Conclusion': `Conclusion sur ${inputData.mc0}` }; } const beforeContent = JSON.parse(JSON.stringify(contentToTransform)); // Deep copy const result = await applyPatternBreakingLayer(contentToTransform, inputData, config); return { content: result.content || result, tokensUsed: result.tokensUsed || 120, cost: (result.tokensUsed || 120) * 0.00002, llmCalls: result.llmCalls || [ { provider: 'gpt4', tokens: 60, cost: 0.0012, phase: 'pattern_analysis' }, { provider: 'mistral', tokens: 60, cost: 0.0003, phase: 'pattern_breaking' } ], phases: { patternBreaking: result.stats }, beforeAfter: { before: beforeContent, after: result.content || result } }; } catch (error) { logSh(`❌ Erreur Pattern Breaking: ${error.message}`, 'ERROR'); return this.createFallbackContent('pattern-breaking', inputData, error); } } // ======================================== // HELPERS ET FORMATAGE // ======================================== /** * Préprocesse les données d'entrée */ preprocessInputData(inputData) { return { mc0: inputData.mc0 || 'mot-clé principal', t0: inputData.t0 || 'titre principal', mcPlus1: inputData.mcPlus1 || '', tPlus1: inputData.tPlus1 || '', personality: inputData.personality || { nom: 'Test', style: 'neutre' }, xmlTemplate: inputData.xmlTemplate || this.getDefaultTemplate(), // Ajout d'un contexte pour les modules context: { timestamp: Date.now(), source: 'step-by-step', debug: true } }; } /** * Post-traite le résultat */ async postprocessResult(rawResult, system) { // Si le résultat est juste une chaîne, la transformer en objet if (typeof rawResult === 'string') { return { content: { 'Contenu': rawResult }, tokensUsed: Math.floor(rawResult.length / 4), // Estimation cost: 0.001, llmCalls: [{ provider: 'unknown', tokens: 50, cost: 0.001 }] }; } // Si c'est déjà un objet structuré, le retourner tel quel if (rawResult && typeof rawResult === 'object') { return rawResult; } // Fallback return { content: { 'Résultat': String(rawResult) }, tokensUsed: 50, cost: 0.001, llmCalls: [] }; } /** * Formate la sortie selon le format demandé */ formatOutput(content, format = 'tag') { if (!content || typeof content !== 'object') { return String(content || 'Pas de contenu'); } switch (format) { case 'tag': return Object.entries(content) .map(([tag, text]) => `[${tag}]\n${text}`) .join('\n\n'); case 'xml': return Object.entries(content) .map(([tag, text]) => `<${tag.toLowerCase()}>${text}`) .join('\n'); case 'json': return JSON.stringify(content, null, 2); default: return this.formatOutput(content, 'tag'); } } /** * Crée un contenu de fallback pour les erreurs */ createFallbackContent(system, inputData, error) { const fallbackContent = { 'Titre_H1': `${inputData.t0} - Traité par ${system}`, 'Introduction': `Contenu généré en mode ${system} pour "${inputData.mc0}".`, 'Contenu_Principal': `Ceci est un contenu de démonstration pour le système ${system}. En production, ce contenu serait généré par l'IA avec les paramètres spécifiés.`, 'Note_Technique': `⚠️ Mode fallback activé - Erreur: ${error.message}` }; return { content: fallbackContent, tokensUsed: 100, cost: 0.002, llmCalls: [ { provider: 'fallback', tokens: 100, cost: 0.002, error: error.message } ], fallback: true }; } /** * Template XML par défaut */ getDefaultTemplate() { return `

|Titre_H1{{T0}}{Titre principal optimisé}|

|Introduction{{MC0}}{Introduction engageante}| |Contenu_Principal{{MC0,T0}}{Contenu principal détaillé}| |Conclusion{{T0}}{Conclusion percutante}|
`; } } module.exports = { StepExecutor };