Merge branch 'fix_chrome'
This commit is contained in:
@@ -1,5 +1,8 @@
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
fetchTasks();
|
||||
fetchAvailableConfigs().then(() => {
|
||||
fetchConfig();
|
||||
fetchTasks();
|
||||
});
|
||||
// Bind filter functionality
|
||||
document.getElementById('total-tasks').parentElement.addEventListener('click', () => setTaskFilter('all'));
|
||||
document.getElementById('active-tasks').parentElement.addEventListener('click', () => setTaskFilter('active'));
|
||||
@@ -9,6 +12,9 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
|
||||
let allTaskData = null;
|
||||
let currentFilter = 'all';
|
||||
let availableConfigs = [];
|
||||
let currentConfig = null;
|
||||
let categoryStats = {};
|
||||
|
||||
function refreshPage() {
|
||||
// Save expanded state before refresh
|
||||
@@ -31,8 +37,8 @@ function fetchTasksForRefresh() {
|
||||
fetch('/api/tasks/brief')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
// Update stored data
|
||||
allTaskData = data;
|
||||
categoryStats = calculateCategoryStats(data);
|
||||
// Only update statistics and task status, do not fully re-render
|
||||
updateStatistics(data);
|
||||
updateTaskStatus(data);
|
||||
@@ -148,6 +154,7 @@ function fetchTasks() {
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
allTaskData = data;
|
||||
categoryStats = calculateCategoryStats(data);
|
||||
renderTasks(data);
|
||||
updateStatistics(data);
|
||||
})
|
||||
@@ -208,13 +215,15 @@ function updateStatistics(data) {
|
||||
document.getElementById('completed-tasks').textContent = completedTasks;
|
||||
document.getElementById('error-tasks').textContent = errorTasks;
|
||||
|
||||
// Update score display with formatted score
|
||||
// Update score display with formatted score and accuracy percentage
|
||||
const scoreDisplay = document.getElementById('score-display');
|
||||
if (completedTasks > 0) {
|
||||
const scoreFormatted = totalScore.toFixed(2);
|
||||
scoreDisplay.innerHTML = `<span>${scoreFormatted}</span> / <span>${completedTasks}</span>`;
|
||||
const averageScore = totalScore / completedTasks;
|
||||
const accuracyPercentage = (averageScore * 100).toFixed(1);
|
||||
scoreDisplay.innerHTML = `<span>${scoreFormatted}</span> / <span>${completedTasks}</span> <span class="accuracy-percentage">(${accuracyPercentage}%)</span>`;
|
||||
} else {
|
||||
scoreDisplay.innerHTML = '<span>0.00</span> / <span>0</span>';
|
||||
scoreDisplay.innerHTML = '<span>0.00</span> / <span>0</span> <span class="accuracy-percentage">(0.0%)</span>';
|
||||
}
|
||||
|
||||
// Highlight the currently selected statistics card
|
||||
@@ -279,6 +288,10 @@ function renderTasks(data) {
|
||||
// Create header with task type name and statistics
|
||||
const typeHeader = document.createElement('div');
|
||||
typeHeader.className = 'task-type-header';
|
||||
|
||||
// Get category stats for this task type
|
||||
const stats = categoryStats[taskType] || {};
|
||||
|
||||
typeHeader.innerHTML = `
|
||||
<span class="task-type-name"><i class="fas fa-layer-group"></i> ${taskType}</span>
|
||||
<div class="task-type-stats">
|
||||
@@ -286,6 +299,9 @@ function renderTasks(data) {
|
||||
<span class="task-stat"><i class="fas fa-tasks"></i> ${tasks.length} total</span>
|
||||
<span class="task-stat running"><i class="fas fa-running"></i> ${runningCount} active</span>
|
||||
<span class="task-stat completed"><i class="fas fa-check-circle"></i> ${completedCount} completed</span>
|
||||
${stats.avg_score ? `<span class="task-stat score"><i class="fas fa-star"></i> ${stats.avg_score} avg score</span>` : ''}
|
||||
${stats.avg_steps ? `<span class="task-stat steps"><i class="fas fa-chart-line"></i> ${stats.avg_steps} avg steps</span>` : ''}
|
||||
${stats.completion_rate ? `<span class="task-stat rate"><i class="fas fa-percentage"></i> ${stats.completion_rate}% completed</span>` : ''}
|
||||
</div>
|
||||
`;
|
||||
typeSection.appendChild(typeHeader);
|
||||
@@ -453,7 +469,181 @@ function renderTasks(data) {
|
||||
container.appendChild(typeSection);
|
||||
});
|
||||
}
|
||||
// add auto-refresh with time interval 10 seconds
|
||||
setInterval(() => {
|
||||
refreshPage();
|
||||
}, 10000); // 10 seconds interval
|
||||
|
||||
function fetchAvailableConfigs() {
|
||||
return fetch('/api/available-configs')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
availableConfigs = data;
|
||||
populateConfigSelect();
|
||||
return data;
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error fetching available configs:', error);
|
||||
return [];
|
||||
});
|
||||
}
|
||||
|
||||
function populateConfigSelect() {
|
||||
const select = document.getElementById('config-select');
|
||||
select.innerHTML = '';
|
||||
|
||||
if (availableConfigs.length === 0) {
|
||||
select.innerHTML = '<option value="">No configurations found in results directory</option>';
|
||||
return;
|
||||
}
|
||||
|
||||
// Add available configurations
|
||||
availableConfigs.forEach((config, index) => {
|
||||
const option = document.createElement('option');
|
||||
option.value = index;
|
||||
option.textContent = `${config.action_space} / ${config.observation_type} / ${config.model_name}`;
|
||||
select.appendChild(option);
|
||||
});
|
||||
}
|
||||
|
||||
function changeConfiguration() {
|
||||
const select = document.getElementById('config-select');
|
||||
const selectedIndex = select.value;
|
||||
|
||||
if (selectedIndex === '' || selectedIndex < 0 || selectedIndex >= availableConfigs.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
const selectedConfig = availableConfigs[selectedIndex];
|
||||
|
||||
// Send configuration change request
|
||||
fetch('/api/set-config', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(selectedConfig)
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
currentConfig = data;
|
||||
displayConfig(data);
|
||||
// Refresh tasks with new configuration
|
||||
fetchTasks();
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error setting config:', error);
|
||||
displayConfigError();
|
||||
});
|
||||
}
|
||||
|
||||
function fetchConfig() {
|
||||
return fetch('/api/current-config')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
currentConfig = data;
|
||||
displayConfig(data);
|
||||
updateConfigSelect();
|
||||
return data;
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error fetching config:', error);
|
||||
displayConfigError();
|
||||
});
|
||||
}
|
||||
|
||||
function updateConfigSelect() {
|
||||
if (!currentConfig || availableConfigs.length === 0) return;
|
||||
|
||||
const select = document.getElementById('config-select');
|
||||
const currentConfigIndex = availableConfigs.findIndex(config =>
|
||||
config.action_space === currentConfig.action_space &&
|
||||
config.observation_type === currentConfig.observation_type &&
|
||||
config.model_name === currentConfig.model_name
|
||||
);
|
||||
|
||||
if (currentConfigIndex !== -1) {
|
||||
select.value = currentConfigIndex;
|
||||
} else {
|
||||
// Current config not found in available configs, select the first one if available
|
||||
if (availableConfigs.length > 0) {
|
||||
select.value = 0;
|
||||
console.warn('Current config not found in available configs, defaulting to first available config');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function displayConfig(config) {
|
||||
document.getElementById('action-space').textContent = config.action_space || 'N/A';
|
||||
document.getElementById('observation-type').textContent = config.observation_type || 'N/A';
|
||||
document.getElementById('model-name').textContent = config.model_name || 'N/A';
|
||||
document.getElementById('max-steps').textContent = config.max_steps || 'N/A';
|
||||
}
|
||||
|
||||
function displayConfigError() {
|
||||
const configValues = document.querySelectorAll('.config-value');
|
||||
configValues.forEach(element => {
|
||||
element.textContent = 'Error loading';
|
||||
element.style.color = '#dc3545';
|
||||
});
|
||||
}
|
||||
|
||||
function calculateCategoryStats(data) {
|
||||
const stats = {};
|
||||
|
||||
Object.entries(data).forEach(([taskType, tasks]) => {
|
||||
let totalTasks = tasks.length;
|
||||
let completedTasks = 0;
|
||||
let runningTasks = 0;
|
||||
let errorTasks = 0;
|
||||
let totalScore = 0;
|
||||
let totalSteps = 0;
|
||||
let completedWithSteps = 0;
|
||||
|
||||
tasks.forEach(task => {
|
||||
const status = task.status.status;
|
||||
|
||||
if (['Done', 'Done (Message Exit)', 'Done (Max Steps)', 'Done (Thought Exit)'].includes(status)) {
|
||||
completedTasks++;
|
||||
|
||||
// Calculate score if available
|
||||
if (task.status.result) {
|
||||
try {
|
||||
const score = parseFloat(task.status.result);
|
||||
if (!isNaN(score) && score >= 0 && score <= 1) {
|
||||
totalScore += score;
|
||||
}
|
||||
} catch (e) {
|
||||
// Ignore parsing errors
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate steps for completed tasks
|
||||
if (task.status.progress && task.status.progress > 0) {
|
||||
totalSteps += task.status.progress;
|
||||
completedWithSteps++;
|
||||
}
|
||||
|
||||
} else if (['Running', 'Preparing', 'Initializing'].includes(status)) {
|
||||
runningTasks++;
|
||||
|
||||
} else if (status === 'Error') {
|
||||
errorTasks++;
|
||||
}
|
||||
});
|
||||
|
||||
// Calculate averages
|
||||
const avgScore = completedTasks > 0 ? totalScore / completedTasks : 0;
|
||||
const avgSteps = completedWithSteps > 0 ? totalSteps / completedWithSteps : 0;
|
||||
const completionRate = totalTasks > 0 ? (completedTasks / totalTasks * 100) : 0;
|
||||
|
||||
stats[taskType] = {
|
||||
total_tasks: totalTasks,
|
||||
completed_tasks: completedTasks,
|
||||
running_tasks: runningTasks,
|
||||
error_tasks: errorTasks,
|
||||
total_score: Math.round(totalScore * 100) / 100,
|
||||
avg_score: Math.round(avgScore * 10000) / 10000,
|
||||
avg_steps: Math.round(avgSteps * 10) / 10,
|
||||
completion_rate: Math.round(completionRate * 10) / 10
|
||||
};
|
||||
});
|
||||
|
||||
return stats;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user