sunholo 0.56.7__py3-none-any.whl → 0.57.1__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.
@@ -29,9 +29,16 @@ try:
29
29
  except ImportError:
30
30
  print("No flask installed for agents.flask.register_qna_routes, install via `pip install sunholo[http]`")
31
31
 
32
+ try:
33
+ from langfuse.decorators import langfuse_context, observe
34
+ except ImportError as err:
35
+ print(f"No langfuse installed for agents.flask.register_qna_routes, install via `pip install sunholo[http]` - {str(err)}")
36
+
37
+
32
38
  def register_qna_routes(app, stream_interpreter, vac_interpreter):
33
39
 
34
40
  @app.route('/vac/streaming/<vector_name>', methods=['POST'])
41
+ @observe()
35
42
  def stream_qa(vector_name):
36
43
  prep = prep_vac(request, vector_name)
37
44
  log.debug(f"Processing prep: {prep}")
@@ -54,6 +61,7 @@ def register_qna_routes(app, stream_interpreter, vac_interpreter):
54
61
  model=vac_config.get("model") or vac_config.get("llm")
55
62
  )
56
63
 
64
+ @observe()
57
65
  def generate_response_content():
58
66
 
59
67
  chunks = ""
@@ -77,9 +85,9 @@ def register_qna_routes(app, stream_interpreter, vac_interpreter):
77
85
  generation.end(output=json.dumps(chunk))
78
86
  span.end(output=json.dumps(chunk))
79
87
  trace.update(output=json.dumps(chunk))
80
- yield f"###JSON_START###{json.dumps(chunk)}###JSON_END###"
81
88
 
82
- return
89
+ return json.dumps(chunk)
90
+
83
91
  else:
84
92
  # Otherwise, we yield the plain text chunks as they come in.
85
93
  if chunk:
@@ -100,6 +108,7 @@ def register_qna_routes(app, stream_interpreter, vac_interpreter):
100
108
  return response
101
109
 
102
110
  @app.route('/vac/<vector_name>', methods=['POST'])
111
+ @observe()
103
112
  def process_qna(vector_name):
104
113
  prep = prep_vac(request, vector_name)
105
114
  log.debug(f"Processing prep: {prep}")
@@ -177,7 +186,9 @@ def create_langfuse_trace(request, vector_name):
177
186
  )
178
187
 
179
188
  def prep_vac(request, vector_name):
180
- trace = create_langfuse_trace(request, vector_name)
189
+ #trace = create_langfuse_trace(request, vector_name)
190
+ trace = None
191
+ span = None
181
192
  data = request.get_json()
182
193
  log.info(f"vac/{vector_name} got data: {data}")
183
194
  config, _ = load_config("config/llm_config.yaml")
@@ -32,12 +32,13 @@ def chunk_doc_to_docs(documents: list, extension: str = ".md", min_size: int = 8
32
32
  docstore_doc_id, documents = send_doc_to_docstore(documents, vector_name=vector_name)
33
33
 
34
34
  doc_summaries = summarise_docs(documents, vector_name=vector_name)
35
- for doc in documents:
36
- # Assuming each doc has a unique identifier in its metadata under 'objectId'
37
- objectId = doc.metadata.get("objectId")
38
- if objectId and objectId in doc_summaries:
39
- # If the objectId is found in doc_summaries, add the summary location to the document's metadata
40
- doc.metadata["summary_location"] = doc_summaries[objectId]
35
+ if doc_summaries:
36
+ for doc in documents:
37
+ # Assuming each doc has a unique identifier in its metadata under 'objectId'
38
+ objectId = doc.metadata.get("objectId")
39
+ if objectId and objectId in doc_summaries:
40
+ # If the objectId is found in doc_summaries, add the summary location to the document's metadata
41
+ doc.metadata["summary_location"] = doc_summaries[objectId]
41
42
 
42
43
  # Combine entire documents that are smaller than min_size
43
44
  combined_documents_content = ""
sunholo/cli/cli.py CHANGED
@@ -1,8 +1,8 @@
1
1
  import argparse
2
2
  try:
3
- from google.cloud import build_v1
3
+ from google.cloud.devtools import cloudbuild_v1
4
4
  except ImportError:
5
- build_v1 = None
5
+ cloudbuild_v1 = None
6
6
 
7
7
  from ..logging import log
8
8
 
@@ -16,21 +16,21 @@ def trigger_build(args):
16
16
  Example:
17
17
  trigger_build(args) where args contains project_id, trigger_id, repo_name, and branch_name.
18
18
  """
19
- if not build_v1:
19
+ if not cloudbuild_v1:
20
20
  log.warning("Can't deploy - google-cloud-build not installed, enable via `pip install sunholo[gcp]")
21
21
 
22
22
  return None
23
23
 
24
- client = build_v1.services.cloud_build.CloudBuildClient()
24
+ client = cloudbuild_v1.CloudBuildClient()
25
25
  # Assuming the build source uses the path to the cloudbuild.yaml if specified.
26
- source = build_v1.RepoSource(
26
+ source = cloudbuild_v1.RepoSource(
27
27
  project_id=args.project_id,
28
28
  repo_name=args.repo_name,
29
29
  branch_name=args.branch_name,
30
30
  substitutions=args.substitutions,
31
31
  dir=args.config_path # Path to directory containing cloudbuild.yaml
32
32
  )
33
- request = build_v1.RunBuildTriggerRequest(
33
+ request = cloudbuild_v1.RunBuildTriggerRequest(
34
34
  project_id=args.project_id,
35
35
  trigger_id=args.trigger_id,
36
36
  source=source
@@ -62,7 +62,7 @@ def main(args=None):
62
62
 
63
63
  Example commands:
64
64
  ```bash
65
- sunholo deploy --project_id "my-gcp-project" --trigger_id "my-trigger-id" --repo_name "my-repo" --branch_name "dev" --config_path "app/vac/my_vac/"
65
+ sunholo deploy --vac edmonbrain --config=llm_config.yaml
66
66
  ```
67
67
  """
68
68
  parser = argparse.ArgumentParser(description="sunholo CLI tool for deploying applications using Google Cloud Build.")
@@ -3,6 +3,20 @@ from ..utils import load_config_key
3
3
 
4
4
  # Load the YAML file
5
5
  def load_prompt_from_yaml(key, prefix="sunholo", file_path=None):
6
+ """
7
+ Returns a string you can use with Langfuse PromptTemplate.from_template()
8
+
9
+ Will first try to load from the Langfuse prompt library, if unavailable will look in promptConfig type file.
10
+
11
+ Langfuse prompts have {{ two braces }}, Langchain prompts have { one brace }.
12
+
13
+ Example:
14
+
15
+ ```python
16
+ from sunholo.langfuse.prompts import load_prompt_from_yaml
17
+ from langchain_core.prompts import PromptTemplate
18
+
19
+ """
6
20
  from langfuse import Langfuse
7
21
 
8
22
  # Initialize Langfuse client
sunholo/qna/parsers.py CHANGED
@@ -21,18 +21,35 @@ def document_to_dict(document):
21
21
  }
22
22
 
23
23
  def parse_output(bot_output):
24
+ """
25
+ Parses VAC output assuming it has an 'answer' and an optional 'source_documents' key
26
+
27
+ """
24
28
  if isinstance(bot_output, str):
29
+
25
30
  return {"answer": bot_output}
31
+
26
32
  if isinstance(bot_output, dict) and 'source_documents' in bot_output:
27
- if 'source_documents' in bot_output:
28
- bot_output['source_documents'] = [document_to_dict(doc) for doc in bot_output['source_documents']]
29
- if bot_output.get("answer", None) is None or bot_output.get("answer") == "":
33
+ bot_output['source_documents'] = [document_to_dict(doc) for doc in bot_output['source_documents']]
34
+ if not bot_output.get("answer") or bot_output.get("answer") == "":
35
+ bot_output['answer'] = "(No text was returned)"
36
+
37
+ return bot_output
38
+
39
+ elif isinstance(bot_output, dict) and 'metadata' in bot_output and isinstance(bot_output.get('metadata')) and 'source_documents' in bot_output.get('metadata'):
40
+ metadata = bot_output.get('metadata')
41
+ bot_output['source_documents'] = [document_to_dict(doc) for doc in metadata['source_documents']]
42
+ if not bot_output.get("answer") or bot_output.get("answer") == "":
30
43
  bot_output['answer'] = "(No text was returned)"
44
+
31
45
  return bot_output
46
+
32
47
  elif isinstance(bot_output, dict):
33
48
  if not bot_output.get("answer"):
34
49
  raise ValueError(f"VAC output was not a string or a dict with the key 'answer' - got: {bot_output}")
35
50
  else:
51
+
36
52
  return bot_output
53
+
37
54
  else:
38
55
  log.error(f"Couldn't parse output for:\n {bot_output}")
@@ -51,7 +51,6 @@ class ContentBuffer:
51
51
  Adds the given text to the existing content of the buffer.
52
52
  """
53
53
  self.content += text
54
- log.debug(f"Written {text} to buffer")
55
54
 
56
55
  def read(self) -> str:
57
56
  """
@@ -61,8 +60,7 @@ class ContentBuffer:
61
60
  str: The content of the buffer.
62
61
 
63
62
  Provides the entire content stored in the buffer.
64
- """
65
- log.debug(f"Read content from buffer")
63
+ """
66
64
  return self.content
67
65
 
68
66
  def clear(self):
@@ -71,7 +69,6 @@ class ContentBuffer:
71
69
 
72
70
  Empties the buffer content, resetting it to an empty string.
73
71
  """
74
- log.debug(f"Clearing content buffer")
75
72
  self.content = ""
76
73
 
77
74
 
@@ -39,8 +39,6 @@ def start_streaming_chat(question,
39
39
  if not check_kwargs_support(qna_func):
40
40
  yield "No **kwargs in qna_func - please add it"
41
41
 
42
- # Immediately yield to indicate the process has started.
43
- yield "Thinking...\n"
44
42
  log.info(f"Streaming chat with wait time {wait_time} seconds and timeout {timeout} seconds and kwargs {kwargs}")
45
43
  # Initialize the chat
46
44
  content_buffer = ContentBuffer()
@@ -82,12 +80,6 @@ def start_streaming_chat(question,
82
80
  yield content_to_send
83
81
  content_buffer.clear()
84
82
  start = time.time() # reset timeout
85
- else:
86
- if time.time() - first_start < wait_time:
87
- # If the initial wait period hasn't passed yet, keep sending "..."
88
- yield "..."
89
- else:
90
- log.info("No content to send")
91
83
 
92
84
  elapsed_time = time.time() - start
93
85
  if elapsed_time > timeout: # If the elapsed time exceeds the timeout
@@ -162,9 +154,10 @@ async def start_streaming_chat_async(question, vector_name, qna_func, chat_histo
162
154
  The `start_streaming_chat_async` function is used in a coroutine that prints messages as they are generated.
163
155
  """
164
156
 
165
- yield "Thinking...\n"
166
157
  log.info(f"Streaming chat with wait time {wait_time} seconds and timeout {timeout} seconds and kwargs {kwargs}")
167
-
158
+ if not check_kwargs_support(qna_func):
159
+ yield "No **kwargs in qna_func - please add it"
160
+
168
161
  content_buffer = ContentBuffer()
169
162
  chat_callback_handler = BufferStreamingStdOutCallbackHandler(content_buffer=content_buffer, tokens=".!?\n")
170
163
 
@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: sunholo
3
- Version: 0.56.7
3
+ Version: 0.57.1
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.56.7.tar.gz
6
+ Download-URL: https://github.com/sunholo-data/sunholo-py/archive/refs/tags/v0.57.1.tar.gz
7
7
  Author: Holosun ApS
8
8
  Author-email: multivac@sunholo.com
9
9
  License: Apache License, Version 2.0
@@ -13,7 +13,7 @@ sunholo/agents/fastapi/base.py,sha256=clk76cHbUAvU0OYJrRfCWX_5f0ACbhDsIzYBhI3wyo
13
13
  sunholo/agents/fastapi/qna_routes.py,sha256=DgK4Btu5XriOC1JaRQ4G_nWEjJfnQ0J5pyLanF6eF1g,3857
14
14
  sunholo/agents/flask/__init__.py,sha256=uqfHNw2Ru3EJ4dJEcbp86h_lkquBQPMxZbjhV_xe3rs,72
15
15
  sunholo/agents/flask/base.py,sha256=RUGWBYWeV60FatYF5sMRrxD-INU97Vodsi6JaB6i93s,763
16
- sunholo/agents/flask/qna_routes.py,sha256=hjUwW3-HEpE0RE2OxtnFJc_CAuzRexJxFSRXEAnFUVo,8426
16
+ sunholo/agents/flask/qna_routes.py,sha256=CIGTNOm0LFyyH8PuQEQyh1FaKJgdMR2nT1UK3jg2u_A,8692
17
17
  sunholo/archive/__init__.py,sha256=qNHWm5rGPVOlxZBZCpA1wTYPbalizRT7f8X4rs2t290,31
18
18
  sunholo/archive/archive.py,sha256=C-UhG5x-XtZ8VheQp92IYJqgD0V3NFQjniqlit94t18,1197
19
19
  sunholo/auth/__init__.py,sha256=4owDjSaWYkbTlPK47UHTOC0gCWbZsqn4ZIEw5NWZTlg,28
@@ -29,9 +29,9 @@ sunholo/chunker/loaders.py,sha256=xiToUVgPz2ZzcqpUAq7aNP3PTenb_rBUAFzu0JPycIg,10
29
29
  sunholo/chunker/message_data.py,sha256=iDP94dySU3Xct-gWGnB4NNRSh2luQmgJeCfQb7ktt3U,6760
30
30
  sunholo/chunker/pdfs.py,sha256=daCZ1xjn1YvxlifIyxskWNpLJLe-Q9D_Jq12MWx3tZo,2473
31
31
  sunholo/chunker/publish.py,sha256=PoT8q3XJeFCg10WrLkYhuaaXIrGVkvUD3-R9IfoWoH4,2703
32
- sunholo/chunker/splitter.py,sha256=CZ33xVWeYdjckd1VTrZnxuLypzzn-yKXQBFZaN7UcjI,6697
32
+ sunholo/chunker/splitter.py,sha256=ug_v-h0wos3b7OkhmedVQs5jtLuDdFDWypvsZVYgxbU,6743
33
33
  sunholo/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
34
- sunholo/cli/cli.py,sha256=ljOso32M1u9_PAx_T2vGQtZcCTNRw8TLblinob8btAo,3352
34
+ sunholo/cli/cli.py,sha256=9ov0GgbdM3IDC4QgqLnG4EBSiCm2_8MlRS-6G45sXJg,3279
35
35
  sunholo/components/__init__.py,sha256=RJGNEihwvRIiDScKis04RHJv4yZGI1UpXlOmuCptNZI,208
36
36
  sunholo/components/llm.py,sha256=T4we3tGmqUj4tPwxQr9M6AXv_BALqZV_dRSvINan-oU,10374
37
37
  sunholo/components/prompt.py,sha256=eZSghXkIlRzXiSrzgkG7e5ytUYq6R6LV-qjHU8jStig,6353
@@ -57,7 +57,7 @@ sunholo/gcs/download_url.py,sha256=PAwYShV-sRd9sNvuJrEOvfF1V34ovVP0omWbuwDkRrA,4
57
57
  sunholo/gcs/metadata.py,sha256=C9sMPsHsq1ETetdQCqB3EBs3Kws8b8QHS9L7ei_v5aw,891
58
58
  sunholo/langfuse/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
59
59
  sunholo/langfuse/callback.py,sha256=G9xcZHpLvyzolU57ycItLaooMCtRuM37QJSWjiwQEd0,1776
60
- sunholo/langfuse/prompts.py,sha256=px6vSxJyiKaT0E34NZdcbSvY8_2TNtOaCsa3Cact17M,774
60
+ sunholo/langfuse/prompts.py,sha256=HO4Zy9usn5tKooBPCKksuw4Lff3c03Ny5wqn4ce_xZM,1217
61
61
  sunholo/llamaindex/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
62
62
  sunholo/llamaindex/generate.py,sha256=l1Picr-hVwkmAUD7XmTCa63qY9ERliFHQXwyX3BqB2Q,686
63
63
  sunholo/llamaindex/import_files.py,sha256=QamEVtFXSD6Zk2La0HDgmtVPhFDdXpjzLACO--BAYpg,9378
@@ -71,21 +71,21 @@ sunholo/pubsub/__init__.py,sha256=wgkrtlL3h8uzNpnlWSHdVMOq0l5Q3D7gkxF_Rp1A6Ro,94
71
71
  sunholo/pubsub/process_pubsub.py,sha256=64hvqMsxbBrf0WGJsprz_SXf9FpjeszAIsqUSBlJrA8,2780
72
72
  sunholo/pubsub/pubsub_manager.py,sha256=M85QPCXYBPzmE8Ha0FYHdzpA-LRX9p3lu6b-UAHAyac,6400
73
73
  sunholo/qna/__init__.py,sha256=F8q1uR_HreoSX0IfmKY1qoSwIgXhO2Q8kuDSxh9_-EE,28
74
- sunholo/qna/parsers.py,sha256=Qn7lYsO2daWN0kDRGop5CkamIPq9wWFPEB1cP6Is7Ng,1585
74
+ sunholo/qna/parsers.py,sha256=mH_SIgN2yXzvcoQZt9ITkdJSw3jgZGuu0p8q_H-kdSM,2140
75
75
  sunholo/qna/retry.py,sha256=gFgOf9AxrZMIO9OwOYu1EW7rhNhyfnw_o4XAsNLBOVQ,2021
76
76
  sunholo/streaming/__init__.py,sha256=k8dBqhzyS1Oi6NfADtRtWfnPtU1FU2kQz-YxH9yrNeQ,197
77
- sunholo/streaming/content_buffer.py,sha256=hr2ySHOTK1zw_3u-JrKwoomsAAdda2VcOxjkvJLcUuM,6596
77
+ sunholo/streaming/content_buffer.py,sha256=fWcg0oTf470M3U40VAChfmHmWRFgRD8VaT90jNfBCH0,6455
78
78
  sunholo/streaming/langserve.py,sha256=6isOvFwZBfmiQY5N41PYPyrdJj9IgJXXHLfTzPvewGw,6299
79
- sunholo/streaming/streaming.py,sha256=TLLBamDs5ihvA77I30xAXu_J8vMVUmhyeJFJkTN9ess,16723
79
+ sunholo/streaming/streaming.py,sha256=WoSRMnD-3sRxmeyxHz3miTtB6ECpj3Dw4SUCcnP0zB4,16473
80
80
  sunholo/summarise/__init__.py,sha256=MZk3dblUMODcPb1crq4v-Z508NrFIpkSWNf9FIO8BcU,38
81
81
  sunholo/summarise/summarise.py,sha256=C3HhjepTjUhUC8FLk4jMQIBvq1BcORniwuTFHjPVhVo,3784
82
82
  sunholo/utils/__init__.py,sha256=G11nN_6ATjxpuMfG_BvcUr9UU8onPIgkpTK6CjOcbr8,48
83
83
  sunholo/utils/config.py,sha256=NW2FFyNNTwCyopOvSzDQ0I0l92LAfJJ7hEzatSuoZho,8689
84
84
  sunholo/utils/gcp.py,sha256=B2G1YKjeD7X9dqO86Jrp2vPuFwZ223Xl5Tg09Ndw-oc,5760
85
85
  sunholo/utils/parsers.py,sha256=OrHmASqIbI45atVOhiGodgLvnfrzkvVzyHnSvAXD89I,3841
86
- sunholo-0.56.7.dist-info/LICENSE.txt,sha256=SdE3QjnD3GEmqqg9EX3TM9f7WmtOzqS1KJve8rhbYmU,11345
87
- sunholo-0.56.7.dist-info/METADATA,sha256=RukURzDPjG_-HJtOirmBNhrbe9oupTyn423r5sxOX-Y,6617
88
- sunholo-0.56.7.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
89
- sunholo-0.56.7.dist-info/entry_points.txt,sha256=bZuN5AIHingMPt4Ro1b_T-FnQvZ3teBes-3OyO0asl4,49
90
- sunholo-0.56.7.dist-info/top_level.txt,sha256=wt5tadn5--5JrZsjJz2LceoUvcrIvxjHJe-RxuudxAk,8
91
- sunholo-0.56.7.dist-info/RECORD,,
86
+ sunholo-0.57.1.dist-info/LICENSE.txt,sha256=SdE3QjnD3GEmqqg9EX3TM9f7WmtOzqS1KJve8rhbYmU,11345
87
+ sunholo-0.57.1.dist-info/METADATA,sha256=s9XOCC178rrc3tpEYhI992r3sFKS-IwKP7AGVAb0EpU,6617
88
+ sunholo-0.57.1.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
89
+ sunholo-0.57.1.dist-info/entry_points.txt,sha256=bZuN5AIHingMPt4Ro1b_T-FnQvZ3teBes-3OyO0asl4,49
90
+ sunholo-0.57.1.dist-info/top_level.txt,sha256=wt5tadn5--5JrZsjJz2LceoUvcrIvxjHJe-RxuudxAk,8
91
+ sunholo-0.57.1.dist-info/RECORD,,