cazyundee commited on
Commit
765d388
·
verified ·
1 Parent(s): 38ffac8

Upload README.md with huggingface_hub

Browse files
Files changed (1) hide show
  1. README.md +200 -35
README.md CHANGED
@@ -1,50 +1,215 @@
1
- ---
2
- title: Respite API
3
- emoji: 🤖
4
- colorFrom: purple
5
- colorTo: blue
6
- sdk: gradio
7
- sdk_version: 6.3.0
8
- app_file: app.py
9
- pinned: false
10
- ---
 
 
 
 
 
11
 
12
- # Respite API
 
 
13
 
14
- A CPU-based Hugging Face Space for generating music using [Stability AI's Stable Audio 3](https://github.com/Stability-AI/stable-audio-3) Small model.
 
 
15
 
16
- ## Features
17
 
18
- - **Model**: `small-music` (433M parameters)
19
- - **Duration**: 1–120 seconds
20
- - **Sample rate**: 44.1 kHz stereo
21
- - **Runs on CPU** (only a 1s ZeroGPU touch at startup; no GPU quota used per request)
22
- - Gradio 6.3.0 interface
23
 
24
- This Space is configured for CPU inference. ZeroGPU Spaces fail to boot unless at least one `spaces.GPU` function is called, so `app.py` calls one minimal `@spaces.GPU(duration=1)` function a single time at startup. Keep every other function (especially generation) undecorated so no GPU allocation happens per request.
 
25
 
26
- ## API discovery endpoints
27
 
28
- Respite API exposes machine-readable API metadata alongside the Gradio UI:
 
 
 
 
 
 
 
 
29
 
30
- - `GET /api/resources` lists callable capabilities, including each resource's method, endpoint, inputs, and output.
31
- - `GET /api/specs` lists server-wide specifications such as version, supported content types, limits, discovery URLs, CPU cores, total RAM, and storage total/used/free space.
32
 
33
- Both endpoints return JSON and currently require no authentication. The metadata is designed to grow as additional AI capabilities are added.
 
 
34
 
35
- ## Usage
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36
 
37
- 1. Enter a text prompt describing the music you want
38
- 2. Adjust duration, steps, CFG scale, and seed
39
- 3. Click **Generate** and wait for the audio
 
 
 
 
 
 
 
 
 
 
 
 
40
 
41
- ## Setup
42
 
43
- ```bash
44
- pip install -r requirements.txt
45
- python app.py
46
- ```
 
 
 
 
 
 
 
47
 
48
- ## License
49
 
50
- This project uses the Stable Audio 3 model. Please refer to Stability AI's [license](https://huggingface.co/stabilityai/stable-audio-3-small) for usage terms.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import platform
3
+ import sys
4
+ import shutil
5
+ import tempfile
6
+ import traceback
7
+ import torch
8
+ import torchaudio
9
+ import gradio as gr
10
+ import spaces
11
+ from fastapi import FastAPI
12
+ from fastapi.responses import JSONResponse
13
+ from einops import rearrange
14
+ from huggingface_hub import login
15
+ from stable_audio_3 import StableAudioModel
16
 
17
+ for _stream in (sys.stdout, sys.stderr):
18
+ if hasattr(_stream, "reconfigure"):
19
+ _stream.reconfigure(encoding="utf-8", errors="backslashreplace")
20
 
21
+ hf_token = os.environ.get("HF_TOKEN")
22
+ if hf_token:
23
+ login(token=hf_token)
24
 
25
+ # GPU touch removed — it was timing out and crashing the Space build.
26
 
 
 
 
 
 
27
 
28
+ def _log(message):
29
+ print(message.encode("ascii", "backslashreplace").decode("ascii"), flush=True)
30
 
 
31
 
32
+ def _get_ram_bytes():
33
+ try:
34
+ with open("/proc/meminfo", "r", encoding="utf-8") as meminfo:
35
+ for line in meminfo:
36
+ if line.startswith("MemTotal:"):
37
+ return int(line.split()[1]) * 1024
38
+ except (FileNotFoundError, OSError, ValueError):
39
+ pass
40
+ return None
41
 
 
 
42
 
43
+ # ---------------------------------------------------------------------------
44
+ # API metadata
45
+ # ---------------------------------------------------------------------------
46
 
47
+ API_RESOURCES = {
48
+ "audio_generation": {
49
+ "name": "Audio generation",
50
+ "description": "Generate music or sound effects from a text prompt.",
51
+ "endpoint": "/api/audio/generate",
52
+ "method": "POST",
53
+ "input": {
54
+ "prompt": "string",
55
+ "duration": "number (1-120 seconds)",
56
+ "steps": "integer (1-50)",
57
+ "cfg_scale": "number (0-10)",
58
+ "seed": "integer (-1 for random)",
59
+ "model": "small-music | small-sfx",
60
+ },
61
+ "output": "WAV audio file",
62
+ }
63
+ }
64
 
65
+ API_SPECS = {
66
+ "name": "Respite API",
67
+ "version": "1.0.0",
68
+ "description": "General-purpose AI API server with audio generation capabilities.",
69
+ "base_path": "/respite",
70
+ "authentication": "none",
71
+ "content_types": ["application/json", "audio/wav"],
72
+ "resources_endpoint": "/respite/resources",
73
+ "specs_endpoint": "/respite/specs",
74
+ "limits": {
75
+ "max_concurrent_requests": 1,
76
+ "max_queue_size": 4,
77
+ "audio_max_duration_seconds": 120,
78
+ },
79
+ }
80
 
 
81
 
82
+ def _get_runtime_specs():
83
+ storage = shutil.disk_usage(os.getcwd())
84
+ return {
85
+ "platform": platform.platform(),
86
+ "python_version": platform.python_version(),
87
+ "cpu_cores": os.cpu_count(),
88
+ "ram_bytes": _get_ram_bytes(),
89
+ "storage_total_bytes": storage.total,
90
+ "storage_used_bytes": storage.used,
91
+ "storage_free_bytes": storage.free,
92
+ }
93
 
 
94
 
95
+ # ---------------------------------------------------------------------------
96
+ # Model cache
97
+ # ---------------------------------------------------------------------------
98
+
99
+ MODEL_CACHE = {}
100
+
101
+
102
+ def load_model(model_name):
103
+ if model_name not in MODEL_CACHE:
104
+ _log(f"Loading {model_name} model...")
105
+ model = StableAudioModel.from_pretrained(model_name, device="cpu")
106
+ MODEL_CACHE[model_name] = model
107
+ _log(f"{model_name} loaded successfully!")
108
+ return MODEL_CACHE[model_name]
109
+
110
+
111
+ def generate_audio(prompt, duration, steps, cfg_scale, seed, model_name):
112
+ _log(
113
+ f"Generating with {model_name}: prompt='{prompt}', "
114
+ f"duration={duration}s, steps={steps}, cfg={cfg_scale}, seed={seed}"
115
+ )
116
+ model = load_model(model_name)
117
+ audio = model.generate(
118
+ prompt=prompt, duration=duration, steps=steps,
119
+ cfg_scale=cfg_scale, seed=seed, batch_size=1,
120
+ )
121
+ audio = rearrange(audio, "b d n -> d (b n)")
122
+ audio = audio.to(torch.float32).clamp(-1, 1).mul(32767).to(torch.int16).cpu()
123
+ output_path = os.path.join(
124
+ tempfile.gettempdir(),
125
+ f"stable_audio_{seed}_{hash(prompt) & 0xFFFFFFFF:08x}.wav",
126
+ )
127
+ torchaudio.save(output_path, audio, 44100)
128
+ _log("Generation complete!")
129
+ return output_path
130
+
131
+
132
+ # ---------------------------------------------------------------------------
133
+ # Gradio UI
134
+ # ---------------------------------------------------------------------------
135
+
136
+ with gr.Blocks(title="Respite API") as demo:
137
+ gr.Markdown("# Respite API - Music & SFX Generation")
138
+ gr.Markdown(
139
+ "Generate music and sound effects using "
140
+ "Stability AI's Stable Audio 3 Small models."
141
+ )
142
+
143
+ with gr.Row():
144
+ with gr.Column():
145
+ model_name = gr.Dropdown(
146
+ choices=["small-music", "small-sfx"],
147
+ value="small-music", label="Model",
148
+ )
149
+ prompt = gr.Textbox(
150
+ label="Prompt",
151
+ placeholder="Describe the music or sound effect you want to generate...",
152
+ lines=2,
153
+ )
154
+ duration = gr.Slider(minimum=1, maximum=120, value=30, step=1, label="Duration (seconds)")
155
+ steps = gr.Slider(minimum=1, maximum=50, value=8, step=1, label="Steps")
156
+ cfg_scale = gr.Slider(minimum=0.0, maximum=10.0, value=1.0, step=0.1, label="CFG Scale")
157
+ seed = gr.Number(value=-1, label="Seed (-1 for random)")
158
+ btn = gr.Button("Generate", variant="primary")
159
+
160
+ with gr.Column():
161
+ audio_output = gr.Audio(label="Generated Audio", type="filepath")
162
+
163
+ btn.click(
164
+ fn=generate_audio,
165
+ inputs=[prompt, duration, steps, cfg_scale, seed, model_name],
166
+ outputs=audio_output,
167
+ )
168
+
169
+
170
+ # ---------------------------------------------------------------------------
171
+ # Inject discovery routes into Gradio's internal FastAPI server.
172
+ #
173
+ # The HF Spaces Gradio runner calls demo.launch() directly, so our own
174
+ # FastAPI app is never served. We monkey-patch Blocks.launch so that
175
+ # AFTER Gradio creates its server, we inject routes onto that server.
176
+ # ---------------------------------------------------------------------------
177
+
178
+ _original_blocks_launch = gr.Blocks.launch
179
+
180
+
181
+ def _patched_blocks_launch(self, *args, **kwargs):
182
+ _log("Intercepted Blocks.launch() - calling original...")
183
+ try:
184
+ result = _original_blocks_launch(self, *args, **kwargs)
185
+ except Exception:
186
+ _log("ERROR in original launch:")
187
+ _log(traceback.format_exc())
188
+ raise
189
+
190
+ if self is demo:
191
+ try:
192
+ fa_app = getattr(self, "app", None)
193
+ _log(f"demo.app is: {fa_app}")
194
+ if fa_app is not None:
195
+ @fa_app.get("/respite/resources")
196
+ def _resources():
197
+ return JSONResponse({"resources": API_RESOURCES})
198
+
199
+ @fa_app.get("/respite/specs")
200
+ def _specs():
201
+ return JSONResponse({**API_SPECS, "runtime": _get_runtime_specs()})
202
+
203
+ _log("Respite API routes injected successfully")
204
+ else:
205
+ _log("Warning: demo.app is None after launch")
206
+ except Exception:
207
+ _log("ERROR injecting routes:")
208
+ _log(traceback.format_exc())
209
+
210
+ return result
211
+
212
+
213
+ gr.Blocks.launch = _patched_blocks_launch
214
+
215
+ demo.queue(max_size=4, default_concurrency_limit=1)