Niansuh commited on
Commit
45fecec
·
verified ·
1 Parent(s): 284013e

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +16 -118
main.py CHANGED
@@ -39,6 +39,22 @@ rate_limit_store = defaultdict(lambda: {"count": 0, "timestamp": time.time()})
39
  CLEANUP_INTERVAL = 60 # seconds
40
  RATE_LIMIT_WINDOW = 60 # seconds
41
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
42
  class Blackbox:
43
  label = "Blackbox AI"
44
  url = "https://www.blackbox.ai"
@@ -327,121 +343,3 @@ class Blackbox:
327
  error_text = f"Error {e.status}: {e.message}"
328
  try:
329
  error_response = await e.response.text()
330
- cleaned_error = cls.clean_response(error_response)
331
- error_text += f" - {cleaned_error}"
332
- except Exception:
333
- pass
334
- raise HTTPException(status_code=e.status, detail=error_text)
335
- except Exception as e:
336
- raise HTTPException(status_code=500, detail=f"Unexpected error during /api/chat request: {str(e)}")
337
-
338
- # FastAPI app setup
339
- app = FastAPI()
340
-
341
- # Add the cleanup task when the app starts
342
- @app.on_event("startup")
343
- async def startup_event():
344
- asyncio.create_task(cleanup_rate_limit_stores())
345
- logger.info("Started rate limit store cleanup task.")
346
-
347
- # Middleware to enhance security and enforce Content-Type for specific endpoints
348
- @app.middleware("http")
349
- async def security_middleware(request: Request, call_next):
350
- client_ip = request.client.host
351
- # Enforce that POST requests to /v1/chat/completions must have Content-Type: application/json
352
- if request.method == "POST" and request.url.path == "/v1/chat/completions":
353
- content_type = request.headers.get("Content-Type")
354
- if content_type != "application/json":
355
- logger.warning(f"Invalid Content-Type from IP: {client_ip} for path: {request.url.path}")
356
- return JSONResponse(
357
- status_code=400,
358
- content={
359
- "error": {
360
- "message": "Content-Type must be application/json",
361
- "type": "invalid_request_error",
362
- "param": None,
363
- "code": None
364
- }
365
- },
366
- )
367
- response = await call_next(request)
368
- return response
369
-
370
- # Request Models
371
- class Message(BaseModel):
372
- role: str
373
- content: str
374
-
375
- class ChatRequest(BaseModel):
376
- model: str
377
- messages: List[Message]
378
- temperature: Optional[float] = 1.0
379
- top_p: Optional[float] = 1.0
380
- n: Optional[int] = 1
381
- max_tokens: Optional[int] = None
382
- presence_penalty: Optional[float] = 0.0
383
- frequency_penalty: Optional[float] = 0.0
384
- logit_bias: Optional[Dict[str, float]] = None
385
- user: Optional[str] = None
386
-
387
- @app.post("/v1/chat/completions", dependencies=[Depends(rate_limiter_per_ip)])
388
- async def chat_completions(request: ChatRequest, req: Request, api_key: str = Depends(get_api_key)):
389
- client_ip = req.client.host
390
- # Redact user messages only for logging purposes
391
- redacted_messages = [{"role": msg.role, "content": "[redacted]"} for msg in request.messages]
392
-
393
- logger.info(f"Received chat completions request from API key: {api_key} | IP: {client_ip} | Model: {request.model} | Messages: {redacted_messages}")
394
-
395
- try:
396
- # Validate that the requested model is available
397
- if request.model not in Blackbox.models and request.model not in Blackbox.model_aliases:
398
- logger.warning(f"Attempt to use unavailable model: {request.model} from IP: {client_ip}")
399
- raise HTTPException(status_code=400, detail="Requested model is not available.")
400
-
401
- # Process the request with actual message content, but don't log it
402
- response_content = await Blackbox.generate_response(
403
- model=request.model,
404
- messages=[{"role": msg.role, "content": msg.content} for msg in request.messages],
405
- temperature=request.temperature,
406
- max_tokens=request.max_tokens
407
- )
408
-
409
- logger.info(f"Completed response generation for API key: {api_key} | IP: {client_ip}")
410
- return response_content
411
- except HTTPException as he:
412
- logger.warning(f"HTTPException: {he.detail} | IP: {client_ip}")
413
- raise he
414
- except Exception as e:
415
- logger.exception(f"An unexpected error occurred while processing the chat completions request from IP: {client_ip}.")
416
- raise HTTPException(status_code=500, detail=str(e))
417
-
418
- # Endpoint: GET /v1/models
419
- @app.get("/v1/models", dependencies=[Depends(rate_limiter_per_ip)])
420
- async def get_models(req: Request):
421
- client_ip = req.client.host
422
- logger.info(f"Fetching available models from IP: {client_ip}")
423
- return {"data": [{"id": model, "object": "model"} for model in Blackbox.models]}
424
-
425
- # Endpoint: GET /v1/health
426
- @app.get("/v1/health", dependencies=[Depends(rate_limiter_per_ip)])
427
- async def health_check(req: Request):
428
- client_ip = req.client.host
429
- logger.info(f"Health check requested from IP: {client_ip}")
430
- return {"status": "ok"}
431
-
432
- # Custom exception handler to match OpenAI's error format
433
- @app.exception_handler(HTTPException)
434
- async def http_exception_handler(request: Request, exc: HTTPException):
435
- client_ip = request.client.host
436
- logger.error(f"HTTPException: {exc.detail} | Path: {request.url.path} | IP: {client_ip}")
437
- return JSONResponse(
438
- status_code=exc.status_code,
439
- content={
440
- "error": {
441
- "message": exc.detail,
442
- "type": "invalid_request_error",
443
- "param": None,
444
- "code": None
445
- }
446
- },
447
- )
 
39
  CLEANUP_INTERVAL = 60 # seconds
40
  RATE_LIMIT_WINDOW = 60 # seconds
41
 
42
+ async def rate_limiter_per_ip(request: Request):
43
+ """
44
+ Rate limiter that enforces a limit based on the client's IP address.
45
+ """
46
+ client_ip = request.client.host
47
+ current_time = time.time()
48
+
49
+ # Initialize or update the count and timestamp
50
+ if current_time - rate_limit_store[client_ip]["timestamp"] > RATE_LIMIT_WINDOW:
51
+ rate_limit_store[client_ip] = {"count": 1, "timestamp": current_time}
52
+ else:
53
+ if rate_limit_store[client_ip]["count"] >= RATE_LIMIT:
54
+ logger.warning(f"Rate limit exceeded for IP address: {client_ip}")
55
+ raise HTTPException(status_code=429, detail='Rate limit exceeded for IP address')
56
+ rate_limit_store[client_ip]["count"] += 1
57
+
58
  class Blackbox:
59
  label = "Blackbox AI"
60
  url = "https://www.blackbox.ai"
 
343
  error_text = f"Error {e.status}: {e.message}"
344
  try:
345
  error_response = await e.response.text()