sunholo 0.62.3__tar.gz → 0.62.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.
- {sunholo-0.62.3 → sunholo-0.62.5}/PKG-INFO +2 -2
- {sunholo-0.62.3 → sunholo-0.62.5}/setup.py +1 -1
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/agents/dispatch_to_qa.py +7 -1
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/agents/route.py +2 -9
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/agents/special_commands.py +2 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/cli/chat_vac.py +83 -35
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/cli/cli.py +0 -3
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/components/__init__.py +0 -1
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/embedder/embed_chunk.py +1 -1
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/gcs/add_file.py +6 -2
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/streaming/__init__.py +2 -1
- sunholo-0.62.5/sunholo/streaming/stream_lookup.py +12 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/utils/config.py +17 -6
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/utils/gcp.py +11 -3
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo.egg-info/PKG-INFO +2 -2
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo.egg-info/SOURCES.txt +1 -1
- sunholo-0.62.3/sunholo/components/prompt.py +0 -151
- {sunholo-0.62.3 → sunholo-0.62.5}/LICENSE.txt +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/MANIFEST.in +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/README.md +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/setup.cfg +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/__init__.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/agents/__init__.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/agents/chat_history.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/agents/fastapi/__init__.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/agents/fastapi/base.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/agents/fastapi/qna_routes.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/agents/flask/__init__.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/agents/flask/base.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/agents/flask/qna_routes.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/agents/langserve.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/agents/pubsub.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/archive/__init__.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/archive/archive.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/auth/__init__.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/auth/run.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/bots/__init__.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/bots/discord.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/bots/github_webhook.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/bots/webapp.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/chunker/__init__.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/chunker/data_to_embed_pubsub.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/chunker/doc_handling.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/chunker/images.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/chunker/loaders.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/chunker/message_data.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/chunker/pdfs.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/chunker/publish.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/chunker/splitter.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/cli/__init__.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/cli/cli_init.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/cli/configs.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/cli/deploy.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/cli/embedder.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/cli/merge_texts.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/cli/run_proxy.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/cli/sun_rich.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/components/llm.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/components/retriever.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/components/vectorstore.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/database/__init__.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/database/alloydb.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/database/database.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/database/lancedb.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/database/sql/sb/create_function.sql +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/database/sql/sb/create_function_time.sql +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/database/sql/sb/create_table.sql +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/database/sql/sb/delete_source_row.sql +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/database/sql/sb/return_sources.sql +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/database/sql/sb/setup.sql +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/database/static_dbs.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/database/uuid.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/embedder/__init__.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/gcs/__init__.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/gcs/download_url.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/gcs/metadata.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/langfuse/__init__.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/langfuse/callback.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/langfuse/prompts.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/llamaindex/__init__.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/llamaindex/generate.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/llamaindex/get_files.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/llamaindex/import_files.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/logging.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/lookup/__init__.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/lookup/model_lookup.yaml +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/patches/__init__.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/patches/langchain/__init__.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/patches/langchain/lancedb.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/patches/langchain/vertexai.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/pubsub/__init__.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/pubsub/process_pubsub.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/pubsub/pubsub_manager.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/qna/__init__.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/qna/parsers.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/qna/retry.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/streaming/content_buffer.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/streaming/langserve.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/streaming/streaming.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/summarise/__init__.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/summarise/summarise.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/utils/__init__.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/utils/big_context.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/utils/config_schema.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/utils/parsers.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/utils/timedelta.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/utils/user_ids.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/vertex/__init__.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/vertex/init.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/vertex/memory_tools.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo.egg-info/dependency_links.txt +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo.egg-info/entry_points.txt +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo.egg-info/requires.txt +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/sunholo.egg-info/top_level.txt +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/tests/test_chat_history.py +0 -0
- {sunholo-0.62.3 → sunholo-0.62.5}/tests/test_config.py +0 -0
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: sunholo
|
|
3
|
-
Version: 0.62.
|
|
3
|
+
Version: 0.62.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.62.
|
|
6
|
+
Download-URL: https://github.com/sunholo-data/sunholo-py/archive/refs/tags/v0.62.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,10 @@ def prep_request_payload(user_input, chat_history, vector_name, stream, **kwargs
|
|
|
59
59
|
# {'stream': '', 'invoke': ''}
|
|
60
60
|
endpoints = route_endpoint(vector_name, override_endpoint=override_endpoint)
|
|
61
61
|
|
|
62
|
-
|
|
62
|
+
if stream:
|
|
63
|
+
qna_endpoint = endpoints["stream"]
|
|
64
|
+
else:
|
|
65
|
+
qna_endpoint = endpoints["invoke"]
|
|
63
66
|
|
|
64
67
|
if agent == "langserve" or agent_type == "langserve":
|
|
65
68
|
qna_data = prepare_request_data(user_input, endpoints["input_schema"], vector_name, **kwargs)
|
|
@@ -71,6 +74,9 @@ def prep_request_payload(user_input, chat_history, vector_name, stream, **kwargs
|
|
|
71
74
|
# Update qna_data with optional values from kwargs
|
|
72
75
|
qna_data.update(kwargs)
|
|
73
76
|
|
|
77
|
+
if not 'vector_name' not in qna_data:
|
|
78
|
+
qna_data['vector_name'] = vector_name
|
|
79
|
+
|
|
74
80
|
return qna_endpoint, qna_data
|
|
75
81
|
|
|
76
82
|
def send_to_qa(user_input, vector_name, chat_history, stream=False, **kwargs):
|
|
@@ -42,15 +42,8 @@ def route_endpoint(vector_name, override_endpoint=None):
|
|
|
42
42
|
agent_type = load_config_key('agent', vector_name, kind="vacConfig")
|
|
43
43
|
|
|
44
44
|
stem = route_qna(vector_name) if not override_endpoint else override_endpoint
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
# Select the appropriate configuration based on agent_type
|
|
49
|
-
if agent_type in agent_config:
|
|
50
|
-
endpoints_config = agent_config[agent_type]
|
|
51
|
-
else:
|
|
52
|
-
log.warning('Using default endpoints configuration')
|
|
53
|
-
endpoints_config = agent_config['default']
|
|
45
|
+
|
|
46
|
+
endpoints_config = load_config_key(agent_type, vector_name, kind="agentConfig")
|
|
54
47
|
|
|
55
48
|
log.info(f"endpoints_config: {endpoints_config}")
|
|
56
49
|
|
|
@@ -46,6 +46,8 @@ def handle_special_commands(user_input,
|
|
|
46
46
|
hourmin = now.strftime("%H%M%S")
|
|
47
47
|
the_datetime = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
|
48
48
|
|
|
49
|
+
user_input = user_input.strip()
|
|
50
|
+
|
|
49
51
|
if not cmds:
|
|
50
52
|
cmds = load_config_key("user_special_cmds", vector_name=vector_name, kind="vacConfig")
|
|
51
53
|
if not cmds:
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
from ..agents import send_to_qa
|
|
2
|
-
from ..streaming import generate_proxy_stream
|
|
1
|
+
from ..agents import send_to_qa, handle_special_commands
|
|
2
|
+
from ..streaming import generate_proxy_stream, can_agent_stream
|
|
3
3
|
from ..utils.user_ids import generate_user_id
|
|
4
4
|
from ..utils.config import load_config_key
|
|
5
|
-
|
|
5
|
+
from ..logging import log
|
|
6
|
+
from ..qna.parsers import parse_output
|
|
6
7
|
from .run_proxy import clean_proxy_list, start_proxy, stop_proxy
|
|
7
8
|
|
|
8
9
|
import uuid
|
|
@@ -42,7 +43,7 @@ def get_service_url(vac_name, project, region, no_config=False):
|
|
|
42
43
|
|
|
43
44
|
return url
|
|
44
45
|
|
|
45
|
-
def stream_chat_session(service_url, service_name):
|
|
46
|
+
def stream_chat_session(service_url, service_name, stream=True):
|
|
46
47
|
|
|
47
48
|
user_id = generate_user_id()
|
|
48
49
|
chat_history = []
|
|
@@ -53,15 +54,19 @@ def stream_chat_session(service_url, service_name):
|
|
|
53
54
|
console.print("[bold red]Exiting chat session.[/bold red]")
|
|
54
55
|
break
|
|
55
56
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
57
|
+
special_reply = handle_special_commands(
|
|
58
|
+
user_input,
|
|
59
|
+
vector_name=service_name,
|
|
60
|
+
chat_history=chat_history)
|
|
61
|
+
|
|
62
|
+
if special_reply:
|
|
63
|
+
console.print(f"[bold yellow]{service_name}:[/bold yellow] {special_reply}", end='\n')
|
|
64
|
+
continue
|
|
65
|
+
|
|
66
|
+
if not stream:
|
|
67
|
+
vac_response = send_to_qa(user_input,
|
|
60
68
|
vector_name=service_name,
|
|
61
69
|
chat_history=chat_history,
|
|
62
|
-
generate_f_output=lambda x: x, # Replace with actual processing function
|
|
63
|
-
stream_wait_time=0.5,
|
|
64
|
-
stream_timeout=120,
|
|
65
70
|
message_author=user_id,
|
|
66
71
|
#TODO: populate these
|
|
67
72
|
image_url=None,
|
|
@@ -77,34 +82,68 @@ def stream_chat_session(service_url, service_name):
|
|
|
77
82
|
user_id=user_id,
|
|
78
83
|
session_id=session_id,
|
|
79
84
|
message_source="cli",
|
|
80
|
-
override_endpoint=service_url
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
85
|
+
override_endpoint=service_url)
|
|
86
|
+
|
|
87
|
+
# ensures {'answer': answer}
|
|
88
|
+
answer = parse_output(vac_response)
|
|
89
|
+
|
|
90
|
+
console.print(f"[bold yellow]{service_name}:[/bold yellow] {answer.get('answer')}", end='\n')
|
|
91
|
+
else:
|
|
84
92
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
93
|
+
def stream_response():
|
|
94
|
+
generate = generate_proxy_stream(
|
|
95
|
+
send_to_qa,
|
|
96
|
+
user_input,
|
|
97
|
+
vector_name=service_name,
|
|
98
|
+
chat_history=chat_history,
|
|
99
|
+
generate_f_output=lambda x: x, # Replace with actual processing function
|
|
100
|
+
stream_wait_time=0.5,
|
|
101
|
+
stream_timeout=120,
|
|
102
|
+
message_author=user_id,
|
|
103
|
+
#TODO: populate these
|
|
104
|
+
image_url=None,
|
|
105
|
+
source_filters=None,
|
|
106
|
+
search_kwargs=None,
|
|
107
|
+
private_docs=None,
|
|
108
|
+
whole_document=False,
|
|
109
|
+
source_filters_and_or=False,
|
|
110
|
+
# system kwargs
|
|
111
|
+
configurable={
|
|
112
|
+
"vector_name": service_name,
|
|
113
|
+
},
|
|
114
|
+
user_id=user_id,
|
|
115
|
+
session_id=session_id,
|
|
116
|
+
message_source="cli",
|
|
117
|
+
override_endpoint=service_url
|
|
118
|
+
)
|
|
119
|
+
for part in generate():
|
|
120
|
+
yield part
|
|
121
|
+
|
|
122
|
+
response_started = False
|
|
123
|
+
vac_response = ""
|
|
124
|
+
|
|
125
|
+
# point or star?
|
|
126
|
+
with console.status("[bold orange]Thinking...[/bold orange]", spinner="star") as status:
|
|
127
|
+
for token in stream_response():
|
|
128
|
+
if not response_started:
|
|
129
|
+
status.stop()
|
|
130
|
+
console.print(f"[bold yellow]{service_name}:[/bold yellow] ", end='')
|
|
131
|
+
response_started = True
|
|
132
|
+
|
|
133
|
+
if isinstance(token, bytes):
|
|
134
|
+
token = token.decode('utf-8')
|
|
135
|
+
console.print(token, end='')
|
|
136
|
+
vac_response += token
|
|
137
|
+
|
|
138
|
+
response_started = False
|
|
100
139
|
|
|
101
140
|
chat_history.append({"name": "Human", "content": user_input})
|
|
102
141
|
chat_history.append({"name": "AI", "content": vac_response})
|
|
103
|
-
|
|
142
|
+
|
|
104
143
|
console.print()
|
|
105
144
|
console.rule()
|
|
106
145
|
|
|
107
|
-
def headless_mode(service_url, service_name, user_input, chat_history=None):
|
|
146
|
+
def headless_mode(service_url, service_name, user_input, chat_history=None, stream=True):
|
|
108
147
|
chat_history = chat_history or []
|
|
109
148
|
|
|
110
149
|
user_id = generate_user_id()
|
|
@@ -196,16 +235,25 @@ def vac_command(args):
|
|
|
196
235
|
service_url = resolve_service_url(args)
|
|
197
236
|
agent_name = load_config_key("agent", args.vac_name, kind="vacConfig")
|
|
198
237
|
|
|
238
|
+
streamer = can_agent_stream(agent_name)
|
|
239
|
+
log.debug(f"streamer: {streamer}")
|
|
240
|
+
if not streamer:
|
|
241
|
+
console.print(f"Non streaming agent: {args.vac_name}")
|
|
242
|
+
|
|
199
243
|
if args.headless:
|
|
200
|
-
headless_mode(service_url, args.vac_name, args.user_input, args.chat_history)
|
|
244
|
+
headless_mode(service_url, args.vac_name, args.user_input, args.chat_history, stream=streamer)
|
|
201
245
|
else:
|
|
202
246
|
display_name = load_config_key("display_name", vector_name=args.vac_name, kind="vacConfig")
|
|
203
247
|
description = load_config_key("description", vector_name=args.vac_name, kind="vacConfig")
|
|
248
|
+
endpoints_config = load_config_key(agent_name, "dummy_value", kind="agentConfig")
|
|
249
|
+
|
|
250
|
+
display_endpoints = ' '.join(f"{key}: {value}" for key, value in endpoints_config.items())
|
|
251
|
+
display_endpoints = display_endpoints.replace("{stem}", service_url).replace("{vector_name}", args.vac_name)
|
|
204
252
|
|
|
205
253
|
if agent_name == "langserve":
|
|
206
254
|
subtitle = f"{service_url}/{args.vac_name}/playground/"
|
|
207
255
|
else:
|
|
208
|
-
subtitle =
|
|
256
|
+
subtitle = display_endpoints
|
|
209
257
|
|
|
210
258
|
print(
|
|
211
259
|
Panel(description or "Starting VAC chat session",
|
|
@@ -213,7 +261,7 @@ def vac_command(args):
|
|
|
213
261
|
subtitle=subtitle)
|
|
214
262
|
)
|
|
215
263
|
|
|
216
|
-
stream_chat_session(service_url, args.vac_name)
|
|
264
|
+
stream_chat_session(service_url, args.vac_name, stream=streamer)
|
|
217
265
|
|
|
218
266
|
stop_proxy(agent_name, stop_local=False)
|
|
219
267
|
|
|
@@ -45,9 +45,6 @@ class CustomHelpAction(argparse.Action):
|
|
|
45
45
|
parser.exit()
|
|
46
46
|
|
|
47
47
|
def main(args=None):
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
48
|
"""
|
|
52
49
|
Entry point for the sunholo console script. This function parses command line arguments
|
|
53
50
|
and invokes the appropriate functionality based on the user input.
|
|
@@ -66,7 +66,7 @@ def embed_pubsub_chunk(data: dict):
|
|
|
66
66
|
log.info(f"Embedding: {vector_name} page_content: {page_content[:30]}...[{len(page_content)}] - {metadata}")
|
|
67
67
|
|
|
68
68
|
if 'eventTime' not in metadata:
|
|
69
|
-
metadata['eventTime'] = datetime.datetime.now(
|
|
69
|
+
metadata['eventTime'] = datetime.datetime.now().isoformat(timespec='microseconds') + "Z"
|
|
70
70
|
metadata['eventtime'] = metadata['eventTime']
|
|
71
71
|
|
|
72
72
|
if 'source' not in metadata:
|
|
@@ -20,8 +20,7 @@ except ImportError:
|
|
|
20
20
|
storage = None
|
|
21
21
|
|
|
22
22
|
from ..logging import log
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
from ..utils.config import load_config_key
|
|
25
24
|
|
|
26
25
|
def add_file_to_gcs(filename: str, vector_name:str, bucket_name: str=None, metadata:dict=None, bucket_filepath:str=None):
|
|
27
26
|
|
|
@@ -33,6 +32,11 @@ def add_file_to_gcs(filename: str, vector_name:str, bucket_name: str=None, metad
|
|
|
33
32
|
except Exception as err:
|
|
34
33
|
log.error(f"Error creating storage client: {str(err)}")
|
|
35
34
|
return None
|
|
35
|
+
|
|
36
|
+
bucket_config = load_config_key("upload", vector_name, "vacConfig")
|
|
37
|
+
if bucket_config:
|
|
38
|
+
if bucket_config.get("buckets"):
|
|
39
|
+
bucket_name = bucket_config.get("buckets").get("all")
|
|
36
40
|
|
|
37
41
|
bucket_name = bucket_name if bucket_name else os.getenv('GCS_BUCKET', None)
|
|
38
42
|
if bucket_name is None:
|
|
@@ -1,2 +1,3 @@
|
|
|
1
1
|
from .streaming import start_streaming_chat, generate_proxy_stream, generate_proxy_stream_async, start_streaming_chat_async
|
|
2
|
-
from .langserve import parse_langserve_token, parse_langserve_token_async
|
|
2
|
+
from .langserve import parse_langserve_token, parse_langserve_token_async
|
|
3
|
+
from .stream_lookup import can_agent_stream
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
from ..utils import load_config_key
|
|
2
|
+
from ..logging import log
|
|
3
|
+
|
|
4
|
+
def can_agent_stream(agent_name: str):
|
|
5
|
+
|
|
6
|
+
log.debug(f"agent_type: {agent_name} checking streaming...")
|
|
7
|
+
endpoints_config = load_config_key(agent_name, "dummy_value", kind="agentConfig")
|
|
8
|
+
|
|
9
|
+
return 'stream' in endpoints_config
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
@@ -58,14 +58,14 @@ def load_all_configs():
|
|
|
58
58
|
from ..logging import log
|
|
59
59
|
|
|
60
60
|
if not os.getenv("_CONFIG_FOLDER", None):
|
|
61
|
-
log.
|
|
61
|
+
log.debug("_CONFIG_FOLDER is not set, using os.getcwd() instead")
|
|
62
62
|
else:
|
|
63
|
-
log.
|
|
63
|
+
log.debug(f"_CONFIG_FOLDER set to: {os.getenv('_CONFIG_FOLDER')}")
|
|
64
64
|
|
|
65
65
|
config_folder = os.getenv("_CONFIG_FOLDER", os.getcwd())
|
|
66
66
|
config_folder = os.path.join(config_folder, "config")
|
|
67
67
|
|
|
68
|
-
log.
|
|
68
|
+
log.debug(f"Loading all configs from folder: {config_folder}")
|
|
69
69
|
current_time = datetime.now()
|
|
70
70
|
|
|
71
71
|
configs_by_kind = defaultdict(dict)
|
|
@@ -82,7 +82,7 @@ def load_all_configs():
|
|
|
82
82
|
cached_config, cache_time = config_cache[filename]
|
|
83
83
|
time_to_recache = (current_time - cache_time)
|
|
84
84
|
if time_to_recache < timedelta(minutes=5):
|
|
85
|
-
log.
|
|
85
|
+
log.debug(f"Returning cached config for {filename} - recache in {format_timedelta(timedelta(minutes=5) - time_to_recache)}")
|
|
86
86
|
config = cached_config
|
|
87
87
|
else:
|
|
88
88
|
config = reload_config_file(config_file, filename)
|
|
@@ -109,7 +109,7 @@ def reload_config_file(config_file, filename):
|
|
|
109
109
|
config = yaml.safe_load(file)
|
|
110
110
|
|
|
111
111
|
config_cache[filename] = (config, datetime.now())
|
|
112
|
-
log.
|
|
112
|
+
log.debug(f"Loaded and cached {config_file}")
|
|
113
113
|
return config
|
|
114
114
|
|
|
115
115
|
|
|
@@ -194,7 +194,9 @@ def load_config_key(key: str, vector_name: str, kind: str):
|
|
|
194
194
|
"""
|
|
195
195
|
from ..logging import log
|
|
196
196
|
|
|
197
|
-
|
|
197
|
+
if kind != 'agentConfig':
|
|
198
|
+
assert isinstance(key, str), f"key must be a string got a {type(key)}"
|
|
199
|
+
|
|
198
200
|
assert isinstance(vector_name, str), f"vector_name must be a string, got a {type(vector_name)}"
|
|
199
201
|
|
|
200
202
|
configs_by_kind = load_all_configs()
|
|
@@ -243,3 +245,12 @@ def load_config_key(key: str, vector_name: str, kind: str):
|
|
|
243
245
|
key_value = prompt_for_vector_name.get(key)
|
|
244
246
|
|
|
245
247
|
return key_value
|
|
248
|
+
elif kind == 'agentConfig':
|
|
249
|
+
agents = config.get('agents')
|
|
250
|
+
|
|
251
|
+
if key in agents:
|
|
252
|
+
return agents[key]
|
|
253
|
+
else:
|
|
254
|
+
log.warning("Returning default agent endpoints")
|
|
255
|
+
return agents["default"]
|
|
256
|
+
|
|
@@ -17,6 +17,8 @@ import socket
|
|
|
17
17
|
# can't install due to circular import sunholo.logging
|
|
18
18
|
import logging
|
|
19
19
|
|
|
20
|
+
from .config import load_config_key
|
|
21
|
+
|
|
20
22
|
def is_running_on_cloudrun():
|
|
21
23
|
"""
|
|
22
24
|
Check if the current environment is a Google Cloud Run instance.
|
|
@@ -127,9 +129,11 @@ def get_gcp_project():
|
|
|
127
129
|
Returns:
|
|
128
130
|
str or None: The project ID if found, None otherwise.
|
|
129
131
|
"""
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
132
|
+
gcp_config = load_config_key("gcp_config", "global", "vacConfig")
|
|
133
|
+
if gcp_config:
|
|
134
|
+
if gcp_config.get('project_id'):
|
|
135
|
+
return gcp_config.get('project_id')
|
|
136
|
+
|
|
133
137
|
project_id = get_env_project_id()
|
|
134
138
|
if project_id:
|
|
135
139
|
return project_id
|
|
@@ -137,6 +141,10 @@ def get_gcp_project():
|
|
|
137
141
|
project_id = get_metadata('project/project-id')
|
|
138
142
|
if project_id:
|
|
139
143
|
os.environ["GCP_PROJECT"] = project_id
|
|
144
|
+
return project_id
|
|
145
|
+
|
|
146
|
+
if not is_running_on_gcp():
|
|
147
|
+
return None
|
|
140
148
|
|
|
141
149
|
logging.warning("GCP Project ID not found. Ensure you are running on GCP or have the GCP_PROJECT environment variable set.")
|
|
142
150
|
return None
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: sunholo
|
|
3
|
-
Version: 0.62.
|
|
3
|
+
Version: 0.62.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.62.
|
|
6
|
+
Download-URL: https://github.com/sunholo-data/sunholo-py/archive/refs/tags/v0.62.5.tar.gz
|
|
7
7
|
Author: Holosun ApS
|
|
8
8
|
Author-email: multivac@sunholo.com
|
|
9
9
|
License: Apache License, Version 2.0
|
|
@@ -53,7 +53,6 @@ sunholo/cli/run_proxy.py
|
|
|
53
53
|
sunholo/cli/sun_rich.py
|
|
54
54
|
sunholo/components/__init__.py
|
|
55
55
|
sunholo/components/llm.py
|
|
56
|
-
sunholo/components/prompt.py
|
|
57
56
|
sunholo/components/retriever.py
|
|
58
57
|
sunholo/components/vectorstore.py
|
|
59
58
|
sunholo/database/__init__.py
|
|
@@ -96,6 +95,7 @@ sunholo/qna/retry.py
|
|
|
96
95
|
sunholo/streaming/__init__.py
|
|
97
96
|
sunholo/streaming/content_buffer.py
|
|
98
97
|
sunholo/streaming/langserve.py
|
|
98
|
+
sunholo/streaming/stream_lookup.py
|
|
99
99
|
sunholo/streaming/streaming.py
|
|
100
100
|
sunholo/summarise/__init__.py
|
|
101
101
|
sunholo/summarise/summarise.py
|
|
@@ -1,151 +0,0 @@
|
|
|
1
|
-
# Copyright [2024] [Holosun ApS]
|
|
2
|
-
#
|
|
3
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
-
# you may not use this file except in compliance with the License.
|
|
5
|
-
# You may obtain a copy of the License at
|
|
6
|
-
#
|
|
7
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
-
#
|
|
9
|
-
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
-
# See the License for the specific language governing permissions and
|
|
13
|
-
# limitations under the License.
|
|
14
|
-
from ..logging import log
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
import datetime
|
|
18
|
-
|
|
19
|
-
from langchain.prompts.prompt import PromptTemplate
|
|
20
|
-
|
|
21
|
-
from ..utils import load_config_key
|
|
22
|
-
from .vectorstore import pick_vectorstore
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
def pick_prompt(vector_name, chat_history=[]):
|
|
26
|
-
"""Pick a custom prompt"""
|
|
27
|
-
log.debug('Picking prompt')
|
|
28
|
-
|
|
29
|
-
prompt_str = load_config_key("prompt", vector_name, filename = "config/llm_config.yaml")
|
|
30
|
-
|
|
31
|
-
the_date = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S %Z')
|
|
32
|
-
prompt_str_default = f"""You are Edmonbrain the chat bot created by Mark Edmondson. It is now {the_date}.
|
|
33
|
-
Use your memory to answer the question at the end.
|
|
34
|
-
Indicate in your reply how sure you are about your answer, for example whether you are certain, taking your best guess, or its very speculative.
|
|
35
|
-
|
|
36
|
-
If you don't know, just say you don't know - don't make anything up. Avoid generic boilerplate answers.
|
|
37
|
-
Consider why the question was asked, and offer follow up questions linked to those reasons.
|
|
38
|
-
Any questions about how you work should direct users to issue the `!help` command.
|
|
39
|
-
"""
|
|
40
|
-
if prompt_str is not None:
|
|
41
|
-
if "{context}" in prompt_str:
|
|
42
|
-
raise ValueError("prompt must not contain a string '{context}'")
|
|
43
|
-
if "{question}" in prompt_str:
|
|
44
|
-
raise ValueError("prompt must not contain a string '{question}'")
|
|
45
|
-
prompt_str_default = prompt_str_default + "\n" + prompt_str
|
|
46
|
-
|
|
47
|
-
chat_summary = ""
|
|
48
|
-
original_question = ""
|
|
49
|
-
if len(chat_history) != 0:
|
|
50
|
-
original_question = chat_history[0][0]
|
|
51
|
-
chat_summary = get_chat_history(chat_history, vector_name)
|
|
52
|
-
|
|
53
|
-
follow_up = "\nIf you can't answer the human's question without more information, ask a follow up question"
|
|
54
|
-
|
|
55
|
-
agent_buddy, agent_description = pick_chat_buddy(vector_name)
|
|
56
|
-
if agent_buddy:
|
|
57
|
-
follow_up += f""" either to the human, or to your friend bot.
|
|
58
|
-
You bot friend will reply back to you within your chat history.
|
|
59
|
-
Ask {agent_buddy} for help with topics: {agent_description}
|
|
60
|
-
Ask clarification questions to the human and wait for response if your friend bot can't help.
|
|
61
|
-
Don't repeat the question if you can see the answer in the chat history (from any source)
|
|
62
|
-
This means there are three people in this conversation - you, the human and your assistant bot.
|
|
63
|
-
Asking questions to your friend bot are only allowed with this format:
|
|
64
|
-
€€Question€€
|
|
65
|
-
(your question here, including all required information needed to answer the question fully)
|
|
66
|
-
Can you help, {agent_buddy} , with the above question?
|
|
67
|
-
€€End Question€€
|
|
68
|
-
"""
|
|
69
|
-
else:
|
|
70
|
-
follow_up += ".\n"
|
|
71
|
-
|
|
72
|
-
memory_str = "\n## Your Memory (ignore if not relevant to question)\n{context}\n"
|
|
73
|
-
|
|
74
|
-
current_conversation = ""
|
|
75
|
-
if chat_summary != "":
|
|
76
|
-
current_conversation =f"## Current Conversation\n{chat_summary}\n"
|
|
77
|
-
current_conversation = current_conversation.replace("{","{{").replace("}","}}") #escape {} characters
|
|
78
|
-
|
|
79
|
-
buddy_question = ""
|
|
80
|
-
my_q = "## Current Question\n{question}\n"
|
|
81
|
-
if agent_buddy:
|
|
82
|
-
buddy_question = f"""(Including, if needed, your question to {agent_buddy})"""
|
|
83
|
-
my_q = f"## Original Question that started conversation\n{original_question}\n" + my_q
|
|
84
|
-
|
|
85
|
-
prompt_template = prompt_str_default + follow_up + memory_str + current_conversation + my_q + buddy_question + "\n## Your response:\n"
|
|
86
|
-
|
|
87
|
-
log.debug(f"--Prompt_template: {prompt_template}")
|
|
88
|
-
QA_PROMPT = PromptTemplate(
|
|
89
|
-
template=prompt_template, input_variables=["context", "question"]
|
|
90
|
-
)
|
|
91
|
-
|
|
92
|
-
return QA_PROMPT
|
|
93
|
-
|
|
94
|
-
def pick_chat_buddy(vector_name):
|
|
95
|
-
chat_buddy = load_config_key("chat_buddy", vector_name, filename = "config/llm_config.yaml")
|
|
96
|
-
if chat_buddy is not None:
|
|
97
|
-
log.info(f"Got chat buddy {chat_buddy} for {vector_name}")
|
|
98
|
-
buddy_description = load_config_key("chat_buddy_description", vector_name)
|
|
99
|
-
return chat_buddy, buddy_description
|
|
100
|
-
return None, None
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
def pick_agent(vector_name):
|
|
104
|
-
agent_str = load_config_key("agent", vector_name, filename = "config/llm_config.yaml")
|
|
105
|
-
if agent_str == "yes":
|
|
106
|
-
return True
|
|
107
|
-
|
|
108
|
-
return False
|
|
109
|
-
|
|
110
|
-
def pick_shared_vectorstore(vector_name, embeddings):
|
|
111
|
-
shared_vectorstore = load_config_key("shared_vectorstore", vector_name, filename = "config/llm_config.yaml")
|
|
112
|
-
vectorstore = pick_vectorstore(shared_vectorstore, embeddings)
|
|
113
|
-
return vectorstore
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
def get_chat_history(inputs, vector_name, last_chars=1000, summary_chars=1500) -> str:
|
|
117
|
-
from langchain.schema import Document
|
|
118
|
-
from ..summarise import summarise_docs
|
|
119
|
-
|
|
120
|
-
# Prepare the full chat history
|
|
121
|
-
res = []
|
|
122
|
-
for human, ai in inputs:
|
|
123
|
-
res.append(f"Human:{human}\nAI:{ai}")
|
|
124
|
-
full_history = "\n".join(res)
|
|
125
|
-
|
|
126
|
-
# Get the last `last_chars` characters of the full chat history
|
|
127
|
-
last_bits = []
|
|
128
|
-
for human, ai in reversed(inputs):
|
|
129
|
-
add_me = f"Human:{human}\nAI:{ai}"
|
|
130
|
-
last_bits.append(add_me)
|
|
131
|
-
|
|
132
|
-
recent_history = "\n".join(reversed(last_bits))
|
|
133
|
-
recent_history = recent_history[-last_chars:]
|
|
134
|
-
log.info(f"Recent chat history: {recent_history}")
|
|
135
|
-
|
|
136
|
-
# Summarize chat history too
|
|
137
|
-
remaining_history = full_history
|
|
138
|
-
log.info(f"Remaining chat history: {remaining_history}")
|
|
139
|
-
doc_history = Document(page_content=remaining_history)
|
|
140
|
-
chat_summary = summarise_docs([doc_history], vector_name=vector_name, skip_if_less=last_chars)
|
|
141
|
-
text_sum = ""
|
|
142
|
-
for summ in chat_summary:
|
|
143
|
-
text_sum += summ.page_content + "\n"
|
|
144
|
-
|
|
145
|
-
log.info(f"Conversation Summary: {text_sum}")
|
|
146
|
-
|
|
147
|
-
# Make sure the summary is not longer than `summary_chars` characters
|
|
148
|
-
summary = text_sum[:summary_chars]
|
|
149
|
-
|
|
150
|
-
# Concatenate the summary and the last `last_chars` characters of the chat history
|
|
151
|
-
return summary + "\n### Recent Chat History\n..." + recent_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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|