修改部分参数

Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
2026-05-08 01:16:40 +08:00
parent 40b8cc8023
commit a26f7214f9
30 changed files with 341 additions and 3206 deletions

View File

@@ -8,7 +8,7 @@ def get_all_engines():
PrusaSlicerEngine()
]
def get_slicer_engine(engine_name="cura"):
def get_slicer_engine(engine_name="prusa", print_config_folder=None):
"""
Factory function to retrieve the requested slicing engine instance.
Valid names: 'cura', 'prusa_slicer'
@@ -16,9 +16,9 @@ def get_slicer_engine(engine_name="cura"):
engine_name = engine_name.lower().strip()
if engine_name in ['cura', 'cura_engine', 'curaengine']:
return CuraEngine()
return CuraEngine(print_config_folder)
elif engine_name in ['prusa', 'prusa_slicer', 'prusaslicer']:
return PrusaSlicerEngine()
return PrusaSlicerEngine(print_config_folder)
else:
# Default fallback
return CuraEngine()
return PrusaSlicerEngine(print_config_folder)

View File

@@ -6,11 +6,12 @@ import configparser
from app.utils.conf_parse import ConfParse
class CuraEngine:
def __init__(self):
def __init__(self, print_config_folder=None):
self.name = "cura"
self.display_name = "UltiMaker Cura"
self.is_available = self._check_available()
self.print_config_folder = os.path.join(print_config_folder, "cura_engine") if print_config_folder else None
def _check_available(self):
try:
# check if CuraEngine is available in PATH
@@ -21,13 +22,6 @@ class CuraEngine:
self.display_name = "UltiMaker Cura"
self.is_available = self._check_available()
def _check_available(self):
try:
# check if CuraEngine is available in PATH
result = subprocess.run(["CuraEngine", "help"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
return result.returncode == 0 or b"Usage:" in result.stdout or b"Usage:" in result.stderr
except (FileNotFoundError, OSError):
return False
def slice(self, app, stl_filepath, gcode_filepath, **kwargs):
"""
@@ -41,23 +35,28 @@ class CuraEngine:
tmp_def_path = None
try:
base_config_path = os.path.abspath(os.path.join(app.root_path, '..', 'print_config'))
print_config_path = os.path.join(base_config_path, 'cura_engine')
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, 'quality')
variants_path = os.path.join(print_config_path, 'variants')
printers_path = os.path.join(self.print_config_folder, 'printers') if self.print_config_folder else None
extruders_path = os.path.join(self.print_config_folder, 'extruders') if self.print_config_folder else None
materials_path = os.path.join(self.print_config_folder, 'materials') if self.print_config_folder else None
presets_path = os.path.join(self.print_config_folder, 'quality') if self.print_config_folder else None
variants_path = os.path.join(self.print_config_folder, 'variants') if self.print_config_folder else None
env = os.environ.copy()
env["CURA_ENGINE_SEARCH_PATH"] = f"{printers_path}:{extruders_path}:{materials_path}:{presets_path}:{variants_path}"
from app.models import SystemConfig
db_printer = SystemConfig.query.filter_by(key='default_printer').first()
p_val = db_printer.value if db_printer and db_printer.value else 'creality_ender3v3se.def.json'
if not p_val.endswith('.def.json'): p_val += '.def.json'
def_files = [
os.path.join(printers_path, "fdmprinter.def.json"),
os.path.join(printers_path, "fdmextruder.def.json"),
os.path.join(printers_path, "creality_base.def.json"),
os.path.join(printers_path, "creality_ender3v3se.def.json")
os.path.join(printers_path, p_val)
]
inst_files_list = []
quality_type = None
@@ -82,19 +81,19 @@ class CuraEngine:
if os.path.exists(m_path): inst_files_list.append(m_path)
if variant_type:
variant_d = variant_type.split("mm")[0]
v_path = os.path.join(variants_path, "creality", f"creality_ender3v3se_{variant_d}.inst.cfg")
v_path = os.path.join(variants_path, "creality", f"{p_val.replace('.def.json', '')}_{variant_d}.inst.cfg")
if os.path.exists(v_path): inst_files_list.append(v_path)
if support_pattern == 'tree':
t_path = os.path.join(print_config_path, 'supports', 'tree.inst.cfg')
if os.path.exists(t_path): inst_files_list.append(t_path)
t_path = os.path.join(self.print_config_folder, 'supports', 'tree.inst.cfg') if self.print_config_folder else None
if t_path and os.path.exists(t_path): inst_files_list.append(t_path)
elif support_pattern and support_pattern != 'false':
n_path = os.path.join(print_config_path, 'supports', 'normal.inst.cfg')
if os.path.exists(n_path): inst_files_list.append(n_path)
n_path = os.path.join(self.print_config_folder, 'supports', 'normal.inst.cfg') if self.print_config_folder else None
if n_path and os.path.exists(n_path): inst_files_list.append(n_path)
if quality_preset and quality_type:
g_path = os.path.join(presets_path, 'creality', 'globals', f"{quality_type}.inst.cfg")
if os.path.exists(g_path): inst_files_list.append(g_path)
g_path = os.path.join(self.print_config_folder, 'creality', 'globals', f"{quality_type}.inst.cfg") if self.print_config_folder else None
if g_path and os.path.exists(g_path): inst_files_list.append(g_path)
if quality_preset and preset_path and os.path.exists(preset_path):
inst_files_list.append(preset_path)
@@ -192,10 +191,10 @@ class CuraEngine:
except Exception as e:
app.logger.error(f"Failed to delete temp JSON config {tmp_def_path}: {e}")
def get_quality_presets(self, app):
def get_quality_presets(self):
try:
path = os.path.join(app.root_path, '..', 'print_config', 'cura_engine', 'quality', 'creality', 'presets')
if not os.path.exists(path): return []
path = os.path.join(self.print_config_folder, 'quality', 'creality', 'presets') if self.print_config_folder else None
if not path or not os.path.exists(path): return []
files = [f for f in os.listdir(path) if f.endswith('.inst.cfg')]
presets = []
for f in files:
@@ -205,7 +204,7 @@ class CuraEngine:
except:
return []
def get_support_patterns(self, app):
def get_support_patterns(self):
return [
{'id': 'tree', 'name': 'Tree'},
{'id': 'lines', 'name': 'Lines'},
@@ -219,10 +218,10 @@ class CuraEngine:
{'id': 'octagon', 'name': 'Octagon'}
]
def get_materials(self, app):
def get_materials(self):
try:
path = os.path.join(app.root_path, '..', 'print_config', 'cura_engine', 'materials')
if not os.path.exists(path): return []
path = os.path.join(self.print_config_folder, 'materials') if self.print_config_folder else None
if not path or not os.path.exists(path): return []
files = [f for f in os.listdir(path) if f.endswith('.inst.cfg')]
materials = []
for f in files:
@@ -231,3 +230,33 @@ class CuraEngine:
return materials
except:
return []
def get_bed_dimensions(self):
from app.models import SystemConfig
import json
try:
db_printer = SystemConfig.query.filter_by(key='default_printer').first()
p_val = db_printer.value if db_printer and db_printer.value else 'creality_ender3v3se.def.json'
if not p_val.endswith('.def.json'): p_val += '.def.json'
path = os.path.join(self.print_config_folder, 'printers', p_val)
with open(path, 'r', encoding='utf-8') as f:
data = json.load(f)
w = data['overrides']['machine_width']['default_value']
h = data['overrides']['machine_depth']['default_value']
hd = data['overrides']['machine_height']['default_value']
return w, h, hd
except:
pass
return 220, 220, 250
def get_all_printers(self):
try:
path = os.path.join(self.print_config_folder, 'printers') if self.print_config_folder else None
if not path or not os.path.exists(path): return []
files = [f for f in os.listdir(path) if f.endswith('.inst.cfg')]
printers = []
for f in files:
printers.append({'id': f, 'name': f.replace('..def.json', '').replace('generic_', 'Generic ').replace('_', ' ').title()})
printers.sort(key=lambda x: x['name'])
return printers
except:
return []

View File

@@ -4,11 +4,12 @@ import configparser
import uuid
class PrusaSlicerEngine:
def __init__(self):
def __init__(self, print_config_folder=None):
self.name = "prusa_slicer"
self.display_name = "PrusaSlicer"
self.is_available = self._check_available()
self.print_config_folder = os.path.join(print_config_folder, 'prusa_slicer') if print_config_folder else None
def _check_available(self):
try:
result = subprocess.run(["prusa-slicer", "--help"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
@@ -47,18 +48,22 @@ class PrusaSlicerEngine:
# print(support_pattern)
all_configs = {}
printer_ini = os.path.join(app.root_path, '..', 'print_config', 'prusa_slicer', 'printers', 'Ender3_V3_SE.ini')
if os.path.exists(printer_ini):
from app.models import SystemConfig
db_printer = SystemConfig.query.filter_by(key='default_printer').first()
p_val = db_printer.value if db_printer and db_printer.value else 'Ender3_V3_SE'
if not p_val.endswith('.ini'): p_val += '.ini'
printer_ini = os.path.join(self.print_config_folder, 'printers', p_val) if self.print_config_folder else None
if printer_ini and os.path.exists(printer_ini):
self.add_ini_keys(printer_ini, 'settings', all_configs)
if quality_preset:
q_ini = os.path.join(app.root_path, '..', 'print_config', 'prusa_slicer', 'quality', f"{quality_preset}.ini")
if os.path.exists(q_ini):
q_ini = os.path.join(self.print_config_folder, 'quality', f"{quality_preset}.ini") if self.print_config_folder else None
if q_ini and os.path.exists(q_ini):
self.add_ini_keys(q_ini, 'settings', all_configs)
if material_preset:
m_ini = os.path.join(app.root_path, '..', 'print_config', 'prusa_slicer', 'materials', f"{material_preset}.ini")
if os.path.exists(m_ini):
m_ini = os.path.join(self.print_config_folder, 'materials', f"{material_preset}.ini") if self.print_config_folder else None
if m_ini and os.path.exists(m_ini):
self.add_ini_keys(m_ini, 'settings', all_configs)
if infill_density is not None:
@@ -69,20 +74,19 @@ class PrusaSlicerEngine:
if support_enable == 'buildplate':
command.append("--support-material-buildplate-only")
# PrusaSlicer equivalent for tree supports => organic
support_pattern_ini = os.path.join(app.root_path, '..', 'print_config', 'prusa_slicer', 'supports', f'{support_pattern}.ini')
if os.path.exists(support_pattern_ini):
support_pattern_ini = os.path.join(self.print_config_folder, 'supports', f'{support_pattern}.ini') if self.print_config_folder else None
if support_pattern_ini and os.path.exists(support_pattern_ini):
self.add_ini_keys(support_pattern_ini, 'settings', all_configs)
else:
# Load the default no_support.ini if no support is enabled
no_support_ini = os.path.join(app.root_path, '..', 'print_config', 'prusa_slicer', 'supports', 'no_support.ini')
if os.path.exists(no_support_ini):
no_support_ini = os.path.join(self.print_config_folder, 'supports', 'no_support.ini') if self.print_config_folder else None
if no_support_ini and os.path.exists(no_support_ini):
self.add_ini_keys(no_support_ini, 'settings', all_configs)
else:
all_configs['support_material'] = '0'
tmp_ini_filename = f"tmp_{uuid.uuid4().hex}.ini"
tmp_ini_path = os.path.join(app.config['UPLOAD_FOLDER'], tmp_ini_filename)
print(f'****tmp_ini_path: {tmp_ini_path}')
with open(tmp_ini_path, 'w') as f:
for key, value in all_configs.items():
f.write(f"{key} = {value}\n")
@@ -108,11 +112,11 @@ class PrusaSlicerEngine:
app.logger.error(f"PrusaSlicer Exception: {e}")
return False, str(e)
def get_quality_presets(self, app):
all_files = [f for f in os.listdir(os.path.join(app.root_path, '..', 'print_config', 'prusa_slicer',"quality")) if f.endswith('.ini')]
def get_quality_presets(self):
all_files = [f for f in os.listdir(os.path.join(self.print_config_folder, "quality")) if f.endswith('.ini')] if self.print_config_folder else []
quality_presets = []
for file in all_files:
with open(os.path.join(app.root_path, '..', 'print_config', 'prusa_slicer', "quality", file), 'r') as f:
with open(os.path.join(self.print_config_folder, "quality", file), 'r') as f:
config = configparser.ConfigParser()
config.read_file(f)
if 'metadata' in config:
@@ -122,11 +126,11 @@ class PrusaSlicerEngine:
})
return quality_presets
def get_support_patterns(self, app):
all_files = [f for f in os.listdir(os.path.join(app.root_path, '..', 'print_config', 'prusa_slicer',"supports")) if f.endswith('.ini')]
def get_support_patterns(self):
all_files = [f for f in os.listdir(os.path.join(self.print_config_folder,"supports")) if f.endswith('.ini')] if self.print_config_folder else []
support_presets = []
for file in all_files:
with open(os.path.join(app.root_path, '..', 'print_config', 'prusa_slicer', "supports", file), 'r') as f:
with open(os.path.join(self.print_config_folder, "supports", file), 'r') as f:
config = configparser.ConfigParser()
config.read_file(f)
if 'metadata' in config:
@@ -136,15 +140,54 @@ class PrusaSlicerEngine:
})
return support_presets
def get_materials(self, app):
def get_materials(self):
all_files = [f for f in os.listdir(os.path.join(self.print_config_folder, "materials")) if f.endswith('.ini')] if self.print_config_folder else []
materials = []
for file in all_files:
with open(os.path.join(self.print_config_folder, "materials", file), 'r') as f:
config = configparser.ConfigParser()
config.read_file(f)
if 'metadata' in config:
materials.append({
'id': file.replace('.ini', ''),
'name': config['metadata'].get('show_name', file.replace('.ini', '').replace('_', ' '))
})
return materials
def get_bed_dimensions(self):
from app.models import SystemConfig
import configparser
try:
path = os.path.join(app.root_path, '..', 'print_config', 'prusa_slicer', 'materials')
if not os.path.exists(path): return []
files = [f for f in os.listdir(path) if f.endswith('.ini')]
materials = []
for f in files:
materials.append({'id': f.replace('.ini', ''), 'name': f.replace('.ini', '').replace('_', ' ')})
materials.sort(key=lambda x: x['name'])
return materials
db_printer = SystemConfig.query.filter_by(key='default_printer').first()
p_val = db_printer.value if db_printer and db_printer.value else 'Ender3_V3_SE.ini'
if not p_val.endswith('.ini'): p_val += '.ini'
path = os.path.join(self.print_config_folder, 'printers', p_val)
config = configparser.ConfigParser()
config.read(path)
if 'settings' in config and 'bed_shape' in config['settings']:
# format is usually like 0x0,220x0,220x220,0x220
coords = config['settings']['bed_shape'].split(',')
max_x = max([float(c.split('x')[0]) for c in coords])
max_y = max([float(c.split('x')[1]) for c in coords])
# height
h = 250
if 'max_print_height' in config['settings']:
h = float(config['settings']['max_print_height'])
return max_x, max_y, h
except:
return []
pass
return 220, 220, 250
def get_all_printers(self):
all_files = [f for f in os.listdir(os.path.join(self.print_config_folder, "printers")) if f.endswith('.ini')] if self.print_config_folder else []
printers = []
for file in all_files:
with open(os.path.join(self.print_config_folder, "printers", file), 'r') as f:
config = configparser.ConfigParser()
config.read_file(f)
if 'metadata' in config:
printers.append({
'id': file.replace('.ini', ''),
'name': config['metadata'].get('show_name', file.replace('.ini', '').replace('_', ' '))
})
return printers

View File

@@ -6,7 +6,7 @@ from app.utils.conf_parse import ConfParse
import json
import uuid
import configparser
from app.utils.slice_engines import get_slicer_engine
import os
@@ -44,17 +44,15 @@ def slice_stl_task(file_id, stl_filepath, quality_preset=None, material_preset=N
# 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
# Optionally fetch the preferred engine from db conf or just default to prusa
# For now default to prusa 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"
engine_name = conf_engine.value if conf_engine and conf_engine.value else "prusa"
db.session.remove()
slicer = get_slicer_engine(engine_name)
slicer = get_slicer_engine(engine_name,app.config['PRINT_CONFIG_FOLDER'])
success, err_msg = slicer.slice(
app=app,