bahi-bh commited on
Commit
36aa72c
·
verified ·
1 Parent(s): d3e94f4

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +192 -269
app.py CHANGED
@@ -7,34 +7,37 @@ import asyncio
7
  import json
8
  import time
9
  import uuid
 
 
10
  import g4f
11
  from g4f.client import Client
12
- from g4f.models import Model
13
- from g4f.providers import Provider, ProviderType
14
- import logging
15
 
16
  # =====================================================
17
  # LOGGING
18
  # =====================================================
 
19
  logging.basicConfig(level=logging.INFO)
20
  logger = logging.getLogger(__name__)
21
 
22
  # =====================================================
23
  # CONFIG
24
  # =====================================================
25
- API_KEY = "sk-your-secret-key" # غير هذا في الإنتاج
 
26
 
27
  # =====================================================
28
  # FASTAPI
29
  # =====================================================
 
30
  app = FastAPI(
31
  title="Universal AI Gateway",
32
- version="3.1.0"
33
  )
34
 
35
  # =====================================================
36
- # CORS (للسماح للواجهة بالتواصل)
37
  # =====================================================
 
38
  app.add_middleware(
39
  CORSMiddleware,
40
  allow_origins=["*"],
@@ -46,6 +49,7 @@ app.add_middleware(
46
  # =====================================================
47
  # MODELS
48
  # =====================================================
 
49
  class Message(BaseModel):
50
  role: str
51
  content: str
@@ -60,211 +64,217 @@ class ChatRequest(BaseModel):
60
  # =====================================================
61
  # AUTH
62
  # =====================================================
 
63
  def verify_api_key(req: Request):
 
64
  auth = req.headers.get("Authorization")
 
 
65
  if not auth:
66
- raise HTTPException(
67
- status_code=401,
68
- detail="Missing Authorization Header"
69
- )
70
  if not auth.startswith("Bearer "):
71
  raise HTTPException(
72
  status_code=401,
73
  detail="Invalid Authorization Format"
74
  )
75
- token = auth.replace("Bearer ", "")
 
 
76
  if token != API_KEY:
77
  raise HTTPException(
78
  status_code=403,
79
  detail="Invalid API Key"
80
  )
81
 
82
- # =====================================================
83
- # PROVIDERS - قائمة المزودين العاملين حالياً
84
- # =====================================================
85
- def get_working_providers():
86
- """إرجاع قائمة المزودين المتاحين في الإصدار الحالي من g4f"""
87
- providers = []
88
-
89
- # المزودين المعروفين بأنهم يعملون حالياً
90
- try:
91
- # محاولة استيراد المزودين المتاحين
92
- from g4f.providers import (
93
- Blackbox,
94
- DuckDuckGo,
95
- Free2GPT,
96
- Liaobots,
97
- Copilot,
98
- Gemini,
99
- OpenaiChat,
100
- DeepAi
101
- )
102
-
103
- # إضافة المزودين الذين يعملون عادةً
104
- providers = [
105
- DuckDuckGo,
106
- Blackbox,
107
- Free2GPT,
108
- Liaobots,
109
- Copilot,
110
- Gemini,
111
- OpenaiChat,
112
- DeepAi
113
- ]
114
- except ImportError:
115
- logger.warning("بعض المزودين غير متاحين، استخدام المزودين الأساسيين")
116
- # محاولة الحصول على المزودين من g4f.Provider مباشرة
117
- if hasattr(g4f.Provider, 'DuckDuckGo'):
118
- providers.append(g4f.Provider.DuckDuckGo)
119
- if hasattr(g4f.Provider, 'Blackbox'):
120
- providers.append(g4f.Provider.Blackbox)
121
- if hasattr(g4f.Provider, 'Free2GPT'):
122
- providers.append(g4f.Provider.Free2GPT)
123
- if hasattr(g4f.Provider, 'Liaobots'):
124
- providers.append(g4f.Provider.Liaobots)
125
-
126
- return providers if providers else [g4f.Provider.Auto]
127
 
128
  # =====================================================
129
  # ROOT
130
  # =====================================================
 
131
  @app.get("/")
132
  async def root():
 
133
  return {
134
  "status": "online",
135
  "service": "Universal AI Gateway",
136
- "version": "3.1.0"
137
  }
138
 
139
  # =====================================================
140
- # MODELS LIST (نقطة نهاية متوافقة مع OpenAI)
141
  # =====================================================
 
142
  @app.get("/v1/models")
143
  async def get_models():
144
- """إرجاع قائمة النماذج المتاحة"""
145
- models_list = []
146
-
 
 
 
 
 
 
 
 
 
 
 
 
147
  try:
148
- # محاولة الحصول على النماذج من g4f
149
- if hasattr(g4f.models, '_all_models'):
150
- for model in list(g4f.models._all_models)[:30]: # حد أقصى 30 نم��ذج
151
- models_list.append({
 
 
 
 
152
  "id": str(model),
153
  "object": "model",
154
  "created": int(time.time()),
155
  "owned_by": "g4f"
156
  })
 
157
  except Exception as e:
158
- logger.error(f"خطأ في جلب النماذج: {e}")
159
-
160
- # نماذج احتياطية إذا فشل الجلب
161
- if not models_list:
162
- fallback_models = [
163
- "gpt-4o-mini", "gpt-4o", "gpt-4", "gpt-3.5-turbo",
164
- "claude-3-haiku", "llama-3.1-70b", "mixtral-8x7b",
165
- "gemini-flash", "deepseek-chat", "blackboxai"
166
- ]
167
- for model_name in fallback_models:
168
- models_list.append({
169
- "id": model_name,
170
  "object": "model",
171
  "created": int(time.time()),
172
  "owned_by": "g4f"
173
  })
174
-
175
  return {
176
  "object": "list",
177
- "data": models_list
178
  }
179
 
180
  # =====================================================
181
- # CHAT COMPLETIONS - الطريقة المحدثة باستخدام Client
182
  # =====================================================
 
183
  @app.post("/v1/chat/completions")
184
  async def chat_completions(
185
  req: Request,
186
  body: ChatRequest
187
  ):
 
188
  verify_api_key(req)
189
-
190
- # تحويل الرسائل إلى الشكل المطلوب
191
  messages = [
192
- {"role": m.role, "content": m.content}
 
 
 
193
  for m in body.messages
194
  ]
195
-
196
- logger.info(f"طلب: model={body.model}, messages={len(messages)}, stream={body.stream}")
197
-
 
 
198
  # =================================================
199
- # وضع الدفق (Streaming) - للتجاوب الفوري
200
  # =================================================
 
201
  if body.stream:
 
202
  async def generate_stream():
203
- providers_list = get_working_providers()
204
- last_error = None
205
- response_text = ""
206
- chunk_id = f"chatcmpl-{uuid.uuid4().hex}"
207
-
208
- for provider in providers_list:
209
- try:
210
- # استخدام الطريقة الحديثة مع Client
211
- client = Client(provider=provider)
212
-
213
- stream_response = await asyncio.to_thread(
214
- client.chat.completions.create,
215
- model=body.model,
216
- messages=messages,
217
- stream=True
218
- )
219
-
220
- for chunk in stream_response:
221
- if chunk.choices and chunk.choices[0].delta.content:
 
 
 
 
 
222
  content = chunk.choices[0].delta.content
223
- response_text += content
 
 
224
  payload = {
225
  "id": chunk_id,
226
  "object": "chat.completion.chunk",
227
  "created": int(time.time()),
228
  "model": body.model,
229
- "choices": [{
230
- "index": 0,
231
- "delta": {"content": content},
232
- "finish_reason": None
233
- }]
 
 
 
 
234
  }
 
235
  yield f"data: {json.dumps(payload)}\n\n"
236
- await asyncio.sleep(0.01)
237
-
238
- # إرسال إشارة الانتهاء
239
- final_payload = {
240
- "id": chunk_id,
241
- "object": "chat.completion.chunk",
242
- "created": int(time.time()),
243
- "model": body.model,
244
- "choices": [{
 
 
 
 
 
 
 
245
  "index": 0,
246
  "delta": {},
247
  "finish_reason": "stop"
248
- }]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
249
  }
250
- yield f"data: {json.dumps(final_payload)}\n\n"
251
- yield "data: [DONE]\n\n"
252
- return
253
-
254
- except Exception as e:
255
- last_error = str(e)
256
- logger.warning(f"المزود {provider.__name__ if hasattr(provider, '__name__') else provider} فشل: {e}")
257
- continue
258
-
259
- # إذا فشلت كل المزودين
260
- error_payload = {
261
- "error": {
262
- "message": last_error or "All providers failed",
263
- "type": "server_error"
264
  }
265
- }
266
- yield f"data: {json.dumps(error_payload)}\n\n"
267
-
268
  return StreamingResponse(
269
  generate_stream(),
270
  media_type="text/event-stream",
@@ -274,154 +284,67 @@ async def chat_completions(
274
  "X-Accel-Buffering": "no"
275
  }
276
  )
277
-
278
  # =================================================
279
- # الوضع العادي (بدون دفق)
280
  # =================================================
281
- providers_list = get_working_providers()
282
- last_error = None
283
-
284
- for provider in providers_list:
 
 
 
 
 
 
 
 
 
285
  try:
286
- logger.info(f"محاولة استخدام المزود: {provider.__name__ if hasattr(provider, '__name__') else provider}")
287
-
288
- # الطريقة الحديثة باستخدام Client
289
- client = Client(provider=provider)
290
- response = await asyncio.to_thread(
291
- client.chat.completions.create,
292
- model=body.model,
293
- messages=messages
294
- )
295
-
296
  assistant_message = response.choices[0].message.content
297
-
298
- return JSONResponse({
299
- "id": f"chatcmpl-{uuid.uuid4().hex}",
300
- "object": "chat.completion",
301
- "created": int(time.time()),
302
- "model": body.model,
303
- "choices": [{
 
 
 
304
  "index": 0,
305
  "message": {
306
  "role": "assistant",
307
  "content": assistant_message
308
  },
309
  "finish_reason": "stop"
310
- }],
311
- "usage": {
312
- "prompt_tokens": 0,
313
- "completion_tokens": 0,
314
- "total_tokens": 0
315
- }
316
- })
317
-
318
- except Exception as e:
319
- last_error = str(e)
320
- logger.warning(f"المزود فشل: {e}")
321
- continue
322
-
323
- # إذا وصلنا إلى هنا، جميع المزودين فشلوا
324
- raise HTTPException(
325
- status_code=500,
326
- detail=last_error or "All providers failed. Please check your internet connection and try again."
327
- )
328
-
329
- # =====================================================
330
- # نقطة نهاية إضافية للاختبار - واجهة بسيطة
331
- # =====================================================
332
- @app.get("/test")
333
- async def test_ui():
334
- """صفحة HTML بسيطة لاختبار البوت"""
335
- return """
336
- <!DOCTYPE html>
337
- <html>
338
- <head>
339
- <title>اختبار البوت</title>
340
- <meta charset="utf-8">
341
- <style>
342
- body { font-family: Arial; max-width: 800px; margin: 50px auto; padding: 20px; }
343
- #chat { border: 1px solid #ccc; height: 400px; overflow-y: auto; padding: 10px; margin-bottom: 10px; }
344
- .user { background: #e3f2fd; padding: 8px; margin: 5px; border-radius: 10px; }
345
- .bot { background: #f5f5f5; padding: 8px; margin: 5px; border-radius: 10px; }
346
- #input { width: 80%; padding: 10px; }
347
- #send { padding: 10px 20px; }
348
- </style>
349
- </head>
350
- <body>
351
- <h1>اختبار البوت</h1>
352
- <div id="chat"></div>
353
- <input type="text" id="input" placeholder="اكتب رسالتك...">
354
- <button id="send">إرسال</button>
355
-
356
- <script>
357
- const API_KEY = "sk-your-secret-key";
358
-
359
- async function sendMessage() {
360
- const input = document.getElementById('input');
361
- const message = input.value.trim();
362
- if (!message) return;
363
-
364
- // عرض رسالة المستخدم
365
- const chatDiv = document.getElementById('chat');
366
- const userMsg = document.createElement('div');
367
- userMsg.className = 'user';
368
- userMsg.textContent = 'أنت: ' + message;
369
- chatDiv.appendChild(userMsg);
370
-
371
- // عرض مؤشر "يكتب..."
372
- const botMsg = document.createElement('div');
373
- botMsg.className = 'bot';
374
- botMsg.textContent = 'البوت: جاري التفكير...';
375
- chatDiv.appendChild(botMsg);
376
- chatDiv.scrollTop = chatDiv.scrollHeight;
377
-
378
- input.value = '';
379
-
380
- try {
381
- const response = await fetch('/v1/chat/completions', {
382
- method: 'POST',
383
- headers: {
384
- 'Content-Type': 'application/json',
385
- 'Authorization': 'Bearer ' + API_KEY
386
- },
387
- body: JSON.stringify({
388
- model: 'gpt-4o-mini',
389
- messages: [{role: 'user', content: message}],
390
- stream: false
391
- })
392
- });
393
-
394
- const data = await response.json();
395
- botMsg.textContent = 'البوت: ' + data.choices[0].message.content;
396
- } catch (err) {
397
- botMsg.textContent = 'البوت: حدث خطأ: ' + err.message;
398
  }
399
- chatDiv.scrollTop = chatDiv.scrollHeight;
 
 
 
 
400
  }
401
-
402
- document.getElementById('send').onclick = sendMessage;
403
- document.getElementById('input').onkeypress = (e) => {
404
- if (e.key === 'Enter') sendMessage();
405
- };
406
- </script>
407
- </body>
408
- </html>
409
- """
 
410
 
411
  # =====================================================
412
  # RUN
413
  # =====================================================
 
414
  if __name__ == "__main__":
 
415
  import uvicorn
416
- print("""
417
- ╔════════════════════════════════════════════════╗
418
- ║ AI Gateway - تم التشغيل بنجاح! 🚀 ║
419
- ╠════════════════════════════════════════════════╣
420
- ║ الواجهة التفاعلية: http://localhost:7860/test║
421
- ║ API: http://localhost:7860/v1/chat/completions║
422
- ║ المفتاح: sk-your-secret-key ║
423
- ╚════════════════════════════════════════════════╝
424
- """)
425
  uvicorn.run(
426
  app,
427
  host="0.0.0.0",
 
7
  import json
8
  import time
9
  import uuid
10
+ import logging
11
+
12
  import g4f
13
  from g4f.client import Client
 
 
 
14
 
15
  # =====================================================
16
  # LOGGING
17
  # =====================================================
18
+
19
  logging.basicConfig(level=logging.INFO)
20
  logger = logging.getLogger(__name__)
21
 
22
  # =====================================================
23
  # CONFIG
24
  # =====================================================
25
+
26
+ API_KEY = "sk-your-secret-key"
27
 
28
  # =====================================================
29
  # FASTAPI
30
  # =====================================================
31
+
32
  app = FastAPI(
33
  title="Universal AI Gateway",
34
+ version="4.0.0"
35
  )
36
 
37
  # =====================================================
38
+ # CORS
39
  # =====================================================
40
+
41
  app.add_middleware(
42
  CORSMiddleware,
43
  allow_origins=["*"],
 
49
  # =====================================================
50
  # MODELS
51
  # =====================================================
52
+
53
  class Message(BaseModel):
54
  role: str
55
  content: str
 
64
  # =====================================================
65
  # AUTH
66
  # =====================================================
67
+
68
  def verify_api_key(req: Request):
69
+
70
  auth = req.headers.get("Authorization")
71
+
72
+ # السماح للاختبار
73
  if not auth:
74
+ return True
75
+
 
 
76
  if not auth.startswith("Bearer "):
77
  raise HTTPException(
78
  status_code=401,
79
  detail="Invalid Authorization Format"
80
  )
81
+
82
+ token = auth.replace("Bearer ", "").strip()
83
+
84
  if token != API_KEY:
85
  raise HTTPException(
86
  status_code=403,
87
  detail="Invalid API Key"
88
  )
89
 
90
+ return True
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
91
 
92
  # =====================================================
93
  # ROOT
94
  # =====================================================
95
+
96
  @app.get("/")
97
  async def root():
98
+
99
  return {
100
  "status": "online",
101
  "service": "Universal AI Gateway",
102
+ "version": "4.0.0"
103
  }
104
 
105
  # =====================================================
106
+ # MODELS
107
  # =====================================================
108
+
109
  @app.get("/v1/models")
110
  async def get_models():
111
+
112
+ models_data = []
113
+
114
+ fallback_models = [
115
+ "gpt-4o-mini",
116
+ "gpt-4o",
117
+ "gpt-4",
118
+ "gpt-3.5-turbo",
119
+ "claude-3-haiku",
120
+ "llama-3.1-70b",
121
+ "mixtral-8x7b",
122
+ "deepseek-chat",
123
+ "gemini-pro"
124
+ ]
125
+
126
  try:
127
+
128
+ if hasattr(g4f.models, "_all_models"):
129
+
130
+ all_models = list(g4f.models._all_models)
131
+
132
+ for model in all_models[:50]:
133
+
134
+ models_data.append({
135
  "id": str(model),
136
  "object": "model",
137
  "created": int(time.time()),
138
  "owned_by": "g4f"
139
  })
140
+
141
  except Exception as e:
142
+
143
+ logger.error(f"Models error: {e}")
144
+
145
+ # fallback
146
+ if not models_data:
147
+
148
+ for model in fallback_models:
149
+
150
+ models_data.append({
151
+ "id": model,
 
 
152
  "object": "model",
153
  "created": int(time.time()),
154
  "owned_by": "g4f"
155
  })
156
+
157
  return {
158
  "object": "list",
159
+ "data": models_data
160
  }
161
 
162
  # =====================================================
163
+ # CHAT COMPLETIONS
164
  # =====================================================
165
+
166
  @app.post("/v1/chat/completions")
167
  async def chat_completions(
168
  req: Request,
169
  body: ChatRequest
170
  ):
171
+
172
  verify_api_key(req)
173
+
 
174
  messages = [
175
+ {
176
+ "role": m.role,
177
+ "content": m.content
178
+ }
179
  for m in body.messages
180
  ]
181
+
182
+ logger.info(
183
+ f"Request model={body.model} stream={body.stream}"
184
+ )
185
+
186
  # =================================================
187
+ # STREAMING
188
  # =================================================
189
+
190
  if body.stream:
191
+
192
  async def generate_stream():
193
+
194
+ try:
195
+
196
+ client = Client()
197
+
198
+ response = client.chat.completions.create(
199
+ model=body.model,
200
+ messages=messages,
201
+ stream=True
202
+ )
203
+
204
+ chunk_id = f"chatcmpl-{uuid.uuid4().hex}"
205
+
206
+ for chunk in response:
207
+
208
+ try:
209
+
210
+ content = ""
211
+
212
+ if (
213
+ chunk.choices
214
+ and chunk.choices[0].delta
215
+ and chunk.choices[0].delta.content
216
+ ):
217
  content = chunk.choices[0].delta.content
218
+
219
+ if content:
220
+
221
  payload = {
222
  "id": chunk_id,
223
  "object": "chat.completion.chunk",
224
  "created": int(time.time()),
225
  "model": body.model,
226
+ "choices": [
227
+ {
228
+ "index": 0,
229
+ "delta": {
230
+ "content": content
231
+ },
232
+ "finish_reason": None
233
+ }
234
+ ]
235
  }
236
+
237
  yield f"data: {json.dumps(payload)}\n\n"
238
+
239
+ await asyncio.sleep(0)
240
+
241
+ except Exception as chunk_error:
242
+
243
+ logger.error(
244
+ f"Chunk error: {chunk_error}"
245
+ )
246
+
247
+ final_payload = {
248
+ "id": chunk_id,
249
+ "object": "chat.completion.chunk",
250
+ "created": int(time.time()),
251
+ "model": body.model,
252
+ "choices": [
253
+ {
254
  "index": 0,
255
  "delta": {},
256
  "finish_reason": "stop"
257
+ }
258
+ ]
259
+ }
260
+
261
+ yield f"data: {json.dumps(final_payload)}\n\n"
262
+
263
+ yield "data: [DONE]\n\n"
264
+
265
+ except Exception as e:
266
+
267
+ logger.error(f"Streaming error: {e}")
268
+
269
+ error_payload = {
270
+ "error": {
271
+ "message": str(e),
272
+ "type": "server_error"
273
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
274
  }
275
+
276
+ yield f"data: {json.dumps(error_payload)}\n\n"
277
+
278
  return StreamingResponse(
279
  generate_stream(),
280
  media_type="text/event-stream",
 
284
  "X-Accel-Buffering": "no"
285
  }
286
  )
287
+
288
  # =================================================
289
+ # NORMAL RESPONSE
290
  # =================================================
291
+
292
+ try:
293
+
294
+ client = Client()
295
+
296
+ response = await asyncio.to_thread(
297
+ client.chat.completions.create,
298
+ model=body.model,
299
+ messages=messages
300
+ )
301
+
302
+ assistant_message = ""
303
+
304
  try:
 
 
 
 
 
 
 
 
 
 
305
  assistant_message = response.choices[0].message.content
306
+ except:
307
+ assistant_message = str(response)
308
+
309
+ return JSONResponse({
310
+ "id": f"chatcmpl-{uuid.uuid4().hex}",
311
+ "object": "chat.completion",
312
+ "created": int(time.time()),
313
+ "model": body.model,
314
+ "choices": [
315
+ {
316
  "index": 0,
317
  "message": {
318
  "role": "assistant",
319
  "content": assistant_message
320
  },
321
  "finish_reason": "stop"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
322
  }
323
+ ],
324
+ "usage": {
325
+ "prompt_tokens": 0,
326
+ "completion_tokens": 0,
327
+ "total_tokens": 0
328
  }
329
+ })
330
+
331
+ except Exception as e:
332
+
333
+ logger.error(f"Chat error: {e}")
334
+
335
+ raise HTTPException(
336
+ status_code=500,
337
+ detail=str(e)
338
+ )
339
 
340
  # =====================================================
341
  # RUN
342
  # =====================================================
343
+
344
  if __name__ == "__main__":
345
+
346
  import uvicorn
347
+
 
 
 
 
 
 
 
 
348
  uvicorn.run(
349
  app,
350
  host="0.0.0.0",