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.
Files changed (160) hide show
  1. {sunholo-0.88.0 → sunholo-0.88.3}/PKG-INFO +2 -2
  2. {sunholo-0.88.0 → sunholo-0.88.3}/setup.py +1 -1
  3. sunholo-0.88.3/sunholo/cli/cli_init.py +130 -0
  4. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/terraform/tfvars_editor.py +81 -12
  5. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo.egg-info/PKG-INFO +2 -2
  6. sunholo-0.88.0/sunholo/cli/cli_init.py +0 -60
  7. {sunholo-0.88.0 → sunholo-0.88.3}/LICENSE.txt +0 -0
  8. {sunholo-0.88.0 → sunholo-0.88.3}/MANIFEST.in +0 -0
  9. {sunholo-0.88.0 → sunholo-0.88.3}/README.md +0 -0
  10. {sunholo-0.88.0 → sunholo-0.88.3}/setup.cfg +0 -0
  11. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/__init__.py +0 -0
  12. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/agents/__init__.py +0 -0
  13. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/agents/chat_history.py +0 -0
  14. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/agents/dispatch_to_qa.py +0 -0
  15. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/agents/fastapi/__init__.py +0 -0
  16. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/agents/fastapi/base.py +0 -0
  17. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/agents/fastapi/qna_routes.py +0 -0
  18. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/agents/flask/__init__.py +0 -0
  19. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/agents/flask/base.py +0 -0
  20. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/agents/flask/qna_routes.py +0 -0
  21. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/agents/flask/vac_routes.py +0 -0
  22. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/agents/langserve.py +0 -0
  23. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/agents/pubsub.py +0 -0
  24. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/agents/route.py +0 -0
  25. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/agents/special_commands.py +0 -0
  26. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/agents/swagger.py +0 -0
  27. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/archive/__init__.py +0 -0
  28. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/archive/archive.py +0 -0
  29. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/auth/__init__.py +0 -0
  30. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/auth/gcloud.py +0 -0
  31. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/auth/refresh.py +0 -0
  32. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/auth/run.py +0 -0
  33. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/azure/__init__.py +0 -0
  34. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/azure/auth.py +0 -0
  35. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/azure/blobs.py +0 -0
  36. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/azure/event_grid.py +0 -0
  37. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/bots/__init__.py +0 -0
  38. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/bots/discord.py +0 -0
  39. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/bots/github_webhook.py +0 -0
  40. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/bots/webapp.py +0 -0
  41. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/chunker/__init__.py +0 -0
  42. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/chunker/azure.py +0 -0
  43. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/chunker/doc_handling.py +0 -0
  44. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/chunker/encode_metadata.py +0 -0
  45. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/chunker/images.py +0 -0
  46. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/chunker/loaders.py +0 -0
  47. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/chunker/message_data.py +0 -0
  48. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/chunker/pdfs.py +0 -0
  49. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/chunker/process_chunker_data.py +0 -0
  50. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/chunker/publish.py +0 -0
  51. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/chunker/pubsub.py +0 -0
  52. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/chunker/splitter.py +0 -0
  53. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/cli/__init__.py +0 -0
  54. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/cli/chat_vac.py +0 -0
  55. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/cli/cli.py +0 -0
  56. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/cli/configs.py +0 -0
  57. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/cli/deploy.py +0 -0
  58. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/cli/embedder.py +0 -0
  59. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/cli/merge_texts.py +0 -0
  60. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/cli/run_proxy.py +0 -0
  61. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/cli/sun_rich.py +0 -0
  62. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/cli/swagger.py +0 -0
  63. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/cli/vertex.py +0 -0
  64. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/components/__init__.py +0 -0
  65. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/components/llm.py +0 -0
  66. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/components/retriever.py +0 -0
  67. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/components/vectorstore.py +0 -0
  68. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/custom_logging.py +0 -0
  69. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/database/__init__.py +0 -0
  70. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/database/alloydb.py +0 -0
  71. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/database/alloydb_client.py +0 -0
  72. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/database/database.py +0 -0
  73. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/database/lancedb.py +0 -0
  74. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/database/sql/sb/create_function.sql +0 -0
  75. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/database/sql/sb/create_function_time.sql +0 -0
  76. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/database/sql/sb/create_table.sql +0 -0
  77. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/database/sql/sb/delete_source_row.sql +0 -0
  78. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/database/sql/sb/return_sources.sql +0 -0
  79. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/database/sql/sb/setup.sql +0 -0
  80. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/database/static_dbs.py +0 -0
  81. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/database/uuid.py +0 -0
  82. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/discovery_engine/__init__.py +0 -0
  83. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/discovery_engine/chunker_handler.py +0 -0
  84. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/discovery_engine/create_new.py +0 -0
  85. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/discovery_engine/discovery_engine_client.py +0 -0
  86. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/discovery_engine/get_ai_search_chunks.py +0 -0
  87. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/embedder/__init__.py +0 -0
  88. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/embedder/embed_chunk.py +0 -0
  89. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/excel/__init__.py +0 -0
  90. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/excel/plugin.py +0 -0
  91. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/gcs/__init__.py +0 -0
  92. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/gcs/add_file.py +0 -0
  93. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/gcs/download_folder.py +0 -0
  94. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/gcs/download_url.py +0 -0
  95. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/gcs/metadata.py +0 -0
  96. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/genai/__init__.py +0 -0
  97. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/genai/init.py +0 -0
  98. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/genai/process_funcs_cls.py +0 -0
  99. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/genai/safety.py +0 -0
  100. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/invoke/__init__.py +0 -0
  101. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/invoke/async_class.py +0 -0
  102. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/invoke/direct_vac_func.py +0 -0
  103. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/invoke/invoke_vac_utils.py +0 -0
  104. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/langfuse/__init__.py +0 -0
  105. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/langfuse/callback.py +0 -0
  106. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/langfuse/prompts.py +0 -0
  107. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/llamaindex/__init__.py +0 -0
  108. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/llamaindex/get_files.py +0 -0
  109. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/llamaindex/import_files.py +0 -0
  110. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/llamaindex/llamaindex_class.py +0 -0
  111. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/llamaindex/user_history.py +0 -0
  112. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/lookup/__init__.py +0 -0
  113. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/lookup/model_lookup.yaml +0 -0
  114. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/patches/__init__.py +0 -0
  115. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/patches/langchain/__init__.py +0 -0
  116. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/patches/langchain/lancedb.py +0 -0
  117. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/patches/langchain/vertexai.py +0 -0
  118. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/pubsub/__init__.py +0 -0
  119. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/pubsub/process_pubsub.py +0 -0
  120. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/pubsub/pubsub_manager.py +0 -0
  121. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/qna/__init__.py +0 -0
  122. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/qna/parsers.py +0 -0
  123. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/qna/retry.py +0 -0
  124. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/streaming/__init__.py +0 -0
  125. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/streaming/content_buffer.py +0 -0
  126. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/streaming/langserve.py +0 -0
  127. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/streaming/stream_lookup.py +0 -0
  128. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/streaming/streaming.py +0 -0
  129. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/summarise/__init__.py +0 -0
  130. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/summarise/summarise.py +0 -0
  131. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/terraform/__init__.py +0 -0
  132. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/tools/__init__.py +0 -0
  133. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/tools/web_browser.py +0 -0
  134. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/utils/__init__.py +0 -0
  135. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/utils/api_key.py +0 -0
  136. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/utils/big_context.py +0 -0
  137. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/utils/config.py +0 -0
  138. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/utils/config_class.py +0 -0
  139. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/utils/config_schema.py +0 -0
  140. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/utils/gcp.py +0 -0
  141. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/utils/gcp_project.py +0 -0
  142. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/utils/parsers.py +0 -0
  143. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/utils/timedelta.py +0 -0
  144. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/utils/user_ids.py +0 -0
  145. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/utils/version.py +0 -0
  146. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/vertex/__init__.py +0 -0
  147. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/vertex/extensions_call.py +0 -0
  148. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/vertex/extensions_class.py +0 -0
  149. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/vertex/genai_functions.py +0 -0
  150. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/vertex/init.py +0 -0
  151. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/vertex/memory_tools.py +0 -0
  152. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/vertex/safety.py +0 -0
  153. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo/vertex/type_dict_to_json.py +0 -0
  154. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo.egg-info/SOURCES.txt +0 -0
  155. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo.egg-info/dependency_links.txt +0 -0
  156. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo.egg-info/entry_points.txt +0 -0
  157. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo.egg-info/requires.txt +0 -0
  158. {sunholo-0.88.0 → sunholo-0.88.3}/sunholo.egg-info/top_level.txt +0 -0
  159. {sunholo-0.88.0 → sunholo-0.88.3}/tests/test_chat_history.py +0 -0
  160. {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.0
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.0.tar.gz
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,6 +1,6 @@
1
1
  from setuptools import setup, find_packages
2
2
 
3
- version = '0.88.0'
3
+ version = '0.88.3'
4
4
 
5
5
  setup(
6
6
  name='sunholo',
@@ -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
- editor.update_or_add_instance('cloud_run', 'new_service', {'cpu': '1', 'memory': '2Gi'})
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
- result = subprocess.run(['terraform', 'validate'], cwd=self.terraform_dir, capture_output=True, text=True)
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 result.returncode == 0:
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(result.stdout)
177
- print(result.stderr)
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
- # Parse the JSON string to a dictionary
293
+ # Load JSON data from the specified file
229
294
  try:
230
- instance_data: Dict[str, Any] = json.loads(args.json_data)
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"[bold red]Error parsing JSON data: {e}[/bold red]")
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('json_data', help='JSON string representing the instance data')
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.0
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.0.tar.gz
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