import base64
import json
import pathlib
import sys
import tiktoken as pytiktoken
import zstandard
from tokenizers import Tokenizer
OUT_DIR = pathlib.Path(__file__).resolve().parent
sys.path.insert(0, str(OUT_DIR.parent.parent / "tests"))
from canonical_corpus import corpus
SOURCES = {
"glm4": (
"zai-org/GLM-4.5",
151_329,
r"(?i:'s|'t|'re|'ve|'m|'ll|'d)|[^\r\n\p{L}\p{N}]?\p{L}+|\p{N}{1,3}| ?[^\s\p{L}\p{N}]+[\r\n]*|\s*[\r\n]+|\s+(?!\S)|\s+",
),
"glm5": (
"zai-org/GLM-5.2",
154_820,
r"(?i:'s|'t|'re|'ve|'m|'ll|'d)|[^\r\n\p{L}\p{N}]?\p{L}+|\p{N}{1,3}| ?[^\s\p{L}\p{N}]+[\r\n]*|\s*[\r\n]+|\s+(?!\S)|\s+",
),
"minimax_m2": (
"MiniMaxAI/MiniMax-M2",
200_000,
r"[^\r\n\p{L}\p{N}]?[\p{Lu}\p{Lt}\p{Lm}\p{Lo}\p{M}]*[\p{Ll}\p{Lm}\p{Lo}\p{M}]+(?i:'s|'t|'re|'ve|'m|'ll|'d)?|[^\r\n\p{L}\p{N}]?[\p{Lu}\p{Lt}\p{Lm}\p{Lo}\p{M}]+[\p{Ll}\p{Lm}\p{Lo}\p{M}]*(?i:'s|'t|'re|'ve|'m|'ll|'d)?|\p{N}{1,3}| ?[^\s\p{L}\p{N}]+[\r\n]*|\s*[\r\n]+|\s+(?!\S)|\s+",
),
}
def bytes_to_unicode():
bs = list(range(ord("!"), ord("~") + 1)) + list(range(0xA1, 0xAD)) + list(range(0xAE, 0x100))
cs = bs[:]
n = 0
for b in range(256):
if b not in bs:
bs.append(b)
cs.append(256 + n)
n += 1
return dict(zip(bs, map(chr, cs)))
UNICODE_TO_BYTE = {v: k for k, v in bytes_to_unicode().items()}
def hf_token_to_bytes(token: str) -> bytes:
return bytes(UNICODE_TO_BYTE[ch] for ch in token)
def convert(name: str):
repo, want_vocab, pat = SOURCES[name]
tok = Tokenizer.from_pretrained(repo)
data = json.loads(tok.to_str())
vocab = data["model"]["vocab"]
if len(vocab) != want_vocab:
raise SystemExit(f"{name}: {repo} vocab {len(vocab)} != expected {want_vocab}")
ranks = {hf_token_to_bytes(tk): rank for tk, rank in vocab.items()}
assert len(ranks) == len(vocab), "byte-mapping collision"
enc = pytiktoken.Encoding(name=name, pat_str=pat, mergeable_ranks=ranks, special_tokens={})
added = {a["content"] for a in data.get("added_tokens", [])}
checked = skipped = 0
for text in corpus():
if any(a in text for a in added):
skipped += 1
continue
ours = enc.encode(text, disallowed_special=())
hf = tok.encode(text, add_special_tokens=False).ids
if ours != hf:
raise SystemExit(f"{name}: divergence on {text!r}\n converted: {ours}\n hf: {hf}")
checked += 1
print(f"{name}: self-check OK ({checked} texts, {skipped} skipped)", file=sys.stderr)
lines = b"".join(
base64.b64encode(tk) + b" " + str(rank).encode() + b"\n"
for tk, rank in sorted(ranks.items(), key=lambda kv: kv[1])
)
out = OUT_DIR / f"{name}.tiktoken.zst"
out.write_bytes(zstandard.ZstdCompressor(level=19).compress(lines))
print(f"{name}: wrote {out} ({out.stat().st_size} bytes)", file=sys.stderr)
if __name__ == "__main__":
names = sys.argv[1:] or list(SOURCES)
for n in names:
convert(n)