feat(avocet): add cancel buttons for benchmark and fine-tune runs
This commit is contained in:
parent
8e016d7fe6
commit
1fa5b9e2b0
1 changed files with 55 additions and 4 deletions
|
|
@ -14,6 +14,13 @@
|
||||||
>
|
>
|
||||||
{{ running ? '⏳ Running…' : results ? '🔄 Re-run' : '▶ Run Benchmark' }}
|
{{ running ? '⏳ Running…' : results ? '🔄 Re-run' : '▶ Run Benchmark' }}
|
||||||
</button>
|
</button>
|
||||||
|
<button
|
||||||
|
v-if="running"
|
||||||
|
class="btn-cancel"
|
||||||
|
@click="cancelBenchmark"
|
||||||
|
>
|
||||||
|
✕ Cancel
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
|
|
@ -36,8 +43,8 @@
|
||||||
<!-- Progress log -->
|
<!-- Progress log -->
|
||||||
<div v-if="running || runLog.length" class="run-log">
|
<div v-if="running || runLog.length" class="run-log">
|
||||||
<div class="run-log-title">
|
<div class="run-log-title">
|
||||||
<span>{{ running ? '⏳ Running benchmark…' : runError ? '❌ Failed' : '✅ Done' }}</span>
|
<span>{{ running ? '⏳ Running benchmark…' : runCancelled ? '⏹ Cancelled' : runError ? '❌ Failed' : '✅ Done' }}</span>
|
||||||
<button class="btn-ghost" @click="runLog = []; runError = ''">Clear</button>
|
<button class="btn-ghost" @click="runLog = []; runError = ''; runCancelled = false">Clear</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="log-lines" ref="logEl">
|
<div class="log-lines" ref="logEl">
|
||||||
<div
|
<div
|
||||||
|
|
@ -169,12 +176,19 @@
|
||||||
>
|
>
|
||||||
{{ ftRunning ? '⏳ Training…' : '▶ Run fine-tune' }}
|
{{ ftRunning ? '⏳ Training…' : '▶ Run fine-tune' }}
|
||||||
</button>
|
</button>
|
||||||
|
<button
|
||||||
|
v-if="ftRunning"
|
||||||
|
class="btn-cancel"
|
||||||
|
@click="cancelFinetune"
|
||||||
|
>
|
||||||
|
✕ Cancel
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="ftRunning || ftLog.length || ftError" class="run-log ft-log">
|
<div v-if="ftRunning || ftLog.length || ftError" class="run-log ft-log">
|
||||||
<div class="run-log-title">
|
<div class="run-log-title">
|
||||||
<span>{{ ftRunning ? '⏳ Training…' : ftError ? '❌ Failed' : '✅ Done' }}</span>
|
<span>{{ ftRunning ? '⏳ Training…' : ftCancelled ? '⏹ Cancelled' : ftError ? '❌ Failed' : '✅ Done' }}</span>
|
||||||
<button class="btn-ghost" @click="ftLog = []; ftError = ''">Clear</button>
|
<button class="btn-ghost" @click="ftLog = []; ftError = ''; ftCancelled = false">Clear</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="log-lines" ref="ftLogEl">
|
<div class="log-lines" ref="ftLogEl">
|
||||||
<div
|
<div
|
||||||
|
|
@ -249,6 +263,17 @@ const ftLog = ref<string[]>([])
|
||||||
const ftError = ref('')
|
const ftError = ref('')
|
||||||
const ftLogEl = ref<HTMLElement | null>(null)
|
const ftLogEl = ref<HTMLElement | null>(null)
|
||||||
|
|
||||||
|
const runCancelled = ref(false)
|
||||||
|
const ftCancelled = ref(false)
|
||||||
|
|
||||||
|
async function cancelBenchmark() {
|
||||||
|
await fetch('/api/benchmark/cancel', { method: 'POST' }).catch(() => {})
|
||||||
|
}
|
||||||
|
|
||||||
|
async function cancelFinetune() {
|
||||||
|
await fetch('/api/finetune/cancel', { method: 'POST' }).catch(() => {})
|
||||||
|
}
|
||||||
|
|
||||||
// ── Derived ──────────────────────────────────────────────────────────────────
|
// ── Derived ──────────────────────────────────────────────────────────────────
|
||||||
const modelNames = computed(() => Object.keys(results.value?.models ?? {}))
|
const modelNames = computed(() => Object.keys(results.value?.models ?? {}))
|
||||||
const modelCount = computed(() => modelNames.value.length)
|
const modelCount = computed(() => modelNames.value.length)
|
||||||
|
|
@ -328,6 +353,7 @@ function startBenchmark() {
|
||||||
running.value = true
|
running.value = true
|
||||||
runLog.value = []
|
runLog.value = []
|
||||||
runError.value = ''
|
runError.value = ''
|
||||||
|
runCancelled.value = false
|
||||||
|
|
||||||
const url = `/api/benchmark/run${includeSlow.value ? '?include_slow=true' : ''}`
|
const url = `/api/benchmark/run${includeSlow.value ? '?include_slow=true' : ''}`
|
||||||
useApiSSE(
|
useApiSSE(
|
||||||
|
|
@ -341,6 +367,10 @@ function startBenchmark() {
|
||||||
if (event.type === 'error' && typeof event.message === 'string') {
|
if (event.type === 'error' && typeof event.message === 'string') {
|
||||||
runError.value = event.message
|
runError.value = event.message
|
||||||
}
|
}
|
||||||
|
if (event.type === 'cancelled') {
|
||||||
|
running.value = false
|
||||||
|
runCancelled.value = true
|
||||||
|
}
|
||||||
},
|
},
|
||||||
async () => {
|
async () => {
|
||||||
running.value = false
|
running.value = false
|
||||||
|
|
@ -363,6 +393,7 @@ function startFinetune() {
|
||||||
ftRunning.value = true
|
ftRunning.value = true
|
||||||
ftLog.value = []
|
ftLog.value = []
|
||||||
ftError.value = ''
|
ftError.value = ''
|
||||||
|
ftCancelled.value = false
|
||||||
|
|
||||||
const params = new URLSearchParams({ model: ftModel.value, epochs: String(ftEpochs.value) })
|
const params = new URLSearchParams({ model: ftModel.value, epochs: String(ftEpochs.value) })
|
||||||
useApiSSE(
|
useApiSSE(
|
||||||
|
|
@ -376,6 +407,10 @@ function startFinetune() {
|
||||||
if (event.type === 'error' && typeof event.message === 'string') {
|
if (event.type === 'error' && typeof event.message === 'string') {
|
||||||
ftError.value = event.message
|
ftError.value = event.message
|
||||||
}
|
}
|
||||||
|
if (event.type === 'cancelled') {
|
||||||
|
ftRunning.value = false
|
||||||
|
ftCancelled.value = true
|
||||||
|
}
|
||||||
},
|
},
|
||||||
async () => {
|
async () => {
|
||||||
ftRunning.value = false
|
ftRunning.value = false
|
||||||
|
|
@ -453,6 +488,22 @@ onMounted(() => {
|
||||||
.btn-run:disabled { opacity: 0.5; cursor: not-allowed; }
|
.btn-run:disabled { opacity: 0.5; cursor: not-allowed; }
|
||||||
.btn-run:not(:disabled):hover { opacity: 0.85; }
|
.btn-run:not(:disabled):hover { opacity: 0.85; }
|
||||||
|
|
||||||
|
.btn-cancel {
|
||||||
|
padding: 0.45rem 0.9rem;
|
||||||
|
background: transparent;
|
||||||
|
border: 1px solid var(--color-text-secondary, #6b7a99);
|
||||||
|
color: var(--color-text-secondary, #6b7a99);
|
||||||
|
border-radius: 0.4rem;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
font-weight: 500;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background 0.15s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-cancel:hover {
|
||||||
|
background: color-mix(in srgb, var(--color-text-secondary, #6b7a99) 12%, transparent);
|
||||||
|
}
|
||||||
|
|
||||||
/* ── Run log ────────────────────────────────────────────── */
|
/* ── Run log ────────────────────────────────────────────── */
|
||||||
.run-log {
|
.run-log {
|
||||||
border: 1px solid var(--color-border, #d0d7e8);
|
border: 1px solid var(--color-border, #d0d7e8);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue