fix: use FRED official JSON API (bypasses CloudFlare) + API key UI

- fred_bootstrap.py: switch from CSV graph endpoint (CloudFlare-blocked)
  to api.stlouisfed.org/fred/series/observations JSON API; reads key
  from DB config 'fred_api_key'; returns clear error if key missing
- eco.py: add GET/POST /api/eco/fred-key to check/save the FRED API key
- CalendarPage.tsx: BootstrapPanel shows API key section with status,
  input to paste key + save button, disables Launch if key missing

Free key: fred.stlouisfed.org -> My Account -> API Keys

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
OpenSquared
2026-06-26 15:47:16 +02:00
parent 202a8ce97c
commit b058b7297a
3 changed files with 156 additions and 42 deletions

View File

@@ -48,6 +48,28 @@ def _run_bootstrap(from_date: str, series_ids: Optional[List[str]], force: bool)
_bootstrap_status["running"] = False
@router.get("/fred-key")
def get_fred_key() -> Dict[str, Any]:
"""Check if a FRED API key is configured."""
from services.database import get_config
key = get_config("fred_api_key") or ""
return {
"configured": bool(key),
"preview": (key[:6] + "" + key[-4:]) if len(key) > 10 else ("***" if key else ""),
}
@router.post("/fred-key")
def save_fred_key(key: str = Query(..., description="FRED API key")) -> Dict[str, Any]:
"""Save FRED API key to DB config."""
from services.database import set_config
key = key.strip()
if not key:
raise HTTPException(400, "Empty key")
set_config("fred_api_key", key)
return {"status": "saved", "preview": key[:6] + "" + key[-4:]}
@router.post("/bootstrap")
def bootstrap(
background_tasks: BackgroundTasks,