sunholo 0.64.6__py3-none-any.whl → 0.64.8__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/__init__.py +1 -0
- sunholo/agents/flask/qna_routes.py +121 -0
- sunholo/agents/route.py +10 -5
- sunholo/agents/swagger.py +208 -0
- sunholo/auth/run.py +2 -2
- sunholo/cli/chat_vac.py +2 -1
- sunholo/cli/cli.py +3 -1
- sunholo/cli/swagger.py +38 -0
- sunholo/database/alloydb.py +4 -0
- sunholo/streaming/stream_lookup.py +2 -1
- {sunholo-0.64.6.dist-info → sunholo-0.64.8.dist-info}/METADATA +2 -2
- {sunholo-0.64.6.dist-info → sunholo-0.64.8.dist-info}/RECORD +16 -14
- {sunholo-0.64.6.dist-info → sunholo-0.64.8.dist-info}/WHEEL +1 -1
- {sunholo-0.64.6.dist-info → sunholo-0.64.8.dist-info}/LICENSE.txt +0 -0
- {sunholo-0.64.6.dist-info → sunholo-0.64.8.dist-info}/entry_points.txt +0 -0
- {sunholo-0.64.6.dist-info → sunholo-0.64.8.dist-info}/top_level.txt +0 -0
sunholo/agents/__init__.py
CHANGED
|
@@ -4,3 +4,4 @@ from .pubsub import process_pubsub
|
|
|
4
4
|
from .special_commands import handle_special_commands, app_to_store, handle_files
|
|
5
5
|
from .flask import register_qna_routes, create_app
|
|
6
6
|
from .fastapi import register_qna_fastapi_routes, create_fastapi_app
|
|
7
|
+
from .swagger import config_to_swagger
|
|
@@ -41,7 +41,32 @@ except ImportError:
|
|
|
41
41
|
|
|
42
42
|
|
|
43
43
|
def register_qna_routes(app, stream_interpreter, vac_interpreter):
|
|
44
|
+
"""
|
|
45
|
+
Register Q&A routes for a Flask application.
|
|
44
46
|
|
|
47
|
+
This function sets up multiple routes for handling Q&A operations,
|
|
48
|
+
including streaming responses and processing static responses.
|
|
49
|
+
|
|
50
|
+
Args:
|
|
51
|
+
app (Flask): The Flask application instance.
|
|
52
|
+
stream_interpreter (function): Function to handle streaming Q&A responses.
|
|
53
|
+
vac_interpreter (function): Function to handle static Q&A responses.
|
|
54
|
+
|
|
55
|
+
Returns:
|
|
56
|
+
None
|
|
57
|
+
|
|
58
|
+
Example:
|
|
59
|
+
from flask import Flask
|
|
60
|
+
app = Flask(__name__)
|
|
61
|
+
|
|
62
|
+
def dummy_stream_interpreter(...):
|
|
63
|
+
...
|
|
64
|
+
|
|
65
|
+
def dummy_vac_interpreter(...):
|
|
66
|
+
...
|
|
67
|
+
|
|
68
|
+
register_qna_routes(app, dummy_stream_interpreter, dummy_vac_interpreter)
|
|
69
|
+
"""
|
|
45
70
|
@app.route("/")
|
|
46
71
|
def home():
|
|
47
72
|
return jsonify("OK")
|
|
@@ -52,6 +77,21 @@ def register_qna_routes(app, stream_interpreter, vac_interpreter):
|
|
|
52
77
|
|
|
53
78
|
@app.route('/vac/streaming/<vector_name>', methods=['POST'])
|
|
54
79
|
def stream_qa(vector_name):
|
|
80
|
+
"""
|
|
81
|
+
Handle streaming Q&A responses.
|
|
82
|
+
|
|
83
|
+
This function sets up a route to handle streaming Q&A responses based on
|
|
84
|
+
the provided vector name.
|
|
85
|
+
|
|
86
|
+
Args:
|
|
87
|
+
vector_name (str): The name of the vector for the request.
|
|
88
|
+
|
|
89
|
+
Returns:
|
|
90
|
+
Response: A Flask response object streaming the Q&A response content.
|
|
91
|
+
|
|
92
|
+
Example:
|
|
93
|
+
response = stream_qa("example_vector")
|
|
94
|
+
"""
|
|
55
95
|
observed_stream_interpreter = observe()(stream_interpreter)
|
|
56
96
|
prep = prep_vac(request, vector_name)
|
|
57
97
|
log.debug(f"Processing prep: {prep}")
|
|
@@ -117,6 +157,21 @@ def register_qna_routes(app, stream_interpreter, vac_interpreter):
|
|
|
117
157
|
|
|
118
158
|
@app.route('/vac/<vector_name>', methods=['POST'])
|
|
119
159
|
def process_qna(vector_name):
|
|
160
|
+
"""
|
|
161
|
+
Handle static Q&A responses.
|
|
162
|
+
|
|
163
|
+
This function sets up a route to handle static Q&A responses based on
|
|
164
|
+
the provided vector name.
|
|
165
|
+
|
|
166
|
+
Args:
|
|
167
|
+
vector_name (str): The name of the vector for the request.
|
|
168
|
+
|
|
169
|
+
Returns:
|
|
170
|
+
Response: A Flask response object with the Q&A response content.
|
|
171
|
+
|
|
172
|
+
Example:
|
|
173
|
+
response = process_qna("example_vector")
|
|
174
|
+
"""
|
|
120
175
|
observed_vac_interpreter = observe()(vac_interpreter)
|
|
121
176
|
prep = prep_vac(request, vector_name)
|
|
122
177
|
log.debug(f"Processing prep: {prep}")
|
|
@@ -167,6 +222,21 @@ def register_qna_routes(app, stream_interpreter, vac_interpreter):
|
|
|
167
222
|
@app.route('/openai/v1/chat/completions', methods=['POST'])
|
|
168
223
|
@app.route('/openai/v1/chat/completions/<vector_name>', methods=['POST'])
|
|
169
224
|
def openai_compatible_endpoint(vector_name=None):
|
|
225
|
+
"""
|
|
226
|
+
Handle OpenAI-compatible chat completions.
|
|
227
|
+
|
|
228
|
+
This function sets up routes to handle OpenAI-compatible chat completion requests,
|
|
229
|
+
both with and without a specified vector name.
|
|
230
|
+
|
|
231
|
+
Args:
|
|
232
|
+
vector_name (str, optional): The name of the vector for the request. Defaults to None.
|
|
233
|
+
|
|
234
|
+
Returns:
|
|
235
|
+
Response: A Flask response object with the chat completion content.
|
|
236
|
+
|
|
237
|
+
Example:
|
|
238
|
+
response = openai_compatible_endpoint("example_vector")
|
|
239
|
+
"""
|
|
170
240
|
data = request.get_json()
|
|
171
241
|
log.info(f'openai_compatible_endpoint got data: {data} for vector: {vector_name}')
|
|
172
242
|
|
|
@@ -301,6 +371,22 @@ def register_qna_routes(app, stream_interpreter, vac_interpreter):
|
|
|
301
371
|
|
|
302
372
|
|
|
303
373
|
def create_langfuse_trace(request, vector_name):
|
|
374
|
+
"""
|
|
375
|
+
Create a Langfuse trace for tracking requests.
|
|
376
|
+
|
|
377
|
+
This function initializes a Langfuse trace object based on the request headers
|
|
378
|
+
and vector name.
|
|
379
|
+
|
|
380
|
+
Args:
|
|
381
|
+
request (Request): The Flask request object.
|
|
382
|
+
vector_name (str): The name of the vector for the request.
|
|
383
|
+
|
|
384
|
+
Returns:
|
|
385
|
+
Langfuse.Trace: The Langfuse trace object.
|
|
386
|
+
|
|
387
|
+
Example:
|
|
388
|
+
trace = create_langfuse_trace(request, "example_vector")
|
|
389
|
+
"""
|
|
304
390
|
try:
|
|
305
391
|
from langfuse import Langfuse
|
|
306
392
|
langfuse = Langfuse()
|
|
@@ -327,6 +413,22 @@ def create_langfuse_trace(request, vector_name):
|
|
|
327
413
|
)
|
|
328
414
|
|
|
329
415
|
def prep_vac(request, vector_name):
|
|
416
|
+
"""
|
|
417
|
+
Prepare the input data for a VAC request.
|
|
418
|
+
|
|
419
|
+
This function processes the incoming request data, extracts relevant
|
|
420
|
+
information, and prepares the data for VAC processing.
|
|
421
|
+
|
|
422
|
+
Args:
|
|
423
|
+
request (Request): The Flask request object.
|
|
424
|
+
vector_name (str): The name of the vector for the request.
|
|
425
|
+
|
|
426
|
+
Returns:
|
|
427
|
+
dict: A dictionary containing prepared input data and metadata.
|
|
428
|
+
|
|
429
|
+
Example:
|
|
430
|
+
prep_data = prep_vac(request, "example_vector")
|
|
431
|
+
"""
|
|
330
432
|
#trace = create_langfuse_trace(request, vector_name)
|
|
331
433
|
trace = None
|
|
332
434
|
span = None
|
|
@@ -396,6 +498,25 @@ def prep_vac(request, vector_name):
|
|
|
396
498
|
|
|
397
499
|
|
|
398
500
|
def handle_file_upload(file, vector_name):
|
|
501
|
+
"""
|
|
502
|
+
Handle file upload and store the file in Google Cloud Storage.
|
|
503
|
+
|
|
504
|
+
This function saves the uploaded file locally, uploads it to Google Cloud Storage,
|
|
505
|
+
and then removes the local copy.
|
|
506
|
+
|
|
507
|
+
Args:
|
|
508
|
+
file (FileStorage): The uploaded file.
|
|
509
|
+
vector_name (str): The name of the vector for the request.
|
|
510
|
+
|
|
511
|
+
Returns:
|
|
512
|
+
tuple: A tuple containing the URI of the uploaded file and its MIME type.
|
|
513
|
+
|
|
514
|
+
Raises:
|
|
515
|
+
Exception: If the file upload fails.
|
|
516
|
+
|
|
517
|
+
Example:
|
|
518
|
+
uri, mime_type = handle_file_upload(file, "example_vector")
|
|
519
|
+
"""
|
|
399
520
|
try:
|
|
400
521
|
file.save(file.filename)
|
|
401
522
|
image_uri = add_file_to_gcs(file.filename, vector_name)
|
sunholo/agents/route.py
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
from ..logging import log
|
|
15
15
|
from ..utils import load_config_key, load_config
|
|
16
16
|
|
|
17
|
-
def
|
|
17
|
+
def route_vac(vector_name):
|
|
18
18
|
|
|
19
19
|
agent_url = load_config_key('agent_url', vector_name=vector_name, kind="vacConfig")
|
|
20
20
|
if agent_url:
|
|
@@ -35,17 +35,22 @@ def route_qna(vector_name):
|
|
|
35
35
|
log.info(f'agent_url: {agent_url}')
|
|
36
36
|
return agent_url
|
|
37
37
|
|
|
38
|
-
def route_endpoint(vector_name, override_endpoint=None):
|
|
38
|
+
def route_endpoint(vector_name, method = 'post', override_endpoint=None):
|
|
39
39
|
|
|
40
40
|
agent_type = load_config_key('agent_type', vector_name, kind="vacConfig")
|
|
41
41
|
if not agent_type:
|
|
42
42
|
agent_type = load_config_key('agent', vector_name, kind="vacConfig")
|
|
43
43
|
|
|
44
|
-
stem =
|
|
44
|
+
stem = route_vac(vector_name) if not override_endpoint else override_endpoint
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
agents_config = load_config_key(agent_type, vector_name, kind="agentConfig")
|
|
47
47
|
|
|
48
|
-
log.info(f"endpoints_config: {
|
|
48
|
+
log.info(f"endpoints_config: {agents_config}")
|
|
49
|
+
if method not in agents_config:
|
|
50
|
+
raise ValueError(f"Invalid method '{method}' for agent configuration.")
|
|
51
|
+
|
|
52
|
+
# 'post' or 'get'
|
|
53
|
+
endpoints_config = agents_config[method]
|
|
49
54
|
|
|
50
55
|
# Replace placeholders in the config
|
|
51
56
|
endpoints = {}
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import yaml
|
|
2
|
+
import copy
|
|
3
|
+
|
|
4
|
+
from ..utils.config import load_all_configs
|
|
5
|
+
from .route import route_vac
|
|
6
|
+
from ..logging import log
|
|
7
|
+
|
|
8
|
+
def config_to_swagger():
|
|
9
|
+
"""
|
|
10
|
+
Load configuration files and generate a Swagger specification.
|
|
11
|
+
|
|
12
|
+
This function loads the 'vacConfig' and 'agentConfig' configuration files,
|
|
13
|
+
validates their presence, and then generates a Swagger specification
|
|
14
|
+
based on these configurations.
|
|
15
|
+
|
|
16
|
+
Returns:
|
|
17
|
+
str: The generated Swagger specification in YAML format.
|
|
18
|
+
|
|
19
|
+
Raises:
|
|
20
|
+
ValueError: If 'vacConfig' or 'agentConfig' is not loaded.
|
|
21
|
+
|
|
22
|
+
Example:
|
|
23
|
+
```python
|
|
24
|
+
swagger_yaml = config_to_swagger()
|
|
25
|
+
print(swagger_yaml)
|
|
26
|
+
```
|
|
27
|
+
"""
|
|
28
|
+
configs = load_all_configs()
|
|
29
|
+
|
|
30
|
+
vac_config = configs.get('vacConfig')
|
|
31
|
+
agent_config = configs.get('agentConfig')
|
|
32
|
+
|
|
33
|
+
if not vac_config:
|
|
34
|
+
raise ValueError("Need valid 'vacConfig' loaded")
|
|
35
|
+
|
|
36
|
+
if not agent_config:
|
|
37
|
+
raise ValueError("Need valid 'agentConfig' loaded")
|
|
38
|
+
|
|
39
|
+
swag = generate_swagger(vac_config, agent_config)
|
|
40
|
+
|
|
41
|
+
return swag
|
|
42
|
+
|
|
43
|
+
def generate_swagger(vac_config, agent_config):
|
|
44
|
+
"""
|
|
45
|
+
Generate a Swagger specification based on the provided configurations.
|
|
46
|
+
|
|
47
|
+
This function creates a Swagger specification using the provided 'vacConfig'
|
|
48
|
+
and 'agentConfig'. It dynamically builds paths and responses based on the
|
|
49
|
+
configurations.
|
|
50
|
+
|
|
51
|
+
Args:
|
|
52
|
+
vac_config (dict): The VAC configuration.
|
|
53
|
+
agent_config (dict): The agent configuration.
|
|
54
|
+
|
|
55
|
+
Returns:
|
|
56
|
+
str: The generated Swagger specification in YAML format.
|
|
57
|
+
|
|
58
|
+
Example:
|
|
59
|
+
```python
|
|
60
|
+
vac_config = {
|
|
61
|
+
'vac': {
|
|
62
|
+
'service1': {
|
|
63
|
+
'llm': 'vertex',
|
|
64
|
+
'model': 'gemini-1.5-flash-001',
|
|
65
|
+
'agent': 'langserve'
|
|
66
|
+
},
|
|
67
|
+
'service2': {
|
|
68
|
+
'llm': 'openai',
|
|
69
|
+
'agent': 'crewai',
|
|
70
|
+
'secrets': ['OPENAI_API_KEY']
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
agent_config = {
|
|
76
|
+
'agents': {
|
|
77
|
+
'default': {
|
|
78
|
+
'stream': "{stem}/vac/streaming/{vector_name}",
|
|
79
|
+
'invoke': "{stem}/vac/{vector_name}",
|
|
80
|
+
'post': {
|
|
81
|
+
'stream': "{stem}/vac/streaming/{vector_name}",
|
|
82
|
+
'invoke': "{stem}/vac/{vector_name}",
|
|
83
|
+
'openai': "{stem}/openai/v1/chat/completions",
|
|
84
|
+
'openai-vac': "{stem}/openai/v1/chat/completions/{vector_name}"
|
|
85
|
+
},
|
|
86
|
+
'get': {
|
|
87
|
+
'home': "{stem}/",
|
|
88
|
+
'health': "{stem}/health"
|
|
89
|
+
},
|
|
90
|
+
'response': {
|
|
91
|
+
'invoke': {
|
|
92
|
+
'200': {
|
|
93
|
+
'description': 'Successful invocation response',
|
|
94
|
+
'schema': {
|
|
95
|
+
'type': 'object',
|
|
96
|
+
'properties': {
|
|
97
|
+
'answer': {'type': 'string'},
|
|
98
|
+
'source_documents': {
|
|
99
|
+
'type': 'array',
|
|
100
|
+
'items': {
|
|
101
|
+
'type': 'object',
|
|
102
|
+
'properties': {
|
|
103
|
+
'page_content': {'type': 'string'},
|
|
104
|
+
'metadata': {'type': 'string'}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
swagger_yaml = generate_swagger(vac_config, agent_config)
|
|
118
|
+
print(swagger_yaml)
|
|
119
|
+
```
|
|
120
|
+
"""
|
|
121
|
+
swagger_template = {
|
|
122
|
+
'swagger': '2.0',
|
|
123
|
+
'info': {
|
|
124
|
+
'title': 'Multivac - Cloud Endpoints + Cloud Run',
|
|
125
|
+
'description': 'Multivac - Cloud Endpoints with a Cloud Run backend',
|
|
126
|
+
'version': '0.1.0'
|
|
127
|
+
},
|
|
128
|
+
'host': '${_ENDPOINTS_HOST}',
|
|
129
|
+
'schemes': ['https'],
|
|
130
|
+
'produces': ['application/json'],
|
|
131
|
+
'paths': {}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
vac_services = vac_config['vac']
|
|
135
|
+
|
|
136
|
+
for vector_name, config in vac_services.items():
|
|
137
|
+
agent_type = config['agent']
|
|
138
|
+
agent_config_paths = agent_config['agents'].get(agent_type, {})
|
|
139
|
+
log.info(f'Configuring swagger for agent_type: {agent_type} for vector_name: {vector_name}')
|
|
140
|
+
try:
|
|
141
|
+
stem = route_vac(vector_name)
|
|
142
|
+
except ValueError:
|
|
143
|
+
stem = f"${{{agent_type.upper()}_BACKEND_URL}}"
|
|
144
|
+
log.warning(f"Failed to find URL stem for {vector_name}/{agent_type} - using {stem} instead")
|
|
145
|
+
|
|
146
|
+
for method, endpoints in agent_config_paths.items():
|
|
147
|
+
if method not in ['get', 'post']:
|
|
148
|
+
log.warning(f"Skipping {endpoints}")
|
|
149
|
+
continue
|
|
150
|
+
for endpoint_key, endpoint_template in endpoints.items():
|
|
151
|
+
endpoint_path = endpoint_template.replace("{stem}", f"/{agent_type}").replace("{vector_name}", vector_name)
|
|
152
|
+
if endpoint_path not in swagger_template['paths']:
|
|
153
|
+
swagger_template['paths'][endpoint_path] = {}
|
|
154
|
+
swagger_template['paths'][endpoint_path][method] = {
|
|
155
|
+
'summary': f"{method.capitalize()} {vector_name}",
|
|
156
|
+
'operationId': f"{method}_{agent_type}_{endpoint_key}",
|
|
157
|
+
'x-google-backend': {
|
|
158
|
+
'address': endpoint_template.replace("{stem}", stem).replace("{vector_name}", vector_name),
|
|
159
|
+
'protocol': 'h2'
|
|
160
|
+
},
|
|
161
|
+
'responses': copy.deepcopy(agent_config_paths.get('response', {}).get(endpoint_key, {
|
|
162
|
+
'200': {
|
|
163
|
+
'description': 'Default - A successful response',
|
|
164
|
+
'schema': {
|
|
165
|
+
'type': 'string'
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}))
|
|
169
|
+
}
|
|
170
|
+
# Handle default agent configuration for agent types without specific entries
|
|
171
|
+
default_agent_config = agent_config['agents'].get('default', {})
|
|
172
|
+
|
|
173
|
+
for vector_name, config in vac_services.items():
|
|
174
|
+
agent_type = config['agent']
|
|
175
|
+
if agent_type in agent_config['agents']:
|
|
176
|
+
continue
|
|
177
|
+
log.info(f'Applying default configuration for agent_type: {agent_type} for vector_name: {vector_name}')
|
|
178
|
+
try:
|
|
179
|
+
stem = route_vac(vector_name)
|
|
180
|
+
except ValueError:
|
|
181
|
+
stem = f"${{{agent_type.upper()}_BACKEND_URL}}"
|
|
182
|
+
log.warning(f"Failed to find URL stem for {vector_name}/{agent_type} - using {stem} instead")
|
|
183
|
+
|
|
184
|
+
for method, endpoints in default_agent_config.items():
|
|
185
|
+
if method not in ['get', 'post']:
|
|
186
|
+
continue
|
|
187
|
+
for endpoint_key, endpoint_template in endpoints.items():
|
|
188
|
+
endpoint_path = endpoint_template.replace("{stem}", f"/{agent_type}").replace("{vector_name}", vector_name)
|
|
189
|
+
if endpoint_path not in swagger_template['paths']:
|
|
190
|
+
swagger_template['paths'][endpoint_path] = {}
|
|
191
|
+
swagger_template['paths'][endpoint_path][method] = {
|
|
192
|
+
'summary': f"{method.capitalize()} {agent_type}",
|
|
193
|
+
'operationId': f"{method}_{agent_type}_{endpoint_key}",
|
|
194
|
+
'x-google-backend': {
|
|
195
|
+
'address': endpoint_template.replace("{stem}", stem).replace("{vector_name}", vector_name),
|
|
196
|
+
'protocol': 'h2'
|
|
197
|
+
},
|
|
198
|
+
'responses': copy.deepcopy(default_agent_config.get('response', {}).get(endpoint_key, {
|
|
199
|
+
'200': {
|
|
200
|
+
'description': 'Default - A successful response',
|
|
201
|
+
'schema': {
|
|
202
|
+
'type': 'string'
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}))
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
return yaml.dump(swagger_template, default_flow_style=False)
|
sunholo/auth/run.py
CHANGED
|
@@ -5,14 +5,14 @@ from typing import Dict, Optional
|
|
|
5
5
|
from ..utils.config import load_config_key, load_config
|
|
6
6
|
from ..utils.gcp import is_running_on_cloudrun
|
|
7
7
|
from ..logging import log
|
|
8
|
-
from ..agents.route import
|
|
8
|
+
from ..agents.route import route_vac
|
|
9
9
|
|
|
10
10
|
def get_run_url(vector_name=None):
|
|
11
11
|
|
|
12
12
|
if not vector_name:
|
|
13
13
|
raise ValueError('Vector name was not specified')
|
|
14
14
|
|
|
15
|
-
cloud_urls =
|
|
15
|
+
cloud_urls = route_vac(vector_name)
|
|
16
16
|
|
|
17
17
|
cloud_urls, _ = load_config('config/cloud_run_urls.json')
|
|
18
18
|
agent = load_config_key("agent", vector_name=vector_name, kind="vacConfig")
|
sunholo/cli/chat_vac.py
CHANGED
|
@@ -272,8 +272,9 @@ def vac_command(args):
|
|
|
272
272
|
display_name = load_config_key("display_name", vector_name=args.vac_name, kind="vacConfig")
|
|
273
273
|
description = load_config_key("description", vector_name=args.vac_name, kind="vacConfig")
|
|
274
274
|
endpoints_config = load_config_key(agent_name, "dummy_value", kind="agentConfig")
|
|
275
|
+
post_endpoints = endpoints_config['post']
|
|
275
276
|
|
|
276
|
-
display_endpoints = ' '.join(f"{key}: {value}" for key, value in
|
|
277
|
+
display_endpoints = ' '.join(f"{key}: {value}" for key, value in post_endpoints.items())
|
|
277
278
|
display_endpoints = display_endpoints.replace("{stem}", service_url).replace("{vector_name}", args.vac_name)
|
|
278
279
|
|
|
279
280
|
if agent_name == "langserve":
|
sunholo/cli/cli.py
CHANGED
|
@@ -8,6 +8,7 @@ from .merge_texts import setup_merge_text_subparser
|
|
|
8
8
|
from .run_proxy import setup_proxy_subparser
|
|
9
9
|
from .chat_vac import setup_vac_subparser
|
|
10
10
|
from .embedder import setup_embedder_subparser
|
|
11
|
+
from .swagger import setup_swagger_subparser
|
|
11
12
|
|
|
12
13
|
from ..utils.config import load_config_key
|
|
13
14
|
|
|
@@ -17,7 +18,6 @@ from .sun_rich import console
|
|
|
17
18
|
import sys
|
|
18
19
|
from rich.panel import Panel
|
|
19
20
|
|
|
20
|
-
|
|
21
21
|
def load_default_gcp_config():
|
|
22
22
|
try:
|
|
23
23
|
gcp_config = load_config_key('gcp_config', 'global', kind="vacConfig")
|
|
@@ -82,6 +82,8 @@ def main(args=None):
|
|
|
82
82
|
setup_vac_subparser(subparsers)
|
|
83
83
|
# embed command
|
|
84
84
|
setup_embedder_subparser(subparsers)
|
|
85
|
+
# swagger generation
|
|
86
|
+
setup_swagger_subparser(subparsers)
|
|
85
87
|
|
|
86
88
|
#TODO: add database setup commands: alloydb and supabase
|
|
87
89
|
|
sunholo/cli/swagger.py
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
from ..agents.swagger import generate_swagger
|
|
2
|
+
from ..utils.config import load_all_configs
|
|
3
|
+
from .sun_rich import console
|
|
4
|
+
|
|
5
|
+
def cli_swagger(args):
|
|
6
|
+
|
|
7
|
+
configs = load_all_configs()
|
|
8
|
+
|
|
9
|
+
vac_config = args.vac_config_path or configs.get('vacConfig')
|
|
10
|
+
agent_config = args.agent_config_path or configs.get('agentConfig')
|
|
11
|
+
if not agent_config:
|
|
12
|
+
raise ValueError('Need an agentConfig path')
|
|
13
|
+
|
|
14
|
+
if not vac_config:
|
|
15
|
+
raise ValueError('Need a vacConfig path')
|
|
16
|
+
|
|
17
|
+
swag = generate_swagger(vac_config, agent_config)
|
|
18
|
+
|
|
19
|
+
console.print(swag)
|
|
20
|
+
|
|
21
|
+
return swag
|
|
22
|
+
|
|
23
|
+
def setup_swagger_subparser(subparsers):
|
|
24
|
+
"""
|
|
25
|
+
Sets up an argparse subparser for the 'swagger' command.
|
|
26
|
+
|
|
27
|
+
By default will use the 'vacConfig' configuration within the folder specified by '_CONFIG_FOLDER'
|
|
28
|
+
|
|
29
|
+
Example command:
|
|
30
|
+
```bash
|
|
31
|
+
sunholo swagger --config .
|
|
32
|
+
```
|
|
33
|
+
"""
|
|
34
|
+
deploy_parser = subparsers.add_parser('swagger', help='Create a swagger specification based off a "vacConfig" configuration')
|
|
35
|
+
deploy_parser.add_argument('--vac_config_path', help='Path to the vacConfig file. Set _CONFIG_FOLDER env var and place file in there to change default config location.')
|
|
36
|
+
deploy_parser.add_argument('--agent_config_path', help='Path to agentConfig file. Set _CONFIG_FOLDER env var and place file in there to change default config location.')
|
|
37
|
+
deploy_parser.set_defaults(func=cli_swagger)
|
|
38
|
+
|
sunholo/database/alloydb.py
CHANGED
|
@@ -234,6 +234,10 @@ def create_alloydb_table(vector_name, engine, type = "vectorstore", alloydb_conf
|
|
|
234
234
|
log.info(f"AlloyDB Table '{table_name}' exists in cache, skipping creation.")
|
|
235
235
|
|
|
236
236
|
return table_name
|
|
237
|
+
|
|
238
|
+
alloydb_table_cache[table_name] = True
|
|
239
|
+
return table_name
|
|
240
|
+
|
|
237
241
|
log.info(f"# Creating AlloyDB table {table_name}")
|
|
238
242
|
try:
|
|
239
243
|
engine.init_vectorstore_table(
|
|
@@ -5,8 +5,9 @@ def can_agent_stream(agent_name: str):
|
|
|
5
5
|
|
|
6
6
|
log.debug(f"agent_type: {agent_name} checking streaming...")
|
|
7
7
|
endpoints_config = load_config_key(agent_name, "dummy_value", kind="agentConfig")
|
|
8
|
+
post_endpoints = endpoints_config['post']
|
|
8
9
|
|
|
9
|
-
return 'stream' in
|
|
10
|
+
return 'stream' in post_endpoints
|
|
10
11
|
|
|
11
12
|
|
|
12
13
|
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: sunholo
|
|
3
|
-
Version: 0.64.
|
|
3
|
+
Version: 0.64.8
|
|
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.64.
|
|
6
|
+
Download-URL: https://github.com/sunholo-data/sunholo-py/archive/refs/tags/v0.64.8.tar.gz
|
|
7
7
|
Author: Holosun ApS
|
|
8
8
|
Author-email: multivac@sunholo.com
|
|
9
9
|
License: Apache License, Version 2.0
|
|
@@ -1,22 +1,23 @@
|
|
|
1
1
|
sunholo/__init__.py,sha256=0CdpufyRKWyZe7J7UKigL6j_qOorM-p0OjHIAuf9M38,864
|
|
2
2
|
sunholo/logging.py,sha256=hPmB5VgHV9fN2Ze55jNkRx5QNfxRtezYQkhu_RaE8mc,11667
|
|
3
|
-
sunholo/agents/__init__.py,sha256=
|
|
3
|
+
sunholo/agents/__init__.py,sha256=Hb4NXy2rN-83Z0-UDRwX-LXv2R29lcbSFPf8G6q4fZg,380
|
|
4
4
|
sunholo/agents/chat_history.py,sha256=bkII7PNEbGCaobu2Rnr2rM9dim3BCK0kM-tiWhoI1tw,5219
|
|
5
5
|
sunholo/agents/dispatch_to_qa.py,sha256=7Dl82DL3Wt-MxpLyCi_Udf8OPvxU6-UXbgP-pojoPuY,8339
|
|
6
6
|
sunholo/agents/langserve.py,sha256=FdhQjorAY2bMn2rpuabNT6bU3uqSKWrl8DjpH3L_V7k,4375
|
|
7
7
|
sunholo/agents/pubsub.py,sha256=5hbbhbBGyVWRpt2sAGC5FEheYH1mCCwVUhZEB1S7vGg,1337
|
|
8
|
-
sunholo/agents/route.py,sha256
|
|
8
|
+
sunholo/agents/route.py,sha256=-O6kljLSPdBOsysKyn6hZvXZlNlqNDHGwWl2WwR6Tss,2304
|
|
9
9
|
sunholo/agents/special_commands.py,sha256=ecD5jrBVXo170sdgPILi0m_m_4nRFEv6qKn5zYEvEK8,6494
|
|
10
|
+
sunholo/agents/swagger.py,sha256=WaF7uecKPAqhBBB2mwPvJ87YkFmYLhGCYGWpVsBN53Q,8428
|
|
10
11
|
sunholo/agents/fastapi/__init__.py,sha256=S_pj4_bTUmDGoq_exaREHlOKThi0zTuGT0VZY0YfODQ,88
|
|
11
12
|
sunholo/agents/fastapi/base.py,sha256=clk76cHbUAvU0OYJrRfCWX_5f0ACbhDsIzYBhI3wyoE,2514
|
|
12
13
|
sunholo/agents/fastapi/qna_routes.py,sha256=DgK4Btu5XriOC1JaRQ4G_nWEjJfnQ0J5pyLanF6eF1g,3857
|
|
13
14
|
sunholo/agents/flask/__init__.py,sha256=uqfHNw2Ru3EJ4dJEcbp86h_lkquBQPMxZbjhV_xe3rs,72
|
|
14
15
|
sunholo/agents/flask/base.py,sha256=FgSaCODyoTtlstJtsqlLPScdgRUtv9_plxftdzHdVFo,809
|
|
15
|
-
sunholo/agents/flask/qna_routes.py,sha256=
|
|
16
|
+
sunholo/agents/flask/qna_routes.py,sha256=9wJC_SDbn7A6EzqsbkQicApztAzvvtKvs6cztXhh9Dw,19027
|
|
16
17
|
sunholo/archive/__init__.py,sha256=qNHWm5rGPVOlxZBZCpA1wTYPbalizRT7f8X4rs2t290,31
|
|
17
18
|
sunholo/archive/archive.py,sha256=C-UhG5x-XtZ8VheQp92IYJqgD0V3NFQjniqlit94t18,1197
|
|
18
19
|
sunholo/auth/__init__.py,sha256=4owDjSaWYkbTlPK47UHTOC0gCWbZsqn4ZIEw5NWZTlg,28
|
|
19
|
-
sunholo/auth/run.py,sha256=
|
|
20
|
+
sunholo/auth/run.py,sha256=1ATGHM1ji-08oDINltfTOabYqG3_nQqL4cNpw-3l4L8,2690
|
|
20
21
|
sunholo/bots/__init__.py,sha256=EMFd7e2z68l6pzYOnkzHbLd2xJRvxTKFRNCTuhZ8hIw,130
|
|
21
22
|
sunholo/bots/discord.py,sha256=cCFae5K1BCa6JVkWGLh_iZ9qFO1JpXb6K4eJrlDfEro,2442
|
|
22
23
|
sunholo/bots/github_webhook.py,sha256=5pQPRLM_wxxcILVaIzUDV8Kt7Arcm2dL1r1kMMHA524,9629
|
|
@@ -31,8 +32,8 @@ sunholo/chunker/pdfs.py,sha256=daCZ1xjn1YvxlifIyxskWNpLJLe-Q9D_Jq12MWx3tZo,2473
|
|
|
31
32
|
sunholo/chunker/publish.py,sha256=GNXV6IPdKM2GZUcjGXIERu49D0ITYtizsLIktKVtMjM,2768
|
|
32
33
|
sunholo/chunker/splitter.py,sha256=FLkDhkePkg_zGQpFBK13Cznw575D-Rf9pcaCpc1HUxY,6726
|
|
33
34
|
sunholo/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
34
|
-
sunholo/cli/chat_vac.py,sha256=
|
|
35
|
-
sunholo/cli/cli.py,sha256=
|
|
35
|
+
sunholo/cli/chat_vac.py,sha256=uksCsOrkEvGXIpG_TTy8rUE3qLdxfUQaxR9MpyZQWFs,17872
|
|
36
|
+
sunholo/cli/cli.py,sha256=8e00HBN6eYIUJ8cnvKteBJNn7aZPRMk4b82jwcGg9D4,3741
|
|
36
37
|
sunholo/cli/cli_init.py,sha256=JMZ9AX2cPDZ-_mv3adiv2ToFVNyRPtjk9Biszl1kiR0,2358
|
|
37
38
|
sunholo/cli/configs.py,sha256=QUM9DvKOdZmEQRM5uI3Nh887T0YDiSMr7O240zTLqws,4546
|
|
38
39
|
sunholo/cli/deploy.py,sha256=zxdwUsRTRMC8U5vyRv0JiKBLFn84Ug_Tc88-_h9hJSs,1609
|
|
@@ -40,12 +41,13 @@ sunholo/cli/embedder.py,sha256=w7LT1CANSoQbOz8xAP3Zt4C_hP4lzGJOf8XD2jY5jBQ,7291
|
|
|
40
41
|
sunholo/cli/merge_texts.py,sha256=U9vdMwKmcPoc6iPOWX5MKSxn49dNGbNzVLw8ui5PhEU,1823
|
|
41
42
|
sunholo/cli/run_proxy.py,sha256=8mrZj0GPYO1q5e6cxej-PHdns5pGguWoDrX7RFg0FWo,11581
|
|
42
43
|
sunholo/cli/sun_rich.py,sha256=UpMqeJ0C8i0pkue1AHnnyyX0bFJ9zZeJ7HBR6yhuA8A,54
|
|
44
|
+
sunholo/cli/swagger.py,sha256=Sa4FuWifyoPow_3DrqvfVIbmaZwGnPmLY1XQjOs7M1g,1397
|
|
43
45
|
sunholo/components/__init__.py,sha256=IDoylb74zFKo6NIS3RQqUl0PDFBGVxM1dfUmO7OJ44U,176
|
|
44
46
|
sunholo/components/llm.py,sha256=T4we3tGmqUj4tPwxQr9M6AXv_BALqZV_dRSvINan-oU,10374
|
|
45
47
|
sunholo/components/retriever.py,sha256=jAgcmEM_D2Qfb3hYqHVZMZMLUEUqUbqmhD6G5czmEas,3820
|
|
46
48
|
sunholo/components/vectorstore.py,sha256=lB8vx_N6eBA44orNeVo1WRn0Q8GCIjvPPT9AfiPWBWE,5620
|
|
47
49
|
sunholo/database/__init__.py,sha256=Zz0Shcq-CtStf9rJGIYB_Ybzb8rY_Q9mfSj-nviM490,241
|
|
48
|
-
sunholo/database/alloydb.py,sha256=
|
|
50
|
+
sunholo/database/alloydb.py,sha256=Myk1l97c7cMgZIk3eiJiJzjQW0GLNTlGqbJJwxFIDdQ,17122
|
|
49
51
|
sunholo/database/database.py,sha256=UDHkceiEvJmS3esQX2LYEjEMrHcogN_JHuJXoVWCH3M,7354
|
|
50
52
|
sunholo/database/lancedb.py,sha256=2rAbJVusMrm5TPtVTsUtmwn0z1iZ_wvbKhc6eyT6ClE,708
|
|
51
53
|
sunholo/database/static_dbs.py,sha256=aOyU3AJ-Dzz3qSNjbuN2293cfYw5PhkcQuQxdwPMJ4w,435
|
|
@@ -84,7 +86,7 @@ sunholo/qna/retry.py,sha256=gFgOf9AxrZMIO9OwOYu1EW7rhNhyfnw_o4XAsNLBOVQ,2021
|
|
|
84
86
|
sunholo/streaming/__init__.py,sha256=MpbydI2UYo_adttPQFkxNM33b-QRyNEbrKJx0C2AGPc,241
|
|
85
87
|
sunholo/streaming/content_buffer.py,sha256=fWcg0oTf470M3U40VAChfmHmWRFgRD8VaT90jNfBCH0,6455
|
|
86
88
|
sunholo/streaming/langserve.py,sha256=4AeNt4FPv461s20_5q17Nx83cHjK7Dl3gVOcWAxMgOk,6350
|
|
87
|
-
sunholo/streaming/stream_lookup.py,sha256=
|
|
89
|
+
sunholo/streaming/stream_lookup.py,sha256=uTTUjf96mV7OCc-Sc8N09Fpu5g0T_mD_HbSzivtHMFQ,353
|
|
88
90
|
sunholo/streaming/streaming.py,sha256=9z6pXINEopuL_Z1RnmgXAoZJum9dzyuOxqYtEYnjf8w,16405
|
|
89
91
|
sunholo/summarise/__init__.py,sha256=MZk3dblUMODcPb1crq4v-Z508NrFIpkSWNf9FIO8BcU,38
|
|
90
92
|
sunholo/summarise/summarise.py,sha256=C3HhjepTjUhUC8FLk4jMQIBvq1BcORniwuTFHjPVhVo,3784
|
|
@@ -102,9 +104,9 @@ sunholo/vertex/__init__.py,sha256=JvHcGFuv6R_nAhY2AdoqqhMpJ5ugeWPZ_svGhWrObBk,13
|
|
|
102
104
|
sunholo/vertex/init.py,sha256=JDMUaBRdednzbKF-5p33qqLit2LMsvgvWW-NRz0AqO0,1801
|
|
103
105
|
sunholo/vertex/memory_tools.py,sha256=8F1iTWnqEK9mX4W5RzCVKIjydIcNp6OFxjn_dtQ3GXo,5379
|
|
104
106
|
sunholo/vertex/safety.py,sha256=3meAX0HyGZYrH7rXPUAHxtI_3w_zoy_RX7Shtkoa660,1275
|
|
105
|
-
sunholo-0.64.
|
|
106
|
-
sunholo-0.64.
|
|
107
|
-
sunholo-0.64.
|
|
108
|
-
sunholo-0.64.
|
|
109
|
-
sunholo-0.64.
|
|
110
|
-
sunholo-0.64.
|
|
107
|
+
sunholo-0.64.8.dist-info/LICENSE.txt,sha256=SdE3QjnD3GEmqqg9EX3TM9f7WmtOzqS1KJve8rhbYmU,11345
|
|
108
|
+
sunholo-0.64.8.dist-info/METADATA,sha256=6m6jy17jtXnhV0pL6yb9jx0_6kc6Y1fs7fRX66Ce8W8,5971
|
|
109
|
+
sunholo-0.64.8.dist-info/WHEEL,sha256=cpQTJ5IWu9CdaPViMhC9YzF8gZuS5-vlfoFihTBC86A,91
|
|
110
|
+
sunholo-0.64.8.dist-info/entry_points.txt,sha256=bZuN5AIHingMPt4Ro1b_T-FnQvZ3teBes-3OyO0asl4,49
|
|
111
|
+
sunholo-0.64.8.dist-info/top_level.txt,sha256=wt5tadn5--5JrZsjJz2LceoUvcrIvxjHJe-RxuudxAk,8
|
|
112
|
+
sunholo-0.64.8.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|