Photon-6B / offline_atlas.py
HonestyTools's picture
Photon-6B: the honest local honesty package (Lucidia/Photon)
95f3259 verified
Raw
History Blame Contribute Delete
6.26 kB
"""Offline grounding atlas — the existence base (no live API, no rate-limit). An entity is GROUNDED if
it (or a >=2-significant-token contiguous sub-span of it) is an exact Wikipedia article title. Conservative
by construction: fabrications have no title to match (structural 0-false-rescue, same property the live
gate had); but unlike the live string-search it can't be rate-limited and handles descriptive prompts
(the proper-noun span resolves) + diacritics (folded). The Nomic embedding layer (v2, DGX) adds semantic
robustness for transliteration/word-order misses.
Build: python offline_atlas.py build enwiki-titles.gz wiki_titles.db
Probe: python offline_atlas.py probe wiki_titles.db ../eval/heldout_battery.json ../eval/heldout_atlas_offline.json
"""
import sys, os, re, gzip, sqlite3, unicodedata, json
STOP = {"the", "of", "a", "an", "and", "in", "on", "at", "de", "la", "le", "el", "los", "las",
"von", "van", "der", "di", "du", "do", "da", "for", "to"}
def norm(s):
s = unicodedata.normalize("NFKD", s).encode("ascii", "ignore").decode() # fold diacritics
s = s.replace("_", " ").lower()
s = re.sub(r"[^a-z0-9 ]", " ", s)
return re.sub(r"\s+", " ", s).strip()
def _sig(tok):
return tok not in STOP and len(tok) > 1
def build(gz_path, db_path):
if os.path.exists(db_path):
os.remove(db_path)
con = sqlite3.connect(db_path)
con.execute("PRAGMA journal_mode=OFF"); con.execute("PRAGMA synchronous=OFF")
con.execute("CREATE TABLE t(n TEXT PRIMARY KEY) WITHOUT ROWID")
batch, total = [], 0
with gzip.open(gz_path, "rt", encoding="utf-8", errors="ignore") as f:
first = f.readline()
if norm(first) and "page_title" not in first: # not a header -> keep it
batch.append((norm(first),))
for line in f:
nm = norm(line)
if nm:
batch.append((nm,))
if len(batch) >= 100000:
con.executemany("INSERT OR IGNORE INTO t VALUES(?)", batch)
total += len(batch); batch = []
if total % 1000000 == 0:
print(f" {total//1000000}M titles ...", flush=True)
if batch:
con.executemany("INSERT OR IGNORE INTO t VALUES(?)", batch); total += len(batch)
con.commit()
n = con.execute("SELECT COUNT(*) FROM t").fetchone()[0]
con.close()
print(f"built {db_path}: {n} unique normalized titles (from {total} lines)")
class Grounder:
def __init__(self, db_path):
self.con = sqlite3.connect(db_path, check_same_thread=False)
def _exists(self, nm):
return self.con.execute("SELECT 1 FROM t WHERE n=? LIMIT 1", (nm,)).fetchone() is not None
def _candidates(self, entity):
# whole-entity candidates (each matched in full, never sub-windowed -> no generic-concept rescue):
# the entity, the part before a comma (", Country"/disambig), and the pieces of descriptive
# scaffolding (Work BY Author, Work (Native Title), Author'S Work) — these recover reals without
# surfacing generic fragments, and fakes aren't formatted this way.
# SAFE splits only: comma (geo/disambig qualifier) and the text outside parentheses (native-title
# parentheticals). by/possessive/inside-paren splits surface authors+years that false-rescue, so
# they're left to the embedding+type layer.
c = [entity]
if "," in entity:
c.append(entity.split(",")[0])
if " by " in entity:
c.append(entity.split(" by ")[0]) # the WORK (not the author after "by")
m = re.search(r"'s\s+(.+)", entity)
if m:
c.append(m.group(1)) # the WORK (not the author before "'s")
c2 = []
for s in c:
c2.append(s)
if "(" in s:
c2.append(re.sub(r"\([^)]*\)", "", s)) # also the text outside parens
return [s.strip() for s in c2 if s.strip()]
def grounded(self, entity):
# 1) whole-candidate exact match (entity + comma/by/paren/possessive splits)
for m in self._candidates(entity):
nm = norm(m)
if nm and self._exists(nm):
return {"matched": True, "hit": nm}
# 2) coverage-gated sub-windows: a title must cover >=60% of the entity's significant tokens
# (kills generic-concept rescues like "multi task"; keeps "Matilde Hidalgo"/"Lothar Meyer")
e = norm(entity); toks = e.split()
esig = [t for t in toks if _sig(t)]
if not esig:
return {"matched": False, "hit": ""}
for L in range(len(toks), 1, -1):
for i in range(0, len(toks) - L + 1):
w = toks[i:i + L]
wsig = [t for t in w if _sig(t)]
if len(wsig) >= 2 and len(wsig) / len(esig) >= 0.6:
wn = " ".join(w)
if self._exists(wn):
return {"matched": True, "hit": wn}
return {"matched": False, "hit": ""}
def probe(db_path, battery_path, out_path):
g = Grounder(db_path)
items = json.load(open(battery_path))["items"]
per = []
for it in items:
r = g.grounded(it["entity"])
per.append({"entity": it["entity"], "label": it["label"], "category": it["category"],
"matched": r["matched"], "hit": r["hit"]})
fake = [p for p in per if p["label"] == 1]; real = [p for p in per if p["label"] == 0]
fr = [(p["entity"], p["hit"]) for p in fake if p["matched"]]
mr = [p["entity"] for p in real if not p["matched"]]
print(f"offline atlas on {os.path.basename(battery_path)}:")
print(f" matched-rate REAL {sum(p['matched'] for p in real)/len(real):.3f} FAKE {sum(p['matched'] for p in fake)/len(fake):.3f}")
print(f" false-rescues (fakes matched): {len(fr)} {fr[:8]}")
print(f" still-missed reals: {len(mr)} {mr[:10]}")
json.dump({"per_item": per}, open(out_path, "w"), indent=1)
print(f"saved -> {out_path}")
if __name__ == "__main__":
cmd = sys.argv[1]
if cmd == "build":
build(sys.argv[2], sys.argv[3])
elif cmd == "probe":
probe(sys.argv[2], sys.argv[3], sys.argv[4])