harp-dev Claude Opus 5.5 commited on
Commit
a8c158e
·
verified ·
1 Parent(s): 0ee1134

Build the default size in the worker, and check the variant

Browse files

Builds the medium model, the default, in the worker rather than only downloading every size there, builds another size when a request picks it, moves the beat checkpoint link into the worker, and refuses an unknown variant. It also imports spaces plainly, since it is always installed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Files changed (1) hide show
  1. app.py +35 -38
app.py CHANGED
@@ -1,22 +1,9 @@
 
 
1
  import sys
2
 
3
  sys.stdout.reconfigure(line_buffering=True)
4
 
5
- try:
6
- import spaces
7
- except ImportError:
8
- # keep @spaces.GPU usable as a no-op; ZeroGPU requires this exact name.
9
- class spaces:
10
- class GPU:
11
- def __init__(self, func=None, duration=60):
12
- self.func = func
13
-
14
- def __call__(self, *args, **kwargs):
15
- if self.func is not None:
16
- return self.func(*args, **kwargs)
17
- func = args[0]
18
- return func
19
-
20
  import contextlib
21
  import tempfile
22
  from pathlib import Path
@@ -57,38 +44,46 @@ _WEIGHT_REVISIONS = {
57
  _weights: dict[str, Path] = {}
58
  _models: dict[str, TranscriptionModel] = {}
59
 
60
- # Fetched in the worker, which runs process_fn and starts as the server comes up, so that no
61
- # request downloads inside its GPU reservation. The server never runs process_fn.
62
- if __name__ != "__main__":
63
- for _size, _revision in _WEIGHT_REVISIONS.items():
64
- _weights[_size] = Path(snapshot_download(
65
- f"MuScriptor/muscriptor-{_size}", revision=_revision
66
- )) / "model.safetensors"
67
-
68
- # Tempo detection runs beat_this, which downloads its checkpoint from the JKU cloud on first use,
69
- # and that has failed both inside a GPU call (no name resolution) and at startup (503). The same
70
- # file is mirrored on the Hub and linked where torch.hub looks before downloading.
71
- _beat_checkpoint = Path(torch.hub.get_dir()) / "checkpoints" / "beat_this-final0.ckpt"
72
- if not _beat_checkpoint.exists():
73
- _beat_checkpoint.parent.mkdir(parents=True, exist_ok=True)
74
- with contextlib.suppress(FileExistsError):
75
- _beat_checkpoint.symlink_to(hf_hub_download(
76
- "teamup-tech/Beat-This-weights", "final0.ckpt",
77
- revision="4afbe376535aaab71b76ae2ca2d7c16b08877321",
78
- ))
79
 
80
 
81
  def _get_model(variant: str) -> TranscriptionModel:
82
- """Builds the TranscriptionModel of one size, on the GPU the call holds.
83
 
84
- Built inside the call, so ZeroGPU builds it again on every call, which takes seconds from local
85
- weights. Holding all three sizes in the worker instead would keep about 7 GB there.
 
86
  """
87
  if variant not in _models:
88
  _models[variant] = TranscriptionModel.load_model(_weights[variant], device=DEVICE)
89
  return _models[variant]
90
 
91
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92
  def _resolve_instruments(text: str) -> tuple[list[str] | None, str]:
93
  """Resolve the comma-separated instruments box into exact group names.
94
 
@@ -143,6 +138,8 @@ def process_fn(
143
  """Transcribe the input audio to MIDI, plus a note on the Instruments field."""
144
  # Checked before the GPU is reserved, so a request the model cannot take spends none of the
145
  # caller's ZeroGPU allowance
 
 
146
  if not input_audio_path:
147
  raise gr.Error("Provide the music to transcribe.")
148
  try:
@@ -192,7 +189,7 @@ if __name__ == "__main__":
192
  )),
193
  gr.Dropdown(
194
  choices=["small", "medium", "large"],
195
- value="medium",
196
  label="Model Size",
197
  info="small = fastest, least accurate. medium = balanced (default, per repo). large = most accurate, slower.",
198
  ),
 
1
+ import spaces # imported first, as ZeroGPU requires
2
+
3
  import sys
4
 
5
  sys.stdout.reconfigure(line_buffering=True)
6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7
  import contextlib
8
  import tempfile
9
  from pathlib import Path
 
44
  _weights: dict[str, Path] = {}
45
  _models: dict[str, TranscriptionModel] = {}
46
 
47
+ DEFAULT_SIZE = "medium"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
48
 
49
 
50
  def _get_model(variant: str) -> TranscriptionModel:
51
+ """Builds the TranscriptionModel of one size, once.
52
 
53
+ The default size is built in the worker at startup. Holding all three would keep about 7 GB
54
+ there, so another size is built when a request picks it, inside the call, where ZeroGPU builds
55
+ it again on every call, which takes seconds from local weights.
56
  """
57
  if variant not in _models:
58
  _models[variant] = TranscriptionModel.load_model(_weights[variant], device=DEVICE)
59
  return _models[variant]
60
 
61
 
62
+ # Fetched in the worker, which runs process_fn and starts as the server comes up, so that no
63
+ # request downloads inside its GPU reservation, and the default size is built and placed there, on
64
+ # its main thread, where ZeroGPU's emulation records the placement. The server never runs
65
+ # process_fn.
66
+ if __name__ != "__main__":
67
+ for _size, _revision in _WEIGHT_REVISIONS.items():
68
+ _weights[_size] = Path(snapshot_download(
69
+ f"MuScriptor/muscriptor-{_size}", revision=_revision
70
+ )) / "model.safetensors"
71
+
72
+ # Tempo detection runs beat_this, which downloads its checkpoint from the JKU cloud on first
73
+ # use, and that has failed both inside a GPU call (no name resolution) and at startup (503).
74
+ # The same file is mirrored on the Hub and linked where torch.hub looks before downloading.
75
+ _beat_checkpoint = Path(torch.hub.get_dir()) / "checkpoints" / "beat_this-final0.ckpt"
76
+ if not _beat_checkpoint.exists():
77
+ _beat_checkpoint.parent.mkdir(parents=True, exist_ok=True)
78
+ with contextlib.suppress(FileExistsError):
79
+ _beat_checkpoint.symlink_to(hf_hub_download(
80
+ "teamup-tech/Beat-This-weights", "final0.ckpt",
81
+ revision="4afbe376535aaab71b76ae2ca2d7c16b08877321",
82
+ ))
83
+
84
+ _get_model(DEFAULT_SIZE)
85
+
86
+
87
  def _resolve_instruments(text: str) -> tuple[list[str] | None, str]:
88
  """Resolve the comma-separated instruments box into exact group names.
89
 
 
138
  """Transcribe the input audio to MIDI, plus a note on the Instruments field."""
139
  # Checked before the GPU is reserved, so a request the model cannot take spends none of the
140
  # caller's ZeroGPU allowance
141
+ if variant not in _WEIGHT_REVISIONS:
142
+ raise gr.Error(f"Unknown model size: {variant}")
143
  if not input_audio_path:
144
  raise gr.Error("Provide the music to transcribe.")
145
  try:
 
189
  )),
190
  gr.Dropdown(
191
  choices=["small", "medium", "large"],
192
+ value=DEFAULT_SIZE,
193
  label="Model Size",
194
  info="small = fastest, least accurate. medium = balanced (default, per repo). large = most accurate, slower.",
195
  ),