chore: initialize git repo, add matplotlib dep, extend config
- Add .gitignore for Python/data/models - Add matplotlib>=3.8.0 for eval plots - Add PretrainConfig, FinetuneConfig, BalabitAdapterConfig, EvalConfig dataclasses
This commit is contained in:
133
static/js/train.js
Normal file
133
static/js/train.js
Normal file
@@ -0,0 +1,133 @@
|
||||
/**
|
||||
* Train tab component — unified training with [鼠标 | 滚轮] sub-tabs.
|
||||
*/
|
||||
|
||||
import { fetchSSE } from './api.js'
|
||||
|
||||
const template = `
|
||||
<div class="view">
|
||||
<div class="sub-tabs">
|
||||
<button class="sub-tab" :class="{active: subTab==='mouse'}" @click="subTab='mouse'">鼠标模型</button>
|
||||
<button class="sub-tab" :class="{active: subTab==='scroll'}" @click="subTab='scroll'">滚轮模型</button>
|
||||
</div>
|
||||
|
||||
<!-- ════════ 鼠标训练 ════════ -->
|
||||
<div v-show="subTab==='mouse'">
|
||||
<div class="form-grid" style="max-width:240px;">
|
||||
<div class="field">
|
||||
<label>训练轮数</label>
|
||||
<input type="number" v-model.number="mouseTrain.epochs" :disabled="mouseTrain.running" min="10" />
|
||||
</div>
|
||||
</div>
|
||||
<button class="btn btn-primary" @click="startMouseTrain" :disabled="mouseTrain.running">
|
||||
{{ mouseTrain.running ? '训练中…' : '开始训练' }}
|
||||
</button>
|
||||
|
||||
<div class="progress-section" v-if="mouseTrain.running || mouseTrain.done">
|
||||
<div class="progress-label">
|
||||
<span>JointCVAE 联合模型</span>
|
||||
<span>{{ mouseTrain.epoch }} / {{ mouseTrain.total }}</span>
|
||||
</div>
|
||||
<div class="progress-track">
|
||||
<div class="progress-fill" :style="{width: mouseTrainPct+'%'}"></div>
|
||||
</div>
|
||||
<div class="loss-display" v-if="mouseTrain.loss !== null">loss = {{ mouseTrain.loss.toFixed(4) }}</div>
|
||||
</div>
|
||||
|
||||
<div v-if="mouseTrain.done" class="msg msg-success">
|
||||
训练完成!点击分布:μ = {{ mouseTrain.mu.toFixed(1) }} ms,σ = {{ mouseTrain.sigma.toFixed(1) }} ms
|
||||
</div>
|
||||
<div v-if="mouseTrain.error" class="msg msg-error">{{ mouseTrain.error }}</div>
|
||||
</div>
|
||||
|
||||
<!-- ════════ 滚轮训练 ════════ -->
|
||||
<div v-show="subTab==='scroll'">
|
||||
<div class="form-grid" style="max-width:240px;">
|
||||
<div class="field">
|
||||
<label>训练轮数</label>
|
||||
<input type="number" v-model.number="scrollTrain.epochs" :disabled="scrollTrain.running" min="10" />
|
||||
</div>
|
||||
</div>
|
||||
<button class="btn btn-primary" @click="startScrollTrain" :disabled="scrollTrain.running">
|
||||
{{ scrollTrain.running ? '训练中…' : '开始训练' }}
|
||||
</button>
|
||||
|
||||
<div class="progress-section" v-if="scrollTrain.running || scrollTrain.done">
|
||||
<div class="progress-label">
|
||||
<span>ScrollCVAE 滚轮模型</span>
|
||||
<span>{{ scrollTrain.epoch }} / {{ scrollTrain.total }}</span>
|
||||
</div>
|
||||
<div class="progress-track">
|
||||
<div class="progress-fill" :style="{width: scrollTrainPct+'%'}"></div>
|
||||
</div>
|
||||
<div class="loss-display" v-if="scrollTrain.loss !== null">loss = {{ scrollTrain.loss.toFixed(4) }}</div>
|
||||
</div>
|
||||
|
||||
<div v-if="scrollTrain.done" class="msg msg-success">滚轮模型训练完成!</div>
|
||||
<div v-if="scrollTrain.error" class="msg msg-error">{{ scrollTrain.error }}</div>
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
|
||||
export const TrainView = {
|
||||
template,
|
||||
emits: ['status-changed'],
|
||||
setup(props, { emit }) {
|
||||
const { ref, reactive, computed } = Vue
|
||||
|
||||
const subTab = ref('mouse')
|
||||
|
||||
// ── 鼠标训练 ──
|
||||
const mouseTrain = reactive({
|
||||
epochs: 100, running: false, done: false,
|
||||
epoch: 0, total: 0, loss: null, mu: 0, sigma: 0, error: '',
|
||||
})
|
||||
|
||||
const mouseTrainPct = computed(() => {
|
||||
if (!mouseTrain.total) return 0
|
||||
return Math.round(mouseTrain.epoch / mouseTrain.total * 100)
|
||||
})
|
||||
|
||||
function startMouseTrain() {
|
||||
mouseTrain.running = true; mouseTrain.done = false; mouseTrain.error = ''
|
||||
mouseTrain.epoch = 0; mouseTrain.total = mouseTrain.epochs; mouseTrain.loss = null
|
||||
|
||||
fetchSSE('/api/train', { epochs: mouseTrain.epochs }, (msg) => {
|
||||
if (msg.error) { mouseTrain.error = msg.error; mouseTrain.running = false; return }
|
||||
if (msg.done) {
|
||||
mouseTrain.mu = msg.mu || 0; mouseTrain.sigma = msg.sigma || 0
|
||||
mouseTrain.running = false; mouseTrain.done = true; emit('status-changed'); return
|
||||
}
|
||||
mouseTrain.epoch = msg.epoch; mouseTrain.total = msg.total; mouseTrain.loss = msg.loss
|
||||
})
|
||||
}
|
||||
|
||||
// ── 滚轮训练 ──
|
||||
const scrollTrain = reactive({
|
||||
epochs: 100, running: false, done: false,
|
||||
epoch: 0, total: 0, loss: null, error: '',
|
||||
})
|
||||
|
||||
const scrollTrainPct = computed(() => {
|
||||
if (!scrollTrain.total) return 0
|
||||
return Math.round(scrollTrain.epoch / scrollTrain.total * 100)
|
||||
})
|
||||
|
||||
function startScrollTrain() {
|
||||
scrollTrain.running = true; scrollTrain.done = false; scrollTrain.error = ''
|
||||
scrollTrain.epoch = 0; scrollTrain.total = scrollTrain.epochs; scrollTrain.loss = null
|
||||
|
||||
fetchSSE('/api/scroll/train', { epochs: scrollTrain.epochs }, (msg) => {
|
||||
if (msg.error) { scrollTrain.error = msg.error; scrollTrain.running = false; return }
|
||||
if (msg.done) { scrollTrain.running = false; scrollTrain.done = true; emit('status-changed'); return }
|
||||
scrollTrain.epoch = msg.epoch; scrollTrain.total = msg.total; scrollTrain.loss = msg.loss
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
subTab, mouseTrain, scrollTrain,
|
||||
mouseTrainPct, scrollTrainPct,
|
||||
startMouseTrain, startScrollTrain,
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user