Metadata-Version: 2.4
Name: intellidoc-sdk
Version: 0.2.0
Summary: Python SDK for IntelliDoc document extraction service
Author: NIA
Requires-Python: >=3.13
Description-Content-Type: text/markdown
Requires-Dist: httpx>=0.27

# IntelliDoc SDK

SDK Python para o serviço de extração de texto IntelliDoc.

## Instalação

```bash
pip install intellidoc-sdk
```

Requisitos: Python 3.13+

## Uso

Você tem **dois métodos**:

- `extract(documento)` — extrai **1 documento** e retorna o resultado direto.
- `extract_batch(documentos)` — extrai **vários documentos**, retorna um iterator que entrega cada um conforme termina.

### 1 documento

```python
from intellidoc_sdk import IntelliDocClient

client = IntelliDocClient(url="http://intellidoc:8000", api_key="sua-chave")

r = client.extract("/dados/contrato.pdf")

print(r.text or r.error)
```

### Vários documentos

```python
from intellidoc_sdk import IntelliDocClient

client = IntelliDocClient(url="http://intellidoc:8000", api_key="sua-chave")

for r in client.extract_batch(["/dados/contrato.pdf", "/dados/cert.html"]):
    print(r.filename, r.text or r.error)
```

Resultados saem conforme cada documento termina — você não espera o batch inteiro. Falhas em um documento não interrompem os outros (chegam em `r.error`).

## O objeto retornado (DocumentResult)

Ambos os métodos retornam objetos `DocumentResult` com 4 campos:

| Campo | Tipo | Quando tem valor |
|---|---|---|
| `r.filename` | `str` | sempre |
| `r.text` | `str` ou `None` | **só quando deu certo** (`None` se falhou) |
| `r.error` | `str` ou `None` | **só quando falhou** (`None` se deu certo) |
| `r.id` | `str` ou `None` | sempre, exceto se foi rejeitado no upload |

**Regra:** ou tem `text` ou tem `error`, nunca os dois ao mesmo tempo.

```python
if r.error:
    # falhou — r.text é None, r.error tem a mensagem
    print(f"{r.filename} falhou: {r.error}")
else:
    # deu certo — r.text tem o texto extraído, r.error é None
    print(f"{r.filename}: {len(r.text)} caracteres")
```

## Tipos de input

Tanto `extract` quanto `extract_batch` aceitam os mesmos formatos. A diferença é que `extract` recebe **um** desses, e `extract_batch` recebe uma **lista**.

### Arquivo no disco

Passa o path como `str`. O filename vem do basename:

```python
client.extract("/dados/contrato.pdf")                  # filename = "contrato.pdf"

client.extract_batch([
    "/dados/contrato.pdf",                              # filename = "contrato.pdf"
    "/dados/cert.html",                                 # filename = "cert.html"
])
```

### Bytes em memória

Dict com `filename` obrigatório e `content` em `bytes`:

```python
pdf_bytes = ...  # vindo de upload, S3, geração programática, etc

client.extract({"filename": "contrato.pdf", "content": pdf_bytes})

client.extract_batch([
    {"filename": "a.pdf", "content": pdf_bytes_a},
    {"filename": "b.pdf", "content": pdf_bytes_b},
])
```

### Base64 string

Dict com `filename` obrigatório e `content` como `str` (assumido base64):

```python
client.extract({"filename": "contrato.pdf", "content": "JVBERi0xLjQK..."})
```

Use quando o documento já chegou como base64 (de fila, banco, payload JSON).

### Misturando formatos

`extract_batch` aceita formatos diferentes na mesma chamada:

```python
client.extract_batch([
    "/dados/contrato.pdf",                              # disco
    {"filename": "doc.pdf", "content": pdf_bytes},      # bytes
    {"filename": "fila.pdf", "content": b64_string},    # base64
])
```

## Filename: quando é obrigatório

| Input | Filename |
|---|---|
| Path (`str`) | automático — vem do basename |
| Dict (bytes ou base64) | **obrigatório** — você fornece em `"filename"` |

Se omitir o filename num dict, a SDK levanta `ValidationError` antes de qualquer requisição HTTP.

## Tratamento de erros

Erros **por documento** vêm em `r.error`. Em `extract_batch`, não interrompem os outros.

Erros que afetam a **requisição inteira** ou seu uso da SDK levantam exceção em ambos os métodos:

```python
from intellidoc_sdk import (
    IntelliDocClient,
    AuthenticationError,
    ValidationError,
    ServiceUnavailableError,
)

client = IntelliDocClient(url="...", api_key="...")

try:
    r = client.extract("/dados/contrato.pdf")
    print(r.text or r.error)
except AuthenticationError:
    # API key inválida ou ausente (HTTP 401/403)
    ...
except ValidationError as e:
    # batch rejeitado (HTTP 400/422) ou input mal-formado pré-HTTP
    # (dict sem filename, tipo de input não suportado, etc)
    print(f"Requisição rejeitada: {e}")
except ServiceUnavailableError:
    # IntelliDoc fora do ar ou erro de rede
    ...
```

## Uso em código async (FastAPI, aiohttp, Starlette)

Importa de `intellidoc_sdk.aio` em vez do namespace raiz. Mesma API, com `async`/`await`:

```python
from intellidoc_sdk.aio import IntelliDocClient

async with IntelliDocClient(url="...", api_key="...") as client:
    # 1 documento
    r = await client.extract("/dados/contrato.pdf")
    print(r.text or r.error)

    # vários documentos
    async for r in client.extract_batch(["a.pdf", "b.pdf"]):
        print(r.filename, r.text or r.error)
```

## Formatos suportados

| Categoria | Formatos |
|---|---|
| Documentos | PDF, DOCX |
| Planilhas | XLSX, XLS, ODS, CSV |
| Texto | HTML, XML, TXT |
| Imagens | JPEG, PNG, TIFF, BMP, WEBP, HEIF/HEIC |
