Adds automatic image tagging that runs as a post-scan phase, sending thumbnails to an OpenAI-compatible vision API and applying matching tags from the user-defined tag vocabulary. - New ai-tagger module with batch processing, failure tolerance, and tag validation against existing vocabulary - Admin settings page (Manage > AI Tagging) for endpoint, model, and enable toggle with connection testing - DB migration for ai_tagged_at tracking column and AI config seeds - Re-tag All support to queue items for reprocessing Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
60 lines
1.8 KiB
TypeScript
60 lines
1.8 KiB
TypeScript
import { getDb } from './db'
|
|
|
|
interface ScanConfig {
|
|
schedule: string
|
|
enabled: boolean
|
|
lastScanAt: number | null
|
|
}
|
|
|
|
function getSetting(key: string): string | null {
|
|
const db = getDb()
|
|
const row = db
|
|
.prepare('SELECT value FROM app_settings WHERE key = ?')
|
|
.get(key) as { value: string } | undefined
|
|
return row?.value ?? null
|
|
}
|
|
|
|
function setSetting(key: string, value: string): void {
|
|
const db = getDb()
|
|
db.prepare('INSERT OR REPLACE INTO app_settings (key, value) VALUES (?, ?)').run(key, value)
|
|
}
|
|
|
|
export function getScanConfig(): ScanConfig {
|
|
const schedule = getSetting('scan_schedule') ?? '0 * * * *'
|
|
const enabled = getSetting('scan_enabled') !== 'false'
|
|
const lastRanRaw = getSetting('scan_last_ran')
|
|
const lastScanAt =
|
|
lastRanRaw && lastRanRaw.length > 0 ? parseInt(lastRanRaw, 10) : null
|
|
return { schedule, enabled, lastScanAt }
|
|
}
|
|
|
|
export function updateScanConfig(schedule: string, enabled: boolean): void {
|
|
setSetting('scan_schedule', schedule)
|
|
setSetting('scan_enabled', enabled ? 'true' : 'false')
|
|
}
|
|
|
|
export function setScanLastRan(ts: number): void {
|
|
setSetting('scan_last_ran', String(ts))
|
|
}
|
|
|
|
// ─── AI Settings ─────────────────────────────────────────────────────────────
|
|
|
|
interface AiConfig {
|
|
endpoint: string
|
|
model: string
|
|
enabled: boolean
|
|
}
|
|
|
|
export function getAiConfig(): AiConfig {
|
|
const endpoint = getSetting('ai_endpoint') ?? ''
|
|
const model = getSetting('ai_model') ?? ''
|
|
const enabled = getSetting('ai_enabled') === 'true'
|
|
return { endpoint, model, enabled }
|
|
}
|
|
|
|
export function updateAiConfig(endpoint: string, model: string, enabled: boolean): void {
|
|
setSetting('ai_endpoint', endpoint)
|
|
setSetting('ai_model', model)
|
|
setSetting('ai_enabled', enabled ? 'true' : 'false')
|
|
}
|