Understanding the Relationship Between Chandra's BatchInputItem and BatchOutputItem Schemas
BatchInputItem and BatchOutputItem form a strict one-to-one request-response pair in Chandra's inference pipeline, where each input item containing an image and optional prompt is transformed by the model into a corresponding output item containing parsed markdown, HTML, bounding boxes, and generation metadata.
In the datalab-to/chandra repository, these two dataclasses define the complete lifecycle of a single document processing operation. Understanding how BatchInputItem and BatchOutputItem relate to each other is essential for implementing custom batch inference workflows or integrating the model into production pipelines.
BatchInputItem and BatchOutputItem Schema Overview
The Input Schema: BatchInputItem
BatchInputItem defines everything the model requires to process a single document. Located in chandra/model/schema.py, this dataclass encapsulates the source image and optional guidance parameters.
image(Image.Image): The source document or page provided as a PIL Image.prompt(str | None): Optional user instructions to guide generation.prompt_type(str | None): Strategy identifier such as"ocr_layout"or"ocr"that controls how the model interprets the image.
The Output Schema: BatchOutputItem
BatchOutputItem captures the complete result set generated for each input. Also defined in chandra/model/schema.py, it contains both rendered formats and raw metadata extracted during inference.
markdown(str): Rendered markdown representation of the document content.html(str): Rendered HTML version of the output.chunks(dict): Bounding-box text fragments parsed from the raw output.raw(str): Unprocessed model output string.page_box(List[int]): Image dimensions formatted as[0, 0, width, height].token_count(int): Number of tokens consumed during generation.images(dict): Extracted images discovered within the output.error(bool): Flag indicating whether generation failed for this item.
How InferenceManager Maps Input to Output
The relationship between these schemas is implemented as a positional transformation inside InferenceManager.generate in chandra/model/__init__.py. The method receives a list of BatchInputItem objects and returns a corresponding list of BatchOutputItem objects, maintaining index alignment throughout the pipeline.
Input Collection
Users or client code construct a Python list of BatchInputItem instances, as demonstrated in tests/integration/test_image_inference.py and the CLI entry point at chandra/scripts/cli.py. Each item bundles the image data with optional prompt configuration.
Processing and Generation
Inside InferenceManager.generate, the batch is submitted to either the VLLM or HuggingFace backend. The system iterates over the input list, generating a GenerationResult for each BatchInputItem through the underlying model inference.
Output Construction
The critical linkage occurs where the code zips results with their originating inputs. For each pair, the method constructs a BatchOutputItem that combines the raw generation result with metadata derived from the original input image:
# From chandra/model/__init__.py - InferenceManager.generate
for result, input_item in zip(results, batch):
chunks = parse_chunks(result.raw, input_item.image, bbox_scale=bbox_scale)
output.append(
BatchOutputItem(
markdown=parse_markdown(result.raw, **output_kwargs),
html=parse_html(result.raw, **output_kwargs),
chunks=chunks,
raw=result.raw,
page_box=[0, 0, input_item.image.width, input_item.image.height],
token_count=result.token_count,
images=extract_images(result.raw, chunks, input_item.image),
error=result.error,
)
)
Notice how page_box explicitly references input_item.image.width and input_item.image.height, demonstrating that output metadata is enriched with properties from the corresponding input item. The chunks and images fields also depend on both the generation result and the original image dimensions.
Practical Batch Processing Example
The following implementation illustrates the complete flow from input definition to output consumption:
from chandra.model.schema import BatchInputItem, BatchOutputItem
from chandra.model import InferenceManager
from PIL import Image
# 1️⃣ Build a batch of inputs
batch = [
BatchInputItem(
image=Image.open("sample_page.png"),
prompt="Summarize the table on page 1",
prompt_type="ocr_layout",
),
BatchInputItem(
image=Image.open("invoice.jpg"),
prompt=None,
prompt_type="ocr",
),
]
# 2️⃣ Run inference (VLLM is the default backend)
manager = InferenceManager(method="vllm")
outputs: list[BatchOutputItem] = manager.generate(batch)
# 3️⃣ Access the paired output
for inp, out in zip(batch, outputs):
print("Input image size:", inp.image.size)
print("Generated Markdown:", out.markdown[:200])
print("Token count:", out.token_count)
print("---")
This example demonstrates the one-to-one correspondence: the first output corresponds to the first input (the table summarization), and the second output corresponds to the second input (the OCR-only invoice processing).
Key Implementation Files
Understanding the relationship between these schemas requires examining four critical files in the datalab-to/chandra repository:
-
chandra/model/schema.py: Defines the dataclass structures for bothBatchInputItemandBatchOutputItem, including type hints and default values. -
chandra/model/__init__.py: ContainsInferenceManager.generate, the core method that implements the input-to-output mapping logic and constructsBatchOutputIteminstances from generation results. -
tests/integration/test_image_inference.py: Provides integration test cases showing howBatchInputItemobjects are instantiated and passed through the inference pipeline. -
chandra/scripts/cli.py: Command-line interface implementation demonstrating batch construction from file paths and argument parsing.
Summary
- BatchInputItem and BatchOutputItem maintain a strict one-to-one positional relationship throughout the inference pipeline.
- Input items carry the source image and optional prompts, while output items contain parsed markdown, HTML, bounding box chunks, and generation metadata.
- The mapping is implemented in
InferenceManager.generateinsidechandra/model/__init__.py, where each output explicitly references properties of its corresponding input (such as image dimensions). - Index alignment is preserved through Python's
zip()function, ensuring thatoutputs[i]always corresponds tobatch[i].
Frequently Asked Questions
How does Chandra ensure each BatchOutputItem corresponds to the correct BatchInputItem?
Chandra maintains index alignment through positional iteration. In InferenceManager.generate, the code uses zip(results, batch) to pair each generation result with its originating input item at the same list index. This positional mapping guarantees that the first output corresponds to the first input, the second to the second, and so on, without requiring unique identifiers.
Can I access the original input image from a BatchOutputItem?
No, BatchOutputItem does not store a reference to the input image object directly. However, it stores the original image dimensions in the page_box field (formatted as [0, 0, width, height]), which is extracted from input_item.image during output construction. If you need the full image, you must maintain a separate reference to your original BatchInputItem list and access it by index.
What happens if one item in the batch fails during generation?
The BatchOutputItem includes an error boolean field that indicates whether generation failed for that specific item. When an error occurs, the raw field typically contains error details while other fields like markdown and html may be empty strings. The remaining items in the batch continue processing normally, preserving the one-to-one relationship between inputs and outputs even for failed generations.
Where are the BatchInputItem and BatchOutputItem schemas defined?
Both dataclasses are defined in chandra/model/schema.py. The input schema contains fields for image, prompt, and prompt_type, while the output schema contains markdown, html, chunks, raw, page_box, token_count, images, and error. These definitions use Python dataclasses with type hints for validation and IDE support.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →