Download scripts/check_fallback.py from vomebook/Hitokoto: direct link, hf CLI and curl.
- Browser
- Download file 2.74 kB
-
https://huggingface.co/spaces/vomebook/Hitokoto/resolve/main/scripts/check_fallback.py
- Command line
-
hf download hf://spaces/vomebook/Hitokoto/scripts/check_fallback.py
-
curl -L -o check_fallback.py https://huggingface.co/spaces/vomebook/Hitokoto/resolve/main/scripts/check_fallback.py
2.74 kB
| """Explicit real-model unknown-symbol pause + short-first-batch acceptance.""" | |
| import argparse | |
| from datetime import datetime, timezone | |
| import json | |
| from pathlib import Path | |
| import sys | |
| import threading | |
| ROOT = Path(__file__).resolve().parents[1] | |
| sys.path.insert(0, str(ROOT)) | |
| from tts.engine import SpeechEngine | |
| from tts.text import SpeechError | |
| def main(): | |
| parser = argparse.ArgumentParser(description=__doc__) | |
| parser.add_argument("--assets", type=Path, required=True) | |
| parser.add_argument("--output", type=Path, required=True) | |
| args = parser.parse_args() | |
| args.output.mkdir(parents=True, exist_ok=True) | |
| engine = SpeechEngine(args.assets, ROOT / "assets.lock.json") | |
| from mutagen.mp3 import MP3 | |
| report = {"at": datetime.now(timezone.utc).isoformat(), "engine": engine.info, "cases": [], "scope": "Real local CPU encoded MP3 and complete source ranges; not manual audible/production latency acceptance"} | |
| cases = (("mixed", "校长读长文。𠮷※★😀αЖ,CPU和API继续。"), ("pause-only", "𠮷※★😀αЖ。"), | |
| ("control", "甲\f乙,后文继续。"), ("short-first", "这是一篇长文,校长文章写得很好,我得亲自处理。")) | |
| for name, text in cases: | |
| file = args.output / (name + ".mp3") | |
| published = [] | |
| result = engine.synthesize(text, "zf_001", 1, file, threading.Event(), progress=published.append, unsupported_policy="pause") | |
| assert result["segments"][0]["start"] == 0 | |
| assert result["segments"][-1]["end"] == len(text.encode("utf-16-le")) // 2 | |
| assert all(a["end"] == b["start"] for a, b in zip(result["segments"], result["segments"][1:])) | |
| assert len(published) == len(result["segments"]) | |
| assert abs(MP3(file).info.length - result["audio_seconds"]) < .25 | |
| for part in published: | |
| clip = file.with_name(f"{file.stem}.{part['index']}.mp3") | |
| assert abs(MP3(clip).info.length - part["audio_seconds"]) < .25 | |
| if name == "mixed": assert result["unsupported_phoneme_count"] >= 6 and result["batches"] > 0 | |
| if name == "pause-only": assert result["batches"] == 0 | |
| report["cases"].append({"name": name, "result": result}) | |
| print(name, "PASS", "duration", result["audio_seconds"], "first-part", result["first_audio_seconds"], flush=True) | |
| try: | |
| engine.synthesize(cases[0][1], "zf_001", 1, args.output / "strict.mp3", threading.Event()) | |
| except SpeechError as error: | |
| assert error.code == "unsupported_text" | |
| else: | |
| raise AssertionError("Default strict API must remain strict") | |
| (args.output / "acceptance.json").write_text(json.dumps(report, ensure_ascii=False, indent=2)) | |
| if __name__ == "__main__": main() | |