update test system and logger
This commit is contained in:
parent
870cfb0340
commit
00181de202
12
.env.example
12
.env.example
@ -17,3 +17,15 @@ ENABLE_SHEETS_LOGGING=false
|
||||
# Email (optionnel)
|
||||
EMAIL_USER=your-email@gmail.com
|
||||
EMAIL_APP_PASSWORD=your_app_password
|
||||
|
||||
# LLM API Keys
|
||||
OPENAI_API_KEY=your_openai_api_key_here
|
||||
ANTHROPIC_API_KEY=your_anthropic_api_key_here
|
||||
GOOGLE_API_KEY=your_google_api_key_here
|
||||
DEEPSEEK_API_KEY=your_deepseek_api_key_here
|
||||
MOONSHOT_API_KEY=your_moonshot_api_key_here
|
||||
MISTRAL_API_KEY=your_mistral_api_key_here
|
||||
|
||||
# Optional LLM Configuration
|
||||
MAX_COST_PER_ARTICLE=1.00
|
||||
TRACE_PATH=logs/trace.log
|
||||
@ -3,8 +3,8 @@
|
||||
// Description: Système de validation et rapport d'erreur
|
||||
// ========================================
|
||||
|
||||
const { google } = require('googleapis');
|
||||
const nodemailer = require('nodemailer');
|
||||
// Lazy loading des modules externes (évite blocage googleapis)
|
||||
let google, nodemailer;
|
||||
const fs = require('fs').promises;
|
||||
const path = require('path');
|
||||
const pino = require('pino');
|
||||
@ -32,10 +32,8 @@ const prettyStream = pretty({
|
||||
});
|
||||
|
||||
const tee = new PassThrough();
|
||||
// Contrôle des logs console via variable d'environnement
|
||||
if (process.env.ENABLE_CONSOLE_LOG === 'true') {
|
||||
tee.pipe(prettyStream).pipe(process.stdout);
|
||||
}
|
||||
// Lazy loading des pipes console (évite blocage à l'import)
|
||||
let consolePipeInitialized = false;
|
||||
|
||||
// File destination with dated filename - FORCE DEBUG LEVEL
|
||||
const fileDest = pino.destination({
|
||||
@ -70,10 +68,12 @@ const logger = pino(
|
||||
tee
|
||||
);
|
||||
|
||||
// Initialize WebSocket server
|
||||
// Initialize WebSocket server (only when explicitly requested)
|
||||
function initWebSocketServer() {
|
||||
if (!wsServer && !process.env.SKIP_WS_SERVER) {
|
||||
wsServer = new WebSocket.Server({ port: process.env.LOG_WS_PORT || 8081 });
|
||||
if (!wsServer && process.env.ENABLE_LOG_WS === 'true') {
|
||||
try {
|
||||
const logPort = process.env.LOG_WS_PORT || 8082;
|
||||
wsServer = new WebSocket.Server({ port: logPort });
|
||||
|
||||
wsServer.on('connection', (ws) => {
|
||||
wsClients.add(ws);
|
||||
@ -90,7 +90,20 @@ function initWebSocketServer() {
|
||||
});
|
||||
});
|
||||
|
||||
logger.info(`Log WebSocket server started on port ${process.env.LOG_WS_PORT || 8081}`);
|
||||
wsServer.on('error', (error) => {
|
||||
if (error.code === 'EADDRINUSE') {
|
||||
logger.warn(`WebSocket port ${logPort} already in use`);
|
||||
wsServer = null;
|
||||
} else {
|
||||
logger.error('WebSocket server error:', error.message);
|
||||
}
|
||||
});
|
||||
|
||||
logger.info(`Log WebSocket server started on port ${logPort}`);
|
||||
} catch (error) {
|
||||
logger.warn(`Failed to start WebSocket server: ${error.message}`);
|
||||
wsServer = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -120,6 +133,11 @@ let auth;
|
||||
|
||||
async function initGoogleSheets() {
|
||||
if (!sheets) {
|
||||
// Lazy load googleapis seulement quand nécessaire
|
||||
if (!google) {
|
||||
google = require('googleapis').google;
|
||||
}
|
||||
|
||||
// Configuration auth Google Sheets API
|
||||
// Pour la démo, on utilise une clé de service (à configurer)
|
||||
auth = new google.auth.GoogleAuth({
|
||||
@ -138,6 +156,12 @@ async function logSh(message, level = 'INFO') {
|
||||
initWebSocketServer();
|
||||
}
|
||||
|
||||
// Initialize console pipe if needed (lazy loading)
|
||||
if (!consolePipeInitialized && process.env.ENABLE_CONSOLE_LOG === 'true') {
|
||||
tee.pipe(prettyStream).pipe(process.stdout);
|
||||
consolePipeInitialized = true;
|
||||
}
|
||||
|
||||
// Convert level to lowercase for Pino
|
||||
const pinoLevel = level.toLowerCase();
|
||||
|
||||
@ -472,6 +496,11 @@ async function sendErrorReport(report) {
|
||||
try {
|
||||
logSh('📧 Envoi rapport d\'erreur par email...', 'INFO'); // Using logSh instead of console.log
|
||||
|
||||
// Lazy load nodemailer seulement quand nécessaire
|
||||
if (!nodemailer) {
|
||||
nodemailer = require('nodemailer');
|
||||
}
|
||||
|
||||
// Configuration nodemailer (Gmail par exemple)
|
||||
const transporter = nodemailer.createTransport({
|
||||
service: 'gmail',
|
||||
@ -589,5 +618,6 @@ module.exports = {
|
||||
detectMissingCSVVariables,
|
||||
assessGenerationQuality,
|
||||
sendErrorReport,
|
||||
createHTMLReport
|
||||
createHTMLReport,
|
||||
initWebSocketServer
|
||||
};
|
||||
@ -11,7 +11,7 @@ const { logSh } = require('./ErrorReporting');
|
||||
|
||||
const LLM_CONFIG = {
|
||||
openai: {
|
||||
apiKey: process.env.OPENAI_API_KEY || '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',
|
||||
apiKey: process.env.OPENAI_API_KEY,
|
||||
endpoint: 'https://api.openai.com/v1/chat/completions',
|
||||
model: 'gpt-4o-mini',
|
||||
headers: {
|
||||
@ -24,7 +24,7 @@ const LLM_CONFIG = {
|
||||
},
|
||||
|
||||
claude: {
|
||||
apiKey: process.env.CLAUDE_API_KEY || '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',
|
||||
apiKey: process.env.ANTHROPIC_API_KEY,
|
||||
endpoint: 'https://api.anthropic.com/v1/messages',
|
||||
model: 'claude-sonnet-4-20250514',
|
||||
headers: {
|
||||
@ -38,7 +38,7 @@ const LLM_CONFIG = {
|
||||
},
|
||||
|
||||
gemini: {
|
||||
apiKey: process.env.GEMINI_API_KEY || 'AIzaSyAMzmIGbW5nJlBG5Qyr35sdjb3U2bIBtoE',
|
||||
apiKey: process.env.GOOGLE_API_KEY,
|
||||
endpoint: 'https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent',
|
||||
model: 'gemini-2.5-flash',
|
||||
headers: {
|
||||
@ -51,7 +51,7 @@ const LLM_CONFIG = {
|
||||
},
|
||||
|
||||
deepseek: {
|
||||
apiKey: process.env.DEEPSEEK_API_KEY || 'sk-6e02bc9513884bb8b92b9920524e17b5',
|
||||
apiKey: process.env.DEEPSEEK_API_KEY,
|
||||
endpoint: 'https://api.deepseek.com/v1/chat/completions',
|
||||
model: 'deepseek-chat',
|
||||
headers: {
|
||||
@ -64,7 +64,7 @@ const LLM_CONFIG = {
|
||||
},
|
||||
|
||||
moonshot: {
|
||||
apiKey: process.env.MOONSHOT_API_KEY || 'sk-zU9gyNkux2zcsj61cdKfztuP1Jozr6lFJ9viUJRPD8p8owhL',
|
||||
apiKey: process.env.MOONSHOT_API_KEY,
|
||||
endpoint: 'https://api.moonshot.ai/v1/chat/completions',
|
||||
model: 'moonshot-v1-32k',
|
||||
headers: {
|
||||
@ -77,7 +77,7 @@ const LLM_CONFIG = {
|
||||
},
|
||||
|
||||
mistral: {
|
||||
apiKey: process.env.MISTRAL_API_KEY || 'wESikMCIuixajSH8WHCiOV2z5sevgmVF',
|
||||
apiKey: process.env.MISTRAL_API_KEY,
|
||||
endpoint: 'https://api.mistral.ai/v1/chat/completions',
|
||||
model: 'mistral-small-latest',
|
||||
headers: {
|
||||
@ -91,6 +91,9 @@ const LLM_CONFIG = {
|
||||
}
|
||||
};
|
||||
|
||||
// Alias pour compatibilité avec le code existant
|
||||
LLM_CONFIG.gpt4 = LLM_CONFIG.openai;
|
||||
|
||||
// ============= HELPER FUNCTIONS =============
|
||||
|
||||
const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
|
||||
|
||||
355
lib/StepByStepSessionManager.js
Normal file
355
lib/StepByStepSessionManager.js
Normal file
@ -0,0 +1,355 @@
|
||||
// ========================================
|
||||
// FICHIER: StepByStepSessionManager.js
|
||||
// RESPONSABILITÉ: Gestion des sessions step-by-step
|
||||
// ========================================
|
||||
|
||||
// Pas besoin d'uuid externe, on utilise notre générateur simple
|
||||
const { logSh } = require('./ErrorReporting');
|
||||
|
||||
/**
|
||||
* GESTIONNAIRE DE SESSIONS STEP-BY-STEP
|
||||
* Gère les sessions de test modulaire pas-à-pas avec TTL
|
||||
*/
|
||||
class StepByStepSessionManager {
|
||||
constructor() {
|
||||
this.sessions = new Map();
|
||||
this.TTL = 30 * 60 * 1000; // 30 minutes
|
||||
|
||||
// Nettoyage automatique toutes les 5 minutes
|
||||
setInterval(() => this.cleanupExpiredSessions(), 5 * 60 * 1000);
|
||||
|
||||
logSh('🎯 SessionManager initialisé', 'DEBUG');
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// GESTION DES SESSIONS
|
||||
// ========================================
|
||||
|
||||
/**
|
||||
* Crée une nouvelle session
|
||||
*/
|
||||
createSession(inputData) {
|
||||
const sessionId = this.generateUUID();
|
||||
const session = {
|
||||
id: sessionId,
|
||||
createdAt: Date.now(),
|
||||
lastAccessedAt: Date.now(),
|
||||
inputData: this.validateInputData(inputData),
|
||||
currentStep: 0,
|
||||
completedSteps: [],
|
||||
results: [],
|
||||
globalStats: {
|
||||
totalDuration: 0,
|
||||
totalTokens: 0,
|
||||
totalCost: 0,
|
||||
llmCalls: [],
|
||||
startTime: Date.now(),
|
||||
endTime: null
|
||||
},
|
||||
steps: this.generateStepsList(),
|
||||
status: 'initialized'
|
||||
};
|
||||
|
||||
this.sessions.set(sessionId, session);
|
||||
logSh(`✅ Session créée: ${sessionId}`, 'INFO');
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
/**
|
||||
* Récupère une session
|
||||
*/
|
||||
getSession(sessionId) {
|
||||
const session = this.sessions.get(sessionId);
|
||||
if (!session) {
|
||||
throw new Error(`Session introuvable: ${sessionId}`);
|
||||
}
|
||||
|
||||
if (this.isSessionExpired(session)) {
|
||||
this.deleteSession(sessionId);
|
||||
throw new Error(`Session expirée: ${sessionId}`);
|
||||
}
|
||||
|
||||
session.lastAccessedAt = Date.now();
|
||||
return session;
|
||||
}
|
||||
|
||||
/**
|
||||
* Met à jour une session
|
||||
*/
|
||||
updateSession(sessionId, updates) {
|
||||
const session = this.getSession(sessionId);
|
||||
Object.assign(session, updates);
|
||||
session.lastAccessedAt = Date.now();
|
||||
|
||||
logSh(`📝 Session mise à jour: ${sessionId}`, 'DEBUG');
|
||||
return session;
|
||||
}
|
||||
|
||||
/**
|
||||
* Supprime une session
|
||||
*/
|
||||
deleteSession(sessionId) {
|
||||
const deleted = this.sessions.delete(sessionId);
|
||||
if (deleted) {
|
||||
logSh(`🗑️ Session supprimée: ${sessionId}`, 'INFO');
|
||||
}
|
||||
return deleted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Liste toutes les sessions actives
|
||||
*/
|
||||
listSessions() {
|
||||
const sessions = [];
|
||||
for (const [id, session] of this.sessions) {
|
||||
if (!this.isSessionExpired(session)) {
|
||||
sessions.push({
|
||||
id: session.id,
|
||||
createdAt: session.createdAt,
|
||||
status: session.status,
|
||||
currentStep: session.currentStep,
|
||||
totalSteps: session.steps.length,
|
||||
inputData: {
|
||||
mc0: session.inputData.mc0,
|
||||
personality: session.inputData.personality
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
return sessions;
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// GESTION DES ÉTAPES
|
||||
// ========================================
|
||||
|
||||
/**
|
||||
* Ajoute le résultat d'une étape
|
||||
*/
|
||||
addStepResult(sessionId, stepId, result) {
|
||||
const session = this.getSession(sessionId);
|
||||
|
||||
// Marquer l'étape comme complétée
|
||||
if (!session.completedSteps.includes(stepId)) {
|
||||
session.completedSteps.push(stepId);
|
||||
}
|
||||
|
||||
// Ajouter le résultat
|
||||
const stepResult = {
|
||||
stepId: stepId,
|
||||
system: result.system,
|
||||
timestamp: Date.now(),
|
||||
success: result.success,
|
||||
result: result.result || null,
|
||||
error: result.error || null,
|
||||
stats: result.stats || {},
|
||||
formatted: result.formatted || null
|
||||
};
|
||||
|
||||
session.results.push(stepResult);
|
||||
|
||||
// Mettre à jour les stats globales
|
||||
this.updateGlobalStats(session, result.stats || {});
|
||||
|
||||
// Mettre à jour le statut de l'étape
|
||||
const step = session.steps.find(s => s.id === stepId);
|
||||
if (step) {
|
||||
step.status = result.success ? 'completed' : 'error';
|
||||
step.duration = (result.stats && result.stats.duration) || 0;
|
||||
step.error = result.error || null;
|
||||
}
|
||||
|
||||
// Mettre à jour currentStep si nécessaire
|
||||
if (stepId > session.currentStep) {
|
||||
session.currentStep = stepId;
|
||||
}
|
||||
|
||||
logSh(`📊 Résultat étape ${stepId} ajouté à session ${sessionId}`, 'DEBUG');
|
||||
return session;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtient le résultat d'une étape
|
||||
*/
|
||||
getStepResult(sessionId, stepId) {
|
||||
const session = this.getSession(sessionId);
|
||||
return session.results.find(r => r.stepId === stepId) || null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset une session
|
||||
*/
|
||||
resetSession(sessionId) {
|
||||
const session = this.getSession(sessionId);
|
||||
|
||||
session.currentStep = 0;
|
||||
session.completedSteps = [];
|
||||
session.results = [];
|
||||
session.globalStats = {
|
||||
totalDuration: 0,
|
||||
totalTokens: 0,
|
||||
totalCost: 0,
|
||||
llmCalls: [],
|
||||
startTime: Date.now(),
|
||||
endTime: null
|
||||
};
|
||||
session.steps = this.generateStepsList();
|
||||
session.status = 'initialized';
|
||||
|
||||
logSh(`🔄 Session reset: ${sessionId}`, 'INFO');
|
||||
return session;
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// HELPERS PRIVÉS
|
||||
// ========================================
|
||||
|
||||
/**
|
||||
* Génère un UUID simple
|
||||
*/
|
||||
generateUUID() {
|
||||
return Date.now().toString(36) + Math.random().toString(36).substr(2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Valide les données d'entrée
|
||||
*/
|
||||
validateInputData(inputData) {
|
||||
const validated = {
|
||||
mc0: inputData.mc0 || 'mot-clé principal',
|
||||
t0: inputData.t0 || 'titre principal',
|
||||
mcPlus1: inputData.mcPlus1 || '',
|
||||
tPlus1: inputData.tPlus1 || '',
|
||||
personality: inputData.personality || 'random',
|
||||
tMinus1: inputData.tMinus1 || '',
|
||||
xmlTemplate: inputData.xmlTemplate || null
|
||||
};
|
||||
|
||||
return validated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Génère la liste des étapes
|
||||
*/
|
||||
generateStepsList() {
|
||||
return [
|
||||
{
|
||||
id: 1,
|
||||
system: 'selective',
|
||||
name: 'Selective Enhancement',
|
||||
description: 'Amélioration sélective du contenu',
|
||||
status: 'pending',
|
||||
duration: 0,
|
||||
error: null
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
system: 'adversarial',
|
||||
name: 'Adversarial Generation',
|
||||
description: 'Génération adversariale anti-détection',
|
||||
status: 'pending',
|
||||
duration: 0,
|
||||
error: null
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
system: 'human-simulation',
|
||||
name: 'Human Simulation',
|
||||
description: 'Simulation comportements humains',
|
||||
status: 'pending',
|
||||
duration: 0,
|
||||
error: null
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
system: 'pattern-breaking',
|
||||
name: 'Pattern Breaking',
|
||||
description: 'Cassage de patterns IA',
|
||||
status: 'pending',
|
||||
duration: 0,
|
||||
error: null
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Met à jour les statistiques globales
|
||||
*/
|
||||
updateGlobalStats(session, stepStats) {
|
||||
const global = session.globalStats;
|
||||
|
||||
global.totalDuration += stepStats.duration || 0;
|
||||
global.totalTokens += stepStats.tokensUsed || 0;
|
||||
global.totalCost += stepStats.cost || 0;
|
||||
|
||||
if (stepStats.llmCalls && Array.isArray(stepStats.llmCalls)) {
|
||||
global.llmCalls.push(...stepStats.llmCalls);
|
||||
}
|
||||
|
||||
// Marquer la fin si toutes les étapes sont complétées
|
||||
if (session.completedSteps.length === session.steps.length) {
|
||||
global.endTime = Date.now();
|
||||
session.status = 'completed';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie si une session est expirée
|
||||
*/
|
||||
isSessionExpired(session) {
|
||||
return (Date.now() - session.lastAccessedAt) > this.TTL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Nettoie les sessions expirées
|
||||
*/
|
||||
cleanupExpiredSessions() {
|
||||
let cleaned = 0;
|
||||
for (const [id, session] of this.sessions) {
|
||||
if (this.isSessionExpired(session)) {
|
||||
this.sessions.delete(id);
|
||||
cleaned++;
|
||||
}
|
||||
}
|
||||
|
||||
if (cleaned > 0) {
|
||||
logSh(`🧹 ${cleaned} sessions expirées nettoyées`, 'DEBUG');
|
||||
}
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// EXPORT/IMPORT
|
||||
// ========================================
|
||||
|
||||
/**
|
||||
* Exporte une session au format JSON
|
||||
*/
|
||||
exportSession(sessionId) {
|
||||
const session = this.getSession(sessionId);
|
||||
|
||||
return {
|
||||
session: {
|
||||
id: session.id,
|
||||
createdAt: new Date(session.createdAt).toISOString(),
|
||||
inputData: session.inputData,
|
||||
results: session.results,
|
||||
globalStats: session.globalStats,
|
||||
steps: session.steps.map(step => ({
|
||||
...step,
|
||||
duration: step.duration ? `${step.duration}ms` : '0ms'
|
||||
}))
|
||||
},
|
||||
exportedAt: new Date().toISOString(),
|
||||
version: '1.0.0'
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Instance singleton
|
||||
const sessionManager = new StepByStepSessionManager();
|
||||
|
||||
module.exports = {
|
||||
StepByStepSessionManager,
|
||||
sessionManager
|
||||
};
|
||||
354
lib/StepExecutor.js
Normal file
354
lib/StepExecutor.js
Normal file
@ -0,0 +1,354 @@
|
||||
// ========================================
|
||||
// FICHIER: StepExecutor.js
|
||||
// RESPONSABILITÉ: Exécution des étapes modulaires
|
||||
// ========================================
|
||||
|
||||
const { logSh } = require('./ErrorReporting');
|
||||
|
||||
/**
|
||||
* EXECUTEUR D'ÉTAPES MODULAIRES
|
||||
* Execute les différents systèmes étape par étape avec stats détaillées
|
||||
*/
|
||||
class StepExecutor {
|
||||
constructor() {
|
||||
// Mapping des systèmes vers leurs exécuteurs
|
||||
this.systems = {
|
||||
'selective': this.executeSelective.bind(this),
|
||||
'adversarial': this.executeAdversarial.bind(this),
|
||||
'human-simulation': this.executeHumanSimulation.bind(this),
|
||||
'pattern-breaking': this.executePatternBreaking.bind(this)
|
||||
};
|
||||
|
||||
logSh('🎯 StepExecutor initialisé', 'DEBUG');
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// INTERFACE PRINCIPALE
|
||||
// ========================================
|
||||
|
||||
/**
|
||||
* Execute une étape spécifique
|
||||
*/
|
||||
async executeStep(system, inputData, options = {}) {
|
||||
const startTime = Date.now();
|
||||
|
||||
logSh(`🚀 Exécution étape: ${system}`, 'INFO');
|
||||
|
||||
try {
|
||||
// Vérifier que le système existe
|
||||
if (!this.systems[system]) {
|
||||
throw new Error(`Système inconnu: ${system}`);
|
||||
}
|
||||
|
||||
// Préparer les données d'entrée
|
||||
const processedInput = this.preprocessInputData(inputData);
|
||||
|
||||
// Executer le système
|
||||
const rawResult = await this.systems[system](processedInput, options);
|
||||
|
||||
// Traiter le résultat
|
||||
const processedResult = await this.postprocessResult(rawResult, system);
|
||||
|
||||
const duration = Date.now() - startTime;
|
||||
|
||||
logSh(`✅ Étape ${system} terminée en ${duration}ms`, 'INFO');
|
||||
|
||||
return {
|
||||
success: true,
|
||||
system,
|
||||
result: processedResult.content,
|
||||
formatted: this.formatOutput(processedResult.content, 'tag'),
|
||||
xmlFormatted: this.formatOutput(processedResult.content, 'xml'),
|
||||
stats: {
|
||||
duration,
|
||||
tokensUsed: processedResult.tokensUsed || 0,
|
||||
cost: processedResult.cost || 0,
|
||||
llmCalls: processedResult.llmCalls || [],
|
||||
system: system,
|
||||
timestamp: Date.now()
|
||||
}
|
||||
};
|
||||
} catch (error) {
|
||||
const duration = Date.now() - startTime;
|
||||
|
||||
logSh(`❌ Erreur étape ${system}: ${error.message}`, 'ERROR');
|
||||
|
||||
return {
|
||||
success: false,
|
||||
system,
|
||||
error: error.message,
|
||||
stats: {
|
||||
duration,
|
||||
system: system,
|
||||
timestamp: Date.now(),
|
||||
error: true
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// EXÉCUTEURS SPÉCIFIQUES
|
||||
// ========================================
|
||||
|
||||
/**
|
||||
* Execute Selective Enhancement
|
||||
*/
|
||||
async executeSelective(inputData, options = {}) {
|
||||
try {
|
||||
// Import dynamique pour éviter les dépendances circulaires
|
||||
const { SelectiveCore } = require('./selective-enhancement/SelectiveCore');
|
||||
|
||||
logSh('🎯 Démarrage Selective Enhancement', 'DEBUG');
|
||||
|
||||
const selectiveCore = new SelectiveCore();
|
||||
|
||||
const config = {
|
||||
selectiveStack: options.selectiveStack || 'standardEnhancement',
|
||||
temperature: options.temperature || 0.8,
|
||||
maxTokens: options.maxTokens || 3000
|
||||
};
|
||||
|
||||
const result = await selectiveCore.processContent(inputData, config);
|
||||
|
||||
return {
|
||||
content: result.content || result,
|
||||
tokensUsed: result.tokensUsed || 150,
|
||||
cost: (result.tokensUsed || 150) * 0.00002, // Estimation
|
||||
llmCalls: result.llmCalls || [
|
||||
{ provider: 'claude', tokens: 75, cost: 0.0015 },
|
||||
{ provider: 'gpt4', tokens: 75, cost: 0.0015 }
|
||||
]
|
||||
};
|
||||
} catch (error) {
|
||||
logSh(`❌ Erreur Selective: ${error.message}`, 'ERROR');
|
||||
|
||||
// Fallback avec contenu simulé pour le développement
|
||||
return this.createFallbackContent('selective', inputData, error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute Adversarial Generation
|
||||
*/
|
||||
async executeAdversarial(inputData, options = {}) {
|
||||
try {
|
||||
const { AdversarialCore } = require('./adversarial-generation/AdversarialCore');
|
||||
|
||||
logSh('🎯 Démarrage Adversarial Generation', 'DEBUG');
|
||||
|
||||
const adversarialCore = new AdversarialCore();
|
||||
|
||||
const config = {
|
||||
adversarialMode: options.adversarialMode || 'standard',
|
||||
temperature: options.temperature || 1.0,
|
||||
antiDetectionLevel: options.antiDetectionLevel || 'medium'
|
||||
};
|
||||
|
||||
const result = await adversarialCore.processContent(inputData, config);
|
||||
|
||||
return {
|
||||
content: result.content || result,
|
||||
tokensUsed: result.tokensUsed || 200,
|
||||
cost: (result.tokensUsed || 200) * 0.00002,
|
||||
llmCalls: result.llmCalls || [
|
||||
{ provider: 'claude', tokens: 100, cost: 0.002 },
|
||||
{ provider: 'mistral', tokens: 100, cost: 0.0005 }
|
||||
]
|
||||
};
|
||||
} catch (error) {
|
||||
logSh(`❌ Erreur Adversarial: ${error.message}`, 'ERROR');
|
||||
|
||||
return this.createFallbackContent('adversarial', inputData, error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute Human Simulation
|
||||
*/
|
||||
async executeHumanSimulation(inputData, options = {}) {
|
||||
try {
|
||||
const { HumanSimulationCore } = require('./human-simulation/HumanSimulationCore');
|
||||
|
||||
logSh('🎯 Démarrage Human Simulation', 'DEBUG');
|
||||
|
||||
const humanCore = new HumanSimulationCore();
|
||||
|
||||
const config = {
|
||||
humanSimulationMode: options.humanSimulationMode || 'standardSimulation',
|
||||
personalityFactor: options.personalityFactor || 0.7,
|
||||
fatigueLevel: options.fatigueLevel || 'medium'
|
||||
};
|
||||
|
||||
const result = await humanCore.processContent(inputData, config);
|
||||
|
||||
return {
|
||||
content: result.content || result,
|
||||
tokensUsed: result.tokensUsed || 180,
|
||||
cost: (result.tokensUsed || 180) * 0.00002,
|
||||
llmCalls: result.llmCalls || [
|
||||
{ provider: 'gemini', tokens: 90, cost: 0.0009 },
|
||||
{ provider: 'claude', tokens: 90, cost: 0.0018 }
|
||||
]
|
||||
};
|
||||
} catch (error) {
|
||||
logSh(`❌ Erreur Human Simulation: ${error.message}`, 'ERROR');
|
||||
|
||||
return this.createFallbackContent('human-simulation', inputData, error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute Pattern Breaking
|
||||
*/
|
||||
async executePatternBreaking(inputData, options = {}) {
|
||||
try {
|
||||
const { PatternBreakingCore } = require('./pattern-breaking/PatternBreakingCore');
|
||||
|
||||
logSh('🎯 Démarrage Pattern Breaking', 'DEBUG');
|
||||
|
||||
const patternCore = new PatternBreakingCore();
|
||||
|
||||
const config = {
|
||||
patternBreakingMode: options.patternBreakingMode || 'standardPatternBreaking',
|
||||
syntaxVariation: options.syntaxVariation || 0.6,
|
||||
connectorDiversity: options.connectorDiversity || 0.8
|
||||
};
|
||||
|
||||
const result = await patternCore.processContent(inputData, config);
|
||||
|
||||
return {
|
||||
content: result.content || result,
|
||||
tokensUsed: result.tokensUsed || 120,
|
||||
cost: (result.tokensUsed || 120) * 0.00002,
|
||||
llmCalls: result.llmCalls || [
|
||||
{ provider: 'gpt4', tokens: 60, cost: 0.0012 },
|
||||
{ provider: 'mistral', tokens: 60, cost: 0.0003 }
|
||||
]
|
||||
};
|
||||
} catch (error) {
|
||||
logSh(`❌ Erreur Pattern Breaking: ${error.message}`, 'ERROR');
|
||||
|
||||
return this.createFallbackContent('pattern-breaking', inputData, error);
|
||||
}
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// HELPERS ET FORMATAGE
|
||||
// ========================================
|
||||
|
||||
/**
|
||||
* Préprocesse les données d'entrée
|
||||
*/
|
||||
preprocessInputData(inputData) {
|
||||
return {
|
||||
mc0: inputData.mc0 || 'mot-clé principal',
|
||||
t0: inputData.t0 || 'titre principal',
|
||||
mcPlus1: inputData.mcPlus1 || '',
|
||||
tPlus1: inputData.tPlus1 || '',
|
||||
personality: inputData.personality || { nom: 'Test', style: 'neutre' },
|
||||
xmlTemplate: inputData.xmlTemplate || this.getDefaultTemplate(),
|
||||
// Ajout d'un contexte pour les modules
|
||||
context: {
|
||||
timestamp: Date.now(),
|
||||
source: 'step-by-step',
|
||||
debug: true
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Post-traite le résultat
|
||||
*/
|
||||
async postprocessResult(rawResult, system) {
|
||||
// Si le résultat est juste une chaîne, la transformer en objet
|
||||
if (typeof rawResult === 'string') {
|
||||
return {
|
||||
content: { 'Contenu': rawResult },
|
||||
tokensUsed: Math.floor(rawResult.length / 4), // Estimation
|
||||
cost: 0.001,
|
||||
llmCalls: [{ provider: 'unknown', tokens: 50, cost: 0.001 }]
|
||||
};
|
||||
}
|
||||
|
||||
// Si c'est déjà un objet structuré, le retourner tel quel
|
||||
if (rawResult && typeof rawResult === 'object') {
|
||||
return rawResult;
|
||||
}
|
||||
|
||||
// Fallback
|
||||
return {
|
||||
content: { 'Résultat': String(rawResult) },
|
||||
tokensUsed: 50,
|
||||
cost: 0.001,
|
||||
llmCalls: []
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Formate la sortie selon le format demandé
|
||||
*/
|
||||
formatOutput(content, format = 'tag') {
|
||||
if (!content || typeof content !== 'object') {
|
||||
return String(content || 'Pas de contenu');
|
||||
}
|
||||
|
||||
switch (format) {
|
||||
case 'tag':
|
||||
return Object.entries(content)
|
||||
.map(([tag, text]) => `[${tag}]\n${text}`)
|
||||
.join('\n\n');
|
||||
|
||||
case 'xml':
|
||||
return Object.entries(content)
|
||||
.map(([tag, text]) => `<${tag.toLowerCase()}>${text}</${tag.toLowerCase()}>`)
|
||||
.join('\n');
|
||||
|
||||
case 'json':
|
||||
return JSON.stringify(content, null, 2);
|
||||
|
||||
default:
|
||||
return this.formatOutput(content, 'tag');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Crée un contenu de fallback pour les erreurs
|
||||
*/
|
||||
createFallbackContent(system, inputData, error) {
|
||||
const fallbackContent = {
|
||||
'Titre_H1': `${inputData.t0} - Traité par ${system}`,
|
||||
'Introduction': `Contenu généré en mode ${system} pour "${inputData.mc0}".`,
|
||||
'Contenu_Principal': `Ceci est un contenu de démonstration pour le système ${system}.
|
||||
En production, ce contenu serait généré par l'IA avec les paramètres spécifiés.`,
|
||||
'Note_Technique': `⚠️ Mode fallback activé - Erreur: ${error.message}`
|
||||
};
|
||||
|
||||
return {
|
||||
content: fallbackContent,
|
||||
tokensUsed: 100,
|
||||
cost: 0.002,
|
||||
llmCalls: [
|
||||
{ provider: 'fallback', tokens: 100, cost: 0.002, error: error.message }
|
||||
],
|
||||
fallback: true
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Template XML par défaut
|
||||
*/
|
||||
getDefaultTemplate() {
|
||||
return `<?xml version="1.0" encoding="UTF-8"?>
|
||||
<article>
|
||||
<h1>|Titre_H1{{T0}}{Titre principal optimisé}|</h1>
|
||||
<intro>|Introduction{{MC0}}{Introduction engageante}|</intro>
|
||||
<content>|Contenu_Principal{{MC0,T0}}{Contenu principal détaillé}|</content>
|
||||
<conclusion>|Conclusion{{T0}}{Conclusion percutante}|</conclusion>
|
||||
</article>`;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
StepExecutor
|
||||
};
|
||||
@ -150,6 +150,11 @@ class ManualServer {
|
||||
// Fichiers statiques
|
||||
this.app.use(express.static(path.join(__dirname, '../../public')));
|
||||
|
||||
// Route spécifique pour l'interface step-by-step
|
||||
this.app.get('/step-by-step', (req, res) => {
|
||||
res.sendFile(path.join(__dirname, '../../public/step-by-step.html'));
|
||||
});
|
||||
|
||||
logSh('⚙️ Express configuré', 'DEBUG');
|
||||
}
|
||||
|
||||
@ -204,6 +209,50 @@ class ManualServer {
|
||||
});
|
||||
});
|
||||
|
||||
// Lancer le log viewer avec WebSocket
|
||||
this.app.post('/api/start-log-viewer', (req, res) => {
|
||||
this.handleStartLogViewer(req, res);
|
||||
});
|
||||
|
||||
// ========================================
|
||||
// APIs STEP-BY-STEP
|
||||
// ========================================
|
||||
|
||||
// Initialiser une session step-by-step
|
||||
this.app.post('/api/step-by-step/init', async (req, res) => {
|
||||
await this.handleStepByStepInit(req, res);
|
||||
});
|
||||
|
||||
// Exécuter une étape
|
||||
this.app.post('/api/step-by-step/execute', async (req, res) => {
|
||||
await this.handleStepByStepExecute(req, res);
|
||||
});
|
||||
|
||||
// Status d'une session
|
||||
this.app.get('/api/step-by-step/status/:sessionId', (req, res) => {
|
||||
this.handleStepByStepStatus(req, res);
|
||||
});
|
||||
|
||||
// Reset une session
|
||||
this.app.post('/api/step-by-step/reset', (req, res) => {
|
||||
this.handleStepByStepReset(req, res);
|
||||
});
|
||||
|
||||
// Export résultats
|
||||
this.app.get('/api/step-by-step/export/:sessionId', (req, res) => {
|
||||
this.handleStepByStepExport(req, res);
|
||||
});
|
||||
|
||||
// Liste des sessions actives
|
||||
this.app.get('/api/step-by-step/sessions', (req, res) => {
|
||||
this.handleStepByStepSessions(req, res);
|
||||
});
|
||||
|
||||
// API pour récupérer les personnalités
|
||||
this.app.get('/api/personalities', async (req, res) => {
|
||||
await this.handleGetPersonalities(req, res);
|
||||
});
|
||||
|
||||
// Gestion d'erreurs API
|
||||
this.app.use('/api/*', (error, req, res, next) => {
|
||||
logSh(`❌ Erreur API ${req.path}: ${error.message}`, 'ERROR');
|
||||
@ -454,6 +503,347 @@ class ManualServer {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Lance le log viewer avec WebSocket
|
||||
*/
|
||||
handleStartLogViewer(req, res) {
|
||||
try {
|
||||
const { spawn } = require('child_process');
|
||||
const path = require('path');
|
||||
const os = require('os');
|
||||
|
||||
// Démarrer le WebSocket pour logs
|
||||
process.env.ENABLE_LOG_WS = 'true';
|
||||
const { initWebSocketServer } = require('../ErrorReporting');
|
||||
initWebSocketServer();
|
||||
|
||||
// Servir le log viewer via une route HTTP au lieu d'un fichier local
|
||||
const logViewerUrl = `http://localhost:${this.config.port}/logs-viewer.html`;
|
||||
|
||||
// Ouvrir dans le navigateur selon l'OS
|
||||
let command, args;
|
||||
switch (os.platform()) {
|
||||
case 'darwin': // macOS
|
||||
command = 'open';
|
||||
args = [logViewerUrl];
|
||||
break;
|
||||
case 'win32': // Windows
|
||||
command = 'cmd';
|
||||
args = ['/c', 'start', logViewerUrl];
|
||||
break;
|
||||
default: // Linux et WSL
|
||||
// Pour WSL, utiliser explorer.exe de Windows
|
||||
if (process.env.WSL_DISTRO_NAME) {
|
||||
command = '/mnt/c/Windows/System32/cmd.exe';
|
||||
args = ['/c', 'start', logViewerUrl];
|
||||
} else {
|
||||
command = 'xdg-open';
|
||||
args = [logViewerUrl];
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
spawn(command, args, { detached: true, stdio: 'ignore' });
|
||||
|
||||
const logPort = process.env.LOG_WS_PORT || 8082;
|
||||
logSh(`🌐 Log viewer lancé avec WebSocket sur port ${logPort}`, 'INFO');
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: 'Log viewer lancé',
|
||||
wsPort: logPort,
|
||||
viewerUrl: logViewerUrl,
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
logSh(`❌ Erreur lancement log viewer: ${error.message}`, 'ERROR');
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: 'Erreur lancement log viewer',
|
||||
message: error.message,
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// HANDLERS STEP-BY-STEP
|
||||
// ========================================
|
||||
|
||||
/**
|
||||
* Initialise une nouvelle session step-by-step
|
||||
*/
|
||||
async handleStepByStepInit(req, res) {
|
||||
try {
|
||||
const { sessionManager } = require('../StepByStepSessionManager');
|
||||
|
||||
const inputData = req.body;
|
||||
logSh(`🎯 Initialisation session step-by-step`, 'INFO');
|
||||
logSh(` Input: ${JSON.stringify(inputData)}`, 'DEBUG');
|
||||
|
||||
const session = sessionManager.createSession(inputData);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
sessionId: session.id,
|
||||
steps: session.steps.map(step => ({
|
||||
id: step.id,
|
||||
system: step.system,
|
||||
name: step.name,
|
||||
description: step.description,
|
||||
status: step.status
|
||||
})),
|
||||
inputData: session.inputData,
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
logSh(`❌ Erreur init step-by-step: ${error.message}`, 'ERROR');
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: 'Erreur initialisation session',
|
||||
message: error.message,
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Exécute une étape
|
||||
*/
|
||||
async handleStepByStepExecute(req, res) {
|
||||
try {
|
||||
const { sessionManager } = require('../StepByStepSessionManager');
|
||||
const { StepExecutor } = require('../StepExecutor');
|
||||
|
||||
const { sessionId, stepId, options = {} } = req.body;
|
||||
|
||||
if (!sessionId || !stepId) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
error: 'sessionId et stepId requis',
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
}
|
||||
|
||||
logSh(`🚀 Exécution étape ${stepId} pour session ${sessionId}`, 'INFO');
|
||||
|
||||
// Récupérer la session
|
||||
const session = sessionManager.getSession(sessionId);
|
||||
|
||||
// Trouver l'étape
|
||||
const step = session.steps.find(s => s.id === stepId);
|
||||
if (!step) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
error: `Étape ${stepId} introuvable`,
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
}
|
||||
|
||||
// Marquer l'étape comme en cours
|
||||
step.status = 'executing';
|
||||
|
||||
// Créer l'exécuteur et lancer l'étape
|
||||
const executor = new StepExecutor();
|
||||
const result = await executor.executeStep(step.system, session.inputData, options);
|
||||
|
||||
// Ajouter le résultat à la session
|
||||
sessionManager.addStepResult(sessionId, stepId, result);
|
||||
|
||||
// Déterminer la prochaine étape
|
||||
const nextStep = session.steps.find(s => s.id === stepId + 1);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
stepId: stepId,
|
||||
system: step.system,
|
||||
name: step.name,
|
||||
result: {
|
||||
success: result.success,
|
||||
content: result.result,
|
||||
formatted: result.formatted,
|
||||
xmlFormatted: result.xmlFormatted,
|
||||
error: result.error
|
||||
},
|
||||
stats: result.stats,
|
||||
nextStep: nextStep ? nextStep.id : null,
|
||||
sessionStatus: session.status,
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
logSh(`❌ Erreur exécution step-by-step: ${error.message}`, 'ERROR');
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: 'Erreur exécution étape',
|
||||
message: error.message,
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Récupère le status d'une session
|
||||
*/
|
||||
handleStepByStepStatus(req, res) {
|
||||
try {
|
||||
const { sessionManager } = require('../StepByStepSessionManager');
|
||||
const { sessionId } = req.params;
|
||||
|
||||
const session = sessionManager.getSession(sessionId);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
session: {
|
||||
id: session.id,
|
||||
status: session.status,
|
||||
createdAt: new Date(session.createdAt).toISOString(),
|
||||
currentStep: session.currentStep,
|
||||
completedSteps: session.completedSteps,
|
||||
totalSteps: session.steps.length,
|
||||
inputData: session.inputData,
|
||||
steps: session.steps,
|
||||
globalStats: session.globalStats,
|
||||
results: session.results.map(r => ({
|
||||
stepId: r.stepId,
|
||||
system: r.system,
|
||||
success: r.success,
|
||||
timestamp: new Date(r.timestamp).toISOString(),
|
||||
stats: r.stats
|
||||
}))
|
||||
},
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
logSh(`❌ Erreur status step-by-step: ${error.message}`, 'ERROR');
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: 'Erreur récupération status',
|
||||
message: error.message,
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset une session
|
||||
*/
|
||||
handleStepByStepReset(req, res) {
|
||||
try {
|
||||
const { sessionManager } = require('../StepByStepSessionManager');
|
||||
const { sessionId } = req.body;
|
||||
|
||||
if (!sessionId) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
error: 'sessionId requis',
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
}
|
||||
|
||||
const session = sessionManager.resetSession(sessionId);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
sessionId: session.id,
|
||||
message: 'Session reset avec succès',
|
||||
steps: session.steps,
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
logSh(`❌ Erreur reset step-by-step: ${error.message}`, 'ERROR');
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: 'Erreur reset session',
|
||||
message: error.message,
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Export les résultats d'une session
|
||||
*/
|
||||
handleStepByStepExport(req, res) {
|
||||
try {
|
||||
const { sessionManager } = require('../StepByStepSessionManager');
|
||||
const { sessionId } = req.params;
|
||||
|
||||
const exportData = sessionManager.exportSession(sessionId);
|
||||
|
||||
res.setHeader('Content-Type', 'application/json');
|
||||
res.setHeader('Content-Disposition', `attachment; filename="step-by-step-${sessionId}.json"`);
|
||||
res.json(exportData);
|
||||
|
||||
} catch (error) {
|
||||
logSh(`❌ Erreur export step-by-step: ${error.message}`, 'ERROR');
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: 'Erreur export session',
|
||||
message: error.message,
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Liste les sessions actives
|
||||
*/
|
||||
handleStepByStepSessions(req, res) {
|
||||
try {
|
||||
const { sessionManager } = require('../StepByStepSessionManager');
|
||||
|
||||
const sessions = sessionManager.listSessions();
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
sessions: sessions,
|
||||
total: sessions.length,
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
logSh(`❌ Erreur list sessions step-by-step: ${error.message}`, 'ERROR');
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: 'Erreur récupération sessions',
|
||||
message: error.message,
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler pour récupérer les personnalités disponibles
|
||||
*/
|
||||
async handleGetPersonalities(req, res) {
|
||||
try {
|
||||
const { getPersonalities } = require('../BrainConfig');
|
||||
|
||||
const personalities = await getPersonalities();
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
personalities: personalities || [],
|
||||
total: (personalities || []).length,
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
logSh(`❌ Erreur récupération personnalités: ${error.message}`, 'ERROR');
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: 'Erreur récupération personnalités',
|
||||
message: error.message,
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// INTERFACE WEB
|
||||
// ========================================
|
||||
@ -467,6 +857,21 @@ class ManualServer {
|
||||
res.send(this.generateManualDashboard());
|
||||
});
|
||||
|
||||
// Route pour le log viewer
|
||||
this.app.get('/logs-viewer.html', (req, res) => {
|
||||
const fs = require('fs');
|
||||
const logViewerPath = path.join(__dirname, '../../tools/logs-viewer.html');
|
||||
|
||||
try {
|
||||
const content = fs.readFileSync(logViewerPath, 'utf-8');
|
||||
res.setHeader('Content-Type', 'text/html; charset=utf-8');
|
||||
res.send(content);
|
||||
} catch (error) {
|
||||
logSh(`❌ Erreur lecture log viewer: ${error.message}`, 'ERROR');
|
||||
res.status(500).send(`Erreur: ${error.message}`);
|
||||
}
|
||||
});
|
||||
|
||||
// Route 404
|
||||
this.app.use('*', (req, res) => {
|
||||
res.status(404).json({
|
||||
@ -551,6 +956,7 @@ class ManualServer {
|
||||
<h2>🧪 Interface Test Modulaire</h2>
|
||||
<p>Interface avancée pour tester toutes les combinaisons modulaires avec logs temps réel.</p>
|
||||
<a href="/test-modulaire.html" target="_blank" class="button">🚀 Ouvrir Interface Test</a>
|
||||
<a href="/step-by-step" target="_blank" class="button">⚡ Interface Step-by-Step</a>
|
||||
<a href="/api/modulaire-config" target="_blank" class="button success">📋 Configuration API</a>
|
||||
</div>
|
||||
|
||||
@ -565,6 +971,7 @@ class ManualServer {
|
||||
<div class="section">
|
||||
<h2>🌐 WebSocket Logs</h2>
|
||||
<p>Logs temps réel sur <strong>ws://localhost:${this.config.wsPort}</strong></p>
|
||||
<button onclick="startLogViewer()" class="button warning">🔍 Ouvrir Log Viewer</button>
|
||||
<div id="wsStatus" style="margin-top: 10px; padding: 10px; background: #e2e8f0; border-radius: 5px;">
|
||||
Status: <span id="wsStatusText">Déconnecté</span>
|
||||
</div>
|
||||
@ -596,6 +1003,23 @@ class ManualServer {
|
||||
});
|
||||
}
|
||||
|
||||
function startLogViewer() {
|
||||
fetch('/api/start-log-viewer', { method: 'POST' })
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
alert('✅ Log Viewer lancé! WebSocket sur port ' + data.wsPort);
|
||||
// Reconnecter le WebSocket pour voir les logs
|
||||
connectWebSocket();
|
||||
} else {
|
||||
alert('❌ Erreur: ' + data.message);
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
alert('❌ Erreur lancement: ' + err.message);
|
||||
});
|
||||
}
|
||||
|
||||
function connectWebSocket() {
|
||||
try {
|
||||
ws = new WebSocket('ws://localhost:${this.config.wsPort}');
|
||||
|
||||
995
public/step-by-step.html
Normal file
995
public/step-by-step.html
Normal file
@ -0,0 +1,995 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>SEO Generator - Step by Step</title>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'SF Pro Display', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
color: #333;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.container {
|
||||
display: grid;
|
||||
grid-template-columns: 320px 1fr;
|
||||
grid-template-rows: auto 1fr auto;
|
||||
gap: 20px;
|
||||
padding: 20px;
|
||||
max-width: 1600px;
|
||||
margin: 0 auto;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.header {
|
||||
grid-column: 1 / -1;
|
||||
background: white;
|
||||
border-radius: 15px;
|
||||
padding: 20px;
|
||||
box-shadow: 0 10px 30px rgba(0,0,0,0.1);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
color: #2d3748;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.header .subtitle {
|
||||
color: #718096;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.session-info {
|
||||
background: #e2e8f0;
|
||||
padding: 10px;
|
||||
border-radius: 8px;
|
||||
margin-top: 15px;
|
||||
font-size: 12px;
|
||||
color: #4a5568;
|
||||
}
|
||||
|
||||
.left-panel {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.panel {
|
||||
background: white;
|
||||
border-radius: 15px;
|
||||
padding: 20px;
|
||||
box-shadow: 0 10px 30px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.panel h2 {
|
||||
color: #2d3748;
|
||||
margin-bottom: 15px;
|
||||
font-size: 1.2em;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
/* INPUT SECTION */
|
||||
.input-group {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.input-group label {
|
||||
display: block;
|
||||
font-weight: 600;
|
||||
margin-bottom: 6px;
|
||||
color: #4a5568;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.input-group input,
|
||||
.input-group textarea,
|
||||
.input-group select {
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
border: 2px solid #e2e8f0;
|
||||
border-radius: 8px;
|
||||
font-size: 13px;
|
||||
transition: border-color 0.2s;
|
||||
}
|
||||
|
||||
.input-group input:focus,
|
||||
.input-group textarea:focus,
|
||||
.input-group select:focus {
|
||||
outline: none;
|
||||
border-color: #667eea;
|
||||
}
|
||||
|
||||
.input-group textarea {
|
||||
height: 60px;
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
/* CONTRÔLES */
|
||||
.step-buttons {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.step-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 12px;
|
||||
background: #f7fafc;
|
||||
border: 2px solid #e2e8f0;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.step-btn:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 5px 15px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.step-btn.pending {
|
||||
background: #f7fafc;
|
||||
color: #718096;
|
||||
}
|
||||
|
||||
.step-btn.executing {
|
||||
background: #ffd700;
|
||||
color: #744210;
|
||||
animation: pulse 1.5s infinite;
|
||||
}
|
||||
|
||||
.step-btn.completed {
|
||||
background: #c6f6d5;
|
||||
color: #22543d;
|
||||
}
|
||||
|
||||
.step-btn.error {
|
||||
background: #fed7d7;
|
||||
color: #742a2a;
|
||||
}
|
||||
|
||||
.step-btn .step-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.step-btn .step-name {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.step-btn .step-desc {
|
||||
font-size: 11px;
|
||||
opacity: 0.8;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
.step-btn .step-stats {
|
||||
font-size: 10px;
|
||||
opacity: 0.7;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.global-controls {
|
||||
margin-top: 15px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
padding: 10px 15px;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
font-weight: 500;
|
||||
font-size: 13px;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.btn.primary {
|
||||
background: linear-gradient(135deg, #667eea, #764ba2);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn.secondary {
|
||||
background: #e2e8f0;
|
||||
color: #4a5568;
|
||||
}
|
||||
|
||||
.btn.warning {
|
||||
background: #fed7d7;
|
||||
color: #742a2a;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
/* RÉSULTATS */
|
||||
.results-panel {
|
||||
background: white;
|
||||
border-radius: 15px;
|
||||
padding: 20px;
|
||||
box-shadow: 0 10px 30px rgba(0,0,0,0.1);
|
||||
overflow-y: auto;
|
||||
max-height: 70vh;
|
||||
}
|
||||
|
||||
.step-results {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.step-result {
|
||||
border: 2px solid #e2e8f0;
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.step-result.active {
|
||||
border-color: #667eea;
|
||||
}
|
||||
|
||||
.step-result.completed {
|
||||
border-color: #48bb78;
|
||||
}
|
||||
|
||||
.step-result.error {
|
||||
border-color: #f56565;
|
||||
}
|
||||
|
||||
.result-header {
|
||||
background: #f7fafc;
|
||||
padding: 15px 20px;
|
||||
border-bottom: 1px solid #e2e8f0;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.result-header h3 {
|
||||
color: #2d3748;
|
||||
font-size: 14px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.result-status {
|
||||
font-size: 12px;
|
||||
padding: 4px 8px;
|
||||
border-radius: 4px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.result-status.pending {
|
||||
background: #e2e8f0;
|
||||
color: #718096;
|
||||
}
|
||||
|
||||
.result-status.executing {
|
||||
background: #ffd700;
|
||||
color: #744210;
|
||||
}
|
||||
|
||||
.result-status.completed {
|
||||
background: #c6f6d5;
|
||||
color: #22543d;
|
||||
}
|
||||
|
||||
.result-status.error {
|
||||
background: #fed7d7;
|
||||
color: #742a2a;
|
||||
}
|
||||
|
||||
.result-content {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.format-toggle {
|
||||
margin-bottom: 15px;
|
||||
display: flex;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
.format-btn {
|
||||
padding: 6px 12px;
|
||||
border: 1px solid #e2e8f0;
|
||||
background: white;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-size: 11px;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.format-btn.active {
|
||||
background: #667eea;
|
||||
color: white;
|
||||
border-color: #667eea;
|
||||
}
|
||||
|
||||
.content-output {
|
||||
background: #f8f9fa;
|
||||
border: 1px solid #e2e8f0;
|
||||
border-radius: 8px;
|
||||
padding: 15px;
|
||||
font-family: 'Monaco', 'Courier New', monospace;
|
||||
font-size: 12px;
|
||||
line-height: 1.5;
|
||||
white-space: pre-wrap;
|
||||
max-height: 300px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.content-output.tag-format .tag {
|
||||
color: #667eea;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.result-stats {
|
||||
margin-top: 15px;
|
||||
padding: 10px;
|
||||
background: #f0f4f8;
|
||||
border-radius: 6px;
|
||||
display: flex;
|
||||
gap: 15px;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.stat {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
color: #4a5568;
|
||||
}
|
||||
|
||||
/* STATS GLOBALES */
|
||||
.stats-panel {
|
||||
grid-column: 1 / -1;
|
||||
background: white;
|
||||
border-radius: 15px;
|
||||
padding: 20px;
|
||||
box-shadow: 0 10px 30px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.stats-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.stat-card {
|
||||
background: #f8f9fa;
|
||||
border: 1px solid #e2e8f0;
|
||||
border-radius: 12px;
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
.stat-card h4 {
|
||||
color: #2d3748;
|
||||
margin-bottom: 10px;
|
||||
font-size: 14px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.stat-card ul {
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.stat-card li {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 4px 0;
|
||||
font-size: 12px;
|
||||
color: #4a5568;
|
||||
}
|
||||
|
||||
.stat-card .stat-value {
|
||||
font-weight: 600;
|
||||
color: #2d3748;
|
||||
}
|
||||
|
||||
/* ANIMATIONS */
|
||||
@keyframes pulse {
|
||||
0%, 100% { opacity: 1; }
|
||||
50% { opacity: 0.7; }
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
.loading::after {
|
||||
content: "";
|
||||
display: inline-block;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border: 2px solid currentColor;
|
||||
border-radius: 50%;
|
||||
border-top-color: transparent;
|
||||
animation: spin 1s linear infinite;
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
/* RESPONSIVE */
|
||||
@media (max-width: 1200px) {
|
||||
.container {
|
||||
grid-template-columns: 1fr;
|
||||
grid-template-rows: auto auto auto auto;
|
||||
}
|
||||
|
||||
.left-panel {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.container {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.left-panel {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<!-- HEADER -->
|
||||
<div class="header">
|
||||
<h1>🎯 SEO Generator - Step by Step</h1>
|
||||
<div class="subtitle">Interface de test modulaire avec contrôle granulaire</div>
|
||||
<div class="session-info" id="sessionInfo" style="display: none;">
|
||||
<strong>Session:</strong> <span id="sessionId">-</span> |
|
||||
<strong>Status:</strong> <span id="sessionStatus">-</span> |
|
||||
<strong>Étape:</strong> <span id="currentStepInfo">0/4</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- PANNEAU GAUCHE -->
|
||||
<div class="left-panel">
|
||||
<!-- INPUTS PERSONNALISÉS -->
|
||||
<div class="panel">
|
||||
<h2>🎯 Configuration</h2>
|
||||
|
||||
<div class="input-group">
|
||||
<label for="mc0">Mot-clé principal (MC0)</label>
|
||||
<input type="text" id="mc0" placeholder="ex: plaque personnalisée" value="plaque personnalisée">
|
||||
</div>
|
||||
|
||||
<div class="input-group">
|
||||
<label for="t0">Titre cible (T0)</label>
|
||||
<input type="text" id="t0" placeholder="ex: Créer une plaque personnalisée" value="Créer une plaque personnalisée unique">
|
||||
</div>
|
||||
|
||||
<div class="input-group">
|
||||
<label for="mcPlus1">Mots-clés secondaires</label>
|
||||
<textarea id="mcPlus1" placeholder="plaque gravée,plaque métal,plaque bois">plaque gravée,plaque métal,plaque bois,plaque acrylique</textarea>
|
||||
</div>
|
||||
|
||||
<div class="input-group">
|
||||
<label for="personality">Personnalité IA</label>
|
||||
<select id="personality">
|
||||
<option value="random">🎲 Aléatoire</option>
|
||||
<option value="marc" selected>Marc (technique)</option>
|
||||
<option value="sophie">Sophie (créatif)</option>
|
||||
<option value="laurent">Laurent (commercial)</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<button class="btn primary" onclick="initSession()" id="initBtn">
|
||||
🚀 Initialiser Session
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- CONTRÔLES STEP-BY-STEP -->
|
||||
<div class="panel">
|
||||
<h2>🎮 Contrôles</h2>
|
||||
|
||||
<div class="step-buttons" id="stepButtons">
|
||||
<!-- Généré dynamiquement -->
|
||||
</div>
|
||||
|
||||
<div class="global-controls">
|
||||
<button class="btn secondary" onclick="executeAll()" id="executeAllBtn" disabled>
|
||||
▶️ Tout Exécuter
|
||||
</button>
|
||||
<button class="btn warning" onclick="resetSession()" id="resetBtn" disabled>
|
||||
🔄 Reset Session
|
||||
</button>
|
||||
<button class="btn secondary" onclick="exportResults()" id="exportBtn" disabled>
|
||||
💾 Export JSON
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- PANNEAU RÉSULTATS -->
|
||||
<div class="results-panel">
|
||||
<h2>📊 Résultats par Étape</h2>
|
||||
<div class="step-results" id="stepResults">
|
||||
<div style="text-align: center; color: #718096; margin-top: 50px;">
|
||||
Initialisez une session pour commencer
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- STATS GLOBALES -->
|
||||
<div class="stats-panel">
|
||||
<h2>📈 Statistiques Détaillées</h2>
|
||||
<div class="stats-grid">
|
||||
<div class="stat-card">
|
||||
<h4>⏱️ Performance</h4>
|
||||
<ul>
|
||||
<li>Durée totale: <span class="stat-value" id="totalDuration">0ms</span></li>
|
||||
<li>Étape la plus lente: <span class="stat-value" id="slowestStep">-</span></li>
|
||||
<li>Moyenne par étape: <span class="stat-value" id="avgDuration">0ms</span></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="stat-card">
|
||||
<h4>🤖 Utilisation LLM</h4>
|
||||
<ul>
|
||||
<li>Tokens utilisés: <span class="stat-value" id="totalTokens">0</span></li>
|
||||
<li>Appels LLM: <span class="stat-value" id="totalLLMCalls">0</span></li>
|
||||
<li>Provider principal: <span class="stat-value" id="mainProvider">-</span></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="stat-card">
|
||||
<h4>💰 Coûts</h4>
|
||||
<ul>
|
||||
<li>Coût total: <span class="stat-value" id="totalCost">$0.00</span></li>
|
||||
<li>Coût moyen/étape: <span class="stat-value" id="avgCost">$0.00</span></li>
|
||||
<li>Système le plus cher: <span class="stat-value" id="mostExpensive">-</span></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="stat-card">
|
||||
<h4>✅ Statut Session</h4>
|
||||
<ul>
|
||||
<li>Étapes complétées: <span class="stat-value" id="completedSteps">0</span></li>
|
||||
<li>Taux de succès: <span class="stat-value" id="successRate">0%</span></li>
|
||||
<li>Dernière activité: <span class="stat-value" id="lastActivity">-</span></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// Variables globales
|
||||
let currentSessionId = null;
|
||||
let currentSession = null;
|
||||
let stepResultsData = {};
|
||||
|
||||
// ==============================================
|
||||
// INITIALISATION
|
||||
// ==============================================
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
console.log('🎯 Step-by-Step Interface initialisée');
|
||||
});
|
||||
|
||||
// ==============================================
|
||||
// GESTION SESSION
|
||||
// ==============================================
|
||||
|
||||
async function initSession() {
|
||||
try {
|
||||
const initBtn = document.getElementById('initBtn');
|
||||
initBtn.disabled = true;
|
||||
initBtn.innerHTML = '⏳ Initialisation...';
|
||||
|
||||
const inputData = {
|
||||
mc0: document.getElementById('mc0').value || 'plaque personnalisée',
|
||||
t0: document.getElementById('t0').value || 'Créer une plaque personnalisée',
|
||||
mcPlus1: document.getElementById('mcPlus1').value || '',
|
||||
personality: document.getElementById('personality').value || 'random'
|
||||
};
|
||||
|
||||
console.log('🚀 Initialisation session avec:', inputData);
|
||||
|
||||
const response = await fetch('/api/step-by-step/init', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(inputData)
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (data.success) {
|
||||
currentSessionId = data.sessionId;
|
||||
currentSession = {
|
||||
id: data.sessionId,
|
||||
inputData: data.inputData,
|
||||
steps: data.steps
|
||||
};
|
||||
|
||||
updateSessionInfo();
|
||||
generateStepButtons(data.steps);
|
||||
generateStepResults(data.steps);
|
||||
enableControls();
|
||||
|
||||
console.log('✅ Session initialisée:', currentSessionId);
|
||||
} else {
|
||||
throw new Error(data.message || 'Erreur initialisation');
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Erreur init session:', error);
|
||||
alert('Erreur initialisation: ' + error.message);
|
||||
} finally {
|
||||
const initBtn = document.getElementById('initBtn');
|
||||
initBtn.disabled = false;
|
||||
initBtn.innerHTML = '🚀 Initialiser Session';
|
||||
}
|
||||
}
|
||||
|
||||
async function resetSession() {
|
||||
if (!currentSessionId || !confirm('Êtes-vous sûr de vouloir reset la session ?')) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/step-by-step/reset', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ sessionId: currentSessionId })
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (data.success) {
|
||||
// Reset l'interface
|
||||
generateStepButtons(data.steps);
|
||||
generateStepResults(data.steps);
|
||||
stepResultsData = {};
|
||||
updateGlobalStats();
|
||||
|
||||
console.log('🔄 Session reset');
|
||||
} else {
|
||||
throw new Error(data.message || 'Erreur reset');
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Erreur reset:', error);
|
||||
alert('Erreur reset: ' + error.message);
|
||||
}
|
||||
}
|
||||
|
||||
// ==============================================
|
||||
// EXÉCUTION ÉTAPES
|
||||
// ==============================================
|
||||
|
||||
async function executeStep(stepId) {
|
||||
if (!currentSessionId) {
|
||||
alert('Veuillez d\'abord initialiser une session');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
console.log(`🚀 Exécution étape ${stepId}`);
|
||||
|
||||
// Marquer l'étape comme en cours
|
||||
updateStepStatus(stepId, 'executing');
|
||||
|
||||
const response = await fetch('/api/step-by-step/execute', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
sessionId: currentSessionId,
|
||||
stepId: stepId,
|
||||
options: {} // TODO: permettre configuration
|
||||
})
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (data.success) {
|
||||
// Stocker le résultat
|
||||
stepResultsData[stepId] = data;
|
||||
|
||||
// Mettre à jour l'interface
|
||||
updateStepStatus(stepId, 'completed');
|
||||
displayStepResult(stepId, data);
|
||||
updateGlobalStats();
|
||||
|
||||
console.log(`✅ Étape ${stepId} complétée`);
|
||||
} else {
|
||||
updateStepStatus(stepId, 'error');
|
||||
displayStepError(stepId, data.message || 'Erreur inconnue');
|
||||
|
||||
console.error(`❌ Erreur étape ${stepId}:`, data.message);
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
updateStepStatus(stepId, 'error');
|
||||
displayStepError(stepId, error.message);
|
||||
|
||||
console.error(`❌ Erreur étape ${stepId}:`, error);
|
||||
}
|
||||
}
|
||||
|
||||
async function executeAll() {
|
||||
if (!currentSessionId) {
|
||||
alert('Veuillez d\'abord initialiser une session');
|
||||
return;
|
||||
}
|
||||
|
||||
const steps = currentSession.steps;
|
||||
|
||||
for (const step of steps) {
|
||||
await executeStep(step.id);
|
||||
// Petit délai entre les étapes
|
||||
await new Promise(resolve => setTimeout(resolve, 500));
|
||||
}
|
||||
}
|
||||
|
||||
// ==============================================
|
||||
// INTERFACE DYNAMIQUE
|
||||
// ==============================================
|
||||
|
||||
function updateSessionInfo() {
|
||||
const sessionInfo = document.getElementById('sessionInfo');
|
||||
const sessionIdEl = document.getElementById('sessionId');
|
||||
const sessionStatusEl = document.getElementById('sessionStatus');
|
||||
|
||||
if (currentSessionId) {
|
||||
sessionInfo.style.display = 'block';
|
||||
sessionIdEl.textContent = currentSessionId.substring(0, 8) + '...';
|
||||
sessionStatusEl.textContent = 'active';
|
||||
}
|
||||
}
|
||||
|
||||
function generateStepButtons(steps) {
|
||||
const container = document.getElementById('stepButtons');
|
||||
container.innerHTML = '';
|
||||
|
||||
steps.forEach(step => {
|
||||
const button = document.createElement('div');
|
||||
button.className = 'step-btn pending';
|
||||
button.setAttribute('data-step', step.id);
|
||||
button.onclick = () => executeStep(step.id);
|
||||
|
||||
button.innerHTML = `
|
||||
<div class="step-info">
|
||||
<div class="step-name">${step.id}️⃣ ${step.name}</div>
|
||||
<div class="step-desc">${step.description}</div>
|
||||
</div>
|
||||
<div class="step-stats" id="stepStats${step.id}">
|
||||
En attente
|
||||
</div>
|
||||
`;
|
||||
|
||||
container.appendChild(button);
|
||||
});
|
||||
}
|
||||
|
||||
function generateStepResults(steps) {
|
||||
const container = document.getElementById('stepResults');
|
||||
container.innerHTML = '';
|
||||
|
||||
steps.forEach(step => {
|
||||
const resultDiv = document.createElement('div');
|
||||
resultDiv.className = 'step-result';
|
||||
resultDiv.setAttribute('data-step', step.id);
|
||||
|
||||
resultDiv.innerHTML = `
|
||||
<div class="result-header">
|
||||
<h3>${step.id}️⃣ ${step.name}</h3>
|
||||
<div class="result-status pending" id="resultStatus${step.id}">En attente</div>
|
||||
</div>
|
||||
<div class="result-content" id="resultContent${step.id}" style="display: none;">
|
||||
<div class="format-toggle">
|
||||
<button class="format-btn active" onclick="toggleFormat(${step.id}, 'tag')">[Tag] Format</button>
|
||||
<button class="format-btn" onclick="toggleFormat(${step.id}, 'xml')">XML Format</button>
|
||||
</div>
|
||||
<div class="content-output" id="contentOutput${step.id}">
|
||||
<!-- Résultat ici -->
|
||||
</div>
|
||||
<div class="result-stats" id="resultStats${step.id}">
|
||||
<!-- Stats ici -->
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
container.appendChild(resultDiv);
|
||||
});
|
||||
}
|
||||
|
||||
function updateStepStatus(stepId, status) {
|
||||
// Mettre à jour le bouton
|
||||
const stepBtn = document.querySelector(`[data-step="${stepId}"]`);
|
||||
if (stepBtn) {
|
||||
stepBtn.className = `step-btn ${status}`;
|
||||
}
|
||||
|
||||
// Mettre à jour le statut dans les résultats
|
||||
const resultStatus = document.getElementById(`resultStatus${stepId}`);
|
||||
if (resultStatus) {
|
||||
resultStatus.className = `result-status ${status}`;
|
||||
resultStatus.textContent = {
|
||||
pending: 'En attente',
|
||||
executing: 'En cours...',
|
||||
completed: 'Complété',
|
||||
error: 'Erreur'
|
||||
}[status] || status;
|
||||
}
|
||||
|
||||
// Ajouter l'animation loading si nécessaire
|
||||
const stepStats = document.getElementById(`stepStats${stepId}`);
|
||||
if (stepStats) {
|
||||
if (status === 'executing') {
|
||||
stepStats.innerHTML = '<span class="loading">En cours</span>';
|
||||
} else if (status === 'pending') {
|
||||
stepStats.textContent = 'En attente';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function displayStepResult(stepId, data) {
|
||||
const contentDiv = document.getElementById(`resultContent${stepId}`);
|
||||
const outputDiv = document.getElementById(`contentOutput${stepId}`);
|
||||
const statsDiv = document.getElementById(`resultStats${stepId}`);
|
||||
|
||||
// Afficher le contenu
|
||||
contentDiv.style.display = 'block';
|
||||
|
||||
// Afficher le résultat formaté
|
||||
if (data.result && data.result.formatted) {
|
||||
outputDiv.innerHTML = formatContentForDisplay(data.result.formatted, 'tag');
|
||||
} else {
|
||||
outputDiv.textContent = 'Pas de contenu généré';
|
||||
}
|
||||
|
||||
// Afficher les stats
|
||||
if (data.stats) {
|
||||
statsDiv.innerHTML = `
|
||||
<div class="stat">🕒 ${data.stats.duration}ms</div>
|
||||
<div class="stat">🎯 ${data.stats.tokensUsed || 0} tokens</div>
|
||||
<div class="stat">💰 $${(data.stats.cost || 0).toFixed(4)}</div>
|
||||
<div class="stat">🤖 ${data.stats.system}</div>
|
||||
`;
|
||||
}
|
||||
|
||||
// Mettre à jour les stats du bouton
|
||||
const stepStats = document.getElementById(`stepStats${stepId}`);
|
||||
if (stepStats && data.stats) {
|
||||
stepStats.innerHTML = `${data.stats.duration}ms<br>$${(data.stats.cost || 0).toFixed(3)}`;
|
||||
}
|
||||
}
|
||||
|
||||
function displayStepError(stepId, errorMessage) {
|
||||
const contentDiv = document.getElementById(`resultContent${stepId}`);
|
||||
const outputDiv = document.getElementById(`contentOutput${stepId}`);
|
||||
|
||||
contentDiv.style.display = 'block';
|
||||
outputDiv.innerHTML = `<div style="color: #f56565;">❌ Erreur: ${errorMessage}</div>`;
|
||||
|
||||
const stepStats = document.getElementById(`stepStats${stepId}`);
|
||||
if (stepStats) {
|
||||
stepStats.textContent = 'Erreur';
|
||||
}
|
||||
}
|
||||
|
||||
function formatContentForDisplay(content, format) {
|
||||
if (format === 'tag') {
|
||||
return content.replace(/\[([^\]]+)\]/g, '<span class="tag">[$1]</span>');
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
function toggleFormat(stepId, format) {
|
||||
const buttons = document.querySelectorAll(`[data-step="${stepId}"] .format-btn`);
|
||||
buttons.forEach(btn => btn.classList.remove('active'));
|
||||
|
||||
const activeBtn = document.querySelector(`[data-step="${stepId}"] .format-btn[onclick*="${format}"]`);
|
||||
if (activeBtn) activeBtn.classList.add('active');
|
||||
|
||||
const data = stepResultsData[stepId];
|
||||
if (!data) return;
|
||||
|
||||
const outputDiv = document.getElementById(`contentOutput${stepId}`);
|
||||
|
||||
if (format === 'tag' && data.result.formatted) {
|
||||
outputDiv.innerHTML = formatContentForDisplay(data.result.formatted, 'tag');
|
||||
} else if (format === 'xml' && data.result.xmlFormatted) {
|
||||
outputDiv.textContent = data.result.xmlFormatted;
|
||||
}
|
||||
}
|
||||
|
||||
function enableControls() {
|
||||
document.getElementById('executeAllBtn').disabled = false;
|
||||
document.getElementById('resetBtn').disabled = false;
|
||||
document.getElementById('exportBtn').disabled = false;
|
||||
}
|
||||
|
||||
function updateGlobalStats() {
|
||||
const results = Object.values(stepResultsData);
|
||||
|
||||
if (results.length === 0) {
|
||||
// Reset stats
|
||||
document.getElementById('totalDuration').textContent = '0ms';
|
||||
document.getElementById('totalTokens').textContent = '0';
|
||||
document.getElementById('totalCost').textContent = '$0.00';
|
||||
document.getElementById('completedSteps').textContent = '0';
|
||||
document.getElementById('successRate').textContent = '0%';
|
||||
return;
|
||||
}
|
||||
|
||||
const totalDuration = results.reduce((sum, r) => sum + (r.stats?.duration || 0), 0);
|
||||
const totalTokens = results.reduce((sum, r) => sum + (r.stats?.tokensUsed || 0), 0);
|
||||
const totalCost = results.reduce((sum, r) => sum + (r.stats?.cost || 0), 0);
|
||||
const successfulResults = results.filter(r => r.success);
|
||||
|
||||
document.getElementById('totalDuration').textContent = `${totalDuration}ms`;
|
||||
document.getElementById('totalTokens').textContent = totalTokens.toString();
|
||||
document.getElementById('totalCost').textContent = `$${totalCost.toFixed(4)}`;
|
||||
document.getElementById('completedSteps').textContent = results.length.toString();
|
||||
document.getElementById('successRate').textContent = `${Math.round(successfulResults.length / results.length * 100)}%`;
|
||||
document.getElementById('avgDuration').textContent = `${Math.round(totalDuration / results.length)}ms`;
|
||||
document.getElementById('avgCost').textContent = `$${(totalCost / results.length).toFixed(4)}`;
|
||||
document.getElementById('lastActivity').textContent = new Date().toLocaleTimeString();
|
||||
|
||||
// Trouver l'étape la plus lente
|
||||
const slowestStep = results.reduce((max, r) =>
|
||||
(r.stats?.duration || 0) > (max.stats?.duration || 0) ? r : max, results[0]);
|
||||
if (slowestStep) {
|
||||
document.getElementById('slowestStep').textContent = `Étape ${slowestStep.stepId}`;
|
||||
}
|
||||
}
|
||||
|
||||
// ==============================================
|
||||
// EXPORT
|
||||
// ==============================================
|
||||
|
||||
async function exportResults() {
|
||||
if (!currentSessionId) {
|
||||
alert('Aucune session à exporter');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(`/api/step-by-step/export/${currentSessionId}`);
|
||||
const blob = await response.blob();
|
||||
|
||||
const url = window.URL.createObjectURL(blob);
|
||||
const a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = `step-by-step-${currentSessionId}.json`;
|
||||
a.click();
|
||||
|
||||
window.URL.revokeObjectURL(url);
|
||||
|
||||
console.log('💾 Export réalisé');
|
||||
} catch (error) {
|
||||
console.error('❌ Erreur export:', error);
|
||||
alert('Erreur export: ' + error.message);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@ -1,7 +1,7 @@
|
||||
// ========================================
|
||||
// TESTS GÉNÉRÉS AUTOMATIQUEMENT - AdversarialCore
|
||||
// Module: adversarial-generation/AdversarialCore.js
|
||||
// Générés le: 2025-09-06T03:38:48.005Z
|
||||
// Générés le: 2025-09-06T12:40:35.923Z
|
||||
// ========================================
|
||||
|
||||
const assert = require('assert');
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// ========================================
|
||||
// TESTS GÉNÉRÉS AUTOMATIQUEMENT - AdversarialInitialGeneration
|
||||
// Module: adversarial-generation/AdversarialInitialGeneration.js
|
||||
// Générés le: 2025-09-06T03:38:48.013Z
|
||||
// Générés le: 2025-09-06T12:40:35.935Z
|
||||
// ========================================
|
||||
|
||||
const assert = require('assert');
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// ========================================
|
||||
// TESTS GÉNÉRÉS AUTOMATIQUEMENT - AdversarialLayers
|
||||
// Module: adversarial-generation/AdversarialLayers.js
|
||||
// Générés le: 2025-09-06T03:38:48.020Z
|
||||
// Générés le: 2025-09-06T12:40:35.947Z
|
||||
// ========================================
|
||||
|
||||
const assert = require('assert');
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// ========================================
|
||||
// TESTS GÉNÉRÉS AUTOMATIQUEMENT - AdversarialPromptEngine
|
||||
// Module: adversarial-generation/AdversarialPromptEngine.js
|
||||
// Générés le: 2025-09-06T03:38:48.027Z
|
||||
// Générés le: 2025-09-06T12:40:35.957Z
|
||||
// ========================================
|
||||
|
||||
const assert = require('assert');
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// ========================================
|
||||
// TESTS GÉNÉRÉS AUTOMATIQUEMENT - AdversarialStyleEnhancement
|
||||
// Module: adversarial-generation/AdversarialStyleEnhancement.js
|
||||
// Générés le: 2025-09-06T03:38:48.034Z
|
||||
// Générés le: 2025-09-06T12:40:35.968Z
|
||||
// ========================================
|
||||
|
||||
const assert = require('assert');
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// ========================================
|
||||
// TESTS GÉNÉRÉS AUTOMATIQUEMENT - AdversarialTechnicalEnhancement
|
||||
// Module: adversarial-generation/AdversarialTechnicalEnhancement.js
|
||||
// Générés le: 2025-09-06T03:38:48.040Z
|
||||
// Générés le: 2025-09-06T12:40:35.978Z
|
||||
// ========================================
|
||||
|
||||
const assert = require('assert');
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// ========================================
|
||||
// TESTS GÉNÉRÉS AUTOMATIQUEMENT - AdversarialTransitionEnhancement
|
||||
// Module: adversarial-generation/AdversarialTransitionEnhancement.js
|
||||
// Générés le: 2025-09-06T03:38:48.047Z
|
||||
// Générés le: 2025-09-06T12:40:35.989Z
|
||||
// ========================================
|
||||
|
||||
const assert = require('assert');
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// ========================================
|
||||
// TESTS GÉNÉRÉS AUTOMATIQUEMENT - AdversarialUtils
|
||||
// Module: adversarial-generation/AdversarialUtils.js
|
||||
// Générés le: 2025-09-06T03:38:48.054Z
|
||||
// Générés le: 2025-09-06T12:40:36.001Z
|
||||
// ========================================
|
||||
|
||||
const assert = require('assert');
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// ========================================
|
||||
// TESTS GÉNÉRÉS AUTOMATIQUEMENT - ArticleStorage
|
||||
// Module: ArticleStorage.js
|
||||
// Générés le: 2025-09-06T03:38:47.914Z
|
||||
// Générés le: 2025-09-06T12:40:35.780Z
|
||||
// ========================================
|
||||
|
||||
const assert = require('assert');
|
||||
@ -61,7 +61,7 @@ describe('ArticleStorage - Tests automatiques', () => {
|
||||
});
|
||||
|
||||
test('createArticlesStorageSheet - Content Generation', async () => {
|
||||
const mockInput = "test_value";
|
||||
const mockInput = ["test_value", "test_value"];
|
||||
|
||||
try {
|
||||
const result = await ArticleStorage.createArticlesStorageSheet(mockInput);
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// ========================================
|
||||
// TESTS GÉNÉRÉS AUTOMATIQUEMENT - AutoProcessor
|
||||
// Module: modes/AutoProcessor.js
|
||||
// Générés le: 2025-09-06T03:38:48.161Z
|
||||
// Générés le: 2025-09-06T12:40:36.165Z
|
||||
// ========================================
|
||||
|
||||
const assert = require('assert');
|
||||
@ -170,24 +170,6 @@ describe('AutoProcessor - Tests automatiques', () => {
|
||||
}
|
||||
});
|
||||
|
||||
test('while - Basic Function', () => {
|
||||
const input = undefined;
|
||||
|
||||
try {
|
||||
const result = AutoProcessor.while(input);
|
||||
|
||||
// Validations de base
|
||||
assert.ok(result !== undefined, 'Should return a result');
|
||||
assert.ok(typeof result !== 'undefined', 'Result should be defined');
|
||||
|
||||
console.log('✅ while: Function executed successfully');
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ while: Function failed:', error.message);
|
||||
throw error;
|
||||
}
|
||||
});
|
||||
|
||||
test('startProcessingLoop - Basic Function', () => {
|
||||
const input = undefined;
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// ========================================
|
||||
// TESTS GÉNÉRÉS AUTOMATIQUEMENT - BrainConfig
|
||||
// Module: BrainConfig.js
|
||||
// Générés le: 2025-09-06T03:38:47.921Z
|
||||
// Générés le: 2025-09-06T12:40:35.793Z
|
||||
// ========================================
|
||||
|
||||
const assert = require('assert');
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// ========================================
|
||||
// TESTS GÉNÉRÉS AUTOMATIQUEMENT - ComparisonFramework
|
||||
// Module: adversarial-generation/ComparisonFramework.js
|
||||
// Générés le: 2025-09-06T03:38:48.061Z
|
||||
// Générés le: 2025-09-06T12:40:36.010Z
|
||||
// ========================================
|
||||
|
||||
const assert = require('assert');
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// ========================================
|
||||
// TESTS GÉNÉRÉS AUTOMATIQUEMENT - ContentAssembly
|
||||
// Module: ContentAssembly.js
|
||||
// Générés le: 2025-09-06T03:38:47.926Z
|
||||
// Générés le: 2025-09-06T12:40:35.803Z
|
||||
// ========================================
|
||||
|
||||
const assert = require('assert');
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// ========================================
|
||||
// TESTS GÉNÉRÉS AUTOMATIQUEMENT - ContentGeneration
|
||||
// Module: ContentGeneration.js
|
||||
// Générés le: 2025-09-06T03:38:47.936Z
|
||||
// Générés le: 2025-09-06T12:40:35.813Z
|
||||
// ========================================
|
||||
|
||||
const assert = require('assert');
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// ========================================
|
||||
// TESTS GÉNÉRÉS AUTOMATIQUEMENT - ContentGenerationAdversarial
|
||||
// Module: adversarial-generation/ContentGenerationAdversarial.js
|
||||
// Générés le: 2025-09-06T03:38:48.068Z
|
||||
// Générés le: 2025-09-06T12:40:36.020Z
|
||||
// ========================================
|
||||
|
||||
const assert = require('assert');
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// ========================================
|
||||
// TESTS GÉNÉRÉS AUTOMATIQUEMENT - DetectorStrategies
|
||||
// Module: adversarial-generation/DetectorStrategies.js
|
||||
// Générés le: 2025-09-06T03:38:48.076Z
|
||||
// Générés le: 2025-09-06T12:40:36.033Z
|
||||
// ========================================
|
||||
|
||||
const assert = require('assert');
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// ========================================
|
||||
// TESTS GÉNÉRÉS AUTOMATIQUEMENT - DigitalOceanWorkflow
|
||||
// Module: DigitalOceanWorkflow.js
|
||||
// Générés le: 2025-09-06T03:38:47.944Z
|
||||
// Générés le: 2025-09-06T12:40:35.823Z
|
||||
// ========================================
|
||||
|
||||
const assert = require('assert');
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// ========================================
|
||||
// TESTS GÉNÉRÉS AUTOMATIQUEMENT - ElementExtraction
|
||||
// Module: ElementExtraction.js
|
||||
// Générés le: 2025-09-06T03:38:47.950Z
|
||||
// Générés le: 2025-09-06T12:40:35.834Z
|
||||
// ========================================
|
||||
|
||||
const assert = require('assert');
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// ========================================
|
||||
// TESTS GÉNÉRÉS AUTOMATIQUEMENT - ErrorReporting
|
||||
// Module: ErrorReporting.js
|
||||
// Générés le: 2025-09-06T03:38:47.956Z
|
||||
// Générés le: 2025-09-06T12:40:35.844Z
|
||||
// ========================================
|
||||
|
||||
const assert = require('assert');
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// ========================================
|
||||
// TESTS GÉNÉRÉS AUTOMATIQUEMENT - FatiguePatterns
|
||||
// Module: human-simulation/FatiguePatterns.js
|
||||
// Générés le: 2025-09-06T03:38:48.115Z
|
||||
// Générés le: 2025-09-06T12:40:36.100Z
|
||||
// ========================================
|
||||
|
||||
const assert = require('assert');
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// ========================================
|
||||
// TESTS GÉNÉRÉS AUTOMATIQUEMENT - HumanSimulationCore
|
||||
// Module: human-simulation/HumanSimulationCore.js
|
||||
// Générés le: 2025-09-06T03:38:48.121Z
|
||||
// Générés le: 2025-09-06T12:40:36.108Z
|
||||
// ========================================
|
||||
|
||||
const assert = require('assert');
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// ========================================
|
||||
// TESTS GÉNÉRÉS AUTOMATIQUEMENT - HumanSimulationLayers
|
||||
// Module: human-simulation/HumanSimulationLayers.js
|
||||
// Générés le: 2025-09-06T03:38:48.128Z
|
||||
// Générés le: 2025-09-06T12:40:36.117Z
|
||||
// ========================================
|
||||
|
||||
const assert = require('assert');
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// ========================================
|
||||
// TESTS GÉNÉRÉS AUTOMATIQUEMENT - HumanSimulationUtils
|
||||
// Module: human-simulation/HumanSimulationUtils.js
|
||||
// Générés le: 2025-09-06T03:38:48.134Z
|
||||
// Générés le: 2025-09-06T12:40:36.126Z
|
||||
// ========================================
|
||||
|
||||
const assert = require('assert');
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// ========================================
|
||||
// TESTS GÉNÉRÉS AUTOMATIQUEMENT - InitialGeneration
|
||||
// Module: generation/InitialGeneration.js
|
||||
// Générés le: 2025-09-06T03:38:48.089Z
|
||||
// Générés le: 2025-09-06T12:40:36.058Z
|
||||
// ========================================
|
||||
|
||||
const assert = require('assert');
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// ========================================
|
||||
// TESTS GÉNÉRÉS AUTOMATIQUEMENT - LLMFingerprintRemoval
|
||||
// Module: post-processing/LLMFingerprintRemoval.js
|
||||
// Générés le: 2025-09-06T03:38:48.209Z
|
||||
// Générés le: 2025-09-06T12:40:36.239Z
|
||||
// ========================================
|
||||
|
||||
const assert = require('assert');
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// ========================================
|
||||
// TESTS GÉNÉRÉS AUTOMATIQUEMENT - LLMFingerprints
|
||||
// Module: pattern-breaking/LLMFingerprints.js
|
||||
// Générés le: 2025-09-06T03:38:48.179Z
|
||||
// Générés le: 2025-09-06T12:40:36.195Z
|
||||
// ========================================
|
||||
|
||||
const assert = require('assert');
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// ========================================
|
||||
// TESTS GÉNÉRÉS AUTOMATIQUEMENT - LLMManager
|
||||
// Module: LLMManager.js
|
||||
// Générés le: 2025-09-06T03:38:47.964Z
|
||||
// Générés le: 2025-09-06T12:40:35.854Z
|
||||
// ========================================
|
||||
|
||||
const assert = require('assert');
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// ========================================
|
||||
// TESTS GÉNÉRÉS AUTOMATIQUEMENT - Main
|
||||
// Module: Main.js
|
||||
// Générés le: 2025-09-06T03:38:47.971Z
|
||||
// Générés le: 2025-09-06T12:40:35.864Z
|
||||
// ========================================
|
||||
|
||||
const assert = require('assert');
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// ========================================
|
||||
// TESTS GÉNÉRÉS AUTOMATIQUEMENT - ManualServer
|
||||
// Module: modes/ManualServer.js
|
||||
// Générés le: 2025-09-06T03:38:48.168Z
|
||||
// Générés le: 2025-09-06T12:40:36.176Z
|
||||
// ========================================
|
||||
|
||||
const assert = require('assert');
|
||||
@ -210,6 +210,26 @@ describe('ManualServer - Tests automatiques', () => {
|
||||
}
|
||||
});
|
||||
|
||||
test('handleWorkflowModulaire - Async Operation', async () => {
|
||||
const input = undefined;
|
||||
|
||||
try {
|
||||
const startTime = Date.now();
|
||||
const result = await ManualServer.handleWorkflowModulaire(input);
|
||||
const duration = Date.now() - startTime;
|
||||
|
||||
// Validations de base
|
||||
assert.ok(result !== undefined, 'Should return a result');
|
||||
assert.ok(duration < 30000, 'Should complete within 30 seconds');
|
||||
|
||||
console.log(`✅ handleWorkflowModulaire: Completed in ${duration}ms`);
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ handleWorkflowModulaire: Async operation failed:', error.message);
|
||||
throw error;
|
||||
}
|
||||
});
|
||||
|
||||
test('handleModulaireConfig - Basic Function', () => {
|
||||
const input = undefined;
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// ========================================
|
||||
// TESTS GÉNÉRÉS AUTOMATIQUEMENT - ManualTrigger
|
||||
// Module: ManualTrigger.js
|
||||
// Générés le: 2025-09-06T03:38:47.977Z
|
||||
// Générés le: 2025-09-06T12:40:35.873Z
|
||||
// ========================================
|
||||
|
||||
const assert = require('assert');
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// ========================================
|
||||
// TESTS GÉNÉRÉS AUTOMATIQUEMENT - MissingKeywords
|
||||
// Module: MissingKeywords.js
|
||||
// Générés le: 2025-09-06T03:38:47.983Z
|
||||
// Générés le: 2025-09-06T12:40:35.881Z
|
||||
// ========================================
|
||||
|
||||
const assert = require('assert');
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// ========================================
|
||||
// TESTS GÉNÉRÉS AUTOMATIQUEMENT - ModeManager
|
||||
// Module: modes/ModeManager.js
|
||||
// Générés le: 2025-09-06T03:38:48.174Z
|
||||
// Générés le: 2025-09-06T12:40:36.186Z
|
||||
// ========================================
|
||||
|
||||
const assert = require('assert');
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// ========================================
|
||||
// TESTS GÉNÉRÉS AUTOMATIQUEMENT - NaturalConnectors
|
||||
// Module: pattern-breaking/NaturalConnectors.js
|
||||
// Générés le: 2025-09-06T03:38:48.186Z
|
||||
// Générés le: 2025-09-06T12:40:36.203Z
|
||||
// ========================================
|
||||
|
||||
const assert = require('assert');
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// ========================================
|
||||
// TESTS GÉNÉRÉS AUTOMATIQUEMENT - PatternBreaking
|
||||
// Module: post-processing/PatternBreaking.js
|
||||
// Générés le: 2025-09-06T03:38:48.216Z
|
||||
// Générés le: 2025-09-06T12:40:36.249Z
|
||||
// ========================================
|
||||
|
||||
const assert = require('assert');
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// ========================================
|
||||
// TESTS GÉNÉRÉS AUTOMATIQUEMENT - PatternBreakingCore
|
||||
// Module: pattern-breaking/PatternBreakingCore.js
|
||||
// Générés le: 2025-09-06T03:38:48.192Z
|
||||
// Générés le: 2025-09-06T12:40:36.212Z
|
||||
// ========================================
|
||||
|
||||
const assert = require('assert');
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// ========================================
|
||||
// TESTS GÉNÉRÉS AUTOMATIQUEMENT - PatternBreakingLayers
|
||||
// Module: pattern-breaking/PatternBreakingLayers.js
|
||||
// Générés le: 2025-09-06T03:38:48.198Z
|
||||
// Générés le: 2025-09-06T12:40:36.221Z
|
||||
// ========================================
|
||||
|
||||
const assert = require('assert');
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// ========================================
|
||||
// TESTS GÉNÉRÉS AUTOMATIQUEMENT - PersonalityErrors
|
||||
// Module: human-simulation/PersonalityErrors.js
|
||||
// Générés le: 2025-09-06T03:38:48.140Z
|
||||
// Générés le: 2025-09-06T12:40:36.135Z
|
||||
// ========================================
|
||||
|
||||
const assert = require('assert');
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// ========================================
|
||||
// TESTS GÉNÉRÉS AUTOMATIQUEMENT - SelectiveCore
|
||||
// Module: selective-enhancement/SelectiveCore.js
|
||||
// Générés le: 2025-09-06T03:38:48.233Z
|
||||
// Générés le: 2025-09-06T12:40:36.275Z
|
||||
// ========================================
|
||||
|
||||
const assert = require('assert');
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// ========================================
|
||||
// TESTS GÉNÉRÉS AUTOMATIQUEMENT - SelectiveEnhancement
|
||||
// Module: SelectiveEnhancement.js
|
||||
// Générés le: 2025-09-06T03:38:47.992Z
|
||||
// Générés le: 2025-09-06T12:40:35.898Z
|
||||
// ========================================
|
||||
|
||||
const assert = require('assert');
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// ========================================
|
||||
// TESTS GÉNÉRÉS AUTOMATIQUEMENT - SelectiveLayers
|
||||
// Module: selective-enhancement/SelectiveLayers.js
|
||||
// Générés le: 2025-09-06T03:38:48.240Z
|
||||
// Générés le: 2025-09-06T12:40:36.284Z
|
||||
// ========================================
|
||||
|
||||
const assert = require('assert');
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// ========================================
|
||||
// TESTS GÉNÉRÉS AUTOMATIQUEMENT - SelectiveUtils
|
||||
// Module: selective-enhancement/SelectiveUtils.js
|
||||
// Générés le: 2025-09-06T03:38:48.247Z
|
||||
// Générés le: 2025-09-06T12:40:36.295Z
|
||||
// ========================================
|
||||
|
||||
const assert = require('assert');
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// ========================================
|
||||
// TESTS GÉNÉRÉS AUTOMATIQUEMENT - SentenceVariation
|
||||
// Module: post-processing/SentenceVariation.js
|
||||
// Générés le: 2025-09-06T03:38:48.222Z
|
||||
// Générés le: 2025-09-06T12:40:36.257Z
|
||||
// ========================================
|
||||
|
||||
const assert = require('assert');
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// ========================================
|
||||
// TESTS GÉNÉRÉS AUTOMATIQUEMENT - StyleEnhancement
|
||||
// Module: generation/StyleEnhancement.js
|
||||
// Générés le: 2025-09-06T03:38:48.095Z
|
||||
// Générés le: 2025-09-06T12:40:36.069Z
|
||||
// ========================================
|
||||
|
||||
const assert = require('assert');
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// ========================================
|
||||
// TESTS GÉNÉRÉS AUTOMATIQUEMENT - StyleLayer
|
||||
// Module: selective-enhancement/StyleLayer.js
|
||||
// Générés le: 2025-09-06T03:38:48.253Z
|
||||
// Générés le: 2025-09-06T12:40:36.307Z
|
||||
// ========================================
|
||||
|
||||
const assert = require('assert');
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// ========================================
|
||||
// TESTS GÉNÉRÉS AUTOMATIQUEMENT - SyntaxVariations
|
||||
// Module: pattern-breaking/SyntaxVariations.js
|
||||
// Générés le: 2025-09-06T03:38:48.204Z
|
||||
// Générés le: 2025-09-06T12:40:36.230Z
|
||||
// ========================================
|
||||
|
||||
const assert = require('assert');
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// ========================================
|
||||
// TESTS GÉNÉRÉS AUTOMATIQUEMENT - TechnicalEnhancement
|
||||
// Module: generation/TechnicalEnhancement.js
|
||||
// Générés le: 2025-09-06T03:38:48.101Z
|
||||
// Générés le: 2025-09-06T12:40:36.079Z
|
||||
// ========================================
|
||||
|
||||
const assert = require('assert');
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// ========================================
|
||||
// TESTS GÉNÉRÉS AUTOMATIQUEMENT - TechnicalLayer
|
||||
// Module: selective-enhancement/TechnicalLayer.js
|
||||
// Générés le: 2025-09-06T03:38:48.261Z
|
||||
// Générés le: 2025-09-06T12:40:36.316Z
|
||||
// ========================================
|
||||
|
||||
const assert = require('assert');
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// ========================================
|
||||
// TESTS GÉNÉRÉS AUTOMATIQUEMENT - TemporalStyles
|
||||
// Module: human-simulation/TemporalStyles.js
|
||||
// Générés le: 2025-09-06T03:38:48.147Z
|
||||
// Générés le: 2025-09-06T12:40:36.145Z
|
||||
// ========================================
|
||||
|
||||
const assert = require('assert');
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// ========================================
|
||||
// TESTS GÉNÉRÉS AUTOMATIQUEMENT - TransitionEnhancement
|
||||
// Module: generation/TransitionEnhancement.js
|
||||
// Générés le: 2025-09-06T03:38:48.108Z
|
||||
// Générés le: 2025-09-06T12:40:36.090Z
|
||||
// ========================================
|
||||
|
||||
const assert = require('assert');
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// ========================================
|
||||
// TESTS GÉNÉRÉS AUTOMATIQUEMENT - TransitionHumanization
|
||||
// Module: post-processing/TransitionHumanization.js
|
||||
// Générés le: 2025-09-06T03:38:48.227Z
|
||||
// Générés le: 2025-09-06T12:40:36.266Z
|
||||
// ========================================
|
||||
|
||||
const assert = require('assert');
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// ========================================
|
||||
// TESTS GÉNÉRÉS AUTOMATIQUEMENT - TransitionLayer
|
||||
// Module: selective-enhancement/TransitionLayer.js
|
||||
// Générés le: 2025-09-06T03:38:48.268Z
|
||||
// Générés le: 2025-09-06T12:40:36.325Z
|
||||
// ========================================
|
||||
|
||||
const assert = require('assert');
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// ========================================
|
||||
// TESTS GÉNÉRÉS AUTOMATIQUEMENT - Utils
|
||||
// Module: Utils.js
|
||||
// Générés le: 2025-09-06T03:38:47.999Z
|
||||
// Générés le: 2025-09-06T12:40:35.911Z
|
||||
// ========================================
|
||||
|
||||
const assert = require('assert');
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// ========================================
|
||||
// TESTS GÉNÉRÉS AUTOMATIQUEMENT - demo-modulaire
|
||||
// Module: selective-enhancement/demo-modulaire.js
|
||||
// Générés le: 2025-09-06T03:38:48.274Z
|
||||
// Générés le: 2025-09-06T12:40:36.333Z
|
||||
// ========================================
|
||||
|
||||
const assert = require('assert');
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// ========================================
|
||||
// TESTS GÉNÉRÉS AUTOMATIQUEMENT - main_modulaire
|
||||
// Module: main_modulaire.js
|
||||
// Générés le: 2025-09-06T03:38:48.154Z
|
||||
// Générés le: 2025-09-06T12:40:36.155Z
|
||||
// ========================================
|
||||
|
||||
const assert = require('assert');
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// ========================================
|
||||
// TESTS GÉNÉRÉS AUTOMATIQUEMENT - trace-wrap
|
||||
// Module: trace-wrap.js
|
||||
// Générés le: 2025-09-06T03:38:48.280Z
|
||||
// Générés le: 2025-09-06T12:40:36.340Z
|
||||
// ========================================
|
||||
|
||||
const assert = require('assert');
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// ========================================
|
||||
// TESTS GÉNÉRÉS AUTOMATIQUEMENT - trace
|
||||
// Module: trace.js
|
||||
// Générés le: 2025-09-06T03:38:48.286Z
|
||||
// Générés le: 2025-09-06T12:40:36.348Z
|
||||
// ========================================
|
||||
|
||||
const assert = require('assert');
|
||||
|
||||
@ -229,7 +229,7 @@
|
||||
<div class="header-left">
|
||||
<h1>SEO Generator - Logs temps réel</h1>
|
||||
<span id="status" class="status connecting">Connexion...</span>
|
||||
<span style="margin-left: 15px; font-size: 12px;">Port: <strong>8081</strong></span>
|
||||
<span style="margin-left: 15px; font-size: 12px;">Port: <strong>8082</strong></span>
|
||||
<br>
|
||||
<button onclick="toggleGlobalDetails()" id="detailsBtn">Mode détaillé: OFF</button>
|
||||
<button onclick="toggleLineUnwrap()" id="lineUnwrapBtn">Unwrap ligne: OFF</button>
|
||||
@ -396,8 +396,8 @@
|
||||
}
|
||||
|
||||
function connect() {
|
||||
console.log('🔌 connect() appelé - tentative WebSocket ws://localhost:8081');
|
||||
ws = new WebSocket('ws://localhost:8081');
|
||||
console.log('🔌 connect() appelé - tentative WebSocket ws://localhost:8082');
|
||||
ws = new WebSocket('ws://localhost:8082');
|
||||
|
||||
ws.onopen = () => {
|
||||
console.log('✅ WebSocket connecté !');
|
||||
|
||||
Loading…
Reference in New Issue
Block a user