isage-middleware 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of isage-middleware might be problematic. Click here for more details.

Files changed (191) hide show
  1. isage_middleware-0.1.0.dist-info/METADATA +424 -0
  2. isage_middleware-0.1.0.dist-info/RECORD +191 -0
  3. isage_middleware-0.1.0.dist-info/WHEEL +5 -0
  4. isage_middleware-0.1.0.dist-info/top_level.txt +1 -0
  5. sage/__init__.py +2 -0
  6. sage/__pycache__/__init__.cpython-311.opt-2.pyc +0 -0
  7. sage/__pycache__/__init__.cpython-311.pyc +0 -0
  8. sage/middleware/__init__.py +83 -0
  9. sage/middleware/__pycache__/__init__.cpython-311.opt-2.pyc +0 -0
  10. sage/middleware/__pycache__/__init__.cpython-311.pyc +0 -0
  11. sage/middleware/api/__init__.py +22 -0
  12. sage/middleware/api/__pycache__/__init__.cpython-311.opt-2.pyc +0 -0
  13. sage/middleware/api/__pycache__/__init__.cpython-311.pyc +0 -0
  14. sage/middleware/api/__pycache__/graph_api.cpython-311.opt-2.pyc +0 -0
  15. sage/middleware/api/__pycache__/graph_api.cpython-311.pyc +0 -0
  16. sage/middleware/api/__pycache__/kv_api.cpython-311.opt-2.pyc +0 -0
  17. sage/middleware/api/__pycache__/kv_api.cpython-311.pyc +0 -0
  18. sage/middleware/api/__pycache__/memory_api.cpython-311.opt-2.pyc +0 -0
  19. sage/middleware/api/__pycache__/memory_api.cpython-311.pyc +0 -0
  20. sage/middleware/api/__pycache__/vdb_api.cpython-311.opt-2.pyc +0 -0
  21. sage/middleware/api/__pycache__/vdb_api.cpython-311.pyc +0 -0
  22. sage/middleware/api/graph_api.py +74 -0
  23. sage/middleware/api/kv_api.py +45 -0
  24. sage/middleware/api/memory_api.py +64 -0
  25. sage/middleware/api/vdb_api.py +60 -0
  26. sage/middleware/enterprise/__init__.py +75 -0
  27. sage/middleware/enterprise/__pycache__/__init__.cpython-311.opt-2.pyc +0 -0
  28. sage/middleware/enterprise/__pycache__/__init__.cpython-311.pyc +0 -0
  29. sage/middleware/enterprise/sage_db/__init__.py +132 -0
  30. sage/middleware/enterprise/sage_db/__pycache__/__init__.cpython-311.opt-2.pyc +0 -0
  31. sage/middleware/enterprise/sage_db/__pycache__/__init__.cpython-311.pyc +0 -0
  32. sage/middleware/enterprise/sage_db/__pycache__/sage_db.cpython-311.opt-2.pyc +0 -0
  33. sage/middleware/enterprise/sage_db/__pycache__/sage_db.cpython-311.pyc +0 -0
  34. sage/middleware/enterprise/sage_db/python/__init__.py +7 -0
  35. sage/middleware/enterprise/sage_db/python/__pycache__/__init__.cpython-311.opt-2.pyc +0 -0
  36. sage/middleware/enterprise/sage_db/python/__pycache__/__init__.cpython-311.pyc +0 -0
  37. sage/middleware/enterprise/sage_db/python/__pycache__/sage_db.cpython-311.opt-2.pyc +0 -0
  38. sage/middleware/enterprise/sage_db/python/__pycache__/sage_db.cpython-311.pyc +0 -0
  39. sage/middleware/enterprise/sage_db/python/sage_db.py +44 -0
  40. sage/middleware/enterprise/sage_db/sage_db.py +395 -0
  41. sage/middleware/enterprise/sage_db/tests/__pycache__/test_python.cpython-311.opt-2.pyc +0 -0
  42. sage/middleware/enterprise/sage_db/tests/__pycache__/test_python.cpython-311.pyc +0 -0
  43. sage/middleware/enterprise/sage_db/tests/test_python.py +144 -0
  44. sage/middleware/examples/__pycache__/api_usage_tutorial.cpython-311.opt-2.pyc +0 -0
  45. sage/middleware/examples/__pycache__/api_usage_tutorial.cpython-311.pyc +0 -0
  46. sage/middleware/examples/__pycache__/dag_microservices_demo.cpython-311.opt-2.pyc +0 -0
  47. sage/middleware/examples/__pycache__/dag_microservices_demo.cpython-311.pyc +0 -0
  48. sage/middleware/examples/__pycache__/microservices_demo.cpython-311.opt-2.pyc +0 -0
  49. sage/middleware/examples/__pycache__/microservices_demo.cpython-311.pyc +0 -0
  50. sage/middleware/examples/__pycache__/microservices_integration_demo.cpython-311.opt-2.pyc +0 -0
  51. sage/middleware/examples/__pycache__/microservices_integration_demo.cpython-311.pyc +0 -0
  52. sage/middleware/examples/__pycache__/microservices_registration_demo.cpython-311.opt-2.pyc +0 -0
  53. sage/middleware/examples/__pycache__/microservices_registration_demo.cpython-311.pyc +0 -0
  54. sage/middleware/examples/api_usage_tutorial.py +339 -0
  55. sage/middleware/examples/dag_microservices_demo.py +220 -0
  56. sage/middleware/examples/microservices_demo.py +0 -0
  57. sage/middleware/examples/microservices_integration_demo.py +373 -0
  58. sage/middleware/examples/microservices_registration_demo.py +144 -0
  59. sage/middleware/py.typed +2 -0
  60. sage/middleware/services/graph/__init__.py +8 -0
  61. sage/middleware/services/graph/__pycache__/__init__.cpython-311.opt-2.pyc +0 -0
  62. sage/middleware/services/graph/__pycache__/__init__.cpython-311.pyc +0 -0
  63. sage/middleware/services/graph/__pycache__/graph_index.cpython-311.opt-2.pyc +0 -0
  64. sage/middleware/services/graph/__pycache__/graph_index.cpython-311.pyc +0 -0
  65. sage/middleware/services/graph/__pycache__/graph_service.cpython-311.opt-2.pyc +0 -0
  66. sage/middleware/services/graph/__pycache__/graph_service.cpython-311.pyc +0 -0
  67. sage/middleware/services/graph/examples/__pycache__/graph_demo.cpython-311.opt-2.pyc +0 -0
  68. sage/middleware/services/graph/examples/__pycache__/graph_demo.cpython-311.pyc +0 -0
  69. sage/middleware/services/graph/examples/graph_demo.py +177 -0
  70. sage/middleware/services/graph/graph_index.py +194 -0
  71. sage/middleware/services/graph/graph_service.py +541 -0
  72. sage/middleware/services/graph/search_engine/__init__.py +0 -0
  73. sage/middleware/services/graph/search_engine/__pycache__/__init__.cpython-311.opt-2.pyc +0 -0
  74. sage/middleware/services/graph/search_engine/__pycache__/__init__.cpython-311.pyc +0 -0
  75. sage/middleware/services/graph/search_engine/__pycache__/base_graph_index.cpython-311.opt-2.pyc +0 -0
  76. sage/middleware/services/graph/search_engine/__pycache__/base_graph_index.cpython-311.pyc +0 -0
  77. sage/middleware/services/graph/search_engine/base_graph_index.py +0 -0
  78. sage/middleware/services/kv/__init__.py +8 -0
  79. sage/middleware/services/kv/__pycache__/__init__.cpython-311.opt-2.pyc +0 -0
  80. sage/middleware/services/kv/__pycache__/__init__.cpython-311.pyc +0 -0
  81. sage/middleware/services/kv/__pycache__/kv_service.cpython-311.opt-2.pyc +0 -0
  82. sage/middleware/services/kv/__pycache__/kv_service.cpython-311.pyc +0 -0
  83. sage/middleware/services/kv/examples/__pycache__/kv_demo.cpython-311.opt-2.pyc +0 -0
  84. sage/middleware/services/kv/examples/__pycache__/kv_demo.cpython-311.pyc +0 -0
  85. sage/middleware/services/kv/examples/kv_demo.py +213 -0
  86. sage/middleware/services/kv/kv_service.py +306 -0
  87. sage/middleware/services/kv/search_engine/__init__.py +0 -0
  88. sage/middleware/services/kv/search_engine/__pycache__/__init__.cpython-311.opt-2.pyc +0 -0
  89. sage/middleware/services/kv/search_engine/__pycache__/__init__.cpython-311.pyc +0 -0
  90. sage/middleware/services/kv/search_engine/__pycache__/base_kv_index.cpython-311.opt-2.pyc +0 -0
  91. sage/middleware/services/kv/search_engine/__pycache__/base_kv_index.cpython-311.pyc +0 -0
  92. sage/middleware/services/kv/search_engine/__pycache__/bm25s_index.cpython-311.opt-2.pyc +0 -0
  93. sage/middleware/services/kv/search_engine/__pycache__/bm25s_index.cpython-311.pyc +0 -0
  94. sage/middleware/services/kv/search_engine/base_kv_index.py +75 -0
  95. sage/middleware/services/kv/search_engine/bm25s_index.py +238 -0
  96. sage/middleware/services/memory/__init__.py +12 -0
  97. sage/middleware/services/memory/__pycache__/__init__.cpython-311.opt-2.pyc +0 -0
  98. sage/middleware/services/memory/__pycache__/__init__.cpython-311.pyc +0 -0
  99. sage/middleware/services/memory/__pycache__/memory_service.cpython-311.opt-2.pyc +0 -0
  100. sage/middleware/services/memory/__pycache__/memory_service.cpython-311.pyc +0 -0
  101. sage/middleware/services/memory/examples/__pycache__/dag_microservices_demo.cpython-311.opt-2.pyc +0 -0
  102. sage/middleware/services/memory/examples/__pycache__/dag_microservices_demo.cpython-311.pyc +0 -0
  103. sage/middleware/services/memory/examples/__pycache__/memory_demo.cpython-311.opt-2.pyc +0 -0
  104. sage/middleware/services/memory/examples/__pycache__/memory_demo.cpython-311.pyc +0 -0
  105. sage/middleware/services/memory/examples/dag_microservices_demo.py +220 -0
  106. sage/middleware/services/memory/examples/memory_demo.py +490 -0
  107. sage/middleware/services/memory/memory_collection/__pycache__/base_collection.cpython-311.opt-2.pyc +0 -0
  108. sage/middleware/services/memory/memory_collection/__pycache__/base_collection.cpython-311.pyc +0 -0
  109. sage/middleware/services/memory/memory_collection/__pycache__/graph_collection.cpython-311.opt-2.pyc +0 -0
  110. sage/middleware/services/memory/memory_collection/__pycache__/graph_collection.cpython-311.pyc +0 -0
  111. sage/middleware/services/memory/memory_collection/__pycache__/kv_collection.cpython-311.opt-2.pyc +0 -0
  112. sage/middleware/services/memory/memory_collection/__pycache__/kv_collection.cpython-311.pyc +0 -0
  113. sage/middleware/services/memory/memory_collection/__pycache__/vdb_collection.cpython-311.opt-2.pyc +0 -0
  114. sage/middleware/services/memory/memory_collection/__pycache__/vdb_collection.cpython-311.pyc +0 -0
  115. sage/middleware/services/memory/memory_collection/base_collection.py +0 -0
  116. sage/middleware/services/memory/memory_collection/graph_collection.py +0 -0
  117. sage/middleware/services/memory/memory_collection/kv_collection.py +0 -0
  118. sage/middleware/services/memory/memory_collection/vdb_collection.py +0 -0
  119. sage/middleware/services/memory/memory_service.py +474 -0
  120. sage/middleware/services/memory/utils/__init__.py +0 -0
  121. sage/middleware/services/memory/utils/__pycache__/__init__.cpython-311.opt-2.pyc +0 -0
  122. sage/middleware/services/memory/utils/__pycache__/__init__.cpython-311.pyc +0 -0
  123. sage/middleware/services/memory/utils/__pycache__/path_utils.cpython-311.opt-2.pyc +0 -0
  124. sage/middleware/services/memory/utils/__pycache__/path_utils.cpython-311.pyc +0 -0
  125. sage/middleware/services/memory/utils/path_utils.py +0 -0
  126. sage/middleware/services/vdb/__init__.py +8 -0
  127. sage/middleware/services/vdb/__pycache__/__init__.cpython-311.opt-2.pyc +0 -0
  128. sage/middleware/services/vdb/__pycache__/__init__.cpython-311.pyc +0 -0
  129. sage/middleware/services/vdb/__pycache__/vdb_service.cpython-311.opt-2.pyc +0 -0
  130. sage/middleware/services/vdb/__pycache__/vdb_service.cpython-311.pyc +0 -0
  131. sage/middleware/services/vdb/examples/__pycache__/vdb_demo.cpython-311.opt-2.pyc +0 -0
  132. sage/middleware/services/vdb/examples/__pycache__/vdb_demo.cpython-311.pyc +0 -0
  133. sage/middleware/services/vdb/examples/vdb_demo.py +447 -0
  134. sage/middleware/services/vdb/search_engine/__init__.py +0 -0
  135. sage/middleware/services/vdb/search_engine/__pycache__/__init__.cpython-311.opt-2.pyc +0 -0
  136. sage/middleware/services/vdb/search_engine/__pycache__/__init__.cpython-311.pyc +0 -0
  137. sage/middleware/services/vdb/search_engine/__pycache__/base_vdb_index.cpython-311.opt-2.pyc +0 -0
  138. sage/middleware/services/vdb/search_engine/__pycache__/base_vdb_index.cpython-311.pyc +0 -0
  139. sage/middleware/services/vdb/search_engine/__pycache__/faiss_index.cpython-311.opt-2.pyc +0 -0
  140. sage/middleware/services/vdb/search_engine/__pycache__/faiss_index.cpython-311.pyc +0 -0
  141. sage/middleware/services/vdb/search_engine/base_vdb_index.py +58 -0
  142. sage/middleware/services/vdb/search_engine/faiss_index.py +461 -0
  143. sage/middleware/services/vdb/vdb_service.py +433 -0
  144. sage/middleware/utils/__init__.py +5 -0
  145. sage/middleware/utils/__pycache__/__init__.cpython-311.opt-2.pyc +0 -0
  146. sage/middleware/utils/__pycache__/__init__.cpython-311.pyc +0 -0
  147. sage/middleware/utils/embedding/__init__.py +35 -0
  148. sage/middleware/utils/embedding/__pycache__/__init__.cpython-311.opt-2.pyc +0 -0
  149. sage/middleware/utils/embedding/__pycache__/__init__.cpython-311.pyc +0 -0
  150. sage/middleware/utils/embedding/__pycache__/_cohere.cpython-311.opt-2.pyc +0 -0
  151. sage/middleware/utils/embedding/__pycache__/_cohere.cpython-311.pyc +0 -0
  152. sage/middleware/utils/embedding/__pycache__/bedrock.cpython-311.opt-2.pyc +0 -0
  153. sage/middleware/utils/embedding/__pycache__/bedrock.cpython-311.pyc +0 -0
  154. sage/middleware/utils/embedding/__pycache__/embedding_api.cpython-311.opt-2.pyc +0 -0
  155. sage/middleware/utils/embedding/__pycache__/embedding_api.cpython-311.pyc +0 -0
  156. sage/middleware/utils/embedding/__pycache__/embedding_model.cpython-311.opt-2.pyc +0 -0
  157. sage/middleware/utils/embedding/__pycache__/embedding_model.cpython-311.pyc +0 -0
  158. sage/middleware/utils/embedding/__pycache__/hf.cpython-311.opt-2.pyc +0 -0
  159. sage/middleware/utils/embedding/__pycache__/hf.cpython-311.pyc +0 -0
  160. sage/middleware/utils/embedding/__pycache__/instructor.cpython-311.opt-2.pyc +0 -0
  161. sage/middleware/utils/embedding/__pycache__/instructor.cpython-311.pyc +0 -0
  162. sage/middleware/utils/embedding/__pycache__/jina.cpython-311.opt-2.pyc +0 -0
  163. sage/middleware/utils/embedding/__pycache__/jina.cpython-311.pyc +0 -0
  164. sage/middleware/utils/embedding/__pycache__/lollms.cpython-311.opt-2.pyc +0 -0
  165. sage/middleware/utils/embedding/__pycache__/lollms.cpython-311.pyc +0 -0
  166. sage/middleware/utils/embedding/__pycache__/mockembedder.cpython-311.opt-2.pyc +0 -0
  167. sage/middleware/utils/embedding/__pycache__/mockembedder.cpython-311.pyc +0 -0
  168. sage/middleware/utils/embedding/__pycache__/nvidia_openai.cpython-311.opt-2.pyc +0 -0
  169. sage/middleware/utils/embedding/__pycache__/nvidia_openai.cpython-311.pyc +0 -0
  170. sage/middleware/utils/embedding/__pycache__/ollama.cpython-311.opt-2.pyc +0 -0
  171. sage/middleware/utils/embedding/__pycache__/ollama.cpython-311.pyc +0 -0
  172. sage/middleware/utils/embedding/__pycache__/openai.cpython-311.opt-2.pyc +0 -0
  173. sage/middleware/utils/embedding/__pycache__/openai.cpython-311.pyc +0 -0
  174. sage/middleware/utils/embedding/__pycache__/siliconcloud.cpython-311.opt-2.pyc +0 -0
  175. sage/middleware/utils/embedding/__pycache__/siliconcloud.cpython-311.pyc +0 -0
  176. sage/middleware/utils/embedding/__pycache__/zhipu.cpython-311.opt-2.pyc +0 -0
  177. sage/middleware/utils/embedding/__pycache__/zhipu.cpython-311.pyc +0 -0
  178. sage/middleware/utils/embedding/_cohere.py +68 -0
  179. sage/middleware/utils/embedding/bedrock.py +174 -0
  180. sage/middleware/utils/embedding/embedding_api.py +12 -0
  181. sage/middleware/utils/embedding/embedding_model.py +150 -0
  182. sage/middleware/utils/embedding/hf.py +90 -0
  183. sage/middleware/utils/embedding/instructor.py +10 -0
  184. sage/middleware/utils/embedding/jina.py +115 -0
  185. sage/middleware/utils/embedding/lollms.py +100 -0
  186. sage/middleware/utils/embedding/mockembedder.py +46 -0
  187. sage/middleware/utils/embedding/nvidia_openai.py +97 -0
  188. sage/middleware/utils/embedding/ollama.py +97 -0
  189. sage/middleware/utils/embedding/openai.py +112 -0
  190. sage/middleware/utils/embedding/siliconcloud.py +133 -0
  191. sage/middleware/utils/embedding/zhipu.py +85 -0
@@ -0,0 +1,433 @@
1
+ """
2
+ VDB Service - 向量数据库微服务
3
+ 提供向量存储和相似性搜索功能的服务任务,集成到SAGE DAG中
4
+ 使用嵌入式FAISS引擎,不依赖外部数据库
5
+ """
6
+ from typing import Dict, Any, Optional, List, Union, Tuple, TYPE_CHECKING
7
+ from dataclasses import dataclass
8
+ import numpy as np
9
+ import logging
10
+ import time
11
+ import uuid
12
+
13
+ from sage.core.api.service.base_service import BaseService
14
+
15
+ if TYPE_CHECKING:
16
+ from sage.core.factory.service_factory import ServiceFactory
17
+ from sage.kernel import ServiceContext
18
+
19
+
20
+ @dataclass
21
+ class VDBConfig:
22
+ """VDB服务配置"""
23
+ embedding_dimension: int = 384
24
+ index_type: str = "IndexFlatL2" # FAISS索引类型
25
+ max_vectors: int = 1000000
26
+ similarity_threshold: float = 0.8
27
+ # FAISS索引配置
28
+ faiss_config: Dict[str, Any] = None
29
+
30
+
31
+ @dataclass
32
+ class VectorDocument:
33
+ """向量文档"""
34
+ id: str
35
+ vector: List[float]
36
+ metadata: Dict[str, Any]
37
+ text: Optional[str] = None
38
+ created_at: float = None
39
+
40
+ def __post_init__(self):
41
+ if self.created_at is None:
42
+ self.created_at = time.time()
43
+
44
+
45
+ class FaissVDBBackend:
46
+ """基于FAISS的向量数据库后端"""
47
+
48
+ def __init__(self, embedding_dimension: int = 384, index_type: str = "IndexFlatL2",
49
+ faiss_config: Optional[Dict[str, Any]] = None):
50
+ self.embedding_dimension = embedding_dimension
51
+ self.index_type = index_type
52
+ self.faiss_config = faiss_config or {}
53
+ self.logger = logging.getLogger(__name__)
54
+
55
+ # 导入FaissIndex
56
+ try:
57
+ from sage.middleware.services.vdb.search_engine.faiss_index import FaissIndex
58
+
59
+ # 初始化FAISS索引
60
+ self.faiss_index = FaissIndex(
61
+ name="vdb_index",
62
+ dim=embedding_dimension,
63
+ config={
64
+ "index_type": index_type,
65
+ **self.faiss_config
66
+ }
67
+ )
68
+
69
+ # 文档存储 (id -> VectorDocument)
70
+ self.documents: Dict[str, VectorDocument] = {}
71
+
72
+ self.logger.info(f"FaissVDBBackend initialized with {index_type}, dim={embedding_dimension}")
73
+
74
+ except ImportError as e:
75
+ self.logger.error(f"Failed to import FaissIndex: {e}")
76
+ raise ImportError("FAISS dependencies not available. Install with: pip install faiss-cpu")
77
+
78
+ def add_vectors(self, vectors: List[VectorDocument]) -> List[str]:
79
+ """添加向量文档"""
80
+ try:
81
+ if not vectors:
82
+ return []
83
+
84
+ # 准备向量和ID
85
+ vector_arrays = []
86
+ vector_ids = []
87
+
88
+ for doc in vectors:
89
+ # 如果没有ID,生成一个
90
+ if not doc.id:
91
+ doc.id = str(uuid.uuid4())
92
+
93
+ # 验证向量维度
94
+ if len(doc.vector) != self.embedding_dimension:
95
+ self.logger.warning(f"Vector dimension mismatch: expected {self.embedding_dimension}, got {len(doc.vector)}")
96
+ continue
97
+
98
+ vector_arrays.append(np.array(doc.vector, dtype=np.float32))
99
+ vector_ids.append(doc.id)
100
+
101
+ # 存储文档
102
+ self.documents[doc.id] = doc
103
+
104
+ if vector_arrays:
105
+ # 添加到FAISS索引
106
+ vectors_np = np.vstack(vector_arrays)
107
+ self.faiss_index.add(vectors_np, vector_ids)
108
+
109
+ self.logger.debug(f"Added {len(vector_ids)} vectors to FAISS index")
110
+ return vector_ids
111
+ else:
112
+ return []
113
+
114
+ except Exception as e:
115
+ self.logger.error(f"Error adding vectors: {e}")
116
+ return []
117
+
118
+ def search_vectors(self, query_vector: List[float], top_k: int = 5,
119
+ metadata_filter: Optional[Dict[str, Any]] = None) -> List[Tuple[VectorDocument, float]]:
120
+ """搜索相似向量"""
121
+ try:
122
+ if len(query_vector) != self.embedding_dimension:
123
+ raise ValueError(f"Query vector dimension mismatch: expected {self.embedding_dimension}, got {len(query_vector)}")
124
+
125
+ # 转换查询向量
126
+ query_np = np.array([query_vector], dtype=np.float32)
127
+
128
+ # 在FAISS中搜索
129
+ distances, indices, ids = self.faiss_index.search(query_np, top_k)
130
+
131
+ results = []
132
+ for i, (distance, doc_id) in enumerate(zip(distances[0], ids[0])):
133
+ if doc_id in self.documents:
134
+ doc = self.documents[doc_id]
135
+
136
+ # 应用元数据过滤
137
+ if metadata_filter and not self._matches_filter(doc.metadata, metadata_filter):
138
+ continue
139
+
140
+ results.append((doc, float(distance)))
141
+ else:
142
+ self.logger.warning(f"Document {doc_id} found in index but not in storage")
143
+
144
+ self.logger.debug(f"Search returned {len(results)} results")
145
+ return results
146
+
147
+ except Exception as e:
148
+ self.logger.error(f"Error searching vectors: {e}")
149
+ return []
150
+
151
+ def get_vector(self, doc_id: str) -> Optional[VectorDocument]:
152
+ """获取向量文档"""
153
+ return self.documents.get(doc_id)
154
+
155
+ def delete_vectors(self, doc_ids: List[str]) -> int:
156
+ """删除向量文档"""
157
+ try:
158
+ deleted_count = 0
159
+ valid_ids = []
160
+
161
+ for doc_id in doc_ids:
162
+ if doc_id in self.documents:
163
+ del self.documents[doc_id]
164
+ valid_ids.append(doc_id)
165
+ deleted_count += 1
166
+
167
+ # 从FAISS索引中删除
168
+ if valid_ids:
169
+ self.faiss_index.delete(valid_ids)
170
+
171
+ self.logger.debug(f"Deleted {deleted_count} vectors")
172
+ return deleted_count
173
+
174
+ except Exception as e:
175
+ self.logger.error(f"Error deleting vectors: {e}")
176
+ return 0
177
+
178
+ def list_vectors(self, metadata_filter: Optional[Dict[str, Any]] = None) -> List[VectorDocument]:
179
+ """列出向量文档"""
180
+ if metadata_filter is None:
181
+ return list(self.documents.values())
182
+
183
+ return [doc for doc in self.documents.values()
184
+ if self._matches_filter(doc.metadata, metadata_filter)]
185
+
186
+ def count(self) -> int:
187
+ """获取向量数量"""
188
+ return len(self.documents)
189
+
190
+ def clear(self) -> None:
191
+ """清空所有向量"""
192
+ self.documents.clear()
193
+ # 重新初始化FAISS索引
194
+ try:
195
+ from sage.middleware.services.vdb.search_engine.faiss_index import FaissIndex
196
+ self.faiss_index = FaissIndex(
197
+ name="vdb_index",
198
+ dim=self.embedding_dimension,
199
+ config={
200
+ "index_type": self.index_type,
201
+ **self.faiss_config
202
+ }
203
+ )
204
+ except Exception as e:
205
+ self.logger.error(f"Error reinitializing FAISS index: {e}")
206
+
207
+ def save_index(self, path: str) -> bool:
208
+ """保存索引到磁盘"""
209
+ try:
210
+ self.faiss_index.save(path)
211
+ return True
212
+ except Exception as e:
213
+ self.logger.error(f"Error saving index: {e}")
214
+ return False
215
+
216
+ def load_index(self, path: str) -> bool:
217
+ """从磁盘加载索引"""
218
+ try:
219
+ from sage.middleware.services.vdb.search_engine.faiss_index import FaissIndex
220
+ self.faiss_index = FaissIndex(
221
+ name="vdb_index",
222
+ dim=self.embedding_dimension,
223
+ load_path=path
224
+ )
225
+ return True
226
+ except Exception as e:
227
+ self.logger.error(f"Error loading index: {e}")
228
+ return False
229
+
230
+ def _matches_filter(self, metadata: Dict[str, Any], filter_dict: Dict[str, Any]) -> bool:
231
+ """检查元数据是否匹配过滤条件"""
232
+ for key, value in filter_dict.items():
233
+ if key not in metadata:
234
+ return False
235
+ if metadata[key] != value:
236
+ return False
237
+ return True
238
+
239
+ def get_stats(self) -> Dict[str, Any]:
240
+ """获取索引统计信息"""
241
+ try:
242
+ return {
243
+ "total_vectors": self.count(),
244
+ "index_type": self.index_type,
245
+ "embedding_dimension": self.embedding_dimension,
246
+ "faiss_index_ntotal": getattr(self.faiss_index.index, 'ntotal', 0) if self.faiss_index.index else 0,
247
+ "max_vectors": getattr(self, 'max_vectors', -1)
248
+ }
249
+ except Exception as e:
250
+ self.logger.error(f"Error getting stats: {e}")
251
+ return {"error": str(e)}
252
+
253
+
254
+ class VDBService(BaseService):
255
+ """
256
+ VDB服务任务
257
+
258
+ 提供向量存储和相似性搜索功能,可以在SAGE DAG中作为服务节点使用
259
+ 使用嵌入式FAISS引擎,高性能的本地向量检索
260
+ """
261
+
262
+ def __init__(self, service_factory: 'ServiceFactory', ctx: 'ServiceContext' = None):
263
+ super().__init__(service_factory, ctx)
264
+
265
+ # 从service_factory获取配置
266
+ self.config: VDBConfig = getattr(service_factory, 'config', VDBConfig())
267
+
268
+ # 初始化FAISS后端
269
+ self.backend = FaissVDBBackend(
270
+ embedding_dimension=self.config.embedding_dimension,
271
+ index_type=self.config.index_type,
272
+ faiss_config=self.config.faiss_config or {}
273
+ )
274
+
275
+ self.logger.info(f"VDB Service '{self.service_name}' initialized with FAISS backend")
276
+ self.logger.info(f"Index type: {self.config.index_type}, Dimension: {self.config.embedding_dimension}")
277
+
278
+ def _start_service_instance(self):
279
+ """启动VDB服务实例"""
280
+ self.logger.info(f"VDB Service '{self.service_name}' started")
281
+
282
+ def _stop_service_instance(self):
283
+ """停止VDB服务实例"""
284
+ self.logger.info(f"VDB Service '{self.service_name}' stopped")
285
+
286
+ # VDB操作方法 - 这些方法可以通过服务调用机制被调用
287
+
288
+ def add_vectors(self, vectors: List[Dict[str, Any]]) -> List[str]:
289
+ """添加向量文档"""
290
+ self.logger.debug(f"Adding {len(vectors)} vectors")
291
+
292
+ # 转换输入格式
293
+ docs = []
294
+ for v in vectors:
295
+ doc = VectorDocument(
296
+ id=v.get('id', ''),
297
+ vector=v['vector'],
298
+ metadata=v.get('metadata', {}),
299
+ text=v.get('text')
300
+ )
301
+ docs.append(doc)
302
+
303
+ result = self.backend.add_vectors(docs)
304
+ self.logger.debug(f"Added {len(result)} vectors successfully")
305
+ return result
306
+
307
+ def search_vectors(self, query_vector: List[float], top_k: int = 5,
308
+ metadata_filter: Optional[Dict[str, Any]] = None) -> List[Dict[str, Any]]:
309
+ """搜索相似向量"""
310
+ self.logger.debug(f"Searching vectors with top_k={top_k}")
311
+
312
+ results = self.backend.search_vectors(query_vector, top_k, metadata_filter)
313
+
314
+ # 转换输出格式
315
+ formatted_results = []
316
+ for doc, distance in results:
317
+ formatted_results.append({
318
+ 'id': doc.id,
319
+ 'vector': doc.vector,
320
+ 'metadata': doc.metadata,
321
+ 'text': doc.text,
322
+ 'distance': distance,
323
+ 'created_at': doc.created_at
324
+ })
325
+
326
+ self.logger.debug(f"Search returned {len(formatted_results)} results")
327
+ return formatted_results
328
+
329
+ def get_vector(self, doc_id: str) -> Optional[Dict[str, Any]]:
330
+ """获取向量文档"""
331
+ self.logger.debug(f"Getting vector: {doc_id}")
332
+
333
+ doc = self.backend.get_vector(doc_id)
334
+ if doc:
335
+ return {
336
+ 'id': doc.id,
337
+ 'vector': doc.vector,
338
+ 'metadata': doc.metadata,
339
+ 'text': doc.text,
340
+ 'created_at': doc.created_at
341
+ }
342
+ return None
343
+
344
+ def delete_vectors(self, doc_ids: List[str]) -> int:
345
+ """删除向量文档"""
346
+ self.logger.debug(f"Deleting {len(doc_ids)} vectors")
347
+ result = self.backend.delete_vectors(doc_ids)
348
+ self.logger.debug(f"Deleted {result} vectors successfully")
349
+ return result
350
+
351
+ def list_vectors(self, metadata_filter: Optional[Dict[str, Any]] = None) -> List[Dict[str, Any]]:
352
+ """列出向量文档"""
353
+ self.logger.debug("Listing vectors")
354
+
355
+ docs = self.backend.list_vectors(metadata_filter)
356
+ results = []
357
+ for doc in docs:
358
+ results.append({
359
+ 'id': doc.id,
360
+ 'vector': doc.vector,
361
+ 'metadata': doc.metadata,
362
+ 'text': doc.text,
363
+ 'created_at': doc.created_at
364
+ })
365
+
366
+ self.logger.debug(f"Listed {len(results)} vectors")
367
+ return results
368
+
369
+ def count(self) -> int:
370
+ """获取向量数量"""
371
+ result = self.backend.count()
372
+ self.logger.debug(f"Vector count: {result}")
373
+ return result
374
+
375
+ def clear(self) -> None:
376
+ """清空所有向量"""
377
+ self.logger.debug("Clearing all vectors")
378
+ self.backend.clear()
379
+
380
+ def save_index(self, path: str) -> bool:
381
+ """保存索引到磁盘"""
382
+ self.logger.debug(f"Saving index to: {path}")
383
+ return self.backend.save_index(path)
384
+
385
+ def load_index(self, path: str) -> bool:
386
+ """从磁盘加载索引"""
387
+ self.logger.debug(f"Loading index from: {path}")
388
+ return self.backend.load_index(path)
389
+
390
+ def stats(self) -> Dict[str, Any]:
391
+ """获取服务统计信息"""
392
+ base_stats = self.get_statistics()
393
+ vdb_stats = self.backend.get_stats()
394
+ base_stats.update(vdb_stats)
395
+ return base_stats
396
+
397
+
398
+ # 工厂函数,用于在DAG中创建VDB服务
399
+ def create_vdb_service_factory(
400
+ service_name: str = "vdb_service",
401
+ embedding_dimension: int = 384,
402
+ index_type: str = "IndexFlatL2",
403
+ max_vectors: int = 1000000,
404
+ similarity_threshold: float = 0.8,
405
+ faiss_config: Optional[Dict[str, Any]] = None
406
+ ):
407
+ """
408
+ 创建VDB服务工厂
409
+
410
+ Args:
411
+ service_name: 服务名称
412
+ embedding_dimension: 向量维度
413
+ index_type: FAISS索引类型 ("IndexFlatL2", "IndexHNSWFlat", "IndexIVFFlat", etc.)
414
+ max_vectors: 最大向量数量
415
+ similarity_threshold: 相似度阈值
416
+ faiss_config: FAISS索引配置
417
+
418
+ Returns:
419
+ ServiceFactory: 可以用于注册到环境的服务工厂
420
+ """
421
+ from sage.core.factory.service_factory import ServiceFactory
422
+
423
+ config = VDBConfig(
424
+ embedding_dimension=embedding_dimension,
425
+ index_type=index_type,
426
+ max_vectors=max_vectors,
427
+ similarity_threshold=similarity_threshold,
428
+ faiss_config=faiss_config or {}
429
+ )
430
+
431
+ factory = ServiceFactory(service_name, VDBService)
432
+ factory.config = config
433
+ return factory
@@ -0,0 +1,5 @@
1
+ """
2
+ Llm module for SAGE framework
3
+ """
4
+
5
+ __version__ = "1.0.0"
@@ -0,0 +1,35 @@
1
+ """
2
+ Embedding methods and models for SAGE middleware.
3
+ """
4
+
5
+ from .embedding_api import apply_embedding_model
6
+ from .embedding_model import EmbeddingModel
7
+
8
+ # Import specific embedding implementations
9
+ from . import hf
10
+ from . import ollama
11
+ from . import siliconcloud
12
+ from . import openai
13
+ from . import bedrock
14
+ from . import zhipu
15
+ from . import mockembedder
16
+ from . import _cohere
17
+ from . import nvidia_openai
18
+ from . import lollms
19
+ from . import jina
20
+
21
+ __all__ = [
22
+ 'apply_embedding_model',
23
+ 'EmbeddingModel',
24
+ 'hf',
25
+ 'ollama',
26
+ 'siliconcloud',
27
+ 'openai',
28
+ 'bedrock',
29
+ 'zhipu',
30
+ 'mockembedder',
31
+ '_cohere',
32
+ 'nvidia_openai',
33
+ 'lollms',
34
+ 'jina'
35
+ ]
@@ -0,0 +1,68 @@
1
+ import os
2
+ import cohere
3
+ import asyncio
4
+
5
+ import numpy as np
6
+
7
+
8
+ async def cohere_embed(
9
+ texts: list[str], api_key: str, model: str = "embed-multilingual-v3.0", input_type: str = "classification",
10
+ embedding_types: list[str] = ["float"]
11
+ ) -> list[float]:
12
+ if api_key is None:
13
+ api_key = os.environ.get("COHERE_API_KEY")
14
+ # print(api_key)
15
+ co = cohere.AsyncClient(api_key=api_key)
16
+
17
+ response = await co.embed(
18
+ texts=texts,
19
+ model=model,
20
+ input_type=input_type,
21
+ # embedding_types=embedding_types
22
+ )
23
+ return response.embeddings
24
+
25
+ import os
26
+ import cohere
27
+
28
+ def cohere_embed_sync(
29
+ texts: list[str],
30
+ api_key: str = None,
31
+ model: str = "embed-multilingual-v3.0",
32
+ input_type: str = "classification",
33
+ embedding_types: list[str] = ["float"]
34
+ ) -> list[list[float]]:
35
+ """
36
+ 同步版本:使用 Cohere 同步客户端生成文本 embeddings。
37
+
38
+ Args:
39
+ texts: 文本列表
40
+ api_key: Cohere API Key
41
+ model: 模型名称
42
+ input_type: 输入类型,如 classification、search_document 等
43
+ embedding_types: 嵌入格式(默认 float)
44
+
45
+ Returns:
46
+ list[list[float]]: 每个文本对应的嵌入向量
47
+ """
48
+ if api_key is None:
49
+ api_key = os.environ.get("COHERE_API_KEY")
50
+ if api_key is None:
51
+ raise ValueError("Cohere API key must be provided.")
52
+
53
+ co = cohere.Client(api_key=api_key)
54
+
55
+ response = co.embed(
56
+ texts=texts,
57
+ model=model,
58
+ input_type=input_type,
59
+ embedding_types=embedding_types,
60
+ )
61
+ return response.embeddings
62
+
63
+
64
+
65
+
66
+
67
+
68
+