llamagen-python 0.1.6__tar.gz → 0.1.8__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 (21) hide show
  1. {llamagen_python-0.1.6 → llamagen_python-0.1.8}/PKG-INFO +203 -117
  2. {llamagen_python-0.1.6 → llamagen_python-0.1.8}/README.md +202 -116
  3. llamagen_python-0.1.8/examples/quickstart.py +279 -0
  4. {llamagen_python-0.1.6 → llamagen_python-0.1.8}/pyproject.toml +1 -1
  5. {llamagen_python-0.1.6 → llamagen_python-0.1.8}/src/llamagen/__init__.py +1 -6
  6. llamagen_python-0.1.8/src/llamagen/_errors.py +65 -0
  7. {llamagen_python-0.1.6 → llamagen_python-0.1.8}/src/llamagen/_http.py +1 -1
  8. {llamagen_python-0.1.6 → llamagen_python-0.1.8}/src/llamagen/_types.py +1 -5
  9. {llamagen_python-0.1.6 → llamagen_python-0.1.8}/src/llamagen/resources/animations.py +0 -3
  10. {llamagen_python-0.1.6 → llamagen_python-0.1.8}/src/llamagen/resources/comics.py +1 -65
  11. {llamagen_python-0.1.6 → llamagen_python-0.1.8}/tests/test_client.py +56 -2
  12. llamagen_python-0.1.6/examples/quickstart.py +0 -246
  13. llamagen_python-0.1.6/src/llamagen/_errors.py +0 -24
  14. llamagen_python-0.1.6/src/llamagen/_webhooks.py +0 -138
  15. llamagen_python-0.1.6/tests/test_webhooks.py +0 -49
  16. {llamagen_python-0.1.6 → llamagen_python-0.1.8}/.gitignore +0 -0
  17. {llamagen_python-0.1.6 → llamagen_python-0.1.8}/LICENSE +0 -0
  18. {llamagen_python-0.1.6 → llamagen_python-0.1.8}/docs/RELEASE.md +0 -0
  19. {llamagen_python-0.1.6 → llamagen_python-0.1.8}/src/llamagen/_client.py +0 -0
  20. {llamagen_python-0.1.6 → llamagen_python-0.1.8}/src/llamagen/py.typed +0 -0
  21. {llamagen_python-0.1.6 → llamagen_python-0.1.8}/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.6
3
+ Version: 0.1.8
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
@@ -23,7 +23,7 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
23
23
  Requires-Python: >=3.9
24
24
  Description-Content-Type: text/markdown
25
25
 
26
- # llamagen-python
26
+ # LlamaGen Python SDK
27
27
 
28
28
  Official Python SDK for LlamaGen's Comic API and Animation API.
29
29
 
@@ -35,11 +35,29 @@ 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
 
56
+ This example creates one comic generation and waits for the final result. API
57
+ generation calls consume credits.
58
+
40
59
  ```python
41
60
  import os
42
- from pathlib import Path
43
61
 
44
62
  from llamagen import LlamaGenClient
45
63
 
@@ -63,14 +81,32 @@ done = client.comic.wait_for_completion(created["id"], timeout_ms=WAIT_TIMEOUT_M
63
81
  print("comic.wait_for_completion:", done["id"], done.get("status"), done.get("comics"))
64
82
  ```
65
83
 
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.
84
+ The full runnable demo is in [`examples/quickstart.py`](examples/quickstart.py):
85
+
86
+ ```bash
87
+ python examples/quickstart.py
88
+ ```
89
+
90
+ Pass a local image path to run the upload example:
91
+
92
+ ```bash
93
+ python examples/quickstart.py upload /path/to/reference.png
94
+ ```
95
+
96
+ Other README examples are available as subcommands, such as `comic-create`,
97
+ `comic-create-advanced`, `comic-get`, `comic-wait`, `comic-create-and-wait`,
98
+ `comic-continue`, `comic-update-panel`, `usage`, `animation-create`,
99
+ `animation-create-wait`, `animation-wait`, and `animation-create-and-wait`.
70
100
 
71
- ## Client
101
+ All Python examples below are self-contained for copy/paste usage. Replace
102
+ `YOUR_COMIC_ID` or `YOUR_ANIMATION_ID` with an existing generation ID when an
103
+ example fetches, waits for, continues, or updates an existing job.
104
+
105
+ ## Configure The Client
72
106
 
73
107
  ```python
108
+ from llamagen import LlamaGenClient
109
+
74
110
  client = LlamaGenClient(
75
111
  api_key="YOUR_API_KEY",
76
112
  base_url="https://api.llamagen.ai/v1",
@@ -88,7 +124,15 @@ dependencies.
88
124
  Use `llamagen.comic` to create comics, manga, webtoons, storyboards,
89
125
  consistent-character pages, and panel edits.
90
126
 
127
+ Create with advanced options:
128
+
91
129
  ```python
130
+ import os
131
+
132
+ from llamagen import LlamaGenClient
133
+
134
+ client = LlamaGenClient(api_key=os.environ["LLAMAGEN_API_KEY"])
135
+
92
136
  generation = client.comic.create({
93
137
  "prompt": "The Little Prince meets the Fox in a luminous desert.",
94
138
  "style": "storybook manga",
@@ -117,116 +161,157 @@ Comic methods:
117
161
  - `llamagen.comic.upload(file, filename=None)` calls `POST /v1/comics/upload`.
118
162
  - `llamagen.comic.wait_for_completion(id, **options)` polls until a terminal status.
119
163
  - `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
164
 
123
165
  Comic examples:
124
166
 
167
+ Create a comic generation:
168
+
125
169
  ```python
126
- # Create a comic generation.
170
+ import os
171
+
172
+ from llamagen import LlamaGenClient
173
+
174
+ client = LlamaGenClient(api_key=os.environ["LLAMAGEN_API_KEY"])
175
+
127
176
  created = client.comic.create({
128
177
  "prompt": "A 4-panel comic about Leo finding a glowing key in a quiet library.",
129
178
  "style": "manga",
130
179
  "fixPanelNum": 4,
131
180
  })
132
181
  print("comic.create:", created["id"], created.get("status"))
182
+ ```
133
183
 
134
- # Fetch the whole generation, or one page/panel.
135
- fetched = client.comic.get(created["id"])
184
+ Fetch a comic generation, page, or panel:
185
+
186
+ ```python
187
+ import os
188
+
189
+ from llamagen import LlamaGenClient
190
+
191
+ client = LlamaGenClient(api_key=os.environ["LLAMAGEN_API_KEY"])
192
+ comic_id = "YOUR_COMIC_ID"
193
+
194
+ fetched = client.comic.get(comic_id)
136
195
  print("comic.get:", fetched["id"], fetched.get("status"))
137
196
 
138
- panel = client.comic.get(created["id"], page=0, panel=0)
139
- print("comic.get panel:", panel.get("id", created["id"]), panel.get("status"))
197
+ panel = client.comic.get(comic_id, page=0, panel=0)
198
+ print("comic.get panel:", panel.get("id", comic_id), panel.get("status"))
199
+ ```
140
200
 
141
- # Wait until the generation reaches a terminal status.
142
- # The default timeout is 30 minutes.
143
- done = client.comic.wait_for_completion(created["id"], timeout_ms=WAIT_TIMEOUT_MS)
201
+ Wait for completion. The default timeout is 30 minutes:
202
+
203
+ ```python
204
+ import os
205
+
206
+ from llamagen import LlamaGenClient
207
+
208
+ WAIT_TIMEOUT_MS = 30 * 60 * 1000
209
+
210
+ client = LlamaGenClient(api_key=os.environ["LLAMAGEN_API_KEY"])
211
+ comic_id = "YOUR_COMIC_ID"
212
+
213
+ done = client.comic.wait_for_completion(comic_id, timeout_ms=WAIT_TIMEOUT_MS)
144
214
  print("comic.wait_for_completion:", done["id"], done.get("status"), done.get("comics"))
215
+ ```
216
+
217
+ Create and wait in one call:
218
+
219
+ ```python
220
+ import os
221
+
222
+ from llamagen import LlamaGenClient
223
+
224
+ WAIT_TIMEOUT_MS = 30 * 60 * 1000
225
+
226
+ client = LlamaGenClient(api_key=os.environ["LLAMAGEN_API_KEY"])
145
227
 
146
- # Create and wait in one call.
147
228
  finished = client.comic.create_and_wait({
148
229
  "prompt": "A cozy 3-panel comic about a robot learning to bake bread.",
149
230
  "style": "storybook",
150
231
  "fixPanelNum": 3,
151
232
  }, timeout_ms=WAIT_TIMEOUT_MS)
152
233
  print("comic.create_and_wait:", finished["id"], finished.get("status"))
234
+ ```
235
+
236
+ Continue an existing comic:
237
+
238
+ ```python
239
+ import os
240
+
241
+ from llamagen import LlamaGenClient
242
+
243
+ client = LlamaGenClient(api_key=os.environ["LLAMAGEN_API_KEY"])
244
+ comic_id = "YOUR_COMIC_ID"
153
245
 
154
- # Continue an existing comic.
155
246
  continued = client.comic.continue_write(
156
- created["id"],
247
+ comic_id,
157
248
  {
158
249
  "prompt": "Continue the story with Leo opening a secret reading room.",
159
250
  "pagination": {"totalPages": 1, "panelsPerPage": 4},
160
251
  },
161
252
  )
162
253
  print("comic.continue_write:", continued["id"], continued.get("status"))
254
+ ```
255
+
256
+ Regenerate one panel:
257
+
258
+ ```python
259
+ import os
260
+
261
+ from llamagen import LlamaGenClient
262
+
263
+ client = LlamaGenClient(api_key=os.environ["LLAMAGEN_API_KEY"])
264
+ comic_id = "YOUR_COMIC_ID"
163
265
 
164
- # Regenerate one panel.
165
266
  updated = client.comic.update_panel(
166
- created["id"],
267
+ comic_id,
167
268
  {
168
269
  "panelIndex": 0,
169
270
  "prompt": "Make the glowing key brighter and add dramatic moonlight.",
170
271
  },
171
272
  )
172
273
  print("comic.update_panel:", updated["id"], updated.get("status"))
274
+ ```
173
275
 
174
- # Check usage.
175
- usage = client.comic.usage()
176
- print("comic.usage:", usage)
276
+ Check usage:
177
277
 
178
- # Upload a local reference image.
179
- upload_file = os.environ.get("LLAMAGEN_UPLOAD_FILE")
180
- if upload_file:
181
- uploaded = client.comic.upload(Path(upload_file))
182
- print("comic.upload:", uploaded)
278
+ ```python
279
+ import os
183
280
 
184
- # Submit many jobs and wait for many jobs.
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)
281
+ from llamagen import LlamaGenClient
202
282
 
203
- finished_many = client.comic.wait_for_many(ids, concurrency=2, timeout_ms=WAIT_TIMEOUT_MS)
204
- print("comic.wait_for_many:", [(item["id"], item.get("status")) for item in finished_many])
205
- ```
283
+ client = LlamaGenClient(api_key=os.environ["LLAMAGEN_API_KEY"])
206
284
 
207
- JavaScript-style aliases are also available: `createComic`, `getComic`,
208
- `continueComic`, `regeneratePanel`, `updateComicPanel`, `waitForCompletion`,
209
- `createAndWait`, and `waitForMany`.
285
+ usage = client.comic.usage()
286
+ print("comic.usage:", usage)
287
+ ```
210
288
 
211
- Alias examples:
289
+ Upload a local reference image:
212
290
 
213
291
  ```python
214
- created = client.comic.createComic({
215
- "prompt": "A 4-panel comic about a lighthouse keeper finding a map.",
216
- "fixPanelNum": 4,
217
- })
218
- print("comic.createComic:", created["id"], created.get("status"))
292
+ import os
293
+ from pathlib import Path
294
+
295
+ from llamagen import LlamaGenClient
219
296
 
220
- fetched = client.comic.getComic(created["id"])
221
- print("comic.getComic:", fetched["id"], fetched.get("status"))
297
+ client = LlamaGenClient(api_key=os.environ["LLAMAGEN_API_KEY"])
222
298
 
223
- done = client.comic.waitForCompletion(created["id"], timeout_ms=WAIT_TIMEOUT_MS)
224
- print("comic.waitForCompletion:", done["id"], done.get("status"))
299
+ image_path = Path("reference.png")
300
+ uploaded = client.comic.upload(image_path)
301
+ print("comic.upload:", uploaded)
225
302
  ```
226
303
 
227
304
  ## Animation API
228
305
 
306
+ Create an animation job and wait for completion:
307
+
229
308
  ```python
309
+ import os
310
+
311
+ from llamagen import LlamaGenClient
312
+
313
+ client = LlamaGenClient(api_key=os.environ["LLAMAGEN_API_KEY"])
314
+
230
315
  video = client.animation.create({
231
316
  "prompt": "A heroic fox detective walks through neon rain, cinematic camera move.",
232
317
  "videoOptions": {
@@ -235,12 +320,14 @@ video = client.animation.create({
235
320
  "aspect_ratio": "16:9",
236
321
  },
237
322
  })
323
+ print("animation.create:", video["id"], video.get("status"))
238
324
 
239
325
  finished = client.animation.wait_for_completion(
240
326
  video["id"],
241
327
  interval_ms=5000,
242
328
  timeout_ms=30 * 60 * 1000,
243
329
  )
330
+ print("animation.wait_for_completion:", finished["id"], finished.get("status"))
244
331
  ```
245
332
 
246
333
  Animation methods:
@@ -250,12 +337,17 @@ Animation methods:
250
337
  - `llamagen.animation.wait_for_completion(id, **options)` polls video status.
251
338
  - `llamagen.animation.create_and_wait(params, **options)` creates and polls.
252
339
 
253
- `llamagen.animations` is an alias for `llamagen.animation`.
254
-
255
340
  Animation examples:
256
341
 
342
+ Create an animation job:
343
+
257
344
  ```python
258
- # Create an animation job.
345
+ import os
346
+
347
+ from llamagen import LlamaGenClient
348
+
349
+ client = LlamaGenClient(api_key=os.environ["LLAMAGEN_API_KEY"])
350
+
259
351
  video = client.animation.create({
260
352
  "prompt": "A heroic fox detective walks through neon rain, cinematic camera move.",
261
353
  "videoOptions": {
@@ -265,15 +357,38 @@ video = client.animation.create({
265
357
  },
266
358
  })
267
359
  print("animation.create:", video["id"], video.get("status"))
360
+ ```
361
+
362
+ Fetch and wait for an animation:
363
+
364
+ ```python
365
+ import os
268
366
 
269
- # Fetch and wait.
270
- fetched = client.animation.get(video["id"])
367
+ from llamagen import LlamaGenClient
368
+
369
+ WAIT_TIMEOUT_MS = 30 * 60 * 1000
370
+
371
+ client = LlamaGenClient(api_key=os.environ["LLAMAGEN_API_KEY"])
372
+ animation_id = "YOUR_ANIMATION_ID"
373
+
374
+ fetched = client.animation.get(animation_id)
271
375
  print("animation.get:", fetched["id"], fetched.get("status"))
272
376
 
273
- finished = client.animation.wait_for_completion(video["id"], timeout_ms=WAIT_TIMEOUT_MS)
377
+ finished = client.animation.wait_for_completion(animation_id, timeout_ms=WAIT_TIMEOUT_MS)
274
378
  print("animation.wait_for_completion:", finished["id"], finished.get("status"))
379
+ ```
380
+
381
+ Create and wait for an animation in one call:
382
+
383
+ ```python
384
+ import os
385
+
386
+ from llamagen import LlamaGenClient
387
+
388
+ WAIT_TIMEOUT_MS = 30 * 60 * 1000
389
+
390
+ client = LlamaGenClient(api_key=os.environ["LLAMAGEN_API_KEY"])
275
391
 
276
- # Create and wait in one call.
277
392
  finished = client.animation.create_and_wait({
278
393
  "prompt": "A paper boat sailing across a watercolor city at sunrise.",
279
394
  "videoOptions": {
@@ -283,61 +398,32 @@ finished = client.animation.create_and_wait({
283
398
  },
284
399
  }, timeout_ms=WAIT_TIMEOUT_MS)
285
400
  print("animation.create_and_wait:", finished["id"], finished.get("status"))
286
-
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
401
  ```
291
402
 
292
- ## Webhooks
403
+ ## Error Handling
293
404
 
294
- ```python
295
- import hashlib
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
- ```
405
+ API errors include the HTTP status, parsed server response, and a readable
406
+ message. For example, a `429` response can include an error code and message
407
+ such as insufficient credits.
328
408
 
329
- The helper verifies `X-Llama-Webhook-Timestamp` and
330
- `X-Llama-Webhook-Signature` with HMAC SHA-256 and a default 5-minute tolerance.
409
+ ```python
410
+ import os
331
411
 
332
- ## Errors
412
+ from llamagen import (
413
+ LlamaGenAPIError,
414
+ LlamaGenClient,
415
+ LlamaGenConnectionError,
416
+ LlamaGenTimeoutError,
417
+ )
333
418
 
334
- ```python
335
- from llamagen import LlamaGenAPIError, LlamaGenConnectionError, LlamaGenTimeoutError
419
+ client = LlamaGenClient(api_key=os.environ["LLAMAGEN_API_KEY"])
336
420
 
337
421
  try:
338
422
  usage = client.comic.usage()
339
423
  except LlamaGenAPIError as error:
340
- print(error.status, error.data)
424
+ print("API request failed:", error)
425
+ print("HTTP status:", error.status)
426
+ print("Server response:", error.data)
341
427
  except LlamaGenConnectionError as error:
342
428
  print("Network connection failed:", error)
343
429
  except LlamaGenTimeoutError as error: