sunholo 0.100.0__py3-none-any.whl → 0.100.1__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.
- sunholo/invoke/async_class.py +22 -18
- sunholo/streaming/content_buffer.py +4 -4
- sunholo/streaming/streaming.py +1 -1
- {sunholo-0.100.0.dist-info → sunholo-0.100.1.dist-info}/METADATA +2 -2
- {sunholo-0.100.0.dist-info → sunholo-0.100.1.dist-info}/RECORD +9 -9
- {sunholo-0.100.0.dist-info → sunholo-0.100.1.dist-info}/LICENSE.txt +0 -0
- {sunholo-0.100.0.dist-info → sunholo-0.100.1.dist-info}/WHEEL +0 -0
- {sunholo-0.100.0.dist-info → sunholo-0.100.1.dist-info}/entry_points.txt +0 -0
- {sunholo-0.100.0.dist-info → sunholo-0.100.1.dist-info}/top_level.txt +0 -0
sunholo/invoke/async_class.py
CHANGED
|
@@ -21,8 +21,9 @@ class AsyncTaskRunner:
|
|
|
21
21
|
"""
|
|
22
22
|
log.info("Running tasks asynchronously and yielding results and heartbeats as they occur")
|
|
23
23
|
queue = asyncio.Queue()
|
|
24
|
-
|
|
25
24
|
tasks = {}
|
|
25
|
+
completed_tasks = set()
|
|
26
|
+
|
|
26
27
|
for name, func, args in self.tasks:
|
|
27
28
|
coro = self._task_wrapper(name, func, args, queue)
|
|
28
29
|
task = asyncio.create_task(coro)
|
|
@@ -32,9 +33,11 @@ class AsyncTaskRunner:
|
|
|
32
33
|
if not queue.empty():
|
|
33
34
|
message = await queue.get()
|
|
34
35
|
log.info(f"Found queue message: {message}")
|
|
36
|
+
# Ignore heartbeats from completed tasks
|
|
37
|
+
if message['type'] == 'heartbeat' and message['func_name'] in completed_tasks:
|
|
38
|
+
continue
|
|
35
39
|
yield message
|
|
36
40
|
else:
|
|
37
|
-
# Wait for either a message in the queue or a task to complete
|
|
38
41
|
done, _ = await asyncio.wait(
|
|
39
42
|
list(tasks.keys()),
|
|
40
43
|
timeout=0.1,
|
|
@@ -42,6 +45,7 @@ class AsyncTaskRunner:
|
|
|
42
45
|
)
|
|
43
46
|
for task in done:
|
|
44
47
|
name = tasks.pop(task)
|
|
48
|
+
completed_tasks.add(name)
|
|
45
49
|
try:
|
|
46
50
|
result = await task
|
|
47
51
|
await queue.put({'type': 'task_complete', 'func_name': name, 'result': result})
|
|
@@ -49,19 +53,20 @@ class AsyncTaskRunner:
|
|
|
49
53
|
log.error(f"Task {name} resulted in an error: {e}\n{traceback.format_exc()}")
|
|
50
54
|
await queue.put({'type': 'task_error', 'func_name': name, 'error': e})
|
|
51
55
|
|
|
52
|
-
#
|
|
56
|
+
# Process any remaining messages in the queue
|
|
53
57
|
while not queue.empty():
|
|
54
58
|
message = await queue.get()
|
|
59
|
+
log.info(f"Found queue message: {message}")
|
|
60
|
+
if message['type'] == 'heartbeat' and message['func_name'] in completed_tasks:
|
|
61
|
+
continue
|
|
55
62
|
yield message
|
|
56
63
|
|
|
57
64
|
async def _task_wrapper(self, name: str, func: Callable[..., Any], args: Any, queue: asyncio.Queue) -> Any:
|
|
58
65
|
"""Wraps the task function to process its output and handle retries, while managing heartbeat updates."""
|
|
59
66
|
async def run_func():
|
|
60
67
|
if asyncio.iscoroutinefunction(func):
|
|
61
|
-
# If the function is async, await it
|
|
62
68
|
return await func(*args)
|
|
63
69
|
else:
|
|
64
|
-
# If the function is sync, run it in a thread to prevent blocking
|
|
65
70
|
return await asyncio.to_thread(func, *args)
|
|
66
71
|
|
|
67
72
|
# Start the heartbeat task
|
|
@@ -87,18 +92,12 @@ class AsyncTaskRunner:
|
|
|
87
92
|
finally:
|
|
88
93
|
# Stop the heartbeat task
|
|
89
94
|
heartbeat_task.cancel()
|
|
90
|
-
#
|
|
95
|
+
# Wait for the heartbeat task to finish
|
|
91
96
|
try:
|
|
92
|
-
await
|
|
97
|
+
await heartbeat_task
|
|
93
98
|
except asyncio.CancelledError:
|
|
94
99
|
pass
|
|
95
100
|
|
|
96
|
-
# Send a message indicating task completion to update the spinner's state
|
|
97
|
-
completion_html = (
|
|
98
|
-
f'<div style="display: none;" data-complete-id="{name}-spinner"></div>'
|
|
99
|
-
)
|
|
100
|
-
await queue.put({'type': 'heartbeat', 'func_name': name, 'token': completion_html})
|
|
101
|
-
|
|
102
101
|
async def _send_heartbeat(self, queue: asyncio.Queue, func_name: str, interval=2):
|
|
103
102
|
"""
|
|
104
103
|
Sends a periodic heartbeat to keep the task alive and update the spinner with elapsed time.
|
|
@@ -117,9 +116,8 @@ class AsyncTaskRunner:
|
|
|
117
116
|
# Keep track of elapsed time
|
|
118
117
|
elapsed_time = 0
|
|
119
118
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
try:
|
|
119
|
+
try:
|
|
120
|
+
while True:
|
|
123
121
|
await asyncio.sleep(interval) # Sleep for the interval
|
|
124
122
|
elapsed_time += interval # Increment elapsed time
|
|
125
123
|
log.info(f"Sending heartbeat for {func_name}: {elapsed_time}s elapsed")
|
|
@@ -130,5 +128,11 @@ class AsyncTaskRunner:
|
|
|
130
128
|
f'</div>'
|
|
131
129
|
)
|
|
132
130
|
await queue.put({'type': 'heartbeat', 'func_name': func_name, 'token': update_html})
|
|
133
|
-
|
|
134
|
-
|
|
131
|
+
except asyncio.CancelledError:
|
|
132
|
+
log.info(f"Heartbeat task for {func_name} has been cancelled.")
|
|
133
|
+
finally:
|
|
134
|
+
# Send a message indicating task completion to update the spinner's state
|
|
135
|
+
completion_html = (
|
|
136
|
+
f'<div style="display: none;" data-complete-id="{func_name}-spinner"></div>'
|
|
137
|
+
)
|
|
138
|
+
await queue.put({'type': 'heartbeat', 'func_name': func_name, 'token': completion_html})
|
|
@@ -173,13 +173,13 @@ class BufferStreamingStdOutCallbackHandler(StreamingStdOutCallbackHandler):
|
|
|
173
173
|
The buffer content is written to the content buffer when appropriate tokens or
|
|
174
174
|
patterns are detected.
|
|
175
175
|
"""
|
|
176
|
-
log.debug(f"on_llm_new_token: {token}")
|
|
176
|
+
#log.debug(f"on_llm_new_token: {token}")
|
|
177
177
|
|
|
178
178
|
# Check if the token is a heartbeat message
|
|
179
179
|
if self._is_heartbeat_token(token):
|
|
180
180
|
# Strip the [[HEARTBEAT]] markers and write immediately
|
|
181
181
|
heartbeat_content = self._strip_heartbeat_markers(token)
|
|
182
|
-
log.info(f"Heartbeat token detected, writing immediately: {heartbeat_content}")
|
|
182
|
+
#log.info(f"Heartbeat token detected, writing immediately: {heartbeat_content}")
|
|
183
183
|
self.content_buffer.write(heartbeat_content)
|
|
184
184
|
else:
|
|
185
185
|
self.buffer += token
|
|
@@ -268,13 +268,13 @@ class BufferStreamingStdOutCallbackHandlerAsync(StreamingStdOutCallbackHandler):
|
|
|
268
268
|
log.info("Starting to stream LLM")
|
|
269
269
|
|
|
270
270
|
async def async_on_llm_new_token(self, token: str, **kwargs: Any) -> None:
|
|
271
|
-
log.debug(f"async_on_llm_new_token: {token}")
|
|
271
|
+
#log.debug(f"async_on_llm_new_token: {token}")
|
|
272
272
|
|
|
273
273
|
# Check if the token is a heartbeat message
|
|
274
274
|
if self._is_heartbeat_token(token):
|
|
275
275
|
# Strip the [[HEARTBEAT]] markers and write immediately
|
|
276
276
|
heartbeat_content = self._strip_heartbeat_markers(token)
|
|
277
|
-
log.info(f"Heartbeat token detected, writing immediately: {heartbeat_content}")
|
|
277
|
+
#log.info(f"Heartbeat token detected, writing immediately: {heartbeat_content}")
|
|
278
278
|
await self.content_buffer.async_write(heartbeat_content)
|
|
279
279
|
else:
|
|
280
280
|
self.buffer += token
|
sunholo/streaming/streaming.py
CHANGED
|
@@ -194,7 +194,7 @@ async def start_streaming_chat_async(question, vector_name, qna_func_async, chat
|
|
|
194
194
|
|
|
195
195
|
content_to_send = await content_buffer.async_read()
|
|
196
196
|
if content_to_send:
|
|
197
|
-
log.info(f"
|
|
197
|
+
log.info(f"==Async\n{content_to_send}")
|
|
198
198
|
yield content_to_send
|
|
199
199
|
await content_buffer.async_clear()
|
|
200
200
|
else:
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: sunholo
|
|
3
|
-
Version: 0.100.
|
|
3
|
+
Version: 0.100.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.100.
|
|
6
|
+
Download-URL: https://github.com/sunholo-data/sunholo-py/archive/refs/tags/v0.100.1.tar.gz
|
|
7
7
|
Author: Holosun ApS
|
|
8
8
|
Author-email: multivac@sunholo.com
|
|
9
9
|
License: Apache License, Version 2.0
|
|
@@ -89,7 +89,7 @@ sunholo/genai/init.py,sha256=yG8E67TduFCTQPELo83OJuWfjwTnGZsyACospahyEaY,687
|
|
|
89
89
|
sunholo/genai/process_funcs_cls.py,sha256=MF3wm-N-zoYvme4I8ffXM9I7cog8OFyBnLu1e3A6eVc,26695
|
|
90
90
|
sunholo/genai/safety.py,sha256=mkFDO_BeEgiKjQd9o2I4UxB6XI7a9U-oOFjZ8LGRUC4,1238
|
|
91
91
|
sunholo/invoke/__init__.py,sha256=o1RhwBGOtVK0MIdD55fAIMCkJsxTksi8GD5uoqVKI-8,184
|
|
92
|
-
sunholo/invoke/async_class.py,sha256=
|
|
92
|
+
sunholo/invoke/async_class.py,sha256=TbYzdS2RDu1WhbYcq6wt7GTJzrtk-7Y3I-2AbJAD1Ik,6134
|
|
93
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
|
|
@@ -114,10 +114,10 @@ sunholo/qna/__init__.py,sha256=F8q1uR_HreoSX0IfmKY1qoSwIgXhO2Q8kuDSxh9_-EE,28
|
|
|
114
114
|
sunholo/qna/parsers.py,sha256=YpOaK5S_LxJ6FbliSYDc3AVOJ62RVduayoNnzi_p8CM,2494
|
|
115
115
|
sunholo/qna/retry.py,sha256=yMw7RTkw-RXCzfENPJOt8c32mXlpvOR589EGkvK-6yI,2028
|
|
116
116
|
sunholo/streaming/__init__.py,sha256=MpbydI2UYo_adttPQFkxNM33b-QRyNEbrKJx0C2AGPc,241
|
|
117
|
-
sunholo/streaming/content_buffer.py,sha256=
|
|
117
|
+
sunholo/streaming/content_buffer.py,sha256=dGzzajY_DEnIxMERiApCKUSzDI5mXKByW9L4dmYRqSw,12814
|
|
118
118
|
sunholo/streaming/langserve.py,sha256=hi7q8WY8DPKrALl9m_dOMxWOdE-iEuk7YW05SVDFIX8,6514
|
|
119
119
|
sunholo/streaming/stream_lookup.py,sha256=hYg1DbdSE_QNJ8ZB-ynXJlWgvFjrGvwoUsGJu_E0pRQ,360
|
|
120
|
-
sunholo/streaming/streaming.py,sha256=
|
|
120
|
+
sunholo/streaming/streaming.py,sha256=S4GzVNol3J_8tkzXodvkcR-THiTGnIKYj40NtrBhtL4,16459
|
|
121
121
|
sunholo/summarise/__init__.py,sha256=MZk3dblUMODcPb1crq4v-Z508NrFIpkSWNf9FIO8BcU,38
|
|
122
122
|
sunholo/summarise/summarise.py,sha256=95A-6PXFGanjona8DvZPnnIHLbzZ2ip5hO0wOAJQhfw,3791
|
|
123
123
|
sunholo/terraform/__init__.py,sha256=yixxEltc3n9UpZaVi05GlgS-YRq_DVGjUc37I9ajeP4,76
|
|
@@ -144,9 +144,9 @@ sunholo/vertex/init.py,sha256=1OQwcPBKZYBTDPdyU7IM4X4OmiXLdsNV30C-fee2scQ,2875
|
|
|
144
144
|
sunholo/vertex/memory_tools.py,sha256=tBZxqVZ4InTmdBvLlOYwoSEWu4-kGquc-gxDwZCC4FA,7667
|
|
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.100.
|
|
148
|
-
sunholo-0.100.
|
|
149
|
-
sunholo-0.100.
|
|
150
|
-
sunholo-0.100.
|
|
151
|
-
sunholo-0.100.
|
|
152
|
-
sunholo-0.100.
|
|
147
|
+
sunholo-0.100.1.dist-info/LICENSE.txt,sha256=SdE3QjnD3GEmqqg9EX3TM9f7WmtOzqS1KJve8rhbYmU,11345
|
|
148
|
+
sunholo-0.100.1.dist-info/METADATA,sha256=dFU8BBZlnOGZpfnkvOiQ-_yO3Hs12mNi0BFWnVQh9QQ,8312
|
|
149
|
+
sunholo-0.100.1.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
|
|
150
|
+
sunholo-0.100.1.dist-info/entry_points.txt,sha256=bZuN5AIHingMPt4Ro1b_T-FnQvZ3teBes-3OyO0asl4,49
|
|
151
|
+
sunholo-0.100.1.dist-info/top_level.txt,sha256=wt5tadn5--5JrZsjJz2LceoUvcrIvxjHJe-RxuudxAk,8
|
|
152
|
+
sunholo-0.100.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|