llamagen-python 0.1.6__tar.gz → 0.1.7__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.
- {llamagen_python-0.1.6 → llamagen_python-0.1.7}/PKG-INFO +168 -114
- {llamagen_python-0.1.6 → llamagen_python-0.1.7}/README.md +167 -113
- llamagen_python-0.1.7/examples/Untitled.ipynb +84 -0
- {llamagen_python-0.1.6 → llamagen_python-0.1.7}/examples/quickstart.py +2 -77
- {llamagen_python-0.1.6 → llamagen_python-0.1.7}/pyproject.toml +1 -1
- {llamagen_python-0.1.6 → llamagen_python-0.1.7}/src/llamagen/__init__.py +1 -6
- llamagen_python-0.1.7/src/llamagen/_errors.py +65 -0
- {llamagen_python-0.1.6 → llamagen_python-0.1.7}/src/llamagen/_http.py +1 -1
- {llamagen_python-0.1.6 → llamagen_python-0.1.7}/src/llamagen/_types.py +1 -5
- {llamagen_python-0.1.6 → llamagen_python-0.1.7}/src/llamagen/resources/animations.py +0 -3
- {llamagen_python-0.1.6 → llamagen_python-0.1.7}/src/llamagen/resources/comics.py +1 -65
- {llamagen_python-0.1.6 → llamagen_python-0.1.7}/tests/test_client.py +56 -2
- llamagen_python-0.1.6/src/llamagen/_errors.py +0 -24
- llamagen_python-0.1.6/src/llamagen/_webhooks.py +0 -138
- llamagen_python-0.1.6/tests/test_webhooks.py +0 -49
- {llamagen_python-0.1.6 → llamagen_python-0.1.7}/.gitignore +0 -0
- {llamagen_python-0.1.6 → llamagen_python-0.1.7}/LICENSE +0 -0
- {llamagen_python-0.1.6 → llamagen_python-0.1.7}/docs/RELEASE.md +0 -0
- {llamagen_python-0.1.6 → llamagen_python-0.1.7}/src/llamagen/_client.py +0 -0
- {llamagen_python-0.1.6 → llamagen_python-0.1.7}/src/llamagen/py.typed +0 -0
- {llamagen_python-0.1.6 → llamagen_python-0.1.7}/src/llamagen/resources/__init__.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: llamagen-python
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.7
|
|
4
4
|
Summary: Official Python SDK for LlamaGen Comic API and Animation API
|
|
5
5
|
Project-URL: Homepage, https://llamagen.ai/comic-api
|
|
6
6
|
Project-URL: Documentation, https://llamagen.ai/comic-api/docs
|
|
@@ -35,11 +35,26 @@ Homepage: <https://llamagen.ai/comic-api>
|
|
|
35
35
|
pip install llamagen-python
|
|
36
36
|
```
|
|
37
37
|
|
|
38
|
+
## Get Your API Key
|
|
39
|
+
|
|
40
|
+
1. Open the [LlamaGen Comic API Dashboard](https://llamagen.ai/comic-api).
|
|
41
|
+
2. Sign in and create an API key.
|
|
42
|
+
3. Use the key with the SDK or an HTTP `Authorization` header:
|
|
43
|
+
|
|
44
|
+
```http
|
|
45
|
+
Authorization: Bearer YOUR_API_KEY
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
For local SDK examples, set the key in your shell or in a local `.env` file:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
LLAMAGEN_API_KEY=YOUR_API_KEY
|
|
52
|
+
```
|
|
53
|
+
|
|
38
54
|
## Quick Start
|
|
39
55
|
|
|
40
56
|
```python
|
|
41
57
|
import os
|
|
42
|
-
from pathlib import Path
|
|
43
58
|
|
|
44
59
|
from llamagen import LlamaGenClient
|
|
45
60
|
|
|
@@ -63,14 +78,12 @@ done = client.comic.wait_for_completion(created["id"], timeout_ms=WAIT_TIMEOUT_M
|
|
|
63
78
|
print("comic.wait_for_completion:", done["id"], done.get("status"), done.get("comics"))
|
|
64
79
|
```
|
|
65
80
|
|
|
66
|
-
The full runnable demo is in [`examples/quickstart.py`](examples/quickstart.py).
|
|
67
|
-
It loads `LLAMAGEN_API_KEY` from the environment or a local `.env` file.
|
|
68
|
-
Set `LLAMAGEN_UPLOAD_FILE=/path/to/reference.png` to run the upload demo, and
|
|
69
|
-
set `LLAMAGEN_RUN_OPTIONAL_DEMOS=1` to run extra paid generation examples.
|
|
70
81
|
|
|
71
82
|
## Client
|
|
72
83
|
|
|
73
84
|
```python
|
|
85
|
+
from llamagen import LlamaGenClient
|
|
86
|
+
|
|
74
87
|
client = LlamaGenClient(
|
|
75
88
|
api_key="YOUR_API_KEY",
|
|
76
89
|
base_url="https://api.llamagen.ai/v1",
|
|
@@ -89,6 +102,12 @@ Use `llamagen.comic` to create comics, manga, webtoons, storyboards,
|
|
|
89
102
|
consistent-character pages, and panel edits.
|
|
90
103
|
|
|
91
104
|
```python
|
|
105
|
+
import os
|
|
106
|
+
|
|
107
|
+
from llamagen import LlamaGenClient
|
|
108
|
+
|
|
109
|
+
client = LlamaGenClient(api_key=os.environ["LLAMAGEN_API_KEY"])
|
|
110
|
+
|
|
92
111
|
generation = client.comic.create({
|
|
93
112
|
"prompt": "The Little Prince meets the Fox in a luminous desert.",
|
|
94
113
|
"style": "storybook manga",
|
|
@@ -117,116 +136,156 @@ Comic methods:
|
|
|
117
136
|
- `llamagen.comic.upload(file, filename=None)` calls `POST /v1/comics/upload`.
|
|
118
137
|
- `llamagen.comic.wait_for_completion(id, **options)` polls until a terminal status.
|
|
119
138
|
- `llamagen.comic.create_and_wait(params, **options)` creates and polls.
|
|
120
|
-
- `llamagen.comic.create_batch(params_list, concurrency=3)` submits many jobs.
|
|
121
|
-
- `llamagen.comic.wait_for_many(ids, concurrency=3)` polls many jobs.
|
|
122
139
|
|
|
123
140
|
Comic examples:
|
|
124
141
|
|
|
142
|
+
Create a comic generation:
|
|
143
|
+
|
|
125
144
|
```python
|
|
126
|
-
|
|
145
|
+
import os
|
|
146
|
+
|
|
147
|
+
from llamagen import LlamaGenClient
|
|
148
|
+
|
|
149
|
+
client = LlamaGenClient(api_key=os.environ["LLAMAGEN_API_KEY"])
|
|
150
|
+
|
|
127
151
|
created = client.comic.create({
|
|
128
152
|
"prompt": "A 4-panel comic about Leo finding a glowing key in a quiet library.",
|
|
129
153
|
"style": "manga",
|
|
130
154
|
"fixPanelNum": 4,
|
|
131
155
|
})
|
|
132
156
|
print("comic.create:", created["id"], created.get("status"))
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Fetch a comic generation, page, or panel:
|
|
133
160
|
|
|
134
|
-
|
|
135
|
-
|
|
161
|
+
```python
|
|
162
|
+
import os
|
|
163
|
+
|
|
164
|
+
from llamagen import LlamaGenClient
|
|
165
|
+
|
|
166
|
+
client = LlamaGenClient(api_key=os.environ["LLAMAGEN_API_KEY"])
|
|
167
|
+
comic_id = "YOUR_COMIC_ID"
|
|
168
|
+
|
|
169
|
+
fetched = client.comic.get(comic_id)
|
|
136
170
|
print("comic.get:", fetched["id"], fetched.get("status"))
|
|
137
171
|
|
|
138
|
-
panel = client.comic.get(
|
|
139
|
-
print("comic.get panel:", panel.get("id",
|
|
172
|
+
panel = client.comic.get(comic_id, page=0, panel=0)
|
|
173
|
+
print("comic.get panel:", panel.get("id", comic_id), panel.get("status"))
|
|
174
|
+
```
|
|
140
175
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
176
|
+
Wait for completion. The default timeout is 30 minutes:
|
|
177
|
+
|
|
178
|
+
```python
|
|
179
|
+
import os
|
|
180
|
+
|
|
181
|
+
from llamagen import LlamaGenClient
|
|
182
|
+
|
|
183
|
+
WAIT_TIMEOUT_MS = 30 * 60 * 1000
|
|
184
|
+
|
|
185
|
+
client = LlamaGenClient(api_key=os.environ["LLAMAGEN_API_KEY"])
|
|
186
|
+
comic_id = "YOUR_COMIC_ID"
|
|
187
|
+
|
|
188
|
+
done = client.comic.wait_for_completion(comic_id, timeout_ms=WAIT_TIMEOUT_MS)
|
|
144
189
|
print("comic.wait_for_completion:", done["id"], done.get("status"), done.get("comics"))
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
Create and wait in one call:
|
|
193
|
+
|
|
194
|
+
```python
|
|
195
|
+
import os
|
|
196
|
+
|
|
197
|
+
from llamagen import LlamaGenClient
|
|
198
|
+
|
|
199
|
+
WAIT_TIMEOUT_MS = 30 * 60 * 1000
|
|
200
|
+
|
|
201
|
+
client = LlamaGenClient(api_key=os.environ["LLAMAGEN_API_KEY"])
|
|
145
202
|
|
|
146
|
-
# Create and wait in one call.
|
|
147
203
|
finished = client.comic.create_and_wait({
|
|
148
204
|
"prompt": "A cozy 3-panel comic about a robot learning to bake bread.",
|
|
149
205
|
"style": "storybook",
|
|
150
206
|
"fixPanelNum": 3,
|
|
151
207
|
}, timeout_ms=WAIT_TIMEOUT_MS)
|
|
152
208
|
print("comic.create_and_wait:", finished["id"], finished.get("status"))
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
Continue an existing comic:
|
|
212
|
+
|
|
213
|
+
```python
|
|
214
|
+
import os
|
|
215
|
+
|
|
216
|
+
from llamagen import LlamaGenClient
|
|
217
|
+
|
|
218
|
+
client = LlamaGenClient(api_key=os.environ["LLAMAGEN_API_KEY"])
|
|
219
|
+
comic_id = "YOUR_COMIC_ID"
|
|
153
220
|
|
|
154
|
-
# Continue an existing comic.
|
|
155
221
|
continued = client.comic.continue_write(
|
|
156
|
-
|
|
222
|
+
comic_id,
|
|
157
223
|
{
|
|
158
224
|
"prompt": "Continue the story with Leo opening a secret reading room.",
|
|
159
225
|
"pagination": {"totalPages": 1, "panelsPerPage": 4},
|
|
160
226
|
},
|
|
161
227
|
)
|
|
162
228
|
print("comic.continue_write:", continued["id"], continued.get("status"))
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
Regenerate one panel:
|
|
232
|
+
|
|
233
|
+
```python
|
|
234
|
+
import os
|
|
235
|
+
|
|
236
|
+
from llamagen import LlamaGenClient
|
|
237
|
+
|
|
238
|
+
client = LlamaGenClient(api_key=os.environ["LLAMAGEN_API_KEY"])
|
|
239
|
+
comic_id = "YOUR_COMIC_ID"
|
|
163
240
|
|
|
164
|
-
# Regenerate one panel.
|
|
165
241
|
updated = client.comic.update_panel(
|
|
166
|
-
|
|
242
|
+
comic_id,
|
|
167
243
|
{
|
|
168
244
|
"panelIndex": 0,
|
|
169
245
|
"prompt": "Make the glowing key brighter and add dramatic moonlight.",
|
|
170
246
|
},
|
|
171
247
|
)
|
|
172
248
|
print("comic.update_panel:", updated["id"], updated.get("status"))
|
|
249
|
+
```
|
|
173
250
|
|
|
174
|
-
|
|
175
|
-
usage = client.comic.usage()
|
|
176
|
-
print("comic.usage:", usage)
|
|
251
|
+
Check usage:
|
|
177
252
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
if upload_file:
|
|
181
|
-
uploaded = client.comic.upload(Path(upload_file))
|
|
182
|
-
print("comic.upload:", uploaded)
|
|
253
|
+
```python
|
|
254
|
+
import os
|
|
183
255
|
|
|
184
|
-
|
|
185
|
-
batch = client.comic.create_batch(
|
|
186
|
-
[
|
|
187
|
-
{
|
|
188
|
-
"prompt": "A 2-panel comic about a cloud trying on hats.",
|
|
189
|
-
"style": "cartoon",
|
|
190
|
-
"fixPanelNum": 2,
|
|
191
|
-
},
|
|
192
|
-
{
|
|
193
|
-
"prompt": "A 2-panel comic about a tiny train crossing a desk.",
|
|
194
|
-
"style": "manga",
|
|
195
|
-
"fixPanelNum": 2,
|
|
196
|
-
},
|
|
197
|
-
],
|
|
198
|
-
concurrency=2,
|
|
199
|
-
)
|
|
200
|
-
ids = [item["result"]["id"] for item in batch if "result" in item]
|
|
201
|
-
print("comic.create_batch:", ids)
|
|
256
|
+
from llamagen import LlamaGenClient
|
|
202
257
|
|
|
203
|
-
|
|
204
|
-
print("comic.wait_for_many:", [(item["id"], item.get("status")) for item in finished_many])
|
|
205
|
-
```
|
|
258
|
+
client = LlamaGenClient(api_key=os.environ["LLAMAGEN_API_KEY"])
|
|
206
259
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
260
|
+
usage = client.comic.usage()
|
|
261
|
+
print("comic.usage:", usage)
|
|
262
|
+
```
|
|
210
263
|
|
|
211
|
-
|
|
264
|
+
Upload a local reference image:
|
|
212
265
|
|
|
213
266
|
```python
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
"fixPanelNum": 4,
|
|
217
|
-
})
|
|
218
|
-
print("comic.createComic:", created["id"], created.get("status"))
|
|
267
|
+
import os
|
|
268
|
+
from pathlib import Path
|
|
219
269
|
|
|
220
|
-
|
|
221
|
-
print("comic.getComic:", fetched["id"], fetched.get("status"))
|
|
270
|
+
from llamagen import LlamaGenClient
|
|
222
271
|
|
|
223
|
-
|
|
224
|
-
|
|
272
|
+
client = LlamaGenClient(api_key=os.environ["LLAMAGEN_API_KEY"])
|
|
273
|
+
|
|
274
|
+
upload_file = os.environ.get("LLAMAGEN_UPLOAD_FILE")
|
|
275
|
+
if upload_file:
|
|
276
|
+
uploaded = client.comic.upload(Path(upload_file))
|
|
277
|
+
print("comic.upload:", uploaded)
|
|
225
278
|
```
|
|
226
279
|
|
|
227
280
|
## Animation API
|
|
228
281
|
|
|
229
282
|
```python
|
|
283
|
+
import os
|
|
284
|
+
|
|
285
|
+
from llamagen import LlamaGenClient
|
|
286
|
+
|
|
287
|
+
client = LlamaGenClient(api_key=os.environ["LLAMAGEN_API_KEY"])
|
|
288
|
+
|
|
230
289
|
video = client.animation.create({
|
|
231
290
|
"prompt": "A heroic fox detective walks through neon rain, cinematic camera move.",
|
|
232
291
|
"videoOptions": {
|
|
@@ -250,12 +309,15 @@ Animation methods:
|
|
|
250
309
|
- `llamagen.animation.wait_for_completion(id, **options)` polls video status.
|
|
251
310
|
- `llamagen.animation.create_and_wait(params, **options)` creates and polls.
|
|
252
311
|
|
|
253
|
-
`llamagen.animations` is an alias for `llamagen.animation`.
|
|
254
|
-
|
|
255
312
|
Animation examples:
|
|
256
313
|
|
|
257
314
|
```python
|
|
258
|
-
|
|
315
|
+
import os
|
|
316
|
+
|
|
317
|
+
from llamagen import LlamaGenClient
|
|
318
|
+
|
|
319
|
+
client = LlamaGenClient(api_key=os.environ["LLAMAGEN_API_KEY"])
|
|
320
|
+
|
|
259
321
|
video = client.animation.create({
|
|
260
322
|
"prompt": "A heroic fox detective walks through neon rain, cinematic camera move.",
|
|
261
323
|
"videoOptions": {
|
|
@@ -266,14 +328,38 @@ video = client.animation.create({
|
|
|
266
328
|
})
|
|
267
329
|
print("animation.create:", video["id"], video.get("status"))
|
|
268
330
|
|
|
269
|
-
|
|
270
|
-
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
Fetch and wait for an animation:
|
|
334
|
+
|
|
335
|
+
```python
|
|
336
|
+
import os
|
|
337
|
+
|
|
338
|
+
from llamagen import LlamaGenClient
|
|
339
|
+
|
|
340
|
+
WAIT_TIMEOUT_MS = 30 * 60 * 1000
|
|
341
|
+
|
|
342
|
+
client = LlamaGenClient(api_key=os.environ["LLAMAGEN_API_KEY"])
|
|
343
|
+
animation_id = "YOUR_ANIMATION_ID"
|
|
344
|
+
|
|
345
|
+
fetched = client.animation.get(animation_id)
|
|
271
346
|
print("animation.get:", fetched["id"], fetched.get("status"))
|
|
272
347
|
|
|
273
|
-
finished = client.animation.wait_for_completion(
|
|
348
|
+
finished = client.animation.wait_for_completion(animation_id, timeout_ms=WAIT_TIMEOUT_MS)
|
|
274
349
|
print("animation.wait_for_completion:", finished["id"], finished.get("status"))
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
Create and wait for an animation in one call:
|
|
353
|
+
|
|
354
|
+
```python
|
|
355
|
+
import os
|
|
356
|
+
|
|
357
|
+
from llamagen import LlamaGenClient
|
|
358
|
+
|
|
359
|
+
WAIT_TIMEOUT_MS = 30 * 60 * 1000
|
|
360
|
+
|
|
361
|
+
client = LlamaGenClient(api_key=os.environ["LLAMAGEN_API_KEY"])
|
|
275
362
|
|
|
276
|
-
# Create and wait in one call.
|
|
277
363
|
finished = client.animation.create_and_wait({
|
|
278
364
|
"prompt": "A paper boat sailing across a watercolor city at sunrise.",
|
|
279
365
|
"videoOptions": {
|
|
@@ -284,60 +370,28 @@ finished = client.animation.create_and_wait({
|
|
|
284
370
|
}, timeout_ms=WAIT_TIMEOUT_MS)
|
|
285
371
|
print("animation.create_and_wait:", finished["id"], finished.get("status"))
|
|
286
372
|
|
|
287
|
-
# Alias form.
|
|
288
|
-
same_result = client.animations.waitForCompletion(video["id"], timeout_ms=WAIT_TIMEOUT_MS)
|
|
289
|
-
print("animations.waitForCompletion:", same_result["id"], same_result.get("status"))
|
|
290
373
|
```
|
|
291
374
|
|
|
292
|
-
##
|
|
375
|
+
## Errors
|
|
293
376
|
|
|
294
377
|
```python
|
|
295
|
-
import
|
|
296
|
-
import hmac
|
|
297
|
-
import json
|
|
298
|
-
import time
|
|
299
|
-
|
|
300
|
-
from llamagen import construct_webhook_event, verify_webhook_signature
|
|
301
|
-
|
|
302
|
-
payload = json.dumps({"type": "comic.completed", "data": {"id": "cm_demo"}}, separators=(",", ":"))
|
|
303
|
-
secret = "whsec_demo"
|
|
304
|
-
timestamp = str(int(time.time()))
|
|
305
|
-
signature = hmac.new(
|
|
306
|
-
secret.encode("utf-8"),
|
|
307
|
-
f"{timestamp}.{payload}".encode("utf-8"),
|
|
308
|
-
hashlib.sha256,
|
|
309
|
-
).hexdigest()
|
|
310
|
-
headers = {
|
|
311
|
-
"X-Llama-Webhook-Timestamp": timestamp,
|
|
312
|
-
"X-Llama-Webhook-Signature": f"v1={signature}",
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
is_valid = verify_webhook_signature(
|
|
316
|
-
payload=payload,
|
|
317
|
-
headers=headers,
|
|
318
|
-
secret=secret,
|
|
319
|
-
)
|
|
320
|
-
event = construct_webhook_event(
|
|
321
|
-
payload=payload,
|
|
322
|
-
headers=headers,
|
|
323
|
-
secret=secret,
|
|
324
|
-
)
|
|
325
|
-
print("verify_webhook_signature:", is_valid)
|
|
326
|
-
print("construct_webhook_event:", event["type"], event["data"]["id"])
|
|
327
|
-
```
|
|
328
|
-
|
|
329
|
-
The helper verifies `X-Llama-Webhook-Timestamp` and
|
|
330
|
-
`X-Llama-Webhook-Signature` with HMAC SHA-256 and a default 5-minute tolerance.
|
|
378
|
+
import os
|
|
331
379
|
|
|
332
|
-
|
|
380
|
+
from llamagen import (
|
|
381
|
+
LlamaGenAPIError,
|
|
382
|
+
LlamaGenClient,
|
|
383
|
+
LlamaGenConnectionError,
|
|
384
|
+
LlamaGenTimeoutError,
|
|
385
|
+
)
|
|
333
386
|
|
|
334
|
-
|
|
335
|
-
from llamagen import LlamaGenAPIError, LlamaGenConnectionError, LlamaGenTimeoutError
|
|
387
|
+
client = LlamaGenClient(api_key=os.environ["LLAMAGEN_API_KEY"])
|
|
336
388
|
|
|
337
389
|
try:
|
|
338
390
|
usage = client.comic.usage()
|
|
339
391
|
except LlamaGenAPIError as error:
|
|
340
|
-
print(
|
|
392
|
+
print("API request failed:", error)
|
|
393
|
+
print("HTTP status:", error.status)
|
|
394
|
+
print("Server response:", error.data)
|
|
341
395
|
except LlamaGenConnectionError as error:
|
|
342
396
|
print("Network connection failed:", error)
|
|
343
397
|
except LlamaGenTimeoutError as error:
|