sunholo 0.60.5__tar.gz → 0.60.8__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 (112) hide show
  1. {sunholo-0.60.5 → sunholo-0.60.8}/PKG-INFO +2 -2
  2. {sunholo-0.60.5 → sunholo-0.60.8}/setup.py +1 -1
  3. sunholo-0.60.8/sunholo/cli/chat_vac.py +301 -0
  4. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/cli/run_proxy.py +7 -62
  5. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo.egg-info/PKG-INFO +2 -2
  6. sunholo-0.60.5/sunholo/cli/chat_vac.py +0 -189
  7. {sunholo-0.60.5 → sunholo-0.60.8}/LICENSE.txt +0 -0
  8. {sunholo-0.60.5 → sunholo-0.60.8}/MANIFEST.in +0 -0
  9. {sunholo-0.60.5 → sunholo-0.60.8}/README.md +0 -0
  10. {sunholo-0.60.5 → sunholo-0.60.8}/setup.cfg +0 -0
  11. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/__init__.py +0 -0
  12. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/agents/__init__.py +0 -0
  13. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/agents/chat_history.py +0 -0
  14. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/agents/dispatch_to_qa.py +0 -0
  15. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/agents/fastapi/__init__.py +0 -0
  16. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/agents/fastapi/base.py +0 -0
  17. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/agents/fastapi/qna_routes.py +0 -0
  18. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/agents/flask/__init__.py +0 -0
  19. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/agents/flask/base.py +0 -0
  20. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/agents/flask/qna_routes.py +0 -0
  21. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/agents/langserve.py +0 -0
  22. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/agents/pubsub.py +0 -0
  23. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/agents/route.py +0 -0
  24. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/agents/special_commands.py +0 -0
  25. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/agents/test_chat_history.py +0 -0
  26. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/archive/__init__.py +0 -0
  27. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/archive/archive.py +0 -0
  28. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/auth/__init__.py +0 -0
  29. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/auth/run.py +0 -0
  30. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/bots/__init__.py +0 -0
  31. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/bots/discord.py +0 -0
  32. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/bots/github_webhook.py +0 -0
  33. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/bots/webapp.py +0 -0
  34. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/chunker/__init__.py +0 -0
  35. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/chunker/data_to_embed_pubsub.py +0 -0
  36. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/chunker/doc_handling.py +0 -0
  37. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/chunker/images.py +0 -0
  38. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/chunker/loaders.py +0 -0
  39. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/chunker/message_data.py +0 -0
  40. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/chunker/pdfs.py +0 -0
  41. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/chunker/publish.py +0 -0
  42. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/chunker/splitter.py +0 -0
  43. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/cli/__init__.py +0 -0
  44. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/cli/cli.py +0 -0
  45. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/cli/cli_init.py +0 -0
  46. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/cli/configs.py +0 -0
  47. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/cli/deploy.py +0 -0
  48. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/cli/merge_texts.py +0 -0
  49. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/cli/sun_rich.py +0 -0
  50. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/components/__init__.py +0 -0
  51. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/components/llm.py +0 -0
  52. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/components/prompt.py +0 -0
  53. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/components/retriever.py +0 -0
  54. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/components/vectorstore.py +0 -0
  55. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/database/__init__.py +0 -0
  56. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/database/alloydb.py +0 -0
  57. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/database/database.py +0 -0
  58. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/database/lancedb.py +0 -0
  59. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/database/sql/sb/create_function.sql +0 -0
  60. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/database/sql/sb/create_function_time.sql +0 -0
  61. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/database/sql/sb/create_table.sql +0 -0
  62. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/database/sql/sb/delete_source_row.sql +0 -0
  63. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/database/sql/sb/return_sources.sql +0 -0
  64. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/database/sql/sb/setup.sql +0 -0
  65. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/database/static_dbs.py +0 -0
  66. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/database/uuid.py +0 -0
  67. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/embedder/__init__.py +0 -0
  68. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/embedder/embed_chunk.py +0 -0
  69. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/gcs/__init__.py +0 -0
  70. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/gcs/add_file.py +0 -0
  71. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/gcs/download_url.py +0 -0
  72. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/gcs/metadata.py +0 -0
  73. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/langfuse/__init__.py +0 -0
  74. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/langfuse/callback.py +0 -0
  75. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/langfuse/prompts.py +0 -0
  76. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/llamaindex/__init__.py +0 -0
  77. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/llamaindex/generate.py +0 -0
  78. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/llamaindex/import_files.py +0 -0
  79. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/logging.py +0 -0
  80. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/lookup/__init__.py +0 -0
  81. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/lookup/model_lookup.yaml +0 -0
  82. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/patches/__init__.py +0 -0
  83. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/patches/langchain/__init__.py +0 -0
  84. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/patches/langchain/lancedb.py +0 -0
  85. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/patches/langchain/vertexai.py +0 -0
  86. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/pubsub/__init__.py +0 -0
  87. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/pubsub/process_pubsub.py +0 -0
  88. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/pubsub/pubsub_manager.py +0 -0
  89. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/qna/__init__.py +0 -0
  90. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/qna/parsers.py +0 -0
  91. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/qna/retry.py +0 -0
  92. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/streaming/__init__.py +0 -0
  93. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/streaming/content_buffer.py +0 -0
  94. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/streaming/langserve.py +0 -0
  95. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/streaming/streaming.py +0 -0
  96. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/summarise/__init__.py +0 -0
  97. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/summarise/summarise.py +0 -0
  98. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/utils/__init__.py +0 -0
  99. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/utils/big_context.py +0 -0
  100. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/utils/config.py +0 -0
  101. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/utils/config_schema.py +0 -0
  102. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/utils/gcp.py +0 -0
  103. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/utils/parsers.py +0 -0
  104. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/utils/user_ids.py +0 -0
  105. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/vertex/__init__.py +0 -0
  106. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo/vertex/init_vertex.py +0 -0
  107. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo.egg-info/SOURCES.txt +0 -0
  108. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo.egg-info/dependency_links.txt +0 -0
  109. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo.egg-info/entry_points.txt +0 -0
  110. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo.egg-info/requires.txt +0 -0
  111. {sunholo-0.60.5 → sunholo-0.60.8}/sunholo.egg-info/top_level.txt +0 -0
  112. {sunholo-0.60.5 → sunholo-0.60.8}/test/test_dispatch_to_qa.py +0 -0
@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: sunholo
3
- Version: 0.60.5
3
+ Version: 0.60.8
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.60.5.tar.gz
6
+ Download-URL: https://github.com/sunholo-data/sunholo-py/archive/refs/tags/v0.60.8.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.60.5'
4
+ version = '0.60.8'
5
5
 
6
6
  setup(
7
7
  name='sunholo',
@@ -0,0 +1,301 @@
1
+ from ..agents import send_to_qa
2
+ from ..streaming import generate_proxy_stream
3
+ from ..utils.user_ids import generate_user_id
4
+ from ..utils.config import load_config_key
5
+
6
+ from .run_proxy import clean_proxy_list, start_proxy, stop_proxy
7
+
8
+ import uuid
9
+ import sys
10
+ import subprocess
11
+ import json
12
+
13
+ from rich import print
14
+ from .sun_rich import console
15
+
16
+ from rich.prompt import Prompt
17
+ from rich.panel import Panel
18
+ from rich.text import Text
19
+ from rich.table import Table
20
+
21
+
22
+ def get_service_url(vac_name, project, region):
23
+ agent_name = load_config_key("agent", vac_name, kind="vacConfig")
24
+ proxies = clean_proxy_list()
25
+ if agent_name in proxies:
26
+ port = proxies[agent_name]['port']
27
+ url = f"http://127.0.0.1:{port}"
28
+ else:
29
+ print(f"No proxy found running for service: {agent_name} required for {vac_name} - attempting to connect")
30
+ url = start_proxy(agent_name, region, project)
31
+
32
+ return url
33
+
34
+ def stream_chat_session(service_url, service_name):
35
+
36
+ user_id = generate_user_id()
37
+ chat_history = []
38
+ while True:
39
+ session_id = str(uuid.uuid4())
40
+ user_input = Prompt.ask("[bold cyan]You[/bold cyan]")
41
+ if user_input.lower() in ["exit", "quit"]:
42
+ console.print("[bold red]Exiting chat session.[/bold red]")
43
+ break
44
+
45
+ def stream_response():
46
+ generate = generate_proxy_stream(
47
+ send_to_qa,
48
+ user_input,
49
+ vector_name=service_name,
50
+ chat_history=chat_history,
51
+ generate_f_output=lambda x: x, # Replace with actual processing function
52
+ stream_wait_time=0.5,
53
+ stream_timeout=120,
54
+ message_author=user_id,
55
+ #TODO: populate these
56
+ image_url=None,
57
+ source_filters=None,
58
+ search_kwargs=None,
59
+ private_docs=None,
60
+ whole_document=False,
61
+ source_filters_and_or=False,
62
+ # system kwargs
63
+ configurable={
64
+ "vector_name": service_name,
65
+ },
66
+ user_id=user_id,
67
+ session_id=session_id,
68
+ message_source="cli",
69
+ override_endpoint=service_url
70
+ )
71
+ for part in generate():
72
+ yield part
73
+
74
+ response_started = False
75
+ vac_response = ""
76
+
77
+ # point or star?
78
+ with console.status("[bold orange]Thinking...[/bold orange]", spinner="star") as status:
79
+ for token in stream_response():
80
+ if not response_started:
81
+ status.stop()
82
+ console.print(f"[bold yellow]{service_name}:[/bold yellow] ", end='')
83
+ response_started = True
84
+
85
+ if isinstance(token, bytes):
86
+ token = token.decode('utf-8')
87
+ console.print(token, end='')
88
+ vac_response += token
89
+
90
+ chat_history.append({"name": "Human", "content": user_input})
91
+ chat_history.append({"name": "AI", "content": vac_response})
92
+ response_started = False
93
+ console.print()
94
+ console.rule()
95
+
96
+ def headless_mode(service_url, service_name, user_input, chat_history=None):
97
+ chat_history = chat_history or []
98
+
99
+ user_id = generate_user_id()
100
+ session_id = str(uuid.uuid4())
101
+
102
+ def stream_response():
103
+ generate = generate_proxy_stream(
104
+ send_to_qa,
105
+ user_input,
106
+ vector_name=service_name,
107
+ chat_history=chat_history,
108
+ generate_f_output=lambda x: x, # Replace with actual processing function
109
+ stream_wait_time=0.5,
110
+ stream_timeout=120,
111
+ message_author=user_id,
112
+ #TODO: populate these
113
+ image_url=None,
114
+ source_filters=None,
115
+ search_kwargs=None,
116
+ private_docs=None,
117
+ whole_document=False,
118
+ source_filters_and_or=False,
119
+ # system kwargs
120
+ configurable={
121
+ "vector_name": service_name,
122
+ },
123
+ user_id=user_id,
124
+ session_id=session_id,
125
+ message_source="cli",
126
+ override_endpoint=service_url
127
+ )
128
+ for part in generate():
129
+ yield part
130
+
131
+ vac_response = ""
132
+
133
+ for token in stream_response():
134
+ if isinstance(token, bytes):
135
+ token = token.decode('utf-8')
136
+ print(token, end='', flush=True)
137
+ vac_response += token
138
+
139
+ if vac_response:
140
+ chat_history.append({"name": "Human", "content": user_input})
141
+ chat_history.append({"name": "AI", "content": vac_response})
142
+ print() # For new line after streaming ends
143
+
144
+ return chat_history
145
+
146
+
147
+ def vac_command(args):
148
+ if args.action == 'list':
149
+ list_cloud_run_services(args.project, args.region)
150
+ return
151
+ elif args.action == 'get-url':
152
+ service_url = get_cloud_run_service_url(args.project, args.region, args.vac_name)
153
+ if service_url:
154
+ console.print(service_url)
155
+ return
156
+ elif args.action == 'chat':
157
+
158
+ if not args.no_proxy:
159
+ try:
160
+ service_url = get_service_url(args.vac_name, args.project, args.region)
161
+ except ValueError as e:
162
+ console.print(f"[bold red]ERROR: Could not start {args.vac_name} proxy URL: {str(e)}[/bold red]")
163
+ sys.exit(1)
164
+ else:
165
+ service_url = get_cloud_run_service_url(args.project, args.region, args.vac_name)
166
+ console.print(f"Not using a proxy, connecting directly to {service_url}")
167
+
168
+ agent_name = load_config_key("agent", args.vac_name, kind="vacConfig")
169
+
170
+ if args.headless:
171
+ headless_mode(service_url, args.vac_name, args.user_input, args.chat_history)
172
+ else:
173
+ display_name = load_config_key("display_name", vector_name=args.vac_name, kind="vacConfig")
174
+ description = load_config_key("description", vector_name=args.vac_name, kind="vacConfig")
175
+
176
+ if agent_name == "langserve":
177
+ subtitle = f"{service_url}/{args.vac_name}/playground/"
178
+ else:
179
+ subtitle = f"{agent_name} - {service_url}/vac/{args.vac_name}"
180
+
181
+ print(
182
+ Panel(description or "Starting VAC chat session",
183
+ title=display_name or args.vac_name,
184
+ subtitle=subtitle)
185
+ )
186
+
187
+ stream_chat_session(service_url, args.vac_name)
188
+
189
+ stop_proxy(agent_name)
190
+
191
+
192
+ def list_cloud_run_services(project, region):
193
+ """
194
+ Lists all Cloud Run services the user has access to in a specific project and region.
195
+
196
+ Args:
197
+ project (str): The GCP project ID.
198
+ region (str): The region of the Cloud Run services.
199
+ """
200
+
201
+ # point or star?
202
+ with console.status("[bold orange]Listing Cloud Run Services[/bold orange]", spinner="star") as status:
203
+ try:
204
+ result = subprocess.run(
205
+ ["gcloud", "run", "services", "list", "--project", project, "--region", region, "--format=json"],
206
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=30
207
+ )
208
+ if result.returncode != 0:
209
+ status.stop()
210
+ console.print(f"[bold red]ERROR: Unable to list Cloud Run services: {result.stderr.decode()}[/bold red]")
211
+ return
212
+
213
+ services = json.loads(result.stdout.decode())
214
+ if not services:
215
+ status.stop()
216
+ console.print("[bold red]No Cloud Run services found.[/bold red]")
217
+ return
218
+
219
+ proxies = clean_proxy_list()
220
+ status.stop()
221
+
222
+ table = Table(title="VAC Cloud Run Services")
223
+ table.add_column("Service Name")
224
+ table.add_column("Region")
225
+ table.add_column("URL")
226
+ table.add_column("Proxied")
227
+ table.add_column("Port")
228
+
229
+ for service in services:
230
+ service_name = service['metadata']['name']
231
+ service_url = service['status']['url']
232
+ if service_name in proxies:
233
+ proxied = "Yes"
234
+ proxy_port = proxies[service_name]['port']
235
+ else:
236
+ proxied = "No"
237
+ proxy_port = "-"
238
+ table.add_row(service_name, region, service_url, proxied, str(proxy_port))
239
+
240
+ console.print(table)
241
+ except Exception as e:
242
+ status.stop()
243
+ console.print(f"[bold red]ERROR: An unexpected error occurred: {e}[/bold red]")
244
+
245
+
246
+ def get_cloud_run_service_url(project, region, service_name):
247
+ """
248
+ Retrieves the URL of a specific Cloud Run service in a given project and region.
249
+
250
+ Args:
251
+ project (str): The GCP project ID.
252
+ region (str): The region of the Cloud Run service.
253
+ service_name (str): The name of the Cloud Run service.
254
+
255
+ Returns:
256
+ str: The URL of the Cloud Run service, or an error message if not found.
257
+ """
258
+ try:
259
+ result = subprocess.run(
260
+ ["gcloud", "run", "services", "describe", service_name, "--project", project, "--region", region, "--format=json"],
261
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=30
262
+ )
263
+ if result.returncode != 0:
264
+ console.print(f"[bold red]ERROR: Unable to get Cloud Run service URL: {result.stderr.decode()}[/bold red]")
265
+ return None
266
+
267
+ service = json.loads(result.stdout.decode())
268
+ service_url = service['status']['url']
269
+ return service_url
270
+ except Exception as e:
271
+ console.print(f"[bold red]ERROR: An unexpected error occurred: {e}[/bold red]")
272
+ return None
273
+
274
+
275
+
276
+ def setup_vac_subparser(subparsers):
277
+ """
278
+ Sets up an argparse subparser for the 'vac' command.
279
+
280
+ Args:
281
+ subparsers: The subparsers object from argparse.ArgumentParser().
282
+ """
283
+ vac_parser = subparsers.add_parser('vac', help='Interact with deployed VAC services.')
284
+ vac_subparsers = vac_parser.add_subparsers(dest='action', help='VAC subcommands')
285
+
286
+ # Subcommand for listing VAC services
287
+ list_parser = vac_subparsers.add_parser('list', help='List all VAC services.')
288
+
289
+ # Subcommand for getting the URL of a specific VAC service
290
+ get_url_parser = vac_subparsers.add_parser('get-url', help='Get the URL of a specific VAC service.')
291
+ get_url_parser.add_argument('vac_name', help='Name of the VAC service.')
292
+
293
+ # Subcommand for interacting with a VAC service
294
+ chat_parser = vac_subparsers.add_parser('chat', help='Interact with a VAC service.')
295
+ chat_parser.add_argument('vac_name', help='Name of the VAC service.')
296
+ chat_parser.add_argument('user_input', help='User input for the VAC service when in headless mode.', nargs='?', default=None)
297
+ chat_parser.add_argument('--headless', action='store_true', help='Run in headless mode.')
298
+ chat_parser.add_argument('--chat_history', help='Chat history for headless mode (as JSON string).', default=None)
299
+ chat_parser.add_argument('--no-proxy', action='store_true', help='Do not use the proxy and connect directly to the VAC service.')
300
+
301
+ vac_parser.set_defaults(func=vac_command)
@@ -109,7 +109,7 @@ def start_proxy(service_name, region, project, port=None):
109
109
  proxies = clean_proxy_list()
110
110
 
111
111
  if service_name in proxies:
112
- print(f"Proxy for service {service_name} is already running on port {proxies[service_name]['port']}.")
112
+ console.print(f"Proxy for service [bold orange]'{service_name}'[/bold orange] is already running on port {proxies[service_name]['port']}.")
113
113
  return
114
114
 
115
115
  if not port:
@@ -130,7 +130,7 @@ def start_proxy(service_name, region, project, port=None):
130
130
  }
131
131
  save_proxies(proxies)
132
132
 
133
- print(f"Proxy for {service_name} setup complete on port {port}")
133
+ console.print(f"Proxy for [bold orange]'{service_name}'[/bold orange] setup complete on port {port}")
134
134
  list_proxies()
135
135
 
136
136
  return f"http://127.0.0.1:{port}"
@@ -154,11 +154,11 @@ def stop_proxy(service_name):
154
154
  os.kill(pid, signal.SIGTERM)
155
155
  del proxies[service_name]
156
156
  save_proxies(proxies)
157
- print(f"Proxy for {service_name} stopped.")
157
+ console.print(f"Proxy for [bold orange]'{service_name}'[bold orange] stopped.")
158
158
  except ProcessLookupError:
159
- print(f"No process found with PID: {pid}")
159
+ console.print(f"No process found with PID: {pid}")
160
160
  except Exception as e:
161
- print(f"Error stopping proxy for {service_name}: {e}")
161
+ console.print(f"[bold red]Error stopping proxy for {service_name}: {e}[/bold red]")
162
162
 
163
163
  list_proxies()
164
164
 
@@ -172,69 +172,16 @@ def stop_all_proxies():
172
172
  pid = info["pid"]
173
173
  try:
174
174
  os.kill(pid, signal.SIGTERM)
175
- print(f"Proxy for {service_name} stopped.")
175
+ print(f"Proxy for [bold orange]'{service_name}'[/bold orange] stopped.")
176
176
  except ProcessLookupError:
177
177
  print(f"No process found with PID: {pid}")
178
178
  except Exception as e:
179
- print(f"Error stopping proxy for {service_name}: {e}")
179
+ print(f"Error stopping proxy for [bold orange]'{service_name}'[/bold orange]: {e}")
180
180
 
181
181
  save_proxies({})
182
182
 
183
183
  list_proxies()
184
184
 
185
- def list_cloud_run_services(project, region):
186
- """
187
- Lists all Cloud Run services the user has access to in a specific project and region.
188
-
189
- Args:
190
- project (str): The GCP project ID.
191
- region (str): The region of the Cloud Run services.
192
- """
193
-
194
- # point or star?
195
- with console.status("[bold orange]Listing Cloud Run Services[/bold orange]", spinner="star") as status:
196
- try:
197
- result = subprocess.run(
198
- ["gcloud", "run", "services", "list", "--project", project, "--region", region, "--format=json"],
199
- stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=30
200
- )
201
- if result.returncode != 0:
202
- status.stop()
203
- console.print(f"[bold red]ERROR: Unable to list Cloud Run services: {result.stderr.decode()}[/bold red]")
204
- return
205
-
206
- services = json.loads(result.stdout.decode())
207
- if not services:
208
- status.stop()
209
- console.print("[bold red]No Cloud Run services found.[/bold red]")
210
- return
211
-
212
- proxies = clean_proxy_list()
213
- status.stop()
214
-
215
- table = Table(title="VAC Cloud Run Services")
216
- table.add_column("Service Name")
217
- table.add_column("Region")
218
- table.add_column("URL")
219
- table.add_column("Proxied")
220
- table.add_column("Port")
221
-
222
- for service in services:
223
- service_name = service['metadata']['name']
224
- service_url = service['status']['url']
225
- if service_name in proxies:
226
- proxied = "Yes"
227
- proxy_port = proxies[service_name]['port']
228
- else:
229
- proxied = "No"
230
- proxy_port = "-"
231
- table.add_row(service_name, region, service_url, proxied, str(proxy_port))
232
-
233
- console.print(table)
234
- except Exception as e:
235
- status.stop()
236
- console.print(f"[bold red]ERROR: An unexpected error occurred: {e}[/bold red]")
237
-
238
185
  def list_proxies():
239
186
  """
240
187
  Lists all running proxies.
@@ -283,7 +230,5 @@ def setup_proxy_subparser(subparsers):
283
230
  stop_all_parser = proxy_subparsers.add_parser('stop-all', help='Stop all running proxies.')
284
231
  stop_all_parser.set_defaults(func=lambda args: stop_all_proxies())
285
232
 
286
- list_services_parser = proxy_subparsers.add_parser('list-vacs', help='List all Cloud Run VAC services.')
287
- list_services_parser.set_defaults(func=lambda args: list_cloud_run_services(args.project, args.region))
288
233
 
289
234
 
@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: sunholo
3
- Version: 0.60.5
3
+ Version: 0.60.8
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.60.5.tar.gz
6
+ Download-URL: https://github.com/sunholo-data/sunholo-py/archive/refs/tags/v0.60.8.tar.gz
7
7
  Author: Holosun ApS
8
8
  Author-email: multivac@sunholo.com
9
9
  License: Apache License, Version 2.0
@@ -1,189 +0,0 @@
1
- from ..agents import send_to_qa
2
- from ..streaming import generate_proxy_stream
3
- from ..utils.user_ids import generate_user_id
4
- from ..utils.config import load_config_key
5
-
6
- from .run_proxy import clean_proxy_list, start_proxy, stop_proxy
7
-
8
- import uuid
9
- import sys
10
-
11
- from rich import print
12
- from .sun_rich import console
13
-
14
- from rich.prompt import Prompt
15
- from rich.panel import Panel
16
- from rich.text import Text
17
-
18
-
19
- def get_service_url(vac_name, project, region):
20
- agent_name = load_config_key("agent", vac_name, kind="vacConfig")
21
- proxies = clean_proxy_list()
22
- if agent_name in proxies:
23
- port = proxies[agent_name]['port']
24
- url = f"http://127.0.0.1:{port}"
25
- else:
26
- print(f"No proxy found running for service: {agent_name} required for {vac_name} - attempting to connect")
27
- url = start_proxy(agent_name, region, project)
28
-
29
- return url
30
-
31
- def stream_chat_session(service_name, project, region):
32
-
33
- service_url = get_service_url(service_name, project, region)
34
- user_id = generate_user_id()
35
- chat_history = []
36
- while True:
37
- session_id = str(uuid.uuid4())
38
- user_input = Prompt.ask("[bold cyan]You[/bold cyan]")
39
- if user_input.lower() in ["exit", "quit"]:
40
- console.print("[bold red]Exiting chat session.[/bold red]")
41
- break
42
-
43
- def stream_response():
44
- generate = generate_proxy_stream(
45
- send_to_qa,
46
- user_input,
47
- vector_name=service_name,
48
- chat_history=chat_history,
49
- generate_f_output=lambda x: x, # Replace with actual processing function
50
- stream_wait_time=0.5,
51
- stream_timeout=120,
52
- message_author=user_id,
53
- #TODO: populate these
54
- image_url=None,
55
- source_filters=None,
56
- search_kwargs=None,
57
- private_docs=None,
58
- whole_document=False,
59
- source_filters_and_or=False,
60
- # system kwargs
61
- configurable={
62
- "vector_name": service_name,
63
- },
64
- user_id=user_id,
65
- session_id=session_id,
66
- message_source="cli",
67
- override_endpoint=service_url
68
- )
69
- for part in generate():
70
- yield part
71
-
72
- response_started = False
73
- vac_response = ""
74
-
75
- # point or star?
76
- with console.status("[bold orange]Thinking...[/bold orange]", spinner="star") as status:
77
- for token in stream_response():
78
- if not response_started:
79
- status.stop()
80
- console.print(f"[bold yellow]{service_name}:[/bold yellow] ", end='')
81
- response_started = True
82
-
83
- if isinstance(token, bytes):
84
- token = token.decode('utf-8')
85
- console.print(token, end='')
86
- vac_response += token
87
-
88
- chat_history.append({"name": "Human", "content": user_input})
89
- chat_history.append({"name": "AI", "content": vac_response})
90
- response_started = False
91
- console.print()
92
- console.rule()
93
-
94
- def headless_mode(service_name, user_input, project, region, chat_history=None):
95
- chat_history = chat_history or []
96
-
97
- service_url = get_service_url(service_name, project, region)
98
- user_id = generate_user_id()
99
- session_id = str(uuid.uuid4())
100
-
101
- def stream_response():
102
- generate = generate_proxy_stream(
103
- send_to_qa,
104
- user_input,
105
- vector_name=service_name,
106
- chat_history=chat_history,
107
- generate_f_output=lambda x: x, # Replace with actual processing function
108
- stream_wait_time=0.5,
109
- stream_timeout=120,
110
- message_author=user_id,
111
- #TODO: populate these
112
- image_url=None,
113
- source_filters=None,
114
- search_kwargs=None,
115
- private_docs=None,
116
- whole_document=False,
117
- source_filters_and_or=False,
118
- # system kwargs
119
- configurable={
120
- "vector_name": service_name,
121
- },
122
- user_id=user_id,
123
- session_id=session_id,
124
- message_source="cli",
125
- override_endpoint=service_url
126
- )
127
- for part in generate():
128
- yield part
129
-
130
- vac_response = ""
131
-
132
- for token in stream_response():
133
- if isinstance(token, bytes):
134
- token = token.decode('utf-8')
135
- print(token, end='', flush=True)
136
- vac_response += token
137
-
138
- if vac_response:
139
- chat_history.append({"name": "Human", "content": user_input})
140
- chat_history.append({"name": "AI", "content": vac_response})
141
- print() # For new line after streaming ends
142
-
143
- return chat_history
144
-
145
-
146
- def vac_command(args):
147
- try:
148
- service_url = get_service_url(args.vac_name, args.project, args.region)
149
- except ValueError as e:
150
- console.print(f"[bold red]ERROR: Could not start {args.vac_name} proxy URL: {str(e)}[/bold red]")
151
- sys.exit(1)
152
-
153
- agent_name = load_config_key("agent", args.vac_name, kind="vacConfig")
154
-
155
- if args.headless:
156
- headless_mode(args.vac_name, args.user_input, args.project, args.region, args.chat_history)
157
- stop_proxy(agent_name)
158
- else:
159
- display_name = load_config_key("display_name", vector_name=args.vac_name, kind="vacConfig")
160
- description = load_config_key("description", vector_name=args.vac_name, kind="vacConfig")
161
-
162
- if agent_name == "langserve":
163
- subtitle = f"{service_url}/{args.vac_name}/playground/"
164
- else:
165
- subtitle = f"{agent_name} - {service_url}/vac/{args.vac_name}"
166
-
167
- print(
168
- Panel(description or "Starting VAC chat session",
169
- title=display_name or args.vac_name,
170
- subtitle=subtitle)
171
- )
172
-
173
- stream_chat_session(args.vac_name, args.project, args.region)
174
- stop_proxy(agent_name)
175
-
176
-
177
- def setup_vac_subparser(subparsers):
178
- """
179
- Sets up an argparse subparser for the 'vac' command.
180
-
181
- Args:
182
- subparsers: The subparsers object from argparse.ArgumentParser().
183
- """
184
- vac_parser = subparsers.add_parser('vac', help='Interact with deployed VAC services.')
185
- vac_parser.add_argument('vac_name', help='Name of the VAC service.')
186
- vac_parser.add_argument('user_input', help='User input for the VAC service when in headless mode.', nargs='?', default=None)
187
- vac_parser.add_argument('--headless', action='store_true', help='Run in headless mode.')
188
- vac_parser.add_argument('--chat_history', help='Chat history for headless mode (as JSON string).', default=None)
189
- vac_parser.set_defaults(func=vac_command)
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