|
@@ -7,12 +7,13 @@
|
|
@Software: PyCharm
|
|
@Software: PyCharm
|
|
"""
|
|
"""
|
|
import base64
|
|
import base64
|
|
-import imghdr
|
|
|
|
|
|
+import io
|
|
import json
|
|
import json
|
|
import logging
|
|
import logging
|
|
import re
|
|
import re
|
|
|
|
|
|
import boto3
|
|
import boto3
|
|
|
|
+from PIL import Image
|
|
|
|
|
|
LOGGER = logging.getLogger('time')
|
|
LOGGER = logging.getLogger('time')
|
|
|
|
|
|
@@ -94,44 +95,50 @@ class NovaImageTagObject(object):
|
|
return ""
|
|
return ""
|
|
b64_str = re.sub(r"^data:image/[^;]+;base64,", "", b64_str)
|
|
b64_str = re.sub(r"^data:image/[^;]+;base64,", "", b64_str)
|
|
b64_str = b64_str.strip().replace("\n", "").replace(" ", "")
|
|
b64_str = b64_str.strip().replace("\n", "").replace(" ", "")
|
|
|
|
+ # 补齐Base64填充
|
|
padding = 4 - (len(b64_str) % 4)
|
|
padding = 4 - (len(b64_str) % 4)
|
|
if padding and padding != 4:
|
|
if padding and padding != 4:
|
|
b64_str += "=" * padding
|
|
b64_str += "=" * padding
|
|
return b64_str
|
|
return b64_str
|
|
|
|
|
|
def process_image_batch(self, base64_images: list, categories: list, uid=''):
|
|
def process_image_batch(self, base64_images: list, categories: list, uid=''):
|
|
- """
|
|
|
|
- 通过单次API调用处理一批图片,并返回结构化的检测结果。
|
|
|
|
- """
|
|
|
|
if not base64_images:
|
|
if not base64_images:
|
|
LOGGER.error(f"{uid}错误: 未提供图片数据。")
|
|
LOGGER.error(f"{uid}错误: 未提供图片数据。")
|
|
return {}
|
|
return {}
|
|
|
|
|
|
image_contents = []
|
|
image_contents = []
|
|
- img_bytes_list = []
|
|
|
|
for idx, b64_image in enumerate(base64_images, start=1):
|
|
for idx, b64_image in enumerate(base64_images, start=1):
|
|
try:
|
|
try:
|
|
- # 规范化 base64
|
|
|
|
|
|
+ # 规范化base64
|
|
b64_image = self.normalize_b64(b64_image)
|
|
b64_image = self.normalize_b64(b64_image)
|
|
if not b64_image:
|
|
if not b64_image:
|
|
raise ValueError("空的base64字符串")
|
|
raise ValueError("空的base64字符串")
|
|
|
|
|
|
- img_bytes = base64.b64decode(b64_image) # 原始二进制
|
|
|
|
- img_type = imghdr.what(None, h=img_bytes)
|
|
|
|
- if not img_type or img_type.lower() not in ["jpeg", "jpg", "png", "webp"]:
|
|
|
|
- raise ValueError(f"不支持的图片格式: {img_type}")
|
|
|
|
|
|
+ # 解码为二进制
|
|
|
|
+ img_bytes = base64.b64decode(b64_image)
|
|
|
|
+
|
|
|
|
+ # 使用PIL处理图像
|
|
|
|
+ image = Image.open(io.BytesIO(img_bytes))
|
|
|
|
+
|
|
|
|
+ # 转换为RGB模式(如果需要)
|
|
|
|
+ if image.mode != 'RGB':
|
|
|
|
+ image = image.convert('RGB')
|
|
|
|
+
|
|
|
|
+ # 转换为WebP格式
|
|
|
|
+ buffer = io.BytesIO()
|
|
|
|
+ image.save(buffer, format="webp", quality=90)
|
|
|
|
+ img_bytes = buffer.getvalue()
|
|
|
|
|
|
- # 直接传原始二进制
|
|
|
|
|
|
+ # 直接传递二进制数据给Bedrock
|
|
image_contents.append({
|
|
image_contents.append({
|
|
- "image": {"format": img_type.lower(), "source": {"bytes": img_bytes}}
|
|
|
|
|
|
+ "image": {"format": "webp", "source": {"bytes": img_bytes}}
|
|
})
|
|
})
|
|
- img_bytes_list.append(img_bytes)
|
|
|
|
|
|
|
|
- LOGGER.info(f"{uid} 第{idx}张图处理成功, 格式={img_type}, 大小={len(img_bytes)}B")
|
|
|
|
|
|
+ LOGGER.info(f"{uid} 第{idx}张图处理成功, 格式=webp, 大小={len(img_bytes)}B")
|
|
|
|
|
|
except Exception as e:
|
|
except Exception as e:
|
|
- LOGGER.error(f"{uid} 第{idx}张图处理失败,已跳过: {repr(e)} (长度={len(b64_image) if b64_image else 0})")
|
|
|
|
- img_bytes_list.append(None) # 添加占位符以保持索引一致
|
|
|
|
|
|
+ LOGGER.error(f"{uid} 第{idx}张图处理失败,已跳过: {repr(e)}")
|
|
|
|
+ image_contents.append(None) # 添加占位符
|
|
|
|
|
|
if not image_contents:
|
|
if not image_contents:
|
|
LOGGER.error(f"{uid}错误: 所有图片均无法处理。")
|
|
LOGGER.error(f"{uid}错误: 所有图片均无法处理。")
|