feat(tagging): title-based WIP auto-tagging (#1458)
Auto-apply the `wip` system tag to posts whose TITLE explicitly declares
work-in-progress ("WIP" / "work in progress") — a deterministic, high-precision
complement to the image-based ML `wip` head. WIP images are excluded from the
Explore/gallery browse, so honouring the artist's own label keeps unfinished
pieces out of the main browse.
- services/wip_title.py: precision-first token-anchored matcher (swipe/wiped
never trip it) + sync apply helpers (source='wip_title', ON CONFLICT DO
NOTHING, chunked under the psycopg param ceiling).
- importer: live hook on FRESH import only (never on deep-scan/supersede), so a
manually-removed WIP tag is never re-applied by a routine re-scan.
- maintenance.backfill_wip_title_tags: operator-triggered back-catalogue sweep
(coarse SQL prefilter + regex confirm, keyset-paginated). Deliberately NOT a
beat — a periodic re-run would silently undo manual removals.
- ImportSettings.wip_title_tagging_enabled (default ON, migration 0085) gating
the live hook; GET/PATCH + POST /settings/wip-title/scan.
- Settings UI: toggle + "Scan existing posts" button.
- Tests: pure matcher unit tests + integration (apply idempotency, backfill
precision).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -16,6 +16,7 @@ export const useImportStore = defineStore('import', () => {
|
||||
const settings = ref(null)
|
||||
const settingsLoading = ref(false)
|
||||
const settingsError = ref(null)
|
||||
const wipScanBusy = ref(false)
|
||||
|
||||
async function loadSettings() {
|
||||
settingsLoading.value = true
|
||||
@@ -40,8 +41,25 @@ export const useImportStore = defineStore('import', () => {
|
||||
}
|
||||
}
|
||||
|
||||
// Enqueue the back-catalogue WIP-title scan (task #1458). New imports are
|
||||
// tagged live; this catches posts already in the library. Fire-and-forget —
|
||||
// the sweep runs on the maintenance worker and its run shows in Activity.
|
||||
async function scanWipTitles() {
|
||||
wipScanBusy.value = true
|
||||
try {
|
||||
const r = await api.post('/api/settings/wip-title/scan')
|
||||
toast({ text: 'Scanning existing posts for WIP titles…', type: 'success' })
|
||||
return r
|
||||
} catch (e) {
|
||||
toast({ text: `WIP scan failed: ${e.message}`, type: 'error' })
|
||||
throw e
|
||||
} finally {
|
||||
wipScanBusy.value = false
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
settings, settingsLoading, settingsError,
|
||||
loadSettings, patchSettings,
|
||||
settings, settingsLoading, settingsError, wipScanBusy,
|
||||
loadSettings, patchSettings, scanWipTitles,
|
||||
}
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user