File size: 5,584 Bytes
1e732dd
 
 
 
 
 
 
 
696f787
1e732dd
 
 
9659593
1e732dd
 
 
696f787
1e732dd
 
 
 
 
 
9659593
1e732dd
 
 
 
 
 
 
 
 
 
9659593
1e732dd
 
 
 
 
 
 
 
 
 
 
 
 
 
9659593
1e732dd
 
 
 
 
 
 
 
 
 
 
 
 
 
9659593
1e732dd
 
 
 
 
 
 
 
 
 
9659593
1e732dd
 
 
 
 
 
 
 
 
 
 
 
 
 
9659593
1e732dd
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9659593
1e732dd
 
 
 
 
 
 
 
 
 
 
 
 
 
9659593
1e732dd
 
 
 
 
 
 
 
 
 
 
 
 
 
9659593
1e732dd
 
 
 
 
 
 
 
 
 
9659593
1e732dd
 
 
 
 
 
9659593
1e732dd
 
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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
"""
MediGuard AI β€” Domain Exception Hierarchy

Production-grade exception classes for the medical RAG system.
Each service layer raises its own exception type so callers can handle
failures precisely without leaking implementation details.
"""

from typing import Any

# ── Base ──────────────────────────────────────────────────────────────────────


class MediGuardError(Exception):
    """Root exception for the entire MediGuard AI application."""

    def __init__(self, message: str = "", *, details: dict[str, Any] | None = None):
        self.details = details or {}
        super().__init__(message)


# ── Configuration / startup ──────────────────────────────────────────────────


class ConfigurationError(MediGuardError):
    """Raised when a required setting is missing or invalid."""


class ServiceInitError(MediGuardError):
    """Raised when a service fails to initialise during app startup."""


# ── Database ─────────────────────────────────────────────────────────────────


class DatabaseError(MediGuardError):
    """Base class for all database-related errors."""


class ConnectionError(DatabaseError):
    """Could not connect to PostgreSQL."""


class RecordNotFoundError(DatabaseError):
    """Expected record does not exist."""


# ── Search engine ────────────────────────────────────────────────────────────


class SearchError(MediGuardError):
    """Base class for search-engine (OpenSearch) errors."""


class IndexNotFoundError(SearchError):
    """The requested OpenSearch index does not exist."""


class SearchQueryError(SearchError):
    """The search query was malformed or returned an error."""


# ── Embeddings ───────────────────────────────────────────────────────────────


class EmbeddingError(MediGuardError):
    """Failed to generate embeddings."""


class EmbeddingProviderError(EmbeddingError):
    """The upstream embedding provider returned an error."""


# ── PDF / document parsing ───────────────────────────────────────────────────


class PDFParsingError(MediGuardError):
    """Base class for PDF-processing errors."""


class PDFExtractionError(PDFParsingError):
    """Could not extract text from a PDF document."""


class PDFValidationError(PDFParsingError):
    """Uploaded PDF failed validation (size, format, etc.)."""


# ── LLM / Ollama ─────────────────────────────────────────────────────────────


class LLMError(MediGuardError):
    """Base class for LLM-related errors."""


class OllamaConnectionError(LLMError):
    """Could not reach the Ollama server."""


class OllamaModelNotFoundError(LLMError):
    """The requested Ollama model is not pulled/available."""


class LLMResponseError(LLMError):
    """The LLM returned an unparseable or empty response."""


# ── Biomarker domain ─────────────────────────────────────────────────────────


class BiomarkerError(MediGuardError):
    """Base class for biomarker-related errors."""


class BiomarkerValidationError(BiomarkerError):
    """A biomarker value is physiologically implausible."""


class BiomarkerNotFoundError(BiomarkerError):
    """The biomarker name is unknown to the system."""


# ── Medical analysis / workflow ──────────────────────────────────────────────


class AnalysisError(MediGuardError):
    """The clinical-analysis workflow encountered an error."""


class GuardrailError(MediGuardError):
    """A safety guardrail was triggered (input or output)."""


class OutOfScopeError(GuardrailError):
    """The user query falls outside the medical domain."""


# ── Cache ────────────────────────────────────────────────────────────────────


class CacheError(MediGuardError):
    """Base class for cache (Redis) errors."""


class CacheConnectionError(CacheError):
    """Could not connect to Redis."""


# ── Observability ────────────────────────────────────────────────────────────


class ObservabilityError(MediGuardError):
    """Langfuse or metrics reporting failed (non-fatal)."""


# ── Telegram bot ─────────────────────────────────────────────────────────────


class TelegramError(MediGuardError):
    """Error from the Telegram bot integration."""