sunholo 0.71.15__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/extensions_class.py +33 -3
- {sunholo-0.71.15.dist-info → sunholo-0.71.16.dist-info}/METADATA +2 -2
- {sunholo-0.71.15.dist-info → sunholo-0.71.16.dist-info}/RECORD +9 -9
- {sunholo-0.71.15.dist-info → sunholo-0.71.16.dist-info}/LICENSE.txt +0 -0
- {sunholo-0.71.15.dist-info → sunholo-0.71.16.dist-info}/WHEEL +0 -0
- {sunholo-0.71.15.dist-info → sunholo-0.71.16.dist-info}/entry_points.txt +0 -0
- {sunholo-0.71.15.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()
|
|
@@ -136,7 +136,11 @@ class VertexAIExtensions:
|
|
|
136
136
|
|
|
137
137
|
return response
|
|
138
138
|
|
|
139
|
-
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):
|
|
140
144
|
if filenames and gcs_files:
|
|
141
145
|
raise ValueError("Can't specify both filenames and gcs_files")
|
|
142
146
|
|
|
@@ -149,7 +153,16 @@ class VertexAIExtensions:
|
|
|
149
153
|
break
|
|
150
154
|
|
|
151
155
|
if not code_interpreter_exists:
|
|
152
|
-
|
|
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)
|
|
164
|
+
|
|
165
|
+
# This field is only applicable when `file_output_gcs_bucket` is specified in `Extension.CodeInterpreterRuntimeConfig`.
|
|
153
166
|
|
|
154
167
|
operation_params = {"query": query}
|
|
155
168
|
|
|
@@ -166,7 +179,7 @@ class VertexAIExtensions:
|
|
|
166
179
|
|
|
167
180
|
if gcs_files:
|
|
168
181
|
operation_params["file_gcs_uris"] = gcs_files
|
|
169
|
-
|
|
182
|
+
log.info("Executing code interpreter")
|
|
170
183
|
response = extension_code_interpreter.execute(
|
|
171
184
|
operation_id="generate_and_execute",
|
|
172
185
|
operation_params=operation_params)
|
|
@@ -175,7 +188,24 @@ class VertexAIExtensions:
|
|
|
175
188
|
[item['name'] for item in response['output_files']])
|
|
176
189
|
|
|
177
190
|
if response.get('execution_error'):
|
|
191
|
+
#TODO: setup iteration many times with a timeout
|
|
178
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
|
+
|
|
179
209
|
|
|
180
210
|
return response
|
|
181
211
|
|
|
@@ -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
|
|
@@ -111,13 +111,13 @@ sunholo/utils/user_ids.py,sha256=SQd5_H7FE7vcTZp9AQuQDWBXd4FEEd7TeVMQe1H4Ny8,292
|
|
|
111
111
|
sunholo/utils/version.py,sha256=P1QAJQdZfT2cMqdTSmXmcxrD2PssMPEGM-WI6083Fck,237
|
|
112
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
|