urwebsiteaz-ux commited on
Commit
caf6590
·
1 Parent(s): abf19d6

Initial AUTOLYRICS space

Browse files
README.md CHANGED
@@ -1,13 +1,15 @@
1
  ---
2
- title: Autolyrics
3
- emoji: 💻
4
  colorFrom: gray
5
- colorTo: pink
6
  sdk: gradio
7
- sdk_version: 6.14.0
8
- python_version: '3.13'
9
  app_file: app.py
10
  pinned: false
 
 
 
11
  ---
12
 
13
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: AUTOLYRICS
3
+ emoji: 🎙
4
  colorFrom: gray
5
+ colorTo: black
6
  sdk: gradio
7
+ sdk_version: 5.6.0
 
8
  app_file: app.py
9
  pinned: false
10
+ license: apache-2.0
11
+ suggested_hardware: t4-small
12
+ short_description: Singing-voice lyrics transcription via fine-tuned Whisper.
13
  ---
14
 
15
+ See [GitHub](https://github.com/ram.duvvuri/autolyrics) for the full story.
app.py ADDED
@@ -0,0 +1,159 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """AUTOLYRICS — side-by-side baseline vs fine-tuned Gradio demo."""
2
+ import os
3
+ import time
4
+ import torch
5
+ import torchaudio
6
+ import gradio as gr
7
+ from transformers import WhisperProcessor, WhisperForConditionalGeneration
8
+ from peft import PeftModel
9
+
10
+ BASE_MODEL = "openai/whisper-small"
11
+ ADAPTER_REPO = os.environ.get(
12
+ "ADAPTER_REPO", "YOURNAME/autolyrics-whisper-small-lora")
13
+
14
+ DEVICE = "cuda" if torch.cuda.is_available() else "cpu"
15
+ DTYPE = torch.float16 if DEVICE == "cuda" else torch.float32
16
+
17
+ # ---------- Lazy model loading ----------
18
+ print(f"Loading models on {DEVICE}…")
19
+ processor = WhisperProcessor.from_pretrained(BASE_MODEL)
20
+
21
+ baseline_model = WhisperForConditionalGeneration.from_pretrained(
22
+ BASE_MODEL, torch_dtype=DTYPE).to(DEVICE).eval()
23
+ for m in (baseline_model.config, baseline_model.generation_config):
24
+ m.language = "de"; m.task = "transcribe"
25
+ m.forced_decoder_ids = None; m.suppress_tokens = []
26
+ baseline_model.generation_config.no_repeat_ngram_size = 3
27
+
28
+ base_for_ft = WhisperForConditionalGeneration.from_pretrained(
29
+ BASE_MODEL, torch_dtype=DTYPE)
30
+ ft_model = PeftModel.from_pretrained(base_for_ft, ADAPTER_REPO).to(DEVICE).eval()
31
+ for m in (ft_model.config, ft_model.generation_config):
32
+ m.language = "de"; m.task = "transcribe"
33
+ m.forced_decoder_ids = None; m.suppress_tokens = []
34
+ ft_model.generation_config.no_repeat_ngram_size = 3
35
+ print("Models ready.")
36
+
37
+
38
+ def load_audio(path: str) -> torch.Tensor:
39
+ wav, sr = torchaudio.load(path)
40
+ if wav.shape[0] > 1:
41
+ wav = wav.mean(0, keepdim=True)
42
+ if sr != 16000:
43
+ wav = torchaudio.functional.resample(wav, sr, 16000)
44
+ return wav.squeeze(0)
45
+
46
+
47
+ @torch.inference_mode()
48
+ def transcribe_with(model, audio_tensor, num_beams: int):
49
+ feats = processor(audio_tensor.numpy(), sampling_rate=16000,
50
+ return_tensors="pt").input_features.to(DEVICE, dtype=DTYPE)
51
+ t0 = time.perf_counter()
52
+ ids = model.generate(feats, num_beams=num_beams, max_new_tokens=225,
53
+ return_dict_in_generate=True, output_scores=True)
54
+ dt = time.perf_counter() - t0
55
+ text = processor.batch_decode(ids.sequences, skip_special_tokens=True)[0].strip()
56
+ # crude confidence: mean negative log-likelihood normalized
57
+ if hasattr(ids, "sequences_scores") and ids.sequences_scores is not None:
58
+ conf = float(torch.exp(ids.sequences_scores[0]).clamp(0, 1))
59
+ else:
60
+ conf = None
61
+ return text, dt, conf
62
+
63
+
64
+ def run(audio_path: str, num_beams: int, model_choice: str):
65
+ if audio_path is None:
66
+ return "—", "—", "—", "—", "Please upload audio."
67
+ audio = load_audio(audio_path)
68
+ duration = audio.shape[-1] / 16000
69
+
70
+ if model_choice == "Baseline only":
71
+ b_text, b_dt, b_conf = transcribe_with(baseline_model, audio, num_beams)
72
+ return b_text, "—", f"{b_dt:.2f}s · RTF {b_dt/duration:.2f}", "—", \
73
+ f"Audio: {duration:.1f}s"
74
+ if model_choice == "Fine-tuned only":
75
+ f_text, f_dt, f_conf = transcribe_with(ft_model, audio, num_beams)
76
+ return "—", f_text, "—", f"{f_dt:.2f}s · RTF {f_dt/duration:.2f}", \
77
+ f"Audio: {duration:.1f}s"
78
+ # both
79
+ b_text, b_dt, _ = transcribe_with(baseline_model, audio, num_beams)
80
+ f_text, f_dt, _ = transcribe_with(ft_model, audio, num_beams)
81
+ return b_text, f_text, \
82
+ f"{b_dt:.2f}s · RTF {b_dt/duration:.2f}", \
83
+ f"{f_dt:.2f}s · RTF {f_dt/duration:.2f}", \
84
+ f"Audio: {duration:.1f}s"
85
+
86
+
87
+ # ---------- UI ----------
88
+ THEME = gr.themes.Monochrome(
89
+ primary_hue="neutral", neutral_hue="slate",
90
+ radius_size=gr.themes.sizes.radius_lg,
91
+ font=[gr.themes.GoogleFont("Inter"), "system-ui", "sans-serif"],
92
+ ).set(
93
+ body_background_fill="#000000",
94
+ body_text_color="#fafafa",
95
+ block_background_fill="#0a0a0a",
96
+ block_border_color="#1a1a1a",
97
+ button_primary_background_fill="#fafafa",
98
+ button_primary_text_color="#000000",
99
+ )
100
+
101
+ CSS = """
102
+ #title { letter-spacing: -0.02em; }
103
+ .gradio-container { max-width: 1100px !important; }
104
+ footer { display: none !important; }
105
+ """
106
+
107
+ with gr.Blocks(theme=THEME, css=CSS, title="AUTOLYRICS") as demo:
108
+ gr.HTML("""
109
+ <div style='padding: 28px 0 8px 0;'>
110
+ <h1 id='title' style='font-size: 44px; font-weight: 600; margin: 0;'>
111
+ AUTOLYRICS
112
+ </h1>
113
+ <p style='color: #888; margin: 8px 0 0 0; font-size: 15px;'>
114
+ Transcribing the voice inside music. Whisper-small fine-tuned with LoRA on singing.
115
+ </p>
116
+ </div>
117
+ """)
118
+
119
+ with gr.Row():
120
+ with gr.Column(scale=1):
121
+ audio = gr.Audio(type="filepath", label="Upload or record",
122
+ sources=["upload", "microphone"])
123
+ with gr.Row():
124
+ beams = gr.Slider(1, 8, value=5, step=1, label="Beam search width")
125
+ choice = gr.Radio(
126
+ ["Both (compare)", "Baseline only", "Fine-tuned only"],
127
+ value="Both (compare)", label="Mode")
128
+ run_btn = gr.Button("Transcribe", variant="primary")
129
+ meta = gr.Markdown("")
130
+
131
+ with gr.Column(scale=1):
132
+ with gr.Group():
133
+ gr.Markdown("### Baseline · Whisper-small")
134
+ base_out = gr.Textbox(lines=4, show_label=False,
135
+ placeholder="Baseline transcription will appear here…")
136
+ base_meta = gr.Markdown("")
137
+ with gr.Group():
138
+ gr.Markdown("### Fine-tuned · AUTOLYRICS (LoRA)")
139
+ ft_out = gr.Textbox(lines=4, show_label=False,
140
+ placeholder="Fine-tuned transcription will appear here…")
141
+ ft_meta = gr.Markdown("")
142
+
143
+ gr.Examples(
144
+ examples=[
145
+ ["examples/pop_clip.wav", 5, "Both (compare)"],
146
+ ["examples/ballad_clip.wav",5, "Both (compare)"],
147
+ ["examples/rap_clip.wav", 5, "Both (compare)"],
148
+ ],
149
+ inputs=[audio, beams, choice],
150
+ )
151
+
152
+ run_btn.click(
153
+ run,
154
+ inputs=[audio, beams, choice],
155
+ outputs=[base_out, ft_out, base_meta, ft_meta, meta],
156
+ )
157
+
158
+ if __name__ == "__main__":
159
+ demo.queue(max_size=12).launch()
examples/ballad_clip.wav ADDED
File without changes
examples/pop_clip.wav ADDED
File without changes
examples/rap_clip.wav ADDED
File without changes
requirements.txt ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ torch
2
+ torchaudio
3
+ transformers
4
+ peft
5
+ gradio
6
+ huggingface_hub
7
+ soundfile
8
+ accelerate
9
+ sentencepiece