fix: analysis 500s, caching, alert page perf

P0: Fix KeyError in 3 analysis endpoints. geojson.py stores 1d risk
as "risk_value" but analysis.py accessed "risk_1d" — always crashed.

Backend: Add lru_cache to GeoJSON/CSV/Parquet loaders, date helpers,
and district loader. Add try/except and FileNotFoundError guards.

Frontend: Debounce riskRange, merge counts into useMemo, stabilize
handleGridClick with ref, memoize nearest-grid scan, wrap AlertMap
in React.memo, switch useLodGrid from fetch to cachedGet.
This commit is contained in:
2026-06-05 02:27:10 +08:00
parent fc468464b2
commit e64ca3b4f5
9 changed files with 154 additions and 114 deletions

View File

@@ -5,6 +5,7 @@ from fastapi import APIRouter, HTTPException
from pydantic import BaseModel
from typing import List, Optional
import logging
from functools import lru_cache
import pandas as pd
from pathlib import Path
@@ -15,6 +16,11 @@ router = APIRouter(prefix="/api/geocoded", tags=["geocoded"])
PROJECT_ROOT = Path(__file__).parent.parent.parent
DATA_DIR = PROJECT_ROOT / "outputs"
@lru_cache(maxsize=1)
def _load_csv(path: Path) -> pd.DataFrame:
return pd.read_csv(path)
class GridCaseData(BaseModel):
"""Grid case data for visualization"""
grid_id: int
@@ -60,7 +66,7 @@ async def get_grid_cases():
raise HTTPException(status_code=404, detail="Grid data not found")
try:
df = pd.read_csv(grid_file)
df = _load_csv(grid_file)
grids = []
for _, row in df.iterrows():
@@ -105,7 +111,7 @@ async def get_geocoded_cases(
raise HTTPException(status_code=404, detail="Geocoded data not found")
try:
df = pd.read_csv(cases_file)
df = _load_csv(cases_file)
# Drop rows with missing coordinates
df = df.dropna(subset=['latitude', 'longitude'])
@@ -122,7 +128,7 @@ async def get_geocoded_cases(
df = df.head(limit)
cases = []
for _, row in df.iterrows():
for row in df.to_dict('records'):
street_val = row.get('street')
if pd.isna(street_val):
street_val = None
@@ -157,7 +163,7 @@ async def get_geocoded_count():
raise HTTPException(status_code=404, detail="Geocoded data not found")
try:
df = pd.read_csv(cases_file)
df = _load_csv(cases_file)
street_matched = len(df[df['geocode_method'] == 'street'])
district_fallback = len(df[df['geocode_method'] == 'district'])