Base code

This commit is contained in:
Kunthawat Greethong
2026-01-08 22:39:53 +07:00
parent 697115c61a
commit c35fa52117
2169 changed files with 626670 additions and 0 deletions

View File

@@ -0,0 +1,285 @@
"""
Blog Writer Exception Hierarchy
Defines custom exception classes for different failure modes in the AI Blog Writer.
Each exception includes error_code, user_message, retry_suggested, and actionable_steps.
"""
from typing import List, Optional, Dict, Any
from enum import Enum
class ErrorCategory(Enum):
"""Categories for error classification."""
TRANSIENT = "transient" # Temporary issues, retry recommended
PERMANENT = "permanent" # Permanent issues, no retry
USER_ERROR = "user_error" # User input issues, fix input
API_ERROR = "api_error" # External API issues
VALIDATION_ERROR = "validation_error" # Data validation issues
SYSTEM_ERROR = "system_error" # Internal system issues
class BlogWriterException(Exception):
"""Base exception for all Blog Writer errors."""
def __init__(
self,
message: str,
error_code: str,
user_message: str,
retry_suggested: bool = False,
actionable_steps: Optional[List[str]] = None,
error_category: ErrorCategory = ErrorCategory.SYSTEM_ERROR,
context: Optional[Dict[str, Any]] = None
):
super().__init__(message)
self.error_code = error_code
self.user_message = user_message
self.retry_suggested = retry_suggested
self.actionable_steps = actionable_steps or []
self.error_category = error_category
self.context = context or {}
def to_dict(self) -> Dict[str, Any]:
"""Convert exception to dictionary for API responses."""
return {
"error_code": self.error_code,
"user_message": self.user_message,
"retry_suggested": self.retry_suggested,
"actionable_steps": self.actionable_steps,
"error_category": self.error_category.value,
"context": self.context
}
class ResearchFailedException(BlogWriterException):
"""Raised when research operation fails."""
def __init__(
self,
message: str,
user_message: str = "Research failed. Please try again with different keywords or check your internet connection.",
retry_suggested: bool = True,
context: Optional[Dict[str, Any]] = None
):
super().__init__(
message=message,
error_code="RESEARCH_FAILED",
user_message=user_message,
retry_suggested=retry_suggested,
actionable_steps=[
"Try with different keywords",
"Check your internet connection",
"Wait a few minutes and try again",
"Contact support if the issue persists"
],
error_category=ErrorCategory.API_ERROR,
context=context
)
class OutlineGenerationException(BlogWriterException):
"""Raised when outline generation fails."""
def __init__(
self,
message: str,
user_message: str = "Outline generation failed. Please try again or adjust your research data.",
retry_suggested: bool = True,
context: Optional[Dict[str, Any]] = None
):
super().__init__(
message=message,
error_code="OUTLINE_GENERATION_FAILED",
user_message=user_message,
retry_suggested=retry_suggested,
actionable_steps=[
"Try generating outline again",
"Check if research data is complete",
"Try with different research keywords",
"Contact support if the issue persists"
],
error_category=ErrorCategory.API_ERROR,
context=context
)
class ContentGenerationException(BlogWriterException):
"""Raised when content generation fails."""
def __init__(
self,
message: str,
user_message: str = "Content generation failed. Please try again or adjust your outline.",
retry_suggested: bool = True,
context: Optional[Dict[str, Any]] = None
):
super().__init__(
message=message,
error_code="CONTENT_GENERATION_FAILED",
user_message=user_message,
retry_suggested=retry_suggested,
actionable_steps=[
"Try generating content again",
"Check if outline is complete",
"Try with a shorter outline",
"Contact support if the issue persists"
],
error_category=ErrorCategory.API_ERROR,
context=context
)
class SEOAnalysisException(BlogWriterException):
"""Raised when SEO analysis fails."""
def __init__(
self,
message: str,
user_message: str = "SEO analysis failed. Content was generated but SEO optimization is unavailable.",
retry_suggested: bool = True,
context: Optional[Dict[str, Any]] = None
):
super().__init__(
message=message,
error_code="SEO_ANALYSIS_FAILED",
user_message=user_message,
retry_suggested=retry_suggested,
actionable_steps=[
"Try SEO analysis again",
"Continue without SEO optimization",
"Contact support if the issue persists"
],
error_category=ErrorCategory.API_ERROR,
context=context
)
class APIRateLimitException(BlogWriterException):
"""Raised when API rate limit is exceeded."""
def __init__(
self,
message: str,
retry_after: Optional[int] = None,
context: Optional[Dict[str, Any]] = None
):
retry_message = f"Rate limit exceeded. Please wait {retry_after} seconds before trying again." if retry_after else "Rate limit exceeded. Please wait a few minutes before trying again."
super().__init__(
message=message,
error_code="API_RATE_LIMIT",
user_message=retry_message,
retry_suggested=True,
actionable_steps=[
f"Wait {retry_after or 60} seconds before trying again",
"Reduce the frequency of requests",
"Try again during off-peak hours",
"Contact support if you need higher limits"
],
error_category=ErrorCategory.API_ERROR,
context=context
)
class APITimeoutException(BlogWriterException):
"""Raised when API request times out."""
def __init__(
self,
message: str,
timeout_seconds: int = 60,
context: Optional[Dict[str, Any]] = None
):
super().__init__(
message=message,
error_code="API_TIMEOUT",
user_message=f"Request timed out after {timeout_seconds} seconds. Please try again.",
retry_suggested=True,
actionable_steps=[
"Try again with a shorter request",
"Check your internet connection",
"Try again during off-peak hours",
"Contact support if the issue persists"
],
error_category=ErrorCategory.TRANSIENT,
context=context
)
class ValidationException(BlogWriterException):
"""Raised when input validation fails."""
def __init__(
self,
message: str,
field: str,
user_message: str = "Invalid input provided. Please check your data and try again.",
context: Optional[Dict[str, Any]] = None
):
super().__init__(
message=message,
error_code="VALIDATION_ERROR",
user_message=user_message,
retry_suggested=False,
actionable_steps=[
f"Check the {field} field",
"Ensure all required fields are filled",
"Verify data format is correct",
"Contact support if you need help"
],
error_category=ErrorCategory.USER_ERROR,
context=context
)
class CircuitBreakerOpenException(BlogWriterException):
"""Raised when circuit breaker is open."""
def __init__(
self,
message: str,
retry_after: int,
context: Optional[Dict[str, Any]] = None
):
super().__init__(
message=message,
error_code="CIRCUIT_BREAKER_OPEN",
user_message=f"Service temporarily unavailable. Please wait {retry_after} seconds before trying again.",
retry_suggested=True,
actionable_steps=[
f"Wait {retry_after} seconds before trying again",
"Try again during off-peak hours",
"Contact support if the issue persists"
],
error_category=ErrorCategory.TRANSIENT,
context=context
)
class PartialSuccessException(BlogWriterException):
"""Raised when operation partially succeeds."""
def __init__(
self,
message: str,
partial_results: Dict[str, Any],
failed_operations: List[str],
user_message: str = "Operation partially completed. Some sections were generated successfully.",
context: Optional[Dict[str, Any]] = None
):
super().__init__(
message=message,
error_code="PARTIAL_SUCCESS",
user_message=user_message,
retry_suggested=True,
actionable_steps=[
"Review the generated content",
"Retry failed sections individually",
"Contact support if you need help with failed sections"
],
error_category=ErrorCategory.TRANSIENT,
context=context
)
self.partial_results = partial_results
self.failed_operations = failed_operations