FUCAT's picture
Deploy grok2api to HF Spaces (Docker)
7e55e53
Raw
History Blame Contribute Delete
8.77 kB
"""HTTP transport for reverse-proxy requests.
Wraps curl_cffi AsyncSession; handles proxy selection, header building,
retry-on-reset, and timeout.
"""
from typing import AsyncGenerator
from app.platform.logging.logger import logger
from app.platform.errors import UpstreamError
from app.control.proxy.models import ProxyLease
from app.dataplane.proxy.adapters.headers import build_http_headers
from app.dataplane.proxy.adapters.session import ResettableSession, build_session_kwargs
async def post_stream(
url: str,
token: str,
payload: bytes,
*,
lease: ProxyLease | None = None,
timeout_s: float = 120.0,
content_type: str = "application/json",
origin: str = "https://grok.com",
referer: str = "https://grok.com/",
) -> AsyncGenerator[str, None]:
"""POST *url* and yield SSE lines from the streaming response.
Raises ``UpstreamError`` on non-200 status.
"""
headers = build_http_headers(
token,
content_type=content_type,
origin=origin,
referer=referer,
lease=lease,
)
kwargs = build_session_kwargs(lease=lease)
session = ResettableSession(**kwargs)
try:
response = await session.post(
url,
headers=headers,
data=payload,
timeout=timeout_s,
stream=True,
)
if response.status_code != 200:
try:
body = (response.content).decode("utf-8", "replace")[:400]
except Exception:
body = ""
logger.error(
"http stream post failed: url={} status={} body={}",
url,
response.status_code,
body,
)
await session.close()
raise UpstreamError(
f"Upstream returned {response.status_code}",
status=response.status_code,
body=body,
)
except Exception:
try:
await session.close()
except Exception:
pass
raise
async def _lines() -> AsyncGenerator[str, None]:
try:
async for line in response.aiter_lines():
yield line
finally:
try:
await session.close()
except Exception:
pass
return _lines()
async def post_json(
url: str,
token: str,
payload: bytes,
*,
lease: ProxyLease | None = None,
timeout_s: float = 30.0,
content_type: str = "application/json",
origin: str = "https://grok.com",
referer: str = "https://grok.com/",
session: "ResettableSession | None" = None,
) -> dict:
"""POST *url* and return parsed JSON response body.
Pass *session* to reuse an existing connection (avoids a new TLS handshake).
When *session* is ``None`` a fresh session is created and closed automatically.
"""
headers = build_http_headers(
token, content_type=content_type, origin=origin, referer=referer, lease=lease
)
import orjson
async def _do(s: "ResettableSession") -> dict:
response = await s.post(url, headers=headers, data=payload, timeout=timeout_s)
body_bytes = response.content
if response.status_code not in (200, 201, 204):
body_text = body_bytes.decode("utf-8", "replace")[:400]
logger.warning(
"http json post failed: url={} status={}", url, response.status_code
)
raise UpstreamError(
f"Upstream returned {response.status_code}",
status=response.status_code,
body=body_text,
)
return orjson.loads(body_bytes) if body_bytes.strip() else {}
if session is not None:
return await _do(session)
async with ResettableSession(**build_session_kwargs(lease=lease)) as s:
return await _do(s)
async def get_json(
url: str,
token: str,
*,
params: dict | None = None,
lease: ProxyLease | None = None,
timeout_s: float = 30.0,
origin: str = "https://grok.com",
referer: str = "https://grok.com/",
) -> dict:
"""GET *url* and return parsed JSON response body."""
headers = build_http_headers(
token,
content_type="application/json",
origin=origin,
referer=referer,
lease=lease,
)
kwargs = build_session_kwargs(lease=lease)
async with ResettableSession(**kwargs) as session:
response = await session.get(
url,
headers=headers,
params=params,
timeout=timeout_s,
)
body_bytes = response.content
if response.status_code != 200:
body_text = body_bytes.decode("utf-8", "replace")[:400]
logger.error(
"http json get failed: url={} status={} body={}",
url,
response.status_code,
body_text,
)
raise UpstreamError(
f"Upstream returned {response.status_code}",
status=response.status_code,
body=body_text,
)
import orjson
return orjson.loads(body_bytes)
async def delete_json(
url: str,
token: str,
*,
lease: ProxyLease | None = None,
timeout_s: float = 30.0,
origin: str = "https://grok.com",
referer: str = "https://grok.com/",
) -> dict:
"""DELETE *url* and return parsed JSON response body (may be empty → {})."""
headers = build_http_headers(
token,
content_type="application/json",
origin=origin,
referer=referer,
lease=lease,
)
kwargs = build_session_kwargs(lease=lease)
async with ResettableSession(**kwargs) as session:
response = await session.delete(
url,
headers=headers,
timeout=timeout_s,
)
body_bytes = response.content
if response.status_code not in (200, 204):
body_text = body_bytes.decode("utf-8", "replace")[:400]
logger.error(
"http json delete failed: url={} status={} body={}",
url,
response.status_code,
body_text,
)
raise UpstreamError(
f"Upstream returned {response.status_code}",
status=response.status_code,
body=body_text,
)
if not body_bytes.strip():
return {}
import orjson
return orjson.loads(body_bytes)
async def get_bytes_stream(
url: str,
token: str,
*,
lease: ProxyLease | None = None,
timeout_s: float = 120.0,
origin: str = "https://assets.grok.com",
referer: str = "https://grok.com/",
extra_headers: dict | None = None,
) -> AsyncGenerator[bytes, None]:
"""GET *url* and yield raw bytes chunks from the streaming response.
Raises ``UpstreamError`` on non-200 status.
"""
headers = build_http_headers(
token,
content_type=None,
origin=origin,
referer=referer,
lease=lease,
)
if extra_headers:
headers.update(extra_headers)
if headers.get("Sec-Fetch-Mode") == "navigate":
headers.pop("Content-Type", None)
headers.pop("Origin", None)
kwargs = build_session_kwargs(lease=lease)
session = ResettableSession(**kwargs)
try:
response = await session.get(
url,
headers=headers,
timeout=timeout_s,
stream=True,
allow_redirects=True,
)
if response.status_code != 200:
try:
body = (response.content).decode("utf-8", "replace")[:400]
except Exception:
body = ""
logger.error(
"http byte stream get failed: url={} status={} body={}",
url,
response.status_code,
body,
)
await session.close()
raise UpstreamError(
f"Upstream returned {response.status_code}",
status=response.status_code,
body=body,
)
except Exception:
try:
await session.close()
except Exception:
pass
raise
async def _chunks() -> AsyncGenerator[bytes, None]:
try:
async for chunk in response.aiter_content():
if chunk:
yield chunk
finally:
try:
await session.close()
except Exception:
pass
return _chunks()
__all__ = ["post_stream", "post_json", "get_json", "delete_json", "get_bytes_stream"]