Spaces:
Running
Running
chore(sync): mirror backend .py + Dockerfile to Space (hf-sync-backend)
Browse filesAutomated backend sync from szl-holdings/a11oy main via hf-sync-backend.
Updated (differed from the Space): serve.py
Deleted (gone from the repo + Dockerfile COPY set): (none)
Keeps the Space-built backend (serve.py + the Dockerfile-COPY'd .py
modules) identical to GitHub main so the Space never rebuilds from a
stale backend, new endpoints don't 404 there, and orphaned modules
removed from the repo don't linger in the Space tree.
serve.py
CHANGED
|
@@ -11097,6 +11097,123 @@ except Exception as _spine_move_e: # pragma: no cover
|
|
| 11097 |
print(f"[a11oy] Spine front-move skipped: {_spine_move_e!r}", file=__import__("sys").stderr)
|
| 11098 |
|
| 11099 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 11100 |
@app.get("/viz")
|
| 11101 |
async def viz_gallery() -> Response:
|
| 11102 |
f = VIZ_DIR / "index.html"
|
|
|
|
| 11097 |
print(f"[a11oy] Spine front-move skipped: {_spine_move_e!r}", file=__import__("sys").stderr)
|
| 11098 |
|
| 11099 |
|
| 11100 |
+
# ---------------------------------------------------------------------------
|
| 11101 |
+
# Federated router spend — surface the BOX szl-router's REAL paid spend on the
|
| 11102 |
+
# /sovereign board. The a11oy container's own szl_spend_cap ledger is local/advisory
|
| 11103 |
+
# and stays ~$0 (no paid inference runs in THIS container); the durable source of
|
| 11104 |
+
# truth for real paid spend is the Hetzner box szl-router's append-only hash-linked
|
| 11105 |
+
# ledger. This reads it live, read-only, at request time (the HF Space FS is ephemeral,
|
| 11106 |
+
# so a pushed copy could never be durable). Honest by construction: env unset ->
|
| 11107 |
+
# "not_configured"; box silent -> "unreachable"; a real $0 is shown ONLY when the box
|
| 11108 |
+
# actually reports $0. NO keys, NO chat cross this feed — the box endpoint exposes only
|
| 11109 |
+
# USD totals + chain hash + provider tiers, GET-only, token-gated, rate-limited at nginx.
|
| 11110 |
+
# ---------------------------------------------------------------------------
|
| 11111 |
+
_fed_spend_cache = {"ts": 0.0, "data": None}
|
| 11112 |
+
_FED_SPEND_TTL = 30.0
|
| 11113 |
+
|
| 11114 |
+
|
| 11115 |
+
def _http_get_auth(url: str, token: str = "", timeout: int = 7):
|
| 11116 |
+
"""Return (status_code, body_text_or_None). Never raises. Optional Bearer auth."""
|
| 11117 |
+
import urllib.request, urllib.error, ssl
|
| 11118 |
+
try:
|
| 11119 |
+
ctx = ssl.create_default_context()
|
| 11120 |
+
headers = {"user-agent": "a11oy-sovereign-fed", "accept": "application/json"}
|
| 11121 |
+
if token:
|
| 11122 |
+
headers["authorization"] = "Bearer " + token
|
| 11123 |
+
req = urllib.request.Request(url, method="GET", headers=headers)
|
| 11124 |
+
with urllib.request.urlopen(req, timeout=timeout, context=ctx) as r:
|
| 11125 |
+
code = int(getattr(r, "status", 0) or 0)
|
| 11126 |
+
body = r.read(65536).decode("utf-8", "replace")
|
| 11127 |
+
return code, body
|
| 11128 |
+
except urllib.error.HTTPError as e:
|
| 11129 |
+
return int(getattr(e, "code", 0) or 0), None
|
| 11130 |
+
except Exception:
|
| 11131 |
+
return 0, None
|
| 11132 |
+
|
| 11133 |
+
|
| 11134 |
+
def _fetch_federated_spend() -> dict:
|
| 11135 |
+
import json as _json, os as _os
|
| 11136 |
+
url = (_os.environ.get("SZL_ROUTER_SPEND_URL", "") or "").strip()
|
| 11137 |
+
token = (_os.environ.get("SZL_ROUTER_SPEND_TOKEN", "") or "").strip()
|
| 11138 |
+
base = {"configured": bool(url), "reachable": False, "http_status": 0,
|
| 11139 |
+
"source_url": url or None}
|
| 11140 |
+
if not url:
|
| 11141 |
+
base["state"] = "not_configured"
|
| 11142 |
+
return base
|
| 11143 |
+
code, body = _http_get_auth(url, token, timeout=7)
|
| 11144 |
+
base["http_status"] = code
|
| 11145 |
+
if not (code and 200 <= code < 400 and body):
|
| 11146 |
+
base["state"] = "unreachable"
|
| 11147 |
+
return base
|
| 11148 |
+
try:
|
| 11149 |
+
s = _json.loads(body)
|
| 11150 |
+
except Exception:
|
| 11151 |
+
base["state"] = "unreachable"
|
| 11152 |
+
return base
|
| 11153 |
+
chain = s.get("chain") if isinstance(s.get("chain"), dict) else {}
|
| 11154 |
+
tail_in = s.get("tail") if isinstance(s.get("tail"), list) else []
|
| 11155 |
+
tail = []
|
| 11156 |
+
for e in tail_in[-6:]:
|
| 11157 |
+
if not isinstance(e, dict):
|
| 11158 |
+
continue
|
| 11159 |
+
meta = e.get("meta") if isinstance(e.get("meta"), dict) else {}
|
| 11160 |
+
tail.append({
|
| 11161 |
+
"amount_usd": e.get("amount_usd"),
|
| 11162 |
+
"source": str(e.get("source", ""))[:40],
|
| 11163 |
+
"estimated": bool(e.get("estimated")),
|
| 11164 |
+
"model": str(meta.get("upstream_model") or meta.get("model") or "")[:40],
|
| 11165 |
+
"basis": str(meta.get("basis", ""))[:40],
|
| 11166 |
+
"ts": e.get("ts"),
|
| 11167 |
+
})
|
| 11168 |
+
base.update({
|
| 11169 |
+
"reachable": True, "state": "live",
|
| 11170 |
+
"cap_usd": s.get("cap_usd"), "spent_usd": s.get("spent_usd"),
|
| 11171 |
+
"remaining_usd": s.get("remaining_usd"), "pct_used": s.get("pct_used"),
|
| 11172 |
+
"armed": s.get("armed"), "tripped": s.get("tripped"),
|
| 11173 |
+
"kill_file_engaged": s.get("kill_file_engaged"), "entries": s.get("entries"),
|
| 11174 |
+
"chain_intact": chain.get("intact"), "chain_entries": chain.get("entries"),
|
| 11175 |
+
"tail": tail,
|
| 11176 |
+
"upstream_schema": str(s.get("schema", ""))[:40],
|
| 11177 |
+
"upstream_generated": str(s.get("generated", ""))[:40],
|
| 11178 |
+
})
|
| 11179 |
+
return base
|
| 11180 |
+
|
| 11181 |
+
|
| 11182 |
+
@app.get("/api/a11oy/v1/spend/federated")
|
| 11183 |
+
async def a11oy_spend_federated() -> Response:
|
| 11184 |
+
import time as _t, datetime as _dt
|
| 11185 |
+
now = _t.monotonic()
|
| 11186 |
+
cached = _fed_spend_cache["data"]
|
| 11187 |
+
if cached is not None and (now - _fed_spend_cache["ts"]) < _FED_SPEND_TTL:
|
| 11188 |
+
return JSONResponse({**cached, "cache": "hit"})
|
| 11189 |
+
payload = await asyncio.to_thread(_fetch_federated_spend)
|
| 11190 |
+
data = {
|
| 11191 |
+
"schema": "szl.federated_spend/v1",
|
| 11192 |
+
"checked_at": _dt.datetime.utcnow().isoformat() + "Z",
|
| 11193 |
+
"authority": "box szl-router append-only ledger (real paid spend, authoritative)",
|
| 11194 |
+
"note": "read live from the box router at request time; a11oy's own szl_spend_cap ledger is local/advisory. Nothing summed, nothing fabricated; chain state is as reported by the source.",
|
| 11195 |
+
"cache": "miss",
|
| 11196 |
+
**payload,
|
| 11197 |
+
}
|
| 11198 |
+
_fed_spend_cache["data"] = data
|
| 11199 |
+
_fed_spend_cache["ts"] = now
|
| 11200 |
+
return JSONResponse(data)
|
| 11201 |
+
|
| 11202 |
+
|
| 11203 |
+
# ROUTE-ORDERING FIX (same proven pattern as constellation/spine): front-move the
|
| 11204 |
+
# federated-spend route ahead of the /api/a11oy/{path:path} Node proxy catch-all.
|
| 11205 |
+
try:
|
| 11206 |
+
_fed_paths = {"/api/a11oy/v1/spend/federated"}
|
| 11207 |
+
_fed_moved = [r for r in app.router.routes if getattr(r, "path", None) in _fed_paths]
|
| 11208 |
+
for _r in _fed_moved:
|
| 11209 |
+
app.router.routes.remove(_r)
|
| 11210 |
+
for _r in reversed(_fed_moved):
|
| 11211 |
+
app.router.routes.insert(0, _r)
|
| 11212 |
+
print(f"[a11oy] Federated-spend route front-moved to router head: {len(_fed_moved)} routes", file=__import__("sys").stderr)
|
| 11213 |
+
except Exception as _fed_move_e: # pragma: no cover
|
| 11214 |
+
print(f"[a11oy] Federated-spend front-move skipped: {_fed_move_e!r}", file=__import__("sys").stderr)
|
| 11215 |
+
|
| 11216 |
+
|
| 11217 |
@app.get("/viz")
|
| 11218 |
async def viz_gallery() -> Response:
|
| 11219 |
f = VIZ_DIR / "index.html"
|