| 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 |
|
|
| |
| import g4f |
| from g4f import ChatCompletion |
| from g4f.Provider import ( |
| Bing, |
| OpenaiChat, |
| Gemini, |
| You, |
| AIChat |
| ) |
|
|
| |
| |
| |
|
|
| logging.basicConfig(level=logging.INFO) |
| logger = logging.getLogger(__name__) |
|
|
| |
| |
| |
|
|
| API_KEY = "sk-your-secret-key" |
|
|
| |
| |
| |
|
|
| app = FastAPI( |
| title="Universal AI Gateway", |
| version="5.3.0" |
| ) |
|
|
| |
| |
| |
|
|
| app.add_middleware( |
| CORSMiddleware, |
| allow_origins=["*"], |
| allow_credentials=True, |
| allow_methods=["*"], |
| allow_headers=["*"], |
| ) |
|
|
| |
| |
| |
|
|
| 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 |
|
|
| |
| |
| |
|
|
| 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 |
|
|
| |
| |
| |
|
|
| @app.get("/") |
| async def root(): |
| return { |
| "status": "online", |
| "service": "Universal AI Gateway", |
| "version": "5.3.0", |
| "providers": ["Bing", "OpenaiChat", "Gemini", "You"] |
| } |
|
|
| |
| |
| |
|
|
| @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 |
| } |
|
|
| |
| |
| |
|
|
| @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}") |
| |
| |
| |
| |
| |
| if body.stream: |
| async def generate_stream() -> AsyncGenerator[str, None]: |
| chunk_id = f"chatcmpl-{uuid.uuid4().hex[:8]}" |
| |
| try: |
| |
| response = await ChatCompletion.create_async( |
| model=body.model, |
| messages=messages, |
| stream=True, |
| provider=Bing |
| ) |
| |
| 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": "*" |
| } |
| ) |
| |
| |
| |
| |
| |
| try: |
| |
| 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)}" |
| ) |
|
|
| |
| |
| |
|
|
| if __name__ == "__main__": |
| import uvicorn |
| uvicorn.run( |
| app, |
| host="0.0.0.0", |
| port=7860, |
| log_level="info" |
| ) |