perf: dual queue, GLB caching, WebP output, persistent BVH

Task 4: Dual render queue
- render-worker: heavy (asset_pipeline, concurrency=1) — HQ 2048x2048, animations
- render-worker-light: light (asset_pipeline_light, concurrency=2) — thumbnails, <=1024
- Thumbnails routed to light queue automatically
- Order line renders routed by resolution at dispatch time

Task 5: GLB caching (skip re-tessellation)
- Before tessellating, check if gltf_geometry MediaAsset exists for the cad_file_id
- If found, copy to expected path — render_blender.py finds it and skips tessellation
- Saves 7-11s per re-render of the same product

Task 6: WebP output format
- New 'webp' option in output_format (OutputType admin)
- Blender renders PNG intermediate, Pillow converts to WebP (quality=90, method=4)
- 50-70% smaller files with no visible quality loss
- Correct MIME type (image/webp) in MediaAsset

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-15 12:07:12 +01:00
parent ffe3eebfca
commit 5a148554c0
5 changed files with 132 additions and 11 deletions
+16 -2
View File
@@ -807,7 +807,21 @@ def _generate_thumbnail(
def _finalise_image(src: Path, dst: Path) -> Path | None:
"""Move src image to dst, always as PNG."""
"""Move src image to dst. When dst has a .webp suffix, convert via Pillow
(quality=90, method=4) for 50-70 % smaller files. Otherwise output PNG."""
if dst.suffix.lower() == ".webp":
try:
from PIL import Image
img = Image.open(str(src))
out = dst.with_suffix(".webp")
img.save(str(out), "WebP", quality=90, method=4)
src.unlink(missing_ok=True)
return out
except Exception:
logger.warning("WebP conversion failed — falling back to PNG")
out = dst.with_suffix(".png")
src.rename(out)
return out
out = dst.with_suffix(".png")
src.rename(out)
return out
@@ -927,7 +941,7 @@ def render_to_file(
settings = _get_all_settings()
renderer = settings["thumbnail_renderer"]
fmt = out.suffix.lstrip(".") or settings.get("thumbnail_format", "jpg")
if fmt not in ("jpg", "png"):
if fmt not in ("jpg", "png", "webp"):
fmt = "jpg"
# Temporary PNG for service renderers