Transcribe a page
OCR has no dedicated endpoint. Send the usual OpenAI-compatiblechat/completions call with a page image and a transcription prompt, at temperature=0.0 with enable_thinking=False. The Markdown comes back in message.content. Client setup is in the Quickstart.
IMAGE_URL = "https://your-host/page.png" # or "data:image/png;base64,..."
OCR_PROMPT = (
"Transcribe this document page to Markdown, preserving the reading order, "
"headings, lists, and tables. Render tables as Markdown tables and equations "
"as LaTeX. Return only the transcription, with no commentary and no surrounding "
"code fence. If the page has no readable text, return an empty string."
)
response = client.chat.completions.create(
model="holo4-35b-a3b",
messages=[{
"role": "user",
"content": [
{"type": "image_url", "image_url": {"url": IMAGE_URL}},
{"type": "text", "text": OCR_PROMPT},
],
}],
temperature=0.0,
extra_body={"chat_template_kwargs": {"enable_thinking": False}},
)
print(response.choices[0].message.content)
const IMAGE_URL = "https://your-host/page.png"; // or "data:image/png;base64,..."
const OCR_PROMPT =
"Transcribe this document page to Markdown, preserving the reading order, " +
"headings, lists, and tables. Render tables as Markdown tables and equations " +
"as LaTeX. Return only the transcription, with no commentary and no surrounding " +
"code fence. If the page has no readable text, return an empty string.";
const response = await client.chat.completions.create({
model: "holo4-35b-a3b",
messages: [
{
role: "user",
content: [
{ type: "image_url", image_url: { url: IMAGE_URL } },
{ type: "text", text: OCR_PROMPT },
],
},
],
temperature: 0.0,
// chat_template_kwargs is H-specific, passed through in the request body
...({ chat_template_kwargs: { enable_thinking: false } } as any),
});
console.log(response.choices[0].message.content);
| Input | Quality |
|---|---|
| English, digitally generated: exported PDFs, slides, web pages, reports | Strongest |
| Scanned pages and photos | Best effort |
| Handwriting, non-Latin scripts | Not a good fit. Use a dedicated OCR system when stakes are high |
Multi-page PDFs
Holo reads images, not PDFs, so rasterize each page to an image and transcribe them one per request, then stitch the results. One page per request keeps each image at full resolution and is the most reliable pattern.import base64
import pymupdf # pip install pymupdf
def ocr_page(png_bytes: bytes) -> str:
data_uri = "data:image/png;base64," + base64.b64encode(png_bytes).decode()
response = client.chat.completions.create(
model="holo4-35b-a3b",
messages=[{
"role": "user",
"content": [
{"type": "image_url", "image_url": {"url": data_uri}},
{"type": "text", "text": OCR_PROMPT},
],
}],
temperature=0.0,
extra_body={"chat_template_kwargs": {"enable_thinking": False}},
)
return response.choices[0].message.content or ""
with pymupdf.open("document.pdf") as doc:
pages = [ocr_page(page.get_pixmap(dpi=200).tobytes("png")) for page in doc]
markdown = "\n\n".join(pages)
print(markdown)
import { pdf } from "pdf-to-img"; // npm install pdf-to-img
async function ocrPage(png: Buffer): Promise<string> {
const dataUri = "data:image/png;base64," + png.toString("base64");
const response = await client.chat.completions.create({
model: "holo4-35b-a3b",
messages: [
{
role: "user",
content: [
{ type: "image_url", image_url: { url: dataUri } },
{ type: "text", text: OCR_PROMPT },
],
},
],
temperature: 0.0,
...({ chat_template_kwargs: { enable_thinking: false } } as any),
});
return response.choices[0].message.content ?? "";
}
const pages: string[] = [];
for await (const page of await pdf("document.pdf", { scale: 2 })) {
pages.push(await ocrPage(page));
}
const markdown = pages.join("\n\n");
console.log(markdown);