sunholo 0.62.3__py3-none-any.whl → 0.62.4__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.
@@ -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)
@@ -67,6 +70,7 @@ def prep_request_payload(user_input, chat_history, vector_name, stream, **kwargs
67
70
  # Base qna_data dictionary
68
71
  qna_data = {
69
72
  'user_input': user_input,
73
+ 'vector_name': vector_name,
70
74
  }
71
75
  # Update qna_data with optional values from kwargs
72
76
  qna_data.update(kwargs)
sunholo/agents/route.py CHANGED
@@ -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
 
sunholo/cli/chat_vac.py CHANGED
@@ -1,7 +1,8 @@
1
1
  from ..agents import send_to_qa
2
- from ..streaming import generate_proxy_stream
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
+ from ..logging import log
5
6
 
6
7
  from .run_proxy import clean_proxy_list, start_proxy, stop_proxy
7
8
 
@@ -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 = []
@@ -52,16 +53,11 @@ def stream_chat_session(service_url, service_name):
52
53
  if user_input.lower() in ["exit", "quit"]:
53
54
  console.print("[bold red]Exiting chat session.[/bold red]")
54
55
  break
55
-
56
- def stream_response():
57
- generate = generate_proxy_stream(
58
- send_to_qa,
59
- user_input,
56
+
57
+ if not stream:
58
+ vac_response = send_to_qa(user_input,
60
59
  vector_name=service_name,
61
60
  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
61
  message_author=user_id,
66
62
  #TODO: populate these
67
63
  image_url=None,
@@ -77,34 +73,65 @@ def stream_chat_session(service_url, service_name):
77
73
  user_id=user_id,
78
74
  session_id=session_id,
79
75
  message_source="cli",
80
- override_endpoint=service_url
81
- )
82
- for part in generate():
83
- yield part
76
+ override_endpoint=service_url)
77
+
78
+ console.print(f"[bold yellow]{service_name}:[/bold yellow] {vac_response}", end='\n')
79
+ else:
84
80
 
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
81
+ def stream_response():
82
+ generate = generate_proxy_stream(
83
+ send_to_qa,
84
+ user_input,
85
+ vector_name=service_name,
86
+ chat_history=chat_history,
87
+ generate_f_output=lambda x: x, # Replace with actual processing function
88
+ stream_wait_time=0.5,
89
+ stream_timeout=120,
90
+ message_author=user_id,
91
+ #TODO: populate these
92
+ image_url=None,
93
+ source_filters=None,
94
+ search_kwargs=None,
95
+ private_docs=None,
96
+ whole_document=False,
97
+ source_filters_and_or=False,
98
+ # system kwargs
99
+ configurable={
100
+ "vector_name": service_name,
101
+ },
102
+ user_id=user_id,
103
+ session_id=session_id,
104
+ message_source="cli",
105
+ override_endpoint=service_url
106
+ )
107
+ for part in generate():
108
+ yield part
109
+
110
+ response_started = False
111
+ vac_response = ""
112
+
113
+ # point or star?
114
+ with console.status("[bold orange]Thinking...[/bold orange]", spinner="star") as status:
115
+ for token in stream_response():
116
+ if not response_started:
117
+ status.stop()
118
+ console.print(f"[bold yellow]{service_name}:[/bold yellow] ", end='')
119
+ response_started = True
120
+
121
+ if isinstance(token, bytes):
122
+ token = token.decode('utf-8')
123
+ console.print(token, end='')
124
+ vac_response += token
125
+
126
+ response_started = False
100
127
 
101
128
  chat_history.append({"name": "Human", "content": user_input})
102
129
  chat_history.append({"name": "AI", "content": vac_response})
103
- response_started = False
130
+
104
131
  console.print()
105
132
  console.rule()
106
133
 
107
- def headless_mode(service_url, service_name, user_input, chat_history=None):
134
+ def headless_mode(service_url, service_name, user_input, chat_history=None, stream=True):
108
135
  chat_history = chat_history or []
109
136
 
110
137
  user_id = generate_user_id()
@@ -196,16 +223,23 @@ def vac_command(args):
196
223
  service_url = resolve_service_url(args)
197
224
  agent_name = load_config_key("agent", args.vac_name, kind="vacConfig")
198
225
 
226
+ streamer = can_agent_stream(agent_name)
227
+ log.warning(f"streamer: {streamer}")
228
+ if not streamer:
229
+ console.print(f"Non streaming agent: {args.vac_name}")
230
+
199
231
  if args.headless:
200
- headless_mode(service_url, args.vac_name, args.user_input, args.chat_history)
232
+ headless_mode(service_url, args.vac_name, args.user_input, args.chat_history, stream=streamer)
201
233
  else:
202
234
  display_name = load_config_key("display_name", vector_name=args.vac_name, kind="vacConfig")
203
235
  description = load_config_key("description", vector_name=args.vac_name, kind="vacConfig")
236
+ endpoints_config = load_config_key(agent_name, "dummy_value", kind="agentConfig")
204
237
 
238
+ display_endpoints = ', '.join(f"{key}: {value}" for key, value in endpoints_config.items())
205
239
  if agent_name == "langserve":
206
240
  subtitle = f"{service_url}/{args.vac_name}/playground/"
207
241
  else:
208
- subtitle = f"{agent_name} - {service_url}/vac/{args.vac_name}"
242
+ subtitle = f"{agent_name} - {display_endpoints}"
209
243
 
210
244
  print(
211
245
  Panel(description or "Starting VAC chat session",
@@ -213,7 +247,7 @@ def vac_command(args):
213
247
  subtitle=subtitle)
214
248
  )
215
249
 
216
- stream_chat_session(service_url, args.vac_name)
250
+ stream_chat_session(service_url, args.vac_name, stream=streamer)
217
251
 
218
252
  stop_proxy(agent_name, stop_local=False)
219
253
 
@@ -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
@@ -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.warning(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
+
sunholo/utils/config.py CHANGED
@@ -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
+
@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: sunholo
3
- Version: 0.62.3
3
+ Version: 0.62.4
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.4.tar.gz
7
7
  Author: Holosun ApS
8
8
  Author-email: multivac@sunholo.com
9
9
  License: Apache License, Version 2.0
@@ -2,10 +2,10 @@ sunholo/__init__.py,sha256=0CdpufyRKWyZe7J7UKigL6j_qOorM-p0OjHIAuf9M38,864
2
2
  sunholo/logging.py,sha256=1jzfy4q9h5DNG4MjwtbTiM8keZxymlrZ0gDQEtGLMHY,11400
3
3
  sunholo/agents/__init__.py,sha256=CnlbVohPt-Doth9PyROSlN3P8xMV9j9yS19YE-wCS90,341
4
4
  sunholo/agents/chat_history.py,sha256=bkII7PNEbGCaobu2Rnr2rM9dim3BCK0kM-tiWhoI1tw,5219
5
- sunholo/agents/dispatch_to_qa.py,sha256=h5qbcPqJ5JGa21T8Z5is7jbn4eG3P4xULLj_X25q3WM,8208
5
+ sunholo/agents/dispatch_to_qa.py,sha256=VaUUD4Y8XmPvrUlHP63yRl8Z2o1wagbcGZi9GwlDTTQ,8286
6
6
  sunholo/agents/langserve.py,sha256=FdhQjorAY2bMn2rpuabNT6bU3uqSKWrl8DjpH3L_V7k,4375
7
7
  sunholo/agents/pubsub.py,sha256=5hbbhbBGyVWRpt2sAGC5FEheYH1mCCwVUhZEB1S7vGg,1337
8
- sunholo/agents/route.py,sha256=0klBifx-QtMGsjq8HB04s9Bytm0nFXPYaWKeyt-S9S4,2356
8
+ sunholo/agents/route.py,sha256=R_j-o2-K0RiDkj8Gt1yZivBohcI9SCl-8j79h03H1mQ,2109
9
9
  sunholo/agents/special_commands.py,sha256=PI4ADgFQvPDCeCpOeWIrD4bD432NYFeVcBBnkqTBWi8,6457
10
10
  sunholo/agents/fastapi/__init__.py,sha256=S_pj4_bTUmDGoq_exaREHlOKThi0zTuGT0VZY0YfODQ,88
11
11
  sunholo/agents/fastapi/base.py,sha256=clk76cHbUAvU0OYJrRfCWX_5f0ACbhDsIzYBhI3wyoE,2514
@@ -31,7 +31,7 @@ sunholo/chunker/pdfs.py,sha256=daCZ1xjn1YvxlifIyxskWNpLJLe-Q9D_Jq12MWx3tZo,2473
31
31
  sunholo/chunker/publish.py,sha256=PoT8q3XJeFCg10WrLkYhuaaXIrGVkvUD3-R9IfoWoH4,2703
32
32
  sunholo/chunker/splitter.py,sha256=FLkDhkePkg_zGQpFBK13Cznw575D-Rf9pcaCpc1HUxY,6726
33
33
  sunholo/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
34
- sunholo/cli/chat_vac.py,sha256=BeDacxULBQN9Q6OvLNv2LTEcE6eghcnhiC7asC5Hx60,14307
34
+ sunholo/cli/chat_vac.py,sha256=H-UzYtQDHM4TQZ8wYkcXfNB5SW5sdYhM7lb17OcZa24,15841
35
35
  sunholo/cli/cli.py,sha256=if2xx99fIUQG_ZYvMpQsRQIvrjBZJTJSn1JBhjeVAZU,3573
36
36
  sunholo/cli/cli_init.py,sha256=JMZ9AX2cPDZ-_mv3adiv2ToFVNyRPtjk9Biszl1kiR0,2358
37
37
  sunholo/cli/configs.py,sha256=QUM9DvKOdZmEQRM5uI3Nh887T0YDiSMr7O240zTLqws,4546
@@ -40,9 +40,8 @@ sunholo/cli/embedder.py,sha256=5m_FaAqF6bnLJQj93HGySC-OOCXo2NCUVG_ZBjE1oUM,6937
40
40
  sunholo/cli/merge_texts.py,sha256=U9vdMwKmcPoc6iPOWX5MKSxn49dNGbNzVLw8ui5PhEU,1823
41
41
  sunholo/cli/run_proxy.py,sha256=0ft_9FUL9d1NKM2ABMMPpvXRTRZd9f-lR2FCahiGzlU,11281
42
42
  sunholo/cli/sun_rich.py,sha256=UpMqeJ0C8i0pkue1AHnnyyX0bFJ9zZeJ7HBR6yhuA8A,54
43
- sunholo/components/__init__.py,sha256=RJGNEihwvRIiDScKis04RHJv4yZGI1UpXlOmuCptNZI,208
43
+ sunholo/components/__init__.py,sha256=IDoylb74zFKo6NIS3RQqUl0PDFBGVxM1dfUmO7OJ44U,176
44
44
  sunholo/components/llm.py,sha256=T4we3tGmqUj4tPwxQr9M6AXv_BALqZV_dRSvINan-oU,10374
45
- sunholo/components/prompt.py,sha256=eZSghXkIlRzXiSrzgkG7e5ytUYq6R6LV-qjHU8jStig,6353
46
45
  sunholo/components/retriever.py,sha256=_Lyt9RIgb2PD-rhV6oKAadiUs3ukT5uAYGW197tEskw,3755
47
46
  sunholo/components/vectorstore.py,sha256=lB8vx_N6eBA44orNeVo1WRn0Q8GCIjvPPT9AfiPWBWE,5620
48
47
  sunholo/database/__init__.py,sha256=Zz0Shcq-CtStf9rJGIYB_Ybzb8rY_Q9mfSj-nviM490,241
@@ -82,15 +81,16 @@ sunholo/pubsub/pubsub_manager.py,sha256=M85QPCXYBPzmE8Ha0FYHdzpA-LRX9p3lu6b-UAHA
82
81
  sunholo/qna/__init__.py,sha256=F8q1uR_HreoSX0IfmKY1qoSwIgXhO2Q8kuDSxh9_-EE,28
83
82
  sunholo/qna/parsers.py,sha256=mH_SIgN2yXzvcoQZt9ITkdJSw3jgZGuu0p8q_H-kdSM,2140
84
83
  sunholo/qna/retry.py,sha256=gFgOf9AxrZMIO9OwOYu1EW7rhNhyfnw_o4XAsNLBOVQ,2021
85
- sunholo/streaming/__init__.py,sha256=k8dBqhzyS1Oi6NfADtRtWfnPtU1FU2kQz-YxH9yrNeQ,197
84
+ sunholo/streaming/__init__.py,sha256=MpbydI2UYo_adttPQFkxNM33b-QRyNEbrKJx0C2AGPc,241
86
85
  sunholo/streaming/content_buffer.py,sha256=fWcg0oTf470M3U40VAChfmHmWRFgRD8VaT90jNfBCH0,6455
87
86
  sunholo/streaming/langserve.py,sha256=4AeNt4FPv461s20_5q17Nx83cHjK7Dl3gVOcWAxMgOk,6350
87
+ sunholo/streaming/stream_lookup.py,sha256=5oYtTSBRU1FtjtugXmBEpyxei2hQOweiLhIhKovYFLk,311
88
88
  sunholo/streaming/streaming.py,sha256=9z6pXINEopuL_Z1RnmgXAoZJum9dzyuOxqYtEYnjf8w,16405
89
89
  sunholo/summarise/__init__.py,sha256=MZk3dblUMODcPb1crq4v-Z508NrFIpkSWNf9FIO8BcU,38
90
90
  sunholo/summarise/summarise.py,sha256=C3HhjepTjUhUC8FLk4jMQIBvq1BcORniwuTFHjPVhVo,3784
91
91
  sunholo/utils/__init__.py,sha256=G11nN_6ATjxpuMfG_BvcUr9UU8onPIgkpTK6CjOcbr8,48
92
92
  sunholo/utils/big_context.py,sha256=gJIP7_ZL-YSLhOMq8jmFTMqH1wq8eB1NK7oKPeZAq2s,5578
93
- sunholo/utils/config.py,sha256=eshtV7faFhMxs6AQejv7TCKzDsJXmKEyMBQ5CVmFKzg,8593
93
+ sunholo/utils/config.py,sha256=y3Ja87ZESlA5x_PVLeNVcpp516rE9LiemmxNrAir3EQ,8902
94
94
  sunholo/utils/config_schema.py,sha256=Wv-ncitzljOhgbDaq9qnFqH5LCuxNv59dTGDWgd1qdk,4189
95
95
  sunholo/utils/gcp.py,sha256=B2G1YKjeD7X9dqO86Jrp2vPuFwZ223Xl5Tg09Ndw-oc,5760
96
96
  sunholo/utils/parsers.py,sha256=OrHmASqIbI45atVOhiGodgLvnfrzkvVzyHnSvAXD89I,3841
@@ -99,9 +99,9 @@ sunholo/utils/user_ids.py,sha256=SQd5_H7FE7vcTZp9AQuQDWBXd4FEEd7TeVMQe1H4Ny8,292
99
99
  sunholo/vertex/__init__.py,sha256=7B5Wf41da0dl9JOOrwq35Ob5jcKen_w5T-Tw5f4eoWE,75
100
100
  sunholo/vertex/init.py,sha256=JDMUaBRdednzbKF-5p33qqLit2LMsvgvWW-NRz0AqO0,1801
101
101
  sunholo/vertex/memory_tools.py,sha256=-o9cas_UeRU5gPLi0qcvNwR0HTU5TamzddGLTHOVjZ4,3598
102
- sunholo-0.62.3.dist-info/LICENSE.txt,sha256=SdE3QjnD3GEmqqg9EX3TM9f7WmtOzqS1KJve8rhbYmU,11345
103
- sunholo-0.62.3.dist-info/METADATA,sha256=TzYCZbU79szVOV-8zXdNsaGtOcfXscxrUhxmcs0pkxA,8057
104
- sunholo-0.62.3.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
105
- sunholo-0.62.3.dist-info/entry_points.txt,sha256=bZuN5AIHingMPt4Ro1b_T-FnQvZ3teBes-3OyO0asl4,49
106
- sunholo-0.62.3.dist-info/top_level.txt,sha256=wt5tadn5--5JrZsjJz2LceoUvcrIvxjHJe-RxuudxAk,8
107
- sunholo-0.62.3.dist-info/RECORD,,
102
+ sunholo-0.62.4.dist-info/LICENSE.txt,sha256=SdE3QjnD3GEmqqg9EX3TM9f7WmtOzqS1KJve8rhbYmU,11345
103
+ sunholo-0.62.4.dist-info/METADATA,sha256=GJYTdsOwRl-RhWvQ5x3oZoh3BDn57DzkubpJrwcBHS0,8057
104
+ sunholo-0.62.4.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
105
+ sunholo-0.62.4.dist-info/entry_points.txt,sha256=bZuN5AIHingMPt4Ro1b_T-FnQvZ3teBes-3OyO0asl4,49
106
+ sunholo-0.62.4.dist-info/top_level.txt,sha256=wt5tadn5--5JrZsjJz2LceoUvcrIvxjHJe-RxuudxAk,8
107
+ sunholo-0.62.4.dist-info/RECORD,,
@@ -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