From 963092384fcc1b05ff454e061ab2d0d9451f3a45 Mon Sep 17 00:00:00 2001 From: wshy Date: Tue, 14 Jul 2026 22:27:03 +0800 Subject: [PATCH] =?UTF-8?q?fix(capabilities):=20=E8=87=AA=E5=AE=9A?= =?UTF-8?q?=E4=B9=89=E5=88=86=E9=92=9F=E6=95=B0=E6=8D=AE=E6=BA=90=E8=A1=A5?= =?UTF-8?q?=20KLINE=5FMINUTE=5FBATCH=20=E8=83=BD=E5=8A=9B=20(#126)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit issue #121: 用户配了自定义分钟数据源, 但分时图/自动同步/回测等功能 仍提示"需 Pro+"。根因: 能力探测(detect_capabilities)只探测 TickFlow API Key 档位, 不感知用户本地配的自定义数据源。 修复: - capabilities.py: CapabilitySet 加 grant() 方法 (不覆盖已有能力) - policy.py: detect_capabilities 拆成 _detect_tickflow_caps (原逻辑不动) + _augment_custom_sources (探测完检查自定义分钟源, 有的话补能力) 补能力后所有 capset.has(KLINE_MINUTE_BATCH) 检查自动通过; 取数函数 内部仍按 preferences.get_minute_data_provider() 分流到自定义源, 不会错误调用 TickFlow。前端读后端返回的 capabilities, 无需改动。 Co-authored-by: shy3130 --- backend/app/tickflow/capabilities.py | 6 ++++++ backend/app/tickflow/policy.py | 29 +++++++++++++++++++++++++++- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/backend/app/tickflow/capabilities.py b/backend/app/tickflow/capabilities.py index 633cd46..60bae72 100644 --- a/backend/app/tickflow/capabilities.py +++ b/backend/app/tickflow/capabilities.py @@ -56,6 +56,12 @@ class CapabilitySet: def all(self) -> dict[Cap, CapabilityLimits]: return dict(self._caps) + def grant(self, cap: Cap, limits: CapabilityLimits | None = None) -> None: + """补授一个能力 (不覆盖已有)。用于自定义数据源: 用户配了自定义分钟源时, + 即使无 TickFlow Pro+ 也补上 KLINE_MINUTE_BATCH, 使所有 capset.has() 检查通过。""" + if cap not in self._caps: + self._caps[cap] = limits or CapabilityLimits() + def to_dict(self) -> dict[str, dict]: return { str(cap): { diff --git a/backend/app/tickflow/policy.py b/backend/app/tickflow/policy.py index e7a7acb..1974bfb 100644 --- a/backend/app/tickflow/policy.py +++ b/backend/app/tickflow/policy.py @@ -285,7 +285,34 @@ def _load_cached_capset(cache_path: Path) -> CapabilitySet | None: def detect_capabilities(force: bool = False) -> CapabilitySet: - """探测当前 API Key 的能力集。""" + """探测当前可用的能力集 (TickFlow API Key 档位 + 自定义数据源)。 + + 自定义数据源补能力: 用户配了自定义分钟数据源时, 即使无 TickFlow Pro+ + 也补上 KLINE_MINUTE_BATCH, 使分时图/自动同步/回测等功能不再被权限门拦。 + 取数函数内部会按 preferences.get_minute_data_provider() 分流到自定义源, + 不会错误调用 TickFlow。 + """ + capset = _detect_tickflow_caps(force) + _augment_custom_sources(capset) + return capset + + +def _augment_custom_sources(capset: CapabilitySet) -> None: + """根据用户配置的自定义数据源, 补充对应能力 (不覆盖 TickFlow 已有的)。""" + try: + from app.services import preferences + provider = preferences.get_minute_data_provider() + if provider != "tickflow": + from app.data_providers import custom as custom_sources + if custom_sources.provider_has_dataset(provider, "minute"): + capset.grant(Cap.KLINE_MINUTE_BATCH) + logger.info("custom minute source '%s' detected: granted KLINE_MINUTE_BATCH", provider) + except Exception as e: # noqa: BLE001 + logger.debug("custom source augment skipped: %s", e) + + +def _detect_tickflow_caps(force: bool = False) -> CapabilitySet: + """探测 TickFlow API Key 的能力集 (不含自定义数据源补能力)。""" cache_path = settings.data_dir / _CAPSET_CACHE_FILE if not force and cache_path.exists(): with cache_path.open(encoding="utf-8") as f: