Spaces:
Running on Zero
Running on Zero
Commit ·
78d7cea
1
Parent(s): 42b7d7f
app.py
CHANGED
|
@@ -1290,6 +1290,15 @@ def _build_waveform_html(audio_path: str, segments: list, slot_id: str,
|
|
| 1290 |
plugins = [regionsPlugin];
|
| 1291 |
}}
|
| 1292 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1293 |
// Wait until the container has a non-zero width before creating WaveSurfer,
|
| 1294 |
// otherwise it renders blank (container is 0px when Gradio first injects HTML).
|
| 1295 |
const wfContainer = document.getElementById('wf_{slot_id}');
|
|
@@ -1302,7 +1311,7 @@ def _build_waveform_html(audio_path: str, segments: list, slot_id: str,
|
|
| 1302 |
barWidth: 2,
|
| 1303 |
barGap: 1,
|
| 1304 |
barRadius: 2,
|
| 1305 |
-
url:
|
| 1306 |
plugins: plugins,
|
| 1307 |
}});
|
| 1308 |
|
|
@@ -1310,7 +1319,6 @@ def _build_waveform_html(audio_path: str, segments: list, slot_id: str,
|
|
| 1310 |
ws.setVolume(0);
|
| 1311 |
ws.on('ready', function() {{
|
| 1312 |
ws.setVolume(0);
|
| 1313 |
-
// Prevent WaveSurfer from auto-playing (it shouldn't, but be safe)
|
| 1314 |
ws.pause();
|
| 1315 |
const segments = {segs_json};
|
| 1316 |
const colors = {json.dumps(colors)};
|
|
@@ -1335,6 +1343,10 @@ def _build_waveform_html(audio_path: str, segments: list, slot_id: str,
|
|
| 1335 |
attachVideoSync(ws);
|
| 1336 |
}});
|
| 1337 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1338 |
// Also silence if WaveSurfer tries to play for any reason
|
| 1339 |
ws.on('play', function() {{ ws.pause(); ws.setVolume(0); }});
|
| 1340 |
|
|
@@ -1355,10 +1367,10 @@ def _build_waveform_html(audio_path: str, segments: list, slot_id: str,
|
|
| 1355 |
}}
|
| 1356 |
}});
|
| 1357 |
ro.observe(wfContainer);
|
| 1358 |
-
// Fallback
|
| 1359 |
setTimeout(function() {{
|
| 1360 |
if (!window["_wf_ws_{slot_id}"]) {{ ro.disconnect(); createWS(); }}
|
| 1361 |
-
}},
|
| 1362 |
}} else {{
|
| 1363 |
// Container not in DOM yet — wait for it
|
| 1364 |
setTimeout(loadWS, 200);
|
|
@@ -1407,7 +1419,7 @@ def _make_output_slots(tab_prefix: str) -> tuple:
|
|
| 1407 |
for i in range(MAX_SLOTS):
|
| 1408 |
with gr.Group(visible=(i == 0)) as g:
|
| 1409 |
slot_id = f"{tab_prefix}_{i}"
|
| 1410 |
-
vids.append(gr.Video(label=f"Generation {i+1} — Video"))
|
| 1411 |
waveforms.append(gr.HTML(
|
| 1412 |
value="<p style='color:#888;font-size:12px'>Generate audio to see waveform.</p>",
|
| 1413 |
label=f"Generation {i+1} — Waveform",
|
|
@@ -1475,9 +1487,16 @@ def _update_slot_visibility(n):
|
|
| 1475 |
# ================================================================== #
|
| 1476 |
|
| 1477 |
_SLOT_CSS = """
|
| 1478 |
-
/* Cap
|
| 1479 |
-
|
| 1480 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1481 |
object-fit: contain;
|
| 1482 |
}
|
| 1483 |
"""
|
|
|
|
| 1290 |
plugins = [regionsPlugin];
|
| 1291 |
}}
|
| 1292 |
|
| 1293 |
+
// Convert base64 audio to a Blob URL — WaveSurfer v7 handles blob: URLs
|
| 1294 |
+
// much more reliably than data: URIs for waveform rendering.
|
| 1295 |
+
const b64 = '{b64}';
|
| 1296 |
+
const byteChars = atob(b64);
|
| 1297 |
+
const byteNums = new Uint8Array(byteChars.length);
|
| 1298 |
+
for (let i = 0; i < byteChars.length; i++) byteNums[i] = byteChars.charCodeAt(i);
|
| 1299 |
+
const blob = new Blob([byteNums], {{type: 'audio/wav'}});
|
| 1300 |
+
const blobUrl = URL.createObjectURL(blob);
|
| 1301 |
+
|
| 1302 |
// Wait until the container has a non-zero width before creating WaveSurfer,
|
| 1303 |
// otherwise it renders blank (container is 0px when Gradio first injects HTML).
|
| 1304 |
const wfContainer = document.getElementById('wf_{slot_id}');
|
|
|
|
| 1311 |
barWidth: 2,
|
| 1312 |
barGap: 1,
|
| 1313 |
barRadius: 2,
|
| 1314 |
+
url: blobUrl,
|
| 1315 |
plugins: plugins,
|
| 1316 |
}});
|
| 1317 |
|
|
|
|
| 1319 |
ws.setVolume(0);
|
| 1320 |
ws.on('ready', function() {{
|
| 1321 |
ws.setVolume(0);
|
|
|
|
| 1322 |
ws.pause();
|
| 1323 |
const segments = {segs_json};
|
| 1324 |
const colors = {json.dumps(colors)};
|
|
|
|
| 1343 |
attachVideoSync(ws);
|
| 1344 |
}});
|
| 1345 |
|
| 1346 |
+
ws.on('error', function(err) {{
|
| 1347 |
+
console.error('[WaveSurfer {slot_id}] error:', err);
|
| 1348 |
+
}});
|
| 1349 |
+
|
| 1350 |
// Also silence if WaveSurfer tries to play for any reason
|
| 1351 |
ws.on('play', function() {{ ws.pause(); ws.setVolume(0); }});
|
| 1352 |
|
|
|
|
| 1367 |
}}
|
| 1368 |
}});
|
| 1369 |
ro.observe(wfContainer);
|
| 1370 |
+
// Fallback after 1s in case ResizeObserver fires late
|
| 1371 |
setTimeout(function() {{
|
| 1372 |
if (!window["_wf_ws_{slot_id}"]) {{ ro.disconnect(); createWS(); }}
|
| 1373 |
+
}}, 1000);
|
| 1374 |
}} else {{
|
| 1375 |
// Container not in DOM yet — wait for it
|
| 1376 |
setTimeout(loadWS, 200);
|
|
|
|
| 1419 |
for i in range(MAX_SLOTS):
|
| 1420 |
with gr.Group(visible=(i == 0)) as g:
|
| 1421 |
slot_id = f"{tab_prefix}_{i}"
|
| 1422 |
+
vids.append(gr.Video(label=f"Generation {i+1} — Video", height=340))
|
| 1423 |
waveforms.append(gr.HTML(
|
| 1424 |
value="<p style='color:#888;font-size:12px'>Generate audio to see waveform.</p>",
|
| 1425 |
label=f"Generation {i+1} — Waveform",
|
|
|
|
| 1487 |
# ================================================================== #
|
| 1488 |
|
| 1489 |
_SLOT_CSS = """
|
| 1490 |
+
/* Cap the entire video component (including the loading/processing state)
|
| 1491 |
+
so the waveform below is never pushed out of view */
|
| 1492 |
+
.gradio-video {
|
| 1493 |
+
max-height: 380px !important;
|
| 1494 |
+
overflow: hidden;
|
| 1495 |
+
}
|
| 1496 |
+
.gradio-video video,
|
| 1497 |
+
.gradio-video .video-container,
|
| 1498 |
+
.gradio-video .wrap {
|
| 1499 |
+
max-height: 340px !important;
|
| 1500 |
object-fit: contain;
|
| 1501 |
}
|
| 1502 |
"""
|