multimodalart HF Staff commited on
Commit
9354f9b
·
verified ·
1 Parent(s): b14ec1f

Upload app.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. app.py +59 -14
app.py CHANGED
@@ -76,18 +76,11 @@ app = Server()
76
  async def set_collider(request: Request):
77
  body = await request.json()
78
  sid = body["session_id"]
79
- prompts = body.get("prompts") or ["instrumental music"]
80
- weights = body.get("weights") or [1.0] * len(prompts)
81
- s = float(sum(weights)) or 1.0
82
- emb = np.zeros(style_model.embedding_dim, np.float32)
83
- for label, w in zip(prompts, weights):
84
- if w <= 0:
85
- continue
86
- emb += (w / s) * _embed(label)
87
- tokens = style_model.tokenize(torch.from_numpy(emb)).tolist()
88
  prev = read_slot(sid) or {}
89
  write_slot(sid, {
90
- "style_tokens": tokens,
 
 
91
  "temperature": float(body.get("temperature", 1.1)),
92
  "top_k": int(body.get("top_k", 50)),
93
  "cfg_musiccoca": float(body.get("cfg", 1.6)),
@@ -102,7 +95,27 @@ async def set_collider(request: Request):
102
  "reset": int(body.get("reset", 0)),
103
  "seed": int(body.get("seed", 0)),
104
  })
105
- return {"ok": True, "tokens": tokens}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
106
 
107
 
108
  @app.api(name="stream")
@@ -127,6 +140,7 @@ def stream(session_id: str) -> str:
127
  prev_active = set()
128
  cur_reset = cur_seed = 0
129
  force_reenc = False
 
130
  while time.time() - t0 < 55.0:
131
  c = read_slot(session_id)
132
  if c is None:
@@ -146,17 +160,48 @@ def stream(session_id: str) -> str:
146
  toks = []
147
  for _ in range(10): # per-frame slot read -> steering applies ~instantly
148
  c = read_slot(session_id) or c
149
- tokens = c["style_tokens"]
 
 
150
  active = set(c.get("notes") or [])
151
  unmask = int(c.get("unmaskwidth", 0))
152
  onsetmode = bool(c.get("onsetmode", False))
153
  drumless = bool(c.get("drumless", False))
154
- sig = (tuple(tokens), tuple(sorted(active)), unmask, onsetmode, drumless)
 
 
155
  if source is None or force_reenc or (sig != cur_sig and time.time() - last_enc >= 0.2):
156
  onsets = active - prev_active
157
  prev_active = set(active)
158
  cur_sig, last_enc = sig, time.time()
159
- force_reenc = onsetmode and bool(onsets) # onset(2)->continuation(1) on the next frame
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
160
  nvec = [] # per-pitch: -1 masked / 0 off / 1 cont / 2 onset / 3 on
161
  for pitch in range(128):
162
  if pitch in active:
 
76
  async def set_collider(request: Request):
77
  body = await request.json()
78
  sid = body["session_id"]
 
 
 
 
 
 
 
 
 
79
  prev = read_slot(sid) or {}
80
  write_slot(sid, {
81
+ "prompts": body.get("prompts") or ["instrumental music"],
82
+ "weights": body.get("weights") or [1.0],
83
+ "audio": body.get("audio") or [],
84
  "temperature": float(body.get("temperature", 1.1)),
85
  "top_k": int(body.get("top_k", 50)),
86
  "cfg_musiccoca": float(body.get("cfg", 1.6)),
 
95
  "reset": int(body.get("reset", 0)),
96
  "seed": int(body.get("seed", 0)),
97
  })
98
+ return {"ok": True}
99
+
100
+
101
+ @app.post("/audio")
102
+ async def set_audio(request: Request):
103
+ """Store an uploaded clip (native-rate mono float32) per (session, slot);
104
+ the GPU stream embeds it with MusicCoCa.embed_audio (resampy -> 16kHz)."""
105
+ body = await request.json()
106
+ sid = os.path.basename(body["session_id"]); slot = int(body.get("slot", 0))
107
+ path = os.path.join(SESSION_DIR, f"{sid}_aud{slot}.bin")
108
+ samples = body.get("samples")
109
+ if not samples:
110
+ try: os.remove(path)
111
+ except OSError: pass
112
+ return {"ok": True}
113
+ raw = base64.b64decode(samples)
114
+ sr = int(body.get("sample_rate", 48000))
115
+ with open(path + ".tmp", "wb") as f:
116
+ f.write(int(sr).to_bytes(4, "little")); f.write(raw)
117
+ os.replace(path + ".tmp", path)
118
+ return {"ok": True}
119
 
120
 
121
  @app.api(name="stream")
 
140
  prev_active = set()
141
  cur_reset = cur_seed = 0
142
  force_reenc = False
143
+ txt_cache, aud_cache = {}, {}
144
  while time.time() - t0 < 55.0:
145
  c = read_slot(session_id)
146
  if c is None:
 
160
  toks = []
161
  for _ in range(10): # per-frame slot read -> steering applies ~instantly
162
  c = read_slot(session_id) or c
163
+ prompts = c.get("prompts") or ["instrumental music"]
164
+ weights = c.get("weights") or [1.0] * len(prompts)
165
+ aflags = (c.get("audio") or []) + [False] * len(prompts)
166
  active = set(c.get("notes") or [])
167
  unmask = int(c.get("unmaskwidth", 0))
168
  onsetmode = bool(c.get("onsetmode", False))
169
  drumless = bool(c.get("drumless", False))
170
+ sig = (tuple(prompts), tuple(round(float(w), 4) for w in weights),
171
+ tuple(bool(a) for a in aflags[:len(prompts)]),
172
+ tuple(sorted(active)), unmask, onsetmode, drumless)
173
  if source is None or force_reenc or (sig != cur_sig and time.time() - last_enc >= 0.2):
174
  onsets = active - prev_active
175
  prev_active = set(active)
176
  cur_sig, last_enc = sig, time.time()
177
+ force_reenc = onsetmode and bool(onsets)
178
+ # ---- style tokens on GPU: embed (text+audio), weight-blend, tokenize ----
179
+ emb = torch.zeros(style_model.embedding_dim, device=dev, dtype=torch.float32)
180
+ tot = float(sum(w for w in weights if w > 0)) or 1.0
181
+ for i in range(len(prompts)):
182
+ w = float(weights[i]) if i < len(weights) else 0.0
183
+ if w <= 0:
184
+ continue
185
+ if i < len(aflags) and aflags[i]:
186
+ ap = os.path.join(SESSION_DIR, f"{os.path.basename(session_id)}_aud{i}.bin")
187
+ try: mt = os.path.getmtime(ap)
188
+ except OSError: continue
189
+ ce = aud_cache.get(i)
190
+ if ce is None or ce[0] != mt:
191
+ data = open(ap, "rb").read()
192
+ asr = int.from_bytes(data[:4], "little")
193
+ samp = np.frombuffer(data[4:], dtype=np.float32)
194
+ ce = (mt, style_model.embed_audio(samp, asr).float()); aud_cache[i] = ce
195
+ e = ce[1]
196
+ else:
197
+ lbl = (prompts[i] or "").strip()
198
+ if not lbl:
199
+ continue
200
+ e = txt_cache.get(lbl)
201
+ if e is None:
202
+ e = style_model.embed(lbl).float(); txt_cache[lbl] = e
203
+ emb = emb + (w / tot) * e
204
+ tokens = style_model.tokenize(emb).tolist() # onset(2)->continuation(1) on the next frame
205
  nvec = [] # per-pitch: -1 masked / 0 off / 1 cont / 2 onset / 3 on
206
  for pitch in range(128):
207
  if pitch in active: