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.
@@ -1,21 +1,25 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: runapi-seedream
3
- Version: 0.1.0
4
- Summary: Seedream text-to-image and edit-image client for RunAPI
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: ai,edit-image,runapi,sdk,seedream,text-to-image
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 API Python SDK for RunAPI
18
+ # Seedream Python SDK for RunAPI
15
19
 
16
- The seedream api Python SDK is the language-specific package for Seedream on RunAPI. Use this seedream api package for text-to-image, image editing, and creative production flows when your application needs JSON request bodies, task status lookup, and consistent RunAPI errors in Python.
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 seedream api 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.
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://example.com/source.jpg"],
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` for text models and `edit_image` for editing models. Keep `RUNAPI_API_KEY` in the environment or your secret manager; never commit API keys or callback secrets.
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 API Python SDK for RunAPI
1
+ # Seedream Python SDK for RunAPI
2
2
 
3
- The seedream api Python SDK is the language-specific package for Seedream on RunAPI. Use this seedream api package for text-to-image, image editing, and creative production flows when your application needs JSON request bodies, task status lookup, and consistent RunAPI errors in Python.
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 seedream api 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.
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://example.com/source.jpg"],
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` for text models and `edit_image` for editing models. Keep `RUNAPI_API_KEY` in the environment or your secret manager; never commit API keys or callback secrets.
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
- LITE_MODELS,
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 V4_MODELS else self.PROMPT_MAX_LENGTH
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 LITE_MODELS and len(prompt) < self.PROMPT_MIN_LENGTH_LITE:
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 {self.PROMPT_MAX_LENGTH} characters"
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:
@@ -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
- LITE_MODELS,
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 V4_MODELS else self.PROMPT_MAX_LENGTH
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 LITE_MODELS and len(prompt) < self.PROMPT_MIN_LENGTH_LITE:
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 {self.PROMPT_MAX_LENGTH} characters"
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 lists, enums, and response models."""
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"