Spaces:
Configuration error
Configuration error
| # Scene Graph Manager API Usage | |
| This document gives a concise, high-signal overview of the HTTP API so other services can integrate without reading the whole codebase. | |
| ## Refresh Checklist (for future updates) | |
| Use this prompt when endpoints change: | |
| > Run `rg "@app" -n api/app.py` and list new/modified routes. Update `docs/api_usage.md` with: | |
| > - Endpoint table (method, path, summary) | |
| > - Auth / header requirements | |
| > - Request & response JSON samples (curl when useful) | |
| > - Notes on query params, error behaviors, and streaming endpoints. | |
| > Re-run `python -m compileall api/app.py` and ensure the doc still reflects reality. | |
| ## Base URL | |
| All paths below are relative to: | |
| ``` | |
| https://scene-graph-mgr-api.fly.dev | |
| ``` | |
| ## Authentication | |
| - Public endpoints are unauthenticated but subject to Fly.io rate limits. | |
| - Internal write endpoints require a shared secret header: `x-internal-secret: <secret>`. | |
| - Standard error payload: | |
| ```json | |
| { | |
| "detail": "Human readable message", | |
| "error_code": "optional-machine-code" | |
| } | |
| ``` | |
| 4xx indicates caller issues (validation, missing scene). 5xx means server-side failure. | |
| ## Endpoint Map | |
| | Method | Path | Summary | | |
| | --- | --- | --- | | |
| | GET | `/healthz` | Liveness check. | | |
| | GET | `/scenes` | List scenes with summary metadata (optional `include_empty`). | | |
| | PUT | `/scenes/{scene_id}` | Overwrite a scene with a full graph payload. | | |
| | PATCH | `/scenes/{scene_id}` | Apply an RFC 6902 patch to the latest graph. | | |
| | POST | `/scenes/{scene_id}/create` | Seed an empty scene (optionally overwrite). | | |
| | GET | `/scenes/{scene_id}/versions/latest` | Latest graph version. | | |
| | GET | `/scenes/{scene_id}/versions` | Metadata for all versions. | | |
| | GET | `/scenes/{scene_id}/versions/{version_id}` | Raw version record (JSON). | | |
| | POST | `/scenes/{scene_id}/add_image` | Upload image bytes and enqueue processing. | | |
| | POST | `/scenes/{scene_id}/add_images_from_keys` | Enqueue processing for existing S3 keys. | | |
| | POST | `/scenes/{scene_id}/upload_video` | Upload video and queue frame extraction batch. | | |
| | POST | `/scenes/{scene_id}/upload_image` | Browser upload β WebP resize β presigned URL. | | |
| | GET | `/scenes/{scene_id}/instances` | List stored instances for the scene (status filters optional). | | |
| | GET | `/scenes/{scene_id}/objects/{obj_id}/beliefs` | Latest improver belief for an object. | | |
| | GET | `/scenes/{scene_id}/objects/{obj_id}/instances` | List stored instances for an object (status filters optional). | | |
| | GET | `/scenes/{scene_id}/improver/backlog` | Inspect improver queue/backlog for a scene. | | |
| | POST | `/scenes/{scene_id}/objects/{obj_id}/instances/{instance_id}/improve_instance` | Queue improver workflow for an instance. | | |
| | GET | `/scenes/{scene_id}/runlogs` | Recent improver run logs (filterable). | | |
| | GET | `/scenes/{scene_id}/change-requests` | Inspect change request queue (pending/applied). | | |
| | GET | `/scenes/{scene_id}/change-summaries` | Stream applied change summaries (newest first). | | |
| | GET | `/scenes/{scene_id}/diff` | Structural diff between two versions (machine patch & stats). | | |
| | GET | `/scenes/{scene_id}/diff-semantic` | Semantic diff (ID-aware ops). | | |
| | GET | `/scenes/{scene_id}/images/presign` | Generate presigned GET URL for an image key. | | |
| | GET | `/scenes/{scene_id}/media` | List recorded media assets (images/videos). | | |
| | POST | `/scenes/{scene_id}/media` | Upsert scene media entries supplied by workers or services. | | |
| | GET | `/jobs/{job_id}` | Inspect queued/finished RQ jobs. | | |
| | POST | `/stream3r/jobs` | Submit a reconstruction job (pose pointmap or model build). | | |
| | GET | `/stream3r/jobs/{job_id}` | Inspect a Stream3R job record. | | |
| | GET | `/stream3r/jobs` | List Stream3R jobs (filter by scene, type, status). | | |
| | GET | `/stream3r/jobs/{job_id}/events` | Server-Sent Events feed for job lifecycle updates. | | |
| | GET | `/stream3r/models/{scene_id}/presign` | Presign the latest model_build scene.glb for download. | | |
| | POST | `/internal/commit-version` | Worker/internal scene commit (requires secret). | | |
| | GET | `/debug/s3-ping` | Smoke-test S3/B2 credentials. | | |
| | WS | `/ws?channel=all|{scene_id}` | Broadcasts scene events over WebSocket. | | |
| --- | |
| ## Endpoint Details & Examples | |
| ### Health & Diagnostics | |
| #### `GET /healthz` | |
| Returns `{ "ok": true, "ts": "ISO timestamp" }` for uptime monitoring. | |
| #### `GET /debug/s3-ping` | |
| Verifies object storage connectivity using a put/delete round-trip. Good for smoke tests. | |
| ### Scene Lifecycle | |
| #### `GET /scenes` | |
| List scenes. Optional `include_empty=true` includes scenes with no versions yet. | |
| ```bash | |
| curl "https://scene-graph-mgr-api.fly.dev/scenes?include_empty=true" | |
| ``` | |
| Response contains summaries with counts and most recent version metadata. | |
| #### `PUT /scenes/{scene_id}` | |
| Replace entire scene graph. | |
| Request body (`SceneGraphEnvelope`): | |
| ```json | |
| { | |
| "scene_location_id": "scene-123", | |
| "scene_graph": {"objects": [], "relations": []}, | |
| "meta": {"source": "manual"} | |
| } | |
| ``` | |
| Creates a new version record and broadcasts `scene.put` on WebSocket. | |
| #### `PATCH /scenes/{scene_id}` | |
| Apply RFC 6902 patch to latest graph. Optional `base_version` guard prevents lost updates. | |
| ```json | |
| { | |
| "scene_location_id": "scene-123", | |
| "json_patch": [ | |
| {"op": "add", "path": "/objects/-", "value": {"id": "chair-1", "attributes": {}}} | |
| ], | |
| "base_version": 1728400000000 | |
| } | |
| ``` | |
| #### `POST /scenes/{scene_id}/create` | |
| Seeds an empty graph. `overwrite=true` allows reseeding existing scenes. | |
| #### Version Reads | |
| - `GET /scenes/{scene_id}/versions/latest` β latest full graph. | |
| - `GET /scenes/{scene_id}/versions` β list of `{version_id, created_at, bytes}`. | |
| - `GET /scenes/{scene_id}/versions/{version_id}` β raw record (graph + metadata). | |
| ### Image Upload & Processing | |
| #### `POST /scenes/{scene_id}/add_image` | |
| Multipart upload (`file=@image.jpg`). Stores bytes via S3-compatible API, seeds scene if empty, enqueues `worker.tasks.process_image_for_scene`. Response includes RQ `job_id` and filename. | |
| #### `POST /scenes/{scene_id}/add_images_from_keys` | |
| JSON body: | |
| ```json | |
| { | |
| "keys": ["scenes/scene-123/images/20241008/a.png"], | |
| "room_hint": "living_room", | |
| "prompt": "describe objects", | |
| "bounding_boxes": {"a.png": [[0.1,0.2,0.5,0.8]]} | |
| } | |
| ``` | |
| Seeds scene if needed and enqueues batch worker job. | |
| Response (`AddImagesFromKeysResponse`): | |
| ```json | |
| { | |
| "scene_location_id": "scene-123", | |
| "queued_at": "2024-10-08T14:12:05Z", | |
| "job_id": "rq-job-id", | |
| "keys": [ | |
| "scenes/scene-123/images/20241008/a.png", | |
| "scenes/scene-123/images/20241008/b.png" | |
| ] | |
| } | |
| ``` | |
| #### `POST /scenes/{scene_id}/upload_image` | |
| For browser uploads. Accepts multipart file, resizes to WebP (max width 1024), uploads, and returns: | |
| ```json | |
| { | |
| "scene_location_id": "scene-123", | |
| "key": "scenes/scene-123/images/20241008/abc.webp", | |
| "url": "https://...presigned...", | |
| "width": 768, | |
| "height": 512, | |
| "bytes": 123456 | |
| } | |
| ``` | |
| #### `GET /scenes/{scene_id}/images/presign` | |
| Query parameters: `key` (must reside under `scenes/{scene_id}/images/β¦` **or** `scenes/{scene_id}/videos/β¦`) and optional `expires`. Returns `{ "url": "...", "expires_in": 900 }`. | |
| ### Video Upload & Frame Extraction | |
| #### `POST /scenes/{scene_id}/upload_video` | |
| Accepts a multipart video upload (e.g., `file=@walkthrough.mp4`). Stores the binary in object storage and seeds an empty scene when needed. The worker enqueues `process_video_for_scene`, which: | |
| - extracts WebP frames at 2fps by default (`frame_interval=0.5` seconds) and stores them under `scenes/{scene_id}/images/video_frames/...` (or keeps the source under `scenes/{scene_id}/videos/...`) so the `/images/presign` endpoint can serve them; | |
| - retries with a software H.264 transcode if AV1 or other codecs fail to decode on the host; | |
| - publishes the same `scene.update` event stream as still-image uploads. | |
| Response payload (`UploadVideoResponse`): | |
| ```json | |
| { | |
| "scene_location_id": "scene-123", | |
| "key": "scenes/scene-123/videos/20241008/abcd1234.mp4", | |
| "filename": "walkthrough.mp4", | |
| "size_bytes": 456789012, | |
| "content_type": "video/mp4", | |
| "queued_at": "2024-10-08T14:12:05Z", | |
| "job_id": "rq-job-id" | |
| } | |
| ``` | |
| Clients should poll `GET /jobs/{job_id}` to track progress. When `job.result.frame_keys` is present the frame extraction succeeded. | |
| ### Scene Media | |
| #### `GET /scenes/{scene_id}/media` | |
| Lists stored media records for a scene. Use `media_type=image` to filter to keyframes vs. `media_type=video` for source clips. | |
| ```bash | |
| curl "https://scene-graph-mgr-api.fly.dev/scenes/scene-123/media?media_type=image&limit=50" | |
| ``` | |
| Response (`SceneMediaListResponse`) includes the total slice returned plus ISO timestamps normalized to UTC. | |
| #### `POST /scenes/{scene_id}/media` | |
| Upserts media entries (usually called by workers after uploading files). Payload: | |
| ```json | |
| { | |
| "entries": [ | |
| { | |
| "file": "scenes/scene-123/keyframes/frame_000012.jpg", | |
| "media_type": "image", | |
| "captured_at": "2024-10-08T14:12:05Z" | |
| }, | |
| { | |
| "file": "scenes/scene-123/videos/20241008/abcd1234.mp4", | |
| "media_type": "video" | |
| } | |
| ] | |
| } | |
| ``` | |
| - `media_type` is optionalβwhen omitted the server infers it from the filename (`image` vs `video`). | |
| - `captured_at` accepts ISO-8601 strings (UTC preferred). If omitted, the server stores `now()`. | |
| - Existing rows are updated in-place thanks to an upsert on the `file` column. | |
| Response (`SceneMediaBatchResponse`) summarizes how many entries were accepted: | |
| ```json | |
| { | |
| "scene_id": "scene-123", | |
| "accepted": 2, | |
| "skipped": 0, | |
| "files": [ | |
| "scenes/scene-123/keyframes/frame_000012.jpg", | |
| "scenes/scene-123/videos/20241008/abcd1234.mp4" | |
| ] | |
| } | |
| ``` | |
| ### Improver Monitoring | |
| #### `GET /scenes/{scene_id}/improver/backlog` | |
| Summarizes outstanding improver work for a scene. Default statuses are `pending`, `queued`, and `processing`, plus records that do not yet have a status. Use this to detect when the improver has drained the backlog. | |
| Query parameters: | |
| - `limit` (default `200`, max `2000`) β cap the number of instances returned. | |
| - `status` β optional list to override which statuses count as βnot yet processed.β Omit to use the defaults. | |
| - `include_missing_status` (default `true`) β include rows with `status IS NULL`. | |
| Response: | |
| ```json | |
| { | |
| "scene_id": "scene-123", | |
| "count": 2, | |
| "instances": [ | |
| { | |
| "scene_id": "scene-123", | |
| "obj_id": "obj-1", | |
| "instance_id": "inst-42", | |
| "status": "pending", | |
| "status_reason": "ambient", | |
| "status_changed_at": "2024-10-08T14:15:06Z", | |
| "last_event_at": "2024-10-08T14:15:06Z", | |
| "created_at": "2024-10-08T13:59:40Z", | |
| "data": { | |
| "image_id": "img-998", | |
| "bbox_xyxy": [0.1, 0.2, 0.5, 0.8] | |
| } | |
| } | |
| ] | |
| } | |
| ``` | |
| When `count` is zero the improver has no pending work for that scene. | |
| ### Improver & Beliefs | |
| #### `POST /scenes/{scene_id}/objects/{obj_id}/instances/{instance_id}/improve_instance` | |
| Queues improver workflow. Body adheres to `InstanceEvent` schema. Example: | |
| ```bash | |
| curl -X POST \ | |
| -H "Content-Type: application/json" \ | |
| -d '{ | |
| "scene_id": "scene-123", | |
| "obj_id": "sofa-1", | |
| "instance_id": "inst-456", | |
| "image_id": "scenes/scene-123/images/20241008/sofa.png", | |
| "bbox_xyxy": [0.1, 0.3, 0.6, 0.9] | |
| }' \ | |
| https://scene-graph-mgr-api.fly.dev/scenes/scene-123/objects/sofa-1/instances/inst-456/improve_instance | |
| ``` | |
| Response: `{ "enqueued": true, "job_id": "rq-job-id" }`. | |
| The worker embeds, seeds Qdrant, and calls `scene_improver.tasks.improve_scene`. | |
| #### `GET /scenes/{scene_id}/objects/{obj_id}/beliefs` | |
| Returns latest belief payload (name Dirichlet, attribute betas, relations) or 404 if none stored. | |
| #### `GET /scenes/{scene_id}/instances` | |
| Returns persisted instances across every object in the scene. Query params: | |
| - `limit` (1β5000, default 1000) | |
| - `status` (optional, repeatable) β only include instances whose `status` matches one of the provided values. | |
| - `exclude_status` (optional, repeatable) β omit instances whose `status` matches any of the provided values (e.g., `exclude_status=superseded` to skip reassigned instances). | |
| Response mirrors the storage map: | |
| ```json | |
| { | |
| "scene_id": "scene-123", | |
| "count": 5, | |
| "objects": { | |
| "sofa-1": [{...}, {...}], | |
| "lamp-4": [{...}] | |
| } | |
| } | |
| ``` | |
| #### `GET /scenes/{scene_id}/objects/{obj_id}/instances` | |
| Returns the persisted instance rows for the object. Query params: | |
| - `limit` (1β1000, default 100) | |
| - `status` (optional, repeatable) β only include instances whose `status` matches one of the provided values. | |
| - `exclude_status` (optional, repeatable) β omit instances whose `status` matches any of the provided values. | |
| Example request skipping superseded items: | |
| ```bash | |
| curl "https://scene-graph-mgr-api.fly.dev/scenes/scene-123/objects/sofa-1/instances?limit=20&exclude_status=superseded" | |
| ``` | |
| Response: | |
| ```json | |
| { | |
| "scene_id": "scene-123", | |
| "obj_id": "sofa-1", | |
| "count": 2, | |
| "instances": [ | |
| { | |
| "id": "inst-456", | |
| "image_id": "scenes/...", | |
| "bbox_xyxy": [0.1,0.3,0.6,0.9], | |
| "captured_at": 1728401000, | |
| "status": "processed" | |
| }, | |
| { | |
| "id": "inst-123", | |
| "image_id": "scenes/...", | |
| "bbox_xyxy": [0.05,0.2,0.4,0.7], | |
| "status": "pending" | |
| } | |
| ] | |
| } | |
| ``` | |
| #### `GET /scenes/{scene_id}/runlogs` | |
| Query params: | |
| - `limit` (1β1000, default 100) | |
| - `obj_id` (optional filter) | |
| - `instance_id` (optional filter) | |
| Response contains `records` newest-first with `step`, `message`, `data`, timestamps, and run IDs. | |
| #### `GET /scenes/{scene_id}/change-requests` | |
| Inspect the change request queue. Query params: | |
| - `state` (optional: `pending`, `applied`, `stale`) | |
| - `limit` (1β200, default 50) | |
| Returns an array mirroring the DB record with preconditions, payload, result, and the new `applied_summary` field: | |
| ```json | |
| [ | |
| { | |
| "request_id": "95e8...", | |
| "scene_id": "scene-123", | |
| "obj_id": "table-1", | |
| "requested_by": "belief-agent", | |
| "state": "applied", | |
| "confidence": 0.92, | |
| "payload": {"operations": [...]}, | |
| "result": {"summary": "Renamed object \"wooden table\" from \"table\" to \"dining table\""}, | |
| "applied_at": "2024-11-19T20:14:32.123Z", | |
| "applied_summary": "Renamed object \"wooden table\" from \"table\" to \"dining table\"" | |
| } | |
| ] | |
| ``` | |
| #### `GET /scenes/{scene_id}/change-summaries` | |
| Lightweight feed of applied change blurbs, ordered by `applied_at` descending. Supports `limit` (1β200, default 50). | |
| ```bash | |
| curl "https://scene-graph-mgr-api.fly.dev/scenes/scene-123/change-summaries?limit=20" | |
| ``` | |
| ```json | |
| [ | |
| { | |
| "request_id": "95e8...", | |
| "scene_id": "scene-123", | |
| "obj_id": "table-1", | |
| "applied_version": 1729300042000, | |
| "applied_at": "2024-11-19T20:14:32.123Z", | |
| "summary": "Updated object \"wooden table\" attribute \"size\" from \"medium\" to \"large\"" | |
| }, | |
| { | |
| "request_id": "73f1...", | |
| "scene_id": "scene-123", | |
| "summary": "Renamed object \"wooden table\" from \"table\" to \"dining table\"" | |
| } | |
| ] | |
| ``` | |
| Use this endpoint for ambient βstream of consciousnessβ UIs showing how the improver evolves the scene. | |
| ### Diffs | |
| #### `GET /scenes/{scene_id}/diff` | |
| Compare two versions (`from_version`, `to_version`). Optional `mode` query (`patch`, `summary`, `both`). Returns machine patch plus stats when requested. | |
| #### `GET /scenes/{scene_id}/diff-semantic` | |
| ID-aware diff returning ordered operations (append/remove/replace) with summary stats. | |
| ### Stream3R Reconstruction Jobs | |
| The Stream3R API wraps the reconstruction workers (pose pointmaps and full models) and provides idempotent enqueue, polling, and event streaming. | |
| #### `POST /stream3r/jobs` | |
| Submit a reconstruction job. Supported `job_type` values are `pose_pointmap` and `model_build`. Provide at least one frame (`url` or `path`) and optional `client_request_id` for idempotency (subsequent calls reuse the existing job and return `200 OK`). | |
| ```bash | |
| curl -X POST https://scene-graph-mgr-api.fly.dev/stream3r/jobs \ | |
| -H "Content-Type: application/json" \ | |
| -d '{ | |
| "job_type": "pose_pointmap", | |
| "scene_id": "scene-123", | |
| "frames": [ | |
| {"url": "https://cdn.example/scene-123/frame_0000.webp"}, | |
| {"path": "/mnt/captures/scene-123/frame_0001.png"} | |
| ], | |
| "session_settings": {"prediction_mode": "pointmap"}, | |
| "client_request_id": "scene-123-20241008-run1" | |
| }' | |
| ``` | |
| Response (`202 Accepted` on first submission): | |
| ```json | |
| { | |
| "job_id": "d8f8a3fc-3aed-441c-ac78-2b953a9229bf", | |
| "job_type": "pose_pointmap", | |
| "scene_id": "scene-123", | |
| "status": "queued", | |
| "created_at": "2024-10-08T14:12:05.417Z", | |
| "payload": { | |
| "job_type": "pose_pointmap", | |
| "scene_id": "scene-123", | |
| "frames": [ | |
| {"url": "https://cdn.example/scene-123/frame_0000.webp"}, | |
| {"path": "/mnt/captures/scene-123/frame_0001.png"} | |
| ], | |
| "session_settings": {"prediction_mode": "pointmap"} | |
| } | |
| } | |
| ``` | |
| #### `GET /stream3r/jobs/{job_id}` | |
| Fetch the canonical job record (backed by Postgres). Fields include: | |
| - `status`: `queued`, `started`, `progress`, `finished`, or `failed` | |
| - `result`: worker-published artifact manifest (S3 URLs, local paths) | |
| - `error`: error string when status is `failed` | |
| - timestamps (`created_at`, `started_at`, `completed_at`) | |
| Typical successful response: | |
| ```json | |
| { | |
| "job_id": "d8f8a3fc-3aed-441c-ac78-2b953a9229bf", | |
| "job_type": "model_build", | |
| "scene_id": "scene-123", | |
| "status": "finished", | |
| "created_at": "2024-10-08T14:12:05.417Z", | |
| "started_at": "2024-10-08T14:12:12.998Z", | |
| "completed_at": "2024-10-08T14:24:39.221Z", | |
| "result": { | |
| "model_dir": "s3://bucket/scene-123/stream3r/models/20241008", | |
| "summary_url": "s3://bucket/scene-123/stream3r/models/20241008/summary.json" | |
| }, | |
| "error": null, | |
| "client_request_id": "scene-123-20241008-run1" | |
| } | |
| ``` | |
| #### `GET /stream3r/jobs` | |
| List jobs with optional filters: | |
| - `scene_id` | |
| - `job_type` | |
| - `status` | |
| - `limit` (1β200, default 50) | |
| - `offset` (default 0) | |
| Returns `{ "jobs": [...], "limit": 50, "offset": 0 }` with the same schema as the single-job response. | |
| #### `GET /stream3r/jobs/{job_id}/events` | |
| Server-Sent Events feed backed by Redis Streams. Use it for near-real-time updates in browser dashboards. | |
| ```bash | |
| curl --no-buffer \ | |
| -H "Accept: text/event-stream" \ | |
| "https://scene-graph-mgr-api.fly.dev/stream3r/jobs/d8f8a3fc-3aed-441c-ac78-2b953a9229bf/events" | |
| ``` | |
| Events are emitted as standard SSE payloads: | |
| ``` | |
| id: 1728409930123-0 | |
| event: progress | |
| data: {"job_id":"d8f8a3fc-3aed-441c-ac78-2b953a9229bf","status":"progress","progress":65} | |
| id: 1728409960456-0 | |
| event: finished | |
| data: {"job_id":"d8f8a3fc-3aed-441c-ac78-2b953a9229bf","status":"finished","result_url":"s3://bucket/.../summary.json"} | |
| ``` | |
| Reconnect with the last `id` to resume (`?last_id=<redis-stream-id>`). When the worker encounters an error the stream emits `event: failed` with an `error` field. | |
| > **Implementation note:** the current worker stub still returns `status="failed"` with `error="stream3r worker not implemented"` until the GPU-backed handler ships. Downstream clients should surface the error text to operators and may retry later. | |
| #### `GET /stream3r/models/{scene_id}/presign` | |
| Fetch a presigned download URL for the most recent `model_build` job's `scene.glb`. Optional query params: | |
| - `job_id` β force a specific job (must belong to the scene). | |
| - `expires` β TTL in seconds (default 900, range 60β86400). | |
| ```bash | |
| curl "https://scene-graph-mgr-api.fly.dev/stream3r/models/scene-123/presign?expires=600" | |
| ``` | |
| Response: | |
| ```json | |
| { | |
| "scene_id": "scene-123", | |
| "job_id": "d8f8a3fc-3aed-441c-ac78-2b953a9229bf", | |
| "key": "scenes/scene-123/stream3r/models/20241008/scene.glb", | |
| "url": "https://s3.amazonaws.com/...signature...", | |
| "expires_in": 600 | |
| } | |
| ``` | |
| Returns `404` if no successful model build exists or the job did not publish a GLB artifact. | |
| ### Jobs & Internal Ops | |
| #### `GET /jobs/{job_id}` | |
| Inspect RQ job status. Returns timestamps, result payload (if finished), and truncated stack trace when failed. | |
| #### `POST /internal/commit-version` | |
| Worker-only commit. Body: | |
| ```json | |
| { | |
| "scene_location_id": "scene-123", | |
| "scene_graph": {...}, | |
| "base_version": 1728400000000, | |
| "meta": {"source": "worker"} | |
| } | |
| ``` | |
| Requires `x-internal-secret` header when enabled. Creates new version, broadcasts `scene.update`, and publishes on Redis pub/sub. | |
| ### WebSocket Stream | |
| #### `WS /ws?channel=all|{scene_id}` | |
| Receives JSON events when scenes change (`scene.create`, `scene.put`, `scene.patch`, `scene.update`). Use to refresh UI state in real time. | |
| --- | |
| ## Notes & Best Practices | |
| - All timestamps are UTC ISO strings. | |
| - Scene writes (`PUT`, `PATCH`, `create`, `commit-version`) broadcast on WebSocket and publish to Redis channel `scene_events`. | |
| - Object storage paths follow `scenes/{scene_id}/images/...`; presign endpoint enforces this prefix. | |
| - Scene graph payloads no longer embed instance blobs; use the `/instances` endpoint for that data. | |
| - Postgres storage is required; filesystem fallbacks have been removed from the API/worker flows. | |
| - Queue jobs default to 15-minute timeout (image) or 30-minute (batch). Track job progress via `/jobs/{job_id}` or Redis CLI. | |
| - Improver run logs are persisted to Postgres (if configured) and mirrored to JSONL under `SCENE_RUN_LOG_DIR`. | |