How to Use the Chandra Streamlit App for Interactive Single-Page Document Processing
The Chandra Streamlit app provides a lightweight web interface that lets you run layout-aware OCR on single PDF pages or images using either local Hugging Face models or remote vLLM servers, with instant visualization of text, layout, and markdown output.
The datalab-to/chandra repository ships with a built-in Streamlit application designed for rapid, interactive testing of layout-aware OCR capabilities. Whether you need to process a single page from a multi-page PDF or analyze a standalone image, the Chandra Streamlit app offers a modular architecture that separates UI concerns from model inference and document parsing. This guide walks through launching the interface, understanding its underlying components, and extending its functionality for custom workflows.
Launching the Chandra Streamlit Interface
Before starting the app, ensure all dependencies are installed from the repository root. The requirements include Streamlit, pypdfium2, Pillow, and the core Chandra package.
pip install -r requirements.txt
You can launch the application using two methods. The recommended approach uses the convenience wrapper in chandra/scripts/run_app.py, which configures headless server settings automatically:
python -m chandra.scripts.run_app
Alternatively, invoke Streamlit directly for custom flag configurations:
streamlit run chandra/scripts/app.py --server.headless true --server.fileWatcherType none
The wrapper script sets critical deployment flags including --server.headless and disables the file watcher to prevent reload loops in containerized environments.
Navigating the User Interface
The front-end logic resides in chandra/scripts/app.py, which implements a clean sidebar-and-tabs layout typical of data-science tools.
File Upload and Page Selection
The sidebar accepts both PDF documents and image files. For PDFs, the app uses page_counter and load_pdf_images from chandra/input.py to render specific pages as PIL Image objects using pypdfium2. A numeric input lets you jump to any page index, and the selected page renders instantly in the main view.
Model Backend Selection
Users choose between two inference modes via a dropdown:
hf: Loads a Hugging Face model locally using theInferenceManagervllm: Connects to a remote vLLM server endpoint
The app lazily instantiates the model through a cached load_model function decorated with @st.cache_resource, ensuring the heavy model weights stay in memory across interactions.
Result Tabs
After processing, the interface presents three tabs:
- Rendered HTML: Visual preview of the extracted content
- Raw Markdown: The parsed text with embedded base-64 images
- Layout Visualization: The original image overlaid with bounding boxes generated by
draw_layoutinchandra/util.py
Understanding the Architecture
The Chandra Streamlit app delegates all heavy lifting to specialized modules, making the codebase maintainable and testable outside the UI context.
The InferenceManager Abstraction
Located in chandra/model/__init__.py, the InferenceManager class provides a unified interface over heterogeneous backends. When you select a mode in the UI, the app invokes:
model = InferenceManager(method="hf") # or method="vllm"
This abstraction handles tokenizer loading, batching, and generation parameters internally, exposing a single generate() method that accepts a list of BatchInputItem objects.
Document Input Handling
The input pipeline in chandra/input.py distinguishes between PDF and image sources:
- PDF pages:
load_pdf_images(pdf_path, page_indices)renders specified pages as high-resolution PIL images - Images: Loaded directly via Pillow for immediate processing
The selected page passes to the OCR engine as a BatchInputItem instance, defined in chandra/model/schema.py, which encapsulates the image tensor and metadata like prompt_type="ocr_layout".
OCR Pipeline and Output Generation
The core processing loop follows this sequence:
- Layout Detection: The model generates structured layout data parsed by
parse_layout - Visualization:
draw_layoutoverlays bounding boxes on the source image - Content Extraction:
parse_markdown,parse_html, andextract_imagesinchandra/output.pyconvert raw tokens into usable formats - Image Embedding:
embed_images_in_markdowntransforms extracted figures into base-64 data-URLs, ensuring self-contained markdown files that render correctly in Streamlit
Results remain cached via @st.cache_data to prevent redundant reprocessing when users switch between visualization tabs.
Processing Documents Programmatically
While the Streamlit UI excels for quick inspections, you can replicate its functionality in scripts for batch automation. The same components power both interfaces:
from chandra.model import InferenceManager
from chandra.input import load_pdf_images
from chandra.model.schema import BatchInputItem
from PIL import Image
# Initialize the backend (local Hugging Face)
model = InferenceManager(method="hf")
# Load a specific PDF page as a PIL image
pdf_path = "document.pdf"
page_image = load_pdf_images(pdf_path, page_indices=[2])[0]
# Construct input batch and run OCR
input_item = BatchInputItem(image=page_image, prompt_type="ocr_layout")
results = model.generate([input_item])
# Access structured outputs
result = results[0]
print(result.markdown) # Extracted text with formatting
print(result.html) # HTML representation
# result.images contains extracted visual elements
This pattern mirrors the internal logic of chandra/scripts/app.py, allowing you to build custom pipelines while leveraging the same caching and error-handling strategies.
Customizing the Deployment
For production deployments or Docker containers, modify chandra/scripts/run_app.py to adjust server bindings or authentication. The default configuration disables CORS and enables headless mode suitable for reverse-proxy setups. You can override these by passing additional arguments through the module invocation or by setting environment variables before importing Streamlit.
Summary
- The Chandra Streamlit app in
chandra/scripts/app.pyprovides an interactive interface for single-page OCR with support for both local Hugging Face models and remote vLLM servers. InferenceManagerabstracts backend complexity, while caching decorators ensure efficient resource utilization across user interactions.- Input handling relies on
load_pdf_imagesfromchandra/input.pyfor PDF rendering and standard Pillow loaders for images. - The output pipeline in
chandra/output.pyconverts raw model predictions into markdown, HTML, and visual layout overlays, withembed_images_in_markdownensuring self-contained export files. - Launch the app via
python -m chandra.scripts.run_appor direct Streamlit commands, using the provided wrapper for optimal server configuration.
Frequently Asked Questions
How does the Chandra Streamlit app handle multi-page PDFs?
The app processes one page at a time interactively. The sidebar provides a page selector that passes specific indices to load_pdf_images in chandra/input.py, rendering only the requested page as a PIL image. While the UI focuses on single-page inspection, you can automate batch processing by calling InferenceManager.generate() in a loop over multiple BatchInputItem instances programmatically.
What is the difference between the "hf" and "vllm" modes in the app?
The "hf" mode loads models directly from Hugging Face using local GPU/CPU resources through the InferenceManager class, suitable for workstations with sufficient VRAM. The "vllm" mode connects to a remote vLLM inference server, enabling distributed processing or usage of larger models hosted on separate infrastructure. Both modes use identical input schemas and output parsers defined in chandra/model/schema.py.
Can I export the OCR results without using the web interface?
Yes. The underlying functions in chandra/output.py—including parse_markdown, parse_html, and extract_images—operate independently of Streamlit. You can generate BatchInputItem objects, call model.generate(), and save the resulting markdown or HTML to disk. The embed_images_in_markdown utility ensures extracted figures remain visible in the exported files by encoding them as base-64 data-URLs.
Where is the layout visualization generated in the codebase?
The visual overlay showing bounding boxes appears in the third tab of the Streamlit interface, generated by the draw_layout function located in chandra/util.py. This function takes the raw layout coordinates from the model output and renders them on the source PIL image using standard drawing primitives, returning an annotated image suitable for immediate display or download.
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 →