bahi-bh commited on
Commit
22ae976
·
verified ·
1 Parent(s): 4a04d06

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +146 -25
app.py CHANGED
@@ -1,24 +1,39 @@
1
  import random
2
- import httpx
3
- from fastapi import FastAPI, Request, HTTPException
4
- from fastapi.middleware.cors import CORSMiddleware
5
- from fastapi.responses import StreamingResponse, JSONResponse
6
- from pydantic import BaseModel
7
- from typing import List, Optional
8
  import asyncio
9
  import json
10
  import time
11
  import uuid
12
  import logging
13
 
 
 
14
  import g4f
15
  from g4f.client import Client
16
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
  # =====================================================
18
  # LOGGING
19
  # =====================================================
20
 
21
- logging.basicConfig(level=logging.INFO)
 
 
 
 
22
  logger = logging.getLogger(__name__)
23
 
24
  # =====================================================
@@ -27,13 +42,35 @@ logger = logging.getLogger(__name__)
27
 
28
  API_KEY = "sk-your-secret-key"
29
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
  # =====================================================
31
  # FASTAPI
32
  # =====================================================
33
 
34
  app = FastAPI(
35
  title="Universal AI Gateway",
36
- version="4.0.0"
37
  )
38
 
39
  # =====================================================
@@ -56,6 +93,7 @@ class Message(BaseModel):
56
  role: str
57
  content: str
58
 
 
59
  class ChatRequest(BaseModel):
60
  model: str
61
  messages: List[Message]
@@ -71,7 +109,6 @@ def verify_api_key(req: Request):
71
 
72
  auth = req.headers.get("Authorization")
73
 
74
- # السماح للاختبار
75
  if not auth:
76
  return True
77
 
@@ -101,7 +138,11 @@ async def root():
101
  return {
102
  "status": "online",
103
  "service": "Universal AI Gateway",
104
- "version": "4.0.0"
 
 
 
 
105
  }
106
 
107
  # =====================================================
@@ -144,7 +185,6 @@ async def get_models():
144
 
145
  logger.error(f"Models error: {e}")
146
 
147
- # fallback
148
  if not models_data:
149
 
150
  for model in fallback_models:
@@ -161,6 +201,74 @@ async def get_models():
161
  "data": models_data
162
  }
163
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
164
  # =====================================================
165
  # CHAT COMPLETIONS
166
  # =====================================================
@@ -195,9 +303,7 @@ async def chat_completions(
195
 
196
  try:
197
 
198
- client = Client()
199
-
200
- response = client.chat.completions.create(
201
  model=body.model,
202
  messages=messages,
203
  stream=True
@@ -212,7 +318,8 @@ async def chat_completions(
212
  content = ""
213
 
214
  if (
215
- chunk.choices
 
216
  and chunk.choices[0].delta
217
  and chunk.choices[0].delta.content
218
  ):
@@ -236,7 +343,10 @@ async def chat_completions(
236
  ]
237
  }
238
 
239
- yield f"data: {json.dumps(payload)}\n\n"
 
 
 
240
 
241
  await asyncio.sleep(0)
242
 
@@ -260,7 +370,10 @@ async def chat_completions(
260
  ]
261
  }
262
 
263
- yield f"data: {json.dumps(final_payload)}\n\n"
 
 
 
264
 
265
  yield "data: [DONE]\n\n"
266
 
@@ -275,7 +388,10 @@ async def chat_completions(
275
  }
276
  }
277
 
278
- yield f"data: {json.dumps(error_payload)}\n\n"
 
 
 
279
 
280
  return StreamingResponse(
281
  generate_stream(),
@@ -293,19 +409,22 @@ async def chat_completions(
293
 
294
  try:
295
 
296
- client = Client()
297
-
298
- response = await asyncio.to_thread(
299
- client.chat.completions.create,
300
  model=body.model,
301
- messages=messages
 
302
  )
303
 
304
  assistant_message = ""
305
 
306
  try:
307
- assistant_message = response.choices[0].message.content
308
- except:
 
 
 
 
 
309
  assistant_message = str(response)
310
 
311
  return JSONResponse({
@@ -347,6 +466,8 @@ if __name__ == "__main__":
347
 
348
  import uvicorn
349
 
 
 
350
  uvicorn.run(
351
  app,
352
  host="0.0.0.0",
 
1
  import random
 
 
 
 
 
 
2
  import asyncio
3
  import json
4
  import time
5
  import uuid
6
  import logging
7
 
8
+ from typing import List, Optional
9
+
10
  import g4f
11
  from g4f.client import Client
12
 
13
+ from fastapi import FastAPI, Request, HTTPException
14
+ from fastapi.middleware.cors import CORSMiddleware
15
+ from fastapi.responses import StreamingResponse, JSONResponse
16
+ from pydantic import BaseModel
17
+
18
+ # =====================================================
19
+ # SAFE PROVIDERS
20
+ # =====================================================
21
+
22
+ SAFE_PROVIDER_NAMES = [
23
+ "DeepInfra",
24
+ "DDG",
25
+ "Cloudflare",
26
+ ]
27
+
28
  # =====================================================
29
  # LOGGING
30
  # =====================================================
31
 
32
+ logging.basicConfig(
33
+ level=logging.INFO,
34
+ format="%(asctime)s [%(levelname)s] %(message)s"
35
+ )
36
+
37
  logger = logging.getLogger(__name__)
38
 
39
  # =====================================================
 
42
 
43
  API_KEY = "sk-your-secret-key"
44
 
45
+ # =====================================================
46
+ # LOAD SAFE PROVIDERS
47
+ # =====================================================
48
+
49
+ AVAILABLE_PROVIDERS = []
50
+
51
+ for provider_name in SAFE_PROVIDER_NAMES:
52
+
53
+ try:
54
+
55
+ provider = getattr(g4f.Provider, provider_name)
56
+
57
+ AVAILABLE_PROVIDERS.append(provider)
58
+
59
+ logger.info(f"Loaded provider: {provider_name}")
60
+
61
+ except Exception:
62
+
63
+ logger.warning(
64
+ f"Provider not available: {provider_name}"
65
+ )
66
+
67
  # =====================================================
68
  # FASTAPI
69
  # =====================================================
70
 
71
  app = FastAPI(
72
  title="Universal AI Gateway",
73
+ version="5.0.0"
74
  )
75
 
76
  # =====================================================
 
93
  role: str
94
  content: str
95
 
96
+
97
  class ChatRequest(BaseModel):
98
  model: str
99
  messages: List[Message]
 
109
 
110
  auth = req.headers.get("Authorization")
111
 
 
112
  if not auth:
113
  return True
114
 
 
138
  return {
139
  "status": "online",
140
  "service": "Universal AI Gateway",
141
+ "version": "5.0.0",
142
+ "providers": [
143
+ p.__name__
144
+ for p in AVAILABLE_PROVIDERS
145
+ ]
146
  }
147
 
148
  # =====================================================
 
185
 
186
  logger.error(f"Models error: {e}")
187
 
 
188
  if not models_data:
189
 
190
  for model in fallback_models:
 
201
  "data": models_data
202
  }
203
 
204
+ # =====================================================
205
+ # PROVIDER PICKER
206
+ # =====================================================
207
+
208
+ def pick_provider():
209
+
210
+ if not AVAILABLE_PROVIDERS:
211
+ return None
212
+
213
+ return random.choice(AVAILABLE_PROVIDERS)
214
+
215
+ # =====================================================
216
+ # COMPLETION HELPER
217
+ # =====================================================
218
+
219
+ async def create_completion(
220
+ model,
221
+ messages,
222
+ stream=False
223
+ ):
224
+
225
+ last_error = None
226
+
227
+ providers = AVAILABLE_PROVIDERS.copy()
228
+
229
+ random.shuffle(providers)
230
+
231
+ for provider in providers:
232
+
233
+ try:
234
+
235
+ logger.info(
236
+ f"Trying provider: {provider.__name__}"
237
+ )
238
+
239
+ client = Client()
240
+
241
+ response = await asyncio.wait_for(
242
+ asyncio.to_thread(
243
+ client.chat.completions.create,
244
+ model=model,
245
+ messages=messages,
246
+ provider=provider,
247
+ stream=stream
248
+ ),
249
+ timeout=45
250
+ )
251
+
252
+ logger.info(
253
+ f"Success provider: {provider.__name__}"
254
+ )
255
+
256
+ return response
257
+
258
+ except Exception as e:
259
+
260
+ last_error = e
261
+
262
+ logger.warning(
263
+ f"Provider failed: {provider.__name__} | {e}"
264
+ )
265
+
266
+ await asyncio.sleep(1)
267
+
268
+ raise Exception(
269
+ f"All providers failed: {last_error}"
270
+ )
271
+
272
  # =====================================================
273
  # CHAT COMPLETIONS
274
  # =====================================================
 
303
 
304
  try:
305
 
306
+ response = await create_completion(
 
 
307
  model=body.model,
308
  messages=messages,
309
  stream=True
 
318
  content = ""
319
 
320
  if (
321
+ hasattr(chunk, "choices")
322
+ and chunk.choices
323
  and chunk.choices[0].delta
324
  and chunk.choices[0].delta.content
325
  ):
 
343
  ]
344
  }
345
 
346
+ yield (
347
+ f"data: "
348
+ f"{json.dumps(payload, ensure_ascii=False)}\n\n"
349
+ )
350
 
351
  await asyncio.sleep(0)
352
 
 
370
  ]
371
  }
372
 
373
+ yield (
374
+ f"data: "
375
+ f"{json.dumps(final_payload)}\n\n"
376
+ )
377
 
378
  yield "data: [DONE]\n\n"
379
 
 
388
  }
389
  }
390
 
391
+ yield (
392
+ f"data: "
393
+ f"{json.dumps(error_payload)}\n\n"
394
+ )
395
 
396
  return StreamingResponse(
397
  generate_stream(),
 
409
 
410
  try:
411
 
412
+ response = await create_completion(
 
 
 
413
  model=body.model,
414
+ messages=messages,
415
+ stream=False
416
  )
417
 
418
  assistant_message = ""
419
 
420
  try:
421
+
422
+ assistant_message = (
423
+ response.choices[0].message.content
424
+ )
425
+
426
+ except Exception:
427
+
428
  assistant_message = str(response)
429
 
430
  return JSONResponse({
 
466
 
467
  import uvicorn
468
 
469
+ logger.info("Starting Universal AI Gateway")
470
+
471
  uvicorn.run(
472
  app,
473
  host="0.0.0.0",