jvonrad commited on
Commit
fef161a
·
verified ·
1 Parent(s): 4ed3d60

Upload src/xscript/flores.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. src/xscript/flores.py +67 -0
src/xscript/flores.py ADDED
@@ -0,0 +1,67 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """FLORES+ (openlanguagedata/flores_plus) loading.
2
+
3
+ FLORES+ is gated ("auto"): accept the terms on Hugging Face once and export
4
+ HF_TOKEN. Files are per-language jsonl: dev/<code>.jsonl, devtest/<code>.jsonl.
5
+
6
+ We key sentences by their FLORES `id` and align across languages on the
7
+ intersection of ids, so byte premiums and retrieval eval always compare the
8
+ same parallel content.
9
+ """
10
+ import json
11
+ from pathlib import Path
12
+
13
+ from .langs import LANGS
14
+ from .paths import FLORES_DIR, ensure
15
+
16
+ REPO_ID = "openlanguagedata/flores_plus"
17
+ SPLITS = ("dev", "devtest")
18
+
19
+ _TEXT_KEYS = ("text", "sentence")
20
+ _ID_KEYS = ("id", "sentence_id")
21
+
22
+
23
+ def download(langs=None, splits=SPLITS, token=None) -> None:
24
+ from huggingface_hub import hf_hub_download
25
+ langs = langs or list(LANGS)
26
+ ensure(FLORES_DIR)
27
+ for lc in langs:
28
+ code = LANGS[lc].flores_code
29
+ for split in splits:
30
+ hf_hub_download(
31
+ repo_id=REPO_ID, repo_type="dataset",
32
+ filename=f"{split}/{code}.jsonl",
33
+ local_dir=FLORES_DIR, token=token,
34
+ )
35
+
36
+
37
+ def _pick(d: dict, keys):
38
+ for k in keys:
39
+ if k in d:
40
+ return d[k]
41
+ raise KeyError(f"none of {keys} in FLORES+ record with keys {sorted(d)}")
42
+
43
+
44
+ def load(lang: str, split: str = "dev") -> dict[int, str]:
45
+ """Return {sentence_id: text} for one language/split."""
46
+ path = FLORES_DIR / split / f"{LANGS[lang].flores_code}.jsonl"
47
+ if not path.exists():
48
+ raise FileNotFoundError(
49
+ f"{path} missing - run `xscript flores-download` (requires HF_TOKEN "
50
+ f"with accepted terms for {REPO_ID})")
51
+ out = {}
52
+ with open(path, encoding="utf-8") as f:
53
+ for line in f:
54
+ if not line.strip():
55
+ continue
56
+ rec = json.loads(line)
57
+ out[int(_pick(rec, _ID_KEYS))] = str(_pick(rec, _TEXT_KEYS))
58
+ return out
59
+
60
+
61
+ def load_parallel(langs, split: str = "dev") -> dict[str, list[str]]:
62
+ """Aligned parallel sentences: same order, intersection of ids."""
63
+ per_lang = {l: load(l, split) for l in langs}
64
+ common = sorted(set.intersection(*(set(v) for v in per_lang.values())))
65
+ if not common:
66
+ raise RuntimeError(f"no common sentence ids across {langs} ({split})")
67
+ return {l: [per_lang[l][i] for i in common] for l in langs}