Skip to content

Commit 2bd0e45

Browse files
authored
feat: remove retired Lucy model IDs (#49)
* Remove retired Lucy model IDs * Fix Lucy 2.1 realtime dimensions * Remove retired model rejection test
1 parent 3c6a145 commit 2bd0e45

8 files changed

Lines changed: 30 additions & 92 deletions

File tree

decart/models.py

Lines changed: 1 addition & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
RealTimeModels = Literal[
99
# Canonical names
1010
"lucy",
11-
"lucy-2",
1211
"lucy-2.1",
1312
"lucy-2.1-vton",
1413
"lucy-restyle",
@@ -22,13 +21,11 @@
2221
"mirage",
2322
"mirage_v2",
2423
"lucy_v2v_720p_rt",
25-
"lucy_2_rt",
2624
"live_avatar",
2725
]
2826
VideoModels = Literal[
2927
# Canonical names
3028
"lucy-clip",
31-
"lucy-2",
3229
"lucy-2.1",
3330
"lucy-2.1-vton",
3431
"lucy-restyle-2",
@@ -42,7 +39,6 @@
4239
# Deprecated names
4340
"lucy-pro-v2v",
4441
"lucy-restyle-v2v",
45-
"lucy-2-v2v",
4642
]
4743
ImageModels = Literal[
4844
# Canonical names
@@ -59,12 +55,10 @@
5955
"mirage": "lucy-restyle",
6056
"mirage_v2": "lucy-restyle-2",
6157
"lucy_v2v_720p_rt": "lucy",
62-
"lucy_2_rt": "lucy-2",
6358
"live_avatar": "live-avatar",
6459
# Video aliases
6560
"lucy-pro-v2v": "lucy-clip",
6661
"lucy-restyle-v2v": "lucy-restyle-2",
67-
"lucy-2-v2v": "lucy-2",
6862
# Image aliases
6963
"lucy-pro-i2i": "lucy-image-2",
7064
}
@@ -163,7 +157,7 @@ def validate_prompt_or_reference_image(self) -> "VideoRestyleInput":
163157

164158

165159
class VideoEdit2Input(DecartBaseModel):
166-
"""Input for lucy-2-v2v model.
160+
"""Input for Lucy 2.1 video editing models.
167161
168162
Prompt is required but can be an empty string.
169163
Optional reference_image can also be provided.
@@ -201,14 +195,6 @@ class ImageToImageInput(DecartBaseModel):
201195
height=704,
202196
input_schema=BaseModel,
203197
),
204-
"lucy-2": ModelDefinition(
205-
name="lucy-2",
206-
url_path="/v1/stream",
207-
fps=20,
208-
width=1280,
209-
height=720,
210-
input_schema=BaseModel,
211-
),
212198
"lucy-2.1": ModelDefinition(
213199
name="lucy-2.1",
214200
url_path="/v1/stream",
@@ -299,14 +285,6 @@ class ImageToImageInput(DecartBaseModel):
299285
height=704,
300286
input_schema=BaseModel,
301287
),
302-
"lucy_2_rt": ModelDefinition(
303-
name="lucy_2_rt",
304-
url_path="/v1/stream",
305-
fps=20,
306-
width=1280,
307-
height=720,
308-
input_schema=BaseModel,
309-
),
310288
"live_avatar": ModelDefinition(
311289
name="live_avatar",
312290
url_path="/v1/stream",
@@ -326,14 +304,6 @@ class ImageToImageInput(DecartBaseModel):
326304
height=704,
327305
input_schema=VideoToVideoInput,
328306
),
329-
"lucy-2": ModelDefinition(
330-
name="lucy-2",
331-
url_path="/v1/jobs/lucy-2",
332-
fps=20,
333-
width=1280,
334-
height=720,
335-
input_schema=VideoEdit2Input,
336-
),
337307
"lucy-2.1": ModelDefinition(
338308
name="lucy-2.1",
339309
url_path="/v1/jobs/lucy-2.1",
@@ -424,14 +394,6 @@ class ImageToImageInput(DecartBaseModel):
424394
height=704,
425395
input_schema=VideoRestyleInput,
426396
),
427-
"lucy-2-v2v": ModelDefinition(
428-
name="lucy-2-v2v",
429-
url_path="/v1/jobs/lucy-2-v2v",
430-
fps=20,
431-
width=1280,
432-
height=720,
433-
input_schema=VideoEdit2Input,
434-
),
435397
},
436398
"image": {
437399
# Canonical names
@@ -483,7 +445,6 @@ def video(model: VideoModels) -> VideoModelDefinition:
483445
484446
Available models:
485447
- "lucy-clip" - Video-to-video
486-
- "lucy-2" - Video editing with reference image support
487448
- "lucy-2.1" - Video editing (newer, higher quality)
488449
- "lucy-restyle-2" - Video restyling with prompt or reference image
489450
- "lucy-motion" - Image-to-motion-video

decart/tokens/client.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ class TokensClient:
2828
# With expiry, model restrictions, and constraints:
2929
token = await client.tokens.create(
3030
expires_in=120,
31-
allowed_models=["lucy-2"],
31+
allowed_models=["lucy-2.1"],
3232
constraints={"realtime": {"maxSessionDuration": 300}},
3333
)
3434
```
@@ -70,7 +70,7 @@ async def create(
7070
token = await client.tokens.create(
7171
metadata={"role": "viewer"},
7272
expires_in=120,
73-
allowed_models=["lucy-2"],
73+
allowed_models=["lucy-2.1"],
7474
constraints={"realtime": {"maxSessionDuration": 300}},
7575
)
7676
```

examples/realtime_synthetic.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ async def main():
7373
print("Creating synthetic video track...")
7474
video_track = SyntheticVideoTrack()
7575

76-
model = models.realtime("lucy-2")
76+
model = models.realtime("lucy-2.1")
7777
print(f"Using model: {model.name}")
7878
print(f"Model config - FPS: {model.fps}, Size: {model.width}x{model.height}")
7979

playground/playground.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -93,14 +93,13 @@ def _check_deps() -> None:
9393

9494
REALTIME_MODELS = [
9595
"lucy",
96-
"lucy-2",
9796
"lucy-2.1",
9897
"lucy-2.1-vton",
9998
"lucy-restyle",
10099
"lucy-restyle-2",
101100
"live-avatar",
102101
]
103-
CAMERA_MODELS = {"lucy", "lucy-2", "lucy-2.1", "lucy-2.1-vton", "lucy-restyle", "lucy-restyle-2"}
102+
CAMERA_MODELS = {"lucy", "lucy-2.1", "lucy-2.1-vton", "lucy-restyle", "lucy-restyle-2"}
104103
AVATAR_MODELS = {"live-avatar"}
105104

106105
BANNER = """
@@ -188,7 +187,7 @@ def parse_args() -> argparse.Namespace:
188187
%(prog)s --model lucy-restyle-2 --prompt "Anime style"
189188
%(prog)s --model live-avatar --image avatar.png
190189
%(prog)s --model live-avatar --image avatar.png --audio speech.mp3
191-
%(prog)s --model lucy-2 --image ref.png --prompt "Lego World"
190+
%(prog)s --model lucy-2.1 --image ref.png --prompt "Lego World"
192191
""",
193192
)
194193
p.add_argument("--model", "-m", choices=REALTIME_MODELS, help="Model name")
@@ -209,7 +208,7 @@ def select_model_interactive() -> str:
209208
note = ""
210209
if name in AVATAR_MODELS:
211210
note = " (requires --image)"
212-
elif name in ("lucy-2", "lucy-2.1", "lucy-2.1-vton", "lucy-restyle-2"):
211+
elif name in ("lucy-2.1", "lucy-2.1-vton", "lucy-restyle-2"):
213212
note = " (supports reference image)"
214213
print(f" {i}. {name}{note}")
215214

tests/test_models.py

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,6 @@ def test_canonical_realtime_models() -> None:
2424
assert model.width == 1280
2525
assert model.height == 704
2626

27-
model = models.realtime("lucy-2")
28-
assert model.name == "lucy-2"
29-
assert model.fps == 20
30-
assert model.width == 1280
31-
assert model.height == 720
32-
3327
model = models.realtime("lucy-2.1")
3428
assert model.name == "lucy-2.1"
3529
assert model.fps == 20
@@ -84,13 +78,6 @@ def test_canonical_video_models() -> None:
8478
assert model.name == "lucy-clip"
8579
assert model.url_path == "/v1/jobs/lucy-clip"
8680

87-
model = models.video("lucy-2")
88-
assert model.name == "lucy-2"
89-
assert model.url_path == "/v1/jobs/lucy-2"
90-
assert model.fps == 20
91-
assert model.width == 1280
92-
assert model.height == 720
93-
9481
model = models.video("lucy-2.1")
9582
assert model.name == "lucy-2.1"
9683
assert model.url_path == "/v1/jobs/lucy-2.1"
@@ -133,15 +120,6 @@ def test_deprecated_video_models() -> None:
133120
assert len(w) == 1
134121
assert "lucy-restyle-2" in str(w[0].message)
135122

136-
_warned_aliases.clear()
137-
138-
with warnings.catch_warnings(record=True) as w:
139-
warnings.simplefilter("always")
140-
model = models.video("lucy-2-v2v")
141-
assert model.name == "lucy-2-v2v"
142-
assert len(w) == 1
143-
assert '"lucy-2"' in str(w[0].message)
144-
145123

146124
def test_canonical_image_models() -> None:
147125
model = models.image("lucy-image-2")

tests/test_queue.py

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -269,70 +269,70 @@ async def test_queue_includes_user_agent_header() -> None:
269269
assert headers["User-Agent"].startswith("decart-python-sdk/")
270270

271271

272-
# Tests for lucy-2
272+
# Tests for lucy-2.1
273273

274274

275275
@pytest.mark.asyncio
276-
async def test_queue_lucy2_v2v_with_prompt() -> None:
276+
async def test_queue_lucy21_v2v_with_prompt() -> None:
277277
client = DecartClient(api_key="test-key")
278278

279279
with patch("decart.queue.client.submit_job") as mock_submit:
280-
mock_submit.return_value = MagicMock(job_id="job-lucy2", status="pending")
280+
mock_submit.return_value = MagicMock(job_id="job-lucy21", status="pending")
281281

282282
job = await client.queue.submit(
283283
{
284-
"model": models.video("lucy-2"),
284+
"model": models.video("lucy-2.1"),
285285
"prompt": "Restyle the scene with softer contrast and warmer highlights",
286286
"data": b"fake video data",
287287
"enhance_prompt": True,
288288
"seed": 42,
289289
}
290290
)
291291

292-
assert job.job_id == "job-lucy2"
292+
assert job.job_id == "job-lucy21"
293293
assert job.status == "pending"
294294
mock_submit.assert_called_once()
295295

296296

297297
@pytest.mark.asyncio
298-
async def test_queue_lucy2_v2v_with_empty_prompt_and_reference_image() -> None:
298+
async def test_queue_lucy21_v2v_with_empty_prompt_and_reference_image() -> None:
299299
client = DecartClient(api_key="test-key")
300300

301301
with patch("decart.queue.client.submit_job") as mock_submit:
302-
mock_submit.return_value = MagicMock(job_id="job-lucy2-ref", status="pending")
302+
mock_submit.return_value = MagicMock(job_id="job-lucy21-ref", status="pending")
303303

304304
job = await client.queue.submit(
305305
{
306-
"model": models.video("lucy-2"),
306+
"model": models.video("lucy-2.1"),
307307
"prompt": "",
308308
"reference_image": b"fake image data",
309309
"data": b"fake video data",
310310
}
311311
)
312312

313-
assert job.job_id == "job-lucy2-ref"
313+
assert job.job_id == "job-lucy21-ref"
314314
assert job.status == "pending"
315315
mock_submit.assert_called_once()
316316

317317

318318
@pytest.mark.asyncio
319-
async def test_queue_lucy2_v2v_with_both_prompt_and_reference_image() -> None:
319+
async def test_queue_lucy21_v2v_with_both_prompt_and_reference_image() -> None:
320320
client = DecartClient(api_key="test-key")
321321

322322
with patch("decart.queue.client.submit_job") as mock_submit:
323-
mock_submit.return_value = MagicMock(job_id="job-lucy2-both", status="pending")
323+
mock_submit.return_value = MagicMock(job_id="job-lucy21-both", status="pending")
324324

325325
job = await client.queue.submit(
326326
{
327-
"model": models.video("lucy-2"),
327+
"model": models.video("lucy-2.1"),
328328
"prompt": "Transform the scene",
329329
"reference_image": b"fake image data",
330330
"data": b"fake video data",
331331
"seed": 123,
332332
}
333333
)
334334

335-
assert job.job_id == "job-lucy2-both"
335+
assert job.job_id == "job-lucy21-both"
336336
assert job.status == "pending"
337337
mock_submit.assert_called_once()
338338

tests/test_realtime_unit.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,11 @@ def test_realtime_models_available():
4646
assert model2.height == 704
4747
assert model2.url_path == "/v1/stream"
4848

49-
model2 = models.realtime("lucy-2")
50-
assert model2.name == "lucy-2"
49+
model2 = models.realtime("lucy-2.1")
50+
assert model2.name == "lucy-2.1"
5151
assert model2.fps == 20
52-
assert model2.width == 1280
53-
assert model2.height == 720
52+
assert model2.width == 1088
53+
assert model2.height == 624
5454
assert model2.url_path == "/v1/stream"
5555

5656

tests/test_tokens.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -158,10 +158,10 @@ async def test_create_token_with_allowed_models() -> None:
158158
)
159159

160160
with patch.object(client, "_get_session", AsyncMock(return_value=mock_session)):
161-
await client.tokens.create(allowed_models=["lucy-2"])
161+
await client.tokens.create(allowed_models=["lucy-2.1"])
162162

163163
call_kwargs = mock_session.post.call_args
164-
assert call_kwargs.kwargs["json"] == {"allowedModels": ["lucy-2"]}
164+
assert call_kwargs.kwargs["json"] == {"allowedModels": ["lucy-2.1"]}
165165

166166

167167
@pytest.mark.asyncio
@@ -199,7 +199,7 @@ async def test_create_token_with_all_v2_fields() -> None:
199199
return_value={
200200
"apiKey": "ek_test123",
201201
"expiresAt": "2024-12-15T12:10:00Z",
202-
"permissions": {"models": ["lucy-2"]},
202+
"permissions": {"models": ["lucy-2.1"]},
203203
"constraints": {"realtime": {"maxSessionDuration": 120}},
204204
}
205205
)
@@ -213,19 +213,19 @@ async def test_create_token_with_all_v2_fields() -> None:
213213
result = await client.tokens.create(
214214
metadata={"role": "viewer"},
215215
expires_in=120,
216-
allowed_models=["lucy-2"],
216+
allowed_models=["lucy-2.1"],
217217
constraints={"realtime": {"maxSessionDuration": 120}},
218218
)
219219

220220
assert result.api_key == "ek_test123"
221221
assert result.expires_at == "2024-12-15T12:10:00Z"
222-
assert result.permissions == {"models": ["lucy-2"]}
222+
assert result.permissions == {"models": ["lucy-2.1"]}
223223
assert result.constraints == {"realtime": {"maxSessionDuration": 120}}
224224

225225
call_kwargs = mock_session.post.call_args
226226
assert call_kwargs.kwargs["json"] == {
227227
"metadata": {"role": "viewer"},
228228
"expiresIn": 120,
229-
"allowedModels": ["lucy-2"],
229+
"allowedModels": ["lucy-2.1"],
230230
"constraints": {"realtime": {"maxSessionDuration": 120}},
231231
}

0 commit comments

Comments
 (0)