// ======================================== // FICHIER: FatiguePatterns.js // RESPONSABILITÉ: Simulation fatigue cognitive // Implémentation courbe fatigue exacte du plan.md // ======================================== const { logSh } = require('../ErrorReporting'); /** * PROFILS DE FATIGUE PAR PERSONNALITÉ * Basé sur les 15 personnalités du système */ const FATIGUE_PROFILES = { // Techniques - Résistent plus longtemps marc: { peakAt: 0.45, recovery: 0.85, intensity: 0.8 }, amara: { peakAt: 0.43, recovery: 0.87, intensity: 0.7 }, yasmine: { peakAt: 0.47, recovery: 0.83, intensity: 0.75 }, fabrice: { peakAt: 0.44, recovery: 0.86, intensity: 0.8 }, // Créatifs - Fatigue plus variable sophie: { peakAt: 0.55, recovery: 0.90, intensity: 1.0 }, émilie: { peakAt: 0.52, recovery: 0.88, intensity: 0.9 }, chloé: { peakAt: 0.58, recovery: 0.92, intensity: 1.1 }, minh: { peakAt: 0.53, recovery: 0.89, intensity: 0.95 }, // Commerciaux - Fatigue rapide mais récupération laurent: { peakAt: 0.40, recovery: 0.80, intensity: 1.2 }, julie: { peakAt: 0.38, recovery: 0.78, intensity: 1.0 }, // Terrain - Endurance élevée kévin: { peakAt: 0.35, recovery: 0.75, intensity: 0.6 }, mamadou: { peakAt: 0.37, recovery: 0.77, intensity: 0.65 }, linh: { peakAt: 0.36, recovery: 0.76, intensity: 0.7 }, // Patrimoniaux - Fatigue progressive 'pierre-henri': { peakAt: 0.48, recovery: 0.82, intensity: 0.85 }, thierry: { peakAt: 0.46, recovery: 0.84, intensity: 0.8 }, // Profil par défaut default: { peakAt: 0.50, recovery: 0.85, intensity: 1.0 } }; /** * CALCUL FATIGUE COGNITIVE - FORMULE EXACTE DU PLAN * Peak à 50% de progression selon courbe sinusoïdale * @param {number} elementIndex - Position élément (0-based) * @param {number} totalElements - Nombre total d'éléments * @returns {number} - Niveau fatigue (0-0.8) */ function calculateFatigue(elementIndex, totalElements) { if (totalElements <= 1) return 0; const position = elementIndex / totalElements; const fatigueLevel = Math.sin(position * Math.PI) * 0.8; // Peak à 50% logSh(`🧠 Fatigue calculée: position=${position.toFixed(2)}, niveau=${fatigueLevel.toFixed(2)}`, 'DEBUG'); return Math.max(0, fatigueLevel); } /** * OBTENIR PROFIL FATIGUE PAR PERSONNALITÉ * @param {string} personalityName - Nom personnalité * @returns {object} - Profil fatigue */ function getFatigueProfile(personalityName) { const normalizedName = personalityName?.toLowerCase() || 'default'; const profile = FATIGUE_PROFILES[normalizedName] || FATIGUE_PROFILES.default; logSh(`🎭 Profil fatigue sélectionné pour ${personalityName}: peakAt=${profile.peakAt}, intensity=${profile.intensity}`, 'DEBUG'); return profile; } /** * INJECTION MARQUEURS DE FATIGUE * @param {string} content - Contenu à modifier * @param {number} fatigueLevel - Niveau fatigue (0-0.8) * @param {object} options - Options { profile, intensity } * @returns {object} - { content, modifications } */ function injectFatigueMarkers(content, fatigueLevel, options = {}) { if (!content || fatigueLevel < 0.05) { // FIXÉ: Seuil beaucoup plus bas (était 0.2) return { content, modifications: 0 }; } const profile = options.profile || FATIGUE_PROFILES.default; const baseIntensity = options.intensity || 1.0; // Intensité ajustée selon personnalité const adjustedIntensity = fatigueLevel * profile.intensity * baseIntensity; logSh(`💤 Injection fatigue: niveau=${fatigueLevel.toFixed(2)}, intensité=${adjustedIntensity.toFixed(2)}`, 'DEBUG'); let modifiedContent = content; let modifications = 0; // ======================================== // FATIGUE LÉGÈRE (0.05 - 0.4) - FIXÉ: Seuil plus bas // ======================================== if (fatigueLevel >= 0.05 && fatigueLevel < 0.4) { const lightFatigueResult = applyLightFatigue(modifiedContent, adjustedIntensity); modifiedContent = lightFatigueResult.content; modifications += lightFatigueResult.count; } // ======================================== // FATIGUE MODÉRÉE (0.4 - 0.6) // ======================================== if (fatigueLevel >= 0.4 && fatigueLevel < 0.6) { const moderateFatigueResult = applyModerateFatigue(modifiedContent, adjustedIntensity); modifiedContent = moderateFatigueResult.content; modifications += moderateFatigueResult.count; } // ======================================== // FATIGUE ÉLEVÉE (0.6+) // ======================================== if (fatigueLevel >= 0.6) { const heavyFatigueResult = applyHeavyFatigue(modifiedContent, adjustedIntensity); modifiedContent = heavyFatigueResult.content; modifications += heavyFatigueResult.count; } logSh(`💤 Fatigue appliquée: ${modifications} modifications`, 'DEBUG'); return { content: modifiedContent, modifications }; } /** * FATIGUE LÉGÈRE - Connecteurs simplifiés */ function applyLightFatigue(content, intensity) { let modified = content; let count = 0; // Probabilité d'application basée sur l'intensité - ENCORE PLUS AGRESSIF const shouldApply = Math.random() < (intensity * 0.9); // FIXÉ: 90% chance d'appliquer if (!shouldApply) return { content: modified, count }; // Simplification des connecteurs complexes - ÉLARGI const complexConnectors = [ { from: /néanmoins/gi, to: 'cependant' }, { from: /par conséquent/gi, to: 'donc' }, { from: /ainsi que/gi, to: 'et' }, { from: /en outre/gi, to: 'aussi' }, { from: /de surcroît/gi, to: 'de plus' }, // NOUVEAUX AJOUTS AGRESSIFS { from: /toutefois/gi, to: 'mais' }, { from: /cependant/gi, to: 'mais bon' }, { from: /par ailleurs/gi, to: 'sinon' }, { from: /en effet/gi, to: 'effectivement' }, { from: /de fait/gi, to: 'en fait' } ]; complexConnectors.forEach(connector => { const matches = modified.match(connector.from); if (matches && Math.random() < 0.9) { // FIXÉ: 90% chance très agressive modified = modified.replace(connector.from, connector.to); count++; } }); // AJOUT FIX: Si aucun connecteur complexe trouvé, appliquer une modification alternative if (count === 0 && Math.random() < 0.7) { // Injecter des simplifications basiques if (modified.includes(' et ') && Math.random() < 0.5) { modified = modified.replace(' et ', ' puis '); count++; } } return { content: modified, count }; } /** * FATIGUE MODÉRÉE - Phrases plus courtes */ function applyModerateFatigue(content, intensity) { let modified = content; let count = 0; const shouldApply = Math.random() < (intensity * 0.5); if (!shouldApply) return { content: modified, count }; // Découpage phrases longues (>120 caractères) const sentences = modified.split('. '); const processedSentences = sentences.map(sentence => { if (sentence.length > 120 && Math.random() < 0.3) { // 30% chance // Trouver un point de découpe logique const cutPoints = [', qui', ', que', ', dont', ' et ', ' car ']; for (const cutPoint of cutPoints) { const cutIndex = sentence.indexOf(cutPoint); if (cutIndex > 30 && cutIndex < sentence.length - 30) { count++; return sentence.substring(0, cutIndex) + '. ' + sentence.substring(cutIndex + cutPoint.length); } } } return sentence; }); modified = processedSentences.join('. '); // Vocabulaire plus simple const simplifications = [ { from: /optimisation/gi, to: 'amélioration' }, { from: /méthodologie/gi, to: 'méthode' }, { from: /problématique/gi, to: 'problème' }, { from: /spécifications/gi, to: 'détails' } ]; simplifications.forEach(simpl => { if (modified.match(simpl.from) && Math.random() < 0.3) { modified = modified.replace(simpl.from, simpl.to); count++; } }); return { content: modified, count }; } /** * FATIGUE ÉLEVÉE - Répétitions et vocabulaire basique */ function applyHeavyFatigue(content, intensity) { let modified = content; let count = 0; const shouldApply = Math.random() < (intensity * 0.7); if (!shouldApply) return { content: modified, count }; // Injection répétitions naturelles const repetitionWords = ['bien', 'très', 'vraiment', 'assez', 'plutôt']; const sentences = modified.split('. '); sentences.forEach((sentence, index) => { if (Math.random() < 0.2 && sentence.length > 50) { // 20% chance const word = repetitionWords[Math.floor(Math.random() * repetitionWords.length)]; // Injecter le mot répétitif au milieu de la phrase const words = sentence.split(' '); const insertIndex = Math.floor(words.length / 2); words.splice(insertIndex, 0, word); sentences[index] = words.join(' '); count++; } }); modified = sentences.join('. '); // Vocabulaire très basique const basicVocab = [ { from: /excellente?/gi, to: 'bonne' }, { from: /remarquable/gi, to: 'bien' }, { from: /sophistiqué/gi, to: 'avancé' }, { from: /performant/gi, to: 'efficace' }, { from: /innovations?/gi, to: 'nouveautés' } ]; basicVocab.forEach(vocab => { if (modified.match(vocab.from) && Math.random() < 0.4) { modified = modified.replace(vocab.from, vocab.to); count++; } }); // Hésitations légères (rare) if (Math.random() < 0.1) { // 10% chance const hesitations = ['... enfin', '... disons', '... comment dire']; const hesitation = hesitations[Math.floor(Math.random() * hesitations.length)]; const words = modified.split(' '); const insertIndex = Math.floor(words.length * 0.7); // Vers la fin words.splice(insertIndex, 0, hesitation); modified = words.join(' '); count++; } return { content: modified, count }; } /** * RÉCUPÉRATION FATIGUE (pour les éléments en fin) * @param {string} content - Contenu à traiter * @param {number} recoveryLevel - Niveau récupération (0-1) * @returns {object} - { content, modifications } */ function applyFatigueRecovery(content, recoveryLevel) { if (recoveryLevel < 0.8) return { content, modifications: 0 }; let modified = content; let count = 0; // Réintroduire vocabulaire plus sophistiqué const recoveryVocab = [ { from: /\bbien\b/gi, to: 'excellent' }, { from: /\befficace\b/gi, to: 'performant' }, { from: /\bméthode\b/gi, to: 'méthodologie' } ]; recoveryVocab.forEach(vocab => { if (modified.match(vocab.from) && Math.random() < 0.3) { modified = modified.replace(vocab.from, vocab.to); count++; } }); return { content: modified, count }; } // ============= EXPORTS ============= module.exports = { calculateFatigue, getFatigueProfile, injectFatigueMarkers, applyLightFatigue, applyModerateFatigue, applyHeavyFatigue, applyFatigueRecovery, FATIGUE_PROFILES };