hxf/backend/th_agenter/utils/exceptions.py

170 lines
4.7 KiB
Python
Raw Normal View History

2025-12-04 14:48:38 +08:00
"""Custom exceptions and error handlers for the chat agent application."""
from typing import Any, Dict, Optional
from fastapi import HTTPException, Request
from fastapi.responses import JSONResponse
from starlette.status import (
HTTP_400_BAD_REQUEST,
HTTP_401_UNAUTHORIZED,
HTTP_403_FORBIDDEN,
HTTP_404_NOT_FOUND,
HTTP_422_UNPROCESSABLE_ENTITY,
HTTP_500_INTERNAL_SERVER_ERROR,
)
from .logger import get_logger
logger = get_logger("exceptions")
class ChatAgentException(Exception):
"""Base exception for chat agent application."""
def __init__(
self,
message: str,
status_code: int = HTTP_500_INTERNAL_SERVER_ERROR,
details: Optional[Dict[str, Any]] = None
):
self.message = message
self.status_code = status_code
self.details = details or {}
super().__init__(self.message)
class ValidationError(ChatAgentException):
"""Validation error exception."""
def __init__(self, message: str, details: Optional[Dict[str, Any]] = None):
super().__init__(message, HTTP_422_UNPROCESSABLE_ENTITY, details)
class AuthenticationError(ChatAgentException):
"""Authentication error exception."""
def __init__(self, message: str = "Authentication failed"):
super().__init__(message, HTTP_401_UNAUTHORIZED)
class AuthorizationError(ChatAgentException):
"""Authorization error exception."""
def __init__(self, message: str = "Access denied"):
super().__init__(message, HTTP_403_FORBIDDEN)
class NotFoundError(ChatAgentException):
"""Resource not found exception."""
def __init__(self, message: str = "Resource not found"):
super().__init__(message, HTTP_404_NOT_FOUND)
class ConversationNotFoundError(NotFoundError):
"""Conversation not found exception."""
def __init__(self, conversation_id: str):
super().__init__(f"Conversation with ID {conversation_id} not found")
class UserNotFoundError(NotFoundError):
"""User not found exception."""
def __init__(self, user_id: str):
super().__init__(f"User with ID {user_id} not found")
class ChatServiceError(ChatAgentException):
"""Chat service error exception."""
def __init__(self, message: str, details: Optional[Dict[str, Any]] = None):
super().__init__(message, HTTP_500_INTERNAL_SERVER_ERROR, details)
class OpenAIError(ChatServiceError):
"""OpenAI API error exception."""
def __init__(self, message: str, details: Optional[Dict[str, Any]] = None):
super().__init__(f"OpenAI API error: {message}", details)
class RateLimitError(ChatAgentException):
"""Rate limit exceeded error."""
pass
class DatabaseError(ChatAgentException):
"""Database operation error exception."""
def __init__(self, message: str, details: Optional[Dict[str, Any]] = None):
super().__init__(f"Database error: {message}", details)
# Error handlers
async def chat_agent_exception_handler(request: Request, exc: ChatAgentException) -> JSONResponse:
"""Handle ChatAgentException and its subclasses."""
logger.error(
f"ChatAgentException: {exc.message}",
extra={
"status_code": exc.status_code,
"details": exc.details,
"path": request.url.path,
"method": request.method
}
)
return JSONResponse(
status_code=exc.status_code,
content={
"error": {
"message": exc.message,
"type": exc.__class__.__name__,
"details": exc.details
}
}
)
async def http_exception_handler(request: Request, exc: HTTPException) -> JSONResponse:
"""Handle HTTPException."""
logger.warning(
f"HTTPException: {exc.detail}",
extra={
"status_code": exc.status_code,
"path": request.url.path,
"method": request.method
}
)
return JSONResponse(
status_code=exc.status_code,
content={
"error": {
"message": exc.detail,
"type": "HTTPException"
}
}
)
async def general_exception_handler(request: Request, exc: Exception) -> JSONResponse:
"""Handle general exceptions."""
logger.error(
f"Unhandled exception: {str(exc)}",
extra={
"exception_type": exc.__class__.__name__,
"path": request.url.path,
"method": request.method
},
exc_info=True
)
return JSONResponse(
status_code=HTTP_500_INTERNAL_SERVER_ERROR,
content={
"error": {
"message": "Internal server error",
"type": "InternalServerError"
}
}
)