315 lines
11 KiB
JavaScript
315 lines
11 KiB
JavaScript
// ========================================
|
|
// 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
|
|
}; |