ysharma HF Staff commited on
Commit
8924e29
·
verified ·
1 Parent(s): 65865a4

Workflow1111 — Automatic1111-style diffusion studio on gr.Workflow

Browse files
Files changed (2) hide show
  1. README.md +23 -12
  2. nodes.py +11 -7
README.md CHANGED
@@ -345,33 +345,40 @@ image, params, hires = client.predict(
345
  Run `python apps/05_workflow1111/test_pipelines.py local` to print the full
346
  endpoint list with parameter names and types.
347
 
348
- ### Bring your own token (API and MCP callers)
349
 
350
  The Space holds **no** `HF_TOKEN` secret. In the browser, the Sign-in button
351
- supplies your token through OAuth; API and MCP callers send it on the request
352
- as an `X-HF-Token` header instead. Two hooks make that work:
353
 
354
  * every node that talks to Inference Providers declares a `request: gr.Request`
355
  parameter, and `_hf_token()` in `nodes.py` resolves the token in this order:
356
- OAuth session → `X-HF-Token` header → `Authorization: Bearer` header →
357
- server `HF_TOKEN` → local `hf auth login`;
358
  * `app.py` extends gradio's own `_resolve_token` (used for `model` and `space`
359
  nodes, which gradio runs itself) with the same header fallback.
360
 
361
- Gradio's MCP server forwards the caller's headers verbatim, so the same header
362
- works for tools. Use `X-HF-Token`, not `Authorization: Bearer`: the Spaces
363
- proxy consumes the `Authorization` header before it reaches the app (it does
364
- work when running locally).
365
 
366
  ```python
367
  from gradio_client import Client
368
 
369
- client = Client("https://ysharma-workflow1111.hf.space",
370
- headers={"X-HF-Token": "hf_..."})
371
  prompt = client.predict("an orange cat with a yellow hat", api_name="/generated_prompt")
372
  ```
373
 
374
- MCP client config (Claude Code, Cursor, Claude Desktop):
 
 
 
 
 
 
 
375
 
376
  ```json
377
  {
@@ -384,6 +391,10 @@ MCP client config (Claude Code, Cursor, Claude Desktop):
384
  }
385
  ```
386
 
 
 
 
 
387
  Without a token, model nodes raise `No Hugging Face token ...`; the purely
388
  local Pillow/numpy nodes never need one.
389
 
 
345
  Run `python apps/05_workflow1111/test_pipelines.py local` to print the full
346
  endpoint list with parameter names and types.
347
 
348
+ ### Bring your own token (API, CLI and MCP callers)
349
 
350
  The Space holds **no** `HF_TOKEN` secret. In the browser, the Sign-in button
351
+ supplies your token through OAuth; every other caller sends it on the request.
352
+ Two hooks make that work:
353
 
354
  * every node that talks to Inference Providers declares a `request: gr.Request`
355
  parameter, and `_hf_token()` in `nodes.py` resolves the token in this order:
356
+ OAuth session → `X-HF-Token` header → `X-HF-Authorization: Bearer` header →
357
+ `Authorization: Bearer` header → server `HF_TOKEN` → local `hf auth login`;
358
  * `app.py` extends gradio's own `_resolve_token` (used for `model` and `space`
359
  nodes, which gradio runs itself) with the same header fallback.
360
 
361
+ `gradio_client` sends your token as `X-HF-Authorization` (it renames the
362
+ `Authorization` header so the Hub proxy never sees it), so the ordinary
363
+ `token=` argument just works — and so does the locally saved `hf auth login`
364
+ token, which the client sends by default:
365
 
366
  ```python
367
  from gradio_client import Client
368
 
369
+ client = Client("https://ysharma-workflow1111.hf.space") # uses `hf auth login` token
370
+ client = Client("https://ysharma-workflow1111.hf.space", token="hf_...")
371
  prompt = client.predict("an orange cat with a yellow hat", api_name="/generated_prompt")
372
  ```
373
 
374
+ From the terminal (needs `typer>=0.15`; `gradio info <url>` prints the payload shapes):
375
+
376
+ ```bash
377
+ gradio predict https://ysharma-workflow1111.hf.space /generated_prompt '{"in_0": "an orange cat with a yellow hat"}'
378
+ ```
379
+
380
+ MCP clients forward custom headers verbatim, so use `X-HF-Token` there
381
+ (Claude Code, Cursor, Claude Desktop):
382
 
383
  ```json
384
  {
 
391
  }
392
  ```
393
 
394
+ Pass a non-empty *Hires refine instruction* to `/image` (for example
395
+ `enhance fine detail`); with an empty one the Kontext hires node fails with
396
+ `KeyError: 'images'` from the provider adapter.
397
+
398
  Without a token, model nodes raise `No Hugging Face token ...`; the purely
399
  local Pillow/numpy nodes never need one.
400
 
nodes.py CHANGED
@@ -631,10 +631,12 @@ def _caller_hf_token(request):
631
  the caller's headers verbatim — so a client can authenticate per call
632
  without the Space holding a token of its own. Two spellings are accepted:
633
 
634
- * ``X-HF-Token: hf_...`` (custom header; works everywhere)
635
- * ``Authorization: Bearer hf_...`` (what ``gradio_client`` sends for
636
- ``Client(..., token=...)``; fine locally, but the Spaces proxy
637
- consumes this header, so on a Space use ``X-HF-Token``)
 
 
638
  """
639
  headers = getattr(request, "headers", None)
640
  if not headers:
@@ -642,9 +644,11 @@ def _caller_hf_token(request):
642
  lower = {str(k).lower(): v for k, v in dict(headers).items()}
643
  token = lower.get("x-hf-token")
644
  if not token:
645
- auth = lower.get("authorization", "")
646
- if auth.lower().startswith("bearer "):
647
- token = auth[7:]
 
 
648
  token = (token or "").strip()
649
  return token if token.startswith("hf_") else None
650
 
 
631
  the caller's headers verbatim — so a client can authenticate per call
632
  without the Space holding a token of its own. Two spellings are accepted:
633
 
634
+ * ``X-HF-Token: hf_...`` (custom header, e.g. MCP configs)
635
+ * ``X-HF-Authorization: Bearer hf_...`` (what ``gradio_client`` and the
636
+ ``gradio predict`` CLI send for ``token=`` / ``--token`` / the locally
637
+ saved ``hf auth login`` token — the client renames ``Authorization``
638
+ to this so the Hub proxy never sees it)
639
+ * ``Authorization: Bearer hf_...`` (plain HTTP callers)
640
  """
641
  headers = getattr(request, "headers", None)
642
  if not headers:
 
644
  lower = {str(k).lower(): v for k, v in dict(headers).items()}
645
  token = lower.get("x-hf-token")
646
  if not token:
647
+ for key in ("x-hf-authorization", "authorization"):
648
+ auth = lower.get(key, "")
649
+ if auth.lower().startswith("bearer "):
650
+ token = auth[7:]
651
+ break
652
  token = (token or "").strip()
653
  return token if token.startswith("hf_") else None
654