Platform bundle: marketing publish, IT ops, packaging, agents mesh.
Volledige Foodlinkk Command Center uitbreiding met social automatisering, reclamefolder filters, Proxmox monitoring en documentatie.
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
"""Packaging generation API routes."""
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Any, Literal
|
||||
from uuid import uuid4
|
||||
|
||||
from fastapi import APIRouter, HTTPException, Query
|
||||
from fastapi.responses import Response
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
from app.packaging.export import svg_to_pdf_bytes, svg_to_png_bytes
|
||||
from app.packaging.generator import FOODLINKK_BRAND, generate_packaging
|
||||
|
||||
router = APIRouter(prefix="/packaging", tags=["packaging"])
|
||||
|
||||
_PROJECTS: dict[str, dict[str, Any]] = {}
|
||||
|
||||
|
||||
class PackagingSpec(BaseModel):
|
||||
type: Literal["folding_box", "wrap", "round_label"]
|
||||
width_mm: float = Field(default=120, gt=0, le=4000)
|
||||
height_mm: float = Field(default=80, gt=0, le=4000)
|
||||
depth_mm: float = Field(default=40, ge=0, le=4000)
|
||||
elements: dict[str, bool] = Field(default_factory=dict)
|
||||
brand: dict[str, str] = Field(default_factory=dict)
|
||||
barcode_value: str | None = Field(default=None, max_length=64)
|
||||
|
||||
|
||||
@router.post("/generate")
|
||||
def packaging_generate(spec: PackagingSpec) -> dict[str, Any]:
|
||||
spec_data = spec.model_dump()
|
||||
if not spec_data["brand"]:
|
||||
spec_data["brand"] = dict(FOODLINKK_BRAND)
|
||||
svg = generate_packaging(spec_data)
|
||||
project_id = uuid4().hex
|
||||
now = datetime.utcnow().isoformat() + "Z"
|
||||
_PROJECTS[project_id] = {
|
||||
"id": project_id,
|
||||
"created_at": now,
|
||||
"spec": spec_data,
|
||||
"svg": svg,
|
||||
}
|
||||
return {"id": project_id, "created_at": now, "svg": svg, "spec": spec_data}
|
||||
|
||||
|
||||
@router.get("/projects")
|
||||
def packaging_projects(limit: int = Query(default=30, ge=1, le=200)) -> dict[str, Any]:
|
||||
items = sorted(_PROJECTS.values(), key=lambda x: x["created_at"], reverse=True)[:limit]
|
||||
return {
|
||||
"items": [{"id": p["id"], "created_at": p["created_at"], "spec": p["spec"]} for p in items],
|
||||
"count": len(items),
|
||||
}
|
||||
|
||||
|
||||
@router.get("/download/{project_id}")
|
||||
def packaging_download(project_id: str, format: str = Query(default="svg", pattern="^(svg|png|pdf)$")):
|
||||
project = _PROJECTS.get(project_id)
|
||||
if not project:
|
||||
raise HTTPException(status_code=404, detail="Packaging project not found")
|
||||
|
||||
svg = project["svg"]
|
||||
filename = f"foodlinkk-packaging-{project_id[:8]}.{format}"
|
||||
if format == "svg":
|
||||
return Response(
|
||||
content=svg.encode("utf-8"),
|
||||
media_type="image/svg+xml",
|
||||
headers={"Content-Disposition": f'attachment; filename="{filename}"'},
|
||||
)
|
||||
if format == "png":
|
||||
return Response(
|
||||
content=svg_to_png_bytes(svg),
|
||||
media_type="image/png",
|
||||
headers={"Content-Disposition": f'attachment; filename="{filename}"'},
|
||||
)
|
||||
return Response(
|
||||
content=svg_to_pdf_bytes(svg),
|
||||
media_type="application/pdf",
|
||||
headers={"Content-Disposition": f'attachment; filename="{filename}"'},
|
||||
)
|
||||
Reference in New Issue
Block a user