perf(review): 安装 Pillow 并优化截图下采样策略
- 视觉 token 成本由像素尺寸决定,故仅在长边超过 IMAGE_MAX_EDGE(默认1280) 时才缩放 - 不需要缩放且格式未变时原样返回,不重新编码,避免 CAD 线稿的无谓压缩损失 - 缩放后默认输出无损 PNG(IMAGE_FORMAT=png),可设 jpeg 换取更小体积 - 缺少 Pillow 时自动降级为原图直传
This commit is contained in:
1 parent
ec5292debe
commit
1cbcbb92f4
3 files changed
+35
-12
No files matched your search
@@ -23,28 +23,46 @@ class LlmError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def downsample_image_b64(b64, mime="image/png", max_edge=None, quality=None):
|
||||
"""把 base64 截图下采样并转 JPEG,降低视觉 token 成本。
|
||||
def downsample_image_b64(b64, mime="image/png", max_edge=None, fmt=None, quality=None):
|
||||
"""缩放截图,降低视觉 token 成本。
|
||||
|
||||
缺少 Pillow 或参数为 0 时原样返回 (b64, mime)。
|
||||
策略(视觉 token 成本主要由**像素尺寸**决定,而非文件大小):
|
||||
- 仅当长边超过 `max_edge` 时才缩放;
|
||||
- 既不需要缩放、目标格式又与原格式一致时,**原样返回**(不重新编码,
|
||||
避免给 CAD 线稿引入无谓的压缩损失);
|
||||
- 需要缩放时按 `fmt` 编码:`png`(默认,无损,适合线稿)/ `jpeg`(体积更小)。
|
||||
|
||||
缺少 Pillow 或 max_edge <= 0 时原样返回 (b64, mime)。
|
||||
"""
|
||||
max_edge = config.IMAGE_MAX_EDGE if max_edge is None else max_edge
|
||||
fmt = (config.IMAGE_FORMAT if fmt is None else fmt).strip().lower()
|
||||
quality = config.IMAGE_JPEG_QUALITY if quality is None else quality
|
||||
if not HAS_PIL or max_edge <= 0:
|
||||
return b64, mime
|
||||
|
||||
target_mime = "image/jpeg" if fmt == "jpeg" else "image/png"
|
||||
try:
|
||||
img = Image.open(io.BytesIO(base64.b64decode(b64)))
|
||||
if img.mode not in ("RGB", "L"):
|
||||
img = img.convert("RGB")
|
||||
w, h = img.size
|
||||
scale = max_edge / float(max(w, h))
|
||||
if scale < 1.0:
|
||||
need_resize = scale < 1.0
|
||||
|
||||
if not need_resize and mime == target_mime:
|
||||
return b64, mime
|
||||
|
||||
if need_resize:
|
||||
img = img.resize(
|
||||
(max(1, int(w * scale)), max(1, int(h * scale))), Image.LANCZOS
|
||||
)
|
||||
|
||||
buf = io.BytesIO()
|
||||
img.save(buf, format="JPEG", quality=quality)
|
||||
return base64.b64encode(buf.getvalue()).decode("ascii"), "image/jpeg"
|
||||
if target_mime == "image/jpeg":
|
||||
if img.mode not in ("RGB", "L"):
|
||||
img = img.convert("RGB")
|
||||
img.save(buf, format="JPEG", quality=quality)
|
||||
else:
|
||||
img.save(buf, format="PNG", optimize=True)
|
||||
return base64.b64encode(buf.getvalue()).decode("ascii"), target_mime
|
||||
except Exception:
|
||||
return b64, mime
|
||||
|
||||
|
||||
Reference in new issue
Block a user