"""Celery tasks for achievements.""" import asyncio from datetime import datetime from sqlalchemy import select from app.core.celery_app import celery_app from app.core.logging import get_logger from app.db.database import _get_session_factory from app.db.models import Story, StoryUniverse from app.services.achievement_extractor import extract_achievements logger = get_logger(__name__) @celery_app.task def extract_story_achievements(story_id: int, universe_id: str) -> None: """Extract achievements and update universe.""" asyncio.run(_extract_story_achievements(story_id, universe_id)) async def _extract_story_achievements(story_id: int, universe_id: str) -> None: session_factory = _get_session_factory() async with session_factory() as session: result = await session.execute(select(Story).where(Story.id == story_id)) story = result.scalar_one_or_none() if not story: logger.warning("achievement_task_story_missing", story_id=story_id) return result = await session.execute( select(StoryUniverse).where(StoryUniverse.id == universe_id) ) universe = result.scalar_one_or_none() if not universe: logger.warning("achievement_task_universe_missing", universe_id=universe_id) return text_content = story.story_text if not text_content and story.pages: # 如果是绘本,拼接每页文本 text_content = "\n".join([str(p.get("text", "")) for p in story.pages]) if not text_content: logger.warning("achievement_task_empty_content", story_id=story_id) return achievements = await extract_achievements(text_content) if not achievements: logger.info("achievement_task_no_new", story_id=story_id) return existing = { (str(item.get("type", "")).strip(), str(item.get("description", "")).strip()) for item in (universe.achievements or []) if isinstance(item, dict) } merged = list(universe.achievements or []) added_count = 0 for item in achievements: key = (item.get("type", "").strip(), item.get("description", "").strip()) if key in existing: continue merged.append({ "type": key[0], "description": key[1], "obtained_at": datetime.now().isoformat(), "source_story_id": story_id, }) existing.add(key) added_count += 1 universe.achievements = merged await session.commit() logger.info( "achievement_task_success", story_id=story_id, universe_id=universe_id, added=added_count, )