bahi-bh commited on
Commit
2550709
·
verified ·
1 Parent(s): 0afa6dc

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +49 -36
app.py CHANGED
@@ -289,7 +289,7 @@ class ChatRequest(BaseModel):
289
  history: List[Any] = []
290
 
291
  # =====================================================
292
- # Claude Desktop / Claude Code Compatible Endpoints
293
  # =====================================================
294
 
295
  def verify_api_key(request: Request):
@@ -308,6 +308,38 @@ def verify_api_key(request: Request):
308
 
309
  raise HTTPException(status_code=401, detail="Invalid API key. Use 'Authorization: Bearer KEY' or 'X-API-Key: KEY'")
310
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
311
  @app.post("/v1/messages")
312
  async def v1_messages(request: Request):
313
  """Anthropic API compatible endpoint for Claude Desktop / Claude Code"""
@@ -315,7 +347,6 @@ async def v1_messages(request: Request):
315
 
316
  body = await request.json()
317
 
318
- # استخراج الرسالة من تنسيق Anthropic
319
  messages = body.get("messages", [])
320
  if not messages:
321
  raise HTTPException(status_code=400, detail="No messages provided")
@@ -323,30 +354,23 @@ async def v1_messages(request: Request):
323
  last_message = messages[-1]
324
  user_message = last_message.get("content", "")
325
 
326
- # استخراج النموذج
327
  model = body.get("model", "sonar")
328
-
329
- # استخراج النظام (system prompt) إن وجد
330
  system_prompt = body.get("system", "")
331
 
332
- # بناء التاريخ من الرسائل السابقة
333
  history = []
334
  for msg in messages[:-1]:
335
  role = msg.get("role", "user")
336
  content = msg.get("content", "")
337
  history.append({"role": role, "content": content})
338
 
339
- # إضافة system prompt إذا موجود
340
  full_message = user_message
341
  if system_prompt:
342
  full_message = f"[System: {system_prompt}]\n\n{user_message}"
343
 
344
- # الحصول على الرد
345
  full_response = ""
346
  for chunk in ask(full_message, history, "Perplexity", model):
347
  full_response = chunk
348
 
349
- # إرجاع الرد بتنسيق Anthropic API
350
  return {
351
  "id": f"msg_{int(time.time())}_{os.urandom(4).hex()}",
352
  "type": "message",
@@ -374,18 +398,26 @@ async def v1_messages_stream(request: Request):
374
  last_message = messages[-1]
375
  user_message = last_message.get("content", "")
376
  model = body.get("model", "sonar")
 
 
 
 
 
377
 
378
  async def generate_stream():
379
  message_id = f"msg_{int(time.time())}_{os.urandom(4).hex()}"
380
 
381
- # رسالة البدء
382
  yield f"event: message_start\ndata: {{\"message\": {{\"id\": \"{message_id}\", \"type\": \"message\", \"role\": \"assistant\", \"content\": [], \"model\": \"{model}\", \"stop_reason\": null, \"stop_sequence\": null, \"usage\": {{\"input_tokens\": 0, \"output_tokens\": 0}}}}}}\n\n"
383
 
384
- # رسالة التدفق
385
- for chunk in ask(user_message, [], "Perplexity", model):
 
 
 
386
  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"
387
 
388
- # رسالة النهاية
389
  yield f"event: message_delta\ndata: {{\"type\": \"message_delta\", \"delta\": {{\"stop_reason\": \"end_turn\", \"stop_sequence\": null}}, \"usage\": {{\"output_tokens\": 100}}}}\n\n"
390
  yield f"event: message_stop\ndata: {{}}\n\n"
391
 
@@ -399,27 +431,8 @@ async def v1_messages_stream(request: Request):
399
  }
400
  )
401
 
402
- @app.get("/v1/models")
403
- async def v1_models(request: Request):
404
- """Anthropic API compatible models endpoint"""
405
- verify_api_key(request)
406
-
407
- models = []
408
- for pname, pobj in REAL_PROVIDERS.items():
409
- if pname not in _PROVIDER_MODEL_CACHE:
410
- _PROVIDER_MODEL_CACHE[pname] = discover_provider_models(pobj, pname)
411
- for model in _PROVIDER_MODEL_CACHE[pname]:
412
- models.append({
413
- "id": model,
414
- "type": "model",
415
- "display_name": f"{pname} - {model}",
416
- "created_at": "2024-01-01T00:00:00Z"
417
- })
418
-
419
- return {"data": models}
420
-
421
  # =====================================================
422
- # ORIGINAL ENDPOINTS (للتوافق مع الواجهة القديمة)
423
  # =====================================================
424
 
425
  @app.get("/")
@@ -429,9 +442,9 @@ async def root():
429
  "endpoints": {
430
  "GET /": "هذه الصفحة",
431
  "GET /health": "التحقق من صحة الخادم",
432
- "GET /v1/models": "قائمة النماذج (Claude-compatible)",
433
- "POST /v1/messages": "إرسال رسالة (Claude-compatible)",
434
- "POST /v1/messages/stream": "إرسال رسالة متدفق (Claude-compatible)",
435
  "GET /providers": "قائمة المزودين (يتطلب مفتاح)",
436
  "POST /chat": "إرسال رسالة (legacy)",
437
  "POST /chat/stream": "إرسال رسالة متدفق (legacy)"
 
289
  history: List[Any] = []
290
 
291
  # =====================================================
292
+ # VERIFY API KEY
293
  # =====================================================
294
 
295
  def verify_api_key(request: Request):
 
308
 
309
  raise HTTPException(status_code=401, detail="Invalid API key. Use 'Authorization: Bearer KEY' or 'X-API-Key: KEY'")
310
 
311
+ # =====================================================
312
+ # CLAUDE-DESKTOP / CLAUDE-CODE COMPATIBLE ENDPOINTS
313
+ # =====================================================
314
+
315
+ @app.get("/v1/models")
316
+ async def v1_models(request: Request):
317
+ """Anthropic API compatible models endpoint - NO AUTH REQUIRED"""
318
+ # Claude Desktop يطلب هذا أولاً بدون مفتاح
319
+
320
+ models = []
321
+ for pname, pobj in REAL_PROVIDERS.items():
322
+ if pname not in _PROVIDER_MODEL_CACHE:
323
+ _PROVIDER_MODEL_CACHE[pname] = discover_provider_models(pobj, pname)
324
+ for model in _PROVIDER_MODEL_CACHE[pname][:5]:
325
+ models.append({
326
+ "id": model,
327
+ "type": "model",
328
+ "display_name": f"{pname} - {model}"
329
+ })
330
+
331
+ # نماذج افتراضية في حال لم يتم العثور على شيء
332
+ if not models:
333
+ models = [
334
+ {"id": "sonar", "type": "model", "display_name": "Perplexity - Sonar"},
335
+ {"id": "sonar-pro", "type": "model", "display_name": "Perplexity - Sonar Pro"},
336
+ {"id": "gpt-4o", "type": "model", "display_name": "GPT-4o"},
337
+ {"id": "claude-3", "type": "model", "display_name": "Claude 3"},
338
+ {"id": "deepseek-chat", "type": "model", "display_name": "DeepSeek Chat"}
339
+ ]
340
+
341
+ return {"data": models}
342
+
343
  @app.post("/v1/messages")
344
  async def v1_messages(request: Request):
345
  """Anthropic API compatible endpoint for Claude Desktop / Claude Code"""
 
347
 
348
  body = await request.json()
349
 
 
350
  messages = body.get("messages", [])
351
  if not messages:
352
  raise HTTPException(status_code=400, detail="No messages provided")
 
354
  last_message = messages[-1]
355
  user_message = last_message.get("content", "")
356
 
 
357
  model = body.get("model", "sonar")
 
 
358
  system_prompt = body.get("system", "")
359
 
 
360
  history = []
361
  for msg in messages[:-1]:
362
  role = msg.get("role", "user")
363
  content = msg.get("content", "")
364
  history.append({"role": role, "content": content})
365
 
 
366
  full_message = user_message
367
  if system_prompt:
368
  full_message = f"[System: {system_prompt}]\n\n{user_message}"
369
 
 
370
  full_response = ""
371
  for chunk in ask(full_message, history, "Perplexity", model):
372
  full_response = chunk
373
 
 
374
  return {
375
  "id": f"msg_{int(time.time())}_{os.urandom(4).hex()}",
376
  "type": "message",
 
398
  last_message = messages[-1]
399
  user_message = last_message.get("content", "")
400
  model = body.get("model", "sonar")
401
+ system_prompt = body.get("system", "")
402
+
403
+ full_message = user_message
404
+ if system_prompt:
405
+ full_message = f"[System: {system_prompt}]\n\n{user_message}"
406
 
407
  async def generate_stream():
408
  message_id = f"msg_{int(time.time())}_{os.urandom(4).hex()}"
409
 
410
+ # Message start
411
  yield f"event: message_start\ndata: {{\"message\": {{\"id\": \"{message_id}\", \"type\": \"message\", \"role\": \"assistant\", \"content\": [], \"model\": \"{model}\", \"stop_reason\": null, \"stop_sequence\": null, \"usage\": {{\"input_tokens\": 0, \"output_tokens\": 0}}}}}}\n\n"
412
 
413
+ # Content block start
414
+ yield f"event: content_block_start\ndata: {{\"type\": \"content_block_start\", \"index\": 0, \"content_block\": {{\"type\": \"text\", \"text\": \"\"}}}}\n\n"
415
+
416
+ # Stream deltas
417
+ for chunk in ask(full_message, [], "Perplexity", model):
418
  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"
419
 
420
+ # Message end
421
  yield f"event: message_delta\ndata: {{\"type\": \"message_delta\", \"delta\": {{\"stop_reason\": \"end_turn\", \"stop_sequence\": null}}, \"usage\": {{\"output_tokens\": 100}}}}\n\n"
422
  yield f"event: message_stop\ndata: {{}}\n\n"
423
 
 
431
  }
432
  )
433
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
434
  # =====================================================
435
+ # ORIGINAL ENDPOINTS (للواجهة القديمة)
436
  # =====================================================
437
 
438
  @app.get("/")
 
442
  "endpoints": {
443
  "GET /": "هذه الصفحة",
444
  "GET /health": "التحقق من صحة الخادم",
445
+ "GET /v1/models": "قائمة النماذج (Claude-compatible - NO AUTH)",
446
+ "POST /v1/messages": "إرسال رسالة (Claude-compatible - REQUIRES AUTH)",
447
+ "POST /v1/messages/stream": "إرسال رسالة متدفق (Claude-compatible - REQUIRES AUTH)",
448
  "GET /providers": "قائمة المزودين (يتطلب مفتاح)",
449
  "POST /chat": "إرسال رسالة (legacy)",
450
  "POST /chat/stream": "إرسال رسالة متدفق (legacy)"