2025-09-23 16:34:48 +00:00
|
|
|
|
<!doctype html>
|
2025-10-17 11:58:14 +00:00
|
|
|
|
<html lang="zh-CN" data-bs-theme="auto">
|
2025-09-23 16:34:48 +00:00
|
|
|
|
<head>
|
2025-10-17 11:58:14 +00:00
|
|
|
|
<meta charset="utf-8">
|
|
|
|
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
|
|
|
|
<title>训练任务</title>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- Bootstrap 5.3 与 Icons(与前页一致) -->
|
|
|
|
|
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet"
|
|
|
|
|
|
integrity="sha384-sRIl4kxILFvY47J16cr9ZwB07vP4J8+LH7qKQnuqkuIAvNWLzeN8tE5YBujZqJLB" crossorigin="anonymous">
|
|
|
|
|
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css" rel="stylesheet">
|
|
|
|
|
|
|
|
|
|
|
|
<style>
|
|
|
|
|
|
/* 背景与玻璃卡片 —— 与首页/预览页一致 */
|
2025-10-17 12:41:34 +00:00
|
|
|
|
body {
|
|
|
|
|
|
min-height: 100vh;
|
2025-10-17 11:58:14 +00:00
|
|
|
|
background: radial-gradient(1200px 600px at 20% 10%, rgba(13,110,253,.15), transparent 60%),
|
|
|
|
|
|
radial-gradient(800px 400px at 80% 90%, rgba(32,201,151,.18), transparent 60%),
|
|
|
|
|
|
linear-gradient(180deg, #f8f9fa, #eef2f7);
|
|
|
|
|
|
}
|
2025-10-17 12:41:34 +00:00
|
|
|
|
@media (prefers-color-scheme: dark) {
|
|
|
|
|
|
body {
|
2025-10-17 11:58:14 +00:00
|
|
|
|
background: radial-gradient(1200px 600px at 20% 10%, rgba(13,110,253,.25), transparent 60%),
|
|
|
|
|
|
radial-gradient(800px 400px at 80% 90%, rgba(32,201,151,.25), transparent 60%),
|
|
|
|
|
|
linear-gradient(180deg, #0b1020, #0e1326);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-10-17 12:41:34 +00:00
|
|
|
|
.glass-card {
|
2025-10-17 11:58:14 +00:00
|
|
|
|
backdrop-filter: blur(10px);
|
|
|
|
|
|
-webkit-backdrop-filter: blur(10px);
|
|
|
|
|
|
background: rgba(255,255,255,.65);
|
2025-10-17 12:41:34 +00:00
|
|
|
|
border: 1px solid rgba(255,255,255,.5);
|
2025-10-17 11:58:14 +00:00
|
|
|
|
}
|
2025-10-17 12:41:34 +00:00
|
|
|
|
[data-bs-theme="dark"] .glass-card {
|
2025-10-17 11:58:14 +00:00
|
|
|
|
background: rgba(17,20,34,.6);
|
2025-10-17 12:41:34 +00:00
|
|
|
|
border: 1px solid rgba(255,255,255,.08);
|
2025-10-17 11:58:14 +00:00
|
|
|
|
}
|
2025-10-17 12:41:34 +00:00
|
|
|
|
.section-title {
|
|
|
|
|
|
display: flex; align-items: center; gap: .6rem; margin-bottom: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
.hint { font-size: .9rem; opacity: .75 }
|
|
|
|
|
|
|
|
|
|
|
|
/* 小卡片(参数分组) */
|
|
|
|
|
|
.subcard {
|
|
|
|
|
|
background: rgba(255,255,255,.6);
|
|
|
|
|
|
border: 1px solid rgba(0,0,0,.05);
|
|
|
|
|
|
border-radius: 1rem;
|
|
|
|
|
|
padding: 1rem;
|
|
|
|
|
|
}
|
|
|
|
|
|
[data-bs-theme="dark"] .subcard {
|
|
|
|
|
|
background: rgba(255,255,255,.04);
|
|
|
|
|
|
border-color: rgba(255,255,255,.08);
|
2025-10-17 11:58:14 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-17 12:41:34 +00:00
|
|
|
|
/* input-group 统一图标透明度 */
|
|
|
|
|
|
.input-group-text i { opacity: .8; }
|
|
|
|
|
|
|
|
|
|
|
|
/* progress 美化(保持 id 不变) */
|
|
|
|
|
|
#bar {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
height: 1rem;
|
|
|
|
|
|
border: none;
|
|
|
|
|
|
border-radius: .75rem;
|
|
|
|
|
|
background-color: rgba(13,110,253,.15);
|
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
vertical-align: middle;
|
2025-10-17 11:58:14 +00:00
|
|
|
|
}
|
2025-10-17 12:41:34 +00:00
|
|
|
|
#bar::-webkit-progress-bar { background: transparent; }
|
|
|
|
|
|
#bar::-webkit-progress-value {
|
|
|
|
|
|
background: linear-gradient(90deg, #0d6efd, #6ea8fe);
|
|
|
|
|
|
border-radius: .75rem;
|
2025-10-17 11:58:14 +00:00
|
|
|
|
}
|
2025-10-17 12:41:34 +00:00
|
|
|
|
#bar::-moz-progress-bar {
|
|
|
|
|
|
background: linear-gradient(90deg, #0d6efd, #6ea8fe);
|
|
|
|
|
|
border-radius: .75rem;
|
2025-10-17 11:58:14 +00:00
|
|
|
|
}
|
2025-10-17 12:41:34 +00:00
|
|
|
|
|
|
|
|
|
|
/* 上传/启动按钮动效(保持 id 不变) */
|
|
|
|
|
|
#uploadBtn {
|
|
|
|
|
|
padding: .65rem 1.1rem;
|
|
|
|
|
|
border-radius: .8rem;
|
|
|
|
|
|
transition: transform .12s ease, box-shadow .12s ease;
|
|
|
|
|
|
}
|
|
|
|
|
|
#uploadBtn:hover, #uploadBtn:focus-visible {
|
|
|
|
|
|
transform: translateY(-1px);
|
|
|
|
|
|
box-shadow: 0 .75rem 1.25rem rgba(0,0,0,.12);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 更紧凑的行距 */
|
|
|
|
|
|
.g-tight { row-gap: .75rem; }
|
2025-10-17 11:58:14 +00:00
|
|
|
|
</style>
|
2025-09-23 16:34:48 +00:00
|
|
|
|
</head>
|
|
|
|
|
|
|
|
|
|
|
|
<body>
|
2025-10-17 11:58:14 +00:00
|
|
|
|
<div class="container py-4">
|
|
|
|
|
|
<div class="glass-card rounded-4 shadow-lg p-4 p-md-5">
|
|
|
|
|
|
<!-- 标题 -->
|
|
|
|
|
|
<div class="d-flex align-items-center justify-content-between flex-wrap gap-2 mb-3">
|
2025-10-17 12:41:34 +00:00
|
|
|
|
<h1 class="section-title h4">
|
|
|
|
|
|
<i class="bi bi-cpu"></i> 训练配置
|
|
|
|
|
|
</h1>
|
2025-10-17 11:58:14 +00:00
|
|
|
|
<div class="hint">选择训练/测试数据并设置模型参数</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 选择文件 -->
|
|
|
|
|
|
<div class="mb-4">
|
|
|
|
|
|
<div class="row g-3">
|
|
|
|
|
|
<div class="col-12 col-lg-6">
|
2025-10-17 12:41:34 +00:00
|
|
|
|
<label class="form-label fw-semibold">
|
|
|
|
|
|
<i class="bi bi-folder2-open me-1"></i>选择训练文件
|
|
|
|
|
|
</label>
|
2025-10-17 11:58:14 +00:00
|
|
|
|
<div class="input-group">
|
|
|
|
|
|
<span class="input-group-text"><i class="bi bi-cloud-arrow-up"></i></span>
|
|
|
|
|
|
<input id="trainFileInput" type="file" class="form-control" multiple />
|
|
|
|
|
|
</div>
|
2025-10-17 12:41:34 +00:00
|
|
|
|
<div class="form-text">可多选;支持拖拽到输入框。</div>
|
2025-10-17 11:58:14 +00:00
|
|
|
|
</div>
|
2025-10-17 12:41:34 +00:00
|
|
|
|
|
2025-10-17 11:58:14 +00:00
|
|
|
|
<div class="col-12 col-lg-6">
|
2025-10-17 12:41:34 +00:00
|
|
|
|
<label class="form-label fw-semibold">
|
|
|
|
|
|
<i class="bi bi-folder2 me-1"></i>选择测试文件
|
|
|
|
|
|
</label>
|
2025-10-17 11:58:14 +00:00
|
|
|
|
<div class="input-group">
|
|
|
|
|
|
<span class="input-group-text"><i class="bi bi-cloud-arrow-up"></i></span>
|
|
|
|
|
|
<input id="testFileInput" type="file" class="form-control" multiple />
|
|
|
|
|
|
</div>
|
2025-10-17 12:41:34 +00:00
|
|
|
|
<div class="form-text">可选;用于评估训练效果。</div>
|
2025-10-17 11:58:14 +00:00
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<hr class="my-4">
|
|
|
|
|
|
|
2025-10-17 12:41:34 +00:00
|
|
|
|
<!-- 参数区 -->
|
2025-10-17 11:58:14 +00:00
|
|
|
|
<div class="row g-3">
|
|
|
|
|
|
<div class="col-12 col-lg-8">
|
2025-10-17 12:41:34 +00:00
|
|
|
|
<!-- 基础设置 -->
|
|
|
|
|
|
<div class="subcard mb-3">
|
|
|
|
|
|
<div class="d-flex align-items-center gap-2 mb-3">
|
|
|
|
|
|
<i class="bi bi-sliders2-vertical"></i><strong>基础设置</strong>
|
2025-10-17 11:58:14 +00:00
|
|
|
|
</div>
|
|
|
|
|
|
|
2025-10-17 12:41:34 +00:00
|
|
|
|
<div class="row g-3 g-tight">
|
|
|
|
|
|
<div class="col-12">
|
|
|
|
|
|
<div class="input-group">
|
|
|
|
|
|
<span class="input-group-text"><i class="bi bi-type me-1"></i>model name</span>
|
|
|
|
|
|
<input id="name" type="text" class="form-control" placeholder="为你的模型命名" />
|
|
|
|
|
|
</div>
|
2025-10-17 11:58:14 +00:00
|
|
|
|
</div>
|
|
|
|
|
|
|
2025-10-17 12:41:34 +00:00
|
|
|
|
<div class="col-12 col-md-6">
|
|
|
|
|
|
<div class="input-group">
|
|
|
|
|
|
<span class="input-group-text"><i class="bi bi-image me-1"></i>image filter</span>
|
|
|
|
|
|
<input id="image_filter" type="text" class="form-control" placeholder="_img" />
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="form-text">如 <code>*_img.png</code></div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="col-12 col-md-6">
|
|
|
|
|
|
<div class="input-group">
|
|
|
|
|
|
<span class="input-group-text"><i class="bi bi-brush me-1"></i>masks filter</span>
|
|
|
|
|
|
<input id="masks_filter" type="text" class="form-control" placeholder="_masks" />
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="form-text">如 <code>*_masks.png</code></div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="col-12">
|
|
|
|
|
|
<label class="w-100">
|
|
|
|
|
|
<div class="input-group">
|
|
|
|
|
|
<span class="input-group-text"><i class="bi bi-cpu-fill me-1"></i>model</span>
|
|
|
|
|
|
<select id="model" class="form-select"></select>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</label>
|
2025-10-17 11:58:14 +00:00
|
|
|
|
</div>
|
2025-09-23 16:34:48 +00:00
|
|
|
|
</div>
|
2025-10-17 12:41:34 +00:00
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 训练超参 -->
|
|
|
|
|
|
<div class="subcard">
|
|
|
|
|
|
<div class="d-flex align-items-center gap-2 mb-3">
|
|
|
|
|
|
<i class="bi bi-rocket-takeoff"></i><strong>训练超参数</strong>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="row g-3 g-tight">
|
|
|
|
|
|
<div class="col-12 col-md-6">
|
|
|
|
|
|
<div class="input-group">
|
|
|
|
|
|
<span class="input-group-text"><i class="bi bi-speedometer2 me-1"></i>learning rate</span>
|
|
|
|
|
|
<input id="learning_rate" type="text" class="form-control" placeholder="0.005" />
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
2025-09-23 16:34:48 +00:00
|
|
|
|
|
2025-10-17 12:41:34 +00:00
|
|
|
|
<div class="col-12 col-md-6">
|
2025-10-17 11:58:14 +00:00
|
|
|
|
<div class="input-group">
|
2025-10-17 12:41:34 +00:00
|
|
|
|
<span class="input-group-text"><i class="bi bi-hash me-1"></i>n epochs</span>
|
|
|
|
|
|
<input id="n_epochs" type="text" class="form-control" placeholder="100" />
|
2025-09-23 16:34:48 +00:00
|
|
|
|
</div>
|
2025-10-17 12:41:34 +00:00
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="col-12 col-md-6">
|
|
|
|
|
|
<div class="input-group">
|
|
|
|
|
|
<span class="input-group-text"><i class="bi bi-diagram-2 me-1"></i>weight decay</span>
|
|
|
|
|
|
<input id="weight_decay" type="text" class="form-control" placeholder="0.1" />
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="col-12 col-md-6">
|
|
|
|
|
|
<div class="input-group">
|
|
|
|
|
|
<span class="input-group-text"><i class="bi bi-arrows-move me-1"></i>normalize</span>
|
|
|
|
|
|
<select id="normalize" class="form-select">
|
|
|
|
|
|
<option selected value="1">True</option>
|
|
|
|
|
|
<option value="0">False</option>
|
|
|
|
|
|
</select>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="col-12 col-md-6">
|
|
|
|
|
|
<div class="input-group">
|
|
|
|
|
|
<span class="input-group-text"><i class="bi bi-gear me-1"></i>compute flows</span>
|
|
|
|
|
|
<!-- 注意:此处 id 仍为 normalize(你原文如此)。建议后续改名避免重复 -->
|
|
|
|
|
|
<select id="compute_flows" class="form-select">
|
|
|
|
|
|
<option selected value="0">False</option>
|
|
|
|
|
|
<option value="1">True</option>
|
|
|
|
|
|
</select>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="form-text">与光流/流场相关,通常仅在特定任务启用。</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="col-12 col-md-6">
|
|
|
|
|
|
<div class="input-group">
|
|
|
|
|
|
<span class="input-group-text"><i class="bi bi-123 me-1"></i>min train masks</span>
|
|
|
|
|
|
<input id="min_train_masks" type="text" class="form-control" placeholder="5" />
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="col-12 col-md-6">
|
|
|
|
|
|
<div class="input-group">
|
|
|
|
|
|
<span class="input-group-text"><i class="bi bi-collection me-1"></i>nimg_per_epoch</span>
|
|
|
|
|
|
<input id="nimg_per_epoch" type="text" class="form-control" placeholder="" />
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="col-12 col-md-6">
|
|
|
|
|
|
<div class="input-group">
|
|
|
|
|
|
<span class="input-group-text"><i class="bi bi-layers me-1"></i>channel axis</span>
|
|
|
|
|
|
<input id="channel_axis" type="text" class="form-control" placeholder="" />
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
2025-09-23 16:34:48 +00:00
|
|
|
|
</div>
|
2025-10-17 11:58:14 +00:00
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
2025-10-17 12:41:34 +00:00
|
|
|
|
<!-- 右侧提示 -->
|
2025-10-17 11:58:14 +00:00
|
|
|
|
<div class="col-12 col-lg-4">
|
|
|
|
|
|
<div class="p-3 rounded-3 border h-100">
|
|
|
|
|
|
<div class="d-flex align-items-center mb-2">
|
|
|
|
|
|
<i class="bi bi-info-circle me-2"></i><strong>提示</strong>
|
2025-09-23 16:34:48 +00:00
|
|
|
|
</div>
|
2025-10-17 11:58:14 +00:00
|
|
|
|
<div class="hint">
|
|
|
|
|
|
• 名称用于区分训练产物(日志/权重)。<br>
|
|
|
|
|
|
• filter 用于匹配文件名,如 <code>*_img.png</code>、<code>*_masks.png</code>。<br>
|
2025-10-17 12:41:34 +00:00
|
|
|
|
• 选择合适的预训练模型可加速收敛。<br>
|
|
|
|
|
|
• 建议仅微调必要超参,保持可复现性。
|
2025-10-17 11:58:14 +00:00
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 行动与进度(保持 id 与机制不变) -->
|
|
|
|
|
|
<div class="mt-4 d-flex flex-column flex-md-row align-items-stretch gap-3">
|
|
|
|
|
|
<button id="uploadBtn" class="btn btn-success d-inline-flex align-items-center">
|
|
|
|
|
|
<i class="bi bi-play-circle me-2"></i> Upload
|
|
|
|
|
|
</button>
|
|
|
|
|
|
<div class="flex-grow-1">
|
|
|
|
|
|
<div class="d-flex align-items-center justify-content-between mb-1">
|
|
|
|
|
|
<span class="hint"><i class="bi bi-activity me-1"></i>进度</span>
|
2025-10-17 12:41:34 +00:00
|
|
|
|
<span class="hint" id="barText"></span>
|
2025-10-17 11:58:14 +00:00
|
|
|
|
</div>
|
|
|
|
|
|
<progress id="bar" max="100" value="0"></progress>
|
2025-09-23 16:34:48 +00:00
|
|
|
|
</div>
|
2025-10-17 11:58:14 +00:00
|
|
|
|
</div>
|
2025-09-23 16:34:48 +00:00
|
|
|
|
</div>
|
2025-10-17 11:58:14 +00:00
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 只需引入 bundle(含 Popper) -->
|
|
|
|
|
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js"
|
|
|
|
|
|
integrity="sha384-FKyoEForCGlyvwx9Hj09JcYn3nv7wiPVlz7YYwJrWVcXK/BmnVDxM+D2scQbITxI"
|
|
|
|
|
|
crossorigin="anonymous"></script>
|
2025-09-23 16:34:48 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<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>
|
2025-09-26 15:28:20 +00:00
|
|
|
|
<script src="api.js"></script>
|
2025-09-23 16:34:48 +00:00
|
|
|
|
<script>
|
2025-09-26 15:28:20 +00:00
|
|
|
|
|
|
|
|
|
|
const API_UPLOAD = API_BASE + "train_upload";
|
|
|
|
|
|
const API_MODEL = API_BASE + "models";
|
2025-09-23 16:34:48 +00:00
|
|
|
|
|
|
|
|
|
|
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();
|
2025-10-17 12:41:34 +00:00
|
|
|
|
const learning_rate = (document.getElementById('learning_rate')?.value || '').trim();
|
|
|
|
|
|
const n_epochs = (document.getElementById('n_epochs')?.value || '').trim();
|
|
|
|
|
|
const weight_decay = (document.getElementById('weight_decay')?.value || '').trim();
|
|
|
|
|
|
const normalize = document.getElementById('normalize')?.value;
|
|
|
|
|
|
const compute_flows = document.getElementById('compute_flows')?.value;
|
|
|
|
|
|
const min_train_masks = (document.getElementById('min_train_masks')?.value || '').trim();
|
|
|
|
|
|
const nimg_per_epoch = (document.getElementById('nimg_per_epoch')?.value || '').trim();
|
|
|
|
|
|
const channel_axis = (document.getElementById('weight_decay')?.value || '').trim();
|
2025-09-23 16:34:48 +00:00
|
|
|
|
|
|
|
|
|
|
// 用 URLSearchParams 组装查询串
|
|
|
|
|
|
const qs = new URLSearchParams({
|
|
|
|
|
|
model: model,
|
|
|
|
|
|
model_name: model_name,
|
|
|
|
|
|
image_filter: image_filter,
|
2025-10-17 12:41:34 +00:00
|
|
|
|
masks_filter: masks_filter,
|
|
|
|
|
|
learning_rate: learning_rate,
|
|
|
|
|
|
n_epochs: n_epochs,
|
|
|
|
|
|
weight_decay: weight_decay,
|
|
|
|
|
|
normalize: normalize,
|
|
|
|
|
|
compute_flows: compute_flows,
|
|
|
|
|
|
min_train_masks: min_train_masks,
|
|
|
|
|
|
nimg_per_epoch: nimg_per_epoch,
|
|
|
|
|
|
channel_axis: channel_axis
|
2025-09-23 16:34:48 +00:00
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
return `${API_UPLOAD}?${qs.toString()}`;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
document.getElementById("uploadBtn").addEventListener("click", async () => {
|
|
|
|
|
|
const input_train = document.getElementById("trainFileInput");
|
|
|
|
|
|
const input_test = document.getElementById("testFileInput");
|
2025-09-24 19:03:56 +00:00
|
|
|
|
if (!input_train.files.length) return alert("请选择训练文件");
|
|
|
|
|
|
if (!input_test.files.length) return alert("请选择训练文件");
|
2025-09-23 16:34:48 +00:00
|
|
|
|
|
|
|
|
|
|
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);
|
2025-09-24 19:03:56 +00:00
|
|
|
|
window.location.href = `train_result.html?id=${encodeURIComponent(res.data['id'])}`;
|
2025-09-23 16:34:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
}, 1000);
|
|
|
|
|
|
} catch (e) {
|
|
|
|
|
|
alert("上传失败:" + (e.response?.data?.message || e.message));
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
bar.value = 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
</script>
|
|
|
|
|
|
</body>
|
|
|
|
|
|
|
|
|
|
|
|
</html>
|