Add EXTRACT_IGNORE list for labels that aren't food or events
Grade ranges like K-8 are always dropped; other labels (such as BHS) are now listed in EXTRACT_IGNORE instead of being built in. Matches whole entries in any case, in menu items and event titles.
This commit is contained in:
1 parent
d781d3d0ea
commit
3b0fb016ed
1 file changed
+23
-5
+23
-5
@@ -9,6 +9,7 @@ Settings (environment variables):
|
||||
EXTRACT_THINK 1 to let an Ollama model reason before answering (default 0)
|
||||
EXTRACT_TEMPERATURE Ollama sampling temperature (default 0)
|
||||
EXTRACT_DOUBLE_READ 1 to read every page twice and flag where the reads disagree (default 0)
|
||||
EXTRACT_IGNORE comma-separated labels to drop from menu items and event titles, e.g. "BHS,Milk" (default none)
|
||||
ANTHROPIC_API_KEY only for claude-* models
|
||||
"""
|
||||
import base64
|
||||
@@ -38,6 +39,7 @@ OLLAMA_URL = os.environ.get("OLLAMA_URL", "http://localhost:11434").rstrip("/")
|
||||
THINK = os.environ.get("EXTRACT_THINK") == "1"
|
||||
TEMPERATURE = float(os.environ.get("EXTRACT_TEMPERATURE", "0"))
|
||||
DOUBLE_READ = os.environ.get("EXTRACT_DOUBLE_READ") == "1"
|
||||
IGNORE = {w.strip().lower() for w in os.environ.get("EXTRACT_IGNORE", "").split(",") if w.strip()}
|
||||
EFFORT = "high" # Claude only
|
||||
LONG_EDGE = 2000 # ponytail: rotate + downscale only; add deskew/crop when angled photos score worse than flat ones
|
||||
LOW_CONFIDENCE = 0.7
|
||||
@@ -153,7 +155,13 @@ Menus
|
||||
`confidence` is 0 to 1. Go below 0.7 whenever you had to guess."""
|
||||
|
||||
GRID_LAYOUTS = ("month_grid", "menu")
|
||||
LABEL = re.compile(r"(k|\d{1,2})\s*-\s*\d{1,2}|bhs", re.I) # ponytail: school-specific labels belong in the source's prompt notes
|
||||
GRADE_RANGE = re.compile(r"(k|\d{1,2})\s*-\s*\d{1,2}", re.I) # "K-8", "6-12": never food, never an event
|
||||
|
||||
|
||||
def ignored(text, words):
|
||||
"""A grade range, or one of the labels the user listed (whole text, any case)."""
|
||||
text = (text or "").strip()
|
||||
return bool(GRADE_RANGE.fullmatch(text)) or text.lower() in words
|
||||
|
||||
|
||||
def load_image(path):
|
||||
@@ -184,15 +192,18 @@ def iso(s):
|
||||
return s
|
||||
|
||||
|
||||
def cleanup(result):
|
||||
"""Deterministic tidy-up before validation: pad dates, drop events with no real title."""
|
||||
def cleanup(result, ignore=None):
|
||||
"""Deterministic tidy-up before validation: pad dates, drop events with no real title,
|
||||
and drop labels (grade ranges and the ignore list) from event titles and menu items."""
|
||||
ignore = IGNORE if ignore is None else ignore
|
||||
for item in [result["date_range"]] + result["events"] + result["menu_items"]:
|
||||
for key in ("date", "end_date", "start", "end"):
|
||||
if item.get(key):
|
||||
item[key] = iso(item[key])
|
||||
result["events"] = [e for e in result["events"] if re.sub(r"[^a-z]", "", e["title"].lower()) not in ("", "event")]
|
||||
result["events"] = [e for e in result["events"] if not ignored(e["title"], ignore)]
|
||||
for m in result["menu_items"]:
|
||||
m["items"] = [i for i in m["items"] if not LABEL.fullmatch(i.strip())]
|
||||
m["items"] = [i for i in m["items"] if not ignored(i, ignore)]
|
||||
return result
|
||||
|
||||
|
||||
@@ -490,7 +501,14 @@ def selftest():
|
||||
# Year boundary: December row ending in January
|
||||
row = [col(wd, d) for wd, d in zip(sun_first, [27, 28, 29, 30, 31, 1, 2])]
|
||||
assert first_column_date(row, 2026, 12) == (date(2026, 12, 27), 0)
|
||||
assert [i for i in ["K-8", "Grapes", "BHS", "6-12", "Corn"] if not LABEL.fullmatch(i)] == ["Grapes", "Corn"]
|
||||
# Labels: grade ranges always go; other words only when listed, matched whole and in any case
|
||||
items = ["K-8", "Grapes", "BHS", "6-12", "Corn", "bhs ", "BHS Pizza"]
|
||||
assert [i for i in items if not ignored(i, set())] == ["Grapes", "BHS", "Corn", "bhs ", "BHS Pizza"]
|
||||
assert [i for i in items if not ignored(i, {"bhs"})] == ["Grapes", "Corn", "BHS Pizza"]
|
||||
r = cleanup({"date_range": {}, "menu_items": [{"date": "2026-11-04", "items": ["K-8", "Grapes", "BHS"]}],
|
||||
"events": [{"date": "2026-11-04", "title": "BHS", "kind": "event"},
|
||||
{"date": "2026-11-04", "title": "No School", "kind": "no_school"}]}, {"bhs"})
|
||||
assert r["menu_items"][0]["items"] == ["Grapes"] and [e["title"] for e in r["events"]] == ["No School"], r
|
||||
# Double read: agreement adds nothing, a moved date and a one-sided item are flagged
|
||||
ev = lambda d, t, **kw: {"date": d, "end_date": None, "all_day": True, "start_time": None,
|
||||
"end_time": None, "kind": "event", "title": t, **kw}
|
||||
|
||||
Reference in new issue
Block a user