justadri23 commited on
Commit
e4aaef9
·
verified ·
1 Parent(s): e8f972d

Upload 27 files

Browse files
Files changed (3) hide show
  1. app.py +53 -9
  2. utils/proxy.py +13 -5
  3. utils/requesty_proxy.py +76 -7
app.py CHANGED
@@ -104,15 +104,55 @@ def chat_completions():
104
  # Pass special token flag to proxy manager for unlimited processing
105
  response = proxy_manager.forward_request(data, token_data['api_key'], is_special_token)
106
 
107
- # Check if request was rejected due to token limits (only for regular tokens)
108
- if not is_special_token and response.status_code == 400:
109
  try:
 
110
  error_data = response.json()
111
- if error_data.get('error', {}).get('type') == 'token_limit_exceeded':
112
- return jsonify(error_data), 400
113
- except:
114
- pass
115
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
116
  if response.status_code == 200:
117
  # Update token usage only for regular tokens and if not from cache
118
  if not is_special_token:
@@ -120,11 +160,15 @@ def chat_completions():
120
  if cache_status != 'HIT':
121
  storage.update_token_usage(token_data['id'], model_cost, model)
122
 
123
- # Return response
124
  if data.get('stream', False):
125
  return response.iter_content(chunk_size=1024), response.status_code, dict(response.headers)
126
  else:
127
- return response.json(), response.status_code
 
 
 
 
128
 
129
  except Exception as e:
130
  return jsonify({"error": {"message": str(e), "type": "internal_error"}}), 500
 
104
  # Pass special token flag to proxy manager for unlimited processing
105
  response = proxy_manager.forward_request(data, token_data['api_key'], is_special_token)
106
 
107
+ # Handle all error responses with detailed error information
108
+ if response.status_code != 200:
109
  try:
110
+ # Try to get detailed error information from the response
111
  error_data = response.json()
112
+
113
+ # Enhance error with provider and context information
114
+ enhanced_error = {
115
+ "error": {
116
+ "message": error_data.get('error', {}).get('message', f"HTTP {response.status_code} error from {proxy_manager.current_provider}"),
117
+ "type": error_data.get('error', {}).get('type', 'api_error'),
118
+ "code": response.status_code,
119
+ "provider": proxy_manager.current_provider,
120
+ "model": model
121
+ }
122
+ }
123
+
124
+ # Include original error details if available
125
+ if 'error' in error_data and isinstance(error_data['error'], dict):
126
+ original_error = error_data['error']
127
+ if 'details' in original_error:
128
+ enhanced_error['error']['details'] = original_error['details']
129
+ if 'param' in original_error:
130
+ enhanced_error['error']['param'] = original_error['param']
131
+ if 'code' in original_error:
132
+ enhanced_error['error']['original_code'] = original_error['code']
133
+
134
+ return jsonify(enhanced_error), response.status_code
135
+
136
+ except (ValueError, KeyError) as e:
137
+ # If response is not valid JSON or missing expected fields
138
+ try:
139
+ response_text = response.text
140
+ except:
141
+ response_text = "Unable to read response content"
142
+
143
+ enhanced_error = {
144
+ "error": {
145
+ "message": f"HTTP {response.status_code} error from {proxy_manager.current_provider}: {response_text[:200]}",
146
+ "type": "api_error",
147
+ "code": response.status_code,
148
+ "provider": proxy_manager.current_provider,
149
+ "model": model,
150
+ "details": f"Response parsing error: {str(e)}"
151
+ }
152
+ }
153
+ return jsonify(enhanced_error), response.status_code
154
+
155
+ # Handle successful responses
156
  if response.status_code == 200:
157
  # Update token usage only for regular tokens and if not from cache
158
  if not is_special_token:
 
160
  if cache_status != 'HIT':
161
  storage.update_token_usage(token_data['id'], model_cost, model)
162
 
163
+ # Return successful response
164
  if data.get('stream', False):
165
  return response.iter_content(chunk_size=1024), response.status_code, dict(response.headers)
166
  else:
167
+ try:
168
+ return response.json(), response.status_code
169
+ except ValueError:
170
+ # If successful response is not JSON, return as text
171
+ return {"message": response.text, "status": "success"}, response.status_code
172
 
173
  except Exception as e:
174
  return jsonify({"error": {"message": str(e), "type": "internal_error"}}), 500
utils/proxy.py CHANGED
@@ -94,7 +94,8 @@ class OpenRouterProxy:
94
  return self._create_error_response(
95
  500,
96
  "connection_error",
97
- f"Failed to connect to OpenRouter: {str(e)}"
 
98
  )
99
 
100
  def _prepare_optimized_headers(self, api_key: str, cache_key: str) -> Dict[str, str]:
@@ -116,17 +117,24 @@ class OpenRouterProxy:
116
  headers.update(cache_headers)
117
  return headers
118
 
119
- def _create_error_response(self, status_code: int, error_type: str, message: str) -> requests.Response:
120
- """Crea una respuesta de error mock"""
121
  mock_response = requests.Response()
122
  mock_response.status_code = status_code
123
- mock_response._content = json.dumps({
 
124
  "error": {
125
  "message": message,
126
  "type": error_type,
127
  "code": status_code
128
  }
129
- }).encode('utf-8')
 
 
 
 
 
 
130
  mock_response.headers['Content-Type'] = 'application/json'
131
  return mock_response
132
 
 
94
  return self._create_error_response(
95
  500,
96
  "connection_error",
97
+ f"Failed to connect to OpenRouter: {str(e)}",
98
+ {"provider": "openrouter", "model": model}
99
  )
100
 
101
  def _prepare_optimized_headers(self, api_key: str, cache_key: str) -> Dict[str, str]:
 
117
  headers.update(cache_headers)
118
  return headers
119
 
120
+ def _create_error_response(self, status_code: int, error_type: str, message: str, context: Dict = None) -> requests.Response:
121
+ """Crea una respuesta de error mock con contexto adicional"""
122
  mock_response = requests.Response()
123
  mock_response.status_code = status_code
124
+
125
+ error_data = {
126
  "error": {
127
  "message": message,
128
  "type": error_type,
129
  "code": status_code
130
  }
131
+ }
132
+
133
+ # Add context information if provided
134
+ if context:
135
+ error_data["error"].update(context)
136
+
137
+ mock_response._content = json.dumps(error_data).encode('utf-8')
138
  mock_response.headers['Content-Type'] = 'application/json'
139
  return mock_response
140
 
utils/requesty_proxy.py CHANGED
@@ -364,8 +364,21 @@ class RequestyProxy:
364
  try:
365
  error_data = response.json()
366
  last_error = error_data.get('error', {}).get('message', f'HTTP {response.status_code}')
 
 
 
 
 
 
 
367
  except:
368
  last_error = f'HTTP {response.status_code} - API key authentication failed'
 
 
 
 
 
 
369
 
370
  logger.warning(f"Requesty API key failed with {response.status_code}, trying next key...")
371
  continue
@@ -378,15 +391,53 @@ class RequestyProxy:
378
  try:
379
  error_data = response.json()
380
  last_error = error_data.get('error', {}).get('message', f'HTTP {response.status_code}')
 
 
 
 
 
 
 
381
  except:
382
  last_error = f'HTTP {response.status_code} - Server error'
 
 
 
 
 
 
383
 
384
  logger.warning(f"Requesty server error {response.status_code}, trying next key...")
385
  continue
386
 
387
  else:
388
- # Other HTTP errors (4xx client errors) - don't retry, return immediately
389
  logger.warning(f"Requesty client error {response.status_code}, not retrying")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
390
  return response
391
 
392
  except requests.exceptions.RequestException as e:
@@ -400,10 +451,20 @@ class RequestyProxy:
400
 
401
  # If we get here, all keys failed
402
  logger.error(f"All Requesty API keys failed after {attempts} attempts")
 
 
 
 
 
 
 
 
 
403
  return self._create_error_response(
404
  500,
405
  "all_keys_failed",
406
- f"All API keys are currently unavailable. Last error: {last_error}"
 
407
  )
408
 
409
  def _add_requesty_optimizations(self, data: Dict[Any, Any], bypass_limitations: bool = False) -> Dict[Any, Any]:
@@ -440,17 +501,25 @@ class RequestyProxy:
440
 
441
  return headers
442
 
443
- def _create_error_response(self, status_code: int, error_type: str, message: str) -> requests.Response:
444
- """Create a mock error response"""
445
  mock_response = requests.Response()
446
  mock_response.status_code = status_code
447
- mock_response._content = json.dumps({
 
448
  "error": {
449
  "message": message,
450
  "type": error_type,
451
- "code": status_code
 
452
  }
453
- }).encode('utf-8')
 
 
 
 
 
 
454
  mock_response.headers['Content-Type'] = 'application/json'
455
  return mock_response
456
 
 
364
  try:
365
  error_data = response.json()
366
  last_error = error_data.get('error', {}).get('message', f'HTTP {response.status_code}')
367
+ # Store detailed error for final response
368
+ error_details = {
369
+ "status_code": response.status_code,
370
+ "response_body": error_data,
371
+ "headers": dict(response.headers),
372
+ "url": url
373
+ }
374
  except:
375
  last_error = f'HTTP {response.status_code} - API key authentication failed'
376
+ error_details = {
377
+ "status_code": response.status_code,
378
+ "response_body": response.text,
379
+ "headers": dict(response.headers),
380
+ "url": url
381
+ }
382
 
383
  logger.warning(f"Requesty API key failed with {response.status_code}, trying next key...")
384
  continue
 
391
  try:
392
  error_data = response.json()
393
  last_error = error_data.get('error', {}).get('message', f'HTTP {response.status_code}')
394
+ # Store detailed error for final response
395
+ error_details = {
396
+ "status_code": response.status_code,
397
+ "response_body": error_data,
398
+ "headers": dict(response.headers),
399
+ "url": url
400
+ }
401
  except:
402
  last_error = f'HTTP {response.status_code} - Server error'
403
+ error_details = {
404
+ "status_code": response.status_code,
405
+ "response_body": response.text,
406
+ "headers": dict(response.headers),
407
+ "url": url
408
+ }
409
 
410
  logger.warning(f"Requesty server error {response.status_code}, trying next key...")
411
  continue
412
 
413
  else:
414
+ # Other HTTP errors (4xx client errors) - don't retry, return with detailed error
415
  logger.warning(f"Requesty client error {response.status_code}, not retrying")
416
+
417
+ try:
418
+ error_data = response.json()
419
+ # Enhance the response with additional context
420
+ if 'error' in error_data:
421
+ error_data['error']['provider'] = 'requesty'
422
+ error_data['error']['url'] = url
423
+ error_data['error']['headers'] = dict(response.headers)
424
+
425
+ # Update response content with enhanced error data
426
+ response._content = json.dumps(error_data).encode('utf-8')
427
+ except:
428
+ # If we can't parse JSON, create our own error response
429
+ return self._create_error_response(
430
+ response.status_code,
431
+ "client_error",
432
+ f"HTTP {response.status_code}: {response.text}",
433
+ {
434
+ "original_status_code": response.status_code,
435
+ "response_body": response.text,
436
+ "headers": dict(response.headers),
437
+ "url": url
438
+ }
439
+ )
440
+
441
  return response
442
 
443
  except requests.exceptions.RequestException as e:
 
451
 
452
  # If we get here, all keys failed
453
  logger.error(f"All Requesty API keys failed after {attempts} attempts")
454
+
455
+ # Include detailed error information if available
456
+ error_context = {
457
+ "attempts_made": attempts,
458
+ "max_attempts": max_attempts,
459
+ "active_keys_count": len(self.key_rotator.active_keys),
460
+ "last_error_details": locals().get('error_details', None)
461
+ }
462
+
463
  return self._create_error_response(
464
  500,
465
  "all_keys_failed",
466
+ f"All API keys are currently unavailable. Last error: {last_error}",
467
+ error_context
468
  )
469
 
470
  def _add_requesty_optimizations(self, data: Dict[Any, Any], bypass_limitations: bool = False) -> Dict[Any, Any]:
 
501
 
502
  return headers
503
 
504
+ def _create_error_response(self, status_code: int, error_type: str, message: str, context: Dict = None) -> requests.Response:
505
+ """Create a mock error response with additional context"""
506
  mock_response = requests.Response()
507
  mock_response.status_code = status_code
508
+
509
+ error_data = {
510
  "error": {
511
  "message": message,
512
  "type": error_type,
513
+ "code": status_code,
514
+ "provider": "requesty"
515
  }
516
+ }
517
+
518
+ # Add context information if provided
519
+ if context:
520
+ error_data["error"].update(context)
521
+
522
+ mock_response._content = json.dumps(error_data).encode('utf-8')
523
  mock_response.headers['Content-Type'] = 'application/json'
524
  return mock_response
525