No description
  • Python 92.2%
  • JavaScript 5.4%
  • CSS 1.6%
  • HTML 0.7%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-08-08 16:56:55 +08:00
app Cull orphaned containers 2026-08-08 16:56:55 +08:00
docs Cull orphaned containers 2026-08-08 16:56:55 +08:00
profiles
scripts
static
templates
tests Cull orphaned containers 2026-08-08 16:56:55 +08:00
.env.example
.gitignore
.pre-commit-config.yaml
.python-version
config.example.yaml
docker-compose.yml
Dockerfile
pyproject.toml
README.md
requirements.txt
uv.lock

Print estimator

Flask multi-STL print estimate API. Create a draft job, attach models, start an on-demand Bambu Studio CLI container via the Docker socket, then poll for filament weight, plate count, and bed-fit.

Production target: remote Linux host with Docker Engine (amd64). Windows Docker Desktop is local-dev only and best-effort.

New to servers / Docker? Follow the step-by-step guide: docs/first-deploy.md (SSH → install Docker → compose → open the UI → run a test STL).

Quick start (Linux)

uv sync
cp .env.example .env
# Edit .env: set API_KEYS (and FRONTEND_API_KEY if ENABLE_FRONTEND=true)
cp config.example.yaml config.yaml   # optional; compose mounts the example by default

Warm-pool spike (Linux Docker host): uv run run-warm-pool-spike --repeats 10

Slice timing (multi-printer / warm vs cold): see docs/slicer-runtime.mduv run run-slice-timing --suite runs every bench. Use --suite-only-errors for the same suite with quiet successes and full slicer.log dumps on slice failures.

The API container mounts /var/run/docker.sock so it can start sibling slicer containers. Profiles under profiles/a2l/ must include the flattened .full.json files referenced in config.

# .env must define API_KEYS
docker compose up -d --build

Health: GET /health{"status":"ok"}.

On first start with the Docker slicer backend, the app pulls bambu_studio_image (see config) so jobs never wait on an anonymous pull.

Local Flask (no compose)

export FLASK_APP=app:create_app
export API_KEYS=dev-key-change-me
flask run --host 0.0.0.0 --port 5000

Offline / CI without Docker:

export SLICER_BACKEND=fake
export API_KEYS=test-key
flask run --host 0.0.0.0 --port 5000

Configuration

Source Notes
config.example.yaml A2L only in v1; copy or set CONFIG_PATH
API_KEYS Comma-separated; required for /api/v1/*
FRONTEND_API_KEY Required when ENABLE_FRONTEND=true; inject into the UI
ENABLE_FRONTEND Serves / and /estimate when true
DOCKER_HOST_PROJECT_ROOT Absolute host path to this repo (Linux or C:/… on Docker Desktop)
API_PORT Host port for compose (default 5050; container stays on 5000)
SLICER_BACKEND docker (default) or fake
BAMBU_STUDIO_IMAGE Override image tag/digest
MAX_CONCURRENT_SLICES Parallel Bambu CLI containers (default 2)
DATA_DIR Job workspace root (default data)

Profile paths in config point at flattened files:

  • profiles/a2l/machine.json
  • profiles/a2l/process_pricing_backend.full.json
  • profiles/a2l/filament_generic_pla.full.json

See profiles/README.md.

API

Auth: X-API-Key or Authorization: Bearer <key> on /api/v1/*. Health: GET /health (no key).

Method Path Purpose
GET /health Liveness ({"status":"ok"})
GET /api/v1/printers Configured printers
GET /api/v1/limits Current upload / concurrency / TTL caps
GET /api/v1/jobs List recent jobs (?limit=20&status=completed)
POST /api/v1/jobs Create draft (printer, filament_colour optional)
PATCH /api/v1/jobs/{id} Update printer / filament colour (force aborts slice + resets to draft)
POST /api/v1/jobs/{id}/models Attach STL/3MF (multipart files or file)
GET /api/v1/jobs/{id}/models/{model_id}/file Original uploaded model bytes
PATCH /api/v1/jobs/{id}/models/{model_id} Scale % / quantity while draft
DELETE /api/v1/jobs/{id}/models/{model_id} Remove model while draft
POST /api/v1/jobs/{id}/start Queue slice
GET /api/v1/jobs/{id} Poll status / result
DELETE /api/v1/jobs/{id} Cancel + cleanup
GET /api/v1/jobs/{id}/plates/{n}/preview Plate layout SVG
GET /api/v1/jobs/{id}/plates/{n}/model Arranged plate GLB
GET /api/v1/jobs/{id}/plates/{n}/gcode Plate toolpath G-code

Real slicer smoke (Linux Docker Engine)

Do this on the Linux host that has Docker Engine (not required on Windows dev machines):

python scripts/pull_bambu_image.py
python scripts/spike_slicer_cli.py --stl tests/fixtures/cube_10mm.stl

Then run the API with SLICER_BACKEND unset (or docker), attach an STL via the API, start the job, and poll until completed. Pin bambu_studio_image to @sha256:… in config after a successful spike (see docs/slicer-runtime.md).

Tests

python -m pytest tests/ -v --ignore-glob='*slicer*'

Parser and API tests use fixtures / FakeSlicer; they do not need Docker.

Printers

Triplets for every Bambu Lab 0.4 nozzle in the slicer image live under profiles/. config.example.yaml enables a2l, h2c, p1s, x1c, a1, a1m; the rest ship with enabled: false. See profiles/README.md / profiles/catalog.json.

Docs