From 8ee20f14ebce4eb3372d25d68e1b0fa452416281 Mon Sep 17 00:00:00 2001 From: "Alex W." Date: Fri, 12 Jun 2026 17:30:30 -1000 Subject: [PATCH 1/2] Add comments for clarity in server.py --- backend/server.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/backend/server.py b/backend/server.py index dad6d8b..0874bd5 100644 --- a/backend/server.py +++ b/backend/server.py @@ -145,18 +145,27 @@ class GenerateRequest(BaseModel): seed: int = DEFAULT_SEED steps: int = Field(default=DEFAULT_STEPS, ge=1) guidance: float = Field(default=DEFAULT_GUIDANCE, ge=0.0) + # Optional for backward compatibility: if omitted, the current resident + # pipeline backend is reused. backend: Backend | SkipJsonSchema[None] = Field(default=None) height: int = Field(default=DEFAULT_HEIGHT, ge=16) width: int = Field(default=DEFAULT_WIDTH, ge=16) + # Allows local callers to point at a specific model without changing the + # process-wide default configuration. model_path: str | None = Field(default=None) + # None means "use the pipeline/server default"; True or False overrides the + # VAE tiling behavior for this request only. tiled_vae: bool | None = Field(default=None) max_sequence_length: int | None = Field(default=None, ge=1) @asynccontextmanager async def lifespan(app: FastAPI): + """Create the resident pipeline once and clean it up on shutdown.""" pipeline = make_pipeline(PipelineConfig.from_env()) app.state.pipeline = pipeline + # Local MLX swaps must be serialized because the process owns one resident + # in-memory model at a time. app.state.swap_lock = asyncio.Lock() try: yield @@ -171,6 +180,8 @@ async def lifespan(app: FastAPI): @app.get("/backends") async def get_backends(force_disable: bool = False) -> dict: pipeline: FluxPipeline | RemoteGpuPipeline = app.state.pipeline + # The active pipeline determines which backend kind this server process can + # actually serve. pipeline_kind: BackendKind = "gemlite" if pipeline.is_remote else "mlx" return _get_backends_payload( force_disable_query=force_disable, @@ -199,6 +210,8 @@ async def get_backends(force_disable: bool = False) -> dict: async def generate(request: GenerateRequest) -> Response: pipeline: FluxPipeline | RemoteGpuPipeline = app.state.pipeline lock: asyncio.Lock = app.state.swap_lock + # If the caller does not specify a backend, keep using the pipeline's + # current resident backend instead of forcing an unnecessary model swap. target_backend: Backend = request.backend if request.backend is not None else pipeline.backend if target_backend not in BACKENDS: raise HTTPException(status_code=400, detail=f"Unknown backend {target_backend!r}.") @@ -226,6 +239,7 @@ async def generate(request: GenerateRequest) -> Response: ) wall_seconds = time.perf_counter() - gen_start headers = {"X-Wall-Seconds": f"{wall_seconds:.3f}"} + # Surface memory telemetry when the pipeline records it. if pipeline.last_peak_memory_mb is not None: headers["X-Peak-Memory-MB"] = f"{pipeline.last_peak_memory_mb:.1f}" return Response( @@ -235,6 +249,8 @@ async def generate(request: GenerateRequest) -> Response: ) finally: if not pipeline.is_remote: + # Release MLX cached allocations after each local render so the + # next request starts with a lower memory watermark. mx.clear_cache() gc.collect() From abd0ed6520e0da4b71a7573dd9dc40ee87035df9 Mon Sep 17 00:00:00 2001 From: Alexander Wang Date: Sat, 27 Jun 2026 11:05:01 -1000 Subject: [PATCH 2/2] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- backend/server.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/server.py b/backend/server.py index 0874bd5..b94083b 100644 --- a/backend/server.py +++ b/backend/server.py @@ -150,8 +150,8 @@ class GenerateRequest(BaseModel): backend: Backend | SkipJsonSchema[None] = Field(default=None) height: int = Field(default=DEFAULT_HEIGHT, ge=16) width: int = Field(default=DEFAULT_WIDTH, ge=16) - # Allows local callers to point at a specific model without changing the - # process-wide default configuration. + # Optional model override for local MLX pipeline runs. Ignored when the server + # is running in remote-GPU mode. model_path: str | None = Field(default=None) # None means "use the pipeline/server default"; True or False overrides the # VAE tiling behavior for this request only.