Writing
Chandra 2: AI OCR for Construction Documents

Chandra 2: From Blueprints to Data — AI OCR for Construction Documents

The Paper Problem

Walk into any construction trailer and you'll see it: binders of submittals, stacks of RFIs with handwritten notes in the margins, inspection forms with checked boxes and scrawled signatures, daily logs on carbon-copy paper, material delivery tickets crumpled in someone's back pocket.

Construction generates an absurd amount of paper. And even when documents are "digital," they're often just scanned PDFs — images of paper, not actual data. Try searching a scanned submittal for "3/4-inch anchor bolt" and nothing happens, because the computer sees pixels, not text.

This is the document bottleneck. Before any AI agent can process an RFI, analyze a submittal, or extract data from an inspection form, that document needs to be converted from an image (or paper) into structured, searchable data. This conversion process is called OCR — Optical Character Recognition.

And until very recently, OCR was terrible at the kinds of documents construction produces: complex tables, checkboxes, handwritten notes, stamps, multi-column layouts, and drawings with callouts.

Chandra 2 (opens in a new tab) changes this. It's a new open-source OCR model that tops the benchmarks at 85.9% accuracy — and it handles exactly the kinds of messy, complex documents that construction throws at it.


What Is OCR? (And Why It Used to Be Bad)

OCR in 30 Seconds

OCR (Optical Character Recognition) is technology that converts images of text into actual, computer-readable text. When you take a photo of a receipt and your phone can read the total — that's OCR.

Old OCR tools worked like a very literal reader: they scanned left to right, top to bottom, and tried to match shapes to letters. This works fine for a clean printed page. But it falls apart when you have:

  • Tables with merged cells and vertical text
  • Handwritten notes in the margins
  • Checkboxes (is it checked or empty?)
  • Multi-column layouts
  • Stamps, signatures, and watermarks overlapping text
  • Drawings with text callouts at angles

Construction documents have all of these, often on the same page. That's why traditional OCR has been essentially useless for the industry.

Chandra 2 is different because it doesn't just read text — it understands document structure. It recognizes tables, forms, checkboxes, headers, footnotes, and handwritten annotations as distinct elements and preserves their relationships in the output.


What Chandra 2 Can Do

Document TypeTraditional OCRChandra 2
Clean typed letter✅ Works fine✅ Works fine
Specification table with merged cells❌ Garbled mess✅ Structured HTML table
Inspection form with checkboxes❌ Can't detect check states✅ Reads checked/unchecked
Hand-marked drawing with callouts❌ Misses most text✅ Extracts callout text with position
Daily log in pencil on carbon paper❌ Unreadable✅ Reads handwriting in 90+ languages
Submittal with stamp + signature overlay❌ Confused by overlapping elements✅ Separates layers
Multi-column spec page❌ Merges columns incorrectly✅ Preserves column structure

Output formats: Chandra 2 doesn't just give you raw text. It outputs:

  • Structured HTML — tables stay as tables, forms stay as forms
  • Markdown — great for feeding into AI agents
  • JSON — structured data for databases and APIs

Quick Start: Installing Chandra 2

Install the Python Package

pip install chandra-ocr

What You Need

  • Python 3.10+ installed on your computer
  • A GPU is recommended for processing large batches (but CPU works for small jobs)
  • About 4GB of disk space for the model weights (downloaded automatically on first use)

Process Your First Document

from chandra import ChandraOCR
 
# Initialize the model (downloads weights on first run)
ocr = ChandraOCR()
 
# Process a single PDF page
result = ocr.process("submittal_page_1.pdf")
 
# Get structured output
print(result.markdown)    # Human-readable markdown
print(result.html)        # Structured HTML (tables preserved)
print(result.json)        # Machine-readable JSON

Process a Stack of Documents

from chandra import ChandraOCR
from pathlib import Path
 
ocr = ChandraOCR()
 
# Process every PDF in a folder
submittal_dir = Path("~/submittals/mechanical/")
for pdf in submittal_dir.glob("*.pdf"):
    result = ocr.process(str(pdf))
 
    # Save structured output alongside the original
    output_path = pdf.with_suffix(".md")
    output_path.write_text(result.markdown)
 
    print(f"Processed: {pdf.name}{output_path.name}")

Construction Use Cases

1. Submittal Processing Pipeline

Submittals are the #1 document bottleneck on most projects. Subcontractors send product data sheets (often scanned PDFs), the GC reviews them, and the architect approves or rejects them. This cycle can involve hundreds of documents per project.

from chandra import ChandraOCR
import json
 
ocr = ChandraOCR()
 
def process_submittal(pdf_path: str, spec_requirements: dict) -> dict:
    """Process a submittal and check against spec requirements."""
 
    # Step 1: Extract structured data from the submittal
    result = ocr.process(pdf_path)
    submittal_data = result.json
 
    # Step 2: Compare against specification requirements
    discrepancies = []
    for field, required_value in spec_requirements.items():
        actual_value = submittal_data.get(field)
        if actual_value and actual_value != required_value:
            discrepancies.append({
                "field": field,
                "specified": required_value,
                "submitted": actual_value,
                "status": "NON-COMPLIANT"
            })
 
    return {
        "submittal": pdf_path,
        "extracted_data": submittal_data,
        "discrepancies": discrepancies,
        "recommendation": "REJECT" if discrepancies else "APPROVE"
    }
 
# Example: Check a valve submittal against specs
spec = {
    "pressure_rating": "200 PSI",
    "material": "316 Stainless Steel",
    "size": "3/4 inch"
}
 
result = process_submittal("valve_submittal_042.pdf", spec)
print(json.dumps(result, indent=2))

2. Inspection Form Digitization

Inspection forms are filled out on-site, often with checkboxes, handwritten notes, and signatures. Chandra 2 reads all of these:

from chandra import ChandraOCR
 
ocr = ChandraOCR()
 
# Process a scanned inspection form
result = ocr.process("safety_inspection_march_25.pdf")
 
# Chandra 2 understands form structure
# Output includes checkbox states:
# {
#   "form_title": "Daily Safety Inspection",
#   "date": "2026-03-25",
#   "inspector": "Mike Rodriguez",
#   "items": [
#     {"check": "Fall protection in place", "status": "checked", "notes": ""},
#     {"check": "Housekeeping acceptable", "status": "unchecked",
#      "notes": "debris in stairwell B - handwritten"},
#     {"check": "PPE compliance", "status": "checked", "notes": ""},
#     {"check": "Fire extinguishers accessible", "status": "checked", "notes": ""}
#   ],
#   "overall_status": "CONDITIONAL PASS",
#   "signature_detected": true
# }

3. Legacy Document Archive Processing

Many construction companies have years of project files sitting in filing cabinets or in boxes of scanned PDFs that have never been made searchable. Chandra 2 can batch-process these into a searchable knowledge base:

from chandra import ChandraOCR
from pathlib import Path
import json
 
ocr = ChandraOCR()
 
def build_project_archive(project_dir: str, output_dir: str):
    """Process all documents in a project folder into searchable data."""
 
    project = Path(project_dir)
    output = Path(output_dir)
    output.mkdir(parents=True, exist_ok=True)
 
    archive_index = []
 
    for doc in project.rglob("*.pdf"):
        print(f"Processing: {doc.name}...")
        result = ocr.process(str(doc))
 
        # Save structured output
        doc_output = {
            "source_file": str(doc),
            "page_count": result.page_count,
            "text_content": result.markdown,
            "tables": result.tables,         # Extracted tables as structured data
            "forms": result.forms,           # Form fields with values
            "handwriting": result.handwriting # Handwritten annotations
        }
 
        output_file = output / f"{doc.stem}.json"
        output_file.write_text(json.dumps(doc_output, indent=2))
 
        archive_index.append({
            "file": doc.name,
            "type": classify_document(result),  # "submittal", "rfi", "daily_log", etc.
            "date": result.detected_date,
            "key_entities": result.entities      # Names, companies, products mentioned
        })
 
    # Save searchable index
    index_file = output / "archive_index.json"
    index_file.write_text(json.dumps(archive_index, indent=2))
    print(f"Archive complete: {len(archive_index)} documents processed")
 
# Process 5 years of project documents
build_project_archive(
    "~/archives/main-st-project/",
    "~/searchable-archives/main-st/"
)

Connecting Chandra 2 to Your AI Agent Pipeline

Chandra 2 is the input layer — it converts documents into data that your AI agents can process. Here's how it fits into the stack:

Example: OpenClaw + Chandra 2

A foreman photographs a delivery ticket and texts it to the OpenClaw field agent on WhatsApp. OpenClaw passes the image through Chandra 2, extracts the vendor, material, quantity, and PO number, and automatically logs the delivery:

# Inside an OpenClaw skill
from chandra import ChandraOCR
 
ocr = ChandraOCR()
 
def process_delivery_photo(image_path: str) -> dict:
    """Extract delivery ticket data from a photo."""
    result = ocr.process(image_path)
 
    # Chandra 2 extracts structured fields from the ticket
    return {
        "vendor": result.json.get("vendor_name"),
        "material": result.json.get("material_description"),
        "quantity": result.json.get("quantity"),
        "po_number": result.json.get("po_number"),
        "delivery_date": result.json.get("date"),
        "received_by": result.json.get("signature_name")
    }

Performance: What to Expect

Document TypeProcessing TimeAccuracy
Clean typed PDF (1 page)~1-2 seconds95%+
Scanned form with checkboxes~2-3 seconds90%+
Handwritten daily log~3-5 seconds80-85%
Complex spec table (multi-page)~2-4 sec/page90%+
Photo of delivery ticket (phone camera)~3-5 seconds85-90%
⚠️

Handwriting Quality Matters

Chandra 2 is impressive with handwriting, but it's not magic. Clean block lettering gives 85%+ accuracy. A superintendent's rushed scrawl at 5 AM might be 60-70%. For critical handwritten documents, always have a human verify the OCR output — especially for numbers (quantities, dollar amounts) where a single digit error matters.


Conclusion

Construction's AI revolution has a prerequisite: the documents need to become data first. You can't build a smart RFI agent if the RFIs are trapped in scanned PDFs. You can't automate submittal review if submittals are just images of product data sheets.

Chandra 2 solves this input problem. It's the bridge between the paper-heavy reality of construction and the data-hungry AI agents that can transform how projects are managed. Open-source, state-of-the-art, and capable of handling the messy, complex documents that define this industry.

Get the documents into data. Then let the agents do their work.