bahi-bh commited on
Commit
33253ea
·
verified ·
1 Parent(s): 2b2b8ca

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +56 -40
app.py CHANGED
@@ -98,7 +98,7 @@ class TTLCache:
98
  CACHE = TTLCache(max_size=100, ttl_seconds=300)
99
 
100
  # =====================================================
101
- # PROVIDERS
102
  # =====================================================
103
  def get_provider(name: str):
104
  try:
@@ -107,27 +107,39 @@ def get_provider(name: str):
107
  return None
108
 
109
  REAL_PROVIDERS = {
110
- "Perplexity": get_provider("Perplexity") or get_provider("PerplexityAi"),
111
- "Copilot": get_provider("Copilot"),
112
  "Qwen": get_provider("Qwen"),
113
- "Blackbox": get_provider("Blackbox"),
114
- "DeepSeek": get_provider("DeepSeek"),
115
- "Bing": get_provider("Bing"),
116
- "You": get_provider("You"),
117
  }
118
  REAL_PROVIDERS = {k: v for k, v in REAL_PROVIDERS.items() if v}
119
 
120
  # =====================================================
121
- # MODEL FALLBACK
122
  # =====================================================
123
  PROVIDER_MODELS_FALLBACK = {
124
- "Perplexity": ["sonar", "sonar-pro", "gpt-4o", "llama-3"],
125
- "Copilot": ["gpt-4o", "gpt-4", "turbo"],
126
- "Qwen": ["qwen-max", "qwen-plus", "qwen-turbo", "qwen"],
127
- "Blackbox": ["gpt-4o", "claude-3", "gemini-pro", "llama-3"],
128
- "DeepSeek": ["deepseek-chat", "deepseek-coder"],
129
- "Bing": ["gpt-4o", "gpt-4"],
130
- "You": ["gpt-4o", "claude", "llama-3"],
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
131
  }
132
 
133
  # =====================================================
@@ -150,7 +162,7 @@ def discover_provider_models(provider_obj: Any, provider_name: str) -> List[str]
150
  except:
151
  pass
152
  if not candidates:
153
- candidates = PROVIDER_MODELS_FALLBACK.get(provider_name, ["gpt-4o"])
154
  seen = set()
155
  return [m for m in candidates if not (m in seen or seen.add(m))]
156
 
@@ -191,7 +203,7 @@ def clean_stream(chunk):
191
  return ""
192
 
193
  # =====================================================
194
- # CHAT LOGIC
195
  # =====================================================
196
  def ask(message: str, history, provider_name: str, model_name: str, stop_flag=None):
197
  message = (message or "").strip()
@@ -225,8 +237,10 @@ def ask(message: str, history, provider_name: str, model_name: str, stop_flag=No
225
 
226
  msgs.append({"role": "user", "content": message})
227
 
 
228
  fallback_providers = [
229
- provider_name, "Perplexity", "Copilot", "Blackbox", "DeepSeek", "Bing", "You", "Qwen"
 
230
  ]
231
  used = []
232
 
@@ -278,14 +292,14 @@ def ask(message: str, history, provider_name: str, model_name: str, stop_flag=No
278
  # =====================================================
279
  # FASTAPI
280
  # =====================================================
281
- app = FastAPI(title="G4F Smart Router", description="Claude-compatible AI Gateway")
282
 
283
  API_KEY = os.getenv("API_KEY", "mysecretkey123")
284
 
285
  class ChatRequest(BaseModel):
286
  message: str
287
- provider: str = "Perplexity"
288
- model: str = "sonar"
289
  history: List[Any] = []
290
 
291
  # =====================================================
@@ -309,34 +323,34 @@ def verify_api_key(request: Request):
309
  raise HTTPException(status_code=401, detail="Invalid API key. Use 'Authorization: Bearer KEY' or 'X-API-Key: KEY'")
310
 
311
  # =====================================================
312
- # SUPPORT HEAD METHOD (لإصلاح خطأ 405)
313
  # =====================================================
314
 
315
  @app.head("/")
316
  async def head_root():
317
- return Response(status_code=200, headers={"Content-Type": "application/json"})
318
 
319
  @app.head("/health")
320
  async def head_health():
321
- return Response(status_code=200, headers={"Content-Type": "application/json"})
322
 
323
  @app.head("/v1/models")
324
  async def head_models():
325
- return Response(status_code=200, headers={"Content-Type": "application/json"})
326
 
327
  # =====================================================
328
- # CLAUDE-DESKTOP / CLAUDE-CODE COMPATIBLE ENDPOINTS
329
  # =====================================================
330
 
331
  @app.get("/v1/models")
332
  async def v1_models(request: Request):
333
- """Anthropic API compatible models endpoint - NO AUTH REQUIRED"""
334
 
335
  models = []
336
  for pname, pobj in REAL_PROVIDERS.items():
337
  if pname not in _PROVIDER_MODEL_CACHE:
338
  _PROVIDER_MODEL_CACHE[pname] = discover_provider_models(pobj, pname)
339
- for model in _PROVIDER_MODEL_CACHE[pname][:5]:
340
  models.append({
341
  "id": model,
342
  "type": "model",
@@ -345,18 +359,19 @@ async def v1_models(request: Request):
345
 
346
  if not models:
347
  models = [
348
- {"id": "sonar", "type": "model", "display_name": "Perplexity - Sonar"},
349
- {"id": "sonar-pro", "type": "model", "display_name": "Perplexity - Sonar Pro"},
350
- {"id": "gpt-4o", "type": "model", "display_name": "GPT-4o"},
351
- {"id": "claude-3", "type": "model", "display_name": "Claude 3"},
352
- {"id": "deepseek-chat", "type": "model", "display_name": "DeepSeek Chat"}
 
353
  ]
354
 
355
  return {"data": models}
356
 
357
  @app.post("/v1/messages")
358
  async def v1_messages(request: Request):
359
- """Anthropic API compatible endpoint for Claude Desktop / Claude Code"""
360
  verify_api_key(request)
361
 
362
  body = await request.json()
@@ -368,7 +383,7 @@ async def v1_messages(request: Request):
368
  last_message = messages[-1]
369
  user_message = last_message.get("content", "")
370
 
371
- model = body.get("model", "sonar")
372
  system_prompt = body.get("system", "")
373
 
374
  history = []
@@ -382,7 +397,7 @@ async def v1_messages(request: Request):
382
  full_message = f"[System: {system_prompt}]\n\n{user_message}"
383
 
384
  full_response = ""
385
- for chunk in ask(full_message, history, "Perplexity", model):
386
  full_response = chunk
387
 
388
  return {
@@ -401,7 +416,7 @@ async def v1_messages(request: Request):
401
 
402
  @app.post("/v1/messages/stream")
403
  async def v1_messages_stream(request: Request):
404
- """Anthropic API compatible streaming endpoint"""
405
  verify_api_key(request)
406
 
407
  body = await request.json()
@@ -411,7 +426,7 @@ async def v1_messages_stream(request: Request):
411
 
412
  last_message = messages[-1]
413
  user_message = last_message.get("content", "")
414
- model = body.get("model", "sonar")
415
  system_prompt = body.get("system", "")
416
 
417
  full_message = user_message
@@ -425,7 +440,7 @@ async def v1_messages_stream(request: Request):
425
 
426
  yield f"event: content_block_start\ndata: {{\"type\": \"content_block_start\", \"index\": 0, \"content_block\": {{\"type\": \"text\", \"text\": \"\"}}}}\n\n"
427
 
428
- for chunk in ask(full_message, [], "Perplexity", model):
429
  yield f"event: content_block_delta\ndata: {{\"type\": \"content_block_delta\", \"index\": 0, \"delta\": {{\"type\": \"text_delta\", \"text\": {json.dumps(chunk, ensure_ascii=False)}}}}}\n\n"
430
 
431
  yield f"event: message_delta\ndata: {{\"type\": \"message_delta\", \"delta\": {{\"stop_reason\": \"end_turn\", \"stop_sequence\": null}}, \"usage\": {{\"output_tokens\": 100}}}}\n\n"
@@ -447,7 +462,8 @@ async def v1_messages_stream(request: Request):
447
  @app.get("/")
448
  async def root():
449
  return {
450
- "message": "G4F Smart Router is running (Claude-compatible)",
 
451
  "endpoints": {
452
  "GET /": "Home page",
453
  "GET /health": "Health check",
 
98
  CACHE = TTLCache(max_size=100, ttl_seconds=300)
99
 
100
  # =====================================================
101
+ # PROVIDERS - فقط Qwen
102
  # =====================================================
103
  def get_provider(name: str):
104
  try:
 
107
  return None
108
 
109
  REAL_PROVIDERS = {
 
 
110
  "Qwen": get_provider("Qwen"),
 
 
 
 
111
  }
112
  REAL_PROVIDERS = {k: v for k, v in REAL_PROVIDERS.items() if v}
113
 
114
  # =====================================================
115
+ # MODELS - جميع نماذج Qwen
116
  # =====================================================
117
  PROVIDER_MODELS_FALLBACK = {
118
+ "Qwen": [
119
+ "qwen-max",
120
+ "qwen-plus",
121
+ "qwen-turbo",
122
+ "qwen-2.5-72b-instruct",
123
+ "qwen-2.5-32b-instruct",
124
+ "qwen-2.5-coder-32b-instruct",
125
+ "qwen-2.5-7b-instruct",
126
+ "qvq-72b-preview",
127
+ "qwen2.5-72b",
128
+ "qwen2.5-32b",
129
+ "qwen2.5-coder-7b",
130
+ "qwen2.5-1.5b",
131
+ "qwen2.5-0.5b",
132
+ "qwen",
133
+ "qwen2.5",
134
+ "qwen-coder",
135
+ "qwen2.5-coder",
136
+ "qwen-vl",
137
+ "qwen-vl-max",
138
+ "qwen-vl-plus",
139
+ "qvq-72b",
140
+ "qwen-max-latest",
141
+ "qwen-plus-latest",
142
+ ],
143
  }
144
 
145
  # =====================================================
 
162
  except:
163
  pass
164
  if not candidates:
165
+ candidates = PROVIDER_MODELS_FALLBACK.get(provider_name, ["qwen-max"])
166
  seen = set()
167
  return [m for m in candidates if not (m in seen or seen.add(m))]
168
 
 
203
  return ""
204
 
205
  # =====================================================
206
+ # CHAT LOGIC - فقط مع Qwen و fallback محدد
207
  # =====================================================
208
  def ask(message: str, history, provider_name: str, model_name: str, stop_flag=None):
209
  message = (message or "").strip()
 
237
 
238
  msgs.append({"role": "user", "content": message})
239
 
240
+ # استراتيجية التراجع: فقط Qwen
241
  fallback_providers = [
242
+ provider_name,
243
+ "Qwen"
244
  ]
245
  used = []
246
 
 
292
  # =====================================================
293
  # FASTAPI
294
  # =====================================================
295
+ app = FastAPI(title="G4F Smart Router", description="AI Gateway - Qwen Only")
296
 
297
  API_KEY = os.getenv("API_KEY", "mysecretkey123")
298
 
299
  class ChatRequest(BaseModel):
300
  message: str
301
+ provider: str = "Qwen"
302
+ model: str = "qwen-max"
303
  history: List[Any] = []
304
 
305
  # =====================================================
 
323
  raise HTTPException(status_code=401, detail="Invalid API key. Use 'Authorization: Bearer KEY' or 'X-API-Key: KEY'")
324
 
325
  # =====================================================
326
+ # SUPPORT HEAD METHOD
327
  # =====================================================
328
 
329
  @app.head("/")
330
  async def head_root():
331
+ return Response(status_code=200)
332
 
333
  @app.head("/health")
334
  async def head_health():
335
+ return Response(status_code=200)
336
 
337
  @app.head("/v1/models")
338
  async def head_models():
339
+ return Response(status_code=200)
340
 
341
  # =====================================================
342
+ # CLAUDE-COMPATIBLE ENDPOINTS
343
  # =====================================================
344
 
345
  @app.get("/v1/models")
346
  async def v1_models(request: Request):
347
+ """نماذ�� Qwen المتاحة"""
348
 
349
  models = []
350
  for pname, pobj in REAL_PROVIDERS.items():
351
  if pname not in _PROVIDER_MODEL_CACHE:
352
  _PROVIDER_MODEL_CACHE[pname] = discover_provider_models(pobj, pname)
353
+ for model in _PROVIDER_MODEL_CACHE[pname][:10]:
354
  models.append({
355
  "id": model,
356
  "type": "model",
 
359
 
360
  if not models:
361
  models = [
362
+ {"id": "qwen-max", "type": "model", "display_name": "Qwen - Max"},
363
+ {"id": "qwen-plus", "type": "model", "display_name": "Qwen - Plus"},
364
+ {"id": "qwen-turbo", "type": "model", "display_name": "Qwen - Turbo"},
365
+ {"id": "qwen-coder", "type": "model", "display_name": "Qwen - Coder"},
366
+ {"id": "qwen2.5-72b", "type": "model", "display_name": "Qwen 2.5 - 72B"},
367
+ {"id": "qwen2.5-32b", "type": "model", "display_name": "Qwen 2.5 - 32B"},
368
  ]
369
 
370
  return {"data": models}
371
 
372
  @app.post("/v1/messages")
373
  async def v1_messages(request: Request):
374
+ """نقطة نهاية متوافقة مع Claude Desktop"""
375
  verify_api_key(request)
376
 
377
  body = await request.json()
 
383
  last_message = messages[-1]
384
  user_message = last_message.get("content", "")
385
 
386
+ model = body.get("model", "qwen-max")
387
  system_prompt = body.get("system", "")
388
 
389
  history = []
 
397
  full_message = f"[System: {system_prompt}]\n\n{user_message}"
398
 
399
  full_response = ""
400
+ for chunk in ask(full_message, history, "Qwen", model):
401
  full_response = chunk
402
 
403
  return {
 
416
 
417
  @app.post("/v1/messages/stream")
418
  async def v1_messages_stream(request: Request):
419
+ """نقطة نهاية متدفقة متوافقة مع Claude Desktop"""
420
  verify_api_key(request)
421
 
422
  body = await request.json()
 
426
 
427
  last_message = messages[-1]
428
  user_message = last_message.get("content", "")
429
+ model = body.get("model", "qwen-max")
430
  system_prompt = body.get("system", "")
431
 
432
  full_message = user_message
 
440
 
441
  yield f"event: content_block_start\ndata: {{\"type\": \"content_block_start\", \"index\": 0, \"content_block\": {{\"type\": \"text\", \"text\": \"\"}}}}\n\n"
442
 
443
+ for chunk in ask(full_message, [], "Qwen", model):
444
  yield f"event: content_block_delta\ndata: {{\"type\": \"content_block_delta\", \"index\": 0, \"delta\": {{\"type\": \"text_delta\", \"text\": {json.dumps(chunk, ensure_ascii=False)}}}}}\n\n"
445
 
446
  yield f"event: message_delta\ndata: {{\"type\": \"message_delta\", \"delta\": {{\"stop_reason\": \"end_turn\", \"stop_sequence\": null}}, \"usage\": {{\"output_tokens\": 100}}}}\n\n"
 
462
  @app.get("/")
463
  async def root():
464
  return {
465
+ "message": "G4F Smart Router is running (Qwen Only)",
466
+ "provider": "Qwen",
467
  "endpoints": {
468
  "GET /": "Home page",
469
  "GET /health": "Health check",