sunholo 0.88.3__tar.gz → 0.89.1__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.3 → sunholo-0.89.1}/PKG-INFO +2 -2
  2. {sunholo-0.88.3 → sunholo-0.89.1}/setup.py +1 -1
  3. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/cli/cli_init.py +93 -8
  4. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/genai/process_funcs_cls.py +19 -8
  5. sunholo-0.89.1/sunholo/langfuse/evals.py +72 -0
  6. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/terraform/tfvars_editor.py +19 -4
  7. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/utils/parsers.py +34 -0
  8. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo.egg-info/PKG-INFO +2 -2
  9. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo.egg-info/SOURCES.txt +1 -0
  10. {sunholo-0.88.3 → sunholo-0.89.1}/LICENSE.txt +0 -0
  11. {sunholo-0.88.3 → sunholo-0.89.1}/MANIFEST.in +0 -0
  12. {sunholo-0.88.3 → sunholo-0.89.1}/README.md +0 -0
  13. {sunholo-0.88.3 → sunholo-0.89.1}/setup.cfg +0 -0
  14. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/__init__.py +0 -0
  15. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/agents/__init__.py +0 -0
  16. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/agents/chat_history.py +0 -0
  17. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/agents/dispatch_to_qa.py +0 -0
  18. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/agents/fastapi/__init__.py +0 -0
  19. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/agents/fastapi/base.py +0 -0
  20. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/agents/fastapi/qna_routes.py +0 -0
  21. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/agents/flask/__init__.py +0 -0
  22. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/agents/flask/base.py +0 -0
  23. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/agents/flask/qna_routes.py +0 -0
  24. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/agents/flask/vac_routes.py +0 -0
  25. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/agents/langserve.py +0 -0
  26. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/agents/pubsub.py +0 -0
  27. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/agents/route.py +0 -0
  28. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/agents/special_commands.py +0 -0
  29. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/agents/swagger.py +0 -0
  30. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/archive/__init__.py +0 -0
  31. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/archive/archive.py +0 -0
  32. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/auth/__init__.py +0 -0
  33. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/auth/gcloud.py +0 -0
  34. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/auth/refresh.py +0 -0
  35. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/auth/run.py +0 -0
  36. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/azure/__init__.py +0 -0
  37. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/azure/auth.py +0 -0
  38. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/azure/blobs.py +0 -0
  39. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/azure/event_grid.py +0 -0
  40. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/bots/__init__.py +0 -0
  41. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/bots/discord.py +0 -0
  42. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/bots/github_webhook.py +0 -0
  43. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/bots/webapp.py +0 -0
  44. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/chunker/__init__.py +0 -0
  45. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/chunker/azure.py +0 -0
  46. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/chunker/doc_handling.py +0 -0
  47. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/chunker/encode_metadata.py +0 -0
  48. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/chunker/images.py +0 -0
  49. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/chunker/loaders.py +0 -0
  50. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/chunker/message_data.py +0 -0
  51. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/chunker/pdfs.py +0 -0
  52. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/chunker/process_chunker_data.py +0 -0
  53. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/chunker/publish.py +0 -0
  54. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/chunker/pubsub.py +0 -0
  55. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/chunker/splitter.py +0 -0
  56. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/cli/__init__.py +0 -0
  57. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/cli/chat_vac.py +0 -0
  58. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/cli/cli.py +0 -0
  59. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/cli/configs.py +0 -0
  60. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/cli/deploy.py +0 -0
  61. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/cli/embedder.py +0 -0
  62. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/cli/merge_texts.py +0 -0
  63. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/cli/run_proxy.py +0 -0
  64. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/cli/sun_rich.py +0 -0
  65. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/cli/swagger.py +0 -0
  66. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/cli/vertex.py +0 -0
  67. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/components/__init__.py +0 -0
  68. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/components/llm.py +0 -0
  69. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/components/retriever.py +0 -0
  70. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/components/vectorstore.py +0 -0
  71. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/custom_logging.py +0 -0
  72. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/database/__init__.py +0 -0
  73. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/database/alloydb.py +0 -0
  74. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/database/alloydb_client.py +0 -0
  75. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/database/database.py +0 -0
  76. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/database/lancedb.py +0 -0
  77. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/database/sql/sb/create_function.sql +0 -0
  78. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/database/sql/sb/create_function_time.sql +0 -0
  79. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/database/sql/sb/create_table.sql +0 -0
  80. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/database/sql/sb/delete_source_row.sql +0 -0
  81. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/database/sql/sb/return_sources.sql +0 -0
  82. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/database/sql/sb/setup.sql +0 -0
  83. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/database/static_dbs.py +0 -0
  84. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/database/uuid.py +0 -0
  85. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/discovery_engine/__init__.py +0 -0
  86. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/discovery_engine/chunker_handler.py +0 -0
  87. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/discovery_engine/create_new.py +0 -0
  88. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/discovery_engine/discovery_engine_client.py +0 -0
  89. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/discovery_engine/get_ai_search_chunks.py +0 -0
  90. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/embedder/__init__.py +0 -0
  91. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/embedder/embed_chunk.py +0 -0
  92. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/excel/__init__.py +0 -0
  93. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/excel/plugin.py +0 -0
  94. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/gcs/__init__.py +0 -0
  95. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/gcs/add_file.py +0 -0
  96. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/gcs/download_folder.py +0 -0
  97. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/gcs/download_url.py +0 -0
  98. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/gcs/metadata.py +0 -0
  99. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/genai/__init__.py +0 -0
  100. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/genai/init.py +0 -0
  101. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/genai/safety.py +0 -0
  102. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/invoke/__init__.py +0 -0
  103. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/invoke/async_class.py +0 -0
  104. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/invoke/direct_vac_func.py +0 -0
  105. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/invoke/invoke_vac_utils.py +0 -0
  106. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/langfuse/__init__.py +0 -0
  107. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/langfuse/callback.py +0 -0
  108. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/langfuse/prompts.py +0 -0
  109. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/llamaindex/__init__.py +0 -0
  110. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/llamaindex/get_files.py +0 -0
  111. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/llamaindex/import_files.py +0 -0
  112. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/llamaindex/llamaindex_class.py +0 -0
  113. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/llamaindex/user_history.py +0 -0
  114. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/lookup/__init__.py +0 -0
  115. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/lookup/model_lookup.yaml +0 -0
  116. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/patches/__init__.py +0 -0
  117. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/patches/langchain/__init__.py +0 -0
  118. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/patches/langchain/lancedb.py +0 -0
  119. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/patches/langchain/vertexai.py +0 -0
  120. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/pubsub/__init__.py +0 -0
  121. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/pubsub/process_pubsub.py +0 -0
  122. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/pubsub/pubsub_manager.py +0 -0
  123. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/qna/__init__.py +0 -0
  124. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/qna/parsers.py +0 -0
  125. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/qna/retry.py +0 -0
  126. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/streaming/__init__.py +0 -0
  127. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/streaming/content_buffer.py +0 -0
  128. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/streaming/langserve.py +0 -0
  129. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/streaming/stream_lookup.py +0 -0
  130. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/streaming/streaming.py +0 -0
  131. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/summarise/__init__.py +0 -0
  132. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/summarise/summarise.py +0 -0
  133. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/terraform/__init__.py +0 -0
  134. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/tools/__init__.py +0 -0
  135. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/tools/web_browser.py +0 -0
  136. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/utils/__init__.py +0 -0
  137. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/utils/api_key.py +0 -0
  138. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/utils/big_context.py +0 -0
  139. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/utils/config.py +0 -0
  140. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/utils/config_class.py +0 -0
  141. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/utils/config_schema.py +0 -0
  142. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/utils/gcp.py +0 -0
  143. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/utils/gcp_project.py +0 -0
  144. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/utils/timedelta.py +0 -0
  145. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/utils/user_ids.py +0 -0
  146. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/utils/version.py +0 -0
  147. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/vertex/__init__.py +0 -0
  148. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/vertex/extensions_call.py +0 -0
  149. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/vertex/extensions_class.py +0 -0
  150. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/vertex/genai_functions.py +0 -0
  151. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/vertex/init.py +0 -0
  152. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/vertex/memory_tools.py +0 -0
  153. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/vertex/safety.py +0 -0
  154. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo/vertex/type_dict_to_json.py +0 -0
  155. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo.egg-info/dependency_links.txt +0 -0
  156. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo.egg-info/entry_points.txt +0 -0
  157. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo.egg-info/requires.txt +0 -0
  158. {sunholo-0.88.3 → sunholo-0.89.1}/sunholo.egg-info/top_level.txt +0 -0
  159. {sunholo-0.88.3 → sunholo-0.89.1}/tests/test_chat_history.py +0 -0
  160. {sunholo-0.88.3 → sunholo-0.89.1}/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
3
+ Version: 0.89.1
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.3.tar.gz
6
+ Download-URL: https://github.com/sunholo-data/sunholo-py/archive/refs/tags/v0.89.1.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.3'
3
+ version = '0.89.1'
4
4
 
5
5
  setup(
6
6
  name='sunholo',
@@ -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
  """
@@ -28,7 +30,7 @@ This will create a new directory named `my_genai_project` with the template file
28
30
  """
29
31
  from .sun_rich import console
30
32
 
31
- project_name = args.project_name
33
+ project_name = sanitize_cloudrun_name(args.project_name)
32
34
  current_dir = os.getcwd() # This captures the current directory where the command is run
33
35
  project_dir = os.path.join(current_dir, project_name)
34
36
 
@@ -51,6 +53,8 @@ This will create a new directory named `my_genai_project` with the template file
51
53
  shutil.copy(src_path, dest_path)
52
54
  elif os.path.isdir(src_path):
53
55
  shutil.copytree(src_path, dest_path)
56
+
57
+
54
58
 
55
59
  # Determine the location of the generated.tfvars file
56
60
  terraform_dir = args.terraform_dir or os.getenv('MULTIVAC_TERRAFORM_DIR')
@@ -62,19 +66,15 @@ This will create a new directory named `my_genai_project` with the template file
62
66
  # Get the service account, either from the CLI argument or default
63
67
  service_account = args.service_account or "sa-llmops" # Default service account
64
68
 
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
69
  # Paths to be included in the cloud build (based on the current working directory)
73
70
  # We want paths to start from 'application/system_services/{project_name}'
74
71
  relative_base = os.path.relpath(current_dir, os.path.join(current_dir, "..", ".."))
75
72
  included_path = os.path.join(relative_base, project_name, "**")
76
73
  cloud_build_path = os.path.join(relative_base, project_name, "cloudbuild.yaml")
77
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
+
78
78
  # Define the cloud_run configuration for 'discord-server' with the correct project_dir path
79
79
  cloud_run_config = {
80
80
  project_name: {
@@ -118,6 +118,91 @@ This will create a new directory named `my_genai_project` with the template file
118
118
  )
119
119
  console.rule()
120
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_path} written successfully with service name '{service_name}'.")
205
+
121
206
 
122
207
  def setup_init_subparser(subparsers):
123
208
  """
@@ -109,14 +109,24 @@ class GenAIFunctionProcessor:
109
109
  work_on = api_requests_and_responses or self.last_api_requests_and_responses
110
110
  parts = []
111
111
  for part in work_on:
112
- parts.append(
113
- Part(
114
- function_response=genai.protos.FunctionResponse(
115
- name=part[0],
116
- response={"result": part[2], "args": json.dumps(part[1])}
112
+ try:
113
+ parts.append(
114
+ Part(
115
+ function_response=genai.protos.FunctionResponse(
116
+ name=part[0],
117
+ response={"result": part[2], "args": json.dumps(part[1])}
118
+ )
117
119
  )
118
120
  )
119
- )
121
+ except Exception as err:
122
+ parts.append(
123
+ Part(
124
+ function_response=genai.protos.FunctionResponse(
125
+ name=part[0],
126
+ response={"result": f"ERROR: {str(err)}"}
127
+ )
128
+ )
129
+ )
120
130
 
121
131
  return parts
122
132
 
@@ -212,14 +222,15 @@ class GenAIFunctionProcessor:
212
222
  if fn := part.function_call:
213
223
  # Extract parameters for the function call
214
224
  function_name = fn.name
215
- params = {key: val for key, val in fn.args.items()}
225
+ params_obj = {key: val for key, val in fn.args.items()}
226
+ params = ', '.join(f'{key}={val}' for key, val in params_obj.items())
216
227
  log.info(f"Executing {function_name} with params {params}")
217
228
 
218
229
  # Check if the function is in our dictionary of available functions
219
230
  if function_name in self.funcs:
220
231
  try:
221
232
  # Execute the function with the provided parameters
222
- result = self.funcs[function_name](**params)
233
+ result = self.funcs[function_name](**params_obj)
223
234
  log.info(f"Got result from {function_name}: {result}")
224
235
  except Exception as err:
225
236
  error_message = f"Error in {function_name}: {str(err)}"
@@ -0,0 +1,72 @@
1
+ import os
2
+ from ..pubsub import decode_pubsub_message
3
+ from langfuse import Langfuse
4
+ from ..custom_logging import log
5
+
6
+ # Example of how eval_funcs might be structured
7
+ def eval_length(trace):
8
+ """
9
+ An example of how eval_funcs might be structured.
10
+ Must output a dictionary with 'score' and 'reason' keys.
11
+ """
12
+ # Example evaluation logic
13
+ return {
14
+ "score": len(trace.output), # Example: length of the output text
15
+ "reason": "Length of the output text"
16
+ }
17
+
18
+ def pubsub_to_evals(data: dict, eval_funcs: list=[eval_length]) -> dict:
19
+ """
20
+ Process a Pub/Sub message and run evaluations using the provided evaluation functions.
21
+
22
+ Args:
23
+ data (dict): The Pub/Sub message data.
24
+ eval_funcs (list): A list of evaluation functions to run. Each function should return a dict with 'score' and 'reason'.
25
+ """
26
+
27
+ # Decode the message
28
+ message_data, metadata, vector_name = decode_pubsub_message(data)
29
+
30
+ if 'trace_id' not in message_data:
31
+ raise ValueError('No trace_id found in message data')
32
+
33
+ # Initialize Langfuse with environment variables
34
+ langfuse = Langfuse(
35
+ secret_key=os.environ["LANGFUSE_SECRET_KEY"],
36
+ public_key=os.environ["LANGFUSE_PUBLIC_KEY"],
37
+ host=os.environ["LANGFUSE_HOST"]
38
+ )
39
+
40
+ trace_id = message_data.pop('trace_id', None)
41
+
42
+ # Fetch the latest trace (or modify as needed to fetch a specific trace)
43
+ trace = langfuse.fetch_trace(id=trace_id)
44
+
45
+ if trace.output is None:
46
+ raise ValueError("Trace {trace.name} had no generated output, it was skipped")
47
+
48
+ # Run the evaluation functions
49
+ eval_results = []
50
+ for eval_func in eval_funcs:
51
+ eval_result = eval_func(trace) # Assuming eval_func returns a dict with 'score' and 'reason'
52
+ eval_results.append(eval_result)
53
+
54
+ eval_name = eval_func.__name__
55
+
56
+ if 'score' or 'reason' not in eval_result:
57
+ raise ValueError(f"Trace {trace.name} using {eval_name=} did not return a dict with 'score' and 'reason': {eval_result=}")
58
+
59
+ log.info(f"TraceId {trace.id} with name {trace.name} had {eval_name=} with score {eval_result=}")
60
+
61
+ # Submit the evaluation to Langfuse
62
+ langfuse.score(
63
+ trace_id=trace.id,
64
+ name=eval_name, # Use the function name as the evaluation name
65
+ value=eval_result["score"],
66
+ comment=eval_result["reason"],
67
+ **message_data
68
+ )
69
+
70
+ return {"trace_id": trace.id, "eval_results": eval_results}
71
+
72
+
@@ -5,6 +5,8 @@ except ImportError:
5
5
 
6
6
  import json
7
7
  import subprocess
8
+ from datetime import datetime
9
+ import shutil
8
10
  import os
9
11
  import io
10
12
  from typing import Dict, Any
@@ -75,6 +77,13 @@ class TerraformVarsEditor:
75
77
 
76
78
  self.tfvars_file = tfvars_file
77
79
  self.terraform_dir = terraform_dir
80
+
81
+ # Ensure the tfvars file exists, if not, create it
82
+ if not os.path.exists(self.tfvars_file):
83
+ log.info(f"{self.tfvars_file} does not exist. Creating a new file.")
84
+ with open(self.tfvars_file, 'w') as file:
85
+ file.write("") # Create an empty tfvars file
86
+
78
87
  self.tfvars_data = self._load_tfvars()
79
88
 
80
89
  def _load_tfvars(self) -> Dict[str, Any]:
@@ -118,8 +127,9 @@ class TerraformVarsEditor:
118
127
  -------
119
128
  backup_file = self._backup_tfvars()
120
129
  """
121
- backup_file = f"{self.tfvars_file}.bak"
122
- os.rename(self.tfvars_file, backup_file)
130
+ timestamp = datetime.now().strftime('%Y%m%d%H%M%S')
131
+ backup_file = f"{self.tfvars_file}.{timestamp}.bak"
132
+ shutil.copy2(self.tfvars_file, backup_file)
123
133
  return backup_file
124
134
 
125
135
  def _restore_tfvars(self, backup_file: str) -> None:
@@ -231,8 +241,10 @@ class TerraformVarsEditor:
231
241
  # Attempt to validate the changes with Terraform
232
242
  if not self.validate_terraform():
233
243
  # If validation fails, restore the original file from the backup
244
+ failed_file = f"{self.tfvars_file}.failed"
245
+ shutil.copy2(self.tfvars_file, failed_file)
234
246
  self._restore_tfvars(backup_file)
235
- log.error(f"Changes aborted, original {self.tfvars_file} restored.")
247
+ print(f"Changes aborted, original {self.tfvars_file} restored. Failed file: {failed_file}")
236
248
  else:
237
249
  log.info(f"Terraform validation passed, changes saved to {self.tfvars_file}.")
238
250
  os.remove(backup_file) # Remove the backup if validation passes
@@ -273,8 +285,11 @@ class TerraformVarsEditor:
273
285
  # Attempt to validate the changes with Terraform
274
286
  if not self.validate_terraform():
275
287
  # If validation fails, restore the original file from the backup
288
+ failed_file = f"{self.tfvars_file}.failed"
289
+ shutil.copy2(self.tfvars_file, failed_file)
276
290
  self._restore_tfvars(backup_file)
277
- console.print(f"Changes aborted, original {self.tfvars_file} restored.")
291
+
292
+ print(f"Changes aborted, original {self.tfvars_file} restored. Failed file: {failed_file}")
278
293
  else:
279
294
  console.print(f"Terraform validation passed, changes saved to {self.tfvars_file}.")
280
295
  os.remove(backup_file) # Remove the backup if validation passes
@@ -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
3
+ Version: 0.89.1
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.3.tar.gz
6
+ Download-URL: https://github.com/sunholo-data/sunholo-py/archive/refs/tags/v0.89.1.tar.gz
7
7
  Author: Holosun ApS
8
8
  Author-email: multivac@sunholo.com
9
9
  License: Apache License, Version 2.0
@@ -105,6 +105,7 @@ sunholo/invoke/direct_vac_func.py
105
105
  sunholo/invoke/invoke_vac_utils.py
106
106
  sunholo/langfuse/__init__.py
107
107
  sunholo/langfuse/callback.py
108
+ sunholo/langfuse/evals.py
108
109
  sunholo/langfuse/prompts.py
109
110
  sunholo/llamaindex/__init__.py
110
111
  sunholo/llamaindex/get_files.py
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