llamagen-python 0.1.7__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.
- {llamagen_python-0.1.7 → llamagen_python-0.1.8}/PKG-INFO +42 -10
- {llamagen_python-0.1.7 → llamagen_python-0.1.8}/README.md +41 -9
- llamagen_python-0.1.8/examples/quickstart.py +279 -0
- {llamagen_python-0.1.7 → llamagen_python-0.1.8}/pyproject.toml +1 -1
- {llamagen_python-0.1.7 → llamagen_python-0.1.8}/src/llamagen/__init__.py +1 -1
- {llamagen_python-0.1.7 → llamagen_python-0.1.8}/src/llamagen/_http.py +1 -1
- {llamagen_python-0.1.7 → llamagen_python-0.1.8}/tests/test_client.py +1 -1
- llamagen_python-0.1.7/examples/Untitled.ipynb +0 -84
- llamagen_python-0.1.7/examples/quickstart.py +0 -171
- {llamagen_python-0.1.7 → llamagen_python-0.1.8}/.gitignore +0 -0
- {llamagen_python-0.1.7 → llamagen_python-0.1.8}/LICENSE +0 -0
- {llamagen_python-0.1.7 → llamagen_python-0.1.8}/docs/RELEASE.md +0 -0
- {llamagen_python-0.1.7 → llamagen_python-0.1.8}/src/llamagen/_client.py +0 -0
- {llamagen_python-0.1.7 → llamagen_python-0.1.8}/src/llamagen/_errors.py +0 -0
- {llamagen_python-0.1.7 → llamagen_python-0.1.8}/src/llamagen/_types.py +0 -0
- {llamagen_python-0.1.7 → llamagen_python-0.1.8}/src/llamagen/py.typed +0 -0
- {llamagen_python-0.1.7 → llamagen_python-0.1.8}/src/llamagen/resources/__init__.py +0 -0
- {llamagen_python-0.1.7 → llamagen_python-0.1.8}/src/llamagen/resources/animations.py +0 -0
- {llamagen_python-0.1.7 → llamagen_python-0.1.8}/src/llamagen/resources/comics.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.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
|
-
#
|
|
26
|
+
# LlamaGen Python SDK
|
|
27
27
|
|
|
28
28
|
Official Python SDK for LlamaGen's Comic API and Animation API.
|
|
29
29
|
|
|
@@ -53,6 +53,9 @@ LLAMAGEN_API_KEY=YOUR_API_KEY
|
|
|
53
53
|
|
|
54
54
|
## Quick Start
|
|
55
55
|
|
|
56
|
+
This example creates one comic generation and waits for the final result. API
|
|
57
|
+
generation calls consume credits.
|
|
58
|
+
|
|
56
59
|
```python
|
|
57
60
|
import os
|
|
58
61
|
|
|
@@ -78,8 +81,28 @@ done = client.comic.wait_for_completion(created["id"], timeout_ms=WAIT_TIMEOUT_M
|
|
|
78
81
|
print("comic.wait_for_completion:", done["id"], done.get("status"), done.get("comics"))
|
|
79
82
|
```
|
|
80
83
|
|
|
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`.
|
|
81
100
|
|
|
82
|
-
|
|
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
|
|
83
106
|
|
|
84
107
|
```python
|
|
85
108
|
from llamagen import LlamaGenClient
|
|
@@ -101,6 +124,8 @@ dependencies.
|
|
|
101
124
|
Use `llamagen.comic` to create comics, manga, webtoons, storyboards,
|
|
102
125
|
consistent-character pages, and panel edits.
|
|
103
126
|
|
|
127
|
+
Create with advanced options:
|
|
128
|
+
|
|
104
129
|
```python
|
|
105
130
|
import os
|
|
106
131
|
|
|
@@ -271,14 +296,15 @@ from llamagen import LlamaGenClient
|
|
|
271
296
|
|
|
272
297
|
client = LlamaGenClient(api_key=os.environ["LLAMAGEN_API_KEY"])
|
|
273
298
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
print("comic.upload:", uploaded)
|
|
299
|
+
image_path = Path("reference.png")
|
|
300
|
+
uploaded = client.comic.upload(image_path)
|
|
301
|
+
print("comic.upload:", uploaded)
|
|
278
302
|
```
|
|
279
303
|
|
|
280
304
|
## Animation API
|
|
281
305
|
|
|
306
|
+
Create an animation job and wait for completion:
|
|
307
|
+
|
|
282
308
|
```python
|
|
283
309
|
import os
|
|
284
310
|
|
|
@@ -294,12 +320,14 @@ video = client.animation.create({
|
|
|
294
320
|
"aspect_ratio": "16:9",
|
|
295
321
|
},
|
|
296
322
|
})
|
|
323
|
+
print("animation.create:", video["id"], video.get("status"))
|
|
297
324
|
|
|
298
325
|
finished = client.animation.wait_for_completion(
|
|
299
326
|
video["id"],
|
|
300
327
|
interval_ms=5000,
|
|
301
328
|
timeout_ms=30 * 60 * 1000,
|
|
302
329
|
)
|
|
330
|
+
print("animation.wait_for_completion:", finished["id"], finished.get("status"))
|
|
303
331
|
```
|
|
304
332
|
|
|
305
333
|
Animation methods:
|
|
@@ -311,6 +339,8 @@ Animation methods:
|
|
|
311
339
|
|
|
312
340
|
Animation examples:
|
|
313
341
|
|
|
342
|
+
Create an animation job:
|
|
343
|
+
|
|
314
344
|
```python
|
|
315
345
|
import os
|
|
316
346
|
|
|
@@ -327,7 +357,6 @@ video = client.animation.create({
|
|
|
327
357
|
},
|
|
328
358
|
})
|
|
329
359
|
print("animation.create:", video["id"], video.get("status"))
|
|
330
|
-
|
|
331
360
|
```
|
|
332
361
|
|
|
333
362
|
Fetch and wait for an animation:
|
|
@@ -369,10 +398,13 @@ finished = client.animation.create_and_wait({
|
|
|
369
398
|
},
|
|
370
399
|
}, timeout_ms=WAIT_TIMEOUT_MS)
|
|
371
400
|
print("animation.create_and_wait:", finished["id"], finished.get("status"))
|
|
372
|
-
|
|
373
401
|
```
|
|
374
402
|
|
|
375
|
-
##
|
|
403
|
+
## Error Handling
|
|
404
|
+
|
|
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.
|
|
376
408
|
|
|
377
409
|
```python
|
|
378
410
|
import os
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#
|
|
1
|
+
# LlamaGen Python SDK
|
|
2
2
|
|
|
3
3
|
Official Python SDK for LlamaGen's Comic API and Animation API.
|
|
4
4
|
|
|
@@ -28,6 +28,9 @@ LLAMAGEN_API_KEY=YOUR_API_KEY
|
|
|
28
28
|
|
|
29
29
|
## Quick Start
|
|
30
30
|
|
|
31
|
+
This example creates one comic generation and waits for the final result. API
|
|
32
|
+
generation calls consume credits.
|
|
33
|
+
|
|
31
34
|
```python
|
|
32
35
|
import os
|
|
33
36
|
|
|
@@ -53,8 +56,28 @@ done = client.comic.wait_for_completion(created["id"], timeout_ms=WAIT_TIMEOUT_M
|
|
|
53
56
|
print("comic.wait_for_completion:", done["id"], done.get("status"), done.get("comics"))
|
|
54
57
|
```
|
|
55
58
|
|
|
59
|
+
The full runnable demo is in [`examples/quickstart.py`](examples/quickstart.py):
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
python examples/quickstart.py
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Pass a local image path to run the upload example:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
python examples/quickstart.py upload /path/to/reference.png
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Other README examples are available as subcommands, such as `comic-create`,
|
|
72
|
+
`comic-create-advanced`, `comic-get`, `comic-wait`, `comic-create-and-wait`,
|
|
73
|
+
`comic-continue`, `comic-update-panel`, `usage`, `animation-create`,
|
|
74
|
+
`animation-create-wait`, `animation-wait`, and `animation-create-and-wait`.
|
|
56
75
|
|
|
57
|
-
|
|
76
|
+
All Python examples below are self-contained for copy/paste usage. Replace
|
|
77
|
+
`YOUR_COMIC_ID` or `YOUR_ANIMATION_ID` with an existing generation ID when an
|
|
78
|
+
example fetches, waits for, continues, or updates an existing job.
|
|
79
|
+
|
|
80
|
+
## Configure The Client
|
|
58
81
|
|
|
59
82
|
```python
|
|
60
83
|
from llamagen import LlamaGenClient
|
|
@@ -76,6 +99,8 @@ dependencies.
|
|
|
76
99
|
Use `llamagen.comic` to create comics, manga, webtoons, storyboards,
|
|
77
100
|
consistent-character pages, and panel edits.
|
|
78
101
|
|
|
102
|
+
Create with advanced options:
|
|
103
|
+
|
|
79
104
|
```python
|
|
80
105
|
import os
|
|
81
106
|
|
|
@@ -246,14 +271,15 @@ from llamagen import LlamaGenClient
|
|
|
246
271
|
|
|
247
272
|
client = LlamaGenClient(api_key=os.environ["LLAMAGEN_API_KEY"])
|
|
248
273
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
print("comic.upload:", uploaded)
|
|
274
|
+
image_path = Path("reference.png")
|
|
275
|
+
uploaded = client.comic.upload(image_path)
|
|
276
|
+
print("comic.upload:", uploaded)
|
|
253
277
|
```
|
|
254
278
|
|
|
255
279
|
## Animation API
|
|
256
280
|
|
|
281
|
+
Create an animation job and wait for completion:
|
|
282
|
+
|
|
257
283
|
```python
|
|
258
284
|
import os
|
|
259
285
|
|
|
@@ -269,12 +295,14 @@ video = client.animation.create({
|
|
|
269
295
|
"aspect_ratio": "16:9",
|
|
270
296
|
},
|
|
271
297
|
})
|
|
298
|
+
print("animation.create:", video["id"], video.get("status"))
|
|
272
299
|
|
|
273
300
|
finished = client.animation.wait_for_completion(
|
|
274
301
|
video["id"],
|
|
275
302
|
interval_ms=5000,
|
|
276
303
|
timeout_ms=30 * 60 * 1000,
|
|
277
304
|
)
|
|
305
|
+
print("animation.wait_for_completion:", finished["id"], finished.get("status"))
|
|
278
306
|
```
|
|
279
307
|
|
|
280
308
|
Animation methods:
|
|
@@ -286,6 +314,8 @@ Animation methods:
|
|
|
286
314
|
|
|
287
315
|
Animation examples:
|
|
288
316
|
|
|
317
|
+
Create an animation job:
|
|
318
|
+
|
|
289
319
|
```python
|
|
290
320
|
import os
|
|
291
321
|
|
|
@@ -302,7 +332,6 @@ video = client.animation.create({
|
|
|
302
332
|
},
|
|
303
333
|
})
|
|
304
334
|
print("animation.create:", video["id"], video.get("status"))
|
|
305
|
-
|
|
306
335
|
```
|
|
307
336
|
|
|
308
337
|
Fetch and wait for an animation:
|
|
@@ -344,10 +373,13 @@ finished = client.animation.create_and_wait({
|
|
|
344
373
|
},
|
|
345
374
|
}, timeout_ms=WAIT_TIMEOUT_MS)
|
|
346
375
|
print("animation.create_and_wait:", finished["id"], finished.get("status"))
|
|
347
|
-
|
|
348
376
|
```
|
|
349
377
|
|
|
350
|
-
##
|
|
378
|
+
## Error Handling
|
|
379
|
+
|
|
380
|
+
API errors include the HTTP status, parsed server response, and a readable
|
|
381
|
+
message. For example, a `429` response can include an error code and message
|
|
382
|
+
such as insufficient credits.
|
|
351
383
|
|
|
352
384
|
```python
|
|
353
385
|
import os
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
import os
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
from llamagen import (
|
|
6
|
+
LlamaGenAPIError,
|
|
7
|
+
LlamaGenClient,
|
|
8
|
+
LlamaGenConnectionError,
|
|
9
|
+
LlamaGenTimeoutError,
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
ROOT = Path(__file__).resolve().parents[1]
|
|
14
|
+
WAIT_TIMEOUT_MS = 30 * 60 * 1000
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def load_dotenv(path: Path) -> None:
|
|
18
|
+
if not path.exists():
|
|
19
|
+
return
|
|
20
|
+
|
|
21
|
+
for raw_line in path.read_text(encoding="utf-8").splitlines():
|
|
22
|
+
line = raw_line.strip()
|
|
23
|
+
if not line or line.startswith("#") or "=" not in line:
|
|
24
|
+
continue
|
|
25
|
+
key, value = line.split("=", 1)
|
|
26
|
+
os.environ.setdefault(key.strip(), value.strip().strip('"').strip("'"))
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def make_client() -> LlamaGenClient:
|
|
30
|
+
load_dotenv(ROOT / ".env")
|
|
31
|
+
return LlamaGenClient(
|
|
32
|
+
api_key=os.environ["LLAMAGEN_API_KEY"],
|
|
33
|
+
timeout_ms=30000,
|
|
34
|
+
max_retries=5,
|
|
35
|
+
retry_delay_ms=500,
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def quick_start(client: LlamaGenClient) -> None:
|
|
40
|
+
created = client.comic.create(
|
|
41
|
+
{
|
|
42
|
+
"prompt": "A 4-panel comic about Leo finding a glowing key in a quiet library.",
|
|
43
|
+
"style": "manga",
|
|
44
|
+
"fixPanelNum": 4,
|
|
45
|
+
}
|
|
46
|
+
)
|
|
47
|
+
print("comic.create:", created["id"], created.get("status"))
|
|
48
|
+
|
|
49
|
+
done = client.comic.wait_for_completion(created["id"], timeout_ms=WAIT_TIMEOUT_MS)
|
|
50
|
+
print("comic.wait_for_completion:", done["id"], done.get("status"), done.get("comics"))
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def create_comic(client: LlamaGenClient) -> None:
|
|
54
|
+
created = client.comic.create(
|
|
55
|
+
{
|
|
56
|
+
"prompt": "A 4-panel comic about Leo finding a glowing key in a quiet library.",
|
|
57
|
+
"style": "manga",
|
|
58
|
+
"fixPanelNum": 4,
|
|
59
|
+
}
|
|
60
|
+
)
|
|
61
|
+
print("comic.create:", created["id"], created.get("status"))
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def create_comic_with_advanced_options(client: LlamaGenClient) -> None:
|
|
65
|
+
generation = client.comic.create(
|
|
66
|
+
{
|
|
67
|
+
"prompt": "The Little Prince meets the Fox in a luminous desert.",
|
|
68
|
+
"style": "storybook manga",
|
|
69
|
+
"size": "1024x1024",
|
|
70
|
+
"pagination": {"totalPages": 2, "panelsPerPage": 4},
|
|
71
|
+
"comicRoles": [
|
|
72
|
+
{
|
|
73
|
+
"name": "The Little Prince",
|
|
74
|
+
"image": "https://example.com/prince.png",
|
|
75
|
+
"clothing": "green coat and yellow scarf",
|
|
76
|
+
}
|
|
77
|
+
],
|
|
78
|
+
"attachments": [{"type": "image", "url": "https://example.com/reference.png"}],
|
|
79
|
+
"language": "en",
|
|
80
|
+
"upscale": "2K",
|
|
81
|
+
}
|
|
82
|
+
)
|
|
83
|
+
print("comic.create advanced:", generation["id"], generation.get("status"))
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def get_comic(client: LlamaGenClient, comic_id: str) -> None:
|
|
87
|
+
fetched = client.comic.get(comic_id)
|
|
88
|
+
print("comic.get:", fetched["id"], fetched.get("status"))
|
|
89
|
+
|
|
90
|
+
panel = client.comic.get(comic_id, page=0, panel=0)
|
|
91
|
+
print("comic.get panel:", panel.get("id", comic_id), panel.get("status"))
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def wait_for_comic(client: LlamaGenClient, comic_id: str) -> None:
|
|
95
|
+
done = client.comic.wait_for_completion(comic_id, timeout_ms=WAIT_TIMEOUT_MS)
|
|
96
|
+
print("comic.wait_for_completion:", done["id"], done.get("status"), done.get("comics"))
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def create_and_wait_for_comic(client: LlamaGenClient) -> None:
|
|
100
|
+
finished = client.comic.create_and_wait(
|
|
101
|
+
{
|
|
102
|
+
"prompt": "A cozy 3-panel comic about a robot learning to bake bread.",
|
|
103
|
+
"style": "storybook",
|
|
104
|
+
"fixPanelNum": 3,
|
|
105
|
+
},
|
|
106
|
+
timeout_ms=WAIT_TIMEOUT_MS,
|
|
107
|
+
)
|
|
108
|
+
print("comic.create_and_wait:", finished["id"], finished.get("status"))
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def continue_comic(client: LlamaGenClient, comic_id: str) -> None:
|
|
112
|
+
continued = client.comic.continue_write(
|
|
113
|
+
comic_id,
|
|
114
|
+
{
|
|
115
|
+
"prompt": "Continue the story with Leo opening a secret reading room.",
|
|
116
|
+
"pagination": {"totalPages": 1, "panelsPerPage": 4},
|
|
117
|
+
},
|
|
118
|
+
)
|
|
119
|
+
print("comic.continue_write:", continued["id"], continued.get("status"))
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def update_comic_panel(client: LlamaGenClient, comic_id: str) -> None:
|
|
123
|
+
updated = client.comic.update_panel(
|
|
124
|
+
comic_id,
|
|
125
|
+
{
|
|
126
|
+
"panelIndex": 0,
|
|
127
|
+
"prompt": "Make the glowing key brighter and add dramatic moonlight.",
|
|
128
|
+
},
|
|
129
|
+
)
|
|
130
|
+
print("comic.update_panel:", updated["id"], updated.get("status"))
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def show_usage(client: LlamaGenClient) -> None:
|
|
134
|
+
usage = client.comic.usage()
|
|
135
|
+
print("comic.usage:", usage)
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def upload_reference_image(client: LlamaGenClient, image_path: Path) -> None:
|
|
139
|
+
uploaded = client.comic.upload(image_path)
|
|
140
|
+
print("comic.upload:", uploaded)
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def create_animation(client: LlamaGenClient) -> None:
|
|
144
|
+
video = client.animation.create(
|
|
145
|
+
{
|
|
146
|
+
"prompt": "A heroic fox detective walks through neon rain, cinematic camera move.",
|
|
147
|
+
"videoOptions": {
|
|
148
|
+
"duration": 5,
|
|
149
|
+
"resolution": "720p",
|
|
150
|
+
"aspect_ratio": "16:9",
|
|
151
|
+
},
|
|
152
|
+
}
|
|
153
|
+
)
|
|
154
|
+
print("animation.create:", video["id"], video.get("status"))
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def create_and_wait_for_animation_with_manual_wait(client: LlamaGenClient) -> None:
|
|
158
|
+
video = client.animation.create(
|
|
159
|
+
{
|
|
160
|
+
"prompt": "A heroic fox detective walks through neon rain, cinematic camera move.",
|
|
161
|
+
"videoOptions": {
|
|
162
|
+
"duration": 5,
|
|
163
|
+
"resolution": "720p",
|
|
164
|
+
"aspect_ratio": "16:9",
|
|
165
|
+
},
|
|
166
|
+
}
|
|
167
|
+
)
|
|
168
|
+
print("animation.create:", video["id"], video.get("status"))
|
|
169
|
+
|
|
170
|
+
finished = client.animation.wait_for_completion(
|
|
171
|
+
video["id"],
|
|
172
|
+
interval_ms=5000,
|
|
173
|
+
timeout_ms=WAIT_TIMEOUT_MS,
|
|
174
|
+
)
|
|
175
|
+
print("animation.wait_for_completion:", finished["id"], finished.get("status"))
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def create_and_wait_for_animation(client: LlamaGenClient) -> None:
|
|
179
|
+
finished = client.animation.create_and_wait(
|
|
180
|
+
{
|
|
181
|
+
"prompt": "A paper boat sailing across a watercolor city at sunrise.",
|
|
182
|
+
"videoOptions": {
|
|
183
|
+
"duration": 5,
|
|
184
|
+
"resolution": "720p",
|
|
185
|
+
"aspect_ratio": "16:9",
|
|
186
|
+
},
|
|
187
|
+
},
|
|
188
|
+
timeout_ms=WAIT_TIMEOUT_MS,
|
|
189
|
+
)
|
|
190
|
+
print("animation.create_and_wait:", finished["id"], finished.get("status"))
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
def wait_for_animation(client: LlamaGenClient, animation_id: str) -> None:
|
|
194
|
+
fetched = client.animation.get(animation_id)
|
|
195
|
+
print("animation.get:", fetched["id"], fetched.get("status"))
|
|
196
|
+
|
|
197
|
+
finished = client.animation.wait_for_completion(animation_id, timeout_ms=WAIT_TIMEOUT_MS)
|
|
198
|
+
print("animation.wait_for_completion:", finished["id"], finished.get("status"))
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
def parse_args() -> argparse.Namespace:
|
|
202
|
+
parser = argparse.ArgumentParser(description="Run LlamaGen Python SDK examples.")
|
|
203
|
+
subparsers = parser.add_subparsers(dest="command")
|
|
204
|
+
|
|
205
|
+
subparsers.add_parser("quickstart", help="Create one comic and wait for completion.")
|
|
206
|
+
subparsers.add_parser("comic-create", help="Create one comic generation.")
|
|
207
|
+
subparsers.add_parser("comic-create-advanced", help="Create a comic with advanced options.")
|
|
208
|
+
subparsers.add_parser("comic-create-and-wait", help="Create one comic and wait in one call.")
|
|
209
|
+
subparsers.add_parser("usage", help="Fetch comic API usage.")
|
|
210
|
+
|
|
211
|
+
get_parser = subparsers.add_parser("comic-get", help="Fetch a comic generation, page, and panel.")
|
|
212
|
+
get_parser.add_argument("comic_id")
|
|
213
|
+
|
|
214
|
+
wait_parser = subparsers.add_parser("comic-wait", help="Wait for a comic generation.")
|
|
215
|
+
wait_parser.add_argument("comic_id")
|
|
216
|
+
|
|
217
|
+
continue_parser = subparsers.add_parser("comic-continue", help="Continue an existing comic.")
|
|
218
|
+
continue_parser.add_argument("comic_id")
|
|
219
|
+
|
|
220
|
+
update_parser = subparsers.add_parser("comic-update-panel", help="Regenerate one panel.")
|
|
221
|
+
update_parser.add_argument("comic_id")
|
|
222
|
+
|
|
223
|
+
upload_parser = subparsers.add_parser("upload", help="Upload a local reference image.")
|
|
224
|
+
upload_parser.add_argument("image_path", type=Path)
|
|
225
|
+
|
|
226
|
+
subparsers.add_parser("animation-create", help="Create an animation job.")
|
|
227
|
+
subparsers.add_parser("animation-create-wait", help="Create an animation job and wait for completion.")
|
|
228
|
+
subparsers.add_parser("animation-create-and-wait", help="Create an animation job and wait in one call.")
|
|
229
|
+
|
|
230
|
+
animation_wait_parser = subparsers.add_parser("animation-wait", help="Fetch and wait for an animation.")
|
|
231
|
+
animation_wait_parser.add_argument("animation_id")
|
|
232
|
+
|
|
233
|
+
return parser.parse_args()
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
def main() -> None:
|
|
237
|
+
args = parse_args()
|
|
238
|
+
client = make_client()
|
|
239
|
+
command = args.command or "quickstart"
|
|
240
|
+
|
|
241
|
+
if command == "quickstart":
|
|
242
|
+
quick_start(client)
|
|
243
|
+
elif command == "comic-create":
|
|
244
|
+
create_comic(client)
|
|
245
|
+
elif command == "comic-create-advanced":
|
|
246
|
+
create_comic_with_advanced_options(client)
|
|
247
|
+
elif command == "comic-get":
|
|
248
|
+
get_comic(client, args.comic_id)
|
|
249
|
+
elif command == "comic-wait":
|
|
250
|
+
wait_for_comic(client, args.comic_id)
|
|
251
|
+
elif command == "comic-create-and-wait":
|
|
252
|
+
create_and_wait_for_comic(client)
|
|
253
|
+
elif command == "comic-continue":
|
|
254
|
+
continue_comic(client, args.comic_id)
|
|
255
|
+
elif command == "comic-update-panel":
|
|
256
|
+
update_comic_panel(client, args.comic_id)
|
|
257
|
+
elif command == "usage":
|
|
258
|
+
show_usage(client)
|
|
259
|
+
elif command == "upload":
|
|
260
|
+
upload_reference_image(client, args.image_path)
|
|
261
|
+
elif command == "animation-create":
|
|
262
|
+
create_animation(client)
|
|
263
|
+
elif command == "animation-create-wait":
|
|
264
|
+
create_and_wait_for_animation_with_manual_wait(client)
|
|
265
|
+
elif command == "animation-wait":
|
|
266
|
+
wait_for_animation(client, args.animation_id)
|
|
267
|
+
elif command == "animation-create-and-wait":
|
|
268
|
+
create_and_wait_for_animation(client)
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
if __name__ == "__main__":
|
|
272
|
+
try:
|
|
273
|
+
main()
|
|
274
|
+
except LlamaGenAPIError as error:
|
|
275
|
+
print("LlamaGen API error:", error)
|
|
276
|
+
except LlamaGenConnectionError as error:
|
|
277
|
+
print("LlamaGen connection error:", error)
|
|
278
|
+
except LlamaGenTimeoutError as error:
|
|
279
|
+
print("LlamaGen timeout:", error)
|
|
@@ -10,7 +10,7 @@ from typing import Any, Dict, Mapping, Optional, Protocol, Tuple
|
|
|
10
10
|
|
|
11
11
|
from ._errors import LlamaGenAPIError, LlamaGenConnectionError, LlamaGenTimeoutError
|
|
12
12
|
|
|
13
|
-
DEFAULT_USER_AGENT = "llamagen-python/0.1.
|
|
13
|
+
DEFAULT_USER_AGENT = "llamagen-python/0.1.8"
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
class Transport(Protocol):
|
|
@@ -80,7 +80,7 @@ class ClientTests(unittest.TestCase):
|
|
|
80
80
|
self.assertEqual(call["url"], "https://api.llamagen.ai/v1/comics/generations")
|
|
81
81
|
self.assertEqual(call["headers"]["Authorization"], "Bearer test-key")
|
|
82
82
|
self.assertEqual(call["headers"]["Accept"], "application/json")
|
|
83
|
-
self.assertEqual(call["headers"]["User-Agent"], "llamagen-python/0.1.
|
|
83
|
+
self.assertEqual(call["headers"]["User-Agent"], "llamagen-python/0.1.8")
|
|
84
84
|
body = json.loads(call["body"].decode("utf-8"))
|
|
85
85
|
self.assertEqual(body["preset"], "neutral")
|
|
86
86
|
self.assertEqual(body["size"], "1024x1024")
|
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"cells": [
|
|
3
|
-
{
|
|
4
|
-
"cell_type": "code",
|
|
5
|
-
"execution_count": null,
|
|
6
|
-
"id": "cdc9de5a-8720-4448-abc3-f4a1a5c8f988",
|
|
7
|
-
"metadata": {},
|
|
8
|
-
"outputs": [
|
|
9
|
-
{
|
|
10
|
-
"name": "stdout",
|
|
11
|
-
"output_type": "stream",
|
|
12
|
-
"text": [
|
|
13
|
-
"comic.create: cmrf1zulc000rl204y6b0w4kg LOADING\n"
|
|
14
|
-
]
|
|
15
|
-
}
|
|
16
|
-
],
|
|
17
|
-
"source": [
|
|
18
|
-
"import os\n",
|
|
19
|
-
"from pathlib import Path\n",
|
|
20
|
-
"\n",
|
|
21
|
-
"from llamagen import LlamaGenClient\n",
|
|
22
|
-
"\n",
|
|
23
|
-
"WAIT_TIMEOUT_MS = 30 * 60 * 1000\n",
|
|
24
|
-
"\n",
|
|
25
|
-
"client = LlamaGenClient(\n",
|
|
26
|
-
" api_key=\"sk-5d609cd64379d048edcb04dcc109a6cfaf7c066f12138c13c8c404766ab9629d\",\n",
|
|
27
|
-
" timeout_ms=30000,\n",
|
|
28
|
-
" max_retries=5,\n",
|
|
29
|
-
" retry_delay_ms=500,\n",
|
|
30
|
-
")\n",
|
|
31
|
-
"\n",
|
|
32
|
-
"created = client.comic.create({\n",
|
|
33
|
-
" \"prompt\": \"The Little Prince meets the Fox in a luminous desert.\",\n",
|
|
34
|
-
" \"style\": \"storybook manga\",\n",
|
|
35
|
-
" \"size\": \"1024x1024\",\n",
|
|
36
|
-
" \"pagination\": {\"totalPages\": 2, \"panelsPerPage\": 4},\n",
|
|
37
|
-
" \"comicRoles\": [\n",
|
|
38
|
-
" {\n",
|
|
39
|
-
" \"name\": \"The Little Prince\",\n",
|
|
40
|
-
" \"image\": \"https://example.com/prince.png\",\n",
|
|
41
|
-
" \"clothing\": \"green coat and yellow scarf\",\n",
|
|
42
|
-
" }\n",
|
|
43
|
-
" ],\n",
|
|
44
|
-
" \"attachments\": [{\"type\": \"image\", \"url\": \"https://example.com/reference.png\"}],\n",
|
|
45
|
-
" \"language\": \"en\",\n",
|
|
46
|
-
" \"upscale\": \"2K\",\n",
|
|
47
|
-
"})\n",
|
|
48
|
-
"print(\"comic.create:\", created[\"id\"], created.get(\"status\"))\n",
|
|
49
|
-
"\n",
|
|
50
|
-
"done = client.comic.wait_for_completion(created[\"id\"], timeout_ms=WAIT_TIMEOUT_MS)\n",
|
|
51
|
-
"print(\"comic.wait_for_completion:\", done[\"id\"], done.get(\"status\"), done.get(\"comics\"))"
|
|
52
|
-
]
|
|
53
|
-
},
|
|
54
|
-
{
|
|
55
|
-
"cell_type": "code",
|
|
56
|
-
"execution_count": null,
|
|
57
|
-
"id": "9be79812-b6f6-443e-9916-c9130dc0526b",
|
|
58
|
-
"metadata": {},
|
|
59
|
-
"outputs": [],
|
|
60
|
-
"source": []
|
|
61
|
-
}
|
|
62
|
-
],
|
|
63
|
-
"metadata": {
|
|
64
|
-
"kernelspec": {
|
|
65
|
-
"display_name": "Python 3 (ipykernel)",
|
|
66
|
-
"language": "python",
|
|
67
|
-
"name": "python3"
|
|
68
|
-
},
|
|
69
|
-
"language_info": {
|
|
70
|
-
"codemirror_mode": {
|
|
71
|
-
"name": "ipython",
|
|
72
|
-
"version": 3
|
|
73
|
-
},
|
|
74
|
-
"file_extension": ".py",
|
|
75
|
-
"mimetype": "text/x-python",
|
|
76
|
-
"name": "python",
|
|
77
|
-
"nbconvert_exporter": "python",
|
|
78
|
-
"pygments_lexer": "ipython3",
|
|
79
|
-
"version": "3.12.7"
|
|
80
|
-
}
|
|
81
|
-
},
|
|
82
|
-
"nbformat": 4,
|
|
83
|
-
"nbformat_minor": 5
|
|
84
|
-
}
|
|
@@ -1,171 +0,0 @@
|
|
|
1
|
-
import os
|
|
2
|
-
from pathlib import Path
|
|
3
|
-
|
|
4
|
-
from llamagen import (
|
|
5
|
-
LlamaGenAPIError,
|
|
6
|
-
LlamaGenClient,
|
|
7
|
-
LlamaGenConnectionError,
|
|
8
|
-
LlamaGenTimeoutError,
|
|
9
|
-
)
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
ROOT = Path(__file__).resolve().parents[1]
|
|
13
|
-
WAIT_TIMEOUT_MS = 30 * 60 * 1000
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
def load_dotenv(path: Path) -> None:
|
|
17
|
-
if not path.exists():
|
|
18
|
-
return
|
|
19
|
-
|
|
20
|
-
for raw_line in path.read_text(encoding="utf-8").splitlines():
|
|
21
|
-
line = raw_line.strip()
|
|
22
|
-
if not line or line.startswith("#") or "=" not in line:
|
|
23
|
-
continue
|
|
24
|
-
key, value = line.split("=", 1)
|
|
25
|
-
os.environ.setdefault(key.strip(), value.strip().strip('"').strip("'"))
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
def make_client() -> LlamaGenClient:
|
|
29
|
-
load_dotenv(ROOT / ".env")
|
|
30
|
-
return LlamaGenClient(
|
|
31
|
-
api_key=os.environ["LLAMAGEN_API_KEY"],
|
|
32
|
-
timeout_ms=30000,
|
|
33
|
-
max_retries=5,
|
|
34
|
-
retry_delay_ms=500,
|
|
35
|
-
)
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
def demo_comic_create_get_wait(client: LlamaGenClient) -> str:
|
|
39
|
-
created = client.comic.create(
|
|
40
|
-
{
|
|
41
|
-
"prompt": "A 4-panel comic about Leo finding a glowing key in a quiet library.",
|
|
42
|
-
"style": "manga",
|
|
43
|
-
"fixPanelNum": 4,
|
|
44
|
-
}
|
|
45
|
-
)
|
|
46
|
-
print("comic.create:", created["id"], created.get("status"))
|
|
47
|
-
|
|
48
|
-
fetched = client.comic.get(created["id"])
|
|
49
|
-
print("comic.get:", fetched["id"], fetched.get("status"))
|
|
50
|
-
|
|
51
|
-
panel = client.comic.get(created["id"], page=0, panel=0)
|
|
52
|
-
print("comic.get panel:", panel.get("id", created["id"]), panel.get("status"))
|
|
53
|
-
|
|
54
|
-
done = client.comic.wait_for_completion(created["id"], timeout_ms=WAIT_TIMEOUT_MS)
|
|
55
|
-
print("comic.wait_for_completion:", done["id"], done.get("status"), done.get("comics"))
|
|
56
|
-
return created["id"]
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
def demo_comic_usage(client: LlamaGenClient) -> None:
|
|
60
|
-
usage = client.comic.usage()
|
|
61
|
-
print("comic.usage:", usage)
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
def demo_comic_upload(client: LlamaGenClient, image_path: Path) -> str:
|
|
65
|
-
uploaded = client.comic.upload(image_path)
|
|
66
|
-
print("comic.upload:", uploaded)
|
|
67
|
-
return str(uploaded.get("url") or uploaded.get("fileUrl") or uploaded.get("id") or "")
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
def demo_comic_continue_write(client: LlamaGenClient, comic_id: str) -> str:
|
|
71
|
-
continued = client.comic.continue_write(
|
|
72
|
-
comic_id,
|
|
73
|
-
{
|
|
74
|
-
"prompt": "Continue the story with Leo opening a secret reading room.",
|
|
75
|
-
"pagination": {"totalPages": 1, "panelsPerPage": 4},
|
|
76
|
-
},
|
|
77
|
-
)
|
|
78
|
-
print("comic.continue_write:", continued["id"], continued.get("status"))
|
|
79
|
-
return continued["id"]
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
def demo_comic_update_panel(client: LlamaGenClient, comic_id: str) -> str:
|
|
83
|
-
updated = client.comic.update_panel(
|
|
84
|
-
comic_id,
|
|
85
|
-
{
|
|
86
|
-
"panelIndex": 0,
|
|
87
|
-
"prompt": "Make the glowing key brighter and add dramatic moonlight.",
|
|
88
|
-
},
|
|
89
|
-
)
|
|
90
|
-
print("comic.update_panel:", updated["id"], updated.get("status"))
|
|
91
|
-
return updated["id"]
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
def demo_comic_create_and_wait(client: LlamaGenClient) -> str:
|
|
95
|
-
done = client.comic.create_and_wait(
|
|
96
|
-
{
|
|
97
|
-
"prompt": "A cozy 3-panel comic about a robot learning to bake bread.",
|
|
98
|
-
"style": "storybook",
|
|
99
|
-
"fixPanelNum": 3,
|
|
100
|
-
},
|
|
101
|
-
timeout_ms=WAIT_TIMEOUT_MS,
|
|
102
|
-
)
|
|
103
|
-
print("comic.create_and_wait:", done["id"], done.get("status"))
|
|
104
|
-
return done["id"]
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
def demo_animation_create_get_wait(client: LlamaGenClient) -> str:
|
|
108
|
-
created = client.animation.create(
|
|
109
|
-
{
|
|
110
|
-
"prompt": "A heroic fox detective walks through neon rain, cinematic camera move.",
|
|
111
|
-
"videoOptions": {
|
|
112
|
-
"duration": 5,
|
|
113
|
-
"resolution": "720p",
|
|
114
|
-
"aspect_ratio": "16:9",
|
|
115
|
-
},
|
|
116
|
-
}
|
|
117
|
-
)
|
|
118
|
-
print("animation.create:", created["id"], created.get("status"))
|
|
119
|
-
|
|
120
|
-
fetched = client.animation.get(created["id"])
|
|
121
|
-
print("animation.get:", fetched["id"], fetched.get("status"))
|
|
122
|
-
|
|
123
|
-
done = client.animation.wait_for_completion(created["id"], timeout_ms=WAIT_TIMEOUT_MS)
|
|
124
|
-
print("animation.wait_for_completion:", done["id"], done.get("status"))
|
|
125
|
-
return created["id"]
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
def demo_animation_create_and_wait(client: LlamaGenClient) -> str:
|
|
129
|
-
done = client.animation.create_and_wait(
|
|
130
|
-
{
|
|
131
|
-
"prompt": "A paper boat sailing across a watercolor city at sunrise.",
|
|
132
|
-
"videoOptions": {
|
|
133
|
-
"duration": 5,
|
|
134
|
-
"resolution": "720p",
|
|
135
|
-
"aspect_ratio": "16:9",
|
|
136
|
-
},
|
|
137
|
-
},
|
|
138
|
-
timeout_ms=WAIT_TIMEOUT_MS,
|
|
139
|
-
)
|
|
140
|
-
print("animation.create_and_wait:", done["id"], done.get("status"))
|
|
141
|
-
return done["id"]
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
def main() -> None:
|
|
145
|
-
client = make_client()
|
|
146
|
-
|
|
147
|
-
comic_id = demo_comic_create_get_wait(client)
|
|
148
|
-
demo_comic_usage(client)
|
|
149
|
-
|
|
150
|
-
upload_file = os.environ.get("LLAMAGEN_UPLOAD_FILE")
|
|
151
|
-
if upload_file:
|
|
152
|
-
demo_comic_upload(client, Path(upload_file))
|
|
153
|
-
|
|
154
|
-
if os.environ.get("LLAMAGEN_RUN_OPTIONAL_DEMOS") == "1":
|
|
155
|
-
demo_comic_continue_write(client, comic_id)
|
|
156
|
-
demo_comic_update_panel(client, comic_id)
|
|
157
|
-
demo_comic_create_and_wait(client)
|
|
158
|
-
|
|
159
|
-
demo_animation_create_get_wait(client)
|
|
160
|
-
demo_animation_create_and_wait(client)
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
if __name__ == "__main__":
|
|
164
|
-
try:
|
|
165
|
-
main()
|
|
166
|
-
except LlamaGenAPIError as error:
|
|
167
|
-
print("LlamaGen API error:", error)
|
|
168
|
-
except LlamaGenConnectionError as error:
|
|
169
|
-
print("LlamaGen connection error:", error)
|
|
170
|
-
except LlamaGenTimeoutError as error:
|
|
171
|
-
print("LlamaGen timeout:", error)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|