mirror of
https://github.com/hay-kot/mealie.git
synced 2025-08-20 21:43:36 -07:00
fix: add confidence calculation for BruteForceParser (#5903)
Co-authored-by: Michael Genson <71845777+michael-genson@users.noreply.github.com>
This commit is contained in:
parent
d4e62c5ab6
commit
0b3fe2c8da
2 changed files with 67 additions and 4 deletions
|
@ -12,6 +12,8 @@ from mealie.schema.recipe.recipe_ingredient import (
|
||||||
CreateIngredientFood,
|
CreateIngredientFood,
|
||||||
CreateIngredientUnit,
|
CreateIngredientUnit,
|
||||||
IngredientConfidence,
|
IngredientConfidence,
|
||||||
|
IngredientFood,
|
||||||
|
IngredientUnit,
|
||||||
ParsedIngredient,
|
ParsedIngredient,
|
||||||
RegisteredParser,
|
RegisteredParser,
|
||||||
)
|
)
|
||||||
|
@ -28,11 +30,11 @@ class BruteForceParser(ABCIngredientParser):
|
||||||
Brute force ingredient parser.
|
Brute force ingredient parser.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
async def parse_one(self, ingredient: str) -> ParsedIngredient:
|
async def parse_one(self, ingredient_string: str) -> ParsedIngredient:
|
||||||
bfi = brute.parse(ingredient, self)
|
bfi = brute.parse(ingredient_string, self)
|
||||||
|
|
||||||
parsed_ingredient = ParsedIngredient(
|
parsed_ingredient = ParsedIngredient(
|
||||||
input=ingredient,
|
input=ingredient_string,
|
||||||
ingredient=RecipeIngredient(
|
ingredient=RecipeIngredient(
|
||||||
unit=CreateIngredientUnit(name=bfi.unit),
|
unit=CreateIngredientUnit(name=bfi.unit),
|
||||||
food=CreateIngredientFood(name=bfi.food),
|
food=CreateIngredientFood(name=bfi.food),
|
||||||
|
@ -41,7 +43,28 @@ class BruteForceParser(ABCIngredientParser):
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
return self.find_ingredient_match(parsed_ingredient)
|
matched_ingredient = self.find_ingredient_match(parsed_ingredient)
|
||||||
|
|
||||||
|
qty_conf = 1
|
||||||
|
note_conf = 1
|
||||||
|
|
||||||
|
unit_obj = matched_ingredient.ingredient.unit
|
||||||
|
food_obj = matched_ingredient.ingredient.food
|
||||||
|
|
||||||
|
unit_conf = 1 if bfi.unit is None or isinstance(unit_obj, IngredientUnit) else 0
|
||||||
|
food_conf = 1 if bfi.food is None or isinstance(food_obj, IngredientFood) else 0
|
||||||
|
|
||||||
|
avg_conf = (qty_conf + unit_conf + food_conf + note_conf) / 4
|
||||||
|
|
||||||
|
matched_ingredient.confidence = IngredientConfidence(
|
||||||
|
average=avg_conf,
|
||||||
|
quantity=qty_conf,
|
||||||
|
unit=unit_conf,
|
||||||
|
food=food_conf,
|
||||||
|
comment=note_conf,
|
||||||
|
)
|
||||||
|
|
||||||
|
return matched_ingredient
|
||||||
|
|
||||||
async def parse(self, ingredients: list[str]) -> list[ParsedIngredient]:
|
async def parse(self, ingredients: list[str]) -> list[ParsedIngredient]:
|
||||||
return [await self.parse_one(ingredient) for ingredient in ingredients]
|
return [await self.parse_one(ingredient) for ingredient in ingredients]
|
||||||
|
|
|
@ -226,6 +226,46 @@ def test_brute_parser(
|
||||||
assert not comment
|
assert not comment
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"unit, food, expect_unit_match, expect_food_match, expected_avg",
|
||||||
|
[
|
||||||
|
pytest.param("Cups", "potatoes", True, True, 1.0, id="all matched"),
|
||||||
|
pytest.param("Cups", "veryuniquefood", True, False, 0.75, id="unit matched only"),
|
||||||
|
pytest.param("veryuniqueunit", "potatoes", False, True, 0.75, id="food matched only"),
|
||||||
|
pytest.param("veryuniqueunit", "veryuniquefood", False, False, 0.5, id="neither matched"),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_brute_parser_confidence(
|
||||||
|
unit: str,
|
||||||
|
food: str,
|
||||||
|
expect_unit_match: bool,
|
||||||
|
expect_food_match: bool,
|
||||||
|
expected_avg: float,
|
||||||
|
unique_local_group_id: UUID4,
|
||||||
|
parsed_ingredient_data: tuple[list[IngredientFood], list[IngredientUnit]],
|
||||||
|
):
|
||||||
|
input_str = f"1 {unit} {food}"
|
||||||
|
|
||||||
|
with session_context() as session:
|
||||||
|
original_loop = asyncio.get_event_loop()
|
||||||
|
try:
|
||||||
|
loop = asyncio.new_event_loop()
|
||||||
|
asyncio.set_event_loop(loop)
|
||||||
|
parser = get_parser(RegisteredParser.brute, unique_local_group_id, session)
|
||||||
|
parsed = loop.run_until_complete(parser.parse_one(input_str))
|
||||||
|
finally:
|
||||||
|
loop.close()
|
||||||
|
asyncio.set_event_loop(original_loop)
|
||||||
|
|
||||||
|
conf = parsed.confidence
|
||||||
|
|
||||||
|
assert conf.quantity == 1
|
||||||
|
assert conf.comment == 1
|
||||||
|
assert conf.unit == (1 if expect_unit_match or not unit else 0)
|
||||||
|
assert conf.food == (1 if expect_food_match or not food else 0)
|
||||||
|
assert conf.average == expected_avg
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"input, expected_unit_name, expected_food_name, expect_unit_match, expect_food_match",
|
"input, expected_unit_name, expected_food_name, expect_unit_match, expect_food_match",
|
||||||
(
|
(
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue