99import httpx
1010from fastapi import APIRouter , Request , Header , HTTPException
1111from fastapi .responses import StreamingResponse , Response
12- from openai import AsyncOpenAI
12+ from openai import AsyncOpenAI , APIError
1313
1414from config import config , logger
1515from constants import OPENROUTER_BASE_URL , PUBLIC_ENDPOINTS , BINARY_ENDPOINTS
1616from key_manager import KeyManager
1717from utils import (
1818 verify_access_key ,
1919 check_rate_limit_error ,
20+ check_rate_limit_openai ,
2021)
2122
2223# Create router
@@ -121,7 +122,7 @@ async def proxy_endpoint(
121122
122123 except Exception as e :
123124 logger .error ("Error proxying request: %s" , str (e ))
124- raise HTTPException (status_code = 500 , detail = f"Proxy error: { str (e )} " )
125+ raise HTTPException (status_code = 500 , detail = f"Proxy error: { str (e )} " ) from e
125126
126127
127128async def handle_chat_completions (
@@ -173,14 +174,17 @@ async def stream_response() -> AsyncGenerator[bytes, None]:
173174
174175 # Send the end marker
175176 yield b"data: [DONE]\n \n "
176- except Exception as e :
177- logger .error ("Error in streaming response: %s" , str ( e ) )
177+ except APIError as err :
178+ logger .error ("Error in streaming response: %s" , err )
178179 # Check if this is a rate limit error
179- if "rate limit" in str (e ).lower () and api_key :
180- logger .warning ("Rate limit detected in stream. Disabling key." )
181- await key_manager .disable_key (
182- api_key , None
183- ) # Disable without reset time
180+ if api_key :
181+ has_rate_limit_error_ , reset_time_ms_ = check_rate_limit_openai (err )
182+ if has_rate_limit_error_ :
183+ logger .warning ("Rate limit detected in stream. Disabling key." )
184+ await key_manager .disable_key (
185+ api_key , reset_time_ms_
186+ )
187+
184188
185189 # Return a streaming response
186190 return StreamingResponse (
@@ -199,29 +203,33 @@ async def stream_response() -> AsyncGenerator[bytes, None]:
199203 ** completion_args , extra_headers = forward_headers , extra_body = extra_body
200204 )
201205
206+ result = response .model_dump ()
207+ if 'error' in result :
208+ raise APIError (result ['error' ].get ("message" , "Error" ), None , body = result ['error' ])
209+
202210 # Return the response as JSON
203211 return Response (
204- content = json .dumps (response . model_dump () ), media_type = "application/json"
212+ content = json .dumps (result ), media_type = "application/json"
205213 )
206- except Exception as e :
214+ except ( APIError , Exception ) as e :
207215 logger .error ("Error in chat completions: %s" , str (e ))
208216 # Check if this is a rate limit error
209- if "rate limit" in str ( e ). lower () and api_key :
210- logger . warning (
211- "Rate limit reached for API key. Disabling key and retrying."
212- )
213- await key_manager .disable_key (api_key , None )
214-
215- # Try again with a new key
216- new_api_key = await key_manager .get_next_key ()
217- if new_api_key :
218- new_client = await get_openai_client (new_api_key )
219- return await handle_chat_completions (
220- new_client , request , request_body , new_api_key , is_stream
221- )
217+ if api_key and isinstance ( e , APIError ) :
218+ has_rate_limit_error , reset_time_ms = check_rate_limit_openai ( e )
219+ if has_rate_limit_error :
220+ logger . warning ( "Rate limit detected in stream. Disabling key." )
221+ await key_manager .disable_key (api_key , reset_time_ms )
222+
223+ # Try again with a new key
224+ new_api_key = await key_manager .get_next_key ()
225+ if new_api_key :
226+ new_client = await get_openai_client (new_api_key )
227+ return await handle_chat_completions (
228+ new_client , request , request_body , new_api_key , is_stream
229+ )
222230
223231 # Raise the exception
224- raise HTTPException (500 , f"Error processing chat completion: { str (e )} " )
232+ raise HTTPException (500 , f"Error processing chat completion: { str (e )} " ) from e
225233
226234
227235async def proxy_with_httpx (
@@ -311,9 +319,7 @@ async def proxy_with_httpx(
311319 status_code = 503 ,
312320 media_type = "application/json" ,
313321 )
314- raise HTTPException (
315- status_code = 503 , detail = "Unable to connect to OpenRouter API"
316- )
322+ raise HTTPException (503 , "Unable to connect to OpenRouter API" ) from e
317323
318324 # Handle binary responses
319325 if is_binary :
@@ -387,17 +393,13 @@ async def stream_sse():
387393
388394 except httpx .ConnectError as e :
389395 logger .error ("Connection error to OpenRouter: %s" , str (e ))
390- raise HTTPException (
391- status_code = 503 , detail = "Unable to connect to OpenRouter API"
392- )
396+ raise HTTPException (503 , "Unable to connect to OpenRouter API" ) from e
393397 except httpx .TimeoutException as e :
394398 logger .error ("Timeout connecting to OpenRouter: %s" , str (e ))
395- raise HTTPException (
396- status_code = 504 , detail = "OpenRouter API request timed out"
397- )
399+ raise HTTPException (504 , "OpenRouter API request timed out" ) from e
398400 except Exception as e :
399401 logger .error ("Error proxying request with httpx: %s" , str (e ))
400- raise HTTPException (status_code = 500 , detail = f"Proxy error: { str (e )} " )
402+ raise HTTPException (500 , f"Proxy error: { str (e )} " ) from e
401403
402404
403405@router .get ("/health" )
0 commit comments