cazyundee commited on
Commit
f889c8e
·
verified ·
1 Parent(s): 62b3862

Minimal baseline to confirm RUNNING state

Browse files
Files changed (1) hide show
  1. app.py +15 -93
app.py CHANGED
@@ -7,27 +7,20 @@ import torch
7
  import torchaudio
8
  import gradio as gr
9
  import spaces
10
- from fastapi.responses import JSONResponse
11
- from einops import rearrange
12
- from huggingface_hub import login
13
- from stable_audio_3 import StableAudioModel
14
 
15
- # Hugging Face Spaces should use UTF-8; explicitly configure streams so model
16
- # libraries cannot inherit a platform-specific charmap encoding.
17
  for _stream in (sys.stdout, sys.stderr):
18
  if hasattr(_stream, "reconfigure"):
19
  _stream.reconfigure(encoding="utf-8", errors="backslashreplace")
20
 
21
- # Authenticate with gated model when HF_TOKEN secret is present
 
 
 
 
22
  hf_token = os.environ.get("HF_TOKEN")
23
  if hf_token:
24
  login(token=hf_token)
25
 
26
-
27
- # ZeroGPU Spaces refuse to start if no @spaces.GPU function is ever called, but
28
- # every call into a GPU function burns quota. So call this exactly ONCE at boot
29
- # with the smallest budget (1s), and keep all real generation on CPU below
30
- # (NOT decorated). That way quota is only touched here, never per request.
31
  try:
32
  @spaces.GPU(duration=1)
33
  def _gpu_startup_touch():
@@ -52,10 +45,6 @@ def _get_ram_bytes():
52
  return None
53
 
54
 
55
- # ---------------------------------------------------------------------------
56
- # API metadata
57
- # ---------------------------------------------------------------------------
58
-
59
  API_RESOURCES = {
60
  "audio_generation": {
61
  "name": "Audio generation",
@@ -78,11 +67,11 @@ API_SPECS = {
78
  "name": "Respite API",
79
  "version": "1.0.0",
80
  "description": "General-purpose AI API server with audio generation capabilities.",
81
- "base_path": "/respite",
82
  "authentication": "none",
83
  "content_types": ["application/json", "audio/wav"],
84
- "resources_endpoint": "/respite/resources",
85
- "specs_endpoint": "/respite/specs",
86
  "limits": {
87
  "max_concurrent_requests": 1,
88
  "max_queue_size": 4,
@@ -104,15 +93,10 @@ def _get_runtime_specs():
104
  }
105
 
106
 
107
- # ---------------------------------------------------------------------------
108
- # Model cache
109
- # ---------------------------------------------------------------------------
110
-
111
  MODEL_CACHE = {}
112
 
113
 
114
  def load_model(model_name):
115
- """Load model on demand and cache it."""
116
  if model_name not in MODEL_CACHE:
117
  _log(f"Loading {model_name} model...")
118
  model = StableAudioModel.from_pretrained(model_name, device="cpu")
@@ -121,31 +105,18 @@ def load_model(model_name):
121
  return MODEL_CACHE[model_name]
122
 
123
 
124
- # Model loading is lazy: startup must remain healthy even when a model download
125
- # or initialization fails. The first generation request loads the selected model.
126
-
127
-
128
  def generate_audio(prompt, duration, steps, cfg_scale, seed, model_name):
129
  _log(
130
  f"Generating with {model_name}: prompt='{prompt}', "
131
  f"duration={duration}s, steps={steps}, cfg={cfg_scale}, seed={seed}"
132
  )
133
-
134
  model = load_model(model_name)
135
-
136
  audio = model.generate(
137
- prompt=prompt,
138
- duration=duration,
139
- steps=steps,
140
- cfg_scale=cfg_scale,
141
- seed=seed,
142
- batch_size=1,
143
  )
144
-
145
- # Post-process: (batch, channels, samples) -> stereo waveform
146
  audio = rearrange(audio, "b d n -> d (b n)")
147
  audio = audio.to(torch.float32).clamp(-1, 1).mul(32767).to(torch.int16).cpu()
148
-
149
  output_path = os.path.join(
150
  tempfile.gettempdir(),
151
  f"stable_audio_{seed}_{hash(prompt) & 0xFFFFFFFF:08x}.wav",
@@ -155,10 +126,6 @@ def generate_audio(prompt, duration, steps, cfg_scale, seed, model_name):
155
  return output_path
156
 
157
 
158
- # ---------------------------------------------------------------------------
159
- # Gradio UI
160
- # ---------------------------------------------------------------------------
161
-
162
  with gr.Blocks(title="Respite API") as demo:
163
  gr.Markdown("# Respite API - Music & SFX Generation")
164
  gr.Markdown(
@@ -170,23 +137,16 @@ with gr.Blocks(title="Respite API") as demo:
170
  with gr.Column():
171
  model_name = gr.Dropdown(
172
  choices=["small-music", "small-sfx"],
173
- value="small-music",
174
- label="Model",
175
  )
176
  prompt = gr.Textbox(
177
  label="Prompt",
178
  placeholder="Describe the music or sound effect you want to generate...",
179
  lines=2,
180
  )
181
- duration = gr.Slider(
182
- minimum=1, maximum=120, value=30, step=1, label="Duration (seconds)"
183
- )
184
- steps = gr.Slider(
185
- minimum=1, maximum=50, value=8, step=1, label="Steps"
186
- )
187
- cfg_scale = gr.Slider(
188
- minimum=0.0, maximum=10.0, value=1.0, step=0.1, label="CFG Scale"
189
- )
190
  seed = gr.Number(value=-1, label="Seed (-1 for random)")
191
  btn = gr.Button("Generate", variant="primary")
192
 
@@ -200,43 +160,5 @@ with gr.Blocks(title="Respite API") as demo:
200
  )
201
 
202
 
203
- # ---------------------------------------------------------------------------
204
- # API discovery endpoints
205
- #
206
- # Use /respite/ prefix instead of /api/ to avoid collision with Gradio's
207
- # internal /api proxy which intercepts all /api/* requests in the
208
- # sdk:gradio Spaces runtime.
209
- # ---------------------------------------------------------------------------
210
-
211
  demo.queue(max_size=4, default_concurrency_limit=1)
212
-
213
- # These decorators run at import time. demo.app is the FastAPI instance
214
- # underlying the Gradio Blocks. Routes registered here will be served
215
- # alongside the Gradio UI once the server starts.
216
- # NOTE: demo.app is created lazily by Gradio, so we use a startup hook
217
- # to register routes after the server is ready.
218
- import threading
219
-
220
- def _register_routes():
221
- # Wait for demo.app to be available (created during launch)
222
- import time
223
- for _ in range(30):
224
- if hasattr(demo, "app") and demo.app is not None:
225
- break
226
- time.sleep(1)
227
-
228
- if not hasattr(demo, "app") or demo.app is None:
229
- _log("Warning: demo.app not available, API routes not registered")
230
- return
231
-
232
- @demo.app.get("/respite/resources")
233
- def resources():
234
- return JSONResponse({"resources": API_RESOURCES})
235
-
236
- @demo.app.get("/respite/specs")
237
- def specs():
238
- return JSONResponse({**API_SPECS, "runtime": _get_runtime_specs()})
239
-
240
- _log("API routes registered at /respite/resources and /respite/specs")
241
-
242
- threading.Thread(target=_register_routes, daemon=True).start()
 
7
  import torchaudio
8
  import gradio as gr
9
  import spaces
 
 
 
 
10
 
 
 
11
  for _stream in (sys.stdout, sys.stderr):
12
  if hasattr(_stream, "reconfigure"):
13
  _stream.reconfigure(encoding="utf-8", errors="backslashreplace")
14
 
15
+ from fastapi.responses import JSONResponse
16
+ from einops import rearrange
17
+ from huggingface_hub import login
18
+ from stable_audio_3 import StableAudioModel
19
+
20
  hf_token = os.environ.get("HF_TOKEN")
21
  if hf_token:
22
  login(token=hf_token)
23
 
 
 
 
 
 
24
  try:
25
  @spaces.GPU(duration=1)
26
  def _gpu_startup_touch():
 
45
  return None
46
 
47
 
 
 
 
 
48
  API_RESOURCES = {
49
  "audio_generation": {
50
  "name": "Audio generation",
 
67
  "name": "Respite API",
68
  "version": "1.0.0",
69
  "description": "General-purpose AI API server with audio generation capabilities.",
70
+ "base_path": "/api",
71
  "authentication": "none",
72
  "content_types": ["application/json", "audio/wav"],
73
+ "resources_endpoint": "/api/resources",
74
+ "specs_endpoint": "/api/specs",
75
  "limits": {
76
  "max_concurrent_requests": 1,
77
  "max_queue_size": 4,
 
93
  }
94
 
95
 
 
 
 
 
96
  MODEL_CACHE = {}
97
 
98
 
99
  def load_model(model_name):
 
100
  if model_name not in MODEL_CACHE:
101
  _log(f"Loading {model_name} model...")
102
  model = StableAudioModel.from_pretrained(model_name, device="cpu")
 
105
  return MODEL_CACHE[model_name]
106
 
107
 
 
 
 
 
108
  def generate_audio(prompt, duration, steps, cfg_scale, seed, model_name):
109
  _log(
110
  f"Generating with {model_name}: prompt='{prompt}', "
111
  f"duration={duration}s, steps={steps}, cfg={cfg_scale}, seed={seed}"
112
  )
 
113
  model = load_model(model_name)
 
114
  audio = model.generate(
115
+ prompt=prompt, duration=duration, steps=steps,
116
+ cfg_scale=cfg_scale, seed=seed, batch_size=1,
 
 
 
 
117
  )
 
 
118
  audio = rearrange(audio, "b d n -> d (b n)")
119
  audio = audio.to(torch.float32).clamp(-1, 1).mul(32767).to(torch.int16).cpu()
 
120
  output_path = os.path.join(
121
  tempfile.gettempdir(),
122
  f"stable_audio_{seed}_{hash(prompt) & 0xFFFFFFFF:08x}.wav",
 
126
  return output_path
127
 
128
 
 
 
 
 
129
  with gr.Blocks(title="Respite API") as demo:
130
  gr.Markdown("# Respite API - Music & SFX Generation")
131
  gr.Markdown(
 
137
  with gr.Column():
138
  model_name = gr.Dropdown(
139
  choices=["small-music", "small-sfx"],
140
+ value="small-music", label="Model",
 
141
  )
142
  prompt = gr.Textbox(
143
  label="Prompt",
144
  placeholder="Describe the music or sound effect you want to generate...",
145
  lines=2,
146
  )
147
+ duration = gr.Slider(minimum=1, maximum=120, value=30, step=1, label="Duration (seconds)")
148
+ steps = gr.Slider(minimum=1, maximum=50, value=8, step=1, label="Steps")
149
+ cfg_scale = gr.Slider(minimum=0.0, maximum=10.0, value=1.0, step=0.1, label="CFG Scale")
 
 
 
 
 
 
150
  seed = gr.Number(value=-1, label="Seed (-1 for random)")
151
  btn = gr.Button("Generate", variant="primary")
152
 
 
160
  )
161
 
162
 
163
+ # This is the only thing that matters for the HF Gradio runner.
 
 
 
 
 
 
 
164
  demo.queue(max_size=4, default_concurrency_limit=1)