MedPlain commited on
Commit
c8da949
·
1 Parent(s): 5edda8d

Add jargon-sensitive readability (Dale-Chall, jargon rate, word familiarity); fix tooltip source term to match the edit

Browse files
Files changed (2) hide show
  1. engine.py +36 -2
  2. static/app.js +3 -0
engine.py CHANGED
@@ -56,6 +56,30 @@ def _read_key(*candidates: Path) -> str:
56
  return ""
57
 
58
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
59
  # --------------------------------------------------------------------------
60
  # Configuration knobs (overridable via environment before first import).
61
  # Mirrors run_local.py's CONFIG block.
@@ -580,6 +604,8 @@ class Engine:
580
  m.update(cs)
581
  except Exception:
582
  pass
 
 
583
  # reference-based edit/replacement F1 (benchmark mode only)
584
  if refs:
585
  try:
@@ -748,6 +774,13 @@ def _segment_tagged(tagged: str, rat_by_key: Dict, op_by_key: Dict) -> List[Dict
748
  seg["attribution_weight"] = gt.get("top_attribution_weight")
749
  seg["src_features"] = gt.get("src_features")
750
  seg["tgt_features"] = gt.get("tgt_features")
 
 
 
 
 
 
 
751
  if op:
752
  cc = op.get("contextcite") or {}
753
  seg["cc_lds"] = cc.get("lds")
@@ -763,11 +796,12 @@ def _segment_tagged(tagged: str, rat_by_key: Dict, op_by_key: Dict) -> List[Dict
763
  "passage": (ts.get("passage") or ts.get("text") or "")[:200],
764
  })
765
  seg["ranked_sources"] = ranked
 
766
  if "source_label" not in seg and ranked:
767
  seg["source_short"] = ranked[0]["source"]
768
  seg["source_passage"] = ranked[0]["passage"]
769
- if ranked and not seg.get("source_term"):
770
- seg["source_term"] = ranked[0]["term"]
771
  segments.append(seg)
772
  last = m.end()
773
  if last < len(tagged):
 
56
  return ""
57
 
58
 
59
+ # Lexical-familiarity metrics: unlike FKGL (syllable-based, blind to jargon),
60
+ # these reward replacing rare technical words with common everyday ones.
61
+ def _lexical(text: str) -> Dict[str, Any]:
62
+ out: Dict[str, Any] = {"dale_chall": None, "jargon_rate": None, "zipf_mean": None}
63
+ t = (text or "").strip()
64
+ if not t:
65
+ return out
66
+ try:
67
+ import textstat as _ts
68
+ out["dale_chall"] = round(_ts.dale_chall_readability_score(t), 2)
69
+ except Exception:
70
+ pass
71
+ try:
72
+ from wordfreq import zipf_frequency as _zf
73
+ words = re.findall(r"[A-Za-z]+", t.lower())
74
+ if words:
75
+ zs = [_zf(w, "en") for w in words]
76
+ out["zipf_mean"] = round(sum(zs) / len(zs), 2)
77
+ out["jargon_rate"] = round(sum(1 for z in zs if z < 3.0) / len(words), 4)
78
+ except Exception:
79
+ pass
80
+ return out
81
+
82
+
83
  # --------------------------------------------------------------------------
84
  # Configuration knobs (overridable via environment before first import).
85
  # Mirrors run_local.py's CONFIG block.
 
604
  m.update(cs)
605
  except Exception:
606
  pass
607
+ # lexical familiarity (captures jargon removal FKGL is blind to)
608
+ m.update(_lexical(sys_out))
609
  # reference-based edit/replacement F1 (benchmark mode only)
610
  if refs:
611
  try:
 
774
  seg["attribution_weight"] = gt.get("top_attribution_weight")
775
  seg["src_features"] = gt.get("src_features")
776
  seg["tgt_features"] = gt.get("tgt_features")
777
+ # The rationale's source_label is "source (term)" from pick_top_source
778
+ # (the edit's ACTUAL glossary source) — use its term, not ContextCite's
779
+ # noisy top-ranked one, so the tooltip source matches the edit.
780
+ _lbl = gt.get("source_label") or ""
781
+ _mt = re.search(r"\((.*)\)\s*$", _lbl)
782
+ if _mt:
783
+ seg["source_term"] = _mt.group(1).strip()
784
  if op:
785
  cc = op.get("contextcite") or {}
786
  seg["cc_lds"] = cc.get("lds")
 
796
  "passage": (ts.get("passage") or ts.get("text") or "")[:200],
797
  })
798
  seg["ranked_sources"] = ranked
799
+ # Only fall back to ContextCite's source if the rationale gave none.
800
  if "source_label" not in seg and ranked:
801
  seg["source_short"] = ranked[0]["source"]
802
  seg["source_passage"] = ranked[0]["passage"]
803
+ if not seg.get("source_term"):
804
+ seg["source_term"] = ranked[0]["term"]
805
  segments.append(seg)
806
  last = m.end()
807
  if last < len(tagged):
static/app.js CHANGED
@@ -300,6 +300,9 @@
300
  { key: "fre", label: "Reading ease (FRE)", desc: "0-100 scale", aim: "higher is easier, aim above 60", better: "higher", fmt: n1 },
301
  { key: "smog", label: "SMOG index", desc: "health-literacy grade", aim: "lower is better", better: "lower", fmt: n1 },
302
  { key: "coleman_liau", label: "Coleman-Liau", desc: "character-based grade", aim: "lower is better", better: "lower", fmt: n1 },
 
 
 
303
  { key: "mepr", label: "Entity preservation", desc: "medical facts kept (MEPR)", aim: "higher is better, keep the facts", better: "higher", fmt: pct, bar01: true },
304
  { key: "nli_faith", label: "NLI faithfulness", desc: "no hallucination vs input", aim: "higher is better, no made-up facts", better: "higher", fmt: pct, bar01: true },
305
  { key: "critical_error", label: "Critical safety error", desc: "lost negation / number / side", aim: "lower is better, 0 is safe", better: "lower", fmt: pct },
 
300
  { key: "fre", label: "Reading ease (FRE)", desc: "0-100 scale", aim: "higher is easier, aim above 60", better: "higher", fmt: n1 },
301
  { key: "smog", label: "SMOG index", desc: "health-literacy grade", aim: "lower is better", better: "lower", fmt: n1 },
302
  { key: "coleman_liau", label: "Coleman-Liau", desc: "character-based grade", aim: "lower is better", better: "lower", fmt: n1 },
303
+ { key: "dale_chall", label: "Dale-Chall grade", desc: "word-familiarity readability (jargon-sensitive)", aim: "lower is better, aim for grade 6", better: "lower", fmt: n1 },
304
+ { key: "jargon_rate", label: "Jargon words", desc: "share of rare/technical words", aim: "lower is better, 0 = none left", better: "lower", fmt: pct, bar01: true },
305
+ { key: "zipf_mean", label: "Word familiarity", desc: "average word commonness (Zipf)", aim: "higher is better, everyday words", better: "higher", fmt: n1 },
306
  { key: "mepr", label: "Entity preservation", desc: "medical facts kept (MEPR)", aim: "higher is better, keep the facts", better: "higher", fmt: pct, bar01: true },
307
  { key: "nli_faith", label: "NLI faithfulness", desc: "no hallucination vs input", aim: "higher is better, no made-up facts", better: "higher", fmt: pct, bar01: true },
308
  { key: "critical_error", label: "Critical safety error", desc: "lost negation / number / side", aim: "lower is better, 0 is safe", better: "lower", fmt: pct },