import sqlite3 import product, recipe, db from pydantic import BaseModel from typing import List, Annotated from fastapi import FastAPI, Depends, Query from fastapi.responses import JSONResponse from fastapi.middleware.cors import CORSMiddleware app = FastAPI() # Add CORS middleware app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"] ) # Dependency to create SQLite connection async def get_db(): sql_db = await db.connect() try: yield sql_db finally: await sql_db.close() @app.get("/recipes/parse") async def parse_recipe_handler(url: str, conn: sqlite3.Connection = Depends(get_db)) -> recipe.Recipe: parsed = await recipe.parse_recipe(conn, url) if not parsed: return JSONResponse(status_code=400, content={'message': 'Recipe not found'}) return parsed @app.get("/recipes/ingredients/parse") async def parse_ingredients(lines: Annotated[ List[str], Query(alias="ingredients", title="Array of ingredients to parse")], conn: sqlite3.Connection = Depends(get_db)) -> List[recipe.Ingredient]: ingredients = recipe.parse_ingredient_from_nlp(lines) recipe.match_existing_products(conn, ingredients) return ingredients class ProductUrl(BaseModel): url: str tags: List[str] = [] @app.post("/products/") async def create_product(url: ProductUrl, conn: sqlite3.Connection = Depends(get_db)) -> product.Product: return await product.get_or_create(conn, url.url, url.tags) @app.get("/recipes/{recipe_id}") async def get_recipe(recipe_id: int, conn: sqlite3.Connection = Depends(get_db)) -> recipe.Recipe: r = await recipe.find_recipe_by_id(conn, recipe_id) if not r: return JSONResponse(status_code=404, content={'message': 'Recipe not found'}) r.ingredients = [] async for ingredient in recipe.find_ingredients_by_recipe_id(conn, recipe_id): ingredient.product = await product.find_product_by_id(conn, ingredient.product_id) r.ingredients.append(ingredient) return r @app.post('/recipes/') async def create_recipe(item: recipe.Recipe, conn: sqlite3.Connection = Depends(get_db)) -> recipe.Recipe: if not item.ingredients: return JSONResponse(status_code=400, content={'message': 'Recipe must have at least one ingredient'}) for ingredient in item.ingredients: if not ingredient.product: return JSONResponse(status_code=400, content={'message': 'Ingredient must have a product'}) await recipe.insert_recipe(conn, item) for ingredient in item.ingredients: ingredient.recipe_id = item.id ingredient.product_id = ingredient.product.id await recipe.insert_ingredient(conn, ingredient) await conn.commit() return item