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 both BatchInputItem and BatchOutputItem, including type hints and default values.

  • chandra/model/__init__.py: Contains InferenceManager.generate, the core method that implements the input-to-output mapping logic and constructs BatchOutputItem instances from generation results.

  • tests/integration/test_image_inference.py: Provides integration test cases showing how BatchInputItem objects 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.generate inside chandra/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 that outputs[i] always corresponds to batch[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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →