Spaces:
Running
Running
File size: 6,732 Bytes
d0dd276 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
import requests
import httpx # 添加 httpx 导入
import logging
import asyncio
from fastapi import HTTPException, status
from app.utils.logging import format_log_message
from app.utils.logging import log
logger = logging.getLogger("my_logger")
def handle_gemini_error(error, current_api_key) -> str:
# 同时检查 requests 和 httpx 的 HTTPError
if isinstance(error, (requests.exceptions.HTTPError, httpx.HTTPStatusError)):
status_code = error.response.status_code
if status_code == 400:
try:
error_data = error.response.json()
if 'error' in error_data:
if error_data['error'].get('code') == "invalid_argument":
error_message = "无效的 API 密钥"
log('ERROR', f"{current_api_key[:8]} ... {current_api_key[-3:]} → 无效,可能已过期或被删除",
extra={'key': current_api_key[:8], 'status_code': status_code, 'error_message': error_message})
# key_manager.blacklist_key(current_api_key)
return error_message
error_message = error_data['error'].get('message', 'Bad Request')
log('WARNING', f"400 错误请求: {error_message}",
extra={'key': current_api_key[:8], 'status_code': status_code, 'error_message': error_message})
return f"400 错误请求: {error_message}"
except ValueError:
error_message = "400 错误请求:响应不是有效的JSON格式"
extra_log_400_json = {'key': current_api_key[:8], 'status_code': status_code, 'error_message': error_message}
log('WARNING', error_message, extra=extra_log_400_json)
return error_message
elif status_code == 403:
error_message = f"权限被拒绝"
log('ERROR', error_message,
extra={'key': current_api_key[:8], 'status_code': status_code})
# key_manager.blacklist_key(current_api_key)
return error_message
elif status_code == 429:
error_message = f"API 密钥配额已用尽或其他原因"
log('WARNING', error_message,
extra={'key': current_api_key[:8], 'status_code': status_code})
# key_manager.blacklist_key(current_api_key)
return error_message
if status_code == 500:
error_message = f'Gemini API 内部错误'
log('WARNING', error_message,
extra={'key': current_api_key[:8], 'status_code': status_code})
return error_message
if status_code == 503:
error_message = f"Gemini API 服务繁忙"
log('WARNING', error_message,
extra={'key': current_api_key[:8], 'status_code': status_code})
return error_message
else:
error_message = f"未知错误: {status_code}"
log('WARNING', f"{status_code} 未知错误",
extra={'key': current_api_key[:8], 'status_code': status_code, 'error_message': error_message})
return f"未知错误/模型不可用: {status_code}"
elif isinstance(error, requests.exceptions.ConnectionError):
error_message = "连接错误"
log('WARNING', error_message, extra={'error_message': error_message})
return error_message
elif isinstance(error, requests.exceptions.Timeout):
error_message = "请求超时"
log('WARNING', error_message, extra={'error_message': error_message})
return error_message
else:
error_message = f"发生未知错误: {error}"
log('ERROR', error_message, extra={'error_message': error_message})
return error_message
def translate_error(message: str) -> str:
if "quota exceeded" in message.lower():
return "API 密钥配额已用尽"
if "invalid argument" in message.lower():
return "无效参数"
if "internal server error" in message.lower():
return "服务器内部错误"
if "service unavailable" in message.lower():
return "服务不可用"
return message
async def handle_api_error(e: Exception, api_key: str, key_manager, request_type: str, model: str, retry_count: int = 0):
"""统一处理API错误"""
# 同时检查 requests 和 httpx 的 HTTPError
if isinstance(e, (requests.exceptions.HTTPError, httpx.HTTPStatusError)):
status_code = e.response.status_code
# 对500和503错误实现自动重试机制, 最多重试3次
if retry_count < 3 and (status_code == 500 or status_code == 503):
error_message = 'Gemini API 内部错误' if (status_code == 500) else "Gemini API 服务目前不可用"
# 等待时间 : MIN_RETRY_DELAY=1, MAX_RETRY_DELAY=16
wait_time = min(1 * (2 ** retry_count), 16)
log('warning', f"{error_message},将等待{wait_time}秒后重试 ({retry_count+1}/3)",
extra={'key': api_key[:8], 'request_type': request_type, 'model': model, 'status_code': int(status_code)})
# 等待后返回重试信号
await asyncio.sleep(wait_time)
return {'remove_cache': False}
elif status_code == 429:
error_message = "API 密钥配额已用尽或其他原因"
log('WARNING', f"429 官方资源耗尽或其他原因",
extra={'key': api_key[:8], 'status_code': status_code, 'error_message': error_message})
# key_manager.blacklist_key(api_key)
return {'remove_cache': False,'error': error_message, 'should_switch_key': True}
else:
error_detail = handle_gemini_error(e, api_key)
# # 重试次数用尽,在日志中输出错误状态码
# log('error', f"Gemini 服务器错误({status_code})",
# extra={'key': api_key[:8], 'request_type': request_type, 'model': model, 'status_code': int(status_code)})
# 不再切换密钥,直接向客户端抛出HTTP异常
raise HTTPException(status_code=int(status_code),
detail=f"Gemini API 服务器错误({status_code}),请稍后重试")
# 对于其他错误,返回切换密钥的信号,并输出错误信息到日志中
error_detail = handle_gemini_error(e, api_key)
return {'should_switch_key': True, 'error': error_detail, 'remove_cache': True}
|