veadk-python 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 veadk-python might be problematic. Click here for more details.
- veadk/__init__.py +31 -0
- veadk/a2a/__init__.py +13 -0
- veadk/a2a/agent_card.py +45 -0
- veadk/a2a/remote_ve_agent.py +19 -0
- veadk/a2a/ve_a2a_server.py +77 -0
- veadk/a2a/ve_agent_executor.py +78 -0
- veadk/a2a/ve_task_store.py +37 -0
- veadk/agent.py +253 -0
- veadk/cli/__init__.py +13 -0
- veadk/cli/main.py +278 -0
- veadk/cli/services/agentpilot/__init__.py +17 -0
- veadk/cli/services/agentpilot/agentpilot.py +77 -0
- veadk/cli/services/veapig/__init__.py +17 -0
- veadk/cli/services/veapig/apig.py +224 -0
- veadk/cli/services/veapig/apig_utils.py +332 -0
- veadk/cli/services/vefaas/__init__.py +17 -0
- veadk/cli/services/vefaas/template/deploy.py +44 -0
- veadk/cli/services/vefaas/template/src/app.py +30 -0
- veadk/cli/services/vefaas/template/src/config.py +58 -0
- veadk/cli/services/vefaas/vefaas.py +346 -0
- veadk/cli/services/vefaas/vefaas_utils.py +408 -0
- veadk/cli/services/vetls/__init__.py +17 -0
- veadk/cli/services/vetls/vetls.py +87 -0
- veadk/cli/studio/__init__.py +13 -0
- veadk/cli/studio/agent_processor.py +247 -0
- veadk/cli/studio/fast_api.py +232 -0
- veadk/cli/studio/model.py +116 -0
- veadk/cloud/__init__.py +13 -0
- veadk/cloud/cloud_agent_engine.py +144 -0
- veadk/cloud/cloud_app.py +123 -0
- veadk/cloud/template/app.py +30 -0
- veadk/cloud/template/config.py +55 -0
- veadk/config.py +131 -0
- veadk/consts.py +17 -0
- veadk/database/__init__.py +17 -0
- veadk/database/base_database.py +45 -0
- veadk/database/database_factory.py +80 -0
- veadk/database/kv/__init__.py +13 -0
- veadk/database/kv/redis_database.py +109 -0
- veadk/database/local_database.py +43 -0
- veadk/database/relational/__init__.py +13 -0
- veadk/database/relational/mysql_database.py +114 -0
- veadk/database/vector/__init__.py +13 -0
- veadk/database/vector/opensearch_vector_database.py +205 -0
- veadk/database/vector/type.py +50 -0
- veadk/database/viking/__init__.py +13 -0
- veadk/database/viking/viking_database.py +378 -0
- veadk/database/viking/viking_memory_db.py +521 -0
- veadk/evaluation/__init__.py +17 -0
- veadk/evaluation/adk_evaluator/__init__.py +13 -0
- veadk/evaluation/adk_evaluator/adk_evaluator.py +291 -0
- veadk/evaluation/base_evaluator.py +242 -0
- veadk/evaluation/deepeval_evaluator/__init__.py +17 -0
- veadk/evaluation/deepeval_evaluator/deepeval_evaluator.py +223 -0
- veadk/evaluation/eval_set_file_loader.py +28 -0
- veadk/evaluation/eval_set_recorder.py +91 -0
- veadk/evaluation/utils/prometheus.py +142 -0
- veadk/knowledgebase/__init__.py +17 -0
- veadk/knowledgebase/knowledgebase.py +83 -0
- veadk/knowledgebase/knowledgebase_database_adapter.py +259 -0
- veadk/memory/__init__.py +13 -0
- veadk/memory/long_term_memory.py +119 -0
- veadk/memory/memory_database_adapter.py +235 -0
- veadk/memory/short_term_memory.py +124 -0
- veadk/memory/short_term_memory_processor.py +90 -0
- veadk/prompts/__init__.py +13 -0
- veadk/prompts/agent_default_prompt.py +30 -0
- veadk/prompts/prompt_evaluator.py +20 -0
- veadk/prompts/prompt_memory_processor.py +55 -0
- veadk/prompts/prompt_optimization.py +158 -0
- veadk/runner.py +252 -0
- veadk/tools/__init__.py +13 -0
- veadk/tools/builtin_tools/__init__.py +13 -0
- veadk/tools/builtin_tools/lark.py +67 -0
- veadk/tools/builtin_tools/las.py +23 -0
- veadk/tools/builtin_tools/vesearch.py +49 -0
- veadk/tools/builtin_tools/web_scraper.py +76 -0
- veadk/tools/builtin_tools/web_search.py +192 -0
- veadk/tools/demo_tools.py +58 -0
- veadk/tools/load_knowledgebase_tool.py +144 -0
- veadk/tools/sandbox/__init__.py +13 -0
- veadk/tools/sandbox/browser_sandbox.py +27 -0
- veadk/tools/sandbox/code_sandbox.py +30 -0
- veadk/tools/sandbox/computer_sandbox.py +27 -0
- veadk/tracing/__init__.py +13 -0
- veadk/tracing/base_tracer.py +172 -0
- veadk/tracing/telemetry/__init__.py +13 -0
- veadk/tracing/telemetry/exporters/__init__.py +13 -0
- veadk/tracing/telemetry/exporters/apiserver_exporter.py +60 -0
- veadk/tracing/telemetry/exporters/apmplus_exporter.py +101 -0
- veadk/tracing/telemetry/exporters/base_exporter.py +28 -0
- veadk/tracing/telemetry/exporters/cozeloop_exporter.py +69 -0
- veadk/tracing/telemetry/exporters/inmemory_exporter.py +88 -0
- veadk/tracing/telemetry/exporters/tls_exporter.py +78 -0
- veadk/tracing/telemetry/metrics/__init__.py +13 -0
- veadk/tracing/telemetry/metrics/opentelemetry_metrics.py +73 -0
- veadk/tracing/telemetry/opentelemetry_tracer.py +167 -0
- veadk/types.py +23 -0
- veadk/utils/__init__.py +13 -0
- veadk/utils/logger.py +59 -0
- veadk/utils/misc.py +33 -0
- veadk/utils/patches.py +85 -0
- veadk/utils/volcengine_sign.py +199 -0
- veadk/version.py +15 -0
- veadk_python-0.1.0.dist-info/METADATA +124 -0
- veadk_python-0.1.0.dist-info/RECORD +110 -0
- veadk_python-0.1.0.dist-info/WHEEL +5 -0
- veadk_python-0.1.0.dist-info/entry_points.txt +2 -0
- veadk_python-0.1.0.dist-info/licenses/LICENSE +201 -0
- veadk_python-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,521 @@
|
|
|
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 json
|
|
16
|
+
import random
|
|
17
|
+
import string
|
|
18
|
+
import threading
|
|
19
|
+
import time
|
|
20
|
+
from datetime import datetime
|
|
21
|
+
from typing import Any, Optional
|
|
22
|
+
|
|
23
|
+
from pydantic import BaseModel, Field
|
|
24
|
+
from volcengine.ApiInfo import ApiInfo
|
|
25
|
+
from volcengine.auth.SignerV4 import SignerV4
|
|
26
|
+
from volcengine.base.Service import Service
|
|
27
|
+
from volcengine.Credentials import Credentials
|
|
28
|
+
from volcengine.ServiceInfo import ServiceInfo
|
|
29
|
+
|
|
30
|
+
from veadk.config import getenv
|
|
31
|
+
from veadk.database.base_database import BaseDatabase
|
|
32
|
+
from veadk.utils.logger import get_logger
|
|
33
|
+
|
|
34
|
+
logger = get_logger(__name__)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class VikingMemConfig(BaseModel):
|
|
38
|
+
volcengine_ak: Optional[str] = Field(
|
|
39
|
+
default=getenv("VOLCENGINE_ACCESS_KEY"),
|
|
40
|
+
description="VikingDB access key",
|
|
41
|
+
)
|
|
42
|
+
volcengine_sk: Optional[str] = Field(
|
|
43
|
+
default=getenv("VOLCENGINE_SECRET_KEY"),
|
|
44
|
+
description="VikingDB secret key",
|
|
45
|
+
)
|
|
46
|
+
project: Optional[str] = Field(
|
|
47
|
+
default=getenv("DATABASE_VIKING_PROJECT"),
|
|
48
|
+
description="VikingDB project name",
|
|
49
|
+
)
|
|
50
|
+
region: Optional[str] = Field(
|
|
51
|
+
default=getenv("DATABASE_VIKING_REGION"),
|
|
52
|
+
description="VikingDB region",
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class VikingDBMemoryException(Exception):
|
|
57
|
+
def __init__(self, code, request_id, message=None):
|
|
58
|
+
self.code = code
|
|
59
|
+
self.request_id = request_id
|
|
60
|
+
self.message = "{}, code:{},request_id:{}".format(
|
|
61
|
+
message, self.code, self.request_id
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
def __str__(self):
|
|
65
|
+
return self.message
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class VikingDBMemoryService(Service):
|
|
69
|
+
_instance_lock = threading.Lock()
|
|
70
|
+
|
|
71
|
+
def __new__(cls, *args, **kwargs):
|
|
72
|
+
if not hasattr(VikingDBMemoryService, "_instance"):
|
|
73
|
+
with VikingDBMemoryService._instance_lock:
|
|
74
|
+
if not hasattr(VikingDBMemoryService, "_instance"):
|
|
75
|
+
VikingDBMemoryService._instance = object.__new__(cls)
|
|
76
|
+
return VikingDBMemoryService._instance
|
|
77
|
+
|
|
78
|
+
def __init__(
|
|
79
|
+
self,
|
|
80
|
+
host="api-knowledgebase.mlp.cn-beijing.volces.com",
|
|
81
|
+
region="cn-beijing",
|
|
82
|
+
ak="",
|
|
83
|
+
sk="",
|
|
84
|
+
sts_token="",
|
|
85
|
+
scheme="http",
|
|
86
|
+
connection_timeout=30,
|
|
87
|
+
socket_timeout=30,
|
|
88
|
+
):
|
|
89
|
+
self.service_info = VikingDBMemoryService.get_service_info(
|
|
90
|
+
host, region, scheme, connection_timeout, socket_timeout
|
|
91
|
+
)
|
|
92
|
+
self.api_info = VikingDBMemoryService.get_api_info()
|
|
93
|
+
super(VikingDBMemoryService, self).__init__(self.service_info, self.api_info)
|
|
94
|
+
if ak:
|
|
95
|
+
self.set_ak(ak)
|
|
96
|
+
if sk:
|
|
97
|
+
self.set_sk(sk)
|
|
98
|
+
if sts_token:
|
|
99
|
+
self.set_session_token(session_token=sts_token)
|
|
100
|
+
try:
|
|
101
|
+
self.get_body("Ping", {}, json.dumps({}))
|
|
102
|
+
except Exception as e:
|
|
103
|
+
raise VikingDBMemoryException(
|
|
104
|
+
1000028, "missed", "host or region is incorrect: {}".format(str(e))
|
|
105
|
+
) from None
|
|
106
|
+
|
|
107
|
+
def setHeader(self, header):
|
|
108
|
+
api_info = VikingDBMemoryService.get_api_info()
|
|
109
|
+
for key in api_info:
|
|
110
|
+
for item in header:
|
|
111
|
+
api_info[key].header[item] = header[item]
|
|
112
|
+
self.api_info = api_info
|
|
113
|
+
|
|
114
|
+
@staticmethod
|
|
115
|
+
def get_service_info(host, region, scheme, connection_timeout, socket_timeout):
|
|
116
|
+
service_info = ServiceInfo(
|
|
117
|
+
host,
|
|
118
|
+
{"Host": host},
|
|
119
|
+
Credentials("", "", "air", region),
|
|
120
|
+
connection_timeout,
|
|
121
|
+
socket_timeout,
|
|
122
|
+
scheme=scheme,
|
|
123
|
+
)
|
|
124
|
+
return service_info
|
|
125
|
+
|
|
126
|
+
@staticmethod
|
|
127
|
+
def get_api_info():
|
|
128
|
+
api_info = {
|
|
129
|
+
"CreateCollection": ApiInfo(
|
|
130
|
+
"POST",
|
|
131
|
+
"/api/memory/collection/create",
|
|
132
|
+
{},
|
|
133
|
+
{},
|
|
134
|
+
{"Accept": "application/json", "Content-Type": "application/json"},
|
|
135
|
+
),
|
|
136
|
+
"GetCollection": ApiInfo(
|
|
137
|
+
"POST",
|
|
138
|
+
"/api/memory/collection/info",
|
|
139
|
+
{},
|
|
140
|
+
{},
|
|
141
|
+
{"Accept": "application/json", "Content-Type": "application/json"},
|
|
142
|
+
),
|
|
143
|
+
"DropCollection": ApiInfo(
|
|
144
|
+
"POST",
|
|
145
|
+
"/api/memory/collection/delete",
|
|
146
|
+
{},
|
|
147
|
+
{},
|
|
148
|
+
{"Accept": "application/json", "Content-Type": "application/json"},
|
|
149
|
+
),
|
|
150
|
+
"UpdateCollection": ApiInfo(
|
|
151
|
+
"POST",
|
|
152
|
+
"/api/memory/collection/update",
|
|
153
|
+
{},
|
|
154
|
+
{},
|
|
155
|
+
{"Accept": "application/json", "Content-Type": "application/json"},
|
|
156
|
+
),
|
|
157
|
+
"SearchMemory": ApiInfo(
|
|
158
|
+
"POST",
|
|
159
|
+
"/api/memory/search",
|
|
160
|
+
{},
|
|
161
|
+
{},
|
|
162
|
+
{"Accept": "application/json", "Content-Type": "application/json"},
|
|
163
|
+
),
|
|
164
|
+
"AddMessages": ApiInfo(
|
|
165
|
+
"POST",
|
|
166
|
+
"/api/memory/messages/add",
|
|
167
|
+
{},
|
|
168
|
+
{},
|
|
169
|
+
{"Accept": "application/json", "Content-Type": "application/json"},
|
|
170
|
+
),
|
|
171
|
+
"Ping": ApiInfo(
|
|
172
|
+
"GET",
|
|
173
|
+
"/api/memory/ping",
|
|
174
|
+
{},
|
|
175
|
+
{},
|
|
176
|
+
{"Accept": "application/json", "Content-Type": "application/json"},
|
|
177
|
+
),
|
|
178
|
+
}
|
|
179
|
+
return api_info
|
|
180
|
+
|
|
181
|
+
def get_body(self, api, params, body):
|
|
182
|
+
if api not in self.api_info:
|
|
183
|
+
raise Exception("no such api")
|
|
184
|
+
api_info = self.api_info[api]
|
|
185
|
+
r = self.prepare_request(api_info, params)
|
|
186
|
+
r.headers["Content-Type"] = "application/json"
|
|
187
|
+
r.headers["Traffic-Source"] = "SDK"
|
|
188
|
+
r.body = body
|
|
189
|
+
|
|
190
|
+
SignerV4.sign(r, self.service_info.credentials)
|
|
191
|
+
|
|
192
|
+
url = r.build()
|
|
193
|
+
resp = self.session.get(
|
|
194
|
+
url,
|
|
195
|
+
headers=r.headers,
|
|
196
|
+
data=r.body,
|
|
197
|
+
timeout=(
|
|
198
|
+
self.service_info.connection_timeout,
|
|
199
|
+
self.service_info.socket_timeout,
|
|
200
|
+
),
|
|
201
|
+
)
|
|
202
|
+
if resp.status_code == 200:
|
|
203
|
+
return json.dumps(resp.json())
|
|
204
|
+
else:
|
|
205
|
+
raise Exception(resp.text.encode("utf-8"))
|
|
206
|
+
|
|
207
|
+
def get_body_exception(self, api, params, body):
|
|
208
|
+
try:
|
|
209
|
+
res = self.get_body(api, params, body)
|
|
210
|
+
except Exception as e:
|
|
211
|
+
try:
|
|
212
|
+
res_json = json.loads(e.args[0].decode("utf-8"))
|
|
213
|
+
except Exception:
|
|
214
|
+
raise VikingDBMemoryException(
|
|
215
|
+
1000028, "missed", "json load res error, res:{}".format(str(e))
|
|
216
|
+
) from None
|
|
217
|
+
code = res_json.get("code", 1000028)
|
|
218
|
+
request_id = res_json.get("request_id", 1000028)
|
|
219
|
+
message = res_json.get("message", None)
|
|
220
|
+
|
|
221
|
+
raise VikingDBMemoryException(code, request_id, message)
|
|
222
|
+
|
|
223
|
+
if res == "":
|
|
224
|
+
raise VikingDBMemoryException(
|
|
225
|
+
1000028,
|
|
226
|
+
"missed",
|
|
227
|
+
"empty response due to unknown error, please contact customer service",
|
|
228
|
+
) from None
|
|
229
|
+
return res
|
|
230
|
+
|
|
231
|
+
def get_exception(self, api, params):
|
|
232
|
+
try:
|
|
233
|
+
res = self.get(api, params)
|
|
234
|
+
except Exception as e:
|
|
235
|
+
try:
|
|
236
|
+
res_json = json.loads(e.args[0].decode("utf-8"))
|
|
237
|
+
except Exception:
|
|
238
|
+
raise VikingDBMemoryException(
|
|
239
|
+
1000028, "missed", "json load res error, res:{}".format(str(e))
|
|
240
|
+
) from None
|
|
241
|
+
code = res_json.get("code", 1000028)
|
|
242
|
+
request_id = res_json.get("request_id", 1000028)
|
|
243
|
+
message = res_json.get("message", None)
|
|
244
|
+
raise VikingDBMemoryException(code, request_id, message)
|
|
245
|
+
if res == "":
|
|
246
|
+
raise VikingDBMemoryException(
|
|
247
|
+
1000028,
|
|
248
|
+
"missed",
|
|
249
|
+
"empty response due to unknown error, please contact customer service",
|
|
250
|
+
) from None
|
|
251
|
+
return res
|
|
252
|
+
|
|
253
|
+
def create_collection(
|
|
254
|
+
self,
|
|
255
|
+
collection_name,
|
|
256
|
+
description="",
|
|
257
|
+
custom_event_type_schemas=None,
|
|
258
|
+
custom_entity_type_schemas=None,
|
|
259
|
+
builtin_event_types=None,
|
|
260
|
+
builtin_entity_types=None,
|
|
261
|
+
):
|
|
262
|
+
if custom_event_type_schemas is None:
|
|
263
|
+
custom_event_type_schemas = []
|
|
264
|
+
if custom_entity_type_schemas is None:
|
|
265
|
+
custom_entity_type_schemas = []
|
|
266
|
+
if builtin_entity_types is None:
|
|
267
|
+
builtin_entity_types = ["sys_profile_v1"]
|
|
268
|
+
if builtin_event_types is None:
|
|
269
|
+
builtin_event_types = ["sys_event_v1", "sys_profile_collect_v1"]
|
|
270
|
+
params = {
|
|
271
|
+
"CollectionName": collection_name,
|
|
272
|
+
"Description": description,
|
|
273
|
+
"CustomEventTypeSchemas": custom_event_type_schemas,
|
|
274
|
+
"CustomEntityTypeSchemas": custom_entity_type_schemas,
|
|
275
|
+
"BuiltinEventTypes": builtin_event_types,
|
|
276
|
+
"BuiltinEntityTypes": builtin_entity_types,
|
|
277
|
+
}
|
|
278
|
+
res = self.json("CreateCollection", {}, json.dumps(params))
|
|
279
|
+
return json.loads(res)
|
|
280
|
+
|
|
281
|
+
def get_collection(self, collection_name):
|
|
282
|
+
params = {"CollectionName": collection_name}
|
|
283
|
+
res = self.json("GetCollection", {}, json.dumps(params))
|
|
284
|
+
return json.loads(res)
|
|
285
|
+
|
|
286
|
+
def drop_collection(self, collection_name):
|
|
287
|
+
params = {"CollectionName": collection_name}
|
|
288
|
+
res = self.json("DropCollection", {}, json.dumps(params))
|
|
289
|
+
return json.loads(res)
|
|
290
|
+
|
|
291
|
+
def update_collection(
|
|
292
|
+
self,
|
|
293
|
+
collection_name,
|
|
294
|
+
custom_event_type_schemas=[],
|
|
295
|
+
custom_entity_type_schemas=[],
|
|
296
|
+
builtin_event_types=[],
|
|
297
|
+
builtin_entity_types=[],
|
|
298
|
+
):
|
|
299
|
+
params = {
|
|
300
|
+
"CollectionName": collection_name,
|
|
301
|
+
"CustomEventTypeSchemas": custom_event_type_schemas,
|
|
302
|
+
"CustomEntityTypeSchemas": custom_entity_type_schemas,
|
|
303
|
+
"BuiltinEventTypes": builtin_event_types,
|
|
304
|
+
"BuiltinEntityTypes": builtin_entity_types,
|
|
305
|
+
}
|
|
306
|
+
res = self.json("UpdateCollection", {}, json.dumps(params))
|
|
307
|
+
return json.loads(res)
|
|
308
|
+
|
|
309
|
+
def search_memory(self, collection_name, query, filter, limit=10):
|
|
310
|
+
params = {
|
|
311
|
+
"collection_name": collection_name,
|
|
312
|
+
"limit": limit,
|
|
313
|
+
"filter": filter,
|
|
314
|
+
}
|
|
315
|
+
if query:
|
|
316
|
+
params["query"] = query
|
|
317
|
+
res = self.json("SearchMemory", {}, json.dumps(params))
|
|
318
|
+
return json.loads(res)
|
|
319
|
+
|
|
320
|
+
def add_messages(
|
|
321
|
+
self, collection_name, session_id, messages, metadata, entities=None
|
|
322
|
+
):
|
|
323
|
+
params = {
|
|
324
|
+
"collection_name": collection_name,
|
|
325
|
+
"session_id": session_id,
|
|
326
|
+
"messages": messages,
|
|
327
|
+
"metadata": metadata,
|
|
328
|
+
}
|
|
329
|
+
if entities is not None:
|
|
330
|
+
params["entities"] = entities
|
|
331
|
+
res = self.json("AddMessages", {}, json.dumps(params))
|
|
332
|
+
return json.loads(res)
|
|
333
|
+
|
|
334
|
+
|
|
335
|
+
def memory2event(role, text):
|
|
336
|
+
return json.dumps({"role": role, "parts": [{"text": text}]}, ensure_ascii=False)
|
|
337
|
+
|
|
338
|
+
|
|
339
|
+
def generate_random_letters(length):
|
|
340
|
+
# 生成包含所有大小写字母的字符集
|
|
341
|
+
letters = string.ascii_letters
|
|
342
|
+
return "".join(random.choice(letters) for _ in range(length))
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
def format_milliseconds(timestamp_ms):
|
|
346
|
+
"""
|
|
347
|
+
Convert the millisecond - level timestamp to a string in the 'YYYYMMDD HH:MM:SS' format.
|
|
348
|
+
|
|
349
|
+
Parameters:
|
|
350
|
+
- timestamp_ms: Millisecond - level timestamp (integer or float)
|
|
351
|
+
|
|
352
|
+
Returns:
|
|
353
|
+
- Formatted time string
|
|
354
|
+
|
|
355
|
+
"""
|
|
356
|
+
# Convert milliseconds to seconds
|
|
357
|
+
timestamp_seconds = timestamp_ms / 1000
|
|
358
|
+
|
|
359
|
+
# Convert to a datetime object
|
|
360
|
+
dt = datetime.fromtimestamp(timestamp_seconds)
|
|
361
|
+
|
|
362
|
+
# Output in the specified format
|
|
363
|
+
return dt.strftime("%Y%m%d %H:%M:%S")
|
|
364
|
+
|
|
365
|
+
|
|
366
|
+
class VikingDatabaseMemory(BaseModel, BaseDatabase):
|
|
367
|
+
config: VikingMemConfig = Field(
|
|
368
|
+
default_factory=VikingMemConfig,
|
|
369
|
+
description="VikingDB configuration",
|
|
370
|
+
)
|
|
371
|
+
|
|
372
|
+
def model_post_init(self, context: Any, /) -> None:
|
|
373
|
+
self._vm = VikingDBMemoryService(
|
|
374
|
+
ak=self.config.volcengine_ak, sk=self.config.volcengine_sk
|
|
375
|
+
)
|
|
376
|
+
|
|
377
|
+
def add_memories(
|
|
378
|
+
self,
|
|
379
|
+
collection_name: str,
|
|
380
|
+
text: str,
|
|
381
|
+
user_id: str,
|
|
382
|
+
) -> str:
|
|
383
|
+
# Add Messages
|
|
384
|
+
session_id = generate_random_letters(10)
|
|
385
|
+
# proces
|
|
386
|
+
message = json.loads(text)
|
|
387
|
+
content = message["parts"][0]["text"]
|
|
388
|
+
role = (
|
|
389
|
+
"user" if message["role"] == "user" else "assistant"
|
|
390
|
+
) # field 'role': viking memory only allow 'assistant','system','user',
|
|
391
|
+
messages = [{"role": role, "content": content}]
|
|
392
|
+
metadata = {
|
|
393
|
+
"default_user_id": user_id,
|
|
394
|
+
"default_assistant_id": "assistant",
|
|
395
|
+
"time": int(time.time() * 1000),
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
rsp = self._vm.add_messages(
|
|
399
|
+
collection_name=collection_name,
|
|
400
|
+
session_id=session_id,
|
|
401
|
+
messages=messages,
|
|
402
|
+
metadata=metadata,
|
|
403
|
+
)
|
|
404
|
+
return str(rsp)
|
|
405
|
+
|
|
406
|
+
def add(self, data: list[str], **kwargs):
|
|
407
|
+
collection_name = kwargs.get("collection_name")
|
|
408
|
+
assert collection_name is not None, "collection_name is required"
|
|
409
|
+
user_id = kwargs.get("user_id")
|
|
410
|
+
assert user_id is not None, "user_id is required"
|
|
411
|
+
try:
|
|
412
|
+
self._vm.get_collection(collection_name=collection_name)
|
|
413
|
+
except Exception:
|
|
414
|
+
self._vm.create_collection(
|
|
415
|
+
collection_name=collection_name,
|
|
416
|
+
)
|
|
417
|
+
|
|
418
|
+
for text in data:
|
|
419
|
+
self.add_memories(
|
|
420
|
+
collection_name=collection_name, text=text, user_id=user_id
|
|
421
|
+
)
|
|
422
|
+
|
|
423
|
+
return "success"
|
|
424
|
+
|
|
425
|
+
def search_memory(
|
|
426
|
+
self, collection_name: str, query: str, user_id: str, top_k: int = 5
|
|
427
|
+
) -> list[str]:
|
|
428
|
+
"""
|
|
429
|
+
Search for stored memories. This method is called whenever a user asks any question.
|
|
430
|
+
If a search yields no results, do not repeat the search within the same conversation.
|
|
431
|
+
The retrieved memories are used to supplement your understanding of the user and to reply to the user's question.
|
|
432
|
+
Args:
|
|
433
|
+
collection_name: viking db collection_name
|
|
434
|
+
query: Any question asked by the user.
|
|
435
|
+
Returns:
|
|
436
|
+
The user's memories related to the query.
|
|
437
|
+
"""
|
|
438
|
+
|
|
439
|
+
result = []
|
|
440
|
+
try:
|
|
441
|
+
# ------- get profiles -----------
|
|
442
|
+
try:
|
|
443
|
+
limit = 1
|
|
444
|
+
filter = {
|
|
445
|
+
"user_id": user_id,
|
|
446
|
+
"memory_type": ["sys_profile_v1"],
|
|
447
|
+
}
|
|
448
|
+
rsp = self._vm.search_memory(
|
|
449
|
+
collection_name=collection_name,
|
|
450
|
+
query="sys_profile_v1",
|
|
451
|
+
filter=filter,
|
|
452
|
+
limit=limit,
|
|
453
|
+
)
|
|
454
|
+
profiles = [
|
|
455
|
+
item.get("memory_info").get("user_profile")
|
|
456
|
+
for item in rsp.get("data").get("result_list")
|
|
457
|
+
]
|
|
458
|
+
if len(profiles) > 0:
|
|
459
|
+
result.append(memory2event("user", profiles[0]))
|
|
460
|
+
except Exception as e:
|
|
461
|
+
result.append(
|
|
462
|
+
memory2event("user", f"SearchMemory: Get Profiles Error: {str(e)}")
|
|
463
|
+
)
|
|
464
|
+
|
|
465
|
+
# -------- get memory -----------
|
|
466
|
+
try:
|
|
467
|
+
# Search Memory
|
|
468
|
+
limit = top_k
|
|
469
|
+
filter = {
|
|
470
|
+
"user_id": user_id,
|
|
471
|
+
"memory_type": ["sys_event_v1"],
|
|
472
|
+
}
|
|
473
|
+
rsp = self._vm.search_memory(
|
|
474
|
+
collection_name=collection_name,
|
|
475
|
+
query=query,
|
|
476
|
+
filter=filter,
|
|
477
|
+
limit=limit,
|
|
478
|
+
)
|
|
479
|
+
result_list = rsp.get("data").get("result_list")
|
|
480
|
+
|
|
481
|
+
content = [
|
|
482
|
+
memory2event("user", item.get("memory_info").get("summary"))
|
|
483
|
+
for item in result_list
|
|
484
|
+
]
|
|
485
|
+
|
|
486
|
+
result.extend(content)
|
|
487
|
+
|
|
488
|
+
except Exception as e:
|
|
489
|
+
result.append(
|
|
490
|
+
memory2event("user", f"SearchMemory: Get Memory Error: {str(e)}")
|
|
491
|
+
)
|
|
492
|
+
|
|
493
|
+
return result
|
|
494
|
+
|
|
495
|
+
except Exception as e:
|
|
496
|
+
logger.error(f"Error in get_doc: {str(e)}")
|
|
497
|
+
result.append(
|
|
498
|
+
memory2event("user", f"SearchMemory: Get Memory Error: {str(e)}")
|
|
499
|
+
)
|
|
500
|
+
return result
|
|
501
|
+
|
|
502
|
+
def query(self, query: str, **kwargs: Any) -> list[str]:
|
|
503
|
+
"""
|
|
504
|
+
Args:
|
|
505
|
+
query: query text
|
|
506
|
+
**kwargs: collection_name(required), top_k(optional, default 5)
|
|
507
|
+
|
|
508
|
+
Returns: list of str, the search result
|
|
509
|
+
"""
|
|
510
|
+
collection_name = kwargs.get("collection_name")
|
|
511
|
+
assert collection_name is not None, "collection_name is required"
|
|
512
|
+
user_id = kwargs.get("user_id")
|
|
513
|
+
assert user_id is not None, "user_id is required"
|
|
514
|
+
|
|
515
|
+
resp = self.search_memory(collection_name, query, user_id=user_id)
|
|
516
|
+
return resp
|
|
517
|
+
|
|
518
|
+
def delete(self, **kwargs: Any):
|
|
519
|
+
collection_name = kwargs.get("collection_name")
|
|
520
|
+
assert collection_name is not None, "collection_name is required"
|
|
521
|
+
self._vm.drop_collection(collection_name)
|
|
@@ -0,0 +1,17 @@
|
|
|
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 .eval_set_recorder import EvalSetRecorder
|
|
16
|
+
|
|
17
|
+
__all__ = ["EvalSetRecorder"]
|
|
@@ -0,0 +1,13 @@
|
|
|
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.
|