sunholo 0.71.14__py3-none-any.whl → 0.71.16__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.
- sunholo/agents/flask/qna_routes.py +1 -2
- sunholo/gcs/add_file.py +45 -17
- sunholo/vertex/__init__.py +1 -0
- sunholo/vertex/extensions_class.py +74 -12
- {sunholo-0.71.14.dist-info → sunholo-0.71.16.dist-info}/METADATA +2 -2
- {sunholo-0.71.14.dist-info → sunholo-0.71.16.dist-info}/RECORD +10 -10
- {sunholo-0.71.14.dist-info → sunholo-0.71.16.dist-info}/LICENSE.txt +0 -0
- {sunholo-0.71.14.dist-info → sunholo-0.71.16.dist-info}/WHEEL +0 -0
- {sunholo-0.71.14.dist-info → sunholo-0.71.16.dist-info}/entry_points.txt +0 -0
- {sunholo-0.71.14.dist-info → sunholo-0.71.16.dist-info}/top_level.txt +0 -0
|
@@ -15,7 +15,6 @@
|
|
|
15
15
|
|
|
16
16
|
import json
|
|
17
17
|
import traceback
|
|
18
|
-
import datetime
|
|
19
18
|
import uuid
|
|
20
19
|
|
|
21
20
|
from ...agents import extract_chat_history, handle_special_commands
|
|
@@ -142,7 +141,7 @@ def register_qna_routes(app, stream_interpreter, vac_interpreter):
|
|
|
142
141
|
name="start_streaming_chat",
|
|
143
142
|
metadata=vac_config,
|
|
144
143
|
input = all_input,
|
|
145
|
-
completion_start_time=datetime.
|
|
144
|
+
completion_start_time=datetime.now(),
|
|
146
145
|
model=vac_config.get("model") or vac_config.get("llm")
|
|
147
146
|
)
|
|
148
147
|
|
sunholo/gcs/add_file.py
CHANGED
|
@@ -25,25 +25,63 @@ from ..logging import log
|
|
|
25
25
|
from ..utils.config import load_config_key
|
|
26
26
|
|
|
27
27
|
|
|
28
|
-
def handle_base64_image(base64_data, vector_name):
|
|
28
|
+
def handle_base64_image(base64_data: str, vector_name: str, extension: str):
|
|
29
|
+
"""
|
|
30
|
+
Handle base64 image data, decode it, save it as a file, upload it to GCS, and return the image URI and MIME type.
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
base64_data (str): The base64 encoded image data.
|
|
34
|
+
vector_name (str): The vector name for the GCS path.
|
|
35
|
+
extension (str): The file extension of the image (e.g., ".jpg", ".png").
|
|
36
|
+
|
|
37
|
+
Returns:
|
|
38
|
+
Tuple[str, str]: The URI of the uploaded image and the MIME type.
|
|
39
|
+
"""
|
|
29
40
|
model = load_config_key("llm", vector_name, "vacConfig")
|
|
30
|
-
if model.startswith("openai"):
|
|
31
|
-
return base64_data, base64_data.split(",",1)
|
|
32
|
-
|
|
41
|
+
if model.startswith("openai"): # pass it to gpt directly
|
|
42
|
+
return base64_data, base64_data.split(",", 1)
|
|
43
|
+
|
|
33
44
|
try:
|
|
34
45
|
header, encoded = base64_data.split(",", 1)
|
|
35
46
|
data = base64.b64decode(encoded)
|
|
36
47
|
|
|
37
|
-
filename = f"{uuid.uuid4()}
|
|
48
|
+
filename = f"{uuid.uuid4()}{extension}"
|
|
38
49
|
with open(filename, "wb") as f:
|
|
39
50
|
f.write(data)
|
|
40
51
|
|
|
41
52
|
image_uri = add_file_to_gcs(filename, vector_name)
|
|
42
53
|
os.remove(filename) # Clean up the saved file
|
|
43
|
-
|
|
54
|
+
|
|
55
|
+
# Determine MIME type based on extension
|
|
56
|
+
mime_type = {
|
|
57
|
+
".jpg": "image/jpeg",
|
|
58
|
+
".jpeg": "image/jpeg",
|
|
59
|
+
".png": "image/png",
|
|
60
|
+
".gif": "image/gif",
|
|
61
|
+
".bmp": "image/bmp",
|
|
62
|
+
".tiff": "image/tiff"
|
|
63
|
+
}.get(extension.lower(), "application/octet-stream") # Default MIME type if unknown
|
|
64
|
+
|
|
65
|
+
return image_uri, mime_type
|
|
44
66
|
except Exception as e:
|
|
45
67
|
raise Exception(f'Base64 image upload failed: {str(e)}')
|
|
46
68
|
|
|
69
|
+
|
|
70
|
+
def resolve_bucket(vector_name):
|
|
71
|
+
bucket_config = load_config_key("upload", vector_name, "vacConfig")
|
|
72
|
+
if bucket_config:
|
|
73
|
+
if bucket_config.get("buckets"):
|
|
74
|
+
bucket_name = bucket_config.get("buckets").get("all")
|
|
75
|
+
|
|
76
|
+
bucket_name = bucket_name if bucket_name else os.getenv('GCS_BUCKET', None)
|
|
77
|
+
if bucket_name is None:
|
|
78
|
+
raise ValueError("No bucket found to upload to: GCS_BUCKET returned None")
|
|
79
|
+
|
|
80
|
+
if bucket_name.startswith("gs://"):
|
|
81
|
+
bucket_name = bucket_name.removeprefix("gs://")
|
|
82
|
+
|
|
83
|
+
return bucket_name
|
|
84
|
+
|
|
47
85
|
def add_file_to_gcs(filename: str, vector_name:str, bucket_name: str=None, metadata:dict=None, bucket_filepath:str=None):
|
|
48
86
|
|
|
49
87
|
if not storage:
|
|
@@ -56,17 +94,7 @@ def add_file_to_gcs(filename: str, vector_name:str, bucket_name: str=None, metad
|
|
|
56
94
|
return None
|
|
57
95
|
|
|
58
96
|
if bucket_name is None:
|
|
59
|
-
|
|
60
|
-
if bucket_config:
|
|
61
|
-
if bucket_config.get("buckets"):
|
|
62
|
-
bucket_name = bucket_config.get("buckets").get("all")
|
|
63
|
-
|
|
64
|
-
bucket_name = bucket_name if bucket_name else os.getenv('GCS_BUCKET', None)
|
|
65
|
-
if bucket_name is None:
|
|
66
|
-
raise ValueError("No bucket found to upload to: GCS_BUCKET returned None")
|
|
67
|
-
|
|
68
|
-
if bucket_name.startswith("gs://"):
|
|
69
|
-
bucket_name = bucket_name.removeprefix("gs://")
|
|
97
|
+
bucket_name = resolve_bucket(vector_name)
|
|
70
98
|
|
|
71
99
|
bucket = storage_client.get_bucket(bucket_name)
|
|
72
100
|
now = datetime.datetime.now()
|
sunholo/vertex/__init__.py
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+
try:
|
|
2
|
+
from vertexai.preview import extensions
|
|
3
|
+
except ImportError:
|
|
4
|
+
extensions = None
|
|
5
|
+
|
|
2
6
|
from .init import init_vertex
|
|
3
7
|
from ..logging import log
|
|
4
8
|
from ..utils.gcp_project import get_gcp_project
|
|
@@ -9,6 +13,9 @@ from io import StringIO
|
|
|
9
13
|
|
|
10
14
|
class VertexAIExtensions:
|
|
11
15
|
def __init__(self):
|
|
16
|
+
if extensions is None:
|
|
17
|
+
raise ImportError("VertexAIExtensions needs vertexai.previewextensions to be installed. Install via `pip install sunholo[gcp]`")
|
|
18
|
+
|
|
12
19
|
self.CODE_INTERPRETER_WRITTEN_FILES = []
|
|
13
20
|
self.css_styles = """
|
|
14
21
|
<style>
|
|
@@ -21,6 +28,20 @@ class VertexAIExtensions:
|
|
|
21
28
|
self.IMAGE_FILE_EXTENSIONS = set(["jpg", "jpeg", "png"])
|
|
22
29
|
self.location = "us-central1"
|
|
23
30
|
|
|
31
|
+
def list_extensions(self):
|
|
32
|
+
the_list = extensions.Extension.list()
|
|
33
|
+
|
|
34
|
+
extensions_list = []
|
|
35
|
+
for ext in the_list:
|
|
36
|
+
extensions_list.append({
|
|
37
|
+
"resource_name": getattr(ext, 'resource_name', ''),
|
|
38
|
+
"display_name": getattr(ext, 'display_name', 'N/A'),
|
|
39
|
+
"description": getattr(ext, 'description', 'N/A')
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
return extensions_list
|
|
43
|
+
|
|
44
|
+
|
|
24
45
|
def get_extension_import_config(self, display_name: str, description: str,
|
|
25
46
|
api_spec_gcs: dict, service_account_name: dict, tool_use_examples: list):
|
|
26
47
|
tool_use_examples = [
|
|
@@ -115,11 +136,35 @@ class VertexAIExtensions:
|
|
|
115
136
|
|
|
116
137
|
return response
|
|
117
138
|
|
|
118
|
-
def execute_code_extension(self,
|
|
139
|
+
def execute_code_extension(self,
|
|
140
|
+
query: str,
|
|
141
|
+
filenames: list[str] = None,
|
|
142
|
+
gcs_files: list[str] = None,
|
|
143
|
+
bucket_name: str = None):
|
|
119
144
|
if filenames and gcs_files:
|
|
120
145
|
raise ValueError("Can't specify both filenames and gcs_files")
|
|
146
|
+
|
|
147
|
+
listed_extensions = self.list_extensions()
|
|
148
|
+
code_interpreter_exists = False
|
|
149
|
+
for ext in listed_extensions:
|
|
150
|
+
if ext.get('display_name') == 'Code Interpreter':
|
|
151
|
+
code_interpreter_exists = True
|
|
152
|
+
extension_code_interpreter = extensions.Extension(ext['resource_name'])
|
|
153
|
+
break
|
|
154
|
+
|
|
155
|
+
if not code_interpreter_exists:
|
|
156
|
+
if bucket_name:
|
|
157
|
+
runtime_config = {
|
|
158
|
+
"codeInterpreterRuntimeConfig": {
|
|
159
|
+
"fileInputGcsBucket": f"{bucket_name}/extensions/input/",
|
|
160
|
+
"fileOutputGcsBucket": f"{bucket_name}/extensions/output/",
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
extension_code_interpreter = extensions.Extension.from_hub("code_interpreter", runtime_config=runtime_config)
|
|
121
164
|
|
|
122
|
-
|
|
165
|
+
# This field is only applicable when `file_output_gcs_bucket` is specified in `Extension.CodeInterpreterRuntimeConfig`.
|
|
166
|
+
|
|
167
|
+
operation_params = {"query": query}
|
|
123
168
|
|
|
124
169
|
file_arr = None
|
|
125
170
|
if filenames:
|
|
@@ -130,20 +175,37 @@ class VertexAIExtensions:
|
|
|
130
175
|
}
|
|
131
176
|
for filename in filenames
|
|
132
177
|
]
|
|
133
|
-
|
|
178
|
+
operation_params["files"] = file_arr
|
|
179
|
+
|
|
180
|
+
if gcs_files:
|
|
181
|
+
operation_params["file_gcs_uris"] = gcs_files
|
|
182
|
+
log.info("Executing code interpreter")
|
|
134
183
|
response = extension_code_interpreter.execute(
|
|
135
184
|
operation_id="generate_and_execute",
|
|
136
|
-
operation_params=
|
|
137
|
-
"query": query,
|
|
138
|
-
"files": file_arr,
|
|
139
|
-
"file_gcs_uris": gcs_files
|
|
140
|
-
})
|
|
185
|
+
operation_params=operation_params)
|
|
141
186
|
|
|
142
187
|
self.CODE_INTERPRETER_WRITTEN_FILES.extend(
|
|
143
188
|
[item['name'] for item in response['output_files']])
|
|
144
189
|
|
|
145
190
|
if response.get('execution_error'):
|
|
191
|
+
#TODO: setup iteration many times with a timeout
|
|
146
192
|
log.error(f"Code Execution Response failed with: {response.get('execution_error')} - maybe retry?")
|
|
193
|
+
new_query = f"""
|
|
194
|
+
<original_query>{query}</original_query>
|
|
195
|
+
<original_output>{response.get('generated_code')}</original_output>
|
|
196
|
+
The code above failed with this error:
|
|
197
|
+
<code_error>{response.get('execution_error')}</code_error>
|
|
198
|
+
Please try again again to satisfy the original query.
|
|
199
|
+
"""
|
|
200
|
+
operation_params = {"query": new_query}
|
|
201
|
+
response = extension_code_interpreter.execute(
|
|
202
|
+
operation_id="generate_and_execute",
|
|
203
|
+
operation_params=operation_params)
|
|
204
|
+
|
|
205
|
+
self.CODE_INTERPRETER_WRITTEN_FILES.extend([item['name'] for item in response['output_files']])
|
|
206
|
+
if response.get('execution_error'):
|
|
207
|
+
log.error(f"Code Execution Response failed twice: {response.get('execution_error')}")
|
|
208
|
+
|
|
147
209
|
|
|
148
210
|
return response
|
|
149
211
|
|
|
@@ -195,7 +257,7 @@ class VertexAIExtensions:
|
|
|
195
257
|
buffer_html = [details_tml.format(**_file) for _file in file_list]
|
|
196
258
|
return "".join(buffer_html)
|
|
197
259
|
|
|
198
|
-
def process_response(self, response: dict,
|
|
260
|
+
def process_response(self, response: dict, save_file_name=None) -> str:
|
|
199
261
|
result_template = """
|
|
200
262
|
<details open>
|
|
201
263
|
<summary class='main_summary'>{summary}:</summary>
|
|
@@ -234,8 +296,8 @@ class VertexAIExtensions:
|
|
|
234
296
|
{result}
|
|
235
297
|
</div>
|
|
236
298
|
"""
|
|
237
|
-
if
|
|
238
|
-
with open('code_execution_results.html', 'w') as file:
|
|
299
|
+
if save_file_name:
|
|
300
|
+
with open(save_file_name or 'code_execution_results.html', 'w') as file:
|
|
239
301
|
file.write(html_content)
|
|
240
302
|
|
|
241
303
|
return html_content
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: sunholo
|
|
3
|
-
Version: 0.71.
|
|
3
|
+
Version: 0.71.16
|
|
4
4
|
Summary: Large Language Model DevOps - a package to help deploy LLMs to the Cloud.
|
|
5
5
|
Home-page: https://github.com/sunholo-data/sunholo-py
|
|
6
|
-
Download-URL: https://github.com/sunholo-data/sunholo-py/archive/refs/tags/v0.71.
|
|
6
|
+
Download-URL: https://github.com/sunholo-data/sunholo-py/archive/refs/tags/v0.71.16.tar.gz
|
|
7
7
|
Author: Holosun ApS
|
|
8
8
|
Author-email: multivac@sunholo.com
|
|
9
9
|
License: Apache License, Version 2.0
|
|
@@ -13,7 +13,7 @@ sunholo/agents/fastapi/base.py,sha256=clk76cHbUAvU0OYJrRfCWX_5f0ACbhDsIzYBhI3wyo
|
|
|
13
13
|
sunholo/agents/fastapi/qna_routes.py,sha256=DgK4Btu5XriOC1JaRQ4G_nWEjJfnQ0J5pyLanF6eF1g,3857
|
|
14
14
|
sunholo/agents/flask/__init__.py,sha256=uqfHNw2Ru3EJ4dJEcbp86h_lkquBQPMxZbjhV_xe3rs,72
|
|
15
15
|
sunholo/agents/flask/base.py,sha256=FgSaCODyoTtlstJtsqlLPScdgRUtv9_plxftdzHdVFo,809
|
|
16
|
-
sunholo/agents/flask/qna_routes.py,sha256=
|
|
16
|
+
sunholo/agents/flask/qna_routes.py,sha256=TUsVn1MGcJ-8JFET5aR9mjGPd4z6K__SjTN8JOOsiTU,21814
|
|
17
17
|
sunholo/agents/flask/vac_routes.py,sha256=l2-w7x437F0Uu3QvwNueEYPtnKuIee6bHJ7LUMt_tkY,19520
|
|
18
18
|
sunholo/archive/__init__.py,sha256=qNHWm5rGPVOlxZBZCpA1wTYPbalizRT7f8X4rs2t290,31
|
|
19
19
|
sunholo/archive/archive.py,sha256=C-UhG5x-XtZ8VheQp92IYJqgD0V3NFQjniqlit94t18,1197
|
|
@@ -67,7 +67,7 @@ sunholo/discovery_engine/discovery_engine_client.py,sha256=YYsFeaW41l8jmWCruQnYx
|
|
|
67
67
|
sunholo/embedder/__init__.py,sha256=sI4N_CqgEVcrMDxXgxKp1FsfsB4FpjoXgPGkl4N_u4I,44
|
|
68
68
|
sunholo/embedder/embed_chunk.py,sha256=d_dIzeNF630Q0Ar-u1hxos60s0tLIImJccAvuo_LTIw,6814
|
|
69
69
|
sunholo/gcs/__init__.py,sha256=DtVw_AZwQn-IguR5BJuIi2XJeF_FQXizhJikzRNrXiE,50
|
|
70
|
-
sunholo/gcs/add_file.py,sha256=
|
|
70
|
+
sunholo/gcs/add_file.py,sha256=K4lvNy22qtFFSJUh6xM7nmJ8_CT-0BIGSNxNXWIt3-U,6643
|
|
71
71
|
sunholo/gcs/download_url.py,sha256=8XSEf8byfubqs5CMQeF_tn9wxqwUTq3n9mo5mLNIUTA,4801
|
|
72
72
|
sunholo/gcs/metadata.py,sha256=C9sMPsHsq1ETetdQCqB3EBs3Kws8b8QHS9L7ei_v5aw,891
|
|
73
73
|
sunholo/langfuse/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -109,15 +109,15 @@ sunholo/utils/parsers.py,sha256=z98cQ1v2_ScnqHxCtApNeAN2the8MdvS6RpKL6vWyOU,5287
|
|
|
109
109
|
sunholo/utils/timedelta.py,sha256=BbLabEx7_rbErj_YbNM0MBcaFN76DC4PTe4zD2ucezg,493
|
|
110
110
|
sunholo/utils/user_ids.py,sha256=SQd5_H7FE7vcTZp9AQuQDWBXd4FEEd7TeVMQe1H4Ny8,292
|
|
111
111
|
sunholo/utils/version.py,sha256=P1QAJQdZfT2cMqdTSmXmcxrD2PssMPEGM-WI6083Fck,237
|
|
112
|
-
sunholo/vertex/__init__.py,sha256=
|
|
112
|
+
sunholo/vertex/__init__.py,sha256=XH7FUKxdIgN9H2iDcWxL3sRnVHC3297G24RqEn4Ob0Y,240
|
|
113
113
|
sunholo/vertex/extensions.py,sha256=d-Ikt9gHFf-jUMPmyU-xHwYe22QtEyr90Ua1LDKgTws,11026
|
|
114
|
-
sunholo/vertex/extensions_class.py,sha256=
|
|
114
|
+
sunholo/vertex/extensions_class.py,sha256=flvWNxzY_0z_nDuoaXq96mmLCON1At793NpEeaJ6T0E,11893
|
|
115
115
|
sunholo/vertex/init.py,sha256=-w7b9GKsyJnAJpYHYz6_zBUtmeJeLXlEkgOfwoe4DEI,2715
|
|
116
116
|
sunholo/vertex/memory_tools.py,sha256=FLTbNX_YbpxxUxZHAsXEihlUgLELfLOfxsdEkwDm_GI,6546
|
|
117
117
|
sunholo/vertex/safety.py,sha256=S9PgQT1O_BQAkcqauWncRJaydiP8Q_Jzmu9gxYfy1VA,2482
|
|
118
|
-
sunholo-0.71.
|
|
119
|
-
sunholo-0.71.
|
|
120
|
-
sunholo-0.71.
|
|
121
|
-
sunholo-0.71.
|
|
122
|
-
sunholo-0.71.
|
|
123
|
-
sunholo-0.71.
|
|
118
|
+
sunholo-0.71.16.dist-info/LICENSE.txt,sha256=SdE3QjnD3GEmqqg9EX3TM9f7WmtOzqS1KJve8rhbYmU,11345
|
|
119
|
+
sunholo-0.71.16.dist-info/METADATA,sha256=xw0dl33vOvPMlNI-Fd_848gY3STZpA7TQZghXh7f0MQ,6767
|
|
120
|
+
sunholo-0.71.16.dist-info/WHEEL,sha256=y4mX-SOX4fYIkonsAGA5N0Oy-8_gI4FXw5HNI1xqvWg,91
|
|
121
|
+
sunholo-0.71.16.dist-info/entry_points.txt,sha256=bZuN5AIHingMPt4Ro1b_T-FnQvZ3teBes-3OyO0asl4,49
|
|
122
|
+
sunholo-0.71.16.dist-info/top_level.txt,sha256=wt5tadn5--5JrZsjJz2LceoUvcrIvxjHJe-RxuudxAk,8
|
|
123
|
+
sunholo-0.71.16.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|