akhaliq HF Staff commited on
Commit
4cde538
·
1 Parent(s): 00d07aa

Blog alignment: reasoning_strength template kwarg, video input support

Browse files
Files changed (3) hide show
  1. app.py +15 -10
  2. index.html +24 -11
  3. requirements.txt +1 -0
app.py CHANGED
@@ -22,7 +22,7 @@ app = Server()
22
  @app.api(name="chat")
23
  @spaces.GPU(size="xlarge", duration=240)
24
  def chat(message: str,
25
- image: FileData | None,
26
  history: list,
27
  max_new_tokens: float,
28
  temperature: float,
@@ -30,28 +30,33 @@ def chat(message: str,
30
  """Streaming multimodal chat with Muse-Glimmer-30B.
31
 
32
  history: list of {"role": "user"|"assistant", "content": str}
33
- image: optional FileData uploaded via the Gradio client
34
  """
35
- messages = [
36
- {"role": "system", "content": f"Reasoning strength: {reasoning}"},
37
- ]
38
  for m in history:
39
  messages.append({"role": m["role"], "content": m["content"]})
40
 
41
  content = []
42
- if image:
43
- content.append({"type": "image", "path": image["path"]})
 
 
 
 
44
  if message:
45
  content.append({"type": "text", "text": message})
46
  messages.append({"role": "user", "content": content})
47
 
48
- inputs = processor.apply_chat_template(
49
- messages,
50
  add_generation_prompt=True,
51
  tokenize=True,
52
  return_dict=True,
53
  return_tensors="pt",
54
- ).to(model.device)
 
 
 
 
55
 
56
  streamer = TextIteratorStreamer(processor, skip_prompt=True, skip_special_tokens=True)
57
  thread = Thread(
 
22
  @app.api(name="chat")
23
  @spaces.GPU(size="xlarge", duration=240)
24
  def chat(message: str,
25
+ media: FileData | None,
26
  history: list,
27
  max_new_tokens: float,
28
  temperature: float,
 
30
  """Streaming multimodal chat with Muse-Glimmer-30B.
31
 
32
  history: list of {"role": "user"|"assistant", "content": str}
33
+ media: optional image or video FileData uploaded via the Gradio client
34
  """
35
+ messages = []
 
 
36
  for m in history:
37
  messages.append({"role": m["role"], "content": m["content"]})
38
 
39
  content = []
40
+ if media:
41
+ path = media["path"]
42
+ if path.lower().rsplit(".", 1)[-1] in ("mp4", "mov", "webm", "mkv", "avi"):
43
+ content.append({"type": "video", "path": path})
44
+ else:
45
+ content.append({"type": "image", "path": path})
46
  if message:
47
  content.append({"type": "text", "text": message})
48
  messages.append({"role": "user", "content": content})
49
 
50
+ template_kwargs = dict(
 
51
  add_generation_prompt=True,
52
  tokenize=True,
53
  return_dict=True,
54
  return_tensors="pt",
55
+ reasoning_strength=reasoning,
56
+ )
57
+ if any(c["type"] == "video" for c in content):
58
+ template_kwargs["processor_kwargs"] = {"num_frames": 32}
59
+ inputs = processor.apply_chat_template(messages, **template_kwargs).to(model.device)
60
 
61
  streamer = TextIteratorStreamer(processor, skip_prompt=True, skip_special_tokens=True)
62
  thread = Thread(
index.html CHANGED
@@ -61,7 +61,7 @@
61
  .msg { max-width: 78%; padding: 12px 16px; border-radius: 20px; line-height: 1.5; white-space: pre-wrap; word-break: break-word; font-size: 15px; }
62
  .user { align-self: flex-end; background: var(--blue); color: #fff; border-bottom-right-radius: 6px; }
63
  .bot { align-self: flex-start; background: var(--card); border: 1px solid var(--border); color: #eef2fb; border-bottom-left-radius: 6px; }
64
- .msg img { max-width: 240px; border-radius: 12px; display: block; margin-bottom: 8px; }
65
  .sys { align-self: center; color: var(--muted); font-size: 12px; background: none; }
66
  .reasoning { margin-bottom: 8px; border-left: 2px solid var(--border); padding-left: 10px; }
67
  .reasoning summary { cursor: pointer; color: #8ab4ff; font-size: 12px; font-weight: 600; text-transform: uppercase; letter-spacing: .5px; }
@@ -148,7 +148,7 @@
148
 
149
  <div class="hero" id="hero">
150
  <h1>Do more with Muse Glimmer</h1>
151
- <p>A 30B multimodal agentic model — answering questions, reasoning over images,<br>and completing tasks, right here on ZeroGPU.</p>
152
  </div>
153
 
154
  <div id="chat"></div>
@@ -169,7 +169,7 @@
169
  <div id="preview"><img id="pimg"><div class="x" onclick="clearImage()">✕</div></div>
170
  <div class="row">
171
  <button id="attach" title="Attach image">📎</button>
172
- <input type="file" id="file" accept="image/*" hidden>
173
  <textarea id="input" rows="1" placeholder="Message Muse Glimmer…"></textarea>
174
  <button id="send">Send</button>
175
  <button id="stop" style="display:none">Stop</button>
@@ -201,15 +201,27 @@ document.getElementById("attach").onclick = () => fileInput.click();
201
 
202
  fileInput.onchange = () => {
203
  attachedFile = fileInput.files[0] || null;
204
- if (attachedFile) { pimg.src = URL.createObjectURL(attachedFile); preview.style.display = "block"; }
205
- else preview.style.display = "none";
 
 
 
 
 
 
 
206
  };
207
  window.clearImage = () => { attachedFile = null; fileInput.value = ""; preview.style.display = "none"; };
208
 
209
- function addMsg(role, text, imgUrl) {
210
  const div = document.createElement("div");
211
  div.className = "msg " + role;
212
- if (imgUrl) { const im = document.createElement("img"); im.src = imgUrl; div.appendChild(im); }
 
 
 
 
 
213
  const t = document.createElement("span"); t.textContent = text; div.appendChild(t);
214
  chatEl.appendChild(div);
215
  chatEl.scrollTop = chatEl.scrollHeight;
@@ -258,8 +270,9 @@ async function send() {
258
  if (!text && !attachedFile) return;
259
  hero.style.display = "none";
260
  document.querySelector(".orb").style.padding = "12px 0 4px";
261
- const imgUrl = attachedFile ? URL.createObjectURL(attachedFile) : null;
262
- addMsg("user", text || "[image]", imgUrl);
 
263
  input.value = "";
264
  input.style.height = "auto";
265
  setBusy(true);
@@ -269,7 +282,7 @@ async function send() {
269
  try {
270
  currentJob = client.submit("/chat", {
271
  message: text,
272
- image: attachedFile ? handle_file(attachedFile) : null,
273
  history: history,
274
  max_new_tokens: +document.getElementById("maxtok").value,
275
  temperature: +document.getElementById("temp").value,
@@ -286,7 +299,7 @@ async function send() {
286
  chatEl.scrollTop = chatEl.scrollHeight;
287
  }
288
  }
289
- history.push({ role: "user", content: text || "[image]" });
290
  history.push({ role: "assistant", content: finalText });
291
  } catch (e) {
292
  botDiv.textContent = "⚠️ " + (e.message || e);
 
61
  .msg { max-width: 78%; padding: 12px 16px; border-radius: 20px; line-height: 1.5; white-space: pre-wrap; word-break: break-word; font-size: 15px; }
62
  .user { align-self: flex-end; background: var(--blue); color: #fff; border-bottom-right-radius: 6px; }
63
  .bot { align-self: flex-start; background: var(--card); border: 1px solid var(--border); color: #eef2fb; border-bottom-left-radius: 6px; }
64
+ .msg img, .msg video { max-width: 240px; border-radius: 12px; display: block; margin-bottom: 8px; }
65
  .sys { align-self: center; color: var(--muted); font-size: 12px; background: none; }
66
  .reasoning { margin-bottom: 8px; border-left: 2px solid var(--border); padding-left: 10px; }
67
  .reasoning summary { cursor: pointer; color: #8ab4ff; font-size: 12px; font-weight: 600; text-transform: uppercase; letter-spacing: .5px; }
 
148
 
149
  <div class="hero" id="hero">
150
  <h1>Do more with Muse Glimmer</h1>
151
+ <p>A 30B multimodal agentic model — answering questions, reasoning over images and video,<br>and completing tasks, right here on ZeroGPU.</p>
152
  </div>
153
 
154
  <div id="chat"></div>
 
169
  <div id="preview"><img id="pimg"><div class="x" onclick="clearImage()">✕</div></div>
170
  <div class="row">
171
  <button id="attach" title="Attach image">📎</button>
172
+ <input type="file" id="file" accept="image/*,video/*" hidden>
173
  <textarea id="input" rows="1" placeholder="Message Muse Glimmer…"></textarea>
174
  <button id="send">Send</button>
175
  <button id="stop" style="display:none">Stop</button>
 
201
 
202
  fileInput.onchange = () => {
203
  attachedFile = fileInput.files[0] || null;
204
+ if (attachedFile) {
205
+ const url = URL.createObjectURL(attachedFile);
206
+ if (attachedFile.type.startsWith("video/")) {
207
+ preview.innerHTML = `<video src="${url}" style="height:64px;border-radius:12px;border:1px solid var(--border)" muted></video><div class="x" onclick="clearImage()">✕</div>`;
208
+ } else {
209
+ preview.innerHTML = `<img src="${url}" style="height:64px;border-radius:12px;border:1px solid var(--border)"><div class="x" onclick="clearImage()">✕</div>`;
210
+ }
211
+ preview.style.display = "block";
212
+ } else preview.style.display = "none";
213
  };
214
  window.clearImage = () => { attachedFile = null; fileInput.value = ""; preview.style.display = "none"; };
215
 
216
+ function addMsg(role, text, mediaUrl, isVideo) {
217
  const div = document.createElement("div");
218
  div.className = "msg " + role;
219
+ if (mediaUrl) {
220
+ const im = document.createElement(isVideo ? "video" : "img");
221
+ im.src = mediaUrl;
222
+ if (isVideo) { im.controls = true; im.muted = true; }
223
+ div.appendChild(im);
224
+ }
225
  const t = document.createElement("span"); t.textContent = text; div.appendChild(t);
226
  chatEl.appendChild(div);
227
  chatEl.scrollTop = chatEl.scrollHeight;
 
270
  if (!text && !attachedFile) return;
271
  hero.style.display = "none";
272
  document.querySelector(".orb").style.padding = "12px 0 4px";
273
+ const isVideo = attachedFile && attachedFile.type.startsWith("video/");
274
+ const mediaUrl = attachedFile ? URL.createObjectURL(attachedFile) : null;
275
+ addMsg("user", text || (isVideo ? "[video]" : "[image]"), mediaUrl, isVideo);
276
  input.value = "";
277
  input.style.height = "auto";
278
  setBusy(true);
 
282
  try {
283
  currentJob = client.submit("/chat", {
284
  message: text,
285
+ media: attachedFile ? handle_file(attachedFile) : null,
286
  history: history,
287
  max_new_tokens: +document.getElementById("maxtok").value,
288
  temperature: +document.getElementById("temp").value,
 
299
  chatEl.scrollTop = chatEl.scrollHeight;
300
  }
301
  }
302
+ history.push({ role: "user", content: text || (isVideo ? "[video]" : "[image]") });
303
  history.push({ role: "assistant", content: finalText });
304
  } catch (e) {
305
  botDiv.textContent = "⚠️ " + (e.message || e);
requirements.txt CHANGED
@@ -5,3 +5,4 @@ transformers
5
  gradio
6
  pillow
7
  accelerate
 
 
5
  gradio
6
  pillow
7
  accelerate
8
+ torchcodec