bahi-bh commited on
Commit
745b6b1
·
verified ·
1 Parent(s): 840e133

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +157 -32
app.py CHANGED
@@ -3,6 +3,7 @@ from fastapi.middleware.cors import CORSMiddleware
3
  from fastapi.responses import StreamingResponse, JSONResponse
4
  from pydantic import BaseModel
5
  from typing import List, Optional
 
6
  import asyncio
7
  import json
8
  import time
@@ -12,6 +13,7 @@ import logging
12
  import g4f
13
  from g4f.client import Client
14
 
 
15
  # =====================================================
16
  # LOGGING
17
  # =====================================================
@@ -19,21 +21,30 @@ from g4f.client import Client
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="6.0.0"
35
  )
36
 
 
37
  # =====================================================
38
  # CORS
39
  # =====================================================
@@ -46,6 +57,7 @@ app.add_middleware(
46
  allow_headers=["*"],
47
  )
48
 
 
49
  # =====================================================
50
  # MODELS
51
  # =====================================================
@@ -60,7 +72,8 @@ class ChatRequest(BaseModel):
60
  messages: List[Message]
61
  stream: bool = False
62
  temperature: Optional[float] = 0.7
63
- max_tokens: Optional[int] = 4096
 
64
 
65
  # =====================================================
66
  # AUTH
@@ -90,6 +103,7 @@ def verify_api_key(req: Request):
90
 
91
  return True
92
 
 
93
  # =====================================================
94
  # ROOT
95
  # =====================================================
@@ -100,9 +114,10 @@ async def root():
100
  return {
101
  "status": "online",
102
  "service": "Universal AI Gateway",
103
- "version": "6.0.0"
104
  }
105
 
 
106
  # =====================================================
107
  # MODELS
108
  # =====================================================
@@ -111,20 +126,62 @@ async def root():
111
  async def get_models():
112
 
113
  models_data = []
114
- existing_models = set()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
115
 
116
  try:
117
 
118
- # ترك g4f يسترد النماذج تلقائياً بدون تقييد
119
  if hasattr(g4f.models, "_all_models"):
120
 
121
  all_models = list(g4f.models._all_models)
122
 
123
- for model in all_models:
124
 
125
  model_name = str(model)
126
 
127
- if model_name not in existing_models:
128
 
129
  models_data.append({
130
  "id": model_name,
@@ -133,18 +190,92 @@ async def get_models():
133
  "owned_by": "g4f"
134
  })
135
 
136
- existing_models.add(model_name)
137
 
138
  except Exception as e:
139
 
140
  logger.error(f"Models error: {e}")
141
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
142
  return {
143
  "object": "list",
144
- "data": models_data,
145
- "total": len(models_data)
146
  }
147
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
148
  # =====================================================
149
  # CHAT COMPLETIONS
150
  # =====================================================
@@ -179,16 +310,7 @@ async def chat_completions(
179
 
180
  try:
181
 
182
- # لا forcing
183
- # لا providers يدوية
184
- # لا routing
185
- # لا watchdog
186
- # لا timeout
187
- # نترك g4f يعمل بطبيعته
188
-
189
- client = Client()
190
-
191
- response = client.chat.completions.create(
192
  model=body.model,
193
  messages=messages,
194
  stream=True
@@ -202,16 +324,11 @@ async def chat_completions(
202
 
203
  try:
204
 
205
- # تجاهل image responses
206
- if hasattr(chunk, "images"):
207
- continue
208
-
209
  content = ""
210
 
211
  if (
212
  hasattr(chunk, "choices")
213
  and chunk.choices
214
- and len(chunk.choices) > 0
215
  and chunk.choices[0].delta
216
  and chunk.choices[0].delta.content
217
  ):
@@ -250,10 +367,19 @@ async def chat_completions(
250
  f"Chunk error: {chunk_error}"
251
  )
252
 
 
253
  if not has_content:
254
 
255
- logger.warning(
256
- f"Empty stream | model={body.model}"
 
 
 
 
 
 
 
 
257
  )
258
 
259
  final_payload = {
@@ -309,12 +435,10 @@ async def chat_completions(
309
 
310
  try:
311
 
312
- client = Client()
313
-
314
- response = await asyncio.to_thread(
315
- client.chat.completions.create,
316
  model=body.model,
317
- messages=messages
 
318
  )
319
 
320
  assistant_message = ""
@@ -360,6 +484,7 @@ async def chat_completions(
360
  detail=str(e)
361
  )
362
 
 
363
  # =====================================================
364
  # RUN
365
  # =====================================================
 
3
  from fastapi.responses import StreamingResponse, JSONResponse
4
  from pydantic import BaseModel
5
  from typing import List, Optional
6
+
7
  import asyncio
8
  import json
9
  import time
 
13
  import g4f
14
  from g4f.client import Client
15
 
16
+
17
  # =====================================================
18
  # LOGGING
19
  # =====================================================
 
21
  logging.basicConfig(level=logging.INFO)
22
  logger = logging.getLogger(__name__)
23
 
24
+
25
  # =====================================================
26
  # CONFIG
27
  # =====================================================
28
 
29
  API_KEY = "sk-your-secret-key"
30
 
31
+ # timeout لمنع التعليق الأبدي
32
+ REQUEST_TIMEOUT = 45
33
+
34
+ # retry خفيف
35
+ MAX_RETRIES = 2
36
+
37
+
38
  # =====================================================
39
  # FASTAPI
40
  # =====================================================
41
 
42
  app = FastAPI(
43
  title="Universal AI Gateway",
44
+ version="4.2.0"
45
  )
46
 
47
+
48
  # =====================================================
49
  # CORS
50
  # =====================================================
 
57
  allow_headers=["*"],
58
  )
59
 
60
+
61
  # =====================================================
62
  # MODELS
63
  # =====================================================
 
72
  messages: List[Message]
73
  stream: bool = False
74
  temperature: Optional[float] = 0.7
75
+ max_tokens: Optional[int] = 32000
76
+
77
 
78
  # =====================================================
79
  # AUTH
 
103
 
104
  return True
105
 
106
+
107
  # =====================================================
108
  # ROOT
109
  # =====================================================
 
114
  return {
115
  "status": "online",
116
  "service": "Universal AI Gateway",
117
+ "version": "4.2.0"
118
  }
119
 
120
+
121
  # =====================================================
122
  # MODELS
123
  # =====================================================
 
126
  async def get_models():
127
 
128
  models_data = []
129
+
130
+ # =================================================
131
+ # MODELS THAT WORK WELL
132
+ # =================================================
133
+
134
+ fallback_models = [
135
+
136
+ # GPT
137
+ "gpt-4o-mini",
138
+ "gpt-4o",
139
+ "gpt-4",
140
+ "gpt-3.5-turbo",
141
+
142
+ # Claude
143
+ "claude-3-haiku",
144
+
145
+ # Llama
146
+ "llama-3.1-70b",
147
+
148
+ # Mixtral
149
+ "mixtral-8x7b",
150
+
151
+ # Deepseek
152
+ "deepseek-chat",
153
+
154
+ # Gemini
155
+ "gemini-pro",
156
+
157
+ # =================================================
158
+ # COHERE FAMILY
159
+ # =================================================
160
+
161
+ "command-r",
162
+ "command-r-plus",
163
+ "command-r7b",
164
+ "command",
165
+ "command-nightly",
166
+
167
+ # Additional Cohere-style names
168
+ "cohere-command-r",
169
+ "cohere-command-r-plus",
170
+ ]
171
+
172
+ added_models = set()
173
 
174
  try:
175
 
 
176
  if hasattr(g4f.models, "_all_models"):
177
 
178
  all_models = list(g4f.models._all_models)
179
 
180
+ for model in all_models[:100]:
181
 
182
  model_name = str(model)
183
 
184
+ if model_name not in added_models:
185
 
186
  models_data.append({
187
  "id": model_name,
 
190
  "owned_by": "g4f"
191
  })
192
 
193
+ added_models.add(model_name)
194
 
195
  except Exception as e:
196
 
197
  logger.error(f"Models error: {e}")
198
 
199
+ # fallback models
200
+ for model in fallback_models:
201
+
202
+ if model not in added_models:
203
+
204
+ models_data.append({
205
+ "id": model,
206
+ "object": "model",
207
+ "created": int(time.time()),
208
+ "owned_by": "g4f"
209
+ })
210
+
211
+ added_models.add(model)
212
+
213
  return {
214
  "object": "list",
215
+ "data": models_data
 
216
  }
217
 
218
+
219
+ # =====================================================
220
+ # SAFE COMPLETION
221
+ # =====================================================
222
+
223
+ async def safe_completion(
224
+ model,
225
+ messages,
226
+ stream=False
227
+ ):
228
+
229
+ last_error = None
230
+
231
+ for attempt in range(MAX_RETRIES):
232
+
233
+ try:
234
+
235
+ logger.info(
236
+ f"Attempt {attempt + 1} | model={model}"
237
+ )
238
+
239
+ client = Client()
240
+
241
+ # timeout لمنع التعليق الأبدي
242
+ response = await asyncio.wait_for(
243
+ asyncio.to_thread(
244
+ client.chat.completions.create,
245
+ model=model,
246
+ messages=messages,
247
+ stream=stream
248
+ ),
249
+ timeout=REQUEST_TIMEOUT
250
+ )
251
+
252
+ logger.info(
253
+ f"Success | model={model}"
254
+ )
255
+
256
+ return response
257
+
258
+ except asyncio.TimeoutError:
259
+
260
+ last_error = "Request timeout"
261
+
262
+ logger.warning(
263
+ f"Timeout | model={model}"
264
+ )
265
+
266
+ except Exception as e:
267
+
268
+ last_error = e
269
+
270
+ logger.warning(
271
+ f"Attempt failed {attempt + 1} | {e}"
272
+ )
273
+
274
+ await asyncio.sleep(1)
275
+
276
+ raise Exception(last_error)
277
+
278
+
279
  # =====================================================
280
  # CHAT COMPLETIONS
281
  # =====================================================
 
310
 
311
  try:
312
 
313
+ response = await safe_completion(
 
 
 
 
 
 
 
 
 
314
  model=body.model,
315
  messages=messages,
316
  stream=True
 
324
 
325
  try:
326
 
 
 
 
 
327
  content = ""
328
 
329
  if (
330
  hasattr(chunk, "choices")
331
  and chunk.choices
 
332
  and chunk.choices[0].delta
333
  and chunk.choices[0].delta.content
334
  ):
 
367
  f"Chunk error: {chunk_error}"
368
  )
369
 
370
+ # provider فتح stream بدون محتوى
371
  if not has_content:
372
 
373
+ error_payload = {
374
+ "error": {
375
+ "message": "Provider returned empty stream",
376
+ "type": "empty_stream"
377
+ }
378
+ }
379
+
380
+ yield (
381
+ f"data: "
382
+ f"{json.dumps(error_payload)}\n\n"
383
  )
384
 
385
  final_payload = {
 
435
 
436
  try:
437
 
438
+ response = await safe_completion(
 
 
 
439
  model=body.model,
440
+ messages=messages,
441
+ stream=False
442
  )
443
 
444
  assistant_message = ""
 
484
  detail=str(e)
485
  )
486
 
487
+
488
  # =====================================================
489
  # RUN
490
  # =====================================================