runapi-seedream 0.1.0__tar.gz → 0.1.2__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.
- {runapi_seedream-0.1.0 → runapi_seedream-0.1.2}/PKG-INFO +25 -9
- {runapi_seedream-0.1.0 → runapi_seedream-0.1.2}/README.md +17 -5
- runapi_seedream-0.1.2/pyproject.toml +34 -0
- {runapi_seedream-0.1.0 → runapi_seedream-0.1.2}/src/runapi/seedream/contract_gen.py +93 -8
- {runapi_seedream-0.1.0 → runapi_seedream-0.1.2}/src/runapi/seedream/resources/edit_image.py +14 -13
- {runapi_seedream-0.1.0 → runapi_seedream-0.1.2}/src/runapi/seedream/resources/text_to_image.py +14 -13
- {runapi_seedream-0.1.0 → runapi_seedream-0.1.2}/src/runapi/seedream/types.py +4 -1
- {runapi_seedream-0.1.0 → runapi_seedream-0.1.2}/tests/test_client.py +76 -0
- runapi_seedream-0.1.0/pyproject.toml +0 -33
- {runapi_seedream-0.1.0 → runapi_seedream-0.1.2}/src/runapi/seedream/__init__.py +0 -0
- {runapi_seedream-0.1.0 → runapi_seedream-0.1.2}/src/runapi/seedream/client.py +0 -0
- {runapi_seedream-0.1.0 → runapi_seedream-0.1.2}/src/runapi/seedream/py.typed +0 -0
- {runapi_seedream-0.1.0 → runapi_seedream-0.1.2}/src/runapi/seedream/resources/__init__.py +0 -0
|
@@ -1,21 +1,25 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: runapi-seedream
|
|
3
|
-
Version: 0.1.
|
|
4
|
-
Summary: Seedream text-to-image and edit-image
|
|
3
|
+
Version: 0.1.2
|
|
4
|
+
Summary: RunAPI Seedream SDK for text-to-image and edit-image workflows in JavaScript, Python, Ruby, Go, Java, and PHP
|
|
5
5
|
Project-URL: Homepage, https://runapi.ai/models/seedream
|
|
6
6
|
Project-URL: Documentation, https://runapi.ai/docs#sdk-seedream
|
|
7
|
+
Project-URL: Source, https://github.com/runapi-ai/seedream-sdk
|
|
8
|
+
Project-URL: Issues, https://github.com/runapi-ai/seedream-sdk/issues
|
|
9
|
+
Project-URL: Changelog, https://github.com/runapi-ai/seedream-sdk/blob/main/CHANGELOG.md
|
|
10
|
+
Project-URL: Release Notes, https://github.com/runapi-ai/seedream-sdk/releases/tag/python%2Fv0.1.2
|
|
7
11
|
Author-email: RunAPI <contact@runapi.ai>
|
|
8
12
|
License-Expression: Apache-2.0
|
|
9
|
-
Keywords:
|
|
13
|
+
Keywords: api,golang,gradle,image-api,image-generation,java,maven,python,ruby,runapi,runapi-ai,sdk,seedream,seedream-api,text-to-image,typescript
|
|
10
14
|
Requires-Python: >=3.9
|
|
11
|
-
Requires-Dist: runapi-core
|
|
15
|
+
Requires-Dist: runapi-core>=0.2.1
|
|
12
16
|
Description-Content-Type: text/markdown
|
|
13
17
|
|
|
14
|
-
# Seedream
|
|
18
|
+
# Seedream Python SDK for RunAPI
|
|
15
19
|
|
|
16
|
-
The
|
|
20
|
+
The Seedream Python SDK is the language-specific package for Seedream on RunAPI. Use this package for image generation, image editing, and creative production workflows when your application needs request bodies, task status lookup, and consistent RunAPI errors in Python.
|
|
17
21
|
|
|
18
|
-
This
|
|
22
|
+
This README is the Python package guide inside the public `seedream-sdk` repository. For the repository overview, start at `../README.md`; for model details, use https://runapi.ai/models/seedream; for API reference, use https://runapi.ai/docs#seedream; for SDK docs, use https://runapi.ai/docs#sdk-seedream.
|
|
19
23
|
|
|
20
24
|
## Install
|
|
21
25
|
|
|
@@ -42,7 +46,15 @@ status = client.text_to_image.get(task.id)
|
|
|
42
46
|
edit = client.edit_image.create(
|
|
43
47
|
model="seedream-v4-edit",
|
|
44
48
|
prompt="Make it golden hour",
|
|
45
|
-
source_image_urls=["https://
|
|
49
|
+
source_image_urls=["https://cdn.runapi.ai/public/samples/image.jpg"],
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
lite = client.text_to_image.create(
|
|
53
|
+
model="seedream-5-lite-text-to-image",
|
|
54
|
+
prompt="A bright editorial photo of a modern bookstore cafe",
|
|
55
|
+
aspect_ratio="4:3",
|
|
56
|
+
output_quality="basic",
|
|
57
|
+
output_format="jpeg",
|
|
46
58
|
)
|
|
47
59
|
```
|
|
48
60
|
|
|
@@ -60,9 +72,13 @@ In web request handlers, prefer `create` plus webhook or later `get` polling so
|
|
|
60
72
|
|
|
61
73
|
RunAPI-generated file URLs are temporary. Download and store generated images, videos, audio, or other files in your own durable storage within 7 days; do not treat returned URLs as long-term assets.
|
|
62
74
|
|
|
75
|
+
## Seedream 5 Pro
|
|
76
|
+
|
|
77
|
+
Use `seedream-5-pro-text-to-image` for generation and `seedream-5-pro-edit` for image editing. Both accept `output_quality`, optional `output_format`, and optional content safety checking; editing accepts up to 10 source image URLs.
|
|
78
|
+
|
|
63
79
|
## Language notes
|
|
64
80
|
|
|
65
|
-
Pass parameters as keyword arguments and catch the `runapi.seedream` error classes when building image jobs or scripts. The available resources are `text_to_image`
|
|
81
|
+
Pass parameters as keyword arguments and catch the `runapi.seedream` error classes when building image jobs or scripts. The available resources are `text_to_image` and `edit_image`. Keep `RUNAPI_API_KEY` in the environment or your secret manager; never commit API keys or callback secrets.
|
|
66
82
|
|
|
67
83
|
## Links
|
|
68
84
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
# Seedream
|
|
1
|
+
# Seedream Python SDK for RunAPI
|
|
2
2
|
|
|
3
|
-
The
|
|
3
|
+
The Seedream Python SDK is the language-specific package for Seedream on RunAPI. Use this package for image generation, image editing, and creative production workflows when your application needs request bodies, task status lookup, and consistent RunAPI errors in Python.
|
|
4
4
|
|
|
5
|
-
This
|
|
5
|
+
This README is the Python package guide inside the public `seedream-sdk` repository. For the repository overview, start at `../README.md`; for model details, use https://runapi.ai/models/seedream; for API reference, use https://runapi.ai/docs#seedream; for SDK docs, use https://runapi.ai/docs#sdk-seedream.
|
|
6
6
|
|
|
7
7
|
## Install
|
|
8
8
|
|
|
@@ -29,7 +29,15 @@ status = client.text_to_image.get(task.id)
|
|
|
29
29
|
edit = client.edit_image.create(
|
|
30
30
|
model="seedream-v4-edit",
|
|
31
31
|
prompt="Make it golden hour",
|
|
32
|
-
source_image_urls=["https://
|
|
32
|
+
source_image_urls=["https://cdn.runapi.ai/public/samples/image.jpg"],
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
lite = client.text_to_image.create(
|
|
36
|
+
model="seedream-5-lite-text-to-image",
|
|
37
|
+
prompt="A bright editorial photo of a modern bookstore cafe",
|
|
38
|
+
aspect_ratio="4:3",
|
|
39
|
+
output_quality="basic",
|
|
40
|
+
output_format="jpeg",
|
|
33
41
|
)
|
|
34
42
|
```
|
|
35
43
|
|
|
@@ -47,9 +55,13 @@ In web request handlers, prefer `create` plus webhook or later `get` polling so
|
|
|
47
55
|
|
|
48
56
|
RunAPI-generated file URLs are temporary. Download and store generated images, videos, audio, or other files in your own durable storage within 7 days; do not treat returned URLs as long-term assets.
|
|
49
57
|
|
|
58
|
+
## Seedream 5 Pro
|
|
59
|
+
|
|
60
|
+
Use `seedream-5-pro-text-to-image` for generation and `seedream-5-pro-edit` for image editing. Both accept `output_quality`, optional `output_format`, and optional content safety checking; editing accepts up to 10 source image URLs.
|
|
61
|
+
|
|
50
62
|
## Language notes
|
|
51
63
|
|
|
52
|
-
Pass parameters as keyword arguments and catch the `runapi.seedream` error classes when building image jobs or scripts. The available resources are `text_to_image`
|
|
64
|
+
Pass parameters as keyword arguments and catch the `runapi.seedream` error classes when building image jobs or scripts. The available resources are `text_to_image` and `edit_image`. Keep `RUNAPI_API_KEY` in the environment or your secret manager; never commit API keys or callback secrets.
|
|
53
65
|
|
|
54
66
|
## Links
|
|
55
67
|
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "runapi-seedream"
|
|
7
|
+
version = "0.1.2"
|
|
8
|
+
description = "RunAPI Seedream SDK for text-to-image and edit-image workflows in JavaScript, Python, Ruby, Go, Java, and PHP"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.9"
|
|
11
|
+
license = "Apache-2.0"
|
|
12
|
+
authors = [{ name = "RunAPI", email = "contact@runapi.ai" }]
|
|
13
|
+
keywords = ["runapi", "runapi-ai", "seedream", "api", "sdk", "typescript", "python", "ruby", "golang", "java", "maven", "gradle", "image-generation", "text-to-image", "image-api", "seedream-api"]
|
|
14
|
+
dependencies = ["runapi-core>=0.2.1"]
|
|
15
|
+
|
|
16
|
+
[project.urls]
|
|
17
|
+
Homepage = "https://runapi.ai/models/seedream"
|
|
18
|
+
Documentation = "https://runapi.ai/docs#sdk-seedream"
|
|
19
|
+
Source = "https://github.com/runapi-ai/seedream-sdk"
|
|
20
|
+
Issues = "https://github.com/runapi-ai/seedream-sdk/issues"
|
|
21
|
+
Changelog = "https://github.com/runapi-ai/seedream-sdk/blob/main/CHANGELOG.md"
|
|
22
|
+
"Release Notes" = "https://github.com/runapi-ai/seedream-sdk/releases/tag/python%2Fv0.1.2"
|
|
23
|
+
|
|
24
|
+
[tool.hatch.build.targets.wheel]
|
|
25
|
+
packages = ["src/runapi"]
|
|
26
|
+
|
|
27
|
+
[tool.uv]
|
|
28
|
+
package = true
|
|
29
|
+
|
|
30
|
+
[dependency-groups]
|
|
31
|
+
dev = ["pytest>=8"]
|
|
32
|
+
|
|
33
|
+
[tool.runapi]
|
|
34
|
+
slug = "seedream"
|
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
# Code generated by SdkContractGenerator. DO NOT EDIT.
|
|
2
|
-
|
|
3
1
|
CONTRACT = {
|
|
4
2
|
"edit-image": {
|
|
5
|
-
"models": ["seedream-4.5-edit", "seedream-5-lite-edit", "seedream-v4-edit"],
|
|
3
|
+
"models": ["seedream-4.5-edit", "seedream-5-lite-edit", "seedream-5-pro-edit", "seedream-v4-edit"],
|
|
6
4
|
"fields_by_model": {
|
|
7
5
|
"seedream-4.5-edit": {
|
|
8
6
|
"aspect_ratio": {
|
|
@@ -20,7 +18,9 @@ CONTRACT = {
|
|
|
20
18
|
"type": "integer"
|
|
21
19
|
},
|
|
22
20
|
"source_image_urls": {
|
|
23
|
-
"required": True
|
|
21
|
+
"required": True,
|
|
22
|
+
"min_items": 1,
|
|
23
|
+
"max_items": 14
|
|
24
24
|
}
|
|
25
25
|
},
|
|
26
26
|
"seedream-5-lite-edit": {
|
|
@@ -31,6 +31,9 @@ CONTRACT = {
|
|
|
31
31
|
"output_count": {
|
|
32
32
|
"type": "integer"
|
|
33
33
|
},
|
|
34
|
+
"output_format": {
|
|
35
|
+
"enum": ["png", "jpeg"]
|
|
36
|
+
},
|
|
34
37
|
"output_quality": {
|
|
35
38
|
"enum": ["basic", "high"],
|
|
36
39
|
"required": True
|
|
@@ -39,7 +42,33 @@ CONTRACT = {
|
|
|
39
42
|
"type": "integer"
|
|
40
43
|
},
|
|
41
44
|
"source_image_urls": {
|
|
45
|
+
"required": True,
|
|
46
|
+
"min_items": 1,
|
|
47
|
+
"max_items": 14
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
"seedream-5-pro-edit": {
|
|
51
|
+
"aspect_ratio": {
|
|
52
|
+
"enum": ["1:1", "4:3", "3:4", "16:9", "9:16", "2:3", "3:2", "21:9"],
|
|
42
53
|
"required": True
|
|
54
|
+
},
|
|
55
|
+
"output_format": {
|
|
56
|
+
"enum": ["png", "jpeg"]
|
|
57
|
+
},
|
|
58
|
+
"output_quality": {
|
|
59
|
+
"enum": ["basic", "high"],
|
|
60
|
+
"required": True
|
|
61
|
+
},
|
|
62
|
+
"prompt": {
|
|
63
|
+
"required": True,
|
|
64
|
+
"min": 3,
|
|
65
|
+
"max": 5000,
|
|
66
|
+
"length": True
|
|
67
|
+
},
|
|
68
|
+
"source_image_urls": {
|
|
69
|
+
"required": True,
|
|
70
|
+
"min_items": 1,
|
|
71
|
+
"max_items": 10
|
|
43
72
|
}
|
|
44
73
|
},
|
|
45
74
|
"seedream-v4-edit": {
|
|
@@ -57,13 +86,31 @@ CONTRACT = {
|
|
|
57
86
|
"type": "integer"
|
|
58
87
|
},
|
|
59
88
|
"source_image_urls": {
|
|
60
|
-
"required": True
|
|
89
|
+
"required": True,
|
|
90
|
+
"min_items": 1,
|
|
91
|
+
"max_items": 10
|
|
61
92
|
}
|
|
62
93
|
}
|
|
63
|
-
}
|
|
94
|
+
},
|
|
95
|
+
"rules": [{
|
|
96
|
+
"when": {
|
|
97
|
+
"model": "seedream-4.5-edit"
|
|
98
|
+
},
|
|
99
|
+
"forbidden": ["output_format"]
|
|
100
|
+
}, {
|
|
101
|
+
"when": {
|
|
102
|
+
"model": "seedream-5-pro-edit"
|
|
103
|
+
},
|
|
104
|
+
"forbidden": ["output_resolution", "output_count", "seed"]
|
|
105
|
+
}, {
|
|
106
|
+
"when": {
|
|
107
|
+
"model": "seedream-v4-edit"
|
|
108
|
+
},
|
|
109
|
+
"forbidden": ["output_format"]
|
|
110
|
+
}]
|
|
64
111
|
},
|
|
65
112
|
"text-to-image": {
|
|
66
|
-
"models": ["seedream-4.5-text-to-image", "seedream-5-lite-text-to-image", "seedream-v4-text-to-image"],
|
|
113
|
+
"models": ["seedream-4.5-text-to-image", "seedream-5-lite-text-to-image", "seedream-5-pro-text-to-image", "seedream-v4-text-to-image"],
|
|
67
114
|
"fields_by_model": {
|
|
68
115
|
"seedream-4.5-text-to-image": {
|
|
69
116
|
"aspect_ratio": {
|
|
@@ -89,6 +136,9 @@ CONTRACT = {
|
|
|
89
136
|
"output_count": {
|
|
90
137
|
"type": "integer"
|
|
91
138
|
},
|
|
139
|
+
"output_format": {
|
|
140
|
+
"enum": ["png", "jpeg"]
|
|
141
|
+
},
|
|
92
142
|
"output_quality": {
|
|
93
143
|
"enum": ["basic", "high"],
|
|
94
144
|
"required": True
|
|
@@ -97,6 +147,25 @@ CONTRACT = {
|
|
|
97
147
|
"type": "integer"
|
|
98
148
|
}
|
|
99
149
|
},
|
|
150
|
+
"seedream-5-pro-text-to-image": {
|
|
151
|
+
"aspect_ratio": {
|
|
152
|
+
"enum": ["1:1", "4:3", "3:4", "16:9", "9:16", "2:3", "3:2", "21:9"],
|
|
153
|
+
"required": True
|
|
154
|
+
},
|
|
155
|
+
"output_format": {
|
|
156
|
+
"enum": ["png", "jpeg"]
|
|
157
|
+
},
|
|
158
|
+
"output_quality": {
|
|
159
|
+
"enum": ["basic", "high"],
|
|
160
|
+
"required": True
|
|
161
|
+
},
|
|
162
|
+
"prompt": {
|
|
163
|
+
"required": True,
|
|
164
|
+
"min": 3,
|
|
165
|
+
"max": 5000,
|
|
166
|
+
"length": True
|
|
167
|
+
}
|
|
168
|
+
},
|
|
100
169
|
"seedream-v4-text-to-image": {
|
|
101
170
|
"aspect_ratio": {
|
|
102
171
|
"enum": ["1:1", "4:3", "3:4", "3:2", "2:3", "16:9", "9:16", "21:9"]
|
|
@@ -112,6 +181,22 @@ CONTRACT = {
|
|
|
112
181
|
"type": "integer"
|
|
113
182
|
}
|
|
114
183
|
}
|
|
115
|
-
}
|
|
184
|
+
},
|
|
185
|
+
"rules": [{
|
|
186
|
+
"when": {
|
|
187
|
+
"model": "seedream-4.5-text-to-image"
|
|
188
|
+
},
|
|
189
|
+
"forbidden": ["output_format"]
|
|
190
|
+
}, {
|
|
191
|
+
"when": {
|
|
192
|
+
"model": "seedream-5-pro-text-to-image"
|
|
193
|
+
},
|
|
194
|
+
"forbidden": ["output_resolution", "output_count", "seed"]
|
|
195
|
+
}, {
|
|
196
|
+
"when": {
|
|
197
|
+
"model": "seedream-v4-text-to-image"
|
|
198
|
+
},
|
|
199
|
+
"forbidden": ["output_format"]
|
|
200
|
+
}]
|
|
116
201
|
}
|
|
117
202
|
}
|
|
@@ -2,13 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
from typing import Any, Dict
|
|
5
|
+
from typing import Any, Dict, Optional
|
|
6
6
|
|
|
7
|
-
from runapi.core import Resource, ValidationError
|
|
7
|
+
from runapi.core import Resource, ValidationError, RequestOptions
|
|
8
8
|
|
|
9
9
|
from ..contract_gen import CONTRACT
|
|
10
10
|
from ..types import (
|
|
11
|
-
|
|
11
|
+
LONG_PROMPT_MODELS,
|
|
12
|
+
MINIMUM_THREE_PROMPT_MODELS,
|
|
12
13
|
V4_MODELS,
|
|
13
14
|
CompletedEditImageResponse,
|
|
14
15
|
EditImageResponse,
|
|
@@ -27,7 +28,7 @@ class EditImage(Resource):
|
|
|
27
28
|
V4_PROMPT_MAX_LENGTH = 5000
|
|
28
29
|
PROMPT_MIN_LENGTH_LITE = 3
|
|
29
30
|
|
|
30
|
-
def run(self, **params: Any) -> Any:
|
|
31
|
+
def run(self, options: Optional[RequestOptions] = None, **params: Any) -> Any:
|
|
31
32
|
"""Edit an image and poll until it completes.
|
|
32
33
|
|
|
33
34
|
Args:
|
|
@@ -36,10 +37,10 @@ class EditImage(Resource):
|
|
|
36
37
|
Returns:
|
|
37
38
|
The completed (narrowed) image edit response.
|
|
38
39
|
"""
|
|
39
|
-
task = self.create(**params)
|
|
40
|
-
return self._poll_until_complete(lambda: self.get(task.id))
|
|
40
|
+
task = self.create(options=options, **params)
|
|
41
|
+
return self._poll_until_complete(lambda: self.get(task.id, options=options))
|
|
41
42
|
|
|
42
|
-
def create(self, **params: Any) -> Any:
|
|
43
|
+
def create(self, options: Optional[RequestOptions] = None, **params: Any) -> Any:
|
|
43
44
|
"""Create an image editing task and return immediately with an id.
|
|
44
45
|
|
|
45
46
|
Args:
|
|
@@ -50,9 +51,9 @@ class EditImage(Resource):
|
|
|
50
51
|
"""
|
|
51
52
|
compacted = self._compact_params(params)
|
|
52
53
|
self._validate_params(compacted)
|
|
53
|
-
return self._request("post", self.ENDPOINT, body=compacted)
|
|
54
|
+
return self._request("post", self.ENDPOINT, body=compacted, options=options)
|
|
54
55
|
|
|
55
|
-
def get(self, id: str) -> Any:
|
|
56
|
+
def get(self, id: str, options: Optional[RequestOptions] = None) -> Any:
|
|
56
57
|
"""Fetch the current status of an image editing task.
|
|
57
58
|
|
|
58
59
|
Args:
|
|
@@ -61,7 +62,7 @@ class EditImage(Resource):
|
|
|
61
62
|
Returns:
|
|
62
63
|
The current task status.
|
|
63
64
|
"""
|
|
64
|
-
return self._request("get", f"{self.ENDPOINT}/{id}")
|
|
65
|
+
return self._request("get", f"{self.ENDPOINT}/{id}", options=options)
|
|
65
66
|
|
|
66
67
|
def _validate_params(self, params: Dict[str, Any]) -> None:
|
|
67
68
|
self._validate_contract(CONTRACT["edit-image"], params)
|
|
@@ -71,12 +72,12 @@ class EditImage(Resource):
|
|
|
71
72
|
prompt = params.get("prompt")
|
|
72
73
|
if not (isinstance(prompt, str) and prompt):
|
|
73
74
|
raise ValidationError("prompt is required")
|
|
74
|
-
max_length = self.V4_PROMPT_MAX_LENGTH if model in
|
|
75
|
+
max_length = self.V4_PROMPT_MAX_LENGTH if model in LONG_PROMPT_MODELS else self.PROMPT_MAX_LENGTH
|
|
75
76
|
if len(prompt) > max_length:
|
|
76
77
|
raise ValidationError(f"prompt must be at most {max_length} characters")
|
|
77
|
-
if model in
|
|
78
|
+
if model in MINIMUM_THREE_PROMPT_MODELS and len(prompt) < self.PROMPT_MIN_LENGTH_LITE:
|
|
78
79
|
raise ValidationError(
|
|
79
|
-
f"prompt must be between {self.PROMPT_MIN_LENGTH_LITE} and {
|
|
80
|
+
f"prompt must be between {self.PROMPT_MIN_LENGTH_LITE} and {max_length} characters"
|
|
80
81
|
)
|
|
81
82
|
|
|
82
83
|
if model in V4_MODELS:
|
{runapi_seedream-0.1.0 → runapi_seedream-0.1.2}/src/runapi/seedream/resources/text_to_image.py
RENAMED
|
@@ -2,13 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
from typing import Any, Dict
|
|
5
|
+
from typing import Any, Dict, Optional
|
|
6
6
|
|
|
7
|
-
from runapi.core import Resource, ValidationError
|
|
7
|
+
from runapi.core import Resource, ValidationError, RequestOptions
|
|
8
8
|
|
|
9
9
|
from ..contract_gen import CONTRACT
|
|
10
10
|
from ..types import (
|
|
11
|
-
|
|
11
|
+
LONG_PROMPT_MODELS,
|
|
12
|
+
MINIMUM_THREE_PROMPT_MODELS,
|
|
12
13
|
V4_MODELS,
|
|
13
14
|
CompletedTextToImageResponse,
|
|
14
15
|
TextToImageResponse,
|
|
@@ -27,7 +28,7 @@ class TextToImage(Resource):
|
|
|
27
28
|
V4_PROMPT_MAX_LENGTH = 5000
|
|
28
29
|
PROMPT_MIN_LENGTH_LITE = 3
|
|
29
30
|
|
|
30
|
-
def run(self, **params: Any) -> Any:
|
|
31
|
+
def run(self, options: Optional[RequestOptions] = None, **params: Any) -> Any:
|
|
31
32
|
"""Create a text-to-image task and poll until it completes.
|
|
32
33
|
|
|
33
34
|
Args:
|
|
@@ -36,10 +37,10 @@ class TextToImage(Resource):
|
|
|
36
37
|
Returns:
|
|
37
38
|
The completed (narrowed) text-to-image response.
|
|
38
39
|
"""
|
|
39
|
-
task = self.create(**params)
|
|
40
|
-
return self._poll_until_complete(lambda: self.get(task.id))
|
|
40
|
+
task = self.create(options=options, **params)
|
|
41
|
+
return self._poll_until_complete(lambda: self.get(task.id, options=options))
|
|
41
42
|
|
|
42
|
-
def create(self, **params: Any) -> Any:
|
|
43
|
+
def create(self, options: Optional[RequestOptions] = None, **params: Any) -> Any:
|
|
43
44
|
"""Create a text-to-image task and return immediately with an id.
|
|
44
45
|
|
|
45
46
|
Args:
|
|
@@ -50,9 +51,9 @@ class TextToImage(Resource):
|
|
|
50
51
|
"""
|
|
51
52
|
compacted = self._compact_params(params)
|
|
52
53
|
self._validate_params(compacted)
|
|
53
|
-
return self._request("post", self.ENDPOINT, body=compacted)
|
|
54
|
+
return self._request("post", self.ENDPOINT, body=compacted, options=options)
|
|
54
55
|
|
|
55
|
-
def get(self, id: str) -> Any:
|
|
56
|
+
def get(self, id: str, options: Optional[RequestOptions] = None) -> Any:
|
|
56
57
|
"""Fetch the current status of a text-to-image task.
|
|
57
58
|
|
|
58
59
|
Args:
|
|
@@ -61,7 +62,7 @@ class TextToImage(Resource):
|
|
|
61
62
|
Returns:
|
|
62
63
|
The current task status.
|
|
63
64
|
"""
|
|
64
|
-
return self._request("get", f"{self.ENDPOINT}/{id}")
|
|
65
|
+
return self._request("get", f"{self.ENDPOINT}/{id}", options=options)
|
|
65
66
|
|
|
66
67
|
def _validate_params(self, params: Dict[str, Any]) -> None:
|
|
67
68
|
self._validate_contract(CONTRACT["text-to-image"], params)
|
|
@@ -71,12 +72,12 @@ class TextToImage(Resource):
|
|
|
71
72
|
prompt = params.get("prompt")
|
|
72
73
|
if not (isinstance(prompt, str) and prompt):
|
|
73
74
|
raise ValidationError("prompt is required")
|
|
74
|
-
max_length = self.V4_PROMPT_MAX_LENGTH if model in
|
|
75
|
+
max_length = self.V4_PROMPT_MAX_LENGTH if model in LONG_PROMPT_MODELS else self.PROMPT_MAX_LENGTH
|
|
75
76
|
if len(prompt) > max_length:
|
|
76
77
|
raise ValidationError(f"prompt must be at most {max_length} characters")
|
|
77
|
-
if model in
|
|
78
|
+
if model in MINIMUM_THREE_PROMPT_MODELS and len(prompt) < self.PROMPT_MIN_LENGTH_LITE:
|
|
78
79
|
raise ValidationError(
|
|
79
|
-
f"prompt must be between {self.PROMPT_MIN_LENGTH_LITE} and {
|
|
80
|
+
f"prompt must be between {self.PROMPT_MIN_LENGTH_LITE} and {max_length} characters"
|
|
80
81
|
)
|
|
81
82
|
|
|
82
83
|
if model in V4_MODELS:
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""Seedream model
|
|
1
|
+
"""Seedream model groups and responses; request enums come from CONTRACT."""
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
@@ -8,7 +8,10 @@ from runapi.core import BaseModel, TaskResponse, optional, required
|
|
|
8
8
|
# contract cannot express). Model membership and field enums are validated by
|
|
9
9
|
# the generated CONTRACT.
|
|
10
10
|
LITE_MODELS = ["seedream-5-lite-text-to-image", "seedream-5-lite-edit"]
|
|
11
|
+
PRO_MODELS = ["seedream-5-pro-text-to-image", "seedream-5-pro-edit"]
|
|
11
12
|
V4_MODELS = ["seedream-v4-text-to-image", "seedream-v4-edit"]
|
|
13
|
+
LONG_PROMPT_MODELS = [*PRO_MODELS, *V4_MODELS]
|
|
14
|
+
MINIMUM_THREE_PROMPT_MODELS = [*LITE_MODELS, *PRO_MODELS]
|
|
12
15
|
|
|
13
16
|
|
|
14
17
|
class Image(BaseModel):
|
|
@@ -80,6 +80,48 @@ def test_create_posts_compacted_body():
|
|
|
80
80
|
assert isinstance(result, TextToImageResponse)
|
|
81
81
|
|
|
82
82
|
|
|
83
|
+
def test_lite_output_format_is_forwarded():
|
|
84
|
+
fake = FakeHttp({"id": "t-lite", "status": "pending"})
|
|
85
|
+
client = SeedreamClient(api_key="k", http_client=fake)
|
|
86
|
+
client.edit_image.create(
|
|
87
|
+
model="seedream-5-lite-edit",
|
|
88
|
+
prompt="restyle this image",
|
|
89
|
+
source_image_urls=["https://cdn.runapi.ai/public/samples/image.jpg"],
|
|
90
|
+
aspect_ratio="1:1",
|
|
91
|
+
output_quality="high",
|
|
92
|
+
output_format="jpeg",
|
|
93
|
+
)
|
|
94
|
+
assert fake.calls == [
|
|
95
|
+
(
|
|
96
|
+
"post",
|
|
97
|
+
"/api/v1/seedream/edit_image",
|
|
98
|
+
{
|
|
99
|
+
"model": "seedream-5-lite-edit",
|
|
100
|
+
"prompt": "restyle this image",
|
|
101
|
+
"source_image_urls": ["https://cdn.runapi.ai/public/samples/image.jpg"],
|
|
102
|
+
"aspect_ratio": "1:1",
|
|
103
|
+
"output_quality": "high",
|
|
104
|
+
"output_format": "jpeg",
|
|
105
|
+
},
|
|
106
|
+
),
|
|
107
|
+
]
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def test_pro_edit_is_forwarded():
|
|
111
|
+
fake = FakeHttp({"id": "t-pro", "status": "pending"})
|
|
112
|
+
client = SeedreamClient(api_key="k", http_client=fake)
|
|
113
|
+
client.edit_image.create(
|
|
114
|
+
model="seedream-5-pro-edit",
|
|
115
|
+
prompt="Turn the material into transparent glass",
|
|
116
|
+
source_image_urls=["https://cdn.runapi.ai/public/samples/image.jpg"],
|
|
117
|
+
aspect_ratio="3:2",
|
|
118
|
+
output_quality="basic",
|
|
119
|
+
output_format="png",
|
|
120
|
+
)
|
|
121
|
+
assert fake.calls[0][2]["model"] == "seedream-5-pro-edit"
|
|
122
|
+
assert fake.calls[0][2]["output_format"] == "png"
|
|
123
|
+
|
|
124
|
+
|
|
83
125
|
def test_get_fetches_by_id():
|
|
84
126
|
fake = FakeHttp({"id": "t1", "status": "processing"})
|
|
85
127
|
client = SeedreamClient(api_key="k", http_client=fake)
|
|
@@ -143,3 +185,37 @@ def test_lite_prompt_min_length():
|
|
|
143
185
|
client = SeedreamClient(api_key="k", http_client=FakeHttp())
|
|
144
186
|
with pytest.raises(ValidationError, match="between 3 and 3000"):
|
|
145
187
|
client.text_to_image.create(model="seedream-5-lite-text-to-image", prompt="hi", aspect_ratio="1:1", output_quality="high")
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
def test_pro_prompt_allows_5000_characters():
|
|
191
|
+
client = SeedreamClient(api_key="k", http_client=FakeHttp())
|
|
192
|
+
client.text_to_image.create(
|
|
193
|
+
model="seedream-5-pro-text-to-image",
|
|
194
|
+
prompt="x" * 5000,
|
|
195
|
+
aspect_ratio="1:1",
|
|
196
|
+
output_quality="high",
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
def test_pro_edit_rejects_more_than_ten_source_images():
|
|
201
|
+
client = SeedreamClient(api_key="k", http_client=FakeHttp())
|
|
202
|
+
with pytest.raises(ValidationError, match="source_image_urls must contain between 1 and 10 items"):
|
|
203
|
+
client.edit_image.create(
|
|
204
|
+
model="seedream-5-pro-edit",
|
|
205
|
+
prompt="restyle this image",
|
|
206
|
+
source_image_urls=["https://cdn.runapi.ai/public/samples/image.jpg"] * 11,
|
|
207
|
+
aspect_ratio="1:1",
|
|
208
|
+
output_quality="high",
|
|
209
|
+
)
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
def test_lite_output_format_enum():
|
|
213
|
+
client = SeedreamClient(api_key="k", http_client=FakeHttp())
|
|
214
|
+
with pytest.raises(ValidationError, match="output_format must be one of: png, jpeg"):
|
|
215
|
+
client.text_to_image.create(
|
|
216
|
+
model="seedream-5-lite-text-to-image",
|
|
217
|
+
prompt="hi there",
|
|
218
|
+
aspect_ratio="1:1",
|
|
219
|
+
output_quality="high",
|
|
220
|
+
output_format="webp",
|
|
221
|
+
)
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
[build-system]
|
|
2
|
-
requires = ["hatchling"]
|
|
3
|
-
build-backend = "hatchling.build"
|
|
4
|
-
|
|
5
|
-
[project]
|
|
6
|
-
name = "runapi-seedream"
|
|
7
|
-
version = "0.1.0"
|
|
8
|
-
description = "Seedream text-to-image and edit-image client for RunAPI"
|
|
9
|
-
readme = "README.md"
|
|
10
|
-
requires-python = ">=3.9"
|
|
11
|
-
license = "Apache-2.0"
|
|
12
|
-
authors = [{ name = "RunAPI", email = "contact@runapi.ai" }]
|
|
13
|
-
keywords = ["runapi", "seedream", "text-to-image", "edit-image", "ai", "sdk"]
|
|
14
|
-
dependencies = ["runapi-core"]
|
|
15
|
-
|
|
16
|
-
[project.urls]
|
|
17
|
-
Homepage = "https://runapi.ai/models/seedream"
|
|
18
|
-
Documentation = "https://runapi.ai/docs#sdk-seedream"
|
|
19
|
-
|
|
20
|
-
[tool.hatch.build.targets.wheel]
|
|
21
|
-
packages = ["src/runapi"]
|
|
22
|
-
|
|
23
|
-
[tool.uv]
|
|
24
|
-
package = true
|
|
25
|
-
|
|
26
|
-
[tool.uv.sources]
|
|
27
|
-
runapi-core = { workspace = true }
|
|
28
|
-
|
|
29
|
-
[dependency-groups]
|
|
30
|
-
dev = ["pytest>=8"]
|
|
31
|
-
|
|
32
|
-
[tool.runapi]
|
|
33
|
-
slug = "seedream"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|