Play Da Vinci Code against a trained AI. A FastAPI + SSE server for real-time human-vs-AI (and PvP) matches, plus a zero-backend browser demo where the policy net runs entirely client-side via ONNX.
- Play in your browser → — the trained policy runs 100% client-side (ONNX + onnxruntime-web). No install, no backend.
- Self-host the full server — one
docker run(see Run the server). Real-time PvP + AI matches over SSE.
The model is trained in a separate repo: davinci-code-agent (PPO self-play).
Table of contents
┌─────────────────────────────────────────────┐
Browser ── REST ───────► │ FastAPI ─► GameService ─► GameManager │
◄── SSE ─────── │ router (facade) └─► GameSession │
(event stream) │ └─► GameEngine (rules)
│ model_loader ─► policy net
└─────────────────────────────────────────────┘
Static demo (docs/, GitHub Pages): Browser ─► model.onnx (onnxruntime-web) [no server]
- Full server (
/): REST actions + an SSE stream push game events in real time; the AI plays via the loaded PyTorch policy. Supports PvP and vs-AI. - Browser demo (
docs/): the game rules are ported to JS and the policy runs as ONNX in the browser — same gameplay, no backend. Deployed to GitHub Pages.
The published image bakes the model in — just pull and run (no mount, no download):
docker pull ghcr.io/rocknroll17/davinci-code-server:latest
# The container always listens on 6000; choose any free host port.
PORT="${PORT:-6000}"
docker run -d --gpus all \
--name davinci-server \
--restart unless-stopped \
-p "${PORT}:6000" \
ghcr.io/rocknroll17/davinci-code-server:latestOpen http://localhost:${PORT}. --gpus all runs inference on the GPU (needs the
NVIDIA Container Toolkit);
drop it to fall back to CPU.
Requires Python 3.10.
python3.10 -m venv venv && source venv/bin/activate
pip install -r requirements.txt
# Fetch the model (it is not in git — see "The model" below)
oras pull ghcr.io/rocknroll17/davinci-model:latest -o checkpoints
python run.py # serves http://0.0.0.0:6000The model is not stored in git. It is versioned independently as a GHCR OCI artifact — the source of truth — because it changes on its own cadence (retraining):
ghcr.io/rocknroll17/davinci-model:<version> (+ :latest)
The release build (release.yml) pulls it with
ORAS and bakes it into the server image, so the deployable image is
self-contained. Publish a new model with scripts/publish_model.sh:
echo "$GHCR_TOKEN" | oras login ghcr.io -u <user> --password-stdin # needs write:packages
scripts/publish_model.sh checkpoints/model.pt 0.3.0 # pushes :0.3.0 and :latestPin which model a build bakes via the repo variable MODEL_TAG (default latest).
An "AI Lab" page (/ai) visualizes what the model attends to and its belief over the
opponent's hidden cards. It's off by default (production = clean game operation) and
gated behind a flag:
ENABLE_REASONING=true python run.py # serves the /ai Lab + reasoning SSEWith the flag off, the AI just plays — no reasoning extraction, no /ai route.
Interactive docs at /docs (FastAPI). Key endpoints:
| Method | Path | Description |
|---|---|---|
POST |
/new |
Create a PvP game |
POST |
/new/vs-ai?use_model=true |
Create a vs-AI game (false = random agent) |
POST |
/join |
Join an existing game |
GET |
/waiting |
List waiting games |
| Method | Path | Description |
|---|---|---|
POST |
/draw |
Draw a card (choose color) |
POST |
/place |
Place the drawn card |
POST |
/guess |
Guess an opponent card |
POST |
/decision |
Continue or stop after a correct guess |
POST |
/state |
Get game state |
POST |
/reasoning_ack |
Ack the AI-reasoning overlay (Lab only) |
GET |
/events |
SSE event stream (?game_id=&player_id=) |
SSE events: game_start, my_action, opponent_action, turn_change, deck_update,
game_over (+ ai_reasoning when the Lab is enabled).
| Path | Description |
|---|---|
GET / |
Web game client |
GET /ai |
AI Lab (only when ENABLE_REASONING=true) |
GET /static/* |
Static assets |
Override via environment or a .env file (app/core/config.py):
| Variable | Default | Description |
|---|---|---|
HOST |
0.0.0.0 |
Bind host |
PORT |
6000 |
Bind port |
CHECKPOINT_PATH |
checkpoints/model.pt |
Model checkpoint path |
ENABLE_REASONING |
false |
Enable the /ai Lab + reasoning SSE |
run.py Server entry point (uvicorn)
app/
main.py FastAPI app (routers, middleware, lifespan)
core/ config.py · model_loader.py · exceptions.py
api/ lobby.py · game.py · sse.py
services/ game_service · game_manager · game_session · game_engine · player
schemas/ request/response · emitters/ (SSE) · results/ · observation
game/ model.py (policy net) · deck · hand · constants · cards/
static/ index.html · game.js · style.css · ai_game.{html,css,js}
docs/ Static in-browser ONNX demo (index.html · engine.js · model.onnx) → Pages
scripts/ export_onnx.py · publish_model.sh · ci_smoke.py