Row-proxy / camoufox_server.py
Moge-Row's picture
add camoufox server and updated dockerfile
26a79ca
import json, uuid, threading
from flask import Flask, request, jsonify
from camoufox.sync_api import Camoufox
app = Flask(__name__)
lock = threading.Lock()
with Camoufox(headless=True) as browser:
ctx = browser.new_context()
page = ctx.new_page()
page.goto("https://chat.z.ai")
page.wait_for_load_state("networkidle")
print("Camoufox ready", flush=True)
def do_chat(messages, model):
body = json.dumps({
"stream": True,
"model": model,
"messages": messages,
"params": {},
"extra": {},
"features": {"image_generation": False, "web_search": False, "preview_mode": True, "flags": [], "enable_thinking": False},
"chat_id": str(uuid.uuid4()),
"id": str(uuid.uuid4()),
})
js = """(bodyStr) => {
return new Promise((resolve) => {
fetch("/api/v2/chat/completions", {
method: "POST",
headers: {"Content-Type": "application/json"},
body: bodyStr
}).then(r => r.text()).then(t => resolve(t)).catch(e => resolve("ERROR:" + e));
setTimeout(() => resolve("TIMEOUT"), 30000);
});
}"""
result = page.evaluate(js, body)
content = ""
for line in str(result).splitlines():
if line.startswith("data: "):
try:
d = json.loads(line[6:])
delta = d.get("data", {}).get("delta_content", "")
phase = d.get("data", {}).get("phase", "")
if phase == "answer":
content += delta
except:
pass
return content
@app.route("/camoufox/chat", methods=["POST"])
def completions():
data = request.json
messages = data.get("messages", [])
model = data.get("model", "glm-4.7")
with lock:
content = do_chat(messages, model)
return jsonify({"content": content})
@app.route("/camoufox/health", methods=["GET"])
def health():
return jsonify({"status": "ok"})
app.run(port=8002, threaded=False)