multimodalart HF Staff commited on
Commit
9539b35
·
verified ·
1 Parent(s): e0f6bde

Pay for the conditioner call with the first ZeroGPU identity that can: the caller's token, this Space's HF_TOKEN, then none

Browse files
Files changed (2) hide show
  1. README.md +19 -16
  2. app.py +58 -43
README.md CHANGED
@@ -184,27 +184,30 @@ on is cold and a cold one pays the lazy 72.16 GiB `PIPE.to("cuda")` inside its f
184
  ## Whose GPU quota pays
185
 
186
  Two cards are booked per request: this Space's denoise loop and the conditioner's forward. ZeroGPU attributes a
187
- booking to the `X-IP-Token` header of the request that triggered it, so this Space forwards the caller's token to the
188
- conditioner (`gradio_client.Client(..., headers={"X-IP-Token": ...})`, off the `gr.Request` gradio injects — the UI
189
- path and the `/generate` API path alike). When ZeroGPU honours it, one user's request bills as one request across both
190
- halves and no org token is spent on it.
191
 
192
- It is best effort, though: ZeroGPU answers `401` for a proxy token it will not honour, which `spaces` surfaces as
193
- `Expired ZeroGPU proxy token`, and a token minted for one Space arriving at another is exactly that case on the API
194
- path. So a refused token falls back to calling the conditioner with no token at all, on an IP-based quota.
 
 
 
 
195
 
196
- That fallback is a working path rather than a degraded one, because the conditioner is sized for it. An unattributed
197
- caller may book at most 120 credits at a time and an `xlarge` booking costs **twice** its seconds, i.e. 60 s — so the
198
- conditioner books the encode (45 s) and a prompt upsample (60 s) as **two separate calls**, each under the ceiling,
199
- where one combined booking would be refused outright.
 
 
 
200
 
201
  ## Secrets
202
 
203
- Nothing this Space loads is private any more: the weights are the public
204
- [`MiniMaxAI/MiniMax-H3`](https://huggingface.co/MiniMaxAI/MiniMax-H3) checkpoint, the compiled AoTI packages are the
205
- public [`multimodalart/minimax-h3-aoti`](https://huggingface.co/multimodalart/minimax-h3-aoti) model repo, and the
206
- conditioner is a public Space called without a token so that round trip runs on the caller's own quota rather than
207
- this org's. No `HF_TOKEN` is required.
208
 
209
  ## Where diffusers comes from
210
 
 
184
  ## Whose GPU quota pays
185
 
186
  Two cards are booked per request: this Space's denoise loop and the conditioner's forward. ZeroGPU attributes a
187
+ booking to the identity of the request that triggered it, so the conditioner call tries three in order:
 
 
 
188
 
189
+ 1. **the caller's own `X-IP-Token`**, forwarded off the `gr.Request` gradio injects (the UI path and the `/generate`
190
+ API path alike). The request then bills as one request across both halves and costs this org nothing. Best effort:
191
+ ZeroGPU answers `401` for a proxy token it will not honour which is what a token minted for *this* Space looks
192
+ like arriving at another one — and `spaces` surfaces that as `Expired ZeroGPU proxy token`.
193
+ 2. **this Space's `HF_TOKEN`**, which charges the account that owns the Space and has a real quota. This is what
194
+ carries the Space in practice.
195
+ 3. **no token**, an IP-based free quota shared by everything calling out of this Space's egress IP. A last resort.
196
 
197
+ Any of ZeroGPU's "this identity cannot pay" answers a refused proxy token, a duration past what the identity may
198
+ book, an exhausted quota moves on to the next identity instead of failing the request, and the log line
199
+ `conditioner call paid for by ...` records which one paid.
200
+
201
+ The conditioner is sized so that even (3) is legal: an unattributed caller may book at most 120 credits at a time and
202
+ an `xlarge` booking costs **twice** its seconds, so the conditioner books the encode (45 s) and a prompt upsample
203
+ (60 s) as **two separate calls**, where one combined booking would be refused outright.
204
 
205
  ## Secrets
206
 
207
+ `HF_TOKEN` used for exactly one thing: paying for the conditioner call when the caller's own ZeroGPU token cannot
208
+ (see above). Everything this Space downloads is public: the [`MiniMaxAI/MiniMax-H3`](https://huggingface.co/MiniMaxAI/MiniMax-H3)
209
+ checkpoint and the [`multimodalart/minimax-h3-aoti`](https://huggingface.co/multimodalart/minimax-h3-aoti) packages.
210
+ Without it, a call the caller cannot pay for falls back to a shared IP quota worth a couple of requests a day.
 
211
 
212
  ## Where diffusers comes from
213
 
app.py CHANGED
@@ -200,7 +200,9 @@ def get_duration(prompt_embeds, text_token_tags, references, height, width, num_
200
  PIPE = None
201
  MANAGER = None
202
  LOAD_ERROR: str | None = None
203
- CLIENTS: dict[str | None, object] = {}
 
 
204
 
205
 
206
  def load_models() -> str | None:
@@ -306,33 +308,70 @@ def _arm_decode_hooks(pipe):
306
  setattr(module, method, armed)
307
 
308
 
309
- def conditioner(ip_token: str | None = None):
310
- """The other half, over the gradio API booked against *the caller's* ZeroGPU quota, not this org's.
311
-
312
- ZeroGPU attributes a booking to the `X-IP-Token` header of the request that triggered it
313
- (`spaces/zero/client.py`), which the Spaces router puts on every browser request. That header is what pays for
314
- this Space's own `@spaces.GPU` call, and forwarding it to the conditioner makes the same identity pay for the
315
- conditioner's — the two halves of one user's request then bill as one request, the way they would if this were a
316
- single Space.
317
 
318
- Without it the conditioner falls back to an IP-based quota, whose ceiling is low enough that an `xlarge` booking
319
- is refused outright ("The requested GPU duration (Ns) is larger than the maximum allowed"), so a call that does
320
- not forward a token only works because the conditioner keeps its own reservation small.
321
-
322
- Cached per token: building a `Client` costs a round trip to the Space config, and a token is per user session.
323
  """
324
  from gradio_client import Client
325
 
326
- if ip_token in CLIENTS:
327
- return CLIENTS[ip_token]
328
- # No org token: the request runs on the caller side quota, which is the point of forwarding theirs.
329
- client = Client(CONDITIONER_SPACE, headers={"X-IP-Token": ip_token} if ip_token else None)
 
 
 
 
330
  if len(CLIENTS) >= 32:
331
  CLIENTS.pop(next(iter(CLIENTS)))
332
- CLIENTS[ip_token] = client
333
  return client
334
 
335
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
336
  def ip_token_of(request) -> str | None:
337
  """The caller's ZeroGPU identity, as the Spaces router put it on this request.
338
 
@@ -346,30 +385,6 @@ def ip_token_of(request) -> str | None:
346
  return token
347
 
348
 
349
- LOG_TAG = "ref2va"
350
-
351
-
352
- def call_conditioner(ip_token, **arguments):
353
- """One conditioner call, on the caller's ZeroGPU identity when that is accepted and anonymously when it is not.
354
-
355
- Forwarding is best effort. ZeroGPU's `/schedule` answers `401` for a proxy token it will not honour — which is
356
- what a token minted for *this* Space looks like when it arrives at the conditioner — and `spaces` surfaces that as
357
- `Expired ZeroGPU proxy token`. So the forwarded call is tried first, and a rejected token falls back to no token
358
- at all rather than failing the request. The conditioner's own bookings are sized to fit the unattributed ceiling,
359
- so the fallback is a working path and not a degraded one.
360
- """
361
- api_name = arguments.pop("api_name")
362
- if ip_token is not None:
363
- try:
364
- return conditioner(ip_token).predict(**arguments, api_name=api_name)
365
- except Exception as error:
366
- if "proxy token" not in str(error):
367
- raise
368
- print(f"[{LOG_TAG}] the forwarded ZeroGPU token was refused ({error}); retrying anonymously", flush=True)
369
- CLIENTS.pop(ip_token, None)
370
- return conditioner(None).predict(**arguments, api_name=api_name)
371
-
372
-
373
  def probe(path: str) -> tuple[float | None, float | None]:
374
  """`(video seconds, audio seconds)` of a media file, either being `None` when the stream is absent."""
375
  import av
 
200
  PIPE = None
201
  MANAGER = None
202
  LOAD_ERROR: str | None = None
203
+ LOG_TAG = "ref2va"
204
+ # One `gradio_client.Client` per ZeroGPU identity the conditioner is called with; see `call_conditioner`.
205
+ CLIENTS: dict[tuple[str | None, str | None], object] = {}
206
 
207
 
208
  def load_models() -> str | None:
 
308
  setattr(module, method, armed)
309
 
310
 
311
+ def conditioner(ip_token: str | None = None, hf_token: str | None = None):
312
+ """A client for the other half, bound to one ZeroGPU identity.
 
 
 
 
 
 
313
 
314
+ Cached per identity: building a `Client` costs a round trip to the Space config, and a forwarded token is per
315
+ user session.
 
 
 
316
  """
317
  from gradio_client import Client
318
 
319
+ key = (ip_token, hf_token)
320
+ if key in CLIENTS:
321
+ return CLIENTS[key]
322
+ client = Client(
323
+ CONDITIONER_SPACE,
324
+ token=hf_token,
325
+ headers={"X-IP-Token": ip_token} if ip_token else None,
326
+ )
327
  if len(CLIENTS) >= 32:
328
  CLIENTS.pop(next(iter(CLIENTS)))
329
+ CLIENTS[key] = client
330
  return client
331
 
332
 
333
+ # What ZeroGPU says when an identity cannot pay for the booking, in any of its forms: a proxy token it will not
334
+ # honour (`401`, surfaced as "Expired ZeroGPU proxy token"), a duration past what that identity may book, and an
335
+ # exhausted quota. All three mean "try the next identity" rather than "fail the request".
336
+ _UNPAYABLE = ("proxy token", "ZeroGPU quota", "larger than the maximum allowed", "GPU limit")
337
+
338
+
339
+ def call_conditioner(ip_token, **arguments):
340
+ """One conditioner call, against the first ZeroGPU identity that can pay for it.
341
+
342
+ In order of preference:
343
+
344
+ 1. **the caller's own forwarded `X-IP-Token`** — the request bills as one request across both halves and costs
345
+ this org nothing. Best effort: a proxy token minted for this Space is not necessarily honoured when it
346
+ arrives at another one, and ZeroGPU answers `401` when it is not.
347
+ 2. **this Space's `HF_TOKEN`** — the booking is charged to the account that owns the Space, which has a real
348
+ quota. This is what carries the Space in practice.
349
+ 3. **no token at all** — an IP-based free quota, shared by everything calling out of this Space's egress IP and
350
+ worth a couple of requests a day. A last resort, not a design.
351
+
352
+ The conditioner's own bookings are sized to fit even (3): it books an encode and a prompt upsample as two calls
353
+ of 45 s and 60 s, because an unattributed caller may book at most 60 s of `xlarge` at a time.
354
+ """
355
+ api_name = arguments.pop("api_name")
356
+ attempts = []
357
+ if ip_token:
358
+ attempts.append(("the caller's forwarded ZeroGPU token", {"ip_token": ip_token}))
359
+ if HF_TOKEN:
360
+ attempts.append(("this Space's HF_TOKEN", {"hf_token": HF_TOKEN}))
361
+ attempts.append(("no token, on an IP quota", {}))
362
+
363
+ for index, (label, identity) in enumerate(attempts):
364
+ try:
365
+ result = conditioner(**identity).predict(**arguments, api_name=api_name)
366
+ print(f"[{LOG_TAG}] conditioner call paid for by {label}", flush=True)
367
+ return result
368
+ except Exception as error:
369
+ if index == len(attempts) - 1 or not any(reason in str(error) for reason in _UNPAYABLE):
370
+ raise
371
+ print(f"[{LOG_TAG}] {label}: {error}; trying the next identity", flush=True)
372
+ CLIENTS.pop((identity.get("ip_token"), identity.get("hf_token")), None)
373
+
374
+
375
  def ip_token_of(request) -> str | None:
376
  """The caller's ZeroGPU identity, as the Spaces router put it on this request.
377
 
 
385
  return token
386
 
387
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
388
  def probe(path: str) -> tuple[float | None, float | None]:
389
  """`(video seconds, audio seconds)` of a media file, either being `None` when the stream is absent."""
390
  import av