From 3a7a57a3c6004e58e75c6688d555e26b13243a21 Mon Sep 17 00:00:00 2001 From: artiz Date: Fri, 24 Jul 2026 06:24:30 +0000 Subject: [PATCH] dev: full OpenAI response schema in the VLM shim (#153) Python docling validates chat-completion responses with a pydantic OpenAiApiResponse model that requires id/created (and reads usage); the shim payload lacked them, so the reference side of the corpus run failed on every request while docling.rs (which only reads choices[0]) worked. Emit the full envelope. Refs #153 Signed-off-by: artiz Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01EY5KAiquN4YpVf2PXEQkVT --- scripts/dev/granite_vlm_server.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/scripts/dev/granite_vlm_server.py b/scripts/dev/granite_vlm_server.py index 66caa641..e170553c 100644 --- a/scripts/dev/granite_vlm_server.py +++ b/scripts/dev/granite_vlm_server.py @@ -105,9 +105,14 @@ def do_POST(self): # noqa: N802 (http.server API) int(req.get("max_tokens", 8192)), ) print(f"page converted in {time.time() - started:.1f}s, {len(text)} chars", flush=True) + # id/created/usage: Python docling validates the response against a + # full OpenAI schema (pydantic OpenAiApiResponse) and rejects a + # payload without them; docling.rs only reads choices[0]. payload = json.dumps( { + "id": f"chatcmpl-{int(time.time() * 1000)}", "object": "chat.completion", + "created": int(time.time()), "model": req.get("model", "granite-docling"), "choices": [ { @@ -116,6 +121,11 @@ def do_POST(self): # noqa: N802 (http.server API) "finish_reason": "stop", } ], + "usage": { + "prompt_tokens": 0, + "completion_tokens": 0, + "total_tokens": 0, + }, } ).encode() self.send_response(200)