bahi-bh commited on
Commit
3bf92b5
·
verified ·
1 Parent(s): 986712b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +27 -74
app.py CHANGED
@@ -19,14 +19,12 @@ from fastapi.templating import Jinja2Templates
19
  HOST = "0.0.0.0"
20
  PORT = int(os.getenv("PORT", "7860"))
21
 
22
- # بيانات حساب Z.AI / Zhipu GLM
 
23
  ZAI_EMAIL = os.getenv("ZAI_EMAIL", "").strip()
24
  ZAI_PASSWORD = os.getenv("ZAI_PASSWORD", "").strip()
25
- ZAI_API_KEY = os.getenv("ZAI_API_KEY", "").strip()
26
 
27
- # روابط الخدمة الخاصة بـ Z.AI / Zhipu AI
28
  ZAI_BASE_URL = "https://open.bigmodel.cn/api/paas/v4"
29
- ZAI_AUTH_URL = "https://open.bigmodel.cn/api/paas/v4/auth/login"
30
 
31
  ZAI_MODELS = [
32
  "glm-4",
@@ -56,8 +54,8 @@ logger = logging.getLogger("zai-gateway")
56
 
57
  app = FastAPI(
58
  title="Z.AI / GLM Gateway Engine",
59
- version="3.0.0",
60
- description="Professional Production Gateway for Z.AI (Zhipu GLM-4) supporting OpenAI & Claude APIs"
61
  )
62
 
63
  app.add_middleware(
@@ -71,60 +69,19 @@ app.add_middleware(
71
  templates = Jinja2Templates(directory="templates")
72
 
73
  # ============================================================
74
- # Z.AI SESSION & AUTH MANAGER
75
  # ============================================================
76
 
77
- class ZAISessionManager:
78
- def __init__(self, email: str, password: str, api_key: str):
79
- self.email = email
80
- self.password = password
81
- self.api_key = api_key
82
- self.access_token: Optional[str] = None
83
- self.token_expiry: float = 0
84
-
85
- async def get_token(self) -> str:
86
- """إدارة واستخراج التوكن تلقائياً وإعادة التجديد عند انتهاء الصلاحية"""
87
- if self.api_key:
88
- return self.api_key
89
-
90
- if self.access_token and time.time() < self.token_expiry:
91
- return self.access_token
92
-
93
- logger.info(f"[Z.AI Auth] جاري استخراج جلسة جديدة للحساب: {self.email}")
94
-
95
- if not self.email or not self.password:
96
- raise HTTPException(
97
- status_code=400,
98
- detail="بيانات ZAI_EMAIL و ZAI_PASSWORD أو ZAI_API_KEY غير متوفرة في متغيرات البيئة."
99
- )
100
-
101
- headers = {
102
- "Content-Type": "application/json",
103
- "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
104
- }
105
-
106
- payload = {
107
- "username": self.email,
108
- "password": self.password
109
- }
110
-
111
- async with httpx.AsyncClient(timeout=15.0) as client:
112
- try:
113
- resp = await client.post(ZAI_AUTH_URL, json=payload, headers=headers)
114
- if resp.status_code == 200:
115
- data = resp.json()
116
- self.access_token = data.get("token") or data.get("access_token")
117
- self.token_expiry = time.time() + 7200 # صلاحية ساعتين
118
- logger.info("[Z.AI Auth] تم تسجيل الدخول واستخراج الجلسة بنجاح.")
119
- return self.access_token
120
- else:
121
- logger.error(f"[Z.AI Auth Error] {resp.status_code}: {resp.text}")
122
- raise HTTPException(status_code=401, detail="فشل المصادقة مع خوادم Z.AI.")
123
- except Exception as e:
124
- logger.error(f"[Z.AI Connection Exception] {e}")
125
- raise HTTPException(status_code=500, detail=f"خطأ في الاتصال بنظام Z.AI: {str(e)}")
126
-
127
- session_manager = ZAISessionManager(ZAI_EMAIL, ZAI_PASSWORD, ZAI_API_KEY)
128
 
129
  # ============================================================
130
  # HELPER FUNCTIONS
@@ -160,16 +117,17 @@ def normalize_messages(messages: List[Dict]) -> List[Dict]:
160
  @app.on_event("startup")
161
  async def startup_event():
162
  logger.info("=" * 60)
163
- logger.info("Z.AI (GLM-4) Gateway Engine Started")
164
  logger.info("Port: %s", PORT)
165
- logger.info("Auth Configured: %s", bool(ZAI_EMAIL or ZAI_API_KEY))
166
  logger.info("=" * 60)
167
 
168
  # ============================================================
169
- # OPENAI COMPATIBLE ENDPOINTS
170
  # ============================================================
171
 
172
  @app.get("/v1/models")
 
173
  async def list_models():
174
  models_data = [
175
  {"id": model, "object": "model", "created": int(time.time()), "owned_by": "z-ai-glm"}
@@ -178,6 +136,7 @@ async def list_models():
178
  return {"object": "list", "data": models_data}
179
 
180
  @app.post("/v1/chat/completions")
 
181
  async def chat_completions(request: Request):
182
  try:
183
  req_data = await request.json()
@@ -198,7 +157,7 @@ async def chat_completions(request: Request):
198
  "temperature": req_data.get("temperature", 0.7)
199
  }
200
 
201
- token = await session_manager.get_token()
202
  headers = {
203
  "Authorization": f"Bearer {token}",
204
  "Content-Type": "application/json",
@@ -213,6 +172,7 @@ async def chat_completions(request: Request):
213
  async with client.stream("POST", endpoint, headers=headers, json=payload) as response:
214
  if response.status_code != 200:
215
  err_body = await response.aread()
 
216
  yield f"data: {json.dumps({'error': err_body.decode('utf-8')})}\n\n"
217
  return
218
  async for chunk in response.aiter_bytes():
@@ -228,6 +188,7 @@ async def chat_completions(request: Request):
228
  async with httpx.AsyncClient(timeout=120.0) as client:
229
  response = await client.post(endpoint, headers=headers, json=payload)
230
  if response.status_code != 200:
 
231
  return JSONResponse(status_code=response.status_code, content={"error": response.text})
232
  return JSONResponse(content=response.json(), status_code=200)
233
 
@@ -245,6 +206,7 @@ async def list_claude_models():
245
  }
246
 
247
  @app.post("/anthropic/v1/messages")
 
248
  async def claude_messages(request: Request):
249
  try:
250
  req_data = await request.json()
@@ -268,7 +230,7 @@ async def claude_messages(request: Request):
268
  "temperature": req_data.get("temperature", 0.7)
269
  }
270
 
271
- token = await session_manager.get_token()
272
  headers = {
273
  "Authorization": f"Bearer {token}",
274
  "Content-Type": "application/json",
@@ -340,27 +302,18 @@ async def claude_messages(request: Request):
340
  async def health():
341
  return {
342
  "status": "online",
343
- "engine": "Z.AI (GLM-4)",
344
- "configured": bool(ZAI_EMAIL or ZAI_API_KEY)
345
  }
346
 
347
  @app.get("/")
348
  async def index(request: Request):
349
- template_path = os.path.join("templates", "welcome.html")
350
- if os.path.isfile(template_path):
351
- return templates.TemplateResponse("welcome.html", {"request": request})
352
  return {
353
  "service": "Z.AI Gateway API Engine",
354
  "status": "running",
355
  "openai_endpoint": "/v1/chat/completions",
356
- "anthropic_endpoint": "/anthropic/v1/messages",
357
- "health": "/health"
358
  }
359
 
360
- # ============================================================
361
- # ENTRYPOINT
362
- # ============================================================
363
-
364
  if __name__ == "__main__":
365
  import uvicorn
366
  uvicorn.run(app, host=HOST, port=PORT)
 
19
  HOST = "0.0.0.0"
20
  PORT = int(os.getenv("PORT", "7860"))
21
 
22
+ # المفتاح أو الحساب الخاص بـ Z.AI / BigModel
23
+ ZAI_API_KEY = os.getenv("ZAI_API_KEY", "").strip()
24
  ZAI_EMAIL = os.getenv("ZAI_EMAIL", "").strip()
25
  ZAI_PASSWORD = os.getenv("ZAI_PASSWORD", "").strip()
 
26
 
 
27
  ZAI_BASE_URL = "https://open.bigmodel.cn/api/paas/v4"
 
28
 
29
  ZAI_MODELS = [
30
  "glm-4",
 
54
 
55
  app = FastAPI(
56
  title="Z.AI / GLM Gateway Engine",
57
+ version="3.1.0",
58
+ description="Fixed Production Gateway for Z.AI (Zhipu GLM-4)"
59
  )
60
 
61
  app.add_middleware(
 
69
  templates = Jinja2Templates(directory="templates")
70
 
71
  # ============================================================
72
+ # Z.AI AUTHENTICATION MANAGER
73
  # ============================================================
74
 
75
+ def get_auth_token() -> str:
76
+ """الحصول على التوكن الصحيح لـ Z.AI"""
77
+ token = ZAI_API_KEY or ZAI_PASSWORD or ZAI_EMAIL
78
+ if not token:
79
+ logger.error("[Z.AI Auth] لم يتم توفير ZAI_API_KEY أو بيانات الاعتماد!")
80
+ raise HTTPException(
81
+ status_code=401,
82
+ detail="يرجى إضافة ZAI_API_KEY في متغيرات البيئة (Environment Variables)."
83
+ )
84
+ return token
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
85
 
86
  # ============================================================
87
  # HELPER FUNCTIONS
 
117
  @app.on_event("startup")
118
  async def startup_event():
119
  logger.info("=" * 60)
120
+ logger.info("Z.AI (GLM-4) Gateway Engine Started Successfully")
121
  logger.info("Port: %s", PORT)
122
+ logger.info("API Key/Token Configured: %s", bool(ZAI_API_KEY or ZAI_PASSWORD))
123
  logger.info("=" * 60)
124
 
125
  # ============================================================
126
+ # OPENAI COMPATIBLE ENDPOINTS (مع إضافة التوجيه القصير لعدم حدوث 404)
127
  # ============================================================
128
 
129
  @app.get("/v1/models")
130
+ @app.get("/models")
131
  async def list_models():
132
  models_data = [
133
  {"id": model, "object": "model", "created": int(time.time()), "owned_by": "z-ai-glm"}
 
136
  return {"object": "list", "data": models_data}
137
 
138
  @app.post("/v1/chat/completions")
139
+ @app.post("/chat/completions")
140
  async def chat_completions(request: Request):
141
  try:
142
  req_data = await request.json()
 
157
  "temperature": req_data.get("temperature", 0.7)
158
  }
159
 
160
+ token = get_auth_token()
161
  headers = {
162
  "Authorization": f"Bearer {token}",
163
  "Content-Type": "application/json",
 
172
  async with client.stream("POST", endpoint, headers=headers, json=payload) as response:
173
  if response.status_code != 200:
174
  err_body = await response.aread()
175
+ logger.error(f"[Z.AI Error] Status {response.status_code}: {err_body.decode('utf-8')}")
176
  yield f"data: {json.dumps({'error': err_body.decode('utf-8')})}\n\n"
177
  return
178
  async for chunk in response.aiter_bytes():
 
188
  async with httpx.AsyncClient(timeout=120.0) as client:
189
  response = await client.post(endpoint, headers=headers, json=payload)
190
  if response.status_code != 200:
191
+ logger.error(f"[Z.AI Error] Status {response.status_code}: {response.text}")
192
  return JSONResponse(status_code=response.status_code, content={"error": response.text})
193
  return JSONResponse(content=response.json(), status_code=200)
194
 
 
206
  }
207
 
208
  @app.post("/anthropic/v1/messages")
209
+ @app.post("/v1/messages")
210
  async def claude_messages(request: Request):
211
  try:
212
  req_data = await request.json()
 
230
  "temperature": req_data.get("temperature", 0.7)
231
  }
232
 
233
+ token = get_auth_token()
234
  headers = {
235
  "Authorization": f"Bearer {token}",
236
  "Content-Type": "application/json",
 
302
  async def health():
303
  return {
304
  "status": "online",
305
+ "engine": "Z.AI (GLM-4)"
 
306
  }
307
 
308
  @app.get("/")
309
  async def index(request: Request):
 
 
 
310
  return {
311
  "service": "Z.AI Gateway API Engine",
312
  "status": "running",
313
  "openai_endpoint": "/v1/chat/completions",
314
+ "anthropic_endpoint": "/anthropic/v1/messages"
 
315
  }
316
 
 
 
 
 
317
  if __name__ == "__main__":
318
  import uvicorn
319
  uvicorn.run(app, host=HOST, port=PORT)