clipia 1.0.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,9 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ .pytest_cache/
4
+ *.egg-info/
5
+ build/
6
+ dist/
7
+ .venv/
8
+ .mypy_cache/
9
+ .ruff_cache/
clipia-1.0.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Clipia (ИП Захаров М. С.)
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.
clipia-1.0.0/PKG-INFO ADDED
@@ -0,0 +1,239 @@
1
+ Metadata-Version: 2.4
2
+ Name: clipia
3
+ Version: 1.0.0
4
+ Summary: Official Python SDK for the Clipia public API (image & video generation, fal-style queue).
5
+ Project-URL: Homepage, https://clipia.ai
6
+ Project-URL: Documentation, https://api.clipia.ai
7
+ Project-URL: Source, https://github.com/clipia-ai/clipia-python
8
+ Project-URL: Issues, https://github.com/clipia-ai/clipia-python/issues
9
+ Author-email: Clipia <support@clipia.ai>
10
+ License: MIT
11
+ License-File: LICENSE
12
+ Keywords: ai,api,clipia,generative-ai,image-generation,image-to-video,mcp,sdk,text-to-image,text-to-video,video-generation
13
+ Classifier: Development Status :: 5 - Production/Stable
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.9
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Programming Language :: Python :: 3.13
23
+ Classifier: Topic :: Multimedia :: Graphics
24
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
25
+ Classifier: Typing :: Typed
26
+ Requires-Python: >=3.9
27
+ Requires-Dist: httpx>=0.27
28
+ Provides-Extra: dev
29
+ Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
30
+ Requires-Dist: pytest>=8.0; extra == 'dev'
31
+ Requires-Dist: respx>=0.21; extra == 'dev'
32
+ Description-Content-Type: text/markdown
33
+
34
+ # clipia — Python SDK
35
+
36
+ Official Python SDK for the [Clipia](https://clipia.ai) public API: queue-based
37
+ AI image & video generation with a `submit → status → result` flow and signed
38
+ webhooks. The DX mirrors fal.ai, but is Clipia-native (credits, not USD).
39
+
40
+ - Sync (`Clipia`) and async (`AsyncClipia`) clients
41
+ - High-level `subscribe()` that submits and polls until the job finishes
42
+ - Typed responses (`SubmitResponse`, `StatusResponse`, `ResultResponse`, ...)
43
+ - HMAC-SHA256 webhook signature verification
44
+ - Single runtime dependency: [`httpx`](https://www.python-httpx.org/)
45
+
46
+ > Prefer driving Clipia from an AI agent (Claude Code / Cursor) instead of
47
+ > writing code? Clipia ships a hosted **MCP server** — no SDK required. See
48
+ > [Using Clipia via MCP](#using-clipia-via-mcp-claude-code--cursor) below.
49
+
50
+ ## Install
51
+
52
+ ```bash
53
+ pip install clipia
54
+ ```
55
+
56
+ Requires Python 3.9+.
57
+
58
+ ## Authentication
59
+
60
+ Create an API key in your Clipia dashboard (`Settings → API keys`). The key is
61
+ shown once — store it as a server-side secret (never ship it to browsers or
62
+ mobile apps). It is sent as `Authorization: Bearer <key>`.
63
+
64
+ ```bash
65
+ export CLIPIA_KEY="clipia_live_xxxxxxxxxxxxxxxxxxxxxx"
66
+ ```
67
+
68
+ Keys come in two flavours: `clipia_live_…` (production, charges credits) and
69
+ `clipia_test_…` (sandbox — instant mock results, no credits charged). Use a
70
+ test key to validate your integration before going live.
71
+
72
+ ## Quickstart (sync)
73
+
74
+ ```python
75
+ import os
76
+ from clipia import Clipia
77
+
78
+ client = Clipia(api_key=os.environ["CLIPIA_KEY"])
79
+
80
+ # One call: submit + poll until COMPLETED / FAILED.
81
+ result = client.subscribe(
82
+ "nano-banana-2",
83
+ input={"prompt": "a sunset over mountains, cinematic"},
84
+ on_queue_update=lambda s: print("status:", s.status, s.progress),
85
+ )
86
+ print(result.output["images"][0]["url"])
87
+ ```
88
+
89
+ ### Manual queue control
90
+
91
+ ```python
92
+ job = client.submit("nano-banana-2", input={"prompt": "a cat"})
93
+ print(job.request_id, job.cost)
94
+
95
+ status = client.status(job.request_id) # IN_QUEUE | IN_PROGRESS | COMPLETED | FAILED
96
+ result = client.result(job.request_id) # result.pending == True while still running (HTTP 202)
97
+ ```
98
+
99
+ > A generation cannot be canceled: credits are reserved the moment it starts
100
+ > and the underlying compute cannot be interrupted. Submit deliberately — and
101
+ > use a `clipia_test_…` sandbox key while iterating.
102
+
103
+ ### Models, cost estimate & account
104
+
105
+ ```python
106
+ client.models.list() # { "data": [ ... ] }
107
+ client.models.get("nano-banana-2")
108
+
109
+ # Deterministic credit cost for an input, before you submit.
110
+ est = client.models.estimate("seedance-2-fast-t2v", {"prompt": "neon city", "duration": 8})
111
+ print(est.credits)
112
+
113
+ client.account.get() # { "balance": { "credits": ... }, "usage_30d": { ... } }
114
+ ```
115
+
116
+ The client is also a context manager:
117
+
118
+ ```python
119
+ with Clipia(api_key=os.environ["CLIPIA_KEY"]) as client:
120
+ client.account.get()
121
+ ```
122
+
123
+ ## Quickstart (async)
124
+
125
+ ```python
126
+ import asyncio, os
127
+ from clipia import AsyncClipia
128
+
129
+ async def main():
130
+ async with AsyncClipia(api_key=os.environ["CLIPIA_KEY"]) as client:
131
+ result = await client.subscribe(
132
+ "seedance-2-fast-i2v",
133
+ input={"image_url": "https://.../in.png", "duration": 4},
134
+ )
135
+ print(result.output["video"]["url"])
136
+
137
+ asyncio.run(main())
138
+ ```
139
+
140
+ `on_queue_update` may be a plain function or an `async def` coroutine.
141
+
142
+ ## Idempotency
143
+
144
+ `submit()` (and `subscribe()`) automatically attach a UUID v4 `Idempotency-Key`
145
+ header so network retries are safe. Pass your own to control retries:
146
+
147
+ ```python
148
+ client.submit("nano-banana-2", input={"prompt": "x"}, idempotency_key="order-42")
149
+ ```
150
+
151
+ ## Webhooks
152
+
153
+ Pass `webhook_url` to `submit()`/`subscribe()` and Clipia will POST the result to
154
+ your server. Always verify the signature on the **raw** request body:
155
+
156
+ ```python
157
+ from clipia import verify_signature
158
+
159
+ # In your web handler (Flask/FastAPI/etc.):
160
+ ok = verify_signature(
161
+ secret=WEBHOOK_SIGNING_SECRET, # from your dashboard
162
+ headers=request.headers, # X-Clipia-Signature: t=...,v1=...
163
+ body=raw_request_body, # bytes or str, exactly as received
164
+ tolerance_seconds=300, # freshness window (default 5 min)
165
+ )
166
+ if not ok:
167
+ return ("invalid signature", 400)
168
+ ```
169
+
170
+ The delivery payload carries `status` `"OK"` (success) or `"ERROR"` (failed).
171
+ Verification is constant-time and rejects deliveries whose timestamp is outside
172
+ the tolerance window. Treat webhooks as **idempotent by `request_id`** —
173
+ deliveries can repeat.
174
+
175
+ ## Errors
176
+
177
+ Non-2xx responses raise `ClipiaApiError`:
178
+
179
+ ```python
180
+ from clipia import ClipiaApiError
181
+
182
+ try:
183
+ client.submit("nano-banana-2", input={"prompt": "x"})
184
+ except ClipiaApiError as e:
185
+ print(e.status, e.code, e.message) # e.g. 402 insufficient_credits "..."
186
+ ```
187
+
188
+ `subscribe()` raises `ClipiaTimeoutError` (a subclass of `ClipiaApiError`,
189
+ `status=0`, `code="poll_timeout"`) if the job does not reach a terminal status
190
+ within `timeout` seconds.
191
+
192
+ ## Using Clipia via MCP (Claude Code / Cursor)
193
+
194
+ Clipia hosts a remote **Model Context Protocol** server, so an AI coding agent
195
+ can generate images/video, poll results, list models, search prompt templates
196
+ and read your balance directly — **no SDK or code required**. The server is
197
+ stateless Streamable HTTP at `https://api.clipia.ai/mcp` and authenticates with
198
+ the same API key (as a Bearer token).
199
+
200
+ Tools exposed: `generate_image`, `generate_video`, `wait_generation`,
201
+ `get_generation`, `list_models`, `get_model`, `get_balance`, `search_templates`.
202
+
203
+ ### Claude Code
204
+
205
+ ```bash
206
+ claude mcp add --transport http clipia https://api.clipia.ai/mcp \
207
+ --header "Authorization: Bearer clipia_live_xxxxxxxx"
208
+ ```
209
+
210
+ ### Cursor
211
+
212
+ Add to `~/.cursor/mcp.json` (or the project's `.cursor/mcp.json`):
213
+
214
+ ```json
215
+ {
216
+ "mcpServers": {
217
+ "clipia": {
218
+ "url": "https://api.clipia.ai/mcp",
219
+ "headers": {
220
+ "Authorization": "Bearer clipia_live_xxxxxxxx"
221
+ }
222
+ }
223
+ }
224
+ }
225
+ ```
226
+
227
+ Use a `clipia_test_…` key first to exercise the integration with instant mock
228
+ results and no credit charges.
229
+
230
+ ## Development
231
+
232
+ ```bash
233
+ pip install -e ".[dev]"
234
+ pytest -q
235
+ ```
236
+
237
+ ## License
238
+
239
+ MIT — see [LICENSE](./LICENSE).
clipia-1.0.0/README.md ADDED
@@ -0,0 +1,206 @@
1
+ # clipia — Python SDK
2
+
3
+ Official Python SDK for the [Clipia](https://clipia.ai) public API: queue-based
4
+ AI image & video generation with a `submit → status → result` flow and signed
5
+ webhooks. The DX mirrors fal.ai, but is Clipia-native (credits, not USD).
6
+
7
+ - Sync (`Clipia`) and async (`AsyncClipia`) clients
8
+ - High-level `subscribe()` that submits and polls until the job finishes
9
+ - Typed responses (`SubmitResponse`, `StatusResponse`, `ResultResponse`, ...)
10
+ - HMAC-SHA256 webhook signature verification
11
+ - Single runtime dependency: [`httpx`](https://www.python-httpx.org/)
12
+
13
+ > Prefer driving Clipia from an AI agent (Claude Code / Cursor) instead of
14
+ > writing code? Clipia ships a hosted **MCP server** — no SDK required. See
15
+ > [Using Clipia via MCP](#using-clipia-via-mcp-claude-code--cursor) below.
16
+
17
+ ## Install
18
+
19
+ ```bash
20
+ pip install clipia
21
+ ```
22
+
23
+ Requires Python 3.9+.
24
+
25
+ ## Authentication
26
+
27
+ Create an API key in your Clipia dashboard (`Settings → API keys`). The key is
28
+ shown once — store it as a server-side secret (never ship it to browsers or
29
+ mobile apps). It is sent as `Authorization: Bearer <key>`.
30
+
31
+ ```bash
32
+ export CLIPIA_KEY="clipia_live_xxxxxxxxxxxxxxxxxxxxxx"
33
+ ```
34
+
35
+ Keys come in two flavours: `clipia_live_…` (production, charges credits) and
36
+ `clipia_test_…` (sandbox — instant mock results, no credits charged). Use a
37
+ test key to validate your integration before going live.
38
+
39
+ ## Quickstart (sync)
40
+
41
+ ```python
42
+ import os
43
+ from clipia import Clipia
44
+
45
+ client = Clipia(api_key=os.environ["CLIPIA_KEY"])
46
+
47
+ # One call: submit + poll until COMPLETED / FAILED.
48
+ result = client.subscribe(
49
+ "nano-banana-2",
50
+ input={"prompt": "a sunset over mountains, cinematic"},
51
+ on_queue_update=lambda s: print("status:", s.status, s.progress),
52
+ )
53
+ print(result.output["images"][0]["url"])
54
+ ```
55
+
56
+ ### Manual queue control
57
+
58
+ ```python
59
+ job = client.submit("nano-banana-2", input={"prompt": "a cat"})
60
+ print(job.request_id, job.cost)
61
+
62
+ status = client.status(job.request_id) # IN_QUEUE | IN_PROGRESS | COMPLETED | FAILED
63
+ result = client.result(job.request_id) # result.pending == True while still running (HTTP 202)
64
+ ```
65
+
66
+ > A generation cannot be canceled: credits are reserved the moment it starts
67
+ > and the underlying compute cannot be interrupted. Submit deliberately — and
68
+ > use a `clipia_test_…` sandbox key while iterating.
69
+
70
+ ### Models, cost estimate & account
71
+
72
+ ```python
73
+ client.models.list() # { "data": [ ... ] }
74
+ client.models.get("nano-banana-2")
75
+
76
+ # Deterministic credit cost for an input, before you submit.
77
+ est = client.models.estimate("seedance-2-fast-t2v", {"prompt": "neon city", "duration": 8})
78
+ print(est.credits)
79
+
80
+ client.account.get() # { "balance": { "credits": ... }, "usage_30d": { ... } }
81
+ ```
82
+
83
+ The client is also a context manager:
84
+
85
+ ```python
86
+ with Clipia(api_key=os.environ["CLIPIA_KEY"]) as client:
87
+ client.account.get()
88
+ ```
89
+
90
+ ## Quickstart (async)
91
+
92
+ ```python
93
+ import asyncio, os
94
+ from clipia import AsyncClipia
95
+
96
+ async def main():
97
+ async with AsyncClipia(api_key=os.environ["CLIPIA_KEY"]) as client:
98
+ result = await client.subscribe(
99
+ "seedance-2-fast-i2v",
100
+ input={"image_url": "https://.../in.png", "duration": 4},
101
+ )
102
+ print(result.output["video"]["url"])
103
+
104
+ asyncio.run(main())
105
+ ```
106
+
107
+ `on_queue_update` may be a plain function or an `async def` coroutine.
108
+
109
+ ## Idempotency
110
+
111
+ `submit()` (and `subscribe()`) automatically attach a UUID v4 `Idempotency-Key`
112
+ header so network retries are safe. Pass your own to control retries:
113
+
114
+ ```python
115
+ client.submit("nano-banana-2", input={"prompt": "x"}, idempotency_key="order-42")
116
+ ```
117
+
118
+ ## Webhooks
119
+
120
+ Pass `webhook_url` to `submit()`/`subscribe()` and Clipia will POST the result to
121
+ your server. Always verify the signature on the **raw** request body:
122
+
123
+ ```python
124
+ from clipia import verify_signature
125
+
126
+ # In your web handler (Flask/FastAPI/etc.):
127
+ ok = verify_signature(
128
+ secret=WEBHOOK_SIGNING_SECRET, # from your dashboard
129
+ headers=request.headers, # X-Clipia-Signature: t=...,v1=...
130
+ body=raw_request_body, # bytes or str, exactly as received
131
+ tolerance_seconds=300, # freshness window (default 5 min)
132
+ )
133
+ if not ok:
134
+ return ("invalid signature", 400)
135
+ ```
136
+
137
+ The delivery payload carries `status` `"OK"` (success) or `"ERROR"` (failed).
138
+ Verification is constant-time and rejects deliveries whose timestamp is outside
139
+ the tolerance window. Treat webhooks as **idempotent by `request_id`** —
140
+ deliveries can repeat.
141
+
142
+ ## Errors
143
+
144
+ Non-2xx responses raise `ClipiaApiError`:
145
+
146
+ ```python
147
+ from clipia import ClipiaApiError
148
+
149
+ try:
150
+ client.submit("nano-banana-2", input={"prompt": "x"})
151
+ except ClipiaApiError as e:
152
+ print(e.status, e.code, e.message) # e.g. 402 insufficient_credits "..."
153
+ ```
154
+
155
+ `subscribe()` raises `ClipiaTimeoutError` (a subclass of `ClipiaApiError`,
156
+ `status=0`, `code="poll_timeout"`) if the job does not reach a terminal status
157
+ within `timeout` seconds.
158
+
159
+ ## Using Clipia via MCP (Claude Code / Cursor)
160
+
161
+ Clipia hosts a remote **Model Context Protocol** server, so an AI coding agent
162
+ can generate images/video, poll results, list models, search prompt templates
163
+ and read your balance directly — **no SDK or code required**. The server is
164
+ stateless Streamable HTTP at `https://api.clipia.ai/mcp` and authenticates with
165
+ the same API key (as a Bearer token).
166
+
167
+ Tools exposed: `generate_image`, `generate_video`, `wait_generation`,
168
+ `get_generation`, `list_models`, `get_model`, `get_balance`, `search_templates`.
169
+
170
+ ### Claude Code
171
+
172
+ ```bash
173
+ claude mcp add --transport http clipia https://api.clipia.ai/mcp \
174
+ --header "Authorization: Bearer clipia_live_xxxxxxxx"
175
+ ```
176
+
177
+ ### Cursor
178
+
179
+ Add to `~/.cursor/mcp.json` (or the project's `.cursor/mcp.json`):
180
+
181
+ ```json
182
+ {
183
+ "mcpServers": {
184
+ "clipia": {
185
+ "url": "https://api.clipia.ai/mcp",
186
+ "headers": {
187
+ "Authorization": "Bearer clipia_live_xxxxxxxx"
188
+ }
189
+ }
190
+ }
191
+ }
192
+ ```
193
+
194
+ Use a `clipia_test_…` key first to exercise the integration with instant mock
195
+ results and no credit charges.
196
+
197
+ ## Development
198
+
199
+ ```bash
200
+ pip install -e ".[dev]"
201
+ pytest -q
202
+ ```
203
+
204
+ ## License
205
+
206
+ MIT — see [LICENSE](./LICENSE).
@@ -0,0 +1,49 @@
1
+ """Clipia — official Python SDK for the Clipia public API.
2
+
3
+ Quickstart (sync)::
4
+
5
+ from clipia import Clipia
6
+
7
+ client = Clipia(api_key="clipia_live_...")
8
+ result = client.subscribe("nano-banana-2", input={"prompt": "a sunset over mountains"})
9
+ print(result.output)
10
+
11
+ Quickstart (async)::
12
+
13
+ import asyncio
14
+ from clipia import AsyncClipia
15
+
16
+ async def main():
17
+ async with AsyncClipia(api_key="clipia_live_...") as client:
18
+ result = await client.subscribe("nano-banana-2", input={"prompt": "a cat"})
19
+ print(result.output)
20
+
21
+ asyncio.run(main())
22
+ """
23
+
24
+ from __future__ import annotations
25
+
26
+ from ._async_client import AsyncClipia
27
+ from ._client import Clipia
28
+ from ._errors import ClipiaApiError, ClipiaTimeoutError
29
+ from ._types import (
30
+ EstimateResponse,
31
+ ResultResponse,
32
+ StatusResponse,
33
+ SubmitResponse,
34
+ )
35
+ from ._version import __version__
36
+ from .webhooks import verify_signature
37
+
38
+ __all__ = [
39
+ "Clipia",
40
+ "AsyncClipia",
41
+ "ClipiaApiError",
42
+ "ClipiaTimeoutError",
43
+ "SubmitResponse",
44
+ "StatusResponse",
45
+ "ResultResponse",
46
+ "EstimateResponse",
47
+ "verify_signature",
48
+ "__version__",
49
+ ]