post_evaluator_v4_image_loader.py 2.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. """
  2. ImageUploader 新实现 - 使用PIL Image对象
  3. 参考demo,直接下载图片到内存并转为PIL Image,不上传文件
  4. """
  5. import asyncio
  6. import requests
  7. from PIL import Image
  8. import io
  9. from typing import Optional, List, Any
  10. class ImageUploader:
  11. """图片加载器 - 下载图片并转为PIL Image对象(参考demo,使用内联数据方式)"""
  12. @staticmethod
  13. async def upload_images(image_urls: List[str]) -> tuple[List[Any], List[str]]:
  14. """
  15. 批量下载图片并转为PIL Image对象
  16. Args:
  17. image_urls: 图片URL列表
  18. Returns:
  19. (image_objects, []) - PIL Image对象列表和空列表(保持接口兼容)
  20. """
  21. if not image_urls:
  22. return [], []
  23. print(f" 📥 准备加载 {len(image_urls)} 张图片(PIL Image方式)...")
  24. # 并发下载所有图片
  25. tasks = [ImageUploader._load_single_image(url, idx) for idx, url in enumerate(image_urls)]
  26. results = await asyncio.gather(*tasks, return_exceptions=True)
  27. # 分离成功和失败的结果
  28. image_objects = []
  29. for idx, result in enumerate(results):
  30. if isinstance(result, Exception):
  31. print(f" ⚠️ 图片{idx}加载失败: {str(result)[:50]}")
  32. elif result is not None:
  33. image_objects.append(result)
  34. print(f" ✅ 成功加载 {len(image_objects)}/{len(image_urls)} 张图片")
  35. return image_objects, [] # 返回空列表作为temp_paths,因为不需要清理
  36. @staticmethod
  37. async def _load_single_image(image_url: str, idx: int) -> Optional[Any]:
  38. """
  39. 下载单张图片并转为PIL Image对象
  40. Args:
  41. image_url: 图片URL
  42. idx: 图片索引(用于日志)
  43. Returns:
  44. PIL Image对象
  45. """
  46. try:
  47. # 下载图片到内存
  48. loop = asyncio.get_event_loop()
  49. response = await loop.run_in_executor(
  50. None,
  51. lambda: requests.get(image_url, timeout=30)
  52. )
  53. response.raise_for_status()
  54. # 转换为PIL Image对象
  55. image = Image.open(io.BytesIO(response.content))
  56. # 转换为RGB模式(Gemini推荐)
  57. if image.mode != 'RGB':
  58. image = image.convert('RGB')
  59. file_size_kb = len(response.content) / 1024
  60. print(f" ✓ 图片{idx}加载成功 ({file_size_kb:.1f}KB, {image.size[0]}x{image.size[1]})")
  61. return image
  62. except Exception as e:
  63. print(f" ✗ 图片{idx}加载失败: {str(e)[:60]}")
  64. return None