ambujm22 commited on
Commit
b583efa
·
verified ·
1 Parent(s): fa0afe5

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +69 -112
app.py CHANGED
@@ -12,7 +12,7 @@ except Exception:
12
  return deco
13
  spaces = _DummySpaces()
14
 
15
- # Publicly-named probes so ZeroGPU supervisor can detect them
16
  @spaces.GPU(duration=10)
17
  def gpu_probe(a: int = 1, b: int = 1):
18
  return a + b
@@ -43,12 +43,24 @@ WEIGHTS_FILE = "model.safetensors"
43
  CACHE_DIR = SPACE_ROOT / "weights"
44
  CACHE_DIR.mkdir(parents=True, exist_ok=True)
45
 
46
- # ================ Lazy resources =================
47
- _weights_path: Optional[Path] = None
48
- _repo_ready: bool = False
 
 
 
 
 
 
 
49
 
 
 
 
 
 
50
  def get_weights_path(progress: Optional[gr.Progress] = None) -> Path:
51
- """Download/resolve weights lazily."""
52
  global _weights_path
53
  if _weights_path is None:
54
  if progress: progress(0.10, desc="Downloading model weights (first run)")
@@ -63,23 +75,9 @@ def get_weights_path(progress: Optional[gr.Progress] = None) -> Path:
63
  _weights_path = Path(wp)
64
  return _weights_path
65
 
66
- def ensure_repo(progress: Optional[gr.Progress] = None) -> Path:
67
- """Clone the repo lazily and add to sys.path."""
68
- global _repo_ready
69
- if not _repo_ready:
70
- if not REPO_DIR.exists():
71
- if progress: progress(0.18, desc="Cloning SonicMaster repo (first run)")
72
- subprocess.run(
73
- ["git", "clone", "--depth", "1", REPO_URL, REPO_DIR.as_posix()],
74
- check=True,
75
- )
76
- if REPO_DIR.as_posix() not in sys.path:
77
- sys.path.append(REPO_DIR.as_posix())
78
- _repo_ready = True
79
- return REPO_DIR
80
-
81
  # ================== Helpers ==================
82
  def save_temp_wav(wav: np.ndarray, sr: int, path: Path):
 
83
  if wav.ndim == 2 and wav.shape[0] < wav.shape[1]:
84
  wav = wav.T
85
  if wav.dtype == np.float64:
@@ -93,11 +91,15 @@ def read_audio(path: str) -> Tuple[np.ndarray, int]:
93
  return wav, sr
94
 
95
  def _candidate_commands(py: str, script: Path, ckpt: Path, inp: Path, prompt: str, out: Path) -> List[List[str]]:
96
- # Try common flag layouts
 
 
 
97
  return [
98
- [py, script.as_posix(), "--ckpt", ckpt.as_posix(), "--input", inp.as_posix(), "--prompt", prompt, "--output", out.as_posix()],
99
- [py, script.as_posix(), "--weights",ckpt.as_posix(), "--input", inp.as_posix(), "--text", prompt, "--out", out.as_posix()],
100
- [py, script.as_posix(), "--ckpt", ckpt.as_posix(), "--input", inp.as_posix(), "--text", prompt, "--output", out.as_posix()],
 
101
  ]
102
 
103
  def run_sonicmaster_cli(
@@ -106,40 +108,37 @@ def run_sonicmaster_cli(
106
  out_path: Path,
107
  progress: Optional[gr.Progress] = None,
108
  ) -> Tuple[bool, str]:
109
- """Run inference scripts via subprocess; return (ok, message)."""
110
  if progress: progress(0.14, desc="Preparing inference")
111
  ckpt = get_weights_path(progress=progress)
112
- repo = ensure_repo(progress=progress)
113
 
114
- candidates = [repo / "infer_single.py", repo / "inference_fullsong.py", repo / "inference_ptload_batch.py"]
115
- scripts = [s for s in candidates if s.exists()]
116
- if not scripts:
117
- return False, "No inference script found in the repo (expected infer_single.py or similar)."
118
 
119
  py = sys.executable or "python3"
120
  env = os.environ.copy()
121
 
122
  last_err = ""
123
- for sidx, script in enumerate(scripts, 1):
124
- for cidx, cmd in enumerate(_candidate_commands(py, script, ckpt, input_wav_path, prompt, out_path), 1):
125
- try:
126
- if progress:
127
- progress(min(0.20 + 0.08 * (sidx + cidx), 0.70), desc=f"Running {script.name} (try {sidx}.{cidx})")
128
- res = subprocess.run(cmd, capture_output=True, text=True, check=True, env=env)
129
- if out_path.exists() and out_path.stat().st_size > 0:
130
- if progress: progress(0.88, desc="Post-processing output")
131
- return True, (res.stdout or "Inference completed.").strip()
132
- last_err = f"{script.name} produced no output file."
133
- except subprocess.CalledProcessError as e:
134
- snippet = "\n".join(filter(None, [e.stdout or "", e.stderr or ""])).strip()
135
- last_err = snippet if snippet else f"{script.name} failed with return code {e.returncode}."
136
- except Exception as e:
137
- import traceback
138
- last_err = f"Unexpected error: {e}\n{traceback.format_exc()}"
139
  return False, last_err or "All candidate commands failed."
140
 
141
  # ============ GPU path (ZeroGPU) ============
142
- @spaces.GPU(duration=60) # 60s is a safe cap for ZeroGPU
143
  def enhance_on_gpu(input_path: str, prompt: str, output_path: str) -> Tuple[bool, str]:
144
  try:
145
  import torch # noqa: F401
@@ -155,7 +154,7 @@ def _has_cuda() -> bool:
155
  except Exception:
156
  return False
157
 
158
- # ================== Examples (lazy) ==================
159
  PROMPTS_10 = [
160
  "Increase the clarity of this song by emphasizing treble frequencies.",
161
  "Make this song sound more boomy by amplifying the low end bass frequencies.",
@@ -169,36 +168,17 @@ PROMPTS_10 = [
169
  "Please, dereverb this audio.",
170
  ]
171
 
172
- def list_example_files(progress: Optional[gr.Progress] = None) -> List[str]:
173
- """Return up to 10 .wav paths inside repo/samples/inputs (lazy clone)."""
174
- repo = ensure_repo(progress=progress)
175
- wav_dir = repo / "samples" / "inputs"
176
- files = sorted(p for p in wav_dir.glob("*.wav") if p.is_file())
177
- return [p.as_posix() for p in files[:10]]
 
 
 
178
 
179
- def load_examples(_: Any = None, progress=gr.Progress()):
180
- """
181
- Returns (dropdown_update, paths:list[str], status:str)
182
- """
183
- paths = list_example_files(progress=progress)
184
- if not paths:
185
- return gr.Dropdown.update(choices=[], value=None), [], "No sample .wav files found in repo/samples/inputs."
186
- labels = [f"{i+1:02d} — {Path(p).name}" for i, p in enumerate(paths)]
187
- # Auto-select first item for convenience
188
- return gr.Dropdown.update(choices=labels, value=labels[0]), paths, f"Loaded {len(paths)} sample audios."
189
-
190
- def set_example_selection(idx_label: str, paths: List[str]) -> Tuple[str, str]:
191
- """When user picks an example, set the audio path + a suggested prompt."""
192
- if not idx_label or not paths:
193
- return "", ""
194
- try:
195
- idx = int(idx_label.split()[0]) - 1 # "01 — file.wav" -> 0
196
- except Exception:
197
- idx = 0
198
- idx = max(0, min(idx, len(paths)-1))
199
- audio_path = paths[idx]
200
- prompt = PROMPTS_10[idx] if idx < len(PROMPTS_10) else PROMPTS_10[-1]
201
- return audio_path, prompt
202
 
203
  # ================== Main callback ==================
204
  def enhance_audio_ui(
@@ -249,52 +229,29 @@ def enhance_audio_ui(
249
  with gr.Blocks(title="SonicMaster – Text-Guided Restoration & Mastering", fill_height=True) as _demo:
250
  gr.Markdown(
251
  "## 🎧 SonicMaster\n"
252
- "Upload audio or **load sample audios**, write a prompt, then click **Enhance**.\n"
 
253
  )
254
  with gr.Row():
255
  with gr.Column(scale=1):
256
- # Sample loader (lazy)
257
- with gr.Accordion("Sample audios (10)", open=False):
258
- load_btn = gr.Button("📥 Load 10 sample audios")
259
- samples_dropdown = gr.Dropdown(
260
- choices=[], value=None, # no default until choices are set
261
- label="Pick a sample",
262
- interactive=True,
263
- )
264
- samples_state = gr.State([]) # holds absolute paths
265
-
266
  in_audio = gr.Audio(label="Input Audio", type="filepath")
267
  prompt = gr.Textbox(label="Text Prompt", placeholder="e.g., Reduce reverb and brighten vocals.")
268
  run_btn = gr.Button("🚀 Enhance", variant="primary")
269
 
270
- gr.Examples(
271
- examples=[[p] for p in [
272
- "Reduce roominess/echo (dereverb).",
273
- "Raise the level of the vocals.",
274
- "Give the song a wider stereo image.",
275
- ]],
276
- inputs=[prompt],
277
- label="Prompt Examples",
278
- )
279
 
280
  with gr.Column(scale=1):
281
  out_audio = gr.Audio(label="Enhanced Audio (output)")
282
  status = gr.Textbox(label="Status / Messages", interactive=False, lines=8)
283
 
284
- # Load samples (3 outputs directly; no .then needed)
285
- load_btn.click(
286
- fn=load_examples,
287
- inputs=None,
288
- outputs=[samples_dropdown, samples_state, status],
289
- )
290
-
291
- # When a sample is chosen, set audio path + suggested prompt
292
- samples_dropdown.change(
293
- fn=set_example_selection,
294
- inputs=[samples_dropdown, samples_state],
295
- outputs=[in_audio, prompt],
296
- )
297
-
298
  run_btn.click(
299
  fn=enhance_audio_ui,
300
  inputs=[in_audio, prompt],
@@ -309,4 +266,4 @@ app = demo
309
 
310
  # Local debugging only
311
  if __name__ == "__main__":
312
- demo.launch(server_name="0.0.0.0", server_port=7860)
 
12
  return deco
13
  spaces = _DummySpaces()
14
 
15
+ # Public probes so ZeroGPU supervisor can detect them
16
  @spaces.GPU(duration=10)
17
  def gpu_probe(a: int = 1, b: int = 1):
18
  return a + b
 
43
  CACHE_DIR = SPACE_ROOT / "weights"
44
  CACHE_DIR.mkdir(parents=True, exist_ok=True)
45
 
46
+ # ================ Repo clone AT STARTUP (per your request) ================
47
+ def ensure_repo() -> Path:
48
+ if not REPO_DIR.exists():
49
+ subprocess.run(
50
+ ["git", "clone", "--depth", "1", REPO_URL, REPO_DIR.as_posix()],
51
+ check=True,
52
+ )
53
+ if REPO_DIR.as_posix() not in sys.path:
54
+ sys.path.append(REPO_DIR.as_posix())
55
+ return REPO_DIR
56
 
57
+ # Clone now so examples are available immediately
58
+ ensure_repo()
59
+
60
+ # ================ Weights: still lazy (download at first run) ================
61
+ _weights_path: Optional[Path] = None
62
  def get_weights_path(progress: Optional[gr.Progress] = None) -> Path:
63
+ """Download/resolve weights lazily (keeps startup fast)."""
64
  global _weights_path
65
  if _weights_path is None:
66
  if progress: progress(0.10, desc="Downloading model weights (first run)")
 
75
  _weights_path = Path(wp)
76
  return _weights_path
77
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
78
  # ================== Helpers ==================
79
  def save_temp_wav(wav: np.ndarray, sr: int, path: Path):
80
+ # Ensure shape (samples, channels)
81
  if wav.ndim == 2 and wav.shape[0] < wav.shape[1]:
82
  wav = wav.T
83
  if wav.dtype == np.float64:
 
91
  return wav, sr
92
 
93
  def _candidate_commands(py: str, script: Path, ckpt: Path, inp: Path, prompt: str, out: Path) -> List[List[str]]:
94
+ """
95
+ Only support infer_single.py variants.
96
+ Expected primary flags: --ckpt --input --prompt --output
97
+ """
98
  return [
99
+ [py, script.as_posix(), "--ckpt", ckpt.as_posix(), "--input", inp.as_posix(), "--prompt", prompt, "--output", out.as_posix()],
100
+ # A couple common alternates some repos use:
101
+ [py, script.as_posix(), "--weights", ckpt.as_posix(), "--input", inp.as_posix(), "--text", prompt, "--out", out.as_posix()],
102
+ [py, script.as_posix(), "--ckpt", ckpt.as_posix(), "--input", inp.as_posix(), "--text", prompt, "--output", out.as_posix()],
103
  ]
104
 
105
  def run_sonicmaster_cli(
 
108
  out_path: Path,
109
  progress: Optional[gr.Progress] = None,
110
  ) -> Tuple[bool, str]:
111
+ """Run inference via subprocess; returns (ok, message). Uses ONLY infer_single.py."""
112
  if progress: progress(0.14, desc="Preparing inference")
113
  ckpt = get_weights_path(progress=progress)
 
114
 
115
+ script = REPO_DIR / "infer_single.py"
116
+ if not script.exists():
117
+ return False, "infer_single.py not found in the SonicMaster repo."
 
118
 
119
  py = sys.executable or "python3"
120
  env = os.environ.copy()
121
 
122
  last_err = ""
123
+ for cidx, cmd in enumerate(_candidate_commands(py, script, ckpt, input_wav_path, prompt, out_path), 1):
124
+ try:
125
+ if progress:
126
+ progress(min(0.25 + 0.10 * cidx, 0.70), desc=f"Running infer_single.py (try {cidx})")
127
+ res = subprocess.run(cmd, capture_output=True, text=True, check=True, env=env)
128
+ if out_path.exists() and out_path.stat().st_size > 0:
129
+ if progress: progress(0.88, desc="Post-processing output")
130
+ return True, (res.stdout or "Inference completed.").strip()
131
+ last_err = "infer_single.py finished but produced no output file."
132
+ except subprocess.CalledProcessError as e:
133
+ snippet = "\n".join(filter(None, [e.stdout or "", e.stderr or ""])).strip()
134
+ last_err = snippet if snippet else f"infer_single.py failed with return code {e.returncode}."
135
+ except Exception as e:
136
+ import traceback
137
+ last_err = f"Unexpected error with infer_single.py: {e}\n{traceback.format_exc()}"
 
138
  return False, last_err or "All candidate commands failed."
139
 
140
  # ============ GPU path (ZeroGPU) ============
141
+ @spaces.GPU(duration=60) # safe cap for ZeroGPU tiers
142
  def enhance_on_gpu(input_path: str, prompt: str, output_path: str) -> Tuple[bool, str]:
143
  try:
144
  import torch # noqa: F401
 
154
  except Exception:
155
  return False
156
 
157
+ # ================== Examples @ STARTUP ==================
158
  PROMPTS_10 = [
159
  "Increase the clarity of this song by emphasizing treble frequencies.",
160
  "Make this song sound more boomy by amplifying the low end bass frequencies.",
 
168
  "Please, dereverb this audio.",
169
  ]
170
 
171
+ def build_startup_examples() -> List[List[Any]]:
172
+ """Build 10 (audio_path, prompt) pairs from repo at import time."""
173
+ wav_dir = REPO_DIR / "samples" / "inputs"
174
+ wav_paths = sorted(p for p in wav_dir.glob("*.wav") if p.is_file())
175
+ ex = []
176
+ for i, p in enumerate(wav_paths[:10]):
177
+ pr = PROMPTS_10[i] if i < len(PROMPTS_10) else PROMPTS_10[-1]
178
+ ex.append([p.as_posix(), pr])
179
+ return ex
180
 
181
+ STARTUP_EXAMPLES = build_startup_examples()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
182
 
183
  # ================== Main callback ==================
184
  def enhance_audio_ui(
 
229
  with gr.Blocks(title="SonicMaster – Text-Guided Restoration & Mastering", fill_height=True) as _demo:
230
  gr.Markdown(
231
  "## 🎧 SonicMaster\n"
232
+ "Upload audio or pick an example, write a prompt, then click **Enhance**.\n"
233
+ "- First run downloads model weights (progress will show).\n"
234
  )
235
  with gr.Row():
236
  with gr.Column(scale=1):
 
 
 
 
 
 
 
 
 
 
237
  in_audio = gr.Audio(label="Input Audio", type="filepath")
238
  prompt = gr.Textbox(label="Text Prompt", placeholder="e.g., Reduce reverb and brighten vocals.")
239
  run_btn = gr.Button("🚀 Enhance", variant="primary")
240
 
241
+ # Show 10 audio+prompt examples immediately at startup
242
+ if STARTUP_EXAMPLES:
243
+ gr.Examples(
244
+ examples=STARTUP_EXAMPLES,
245
+ inputs=[in_audio, prompt],
246
+ label="Sample Inputs (10)",
247
+ )
248
+ else:
249
+ gr.Markdown("> ⚠️ No sample .wav files found in `samples/inputs/`.")
250
 
251
  with gr.Column(scale=1):
252
  out_audio = gr.Audio(label="Enhanced Audio (output)")
253
  status = gr.Textbox(label="Status / Messages", interactive=False, lines=8)
254
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
255
  run_btn.click(
256
  fn=enhance_audio_ui,
257
  inputs=[in_audio, prompt],
 
266
 
267
  # Local debugging only
268
  if __name__ == "__main__":
269
+ demo.launch(server_name="0.0.0.0", server_port=7860)