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.
- {sunholo-0.80.6 → sunholo-0.81.1}/PKG-INFO +2 -2
- sunholo-0.81.1/setup.cfg +16 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/setup.py +1 -1
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/auth/refresh.py +1 -3
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/components/retriever.py +1 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/database/__init__.py +1 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/database/alloydb.py +7 -2
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/database/alloydb_client.py +99 -5
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/discovery_engine/get_ai_search_chunks.py +1 -1
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/gcs/add_file.py +1 -1
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/gcs/download_url.py +41 -21
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/utils/config_class.py +2 -2
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/utils/gcp_project.py +1 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo.egg-info/PKG-INFO +2 -2
- sunholo-0.80.6/setup.cfg +0 -7
- {sunholo-0.80.6 → sunholo-0.81.1}/LICENSE.txt +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/MANIFEST.in +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/README.md +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/__init__.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/agents/__init__.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/agents/chat_history.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/agents/dispatch_to_qa.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/agents/fastapi/__init__.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/agents/fastapi/base.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/agents/fastapi/qna_routes.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/agents/flask/__init__.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/agents/flask/base.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/agents/flask/qna_routes.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/agents/flask/vac_routes.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/agents/langserve.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/agents/pubsub.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/agents/route.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/agents/special_commands.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/agents/swagger.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/archive/__init__.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/archive/archive.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/auth/__init__.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/auth/gcloud.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/auth/run.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/azure/__init__.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/azure/auth.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/azure/blobs.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/azure/event_grid.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/bots/__init__.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/bots/discord.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/bots/github_webhook.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/bots/webapp.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/chunker/__init__.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/chunker/azure.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/chunker/doc_handling.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/chunker/encode_metadata.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/chunker/images.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/chunker/loaders.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/chunker/message_data.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/chunker/pdfs.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/chunker/process_chunker_data.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/chunker/publish.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/chunker/pubsub.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/chunker/splitter.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/cli/__init__.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/cli/chat_vac.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/cli/cli.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/cli/cli_init.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/cli/configs.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/cli/deploy.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/cli/embedder.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/cli/merge_texts.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/cli/run_proxy.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/cli/sun_rich.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/cli/swagger.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/cli/vertex.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/components/__init__.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/components/llm.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/components/vectorstore.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/custom_logging.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/database/database.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/database/lancedb.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/database/sql/sb/create_function.sql +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/database/sql/sb/create_function_time.sql +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/database/sql/sb/create_table.sql +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/database/sql/sb/delete_source_row.sql +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/database/sql/sb/return_sources.sql +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/database/sql/sb/setup.sql +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/database/static_dbs.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/database/uuid.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/discovery_engine/__init__.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/discovery_engine/chunker_handler.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/discovery_engine/create_new.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/discovery_engine/discovery_engine_client.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/embedder/__init__.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/embedder/embed_chunk.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/gcs/__init__.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/gcs/download_folder.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/gcs/metadata.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/invoke/__init__.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/invoke/direct_vac_func.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/invoke/invoke_vac_utils.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/langfuse/__init__.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/langfuse/callback.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/langfuse/prompts.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/llamaindex/__init__.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/llamaindex/get_files.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/llamaindex/import_files.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/llamaindex/llamaindex_class.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/llamaindex/user_history.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/lookup/__init__.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/lookup/model_lookup.yaml +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/patches/__init__.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/patches/langchain/__init__.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/patches/langchain/lancedb.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/patches/langchain/vertexai.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/pubsub/__init__.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/pubsub/process_pubsub.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/pubsub/pubsub_manager.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/qna/__init__.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/qna/parsers.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/qna/retry.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/streaming/__init__.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/streaming/content_buffer.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/streaming/langserve.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/streaming/stream_lookup.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/streaming/streaming.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/summarise/__init__.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/summarise/summarise.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/tools/__init__.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/tools/web_browser.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/utils/__init__.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/utils/api_key.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/utils/big_context.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/utils/config.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/utils/config_schema.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/utils/gcp.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/utils/parsers.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/utils/timedelta.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/utils/user_ids.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/utils/version.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/vertex/__init__.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/vertex/extensions_call.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/vertex/extensions_class.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/vertex/genai_functions.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/vertex/init.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/vertex/memory_tools.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/vertex/safety.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo/vertex/type_dict_to_json.py +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo.egg-info/SOURCES.txt +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo.egg-info/dependency_links.txt +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo.egg-info/entry_points.txt +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo.egg-info/requires.txt +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/sunholo.egg-info/top_level.txt +0 -0
- {sunholo-0.80.6 → sunholo-0.81.1}/tests/test_chat_history.py +0 -0
- {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.
|
|
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.
|
|
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.81.1/setup.cfg
ADDED
|
@@ -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
|
+
|
|
@@ -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
|
|
@@ -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
|
-
|
|
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
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
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:
|
|
@@ -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 ..
|
|
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
|
-
|
|
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
|
-
|
|
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) ->
|
|
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) ->
|
|
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
|
-
|
|
148
|
-
return public_url, filename, signed
|
|
168
|
+
return public_url, filename, False
|
|
149
169
|
|
|
150
|
-
def parse_gs_uri(gs_uri: 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.
|
|
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.
|
|
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
|
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
|