BoxOfColors commited on
Commit
1cf1eb7
Β·
1 Parent(s): 504a99f
Files changed (1) hide show
  1. app.py +52 -26
app.py CHANGED
@@ -1209,7 +1209,9 @@ def _build_waveform_html(audio_path: str, segments: list, slot_id: str,
1209
  const canvas = document.getElementById('wf_canvas_{slot_id}');
1210
  if (!canvas) return;
1211
  const dpr = window.devicePixelRatio || 1;
1212
- const W = canvas.offsetWidth || canvas.parentElement.offsetWidth || 600;
 
 
1213
  const H = 80;
1214
  canvas.width = W * dpr;
1215
  canvas.height = H * dpr;
@@ -1276,7 +1278,9 @@ def _build_waveform_html(audio_path: str, segments: list, slot_id: str,
1276
  const canvas = document.getElementById('wf_playhead_{slot_id}');
1277
  if (!canvas) return;
1278
  const dpr = window.devicePixelRatio || 1;
1279
- const W = canvas.offsetWidth || canvas.parentElement.offsetWidth || 600;
 
 
1280
  const H = 80;
1281
  if (canvas.width !== W*dpr) {{ canvas.width=W*dpr; canvas.height=H*dpr; }}
1282
  const ctx = canvas.getContext('2d');
@@ -1317,33 +1321,39 @@ def _build_waveform_html(audio_path: str, segments: list, slot_id: str,
1317
  }}
1318
 
1319
  // ── Decode audio & render ─────────────────────────────────────────
1320
- function init() {{
1321
- const b64str = '{b64}';
1322
- // decode base64 β†’ ArrayBuffer
1323
- const bin = atob(b64str);
1324
- const buf = new Uint8Array(bin.length);
1325
- for (let i = 0; i < bin.length; i++) buf[i] = bin.charCodeAt(i);
1326
-
1327
- const AudioCtx = window.AudioContext || window.webkitAudioContext;
1328
- if (!AudioCtx) {{ console.warn('No AudioContext'); return; }}
1329
- const actx = new AudioCtx();
1330
- actx.decodeAudioData(buf.buffer, function(audioBuffer) {{
 
 
1331
  const channelData = audioBuffer.getChannelData(0);
1332
- drawWaveform(channelData, audioBuffer.duration);
1333
- attachVideoSync();
1334
- actx.close();
 
 
 
 
 
 
 
 
 
 
 
 
1335
  }}, function(err) {{
1336
  console.error('[waveform {slot_id}] decodeAudioData error:', err);
1337
  }});
1338
  }}
1339
-
1340
- // Run after the canvas is in the DOM and has layout
1341
- if (document.readyState === 'loading') {{
1342
- document.addEventListener('DOMContentLoaded', init);
1343
- }} else {{
1344
- // Small delay to let Gradio finish laying out the component
1345
- setTimeout(init, 100);
1346
- }}
1347
  }})();
1348
  </script>
1349
  """
@@ -1359,7 +1369,7 @@ def _make_output_slots(tab_prefix: str) -> tuple:
1359
  for i in range(MAX_SLOTS):
1360
  with gr.Group(visible=(i == 0)) as g:
1361
  slot_id = f"{tab_prefix}_{i}"
1362
- vids.append(gr.Video(label=f"Generation {i+1} β€” Video", height=340))
1363
  waveforms.append(gr.HTML(
1364
  value="<p style='color:#888;font-size:12px'>Generate audio to see waveform.</p>",
1365
  label=f"Generation {i+1} β€” Waveform",
@@ -1426,7 +1436,23 @@ def _update_slot_visibility(n):
1426
  # GRADIO UI #
1427
  # ================================================================== #
1428
 
1429
- _SLOT_CSS = ""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1430
 
1431
  with gr.Blocks(title="Generate Audio for Video", css=_SLOT_CSS) as demo:
1432
  gr.Markdown(
 
1209
  const canvas = document.getElementById('wf_canvas_{slot_id}');
1210
  if (!canvas) return;
1211
  const dpr = window.devicePixelRatio || 1;
1212
+ const W = canvas.getBoundingClientRect().width
1213
+ || (canvas.parentElement ? canvas.parentElement.getBoundingClientRect().width : 0)
1214
+ || 600;
1215
  const H = 80;
1216
  canvas.width = W * dpr;
1217
  canvas.height = H * dpr;
 
1278
  const canvas = document.getElementById('wf_playhead_{slot_id}');
1279
  if (!canvas) return;
1280
  const dpr = window.devicePixelRatio || 1;
1281
+ const W = canvas.getBoundingClientRect().width
1282
+ || (canvas.parentElement ? canvas.parentElement.getBoundingClientRect().width : 0)
1283
+ || 600;
1284
  const H = 80;
1285
  if (canvas.width !== W*dpr) {{ canvas.width=W*dpr; canvas.height=H*dpr; }}
1286
  const ctx = canvas.getContext('2d');
 
1321
  }}
1322
 
1323
  // ── Decode audio & render ─────────────────────────────────────────
1324
+ // Decode audio immediately (doesn't need canvas dimensions).
1325
+ // Drawing is deferred until the canvas actually has a non-zero width.
1326
+ const b64str = '{b64}';
1327
+ const bin = atob(b64str);
1328
+ const buf = new Uint8Array(bin.length);
1329
+ for (let i = 0; i < bin.length; i++) buf[i] = bin.charCodeAt(i);
1330
+
1331
+ const AudioCtx = window.AudioContext || window.webkitAudioContext;
1332
+ if (!AudioCtx) {{ console.warn('[waveform {slot_id}] No AudioContext available'); }}
1333
+ else {{
1334
+ // Use OfflineAudioContext so decoding works even without user gesture
1335
+ const tmpCtx = new AudioCtx({{latencyHint:'playback', sampleRate:44100}});
1336
+ tmpCtx.decodeAudioData(buf.buffer.slice(0), function(audioBuffer) {{
1337
  const channelData = audioBuffer.getChannelData(0);
1338
+ const duration = audioBuffer.duration;
1339
+ tmpCtx.close();
1340
+
1341
+ // Now wait for the canvas to have layout width before drawing
1342
+ function tryDraw() {{
1343
+ const canvas = document.getElementById('wf_canvas_{slot_id}');
1344
+ if (!canvas) {{ setTimeout(tryDraw, 100); return; }}
1345
+ // Force a width by walking up to a sized ancestor if needed
1346
+ let W = canvas.getBoundingClientRect().width;
1347
+ if (W <= 0) W = canvas.parentElement ? canvas.parentElement.getBoundingClientRect().width : 0;
1348
+ if (W <= 0) {{ setTimeout(tryDraw, 100); return; }}
1349
+ drawWaveform(channelData, duration);
1350
+ attachVideoSync();
1351
+ }}
1352
+ tryDraw();
1353
  }}, function(err) {{
1354
  console.error('[waveform {slot_id}] decodeAudioData error:', err);
1355
  }});
1356
  }}
 
 
 
 
 
 
 
 
1357
  }})();
1358
  </script>
1359
  """
 
1369
  for i in range(MAX_SLOTS):
1370
  with gr.Group(visible=(i == 0)) as g:
1371
  slot_id = f"{tab_prefix}_{i}"
1372
+ vids.append(gr.Video(label=f"Generation {i+1} β€” Video"))
1373
  waveforms.append(gr.HTML(
1374
  value="<p style='color:#888;font-size:12px'>Generate audio to see waveform.</p>",
1375
  label=f"Generation {i+1} β€” Waveform",
 
1436
  # GRADIO UI #
1437
  # ================================================================== #
1438
 
1439
+ _SLOT_CSS = """
1440
+ /* Make all video components (input and output) use the same responsive
1441
+ aspect-ratio container so they match at any window size. */
1442
+ .gradio-video,
1443
+ .gradio-video > div {
1444
+ aspect-ratio: 16 / 9;
1445
+ width: 100%;
1446
+ height: auto !important;
1447
+ min-height: unset !important;
1448
+ max-height: unset !important;
1449
+ }
1450
+ .gradio-video video {
1451
+ width: 100%;
1452
+ height: 100%;
1453
+ object-fit: contain;
1454
+ }
1455
+ """
1456
 
1457
  with gr.Blocks(title="Generate Audio for Video", css=_SLOT_CSS) as demo:
1458
  gr.Markdown(