3f92669f12
Promotes the prediction store-floor from the TAGGER_STORE_FLOOR env (default 0.05) to a DB-backed, Settings-UI-tunable ml_settings column (default 0.70). Storing every tag down to 0.05 from a ~10k-tag tagger is what grew image_record's TOAST to ~100 GB; the suggestion path already filters at 0.70 and the centroid/learned path covers lower-confidence preferred tags, so the sub-0.70 tail is redundant. Foundation for plan-task #764 (backfill + reclaim land next; this only changes the write gate for NEW imports). - ml_settings.tagger_store_floor (migration 0044, default 0.70) - tagger.Tagger.infer(store_floor=...); ml task passes settings.tagger_store_floor - ML admin GET/PATCH expose it; PATCH rejects a category suggestion threshold below the floor (nothing below the floor is stored, so the gap surfaces nothing) — server backstop for the UI slider clamp - Settings → ML: store-floor slider + caption; category sliders min-bound to it Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
69 lines
2.6 KiB
Vue
69 lines
2.6 KiB
Vue
<template>
|
|
<v-card>
|
|
<v-card-title>Suggestion thresholds</v-card-title>
|
|
<v-card-text v-if="store.settings">
|
|
<v-row v-for="f in fields" :key="f.key">
|
|
<v-col cols="12">
|
|
<v-slider
|
|
v-model="local[f.key]" :label="f.label"
|
|
:min="f.floorMin ? local.tagger_store_floor : 0" max="1" step="0.05"
|
|
thumb-label hide-details
|
|
color="accent" @end="save"
|
|
/>
|
|
</v-col>
|
|
</v-row>
|
|
|
|
<v-divider class="my-4" />
|
|
|
|
<v-row>
|
|
<v-col cols="12">
|
|
<v-slider
|
|
v-model="local.tagger_store_floor" label="Tagger store floor"
|
|
min="0" max="1" step="0.05" thumb-label hide-details
|
|
color="accent" @end="save"
|
|
/>
|
|
<div class="text-caption fc-muted mt-1">
|
|
Tagger predictions below this confidence aren't stored — raising it
|
|
keeps the image library lean. Suggestions can't be shown below the
|
|
floor; lower-confidence tags you actually want still surface through
|
|
the learned centroid path.
|
|
</div>
|
|
</v-col>
|
|
</v-row>
|
|
</v-card-text>
|
|
<v-card-text v-else><v-skeleton-loader type="paragraph" /></v-card-text>
|
|
</v-card>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { toast } from '../../utils/toast.js'
|
|
import { reactive, watch } from 'vue'
|
|
import { useMLStore } from '../../stores/ml.js'
|
|
|
|
const store = useMLStore()
|
|
// 'artist' (FC-2d-vii-c) and 'copyright' (2026-06-01) retired as
|
|
// suggestion categories; their threshold rows are gone.
|
|
// floorMin: the per-category suggestion thresholds can't drop below the
|
|
// tagger store floor (nothing below the floor is stored to surface).
|
|
const fields = [
|
|
{ key: 'suggestion_threshold_character', label: 'Character', floorMin: true },
|
|
{ key: 'suggestion_threshold_general', label: 'General', floorMin: true },
|
|
{ key: 'centroid_similarity_threshold', label: 'Centroid similarity' }
|
|
]
|
|
const local = reactive({})
|
|
watch(() => store.settings, (s) => { if (s) Object.assign(local, s) }, { immediate: true })
|
|
|
|
async function save() {
|
|
// Mirror the server invariant: keep the category thresholds at or above the
|
|
// store floor so a raised floor doesn't leave a threshold stranded below it.
|
|
const floor = local.tagger_store_floor
|
|
local.suggestion_threshold_character = Math.max(local.suggestion_threshold_character, floor)
|
|
local.suggestion_threshold_general = Math.max(local.suggestion_threshold_general, floor)
|
|
const patch = {}
|
|
for (const f of fields) patch[f.key] = local[f.key]
|
|
patch.tagger_store_floor = local.tagger_store_floor
|
|
try { await store.patchSettings(patch) }
|
|
catch (e) { toast({ text: e.message, type: 'error' }) }
|
|
}
|
|
</script>
|