seo-generator-server/lib/batch/BatchController.js
StillHammer f51c4095f6 Add modular pipeline demo system with real module integration
- Add complete modular demo interface (public/modular-pipeline-demo.html)
- Add standalone demo server (simple-server.js) on port 3333
- Integrate real SelectiveCore, AdversarialCore, HumanSimulation, PatternBreaking modules
- Add configurable pipeline with step-by-step content transformation display
- Add new trend management and workflow configuration modules
- Add comprehensive test suite for full pipeline validation
- Update core modules for better modular integration and demo compatibility

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-23 16:03:20 +08:00

515 lines
13 KiB
JavaScript

// ========================================
// BATCH CONTROLLER - API ENDPOINTS
// Responsabilité: Gestion API pour traitement batch avec configuration pipeline
// ========================================
const { logSh } = require('../ErrorReporting');
const fs = require('fs').promises;
const path = require('path');
const { BatchProcessor } = require('./BatchProcessor');
const { DigitalOceanTemplates } = require('./DigitalOceanTemplates');
const { TrendManager } = require('../trend-prompts/TrendManager');
/**
* BATCH CONTROLLER
* Gestion complète de l'interface de traitement batch
*/
class BatchController {
constructor() {
this.configPath = path.join(__dirname, '../../config/batch-config.json');
this.statusPath = path.join(__dirname, '../../config/batch-status.json');
// Initialiser les composants Phase 2
this.batchProcessor = new BatchProcessor();
this.digitalOceanTemplates = new DigitalOceanTemplates();
this.trendManager = new TrendManager();
// Configuration par défaut
this.defaultConfig = {
selective: 'standardEnhancement',
adversarial: 'light',
humanSimulation: 'none',
patternBreaking: 'none',
intensity: 1.0,
rowRange: { start: 2, end: 10 },
saveIntermediateSteps: false,
trendId: null, // Tendance à appliquer (optionnel)
lastUpdated: new Date().toISOString()
};
// État par défaut
this.defaultStatus = {
status: 'idle',
currentRow: null,
totalRows: 0,
progress: 0,
startTime: null,
estimatedEnd: null,
errors: [],
lastResult: null,
config: this.defaultConfig
};
this.initializeFiles();
}
/**
* Initialise les fichiers de configuration
*/
async initializeFiles() {
try {
// Créer le dossier config s'il n'existe pas
const configDir = path.dirname(this.configPath);
await fs.mkdir(configDir, { recursive: true });
// Créer config par défaut si inexistant
try {
await fs.access(this.configPath);
} catch {
await fs.writeFile(this.configPath, JSON.stringify(this.defaultConfig, null, 2));
logSh('📝 Configuration batch par défaut créée', 'DEBUG');
}
// Créer status par défaut si inexistant
try {
await fs.access(this.statusPath);
} catch {
await fs.writeFile(this.statusPath, JSON.stringify(this.defaultStatus, null, 2));
logSh('📊 Status batch par défaut créé', 'DEBUG');
}
} catch (error) {
logSh(`❌ Erreur initialisation fichiers batch: ${error.message}`, 'ERROR');
}
}
// ========================================
// ENDPOINTS CONFIGURATION
// ========================================
/**
* GET /api/batch/config
* Récupère la configuration actuelle
*/
async getConfig(req, res) {
try {
// Utiliser la nouvelle API du BatchProcessor refactorisé
const status = this.batchProcessor.getExtendedStatus();
// Ajouter les tendances disponibles
const availableTrends = this.trendManager.getAvailableTrends();
const currentTrend = this.trendManager.getCurrentTrend();
logSh('📋 Configuration batch récupérée', 'DEBUG');
res.json({
success: true,
config: status.config,
availableOptions: status.availableOptions,
trends: {
available: availableTrends,
current: currentTrend,
categories: this.groupTrendsByCategory(availableTrends)
}
});
} catch (error) {
logSh(`❌ Erreur récupération config: ${error.message}`, 'ERROR');
res.status(500).json({
success: false,
error: 'Erreur récupération configuration',
details: error.message
});
}
}
/**
* POST /api/batch/config
* Sauvegarde la configuration
*/
async saveConfig(req, res) {
try {
const newConfig = req.body;
// Utiliser la nouvelle API du BatchProcessor refactorisé
const result = await this.batchProcessor.updateConfiguration(newConfig);
res.json({
success: true,
message: 'Configuration sauvegardée avec succès',
config: result.config
});
} catch (error) {
logSh(`❌ Erreur sauvegarde config: ${error.message}`, 'ERROR');
res.status(500).json({
success: false,
error: 'Erreur sauvegarde configuration',
details: error.message
});
}
}
// ========================================
// ENDPOINTS CONTRÔLE TRAITEMENT
// ========================================
/**
* POST /api/batch/start
* Démarre le traitement batch
*/
async startBatch(req, res) {
try {
// Démarrer le traitement via BatchProcessor
const status = await this.batchProcessor.start();
logSh(`🚀 Traitement batch démarré - ${status.totalRows} lignes`, 'INFO');
res.json({
success: true,
message: 'Traitement batch démarré',
status: status
});
} catch (error) {
logSh(`❌ Erreur démarrage batch: ${error.message}`, 'ERROR');
res.status(500).json({
success: false,
error: 'Erreur démarrage traitement',
details: error.message
});
}
}
/**
* POST /api/batch/stop
* Arrête le traitement batch
*/
async stopBatch(req, res) {
try {
const status = await this.batchProcessor.stop();
logSh('🛑 Traitement batch arrêté', 'INFO');
res.json({
success: true,
message: 'Traitement batch arrêté',
status: status
});
} catch (error) {
logSh(`❌ Erreur arrêt batch: ${error.message}`, 'ERROR');
res.status(500).json({
success: false,
error: 'Erreur arrêt traitement',
details: error.message
});
}
}
/**
* POST /api/batch/pause
* Met en pause le traitement
*/
async pauseBatch(req, res) {
try {
const status = await this.batchProcessor.pause();
logSh('⏸️ Traitement batch mis en pause', 'INFO');
res.json({
success: true,
message: 'Traitement mis en pause',
status: status
});
} catch (error) {
logSh(`❌ Erreur pause batch: ${error.message}`, 'ERROR');
res.status(500).json({
success: false,
error: 'Erreur pause traitement',
details: error.message
});
}
}
/**
* POST /api/batch/resume
* Reprend le traitement
*/
async resumeBatch(req, res) {
try {
const status = await this.batchProcessor.resume();
logSh('▶️ Traitement batch repris', 'INFO');
res.json({
success: true,
message: 'Traitement repris',
status: status
});
} catch (error) {
logSh(`❌ Erreur reprise batch: ${error.message}`, 'ERROR');
res.status(500).json({
success: false,
error: 'Erreur reprise traitement',
details: error.message
});
}
}
// ========================================
// ENDPOINTS MONITORING
// ========================================
/**
* GET /api/batch/status
* Récupère l'état actuel du traitement
*/
async getStatus(req, res) {
try {
const status = this.batchProcessor.getStatus();
res.json({
success: true,
status: status,
timestamp: new Date().toISOString()
});
} catch (error) {
logSh(`❌ Erreur récupération status: ${error.message}`, 'ERROR');
res.status(500).json({
success: false,
error: 'Erreur récupération status',
details: error.message
});
}
}
/**
* GET /api/batch/progress
* Récupère la progression détaillée
*/
async getProgress(req, res) {
try {
const progress = this.batchProcessor.getProgress();
res.json({
success: true,
progress: progress,
timestamp: new Date().toISOString()
});
} catch (error) {
logSh(`❌ Erreur récupération progress: ${error.message}`, 'ERROR');
res.status(500).json({
success: false,
error: 'Erreur récupération progression',
details: error.message
});
}
}
// ========================================
// ENDPOINTS TENDANCES
// ========================================
/**
* GET /api/batch/trends
* Liste toutes les tendances disponibles
*/
async getTrends(req, res) {
try {
const trends = this.trendManager.getAvailableTrends();
const current = this.trendManager.getCurrentTrend();
const status = this.trendManager.getStatus();
res.json({
success: true,
trends: {
available: trends,
current: current,
categories: this.groupTrendsByCategory(trends),
status: status
},
timestamp: new Date().toISOString()
});
} catch (error) {
logSh(`❌ Erreur récupération tendances: ${error.message}`, 'ERROR');
res.status(500).json({
success: false,
error: 'Erreur récupération tendances',
details: error.message
});
}
}
/**
* POST /api/batch/trends/select
* Sélectionne une tendance
*/
async selectTrend(req, res) {
try {
const { trendId } = req.body;
if (!trendId) {
return res.status(400).json({
success: false,
error: 'ID de tendance requis'
});
}
const result = await this.trendManager.setTrend(trendId);
logSh(`🎯 Tendance sélectionnée: ${result.name}`, 'INFO');
res.json({
success: true,
trend: result,
message: `Tendance "${result.name}" appliquée`,
timestamp: new Date().toISOString()
});
} catch (error) {
logSh(`❌ Erreur sélection tendance: ${error.message}`, 'ERROR');
res.status(400).json({
success: false,
error: 'Erreur sélection tendance',
details: error.message
});
}
}
/**
* DELETE /api/batch/trends
* Désactive la tendance actuelle
*/
async clearTrend(req, res) {
try {
this.trendManager.clearTrend();
logSh('🔄 Tendance désactivée', 'INFO');
res.json({
success: true,
message: 'Aucune tendance appliquée',
timestamp: new Date().toISOString()
});
} catch (error) {
logSh(`❌ Erreur désactivation tendance: ${error.message}`, 'ERROR');
res.status(500).json({
success: false,
error: 'Erreur désactivation tendance',
details: error.message
});
}
}
// ========================================
// HELPER METHODS TENDANCES
// ========================================
/**
* Groupe les tendances par catégorie
*/
groupTrendsByCategory(trends) {
const categories = {};
trends.forEach(trend => {
const category = trend.category || 'autre';
if (!categories[category]) {
categories[category] = [];
}
categories[category].push(trend);
});
return categories;
}
// ========================================
// ENDPOINTS DIGITAL OCEAN
// ========================================
/**
* GET /api/batch/templates
* Liste les templates disponibles
*/
async getTemplates(req, res) {
try {
const templates = await this.digitalOceanTemplates.listAvailableTemplates();
const stats = this.digitalOceanTemplates.getCacheStats();
res.json({
success: true,
templates: templates,
cacheStats: stats,
timestamp: new Date().toISOString()
});
} catch (error) {
logSh(`❌ Erreur récupération templates: ${error.message}`, 'ERROR');
res.status(500).json({
success: false,
error: 'Erreur récupération templates',
details: error.message
});
}
}
/**
* GET /api/batch/templates/:filename
* Récupère un template spécifique
*/
async getTemplate(req, res) {
try {
const { filename } = req.params;
const template = await this.digitalOceanTemplates.getTemplate(filename);
res.json({
success: true,
filename: filename,
template: template,
timestamp: new Date().toISOString()
});
} catch (error) {
logSh(`❌ Erreur récupération template ${req.params.filename}: ${error.message}`, 'ERROR');
res.status(500).json({
success: false,
error: 'Erreur récupération template',
details: error.message
});
}
}
/**
* DELETE /api/batch/cache
* Vide le cache des templates
*/
async clearCache(req, res) {
try {
await this.digitalOceanTemplates.clearCache();
res.json({
success: true,
message: 'Cache vidé avec succès',
timestamp: new Date().toISOString()
});
} catch (error) {
logSh(`❌ Erreur vidage cache: ${error.message}`, 'ERROR');
res.status(500).json({
success: false,
error: 'Erreur vidage cache',
details: error.message
});
}
}
}
// ============= EXPORTS =============
module.exports = { BatchController };