Files
AIO_3D_Print_Web_Platform/app/utils/tasks.py

174 lines
6.3 KiB
Python

from huey import SqliteHuey
import subprocess
import os
from app.models import db, PrintFile, SystemConfig
from app.utils.conf_parse import ConfParse
import json
import uuid
import configparser
import os
# Ensure instance directory exists
instance_dir = os.path.join(os.path.dirname(os.path.dirname(__file__)), '..', 'instance')
os.makedirs(instance_dir, exist_ok=True)
huey_db_path = os.path.join(instance_dir, 'huey_queue.db')
huey = SqliteHuey(filename=huey_db_path)
def get_gcode_dir(app):
with app.app_context():
conf = SystemConfig.query.filter_by(key='gcode_upload_folder').first()
if conf and conf.value and os.path.exists(conf.value):
return conf.value
return app.config['UPLOAD_FOLDER']
@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(get_gcode_dir(app), 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()
from app.utils.slice_engines import get_slicer_engine
try:
# Optionally fetch the preferred engine from db conf or just default to cura
# For now default to cura or whichever is passed via kwargs if implemented later
conf_engine = SystemConfig.query.filter_by(key='slicer_engine').first()
engine_name = conf_engine.value if conf_engine and conf_engine.value else "cura"
db.session.remove()
slicer = get_slicer_engine(engine_name)
success, err_msg = slicer.slice(
app=app,
stl_filepath=stl_filepath,
gcode_filepath=gcode_filepath,
quality_preset=quality_preset,
infill_density=infill_density,
support_enable=support_enable,
support_pattern=support_pattern
)
# Re-fetch print_file and update status
print_file = PrintFile.query.get(file_id)
if not print_file:
return
if success:
print_file.status = 'sliced'
else:
print_file.status = 'failed'
app.logger.error(f"Slicing Task Failed: {err_msg}")
except Exception as e:
print_file = PrintFile.query.get(file_id)
if print_file:
print_file.status = 'failed'
app.logger.error(f"Subprocess Exception: {e}")
finally:
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 app.models import PrintFile, db
print_file = PrintFile.query.get(file_id)
if not print_file:
return
db.session.remove()
try:
from app.utils.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()
@huey.task()
def simplify_stl_task(file_id, filepath):
from app import create_app
app = create_app()
with app.app_context():
from app.models import PrintFile, SystemConfig, db
import os
from app.utils.stl_simplifier import simplify_stl
print_file = PrintFile.query.get(file_id)
if not print_file:
return
try:
file_size_mb = os.path.getsize(filepath) / (1024 * 1024)
configs = {c.key: c.value for c in SystemConfig.query.all()}
skip_size = float(configs.get('proxy_skip_size_mb', '5.0'))
proxy_path = filepath + '.proxy.stl'
if file_size_mb <= skip_size:
# File is small enough, no proxy needed
print_file.status = 'uploaded'
db.session.commit()
return
# Aim for approx 7.5 MB for the proxy
target_mb = 7.5
keep_ratio = target_mb / file_size_mb
if keep_ratio > 1.0:
keep_ratio = 1.0
elif keep_ratio < 0.01:
keep_ratio = 0.01
app.logger.info(f"Simplifying {filepath}... Size: {file_size_mb:.2f}MB, Target Ratio: {keep_ratio:.3f}")
simplify_stl(filepath, proxy_path, keep_ratio=keep_ratio)
except Exception as e:
app.logger.error(f"Simplify task error: {e}")
# Update status to uploaded regardless of success or failure of proxy generation
# So the user can still slice or download it
print_file = PrintFile.query.get(file_id)
if print_file:
print_file.status = 'uploaded'
db.session.commit()
db.session.remove()