diff --git a/backend/app/services/rezepte.py b/backend/app/services/rezepte.py index c24d6d9..ee253f7 100644 --- a/backend/app/services/rezepte.py +++ b/backend/app/services/rezepte.py @@ -145,29 +145,56 @@ def _stamm(text: str) -> str: # „veganer Lime Curd" auf „Vegane Mühlen-Schnitzel". Geteilt wird dort nur die # Eigenschaft, nicht die Sache. # -# Als Wortanfänge aufgeführt, weil Deutsch beugt: „vegan", „vegane", „veganer", -# „veganes" sollen alle gemeint sein. Verglichen wird gegen die zusammengezogene -# Form aus ``_stamm`` (ae/oe/ue schon aufgelöst). -_NUR_EIGENSCHAFT = ( - "vegan", "vegetar", "bio", "biologisch", "frisch", "roh", +# Verglichen wird gegen die zusammengezogene Form aus ``_stamm`` (ae/oe/ue schon +# aufgelöst) - die Listen unten stehen deshalb ebenfalls in dieser Form. +# +# Zwei Toepfe, weil es zwei Sorten Wort sind. Die Trennung ist nicht Kosmetik: +# Als EINE Liste mit Praefix-Vergleich hat sie ganze Artikelnamen verschluckt. +# 'Frischkaese' begann mit 'frisch', galt damit als blosse Eigenschaft und fiel +# aus dem Vergleich - die Zutat 'Kaese' fand den Frischkaese deshalb NIE. Ebenso +# 'Biomilch' (bio), 'Rohrzucker' (roh), 'Kleingebaeck' (klein), 'Ganzkornbrot' +# (ganz). Der Fehler war unsichtbar: kein falscher Treffer, nur ausbleibende +# richtige. +# +# 1. Stammformen, die in JEDER Beugung gemeint sind. Praefix-Vergleich, weil +# Deutsch beugt: 'getrock' deckt getrocknet/getrocknete/getrocknetes ab. +# Diese Stuecke fangen keine Komposita an, die ein Lebensmittel benennen. +_EIGENSCHAFT_STAMM = ( + "vegan", "vegetar", "biologisch", "gekocht", "gebacken", "geschmolz", "gesalz", "ungesalz", "gezuckert", "getrock", "gefror", "gerieb", "gewurf", "geschnitt", "geschal", "gehackt", - "gemahl", "gepresst", "zimmertemperatur", "lauwarm", - "klein", "gross", "mittel", "fein", "grob", "ganz", - "oder", "sowie", "etwa", "circa", "nach", "ohne", "optional", "evtl", - "block", "stueck", "stuck", "gehauft", "gestrich", + "gemahl", "gepresst", "zimmertemperatur", "lauwarm", "gehauft", "gestrich", + "optional", ) +# 2. Kurze Alltagswoerter, die AUCH am Anfang echter Namen stehen. Hier zaehlt +# nur das Wort selbst, hoechstens mit einer Beugungsendung dran: 'frische' +# ja, 'frischkase' nein. +_EIGENSCHAFT_WORT = ( + "bio", "frisch", "roh", "klein", "gross", "mittel", "fein", "grob", "ganz", + "oder", "sowie", "etwa", "circa", "nach", "ohne", "evtl", + "block", "stueck", "stuck", +) + +# Deutsche Beugungsendungen. Was laenger ist, ist keine Endung mehr, sondern ein +# zweites Wort - und genau das soll den Namen retten. +_BEUGUNG = ("", "e", "er", "es", "en", "em", "ene", "enes", "ener", "enen") + def _nur_eigenschaft(wort: str) -> bool: - return wort.isdigit() or wort.startswith(_NUR_EIGENSCHAFT) + if wort.isdigit() or wort.startswith(_EIGENSCHAFT_STAMM): + return True + return any( + wort.startswith(w) and wort[len(w):] in _BEUGUNG + for w in _EIGENSCHAFT_WORT + ) def _woerter(text: str) -> list[str]: """Bedeutungstragende Wörter einer Zutat. Weg fallen sehr kurze („1 TL"), reine Zahlen und alles, was die Zutat nur - beschreibt (siehe ``_NUR_EIGENSCHAFT``). Übrig bleibt, was sie IST: „Mehl", + beschreibt (siehe ``_nur_eigenschaft``). Übrig bleibt, was sie IST: „Mehl", „Apfel", „Butter", „Joghurt". """ return [ diff --git a/backend/tests/test_rezept_abgleich.py b/backend/tests/test_rezept_abgleich.py index 1516f0e..1514dd0 100644 --- a/backend/tests/test_rezept_abgleich.py +++ b/backend/tests/test_rezept_abgleich.py @@ -372,6 +372,48 @@ def test_umlaut_und_mehrzahl_finden_sich(db): assert zutat.status == "vorhanden" +def test_eigenschaftswort_verschluckt_den_artikelnamen_nicht(db): + '''Der Fund aus der Modellprobe: 'Frischkaese' fing mit 'frisch' an. + + Damit galt der ganze Name als blosse Eigenschaft, fiel aus dem Vergleich - + und die Zutat 'Kaese' fand den Frischkaese NIE. Unsichtbar, weil kein + falscher Treffer entstand, sondern ein richtiger ausblieb. + ''' + cat = _kategorie(db, "Molkerei") + kaese = _artikel(db, "Frischkäse", cat, bestand=400) + + [zutat] = pruefe_zutaten(db, [_zutat("Käse", 100, "g")]) + + assert zutat.ziel_id == kaese.id + assert zutat.status == "vorhanden" + + +@pytest.mark.parametrize("artikel,zutat_name", [ + ("Biomilch", "Milch"), + ("Rohrzucker", "Zucker"), + ("Kleingebäck", "Gebäck"), + ("Ganzkornbrot", "Brot"), + ("Grobgrieß", "Grieß"), +]) +def test_komposita_mit_eigenschaft_am_anfang_bleiben_auffindbar(db, artikel, zutat_name): + cat = _kategorie(db, "Vorrat") + ziel = _artikel(db, artikel, cat, bestand=1000) + + [zutat] = pruefe_zutaten(db, [_zutat(zutat_name, 100, "g")]) + + assert zutat.ziel_id == ziel.id + + +def test_das_eigenschaftswort_selbst_begruendet_weiter_keinen_treffer(db): + """Die Gegenprobe – sonst waere die Sperre bloss ausgehebelt.""" + cat = _kategorie(db, "Kuehlregal") + _artikel(db, "Frische Kräuter", cat, bestand=100) + + [zutat] = pruefe_zutaten(db, [_zutat("frische Hefe", 20, "g")]) + + assert zutat.status == "kein_treffer" + + def test_vollmilch_findet_die_h_vollmilch(db): cat = _kategorie(db, "Molkerei") milch = _artikel(db, "H Vollmilch", cat, base=BaseUnit.milliliter, bestand=1000)