Files
FabledCurator/frontend/src/stores/import.js
T
bvandeusen 571938781a
CI / lint (push) Failing after 2s
CI / frontend-build (push) Successful in 19s
CI / backend-lint-and-test (push) Successful in 34s
CI / integration (push) Failing after 3m50s
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>
2026-07-12 12:12:19 -04:00

66 lines
2.2 KiB
JavaScript

import { defineStore } from 'pinia'
import { toast } from '../utils/toast.js'
import { ref } from 'vue'
import { useApi } from '../composables/useApi.js'
// Import SETTINGS only. The manual-scan trigger + task-list surfaces retired
// with the Import tab (2026-07-02): imports arrive via downloads/extension and
// heal themselves (Layer-2 auto-refetch sweep); their runs show in Activity.
// The /api/import/trigger + /tasks endpoints remain for direct/API use.
// Consumers: ImportFiltersForm (Maintenance → Ingestion & filters) and the
// Subscriptions Settings tab (downloader/extdl/schedule fields on the same
// ImportSettings row).
export const useImportStore = defineStore('import', () => {
const api = useApi()
const settings = ref(null)
const settingsLoading = ref(false)
const settingsError = ref(null)
const wipScanBusy = ref(false)
async function loadSettings() {
settingsLoading.value = true
settingsError.value = null
try {
settings.value = await api.get('/api/settings/import')
} catch (e) {
settingsError.value = e.message
} finally {
settingsLoading.value = false
}
}
async function patchSettings(patch) {
settingsError.value = null
try {
settings.value = await api.patch('/api/settings/import', { body: patch })
} catch (e) {
settingsError.value = e.message
toast({ text: `Settings save failed: ${e.message}`, type: 'error' })
throw e
}
}
// 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, wipScanBusy,
loadSettings, patchSettings, scanWipTitles,
}
})