feat: M3 — automatic channel tagging (language + topic system tags)

- Tag and ChannelTag models + migration 0003 (partial unique indexes split
  system vs per-user tag names)
- Offline language detection (py3langid) constrained to a curated language set,
  with the channel's declared default language as a strong prior
- Topic tags mapped from YouTube topicDetails + dominant video category; the
  generic "Lifestyle" catch-all is intentionally dropped
- System (auto) tags are regenerated idempotently and never touch user tags;
  orphaned system tags are cleaned up
- GET /api/tags and admin POST /api/tags/recompute; scheduled autotag job
This commit is contained in:
npeter83 2026-06-11 01:57:19 +02:00
parent 64b18b3cc1
commit 68dad91e8a
9 changed files with 482 additions and 1 deletions

View file

@ -6,6 +6,7 @@ from apscheduler.schedulers.background import BackgroundScheduler
from app.config import settings
from app.db import SessionLocal
from app.sync.autotag import run_autotag_all
from app.sync.runner import (
run_deep_backfill,
run_enrich,
@ -48,6 +49,10 @@ def _backfill_job() -> None:
_job("backfill", work)
def _autotag_job() -> None:
_job("autotag", lambda db: run_autotag_all(db, only_missing=True))
def start_scheduler() -> None:
global _scheduler
if not settings.scheduler_enabled or _scheduler is not None:
@ -65,6 +70,12 @@ def start_scheduler() -> None:
minutes=settings.backfill_interval_minutes,
id="backfill",
)
scheduler.add_job(
_autotag_job,
"interval",
minutes=settings.autotag_interval_minutes,
id="autotag",
)
scheduler.start()
_scheduler = scheduler
logger.info("scheduler started")