llamagen-python 0.1.7__tar.gz → 0.1.9__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.9}/PKG-INFO +26 -10
- {llamagen_python-0.1.7 → llamagen_python-0.1.9}/README.md +25 -9
- llamagen_python-0.1.9/examples/quickstart.py +279 -0
- {llamagen_python-0.1.7 → llamagen_python-0.1.9}/pyproject.toml +1 -1
- {llamagen_python-0.1.7 → llamagen_python-0.1.9}/src/llamagen/__init__.py +1 -1
- {llamagen_python-0.1.7 → llamagen_python-0.1.9}/src/llamagen/_http.py +1 -1
- {llamagen_python-0.1.7 → llamagen_python-0.1.9}/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.9}/.gitignore +0 -0
- {llamagen_python-0.1.7 → llamagen_python-0.1.9}/LICENSE +0 -0
- {llamagen_python-0.1.7 → llamagen_python-0.1.9}/docs/RELEASE.md +0 -0
- {llamagen_python-0.1.7 → llamagen_python-0.1.9}/src/llamagen/_client.py +0 -0
- {llamagen_python-0.1.7 → llamagen_python-0.1.9}/src/llamagen/_errors.py +0 -0
- {llamagen_python-0.1.7 → llamagen_python-0.1.9}/src/llamagen/_types.py +0 -0
- {llamagen_python-0.1.7 → llamagen_python-0.1.9}/src/llamagen/py.typed +0 -0
- {llamagen_python-0.1.7 → llamagen_python-0.1.9}/src/llamagen/resources/__init__.py +0 -0
- {llamagen_python-0.1.7 → llamagen_python-0.1.9}/src/llamagen/resources/animations.py +0 -0
- {llamagen_python-0.1.7 → llamagen_python-0.1.9}/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.9
|
|
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,12 @@ 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
|
+
All Python examples below are self-contained for copy/paste usage in your own
|
|
85
|
+
script, notebook, worker, or backend service. Replace `YOUR_COMIC_ID` or
|
|
86
|
+
`YOUR_ANIMATION_ID` with an existing generation ID when an example fetches,
|
|
87
|
+
waits for, continues, or updates an existing job.
|
|
81
88
|
|
|
82
|
-
## Client
|
|
89
|
+
## Configure The Client
|
|
83
90
|
|
|
84
91
|
```python
|
|
85
92
|
from llamagen import LlamaGenClient
|
|
@@ -101,6 +108,8 @@ dependencies.
|
|
|
101
108
|
Use `llamagen.comic` to create comics, manga, webtoons, storyboards,
|
|
102
109
|
consistent-character pages, and panel edits.
|
|
103
110
|
|
|
111
|
+
Create with advanced options:
|
|
112
|
+
|
|
104
113
|
```python
|
|
105
114
|
import os
|
|
106
115
|
|
|
@@ -271,14 +280,15 @@ from llamagen import LlamaGenClient
|
|
|
271
280
|
|
|
272
281
|
client = LlamaGenClient(api_key=os.environ["LLAMAGEN_API_KEY"])
|
|
273
282
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
print("comic.upload:", uploaded)
|
|
283
|
+
image_path = Path("reference.png")
|
|
284
|
+
uploaded = client.comic.upload(image_path)
|
|
285
|
+
print("comic.upload:", uploaded)
|
|
278
286
|
```
|
|
279
287
|
|
|
280
288
|
## Animation API
|
|
281
289
|
|
|
290
|
+
Create an animation job and wait for completion:
|
|
291
|
+
|
|
282
292
|
```python
|
|
283
293
|
import os
|
|
284
294
|
|
|
@@ -294,12 +304,14 @@ video = client.animation.create({
|
|
|
294
304
|
"aspect_ratio": "16:9",
|
|
295
305
|
},
|
|
296
306
|
})
|
|
307
|
+
print("animation.create:", video["id"], video.get("status"))
|
|
297
308
|
|
|
298
309
|
finished = client.animation.wait_for_completion(
|
|
299
310
|
video["id"],
|
|
300
311
|
interval_ms=5000,
|
|
301
312
|
timeout_ms=30 * 60 * 1000,
|
|
302
313
|
)
|
|
314
|
+
print("animation.wait_for_completion:", finished["id"], finished.get("status"))
|
|
303
315
|
```
|
|
304
316
|
|
|
305
317
|
Animation methods:
|
|
@@ -311,6 +323,8 @@ Animation methods:
|
|
|
311
323
|
|
|
312
324
|
Animation examples:
|
|
313
325
|
|
|
326
|
+
Create an animation job:
|
|
327
|
+
|
|
314
328
|
```python
|
|
315
329
|
import os
|
|
316
330
|
|
|
@@ -327,7 +341,6 @@ video = client.animation.create({
|
|
|
327
341
|
},
|
|
328
342
|
})
|
|
329
343
|
print("animation.create:", video["id"], video.get("status"))
|
|
330
|
-
|
|
331
344
|
```
|
|
332
345
|
|
|
333
346
|
Fetch and wait for an animation:
|
|
@@ -369,10 +382,13 @@ finished = client.animation.create_and_wait({
|
|
|
369
382
|
},
|
|
370
383
|
}, timeout_ms=WAIT_TIMEOUT_MS)
|
|
371
384
|
print("animation.create_and_wait:", finished["id"], finished.get("status"))
|
|
372
|
-
|
|
373
385
|
```
|
|
374
386
|
|
|
375
|
-
##
|
|
387
|
+
## Error Handling
|
|
388
|
+
|
|
389
|
+
API errors include the HTTP status, parsed server response, and a readable
|
|
390
|
+
message. For example, a `429` response can include an error code and message
|
|
391
|
+
such as insufficient credits.
|
|
376
392
|
|
|
377
393
|
```python
|
|
378
394
|
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,12 @@ 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
|
+
All Python examples below are self-contained for copy/paste usage in your own
|
|
60
|
+
script, notebook, worker, or backend service. Replace `YOUR_COMIC_ID` or
|
|
61
|
+
`YOUR_ANIMATION_ID` with an existing generation ID when an example fetches,
|
|
62
|
+
waits for, continues, or updates an existing job.
|
|
56
63
|
|
|
57
|
-
## Client
|
|
64
|
+
## Configure The Client
|
|
58
65
|
|
|
59
66
|
```python
|
|
60
67
|
from llamagen import LlamaGenClient
|
|
@@ -76,6 +83,8 @@ dependencies.
|
|
|
76
83
|
Use `llamagen.comic` to create comics, manga, webtoons, storyboards,
|
|
77
84
|
consistent-character pages, and panel edits.
|
|
78
85
|
|
|
86
|
+
Create with advanced options:
|
|
87
|
+
|
|
79
88
|
```python
|
|
80
89
|
import os
|
|
81
90
|
|
|
@@ -246,14 +255,15 @@ from llamagen import LlamaGenClient
|
|
|
246
255
|
|
|
247
256
|
client = LlamaGenClient(api_key=os.environ["LLAMAGEN_API_KEY"])
|
|
248
257
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
print("comic.upload:", uploaded)
|
|
258
|
+
image_path = Path("reference.png")
|
|
259
|
+
uploaded = client.comic.upload(image_path)
|
|
260
|
+
print("comic.upload:", uploaded)
|
|
253
261
|
```
|
|
254
262
|
|
|
255
263
|
## Animation API
|
|
256
264
|
|
|
265
|
+
Create an animation job and wait for completion:
|
|
266
|
+
|
|
257
267
|
```python
|
|
258
268
|
import os
|
|
259
269
|
|
|
@@ -269,12 +279,14 @@ video = client.animation.create({
|
|
|
269
279
|
"aspect_ratio": "16:9",
|
|
270
280
|
},
|
|
271
281
|
})
|
|
282
|
+
print("animation.create:", video["id"], video.get("status"))
|
|
272
283
|
|
|
273
284
|
finished = client.animation.wait_for_completion(
|
|
274
285
|
video["id"],
|
|
275
286
|
interval_ms=5000,
|
|
276
287
|
timeout_ms=30 * 60 * 1000,
|
|
277
288
|
)
|
|
289
|
+
print("animation.wait_for_completion:", finished["id"], finished.get("status"))
|
|
278
290
|
```
|
|
279
291
|
|
|
280
292
|
Animation methods:
|
|
@@ -286,6 +298,8 @@ Animation methods:
|
|
|
286
298
|
|
|
287
299
|
Animation examples:
|
|
288
300
|
|
|
301
|
+
Create an animation job:
|
|
302
|
+
|
|
289
303
|
```python
|
|
290
304
|
import os
|
|
291
305
|
|
|
@@ -302,7 +316,6 @@ video = client.animation.create({
|
|
|
302
316
|
},
|
|
303
317
|
})
|
|
304
318
|
print("animation.create:", video["id"], video.get("status"))
|
|
305
|
-
|
|
306
319
|
```
|
|
307
320
|
|
|
308
321
|
Fetch and wait for an animation:
|
|
@@ -344,10 +357,13 @@ finished = client.animation.create_and_wait({
|
|
|
344
357
|
},
|
|
345
358
|
}, timeout_ms=WAIT_TIMEOUT_MS)
|
|
346
359
|
print("animation.create_and_wait:", finished["id"], finished.get("status"))
|
|
347
|
-
|
|
348
360
|
```
|
|
349
361
|
|
|
350
|
-
##
|
|
362
|
+
## Error Handling
|
|
363
|
+
|
|
364
|
+
API errors include the HTTP status, parsed server response, and a readable
|
|
365
|
+
message. For example, a `429` response can include an error code and message
|
|
366
|
+
such as insufficient credits.
|
|
351
367
|
|
|
352
368
|
```python
|
|
353
369
|
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.9"
|
|
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.9")
|
|
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
|