fix:批量修复了一些问题
This commit is contained in:
@@ -0,0 +1,113 @@
|
||||
"""极简基线预测:主客场场均进球估计(不调用 LLM,不产生费用)。
|
||||
|
||||
用于与 LLM 预测做 eval 对比。这是最简单的统计基线,仅供研究参考,
|
||||
文档与 reasoning 均明确标注「非投注建议」。
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from datetime import datetime
|
||||
|
||||
from sqlalchemy import case, func, select
|
||||
|
||||
from src.db.base import AsyncSession, AsyncSessionLocal
|
||||
from src.db.models import Match
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def _avg_goals(
|
||||
db: AsyncSession,
|
||||
*,
|
||||
team_id: int,
|
||||
side: str,
|
||||
league_id: int,
|
||||
before: datetime | None,
|
||||
) -> float:
|
||||
"""某队在该联赛已完赛场次的场均进球(side=home/away)。"""
|
||||
if side == "home":
|
||||
goals_col = Match.home_goals
|
||||
team_col = Match.home_team_id
|
||||
else:
|
||||
goals_col = Match.away_goals
|
||||
team_col = Match.away_team_id
|
||||
|
||||
stmt = (
|
||||
select(func.avg(goals_col).label("avg_goals"), func.count().label("cnt"))
|
||||
.where(
|
||||
Match.match_status == "finished",
|
||||
team_col == team_id,
|
||||
Match.league_id == league_id,
|
||||
goals_col.is_not(None),
|
||||
)
|
||||
)
|
||||
if before is not None:
|
||||
stmt = stmt.where(Match.match_date < before)
|
||||
row = (await db.execute(stmt)).one()
|
||||
return float(row.avg_goals) if row.avg_goals is not None and row.cnt > 0 else 0.0
|
||||
|
||||
|
||||
async def predict_baseline(
|
||||
match_id: int,
|
||||
*,
|
||||
backtest: bool = False,
|
||||
cutoff_at: datetime | None = None,
|
||||
) -> dict:
|
||||
"""极简基线预测:主场场均进球 vs 客场场均进球。
|
||||
|
||||
返回与 PredictResult 兼容的字典:
|
||||
provider=model="baseline", 不调用 LLM,latency_ms≈0。
|
||||
"""
|
||||
async with AsyncSessionLocal() as db:
|
||||
match = await db.get(Match, match_id)
|
||||
if match is None:
|
||||
raise ValueError(f"match {match_id} not found")
|
||||
|
||||
before = None
|
||||
if backtest and match.match_dt:
|
||||
from datetime import timedelta
|
||||
|
||||
before = match.match_dt - timedelta(days=1)
|
||||
elif cutoff_at is not None:
|
||||
before = cutoff_at
|
||||
|
||||
home_avg = await _avg_goals(
|
||||
db, team_id=match.home_team_id, side="home",
|
||||
league_id=match.league_id, before=before,
|
||||
)
|
||||
away_avg = await _avg_goals(
|
||||
db, team_id=match.away_team_id, side="away",
|
||||
league_id=match.league_id, before=before,
|
||||
)
|
||||
|
||||
pred_home = max(0, min(10, round(home_avg)))
|
||||
pred_away = max(0, min(10, round(away_avg)))
|
||||
# 主场轻微加成(可选,这里保持极简不额外加权)
|
||||
if pred_home > pred_away:
|
||||
pred_1x2 = "1"
|
||||
elif pred_home < pred_away:
|
||||
pred_1x2 = "2"
|
||||
else:
|
||||
pred_1x2 = "X"
|
||||
|
||||
return {
|
||||
"pred_home_goals": float(pred_home),
|
||||
"pred_away_goals": float(pred_away),
|
||||
"alt_pred_home_goals": None,
|
||||
"alt_pred_away_goals": None,
|
||||
"pred_1x2": pred_1x2,
|
||||
"subjective_confidence": 0.5,
|
||||
"prompt_tokens": 0,
|
||||
"completion_tokens": 0,
|
||||
"reasoning": (
|
||||
f"基线估计(非投注建议): 主队主场场均进球 {home_avg:.2f} → 预测 {pred_home}; "
|
||||
f"客队客场场均进球 {away_avg:.2f} → 预测 {pred_away}。"
|
||||
),
|
||||
"provider": "baseline",
|
||||
"model": "baseline",
|
||||
"prompt_version": "baseline_v1",
|
||||
"mode": "baseline",
|
||||
"status": "success",
|
||||
"latency_ms": 0,
|
||||
"raw": {"home_avg": round(home_avg, 2), "away_avg": round(away_avg, 2)},
|
||||
}
|
||||
Reference in New Issue
Block a user