Metadata-Version: 2.4
Name: voxelion
Version: 0.1.0
Summary: Perceptual deduplication for image datasets — the official Python client for the Voxelion API.
Project-URL: Homepage, https://voxelion.ai
Project-URL: Documentation, https://voxelion.ai/docs/
Project-URL: Changelog, https://github.com/Asekun/bioHarmonix/blob/main/sdk/python/CHANGELOG.md
Author: Voxelion
License-Expression: MIT
License-File: LICENSE
Keywords: data-quality,dataset,deduplication,dicom,machine-learning,perceptual-hash
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Science/Research
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 :: Image Processing
Classifier: Typing :: Typed
Requires-Python: >=3.9
Requires-Dist: httpx<1,>=0.24
Requires-Dist: pydantic<3,>=2
Provides-Extra: dev
Requires-Dist: mypy>=1.8; extra == 'dev'
Requires-Dist: pytest-httpx>=0.30; extra == 'dev'
Requires-Dist: pytest>=7; extra == 'dev'
Requires-Dist: ruff>=0.4; extra == 'dev'
Description-Content-Type: text/markdown

# voxelion

Perceptual deduplication for image datasets — the official Python client for the
[Voxelion API](https://voxelion.ai/docs/).

Voxelion finds the files in a dataset that are the *same image* — after
re-encoding, resizing, format conversion or a metadata rewrite — and tells you
which ones are redundant. It never deletes anything.

```bash
pip install voxelion
```

## Quickstart

```python
from voxelion import Voxelion

vx = Voxelion()                       # reads VOXELION_API_KEY
report = vx.dedup(["a.png", "b.png", "c.png"], engine="curate")

print(f"{report.leakage:.1%} redundant across {report.count} images")
for cluster in report.clusters:
    print("same image:", ", ".join(cluster))
```

Create a key in the console under **API Keys**, then:

```bash
export VOXELION_API_KEY=pk_live_...
```

## Large datasets

A batch that fits in one upload goes through `dedup()`. Anything larger is
queued, which survives a disconnect and reports progress:

```python
job = vx.submit_job("corpus.zip", engine="curate")
print(job.id, job.status)

report = job.wait()                   # polls with backoff
plan = vx.manifest(report.id)
print(f"keep {len(plan.keep)}, drop {len(plan.drop)}")
```

`plan.drop` is a list of filenames. **Voxelion does not delete them** — what
you do with the plan is yours to decide.

## Engines

| Engine | For |
|---|---|
| `health` | Medical imaging. DICOM-aware: a CT or MR series is deduplicated as a scan, not as loose slices. |
| `curate` | General image archives — product photography, scraped corpora, generated output. |

Omit `engine=` to use your account's default. The engine that actually ran is
on the report either way:

```python
report = vx.dedup(files)
print(report.engine)                  # "curate"
```

## Errors

Exceptions are typed by what went wrong, not by status code:

```python
from voxelion import InsufficientCreditError, ConsentRequiredError

try:
    report = vx.dedup(files)
except InsufficientCreditError as e:
    print(f"needs {e.required_cents}c, have {e.available_cents}c")
except ConsentRequiredError:
    print("Grant data-processing consent in the console first.")
```

`429` responses honour the server's `Retry-After` automatically, and `5xx`
retries with exponential backoff. Nothing else is retried: a `402` will not
become affordable by asking again.

## Sandbox

The sandbox is a separate deployment with its own database and accounts. It is
the same client with a different base URL:

```python
from voxelion import Voxelion, SANDBOX_BASE_URL

vx = Voxelion(base_url=SANDBOX_BASE_URL)
```

## Checking cost before spending

```python
account = vx.balance()
print(account.spendable_cents)        # not balance_cents — see below
```

`spendable_cents` is the balance minus credit already held against runs in
flight. It is the number that decides whether the next call succeeds.

## Development

Models in `src/voxelion/models.py` are **generated** from the API's OpenAPI
document. Do not edit them by hand:

```bash
./scripts-generate.sh
```

```bash
pytest                      # unit tests, no network
pytest -m live              # against a real deployment; needs VOXELION_API_KEY
```
