File size: 2,205 Bytes
9b5157d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
"""
Domain exception hierarchy.
Each exception maps to an HTTP status code and a machine-readable error_code.
Routers raise these; exception handlers in main.py convert them to HTTP responses.
"""
from typing import Any


class AppError(Exception):
    status_code: int = 500
    error_code: str = "INTERNAL_ERROR"

    def __init__(self, message: str = "An unexpected error occurred", context: dict[str, Any] | None = None):
        self.message = message
        self.context = context or {}
        super().__init__(message)


class ImageDecodeError(AppError):
    status_code = 400
    error_code = "IMAGE_DECODE_ERROR"

    def __init__(self):
        super().__init__("Could not decode image. Ensure it is a valid JPEG, PNG, or WebP file.")


class ImageTooLargeError(AppError):
    status_code = 413
    error_code = "IMAGE_TOO_LARGE"

    def __init__(self, max_mb: int = 10, detail: str | None = None):
        super().__init__(
            detail or f"Image exceeds maximum size of {max_mb}MB.",
            context={"max_mb": max_mb},
        )


class InvalidMimeTypeError(AppError):
    status_code = 415
    error_code = "INVALID_MIME_TYPE"

    def __init__(self, received: str, allowed: set[str]):
        super().__init__(
            f"Unsupported file type '{received}'. Allowed: {', '.join(sorted(allowed))}.",
            context={"received": received, "allowed": sorted(allowed)},
        )


class UnknownChallengeError(AppError):
    status_code = 400
    error_code = "UNKNOWN_CHALLENGE"

    def __init__(self, challenge_type: str, valid: list[str]):
        super().__init__(
            f"Unknown challenge '{challenge_type}'.",
            context={"received": challenge_type, "valid": valid},
        )


class ModelNotReadyError(AppError):
    status_code = 503
    error_code = "MODEL_NOT_READY"

    def __init__(self, model_name: str):
        super().__init__(
            f"Model '{model_name}' is not loaded. Retry in a moment.",
            context={"model": model_name},
        )


class RateLimitError(AppError):
    status_code = 429
    error_code = "RATE_LIMIT_EXCEEDED"

    def __init__(self):
        super().__init__("Too many requests. Please slow down.")