Plutôt que de porter Qwen3 BPE (NFC + pre-tokenize regex Unicode + ByteLevel +
merges + ignore_merges) à la main en C++ (~500 LOC risquées), on charge
n'importe quelle Qwen3 GGUF en vocab_only=true (~50 MB RAM, pas de poids) et
on appelle llama_tokenize(parse_special=true). Bit-exact garanti par
construction.
kazeia_text_tokenizer.h/cpp : API courte
kz_tok_load(tok, gguf_path) / kz_tok_free / kz_tok_encode
kz_tok_encode_tts_prompt(tok, content) -> enveloppe dans le template chat
<|im_start|>assistant\n{content}<|im_end|>\n<|im_start|>assistant\n
(déduit du dump golden : 16 tokens pour 'Bonjour je m'appelle Kazeia').
test_tokenizer : binaire standalone vérifiant bit-exact vs input_ids_full.bin
./test_tokenizer Qwen3-4B-Q4_0.gguf tts_dump/input_ids_full.bin 'Bonjour je m'appelle Kazeia'
-> OK BIT-EXACT (16/16 tokens identiques au golden HF).
tts_pipeline : si KZTTS_TEXT et KZTTS_VOCAB_GGUF posés, tokenize la phrase au
lieu de lire input_ids_full.bin. La structure attendue (3 role + Nt body + 5
trailing) est exactement ce que kz_tok_encode_tts_prompt produit, donc
input_ids_len = Nt + 8 sans rien d'autre à changer dans la construction
prefill_embeds.
Mesure tablette Pad3 (cpu 6t, KZTTS_CP_CACHE=1, seed=42) :
A fixture : 31 frames, total 7.866s, RTF 3.04
B tokenizer C++ : 31 frames, total 7.842s, RTF 3.04 + WAV md5 identique
C 'Bonsoir...' : 41 frames audio 3.4s, total 10.5s, RTF 3.09 (phrase neuve OK)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>