Metadata-Version: 2.4
Name: lawsaathi
Version: 2.0.1
Summary: Official Python SDK for the LawSaathi Developer API (delta-2.0-pro) — OpenAI-compatible legal AI.
Author: LawSaathi
License: MIT
Project-URL: Homepage, https://lawsaathi.in
Project-URL: Documentation, https://lawsaathi.in/developers
Keywords: lawsaathi,legal,ai,delta,india,openai-compatible
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.8
Description-Content-Type: text/markdown
Requires-Dist: requests>=2.28

# lawsaathi — Official Python SDK

OpenAI-compatible Python client for the **LawSaathi Developer API** (`delta-2.0-pro`).

## Install

```bash
pip install lawsaathi
```

(While in private beta, install from the repository: `pip install <path-or-url-to-this-folder>`. Publishing to PyPI: `python -m build && twine upload dist/*`.)

## Quickstart

```python
from lawsaathi import LawSaathi

client = LawSaathi(api_key="ls_live_...")  # from https://lawsaathi.in/developers

# ── Non-streaming ──
resp = client.chat.completions.create(
    model="delta-2.0-pro",
    messages=[{"role": "user", "content": "Explain anticipatory bail under BNSS 482"}],
)
print(resp.choices[0].message.content)
print(resp.usage.total_tokens)
print(resp.lawsaathi.cost_breakdown)   # {'input': ..., 'output': ..., 'total': ...}

# ── Streaming (SSE) ──
stream = client.chat.completions.create(
    model="delta-2.0-pro",
    messages=[{"role": "user", "content": "Draft a legal notice for cheque bounce"}],
    stream=True,
    thinking=True,                        # optional extended reasoning
)
for chunk in stream:
    delta = chunk.choices[0].delta
    if getattr(delta, "reasoning_content", None):
        print("[thinking]", delta.reasoning_content, end="")
    if delta.content:
        print(delta.content, end="")

# ── Custom persona (optional — default is DELTA) ──
resp = client.chat.completions.create(
    model="delta-2.0-pro",
    messages=[{"role": "user", "content": "What is Section 138 of the NI Act?"}],
    persona="A patient law-school tutor who explains with examples",
)

# ── Files (PDF / images / DOCX / text) ──
resp = client.chat.completions.create(
    model="delta-2.0-pro",
    messages=[{"role": "user", "content": "Summarize this FIR and cite the sections"}],
    files=["/path/to/fir.pdf"],
)

# ── Files: staged upload (reuse a file across many requests) ──
with open("/path/to/contract.docx", "rb") as f:
    staged = client.files.create(f)          # -> { id, filename, bytes, expires_at }

resp = client.chat.completions.create(
    model="delta-2.0-pro",
    messages=[{"role": "user", "content": "List every termination clause in this contract"}],
    file_ids=[staged.id],
)

# ── Models ──
print(client.models.list().data)
```

## Attaching files

Two ways to attach documents:

**1. Inline (one-off requests):** pass local paths via `files=[...]` — the SDK
uploads them as multipart with your request.

**2. Staged (`/v1/files`):** upload once with `client.files.create(file)`, then
reference `file_ids=[...]` in any number of chat requests. Files auto-expire
after **24 hours**.

| | |
|---|---|
| Supported types | PDF, PNG, JPEG, WEBP, GIF, DOCX, TXT, JSON, CSV, Markdown |
| Max per request | 5 files |
| Max size | 10 MB per file |
| PDF page limit | 100 pages |

**DOCX handling:** when you upload a `.docx`, LawSaathi **converts it to PDF
server-side** (via Google Drive export) and attaches the rendered PDF to the
model — so the AI sees the real layout, tables, and signatures, not just raw
extracted text. If conversion ever fails, the server automatically falls back
to text extraction. Your code doesn't need to do anything special — upload
the `.docx` exactly as you would any other file.

**cURL (staged upload):**

```bash
# 1. Stage the file
curl https://lawsaathi.in/v1/files/   -H "Authorization: Bearer ls_live_..."   -F "file=@/path/to/contract.docx"
# -> {"id": "3f1c...", "filename": "contract.docx", "bytes": 48213, ...}

# 2. Reference it
curl https://lawsaathi.in/v1/chat/completions/   -H "Authorization: Bearer ls_live_..."   -H "Content-Type: application/json"   -d '{"model": "delta-2.0-pro", "messages": [{"role": "user", "content": "Summarize this contract"}], "file_ids": ["3f1c..."]}'
```

## Rate limits

| Limit | Value |
|---|---|
| Requests | 100 / minute per user |
| Input tokens | 500,000 / minute per user |
| Output tokens | 100,000 / minute per user |

Exceeding any limit returns `429 RateLimitError` — retry with backoff.

## Web search

```python
resp = client.chat.completions.create(
    model="delta-2.0-pro",
    messages=[{"role": "user", "content": "Latest Supreme Court judgment on Article 21?"}],
    web_search=True,   # model may call the server-executed google search tool
)
print(resp.lawsaathi.searches)                    # number of search executions
print(resp.lawsaathi.cost_breakdown["search"])    # Rs.0.50 per execution
```

## Tool calling (OpenAI-compatible, client-executed)

```python
import json

tools = [{
    "type": "function",
    "function": {
        "name": "get_case_status",
        "description": "Look up a court case status by number",
        "parameters": {
            "type": "object",
            "properties": {"case_number": {"type": "string"}},
            "required": ["case_number"],
        },
    },
}]

resp = client.chat.completions.create(
    model="delta-2.0-pro",
    messages=[{"role": "user", "content": "Status of case 1234/2024?"}],
    tools=tools,
)
if resp.choices[0].finish_reason == "tool_calls":
    call = resp.choices[0].message.tool_calls[0]
    result = your_function(**json.loads(call.function.arguments))
    # send the result back
    final = client.chat.completions.create(
        model="delta-2.0-pro",
        messages=[
            {"role": "user", "content": "Status of case 1234/2024?"},
            {"role": "assistant", "tool_calls": [
                {"id": call.id, "function": {"name": call.function.name,
                                             "arguments": call.function.arguments}}],
            },
            {"role": "tool", "tool_call_id": call.id,
             "content": json.dumps({"status": "Listed for hearing on 20-09-2026"})},
        ],
        tools=tools,
    )
```

## Billing

Input: ₹145 / million tokens · Output: ₹449 / million tokens · Search: ₹0.50 per execution.
Every response includes `lawsaathi.cost_breakdown` and `credits_remaining`.
Errors: `401 AuthenticationError` (bad key), `402 InsufficientQuotaError`
(top up at lawsaathi.in/developers → Billing), `429 RateLimitError`, `400 InvalidRequestError`.

## Error handling

```python
from lawsaathi import LawSaathi, InsufficientQuotaError, AuthenticationError

try:
    resp = client.chat.completions.create(model="delta-2.0-pro", messages=[...])
except AuthenticationError:
    ...
except InsufficientQuotaError:
    ...
```
