From 464145a23460d6cc9d3eb781ac92cf560647e33b Mon Sep 17 00:00:00 2001 From: hbyang Date: Thu, 11 Jun 2026 11:55:50 +0900 Subject: [PATCH] =?UTF-8?q?feat(ai):=20=EC=A0=84=EC=B2=B4=20AI=20=EC=98=88?= =?UTF-8?q?=EC=B8=A1=20=EC=9E=AC=EC=83=9D=EC=84=B1=20=EC=8A=A4=ED=81=AC?= =?UTF-8?q?=EB=A6=BD=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 워커의 generate_ai_predictions() 를 즉시 1회 실행하는 수동 트리거. 미종료 경기 전부에 대해 GPT/Claude/Gemini 재생성(덮어쓰기). 실행: docker compose run --rm worker python -m app.regenerate_ai Co-Authored-By: Claude Opus 4.8 (1M context) --- backend/app/regenerate_ai.py | 57 ++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 backend/app/regenerate_ai.py 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())