cellpose-web/frontend/train.html

197 lines
No EOL
8.2 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Bootstrap demo</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-GLhlTQ8iRABdZLl6O3oVMWSktQOp6b7In1Zl3/Jr59b6EGGoI1aFkw7cmDA6j6gD" crossorigin="anonymous">
</head>
<body>
<div style="padding: 1rem 1rem;">
<div class="mb-3 border" style="padding: 1rem 1rem;">
<div class="input-group mb-3">
<h5>选择训练文件</h5>
<input id="trainFileInput" type="file" class="form-control" multiple />
</div>
<div class="input-group mb-3">
<h5>选择测试文件</h5>
<input id="testFileInput" type="file" class="form-control" multiple />
</div>
<hr>
<div>
<div style="padding-right: 50rem;">
<div class="input-group mb-3">
<span class="input-group-text">model name:</span>
<input id="name" type="text" class="form-control" placeholder="为你的模型命名" />
</div>
<div class="input-group mb-3">
<span class="input-group-text">image filter:</span>
<input id="image_filter" type="text" class="form-control" placeholder="_img" />
</div>
<div class="input-group mb-3">
<span class="input-group-text">masks filter</span>
<input id="masks_filter" type="text" class="form-control" placeholder="_masks" />
</div>
<label>
<select id="model" class="form-select"></select>
</label>
</label>
</div>
</div>
<br>
<div>
<button id="uploadBtn" class="btn btn-success">Upload</button>
<progress id="bar" max="100" value="0" style="width:300px;"></progress>
</div>
</div>
</div>
<br><br><br>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.6/dist/umd/popper.min.js"
integrity="sha384-oBqDVmMz9ATKxIep9tiCxS/Z9fNfEXiDAYTujMAeBAsjFuCZSmKbSSUnQlmh/jp3"
crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.min.js"
integrity="sha384-ep+dxp/oz2RKF89ALMPGc7Z89QFa32C8Uv1A3TcEK8sMzXVysblLA3+eJWTzPJzT"
crossorigin="anonymous"></script>
<script src="api.js"></script>
<script>
const API_UPLOAD = API_BASE + "train_upload";
const API_MODEL = API_BASE + "models";
async function loadModels() {
const select = document.getElementById('model');
// 占位 & 禁用,避免用户在加载中点选
select.disabled = true;
select.innerHTML = '<option value="">加载中…</option>';
// 可选超时控制5 秒)
const controller = new AbortController();
const t = setTimeout(() => controller.abort(), 5000);
try {
const resp = await fetch(API_MODEL, {
headers: { 'Accept': 'application/json' },
signal: controller.signal
});
if (!resp.ok) throw new Error(`HTTP ${resp.status}`);
const data = await resp.json();
const list = Array.isArray(data.models) ? data.models : [];
// 记住之前的选择(如果有)
const prev = select.value;
// 重新渲染选项
select.innerHTML = '<option value="" disabled selected>请选择基础模型</option>';
const seen = new Set();
for (const name of list) {
if (!name || seen.has(name)) continue;
seen.add(name);
const opt = document.createElement('option');
opt.value = String(name);
opt.textContent = String(name);
select.appendChild(opt);
}
// 如果原选择仍然存在,则恢复它
if (prev && seen.has(prev)) {
select.value = prev;
}
} catch (err) {
console.error('加载模型列表失败:', err);
select.innerHTML = '<option value="">加载失败(点击重试)</option>';
// 点击下拉框时重试
select.addEventListener('click', loadModels, { once: true });
} finally {
clearTimeout(t);
select.disabled = false;
}
}
document.addEventListener('DOMContentLoaded', loadModels);
function buildUrl() {
// 获取参数
const model = document.getElementById('model')?.value;
const model_name = (document.getElementById('model_name')?.value || '').trim();
const image_filter = (document.getElementById('image_filter')?.value || '').trim();
const masks_filter = (document.getElementById('masks_filter')?.value || '').trim();
// 用 URLSearchParams 组装查询串
const qs = new URLSearchParams({
model: model,
model_name: model_name,
image_filter: image_filter,
masks_filter: masks_filter
});
return `${API_UPLOAD}?${qs.toString()}`;
}
document.getElementById("uploadBtn").addEventListener("click", async () => {
const input_train = document.getElementById("trainFileInput");
const input_test = document.getElementById("testFileInput");
if (!input_train.files.length) return alert("请选择训练文件");
if (!input_test.files.length) return alert("请选择训练文件");
const fd = new FormData();
for (const f of input_train.files) fd.append("train_files", f);
for (const f of input_test.files) fd.append("test_files", f);
const bar = document.getElementById("bar");
try {
const URL = buildUrl();
const res = await axios.post(URL, fd, {
onUploadProgress: (e) => {
if (e.total) bar.value = Math.round((e.loaded * 100) / e.total);
},
});
// alert("" + JSON.stringify(res.data));
// 创建一个提示元素
const notice = document.createElement("div");
notice.style.position = "fixed";
notice.style.top = "20px";
notice.style.left = "50%";
notice.style.transform = "translateX(-50%)";
notice.style.padding = "10px 20px";
notice.style.background = "#4caf50";
notice.style.color = "white";
notice.style.borderRadius = "8px";
notice.style.fontSize = "16px";
notice.style.zIndex = "9999";
let seconds = 3;
notice.textContent = `上传成功!${seconds} 秒后跳转预览页面…`;
document.body.appendChild(notice);
const timer = setInterval(() => {
seconds--;
if (seconds > 0) {
notice.textContent = `上传成功!${seconds} 秒后跳转预览页面…`;
} else {
clearInterval(timer);
document.body.removeChild(notice);
window.location.href = `train_result.html?id=${encodeURIComponent(res.data['id'])}`;
}
}, 1000);
} catch (e) {
alert("上传失败:" + (e.response?.data?.message || e.message));
} finally {
bar.value = 0;
}
});
</script>
</body>
</html>