diff --git a/backend/Dockerfile b/Slicer Project/backend/Dockerfile similarity index 98% rename from backend/Dockerfile rename to Slicer Project/backend/Dockerfile index d05fb1e..03923c1 100644 --- a/backend/Dockerfile +++ b/Slicer Project/backend/Dockerfile @@ -64,7 +64,6 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ libxfixes3 libdrm2 libxdamage1 libxcomposite1 libwayland-client0 libxcb1 \ python3 make g++ libsqlite3-dev \ curl tini \ - # 👇 add these for libGL.so.1 (Mesa) libgl1 libgl1-mesa-dri libglu1-mesa \ && rm -rf /var/lib/apt/lists/* diff --git a/backend/package.json b/Slicer Project/backend/package.json similarity index 100% rename from backend/package.json rename to Slicer Project/backend/package.json diff --git a/backend/src/db.ts b/Slicer Project/backend/src/db.ts similarity index 100% rename from backend/src/db.ts rename to Slicer Project/backend/src/db.ts diff --git a/backend/src/server.ts b/Slicer Project/backend/src/server.ts similarity index 97% rename from backend/src/server.ts rename to Slicer Project/backend/src/server.ts index 762b7bd..35e4939 100644 --- a/backend/src/server.ts +++ b/Slicer Project/backend/src/server.ts @@ -91,7 +91,7 @@ app.post("/api/jobs", upload.single("model"), async (req, res) => { const job: JobRecord = { id, - filename: req.file.originalname, + filename: path.join(outputDir, "transformed_input.stl"), ext, profile: profilePath, supports, @@ -103,6 +103,10 @@ app.post("/api/jobs", upload.single("model"), async (req, res) => { finishedAt: null }; insertJob.run(job); + try { + db.prepare("UPDATE jobs SET rot_x=?, rot_y=?, rot_z=?, scale=? WHERE id=?") + .run(rotX, rotY, rotZ, scale, id); + } catch {} // Kick slicing async runSlicing(job, outputPath, supports, profilePath).catch(() => { /* already captured in DB */ }); @@ -153,7 +157,7 @@ function mapRow(r: any) { profile: path.basename(r.profile), supports: r.supports, inputPath: r.input_path, - outputPath: r.output_path ? `/outputs/${r.id}/result.gcode` : null, + outputPath: r.output_path ? `/outputs/${r.id}/result.3mf` : null, status: r.status, errorMsg: r.error_msg, createdAt: r.created_at, diff --git a/backend/src/types.ts b/Slicer Project/backend/src/types.ts similarity index 100% rename from backend/src/types.ts rename to Slicer Project/backend/src/types.ts diff --git a/backend/tsconfig.json b/Slicer Project/backend/tsconfig.json similarity index 100% rename from backend/tsconfig.json rename to Slicer Project/backend/tsconfig.json diff --git a/docker-compose.yml b/Slicer Project/docker-compose.yml similarity index 81% rename from docker-compose.yml rename to Slicer Project/docker-compose.yml index 32624a5..7520ad2 100644 --- a/docker-compose.yml +++ b/Slicer Project/docker-compose.yml @@ -1,7 +1,7 @@ services: backend: build: - context: . # repo root + context: . dockerfile: backend/Dockerfile env_file: .env ports: diff --git a/frontend/Dockerfile b/Slicer Project/frontend/Dockerfile similarity index 100% rename from frontend/Dockerfile rename to Slicer Project/frontend/Dockerfile diff --git a/frontend/index.html b/Slicer Project/frontend/index.html similarity index 100% rename from frontend/index.html rename to Slicer Project/frontend/index.html diff --git a/frontend/package.json b/Slicer Project/frontend/package.json similarity index 100% rename from frontend/package.json rename to Slicer Project/frontend/package.json diff --git a/frontend/src/App.tsx b/Slicer Project/frontend/src/App.tsx similarity index 100% rename from frontend/src/App.tsx rename to Slicer Project/frontend/src/App.tsx diff --git a/frontend/src/main.tsx b/Slicer Project/frontend/src/main.tsx similarity index 100% rename from frontend/src/main.tsx rename to Slicer Project/frontend/src/main.tsx diff --git a/frontend/src/three-preview.tsx b/Slicer Project/frontend/src/three-preview.tsx similarity index 100% rename from frontend/src/three-preview.tsx rename to Slicer Project/frontend/src/three-preview.tsx diff --git a/frontend/vite.config.ts b/Slicer Project/frontend/vite.config.ts similarity index 100% rename from frontend/vite.config.ts rename to Slicer Project/frontend/vite.config.ts diff --git a/Web UI Project/.dockerignore b/Web UI Project/.dockerignore new file mode 100644 index 0000000..8dd0f69 --- /dev/null +++ b/Web UI Project/.dockerignore @@ -0,0 +1,11 @@ +__pycache__/ +*.pyc +*.pyo +*.pyd +*.env +.env* +.vscode/ +.idea/ +.git/ +dist/ +build/ diff --git a/Web UI Project/app/__init__.py b/Web UI Project/app/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/Web UI Project/app/__pycache__/__init__.cpython-312.pyc b/Web UI Project/app/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..53d8f04 Binary files /dev/null and b/Web UI Project/app/__pycache__/__init__.cpython-312.pyc differ diff --git a/Web UI Project/app/__pycache__/main.cpython-312.pyc b/Web UI Project/app/__pycache__/main.cpython-312.pyc new file mode 100644 index 0000000..3d5c8ee Binary files /dev/null and b/Web UI Project/app/__pycache__/main.cpython-312.pyc differ diff --git a/Web UI Project/app/__pycache__/printer.cpython-312.pyc b/Web UI Project/app/__pycache__/printer.cpython-312.pyc new file mode 100644 index 0000000..d917616 Binary files /dev/null and b/Web UI Project/app/__pycache__/printer.cpython-312.pyc differ diff --git a/Web UI Project/app/main.py b/Web UI Project/app/main.py new file mode 100644 index 0000000..7b82b17 --- /dev/null +++ b/Web UI Project/app/main.py @@ -0,0 +1,115 @@ +from fastapi import FastAPI, Request +from fastapi.responses import HTMLResponse +from fastapi.staticfiles import StaticFiles +from fastapi.templating import Jinja2Templates +import uvicorn +import bambulabs_api as bl +import os +from datetime import datetime, timedelta + +app = FastAPI(title="X1C Connection") + +IP = "10.0.2.10" +ACCESS_CODE = "e0f815a7" +SERIAL = "00M09A360300272" + +printer = bl.Printer(IP, ACCESS_CODE, SERIAL) + +# Serve /static/* +app.mount("/static", StaticFiles(directory="app/static"), name="static") + +templates = Jinja2Templates(directory="app/templates") + +# track connection state in-memory for UI (simple flag) +connectionState = False + + +@app.get("/", response_class=HTMLResponse) +def home(request: Request): + # Render page and pass current connection state + try: + connected = bool(connectionState) + except NameError: + connected = False + return templates.TemplateResponse("index.html", {"request": request, "connected": connected}) + + +@app.post("/connect", response_class=HTMLResponse) +def connect(request: Request): + global connectionState + try: + printer.mqtt_start() + if(printer.mqtt_start()): + connectionState = True + except Exception: + connectionState = False + + # Return the connect area so HTMX can swap the button immediately + return templates.TemplateResponse("_connect_area.html", {"request": request, "connected": connectionState}) + + +@app.post("/disconnect", response_class=HTMLResponse) +def disconnect(request: Request): + global connectionState + try: + printer.mqtt_stop() + connectionState = False + except Exception: + connectionState = False + + # Return the connect area so HTMX can swap the button immediately + return templates.TemplateResponse("_connect_area.html", {"request": request, "connected": connectionState}) + + +@app.post("/status", response_class=HTMLResponse) +def status(request: Request): + + + try: + # Preferred direct calls (if the API exposes them) + status = {} + status['bed_temp'] = printer.get_bed_temperature() + status['nozzle_temp'] = printer.get_nozzle_temperature() + status['chamber_temp'] = printer.get_chamber_temperature() + status['percentage'] = printer.get_percentage() + remaining_time = printer.get_time() + current = printer.get_file_name() + except Exception as e: + return templates.TemplateResponse("_status.html", {"request": request, "status": {"error": str(e)}}) + + # Normalize current file: remove /data/Metadata/ prefix or use basename + current_file = str(current or '') + if current_file.startswith('/data/Metadata/'): + current_file = current_file[len('/data/Metadata/'):] + else: + current_file = os.path.basename(current_file) + status['current_file'] = current_file or 'N/A' + + if remaining_time is not None: + finish_time = datetime.now() + timedelta(seconds=int(remaining_time)) + status['finish_time'] = finish_time.strftime("%Y-%m-%d %H:%M:%S") + status['remaining_time'] = timedelta(seconds=int(remaining_time)) + + else: + status['finish_time'] = "NA" + status['remaining_time'] = "N/A" + + + + + # stringify values + for k in status: + try: + status[k] = str(status[k]) + except Exception: + status[k] = 'N/A' + + return templates.TemplateResponse("_status.html", {"request": request, "status": status}) + + + + +if __name__ == "__main__": + # Dev convenience; in Docker we launch via CMD + uvicorn.run("app.main:app", host="0.0.0.0", port=8000, reload=True) + diff --git a/Web UI Project/app/static/ass.css b/Web UI Project/app/static/ass.css new file mode 100644 index 0000000..e69de29 diff --git a/Web UI Project/app/templates/_action_results.html b/Web UI Project/app/templates/_action_results.html new file mode 100644 index 0000000..c0241f9 --- /dev/null +++ b/Web UI Project/app/templates/_action_results.html @@ -0,0 +1,12 @@ +