Skip to content

Commit 238ca5b

Browse files
authored
feat: fetch_lexicon — canonical sha-verified lexicon loader (WO19) (#33)
1 parent 9a5c671 commit 238ca5b

2 files changed

Lines changed: 59 additions & 0 deletions

File tree

‎src/interscript/ml/thai_hybrid.py‎

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,3 +92,28 @@ def build_lexicon_from_kaikki(entries, min_head_len: int = 1) -> Lexicon:
9292
for word, ipas in counts.items():
9393
lex[word] = max(ipas.items(), key=lambda kv: kv[1])[0]
9494
return lex
95+
96+
97+
LEXICON_URL = (
98+
"https://github.com/interscript/interscript-models/releases/download/"
99+
"tha-lexicon-kaikki-1.0/tha-lexicon-kaikki.json"
100+
)
101+
LEXICON_SHA256 = "6e44c7116aca3e570f6b8a12d9c0ca8f7631336147448d0818ad7e076b72b911"
102+
103+
104+
def fetch_lexicon(index_url=None, _base_url=None, _sha256=None) -> Lexicon:
105+
"""Fetch the canonical lexicon artifact, sha-verified (same trust
106+
contract as model artifacts — no unverified data paths). Test hooks
107+
take precedence over the release defaults."""
108+
import hashlib
109+
import json
110+
import urllib.request
111+
112+
url = _base_url or LEXICON_URL
113+
expected = _sha256 or LEXICON_SHA256
114+
with urllib.request.urlopen(url) as r:
115+
blob = r.read()
116+
got = hashlib.sha256(blob).hexdigest()
117+
if got != expected:
118+
raise ValueError(f"lexicon sha256 mismatch: {got}")
119+
return Lexicon(json.loads(blob.decode("utf-8")))

‎tests/test_thai_hybrid.py‎

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,3 +54,37 @@ def test_hybrid_all_oov_single_span():
5454
out = hybrid_translate("นอนๆ", make_lexicon(), model)
5555
assert out == "|นอนๆ|"
5656
assert model.calls == ["นอนๆ"]
57+
58+
59+
class TestFetchLexicon:
60+
def test_fetches_sha_verified_and_builds_a_lexicon(self, tmp_path, monkeypatch):
61+
import json as _json
62+
63+
lexicon = {"กิน": "kin", "ข้าว": "kʰâːw"}
64+
blob = _json.dumps(lexicon, ensure_ascii=False).encode("utf-8")
65+
import hashlib
66+
67+
sha = hashlib.sha256(blob).hexdigest()
68+
(tmp_path / "lex.json").write_bytes(blob)
69+
base = f"file://{tmp_path}/lex.json"
70+
71+
from interscript.ml import thai_hybrid as TH
72+
73+
got = TH.fetch_lexicon(index_url=None, _base_url=base, _sha256=sha)
74+
assert got["กิน"] == "kin"
75+
assert isinstance(got, TH.Lexicon)
76+
77+
def test_rejects_sha_mismatch(self, tmp_path):
78+
(tmp_path / "lex.json").write_bytes(b'{"a":"b"}')
79+
from interscript.ml import thai_hybrid as TH
80+
81+
try:
82+
TH.fetch_lexicon(
83+
index_url=None,
84+
_base_url=f"file://{tmp_path}/lex.json",
85+
_sha256="0" * 64,
86+
)
87+
except ValueError as e:
88+
assert "sha256" in str(e)
89+
else:
90+
raise AssertionError("expected sha mismatch")

0 commit comments

Comments
 (0)