mirror of
				https://github.com/mealie-recipes/mealie.git
				synced 2025-10-31 10:13:32 -04:00 
			
		
		
		
	* increased float rounding precision for crf parser * limited fractions to a max denominator of 32 to prevent weirdly specific values * add test cases for 1/8 and 1/32 * add rounding to avoid more digits than necessary Co-authored-by: Hayden <64056131+hay-kot@users.noreply.github.com>
		
			
				
	
	
		
			80 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			80 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| import shutil
 | ||
| from dataclasses import dataclass
 | ||
| from fractions import Fraction
 | ||
| 
 | ||
| import pytest
 | ||
| 
 | ||
| from mealie.services.parser_services import RegisteredParser, get_parser
 | ||
| from mealie.services.parser_services.crfpp.processor import CRFIngredient, convert_list_to_crf_model
 | ||
| 
 | ||
| 
 | ||
| @dataclass
 | ||
| class TestIngredient:
 | ||
|     input: str
 | ||
|     quantity: float
 | ||
|     unit: str
 | ||
|     food: str
 | ||
|     comments: str
 | ||
| 
 | ||
| 
 | ||
| def crf_exists() -> bool:
 | ||
| 
 | ||
|     return shutil.which("crf_test") is not None
 | ||
| 
 | ||
| 
 | ||
| # TODO - add more robust test cases
 | ||
| test_ingredients = [
 | ||
|     TestIngredient("½ cup all-purpose flour", 0.5, "cup", "all-purpose flour", ""),
 | ||
|     TestIngredient("1 ½ teaspoons ground black pepper", 1.5, "teaspoon", "black pepper", "ground"),
 | ||
|     TestIngredient("⅔ cup unsweetened flaked coconut", 0.667, "cup", "coconut", "unsweetened flaked"),
 | ||
|     TestIngredient("⅓ cup panko bread crumbs", 0.333, "cup", "panko bread crumbs", ""),
 | ||
|     # Small Fraction Tests - PR #1369
 | ||
|     # Reported error is was for 1/8 - new lowest expected threshold is 1/32
 | ||
|     TestIngredient("1/8 cup all-purpose flour", 0.125, "cup", "all-purpose flour", ""),
 | ||
|     TestIngredient("1/32 cup all-purpose flour", 0.03125, "cup", "all-purpose flour", ""),
 | ||
| ]
 | ||
| 
 | ||
| 
 | ||
| @pytest.mark.skipif(not crf_exists(), reason="CRF++ not installed")
 | ||
| def test_nlp_parser():
 | ||
|     models: list[CRFIngredient] = convert_list_to_crf_model([x.input for x in test_ingredients])
 | ||
| 
 | ||
|     # Itterate over mdoels and test_ingreidnets to gether
 | ||
|     for model, test_ingredient in zip(models, test_ingredients):
 | ||
|         assert float(sum(Fraction(s) for s in model.qty.split())) == test_ingredient.quantity
 | ||
| 
 | ||
|         assert model.comment == test_ingredient.comments
 | ||
|         assert model.name == test_ingredient.food
 | ||
|         assert model.unit == test_ingredient.unit
 | ||
| 
 | ||
| 
 | ||
| def test_brute_parser():
 | ||
|     # input: (quantity, unit, food, comments)
 | ||
|     expectations = {
 | ||
|         # Dutch
 | ||
|         "1 theelepel koffie": (1, "theelepel", "koffie", ""),
 | ||
|         "3 theelepels koffie": (3, "theelepels", "koffie", ""),
 | ||
|         "1 eetlepel tarwe": (1, "eetlepel", "tarwe", ""),
 | ||
|         "20 eetlepels bloem": (20, "eetlepels", "bloem", ""),
 | ||
|         "1 mespunt kaneel": (1, "mespunt", "kaneel", ""),
 | ||
|         "1 snuf(je) zout": (1, "snuf(je)", "zout", ""),
 | ||
|         "2 tbsp minced cilantro, leaves and stems": (2, "tbsp", "minced cilantro", "leaves and stems"),
 | ||
|         "1 large yellow onion, coarsely chopped": (1, "large", "yellow onion", "coarsely chopped"),
 | ||
|         "1 1/2 tsp garam masala": (1.5, "tsp", "garam masala", ""),
 | ||
|         "2 cups mango chunks, (2 large mangoes) (fresh or frozen)": (
 | ||
|             2,
 | ||
|             "cups",
 | ||
|             "mango chunks, (2 large mangoes)",
 | ||
|             "fresh or frozen",
 | ||
|         ),
 | ||
|     }
 | ||
|     parser = get_parser(RegisteredParser.brute)
 | ||
| 
 | ||
|     for key, val in expectations.items():
 | ||
|         parsed = parser.parse_one(key)
 | ||
| 
 | ||
|         assert parsed.ingredient.quantity == val[0]
 | ||
|         assert parsed.ingredient.unit.name == val[1]
 | ||
|         assert parsed.ingredient.food.name == val[2]
 | ||
|         assert parsed.ingredient.note in {val[3], None}
 |