commoncompute 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,38 @@
1
+ node_modules/
2
+ .npm/
3
+ dist/
4
+ coverage/
5
+ .wrangler/
6
+ .pytest_cache/
7
+ __pycache__/
8
+ *.pyc
9
+ *.db
10
+ .DS_Store
11
+ .env
12
+ .env.*
13
+ !.env.example
14
+ .dev.vars
15
+ .local-test-key
16
+ Cargo.lock
17
+ .vercel
18
+
19
+ # Build artifacts — these are generated and must never be tracked.
20
+ # (Web deploys rebuild from source via `wrangler pages deploy out`.)
21
+ .next/
22
+ apps/web/out/
23
+ *.tsbuildinfo
24
+
25
+ # Xcode build output (provider app)
26
+ apps/provider/build/
27
+
28
+ # Per-app local Claude scratch dirs
29
+ apps/web/.claude/
30
+
31
+ # Playwright E2E artifacts (apps/web)
32
+ apps/web/playwright-report/
33
+ apps/web/test-results/
34
+ apps/web/.playwright/
35
+
36
+ # Local scratch — never tracked (internal notes, draft reviews)
37
+ tmp/
38
+ .venv
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Common Compute, Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,210 @@
1
+ Metadata-Version: 2.4
2
+ Name: commoncompute
3
+ Version: 0.1.0
4
+ Summary: Official Python SDK for Common Compute — the batch AI bill you shouldn't be paying.
5
+ Project-URL: Homepage, https://commoncompute.ai
6
+ Project-URL: Documentation, https://commoncompute.ai/docs
7
+ Project-URL: Source, https://github.com/Ikaikaalika/commoncomputeai
8
+ Project-URL: Changelog, https://commoncompute.ai/changelog
9
+ Author-email: Common Compute <support@commoncompute.ai>
10
+ License: MIT
11
+ License-File: LICENSE
12
+ Keywords: ai,apple-silicon,embeddings,inference,llm,openai-compatible
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.9
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
23
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
24
+ Requires-Python: >=3.9
25
+ Requires-Dist: httpx<1.0,>=0.24
26
+ Requires-Dist: pydantic<3.0,>=2.0
27
+ Provides-Extra: cli
28
+ Requires-Dist: rich>=13; extra == 'cli'
29
+ Requires-Dist: typer>=0.9; extra == 'cli'
30
+ Provides-Extra: test
31
+ Requires-Dist: pytest-asyncio>=0.21; extra == 'test'
32
+ Requires-Dist: pytest>=7.0; extra == 'test'
33
+ Requires-Dist: respx>=0.20; extra == 'test'
34
+ Description-Content-Type: text/markdown
35
+
36
+ # Common Compute — Python SDK
37
+
38
+ The official Python SDK + CLI for [Common Compute](https://commoncompute.ai) —
39
+ batch AI compute without the AWS tax, on Apple Silicon hardware AWS can't offer.
40
+
41
+ One SDK call replaces the IAM roles, compute environments, and job definitions.
42
+ Every job returns its **price and ETA before it runs**, and you're only billed
43
+ for **successful** jobs — each with a verifiable receipt.
44
+
45
+ ```bash
46
+ pip install commoncompute # core: httpx + pydantic only
47
+ pip install "commoncompute[cli]" # + the `cc` command line
48
+ cc login # opens the browser — no key to copy-paste
49
+ ```
50
+
51
+ `cc login` (or `commoncompute.connect()` from a script or notebook) opens an
52
+ approval page in your browser; click **Approve** and a fresh API key is saved
53
+ to `~/.config/commoncompute/credentials`, where the SDK finds it automatically.
54
+ Prefer explicit config? `export CC_API_KEY=cc_live_...` works everywhere and
55
+ takes precedence.
56
+
57
+ ## The 10-minute path
58
+
59
+ ```python
60
+ import commoncompute as cc
61
+
62
+ client = cc.Client() # CC_API_KEY, or ~/.commoncompute/config
63
+
64
+ job = client.transcription.create("s3://my-bucket/meeting.mp3", timestamps=True)
65
+ print(job.job_id, job.locked_price_usd, job.eta_seconds) # price known BEFORE it runs
66
+
67
+ result = client.result(job) # waits, downloads, attaches the receipt
68
+ print(result.output)
69
+ print(result.receipt) # signed proof of what ran, where, for how much
70
+ ```
71
+
72
+ ## Examples
73
+
74
+ ### 1. OCR / document extraction — vs AWS Textract
75
+
76
+ ```python
77
+ job = client.ocr.extract("https://example.com/contracts.pdf", structured=True)
78
+ result = client.result(job) # blocks + bounding boxes as JSON
79
+ ```
80
+
81
+ ### 2. Transcription in bulk
82
+
83
+ ```python
84
+ jobs = client.transcription.create_many(
85
+ [f"s3://recordings/call-{i}.mp3" for i in range(200)],
86
+ language="en",
87
+ max_concurrent=16,
88
+ )
89
+ ```
90
+
91
+ ### 3. Reranking — sharpen RAG retrieval
92
+
93
+ ```python
94
+ job = client.rerank("what is the neural engine?", documents, top_n=5)
95
+ top = client.result(job).output
96
+ ```
97
+
98
+ ### 4. Translation
99
+
100
+ ```python
101
+ job = client.translate(catalog_descriptions, target_lang="de")
102
+ ```
103
+
104
+ ### 5. Background removal
105
+
106
+ ```python
107
+ job = client.images.remove_background("product-shot.png")
108
+ ```
109
+
110
+ Also available: `client.video.transcode(...)`, `client.build.ios_test(...)`,
111
+ `client.images.generate(...)`, `client.embeddings.create(...)`, and the
112
+ generic `client.submit(workload_id, payload)` for anything in
113
+ [the catalog](https://commoncompute.ai/workloads).
114
+
115
+ ## Price before execution, hard caps, dry runs
116
+
117
+ ```python
118
+ quote = client.ocr.extract("scan.pdf", dry_run=True) # price + ETA, no job
119
+ job = client.ocr.extract("scan.pdf", max_spend_usd=1.0) # refused if it would exceed
120
+ ```
121
+
122
+ ## Batches that stream back
123
+
124
+ ```python
125
+ for result in client.submit_many("vision_bgremove", images, max_concurrent=8):
126
+ save(result.output) # results stream as they complete
127
+ ```
128
+
129
+ ## Receipts
130
+
131
+ Every successful job carries a receipt (`job_id`, cost, provider id,
132
+ timestamps, input/output hashes, signature):
133
+
134
+ ```python
135
+ client.receipts.list()
136
+ csv_blob = client.receipts.export(format="csv")
137
+ ```
138
+
139
+ ## Account
140
+
141
+ ```python
142
+ client.account.balance() # card-on-file billing state (cash only)
143
+ client.account.spend(days=30) # spend summary by workload
144
+ client.account.tier() # your volume tier + the next threshold
145
+ ```
146
+
147
+ Per-task prices step down automatically as your monthly usage grows —
148
+ your current rate is always the one a quote returns.
149
+
150
+ ## Async
151
+
152
+ ```python
153
+ async with cc.AsyncClient() as client:
154
+ job = await client.jobs.submit(workload_id="coreml_embed", payload={"input": ["hi"]})
155
+ ```
156
+
157
+ ## CLI
158
+
159
+ ```bash
160
+ cc login # stores the key locally
161
+ cc estimate vision_ocr --units 5 # price + ETA, no execution
162
+ cc submit coreml_embed --payload '{"input":["hi"]}' --wait
163
+ cc jobs list
164
+ cc jobs status <id> # via: cc jobs get <id>
165
+ cc balance
166
+ cc receipts export --format csv --out receipts.csv
167
+ ```
168
+
169
+ ## Migrating from OpenAI (optional)
170
+
171
+ Existing OpenAI-based pipelines (embeddings, chat, transcription) can point
172
+ at Common Compute by swapping two env vars — or:
173
+
174
+ ```python
175
+ from commoncompute.compat import openai # sets OPENAI_BASE_URL / OPENAI_API_KEY
176
+ client = openai.OpenAI()
177
+ ```
178
+
179
+ This is a migration path, not the recommended interface: the native client
180
+ returns locked prices, ETAs, and receipts that the OpenAI wire format can't
181
+ express.
182
+
183
+ ## Errors
184
+
185
+ Typed, always:
186
+
187
+ ```python
188
+ try:
189
+ client.ocr.extract("scan.pdf", max_spend_usd=0.01)
190
+ except cc.InsufficientFundsError: # quote exceeded the cap / no card
191
+ ...
192
+ except cc.UnsupportedFormatError: # wrong file type for the workload
193
+ ...
194
+ except cc.JobTimeoutError: # wait() expired; job still running
195
+ ...
196
+ except cc.NetworkError: # no HTTP response after retries
197
+ ...
198
+ except cc.CommonComputeError as e: # everything raises from this
199
+ print(e.request_id)
200
+ ```
201
+
202
+ ## Configuration
203
+
204
+ | Setting | Env var | Fallback |
205
+ |----------|--------------|----------|
206
+ | API key | `CC_API_KEY` | `~/.commoncompute/config`, then `~/.config/commoncompute/credentials` |
207
+ | Base URL | `CC_BASE_URL`| `https://api.commoncompute.ai` |
208
+ | Org id | `CC_ORG` | default workspace |
209
+
210
+ Python 3.9+. Core dependencies: `httpx`, `pydantic`. MIT license.
@@ -0,0 +1,175 @@
1
+ # Common Compute — Python SDK
2
+
3
+ The official Python SDK + CLI for [Common Compute](https://commoncompute.ai) —
4
+ batch AI compute without the AWS tax, on Apple Silicon hardware AWS can't offer.
5
+
6
+ One SDK call replaces the IAM roles, compute environments, and job definitions.
7
+ Every job returns its **price and ETA before it runs**, and you're only billed
8
+ for **successful** jobs — each with a verifiable receipt.
9
+
10
+ ```bash
11
+ pip install commoncompute # core: httpx + pydantic only
12
+ pip install "commoncompute[cli]" # + the `cc` command line
13
+ cc login # opens the browser — no key to copy-paste
14
+ ```
15
+
16
+ `cc login` (or `commoncompute.connect()` from a script or notebook) opens an
17
+ approval page in your browser; click **Approve** and a fresh API key is saved
18
+ to `~/.config/commoncompute/credentials`, where the SDK finds it automatically.
19
+ Prefer explicit config? `export CC_API_KEY=cc_live_...` works everywhere and
20
+ takes precedence.
21
+
22
+ ## The 10-minute path
23
+
24
+ ```python
25
+ import commoncompute as cc
26
+
27
+ client = cc.Client() # CC_API_KEY, or ~/.commoncompute/config
28
+
29
+ job = client.transcription.create("s3://my-bucket/meeting.mp3", timestamps=True)
30
+ print(job.job_id, job.locked_price_usd, job.eta_seconds) # price known BEFORE it runs
31
+
32
+ result = client.result(job) # waits, downloads, attaches the receipt
33
+ print(result.output)
34
+ print(result.receipt) # signed proof of what ran, where, for how much
35
+ ```
36
+
37
+ ## Examples
38
+
39
+ ### 1. OCR / document extraction — vs AWS Textract
40
+
41
+ ```python
42
+ job = client.ocr.extract("https://example.com/contracts.pdf", structured=True)
43
+ result = client.result(job) # blocks + bounding boxes as JSON
44
+ ```
45
+
46
+ ### 2. Transcription in bulk
47
+
48
+ ```python
49
+ jobs = client.transcription.create_many(
50
+ [f"s3://recordings/call-{i}.mp3" for i in range(200)],
51
+ language="en",
52
+ max_concurrent=16,
53
+ )
54
+ ```
55
+
56
+ ### 3. Reranking — sharpen RAG retrieval
57
+
58
+ ```python
59
+ job = client.rerank("what is the neural engine?", documents, top_n=5)
60
+ top = client.result(job).output
61
+ ```
62
+
63
+ ### 4. Translation
64
+
65
+ ```python
66
+ job = client.translate(catalog_descriptions, target_lang="de")
67
+ ```
68
+
69
+ ### 5. Background removal
70
+
71
+ ```python
72
+ job = client.images.remove_background("product-shot.png")
73
+ ```
74
+
75
+ Also available: `client.video.transcode(...)`, `client.build.ios_test(...)`,
76
+ `client.images.generate(...)`, `client.embeddings.create(...)`, and the
77
+ generic `client.submit(workload_id, payload)` for anything in
78
+ [the catalog](https://commoncompute.ai/workloads).
79
+
80
+ ## Price before execution, hard caps, dry runs
81
+
82
+ ```python
83
+ quote = client.ocr.extract("scan.pdf", dry_run=True) # price + ETA, no job
84
+ job = client.ocr.extract("scan.pdf", max_spend_usd=1.0) # refused if it would exceed
85
+ ```
86
+
87
+ ## Batches that stream back
88
+
89
+ ```python
90
+ for result in client.submit_many("vision_bgremove", images, max_concurrent=8):
91
+ save(result.output) # results stream as they complete
92
+ ```
93
+
94
+ ## Receipts
95
+
96
+ Every successful job carries a receipt (`job_id`, cost, provider id,
97
+ timestamps, input/output hashes, signature):
98
+
99
+ ```python
100
+ client.receipts.list()
101
+ csv_blob = client.receipts.export(format="csv")
102
+ ```
103
+
104
+ ## Account
105
+
106
+ ```python
107
+ client.account.balance() # card-on-file billing state (cash only)
108
+ client.account.spend(days=30) # spend summary by workload
109
+ client.account.tier() # your volume tier + the next threshold
110
+ ```
111
+
112
+ Per-task prices step down automatically as your monthly usage grows —
113
+ your current rate is always the one a quote returns.
114
+
115
+ ## Async
116
+
117
+ ```python
118
+ async with cc.AsyncClient() as client:
119
+ job = await client.jobs.submit(workload_id="coreml_embed", payload={"input": ["hi"]})
120
+ ```
121
+
122
+ ## CLI
123
+
124
+ ```bash
125
+ cc login # stores the key locally
126
+ cc estimate vision_ocr --units 5 # price + ETA, no execution
127
+ cc submit coreml_embed --payload '{"input":["hi"]}' --wait
128
+ cc jobs list
129
+ cc jobs status <id> # via: cc jobs get <id>
130
+ cc balance
131
+ cc receipts export --format csv --out receipts.csv
132
+ ```
133
+
134
+ ## Migrating from OpenAI (optional)
135
+
136
+ Existing OpenAI-based pipelines (embeddings, chat, transcription) can point
137
+ at Common Compute by swapping two env vars — or:
138
+
139
+ ```python
140
+ from commoncompute.compat import openai # sets OPENAI_BASE_URL / OPENAI_API_KEY
141
+ client = openai.OpenAI()
142
+ ```
143
+
144
+ This is a migration path, not the recommended interface: the native client
145
+ returns locked prices, ETAs, and receipts that the OpenAI wire format can't
146
+ express.
147
+
148
+ ## Errors
149
+
150
+ Typed, always:
151
+
152
+ ```python
153
+ try:
154
+ client.ocr.extract("scan.pdf", max_spend_usd=0.01)
155
+ except cc.InsufficientFundsError: # quote exceeded the cap / no card
156
+ ...
157
+ except cc.UnsupportedFormatError: # wrong file type for the workload
158
+ ...
159
+ except cc.JobTimeoutError: # wait() expired; job still running
160
+ ...
161
+ except cc.NetworkError: # no HTTP response after retries
162
+ ...
163
+ except cc.CommonComputeError as e: # everything raises from this
164
+ print(e.request_id)
165
+ ```
166
+
167
+ ## Configuration
168
+
169
+ | Setting | Env var | Fallback |
170
+ |----------|--------------|----------|
171
+ | API key | `CC_API_KEY` | `~/.commoncompute/config`, then `~/.config/commoncompute/credentials` |
172
+ | Base URL | `CC_BASE_URL`| `https://api.commoncompute.ai` |
173
+ | Org id | `CC_ORG` | default workspace |
174
+
175
+ Python 3.9+. Core dependencies: `httpx`, `pydantic`. MIT license.
@@ -0,0 +1,86 @@
1
+ """Common Compute — official Python SDK.
2
+
3
+ Thin, typed wrapper around the Common Compute HTTP API. Ships an OpenAI-
4
+ compatible path for drop-in migration plus first-class helpers for the
5
+ native job API. See https://commoncompute.ai/docs for the full reference.
6
+
7
+ Quickstart::
8
+
9
+ import commoncompute as cc
10
+
11
+ client = cc.Client(api_key="cc_live_...")
12
+ print(client.balance())
13
+
14
+ # OpenAI-compatible chat
15
+ reply = client.chat.create(
16
+ model="qwen-2.5-7b-instruct",
17
+ messages=[{"role": "user", "content": "hi"}],
18
+ )
19
+ print(reply["choices"][0]["message"]["content"])
20
+
21
+ # Native job submission
22
+ job = client.jobs.submit(
23
+ workload_id="coreml_embed",
24
+ payload={"inputs": ["hello world"]},
25
+ )
26
+ result = client.jobs.wait(job["id"])
27
+
28
+ Streaming chat::
29
+
30
+ for chunk in client.chat.stream(model="qwen-2.5-7b-instruct",
31
+ messages=[{"role": "user", "content": "hi"}]):
32
+ delta = chunk["choices"][0].get("delta", {}).get("content", "")
33
+ print(delta, end="", flush=True)
34
+ """
35
+
36
+ # MUST come before any submodule imports — _transport.py reads
37
+ # `commoncompute.__version__` at import time for the User-Agent header,
38
+ # and the previous ordering (`__version__` defined at the bottom) made
39
+ # every clean install of the SDK fail with a circular ImportError.
40
+ __version__ = "0.1.0"
41
+
42
+ from .client import Client, AsyncClient
43
+ from .errors import (
44
+ CommonComputeError,
45
+ AuthenticationError,
46
+ NotFoundError,
47
+ RateLimitError,
48
+ InsufficientFundsError,
49
+ InsufficientCreditsError, # legacy alias of InsufficientFundsError
50
+ BadRequestError,
51
+ ValidationError,
52
+ UnsupportedFormatError,
53
+ NetworkError,
54
+ JobTimeoutError,
55
+ APIError,
56
+ )
57
+ from .models import Job, Quote, Receipt, TaskResult, AccountTier, SpendSummary
58
+ from .connect import connect, login
59
+ from . import aws_batch # noqa: E402 (intentional re-export)
60
+
61
+ __all__ = [
62
+ "Client",
63
+ "AsyncClient",
64
+ "connect",
65
+ "login",
66
+ "CommonComputeError",
67
+ "AuthenticationError",
68
+ "NotFoundError",
69
+ "RateLimitError",
70
+ "InsufficientFundsError",
71
+ "InsufficientCreditsError",
72
+ "BadRequestError",
73
+ "ValidationError",
74
+ "UnsupportedFormatError",
75
+ "NetworkError",
76
+ "JobTimeoutError",
77
+ "APIError",
78
+ "Job",
79
+ "Quote",
80
+ "Receipt",
81
+ "TaskResult",
82
+ "AccountTier",
83
+ "SpendSummary",
84
+ "aws_batch",
85
+ "__version__",
86
+ ]
@@ -0,0 +1,60 @@
1
+ # @generated by packages/workloads/codegen/emit-sdk-workloads.ts — DO NOT EDIT.
2
+ # Regenerate: npx tsx packages/workloads/codegen/emit-sdk-workloads.ts
3
+ # Source of truth: packages/workloads (the shared catalog). CI fails if this
4
+ # file drifts from the catalog (see tests/unit/workloads-parity.test.ts).
5
+ from __future__ import annotations
6
+
7
+ # Every workload id in the catalog. Used to decide whether a jobDefinition head
8
+ # names a workload directly vs. a model.
9
+ KNOWN_WORKLOAD_IDS: frozenset[str] = frozenset({
10
+ "coreml_embed",
11
+ "whisper_ane",
12
+ "whisper_subtitle",
13
+ "accelerate_denoise",
14
+ "pyannote_diarize",
15
+ "audio_classify",
16
+ "avspeech_tts",
17
+ "apple_translate",
18
+ "bge_rerank",
19
+ "nl_langdetect",
20
+ "nl_ner",
21
+ "nl_sentiment",
22
+ "vision_ocr",
23
+ "vision_bgremove",
24
+ "vision_aesthetics",
25
+ "vision_face",
26
+ "vision_detect",
27
+ "vision_pose",
28
+ "vision_barcode",
29
+ "vision_segment",
30
+ "coreml_upscale",
31
+ "vt_transcode",
32
+ "videotoolbox_heic",
33
+ "av_thumbnail",
34
+ "vision_scene",
35
+ "mlx_image",
36
+ "xcode_build",
37
+ "xctest_runner",
38
+ "mlx_small_rag",
39
+ "mlx_llm",
40
+ "mlx_llm_long_ctx",
41
+ "coreml_vision",
42
+ "sd_mlx",
43
+ "mlx_finetune",
44
+ "pytorch_mps",
45
+ "blender_metal",
46
+ "cpu_bench",
47
+ })
48
+
49
+ # (regex source, workload_id), highest priority first. Compile with re.IGNORECASE.
50
+ IMAGE_PATTERNS: tuple[tuple[str, str], ...] = (
51
+ ("whisper", "whisper_ane"),
52
+ ("(embed|sentence-transformer|bge|e5-)", "coreml_embed"),
53
+ ("(stable-diffusion|sdxl|sd-|sd_)", "sd_mlx"),
54
+ ("(flux|mlx-image)", "mlx_image"),
55
+ ("(llama|mistral|qwen|mlx-llm|chat-llm)", "mlx_llm"),
56
+ ("(ffmpeg|transcode|videotoolbox|vt[-_])", "vt_transcode"),
57
+ ("(ocr|tesseract|textract)", "vision_ocr"),
58
+ ("(blender|cycles)", "blender_metal"),
59
+ ("(pytorch|torch)", "pytorch_mps"),
60
+ )