creativai 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.
Files changed (39) hide show
  1. creativai-0.1.0/PKG-INFO +473 -0
  2. creativai-0.1.0/README.md +440 -0
  3. creativai-0.1.0/creativai/__init__.py +63 -0
  4. creativai-0.1.0/creativai/_http.py +208 -0
  5. creativai-0.1.0/creativai/client.py +161 -0
  6. creativai-0.1.0/creativai/exceptions.py +78 -0
  7. creativai-0.1.0/creativai/resources/__init__.py +53 -0
  8. creativai-0.1.0/creativai/resources/agentic_chat.py +122 -0
  9. creativai-0.1.0/creativai/resources/chat.py +44 -0
  10. creativai-0.1.0/creativai/resources/collections.py +58 -0
  11. creativai-0.1.0/creativai/resources/data_plates.py +174 -0
  12. creativai-0.1.0/creativai/resources/health.py +20 -0
  13. creativai-0.1.0/creativai/resources/indexing.py +77 -0
  14. creativai-0.1.0/creativai/resources/invoices.py +26 -0
  15. creativai-0.1.0/creativai/resources/jobs.py +36 -0
  16. creativai-0.1.0/creativai/resources/knowledge_extraction.py +88 -0
  17. creativai-0.1.0/creativai/resources/live_stream.py +143 -0
  18. creativai-0.1.0/creativai/resources/media.py +65 -0
  19. creativai-0.1.0/creativai/resources/online_search.py +38 -0
  20. creativai-0.1.0/creativai/resources/organizations.py +28 -0
  21. creativai-0.1.0/creativai/resources/projects.py +31 -0
  22. creativai-0.1.0/creativai/resources/search.py +60 -0
  23. creativai-0.1.0/creativai/resources/sharing.py +161 -0
  24. creativai-0.1.0/creativai/resources/sub_plates.py +83 -0
  25. creativai-0.1.0/creativai/resources/subscriptions.py +54 -0
  26. creativai-0.1.0/creativai/resources/tasks.py +62 -0
  27. creativai-0.1.0/creativai/resources/transactions.py +50 -0
  28. creativai-0.1.0/creativai/resources/transfers.py +33 -0
  29. creativai-0.1.0/creativai/resources/upload_integrations.py +146 -0
  30. creativai-0.1.0/creativai/resources/uploads.py +45 -0
  31. creativai-0.1.0/creativai/resources/users.py +50 -0
  32. creativai-0.1.0/creativai/resources/youtube_search.py +59 -0
  33. creativai-0.1.0/creativai.egg-info/PKG-INFO +473 -0
  34. creativai-0.1.0/creativai.egg-info/SOURCES.txt +37 -0
  35. creativai-0.1.0/creativai.egg-info/dependency_links.txt +1 -0
  36. creativai-0.1.0/creativai.egg-info/requires.txt +10 -0
  37. creativai-0.1.0/creativai.egg-info/top_level.txt +1 -0
  38. creativai-0.1.0/pyproject.toml +58 -0
  39. creativai-0.1.0/setup.cfg +4 -0
@@ -0,0 +1,473 @@
1
+ Metadata-Version: 2.4
2
+ Name: creativai
3
+ Version: 0.1.0
4
+ Summary: Official Python SDK for CreativAI — Video Intelligence Platform
5
+ Author-email: CreativAI <support@creativ-ai.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://creativ-ai.com
8
+ Project-URL: Documentation, https://github.com/creativ-ai/creativai-python
9
+ Project-URL: Repository, https://github.com/creativ-ai/creativai-python
10
+ Project-URL: Bug Tracker, https://github.com/creativ-ai/creativai-python/issues
11
+ Keywords: video,ai,search,intelligence,creativ-ai,sdk
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.9
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
21
+ Classifier: Topic :: Multimedia :: Video
22
+ Requires-Python: >=3.9
23
+ Description-Content-Type: text/markdown
24
+ Requires-Dist: httpx>=0.27.0
25
+ Requires-Dist: httpx-sse>=0.4.0
26
+ Provides-Extra: dev
27
+ Requires-Dist: pytest>=8.0; extra == "dev"
28
+ Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
29
+ Requires-Dist: pytest-httpx>=0.30; extra == "dev"
30
+ Requires-Dist: black>=24.0; extra == "dev"
31
+ Requires-Dist: ruff>=0.4; extra == "dev"
32
+ Requires-Dist: mypy>=1.10; extra == "dev"
33
+
34
+ # CreativAI Python SDK
35
+
36
+ Official Python SDK for the [CreativAI](https://creativ-ai.com) Video Intelligence Platform.
37
+
38
+ > Upload, index, search, and extract structured knowledge from video libraries at scale — all from Python.
39
+
40
+ ---
41
+
42
+ ## Installation
43
+
44
+ ```bash
45
+ pip install creativai
46
+ ```
47
+
48
+ For SSE streaming support (agentic chat, live stream events), `httpx-sse` is installed automatically as a dependency.
49
+
50
+ **Requires Python 3.9+**
51
+
52
+ ---
53
+
54
+ ## Authentication
55
+
56
+ Get your API key from the CreativAI app (profile avatar → **API Key**). Keys begin with `sk_live_`.
57
+
58
+ ```python
59
+ import creativai
60
+
61
+ # Option 1 — pass directly
62
+ client = creativai.CreativAI(api_key="sk_live_...")
63
+
64
+ # Option 2 — environment variable (recommended for production)
65
+ # export CREATIVAI_API_KEY="sk_live_..."
66
+ client = creativai.CreativAI()
67
+ ```
68
+
69
+ ---
70
+
71
+ ## MCP Quick Start — Use CreativAI inside Claude, Cursor, and Copilot
72
+
73
+ CreativAI supports the [Model Context Protocol (MCP)](https://modelcontextprotocol.io), letting any compatible AI
74
+ assistant call CreativAI tools directly in conversation.
75
+
76
+ ### Option A — npx (no Python install needed, recommended for most users)
77
+
78
+ Add to your Claude Desktop / Cursor config:
79
+
80
+ ```json
81
+ {
82
+ "mcpServers": {
83
+ "creativai": {
84
+ "command": "npx",
85
+ "args": ["-y", "creativai-mcp"],
86
+ "env": { "CREATIVAI_API_KEY": "sk_live_..." }
87
+ }
88
+ }
89
+ }
90
+ ```
91
+
92
+ ### Option B — pip
93
+
94
+ ```bash
95
+ pip install creativai-mcp
96
+ CREATIVAI_API_KEY="sk_live_..." creativai-mcp # stdio (Claude Desktop)
97
+ creativai-mcp --transport sse --port 8090 # HTTP/SSE server
98
+ ```
99
+
100
+ ### Option C — from the SDK
101
+
102
+ ```python
103
+ import creativai
104
+
105
+ client = creativai.CreativAI()
106
+ server = client.as_mcp_server() # returns a FastMCP instance
107
+ server.run(transport="stdio") # or transport="sse"
108
+ ```
109
+
110
+ ### HTTP/SSE (hosted, no install)
111
+
112
+ Connect directly to the CreativAI backend — no local binary needed:
113
+
114
+ ```json
115
+ {
116
+ "mcpServers": {
117
+ "creativai": {
118
+ "type": "sse",
119
+ "url": "https://creativai-apis.com/api/v2/mcp/sse",
120
+ "headers": { "X-API-Key": "sk_live_..." }
121
+ }
122
+ }
123
+ }
124
+ ```
125
+
126
+ **Available tools (42 total):** collections, media, indexing, search, agentic chat,
127
+ knowledge extraction, data plates, tasks, live stream, online search, YouTube, organizations/projects, account info.
128
+
129
+ **MCP setup page:** [creativ-ai.com/mcp](https://creativ-ai.com/mcp)
130
+
131
+ ---
132
+
133
+ ## Quick Start
134
+
135
+ ```python
136
+ import time
137
+ import creativai
138
+
139
+ client = creativai.CreativAI()
140
+
141
+ # Verify your key and check credits
142
+ info = client.users.get_users_info()
143
+ print(f"Credits: {info['credits']}")
144
+
145
+ # Create a collection
146
+ collection = client.collections.create("my-dashcam-footage", model="video_only")
147
+ cid = collection["collection_id"]
148
+
149
+ # Upload a local file
150
+ client.media.upload_file(cid, "dashcam_2026.mp4")
151
+
152
+ # Start indexing (async — returns immediately with a job ID)
153
+ job = client.indexing.start(cid)
154
+ indexing_id = job["indexing_id"]
155
+
156
+ # Poll until complete
157
+ while True:
158
+ status = client.indexing.get_status(indexing_id)
159
+ if status["status"] == "completed":
160
+ break
161
+ time.sleep(10)
162
+
163
+ # Semantic search
164
+ results = client.search.query(cid, "pedestrian crossing the road")
165
+ for hit in results["results"][:5]:
166
+ print(f"[{hit['score']:.2f}] {hit['video_name']} @ {hit['start_time']}s")
167
+ ```
168
+
169
+ ---
170
+
171
+ ## Resource Reference
172
+
173
+ All resources are accessed as attributes on the `CreativAI` client instance.
174
+
175
+ ### `client.health`
176
+
177
+ ```python
178
+ client.health.check() # GET /health
179
+ client.health.versioned() # GET /api/v2/health
180
+ ```
181
+
182
+ ### `client.users`
183
+
184
+ ```python
185
+ client.users.me()
186
+ client.users.info()
187
+ client.users.get_users_info()
188
+ client.users.claim_welcome_credits()
189
+ ```
190
+
191
+ ### `client.collections`
192
+
193
+ ```python
194
+ client.collections.create("name", model="video_only") # model: "video_only" | "multimodal"
195
+ client.collections.list()
196
+ client.collections.get(collection_id)
197
+ client.collections.update(collection_id, collection_name="new-name")
198
+ client.collections.delete(collection_id)
199
+ client.collections.restore(collection_id)
200
+ client.collections.list_by_organization(org_id)
201
+ client.collections.list_by_project(org_id, project_name)
202
+ ```
203
+
204
+ ### `client.media`
205
+
206
+ ```python
207
+ client.media.list(collection_id)
208
+ client.media.upload_file(collection_id, "/path/to/video.mp4") # convenience helper
209
+ client.media.get_upload_url(collection_id, "video.mp4") # get presigned URL
210
+ client.media.get_upload_urls(collection_id, ["a.mp4", "b.mp4"])
211
+ client.media.delete(collection_id, ["s3://bucket/key1.mp4"])
212
+ ```
213
+
214
+ ### `client.uploads` — multipart
215
+
216
+ ```python
217
+ upload = client.uploads.initiate(collection_id, "large-video.mp4")
218
+ client.uploads.complete(upload["upload_id"], parts=[{"part_number": 1, "etag": "..."}])
219
+ client.uploads.abort(upload["upload_id"])
220
+ client.uploads.regenerate_urls(upload["upload_id"])
221
+ ```
222
+
223
+ ### `client.transfers` — external S3 / URL
224
+
225
+ ```python
226
+ job = client.transfers.start(collection_id, "s3://my-bucket/video.mp4")
227
+ client.transfers.get_status(job["job_id"])
228
+ client.transfers.validate("https://example.com/video.mp4")
229
+ ```
230
+
231
+ ### `client.indexing`
232
+
233
+ ```python
234
+ job = client.indexing.start(collection_id)
235
+ client.indexing.get_status(job["indexing_id"])
236
+ client.indexing.estimate_cost(collection_id)
237
+ client.indexing.get_preprocessing_status(collection_id)
238
+ client.indexing.list_preprocessed_videos(collection_id)
239
+ ```
240
+
241
+ ### `client.search`
242
+
243
+ ```python
244
+ results = client.search.query(
245
+ collection_id,
246
+ "person wearing PPE",
247
+ search_type="hybrid", # "hybrid" | "vision" | "audio"
248
+ page_number=1,
249
+ page_size=50,
250
+ refine_query=True,
251
+ )
252
+ ```
253
+
254
+ ### `client.data_plates`
255
+
256
+ ```python
257
+ plate_job = client.data_plates.create_from_collection(collection_id, plate_name="All Segments")
258
+ plate_id = poll_until_done(client.data_plates.get_creation_job, plate_job["job_id"])["plate_id"]
259
+
260
+ plate = client.data_plates.get(collection_id, plate_id, page_size=100)
261
+ client.data_plates.update(collection_id, plate_id, plate_name="Renamed")
262
+ client.data_plates.delete(collection_id, plate_id)
263
+
264
+ # Segments
265
+ client.data_plates.add_segments(collection_id, plate_id, segments=[...])
266
+ client.data_plates.remove_segments(collection_id, plate_id, segment_ids=["seg_1"])
267
+ client.data_plates.update_extracted_info(collection_id, plate_id, "seg_1", "ppe_worn", True)
268
+
269
+ # Export
270
+ client.data_plates.generate_csv(collection_id, plate_id)
271
+ csv_bytes = client.data_plates.export_csv(collection_id, plate_id)
272
+ ```
273
+
274
+ ### `client.knowledge_extraction`
275
+
276
+ ```python
277
+ ke_job = client.knowledge_extraction.add_columns(
278
+ collection_id,
279
+ plate_id,
280
+ columns=[
281
+ {"name": "ppe_worn", "question": "Is PPE worn?", "type": "boolean"},
282
+ {"name": "activity", "question": "What is happening?", "type": "text"},
283
+ ],
284
+ )
285
+ client.knowledge_extraction.get_job(ke_job["job_id"])
286
+
287
+ # AI chat query over the plate data
288
+ answer = client.knowledge_extraction.chat_query(collection_id, plate_id, "How many PPE violations?")
289
+ print(answer["answer"])
290
+
291
+ # Charts
292
+ charts = client.knowledge_extraction.get_plate_charts(collection_id, plate_id)
293
+ ```
294
+
295
+ ### `client.agentic_chat` — SSE streaming
296
+
297
+ ```python
298
+ session = client.agentic_chat.create_session(collection_id, title="My analysis")
299
+ sid = session["session_id"]
300
+
301
+ for event in client.agentic_chat.chat(sid, "Find all forklift incidents and summarize them"):
302
+ match event["event"]:
303
+ case "thinking":
304
+ print(f" [thinking] {event['data'].get('text', '')[:80]}")
305
+ case "search":
306
+ print(f" [search] {event['data']}")
307
+ case "answer":
308
+ print(f"\n{event['data'].get('text', '')}")
309
+ case "done":
310
+ break
311
+
312
+ # Session management
313
+ client.agentic_chat.list_sessions(collection_id=collection_id)
314
+ client.agentic_chat.get_messages(sid)
315
+ client.agentic_chat.stop(sid)
316
+ client.agentic_chat.delete_session(sid)
317
+ ```
318
+
319
+ ### `client.live_stream`
320
+
321
+ ```python
322
+ # RTMP push — point OBS or ffmpeg at publish_url
323
+ session = client.live_stream.stream_rtmp(
324
+ collection_id=collection_id,
325
+ name="Entrance Camera",
326
+ model="video_only",
327
+ )
328
+ print(session["publish_url"])
329
+
330
+ # RTSP pull — IP camera
331
+ session = client.live_stream.stream_rtsp("rtsp://192.168.1.100/stream", collection_id=collection_id)
332
+
333
+ # WebRTC — browser webcam
334
+ session = client.live_stream.stream_webrtc(collection_id=collection_id)
335
+ print(session["whip_url"], session["whep_url"])
336
+
337
+ # Add questions and poll
338
+ client.live_stream.add_questions(sid, ["Is anyone present?", "Is the door open?"])
339
+ client.live_stream.stop_session(sid)
340
+ ```
341
+
342
+ ### `client.upload_integrations`
343
+
344
+ ```python
345
+ # Google Drive
346
+ files = client.upload_integrations.google_drive_list_files(google_access_token)
347
+ client.upload_integrations.google_drive_transfer(
348
+ collection_id, google_access_token,
349
+ file_ids=["drive_file_id"], file_names=["video.mp4"]
350
+ )
351
+
352
+ # Dropbox
353
+ files = client.upload_integrations.dropbox_list_files(dropbox_access_token)
354
+ client.upload_integrations.dropbox_transfer(
355
+ collection_id, dropbox_access_token,
356
+ file_paths=["/Videos/clip.mp4"], file_names=["clip.mp4"]
357
+ )
358
+
359
+ # Hugging Face
360
+ files = client.upload_integrations.huggingface_list_files(hf_token, "username/my-dataset")
361
+ client.upload_integrations.huggingface_transfer(
362
+ collection_id, hf_token, "username/my-dataset",
363
+ file_paths=["videos/clip.mp4"]
364
+ )
365
+ ```
366
+
367
+ ### `client.organizations` / `client.projects`
368
+
369
+ ```python
370
+ org = client.organizations.create("Acme Corp")
371
+ client.projects.create(org["org_id"], "production-analysis")
372
+ client.projects.list(org["org_id"])
373
+ ```
374
+
375
+ ### `client.sharing`
376
+
377
+ ```python
378
+ client.sharing.invite(collection_id, "alice@example.com", role="viewer")
379
+ client.sharing.list_members(collection_id)
380
+ client.sharing.update_member(collection_id, user_id, role="editor")
381
+ client.sharing.remove_member(collection_id, user_id)
382
+ client.sharing.create_group(collection_id, "annotators")
383
+ ```
384
+
385
+ ### `client.tasks`
386
+
387
+ ```python
388
+ task = client.tasks.create(collection_id, title="Review batch 1", assigned_to=[user_id])
389
+ client.tasks.update_status(task["task_id"], "in_progress")
390
+ client.tasks.update_progress(task["task_id"], 50)
391
+ client.tasks.add_comment(task["task_id"], "Segment 12 flagged for review")
392
+ client.tasks.my_tasks()
393
+ ```
394
+
395
+ ### `client.transactions` / `client.subscriptions` / `client.invoices`
396
+
397
+ ```python
398
+ client.transactions.summary()
399
+ client.transactions.breakdown_by_collections()
400
+ client.transactions.export() # CSV bytes
401
+
402
+ client.subscriptions.current()
403
+ client.subscriptions.list_plans()
404
+
405
+ client.invoices.list()
406
+ pdf = client.invoices.download("inv_123")
407
+ ```
408
+
409
+ ### `client.jobs` — cancel any async job
410
+
411
+ ```python
412
+ client.jobs.cancel("indexing-chunk", "idx_abc123")
413
+ client.jobs.cancel("knowledge-extraction", "ke_job_xyz")
414
+ ```
415
+
416
+ ---
417
+
418
+ ## Error Handling
419
+
420
+ ```python
421
+ import creativai
422
+
423
+ client = creativai.CreativAI()
424
+
425
+ try:
426
+ results = client.search.query("col_invalid", "query")
427
+ except creativai.NotFoundError as e:
428
+ print(f"Not found: {e.message}")
429
+ except creativai.InsufficientCreditsError:
430
+ print("Top up your credits at https://creativ-ai.com/pricing")
431
+ except creativai.AuthenticationError:
432
+ print("Check your CREATIVAI_API_KEY")
433
+ except creativai.APIError as e:
434
+ print(f"API error {e.status_code}: {e.message} (code={e.code})")
435
+ ```
436
+
437
+ | Exception | HTTP status |
438
+ |-----------|-------------|
439
+ | `AuthenticationError` | 401 |
440
+ | `InsufficientCreditsError` | 402 |
441
+ | `PermissionError` | 403 |
442
+ | `NotFoundError` | 404 |
443
+ | `ValidationError` | 400 / 422 |
444
+ | `RateLimitError` | 429 |
445
+ | `ServerError` | 5xx |
446
+ | `StreamingError` | SSE connection failure |
447
+ | `TimeoutError` | Request timeout |
448
+
449
+ ---
450
+
451
+ ## Context Manager
452
+
453
+ ```python
454
+ with creativai.CreativAI() as client:
455
+ collections = client.collections.list()
456
+ # HTTP connection pool closed automatically
457
+ ```
458
+
459
+ ---
460
+
461
+ ## Examples
462
+
463
+ | File | Description |
464
+ |------|-------------|
465
+ | [examples/quickstart.py](examples/quickstart.py) | Upload, index, search, and agentic chat |
466
+ | [examples/knowledge_extraction.py](examples/knowledge_extraction.py) | Structured data extraction → CSV |
467
+ | [examples/live_stream.py](examples/live_stream.py) | RTMP live stream session |
468
+
469
+ ---
470
+
471
+ ## License
472
+
473
+ MIT