diff --git a/lightllm/server/api_models.py b/lightllm/server/api_models.py index eb10c5b384..b2cd53a4c1 100644 --- a/lightllm/server/api_models.py +++ b/lightllm/server/api_models.py @@ -447,19 +447,19 @@ class ImageConfig(BaseModel): cfg_norm: Optional[Literal["none", "cfg_zero_star", "global", "text_channel", "channel"]] = None dynamic_resolution: Optional[bool] = True _aspect_ratio_to_resolution: ClassVar[dict] = { - "1:1": {"1K": (1024, 1024), "1.5K": (1536, 1536), "2K": (2048, 2048)}, - "16:9": {"1.5K": (2048, 1152), "2K": (2720, 1536)}, - "9:16": {"1.5K": (1152, 2048), "2K": (1536, 2720)}, - "3:2": {"1.5K": (1888, 1248), "2K": (2496, 1664)}, - "2:3": {"1.5K": (1248, 1888), "2K": (1664, 2496)}, - "4:3": {"1.5K": (1760, 1312), "2K": (2368, 1760)}, - "3:4": {"1.5K": (1312, 1760), "2K": (1760, 2368)}, - "1:2": {"1.5K": (1088, 2144), "2K": (1440, 2880)}, - "2:1": {"1.5K": (2144, 1088), "2K": (2880, 1440)}, - "1:3": {"1.5K": (864, 2592), "2K": (1152, 3456)}, - "3:1": {"1.5K": (2592, 864), "2K": (3456, 1152)}, + "1:1": {"1K": (1024, 1024), "1.5K": (1536, 1536), "2K": (2048, 2048), "4K": (4096, 4096)}, + "16:9": {"1.5K": (2048, 1152), "2K": (2720, 1536), "4K": (4096, 2304)}, + "9:16": {"1.5K": (1152, 2048), "2K": (1536, 2720), "4K": (2304, 4096)}, + "3:2": {"1.5K": (1888, 1248), "2K": (2496, 1664), "4K": (4096, 2720)}, + "2:3": {"1.5K": (1248, 1888), "2K": (1664, 2496), "4K": (2720, 4096)}, + "4:3": {"1.5K": (1760, 1312), "2K": (2368, 1760), "4K": (4096, 3072)}, + "3:4": {"1.5K": (1312, 1760), "2K": (1760, 2368), "4K": (3072, 4096)}, + "1:2": {"1.5K": (1088, 2144), "2K": (1440, 2880), "4K": (2048, 4096)}, + "2:1": {"1.5K": (2144, 1088), "2K": (2880, 1440), "4K": (4096, 2048)}, + "1:3": {"1.5K": (864, 2592), "2K": (1152, 3456), "4K": (1376, 4096)}, + "3:1": {"1.5K": (2592, 864), "2K": (3456, 1152), "4K": (4096, 1376)}, } - _size_set: ClassVar[set[str]] = {"1.5K", "2K"} + _size_set: ClassVar[set[str]] = {"1.5K", "2K", "4K"} @field_validator("image_size", mode="before") @classmethod @@ -508,7 +508,7 @@ def get_resolution(self): base = self._aspect_ratio_to_resolution[self.aspect_ratio][self.image_size] w, h = base - h, w = smart_resize(h, w, factor=32, min_pixels=1024 * 1024, max_pixels=2048 * 2048) + h, w = smart_resize(h, w, factor=32, min_pixels=1024 * 1024, max_pixels=4096 * 4096) return w, h diff --git a/lightllm/server/build_prompt.py b/lightllm/server/build_prompt.py index 84044fccce..827c172fe6 100644 --- a/lightllm/server/build_prompt.py +++ b/lightllm/server/build_prompt.py @@ -79,11 +79,37 @@ def _alias_reasoning_to_reasoning_content(messages: list) -> None: msg["reasoning_content"] = reasoning +def _flatten_multimodal_content(messages: list) -> None: + # OpenAI-style chat requests may send content as a list of parts + # ({"type": "text", ...}, {"type": "image_url", ...}). Most HF chat + # templates (Qwen, LLaMA, ...) call string methods on `content` directly + # and crash on lists. Flatten into a plain string with placeholder tokens + # so the template can render; the image data itself is already extracted + # upstream via `_get_images_and_audios` and fed through MultimodalParams. + for msg in messages: + content = msg.get("content") + if not isinstance(content, list): + continue + parts: list = [] + for item in content: + if not isinstance(item, dict): + continue + t = item.get("type") + if t == "text": + parts.append(item.get("text", "") or "") + elif t == "image_url": + parts.append("") + elif t == "audio_url": + parts.append("