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.
Files changed (21) hide show
  1. {llamagen_python-0.1.6 → llamagen_python-0.1.7}/PKG-INFO +168 -114
  2. {llamagen_python-0.1.6 → llamagen_python-0.1.7}/README.md +167 -113
  3. llamagen_python-0.1.7/examples/Untitled.ipynb +84 -0
  4. {llamagen_python-0.1.6 → llamagen_python-0.1.7}/examples/quickstart.py +2 -77
  5. {llamagen_python-0.1.6 → llamagen_python-0.1.7}/pyproject.toml +1 -1
  6. {llamagen_python-0.1.6 → llamagen_python-0.1.7}/src/llamagen/__init__.py +1 -6
  7. llamagen_python-0.1.7/src/llamagen/_errors.py +65 -0
  8. {llamagen_python-0.1.6 → llamagen_python-0.1.7}/src/llamagen/_http.py +1 -1
  9. {llamagen_python-0.1.6 → llamagen_python-0.1.7}/src/llamagen/_types.py +1 -5
  10. {llamagen_python-0.1.6 → llamagen_python-0.1.7}/src/llamagen/resources/animations.py +0 -3
  11. {llamagen_python-0.1.6 → llamagen_python-0.1.7}/src/llamagen/resources/comics.py +1 -65
  12. {llamagen_python-0.1.6 → llamagen_python-0.1.7}/tests/test_client.py +56 -2
  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.7}/.gitignore +0 -0
  17. {llamagen_python-0.1.6 → llamagen_python-0.1.7}/LICENSE +0 -0
  18. {llamagen_python-0.1.6 → llamagen_python-0.1.7}/docs/RELEASE.md +0 -0
  19. {llamagen_python-0.1.6 → llamagen_python-0.1.7}/src/llamagen/_client.py +0 -0
  20. {llamagen_python-0.1.6 → llamagen_python-0.1.7}/src/llamagen/py.typed +0 -0
  21. {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.6
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
- # Create a comic generation.
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
- # Fetch the whole generation, or one page/panel.
135
- fetched = client.comic.get(created["id"])
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(created["id"], page=0, panel=0)
139
- print("comic.get panel:", panel.get("id", created["id"]), panel.get("status"))
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
- # 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)
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
- created["id"],
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
- created["id"],
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
- # Check usage.
175
- usage = client.comic.usage()
176
- print("comic.usage:", usage)
251
+ Check usage:
177
252
 
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)
253
+ ```python
254
+ import os
183
255
 
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)
256
+ from llamagen import LlamaGenClient
202
257
 
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
- ```
258
+ client = LlamaGenClient(api_key=os.environ["LLAMAGEN_API_KEY"])
206
259
 
207
- JavaScript-style aliases are also available: `createComic`, `getComic`,
208
- `continueComic`, `regeneratePanel`, `updateComicPanel`, `waitForCompletion`,
209
- `createAndWait`, and `waitForMany`.
260
+ usage = client.comic.usage()
261
+ print("comic.usage:", usage)
262
+ ```
210
263
 
211
- Alias examples:
264
+ Upload a local reference image:
212
265
 
213
266
  ```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"))
267
+ import os
268
+ from pathlib import Path
219
269
 
220
- fetched = client.comic.getComic(created["id"])
221
- print("comic.getComic:", fetched["id"], fetched.get("status"))
270
+ from llamagen import LlamaGenClient
222
271
 
223
- done = client.comic.waitForCompletion(created["id"], timeout_ms=WAIT_TIMEOUT_MS)
224
- print("comic.waitForCompletion:", done["id"], done.get("status"))
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
- # Create an animation job.
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
- # Fetch and wait.
270
- fetched = client.animation.get(video["id"])
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(video["id"], timeout_ms=WAIT_TIMEOUT_MS)
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
- ## Webhooks
375
+ ## Errors
293
376
 
294
377
  ```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
- ```
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
- ## Errors
380
+ from llamagen import (
381
+ LlamaGenAPIError,
382
+ LlamaGenClient,
383
+ LlamaGenConnectionError,
384
+ LlamaGenTimeoutError,
385
+ )
333
386
 
334
- ```python
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(error.status, error.data)
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: