bahi-bh commited on
Commit
7804213
·
verified ·
1 Parent(s): abb0b40

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +65 -611
app.py CHANGED
@@ -2,251 +2,38 @@ from fastapi import FastAPI, Request, HTTPException
2
  from fastapi.middleware.cors import CORSMiddleware
3
  from fastapi.responses import StreamingResponse, JSONResponse
4
  from pydantic import BaseModel
5
- from typing import List, Optional, Dict
6
-
7
  import asyncio
8
  import json
9
  import time
10
  import uuid
11
  import logging
12
- import random
13
- import httpx
14
- import g4f
15
 
 
16
  from g4f.client import Client
17
- from g4f import Provider
18
-
19
 
20
  # =====================================================
21
  # LOGGING
22
  # =====================================================
23
 
24
- logging.basicConfig(
25
- level=logging.INFO,
26
- format="%(asctime)s [%(levelname)s] %(message)s"
27
- )
28
-
29
  logger = logging.getLogger(__name__)
30
 
31
-
32
  # =====================================================
33
  # CONFIG
34
  # =====================================================
35
 
36
  API_KEY = "sk-your-secret-key"
37
 
38
-
39
- # =====================================================
40
- # PROXY CONFIG
41
- # =====================================================
42
-
43
- # قائمة البروكسيات - أضف بروكسياتك هنا
44
- PROXY_LIST = [
45
- # "http://user:pass@proxy1:port",
46
- # "http://user:pass@proxy2:port",
47
- # "socks5://user:pass@proxy3:port",
48
- ]
49
-
50
- # بروكسي واحد إذا كان لديك
51
- SINGLE_PROXY = None
52
-
53
- # مثال:
54
- # "http://user:pass@host:port"
55
-
56
-
57
- # =====================================================
58
- # PROVIDER SAFE LOADER
59
- # =====================================================
60
-
61
- def safe_provider(name: str):
62
- """
63
- تحميل المزود إذا كان موجود داخل g4f
64
- """
65
-
66
- if hasattr(Provider, name):
67
- return getattr(Provider, name)
68
-
69
- logger.warning(f"Provider not found: {name}")
70
-
71
- return None
72
-
73
-
74
- # =====================================================
75
- # PROVIDERS
76
- # =====================================================
77
-
78
- BLACKBOX = safe_provider("Blackbox")
79
- LIAOBOTS = safe_provider("Liaobots")
80
- OPENAICHAT = safe_provider("OpenaiChat")
81
- DDG = safe_provider("DDG")
82
- DEEPINFRA = safe_provider("DeepInfra")
83
- CLOUDFLARE = safe_provider("Cloudflare")
84
-
85
-
86
- # =====================================================
87
- # PROVIDER MAP - ربط النماذج بمزوديها
88
- # =====================================================
89
-
90
- MODEL_PROVIDER_MAP: Dict[str, list] = {
91
-
92
- # GPT Models
93
- "gpt-4o": [
94
- p for p in [
95
- BLACKBOX,
96
- LIAOBOTS,
97
- OPENAICHAT
98
- ] if p
99
- ],
100
-
101
- "gpt-4o-mini": [
102
- p for p in [
103
- BLACKBOX,
104
- DDG,
105
- LIAOBOTS,
106
- OPENAICHAT
107
- ] if p
108
- ],
109
-
110
- "gpt-4": [
111
- p for p in [
112
- BLACKBOX,
113
- LIAOBOTS,
114
- OPENAICHAT
115
- ] if p
116
- ],
117
-
118
- "gpt-3.5-turbo": [
119
- p for p in [
120
- DDG,
121
- BLACKBOX,
122
- OPENAICHAT
123
- ] if p
124
- ],
125
-
126
- # Claude Models
127
- "claude-3-haiku": [
128
- p for p in [
129
- DDG,
130
- BLACKBOX
131
- ] if p
132
- ],
133
-
134
- "claude-3-5-sonnet": [
135
- p for p in [
136
- BLACKBOX,
137
- LIAOBOTS
138
- ] if p
139
- ],
140
-
141
- "claude-3-opus": [
142
- p for p in [
143
- LIAOBOTS,
144
- BLACKBOX
145
- ] if p
146
- ],
147
-
148
- # Llama Models
149
- "llama-3.1-70b": [
150
- p for p in [
151
- BLACKBOX,
152
- DEEPINFRA,
153
- CLOUDFLARE
154
- ] if p
155
- ],
156
-
157
- "llama-3.1-8b": [
158
- p for p in [
159
- CLOUDFLARE,
160
- DEEPINFRA
161
- ] if p
162
- ],
163
-
164
- "llama-3.2-90b": [
165
- p for p in [
166
- BLACKBOX,
167
- DEEPINFRA
168
- ] if p
169
- ],
170
-
171
- # Mixtral Models
172
- "mixtral-8x7b": [
173
- p for p in [
174
- DEEPINFRA,
175
- BLACKBOX
176
- ] if p
177
- ],
178
-
179
- # Deepseek Models
180
- "deepseek-chat": [
181
- p for p in [
182
- DEEPINFRA,
183
- BLACKBOX
184
- ] if p
185
- ],
186
-
187
- "deepseek-v3": [
188
- p for p in [
189
- BLACKBOX,
190
- DEEPINFRA
191
- ] if p
192
- ],
193
-
194
- # Gemini Models
195
- "gemini-pro": [
196
- p for p in [
197
- BLACKBOX,
198
- LIAOBOTS
199
- ] if p
200
- ],
201
-
202
- "gemini-1.5-pro": [
203
- p for p in [
204
- BLACKBOX,
205
- LIAOBOTS
206
- ] if p
207
- ],
208
-
209
- # Qwen Models
210
- "qwen-2.5-72b": [
211
- p for p in [
212
- BLACKBOX,
213
- DEEPINFRA
214
- ] if p
215
- ],
216
-
217
- # Default fallback
218
- "default": [
219
- p for p in [
220
- BLACKBOX,
221
- DDG,
222
- DEEPINFRA
223
- ] if p
224
- ],
225
- }
226
-
227
-
228
- # =====================================================
229
- # FALLBACK MODELS - إذا فشل النموذج المطلوب
230
- # =====================================================
231
-
232
- FALLBACK_MODELS = [
233
- "gpt-4o-mini",
234
- "gpt-3.5-turbo",
235
- "llama-3.1-70b",
236
- ]
237
-
238
-
239
  # =====================================================
240
  # FASTAPI
241
  # =====================================================
242
 
243
  app = FastAPI(
244
  title="Universal AI Gateway",
245
- description="بوابة ذكاء اصطناعي شاملة مع دعم البروكسي",
246
- version="5.0.0"
247
  )
248
 
249
-
250
  # =====================================================
251
  # CORS
252
  # =====================================================
@@ -259,7 +46,6 @@ app.add_middleware(
259
  allow_headers=["*"],
260
  )
261
 
262
-
263
  # =====================================================
264
  # MODELS
265
  # =====================================================
@@ -268,7 +54,6 @@ class Message(BaseModel):
268
  role: str
269
  content: str
270
 
271
-
272
  class ChatRequest(BaseModel):
273
  model: str
274
  messages: List[Message]
@@ -276,74 +61,22 @@ class ChatRequest(BaseModel):
276
  temperature: Optional[float] = 0.7
277
  max_tokens: Optional[int] = 4096
278
 
279
-
280
- # =====================================================
281
- # PROXY HELPER
282
- # =====================================================
283
-
284
- def get_proxy() -> Optional[str]:
285
- """الحصول على بروكسي من القائمة"""
286
-
287
- if SINGLE_PROXY:
288
- logger.info(f"Using single proxy: {SINGLE_PROXY[:20]}...")
289
- return SINGLE_PROXY
290
-
291
- if PROXY_LIST:
292
- proxy = random.choice(PROXY_LIST)
293
- logger.info(f"Using proxy from list: {proxy[:20]}...")
294
- return proxy
295
-
296
- return None
297
-
298
-
299
- def get_g4f_proxy_config() -> dict:
300
- """إعداد البروكسي لـ g4f"""
301
-
302
- proxy = get_proxy()
303
-
304
- if proxy:
305
- return {"proxy": proxy}
306
-
307
- return {}
308
-
309
-
310
- # =====================================================
311
- # CLIENT BUILDER
312
- # =====================================================
313
-
314
- def build_client(proxy: Optional[str] = None) -> Client:
315
- """بناء عميل g4f مع البروكسي"""
316
-
317
- proxy_url = proxy or get_proxy()
318
-
319
- if proxy_url:
320
- try:
321
- client = Client(proxies=proxy_url)
322
- logger.info("Client created with proxy")
323
- return client
324
-
325
- except Exception as e:
326
- logger.warning(f"Failed to create client with proxy: {e}")
327
-
328
- return Client()
329
-
330
-
331
  # =====================================================
332
  # AUTH
333
  # =====================================================
334
 
335
  def verify_api_key(req: Request):
336
- """التحقق من مفتاح API"""
337
 
338
  auth = req.headers.get("Authorization")
339
 
 
340
  if not auth:
341
  return True
342
 
343
  if not auth.startswith("Bearer "):
344
  raise HTTPException(
345
  status_code=401,
346
- detail="Invalid Authorization Format - يجب أن يبدأ بـ Bearer"
347
  )
348
 
349
  token = auth.replace("Bearer ", "").strip()
@@ -351,172 +84,11 @@ def verify_api_key(req: Request):
351
  if token != API_KEY:
352
  raise HTTPException(
353
  status_code=403,
354
- detail="Invalid API Key - مفتاح API غير صحيح"
355
  )
356
 
357
  return True
358
 
359
-
360
- # =====================================================
361
- # CORE: SMART COMPLETION WITH RETRY + FALLBACK
362
- # =====================================================
363
-
364
- async def smart_completion(
365
- model: str,
366
- messages: list,
367
- stream: bool = False,
368
- max_retries: int = 3,
369
- proxy: Optional[str] = None
370
- ):
371
-
372
- providers = MODEL_PROVIDER_MAP.get(
373
- model,
374
- MODEL_PROVIDER_MAP["default"]
375
- )
376
-
377
- providers_shuffled = providers.copy()
378
- random.shuffle(providers_shuffled)
379
-
380
- last_error = None
381
-
382
- for attempt in range(max_retries):
383
-
384
- for provider in providers_shuffled:
385
-
386
- try:
387
- logger.info(
388
- f"Attempt {attempt+1} | Model: {model} | Provider: {provider.__name__}"
389
- )
390
-
391
- client = build_client(proxy)
392
-
393
- proxy_config = get_g4f_proxy_config()
394
-
395
- response = await asyncio.to_thread(
396
- client.chat.completions.create,
397
- model=model,
398
- messages=messages,
399
- provider=provider,
400
- stream=stream,
401
- **proxy_config
402
- )
403
-
404
- logger.info(
405
- f"SUCCESS | Model: {model} | Provider: {provider.__name__}"
406
- )
407
-
408
- return response, model
409
-
410
- except Exception as e:
411
-
412
- last_error = e
413
-
414
- logger.warning(
415
- f"FAILED | Model: {model} | Provider: {provider.__name__} | Error: {str(e)[:100]}"
416
- )
417
-
418
- await asyncio.sleep(0.5)
419
-
420
- if attempt < max_retries - 1:
421
-
422
- wait_time = (attempt + 1) * 1.5
423
-
424
- logger.info(
425
- f"Waiting {wait_time}s before retry..."
426
- )
427
-
428
- await asyncio.sleep(wait_time)
429
-
430
- # =================================================
431
- # FALLBACK MODELS
432
- # =================================================
433
-
434
- logger.warning(
435
- f"All providers failed for {model}"
436
- )
437
-
438
- for fallback_model in FALLBACK_MODELS:
439
-
440
- if fallback_model == model:
441
- continue
442
-
443
- fallback_providers = MODEL_PROVIDER_MAP.get(
444
- fallback_model,
445
- MODEL_PROVIDER_MAP["default"]
446
- )
447
-
448
- for fb_provider in fallback_providers[:2]:
449
-
450
- try:
451
- logger.info(
452
- f"Fallback => {fallback_model} | Provider => {fb_provider.__name__}"
453
- )
454
-
455
- client = build_client(proxy)
456
-
457
- proxy_config = get_g4f_proxy_config()
458
-
459
- response = await asyncio.to_thread(
460
- client.chat.completions.create,
461
- model=fallback_model,
462
- messages=messages,
463
- provider=fb_provider,
464
- stream=stream,
465
- **proxy_config
466
- )
467
-
468
- logger.info(
469
- f"Fallback Success => {fallback_model}"
470
- )
471
-
472
- return response, fallback_model
473
-
474
- except Exception as e:
475
-
476
- logger.warning(
477
- f"Fallback Failed => {fallback_model} | {str(e)[:100]}"
478
- )
479
-
480
- await asyncio.sleep(0.3)
481
-
482
- # =================================================
483
- # LAST ATTEMPT
484
- # =================================================
485
-
486
- try:
487
-
488
- logger.info(
489
- f"Last attempt without provider => {model}"
490
- )
491
-
492
- client = build_client(proxy)
493
-
494
- response = await asyncio.to_thread(
495
- client.chat.completions.create,
496
- model=model,
497
- messages=messages,
498
- stream=stream
499
- )
500
-
501
- return response, model
502
-
503
- except Exception as e:
504
-
505
- last_error = e
506
-
507
- logger.error(f"All attempts failed => {e}")
508
-
509
- raise HTTPException(
510
- status_code=503,
511
- detail={
512
- "error": "All providers failed",
513
- "message": str(last_error),
514
- "model_requested": model,
515
- "suggestion": "Try another model"
516
- }
517
- )
518
-
519
-
520
  # =====================================================
521
  # ROOT
522
  # =====================================================
@@ -527,61 +99,11 @@ async def root():
527
  return {
528
  "status": "online",
529
  "service": "Universal AI Gateway",
530
- "version": "5.0.0",
531
- "proxy_enabled": bool(PROXY_LIST or SINGLE_PROXY),
532
- "supported_models": list(MODEL_PROVIDER_MAP.keys())
533
  }
534
 
535
-
536
- # =====================================================
537
- # HEALTH CHECK
538
  # =====================================================
539
-
540
- @app.get("/health")
541
- async def health_check():
542
-
543
- proxy_status = "disabled"
544
-
545
- if SINGLE_PROXY or PROXY_LIST:
546
-
547
- proxy_status = "enabled"
548
-
549
- proxy = get_proxy()
550
-
551
- if proxy:
552
-
553
- try:
554
-
555
- async with httpx.AsyncClient(
556
- proxies=proxy,
557
- timeout=10
558
- ) as client:
559
-
560
- resp = await client.get(
561
- "https://api.ipify.org?format=json"
562
- )
563
-
564
- ip_data = resp.json()
565
-
566
- proxy_status = (
567
- f"working - IP: {ip_data.get('ip', 'unknown')}"
568
- )
569
-
570
- except Exception as e:
571
-
572
- proxy_status = f"error - {str(e)[:50]}"
573
-
574
- return {
575
- "status": "healthy",
576
- "timestamp": int(time.time()),
577
- "proxy": proxy_status,
578
- "providers_count": len(MODEL_PROVIDER_MAP),
579
- "fallback_models": FALLBACK_MODELS
580
- }
581
-
582
-
583
- # =====================================================
584
- # MODELS LIST
585
  # =====================================================
586
 
587
  @app.get("/v1/models")
@@ -589,23 +111,17 @@ async def get_models():
589
 
590
  models_data = []
591
 
592
- for model_id in MODEL_PROVIDER_MAP.keys():
593
-
594
- if model_id == "default":
595
- continue
596
-
597
- providers_count = len(MODEL_PROVIDER_MAP[model_id])
598
-
599
- models_data.append({
600
- "id": model_id,
601
- "object": "model",
602
- "created": int(time.time()),
603
- "owned_by": "g4f",
604
- "providers_available": providers_count,
605
- "permission": [],
606
- "root": model_id,
607
- "parent": None
608
- })
609
 
610
  try:
611
 
@@ -613,43 +129,36 @@ async def get_models():
613
 
614
  all_models = list(g4f.models._all_models)
615
 
616
- existing_ids = {
617
- m["id"]
618
- for m in models_data
619
- }
620
-
621
- for model in all_models[:30]:
622
 
623
- model_str = str(model)
 
 
 
 
 
624
 
625
- if model_str not in existing_ids:
626
 
627
- models_data.append({
628
- "id": model_str,
629
- "object": "model",
630
- "created": int(time.time()),
631
- "owned_by": "g4f",
632
- "providers_available": 1,
633
- "permission": [],
634
- "root": model_str,
635
- "parent": None
636
- })
637
 
638
- existing_ids.add(model_str)
 
639
 
640
- except Exception as e:
641
 
642
- logger.warning(
643
- f"Could not fetch g4f models: {e}"
644
- )
 
 
 
645
 
646
  return {
647
  "object": "list",
648
- "data": models_data,
649
- "total": len(models_data)
650
  }
651
 
652
-
653
  # =====================================================
654
  # CHAT COMPLETIONS
655
  # =====================================================
@@ -671,7 +180,7 @@ async def chat_completions(
671
  ]
672
 
673
  logger.info(
674
- f"Request | model={body.model} | stream={body.stream}"
675
  )
676
 
677
  # =================================================
@@ -684,7 +193,9 @@ async def chat_completions(
684
 
685
  try:
686
 
687
- response, actual_model = await smart_completion(
 
 
688
  model=body.model,
689
  messages=messages,
690
  stream=True
@@ -700,7 +211,6 @@ async def chat_completions(
700
 
701
  if (
702
  chunk.choices
703
- and len(chunk.choices) > 0
704
  and chunk.choices[0].delta
705
  and chunk.choices[0].delta.content
706
  ):
@@ -712,12 +222,11 @@ async def chat_completions(
712
  "id": chunk_id,
713
  "object": "chat.completion.chunk",
714
  "created": int(time.time()),
715
- "model": actual_model,
716
  "choices": [
717
  {
718
  "index": 0,
719
  "delta": {
720
- "role": "assistant",
721
  "content": content
722
  },
723
  "finish_reason": None
@@ -725,26 +234,21 @@ async def chat_completions(
725
  ]
726
  }
727
 
728
- yield (
729
- f"data: "
730
- f"{json.dumps(payload, ensure_ascii=False)}\n\n"
731
- )
732
 
733
  await asyncio.sleep(0)
734
 
735
  except Exception as chunk_error:
736
 
737
  logger.error(
738
- f"Chunk processing error: {chunk_error}"
739
  )
740
 
741
- continue
742
-
743
  final_payload = {
744
  "id": chunk_id,
745
  "object": "chat.completion.chunk",
746
  "created": int(time.time()),
747
- "model": actual_model,
748
  "choices": [
749
  {
750
  "index": 0,
@@ -754,16 +258,13 @@ async def chat_completions(
754
  ]
755
  }
756
 
757
- yield (
758
- f"data: "
759
- f"{json.dumps(final_payload)}\n\n"
760
- )
761
 
762
  yield "data: [DONE]\n\n"
763
 
764
  except Exception as e:
765
 
766
- logger.error(f"Stream generation error: {e}")
767
 
768
  error_payload = {
769
  "error": {
@@ -772,10 +273,7 @@ async def chat_completions(
772
  }
773
  }
774
 
775
- yield (
776
- f"data: "
777
- f"{json.dumps(error_payload)}\n\n"
778
- )
779
 
780
  return StreamingResponse(
781
  generate_stream(),
@@ -783,8 +281,7 @@ async def chat_completions(
783
  headers={
784
  "Cache-Control": "no-cache",
785
  "Connection": "keep-alive",
786
- "X-Accel-Buffering": "no",
787
- "Transfer-Encoding": "chunked"
788
  }
789
  )
790
 
@@ -794,46 +291,26 @@ async def chat_completions(
794
 
795
  try:
796
 
797
- proxy = get_proxy()
798
 
799
- response, actual_model = await smart_completion(
 
800
  model=body.model,
801
- messages=messages,
802
- stream=False,
803
- max_retries=3,
804
- proxy=proxy
805
  )
806
 
807
  assistant_message = ""
808
 
809
  try:
810
-
811
- assistant_message = (
812
- response.choices[0].message.content or ""
813
- )
814
-
815
- except AttributeError:
816
-
817
- try:
818
- assistant_message = str(response)
819
-
820
- except Exception:
821
- assistant_message = "Error extracting response"
822
-
823
- prompt_tokens = sum(
824
- len(m["content"].split())
825
- for m in messages
826
- )
827
-
828
- completion_tokens = len(
829
- assistant_message.split()
830
- )
831
 
832
  return JSONResponse({
833
  "id": f"chatcmpl-{uuid.uuid4().hex}",
834
  "object": "chat.completion",
835
  "created": int(time.time()),
836
- "model": actual_model,
837
  "choices": [
838
  {
839
  "index": 0,
@@ -845,31 +322,21 @@ async def chat_completions(
845
  }
846
  ],
847
  "usage": {
848
- "prompt_tokens": prompt_tokens,
849
- "completion_tokens": completion_tokens,
850
- "total_tokens": (
851
- prompt_tokens + completion_tokens
852
- )
853
  }
854
  })
855
 
856
- except HTTPException:
857
- raise
858
-
859
  except Exception as e:
860
 
861
- logger.error(f"Chat completion error: {e}")
862
 
863
  raise HTTPException(
864
  status_code=500,
865
- detail={
866
- "error": str(e),
867
- "model": body.model,
868
- "message": "Internal server error"
869
- }
870
  )
871
 
872
-
873
  # =====================================================
874
  # RUN
875
  # =====================================================
@@ -878,21 +345,8 @@ if __name__ == "__main__":
878
 
879
  import uvicorn
880
 
881
- logger.info(
882
- "Starting Universal AI Gateway v5.0.0"
883
- )
884
-
885
- logger.info(
886
- f"Proxy enabled: {bool(PROXY_LIST or SINGLE_PROXY)}"
887
- )
888
-
889
- logger.info(
890
- f"Models configured: {len(MODEL_PROVIDER_MAP)}"
891
- )
892
-
893
  uvicorn.run(
894
  app,
895
  host="0.0.0.0",
896
- port=7860,
897
- log_level="info"
898
  )
 
2
  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
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
  # =====================================================
 
46
  allow_headers=["*"],
47
  )
48
 
 
49
  # =====================================================
50
  # MODELS
51
  # =====================================================
 
54
  role: str
55
  content: str
56
 
 
57
  class ChatRequest(BaseModel):
58
  model: str
59
  messages: List[Message]
 
61
  temperature: Optional[float] = 0.7
62
  max_tokens: Optional[int] = 4096
63
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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()
 
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
  # =====================================================
 
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")
 
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
 
 
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
  # =====================================================
 
180
  ]
181
 
182
  logger.info(
183
+ f"Request model={body.model} stream={body.stream}"
184
  )
185
 
186
  # =================================================
 
193
 
194
  try:
195
 
196
+ client = Client()
197
+
198
+ response = client.chat.completions.create(
199
  model=body.model,
200
  messages=messages,
201
  stream=True
 
211
 
212
  if (
213
  chunk.choices
 
214
  and chunk.choices[0].delta
215
  and chunk.choices[0].delta.content
216
  ):
 
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
 
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,
 
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": {
 
273
  }
274
  }
275
 
276
+ yield f"data: {json.dumps(error_payload)}\n\n"
 
 
 
277
 
278
  return StreamingResponse(
279
  generate_stream(),
 
281
  headers={
282
  "Cache-Control": "no-cache",
283
  "Connection": "keep-alive",
284
+ "X-Accel-Buffering": "no"
 
285
  }
286
  )
287
 
 
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,
 
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
  # =====================================================
 
345
 
346
  import uvicorn
347
 
 
 
 
 
 
 
 
 
 
 
 
 
348
  uvicorn.run(
349
  app,
350
  host="0.0.0.0",
351
+ port=7860
 
352
  )