import random from typing import List, Optional from fastapi import FastAPI, HTTPException, Query from fastapi.middleware.cors import CORSMiddleware from pydantic import BaseModel import os import uvicorn from db_utils import ( list_recipes_db, create_recipe_db, get_recipes_by_filters_db, update_recipe_db, delete_recipe_db, ) class RecipeBase(BaseModel): name: str meal_type: str # breakfast / lunch / dinner / snack time_minutes: int tags: List[str] = [] ingredients: List[str] = [] steps: List[str] = [] class RecipeCreate(RecipeBase): pass class Recipe(RecipeBase): id: int class RecipeUpdate(RecipeBase): pass app = FastAPI( title="Random Recipes API", description="API פשוט לבחירת מתכונים לצהריים / ערב / כל ארוחה 😋", ) app.add_middleware( CORSMiddleware, allow_origins=["http://localhost:5173", "http://localhost:3000"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) @app.get("/recipes", response_model=List[Recipe]) def list_recipes(): rows = list_recipes_db() recipes = [ Recipe( id=r["id"], name=r["name"], meal_type=r["meal_type"], time_minutes=r["time_minutes"], tags=r["tags"] or [], ingredients=r["ingredients"] or [], steps=r["steps"] or [], ) for r in rows ] return recipes @app.post("/recipes", response_model=Recipe, status_code=201) def create_recipe(recipe_in: RecipeCreate): data = recipe_in.dict() data["meal_type"] = data["meal_type"].lower() row = create_recipe_db(data) return Recipe( id=row["id"], name=row["name"], meal_type=row["meal_type"], time_minutes=row["time_minutes"], tags=row["tags"] or [], ingredients=row["ingredients"] or [], steps=row["steps"] or [], ) @app.put("/recipes/{recipe_id}", response_model=Recipe) def update_recipe(recipe_id: int, recipe_in: RecipeUpdate): data = recipe_in.dict() data["meal_type"] = data["meal_type"].lower() row = update_recipe_db(recipe_id, data) if not row: raise HTTPException(status_code=404, detail="המתכון לא נמצא") return Recipe( id=row["id"], name=row["name"], meal_type=row["meal_type"], time_minutes=row["time_minutes"], tags=row["tags"] or [], ingredients=row["ingredients"] or [], steps=row["steps"] or [], ) @app.delete("/recipes/{recipe_id}", status_code=204) def delete_recipe(recipe_id: int): deleted = delete_recipe_db(recipe_id) if not deleted: raise HTTPException(status_code=404, detail="המתכון לא נמצא") return @app.get("/recipes/random", response_model=Recipe) def random_recipe( meal_type: Optional[str] = None, max_time: Optional[int] = None, ingredients: Optional[List[str]] = Query( None, description="רשימת מרכיבים (ingredients=ביצה&ingredients=עגבניה...)", ), ): rows = get_recipes_by_filters_db(meal_type, max_time) recipes = [ Recipe( id=r["id"], name=r["name"], meal_type=r["meal_type"], time_minutes=r["time_minutes"], tags=r["tags"] or [], ingredients=r["ingredients"] or [], steps=r["steps"] or [], ) for r in rows ] # סינון לפי מרכיבים באפליקציה if ingredients: desired = {i.strip().lower() for i in ingredients if i.strip()} if desired: recipes = [ r for r in recipes if desired.issubset({ing.lower() for ing in r.ingredients}) ] if not recipes: raise HTTPException( status_code=404, detail="לא נמצאו מתכונים מתאימים לפילטרים שבחרת", ) return random.choice(recipes) if __name__ == "__main__": uvicorn.run("main:app", host="0.0.0.0", port=8000, reload=True)