Spaces:
Running on CPU Upgrade
Running on CPU Upgrade
Upload 6 files
Browse files- CHANGELOG.md +7 -0
- app.py +36 -0
CHANGELOG.md
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
## v47 — Simple spec reset
|
| 2 |
|
| 3 |
- Reset the custom UI to three top-level tabs only: Build, Runs, and Space Test.
|
|
|
|
| 1 |
+
## v100 — Compact storage and billing cockpit
|
| 2 |
+
|
| 3 |
+
- Reworked the left-column Run storage block into a compact status card with clearer checking/creating/ready feedback.
|
| 4 |
+
- Added a Billing & compute card below New Build showing account, payment-readiness signal, inference-credit tier, and links to Hugging Face Billing, Jobs pricing, and Inference Providers pricing.
|
| 5 |
+
- Added `/api/billing/status` to expose only the billing signals available through OAuth, without pretending to mirror numeric usage totals from the HF Billing dashboard.
|
| 6 |
+
- Kept the build and validation workflows unchanged.
|
| 7 |
+
|
| 8 |
## v47 — Simple spec reset
|
| 9 |
|
| 10 |
- Reset the custom UI to three top-level tabs only: Build, Runs, and Space Test.
|
app.py
CHANGED
|
@@ -258,6 +258,40 @@ def register_custom_routes(fastapi_app: FastAPI) -> None:
|
|
| 258 |
ctx = extract_oauth_context(request)
|
| 259 |
return JSONResponse({"user": public_oauth_context(ctx), "token_identity": verify_token_identity(ctx)})
|
| 260 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 261 |
@fastapi_app.get("/api/bucket/status")
|
| 262 |
async def api_bucket_status(request: Request, bucket_name: str = settings.bucket_name): # type: ignore[no-untyped-def]
|
| 263 |
ctx = _oauth_context_from_request(request)
|
|
@@ -548,8 +582,10 @@ def register_custom_routes(fastapi_app: FastAPI) -> None:
|
|
| 548 |
"job_logs_polled": bool(include_job_logs),
|
| 549 |
"inference_gate": bundle.get("inference_gate") or {},
|
| 550 |
"generation_smoke": bundle.get("generation_smoke") or {},
|
|
|
|
| 551 |
"hardware_strategy": bundle.get("hardware_strategy") or {},
|
| 552 |
"technical_blockers": bundle.get("technical_blockers") or {},
|
|
|
|
| 553 |
"events": events[-20:],
|
| 554 |
"view": view,
|
| 555 |
"links": view.get("links") or _api_links(
|
|
|
|
| 258 |
ctx = extract_oauth_context(request)
|
| 259 |
return JSONResponse({"user": public_oauth_context(ctx), "token_identity": verify_token_identity(ctx)})
|
| 260 |
|
| 261 |
+
@fastapi_app.get("/api/billing/status")
|
| 262 |
+
async def api_billing_status(request: Request): # type: ignore[no-untyped-def]
|
| 263 |
+
"""Return the billing signals available through HF OAuth.
|
| 264 |
+
|
| 265 |
+
Hugging Face's public docs describe the billing dashboard as the place
|
| 266 |
+
to monitor compute usage. The OAuth `read-billing` scope exposes whether
|
| 267 |
+
the account can pay, but this app should not pretend it can mirror the
|
| 268 |
+
dashboard's numeric usage totals.
|
| 269 |
+
"""
|
| 270 |
+
ctx = _oauth_context_from_request(request)
|
| 271 |
+
scopes = set(ctx.get("scopes", []))
|
| 272 |
+
missing = set(ctx.get("missing_scopes", []))
|
| 273 |
+
can_read_billing = "read-billing" in scopes and "read-billing" not in missing
|
| 274 |
+
return JSONResponse(
|
| 275 |
+
{
|
| 276 |
+
"username": ctx["username"],
|
| 277 |
+
"profile": {
|
| 278 |
+
"is_pro": ctx.get("is_pro"),
|
| 279 |
+
"can_pay": ctx.get("can_pay"),
|
| 280 |
+
},
|
| 281 |
+
"can_read_billing": can_read_billing,
|
| 282 |
+
"can_pay": ctx.get("can_pay"),
|
| 283 |
+
"is_pro": ctx.get("is_pro"),
|
| 284 |
+
"missing_scopes": sorted(missing),
|
| 285 |
+
"links": {
|
| 286 |
+
"billing": "https://huggingface.co/settings/billing",
|
| 287 |
+
"jobs_pricing": "https://huggingface.co/docs/hub/jobs-pricing",
|
| 288 |
+
"inference_pricing": "https://huggingface.co/docs/inference-providers/pricing",
|
| 289 |
+
},
|
| 290 |
+
"usage_totals_available": False,
|
| 291 |
+
"note": "Compute usage totals are available in the Hugging Face Billing dashboard; this API only returns OAuth billing-readiness signals.",
|
| 292 |
+
}
|
| 293 |
+
)
|
| 294 |
+
|
| 295 |
@fastapi_app.get("/api/bucket/status")
|
| 296 |
async def api_bucket_status(request: Request, bucket_name: str = settings.bucket_name): # type: ignore[no-untyped-def]
|
| 297 |
ctx = _oauth_context_from_request(request)
|
|
|
|
| 582 |
"job_logs_polled": bool(include_job_logs),
|
| 583 |
"inference_gate": bundle.get("inference_gate") or {},
|
| 584 |
"generation_smoke": bundle.get("generation_smoke") or {},
|
| 585 |
+
"api_schema": bundle.get("api_schema") or {},
|
| 586 |
"hardware_strategy": bundle.get("hardware_strategy") or {},
|
| 587 |
"technical_blockers": bundle.get("technical_blockers") or {},
|
| 588 |
+
"run_documents": bundle.get("run_documents") or [],
|
| 589 |
"events": events[-20:],
|
| 590 |
"view": view,
|
| 591 |
"links": view.get("links") or _api_links(
|