seo-generator-server/lib/human-simulation/HumanSimulationCore.js

298 lines
11 KiB
JavaScript

// ========================================
// FICHIER: HumanSimulationCore.js
// RESPONSABILITÉ: Orchestrateur principal Human Simulation
// Niveau 5: Temporal & Personality Injection
// ========================================
const { logSh } = require('../ErrorReporting');
const { tracer } = require('../trace');
const { calculateFatigue, injectFatigueMarkers, getFatigueProfile } = require('./FatiguePatterns');
const { injectPersonalityErrors, getPersonalityErrorPatterns } = require('./PersonalityErrors');
const { applyTemporalStyle, getTemporalStyle } = require('./TemporalStyles');
const {
analyzeContentComplexity,
calculateReadabilityScore,
preserveKeywords,
validateSimulationQuality
} = require('./HumanSimulationUtils');
/**
* CONFIGURATION PAR DÉFAUT
*/
const DEFAULT_CONFIG = {
fatigueEnabled: true,
personalityErrorsEnabled: true,
temporalStyleEnabled: true,
imperfectionIntensity: 0.8, // FIXÉ: Plus d'intensité (était 0.3)
naturalRepetitions: true,
qualityThreshold: 0.4, // FIXÉ: Seuil plus bas (était 0.7)
maxModificationsPerElement: 5 // FIXÉ: Plus de modifs possibles (était 3)
};
/**
* ORCHESTRATEUR PRINCIPAL - Human Simulation Layer
* @param {object} content - Contenu généré à simuler
* @param {object} options - Options de simulation
* @returns {object} - { content, stats, fallback }
*/
async function applyHumanSimulationLayer(content, options = {}) {
return await tracer.run('HumanSimulationCore.applyHumanSimulationLayer()', async () => {
const startTime = Date.now();
await tracer.annotate({
contentKeys: Object.keys(content).length,
elementIndex: options.elementIndex,
totalElements: options.totalElements,
currentHour: options.currentHour,
personality: options.csvData?.personality?.nom
});
logSh(`🧠 HUMAN SIMULATION - Début traitement`, 'INFO');
logSh(` 📊 ${Object.keys(content).length} éléments | Position: ${options.elementIndex}/${options.totalElements}`, 'DEBUG');
try {
// Configuration fusionnée
const config = { ...DEFAULT_CONFIG, ...options };
// Stats de simulation
const simulationStats = {
elementsProcessed: 0,
fatigueModifications: 0,
personalityModifications: 0,
temporalModifications: 0,
totalModifications: 0,
qualityScore: 0,
fallbackUsed: false
};
// Contenu simulé
let simulatedContent = { ...content };
// ========================================
// 1. ANALYSE CONTEXTE GLOBAL
// ========================================
const globalContext = await analyzeGlobalContext(content, config);
logSh(` 🔍 Contexte: fatigue=${globalContext.fatigueLevel.toFixed(2)}, heure=${globalContext.currentHour}h, personnalité=${globalContext.personalityName}`, 'DEBUG');
// ========================================
// 2. TRAITEMENT PAR ÉLÉMENT
// ========================================
for (const [elementKey, elementContent] of Object.entries(content)) {
await tracer.run(`HumanSimulation.processElement(${elementKey})`, async () => {
logSh(` 🎯 Traitement élément: ${elementKey}`, 'DEBUG');
let processedContent = elementContent;
let elementModifications = 0;
try {
// 2a. Simulation Fatigue Cognitive
if (config.fatigueEnabled && globalContext.fatigueLevel > 0.1) { // FIXÉ: Seuil plus bas (était 0.3)
const fatigueResult = await applyFatigueSimulation(processedContent, globalContext, config);
processedContent = fatigueResult.content;
elementModifications += fatigueResult.modifications;
simulationStats.fatigueModifications += fatigueResult.modifications;
logSh(` 💤 Fatigue: ${fatigueResult.modifications} modifications (niveau: ${globalContext.fatigueLevel.toFixed(2)})`, 'DEBUG');
}
// 2b. Erreurs Personnalité
if (config.personalityErrorsEnabled && globalContext.personalityProfile) {
const personalityResult = await applyPersonalitySimulation(processedContent, globalContext, config);
processedContent = personalityResult.content;
elementModifications += personalityResult.modifications;
simulationStats.personalityModifications += personalityResult.modifications;
logSh(` 🎭 Personnalité: ${personalityResult.modifications} erreurs injectées`, 'DEBUG');
}
// 2c. Style Temporel
if (config.temporalStyleEnabled && globalContext.temporalStyle) {
const temporalResult = await applyTemporalSimulation(processedContent, globalContext, config);
processedContent = temporalResult.content;
elementModifications += temporalResult.modifications;
simulationStats.temporalModifications += temporalResult.modifications;
logSh(` ⏰ Temporel: ${temporalResult.modifications} ajustements (${globalContext.temporalStyle.period})`, 'DEBUG');
}
// 2d. Validation Qualité
const qualityCheck = validateSimulationQuality(elementContent, processedContent, config.qualityThreshold);
if (qualityCheck.acceptable) {
simulatedContent[elementKey] = processedContent;
simulationStats.elementsProcessed++;
simulationStats.totalModifications += elementModifications;
logSh(` ✅ Élément simulé: ${elementModifications} modifications totales`, 'DEBUG');
} else {
// Fallback: garder contenu original
simulatedContent[elementKey] = elementContent;
simulationStats.fallbackUsed = true;
logSh(` ⚠️ Qualité insuffisante, fallback vers contenu original`, 'WARNING');
}
} catch (elementError) {
logSh(` ❌ Erreur simulation élément ${elementKey}: ${elementError.message}`, 'WARNING');
simulatedContent[elementKey] = elementContent; // Fallback
simulationStats.fallbackUsed = true;
}
}, { elementKey, originalLength: elementContent?.length });
}
// ========================================
// 3. CALCUL SCORE QUALITÉ GLOBAL
// ========================================
simulationStats.qualityScore = calculateGlobalQualityScore(content, simulatedContent);
// ========================================
// 4. RÉSULTATS FINAUX
// ========================================
const duration = Date.now() - startTime;
const success = simulationStats.elementsProcessed > 0 && !simulationStats.fallbackUsed;
logSh(`🧠 HUMAN SIMULATION - Terminé (${duration}ms)`, 'INFO');
logSh(`${simulationStats.elementsProcessed}/${Object.keys(content).length} éléments simulés`, 'INFO');
logSh(` 📊 ${simulationStats.fatigueModifications} fatigue | ${simulationStats.personalityModifications} personnalité | ${simulationStats.temporalModifications} temporel`, 'INFO');
logSh(` 🎯 Score qualité: ${simulationStats.qualityScore.toFixed(2)} | Fallback: ${simulationStats.fallbackUsed ? 'OUI' : 'NON'}`, 'INFO');
await tracer.event('Human Simulation terminée', {
success,
duration,
stats: simulationStats
});
return {
content: simulatedContent,
stats: simulationStats,
fallback: simulationStats.fallbackUsed,
qualityScore: simulationStats.qualityScore,
duration
};
} catch (error) {
const duration = Date.now() - startTime;
logSh(`❌ HUMAN SIMULATION ÉCHOUÉE (${duration}ms): ${error.message}`, 'ERROR');
await tracer.event('Human Simulation échouée', {
error: error.message,
duration,
contentKeys: Object.keys(content).length
});
// Fallback complet
return {
content,
stats: { fallbackUsed: true, error: error.message },
fallback: true,
qualityScore: 0,
duration
};
}
}, {
contentElements: Object.keys(content).length,
elementIndex: options.elementIndex,
personality: options.csvData?.personality?.nom
});
}
/**
* ANALYSE CONTEXTE GLOBAL
*/
async function analyzeGlobalContext(content, config) {
const elementIndex = config.elementIndex || 0;
const totalElements = config.totalElements || Object.keys(content).length;
const currentHour = config.currentHour || new Date().getHours();
const personality = config.csvData?.personality;
return {
fatigueLevel: calculateFatigue(elementIndex, totalElements),
fatigueProfile: personality ? getFatigueProfile(personality.nom) : null,
personalityName: personality?.nom || 'unknown',
personalityProfile: personality ? getPersonalityErrorPatterns(personality.nom) : null,
temporalStyle: getTemporalStyle(currentHour),
currentHour,
elementIndex,
totalElements,
contentComplexity: analyzeContentComplexity(content)
};
}
/**
* APPLICATION SIMULATION FATIGUE
*/
async function applyFatigueSimulation(content, globalContext, config) {
const fatigueResult = injectFatigueMarkers(content, globalContext.fatigueLevel, {
profile: globalContext.fatigueProfile,
intensity: config.imperfectionIntensity
});
return {
content: fatigueResult.content,
modifications: fatigueResult.modifications || 0
};
}
/**
* APPLICATION SIMULATION PERSONNALITÉ
*/
async function applyPersonalitySimulation(content, globalContext, config) {
const personalityResult = injectPersonalityErrors(
content,
globalContext.personalityProfile,
config.imperfectionIntensity
);
return {
content: personalityResult.content,
modifications: personalityResult.modifications || 0
};
}
/**
* APPLICATION SIMULATION TEMPORELLE
*/
async function applyTemporalSimulation(content, globalContext, config) {
const temporalResult = applyTemporalStyle(content, globalContext.temporalStyle, {
intensity: config.imperfectionIntensity
});
return {
content: temporalResult.content,
modifications: temporalResult.modifications || 0
};
}
/**
* CALCUL SCORE QUALITÉ GLOBAL
*/
function calculateGlobalQualityScore(originalContent, simulatedContent) {
let totalScore = 0;
let elementCount = 0;
for (const [key, original] of Object.entries(originalContent)) {
const simulated = simulatedContent[key];
if (simulated) {
const elementScore = calculateReadabilityScore(simulated) * 0.7 +
preserveKeywords(original, simulated) * 0.3;
totalScore += elementScore;
elementCount++;
}
}
return elementCount > 0 ? totalScore / elementCount : 0;
}
// ============= EXPORTS =============
module.exports = {
applyHumanSimulationLayer,
analyzeGlobalContext,
applyFatigueSimulation,
applyPersonalitySimulation,
applyTemporalSimulation,
calculateGlobalQualityScore,
DEFAULT_CONFIG
};