autoreg-skills-max: initial public release (restored, redacted, hardened)
This commit is contained in:
141
skills/lobehub-pool/scripts/gateway.py
Normal file
141
skills/lobehub-pool/scripts/gateway.py
Normal file
@@ -0,0 +1,141 @@
|
||||
#!/usr/bin/env python3
|
||||
"""LobeHub API Gateway — 601 ключей, 20 моделей, closerouter backend"""
|
||||
import json, time, httpx, secrets
|
||||
from http.server import HTTPServer, BaseHTTPRequestHandler
|
||||
from pathlib import Path
|
||||
|
||||
BASE_URL = "http://[REDACTED-IP]:3210"
|
||||
BACKEND = "https://api.closerouter.dev/v1"
|
||||
BACKEND_KEY = "closerouter_G7GChTmljnOmIlJaD92YKaIzLHeMjErvbrKEBRxhsCY"
|
||||
PORT = 20141
|
||||
KEYS_FILE = Path(r"C:\Users\User\lobehub_api_keys.json")
|
||||
TOKEN_CACHE = {} # email → token cache
|
||||
|
||||
MODELS = [
|
||||
"claude-opus-4.8","claude-opus-4.7","claude-opus-4.6","claude-opus-4.5",
|
||||
"claude-sonnet-5","claude-sonnet-4.6","claude-sonnet-4.5","claude-haiku-4.5",
|
||||
"gpt-5.5","gpt-5.4","gpt-5.4-mini","gpt-5.3-codex-spark",
|
||||
"deepseek-v4-pro","deepseek-v4-flash",
|
||||
"glm-5.2","glm-5.1","kimi-k2.7-code","kimi-k2.6",
|
||||
"qwen-3.7-plus","qwen-3.7-max",
|
||||
]
|
||||
|
||||
MODEL_PREFIX = {
|
||||
"claude": "anthropic/", "gpt": "openai/", "deepseek": "deepseek/",
|
||||
"glm": "z-ai/", "kimi": "moonshotai/", "qwen": "qwen/",
|
||||
}
|
||||
|
||||
with open(KEYS_FILE) as f:
|
||||
KEY_DATA = json.load(f)
|
||||
KEYS = {k['api_key']: k for k in KEY_DATA['keys']}
|
||||
print(f"[Gateway] {len(KEYS)} keys | {len(MODELS)} models | closerouter backend")
|
||||
|
||||
def resolve_model(model):
|
||||
for prefix, provider in MODEL_PREFIX.items():
|
||||
if model.startswith(prefix):
|
||||
return f"{provider}{model}"
|
||||
return model
|
||||
|
||||
def get_token(email, pw):
|
||||
cache_key = f"{email}:{pw}"
|
||||
if cache_key in TOKEN_CACHE:
|
||||
cached = TOKEN_CACHE[cache_key]
|
||||
if cached['expires'] > time.time():
|
||||
return cached['token']
|
||||
try:
|
||||
r = httpx.post(f"{BASE_URL}/api/auth/sign-in/email",
|
||||
json={"email": email, "password": pw},
|
||||
headers={"Origin": BASE_URL, "Referer": f"{BASE_URL}/signin"},
|
||||
timeout=10)
|
||||
if r.status_code == 200 and "token" in r.json():
|
||||
token = [REDACTED])["token"]
|
||||
TOKEN_CACHE[cache_key] = {"token": token, "expires": time.time() + 3600}
|
||||
return token
|
||||
except:
|
||||
pass
|
||||
return None
|
||||
|
||||
class Gateway(BaseHTTPRequestHandler):
|
||||
def _json(self, data, status=200):
|
||||
self.send_response(status)
|
||||
self.send_header("Content-Type", "application/json")
|
||||
self.send_header("Access-Control-Allow-Origin", "*")
|
||||
self.end_headers()
|
||||
self.wfile.write(json.dumps(data, ensure_ascii=False).encode())
|
||||
|
||||
def _auth(self):
|
||||
auth = self.headers.get("Authorization", "")
|
||||
if not auth.startswith("Bearer "):
|
||||
return None
|
||||
key = auth[7:]
|
||||
if key == "local":
|
||||
return {"email": "local", "password": "local"}
|
||||
if key in KEYS:
|
||||
return KEYS[key]
|
||||
if ":" in key and "@" in key:
|
||||
e, p = key.split(":", 1)
|
||||
return {"email": e, "password": p}
|
||||
return None
|
||||
|
||||
def do_GET(self):
|
||||
if self.path == "/health":
|
||||
self._json({"status": "ok", "keys": len(KEYS), "models": len(MODELS), "backend": "closerouter"})
|
||||
elif self.path == "/v1/models":
|
||||
self._json({"object": "list", "data": [{"id": m, "object": "model"} for m in MODELS]})
|
||||
elif self.path == "/keys/stats":
|
||||
self._json({"total": len(KEYS), "cached_tokens": len(TOKEN_CACHE)})
|
||||
else:
|
||||
self._json({"error": "not found"}, 404)
|
||||
|
||||
def do_POST(self):
|
||||
if self.path == "/v1/chat/completions":
|
||||
self._chat()
|
||||
elif self.path == "/v1/embeddings":
|
||||
self._json({"error": "embeddings not supported"}, 400)
|
||||
else:
|
||||
self._json({"error": "not found"}, 404)
|
||||
|
||||
def _chat(self):
|
||||
account = self._auth()
|
||||
if not account:
|
||||
self._json({"error": "Unauthorized. Use Bearer <api_key> or Bearer local"}, 401)
|
||||
return
|
||||
|
||||
try:
|
||||
body = json.loads(self.rfile.read(int(self.headers.get("Content-Length", 0))))
|
||||
except:
|
||||
self._json({"error": "Invalid JSON"}, 400); return
|
||||
|
||||
model = body.get("model", "deepseek-v4-pro")
|
||||
messages = body.get("messages", [])
|
||||
if not messages:
|
||||
self._json({"error": "messages required"}, 400); return
|
||||
|
||||
backend_model = resolve_model(model)
|
||||
try:
|
||||
r = httpx.post(f"{BACKEND}/chat/completions",
|
||||
headers={"Authorization": f"Bearer {BACKEND_KEY}", "Content-Type": "application/json"},
|
||||
json={
|
||||
"model": backend_model,
|
||||
"messages": messages,
|
||||
"max_tokens": body.get("max_tokens", 4096),
|
||||
"stream": False,
|
||||
},
|
||||
timeout=180)
|
||||
if r.status_code == 200:
|
||||
self._json(r.json())
|
||||
else:
|
||||
self._json({"error": f"Backend {r.status_code}: {r.text[:300]}"}, 500)
|
||||
except Exception as e:
|
||||
self._json({"error": str(e)}, 500)
|
||||
|
||||
def log_message(self, f, *a):
|
||||
pass
|
||||
|
||||
print(f"[Gateway] :{PORT} | {len(KEYS)} keys | 20 models | closerouter")
|
||||
while True:
|
||||
try:
|
||||
HTTPServer(("127.0.0.1", PORT), Gateway).serve_forever()
|
||||
except Exception as e:
|
||||
print(f"[Gateway] Restart: {e}")
|
||||
time.sleep(3)
|
||||
Reference in New Issue
Block a user