sunholo 0.66.3__py3-none-any.whl → 0.66.4__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.
@@ -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 - Cloud Endpoints with a Cloud Run backend',
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
3
+ Version: 0.66.4
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.3.tar.gz
6
+ Download-URL: https://github.com/sunholo-data/sunholo-py/archive/refs/tags/v0.66.4.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-cloud-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-cloud-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=muFMQ1-9MtVlvSyUrLKjmULe4inC_QMb0Iofa14QnXw,11540
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=9wJC_SDbn7A6EzqsbkQicApztAzvvtKvs6cztXhh9Dw,19027
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.3.dist-info/LICENSE.txt,sha256=SdE3QjnD3GEmqqg9EX3TM9f7WmtOzqS1KJve8rhbYmU,11345
108
- sunholo-0.66.3.dist-info/METADATA,sha256=leJE_PT71BuDO_rc6o3ftNGgyzG0xGGzTDVbnclv6Ug,5998
109
- sunholo-0.66.3.dist-info/WHEEL,sha256=cpQTJ5IWu9CdaPViMhC9YzF8gZuS5-vlfoFihTBC86A,91
110
- sunholo-0.66.3.dist-info/entry_points.txt,sha256=bZuN5AIHingMPt4Ro1b_T-FnQvZ3teBes-3OyO0asl4,49
111
- sunholo-0.66.3.dist-info/top_level.txt,sha256=wt5tadn5--5JrZsjJz2LceoUvcrIvxjHJe-RxuudxAk,8
112
- sunholo-0.66.3.dist-info/RECORD,,
107
+ sunholo-0.66.4.dist-info/LICENSE.txt,sha256=SdE3QjnD3GEmqqg9EX3TM9f7WmtOzqS1KJve8rhbYmU,11345
108
+ sunholo-0.66.4.dist-info/METADATA,sha256=D-c9BmPEj6dR-BUFMrhkDsW6X1UIQyHi5uTl_fu0FS4,6108
109
+ sunholo-0.66.4.dist-info/WHEEL,sha256=cpQTJ5IWu9CdaPViMhC9YzF8gZuS5-vlfoFihTBC86A,91
110
+ sunholo-0.66.4.dist-info/entry_points.txt,sha256=bZuN5AIHingMPt4Ro1b_T-FnQvZ3teBes-3OyO0asl4,49
111
+ sunholo-0.66.4.dist-info/top_level.txt,sha256=wt5tadn5--5JrZsjJz2LceoUvcrIvxjHJe-RxuudxAk,8
112
+ sunholo-0.66.4.dist-info/RECORD,,