import { computed, ref } from 'vue' import { useHeadsStore } from '../stores/heads.js' import { toast } from '../utils/toast.js' // Shared "(re)train the concept heads" behaviour (#114): trigger + poll status, // with toasts on start/finish. Backs both the Settings card and the Explore // view's inline button so the active retrain works the same everywhere. // Call start() on mount and stop() on unmount to manage the poll timer. export function useHeadTraining() { const store = useHeadsStore() const summary = ref(null) const busy = ref(false) // the trigger POST is in flight let timer = null const running = computed(() => summary.value?.running_id != null) const headCount = computed(() => summary.value?.head_count ?? 0) async function refresh() { try { summary.value = await store.status() } catch { /* non-fatal — the button still offers a fresh train */ } } function startPoll() { stopPoll() timer = setInterval(async () => { const wasRunning = running.value await refresh() // Announce completion once, on the running → done transition. if (wasRunning && !running.value) { toast({ text: `Heads retrained — ${headCount.value} concept${headCount.value === 1 ? '' : 's'}`, type: 'success', }) } if (!running.value) stopPoll() }, 5000) } function stopPoll() { if (timer) { clearInterval(timer); timer = null } } // Reflect an already-running run (e.g. the nightly one) on mount. async function start() { await refresh() if (running.value) startPoll() } async function train() { busy.value = true try { await store.train() toast({ text: 'Head training started…', type: 'info' }) await refresh() startPoll() } catch (e) { const msg = e.body?.running_id ? 'Training is already running.' : e.message toast({ text: `Could not start training: ${msg}`, type: 'error' }) } finally { busy.value = false } } return { summary, running, busy, headCount, refresh, train, start, stop: stopPoll } }