Spaces:
Running
Running
Commit History
-
Port g2p_en's real OOV GRU model (close English g2p parity gap)β
Ships g2p_en's actual trained checkpoint20.npz weights (packed as a binary blob) and reimplements its GRU encoder-decoder inference exactly in JS, verified to produce byte-identical ARPABET output to the real Python package on OOV test words. Replaces the earlier letter-to-sound heuristic fallback. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>6d42bcb -
Migrate to static WASM app (100% client-side, no server)β
Replaces the FastAPI + WebSocket backend with a static Space that runs the full TTS pipeline in-browser: onnxruntime-web for the streaming vocoder and g2pw BERT model, a JS port of the text-norm/g2p frontend, and wllama (llama.cpp WASM) for the story/chat LLM demo. All model weights are fetched lazily from the Luigi/PrimeTTS model repo and cached by the browser. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>dae0d82
-
Remove MOSS-TTS-Nano backend (not real-time on free CPU tier)β
LuigiMOSS-Nano (RTF>1 on 2 vCPU) can't stream in real-time, which is this demo's whole premise. Revert to VITS-only real-time streaming; MOSS moves to the non-streaming comparison Space (PrimeTTS-vs-Inflect-Nano-v1) where batch one-pass fits.99cb6cb -
ui: label engines honestly (VITS real-time / MOSS slow HD preview)β
LuigiMOSS-Nano is not real-time on the free-tier CPU (RTF>1 -> ~15s generate-then-play). Label it as an HD quality/clone preview, not a real-time streaming engine, so the selector sets correct expectations.5a60841 -
moss_ws: one-pass whole-text generation (fix inter-clause silence)β
LuigiNow that the backend is per-call (reliable, no persistent serve to wedge), generate the whole text in one moss-gen call -> single continuous utterance, no silence gap between clauses (e.g. '...ηηΆη' -> 'δ»ηεζ©ζ―...'). Trades slightly higher first-audio for gapless playback. (One-pass logic was always correct; the earlier hang was test-overload + the serve process, both resolved.) π€ Generated with [Claude Code](https://claude.com/claude-code)807589a -
moss: official text normalization (WeTextProcessing) β fix numbers/entitiesβ
LuigiMOSS fed raw text to SentencePiece, so '2580'/'Jason' etc. were mangled. Add the official OpenMOSS normalization (tts_robust_normalizer + WeTextProcessing) applied before tokenization: '2580' -> δΈ€εδΊηΎε «ε, normalized to the model's training form. Graceful: robust-only cleanup if WeTextProcessing is unavailable. π€ Generated with [Claude Code](https://claude.com/claude-code)8d94964 -
moss: drop persistent serve, use per-call moss-gen (fix free-tier hang)β
LuigiThe persistent serve process wedged on the free-tier container (worked locally but hung live, taking the demo down). Revert to one-shot per-call moss-gen with a 120s timeout β no persistent state to get stuck. Keeps the local-KV-cache speedup in the binary; gguf reload is page-cached after the first call. π€ Generated with [Claude Code](https://claude.com/claude-code)b07b2fa -
moss_ws: revert to per-clause (one-pass hung the demo; restore working RTF 1.72)
Luigibcdef67 -
moss_ws: one-pass generation for whole text (remove inter-utterance gaps)β
LuigiPer-clause streaming spawned a fresh moss-gen/codec-cli per clause; with RTF>1 the next clause's generation overran the current clause's playback -> multi-second silent gaps between utterances (seen: 3.3s gap in a 5.6s clip). Generate the whole text in one pass (single moss-gen + single codec decode) -> contiguous audio, no mid-gaps. Trades a slightly higher first-audio for gapless playback. π€ Generated with [Claude Code](https://claude.com/claude-code)87de70a -
moss: rebuild moss-gen with local KV cache (fork 09308c9, ~1.43x CPU)
Luigi5a65ddc -
moss: persistent moss-gen serve process (kill per-clause gguf reload)β
LuigiKeep one moss-gen 'serve' process alive (gguf loaded once); send one request per clause over stdin. Eliminates the ~138MB reload that dominated multi-clause latency (RTF 7+ -> per-clause gen only). Rebuild from fork rev d8da064. π€ Generated with [Claude Code](https://claude.com/claude-code)82e4986 -
moss: default to zh-TW voice (Yuewen/zh_4) when no user ref β fixes runaway generationβ
LuigiA pad/empty reference made the model skip the end-token and run to the frame cap (~20s of babble for a short sentence). Default to a built-in voice so generation ends naturally; prefer the official demo's zh-TW/ε°ζΉΎθ sample (Yuewen, zh_4.wav). User-uploaded refs still override. Verified: 3.76s natural stop vs 20s cap. π€ Generated with [Claude Code](https://claude.com/claude-code)e9dc86d -
moss: rebuild moss-gen from fork rev dd64994 (MOSS_DIR support)β
LuigiThe deployed moss-gen used hardcoded /home/luigi/moss-port paths (the MOSS_DIR generalization wasn't committed to the fork). Fork now has it (dd64994); bust the build-layer cache to recompile. codec.cpp layer stays cached -> fast rebuild. π€ Generated with [Claude Code](https://claude.com/claude-code)e0c84ed -
moss: capture moss-gen stderr to surface the real failure
Luigiea828c9 -
moss: persist embedding tables to MOSS_DIR for moss-gen (fix exit 1)β
Luigimoss-gen reads gg_tok_embd.bin / gg_audio_embd.bin from $MOSS_DIR (per-frame feedback embeddings + head sampling). They weren't present on the Space (only the Python side derived them in-memory) -> moss-gen file-open failed -> exit 1. Dump the derived tables to MOSS_DIR so the binary can read them. π€ Generated with [Claude Code](https://claude.com/claude-code)cf34d92 -
moss_ws: robust worker (always close socket, surface errors, cap frames)β
LuigiIf m.stream raised, the worker died before sending None -> the reader awaited forever and the socket hung. Wrap in try/finally so the reader always unblocks; surface the error to the client; cap max_frames=200 to bound generation time. π€ Generated with [Claude Code](https://claude.com/claude-code)2366535 -
moss: warm the pipeline at startup (preload gguf into page cache)β
LuigiPreload per the demo goal: the background warm now also runs one tiny generation after init, so moss-gen's gguf + codec.cpp are hot before the first user request (VITS + LLMs already load at import). π€ Generated with [Claude Code](https://claude.com/claude-code)7c1ac02 -
moss: copy versioned ggml .so (libggml*.so*) β fix moss-gen loaderβ
Luigimoss-gen NEEDED libggml-base.so.0 / libggml-cpu.so.0 (SONAME), but the Dockerfile copied only the bare 'libggml*.so' symlink, not the versioned real files -> at runtime 'libggml-base.so.0: cannot open shared object file'. Copy all variants (*.so*) with cp -P to preserve the symlink chain. π€ Generated with [Claude Code](https://claude.com/claude-code)cbb6040 -
moss: add python-multipart (required by /moss_ref UploadFile) β fixes startup crashβ
LuigiRoot cause of RUNTIME_ERROR: the /moss_ref ref-audio upload endpoint uses multipart form data (UploadFile/File), which FastAPI validates at import time. Without python-multipart it raises RuntimeError during route registration, crashing app startup. (Confirmed by reproducing the import locally in Docker.) π€ Generated with [Claude Code](https://claude.com/claude-code)97959c8 -
moss: scope ggml libs to subprocesses (fix llama-cpp libggml clash)β
LuigiGlobal LD_LIBRARY_PATH=/app/bin put codec.cpp's libggml on the loader path for the WHOLE process, clashing with the libggml bundled in llama-cpp-python (the demo's story/chat LLMs) -> startup crash (RUNTIME_ERROR). Drop the global env; set LD_LIBRARY_PATH only in the moss-gen / codec-cli subprocess env (MOSS_LIB). π€ Generated with [Claude Code](https://claude.com/claude-code)76725a9 -
moss: lazy init + background warm (don't block startup)β
LuigiThe import-time asset download (138MB gguf) blocked app startup past the health check -> RUNTIME_ERROR. Move MOSS download + instantiation off the import path: lazy _get_moss() (thread-safe, cached) warmed in a daemon thread; /has_moss is a light binary-presence check; endpoints resolve the backend lazily. VITS serves immediately; MOSS attaches when ready. Any MOSS failure can no longer crash startup. π€ Generated with [Claude Code](https://claude.com/claude-code)558531c -
Add MOSS-TTS-Nano 2nd backend (rs.cpp + codec.cpp, ORT-free) with voice cloneβ
LuigiSecond TTS engine alongside the MB-iSTFT-VITS: MOSS-TTS-Nano-100M autoregressive LLM-TTS, fully ggml (no onnxruntime). Pipeline: SentencePiece tokenizer + manifest-driven prompt + rs.cpp moss-gen (AR, 16 codebooks) + codec.cpp (moss_audio codec) -> 48kHz. User can upload a reference clip to clone its voice. - moss_backend.py: self-contained streaming backend (graceful-degrades to VITS-only) - server.py: /has_moss, /moss_ref (ref upload), /moss_ws (48kHz stream); startup asset download (gguf + tokenizer + manifest + hans00 codec gguf) - static/index.html: engine selector + ref-audio upload + dynamic playback SR - Dockerfile: builds moss-gen + codec-cli (shared ggml, CPU) in-image - requirements: sentencepiece, librosa, gguf RTF ~0.7 on 2 vCPU = real-time on the free CPU tier. π€ Generated with [Claude Code](https://claude.com/claude-code)55bcc77
-
Super-squash branch 'main' using huggingface_hub
06a6552