sunholo 0.96.2__py3-none-any.whl → 0.96.5__py3-none-any.whl

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.
@@ -280,7 +280,7 @@ class AlloyDBClient:
280
280
  query = f"""
281
281
  SELECT page_content, source, langchain_metadata, images_gsurls, doc_id::text as doc_id
282
282
  FROM "{table_name}"
283
- WHERE source = '{source}'
283
+ WHERE source ILIKE '%{source}%'
284
284
  LIMIT 500;
285
285
  """
286
286
 
@@ -1,9 +1,11 @@
1
1
  from ..custom_logging import log
2
- from ..agents import send_to_qa
2
+ from ..agents import send_to_qa, send_to_qa_async
3
3
  from ..qna.parsers import parse_output
4
4
  from ..streaming import generate_proxy_stream
5
5
  from ..utils import ConfigManager
6
6
  from ..utils.api_key import has_multivac_api_key
7
+ import asyncio
8
+ from threading import Thread
7
9
 
8
10
  def direct_vac(vac_input: dict, vac_name: str, chat_history=[]):
9
11
  """
@@ -66,6 +68,76 @@ def direct_vac(vac_input: dict, vac_name: str, chat_history=[]):
66
68
 
67
69
  return answer
68
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
+
69
141
  def direct_vac_stream(vac_input: dict, vac_name: str, chat_history=[]):
70
142
 
71
143
  if 'user_input' not in vac_input:
@@ -120,4 +192,88 @@ def direct_vac_stream(vac_input: dict, vac_name: str, chat_history=[]):
120
192
  chat_history.append({"name": "Human", "content": vac_input})
121
193
  chat_history.append({"name": "AI", "content": answer})
122
194
 
123
- return chat_history
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.2
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.2.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
@@ -59,7 +59,7 @@ sunholo/components/retriever.py,sha256=bKIVT7_18Ut3OJd0E0jyiISPnD9qkHWVjcQPT4i1_
59
59
  sunholo/components/vectorstore.py,sha256=xKk7micTRwZckaI7U6PxvFz_ZSjCH48xPTDYiDcv2tc,5913
60
60
  sunholo/database/__init__.py,sha256=bpB5Nk21kwqYj-qdVnvNgXjLsbflnH4g-San7OHMqR4,283
61
61
  sunholo/database/alloydb.py,sha256=YH8wNPS8gN-TDZEXQcVHxwd1NScHRfAxma3gK4R6KCk,11740
62
- sunholo/database/alloydb_client.py,sha256=pD3aVT_UWEtcT8Ma1glyj6QEWHRqbNKJNKe3oau_0HA,18304
62
+ sunholo/database/alloydb_client.py,sha256=bvQzvnLEYGrmOgTBx7QjgIn_-4N4aN8JNRUNOLNSRc8,18310
63
63
  sunholo/database/database.py,sha256=VqhZdkXUNdvWn8sUcUV3YNby1JDVf7IykPVXWBtxo9U,7361
64
64
  sunholo/database/lancedb.py,sha256=DyfZntiFKBlVPaFooNN1Z6Pl-LAs4nxWKKuq8GBqN58,715
65
65
  sunholo/database/static_dbs.py,sha256=8cvcMwUK6c32AS2e_WguKXWMkFf5iN3g9WHzsh0C07Q,442
@@ -90,7 +90,7 @@ sunholo/genai/process_funcs_cls.py,sha256=M6vE_-Mi8v1Od8iny3h9-pRA5KbO5n4hiJKr1y
90
90
  sunholo/genai/safety.py,sha256=mkFDO_BeEgiKjQd9o2I4UxB6XI7a9U-oOFjZ8LGRUC4,1238
91
91
  sunholo/invoke/__init__.py,sha256=VOpsfhNf98az3at7bMaY1Fiw4UIZAS6zMmSqWd6_ksI,141
92
92
  sunholo/invoke/async_class.py,sha256=uvCP8ekUCfTRWk7xwofTzRqFykMAwrRZ4Ce_YUR6PVs,2820
93
- sunholo/invoke/direct_vac_func.py,sha256=fuTJlH5PsqWhN_yVMaWisHCTZU1JEUz8I8yVbWsNUFE,4268
93
+ sunholo/invoke/direct_vac_func.py,sha256=GXSCMkC6vOWGUtQjxy-ZpTrMvJa3CgcW-y9mDpJwWC8,9533
94
94
  sunholo/invoke/invoke_vac_utils.py,sha256=sJc1edHTHMzMGXjji1N67c3iUaP7BmAL5nj82Qof63M,2053
95
95
  sunholo/langfuse/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
96
96
  sunholo/langfuse/callback.py,sha256=jl0SZsFS53uMW9DGeM9SOL_EsRZsba0wwFGLqKzu9_U,1684
@@ -144,9 +144,9 @@ sunholo/vertex/init.py,sha256=1OQwcPBKZYBTDPdyU7IM4X4OmiXLdsNV30C-fee2scQ,2875
144
144
  sunholo/vertex/memory_tools.py,sha256=ZirFbS7EKxQaoRmOrb4BnG6jPJ83wt43N8M4zTVbutU,7717
145
145
  sunholo/vertex/safety.py,sha256=S9PgQT1O_BQAkcqauWncRJaydiP8Q_Jzmu9gxYfy1VA,2482
146
146
  sunholo/vertex/type_dict_to_json.py,sha256=uTzL4o9tJRao4u-gJOFcACgWGkBOtqACmb6ihvCErL8,4694
147
- sunholo-0.96.2.dist-info/LICENSE.txt,sha256=SdE3QjnD3GEmqqg9EX3TM9f7WmtOzqS1KJve8rhbYmU,11345
148
- sunholo-0.96.2.dist-info/METADATA,sha256=SjGyoQwCjP0t2BgYpsZQAm2d4Ckj3Q9TrJd5WUdTn0I,7889
149
- sunholo-0.96.2.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
150
- sunholo-0.96.2.dist-info/entry_points.txt,sha256=bZuN5AIHingMPt4Ro1b_T-FnQvZ3teBes-3OyO0asl4,49
151
- sunholo-0.96.2.dist-info/top_level.txt,sha256=wt5tadn5--5JrZsjJz2LceoUvcrIvxjHJe-RxuudxAk,8
152
- sunholo-0.96.2.dist-info/RECORD,,
147
+ sunholo-0.96.5.dist-info/LICENSE.txt,sha256=SdE3QjnD3GEmqqg9EX3TM9f7WmtOzqS1KJve8rhbYmU,11345
148
+ sunholo-0.96.5.dist-info/METADATA,sha256=xSaGe0hLQU4vUWrnPs5v67kzLo3WMFwptSMOBXRSHvA,7889
149
+ sunholo-0.96.5.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
150
+ sunholo-0.96.5.dist-info/entry_points.txt,sha256=bZuN5AIHingMPt4Ro1b_T-FnQvZ3teBes-3OyO0asl4,49
151
+ sunholo-0.96.5.dist-info/top_level.txt,sha256=wt5tadn5--5JrZsjJz2LceoUvcrIvxjHJe-RxuudxAk,8
152
+ sunholo-0.96.5.dist-info/RECORD,,