chore: 死代码与重复逻辑清理
删除未引用/未调用符号: - PredictionRepository(无引用) - is_correct_1x2(无调用者) - LeagueOut(路由用 list[dict]) - IngestResponse(IngestBzzoiroResponse 已替代) - SecurityCheckError(从未 raise,assert_security_on_startup 用 sys.exit) - short_write(仅自引用,全仓库无外部调用) - fetchIngestJobs(列表函数无页面使用,单数 fetchIngestJob 仍保留) - clear_prompt_cache(无入口) 去重: - eval._actual_1x2 改为委托 utils.actual_1x2(单一权威源) 全量测试 270 通过,业务行为不变。
This commit is contained in:
@@ -370,13 +370,6 @@ export function fetchIngestJob(jobId: string): Promise<IngestJob> {
|
||||
return api.get<IngestJob>(`${API_BASE}/admin/ingest/jobs/${jobId}`)
|
||||
}
|
||||
|
||||
/**
|
||||
* 最近采集任务列表(最新在前)
|
||||
*/
|
||||
export function fetchIngestJobs(limit = 20): Promise<IngestJob[]> {
|
||||
return api.get<IngestJob[]>(`${API_BASE}/admin/ingest/jobs?limit=${limit}`)
|
||||
}
|
||||
|
||||
/**
|
||||
* 比赛详情(含最近预测摘要)
|
||||
*/
|
||||
|
||||
@@ -7,13 +7,6 @@ from typing import Any
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
class LeagueOut(BaseModel):
|
||||
id: int
|
||||
code: str
|
||||
name: str
|
||||
country: str | None
|
||||
|
||||
|
||||
class MatchOut(BaseModel):
|
||||
id: int
|
||||
league_code: str | None
|
||||
@@ -130,13 +123,6 @@ class TeamAliasOut(BaseModel):
|
||||
original_alias: str
|
||||
|
||||
|
||||
class IngestResponse(BaseModel):
|
||||
leagues: dict
|
||||
total_inserted: int
|
||||
total_updated: int
|
||||
errors: list[str] = []
|
||||
|
||||
|
||||
class IngestBzzoiroResponse(BaseModel):
|
||||
"""POST /api/v1/ingest/bzzoiro 响应:兼容原 message 字段,新增 job_id 供轮询。"""
|
||||
|
||||
|
||||
@@ -30,10 +30,6 @@ _MIN_SECRET_KEY_LEN = 16
|
||||
_WEAK_DB_PATTERNS = ("football:football@", "admin:admin@", "password@", "123456@")
|
||||
|
||||
|
||||
class SecurityCheckError(Exception):
|
||||
"""生产环境安全校验失败。"""
|
||||
|
||||
|
||||
async def _auth_configured() -> bool:
|
||||
"""运行时鉴权是否已配置(含数据库密码哈希/.env 明文/API Key)。"""
|
||||
if await get_admin_password_hash():
|
||||
|
||||
@@ -68,25 +68,6 @@ async def short_read():
|
||||
yield session
|
||||
|
||||
|
||||
@asynccontextmanager
|
||||
async def short_write():
|
||||
"""短生命周期 write session: 提交后立即释放。
|
||||
|
||||
用法:
|
||||
async with short_write() as session:
|
||||
session.add(pred)
|
||||
await session.commit()
|
||||
# session 已关闭,连接已释放
|
||||
"""
|
||||
async with AsyncSessionLocal() as session:
|
||||
try:
|
||||
yield session
|
||||
await session.commit()
|
||||
except Exception:
|
||||
await session.rollback()
|
||||
raise
|
||||
|
||||
|
||||
async def init_db() -> None:
|
||||
"""验证数据库连接(不建表)。
|
||||
|
||||
|
||||
@@ -215,17 +215,3 @@ class LeagueRepository:
|
||||
async def add(self, league: League) -> None:
|
||||
self._session.add(league)
|
||||
await self._session.flush()
|
||||
|
||||
|
||||
class PredictionRepository:
|
||||
"""预测记录数据访问。"""
|
||||
|
||||
def __init__(self, session: AsyncSession) -> None:
|
||||
self._session = session
|
||||
|
||||
async def get_by_id(self, prediction_id: int) -> Prediction | None:
|
||||
return await self._session.get(Prediction, prediction_id)
|
||||
|
||||
async def add(self, prediction: Prediction) -> None:
|
||||
self._session.add(prediction)
|
||||
await self._session.flush()
|
||||
|
||||
+3
-6
@@ -7,6 +7,7 @@ from sqlalchemy import func, or_, select
|
||||
|
||||
from src.db.models import Prediction, Match, League
|
||||
from src.db.unit_of_work import get_uow
|
||||
from src.llm.utils import actual_1x2
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -33,12 +34,8 @@ async def settle_prediction(prediction_id: int, home_goals: int, away_goals: int
|
||||
|
||||
|
||||
def _actual_1x2(home: int, away: int) -> str:
|
||||
"""根据实际比分返胜平负。"""
|
||||
if home > away:
|
||||
return "1"
|
||||
if home == away:
|
||||
return "X"
|
||||
return "2"
|
||||
"""根据实际比分返胜平负(委托 utils.actual_1x2 单一权威源)。"""
|
||||
return actual_1x2(home, away)
|
||||
|
||||
|
||||
def _build_filters(
|
||||
|
||||
@@ -172,20 +172,6 @@ async def _set_cached(match_id: int, provider: str, model: str, version: str, tp
|
||||
await _cache_backend.set(key, result, _CACHE_TTL_SEC)
|
||||
|
||||
|
||||
def clear_prompt_cache() -> None:
|
||||
"""清空 prompt 模板缓存(供开发/热更新时手动调用)。
|
||||
|
||||
lru_cache 的模板缓存是进程级的,改完 .md 需要重启进程才能生效;
|
||||
提供显式清理入口,避免"改了模板却看不到变化"的困惑(见审查报告 P2-5)。
|
||||
同时清空预测响应缓存(内存后端);Redis 后端因共享不清除。
|
||||
"""
|
||||
_load_prompt_template.cache_clear()
|
||||
if isinstance(_cache_backend, _MemoryCache):
|
||||
_cache_backend._store.clear()
|
||||
logger.info("prompt 模板缓存 + 预测响应缓存(内存)已清空")
|
||||
|
||||
|
||||
@functools.lru_cache(maxsize=8)
|
||||
def _load_prompt_template(version: str = "v1") -> str:
|
||||
"""缓存 prompt 模板(进程生命周期内每个版本只读一次)。"""
|
||||
path = _PROMPT_DIR / f"match_prediction_{version}.md"
|
||||
|
||||
+1
-9
@@ -3,17 +3,9 @@ from __future__ import annotations
|
||||
|
||||
|
||||
def actual_1x2(home: int, away: int) -> str:
|
||||
"""实际比分 → 胜平负。
|
||||
|
||||
单一权威源: backtest.py 和 eval.py 共用,避免重复定义。
|
||||
"""
|
||||
"""实际比分 → 胜平负(单一权威源:backtest.py 与 eval.py 共用)。"""
|
||||
if home > away:
|
||||
return "1"
|
||||
if home == away:
|
||||
return "X"
|
||||
return "2"
|
||||
|
||||
|
||||
def is_correct_1x2(pred: str | None, actual: str) -> bool:
|
||||
"""预测是否命中胜平负。"""
|
||||
return pred == actual
|
||||
|
||||
Reference in New Issue
Block a user