John Ho Claude Fable 5.1 commited on
Commit
8557aff
Β·
1 Parent(s): 0a42a43

Set per-event Gradio concurrency limits and ZeroGPU queue size

Browse files

- detect (ZeroGPU @spaces.GPU): concurrency_limit=2 β€” each call forks its
own worker/GPU, so VRAM isn't shared; higher mostly waits on the pool and
burns quota faster
- annotate (.change() calling the pilbox Space): concurrency_limit=4 β€”
network-bound, requests overlap; at the default of 1 it choked after
every detection
- demo.queue(max_size=12) β€” ZeroGPU otherwise forces max_size=1, so a
second waiting request got HTTP 503 "Queue is full"
- Document the limits in CLAUDE.md

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

Files changed (2) hide show
  1. CLAUDE.md +1 -0
  2. app.py +5 -0
CLAUDE.md CHANGED
@@ -20,3 +20,4 @@ Gradio launches with `mcp_server=True` (exposes an MCP endpoint) and `app_kwargs
20
  - Loads `vikhyatk/moondream2` at revision `2025-04-14` with `trust_remote_code=True`. Pinning the revision is intentional β€” the model repo changes its API surface across revisions, so bumping it can break `model.point(...)` / `model.detect(...)` return shapes.
21
  - `@spaces.GPU(duration=30)` decorators are HF Spaces ZeroGPU directives β€” they only activate on the Space; locally they are no-ops requiring a CUDA device (the `device_map={"": "cuda"}` hard-codes GPU). Local CPU runs need that removed.
22
  - `detect()` returns the inner list (`["points"]` or `["objects"]`) rather than the full dict β€” callers (including the MCP tool surface) depend on that shape.
 
 
20
  - Loads `vikhyatk/moondream2` at revision `2025-04-14` with `trust_remote_code=True`. Pinning the revision is intentional β€” the model repo changes its API surface across revisions, so bumping it can break `model.point(...)` / `model.detect(...)` return shapes.
21
  - `@spaces.GPU(duration=30)` decorators are HF Spaces ZeroGPU directives β€” they only activate on the Space; locally they are no-ops requiring a CUDA device (the `device_map={"": "cuda"}` hard-codes GPU). Local CPU runs need that removed.
22
  - `detect()` returns the inner list (`["points"]` or `["objects"]`) rather than the full dict β€” callers (including the MCP tool surface) depend on that shape.
23
+ - Concurrency (Gradio queue): `detect` runs at most 2 calls at once (`concurrency_limit=2` on the Interface; ZeroGPU forks a worker per call), the pilbox `annotate` `.change()` event at most 4, and `demo.queue(max_size=12)` caps waiters (ZeroGPU otherwise forces `max_size=1`, so a second waiter gets a 503 "Queue is full"). Limits are per event; work inside a single request is still sequential.
app.py CHANGED
@@ -118,6 +118,8 @@ demo = gr.Interface(
118
  ),
119
  ],
120
  outputs=gr.JSON(label="Output JSON"),
 
 
121
  )
122
  with demo, demo.output_components[0].parent: # render inside the output column
123
  demo.output_components[0].change(
@@ -125,7 +127,10 @@ with demo, demo.output_components[0].parent: # render inside the output column
125
  [demo.input_components[0], demo.output_components[0], demo.input_components[2]],
126
  gr.Image(label="Annotated Image"),
127
  api_name=False,
 
 
128
  )
 
129
  demo.launch(
130
  mcp_server=True, app_kwargs={"docs_url": "/docs"} # add FastAPI Swagger API Docs
131
  )
 
118
  ),
119
  ],
120
  outputs=gr.JSON(label="Output JSON"),
121
+ # ZeroGPU: each call forks its own worker/GPU (no shared VRAM); higher just waits on the pool and burns quota faster
122
+ concurrency_limit=2,
123
  )
124
  with demo, demo.output_components[0].parent: # render inside the output column
125
  demo.output_components[0].change(
 
127
  [demo.input_components[0], demo.output_components[0], demo.input_components[2]],
128
  gr.Image(label="Annotated Image"),
129
  api_name=False,
130
+ # network-bound call to the pilbox Space: requests overlap; at 1 this would choke after every detection
131
+ concurrency_limit=4,
132
  )
133
+ demo.queue(max_size=12) # ZeroGPU forces max_size=1 otherwise -> 2nd waiter gets HTTP 503 "Queue is full"; ~2x sum of limits
134
  demo.launch(
135
  mcp_server=True, app_kwargs={"docs_url": "/docs"} # add FastAPI Swagger API Docs
136
  )