Introcuced a Free LLM for easier food input
This commit is contained in:
@@ -2,17 +2,36 @@ from uuid import uuid4
|
||||
|
||||
import httpx
|
||||
from fastapi import APIRouter, HTTPException, Query, status
|
||||
from pydantic import ValidationError
|
||||
from sqlmodel import select
|
||||
|
||||
from app import llm
|
||||
from app.access import product_barcode_accessible
|
||||
from app.deps import CurrentUserDep, SessionDep
|
||||
from app.models import FoodLog, Product
|
||||
from app.schemas import ProductCreate, ProductRead, ProductSearchResult
|
||||
from app.schemas import (
|
||||
NutritionEstimateRequest,
|
||||
NutritionEstimateResponse,
|
||||
ProductCreate,
|
||||
ProductRead,
|
||||
ProductSearchResult,
|
||||
)
|
||||
|
||||
router = APIRouter(prefix="/api/products", tags=["products"])
|
||||
|
||||
OFF_API_URL = "https://world.openfoodfacts.org/api/v2/product/{barcode}.json"
|
||||
|
||||
ESTIMATE_SYSTEM_PROMPT = """Du bist ein Ernährungsexperte. Schätze die Nährwerte des vom Nutzer beschriebenen Lebensmittels oder Gerichts.
|
||||
|
||||
Antworte AUSSCHLIESSLICH mit einem JSON-Objekt in genau diesem Format:
|
||||
{"name": "kurzer Produktname", "calories": 250.0, "carbs": 30.0, "protein": 12.0, "fat": 9.0, "sugar": 3.0, "fiber": 2.0, "saturated_fat": 3.5, "salt": 1.2, "portion_g": 350.0}
|
||||
|
||||
Regeln:
|
||||
- Alle Nährwerte beziehen sich auf 100 g (calories in kcal, alles andere in Gramm).
|
||||
- portion_g ist die geschätzte übliche Portionsgröße der Beschreibung in Gramm.
|
||||
- name ist ein kurzer, gut lesbarer deutscher Produktname ohne Mengenangabe.
|
||||
- Nutze realistische Durchschnittswerte. Keine Erklärungen, kein Text außerhalb des JSON."""
|
||||
|
||||
|
||||
def _extract_macros(nutriments: dict) -> dict:
|
||||
calories = nutriments.get("energy-kcal_100g")
|
||||
@@ -71,6 +90,31 @@ def create_product(product_in: ProductCreate, current_user: CurrentUserDep, sess
|
||||
return product
|
||||
|
||||
|
||||
@router.post("/estimate", response_model=NutritionEstimateResponse)
|
||||
def estimate_nutrition(estimate_in: NutritionEstimateRequest, current_user: CurrentUserDep):
|
||||
if not llm.is_configured():
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
|
||||
detail="KI-Schätzung ist auf diesem Server nicht konfiguriert",
|
||||
)
|
||||
|
||||
try:
|
||||
data = llm.complete_json(ESTIMATE_SYSTEM_PROMPT, estimate_in.description)
|
||||
except llm.LLMUnavailableError:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
|
||||
detail="KI-Schätzung gerade nicht erreichbar. Bitte später erneut versuchen.",
|
||||
)
|
||||
|
||||
try:
|
||||
return NutritionEstimateResponse(**data)
|
||||
except (ValidationError, TypeError):
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_502_BAD_GATEWAY,
|
||||
detail="KI-Antwort war unbrauchbar. Bitte erneut versuchen oder Werte manuell eintragen.",
|
||||
)
|
||||
|
||||
|
||||
@router.get("/search", response_model=list[ProductSearchResult])
|
||||
def search_products(
|
||||
current_user: CurrentUserDep,
|
||||
|
||||
Reference in New Issue
Block a user