sunholo 0.96.3__tar.gz → 0.96.5__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 (161) hide show
  1. {sunholo-0.96.3 → sunholo-0.96.5}/PKG-INFO +2 -2
  2. {sunholo-0.96.3 → sunholo-0.96.5}/setup.py +1 -1
  3. sunholo-0.96.5/sunholo/invoke/direct_vac_func.py +279 -0
  4. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo.egg-info/PKG-INFO +2 -2
  5. sunholo-0.96.3/sunholo/invoke/direct_vac_func.py +0 -123
  6. {sunholo-0.96.3 → sunholo-0.96.5}/LICENSE.txt +0 -0
  7. {sunholo-0.96.3 → sunholo-0.96.5}/MANIFEST.in +0 -0
  8. {sunholo-0.96.3 → sunholo-0.96.5}/README.md +0 -0
  9. {sunholo-0.96.3 → sunholo-0.96.5}/setup.cfg +0 -0
  10. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/__init__.py +0 -0
  11. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/agents/__init__.py +0 -0
  12. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/agents/chat_history.py +0 -0
  13. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/agents/dispatch_to_qa.py +0 -0
  14. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/agents/fastapi/__init__.py +0 -0
  15. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/agents/fastapi/base.py +0 -0
  16. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/agents/fastapi/qna_routes.py +0 -0
  17. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/agents/flask/__init__.py +0 -0
  18. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/agents/flask/base.py +0 -0
  19. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/agents/flask/qna_routes.py +0 -0
  20. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/agents/flask/vac_routes.py +0 -0
  21. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/agents/langserve.py +0 -0
  22. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/agents/pubsub.py +0 -0
  23. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/agents/route.py +0 -0
  24. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/agents/special_commands.py +0 -0
  25. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/agents/swagger.py +0 -0
  26. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/archive/__init__.py +0 -0
  27. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/archive/archive.py +0 -0
  28. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/auth/__init__.py +0 -0
  29. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/auth/gcloud.py +0 -0
  30. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/auth/refresh.py +0 -0
  31. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/auth/run.py +0 -0
  32. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/azure/__init__.py +0 -0
  33. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/azure/auth.py +0 -0
  34. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/azure/blobs.py +0 -0
  35. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/azure/event_grid.py +0 -0
  36. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/bots/__init__.py +0 -0
  37. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/bots/discord.py +0 -0
  38. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/bots/github_webhook.py +0 -0
  39. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/bots/webapp.py +0 -0
  40. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/chunker/__init__.py +0 -0
  41. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/chunker/azure.py +0 -0
  42. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/chunker/doc_handling.py +0 -0
  43. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/chunker/encode_metadata.py +0 -0
  44. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/chunker/images.py +0 -0
  45. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/chunker/loaders.py +0 -0
  46. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/chunker/message_data.py +0 -0
  47. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/chunker/pdfs.py +0 -0
  48. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/chunker/process_chunker_data.py +0 -0
  49. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/chunker/publish.py +0 -0
  50. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/chunker/pubsub.py +0 -0
  51. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/chunker/splitter.py +0 -0
  52. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/cli/__init__.py +0 -0
  53. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/cli/chat_vac.py +0 -0
  54. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/cli/cli.py +0 -0
  55. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/cli/cli_init.py +0 -0
  56. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/cli/configs.py +0 -0
  57. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/cli/deploy.py +0 -0
  58. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/cli/embedder.py +0 -0
  59. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/cli/merge_texts.py +0 -0
  60. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/cli/run_proxy.py +0 -0
  61. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/cli/sun_rich.py +0 -0
  62. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/cli/swagger.py +0 -0
  63. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/cli/vertex.py +0 -0
  64. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/components/__init__.py +0 -0
  65. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/components/llm.py +0 -0
  66. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/components/retriever.py +0 -0
  67. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/components/vectorstore.py +0 -0
  68. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/custom_logging.py +0 -0
  69. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/database/__init__.py +0 -0
  70. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/database/alloydb.py +0 -0
  71. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/database/alloydb_client.py +0 -0
  72. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/database/database.py +0 -0
  73. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/database/lancedb.py +0 -0
  74. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/database/sql/sb/create_function.sql +0 -0
  75. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/database/sql/sb/create_function_time.sql +0 -0
  76. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/database/sql/sb/create_table.sql +0 -0
  77. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/database/sql/sb/delete_source_row.sql +0 -0
  78. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/database/sql/sb/return_sources.sql +0 -0
  79. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/database/sql/sb/setup.sql +0 -0
  80. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/database/static_dbs.py +0 -0
  81. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/database/uuid.py +0 -0
  82. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/discovery_engine/__init__.py +0 -0
  83. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/discovery_engine/chunker_handler.py +0 -0
  84. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/discovery_engine/create_new.py +0 -0
  85. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/discovery_engine/discovery_engine_client.py +0 -0
  86. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/discovery_engine/get_ai_search_chunks.py +0 -0
  87. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/embedder/__init__.py +0 -0
  88. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/embedder/embed_chunk.py +0 -0
  89. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/excel/__init__.py +0 -0
  90. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/excel/plugin.py +0 -0
  91. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/gcs/__init__.py +0 -0
  92. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/gcs/add_file.py +0 -0
  93. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/gcs/download_folder.py +0 -0
  94. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/gcs/download_url.py +0 -0
  95. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/gcs/metadata.py +0 -0
  96. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/genai/__init__.py +0 -0
  97. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/genai/init.py +0 -0
  98. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/genai/process_funcs_cls.py +0 -0
  99. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/genai/safety.py +0 -0
  100. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/invoke/__init__.py +0 -0
  101. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/invoke/async_class.py +0 -0
  102. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/invoke/invoke_vac_utils.py +0 -0
  103. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/langfuse/__init__.py +0 -0
  104. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/langfuse/callback.py +0 -0
  105. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/langfuse/evals.py +0 -0
  106. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/langfuse/prompts.py +0 -0
  107. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/llamaindex/__init__.py +0 -0
  108. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/llamaindex/get_files.py +0 -0
  109. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/llamaindex/import_files.py +0 -0
  110. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/llamaindex/llamaindex_class.py +0 -0
  111. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/llamaindex/user_history.py +0 -0
  112. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/lookup/__init__.py +0 -0
  113. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/lookup/model_lookup.yaml +0 -0
  114. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/patches/__init__.py +0 -0
  115. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/patches/langchain/__init__.py +0 -0
  116. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/patches/langchain/lancedb.py +0 -0
  117. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/patches/langchain/vertexai.py +0 -0
  118. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/pubsub/__init__.py +0 -0
  119. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/pubsub/process_pubsub.py +0 -0
  120. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/pubsub/pubsub_manager.py +0 -0
  121. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/qna/__init__.py +0 -0
  122. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/qna/parsers.py +0 -0
  123. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/qna/retry.py +0 -0
  124. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/streaming/__init__.py +0 -0
  125. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/streaming/content_buffer.py +0 -0
  126. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/streaming/langserve.py +0 -0
  127. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/streaming/stream_lookup.py +0 -0
  128. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/streaming/streaming.py +0 -0
  129. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/summarise/__init__.py +0 -0
  130. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/summarise/summarise.py +0 -0
  131. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/terraform/__init__.py +0 -0
  132. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/terraform/tfvars_editor.py +0 -0
  133. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/tools/__init__.py +0 -0
  134. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/tools/web_browser.py +0 -0
  135. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/utils/__init__.py +0 -0
  136. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/utils/api_key.py +0 -0
  137. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/utils/big_context.py +0 -0
  138. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/utils/config.py +0 -0
  139. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/utils/config_class.py +0 -0
  140. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/utils/config_schema.py +0 -0
  141. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/utils/gcp.py +0 -0
  142. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/utils/gcp_project.py +0 -0
  143. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/utils/parsers.py +0 -0
  144. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/utils/timedelta.py +0 -0
  145. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/utils/user_ids.py +0 -0
  146. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/utils/version.py +0 -0
  147. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/vertex/__init__.py +0 -0
  148. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/vertex/extensions_call.py +0 -0
  149. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/vertex/extensions_class.py +0 -0
  150. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/vertex/genai_functions.py +0 -0
  151. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/vertex/init.py +0 -0
  152. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/vertex/memory_tools.py +0 -0
  153. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/vertex/safety.py +0 -0
  154. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo/vertex/type_dict_to_json.py +0 -0
  155. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo.egg-info/SOURCES.txt +0 -0
  156. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo.egg-info/dependency_links.txt +0 -0
  157. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo.egg-info/entry_points.txt +0 -0
  158. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo.egg-info/requires.txt +0 -0
  159. {sunholo-0.96.3 → sunholo-0.96.5}/sunholo.egg-info/top_level.txt +0 -0
  160. {sunholo-0.96.3 → sunholo-0.96.5}/tests/test_chat_history.py +0 -0
  161. {sunholo-0.96.3 → sunholo-0.96.5}/tests/test_config.py +0 -0
@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: sunholo
3
- Version: 0.96.3
3
+ Version: 0.96.5
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.96.3.tar.gz
6
+ Download-URL: https://github.com/sunholo-data/sunholo-py/archive/refs/tags/v0.96.5.tar.gz
7
7
  Author: Holosun ApS
8
8
  Author-email: multivac@sunholo.com
9
9
  License: Apache License, Version 2.0
@@ -1,6 +1,6 @@
1
1
  from setuptools import setup, find_packages
2
2
 
3
- version = '0.96.3'
3
+ version = '0.96.5'
4
4
 
5
5
  setup(
6
6
  name='sunholo',
@@ -0,0 +1,279 @@
1
+ from ..custom_logging import log
2
+ from ..agents import send_to_qa, send_to_qa_async
3
+ from ..qna.parsers import parse_output
4
+ from ..streaming import generate_proxy_stream
5
+ from ..utils import ConfigManager
6
+ from ..utils.api_key import has_multivac_api_key
7
+ import asyncio
8
+ from threading import Thread
9
+
10
+ def direct_vac(vac_input: dict, vac_name: str, chat_history=[]):
11
+ """
12
+ This lets VACs call other VAC Q&A endpoints within their code
13
+ """
14
+
15
+ log.info(f"Invoking VAC Q&A endpoints for {vac_name}")
16
+
17
+ if 'user_input' not in vac_input:
18
+ raise ValueError(f'vac_input must contain at least "user_input" key - got {vac_input}')
19
+
20
+ global_config = ConfigManager('global')
21
+ config = ConfigManager(vac_name)
22
+
23
+ agent_name = config.vacConfig('agent')
24
+ agent_url = config.vacConfig("agent_url")
25
+
26
+ if agent_url:
27
+ log.info("Found agent_url within vacConfig: {agent_url}")
28
+ # via public cloud endpoints - assumes no gcloud auth
29
+ override_endpoint = None
30
+ if has_multivac_api_key():
31
+ print("Found MULTIVAC_API_KEY")
32
+ gcp_config = global_config.vacConfig("gcp_config")
33
+ endpoints_base_url = gcp_config.get("endpoints_base_url")
34
+ if not endpoints_base_url:
35
+ raise ValueError("MULTIVAC_API_KEY env var is set but no config.gcp_config.endpoints_base_url can be found")
36
+
37
+ override_endpoint = f"{endpoints_base_url}/v1/{agent_name}"
38
+
39
+ override_endpoint = agent_url or override_endpoint
40
+
41
+ print(f"Using {override_endpoint=}")
42
+
43
+ # Prepare the kwargs for send_to_qa by copying vac_input and adding more values
44
+ qa_kwargs = vac_input.copy()
45
+
46
+ # Add additional arguments
47
+ qa_kwargs.update({
48
+ 'vector_name': vac_name,
49
+ 'chat_history': chat_history,
50
+ 'image_url': vac_input.get('image_url') or vac_input.get('image_uri'),
51
+ 'override_endpoint': override_endpoint,
52
+ 'message_source': "sunholo.invoke_vac_qa.invoke",
53
+ 'stream': False,
54
+ 'configurable': {
55
+ "vector_name": vac_name,
56
+ },
57
+ })
58
+
59
+ log.info(f'Batch invoke_vac_qa {vac_name} with {qa_kwargs=}')
60
+
61
+ vac_response = send_to_qa(**qa_kwargs)
62
+
63
+ # ensures {'answer': answer}
64
+ answer = parse_output(vac_response)
65
+ chat_history.append({"name": "Human", "content": vac_input})
66
+ chat_history.append({"name": "AI", "content": answer})
67
+ answer["chat_history"] = chat_history
68
+
69
+ return answer
70
+
71
+ async def async_direct_vac(vac_input: dict, vac_name: str, chat_history=[]):
72
+ """
73
+ Asynchronous version of direct_vac using send_to_qa_async.
74
+ Allows VACs to call other VAC Q&A endpoints without blocking the event loop.
75
+ """
76
+ log.info(f"Invoking VAC Q&A endpoints for {vac_name}")
77
+
78
+ if 'user_input' not in vac_input:
79
+ raise ValueError(f'vac_input must contain at least "user_input" key - got {vac_input}')
80
+
81
+ global_config = ConfigManager('global')
82
+ config = ConfigManager(vac_name)
83
+
84
+ agent_name = config.vacConfig('agent')
85
+ agent_url = config.vacConfig("agent_url")
86
+
87
+ if agent_url:
88
+ log.info(f"Found agent_url within vacConfig: {agent_url}")
89
+
90
+ # Via public cloud endpoints - assumes no gcloud auth
91
+ override_endpoint = None
92
+ if has_multivac_api_key():
93
+ print("Found MULTIVAC_API_KEY")
94
+ gcp_config = global_config.vacConfig("gcp_config")
95
+ endpoints_base_url = gcp_config.get("endpoints_base_url")
96
+ if not endpoints_base_url:
97
+ raise ValueError("MULTIVAC_API_KEY env var is set but no config.gcp_config.endpoints_base_url can be found")
98
+
99
+ override_endpoint = f"{endpoints_base_url}/v1/{agent_name}"
100
+
101
+ override_endpoint = agent_url or override_endpoint
102
+
103
+ print(f"Using override_endpoint={override_endpoint}")
104
+
105
+ # Prepare the kwargs for send_to_qa_async by copying vac_input and adding more values
106
+ qa_kwargs = vac_input.copy()
107
+
108
+ # Add additional arguments
109
+ qa_kwargs.update({
110
+ 'vector_name': vac_name,
111
+ 'chat_history': chat_history,
112
+ 'image_url': vac_input.get('image_url') or vac_input.get('image_uri'),
113
+ 'override_endpoint': override_endpoint,
114
+ 'message_source': "sunholo.invoke_vac_qa.invoke",
115
+ 'stream': False,
116
+ 'configurable': {
117
+ "vector_name": vac_name,
118
+ },
119
+ })
120
+
121
+ log.info(f'Batch invoke_vac_qa {vac_name} with qa_kwargs={qa_kwargs}')
122
+
123
+ # Call send_to_qa_async directly
124
+ vac_response_generator = send_to_qa_async(**qa_kwargs)
125
+
126
+ # Since send_to_qa_async returns an async generator, we can get the response
127
+ vac_response = None
128
+ async for response in vac_response_generator:
129
+ vac_response = response # Since stream=False, we expect only one response
130
+ break
131
+
132
+ # Call parse_output synchronously (since it's non-blocking)
133
+ answer = parse_output(vac_response)
134
+
135
+ chat_history.append({"name": "Human", "content": vac_input})
136
+ chat_history.append({"name": "AI", "content": answer})
137
+ answer["chat_history"] = chat_history
138
+
139
+ return answer
140
+
141
+ def direct_vac_stream(vac_input: dict, vac_name: str, chat_history=[]):
142
+
143
+ if 'user_input' not in vac_input:
144
+ raise ValueError('vac_input must contain at least "user_input" key - got {vac_input}')
145
+
146
+ user_id = vac_input.get('user_id')
147
+ session_id = vac_input.get('session_id')
148
+ image_uri = vac_input.get('image_url') or vac_input.get('image_uri')
149
+
150
+ log.info(f"Streaming invoke_vac_qa with {vac_input=}")
151
+ def stream_response():
152
+ generate = generate_proxy_stream(
153
+ send_to_qa,
154
+ vac_input["user_input"],
155
+ vector_name=vac_name,
156
+ chat_history=chat_history,
157
+ generate_f_output=lambda x: x, # Replace with actual processing function
158
+ stream_wait_time=0.5,
159
+ stream_timeout=120,
160
+ message_author=user_id,
161
+ #TODO: populate these
162
+ image_url=image_uri,
163
+ source_filters=None,
164
+ search_kwargs=None,
165
+ private_docs=None,
166
+ whole_document=False,
167
+ source_filters_and_or=False,
168
+ # system kwargs
169
+ configurable={
170
+ "vector_name": vac_name,
171
+ },
172
+ user_id=user_id,
173
+ session_id=session_id,
174
+ message_source="sunholo.invoke_vac_qa.stream"
175
+ )
176
+ for part in generate():
177
+ yield part
178
+
179
+ answer = ""
180
+
181
+ for token in stream_response():
182
+ if isinstance(token, bytes):
183
+ token = token.decode('utf-8')
184
+ yield token
185
+ if isinstance(token, dict):
186
+ # ?
187
+ pass
188
+ elif isinstance(token, str):
189
+ answer += token
190
+
191
+ if answer:
192
+ chat_history.append({"name": "Human", "content": vac_input})
193
+ chat_history.append({"name": "AI", "content": answer})
194
+
195
+ return chat_history
196
+
197
+
198
+
199
+ async def async_direct_vac_stream(vac_input: dict, vac_name: str, chat_history=[]):
200
+ """
201
+ Asynchronous version of direct_vac_stream.
202
+ Streams responses from VAC Q&A endpoints without blocking the event loop.
203
+ """
204
+ if 'user_input' not in vac_input:
205
+ raise ValueError(f'vac_input must contain at least "user_input" key - got {vac_input}')
206
+
207
+ user_id = vac_input.get('user_id')
208
+ session_id = vac_input.get('session_id')
209
+ image_uri = vac_input.get('image_url') or vac_input.get('image_uri')
210
+
211
+ log.info(f"Streaming invoke_vac_qa with vac_input={vac_input}")
212
+
213
+ def sync_stream_response():
214
+ generate = generate_proxy_stream(
215
+ send_to_qa,
216
+ vac_input["user_input"],
217
+ vector_name=vac_name,
218
+ chat_history=chat_history,
219
+ generate_f_output=lambda x: x, # Replace with actual processing function
220
+ stream_wait_time=0.5,
221
+ stream_timeout=120,
222
+ message_author=user_id,
223
+ # TODO: populate these
224
+ image_url=image_uri,
225
+ source_filters=None,
226
+ search_kwargs=None,
227
+ private_docs=None,
228
+ whole_document=False,
229
+ source_filters_and_or=False,
230
+ # system kwargs
231
+ configurable={
232
+ "vector_name": vac_name,
233
+ },
234
+ user_id=user_id,
235
+ session_id=session_id,
236
+ message_source="sunholo.invoke_vac_qa.stream"
237
+ )
238
+ for part in generate():
239
+ yield part
240
+
241
+ async def async_stream_response():
242
+ loop = asyncio.get_event_loop()
243
+ queue = asyncio.Queue()
244
+
245
+ def run_sync_gen():
246
+ try:
247
+ for item in sync_stream_response():
248
+ loop.call_soon_threadsafe(queue.put_nowait, item)
249
+ finally:
250
+ loop.call_soon_threadsafe(queue.put_nowait, None) # Sentinel
251
+
252
+ thread = Thread(target=run_sync_gen)
253
+ thread.start()
254
+
255
+ while True:
256
+ item = await queue.get()
257
+ if item is None:
258
+ break
259
+ yield item
260
+
261
+ thread.join()
262
+
263
+ answer = ""
264
+
265
+ async for token in async_stream_response():
266
+ if isinstance(token, bytes):
267
+ token = token.decode('utf-8')
268
+ yield token
269
+ if isinstance(token, dict):
270
+ # Process dict token if necessary
271
+ pass
272
+ elif isinstance(token, str):
273
+ answer += token
274
+
275
+ if answer:
276
+ chat_history.append({"name": "Human", "content": vac_input})
277
+ chat_history.append({"name": "AI", "content": answer})
278
+
279
+ yield chat_history
@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: sunholo
3
- Version: 0.96.3
3
+ Version: 0.96.5
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.96.3.tar.gz
6
+ Download-URL: https://github.com/sunholo-data/sunholo-py/archive/refs/tags/v0.96.5.tar.gz
7
7
  Author: Holosun ApS
8
8
  Author-email: multivac@sunholo.com
9
9
  License: Apache License, Version 2.0
@@ -1,123 +0,0 @@
1
- from ..custom_logging import log
2
- from ..agents import send_to_qa
3
- from ..qna.parsers import parse_output
4
- from ..streaming import generate_proxy_stream
5
- from ..utils import ConfigManager
6
- from ..utils.api_key import has_multivac_api_key
7
-
8
- def direct_vac(vac_input: dict, vac_name: str, chat_history=[]):
9
- """
10
- This lets VACs call other VAC Q&A endpoints within their code
11
- """
12
-
13
- log.info(f"Invoking VAC Q&A endpoints for {vac_name}")
14
-
15
- if 'user_input' not in vac_input:
16
- raise ValueError(f'vac_input must contain at least "user_input" key - got {vac_input}')
17
-
18
- global_config = ConfigManager('global')
19
- config = ConfigManager(vac_name)
20
-
21
- agent_name = config.vacConfig('agent')
22
- agent_url = config.vacConfig("agent_url")
23
-
24
- if agent_url:
25
- log.info("Found agent_url within vacConfig: {agent_url}")
26
- # via public cloud endpoints - assumes no gcloud auth
27
- override_endpoint = None
28
- if has_multivac_api_key():
29
- print("Found MULTIVAC_API_KEY")
30
- gcp_config = global_config.vacConfig("gcp_config")
31
- endpoints_base_url = gcp_config.get("endpoints_base_url")
32
- if not endpoints_base_url:
33
- raise ValueError("MULTIVAC_API_KEY env var is set but no config.gcp_config.endpoints_base_url can be found")
34
-
35
- override_endpoint = f"{endpoints_base_url}/v1/{agent_name}"
36
-
37
- override_endpoint = agent_url or override_endpoint
38
-
39
- print(f"Using {override_endpoint=}")
40
-
41
- # Prepare the kwargs for send_to_qa by copying vac_input and adding more values
42
- qa_kwargs = vac_input.copy()
43
-
44
- # Add additional arguments
45
- qa_kwargs.update({
46
- 'vector_name': vac_name,
47
- 'chat_history': chat_history,
48
- 'image_url': vac_input.get('image_url') or vac_input.get('image_uri'),
49
- 'override_endpoint': override_endpoint,
50
- 'message_source': "sunholo.invoke_vac_qa.invoke",
51
- 'stream': False,
52
- 'configurable': {
53
- "vector_name": vac_name,
54
- },
55
- })
56
-
57
- log.info(f'Batch invoke_vac_qa {vac_name} with {qa_kwargs=}')
58
-
59
- vac_response = send_to_qa(**qa_kwargs)
60
-
61
- # ensures {'answer': answer}
62
- answer = parse_output(vac_response)
63
- chat_history.append({"name": "Human", "content": vac_input})
64
- chat_history.append({"name": "AI", "content": answer})
65
- answer["chat_history"] = chat_history
66
-
67
- return answer
68
-
69
- def direct_vac_stream(vac_input: dict, vac_name: str, chat_history=[]):
70
-
71
- if 'user_input' not in vac_input:
72
- raise ValueError('vac_input must contain at least "user_input" key - got {vac_input}')
73
-
74
- user_id = vac_input.get('user_id')
75
- session_id = vac_input.get('session_id')
76
- image_uri = vac_input.get('image_url') or vac_input.get('image_uri')
77
-
78
- log.info(f"Streaming invoke_vac_qa with {vac_input=}")
79
- def stream_response():
80
- generate = generate_proxy_stream(
81
- send_to_qa,
82
- vac_input["user_input"],
83
- vector_name=vac_name,
84
- chat_history=chat_history,
85
- generate_f_output=lambda x: x, # Replace with actual processing function
86
- stream_wait_time=0.5,
87
- stream_timeout=120,
88
- message_author=user_id,
89
- #TODO: populate these
90
- image_url=image_uri,
91
- source_filters=None,
92
- search_kwargs=None,
93
- private_docs=None,
94
- whole_document=False,
95
- source_filters_and_or=False,
96
- # system kwargs
97
- configurable={
98
- "vector_name": vac_name,
99
- },
100
- user_id=user_id,
101
- session_id=session_id,
102
- message_source="sunholo.invoke_vac_qa.stream"
103
- )
104
- for part in generate():
105
- yield part
106
-
107
- answer = ""
108
-
109
- for token in stream_response():
110
- if isinstance(token, bytes):
111
- token = token.decode('utf-8')
112
- yield token
113
- if isinstance(token, dict):
114
- # ?
115
- pass
116
- elif isinstance(token, str):
117
- answer += token
118
-
119
- if answer:
120
- chat_history.append({"name": "Human", "content": vac_input})
121
- chat_history.append({"name": "AI", "content": answer})
122
-
123
- return chat_history
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes