|
|
""" |
|
|
Utility decorators for error handling and timing |
|
|
""" |
|
|
import time |
|
|
from functools import wraps |
|
|
from typing import Callable, Any |
|
|
import groq |
|
|
from src.utils.logger import logger |
|
|
|
|
|
|
|
|
def handle_groq_errors(max_retries: int = 3, retry_delay: float = 1.0) -> Callable: |
|
|
""" |
|
|
π‘οΈ GROQ API ERROR HANDLER WITH EXPONENTIAL BACKOFF |
|
|
""" |
|
|
def decorator(func: Callable) -> Callable: |
|
|
@wraps(func) |
|
|
def wrapper(*args, **kwargs) -> Any: |
|
|
last_exception = None |
|
|
|
|
|
for attempt in range(max_retries): |
|
|
try: |
|
|
return func(*args, **kwargs) |
|
|
|
|
|
except groq.RateLimitError as e: |
|
|
last_exception = e |
|
|
wait_time = retry_delay * (2 ** attempt) |
|
|
logger.warning(f"β³ Rate limit hit. Waiting {wait_time:.1f}s... (Attempt {attempt + 1}/{max_retries})") |
|
|
time.sleep(wait_time) |
|
|
|
|
|
except groq.APIConnectionError as e: |
|
|
last_exception = e |
|
|
wait_time = retry_delay * (2 ** attempt) |
|
|
logger.warning(f"π Connection error. Retrying in {wait_time:.1f}s... (Attempt {attempt + 1}/{max_retries})") |
|
|
time.sleep(wait_time) |
|
|
|
|
|
except groq.AuthenticationError as e: |
|
|
logger.error(f"π Authentication failed: {e}") |
|
|
raise ValueError("Invalid GROQ_API_KEY. Please check your API key.") from e |
|
|
|
|
|
except groq.BadRequestError as e: |
|
|
logger.error(f"β Invalid request: {e}") |
|
|
raise ValueError(f"Invalid request parameters: {str(e)}") from e |
|
|
|
|
|
except Exception as e: |
|
|
last_exception = e |
|
|
logger.error(f"β Unexpected error: {e}", exc_info=True) |
|
|
if attempt == max_retries - 1: |
|
|
break |
|
|
time.sleep(retry_delay * (2 ** attempt)) |
|
|
|
|
|
error_msg = f"Failed after {max_retries} attempts: {str(last_exception)}" |
|
|
logger.error(error_msg) |
|
|
raise Exception(error_msg) from last_exception |
|
|
|
|
|
return wrapper |
|
|
return decorator |
|
|
|
|
|
|
|
|
def with_rate_limit(rate_limiter): |
|
|
""" |
|
|
β±οΈ RATE LIMITING DECORATOR |
|
|
""" |
|
|
def decorator(func: Callable) -> Callable: |
|
|
@wraps(func) |
|
|
def wrapper(*args, **kwargs) -> Any: |
|
|
rate_limiter.acquire() |
|
|
return func(*args, **kwargs) |
|
|
return wrapper |
|
|
return decorator |
|
|
|
|
|
|
|
|
def timer_decorator(func: Callable) -> Callable: |
|
|
""" |
|
|
β±οΈ TIMING DECORATOR |
|
|
""" |
|
|
@wraps(func) |
|
|
def wrapper(*args, **kwargs) -> Any: |
|
|
start_time = time.time() |
|
|
result = func(*args, **kwargs) |
|
|
elapsed_time = time.time() - start_time |
|
|
logger.debug(f"β±οΈ {func.__name__} took {elapsed_time:.2f}s") |
|
|
return result |
|
|
return wrapper |
|
|
|