ReflAgent / cross_reading /consensus_building.js
OUAREDAEK's picture
Upload cross_reading/consensus_building.js with huggingface_hub
c748911 verified
Raw
History Blame Contribute Delete
19.7 kB
// ================= VARIABLES GLOBALES =================
let currentExpert = null;
let scenariosData = [];
let calibrationData = { experts: [] };
const totalExperts = 14;
const metrics = ['AR', 'AE', 'ESR', 'SDM', 'SM'];
// ================= INITIALISATION =================
document.addEventListener('DOMContentLoaded', function() {
console.log('Initialisation du formulaire d\'évaluation des experts...');
initializeUI();
loadAllData();
});
function initializeUI() {
// Initialiser la grille d'experts avec des boutons vides
const expertGrid = document.getElementById('expertGrid');
let html = '';
for (let i = 1; i <= totalExperts; i++) {
html += `
<div class="expert-btn" onclick="selectExpert(${i})">
Expert ${i}
</div>
`;
}
expertGrid.innerHTML = html;
// Initialiser le texte de progression
updateProgressText(0);
}
function updateProgressText(completedCount) {
document.getElementById('progressText').textContent =
`${completedCount}/${totalExperts} experts ont complété leur évaluation`;
document.getElementById('progressFill').style.width = `${(completedCount / totalExperts) * 100}%`;
}
async function loadAllData() {
showLoading(true);
showInfo('Chargement des données en cours...');
try {
// Charger les scénarios
const scenariosResponse = await fetch('scenarios_list.json');
if (!scenariosResponse.ok) {
throw new Error('scenarios_list.json non trouvé ou erreur de chargement');
}
const scenariosJson = await scenariosResponse.json();
scenariosData = scenariosJson.scenarios || [];
console.log(`${scenariosData.length} scénarios chargés`);
// Charger ou créer les données de calibration
await loadCalibrationData();
// Initialiser la liste des scénarios
initializeScenarioList();
// Mettre à jour la grille des experts avec les données chargées
updateExpertGrid();
showLoading(false);
showSuccess('Données chargées avec succès');
} catch (error) {
console.error('Erreur de chargement:', error);
showLoading(false);
showInfo(`Erreur lors du chargement: ${error.message}. Vous pouvez continuer avec des données vides.`);
// Initialiser avec des données vides
if (scenariosData.length === 0) {
scenariosData = Array.from({length: 16}, (_, i) => ({
id: i + 1,
title: `Scénario ${i + 1}`
}));
initializeScenarioList();
}
updateExpertGrid();
}
}
async function loadCalibrationData() {
try {
// Essayer de charger depuis le localStorage d'abord
const savedData = localStorage.getItem('calibration_trust_data');
if (savedData) {
calibrationData = JSON.parse(savedData);
console.log('Données de calibration chargées depuis localStorage:', calibrationData);
return;
}
// Essayer de charger depuis le fichier
try {
const response = await fetch('calibration-trust.json');
if (response.ok) {
calibrationData = await response.json();
console.log('Données de calibration chargées depuis fichier:', calibrationData);
// Sauvegarder dans localStorage pour usage futur
localStorage.setItem('calibration_trust_data', JSON.stringify(calibrationData));
} else {
createEmptyCalibrationData();
}
} catch (fileError) {
console.log('Fichier calibration-trust.json non trouvé, création de nouvelles données');
createEmptyCalibrationData();
}
} catch (error) {
console.error('Erreur lors du chargement des données de calibration:', error);
createEmptyCalibrationData();
}
// S'assurer que nous avons des données pour tous les experts
ensureAllExpertsExist();
}
function createEmptyCalibrationData() {
calibrationData = { experts: [] };
for (let i = 1; i <= totalExperts; i++) {
calibrationData.experts.push({
expert_id: i,
evaluations: [],
last_updated: null
});
}
console.log('Nouvelles données de calibration créées');
}
function ensureAllExpertsExist() {
for (let i = 1; i <= totalExperts; i++) {
const existingExpert = calibrationData.experts.find(e => e.expert_id === i);
if (!existingExpert) {
calibrationData.experts.push({
expert_id: i,
evaluations: [],
last_updated: null
});
}
}
// Trier par ID d'expert
calibrationData.experts.sort((a, b) => a.expert_id - b.expert_id);
}
function updateExpertGrid() {
const expertGrid = document.getElementById('expertGrid');
let html = '';
let completedCount = 0;
for (let i = 1; i <= totalExperts; i++) {
const expert = calibrationData.experts.find(e => e.expert_id === i);
const isCompleted = expert && expert.evaluations &&
expert.evaluations.length === scenariosData.length &&
expert.evaluations.every(e =>
metrics.every(m => e[m] !== null && e[m] !== undefined)
);
const isCurrent = currentExpert === i;
if (isCompleted) completedCount++;
html += `
<div class="expert-btn ${isCurrent ? 'active' : ''} ${isCompleted ? 'completed' : ''}"
onclick="selectExpert(${i})">
Expert ${i}
${isCompleted ? '✓' : ''}
</div>
`;
}
expertGrid.innerHTML = html;
// Mettre à jour la barre de progression
updateProgressText(completedCount);
}
function initializeScenarioList() {
const scenarioList = document.getElementById('scenarioList');
let html = '';
scenariosData.forEach((scenario, index) => {
html += `
<div class="scenario-item" data-scenario-id="${scenario.id}">
<div class="scenario-title">
<span>${scenario.title || `Scénario ${scenario.id}`}</span>
<span class="scenario-id">S${scenario.id}</span>
</div>
<div class="metrics-grid">
${metrics.map(metric => `
<div class="metric-input">
<label>${metric}</label>
<select id="metric-${scenario.id}-${metric}"
onchange="updateMetricColor(this, ${scenario.id}, '${metric}')"
data-scenario="${scenario.id}"
data-metric="${metric}">
<option value="">--</option>
<option value="1">1 ★</option>
<option value="2">2 ★★</option>
<option value="3">3 ★★★</option>
<option value="4">4 ★★★★</option>
<option value="5">5 ★★★★★</option>
</select>
</div>
`).join('')}
</div>
</div>
`;
});
scenarioList.innerHTML = html;
}
// ================= GESTION DES EXPERTS =================
function selectExpert(expertId) {
currentExpert = expertId;
document.getElementById('currentExpert').textContent = expertId;
// Mettre à jour l'affichage des boutons d'experts
const expertButtons = document.querySelectorAll('.expert-btn');
expertButtons.forEach(btn => {
btn.classList.remove('active');
if (btn.textContent.includes(`Expert ${expertId}`)) {
btn.classList.add('active');
}
});
// Afficher le formulaire
document.getElementById('evaluationForm').style.display = 'block';
document.getElementById('summaryPanel').classList.remove('active');
// Charger les évaluations existantes
loadExpertEvaluations(expertId);
}
function loadExpertEvaluations(expertId) {
const expert = calibrationData.experts.find(e => e.expert_id === expertId);
if (!expert || !expert.evaluations || expert.evaluations.length === 0) {
// Réinitialiser tous les champs
resetForm();
showInfo(`Aucune évaluation trouvée pour l'expert ${expertId}. Commencez une nouvelle évaluation.`);
return;
}
// Remplir les champs avec les évaluations existantes
let loadedCount = 0;
expert.evaluations.forEach(evaluation => {
metrics.forEach(metric => {
const selectElement = document.getElementById(`metric-${evaluation.scenario_id}-${metric}`);
if (selectElement && evaluation[metric]) {
selectElement.value = evaluation[metric];
updateMetricColor(selectElement, evaluation.scenario_id, metric);
loadedCount++;
}
});
});
showSuccess(`${loadedCount} évaluations chargées pour l'expert ${expertId}`);
}
// ================= GESTION DU FORMULAIRE =================
function updateMetricColor(selectElement, scenarioId, metric) {
const value = parseInt(selectElement.value);
selectElement.className = '';
if (value >= 4) {
selectElement.classList.add('high');
} else if (value >= 3) {
selectElement.classList.add('medium');
} else if (value >= 1) {
selectElement.classList.add('low');
}
}
function resetForm() {
if (!currentExpert) {
showInfo('Veuillez d\'abord sélectionner un expert.');
return;
}
// Réinitialiser tous les champs de sélection
const selectElements = document.querySelectorAll('.metric-input select');
selectElements.forEach(select => {
select.value = '';
select.className = '';
});
showInfo('Formulaire réinitialisé. Tous les champs sont vides.');
}
async function saveEvaluation() {
if (!currentExpert) {
showInfo('Veuillez d\'abord sélectionner un expert.');
return;
}
// Collecter toutes les évaluations
const evaluations = [];
let allFilled = true;
let emptyCount = 0;
let filledCount = 0;
scenariosData.forEach(scenario => {
const evaluation = { scenario_id: scenario.id };
metrics.forEach(metric => {
const selectElement = document.getElementById(`metric-${scenario.id}-${metric}`);
const value = selectElement ? parseInt(selectElement.value) : null;
if (value && !isNaN(value) && value >= 1 && value <= 5) {
evaluation[metric] = value;
filledCount++;
} else {
evaluation[metric] = null;
allFilled = false;
emptyCount++;
}
});
evaluations.push(evaluation);
});
if (filledCount === 0) {
showInfo('Aucune évaluation saisie. Veuillez remplir au moins un champ.');
return;
}
if (!allFilled) {
const confirmSave = confirm(`Attention : ${emptyCount} champs sur ${scenariosData.length * 5} ne sont pas remplis. Voulez-vous quand même sauvegarder ?`);
if (!confirmSave) {
return;
}
}
// Mettre à jour les données de calibration
const expertIndex = calibrationData.experts.findIndex(e => e.expert_id === currentExpert);
if (expertIndex !== -1) {
calibrationData.experts[expertIndex].evaluations = evaluations;
calibrationData.experts[expertIndex].last_updated = new Date().toISOString();
}
// Sauvegarder dans le localStorage
localStorage.setItem('calibration_trust_data', JSON.stringify(calibrationData));
// Sauvegarder dans le fichier calibration-trust.json
await saveCalibrationToFile();
// Mettre à jour l'interface
updateExpertGrid();
showSummary();
showSuccess(`Évaluations sauvegardées pour l'expert ${currentExpert} ! ${filledCount} valeurs enregistrées.`);
}
async function saveCalibrationToFile() {
try {
// Créer un objet Blob avec les données
const dataStr = JSON.stringify(calibrationData, null, 2);
const dataBlob = new Blob([dataStr], { type: 'application/json' });
// Créer un lien de téléchargement
const downloadLink = document.createElement('a');
downloadLink.href = URL.createObjectURL(dataBlob);
downloadLink.download = 'calibration-trust.json';
// Déclencher le téléchargement
document.body.appendChild(downloadLink);
downloadLink.click();
document.body.removeChild(downloadLink);
console.log('Données de calibration sauvegardées dans calibration-trust.json');
} catch (error) {
console.error('Erreur lors de la sauvegarde du fichier:', error);
showInfo('Les données ont été sauvegardées localement mais une erreur est survenue lors de l\'export du fichier.');
}
}
// ================= RÉSUMÉ ET ANALYSE =================
function showSummary() {
if (!currentExpert) return;
const expert = calibrationData.experts.find(e => e.expert_id === currentExpert);
if (!expert || !expert.evaluations || expert.evaluations.length === 0) {
showInfo('Aucune évaluation à afficher.');
return;
}
// Calculer les statistiques
const stats = calculateExpertStatistics(expert);
// Mettre à jour le panneau de résumé
const summaryGrid = document.getElementById('summaryGrid');
summaryGrid.innerHTML = `
<div class="summary-card">
<h4>Scénarios évalués</h4>
<div class="summary-value">${stats.completedScenarios}/${scenariosData.length}</div>
<div class="summary-label">${stats.completionRate}% complétés</div>
</div>
<div class="summary-card">
<h4>Moyenne AR</h4>
<div class="summary-value">${stats.averages.AR.toFixed(2)}</div>
<div class="summary-label">/ 5.0</div>
</div>
<div class="summary-card">
<h4>Moyenne AE</h4>
<div class="summary-value">${stats.averages.AE.toFixed(2)}</div>
<div class="summary-label">/ 5.0</div>
</div>
<div class="summary-card">
<h4>Moyenne ESR</h4>
<div class="summary-value">${stats.averages.ESR.toFixed(2)}</div>
<div class="summary-label">/ 5.0</div>
</div>
<div class="summary-card">
<h4>Moyenne SDM</h4>
<div class="summary-value">${stats.averages.SDM.toFixed(2)}</div>
<div class="summary-label">/ 5.0</div>
</div>
<div class="summary-card">
<h4>Moyenne SM</h4>
<div class="summary-value">${stats.averages.SM.toFixed(2)}</div>
<div class="summary-label">/ 5.0</div>
</div>
<div class="summary-card">
<h4>Indice Global</h4>
<div class="summary-value">${stats.globalIndex.toFixed(2)}</div>
<div class="summary-label">/ 5.0</div>
</div>
<div class="summary-card">
<h4>Dernière mise à jour</h4>
<div class="summary-value">${stats.lastUpdated ? new Date(stats.lastUpdated).toLocaleDateString('fr-FR') : 'N/A'}</div>
<div class="summary-label">Date</div>
</div>
`;
// Afficher le panneau
document.getElementById('summaryPanel').classList.add('active');
document.getElementById('evaluationForm').style.display = 'none';
}
function calculateExpertStatistics(expert) {
const evaluations = expert.evaluations;
// Compter les scénarios complètement évalués (toutes les métriques remplies)
const completedScenarios = evaluations.filter(e =>
metrics.every(m => e[m] !== null && e[m] !== undefined)
).length;
const completionRate = scenariosData.length > 0
? ((completedScenarios / scenariosData.length) * 100).toFixed(1)
: '0.0';
// Calculer les moyennes par métrique
const averages = {};
metrics.forEach(metric => {
const values = evaluations
.map(e => e[metric])
.filter(v => v !== null && v !== undefined && !isNaN(v));
averages[metric] = values.length > 0
? values.reduce((sum, val) => sum + val, 0) / values.length
: 0;
});
// Calculer l'indice global (moyenne des moyennes)
const metricValues = Object.values(averages).filter(v => v > 0);
const globalIndex = metricValues.length > 0
? metricValues.reduce((sum, val) => sum + val, 0) / metricValues.length
: 0;
return {
completedScenarios,
completionRate,
averages,
globalIndex,
lastUpdated: expert.last_updated
};
}
function showConsensusAnalysis() {
// Sauvegarder d'abord les données actuelles
saveCalibrationToFile();
// Rediriger vers la page d'analyse du consensus
window.location.href = 'consensus_building.html?fromEvaluation=true';
}
function exportCalibrationData() {
saveCalibrationToFile();
showSuccess('Données de calibration exportées dans calibration-trust.json !');
}
// ================= FONCTIONS UTILITAIRES =================
function showLoading(show) {
document.getElementById('loading').style.display = show ? 'block' : 'none';
}
function showInfo(message) {
const alertBox = document.getElementById('infoAlert');
const messageElement = document.getElementById('infoMessage');
if (messageElement) {
messageElement.textContent = message;
}
if (alertBox) {
alertBox.style.display = 'block';
setTimeout(() => {
alertBox.style.display = 'none';
}, 5000);
}
}
function showSuccess(message) {
const alertBox = document.getElementById('successAlert');
const messageElement = document.getElementById('successMessage');
if (messageElement) {
messageElement.textContent = message;
}
if (alertBox) {
alertBox.style.display = 'block';
setTimeout(() => {
alertBox.style.display = 'none';
}, 5000);
}
}
// ================= FONCTIONS D'EXPORT =================
window.resetForm = resetForm;
window.saveEvaluation = saveEvaluation;
window.selectExpert = selectExpert;
window.updateMetricColor = updateMetricColor;
window.showConsensusAnalysis = showConsensusAnalysis;
window.exportCalibrationData = exportCalibrationData;