sunholo 0.66.3__py3-none-any.whl → 0.66.5__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 +42 -1
- sunholo/agents/swagger.py +27 -2
- {sunholo-0.66.3.dist-info → sunholo-0.66.5.dist-info}/METADATA +4 -2
- {sunholo-0.66.3.dist-info → sunholo-0.66.5.dist-info}/RECORD +8 -8
- {sunholo-0.66.3.dist-info → sunholo-0.66.5.dist-info}/LICENSE.txt +0 -0
- {sunholo-0.66.3.dist-info → sunholo-0.66.5.dist-info}/WHEEL +0 -0
- {sunholo-0.66.3.dist-info → sunholo-0.66.5.dist-info}/entry_points.txt +0 -0
- {sunholo-0.66.3.dist-info → sunholo-0.66.5.dist-info}/top_level.txt +0 -0
|
@@ -27,7 +27,8 @@ from ...utils.config import load_config
|
|
|
27
27
|
from ...utils.version import sunholo_version
|
|
28
28
|
import os
|
|
29
29
|
from ...gcs.add_file import add_file_to_gcs, handle_base64_image
|
|
30
|
-
|
|
30
|
+
from ..swagger import validate_api_key
|
|
31
|
+
from datetime import datetime, timedelta
|
|
31
32
|
|
|
32
33
|
try:
|
|
33
34
|
from flask import request, jsonify, Response
|
|
@@ -39,6 +40,9 @@ try:
|
|
|
39
40
|
except ImportError:
|
|
40
41
|
pass
|
|
41
42
|
|
|
43
|
+
# Cache dictionary to store validated API keys
|
|
44
|
+
api_key_cache = {}
|
|
45
|
+
cache_duration = timedelta(minutes=5) # Cache duration
|
|
42
46
|
|
|
43
47
|
def register_qna_routes(app, stream_interpreter, vac_interpreter):
|
|
44
48
|
"""
|
|
@@ -219,6 +223,43 @@ def register_qna_routes(app, stream_interpreter, vac_interpreter):
|
|
|
219
223
|
# {'answer': 'output'}
|
|
220
224
|
return jsonify(bot_output)
|
|
221
225
|
|
|
226
|
+
@app.before_request
|
|
227
|
+
def check_authentication_header():
|
|
228
|
+
if request.path.startswith('/openai/'):
|
|
229
|
+
auth_header = request.headers.get('Authorization')
|
|
230
|
+
if auth_header:
|
|
231
|
+
api_key = auth_header.split(' ')[1] # Assuming "Bearer <api_key>"
|
|
232
|
+
endpoints_host = os.getenv('_ENDPOINTS_HOST')
|
|
233
|
+
if not endpoints_host:
|
|
234
|
+
return jsonify({'error': '_ENDPOINTS_HOST environment variable not found'}), 401
|
|
235
|
+
|
|
236
|
+
# Check cache first
|
|
237
|
+
current_time = datetime.now()
|
|
238
|
+
if api_key in api_key_cache:
|
|
239
|
+
cached_result, cache_time = api_key_cache[api_key]
|
|
240
|
+
if current_time - cache_time < cache_duration:
|
|
241
|
+
if not cached_result:
|
|
242
|
+
return jsonify({'error': 'Invalid cached API key'}), 401
|
|
243
|
+
else:
|
|
244
|
+
return # Valid API key, continue to the endpoint
|
|
245
|
+
else:
|
|
246
|
+
# Cache expired, remove from cache
|
|
247
|
+
del api_key_cache[api_key]
|
|
248
|
+
|
|
249
|
+
# Validate API key
|
|
250
|
+
is_valid = validate_api_key(api_key, endpoints_host)
|
|
251
|
+
# Update cache
|
|
252
|
+
api_key_cache[api_key] = (is_valid, current_time)
|
|
253
|
+
|
|
254
|
+
if not is_valid:
|
|
255
|
+
return jsonify({'error': 'Invalid API key'}), 401
|
|
256
|
+
else:
|
|
257
|
+
return jsonify({'error': 'Missing Authorization header'}), 401
|
|
258
|
+
|
|
259
|
+
@app.route('/openai/health', methods=['GET', 'POST'])
|
|
260
|
+
def openai_health_endpoint():
|
|
261
|
+
return jsonify({'message': 'Success'})
|
|
262
|
+
|
|
222
263
|
@app.route('/openai/v1/chat/completions', methods=['POST'])
|
|
223
264
|
@app.route('/openai/v1/chat/completions/<vector_name>', methods=['POST'])
|
|
224
265
|
def openai_compatible_endpoint(vector_name=None):
|
sunholo/agents/swagger.py
CHANGED
|
@@ -6,6 +6,31 @@ from ruamel.yaml import YAML
|
|
|
6
6
|
from io import StringIO
|
|
7
7
|
# check it here:
|
|
8
8
|
# https://editor.swagger.io/
|
|
9
|
+
from functools import lru_cache
|
|
10
|
+
|
|
11
|
+
try:
|
|
12
|
+
from google.cloud import endpoints_v1
|
|
13
|
+
except ImportError:
|
|
14
|
+
endpoints_v1 = None
|
|
15
|
+
|
|
16
|
+
def validate_api_key(api_key: str, service_name: str) -> bool:
|
|
17
|
+
"""
|
|
18
|
+
Validate an API key against the service name e.g. 'endpoints-xxxx.a.run.app'
|
|
19
|
+
"""
|
|
20
|
+
if not endpoints_v1:
|
|
21
|
+
raise ImportError("Cloud Endpoints API key validation is required, install via `pip install google-cloud-endpoints`")
|
|
22
|
+
|
|
23
|
+
return _validate_api_key_cached(api_key, service_name)
|
|
24
|
+
|
|
25
|
+
@lru_cache(maxsize=1024)
|
|
26
|
+
def _validate_api_key_cached(api_key: str, service_name: str) -> bool:
|
|
27
|
+
client = endpoints_v1.ServiceControlServiceClient()
|
|
28
|
+
response = client.check(
|
|
29
|
+
service_name=service_name,
|
|
30
|
+
operation={'consumer_id': f'api_key:{api_key}'}
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
return response.check_errors is None
|
|
9
34
|
|
|
10
35
|
def config_to_swagger():
|
|
11
36
|
"""
|
|
@@ -123,8 +148,8 @@ def generate_swagger(vac_config, agent_config):
|
|
|
123
148
|
swagger_template = {
|
|
124
149
|
'swagger': '2.0',
|
|
125
150
|
'info': {
|
|
126
|
-
'title': 'Multivac - Cloud Endpoints + Cloud Run',
|
|
127
|
-
'description': 'Multivac
|
|
151
|
+
'title': 'Multivac ${_BRANCH_NAME} - Cloud Endpoints + Cloud Run',
|
|
152
|
+
'description': 'Multivac Endpoints - see documentation at https://dev.sunholo.com/',
|
|
128
153
|
'version': '0.1.0'
|
|
129
154
|
},
|
|
130
155
|
'host': '${_ENDPOINTS_HOST}',
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: sunholo
|
|
3
|
-
Version: 0.66.
|
|
3
|
+
Version: 0.66.5
|
|
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.66.
|
|
6
|
+
Download-URL: https://github.com/sunholo-data/sunholo-py/archive/refs/tags/v0.66.5.tar.gz
|
|
7
7
|
Author: Holosun ApS
|
|
8
8
|
Author-email: multivac@sunholo.com
|
|
9
9
|
License: Apache License, Version 2.0
|
|
@@ -36,6 +36,7 @@ Requires-Dist: google-api-python-client ; extra == 'all'
|
|
|
36
36
|
Requires-Dist: google-cloud-alloydb-connector[pg8000] ; extra == 'all'
|
|
37
37
|
Requires-Dist: google-cloud-bigquery ; extra == 'all'
|
|
38
38
|
Requires-Dist: google-cloud-build ; extra == 'all'
|
|
39
|
+
Requires-Dist: google-endpoints ; extra == 'all'
|
|
39
40
|
Requires-Dist: google-cloud-logging ; extra == 'all'
|
|
40
41
|
Requires-Dist: google-cloud-storage ; extra == 'all'
|
|
41
42
|
Requires-Dist: google-cloud-pubsub ; extra == 'all'
|
|
@@ -81,6 +82,7 @@ Requires-Dist: google-auth-oauthlib ; extra == 'gcp'
|
|
|
81
82
|
Requires-Dist: google-cloud-aiplatform ; extra == 'gcp'
|
|
82
83
|
Requires-Dist: google-cloud-bigquery ; extra == 'gcp'
|
|
83
84
|
Requires-Dist: google-cloud-build ; extra == 'gcp'
|
|
85
|
+
Requires-Dist: google-endpoints ; extra == 'gcp'
|
|
84
86
|
Requires-Dist: google-cloud-storage ; extra == 'gcp'
|
|
85
87
|
Requires-Dist: google-cloud-logging ; extra == 'gcp'
|
|
86
88
|
Requires-Dist: google-cloud-pubsub ; extra == 'gcp'
|
|
@@ -7,13 +7,13 @@ sunholo/agents/langserve.py,sha256=FdhQjorAY2bMn2rpuabNT6bU3uqSKWrl8DjpH3L_V7k,4
|
|
|
7
7
|
sunholo/agents/pubsub.py,sha256=5hbbhbBGyVWRpt2sAGC5FEheYH1mCCwVUhZEB1S7vGg,1337
|
|
8
8
|
sunholo/agents/route.py,sha256=V1HKXTvaNuYgjmT5_QgIQum4O7O0Mw497m6YiMpEzX0,2383
|
|
9
9
|
sunholo/agents/special_commands.py,sha256=ecD5jrBVXo170sdgPILi0m_m_4nRFEv6qKn5zYEvEK8,6494
|
|
10
|
-
sunholo/agents/swagger.py,sha256=
|
|
10
|
+
sunholo/agents/swagger.py,sha256=bX4SkHt-0Qjm7dslK9Vf_6deyh-4ibEn2COjIEGbME4,12388
|
|
11
11
|
sunholo/agents/fastapi/__init__.py,sha256=S_pj4_bTUmDGoq_exaREHlOKThi0zTuGT0VZY0YfODQ,88
|
|
12
12
|
sunholo/agents/fastapi/base.py,sha256=clk76cHbUAvU0OYJrRfCWX_5f0ACbhDsIzYBhI3wyoE,2514
|
|
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=bHZSsNrgBCu-AVhOJ5WmvKCogsHHOXEXK65k4tccnnM,20948
|
|
17
17
|
sunholo/archive/__init__.py,sha256=qNHWm5rGPVOlxZBZCpA1wTYPbalizRT7f8X4rs2t290,31
|
|
18
18
|
sunholo/archive/archive.py,sha256=C-UhG5x-XtZ8VheQp92IYJqgD0V3NFQjniqlit94t18,1197
|
|
19
19
|
sunholo/auth/__init__.py,sha256=4owDjSaWYkbTlPK47UHTOC0gCWbZsqn4ZIEw5NWZTlg,28
|
|
@@ -104,9 +104,9 @@ sunholo/vertex/__init__.py,sha256=JvHcGFuv6R_nAhY2AdoqqhMpJ5ugeWPZ_svGhWrObBk,13
|
|
|
104
104
|
sunholo/vertex/init.py,sha256=JDMUaBRdednzbKF-5p33qqLit2LMsvgvWW-NRz0AqO0,1801
|
|
105
105
|
sunholo/vertex/memory_tools.py,sha256=8F1iTWnqEK9mX4W5RzCVKIjydIcNp6OFxjn_dtQ3GXo,5379
|
|
106
106
|
sunholo/vertex/safety.py,sha256=3meAX0HyGZYrH7rXPUAHxtI_3w_zoy_RX7Shtkoa660,1275
|
|
107
|
-
sunholo-0.66.
|
|
108
|
-
sunholo-0.66.
|
|
109
|
-
sunholo-0.66.
|
|
110
|
-
sunholo-0.66.
|
|
111
|
-
sunholo-0.66.
|
|
112
|
-
sunholo-0.66.
|
|
107
|
+
sunholo-0.66.5.dist-info/LICENSE.txt,sha256=SdE3QjnD3GEmqqg9EX3TM9f7WmtOzqS1KJve8rhbYmU,11345
|
|
108
|
+
sunholo-0.66.5.dist-info/METADATA,sha256=ESpWjQSCpZfxbsF1eUCZ5Op13ztl3Kb0ANiyYdK4LpQ,6096
|
|
109
|
+
sunholo-0.66.5.dist-info/WHEEL,sha256=cpQTJ5IWu9CdaPViMhC9YzF8gZuS5-vlfoFihTBC86A,91
|
|
110
|
+
sunholo-0.66.5.dist-info/entry_points.txt,sha256=bZuN5AIHingMPt4Ro1b_T-FnQvZ3teBes-3OyO0asl4,49
|
|
111
|
+
sunholo-0.66.5.dist-info/top_level.txt,sha256=wt5tadn5--5JrZsjJz2LceoUvcrIvxjHJe-RxuudxAk,8
|
|
112
|
+
sunholo-0.66.5.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|