From 7d2eabf750a34d7dd72e8219ec99c5002437c9c1 Mon Sep 17 00:00:00 2001 From: shangfangjian Date: Tue, 22 Sep 2026 01:55:52 +0800 Subject: [PATCH] =?UTF-8?q?chore:=20=E6=AD=BB=E4=BB=A3=E7=A0=81=E4=B8=8E?= =?UTF-8?q?=E9=87=8D=E5=A4=8D=E9=80=BB=E8=BE=91=E6=B8=85=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 删除未引用/未调用符号: - 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 通过,业务行为不变。 --- frontend/src/admin/dal.ts | 7 ------- src/api/schemas.py | 14 -------------- src/core/security_check.py | 4 ---- src/db/base.py | 19 ------------------- src/db/repositories.py | 14 -------------- src/llm/eval.py | 9 +++------ src/llm/predict.py | 14 -------------- src/llm/utils.py | 10 +--------- 8 files changed, 4 insertions(+), 87 deletions(-) diff --git a/frontend/src/admin/dal.ts b/frontend/src/admin/dal.ts index 4aa998a..90cc311 100644 --- a/frontend/src/admin/dal.ts +++ b/frontend/src/admin/dal.ts @@ -370,13 +370,6 @@ export function fetchIngestJob(jobId: string): Promise { return api.get(`${API_BASE}/admin/ingest/jobs/${jobId}`) } -/** - * 最近采集任务列表(最新在前) - */ -export function fetchIngestJobs(limit = 20): Promise { - return api.get(`${API_BASE}/admin/ingest/jobs?limit=${limit}`) -} - /** * 比赛详情(含最近预测摘要) */ diff --git a/src/api/schemas.py b/src/api/schemas.py index b124e28..02035d7 100644 --- a/src/api/schemas.py +++ b/src/api/schemas.py @@ -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 供轮询。""" diff --git a/src/core/security_check.py b/src/core/security_check.py index 4e9ead4..7b4a997 100644 --- a/src/core/security_check.py +++ b/src/core/security_check.py @@ -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(): diff --git a/src/db/base.py b/src/db/base.py index b3f3025..d667e22 100644 --- a/src/db/base.py +++ b/src/db/base.py @@ -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: """验证数据库连接(不建表)。 diff --git a/src/db/repositories.py b/src/db/repositories.py index 576f8d6..5bcf858 100644 --- a/src/db/repositories.py +++ b/src/db/repositories.py @@ -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() diff --git a/src/llm/eval.py b/src/llm/eval.py index 612a6cf..d7daf0d 100644 --- a/src/llm/eval.py +++ b/src/llm/eval.py @@ -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( diff --git a/src/llm/predict.py b/src/llm/predict.py index 7220571..48b739a 100644 --- a/src/llm/predict.py +++ b/src/llm/predict.py @@ -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" diff --git a/src/llm/utils.py b/src/llm/utils.py index 3cbd4cb..e646021 100644 --- a/src/llm/utils.py +++ b/src/llm/utils.py @@ -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