File size: 3,067 Bytes
2446f5f 500ef17 2446f5f 56d0fcf 2446f5f 1c864be 500ef17 2446f5f 1c864be 2446f5f 326f1b4 500ef17 2446f5f 500ef17 2446f5f 56d0fcf 2446f5f 1c864be 500ef17 1c864be 56d0fcf 500ef17 1c864be 500ef17 56d0fcf 500ef17 56d0fcf 500ef17 56d0fcf 500ef17 1c864be 500ef17 56d0fcf 2446f5f 56d0fcf 2d93720 56d0fcf |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
import httpx
from fastapi import FastAPI, Request, HTTPException
from fastapi.responses import StreamingResponse
import json
import random
import logging
# Configure logging to output to stdout
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s - %(levelname)s - %(message)s",
datefmt="%Y-%m-%d %H:%M:%S",
)
app = FastAPI()
# List of API URLs to be randomized
API_URLS = [
"https://api.deepinfra.com/v1/openai/chat/completions",
"https://stage.api.deepinfra.com/v1/openai/chat/completions",
]
@app.post("/v1/openai/chat/completions")
async def proxy_deepinfra(request: Request):
"""
Proxies chat completion requests to the DeepInfra API.
It randomizes the order of API URLs and uses the next as a fallback.
"""
try:
body = await request.json()
except json.JSONDecodeError:
raise HTTPException(status_code=400, detail="Invalid JSON in request body")
headers = {
'sec-ch-ua-platform': request.headers.get('sec-ch-ua-platform', '"Windows"'),
'Referer': request.headers.get('Referer', 'https://deepinfra.com/'),
'sec-ch-ua': request.headers.get('sec-ch-ua', '"Chromium";v="140", "Not=A?Brand";v="24", "Google Chrome";v="140"'),
'sec-ch-ua-mobile': request.headers.get('sec-ch-ua-mobile', '?0'),
'User-Agent': request.headers.get('User-Agent', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36'),
'accept': request.headers.get('accept', 'text-event-stream'),
'X-Deepinfra-Source': request.headers.get('X-Deepinfra-Source', 'web-embed'),
'Content-Type': request.headers.get('Content-Type', 'application/json'),
}
shuffled_urls = random.sample(API_URLS, len(API_URLS))
async def stream_generator():
last_error = None
for url in shuffled_urls:
logging.info(f"Attempting to connect to: {url}")
try:
async with httpx.AsyncClient() as client:
async with client.stream("POST", url, headers=headers, json=body, timeout=None) as response:
response.raise_for_status()
logging.info(f"Successfully connected. Streaming from: {url}")
async for chunk in response.aiter_bytes():
yield chunk
return
except (httpx.RequestError, httpx.HTTPStatusError) as e:
last_error = e
logging.warning(f"Failed to connect to {url}: {e}. Trying next URL.")
continue
if last_error:
logging.error(f"All API endpoints failed. Last error: {last_error}")
# In a streaming response, we can't easily raise an HTTPException after starting.
# The connection will simply close, which the client will see as a failed request.
return StreamingResponse(stream_generator(), media_type="text-event-stream")
# The `if __name__ == "__main__":` block is removed as Gunicorn will run the app. |