Overview
Document ingestion is handled by the document transcoder insrc/transcode/ — document.hpp / document.cpp. It decomposes an uploaded PDF or spreadsheet into an ordered list of LLM-consumable parts (text and/or images), strategy “text first, image (and OCR) fallback.” For the conceptual walkthrough see File Processing.
The document transcoder decomposes an uploaded document into text and image parts that a vision-capable LLM reads during the chat turn. (verify upload wiring against the current HTTP layer.)
Supported formats & build gates
Format is sniffed from magic bytes (detect_format), then routed:
With a gate off, the format still sniffs but
process() throws DocumentError("... not built").
The API
What each path emits
- PDF, text page → a
Textpart with the extracted text layer. - PDF, scanned page (text below
pdf_text_threshold) → rasterized atraster_dpi, PNG-encoded, run throughimage::Transcoderto fitimage_limits, emitted as anImagepart. In aMIROBODY_ENABLE_OCRbuild the same raster is also OCR’d and the recovered text appended as aTextpart. - .xlsx / .xls → one
Textpart per worksheet, a GitHub-flavored Markdown table (## <sheet title>+ table). Never an image. - .csv → a single
Textpart (RFC 4180 parse → Markdown table; UTF-8 BOM stripped).
to_markdown() flattens a Document: text parts inline, image parts as a  placeholder line.
Threading (PDF)
PDFium’s library init/teardown is process-global and not thread-safe, and a loaded document may not be touched concurrently. The PDF path serializes all PDFium work behind an internal mutex and owns the one-time global init, soTranscoder is safe to call from multiple threads — PDF work simply isn’t parallel while a PDF is being processed. CSV / xlsx have no such constraint.
Try it — the document CLI
The cli/document.cpp tool (built when MIROBODY_BUILD_TOOLS is ON) exercises the transcoder end to end:
<out>; text parts land in the Markdown. --target picks the vision preset for rasterized pages (default qwen).
Units
Values pulled from documents can be normalized to UCUM with the units engine (src/fhir/units/) — see Data Mapping.
Tests
tests/transcode/document_test.cpp, tests/transcode/file_test.cpp, tests/transcode/image_test.cpp, and tests/fhir/units_test.cpp (Catch2). Run the transcoder subset:
Writing extracted values back to the FHIR store as coded
Observations (the document → indicator → FHIR pipeline) is in progress — the transcoder and UCUM normalization ship; terminology mapping and write-back are planned (src/fhir/README.md phases 3–4). (verify)Next steps
File Processing (concept)
The pipeline at a glance
Data Flow
Where uploads fit
Data Mapping
UCUM normalization
Testing
Run the transcoder tests