How do I use this space with the API?

#24
by gonegirl - opened

I copied the example, set handle_file to None, reduced the step size, and increased GPU time, but nothing works, i keep getting either gradio_client.exceptions.AppError: ValueError.
gradio_client.exceptions.AppError: GPU task aborted.

from gradio_client import Client, handle_file

from huggingface_hub import login
login("hf_xxxxxx")

client = Client("John6666/DiffuseCraftMod")
result = client.predict(
param_0="Hello!!",
param_1="lowres, bad anatomy, bad hands, missing fingers, extra digit, fewer digits, worst quality, low quality, very displeasing, (bad)",
param_2=1,
param_3=5,
param_4=7,
param_5=False,
param_6=-1,
param_7="",
param_8=1,
param_9="",
param_10=1,
param_11="",
param_12=1,
param_13="",
param_14=1,
param_15="",
param_16=1,
param_17="",
param_18=1,
param_19="",
param_20=1,
param_21="Euler",
param_22="Automatic",
param_23="Automatic",
param_24=1024,
param_25=1024,
param_26="votepurchase/animagine-xl-3.1",
param_27="None",
param_28="txt2img",
param_29=None,
param_30="Canny",
param_31=512,
param_32=1024,
param_33=["(No style)"],
param_34=None,
param_35=None,
param_36=0.55,
param_37=100,
param_38=200,
param_39=0.1,
param_40=0.1,
param_41=1,
param_42=9,
param_43=1,
param_44=0,
param_45=1,
param_46=False,
param_47="Classic",
param_48=None,
param_49=1.2,
param_50=0,
param_51=8,
param_52=30,
param_53=0.55,
param_54="Use same sampler",
param_55="Hello!!",
param_56="Hello!!",
param_57=False,
param_58=True,
param_59="Use same schedule type",
param_60=-1,
param_61="Automatic",
param_62=1,
param_63=True,
param_64=False,
param_65=True,
param_66=False,
param_67=False,
param_68="model,seed",
param_69="./images/",
param_70=False,
param_71=False,
param_72=False,
param_73=True,
param_74=1,
param_75=0.55,
param_76=False,
param_77=False,
param_78=False,
param_79=True,
param_80=False,
param_81="Use same sampler",
param_82=False,
param_83="Hello!!",
param_84="Hello!!",
param_85=0.35,
param_86=False,
param_87=True,
param_88=False,
param_89=4,
param_90=4,
param_91=32,
param_92=False,
param_93="Hello!!",
param_94="Hello!!",
param_95=0.35,
param_96=False,
param_97=True,
param_98=False,
param_99=4,
param_100=4,
param_101=32,
param_102=True,
param_103=0,
param_104=None,
param_105=None,
param_106="plus_face",
param_107="original",
param_108=0.7,
param_109=None,
param_110=None,
param_111="base",
param_112="style",
param_113=0.7,
param_114=0,
param_115=None,
param_116=1,
param_117=0.5,
param_118=False,
param_119=False,
param_120=50,
api_name="/sd_gen_generate_pipeline"
)
print(result)

Thanks. There was an issue inside the Space. I think I fixed it.
However, I've never used this Space via the API, so I can't guarantee anything about the API...

Thanks it works now. Loaded as API: https://john6666-diffusecraftmod.hf.space
('GPU task complete in: 9 seconds', {'type': 'update'}, {'type': 'update'})

btw why was the generation step images also downloaded?

why was the generation step images also downloaded?

That's because it actually outputs the image from the generation process for preview purposes.😅
Using the following space without previews, where the output is nearly same, for the API usage might be a good idea.
https://huggingface.co/spaces/John6666/votepurchase-multiple-model

DiffuseCraft loaded the wrong model (probably the last used model) i need to add this before sd_gen_generate_pipeline

client.predict(
model_name="votepurchase/animagine-xl-3.1",
vae_model=None,
task="txt2img",
controlnet_model="Automatic",
api_name="/load_new_model",
)

I tried votepurchase, right, it's more straightforward. Thanks.

Hi just so you know, if someone else is using vp, my api call will use their model. In dc that's not a problem https://huggingface.co/spaces/r3gm/DiffuseCraft/discussions/8

Sorry... Thanks! I totally forgot to make it work for multiple users at the same time... I think I fixed it.😅

Sorry to bother you again, is there any way the python api can show info and errors like the web version (pop ups or progress indicators)? now it’s very minimal, you either get the image or a null error, don't bother if that's too much work :)

Hmm... Before even considering the burden, it's probably simply impossible given Gradio's API specifications...😅
Technically (ideally), there might be ways to implement a streaming API like OpenAI's LLM, but there's likely no way to do that with Zero GPU + Gradio at present...
Endpoint performs fastest when operating in a “success or death. No progress displayed” manner. To show progress, you need to communicate with the server frequently for the purpose of showing progress...

Try swapping client.predict for client.submit, but that one only returns intermediate results...

result = client.submit(<params>)
for data in result:
    print(data)

Probably, according to the Gradio API's design, we'd have to manually iterate the required number of times for the progress...
Was there a standard streaming API...?

dc python api shows this simple log

Loaded as API: https://john6666-diffusecraftmod.hf.space ✔
Model loaded: votepurchase/animagine-xl-3.1
('GPU task complete in: 11 seconds', {'__type__': 'update'}, {'__type__': 'update'})

from same example but with the raw curl api,

curl -X POST https://john6666-diffusecraftmod.hf.space/gradio_api/call/load_new_model -s -H "Content-Type: application/json" -d '{
  "data": [
  "votepurchase/waiNSFWIllustrious_v120",
  "None",
  "txt2img",
  "Automatic"
  ]}' \
      | awk -F'"' '{ print $4}'  \
      | read EVENT_ID; curl -N https://john6666-diffusecraftmod.hf.space/gradio_api/call/load_new_model/$EVENT_ID
event: heartbeat
data: null

event: generating
data: ["Loading model: votepurchase/waiNSFWIllustrious_v120"]

event: generating
data: ["Model loaded: votepurchase/waiNSFWIllustrious_v120"]

event: complete
data: ["Model loaded: votepurchase/waiNSFWIllustrious_v120"]

curl sd_gen_generate_pipeline doesn't even seem to work? it always shows

event: error
data: null

event: error
data: null

If the trailing arguments are insufficient, it might behave that way...?


Fix: make the handler parse the three trailing flags defensively and only slice them off when they’re actually present. Use helpers for safe type coercion. Apply the same patch to both Spaces.

Drop-in patch for r3gm/DiffuseCraft → app.py

Replace the current tail parsing and direct indexing in sd_gen_generate_pipeline(*args) with this:

# --- helpers (place near the function) ---
def _as_int(v, default):
    try:
        if v is None or str(v).strip() == "":
            return default
        return int(float(v))
    except Exception:
        return default

def _as_bool(v, default):
    if isinstance(v, bool):
        return v
    if v is None:
        return default
    s = str(v).strip().lower()
    if s in {"1", "true", "yes", "on"}:
        return True
    if s in {"0", "false", "no", "off"}:
        return False
    return default

def _flags_present(args):
    # Expect ... , load_lora_cpu(bool), verbose(int), gpu_duration(int)
    if len(args) < 3:
        return False
    looks_bool = str(args[-3]).strip().lower() in {"0","1","true","false","yes","no","on","off"} or isinstance(args[-3], bool)
    looks_int2 = str(args[-2]).strip().lstrip("+-").replace(".","",1).isdigit()
    looks_int1 = str(args[-1]).strip().lstrip("+-").replace(".","",1).isdigit()
    return looks_bool and looks_int2 and looks_int1
# --- end helpers ---

def sd_gen_generate_pipeline(*args):
    # Tail-safe parsing. Defaults match UI expectations.
    if _flags_present(args):
        load_lora_cpu   = _as_bool(args[-3], True)
        verbose_arg     = _as_int(args[-2], 0)
        gpu_duration_arg= _as_int(args[-1], 59)
        generation_args = args[:-3]
    else:
        load_lora_cpu   = True
        verbose_arg     = 0
        gpu_duration_arg= 59
        generation_args = args  # do not chop real arguments

    # existing LoRA bookkeeping (kept as-is; indices remain valid)
    lora_list = [None if item == "None" else item for item in
                 [args[7], args[9], args[11], args[13], args[15], args[17], args[19]]]

    # ... unchanged logic ...

    # Run under a GPU time budget
    yield from dynamic_gpu_duration(sd_gen.generate_pipeline, gpu_duration_arg, *generation_args)

Why this fixes your event: error with “short” payloads:

  • The original code unconditionally did args[-1], args[-2], args[-3] and args[:-3], so omitting the last flags mis-parsed and truncated required positional args. (Hugging Face)
  • The patch detects whether the last 3 items look like the flags. If not, it uses defaults and does not slice, preserving the caller’s arguments. (gradio.app)

Reference lines showing the fragile tail indexing and fixed-position LoRA access in the original: gpu_duration_arg = int(args[-1]) ..., verbose_arg = int(args[-2]), load_lora_cpu = args[-3], and the LoRA indices args[7]..args[20]. (Hugging Face)

Drop-in patch for John6666/DiffuseCraftMod → app.py

Do the same change in its sd_gen_generate_pipeline(*args); the function has the same tail indexing pattern:

# add the same _as_int, _as_bool, _flags_present helpers

def sd_gen_generate_pipeline(*args):
    if _flags_present(args):
        load_lora_cpu   = _as_bool(args[-3], True)
        verbose_arg     = _as_int(args[-2], 0)
        gpu_duration_arg= _as_int(args[-1], 59)
        generation_args = args[:-3]
    else:
        load_lora_cpu   = True
        verbose_arg     = 0
        gpu_duration_arg= 59
        generation_args = args

    lora_list = [None if (item in ("None","")) else item for item in
                 [args[7], args[9], args[11], args[13], args[15], args[17], args[19]]]

    # ... unchanged ...
    yield from dynamic_gpu_duration(sd_gen.generate_pipeline, gpu_duration_arg, *generation_args)

The vulnerable lines in the Mod are identical (args[-1], args[-2], args[-3], plus args[7]..args[22]). (Hugging Face)

Optional hardening

  • Add stable API names so cURL examples stay consistent across edits: set api_name="load_new_model" and api_name="sd_gen_generate_pipeline" on the wired events. This is how Gradio exposes endpoints on the “Use via API” page. (gradio.app)

  • Publish a minimal typed endpoint that avoids positional arrays entirely:

    import gradio as gr
    
    def txt2img_api(prompt: str, model_name: str, width: int = 1024, height: int = 1024,
                    steps: int = 28, cfg: float = 7.0, seed: int = 0) -> list[str]:
        # warm model, then call your generator with fixed defaults
        for _ in sd_gen.load_new_model(model_name, "None", "txt2img", "Automatic"): pass
        # return paths or base64 as you prefer
        # ... call underlying pipeline with your defaults ...
    
    gr.api(txt2img_api, api_name="txt2img")  # creates a stable, typed REST route
    

    gr.api() generates a clean REST surface independent of GUI component order. (gradio.app)

Why this is the right lever

  • Gradio’s REST uses a positional data: [...] array defined by the component order. Manual callers often omit trailing items. Defensive tail parsing prevents accidental truncation while keeping backward compatibility. (gradio.app)

Pointers and proofs

  • DiffuseCraft handler with tail and LoRA fixed indices. (Hugging Face)
  • DiffuseCraftMod handler with the same tail pattern. (Hugging Face)
  • Gradio API exposure, event wiring, and the “Use via API” schema. (gradio.app)
  • cURL behavior for Gradio apps and positional payloads. (gradio.app)

If you also want session isolation or queue tuning, use Request.session_hash for per-session caches and concurrency_id to serialize model load and generate. Docs for both are here. (gradio.app)

Tip: after patching, open each Space’s footer → “Use via API” and verify the generation endpoint shows the same schema as before, with your new api_name and that your cURL without the last three flags now streams generating → complete, not event: error. (gradio.app)


Short, high-value references

  • Gradio “Use via API” and schema derivation from events. (gradio.app)
  • gr.api() for a typed, GUI-independent REST endpoint. (gradio.app)
  • cURL guide for Gradio REST. (gradio.app)
  • Per-session data and request metadata. (gradio.app)
  • Queue and concurrency_id. (gradio.app)

don't know. other space python api is okay, curl api error

Loaded as API: https://hysts-mistral-7b.hf.space ✔
I'm an AI and don't have the ability to sing, but here's a fun little ditty:

(Verse 1)
In a world where the sun always shines,
And the stars are just sparkling designs.
There lived a curious mind like yours and mine,
Wondering what tomorrow might find.

(Chorus)
So let your imagination fly high,
Underneath the endless sky so wide.
Reach for the moon, touch the starry tide,
For dreams are the seeds that we plant inside.

(Verse 2)
With every question, new answers unfold,
Like a story waiting to be told.
Through twists and turns, uphill or down,
Life is an adventure, not a frown.

(Bridge)
Embrace the unknown with courage and grace,
Find joy in each moment you embrace.
Remember this truth as you dance through life,
Every day brings a brand-new start, my friend,
A fresh canvas on which to expend.

(Outro)
So dream big, reach higher, explore,
Let curiosity guide you evermore!
curl -X POST https://hysts-mistral-7b.hf.space/gradio_api/call/chat -s -H "Content-Type: application/json" -d '{
    "data": [
  "sing a song",
  1,
  0.1,
  0.05,
  1,
  1
  ]}' \
        | awk -F'"' '{ print $4}'  \
        | read EVENT_ID; curl -N https://hysts-mistral-7b.hf.space/gradio_api/call/chat/$EVENT_ID
event: error
data: null

actually, that's a good idea, create a txt2img_api, img2img_api and others, instead of calling sd_gen_generate_pipeline directly (too many parameters)

Gradio's API seems extremely strict about parameter mismatches.

Yeah. When modfiying a Space for regular use as an Endpoint, it's probably safer to define a dedicated wrapper function for that Endpoint and use that. This functionality appears to exist as part of Gradio. If you want to use an existing Space as-is, I think there's a way to write a function in your own code that automatically completes missing parameters. (Client-Side Gradio API Endpoint Missing Argument Auto-Completion Helper Script?)
For r3gm and myself, some improvements might be possible on the Space side like above, but expecting that for all Spaces would be reckless...


Your cURL payload is missing the second argument that ChatInterface expects: the chat history. That shifts every value left and the handler throws, so you get event: error. Fix: include an empty list [] as the second item, then the 5 sliders in the exact order shown in the code.

Correct payload shape for this Space

data = [ message:str, history:list[dict], max_new_tokens:int, temperature:float, top_p:float, top_k:int, repetition_penalty:float ] (Hugging Face)

Working cURL

URL="https://hysts-mistral-7b.hf.space"

# simple one-shot
curl -s -X POST "$URL/gradio_api/call/chat" \
  -H "Content-Type: application/json" \
  -d '{
    "data": [
      "sing a song",
      [],
      256,
      0.7,
      0.9,
      50,
      1.2
    ]
  }' \
| awk -F'"' '{ print $4 }' | read EID
curl -N "$URL/gradio_api/call/chat/$EID"

Continuing a conversation

Build history as a list of {"role","content"} messages. The app concatenates [*history, {"role":"user","content":message}] before generation. (Hugging Face)

# assume PREV is the assistant reply you got from the first call
curl -s -X POST "$URL/gradio_api/call/chat" \
  -H "Content-Type: application/json" \
  -d '{
    "data": [
      "make it shorter",
      [
        {"role":"user","content":"sing a song"},
        {"role":"assistant","content":"'"$PREV"'"}
      ],
      128, 0.7, 0.9, 50, 1.1
    ]
  }' \
| awk -F'"' '{ print $4 }' | read EID
curl -N "$URL/gradio_api/call/chat/$EID"

Why Python “works” while cURL failed

  • The Space defines gr.ChatInterface(fn=generate, additional_inputs=[...]). That means the REST endpoint named chat requires two leading inputs: message and history, then the sliders in order. (Hugging Face)
  • The Python Gradio client builds that array for you and initializes history=[], so your call succeeds. With raw cURL you must supply it yourself. Gradio’s docs confirm the cURL API is positional and must match the component order. (gradio.app)

Common pitfalls that also yield event: error

  • Wrong argument count or order for ChatInterface (most frequent). See above. (gradio.app)
  • History uses the wrong format. With type="messages" it should be a list of {role, content} dicts. (gradio.app)
  • Posting numbers as strings that can’t coerce to required types for sliders. Keep them numeric.
  • Calling the wrong endpoint name. For ChatInterface it’s usually /chat, but confirm via the page’s Use via API. (gradio.app)
John6666 changed discussion status to closed
John6666 changed discussion status to open

Well, I took it from the api documentation, it seem gradio auto generate the wrong example. the error message is no help 😆

A dirty but (maybe) working preprocessor implementation.


Add a small pre-processor that looks up the Space’s OpenAPI spec, figures out the exact positional input list, fills in any missing trailing items with defaults, then sends the corrected curl request. This removes most “event: error” cases caused by short payloads, especially for chat UIs that also require a history parameter.

Below are two drop-in options. Pick one.


Why this works (context)

  • Gradio’s REST API expects a JSON array in {"data": [...]} with one element per input component, in order. If you omit items at the end, the server raises and you see event: error. (gradio.app)

  • Every Gradio app exposes a machine-readable OpenAPI spec at:

    <app-url>/gradio_api/openapi.json
    

    You can parse this to get the endpoint name and the full ordered input list (plus defaults). (gradio.app)

  • For chat apps (gr.ChatInterface), the first two inputs are always message then history. If you send only a message, you must still pass an empty list for history: []. (gradio.app)

  • Spaces require two requests: POST to start a job and get {"event_id": ...}, then GET the SSE stream at /call/<api_name>/<EVENT_ID> to read generating | complete | error. (gradio.app)


Option A — Bash + jq shim (portable)

This wrapper fetches OpenAPI, pads your partial data array to the expected length using documented defaults or safe fallbacks, auto-inserts [] for a missing chat history, and then performs the standard POST→SSE flow.

#!/usr/bin/env bash
# hfspace-call.sh
# deps: curl, jq
set -euo pipefail

SPACE_URL="${1:?ex: https://hysts-mistral-7b.hf.space}"
API_NAME="${2:?ex: chat}"
# user-supplied partial data array (JSON string or path to a file). optional.
PARTIAL="${3:-[]}"

# read file or take string
if [[ -f "$PARTIAL" ]]; then PARTIAL_JSON="$(cat "$PARTIAL")"; else PARTIAL_JSON="$PARTIAL"; fi

SPEC="$(curl -fsSL "${SPACE_URL%/}/gradio_api/openapi.json")"  # OpenAPI spec
EP="/gradio_api/call/${API_NAME}"

# ordered arg schemas for "data"
PARAMS_JSON="$(jq -c --arg ep "$EP" '
  .paths[$ep].post.requestBody.content["application/json"].schema.properties.data
  | ( ( .prefixItems // .items ) // [] )
' <<<"$SPEC")"

EXPECTED_N="$(jq 'length // 0' <<<"$PARAMS_JSON")"

DEFAULTS="$(jq -c '
  map( ( .default // ( .type=="array" ? [] : ( .type=="boolean" ? false : null ) ) ) )
' <<<"$PARAMS_JSON")"

# parse user array or fall back to []
USER_ARR="$(jq -c '(try fromjson catch .) as $x | if ($x|type)=="array" then $x else [] end' <<<"$PARTIAL_JSON")"

# Heuristic: if endpoint summary mentions chat and user only passed a message, inject empty history
IS_CHAT="$(jq -r --arg ep "$EP" '.paths[$ep].post.summary // "" | ascii_downcase | contains("chat")' <<<"$SPEC")"
if [[ "$IS_CHAT" == "true" ]]; then
  LEN="$(jq 'length' <<<"$USER_ARR")"
  if (( LEN == 1 )); then USER_ARR="$(jq -c '[.[0], []] + (.[2:] // [])' <<<"$USER_ARR")"; fi
fi

# pad trailing args with defaults
PADDED="$(jq -c --argjson defs "$DEFAULTS" --argjson need "$EXPECTED_N" '
  . as $u | ($need - ($u|length)) as $k
  | if $k > 0 then $u + ($defs[($u|length):$need]) else $u end
' <<<"$USER_ARR")"

BODY="$(jq -c --argjson data "$PADDED" '{data: $data}')"

# 1) POST to start the job
EID="$(curl -fsS -X POST "${SPACE_URL%/}/gradio_api/call/${API_NAME}" \
  -H 'Content-Type: application/json' -d "$BODY" | awk -F'"' '{print $4}')"

# 2) Stream results (SSE)
curl -N "${SPACE_URL%/}/gradio_api/call/${API_NAME}/${EID}"

Usage examples

# ChatInterface: only message provided; wrapper injects []
./hfspace-call.sh https://hysts-mistral-7b.hf.space chat '["sing a song"]'

# Any Blocks/Interface endpoint: pass a partial array; wrapper pads trailing args from OpenAPI
./hfspace-call.sh https://r3gm-diffusecraft.hf.space sd_gen_generate_pipeline partial.json

Why this eliminates most cURL “short payload” errors:

  • We always submit the right number of positional arguments, in order, matching the “Use via API” page. (gradio.app)
  • We respect endpoint naming via api_name, which the app controls. (gradio.app)
  • We fix the common chat mistake by inserting an empty history. (gradio.app)

Option B — Tiny Python helper (more robust typing)

Same idea as A, but easier to extend. It also adds a session_hash if you want sticky sessions. (gradio.app)

#!/usr/bin/env python3
# hfspace_call.py
import json, sys, requests, sseclient

space, api = sys.argv[1], sys.argv[2]
partial = json.loads(sys.argv[3]) if len(sys.argv) > 3 else []

spec = requests.get(f"{space.rstrip('/')}/gradio_api/openapi.json").json()
path = spec["paths"][f"/gradio_api/call/{api}"]["post"]
schema = path["requestBody"]["content"]["application/json"]["schema"]["properties"]["data"]
prefix = schema.get("prefixItems") or schema.get("items") or []
expected = len(prefix)

# If endpoint looks like chat and only message was provided, inject empty history
if ("chat" in (path.get("summary","")+path.get("operationId","")).lower()) and len(partial) == 1:
    partial = [partial[0], []]

def default_of(s):
    if "default" in s: return s["default"]
    t = s.get("type")
    return [] if t == "array" else (False if t == "boolean" else None)

filled = partial + [default_of(s) for s in prefix[len(partial):expected]]
payload = {"data": filled}
r = requests.post(f"{space.rstrip('/')}/gradio_api/call/{api}", json=payload)
eid = r.json()["event_id"]

for ev in sseclient.SSEClient(f"{space.rstrip('/')}/gradio_api/call/{api}/{eid}"):
    print(f"{ev.event}: {ev.data}")

Run

python hfspace_call.py https://hysts-mistral-7b.hf.space chat '["sing a song"]'

Practical checklist before calling any Space

  1. Use the app URL, not the Space page.
    Example: ✅ https://abidlabs-en2fr.hf.space/ not ❌ https://huggingface.co/spaces/abidlabs/en2fr. (gradio.app)

  2. Confirm the endpoint name on the “Use via API” page or from OpenAPI. It’s derived from the code’s api_name or function name. (gradio.app)

  3. Match the positional input order exactly. Your payload must have one element for each input component. (gradio.app)

  4. For ChatInterface always include history (use [] to start), then any extra sliders or options the app added as “additional inputs.” (gradio.app)

  5. POST to start → GET to stream. Expect generating, complete, error, and heartbeat events over SSE. (gradio.app)


Common failure patterns this shim prevents

  • Short arrays: missing trailing flags or sliders. The shim pads from OpenAPI defaults. (gradio.app)
  • Chat without history: you sent only the message. The shim inserts []. (gradio.app)
  • Wrong host: using the Space page URL instead of the hf.space app URL. The guide shows the correct URL. (gradio.app)

Extra resources

  • “View API” + OpenAPI for any app: where to find endpoint names, input order, defaults, and the JSON spec. (gradio.app)
  • cURL guide for Gradio: POST→SSE pattern, data is a positional list, hf.space URLs. (gradio.app)
  • ChatInterface docs: required message, history, and what “messages” format means. (gradio.app)
  • Messages format details: list of {role, content} dicts. (gradio.app)
  • Known ChatInterface API quirks: history format mismatches in some versions; reason to normalize inputs in your wrapper. (GitHub)

Use either wrapper and you can keep writing short, human-sized payloads; the script will pad and normalize them so curl requests behave like the Python client.

Ensure avoid typo.

You’re missing the second positional input the endpoint expects: history. Your array shifts left and the handler throws, so you get event: error.

What about the parameters in def sd_gen_generate_pipeline(*args): How do I check those

How do I check those

If manually, click Use via API at the bottom of the Space screen. If the auto-generated arguments are incorrect, refer to the actual function.

I don't really know python, it seems to just take an array? Can you add something similar to this https://huggingface.co/spaces/John6666/votepurchase-multiple-model/blob/main/dc.py#L824

Do you know how to enable streaming output in the python api? curl api does that, but it's not processed

example curl

event: generating
data: ["I", null]

event: complete
data: ["I", null]

how to enable streaming output in the python api?

maybe this?
https://www.gradio.app/guides/getting-started-with-the-python-client#generator-endpoints

Can you add something similar to this https://huggingface.co/spaces/John6666/votepurchase-multiple-model/blob/main/dc.py#L824

It's not impossible to create a wrapper function for Gradio APIs. There is a dedicated Gradio component (gr.api) for that purpose. However, it takes a bit of time (lots of arguments!).
Also, (well, we could duplicate and modify it ourselves...) this method has the constraint that the author themselves must create it for it to be usable.

Concept

# app.py
import gradio as gr

# 1) a small wrapper with type hints
def txt2img_api(
    model_name: str,
    prompt: str,
    negative_prompt: str = "",
    width: int = 1024,
    height: int = 1024,
    steps: int = 28,
    guidance_scale: float = 7.0,
    seed: int = 0,
):
    # Ensure model is loaded (your existing generator yields progress strings)
    for _ in sd_gen.load_new_model(model_name, "None", "txt2img", "Automatic"):
        pass

    # Call your existing generator and collect the final images.
    # If you already have an `infer(...)` wrapper, you can call that instead.
    last_imgs = None
    for _status, imgs, _task_info in sd_gen.generate_pipeline(
        prompt, negative_prompt,
        1,                # batch
        steps, guidance_scale,
        1,                # cfg_rescale or similar toggle (keep your default)
        seed,
        # ... keep passing your project’s fixed defaults here ...
        # width/height, sampler, schedule, VAE, LoRA slots -> use your usual defaults
        width, height,
        # sampler="Euler", schedule_type="Classic", schedule_prediction_type="Epsilon",
        # vae_model="None", controlnet_model="Automatic", etc.
    ):
        if imgs:
            last_imgs = imgs

    return last_imgs  # list of file paths / URLs as your fn already returns

with gr.Blocks() as demo:
    # ... your existing UI code ...

    # 2) expose a stable programmatic endpoint
    gr.api(
        txt2img_api,
        api_name="txt2img",           # stable route: /gradio_api/call/txt2img
        queue=True,                   # keep queued like the rest of your app
        concurrency_id="gpu",         # optional: share queue with other GPU ops
        concurrency_limit="default",
    )

# demo.launch()

You don't have to create a wrapper for each, just a single api like vp Infer, which does not download preview images

just a single api like vp Infer

That's a wrapper function. I just made one.

how to use generate api? 😕

can you provide the full parameters so the api documentation shows that?

prompt, negative_prompt, seed, randomize_seed, width, height, guidance_scale, num_inference_steps,
          model_name=load_diffusers_format_model[0], lora1=None, lora1_wt=1.0, lora2=None, lora2_wt=1.0,
          lora3=None, lora3_wt=1.0, lora4=None, lora4_wt=1.0, lora5=None, lora5_wt=1.0, lora6=None, lora6_wt=1.0, lora7=None, lora7_wt=1.0,
          task=TASK_MODEL_LIST[0], prompt_syntax="Classic", sampler="Euler", vae=None, schedule_type=SCHEDULE_TYPE_OPTIONS[0], schedule_prediction_type=SCHEDULE_PREDICTION_TYPE_OPTIONS[0],
          clip_skip=True, pag_scale=0.0, free_u=False, guidance_rescale=0., image_control_dict=None, image_mask=None, strength=0.35, image_resolution=1024,
          controlnet_model=DIFFUSERS_CONTROLNET_MODEL[0], control_net_output_scaling=1.0, control_net_start_threshold=0., control_net_stop_threshold=1.,
          preprocessor_name="Canny", preprocess_resolution=512, low_threshold=100, high_threshold=200,
          value_threshold=0.1, distance_threshold=0.1, recolor_gamma_correction=1., tile_blur_sigma=9,
          image_ip1_dict=None, mask_ip1=None, model_ip1="plus_face", mode_ip1="original", scale_ip1=0.7,
          image_ip2_dict=None, mask_ip2=None, model_ip2="base", mode_ip2="style", scale_ip2=0.7,
          upscaler_model_path=None, upscaler_increases_size=1.0, upscaler_tile_size=0, upscaler_tile_overlap=8, hires_steps=30, hires_denoising_strength=0.55,
          hires_sampler="Use same sampler", hires_schedule_type="Use same schedule type", hires_guidance_scale=-1, hires_prompt="", hires_negative_prompt="",
          adetailer_inpaint_only=True, adetailer_verbose=False, adetailer_sampler="Use same sampler", adetailer_active_a=False,
          prompt_ad_a="", negative_prompt_ad_a="", strength_ad_a=0.35, face_detector_ad_a=True, person_detector_ad_a=True, hand_detector_ad_a=False,
          mask_dilation_a=4, mask_blur_a=4, mask_padding_a=32, adetailer_active_b=False, prompt_ad_b="", negative_prompt_ad_b="", strength_ad_b=0.35,
          face_detector_ad_b=True, person_detector_ad_b=True, hand_detector_ad_b=False, mask_dilation_b=4, mask_blur_b=4, mask_padding_b=32,
          active_textual_inversion=False, face_restoration_model=None, face_restoration_visibility=1., face_restoration_weight=.5,
          gpu_duration=59, translate=False, recom_prompt=True

This. args is same as args for sd_gen_generate_pipeline.

API name: /generate_image Preload model then generate with full positional args. Returns final (status, images, info).
copy
from gradio_client import Client

    client = Client("John6666/DiffuseCraftMod")
    result = client.predict(
            args=...,
            model_name="...",
            vae_model="...",
            task="...",
            controlnet_model="...",
            api_name="/generate_image"
    )
    print(result)
Accepts 5 parameters:
args list[Any] Required

The input value that is provided in the "1st" Api component.

model_name str Required

The input value that is provided in the "2nd" Api component.

vae_model str Required

The input value that is provided in the "3rd" Api component.

task str Required

The input value that is provided in the "4th" Api component.

controlnet_model str Required

The input value that is provided in the "5th" Api component.

result = client.predict(
    args = [
            "Hello!!",
            "lowres, bad anatomy, bad hands, missing fingers, extra digit, fewer digits, worst quality, low quality, very displeasing, (bad)",
            1,
            5,
            7,
            False,
            -1,
            "",
            1,
            "",
            1,
            "",
            1,
            "",
            1,
            "",
            1,
            "",
            1,
            "",
            1,
            "Euler",
            "Automatic",
            "Automatic",
            1024,
            1024,
            "votepurchase/animagine-xl-3.1",
            "None",
            "txt2img",
            None,
            "Canny",
            512,
            1024,
            ["(No style)"],
            None,
            None,
            0.55,
            100,
            200,
            0.1,
            0.1,
            1,
            9,
            1,
            0,
            1,
            False,
            "Classic",
            None,
            1.2,
            0,
            8,
            30,
            0.55,
            "Use same sampler",
            "Hello!!",
            "Hello!!",
            False,
            True,
            "Use same schedule type",
            -1,
            "Automatic",
            1,
            True,
            False,
            True,
            False,
            False,
            "model,seed",
            "./images/",
            False,
            False,
            False,
            True,
            1,
            0.55,
            False,
            False,
            False,
            True,
            False,
            "Use same sampler",
            False,
            "Hello!!",
            "Hello!!",
            0.35,
            False,
            True,
            False,
            4,
            4,
            32,
            False,
            "Hello!!",
            "Hello!!",
            0.35,
            False,
            True,
            False,
            4,
            4,
            32,
            True,
            0,
            None,
            None,
            "plus_face",
            "original",
            0.7,
            None,
            None,
            "base",
            "style",
            0.7,
            0,
            None,
            1,
            0.5,
            False,
            False,
            20
      ],
      model_name="votepurchase/animagine-xl-3.1",
      vae_model="None",
      task="txt2img",
      controlnet_model="Automatic",
      api_name="/generate_image"
)

gradio_client.exceptions.AppError: Api.init() got an unexpected keyword argument 'render'

Hmm... This can generally be categorized into two cases: when the argument passing method (positional or keyword arguments) is incorrect, and when Gradio 5 cannot be installed due to Python 3.9.


Your Python client is older than the server. The server (new Gradio) emits OpenAPI fields like render. Your gradio_client doesn’t know that field and crashes while initializing the endpoint schema, hence:

gradio_client.exceptions.AppError: Api.init() got an unexpected keyword argument 'render'

Fix and verify:

  1. Upgrade the client
python -V              # use 3.10+
pip install -U gradio_client

Gradio 5 introduced render and other metadata; old clients can’t parse them. Unexpected-keyword errors on fields like api_mode/render are a classic version mismatch symptom. (gradio.app)

  1. Confirm the endpoint and argument names
    Open the app’s View API and inspect /gradio_api/call/generate_image. It shows the exact parameter order and names the client must use. (gradio.app)

  2. Call with the correct signature
    Your endpoint was defined as:

def generate_minimal(args, model_name, vae_model, task, controlnet_model): ...

Pass either positional args or matching keyword args, and always set api_name="/generate_image". Both forms are supported by the client. (gradio.app)

Working Python call (positional)

from gradio_client import Client
client = Client("https://<your-space>.hf.space")

result = client.predict(
    [/* full positional array for sd_gen_generate_pipeline */],
    "votepurchase/animagine-xl-3.1",
    "None",
    "txt2img",
    "Automatic",
    api_name="/generate_image",
)

The client’s predict pattern and api_name usage are documented here. (gradio.app)

Working Python call (keywords)

result = client.predict(
    args=[/* full array */],
    model_name="votepurchase/animagine-xl-3.1",
    vae_model="None",
    task="txt2img",
    controlnet_model="Automatic",
    api_name="/generate_image",
)

Keyword arguments must match the function’s parameter names. The client maps them to the server’s schema. (Hugging Face)

If you want streaming in Python

Use submit() and iterate the returned job; this mirrors cURL’s SSE. (gradio.app)

job = client.submit(
    [/* full array */], "votepurchase/animagine-xl-3.1", "None", "txt2img", "Automatic",
    api_name="/generate_image",
)
for chunk in job:
    print(chunk)

Quick checklist

  • Client updated to latest. (PyPI)
  • api_name includes the leading slash: "/generate_image". (gradio.app)
  • Parameters provided as documented on View API/OpenAPI. (gradio.app)

These changes remove the Api.init(..., render=...) failure and make your generate_image endpoint callable from the Python client.

python -V
Python 3.12.12
pip install -U gradio_client
Requirement already satisfied: gradio_client in /usr/lib/python3.12/site-packages (1.13.3)
....

can you just do it similar to vp infer? It's works and has named arguments. sorry if I'm being bit annoying 😆

from gradio_client import Client, handle_file

from huggingface_hub import login
login("hf_")

client = Client("John6666/votepurchase-multiple-model")
result = client.predict(
    prompt="Hello!!",
    negative_prompt="(low quality, worst quality:1.2), very displeasing, watermark, signature, ugly",
    seed=0,
    randomize_seed=True,
    width=1024,
    height=1024,
    guidance_scale=7,
    num_inference_steps=28,
    model_name="cagliostrolab/animagine-xl-4.0",
    lora1="",
    lora1_wt=1,
    lora2="",
    lora2_wt=1,
    lora3="",
    lora3_wt=1,
    lora4="",
    lora4_wt=1,
    lora5="",
    lora5_wt=1,
    lora6="",
    lora6_wt=1,
    lora7="",
    lora7_wt=1,
    task="txt2img",
    prompt_syntax="Classic",
    sampler="Euler",
    vae="None",
    schedule_type="Automatic",
    schedule_prediction_type="Automatic",
    clip_skip=True,
    pag_scale=0,
    free_u=False,
    guidance_rescale=0,
    image_control_dict=None,
    image_mask=None,
    strength=0.55,
    image_resolution=1024,
    controlnet_model="Automatic",
    control_net_output_scaling=1,
    control_net_start_threshold=0,
    control_net_stop_threshold=1,
    preprocessor_name="Canny",
    preprocess_resolution=512,
    low_threshold=100,
    high_threshold=200,
    value_threshold=0.1,
    distance_threshold=0.1,
    recolor_gamma_correction=1,
    tile_blur_sigma=9,
    image_ip1_dict=None,
    mask_ip1=None,
    model_ip1="plus_face",
    mode_ip1="original",
    scale_ip1=0.7,
    image_ip2_dict=None,
    mask_ip2=None,
    model_ip2="base",
    mode_ip2="style",
    scale_ip2=0.7,
    upscaler_model_path=None,
    upscaler_increases_size=1.2,
    upscaler_tile_size=0,
    upscaler_tile_overlap=8,
    hires_steps=30,
    hires_denoising_strength=0.55,
    hires_sampler="Use same sampler",
    hires_schedule_type="Use same schedule type",
    hires_guidance_scale=-1,
    hires_prompt="Hello!!",
    hires_negative_prompt="Hello!!",
    adetailer_inpaint_only=True,
    adetailer_verbose=False,
    adetailer_sampler="Use same sampler",
    adetailer_active_a=False,
    prompt_ad_a="Hello!!",
    negative_prompt_ad_a="Hello!!",
    strength_ad_a=0.35,
    face_detector_ad_a=False,
    person_detector_ad_a=True,
    hand_detector_ad_a=False,
    mask_dilation_a=4,
    mask_blur_a=4,
    mask_padding_a=32,
    adetailer_active_b=False,
    prompt_ad_b="Hello!!",
    negative_prompt_ad_b="Hello!!",
    strength_ad_b=0.35,
    face_detector_ad_b=False,
    person_detector_ad_b=True,
    hand_detector_ad_b=False,
    mask_dilation_b=4,
    mask_blur_b=4,
    mask_padding_b=32,
    active_textual_inversion=False,
    face_restoration_model=None,
    face_restoration_visibility=1,
    face_restoration_weight=0.5,
    gpu_duration=20,
    translate=False,
    recom_prompt=True,
    api_name="/infer"
)
print(result)

can you just do it similar to vp infer?

Implemented generate_image and generate_image_stream. For maintenance reasons, the argument order was aligned with DiffuseCraft.

Sign up or log in to comment