FastAPI wrapper exposing easystitch pipeline as HTTP service #1

Closed
opened 2026-06-23 21:20:11 +00:00 by Mark · 1 comment
Owner

Goal

Implement the FastAPI app that wraps ~/Projects/easystitch/'s EmbroideryPipeline and exposes the three endpoints specified in Kimi_Agent_Brother_10_Digitizing_App#11:

  • POST /v1/digitize — raster in, regions + stitch objects out
  • POST /v1/export — stitch objects in, embroidery file bytes out (PES/DST/EXP/JEF)
  • POST /v1/threads/resolve — ΔE-2000 thread palette lookup

Implementation

  1. App layout — app.py is the FastAPI entrypoint. Imports src.main_pipeline.EmbroideryPipeline and the relevant modules from Mark/easystitch (src/embroidery_converter/, src/output_generators/, src/post_processing/, src/embroidery_converter/thread_manager.py).
  2. Pydantic models for request/response — keep these in lockstep with the TS types generated client-side (codegen from OpenAPI is a v2 follow-up; for v1 keep them manually synced).
  3. Concurrency — pipeline is CPU-bound. Use run_in_executor per request, with a thread pool sized to N=CPU cores. Reject beyond-queue-depth requests with 503.
  4. Input validation — base64 PNG/JPG ≤ 4MB encoded (reject larger with 413). Settings validated via pydantic (stitchPreference, fillDensityMm, etc. as in #11's spec).
  5. CORS — allow http://localhost:3000 (ThreadCraft dev) and the production ThreadCraft origin only. Tailnet is trusted; no auth.
  6. Healthcheck — GET /healthz returns {"status": "ok", "version": "..."} for node_hub liveness.
  7. Logging — structured JSON logs, request_id per call, log processingMs and totalStitches on /v1/digitize responses.
  8. Error handling — pydantic validation errors → 422; oversized uploads → 413; engine exceptions → 500 with sanitized message (no internals leaked). Wrap the executor calls with a try/except that converts EngineError → 500.

Files to create

  • app.py — FastAPI app, endpoint handlers, lifespan management
  • models.py — pydantic request/response models
  • pipeline_runner.py — thread-pool wrapper around EmbroideryPipeline
  • requirements.txt — fastapi, uvicorn[standard], pydantic, python-multipart, plus easystitch's own deps (or rely on the easystitch Docker base image)

Out of scope (this issue)

  • Dockerfile / container build (separate issue)
  • node_hub deployment / reverse proxy config (separate issue)
  • TS client wrapper in ThreadCraft (separate issue, lives in the frontend repo)

Acceptance

  • POST /v1/digitize on a 1024×1024 PNG returns stitch objects within 5 seconds on a dev box (CPU-only is fine).
  • POST /v1/export with format=pes returns a file that loads in an embroidery viewer.
  • POST /v1/threads/resolve returns ΔE-2000 distances.
  • GET /healthz returns 200 with version.
  • OpenAPI schema at /openapi.json reflects all endpoints.
  • Unit tests cover the pydantic validators, error paths (oversized upload, missing fields, invalid base64), and the executor wrapper.

Dependencies

  • Mark/easystitch is a sibling repo. Either:
    • Install via pip install -e ../easystitch in dev, or
    • Vendor via Docker FROM mark/easystitch:latest (see Dockerfile issue).
  • This issue blocks the Dockerfile + node_hub deployment issue.
## Goal Implement the FastAPI app that wraps `~/Projects/easystitch/`'s `EmbroideryPipeline` and exposes the three endpoints specified in **Kimi_Agent_Brother_10_Digitizing_App#11**: - `POST /v1/digitize` — raster in, regions + stitch objects out - `POST /v1/export` — stitch objects in, embroidery file bytes out (PES/DST/EXP/JEF) - `POST /v1/threads/resolve` — ΔE-2000 thread palette lookup ## Implementation 1. **App layout** — `app.py` is the FastAPI entrypoint. Imports `src.main_pipeline.EmbroideryPipeline` and the relevant modules from `Mark/easystitch` (`src/embroidery_converter/`, `src/output_generators/`, `src/post_processing/`, `src/embroidery_converter/thread_manager.py`). 2. **Pydantic models** for request/response — keep these in lockstep with the TS types generated client-side (codegen from OpenAPI is a v2 follow-up; for v1 keep them manually synced). 3. **Concurrency** — pipeline is CPU-bound. Use `run_in_executor` per request, with a thread pool sized to N=CPU cores. Reject beyond-queue-depth requests with `503`. 4. **Input validation** — base64 PNG/JPG ≤ 4MB encoded (reject larger with `413`). Settings validated via pydantic (`stitchPreference`, `fillDensityMm`, etc. as in #11's spec). 5. **CORS** — allow `http://localhost:3000` (ThreadCraft dev) and the production ThreadCraft origin only. Tailnet is trusted; no auth. 6. **Healthcheck** — `GET /healthz` returns `{"status": "ok", "version": "..."}` for node_hub liveness. 7. **Logging** — structured JSON logs, request_id per call, log `processingMs` and `totalStitches` on `/v1/digitize` responses. 8. **Error handling** — pydantic validation errors → 422; oversized uploads → 413; engine exceptions → 500 with sanitized message (no internals leaked). Wrap the executor calls with a try/except that converts EngineError → 500. ## Files to create - `app.py` — FastAPI app, endpoint handlers, lifespan management - `models.py` — pydantic request/response models - `pipeline_runner.py` — thread-pool wrapper around `EmbroideryPipeline` - `requirements.txt` — fastapi, uvicorn[standard], pydantic, python-multipart, plus easystitch's own deps (or rely on the easystitch Docker base image) ## Out of scope (this issue) - Dockerfile / container build (separate issue) - node_hub deployment / reverse proxy config (separate issue) - TS client wrapper in ThreadCraft (separate issue, lives in the frontend repo) ## Acceptance - `POST /v1/digitize` on a 1024×1024 PNG returns stitch objects within 5 seconds on a dev box (CPU-only is fine). - `POST /v1/export` with `format=pes` returns a file that loads in an embroidery viewer. - `POST /v1/threads/resolve` returns ΔE-2000 distances. - `GET /healthz` returns 200 with version. - OpenAPI schema at `/openapi.json` reflects all endpoints. - Unit tests cover the pydantic validators, error paths (oversized upload, missing fields, invalid base64), and the executor wrapper. ## Dependencies - `Mark/easystitch` is a sibling repo. Either: - Install via `pip install -e ../easystitch` in dev, or - Vendor via Docker `FROM mark/easystitch:latest` (see Dockerfile issue). - This issue blocks the Dockerfile + node_hub deployment issue.
Author
Owner

Dependency

Depends on easystitch#82 — version accessor.

Why: /healthz needs easystitch_version.

This is one of 8 easystitch issues opened against Mark/easystitch to unblock the service:

  • #75 digitize_to_stitches()
  • #76 thread settings dict
  • #77 raster placeholder bug
  • #78 BrotherPR10ThreadLibrary
  • #79 ΔE-2000 distance
  • #80 match_color_with_alternatives
  • #81 paletteIndex assignment
  • #82 version accessor

All eight are triaged-approved on Mark/easystitch. Until they land, /v1/digitize and /v1/threads/resolve cannot return the contract shape.

## Dependency Depends on **easystitch#82** — version accessor. **Why:** /healthz needs easystitch_version. This is one of 8 easystitch issues opened against `Mark/easystitch` to unblock the service: - #75 digitize_to_stitches() - #76 thread settings dict - #77 raster placeholder bug - #78 BrotherPR10ThreadLibrary - #79 ΔE-2000 distance - #80 match_color_with_alternatives - #81 paletteIndex assignment - #82 version accessor All eight are triaged-approved on `Mark/easystitch`. Until they land, `/v1/digitize` and `/v1/threads/resolve` cannot return the contract shape.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Mark/easystitch-service#1
No description provided.