Skip to content

Commit 66e243f

Browse files
author
yiguang
committed
feat: add seedream stream sdk
1 parent d6f9351 commit 66e243f

File tree

7 files changed

+351
-8
lines changed

7 files changed

+351
-8
lines changed
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import os
2+
3+
from volcenginesdkarkruntime import Ark
4+
from volcenginesdkarkruntime.types.images.images import SequentialImageGenerationOptions
5+
6+
client = Ark(
7+
base_url="https://ark.cn-beijing.volces.com/api/v3",
8+
api_key=os.environ.get("ARK_API_KEY"),
9+
)
10+
11+
if __name__ == "__main__":
12+
modelEp = "YOUR_ENDPOINT_ID"
13+
print("----- [Seedream] generate images (response format: url) -----")
14+
stream = client.images.generate(
15+
model=modelEp,
16+
prompt="星球大战, 需要三幅图片描绘不同的战斗场景",
17+
response_format= "url",
18+
seed=1234567890,
19+
watermark=True,
20+
size="1024x1024",
21+
stream=True,
22+
sequential_image_generation="auto",
23+
sequential_image_generation_options=SequentialImageGenerationOptions(max_images=3),
24+
)
25+
26+
for event in stream:
27+
if event is None:
28+
continue
29+
30+
if event.type == "image_generation.partial_failed":
31+
print(f"Stream generate images error: {event.error}")
32+
if event.error and event.error.code and event.error.code.startswith("5"):
33+
break
34+
35+
elif event.type == "image_generation.partial_succeeded":
36+
if event.error is None and event.url:
37+
print(f"recv.Size: {event.size}, recv.Url: {event.url}")
38+
39+
elif event.type == "image_generation.completed":
40+
if event.error is None:
41+
print("Final completed event:")
42+
print("recv.Usage:", event.usage)
43+
44+
elif event.type == "image_generation.partial_image":
45+
print(f"Partial image index={event.partial_image_index}, size={len(event.b64_json)}")

volcenginesdkarkruntime/resources/images/images.py

Lines changed: 172 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,23 +12,107 @@
1212

1313
from __future__ import annotations
1414

15+
from typing import Optional
16+
from typing_extensions import Literal, overload
17+
1518
import httpx
1619

20+
from ..._types import NOT_GIVEN, NotGiven
1721
from ..._base_client import make_request_options
1822
from ..._utils._utils import apikey_required, async_apikey_required
1923
from ..._resource import SyncAPIResource, AsyncAPIResource
20-
from ...types.images import ImagesResponse
24+
from ...types.images import SequentialImageGenerationOptions, ImagesResponse
25+
from ...types.images.image_gen_stream_event import ImageGenStreamEvent
2126
from ..._types import Body, Query, Headers
27+
from ..._streaming import Stream
2228

2329

2430
class Images(SyncAPIResource):
31+
@overload
32+
def generate(
33+
self,
34+
*,
35+
model: str,
36+
prompt: str,
37+
image: str | list[str] | None = None,
38+
response_format: str | None = None,
39+
size: str | None = None,
40+
seed: int | None = None,
41+
guidance_scale: float | None = None,
42+
watermark: bool | None = None,
43+
optimize_prompt: bool | None = None,
44+
extra_headers: Headers | None = None,
45+
extra_query: Query | None = None,
46+
extra_body: Body | None = None,
47+
timeout: float | httpx.Timeout | None = None,
48+
sequential_image_generation: str | None = None,
49+
sequential_image_generation_options: SequentialImageGenerationOptions | None = None,
50+
stream: Optional[Literal[False]] | NotGiven = NOT_GIVEN,
51+
) -> ImagesResponse:
52+
...
53+
54+
"""
55+
ImageSequenceGeneration:
56+
Controls whether the multi-image feature is enforced
57+
- Enum values:
58+
- auto: Automatic mode; the model decides whether to return multiple images and how many based on the user's prompt
59+
- disabled: Disables multi-image; the model generates only a single image
60+
"""
61+
62+
63+
@overload
64+
def generate(
65+
self,
66+
*,
67+
model: str,
68+
prompt: str,
69+
image: str | list[str] | None = None,
70+
response_format: str | None = None,
71+
size: str | None = None,
72+
seed: int | None = None,
73+
guidance_scale: float | None = None,
74+
watermark: bool | None = None,
75+
optimize_prompt: bool | None = None,
76+
extra_headers: Headers | None = None,
77+
extra_query: Query | None = None,
78+
extra_body: Body | None = None,
79+
timeout: float | httpx.Timeout | None = None,
80+
sequential_image_generation: str | None = None,
81+
sequential_image_generation_options: SequentialImageGenerationOptions | None = None,
82+
stream: Literal[True],
83+
) -> Stream[ImageGenStreamEvent]:
84+
...
85+
86+
@overload
87+
def generate(
88+
self,
89+
*,
90+
model: str,
91+
prompt: str,
92+
image: str | list[str] | None = None,
93+
response_format: str | None = None,
94+
size: str | None = None,
95+
seed: int | None = None,
96+
guidance_scale: float | None = None,
97+
watermark: bool | None = None,
98+
optimize_prompt: bool | None = None,
99+
extra_headers: Headers | None = None,
100+
extra_query: Query | None = None,
101+
extra_body: Body | None = None,
102+
timeout: float | httpx.Timeout | None = None,
103+
sequential_image_generation: str | None = None,
104+
sequential_image_generation_options: SequentialImageGenerationOptions | None = None,
105+
stream: bool,
106+
) -> ImagesResponse | Stream[ImageGenStreamEvent]:
107+
...
108+
25109
@apikey_required
26110
def generate(
27111
self,
28112
*,
29113
model: str,
30114
prompt: str,
31-
image: str | None = None,
115+
image: str | list[str] | None = None,
32116
response_format: str | None = None,
33117
size: str | None = None,
34118
seed: int | None = None,
@@ -39,6 +123,9 @@ def generate(
39123
extra_query: Query | None = None,
40124
extra_body: Body | None = None,
41125
timeout: float | httpx.Timeout | None = None,
126+
sequential_image_generation: str | None = None,
127+
sequential_image_generation_options: SequentialImageGenerationOptions | None = None,
128+
stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN,
42129
) -> ImagesResponse:
43130
resp = self._post(
44131
"/images/generations",
@@ -52,6 +139,9 @@ def generate(
52139
"guidance_scale": guidance_scale,
53140
"watermark": watermark,
54141
"optimize_prompt": optimize_prompt,
142+
"sequential_image_generation": sequential_image_generation,
143+
"sequential_image_generation_options": sequential_image_generation_options.model_dump(mode='json'),
144+
"stream": stream,
55145
},
56146
options=make_request_options(
57147
extra_headers=extra_headers,
@@ -60,19 +150,90 @@ def generate(
60150
timeout=timeout,
61151
),
62152
cast_to=ImagesResponse,
153+
stream=stream or False,
154+
stream_cls=Stream[ImageGenStreamEvent],
63155
)
64156

65157
return resp
66158

67159

68160
class AsyncImages(AsyncAPIResource):
161+
@overload
162+
async def generate(
163+
self,
164+
*,
165+
model: str,
166+
prompt: str,
167+
image: str | list[str] | None = None,
168+
response_format: str | None = None,
169+
size: str | None = None,
170+
seed: int | None = None,
171+
guidance_scale: float | None = None,
172+
watermark: bool | None = None,
173+
optimize_prompt: bool | None = None,
174+
extra_headers: Headers | None = None,
175+
extra_query: Query | None = None,
176+
extra_body: Body | None = None,
177+
timeout: float | httpx.Timeout | None = None,
178+
sequential_image_generation: str | None = None,
179+
sequential_image_generation_options: SequentialImageGenerationOptions | None = None,
180+
stream: Optional[Literal[False]] | NotGiven = NOT_GIVEN,
181+
) -> ImagesResponse:
182+
...
183+
184+
@overload
185+
async def generate(
186+
self,
187+
*,
188+
model: str,
189+
prompt: str,
190+
image: str | list[str] | None = None,
191+
response_format: str | None = None,
192+
size: str | None = None,
193+
seed: int | None = None,
194+
guidance_scale: float | None = None,
195+
watermark: bool | None = None,
196+
optimize_prompt: bool | None = None,
197+
extra_headers: Headers | None = None,
198+
extra_query: Query | None = None,
199+
extra_body: Body | None = None,
200+
timeout: float | httpx.Timeout | None = None,
201+
sequential_image_generation: str | None = None,
202+
sequential_image_generation_options: SequentialImageGenerationOptions | None = None,
203+
stream: Literal[True],
204+
) -> Stream[ImageGenStreamEvent]:
205+
...
206+
207+
@overload
208+
async def generate(
209+
self,
210+
*,
211+
model: str,
212+
prompt: str,
213+
image: str | list[str] | None = None,
214+
response_format: str | None = None,
215+
size: str | None = None,
216+
seed: int | None = None,
217+
guidance_scale: float | None = None,
218+
watermark: bool | None = None,
219+
optimize_prompt: bool | None = None,
220+
extra_headers: Headers | None = None,
221+
extra_query: Query | None = None,
222+
extra_body: Body | None = None,
223+
timeout: float | httpx.Timeout | None = None,
224+
sequential_image_generation: str | None = None,
225+
sequential_image_generation_options: SequentialImageGenerationOptions | None = None,
226+
stream: bool,
227+
) -> ImagesResponse | Stream[ImageGenStreamEvent]:
228+
...
229+
69230
@async_apikey_required
70231
async def generate(
71232
self,
72233
*,
73234
model: str,
74235
prompt: str,
75-
image: str | None = None,
236+
image: str | list[str] | None = None,
76237
response_format: str | None = None,
77238
size: str | None = None,
78239
seed: int | None = None,
@@ -83,7 +244,10 @@ async def generate(
83244
extra_query: Query | None = None,
84245
extra_body: Body | None = None,
85246
timeout: float | httpx.Timeout | None = None,
86-
) -> ImagesResponse:
247+
sequential_image_generation: str | None = None,
248+
sequential_image_generation_options: SequentialImageGenerationOptions | None = None,
249+
stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN,
250+
) -> ImagesResponse | Stream[ImageGenStreamEvent]:
87251
return await self._post(
88252
"/images/generations",
89253
body={
@@ -96,6 +260,8 @@ async def generate(
96260
"guidance_scale": guidance_scale,
97261
"watermark": watermark,
98262
"optimize_prompt": optimize_prompt,
263+
"sequential_image_generation": sequential_image_generation,
264+
"sequential_image_generation_options": sequential_image_generation_options,
99265
},
100266
options=make_request_options(
101267
extra_headers=extra_headers,
@@ -104,4 +270,6 @@ async def generate(
104270
timeout=timeout,
105271
),
106272
cast_to=ImagesResponse,
273+
stream=stream or False,
274+
stream_cls=Stream[ImageGenStreamEvent],
107275
)

volcenginesdkarkruntime/types/images/__init__.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#
1111
# This modified file is released under the same license.
1212

13-
from .images import ImagesResponse
13+
from .images import SequentialImageGenerationOptions, ImagesResponse
1414

15-
__all__ = ["ImagesResponse"]
15+
16+
__all__ = ["SequentialImageGenerationOptions","ImagesResponse"]
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
2+
# Copyright (c) [2025] [OpenAI]
3+
# Copyright (c) [2025] [ByteDance Ltd. and/or its affiliates.]
4+
# SPDX-License-Identifier: Apache-2.0
5+
#
6+
# This file has been modified by [ByteDance Ltd. and/or its affiliates.] on 2025.7
7+
#
8+
# Original file was released under Apache License Version 2.0, with the full license text
9+
# available at https://github.com/openai/openai-python/blob/main/LICENSE.
10+
#
11+
# This modified file is released under the same license.
12+
13+
from typing import List
14+
15+
from volcenginesdkarkruntime._models import BaseModel
16+
17+
__all__ = ["ImageGenCompletedEvent"]
18+
19+
20+
class Usage(BaseModel):
21+
generated_images: int
22+
"""The number of images generated."""
23+
output_tokens: int
24+
"""The number of output tokens."""
25+
total_tokens: int
26+
"""The total number of tokens."""
27+
28+
class Error(BaseModel):
29+
message: str
30+
"""The reason for failed image generation"""
31+
32+
code: str
33+
"""The error code for failed image generation"""
34+
35+
36+
class ImageGenCompletedEvent(BaseModel):
37+
type: str
38+
"""The type of image generating event."""
39+
40+
model: str
41+
"""The model used to generated the images."""
42+
43+
error: Error
44+
"""The error body, if applicable."""
45+
46+
usage: Usage
47+
"""The usage information for the generation of images."""
48+
49+
created_at: int
50+
"""The Unix timestamp when the image was generated."""

0 commit comments

Comments
 (0)