from fastapi import FastAPI, Request, HTTPException from fastapi.middleware.cors import CORSMiddleware from fastapi.responses import StreamingResponse, JSONResponse from pydantic import BaseModel from typing import List, Optional, AsyncGenerator import json import time import uuid import logging import asyncio # استيراد g4f بالطريقة الصحيحة import g4f from g4f import ChatCompletion from g4f.Provider import ( Bing, OpenaiChat, Gemini, You, AIChat ) # ===================================================== # LOGGING # ===================================================== logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) # ===================================================== # CONFIG # ===================================================== API_KEY = "sk-your-secret-key" # غيّر هذا # ===================================================== # FASTAPI # ===================================================== app = FastAPI( title="Universal AI Gateway", version="5.3.0" ) # ===================================================== # CORS # ===================================================== app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) # ===================================================== # MODELS # ===================================================== class Message(BaseModel): role: str content: str class ChatRequest(BaseModel): model: str = "gpt-3.5-turbo" messages: List[Message] stream: bool = False temperature: Optional[float] = 0.7 max_tokens: Optional[int] = 4096 # ===================================================== # AUTH # ===================================================== def verify_api_key(req: Request): # للاختبار: السماح بدون مفتاح auth = req.headers.get("Authorization") if not auth: return True if not auth.startswith("Bearer "): raise HTTPException(status_code=401, detail="Invalid Authorization Format") token = auth.replace("Bearer ", "").strip() if token != API_KEY: raise HTTPException(status_code=403, detail="Invalid API Key") return True # ===================================================== # ROOT # ===================================================== @app.get("/") async def root(): return { "status": "online", "service": "Universal AI Gateway", "version": "5.3.0", "providers": ["Bing", "OpenaiChat", "Gemini", "You"] } # ===================================================== # MODELS # ===================================================== @app.get("/v1/models") async def get_models(): # قائمة النماذج المدعومة فعلياً models_data = [ {"id": "gpt-3.5-turbo", "object": "model", "owned_by": "g4f"}, {"id": "gpt-4", "object": "model", "owned_by": "g4f"}, {"id": "gpt-4o-mini", "object": "model", "owned_by": "g4f"}, {"id": "gemini", "object": "model", "owned_by": "g4f"}, ] return { "object": "list", "data": models_data } # ===================================================== # CHAT COMPLETIONS # ===================================================== @app.post("/v1/chat/completions") async def chat_completions( req: Request, body: ChatRequest ): # التحقق من المفتاح verify_api_key(req) # تحويل الرسائل messages = [ {"role": m.role, "content": m.content} for m in body.messages ] logger.info(f"Request: model={body.model}, stream={body.stream}") logger.info(f"Messages: {messages}") # ================================================= # STREAMING # ================================================= if body.stream: async def generate_stream() -> AsyncGenerator[str, None]: chunk_id = f"chatcmpl-{uuid.uuid4().hex[:8]}" try: # استخدام ChatCompletion.create مع stream=True response = await ChatCompletion.create_async( model=body.model, messages=messages, stream=True, provider=Bing # جرب Bing أو OpenaiChat ) async for chunk in response: if chunk: payload = { "id": chunk_id, "object": "chat.completion.chunk", "created": int(time.time()), "model": body.model, "choices": [ { "index": 0, "delta": {"content": chunk}, "finish_reason": None } ] } yield f"data: {json.dumps(payload, ensure_ascii=False)}\n\n" # إرسال إشارة النهاية final_payload = { "id": chunk_id, "object": "chat.completion.chunk", "created": int(time.time()), "model": body.model, "choices": [ { "index": 0, "delta": {}, "finish_reason": "stop" } ] } yield f"data: {json.dumps(final_payload)}\n\n" yield "data: [DONE]\n\n" except Exception as e: logger.error(f"Streaming error: {e}", exc_info=True) error_msg = {"error": {"message": str(e), "type": "stream_error"}} yield f"data: {json.dumps(error_msg)}\n\n" yield "data: [DONE]\n\n" return StreamingResponse( generate_stream(), media_type="text/event-stream", headers={ "Cache-Control": "no-cache", "Connection": "keep-alive", "Access-Control-Allow-Origin": "*" } ) # ================================================= # NORMAL RESPONSE # ================================================= try: # استخدام ChatCompletion.create_async response = await ChatCompletion.create_async( model=body.model, messages=messages, stream=False, provider=Bing # جرب مزوداً مختلفاً إذا فشل ) return JSONResponse({ "id": f"chatcmpl-{uuid.uuid4().hex[:8]}", "object": "chat.completion", "created": int(time.time()), "model": body.model, "choices": [ { "index": 0, "message": { "role": "assistant", "content": response }, "finish_reason": "stop" } ], "usage": { "prompt_tokens": 0, "completion_tokens": 0, "total_tokens": 0 } }) except Exception as e: logger.error(f"Chat error: {e}", exc_info=True) raise HTTPException( status_code=500, detail=f"Provider error: {str(e)}" ) # ===================================================== # RUN # ===================================================== if __name__ == "__main__": import uvicorn uvicorn.run( app, host="0.0.0.0", port=7860, log_level="info" )