Spaces:
Runtime error
Runtime error
Download scripts/test-lyric-structure.py from RalphThings/yue2-studio: direct link, hf CLI and curl.
- Browser
- Download file 4.21 kB
-
https://huggingface.co/spaces/RalphThings/yue2-studio/resolve/main/scripts/test-lyric-structure.py
- Command line
-
hf download hf://spaces/RalphThings/yue2-studio/scripts/test-lyric-structure.py
-
curl -L -o test-lyric-structure.py https://huggingface.co/spaces/RalphThings/yue2-studio/resolve/main/scripts/test-lyric-structure.py
4.21 kB
| import importlib.util, sys | |
| spec = importlib.util.spec_from_file_location("tl", "/home/claude/yue2-studio/scripts/transcribe-lyrics.py") | |
| tl = importlib.util.module_from_spec(spec); spec.loader.exec_module(tl) | |
| fails = [] | |
| def check(label, ok): | |
| print((" ok " if ok else " FAIL ") + label) | |
| if not ok: fails.append(label) | |
| def words(text, t0, word_gap=0.30, dur=0.28): | |
| """Build word-level chunks the way the pipeline returns them.""" | |
| out, t = [], t0 | |
| for w in text.split(): | |
| out.append({"text": " " + w, "timestamp": (round(t, 2), round(t + dur, 2))}) | |
| t += dur + word_gap | |
| return out, t | |
| # --- A realistic word-timed song ------------------------------------------- | |
| chunks = [] | |
| t = 0.0 | |
| V1, t = words("The kettle ticks itself to sleep. Your coat still holding yesterday.", t); chunks += V1 | |
| t += 1.9 # instrumental turnaround | |
| C1, t = words("Say it slow, I have got all night. Every word can take its time.", t); chunks += C1 | |
| t += 2.1 | |
| V2, t = words("Rain has found the kitchen window. Running lines it cannot keep.", t); chunks += V2 | |
| t += 1.8 | |
| C2, t = words("Say it slow, I have got all night. Every word can take it's time.", t); chunks += C2 | |
| stanzas = tl.force_structure(tl.group(tl.words_from({"chunks": chunks}))) | |
| out = tl.render(stanzas) | |
| print("\n" + out + "\n") | |
| check("four sections found, not one", len(stanzas) == 4) | |
| check("both section kinds present", "[Verse]" in out and "[Chorus]" in out) | |
| check("the repeated hook is tagged chorus twice", out.count("[Chorus]") == 2) | |
| check("the two verses are tagged verse", out.count("[Verse]") == 2) | |
| check("a near miss still counts as a repeat", "it's time" in out.lower() or "its time" in out.lower()) | |
| check("lines do not end in full stops", not any(l.rstrip().endswith(".") for l in out.split("\n"))) | |
| check("lines start capitalised", all(l[0].isupper() or l.startswith("[") for l in out.split("\n") if l.strip())) | |
| check("no line runs longer than the cap", all(len(l.split()) <= tl.MAX_WORDS_PER_LINE for l in out.split("\n") if not l.startswith("["))) | |
| # The length cap must never fire before the sentence split, or a phrase gets | |
| # chopped at an arbitrary word and the sentence break lands inside the piece. | |
| check("sentences break before the length cap does", "Say it slow, I have got all night" in out) | |
| check("no orphaned sentence fragment", "\nNight" not in out) | |
| check("both chorus passes read as whole lines", out.count("Say it slow, I have got all night") == 2) | |
| # --- What the OLD code actually received: contiguous sentence chunks -------- | |
| # Whisper's sentence timestamps butt up against each other, which is precisely | |
| # why the previous version produced a single [Verse]. | |
| contiguous = [ | |
| {"text": " The kettle ticks itself to sleep.", "timestamp": (0.0, 4.0)}, | |
| {"text": " Your coat still holding yesterday.", "timestamp": (4.0, 8.0)}, | |
| {"text": " Say it slow, I have got all night.", "timestamp": (8.0, 12.0)}, | |
| {"text": " Every word can take its time.", "timestamp": (12.0, 16.0)}, | |
| {"text": " Rain has found the kitchen window.", "timestamp": (16.0, 20.0)}, | |
| {"text": " Running lines it cannot keep.", "timestamp": (20.0, 24.0)}, | |
| {"text": " Say it slow, I have got all night.", "timestamp": (24.0, 28.0)}, | |
| {"text": " Every word can take its time.", "timestamp": (28.0, 32.0)}, | |
| {"text": " You are humming something older.", "timestamp": (32.0, 36.0)}, | |
| {"text": " Than the both of us asleep.", "timestamp": (36.0, 40.0)}, | |
| ] | |
| old_style = tl.group(tl.words_from({"chunks": contiguous})) | |
| check("contiguous input really does collapse to one block", len(old_style) == 1) | |
| forced = tl.force_structure(old_style) | |
| check("the fallback rescues it into sections", len(forced) > 1) | |
| rendered = tl.render(forced) | |
| print(rendered + "\n") | |
| check("fallback output still carries tags", rendered.startswith("[")) | |
| # --- Degenerate inputs ------------------------------------------------------ | |
| check("empty input renders empty", tl.render([]) == "") | |
| check("a short song is left alone by the fallback", len(tl.force_structure([["one", "two"]])) == 1) | |
| check("blank lines are dropped", tl.render([["", " ", "real line"]]).count("\n") == 1) | |
| sys.exit(1 if fails else 0) | |