132 lines
4.8 KiB
Python
132 lines
4.8 KiB
Python
"""
|
|
Conol.ai Proxy Handler — OpenAI-compatible API on :8080
|
|
Proxies requests to DashScope (deepseek-v4-pro) with conol.ai model names.
|
|
Template — customize AUTH_TOKEN and backend before use.
|
|
"""
|
|
import http.server
|
|
import json
|
|
import os
|
|
import time
|
|
import requests
|
|
|
|
AUTH_TOKEN = "YOUR_BEARER_TOKEN_HERE"
|
|
PORT = 8080
|
|
DASHSCOPE_KEY = os.environ.get("HERMES_DASHSCOPE_API_KEY", "")
|
|
DASHSCOPE_URL = "https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions"
|
|
|
|
# All 28 conol.ai agent-server models + extras
|
|
CONOL_MODELS = [
|
|
"claude-opus-4-8", "claude-fable-5", "claude-opus-4-7",
|
|
"claude-sonnet-5", "claude-sonnet-4-6", "claude-haiku-4-5",
|
|
"gpt-5.5", "gpt-5.5-pro", "gpt-5.6-sol", "gpt-5.6-terra", "gpt-5.6-luna",
|
|
"deepseek-v4-pro", "deepseek-v4-flash",
|
|
"openrouter-fusion", "glm-5.2", "glm-5.1", "hy3",
|
|
"kimi-k3", "kimi-k2.7-code",
|
|
"qwen3.7-plus", "qwen3.7-max",
|
|
"minimax-m3", "step-3.7-flash",
|
|
"gemini-3.5-flash", "gemini-3.1-pro", "gemini-3.1-flash-lite",
|
|
"grok-4.3", "mimo-v2.5", "mimo-v2.5-pro",
|
|
"conol-agent", "gpt-4o"
|
|
]
|
|
|
|
|
|
class ProxyHandler(http.server.BaseHTTPRequestHandler):
|
|
"""OpenAI-compatible proxy with Bearer auth and model mapping."""
|
|
|
|
def _check_auth(self):
|
|
auth = self.headers.get("Authorization", "")
|
|
return f"Bearer {AUTH_TOKEN}" in auth
|
|
|
|
def _json(self, code, data):
|
|
self.send_response(code)
|
|
self.send_header("Content-Type", "application/json")
|
|
self.send_header("Access-Control-Allow-Origin", "*")
|
|
self.end_headers()
|
|
self.wfile.write(json.dumps(data).encode())
|
|
|
|
def do_OPTIONS(self):
|
|
self.send_response(200)
|
|
self.send_header("Access-Control-Allow-Origin", "*")
|
|
self.send_header("Access-Control-Allow-Methods", "GET, POST, OPTIONS")
|
|
self.send_header("Access-Control-Allow-Headers", "Authorization, Content-Type")
|
|
self.end_headers()
|
|
|
|
def do_GET(self):
|
|
if not self._check_auth():
|
|
return self._json(401, {"error": "Unauthorized"})
|
|
|
|
if self.path == "/v1/models":
|
|
models = {
|
|
"object": "list",
|
|
"data": [{"id": m, "object": "model", "owned_by": "conol"} for m in CONOL_MODELS]
|
|
}
|
|
self._json(200, models)
|
|
elif self.path == "/health":
|
|
self._json(200, {
|
|
"status": "ok",
|
|
"backend": "dashscope",
|
|
"model": "deepseek-v4-pro",
|
|
"conol_models": len(CONOL_MODELS),
|
|
"uptime": int(time.time())
|
|
})
|
|
else:
|
|
self._json(404, {"error": "Not found"})
|
|
|
|
def do_POST(self):
|
|
if not self._check_auth():
|
|
return self._json(401, {"error": "Unauthorized"})
|
|
|
|
if self.path == "/v1/chat/completions":
|
|
content_length = int(self.headers.get("Content-Length", 0))
|
|
body = self.rfile.read(content_length)
|
|
data = json.loads(body)
|
|
|
|
stream = data.get("stream", False)
|
|
model = data.get("model", "conol-agent")
|
|
messages = data.get("messages", [])
|
|
max_tokens = data.get("max_tokens", 4096)
|
|
temperature = data.get("temperature", 0.7)
|
|
|
|
payload = {
|
|
"model": "deepseek-v4-pro",
|
|
"messages": messages,
|
|
"max_tokens": min(max_tokens, 4096),
|
|
"temperature": temperature,
|
|
"stream": stream
|
|
}
|
|
|
|
headers = {
|
|
"Authorization": f"Bearer {DASHSCOPE_KEY}",
|
|
"Content-Type": "application/json"
|
|
}
|
|
|
|
try:
|
|
r = requests.post(DASHSCOPE_URL, json=payload, headers=headers, timeout=120, stream=stream)
|
|
|
|
if stream:
|
|
self.send_response(r.status_code)
|
|
self.send_header("Content-Type", "text/event-stream")
|
|
self.end_headers()
|
|
for chunk in r.iter_content(chunk_size=4096):
|
|
if chunk:
|
|
self.wfile.write(chunk)
|
|
self.wfile.flush()
|
|
else:
|
|
resp_data = r.json()
|
|
if "choices" in resp_data:
|
|
resp_data["model"] = model
|
|
self._json(r.status_code, resp_data)
|
|
except Exception as e:
|
|
self._json(500, {"error": str(e)})
|
|
else:
|
|
self._json(404, {"error": "Not found"})
|
|
|
|
def log_message(self, format, *args):
|
|
if "/v1/" in str(args):
|
|
print(f"[{time.strftime('%H:%M:%S')}] {args[0]}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
print(f"[PROXY] :{PORT} | Auth: Bearer {AUTH_TOKEN[:15]}... | {len(CONOL_MODELS)} models")
|
|
server = http.server.HTTPServer(("0.0.0.0", PORT), ProxyHandler)
|
|
server.serve_forever() |