aaxaxax commited on
Commit
3d7e312
·
1 Parent(s): 19e969a

Restore original code with detailed logging

Browse files
Files changed (1) hide show
  1. app.py +71 -23
app.py CHANGED
@@ -17,68 +17,116 @@ for i in range(1, 20):
17
 
18
  key_status = {}
19
  for idx, k in enumerate(OLLAMA_KEYS, 1):
20
- key_status[k] = {"index": idx, "prefix": k[:8]+"...", "success": 0, "healthy": True}
21
 
22
  def log(msg):
23
  print(f"[{time.strftime('%H:%M:%S')}] {msg}")
24
 
25
  @app.get("/")
26
  def root():
27
- healthy = [k for k, v in key_status.items() if v["healthy"]]
28
- return {"status": "ok", "keys_loaded": len(OLLAMA_KEYS), "healthy": len(healthy),
29
- "keys_status": {v["prefix"]: {"s": v["success"], "h": v["healthy"]} for v in key_status.values()}}
 
 
 
 
 
30
 
31
- def get_best_keys(max_failures=2, limit=2):
32
- """Get best healthy keys sorted by fewest failures"""
33
- healthy = sorted([(k, v) for k, v in key_status.items() if v["healthy"]], key=lambda x: x[1]["success"])
34
- return [k for k, v in healthy[:limit]]
 
 
 
 
 
35
 
36
  @app.post("/v1/chat/completions")
37
  async def chat(req: Request):
38
  auth_key = req.headers.get("Authorization", "").replace("Bearer ", "")
39
  if auth_key != MASTER_API_KEY:
 
40
  return JSONResponse({"error": "Unauthorized"}, status_code=401)
41
 
42
  body = await req.json()
 
43
  model = body.get("model", "?")
 
44
 
45
- selected = get_best_keys(max_failures=2, limit=2)
46
- if not selected:
47
- for v in key_status.values(): v["healthy"] = True
48
- selected = OLLAMA_KEYS[:2]
49
 
50
- log(f"REQ: {model} -> {[key_status[k]['prefix'] for k in selected]}")
51
-
52
- for key in selected:
53
  ki = key_status[key]
 
 
54
  try:
55
- start = time.time()
56
  async with httpx.AsyncClient(timeout=30.0) as client:
57
  resp = await client.post(f"{BASE_URL}/v1/chat/completions", json=body, headers={"Authorization": f"Bearer {key}"})
 
58
 
59
  if resp.status_code == 200:
60
  ki["success"] += 1
61
- log(f"OK: key#{ki['index']} in {time.time()-start:.2f}s")
 
 
62
  return Response(resp.content, status_code=200)
 
63
  elif resp.status_code == 429:
 
64
  ki["healthy"] = False
 
65
  continue
66
- except Exception as e:
 
 
 
 
 
 
 
 
 
 
 
 
 
67
  ki["healthy"] = False
 
 
 
 
 
 
 
 
68
  continue
69
 
70
- return JSONResponse({"error": "all failed"}, status_code=500)
 
 
71
 
72
  @app.get("/v1/models")
73
  def models(req: Request):
74
  auth_key = req.headers.get("Authorization", "").replace("Bearer ", "")
75
  if auth_key != MASTER_API_KEY:
76
  return JSONResponse({"error": "Unauthorized"}, status_code=401)
77
- for key in get_best_keys(limit=2):
 
 
 
 
78
  try:
79
  resp = httpx.get(f"{BASE_URL}/v1/models", headers={"Authorization": f"Bearer {key}"}, timeout=10)
80
  if resp.status_code == 200:
 
 
81
  return Response(resp.content, status_code=200)
82
- except:
83
- pass
84
- return JSONResponse({"error": "no keys"}, status_code=500)
 
 
 
17
 
18
  key_status = {}
19
  for idx, k in enumerate(OLLAMA_KEYS, 1):
20
+ key_status[k] = {"index": idx, "prefix": k[:8]+"...", "failures": 0, "success": 0, "last_error": None, "healthy": True}
21
 
22
  def log(msg):
23
  print(f"[{time.strftime('%H:%M:%S')}] {msg}")
24
 
25
  @app.get("/")
26
  def root():
27
+ return {
28
+ "status": "ok",
29
+ "base_url": BASE_URL,
30
+ "master_key": MASTER_API_KEY[:8] + "...",
31
+ "keys_loaded": len(OLLAMA_KEYS),
32
+ "healthy_keys": sum(1 for v in key_status.values() if v["healthy"]),
33
+ "keys_status": {v["prefix"]: {"failures": v["failures"], "success": v["success"], "healthy": v["healthy"]} for v in key_status.values()}
34
+ }
35
 
36
+ def get_healthy_keys(max_failures=2):
37
+ """Get keys that are healthy (low failures)"""
38
+ healthy = [k for k, v in key_status.items() if v["failures"] < max_failures and v["healthy"]]
39
+ if not healthy:
40
+ for v in key_status.values():
41
+ v["failures"] = 0
42
+ v["healthy"] = True
43
+ return OLLAMA_KEYS[:2]
44
+ return healthy[:2]
45
 
46
  @app.post("/v1/chat/completions")
47
  async def chat(req: Request):
48
  auth_key = req.headers.get("Authorization", "").replace("Bearer ", "")
49
  if auth_key != MASTER_API_KEY:
50
+ log(f"AUTH FAIL: received '{auth_key[:8]}...' expected '{MASTER_API_KEY[:8]}...'")
51
  return JSONResponse({"error": "Unauthorized"}, status_code=401)
52
 
53
  body = await req.json()
54
+ is_stream = body.get("stream", False)
55
  model = body.get("model", "?")
56
+ log(f"REQUEST: model='{model}'")
57
 
58
+ candidate_keys = get_healthy_keys(max_failures=2)
59
+ log(f"Using top {len(candidate_keys)} keys")
 
 
60
 
61
+ for attempt, key in enumerate(candidate_keys):
 
 
62
  ki = key_status[key]
63
+ log(f"TRY #{attempt+1}: using key#{ki['index']} ({ki['prefix']})")
64
+
65
  try:
66
+ start_time = time.time()
67
  async with httpx.AsyncClient(timeout=30.0) as client:
68
  resp = await client.post(f"{BASE_URL}/v1/chat/completions", json=body, headers={"Authorization": f"Bearer {key}"})
69
+ elapsed = time.time() - start_time
70
 
71
  if resp.status_code == 200:
72
  ki["success"] += 1
73
+ ki["failures"] = 0
74
+ ki["healthy"] = True
75
+ log(f"SUCCESS: key#{ki['index']} responded in {elapsed:.2f}s")
76
  return Response(resp.content, status_code=200)
77
+
78
  elif resp.status_code == 429:
79
+ ki["failures"] += 1
80
  ki["healthy"] = False
81
+ log(f"RATE LIMIT: key#{ki['index']} - skip to next")
82
  continue
83
+
84
+ elif resp.status_code >= 500:
85
+ ki["failures"] += 1
86
+ ki["last_error"] = f"http {resp.status_code}"
87
+ log(f"SERVER ERROR: key#{ki['index']} got {resp.status_code}, trying next")
88
+ continue
89
+
90
+ else:
91
+ ki["last_error"] = f"http {resp.status_code}"
92
+ log(f"ERROR: key#{ki['index']} got {resp.status_code}")
93
+ return Response(resp.content, status_code=resp.status_code)
94
+
95
+ except httpx.TimeoutException:
96
+ ki["failures"] += 1
97
  ki["healthy"] = False
98
+ ki["last_error"] = "timeout after 30s"
99
+ log(f"TIMEOUT: key#{ki['index']} - already healthy=False, try next")
100
+ continue
101
+
102
+ except Exception as e:
103
+ ki["failures"] += 1
104
+ ki["last_error"] = str(e)[:50]
105
+ log(f"EXCEPTION: key#{ki['index']} error: {e}")
106
  continue
107
 
108
+ log(f"ALL KEYS FAILED for model='{model}'")
109
+ return JSONResponse({"error": "all keys failed after 2 attempts", "model": model,
110
+ "keys_status": {v["prefix"]: {"failures": v["failures"], "last_error": v["last_error"]} for v in key_status.values()}}, status_code=500)
111
 
112
  @app.get("/v1/models")
113
  def models(req: Request):
114
  auth_key = req.headers.get("Authorization", "").replace("Bearer ", "")
115
  if auth_key != MASTER_API_KEY:
116
  return JSONResponse({"error": "Unauthorized"}, status_code=401)
117
+
118
+ log("REQUEST: GET /v1/models")
119
+
120
+ for key in get_healthy_keys(max_failures=2):
121
+ ki = key_status[key]
122
  try:
123
  resp = httpx.get(f"{BASE_URL}/v1/models", headers={"Authorization": f"Bearer {key}"}, timeout=10)
124
  if resp.status_code == 200:
125
+ ki["success"] += 1
126
+ log(f"MODELS OK: key#{ki['index']}")
127
  return Response(resp.content, status_code=200)
128
+ except Exception as e:
129
+ ki["last_error"] = str(e)[:50]
130
+ log(f"MODELS FAIL: key#{ki['index']} - {e}")
131
+
132
+ return JSONResponse({"error": "no keys available"}, status_code=500)