sunholo 0.60.3__py3-none-any.whl → 0.60.5__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
sunholo/cli/chat_vac.py CHANGED
@@ -3,9 +3,10 @@ from ..streaming import generate_proxy_stream
3
3
  from ..utils.user_ids import generate_user_id
4
4
  from ..utils.config import load_config_key
5
5
 
6
- from .run_proxy import clean_proxy_list, start_proxy
6
+ from .run_proxy import clean_proxy_list, start_proxy, stop_proxy
7
7
 
8
8
  import uuid
9
+ import sys
9
10
 
10
11
  from rich import print
11
12
  from .sun_rich import console
@@ -15,14 +16,17 @@ from rich.panel import Panel
15
16
  from rich.text import Text
16
17
 
17
18
 
18
- def get_service_url(service_name, project, region):
19
+ def get_service_url(vac_name, project, region):
20
+ agent_name = load_config_key("agent", vac_name, kind="vacConfig")
19
21
  proxies = clean_proxy_list()
20
- if service_name in proxies:
21
- port = proxies[service_name]['port']
22
- return f"http://127.0.0.1:{port}"
22
+ if agent_name in proxies:
23
+ port = proxies[agent_name]['port']
24
+ url = f"http://127.0.0.1:{port}"
23
25
  else:
24
- print(f"No proxy found running for service: {service_name} - attempting to connect")
25
- return start_proxy(service_name, region, project)
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
26
30
 
27
31
  def stream_chat_session(service_name, project, region):
28
32
 
@@ -36,8 +40,6 @@ def stream_chat_session(service_name, project, region):
36
40
  console.print("[bold red]Exiting chat session.[/bold red]")
37
41
  break
38
42
 
39
- chat_history.append({"role": "Human", "content": user_input})
40
-
41
43
  def stream_response():
42
44
  generate = generate_proxy_stream(
43
45
  send_to_qa,
@@ -83,15 +85,16 @@ def stream_chat_session(service_name, project, region):
83
85
  console.print(token, end='')
84
86
  vac_response += token
85
87
 
86
- chat_history.append({"role": "AI", "content": vac_response})
88
+ chat_history.append({"name": "Human", "content": user_input})
89
+ chat_history.append({"name": "AI", "content": vac_response})
87
90
  response_started = False
88
91
  console.print()
89
92
  console.rule()
90
93
 
91
94
  def headless_mode(service_name, user_input, project, region, chat_history=None):
92
95
  chat_history = chat_history or []
93
- chat_history.append({"role": "Human", "content": user_input})
94
- service_url = get_service_url(project, region)
96
+
97
+ service_url = get_service_url(service_name, project, region)
95
98
  user_id = generate_user_id()
96
99
  session_id = str(uuid.uuid4())
97
100
 
@@ -124,13 +127,17 @@ def headless_mode(service_name, user_input, project, region, chat_history=None):
124
127
  for part in generate():
125
128
  yield part
126
129
 
127
- print(f"VAC {service_name}: ", end='', flush=True)
130
+ vac_response = ""
131
+
128
132
  for token in stream_response():
129
133
  if isinstance(token, bytes):
130
134
  token = token.decode('utf-8')
131
135
  print(token, end='', flush=True)
136
+ vac_response += token
132
137
 
133
- chat_history.append({"role": "AI", "content": token})
138
+ if vac_response:
139
+ chat_history.append({"name": "Human", "content": user_input})
140
+ chat_history.append({"name": "AI", "content": vac_response})
134
141
  print() # For new line after streaming ends
135
142
 
136
143
  return chat_history
@@ -138,24 +145,34 @@ def headless_mode(service_name, user_input, project, region, chat_history=None):
138
145
 
139
146
  def vac_command(args):
140
147
  try:
141
- service_url = get_service_url(args.service_name, args.project, args.region)
148
+ service_url = get_service_url(args.vac_name, args.project, args.region)
142
149
  except ValueError as e:
143
- console.print(f"[bold red]ERROR: Could not start {args.service_name} proxy URL: {str(e)}[/bold red]")
144
- return
145
-
146
- display_name = load_config_key("display_name", vector_name=args.service_name, kind="vacConfig")
147
- description = load_config_key("description", vector_name=args.service_name, kind="vacConfig")
148
-
149
- print(
150
- Panel(description or "Starting VAC chat session",
151
- title=display_name or args.service_name,
152
- subtitle=service_url)
153
- )
150
+ console.print(f"[bold red]ERROR: Could not start {args.vac_name} proxy URL: {str(e)}[/bold red]")
151
+ sys.exit(1)
154
152
 
153
+ agent_name = load_config_key("agent", args.vac_name, kind="vacConfig")
154
+
155
155
  if args.headless:
156
- headless_mode(args.service_name, args.user_input, args.project, args.region, args.chat_history)
156
+ headless_mode(args.vac_name, args.user_input, args.project, args.region, args.chat_history)
157
+ stop_proxy(agent_name)
157
158
  else:
158
- stream_chat_session(args.service_name, args.project, args.region)
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
+
159
176
 
160
177
  def setup_vac_subparser(subparsers):
161
178
  """
@@ -165,7 +182,7 @@ def setup_vac_subparser(subparsers):
165
182
  subparsers: The subparsers object from argparse.ArgumentParser().
166
183
  """
167
184
  vac_parser = subparsers.add_parser('vac', help='Interact with deployed VAC services.')
168
- vac_parser.add_argument('service_name', help='Name of the VAC service.')
185
+ vac_parser.add_argument('vac_name', help='Name of the VAC service.')
169
186
  vac_parser.add_argument('user_input', help='User input for the VAC service when in headless mode.', nargs='?', default=None)
170
187
  vac_parser.add_argument('--headless', action='store_true', help='Run in headless mode.')
171
188
  vac_parser.add_argument('--chat_history', help='Chat history for headless mode (as JSON string).', default=None)
sunholo/cli/cli.py CHANGED
@@ -11,13 +11,7 @@ from ..utils.config import load_config_key
11
11
 
12
12
  from ..logging import log
13
13
 
14
- from rich import print
15
- from rich.console import Console
16
- from rich.prompt import Prompt
17
- from rich.spinner import Spinner
18
- from rich.panel import Panel
19
- from rich.text import Text
20
- console = Console()
14
+
21
15
 
22
16
  def load_default_gcp_config():
23
17
  gcp_config = load_config_key('gcp_config', 'global', kind="vacConfig")
@@ -67,8 +61,8 @@ def main(args=None):
67
61
  args = parser.parse_args(args)
68
62
 
69
63
  if args.debug:
70
- log.setLevel(logging.INFO)
71
- logging.getLogger().setLevel(logging.INFO)
64
+ log.setLevel(logging.DEBUG)
65
+ logging.getLogger().setLevel(logging.DEBUG)
72
66
  else:
73
67
  log.setLevel(logging.WARNING)
74
68
  logging.getLogger().setLevel(logging.WARNING)
sunholo/cli/run_proxy.py CHANGED
@@ -52,7 +52,7 @@ def check_gcloud():
52
52
  # Check if gcloud is installed
53
53
  result = subprocess.run(["gcloud", "--version"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=30)
54
54
  if result.returncode != 0:
55
- print("ERROR: gcloud is not installed or not found in PATH.")
55
+ print("[bold red]ERROR: gcloud is not installed or not found in PATH.[/bold red]")
56
56
  return False
57
57
 
58
58
  # Check if gcloud is authenticated
@@ -239,8 +239,9 @@ def list_proxies():
239
239
  """
240
240
  Lists all running proxies.
241
241
  """
242
- print("Listing Proxies...")
243
- proxies = clean_proxy_list()
242
+ with console.status("[bold orange]Listing Proxies[/bold orange]", spinner="star"):
243
+ proxies = clean_proxy_list()
244
+
244
245
  if not proxies:
245
246
  print("No proxies currently running.")
246
247
  else:
@@ -264,10 +265,10 @@ def setup_proxy_subparser(subparsers):
264
265
  subparsers: The subparsers object from argparse.ArgumentParser().
265
266
  """
266
267
 
267
- proxy_parser = subparsers.add_parser('proxy', help='Set up or stop a proxy to the Cloud Run service.')
268
+ proxy_parser = subparsers.add_parser('proxy', help='Set up or stop a proxy to the VAC Cloud Run services')
268
269
  proxy_subparsers = proxy_parser.add_subparsers(dest='proxy_command', required=True)
269
270
 
270
- start_parser = proxy_subparsers.add_parser('start', help='Start the proxy to the Cloud Run service.')
271
+ start_parser = proxy_subparsers.add_parser('start', help='Start the proxy to the VAC Cloud Run service')
271
272
  start_parser.add_argument('service_name', help='Name of the Cloud Run service.')
272
273
  start_parser.add_argument('--port', type=int, help='Port to run the proxy on. Auto-assigns if not provided.')
273
274
  start_parser.set_defaults(func=lambda args: start_proxy(args.service_name, args.region, args.project, args.port))
@@ -171,6 +171,56 @@ class AlloyDBClient:
171
171
 
172
172
  return self.execute_sql(query)
173
173
 
174
+ def create_database(self, database_name):
175
+ self.execute_sql(f'CREATE DATABASE "{database_name}"')
176
+
177
+ def fetch_owners(self):
178
+ owners = self.execute_sql('SELECT table_schema, table_name, privilege_type FROM information_schema.table_privileges')
179
+ for row in owners:
180
+ print(f"Schema: {row[0]}, Table: {row[1]}, Privilege: {row[2]}")
181
+ return owners
182
+
183
+ def create_schema(self, schema_name="public"):
184
+ self.execute_sql(f'CREATE SCHEMA IF NOT EXISTS {schema_name};')
185
+
186
+ def grant_permissions(self, schema_name, users):
187
+ for user in users:
188
+ self.execute_sql(f'GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA {schema_name} TO "{user}";')
189
+ self.execute_sql(f'GRANT USAGE, CREATE ON SCHEMA {schema_name} TO "{user}";')
190
+ self.execute_sql(f'ALTER DEFAULT PRIVILEGES IN SCHEMA {schema_name} GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO "{user}";')
191
+ self.execute_sql(f'GRANT USAGE ON SCHEMA information_schema TO "{user}";')
192
+ self.execute_sql(f'GRANT SELECT ON information_schema.columns TO "{user}";')
193
+
194
+ def create_docstore_tables(self, vector_names, users):
195
+ for vector_name in vector_names:
196
+ table_name = f"{vector_name}_docstore"
197
+ sql = f'''
198
+ CREATE TABLE IF NOT EXISTS "{table_name}"
199
+ (page_content TEXT, doc_id UUID, source TEXT, images_gsurls JSONB, chunk_metadata JSONB, langchain_metadata JSONB)
200
+ '''
201
+ self.execute_sql(sql)
202
+
203
+ for user in users:
204
+ self.execute_sql(f'GRANT SELECT, INSERT, UPDATE, DELETE ON TABLE "{table_name}" TO "{user}";')
205
+
206
+ vectorstore_id = f"{vector_name}_vectorstore_1536"
207
+ sql = f'''
208
+ CREATE TABLE IF NOT EXISTS "{vectorstore_id}" (
209
+ langchain_id UUID NOT NULL,
210
+ content TEXT NOT NULL,
211
+ embedding vector NOT NULL,
212
+ source TEXT,
213
+ langchain_metadata JSONB,
214
+ docstore_doc_id UUID,
215
+ eventTime TIMESTAMPTZ
216
+ );
217
+ '''
218
+ self.execute_sql(sql)
219
+
220
+ for user in users:
221
+ self.execute_sql(f'GRANT SELECT, INSERT, UPDATE, DELETE ON TABLE {vectorstore_id} TO "{user}";')
222
+
223
+
174
224
  alloydb_table_cache = {} # Our cache, initially empty # noqa: F841
175
225
  def create_alloydb_table(vector_name, engine, type = "vectorstore", alloydb_config=None, username=None):
176
226
  global alloydb_table_cache
@@ -157,8 +157,8 @@ def parse_json_data(json_data: dict):
157
157
  """
158
158
  try:
159
159
  if isinstance(json_data, dict):
160
- content = json_data.get('content')
161
- if content:
160
+ content = json_data.get('content', None)
161
+ if content is not None: # content can be '' empty string
162
162
  #log.debug(f'Yield content: {content}')
163
163
  yield content
164
164
  else:
@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: sunholo
3
- Version: 0.60.3
3
+ Version: 0.60.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.60.3.tar.gz
6
+ Download-URL: https://github.com/sunholo-data/sunholo-py/archive/refs/tags/v0.60.5.tar.gz
7
7
  Author: Holosun ApS
8
8
  Author-email: multivac@sunholo.com
9
9
  License: Apache License, Version 2.0
@@ -32,13 +32,13 @@ sunholo/chunker/pdfs.py,sha256=daCZ1xjn1YvxlifIyxskWNpLJLe-Q9D_Jq12MWx3tZo,2473
32
32
  sunholo/chunker/publish.py,sha256=PoT8q3XJeFCg10WrLkYhuaaXIrGVkvUD3-R9IfoWoH4,2703
33
33
  sunholo/chunker/splitter.py,sha256=FLkDhkePkg_zGQpFBK13Cznw575D-Rf9pcaCpc1HUxY,6726
34
34
  sunholo/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
35
- sunholo/cli/chat_vac.py,sha256=o17_ErIsR0FtCelSCTRSyleUeqZkbA7M463F7e61KBs,6360
36
- sunholo/cli/cli.py,sha256=d52lyS0WnEWK8qSDX6-B6KgpNhQC6R9hiENE9s-qSqM,2613
35
+ sunholo/cli/chat_vac.py,sha256=0ta0uXsGJQlUHrSiMY7wbUp9AaljLJA5R8xDIF2isgk,6857
36
+ sunholo/cli/cli.py,sha256=LWA5OveHx3ocy9KD1XwAwosBFrTUwifArIbltYgpul4,2420
37
37
  sunholo/cli/cli_init.py,sha256=JMZ9AX2cPDZ-_mv3adiv2ToFVNyRPtjk9Biszl1kiR0,2358
38
38
  sunholo/cli/configs.py,sha256=QUM9DvKOdZmEQRM5uI3Nh887T0YDiSMr7O240zTLqws,4546
39
39
  sunholo/cli/deploy.py,sha256=zxdwUsRTRMC8U5vyRv0JiKBLFn84Ug_Tc88-_h9hJSs,1609
40
40
  sunholo/cli/merge_texts.py,sha256=U9vdMwKmcPoc6iPOWX5MKSxn49dNGbNzVLw8ui5PhEU,1823
41
- sunholo/cli/run_proxy.py,sha256=2ZFjOPMUNeC2nK2iwLZfE2HQkq9ZDaDen2EabHuNAFs,9606
41
+ sunholo/cli/run_proxy.py,sha256=kYi3LnMdi27IqzA-k37WyT8AnFifn5ePP7jNK-8UmhE,9694
42
42
  sunholo/cli/sun_rich.py,sha256=UpMqeJ0C8i0pkue1AHnnyyX0bFJ9zZeJ7HBR6yhuA8A,54
43
43
  sunholo/components/__init__.py,sha256=RJGNEihwvRIiDScKis04RHJv4yZGI1UpXlOmuCptNZI,208
44
44
  sunholo/components/llm.py,sha256=T4we3tGmqUj4tPwxQr9M6AXv_BALqZV_dRSvINan-oU,10374
@@ -46,7 +46,7 @@ sunholo/components/prompt.py,sha256=eZSghXkIlRzXiSrzgkG7e5ytUYq6R6LV-qjHU8jStig,
46
46
  sunholo/components/retriever.py,sha256=_Lyt9RIgb2PD-rhV6oKAadiUs3ukT5uAYGW197tEskw,3755
47
47
  sunholo/components/vectorstore.py,sha256=dzspqOBtuxSjCFxem5_50sqwUUjbZ4oBYERtCwxZR6E,5619
48
48
  sunholo/database/__init__.py,sha256=Zz0Shcq-CtStf9rJGIYB_Ybzb8rY_Q9mfSj-nviM490,241
49
- sunholo/database/alloydb.py,sha256=J4VzrW2ChIYyqtccUBCtoN-vClfn-iipEDJpxN7GJkY,14820
49
+ sunholo/database/alloydb.py,sha256=0zRLyeC9nACzj3v36ET9NqLeuzdwBJ2bE09CzgVTTFM,17098
50
50
  sunholo/database/database.py,sha256=doY05kG8BZBLL-arh4hq5ef1ouWOtGHqdsDc6M2YHgk,7345
51
51
  sunholo/database/lancedb.py,sha256=WSrbY5mgyeXx6i7UBiz4YQ_i5UIYVYFo-vPGO72bQKY,707
52
52
  sunholo/database/static_dbs.py,sha256=aOyU3AJ-Dzz3qSNjbuN2293cfYw5PhkcQuQxdwPMJ4w,435
@@ -83,7 +83,7 @@ sunholo/qna/parsers.py,sha256=mH_SIgN2yXzvcoQZt9ITkdJSw3jgZGuu0p8q_H-kdSM,2140
83
83
  sunholo/qna/retry.py,sha256=gFgOf9AxrZMIO9OwOYu1EW7rhNhyfnw_o4XAsNLBOVQ,2021
84
84
  sunholo/streaming/__init__.py,sha256=k8dBqhzyS1Oi6NfADtRtWfnPtU1FU2kQz-YxH9yrNeQ,197
85
85
  sunholo/streaming/content_buffer.py,sha256=fWcg0oTf470M3U40VAChfmHmWRFgRD8VaT90jNfBCH0,6455
86
- sunholo/streaming/langserve.py,sha256=6isOvFwZBfmiQY5N41PYPyrdJj9IgJXXHLfTzPvewGw,6299
86
+ sunholo/streaming/langserve.py,sha256=4AeNt4FPv461s20_5q17Nx83cHjK7Dl3gVOcWAxMgOk,6350
87
87
  sunholo/streaming/streaming.py,sha256=9z6pXINEopuL_Z1RnmgXAoZJum9dzyuOxqYtEYnjf8w,16405
88
88
  sunholo/summarise/__init__.py,sha256=MZk3dblUMODcPb1crq4v-Z508NrFIpkSWNf9FIO8BcU,38
89
89
  sunholo/summarise/summarise.py,sha256=C3HhjepTjUhUC8FLk4jMQIBvq1BcORniwuTFHjPVhVo,3784
@@ -96,9 +96,9 @@ sunholo/utils/parsers.py,sha256=OrHmASqIbI45atVOhiGodgLvnfrzkvVzyHnSvAXD89I,3841
96
96
  sunholo/utils/user_ids.py,sha256=SQd5_H7FE7vcTZp9AQuQDWBXd4FEEd7TeVMQe1H4Ny8,292
97
97
  sunholo/vertex/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
98
98
  sunholo/vertex/init_vertex.py,sha256=JDMUaBRdednzbKF-5p33qqLit2LMsvgvWW-NRz0AqO0,1801
99
- sunholo-0.60.3.dist-info/LICENSE.txt,sha256=SdE3QjnD3GEmqqg9EX3TM9f7WmtOzqS1KJve8rhbYmU,11345
100
- sunholo-0.60.3.dist-info/METADATA,sha256=Zk0NZ77eeA0GocxUY1fVWY7RA7rtma6t531MCjaBiVU,8057
101
- sunholo-0.60.3.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
102
- sunholo-0.60.3.dist-info/entry_points.txt,sha256=bZuN5AIHingMPt4Ro1b_T-FnQvZ3teBes-3OyO0asl4,49
103
- sunholo-0.60.3.dist-info/top_level.txt,sha256=wt5tadn5--5JrZsjJz2LceoUvcrIvxjHJe-RxuudxAk,8
104
- sunholo-0.60.3.dist-info/RECORD,,
99
+ sunholo-0.60.5.dist-info/LICENSE.txt,sha256=SdE3QjnD3GEmqqg9EX3TM9f7WmtOzqS1KJve8rhbYmU,11345
100
+ sunholo-0.60.5.dist-info/METADATA,sha256=bYtLnWZBwnj6r_Nzbc6TqFANw0lZuv9OCk4eldL_RZQ,8057
101
+ sunholo-0.60.5.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
102
+ sunholo-0.60.5.dist-info/entry_points.txt,sha256=bZuN5AIHingMPt4Ro1b_T-FnQvZ3teBes-3OyO0asl4,49
103
+ sunholo-0.60.5.dist-info/top_level.txt,sha256=wt5tadn5--5JrZsjJz2LceoUvcrIvxjHJe-RxuudxAk,8
104
+ sunholo-0.60.5.dist-info/RECORD,,