Skip to content

Commit 39683d7

Browse files
committed
fix(routes): Fix httpx streaming and error handling
1 parent c17d2d8 commit 39683d7

File tree

1 file changed

+22
-31
lines changed

1 file changed

+22
-31
lines changed

routes.py

Lines changed: 22 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -61,12 +61,9 @@ async def get_openai_client(api_key: str, request: Request) -> AsyncOpenAI:
6161

6262

6363
async def check_httpx_err(body: str | bytes, api_key: str | None):
64-
# too big for error
65-
if len(body) > 4000 or not api_key:
64+
# too big or small for error
65+
if 10 > len(body) > 4000 or not api_key:
6666
return
67-
if (isinstance(body, str) and body.startswith("data: ") or (
68-
isinstance(body, bytes) and body.startswith(b"data: "))):
69-
body = body[6:]
7067
has_rate_limit_error, reset_time_ms = await check_rate_limit(body)
7168
if has_rate_limit_error:
7269
await key_manager.disable_key(api_key, reset_time_ms)
@@ -287,30 +284,28 @@ async def proxy_with_httpx(
287284
"""Fall back to httpx for endpoints not supported by the OpenAI SDK."""
288285
free_only = (any(f"/api/v1{path}" == ep for ep in MODELS_ENDPOINTS) and
289286
config["openrouter"]["free_only"])
290-
headers = prepare_forward_headers(request)
291287
req_kwargs = {
292288
"method": request.method,
293289
"url": f"{config['openrouter']['base_url']}{path}",
294-
"headers": headers,
290+
"headers": prepare_forward_headers(request),
295291
"content": await request.body(),
292+
"params": request.query_params,
296293
}
297-
# Add query parameters if they exist
298-
if request.query_params:
299-
req_kwargs["url"] = f"{req_kwargs['url']}?{request.url.query}"
300-
301294
if api_key:
302295
req_kwargs["headers"]["Authorization"] = f"Bearer {api_key}"
303296

304297
client = await get_async_client(request)
305298
try:
306-
openrouter_resp = await client.request(**req_kwargs)
299+
openrouter_req = client.build_request(**req_kwargs)
300+
openrouter_resp = await client.send(openrouter_req, stream=is_stream)
301+
307302
headers = dict(openrouter_resp.headers)
308303
# Content has already been decoded
309304
headers.pop("content-encoding", None)
310305
headers.pop("Content-Encoding", None)
311306

312307
if not is_stream:
313-
body = await openrouter_resp.aread()
308+
body = openrouter_resp.content
314309
await check_httpx_err(body, api_key)
315310
if free_only:
316311
body = remove_paid_models(body)
@@ -319,30 +314,26 @@ async def proxy_with_httpx(
319314
status_code=openrouter_resp.status_code,
320315
headers=headers,
321316
)
322-
if not api_key and not is_completion:
323-
return StreamingResponse(
324-
openrouter_resp.aiter_bytes(),
325-
status_code=openrouter_resp.status_code,
326-
headers=headers,
327-
)
328317

329318
async def stream_completion():
330-
data = ''
319+
if not (api_key or is_completion):
320+
try:
321+
async for chunk in openrouter_resp.aiter_bytes():
322+
yield chunk
323+
finally:
324+
await openrouter_resp.aclose()
325+
return
326+
last_json = ""
331327
try:
332328
async for line in openrouter_resp.aiter_lines():
333-
if line.startswith("data: "):
334-
data = line[6:] # Get data without 'data: ' prefix
335-
if data == "[DONE]":
336-
yield "data: [DONE]\n\n".encode("utf-8")
337-
else:
338-
# Forward the original data without reformatting
339-
data = line
340-
yield f"{line}\n\n".encode("utf-8")
341-
elif line:
342-
yield f"{line}\n\n".encode("utf-8")
329+
if line.startswith("data: {"): # get json only
330+
last_json = line[6:]
331+
yield f"{line}\n\n".encode("utf-8")
343332
except Exception as err:
344333
logger.error("stream_completion error: %s", err)
345-
await check_httpx_err(data, api_key)
334+
finally:
335+
await openrouter_resp.aclose()
336+
await check_httpx_err(last_json, api_key)
346337

347338

348339
return StreamingResponse(

0 commit comments

Comments
 (0)