feat(backend): 新增更多接口

feat(frontend): 前端样式优化
This commit is contained in:
ClovertaTheTrilobita 2025-10-17 11:58:14 +00:00
parent 8ca5f971ba
commit 723bfdf2d9
6 changed files with 653 additions and 73 deletions

View file

@ -5,6 +5,8 @@ import redis
import datetime
import json
from sympy import false
CONFIG_PATH = Path(__file__).parent / "config.yaml"
cfg = OmegaConf.load(CONFIG_PATH)
cfg.data.root_dir = str((CONFIG_PATH.parent / cfg.data.root_dir).resolve())
@ -34,11 +36,25 @@ class Cptrain:
@classmethod
async def start_train(cls,
time: str | None = None,
model_name: str | None = None,
image_filter: str = "_img",
mask_filter: str = "_masks",
base_model: str = "cpsam"):
time: str | None = None,
model_name: str | None = None,
image_filter: str = "_img",
mask_filter: str = "_masks",
base_model: str = "cpsam",
train_probs: list[float] = None,
test_probs: list[float] = None,
batch_size: int = 8,
learning_rate = 5e-5,
n_epochs: int = 100,
weight_decay=0.1,
normalize: bool =True,
compute_flows: bool = False,
min_train_masks: int = 5,
nimg_per_epoch: int =None,
rescale: bool= False,
scale_range=None,
channel_axis: int = None,
):
train_dir = Path(TRAIN_DIR) / time
test_dir = Path(TEST_DIR) / time
@ -56,9 +72,13 @@ class Cptrain:
model_path, train_losses, test_losses = train.train_seg(model.net,
train_data=images, train_labels=labels,
test_data=test_images, test_labels=test_labels,
weight_decay=0.1, learning_rate=1e-5,
n_epochs=100, model_name=model_name,
save_path=BASE_DIR)
train_probs=train_probs, test_probs=test_probs,
weight_decay=weight_decay, learning_rate=learning_rate,
n_epochs=n_epochs, model_name=model_name,
save_path=BASE_DIR, batch_size=batch_size,
normalize=normalize, compute_flows=compute_flows, min_train_masks=min_train_masks,
nimg_per_epoch=nimg_per_epoch, rescale=rescale, scale_range=scale_range, channel_axis=channel_axis
)
set_status(time, "done", train_losses, test_losses)
print("模型已保存到:", model_path)

View file

@ -145,6 +145,17 @@ def train_upload():
image_filter = request.args.get("image_filter") or "_img"
mask_filter = request.args.get("mask_filter") or "_masks"
base_model = request.args.get("base_model") or "cpsam"
batch_size = request.args.get("batch_size") or 8
learning_rate = request.args.get("learning_rate") or 5e-5
n_epochs = request.args.get("n_epochs") or 100
weight_decay = request.args.get("weight_decay") or 0.1
normalize = request.args.get("normalize") or True
compute_flows = request.args.get("compute_flows") or False
min_train_masks = request.args.get(" min_train_masks") or 5
nimg_per_epoch = request.args.get("nimg_per_epoch") or None
rescale = request.args.get("rescale") or False
scale_range = request.args.get("scale_range") or None
channel_axis = request.args.get("channel_axis") or None
train_files = request.files.getlist("train_files")
test_files = request.files.getlist("test_files")
@ -172,7 +183,18 @@ def train_upload():
model_name=model_name,
image_filter=image_filter,
mask_filter=mask_filter,
base_model=base_model
base_model=base_model,
batch_size=batch_size,
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,
rescale=rescale,
scale_range=scale_range,
channel_axis=channel_axis,
))
fut = executor.submit(job)

View file

@ -1,18 +1,139 @@
<!DOCTYPE html>
<html lang="en">
<html lang="zh-CN" data-bs-theme="auto">
<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">
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>任务面板</title>
<!-- Bootstrap CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-sRIl4kxILFvY47J16cr9ZwB07vP4J8+LH7qKQnuqkuIAvNWLzeN8tE5YBujZqJLB" crossorigin="anonymous" />
<!-- Bootstrap Icons -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css" rel="stylesheet">
<style>
/* 背景渐变 + 玻璃感卡片 */
body {
min-height: 100vh;
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);
}
@media (prefers-color-scheme: dark) {
body {
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);
}
}
.glass-card {
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
background: rgba(255, 255, 255, 0.65);
border: 1px solid rgba(255, 255, 255, 0.5);
}
[data-bs-theme="dark"] .glass-card {
background: rgba(17, 20, 34, 0.6);
border: 1px solid rgba(255, 255, 255, 0.08);
}
.action-btn {
transition: transform .15s ease, box-shadow .15s ease;
padding: 1.1rem 1.4rem;
font-size: 1.05rem;
border-radius: 1rem;
}
.action-btn:hover, .action-btn:focus-visible {
transform: translateY(-2px);
box-shadow: 0 0.75rem 1.25rem rgba(0,0,0,.12);
}
.btn-icon {
display: inline-flex;
align-items: center;
gap: .6rem;
}
.brand-badge {
letter-spacing: .08em;
background: rgba(13,110,253,.1);
color: #0d6efd;
border: 1px solid rgba(13,110,253,.15);
}
[data-bs-theme="dark"] .brand-badge {
background: rgba(13,110,253,.15);
color: #9ec5fe;
border-color: rgba(13,110,253,.25);
}
</style>
</head>
<body>
<main class="container min-vh-100 d-flex align-items-center justify-content-center py-5">
<div class="col-12 col-md-10 col-lg-8">
<div class="glass-card rounded-4 shadow-lg p-4 p-md-5 text-center">
<div class="d-flex justify-content-center mb-3">
<span class="badge brand-badge rounded-pill px-3 py-2">
<i class="bi bi-rocket-takeoff me-1"></i> Cell Processing
</span>
</div>
<a href="run.html">运行</a>
<a href="train.html">训练</a>
<h1 class="display-6 fw-semibold mb-2">欢迎使用任务面板</h1>
<p class="text-secondary mb-4">
选择你要进行的操作。可随时返回此页切换任务。
</p>
<div class="row g-3 g-md-4 justify-content-center">
<div class="col-12 col-sm-6">
<a href="run.html" class="btn btn-primary w-100 action-btn btn-icon" role="button" aria-label="进入运行页面">
<i class="bi bi-play-circle-fill fs-4"></i>
<span>
运行<br>
<small class="opacity-75">快速执行已有模型/流程</small>
</span>
</a>
</div>
<div class="col-12 col-sm-6">
<a href="train.html" class="btn btn-outline-primary w-100 action-btn btn-icon" role="button" aria-label="进入训练页面">
<i class="bi bi-cpu-fill fs-4"></i>
<span>
训练<br>
<small class="opacity-75">启动或继续训练任务</small>
</span>
</a>
</div>
</div>
<hr class="my-4 my-md-5">
<div class="d-flex flex-column flex-md-row gap-2 justify-content-center">
<a href="#" class="link-secondary text-decoration-none">
<i class="bi bi-book"></i> 文档
</a>
<span class="text-secondary d-none d-md-inline"></span>
<a href="#" class="link-secondary text-decoration-none">
<i class="bi bi-gear"></i> 设置
</a>
<span class="text-secondary d-none d-md-inline"></span>
<span class="text-secondary"><i class="bi bi-keyboard"></i> 快捷键:<kbd>R</kbd> 运行,<kbd>T</kbd> 训练</span>
</div>
</div>
</div>
</main>
<!-- 键盘快捷键(可选) -->
<script>
window.addEventListener('keydown', (e) => {
if (['INPUT','TEXTAREA'].includes((e.target.tagName || '').toUpperCase())) return;
if (e.key.toLowerCase() === 'r') location.href = 'run.html';
if (e.key.toLowerCase() === 't') location.href = 'train.html';
});
</script>
<!-- 只需引入 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>
</body>
</html>

View file

@ -1,9 +1,148 @@
<!DOCTYPE html>
<meta charset="UTF-8" />
<h1>运行结果预览</h1>
<p id="none-exist" hidden></p>
<div id="gallery"></div>
<button onclick="downloadTif()">下载tif</button>
<html lang="zh-CN" data-bs-theme="auto">
<head>
<meta charset="UTF-8" />
<title>运行结果预览</title>
<!-- Bootstrap + 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>
/* 背景与玻璃卡片 —— 与首页一致 */
body {
min-height: 100vh;
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);
}
@media (prefers-color-scheme: dark) {
body {
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);
}
}
.glass-card {
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
background: rgba(255, 255, 255, 0.65);
border: 1px solid rgba(255, 255, 255, 0.5);
}
[data-bs-theme="dark"] .glass-card {
background: rgba(17, 20, 34, 0.6);
border: 1px solid rgba(255, 255, 255, 0.08);
}
/* 标题区 */
.page-title {
display: flex;
align-items: center;
gap: .6rem;
margin-bottom: 0;
}
.sub-hint {
font-size: .9rem;
opacity: .75;
}
/* 预览网格:仅美化 #gallery保持 id 不变 */
#gallery {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
gap: 1rem;
}
/* 预览卡片 */
.thumb {
position: relative;
overflow: hidden;
border-radius: 1rem;
background: rgba(0,0,0,.05);
border: 1px solid rgba(0,0,0,.06);
transition: transform .12s ease, box-shadow .12s ease;
}
.thumb:hover {
transform: translateY(-2px);
box-shadow: 0 .9rem 1.2rem rgba(0,0,0,.12);
}
.thumb img, .thumb canvas, .thumb video {
width: 100%;
height: 180px;
object-fit: cover;
display: block;
}
.thumb .badge-overlay {
position: absolute;
top: .5rem;
left: .5rem;
padding: .25rem .5rem;
border-radius: .5rem;
background: rgba(13,110,253,.85);
color: #fff;
font-size: .75rem;
}
/* 空态提示:仅美化 #none-exist */
#none-exist {
margin: 0;
padding: 1rem 1.25rem;
border-radius: .75rem;
background: rgba(108,117,125,.08);
border: 1px dashed rgba(108,117,125,.35);
color: inherit;
}
/* 下载按钮 */
.download-wrap {
gap: .75rem;
}
.download-btn {
padding: .65rem 1.1rem;
border-radius: .8rem;
transition: transform .12s ease, box-shadow .12s ease;
}
.download-btn:hover, .download-btn:focus-visible {
transform: translateY(-1px);
box-shadow: 0 .75rem 1.25rem rgba(0,0,0,.12);
}
</style>
</head>
<body>
<div class="container py-4">
<div class="glass-card rounded-4 shadow-lg p-4 p-md-5">
<!-- 标题区(保持语义,未改 id -->
<div class="d-flex align-items-center justify-content-between flex-wrap gap-2 mb-3">
<h1 class="page-title h4">
<i class="bi bi-images"></i> 运行结果预览
</h1>
<div class="sub-hint">
生成的图像/掩膜将显示在下方网格中
</div>
</div>
<!-- 空态提示:仅样式增强,不改 id/hidden 机制 -->
<p id="none-exist" hidden></p>
<!-- 预览网格:只美化 #gallery -->
<div id="gallery"></div>
<!-- 下载按钮:保留 onclick不动逻辑只加样式 -->
<div class="mt-4 d-flex download-wrap">
<button class="btn btn-primary d-inline-flex align-items-center download-btn"
onclick="downloadTif()">
<i class="bi bi-download me-2"></i> 下载 TIF
</button>
</div>
</div>
</div>
<!-- 仅需引入 bundle如你已有可省略 -->
<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>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script src="api.js"></script>
@ -67,3 +206,5 @@
document.body.removeChild(a);
}
</script>
</body>
</html>

View file

@ -10,7 +10,7 @@
</head>
<body>
<div style="padding: 1rem 1rem;">
<!-- <div style="padding: 1rem 1rem;">
<div class="mb-3 border" style="padding: 1rem 1rem;">
<div class="input-group mb-3">
<input id="fileInput" type="file" class="form-control" multiple />
@ -47,7 +47,94 @@
</div>
</div>
</div>
<br><br><br>
<br><br><br> -->
<div class="container py-4">
<div class="glass-card rounded-4 shadow-lg p-4 p-md-5">
<!-- 上传区 -->
<div class="mb-4">
<div class="d-flex align-items-center justify-content-between mb-3">
<h2 class="h5 section-title mb-0"><i class="bi bi-folder2-open me-2"></i>选择文件</h2>
<span class="hint">可多选</span>
</div>
<div class="input-group">
<span class="input-group-text"><i class="bi bi-cloud-arrow-up"></i></span>
<input id="fileInput" type="file" class="form-control" multiple />
</div>
</div>
<hr class="my-4">
<!-- 参数区 -->
<div class="row g-3">
<div class="col-12 col-lg-8">
<div class="row g-3">
<div class="col-12 col-md-6">
<div class="input-group">
<span class="input-group-text"><i class="bi bi-speedometer2 me-1"></i>flow threshold</span>
<input id="flow" 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-bezier2 me-1"></i>cellprob threshold</span>
<input id="cellprob" 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-bounding-box-circles me-1"></i>diameter</span>
<input id="diameter" type="text" class="form-control" placeholder="" />
</div>
</div>
<div class="col-12 col-md-6">
<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>
</div>
</div>
</div>
<!-- 右侧说明(可删) -->
<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>
</div>
<div class="hint">
• 参数留空将使用默认值。<br>
• 数值可使用小数(如 0.4)。<br>
• 选择合适的模型以获得更稳健的分割效果。
</div>
</div>
</div>
</div>
<!-- 行动区 -->
<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-upload 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>
<span class="hint" id="barText"></span><!-- 如需,你的 JS 可写入文本 -->
</div>
<progress id="bar" max="100" value="0"></progress>
</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
@ -184,6 +271,82 @@
}
});
</script>
<style>
/* 页面背景与卡片 */
body {
min-height: 100vh;
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);
}
@media (prefers-color-scheme: dark) {
body {
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);
}
}
.glass-card {
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
background: rgba(255, 255, 255, 0.65);
border: 1px solid rgba(255, 255, 255, 0.5);
}
[data-bs-theme="dark"] .glass-card {
background: rgba(17, 20, 34, 0.6);
border: 1px solid rgba(255, 255, 255, 0.08);
}
/* 区块与控件 */
.section-title {
font-weight: 600;
letter-spacing: .02em;
}
.input-group-text i {
opacity: .7;
}
.hint {
font-size: .875rem;
opacity: .75;
}
/* 原生 <progress> 美化(保持 id 不变) */
#bar {
width: 100%;
height: 1rem;
border: none;
border-radius: .75rem;
background-color: rgba(13,110,253,.15);
overflow: hidden;
vertical-align: middle;
}
/* Chrome / Edge / Safari */
#bar::-webkit-progress-bar {
background-color: transparent;
}
#bar::-webkit-progress-value {
background: linear-gradient(90deg, #0d6efd, #6ea8fe);
border-radius: .75rem;
}
/* Firefox */
#bar::-moz-progress-bar {
background: linear-gradient(90deg, #0d6efd, #6ea8fe);
border-radius: .75rem;
}
/* 上传按钮动效 */
#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);
}
</style>
</body>
</html>

View file

@ -1,58 +1,171 @@
<!doctype html>
<html lang="en">
<html lang="zh-CN" data-bs-theme="auto">
<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">
<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>
/* 背景与玻璃卡片 —— 与首页/预览页一致 */
body{
min-height:100vh;
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);
}
@media (prefers-color-scheme: dark){
body{
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);
}
}
.glass-card{
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
background: rgba(255,255,255,.65);
border:1px solid rgba(255,255,255,.5);
}
[data-bs-theme="dark"] .glass-card{
background: rgba(17,20,34,.6);
border:1px solid rgba(255,255,255,.08);
}
.section-title{
display:flex; align-items:center; gap:.6rem;
margin-bottom:0;
}
.hint{font-size:.9rem; opacity:.75}
/* 原生 progress 美化(保持 id 不变) */
#bar{
width:100%; height:1rem; border:none; border-radius:.75rem;
background-color:rgba(13,110,253,.15); overflow:hidden; vertical-align:middle;
}
#bar::-webkit-progress-bar{background:transparent}
#bar::-webkit-progress-value{background:linear-gradient(90deg,#0d6efd,#6ea8fe); border-radius:.75rem}
#bar::-moz-progress-bar{background:linear-gradient(90deg,#0d6efd,#6ea8fe); border-radius:.75rem}
/* 上传按钮动效(保持 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);
}
</style>
</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>
<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">
<h1 class="section-title h4"><i class="bi bi-cpu"></i> 训练配置</h1>
<div class="hint">选择训练/测试数据并设置模型参数</div>
</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 class="mb-4">
<div class="row g-3">
<div class="col-12 col-lg-6">
<label class="form-label fw-semibold"><i class="bi bi-folder2-open me-1"></i>选择训练文件</label>
<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>
<br>
<div>
<button id="uploadBtn" class="btn btn-success">Upload</button>
<progress id="bar" max="100" value="0" style="width:300px;"></progress>
</div>
<div class="col-12 col-lg-6">
<label class="form-label fw-semibold"><i class="bi bi-folder2 me-1"></i>选择测试文件</label>
<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>
</div>
</div>
</div>
<hr class="my-4">
<!-- 参数区(仅美化,不改 id -->
<div class="row g-3">
<div class="col-12 col-lg-8">
<div class="row g-3">
<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>
</div>
<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>
<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>
<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>
</div>
</div>
</div>
<!-- 右侧提示(可删,不影响逻辑) -->
<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>
</div>
<div class="hint">
• 名称用于区分训练产物(日志/权重)。<br>
• filter 用于匹配文件名,如 <code>*_img.png</code><code>*_masks.png</code><br>
• 选择合适的预训练模型可加速收敛。
</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>
<span class="hint" id="barText"></span><!-- 如需 JS 写入文字可用;不用也不影响 -->
</div>
<progress id="bar" max="100" value="0"></progress>
</div>
</div>
</div>
<br><br><br>
</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>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>