Metadata-Version: 2.5
Name: z-parser-sdk
Version: 1.6.0
Summary: Client SDK for the z-parser document extraction service — bytes in, RAG-ready Markdown out (PDF/OCR, Office, images, manuscripts, audio/video, EPUB, e-mail).
Project-URL: Documentation, https://github.com/novagen/z-parser
Author-email: Novagen <yarab@novagen.tech>
License: MIT
Keywords: document,extraction,markdown,ocr,parser,pdf,rag
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Text Processing :: General
Requires-Python: >=3.9
Requires-Dist: httpx>=0.24
Provides-Extra: estimate
Requires-Dist: pypdf>=4; extra == 'estimate'
Provides-Extra: test
Requires-Dist: pymupdf; extra == 'test'
Requires-Dist: pytest>=7; extra == 'test'
Description-Content-Type: text/markdown

# z-parser

Python SDK for the **z-parser** document-extraction service: bytes in, RAG-ready
Markdown out. Scanned PDFs (SOTA OCR + vision escalation), Office, spreadsheets,
images, charts, manuscripts, EPUB, e-mail, audio/video transcription — one client.

```bash
pip install z-parser-sdk       # the import stays `z_parser`, the CLI stays `z-parser`
# no service running yet? one container, one key:
docker run -d -p 4056:4056 -e MISTRAL_API_KEY=xxx yatchiyax/z-parser
```

```python
from z_parser import ZParser

zp = ZParser("http://localhost:4056")     # or export Z_PARSER_URL
doc = zp.parse("rapport.pdf")             # path, or bytes + filename=
print(doc.parser, doc.num_chars)          # e.g. "mistral-ocr+figures(2)" 48213
doc.save("rapport.md")

pdf = zp.render_pdf("deck.pptx")          # Office → viewable PDF (page N = slide N)
figs = zp.images("catalogue.pdf", mode="artwork")   # per-figure crops + captions
```

CLI:

```bash
z-parser contract.pdf -o contract.md
```

## Control plane — route, score, arbitrate

The client is not just a wrapper: it picks the engine, scores the result offline
and escalates only when the score says so.

```python
# cheap first, escalate only if the output looks broken
doc = zp.parse("scan.pdf", strategy="auto", escalate=["mistral-medium-latest"])
doc.quality.score        # 0.0 … 1.0, computed locally (no tokens, no network)
doc.attempts             # what was tried, what it scored, what it cost

# two engines read the same document; disagreement = likely hallucination
doc = zp.parse("manuscrit.jpg", strategy="consensus",
               engines=[{"vision_provider": "mistral", "vision_model": "mistral-small-latest"},
                        {"vision_provider": "gemini",  "vision_model": "gemini-2.5-flash"}],
               escalate=[{"vision_model": "mistral-medium-latest"}])
doc.agreement            # 0.16 → the two engines invented different things
```

The quality evaluator detects what actually breaks in production: empty output,
symbol soup, **degenerate repetition** (the silent VLM loop), and near-empty
pages. It cannot detect a fluent invention — that is what `strategy="consensus"`
is for: two engines rarely hallucinate the *same* text, so low agreement is the
signal, and a stronger arbiter settles it.

Measured on a real 1831 manuscript: both cheap engines self-reported quality
1.00 and both were wrong; agreement was 16 %, arbitration recovered the correct
transcription, and the final score was honestly downgraded to 0.58 with the
reason attached.

## Domain context — accuracy through vocabulary

A vision model reads "Dig. 0.25 mg" far more reliably when it knows it is looking
at a prescription. Describe the document before parsing it:

```python
zp.parse("prescription.jpg", domain="medical")
zp.parse("balance.pdf", domain="finance", context="Amounts in DZD, SCF chart of accounts.")
```

Seven presets — `medical`, `finance`, `legal`, `technical`, `academic`,
`historical`, `administrative` — or free text via `context=`. The hint is
**appended** to the extraction prompt, never replacing it (capped at 2000 chars),
so the extraction contract stays intact. Read or copy them:
`from z_parser import DOMAINS`.

## What it costs

Know **before** you parse, and **exactly** after:

```python
est = zp.estimate("catalogue.pdf")     # local only: no upload, no API call, free
print(est)                             # ~$0.7000 (175 page(s), ocr:mistral-ocr-latest)
print(est.assumptions)                 # how the number was obtained

doc = zp.parse("catalogue.pdf")
print(doc.cost)                        # 0.0533  — real USD at list prices
print(doc.usage)                       # [{'model': 'mistral-ocr-latest', 'pages': 13}, …]
```

Every billable unit is counted, including the vision calls made by figure
descriptions and manuscript escalation. `parse(..., with_cost=False)` skips the
computation (`doc.cost` stays `None`). Local engines (text, HTML, XML, CSV,
Excel) cost **$0**.

Rates are Mistral's public list prices (checked 2026-08-21) and are overridable —
`z_parser.pricing.PRICES["mistral-ocr-latest"]["per_page"] = 0.002` for a
negotiated rate; `doc.cost_unpriced` names any model billed by a provider whose
rate is unknown, so a cost is never silently too low.

```bash
pip install 'z-parser-sdk[estimate]'   # exact PDF page counts in estimate()
```

**Pick your provider and quality levers from the client** — Mistral, Ollama
(100 % local), vLLM, Hugging Face, Gemini or any OpenAI-compatible vision
endpoint, per client or per call:

```python
# Mistral vision in one word (openai dialect on api.mistral.ai, server key applies)
zp = ZParser(vision_provider="mistral", vision_model="mistral-small-latest")

# 100 % local with Ollama — no data leaves your machine
zp = ZParser(vision_provider="openai",
             vision_base_url="http://host.docker.internal:11434/v1",  # seen FROM the server
             vision_model="llama3.2-vision",
             doc_vision=True)      # PDFs through local vision too → fully offline

# Quality levers (mirror the server's .env):
doc = zp.parse("dossier.pdf",
               ocr_escalate=True,       # weak OCR pages re-read by vision (manuscripts)
               describe_figures=True)   # embedded charts/diagrams described on their page
```

One runnable example per provider ships in `examples/` (with sample files), plus
`09_formats_sweep.py` — a QA battery (PDF, image, Excel, HTML, XML, LaTeX, CSV)
that checks Markdown *structure* and writes a browsable `results/` gallery.
Safety contract: a caller-chosen `vision_base_url` never receives the server's
own API keys (`api_key` is an alias for `vision_api_key`). With no params, the
server's configuration applies.

Errors are explicit: `ZParserError` carries the service's `status`
(`unsupported` / `error`) and message. Timeouts default to 15 minutes — large
OCR jobs are slow by nature; pass `timeout=` to change.

The service itself (Docker, one container) and its ground-truth benchmark live in
the main repository.
