2025-12-07 19:15:23 +02:00

182 lines
4.6 KiB
Python

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
made_by: Optional[str] = None # Person who created this recipe version
tags: List[str] = []
ingredients: List[str] = []
steps: List[str] = []
image: Optional[str] = None # Base64-encoded image or image URL
class RecipeCreate(RecipeBase):
pass
class Recipe(RecipeBase):
id: int
class RecipeUpdate(RecipeBase):
pass
app = FastAPI(
title="Random Recipes API",
description="API פשוט לבחירת מתכונים לצהריים / ערב / כל ארוחה 😋",
)
# Allow CORS from frontend domains
allowed_origins = [
"http://localhost:5173",
"http://localhost:3000",
"https://my-recipes.dvirlabs.com",
"http://my-recipes.dvirlabs.com",
]
app.add_middleware(
CORSMiddleware,
allow_origins=allowed_origins,
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"],
made_by=r.get("made_by"),
tags=r["tags"] or [],
ingredients=r["ingredients"] or [],
steps=r["steps"] or [],
image=r.get("image"),
)
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"],
made_by=row.get("made_by"),
tags=row["tags"] or [],
ingredients=row["ingredients"] or [],
steps=row["steps"] or [],
image=row.get("image"),
)
@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"],
made_by=row.get("made_by"),
tags=row["tags"] or [],
ingredients=row["ingredients"] or [],
steps=row["steps"] or [],
image=row.get("image"),
)
@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"],
made_by=r.get("made_by"),
tags=r["tags"] or [],
ingredients=r["ingredients"] or [],
steps=r["steps"] or [],
image=r.get("image"),
)
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)