// ======================================== // FICHIER: TemporalStyles.js // RESPONSABILITÉ: Variations temporelles d'écriture // Simulation comportement humain selon l'heure // ======================================== const { logSh } = require('../ErrorReporting'); /** * STYLES TEMPORELS PAR TRANCHES HORAIRES * Simule l'énergie et style d'écriture selon l'heure */ const TEMPORAL_STYLES = { // ======================================== // MATIN (6h-11h) - Énergique et Direct // ======================================== morning: { period: 'matin', timeRange: [6, 11], energy: 'high', characteristics: { sentenceLength: 'short', // Phrases plus courtes vocabulary: 'dynamic', // Mots énergiques connectors: 'direct', // Connecteurs simples rhythm: 'fast' // Rythme soutenu }, vocabularyPreferences: { energy: ['dynamique', 'efficace', 'rapide', 'direct', 'actif', 'performant'], connectors: ['donc', 'puis', 'ensuite', 'maintenant', 'immédiatement'], modifiers: ['très', 'vraiment', 'particulièrement', 'nettement'], actions: ['optimiser', 'accélérer', 'améliorer', 'développer', 'créer'] }, styleTendencies: { shortSentencesBias: 0.7, // 70% chance phrases courtes directConnectorsBias: 0.8, // 80% connecteurs simples energyWordsBias: 0.6 // 60% mots énergiques } }, // ======================================== // APRÈS-MIDI (12h-17h) - Équilibré et Professionnel // ======================================== afternoon: { period: 'après-midi', timeRange: [12, 17], energy: 'medium', characteristics: { sentenceLength: 'medium', // Phrases équilibrées vocabulary: 'professional', // Vocabulaire standard connectors: 'balanced', // Connecteurs variés rhythm: 'steady' // Rythme régulier }, vocabularyPreferences: { energy: ['professionnel', 'efficace', 'qualité', 'standard', 'adapté'], connectors: ['par ailleurs', 'de plus', 'également', 'ainsi', 'cependant'], modifiers: ['assez', 'plutôt', 'relativement', 'suffisamment'], actions: ['réaliser', 'développer', 'analyser', 'étudier', 'concevoir'] }, styleTendencies: { shortSentencesBias: 0.4, // 40% phrases courtes directConnectorsBias: 0.5, // 50% connecteurs simples energyWordsBias: 0.3 // 30% mots énergiques } }, // ======================================== // SOIR (18h-23h) - Détendu et Réflexif // ======================================== evening: { period: 'soir', timeRange: [18, 23], energy: 'low', characteristics: { sentenceLength: 'long', // Phrases plus longues vocabulary: 'nuanced', // Vocabulaire nuancé connectors: 'complex', // Connecteurs élaborés rhythm: 'relaxed' // Rythme posé }, vocabularyPreferences: { energy: ['approfondi', 'réfléchi', 'considéré', 'nuancé', 'détaillé'], connectors: ['néanmoins', 'cependant', 'par conséquent', 'en outre', 'toutefois'], modifiers: ['quelque peu', 'relativement', 'dans une certaine mesure', 'assez'], actions: ['examiner', 'considérer', 'réfléchir', 'approfondir', 'explorer'] }, styleTendencies: { shortSentencesBias: 0.2, // 20% phrases courtes directConnectorsBias: 0.2, // 20% connecteurs simples energyWordsBias: 0.1 // 10% mots énergiques } }, // ======================================== // NUIT (0h-5h) - Fatigue et Simplicité // ======================================== night: { period: 'nuit', timeRange: [0, 5], energy: 'very_low', characteristics: { sentenceLength: 'short', // Phrases courtes par fatigue vocabulary: 'simple', // Vocabulaire basique connectors: 'minimal', // Connecteurs rares rhythm: 'slow' // Rythme lent }, vocabularyPreferences: { energy: ['simple', 'basique', 'standard', 'normal', 'classique'], connectors: ['et', 'mais', 'ou', 'donc', 'puis'], modifiers: ['assez', 'bien', 'pas mal', 'correct'], actions: ['faire', 'utiliser', 'prendre', 'mettre', 'avoir'] }, styleTendencies: { shortSentencesBias: 0.8, // 80% phrases courtes directConnectorsBias: 0.9, // 90% connecteurs simples energyWordsBias: 0.1 // 10% mots énergiques } } }; /** * DÉTERMINER STYLE TEMPOREL SELON L'HEURE * @param {number} currentHour - Heure actuelle (0-23) * @returns {object} - Style temporel correspondant */ function getTemporalStyle(currentHour) { // Validation heure const hour = Math.max(0, Math.min(23, Math.floor(currentHour || new Date().getHours()))); logSh(`⏰ Détermination style temporel pour ${hour}h`, 'DEBUG'); // Déterminer période let selectedStyle; if (hour >= 6 && hour <= 11) { selectedStyle = TEMPORAL_STYLES.morning; } else if (hour >= 12 && hour <= 17) { selectedStyle = TEMPORAL_STYLES.afternoon; } else if (hour >= 18 && hour <= 23) { selectedStyle = TEMPORAL_STYLES.evening; } else { selectedStyle = TEMPORAL_STYLES.night; } logSh(`⏰ Style temporel sélectionné: ${selectedStyle.period} (énergie: ${selectedStyle.energy})`, 'DEBUG'); return { ...selectedStyle, currentHour: hour, timestamp: new Date().toISOString() }; } /** * APPLICATION STYLE TEMPOREL * @param {string} content - Contenu à modifier * @param {object} temporalStyle - Style temporel à appliquer * @param {object} options - Options { intensity } * @returns {object} - { content, modifications } */ function applyTemporalStyle(content, temporalStyle, options = {}) { if (!content || !temporalStyle) { return { content, modifications: 0 }; } const intensity = options.intensity || 1.0; logSh(`⏰ Application style temporel: ${temporalStyle.period} (intensité: ${intensity})`, 'DEBUG'); let modifiedContent = content; let modifications = 0; // ======================================== // 1. AJUSTEMENT LONGUEUR PHRASES // ======================================== const sentenceResult = adjustSentenceLength(modifiedContent, temporalStyle, intensity); modifiedContent = sentenceResult.content; modifications += sentenceResult.count; // ======================================== // 2. ADAPTATION VOCABULAIRE // ======================================== const vocabularyResult = adaptVocabulary(modifiedContent, temporalStyle, intensity); modifiedContent = vocabularyResult.content; modifications += vocabularyResult.count; // ======================================== // 3. MODIFICATION CONNECTEURS // ======================================== const connectorResult = adjustConnectors(modifiedContent, temporalStyle, intensity); modifiedContent = connectorResult.content; modifications += connectorResult.count; // ======================================== // 4. AJUSTEMENT RYTHME // ======================================== const rhythmResult = adjustRhythm(modifiedContent, temporalStyle, intensity); modifiedContent = rhythmResult.content; modifications += rhythmResult.count; logSh(`⏰ Style temporel appliqué: ${modifications} modifications`, 'DEBUG'); return { content: modifiedContent, modifications }; } /** * AJUSTEMENT LONGUEUR PHRASES */ function adjustSentenceLength(content, temporalStyle, intensity) { let modified = content; let count = 0; const bias = temporalStyle.styleTendencies.shortSentencesBias * intensity; const sentences = modified.split('. '); // Probabilité d'appliquer les modifications if (Math.random() > intensity * 0.9) { // FIXÉ: Presque toujours appliquer (était 0.7) return { content: modified, count }; } const processedSentences = sentences.map(sentence => { if (sentence.length < 20) return sentence; // Ignorer phrases très courtes // Style MATIN/NUIT - Raccourcir phrases longues if ((temporalStyle.period === 'matin' || temporalStyle.period === 'nuit') && sentence.length > 100 && Math.random() < bias) { // Chercher point de coupe naturel const cutPoints = [', qui', ', que', ', dont', ' et ', ' car ', ' mais ']; for (const cutPoint of cutPoints) { const cutIndex = sentence.indexOf(cutPoint); if (cutIndex > 30 && cutIndex < sentence.length - 30) { count++; logSh(` ✂️ Phrase raccourcie (${temporalStyle.period}): ${sentence.length} → ${cutIndex} chars`, 'DEBUG'); return sentence.substring(0, cutIndex) + '. ' + sentence.substring(cutIndex + cutPoint.length); } } } // Style SOIR - Allonger phrases courtes if (temporalStyle.period === 'soir' && sentence.length > 30 && sentence.length < 80 && Math.random() < (1 - bias)) { // Ajouter développements const developments = [ ', ce qui constitue un avantage notable', ', permettant ainsi d\'optimiser les résultats', ', dans une démarche d\'amélioration continue', ', contribuant à l\'efficacité globale' ]; const development = developments[Math.floor(Math.random() * developments.length)]; count++; logSh(` 📝 Phrase allongée (soir): ${sentence.length} → ${sentence.length + development.length} chars`, 'DEBUG'); return sentence + development; } return sentence; }); modified = processedSentences.join('. '); return { content: modified, count }; } /** * ADAPTATION VOCABULAIRE */ function adaptVocabulary(content, temporalStyle, intensity) { let modified = content; let count = 0; const vocabularyPrefs = temporalStyle.vocabularyPreferences; const energyBias = temporalStyle.styleTendencies.energyWordsBias * intensity; // Probabilité d'appliquer if (Math.random() > intensity * 0.9) { // FIXÉ: Presque toujours appliquer (était 0.6) return { content: modified, count }; } // Remplacements selon période const replacements = buildVocabularyReplacements(temporalStyle.period, vocabularyPrefs); replacements.forEach(replacement => { if (Math.random() < Math.max(0.6, energyBias)) { // FIXÉ: Minimum 60% chance const regex = new RegExp(`\\b${replacement.from}\\b`, 'gi'); if (modified.match(regex)) { modified = modified.replace(regex, replacement.to); count++; logSh(` 📚 Vocabulaire adapté (${temporalStyle.period}): "${replacement.from}" → "${replacement.to}"`, 'DEBUG'); } } }); // AJOUT FIX: Si aucun remplacement, forcer au moins une modification temporelle basique if (count === 0 && Math.random() < 0.5) { // Modification basique selon période if (temporalStyle.period === 'matin' && modified.includes('utiliser')) { modified = modified.replace(/\butiliser\b/gi, 'optimiser'); count++; logSh(` 📚 Modification temporelle forcée: utiliser → optimiser`, 'DEBUG'); } } return { content: modified, count }; } /** * CONSTRUCTION REMPLACEMENTS VOCABULAIRE */ function buildVocabularyReplacements(period, vocabPrefs) { const replacements = []; switch (period) { case 'matin': replacements.push( { from: 'bon', to: 'excellent' }, { from: 'intéressant', to: 'dynamique' }, { from: 'utiliser', to: 'optimiser' }, { from: 'faire', to: 'créer' } ); break; case 'soir': replacements.push( { from: 'bon', to: 'considérable' }, { from: 'faire', to: 'examiner' }, { from: 'utiliser', to: 'exploiter' }, { from: 'voir', to: 'considérer' } ); break; case 'nuit': replacements.push( { from: 'excellent', to: 'bien' }, { from: 'optimiser', to: 'utiliser' }, { from: 'considérable', to: 'correct' }, { from: 'examiner', to: 'regarder' } ); break; default: // après-midi // Vocabulaire équilibré - pas de remplacements drastiques break; } return replacements; } /** * AJUSTEMENT CONNECTEURS */ function adjustConnectors(content, temporalStyle, intensity) { let modified = content; let count = 0; const connectorBias = temporalStyle.styleTendencies.directConnectorsBias * intensity; const preferredConnectors = temporalStyle.vocabularyPreferences.connectors; if (Math.random() > intensity * 0.5) { return { content: modified, count }; } // Connecteurs selon période const connectorMappings = { matin: [ { from: /par conséquent/gi, to: 'donc' }, { from: /néanmoins/gi, to: 'mais' }, { from: /en outre/gi, to: 'aussi' } ], soir: [ { from: /donc/gi, to: 'par conséquent' }, { from: /mais/gi, to: 'néanmoins' }, { from: /aussi/gi, to: 'en outre' } ], nuit: [ { from: /par conséquent/gi, to: 'donc' }, { from: /néanmoins/gi, to: 'mais' }, { from: /cependant/gi, to: 'mais' } ] }; const mappings = connectorMappings[temporalStyle.period] || []; mappings.forEach(mapping => { if (Math.random() < connectorBias) { if (modified.match(mapping.from)) { modified = modified.replace(mapping.from, mapping.to); count++; logSh(` 🔗 Connecteur adapté (${temporalStyle.period}): "${mapping.from}" → "${mapping.to}"`, 'DEBUG'); } } }); return { content: modified, count }; } /** * AJUSTEMENT RYTHME */ function adjustRhythm(content, temporalStyle, intensity) { let modified = content; let count = 0; // Le rythme affecte la ponctuation et les pauses if (Math.random() > intensity * 0.3) { return { content: modified, count }; } switch (temporalStyle.characteristics.rhythm) { case 'fast': // Matin - moins de virgules, plus direct if (Math.random() < 0.4) { // Supprimer quelques virgules non essentielles const originalCommas = (modified.match(/,/g) || []).length; modified = modified.replace(/, qui /gi, ' qui '); modified = modified.replace(/, que /gi, ' que '); const newCommas = (modified.match(/,/g) || []).length; count = originalCommas - newCommas; if (count > 0) { logSh(` ⚡ Rythme accéléré: ${count} virgules supprimées`, 'DEBUG'); } } break; case 'relaxed': // Soir - plus de pauses if (Math.random() < 0.3) { // Ajouter quelques pauses réflexives modified = modified.replace(/\. ([A-Z])/g, '. Ainsi, $1'); count++; logSh(` 🧘 Rythme ralenti: pauses ajoutées`, 'DEBUG'); } break; case 'slow': // Nuit - simplification if (Math.random() < 0.5) { // Simplifier structures complexes modified = modified.replace(/ ; /g, '. '); count++; logSh(` 😴 Rythme simplifié: structures allégées`, 'DEBUG'); } break; } return { content: modified, count }; } /** * ANALYSE COHÉRENCE TEMPORELLE * @param {string} content - Contenu à analyser * @param {object} temporalStyle - Style appliqué * @returns {object} - Métriques de cohérence */ function analyzeTemporalCoherence(content, temporalStyle) { const sentences = content.split('. '); const avgSentenceLength = sentences.reduce((sum, s) => sum + s.length, 0) / sentences.length; const energyWords = temporalStyle.vocabularyPreferences.energy; const energyWordCount = energyWords.reduce((count, word) => { const regex = new RegExp(`\\b${word}\\b`, 'gi'); return count + (content.match(regex) || []).length; }, 0); return { avgSentenceLength, energyWordDensity: energyWordCount / sentences.length, period: temporalStyle.period, coherenceScore: calculateCoherenceScore(avgSentenceLength, temporalStyle), expectedCharacteristics: temporalStyle.characteristics }; } /** * CALCUL SCORE COHÉRENCE */ function calculateCoherenceScore(avgLength, temporalStyle) { let score = 1.0; // Vérifier cohérence longueur phrases avec période const expectedLength = { 'matin': { min: 40, max: 80 }, 'après-midi': { min: 60, max: 120 }, 'soir': { min: 80, max: 150 }, 'nuit': { min: 30, max: 70 } }; const expected = expectedLength[temporalStyle.period]; if (expected) { if (avgLength < expected.min || avgLength > expected.max) { score *= 0.7; } } return Math.max(0, Math.min(1, score)); } // ============= EXPORTS ============= module.exports = { getTemporalStyle, applyTemporalStyle, adjustSentenceLength, adaptVocabulary, adjustConnectors, adjustRhythm, analyzeTemporalCoherence, calculateCoherenceScore, buildVocabularyReplacements, TEMPORAL_STYLES };