seo-generator-server/lib/StepExecutor.js

354 lines
11 KiB
JavaScript

// ========================================
// 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 = {
'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 Selective Enhancement
*/
async executeSelective(inputData, options = {}) {
try {
// Import dynamique pour éviter les dépendances circulaires
const { SelectiveCore } = require('./selective-enhancement/SelectiveCore');
logSh('🎯 Démarrage Selective Enhancement', 'DEBUG');
const selectiveCore = new SelectiveCore();
const config = {
selectiveStack: options.selectiveStack || 'standardEnhancement',
temperature: options.temperature || 0.8,
maxTokens: options.maxTokens || 3000
};
const result = await selectiveCore.processContent(inputData, config);
return {
content: result.content || result,
tokensUsed: result.tokensUsed || 150,
cost: (result.tokensUsed || 150) * 0.00002, // Estimation
llmCalls: result.llmCalls || [
{ provider: 'claude', tokens: 75, cost: 0.0015 },
{ provider: 'gpt4', tokens: 75, cost: 0.0015 }
]
};
} 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 { AdversarialCore } = require('./adversarial-generation/AdversarialCore');
logSh('🎯 Démarrage Adversarial Generation', 'DEBUG');
const adversarialCore = new AdversarialCore();
const config = {
adversarialMode: options.adversarialMode || 'standard',
temperature: options.temperature || 1.0,
antiDetectionLevel: options.antiDetectionLevel || 'medium'
};
const result = await adversarialCore.processContent(inputData, config);
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 },
{ provider: 'mistral', tokens: 100, cost: 0.0005 }
]
};
} catch (error) {
logSh(`❌ Erreur Adversarial: ${error.message}`, 'ERROR');
return this.createFallbackContent('adversarial', inputData, error);
}
}
/**
* Execute Human Simulation
*/
async executeHumanSimulation(inputData, options = {}) {
try {
const { HumanSimulationCore } = require('./human-simulation/HumanSimulationCore');
logSh('🎯 Démarrage Human Simulation', 'DEBUG');
const humanCore = new HumanSimulationCore();
const config = {
humanSimulationMode: options.humanSimulationMode || 'standardSimulation',
personalityFactor: options.personalityFactor || 0.7,
fatigueLevel: options.fatigueLevel || 'medium'
};
const result = await humanCore.processContent(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 },
{ provider: 'claude', tokens: 90, cost: 0.0018 }
]
};
} 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 { PatternBreakingCore } = require('./pattern-breaking/PatternBreakingCore');
logSh('🎯 Démarrage Pattern Breaking', 'DEBUG');
const patternCore = new PatternBreakingCore();
const config = {
patternBreakingMode: options.patternBreakingMode || 'standardPatternBreaking',
syntaxVariation: options.syntaxVariation || 0.6,
connectorDiversity: options.connectorDiversity || 0.8
};
const result = await patternCore.processContent(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 },
{ provider: 'mistral', tokens: 60, cost: 0.0003 }
]
};
} 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}</${tag.toLowerCase()}>`)
.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 `<?xml version="1.0" encoding="UTF-8"?>
<article>
<h1>|Titre_H1{{T0}}{Titre principal optimisé}|</h1>
<intro>|Introduction{{MC0}}{Introduction engageante}|</intro>
<content>|Contenu_Principal{{MC0,T0}}{Contenu principal détaillé}|</content>
<conclusion>|Conclusion{{T0}}{Conclusion percutante}|</conclusion>
</article>`;
}
}
module.exports = {
StepExecutor
};