Update app.py
Browse files
app.py
CHANGED
|
@@ -65,23 +65,41 @@ STREAM_RESPONSE_HEADERS = {
|
|
| 65 |
# MODELS
|
| 66 |
# =========================================================
|
| 67 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 68 |
MODEL_MAP = {
|
| 69 |
-
"claude-sonnet-4-6":
|
| 70 |
-
"claude-sonnet-4-5":
|
| 71 |
-
"claude-haiku-4-6":
|
| 72 |
-
"claude-haiku-4-5":
|
| 73 |
"claude-haiku-4-5-20251001": "deepseek-v4-flash-free",
|
| 74 |
-
"claude-opus-4-6":
|
| 75 |
-
|
| 76 |
-
"
|
| 77 |
-
"
|
| 78 |
-
"
|
| 79 |
-
"
|
| 80 |
-
"big-pickle": "big-pickle",
|
| 81 |
}
|
| 82 |
|
| 83 |
DEFAULT_MODEL = "deepseek-v4-flash-free"
|
| 84 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 85 |
# =========================================================
|
| 86 |
# BROWSER TOOLS FILTER
|
| 87 |
# =========================================================
|
|
@@ -1316,9 +1334,17 @@ async def messages(
|
|
| 1316 |
|
| 1317 |
last_error = raw_error
|
| 1318 |
|
| 1319 |
-
# 429 = rate limit:
|
| 1320 |
if response.status_code == 429:
|
| 1321 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1322 |
|
| 1323 |
await asyncio.sleep(RETRY_DELAY)
|
| 1324 |
|
|
@@ -1353,9 +1379,17 @@ async def messages(
|
|
| 1353 |
|
| 1354 |
last_error = response.text
|
| 1355 |
|
| 1356 |
-
# 429 = rate limit:
|
| 1357 |
if response.status_code == 429:
|
| 1358 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1359 |
|
| 1360 |
await asyncio.sleep(RETRY_DELAY)
|
| 1361 |
|
|
@@ -1403,9 +1437,9 @@ async def messages(
|
|
| 1403 |
await asyncio.sleep(RETRY_DELAY)
|
| 1404 |
|
| 1405 |
return JSONResponse(
|
| 1406 |
-
status_code=
|
| 1407 |
content={
|
| 1408 |
-
"error": "
|
| 1409 |
-
"details": last_error
|
| 1410 |
},
|
| 1411 |
)
|
|
|
|
| 65 |
# MODELS
|
| 66 |
# =========================================================
|
| 67 |
|
| 68 |
+
# Pool of free models — rotated automatically on 429
|
| 69 |
+
FREE_MODELS_POOL = [
|
| 70 |
+
"deepseek-v4-flash-free",
|
| 71 |
+
"qwen3.6-plus-free",
|
| 72 |
+
"minimax-m2.5-free",
|
| 73 |
+
"nemotron-3-super-free",
|
| 74 |
+
"big-pickle",
|
| 75 |
+
]
|
| 76 |
+
|
| 77 |
MODEL_MAP = {
|
| 78 |
+
"claude-sonnet-4-6": "deepseek-v4-flash-free",
|
| 79 |
+
"claude-sonnet-4-5": "deepseek-v4-flash-free",
|
| 80 |
+
"claude-haiku-4-6": "deepseek-v4-flash-free",
|
| 81 |
+
"claude-haiku-4-5": "deepseek-v4-flash-free",
|
| 82 |
"claude-haiku-4-5-20251001": "deepseek-v4-flash-free",
|
| 83 |
+
"claude-opus-4-6": "nemotron-3-super-free",
|
| 84 |
+
"deepseek-v4-flash-free": "deepseek-v4-flash-free",
|
| 85 |
+
"nemotron-3-super-free": "nemotron-3-super-free",
|
| 86 |
+
"qwen3.6-plus-free": "qwen3.6-plus-free",
|
| 87 |
+
"minimax-m2.5-free": "minimax-m2.5-free",
|
| 88 |
+
"big-pickle": "big-pickle",
|
|
|
|
| 89 |
}
|
| 90 |
|
| 91 |
DEFAULT_MODEL = "deepseek-v4-flash-free"
|
| 92 |
|
| 93 |
+
|
| 94 |
+
def _next_model(current_model):
|
| 95 |
+
"""Return the next free model in the pool after current_model."""
|
| 96 |
+
try:
|
| 97 |
+
idx = FREE_MODELS_POOL.index(current_model)
|
| 98 |
+
except ValueError:
|
| 99 |
+
idx = -1
|
| 100 |
+
next_idx = (idx + 1) % len(FREE_MODELS_POOL)
|
| 101 |
+
return FREE_MODELS_POOL[next_idx]
|
| 102 |
+
|
| 103 |
# =========================================================
|
| 104 |
# BROWSER TOOLS FILTER
|
| 105 |
# =========================================================
|
|
|
|
| 1334 |
|
| 1335 |
last_error = raw_error
|
| 1336 |
|
| 1337 |
+
# 429 = rate limit: rotate to next free model
|
| 1338 |
if response.status_code == 429:
|
| 1339 |
+
next_m = _next_model(mapped_model)
|
| 1340 |
+
logger.warning(
|
| 1341 |
+
"[%s] 429 on %s -> rotating to %s",
|
| 1342 |
+
request_id, mapped_model, next_m,
|
| 1343 |
+
)
|
| 1344 |
+
mapped_model = next_m
|
| 1345 |
+
payload["model"] = mapped_model
|
| 1346 |
+
await asyncio.sleep(1)
|
| 1347 |
+
continue
|
| 1348 |
|
| 1349 |
await asyncio.sleep(RETRY_DELAY)
|
| 1350 |
|
|
|
|
| 1379 |
|
| 1380 |
last_error = response.text
|
| 1381 |
|
| 1382 |
+
# 429 = rate limit: rotate to next free model
|
| 1383 |
if response.status_code == 429:
|
| 1384 |
+
next_m = _next_model(mapped_model)
|
| 1385 |
+
logger.warning(
|
| 1386 |
+
"[%s] 429 on %s -> rotating to %s",
|
| 1387 |
+
request_id, mapped_model, next_m,
|
| 1388 |
+
)
|
| 1389 |
+
mapped_model = next_m
|
| 1390 |
+
payload["model"] = mapped_model
|
| 1391 |
+
await asyncio.sleep(1)
|
| 1392 |
+
continue
|
| 1393 |
|
| 1394 |
await asyncio.sleep(RETRY_DELAY)
|
| 1395 |
|
|
|
|
| 1437 |
await asyncio.sleep(RETRY_DELAY)
|
| 1438 |
|
| 1439 |
return JSONResponse(
|
| 1440 |
+
status_code=502,
|
| 1441 |
content={
|
| 1442 |
+
"error": "All free models exhausted or upstream failed",
|
| 1443 |
+
"details": last_error,
|
| 1444 |
},
|
| 1445 |
)
|