kavel 0.1.0__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.
- kavel-0.1.0/PKG-INFO +83 -0
- kavel-0.1.0/README.md +64 -0
- kavel-0.1.0/pyproject.toml +29 -0
- kavel-0.1.0/setup.cfg +4 -0
- kavel-0.1.0/src/kavel/__init__.py +132 -0
- kavel-0.1.0/src/kavel.egg-info/PKG-INFO +83 -0
- kavel-0.1.0/src/kavel.egg-info/SOURCES.txt +7 -0
- kavel-0.1.0/src/kavel.egg-info/dependency_links.txt +1 -0
- kavel-0.1.0/src/kavel.egg-info/top_level.txt +1 -0
kavel-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: kavel
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Generate images from a prompt with no API key and no account
|
|
5
|
+
Author: hanshs474
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://www.kavel.ai/?ref=pypi
|
|
8
|
+
Project-URL: Image tools, https://www.kavel.ai/image?ref=pypi
|
|
9
|
+
Project-URL: Video tools, https://www.kavel.ai/video?ref=pypi
|
|
10
|
+
Project-URL: Source, https://github.com/hanshs474/kavel-image-skill
|
|
11
|
+
Keywords: ai,image-generation,text-to-image,image-editing,no-api-key
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Topic :: Multimedia :: Graphics
|
|
17
|
+
Requires-Python: >=3.8
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
|
|
20
|
+
# kavel
|
|
21
|
+
|
|
22
|
+
Generate images from a prompt with **no API key and no account**.
|
|
23
|
+
|
|
24
|
+
```python
|
|
25
|
+
from kavel import generate
|
|
26
|
+
|
|
27
|
+
url = generate("a paper-cut layered mountain range at dusk, warm rim light")
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
That is the whole setup. No key to fetch, no config file, no dependencies —
|
|
31
|
+
standard library only. It calls the anonymous endpoint on
|
|
32
|
+
[Kavel](https://www.kavel.ai/?ref=pypi), an online AI image and video studio.
|
|
33
|
+
|
|
34
|
+
## Editing a photo
|
|
35
|
+
|
|
36
|
+
Pass `image_url` and the prompt describes the change rather than the picture:
|
|
37
|
+
|
|
38
|
+
```python
|
|
39
|
+
url = generate(
|
|
40
|
+
"restyle the hair into a shoulder-length layered cut, "
|
|
41
|
+
"keep the same face, skin and lighting",
|
|
42
|
+
image_url="https://example.com/portrait.jpg",
|
|
43
|
+
)
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Naming what must stay is what holds the likeness. Prompts that only name the
|
|
47
|
+
edit tend to drift the whole face.
|
|
48
|
+
|
|
49
|
+
## What the free tier actually covers
|
|
50
|
+
|
|
51
|
+
| | |
|
|
52
|
+
|---|---|
|
|
53
|
+
| Anonymous grant | 15 credits |
|
|
54
|
+
| Text-to-image | 5 credits — so the grant covers two |
|
|
55
|
+
| Photo edit (`nano-banana-2-lite`) | 15 credits — exactly one |
|
|
56
|
+
| Per-IP ceiling | 30 credits a day |
|
|
57
|
+
|
|
58
|
+
Anonymous output is 1K and watermarked. Signing in on
|
|
59
|
+
[kavel.ai](https://www.kavel.ai/?ref=pypi) removes the watermark and opens the
|
|
60
|
+
larger models.
|
|
61
|
+
|
|
62
|
+
**Video is deliberately not exposed here.** The cheapest clip is 40 credits
|
|
63
|
+
against a 15-credit anonymous wallet, so a signed-out call cannot succeed at
|
|
64
|
+
any setting. Signed-out video on the site runs on a browser-side engine
|
|
65
|
+
instead — see [the video tools](https://www.kavel.ai/video?ref=pypi).
|
|
66
|
+
|
|
67
|
+
## Errors worth catching
|
|
68
|
+
|
|
69
|
+
`KavelError` covers the three things that actually happen:
|
|
70
|
+
|
|
71
|
+
- the content filter refused the prompt (credits are spent either way, so
|
|
72
|
+
rewrite rather than retry)
|
|
73
|
+
- the queue ran past `timeout`
|
|
74
|
+
- the per-IP daily ceiling returned 429
|
|
75
|
+
|
|
76
|
+
## Prompts that work
|
|
77
|
+
|
|
78
|
+
Kavel keeps a page per edit, each preloaded with a prompt for that specific
|
|
79
|
+
job — [hairstyle](https://www.kavel.ai/image/ai-hairstyle-changer?ref=pypi),
|
|
80
|
+
[outfit](https://www.kavel.ai/image/ai-outfit-generator?ref=pypi),
|
|
81
|
+
and the rest under [image tools](https://www.kavel.ai/image?ref=pypi).
|
|
82
|
+
|
|
83
|
+
MIT licensed.
|
kavel-0.1.0/README.md
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# kavel
|
|
2
|
+
|
|
3
|
+
Generate images from a prompt with **no API key and no account**.
|
|
4
|
+
|
|
5
|
+
```python
|
|
6
|
+
from kavel import generate
|
|
7
|
+
|
|
8
|
+
url = generate("a paper-cut layered mountain range at dusk, warm rim light")
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
That is the whole setup. No key to fetch, no config file, no dependencies —
|
|
12
|
+
standard library only. It calls the anonymous endpoint on
|
|
13
|
+
[Kavel](https://www.kavel.ai/?ref=pypi), an online AI image and video studio.
|
|
14
|
+
|
|
15
|
+
## Editing a photo
|
|
16
|
+
|
|
17
|
+
Pass `image_url` and the prompt describes the change rather than the picture:
|
|
18
|
+
|
|
19
|
+
```python
|
|
20
|
+
url = generate(
|
|
21
|
+
"restyle the hair into a shoulder-length layered cut, "
|
|
22
|
+
"keep the same face, skin and lighting",
|
|
23
|
+
image_url="https://example.com/portrait.jpg",
|
|
24
|
+
)
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Naming what must stay is what holds the likeness. Prompts that only name the
|
|
28
|
+
edit tend to drift the whole face.
|
|
29
|
+
|
|
30
|
+
## What the free tier actually covers
|
|
31
|
+
|
|
32
|
+
| | |
|
|
33
|
+
|---|---|
|
|
34
|
+
| Anonymous grant | 15 credits |
|
|
35
|
+
| Text-to-image | 5 credits — so the grant covers two |
|
|
36
|
+
| Photo edit (`nano-banana-2-lite`) | 15 credits — exactly one |
|
|
37
|
+
| Per-IP ceiling | 30 credits a day |
|
|
38
|
+
|
|
39
|
+
Anonymous output is 1K and watermarked. Signing in on
|
|
40
|
+
[kavel.ai](https://www.kavel.ai/?ref=pypi) removes the watermark and opens the
|
|
41
|
+
larger models.
|
|
42
|
+
|
|
43
|
+
**Video is deliberately not exposed here.** The cheapest clip is 40 credits
|
|
44
|
+
against a 15-credit anonymous wallet, so a signed-out call cannot succeed at
|
|
45
|
+
any setting. Signed-out video on the site runs on a browser-side engine
|
|
46
|
+
instead — see [the video tools](https://www.kavel.ai/video?ref=pypi).
|
|
47
|
+
|
|
48
|
+
## Errors worth catching
|
|
49
|
+
|
|
50
|
+
`KavelError` covers the three things that actually happen:
|
|
51
|
+
|
|
52
|
+
- the content filter refused the prompt (credits are spent either way, so
|
|
53
|
+
rewrite rather than retry)
|
|
54
|
+
- the queue ran past `timeout`
|
|
55
|
+
- the per-IP daily ceiling returned 429
|
|
56
|
+
|
|
57
|
+
## Prompts that work
|
|
58
|
+
|
|
59
|
+
Kavel keeps a page per edit, each preloaded with a prompt for that specific
|
|
60
|
+
job — [hairstyle](https://www.kavel.ai/image/ai-hairstyle-changer?ref=pypi),
|
|
61
|
+
[outfit](https://www.kavel.ai/image/ai-outfit-generator?ref=pypi),
|
|
62
|
+
and the rest under [image tools](https://www.kavel.ai/image?ref=pypi).
|
|
63
|
+
|
|
64
|
+
MIT licensed.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "kavel"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Generate images from a prompt with no API key and no account"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.8"
|
|
11
|
+
license = { text = "MIT" }
|
|
12
|
+
authors = [{ name = "hanshs474" }]
|
|
13
|
+
keywords = ["ai", "image-generation", "text-to-image", "image-editing", "no-api-key"]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Development Status :: 4 - Beta",
|
|
16
|
+
"Intended Audience :: Developers",
|
|
17
|
+
"License :: OSI Approved :: MIT License",
|
|
18
|
+
"Programming Language :: Python :: 3",
|
|
19
|
+
"Topic :: Multimedia :: Graphics",
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
[project.urls]
|
|
23
|
+
Homepage = "https://www.kavel.ai/?ref=pypi"
|
|
24
|
+
"Image tools" = "https://www.kavel.ai/image?ref=pypi"
|
|
25
|
+
"Video tools" = "https://www.kavel.ai/video?ref=pypi"
|
|
26
|
+
Source = "https://github.com/hanshs474/kavel-image-skill"
|
|
27
|
+
|
|
28
|
+
[tool.setuptools.packages.find]
|
|
29
|
+
where = ["src"]
|
kavel-0.1.0/setup.cfg
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"""Generate images from a prompt with no API key and no account.
|
|
2
|
+
|
|
3
|
+
Calls the anonymous endpoint on kavel.ai — https://www.kavel.ai/?ref=pypi
|
|
4
|
+
|
|
5
|
+
from kavel import generate
|
|
6
|
+
url = generate("a paper-cut layered mountain range at dusk")
|
|
7
|
+
|
|
8
|
+
Standard library only. No dependencies, no configuration.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import json
|
|
14
|
+
import time
|
|
15
|
+
import urllib.error
|
|
16
|
+
import urllib.request
|
|
17
|
+
import uuid
|
|
18
|
+
|
|
19
|
+
__version__ = "0.1.0"
|
|
20
|
+
__all__ = ["generate", "KavelError", "BASE"]
|
|
21
|
+
|
|
22
|
+
BASE = "https://www.kavel.ai"
|
|
23
|
+
|
|
24
|
+
#: Anonymous wallet, measured against the live site on 2026-09-04.
|
|
25
|
+
#: A text-to-image run costs 5 of the 15 credits a fresh visitor is granted;
|
|
26
|
+
#: an edit (``nano-banana-2-lite``) costs all 15. There is also a per-IP
|
|
27
|
+
#: ceiling of 30 credits a day. Video cannot be paid for anonymously at any
|
|
28
|
+
#: setting, which is why this module does not expose it.
|
|
29
|
+
ANON_GRANT = 15
|
|
30
|
+
COST_TEXT_TO_IMAGE = 5
|
|
31
|
+
COST_EDIT = 15
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class KavelError(RuntimeError):
|
|
35
|
+
"""Raised when a generation is refused, times out, or comes back empty."""
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def _post(path: str, payload: dict, anon: str) -> dict:
|
|
39
|
+
req = urllib.request.Request(
|
|
40
|
+
BASE + path,
|
|
41
|
+
data=json.dumps(payload).encode(),
|
|
42
|
+
headers={
|
|
43
|
+
"Content-Type": "application/json",
|
|
44
|
+
"x-anon-id": anon,
|
|
45
|
+
"User-Agent": f"kavel-python/{__version__}",
|
|
46
|
+
},
|
|
47
|
+
)
|
|
48
|
+
try:
|
|
49
|
+
with urllib.request.urlopen(req, timeout=60) as r:
|
|
50
|
+
return json.loads(r.read())
|
|
51
|
+
except urllib.error.HTTPError as e:
|
|
52
|
+
if e.code == 429:
|
|
53
|
+
raise KavelError(
|
|
54
|
+
"per-IP daily ceiling reached (30 credits); wait or sign in"
|
|
55
|
+
) from e
|
|
56
|
+
raise KavelError(f"HTTP {e.code}: {e.read()[:200]!r}") from e
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def _get(path: str, anon: str) -> dict:
|
|
60
|
+
req = urllib.request.Request(
|
|
61
|
+
BASE + path,
|
|
62
|
+
headers={"x-anon-id": anon, "User-Agent": f"kavel-python/{__version__}"},
|
|
63
|
+
)
|
|
64
|
+
with urllib.request.urlopen(req, timeout=60) as r:
|
|
65
|
+
return json.loads(r.read())
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def generate(
|
|
69
|
+
prompt: str,
|
|
70
|
+
*,
|
|
71
|
+
aspect_ratio: str = "1:1",
|
|
72
|
+
image_url: str | None = None,
|
|
73
|
+
timeout: float = 240.0,
|
|
74
|
+
poll_every: float = 4.0,
|
|
75
|
+
) -> str:
|
|
76
|
+
"""Generate one image and return its CDN URL.
|
|
77
|
+
|
|
78
|
+
``prompt`` describes the picture. Pass ``image_url`` to edit an existing
|
|
79
|
+
photo instead of generating from scratch — the prompt then describes the
|
|
80
|
+
change and should name what must stay ("keep the same face and lighting"),
|
|
81
|
+
because anything left unsaid is fair game for the model.
|
|
82
|
+
|
|
83
|
+
Editing runs on ``nano-banana-2-lite`` and costs the whole anonymous grant,
|
|
84
|
+
so a signed-out caller gets one edit. Text-to-image runs on
|
|
85
|
+
``kavel-image-v1``, which takes no image input.
|
|
86
|
+
|
|
87
|
+
Raises :class:`KavelError` on refusal, timeout, or an empty result.
|
|
88
|
+
"""
|
|
89
|
+
anon = f"anon-{uuid.uuid4()}"
|
|
90
|
+
model = "nano-banana-2-lite" if image_url else "kavel-image-v1"
|
|
91
|
+
scene = "image-to-image" if image_url else "text-to-image"
|
|
92
|
+
options: dict = {"aspect_ratio": aspect_ratio}
|
|
93
|
+
if image_url:
|
|
94
|
+
options["imageUrl"] = image_url
|
|
95
|
+
|
|
96
|
+
submitted = _post(
|
|
97
|
+
"/api/ai/generate",
|
|
98
|
+
{
|
|
99
|
+
"provider": "kie",
|
|
100
|
+
"mediaType": "image",
|
|
101
|
+
"model": model,
|
|
102
|
+
"scene": scene,
|
|
103
|
+
"prompt": prompt,
|
|
104
|
+
"options": options,
|
|
105
|
+
},
|
|
106
|
+
anon,
|
|
107
|
+
)
|
|
108
|
+
task_id = (submitted.get("data") or {}).get("id")
|
|
109
|
+
if not task_id:
|
|
110
|
+
raise KavelError(f"no task id in response: {str(submitted)[:200]}")
|
|
111
|
+
|
|
112
|
+
deadline = time.monotonic() + timeout
|
|
113
|
+
while time.monotonic() < deadline:
|
|
114
|
+
time.sleep(poll_every)
|
|
115
|
+
data = _get(
|
|
116
|
+
f"/api/ai/anon-query?taskId={task_id}"
|
|
117
|
+
"&provider=kie&mediaType=image",
|
|
118
|
+
anon,
|
|
119
|
+
).get("data") or {}
|
|
120
|
+
images = data.get("images") or []
|
|
121
|
+
if images:
|
|
122
|
+
return images[0]
|
|
123
|
+
status = str(data.get("status") or "").lower()
|
|
124
|
+
if status in {"failed", "error"}:
|
|
125
|
+
# A finished task with no image is the content filter, and the
|
|
126
|
+
# credits are already spent — retrying the same text spends them
|
|
127
|
+
# again for the same answer.
|
|
128
|
+
raise KavelError(
|
|
129
|
+
"generation refused (content filter); rewrite the prompt "
|
|
130
|
+
"rather than retrying it"
|
|
131
|
+
)
|
|
132
|
+
raise KavelError(f"timed out after {timeout:g}s; the queue can run long")
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: kavel
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Generate images from a prompt with no API key and no account
|
|
5
|
+
Author: hanshs474
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://www.kavel.ai/?ref=pypi
|
|
8
|
+
Project-URL: Image tools, https://www.kavel.ai/image?ref=pypi
|
|
9
|
+
Project-URL: Video tools, https://www.kavel.ai/video?ref=pypi
|
|
10
|
+
Project-URL: Source, https://github.com/hanshs474/kavel-image-skill
|
|
11
|
+
Keywords: ai,image-generation,text-to-image,image-editing,no-api-key
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Topic :: Multimedia :: Graphics
|
|
17
|
+
Requires-Python: >=3.8
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
|
|
20
|
+
# kavel
|
|
21
|
+
|
|
22
|
+
Generate images from a prompt with **no API key and no account**.
|
|
23
|
+
|
|
24
|
+
```python
|
|
25
|
+
from kavel import generate
|
|
26
|
+
|
|
27
|
+
url = generate("a paper-cut layered mountain range at dusk, warm rim light")
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
That is the whole setup. No key to fetch, no config file, no dependencies —
|
|
31
|
+
standard library only. It calls the anonymous endpoint on
|
|
32
|
+
[Kavel](https://www.kavel.ai/?ref=pypi), an online AI image and video studio.
|
|
33
|
+
|
|
34
|
+
## Editing a photo
|
|
35
|
+
|
|
36
|
+
Pass `image_url` and the prompt describes the change rather than the picture:
|
|
37
|
+
|
|
38
|
+
```python
|
|
39
|
+
url = generate(
|
|
40
|
+
"restyle the hair into a shoulder-length layered cut, "
|
|
41
|
+
"keep the same face, skin and lighting",
|
|
42
|
+
image_url="https://example.com/portrait.jpg",
|
|
43
|
+
)
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Naming what must stay is what holds the likeness. Prompts that only name the
|
|
47
|
+
edit tend to drift the whole face.
|
|
48
|
+
|
|
49
|
+
## What the free tier actually covers
|
|
50
|
+
|
|
51
|
+
| | |
|
|
52
|
+
|---|---|
|
|
53
|
+
| Anonymous grant | 15 credits |
|
|
54
|
+
| Text-to-image | 5 credits — so the grant covers two |
|
|
55
|
+
| Photo edit (`nano-banana-2-lite`) | 15 credits — exactly one |
|
|
56
|
+
| Per-IP ceiling | 30 credits a day |
|
|
57
|
+
|
|
58
|
+
Anonymous output is 1K and watermarked. Signing in on
|
|
59
|
+
[kavel.ai](https://www.kavel.ai/?ref=pypi) removes the watermark and opens the
|
|
60
|
+
larger models.
|
|
61
|
+
|
|
62
|
+
**Video is deliberately not exposed here.** The cheapest clip is 40 credits
|
|
63
|
+
against a 15-credit anonymous wallet, so a signed-out call cannot succeed at
|
|
64
|
+
any setting. Signed-out video on the site runs on a browser-side engine
|
|
65
|
+
instead — see [the video tools](https://www.kavel.ai/video?ref=pypi).
|
|
66
|
+
|
|
67
|
+
## Errors worth catching
|
|
68
|
+
|
|
69
|
+
`KavelError` covers the three things that actually happen:
|
|
70
|
+
|
|
71
|
+
- the content filter refused the prompt (credits are spent either way, so
|
|
72
|
+
rewrite rather than retry)
|
|
73
|
+
- the queue ran past `timeout`
|
|
74
|
+
- the per-IP daily ceiling returned 429
|
|
75
|
+
|
|
76
|
+
## Prompts that work
|
|
77
|
+
|
|
78
|
+
Kavel keeps a page per edit, each preloaded with a prompt for that specific
|
|
79
|
+
job — [hairstyle](https://www.kavel.ai/image/ai-hairstyle-changer?ref=pypi),
|
|
80
|
+
[outfit](https://www.kavel.ai/image/ai-outfit-generator?ref=pypi),
|
|
81
|
+
and the rest under [image tools](https://www.kavel.ai/image?ref=pypi).
|
|
82
|
+
|
|
83
|
+
MIT licensed.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
kavel
|