sunholo 0.100.3__tar.gz → 0.101.2__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.100.3 → sunholo-0.101.2}/PKG-INFO +2 -2
- {sunholo-0.100.3 → sunholo-0.101.2}/setup.py +1 -1
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/gcs/add_file.py +35 -8
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/gcs/download_url.py +1 -0
- sunholo-0.101.2/sunholo/gcs/extract_and_sign.py +41 -0
- sunholo-0.101.2/sunholo/genai/images.py +38 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/genai/process_funcs_cls.py +50 -3
- sunholo-0.101.2/sunholo/langfuse/prompts.py +80 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/streaming/content_buffer.py +0 -1
- sunholo-0.101.2/sunholo/utils/mime.py +63 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo.egg-info/PKG-INFO +2 -2
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo.egg-info/SOURCES.txt +4 -0
- sunholo-0.101.2/tests/test_async.py +93 -0
- sunholo-0.100.3/sunholo/langfuse/prompts.py +0 -44
- {sunholo-0.100.3 → sunholo-0.101.2}/LICENSE.txt +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/MANIFEST.in +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/README.md +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/setup.cfg +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/__init__.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/agents/__init__.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/agents/chat_history.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/agents/dispatch_to_qa.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/agents/fastapi/__init__.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/agents/fastapi/base.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/agents/fastapi/qna_routes.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/agents/flask/__init__.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/agents/flask/base.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/agents/flask/qna_routes.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/agents/flask/vac_routes.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/agents/langserve.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/agents/pubsub.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/agents/route.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/agents/special_commands.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/agents/swagger.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/archive/__init__.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/archive/archive.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/auth/__init__.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/auth/gcloud.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/auth/refresh.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/auth/run.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/azure/__init__.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/azure/auth.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/azure/blobs.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/azure/event_grid.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/bots/__init__.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/bots/discord.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/bots/github_webhook.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/bots/webapp.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/chunker/__init__.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/chunker/azure.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/chunker/doc_handling.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/chunker/encode_metadata.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/chunker/images.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/chunker/loaders.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/chunker/message_data.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/chunker/pdfs.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/chunker/process_chunker_data.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/chunker/publish.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/chunker/pubsub.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/chunker/splitter.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/cli/__init__.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/cli/chat_vac.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/cli/cli.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/cli/cli_init.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/cli/configs.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/cli/deploy.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/cli/embedder.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/cli/merge_texts.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/cli/run_proxy.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/cli/sun_rich.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/cli/swagger.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/cli/vertex.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/components/__init__.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/components/llm.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/components/retriever.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/components/vectorstore.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/custom_logging.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/database/__init__.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/database/alloydb.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/database/alloydb_client.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/database/database.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/database/lancedb.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/database/sql/sb/create_function.sql +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/database/sql/sb/create_function_time.sql +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/database/sql/sb/create_table.sql +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/database/sql/sb/delete_source_row.sql +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/database/sql/sb/return_sources.sql +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/database/sql/sb/setup.sql +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/database/static_dbs.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/database/uuid.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/discovery_engine/__init__.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/discovery_engine/chunker_handler.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/discovery_engine/create_new.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/discovery_engine/discovery_engine_client.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/discovery_engine/get_ai_search_chunks.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/embedder/__init__.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/embedder/embed_chunk.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/excel/__init__.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/excel/plugin.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/gcs/__init__.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/gcs/download_folder.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/gcs/metadata.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/genai/__init__.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/genai/init.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/genai/safety.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/invoke/__init__.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/invoke/async_class.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/invoke/direct_vac_func.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/invoke/invoke_vac_utils.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/langfuse/__init__.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/langfuse/callback.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/langfuse/evals.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/llamaindex/__init__.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/llamaindex/get_files.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/llamaindex/import_files.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/llamaindex/llamaindex_class.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/llamaindex/user_history.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/lookup/__init__.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/lookup/model_lookup.yaml +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/patches/__init__.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/patches/langchain/__init__.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/patches/langchain/lancedb.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/patches/langchain/vertexai.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/pubsub/__init__.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/pubsub/process_pubsub.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/pubsub/pubsub_manager.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/qna/__init__.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/qna/parsers.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/qna/retry.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/streaming/__init__.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/streaming/langserve.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/streaming/stream_lookup.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/streaming/streaming.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/summarise/__init__.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/summarise/summarise.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/terraform/__init__.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/terraform/tfvars_editor.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/tools/__init__.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/tools/web_browser.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/utils/__init__.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/utils/api_key.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/utils/big_context.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/utils/config.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/utils/config_class.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/utils/config_schema.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/utils/gcp.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/utils/gcp_project.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/utils/parsers.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/utils/timedelta.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/utils/user_ids.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/utils/version.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/vertex/__init__.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/vertex/extensions_call.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/vertex/extensions_class.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/vertex/genai_functions.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/vertex/init.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/vertex/memory_tools.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/vertex/safety.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo/vertex/type_dict_to_json.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo.egg-info/dependency_links.txt +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo.egg-info/entry_points.txt +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo.egg-info/requires.txt +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/sunholo.egg-info/top_level.txt +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/tests/test_chat_history.py +0 -0
- {sunholo-0.100.3 → sunholo-0.101.2}/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.101.2
|
|
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.101.2.tar.gz
|
|
7
7
|
Author: Holosun ApS
|
|
8
8
|
Author-email: multivac@sunholo.com
|
|
9
9
|
License: Apache License, Version 2.0
|
|
@@ -25,6 +25,40 @@ except ImportError:
|
|
|
25
25
|
from ..custom_logging import log
|
|
26
26
|
from ..utils import ConfigManager
|
|
27
27
|
|
|
28
|
+
def guess_image_type(file_path: str) -> str:
|
|
29
|
+
"""
|
|
30
|
+
Guess the image type based on the file extension.
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
file_path (str): The path or URL of the image file.
|
|
34
|
+
|
|
35
|
+
Returns:
|
|
36
|
+
str: The guessed image type (e.g., "jpeg", "png", "gif", etc.)
|
|
37
|
+
or None if the extension is not recognized.
|
|
38
|
+
"""
|
|
39
|
+
# Extract the file extension
|
|
40
|
+
_, ext = os.path.splitext(file_path)
|
|
41
|
+
|
|
42
|
+
# Normalize and remove the leading dot
|
|
43
|
+
ext = ext.lower().strip('.')
|
|
44
|
+
|
|
45
|
+
# Mapping of common file extensions to image types
|
|
46
|
+
extension_to_type = {
|
|
47
|
+
"jpg": "image/jpeg",
|
|
48
|
+
"jpeg": "image/jpeg",
|
|
49
|
+
"png": "image/png",
|
|
50
|
+
"gif": "image/gif",
|
|
51
|
+
"bmp": "image/bmp",
|
|
52
|
+
"tiff": "image/tiff",
|
|
53
|
+
"tif": "image/tiff",
|
|
54
|
+
"webp": "image/webp",
|
|
55
|
+
"ico": "image/ico",
|
|
56
|
+
"svg": "image/svg",
|
|
57
|
+
"pdf": "application/pdf",
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return extension_to_type.get(ext.lower(), None)
|
|
61
|
+
|
|
28
62
|
|
|
29
63
|
def handle_base64_image(base64_data: str, vector_name: str, extension: str):
|
|
30
64
|
"""
|
|
@@ -58,14 +92,7 @@ def handle_base64_image(base64_data: str, vector_name: str, extension: str):
|
|
|
58
92
|
os.remove(filename) # Clean up the saved file
|
|
59
93
|
|
|
60
94
|
# Determine MIME type based on extension
|
|
61
|
-
mime_type =
|
|
62
|
-
".jpg": "image/jpeg",
|
|
63
|
-
".jpeg": "image/jpeg",
|
|
64
|
-
".png": "image/png",
|
|
65
|
-
".gif": "image/gif",
|
|
66
|
-
".bmp": "image/bmp",
|
|
67
|
-
".tiff": "image/tiff"
|
|
68
|
-
}.get(extension.lower(), "application/octet-stream") # Default MIME type if unknown
|
|
95
|
+
mime_type = guess_image_type(extension) or "application/octet-stream"
|
|
69
96
|
|
|
70
97
|
return image_uri, mime_type
|
|
71
98
|
except Exception as e:
|
|
@@ -176,6 +176,7 @@ def construct_download_link_simple(bucket_name:str, object_name:str) -> Tuple[st
|
|
|
176
176
|
else:
|
|
177
177
|
public_url = f"https://storage.cloud.google.com/{bucket_name}/{quote(object_name)}"
|
|
178
178
|
filename = os.path.basename(object_name)
|
|
179
|
+
log.info(f"Created simple download link: {public_url}")
|
|
179
180
|
return public_url, filename, False
|
|
180
181
|
|
|
181
182
|
def parse_gs_uri(gs_uri: str) -> Tuple[str, str]:
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import re
|
|
2
|
+
import asyncio
|
|
3
|
+
|
|
4
|
+
from .download_url import construct_download_link
|
|
5
|
+
from ..utils.mime import guess_mime_type
|
|
6
|
+
from ..custom_logging import log
|
|
7
|
+
|
|
8
|
+
async def extract_gs_uris_and_sign(content, pattern=r'gs://[^\n]+\.(?:png|jpg|jpeg|pdf|txt|md)'):
|
|
9
|
+
|
|
10
|
+
gs_matches = re.findall(pattern, content)
|
|
11
|
+
unique_gs_matches = set(gs_matches)
|
|
12
|
+
image_signed_urls = []
|
|
13
|
+
if unique_gs_matches:
|
|
14
|
+
log.info(f"Got gs matches: {unique_gs_matches}")
|
|
15
|
+
|
|
16
|
+
async def process_link(gs_url):
|
|
17
|
+
log.info(f"Processing {gs_url}")
|
|
18
|
+
link, encoded_filename, signed = await asyncio.to_thread(construct_download_link, gs_url)
|
|
19
|
+
if signed:
|
|
20
|
+
try:
|
|
21
|
+
mime_type = guess_mime_type(gs_url)
|
|
22
|
+
except Exception as err:
|
|
23
|
+
log.error(f"Could not find mime_type for {link} - {str(err)}")
|
|
24
|
+
mime_type = "application/octet-stream"
|
|
25
|
+
|
|
26
|
+
return {
|
|
27
|
+
"original": gs_url,
|
|
28
|
+
"link": link,
|
|
29
|
+
"name": encoded_filename,
|
|
30
|
+
"mime": mime_type,
|
|
31
|
+
"signed": signed
|
|
32
|
+
}
|
|
33
|
+
else:
|
|
34
|
+
log.info(f"Could not sign this GS_URI: {gs_url} - skipping")
|
|
35
|
+
return None
|
|
36
|
+
|
|
37
|
+
# Gather all tasks and run them concurrently
|
|
38
|
+
image_signed_urls = await asyncio.gather(*(process_link(gs_url) for gs_url in unique_gs_matches))
|
|
39
|
+
|
|
40
|
+
log.info(f"found files to msg: {image_signed_urls}")
|
|
41
|
+
return image_signed_urls
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import re
|
|
2
|
+
from ..utils.mime import guess_mime_type
|
|
3
|
+
from ..gcs import get_bytes_from_gcs
|
|
4
|
+
from ..custom_logging import log
|
|
5
|
+
import io
|
|
6
|
+
import os
|
|
7
|
+
try:
|
|
8
|
+
import google.generativeai as genai
|
|
9
|
+
except ImportError:
|
|
10
|
+
genai = None
|
|
11
|
+
|
|
12
|
+
def extract_gs_images_and_genai_upload(content:str):
|
|
13
|
+
# Regular expression to find gs:// URLs
|
|
14
|
+
pattern = r'gs://[^ ]+\.(?:png|jpg|jpeg|pdf)'
|
|
15
|
+
|
|
16
|
+
gs_matches = re.findall(pattern, content)
|
|
17
|
+
unique_gs_matches = set(gs_matches)
|
|
18
|
+
output_gs_images = []
|
|
19
|
+
for gs_uri in unique_gs_matches:
|
|
20
|
+
mime_type = guess_mime_type(gs_uri)
|
|
21
|
+
if mime_type is None:
|
|
22
|
+
continue
|
|
23
|
+
|
|
24
|
+
log.info(f"Getting bytes from GCS: {gs_uri}")
|
|
25
|
+
image_bytes = get_bytes_from_gcs(gs_uri)
|
|
26
|
+
if image_bytes is None:
|
|
27
|
+
continue
|
|
28
|
+
image_file = io.BytesIO(image_bytes)
|
|
29
|
+
image_file.name = os.path.basename(gs_uri) # Assign a name, as some APIs require it
|
|
30
|
+
|
|
31
|
+
try:
|
|
32
|
+
uploaded_file = genai.upload_file(image_file)
|
|
33
|
+
output_gs_images.append(uploaded_file)
|
|
34
|
+
|
|
35
|
+
except Exception as e:
|
|
36
|
+
log.error(f"Error adding {gs_uri} to base64: {str(e)}")
|
|
37
|
+
|
|
38
|
+
return output_gs_images
|
|
@@ -14,11 +14,18 @@ try:
|
|
|
14
14
|
import proto
|
|
15
15
|
from google.generativeai.types import RequestOptions
|
|
16
16
|
from google.api_core import retry
|
|
17
|
+
from google.generativeai import ChatSession
|
|
17
18
|
except ImportError:
|
|
18
19
|
genai = None
|
|
20
|
+
ChatSession = None
|
|
21
|
+
|
|
22
|
+
from .images import extract_gs_images_and_genai_upload
|
|
19
23
|
|
|
20
24
|
if TYPE_CHECKING:
|
|
21
25
|
from google.generativeai.protos import Part
|
|
26
|
+
from google.generativeai import ChatSession
|
|
27
|
+
|
|
28
|
+
|
|
22
29
|
|
|
23
30
|
class GenAIFunctionProcessor:
|
|
24
31
|
"""
|
|
@@ -365,21 +372,43 @@ class GenAIFunctionProcessor:
|
|
|
365
372
|
log.info(f"Cleaning:\n{string}\n > to >\n{clean}")
|
|
366
373
|
|
|
367
374
|
return clean
|
|
375
|
+
|
|
376
|
+
def convert_composite_to_native(self, value):
|
|
377
|
+
"""
|
|
378
|
+
Recursively converts a proto MapComposite or RepeatedComposite object to native Python types.
|
|
379
|
+
|
|
380
|
+
Args:
|
|
381
|
+
value: The proto object, which could be a MapComposite, RepeatedComposite, or a primitive.
|
|
368
382
|
|
|
369
|
-
|
|
383
|
+
Returns:
|
|
384
|
+
The equivalent Python dictionary, list, or primitive type.
|
|
385
|
+
"""
|
|
386
|
+
if isinstance(value, proto.marshal.collections.maps.MapComposite):
|
|
387
|
+
# Convert MapComposite to a dictionary, recursively processing its values
|
|
388
|
+
return {key: self.convert_composite_to_native(val) for key, val in value.items()}
|
|
389
|
+
elif isinstance(value, proto.marshal.collections.repeated.RepeatedComposite):
|
|
390
|
+
# Convert RepeatedComposite to a list, recursively processing its elements
|
|
391
|
+
return [self.convert_composite_to_native(item) for item in value]
|
|
392
|
+
else:
|
|
393
|
+
# If it's a primitive value, return it as is
|
|
394
|
+
return value
|
|
395
|
+
|
|
396
|
+
def run_agent_loop(self, chat:ChatSession, content:list, callback=None, guardrail_max=10, loop_return=3):
|
|
370
397
|
"""
|
|
371
398
|
Runs the agent loop, sending messages to the orchestrator, processing responses, and executing functions.
|
|
372
399
|
|
|
373
400
|
Args:
|
|
374
401
|
chat: The chat object for interaction with the orchestrator.
|
|
375
402
|
content: The initial content to send to the agent.
|
|
376
|
-
callback: The callback object for handling intermediate responses.
|
|
403
|
+
callback: The callback object for handling intermediate responses. If not supplied will use self.IOCallback()
|
|
377
404
|
guardrail_max (int): The maximum number of iterations for the loop.
|
|
378
405
|
loop_return (int): The number of last loop iterations to return. Default 3 will return last 3 iterations. If loop_return > guardrail_max then all iterations are returned.
|
|
379
406
|
|
|
380
407
|
Returns:
|
|
381
408
|
tuple: (big_text, usage_metadata) from the loop execution.
|
|
382
409
|
"""
|
|
410
|
+
if not callback:
|
|
411
|
+
callback = self.IOCallback()
|
|
383
412
|
guardrail = 0
|
|
384
413
|
big_result = []
|
|
385
414
|
usage_metadata = {
|
|
@@ -482,7 +511,9 @@ class GenAIFunctionProcessor:
|
|
|
482
511
|
fn_result_json = None
|
|
483
512
|
# Convert MapComposite to a standard Python dictionary
|
|
484
513
|
if isinstance(fn_result, proto.marshal.collections.maps.MapComposite):
|
|
485
|
-
fn_result_json =
|
|
514
|
+
fn_result_json = self.convert_composite_to_native(fn_result)
|
|
515
|
+
elif isinstance(fn_result, proto.marshal.collections.repeated.RepeatedComposite):
|
|
516
|
+
fn_result = self.convert_composite_to_native(fn_result)
|
|
486
517
|
elif isinstance(fn_result, dict):
|
|
487
518
|
fn_result_json = fn_result
|
|
488
519
|
elif isinstance(fn_result, str):
|
|
@@ -535,6 +566,13 @@ class GenAIFunctionProcessor:
|
|
|
535
566
|
|
|
536
567
|
if this_text:
|
|
537
568
|
content.append(f"Agent: {this_text}")
|
|
569
|
+
# if text includes gs:// try to download it
|
|
570
|
+
image_uploads = extract_gs_images_and_genai_upload(this_text)
|
|
571
|
+
if image_uploads:
|
|
572
|
+
for img in image_uploads:
|
|
573
|
+
log.info(f"Adding {img=}")
|
|
574
|
+
content.append(img)
|
|
575
|
+
content.append(f"{img.name} was created by agent and added")
|
|
538
576
|
log.info(f"[{guardrail}] Updated content:\n{this_text}")
|
|
539
577
|
big_result.append(this_text)
|
|
540
578
|
else:
|
|
@@ -567,6 +605,15 @@ class GenAIFunctionProcessor:
|
|
|
567
605
|
|
|
568
606
|
return big_text, usage_metadata
|
|
569
607
|
|
|
608
|
+
class IOCallback:
|
|
609
|
+
"""
|
|
610
|
+
This is a default callback that will print to console any tokens it recieves.
|
|
611
|
+
"""
|
|
612
|
+
def on_llm_new_token(self, token:str):
|
|
613
|
+
print(token)
|
|
614
|
+
def on_llm_end(self, response):
|
|
615
|
+
print(f"\nFull response: \n{response}")
|
|
616
|
+
|
|
570
617
|
@staticmethod
|
|
571
618
|
def decide_to_go_on(go_on: bool, chat_summary: str) -> dict:
|
|
572
619
|
"""
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
from ..custom_logging import log
|
|
2
|
+
from ..utils import ConfigManager
|
|
3
|
+
|
|
4
|
+
# Load the YAML file
|
|
5
|
+
def load_prompt_from_yaml(key, prefix="sunholo", load_from_file=False, f_string=True):
|
|
6
|
+
"""
|
|
7
|
+
Returns a string you can use with prompts.
|
|
8
|
+
|
|
9
|
+
If load_from_file=False, by default it will try to load from Langfuse, if fails (which is laggy so not ideal) then load from file.
|
|
10
|
+
|
|
11
|
+
Prompts on Langfuse should be specified with a name with {prefix}-{key} e.g. "sunholo-hello"
|
|
12
|
+
|
|
13
|
+
Prompts in files will use yaml:
|
|
14
|
+
|
|
15
|
+
```yaml
|
|
16
|
+
kind: promptConfig
|
|
17
|
+
apiVersion: v1
|
|
18
|
+
prompts:
|
|
19
|
+
sunholo:
|
|
20
|
+
hello: |
|
|
21
|
+
Say hello to {name}
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
And load via utils.ConfigManager:
|
|
25
|
+
|
|
26
|
+
```python
|
|
27
|
+
# equivalent to load_prompt_from_yaml("hello", load_from_file=True)
|
|
28
|
+
config = ConfigManager("sunholo")
|
|
29
|
+
config.promptConfig("hello")
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
If f_string is True will be in a Langchain style prompt e.g. { one brace }
|
|
33
|
+
If f_string is False will be Langfuse style prompt e.g. {{ two braces }} - see https://langfuse.com/docs/prompts/get-started
|
|
34
|
+
|
|
35
|
+
Example:
|
|
36
|
+
|
|
37
|
+
```python
|
|
38
|
+
from sunholo.langfuse.prompts import load_prompt_from_yaml
|
|
39
|
+
# f_string
|
|
40
|
+
hello_template = load_prompt_from_yaml("hello")
|
|
41
|
+
hello_template.format(name="Bob")
|
|
42
|
+
|
|
43
|
+
#langfuse style
|
|
44
|
+
hello_template = load_prompt_from_yaml("hello", f_string=False)
|
|
45
|
+
hello_template.compile(name="Bob")
|
|
46
|
+
|
|
47
|
+
# if prompt not available on langfuse, will attempt to load from local promptConfig file
|
|
48
|
+
hello_template = load_prompt_from_yaml("hello", load_from_file=True)
|
|
49
|
+
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
"""
|
|
53
|
+
config = ConfigManager(prefix)
|
|
54
|
+
if load_from_file:
|
|
55
|
+
|
|
56
|
+
return config.promptConfig(key)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
from langfuse import Langfuse
|
|
60
|
+
|
|
61
|
+
# Initialize Langfuse client
|
|
62
|
+
langfuse = Langfuse()
|
|
63
|
+
|
|
64
|
+
try:
|
|
65
|
+
if prefix is None:
|
|
66
|
+
langfuse_template = key
|
|
67
|
+
else:
|
|
68
|
+
langfuse_template = f"{prefix}-{key}"
|
|
69
|
+
|
|
70
|
+
langfuse_prompt = langfuse.get_prompt(langfuse_template, cache_ttl_seconds=300)
|
|
71
|
+
|
|
72
|
+
if f_string:
|
|
73
|
+
return langfuse_prompt.get_langchain_prompt()
|
|
74
|
+
|
|
75
|
+
return langfuse_prompt
|
|
76
|
+
|
|
77
|
+
except Exception as err:
|
|
78
|
+
log.warning(f"Could not find langfuse template: {langfuse_template} - {str(err)} - attempting to load from promptConfig")
|
|
79
|
+
|
|
80
|
+
return config.promptConfig(key)
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import os
|
|
2
|
+
|
|
3
|
+
def guess_mime_type(file_path: str) -> str:
|
|
4
|
+
"""
|
|
5
|
+
Guess the mime type based on the file extension.
|
|
6
|
+
|
|
7
|
+
Args:
|
|
8
|
+
file_path (str): The path or URL of the image file.
|
|
9
|
+
|
|
10
|
+
Returns:
|
|
11
|
+
str: The guessed image type (e.g., "jpeg", "png", "gif", etc.)
|
|
12
|
+
or None if the extension is not recognized.
|
|
13
|
+
"""
|
|
14
|
+
# Extract the file extension
|
|
15
|
+
_, ext = os.path.splitext(file_path)
|
|
16
|
+
|
|
17
|
+
# Normalize and remove the leading dot
|
|
18
|
+
ext = ext.lower().strip('.')
|
|
19
|
+
|
|
20
|
+
# Mapping of common file extensions to file types
|
|
21
|
+
extension_to_type = {
|
|
22
|
+
"jpg": "image/jpeg",
|
|
23
|
+
"jpeg": "image/jpeg",
|
|
24
|
+
"png": "image/png",
|
|
25
|
+
"gif": "image/gif",
|
|
26
|
+
"bmp": "image/bmp",
|
|
27
|
+
"tiff": "image/tiff",
|
|
28
|
+
"tif": "image/tiff",
|
|
29
|
+
"webp": "image/webp",
|
|
30
|
+
"ico": "image/vnd.microsoft.icon",
|
|
31
|
+
"svg": "image/svg+xml",
|
|
32
|
+
"pdf": "application/pdf",
|
|
33
|
+
"txt": "text/plain",
|
|
34
|
+
"md": "text/markdown",
|
|
35
|
+
"html": "text/html",
|
|
36
|
+
"css": "text/css",
|
|
37
|
+
"js": "application/javascript",
|
|
38
|
+
"json": "application/json",
|
|
39
|
+
"xml": "application/xml",
|
|
40
|
+
"csv": "text/csv",
|
|
41
|
+
"py": "text/x-python",
|
|
42
|
+
"java": "text/x-java-source",
|
|
43
|
+
"c": "text/x-c",
|
|
44
|
+
"cpp": "text/x-c++",
|
|
45
|
+
"h": "text/x-c",
|
|
46
|
+
"hpp": "text/x-c++",
|
|
47
|
+
"sh": "application/x-sh",
|
|
48
|
+
"bat": "application/x-msdos-program",
|
|
49
|
+
"php": "application/x-httpd-php",
|
|
50
|
+
"rb": "application/x-ruby",
|
|
51
|
+
"pl": "application/x-perl",
|
|
52
|
+
"swift": "application/x-swift",
|
|
53
|
+
"r": "text/x-r",
|
|
54
|
+
"go": "text/x-go",
|
|
55
|
+
"sql": "application/sql",
|
|
56
|
+
"yaml": "text/yaml",
|
|
57
|
+
"yml": "text/yaml",
|
|
58
|
+
"ts": "application/typescript",
|
|
59
|
+
"tsx": "text/tsx",
|
|
60
|
+
"jsx": "text/jsx",
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return extension_to_type.get(ext, "")
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: sunholo
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.101.2
|
|
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.101.2.tar.gz
|
|
7
7
|
Author: Holosun ApS
|
|
8
8
|
Author-email: multivac@sunholo.com
|
|
9
9
|
License: Apache License, Version 2.0
|
|
@@ -94,8 +94,10 @@ sunholo/gcs/__init__.py
|
|
|
94
94
|
sunholo/gcs/add_file.py
|
|
95
95
|
sunholo/gcs/download_folder.py
|
|
96
96
|
sunholo/gcs/download_url.py
|
|
97
|
+
sunholo/gcs/extract_and_sign.py
|
|
97
98
|
sunholo/gcs/metadata.py
|
|
98
99
|
sunholo/genai/__init__.py
|
|
100
|
+
sunholo/genai/images.py
|
|
99
101
|
sunholo/genai/init.py
|
|
100
102
|
sunholo/genai/process_funcs_cls.py
|
|
101
103
|
sunholo/genai/safety.py
|
|
@@ -143,6 +145,7 @@ sunholo/utils/config_class.py
|
|
|
143
145
|
sunholo/utils/config_schema.py
|
|
144
146
|
sunholo/utils/gcp.py
|
|
145
147
|
sunholo/utils/gcp_project.py
|
|
148
|
+
sunholo/utils/mime.py
|
|
146
149
|
sunholo/utils/parsers.py
|
|
147
150
|
sunholo/utils/timedelta.py
|
|
148
151
|
sunholo/utils/user_ids.py
|
|
@@ -155,5 +158,6 @@ sunholo/vertex/init.py
|
|
|
155
158
|
sunholo/vertex/memory_tools.py
|
|
156
159
|
sunholo/vertex/safety.py
|
|
157
160
|
sunholo/vertex/type_dict_to_json.py
|
|
161
|
+
tests/test_async.py
|
|
158
162
|
tests/test_chat_history.py
|
|
159
163
|
tests/test_config.py
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
from sunholo.invoke import AsyncTaskRunner
|
|
3
|
+
# Mock logger for demonstration
|
|
4
|
+
import logging
|
|
5
|
+
logging.basicConfig(level=logging.INFO)
|
|
6
|
+
log = logging.getLogger(__name__)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
# Dummy task functions for testing
|
|
10
|
+
async def google_search(query, config_manager):
|
|
11
|
+
await asyncio.sleep(5) # Simulate a long-running task
|
|
12
|
+
return f"Results for '{query}'"
|
|
13
|
+
|
|
14
|
+
async def use_pdfs(query, arg2, arg3):
|
|
15
|
+
await asyncio.sleep(2) # Simulate a medium-running task
|
|
16
|
+
return "No image_uri specified\n"
|
|
17
|
+
|
|
18
|
+
async def process_urls(url):
|
|
19
|
+
await asyncio.sleep(1) # Simulate a short-running task
|
|
20
|
+
return "No URLs were found"
|
|
21
|
+
|
|
22
|
+
# Mock callback for demonstration
|
|
23
|
+
class MockCallback:
|
|
24
|
+
async def async_on_llm_new_token(self, token):
|
|
25
|
+
log.info(f"Callback received token: {token}")
|
|
26
|
+
|
|
27
|
+
# Mock functions for demonstration
|
|
28
|
+
def format_token_output(func_name, tokens, result=None, error=None):
|
|
29
|
+
if error:
|
|
30
|
+
return f"Error in {func_name}: {error}"
|
|
31
|
+
return f"{func_name} completed with {tokens} tokens. Result: {result}"
|
|
32
|
+
|
|
33
|
+
async def count_tokens(result):
|
|
34
|
+
return len(result.split())
|
|
35
|
+
|
|
36
|
+
# Example usage
|
|
37
|
+
async def main():
|
|
38
|
+
runner = AsyncTaskRunner(retry_enabled=True)
|
|
39
|
+
|
|
40
|
+
# Add your tasks
|
|
41
|
+
runner.add_task(google_search, "<original user question>...", "<config>")
|
|
42
|
+
runner.add_task(use_pdfs, "<original user question>...", None, None)
|
|
43
|
+
runner.add_task(process_urls, "please give me a forecast of ppas for spain using wind energy")
|
|
44
|
+
|
|
45
|
+
callback = MockCallback()
|
|
46
|
+
answers = {}
|
|
47
|
+
total_context_tokens = 0
|
|
48
|
+
|
|
49
|
+
async for message in runner.run_async_as_completed():
|
|
50
|
+
log.info(f"Runner message={message}")
|
|
51
|
+
if message['type'] == 'heartbeat':
|
|
52
|
+
func_name = message['name']
|
|
53
|
+
elapsed_time = message['elapsed_time']
|
|
54
|
+
log.info(f"Runner Heartbeat for {func_name}, elapsed_time={elapsed_time}")
|
|
55
|
+
# Send heartbeat to callback
|
|
56
|
+
update_html = (
|
|
57
|
+
f'<div style="display: none;" data-update-id="{func_name}-spinner">'
|
|
58
|
+
f'<span class="elapsed-time">{elapsed_time} seconds elapsed</span>'
|
|
59
|
+
f'</div>'
|
|
60
|
+
)
|
|
61
|
+
await callback.async_on_llm_new_token(token=f"[[HEARTBEAT]]{update_html}[[/HEARTBEAT]]")
|
|
62
|
+
elif message['type'] == 'task_complete':
|
|
63
|
+
func_name = message['func_name']
|
|
64
|
+
result = message['result']
|
|
65
|
+
log.info(f"Runner completed task: {func_name}")
|
|
66
|
+
# Process result
|
|
67
|
+
if isinstance(result, Exception):
|
|
68
|
+
log.info(f"Error Exception for {func_name}: {str(result)}")
|
|
69
|
+
formatted_output = format_token_output(func_name, 0, error="No results")
|
|
70
|
+
await callback.async_on_llm_new_token(token=formatted_output)
|
|
71
|
+
else:
|
|
72
|
+
# Stream the result to the callback
|
|
73
|
+
tokens = await count_tokens(result)
|
|
74
|
+
total_context_tokens += tokens
|
|
75
|
+
log.info(f"Got task {func_name} to stream result length [{len(result)}] [{tokens} tokens]")
|
|
76
|
+
formatted_output = format_token_output(func_name, tokens, result=result)
|
|
77
|
+
await callback.async_on_llm_new_token(token=formatted_output)
|
|
78
|
+
answers[func_name] = result
|
|
79
|
+
elif message['type'] == 'task_error':
|
|
80
|
+
func_name = message['func_name']
|
|
81
|
+
error = message['error']
|
|
82
|
+
log.info(f"Error Exception for {func_name}: {str(error)}")
|
|
83
|
+
formatted_output = format_token_output(func_name, 0, error="No results")
|
|
84
|
+
await callback.async_on_llm_new_token(token=formatted_output)
|
|
85
|
+
|
|
86
|
+
await callback.async_on_llm_new_token(
|
|
87
|
+
token=f'<div style="margin-top: 20px; color: #333;"><strong>-- Using [{total_context_tokens}] tokens in context for final answer --</strong></div>'
|
|
88
|
+
)
|
|
89
|
+
log.info("All tasks have been processed.")
|
|
90
|
+
|
|
91
|
+
# Run the main coroutine
|
|
92
|
+
if __name__ == "__main__":
|
|
93
|
+
asyncio.run(main())
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
from ..custom_logging import log
|
|
2
|
-
from ..utils import ConfigManager
|
|
3
|
-
|
|
4
|
-
# Load the YAML file
|
|
5
|
-
def load_prompt_from_yaml(key, prefix="sunholo", load_from_file=False):
|
|
6
|
-
"""
|
|
7
|
-
Returns a string you can use with Langfuse PromptTemplate.from_template()
|
|
8
|
-
|
|
9
|
-
Will first try to load from the Langfuse prompt library, if unavailable will look in promptConfig type file.
|
|
10
|
-
|
|
11
|
-
Langfuse prompts have {{ two braces }}, Langchain prompts have { one brace }.
|
|
12
|
-
|
|
13
|
-
Example:
|
|
14
|
-
|
|
15
|
-
```python
|
|
16
|
-
from sunholo.langfuse.prompts import load_prompt_from_yaml
|
|
17
|
-
from langchain_core.prompts import PromptTemplate
|
|
18
|
-
|
|
19
|
-
"""
|
|
20
|
-
config = ConfigManager(prefix)
|
|
21
|
-
if load_from_file:
|
|
22
|
-
|
|
23
|
-
return config.promptConfig(key)
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
from langfuse import Langfuse
|
|
27
|
-
|
|
28
|
-
# Initialize Langfuse client
|
|
29
|
-
langfuse = Langfuse()
|
|
30
|
-
|
|
31
|
-
try:
|
|
32
|
-
if prefix is None:
|
|
33
|
-
langfuse_template = key
|
|
34
|
-
else:
|
|
35
|
-
langfuse_template = f"{prefix}-{key}"
|
|
36
|
-
|
|
37
|
-
langfuse_prompt = langfuse.get_prompt(langfuse_template, cache_ttl_seconds=300)
|
|
38
|
-
|
|
39
|
-
return langfuse_prompt.get_langchain_prompt()
|
|
40
|
-
|
|
41
|
-
except Exception as err:
|
|
42
|
-
log.warning(f"Could not find langfuse template: {langfuse_template} - {str(err)} - attempting to load from promptConfig")
|
|
43
|
-
|
|
44
|
-
return config.promptConfig(key)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|