sunholo 0.114.1__tar.gz → 0.115.0__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 (169) hide show
  1. {sunholo-0.114.1 → sunholo-0.115.0}/PKG-INFO +14 -10
  2. {sunholo-0.114.1 → sunholo-0.115.0}/setup.py +15 -11
  3. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/__init__.py +0 -2
  4. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/chunker/message_data.py +1 -4
  5. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/chunker/pdfs.py +1 -1
  6. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/chunker/publish.py +1 -5
  7. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/chunker/splitter.py +6 -0
  8. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/cli/cli_init.py +3 -1
  9. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/components/llm.py +1 -1
  10. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/components/vectorstore.py +1 -1
  11. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/embedder/embed_chunk.py +3 -0
  12. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/senses/stream_voice.py +22 -7
  13. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/streaming/content_buffer.py +6 -13
  14. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/summarise/summarise.py +5 -5
  15. sunholo-0.115.0/sunholo/types.py +52 -0
  16. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/utils/config.py +4 -3
  17. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/utils/config_class.py +20 -20
  18. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/utils/gcp.py +0 -3
  19. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/vertex/extensions_class.py +4 -4
  20. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo.egg-info/PKG-INFO +14 -10
  21. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo.egg-info/SOURCES.txt +1 -4
  22. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo.egg-info/requires.txt +12 -8
  23. sunholo-0.114.1/sunholo/patches/__init__.py +0 -0
  24. sunholo-0.114.1/sunholo/patches/langchain/__init__.py +0 -0
  25. sunholo-0.114.1/sunholo/patches/langchain/lancedb.py +0 -219
  26. sunholo-0.114.1/sunholo/patches/langchain/vertexai.py +0 -506
  27. {sunholo-0.114.1 → sunholo-0.115.0}/LICENSE.txt +0 -0
  28. {sunholo-0.114.1 → sunholo-0.115.0}/MANIFEST.in +0 -0
  29. {sunholo-0.114.1 → sunholo-0.115.0}/README.md +0 -0
  30. {sunholo-0.114.1 → sunholo-0.115.0}/setup.cfg +0 -0
  31. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/agents/__init__.py +0 -0
  32. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/agents/chat_history.py +0 -0
  33. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/agents/dispatch_to_qa.py +0 -0
  34. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/agents/fastapi/__init__.py +0 -0
  35. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/agents/fastapi/base.py +0 -0
  36. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/agents/fastapi/qna_routes.py +0 -0
  37. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/agents/flask/__init__.py +0 -0
  38. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/agents/flask/base.py +0 -0
  39. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/agents/flask/qna_routes.py +0 -0
  40. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/agents/flask/vac_routes.py +0 -0
  41. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/agents/langserve.py +0 -0
  42. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/agents/pubsub.py +0 -0
  43. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/agents/route.py +0 -0
  44. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/agents/special_commands.py +0 -0
  45. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/agents/swagger.py +0 -0
  46. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/archive/__init__.py +0 -0
  47. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/archive/archive.py +0 -0
  48. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/auth/__init__.py +0 -0
  49. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/auth/gcloud.py +0 -0
  50. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/auth/refresh.py +0 -0
  51. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/auth/run.py +0 -0
  52. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/azure/__init__.py +0 -0
  53. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/azure/auth.py +0 -0
  54. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/azure/blobs.py +0 -0
  55. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/azure/event_grid.py +0 -0
  56. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/bots/__init__.py +0 -0
  57. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/bots/discord.py +0 -0
  58. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/bots/github_webhook.py +0 -0
  59. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/bots/webapp.py +0 -0
  60. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/chunker/__init__.py +0 -0
  61. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/chunker/azure.py +0 -0
  62. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/chunker/doc_handling.py +0 -0
  63. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/chunker/encode_metadata.py +0 -0
  64. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/chunker/images.py +0 -0
  65. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/chunker/loaders.py +0 -0
  66. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/chunker/process_chunker_data.py +0 -0
  67. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/chunker/pubsub.py +0 -0
  68. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/cli/__init__.py +0 -0
  69. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/cli/chat_vac.py +0 -0
  70. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/cli/cli.py +0 -0
  71. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/cli/configs.py +0 -0
  72. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/cli/deploy.py +0 -0
  73. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/cli/embedder.py +0 -0
  74. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/cli/merge_texts.py +0 -0
  75. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/cli/run_proxy.py +0 -0
  76. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/cli/sun_rich.py +0 -0
  77. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/cli/swagger.py +0 -0
  78. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/cli/vertex.py +0 -0
  79. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/components/__init__.py +0 -0
  80. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/components/retriever.py +0 -0
  81. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/custom_logging.py +0 -0
  82. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/database/__init__.py +0 -0
  83. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/database/alloydb.py +0 -0
  84. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/database/alloydb_client.py +0 -0
  85. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/database/database.py +0 -0
  86. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/database/lancedb.py +0 -0
  87. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/database/sql/sb/create_function.sql +0 -0
  88. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/database/sql/sb/create_function_time.sql +0 -0
  89. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/database/sql/sb/create_table.sql +0 -0
  90. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/database/sql/sb/delete_source_row.sql +0 -0
  91. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/database/sql/sb/return_sources.sql +0 -0
  92. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/database/sql/sb/setup.sql +0 -0
  93. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/database/static_dbs.py +0 -0
  94. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/database/uuid.py +0 -0
  95. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/discovery_engine/__init__.py +0 -0
  96. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/discovery_engine/chunker_handler.py +0 -0
  97. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/discovery_engine/create_new.py +0 -0
  98. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/discovery_engine/discovery_engine_client.py +0 -0
  99. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/discovery_engine/get_ai_search_chunks.py +0 -0
  100. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/embedder/__init__.py +0 -0
  101. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/excel/__init__.py +0 -0
  102. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/excel/plugin.py +0 -0
  103. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/gcs/__init__.py +0 -0
  104. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/gcs/add_file.py +0 -0
  105. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/gcs/download_folder.py +0 -0
  106. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/gcs/download_url.py +0 -0
  107. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/gcs/extract_and_sign.py +0 -0
  108. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/gcs/metadata.py +0 -0
  109. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/genai/__init__.py +0 -0
  110. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/genai/file_handling.py +0 -0
  111. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/genai/images.py +0 -0
  112. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/genai/init.py +0 -0
  113. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/genai/process_funcs_cls.py +0 -0
  114. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/genai/safety.py +0 -0
  115. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/invoke/__init__.py +0 -0
  116. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/invoke/async_class.py +0 -0
  117. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/invoke/direct_vac_func.py +0 -0
  118. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/invoke/invoke_vac_utils.py +0 -0
  119. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/langfuse/__init__.py +0 -0
  120. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/langfuse/callback.py +0 -0
  121. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/langfuse/evals.py +0 -0
  122. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/langfuse/prompts.py +0 -0
  123. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/llamaindex/__init__.py +0 -0
  124. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/llamaindex/get_files.py +0 -0
  125. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/llamaindex/import_files.py +0 -0
  126. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/llamaindex/llamaindex_class.py +0 -0
  127. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/llamaindex/user_history.py +0 -0
  128. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/lookup/__init__.py +0 -0
  129. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/lookup/model_lookup.yaml +0 -0
  130. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/pubsub/__init__.py +0 -0
  131. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/pubsub/process_pubsub.py +0 -0
  132. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/pubsub/pubsub_manager.py +0 -0
  133. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/qna/__init__.py +0 -0
  134. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/qna/parsers.py +0 -0
  135. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/qna/retry.py +0 -0
  136. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/senses/__init__.py +0 -0
  137. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/streaming/__init__.py +0 -0
  138. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/streaming/langserve.py +0 -0
  139. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/streaming/stream_lookup.py +0 -0
  140. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/streaming/streaming.py +0 -0
  141. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/summarise/__init__.py +0 -0
  142. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/terraform/__init__.py +0 -0
  143. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/terraform/tfvars_editor.py +0 -0
  144. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/tools/__init__.py +0 -0
  145. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/tools/web_browser.py +0 -0
  146. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/utils/__init__.py +0 -0
  147. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/utils/api_key.py +0 -0
  148. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/utils/big_context.py +0 -0
  149. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/utils/config_schema.py +0 -0
  150. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/utils/gcp_project.py +0 -0
  151. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/utils/mime.py +0 -0
  152. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/utils/parsers.py +0 -0
  153. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/utils/timedelta.py +0 -0
  154. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/utils/user_ids.py +0 -0
  155. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/utils/version.py +0 -0
  156. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/vertex/__init__.py +0 -0
  157. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/vertex/extensions_call.py +0 -0
  158. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/vertex/genai_functions.py +0 -0
  159. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/vertex/init.py +0 -0
  160. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/vertex/memory_tools.py +0 -0
  161. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/vertex/safety.py +0 -0
  162. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo/vertex/type_dict_to_json.py +0 -0
  163. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo.egg-info/dependency_links.txt +0 -0
  164. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo.egg-info/entry_points.txt +0 -0
  165. {sunholo-0.114.1 → sunholo-0.115.0}/sunholo.egg-info/top_level.txt +0 -0
  166. {sunholo-0.114.1 → sunholo-0.115.0}/tests/test_async.py +0 -0
  167. {sunholo-0.114.1 → sunholo-0.115.0}/tests/test_chat_history.py +0 -0
  168. {sunholo-0.114.1 → sunholo-0.115.0}/tests/test_config.py +0 -0
  169. {sunholo-0.114.1 → sunholo-0.115.0}/tests/test_unstructured.py +0 -0
@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: sunholo
3
- Version: 0.114.1
3
+ Version: 0.115.0
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.114.1.tar.gz
6
+ Download-URL: https://github.com/sunholo-data/sunholo-py/archive/refs/tags/v0.115.0.tar.gz
7
7
  Author: Holosun ApS
8
8
  Author-email: multivac@sunholo.com
9
9
  License: Apache License, Version 2.0
@@ -18,13 +18,14 @@ Classifier: Programming Language :: Python :: 3.11
18
18
  Classifier: Programming Language :: Python :: 3.12
19
19
  Description-Content-Type: text/markdown
20
20
  License-File: LICENSE.txt
21
+ Requires-Dist: aiohttp
21
22
  Requires-Dist: google-auth
23
+ Requires-Dist: pydantic
24
+ Requires-Dist: requests
22
25
  Requires-Dist: ruamel.yaml
23
- Requires-Dist: langchain==0.2.16
24
- Requires-Dist: langchain_experimental==0.0.65
25
- Requires-Dist: langchain-community==0.2.17
26
- Requires-Dist: langsmith==0.1.143
26
+ Requires-Dist: tenacity
27
27
  Provides-Extra: all
28
+ Requires-Dist: aiohttp; extra == "all"
28
29
  Requires-Dist: anthropic[vertex]; extra == "all"
29
30
  Requires-Dist: asyncpg; extra == "all"
30
31
  Requires-Dist: azure-identity; extra == "all"
@@ -68,10 +69,12 @@ Requires-Dist: pillow; extra == "all"
68
69
  Requires-Dist: playwright; extra == "all"
69
70
  Requires-Dist: psutil; extra == "all"
70
71
  Requires-Dist: psycopg2-binary; extra == "all"
72
+ Requires-Dist: pydantic; extra == "all"
71
73
  Requires-Dist: pypdf; extra == "all"
72
74
  Requires-Dist: python-hcl2; extra == "all"
73
75
  Requires-Dist: python-socketio; extra == "all"
74
76
  Requires-Dist: pytesseract; extra == "all"
77
+ Requires-Dist: requests; extra == "all"
75
78
  Requires-Dist: rich; extra == "all"
76
79
  Requires-Dist: sounddevice; extra == "all"
77
80
  Requires-Dist: supabase; extra == "all"
@@ -82,10 +85,10 @@ Requires-Dist: tiktoken; extra == "all"
82
85
  Requires-Dist: unstructured[all-docs,local-inference]; extra == "all"
83
86
  Requires-Dist: xlwings; extra == "all"
84
87
  Provides-Extra: langchain
85
- Requires-Dist: langchain==0.2.16; extra == "langchain"
86
- Requires-Dist: langchain_experimental==0.0.65; extra == "langchain"
87
- Requires-Dist: langchain-community==0.2.17; extra == "langchain"
88
- Requires-Dist: langsmith==0.1.143; extra == "langchain"
88
+ Requires-Dist: langchain; extra == "langchain"
89
+ Requires-Dist: langchain_experimental; extra == "langchain"
90
+ Requires-Dist: langchain-community; extra == "langchain"
91
+ Requires-Dist: langsmith; extra == "langchain"
89
92
  Provides-Extra: azure
90
93
  Requires-Dist: azure-identity; extra == "azure"
91
94
  Requires-Dist: azure-storage-blob; extra == "azure"
@@ -104,6 +107,7 @@ Requires-Dist: tantivy; extra == "database"
104
107
  Provides-Extra: pipeline
105
108
  Requires-Dist: GitPython; extra == "pipeline"
106
109
  Requires-Dist: lark; extra == "pipeline"
110
+ Requires-Dist: langchain>=0.2.16; extra == "pipeline"
107
111
  Requires-Dist: langchain-unstructured; extra == "pipeline"
108
112
  Requires-Dist: psutil; extra == "pipeline"
109
113
  Requires-Dist: pypdf; extra == "pipeline"
@@ -1,6 +1,6 @@
1
1
  from setuptools import setup, find_packages
2
2
 
3
- version = '0.114.1'
3
+ version = '0.115.0'
4
4
 
5
5
  setup(
6
6
  name='sunholo',
@@ -27,16 +27,17 @@ setup(
27
27
  },
28
28
  install_requires=[
29
29
  # Base dependencies
30
+ "aiohttp",
30
31
  "google-auth", # to check if on gcp
32
+ "pydantic",
33
+ "requests",
31
34
  "ruamel.yaml",
32
- "langchain==0.2.16",
33
- "langchain_experimental==0.0.65",
34
- "langchain-community==0.2.17",
35
- "langsmith==0.1.143",
35
+ "tenacity"
36
36
  ],
37
37
  extras_require={
38
38
  # Define optional dependencies with feature names
39
39
  'all': [
40
+ "aiohttp",
40
41
  "anthropic[vertex]",
41
42
  "asyncpg",
42
43
  "azure-identity",
@@ -80,10 +81,12 @@ setup(
80
81
  "playwright",
81
82
  "psutil",
82
83
  "psycopg2-binary",
84
+ "pydantic",
83
85
  "pypdf",
84
86
  "python-hcl2",
85
87
  "python-socketio",
86
88
  "pytesseract",
89
+ "requests",
87
90
  "rich",
88
91
  "sounddevice",
89
92
  "supabase",
@@ -95,10 +98,10 @@ setup(
95
98
  "xlwings"
96
99
  ],
97
100
  'langchain': [
98
- "langchain==0.2.16",
99
- "langchain_experimental==0.0.65",
100
- "langchain-community==0.2.17",
101
- "langsmith==0.1.143",
101
+ "langchain",
102
+ "langchain_experimental",
103
+ "langchain-community",
104
+ "langsmith",
102
105
  ],
103
106
  'azure': [
104
107
  "azure-identity",
@@ -121,6 +124,7 @@ setup(
121
124
  'pipeline': [
122
125
  "GitPython",
123
126
  "lark",
127
+ "langchain>=0.2.16",
124
128
  "langchain-unstructured",
125
129
  "psutil",
126
130
  "pypdf",
@@ -189,10 +193,10 @@ setup(
189
193
  },
190
194
  classifiers=[
191
195
  'Development Status :: 3 - Alpha', # Chose either "3 - Alpha", "4 - Beta" or "5 - Production/Stable" as the current state of your package
192
- 'Intended Audience :: Developers', # Define that your audience are developers
196
+ 'Intended Audience :: Developers',
193
197
  'Topic :: Software Development :: Build Tools',
194
198
  'License :: OSI Approved :: Apache Software License',
195
- 'Programming Language :: Python :: 3', #Specify which python versions that you want to support
199
+ 'Programming Language :: Python :: 3',
196
200
  'Programming Language :: Python :: 3.10',
197
201
  'Programming Language :: Python :: 3.11',
198
202
  'Programming Language :: Python :: 3.12'
@@ -15,7 +15,6 @@ from . import invoke
15
15
  from . import langfuse
16
16
  from . import llamaindex
17
17
  from . import lookup
18
- from . import patches
19
18
  from . import pubsub
20
19
  from . import qna
21
20
  from . import senses
@@ -44,7 +43,6 @@ __all__ = ['agents',
44
43
  'langfuse',
45
44
  'llamaindex',
46
45
  'lookup',
47
- 'patches',
48
46
  'pubsub',
49
47
  'qna',
50
48
  'senses',
@@ -29,10 +29,7 @@ try:
29
29
  except ImportError:
30
30
  BlobServiceClient = None
31
31
 
32
- try:
33
- from langchain.schema import Document
34
- except ImportError:
35
- Document = None
32
+ from ..types import Document
36
33
 
37
34
  from .splitter import chunk_doc_to_docs
38
35
  from .pdfs import split_pdf_to_pages
@@ -14,6 +14,7 @@
14
14
  import os
15
15
  import pathlib
16
16
  from ..custom_logging import log
17
+ from ..types import Document
17
18
 
18
19
  def split_pdf_to_pages(pdf_path, temp_dir):
19
20
 
@@ -51,7 +52,6 @@ def split_pdf_to_pages(pdf_path, temp_dir):
51
52
  return page_files
52
53
 
53
54
  def read_pdf_file(pdf_path, metadata):
54
- from langchain.schema import Document
55
55
  from pypdf import PdfReader
56
56
  log.info(f"Trying local PDF parsing. Reading PDF {pdf_path}...")
57
57
 
@@ -2,11 +2,7 @@ from ..custom_logging import log
2
2
  from ..pubsub import PubSubManager
3
3
  from ..utils.parsers import contains_url, extract_urls
4
4
  from ..utils.gcp_project import get_gcp_project
5
-
6
- try:
7
- from langchain.schema import Document
8
- except ImportError:
9
- Document=None
5
+ from ..types import Document
10
6
 
11
7
  def publish_if_urls(the_content, vector_name):
12
8
  """
@@ -28,6 +28,9 @@ except ImportError:
28
28
  def chunk_doc_to_docs(documents: list, extension: str = ".md", min_size: int = 800, vector_name=None, **kwargs):
29
29
  """Turns a Document object into a list of many Document chunks.
30
30
  If a document or chunk is smaller than min_size, it will be merged with adjacent documents or chunks."""
31
+
32
+ if Document is None:
33
+ raise ImportError("Document chunker needs langchain installed via sunholo[pipeline]")
31
34
 
32
35
  if len(documents)==0:
33
36
  log.warning("No documents found to chunk in chunk_doc_to_docs")
@@ -137,6 +140,9 @@ def choose_splitter(extension: str, chunk_size: int=1024, chunk_overlap:int=200,
137
140
 
138
141
  return semantic_splitter
139
142
 
143
+ if not text_splitter:
144
+ raise ImportError("text_splitter needs langchain installed via sunholo[pipeline]")
145
+
140
146
 
141
147
  if extension == ".py":
142
148
  return text_splitter.PythonCodeTextSplitter()
@@ -1,9 +1,11 @@
1
1
  import os
2
- import yaml
2
+ from ruamel.yaml import YAML
3
3
  import shutil
4
4
  from ..utils.config import get_module_filepath
5
5
  from ..utils.parsers import sanitize_cloudrun_name
6
6
 
7
+ yaml = YAML(typ='safe')
8
+
7
9
  def init_project(args):
8
10
  """
9
11
  Initializes a new sunholo project with a basic configuration file and directory structure.
@@ -110,7 +110,7 @@ def llm_str_to_llm(llm_str, model=None, vector_name=None, config=None):
110
110
  return VertexAI(model_name = model, temperature=0, max_output_tokens=1024)
111
111
 
112
112
  elif llm_str == 'model_garden':
113
- from ..patches.langchain.vertexai import VertexAIModelGarden
113
+ from langchain_google_vertexai import VertexAIModelGarden
114
114
  model_garden_config = config.vacConfig("gcp_config")
115
115
  if model_garden_config is None:
116
116
  raise ValueError("llm='model_garden' requires a gcp_config entry in config yaml file")
@@ -102,7 +102,7 @@ def pick_vectorstore(vs_str: str, vector_name: str=None, embeddings=None, config
102
102
  return vectorstore
103
103
 
104
104
  elif vs_str == "lancedb":
105
- from ..patches.langchain.lancedb import LanceDB
105
+ from langchain_community.vectorstores import LanceDB
106
106
  import lancedb
107
107
 
108
108
  LANCEDB_BUCKET = os.environ.get("LANCEDB_BUCKET")
@@ -34,6 +34,9 @@ def embed_pubsub_chunk(data: dict):
34
34
  data JSON
35
35
  """
36
36
 
37
+ if Document is None:
38
+ raise ImportError("Embeddin requires langchain installed via sunholo[pipeline]")
39
+
37
40
  message_data = base64.b64decode(data['message']['data']).decode('utf-8')
38
41
  messageId = data['message'].get('messageId')
39
42
  publishTime = data['message'].get('publishTime')
@@ -1,3 +1,12 @@
1
+ from typing import Optional, TYPE_CHECKING, Union, Any
2
+
3
+ if TYPE_CHECKING:
4
+ import numpy as np
5
+ from numpy.typing import NDArray
6
+ ArrayType = NDArray[np.int16]
7
+ else:
8
+ ArrayType = Any # Fallback type when numpy isn't available
9
+
1
10
  try:
2
11
  from google.cloud import texttospeech
3
12
  except ImportError:
@@ -29,9 +38,6 @@ import io
29
38
  import wave
30
39
 
31
40
  import argparse
32
- import json
33
- from typing import Optional
34
- from pathlib import Path
35
41
  import sys
36
42
 
37
43
  class StreamingTTS:
@@ -195,8 +201,11 @@ class StreamingTTS:
195
201
  log.error(f"Error initializing audio device: {e}")
196
202
  raise
197
203
 
198
- def _make_fade(self, length: int, fade_type: str='l') -> np.ndarray:
204
+ def _make_fade(self, length: int, fade_type: str='l') -> ArrayType:
199
205
  """Generate a fade curve of specified length and type."""
206
+ if np is None: # Runtime check
207
+ raise ImportError("numpy is required. Install with pip install sunholo[tts]")
208
+
200
209
  fade = np.arange(length, dtype=np.float32) / length
201
210
 
202
211
  if fade_type == 't': # triangle
@@ -214,8 +223,11 @@ class StreamingTTS:
214
223
 
215
224
  return fade
216
225
 
217
- def _apply_fade(self, audio: np.ndarray, fade_duration: float, fade_in: bool = True, fade_out: bool = True) -> np.ndarray:
226
+ def _apply_fade(self, audio: ArrayType, fade_duration: float, fade_in: bool = True, fade_out: bool = True) -> ArrayType:
218
227
  """Apply fade in/out to audio with specified duration."""
228
+ if np is None: # Runtime check
229
+ raise ImportError("numpy is required. Install with pip install sunholo[tts]")
230
+
219
231
  if audio.ndim != 1:
220
232
  raise ValueError("Audio must be 1-dimensional")
221
233
 
@@ -233,8 +245,11 @@ class StreamingTTS:
233
245
  return audio.astype(np.int16)
234
246
 
235
247
 
236
- def _play_audio_chunk(self, audio_chunk: np.ndarray, is_final_chunk: bool = False):
248
+ def _play_audio_chunk(self, audio_chunk: ArrayType, is_final_chunk: bool = False):
237
249
  """Play a single audio chunk with proper device handling."""
250
+ if np is None: # Runtime check
251
+ raise ImportError("numpy is required. Install with pip install sunholo[tts]")
252
+
238
253
  try:
239
254
  # Add longer padding for the final chunk
240
255
  padding_duration = 0.1 if is_final_chunk else 0.02
@@ -415,7 +430,7 @@ def tts_command(args):
415
430
  Panel((
416
431
  f"Saying: {args.text}"
417
432
  ),
418
- title=f"Text to Speech",
433
+ title="Text to Speech",
419
434
  subtitle=f"{tts.voice_name} is talking"),
420
435
  )
421
436
  tts.process_text_stream(
@@ -13,13 +13,6 @@
13
13
  # limitations under the License.
14
14
  from typing import Any, Dict, List, Union
15
15
 
16
- try:
17
- from langchain.callbacks.streaming_stdout import StreamingStdOutCallbackHandler
18
- from langchain.schema import LLMResult
19
- except ImportError:
20
- StreamingStdOutCallbackHandler = None
21
- LLMResult = None
22
-
23
16
  import threading
24
17
  import asyncio
25
18
  import re
@@ -114,7 +107,7 @@ class ContentBuffer:
114
107
  self.content_available.clear()
115
108
 
116
109
 
117
- class BufferStreamingStdOutCallbackHandler(StreamingStdOutCallbackHandler):
110
+ class BufferStreamingStdOutCallbackHandler:
118
111
  """
119
112
  A callback handler for streaming LLM output to a content buffer.
120
113
 
@@ -212,12 +205,12 @@ class BufferStreamingStdOutCallbackHandler(StreamingStdOutCallbackHandler):
212
205
  self.content_buffer.write(self.buffer)
213
206
  self.buffer = ""
214
207
 
215
- def on_llm_end(self, response: LLMResult, **kwargs: Any) -> None:
208
+ def on_llm_end(self, response, **kwargs: Any) -> None:
216
209
  """
217
210
  Handles the end of LLM streaming.
218
211
 
219
212
  Args:
220
- response (LLMResult): The result returned by the LLM.
213
+ response: The result returned by the LLM.
221
214
  **kwargs: Additional keyword arguments.
222
215
 
223
216
  Writes any remaining buffer content to the content buffer, and sets a signal indicating
@@ -233,7 +226,7 @@ class BufferStreamingStdOutCallbackHandler(StreamingStdOutCallbackHandler):
233
226
 
234
227
 
235
228
 
236
- class BufferStreamingStdOutCallbackHandlerAsync(StreamingStdOutCallbackHandler):
229
+ class BufferStreamingStdOutCallbackHandlerAsync:
237
230
  """
238
231
  An async callback handler for streaming LLM output to a content buffer.
239
232
 
@@ -315,12 +308,12 @@ class BufferStreamingStdOutCallbackHandlerAsync(StreamingStdOutCallbackHandler):
315
308
  await self.content_buffer.async_write(self.buffer)
316
309
  self.buffer = ""
317
310
 
318
- async def async_on_llm_end(self, response: LLMResult, **kwargs: Any) -> None:
311
+ async def async_on_llm_end(self, response, **kwargs: Any) -> None:
319
312
  """
320
313
  Asynchronously handles the end of LLM streaming.
321
314
 
322
315
  Args:
323
- response (LLMResult): The result returned by the LLM.
316
+ response: The result returned by the LLM.
324
317
  **kwargs: Additional keyword arguments.
325
318
  """
326
319
  if self.buffer:
@@ -13,8 +13,6 @@
13
13
  # limitations under the License.
14
14
  from ..custom_logging import log
15
15
 
16
-
17
-
18
16
  from ..components import get_llm
19
17
  from ..chunker.splitter import chunk_doc_to_docs
20
18
 
@@ -36,6 +34,8 @@ except ImportError:
36
34
  VertexAI=None
37
35
  load_summarize_chain=None
38
36
  Document=None
37
+ import time
38
+ import random
39
39
 
40
40
  prompt_template = """Write a summary for below, including key concepts, people and distinct information but do not add anything that is not in the original text:
41
41
 
@@ -45,10 +45,10 @@ SUMMARY:"""
45
45
  MAP_PROMPT = PromptTemplate(template=prompt_template, input_variables=["text"])
46
46
 
47
47
 
48
- import time
49
- import random
50
-
51
48
  def summarise_docs(docs, vector_name, skip_if_less=10000):
49
+ if Document is None:
50
+ raise ImportError("summarise_docs requires langchain installed via sunholo[pipeline]")
51
+
52
52
  llm = get_llm(vector_name)
53
53
 
54
54
  if isinstance(llm, ChatOpenAI) or isinstance(llm, OpenAI):
@@ -0,0 +1,52 @@
1
+ from typing import Any, Dict, Optional, TYPE_CHECKING, Union
2
+ from dataclasses import dataclass, asdict
3
+ import json
4
+
5
+ if TYPE_CHECKING:
6
+ from langchain.schema import Document as LangchainDocument
7
+
8
+
9
+ @dataclass
10
+ class Document:
11
+ """A simple document class with content and metadata.
12
+
13
+ Used for storing text content and associated metadata when not using LangChain.
14
+ Maintains the same basic interface (page_content and metadata) for compatibility.
15
+
16
+ Using @dataclass makes it automatically serializable and provides nice defaults.
17
+ """
18
+ page_content: str
19
+ metadata: Dict[str, Any] = None
20
+
21
+ def __post_init__(self) -> None:
22
+ """Initialize metadata if None."""
23
+ if self.metadata is None:
24
+ self.metadata = {}
25
+
26
+ def to_dict(self) -> Dict[str, Any]:
27
+ """Convert to dictionary."""
28
+ return asdict(self)
29
+
30
+ @classmethod
31
+ def from_dict(cls, data: Dict[str, Any]) -> "Document":
32
+ """Create from dictionary."""
33
+ return cls(**data)
34
+
35
+ def json(self) -> str:
36
+ """Convert to JSON string - for compatibility with LangChain's Document."""
37
+ return json.dumps(self.to_dict())
38
+
39
+ def convert_to_langchain_doc(doc: Document) -> Union[Any, "LangchainDocument"]:
40
+ """Convert our Document to a LangChain Document.
41
+
42
+ Returns Any when LangChain isn't available to avoid type errors.
43
+ Only imports LangChain when the function is actually called.
44
+ """
45
+ try:
46
+ from langchain.schema import Document as LangchainDocument
47
+ return LangchainDocument(
48
+ page_content=doc.page_content,
49
+ metadata=doc.metadata
50
+ )
51
+ except ImportError:
52
+ raise ImportError("LangChain is required for this conversion. Please install langchain.")
@@ -14,11 +14,12 @@
14
14
 
15
15
  import os
16
16
  import json
17
- import yaml
18
17
  from datetime import datetime, timedelta
19
18
  from collections import defaultdict
20
19
  from .timedelta import format_timedelta
21
20
 
21
+ from ruamel.yaml import YAML
22
+ yaml = YAML(typ='safe')
22
23
 
23
24
  def get_module_filepath(filepath: str):
24
25
  """
@@ -107,7 +108,7 @@ def reload_config_file(config_file, filename):
107
108
  if filename.endswith('.json'):
108
109
  config = json.load(file)
109
110
  else:
110
- config = yaml.safe_load(file)
111
+ config = yaml.load(file)
111
112
 
112
113
  config_cache[filename] = (config, datetime.now())
113
114
  log.debug(f"Loaded and cached {config_file}")
@@ -166,7 +167,7 @@ def load_config(filename: str=None) -> tuple[dict, str]:
166
167
  if filename.endswith(".json"):
167
168
  config = json.load(f)
168
169
  elif filename.endswith(".yaml") or filename.endswith(".yml"):
169
- config = yaml.safe_load(f)
170
+ config = yaml.load(f)
170
171
  else:
171
172
  raise ValueError(f"Unsupported config file format: {config_file}. The supported formats are JSON and YAML.")
172
173
 
@@ -1,9 +1,7 @@
1
1
  import os
2
2
  import json
3
- import yaml
4
3
  from datetime import datetime, timedelta
5
4
  from collections import defaultdict
6
- from yaml.constructor import SafeConstructor, ConstructorError
7
5
 
8
6
  from .timedelta import format_timedelta
9
7
 
@@ -122,30 +120,32 @@ class ConfigManager:
122
120
  Returns:
123
121
  dict: The loaded configuration.
124
122
  """
125
- from ..custom_logging import log
123
+ def _reload_config_file(self, config_file, filename, is_local=False):
124
+ """
125
+ Helper function to load a config file and update the cache.
126
126
 
127
- class NoDuplicateKeyConstructor(SafeConstructor):
128
- def construct_mapping(self, node, deep=False):
129
- mapping = {}
130
- for key_node, value_node in node.value:
131
- key = self.construct_object(key_node, deep=deep)
132
- if key in mapping:
133
- raise ConstructorError(f"Duplicate key found: {key_node.start_mark}")
134
- value = self.construct_object(value_node, deep=deep)
135
- mapping[key] = value
136
- return mapping
137
-
138
- NoDuplicateKeyLoader = yaml.Loader
139
- NoDuplicateKeyLoader.add_constructor(
140
- yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG,
141
- NoDuplicateKeyConstructor.construct_mapping
142
- )
127
+ Args:
128
+ config_file (str): The path to the configuration file.
129
+ filename (str): The name of the configuration file.
130
+ is_local (bool): Indicates if the config file is from the local folder.
131
+
132
+ Returns:
133
+ dict: The loaded configuration.
134
+ """
135
+ from ..custom_logging import log
136
+ from ruamel.yaml import YAML, DuplicateKeyError
143
137
 
144
138
  with open(config_file, 'r') as file:
145
139
  if filename.endswith('.json'):
146
140
  config = json.load(file)
147
141
  else:
148
- config = yaml.load(file, Loader=NoDuplicateKeyLoader)
142
+ # Create YAML parser that forbids duplicates
143
+ yaml = YAML(typ='safe')
144
+ yaml.allow_duplicate_keys = False
145
+ try:
146
+ config = yaml.load(file)
147
+ except DuplicateKeyError as e:
148
+ raise ValueError(f"Duplicate key found in {filename}: {str(e)}")
149
149
 
150
150
  self.config_cache[filename] = (config, datetime.now())
151
151
  if is_local:
@@ -14,9 +14,6 @@
14
14
  import os
15
15
  import requests
16
16
  import socket
17
- # can't install due to circular import sunholo.logging
18
- import logging
19
-
20
17
 
21
18
  def is_running_on_cloudrun():
22
19
  """
@@ -13,6 +13,8 @@ import json
13
13
  from io import StringIO
14
14
  import os
15
15
  import re
16
+ from ruamel.yaml import YAML
17
+ yaml = YAML(typ='safe')
16
18
 
17
19
  class VertexAIExtensions:
18
20
  """
@@ -115,13 +117,12 @@ class VertexAIExtensions:
115
117
  def upload_openapi_file(self, filename: str, extension_name:str, vac:str=None):
116
118
  if vac:
117
119
  from ..agents.route import route_vac
118
- import yaml
119
120
 
120
121
  new_url = route_vac(vac)
121
122
 
122
123
  log.info(f'Overwriting extension URL with VAC url for {vac=} - {new_url=}')
123
124
 
124
- openapi = yaml.safe_load(filename)
125
+ openapi = yaml.load(filename)
125
126
 
126
127
  openapi['servers'][0]['url'] = new_url
127
128
  with open(filename, 'w') as file:
@@ -145,10 +146,9 @@ class VertexAIExtensions:
145
146
  return self.current_extension.api_spec()
146
147
 
147
148
  def load_tool_use_examples(self, filename: str):
148
- import yaml
149
149
 
150
150
  with open(filename, 'r') as file:
151
- self.tool_use_examples = yaml.safe_load(file)
151
+ self.tool_use_examples = yaml.load(file)
152
152
 
153
153
  # google.cloud.aiplatform_v1beta1.types.ToolUseExample
154
154
  return self.tool_use_examples