Skip to content

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.

MethodPathNotes
POST/v1/recognitionsSync by default. Returns 200 with the SGF on completion.
POST/v1/recognitions?async=trueReturns 202 with { id, status: "queued" }.
GET/v1/recognitions/:idStatus check.
GET/v1/recognitions/:id/resultFinal SGF.

Sync mode times out at ~30 s; long-running photos should use ?async=true.

Terminal window
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.

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.

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.

Terminal window
cd apps/weiqi-server
docker compose --profile recognition up -d # spins up the service on :4010

Or run the Node process directly:

Terminal window
pnpm --dir apps/recognition-service dev

The first boot will download the moku-v3 ONNX model — make sure outbound HTTPS is available.

Terminal window
pnpm --dir apps/recognition-service test

Suite covers the pre-processing pipeline with fixture images; the model itself is not retrained in tests.