makepad/libs/ai/models/speech/tools/gen_vocab.py
Admin 7f59912916 libs/ai: one AI stack, replacing libs/ggml, llama, mlx, cuda, tts, voice2 and pbr_paint
The model code was spread across eight crates that had grown into each other:
ggml and cuda and mlx each owned part of a tensor runtime, llama and tts and
voice2 each owned part of a model, and libs/diffusion owned everything else.
They are now one tree with an explicit shape:

  libs/ai/cuda     — kernels and launch surface
  libs/ai/metal    — Metal shaders and the shim
  libs/ai/llm      — the language-model runtime (sessions, lanes, contexts,
                     the CUDA and Metal executors, the compiled Metal path)
  libs/ai/models/  — common, flux, h3, music, paint, speech, stems, vision

libs/diffusion is not deleted but demoted: what remains is the VALIDATOR
crate — several dozen `*_validate.rs` oracles that check a native
implementation against a reference, which is where they belong now that the
implementations live next door.

The functional work inside the move is mostly in the LLM runtime: N lanes that
draft while one verify batch serves all of them, per-slot prefill over a shared
folded attention arena, speculation that survives batching, and a scheduler
that reports rather than publishes. And in the CUDA build: a machine without
usable CUDA must still LINK (and say so), the default kernel arch is the
building machine's GPU, `NO_CUDA` forces the stub even where the toolkit
exists, and kernels compile in parallel with progress.

libs/video_flow is new here: classical optical flow estimation and the `mkfl`
motion-field payload — a flow field measured from a clip without a model,
which is what drives free-rate bounce-looping playback and the uprez/tween
enhance pipe.
2026-08-23 01:34:35 +02:00

44 lines
1.4 KiB
Python

#!/usr/bin/env python3
"""Emit `src/g2p/vocab.rs` from Kokoro's `config.json`.
python3 gen_vocab.py config.json ../src/g2p/vocab.rs
"""
import json
import sys
def main():
src, dst = sys.argv[1], sys.argv[2]
vocab = json.load(open(src))["vocab"]
pairs = sorted(vocab.items(), key=lambda kv: kv[0])
lines = [
"// Generated by tools/gen_vocab.py from Kokoro's config.json. Do not edit.",
"",
"/// Phoneme symbol -> token id, sorted by symbol for binary search.",
f"pub const VOCAB: [(char, u16); {len(pairs)}] = [",
]
for symbol, token in pairs:
# Always escape: the vocab contains `'`, `"`, a combining tilde and IPA.
escaped = f"\\u{{{ord(symbol):04x}}}"
shown = symbol if symbol.strip() and symbol != "'" else repr(symbol)
lines.append(f" ('{escaped}', {token}), // {shown}")
lines.append("];")
lines.append("")
lines.append("/// Look up a phoneme symbol's token id.")
lines.append("pub fn token(symbol: char) -> Option<u16> {")
lines.append(" VOCAB")
lines.append(" .binary_search_by_key(&symbol, |(sym, _)| *sym)")
lines.append(" .ok()")
lines.append(" .map(|index| VOCAB[index].1)")
lines.append("}")
lines.append("")
with open(dst, "w") as out:
out.write("\n".join(lines))
print(f"{dst}: {len(pairs)} symbols")
if __name__ == "__main__":
main()