schroneko commited on
Commit
a85df97
·
1 Parent(s): f5c4221

Use direct ZeroGPU queue for synthesis

Browse files
Files changed (2) hide show
  1. app.py +73 -18
  2. requirements.txt +0 -1
app.py CHANGED
@@ -1,6 +1,7 @@
1
  from __future__ import annotations
2
 
3
  import hashlib
 
4
  import os
5
  import shutil
6
  import time
@@ -11,7 +12,6 @@ from typing import Any
11
  import requests
12
  from fastapi import FastAPI, HTTPException, Query, Request
13
  from fastapi.responses import FileResponse, JSONResponse
14
- from gradio_client import Client
15
 
16
  ZERO_SPACE = os.getenv("ZERO_SPACE", "schroneko/irodori-tts-zerogpu")
17
  HF_TOKEN = os.getenv("HF_TOKEN", "")
@@ -53,16 +53,70 @@ def _seed_for_speaker(speaker: str) -> str:
53
  return str(value)
54
 
55
 
56
- def _zero_client(x_ip_token: str = "") -> Client:
57
- headers: dict[str, str] = {}
 
 
 
 
 
 
 
58
  if HF_TOKEN:
59
  headers["Authorization"] = f"Bearer {HF_TOKEN}"
60
  if x_ip_token:
61
  headers["x-ip-token"] = x_ip_token
62
- return Client(ZERO_SPACE, token=HF_TOKEN or None, headers=headers)
 
 
 
 
 
 
 
63
 
64
 
65
- def _copy_result_file(result: Any) -> Path:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
66
  source: str | None = None
67
  if isinstance(result, (list, tuple)) and result:
68
  source = result[0]
@@ -79,9 +133,8 @@ def _copy_result_file(result: Any) -> Path:
79
  output_path = OUTPUT_DIR / f"{int(time.time() * 1000)}_{uuid.uuid4().hex}.mp3"
80
  source_text = str(source)
81
  if source_text.startswith("http://") or source_text.startswith("https://"):
82
- response = requests.get(source_text, timeout=60)
83
- if not response.ok:
84
- raise RuntimeError(f"Generated audio download failed: {response.status_code} {response.text.strip()}")
85
  output_path.write_bytes(response.content)
86
  return output_path
87
 
@@ -139,18 +192,20 @@ def synthesis(
139
  try:
140
  x_ip_token = request.headers.get("x-ip-token", "").strip()
141
  seed_value = str(seed).strip() or _seed_for_speaker(str(speaker))
142
- result = _zero_client(x_ip_token).predict(
143
- text=text,
144
- speaker=str(speaker),
145
- seconds=str(seconds),
146
- duration_scale=float(duration_scale),
147
- steps=int(steps),
148
- seed=seed_value,
149
- caption=str(caption).strip() or DEFAULT_CAPTION,
150
- api_name="/synthesize",
 
 
151
  )
152
  metadata = _result_metadata(result)
153
- output_path = _copy_result_file(result)
154
  except Exception as exc:
155
  return JSONResponse(
156
  status_code=502,
 
1
  from __future__ import annotations
2
 
3
  import hashlib
4
+ import json
5
  import os
6
  import shutil
7
  import time
 
12
  import requests
13
  from fastapi import FastAPI, HTTPException, Query, Request
14
  from fastapi.responses import FileResponse, JSONResponse
 
15
 
16
  ZERO_SPACE = os.getenv("ZERO_SPACE", "schroneko/irodori-tts-zerogpu")
17
  HF_TOKEN = os.getenv("HF_TOKEN", "")
 
53
  return str(value)
54
 
55
 
56
+ def _zero_space_base_url() -> str:
57
+ space = ZERO_SPACE.strip().rstrip("/")
58
+ if space.startswith("http://") or space.startswith("https://"):
59
+ return space
60
+ return f"https://{space.replace('/', '-')}.hf.space"
61
+
62
+
63
+ def _zero_headers(x_ip_token: str = "") -> dict[str, str]:
64
+ headers = {"Content-Type": "application/json"}
65
  if HF_TOKEN:
66
  headers["Authorization"] = f"Bearer {HF_TOKEN}"
67
  if x_ip_token:
68
  headers["x-ip-token"] = x_ip_token
69
+ return headers
70
+
71
+
72
+ def _raise_for_response(response: requests.Response) -> None:
73
+ if response.ok:
74
+ return
75
+ detail = response.text.strip()
76
+ raise RuntimeError(f"ZeroGPU request failed: {response.status_code} {detail}")
77
 
78
 
79
+ def _predict_zero_space(payload: dict[str, Any], x_ip_token: str = "") -> Any:
80
+ base_url = _zero_space_base_url()
81
+ response = requests.post(
82
+ f"{base_url}/gradio_api/call/v2/synthesize",
83
+ json=payload,
84
+ headers=_zero_headers(x_ip_token),
85
+ timeout=30,
86
+ )
87
+ _raise_for_response(response)
88
+ event_id = response.json().get("event_id")
89
+ if not event_id:
90
+ raise RuntimeError(f"ZeroGPU did not return event_id: {response.text}")
91
+
92
+ response = requests.get(
93
+ f"{base_url}/gradio_api/call/synthesize/{event_id}",
94
+ headers=_zero_headers(x_ip_token),
95
+ stream=True,
96
+ timeout=(10, 300),
97
+ )
98
+ _raise_for_response(response)
99
+
100
+ event_name = ""
101
+ for line in response.iter_lines(decode_unicode=True):
102
+ if not line:
103
+ continue
104
+ if line.startswith("event:"):
105
+ event_name = line.split(":", 1)[1].strip()
106
+ continue
107
+ if not line.startswith("data:"):
108
+ continue
109
+ data = line.split(":", 1)[1].strip()
110
+ if event_name == "error":
111
+ raise RuntimeError(data)
112
+ parsed = json.loads(data)
113
+ if event_name == "complete":
114
+ return parsed
115
+
116
+ raise RuntimeError("ZeroGPU stream ended before completion")
117
+
118
+
119
+ def _copy_result_file(result: Any, x_ip_token: str = "") -> Path:
120
  source: str | None = None
121
  if isinstance(result, (list, tuple)) and result:
122
  source = result[0]
 
133
  output_path = OUTPUT_DIR / f"{int(time.time() * 1000)}_{uuid.uuid4().hex}.mp3"
134
  source_text = str(source)
135
  if source_text.startswith("http://") or source_text.startswith("https://"):
136
+ response = requests.get(source_text, headers=_zero_headers(x_ip_token), timeout=60)
137
+ _raise_for_response(response)
 
138
  output_path.write_bytes(response.content)
139
  return output_path
140
 
 
192
  try:
193
  x_ip_token = request.headers.get("x-ip-token", "").strip()
194
  seed_value = str(seed).strip() or _seed_for_speaker(str(speaker))
195
+ result = _predict_zero_space(
196
+ {
197
+ "text": text,
198
+ "speaker": str(speaker),
199
+ "seconds": str(seconds),
200
+ "duration_scale": float(duration_scale),
201
+ "steps": int(steps),
202
+ "seed": seed_value,
203
+ "caption": str(caption).strip() or DEFAULT_CAPTION,
204
+ },
205
+ x_ip_token=x_ip_token,
206
  )
207
  metadata = _result_metadata(result)
208
+ output_path = _copy_result_file(result, x_ip_token=x_ip_token)
209
  except Exception as exc:
210
  return JSONResponse(
211
  status_code=502,
requirements.txt CHANGED
@@ -1,4 +1,3 @@
1
  fastapi>=0.115.0
2
  uvicorn[standard]>=0.30.0
3
- gradio_client>=2.5.0
4
  requests>=2.32.0
 
1
  fastapi>=0.115.0
2
  uvicorn[standard]>=0.30.0
 
3
  requests>=2.32.0