Spaces:
Sleeping
Sleeping
Upload main.py
Browse files
main.py
CHANGED
|
@@ -77,8 +77,8 @@ from core import storage
|
|
| 77 |
|
| 78 |
# ---------- 日志配置 ----------
|
| 79 |
|
| 80 |
-
# 内存日志缓冲区 (保留最近
|
| 81 |
-
log_buffer = deque(maxlen=
|
| 82 |
log_lock = Lock()
|
| 83 |
|
| 84 |
# 统计数据持久化
|
|
@@ -938,7 +938,8 @@ async def admin_get_settings(request: Request):
|
|
| 938 |
},
|
| 939 |
"image_generation": {
|
| 940 |
"enabled": config.image_generation.enabled,
|
| 941 |
-
"supported_models": config.image_generation.supported_models
|
|
|
|
| 942 |
},
|
| 943 |
"retry": {
|
| 944 |
"max_new_session_tries": config.retry.max_new_session_tries,
|
|
@@ -968,6 +969,13 @@ async def admin_update_settings(request: Request, new_settings: dict = Body(...)
|
|
| 968 |
global SESSION_EXPIRE_HOURS, multi_account_mgr, http_client
|
| 969 |
|
| 970 |
try:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 971 |
# 保存旧配置用于对比
|
| 972 |
old_proxy = PROXY
|
| 973 |
old_retry_config = {
|
|
@@ -1040,7 +1048,7 @@ async def admin_update_settings(request: Request, new_settings: dict = Body(...)
|
|
| 1040 |
@require_login()
|
| 1041 |
async def admin_get_logs(
|
| 1042 |
request: Request,
|
| 1043 |
-
limit: int =
|
| 1044 |
level: str = None,
|
| 1045 |
search: str = None,
|
| 1046 |
start_time: str = None,
|
|
@@ -1070,7 +1078,7 @@ async def admin_get_logs(
|
|
| 1070 |
if end_time:
|
| 1071 |
logs = [log for log in logs if log["time"] <= end_time]
|
| 1072 |
|
| 1073 |
-
limit = min(limit,
|
| 1074 |
filtered_logs = logs[-limit:]
|
| 1075 |
|
| 1076 |
return {
|
|
@@ -1412,17 +1420,17 @@ async def chat_impl(
|
|
| 1412 |
# 检查是否为429错误(Rate Limit)
|
| 1413 |
is_rate_limit = isinstance(e, HTTPException) and e.status_code == 429
|
| 1414 |
|
| 1415 |
-
# 增加
|
| 1416 |
-
account_manager.last_error_time = time.time()
|
| 1417 |
if is_rate_limit:
|
| 1418 |
account_manager.last_429_time = time.time()
|
| 1419 |
-
|
| 1420 |
-
|
| 1421 |
-
|
| 1422 |
-
|
| 1423 |
-
|
| 1424 |
-
|
| 1425 |
-
|
|
|
|
| 1426 |
logger.error(f"[ACCOUNT] [{account_manager.config.account_id}] [req_{request_id}] 请求连续失败{account_manager.error_count}次,账户已永久禁用")
|
| 1427 |
|
| 1428 |
retry_count += 1
|
|
@@ -1443,10 +1451,26 @@ async def chat_impl(
|
|
| 1443 |
# 检查是否还能继续重试
|
| 1444 |
if retry_count <= max_retries:
|
| 1445 |
logger.warning(f"[CHAT] [{account_manager.config.account_id}] [req_{request_id}] 正在重试 ({retry_count}/{max_retries})")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1446 |
# 尝试切换到其他账户(客户端会传递完整上下文)
|
| 1447 |
try:
|
| 1448 |
# 获取新账户,跳过已失败的账户
|
| 1449 |
-
max_account_tries = MAX_ACCOUNT_SWITCH_TRIES #
|
| 1450 |
new_account = None
|
| 1451 |
|
| 1452 |
for _ in range(max_account_tries):
|
|
@@ -1456,9 +1480,9 @@ async def chat_impl(
|
|
| 1456 |
break
|
| 1457 |
|
| 1458 |
if not new_account:
|
| 1459 |
-
logger.error(f"[CHAT] [req_{request_id}]
|
| 1460 |
-
await finalize_result("error", 503, "All
|
| 1461 |
-
if req.stream: yield f"data: {json.dumps({'error': {'message': 'All
|
| 1462 |
return
|
| 1463 |
|
| 1464 |
logger.info(f"[CHAT] [req_{request_id}] 切换账户: {account_manager.config.account_id} -> {new_account.config.account_id}")
|
|
|
|
| 77 |
|
| 78 |
# ---------- 日志配置 ----------
|
| 79 |
|
| 80 |
+
# 内存日志缓冲区 (保留最近 1000 条日志,重启后清空)
|
| 81 |
+
log_buffer = deque(maxlen=1000)
|
| 82 |
log_lock = Lock()
|
| 83 |
|
| 84 |
# 统计数据持久化
|
|
|
|
| 938 |
},
|
| 939 |
"image_generation": {
|
| 940 |
"enabled": config.image_generation.enabled,
|
| 941 |
+
"supported_models": config.image_generation.supported_models,
|
| 942 |
+
"output_format": config.image_generation.output_format
|
| 943 |
},
|
| 944 |
"retry": {
|
| 945 |
"max_new_session_tries": config.retry.max_new_session_tries,
|
|
|
|
| 969 |
global SESSION_EXPIRE_HOURS, multi_account_mgr, http_client
|
| 970 |
|
| 971 |
try:
|
| 972 |
+
image_generation = dict(new_settings.get("image_generation") or {})
|
| 973 |
+
output_format = str(image_generation.get("output_format") or config_manager.image_output_format).lower()
|
| 974 |
+
if output_format not in ("base64", "url"):
|
| 975 |
+
output_format = "base64"
|
| 976 |
+
image_generation["output_format"] = output_format
|
| 977 |
+
new_settings["image_generation"] = image_generation
|
| 978 |
+
|
| 979 |
# 保存旧配置用于对比
|
| 980 |
old_proxy = PROXY
|
| 981 |
old_retry_config = {
|
|
|
|
| 1048 |
@require_login()
|
| 1049 |
async def admin_get_logs(
|
| 1050 |
request: Request,
|
| 1051 |
+
limit: int = 300,
|
| 1052 |
level: str = None,
|
| 1053 |
search: str = None,
|
| 1054 |
start_time: str = None,
|
|
|
|
| 1078 |
if end_time:
|
| 1079 |
logs = [log for log in logs if log["time"] <= end_time]
|
| 1080 |
|
| 1081 |
+
limit = min(limit, log_buffer.maxlen)
|
| 1082 |
filtered_logs = logs[-limit:]
|
| 1083 |
|
| 1084 |
return {
|
|
|
|
| 1420 |
# 检查是否为429错误(Rate Limit)
|
| 1421 |
is_rate_limit = isinstance(e, HTTPException) and e.status_code == 429
|
| 1422 |
|
| 1423 |
+
# 429错误单独处理(不增加error_count,只设置冷却时间)
|
|
|
|
| 1424 |
if is_rate_limit:
|
| 1425 |
account_manager.last_429_time = time.time()
|
| 1426 |
+
account_manager.is_available = False # 临时禁用,冷却期后自动恢复
|
| 1427 |
+
logger.warning(f"[ACCOUNT] [{account_manager.config.account_id}] [req_{request_id}] 遇到429限流,账户将休息{RATE_LIMIT_COOLDOWN_SECONDS}秒后自动恢复")
|
| 1428 |
+
else:
|
| 1429 |
+
# 非429错误才增加失败计数
|
| 1430 |
+
account_manager.last_error_time = time.time()
|
| 1431 |
+
account_manager.error_count += 1
|
| 1432 |
+
if account_manager.error_count >= ACCOUNT_FAILURE_THRESHOLD:
|
| 1433 |
+
account_manager.is_available = False
|
| 1434 |
logger.error(f"[ACCOUNT] [{account_manager.config.account_id}] [req_{request_id}] 请求连续失败{account_manager.error_count}次,账户已永久禁用")
|
| 1435 |
|
| 1436 |
retry_count += 1
|
|
|
|
| 1451 |
# 检查是否还能继续重试
|
| 1452 |
if retry_count <= max_retries:
|
| 1453 |
logger.warning(f"[CHAT] [{account_manager.config.account_id}] [req_{request_id}] 正在重试 ({retry_count}/{max_retries})")
|
| 1454 |
+
|
| 1455 |
+
# 快速失败:检查是否还有可用账户(避免无效重试)
|
| 1456 |
+
available_count = sum(
|
| 1457 |
+
1 for acc in multi_account_mgr.accounts.values()
|
| 1458 |
+
if (acc.should_retry() and
|
| 1459 |
+
not acc.config.is_expired() and
|
| 1460 |
+
not acc.config.disabled and
|
| 1461 |
+
acc.config.account_id not in failed_accounts)
|
| 1462 |
+
)
|
| 1463 |
+
|
| 1464 |
+
if available_count == 0:
|
| 1465 |
+
logger.error(f"[CHAT] [req_{request_id}] 所有账户均不可用,快速失败")
|
| 1466 |
+
await finalize_result("error", 503, "All accounts unavailable")
|
| 1467 |
+
if req.stream: yield f"data: {json.dumps({'error': {'message': 'All accounts unavailable'}})}\n\n"
|
| 1468 |
+
return
|
| 1469 |
+
|
| 1470 |
# 尝试切换到其他账户(客户端会传递完整上下文)
|
| 1471 |
try:
|
| 1472 |
# 获取新账户,跳过已失败的账户
|
| 1473 |
+
max_account_tries = min(MAX_ACCOUNT_SWITCH_TRIES, available_count) # 限制尝试次数
|
| 1474 |
new_account = None
|
| 1475 |
|
| 1476 |
for _ in range(max_account_tries):
|
|
|
|
| 1480 |
break
|
| 1481 |
|
| 1482 |
if not new_account:
|
| 1483 |
+
logger.error(f"[CHAT] [req_{request_id}] 所有可用账户均已失败")
|
| 1484 |
+
await finalize_result("error", 503, "All available accounts failed")
|
| 1485 |
+
if req.stream: yield f"data: {json.dumps({'error': {'message': 'All available accounts failed'}})}\n\n"
|
| 1486 |
return
|
| 1487 |
|
| 1488 |
logger.info(f"[CHAT] [req_{request_id}] 切换账户: {account_manager.config.account_id} -> {new_account.config.account_id}")
|