AIMaster7 commited on
Commit
343e32f
Β·
verified Β·
1 Parent(s): e8cfe71

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +31 -55
main.py CHANGED
@@ -13,13 +13,7 @@ import importlib
13
  from fastapi import FastAPI, Request, HTTPException
14
  from fastapi.middleware.cors import CORSMiddleware
15
  from fastapi.responses import StreamingResponse
16
- from tenacity import (
17
- retry,
18
- stop_after_attempt,
19
- wait_exponential,
20
- retry_if_exception_type,
21
- RetryError,
22
- )
23
 
24
  # ─── Logging ───
25
  logging.basicConfig(
@@ -70,17 +64,10 @@ app.add_middleware(
70
  )
71
 
72
  HTTP_SESSION: aiohttp.ClientSession = None
73
-
74
- class RetryableStatusError(Exception):
75
- def __init__(self, status: int, text: str):
76
- self.status = status
77
- self.text = text
78
- super().__init__(f"status={status} body={text[:100]}...")
79
-
80
  RETRYABLE_STATUSES = {400, 429, 500, 502, 503, 504}
81
-
82
  _ascii = string.ascii_letters + string.digits
83
 
 
84
  def _rand(n, pool=_ascii): return "".join(random.choice(pool) for _ in range(n))
85
  def random_email(): return _rand(12) + "@gmail.com"
86
  def random_id(): return _rand(21, string.digits)
@@ -146,12 +133,14 @@ def build_payload(messages: List[Dict[str, Any]]) -> Dict[str, Any]:
146
  "designerMode": False
147
  }
148
 
149
- # ─── Retry Logic ───
 
 
 
 
150
  def log_retry(retry_state):
151
  rid = retry_state.kwargs.get("request_id", "unknown")
152
- attempt = retry_state.attempt_number
153
- err = retry_state.outcome.exception()
154
- logger.warning("[%s] retry %s/3 due to %s", rid, attempt, err)
155
 
156
  @retry(
157
  stop=stop_after_attempt(3),
@@ -164,30 +153,23 @@ def log_retry(retry_state):
164
  async def get_blackbox_response(*, data, stream: bool, request_id: str) -> AsyncGenerator[str, None]:
165
  global HTTP_SESSION
166
  if not HTTP_SESSION:
167
- try:
168
- importlib.import_module("brotli")
169
- except ImportError:
170
- logger.error("Missing Brotli module. Install with: pip install brotli")
171
- raise HTTPException(status_code=502, detail="Missing Brotli module on server")
172
  HTTP_SESSION = aiohttp.ClientSession(timeout=aiohttp.ClientTimeout(total=REQUEST_TIMEOUT))
173
 
174
- try:
175
- async with HTTP_SESSION.post(BLACKBOX_URL, json=data, headers=HEADERS, timeout=REQUEST_TIMEOUT) as resp:
176
- if resp.status != 200:
177
- body = await resp.text()
178
- logger.error("[%s] Upstream %s error: %s", request_id, BLACKBOX_URL, resp.status)
179
- if resp.status in RETRYABLE_STATUSES:
180
- raise RetryableStatusError(resp.status, body)
181
- raise HTTPException(status_code=502, detail=f"Upstream error {resp.status}")
182
- if stream:
183
- async for chunk in resp.content.iter_any():
184
- if chunk:
185
- yield chunk.decode("utf-8", "ignore")
186
- else:
187
- yield await resp.text()
188
- except Exception as e:
189
- logger.exception("[%s] Unexpected upstream error", request_id)
190
- raise HTTPException(status_code=502, detail="Failed to contact upstream") from e
191
 
192
  # ─── Middleware ───
193
  @app.middleware("http")
@@ -231,13 +213,11 @@ async def chat_completions(request: Request):
231
  "object": "chat.completion",
232
  "created": int(time.time()),
233
  "model": "DeepResearch",
234
- "choices": [
235
- {
236
- "index": 0,
237
- "message": {"role": "assistant", "content": answer},
238
- "finish_reason": "stop",
239
- }
240
- ],
241
  }
242
 
243
  async def event_stream():
@@ -249,12 +229,8 @@ async def chat_completions(request: Request):
249
  "model": "DeepResearch",
250
  "choices": [{"index": 0, "delta": {"content": chunk}}],
251
  }
252
- yield f"data: {json.dumps(msg)}
253
-
254
- "
255
- yield "data: [DONE]
256
-
257
- "
258
 
259
  return StreamingResponse(event_stream(), media_type="text/event-stream")
260
 
@@ -265,4 +241,4 @@ async def chat_completions(request: Request):
265
  raise HTTPException(status_code=502, detail="Blackbox upstream failed")
266
  except Exception as e:
267
  logger.exception("[%s] error", rid)
268
- raise HTTPException(status_code=500, detail="Internal proxy error")
 
13
  from fastapi import FastAPI, Request, HTTPException
14
  from fastapi.middleware.cors import CORSMiddleware
15
  from fastapi.responses import StreamingResponse
16
+ from tenacity import retry, stop_after_attempt, wait_exponential, retry_if_exception_type, RetryError
 
 
 
 
 
 
17
 
18
  # ─── Logging ───
19
  logging.basicConfig(
 
64
  )
65
 
66
  HTTP_SESSION: aiohttp.ClientSession = None
 
 
 
 
 
 
 
67
  RETRYABLE_STATUSES = {400, 429, 500, 502, 503, 504}
 
68
  _ascii = string.ascii_letters + string.digits
69
 
70
+ # ─── Utility ───
71
  def _rand(n, pool=_ascii): return "".join(random.choice(pool) for _ in range(n))
72
  def random_email(): return _rand(12) + "@gmail.com"
73
  def random_id(): return _rand(21, string.digits)
 
133
  "designerMode": False
134
  }
135
 
136
+ # ─── Retry ───
137
+ class RetryableStatusError(Exception):
138
+ def __init__(self, status: int, text: str):
139
+ super().__init__(f"status={status} body={text[:100]}...")
140
+
141
  def log_retry(retry_state):
142
  rid = retry_state.kwargs.get("request_id", "unknown")
143
+ logger.warning("[%s] retry %s/3 due to %s", rid, retry_state.attempt_number, retry_state.outcome.exception())
 
 
144
 
145
  @retry(
146
  stop=stop_after_attempt(3),
 
153
  async def get_blackbox_response(*, data, stream: bool, request_id: str) -> AsyncGenerator[str, None]:
154
  global HTTP_SESSION
155
  if not HTTP_SESSION:
156
+ importlib.import_module("brotli")
 
 
 
 
157
  HTTP_SESSION = aiohttp.ClientSession(timeout=aiohttp.ClientTimeout(total=REQUEST_TIMEOUT))
158
 
159
+ async with HTTP_SESSION.post(BLACKBOX_URL, json=data, headers=HEADERS, timeout=REQUEST_TIMEOUT) as resp:
160
+ if resp.status != 200:
161
+ body = await resp.text()
162
+ logger.error("[%s] Upstream %s error: %s", request_id, BLACKBOX_URL, resp.status)
163
+ if resp.status in RETRYABLE_STATUSES:
164
+ raise RetryableStatusError(resp.status, body)
165
+ raise HTTPException(status_code=502, detail=f"Upstream error {resp.status}")
166
+
167
+ if stream:
168
+ async for chunk in resp.content.iter_any():
169
+ if chunk:
170
+ yield chunk.decode("utf-8", "ignore")
171
+ else:
172
+ yield await resp.text()
 
 
 
173
 
174
  # ─── Middleware ───
175
  @app.middleware("http")
 
213
  "object": "chat.completion",
214
  "created": int(time.time()),
215
  "model": "DeepResearch",
216
+ "choices": [{
217
+ "index": 0,
218
+ "message": {"role": "assistant", "content": answer},
219
+ "finish_reason": "stop",
220
+ }],
 
 
221
  }
222
 
223
  async def event_stream():
 
229
  "model": "DeepResearch",
230
  "choices": [{"index": 0, "delta": {"content": chunk}}],
231
  }
232
+ yield f"data: {json.dumps(msg)}\n\n"
233
+ yield "data: [DONE]\n\n"
 
 
 
 
234
 
235
  return StreamingResponse(event_stream(), media_type="text/event-stream")
236
 
 
241
  raise HTTPException(status_code=502, detail="Blackbox upstream failed")
242
  except Exception as e:
243
  logger.exception("[%s] error", rid)
244
+ raise HTTPException(status_code=500, detail="Internal proxy error")