
Hugging Face Space에서 gradio_client로 API를 호출하려고 했는데,
Client() 선언만 했는데도 JSONDecodeError가 났다.
from gradio_client.client import Client
client = Client(src="**/space", hf_token="hf_*******")
에러
JSONDecodeError: Expecting value: line 1 column 1 (char 0)
응답이 빈 문자열이라 JSON 파싱이 안 됐다.
r.text 자체가 ''로 비어 있었다.
원인
gradio_client 내부에서 API 정보를 불러올 때 URL이 이렇게 되어 있다.
API_INFO_URL = "info?all_endpoints=True"
그런데 Gradio 최신 버전에서는 /info가 아니라 /gradio_api/info를 써야 한다.
즉, 버전이 달라서 잘못된 경로를 호출하게 된 거다.
그래서 r.json()에서 JSONDecodeError가 발생했다.
해결
내부 코드를 직접 바꾸려니 온갖 함수와 상속관계를 다 풀어내야해서
wrapper 클래스를 하나 만들었다.
/config에서 api_prefix(/gradio_api)를 읽어올 수 있길래 지정하고
그 경로로 /info를 다시 호출하도록 했다.
import httpx
from typing import Any
from pathlib import Path
class SafeClient:
def __init__(
self,
src: str,
hf_token=None,
*,
headers=None,
ssl_verify: bool = True,
download_files: str | Path = "/tmp",
):
self.src = src.rstrip("/")
self.hf_token = hf_token
self.ssl_verify = ssl_verify
self.headers = headers or {"User-Agent": "safe-gradio-client/0.1"}
if hf_token:
self.headers["Authorization"] = f"Bearer {hf_token}"
self.download_files = download_files
# config에서 api_prefix 확인
config = self._fetch_json(f"{self.src}/config")
self.api_prefix = config.get("api_prefix", "")
self.enable_queue = config.get("enable_queue", False)
# info 호출
info_url = f"{self.src}{self.api_prefix}/info"
self._info = self._fetch_json(info_url) or {
"named_endpoints": {},
"unnamed_endpoints": []
}
def _fetch_json(self, url: str) -> dict[str, Any]:
try:
r = httpx.get(url, headers=self.headers, verify=self.ssl_verify, timeout=10)
if r.status_code == 200 and "application/json" in r.headers.get("content-type", ""):
return r.json()
except Exception:
pass
return {}
def view_api(self) -> dict[str, Any]:
return self._info
def predict(self, *inputs, api_name="/predict"):
base = f"{self.src}{self.api_prefix}"
if self.enable_queue:
url = f"{base}/queue/join"
else:
url = f"{base}/predict/"
payload = {"data": list(inputs)}
r = httpx.post(url, headers=self.headers, json=payload, verify=self.ssl_verify, timeout=120)
try:
return r.json()
except Exception:
return {"error": "Invalid JSON response", "raw": r.text[:500]}
사용 예시
client = SafeClient(src="org/space-app", hf_token="hf_***")
print(client.view_api())
result = client.predict("/api-test")
print(result)
3줄요약
Gradio API 경로가 /info → /gradio_api/info로 바뀜
기존 gradio_client는 하드코딩된 경로라서 깨짐
SafeClient로 api_prefix 자동 감지해서 해결
queue 모드(enable_queue=True)도 정상 작동
필요하면 나중에 gradio_client에 PR 넣을 생각.
지금은 그냥 이 wrapper로 쓰는 게 제일 편하다.