aaxaxax commited on
Commit
cdb6e97
·
1 Parent(s): 6ef5c36

Simplified proxy

Browse files
Files changed (1) hide show
  1. app.py +38 -78
app.py CHANGED
@@ -1,101 +1,61 @@
1
  import os
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
- MASTER_API_KEY = "ollama-proxy-free"
13
 
14
- API_KEYS = [
15
  "8ca25de51e554c099962b78b7ce0c9e9.Mp5dnqctR2zzq3g-NO_M-cjW",
16
  "dbd1d0c534964684a6d4678348ab8d30.ieDfmSYVnf0MmTjR-AIdNrW9",
17
  "37e81a6be4104fbfbfbe2ecf557a2c10.GoIbzpHebdM9ZcHarQ9A12Cp"
18
  ]
19
 
20
- key_status = {k: {"fail": 0, "cooldown": 0, "status": "active"} for k in API_KEYS}
21
-
22
- def auth(req: Request):
23
- key = req.headers.get("Authorization", "").replace("Bearer ", "")
24
- if key != MASTER_API_KEY:
25
- print(f"[AUTH] reject: {key[:8]} != {MASTER_API_KEY[:8]}")
26
- raise HTTPException(401, "Unauthorized")
27
- print(f"[AUTH] ok")
28
-
29
- def pick_key() -> str:
30
- now = time.time()
31
- valid = [k for k, v in key_status.items() if v["status"] != "dead" and v["cooldown"] < now]
32
- return random.choice(valid) if valid else random.choice(API_KEYS)
33
-
34
- def mark_fail(k):
35
- key_status[k]["fail"] += 1
36
- if key_status[k]["fail"] >= 3:
37
- key_status[k]["cooldown"] = time.time() + 60
38
-
39
- def mark_ok(k):
40
- key_status[k]["fail"] = 0
41
- key_status[k]["status"] = "active"
42
-
43
  @app.get("/")
44
  def root():
45
- return {"status": "ok", "keys": len(API_KEYS), "master_set": MASTER_API_KEY[:10]}
46
 
47
- # Simple route for testing
48
- @app.post("/test")
49
- def test(req: Request):
50
- auth(req)
51
- key = pick_key()
52
- return {"key": key[:10], "url": BASE_URL}
53
-
54
- @app.api_route("/v1/{path:path}", methods=["GET", "POST", "PUT", "DELETE"])
55
- async def proxy(req: Request, path: str):
56
- try:
57
- auth(req)
58
- except HTTPException:
59
- raise
60
 
61
- target = f"{BASE_URL}/v1/{path}"
62
- body = await req.body()
63
- headers = dict(req.headers)
64
- headers.pop("host", None)
65
- headers.pop("content-length", None)
66
-
67
- print(f"[PROXY] {req.method} {path}")
68
 
69
- for i in range(len(API_KEYS)):
70
- key = pick_key()
71
- headers["Authorization"] = f"Bearer {key}"
72
-
73
- print(f"[TRY] key={key[:6]}...")
74
-
75
  try:
76
- async with httpx.AsyncClient(timeout=120.0, follow_redirects=True) as client:
77
- resp = await client.request(
78
- method=req.method,
79
- url=target,
80
- headers=headers,
81
- content=body,
82
- params=req.query_params
83
  )
84
 
85
- print(f"[RESP] {key[:6]} <- {resp.status_code}")
86
-
87
- if resp.status_code < 400:
88
- mark_ok(key)
89
- return Response(
90
- content=resp.content,
91
- status_code=resp.status_code,
92
- headers=dict(resp.headers)
93
- )
94
-
95
- mark_fail(key)
96
  except Exception as e:
97
- print(f"[ERR] {key[:6]} {type(e).__name__}: {e}")
98
- mark_fail(key)
99
-
100
- print("[FAIL] all keys failed")
101
  return JSONResponse({"error": "all keys failed"}, status_code=500)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import os
 
2
  import random
3
  import httpx
 
4
  from fastapi import FastAPI, Request, HTTPException
5
+ from fastapi.responses import JSONResponse, Response
6
 
7
  app = FastAPI()
8
 
9
+ BASE_URL = "https://ollama.com"
10
+ MASTER_KEY = "ollama-proxy-free"
11
 
12
+ KEYS = [
13
  "8ca25de51e554c099962b78b7ce0c9e9.Mp5dnqctR2zzq3g-NO_M-cjW",
14
  "dbd1d0c534964684a6d4678348ab8d30.ieDfmSYVnf0MmTjR-AIdNrW9",
15
  "37e81a6be4104fbfbfbe2ecf557a2c10.GoIbzpHebdM9ZcHarQ9A12Cp"
16
  ]
17
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
  @app.get("/")
19
  def root():
20
+ return {"status": "ok", "master": MASTER_KEY[:10]}
21
 
22
+ @app.post("/v1/chat/completions")
23
+ async def chat(req: Request):
24
+ # Auth
25
+ auth_key = req.headers.get("Authorization", "").replace("Bearer ", "")
26
+ if auth_key != MASTER_KEY:
27
+ raise HTTPException(401, "Unauthorized")
 
 
 
 
 
 
 
28
 
29
+ body = await req.json()
 
 
 
 
 
 
30
 
31
+ for key in KEYS:
 
 
 
 
 
32
  try:
33
+ async with httpx.AsyncClient(timeout=60) as client:
34
+ resp = await client.post(
35
+ f"{BASE_URL}/v1/chat/completions",
36
+ json=body,
37
+ headers={"Authorization": f"Bearer {key}"}
 
 
38
  )
39
 
40
+ if resp.status_code == 200:
41
+ return Response(resp.content, status_code=200)
 
 
 
 
 
 
 
 
 
42
  except Exception as e:
43
+ print(f"ERR {key[:6]}: {e}")
44
+
 
 
45
  return JSONResponse({"error": "all keys failed"}, status_code=500)
46
+
47
+ @app.get("/v1/models")
48
+ def models():
49
+ for key in KEYS:
50
+ try:
51
+ resp = httpx.get(
52
+ f"{BASE_URL}/v1/models",
53
+ headers={"Authorization": f"Bearer {key}"},
54
+ timeout=30
55
+ )
56
+ if resp.status_code == 200:
57
+ return Response(resp.content, status_code=200)
58
+ except:
59
+ pass
60
+
61
+ return JSONResponse({"error": "error"}, status_code=500)