fffiloni commited on
Commit
f5368d5
·
verified ·
1 Parent(s): 25e0d1b

Upload 8 files

Browse files
Files changed (3) hide show
  1. app.py +191 -92
  2. studio_component.py +1 -2
  3. studio_component.pyi +0 -1
app.py CHANGED
@@ -109,7 +109,7 @@ def _load_model() -> Any | None:
109
  )
110
  from safetensors.torch import load_file
111
  except Exception as exc:
112
- MODEL_ERROR = f"Dépendances MuScriptor indisponibles : {type(exc).__name__}: {exc}"
113
  return None
114
 
115
  NoteStartEvent = _NoteStartEvent
@@ -120,8 +120,8 @@ def _load_model() -> Any | None:
120
  token = os.environ.get("HF_TOKEN")
121
  if not token:
122
  MODEL_ERROR = (
123
- "HF_TOKEN absent. Acceptez la licence du modèle MuScriptor medium, "
124
- "puis ajoutez un secret HF_TOKEN en lecture dans les réglages du Space."
125
  )
126
  return None
127
 
@@ -144,18 +144,18 @@ def _load_model() -> Any | None:
144
  tokenizer = MT3Tokenizer(instrument_vocabulary="MT3_FULL_PLUS", max_shift_steps=1001)
145
  return TranscriptionModel(model=model, tokenizer=tokenizer, device=device)
146
  except Exception as exc:
147
- MODEL_ERROR = f"Chargement du modèle impossible : {type(exc).__name__}: {exc}"
148
  return None
149
 
150
 
151
  if os.environ.get("MUSCRIPTOR_SKIP_MODEL_LOAD") != "1":
152
  started = time.perf_counter()
153
- print(f"[MuScriptor Studio] Chargement du modèle {MODEL_VARIANT}…", flush=True)
154
  MODEL = _load_model()
155
  if MODEL is None:
156
- print(f"[MuScriptor Studio] Mode interface uniquement : {MODEL_ERROR}", file=sys.stderr, flush=True)
157
  else:
158
- print(f"[MuScriptor Studio] Modèle prêt en {time.perf_counter() - started:.2f}s.", flush=True)
159
 
160
 
161
  def _audio_path(value: Any) -> str | None:
@@ -217,7 +217,7 @@ def _color_for(name: str) -> str:
217
 
218
 
219
  def _slug(name: str) -> str:
220
- return re.sub(r"[^a-z0-9]+", "-", name.lower()).strip("-") or "piste"
221
 
222
 
223
  def _data_uri(data: bytes, mime: str = "audio/midi") -> str:
@@ -328,7 +328,7 @@ def _event_for_instrument(event: Any, instrument: str) -> bool:
328
 
329
  def _write_midi_outputs(events: list[Any], track_names: list[str]) -> tuple[Path, dict[str, Path], bytes, dict[str, bytes]]:
330
  if MODEL is None:
331
- raise RuntimeError(MODEL_ERROR or "Modèle non chargé.")
332
  output_dir = Path(tempfile.mkdtemp(prefix="muscriptor-midi-"))
333
  full_bytes = MODEL.events_to_midi_bytes(iter(events))
334
  full_path = output_dir / "transcription-complete.mid"
@@ -389,17 +389,17 @@ def transcribe_audio(
389
  ]:
390
  path = _audio_path(audio)
391
  if not path:
392
- yield _error_result("Importez un fichier audio avant de lancer la transcription.")
393
  return
394
 
395
  audio_name = Path(path).name
396
  duration = _audio_duration(path)
397
  if duration <= 0:
398
- yield _error_result("La durée du fichier audio n’a pas pu être déterminée.", audio_name, original_audio=path)
399
  return
400
  if duration > MAX_AUDIO_SECONDS:
401
  yield _error_result(
402
- f"Ce Space accepte des enregistrements de {MAX_AUDIO_SECONDS / 60:.1f} minutes maximum.",
403
  audio_name,
404
  duration,
405
  path,
@@ -407,7 +407,7 @@ def transcribe_audio(
407
  return
408
  if MODEL is None:
409
  yield _error_result(
410
- MODEL_ERROR or "Le modèle MuScriptor n’est pas disponible.",
411
  audio_name,
412
  duration,
413
  path,
@@ -440,9 +440,9 @@ def transcribe_audio(
440
  tracks = _track_payloads(notes, requested)
441
  fraction = event.completed / max(1, event.total)
442
  status = (
443
- "ZeroGPU prêt · préparation de la première fenêtre"
444
  if event.completed == 0
445
- else f"Fenêtre {event.completed}/{event.total} transcrite"
446
  )
447
  viewer = _viewer_payload(
448
  state="transcribing",
@@ -470,7 +470,7 @@ def transcribe_audio(
470
  tracks = _track_payloads(notes, midi_by_instrument=midi_by_instrument)
471
  viewer = _viewer_payload(
472
  state="complete",
473
- status=f"Transcription terminée en {elapsed:.1f} s · partition disponible sur demande",
474
  progress=1,
475
  audio_name=audio_name,
476
  elapsed=elapsed,
@@ -499,7 +499,7 @@ def transcribe_audio(
499
  )
500
  except Exception as exc:
501
  elapsed = time.perf_counter() - started
502
- message = f"Transcription interrompue : {type(exc).__name__}: {exc}"
503
  print(f"[MuScriptor Studio] {message}", file=sys.stderr, flush=True)
504
  tracks = _track_payloads(_notes_from_events(events), requested)
505
  viewer = _viewer_payload(
@@ -521,8 +521,36 @@ def transcribe_audio(
521
  )
522
 
523
 
524
- def reset_score_outputs() -> tuple[None, None, None, dict[str, Any]]:
525
- return None, None, None, gr.update(interactive=False)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
526
 
527
 
528
  def finalize_notation(
@@ -550,7 +578,7 @@ def finalize_notation(
550
  updated.update(
551
  {
552
  "state": "ready",
553
- "status": "Transcription et partition prêtes",
554
  "score_svg": result.preview_svg,
555
  "score_pages": len(result.svg_pages),
556
  "notation": {
@@ -572,98 +600,163 @@ def finalize_notation(
572
  except Exception as exc:
573
  updated = dict(viewer)
574
  updated["state"] = "notation_error"
575
- updated["status"] = f"MIDI prêt, mais partition non générée : {type(exc).__name__}: {exc}"
576
  return None, None, None, updated
577
 
578
 
579
  APP_CSS = (ROOT / "frontend" / "app.css").read_text(encoding="utf-8")
580
 
581
- INSTRUMENT_CHOICES = [(_display_name(name), name) for name in sorted(INSTRUMENT_NAMES)]
582
 
583
  HEADER = """
584
- <header class="studio-masthead">
585
- <div class="studio-brand"><span class="studio-logo">♫</span><div><strong>MuScriptor Studio</strong><small>Audio multipiste vers MIDI et partition</small></div></div>
586
- <div class="studio-badges"><span class="model-badge">Large · 1.4B</span><span class="gpu-badge">ZeroGPU</span></div>
 
 
 
 
 
 
587
  </header>
588
  """
589
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
590
  with gr.Blocks(title="MuScriptor Studio") as demo:
591
- gr.HTML(HEADER)
592
- with gr.Row(elem_id="input-grid", equal_height=True):
593
- with gr.Column(scale=7, min_width=360, elem_classes="input-card"):
594
- gr.Markdown(
595
- f"### 1. Importer un enregistrement\n"
596
- f"Déposez un morceau de {MAX_AUDIO_SECONDS / 60:.0f} minutes maximum."
597
- )
598
- audio_input = gr.Audio(
599
- label="Audio source",
600
- sources=["upload"],
601
- type="filepath",
602
- format="wav",
603
- elem_id="audio-input",
604
- )
605
- transcribe_button = gr.Button(
606
- "Transcrire le morceau",
607
- variant="primary",
608
- size="lg",
609
- elem_id="transcribe-button",
610
- )
611
- with gr.Column(scale=5, min_width=320, elem_classes="settings-card"):
612
- gr.Markdown("### 2. Paramètres")
613
- instrument_input = gr.CheckboxGroup(
614
- choices=INSTRUMENT_CHOICES,
615
- value=[],
616
- label="Known instruments",
617
- info="Optional — leave empty for automatic discovery.",
618
- )
619
- with gr.Accordion("Décodage avancé", open=False):
620
- use_sampling_input = gr.Checkbox(label="Décodage créatif", value=False)
621
- temperature_input = gr.Slider(0.2, 1.4, value=1.0, step=0.1, label="Température")
622
- beam_size_input = gr.Slider(
623
- 1,
624
- 4,
625
- value=1,
626
- step=1,
627
- label="Largeur du beam",
628
- info="Conservez 1 pour les morceaux longs ; 2–4 multiplient le temps GPU.",
629
  )
630
- with gr.Accordion("Partition", open=True):
631
- with gr.Row():
632
- tempo_input = gr.Number(value=120, minimum=20, maximum=300, label="Tempo (BPM)")
633
- time_signature_input = gr.Dropdown(
634
- ["4/4", "3/4", "6/8", "2/4", "12/8"], value="4/4", label="Mesure"
 
 
 
 
 
635
  )
636
- quantization_input = gr.Radio(
637
- ["1/8", "1/16", "1/32"], value="1/16", label="Quantification"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
638
  )
639
- solfege_input = gr.Checkbox(label="Afficher Do Ré Mi", value=False)
640
- generate_score_button = gr.Button(
641
- "Generate score from transcription",
642
- variant="secondary",
 
 
 
 
 
 
643
  interactive=False,
644
- elem_id="generate-score-button",
 
645
  )
646
 
647
- session_state = gr.State(value={})
648
- viewer = StudioViewer(elem_id="studio-viewer")
649
- original_audio_output = gr.Audio(
650
- label="Original audio playback",
651
- interactive=False,
652
- visible="hidden",
653
- elem_id="original-audio-output",
654
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
655
 
656
- with gr.Accordion("Downloads", open=False, elem_id="downloads-panel"):
657
- with gr.Row(elem_id="downloads-row"):
658
- full_midi_output = gr.File(label="Full MIDI")
659
- track_midi_output = gr.File(label="MIDI by instrument", file_count="multiple")
660
- musicxml_output = gr.File(label="MusicXML")
661
- pdf_output = gr.File(label="Score PDF")
662
- bundle_output = gr.File(label="All exports (.zip)")
663
 
664
  preflight = transcribe_button.click(
665
  reset_score_outputs,
666
- outputs=[musicxml_output, pdf_output, bundle_output, generate_score_button],
 
 
 
 
 
 
 
 
 
 
 
667
  queue=False,
668
  show_progress="hidden",
669
  )
@@ -704,5 +797,11 @@ if __name__ == "__main__":
704
  demo.launch(
705
  css=APP_CSS,
706
  theme=gr.themes.Base(primary_hue="violet", neutral_hue="slate"),
707
- footer_links=["gradio"],
 
 
 
 
 
 
708
  )
 
109
  )
110
  from safetensors.torch import load_file
111
  except Exception as exc:
112
+ MODEL_ERROR = f"MuScriptor dependencies are unavailable: {type(exc).__name__}: {exc}"
113
  return None
114
 
115
  NoteStartEvent = _NoteStartEvent
 
120
  token = os.environ.get("HF_TOKEN")
121
  if not token:
122
  MODEL_ERROR = (
123
+ "HF_TOKEN is missing. Accept the MuScriptor large model license, then "
124
+ "add a read-only HF_TOKEN secret in the Space settings."
125
  )
126
  return None
127
 
 
144
  tokenizer = MT3Tokenizer(instrument_vocabulary="MT3_FULL_PLUS", max_shift_steps=1001)
145
  return TranscriptionModel(model=model, tokenizer=tokenizer, device=device)
146
  except Exception as exc:
147
+ MODEL_ERROR = f"The model could not be loaded: {type(exc).__name__}: {exc}"
148
  return None
149
 
150
 
151
  if os.environ.get("MUSCRIPTOR_SKIP_MODEL_LOAD") != "1":
152
  started = time.perf_counter()
153
+ print(f"[MuScriptor Studio] Loading the {MODEL_VARIANT} model…", flush=True)
154
  MODEL = _load_model()
155
  if MODEL is None:
156
+ print(f"[MuScriptor Studio] Interface-only mode: {MODEL_ERROR}", file=sys.stderr, flush=True)
157
  else:
158
+ print(f"[MuScriptor Studio] Model ready in {time.perf_counter() - started:.2f}s.", flush=True)
159
 
160
 
161
  def _audio_path(value: Any) -> str | None:
 
217
 
218
 
219
  def _slug(name: str) -> str:
220
+ return re.sub(r"[^a-z0-9]+", "-", name.lower()).strip("-") or "track"
221
 
222
 
223
  def _data_uri(data: bytes, mime: str = "audio/midi") -> str:
 
328
 
329
  def _write_midi_outputs(events: list[Any], track_names: list[str]) -> tuple[Path, dict[str, Path], bytes, dict[str, bytes]]:
330
  if MODEL is None:
331
+ raise RuntimeError(MODEL_ERROR or "Model not loaded.")
332
  output_dir = Path(tempfile.mkdtemp(prefix="muscriptor-midi-"))
333
  full_bytes = MODEL.events_to_midi_bytes(iter(events))
334
  full_path = output_dir / "transcription-complete.mid"
 
389
  ]:
390
  path = _audio_path(audio)
391
  if not path:
392
+ yield _error_result("Upload an audio file before starting transcription.")
393
  return
394
 
395
  audio_name = Path(path).name
396
  duration = _audio_duration(path)
397
  if duration <= 0:
398
+ yield _error_result("The audio duration could not be determined.", audio_name, original_audio=path)
399
  return
400
  if duration > MAX_AUDIO_SECONDS:
401
  yield _error_result(
402
+ f"This Space accepts recordings up to {MAX_AUDIO_SECONDS / 60:.1f} minutes.",
403
  audio_name,
404
  duration,
405
  path,
 
407
  return
408
  if MODEL is None:
409
  yield _error_result(
410
+ MODEL_ERROR or "The MuScriptor model is unavailable.",
411
  audio_name,
412
  duration,
413
  path,
 
440
  tracks = _track_payloads(notes, requested)
441
  fraction = event.completed / max(1, event.total)
442
  status = (
443
+ "ZeroGPU ready · preparing the first five-second window"
444
  if event.completed == 0
445
+ else f"Transcribed window {event.completed}/{event.total}"
446
  )
447
  viewer = _viewer_payload(
448
  state="transcribing",
 
470
  tracks = _track_payloads(notes, midi_by_instrument=midi_by_instrument)
471
  viewer = _viewer_payload(
472
  state="complete",
473
+ status=f"Transcription complete in {elapsed:.1f}s · score available on demand",
474
  progress=1,
475
  audio_name=audio_name,
476
  elapsed=elapsed,
 
499
  )
500
  except Exception as exc:
501
  elapsed = time.perf_counter() - started
502
+ message = f"Transcription stopped: {type(exc).__name__}: {exc}"
503
  print(f"[MuScriptor Studio] {message}", file=sys.stderr, flush=True)
504
  tracks = _track_payloads(_notes_from_events(events), requested)
505
  viewer = _viewer_payload(
 
521
  )
522
 
523
 
524
+ def reset_score_outputs(audio: Any) -> tuple[Any, ...]:
525
+ """Clear the previous session immediately, before ZeroGPU enters its queue."""
526
+
527
+ path = _audio_path(audio)
528
+ audio_name = Path(path).name if path else ""
529
+ duration = _audio_duration(path) if path else 0.0
530
+ viewer = _viewer_payload(
531
+ state="queued" if path else "idle",
532
+ status=(
533
+ "Request sent · waiting for a ZeroGPU worker"
534
+ if path
535
+ else "Upload a recording to begin."
536
+ ),
537
+ progress=0.01 if path else 0,
538
+ audio_name=audio_name,
539
+ elapsed=0,
540
+ duration=duration,
541
+ tracks=[],
542
+ )
543
+ return (
544
+ path,
545
+ None,
546
+ None,
547
+ None,
548
+ None,
549
+ None,
550
+ viewer,
551
+ {},
552
+ gr.update(interactive=False),
553
+ )
554
 
555
 
556
  def finalize_notation(
 
578
  updated.update(
579
  {
580
  "state": "ready",
581
+ "status": "Transcription and score are ready",
582
  "score_svg": result.preview_svg,
583
  "score_pages": len(result.svg_pages),
584
  "notation": {
 
600
  except Exception as exc:
601
  updated = dict(viewer)
602
  updated["state"] = "notation_error"
603
+ updated["status"] = f"MIDI is ready, but the score could not be generated: {type(exc).__name__}: {exc}"
604
  return None, None, None, updated
605
 
606
 
607
  APP_CSS = (ROOT / "frontend" / "app.css").read_text(encoding="utf-8")
608
 
609
+ INSTRUMENT_CHOICES = [(_display_name(name), name) for name in INSTRUMENT_NAMES]
610
 
611
  HEADER = """
612
+ <header class="masthead-inner">
613
+ <a class="brand" href="https://github.com/muscriptor/muscriptor" target="_blank" rel="noreferrer">
614
+ <span class="brand-mark" aria-hidden="true"><i></i><i></i><i></i><i></i></span>
615
+ <span>MuScriptor Studio</span>
616
+ </a>
617
+ <div class="header-meta">
618
+ <span id="model-badge"><b></b> Large · 1.4B</span>
619
+ <span class="zerogpu-badge">ZeroGPU</span>
620
+ </div>
621
  </header>
622
  """
623
 
624
+ INTRO = """
625
+ <div class="intro-copy">
626
+ <span class="eyebrow">Multitrack transcription</span>
627
+ <h1>Turn a recording into<br><em>editable music.</em></h1>
628
+ <p>Separate a performance into instrument-aware MIDI tracks, inspect every note, compare it with the original recording and create an editable score.</p>
629
+ </div>
630
+ """
631
+
632
+ UPLOAD_HEADING = f"""
633
+ <div class="section-heading">
634
+ <span class="step-number">01</span>
635
+ <div><h2>Choose audio</h2><p>WAV, MP3, FLAC or OGG · up to {MAX_AUDIO_SECONDS / 60:.0f} minutes</p></div>
636
+ </div>
637
+ """
638
+
639
+ RESULT_HEADING = """
640
+ <div class="section-heading result-heading">
641
+ <span class="step-number">02</span>
642
+ <div><h2>Transcription studio</h2><p>Original/MIDI comparison, isolated tracks and notation</p></div>
643
+ </div>
644
+ """
645
+
646
+ FOOTNOTE = """
647
+ <div class="footnote">
648
+ <span>Audio is processed ephemerally and is not retained.</span>
649
+ <span>MuScriptor Large · ZeroGPU · CC BY-NC 4.0 weights</span>
650
+ </div>
651
+ """
652
+
653
  with gr.Blocks(title="MuScriptor Studio") as demo:
654
+ with gr.Column(elem_id="app-shell"):
655
+ gr.HTML(HEADER, elem_id="masthead")
656
+ gr.HTML(INTRO, elem_id="intro")
657
+
658
+ with gr.Row(elem_id="studio-grid", equal_height=False):
659
+ with gr.Column(scale=4, min_width=320, elem_id="upload-card"):
660
+ gr.HTML(UPLOAD_HEADING)
661
+ audio_input = gr.Audio(
662
+ label="Drop audio here",
663
+ sources=["upload"],
664
+ type="filepath",
665
+ elem_id="audio-input",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
666
  )
667
+ with gr.Accordion(
668
+ "Guide the transcription",
669
+ open=False,
670
+ elem_id="advanced-settings",
671
+ ):
672
+ instrument_input = gr.CheckboxGroup(
673
+ choices=INSTRUMENT_CHOICES,
674
+ value=[],
675
+ label="Known instruments",
676
+ info="Optional — leave empty for automatic discovery.",
677
  )
678
+ use_sampling_input = gr.Checkbox(
679
+ label="Creative decoding",
680
+ value=False,
681
+ info="Use stochastic sampling instead of deterministic decoding.",
682
+ )
683
+ temperature_input = gr.Slider(
684
+ 0.2,
685
+ 1.4,
686
+ value=1.0,
687
+ step=0.1,
688
+ label="Temperature",
689
+ )
690
+ beam_size_input = gr.Slider(
691
+ 1,
692
+ 4,
693
+ value=1,
694
+ step=1,
695
+ label="Beam width",
696
+ info="1 is fastest. Widths 2–4 multiply GPU time.",
697
+ )
698
+ transcribe_button = gr.Button(
699
+ "Transcribe audio",
700
+ variant="primary",
701
+ size="lg",
702
+ elem_id="transcribe-button",
703
  )
704
+ gr.HTML(
705
+ '<p class="cold-note"><span></span> The first run can take a moment while ZeroGPU restores the model.</p>'
706
+ )
707
+
708
+ with gr.Column(scale=7, min_width=420, elem_id="result-panel"):
709
+ gr.HTML(RESULT_HEADING)
710
+ session_state = gr.State(value={})
711
+ viewer = StudioViewer(elem_id="studio-viewer")
712
+ original_audio_output = gr.Audio(
713
+ label="Original audio playback",
714
  interactive=False,
715
+ visible="hidden",
716
+ elem_id="original-audio-output",
717
  )
718
 
719
+ with gr.Accordion("Create an editable score", open=False, elem_id="score-settings"):
720
+ with gr.Row():
721
+ tempo_input = gr.Number(value=120, minimum=20, maximum=300, label="Tempo (BPM)")
722
+ time_signature_input = gr.Dropdown(
723
+ ["4/4", "3/4", "6/8", "2/4", "12/8"], value="4/4", label="Time signature"
724
+ )
725
+ quantization_input = gr.Radio(
726
+ ["1/8", "1/16", "1/32"], value="1/16", label="Quantization"
727
+ )
728
+ solfege_input = gr.Checkbox(label="Show solfège names (Do, Ré, Mi)", value=False)
729
+ generate_score_button = gr.Button(
730
+ "Generate score from transcription",
731
+ variant="secondary",
732
+ interactive=False,
733
+ elem_id="generate-score-button",
734
+ )
735
+
736
+ with gr.Accordion("All downloads", open=False, elem_id="downloads-panel"):
737
+ with gr.Row(elem_id="downloads-row"):
738
+ full_midi_output = gr.File(label="Full MIDI")
739
+ track_midi_output = gr.File(label="MIDI by instrument", file_count="multiple")
740
+ musicxml_output = gr.File(label="MusicXML")
741
+ pdf_output = gr.File(label="Score PDF")
742
+ bundle_output = gr.File(label="All exports (.zip)")
743
 
744
+ gr.HTML(FOOTNOTE)
 
 
 
 
 
 
745
 
746
  preflight = transcribe_button.click(
747
  reset_score_outputs,
748
+ inputs=[audio_input],
749
+ outputs=[
750
+ original_audio_output,
751
+ full_midi_output,
752
+ track_midi_output,
753
+ musicxml_output,
754
+ pdf_output,
755
+ bundle_output,
756
+ viewer,
757
+ session_state,
758
+ generate_score_button,
759
+ ],
760
  queue=False,
761
  show_progress="hidden",
762
  )
 
797
  demo.launch(
798
  css=APP_CSS,
799
  theme=gr.themes.Base(primary_hue="violet", neutral_hue="slate"),
800
+ js="""() => {
801
+ document.documentElement.classList.add('dark');
802
+ document.body.classList.add('dark');
803
+ document.body.style.background = '#090b0f';
804
+ try { localStorage.setItem('theme', 'dark'); } catch (_) {}
805
+ }""",
806
+ footer_links=[],
807
  )
studio_component.py CHANGED
@@ -18,7 +18,7 @@ def _read_frontend(name: str) -> str:
18
  def initial_studio_value() -> dict[str, Any]:
19
  return {
20
  "state": "idle",
21
- "status": "Importez un enregistrement pour commencer.",
22
  "progress": 0,
23
  "audio_name": "",
24
  "elapsed": 0,
@@ -45,7 +45,6 @@ class StudioViewer(gr.HTML):
45
  js_on_load=f"{synth_bundle}\n{viewer_script}",
46
  apply_default_css=False,
47
  container=False,
48
- min_height=780,
49
  **kwargs,
50
  )
51
 
 
18
  def initial_studio_value() -> dict[str, Any]:
19
  return {
20
  "state": "idle",
21
+ "status": "Upload a recording to begin.",
22
  "progress": 0,
23
  "audio_name": "",
24
  "elapsed": 0,
 
45
  js_on_load=f"{synth_bundle}\n{viewer_script}",
46
  apply_default_css=False,
47
  container=False,
 
48
  **kwargs,
49
  )
50
 
studio_component.pyi CHANGED
@@ -46,7 +46,6 @@ class StudioViewer(gr.HTML):
46
  js_on_load=f"{synth_bundle}\n{viewer_script}",
47
  apply_default_css=False,
48
  container=False,
49
- min_height=780,
50
  **kwargs,
51
  )
52
 
 
46
  js_on_load=f"{synth_bundle}\n{viewer_script}",
47
  apply_default_css=False,
48
  container=False,
 
49
  **kwargs,
50
  )
51