slicer_utils.py 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
  1. import subprocess
  2. import os
  3. import re
  4. import logging
  5. import shutil
  6. from config import SLICER_PATH, SLICER_CONFIG
  7. logger = logging.getLogger(__name__)
  8. def slice_model(file_path: str):
  9. """
  10. Runs PrusaSlicer CLI to extract the EXACT 3D volume of the STL/OBJ file using --info.
  11. Returns a dict with estimated print_time (str) and filament_used (g).
  12. """
  13. if not shutil.which(SLICER_PATH):
  14. logger.error(f"Slicer not found at {SLICER_PATH}")
  15. return None
  16. cmd = [
  17. SLICER_PATH,
  18. "--info",
  19. file_path
  20. ]
  21. try:
  22. # Run info extraction (very fast, no full G-code generation)
  23. process = subprocess.run(cmd, capture_output=True, text=True, check=True)
  24. content = process.stdout
  25. # Regex to find volume and sizes
  26. volume_match = re.search(r"volume\s*=\s*([\d\.]+)", content)
  27. size_x_match = re.search(r"size_x\s*=\s*([\d\.]+)", content)
  28. size_y_match = re.search(r"size_y\s*=\s*([\d\.]+)", content)
  29. size_z_match = re.search(r"size_z\s*=\s*([\d\.]+)", content)
  30. if not volume_match:
  31. logger.error("Volume could not be parsed from PrusaSlicer output.")
  32. return None
  33. volume_mm3 = float(volume_match.group(1))
  34. volume_cm3 = volume_mm3 / 1000.0
  35. dimensions_str = ""
  36. if size_x_match and size_y_match and size_z_match:
  37. x = round(float(size_x_match.group(1)), 1)
  38. y = round(float(size_y_match.group(1)), 1)
  39. z = round(float(size_z_match.group(1)), 1)
  40. dimensions_str = f"{x} x {y} x {z} mm"
  41. # Estimate weight assuming average density of PLA/PETG (~1.25 g/cm3)
  42. filament_g = round(volume_cm3 * 1.25, 2)
  43. # Estimate printing time assuming average volumetric flow rate of ~10 mm3/s
  44. time_seconds = int(volume_mm3 / 10.0)
  45. hours = time_seconds // 3600
  46. minutes = (time_seconds % 3600) // 60
  47. if hours > 0:
  48. time_str = f"{hours}h {minutes}m"
  49. else:
  50. time_str = f"{minutes}m"
  51. return {
  52. "filament_g": filament_g,
  53. "print_time_str": time_str,
  54. "dimensions": dimensions_str,
  55. "success": True
  56. }
  57. except subprocess.CalledProcessError as e:
  58. logger.error(f"Slicing info error: {e.stderr}")
  59. return None
  60. except Exception as e:
  61. logger.error(f"General error in slice_model: {e}")
  62. return None