sunholo 0.88.0__tar.gz → 0.88.3__tar.gz
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-0.88.0 → sunholo-0.88.3}/PKG-INFO +2 -2
- {sunholo-0.88.0 → sunholo-0.88.3}/setup.py +1 -1
- sunholo-0.88.3/sunholo/cli/cli_init.py +130 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/terraform/tfvars_editor.py +81 -12
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo.egg-info/PKG-INFO +2 -2
- sunholo-0.88.0/sunholo/cli/cli_init.py +0 -60
- {sunholo-0.88.0 → sunholo-0.88.3}/LICENSE.txt +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/MANIFEST.in +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/README.md +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/setup.cfg +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/__init__.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/agents/__init__.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/agents/chat_history.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/agents/dispatch_to_qa.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/agents/fastapi/__init__.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/agents/fastapi/base.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/agents/fastapi/qna_routes.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/agents/flask/__init__.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/agents/flask/base.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/agents/flask/qna_routes.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/agents/flask/vac_routes.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/agents/langserve.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/agents/pubsub.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/agents/route.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/agents/special_commands.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/agents/swagger.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/archive/__init__.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/archive/archive.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/auth/__init__.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/auth/gcloud.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/auth/refresh.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/auth/run.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/azure/__init__.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/azure/auth.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/azure/blobs.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/azure/event_grid.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/bots/__init__.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/bots/discord.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/bots/github_webhook.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/bots/webapp.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/chunker/__init__.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/chunker/azure.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/chunker/doc_handling.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/chunker/encode_metadata.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/chunker/images.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/chunker/loaders.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/chunker/message_data.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/chunker/pdfs.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/chunker/process_chunker_data.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/chunker/publish.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/chunker/pubsub.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/chunker/splitter.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/cli/__init__.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/cli/chat_vac.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/cli/cli.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/cli/configs.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/cli/deploy.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/cli/embedder.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/cli/merge_texts.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/cli/run_proxy.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/cli/sun_rich.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/cli/swagger.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/cli/vertex.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/components/__init__.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/components/llm.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/components/retriever.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/components/vectorstore.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/custom_logging.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/database/__init__.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/database/alloydb.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/database/alloydb_client.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/database/database.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/database/lancedb.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/database/sql/sb/create_function.sql +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/database/sql/sb/create_function_time.sql +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/database/sql/sb/create_table.sql +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/database/sql/sb/delete_source_row.sql +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/database/sql/sb/return_sources.sql +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/database/sql/sb/setup.sql +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/database/static_dbs.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/database/uuid.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/discovery_engine/__init__.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/discovery_engine/chunker_handler.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/discovery_engine/create_new.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/discovery_engine/discovery_engine_client.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/discovery_engine/get_ai_search_chunks.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/embedder/__init__.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/embedder/embed_chunk.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/excel/__init__.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/excel/plugin.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/gcs/__init__.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/gcs/add_file.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/gcs/download_folder.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/gcs/download_url.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/gcs/metadata.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/genai/__init__.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/genai/init.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/genai/process_funcs_cls.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/genai/safety.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/invoke/__init__.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/invoke/async_class.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/invoke/direct_vac_func.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/invoke/invoke_vac_utils.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/langfuse/__init__.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/langfuse/callback.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/langfuse/prompts.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/llamaindex/__init__.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/llamaindex/get_files.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/llamaindex/import_files.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/llamaindex/llamaindex_class.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/llamaindex/user_history.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/lookup/__init__.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/lookup/model_lookup.yaml +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/patches/__init__.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/patches/langchain/__init__.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/patches/langchain/lancedb.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/patches/langchain/vertexai.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/pubsub/__init__.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/pubsub/process_pubsub.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/pubsub/pubsub_manager.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/qna/__init__.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/qna/parsers.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/qna/retry.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/streaming/__init__.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/streaming/content_buffer.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/streaming/langserve.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/streaming/stream_lookup.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/streaming/streaming.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/summarise/__init__.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/summarise/summarise.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/terraform/__init__.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/tools/__init__.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/tools/web_browser.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/utils/__init__.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/utils/api_key.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/utils/big_context.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/utils/config.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/utils/config_class.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/utils/config_schema.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/utils/gcp.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/utils/gcp_project.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/utils/parsers.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/utils/timedelta.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/utils/user_ids.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/utils/version.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/vertex/__init__.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/vertex/extensions_call.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/vertex/extensions_class.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/vertex/genai_functions.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/vertex/init.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/vertex/memory_tools.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/vertex/safety.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/vertex/type_dict_to_json.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo.egg-info/SOURCES.txt +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo.egg-info/dependency_links.txt +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo.egg-info/entry_points.txt +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo.egg-info/requires.txt +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/sunholo.egg-info/top_level.txt +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/tests/test_chat_history.py +0 -0
- {sunholo-0.88.0 → sunholo-0.88.3}/tests/test_config.py +0 -0
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: sunholo
|
|
3
|
-
Version: 0.88.
|
|
3
|
+
Version: 0.88.3
|
|
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.3.tar.gz
|
|
7
7
|
Author: Holosun ApS
|
|
8
8
|
Author-email: multivac@sunholo.com
|
|
9
9
|
License: Apache License, Version 2.0
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import shutil
|
|
3
|
+
from ..utils.config import get_module_filepath
|
|
4
|
+
|
|
5
|
+
def init_project(args):
|
|
6
|
+
"""
|
|
7
|
+
Initializes a new sunholo project with a basic configuration file and directory structure.
|
|
8
|
+
|
|
9
|
+
**Template Files (`templates/project`):**
|
|
10
|
+
|
|
11
|
+
A `templates/project` directory is within the `sunholo` package with the following template files in it:
|
|
12
|
+
|
|
13
|
+
* **`config/llm_config.yaml`:** A basic configuration file with placeholders for LLM settings, vector stores, etc.
|
|
14
|
+
* **`config/cloud_run_urls.json`:** A template for Cloud Run URLs.
|
|
15
|
+
* **`app.py`:** A basic Flask app that can be customized for the project.
|
|
16
|
+
* **`.gitignore`:** A gitignore file to exclude unnecessary files from version control.
|
|
17
|
+
* **`README.md`:** A README file with instructions for setting up and running the project.
|
|
18
|
+
|
|
19
|
+
**Usage:**
|
|
20
|
+
|
|
21
|
+
Users can initialize a new project using the following command:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
sunholo init my_genai_project
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
This will create a new directory named `my_genai_project` with the template files, allowing users to start building their GenAI application.
|
|
28
|
+
"""
|
|
29
|
+
from .sun_rich import console
|
|
30
|
+
|
|
31
|
+
project_name = args.project_name
|
|
32
|
+
current_dir = os.getcwd() # This captures the current directory where the command is run
|
|
33
|
+
project_dir = os.path.join(current_dir, project_name)
|
|
34
|
+
|
|
35
|
+
console.rule(project_name)
|
|
36
|
+
console.print(f"Initializing in directory: {project_dir}")
|
|
37
|
+
|
|
38
|
+
# Create project directory
|
|
39
|
+
if os.path.exists(project_dir):
|
|
40
|
+
console.print(f"[bold red]ERROR: Directory {project_dir} already exists. Please choose a different project name.[/bold red]")
|
|
41
|
+
return
|
|
42
|
+
|
|
43
|
+
os.makedirs(project_dir)
|
|
44
|
+
|
|
45
|
+
# Copy template files
|
|
46
|
+
template_dir = get_module_filepath("templates/project")
|
|
47
|
+
for filename in os.listdir(template_dir):
|
|
48
|
+
src_path = os.path.join(template_dir, filename)
|
|
49
|
+
dest_path = os.path.join(project_dir, filename)
|
|
50
|
+
if os.path.isfile(src_path):
|
|
51
|
+
shutil.copy(src_path, dest_path)
|
|
52
|
+
elif os.path.isdir(src_path):
|
|
53
|
+
shutil.copytree(src_path, dest_path)
|
|
54
|
+
|
|
55
|
+
# Determine the location of the generated.tfvars file
|
|
56
|
+
terraform_dir = args.terraform_dir or os.getenv('MULTIVAC_TERRAFORM_DIR')
|
|
57
|
+
if terraform_dir is None:
|
|
58
|
+
raise ValueError("Must specify a terraform_dir or use the MULTIVAC_TERRAFORM_DIR environment variable")
|
|
59
|
+
|
|
60
|
+
tfvars_file = os.path.join(terraform_dir, 'generated.tfvars')
|
|
61
|
+
|
|
62
|
+
# Get the service account, either from the CLI argument or default
|
|
63
|
+
service_account = args.service_account or "sa-llmops" # Default service account
|
|
64
|
+
|
|
65
|
+
# Determine the relative path for the cloud build included directories
|
|
66
|
+
def get_relative_application_path(full_path: str, base_dir: str) -> str:
|
|
67
|
+
application_base_index = full_path.find("application/")
|
|
68
|
+
if application_base_index != -1:
|
|
69
|
+
return full_path[application_base_index:]
|
|
70
|
+
return os.path.relpath(full_path, base_dir)
|
|
71
|
+
|
|
72
|
+
# Paths to be included in the cloud build (based on the current working directory)
|
|
73
|
+
# We want paths to start from 'application/system_services/{project_name}'
|
|
74
|
+
relative_base = os.path.relpath(current_dir, os.path.join(current_dir, "..", ".."))
|
|
75
|
+
included_path = os.path.join(relative_base, project_name, "**")
|
|
76
|
+
cloud_build_path = os.path.join(relative_base, project_name, "cloudbuild.yaml")
|
|
77
|
+
|
|
78
|
+
# Define the cloud_run configuration for 'discord-server' with the correct project_dir path
|
|
79
|
+
cloud_run_config = {
|
|
80
|
+
project_name: {
|
|
81
|
+
"cpu": "1",
|
|
82
|
+
"memory": "2Gi",
|
|
83
|
+
"max_instance_count": 3,
|
|
84
|
+
"timeout_seconds": 1500,
|
|
85
|
+
"port": 8080,
|
|
86
|
+
"service_account": service_account,
|
|
87
|
+
"invokers": ["allUsers"],
|
|
88
|
+
"cloud_build": {
|
|
89
|
+
"included": [included_path],
|
|
90
|
+
"path": cloud_build_path,
|
|
91
|
+
"substitutions": {},
|
|
92
|
+
"repo_name": "",
|
|
93
|
+
"repo_owner": ""
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
# Initialize the TerraformVarsEditor and update the .tfvars file
|
|
100
|
+
try:
|
|
101
|
+
from ..terraform import TerraformVarsEditor
|
|
102
|
+
editor = TerraformVarsEditor(tfvars_file, terraform_dir)
|
|
103
|
+
editor.update_from_dict(cloud_run_config, 'cloud_run_autogenerated')
|
|
104
|
+
except ImportError as 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
|
+
|
|
122
|
+
def setup_init_subparser(subparsers):
|
|
123
|
+
"""
|
|
124
|
+
Sets up an argparse subparser for the 'init' command.
|
|
125
|
+
"""
|
|
126
|
+
init_parser = subparsers.add_parser('init', help='Initializes a new Multivac project.')
|
|
127
|
+
init_parser.add_argument('project_name', help='The name of the new project.')
|
|
128
|
+
init_parser.add_argument('--terraform-dir', help='The directory where Terraform files will be generated.')
|
|
129
|
+
init_parser.add_argument('--service-account', help='The service account to use for Cloud Run. Defaults to "sa-llmops"')
|
|
130
|
+
init_parser.set_defaults(func=init_project)
|
|
@@ -6,6 +6,7 @@ except ImportError:
|
|
|
6
6
|
import json
|
|
7
7
|
import subprocess
|
|
8
8
|
import os
|
|
9
|
+
import io
|
|
9
10
|
from typing import Dict, Any
|
|
10
11
|
from ..custom_logging import log
|
|
11
12
|
|
|
@@ -57,7 +58,7 @@ class TerraformVarsEditor:
|
|
|
57
58
|
tfvars_file : str
|
|
58
59
|
The path to the .tfvars file to be edited.
|
|
59
60
|
terraform_dir : str
|
|
60
|
-
The directory where Terraform commands will be executed (default is current directory).
|
|
61
|
+
The directory where Terraform commands will be executed (default is current directory). Will use MULTIVAC_TERRAFORM_DIR env var if present.
|
|
61
62
|
|
|
62
63
|
Example:
|
|
63
64
|
-------
|
|
@@ -65,6 +66,12 @@ class TerraformVarsEditor:
|
|
|
65
66
|
"""
|
|
66
67
|
if hcl2 is None:
|
|
67
68
|
raise ImportError('hcl2 is required for parsing terraform files, install via `pip install sunholo[iac]`')
|
|
69
|
+
|
|
70
|
+
# Check for the MULTIVAC_TERRAFORM_DIR environment variable
|
|
71
|
+
if terraform_dir == '.' and 'MULTIVAC_TERRAFORM_DIR' in os.environ:
|
|
72
|
+
terraform_dir = os.environ['MULTIVAC_TERRAFORM_DIR']
|
|
73
|
+
|
|
74
|
+
log.info(f'MULTIVAC_TERRAFORM_DIR environment variable is set to {terraform_dir}')
|
|
68
75
|
|
|
69
76
|
self.tfvars_file = tfvars_file
|
|
70
77
|
self.terraform_dir = terraform_dir
|
|
@@ -144,8 +151,10 @@ class TerraformVarsEditor:
|
|
|
144
151
|
The dictionary containing the instance data.
|
|
145
152
|
|
|
146
153
|
Example:
|
|
147
|
-
|
|
148
|
-
|
|
154
|
+
|
|
155
|
+
```python
|
|
156
|
+
editor.update_or_add_instance('cloud_run', 'new_service', (your dict))
|
|
157
|
+
```
|
|
149
158
|
"""
|
|
150
159
|
if main_key not in self.tfvars_data:
|
|
151
160
|
self.tfvars_data[main_key] = {}
|
|
@@ -154,7 +163,7 @@ class TerraformVarsEditor:
|
|
|
154
163
|
|
|
155
164
|
def validate_terraform(self) -> bool:
|
|
156
165
|
"""
|
|
157
|
-
Runs `terraform validate` in the specified directory.
|
|
166
|
+
Runs `terraform init` followed by `terraform validate` in the specified directory.
|
|
158
167
|
|
|
159
168
|
Returns:
|
|
160
169
|
-------
|
|
@@ -163,18 +172,32 @@ class TerraformVarsEditor:
|
|
|
163
172
|
|
|
164
173
|
Example:
|
|
165
174
|
-------
|
|
175
|
+
```python
|
|
166
176
|
if self.validate_terraform():
|
|
167
177
|
print("Validation passed.")
|
|
178
|
+
```
|
|
168
179
|
"""
|
|
169
|
-
|
|
180
|
+
# Step 1: Run `terraform init` to ensure the directory is initialized
|
|
181
|
+
init_process = subprocess.run(['terraform', 'init'], cwd=self.terraform_dir, capture_output=True, text=True)
|
|
170
182
|
|
|
171
|
-
if
|
|
183
|
+
if init_process.returncode != 0:
|
|
184
|
+
log.error("Terraform initialization failed.")
|
|
185
|
+
print(init_process.stdout)
|
|
186
|
+
print(init_process.stderr)
|
|
187
|
+
return False
|
|
188
|
+
|
|
189
|
+
log.info("Terraform initialized successfully.")
|
|
190
|
+
|
|
191
|
+
# Step 2: Run `terraform validate`
|
|
192
|
+
validate_process = subprocess.run(['terraform', 'validate'], cwd=self.terraform_dir, capture_output=True, text=True)
|
|
193
|
+
|
|
194
|
+
if validate_process.returncode == 0:
|
|
172
195
|
log.info("Terraform validation passed.")
|
|
173
196
|
return True
|
|
174
197
|
else:
|
|
175
198
|
log.error("Terraform validation failed.")
|
|
176
|
-
print(
|
|
177
|
-
print(
|
|
199
|
+
print(validate_process.stdout)
|
|
200
|
+
print(validate_process.stderr)
|
|
178
201
|
return False
|
|
179
202
|
|
|
180
203
|
def update_from_json(self, json_file: str, main_key: str) -> None:
|
|
@@ -214,6 +237,48 @@ class TerraformVarsEditor:
|
|
|
214
237
|
log.info(f"Terraform validation passed, changes saved to {self.tfvars_file}.")
|
|
215
238
|
os.remove(backup_file) # Remove the backup if validation passes
|
|
216
239
|
|
|
240
|
+
def update_from_dict(self, data: Dict[str, Any], main_key: str) -> None:
|
|
241
|
+
"""
|
|
242
|
+
Updates the .tfvars file based on the content of a Python dictionary and validates the changes.
|
|
243
|
+
|
|
244
|
+
Parameters:
|
|
245
|
+
----------
|
|
246
|
+
data : dict
|
|
247
|
+
The dictionary with the new instance data.
|
|
248
|
+
main_key : str
|
|
249
|
+
The top-level key under which the instance is added (e.g., "cloud_run").
|
|
250
|
+
|
|
251
|
+
Example:
|
|
252
|
+
-------
|
|
253
|
+
editor.update_from_dict(data, 'cloud_run')
|
|
254
|
+
"""
|
|
255
|
+
# Create an in-memory file-like object from the dictionary by converting it to JSON
|
|
256
|
+
json_data = json.dumps({main_key: data})
|
|
257
|
+
json_file = io.StringIO(json_data)
|
|
258
|
+
|
|
259
|
+
# Load the JSON data from the StringIO object
|
|
260
|
+
parsed_data = json.load(json_file)
|
|
261
|
+
|
|
262
|
+
# Update the tfvars data in memory
|
|
263
|
+
for instance_name, instance_data in parsed_data.get(main_key, {}).items():
|
|
264
|
+
self.update_or_add_instance(main_key, instance_name, instance_data)
|
|
265
|
+
|
|
266
|
+
# Now that the data is updated in memory, proceed to validate and write it back to the file
|
|
267
|
+
# Backup the original .tfvars file
|
|
268
|
+
backup_file = self._backup_tfvars()
|
|
269
|
+
|
|
270
|
+
# Temporarily save the updated data to the original file location
|
|
271
|
+
self._save_tfvars()
|
|
272
|
+
|
|
273
|
+
# Attempt to validate the changes with Terraform
|
|
274
|
+
if not self.validate_terraform():
|
|
275
|
+
# If validation fails, restore the original file from the backup
|
|
276
|
+
self._restore_tfvars(backup_file)
|
|
277
|
+
console.print(f"Changes aborted, original {self.tfvars_file} restored.")
|
|
278
|
+
else:
|
|
279
|
+
console.print(f"Terraform validation passed, changes saved to {self.tfvars_file}.")
|
|
280
|
+
os.remove(backup_file) # Remove the backup if validation passes
|
|
281
|
+
|
|
217
282
|
def tfvars_command(args):
|
|
218
283
|
"""
|
|
219
284
|
Executes the tfvars command based on parsed arguments.
|
|
@@ -225,11 +290,15 @@ def tfvars_command(args):
|
|
|
225
290
|
if console is None:
|
|
226
291
|
raise ImportError("Need cli tools to use `sunholo tfvars` - install via `pip install sunholo[cli]`")
|
|
227
292
|
|
|
228
|
-
#
|
|
293
|
+
# Load JSON data from the specified file
|
|
229
294
|
try:
|
|
230
|
-
|
|
295
|
+
with open(args.json_file, 'r') as f:
|
|
296
|
+
instance_data = json.load(f)
|
|
297
|
+
except FileNotFoundError:
|
|
298
|
+
console.print(f"Error: The JSON file '{args.json_file}' was not found.")
|
|
299
|
+
return
|
|
231
300
|
except json.JSONDecodeError as e:
|
|
232
|
-
console.print(f"
|
|
301
|
+
console.print(f"Error parsing JSON data: {e}")
|
|
233
302
|
return
|
|
234
303
|
|
|
235
304
|
# Create an instance of TerraformVarsEditor
|
|
@@ -260,7 +329,7 @@ def setup_tfvarseditor_subparser(subparsers):
|
|
|
260
329
|
add_parser.add_argument('tfvars_file', help='Path to the .tfvars file')
|
|
261
330
|
add_parser.add_argument('main_key', help='The main key under which the instance is added (e.g., "cloud_run")')
|
|
262
331
|
add_parser.add_argument('instance_name', help='The name of the instance to add or update')
|
|
263
|
-
add_parser.add_argument('
|
|
332
|
+
add_parser.add_argument('--json-file', help='Path to a JSON file with the instance data', required=True)
|
|
264
333
|
add_parser.add_argument('--terraform-dir', default='.', help='The directory where Terraform is initialized')
|
|
265
334
|
|
|
266
335
|
tfvars_parser.set_defaults(func=tfvars_command)
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: sunholo
|
|
3
|
-
Version: 0.88.
|
|
3
|
+
Version: 0.88.3
|
|
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.3.tar.gz
|
|
7
7
|
Author: Holosun ApS
|
|
8
8
|
Author-email: multivac@sunholo.com
|
|
9
9
|
License: Apache License, Version 2.0
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
import os
|
|
2
|
-
import shutil
|
|
3
|
-
from ..utils.config import get_module_filepath
|
|
4
|
-
|
|
5
|
-
def init_project(args):
|
|
6
|
-
"""
|
|
7
|
-
Initializes a new sunholo project with a basic configuration file and directory structure.
|
|
8
|
-
|
|
9
|
-
**Template Files (`templates/project`):**
|
|
10
|
-
|
|
11
|
-
A `templates/project` directory is within the `sunholo` package with the following template files in it:
|
|
12
|
-
|
|
13
|
-
* **`config/llm_config.yaml`:** A basic configuration file with placeholders for LLM settings, vector stores, etc.
|
|
14
|
-
* **`config/cloud_run_urls.json`:** A template for Cloud Run URLs.
|
|
15
|
-
* **`app.py`:** A basic Flask app that can be customized for the project.
|
|
16
|
-
* **`.gitignore`:** A gitignore file to exclude unnecessary files from version control.
|
|
17
|
-
* **`README.md`:** A README file with instructions for setting up and running the project.
|
|
18
|
-
|
|
19
|
-
**Usage:**
|
|
20
|
-
|
|
21
|
-
Users can initialize a new project using the following command:
|
|
22
|
-
|
|
23
|
-
```bash
|
|
24
|
-
sunholo init my_genai_project
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
This will create a new directory named `my_genai_project` with the template files, allowing users to start building their GenAI application.
|
|
28
|
-
"""
|
|
29
|
-
project_name = args.project_name
|
|
30
|
-
project_dir = os.path.join(os.getcwd(), project_name)
|
|
31
|
-
|
|
32
|
-
print(f"Initializing project: {project_name} in directory: {project_dir}")
|
|
33
|
-
|
|
34
|
-
# Create project directory
|
|
35
|
-
if os.path.exists(project_dir):
|
|
36
|
-
print(f"Directory {project_dir} already exists. Please choose a different project name.")
|
|
37
|
-
return
|
|
38
|
-
|
|
39
|
-
os.makedirs(project_dir)
|
|
40
|
-
|
|
41
|
-
# Copy template files
|
|
42
|
-
template_dir = get_module_filepath("templates/project")
|
|
43
|
-
for filename in os.listdir(template_dir):
|
|
44
|
-
src_path = os.path.join(template_dir, filename)
|
|
45
|
-
dest_path = os.path.join(project_dir, filename)
|
|
46
|
-
if os.path.isfile(src_path):
|
|
47
|
-
shutil.copy(src_path, dest_path)
|
|
48
|
-
elif os.path.isdir(src_path):
|
|
49
|
-
shutil.copytree(src_path, dest_path)
|
|
50
|
-
|
|
51
|
-
print(f"Project {project_name} initialized successfully.")
|
|
52
|
-
print(f"Navigate to {project_dir} and customize the configuration files in the 'config' directory.")
|
|
53
|
-
|
|
54
|
-
def setup_init_subparser(subparsers):
|
|
55
|
-
"""
|
|
56
|
-
Sets up an argparse subparser for the 'init' command.
|
|
57
|
-
"""
|
|
58
|
-
init_parser = subparsers.add_parser('init', help='Initializes a new Multivac project.')
|
|
59
|
-
init_parser.add_argument('project_name', help='The name of the new project.')
|
|
60
|
-
init_parser.set_defaults(func=init_project)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|