166 lines
5.0 KiB
Python
166 lines
5.0 KiB
Python
"""食谱 API - 支持热量识别与营养分析"""
|
|
|
|
from typing import Optional
|
|
from fastapi import APIRouter, Depends, HTTPException, UploadFile, File
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from ..core.database import get_db
|
|
from ..dependencies.auth import get_current_tenant_id
|
|
from ..schemas.recipe import (
|
|
RecipeCreate,
|
|
RecipeUpdate,
|
|
RecipeResponse,
|
|
RecipeImageUploadRequest,
|
|
RecipeAnalyzeCaloriesResponse,
|
|
)
|
|
from ..services.recipe import get_recipe_service
|
|
|
|
router = APIRouter(prefix="/recipes", tags=["食谱"])
|
|
|
|
|
|
@router.post("/", response_model=RecipeResponse, summary="创建食谱")
|
|
async def create_recipe(
|
|
recipe_data: RecipeCreate,
|
|
db: AsyncSession = Depends(get_db),
|
|
tenant_id: int = Depends(get_current_tenant_id),
|
|
):
|
|
"""创建新食谱"""
|
|
service = get_recipe_service()
|
|
recipe = await service.create_recipe(db, recipe_data, tenant_id)
|
|
return recipe
|
|
|
|
|
|
@router.post("/analyze", response_model=RecipeAnalyzeCaloriesResponse, summary="AI 热量分析")
|
|
async def analyze_food_calories(
|
|
recipe_data: RecipeCreate,
|
|
food_description: str,
|
|
db: AsyncSession = Depends(get_db),
|
|
tenant_id: int = Depends(get_current_tenant_id),
|
|
):
|
|
"""
|
|
创建食谱并进行 AI 热量分析
|
|
|
|
- food_description: 食物描述(可以是图片识别后的描述)
|
|
"""
|
|
service = get_recipe_service()
|
|
recipe, analysis = await service.create_recipe_with_ai_analysis(
|
|
db, recipe_data, food_description, tenant_id
|
|
)
|
|
|
|
if not analysis["success"]:
|
|
return RecipeAnalyzeCaloriesResponse(
|
|
success=False,
|
|
data=None,
|
|
message=analysis["message"],
|
|
)
|
|
|
|
return RecipeAnalyzeCaloriesResponse(
|
|
success=True,
|
|
data=recipe,
|
|
message=analysis["message"],
|
|
)
|
|
|
|
|
|
@router.get("/", response_model=list[RecipeResponse], summary="获取食谱列表")
|
|
async def list_recipes(
|
|
skip: int = 0,
|
|
limit: int = 20,
|
|
category: Optional[str] = None,
|
|
cuisine: Optional[str] = None,
|
|
status: Optional[str] = None,
|
|
is_favorite: Optional[bool] = None,
|
|
db: AsyncSession = Depends(get_db),
|
|
tenant_id: int = Depends(get_current_tenant_id),
|
|
):
|
|
"""获取食谱列表,支持分类筛选"""
|
|
service = get_recipe_service()
|
|
recipes = await service.list_recipes(
|
|
db,
|
|
tenant_id,
|
|
skip=skip,
|
|
limit=limit,
|
|
category=category,
|
|
cuisine=cuisine,
|
|
status=status,
|
|
is_favorite=is_favorite,
|
|
)
|
|
return recipes
|
|
|
|
|
|
@router.get("/{recipe_id}", response_model=RecipeResponse, summary="获取单个食谱")
|
|
async def get_recipe(
|
|
recipe_id: int,
|
|
db: AsyncSession = Depends(get_db),
|
|
tenant_id: int = Depends(get_current_tenant_id),
|
|
):
|
|
"""获取指定食谱详情"""
|
|
service = get_recipe_service()
|
|
recipe = await service.get_recipe(db, recipe_id, tenant_id)
|
|
if not recipe:
|
|
raise HTTPException(status_code=404, detail="食谱不存在")
|
|
return recipe
|
|
|
|
|
|
@router.put("/{recipe_id}", response_model=RecipeResponse, summary="更新食谱")
|
|
async def update_recipe(
|
|
recipe_id: int,
|
|
recipe_data: RecipeUpdate,
|
|
db: AsyncSession = Depends(get_db),
|
|
tenant_id: int = Depends(get_current_tenant_id),
|
|
):
|
|
"""更新食谱信息"""
|
|
service = get_recipe_service()
|
|
recipe = await service.update_recipe(db, recipe_id, recipe_data, tenant_id)
|
|
if not recipe:
|
|
raise HTTPException(status_code=404, detail="食谱不存在")
|
|
return recipe
|
|
|
|
|
|
@router.delete("/{recipe_id}", summary="删除食谱")
|
|
async def delete_recipe(
|
|
recipe_id: int,
|
|
db: AsyncSession = Depends(get_db),
|
|
tenant_id: int = Depends(get_current_tenant_id),
|
|
):
|
|
"""删除食谱"""
|
|
service = get_recipe_service()
|
|
success = await service.delete_recipe(db, recipe_id, tenant_id)
|
|
if not success:
|
|
raise HTTPException(status_code=404, detail="食谱不存在")
|
|
return {"message": "删除成功"}
|
|
|
|
|
|
@router.post("/{recipe_id}/favorite", response_model=RecipeResponse, summary="收藏/取消收藏食谱")
|
|
async def toggle_favorite(
|
|
recipe_id: int,
|
|
db: AsyncSession = Depends(get_db),
|
|
tenant_id: int = Depends(get_current_tenant_id),
|
|
):
|
|
"""收藏或取消收藏食谱"""
|
|
service = get_recipe_service()
|
|
recipe = await service.get_recipe(db, recipe_id, tenant_id)
|
|
if not recipe:
|
|
raise HTTPException(status_code=404, detail="食谱不存在")
|
|
|
|
recipe.is_favorite = not recipe.is_favorite
|
|
await db.commit()
|
|
await db.refresh(recipe)
|
|
return recipe
|
|
|
|
|
|
@router.post("/upload-image", response_model=dict, summary="上传图片(示例)")
|
|
async def upload_recipe_image(
|
|
image_base64: str,
|
|
filename: Optional[str] = None,
|
|
db: AsyncSession = Depends(get_db),
|
|
tenant_id: int = Depends(get_current_tenant_id),
|
|
):
|
|
"""
|
|
上传食谱图片
|
|
|
|
注意:这是示例实现,实际项目中需要集成对象存储服务(如 S3、OSS、COS 等)
|
|
"""
|
|
service = get_recipe_service()
|
|
image_url = await service.upload_image(image_base64, filename)
|
|
return {"image_url": image_url}
|