| 373 | |
| 374 | @dataclass |
| 375 | class ReferenceImageSpec: |
| 376 | path: str |
| 377 | mode: str |
| 378 | |
| 379 | def __post_init__(self) -> None: |
| 380 | normalized = self.mode.lower() |
| 381 | if normalized not in REFERENCE_MODE_CHOICES: |
| 382 | raise ValueError(f"Unsupported reference image mode: {self.mode}") |
| 383 | self.mode = normalized |
| 384 | |
| 385 | def build_message(self, model: str, size: str) -> Dict[str, str]: |
| 386 | if cv2 is None: |
| 387 | raise RuntimeError("opencv-python not found, please install and try again.") |
| 388 | if not os.path.exists(self.path): |
| 389 | raise FileNotFoundError(f"Reference image does not exist: {self.path}") |
| 390 | |
| 391 | image = cv2.imread(self.path) |
| 392 | if image is None: |
| 393 | raise RuntimeError(f"Failed to read reference image: {self.path}") |
| 394 | |
| 395 | resized = image |
| 396 | if model.startswith("sora"): |
| 397 | target_size = size_str_to_tuple(size) |
| 398 | if target_size: |
| 399 | resized = cv2.resize(image, target_size, interpolation=cv2.INTER_AREA) |
| 400 | |
| 401 | success, buffer = cv2.imencode(".png", resized) |
| 402 | if not success: |
| 403 | raise RuntimeError(f"Image encoding failed: {self.path}") |
| 404 | image_data = base64.b64encode(buffer.tobytes()).decode("utf-8") |
| 405 | |
| 406 | # Special handling for Wan2.5 and ViduQ2 models: use simple image_url format |
| 407 | if model in ("Wan2.5", "ViduQ2"): |
| 408 | return { |
| 409 | "type": "image_url", |
| 410 | "value": f"data:image/png;base64,{image_data}", |
| 411 | } |
| 412 | |
| 413 | # Processing for other models |
| 414 | if self.mode == "first": |
| 415 | return { |
| 416 | "type": "image_url", |
| 417 | "value": f"data:image/png;base64,{image_data}", |
| 418 | } |
| 419 | return { |
| 420 | "type": "reference_image_url", |
| 421 | "value": f"data:image/png;base64,{image_data}", |
| 422 | "reference_type": self.mode, |
| 423 | } |
| 424 | |
| 425 | |
| 426 | @dataclass |
no outgoing calls
no test coverage detected