Metadata-Version: 2.4
Name: docslight
Version: 0.1.5
Summary: Lightweight ComPDF document parsing and extraction SDK
Author-email: ComPDF AI <support@compdf.com>
License-Expression: MIT
Requires-Python: <=3.13,>=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: requests>=2.31.0
Requires-Dist: pydantic>=2.5.0
Requires-Dist: typing-extensions>=4.8.0; python_version < "3.11"
Requires-Dist: tomli>=2.0.1; python_version < "3.11"
Requires-Dist: flask>=3.1.3
Requires-Dist: werkzeug>=3.1.8
Requires-Dist: Pillow>=10.0.0
Requires-Dist: PyMuPDF>=1.23.0
Requires-Dist: numpy>=1.24.0
Requires-Dist: paddlepaddle>=3.3.0
Requires-Dist: paddleocr[doc-parser]>=3.3.0
Requires-Dist: python-docx>=1.1.0
Requires-Dist: python-pptx>=0.6.23
Requires-Dist: openpyxl>=3.1.0
Requires-Dist: openai>=1.0.0
Provides-Extra: dev
Requires-Dist: pytest>=7.4.0; extra == "dev"
Requires-Dist: pytest-cov>=4.1.0; extra == "dev"
Requires-Dist: ruff>=0.1.0; extra == "dev"
Requires-Dist: mypy>=1.7.0; extra == "dev"
Requires-Dist: build>=1.0.0; extra == "dev"
Requires-Dist: twine>=4.0.0; extra == "dev"
Requires-Dist: playwright>=1.40.0; extra == "dev"
Dynamic: license-file

<p align="center">
  <h1 align="center">DocSlight</h1>
  <p align="center">Lightweight Python SDK & CLI for document parsing and structured extraction</p>
  <p align="center">
    <a href="https://pypi.org/project/docslight/"><img src="https://img.shields.io/pypi/v/docslight" alt="PyPI"></a>
    <a href="https://pypi.org/project/docslight/"><img src="https://img.shields.io/pypi/pyversions/docslight" alt="Python versions"></a>
    <a href="LICENSE"><img src="https://img.shields.io/github/license/kdanmobile/docslight" alt="License"></a>
  </p>
</p>

## What is DocSlight?

A lightweight Python library that turns PDFs, images, and Office documents into clean Markdown or structured JSON — with one line of code. Works with ComPDF Cloud (recommended) or fully offline with local parsers.

```python
from docslight import DocSlight

client = DocSlight(api_key="<COMPDF_API_KEY>")
result = client.parse("<DOCUMENT_PATH>")
print(result.to_markdown())
```

## Quick Start

```bash
pip install docslight
```

Cloud parse with the CLI:

```bash
docslight parse "<DOCUMENT_PATH>" --mode cloud --api-key "<COMPDF_API_KEY>" --output "<OUTPUT.md>"
```

Cloud extract with the CLI:

```bash
docslight extract "<DOCUMENT_PATH>" --mode cloud --api-key "<COMPDF_API_KEY>" --fields "invoice_number,total_amount" --output "<OUTPUT.json>"
```

Local parse and extract:

```bash
docslight parse "<DOCUMENT_PATH>" --mode local --output "<OUTPUT.md>"
docslight extract "<DOCUMENT_PATH>" --mode local --fields "invoice_number,total_amount" --local-llm-provider ollama --local-llm-model "<OLLAMA_MODEL>" --output "<OUTPUT.json>"
```

Launch the API server:

```bash
docslight web
# Health: http://127.0.0.1:8000/api/health
```

Placeholders used above:

| Placeholder | Description |
|-------------|-------------|
| `<DOCUMENT_PATH>` | Input file path. Use an absolute or relative path, and quote paths that contain spaces. |
| `<COMPDF_API_KEY>` | ComPDF Cloud API key. You can also set `DOCSLIGHT_API_KEY` instead of passing `--api-key`. |
| `<OUTPUT.md>` | Markdown output path for parse results. |
| `<OUTPUT.json>` | JSON output path for extract results. |
| `<OUTPUT.zip>` | ZIP output path for raw parse archives. |
| `<OLLAMA_MODEL>` | Model name available in your Ollama service, for example `llama3.1` or `qwen2.5:7b`. |

## Features

- **Dual mode** — ComPDF Cloud for production-grade results, or local CPU parsing for offline evaluation
- **Parse → Markdown** — Convert PDF, DOCX, PPTX, XLSX, and images (PNG, JPG, TIFF, BMP, WebP) to clean Markdown
- **Extract → JSON** — Pull structured data by field list, JSON Schema, or structured template (key-value + table extraction)
- **CLI first** — Full-featured command-line interface, script-friendly
- **API server** — Local Flask backend exposing parse, extract, preview, health, and system-info endpoints
- **Batch processing** — `parse_batch()` / `extract_batch()` for multiple files
- **Local LLM extraction** — Ollama or any OpenAI-compatible provider for offline extraction
- **Document types** — Classify and route documents by type for cloud extraction
- **Error-safe** — Typed result objects, structured error hierarchy, no credential leaks

## Install

| Scenario | Command |
|----------|---------|
| Runtime package (cloud, local, web, CLI, SDK) | `pip install docslight` |
| Development tools (tests, lint, build, upload) | `pip install -e ".[dev]"` |

> Local CPU parsing is experimental. Validate accuracy and latency on your own documents before production use.

## SDK Usage

### Cloud — Parse

```python
from docslight import DocSlight

client = DocSlight(
    mode="cloud",
    api_key="<COMPDF_API_KEY>",
    base_url="https://api-server.compdf.com",
)

result = client.parse("<DOCUMENT_PATH>")
print(result.to_markdown())   # Clean markdown
print(result.to_json())       # Full result with pages + metadata

if result.raw_archive:
    with open("<OUTPUT.zip>", "wb") as file:
        file.write(result.raw_archive)
```

Parameters:

| Parameter | Required | Description |
|-----------|----------|-------------|
| `mode="cloud"` | Yes | Use ComPDF Cloud. This is the default if `mode` is omitted. |
| `api_key` | Yes for cloud | ComPDF Cloud API key. Can also come from `DOCSLIGHT_API_KEY`. |
| `base_url` | No | Cloud API base URL. Defaults to `https://api-server.compdf.com`. |
| `<DOCUMENT_PATH>` | Yes | PDF, image, DOCX, PPTX, or XLSX input file. |
| `<OUTPUT.zip>` | No | Optional path if you want to save the raw parse ZIP archive returned by cloud parse. |

### Cloud — Extract

```python
result = client.extract(
    "<DOCUMENT_PATH>",
    fields=["invoice_number", "invoice_date", "total_amount"],
)
print(result.to_json())
```

With a JSON Schema:

```python
schema = {
    "type": "object",
    "properties": {
        "invoice_number": {"type": "string"},
        "total_amount": {"type": "number"},
    },
    "required": ["invoice_number"],
}
result = client.extract("<DOCUMENT_PATH>", schema=schema)
```

With document type classification:

```python
result = client.extract(
    "<DOCUMENT_PATH>",
    fields=["invoice_number"],
    document_types=["invoice"],
)
```

Cloud extract parameters:

| Parameter | Required | Description |
|-----------|----------|-------------|
| `fields` | Optional | Field list to extract. Accepts `list[str]`, comma-separated string, or structured object with `keys` and `tableHeaders`. |
| `schema` | Optional | JSON Schema describing the desired output. If both `fields` and `schema` are provided, schema is used as the structured output contract. |
| `document_types` | Optional | List of document type labels for cloud-side classification/routing. |

### Local — Parse (Offline)

```python
client = DocSlight(mode="local")
result = client.parse("<DOCUMENT_PATH>")
print(result.to_markdown())
```

Local parse uses the runtime dependencies installed with:

```bash
pip install docslight
```

### Local — Extract with Ollama

```python
client = DocSlight(
    mode="local",
    local_llm={
        "provider": "ollama",
        "model": "<OLLAMA_MODEL>",
        "base_url": "http://localhost:11434",
    },
)
result = client.extract(
    "<DOCUMENT_PATH>",
    fields=["invoice_number", "invoice_date"],
)
print(result.to_json())
```

### Local — Extract with OpenAI-Compatible API

```python
client = DocSlight(
    mode="local",
    local_llm={
        "provider": "openai-compatible",
        "base_url": "<OPENAI_COMPATIBLE_BASE_URL>",
        "model": "<MODEL_NAME>",
        "api_key": "<LOCAL_LLM_API_KEY>",
        "extra_body": {"enable_thinking": False},  # e.g., DashScope qwen3
    },
)
result = client.extract("<DOCUMENT_PATH>", fields=["invoice_number"])
print(result.to_json())
```

Local LLM parameters:

| Parameter | Required | Description |
|-----------|----------|-------------|
| `provider` | No | `ollama`, `openai`, or `openai-compatible`. Defaults to `ollama` when other local LLM fields are set. |
| `model` | Yes for local extract | Local or OpenAI-compatible model name. |
| `base_url` | Required for `openai-compatible` | LLM endpoint base URL. Ollama defaults to `http://localhost:11434`. |
| `api_key` | Usually required for `openai-compatible` | API key for the LLM endpoint. Ollama can use the default placeholder key. |
| `extra_body` | No | Extra provider-specific request body, such as `{"enable_thinking": False}`. |

### Batch Processing

```python
results = client.parse_batch(["<DOCUMENT_1>", "<DOCUMENT_2>", "<DOCUMENT_3>"])
for r in results:
    print(r.to_markdown()[:200])
```

## CLI Usage

### Cloud CLI

Parse to Markdown:

```bash
docslight parse "<DOCUMENT_PATH>" --mode cloud --api-key "<COMPDF_API_KEY>" --output "<OUTPUT.md>"
```

Save the raw parse ZIP archive:

```bash
docslight parse "<DOCUMENT_PATH>" --mode cloud --api-key "<COMPDF_API_KEY>" --format zip --output "<OUTPUT.zip>"
```

Extract fields to JSON:

```bash
docslight extract "<DOCUMENT_PATH>" --mode cloud --api-key "<COMPDF_API_KEY>" --fields "invoice_number,total_amount" --output "<OUTPUT.json>"
```

Extract with a JSON Schema file:

```bash
docslight extract "<DOCUMENT_PATH>" --mode cloud --api-key "<COMPDF_API_KEY>" --schema "<SCHEMA_PATH.json>" --output "<OUTPUT.json>"
```

### Local CLI

Parse locally:

```bash
docslight parse "<DOCUMENT_PATH>" --mode local --output "<OUTPUT.md>"
```

Extract locally with Ollama:

```bash
docslight extract "<DOCUMENT_PATH>" --mode local --fields "invoice_number,total_amount" --local-llm-provider ollama --local-llm-model "<OLLAMA_MODEL>" --local-llm-base-url "http://localhost:11434" --output "<OUTPUT.json>"
```

Extract locally with an OpenAI-compatible endpoint:

```bash
docslight extract "<DOCUMENT_PATH>" --mode local --fields "invoice_number,total_amount" --local-llm-provider openai-compatible --local-llm-model "<MODEL_NAME>" --local-llm-base-url "<OPENAI_COMPATIBLE_BASE_URL>" --local-llm-api-key "<LOCAL_LLM_API_KEY>" --output "<OUTPUT.json>"
```

CLI parameters:

| Option | Required | Description |
|--------|----------|-------------|
| `<DOCUMENT_PATH>` | Yes | Input file path. Quote paths that contain spaces. |
| `--mode` | No | `cloud` or `local`. Defaults to config/env/default mode, which is `cloud`. |
| `--api-key` | Yes for cloud unless env is set | ComPDF Cloud API key. Can be replaced by `DOCSLIGHT_API_KEY`. |
| `--base-url` | No | Cloud API base URL. Defaults to `https://api-server.compdf.com`. |
| `--output`, `-o` | No | Output path. If omitted, text/JSON is written to stdout. Binary ZIP output should use `--output`. |
| `--format` | No | Parse output format: `markdown`, `json`, `standard-json`, or `zip`. If output ends in `.zip`, `zip` is inferred. |
| `--fields` | Optional for extract | Comma-separated field names, for example `"invoice_number,total_amount"`, or a JSON object string. |
| `--schema` | Optional for extract | Path to a JSON Schema file. |
| `--document-types` | Optional for cloud extract | Path to a JSON file containing a list, for example `["invoice"]`. |
| `--local-llm-provider` | Required for explicit local extract setup | `ollama`, `openai`, or `openai-compatible`. Defaults to `ollama` if other local LLM args are supplied. |
| `--local-llm-model` | Yes for local extract | Local LLM model name. |
| `--local-llm-base-url` | Required for OpenAI-compatible local extract | LLM service base URL. Ollama defaults to `http://localhost:11434`. |
| `--local-llm-api-key` | Usually required for OpenAI-compatible local extract | API key for the local or private LLM service. |
| `--host` | No, `docslight web` only | API server host. Defaults to `127.0.0.1`. |
| `--port` | No, `docslight web` only | API server port. Defaults to `8000`. |
| `--debug` | No, `docslight web` only | Enable Flask debug logging. |

## API Server

DocSlight includes a local Flask API server for document processing. Frontend assets are not bundled in this package.

Install and start:

```bash
pip install docslight
docslight web --host 127.0.0.1 --port 8000
```

You can also run the same server module directly:

```bash
python -m docslight.web_app --host 127.0.0.1 --port 8000 --debug
```

### API Health

```powershell
curl.exe "http://127.0.0.1:8000/api/health"
curl.exe "http://127.0.0.1:8000/api/system-info"
```

### Cloud Parse API

`POST /api/parse` returns a ZIP file when the cloud parser returns a parse archive.

```powershell
curl.exe -X POST "http://127.0.0.1:8000/api/parse" `
  -F "file=@<DOCUMENT_PATH>" `
  -F "mode=cloud" `
  -F "api_key=<COMPDF_API_KEY>" `
  -F "base_url=https://api-server.compdf.com" `
  --output "<OUTPUT.zip>"
```

### Cloud Extract API

```powershell
curl.exe -X POST "http://127.0.0.1:8000/api/extract" `
  -F "file=@<DOCUMENT_PATH>" `
  -F "mode=cloud" `
  -F "api_key=<COMPDF_API_KEY>" `
  -F "base_url=https://api-server.compdf.com" `
  -F 'fields={"name":"Invoice","keys":{"invoice_number":{"prompt":null,"mapping":null},"total_amount":{"prompt":null,"mapping":null}}}' `
  -F "cloud_extract_mode=vlm" `
  --output "<OUTPUT.json>"
```

### Local Parse API

```powershell
curl.exe -X POST "http://127.0.0.1:8000/api/parse" `
  -F "file=@<DOCUMENT_PATH>" `
  -F "mode=local" `
  --output "<OUTPUT.zip>"
```

### Local Extract API with Ollama

```powershell
curl.exe -X POST "http://127.0.0.1:8000/api/extract" `
  -F "file=@<DOCUMENT_PATH>" `
  -F "mode=local" `
  -F 'fields={"name":"Invoice","keys":{"invoice_number":{"prompt":null,"mapping":null},"total_amount":{"prompt":null,"mapping":null}}}' `
  -F "local_llm_provider=ollama" `
  -F "local_llm_model=<OLLAMA_MODEL>" `
  -F "local_llm_base_url=http://localhost:11434" `
  --output "<OUTPUT.json>"
```

### Local Extract API with OpenAI-Compatible LLM

```powershell
curl.exe -X POST "http://127.0.0.1:8000/api/extract" `
  -F "file=@<DOCUMENT_PATH>" `
  -F "mode=local" `
  -F "fields=invoice_number,total_amount" `
  -F "local_llm_provider=openai-compatible" `
  -F "local_llm_model=<MODEL_NAME>" `
  -F "local_llm_base_url=<OPENAI_COMPATIBLE_BASE_URL>" `
  -F "local_llm_api_key=<LOCAL_LLM_API_KEY>" `
  --output "<OUTPUT.json>"
```

API form fields:

| Field | Required | Description |
|-------|----------|-------------|
| `file` | Yes | Uploaded document. In curl, use `file=@<DOCUMENT_PATH>`. |
| `mode` | No | `cloud` or `local`. Defaults to `cloud`. |
| `api_key` | Yes for cloud unless env is set | ComPDF Cloud API key. |
| `base_url` | No | Cloud API base URL. Defaults to `https://api-server.compdf.com`. |
| `fields` | Optional for extract | Comma-separated field names or a structured JSON object with `name`, `keys`, and optional `tableHeaders`. |
| `schema` | Optional for extract | JSON Schema string. |
| `document_types` | Optional for cloud extract | JSON list string, for example `["invoice"]`. |
| `cloud_extract_mode` | No, cloud extract only | Cloud extraction mode. Defaults to `vlm`. |
| `enable_grounding` | No, cloud extract only | Boolean value used when `cloud_extract_mode=integrate`. Accepted values include `true`, `false`, `1`, and `0`. |
| `local_llm_provider` | Required for local extract | `ollama`, `openai`, or `openai-compatible`. |
| `local_llm_model` | Yes for local extract | Local LLM model name. |
| `local_llm_base_url` | Required for OpenAI-compatible local extract | LLM endpoint base URL. |
| `local_llm_api_key` | Usually required for OpenAI-compatible local extract | LLM endpoint API key. |

Response behavior:

| Endpoint | Cloud | Local |
|----------|-------|-------|
| `POST /api/parse` | Returns the parse ZIP archive when available. | Returns the parse ZIP archive when available. |
| `POST /api/extract` | Returns JSON with top-level `success`, `results`, and `metadata`. | Returns JSON with top-level `success`, `results`, and `metadata`. |
| `POST /api/preview` | Returns preview JSON for PDF/images; Office preview is not supported. | Same behavior. |

## Environment Variables

| Variable | Description |
|----------|-------------|
| `DOCSLIGHT_API_KEY` | API key for cloud mode |
| `DOCSLIGHT_MODE` | Processing mode: `cloud` or `local` (default: `cloud`) |
| `DOCSLIGHT_BASE_URL` | Cloud API base URL (default: `https://api-server.compdf.com`) |
| `DOCSLIGHT_TIMEOUT` | Request timeout in seconds |
| `DOCSLIGHT_LOCAL_PARSER` | Local parser selector, usually left unset |

## Supported Inputs

| Mode | Formats |
|------|---------|
| Cloud | PDF, images (PNG/JPG/TIFF/BMP/WebP), DOCX, PPTX, XLSX, and more via ComPDF Cloud API |
| Local | PDF, images (PNG/JPG/TIFF/BMP/WebP), DOCX, PPTX, XLSX |

> Legacy Office formats (`.doc`, `.ppt`, `.xls`) must be converted to DOCX/PPTX/XLSX for local processing.

## Development

```bash
pip install -e ".[dev]"
ruff check .
mypy docslight
pytest
python -m build
```

## License

MIT License. See `LICENSE`.
