nomid2 commited on
Commit
6335cf0
·
verified ·
1 Parent(s): 72566c7

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +102 -8
app.py CHANGED
@@ -182,6 +182,51 @@ def decode_base64_file(data_url: str) -> tuple[str, str, str]:
182
  logger.error(f"Failed to parse data URL: {e}")
183
  return None, None, None
184
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
185
  async def upload_image_to_imgbb(base64_data: str) -> str:
186
  """
187
  将 base64 图片上传到 imgbb
@@ -280,6 +325,25 @@ def format_image_as_data_url(base64_data: str) -> str:
280
  logger.warning(f"Failed to detect image format: {e}, using JPEG as default")
281
  return f"data:image/jpeg;base64,{base64_data}"
282
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
283
  def extract_content_from_message(message: Dict[str, Any]) -> tuple[str, List[str], List[Dict[str, str]]]:
284
  """
285
  从消息中提取文本内容、图片和文件
@@ -290,7 +354,10 @@ def extract_content_from_message(message: Dict[str, Any]) -> tuple[str, List[str
290
  files = []
291
 
292
  if isinstance(content, str):
293
- # 简单文本消息
 
 
 
294
  return content, images, files
295
  elif isinstance(content, list):
296
  # 复合消息(文本 + 图片 + 文件)
@@ -301,7 +368,12 @@ def extract_content_from_message(message: Dict[str, Any]) -> tuple[str, List[str
301
  item_type = item.get("type", "")
302
 
303
  if item_type == "text":
304
- text_parts.append(item.get("text", ""))
 
 
 
 
 
305
 
306
  elif item_type == "image_url":
307
  image_url = item.get("image_url", {})
@@ -319,8 +391,12 @@ def extract_content_from_message(message: Dict[str, Any]) -> tuple[str, List[str
319
  logger.warning(f"Image URL format not supported: {url[:100]}...")
320
  except Exception as e:
321
  logger.error(f"Error processing image: {e}")
 
 
 
 
322
  else:
323
- logger.warning(f"External image URLs not supported: {url}")
324
 
325
  elif item_type == "file" or (item_type == "image_url" and not item.get("image_url", {}).get("url", "").startswith("data:image/")):
326
  # 处理文件上传
@@ -349,6 +425,10 @@ def extract_content_from_message(message: Dict[str, Any]) -> tuple[str, List[str
349
 
350
  elif isinstance(item, str):
351
  text_parts.append(item)
 
 
 
 
352
 
353
  return " ".join(text_parts), images, files
354
 
@@ -450,11 +530,24 @@ async def transform_openai_to_replicate(openai_request: Dict[str, Any], model_ov
450
  formatted_image = None
451
  if has_images and primary_image:
452
  logger.info(f"Processing image for model {model} with format {model_config.get('image_format')}")
453
- formatted_image = await format_image_for_model(primary_image, model_config)
454
 
455
- if not formatted_image:
456
- logger.error("Failed to format image for model")
457
- raise HTTPException(status_code=500, detail="Failed to process image")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
458
 
459
  # 构建 Replicate 格式的输入
460
  replicate_input = {}
@@ -661,10 +754,11 @@ async def root():
661
  "status": "running",
662
  "replicate_token_configured": bool(REPLICATE_API_TOKEN),
663
  "imgbb_token_configured": bool(IMGBB_API_KEY),
664
- "version": "1.2.2",
665
  "supported_models": list(MODEL_CONFIGS.keys()),
666
  "vision_support": True,
667
  "file_support": True,
 
668
  "supported_text_files": list(SUPPORTED_TEXT_EXTENSIONS),
669
  "supported_image_files": list(SUPPORTED_IMAGE_EXTENSIONS),
670
  "claude4_vision_support": "Full support via imgbb image hosting"
 
182
  logger.error(f"Failed to parse data URL: {e}")
183
  return None, None, None
184
 
185
+ async def download_image_from_url(url: str) -> str:
186
+ """
187
+ 从URL下载图片并转换为base64
188
+ 返回base64编码的图片数据
189
+ """
190
+ try:
191
+ logger.info(f"Downloading image from URL: {url}")
192
+
193
+ async with aiohttp.ClientSession() as session:
194
+ async with session.get(url, timeout=30) as response:
195
+ if response.status == 200:
196
+ image_bytes = await response.read()
197
+
198
+ # 检测图片格式
199
+ content_type = response.headers.get('content-type', '')
200
+ if not content_type.startswith('image/'):
201
+ # 尝试从文件扩展名推断
202
+ if url.lower().endswith(('.jpg', '.jpeg')):
203
+ content_type = 'image/jpeg'
204
+ elif url.lower().endswith('.png'):
205
+ content_type = 'image/png'
206
+ elif url.lower().endswith('.gif'):
207
+ content_type = 'image/gif'
208
+ elif url.lower().endswith('.webp'):
209
+ content_type = 'image/webp'
210
+ else:
211
+ content_type = 'image/jpeg' # 默认
212
+
213
+ # 转换为base64
214
+ base64_data = base64.b64encode(image_bytes).decode('utf-8')
215
+ data_url = f"data:{content_type};base64,{base64_data}"
216
+
217
+ logger.info(f"Successfully downloaded image, size: {len(image_bytes)} bytes, base64 size: {len(base64_data)} chars")
218
+ return data_url
219
+ else:
220
+ logger.error(f"Failed to download image: HTTP {response.status}")
221
+ return None
222
+
223
+ except asyncio.TimeoutError:
224
+ logger.error(f"Timeout downloading image from {url}")
225
+ return None
226
+ except Exception as e:
227
+ logger.error(f"Error downloading image from {url}: {e}")
228
+ return None
229
+
230
  async def upload_image_to_imgbb(base64_data: str) -> str:
231
  """
232
  将 base64 图片上传到 imgbb
 
325
  logger.warning(f"Failed to detect image format: {e}, using JPEG as default")
326
  return f"data:image/jpeg;base64,{base64_data}"
327
 
328
+ def extract_images_from_context(content: str) -> List[str]:
329
+ """
330
+ 从系统上下文中提取图片URL
331
+ """
332
+ images = []
333
+ try:
334
+ # 查找类似 <image name="..." url="..."></image> 的标签
335
+ import re
336
+ pattern = r'<image[^>]+url="([^"]+)"[^>]*></image>'
337
+ matches = re.findall(pattern, content)
338
+ for url in matches:
339
+ if url.startswith('http'):
340
+ images.append(url)
341
+ logger.info(f"Found image URL in context: {url}")
342
+ except Exception as e:
343
+ logger.error(f"Error extracting images from context: {e}")
344
+
345
+ return images
346
+
347
  def extract_content_from_message(message: Dict[str, Any]) -> tuple[str, List[str], List[Dict[str, str]]]:
348
  """
349
  从消息中提取文本内容、图片和文件
 
354
  files = []
355
 
356
  if isinstance(content, str):
357
+ # 检查文本内容中是否包含系统上下文中的图片
358
+ context_images = extract_images_from_context(content)
359
+ if context_images:
360
+ images.extend(context_images)
361
  return content, images, files
362
  elif isinstance(content, list):
363
  # 复合消息(文本 + 图片 + 文件)
 
368
  item_type = item.get("type", "")
369
 
370
  if item_type == "text":
371
+ text_content = item.get("text", "")
372
+ text_parts.append(text_content)
373
+ # 检查文本中的上下文图片
374
+ context_images = extract_images_from_context(text_content)
375
+ if context_images:
376
+ images.extend(context_images)
377
 
378
  elif item_type == "image_url":
379
  image_url = item.get("image_url", {})
 
391
  logger.warning(f"Image URL format not supported: {url[:100]}...")
392
  except Exception as e:
393
  logger.error(f"Error processing image: {e}")
394
+ elif url.startswith("http"):
395
+ # 外部图片URL
396
+ images.append(url)
397
+ logger.info(f"Found external image URL: {url}")
398
  else:
399
+ logger.warning(f"Unsupported image URL format: {url}")
400
 
401
  elif item_type == "file" or (item_type == "image_url" and not item.get("image_url", {}).get("url", "").startswith("data:image/")):
402
  # 处理文件上传
 
425
 
426
  elif isinstance(item, str):
427
  text_parts.append(item)
428
+ # 检查文本中的上下文图片
429
+ context_images = extract_images_from_context(item)
430
+ if context_images:
431
+ images.extend(context_images)
432
 
433
  return " ".join(text_parts), images, files
434
 
 
530
  formatted_image = None
531
  if has_images and primary_image:
532
  logger.info(f"Processing image for model {model} with format {model_config.get('image_format')}")
 
533
 
534
+ # 如果是外部URL,先下载转换为base64
535
+ if primary_image.startswith("http"):
536
+ logger.info(f"Downloading external image: {primary_image}")
537
+ downloaded_image = await download_image_from_url(primary_image)
538
+ if downloaded_image:
539
+ primary_image = downloaded_image
540
+ logger.info("External image downloaded and converted to base64")
541
+ else:
542
+ logger.error("Failed to download external image")
543
+ primary_image = None
544
+
545
+ if primary_image:
546
+ formatted_image = await format_image_for_model(primary_image, model_config)
547
+
548
+ if not formatted_image:
549
+ logger.error("Failed to format image for model")
550
+ raise HTTPException(status_code=500, detail="Failed to process image")
551
 
552
  # 构建 Replicate 格式的输入
553
  replicate_input = {}
 
754
  "status": "running",
755
  "replicate_token_configured": bool(REPLICATE_API_TOKEN),
756
  "imgbb_token_configured": bool(IMGBB_API_KEY),
757
+ "version": "1.3.0",
758
  "supported_models": list(MODEL_CONFIGS.keys()),
759
  "vision_support": True,
760
  "file_support": True,
761
+ "external_image_support": True,
762
  "supported_text_files": list(SUPPORTED_TEXT_EXTENSIONS),
763
  "supported_image_files": list(SUPPORTED_IMAGE_EXTENSIONS),
764
  "claude4_vision_support": "Full support via imgbb image hosting"