sunholo 0.80.6__tar.gz → 0.81.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 (151) hide show
  1. {sunholo-0.80.6 → sunholo-0.81.1}/PKG-INFO +2 -2
  2. sunholo-0.81.1/setup.cfg +16 -0
  3. {sunholo-0.80.6 → sunholo-0.81.1}/setup.py +1 -1
  4. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/auth/refresh.py +1 -3
  5. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/components/retriever.py +1 -0
  6. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/database/__init__.py +1 -0
  7. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/database/alloydb.py +7 -2
  8. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/database/alloydb_client.py +99 -5
  9. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/discovery_engine/get_ai_search_chunks.py +1 -1
  10. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/gcs/add_file.py +1 -1
  11. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/gcs/download_url.py +41 -21
  12. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/utils/config_class.py +2 -2
  13. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/utils/gcp_project.py +1 -0
  14. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo.egg-info/PKG-INFO +2 -2
  15. sunholo-0.80.6/setup.cfg +0 -7
  16. {sunholo-0.80.6 → sunholo-0.81.1}/LICENSE.txt +0 -0
  17. {sunholo-0.80.6 → sunholo-0.81.1}/MANIFEST.in +0 -0
  18. {sunholo-0.80.6 → sunholo-0.81.1}/README.md +0 -0
  19. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/__init__.py +0 -0
  20. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/agents/__init__.py +0 -0
  21. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/agents/chat_history.py +0 -0
  22. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/agents/dispatch_to_qa.py +0 -0
  23. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/agents/fastapi/__init__.py +0 -0
  24. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/agents/fastapi/base.py +0 -0
  25. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/agents/fastapi/qna_routes.py +0 -0
  26. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/agents/flask/__init__.py +0 -0
  27. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/agents/flask/base.py +0 -0
  28. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/agents/flask/qna_routes.py +0 -0
  29. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/agents/flask/vac_routes.py +0 -0
  30. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/agents/langserve.py +0 -0
  31. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/agents/pubsub.py +0 -0
  32. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/agents/route.py +0 -0
  33. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/agents/special_commands.py +0 -0
  34. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/agents/swagger.py +0 -0
  35. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/archive/__init__.py +0 -0
  36. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/archive/archive.py +0 -0
  37. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/auth/__init__.py +0 -0
  38. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/auth/gcloud.py +0 -0
  39. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/auth/run.py +0 -0
  40. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/azure/__init__.py +0 -0
  41. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/azure/auth.py +0 -0
  42. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/azure/blobs.py +0 -0
  43. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/azure/event_grid.py +0 -0
  44. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/bots/__init__.py +0 -0
  45. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/bots/discord.py +0 -0
  46. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/bots/github_webhook.py +0 -0
  47. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/bots/webapp.py +0 -0
  48. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/chunker/__init__.py +0 -0
  49. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/chunker/azure.py +0 -0
  50. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/chunker/doc_handling.py +0 -0
  51. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/chunker/encode_metadata.py +0 -0
  52. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/chunker/images.py +0 -0
  53. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/chunker/loaders.py +0 -0
  54. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/chunker/message_data.py +0 -0
  55. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/chunker/pdfs.py +0 -0
  56. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/chunker/process_chunker_data.py +0 -0
  57. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/chunker/publish.py +0 -0
  58. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/chunker/pubsub.py +0 -0
  59. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/chunker/splitter.py +0 -0
  60. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/cli/__init__.py +0 -0
  61. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/cli/chat_vac.py +0 -0
  62. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/cli/cli.py +0 -0
  63. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/cli/cli_init.py +0 -0
  64. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/cli/configs.py +0 -0
  65. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/cli/deploy.py +0 -0
  66. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/cli/embedder.py +0 -0
  67. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/cli/merge_texts.py +0 -0
  68. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/cli/run_proxy.py +0 -0
  69. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/cli/sun_rich.py +0 -0
  70. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/cli/swagger.py +0 -0
  71. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/cli/vertex.py +0 -0
  72. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/components/__init__.py +0 -0
  73. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/components/llm.py +0 -0
  74. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/components/vectorstore.py +0 -0
  75. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/custom_logging.py +0 -0
  76. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/database/database.py +0 -0
  77. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/database/lancedb.py +0 -0
  78. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/database/sql/sb/create_function.sql +0 -0
  79. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/database/sql/sb/create_function_time.sql +0 -0
  80. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/database/sql/sb/create_table.sql +0 -0
  81. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/database/sql/sb/delete_source_row.sql +0 -0
  82. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/database/sql/sb/return_sources.sql +0 -0
  83. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/database/sql/sb/setup.sql +0 -0
  84. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/database/static_dbs.py +0 -0
  85. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/database/uuid.py +0 -0
  86. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/discovery_engine/__init__.py +0 -0
  87. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/discovery_engine/chunker_handler.py +0 -0
  88. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/discovery_engine/create_new.py +0 -0
  89. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/discovery_engine/discovery_engine_client.py +0 -0
  90. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/embedder/__init__.py +0 -0
  91. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/embedder/embed_chunk.py +0 -0
  92. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/gcs/__init__.py +0 -0
  93. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/gcs/download_folder.py +0 -0
  94. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/gcs/metadata.py +0 -0
  95. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/invoke/__init__.py +0 -0
  96. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/invoke/direct_vac_func.py +0 -0
  97. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/invoke/invoke_vac_utils.py +0 -0
  98. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/langfuse/__init__.py +0 -0
  99. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/langfuse/callback.py +0 -0
  100. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/langfuse/prompts.py +0 -0
  101. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/llamaindex/__init__.py +0 -0
  102. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/llamaindex/get_files.py +0 -0
  103. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/llamaindex/import_files.py +0 -0
  104. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/llamaindex/llamaindex_class.py +0 -0
  105. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/llamaindex/user_history.py +0 -0
  106. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/lookup/__init__.py +0 -0
  107. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/lookup/model_lookup.yaml +0 -0
  108. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/patches/__init__.py +0 -0
  109. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/patches/langchain/__init__.py +0 -0
  110. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/patches/langchain/lancedb.py +0 -0
  111. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/patches/langchain/vertexai.py +0 -0
  112. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/pubsub/__init__.py +0 -0
  113. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/pubsub/process_pubsub.py +0 -0
  114. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/pubsub/pubsub_manager.py +0 -0
  115. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/qna/__init__.py +0 -0
  116. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/qna/parsers.py +0 -0
  117. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/qna/retry.py +0 -0
  118. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/streaming/__init__.py +0 -0
  119. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/streaming/content_buffer.py +0 -0
  120. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/streaming/langserve.py +0 -0
  121. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/streaming/stream_lookup.py +0 -0
  122. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/streaming/streaming.py +0 -0
  123. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/summarise/__init__.py +0 -0
  124. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/summarise/summarise.py +0 -0
  125. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/tools/__init__.py +0 -0
  126. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/tools/web_browser.py +0 -0
  127. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/utils/__init__.py +0 -0
  128. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/utils/api_key.py +0 -0
  129. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/utils/big_context.py +0 -0
  130. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/utils/config.py +0 -0
  131. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/utils/config_schema.py +0 -0
  132. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/utils/gcp.py +0 -0
  133. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/utils/parsers.py +0 -0
  134. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/utils/timedelta.py +0 -0
  135. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/utils/user_ids.py +0 -0
  136. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/utils/version.py +0 -0
  137. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/vertex/__init__.py +0 -0
  138. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/vertex/extensions_call.py +0 -0
  139. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/vertex/extensions_class.py +0 -0
  140. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/vertex/genai_functions.py +0 -0
  141. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/vertex/init.py +0 -0
  142. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/vertex/memory_tools.py +0 -0
  143. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/vertex/safety.py +0 -0
  144. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/vertex/type_dict_to_json.py +0 -0
  145. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo.egg-info/SOURCES.txt +0 -0
  146. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo.egg-info/dependency_links.txt +0 -0
  147. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo.egg-info/entry_points.txt +0 -0
  148. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo.egg-info/requires.txt +0 -0
  149. {sunholo-0.80.6 → sunholo-0.81.1}/sunholo.egg-info/top_level.txt +0 -0
  150. {sunholo-0.80.6 → sunholo-0.81.1}/tests/test_chat_history.py +0 -0
  151. {sunholo-0.80.6 → sunholo-0.81.1}/tests/test_config.py +0 -0
@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: sunholo
3
- Version: 0.80.6
3
+ Version: 0.81.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.80.6.tar.gz
6
+ Download-URL: https://github.com/sunholo-data/sunholo-py/archive/refs/tags/v0.81.1.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,16 @@
1
+ [metadata]
2
+ description-file = README.md
3
+
4
+ [mypy]
5
+ files = sunholo, tests
6
+ python_version = 3.9
7
+ disallow_untyped_calls = True
8
+ warn_return_any = True
9
+ warn_unused_ignores = True
10
+ strict_optional = True
11
+ ignore_missing_imports = True
12
+
13
+ [egg_info]
14
+ tag_build =
15
+ tag_date = 0
16
+
@@ -1,7 +1,7 @@
1
1
  from setuptools import setup, find_packages
2
2
 
3
3
  # Define your base version
4
- version = '0.80.6'
4
+ version = '0.81.1'
5
5
 
6
6
  setup(
7
7
  name='sunholo',
@@ -4,8 +4,6 @@ import os
4
4
  import google.auth
5
5
  from google.auth.transport import requests
6
6
  from ..utils.gcp import is_running_on_gcp
7
-
8
-
9
7
  from ..custom_logging import log
10
8
 
11
9
  def get_default_email():
@@ -26,7 +24,7 @@ def get_default_email():
26
24
  return None
27
25
 
28
26
  log.info(f"Found default email: {service_account_email=} for {project_id=}")
29
- return service_account_email
27
+ return service_account_email, gcs_credentials
30
28
 
31
29
  def get_default_creds():
32
30
  gcs_credentials = None
@@ -170,4 +170,5 @@ def process_retrieval(retriever_list: list, config: ConfigManager):
170
170
  base_compressor=pipeline, base_retriever=lotr,
171
171
  k=k_override)
172
172
 
173
+ log.info(f"Returning Langchain retrieval object: {retriever}")
173
174
  return retriever
@@ -4,3 +4,4 @@ from .database import setup_database
4
4
  from .database import return_sources_last24
5
5
  from .database import delete_row_from_source
6
6
  from .static_dbs import get_db_directory
7
+ from .alloydb_client import AlloyDBClient
@@ -14,6 +14,8 @@ from .alloydb_client import AlloyDBClient
14
14
  from ..custom_logging import log
15
15
  from ..utils.config import load_config_key
16
16
 
17
+ from typing import List
18
+
17
19
 
18
20
  def create_alloydb_engine(vector_name):
19
21
 
@@ -231,8 +233,11 @@ async def load_alloydb_sql_async(sql, vector_name):
231
233
 
232
234
  return documents
233
235
 
234
- def and_or_ilike(sources, search_type="OR", operator="ILIKE"):
235
- unique_sources = set(sources.split())
236
+ def and_or_ilike(sources:List[str], search_type:str="OR", operator:str="ILIKE"):
237
+ if not isinstance(sources, list) or not all(isinstance(source, str) for source in sources):
238
+ raise TypeError("The `sources` argument must be a list of strings.")
239
+
240
+ unique_sources = set(sources)
236
241
  # Choose the delimiter based on the search_type argument
237
242
  delimiter = ' AND ' if search_type.upper() == "AND" else ' OR '
238
243
 
@@ -1,3 +1,4 @@
1
+ import os
1
2
  try:
2
3
  import pg8000
3
4
  import sqlalchemy
@@ -9,6 +10,7 @@ except ImportError:
9
10
 
10
11
  from .database import get_vector_size
11
12
  from ..custom_logging import log
13
+ from ..utils import ConfigManager
12
14
 
13
15
  class AlloyDBClient:
14
16
  """
@@ -35,11 +37,12 @@ class AlloyDBClient:
35
37
  """
36
38
 
37
39
  def __init__(self,
38
- project_id: str,
39
- region: str,
40
- cluster_name:str,
41
- instance_name:str,
42
- user:str,
40
+ config:ConfigManager,
41
+ project_id: str=None,
42
+ region: str=None,
43
+ cluster_name:str=None,
44
+ instance_name:str=None,
45
+ user:str=None,
43
46
  password=None,
44
47
  db="postgres"):
45
48
  """Initializes the AlloyDB client.
@@ -51,6 +54,23 @@ class AlloyDBClient:
51
54
  - password (str): The database user's password.
52
55
  - db_name (str): The name of the database.
53
56
  """
57
+ if config is None:
58
+ if project_id is None or region is None or cluster_name is None or instance_name is None:
59
+ raise ValueError("Must specify config or project_id, region, cluster_name, instance_name")
60
+ if config:
61
+ alloydb_config = config.vacConfig("alloydb_config")
62
+ if not alloydb_config:
63
+ raise ValueError("Must specify vac.alloydb_config")
64
+ project_id = alloydb_config["project_id"]
65
+ region = alloydb_config["region"]
66
+ cluster_name = alloydb_config["cluster"]
67
+ instance_name = alloydb_config["instance"]
68
+
69
+ ALLOYDB_DB = os.environ.get("ALLOYDB_DB")
70
+ if ALLOYDB_DB is None and alloydb_config.get("database") is None:
71
+ log.warning("Could not locate ALLOYDB_DB environment variable or 'alloydb_config.database'")
72
+
73
+ self.database = alloydb_config.get("database") or ALLOYDB_DB,
54
74
  self.connector = Connector()
55
75
  self.inst_uri = self._build_instance_uri(project_id, region, cluster_name, instance_name)
56
76
  self.engine = self._create_engine(self.inst_uri, user, password, db)
@@ -100,6 +120,80 @@ class AlloyDBClient:
100
120
  conn.close()
101
121
 
102
122
  return result
123
+
124
+ async def execute_sql_async(self, sql_statement):
125
+ """Executes a given SQL statement asynchronously with error handling."""
126
+ sql_ = sqlalchemy.text(sql_statement)
127
+ result = None
128
+ async with self.engine.connect() as conn:
129
+ try:
130
+ log.info(f"Executing SQL statement asynchronously: {sql_}")
131
+ result = await conn.execute(sql_)
132
+ except DatabaseError as e:
133
+ if "already exists" in str(e):
134
+ log.warning(f"Error ignored: {str(e)}. Assuming object already exists.")
135
+ else:
136
+ raise
137
+ finally:
138
+ await conn.close()
139
+
140
+ return result
141
+
142
+ async def get_sources_from_docstore_async(self, sources, vector_name, search_type="OR", just_source_name=False):
143
+ """Fetches sources from the docstore asynchronously."""
144
+ if just_source_name:
145
+ query = self._list_sources_from_docstore(sources, vector_name=vector_name, search_type=search_type)
146
+ else:
147
+ query = self._get_sources_from_docstore(sources, vector_name=vector_name, search_type=search_type)
148
+
149
+ if not query:
150
+ return []
151
+
152
+ documents = await self.execute_sql_async(query)
153
+ return documents
154
+
155
+ def _get_sources_from_docstore(self, sources, vector_name, search_type="OR"):
156
+ """Helper function to build the SQL query for fetching sources."""
157
+ if not sources:
158
+ log.warning("No sources found for alloydb fetch")
159
+ return ""
160
+
161
+ table_name = f"{vector_name}_docstore"
162
+
163
+ conditions = self._and_or_ilike(sources, search_type=search_type)
164
+
165
+ query = f"""
166
+ SELECT *
167
+ FROM {table_name}
168
+ WHERE {conditions}
169
+ ORDER BY langchain_metadata->>'objectId' ASC
170
+ LIMIT 500;
171
+ """
172
+
173
+ return query
174
+
175
+ def _list_sources_from_docstore(self, sources, vector_name, search_type="OR"):
176
+ """Helper function to build the SQL query for listing sources."""
177
+ table_name = f"{vector_name}_docstore"
178
+
179
+ if sources:
180
+ conditions = self._and_or_ilike(sources, search_type=search_type)
181
+ query = f"""
182
+ SELECT DISTINCT langchain_metadata->>'objectId' AS objectId
183
+ FROM {table_name}
184
+ WHERE {conditions}
185
+ ORDER BY langchain_metadata->>'objectId' ASC
186
+ LIMIT 500;
187
+ """
188
+ else:
189
+ query = f"""
190
+ SELECT DISTINCT langchain_metadata->>'objectId' AS objectId
191
+ FROM {table_name}
192
+ ORDER BY langchain_metadata->>'objectId' ASC
193
+ LIMIT 500;
194
+ """
195
+
196
+ return query
103
197
 
104
198
  @staticmethod
105
199
  def _and_or_ilike(sources, search_type="OR", operator="ILIKE"):
@@ -43,7 +43,7 @@ def get_all_chunks(question:str, config:ConfigManager):
43
43
  return None
44
44
 
45
45
  def get_chunks(question, vector_name, num_chunks):
46
- de = DiscoveryEngineClient(vector_name, project_id=get_gcp_project())
46
+ de = DiscoveryEngineClient(vector_name, project_id=get_gcp_project(include_config=True))
47
47
  try:
48
48
  return de.get_chunks(question, num_previous_chunks=num_chunks, num_next_chunks=num_chunks)
49
49
  except Exception as err:
@@ -22,7 +22,7 @@ except ImportError:
22
22
  storage = None
23
23
 
24
24
  from ..custom_logging import log
25
- from ..utils import load_config_key, ConfigManager
25
+ from ..utils import ConfigManager
26
26
 
27
27
 
28
28
  def handle_base64_image(base64_data: str, vector_name: str, extension: str):
@@ -1,3 +1,9 @@
1
+ from __future__ import annotations
2
+ from typing import Optional, Tuple, TYPE_CHECKING
3
+ if TYPE_CHECKING:
4
+ from PIL import Image
5
+ from google.cloud.storage.bucket import Bucket
6
+
1
7
  import os
2
8
  from urllib.parse import quote
3
9
  from datetime import datetime, timedelta
@@ -6,25 +12,20 @@ from datetime import datetime, timedelta
6
12
  from google.auth.exceptions import RefreshError
7
13
 
8
14
  try:
9
- from google.cloud import storage
15
+ from google.cloud import storage
10
16
  except ImportError:
11
17
  storage = None
12
18
 
13
19
  from ..custom_logging import log
14
- from ..utils.gcp import is_running_on_gcp
15
- from ..auth.refresh import refresh_credentials, get_default_creds, get_default_email
20
+ from ..auth.refresh import refresh_credentials, get_default_email
16
21
  from io import BytesIO
17
22
  try:
18
23
  from PIL import Image
19
24
  except ImportError:
20
25
  Image = None
21
26
 
22
- gcs_credentials = None
23
- project_id = None
24
- gcs_client = None
25
- gcs_bucket_cache = {}
26
27
 
27
- def get_image_from_gcs(gs_uri: str):
28
+ def get_image_from_gcs(gs_uri: str) -> Image.Image: # type: ignore
28
29
  """Converts image bytes from GCS to a PIL Image object."""
29
30
  image_bytes = get_bytes_from_gcs(gs_uri)
30
31
  if not Image:
@@ -35,7 +36,7 @@ def get_image_from_gcs(gs_uri: str):
35
36
  except IOError as e:
36
37
  raise ValueError("Unable to open image from bytes:", e)
37
38
 
38
- def get_bytes_from_gcs(gs_uri):
39
+ def get_bytes_from_gcs(gs_uri) -> Optional[bytes]:
39
40
  """
40
41
  Downloads a file from Google Cloud Storage and returns its bytes.
41
42
 
@@ -73,22 +74,39 @@ def get_bytes_from_gcs(gs_uri):
73
74
  log.error(f"Error downloading file from GCS: {str(err)}")
74
75
  return None
75
76
 
77
+ gcs_bucket_cache = {}
78
+ def get_bucket(bucket_name: str) -> Optional[Bucket]:
79
+ """
80
+ Gets a Cloud Storage bucket and initialised GCS client
81
+
82
+ Args:
83
+ bucket_name: Name of the bucket
84
+
85
+ Returns:
76
86
 
77
- if is_running_on_gcp():
78
- # Perform a refresh request to get the access token of the current credentials (Else, it's None)
79
- gcs_credentials, project_id = get_default_creds()
80
- # Prepare global variables for client reuse
87
+ """
81
88
  if storage:
82
89
  gcs_client = storage.Client()
90
+ else:
91
+ raise ImportError("google storage pip required - install via `pip install sunholo[gcp]`")
83
92
 
84
- def get_bucket(bucket_name):
85
93
  if bucket_name not in gcs_bucket_cache:
86
94
  gcs_bucket_cache[bucket_name] = gcs_client.get_bucket(bucket_name)
87
95
  return gcs_bucket_cache[bucket_name]
88
96
 
89
- def sign_gcs_url(bucket_name:str, object_name:str, expiry_secs = 86400):
97
+ def sign_gcs_url(bucket_name:str, object_name:str, expiry_secs:int = 86400) -> Optional[str]:
98
+ """
99
+ Creates a signed URL so that users can download a file from Google Cloud Storage without authentication
100
+
101
+ Args:
102
+ bucket_name: Name of the bucket where the object lies
103
+ object_name: Object within the bucket
104
+ expiry_secs: How long the link will be valid - default 24hrs
90
105
 
91
- service_account_email = get_default_email()
106
+ Returns:
107
+ str: The signed URL or None if not avialable
108
+ """
109
+ service_account_email, gcs_credentials = get_default_email()
92
110
 
93
111
  expires = datetime.now() + timedelta(seconds=expiry_secs)
94
112
 
@@ -115,7 +133,7 @@ def sign_gcs_url(bucket_name:str, object_name:str, expiry_secs = 86400):
115
133
  return None
116
134
 
117
135
 
118
- def construct_download_link(source_uri: str) -> tuple[str, str, bool]:
136
+ def construct_download_link(source_uri: str) -> Tuple[str, str, bool]:
119
137
  """Creates a viewable Cloud Storage web browser link from a gs:// URI."""
120
138
  if not source_uri.startswith("gs://"):
121
139
  return source_uri, source_uri, False # Return the URI as is if it doesn't start with gs://
@@ -132,7 +150,7 @@ def construct_download_link(source_uri: str) -> tuple[str, str, bool]:
132
150
  return construct_download_link_simple(bucket_name, object_name)
133
151
 
134
152
 
135
- def construct_download_link_simple(bucket_name:str, object_name:str) -> tuple[str, str, bool]:
153
+ def construct_download_link_simple(bucket_name:str, object_name:str) -> Tuple[str, str, bool]:
136
154
  """Creates a viewable Cloud Storage web browser link from a gs:// URI.
137
155
 
138
156
  Args:
@@ -142,12 +160,14 @@ def construct_download_link_simple(bucket_name:str, object_name:str) -> tuple[st
142
160
  A URL that directly access the object in the Cloud Storage web browser.
143
161
  """
144
162
 
163
+ if object_name.startswith("gs://"):
164
+ object_name = object_name.replace("gs://", "https://storage.cloud.google.com")
165
+
145
166
  public_url = f"https://storage.cloud.google.com/{bucket_name}/{quote(object_name)}"
146
167
  filename = os.path.basename(object_name)
147
- signed = False
148
- return public_url, filename, signed
168
+ return public_url, filename, False
149
169
 
150
- def parse_gs_uri(gs_uri: str) -> tuple[str, str]:
170
+ def parse_gs_uri(gs_uri: str) -> Tuple[str, str]:
151
171
  """Parses a gs:// URI into the bucket name and object name.
152
172
 
153
173
  Args:
@@ -37,9 +37,10 @@ class ConfigManager:
37
37
  self.config_folder = os.getenv("VAC_CONFIG_FOLDER", os.getcwd())
38
38
  self.local_config_folder = local_config_folder
39
39
  self.configs_by_kind = self.load_all_configs()
40
+ self.validate = validate
40
41
 
41
42
  test_agent = self.vacConfig("agent")
42
- if not test_agent and self.vector_name != "global" and validate:
43
+ if not test_agent and self.vector_name != "global" and self.validate:
43
44
  print(f"WARNING: No vacConfig.agent found for {self.vector_name} - are you in right folder? {local_config_folder=} {self.config_folder=}")
44
45
 
45
46
  def load_all_configs(self):
@@ -125,7 +126,6 @@ class ConfigManager:
125
126
  else:
126
127
  config = yaml.safe_load(file)
127
128
  self.config_cache[filename] = (config, datetime.now())
128
- log.debug(f"Loaded and cached {config_file}")
129
129
  if is_local:
130
130
  log.warning(f"Local configuration override for {filename} via {self.local_config_folder}")
131
131
  return config
@@ -24,6 +24,7 @@ def get_gcp_project(include_config=False):
24
24
  gcp_config = load_config_key("gcp_config", "global", "vacConfig")
25
25
  if gcp_config:
26
26
  if gcp_config.get('project_id'):
27
+ logging.info("Using project_id from vacConfig.gcp_config.project_id")
27
28
  return gcp_config.get('project_id')
28
29
 
29
30
  project_id = get_env_project_id()
@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: sunholo
3
- Version: 0.80.6
3
+ Version: 0.81.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.80.6.tar.gz
6
+ Download-URL: https://github.com/sunholo-data/sunholo-py/archive/refs/tags/v0.81.1.tar.gz
7
7
  Author: Holosun ApS
8
8
  Author-email: multivac@sunholo.com
9
9
  License: Apache License, Version 2.0
sunholo-0.80.6/setup.cfg DELETED
@@ -1,7 +0,0 @@
1
- [metadata]
2
- description-file = README.md
3
-
4
- [egg_info]
5
- tag_build =
6
- tag_date = 0
7
-
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