Added num serves to recipe
This commit is contained in:
parent
6b684fadd8
commit
c1375d8d52
4 changed files with 57 additions and 13 deletions
4
main.py
4
main.py
|
|
@ -32,8 +32,8 @@ async def cookie_person(user_id: Annotated[int, Cookie(alias='user_id')], conn:
|
||||||
return await persons.get_by_id(conn, user_id)
|
return await persons.get_by_id(conn, user_id)
|
||||||
|
|
||||||
@app.get("/recipes/parse")
|
@app.get("/recipes/parse")
|
||||||
async def parse_recipe_handler(url: str, conn: sqlite3.Connection = Depends(get_db)) -> recipes.Recipe:
|
async def parse_recipe_handler(url: str, conn: sqlite3.Connection = Depends(get_db), person = Depends(cookie_person)) -> recipes.Recipe:
|
||||||
parsed = await recipes.parse_recipe(conn, url)
|
parsed = await recipes.parse_recipe(conn, person, url)
|
||||||
if not parsed:
|
if not parsed:
|
||||||
return JSONResponse(status_code=400, content={'message': 'Recipe not found'})
|
return JSONResponse(status_code=400, content={'message': 'Recipe not found'})
|
||||||
return parsed
|
return parsed
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,42 @@
|
||||||
|
from persons import Person
|
||||||
|
|
||||||
from recipes.db import Recipe, insert_recipe, find_recipe_by_id, get_all, find_recipes_by_name, row_to_recipe, load_recipe_ingredients, hide_recipe
|
from recipes.db import Recipe, insert_recipe, find_recipe_by_id, get_all, find_recipes_by_name, row_to_recipe, load_recipe_ingredients, hide_recipe
|
||||||
from recipes.scraping import scrape_recipe_ldata as _scrape_recipe_ldata
|
from recipes.scraping import scrape_recipe_ldata as _scrape_recipe_ldata
|
||||||
from ingredients import parse_ingredient_from_nlp as _parse_ingredient_from_nlp, match_existing_products as _match_existing_products
|
from ingredients import parse_ingredient_from_nlp as _parse_ingredient_from_nlp, match_existing_products as _match_existing_products
|
||||||
|
|
||||||
async def parse_recipe(conn, url: str) -> Recipe:
|
import re
|
||||||
|
|
||||||
|
async def parse_recipe(conn, created_by: Person, url: str) -> Recipe:
|
||||||
ldata = await _scrape_recipe_ldata(url)
|
ldata = await _scrape_recipe_ldata(url)
|
||||||
if ldata:
|
if ldata:
|
||||||
return await _get_recipe_from_ldata(conn, url, ldata)
|
return await _get_recipe_from_ldata(conn, url, ldata, created_by)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def find_yield(recipe_ldata: dict) -> int:
|
||||||
|
if 'recipeYield' in recipe_ldata:
|
||||||
|
yield_vals = recipe_ldata['recipeYield']
|
||||||
|
if not isinstance(yield_vals, list):
|
||||||
|
yield_vals = [yield_vals]
|
||||||
|
|
||||||
|
for val in yield_vals:
|
||||||
|
try:
|
||||||
|
return int(val)
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
for val in yield_vals:
|
||||||
|
match = re.match(r'(\d+)', val)
|
||||||
|
if match:
|
||||||
|
return int(match.group(1))
|
||||||
|
|
||||||
|
return 4
|
||||||
|
|
||||||
async def _get_recipe_from_ldata(conn, url: str, ldata: dict) -> dict:
|
async def _get_recipe_from_ldata(conn, url: str, ldata: dict, created_by: Person) -> dict:
|
||||||
ingredients = _parse_ingredient_from_nlp(ldata['recipeIngredient'])
|
ingredients = _parse_ingredient_from_nlp(ldata['recipeIngredient'])
|
||||||
ingredients = await _match_existing_products(conn, ingredients)
|
ingredients = await _match_existing_products(conn, ingredients)
|
||||||
name = ldata['name'] if 'name' in ldata else url
|
name = ldata['name'] if 'name' in ldata else url
|
||||||
images = ldata['image'] if 'image' in ldata else []
|
images = ldata['image'] if 'image' in ldata else []
|
||||||
|
serves = find_yield(ldata)
|
||||||
|
|
||||||
if isinstance(images, list) and len(images) > 0 and isinstance(images[0], dict):
|
if isinstance(images, list) and len(images) > 0 and isinstance(images[0], dict):
|
||||||
images = [image['url'] for image in images]
|
images = [image['url'] for image in images]
|
||||||
|
|
@ -27,6 +51,9 @@ async def _get_recipe_from_ldata(conn, url: str, ldata: dict) -> dict:
|
||||||
id=0,
|
id=0,
|
||||||
name=name,
|
name=name,
|
||||||
link=url,
|
link=url,
|
||||||
|
serves=serves,
|
||||||
image_urls=images,
|
image_urls=images,
|
||||||
ingredients=ingredients
|
ingredients=ingredients,
|
||||||
|
created_by=created_by,
|
||||||
|
created_by_id=created_by.id,
|
||||||
)
|
)
|
||||||
|
|
@ -7,16 +7,19 @@ from pydantic import BaseModel
|
||||||
from typing import AsyncIterator, List, ClassVar, Tuple, Optional
|
from typing import AsyncIterator, List, ClassVar, Tuple, Optional
|
||||||
|
|
||||||
class Recipe(BaseModel):
|
class Recipe(BaseModel):
|
||||||
KEYS: ClassVar[List[str]] = ['id', 'name', 'link', 'image_urls', 'based_on_recipe', 'created_by_id', 'date_created', 'hidden_by_id', 'date_hidden']
|
KEYS: ClassVar[List[str]] = ['id', 'name', 'link', 'serves', 'image_urls', 'based_on_recipe', 'created_by_id', 'date_created', 'hidden_by_id', 'date_hidden']
|
||||||
|
NON_INSERT_KEYS: ClassVar[List[str]] = ['id', 'created_date', 'hidden_by_id', 'date_hidden']
|
||||||
|
|
||||||
id: int
|
id: int
|
||||||
name: str
|
name: str
|
||||||
link: str
|
link: str
|
||||||
|
serves: int
|
||||||
image_urls: List[str] = []
|
image_urls: List[str] = []
|
||||||
ingredients: List[Ingredient] = []
|
ingredients: List[Ingredient] = []
|
||||||
based_on_recipe: Optional[int] = None
|
based_on_recipe: Optional[int] = None
|
||||||
|
|
||||||
date_created: Optional[datetime.datetime] = None
|
date_created: datetime.datetime = datetime.datetime.now()
|
||||||
created_by_id: Optional[int] = None
|
created_by_id: int
|
||||||
created_by: Optional[Person] = None
|
created_by: Optional[Person] = None
|
||||||
|
|
||||||
date_hidden: Optional[datetime.datetime] = None
|
date_hidden: Optional[datetime.datetime] = None
|
||||||
|
|
@ -29,6 +32,7 @@ async def create(conn):
|
||||||
id INTEGER PRIMARY KEY,
|
id INTEGER PRIMARY KEY,
|
||||||
name TEXT NOT NULL,
|
name TEXT NOT NULL,
|
||||||
link TEXT NOT NULL,
|
link TEXT NOT NULL,
|
||||||
|
serves INTEGER NOT NULL,
|
||||||
image_urls TEXT NOT NULL,
|
image_urls TEXT NOT NULL,
|
||||||
based_on_recipe INTEGER NULL,
|
based_on_recipe INTEGER NULL,
|
||||||
|
|
||||||
|
|
@ -43,11 +47,22 @@ async def create(conn):
|
||||||
FOREIGN KEY (hidden_by_id) REFERENCES Person(id)
|
FOREIGN KEY (hidden_by_id) REFERENCES Person(id)
|
||||||
);''')
|
);''')
|
||||||
|
|
||||||
|
def _as_insert_field(recipe: Recipe, name: str):
|
||||||
|
value = getattr(recipe, name)
|
||||||
|
if name == 'image_urls':
|
||||||
|
return json.dumps(value)
|
||||||
|
return value
|
||||||
|
|
||||||
async def insert_recipe(conn, recipe: Recipe):
|
async def insert_recipe(conn, recipe: Recipe):
|
||||||
async with conn.execute('''
|
fields_to_insert = [k for k in Recipe.KEYS if k not in Recipe.NON_INSERT_KEYS]
|
||||||
INSERT INTO Recipe (name, link, image_urls, based_on_recipe, created_by_id)
|
actual_values = [_as_insert_field(recipe, k) for k in fields_to_insert]
|
||||||
VALUES (?, ?, ?, ?, ?)
|
|
||||||
''', (recipe.name, recipe.link, json.dumps(recipe.image_urls), recipe.based_on_recipe, recipe.created_by_id)) as cursor:
|
insert_stmt = f'''
|
||||||
|
INSERT INTO Recipe ({','.join(fields_to_insert)})
|
||||||
|
VALUES ({','.join(['?'] * len(fields_to_insert))})
|
||||||
|
'''
|
||||||
|
|
||||||
|
async with conn.execute(insert_stmt, actual_values) as cursor:
|
||||||
recipe.id = cursor.lastrowid
|
recipe.id = cursor.lastrowid
|
||||||
|
|
||||||
async def hide_recipe(conn, recipe_id: int, person: Person):
|
async def hide_recipe(conn, recipe_id: int, person: Person):
|
||||||
|
|
|
||||||
|
|
@ -191,6 +191,7 @@ class Recipes:
|
||||||
id=0,
|
id=0,
|
||||||
name='Broccoli Soup',
|
name='Broccoli Soup',
|
||||||
link='https://www.bbcgoodfood.com/recipes/broccoli-soup',
|
link='https://www.bbcgoodfood.com/recipes/broccoli-soup',
|
||||||
|
serves=4,
|
||||||
image_urls=['https://www.bbcgoodfood.com/sites/default/files/styles/recipe/public/recipe/recipe-image/2018/10/broccoli-soup.jpg'],
|
image_urls=['https://www.bbcgoodfood.com/sites/default/files/styles/recipe/public/recipe/recipe-image/2018/10/broccoli-soup.jpg'],
|
||||||
ingredients=[Ingredients.broccoli_chopped_1kg],
|
ingredients=[Ingredients.broccoli_chopped_1kg],
|
||||||
created_by_id=Persons.jacob.id,
|
created_by_id=Persons.jacob.id,
|
||||||
|
|
@ -200,6 +201,7 @@ class Recipes:
|
||||||
id=0,
|
id=0,
|
||||||
name="How to Steam Green Beans",
|
name="How to Steam Green Beans",
|
||||||
link="https://www.thespruceeats.com/steamed-green-beans-3057051",
|
link="https://www.thespruceeats.com/steamed-green-beans-3057051",
|
||||||
|
serves=4,
|
||||||
image_urls=["https://www.thespruceeats.com/thmb/CLROdq9dlYbjKjlOlA_kmFdunTY=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/steamed-green-beans-3057051-hero-01-b1c4f894da5b4bc0a01cd43886df0100.jpg"],
|
image_urls=["https://www.thespruceeats.com/thmb/CLROdq9dlYbjKjlOlA_kmFdunTY=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/steamed-green-beans-3057051-hero-01-b1c4f894da5b4bc0a01cd43886df0100.jpg"],
|
||||||
ingredients=[Ingredients.green_beans,Ingredients.butter,Ingredients.salt,Ingredients.freshly_ground_black_pepper],
|
ingredients=[Ingredients.green_beans,Ingredients.butter,Ingredients.salt,Ingredients.freshly_ground_black_pepper],
|
||||||
created_by_id=Persons.jacob.id,
|
created_by_id=Persons.jacob.id,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue