Metadata-Version: 2.4
Name: truetrace
Version: 0.1.0
Summary: Python client for the TrueTrace document-intelligence API — extraction, review, and Q&A with confidence scores and bounding boxes on every value
Project-URL: Homepage, https://roysa.ai
Project-URL: Documentation, https://roysa.ai/api
Project-URL: Changelog, https://github.com/ahmad-shirazi/roysa.ai/blob/main/sdk/python/CHANGELOG.md
Author-email: Roysa <ahmad@roysa.ai>
License: MIT License
        
        Copyright (c) 2026 Roysa
        
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
License-File: LICENSE
Keywords: bounding-box,document-ai,document-extraction,grounding,idp,invoice,ocr,pdf,truetrace
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Classifier: Topic :: Text Processing
Classifier: Typing :: Typed
Requires-Python: >=3.9
Requires-Dist: httpx>=0.24
Provides-Extra: dev
Requires-Dist: build>=1.0; extra == 'dev'
Requires-Dist: pytest>=7; extra == 'dev'
Requires-Dist: respx>=0.20; extra == 'dev'
Requires-Dist: twine>=5.0; extra == 'dev'
Description-Content-Type: text/markdown

# TrueTrace Python SDK

Grounded document intelligence. Every value TrueTrace returns carries a
confidence score and a bounding box, so you can show a reviewer exactly where on
the page an answer came from — or reject it before it reaches your database.

```bash
pip install truetrace
```

```python
from truetrace import TrueTrace

tt = TrueTrace(api_key="rk_…")          # or TrueTrace.from_env() via TRUETRACE_API_KEY

out = tt.extract("invoice.pdf", fields=[
    {"name": "Invoice Number"},
    {"name": "Total", "description": "grand total including tax"},
])

print(out["extracted_features"]["Total"])            # "$12,480.00"
print(out["confidence_scores"]["Total"])             # 0.97
print(out["bounding_boxes"]["Total"]["boxes"][0])    # {page: 1, x1: .62, y1: .81, …}
print(out["bounding_boxes"]["Total"]["source"])      # "ocr_snapped"
```

Boxes are normalised 0-1 and nested under `["boxes"]`, so a field with a value
appearing in two places gives you both. `out["vision_data"]` is the OCR payload —
pass it back into a later `extract()` or `review()` to skip re-running OCR.

Get a key at [roysa.ai/account](https://roysa.ai/account) → API keys.

## Extraction

```python
# flat fields
tt.extract("invoice.pdf", fields=[{"name": "Total"}])

# nested objects and arrays, via JSON Schema
tt.extract_schema("policy.pdf", schema={
    "type": "object",
    "properties": {
        "insured": {"type": "object", "properties": {"name": {"type": "string"}}},
        "coverages": {"type": "array", "items": {"type": "object", "properties": {
            "kind": {"type": "string"},
            "limit": {"type": "number"},
        }}},
    },
})
# → bounding_boxes keyed by leaf path: "coverages[1].limit"

# let TrueTrace design the schema from samples
tt.generate_schema(["sample1.pdf", "sample2.pdf"], doc_type="invoice")
```

Field `description`s materially steer the model and are part of the response
cache key — once a description gives you good output, keep it stable.

## Layout, classification, splitting

```python
tt.parse("report.pdf", grounded=True)   # markdown + typed blocks, each with boxes
tt.classify("doc.pdf", categories=["invoice", "receipt", "contract"])
tt.split("packet.pdf")                  # segment boundaries, each with grounded evidence
```

`parse()` caps very large PDFs server-side — check `truncated` and compare
`pages_parsed` with `page_count`.

## Q&A over a document

```python
first = tt.ask("What is the cancellation notice period?", "contract.pdf")
print(first["answer"], first["references"])

# Follow-ups: pass the session id AND the file. The session skips the upload;
# the file is a fallback the SDK re-sends automatically if the session has
# expired or the request lands on a different server instance.
tt.ask("And who has to be notified?",
       "contract.pdf", session_id=first["session_id"])

# or stream it
for event in tt.ask_stream("Summarise the payment terms", "contract.pdf"):
    if event["type"] == "token":
        print(event.get("text", ""), end="", flush=True)
```

## Review — deterministic and reproducible

```python
result = tt.review("coi.pdf", criteria=[
    {"name": "Not expired", "field": "policy_expiration_date",
     "operator": "after", "value": "today"},
    {"name": "$1M+ coverage", "field": "each_occurrence_limit",
     "operator": "gte", "value": 1_000_000},
], as_of="2026-08-09")
```

Each returned criterion exposes `field`, `operator`, `reference_value`,
`extracted_value`, `verdict`, `confidence`, and `source_reference` — nothing is a
black box. Deterministic criteria give byte-identical verdicts for the same
document, and `"today"` pins to `as_of` so a dated check stays reproducible.

Mix in model-judged criteria when a rule isn't expressible as a comparison:

```python
tt.review("contract.pdf", criteria=[
    {"name": "Auto-renews", "prompt": "Does this contract renew automatically?"},
])
```

Save a definition once and re-run it at volume:

```python
rid = tt.define_review("COI check", criteria=[...])["id"]
tt.review("coi.pdf", review_id=rid)
```

Derived values are computed, never generated, so they can't be hallucinated:

```python
tt.compute("statement.pdf", derived_fields=[
    {"name": "total", "operation": "sum", "inputs": ["fees", "interest", "principal"]},
])
```

## Forms, geo, redaction

```python
tt.detect_form("acord-125.pdf")

out = tt.fill_form("acord-125.pdf", values={"Named Insured": "Acme LLC"})
print(out["filled_count"], "of", out["detected_count"], "fields")
Path("filled.pdf").write_bytes(base64.b64decode(out["filled_pdf_base64"]))

tt.geo("survey.pdf")
tt.redact("application.pdf", target="names, SSNs, emails", apply=True)
```

## Audio and video

```python
media = tt.process_media("call.mp4")
tt.extract_media(
    fields=[{"name": "Quoted premium"}],
    transcript_segments=media["transcript_segments"],
    media_type="video",
)
tt.ask("What did the client agree to?", transcript_text=media["transcript"])
```

## Methods that return a document, not JSON

`transcribe()` and `translate()` build a PDF, and so does
`redact(apply=True)`. Those return raw bytes plus the server's suggested
filename instead of a JSON body:

```python
out = tt.transcribe("call.mp3")
Path(out["filename"]).write_bytes(out["content"])   # transcript_call.pdf
```

`fill_form()` is the exception — it returns JSON with the PDF as base64 in
`filled_pdf_base64`. Use `process_media()` when you want a transcript as data
rather than as a document.

## Batch

```python
job = tt.submit_batch(
    files=[{"fileName": "a.pdf", "url": "https://…/a.pdf"}],
    fields=["Invoice Number", "Total"],
)
final = tt.wait_for_batch(job["job_id"])     # polls to a terminal state
```

Up to 500 files per job. API-key callers pass a reachable https URL per file.
Batch needs a **Scale** plan, and `provenance_export()` needs **Pro** — on a
lower plan both raise `PermissionDeniedError` naming the missing feature.

## Errors

```python
from truetrace import InsufficientCreditsError, RateLimitError, AuthenticationError

try:
    tt.extract("invoice.pdf", fields=[{"name": "Total"}])
except InsufficientCreditsError as e:
    print(e.credits_required, e.action)      # nothing was charged
except RateLimitError as e:
    print(e.limit, e.retry_after, e.is_daily)
except AuthenticationError:
    ...
```

429s and 5xx are retried automatically (3 attempts, honouring the server's
`Retry-After`). Tune with `max_retries=`, or `max_retries=0` to handle it
yourself. Failed tasks are never billed.

## Configuration

| Argument | Default | Notes |
| --- | --- | --- |
| `api_key` | `$TRUETRACE_API_KEY` | `rk_…` from your account page |
| `base_url` | `$TRUETRACE_BASE_URL`, else production | point at staging/dev |
| `timeout` | 600s read, 10s connect | matches the server's own ceiling |
| `max_retries` | 3 | 429/5xx and transport errors |
| `http_client` | — | bring your own `httpx.Client` for proxies |

```python
with TrueTrace.from_env() as tt:
    print(tt.verify_key())      # {valid, rate_limit, daily_limit, …}
    print(tt.credit_rates())    # per-task credit costs
```

Files can be a path, `bytes`, a `(filename, bytes)` tuple, or any binary
file object.

## Reference

Full endpoint docs: [roysa.ai/api](https://roysa.ai/api).
