recognition-service
apps/recognition-service is the internal microservice that turns a photo of
a Go board into an SGF. It runs the moku-v3 ONNX model on top of
onnxruntime-node, pre-processes the image (auto-invert for dark boards),
and either returns the result inline or queues it for later fetch.
Endpoints
Section titled “Endpoints”| Method | Path | Notes |
|---|---|---|
| POST | /v1/recognitions | Sync by default. Returns 200 with the SGF on completion. |
| POST | /v1/recognitions?async=true | Returns 202 with { id, status: "queued" }. |
| GET | /v1/recognitions/:id | Status check. |
| GET | /v1/recognitions/:id/result | Final SGF. |
Sync mode times out at ~30 s; long-running photos should use ?async=true.
Sync request
Section titled “Sync request”curl -s -X POST http://localhost:4010/v1/recognitions \ -F "image=@/path/to/board.jpg"Response shape (success):
{ "id": "rec_01HZ...", "status": "completed", "sgf": "(;FF[4]GM[1]CA[UTF-8]SZ[19]... )", "moves": [["B", "pd"], ["W", "dp"], ...], "boardSize": 19, "confidence": 0.94}The inference engine is src/adapters/inference/moku-v3.engine.ts:1. Constants
live in moku-v3.constants.ts:
MOKU_V3_MODEL_URL— URL the engine downloads the model from on first boot.MOKU_V3_MODEL_INPUT_SIZE— square input dimension (e.g.224).MOKU_V3_MIN_THRESHOLD— minimum cell-level confidence to count as a stone.
The model is cached on disk after the first download. Subsequent boots skip the network entirely.
Image pre-processing
Section titled “Image pre-processing”maybeInvertDarkImage (src/adapters/inference/moku-v3.engine.ts, see also
src/recognition/recognition.processor.ts) detects dark boards (low mean
luminance) and inverts the channels before inference. This lets users upload
photos of black-wood boards without manually cropping or rotating.
BullMQ + Redis
Section titled “BullMQ + Redis”Long-running jobs go through BullMQ. The service uses a separate Redis
instance from the bot pipeline; REDIS_URL points at the standard local
Redis on 6379.
The service allows http://localhost:3001 by default
(src/main.ts:11). For staging, add the staging origin to the allow-list.
The gateway (weiqi-server) calls this service server-to-server — CORS does
not apply on that path.
None at the network layer today. The service is intended to be reached only
from weiqi-server over the private network. If you expose it to a less
trusted environment, add a shared-secret header check in the controller.
Local dev
Section titled “Local dev”cd apps/weiqi-serverdocker compose --profile recognition up -d # spins up the service on :4010Or run the Node process directly:
pnpm --dir apps/recognition-service devThe first boot will download the moku-v3 ONNX model — make sure outbound HTTPS is available.
pnpm --dir apps/recognition-service testSuite covers the pre-processing pipeline with fixture images; the model itself is not retrained in tests.