Spaces:
Paused
Paused
add camoufox server and updated dockerfile
Browse files- Dockerfile +13 -14
- camoufox_server.py +63 -0
Dockerfile
CHANGED
|
@@ -1,29 +1,28 @@
|
|
| 1 |
FROM golang:1.23-alpine AS builder
|
| 2 |
-
|
| 3 |
WORKDIR /app
|
| 4 |
-
|
| 5 |
-
# 安装 git 和 ca-certificates,某些依赖可能需要
|
| 6 |
RUN apk add --no-cache git ca-certificates
|
| 7 |
-
|
| 8 |
COPY go.mod go.sum ./
|
| 9 |
RUN go mod download -x || (cat go.mod && cat go.sum && exit 1)
|
| 10 |
-
|
| 11 |
COPY . .
|
| 12 |
RUN CGO_ENABLED=0 GOOS=linux go build -o zai-proxy .
|
| 13 |
|
| 14 |
-
FROM
|
| 15 |
-
|
| 16 |
WORKDIR /app
|
| 17 |
|
| 18 |
-
#
|
| 19 |
-
RUN
|
| 20 |
|
| 21 |
-
|
|
|
|
| 22 |
|
| 23 |
-
#
|
| 24 |
-
|
| 25 |
|
| 26 |
-
|
|
|
|
|
|
|
| 27 |
|
|
|
|
| 28 |
ENV PORT=7860
|
| 29 |
-
|
|
|
|
|
|
| 1 |
FROM golang:1.23-alpine AS builder
|
|
|
|
| 2 |
WORKDIR /app
|
|
|
|
|
|
|
| 3 |
RUN apk add --no-cache git ca-certificates
|
|
|
|
| 4 |
COPY go.mod go.sum ./
|
| 5 |
RUN go mod download -x || (cat go.mod && cat go.sum && exit 1)
|
|
|
|
| 6 |
COPY . .
|
| 7 |
RUN CGO_ENABLED=0 GOOS=linux go build -o zai-proxy .
|
| 8 |
|
| 9 |
+
FROM python:3.11-slim
|
|
|
|
| 10 |
WORKDIR /app
|
| 11 |
|
| 12 |
+
# Instalar dependencias del sistema para Firefox/Camoufox
|
| 13 |
+
RUN apt-get update && apt-get install -y wget curl ca-certificates libgtk-3-0 libdbus-glib-1-2 libxt6 libx11-xcb1 xvfb --no-install-recommends && rm -rf /var/lib/apt/lists/*
|
| 14 |
|
| 15 |
+
# Instalar Python deps
|
| 16 |
+
RUN pip install camoufox[geoip] flask --no-cache-dir
|
| 17 |
|
| 18 |
+
# Descargar Camoufox browser
|
| 19 |
+
RUN python3 -m camoufox fetch
|
| 20 |
|
| 21 |
+
# Copiar binario Go
|
| 22 |
+
COPY --from=builder /app/zai-proxy .
|
| 23 |
+
COPY . .
|
| 24 |
|
| 25 |
+
EXPOSE 7860
|
| 26 |
ENV PORT=7860
|
| 27 |
+
|
| 28 |
+
CMD ["sh", "-c", "python3 camoufox_server.py & ./zai-proxy"]
|
camoufox_server.py
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import json, uuid, threading
|
| 2 |
+
from flask import Flask, request, jsonify
|
| 3 |
+
from camoufox.sync_api import Camoufox
|
| 4 |
+
|
| 5 |
+
app = Flask(__name__)
|
| 6 |
+
lock = threading.Lock()
|
| 7 |
+
|
| 8 |
+
with Camoufox(headless=True) as browser:
|
| 9 |
+
ctx = browser.new_context()
|
| 10 |
+
page = ctx.new_page()
|
| 11 |
+
page.goto("https://chat.z.ai")
|
| 12 |
+
page.wait_for_load_state("networkidle")
|
| 13 |
+
print("Camoufox ready", flush=True)
|
| 14 |
+
|
| 15 |
+
def do_chat(messages, model):
|
| 16 |
+
body = json.dumps({
|
| 17 |
+
"stream": True,
|
| 18 |
+
"model": model,
|
| 19 |
+
"messages": messages,
|
| 20 |
+
"params": {},
|
| 21 |
+
"extra": {},
|
| 22 |
+
"features": {"image_generation": False, "web_search": False, "preview_mode": True, "flags": [], "enable_thinking": False},
|
| 23 |
+
"chat_id": str(uuid.uuid4()),
|
| 24 |
+
"id": str(uuid.uuid4()),
|
| 25 |
+
})
|
| 26 |
+
js = """(bodyStr) => {
|
| 27 |
+
return new Promise((resolve) => {
|
| 28 |
+
fetch("/api/v2/chat/completions", {
|
| 29 |
+
method: "POST",
|
| 30 |
+
headers: {"Content-Type": "application/json"},
|
| 31 |
+
body: bodyStr
|
| 32 |
+
}).then(r => r.text()).then(t => resolve(t)).catch(e => resolve("ERROR:" + e));
|
| 33 |
+
setTimeout(() => resolve("TIMEOUT"), 30000);
|
| 34 |
+
});
|
| 35 |
+
}"""
|
| 36 |
+
result = page.evaluate(js, body)
|
| 37 |
+
content = ""
|
| 38 |
+
for line in str(result).splitlines():
|
| 39 |
+
if line.startswith("data: "):
|
| 40 |
+
try:
|
| 41 |
+
d = json.loads(line[6:])
|
| 42 |
+
delta = d.get("data", {}).get("delta_content", "")
|
| 43 |
+
phase = d.get("data", {}).get("phase", "")
|
| 44 |
+
if phase == "answer":
|
| 45 |
+
content += delta
|
| 46 |
+
except:
|
| 47 |
+
pass
|
| 48 |
+
return content
|
| 49 |
+
|
| 50 |
+
@app.route("/camoufox/chat", methods=["POST"])
|
| 51 |
+
def completions():
|
| 52 |
+
data = request.json
|
| 53 |
+
messages = data.get("messages", [])
|
| 54 |
+
model = data.get("model", "glm-4.7")
|
| 55 |
+
with lock:
|
| 56 |
+
content = do_chat(messages, model)
|
| 57 |
+
return jsonify({"content": content})
|
| 58 |
+
|
| 59 |
+
@app.route("/camoufox/health", methods=["GET"])
|
| 60 |
+
def health():
|
| 61 |
+
return jsonify({"status": "ok"})
|
| 62 |
+
|
| 63 |
+
app.run(port=8002, threaded=False)
|