Lebensmittel oder Rezept wählbar; gemappte Zutaten werden übernommen, offene erscheinen in der Liste. Dazu Fettgehalt-Suche, EPA-Stoffe, Rezept-CRUD und Wechsel bestehender Zuordnungen. Co-authored-by: Cursor <cursoragent@cursor.com>
108 lines
4.5 KiB
Python
108 lines
4.5 KiB
Python
from data_layer.food_suggest import (
|
|
collapse_key,
|
|
name_tokens,
|
|
score_name_match,
|
|
suggest_batch,
|
|
suggest_for_name,
|
|
)
|
|
|
|
|
|
def _index(*foods):
|
|
index = {"foods": [], "by_collapse": {}, "by_token": {}, "by_prefix": {}, "by_suffix": {}}
|
|
for food in foods:
|
|
food["_c"] = collapse_key(food["name_de"])
|
|
food["_t"] = name_tokens(food["name_de"])
|
|
if food["_c"]:
|
|
index["by_collapse"].setdefault(food["_c"], []).append(food)
|
|
index["by_prefix"].setdefault(food["_c"][:4], []).append(food)
|
|
if len(food["_c"]) >= 4:
|
|
index["by_suffix"].setdefault(food["_c"][-4:], []).append(food)
|
|
for tok in food["_t"]:
|
|
index["by_token"].setdefault(tok, []).append(food)
|
|
return index
|
|
|
|
|
|
def test_collapse_treats_space_as_same():
|
|
assert collapse_key("Haferflocken") == collapse_key("Hafer Flocken")
|
|
|
|
|
|
def test_haferflocken_ranks_simple_name_first():
|
|
index = {
|
|
"foods": [],
|
|
"by_collapse": {},
|
|
"by_token": {},
|
|
"by_prefix": {},
|
|
"by_suffix": {},
|
|
}
|
|
simple = {"id": "1", "name_de": "Hafer Flocken", "name_en": "oat flakes", "bls_code": "C131111", "catalog_kind": "official_bls"}
|
|
dish = {"id": "2", "name_de": "Milch-Getreide-Brei, mit Haferflocken und Apfelsaft (geeignet für Beikost)", "name_en": "", "bls_code": "X", "catalog_kind": "official_bls"}
|
|
for food in (simple, dish):
|
|
food["_c"] = collapse_key(food["name_de"])
|
|
index["by_collapse"].setdefault(food["_c"], []).append(food)
|
|
index["by_prefix"].setdefault(food["_c"][:4], []).append(food)
|
|
index["by_suffix"].setdefault(food["_c"][-4:], []).append(food)
|
|
packed = suggest_for_name(index, "Haferflocken", limit=3)
|
|
assert packed["suggestions"][0]["name_de"] == "Hafer Flocken"
|
|
assert packed["suggestions"][0]["score"] >= score_name_match("Haferflocken", dish["name_de"])
|
|
|
|
|
|
def test_close_scores_are_ambiguous():
|
|
a = {"id": "1", "name_de": "Olivenöl nativ", "name_en": "", "bls_code": "A", "catalog_kind": "official_bls"}
|
|
b = {"id": "2", "name_de": "Olivenöl raffiniert", "name_en": "", "bls_code": "B", "catalog_kind": "official_bls"}
|
|
index = {"foods": [], "by_collapse": {}, "by_token": {}, "by_prefix": {}, "by_suffix": {}}
|
|
for food in (a, b):
|
|
food["_c"] = collapse_key(food["name_de"])
|
|
index["by_prefix"].setdefault(food["_c"][:4], []).append(food)
|
|
for tok in food["name_de"].lower().replace(",", "").split():
|
|
if len(tok) >= 2:
|
|
index["by_token"].setdefault(tok, []).append(food)
|
|
packed = suggest_for_name(index, "Olivenöl", limit=3)
|
|
assert packed["ambiguous"] is True
|
|
assert packed["suggestion_count"] >= 2
|
|
|
|
|
|
def test_large_prefix_bucket_keeps_exact_collapse():
|
|
index = {"foods": [], "by_collapse": {}, "by_token": {}, "by_prefix": {}, "by_suffix": {}}
|
|
target = {"id": "hit", "name_de": "Hafer Flocken", "name_en": "", "bls_code": "C", "catalog_kind": "official_bls"}
|
|
target["_c"] = collapse_key(target["name_de"])
|
|
index["by_collapse"][target["_c"]] = [target]
|
|
index["by_prefix"][target["_c"][:4]] = [target] + [
|
|
{"id": str(i), "name_de": f"Hafer Gericht {i}", "name_en": "", "_c": f"hafergericht{i}"}
|
|
for i in range(80)
|
|
]
|
|
packed = suggest_for_name(index, "Haferflocken", limit=3)
|
|
assert packed["suggestions"][0]["name_de"] == "Hafer Flocken"
|
|
|
|
|
|
def test_suggest_batch_dedupes_names():
|
|
class _Cur:
|
|
def execute(self, *args, **kwargs):
|
|
return None
|
|
def fetchall(self):
|
|
return []
|
|
|
|
out = suggest_batch(_Cur(), None, ["Haferflocken", "Haferflocken", ""], limit=2)
|
|
assert "Haferflocken" in out
|
|
assert out["Haferflocken"]["suggestions"] == []
|
|
|
|
|
|
def test_number_tokens_keep_decimal_fat():
|
|
assert "9.5" in name_tokens("Joghurt 9,5%")
|
|
assert "10" in name_tokens("Joghurt, aus Kuhmilch, 10 % Fett")
|
|
|
|
|
|
def test_joghurt_10_ranks_above_35():
|
|
light = {"id": "a", "name_de": "Joghurt >3,5% Fett", "name_en": "", "bls_code": "M", "catalog_kind": "official_bls"}
|
|
full = {
|
|
"id": "b",
|
|
"name_de": "Joghurt, aus Kuhmilch, 10 % Fett",
|
|
"name_en": "",
|
|
"bls_code": "N",
|
|
"catalog_kind": "official_bls",
|
|
}
|
|
index = _index(light, full)
|
|
for query in ("Joghurt 10%", "Joghurt 9,5%", "Joghurt 10"):
|
|
packed = suggest_for_name(index, query, limit=3)
|
|
assert packed["suggestions"][0]["name_de"] == full["name_de"], query
|
|
assert packed["suggestions"][0]["score"] > score_name_match(query, light["name_de"])
|