补充遗漏翻译,新增启动脚本,整理import

This commit is contained in:
2026-05-09 16:42:17 +08:00
parent e542c482d7
commit 75ceec0798
16 changed files with 152 additions and 103 deletions

View File

@@ -260,5 +260,14 @@
"No active sessions found.": "Keine aktiven Sitzungen gefunden.", "No active sessions found.": "Keine aktiven Sitzungen gefunden.",
"Please login to view the webcam stream.": "Bitte melden Sie sich an, um die Live-Kamera zu sehen.", "Please login to view the webcam stream.": "Bitte melden Sie sich an, um die Live-Kamera zu sehen.",
"Remember Me": "Erinnere dich an mich", "Remember Me": "Erinnere dich an mich",
"Merge Guest Data": "Gästendaten zusammenführen" "Merge Guest Data": "Gästendaten zusammenführen",
"Main configuration for the printer dimensions, limits and base profiles.": "Hauptkonfiguration für die Druckerabmessungen, -grenzen und Basisprofile.",
"API Keys Management": "API-Schlüsselverwaltung",
"Create New API Key": "Neuen API-Schlüssel erstellen",
"Key Name": "Schlüsselname",
"Generate Key": "Schlüssel generieren",
"Are you sure you want to delete this API Key?": "Sind Sie sicher, dass Sie diesen API-Schlüssel löschen möchten?",
"API Key Name": "API-Schlüsselname",
"No API keys found.": "Keine API-Schlüssel gefunden.",
"API Keys": "API-Schlüssel"
} }

View File

@@ -260,5 +260,14 @@
"No active sessions found.": "No active sessions found.", "No active sessions found.": "No active sessions found.",
"Please login to view the webcam stream.": "Please login to view the webcam stream.", "Please login to view the webcam stream.": "Please login to view the webcam stream.",
"Remember Me": "Remember Me", "Remember Me": "Remember Me",
"Merge Guest Data": "Merge Guest Data" "Merge Guest Data": "Merge Guest Data",
"Main configuration for the printer dimensions, limits and base profiles.": "Main configuration for the printer dimensions, limits and base profiles.",
"API Keys Management": "API Keys Management",
"Create New API Key": "Create New API Key",
"Key Name": "Key Name",
"Generate Key": "Generate Key",
"Are you sure you want to delete this API Key?": "Are you sure you want to delete this API Key?",
"API Key Name": "API Key Name",
"No API keys found.": "No API keys found.",
"API Keys": "API Keys"
} }

View File

@@ -260,5 +260,14 @@
"No active sessions found.": "未找到活跃的会话。", "No active sessions found.": "未找到活跃的会话。",
"Please login to view the webcam stream.": "请登录以查看实时摄像头。", "Please login to view the webcam stream.": "请登录以查看实时摄像头。",
"Remember Me": "记住我", "Remember Me": "记住我",
"Merge Guest Data": "合并访客数据" "Merge Guest Data": "合并访客数据",
"Main configuration for the printer dimensions, limits and base profiles.": "打印机尺寸、限制和基础配置的主要配置。",
"API Keys Management": "API 密钥管理",
"Create New API Key": "创建新的 API 密钥",
"Key Name": "密钥名称",
"Generate Key": "生成密钥",
"Are you sure you want to delete this API Key?": "您确定要删除此 API 密钥吗?",
"API Key Name": "API 密钥名称",
"No API keys found.": "未找到 API 密钥。",
"API Keys": "API 密钥"
} }

View File

@@ -1,17 +1,16 @@
import json import json
import trimesh
import uuid import uuid
import os import os
import configparser import configparser
import secrets
from datetime import datetime from datetime import datetime
from flask import Blueprint, render_template, request, redirect, url_for, flash, current_app, session, make_response, send_file, abort, jsonify from flask import Blueprint, render_template, request, redirect, url_for, flash, current_app, session, make_response, send_file, abort, jsonify
from flask_login import login_user, logout_user, login_required, current_user from flask_login import login_user, logout_user, login_required, current_user
from werkzeug.security import generate_password_hash, check_password_hash from werkzeug.security import generate_password_hash, check_password_hash
from werkzeug.utils import secure_filename from werkzeug.utils import secure_filename
from app.models import db, User, PrintFile, SystemConfig from app.models import db, User, PrintFile, SystemConfig, ApiKey
from app.utils.tasks import merge_and_slice_task, slice_stl_task, simplify_stl_task from app.utils.tasks import merge_and_slice_task, slice_stl_task, simplify_stl_task
from app import i18n_dict from app import i18n_dict
# import trimesh.repair
from app.utils.stl_simplifier import simplify_stl from app.utils.stl_simplifier import simplify_stl
from app.utils.slice_engines import get_all_engines from app.utils.slice_engines import get_all_engines
@@ -194,14 +193,11 @@ def delete_user(user_id):
@admin_bp.route('/api_keys') @admin_bp.route('/api_keys')
def api_keys(): def api_keys():
from app.models import ApiKey
keys = ApiKey.query.order_by(ApiKey.created_at.desc()).all() keys = ApiKey.query.order_by(ApiKey.created_at.desc()).all()
return render_template('admin/api_keys.html', keys=keys) return render_template('admin/api_keys.html', keys=keys)
@admin_bp.route('/api_key/add', methods=['POST']) @admin_bp.route('/api_key/add', methods=['POST'])
def add_api_key(): def add_api_key():
from app.models import ApiKey
import secrets
name = request.form.get('name') name = request.form.get('name')
if not name: if not name:
flash("Name is required", "danger") flash("Name is required", "danger")
@@ -216,7 +212,6 @@ def add_api_key():
@admin_bp.route('/api_key/<int:key_id>/delete', methods=['POST']) @admin_bp.route('/api_key/<int:key_id>/delete', methods=['POST'])
def delete_api_key(key_id): def delete_api_key(key_id):
from app.models import ApiKey
key = ApiKey.query.get_or_404(key_id) key = ApiKey.query.get_or_404(key_id)
db.session.delete(key) db.session.delete(key)
db.session.commit() db.session.commit()

View File

@@ -1,5 +1,4 @@
import json import json
import trimesh
import uuid import uuid
import os import os
import configparser import configparser
@@ -8,11 +7,12 @@ from flask import Blueprint, render_template, request, redirect, url_for, flash,
from flask_login import login_user, logout_user, login_required, current_user from flask_login import login_user, logout_user, login_required, current_user
from werkzeug.security import generate_password_hash, check_password_hash from werkzeug.security import generate_password_hash, check_password_hash
from werkzeug.utils import secure_filename from werkzeug.utils import secure_filename
from app.models import db, User, PrintFile, SystemConfig from app.models import db, User, PrintFile, SystemConfig, UserSession
from app.utils.tasks import merge_and_slice_task, slice_stl_task, simplify_stl_task from app.utils.tasks import merge_and_slice_task, slice_stl_task, simplify_stl_task
from app import i18n_dict from app import i18n_dict
# import trimesh.repair
from app.utils.stl_simplifier import simplify_stl from app.utils.stl_simplifier import simplify_stl
from app.routes.main_routes import get_quota_info
from app.routes.admin_routes import get_gcode_dir
main_bp = Blueprint('main', __name__) main_bp = Blueprint('main', __name__)
@@ -36,8 +36,6 @@ def login():
if user and check_password_hash(user.password_hash, password): if user and check_password_hash(user.password_hash, password):
login_user(user, remember=remember) login_user(user, remember=remember)
from app.models import UserSession
session_token = str(uuid.uuid4()) session_token = str(uuid.uuid4())
# 尝试获取反向代理传递的真实 IP # 尝试获取反向代理传递的真实 IP
client_ip = request.headers.get('X-Real-IP') client_ip = request.headers.get('X-Real-IP')
@@ -59,7 +57,6 @@ def login():
if guest_id: if guest_id:
guest_user = User.query.filter_by(guest_cookie_id=guest_id, is_guest=True).first() guest_user = User.query.filter_by(guest_cookie_id=guest_id, is_guest=True).first()
if guest_user: if guest_user:
from app.routes.main_routes import get_quota_info
guest_files = PrintFile.query.filter_by(user_id=guest_user.id).all() guest_files = PrintFile.query.filter_by(user_id=guest_user.id).all()
stl_quota, stl_used = get_quota_info(user, 'stl') stl_quota, stl_used = get_quota_info(user, 'stl')
@@ -68,7 +65,6 @@ def login():
stl_quota_bytes = stl_quota * 1024 * 1024 if stl_quota > 0 else float('inf') stl_quota_bytes = stl_quota * 1024 * 1024 if stl_quota > 0 else float('inf')
gcode_quota_bytes = gcode_quota * 1024 * 1024 if gcode_quota > 0 else float('inf') gcode_quota_bytes = gcode_quota * 1024 * 1024 if gcode_quota > 0 else float('inf')
from app.routes.admin_routes import get_gcode_dir
upload_dir = current_app.config.get('UPLOAD_FOLDER', 'uploads') upload_dir = current_app.config.get('UPLOAD_FOLDER', 'uploads')
gcode_dir = get_gcode_dir() gcode_dir = get_gcode_dir()
@@ -135,7 +131,6 @@ def login():
def logout(): def logout():
session_token = session.get('user_session_token') session_token = session.get('user_session_token')
if session_token: if session_token:
from app.models import UserSession
user_session = UserSession.query.filter_by(session_token=session_token).first() user_session = UserSession.query.filter_by(session_token=session_token).first()
if user_session: if user_session:
user_session.is_active = False user_session.is_active = False

View File

@@ -1,5 +1,4 @@
import json import json
import trimesh
import uuid import uuid
import os import os
import configparser import configparser
@@ -8,15 +7,13 @@ from flask import Blueprint, render_template, request, redirect, url_for, flash,
from flask_login import login_user, logout_user, login_required, current_user from flask_login import login_user, logout_user, login_required, current_user
from werkzeug.security import generate_password_hash, check_password_hash from werkzeug.security import generate_password_hash, check_password_hash
from werkzeug.utils import secure_filename from werkzeug.utils import secure_filename
from app.models import db, User, PrintFile, SystemConfig from app.models import db, User, PrintFile, SystemConfig, UserSession
from app.utils.tasks import merge_and_slice_task, slice_stl_task, simplify_stl_task from app.utils.tasks import merge_and_slice_task, slice_stl_task, simplify_stl_task
from app import i18n_dict from app import i18n_dict
# import trimesh.repair
from app.utils.stl_simplifier import simplify_stl from app.utils.stl_simplifier import simplify_stl
from app.routes.admin_routes import get_gcode_dir from app.routes.admin_routes import get_gcode_dir
from app.utils.slice_engines import get_slicer_engine from app.utils.slice_engines import get_slicer_engine
from app.models import UserSession from app.utils.gcode_parser import get_gcode_metadata
from flask_login import logout_user
main_bp = Blueprint('main', __name__) main_bp = Blueprint('main', __name__)
@@ -90,6 +87,8 @@ def check_quota(user, file_type, size_bytes):
# Guest User Middleware # Guest User Middleware
@main_bp.before_app_request @main_bp.before_app_request
def assign_guest_cookie(): def assign_guest_cookie():
if request.path.startswith('/api/'):
return
if not current_user.is_authenticated: if not current_user.is_authenticated:
guest_id = request.cookies.get('guest_id') guest_id = request.cookies.get('guest_id')
if not guest_id: if not guest_id:
@@ -304,7 +303,6 @@ def preview_gcode(file_id):
filament_used = "-" filament_used = "-"
if os.path.exists(filepath): if os.path.exists(filepath):
from app.utils.gcode_parser import get_gcode_metadata
metadata = get_gcode_metadata(filepath) metadata = get_gcode_metadata(filepath)
time_info = metadata.get('print_time', '-') time_info = metadata.get('print_time', '-')
layer1_time = metadata.get('first_layer_time', '-') layer1_time = metadata.get('first_layer_time', '-')
@@ -595,8 +593,6 @@ def account():
flash('Guests cannot manage accounts.', 'danger') flash('Guests cannot manage accounts.', 'danger')
return redirect(url_for('main.index')) return redirect(url_for('main.index'))
from app.models import UserSession
if request.method == 'POST': if request.method == 'POST':
action = request.form.get('action') action = request.form.get('action')

View File

@@ -1,14 +1,18 @@
from flask import Blueprint, render_template, request, jsonify, flash, redirect, url_for, current_app, Response import os
from flask_login import login_required, current_user
from websockets.sync.client import connect as ws_connect
import websockets.exceptions import websockets.exceptions
import threading import threading
import requests import requests
from urllib.parse import urlparse import uuid
from app.models import SystemConfig, db import traceback
from werkzeug.utils import secure_filename
from flask import Blueprint, render_template, request, jsonify, flash, redirect, url_for, current_app, Response
from flask_login import login_required, current_user
from flask_sock import Server, ConnectionClosed
from websockets.sync.client import connect as ws_connect
from urllib.parse import urlparse, urlencode
from app.models import SystemConfig, db, PrintFile
from app.utils.octoprint_client import OctoPrintClient from app.utils.octoprint_client import OctoPrintClient
from app.models import PrintFile from app.utils.gcode_parser import get_gcode_metadata
import os
printer_bp = Blueprint('printer', __name__, url_prefix='/printer') printer_bp = Blueprint('printer', __name__, url_prefix='/printer')
@@ -21,17 +25,17 @@ def get_octo_client():
def _enrich_job_data(job_data): def _enrich_job_data(job_data):
if job_data and job_data.get('job', {}).get('file', {}).get('name'): if job_data and job_data.get('job', {}).get('file', {}).get('name'):
from app.models import PrintFile
internal_name = job_data['job']['file']['name'] internal_name = job_data['job']['file']['name']
internal_stl_name = str(internal_name)[:-5]+"stl" internal_stl_name = str(internal_name)[:-5]+"stl"
user_files = {} if current_user.is_authenticated and current_user.is_admin:
print_file = None pf = PrintFile.query.filter_by(filename=internal_stl_name).first()
for f in PrintFile.query.filter_by(user_id=current_user.id, status='sliced').all(): elif current_user.is_authenticated:
user_files[f.filename] = f.original_filename pf = PrintFile.query.filter_by(filename=internal_stl_name, user_id=current_user.id).first()
if internal_stl_name in user_files.keys(): else:
print_file = user_files[str(internal_name)[:-5]+"stl"] pf = None
if print_file:
job_data['job']['file']['display_name'] = print_file if pf:
job_data['job']['file']['display_name'] = pf.original_filename
else: else:
job_data['job']['file']['display_name'] = internal_name job_data['job']['file']['display_name'] = internal_name
return job_data return job_data
@@ -81,9 +85,6 @@ def get_gcode_dir():
@printer_bp.route('/prepare') @printer_bp.route('/prepare')
@login_required @login_required
def prepare(): def prepare():
from app.models import PrintFile
import os
from app.utils.gcode_parser import get_gcode_metadata
# Query only the sliced GCode files belonging to the current user # Query only the sliced GCode files belonging to the current user
user_files = PrintFile.query.filter_by(user_id=current_user.id, status='sliced').order_by(PrintFile.created_at.desc()).all() user_files = PrintFile.query.filter_by(user_id=current_user.id, status='sliced').order_by(PrintFile.created_at.desc()).all()
@@ -151,7 +152,6 @@ def prepare():
def check_printer_control_permission(client): def check_printer_control_permission(client):
from flask_login import current_user
if current_user.is_admin: if current_user.is_admin:
return True, None return True, None
@@ -167,7 +167,6 @@ def check_printer_control_permission(client):
if not internal_name: if not internal_name:
return False, "现在有任务正在运行,非管理员无法进行控制。" return False, "现在有任务正在运行,非管理员无法进行控制。"
from app.models import PrintFile
pf = PrintFile.query.filter_by(filename=internal_name).first() pf = PrintFile.query.filter_by(filename=internal_name).first()
if pf and pf.user_id == current_user.id: if pf and pf.user_id == current_user.id:
return True, None return True, None
@@ -204,7 +203,6 @@ def control():
try: try:
raw_url = client.get_webcam_stream_url() raw_url = client.get_webcam_stream_url()
# If it's an absolute url pointing to the base url, strip it or proxy it via octo_proxy # If it's an absolute url pointing to the base url, strip it or proxy it via octo_proxy
from urllib.parse import urlparse, urlencode
parsed_raw = urlparse(raw_url) parsed_raw = urlparse(raw_url)
base_config = SystemConfig.query.filter_by(key='octoprint_url').first() base_config = SystemConfig.query.filter_by(key='octoprint_url').first()
if base_config and base_config.value: if base_config and base_config.value:
@@ -256,11 +254,6 @@ def api_command():
@printer_bp.route('/api/upload_gcode', methods=['POST']) @printer_bp.route('/api/upload_gcode', methods=['POST'])
@login_required @login_required
def upload_gcode(): def upload_gcode():
from app.models import PrintFile
import os
import uuid
from werkzeug.utils import secure_filename
if 'file' not in request.files: if 'file' not in request.files:
return jsonify({"success": False, "error": "No file part"}), 400 return jsonify({"success": False, "error": "No file part"}), 400
@@ -366,8 +359,6 @@ def octo_proxy(path):
# --- WebSocket Proxy Logic --- # --- WebSocket Proxy Logic ---
if request.headers.get('Upgrade', '').lower() == 'websocket': if request.headers.get('Upgrade', '').lower() == 'websocket':
from flask_sock import Server, ConnectionClosed
# Check if environment supports WebSockets # Check if environment supports WebSockets
try: try:
ws = Server(request.environ) ws = Server(request.environ)
@@ -413,7 +404,6 @@ def octo_proxy(path):
remote_ws = ws_connect(target_url, additional_headers=ws_headers) remote_ws = ws_connect(target_url, additional_headers=ws_headers)
print("WS Proxy connected to remote.") print("WS Proxy connected to remote.")
except Exception as e: except Exception as e:
import traceback
traceback.print_exc() traceback.print_exc()
print(f"Remote WS Connection Error: {e}") print(f"Remote WS Connection Error: {e}")
ws.close(1011, str(e)) ws.close(1011, str(e))
@@ -473,7 +463,6 @@ def octo_proxy(path):
return WebSocketResponse() return WebSocketResponse()
# --- Standard HTTP Proxy Logic --- # --- Standard HTTP Proxy Logic ---
# from urllib.parse import urlparse
target_url = f"{base_url}/{path}" target_url = f"{base_url}/{path}"
if request.query_string: if request.query_string:

View File

@@ -2,14 +2,14 @@
{% block content %} {% block content %}
<div class="container mt-4"> <div class="container mt-4">
<h2>API Keys Management</h2> <h2>{{ _('API Keys Management') }}</h2>
<div class="card mb-4"> <div class="card mb-4">
<div class="card-header">Create New API Key</div> <div class="card-header">{{ _('Create New API Key') }}</div>
<div class="card-body"> <div class="card-body">
<form action="{{ url_for('admin.add_api_key') }}" method="POST" class="form-inline"> <form action="{{ url_for('admin.add_api_key') }}" method="POST" class="form-inline">
<input type="text" name="name" class="form-control mb-2 mr-sm-2" placeholder="Key Name" required> <input type="text" name="name" class="form-control mb-2 mr-sm-2" placeholder="{{ _('Key Name') }}" required>
<button type="submit" class="btn btn-primary mb-2">Generate Key</button> <button type="submit" class="btn btn-primary mb-2">{{ _('Generate Key') }}</button>
</form> </form>
</div> </div>
</div> </div>
@@ -17,11 +17,11 @@
<table class="table table-bordered"> <table class="table table-bordered">
<thead> <thead>
<tr> <tr>
<th>ID</th> <th>{{ _('ID') }}</th>
<th>Name</th> <th>{{ _('API Key Name') }}</th>
<th>API Key</th> <th>{{ _('API Key') }}</th>
<th>Created At</th> <th>{{ _('Created At') }}</th>
<th>Action</th> <th>{{ _('Action') }}</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@@ -32,14 +32,14 @@
<td><code>{{ key.key }}</code></td> <td><code>{{ key.key }}</code></td>
<td>{{ key.created_at.strftime('%Y-%m-%d %H:%M:%S') }}</td> <td>{{ key.created_at.strftime('%Y-%m-%d %H:%M:%S') }}</td>
<td> <td>
<form action="{{ url_for('admin.delete_api_key', key_id=key.id) }}" method="POST" style="display:inline;"> <form action="{{ url_for('admin.delete_api_key', key_id=key.id) }}" method="POST" style="display:inline;" onsubmit="event.preventDefault(); window.customConfirm('{{ _('Are you sure you want to delete this API Key?') }}', () => { this.submit(); });">
<button type="submit" class="btn btn-danger btn-sm" onclick="return confirm('Are you sure you want to delete this API Key?');">Delete</button> <button type="submit" class="btn btn-danger btn-sm">{{ _('Delete') }}</button>
</form> </form>
</td> </td>
</tr> </tr>
{% else %} {% else %}
<tr> <tr>
<td colspan="5" class="text-center">No API keys found.</td> <td colspan="5" class="text-center">{{ _('No API keys found.') }}</td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>

View File

@@ -204,7 +204,7 @@
</li> </li>
<li class="nav-item"> <li class="nav-item">
<a class="nav-link text-dark {% if request.endpoint == 'admin.api_keys' %}active text-white shadow-sm{% endif %}" href="{{ url_for('admin.api_keys') }}"> <a class="nav-link text-dark {% if request.endpoint == 'admin.api_keys' %}active text-white shadow-sm{% endif %}" href="{{ url_for('admin.api_keys') }}">
<i class="bi bi-key me-2"></i>API Keys <i class="bi bi-key me-2"></i>{{ _('API Keys') }}
</a> </a>
</li> </li>
</ul> </ul>

View File

@@ -1,8 +1,7 @@
import functools import functools
from flask import Blueprint, request, jsonify from flask import Blueprint, request, jsonify
from app.models import ApiKey from app.models import ApiKey, PrintFile, SystemConfig
from app.utils.octoprint_client import OctoPrintClient from app.utils.octoprint_client import OctoPrintClient
from app.models import SystemConfig
api_bp = Blueprint('api_handle', __name__, url_prefix='/api/v1') api_bp = Blueprint('api_handle', __name__, url_prefix='/api/v1')
@@ -13,6 +12,17 @@ def get_octo_client():
return OctoPrintClient(url.value, apikey.value) return OctoPrintClient(url.value, apikey.value)
return None return None
def _enrich_job_data(job_data):
if job_data and job_data.get('job', {}).get('file', {}).get('name'):
internal_name = job_data['job']['file']['name']
internal_stl_name = str(internal_name)[:-5]+"stl"
pf = PrintFile.query.filter_by(filename=internal_stl_name).first()
if pf:
job_data['job']['file']['display_name'] = pf.original_filename
else:
job_data['job']['file']['display_name'] = internal_name
return job_data
def require_api_key(f): def require_api_key(f):
@functools.wraps(f) @functools.wraps(f)
def decorated(*args, **kwargs): def decorated(*args, **kwargs):
@@ -30,15 +40,60 @@ def require_api_key(f):
@api_bp.route('/status', methods=['GET']) @api_bp.route('/status', methods=['GET'])
@require_api_key @require_api_key
def get_status(): def get_status():
client = get_octo_client() test_data = {
if not client: 'job': {
return jsonify({'error': 'Printer not configured'}), 503 'job': {
try: 'estimatedPrintTime': 1234,
status_data = client.get_printer_status() 'filament': {'length': 765, 'volume': 24356},
job_data = client.get_job_info() 'file': {'display_name': 'Test File','date': None, 'name': '20260414135441_42bff5215c6148b8b5f4d8c4f15d5ddc.gcode', 'origin': 'local', 'path': None, 'size': 1468987},
return jsonify({'status': status_data, 'job': job_data}) 'lastPrintTime': None,
except Exception as e: 'user': None
return jsonify({'error': str(e)}), 500 },
'progress': {
'completion': 74.8,
'filepos': 1234,
'printTime': 1235,
'printTimeLeft': 6353,
'printTimeLeftOrigin': 5366
},
'state': 'Operational'
},
'status': {
'sd': {'ready': False},
'state': {
'error': '',
'flags': {
'cancelling': False,
'closedOrError': False,
'error': False,
'finishing': False,
'operational': True,
'paused': False,
'pausing': False,
'printing': False,
'ready': True,
'resuming': False,
'sdReady': False
},
'text': 'Operational test'
},
'temperature': {
'bed': {'actual': 85, 'offset': 0, 'target': 56},
'tool0': {'actual': 0.0, 'offset': 0, 'target': 340}
}
}
}
return jsonify(test_data)
# client = get_octo_client()
# if not client:
# return jsonify({'error': 'Printer not configured'}), 503
# try:
# status_data = client.get_printer_status()
# job_data = client.get_job_info()
# job_data = _enrich_job_data(job_data)
# return jsonify({'status': status_data, 'job': job_data})
# except Exception as e:
# return jsonify({'error': str(e)}), 500
@api_bp.route('/octoprint_client', methods=['POST']) @api_bp.route('/octoprint_client', methods=['POST'])
@require_api_key @require_api_key

View File

@@ -143,7 +143,6 @@ class ConfParse:
if evaluated != field_val and not isinstance(evaluated, type): if evaluated != field_val and not isinstance(evaluated, type):
if val_dict.get("type") == "str" and not isinstance(evaluated, str): if val_dict.get("type") == "str" and not isinstance(evaluated, str):
if isinstance(evaluated, (list, dict)): if isinstance(evaluated, (list, dict)):
import json
val_dict[field] = json.dumps(evaluated).replace(" ", "") val_dict[field] = json.dumps(evaluated).replace(" ", "")
else: else:
val_dict[field] = str(evaluated) val_dict[field] = str(evaluated)

View File

@@ -4,6 +4,7 @@ import json
import uuid import uuid
import configparser import configparser
from app.utils.conf_parse import ConfParse from app.utils.conf_parse import ConfParse
from app.models import SystemConfig
class CuraEngine: class CuraEngine:
def __init__(self, print_config_folder=None): def __init__(self, print_config_folder=None):
@@ -44,8 +45,6 @@ class CuraEngine:
env = os.environ.copy() env = os.environ.copy()
env["CURA_ENGINE_SEARCH_PATH"] = f"{printers_path}:{extruders_path}:{materials_path}:{presets_path}:{variants_path}" 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() 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' 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' if not p_val.endswith('.def.json'): p_val += '.def.json'
@@ -232,8 +231,6 @@ class CuraEngine:
return [] return []
def get_bed_dimensions(self): def get_bed_dimensions(self):
from app.models import SystemConfig
import json
try: try:
db_printer = SystemConfig.query.filter_by(key='default_printer').first() 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' p_val = db_printer.value if db_printer and db_printer.value else 'creality_ender3v3se.def.json'

View File

@@ -2,6 +2,7 @@ import os
import subprocess import subprocess
import configparser import configparser
import uuid import uuid
from app.models import SystemConfig
class PrusaSlicerEngine: class PrusaSlicerEngine:
def __init__(self, print_config_folder=None): def __init__(self, print_config_folder=None):
@@ -47,8 +48,6 @@ class PrusaSlicerEngine:
# print(support_pattern) # print(support_pattern)
all_configs = {} all_configs = {}
from app.models import SystemConfig
db_printer = SystemConfig.query.filter_by(key='default_printer').first() 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' 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' if not p_val.endswith('.ini'): p_val += '.ini'
@@ -156,8 +155,6 @@ class PrusaSlicerEngine:
def get_bed_dimensions(self): def get_bed_dimensions(self):
from app.models import SystemConfig
import configparser
try: try:
db_printer = SystemConfig.query.filter_by(key='default_printer').first() 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' p_val = db_printer.value if db_printer and db_printer.value else 'Ender3_V3_SE.ini'

View File

@@ -1,14 +1,16 @@
from huey import SqliteHuey
import subprocess import subprocess
import os import os
from app.models import db, PrintFile, SystemConfig
from app.utils.conf_parse import ConfParse
import json import json
import uuid import uuid
import configparser import configparser
from huey import SqliteHuey
from app import create_app
from app.models import db, PrintFile, SystemConfig
from app.utils.conf_parse import ConfParse
from app.utils.slice_engines import get_slicer_engine from app.utils.slice_engines import get_slicer_engine
from app.utils.stl_merger import merge_stls
from app.utils.stl_simplifier import simplify_stl
import os
# Ensure instance directory exists # Ensure instance directory exists
instance_dir = os.path.join(os.path.dirname(os.path.dirname(__file__)), '..', 'instance') instance_dir = os.path.join(os.path.dirname(os.path.dirname(__file__)), '..', 'instance')
@@ -29,7 +31,6 @@ def get_gcode_dir(app):
def slice_stl_task(file_id, stl_filepath, quality_preset=None, material_preset=None, infill_density=None, support_enable=None, support_pattern=None, delete_stl=False): def slice_stl_task(file_id, stl_filepath, quality_preset=None, material_preset=None, infill_density=None, support_enable=None, support_pattern=None, delete_stl=False):
# This is run by the Huey worker # This is run by the Huey worker
# We need to create an app context to interact with the database # We need to create an app context to interact with the database
from app import create_app
app = create_app() app = create_app()
with app.app_context(): with app.app_context():
print_file = PrintFile.query.get(file_id) print_file = PrintFile.query.get(file_id)
@@ -95,10 +96,8 @@ def slice_stl_task(file_id, stl_filepath, quality_preset=None, material_preset=N
@huey.task() @huey.task()
def merge_and_slice_task(file_id, inputs, merged_filepath, quality_preset=None, material_preset=None, infill_density=None, support_enable=None, support_pattern=None, delete_stl=False): def merge_and_slice_task(file_id, inputs, merged_filepath, quality_preset=None, material_preset=None, infill_density=None, support_enable=None, support_pattern=None, delete_stl=False):
from app import create_app
app = create_app() app = create_app()
with app.app_context(): with app.app_context():
from app.models import PrintFile, db
print_file = PrintFile.query.get(file_id) print_file = PrintFile.query.get(file_id)
if not print_file: if not print_file:
return return
@@ -106,7 +105,6 @@ def merge_and_slice_task(file_id, inputs, merged_filepath, quality_preset=None,
db.session.remove() db.session.remove()
try: try:
from app.utils.stl_merger import merge_stls
merge_stls(inputs, merged_filepath) merge_stls(inputs, merged_filepath)
# Now trigger the regular slicing task # Now trigger the regular slicing task
@@ -123,13 +121,8 @@ def merge_and_slice_task(file_id, inputs, merged_filepath, quality_preset=None,
@huey.task() @huey.task()
def simplify_stl_task(file_id, filepath): def simplify_stl_task(file_id, filepath):
from app import create_app
app = create_app() app = create_app()
with app.app_context(): 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) print_file = PrintFile.query.get(file_id)
if not print_file: if not print_file:
return return

3
run_huey.sh Executable file
View File

@@ -0,0 +1,3 @@
#!/bin/bash
venv/bin/huey_consumer run_huey.huey

3
run_main.sh Executable file
View File

@@ -0,0 +1,3 @@
#!/bin/bash
venv/bin/python run.py