hypercli-sdk 0.4.2__py3-none-any.whl
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.
- c3/__init__.py +57 -0
- c3/billing.py +72 -0
- c3/client.py +60 -0
- c3/config.py +70 -0
- c3/files.py +386 -0
- c3/http.py +217 -0
- c3/instances.py +211 -0
- c3/job/__init__.py +24 -0
- c3/job/base.py +249 -0
- c3/job/comfyui.py +1469 -0
- c3/jobs.py +285 -0
- c3/logs.py +273 -0
- c3/renders.py +339 -0
- c3/user.py +37 -0
- hypercli_sdk-0.4.2.dist-info/METADATA +141 -0
- hypercli_sdk-0.4.2.dist-info/RECORD +17 -0
- hypercli_sdk-0.4.2.dist-info/WHEEL +4 -0
c3/renders.py
ADDED
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
"""Renders API"""
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
from typing import TYPE_CHECKING, List, Optional
|
|
4
|
+
|
|
5
|
+
if TYPE_CHECKING:
|
|
6
|
+
from .http import HTTPClient
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@dataclass
|
|
10
|
+
class Render:
|
|
11
|
+
render_id: str
|
|
12
|
+
state: str
|
|
13
|
+
template: str | None = None
|
|
14
|
+
render_type: str | None = None
|
|
15
|
+
result_url: str | None = None
|
|
16
|
+
error: str | None = None
|
|
17
|
+
created_at: float | None = None
|
|
18
|
+
started_at: float | None = None
|
|
19
|
+
completed_at: float | None = None
|
|
20
|
+
|
|
21
|
+
@classmethod
|
|
22
|
+
def from_dict(cls, data: dict) -> "Render":
|
|
23
|
+
return cls(
|
|
24
|
+
render_id=data.get("id") or data.get("render_id", ""),
|
|
25
|
+
state=data.get("state", ""),
|
|
26
|
+
template=data.get("template") or data.get("meta", {}).get("template"),
|
|
27
|
+
render_type=data.get("type") or data.get("render_type"),
|
|
28
|
+
result_url=data.get("result_url"),
|
|
29
|
+
error=data.get("error"),
|
|
30
|
+
created_at=data.get("created_at"),
|
|
31
|
+
started_at=data.get("started_at"),
|
|
32
|
+
completed_at=data.get("completed_at"),
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@dataclass
|
|
37
|
+
class RenderStatus:
|
|
38
|
+
render_id: str
|
|
39
|
+
state: str
|
|
40
|
+
progress: float | None = None
|
|
41
|
+
|
|
42
|
+
@classmethod
|
|
43
|
+
def from_dict(cls, data: dict) -> "RenderStatus":
|
|
44
|
+
return cls(
|
|
45
|
+
render_id=data.get("id") or data.get("render_id", ""),
|
|
46
|
+
state=data.get("state", ""),
|
|
47
|
+
progress=data.get("progress"),
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class Renders:
|
|
52
|
+
"""Renders API wrapper"""
|
|
53
|
+
|
|
54
|
+
def __init__(self, http: "HTTPClient"):
|
|
55
|
+
self._http = http
|
|
56
|
+
|
|
57
|
+
def list(
|
|
58
|
+
self,
|
|
59
|
+
state: str = None,
|
|
60
|
+
template: str = None,
|
|
61
|
+
type: str = None,
|
|
62
|
+
) -> list[Render]:
|
|
63
|
+
"""List all renders.
|
|
64
|
+
|
|
65
|
+
Args:
|
|
66
|
+
state: Filter by state (e.g., "pending", "running", "completed")
|
|
67
|
+
template: Filter by template name
|
|
68
|
+
type: Filter by render type (e.g., "comfyui")
|
|
69
|
+
"""
|
|
70
|
+
params = {}
|
|
71
|
+
if state:
|
|
72
|
+
params["state"] = state
|
|
73
|
+
if template:
|
|
74
|
+
params["template"] = template
|
|
75
|
+
if type:
|
|
76
|
+
params["type"] = type
|
|
77
|
+
|
|
78
|
+
data = self._http.get("/api/renders", params=params or None)
|
|
79
|
+
# Handle paginated response
|
|
80
|
+
items = data.get("items", data) if isinstance(data, dict) else data
|
|
81
|
+
return [Render.from_dict(r) for r in items]
|
|
82
|
+
|
|
83
|
+
def get(self, render_id: str) -> Render:
|
|
84
|
+
"""Get render details"""
|
|
85
|
+
data = self._http.get(f"/api/renders/{render_id}")
|
|
86
|
+
return Render.from_dict(data)
|
|
87
|
+
|
|
88
|
+
def create(
|
|
89
|
+
self,
|
|
90
|
+
params: dict,
|
|
91
|
+
render_type: str = "comfyui",
|
|
92
|
+
notify_url: str = None,
|
|
93
|
+
) -> Render:
|
|
94
|
+
"""Create a new render.
|
|
95
|
+
|
|
96
|
+
Args:
|
|
97
|
+
params: Render parameters (workflow-specific)
|
|
98
|
+
render_type: Type of render (default: "comfyui")
|
|
99
|
+
notify_url: Optional webhook URL for completion notification
|
|
100
|
+
"""
|
|
101
|
+
payload = {
|
|
102
|
+
"type": render_type,
|
|
103
|
+
"params": params,
|
|
104
|
+
}
|
|
105
|
+
if notify_url:
|
|
106
|
+
payload["notify_url"] = notify_url
|
|
107
|
+
|
|
108
|
+
data = self._http.post("/api/renders", json=payload)
|
|
109
|
+
return Render.from_dict(data)
|
|
110
|
+
|
|
111
|
+
def cancel(self, render_id: str) -> dict:
|
|
112
|
+
"""Cancel a render"""
|
|
113
|
+
return self._http.delete(f"/api/renders/{render_id}")
|
|
114
|
+
|
|
115
|
+
def status(self, render_id: str) -> RenderStatus:
|
|
116
|
+
"""Get render status (lightweight polling endpoint)"""
|
|
117
|
+
data = self._http.get(f"/api/renders/{render_id}/status")
|
|
118
|
+
return RenderStatus.from_dict(data)
|
|
119
|
+
|
|
120
|
+
# =========================================================================
|
|
121
|
+
# Flow endpoints - simplified interfaces
|
|
122
|
+
# =========================================================================
|
|
123
|
+
|
|
124
|
+
def _flow(self, endpoint: str, **kwargs) -> Render:
|
|
125
|
+
"""Helper for flow endpoints. Filters None values from payload."""
|
|
126
|
+
payload = {k: v for k, v in kwargs.items() if v is not None}
|
|
127
|
+
data = self._http.post(endpoint, json=payload)
|
|
128
|
+
return Render.from_dict(data)
|
|
129
|
+
|
|
130
|
+
def text_to_image(
|
|
131
|
+
self,
|
|
132
|
+
prompt: str,
|
|
133
|
+
negative: str = None,
|
|
134
|
+
width: int = None,
|
|
135
|
+
height: int = None,
|
|
136
|
+
notify_url: str = None,
|
|
137
|
+
) -> Render:
|
|
138
|
+
"""Generate an image using Qwen-Image (great for text in images).
|
|
139
|
+
|
|
140
|
+
Args:
|
|
141
|
+
prompt: Text description of the image
|
|
142
|
+
negative: Optional negative prompt (things to avoid)
|
|
143
|
+
width: Optional output width
|
|
144
|
+
height: Optional output height
|
|
145
|
+
notify_url: Optional webhook URL for completion notification
|
|
146
|
+
|
|
147
|
+
Example:
|
|
148
|
+
render = c3.renders.text_to_image("a cat wearing sunglasses")
|
|
149
|
+
"""
|
|
150
|
+
return self._flow("/api/flow/text-to-image", prompt=prompt, negative=negative, width=width, height=height, notify_url=notify_url)
|
|
151
|
+
|
|
152
|
+
def text_to_image_hidream(
|
|
153
|
+
self,
|
|
154
|
+
prompt: str,
|
|
155
|
+
negative: str = None,
|
|
156
|
+
width: int = None,
|
|
157
|
+
height: int = None,
|
|
158
|
+
notify_url: str = None,
|
|
159
|
+
) -> Render:
|
|
160
|
+
"""Generate an image using HiDream I1 Full (highest quality).
|
|
161
|
+
|
|
162
|
+
Args:
|
|
163
|
+
prompt: Text description of the image
|
|
164
|
+
negative: Optional negative prompt (things to avoid)
|
|
165
|
+
width: Optional output width
|
|
166
|
+
height: Optional output height
|
|
167
|
+
notify_url: Optional webhook URL for completion notification
|
|
168
|
+
|
|
169
|
+
Example:
|
|
170
|
+
render = c3.renders.text_to_image_hidream("a mystical forest")
|
|
171
|
+
"""
|
|
172
|
+
return self._flow("/api/flow/text-to-image-hidream", prompt=prompt, negative=negative, width=width, height=height, notify_url=notify_url)
|
|
173
|
+
|
|
174
|
+
def text_to_video(
|
|
175
|
+
self,
|
|
176
|
+
prompt: str,
|
|
177
|
+
negative: str = None,
|
|
178
|
+
width: int = None,
|
|
179
|
+
height: int = None,
|
|
180
|
+
notify_url: str = None,
|
|
181
|
+
) -> Render:
|
|
182
|
+
"""Generate a video using Wan 2.2 14B.
|
|
183
|
+
|
|
184
|
+
Args:
|
|
185
|
+
prompt: Text description of the video
|
|
186
|
+
negative: Optional negative prompt (things to avoid)
|
|
187
|
+
width: Optional video width
|
|
188
|
+
height: Optional video height
|
|
189
|
+
notify_url: Optional webhook URL for completion notification
|
|
190
|
+
|
|
191
|
+
Example:
|
|
192
|
+
render = c3.renders.text_to_video("a cat walking through a garden")
|
|
193
|
+
"""
|
|
194
|
+
return self._flow("/api/flow/text-to-video", prompt=prompt, negative=negative, width=width, height=height, notify_url=notify_url)
|
|
195
|
+
|
|
196
|
+
def image_to_video(
|
|
197
|
+
self,
|
|
198
|
+
prompt: str,
|
|
199
|
+
image_url: str,
|
|
200
|
+
negative: str = None,
|
|
201
|
+
width: int = None,
|
|
202
|
+
height: int = None,
|
|
203
|
+
notify_url: str = None,
|
|
204
|
+
) -> Render:
|
|
205
|
+
"""Animate an image using Wan 2.2 Animate.
|
|
206
|
+
|
|
207
|
+
Args:
|
|
208
|
+
prompt: Description of the motion/animation
|
|
209
|
+
image_url: URL of the image to animate
|
|
210
|
+
negative: Optional negative prompt (things to avoid)
|
|
211
|
+
width: Optional video width
|
|
212
|
+
height: Optional video height
|
|
213
|
+
notify_url: Optional webhook URL for completion notification
|
|
214
|
+
|
|
215
|
+
Example:
|
|
216
|
+
render = c3.renders.image_to_video("dancing", "https://example.com/img.png", width=832, height=480)
|
|
217
|
+
"""
|
|
218
|
+
return self._flow("/api/flow/image-to-video", prompt=prompt, image_url=image_url, negative=negative, width=width, height=height, notify_url=notify_url)
|
|
219
|
+
|
|
220
|
+
def speaking_video(
|
|
221
|
+
self,
|
|
222
|
+
prompt: str,
|
|
223
|
+
image_url: str,
|
|
224
|
+
audio_url: str,
|
|
225
|
+
negative: str = None,
|
|
226
|
+
width: int = None,
|
|
227
|
+
height: int = None,
|
|
228
|
+
notify_url: str = None,
|
|
229
|
+
) -> Render:
|
|
230
|
+
"""Generate a lip-sync video using HuMo.
|
|
231
|
+
|
|
232
|
+
Args:
|
|
233
|
+
prompt: Description of the scene/character
|
|
234
|
+
image_url: URL of the face/character image
|
|
235
|
+
audio_url: URL of the audio/speech file
|
|
236
|
+
negative: Optional negative prompt (things to avoid)
|
|
237
|
+
width: Optional video width
|
|
238
|
+
height: Optional video height
|
|
239
|
+
notify_url: Optional webhook URL for completion notification
|
|
240
|
+
|
|
241
|
+
Example:
|
|
242
|
+
render = c3.renders.speaking_video(
|
|
243
|
+
"A person talking to camera",
|
|
244
|
+
"https://example.com/face.png",
|
|
245
|
+
"https://example.com/speech.mp3"
|
|
246
|
+
)
|
|
247
|
+
"""
|
|
248
|
+
return self._flow("/api/flow/speaking-video", prompt=prompt, image_url=image_url, audio_url=audio_url, negative=negative, width=width, height=height, notify_url=notify_url)
|
|
249
|
+
|
|
250
|
+
def speaking_video_wan(
|
|
251
|
+
self,
|
|
252
|
+
prompt: str,
|
|
253
|
+
image_url: str,
|
|
254
|
+
audio_url: str,
|
|
255
|
+
negative: str = None,
|
|
256
|
+
width: int = None,
|
|
257
|
+
height: int = None,
|
|
258
|
+
notify_url: str = None,
|
|
259
|
+
) -> Render:
|
|
260
|
+
"""Generate an audio-driven video using Wan 2.2 S2V.
|
|
261
|
+
|
|
262
|
+
Args:
|
|
263
|
+
prompt: Description of the scene/action
|
|
264
|
+
image_url: URL of the image
|
|
265
|
+
audio_url: URL of the audio file
|
|
266
|
+
negative: Optional negative prompt (things to avoid)
|
|
267
|
+
width: Optional video width
|
|
268
|
+
height: Optional video height
|
|
269
|
+
notify_url: Optional webhook URL for completion notification
|
|
270
|
+
|
|
271
|
+
Example:
|
|
272
|
+
render = c3.renders.speaking_video_wan(
|
|
273
|
+
"The person is singing",
|
|
274
|
+
"https://example.com/face.png",
|
|
275
|
+
"https://example.com/song.mp3"
|
|
276
|
+
)
|
|
277
|
+
"""
|
|
278
|
+
return self._flow("/api/flow/speaking-video-wan", prompt=prompt, image_url=image_url, audio_url=audio_url, negative=negative, width=width, height=height, notify_url=notify_url)
|
|
279
|
+
|
|
280
|
+
def image_to_image(
|
|
281
|
+
self,
|
|
282
|
+
prompt: str,
|
|
283
|
+
image_urls: List[str],
|
|
284
|
+
negative: str = None,
|
|
285
|
+
width: int = None,
|
|
286
|
+
height: int = None,
|
|
287
|
+
notify_url: str = None,
|
|
288
|
+
) -> Render:
|
|
289
|
+
"""Transform images using Qwen Image Edit with 1-3 input images.
|
|
290
|
+
|
|
291
|
+
Args:
|
|
292
|
+
prompt: Description of the transformation
|
|
293
|
+
image_urls: List of 1-3 image URLs (first is main, others are references)
|
|
294
|
+
negative: Optional negative prompt (things to avoid)
|
|
295
|
+
width: Optional output width
|
|
296
|
+
height: Optional output height
|
|
297
|
+
notify_url: Optional webhook URL for completion notification
|
|
298
|
+
|
|
299
|
+
Example:
|
|
300
|
+
render = c3.renders.image_to_image(
|
|
301
|
+
"Apply the artistic style from the references",
|
|
302
|
+
[
|
|
303
|
+
"https://example.com/subject.jpg",
|
|
304
|
+
"https://example.com/style1.jpg",
|
|
305
|
+
"https://example.com/style2.jpg",
|
|
306
|
+
]
|
|
307
|
+
)
|
|
308
|
+
"""
|
|
309
|
+
return self._flow("/api/flow/image-to-image", prompt=prompt, image_urls=image_urls, negative=negative, width=width, height=height, notify_url=notify_url)
|
|
310
|
+
|
|
311
|
+
def first_last_frame_video(
|
|
312
|
+
self,
|
|
313
|
+
prompt: str,
|
|
314
|
+
start_image_url: str,
|
|
315
|
+
end_image_url: str,
|
|
316
|
+
negative: str = None,
|
|
317
|
+
width: int = None,
|
|
318
|
+
height: int = None,
|
|
319
|
+
notify_url: str = None,
|
|
320
|
+
) -> Render:
|
|
321
|
+
"""Generate video morphing between two images using Wan 2.2.
|
|
322
|
+
|
|
323
|
+
Args:
|
|
324
|
+
prompt: Description of the transition/motion
|
|
325
|
+
start_image_url: URL of the starting frame
|
|
326
|
+
end_image_url: URL of the ending frame
|
|
327
|
+
negative: Optional negative prompt (things to avoid)
|
|
328
|
+
width: Optional video width
|
|
329
|
+
height: Optional video height
|
|
330
|
+
notify_url: Optional webhook URL for completion notification
|
|
331
|
+
|
|
332
|
+
Example:
|
|
333
|
+
render = c3.renders.first_last_frame_video(
|
|
334
|
+
"smooth transition from day to night",
|
|
335
|
+
"https://example.com/day.png",
|
|
336
|
+
"https://example.com/night.png"
|
|
337
|
+
)
|
|
338
|
+
"""
|
|
339
|
+
return self._flow("/api/flow/first-last-frame-video", prompt=prompt, start_image_url=start_image_url, end_image_url=end_image_url, negative=negative, width=width, height=height, notify_url=notify_url)
|
c3/user.py
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"""User API"""
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
if TYPE_CHECKING:
|
|
6
|
+
from .http import HTTPClient
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@dataclass
|
|
10
|
+
class User:
|
|
11
|
+
user_id: str
|
|
12
|
+
email: str | None
|
|
13
|
+
name: str | None
|
|
14
|
+
is_active: bool
|
|
15
|
+
created_at: str
|
|
16
|
+
|
|
17
|
+
@classmethod
|
|
18
|
+
def from_dict(cls, data: dict) -> "User":
|
|
19
|
+
return cls(
|
|
20
|
+
user_id=data.get("user_id", ""),
|
|
21
|
+
email=data.get("email"),
|
|
22
|
+
name=data.get("name"),
|
|
23
|
+
is_active=data.get("is_active", True),
|
|
24
|
+
created_at=data.get("created_at", ""),
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class UserAPI:
|
|
29
|
+
"""User API wrapper"""
|
|
30
|
+
|
|
31
|
+
def __init__(self, http: "HTTPClient"):
|
|
32
|
+
self._http = http
|
|
33
|
+
|
|
34
|
+
def get(self) -> User:
|
|
35
|
+
"""Get current user info"""
|
|
36
|
+
data = self._http.get("/api/user")
|
|
37
|
+
return User.from_dict(data)
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: hypercli-sdk
|
|
3
|
+
Version: 0.4.2
|
|
4
|
+
Summary: Python SDK for HyperCLI - GPU orchestration and LLM API
|
|
5
|
+
Project-URL: Homepage, https://hypercli.com
|
|
6
|
+
Project-URL: Documentation, https://docs.hypercli.com
|
|
7
|
+
Project-URL: Repository, https://github.com/hypercli/sdk-python
|
|
8
|
+
Author-email: HyperCLI <support@hypercli.com>
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Requires-Python: >=3.10
|
|
17
|
+
Requires-Dist: httpx>=0.28.1
|
|
18
|
+
Requires-Dist: websockets>=15.0.1
|
|
19
|
+
Provides-Extra: comfyui
|
|
20
|
+
Requires-Dist: comfyui-workflow-templates-media-image>=0.3.0; extra == 'comfyui'
|
|
21
|
+
Requires-Dist: comfyui-workflow-templates>=0.7.0; extra == 'comfyui'
|
|
22
|
+
Provides-Extra: dev
|
|
23
|
+
Requires-Dist: pytest-asyncio>=0.23.0; extra == 'dev'
|
|
24
|
+
Requires-Dist: pytest>=8.0.0; extra == 'dev'
|
|
25
|
+
Requires-Dist: ruff>=0.3.0; extra == 'dev'
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
|
|
28
|
+
# C3 SDK
|
|
29
|
+
|
|
30
|
+
Python SDK for [HyperCLI](https://hypercli.com) - GPU orchestration API.
|
|
31
|
+
|
|
32
|
+
## Installation
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
pip install c3-sdk
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Setup
|
|
39
|
+
|
|
40
|
+
Set your API key:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
export C3_API_KEY=your_api_key
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Or create `~/.c3/config`:
|
|
47
|
+
```
|
|
48
|
+
C3_API_KEY=your_api_key
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Or pass directly:
|
|
52
|
+
```python
|
|
53
|
+
c3 = C3(api_key="your_api_key")
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Usage
|
|
57
|
+
|
|
58
|
+
```python
|
|
59
|
+
from c3 import C3
|
|
60
|
+
|
|
61
|
+
c3 = C3()
|
|
62
|
+
|
|
63
|
+
# Check balance
|
|
64
|
+
balance = c3.billing.balance()
|
|
65
|
+
print(f"Balance: ${balance.total:.2f}")
|
|
66
|
+
print(f"Rewards: ${balance.rewards:.2f}")
|
|
67
|
+
|
|
68
|
+
# List transactions
|
|
69
|
+
for tx in c3.billing.transactions(limit=10):
|
|
70
|
+
print(f"{tx.transaction_type}: ${tx.amount_usd:.4f}")
|
|
71
|
+
|
|
72
|
+
# Create a job
|
|
73
|
+
job = c3.jobs.create(
|
|
74
|
+
image="nvidia/cuda:12.0",
|
|
75
|
+
command="python train.py",
|
|
76
|
+
gpu_type="l40s",
|
|
77
|
+
gpu_count=1,
|
|
78
|
+
)
|
|
79
|
+
print(f"Job ID: {job.job_id}")
|
|
80
|
+
print(f"State: {job.state}")
|
|
81
|
+
|
|
82
|
+
# List jobs
|
|
83
|
+
for job in c3.jobs.list():
|
|
84
|
+
print(f"{job.job_id}: {job.state}")
|
|
85
|
+
|
|
86
|
+
# Get job details
|
|
87
|
+
job = c3.jobs.get("job_id")
|
|
88
|
+
|
|
89
|
+
# Get job logs
|
|
90
|
+
logs = c3.jobs.logs("job_id")
|
|
91
|
+
|
|
92
|
+
# Get GPU metrics
|
|
93
|
+
metrics = c3.jobs.metrics("job_id")
|
|
94
|
+
for gpu in metrics.gpus:
|
|
95
|
+
print(f"GPU {gpu.index}: {gpu.utilization}% util, {gpu.temperature}°C")
|
|
96
|
+
|
|
97
|
+
# Cancel a job
|
|
98
|
+
c3.jobs.cancel("job_id")
|
|
99
|
+
|
|
100
|
+
# Extend runtime
|
|
101
|
+
c3.jobs.extend("job_id", runtime=7200)
|
|
102
|
+
|
|
103
|
+
# Get user info
|
|
104
|
+
user = c3.user.get()
|
|
105
|
+
print(f"User: {user.email}")
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## LLM API
|
|
109
|
+
|
|
110
|
+
For LLM access, use the OpenAI SDK with C3's base URL:
|
|
111
|
+
|
|
112
|
+
```python
|
|
113
|
+
from openai import OpenAI
|
|
114
|
+
|
|
115
|
+
client = OpenAI(
|
|
116
|
+
api_key="your_c3_api_key",
|
|
117
|
+
base_url="https://api.hypercli.com/v1"
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
response = client.chat.completions.create(
|
|
121
|
+
model="deepseek-v3.1",
|
|
122
|
+
messages=[{"role": "user", "content": "Hello!"}]
|
|
123
|
+
)
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## Error Handling
|
|
127
|
+
|
|
128
|
+
```python
|
|
129
|
+
from c3 import C3, APIError
|
|
130
|
+
|
|
131
|
+
c3 = C3()
|
|
132
|
+
|
|
133
|
+
try:
|
|
134
|
+
job = c3.jobs.get("invalid_id")
|
|
135
|
+
except APIError as e:
|
|
136
|
+
print(f"Error {e.status_code}: {e.detail}")
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## License
|
|
140
|
+
|
|
141
|
+
MIT
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
c3/__init__.py,sha256=d3rSgVM3gYEtqlz11gkJY-gNQ3IDd_MO609TxDlOWFk,1431
|
|
2
|
+
c3/billing.py,sha256=zktogvY4XJhJKuQwq0OQcOM_R36rDRJ-jkDwQdkz9qI,2014
|
|
3
|
+
c3/client.py,sha256=hB2JiXNIZu24s5OsPGOrVgbLWt2sNh2VP-bvJxmoVJo,1578
|
|
4
|
+
c3/config.py,sha256=hh3u6-Iewt4nY2gKREOSwRAWl24rmdEYoZvs-Jv_sJs,1998
|
|
5
|
+
c3/files.py,sha256=ipkzs9L1FlgNY_HLdZEGovpfI9Gh4C6yRX4wvE3rbiM,12504
|
|
6
|
+
c3/http.py,sha256=uzxaEI_q1OPv75g56WNCCtPOcmuRsbsrbvvFJrUnyik,7215
|
|
7
|
+
c3/instances.py,sha256=d_zw_JbxL0XPf2kroVtjCK4fjvBx_sBIRMqKP-_kdeQ,7112
|
|
8
|
+
c3/jobs.py,sha256=o1I9cS3QRZiGGw9q-rZ_RwcfTNZxCmRbLdxpb4PxeK8,8307
|
|
9
|
+
c3/logs.py,sha256=tBRIk3ymWcKjEP7EsYVJFZlNRBlZfvEo5JR8mlEVbi4,8956
|
|
10
|
+
c3/renders.py,sha256=rJVS2rP19V1XLX-MBHsM2y_g_fdXnCBErO_oBsZzSTI,11871
|
|
11
|
+
c3/user.py,sha256=Fbzxq64HgDSiP8KyyocKdYVLrTZjFet9LbxCQLhKgDg,830
|
|
12
|
+
c3/job/__init__.py,sha256=q7qh7HyPuYdbMGE-ZPbqN7ss7-irlhLcASNH6K0PllE,448
|
|
13
|
+
c3/job/base.py,sha256=8tvkM1ebhQdNIpFPe6431gkKsCVOLKJXXWQRYB_Iz_g,8529
|
|
14
|
+
c3/job/comfyui.py,sha256=NIcTkCrHMcDxKC5v68Whbgmb0_T8hbYAAGhCRUthjEw,58817
|
|
15
|
+
hypercli_sdk-0.4.2.dist-info/METADATA,sha256=UL5AfalUjQW_vasMH697gfCGeYSPR07FGyrdHx-coys,2970
|
|
16
|
+
hypercli_sdk-0.4.2.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
17
|
+
hypercli_sdk-0.4.2.dist-info/RECORD,,
|