initial push
This commit is contained in:
254
overview-training.html
Normal file
254
overview-training.html
Normal file
@@ -0,0 +1,254 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta charset="utf-8" />
|
||||
<link rel="stylesheet" href="globals.css" />
|
||||
<link rel="stylesheet" href="styleguide.css" />
|
||||
<link rel="stylesheet" href="style.css" />
|
||||
<style>
|
||||
#projects-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 15px;
|
||||
justify-content: flex-start;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.dataset-card {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body onload="pollStatus()">
|
||||
<div>
|
||||
<div id="header">
|
||||
<icon class="header-icon" onclick="window.location.href='/index.html'" , onmouseover="" style="cursor: pointer;"
|
||||
src="./media/logo.png" alt="Logo"></icon>
|
||||
<label id="project-title-label"
|
||||
style="display: block; text-align: left; font-weight: bold; font-size: x-large;">Project</label>
|
||||
<div class="button-row">
|
||||
<button id="Add Training Project" onclick="window.location.href='/add-project.html'" class="button-red">Add
|
||||
Training Project</button>
|
||||
<button id="seed-db-btn" class="button">
|
||||
Seed Database
|
||||
<div class="loader" id="loader" style="display: none"></div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</button>
|
||||
<button id="generate-yolox-json-btn" class="button">
|
||||
Generate YOLOX JSON
|
||||
</button>
|
||||
|
||||
</button>
|
||||
<button id="setup-details" class="button">
|
||||
Show Details
|
||||
</button>
|
||||
|
||||
<script>
|
||||
document.getElementById('seed-db-btn').addEventListener('click', function () {
|
||||
const elLoader = document.getElementById("loader")
|
||||
elLoader.style.display = "inherit"
|
||||
|
||||
fetch('/api/seed')
|
||||
.finally(() => {
|
||||
// Instead of hiding loader immediately, poll /api/update-status until done
|
||||
function pollStatus() {
|
||||
fetch('/api/update-status')
|
||||
.then(res => res.json())
|
||||
.then(status => {
|
||||
if (status && status.running) {
|
||||
// Still running, poll again after short delay
|
||||
setTimeout(pollStatus, 5000);
|
||||
} else {
|
||||
elLoader.style.display = "none";
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
elLoader.style.display = "none";
|
||||
});
|
||||
}
|
||||
pollStatus();
|
||||
})
|
||||
});
|
||||
|
||||
// Show loader if backend is still processing on page load
|
||||
|
||||
function pollStatus() {
|
||||
const elLoader = document.getElementById("loader");
|
||||
fetch('/api/update-status')
|
||||
.then(res => res.json())
|
||||
|
||||
.then(status => {
|
||||
if (status && status.running) {
|
||||
elLoader.style.display = "inherit";
|
||||
setTimeout(pollStatus, 5000);
|
||||
} else {
|
||||
elLoader.style.display = "none";
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
elLoader.style.display = "none";
|
||||
});
|
||||
}
|
||||
|
||||
</script>
|
||||
<script>
|
||||
// Declare urlParams and projectId once
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
const projectId = urlParams.get('id');
|
||||
// Set project title in header
|
||||
fetch('/api/training-projects')
|
||||
.then(res => res.json())
|
||||
.then(projects => {
|
||||
const project = projects.find(p => p.project_id == projectId || p.id == projectId);
|
||||
if (project) {
|
||||
const titleLabel = document.getElementById('project-title-label');
|
||||
if (titleLabel) titleLabel.textContent = '/' + project.title;
|
||||
}
|
||||
});
|
||||
// Render trainings
|
||||
function renderTrainings(trainings) {
|
||||
const list = document.getElementById('projects-list');
|
||||
list.innerHTML = '';
|
||||
if (!Array.isArray(trainings) || trainings.length === 0) {
|
||||
list.innerHTML = '<div style="color:#009eac;padding:16px;">No trainings found for this project.</div>';
|
||||
return;
|
||||
}
|
||||
trainings.forEach(training => {
|
||||
const card = document.createElement('div');
|
||||
card.className = 'dataset-card';
|
||||
card.style = 'border:1px solid #009eac;padding:12px;margin:8px;border-radius:8px;background:#eaf7fa;position:relative;min-width:320px;min-height:120px;display:flex;flex-direction:row;justify-content:space-between;align-items:stretch;';
|
||||
|
||||
// Info section (left)
|
||||
const infoDiv = document.createElement('div');
|
||||
infoDiv.style = 'flex:1; text-align:left;';
|
||||
infoDiv.innerHTML = `<b>${training.exp_name || 'Training'}</b><br>Epochs: ${training.max_epoch}<br>Depth: ${training.depth}<br>Width: ${training.width}<br>Activation: ${training.activation || training.act || ''}`;
|
||||
|
||||
// Buttons section (right)
|
||||
const btnDiv = document.createElement('div');
|
||||
btnDiv.style = 'display:flex;flex-direction:column;align-items:flex-end;gap:8px;min-width:160px;';
|
||||
|
||||
// Start Training button
|
||||
const startBtn = document.createElement('button');
|
||||
startBtn.textContent = 'Start YOLOX Training';
|
||||
startBtn.style = 'background:#009eac;color:white;border:none;border-radius:6px;padding:6px 12px;cursor:pointer;';
|
||||
startBtn.onclick = function() {
|
||||
startBtn.disabled = true;
|
||||
fetch('/api/start-yolox-training', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ project_id: projectId, training_id: training.id })
|
||||
})
|
||||
.then(res => res.json())
|
||||
.then(result => {
|
||||
alert(result.message || 'Training started');
|
||||
startBtn.disabled = false;
|
||||
})
|
||||
.catch(() => {
|
||||
alert('Failed to start training');
|
||||
startBtn.disabled = false;
|
||||
});
|
||||
};
|
||||
btnDiv.appendChild(startBtn);
|
||||
|
||||
// View Log button
|
||||
const logBtn = document.createElement('button');
|
||||
logBtn.textContent = 'View Training Log';
|
||||
logBtn.style = 'background:#666;color:white;border:none;border-radius:6px;padding:6px 12px;cursor:pointer;';
|
||||
logBtn.onclick = function() {
|
||||
showLogModal(training.id);
|
||||
};
|
||||
btnDiv.appendChild(logBtn);
|
||||
|
||||
// Remove button
|
||||
const removeBtn = document.createElement('button');
|
||||
removeBtn.textContent = 'Remove';
|
||||
removeBtn.style = 'background:#ff4d4f;color:white;border:none;border-radius:6px;padding:6px 12px;cursor:pointer;';
|
||||
removeBtn.onclick = function() {
|
||||
if (confirm('Are you sure you want to delete this training?')) {
|
||||
fetch(`/api/trainings/${training.id}`, { method: 'DELETE' })
|
||||
.then(res => res.json())
|
||||
.then(result => {
|
||||
alert(result.message || 'Training deleted');
|
||||
fetchTrainings(); // Refresh list
|
||||
})
|
||||
.catch(() => alert('Failed to delete training'));
|
||||
}
|
||||
};
|
||||
btnDiv.appendChild(removeBtn);
|
||||
|
||||
card.appendChild(infoDiv);
|
||||
card.appendChild(btnDiv);
|
||||
list.appendChild(card);
|
||||
});
|
||||
// Modal for log display
|
||||
if (!document.getElementById('log-modal')) {
|
||||
const modal = document.createElement('div');
|
||||
modal.id = 'log-modal';
|
||||
modal.style = 'display:none;position:fixed;top:0;left:0;width:100vw;height:100vh;background:rgba(0,0,0,0.5);z-index:9999;justify-content:center;align-items:center;';
|
||||
modal.innerHTML = `<div style="background:#fff;padding:24px;border-radius:8px;max-width:800px;width:90vw;max-height:80vh;overflow:auto;position:relative;"><pre id='log-content' style='font-size:13px;white-space:pre-wrap;word-break:break-all;max-height:60vh;overflow:auto;background:#f7f7f7;padding:12px;border-radius:6px;'></pre><button id='close-log-modal' style='position:absolute;top:8px;right:8px;background:#009eac;color:#fff;border:none;border-radius:4px;padding:6px 12px;cursor:pointer;'>Close</button></div>`;
|
||||
document.body.appendChild(modal);
|
||||
document.getElementById('close-log-modal').onclick = function() {
|
||||
modal.style.display = 'none';
|
||||
};
|
||||
}
|
||||
|
||||
// Function to show log modal and poll log
|
||||
function showLogModal(trainingId) {
|
||||
const modal = document.getElementById('log-modal');
|
||||
const logContent = document.getElementById('log-content');
|
||||
modal.style.display = 'flex';
|
||||
function fetchLog() {
|
||||
fetch(`/api/training-log?project_id=${projectId}&training_id=${trainingId}`)
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
logContent.textContent = data.log || 'No log found.';
|
||||
})
|
||||
.catch(() => {
|
||||
logContent.textContent = 'Failed to fetch log.';
|
||||
});
|
||||
}
|
||||
fetchLog();
|
||||
// Poll every 5 seconds while modal is open
|
||||
let poller = setInterval(() => {
|
||||
if (modal.style.display === 'flex') fetchLog();
|
||||
else clearInterval(poller);
|
||||
}, 5000);
|
||||
}
|
||||
}
|
||||
// Fetch trainings for project
|
||||
function fetchTrainings() {
|
||||
if (!projectId) return;
|
||||
fetch(`/api/trainings?project_id=${projectId}`)
|
||||
.then(res => res.json())
|
||||
.then(trainings => {
|
||||
renderTrainings(trainings);
|
||||
});
|
||||
}
|
||||
window.addEventListener('DOMContentLoaded', fetchTrainings);
|
||||
document.getElementById('generate-yolox-json-btn').addEventListener('click', function () {
|
||||
fetch('/api/generate-yolox-json', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ project_id: projectId })
|
||||
})
|
||||
.then(res => res.json())
|
||||
.then(result => {
|
||||
alert('YOLOX JSON generated!');
|
||||
})
|
||||
.catch(err => {
|
||||
alert('Failed to generate YOLOX JSON');
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<div id="projects-list"></div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
Reference in New Issue
Block a user