// ======================================== // ORCHESTRATEUR GÉNÉRATION - ARCHITECTURE REFACTORISÉE // Responsabilité: Coordonner les 4 étapes de génération // ======================================== const { logSh } = require('./ErrorReporting'); const { tracer } = require('./trace'); // Import des 4 étapes séparées const { generateInitialContent } = require('./generation/InitialGeneration'); const { enhanceTechnicalTerms } = require('./generation/TechnicalEnhancement'); const { enhanceTransitions } = require('./generation/TransitionEnhancement'); const { applyPersonalityStyle } = require('./generation/StyleEnhancement'); // Import Pattern Breaking (Niveau 2) const { applyPatternBreaking } = require('./post-processing/PatternBreaking'); /** * MAIN ENTRY POINT - GÉNÉRATION AVEC SELECTIVE ENHANCEMENT * @param {Object} hierarchy - Hiérarchie des éléments extraits * @param {Object} csvData - Données CSV avec personnalité * @param {Object} options - Options de génération * @returns {Object} - Contenu généré final */ async function generateWithContext(hierarchy, csvData, options = {}) { return await tracer.run('ContentGeneration.generateWithContext()', async () => { const startTime = Date.now(); const pipelineName = options.patternBreaking ? 'selective_enhancement_with_pattern_breaking' : 'selective_enhancement'; const totalSteps = options.patternBreaking ? 5 : 4; await tracer.annotate({ pipeline: pipelineName, elementsCount: Object.keys(hierarchy).length, personality: csvData.personality?.nom, mc0: csvData.mc0, options, totalSteps }); logSh(`🚀 DÉBUT PIPELINE ${options.patternBreaking ? 'NIVEAU 2' : 'NIVEAU 1'}`, 'INFO'); logSh(` 🎭 Personnalité: ${csvData.personality?.nom} (${csvData.personality?.style})`, 'INFO'); logSh(` 📊 ${Object.keys(hierarchy).length} éléments à traiter`, 'INFO'); logSh(` 🔧 Options: ${JSON.stringify(options)}`, 'DEBUG'); try { let pipelineResults = { content: {}, stats: { stages: [], totalDuration: 0 }, debug: { pipeline: 'selective_enhancement', stages: [] } }; // ÉTAPE 1: GÉNÉRATION INITIALE (Claude) const step1Result = await generateInitialContent({ hierarchy, csvData, context: { step: 1, totalSteps, options } }); pipelineResults.content = step1Result.content; pipelineResults.stats.stages.push({ stage: 1, name: 'InitialGeneration', ...step1Result.stats }); pipelineResults.debug.stages.push(step1Result.debug); // ÉTAPE 2: ENHANCEMENT TECHNIQUE (GPT-4) - Optionnel if (!options.skipTechnical) { const step2Result = await enhanceTechnicalTerms({ content: pipelineResults.content, csvData, context: { step: 2, totalSteps, options } }); pipelineResults.content = step2Result.content; pipelineResults.stats.stages.push({ stage: 2, name: 'TechnicalEnhancement', ...step2Result.stats }); pipelineResults.debug.stages.push(step2Result.debug); } else { logSh(`⏭️ ÉTAPE 2/4 IGNORÉE: Enhancement technique désactivé`, 'INFO'); } // ÉTAPE 3: ENHANCEMENT TRANSITIONS (Gemini) - Optionnel if (!options.skipTransitions) { const step3Result = await enhanceTransitions({ content: pipelineResults.content, csvData, context: { step: 3, totalSteps, options } }); pipelineResults.content = step3Result.content; pipelineResults.stats.stages.push({ stage: 3, name: 'TransitionEnhancement', ...step3Result.stats }); pipelineResults.debug.stages.push(step3Result.debug); } else { logSh(`⏭️ ÉTAPE 3/4 IGNORÉE: Enhancement transitions désactivé`, 'INFO'); } // ÉTAPE 4: ENHANCEMENT STYLE (Mistral) - Optionnel if (!options.skipStyle) { const step4Result = await applyPersonalityStyle({ content: pipelineResults.content, csvData, context: { step: 4, totalSteps, options } }); pipelineResults.content = step4Result.content; pipelineResults.stats.stages.push({ stage: 4, name: 'StyleEnhancement', ...step4Result.stats }); pipelineResults.debug.stages.push(step4Result.debug); } else { logSh(`⏭️ ÉTAPE 4/${totalSteps} IGNORÉE: Enhancement style désactivé`, 'INFO'); } // ÉTAPE 5: PATTERN BREAKING (NIVEAU 2) - Optionnel if (options.patternBreaking) { const step5Result = await applyPatternBreaking({ content: pipelineResults.content, csvData, options: options.patternBreakingConfig || {} }); pipelineResults.content = step5Result.content; pipelineResults.stats.stages.push({ stage: 5, name: 'PatternBreaking', ...step5Result.stats }); pipelineResults.debug.stages.push(step5Result.debug); } else if (totalSteps === 5) { logSh(`⏭️ ÉTAPE 5/5 IGNORÉE: Pattern Breaking désactivé`, 'INFO'); } // RÉSULTATS FINAUX const totalDuration = Date.now() - startTime; pipelineResults.stats.totalDuration = totalDuration; const totalProcessed = pipelineResults.stats.stages.reduce((sum, stage) => sum + (stage.processed || 0), 0); const totalEnhanced = pipelineResults.stats.stages.reduce((sum, stage) => sum + (stage.enhanced || 0), 0); logSh(`✅ PIPELINE TERMINÉ: ${Object.keys(pipelineResults.content).length} éléments générés`, 'INFO'); logSh(` ⏱️ Durée totale: ${totalDuration}ms`, 'INFO'); logSh(` 📈 Enhancements: ${totalEnhanced} sur ${totalProcessed} éléments traités`, 'INFO'); // Log détaillé par étape pipelineResults.stats.stages.forEach(stage => { const enhancementRate = stage.processed > 0 ? Math.round((stage.enhanced / stage.processed) * 100) : 0; logSh(` ${stage.stage}. ${stage.name}: ${stage.enhanced}/${stage.processed} (${enhancementRate}%) en ${stage.duration}ms`, 'DEBUG'); }); await tracer.event(`Pipeline ${pipelineName} terminé`, { totalElements: Object.keys(pipelineResults.content).length, totalEnhanced, totalDuration, stagesExecuted: pipelineResults.stats.stages.length }); // Retourner uniquement le contenu pour compatibilité return pipelineResults.content; } catch (error) { const totalDuration = Date.now() - startTime; logSh(`❌ PIPELINE ÉCHOUÉ après ${totalDuration}ms: ${error.message}`, 'ERROR'); logSh(`❌ Stack trace: ${error.stack}`, 'DEBUG'); await tracer.event(`Pipeline ${pipelineName} échoué`, { error: error.message, duration: totalDuration }); throw new Error(`ContentGeneration pipeline failed: ${error.message}`); } }, { hierarchy, csvData, options }); } /** * GÉNÉRATION SIMPLE (ÉTAPE 1 UNIQUEMENT) * Pour tests ou fallback rapide */ async function generateSimple(hierarchy, csvData) { logSh(`🔥 GÉNÉRATION SIMPLE: Claude uniquement`, 'INFO'); const result = await generateInitialContent({ hierarchy, csvData, context: { step: 1, totalSteps: 1, simple: true } }); return result.content; } /** * GÉNÉRATION AVANCÉE AVEC CONTRÔLE GRANULAIRE * Permet de choisir exactement quelles étapes exécuter */ async function generateAdvanced(hierarchy, csvData, stageConfig = {}) { const { initial = true, technical = true, transitions = true, style = true, patternBreaking = false, // ✨ NOUVEAU: Niveau 2 patternBreakingConfig = {} // ✨ NOUVEAU: Config Pattern Breaking } = stageConfig; const options = { skipTechnical: !technical, skipTransitions: !transitions, skipStyle: !style, patternBreaking, // ✨ NOUVEAU patternBreakingConfig // ✨ NOUVEAU }; const activeStages = [ initial && 'Initial', technical && 'Technical', transitions && 'Transitions', style && 'Style', patternBreaking && 'PatternBreaking' // ✨ NOUVEAU ].filter(Boolean); logSh(`🎛️ GÉNÉRATION AVANCÉE: ${activeStages.join(' + ')}`, 'INFO'); return await generateWithContext(hierarchy, csvData, options); } /** * GÉNÉRATION NIVEAU 2 (AVEC PATTERN BREAKING) * Shortcut pour activer Pattern Breaking facilement */ async function generateWithPatternBreaking(hierarchy, csvData, patternConfig = {}) { logSh(`🎯 GÉNÉRATION NIVEAU 2: Pattern Breaking activé`, 'INFO'); const options = { patternBreaking: true, patternBreakingConfig: { intensity: 0.6, sentenceVariation: true, fingerprintRemoval: true, transitionHumanization: true, ...patternConfig } }; return await generateWithContext(hierarchy, csvData, options); } /** * DIAGNOSTIC PIPELINE * Exécute chaque étape avec mesures détaillées */ async function diagnosticPipeline(hierarchy, csvData) { logSh(`🔬 MODE DIAGNOSTIC: Analyse détaillée pipeline`, 'INFO'); const diagnostics = { stages: [], errors: [], performance: {}, content: {} }; let currentContent = {}; try { // Test étape 1 const step1Start = Date.now(); const step1Result = await generateInitialContent({ hierarchy, csvData }); diagnostics.stages.push({ stage: 1, name: 'InitialGeneration', success: true, duration: Date.now() - step1Start, elementsGenerated: Object.keys(step1Result.content).length, stats: step1Result.stats }); currentContent = step1Result.content; } catch (error) { diagnostics.errors.push({ stage: 1, error: error.message }); diagnostics.stages.push({ stage: 1, name: 'InitialGeneration', success: false }); return diagnostics; } // Test étapes 2-4 individuellement const stages = [ { stage: 2, name: 'TechnicalEnhancement', func: enhanceTechnicalTerms }, { stage: 3, name: 'TransitionEnhancement', func: enhanceTransitions }, { stage: 4, name: 'StyleEnhancement', func: applyPersonalityStyle } ]; for (const stageInfo of stages) { try { const stageStart = Date.now(); const stageResult = await stageInfo.func({ content: currentContent, csvData }); diagnostics.stages.push({ ...stageInfo, success: true, duration: Date.now() - stageStart, stats: stageResult.stats }); currentContent = stageResult.content; } catch (error) { diagnostics.errors.push({ stage: stageInfo.stage, error: error.message }); diagnostics.stages.push({ ...stageInfo, success: false }); } } diagnostics.content = currentContent; diagnostics.performance.totalDuration = diagnostics.stages.reduce((sum, stage) => sum + (stage.duration || 0), 0); logSh(`🔬 DIAGNOSTIC TERMINÉ: ${diagnostics.stages.filter(s => s.success).length}/4 étapes réussies`, 'INFO'); return diagnostics; } module.exports = { generateWithContext, // ← MAIN ENTRY POINT (compatible ancien code) generateSimple, // ← Génération rapide generateAdvanced, // ← Contrôle granulaire generateWithPatternBreaking, // ← NOUVEAU: Niveau 2 shortcut diagnosticPipeline // ← Tests et debug };