Spaces:
Running on Zero
Running on Zero
Fall back to an anonymous conditioner call when the forwarded ZeroGPU token is refused
Browse files
README.md
CHANGED
|
@@ -162,14 +162,18 @@ one-time `PIPE.to("cuda")` is inside the first row's 339 s and does not reappear
|
|
| 162 |
|
| 163 |
Two cards are booked per request: this Space's denoise loop and the conditioner's forward. ZeroGPU attributes a
|
| 164 |
booking to the `X-IP-Token` header of the request that triggered it, so this Space forwards the caller's token to the
|
| 165 |
-
conditioner (`gradio_client.Client(..., headers={"X-IP-Token": ...})`,
|
| 166 |
-
path and the `/generate` API path alike).
|
| 167 |
-
|
| 168 |
-
|
| 169 |
-
|
| 170 |
-
|
| 171 |
-
|
| 172 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 173 |
|
| 174 |
## Secrets
|
| 175 |
|
|
|
|
| 162 |
|
| 163 |
Two cards are booked per request: this Space's denoise loop and the conditioner's forward. ZeroGPU attributes a
|
| 164 |
booking to the `X-IP-Token` header of the request that triggered it, so this Space forwards the caller's token to the
|
| 165 |
+
conditioner (`gradio_client.Client(..., headers={"X-IP-Token": ...})`, off the `gr.Request` gradio injects — the UI
|
| 166 |
+
path and the `/generate` API path alike). When ZeroGPU honours it, one user's request bills as one request across both
|
| 167 |
+
halves and no org token is spent on it.
|
| 168 |
+
|
| 169 |
+
It is best effort, though: ZeroGPU answers `401` for a proxy token it will not honour, which `spaces` surfaces as
|
| 170 |
+
`Expired ZeroGPU proxy token`, and a token minted for one Space arriving at another is exactly that case on the API
|
| 171 |
+
path. So a refused token falls back to calling the conditioner with no token at all, on an IP-based quota.
|
| 172 |
+
|
| 173 |
+
That fallback is a working path rather than a degraded one, because the conditioner is sized for it. An unattributed
|
| 174 |
+
caller may book at most 120 credits at a time and an `xlarge` booking costs **twice** its seconds, i.e. 60 s — so the
|
| 175 |
+
conditioner books the encode (45 s) and a prompt upsample (60 s) as **two separate calls**, each under the ceiling,
|
| 176 |
+
where one combined booking would be refused outright.
|
| 177 |
|
| 178 |
## Secrets
|
| 179 |
|
app.py
CHANGED
|
@@ -210,6 +210,30 @@ def ip_token_of(request) -> str | None:
|
|
| 210 |
return token
|
| 211 |
|
| 212 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 213 |
def encode_remote(prompt, image_path, last_image_path, canvas, num_frames, rewrite_prompt=False, ip_token=None):
|
| 214 |
"""Ask the conditioner Space for `prompt_embeds` + `text_token_tags`. Off this Space's GPU time entirely.
|
| 215 |
|
|
@@ -221,7 +245,8 @@ def encode_remote(prompt, image_path, last_image_path, canvas, num_frames, rewri
|
|
| 221 |
from gradio_client import handle_file
|
| 222 |
from safetensors import safe_open
|
| 223 |
|
| 224 |
-
path, plan =
|
|
|
|
| 225 |
prompt=prompt,
|
| 226 |
image_path=handle_file(image_path) if image_path else None,
|
| 227 |
last_image_path=handle_file(last_image_path) if last_image_path else None,
|
|
|
|
| 210 |
return token
|
| 211 |
|
| 212 |
|
| 213 |
+
LOG_TAG = "gen"
|
| 214 |
+
|
| 215 |
+
|
| 216 |
+
def call_conditioner(ip_token, **arguments):
|
| 217 |
+
"""One conditioner call, on the caller's ZeroGPU identity when that is accepted and anonymously when it is not.
|
| 218 |
+
|
| 219 |
+
Forwarding is best effort. ZeroGPU's `/schedule` answers `401` for a proxy token it will not honour — which is
|
| 220 |
+
what a token minted for *this* Space looks like when it arrives at the conditioner — and `spaces` surfaces that as
|
| 221 |
+
`Expired ZeroGPU proxy token`. So the forwarded call is tried first, and a rejected token falls back to no token
|
| 222 |
+
at all rather than failing the request. The conditioner's own bookings are sized to fit the unattributed ceiling,
|
| 223 |
+
so the fallback is a working path and not a degraded one.
|
| 224 |
+
"""
|
| 225 |
+
api_name = arguments.pop("api_name")
|
| 226 |
+
if ip_token is not None:
|
| 227 |
+
try:
|
| 228 |
+
return conditioner(ip_token).predict(**arguments, api_name=api_name)
|
| 229 |
+
except Exception as error:
|
| 230 |
+
if "proxy token" not in str(error):
|
| 231 |
+
raise
|
| 232 |
+
print(f"[{LOG_TAG}] the forwarded ZeroGPU token was refused ({error}); retrying anonymously", flush=True)
|
| 233 |
+
CLIENTS.pop(ip_token, None)
|
| 234 |
+
return conditioner(None).predict(**arguments, api_name=api_name)
|
| 235 |
+
|
| 236 |
+
|
| 237 |
def encode_remote(prompt, image_path, last_image_path, canvas, num_frames, rewrite_prompt=False, ip_token=None):
|
| 238 |
"""Ask the conditioner Space for `prompt_embeds` + `text_token_tags`. Off this Space's GPU time entirely.
|
| 239 |
|
|
|
|
| 245 |
from gradio_client import handle_file
|
| 246 |
from safetensors import safe_open
|
| 247 |
|
| 248 |
+
path, plan = call_conditioner(
|
| 249 |
+
ip_token,
|
| 250 |
prompt=prompt,
|
| 251 |
image_path=handle_file(image_path) if image_path else None,
|
| 252 |
last_image_path=handle_file(last_image_path) if last_image_path else None,
|