File size: 9,973 Bytes
ea53ae2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
"""
外部服务抽象接口
为LLM、Embedding和VectorStore等外部依赖提供抽象层
"""

from abc import ABC, abstractmethod
from typing import Any, Dict, List, Optional, Union, Tuple
from dataclasses import dataclass
from enum import Enum
import asyncio


class ModelStatus(Enum):
    """模型状态枚举"""
    AVAILABLE = "available"
    UNAVAILABLE = "unavailable"
    ERROR = "error"
    RATE_LIMITED = "rate_limited"


@dataclass
class ModelInfo:
    """模型信息"""
    name: str
    provider: str
    status: ModelStatus
    capabilities: List[str]
    context_length: Optional[int] = None
    cost_per_token: Optional[float] = None
    rate_limit: Optional[Dict[str, int]] = None


@dataclass
class ChatMessage:
    """聊天消息"""
    role: str  # "user", "assistant", "system"
    content: str
    timestamp: Optional[str] = None
    metadata: Optional[Dict[str, Any]] = None


@dataclass
class ChatResponse:
    """聊天响应"""
    content: str
    model_used: str
    tokens_used: Optional[int] = None
    finish_reason: Optional[str] = None
    metadata: Optional[Dict[str, Any]] = None


@dataclass
class EmbeddingResult:
    """嵌入结果"""
    vectors: List[List[float]]
    model_used: str
    tokens_used: Optional[int] = None
    metadata: Optional[Dict[str, Any]] = None


@dataclass
class DocumentChunk:
    """文档块"""
    content: str
    metadata: Dict[str, Any]
    chunk_id: Optional[str] = None
    source: Optional[str] = None


@dataclass
class SearchResult:
    """搜索结果"""
    document: DocumentChunk
    score: float
    rank: int


class ILLMService(ABC):
    """大语言模型服务抽象接口"""

    @abstractmethod
    def get_available_models(self) -> List[ModelInfo]:
        """获取可用模型列表"""
        pass

    @abstractmethod
    def chat(self,
             messages: List[ChatMessage],
             model: Optional[str] = None,
             temperature: float = 0.7,
             max_tokens: Optional[int] = None,
             **kwargs) -> ChatResponse:
        """聊天对话"""
        pass

    @abstractmethod
    async def chat_async(self,
                         messages: List[ChatMessage],
                         model: Optional[str] = None,
                         temperature: float = 0.7,
                         max_tokens: Optional[int] = None,
                         **kwargs) -> ChatResponse:
        """异步聊天对话"""
        pass

    @abstractmethod
    def stream_chat(self,
                   messages: List[ChatMessage],
                   model: Optional[str] = None,
                   temperature: float = 0.7,
                   max_tokens: Optional[int] = None,
                   **kwargs):
        """流式聊天对话"""
        pass

    @abstractmethod
    def get_model_status(self, model: str) -> ModelStatus:
        """获取模型状态"""
        pass

    @abstractmethod
    def validate_connection(self) -> bool:
        """验证连接"""
        pass


class IEmbeddingService(ABC):
    """嵌入服务抽象接口"""

    @abstractmethod
    def get_available_models(self) -> List[ModelInfo]:
        """获取可用嵌入模型列表"""
        pass

    @abstractmethod
    def embed_texts(self,
                   texts: List[str],
                   model: Optional[str] = None,
                   **kwargs) -> EmbeddingResult:
        """文本嵌入"""
        pass

    @abstractmethod
    async def embed_texts_async(self,
                               texts: List[str],
                               model: Optional[str] = None,
                               **kwargs) -> EmbeddingResult:
        """异步文本嵌入"""
        pass

    @abstractmethod
    def embed_query(self,
                   query: str,
                   model: Optional[str] = None,
                   **kwargs) -> List[float]:
        """查询嵌入"""
        pass

    @abstractmethod
    def get_embedding_dimension(self, model: Optional[str] = None) -> int:
        """获取嵌入维度"""
        pass

    @abstractmethod
    def validate_connection(self) -> bool:
        """验证连接"""
        pass


class IVectorStoreService(ABC):
    """向量存储服务抽象接口"""

    @abstractmethod
    def create_collection(self,
                         name: str,
                         dimension: int,
                         metadata: Optional[Dict[str, Any]] = None) -> bool:
        """创建集合"""
        pass

    @abstractmethod
    def delete_collection(self, name: str) -> bool:
        """删除集合"""
        pass

    @abstractmethod
    def list_collections(self) -> List[str]:
        """列出所有集合"""
        pass

    @abstractmethod
    def add_documents(self,
                     collection_name: str,
                     documents: List[DocumentChunk],
                     embeddings: List[List[float]],
                     **kwargs) -> bool:
        """添加文档"""
        pass

    @abstractmethod
    def search(self,
              collection_name: str,
              query_embedding: List[float],
              top_k: int = 5,
              filter_conditions: Optional[Dict[str, Any]] = None,
              **kwargs) -> List[SearchResult]:
        """相似性搜索"""
        pass

    @abstractmethod
    def delete_documents(self,
                        collection_name: str,
                        document_ids: List[str]) -> bool:
        """删除文档"""
        pass

    @abstractmethod
    def get_collection_stats(self, collection_name: str) -> Dict[str, Any]:
        """获取集合统计信息"""
        pass

    @abstractmethod
    def validate_connection(self) -> bool:
        """验证连接"""
        pass


class IDocumentProcessorService(ABC):
    """文档处理服务抽象接口"""

    @abstractmethod
    def process_file(self,
                    file_path: str,
                    chunk_size: int = 1000,
                    chunk_overlap: int = 200,
                    **kwargs) -> List[DocumentChunk]:
        """处理文件并分块"""
        pass

    @abstractmethod
    def extract_text(self, file_path: str, **kwargs) -> str:
        """提取文本内容"""
        pass

    @abstractmethod
    def get_supported_formats(self) -> List[str]:
        """获取支持的文件格式"""
        pass

    @abstractmethod
    def validate_file(self, file_path: str) -> Tuple[bool, Optional[str]]:
        """验证文件格式和大小"""
        pass


class IMemoryService(ABC):
    """内存服务抽象接口"""

    @abstractmethod
    def save_conversation(self,
                         conversation_id: str,
                         messages: List[ChatMessage]) -> bool:
        """保存对话"""
        pass

    @abstractmethod
    def load_conversation(self, conversation_id: str) -> List[ChatMessage]:
        """加载对话"""
        pass

    @abstractmethod
    def delete_conversation(self, conversation_id: str) -> bool:
        """删除对话"""
        pass

    @abstractmethod
    def list_conversations(self) -> List[Dict[str, Any]]:
        """列出所有对话"""
        pass

    @abstractmethod
    def cleanup_old_conversations(self, days: int = 30) -> int:
        """清理旧对话"""
        pass


class IRateLimiterService(ABC):
    """限流服务抽象接口"""

    @abstractmethod
    def check_rate_limit(self,
                        key: str,
                        limit: int,
                        window_seconds: int) -> Tuple[bool, int]:
        """检查限流状态

        Returns:
            Tuple[bool, int]: (是否允许请求, 剩余配额)
        """
        pass

    @abstractmethod
    def reset_rate_limit(self, key: str) -> bool:
        """重置限流"""
        pass

    @abstractmethod
    def get_rate_limit_info(self, key: str) -> Dict[str, Any]:
        """获取限流信息"""
        pass


class IHealthCheckService(ABC):
    """健康检查服务抽象接口"""

    @abstractmethod
    def check_service_health(self, service_name: str) -> Dict[str, Any]:
        """检查单个服务健康状态"""
        pass

    @abstractmethod
    def check_all_services_health(self) -> Dict[str, Dict[str, Any]]:
        """检查所有服务健康状态"""
        pass

    @abstractmethod
    def register_health_check(self,
                             service_name: str,
                             check_function: callable) -> bool:
        """注册健康检查"""
        pass


class IMetricsService(ABC):
    """指标服务抽象接口"""

    @abstractmethod
    def record_metric(self,
                     name: str,
                     value: float,
                     tags: Optional[Dict[str, str]] = None) -> None:
        """记录指标"""
        pass

    @abstractmethod
    def increment_counter(self,
                         name: str,
                         tags: Optional[Dict[str, str]] = None) -> None:
        """递增计数器"""
        pass

    @abstractmethod
    def record_histogram(self,
                        name: str,
                        value: float,
                        tags: Optional[Dict[str, str]] = None) -> None:
        """记录直方图"""
        pass

    @abstractmethod
    def get_metrics(self,
                   name_pattern: Optional[str] = None) -> Dict[str, Any]:
        """获取指标数据"""
        pass


# 异常类
class ExternalServiceException(Exception):
    """外部服务异常基类"""
    pass


class LLMServiceException(ExternalServiceException):
    """LLM服务异常"""
    pass


class EmbeddingServiceException(ExternalServiceException):
    """嵌入服务异常"""
    pass


class VectorStoreException(ExternalServiceException):
    """向量存储异常"""
    pass


class RateLimitException(ExternalServiceException):
    """限流异常"""
    pass


class HealthCheckException(ExternalServiceException):
    """健康检查异常"""
    pass