import logging from pathlib import Path from sqlalchemy.orm import Session from app.models.stl_cache import StlCache logger = logging.getLogger("pops") _ANALYSABLE = {".stl", ".3mf"} def analyse(filename: str, db: Session) -> StlCache | None: """Return cached analysis for filename, computing it if missing.""" existing = db.query(StlCache).filter(StlCache.filename == filename).first() if existing: return existing from app.stl import get_stl_dir filepath = get_stl_dir() / filename if Path(filename).suffix.lower() not in _ANALYSABLE or not filepath.exists(): return None try: import trimesh mesh = trimesh.load(str(filepath), force="mesh") extents = mesh.extents # [size_x, size_y, size_z] in mm volume_mm3 = abs(mesh.volume) # mm³ (negative for inverted normals) entry = StlCache( filename=filename, cube_x=round(float(extents[0]), 2), cube_y=round(float(extents[1]), 2), cube_z=round(float(extents[2]), 2), volume_ccm=round(volume_mm3 / 1000, 3), ) db.add(entry) db.commit() return entry except Exception: logger.exception("STL analysis failed for %s", filename) return None def get_cache_map(filenames: list[str], db: Session) -> dict[str, StlCache]: """Bulk-fetch cached entries for a list of filenames.""" rows = db.query(StlCache).filter(StlCache.filename.in_(filenames)).all() return {r.filename: r for r in rows}