#!/usr/bin/env bash
set -euo pipefail

export SURYA_MODEL_CHECKPOINT="${SURYA_MODEL_CHECKPOINT:-datalab-to/surya-ocr-2}"
export SURYA_INFERENCE_BACKEND="${SURYA_INFERENCE_BACKEND:-vllm}"
export SURYA_INFERENCE_URL="${SURYA_INFERENCE_URL:-http://127.0.0.1:8000/v1}"
export SURYA_INFERENCE_AUTOSTART="${SURYA_INFERENCE_AUTOSTART:-false}"
export SURYA_INFERENCE_PARALLEL="${SURYA_INFERENCE_PARALLEL:-8}"
export SURYA_INFERENCE_LOGPROBS="${SURYA_INFERENCE_LOGPROBS:-false}"
export SURYA_INFERENCE_MAX_RETRIES="${SURYA_INFERENCE_MAX_RETRIES:-1}"
# Keep in sync with VLLM_MAX_NUM_SEQS so the batcher fills every vLLM sequence
# slot (see docs/diagnosis_baseline.md). Overcommitting past it only queues.
export SURYA_INFERENCE_MAX_INFLIGHT="${SURYA_INFERENCE_MAX_INFLIGHT:-16}"
export SURYA_MAX_TOKENS_FULL_PAGE="${SURYA_MAX_TOKENS_FULL_PAGE:-6144}"
export SURYA_MAX_BLOCKS_PER_PAGE="${SURYA_MAX_BLOCKS_PER_PAGE:-80}"
export SUYA_OCR_MODE="${SUYA_OCR_MODE:-block}"
export SUYA_MAX_BATCH_SIZE="${SUYA_MAX_BATCH_SIZE:-8}"
export SUYA_BATCH_WAIT_MS="${SUYA_BATCH_WAIT_MS:-25}"
export SUYA_VLLM_IMAGE_FORMAT="${SUYA_VLLM_IMAGE_FORMAT:-JPEG}"
export SUYA_VLLM_JPEG_QUALITY="${SUYA_VLLM_JPEG_QUALITY:-92}"
export VLLM_DTYPE="${VLLM_DTYPE:-float16}"
export VLLM_GPU_MEMORY_UTILIZATION="${VLLM_GPU_MEMORY_UTILIZATION:-0.85}"
export VLLM_MAX_MODEL_LEN="${VLLM_MAX_MODEL_LEN:-18000}"
export VLLM_MAX_NUM_SEQS="${VLLM_MAX_NUM_SEQS:-16}"
export VLLM_MAX_BATCHED_TOKENS="${VLLM_MAX_BATCHED_TOKENS:-4096}"

# vLLM serving parameters are tuned for latency — see
# docs/quantization_benchmark_results.md §5 (A100, BF16). Three flags carry the
# win and MUST stay on; do not pass their negations via VLLM_EXTRA_ARGS:
#   --no-enforce-eager      CUDA-graph capture. The single biggest lever: eager
#                           mode (--enforce-eager) measured ~9.5x slower
#                           (48.97s vs 5.15s/page). Set explicitly so a future
#                           vLLM default flip can't silently disable graphs.
#   --enable-prefix-caching ~15% win; OCR prompts share a long fixed prefix.
#   chunked prefill (on by default) is REQUIRED — the qwen3_5 mamba/SSM cache
#                           fails engine init with --no-enable-chunked-prefill.
python3 -m vllm.entrypoints.openai.api_server \
  --host 127.0.0.1 \
  --port 8000 \
  --model "${SURYA_MODEL_CHECKPOINT}" \
  --served-model-name "${SURYA_MODEL_CHECKPOINT}" \
  --dtype "${VLLM_DTYPE}" \
  --max-model-len "${VLLM_MAX_MODEL_LEN}" \
  --max-num-seqs "${VLLM_MAX_NUM_SEQS}" \
  --max-num-batched-tokens "${VLLM_MAX_BATCHED_TOKENS}" \
  --gpu-memory-utilization "${VLLM_GPU_MEMORY_UTILIZATION}" \
  --no-enforce-eager \
  --enable-prefix-caching \
  --mm-processor-kwargs '{"min_pixels":3136,"max_pixels":6291456}' \
  ${VLLM_EXTRA_ARGS:-} &
VLLM_PID=$!

cleanup() {
  kill "${VLLM_PID}" 2>/dev/null || true
}
trap cleanup EXIT INT TERM

python3 - <<'PY'
import os
import time
import urllib.request

base = os.environ.get("SURYA_INFERENCE_URL", "http://127.0.0.1:8000/v1")
health = base[:-3] + "/health" if base.endswith("/v1") else base.rstrip("/") + "/health"
deadline = time.time() + float(os.environ.get("SURYA_INFERENCE_STARTUP_TIMEOUT", "900"))
while time.time() < deadline:
    try:
        with urllib.request.urlopen(health, timeout=2) as response:
            if response.status == 200:
                print(f"vLLM health check passed: {health}", flush=True)
                raise SystemExit(0)
    except Exception:
        time.sleep(2)
raise SystemExit(f"vLLM did not become healthy: {health}")
PY

python3 api.py
