Metadata-Version: 2.4
Name: commoncompute
Version: 0.2.0
Summary: Official Python SDK for Common Compute — the batch AI bill you shouldn't be paying.
Project-URL: Homepage, https://commoncompute.ai
Project-URL: Documentation, https://commoncompute.ai/docs
Project-URL: Source, https://github.com/Ikaikaalika/commoncomputeai
Project-URL: Changelog, https://commoncompute.ai/changelog
Author-email: Common Compute <support@commoncompute.ai>
License: MIT
License-File: LICENSE
Keywords: ai,apple-silicon,embeddings,inference,llm,openai-compatible
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
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 :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.9
Requires-Dist: httpx<1.0,>=0.24
Requires-Dist: pydantic<3.0,>=2.0
Provides-Extra: cli
Requires-Dist: rich>=13; extra == 'cli'
Requires-Dist: typer>=0.9; extra == 'cli'
Provides-Extra: test
Requires-Dist: pytest-asyncio>=0.21; extra == 'test'
Requires-Dist: pytest>=7.0; extra == 'test'
Requires-Dist: respx>=0.20; extra == 'test'
Description-Content-Type: text/markdown

# Common Compute — Python SDK

The official Python SDK + CLI for [Common Compute](https://commoncompute.ai) —
batch AI compute without the AWS tax, on Apple Silicon hardware AWS can't offer.

One SDK call replaces the IAM roles, compute environments, and job definitions.
Every job returns its **price and ETA before it runs**, and you're only billed
for **successful** jobs — each with a verifiable receipt.

```bash
pip install commoncompute          # core: httpx + pydantic only
pip install "commoncompute[cli]"   # + the `cc` command line
cc login                           # opens the browser — no key to copy-paste
```

`cc login` (or `commoncompute.connect()` from a script or notebook) opens an
approval page in your browser; click **Approve** and a fresh API key is saved
to `~/.config/commoncompute/credentials`, where the SDK finds it automatically.
Prefer explicit config? `export CC_API_KEY=cc_live_...` works everywhere and
takes precedence.

## The 10-minute path

```python
import commoncompute as cc

client = cc.Client()   # reads CC_API_KEY, or the saved credentials file

job = client.transcription.create("s3://my-bucket/meeting.mp3", timestamps=True)
print(job.job_id, job.locked_price_usd, job.eta_seconds)   # price known BEFORE it runs

result = client.result(job)          # waits, downloads, attaches the receipt
print(result.output)
print(result.receipt)                # signed proof of what ran, where, for how much
```

## Examples

### 1. OCR / document extraction — vs AWS Textract

```python
job = client.ocr.extract("https://example.com/contracts.pdf", structured=True)
result = client.result(job)          # blocks + bounding boxes as JSON
```

### 2. Transcription in bulk

```python
jobs = client.transcription.create_many(
    [f"s3://recordings/call-{i}.mp3" for i in range(200)],
    language="en",
    max_concurrent=16,
)
```

### 3. Reranking — sharpen RAG retrieval

```python
job = client.rerank("what is the neural engine?", documents, top_n=5)
top = client.result(job).output
```

### 4. Translation

```python
job = client.translate(catalog_descriptions, target_lang="de")
```

### 5. Background removal

```python
job = client.images.remove_background("product-shot.png")
```

Also available: `client.video.transcode(...)`, `client.build.ios_test(...)`,
`client.images.generate(...)`, `client.embeddings.create(...)`, and the
generic `client.submit(workload_id, payload)` for anything in
[the catalog](https://commoncompute.ai/workloads).

## Price before execution, hard caps, dry runs

```python
quote = client.ocr.extract("scan.pdf", dry_run=True)     # price + ETA, no job
job = client.ocr.extract("scan.pdf", max_spend_usd=1.0)  # refused if it would exceed
```

## Batches that stream back

```python
for result in client.submit_many("vision_bgremove", images, max_concurrent=8):
    save(result.output)              # results stream as they complete
```

## Receipts

Every successful job carries a receipt (`job_id`, cost, provider id,
timestamps, input/output hashes, signature):

```python
client.receipts.list()
csv_blob = client.receipts.export(format="csv")
```

## Account

```python
client.account.balance()         # card-on-file billing state (cash only)
client.account.spend(days=30)    # spend summary by workload
client.account.tier()            # your volume tier + the next threshold
```

Per-task prices step down automatically as your monthly usage grows —
your current rate is always the one a quote returns.

## Async

`AsyncClient` mirrors `Client` method-for-method — `submit`, `wait`, `result`,
and `submit_many` all have `await`-able twins. Use it as an async context
manager so the underlying HTTP pool is closed for you:

```python
import asyncio
import commoncompute as cc

async def main():
    async with cc.AsyncClient() as client:          # closes the pool on exit
        job = await client.submit("coreml_embed", {"input": ["hello world"]})
        print(job.job_id, job.locked_price_usd, job.eta_seconds)  # price BEFORE it runs

        await client.wait(job)                       # poll until terminal
        result = await client.result(job)            # + download output & receipt
        print(result.output)

asyncio.run(main())
```

Batches stream back the same way — `submit_many` is an async generator:

```python
async with cc.AsyncClient() as client:
    async for r in client.submit_many("coreml_embed", batches, max_concurrent=8):
        save(r.output)                               # each result as it completes
```

The lower-level `client.jobs.*` namespace (`jobs.submit`, `jobs.wait`,
`jobs.get`, `jobs.events`, `jobs.download`) is async here too when you want the
raw request/response dicts instead of typed `Job`/`TaskResult` objects.

## CLI

`pip install "commoncompute[cli]"` installs the `cc` command.

```bash
cc login                              # stores the key locally
cc quote vision_ocr --units 5         # price + ETA, no execution
cc submit coreml_embed --payload '{"input":["hi"]}' --wait
cc jobs list
cc jobs get <id>
cc balance
cc receipts export --format csv --out receipts.csv
```

### Commands

| Command | What it does |
|---------|--------------|
| `cc login` / `cc logout` | Store / remove the API key (browser approval, or `--api-key`) |
| `cc whoami` | Show the account behind the current key |
| `cc balance` | Current workspace balance |
| `cc usage` | Spend + call-count rollups over a date range (`--start`, `--end`, `--group-by`) |
| `cc spend` | Total spend over the last `--days` N, grouped by workload |
| `cc tier` | Current volume tier and the next threshold |
| `cc workloads` | List available workloads |
| `cc models` | List models (`--workload` to filter) |
| `cc quote` | Price + ETA for a workload without submitting (`--units`, `--priority`, `--model`) |
| `cc submit` | Submit one job (`--payload/-f`, `--model`, `--priority`, `--wait`, `--timeout`) |
| `cc submit-many` | Submit a JSONL file of payloads; stream one result per line as NDJSON (`--input/-i`, `--max-concurrent`, `--no-wait`) |
| `cc chat` | One-shot chat message to a model (`--model`, `--stream/--no-stream`) |
| `cc embed` | Embed a single string (prints the vector length) |
| `cc playground` | Open the web playground |
| `cc jobs list` | Recent submissions, newest first (`--limit/-n`) |
| `cc jobs get <id>` | Fetch one job |
| `cc jobs wait <id>` | Poll a job to a terminal state (`--timeout/-t`) |
| `cc jobs events <id>` | Event timeline for a job |
| `cc jobs download <id>` | Download a job's result (`--out/-o`, else stdout) |
| `cc keys list` / `create` / `revoke` | Manage API keys |
| `cc receipts list` | Receipts for completed jobs (`--limit/-n`) |
| `cc receipts get <id>` | Signed receipt for a single job |
| `cc receipts export` | Export receipts as CSV or JSON (`--format/-f`, `--out/-o`, `--limit/-n`) |
| `cc config path` / `show` / `set` / `unset` | Inspect and edit local settings (see below) |

`cc --version` (or `-V`) prints the version. Every read command that renders a
table also accepts **`--json`** for plain, ANSI-free machine-readable output —
`whoami`, `balance`, `usage`, `spend`, `tier`, `workloads`, `models`, `quote`,
`submit`, `jobs list/get/wait/events`, `keys list`, and `receipts list`.

### Shell completion

Typer ships completion for bash, zsh, fish, and PowerShell:

```bash
cc --install-completion        # install for the current shell
cc --show-completion           # print the script to inspect or customise
```

### Exit codes

Scripts can branch on `cc`'s exit status:

| Code | Meaning |
|------|---------|
| `0` | Success |
| `1` | API or runtime error (network, server, bad request) |
| `2` | Usage error — missing/invalid arguments, or no credentials found |
| `3` | The job reached a **failed** terminal state (`failed` / `dead_letter` / `cancelled`) — `cc jobs wait` and `cc submit --wait` only |

## Migrating from OpenAI (optional)

Existing OpenAI-based pipelines (embeddings, chat, transcription) can point
at Common Compute by swapping two env vars — or:

```python
from commoncompute.compat import openai   # sets OPENAI_BASE_URL / OPENAI_API_KEY
client = openai.OpenAI()
```

This is a migration path, not the recommended interface: the native client
returns locked prices, ETAs, and receipts that the OpenAI wire format can't
express.

## Errors

Typed, always:

```python
try:
    client.ocr.extract("scan.pdf", max_spend_usd=0.01)
except cc.InsufficientFundsError:      # quote exceeded the cap / no card
    ...
except cc.PermissionDeniedError:       # key lacks scope for this workload
    ...
except cc.ConflictError:               # idempotency-key or state conflict (409)
    ...
except cc.UnsupportedFormatError:      # wrong file type for the workload
    ...
except cc.JobTimeoutError:             # wait() expired; job still running
    ...
except cc.NetworkError:                # no HTTP response after retries
    ...
except cc.CommonComputeError as e:     # everything raises from this
    print(e.request_id)
```

The full hierarchy — `AuthenticationError`, `PermissionDeniedError`,
`NotFoundError`, `ConflictError`, `RateLimitError`, `InsufficientFundsError`,
`BadRequestError`, `ValidationError`, `UnsupportedFormatError`, `NetworkError`,
`JobTimeoutError`, `APIError` — all subclass `CommonComputeError`.

## Configuration

Credentials and settings live under one canonical directory (override the whole
directory with `$CC_CONFIG_DIR`):

```
~/.config/commoncompute/credentials   # the API key (single line)
~/.config/commoncompute/config        # settings: base_url, org (key = value)
```

Two **legacy** locations are still read (never written) so older installs keep
working: `~/.commoncompute/config` and `~/.commoncompute/credentials`.

Environment variables take precedence over both files at runtime:

| Setting  | Env var         | Resolution order (first match wins) |
|----------|-----------------|-------------------------------------|
| API key  | `CC_API_KEY`    | env → `~/.config/commoncompute/credentials` → `~/.commoncompute/config` → `~/.commoncompute/credentials` |
| Base URL | `CC_BASE_URL`   | env → `config` file `base_url` → `https://api.commoncompute.ai` |
| Org id   | `CC_ORG`        | env → `config` file `org` → default workspace |
| Config dir | `CC_CONFIG_DIR` | overrides the `~/.config/commoncompute` location above |

Inspect and edit the local config from the CLI:

```bash
cc config path                        # print the config directory
cc config show                        # settings + active credential source (key masked)
cc config set base_url https://api.commoncompute.ai
cc config set org my-workspace
cc config unset org
```

Env vars still win at runtime — `cc config set` writes the file, but
`CC_BASE_URL` / `CC_ORG` override it for a given process.

Python 3.9+. Core dependencies: `httpx`, `pydantic`. MIT license.
