Files
Vorrania/backend/app/off.py
Scarriffle ea67e6c1b0 Umbenennung Pantry -> Project-Good; README mit echter Clone-URL
- Anzeigename, Paketname, Token-Key, DB-/Volume-Namen auf project_good
- README Clone-Abschnitt mit git.scarriffle.com/Scarriffle/project-good

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-22 09:24:54 +02:00

73 lines
2.0 KiB
Python

"""Open Food Facts Lookup-Client."""
from __future__ import annotations
import json
import httpx
from .config import get_settings
settings = get_settings()
def _guess_base_unit(quantity: str | None) -> str:
"""Rät die Basiseinheit aus dem OFF-Feld 'quantity' (z.B. '500 g', '1 l')."""
if not quantity:
return "piece"
q = quantity.lower()
if "ml" in q or "cl" in q or "l" in q or "liter" in q:
return "milliliter"
if "kg" in q or " g" in q or "gramm" in q or q.strip().endswith("g"):
return "gram"
return "piece"
def lookup_barcode(barcode: str) -> dict | None:
"""Fragt Open Food Facts nach einem Barcode.
Gibt ein vorbefülltes Produkt-Dict zurück oder None, wenn nicht gefunden.
"""
url = f"{settings.off_base_url}/api/v2/product/{barcode}.json"
try:
resp = httpx.get(
url,
timeout=settings.off_timeout_seconds,
headers={"User-Agent": "Project-Good-Selfhosted/1.0"},
)
except httpx.HTTPError:
return None
if resp.status_code != 200:
return None
data = resp.json()
if data.get("status") != 1:
return None
product = data.get("product", {})
name = (
product.get("product_name_de")
or product.get("product_name")
or product.get("generic_name")
or ""
).strip()
if not name:
return None
categories = product.get("categories") or ""
category_tags = product.get("categories_tags") or []
return {
"barcode": barcode,
"name": name,
"brand": (product.get("brands") or "").strip() or None,
"image_url": product.get("image_front_url") or product.get("image_url") or None,
"base_unit": _guess_base_unit(product.get("quantity")),
"quantity_text": product.get("quantity"),
"category_suggestion": categories.split(",")[0].strip() if categories else None,
"category_tags": category_tags,
"source": "off",
"off_raw": json.dumps(product)[:20000],
}