Spaces:
Running
Running
Wimmboo commited on
Commit ·
c6b6b9c
1
Parent(s): b1024aa
fix streaming: async generator keeps httpx client alive internally
Browse files- Dockerfile +1 -1
- proxy/client.py +15 -21
Dockerfile
CHANGED
|
@@ -12,4 +12,4 @@ RUN pip install --no-cache-dir --upgrade -r requirements.txt
|
|
| 12 |
COPY --chown=user . .
|
| 13 |
|
| 14 |
EXPOSE 7860
|
| 15 |
-
CMD uvicorn main:app --host 0.0.0.0 --port 7860
|
|
|
|
| 12 |
COPY --chown=user . .
|
| 13 |
|
| 14 |
EXPOSE 7860
|
| 15 |
+
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "7860"]
|
proxy/client.py
CHANGED
|
@@ -52,35 +52,29 @@ async def _poll_nvidia(client: httpx.AsyncClient, provider: Provider, request_id
|
|
| 52 |
raise HTTPException(status_code=504, detail=f"NVIDIA async job {request_id} timed out after polling")
|
| 53 |
|
| 54 |
|
| 55 |
-
async def
|
| 56 |
-
|
| 57 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 58 |
|
| 59 |
|
| 60 |
async def forward_request(provider: Provider, real_key: str, request: Request, body: dict[str, Any]) -> Any:
|
| 61 |
target_url = f"{provider.base_url}/v1/chat/completions"
|
| 62 |
headers = _build_headers(provider, real_key, dict(request.headers))
|
| 63 |
-
|
|
|
|
|
|
|
| 64 |
|
| 65 |
async with httpx.AsyncClient(timeout=_TIMEOUT, follow_redirects=True) as client:
|
| 66 |
try:
|
| 67 |
-
|
| 68 |
-
req = client.build_request("POST", target_url, headers=headers, json=body)
|
| 69 |
-
upstream = await client.send(req, stream=True)
|
| 70 |
-
|
| 71 |
-
if upstream.status_code >= 400:
|
| 72 |
-
content = await upstream.aread()
|
| 73 |
-
logger.warning("Upstream error from %s: %d %s", provider.name, upstream.status_code, content[:500])
|
| 74 |
-
raise HTTPException(status_code=upstream.status_code, detail=content.decode("utf-8", errors="replace"))
|
| 75 |
-
|
| 76 |
-
return StreamingResponse(
|
| 77 |
-
_stream_chunks(upstream),
|
| 78 |
-
status_code=upstream.status_code,
|
| 79 |
-
media_type=upstream.headers.get("content-type", "text/event-stream"),
|
| 80 |
-
headers={k: v for k, v in upstream.headers.items() if k.lower() in ("cache-control", "x-request-id")},
|
| 81 |
-
)
|
| 82 |
-
else:
|
| 83 |
-
upstream = await client.post(target_url, headers=headers, json=body)
|
| 84 |
except httpx.TimeoutException as exc:
|
| 85 |
logger.warning("Upstream timeout for %s: %s", provider.name, exc)
|
| 86 |
raise HTTPException(status_code=504, detail="Upstream provider timed out")
|
|
|
|
| 52 |
raise HTTPException(status_code=504, detail=f"NVIDIA async job {request_id} timed out after polling")
|
| 53 |
|
| 54 |
|
| 55 |
+
async def _stream_response(provider: Provider, real_key: str, body: dict[str, Any]) -> AsyncIterator[bytes]:
|
| 56 |
+
"""Async generator that manages its own httpx client for streaming."""
|
| 57 |
+
target_url = f"{provider.base_url}/v1/chat/completions"
|
| 58 |
+
headers = _build_headers(provider, real_key, {})
|
| 59 |
+
async with httpx.AsyncClient(timeout=_TIMEOUT, follow_redirects=True) as client:
|
| 60 |
+
async with client.stream("POST", target_url, headers=headers, json=body) as upstream:
|
| 61 |
+
if upstream.status_code >= 400:
|
| 62 |
+
content = await upstream.aread()
|
| 63 |
+
raise HTTPException(status_code=upstream.status_code, detail=content.decode("utf-8", errors="replace"))
|
| 64 |
+
async for chunk in upstream.aiter_raw():
|
| 65 |
+
yield chunk
|
| 66 |
|
| 67 |
|
| 68 |
async def forward_request(provider: Provider, real_key: str, request: Request, body: dict[str, Any]) -> Any:
|
| 69 |
target_url = f"{provider.base_url}/v1/chat/completions"
|
| 70 |
headers = _build_headers(provider, real_key, dict(request.headers))
|
| 71 |
+
|
| 72 |
+
if bool(body.get("stream")):
|
| 73 |
+
return StreamingResponse(_stream_response(provider, real_key, body), media_type="text/event-stream")
|
| 74 |
|
| 75 |
async with httpx.AsyncClient(timeout=_TIMEOUT, follow_redirects=True) as client:
|
| 76 |
try:
|
| 77 |
+
upstream = await client.post(target_url, headers=headers, json=body)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 78 |
except httpx.TimeoutException as exc:
|
| 79 |
logger.warning("Upstream timeout for %s: %s", provider.name, exc)
|
| 80 |
raise HTTPException(status_code=504, detail="Upstream provider timed out")
|