feat: 足球 LLM 预测服务初始提交

Profeto — 给 LLM 提供数据,让 LLM 预测足球比分。

核心模块:
- FastAPI 后端 + PostgreSQL (SQLAlchemy async)
- 多 Agent LLM 预测 (5 专家 + 终裁)
- 数据采集 (bzzoiro / understat / injuries)
- React 前端 (Vite + Tailwind)

包含:
- 数据源抽象 (DataSource 协议 + 注册表)
- Alembic 数据库迁移
- Prompt 模板 (单/多 Agent)
- 核心路径单元测试
This commit is contained in:
shangfangjian
2026-09-09 02:10:47 +08:00
commit 0a27b18c27
74 changed files with 5667 additions and 0 deletions
+56
View File
@@ -0,0 +1,56 @@
"""采集路由。"""
from __future__ import annotations
from fastapi import APIRouter, HTTPException
from src.api.schemas import IngestBzzoiroRequest, IngestResponse, IngestUnderstatRequest, IngestInjuriesRequest, IngestSimpleResponse
from src.data.sources import get_source
from src.data.injuries import ingest_injuries
from src.db.base import AsyncSessionLocal
router = APIRouter(prefix="/api/v1", tags=["ingest"])
@router.post("/ingest/bzzoiro", response_model=IngestResponse)
async def ingest_bzzoiro_route(req: IngestBzzoiroRequest):
"""触发 bzzoiro 采集。"""
source = get_source("bzzoiro")
async with AsyncSessionLocal() as db:
try:
result = await source.ingest(
db,
leagues=req.leagues,
date_from=req.date_from,
date_to=req.date_to,
status=req.status,
)
await db.commit()
return IngestResponse(**result)
except Exception as e:
await db.rollback()
raise HTTPException(500, str(e))
@router.post("/ingest/understat", response_model=IngestSimpleResponse)
async def ingest_understat_route(req: IngestUnderstatRequest):
"""触发 understat xG 回填。"""
source = get_source("understat")
async with AsyncSessionLocal() as db:
try:
result = await source.ingest(db, league=req.league, season=req.season)
return IngestSimpleResponse(**result)
except Exception as e:
await db.rollback()
raise HTTPException(500, str(e))
@router.post("/ingest/injuries", response_model=IngestSimpleResponse)
async def ingest_injuries_route(req: IngestInjuriesRequest):
"""触发伤停采集。"""
async with AsyncSessionLocal() as db:
try:
result = await ingest_injuries(db, date=req.date)
return IngestSimpleResponse(**result)
except Exception as e:
await db.rollback()
raise HTTPException(500, str(e))