from huey import SqliteHuey import subprocess import os from .models import db, PrintFile, SystemConfig huey = SqliteHuey(filename='huey_queue.db') import configparser @huey.task() def slice_stl_task(file_id, stl_filepath, quality_preset=None, infill_density=None, support_enable=None, support_pattern=None, delete_stl=False): # This is run by the Huey worker # We need to create an app context to interact with the database from app import create_app app = create_app() with app.app_context(): print_file = PrintFile.query.get(file_id) if not print_file: return # Cache variables and commit slicing status gcode_filename = print_file.filename.rsplit('.', 1)[0] + '.gcode' gcode_filepath = os.path.join(app.config['UPLOAD_FOLDER'], gcode_filename) print_file.status = 'slicing' db.session.commit() # Remove DB session to avoid locking the sqlite db during long slicing operations db.session.remove() try: # Create Cura engine options # use our local minimal configurations detached from the entire Cura framework print_config_path = os.path.abspath(os.path.join(app.root_path, '..', 'print_config')) printers_path = os.path.join(print_config_path, 'printers') extruders_path = os.path.join(print_config_path, 'extruders') materials_path = os.path.join(print_config_path, 'materials') presets_path = os.path.join(print_config_path, 'presets') env = os.environ.copy() env["CURA_ENGINE_SEARCH_PATH"] = f"{printers_path}:{extruders_path}:{materials_path}:{presets_path}" command = [ "CuraEngine", "slice", "-j", os.path.join(printers_path, "creality_ender3v3se.def.json") ] # Apply quality presets if any if quality_preset: config = configparser.ConfigParser() preset_path = os.path.join(presets_path, 'creality', 'base', quality_preset) if os.path.exists(preset_path): config.read(preset_path) if config.has_section('values'): for key, val in config.items('values'): command.extend(['-s', f"{key}={val}"]) if infill_density is not None: command.extend(['-s', f"infill_sparse_density={infill_density}"]) command.extend(['-s', f"infill_line_distance={100 / int(infill_density) if int(infill_density) > 0 else 9999}"]) if support_enable is not None: command.extend(['-s', f"support_enable={'true' if support_enable == 'true' or support_enable == 'buildplate' else 'false'}"]) command.extend(['-s', f"support_type={'buildplate' if support_enable == 'buildplate' else 'everywhere'}"]) if support_pattern == 'tree': command.extend(['-s', 'support_structure=tree']) command.extend(['-s', 'support_tree_enable=true']) elif support_pattern and support_pattern != 'false': command.extend(['-s', 'support_structure=normal']) command.extend(['-s', f'support_pattern={support_pattern}']) command.extend([ "-l", stl_filepath, "-o", gcode_filepath ]) app.logger.info(f"Running command: {' '.join(command)}") process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env) stdout, stderr = process.communicate() # Re-fetch print_file and update status print_file = PrintFile.query.get(file_id) if not print_file: return if process.returncode == 0: print_file.status = 'sliced' else: print_file.status = 'failed' app.logger.error(f"CuraEngine Error: {stderr.decode()}") except Exception as e: # Re-fetch in case of exception print_file = PrintFile.query.get(file_id) if print_file: print_file.status = 'failed' app.logger.error(f"Subprocess Exception: {e}") if delete_stl and os.path.exists(stl_filepath): try: os.remove(stl_filepath) except Exception as e: app.logger.error(f"Failed to delete temp STL {stl_filepath}: {e}") db.session.commit() db.session.remove() @huey.task() def merge_and_slice_task(file_id, inputs, merged_filepath, quality_preset=None, infill_density=None, support_enable=None, support_pattern=None, delete_stl=False): from app import create_app app = create_app() with app.app_context(): from .models import PrintFile, db print_file = PrintFile.query.get(file_id) if not print_file: return db.session.remove() try: from stl_merger import merge_stls merge_stls(inputs, merged_filepath) # Now trigger the regular slicing task # We can just call the slicing logic or enqueue it slice_stl_task(file_id, merged_filepath, quality_preset, infill_density, support_enable, support_pattern, delete_stl=delete_stl) except Exception as e: print_file = PrintFile.query.get(file_id) if print_file: print_file.status = 'failed' db.session.commit() app.logger.error(f"Merge Exception: {e}") finally: db.session.remove()