|
@@ -7,13 +7,12 @@
|
|
|
@Software: PyCharm
|
|
|
"""
|
|
|
import base64
|
|
|
-import io
|
|
|
+import imghdr
|
|
|
import json
|
|
|
import logging
|
|
|
import re
|
|
|
|
|
|
import boto3
|
|
|
-from PIL import Image
|
|
|
|
|
|
LOGGER = logging.getLogger('time')
|
|
|
|
|
@@ -88,74 +87,28 @@ class NovaImageTagObject(object):
|
|
|
})
|
|
|
return formatted_results
|
|
|
|
|
|
- @staticmethod
|
|
|
- def normalize_b64(b64_str: str) -> str:
|
|
|
- """清理并验证base64字符串"""
|
|
|
- if not b64_str:
|
|
|
- return ""
|
|
|
-
|
|
|
- # 移除可能的数据URL前缀
|
|
|
- b64_str = re.sub(r"^data:image/[^;]+;base64,", "", b64_str)
|
|
|
-
|
|
|
- # 移除所有非Base64字符(包括空格、换行等)
|
|
|
- b64_str = re.sub(r"[^A-Za-z0-9+/=]", "", b64_str)
|
|
|
-
|
|
|
- # 检查Base64有效性
|
|
|
- if len(b64_str) % 4 != 0:
|
|
|
- # 自动补全填充位
|
|
|
- b64_str += "=" * (4 - len(b64_str) % 4)
|
|
|
-
|
|
|
- return b64_str
|
|
|
-
|
|
|
def process_image_batch(self, base64_images: list, categories: list, uid=''):
|
|
|
+ """
|
|
|
+ 通过单次API调用处理一批图片,并返回结构化的检测结果。
|
|
|
+ """
|
|
|
if not base64_images:
|
|
|
LOGGER.error(f"{uid}错误: 未提供图片数据。")
|
|
|
return {}
|
|
|
|
|
|
image_contents = []
|
|
|
- for idx, b64_image in enumerate(base64_images, start=1):
|
|
|
+ img_bytes_list = []
|
|
|
+ for b64_image in base64_images:
|
|
|
try:
|
|
|
- # 规范化base64
|
|
|
- original_b64 = b64_image # 保存原始值用于调试
|
|
|
- b64_image = self.normalize_b64(b64_image)
|
|
|
-
|
|
|
- if not b64_image:
|
|
|
- raise ValueError("空的base64字符串")
|
|
|
-
|
|
|
- # 调试输出
|
|
|
- LOGGER.debug(f"{uid} 第{idx}张图处理前: {original_b64[:50]}...")
|
|
|
- LOGGER.debug(f"{uid} 第{idx}张图处理后: {b64_image[:50]}...")
|
|
|
-
|
|
|
- # 解码为二进制
|
|
|
+ LOGGER.info('{}:{}'.format(uid, b64_image))
|
|
|
img_bytes = base64.b64decode(b64_image)
|
|
|
-
|
|
|
- # 验证解码后的数据
|
|
|
- if len(img_bytes) == 0:
|
|
|
- raise ValueError("解码后得到空字节数据")
|
|
|
-
|
|
|
- # 使用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)
|
|
|
- webp_bytes = buffer.getvalue()
|
|
|
-
|
|
|
- image_contents.append({
|
|
|
- "image": {"format": "webp", "source": {"bytes": webp_bytes}}
|
|
|
- })
|
|
|
-
|
|
|
- LOGGER.info(f"{uid} 第{idx}张图处理成功, 格式=webp, 大小={len(webp_bytes)}B")
|
|
|
-
|
|
|
+ img_type = imghdr.what(None, h=img_bytes)
|
|
|
+ if img_type.lower() not in ["jpeg", "jpg", "png", "webp"]:
|
|
|
+ raise ValueError(f"不支持的图片格式: {img_type}")
|
|
|
+ image_contents.append({"image": {"format": img_type, "source": {"bytes": img_bytes}}})
|
|
|
+ img_bytes_list.append(img_bytes)
|
|
|
except Exception as e:
|
|
|
- LOGGER.error(f"{uid} 第{idx}张图处理失败: {repr(e)}")
|
|
|
- LOGGER.debug(f"{uid}失败图像的Base64前100字符: {b64_image[:100]}")
|
|
|
- # 不要添加None,而是跳过或使用占位符图像
|
|
|
- continue # 直接跳过这张图
|
|
|
+ LOGGER.error(f"{uid}处理图片时出错,已跳过: {repr(e)}")
|
|
|
+ img_bytes_list.append(None) # 添加占位符以保持索引一致
|
|
|
|
|
|
if not image_contents:
|
|
|
LOGGER.error(f"{uid}错误: 所有图片均无法处理。")
|