runapi-seedance 0.2.2__tar.gz → 0.2.3__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,18 +1,18 @@
1
- Metadata-Version: 2.4
1
+ Metadata-Version: 2.5
2
2
  Name: runapi-seedance
3
- Version: 0.2.2
3
+ Version: 0.2.3
4
4
  Summary: RunAPI Seedance SDK for text-to-video workflows in JavaScript, Python, Ruby, Go, Java, and PHP
5
5
  Project-URL: Homepage, https://runapi.ai/models/seedance
6
6
  Project-URL: Documentation, https://runapi.ai/docs/resources/sdks
7
7
  Project-URL: Source, https://github.com/runapi-ai/seedance-sdk
8
8
  Project-URL: Issues, https://github.com/runapi-ai/seedance-sdk/issues
9
9
  Project-URL: Changelog, https://github.com/runapi-ai/seedance-sdk/blob/main/CHANGELOG.md
10
- Project-URL: Release Notes, https://github.com/runapi-ai/seedance-sdk/releases/tag/python%2Fv0.2.2
10
+ Project-URL: Release Notes, https://github.com/runapi-ai/seedance-sdk/releases/tag/python%2Fv0.2.3
11
11
  Author-email: RunAPI <contact@runapi.ai>
12
12
  License-Expression: Apache-2.0
13
13
  Keywords: api,golang,gradle,java,maven,python,ruby,runapi,runapi-ai,sdk,seedance,seedance-api,text-to-video,typescript,video-api,video-generation
14
14
  Requires-Python: >=3.9
15
- Requires-Dist: runapi-core>=0.3.3
15
+ Requires-Dist: runapi-core>=0.5.1
16
16
  Description-Content-Type: text/markdown
17
17
 
18
18
  # Seedance Python SDK for RunAPI
@@ -4,14 +4,14 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "runapi-seedance"
7
- version = "0.2.2"
7
+ version = "0.2.3"
8
8
  description = "RunAPI Seedance SDK for text-to-video workflows in JavaScript, Python, Ruby, Go, Java, and PHP"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"
11
11
  license = "Apache-2.0"
12
12
  authors = [{ name = "RunAPI", email = "contact@runapi.ai" }]
13
13
  keywords = ["runapi", "runapi-ai", "seedance", "api", "sdk", "typescript", "python", "ruby", "golang", "java", "maven", "gradle", "video-generation", "text-to-video", "video-api", "seedance-api"]
14
- dependencies = ["runapi-core>=0.3.3"]
14
+ dependencies = ["runapi-core>=0.5.1"]
15
15
 
16
16
  [project.urls]
17
17
  Homepage = "https://runapi.ai/models/seedance"
@@ -19,7 +19,7 @@ Documentation = "https://runapi.ai/docs/resources/sdks"
19
19
  Source = "https://github.com/runapi-ai/seedance-sdk"
20
20
  Issues = "https://github.com/runapi-ai/seedance-sdk/issues"
21
21
  Changelog = "https://github.com/runapi-ai/seedance-sdk/blob/main/CHANGELOG.md"
22
- "Release Notes" = "https://github.com/runapi-ai/seedance-sdk/releases/tag/python%2Fv0.2.2"
22
+ "Release Notes" = "https://github.com/runapi-ai/seedance-sdk/releases/tag/python%2Fv0.2.3"
23
23
 
24
24
  [tool.hatch.build.targets.wheel]
25
25
  packages = ["src/runapi"]
@@ -1,6 +1,6 @@
1
1
  CONTRACT = {
2
2
  "text-to-video": {
3
- "models": ["seedance-1.5-pro", "seedance-2-mini", "seedance-2.0", "seedance-2.0-fast", "seedance-v1-pro", "seedance-v1-pro-fast"],
3
+ "models": ["seedance-1.5-pro", "seedance-2-mini", "seedance-2.0", "seedance-2.0-fast", "seedance-2.5", "seedance-v1-pro", "seedance-v1-pro-fast"],
4
4
  "fields_by_model": {
5
5
  "seedance-1.5-pro": {
6
6
  "aspect_ratio": {
@@ -90,6 +90,39 @@ CONTRACT = {
90
90
  "max_items": 3
91
91
  }
92
92
  },
93
+ "seedance-2.5": {
94
+ "aspect_ratio": {
95
+ "enum": ["1:1", "4:3", "3:4", "16:9", "9:16", "21:9", "auto"]
96
+ },
97
+ "duration_seconds": {
98
+ "enum": [-1, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30],
99
+ "type": "integer"
100
+ },
101
+ "model": {
102
+ "required": True
103
+ },
104
+ "output_format": {
105
+ "enum": ["mp4", "mov"]
106
+ },
107
+ "output_resolution": {
108
+ "enum": ["480p", "720p"]
109
+ },
110
+ "prompt": {
111
+ "required": True,
112
+ "min": 3,
113
+ "max": 30000,
114
+ "length": True
115
+ },
116
+ "reference_audio_urls": {
117
+ "max_items": 10
118
+ },
119
+ "reference_image_urls": {
120
+ "max_items": 30
121
+ },
122
+ "reference_video_urls": {
123
+ "max_items": 10
124
+ }
125
+ },
93
126
  "seedance-v1-pro": {
94
127
  "aspect_ratio": {
95
128
  "enum": ["1:1", "4:3", "3:4", "16:9", "9:16", "21:9"]
@@ -126,35 +159,57 @@ CONTRACT = {
126
159
  }
127
160
  },
128
161
  "rules": [{
162
+ "when": {
163
+ "model": "seedance-2.5",
164
+ "first_frame_image_url": {
165
+ "present": True
166
+ }
167
+ },
168
+ "forbidden": ["reference_image_urls", "reference_video_urls", "reference_audio_urls"]
169
+ }, {
170
+ "when": {
171
+ "model": "seedance-2.5",
172
+ "last_frame_image_url": {
173
+ "present": True
174
+ }
175
+ },
176
+ "required": ["first_frame_image_url"],
177
+ "forbidden": ["reference_image_urls", "reference_video_urls", "reference_audio_urls"]
178
+ }, {
129
179
  "when": {
130
180
  "model": "seedance-1.5-pro"
131
181
  },
132
- "forbidden": ["first_frame_image_url", "last_frame_image_url", "reference_image_urls", "reference_video_urls", "reference_audio_urls", "web_search"]
182
+ "forbidden": ["first_frame_image_url", "last_frame_image_url", "reference_image_urls", "reference_video_urls", "reference_audio_urls", "web_search", "return_last_frame", "output_format"]
133
183
  }, {
134
184
  "when": {
135
185
  "model": "seedance-2-mini"
136
186
  },
137
- "forbidden": ["source_image_urls", "lock_camera", "seed", "enable_safety_checker"]
187
+ "forbidden": ["source_image_urls", "lock_camera", "seed", "enable_safety_checker", "return_last_frame", "output_format"]
138
188
  }, {
139
189
  "when": {
140
190
  "model": "seedance-2.0"
141
191
  },
142
- "forbidden": ["source_image_urls", "lock_camera", "seed"]
192
+ "forbidden": ["source_image_urls", "lock_camera", "seed", "return_last_frame", "output_format"]
143
193
  }, {
144
194
  "when": {
145
195
  "model": "seedance-2.0-fast"
146
196
  },
197
+ "forbidden": ["source_image_urls", "lock_camera", "seed", "return_last_frame", "output_format"]
198
+ }, {
199
+ "when": {
200
+ "model": "seedance-2.5"
201
+ },
147
202
  "forbidden": ["source_image_urls", "lock_camera", "seed"]
148
203
  }, {
149
204
  "when": {
150
205
  "model": "seedance-v1-pro"
151
206
  },
152
- "forbidden": ["source_image_urls", "last_frame_image_url", "reference_image_urls", "reference_video_urls", "reference_audio_urls", "web_search", "generate_audio"]
207
+ "forbidden": ["source_image_urls", "last_frame_image_url", "reference_image_urls", "reference_video_urls", "reference_audio_urls", "web_search", "generate_audio", "return_last_frame", "output_format"]
153
208
  }, {
154
209
  "when": {
155
210
  "model": "seedance-v1-pro-fast"
156
211
  },
157
- "forbidden": ["aspect_ratio", "source_image_urls", "lock_camera", "last_frame_image_url", "reference_image_urls", "reference_video_urls", "reference_audio_urls", "web_search", "generate_audio"]
212
+ "forbidden": ["aspect_ratio", "source_image_urls", "lock_camera", "last_frame_image_url", "reference_image_urls", "reference_video_urls", "reference_audio_urls", "web_search", "generate_audio", "return_last_frame", "output_format"]
158
213
  }]
159
214
  }
160
215
  }
@@ -73,16 +73,17 @@ class TextToVideo(Resource):
73
73
  self._validate_contract(CONTRACT["text-to-video"], params)
74
74
 
75
75
  model = params.get("model")
76
- if model == "seedance-1.5-pro":
77
- max_prompt = PROMPT_MAX_LENGTH_1_5
78
- elif model in V1_MODELS:
79
- max_prompt = PROMPT_MAX_LENGTH_V1
80
- else:
81
- max_prompt = PROMPT_MAX_LENGTH_2
82
- if not (PROMPT_MIN_LENGTH <= len(prompt) <= max_prompt):
83
- raise ValidationError(
84
- f"prompt length must be between {PROMPT_MIN_LENGTH} and {max_prompt} characters"
85
- )
76
+ if model != "seedance-2.5":
77
+ if model == "seedance-1.5-pro":
78
+ max_prompt = PROMPT_MAX_LENGTH_1_5
79
+ elif model in V1_MODELS:
80
+ max_prompt = PROMPT_MAX_LENGTH_V1
81
+ else:
82
+ max_prompt = PROMPT_MAX_LENGTH_2
83
+ if not (PROMPT_MIN_LENGTH <= len(prompt) <= max_prompt):
84
+ raise ValidationError(
85
+ f"prompt length must be between {PROMPT_MIN_LENGTH} and {max_prompt} characters"
86
+ )
86
87
 
87
88
  if model == "seedance-1.5-pro":
88
89
  self._validate_1_5_pro(params)
@@ -167,6 +167,25 @@ def test_v2_mini_accepts_reference_mode():
167
167
  assert http.calls[0][2]["model"] == "seedance-2-mini"
168
168
 
169
169
 
170
+ def test_v2_5_accepts_multimodal_fields():
171
+ http = FakeHttp({"id": "task-25", "status": "processing"})
172
+ client = SeedanceClient(api_key="k", http_client=http)
173
+
174
+ client.text_to_video.create(
175
+ model="seedance-2.5",
176
+ prompt="Match the reference media",
177
+ reference_image_urls=["https://cdn.runapi.ai/public/samples/reference.jpg"],
178
+ reference_video_urls=["https://cdn.runapi.ai/public/samples/reference.mp4"],
179
+ duration_seconds=-1,
180
+ return_last_frame=True,
181
+ output_format="mov",
182
+ )
183
+
184
+ assert http.calls[0][2]["model"] == "seedance-2.5"
185
+ assert http.calls[0][2]["return_last_frame"] is True
186
+ assert http.calls[0][2]["output_format"] == "mov"
187
+
188
+
170
189
  def test_v2_mini_resolution_excludes_1080p():
171
190
  client = SeedanceClient(api_key="k", http_client=FakeHttp())
172
191
  with pytest.raises(ValidationError, match="output_resolution must be one of:"):