aaxaxax commited on
Commit
ebba60d
·
1 Parent(s): 674a2d7

Add client auth with ollama-proxy-free

Browse files
Files changed (1) hide show
  1. app.py +20 -17
app.py CHANGED
@@ -2,15 +2,18 @@ import os
2
  import time
3
  import random
4
  import httpx
5
- from typing import Dict, List
6
- from fastapi import FastAPI, Request
7
  from fastapi.responses import JSONResponse, StreamingResponse, Response
8
 
9
  app = FastAPI()
10
 
11
  BASE_URL = os.getenv("BASE_URL", "https://ollama.com")
12
 
13
- # 3 API KEYS - FAILOVER
 
 
 
14
  API_KEYS = [
15
  "8ca25de51e554c099962b78b7ce0c9e9.Mp5dnqctR2zzq3g-NO_M-cjW",
16
  "dbd1d0c534964684a6d4678348ab8d30.ieDfmSYVnf0MmTjR-AIdNrW9",
@@ -23,8 +26,13 @@ key_status: Dict[str, Dict] = {
23
  for k in API_KEYS
24
  }
25
 
26
- def pick_key() -> str:
27
- """Pick an available key, fallback if all fail"""
 
 
 
 
 
28
  now = time.time()
29
  valid = [k for k, v in key_status.items()
30
  if v["status"] != "dead" and v["cooldown"] < now]
@@ -32,7 +40,7 @@ def pick_key() -> str:
32
  if valid:
33
  return random.choice(valid)
34
 
35
- # All failed, reset and try again
36
  for k in key_status:
37
  key_status[k]["status"] = "active"
38
  key_status[k]["fail"] = 0
@@ -43,7 +51,6 @@ def mark_fail(key: str):
43
  key_status[key]["fail"] += 1
44
  if key_status[key]["fail"] >= 3:
45
  key_status[key]["cooldown"] = time.time() + 60
46
- print(f"[KEY] {key[:8]}... -> cooldown 60s")
47
 
48
  def mark_ok(key: str):
49
  key_status[key]["fail"] = 0
@@ -54,12 +61,16 @@ def root():
54
  active = sum(1 for v in key_status.values() if v["status"] == "active")
55
  return {
56
  "status": "ok",
 
57
  "keys_total": len(API_KEYS),
58
  "keys_active": active
59
  }
60
 
61
  @app.api_route("/v1/{path:path}", methods=["GET", "POST", "PUT", "DELETE"])
62
  async def proxy(req: Request, path: str):
 
 
 
63
  target_url = f"{BASE_URL}/v1/{path}"
64
  body = await req.body()
65
 
@@ -67,7 +78,7 @@ async def proxy(req: Request, path: str):
67
  headers.pop("host", None)
68
  headers.pop("content-length", None)
69
 
70
- # Try each key until success
71
  tried = set()
72
  for _ in range(len(API_KEYS)):
73
  key = pick_key()
@@ -89,25 +100,17 @@ async def proxy(req: Request, path: str):
89
 
90
  if resp.status_code < 400:
91
  mark_ok(key)
92
- print(f"[OK] key={key[:6]}...")
93
  return Response(
94
  content=resp.content,
95
  status_code=resp.status_code,
96
  headers=dict(resp.headers)
97
  )
98
 
99
- # Error with this key
100
  mark_fail(key)
101
- print(f"[FAIL] key={key[:6]}... status={resp.status_code}")
102
  continue
103
 
104
  except Exception as e:
105
  mark_fail(key)
106
- print(f"[ERROR] key={key[:6]}... {e}")
107
  continue
108
 
109
- # All keys failed
110
- return JSONResponse(
111
- {"error": "all keys failed", "tried": len(API_KEYS)},
112
- status_code=500
113
- )
 
2
  import time
3
  import random
4
  import httpx
5
+ from typing import Dict
6
+ from fastapi import FastAPI, Request, HTTPException
7
  from fastapi.responses import JSONResponse, StreamingResponse, Response
8
 
9
  app = FastAPI()
10
 
11
  BASE_URL = os.getenv("BASE_URL", "https://ollama.com")
12
 
13
+ # CLIENT API KEY (for auth)
14
+ MASTER_API_KEY = "ollama-proxy-free"
15
+
16
+ # BACKEND API KEYS (for Ollama)
17
  API_KEYS = [
18
  "8ca25de51e554c099962b78b7ce0c9e9.Mp5dnqctR2zzq3g-NO_M-cjW",
19
  "dbd1d0c534964684a6d4678348ab8d30.ieDfmSYVnf0MmTjR-AIdNrW9",
 
26
  for k in API_KEYS
27
  }
28
 
29
+ def auth(req: Request):
30
+ """Validate client API key"""
31
+ client_key = req.headers.get("Authorization", "").replace("Bearer ", "")
32
+ if client_key != MASTER_API_KEY:
33
+ raise HTTPException(401, "Unauthorized")
34
+
35
+ def pick_key():
36
  now = time.time()
37
  valid = [k for k, v in key_status.items()
38
  if v["status"] != "dead" and v["cooldown"] < now]
 
40
  if valid:
41
  return random.choice(valid)
42
 
43
+ # Reset if all failed
44
  for k in key_status:
45
  key_status[k]["status"] = "active"
46
  key_status[k]["fail"] = 0
 
51
  key_status[key]["fail"] += 1
52
  if key_status[key]["fail"] >= 3:
53
  key_status[key]["cooldown"] = time.time() + 60
 
54
 
55
  def mark_ok(key: str):
56
  key_status[key]["fail"] = 0
 
61
  active = sum(1 for v in key_status.values() if v["status"] == "active")
62
  return {
63
  "status": "ok",
64
+ "mode": "openai-proxy",
65
  "keys_total": len(API_KEYS),
66
  "keys_active": active
67
  }
68
 
69
  @app.api_route("/v1/{path:path}", methods=["GET", "POST", "PUT", "DELETE"])
70
  async def proxy(req: Request, path: str):
71
+ # Auth first
72
+ auth(req)
73
+
74
  target_url = f"{BASE_URL}/v1/{path}"
75
  body = await req.body()
76
 
 
78
  headers.pop("host", None)
79
  headers.pop("content-length", None)
80
 
81
+ # Try each key
82
  tried = set()
83
  for _ in range(len(API_KEYS)):
84
  key = pick_key()
 
100
 
101
  if resp.status_code < 400:
102
  mark_ok(key)
 
103
  return Response(
104
  content=resp.content,
105
  status_code=resp.status_code,
106
  headers=dict(resp.headers)
107
  )
108
 
 
109
  mark_fail(key)
 
110
  continue
111
 
112
  except Exception as e:
113
  mark_fail(key)
 
114
  continue
115
 
116
+ return JSONResponse({"error": "all keys failed"}, status_code=500)