sunholo 0.88.2__py3-none-any.whl → 0.88.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.
- sunholo/cli/cli_init.py +114 -15
- sunholo/utils/parsers.py +34 -0
- {sunholo-0.88.2.dist-info → sunholo-0.88.4.dist-info}/METADATA +2 -2
- {sunholo-0.88.2.dist-info → sunholo-0.88.4.dist-info}/RECORD +8 -8
- {sunholo-0.88.2.dist-info → sunholo-0.88.4.dist-info}/LICENSE.txt +0 -0
- {sunholo-0.88.2.dist-info → sunholo-0.88.4.dist-info}/WHEEL +0 -0
- {sunholo-0.88.2.dist-info → sunholo-0.88.4.dist-info}/entry_points.txt +0 -0
- {sunholo-0.88.2.dist-info → sunholo-0.88.4.dist-info}/top_level.txt +0 -0
sunholo/cli/cli_init.py
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import os
|
|
2
|
+
import yaml
|
|
2
3
|
import shutil
|
|
3
4
|
from ..utils.config import get_module_filepath
|
|
5
|
+
from ..utils.parsers import sanitize_cloudrun_name
|
|
4
6
|
|
|
5
7
|
def init_project(args):
|
|
6
8
|
"""
|
|
@@ -26,15 +28,18 @@ sunholo init my_genai_project
|
|
|
26
28
|
|
|
27
29
|
This will create a new directory named `my_genai_project` with the template files, allowing users to start building their GenAI application.
|
|
28
30
|
"""
|
|
29
|
-
|
|
31
|
+
from .sun_rich import console
|
|
32
|
+
|
|
33
|
+
project_name = sanitize_cloudrun_name(args.project_name)
|
|
30
34
|
current_dir = os.getcwd() # This captures the current directory where the command is run
|
|
31
35
|
project_dir = os.path.join(current_dir, project_name)
|
|
32
36
|
|
|
33
|
-
|
|
37
|
+
console.rule(project_name)
|
|
38
|
+
console.print(f"Initializing in directory: {project_dir}")
|
|
34
39
|
|
|
35
40
|
# Create project directory
|
|
36
41
|
if os.path.exists(project_dir):
|
|
37
|
-
print(f"Directory {project_dir} already exists. Please choose a different project name.")
|
|
42
|
+
console.print(f"[bold red]ERROR: Directory {project_dir} already exists. Please choose a different project name.[/bold red]")
|
|
38
43
|
return
|
|
39
44
|
|
|
40
45
|
os.makedirs(project_dir)
|
|
@@ -48,6 +53,8 @@ This will create a new directory named `my_genai_project` with the template file
|
|
|
48
53
|
shutil.copy(src_path, dest_path)
|
|
49
54
|
elif os.path.isdir(src_path):
|
|
50
55
|
shutil.copytree(src_path, dest_path)
|
|
56
|
+
|
|
57
|
+
|
|
51
58
|
|
|
52
59
|
# Determine the location of the generated.tfvars file
|
|
53
60
|
terraform_dir = args.terraform_dir or os.getenv('MULTIVAC_TERRAFORM_DIR')
|
|
@@ -59,19 +66,15 @@ This will create a new directory named `my_genai_project` with the template file
|
|
|
59
66
|
# Get the service account, either from the CLI argument or default
|
|
60
67
|
service_account = args.service_account or "sa-llmops" # Default service account
|
|
61
68
|
|
|
62
|
-
# Determine the relative path for the cloud build included directories
|
|
63
|
-
def get_relative_application_path(full_path: str, base_dir: str) -> str:
|
|
64
|
-
application_base_index = full_path.find("application/")
|
|
65
|
-
if application_base_index != -1:
|
|
66
|
-
return full_path[application_base_index:]
|
|
67
|
-
return os.path.relpath(full_path, base_dir)
|
|
68
|
-
|
|
69
69
|
# Paths to be included in the cloud build (based on the current working directory)
|
|
70
70
|
# We want paths to start from 'application/system_services/{project_name}'
|
|
71
71
|
relative_base = os.path.relpath(current_dir, os.path.join(current_dir, "..", ".."))
|
|
72
72
|
included_path = os.path.join(relative_base, project_name, "**")
|
|
73
73
|
cloud_build_path = os.path.join(relative_base, project_name, "cloudbuild.yaml")
|
|
74
74
|
|
|
75
|
+
update_cloudbuild_template(project_dir, project_name, os.path.join(relative_base, project_name))
|
|
76
|
+
write_vac_config(project_dir, project_name)
|
|
77
|
+
|
|
75
78
|
# Define the cloud_run configuration for 'discord-server' with the correct project_dir path
|
|
76
79
|
cloud_run_config = {
|
|
77
80
|
project_name: {
|
|
@@ -97,13 +100,109 @@ This will create a new directory named `my_genai_project` with the template file
|
|
|
97
100
|
try:
|
|
98
101
|
from ..terraform import TerraformVarsEditor
|
|
99
102
|
editor = TerraformVarsEditor(tfvars_file, terraform_dir)
|
|
100
|
-
editor.update_from_dict(cloud_run_config, '
|
|
101
|
-
print(f"{tfvars_file} file initialized and updated successfully.")
|
|
103
|
+
editor.update_from_dict(cloud_run_config, 'cloud_run_autogenerated')
|
|
102
104
|
except ImportError as e:
|
|
103
|
-
print(f"Error initializing TerraformVarsEditor: {e}")
|
|
105
|
+
console.print(f"Error initializing TerraformVarsEditor: {e}")
|
|
106
|
+
|
|
107
|
+
from rich.panel import Panel
|
|
108
|
+
|
|
109
|
+
console.print(
|
|
110
|
+
Panel((
|
|
111
|
+
"Next steps: \n"
|
|
112
|
+
f" - Navigate to [orange]{project_dir}/config[/orange] and customize VAC configuration files.\n"
|
|
113
|
+
f" - Add your own GenAI app logic to [orange]{project_dir}/vac_service.py[/orange]\n"
|
|
114
|
+
f" - Check terraform [orange]{terraform_dir}/generated.tfvars[/orange] for Multivac deployment"
|
|
115
|
+
),
|
|
116
|
+
title=f"Project [bold orange]{project_name}[/bold orange] initialized successfully.",
|
|
117
|
+
subtitle=project_dir),
|
|
118
|
+
)
|
|
119
|
+
console.rule()
|
|
120
|
+
|
|
121
|
+
def update_cloudbuild_template(project_dir: str, service_name: str, build_folder: str):
|
|
122
|
+
"""
|
|
123
|
+
Updates the cloudbuild.yaml template file by replacing the `CHANGE_ME` placeholders with actual values.
|
|
124
|
+
|
|
125
|
+
Args:
|
|
126
|
+
-----
|
|
127
|
+
project_dir : str
|
|
128
|
+
The directory where the project and cloudbuild.yaml are located.
|
|
129
|
+
service_name : str
|
|
130
|
+
The name of the service to be used in Cloud Run.
|
|
131
|
+
build_folder : str
|
|
132
|
+
The build folder where the Docker build will take place.
|
|
133
|
+
|
|
134
|
+
Example:
|
|
135
|
+
-------
|
|
136
|
+
update_cloudbuild_template('/path/to/project', 'my_service', 'src')
|
|
137
|
+
"""
|
|
138
|
+
cloudbuild_path = os.path.join(project_dir, "cloudbuild.yaml")
|
|
139
|
+
|
|
140
|
+
# Define the substitutions to replace CHANGE_ME
|
|
141
|
+
substitutions = {
|
|
142
|
+
"_SERVICE_NAME": service_name,
|
|
143
|
+
"_BUILD_FOLDER": build_folder,
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
# Read the cloudbuild.yaml template
|
|
147
|
+
with open(cloudbuild_path, 'r') as file:
|
|
148
|
+
content = file.read()
|
|
149
|
+
|
|
150
|
+
# Replace each placeholder with its corresponding value
|
|
151
|
+
for placeholder, value in substitutions.items():
|
|
152
|
+
content = content.replace(f"{placeholder}: CHANGE_ME", f"{placeholder}: {value}")
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
# Write the updated content back to cloudbuild.yaml
|
|
156
|
+
with open(cloudbuild_path, 'w') as file:
|
|
157
|
+
file.write(content)
|
|
158
|
+
|
|
159
|
+
print(f"cloudbuild.yaml updated successfully with service name '{service_name}' and build folder '{build_folder}'.")
|
|
160
|
+
|
|
161
|
+
def write_vac_config(project_dir: str, service_name: str):
|
|
162
|
+
"""
|
|
163
|
+
Writes the vac_config.yaml file with the provided service name as the key.
|
|
164
|
+
"""
|
|
165
|
+
vac_config_content = {
|
|
166
|
+
'kind': 'vacConfig',
|
|
167
|
+
'apiVersion': 'v1',
|
|
168
|
+
'vac': {
|
|
169
|
+
service_name: { # Use the service name here
|
|
170
|
+
'llm': 'vertex',
|
|
171
|
+
'model': 'gemini-1.5-pro-preview-0514',
|
|
172
|
+
'agent': 'vertex-genai',
|
|
173
|
+
'display_name': 'Template VAC',
|
|
174
|
+
'memory': [
|
|
175
|
+
{
|
|
176
|
+
'llamaindex-native': {
|
|
177
|
+
'vectorstore': 'llamaindex'
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
],
|
|
181
|
+
'gcp_config': {
|
|
182
|
+
'project_id': 'llamaindex_project',
|
|
183
|
+
'location': 'europe-west1',
|
|
184
|
+
'rag_id': '1234544343434' # Replace with actual RAG ID
|
|
185
|
+
},
|
|
186
|
+
'chunker': {
|
|
187
|
+
'chunk_size': 1000,
|
|
188
|
+
'overlap': 200
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
config_dir = os.path.join(project_dir, 'config')
|
|
195
|
+
if not os.path.exists(config_dir):
|
|
196
|
+
os.makedirs(config_dir)
|
|
197
|
+
|
|
198
|
+
vac_config_path = os.path.join(config_dir, 'vac_config.yaml')
|
|
199
|
+
|
|
200
|
+
# Write the YAML configuration to the file
|
|
201
|
+
with open(vac_config_path, 'w') as file:
|
|
202
|
+
yaml.dump(vac_config_content, file, default_flow_style=False)
|
|
203
|
+
|
|
204
|
+
print(f"vac_config.yaml written successfully with service name '{service_name}'.")
|
|
104
205
|
|
|
105
|
-
print(f"Project {project_name} initialized successfully.")
|
|
106
|
-
print(f"Navigate to {project_dir} and customize the configuration files in the 'config' directory.")
|
|
107
206
|
|
|
108
207
|
def setup_init_subparser(subparsers):
|
|
109
208
|
"""
|
sunholo/utils/parsers.py
CHANGED
|
@@ -15,6 +15,40 @@ import re
|
|
|
15
15
|
import hashlib
|
|
16
16
|
import urllib.parse
|
|
17
17
|
|
|
18
|
+
def sanitize_cloudrun_name(name: str) -> str:
|
|
19
|
+
"""
|
|
20
|
+
Sanitizes the project name to be a valid Cloud Run service name.
|
|
21
|
+
|
|
22
|
+
- Converts to lowercase.
|
|
23
|
+
- Replaces invalid characters with hyphens.
|
|
24
|
+
- Ensures the name starts with a letter.
|
|
25
|
+
- Trims the name to be less than 64 characters.
|
|
26
|
+
- Removes trailing hyphens.
|
|
27
|
+
|
|
28
|
+
Args:
|
|
29
|
+
name (str): The original project name.
|
|
30
|
+
|
|
31
|
+
Returns:
|
|
32
|
+
str: The sanitized project name.
|
|
33
|
+
"""
|
|
34
|
+
# Convert to lowercase
|
|
35
|
+
name = name.lower()
|
|
36
|
+
|
|
37
|
+
# Replace invalid characters with hyphens
|
|
38
|
+
name = re.sub(r'[^a-z0-9-]', '-', name)
|
|
39
|
+
|
|
40
|
+
# Ensure the name starts with a letter
|
|
41
|
+
if not name[0].isalpha():
|
|
42
|
+
name = 'a' + name
|
|
43
|
+
|
|
44
|
+
# Trim to 63 characters to leave room for suffixes if needed
|
|
45
|
+
name = name[:63]
|
|
46
|
+
|
|
47
|
+
# Remove trailing hyphens
|
|
48
|
+
name = name.rstrip('-')
|
|
49
|
+
|
|
50
|
+
return name
|
|
51
|
+
|
|
18
52
|
def validate_extension_id(ext_id):
|
|
19
53
|
"""
|
|
20
54
|
Ensures the passed string fits the criteria for an extension ID.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: sunholo
|
|
3
|
-
Version: 0.88.
|
|
3
|
+
Version: 0.88.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.88.
|
|
6
|
+
Download-URL: https://github.com/sunholo-data/sunholo-py/archive/refs/tags/v0.88.4.tar.gz
|
|
7
7
|
Author: Holosun ApS
|
|
8
8
|
Author-email: multivac@sunholo.com
|
|
9
9
|
License: Apache License, Version 2.0
|
|
@@ -44,7 +44,7 @@ sunholo/chunker/splitter.py,sha256=QLAEsJOpEYFZr9-UGZUuAlNVyjfCWb8jvzCHg0rVShE,6
|
|
|
44
44
|
sunholo/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
45
45
|
sunholo/cli/chat_vac.py,sha256=jTmCt62U4uqJjeGp_XfIbxnafAAOhQAJMi8TxSkeKlM,23164
|
|
46
46
|
sunholo/cli/cli.py,sha256=q-ATmnWnc_PPo2q31xhqpp-m3GtOSBoqh0gvMeSo4XU,4374
|
|
47
|
-
sunholo/cli/cli_init.py,sha256=
|
|
47
|
+
sunholo/cli/cli_init.py,sha256=31DdDecaYoREkoa5itjAElSJu_gmod5V4Z3h4ohKqU8,8296
|
|
48
48
|
sunholo/cli/configs.py,sha256=QUM9DvKOdZmEQRM5uI3Nh887T0YDiSMr7O240zTLqws,4546
|
|
49
49
|
sunholo/cli/deploy.py,sha256=zxdwUsRTRMC8U5vyRv0JiKBLFn84Ug_Tc88-_h9hJSs,1609
|
|
50
50
|
sunholo/cli/embedder.py,sha256=v-FKiSPHaQzB6ctClclYueIf3bf3CqYtC1oRgPfT4dY,5566
|
|
@@ -131,7 +131,7 @@ sunholo/utils/config_class.py,sha256=4uY7i7y18bDLvGNY1PiQ8c4LM-whopsjEWZerHEckwQ
|
|
|
131
131
|
sunholo/utils/config_schema.py,sha256=Wv-ncitzljOhgbDaq9qnFqH5LCuxNv59dTGDWgd1qdk,4189
|
|
132
132
|
sunholo/utils/gcp.py,sha256=uueODEpA-P6O15-t0hmcGC9dONLO_hLfzSsSoQnkUss,4854
|
|
133
133
|
sunholo/utils/gcp_project.py,sha256=Fa0IhCX12bZ1ctF_PKN8PNYd7hihEUfb90kilBfUDjg,1411
|
|
134
|
-
sunholo/utils/parsers.py,sha256=
|
|
134
|
+
sunholo/utils/parsers.py,sha256=LxzkCTBQ4uYhf0FfqiO4yWeP_yqVaMz_fw7sMu7mq5E,6421
|
|
135
135
|
sunholo/utils/timedelta.py,sha256=BbLabEx7_rbErj_YbNM0MBcaFN76DC4PTe4zD2ucezg,493
|
|
136
136
|
sunholo/utils/user_ids.py,sha256=SQd5_H7FE7vcTZp9AQuQDWBXd4FEEd7TeVMQe1H4Ny8,292
|
|
137
137
|
sunholo/utils/version.py,sha256=P1QAJQdZfT2cMqdTSmXmcxrD2PssMPEGM-WI6083Fck,237
|
|
@@ -143,9 +143,9 @@ sunholo/vertex/init.py,sha256=1OQwcPBKZYBTDPdyU7IM4X4OmiXLdsNV30C-fee2scQ,2875
|
|
|
143
143
|
sunholo/vertex/memory_tools.py,sha256=q_phxgGX2TG2j2MXNULF2xGzQnQPENwjPN9nZ_A9Gh0,7526
|
|
144
144
|
sunholo/vertex/safety.py,sha256=S9PgQT1O_BQAkcqauWncRJaydiP8Q_Jzmu9gxYfy1VA,2482
|
|
145
145
|
sunholo/vertex/type_dict_to_json.py,sha256=uTzL4o9tJRao4u-gJOFcACgWGkBOtqACmb6ihvCErL8,4694
|
|
146
|
-
sunholo-0.88.
|
|
147
|
-
sunholo-0.88.
|
|
148
|
-
sunholo-0.88.
|
|
149
|
-
sunholo-0.88.
|
|
150
|
-
sunholo-0.88.
|
|
151
|
-
sunholo-0.88.
|
|
146
|
+
sunholo-0.88.4.dist-info/LICENSE.txt,sha256=SdE3QjnD3GEmqqg9EX3TM9f7WmtOzqS1KJve8rhbYmU,11345
|
|
147
|
+
sunholo-0.88.4.dist-info/METADATA,sha256=Uur6zt3dM6bwdo4jirZRZ1sTvlFzhurLhJpg2H-NdU8,7706
|
|
148
|
+
sunholo-0.88.4.dist-info/WHEEL,sha256=UvcQYKBHoFqaQd6LKyqHw9fxEolWLQnlzP0h_LgJAfI,91
|
|
149
|
+
sunholo-0.88.4.dist-info/entry_points.txt,sha256=bZuN5AIHingMPt4Ro1b_T-FnQvZ3teBes-3OyO0asl4,49
|
|
150
|
+
sunholo-0.88.4.dist-info/top_level.txt,sha256=wt5tadn5--5JrZsjJz2LceoUvcrIvxjHJe-RxuudxAk,8
|
|
151
|
+
sunholo-0.88.4.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|