后端深度清理 Polymarket:删除 readonly 层+WS 缓存+market_scan API
删除 src/data_collection/polymarket_readonly.py(2500行)和 polymarket_ws_cache.py。city_payloads 移除 _get_polymarket_layer/_top_probability_bucket/build_city_market_scan_payload。city.py 移除 /market-scan 和 /holders 路由。scan_terminal 移除 skip_polymarket。
This commit is contained in:
@@ -3,7 +3,11 @@
|
|||||||
"allow": [
|
"allow": [
|
||||||
"Bash(npm --prefix \"/e/web/PolyWeather/frontend\" run build)",
|
"Bash(npm --prefix \"/e/web/PolyWeather/frontend\" run build)",
|
||||||
"mcp__Claude_Preview__preview_start",
|
"mcp__Claude_Preview__preview_start",
|
||||||
"Bash(git:*)"
|
"Bash(git:*)",
|
||||||
|
"Bash(python -c \"from web.services.city_payloads import build_city_detail_payload; print\\('OK'\\)\")",
|
||||||
|
"Bash(python -m ruff check web/services/city_runtime.py web/services/city_api.py)",
|
||||||
|
"Bash(python -m ruff check .)",
|
||||||
|
"Bash(python -m pytest tests/ -q)"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+748
-750
File diff suppressed because it is too large
Load Diff
@@ -7,7 +7,6 @@ from fastapi import APIRouter, BackgroundTasks, Query, Request
|
|||||||
from web.services.city_api import (
|
from web.services.city_api import (
|
||||||
get_city_detail_aggregate_payload,
|
get_city_detail_aggregate_payload,
|
||||||
get_city_detail_payload,
|
get_city_detail_payload,
|
||||||
get_city_market_scan_payload,
|
|
||||||
get_city_summary_payload,
|
get_city_summary_payload,
|
||||||
list_cities_payload,
|
list_cities_payload,
|
||||||
)
|
)
|
||||||
@@ -152,65 +151,6 @@ async def city_detail_aggregate(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@router.get("/api/city/{name}/market-scan")
|
|
||||||
async def city_market_scan(
|
|
||||||
request: Request,
|
|
||||||
background_tasks: BackgroundTasks,
|
|
||||||
name: str,
|
|
||||||
force_refresh: bool = False,
|
|
||||||
market_slug: Optional[str] = None,
|
|
||||||
target_date: Optional[str] = None,
|
|
||||||
lite: bool = False,
|
|
||||||
):
|
|
||||||
return await get_city_market_scan_payload(
|
|
||||||
request,
|
|
||||||
background_tasks,
|
|
||||||
name,
|
|
||||||
force_refresh=force_refresh,
|
|
||||||
market_slug=market_slug,
|
|
||||||
target_date=target_date,
|
|
||||||
lite=lite,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@router.get("/api/city/{name}/holders")
|
|
||||||
async def city_holders(
|
|
||||||
name: str,
|
|
||||||
limit: int = 10,
|
|
||||||
):
|
|
||||||
"""Return top token holders for a city's primary Polymarket market."""
|
|
||||||
from web.services.city_payloads import _get_polymarket_layer
|
|
||||||
from web.analysis_service import _analyze
|
|
||||||
|
|
||||||
layer = _get_polymarket_layer()
|
|
||||||
if not layer.enabled:
|
|
||||||
return {"holders": [], "available": False}
|
|
||||||
|
|
||||||
data = _analyze(name, force_refresh=False, include_llm_commentary=False, detail_mode="market")
|
|
||||||
local_date = str(data.get("local_date") or "").strip()
|
|
||||||
if not local_date:
|
|
||||||
return {"holders": [], "available": False}
|
|
||||||
|
|
||||||
scan = layer.build_market_scan(
|
|
||||||
city=name,
|
|
||||||
target_date=local_date,
|
|
||||||
include_related_buckets=False,
|
|
||||||
)
|
|
||||||
if not scan.get("available"):
|
|
||||||
return {"holders": [], "available": False}
|
|
||||||
|
|
||||||
condition_id = scan.get("selected_condition_id")
|
|
||||||
if not condition_id:
|
|
||||||
return {"holders": [], "available": False}
|
|
||||||
|
|
||||||
holders = layer.get_market_holders(condition_id, limit=limit)
|
|
||||||
return {
|
|
||||||
"holders": holders,
|
|
||||||
"available": True,
|
|
||||||
"condition_id": condition_id,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@router.get("/api/city/{name}/realtime-stream")
|
@router.get("/api/city/{name}/realtime-stream")
|
||||||
async def city_realtime_stream(name: str):
|
async def city_realtime_stream(name: str):
|
||||||
"""Return a rolling window of recent temperature readings + market
|
"""Return a rolling window of recent temperature readings + market
|
||||||
|
|||||||
+1
-3
@@ -30,7 +30,6 @@ async def scan_terminal(
|
|||||||
force_refresh: bool = False,
|
force_refresh: bool = False,
|
||||||
region: str = "",
|
region: str = "",
|
||||||
trading_region: str = "",
|
trading_region: str = "",
|
||||||
skip_polymarket: bool = False,
|
|
||||||
timezone_offset_seconds: int | None = None,
|
timezone_offset_seconds: int | None = None,
|
||||||
):
|
):
|
||||||
return await get_scan_terminal_payload(
|
return await get_scan_terminal_payload(
|
||||||
@@ -46,8 +45,7 @@ async def scan_terminal(
|
|||||||
limit=limit,
|
limit=limit,
|
||||||
force_refresh=force_refresh,
|
force_refresh=force_refresh,
|
||||||
region=region or trading_region or None,
|
region=region or trading_region or None,
|
||||||
skip_polymarket=skip_polymarket,
|
timezone_offset_seconds=timezone_offset_seconds,
|
||||||
timezone_offset_seconds=timezone_offset_seconds,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ from datetime import datetime, timedelta
|
|||||||
from typing import Any, Dict, List, Optional
|
from typing import Any, Dict, List, Optional
|
||||||
|
|
||||||
from web.core import CITIES
|
from web.core import CITIES
|
||||||
from web.analysis_service import _analyze, _build_city_market_scan_payload
|
from web.analysis_service import _analyze
|
||||||
from web.scan_city_ai_helpers import _safe_float
|
from web.scan_city_ai_helpers import _safe_float
|
||||||
from web.scan_terminal_ai_compact import _build_metar_decision_context
|
from web.scan_terminal_ai_compact import _build_metar_decision_context
|
||||||
from web.scan_terminal_filters import (
|
from web.scan_terminal_filters import (
|
||||||
@@ -164,14 +164,7 @@ def _scan_city_terminal_rows(
|
|||||||
candidate_total = 0
|
candidate_total = 0
|
||||||
|
|
||||||
for target_date in target_dates:
|
for target_date in target_dates:
|
||||||
payload = _build_city_market_scan_payload(
|
scan = {"available": False}
|
||||||
data,
|
|
||||||
market_slug=None,
|
|
||||||
target_date=target_date,
|
|
||||||
lite=True,
|
|
||||||
scan_filters=filters,
|
|
||||||
)
|
|
||||||
scan = payload.get("market_scan") or {}
|
|
||||||
candidate_total += int(scan.get("candidate_count") or 0)
|
candidate_total += int(scan.get("candidate_count") or 0)
|
||||||
raw_rows = scan.get("scan_rows")
|
raw_rows = scan.get("scan_rows")
|
||||||
if not isinstance(raw_rows, list) or not raw_rows:
|
if not isinstance(raw_rows, list) or not raw_rows:
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ def normalize_scan_terminal_filters(
|
|||||||
or "today",
|
or "today",
|
||||||
"limit": max(1, min(safe_int(raw.get("limit"), 25), 200)),
|
"limit": max(1, min(safe_int(raw.get("limit"), 25), 200)),
|
||||||
"max_spread": max(0.0, _safe_float(raw.get("max_spread")) or 0.03),
|
"max_spread": max(0.0, _safe_float(raw.get("max_spread")) or 0.03),
|
||||||
"skip_polymarket": str(raw.get("skip_polymarket") or "false").lower()
|
|
||||||
in {"1", "true", "yes", "on"},
|
in {"1", "true", "yes", "on"},
|
||||||
}
|
}
|
||||||
trading_region = str(raw.get("trading_region") or "").strip().lower()
|
trading_region = str(raw.get("trading_region") or "").strip().lower()
|
||||||
|
|||||||
@@ -222,10 +222,4 @@ async def get_city_market_scan_payload(
|
|||||||
)
|
)
|
||||||
if cached_scan is not None:
|
if cached_scan is not None:
|
||||||
return cached_scan
|
return cached_scan
|
||||||
return await run_in_threadpool(
|
return {"market_scan": {"available": False}, "selected_date": target_date or str(data.get("local_date", "")), "fetched_at": data.get("updated_at")}
|
||||||
legacy_routes._build_city_market_scan_payload,
|
|
||||||
data,
|
|
||||||
market_slug,
|
|
||||||
target_date,
|
|
||||||
lite,
|
|
||||||
)
|
|
||||||
|
|||||||
@@ -8,27 +8,6 @@ from web.core import _is_excluded_model_name
|
|||||||
|
|
||||||
TURKISH_MGM_CITIES = {"ankara", "istanbul"}
|
TURKISH_MGM_CITIES = {"ankara", "istanbul"}
|
||||||
|
|
||||||
_polymarket_layer = None
|
|
||||||
|
|
||||||
|
|
||||||
def _get_polymarket_layer():
|
|
||||||
global _polymarket_layer
|
|
||||||
if _polymarket_layer is None:
|
|
||||||
from src.data_collection.polymarket_readonly import PolymarketReadOnlyLayer
|
|
||||||
|
|
||||||
_polymarket_layer = PolymarketReadOnlyLayer()
|
|
||||||
return _polymarket_layer
|
|
||||||
|
|
||||||
|
|
||||||
def _top_probability_bucket(distribution: Any) -> Optional[Dict[str, Any]]:
|
|
||||||
if not isinstance(distribution, list):
|
|
||||||
return None
|
|
||||||
candidates = [row for row in distribution if isinstance(row, dict)]
|
|
||||||
if not candidates:
|
|
||||||
return None
|
|
||||||
return max(candidates, key=lambda row: float(row.get("probability") or -1.0))
|
|
||||||
|
|
||||||
|
|
||||||
def build_city_summary_payload(data: Dict[str, Any]) -> Dict[str, Any]:
|
def build_city_summary_payload(data: Dict[str, Any]) -> Dict[str, Any]:
|
||||||
return {
|
return {
|
||||||
"name": data.get("name"),
|
"name": data.get("name"),
|
||||||
@@ -54,66 +33,11 @@ def build_city_summary_payload(data: Dict[str, Any]) -> Dict[str, Any]:
|
|||||||
"updated_at": data.get("updated_at"),
|
"updated_at": data.get("updated_at"),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def build_city_market_scan_payload(
|
|
||||||
data: Dict[str, Any],
|
|
||||||
market_slug: Optional[str] = None,
|
|
||||||
target_date: Optional[str] = None,
|
|
||||||
lite: bool = False,
|
|
||||||
scan_filters: Optional[Dict[str, Any]] = None,
|
|
||||||
) -> Dict[str, Any]:
|
|
||||||
local_date = str(data.get("local_date") or "").strip()
|
|
||||||
requested_date = str(target_date or "").strip()
|
|
||||||
selected_date = requested_date or local_date
|
|
||||||
|
|
||||||
try:
|
|
||||||
layer = _get_polymarket_layer()
|
|
||||||
probabilities = data.get("probabilities") or {}
|
|
||||||
distribution = probabilities.get("distribution") or []
|
|
||||||
top_bucket = _top_probability_bucket(distribution)
|
|
||||||
model_probability = (
|
|
||||||
float(top_bucket.get("probability"))
|
|
||||||
if (isinstance(top_bucket, dict) and top_bucket.get("probability") is not None)
|
|
||||||
else None
|
|
||||||
)
|
|
||||||
|
|
||||||
scan = layer.build_market_scan(
|
|
||||||
city=data.get("name"),
|
|
||||||
target_date=selected_date,
|
|
||||||
temperature_bucket=top_bucket,
|
|
||||||
model_probability=model_probability,
|
|
||||||
probability_distribution=distribution,
|
|
||||||
temp_symbol=str(data.get("temp_symbol") or ""),
|
|
||||||
forced_market_slug=market_slug,
|
|
||||||
include_related_buckets=not lite,
|
|
||||||
scan_filters=scan_filters,
|
|
||||||
)
|
|
||||||
return {
|
|
||||||
"market_scan": scan,
|
|
||||||
"selected_date": selected_date,
|
|
||||||
"fetched_at": data.get("updated_at"),
|
|
||||||
}
|
|
||||||
except Exception:
|
|
||||||
import traceback
|
|
||||||
traceback.print_exc()
|
|
||||||
return {
|
|
||||||
"market_scan": {"available": False},
|
|
||||||
"selected_date": selected_date,
|
|
||||||
"fetched_at": data.get("updated_at"),
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def build_city_detail_payload(
|
def build_city_detail_payload(
|
||||||
data: Dict[str, Any],
|
data: Dict[str, Any],
|
||||||
market_slug: Optional[str] = None,
|
market_slug: Optional[str] = None,
|
||||||
target_date: Optional[str] = None,
|
target_date: Optional[str] = None,
|
||||||
) -> Dict[str, Any]:
|
) -> Dict[str, Any]:
|
||||||
market_payload = build_city_market_scan_payload(
|
|
||||||
data,
|
|
||||||
market_slug=market_slug,
|
|
||||||
target_date=target_date,
|
|
||||||
)
|
|
||||||
market_scan = market_payload.get("market_scan")
|
|
||||||
return {
|
return {
|
||||||
"city": data.get("name"),
|
"city": data.get("name"),
|
||||||
"fetched_at": data.get("updated_at"),
|
"fetched_at": data.get("updated_at"),
|
||||||
@@ -200,7 +124,7 @@ def build_city_detail_payload(
|
|||||||
or _build_intraday_meteorology(data),
|
or _build_intraday_meteorology(data),
|
||||||
"vertical_profile_signal": data.get("vertical_profile_signal") or {},
|
"vertical_profile_signal": data.get("vertical_profile_signal") or {},
|
||||||
"taf": data.get("taf") or {},
|
"taf": data.get("taf") or {},
|
||||||
"market_scan": market_scan,
|
"market_scan": {"available": False},
|
||||||
"risk": data.get("risk"),
|
"risk": data.get("risk"),
|
||||||
"settlement_station": data.get("settlement_station") or {},
|
"settlement_station": data.get("settlement_station") or {},
|
||||||
"airport_primary": data.get("airport_primary") or {},
|
"airport_primary": data.get("airport_primary") or {},
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ from web.analysis_service import (
|
|||||||
_analyze,
|
_analyze,
|
||||||
_analyze_summary,
|
_analyze_summary,
|
||||||
_build_city_detail_payload, # noqa: F401 - compatibility export for tests and transitional routers
|
_build_city_detail_payload, # noqa: F401 - compatibility export for tests and transitional routers
|
||||||
_build_city_market_scan_payload,
|
|
||||||
_build_city_summary_payload,
|
_build_city_summary_payload,
|
||||||
)
|
)
|
||||||
from web.scan_terminal_service import (
|
from web.scan_terminal_service import (
|
||||||
@@ -195,12 +194,7 @@ def _attach_market_scan_payload(
|
|||||||
) -> dict:
|
) -> dict:
|
||||||
if not isinstance(payload, dict):
|
if not isinstance(payload, dict):
|
||||||
return payload
|
return payload
|
||||||
scan_payload = _build_city_market_scan_payload(
|
scan_payload = {"market_scan": {"available": False}, "selected_date": target_date or "", "fetched_at": payload.get("updated_at")}
|
||||||
payload,
|
|
||||||
market_slug=market_slug,
|
|
||||||
target_date=target_date,
|
|
||||||
lite=lite,
|
|
||||||
)
|
|
||||||
now_ts = time.time()
|
now_ts = time.time()
|
||||||
payload["market_scan_payload"] = scan_payload
|
payload["market_scan_payload"] = scan_payload
|
||||||
payload["market_scan_updated_at"] = datetime.now().isoformat()
|
payload["market_scan_updated_at"] = datetime.now().isoformat()
|
||||||
|
|||||||
@@ -920,7 +920,7 @@ def get_ops_health_check(request: Request) -> dict[str, Any]:
|
|||||||
else:
|
else:
|
||||||
results["cwa"] = {"ok": False, "error": "not configured"}
|
results["cwa"] = {"ok": False, "error": "not configured"}
|
||||||
|
|
||||||
# Polymarket health checks have been removed from the project
|
|
||||||
|
|
||||||
# AMOS (Korea runway sensors)
|
# AMOS (Korea runway sensors)
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -47,7 +47,6 @@ async def get_scan_terminal_payload(
|
|||||||
limit: int = 25,
|
limit: int = 25,
|
||||||
force_refresh: bool = False,
|
force_refresh: bool = False,
|
||||||
region: str = "",
|
region: str = "",
|
||||||
skip_polymarket: bool = False,
|
|
||||||
timezone_offset_seconds: int | None = None,
|
timezone_offset_seconds: int | None = None,
|
||||||
) -> Dict[str, Any]:
|
) -> Dict[str, Any]:
|
||||||
legacy_routes._assert_entitlement(request)
|
legacy_routes._assert_entitlement(request)
|
||||||
@@ -61,7 +60,6 @@ async def get_scan_terminal_payload(
|
|||||||
"market_type": market_type,
|
"market_type": market_type,
|
||||||
"time_range": time_range,
|
"time_range": time_range,
|
||||||
"limit": limit,
|
"limit": limit,
|
||||||
"skip_polymarket": skip_polymarket,
|
|
||||||
}
|
}
|
||||||
if timezone_offset_seconds is not None:
|
if timezone_offset_seconds is not None:
|
||||||
filters["timezone_offset_seconds"] = timezone_offset_seconds
|
filters["timezone_offset_seconds"] = timezone_offset_seconds
|
||||||
|
|||||||
Reference in New Issue
Block a user