banyaro/backend/routes/ernaehrung.py

145 lines
5.2 KiB
Python

"""BAN YARO — Ernährungs-Routes"""
import logging
from fastapi import APIRouter, Depends, HTTPException, Request
from pydantic import BaseModel
from typing import Optional
from database import db
from auth import get_current_user
import ki as ki_module
router = APIRouter()
logger = logging.getLogger(__name__)
# ------------------------------------------------------------------
# Schemas
# ------------------------------------------------------------------
class FutterProfilUpdate(BaseModel):
futter_typ: Optional[str] = None # trocken|nass|barf|mix
marke: Optional[str] = None
kcal_tag: Optional[int] = None
portionen: Optional[int] = None
notizen: Optional[str] = None
class KiBeratungRequest(BaseModel):
frage: str
dog_name: Optional[str] = None
rasse: Optional[str] = None
alter: Optional[str] = None
gewicht: Optional[float] = None
aktiv: Optional[bool] = None
# ------------------------------------------------------------------
# Hilfsfunktion: Zugriffsprüfung
# ------------------------------------------------------------------
def _check_dog_access(conn, dog_id: int, user_id: int):
row = conn.execute(
"SELECT id FROM dogs WHERE id=? AND user_id=?", (dog_id, user_id)
).fetchone()
if not row:
raise HTTPException(404, "Hund nicht gefunden.")
# ------------------------------------------------------------------
# GET /dogs/{dog_id}/ernaehrung
# ------------------------------------------------------------------
@router.get("/{dog_id}/ernaehrung")
async def get_ernaehrung(dog_id: int, user=Depends(get_current_user)):
with db() as conn:
_check_dog_access(conn, dog_id, user["id"])
row = conn.execute(
"SELECT * FROM futter_profil WHERE dog_id=?", (dog_id,)
).fetchone()
if not row:
return {}
return dict(row)
# ------------------------------------------------------------------
# PUT /dogs/{dog_id}/ernaehrung
# ------------------------------------------------------------------
@router.put("/{dog_id}/ernaehrung")
async def put_ernaehrung(dog_id: int, body: FutterProfilUpdate,
user=Depends(get_current_user)):
with db() as conn:
_check_dog_access(conn, dog_id, user["id"])
existing = conn.execute(
"SELECT id FROM futter_profil WHERE dog_id=?", (dog_id,)
).fetchone()
if existing:
conn.execute("""
UPDATE futter_profil
SET futter_typ=COALESCE(?, futter_typ),
marke=COALESCE(?, marke),
kcal_tag=COALESCE(?, kcal_tag),
portionen=COALESCE(?, portionen),
notizen=COALESCE(?, notizen),
updated_at=datetime('now')
WHERE dog_id=?
""", (body.futter_typ, body.marke, body.kcal_tag,
body.portionen, body.notizen, dog_id))
else:
conn.execute("""
INSERT INTO futter_profil
(dog_id, futter_typ, marke, kcal_tag, portionen, notizen)
VALUES (?, ?, ?, ?, ?, ?)
""", (dog_id, body.futter_typ, body.marke, body.kcal_tag,
body.portionen or 2, body.notizen))
row = conn.execute(
"SELECT * FROM futter_profil WHERE dog_id=?", (dog_id,)
).fetchone()
return dict(row)
# ------------------------------------------------------------------
# POST /dogs/{dog_id}/ernaehrung/ki-beratung
# ------------------------------------------------------------------
@router.post("/{dog_id}/ernaehrung/ki-beratung")
async def ki_ernaehrung(dog_id: int, body: KiBeratungRequest,
request: Request,
user=Depends(get_current_user)):
if not body.frage or len(body.frage.strip()) < 3:
raise HTTPException(400, "Bitte stelle eine Frage.")
if len(body.frage) > 800:
raise HTTPException(400, "Frage zu lang (max. 800 Zeichen).")
with db() as conn:
_check_dog_access(conn, dog_id, user["id"])
dog_name = body.dog_name or "unbekannt"
rasse = body.rasse or "unbekannt"
alter = body.alter or "unbekannt"
gewicht = f"{body.gewicht} kg" if body.gewicht else "unbekannt"
aktiv_str = "aktiv" if body.aktiv else "normal aktiv"
system = (
"Du bist Ernährungsberater für Hunde. "
"Antworte immer auf Deutsch, kurz und praktisch. "
"Keine unnötigen Füllsätze. "
"Weise bei ernsthaften Gesundheitsfragen immer auf den Tierarzt hin. "
"Stelle keine medizinischen Diagnosen."
)
prompt = (
f"Hund: {dog_name}, Rasse: {rasse}, Alter: {alter}, "
f"Gewicht: {gewicht}, Aktivität: {aktiv_str}.\n\n"
f"Frage: {body.frage.strip()}\n\n"
"Antworte konkret und praktisch, maximal 200 Wörter."
)
try:
antwort = await ki_module.complete(
prompt=prompt,
system=system,
max_tokens=500,
requires_premium=False,
user_id=user["id"],
)
return {"antwort": antwort}
except ki_module.KIUnavailableError as e:
raise HTTPException(503, str(e))
except Exception:
raise HTTPException(500, "KI momentan nicht verfügbar.")