Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions mealie/routes/parser/ingredient_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ class IngredientParserController(BaseUserController):
@router.post("/ingredient", response_model=ParsedIngredient)
async def parse_ingredient(self, ingredient: IngredientRequest):
parser = get_parser(ingredient.parser, self.group_id, self.session)
response = await parser.parse([ingredient.ingredient])
response = await parser.parse([ingredient.ingredient], translate_language=ingredient.translate_language)
return response[0]

@router.post("/ingredients", response_model=list[ParsedIngredient])
async def parse_ingredients(self, ingredients: IngredientsRequest):
parser = get_parser(ingredients.parser, self.group_id, self.session)
return await parser.parse(ingredients.ingredients)
return await parser.parse(ingredients.ingredients, translate_language=ingredients.translate_language)
2 changes: 2 additions & 0 deletions mealie/schema/recipe/recipe_ingredient.py
Original file line number Diff line number Diff line change
Expand Up @@ -329,11 +329,13 @@ class RegisteredParser(str, enum.Enum):
class IngredientsRequest(MealieModel):
parser: RegisteredParser = RegisteredParser.nlp
ingredients: list[str]
translate_language: str | None = None


class IngredientRequest(MealieModel):
parser: RegisteredParser = RegisteredParser.nlp
ingredient: str
translate_language: str | None = None


class MergeFood(MealieModel):
Expand Down
4 changes: 2 additions & 2 deletions mealie/services/parser_services/_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,10 +148,10 @@ def unit_fuzzy_match_threshold(self) -> int:
return 70

@abstractmethod
async def parse_one(self, ingredient_string: str) -> ParsedIngredient: ...
async def parse_one(self, ingredient_string: str, translate_language: str | None = None) -> ParsedIngredient: ...

@abstractmethod
async def parse(self, ingredients: list[str]) -> list[ParsedIngredient]: ...
async def parse(self, ingredients: list[str], translate_language: str | None = None) -> list[ParsedIngredient]: ...

def find_ingredient_match(self, ingredient: ParsedIngredient) -> ParsedIngredient:
if ingredient.ingredient.food and (food_match := self.data_matcher.find_food_match(ingredient.ingredient.food)):
Expand Down
8 changes: 4 additions & 4 deletions mealie/services/parser_services/ingredient_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class BruteForceParser(ABCIngredientParser):
Brute force ingredient parser.
"""

async def parse_one(self, ingredient_string: str) -> ParsedIngredient:
async def parse_one(self, ingredient_string: str, translate_language: str | None = None) -> ParsedIngredient:
bfi = brute.parse(ingredient_string, self)

parsed_ingredient = ParsedIngredient(
Expand Down Expand Up @@ -66,7 +66,7 @@ async def parse_one(self, ingredient_string: str) -> ParsedIngredient:

return matched_ingredient

async def parse(self, ingredients: list[str]) -> list[ParsedIngredient]:
async def parse(self, ingredients: list[str], translate_language: str | None = None) -> list[ParsedIngredient]:
return [await self.parse_one(ingredient) for ingredient in ingredients]


Expand Down Expand Up @@ -182,11 +182,11 @@ def _convert_ingredient(self, ingredient: IngredientParserParsedIngredient) -> P

return self.find_ingredient_match(parsed_ingredient)

async def parse_one(self, ingredient_string: str) -> ParsedIngredient:
async def parse_one(self, ingredient_string: str, translate_language: str | None = None) -> ParsedIngredient:
parsed_ingredient = parse_ingredient(ingredient_string)
return self._convert_ingredient(parsed_ingredient)

async def parse(self, ingredients: list[str]) -> list[ParsedIngredient]:
async def parse(self, ingredients: list[str], translate_language: str | None = None) -> list[ParsedIngredient]:
return [await self.parse_one(ingredient) for ingredient in ingredients]


Expand Down
14 changes: 8 additions & 6 deletions mealie/services/parser_services/openai/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ def _get_prompt(self, service: OpenAIService) -> str:
OpenAIDataInjection(
description=(
"This is the JSON response schema. You must respond in valid JSON that follows this schema. "
"Your payload should be as compact as possible, eliminating unncessesary whitespace. Any fields "
"Your payload should be as compact as possible, eliminating unnecessary whitespace. Any fields "
"with default values which you do not populate should not be in the payload."
),
value=OpenAIIngredients,
Expand Down Expand Up @@ -142,7 +142,7 @@ def _chunk_messages(messages: list[str], n=1) -> list[list[str]]:
n = 1
return [messages[i : i + n] for i in range(0, len(messages), n)]

async def _parse(self, ingredients: list[str]) -> OpenAIIngredients:
async def _parse(self, ingredients: list[str], translate_language: str | None = None) -> OpenAIIngredients:
service = OpenAIService()
prompt = self._get_prompt(service)

Expand All @@ -151,6 +151,8 @@ async def _parse(self, ingredients: list[str]) -> OpenAIIngredients:
tasks: list[Awaitable[str | None]] = []
for ingredient_chunk in ingredient_chunks:
message = json.dumps(ingredient_chunk, separators=(",", ":"))
if translate_language:
message += f" Please translate the recipe to {translate_language}."
tasks.append(service.get_response(prompt, message, force_json_response=True))

# re-combine chunks into one response
Expand All @@ -175,12 +177,12 @@ async def _parse(self, ingredients: list[str]) -> OpenAIIngredients:
ingredients=[ingredient for response in responses for ingredient in response.ingredients]
)

async def parse_one(self, ingredient_string: str) -> ParsedIngredient:
items = await self.parse([ingredient_string])
async def parse_one(self, ingredient_string: str, translate_language: str | None = None) -> ParsedIngredient:
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could it be that this method is never called? I'm assuming it has to exist because of the abstract method in _base.py, but imo it is a bit confusing to have any logic within it beyond a raise NotImplementedError("This method is not supported.")

items = await self.parse([ingredient_string], translate_language=translate_language)
return items[0]

async def parse(self, ingredients: list[str]) -> list[ParsedIngredient]:
response = await self._parse(ingredients)
async def parse(self, ingredients: list[str], translate_language: str | None = None) -> list[ParsedIngredient]:
response = await self._parse(ingredients, translate_language=translate_language)
if len(response.ingredients) != len(ingredients):
raise ValueError(
"OpenAI returned an unexpected number of ingredients. "
Expand Down