veadk-python 0.2.6__py3-none-any.whl → 0.2.8__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 veadk-python might be problematic. Click here for more details.
- veadk/agent.py +11 -18
- veadk/agent_builder.py +94 -0
- veadk/{database/__init__.py → auth/base_auth.py} +7 -2
- veadk/auth/veauth/apmplus_veauth.py +65 -0
- veadk/auth/veauth/ark_veauth.py +77 -0
- veadk/auth/veauth/base_veauth.py +50 -0
- veadk/auth/veauth/opensearch_veauth.py +75 -0
- veadk/auth/veauth/postgresql_veauth.py +75 -0
- veadk/auth/veauth/prompt_pilot_veauth.py +60 -0
- veadk/auth/veauth/vesearch_veauth.py +62 -0
- veadk/cli/cli.py +4 -0
- veadk/cli/cli_deploy.py +3 -2
- veadk/cli/cli_eval.py +160 -0
- veadk/cli/cli_init.py +1 -1
- veadk/cli/cli_pipeline.py +220 -0
- veadk/cli/cli_prompt.py +4 -4
- veadk/cli/cli_web.py +3 -1
- veadk/config.py +45 -81
- veadk/configs/database_configs.py +117 -0
- veadk/configs/model_configs.py +74 -0
- veadk/configs/tool_configs.py +42 -0
- veadk/configs/tracing_configs.py +110 -0
- veadk/consts.py +13 -1
- veadk/evaluation/base_evaluator.py +60 -44
- veadk/evaluation/deepeval_evaluator/deepeval_evaluator.py +18 -12
- veadk/evaluation/eval_set_recorder.py +2 -2
- veadk/integrations/ve_code_pipeline/__init__.py +13 -0
- veadk/integrations/ve_code_pipeline/ve_code_pipeline.py +431 -0
- veadk/integrations/ve_cozeloop/__init__.py +13 -0
- veadk/integrations/ve_cozeloop/ve_cozeloop.py +96 -0
- veadk/integrations/ve_cr/ve_cr.py +20 -5
- veadk/integrations/ve_faas/template/cookiecutter.json +1 -1
- veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/deploy.py +2 -2
- veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/agent.py +1 -1
- veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/run.sh +1 -5
- veadk/integrations/ve_faas/ve_faas.py +351 -36
- veadk/integrations/ve_prompt_pilot/ve_prompt_pilot.py +6 -3
- veadk/integrations/ve_tls/__init__.py +13 -0
- veadk/integrations/ve_tls/utils.py +117 -0
- veadk/integrations/ve_tls/ve_tls.py +208 -0
- veadk/integrations/ve_tos/ve_tos.py +71 -75
- veadk/knowledgebase/backends/__init__.py +13 -0
- veadk/knowledgebase/backends/base_backend.py +59 -0
- veadk/knowledgebase/backends/in_memory_backend.py +82 -0
- veadk/knowledgebase/backends/opensearch_backend.py +136 -0
- veadk/knowledgebase/backends/redis_backend.py +144 -0
- veadk/knowledgebase/backends/utils.py +91 -0
- veadk/knowledgebase/backends/vikingdb_knowledge_backend.py +412 -0
- veadk/knowledgebase/knowledgebase.py +109 -55
- veadk/memory/__init__.py +22 -0
- veadk/memory/long_term_memory.py +120 -51
- veadk/memory/long_term_memory_backends/__init__.py +13 -0
- veadk/{database/base_database.py → memory/long_term_memory_backends/base_backend.py} +10 -22
- veadk/memory/long_term_memory_backends/in_memory_backend.py +65 -0
- veadk/memory/long_term_memory_backends/opensearch_backend.py +120 -0
- veadk/memory/long_term_memory_backends/redis_backend.py +127 -0
- veadk/memory/long_term_memory_backends/vikingdb_memory_backend.py +148 -0
- veadk/memory/short_term_memory.py +80 -72
- veadk/memory/short_term_memory_backends/__init__.py +13 -0
- veadk/memory/short_term_memory_backends/base_backend.py +31 -0
- veadk/memory/short_term_memory_backends/mysql_backend.py +41 -0
- veadk/memory/short_term_memory_backends/postgresql_backend.py +41 -0
- veadk/memory/short_term_memory_backends/sqlite_backend.py +48 -0
- veadk/memory/short_term_memory_processor.py +9 -4
- veadk/runner.py +204 -247
- veadk/tools/builtin_tools/vesearch.py +2 -2
- veadk/tools/builtin_tools/video_generate.py +27 -20
- veadk/tools/builtin_tools/web_scraper.py +1 -1
- veadk/tools/builtin_tools/web_search.py +7 -7
- veadk/tools/load_knowledgebase_tool.py +1 -1
- veadk/tracing/telemetry/attributes/extractors/llm_attributes_extractors.py +20 -2
- veadk/tracing/telemetry/exporters/apmplus_exporter.py +178 -14
- veadk/tracing/telemetry/exporters/cozeloop_exporter.py +6 -9
- veadk/tracing/telemetry/exporters/inmemory_exporter.py +22 -8
- veadk/tracing/telemetry/exporters/tls_exporter.py +6 -10
- veadk/tracing/telemetry/opentelemetry_tracer.py +5 -8
- veadk/tracing/telemetry/telemetry.py +66 -60
- veadk/utils/logger.py +1 -1
- veadk/utils/misc.py +63 -0
- veadk/utils/volcengine_sign.py +6 -2
- veadk/version.py +1 -1
- {veadk_python-0.2.6.dist-info → veadk_python-0.2.8.dist-info}/METADATA +16 -3
- {veadk_python-0.2.6.dist-info → veadk_python-0.2.8.dist-info}/RECORD +93 -64
- veadk/database/database_adapter.py +0 -368
- veadk/database/database_factory.py +0 -80
- veadk/database/kv/redis_database.py +0 -159
- veadk/database/local_database.py +0 -61
- veadk/database/relational/mysql_database.py +0 -173
- veadk/database/vector/opensearch_vector_database.py +0 -263
- veadk/database/vector/type.py +0 -50
- veadk/database/viking/viking_database.py +0 -471
- veadk/database/viking/viking_memory_db.py +0 -525
- /veadk/{database/kv → auth}/__init__.py +0 -0
- /veadk/{database/relational → auth/veauth}/__init__.py +0 -0
- /veadk/{database/vector/__init__.py → auth/veauth/cozeloop_veauth.py} +0 -0
- /veadk/{database/viking → configs}/__init__.py +0 -0
- /veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/{{{ cookiecutter.app_name|replace('-', '_') }} → {{ cookiecutter.app_name }}}/__init__.py +0 -0
- /veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/{{{ cookiecutter.app_name|replace('-', '_') }} → {{ cookiecutter.app_name }}}/agent.py +0 -0
- {veadk_python-0.2.6.dist-info → veadk_python-0.2.8.dist-info}/WHEEL +0 -0
- {veadk_python-0.2.6.dist-info → veadk_python-0.2.8.dist-info}/entry_points.txt +0 -0
- {veadk_python-0.2.6.dist-info → veadk_python-0.2.8.dist-info}/licenses/LICENSE +0 -0
- {veadk_python-0.2.6.dist-info → veadk_python-0.2.8.dist-info}/top_level.txt +0 -0
|
@@ -1,368 +0,0 @@
|
|
|
1
|
-
# Copyright (c) 2025 Beijing Volcano Engine Technology Co., Ltd. and/or its affiliates.
|
|
2
|
-
#
|
|
3
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
-
# you may not use this file except in compliance with the License.
|
|
5
|
-
# You may obtain a copy of the License at
|
|
6
|
-
#
|
|
7
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
-
#
|
|
9
|
-
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
-
# See the License for the specific language governing permissions and
|
|
13
|
-
# limitations under the License.
|
|
14
|
-
|
|
15
|
-
import re
|
|
16
|
-
import time
|
|
17
|
-
from typing import BinaryIO, TextIO
|
|
18
|
-
|
|
19
|
-
from veadk.database.base_database import BaseDatabase
|
|
20
|
-
from veadk.utils.logger import get_logger
|
|
21
|
-
|
|
22
|
-
logger = get_logger(__name__)
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
class KVDatabaseAdapter:
|
|
26
|
-
def __init__(self, client):
|
|
27
|
-
from veadk.database.kv.redis_database import RedisDatabase
|
|
28
|
-
|
|
29
|
-
self.client: RedisDatabase = client
|
|
30
|
-
|
|
31
|
-
def add(self, data: list[str], index: str):
|
|
32
|
-
logger.debug(f"Adding documents to Redis database: index={index}")
|
|
33
|
-
|
|
34
|
-
try:
|
|
35
|
-
for _data in data:
|
|
36
|
-
self.client.add(key=index, value=_data)
|
|
37
|
-
logger.debug(f"Added {len(data)} texts to Redis database: index={index}")
|
|
38
|
-
except Exception as e:
|
|
39
|
-
logger.error(
|
|
40
|
-
f"Failed to add data to Redis database: index={index} error={e}"
|
|
41
|
-
)
|
|
42
|
-
raise e
|
|
43
|
-
|
|
44
|
-
def query(self, query: str, index: str, top_k: int = 0) -> list:
|
|
45
|
-
logger.debug(f"Querying Redis database: index={index} query={query}")
|
|
46
|
-
|
|
47
|
-
# ignore top_k, as KV search only return one result
|
|
48
|
-
_ = top_k
|
|
49
|
-
|
|
50
|
-
try:
|
|
51
|
-
result = self.client.query(key=index, query=query)
|
|
52
|
-
return result
|
|
53
|
-
except Exception as e:
|
|
54
|
-
logger.error(f"Failed to search from Redis: index={index} error={e}")
|
|
55
|
-
raise e
|
|
56
|
-
|
|
57
|
-
def delete_doc(self, index: str, id: str) -> bool:
|
|
58
|
-
logger.debug(f"Deleting document from Redis database: index={index} id={id}")
|
|
59
|
-
try:
|
|
60
|
-
# For Redis, we need to handle deletion differently since RedisDatabase.delete_doc
|
|
61
|
-
# takes a key and a single id
|
|
62
|
-
result = self.client.delete_doc(key=index, id=id)
|
|
63
|
-
return result
|
|
64
|
-
except Exception as e:
|
|
65
|
-
logger.error(
|
|
66
|
-
f"Failed to delete document from Redis database: index={index} id={id} error={e}"
|
|
67
|
-
)
|
|
68
|
-
return False
|
|
69
|
-
|
|
70
|
-
def list_docs(self, index: str, offset: int = 0, limit: int = 100) -> list[dict]:
|
|
71
|
-
logger.debug(f"Listing documents from Redis database: index={index}")
|
|
72
|
-
try:
|
|
73
|
-
# Get all documents from Redis
|
|
74
|
-
docs = self.client.list_docs(key=index)
|
|
75
|
-
|
|
76
|
-
# Apply offset and limit for pagination
|
|
77
|
-
return docs[offset : offset + limit]
|
|
78
|
-
except Exception as e:
|
|
79
|
-
logger.error(
|
|
80
|
-
f"Failed to list documents from Redis database: index={index} error={e}"
|
|
81
|
-
)
|
|
82
|
-
return []
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
class RelationalDatabaseAdapter:
|
|
86
|
-
def __init__(self, client):
|
|
87
|
-
from veadk.database.relational.mysql_database import MysqlDatabase
|
|
88
|
-
|
|
89
|
-
self.client: MysqlDatabase = client
|
|
90
|
-
|
|
91
|
-
def create_table(self, table_name: str):
|
|
92
|
-
logger.debug(f"Creating table for SQL database: table_name={table_name}")
|
|
93
|
-
|
|
94
|
-
sql = f"""
|
|
95
|
-
CREATE TABLE `{table_name}` (
|
|
96
|
-
`id` BIGINT AUTO_INCREMENT PRIMARY KEY,
|
|
97
|
-
`data` TEXT NOT NULL,
|
|
98
|
-
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
99
|
-
) ENGINE=InnoDB DEFAULT CHARSET={self.client.config.charset};
|
|
100
|
-
"""
|
|
101
|
-
self.client.add(sql)
|
|
102
|
-
|
|
103
|
-
def add(self, data: list[str], index: str):
|
|
104
|
-
logger.debug(
|
|
105
|
-
f"Adding documents to SQL database: table_name={index} data_len={len(data)}"
|
|
106
|
-
)
|
|
107
|
-
|
|
108
|
-
if not self.client.table_exists(index):
|
|
109
|
-
logger.warning(f"Table {index} does not exist, creating a new table.")
|
|
110
|
-
self.create_table(index)
|
|
111
|
-
|
|
112
|
-
for _data in data:
|
|
113
|
-
sql = f"""
|
|
114
|
-
INSERT INTO `{index}` (`data`)
|
|
115
|
-
VALUES (%s);
|
|
116
|
-
"""
|
|
117
|
-
self.client.add(sql, params=(_data,))
|
|
118
|
-
logger.debug(f"Added {len(data)} texts to table {index}.")
|
|
119
|
-
|
|
120
|
-
def query(self, query: str, index: str, top_k: int) -> list[str]:
|
|
121
|
-
logger.debug(
|
|
122
|
-
f"Querying SQL database: table_name={index} query={query} top_k={top_k}"
|
|
123
|
-
)
|
|
124
|
-
|
|
125
|
-
if not self.client.table_exists(index):
|
|
126
|
-
logger.warning(
|
|
127
|
-
f"Querying SQL database, but table `{index}` does not exist, returning empty list."
|
|
128
|
-
)
|
|
129
|
-
return []
|
|
130
|
-
|
|
131
|
-
sql = f"""
|
|
132
|
-
SELECT `data` FROM `{index}` ORDER BY `created_at` DESC LIMIT {top_k};
|
|
133
|
-
"""
|
|
134
|
-
results = self.client.query(sql)
|
|
135
|
-
|
|
136
|
-
return [item["data"] for item in results]
|
|
137
|
-
|
|
138
|
-
def delete_doc(self, index: str, id: str) -> bool:
|
|
139
|
-
logger.debug(f"Deleting document from SQL database: table_name={index} id={id}")
|
|
140
|
-
try:
|
|
141
|
-
# Convert single id to list for the client method
|
|
142
|
-
result = self.client.delete_doc(table=index, ids=[int(id)])
|
|
143
|
-
return result
|
|
144
|
-
except Exception as e:
|
|
145
|
-
logger.error(
|
|
146
|
-
f"Failed to delete document from SQL database: table_name={index} id={id} error={e}"
|
|
147
|
-
)
|
|
148
|
-
return False
|
|
149
|
-
|
|
150
|
-
def list_docs(self, index: str, offset: int = 0, limit: int = 100) -> list[dict]:
|
|
151
|
-
logger.debug(f"Listing documents from SQL database: table_name={index}")
|
|
152
|
-
try:
|
|
153
|
-
return self.client.list_docs(table=index, offset=offset, limit=limit)
|
|
154
|
-
except Exception as e:
|
|
155
|
-
logger.error(
|
|
156
|
-
f"Failed to list documents from SQL database: table_name={index} error={e}"
|
|
157
|
-
)
|
|
158
|
-
return []
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
class VectorDatabaseAdapter:
|
|
162
|
-
def __init__(self, client):
|
|
163
|
-
from veadk.database.vector.opensearch_vector_database import (
|
|
164
|
-
OpenSearchVectorDatabase,
|
|
165
|
-
)
|
|
166
|
-
|
|
167
|
-
self.client: OpenSearchVectorDatabase = client
|
|
168
|
-
|
|
169
|
-
def _validate_index(self, index: str):
|
|
170
|
-
"""
|
|
171
|
-
Verify whether the string conforms to the naming rules of index_name in OpenSearch.
|
|
172
|
-
https://docs.opensearch.org/2.8/api-reference/index-apis/create-index/
|
|
173
|
-
"""
|
|
174
|
-
if not (
|
|
175
|
-
isinstance(index, str)
|
|
176
|
-
and not index.startswith(("_", "-"))
|
|
177
|
-
and index.islower()
|
|
178
|
-
and re.match(r"^[a-z0-9_\-.]+$", index)
|
|
179
|
-
):
|
|
180
|
-
raise ValueError(
|
|
181
|
-
"The index name does not conform to the naming rules of OpenSearch"
|
|
182
|
-
)
|
|
183
|
-
|
|
184
|
-
def add(self, data: list[str], index: str):
|
|
185
|
-
self._validate_index(index)
|
|
186
|
-
|
|
187
|
-
logger.debug(
|
|
188
|
-
f"Adding documents to vector database: index={index} data_len={len(data)}"
|
|
189
|
-
)
|
|
190
|
-
|
|
191
|
-
self.client.add(data, collection_name=index)
|
|
192
|
-
|
|
193
|
-
def query(self, query: str, index: str, top_k: int) -> list[str]:
|
|
194
|
-
logger.debug(
|
|
195
|
-
f"Querying vector database: collection_name={index} query={query} top_k={top_k}"
|
|
196
|
-
)
|
|
197
|
-
|
|
198
|
-
return self.client.query(
|
|
199
|
-
query=query,
|
|
200
|
-
collection_name=index,
|
|
201
|
-
top_k=top_k,
|
|
202
|
-
)
|
|
203
|
-
|
|
204
|
-
def delete_doc(self, index: str, id: str) -> bool:
|
|
205
|
-
self._validate_index(index)
|
|
206
|
-
logger.debug(f"Deleting documents from vector database: index={index} id={id}")
|
|
207
|
-
try:
|
|
208
|
-
self.client.delete_by_id(collection_name=index, id=id)
|
|
209
|
-
return True
|
|
210
|
-
except Exception as e:
|
|
211
|
-
logger.error(
|
|
212
|
-
f"Failed to delete document from vector database: index={index} id={id} error={e}"
|
|
213
|
-
)
|
|
214
|
-
return False
|
|
215
|
-
|
|
216
|
-
def list_docs(self, index: str, offset: int = 0, limit: int = 1000) -> list[dict]:
|
|
217
|
-
self._validate_index(index)
|
|
218
|
-
logger.debug(f"Listing documents from vector database: index={index}")
|
|
219
|
-
return self.client.list_docs(collection_name=index, offset=offset, limit=limit)
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
class VikingDatabaseAdapter:
|
|
223
|
-
def __init__(self, client):
|
|
224
|
-
from veadk.database.viking.viking_database import VikingDatabase
|
|
225
|
-
|
|
226
|
-
self.client: VikingDatabase = client
|
|
227
|
-
|
|
228
|
-
def _validate_index(self, index: str):
|
|
229
|
-
"""
|
|
230
|
-
Only English letters, numbers, and underscores (_) are allowed.
|
|
231
|
-
It must start with an English letter and cannot be empty. Length requirement: [1, 128].
|
|
232
|
-
For details, please see: https://www.volcengine.com/docs/84313/1254542?lang=zh
|
|
233
|
-
"""
|
|
234
|
-
if not (
|
|
235
|
-
isinstance(index, str)
|
|
236
|
-
and 0 < len(index) <= 128
|
|
237
|
-
and re.fullmatch(r"^[a-zA-Z][a-zA-Z0-9_]*$", index)
|
|
238
|
-
):
|
|
239
|
-
raise ValueError(
|
|
240
|
-
"The index name does not conform to the rules: it must start with an English letter, contain only letters, numbers, and underscores, and have a length of 1-128."
|
|
241
|
-
)
|
|
242
|
-
|
|
243
|
-
def get_or_create_collection(self, collection_name: str):
|
|
244
|
-
if not self.client.collection_exists(collection_name):
|
|
245
|
-
logger.warning(
|
|
246
|
-
f"Collection {collection_name} does not exist, creating a new collection."
|
|
247
|
-
)
|
|
248
|
-
self.client.create_collection(collection_name)
|
|
249
|
-
|
|
250
|
-
# After creation, it is necessary to wait for a while.
|
|
251
|
-
count = 0
|
|
252
|
-
while not self.client.collection_exists(collection_name):
|
|
253
|
-
print("here")
|
|
254
|
-
time.sleep(1)
|
|
255
|
-
count += 1
|
|
256
|
-
if count > 60:
|
|
257
|
-
raise TimeoutError(
|
|
258
|
-
f"Collection {collection_name} not created after 50 seconds"
|
|
259
|
-
)
|
|
260
|
-
|
|
261
|
-
def add(
|
|
262
|
-
self, data: str | list[str] | TextIO | BinaryIO | bytes, index: str, **kwargs
|
|
263
|
-
):
|
|
264
|
-
self._validate_index(index)
|
|
265
|
-
|
|
266
|
-
logger.debug(f"Adding documents to Viking database: collection_name={index}")
|
|
267
|
-
|
|
268
|
-
self.get_or_create_collection(index)
|
|
269
|
-
self.client.add(data, collection_name=index, **kwargs)
|
|
270
|
-
|
|
271
|
-
def query(self, query: str, index: str, top_k: int) -> list[str]:
|
|
272
|
-
self._validate_index(index)
|
|
273
|
-
|
|
274
|
-
logger.debug(f"Querying Viking database: collection_name={index} query={query}")
|
|
275
|
-
|
|
276
|
-
if not self.client.collection_exists(index):
|
|
277
|
-
return []
|
|
278
|
-
|
|
279
|
-
return self.client.query(query, collection_name=index, top_k=top_k)
|
|
280
|
-
|
|
281
|
-
def delete_doc(self, index: str, id: str) -> bool:
|
|
282
|
-
self._validate_index(index)
|
|
283
|
-
logger.debug(f"Deleting documents from vector database: index={index} id={id}")
|
|
284
|
-
return self.client.delete_by_id(collection_name=index, id=id)
|
|
285
|
-
|
|
286
|
-
def list_docs(self, index: str, offset: int, limit: int) -> list[dict]:
|
|
287
|
-
self._validate_index(index)
|
|
288
|
-
logger.debug(f"Listing documents from vector database: index={index}")
|
|
289
|
-
return self.client.list_docs(collection_name=index, offset=offset, limit=limit)
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
class VikingMemoryDatabaseAdapter:
|
|
293
|
-
def __init__(self, client):
|
|
294
|
-
from veadk.database.viking.viking_memory_db import VikingMemoryDatabase
|
|
295
|
-
|
|
296
|
-
self.client: VikingMemoryDatabase = client
|
|
297
|
-
|
|
298
|
-
def _validate_index(self, index: str):
|
|
299
|
-
if not (
|
|
300
|
-
isinstance(index, str)
|
|
301
|
-
and 1 <= len(index) <= 128
|
|
302
|
-
and re.fullmatch(r"^[a-zA-Z][a-zA-Z0-9_]*$", index)
|
|
303
|
-
):
|
|
304
|
-
raise ValueError(
|
|
305
|
-
"The index name does not conform to the rules: it must start with an English letter, contain only letters, numbers, and underscores, and have a length of 1-128."
|
|
306
|
-
)
|
|
307
|
-
|
|
308
|
-
def add(self, data: list[str], index: str, **kwargs):
|
|
309
|
-
self._validate_index(index)
|
|
310
|
-
|
|
311
|
-
logger.debug(
|
|
312
|
-
f"Adding documents to Viking database memory: collection_name={index} data_len={len(data)}"
|
|
313
|
-
)
|
|
314
|
-
|
|
315
|
-
self.client.add(data, collection_name=index, **kwargs)
|
|
316
|
-
|
|
317
|
-
def query(self, query: str, index: str, top_k: int, **kwargs):
|
|
318
|
-
self._validate_index(index)
|
|
319
|
-
|
|
320
|
-
logger.debug(
|
|
321
|
-
f"Querying Viking database memory: collection_name={index} query={query} top_k={top_k}"
|
|
322
|
-
)
|
|
323
|
-
|
|
324
|
-
result = self.client.query(query, collection_name=index, top_k=top_k, **kwargs)
|
|
325
|
-
return result
|
|
326
|
-
|
|
327
|
-
def delete_docs(self, index: str, ids: list[int]):
|
|
328
|
-
raise NotImplementedError("VikingMemoryDatabase does not support delete_docs")
|
|
329
|
-
|
|
330
|
-
def list_docs(self, index: str):
|
|
331
|
-
raise NotImplementedError("VikingMemoryDatabase does not support list_docs")
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
class LocalDatabaseAdapter:
|
|
335
|
-
def __init__(self, client):
|
|
336
|
-
from veadk.database.local_database import LocalDataBase
|
|
337
|
-
|
|
338
|
-
self.client: LocalDataBase = client
|
|
339
|
-
|
|
340
|
-
def add(self, data: list[str], **kwargs):
|
|
341
|
-
self.client.add(data)
|
|
342
|
-
|
|
343
|
-
def query(self, query: str, **kwargs):
|
|
344
|
-
return self.client.query(query, **kwargs)
|
|
345
|
-
|
|
346
|
-
def delete_doc(self, index: str, id: str) -> bool:
|
|
347
|
-
return self.client.delete_doc(id)
|
|
348
|
-
|
|
349
|
-
def list_docs(self, index: str, offset: int = 0, limit: int = 100) -> list[dict]:
|
|
350
|
-
return self.client.list_docs(offset=offset, limit=limit)
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
MAPPING = {
|
|
354
|
-
"RedisDatabase": KVDatabaseAdapter,
|
|
355
|
-
"MysqlDatabase": RelationalDatabaseAdapter,
|
|
356
|
-
"LocalDataBase": LocalDatabaseAdapter,
|
|
357
|
-
"VikingDatabase": VikingDatabaseAdapter,
|
|
358
|
-
"OpenSearchVectorDatabase": VectorDatabaseAdapter,
|
|
359
|
-
"VikingMemoryDatabase": VikingMemoryDatabaseAdapter,
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
def get_knowledgebase_database_adapter(database_client: BaseDatabase):
|
|
364
|
-
return MAPPING[type(database_client).__name__](client=database_client)
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
def get_long_term_memory_database_adapter(database_client: BaseDatabase):
|
|
368
|
-
return MAPPING[type(database_client).__name__](client=database_client)
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
# Copyright (c) 2025 Beijing Volcano Engine Technology Co., Ltd. and/or its affiliates.
|
|
2
|
-
#
|
|
3
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
-
# you may not use this file except in compliance with the License.
|
|
5
|
-
# You may obtain a copy of the License at
|
|
6
|
-
#
|
|
7
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
-
#
|
|
9
|
-
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
-
# See the License for the specific language governing permissions and
|
|
13
|
-
# limitations under the License.
|
|
14
|
-
|
|
15
|
-
from veadk.utils.logger import get_logger
|
|
16
|
-
|
|
17
|
-
from .base_database import BaseDatabase
|
|
18
|
-
|
|
19
|
-
logger = get_logger(__name__)
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
class DatabaseBackend:
|
|
23
|
-
OPENSEARCH = "opensearch"
|
|
24
|
-
LOCAL = "local"
|
|
25
|
-
MYSQL = "mysql"
|
|
26
|
-
REDIS = "redis"
|
|
27
|
-
VIKING = "viking"
|
|
28
|
-
VIKING_MEM = "viking_mem"
|
|
29
|
-
|
|
30
|
-
@classmethod
|
|
31
|
-
def get_attr(cls) -> set[str]:
|
|
32
|
-
return {
|
|
33
|
-
value
|
|
34
|
-
for attr, value in cls.__dict__.items()
|
|
35
|
-
if not attr.startswith("__") and attr != "get_attr"
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
class DatabaseFactory:
|
|
40
|
-
@staticmethod
|
|
41
|
-
def create(backend: str, config=None) -> BaseDatabase:
|
|
42
|
-
if backend not in DatabaseBackend.get_attr():
|
|
43
|
-
logger.warning(f"Unknown backend: {backend}), change backend to `local`")
|
|
44
|
-
backend = "local"
|
|
45
|
-
|
|
46
|
-
if backend == DatabaseBackend.LOCAL:
|
|
47
|
-
from .local_database import LocalDataBase
|
|
48
|
-
|
|
49
|
-
return LocalDataBase()
|
|
50
|
-
if backend == DatabaseBackend.OPENSEARCH:
|
|
51
|
-
from .vector.opensearch_vector_database import OpenSearchVectorDatabase
|
|
52
|
-
|
|
53
|
-
return (
|
|
54
|
-
OpenSearchVectorDatabase()
|
|
55
|
-
if config is None
|
|
56
|
-
else OpenSearchVectorDatabase(config=config)
|
|
57
|
-
)
|
|
58
|
-
if backend == DatabaseBackend.MYSQL:
|
|
59
|
-
from .relational.mysql_database import MysqlDatabase
|
|
60
|
-
|
|
61
|
-
return MysqlDatabase() if config is None else MysqlDatabase(config=config)
|
|
62
|
-
if backend == DatabaseBackend.REDIS:
|
|
63
|
-
from .kv.redis_database import RedisDatabase
|
|
64
|
-
|
|
65
|
-
return RedisDatabase() if config is None else RedisDatabase(config=config)
|
|
66
|
-
if backend == DatabaseBackend.VIKING:
|
|
67
|
-
from .viking.viking_database import VikingDatabase
|
|
68
|
-
|
|
69
|
-
return VikingDatabase() if config is None else VikingDatabase(config=config)
|
|
70
|
-
|
|
71
|
-
if backend == DatabaseBackend.VIKING_MEM:
|
|
72
|
-
from .viking.viking_memory_db import VikingMemoryDatabase
|
|
73
|
-
|
|
74
|
-
return (
|
|
75
|
-
VikingMemoryDatabase()
|
|
76
|
-
if config is None
|
|
77
|
-
else VikingMemoryDatabase(config=config)
|
|
78
|
-
)
|
|
79
|
-
else:
|
|
80
|
-
raise ValueError(f"Unsupported database type: {backend}")
|
|
@@ -1,159 +0,0 @@
|
|
|
1
|
-
# Copyright (c) 2025 Beijing Volcano Engine Technology Co., Ltd. and/or its affiliates.
|
|
2
|
-
#
|
|
3
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
-
# you may not use this file except in compliance with the License.
|
|
5
|
-
# You may obtain a copy of the License at
|
|
6
|
-
#
|
|
7
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
-
#
|
|
9
|
-
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
-
# See the License for the specific language governing permissions and
|
|
13
|
-
# limitations under the License.
|
|
14
|
-
|
|
15
|
-
from __future__ import annotations
|
|
16
|
-
|
|
17
|
-
from typing import Any
|
|
18
|
-
|
|
19
|
-
import redis
|
|
20
|
-
from pydantic import BaseModel, Field
|
|
21
|
-
from typing_extensions import override
|
|
22
|
-
|
|
23
|
-
from veadk.config import getenv
|
|
24
|
-
from veadk.utils.logger import get_logger
|
|
25
|
-
|
|
26
|
-
from ..base_database import BaseDatabase
|
|
27
|
-
|
|
28
|
-
logger = get_logger(__name__)
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
class RedisDatabaseConfig(BaseModel):
|
|
32
|
-
host: str = Field(
|
|
33
|
-
default_factory=lambda: getenv("DATABASE_REDIS_HOST"),
|
|
34
|
-
description="Redis host",
|
|
35
|
-
)
|
|
36
|
-
port: int = Field(
|
|
37
|
-
default_factory=lambda: int(getenv("DATABASE_REDIS_PORT")),
|
|
38
|
-
description="Redis port",
|
|
39
|
-
)
|
|
40
|
-
db: int = Field(
|
|
41
|
-
default_factory=lambda: int(getenv("DATABASE_REDIS_DB")),
|
|
42
|
-
description="Redis db",
|
|
43
|
-
)
|
|
44
|
-
password: str = Field(
|
|
45
|
-
default_factory=lambda: getenv("DATABASE_REDIS_PASSWORD"),
|
|
46
|
-
description="Redis password",
|
|
47
|
-
)
|
|
48
|
-
decode_responses: bool = Field(
|
|
49
|
-
default=True,
|
|
50
|
-
description="Redis decode responses",
|
|
51
|
-
)
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
class RedisDatabase(BaseModel, BaseDatabase):
|
|
55
|
-
config: RedisDatabaseConfig = Field(default_factory=RedisDatabaseConfig)
|
|
56
|
-
|
|
57
|
-
def model_post_init(self, context: Any, /) -> None:
|
|
58
|
-
try:
|
|
59
|
-
self._client = redis.StrictRedis(
|
|
60
|
-
host=self.config.host,
|
|
61
|
-
port=self.config.port,
|
|
62
|
-
db=self.config.db,
|
|
63
|
-
password=self.config.password,
|
|
64
|
-
decode_responses=self.config.decode_responses,
|
|
65
|
-
)
|
|
66
|
-
|
|
67
|
-
self._client.ping()
|
|
68
|
-
logger.info("Connected to Redis successfully.")
|
|
69
|
-
except Exception as e:
|
|
70
|
-
logger.error(f"Failed to connect to Redis: {e}")
|
|
71
|
-
raise e
|
|
72
|
-
|
|
73
|
-
@override
|
|
74
|
-
def add(self, key: str, value: str, **kwargs):
|
|
75
|
-
try:
|
|
76
|
-
self._client.rpush(key, value)
|
|
77
|
-
except Exception as e:
|
|
78
|
-
logger.error(f"Failed to add value to Redis list key `{key}`: {e}")
|
|
79
|
-
raise e
|
|
80
|
-
|
|
81
|
-
@override
|
|
82
|
-
def query(self, key: str, query: str = "", **kwargs) -> list:
|
|
83
|
-
try:
|
|
84
|
-
result = self._client.lrange(key, 0, -1)
|
|
85
|
-
return result # type: ignore
|
|
86
|
-
except Exception as e:
|
|
87
|
-
logger.error(f"Failed to search from Redis list key '{key}': {e}")
|
|
88
|
-
raise e
|
|
89
|
-
|
|
90
|
-
@override
|
|
91
|
-
def delete(self, **kwargs):
|
|
92
|
-
"""Delete Redis list key based on app_name, user_id and session_id, or directly by key."""
|
|
93
|
-
key = kwargs.get("key")
|
|
94
|
-
if key is None:
|
|
95
|
-
app_name = kwargs.get("app_name")
|
|
96
|
-
user_id = kwargs.get("user_id")
|
|
97
|
-
session_id = kwargs.get("session_id")
|
|
98
|
-
key = f"{app_name}:{user_id}:{session_id}"
|
|
99
|
-
|
|
100
|
-
try:
|
|
101
|
-
# For simple key deletion
|
|
102
|
-
# We use sync Redis client to delete the key
|
|
103
|
-
# so the result will be `int`
|
|
104
|
-
result = self._client.delete(key)
|
|
105
|
-
|
|
106
|
-
if result > 0: # type: ignore
|
|
107
|
-
logger.info(f"Deleted key `{key}` from Redis.")
|
|
108
|
-
else:
|
|
109
|
-
logger.info(f"Key `{key}` not found in Redis. Skipping deletion.")
|
|
110
|
-
except Exception as e:
|
|
111
|
-
logger.error(f"Failed to delete key `{key}`: {e}")
|
|
112
|
-
raise e
|
|
113
|
-
|
|
114
|
-
def delete_doc(self, key: str, id: str) -> bool:
|
|
115
|
-
"""Delete a specific document by ID from a Redis list.
|
|
116
|
-
|
|
117
|
-
Args:
|
|
118
|
-
key: The Redis key (list) to delete from
|
|
119
|
-
id: The ID of the document to delete
|
|
120
|
-
|
|
121
|
-
Returns:
|
|
122
|
-
bool: True if deletion was successful, False otherwise
|
|
123
|
-
"""
|
|
124
|
-
try:
|
|
125
|
-
# Get all items in the list
|
|
126
|
-
items = self._client.lrange(key, 0, -1)
|
|
127
|
-
|
|
128
|
-
# Find the index of the item to delete
|
|
129
|
-
for i, item in enumerate(items):
|
|
130
|
-
# Assuming the item is stored as a JSON string with an 'id' field
|
|
131
|
-
# If it's just the content, we'll use the list index as ID
|
|
132
|
-
if str(i) == id:
|
|
133
|
-
self._client.lrem(key, 1, item)
|
|
134
|
-
return True
|
|
135
|
-
|
|
136
|
-
logger.warning(f"Document with id {id} not found in key {key}")
|
|
137
|
-
return False
|
|
138
|
-
except Exception as e:
|
|
139
|
-
logger.error(f"Failed to delete document with id {id} from key {key}: {e}")
|
|
140
|
-
return False
|
|
141
|
-
|
|
142
|
-
def list_docs(self, key: str) -> list[dict]:
|
|
143
|
-
"""List all documents in a Redis list.
|
|
144
|
-
|
|
145
|
-
Args:
|
|
146
|
-
key: The Redis key (list) to list documents from
|
|
147
|
-
|
|
148
|
-
Returns:
|
|
149
|
-
list[dict]: List of documents with id and content
|
|
150
|
-
"""
|
|
151
|
-
try:
|
|
152
|
-
items = self._client.lrange(key, 0, -1)
|
|
153
|
-
return [
|
|
154
|
-
{"id": str(i), "content": item, "metadata": {}}
|
|
155
|
-
for i, item in enumerate(items)
|
|
156
|
-
]
|
|
157
|
-
except Exception as e:
|
|
158
|
-
logger.error(f"Failed to list documents from key {key}: {e}")
|
|
159
|
-
return []
|
veadk/database/local_database.py
DELETED
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
# Copyright (c) 2025 Beijing Volcano Engine Technology Co., Ltd. and/or its affiliates.
|
|
2
|
-
#
|
|
3
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
-
# you may not use this file except in compliance with the License.
|
|
5
|
-
# You may obtain a copy of the License at
|
|
6
|
-
#
|
|
7
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
-
#
|
|
9
|
-
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
-
# See the License for the specific language governing permissions and
|
|
13
|
-
# limitations under the License.
|
|
14
|
-
|
|
15
|
-
from typing import Any
|
|
16
|
-
|
|
17
|
-
from .base_database import BaseDatabase
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
class LocalDataBase(BaseDatabase):
|
|
21
|
-
"""This database is only for basic demonstration.
|
|
22
|
-
It does not support the vector search function, and the `search` function will return all data.
|
|
23
|
-
"""
|
|
24
|
-
|
|
25
|
-
def __init__(self, **kwargs):
|
|
26
|
-
super().__init__()
|
|
27
|
-
self.data = {}
|
|
28
|
-
self._type = "local"
|
|
29
|
-
self._next_id = 0 # Used to generate unique IDs
|
|
30
|
-
|
|
31
|
-
def add_texts(self, texts: list[str], **kwargs):
|
|
32
|
-
for text in texts:
|
|
33
|
-
self.data[str(self._next_id)] = text
|
|
34
|
-
self._next_id += 1
|
|
35
|
-
|
|
36
|
-
def is_empty(self):
|
|
37
|
-
return len(self.data) == 0
|
|
38
|
-
|
|
39
|
-
def query(self, query: str, **kwargs: Any) -> list[str]:
|
|
40
|
-
return list(self.data.values())
|
|
41
|
-
|
|
42
|
-
def delete(self, **kwargs: Any):
|
|
43
|
-
self.data = {}
|
|
44
|
-
|
|
45
|
-
def add(self, texts: list[str], **kwargs: Any):
|
|
46
|
-
return self.add_texts(texts)
|
|
47
|
-
|
|
48
|
-
def list_docs(self, **kwargs: Any) -> list[dict]:
|
|
49
|
-
return [
|
|
50
|
-
{"id": id, "content": content, "metadata": {}}
|
|
51
|
-
for id, content in self.data.items()
|
|
52
|
-
]
|
|
53
|
-
|
|
54
|
-
def delete_doc(self, id: str, **kwargs: Any):
|
|
55
|
-
if id not in self.data:
|
|
56
|
-
raise ValueError(f"id {id} not found")
|
|
57
|
-
try:
|
|
58
|
-
del self.data[id]
|
|
59
|
-
return True
|
|
60
|
-
except Exception:
|
|
61
|
-
return False
|