File size: 7,819 Bytes
42ca926 c1b700d 42ca926 c1b700d 42ca926 c1b700d 42ca926 c1b700d 42ca926 c1b700d 42ca926 c1b700d 42ca926 c1b700d 42ca926 939683f 42ca926 c1b700d 42ca926 c1b700d 42ca926 c1b700d 42ca926 c1b700d 42ca926 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 | # MOSS-Image API spec (node4)
HTTP image-generation API for the MOSS-Image TTNN bundle. Diffusion model β **no tokens, no
KV cache, no streaming**; requests are image jobs.
## Base URL
- From node4 itself: `http://127.0.0.1:8000`
- From other boxes on the LAN: `http://192.168.50.97:8000` (node4), or `http://node4:8000` if
your `/etc/hosts`/DNS resolves it.
- The server binds `0.0.0.0:$PORT` (default **8000**). Open that port in any firewall between
boxes. No auth (intended for a trusted LAN); put it behind a proxy if you need auth.
> Status note: the API shape below is identical whether it is served by the device bundle
> (TTNN on the Blackhole card) or the CPU reference β same endpoints, same schemas. Only speed
> differs.
## Endpoints
### `GET /health`
Liveness + which model/mesh is loaded, and the capability contract.
```json
{ "status": "ok", "model": "OpenMOSS-Team/MOSS-Image-Base",
"mesh": "P150", "mesh_shape": "1x1", "vae_device": true,
"pipeline_loaded": true, "kind": "tt-dit-server",
"progress_reporting": true, "job_persistence": true,
"private_ephemeral_jobs": true, "private_result_ttl_s": 900 }
```
- `vae_device` β `true` when the VAE decodes on the device (pure `ttnn`, the default;
validated vs host fp32 to PCC β₯0.9999 at all resolutions). Force host with `MOSS_VAE_DEVICE=0`.
- `mesh_shape` β DiT topology (`MOSS_MESH`): `1x1` single-chip (default), `1x2`/`1x4` mesh.
- `private_ephemeral_jobs` / `private_result_ttl_s` β see **Private jobs** below.
### Private jobs (default for new `POST /generate`)
Send an `X-Moss-Job-Token` header on `POST /generate` (or let the server mint one and return it
as `job_token`). The job is then token-scoped: **not** listed in `GET /jobs`, **never** written
to disk (result held in memory only), and reaped after a **900 s** TTL. The same token is
required on `GET /jobs/{id}`, `GET /images/{id}.png`, and `DELETE /jobs/{id}`; a missing/wrong
token returns **404**. Limits: max 8 private jobs, 64 MiB encoded result each. Legacy disk-backed
jobs (created without a token) remain listable and survive restarts.
### `GET /v1/models`
OpenAI-style model list.
```json
{ "object": "list", "data": [
{ "id": "OpenMOSS-Team/MOSS-Image-Base", "object": "model", "owned_by": "openmoss" } ] }
```
### `POST /generate` β submit an async job (recommended)
Request body (JSON):
| field | type | default | notes |
| --- | --- | --- | --- |
| `prompt` | string | β | **required** |
| `height` | int | 1024 | 256β2048, multiple of 16 |
| `width` | int | 1024 | 256β2048, multiple of 16 |
| `num_inference_steps` | int | 50 | 1β200; β₯28 for quality |
| `guidance_scale` | float | 3.0 | 0β20; CFG scale (1.0 disables CFG) |
| `negative_prompt` | string | `""` | used when `guidance_scale != 1` |
| `seed` | int\|null | null | reproducibility (CPU RNG) |
| `max_sequence_length` | int | 4096 | 1β4096; max prompt tokens |
| `shift` | float\|null | nullβ5.0 | 1β10; flow-match scheduler shift |
| `uncond_skip_layers` | list[int] | `[22]` | DiT layers skipped on the CFG negative branch; `[]` disables |
| `slg_layers` | list[int]\|null | null | skip-layer-guidance layers; null/`[]` disables the extra forward |
| `slg_scale` | float | 0.0 | 0β20; `prediction += slg_scale*(cond β cond_skipped)` |
| `slg_start` | float | 0.0 | 0β1; SLG/skip window start (fraction of steps) |
| `slg_stop` | float | 1.0 | 0β1; SLG/skip window stop (fraction of steps) |
The advanced knobs mirror `reference/pipeline_moss_image.py __call__`. Call **`GET /v1/parameters`**
(alias `GET /config`) for this schema with ranges at runtime.
Response (every new job is private by default β keep the `job_token`):
```json
{ "job_id": "ff70ee2b28e4", "status": "queued", "poll": "/jobs/ff70ee2b28e4",
"job_token": "<43β128 url-safe chars>", "storage": "memory", "private": true, "result_ttl_s": 900 }
```
Jobs are serialized through one worker (one model / one device); submitting many just queues them.
### `GET /jobs/{job_id}` β poll status
```json
{ "job_id": "ff70ee2b28e4", "status": "done",
"request": { ... }, "image_url": "/images/ff70ee2b28e4.png" }
```
`status` β `queued` | `running` | `done` | `error`. On `error`, an `error` field carries the message.
### `GET /images/{job_id}.png` β fetch the result
Returns `image/png` once the job is `done` (404 until then). Finished images are
saved to disk (`$MOSS_OUTPUT_DIR`, default `./moss_outputs`) and freed from memory, so
this is served from the saved file after the job completes.
### `GET /jobs` β list jobs
```json
{ "jobs": [ { "job_id": "ff70ee2b28e4", "status": "done",
"file_path": "/.../moss_outputs/ff70ee2b28e4.png", "prompt": "a red fox in snow" } ] }
```
### `DELETE /jobs/{job_id}` β delete a job + its saved image
Drops the job from memory and removes its PNG from disk.
```json
{ "deleted": true, "job_id": "ff70ee2b28e4", "file_removed": true }
```
### `POST /generate/sync` β blocking, returns PNG directly
Same body as `/generate`; responds with `image/png`. Convenient but holds the connection for the
full generation (minutes at 1024Β²/50) β prefer the async flow for anything non-trivial.
### `POST /v1/images/generations` β OpenAI-compatible (blocking)
Request (superset of the OpenAI schema β the full control set is accepted here too):
```json
{ "prompt": "a red fox in snow", "n": 1, "size": "1024x1024", "seed": 42,
"width": 1024, "height": 1024, "num_inference_steps": 50, "guidance_scale": 3.0,
"negative_prompt": "", "shift": 5.0, "slg_layers": [24], "slg_scale": 3.0 }
```
`size` is `WIDTHxHEIGHT`; explicit `width`+`height` override it. All `/generate` advanced knobs
(`max_sequence_length`, `shift`, `uncond_skip_layers`, `slg_*`) are accepted. Response (base64
PNGs, OpenAI Images shape):
```json
{ "created": 1760000000, "data": [ { "b64_json": "<base64 png>" } ] }
```
### `GET /v1/parameters` (alias `GET /config`) β controllable-parameter schema
A UI reads this to render generation controls. Each entry has `name`, `type`, `default`, and
`min`/`max`/`multiple_of`/`max_length` where applicable.
```json
{ "model": "OpenMOSS-Team/MOSS-Image-Base",
"endpoints": ["/generate", "/v1/images/generations"],
"parameters": [
{ "name": "num_inference_steps", "type": "int", "default": 50, "min": 1, "max": 200 },
{ "name": "guidance_scale", "type": "float", "default": 3.0, "min": 0.0, "max": 20.0 },
{ "name": "shift", "type": "float|null", "default": 5.0, "min": 1.0, "max": 10.0 },
{ "name": "width", "type": "int", "default": 1024, "min": 256, "max": 2048, "multiple_of": 16 }
/* β¦height, seed, negative_prompt, max_sequence_length, uncond_skip_layers, slg_* β¦ */
] }
```
## Example (async)
```bash
HOST=http://192.168.50.97:8000
JID=$(curl -s -X POST $HOST/generate -H 'content-type: application/json' \
-d '{"prompt":"a cozy bookshop, warm light, a cat asleep on a chair","height":1024,"width":1024,"num_inference_steps":50,"seed":7}' \
| python3 -c 'import sys,json;print(json.load(sys.stdin)["job_id"])')
until curl -s $HOST/jobs/$JID | grep -q '"status":"done"'; do sleep 5; done
curl -s $HOST/images/$JID.png -o out.png
```
## Notes for client/agent builders
- **Latency** (single p150, device backend): ~12β25 s for 256Β²/4-step warm; ~235 s for
1024Β²/50-step. Set generous client timeouts; prefer `/generate` + poll over `/generate/sync`.
- **Concurrency:** requests queue (single device). Don't fan out expecting parallelism.
- **Resolution:** `height`/`width` must be multiples of 16.
- **Determinism:** pass `seed` for reproducible images.
- **Errors:** poll `/jobs/{id}` and check `status == "error"` + the `error` string; HTTP 4xx for
bad input (e.g. malformed `size`), 404 for an unknown job or an image not yet ready.
|