diff --git a/backend/app/regenerate_ai.py b/backend/app/regenerate_ai.py new file mode 100644 index 0000000..7f71cfc --- /dev/null +++ b/backend/app/regenerate_ai.py @@ -0,0 +1,57 @@ +"""전체 AI 예측 재생성 — 수동 트리거. + +워커의 generate_ai_predictions() 를 즉시 1회 실행한다(매일 00:05 자동 생성과 동일 로직). +미종료(결과 미입력) 경기 전부에 대해 GPT/Claude/Gemini 를 실 API 호출하여 +ai_predictions 를 덮어쓴다(source='llm'). 키 없는/실패한 모델은 건너뛴다. + +DB 접속은 backend/.env(DB_* 또는 DATABASE_URL)를 따른다. + +실행: + # Docker (운영 DB로 1회 실행) + docker compose run --rm worker python -m app.regenerate_ai + # 로컬 + cd backend && python -m app.regenerate_ai +""" +from __future__ import annotations + +import asyncio +import logging + +from sqlalchemy import func, select + +from .database import SessionLocal, init_db +from .models import AIPrediction, Match +from .worker import generate_ai_predictions + +logging.basicConfig(level=logging.INFO) +log = logging.getLogger("triplepick.regen") + + +async def main() -> None: + await init_db() # 테이블 보장(idempotent) + + async with SessionLocal() as db: + targets = ( + await db.execute( + select(func.count()) + .select_from(Match) + .where(Match.result_outcome.is_(None)) + ) + ).scalar_one() + log.info("재생성 대상(미종료) 경기: %d", targets) + + await generate_ai_predictions() # GPT/Claude/Gemini 실 API 호출 → 덮어쓰기 + + async with SessionLocal() as db: + rows = ( + await db.execute( + select(AIPrediction.model, func.count()) + .where(AIPrediction.source == "llm") + .group_by(AIPrediction.model) + ) + ).all() + log.info("재생성 완료. 모델별 LLM 예측 수: %s", {m: c for m, c in rows}) + + +if __name__ == "__main__": + asyncio.run(main())