feat: auto-avatar integration with TheAudioDB
- Added avatar_url, avatar_source, avatar_fetched_at columns to Creator
model with Alembic migration 014
- New backend/services/avatar.py — TheAudioDB lookup with token-based
name similarity scoring and genre overlap bonus
- New Celery task fetch_creator_avatar for background avatar fetching
- Admin endpoints: POST /creators/{id}/fetch-avatar (single) and
POST /creators/fetch-all-avatars (batch for missing avatars)
- Wired avatar_url into CreatorRead, CreatorInfo, and CreatorBrowseItem
schemas so all API responses include avatar data
This commit is contained in:
parent
89ef2751fa
commit
44e5905bd7
2 changed files with 44 additions and 0 deletions
|
|
@ -1306,6 +1306,48 @@ async def reindex_all(
|
|||
}
|
||||
|
||||
|
||||
# ── Admin: Avatar fetching ───────────────────────────────────────────────────
|
||||
|
||||
@router.post("/admin/pipeline/creators/{creator_id}/fetch-avatar")
|
||||
async def fetch_creator_avatar(
|
||||
creator_id: str,
|
||||
db: AsyncSession = Depends(get_session),
|
||||
):
|
||||
"""Trigger avatar lookup from TheAudioDB for a single creator."""
|
||||
from pipeline.stages import fetch_creator_avatar as _task
|
||||
|
||||
creator = (await db.execute(
|
||||
select(Creator).where(Creator.id == creator_id)
|
||||
)).scalar_one_or_none()
|
||||
if not creator:
|
||||
raise HTTPException(status_code=404, detail="Creator not found")
|
||||
|
||||
_task.delay(creator_id)
|
||||
return {"status": "dispatched", "creator": creator.name, "creator_id": creator_id}
|
||||
|
||||
|
||||
@router.post("/admin/pipeline/creators/fetch-all-avatars")
|
||||
async def fetch_all_avatars(
|
||||
db: AsyncSession = Depends(get_session),
|
||||
):
|
||||
"""Trigger avatar lookup for all creators missing avatars."""
|
||||
from pipeline.stages import fetch_creator_avatar as _task
|
||||
|
||||
result = await db.execute(
|
||||
select(Creator.id, Creator.name).where(
|
||||
(Creator.avatar_url.is_(None)) | (Creator.avatar_source == "generated")
|
||||
)
|
||||
)
|
||||
creators = result.all()
|
||||
|
||||
dispatched = 0
|
||||
for cid, name in creators:
|
||||
_task.delay(str(cid))
|
||||
dispatched += 1
|
||||
|
||||
return {"status": "dispatched", "count": dispatched}
|
||||
|
||||
|
||||
# ── Admin: Worker status ─────────────────────────────────────────────────────
|
||||
|
||||
WORKER_STATUS_CACHE_KEY = "chrysopedia:worker_status"
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ class CreatorRead(CreatorBase):
|
|||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
id: uuid.UUID
|
||||
avatar_url: str | None = None
|
||||
view_count: int = 0
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
|
|
@ -288,6 +289,7 @@ class CreatorInfo(BaseModel):
|
|||
name: str
|
||||
slug: str
|
||||
genres: list[str] | None = None
|
||||
avatar_url: str | None = None
|
||||
|
||||
|
||||
class SourceVideoSummary(BaseModel):
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue