veadk-python 0.2.5__py3-none-any.whl → 0.2.6__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 +19 -7
- veadk/cli/cli_deploy.py +2 -0
- veadk/cli/cli_init.py +25 -6
- veadk/consts.py +20 -1
- veadk/database/database_adapter.py +88 -0
- veadk/database/kv/redis_database.py +47 -0
- veadk/database/local_database.py +22 -4
- veadk/database/relational/mysql_database.py +58 -0
- veadk/database/vector/opensearch_vector_database.py +6 -3
- veadk/database/viking/viking_database.py +69 -0
- veadk/integrations/ve_cr/__init__.py +13 -0
- veadk/integrations/ve_cr/ve_cr.py +205 -0
- veadk/integrations/ve_faas/template/cookiecutter.json +2 -1
- veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/app.py +24 -1
- veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/requirements.txt +3 -1
- veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/run.sh +0 -7
- veadk/integrations/ve_faas/ve_faas.py +2 -0
- veadk/integrations/ve_faas/web_template/cookiecutter.json +17 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/__init__.py +13 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/clean.py +23 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/config.yaml.example +2 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/deploy.py +41 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/Dockerfile +23 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/app.py +123 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/init_db.py +46 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/models.py +36 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/requirements.txt +4 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/run.sh +21 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/static/css/style.css +368 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/static/js/admin.js +0 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/admin/dashboard.html +21 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/admin/edit_post.html +24 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/admin/login.html +21 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/admin/posts.html +53 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/base.html +45 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/index.html +29 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/post.html +14 -0
- veadk/integrations/ve_tos/ve_tos.py +92 -30
- veadk/knowledgebase/knowledgebase.py +8 -0
- veadk/runner.py +49 -16
- veadk/tracing/telemetry/attributes/extractors/common_attributes_extractors.py +5 -0
- veadk/tracing/telemetry/attributes/extractors/llm_attributes_extractors.py +253 -129
- veadk/tracing/telemetry/attributes/extractors/types.py +15 -4
- veadk/tracing/telemetry/opentelemetry_tracer.py +11 -5
- veadk/tracing/telemetry/telemetry.py +19 -4
- veadk/version.py +1 -1
- {veadk_python-0.2.5.dist-info → veadk_python-0.2.6.dist-info}/METADATA +1 -1
- {veadk_python-0.2.5.dist-info → veadk_python-0.2.6.dist-info}/RECORD +52 -30
- {veadk_python-0.2.5.dist-info → veadk_python-0.2.6.dist-info}/WHEEL +0 -0
- {veadk_python-0.2.5.dist-info → veadk_python-0.2.6.dist-info}/entry_points.txt +0 -0
- {veadk_python-0.2.5.dist-info → veadk_python-0.2.6.dist-info}/licenses/LICENSE +0 -0
- {veadk_python-0.2.5.dist-info → veadk_python-0.2.6.dist-info}/top_level.txt +0 -0
|
@@ -15,7 +15,6 @@
|
|
|
15
15
|
import os
|
|
16
16
|
from veadk.config import getenv
|
|
17
17
|
from veadk.utils.logger import get_logger
|
|
18
|
-
import tos
|
|
19
18
|
import asyncio
|
|
20
19
|
from typing import Union
|
|
21
20
|
from pydantic import BaseModel, Field
|
|
@@ -23,8 +22,20 @@ from typing import Any
|
|
|
23
22
|
from urllib.parse import urlparse
|
|
24
23
|
from datetime import datetime
|
|
25
24
|
|
|
25
|
+
# Initialize logger before using it
|
|
26
26
|
logger = get_logger(__name__)
|
|
27
27
|
|
|
28
|
+
# Try to import tos module, and provide helpful error message if it fails
|
|
29
|
+
try:
|
|
30
|
+
import tos
|
|
31
|
+
except ImportError as e:
|
|
32
|
+
logger.error(
|
|
33
|
+
"Failed to import 'tos' module. Please install it using: pip install tos\n"
|
|
34
|
+
)
|
|
35
|
+
raise ImportError(
|
|
36
|
+
"Missing 'tos' module. Please install it using: pip install tos\n"
|
|
37
|
+
) from e
|
|
38
|
+
|
|
28
39
|
|
|
29
40
|
class TOSConfig(BaseModel):
|
|
30
41
|
region: str = Field(
|
|
@@ -59,25 +70,76 @@ class VeTOS(BaseModel):
|
|
|
59
70
|
logger.info("Connected to TOS successfully.")
|
|
60
71
|
except Exception as e:
|
|
61
72
|
logger.error(f"Client initialization failed:{e}")
|
|
62
|
-
|
|
73
|
+
self._client = None
|
|
74
|
+
|
|
75
|
+
def _refresh_client(self):
|
|
76
|
+
try:
|
|
77
|
+
if self._client:
|
|
78
|
+
self._client.close()
|
|
79
|
+
self._client = tos.TosClientV2(
|
|
80
|
+
self.config.ak,
|
|
81
|
+
self.config.sk,
|
|
82
|
+
endpoint=f"tos-{self.config.region}.volces.com",
|
|
83
|
+
region=self.config.region,
|
|
84
|
+
)
|
|
85
|
+
logger.info("refreshed client successfully.")
|
|
86
|
+
except Exception as e:
|
|
87
|
+
logger.error(f"Failed to refresh client: {str(e)}")
|
|
88
|
+
self._client = None
|
|
63
89
|
|
|
64
90
|
def create_bucket(self) -> bool:
|
|
65
|
-
"""If the bucket does not exist, create it"""
|
|
91
|
+
"""If the bucket does not exist, create it and set CORS rules"""
|
|
92
|
+
if not self._client:
|
|
93
|
+
logger.error("TOS client is not initialized")
|
|
94
|
+
return False
|
|
66
95
|
try:
|
|
67
96
|
self._client.head_bucket(self.config.bucket_name)
|
|
68
97
|
logger.info(f"Bucket {self.config.bucket_name} already exists")
|
|
69
|
-
return True
|
|
70
98
|
except tos.exceptions.TosServerError as e:
|
|
71
99
|
if e.status_code == 404:
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
100
|
+
try:
|
|
101
|
+
self._client.create_bucket(
|
|
102
|
+
bucket=self.config.bucket_name,
|
|
103
|
+
storage_class=tos.StorageClassType.Storage_Class_Standard,
|
|
104
|
+
acl=tos.ACLType.ACL_Public_Read, # 公开读
|
|
105
|
+
)
|
|
106
|
+
logger.info(
|
|
107
|
+
f"Bucket {self.config.bucket_name} created successfully"
|
|
108
|
+
)
|
|
109
|
+
self._refresh_client()
|
|
110
|
+
except Exception as create_error:
|
|
111
|
+
logger.error(f"Bucket creation failed: {str(create_error)}")
|
|
112
|
+
return False
|
|
113
|
+
else:
|
|
114
|
+
logger.error(f"Bucket check failed: {str(e)}")
|
|
115
|
+
return False
|
|
116
|
+
except Exception as e:
|
|
117
|
+
logger.error(f"Bucket check failed: {str(e)}")
|
|
118
|
+
return False
|
|
119
|
+
|
|
120
|
+
# 确保在所有路径上返回布尔值
|
|
121
|
+
return self._set_cors_rules()
|
|
122
|
+
|
|
123
|
+
def _set_cors_rules(self) -> bool:
|
|
124
|
+
if not self._client:
|
|
125
|
+
logger.error("TOS client is not initialized")
|
|
126
|
+
return False
|
|
127
|
+
try:
|
|
128
|
+
rule = tos.models2.CORSRule(
|
|
129
|
+
allowed_origins=["*"],
|
|
130
|
+
allowed_methods=["GET", "HEAD"],
|
|
131
|
+
allowed_headers=["*"],
|
|
132
|
+
max_age_seconds=1000,
|
|
133
|
+
)
|
|
134
|
+
self._client.put_bucket_cors(self.config.bucket_name, [rule])
|
|
135
|
+
logger.info(
|
|
136
|
+
f"CORS rules for bucket {self.config.bucket_name} set successfully"
|
|
137
|
+
)
|
|
138
|
+
return True
|
|
79
139
|
except Exception as e:
|
|
80
|
-
logger.error(
|
|
140
|
+
logger.error(
|
|
141
|
+
f"Failed to set CORS rules for bucket {self.config.bucket_name}: {str(e)}"
|
|
142
|
+
)
|
|
81
143
|
return False
|
|
82
144
|
|
|
83
145
|
def build_tos_url(
|
|
@@ -103,55 +165,55 @@ class VeTOS(BaseModel):
|
|
|
103
165
|
data: Union[str, bytes],
|
|
104
166
|
):
|
|
105
167
|
if isinstance(data, str):
|
|
106
|
-
|
|
168
|
+
# data is a file path
|
|
169
|
+
return asyncio.to_thread(self._do_upload_file, object_key, data)
|
|
107
170
|
elif isinstance(data, bytes):
|
|
108
|
-
|
|
171
|
+
# data is bytes content
|
|
172
|
+
return asyncio.to_thread(self._do_upload_bytes, object_key, data)
|
|
109
173
|
else:
|
|
110
174
|
error_msg = f"Upload failed: data type error. Only str (file path) and bytes are supported, got {type(data)}"
|
|
111
175
|
logger.error(error_msg)
|
|
112
176
|
raise ValueError(error_msg)
|
|
113
|
-
if data_type == "file":
|
|
114
|
-
return asyncio.to_thread(self._do_upload_file, object_key, data)
|
|
115
|
-
elif data_type == "bytes":
|
|
116
|
-
return asyncio.to_thread(self._do_upload_bytes, object_key, data)
|
|
117
177
|
|
|
118
|
-
def _do_upload_bytes(self, object_key: str,
|
|
178
|
+
def _do_upload_bytes(self, object_key: str, data: bytes) -> None:
|
|
119
179
|
try:
|
|
120
180
|
if not self._client:
|
|
121
|
-
return
|
|
181
|
+
return
|
|
122
182
|
if not self.create_bucket():
|
|
123
|
-
return
|
|
183
|
+
return
|
|
124
184
|
self._client.put_object(
|
|
125
|
-
bucket=self.config.bucket_name, key=object_key, content=
|
|
185
|
+
bucket=self.config.bucket_name, key=object_key, content=data
|
|
126
186
|
)
|
|
127
187
|
logger.debug(f"Upload success, object_key: {object_key}")
|
|
128
188
|
self._close()
|
|
129
|
-
return
|
|
189
|
+
return
|
|
130
190
|
except Exception as e:
|
|
131
191
|
logger.error(f"Upload failed: {e}")
|
|
132
192
|
self._close()
|
|
133
|
-
return
|
|
193
|
+
return
|
|
134
194
|
|
|
135
|
-
def _do_upload_file(self, object_key: str, file_path: str) ->
|
|
195
|
+
def _do_upload_file(self, object_key: str, file_path: str) -> None:
|
|
136
196
|
try:
|
|
137
197
|
if not self._client:
|
|
138
|
-
return
|
|
198
|
+
return
|
|
139
199
|
if not self.create_bucket():
|
|
140
|
-
return
|
|
141
|
-
|
|
200
|
+
return
|
|
142
201
|
self._client.put_object_from_file(
|
|
143
202
|
bucket=self.config.bucket_name, key=object_key, file_path=file_path
|
|
144
203
|
)
|
|
145
204
|
self._close()
|
|
146
205
|
logger.debug(f"Upload success, object_key: {object_key}")
|
|
147
|
-
return
|
|
206
|
+
return
|
|
148
207
|
except Exception as e:
|
|
149
208
|
logger.error(f"Upload failed: {e}")
|
|
150
209
|
self._close()
|
|
151
|
-
return
|
|
210
|
+
return
|
|
152
211
|
|
|
153
212
|
def download(self, object_key: str, save_path: str) -> bool:
|
|
154
213
|
"""download image from TOS"""
|
|
214
|
+
if not self._client:
|
|
215
|
+
logger.error("TOS client is not initialized")
|
|
216
|
+
return False
|
|
155
217
|
try:
|
|
156
218
|
object_stream = self._client.get_object(self.config.bucket_name, object_key)
|
|
157
219
|
|
|
@@ -80,3 +80,11 @@ class KnowledgeBase:
|
|
|
80
80
|
if len(result) == 0:
|
|
81
81
|
logger.warning(f"No documents found in knowledgebase. Query: {query}")
|
|
82
82
|
return result
|
|
83
|
+
|
|
84
|
+
def delete_doc(self, app_name: str, id: str) -> bool:
|
|
85
|
+
index = build_knowledgebase_index(app_name)
|
|
86
|
+
return self.adapter.delete_doc(index=index, id=id)
|
|
87
|
+
|
|
88
|
+
def list_docs(self, app_name: str, offset: int = 0, limit: int = 100) -> list[dict]:
|
|
89
|
+
index = build_knowledgebase_index(app_name)
|
|
90
|
+
return self.adapter.list_docs(index=index, offset=offset, limit=limit)
|
veadk/runner.py
CHANGED
|
@@ -27,12 +27,12 @@ from veadk.agent import Agent
|
|
|
27
27
|
from veadk.agents.loop_agent import LoopAgent
|
|
28
28
|
from veadk.agents.parallel_agent import ParallelAgent
|
|
29
29
|
from veadk.agents.sequential_agent import SequentialAgent
|
|
30
|
+
from veadk.config import getenv
|
|
30
31
|
from veadk.evaluation import EvalSetRecorder
|
|
31
32
|
from veadk.memory.short_term_memory import ShortTermMemory
|
|
32
33
|
from veadk.types import MediaMessage
|
|
33
34
|
from veadk.utils.logger import get_logger
|
|
34
35
|
from veadk.utils.misc import read_png_to_bytes
|
|
35
|
-
from veadk.integrations.ve_tos.ve_tos import VeTOS
|
|
36
36
|
|
|
37
37
|
logger = get_logger(__name__)
|
|
38
38
|
|
|
@@ -86,7 +86,9 @@ class Runner:
|
|
|
86
86
|
plugins=plugins,
|
|
87
87
|
)
|
|
88
88
|
|
|
89
|
-
def _convert_messages(
|
|
89
|
+
def _convert_messages(
|
|
90
|
+
self, messages, session_id, upload_inline_data_to_tos
|
|
91
|
+
) -> list:
|
|
90
92
|
if isinstance(messages, str):
|
|
91
93
|
messages = [types.Content(role="user", parts=[types.Part(text=messages)])]
|
|
92
94
|
elif isinstance(messages, MediaMessage):
|
|
@@ -94,16 +96,26 @@ class Runner:
|
|
|
94
96
|
"The MediaMessage only supports PNG format file for now."
|
|
95
97
|
)
|
|
96
98
|
data = read_png_to_bytes(messages.media)
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
99
|
+
tos_url = "<tos_url>"
|
|
100
|
+
if upload_inline_data_to_tos:
|
|
101
|
+
try:
|
|
102
|
+
from veadk.integrations.ve_tos.ve_tos import VeTOS
|
|
103
|
+
|
|
104
|
+
ve_tos = VeTOS()
|
|
105
|
+
object_key, tos_url = ve_tos.build_tos_url(
|
|
106
|
+
self.user_id, self.app_name, session_id, messages.media
|
|
107
|
+
)
|
|
108
|
+
upload_task = ve_tos.upload(object_key, data)
|
|
109
|
+
if upload_task is not None:
|
|
110
|
+
asyncio.create_task(upload_task)
|
|
111
|
+
except Exception as e:
|
|
112
|
+
logger.error(f"Upload to TOS failed: {e}")
|
|
113
|
+
tos_url = None
|
|
114
|
+
|
|
115
|
+
else:
|
|
116
|
+
logger.warning(
|
|
117
|
+
"Loss of multimodal data may occur in the tracing process."
|
|
118
|
+
)
|
|
107
119
|
|
|
108
120
|
messages = [
|
|
109
121
|
types.Content(
|
|
@@ -123,7 +135,11 @@ class Runner:
|
|
|
123
135
|
elif isinstance(messages, list):
|
|
124
136
|
converted_messages = []
|
|
125
137
|
for message in messages:
|
|
126
|
-
converted_messages.extend(
|
|
138
|
+
converted_messages.extend(
|
|
139
|
+
self._convert_messages(
|
|
140
|
+
message, session_id, upload_inline_data_to_tos
|
|
141
|
+
)
|
|
142
|
+
)
|
|
127
143
|
messages = converted_messages
|
|
128
144
|
else:
|
|
129
145
|
raise ValueError(f"Unknown message type: {type(messages)}")
|
|
@@ -142,7 +158,13 @@ class Runner:
|
|
|
142
158
|
if run_config is not None:
|
|
143
159
|
stream_mode = run_config.streaming_mode
|
|
144
160
|
else:
|
|
145
|
-
run_config = RunConfig(
|
|
161
|
+
run_config = RunConfig(
|
|
162
|
+
streaming_mode=stream_mode,
|
|
163
|
+
max_llm_calls=int(getenv("MODEL_AGENT_MAX_LLM_CALLS", 100)),
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
logger.info(f"Run config: {run_config}")
|
|
167
|
+
|
|
146
168
|
try:
|
|
147
169
|
|
|
148
170
|
async def event_generator():
|
|
@@ -172,6 +194,7 @@ class Runner:
|
|
|
172
194
|
print() # end with a new line
|
|
173
195
|
except LlmCallsLimitExceededError as e:
|
|
174
196
|
logger.warning(f"Max number of llm calls limit exceeded: {e}")
|
|
197
|
+
final_output = ""
|
|
175
198
|
|
|
176
199
|
return final_output
|
|
177
200
|
|
|
@@ -182,8 +205,11 @@ class Runner:
|
|
|
182
205
|
stream: bool = False,
|
|
183
206
|
run_config: RunConfig | None = None,
|
|
184
207
|
save_tracing_data: bool = False,
|
|
208
|
+
upload_inline_data_to_tos: bool = False,
|
|
185
209
|
):
|
|
186
|
-
converted_messages: list = self._convert_messages(
|
|
210
|
+
converted_messages: list = self._convert_messages(
|
|
211
|
+
messages, session_id, upload_inline_data_to_tos
|
|
212
|
+
)
|
|
187
213
|
|
|
188
214
|
await self.short_term_memory.create_session(
|
|
189
215
|
app_name=self.app_name, user_id=self.user_id, session_id=session_id
|
|
@@ -231,7 +257,13 @@ class Runner:
|
|
|
231
257
|
session_id: str,
|
|
232
258
|
run_config: RunConfig | None = None,
|
|
233
259
|
):
|
|
234
|
-
run_config =
|
|
260
|
+
run_config = (
|
|
261
|
+
RunConfig(max_llm_calls=int(getenv("MODEL_AGENT_MAX_LLM_CALLS", 100)))
|
|
262
|
+
if not run_config
|
|
263
|
+
else run_config
|
|
264
|
+
)
|
|
265
|
+
|
|
266
|
+
logger.info(f"Run config: {run_config}")
|
|
235
267
|
|
|
236
268
|
await self.short_term_memory.create_session(
|
|
237
269
|
app_name=self.app_name, user_id=self.user_id, session_id=session_id
|
|
@@ -263,6 +295,7 @@ class Runner:
|
|
|
263
295
|
final_output += chunk
|
|
264
296
|
except LlmCallsLimitExceededError as e:
|
|
265
297
|
logger.warning(f"Max number of llm calls limit exceeded: {e}")
|
|
298
|
+
final_output = ""
|
|
266
299
|
|
|
267
300
|
return final_output
|
|
268
301
|
|
|
@@ -49,6 +49,10 @@ def common_cozeloop_report_source(**kwargs) -> str:
|
|
|
49
49
|
return "veadk"
|
|
50
50
|
|
|
51
51
|
|
|
52
|
+
def common_cozeloop_call_type(**kwargs) -> str:
|
|
53
|
+
return kwargs.get("call_type")
|
|
54
|
+
|
|
55
|
+
|
|
52
56
|
def llm_openinference_instrumentation_veadk(**kwargs) -> str:
|
|
53
57
|
return VERSION
|
|
54
58
|
|
|
@@ -68,4 +72,5 @@ COMMON_ATTRIBUTES = {
|
|
|
68
72
|
"user.id": common_gen_ai_user_id, # CozeLoop / TLS required
|
|
69
73
|
"session.id": common_gen_ai_session_id, # CozeLoop / TLS required
|
|
70
74
|
"cozeloop.report.source": common_cozeloop_report_source, # CozeLoop required
|
|
75
|
+
"cozeloop.call_type": common_cozeloop_call_type, # CozeLoop required
|
|
71
76
|
}
|