Application systématique et méthodique de tous les patches historiques. ## ✅ FICHIERS SYNCHRONISÉS (19 fichiers) ### Core & Infrastructure: - server.js (14 patches) - Lazy loading ModeManager, SIGINT hard kill, timing logs - ModeManager.js (4 patches) - Instrumentation complète avec timing détaillé ### Pipeline System: - PipelineDefinition.js (6 patches) - Source unique getLLMProvidersList() - pipeline-builder.js (8 patches) - Standardisation LLM providers - pipeline-runner.js (6 patches) - Affichage résultats structurés + debug console - pipeline-builder.html (2 patches) - Fallback providers synchronisés - pipeline-runner.html (3 patches) - UI améliorée résultats ### Enhancement Layers: - TechnicalLayer.js (1 patch) - defaultLLM: 'gpt-4o-mini' - StyleLayer.js (1 patch) - Type safety vocabulairePref - PatternBreakingCore.js (1 patch) - Mapping modifications - PatternBreakingLayers.js (1 patch) - LLM standardisé ### Validators & Tests: - QualityMetrics.js (1 patch) - callLLM('gpt-4o-mini') - PersonalityValidator.js (1 patch) - Provider gpt-4o-mini - AntiDetectionValidator.js - Synchronisé ### Documentation: - TODO.md (1 patch) - Section LiteLLM pour tracking coûts - CLAUDE.md - Documentation à jour ### Tools: - tools/analyze-skipped-exports.js (nouveau) - tools/apply-claude-exports.js (nouveau) - tools/apply-claude-exports-fuzzy.js (nouveau) ## 🎯 Changements principaux: - ✅ Standardisation LLM providers (openai → gpt-4o-mini, claude → claude-sonnet-4-5) - ✅ Lazy loading optimisé (ModeManager chargé à la demande) - ✅ SIGINT immediate exit (pas de graceful shutdown) - ✅ Type safety renforcé (conversions string explicites) - ✅ Instrumentation timing complète - ✅ Debug logging amélioré (console.log résultats pipeline) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
290 lines
9.0 KiB
JavaScript
290 lines
9.0 KiB
JavaScript
// ========================================
|
|
// FICHIER: server.js - POINT D'ENTRÉE MODES EXCLUSIFS
|
|
// RESPONSABILITÉ: Démarrage serveur avec sélection mode MANUAL/AUTO
|
|
// MODES: MANUAL (interface client) | AUTO (batch GSheets)
|
|
// ========================================
|
|
|
|
const startupTime = Date.now();
|
|
console.log(`[${Date.now() - startupTime}ms] Chargement dotenv...`);
|
|
require('dotenv').config();
|
|
|
|
console.log(`[${Date.now() - startupTime}ms] Chargement ErrorReporting...`);
|
|
const { logSh } = require('./lib/ErrorReporting');
|
|
|
|
console.log(`[${Date.now() - startupTime}ms] Chargement ModeManager...`);
|
|
|
|
// ⚡ LAZY LOADING: Charger ModeManager seulement quand nécessaire
|
|
let ModeManager = null;
|
|
function getModeManager() {
|
|
if (!ModeManager) {
|
|
const loadStart = Date.now();
|
|
logSh('⚡ Chargement ModeManager (lazy)...', 'DEBUG');
|
|
ModeManager = require('./lib/modes/ModeManager').ModeManager;
|
|
console.log(`[${Date.now() - startupTime}ms] ModeManager chargé !`);
|
|
logSh(`⚡ ModeManager chargé en ${Date.now() - loadStart}ms`, 'DEBUG');
|
|
}
|
|
return ModeManager;
|
|
}
|
|
|
|
/**
|
|
* SERVEUR SEO GENERATOR - MODES EXCLUSIFS
|
|
* Point d'entrée unique pour démarrer en mode MANUAL ou AUTO
|
|
*/
|
|
class SEOGeneratorServer {
|
|
|
|
constructor() {
|
|
this.startTime = Date.now();
|
|
this.isShuttingDown = false;
|
|
}
|
|
|
|
/**
|
|
* Démarrage principal du serveur
|
|
*/
|
|
async start() {
|
|
try {
|
|
// Banner de démarrage
|
|
this.displayStartupBanner();
|
|
|
|
// Gestion signaux système
|
|
this.setupSignalHandlers();
|
|
|
|
// Initialisation du gestionnaire de modes
|
|
const MM = getModeManager();
|
|
const mode = await MM.initialize();
|
|
|
|
logSh(`🎯 Serveur démarré en mode ${mode.toUpperCase()}`, 'INFO');
|
|
logSh(`⏱️ Temps de démarrage: ${Date.now() - this.startTime}ms`, 'DEBUG');
|
|
|
|
// Monitoring périodique
|
|
this.startHealthMonitoring();
|
|
|
|
return mode;
|
|
|
|
} catch (error) {
|
|
logSh(`❌ ÉCHEC DÉMARRAGE SERVEUR: ${error.message}`, 'ERROR');
|
|
logSh(`Stack trace: ${error.stack}`, 'ERROR');
|
|
|
|
await this.gracefulShutdown(1);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Affiche la bannière de démarrage
|
|
*/
|
|
displayStartupBanner() {
|
|
const version = require('./package.json').version || '1.0.0';
|
|
const nodeVersion = process.version;
|
|
const platform = process.platform;
|
|
|
|
// Bannière visuelle en console.log (pas de logging structuré)
|
|
console.log(`
|
|
╔════════════════════════════════════════════════════════════╗
|
|
║ SEO GENERATOR SERVER ║
|
|
║ MODES EXCLUSIFS ║
|
|
╠════════════════════════════════════════════════════════════╣
|
|
║ Version: ${version.padEnd(10)} │ Node: ${nodeVersion.padEnd(10)} │ OS: ${platform.padEnd(8)} ║
|
|
║ ║
|
|
║ 🎯 MANUAL MODE: Interface Client + API + WebSocket ║
|
|
║ 🤖 AUTO MODE: Traitement Batch Google Sheets ║
|
|
║ ║
|
|
║ 💡 Utilisation: ║
|
|
║ npm start (défaut: MANUAL) ║
|
|
║ npm start -- --mode=manual ║
|
|
║ npm start -- --mode=auto ║
|
|
║ SERVER_MODE=auto npm start ║
|
|
╚════════════════════════════════════════════════════════════╝
|
|
`);
|
|
|
|
logSh('🚀 === SEO GENERATOR SERVER - DÉMARRAGE ===', 'INFO');
|
|
logSh(`📦 Version: ${version} | Node: ${nodeVersion}`, 'INFO');
|
|
}
|
|
|
|
/**
|
|
* Configure la gestion des signaux système
|
|
*/
|
|
setupSignalHandlers() {
|
|
// SIGINT (Ctrl+C) : Kill immédiat sans graceful shutdown
|
|
process.on('SIGINT', () => {
|
|
console.log('\n🛑 SIGINT reçu - Arrêt immédiat (hard kill)');
|
|
process.exit(0);
|
|
});
|
|
|
|
// Arrêt propre sur SIGTERM
|
|
process.on('SIGTERM', () => this.handleShutdownSignal('SIGTERM'));
|
|
|
|
// Gestion erreurs non capturées
|
|
process.on('uncaughtException', (error) => {
|
|
logSh(`❌ ERREUR NON CAPTURÉE: ${error.message}`, 'ERROR');
|
|
logSh(`Stack: ${error.stack}`, 'ERROR');
|
|
this.gracefulShutdown(1);
|
|
});
|
|
|
|
process.on('unhandledRejection', (reason, promise) => {
|
|
logSh(`❌ PROMESSE REJETÉE: ${reason}`, 'ERROR');
|
|
logSh(`Promise: ${promise}`, 'DEBUG');
|
|
// Ne pas arrêter pour les rejections non gérées, juste logger
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Gère les signaux d'arrêt
|
|
*/
|
|
async handleShutdownSignal(signal) {
|
|
logSh(`🛑 Signal reçu: ${signal}`, 'INFO');
|
|
await this.gracefulShutdown(0);
|
|
}
|
|
|
|
/**
|
|
* Arrêt propre du serveur
|
|
*/
|
|
async gracefulShutdown(exitCode = 0) {
|
|
if (this.isShuttingDown) {
|
|
logSh('⚠️ Arrêt déjà en cours...', 'WARNING');
|
|
return;
|
|
}
|
|
|
|
this.isShuttingDown = true;
|
|
const shutdownStart = Date.now();
|
|
|
|
logSh('🛑 ARRÊT SERVEUR EN COURS...', 'INFO');
|
|
|
|
try {
|
|
// Arrêter le monitoring
|
|
if (this.healthInterval) {
|
|
clearInterval(this.healthInterval);
|
|
}
|
|
|
|
// Arrêter le mode actuel via ModeManager
|
|
const MM = getModeManager();
|
|
await MM.stopCurrentMode();
|
|
|
|
// Nettoyage final
|
|
await this.finalCleanup();
|
|
|
|
const shutdownDuration = Date.now() - shutdownStart;
|
|
const totalUptime = Date.now() - this.startTime;
|
|
|
|
logSh(`✅ Arrêt terminé (${shutdownDuration}ms)`, 'INFO');
|
|
logSh(`⏱️ Uptime total: ${Math.floor(totalUptime / 1000)}s`, 'INFO');
|
|
logSh('👋 Au revoir !', 'INFO');
|
|
|
|
} catch (error) {
|
|
logSh(`❌ Erreur durant arrêt: ${error.message}`, 'ERROR');
|
|
exitCode = 1;
|
|
}
|
|
|
|
// Attendre un peu pour que les logs se finalisent
|
|
setTimeout(() => {
|
|
process.exit(exitCode);
|
|
}, 100);
|
|
}
|
|
|
|
/**
|
|
* Nettoyage final avant arrêt
|
|
*/
|
|
async finalCleanup() {
|
|
try {
|
|
// Sauvegarder l'état final
|
|
const MM = getModeManager();
|
|
MM.saveModeState();
|
|
|
|
// Autres nettoyages si nécessaire
|
|
|
|
} catch (error) {
|
|
logSh(`⚠️ Erreur nettoyage final: ${error.message}`, 'WARNING');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Démarre le monitoring de santé
|
|
*/
|
|
startHealthMonitoring() {
|
|
const HEALTH_CHECK_INTERVAL = 30000; // 30 secondes
|
|
|
|
this.healthInterval = setInterval(() => {
|
|
try {
|
|
this.performHealthCheck();
|
|
} catch (error) {
|
|
logSh(`⚠️ Erreur health check: ${error.message}`, 'WARNING');
|
|
}
|
|
}, HEALTH_CHECK_INTERVAL);
|
|
|
|
logSh('💓 Health monitoring démarré', 'DEBUG');
|
|
}
|
|
|
|
/**
|
|
* Vérifie la santé du système
|
|
*/
|
|
performHealthCheck() {
|
|
const MM = getModeManager();
|
|
const status = MM.getStatus();
|
|
const memUsage = process.memoryUsage();
|
|
const uptime = process.uptime();
|
|
|
|
// Log périodique de l'état
|
|
logSh(`💓 Health Check - Mode: ${status.currentMode} | Uptime: ${Math.floor(uptime)}s | RAM: ${Math.round(memUsage.rss / 1024 / 1024)}MB`, 'TRACE');
|
|
|
|
// Vérifications critiques
|
|
if (memUsage.rss > 1024 * 1024 * 1024) { // > 1GB
|
|
logSh('⚠️ Utilisation mémoire élevée', 'WARNING');
|
|
}
|
|
|
|
if (!status.currentMode) {
|
|
logSh('⚠️ Aucun mode actif détecté', 'WARNING');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* API pour changer de mode (si nécessaire)
|
|
*/
|
|
async switchMode(newMode, force = false) {
|
|
logSh(`🔄 Demande changement mode vers: ${newMode}`, 'INFO');
|
|
|
|
try {
|
|
const MM = getModeManager();
|
|
await MM.switchToMode(newMode, force);
|
|
logSh(`✅ Changement mode réussi vers: ${newMode}`, 'INFO');
|
|
return true;
|
|
|
|
} catch (error) {
|
|
logSh(`❌ Échec changement mode: ${error.message}`, 'ERROR');
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Retourne le statut actuel
|
|
*/
|
|
getStatus() {
|
|
return {
|
|
server: {
|
|
startTime: this.startTime,
|
|
uptime: Date.now() - this.startTime,
|
|
isShuttingDown: this.isShuttingDown,
|
|
nodeVersion: process.version,
|
|
platform: process.platform,
|
|
pid: process.pid
|
|
},
|
|
mode: getModeManager().getStatus(),
|
|
memory: process.memoryUsage(),
|
|
timestamp: new Date().toISOString()
|
|
};
|
|
}
|
|
}
|
|
|
|
// ========================================
|
|
// DÉMARRAGE AUTOMATIQUE
|
|
// ========================================
|
|
|
|
// Démarrer le serveur si ce fichier est exécuté directement
|
|
if (require.main === module) {
|
|
const server = new SEOGeneratorServer();
|
|
|
|
server.start().catch((error) => {
|
|
logSh(`💥 ERREUR CRITIQUE DÉMARRAGE: ${error.message}`, 'ERROR');
|
|
process.exit(1);
|
|
});
|
|
}
|
|
|
|
// ============= EXPORTS =============
|
|
module.exports = { SEOGeneratorServer }; |