Add AI-powered image tagging via local LLM

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>
This commit is contained in:
Garret Patti
2026-04-12 15:18:03 -04:00
parent 9bff0f848a
commit 0238dbda7a
9 changed files with 708 additions and 0 deletions

View File

@@ -102,6 +102,7 @@ function initDb(db: Database.Database): void {
migrateMediaItemsSchema(db)
migrateMediaItemsFingerprint(db)
migrateMediaTagsToItemKey(db)
migrateMediaItemsAiTagged(db)
seedAppSettings(db)
}
@@ -110,6 +111,9 @@ function seedAppSettings(db: Database.Database): void {
scan_schedule: '0 * * * *',
scan_enabled: 'true',
scan_last_ran: '',
ai_enabled: 'false',
ai_endpoint: '',
ai_model: '',
}
const insert = db.prepare(
'INSERT OR IGNORE INTO app_settings (key, value) VALUES (?, ?)'
@@ -228,6 +232,15 @@ function migrateMediaTagsToItemKey(db: Database.Database): void {
`)
}
function migrateMediaItemsAiTagged(db: Database.Database): void {
const row = db
.prepare("SELECT sql FROM sqlite_master WHERE type='table' AND name='media_items'")
.get() as { sql: string } | undefined
if (row && !row.sql.includes('ai_tagged_at')) {
db.exec('ALTER TABLE media_items ADD COLUMN ai_tagged_at INTEGER')
}
}
function migrateLibrariesType(db: Database.Database): void {
const row = db
.prepare("SELECT sql FROM sqlite_master WHERE type='table' AND name='libraries'")