- Python 92.2%
- JavaScript 5.4%
- CSS 1.6%
- HTML 0.7%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| app | ||
| docs | ||
| profiles | ||
| scripts | ||
| static | ||
| templates | ||
| tests | ||
| .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.md —
uv 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.
Compose (recommended)
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.jsonprofiles/a2l/process_pricing_backend.full.jsonprofiles/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).
- Contract:
docs/openapi.yaml - Client walkthrough (server-to-server):
docs/frontend-integration.md
| 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
docs/first-deploy.md— beginner Linux deploydocs/openapi.yaml— API contractdocs/frontend-integration.md— server-to-server client walkthroughdocs/job-schema.jsondocs/slicer-runtime.mddocs/contracts.md