• Stefy Lanza (nextime / spora )'s avatar
    ocr: recover surya's accents on vLLM 0.27.1 from the token IDS (v0.3.31) · 3353ac28
    Stefy Lanza (nextime / spora ) authored
    The byte channel is a dead end on 0.27.1 -- measured: `content` comes back with
    one U+FFFD per accented letter AND the per-token `bytes` come back EMPTY (257 of
    them on one page, no byte >= 0x80 anywhere), so neither output carries the
    character. But the token IDS are not lossy, and surya's OWN tokenizer decodes
    them correctly: decode([2131, 2104]) == 'e-grave', measured in its venv.
    
    So the repair now asks for ids and decodes them itself, bypassing vLLM's
    detokenizer entirely. Both halves, because each alone does nothing:
    
    1. THE WORKER reads vLLM's `token_id:{id}` form, decodes with surya's tokenizer
       (lazily loaded and cached -- the worker must start while the venv is building,
       and a clean page must not pay for a tokenizer), and keeps the byte route as the
       fallback for any stack that reports bytes honestly. Ids are tried FIRST because
       on 0.27.1 the bytes lead nowhere. All-or-nothing on the id list: a partial one
       would decode to a partial page. The ASCII-skeleton guard still applies, so a
       decode of the wrong call cannot be substituted.
    
    2. THE PROXY stops dropping the request. `return_tokens_as_token_ids` is a
       per-request field on vLLM's ChatCompletionRequest, but sending it to a pod
       changed nothing -- because codai/backends/vllm.py::_chat_payload builds an
       explicit whitelist and silently discarded it. That is exactly the failure its
       own neighbouring comment warns about ("a proxy that edits the request decides
       for it"), five lines further up. Now forwarded, gated on
       `vllm.return_token_ids`, and only alongside logprobs since it describes how
       logprob tokens are rendered.
    
    `vllm.return_token_ids` is off by default (it changes what the `token` field
    looks like, and only this one consumer reads it) and is in VLLM_FIELDS, so the
    single checkpoint with a byte-level vocabulary can ask for ids without changing
    what every other vLLM model reports. A config field rather than relaunching the
    server with --return-tokens-as-token-ids: same effect, no pod rebuild.
    
    This is a fix ON 0.27.1. It makes the coderai-vllm-ocr image (vLLM 0.20.1) a
    CONTROL that confirms the diagnosis rather than the only way out.
    
    tests: +11 in test_ocr_accent_repair.py (36 -> 47) covering the id form, the
    all-or-nothing rule, ids-before-bytes, the fallback when a decode fails, the
    skeleton guard on the id route, and the proxy forwarding with its logprobs
    gating. 912 passed across the ocr/front/config/admin/runpod/vllm/backend
    selection; the 9 failures are pre-existing (broker x6, studio, whisper x2) plus
    test_cluster's RPC check, which depends on llama_cpp being installed in this venv
    and touches nothing changed here.
    Co-Authored-By: 's avatarClaude Opus 5 <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01PxYHWbCAjjjD7A1rhFKtaW
    3353ac28
ocr_worker.py 36.2 KB