harp-dev commited on
Commit
bd7813d
·
verified ·
1 Parent(s): eaaabca

Deploy HARP wrapper via model agent

Browse files
Files changed (4) hide show
  1. .harp/manifest.json +26 -0
  2. README.md +13 -7
  3. app.py +187 -0
  4. requirements.txt +3 -0
.harp/manifest.json ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "backend_space": "ASLP-lab/DiffRhythm2",
3
+ "deploy_mode": "remote-backend",
4
+ "entry": "app.py",
5
+ "framework": "gradio_client",
6
+ "generated": true,
7
+ "io": {
8
+ "inputs": [
9
+ "textbox",
10
+ "audio",
11
+ "textbox",
12
+ "slider",
13
+ "checkbox",
14
+ "slider",
15
+ "slider",
16
+ "dropdown"
17
+ ],
18
+ "outputs": [
19
+ "audio"
20
+ ]
21
+ },
22
+ "repo_id": "ASLP-lab/DiffRhythm2",
23
+ "source": "recipe",
24
+ "space_layout": "huggingface-gradio",
25
+ "task": "custom"
26
+ }
README.md CHANGED
@@ -1,13 +1,19 @@
1
  ---
2
- title: DiffRhythm2
3
- emoji: 🐢
4
- colorFrom: purple
5
- colorTo: green
6
  sdk: gradio
7
- sdk_version: 6.20.0
8
- python_version: '3.13'
9
  app_file: app.py
10
  pinned: false
 
11
  ---
12
 
13
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
1
  ---
2
+ title: "Diffrhythm2"
3
+ colorFrom: indigo
4
+ colorTo: gray
 
5
  sdk: gradio
6
+ sdk_version: 5.28.0
 
7
  app_file: app.py
8
  pinned: false
9
+ license: "other"
10
  ---
11
 
12
+ # Diffrhythm2
13
+
14
+ TODO: describe this model.
15
+
16
+ - Inputs: textbox, audio, textbox, slider, checkbox, slider, slider, dropdown
17
+ - Outputs: audio
18
+
19
+ Generated by the HARP model agent from a recipe.
app.py ADDED
@@ -0,0 +1,187 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ import os
4
+ import time
5
+ import urllib.request
6
+
7
+ import gradio as gr
8
+
9
+ from pyharp import *
10
+ from gradio_client import Client, handle_file
11
+
12
+
13
+ _BACKEND_SPACE = "ASLP-lab/DiffRhythm2"
14
+ _BACKEND_API_NAME = "/infer_music"
15
+ _BACKEND_TOKEN_ENV = "HF_TOKEN"
16
+ _ACCEPT_USER_TOKEN = False
17
+ # How many times to wake+retry a sleeping backend, and how long to wait for
18
+ # it to boot (a free Space cold start can take a few minutes).
19
+ _CALL_RETRIES = int(os.environ.get("BACKEND_CALL_RETRIES", "4"))
20
+ _WAKE_TIMEOUT = float(os.environ.get("BACKEND_WAKE_TIMEOUT", "420"))
21
+ _client = None
22
+
23
+
24
+ def _backend_client():
25
+ # Lazily create and cache one warm connection using this Space's own
26
+ # token (from the HF_TOKEN secret) or anonymous if none is set. User
27
+ # tokens are NOT cached here -- they get a fresh per-call connection.
28
+ global _client
29
+ if _client is None:
30
+ _token = os.environ.get(_BACKEND_TOKEN_ENV) or None
31
+ _client = Client(_BACKEND_SPACE, hf_token=_token)
32
+ return _client
33
+
34
+
35
+ def _reset_client():
36
+ # Drop the cached connection so the next attempt reconnects to a Space
37
+ # that has since finished waking.
38
+ global _client
39
+ _client = None
40
+
41
+
42
+ def _make_conn(tok):
43
+ tok = (tok or '').strip()
44
+ if tok:
45
+ return Client(_BACKEND_SPACE, hf_token=tok)
46
+ return _backend_client()
47
+
48
+
49
+ def _space_url(space):
50
+ slug = space.strip().lower().replace('/', '-').replace('_', '-')
51
+ return f'https://{slug}.hf.space/'
52
+
53
+
54
+ def _is_cold_start(message):
55
+ # Errors that mean 'the backend was asleep/booting', worth waking+retrying
56
+ # (vs. a real application error, which we surface immediately).
57
+ _low = (message or '').lower()
58
+ return any(s in _low for s in (
59
+ 'read operation timed out', 'timed out', 'timeout', 'starting',
60
+ 'building', 'not ready', 'no application', 'connection', '503', '502',
61
+ ))
62
+
63
+
64
+ def _wake_backend():
65
+ # A sleeping Space boots when its URL is hit; poll until it answers (or
66
+ # the budget expires) so the retried call lands on a running backend.
67
+ _url = _space_url(_BACKEND_SPACE)
68
+ _deadline = time.time() + _WAKE_TIMEOUT
69
+ _delay = 5.0
70
+ while time.time() < _deadline:
71
+ try:
72
+ _req = urllib.request.Request(_url, headers={'User-Agent': 'harp-frontend'})
73
+ with urllib.request.urlopen(_req, timeout=30) as _resp:
74
+ if getattr(_resp, 'status', 200) < 500:
75
+ return True
76
+ except Exception:
77
+ pass
78
+ time.sleep(_delay)
79
+ _delay = min(_delay * 1.5, 30.0)
80
+ return False
81
+
82
+
83
+ def _quota_hint(message):
84
+ # Turn a backend error into an actionable message.
85
+ # NOTE: 'message' is the backend's error text; it never contains our token.
86
+ _low = (message or "").lower()
87
+ if "quota" in _low or "zerogpu" in _low:
88
+ if _ACCEPT_USER_TOKEN:
89
+ return (
90
+ "The backend's ZeroGPU quota is exhausted for the identity making "
91
+ "this call. Paste your own Hugging Face token in the token field "
92
+ "(read scope) so usage is attributed to your account."
93
+ )
94
+ return (
95
+ "The backend's ZeroGPU quota is exhausted. This Space's calls are "
96
+ "anonymous unless an HF_TOKEN secret is set (Settings -> Variables "
97
+ "and secrets); use a token from a PRO account or a ZeroGPU-enabled org."
98
+ )
99
+ # Opaque backend failure: the Space raised an exception it refuses to
100
+ # expose (it runs with show_error=False), so all we get is a generic
101
+ # 'Internal Gradio error'. The frontend can't fix a server-side crash --
102
+ # point the user at where the real cause lives.
103
+ if (
104
+ "internal gradio error" in _low
105
+ or "internal server error" in _low
106
+ or "apperror" in _low
107
+ or _low.strip() in ("", "none")
108
+ ):
109
+ _hint = (
110
+ "The backend Space raised an error it did not expose (it runs with "
111
+ "show_error disabled), so the real cause is only in the backend "
112
+ "Space's Logs tab (" + _BACKEND_SPACE + ")."
113
+ )
114
+ if _ACCEPT_USER_TOKEN:
115
+ _hint += (
116
+ " If it is a ZeroGPU Space, an anonymous call can fail this way -- "
117
+ "paste a Hugging Face token in the token field and retry."
118
+ )
119
+ return _hint
120
+ return message or "Backend call failed."
121
+
122
+
123
+ model_card = ModelCard(
124
+ name="Diffrhythm2",
125
+ description="TODO: describe this model.",
126
+ author="ASLP-lab",
127
+ tags=[],
128
+ )
129
+
130
+
131
+ def process_fn(lrc, audio_prompt, text_prompt, seed, randomize_seed, steps, cfg_strength, file_type):
132
+ _tok = ''
133
+ # Call the backend, waking it and retrying if it was asleep (a cold
134
+ # start otherwise fails the first hit with 'read operation timed out').
135
+ _raw = None
136
+ for _attempt in range(_CALL_RETRIES + 1):
137
+ try:
138
+ _conn = _make_conn(_tok)
139
+ _raw = _conn.predict(
140
+ lrc,
141
+ (handle_file(audio_prompt) if audio_prompt else None),
142
+ text_prompt,
143
+ seed,
144
+ randomize_seed,
145
+ steps,
146
+ cfg_strength,
147
+ file_type,
148
+ 'euler',
149
+ api_name="/infer_music",
150
+ )
151
+ break
152
+ except Exception as _exc: # never surfaces the token
153
+ if _attempt < _CALL_RETRIES and _is_cold_start(str(_exc)):
154
+ _reset_client()
155
+ _wake_backend()
156
+ continue
157
+ raise gr.Error(_quota_hint(str(_exc)))
158
+ _values = list(_raw) if isinstance(_raw, (list, tuple)) else [_raw]
159
+ _detail = " | ".join(str(_v) for _v in _values if isinstance(_v, str) and _v.strip())
160
+ _out_audio_result = _values[0] if len(_values) > 0 else None
161
+ if not _out_audio_result:
162
+ raise gr.Error(_detail or "The backend Space returned no 'audio_result' output. Check the backend Space's logs; if it uses ZeroGPU it may need a moment to warm up.")
163
+ return _out_audio_result
164
+
165
+
166
+ with gr.Blocks() as demo:
167
+ input_components = [
168
+ gr.Textbox(label="Lyrics", value="[start]\n[intro]\n[verse]\nThought I heard your voice yesterday\nWhen I turned around to say\nThat I loved you baby\nI realize it was juss my mind\nPlayed tricks on me\nAnd it seems colder lately at night\nAnd I try to sleep with the lights on\nEvery time the phone rings\nI pray to God it's you\nAnd I just can't believe\nThat we're through\n[chorus]\nI miss you\nThere's no other way to say it\nAnd I can't deny it\nI miss you\nIt's so easy to see\nI miss you and me\n[verse]\nIs it turning over this time\nHave we really changed our minds about each other's love\nAll the feelings that we used to share\nI refuse to believe\nThat you don't care\n[chorus]\nI miss you\nThere's no other way to say it\nAnd I and I can't deny it\nI miss you\n[verse]\nIt's so easy to see\nI've got to gather myself as together\nI've been through worst kinds of weather\nIf it's over now\n[outro]"),
169
+ gr.Audio(type="filepath", label="Audio Prompt"),
170
+ gr.Textbox(label="Text Prompt", value="Pop, Piano, Bass, Drums, Happy"),
171
+ gr.Slider(minimum=0.0, maximum=1.0, step=0.1, value=0, label="Seed"),
172
+ gr.Checkbox(value=True, label="Randomize seed"),
173
+ gr.Slider(minimum=0.0, maximum=1.0, step=0.1, value=16, label="Diffusion Steps"),
174
+ gr.Slider(minimum=0.0, maximum=1.0, step=0.1, value=1.3, label="CFG Strength"),
175
+ gr.Dropdown(choices=["TODO_option_1", "TODO_option_2"], value="mp3", label="Output Format"),
176
+ ]
177
+ output_components = [
178
+ gr.Audio(type="filepath", label="Audio Result"),
179
+ ]
180
+ build_endpoint(
181
+ model_card=model_card,
182
+ input_components=input_components,
183
+ output_components=output_components,
184
+ process_fn=process_fn,
185
+ )
186
+
187
+ demo.queue().launch(share=True, show_error=False, pwa=True)
requirements.txt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ git+https://github.com/TEAMuP-dev/pyharp.git@develop
2
+ gradio>=4.0
3
+ gradio_client