feat(api): support remote image URL downloading in chat completion
Browse files- Extract image from URL or base64 instead of base64 only
- Add support for downloading remote image URLs starting with http/https
- Implement error handling for image download failures
- Add debug logging for image processing steps
fix(config): update model keys for veo_3_0 video generation
- Update veo_3_0_r2v_fast_portrait model key to
veo_3_0_r2v_fast_portrait_ultra_relaxed
- Update veo_3_0_r2v_fast_landscape model key to
veo_3_0_r2v_fast_ultra_relaxed
- src/api/routes.py +13 -1
- src/services/generation_handler.py +2 -2
src/api/routes.py
CHANGED
|
@@ -111,7 +111,7 @@ async def create_chat_completion(
|
|
| 111 |
if item.get("type") == "text":
|
| 112 |
prompt = item.get("text", "")
|
| 113 |
elif item.get("type") == "image_url":
|
| 114 |
-
# Extract
|
| 115 |
image_url = item.get("image_url", {}).get("url", "")
|
| 116 |
if image_url.startswith("data:image"):
|
| 117 |
# Parse base64
|
|
@@ -120,6 +120,18 @@ async def create_chat_completion(
|
|
| 120 |
image_base64 = match.group(1)
|
| 121 |
image_bytes = base64.b64decode(image_base64)
|
| 122 |
images.append(image_bytes)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 123 |
|
| 124 |
# Fallback to deprecated image parameter
|
| 125 |
if request.image and not images:
|
|
|
|
| 111 |
if item.get("type") == "text":
|
| 112 |
prompt = item.get("text", "")
|
| 113 |
elif item.get("type") == "image_url":
|
| 114 |
+
# Extract image from URL or base64
|
| 115 |
image_url = item.get("image_url", {}).get("url", "")
|
| 116 |
if image_url.startswith("data:image"):
|
| 117 |
# Parse base64
|
|
|
|
| 120 |
image_base64 = match.group(1)
|
| 121 |
image_bytes = base64.b64decode(image_base64)
|
| 122 |
images.append(image_bytes)
|
| 123 |
+
elif image_url.startswith("http://") or image_url.startswith("https://"):
|
| 124 |
+
# Download remote image URL
|
| 125 |
+
debug_logger.log_info(f"[IMAGE_URL] 下载远程图片: {image_url}")
|
| 126 |
+
try:
|
| 127 |
+
downloaded_bytes = await retrieve_image_data(image_url)
|
| 128 |
+
if downloaded_bytes and len(downloaded_bytes) > 0:
|
| 129 |
+
images.append(downloaded_bytes)
|
| 130 |
+
debug_logger.log_info(f"[IMAGE_URL] ✅ 远程图片下载成功: {len(downloaded_bytes)} 字节")
|
| 131 |
+
else:
|
| 132 |
+
debug_logger.log_warning(f"[IMAGE_URL] ⚠️ 远程图片下载失败或为空: {image_url}")
|
| 133 |
+
except Exception as e:
|
| 134 |
+
debug_logger.log_error(f"[IMAGE_URL] ❌ 远程图片下载异常: {str(e)}")
|
| 135 |
|
| 136 |
# Fallback to deprecated image parameter
|
| 137 |
if request.image and not images:
|
src/services/generation_handler.py
CHANGED
|
@@ -172,7 +172,7 @@ MODEL_CONFIG = {
|
|
| 172 |
"veo_3_0_r2v_fast_portrait": {
|
| 173 |
"type": "video",
|
| 174 |
"video_type": "r2v",
|
| 175 |
-
"model_key": "
|
| 176 |
"aspect_ratio": "VIDEO_ASPECT_RATIO_PORTRAIT",
|
| 177 |
"supports_images": True,
|
| 178 |
"min_images": 0,
|
|
@@ -181,7 +181,7 @@ MODEL_CONFIG = {
|
|
| 181 |
"veo_3_0_r2v_fast_landscape": {
|
| 182 |
"type": "video",
|
| 183 |
"video_type": "r2v",
|
| 184 |
-
"model_key": "
|
| 185 |
"aspect_ratio": "VIDEO_ASPECT_RATIO_LANDSCAPE",
|
| 186 |
"supports_images": True,
|
| 187 |
"min_images": 0,
|
|
|
|
| 172 |
"veo_3_0_r2v_fast_portrait": {
|
| 173 |
"type": "video",
|
| 174 |
"video_type": "r2v",
|
| 175 |
+
"model_key": "veo_3_0_r2v_fast_portrait_ultra_relaxed",
|
| 176 |
"aspect_ratio": "VIDEO_ASPECT_RATIO_PORTRAIT",
|
| 177 |
"supports_images": True,
|
| 178 |
"min_images": 0,
|
|
|
|
| 181 |
"veo_3_0_r2v_fast_landscape": {
|
| 182 |
"type": "video",
|
| 183 |
"video_type": "r2v",
|
| 184 |
+
"model_key": "veo_3_0_r2v_fast_ultra_relaxed",
|
| 185 |
"aspect_ratio": "VIDEO_ASPECT_RATIO_LANDSCAPE",
|
| 186 |
"supports_images": True,
|
| 187 |
"min_images": 0,
|