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.
Files changed (116) hide show
  1. {sunholo-0.62.3 → sunholo-0.62.5}/PKG-INFO +2 -2
  2. {sunholo-0.62.3 → sunholo-0.62.5}/setup.py +1 -1
  3. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/agents/dispatch_to_qa.py +7 -1
  4. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/agents/route.py +2 -9
  5. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/agents/special_commands.py +2 -0
  6. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/cli/chat_vac.py +83 -35
  7. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/cli/cli.py +0 -3
  8. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/components/__init__.py +0 -1
  9. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/embedder/embed_chunk.py +1 -1
  10. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/gcs/add_file.py +6 -2
  11. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/streaming/__init__.py +2 -1
  12. sunholo-0.62.5/sunholo/streaming/stream_lookup.py +12 -0
  13. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/utils/config.py +17 -6
  14. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/utils/gcp.py +11 -3
  15. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo.egg-info/PKG-INFO +2 -2
  16. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo.egg-info/SOURCES.txt +1 -1
  17. sunholo-0.62.3/sunholo/components/prompt.py +0 -151
  18. {sunholo-0.62.3 → sunholo-0.62.5}/LICENSE.txt +0 -0
  19. {sunholo-0.62.3 → sunholo-0.62.5}/MANIFEST.in +0 -0
  20. {sunholo-0.62.3 → sunholo-0.62.5}/README.md +0 -0
  21. {sunholo-0.62.3 → sunholo-0.62.5}/setup.cfg +0 -0
  22. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/__init__.py +0 -0
  23. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/agents/__init__.py +0 -0
  24. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/agents/chat_history.py +0 -0
  25. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/agents/fastapi/__init__.py +0 -0
  26. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/agents/fastapi/base.py +0 -0
  27. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/agents/fastapi/qna_routes.py +0 -0
  28. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/agents/flask/__init__.py +0 -0
  29. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/agents/flask/base.py +0 -0
  30. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/agents/flask/qna_routes.py +0 -0
  31. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/agents/langserve.py +0 -0
  32. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/agents/pubsub.py +0 -0
  33. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/archive/__init__.py +0 -0
  34. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/archive/archive.py +0 -0
  35. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/auth/__init__.py +0 -0
  36. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/auth/run.py +0 -0
  37. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/bots/__init__.py +0 -0
  38. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/bots/discord.py +0 -0
  39. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/bots/github_webhook.py +0 -0
  40. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/bots/webapp.py +0 -0
  41. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/chunker/__init__.py +0 -0
  42. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/chunker/data_to_embed_pubsub.py +0 -0
  43. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/chunker/doc_handling.py +0 -0
  44. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/chunker/images.py +0 -0
  45. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/chunker/loaders.py +0 -0
  46. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/chunker/message_data.py +0 -0
  47. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/chunker/pdfs.py +0 -0
  48. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/chunker/publish.py +0 -0
  49. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/chunker/splitter.py +0 -0
  50. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/cli/__init__.py +0 -0
  51. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/cli/cli_init.py +0 -0
  52. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/cli/configs.py +0 -0
  53. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/cli/deploy.py +0 -0
  54. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/cli/embedder.py +0 -0
  55. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/cli/merge_texts.py +0 -0
  56. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/cli/run_proxy.py +0 -0
  57. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/cli/sun_rich.py +0 -0
  58. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/components/llm.py +0 -0
  59. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/components/retriever.py +0 -0
  60. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/components/vectorstore.py +0 -0
  61. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/database/__init__.py +0 -0
  62. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/database/alloydb.py +0 -0
  63. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/database/database.py +0 -0
  64. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/database/lancedb.py +0 -0
  65. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/database/sql/sb/create_function.sql +0 -0
  66. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/database/sql/sb/create_function_time.sql +0 -0
  67. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/database/sql/sb/create_table.sql +0 -0
  68. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/database/sql/sb/delete_source_row.sql +0 -0
  69. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/database/sql/sb/return_sources.sql +0 -0
  70. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/database/sql/sb/setup.sql +0 -0
  71. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/database/static_dbs.py +0 -0
  72. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/database/uuid.py +0 -0
  73. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/embedder/__init__.py +0 -0
  74. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/gcs/__init__.py +0 -0
  75. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/gcs/download_url.py +0 -0
  76. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/gcs/metadata.py +0 -0
  77. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/langfuse/__init__.py +0 -0
  78. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/langfuse/callback.py +0 -0
  79. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/langfuse/prompts.py +0 -0
  80. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/llamaindex/__init__.py +0 -0
  81. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/llamaindex/generate.py +0 -0
  82. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/llamaindex/get_files.py +0 -0
  83. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/llamaindex/import_files.py +0 -0
  84. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/logging.py +0 -0
  85. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/lookup/__init__.py +0 -0
  86. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/lookup/model_lookup.yaml +0 -0
  87. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/patches/__init__.py +0 -0
  88. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/patches/langchain/__init__.py +0 -0
  89. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/patches/langchain/lancedb.py +0 -0
  90. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/patches/langchain/vertexai.py +0 -0
  91. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/pubsub/__init__.py +0 -0
  92. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/pubsub/process_pubsub.py +0 -0
  93. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/pubsub/pubsub_manager.py +0 -0
  94. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/qna/__init__.py +0 -0
  95. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/qna/parsers.py +0 -0
  96. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/qna/retry.py +0 -0
  97. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/streaming/content_buffer.py +0 -0
  98. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/streaming/langserve.py +0 -0
  99. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/streaming/streaming.py +0 -0
  100. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/summarise/__init__.py +0 -0
  101. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/summarise/summarise.py +0 -0
  102. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/utils/__init__.py +0 -0
  103. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/utils/big_context.py +0 -0
  104. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/utils/config_schema.py +0 -0
  105. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/utils/parsers.py +0 -0
  106. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/utils/timedelta.py +0 -0
  107. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/utils/user_ids.py +0 -0
  108. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/vertex/__init__.py +0 -0
  109. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/vertex/init.py +0 -0
  110. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo/vertex/memory_tools.py +0 -0
  111. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo.egg-info/dependency_links.txt +0 -0
  112. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo.egg-info/entry_points.txt +0 -0
  113. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo.egg-info/requires.txt +0 -0
  114. {sunholo-0.62.3 → sunholo-0.62.5}/sunholo.egg-info/top_level.txt +0 -0
  115. {sunholo-0.62.3 → sunholo-0.62.5}/tests/test_chat_history.py +0 -0
  116. {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
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.3.tar.gz
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
@@ -1,7 +1,7 @@
1
1
  from setuptools import setup, find_packages
2
2
 
3
3
  # Define your base version
4
- version = '0.62.3'
4
+ version = '0.62.5'
5
5
 
6
6
  setup(
7
7
  name='sunholo',
@@ -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
- qna_endpoint = endpoints["stream"] if stream else endpoints["invoke"]
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
- agent_config, _ = load_config('config/agent_config.yaml')
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
- def stream_response():
57
- generate = generate_proxy_stream(
58
- send_to_qa,
59
- user_input,
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
- for part in generate():
83
- yield part
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
- response_started = False
86
- vac_response = ""
87
-
88
- # point or star?
89
- with console.status("[bold orange]Thinking...[/bold orange]", spinner="star") as status:
90
- for token in stream_response():
91
- if not response_started:
92
- status.stop()
93
- console.print(f"[bold yellow]{service_name}:[/bold yellow] ", end='')
94
- response_started = True
95
-
96
- if isinstance(token, bytes):
97
- token = token.decode('utf-8')
98
- console.print(token, end='')
99
- vac_response += token
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
- response_started = False
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 = f"{agent_name} - {service_url}/vac/{args.vac_name}"
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.
@@ -1,4 +1,3 @@
1
1
  from .vectorstore import pick_vectorstore
2
2
  from .retriever import pick_retriever, load_memories
3
- from .prompt import pick_prompt
4
3
  from .llm import pick_llm, get_embeddings, get_llm, get_llm_chat, pick_embedding
@@ -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(datetime.UTC).isoformat(timespec='microseconds') + "Z"
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.warning("_CONFIG_FOLDER is not set, using os.getcwd() instead")
61
+ log.debug("_CONFIG_FOLDER is not set, using os.getcwd() instead")
62
62
  else:
63
- log.warning(f"_CONFIG_FOLDER set to: {os.getenv('_CONFIG_FOLDER')}")
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.info(f"Loading all configs from folder: {config_folder}")
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.info(f"Returning cached config for {filename} - recache in {format_timedelta(time_to_recache)}")
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.info(f"Loaded and cached {filename}")
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
- assert isinstance(key, str), f"key must be a string got a {type(key)}"
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
- if not is_running_on_gcp():
131
- return None
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
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.3.tar.gz
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