seo-generator-server/reports/auto-report-2025-09-18T00-47-35-582Z.html
StillHammer 4f60de68d6 Fix BatchProcessor initialization and add comprehensive test suite
- Fix BatchProcessor constructor to avoid server blocking during startup
- Add comprehensive integration tests for all modular combinations
- Enhance CLAUDE.md documentation with new test commands
- Update SelectiveLayers configuration for better LLM allocation
- Add AutoReporter system for test automation
- Include production workflow validation tests

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-19 14:17:49 +08:00

486 lines
25 KiB
HTML

<!DOCTYPE html>
<html>
<head>
<title>Auto-Rapport TI - 9/18/2025, 8:47:35 AM</title>
<style>
body { font-family: Arial, sans-serif; margin: 20px; background: #f5f5f5; }
.container { max-width: 1000px; margin: 0 auto; }
.header { background: white; padding: 20px; border-radius: 8px; margin-bottom: 20px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }
.stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 15px; margin-bottom: 20px; }
.stat-card { background: white; padding: 15px; border-radius: 8px; text-align: center; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }
.stat-value { font-size: 1.8em; font-weight: bold; color: #2196F3; }
.stat-label { color: #666; margin-top: 5px; font-size: 14px; }
.test-list { background: white; padding: 20px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }
.test-item { padding: 10px; border-bottom: 1px solid #eee; display: flex; justify-content: space-between; align-items: center; cursor: pointer; transition: background-color 0.2s; }
.test-item:hover { background: #f8f9fa; }
.test-item.clickable { border-left: 4px solid #4CAF50; }
.test-status { width: 12px; height: 12px; border-radius: 50%; margin-right: 10px; }
.status-passed { background: #4CAF50; }
.status-failed { background: #f44336; }
.llm-section { background: white; padding: 20px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); margin-top: 20px; }
.llm-call { background: #f9f9f9; padding: 10px; margin: 5px 0; border-radius: 4px; display: flex; justify-content: space-between; cursor: pointer; transition: background-color 0.2s; }
.llm-call:hover { background: #e8f4f8; }
.llm-call.clickable { border-left: 4px solid #2196F3; }
.phases-section { background: white; padding: 20px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); margin-top: 20px; }
.phase-timeline { display: flex; flex-direction: column; gap: 10px; }
.phase-item { background: #f8f9fa; padding: 12px; border-radius: 6px; border-left: 4px solid #9C27B0; display: flex; justify-content: space-between; align-items: center; }
.phase-item.completed { border-left-color: #4CAF50; background: #f1f8e9; }
.phase-item.started { border-left-color: #FF9800; background: #fff3e0; }
.phase-number { width: 30px; height: 30px; border-radius: 50%; background: #9C27B0; color: white; display: flex; align-items: center; justify-content: center; font-weight: bold; margin-right: 12px; }
.phase-number.completed { background: #4CAF50; }
.phase-number.started { background: #FF9800; }
/* Modal styles */
.modal { display: none; position: fixed; z-index: 1000; left: 0; top: 0; width: 100%; height: 100%; background-color: rgba(0,0,0,0.5); }
#llmModal { z-index: 1100; } /* LLM modal au-dessus du test modal */
.modal-content { background-color: white; margin: 5% auto; padding: 20px; border-radius: 8px; width: 90%; max-width: 800px; max-height: 80vh; overflow-y: auto; }
.close { color: #aaa; float: right; font-size: 28px; font-weight: bold; cursor: pointer; }
.close:hover { color: black; }
.prompt-section, .response-section { margin: 15px 0; }
.prompt-section h4, .response-section h4 { color: #333; border-bottom: 2px solid #2196F3; padding-bottom: 5px; }
.prompt-content, .response-content { background: #f5f5f5; padding: 15px; border-radius: 4px; white-space: pre-wrap; font-family: monospace; font-size: 14px; max-height: 300px; overflow-y: auto; }
.response-content { background: #f0f8ff; }
/* Test details modal styles */
.test-details-section { margin: 15px 0; }
.test-details-section h4 { color: #333; border-bottom: 2px solid #4CAF50; padding-bottom: 5px; }
.test-llm-list { background: #f8f9fa; padding: 10px; border-radius: 4px; margin-top: 10px; }
.test-llm-item { background: white; margin: 5px 0; padding: 8px; border-radius: 3px; display: flex; justify-content: space-between; cursor: pointer; border: 1px solid #ddd; }
.test-llm-item:hover { background: #e8f4f8; }
.test-stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: 10px; margin: 10px 0; }
.test-stat { background: #f0f0f0; padding: 8px; border-radius: 4px; text-align: center; }
.test-stat-value { font-weight: bold; color: #2196F3; }
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>📊 Auto-Rapport Tests d'Intégration</h1>
<p>Généré automatiquement le 9/18/2025, 8:47:35 AM</p>
</div>
<div class="stats">
<div class="stat-card">
<div class="stat-value">1</div>
<div class="stat-label">Tests</div>
</div>
<div class="stat-card">
<div class="stat-value" style="color: #4CAF50">1</div>
<div class="stat-label">Réussis</div>
</div>
<div class="stat-card">
<div class="stat-value" style="color: #f44336">0</div>
<div class="stat-label">Échoués</div>
</div>
<div class="stat-card">
<div class="stat-value">1</div>
<div class="stat-label">LLM Calls</div>
</div>
<div class="stat-card">
<div class="stat-value">3s</div>
<div class="stat-label">Durée</div>
</div>
</div>
<div class="test-list">
<h3>Résultats des Tests</h3>
<div class="test-item clickable" onclick="openTestModal(0)">
<div style="display: flex; align-items: center;">
<span class="test-status status-passed"></span>
<div>
<div><strong>Test Pipeline Capture Réelle</strong></div>
<div style="font-size: 12px; color: #666;">
1 LLM calls • 3s durée LLM
</div>
</div>
</div>
<div style="text-align: right;">
<div style="color: #4CAF50; font-weight: bold;">
✓ RÉUSSI
</div>
<div style="font-size: 10px; color: #2196F3; margin-top: 2px;">
🔍 Cliquer pour détails
</div>
</div>
</div>
</div>
<div class="phases-section">
<h3>🔄 Pipeline Phases (2)</h3>
<div class="phase-timeline">
<div class="phase-item completed clickable" onclick="openPhaseModal(0)">
<div style="display: flex; align-items: center; flex: 1;">
<div class="phase-number completed">1</div>
<div style="flex: 1;">
<div><strong>Phase 1/4: Génération Initiale</strong></div>
<div style="font-size: 12px; color: #666; margin-top: 2px;">
✅ Terminé • 8:47:30 AM
→ 8:47:31 AM
(500ms)
</div>
<div style="font-size: 11px; color: #888; margin-top: 2px;">
📊 2 éléments
• ✏️ 2 modifs
• 🎯 2/2 traités
</div>
</div>
</div>
<div style="text-align: right;">
<div style="color: #4CAF50; font-weight: bold;">
✓ COMPLÉTÉ
</div>
<div style="font-size: 10px; color: #2196F3; margin-top: 2px;">
🔍 Cliquer pour détails
</div>
</div>
</div>
<div class="phase-item completed clickable" onclick="openPhaseModal(1)">
<div style="display: flex; align-items: center; flex: 1;">
<div class="phase-number completed">3</div>
<div style="flex: 1;">
<div><strong>Phase 3/4: Heavy Enhancement</strong></div>
<div style="font-size: 12px; color: #666; margin-top: 2px;">
✅ Terminé • 8:47:31 AM
→ 8:47:33 AM
(2000ms)
</div>
<div style="font-size: 11px; color: #888; margin-top: 2px;">
📊 2 éléments
• ✏️ 2 modifs
• 🎯 2/2 traités
</div>
</div>
</div>
<div style="text-align: right;">
<div style="color: #4CAF50; font-weight: bold;">
✓ COMPLÉTÉ
</div>
<div style="font-size: 10px; color: #2196F3; margin-top: 2px;">
🔍 Cliquer pour détails
</div>
</div>
</div>
</div>
</div>
<div class="llm-section">
<h3>Appels LLM (1)</h3>
<div class="llm-call clickable" onclick="openModal(0)">
<div>
<strong>openai</strong> (gpt-4o-mini)
<div style="font-size: 12px; color: #666; margin-top: 2px;">
Test: Test Pipeline Capture Réelle
</div>
</div>
<div style="text-align: right;">
<div>3200ms</div>
<div style="font-size: 12px; color: #666;">0→0 tokens</div>
<div style="font-size: 10px; color: #2196F3; margin-top: 2px;">📋 Cliquer pour voir détails</div>
</div>
</div>
</div>
<!-- Modal pour afficher les détails LLM -->
<div id="llmModal" class="modal">
<div class="modal-content">
<span class="close" onclick="closeModal()">&times;</span>
<h2 id="modalTitle">Détails de l'appel LLM</h2>
<div class="prompt-section">
<h4>🔍 Prompt envoyé</h4>
<div id="promptContent" class="prompt-content">Aucun prompt capturé</div>
</div>
<div class="response-section">
<h4>📥 Réponse reçue</h4>
<div id="responseContent" class="response-content">Aucune réponse capturée</div>
</div>
</div>
</div>
<!-- Modal pour afficher les détails de test -->
<div id="testModal" class="modal">
<div class="modal-content">
<span class="close" onclick="closeTestModal()">&times;</span>
<h2 id="testModalTitle">Détails du test</h2>
<div class="test-details-section">
<h4>📊 Statistiques</h4>
<div id="testStats" class="test-stats">
<!-- Stats will be populated here -->
</div>
</div>
<div class="test-details-section">
<h4>🚀 Appels LLM associés</h4>
<div id="testLLMCalls" class="test-llm-list">
<!-- LLM calls will be listed here -->
</div>
</div>
</div>
</div>
<!-- Modal pour afficher les détails de phase -->
<div id="phaseModal" class="modal">
<div class="modal-content">
<span class="close" onclick="closePhaseModal()">&times;</span>
<h2 id="phaseModalTitle">Détails de la phase</h2>
<div class="test-details-section">
<h4>📊 Métriques de la phase</h4>
<div id="phaseMetrics" class="test-stats">
<!-- Metrics will be populated here -->
</div>
</div>
<div class="test-details-section">
<h4>🚀 Appels LLM de cette phase</h4>
<div id="phaseLLMCalls" class="test-llm-list">
<!-- Phase LLM calls will be listed here -->
</div>
</div>
<div class="test-details-section">
<h4>⏱️ Timeline</h4>
<div id="phaseTimeline" style="background: #f8f9fa; padding: 10px; border-radius: 4px;">
<!-- Timeline will be populated here -->
</div>
</div>
</div>
</div>
</div>
<script>
const llmCalls = [{"provider":"openai","model":"gpt-4o-mini","promptTokens":1500,"responseTokens":800,"duration":3200,"timestamp":"2025-09-18T00:47:34.581Z","testContext":"Test Pipeline Capture Réelle","cost":0.015,"prompt":"VRAIES DONNÉES CAPTURÉES:\n\nÉLÉMENTS AVANT PHASE 3:\n[1] \"Solutions digitales enterprise\"\n[2] \"Architecture moderne\"\n\nMISSION: Appliquer enhancement technique","response":"RÉSULTAT PHASE 3:\n[1] \"Solutions digitales enterprise avec matériaux dibond et aluminium anodisé\"\n[2] \"Architecture moderne intégrant procédés impression UV et découpe laser CNC\""}];
const testResults = [{"name":"Test Pipeline Capture Réelle","status":"passed","duration":5000,"error":null,"timestamp":"2025-09-18T00:47:34.581Z","llmCallsCount":1}];
const phases = [{"number":1,"name":"Génération Initiale","timestamp":"2025-09-18T00:47:30.581Z","endTimestamp":"2025-09-18T00:47:31.081Z","duration":500,"status":"completed","inputElements":{"Titre_H1":"Titre générique à améliorer","Introduction":"Introduction basique sans termes techniques"},"outputElements":{"Titre_H1":"Solutions digitales enterprise","Introduction":"Architecture moderne pour transformation"},"metrics":{"totalElements":2,"modifications":2,"processed":2,"total":2}},{"number":3,"name":"Heavy Enhancement","timestamp":"2025-09-18T00:47:31.581Z","endTimestamp":"2025-09-18T00:47:33.581Z","duration":2000,"status":"completed","inputElements":{"Titre_H1":"Solutions digitales enterprise","Introduction":"Architecture moderne pour transformation"},"outputElements":{"Titre_H1":"Solutions digitales enterprise avec matériaux dibond et aluminium anodisé","Introduction":"Architecture moderne intégrant procédés impression UV et découpe laser CNC"},"metrics":{"totalElements":2,"modifications":2,"processed":2,"total":2}}];
function openModal(index) {
const call = llmCalls[index];
if (!call) return;
const modal = document.getElementById('llmModal');
const title = document.getElementById('modalTitle');
const promptContent = document.getElementById('promptContent');
const responseContent = document.getElementById('responseContent');
title.textContent = `${call.provider.toUpperCase()} (${call.model}) - ${call.testContext}`;
promptContent.textContent = call.prompt || 'Aucun prompt capturé';
responseContent.textContent = call.response || 'Aucune réponse capturée';
modal.style.display = 'block';
}
function closeModal() {
document.getElementById('llmModal').style.display = 'none';
}
function openTestModal(index) {
const test = testResults[index];
if (!test) return;
const modal = document.getElementById('testModal');
const title = document.getElementById('testModalTitle');
const statsDiv = document.getElementById('testStats');
const llmCallsDiv = document.getElementById('testLLMCalls');
title.textContent = `Test: ${test.name}`;
// Get LLM calls for this test
const testLLMCalls = llmCalls.filter(call => call.testContext === test.name);
const totalDuration = testLLMCalls.reduce((sum, call) => sum + call.duration, 0);
const totalTokensIn = testLLMCalls.reduce((sum, call) => sum + (call.tokens?.prompt || 0), 0);
const totalTokensOut = testLLMCalls.reduce((sum, call) => sum + (call.tokens?.response || 0), 0);
// Populate stats
statsDiv.innerHTML = `
<div class="test-stat">
<div class="test-stat-value">${test.status === 'passed' ? '✓' : '✗'}</div>
<div>Statut</div>
</div>
<div class="test-stat">
<div class="test-stat-value">${testLLMCalls.length}</div>
<div>LLM Calls</div>
</div>
<div class="test-stat">
<div class="test-stat-value">${Math.round(totalDuration/1000)}s</div>
<div>Durée LLM</div>
</div>
<div class="test-stat">
<div class="test-stat-value">${totalTokensIn}</div>
<div>Tokens Input</div>
</div>
<div class="test-stat">
<div class="test-stat-value">${totalTokensOut}</div>
<div>Tokens Output</div>
</div>
`;
// Populate LLM calls
if (testLLMCalls.length > 0) {
llmCallsDiv.innerHTML = testLLMCalls.map((call, callIndex) => {
const globalIndex = llmCalls.findIndex(c => c === call);
return `
<div class="test-llm-item" onclick="openModal(${globalIndex})">
<div>
<strong>${call.provider.toUpperCase()}</strong> (${call.model})
<div style="font-size: 11px; color: #666; margin-top: 2px;">
${new Date(call.timestamp).toLocaleTimeString()}
</div>
</div>
<div style="text-align: right;">
<div>${call.duration}ms</div>
<div style="font-size: 11px; color: #666;">
${call.tokens?.prompt || 0}${call.tokens?.response || 0} tokens
</div>
</div>
</div>
`;
}).join('');
} else {
llmCallsDiv.innerHTML = '<div style="color: #666; text-align: center; padding: 20px;">Aucun appel LLM pour ce test</div>';
}
modal.style.display = 'block';
}
function closeTestModal() {
document.getElementById('testModal').style.display = 'none';
}
function openPhaseModal(index) {
const phase = phases[index];
if (!phase) return;
const modal = document.getElementById('phaseModal');
const title = document.getElementById('phaseModalTitle');
const metricsDiv = document.getElementById('phaseMetrics');
const llmCallsDiv = document.getElementById('phaseLLMCalls');
const timelineDiv = document.getElementById('phaseTimeline');
title.textContent = `Phase ${phase.number}/4: ${phase.name}`;
// Populate metrics
const metrics = phase.metrics || {};
metricsDiv.innerHTML = `
<div class="test-stat">
<div class="test-stat-value">${phase.status === 'completed' ? '✓' : '⏳'}</div>
<div>Statut</div>
</div>
<div class="test-stat">
<div class="test-stat-value">${metrics.totalElements || 0}</div>
<div>Éléments</div>
</div>
<div class="test-stat">
<div class="test-stat-value">${metrics.modifications || 0}</div>
<div>Modifications</div>
</div>
<div class="test-stat">
<div class="test-stat-value">${metrics.processed || 0}/${metrics.total || 0}</div>
<div>Traités</div>
</div>
<div class="test-stat">
<div class="test-stat-value">${phase.duration ? Math.round(phase.duration) + 'ms' : 'N/A'}</div>
<div>Durée</div>
</div>
`;
// Get LLM calls for this phase (by timestamp range)
const phaseStart = new Date(phase.timestamp);
const phaseEnd = phase.endTimestamp ? new Date(phase.endTimestamp) : new Date();
const phaseLLMCalls = llmCalls.filter(call => {
const callTime = new Date(call.timestamp);
return callTime >= phaseStart && callTime <= phaseEnd;
});
// Populate LLM calls
if (phaseLLMCalls.length > 0) {
llmCallsDiv.innerHTML = phaseLLMCalls.map((call, callIndex) => {
const globalIndex = llmCalls.findIndex(c => c === call);
return `
<div class="test-llm-item" onclick="openModal(${globalIndex})">
<div>
<strong>${call.provider.toUpperCase()}</strong> (${call.model})
<div style="font-size: 11px; color: #666; margin-top: 2px;">
${new Date(call.timestamp).toLocaleTimeString()}
</div>
</div>
<div style="text-align: right;">
<div>${call.duration}ms</div>
<div style="font-size: 11px; color: #666;">
${call.promptTokens || 0}${call.responseTokens || 0} tokens
</div>
</div>
</div>
`;
}).join('');
} else {
llmCallsDiv.innerHTML = '<div style="color: #666; text-align: center; padding: 20px;">Aucun appel LLM pour cette phase</div>';
}
// Populate timeline
timelineDiv.innerHTML = `
<div style="margin-bottom: 10px;">
<strong>🚀 Début:</strong> ${new Date(phase.timestamp).toLocaleTimeString()}
</div>
${phase.endTimestamp ? `
<div style="margin-bottom: 10px;">
<strong>✅ Fin:</strong> ${new Date(phase.endTimestamp).toLocaleTimeString()}
</div>
<div style="margin-bottom: 10px;">
<strong>⏱️ Durée:</strong> ${phase.duration ? Math.round(phase.duration) + 'ms' : 'N/A'}
</div>
` : '<div style="color: #FF9800;"><strong>⏳ En cours...</strong></div>'}
<div>
<strong>🧪 Test:</strong> ${phase.testContext || 'unknown'}
</div>
`;
modal.style.display = 'block';
}
function closePhaseModal() {
document.getElementById('phaseModal').style.display = 'none';
}
// Fermer modal en cliquant à l'extérieur
window.onclick = function(event) {
const llmModal = document.getElementById('llmModal');
const testModal = document.getElementById('testModal');
const phaseModal = document.getElementById('phaseModal');
if (event.target === llmModal) {
closeModal();
}
if (event.target === testModal) {
closeTestModal();
}
if (event.target === phaseModal) {
closePhaseModal();
}
}
// Fermer modal avec Escape
document.addEventListener('keydown', function(event) {
if (event.key === 'Escape') {
closeModal();
closeTestModal();
closePhaseModal();
}
});
</script>
</body>
</html>