Play against the compact <1M-param chess transformer in the browser. The app is
a thin Flask frontend; ALL engine behavior (model, quantization, MCTS search,
per-game tree reuse) lives in the engine repo compact_chess_transformers.
The app talks to the engine through exactly one class:
from engine.app_predictor import EnginePredictor # engine repo, on CCT_ENGINE_PATH
predictor = EnginePredictor(MODEL_PATH, threads=ORT_THREADS)
move, info = predictor.get_move(board, nodes=1000, game_id=gid)
predictor.drop_game(gid)info = {win_prob_white, nodes, depth, time}. nodes is the strength slider
(fixed eval budget, 0 = greedy policy). Nothing else crosses the boundary: the
app never imports search/model internals, the engine never imports Flask.
Environment:
CCT_ENGINE_PATH— engine repo root (default/opt/cct= the Docker mount)MODEL_PATH— ONNX checkpoint (default: the current ship int8 model under$CCT_ENGINE_PATH/onnx_models/);m=CANON*models are auto-wrapped by the engine (STM canonicalization)ORT_THREADS,APP_PASSWORD(empty = no auth)
/chess-app
├── app.py # Flask routes: /start /move /ai (+ auth, game eviction)
├── templates/, static/ # board UI (chessboard.js, jquery)
├── Dockerfile # 2-stage: chesscore wheel build, then app + engine subset
├── deploy.sh # stages ./engine-repo from the engine checkout, syncs, builds
└── requirements.txt # flask/gunicorn + engine runtime deps (torch-cpu, ORT-OpenVINO)
./engine-repo/ is generated by deploy.sh (gitignored): engine/,
data_processing/, config.py, chesscore/ (built in the Docker builder
stage) and the single ONNX model file (MODEL_FILE env to override).
CCT_ENGINE_PATH=~/Dev/compact_chess_transformers python app.py(needs the engine conda env or equivalent: torch, onnxruntime-openvino, python-chess, numpy + the chesscore wheel — see the engine repo's README)
./deploy.sh # rsync to the server + docker build + restart
MODEL_FILE=chess_transformer_m=CANON65_FEAT16_legalmask_ds=M.nncf-int8.onnx ./deploy.sh