"""`resolution` × `ratio` → 像素宽高的对照表。 **这是纯静态数据,不需要查询任何东西、也不依赖存储方案。** 厂商的查询接口会返回 `ratio` 与 `resolution`(但不返回像素值),查本表即可换算——无需下载产物、无需 探测文件。数值逐格取自官方文档「不同宽高比对应的宽高像素值」一节。 有了它,`widthPx`/`heightPx` 在 AI 视频产物上就能填真实值,而不必等到把文件 下载下来解码——这也正是 ADR-023 §11 所说「AI 输出路径不需要解码」的落地方式。 **实现上的一个关键观察**:Seedance 2.5 与 2.0 系列的 24 格里**只有两格不同** (480p 的 `16:9` 与 `9:16`),其余完全一致。故实现为「共享表 + 两格覆盖」, 而不是抄两份 24 行——后者每次改动都要改两处,迟早只改一处。 """ from __future__ import annotations from .capabilities import SEEDANCE_2_0, SEEDANCE_2_5, ModelLimits #: (resolution, ratio) → (width, height)。两个模型族共用的 22 格。 _SHARED: dict[tuple[str, str], tuple[int, int]] = { ("480p", "4:3"): (752, 560), ("480p", "1:1"): (640, 640), ("480p", "3:4"): (560, 752), ("480p", "21:9"): (992, 432), ("720p", "16:9"): (1280, 720), ("720p", "4:3"): (1112, 834), ("720p", "1:1"): (960, 960), ("720p", "3:4"): (834, 1112), ("720p", "9:16"): (720, 1280), ("720p", "21:9"): (1470, 630), ("1080p", "16:9"): (1920, 1080), ("1080p", "4:3"): (1664, 1248), ("1080p", "1:1"): (1440, 1440), ("1080p", "3:4"): (1248, 1664), ("1080p", "9:16"): (1080, 1920), ("1080p", "21:9"): (2206, 946), } #: 2.5 与 2.0 系列**唯一**不同的两格:480p 的 16:9 与 9:16。 _OVERRIDES_2_5: dict[tuple[str, str], tuple[int, int]] = { ("480p", "16:9"): (854, 480), ("480p", "9:16"): (480, 854), } _OVERRIDES_2_0: dict[tuple[str, str], tuple[int, int]] = { ("480p", "16:9"): (864, 496), ("480p", "9:16"): (496, 864), # 4k 仅 2.0 系列支持。 ("4k", "16:9"): (3840, 2160), ("4k", "4:3"): (3326, 2494), ("4k", "1:1"): (2880, 2880), ("4k", "3:4"): (2494, 3326), ("4k", "9:16"): (2160, 3840), ("4k", "21:9"): (4398, 1886), } _BY_FAMILY: dict[int, dict[tuple[str, str], tuple[int, int]]] = { id(SEEDANCE_2_5): {**_SHARED, **_OVERRIDES_2_5}, id(SEEDANCE_2_0): {**_SHARED, **_OVERRIDES_2_0}, } def pixels_for( limits: ModelLimits | None, resolution: str | None, ratio: str | None ) -> tuple[int | None, int | None]: """查像素宽高;查不到返回 `(None, None)`。 查不到的三种情形都**返回 None 而不猜**——一个错的尺寸比留空更糟,它会让 客户端按错误的比例渲染,而且看不出是错的: 1. **`ratio` 为 `adaptive`**:厂商在图生视频时自动适配首帧图片的比例。查询 响应是否把它解析成具体比例、抑或原样返回 `adaptive`,文档未明确说明; 原样返回时本表无从查起。 2. **未知模型族**:能力表放行了未知模型(见 `capabilities.py`),但像素值 无法凭空推断。 3. **该模型不支持的组合**:如 2.5 的 4k——本不该发生(提交前已预校验), 出现即说明厂商行为与文档不符,留空并让上层看到缺值。 """ if limits is None or not resolution or not ratio: return (None, None) table = _BY_FAMILY.get(id(limits)) if table is None: return (None, None) found = table.get((resolution, ratio)) return found if found else (None, None)