Skip to main content

Zero-config schema discovery for document collections. Drop a folder of PDFs, get a JSON Schema.

Project description

Lakshana

CI License: MIT Python

लक्षण (lakṣaṇa, Sanskrit) — "defining characteristic, marker, distinguishing feature."

Zero-config schema discovery for document collections. Drop a folder of PDFs, get a JSON Schema. No training, no labels, no manual schema design.

Two ways to use it. A Python library + CLI for pipelines (available now). A graphical app you download and click through (shipping next — same wizard as the live demo, runs on your own machine).

# Install from source (PyPI release coming)
git clone https://github.com/mickyaero/lakshana && cd lakshana
pip install -e ".[openai]"

export OPENAI_API_KEY=...        # or GROQ / ANTHROPIC / CEREBRAS / GOOGLE
lakshana analyze ./my_docs --output schema.json

What it does

Given a folder of mixed documents — invoices, contracts, statements, forms — Lakshana figures out:

  1. What document types are in there. Clusters similar docs together via UMAP + HDBSCAN over a hybrid structural+semantic embedding.
  2. What fields each type has. Asks an LLM to infer a schema, then verifies field frequency across the cluster with grounding quotes.
  3. A clean JSON Schema (or CSV headers, or Markdown table) per type. Ready to drive downstream extraction.

It's the "tell me what I have" step that every document-extraction pipeline skips — and pays for later.

What you actually get

Real LLM run on 10 mixed docs (5 contracts + 5 invoices) — captured verbatim (this one used Groq's Llama 3.3 70B; works the same with Claude, GPT-4o, Gemini, Cerebras, or local Ollama):

cluster 0: 'Service Agreement'  (5 docs)
  fields:  provider, client, agreement_date, scope_of_services, compensation,
           term_start_date, term_end_date, payment_terms
  groups:  Contract Terms, Service Parties

cluster 1: 'Invoice'  (5 docs)
  fields:  invoice_number, date, bill_to, description, quantity, price,
           tax_amount, total_amount
  groups:  Invoice Line Items, Invoice Metadata, Tax & Totals
  • 100% cluster purity vs. ground truth labels
  • 107 seconds end-to-end (clustering + LLM schema discovery + frequency verification + semantic grouping)
  • $0 with the free Groq tier

And honestly, where it degrades

A full 50-doc run on the bundled synthetic set (result JSON) measured:

  • 5 of 5 clusters discovered, exactly the right size (10 docs each) — clustering itself is reliable.
  • 88% purity, ARI 0.74, V-measure 0.80 — schema discovery quality drops at scale.
  • 2 of 5 clusters got proper names ("Quarterly Report", "Company Memo"); the other 3 hit Groq's free-tier daily token limit (100K/day) mid-run and fell back to "Unknown Type" with empty schemas.

The pipeline is degrading gracefully there, not crashing — but if you're running on >30 docs and want full schemas, use a paid tier or a higher-limit provider (Anthropic, OpenAI, Cerebras paid). The bundled benchmark is reproducible with any of them: just swap --model.

Highlights

  • Zero schema design. Point it at a folder. Get back a typed schema with frequency and grounding for every field.
  • No labels, no training. Pure clustering + LLM inference. Works on a dataset of 10 docs or 10,000.
  • Runs anywhere. Works on a laptop CPU; scales on GPU. No GPU required.
  • Bring your own LLM. Anthropic, OpenAI, Groq, Cerebras, Google, OpenRouter, Ollama, or any OpenAI-compatible endpoint. Not tied to any one model.
  • India-first by accident. Born inside a stack focused on Indian financial documents — the bundled BFSI benchmark covers 7 doc types including GST invoices, Form 26AS, ITR, and KYC.
  • 77 unit tests, CI green on Python 3.10 / 3.11 / 3.12.

Python API

from lakshana import discover

result = discover(
    files=["./docs/inv1.pdf", "./docs/inv2.pdf", "./docs/contract.pdf"],
    model="groq/llama-3.3-70b-versatile",
    min_cluster_size=3,
)

for cluster in result.clusters:
    schema = result.schemas[str(cluster["id"])]
    print(cluster["name"], "→", [f["name"] for f in schema["fields"]])

Export formats:

from lakshana import export_as_json_schema, export_as_csv_headers, export_as_markdown

schema = result.schemas["0"]
json_schema_doc = export_as_json_schema(schema, name="Invoice")  # standard JSON Schema
csv_header_row  = export_as_csv_headers(schema)                  # spreadsheet headers
markdown_table  = export_as_markdown(schema, name="Invoice")     # docs / wiki

CLI

lakshana analyze ./docs --model groq/llama-3.3-70b-versatile --output result.json

Run the benchmarks yourself

The claims above aren't marketing numbers — they're reproducible from a fresh clone:

git clone https://github.com/mickyaero/lakshana && cd lakshana
export GROQ_API_KEY=...

# 50 docs across 5 generic types (invoice/memo/contract/resume/report)
python benchmarks/run.py --dataset synthetic

# 35 Indian financial docs across 7 types (GST invoice, ITR, 26AS, KYC, bank stmt, loan, insurance)
python benchmarks/run.py --dataset bfsi

Reports ARI, NMI, V-measure, homogeneity, completeness, and cluster purity. See benchmarks/README.md.

Examples

How it works

parse → embed (structural + semantic)
     → cluster (UMAP + HDBSCAN)
     → label cluster (LLM)
     → infer schema (LLM)
     → verify field frequency across the cluster (LLM + grounding)
     → deduplicate + group fields semantically
     → export (JSON Schema / CSV / Markdown)

Every step has a graceful fallback. Every output is from real text in your documents, not a hallucination — fields ship with frequency, doc_count, and verified_against so you can see exactly how trustworthy each one is.

Why it exists

Most "AI document extraction" tools assume you already know what fields you want. Real-world data is messier than that — you get a hard drive of receipts and contracts and ??? and you have to figure out the shape before you can extract anything.

Lakshana is the discovery step that lets the rest of your pipeline be simple. It started as a feature inside docstruct (an internal document-extraction stack); it's now its own thing so anyone can use it.

Micky Droch

Contributing

Issues and PRs welcome. Especially:

  • New LLM provider integrations (add to src/lakshana/llm.py)
  • Real-world benchmark datasets (please anonymize before sharing)
  • Examples in other domains (medical, legal, scientific)

pip install -e ".[dev]" && pytest to develop locally.

License

MIT — use it freely, including commercially. Attribution appreciated, not required.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

lakshana-0.1.0.tar.gz (39.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

lakshana-0.1.0-py3-none-any.whl (30.8 kB view details)

Uploaded Python 3

File details

Details for the file lakshana-0.1.0.tar.gz.

File metadata

  • Download URL: lakshana-0.1.0.tar.gz
  • Upload date:
  • Size: 39.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.5

File hashes

Hashes for lakshana-0.1.0.tar.gz
Algorithm Hash digest
SHA256 3454307a548ea1caa9321b84c3414b99239abd200085be382e667664e75eef17
MD5 d5c856a2a49bb0f8cc4204af38c71fa5
BLAKE2b-256 4dd1deafd7d39de8590d4e36f4c3be1f0b082d7078b25283a4c6ec6e4d5e0315

See more details on using hashes here.

File details

Details for the file lakshana-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: lakshana-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 30.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.5

File hashes

Hashes for lakshana-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 43bf2cbdef90bb1d2fd3d8cf4acbdca8485a3265af1039955135b04ec7c87a1e
MD5 a787b792360ae355a8e560f902d43248
BLAKE2b-256 ebd2cb2f9ea1eb5f1bba60c0eaaa8ffd757a85d5d156a64d380901b0559043fe

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page