sunholo 0.140.5__tar.gz → 0.140.7__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 (189) hide show
  1. {sunholo-0.140.5/src/sunholo.egg-info → sunholo-0.140.7}/PKG-INFO +1 -1
  2. {sunholo-0.140.5 → sunholo-0.140.7}/pyproject.toml +1 -1
  3. sunholo-0.140.7/src/sunholo/agents/flask/base.py +48 -0
  4. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/agents/flask/vac_routes.py +191 -92
  5. {sunholo-0.140.5 → sunholo-0.140.7/src/sunholo.egg-info}/PKG-INFO +1 -1
  6. sunholo-0.140.5/src/sunholo/agents/flask/base.py +0 -22
  7. {sunholo-0.140.5 → sunholo-0.140.7}/LICENSE.txt +0 -0
  8. {sunholo-0.140.5 → sunholo-0.140.7}/MANIFEST.in +0 -0
  9. {sunholo-0.140.5 → sunholo-0.140.7}/README.md +0 -0
  10. {sunholo-0.140.5 → sunholo-0.140.7}/setup.cfg +0 -0
  11. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/__init__.py +0 -0
  12. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/agents/__init__.py +0 -0
  13. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/agents/chat_history.py +0 -0
  14. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/agents/dispatch_to_qa.py +0 -0
  15. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/agents/fastapi/__init__.py +0 -0
  16. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/agents/fastapi/base.py +0 -0
  17. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/agents/fastapi/qna_routes.py +0 -0
  18. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/agents/flask/__init__.py +0 -0
  19. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/agents/langserve.py +0 -0
  20. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/agents/pubsub.py +0 -0
  21. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/agents/route.py +0 -0
  22. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/agents/special_commands.py +0 -0
  23. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/agents/swagger.py +0 -0
  24. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/archive/__init__.py +0 -0
  25. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/archive/archive.py +0 -0
  26. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/auth/__init__.py +0 -0
  27. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/auth/gcloud.py +0 -0
  28. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/auth/refresh.py +0 -0
  29. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/auth/run.py +0 -0
  30. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/azure/__init__.py +0 -0
  31. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/azure/auth.py +0 -0
  32. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/azure/blobs.py +0 -0
  33. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/azure/event_grid.py +0 -0
  34. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/bots/__init__.py +0 -0
  35. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/bots/discord.py +0 -0
  36. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/bots/github_webhook.py +0 -0
  37. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/bots/webapp.py +0 -0
  38. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/chunker/__init__.py +0 -0
  39. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/chunker/azure.py +0 -0
  40. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/chunker/doc_handling.py +0 -0
  41. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/chunker/encode_metadata.py +0 -0
  42. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/chunker/images.py +0 -0
  43. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/chunker/loaders.py +0 -0
  44. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/chunker/message_data.py +0 -0
  45. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/chunker/pdfs.py +0 -0
  46. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/chunker/process_chunker_data.py +0 -0
  47. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/chunker/publish.py +0 -0
  48. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/chunker/pubsub.py +0 -0
  49. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/chunker/splitter.py +0 -0
  50. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/cli/__init__.py +0 -0
  51. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/cli/chat_vac.py +0 -0
  52. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/cli/cli.py +0 -0
  53. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/cli/cli_init.py +0 -0
  54. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/cli/configs.py +0 -0
  55. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/cli/deploy.py +0 -0
  56. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/cli/embedder.py +0 -0
  57. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/cli/merge_texts.py +0 -0
  58. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/cli/run_proxy.py +0 -0
  59. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/cli/sun_rich.py +0 -0
  60. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/cli/swagger.py +0 -0
  61. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/cli/vertex.py +0 -0
  62. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/components/__init__.py +0 -0
  63. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/components/llm.py +0 -0
  64. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/components/retriever.py +0 -0
  65. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/components/vectorstore.py +0 -0
  66. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/custom_logging.py +0 -0
  67. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/database/__init__.py +0 -0
  68. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/database/alloydb.py +0 -0
  69. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/database/alloydb_client.py +0 -0
  70. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/database/database.py +0 -0
  71. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/database/lancedb.py +0 -0
  72. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/database/sql/sb/create_function.sql +0 -0
  73. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/database/sql/sb/create_function_time.sql +0 -0
  74. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/database/sql/sb/create_table.sql +0 -0
  75. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/database/sql/sb/delete_source_row.sql +0 -0
  76. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/database/sql/sb/return_sources.sql +0 -0
  77. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/database/sql/sb/setup.sql +0 -0
  78. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/database/static_dbs.py +0 -0
  79. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/database/uuid.py +0 -0
  80. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/discovery_engine/__init__.py +0 -0
  81. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/discovery_engine/chunker_handler.py +0 -0
  82. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/discovery_engine/cli.py +0 -0
  83. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/discovery_engine/create_new.py +0 -0
  84. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/discovery_engine/discovery_engine_client.py +0 -0
  85. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/discovery_engine/get_ai_search_chunks.py +0 -0
  86. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/embedder/__init__.py +0 -0
  87. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/embedder/embed_chunk.py +0 -0
  88. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/embedder/embed_metadata.py +0 -0
  89. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/excel/__init__.py +0 -0
  90. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/excel/plugin.py +0 -0
  91. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/gcs/__init__.py +0 -0
  92. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/gcs/add_file.py +0 -0
  93. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/gcs/download_folder.py +0 -0
  94. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/gcs/download_gcs_text.py +0 -0
  95. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/gcs/download_url.py +0 -0
  96. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/gcs/extract_and_sign.py +0 -0
  97. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/gcs/metadata.py +0 -0
  98. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/genai/__init__.py +0 -0
  99. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/genai/file_handling.py +0 -0
  100. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/genai/genaiv2.py +0 -0
  101. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/genai/images.py +0 -0
  102. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/genai/init.py +0 -0
  103. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/genai/process_funcs_cls.py +0 -0
  104. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/genai/safety.py +0 -0
  105. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/invoke/__init__.py +0 -0
  106. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/invoke/async_class.py +0 -0
  107. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/invoke/direct_vac_func.py +0 -0
  108. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/invoke/invoke_vac_utils.py +0 -0
  109. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/langchain_types.py +0 -0
  110. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/langfuse/__init__.py +0 -0
  111. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/langfuse/callback.py +0 -0
  112. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/langfuse/evals.py +0 -0
  113. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/langfuse/prompts.py +0 -0
  114. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/llamaindex/__init__.py +0 -0
  115. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/llamaindex/get_files.py +0 -0
  116. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/llamaindex/import_files.py +0 -0
  117. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/llamaindex/llamaindex_class.py +0 -0
  118. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/llamaindex/user_history.py +0 -0
  119. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/lookup/__init__.py +0 -0
  120. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/lookup/model_lookup.yaml +0 -0
  121. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/mcp/__init__.py +0 -0
  122. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/mcp/cli.py +0 -0
  123. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/ollama/__init__.py +0 -0
  124. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/ollama/ollama_images.py +0 -0
  125. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/pubsub/__init__.py +0 -0
  126. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/pubsub/process_pubsub.py +0 -0
  127. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/pubsub/pubsub_manager.py +0 -0
  128. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/qna/__init__.py +0 -0
  129. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/qna/parsers.py +0 -0
  130. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/qna/retry.py +0 -0
  131. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/senses/__init__.py +0 -0
  132. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/senses/stream_voice.py +0 -0
  133. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/streaming/__init__.py +0 -0
  134. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/streaming/content_buffer.py +0 -0
  135. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/streaming/langserve.py +0 -0
  136. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/streaming/stream_lookup.py +0 -0
  137. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/streaming/streaming.py +0 -0
  138. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/summarise/__init__.py +0 -0
  139. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/summarise/summarise.py +0 -0
  140. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/templates/agent/__init__.py +0 -0
  141. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/templates/agent/agent_service.py +0 -0
  142. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/templates/agent/app.py +0 -0
  143. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/templates/agent/my_log.py +0 -0
  144. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/templates/agent/tools/__init__.py +0 -0
  145. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/templates/agent/tools/your_agent.py +0 -0
  146. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/templates/agent/vac_service.py +0 -0
  147. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/templates/project/__init__.py +0 -0
  148. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/templates/project/app.py +0 -0
  149. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/templates/project/my_log.py +0 -0
  150. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/templates/project/vac_service.py +0 -0
  151. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/templates/system_services/__init__.py +0 -0
  152. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/templates/system_services/app.py +0 -0
  153. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/templates/system_services/my_log.py +0 -0
  154. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/terraform/__init__.py +0 -0
  155. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/terraform/tfvars_editor.py +0 -0
  156. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/tools/__init__.py +0 -0
  157. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/tools/web_browser.py +0 -0
  158. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/utils/__init__.py +0 -0
  159. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/utils/api_key.py +0 -0
  160. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/utils/big_context.py +0 -0
  161. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/utils/config.py +0 -0
  162. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/utils/config_class.py +0 -0
  163. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/utils/config_schema.py +0 -0
  164. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/utils/gcp.py +0 -0
  165. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/utils/gcp_project.py +0 -0
  166. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/utils/mime.py +0 -0
  167. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/utils/parsers.py +0 -0
  168. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/utils/timedelta.py +0 -0
  169. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/utils/user_ids.py +0 -0
  170. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/utils/version.py +0 -0
  171. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/vertex/__init__.py +0 -0
  172. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/vertex/extensions_call.py +0 -0
  173. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/vertex/extensions_class.py +0 -0
  174. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/vertex/genai_functions.py +0 -0
  175. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/vertex/init.py +0 -0
  176. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/vertex/memory_tools.py +0 -0
  177. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/vertex/safety.py +0 -0
  178. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo/vertex/type_dict_to_json.py +0 -0
  179. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo.egg-info/SOURCES.txt +0 -0
  180. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo.egg-info/dependency_links.txt +0 -0
  181. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo.egg-info/entry_points.txt +0 -0
  182. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo.egg-info/requires.txt +0 -0
  183. {sunholo-0.140.5 → sunholo-0.140.7}/src/sunholo.egg-info/top_level.txt +0 -0
  184. {sunholo-0.140.5 → sunholo-0.140.7}/tests/test_async.py +0 -0
  185. {sunholo-0.140.5 → sunholo-0.140.7}/tests/test_async_genai2.py +0 -0
  186. {sunholo-0.140.5 → sunholo-0.140.7}/tests/test_chat_history.py +0 -0
  187. {sunholo-0.140.5 → sunholo-0.140.7}/tests/test_config.py +0 -0
  188. {sunholo-0.140.5 → sunholo-0.140.7}/tests/test_genai2.py +0 -0
  189. {sunholo-0.140.5 → sunholo-0.140.7}/tests/test_unstructured.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sunholo
3
- Version: 0.140.5
3
+ Version: 0.140.7
4
4
  Summary: AI DevOps - a package to help deploy GenAI to the Cloud.
5
5
  Author-email: Holosun ApS <multivac@sunholo.com>
6
6
  License: Apache License, Version 2.0
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "sunholo"
7
- version = "0.140.5"
7
+ version = "0.140.7"
8
8
  description = "AI DevOps - a package to help deploy GenAI to the Cloud."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -0,0 +1,48 @@
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
+
15
+ from ...custom_logging import log
16
+ import time
17
+
18
+ def create_app(name):
19
+ from flask import Flask, request
20
+
21
+ app = Flask(name)
22
+
23
+ app.config['TRAP_HTTP_EXCEPTIONS'] = True
24
+ app.config['PROPAGATE_EXCEPTIONS'] = True
25
+
26
+ @app.before_request
27
+ def start_timer():
28
+ request.start_time = time.time()
29
+
30
+ @app.after_request
31
+ def log_timing(response):
32
+ if hasattr(request, 'start_time'):
33
+ duration = time.time() - request.start_time
34
+
35
+ # Log all VAC requests with different detail levels
36
+ if request.path.startswith('/vac/streaming/'):
37
+ log.info(f"🚀 STREAMING: {duration:.3f}s - {request.path}")
38
+ elif request.path.startswith('/vac/'):
39
+ log.info(f"⚡ VAC: {duration:.3f}s - {request.path}")
40
+ elif duration > 1.0: # Log any slow requests
41
+ log.warning(f"🐌 SLOW REQUEST: {duration:.3f}s - {request.path}")
42
+
43
+ # Add response headers with timing info for debugging
44
+ response.headers['X-Response-Time'] = f"{duration:.3f}s"
45
+
46
+ return response
47
+
48
+ return app
@@ -6,8 +6,11 @@ import random
6
6
  from functools import partial
7
7
  import inspect
8
8
  import asyncio
9
+ import time
10
+ import threading
11
+ from functools import lru_cache
12
+ from concurrent.futures import ThreadPoolExecutor
9
13
 
10
- from ...agents import handle_special_commands
11
14
  from ..chat_history import extract_chat_history_with_cache, extract_chat_history_async_cached
12
15
  from ...qna.parsers import parse_output
13
16
  from ...streaming import start_streaming_chat, start_streaming_chat_async
@@ -33,6 +36,11 @@ except ImportError:
33
36
  # Cache dictionary to store validated API keys
34
37
  api_key_cache = {}
35
38
  cache_duration = timedelta(minutes=5) # Cache duration
39
+ # Global caches and thread pool (add these after your existing globals)
40
+ _config_cache = {}
41
+ _config_lock = threading.Lock()
42
+ _thread_pool = ThreadPoolExecutor(max_workers=4)
43
+
36
44
 
37
45
  class VACRoutes:
38
46
  """
@@ -70,8 +78,37 @@ if __name__ == "__main__":
70
78
  self.additional_routes = additional_routes if additional_routes is not None else []
71
79
  self.async_stream = async_stream
72
80
  self.add_langfuse_eval = add_langfuse_eval
81
+
82
+ # Pre-warm common configs
83
+ self._preload_common_configs()
84
+
73
85
  self.register_routes()
74
-
86
+
87
+ def _preload_common_configs(self):
88
+ """Pre-load commonly used configurations to cache"""
89
+ common_vector_names = ["aitana3"] # Add your common vector names
90
+ for vector_name in common_vector_names:
91
+ try:
92
+ self._get_cached_config(vector_name)
93
+ log.info(f"Pre-loaded config for {vector_name}")
94
+ except Exception as e:
95
+ log.warning(f"Failed to pre-load config for {vector_name}: {e}")
96
+
97
+
98
+ @lru_cache(maxsize=100)
99
+ def _get_cached_config(self, vector_name: str):
100
+ """Cached config loader with thread safety"""
101
+ with _config_lock:
102
+ if vector_name in _config_cache:
103
+ return _config_cache[vector_name]
104
+
105
+ try:
106
+ config = ConfigManager(vector_name)
107
+ _config_cache[vector_name] = config
108
+ return config
109
+ except Exception as e:
110
+ log.error(f"Error loading config for {vector_name}: {e}")
111
+ raise
75
112
 
76
113
  def vac_interpreter_default(self, question: str, vector_name: str, chat_history=[], **kwargs):
77
114
  # Create a callback that does nothing for streaming if you don't want intermediate outputs
@@ -229,26 +266,43 @@ if __name__ == "__main__":
229
266
 
230
267
  log.info(f"OpenAI response: {openai_response}")
231
268
  return jsonify(openai_response)
232
-
269
+
270
+ def _finalize_trace_background(self, trace, span, response, all_input):
271
+ """Finalize trace operations in background"""
272
+ try:
273
+ if span:
274
+ span.end(output=str(response))
275
+ if trace:
276
+ trace.update(output=str(response))
277
+ self.langfuse_eval_response(trace_id=trace.id, eval_percent=all_input.get('eval_percent'))
278
+ except Exception as e:
279
+ log.warning(f"Background trace finalization failed: {e}")
280
+
233
281
  def handle_stream_vac(self, vector_name):
282
+ request_start = time.time()
234
283
  observed_stream_interpreter = self.stream_interpreter
235
284
  is_async = inspect.iscoroutinefunction(self.stream_interpreter)
236
285
 
237
286
  if is_async:
238
287
  log.info(f"Stream interpreter is async: {observed_stream_interpreter}")
239
288
 
289
+ # Fast prep
240
290
  prep = self.prep_vac(request, vector_name)
241
- log.info(f"Processing prep: {prep}")
242
- trace = prep["trace"]
243
- span = prep["span"]
244
- command_response = prep["command_response"]
291
+
292
+ # Check for prep errors
293
+ if isinstance(prep, tuple) and len(prep) == 2:
294
+ error_response, status_code = prep
295
+ return jsonify(error_response), status_code
296
+
297
+ log.info(f"Processing prep completed in {time.time() - request_start:.3f}s")
298
+
299
+ trace = prep.get("trace")
300
+ span = prep.get("span")
245
301
  vac_config = prep["vac_config"]
246
302
  all_input = prep["all_input"]
247
303
 
248
- if command_response:
249
- return jsonify(command_response)
250
-
251
- log.info(f'Streaming data with: {all_input}')
304
+ log.info(f'Starting stream with: {all_input["user_input"][:100]}...')
305
+
252
306
  if span:
253
307
  span.update(
254
308
  name="start_streaming_chat",
@@ -259,7 +313,7 @@ if __name__ == "__main__":
259
313
  def generate_response_content():
260
314
  try:
261
315
  if is_async:
262
- from queue import Queue, Empty
316
+ from queue import Queue
263
317
  result_queue = Queue()
264
318
  import threading
265
319
 
@@ -276,7 +330,7 @@ if __name__ == "__main__":
276
330
  trace_id=trace.id if trace else None,
277
331
  **all_input["kwargs"]
278
332
  )
279
- log.info(f"{async_gen=}")
333
+
280
334
  async for chunk in async_gen:
281
335
  if isinstance(chunk, dict) and 'answer' in chunk:
282
336
  if trace:
@@ -292,6 +346,7 @@ if __name__ == "__main__":
292
346
  result_queue.put(f"Streaming Error: {str(e)} {traceback.format_exc()}")
293
347
  finally:
294
348
  result_queue.put(None) # Sentinel
349
+
295
350
  asyncio.run(process_async())
296
351
 
297
352
  thread = threading.Thread(target=run_async)
@@ -306,7 +361,7 @@ if __name__ == "__main__":
306
361
 
307
362
  thread.join()
308
363
  else:
309
- log.info("sync streaming response")
364
+ log.info("Starting sync streaming response")
310
365
  for chunk in start_streaming_chat(
311
366
  question=all_input["user_input"],
312
367
  vector_name=vector_name,
@@ -332,15 +387,15 @@ if __name__ == "__main__":
332
387
  except Exception as e:
333
388
  yield f"Streaming Error: {str(e)} {traceback.format_exc()}"
334
389
 
335
- # Here, the generator function will handle streaming the content to the client.
390
+ # Create streaming response
336
391
  response = Response(generate_response_content(), content_type='text/plain; charset=utf-8')
337
392
  response.headers['Transfer-Encoding'] = 'chunked'
338
393
 
339
- log.debug(f"streaming response: {response}")
394
+ log.debug(f"Streaming response created in {time.time() - request_start:.3f}s")
395
+
340
396
  if trace:
341
- span.end(output=response)
342
- trace.update(output=response)
343
- self.langfuse_eval_response(trace_id=trace.id, eval_percent=all_input.get('eval_percent'))
397
+ # Do final trace operations in background
398
+ _thread_pool.submit(self._finalize_trace_background, trace, span, response, all_input)
344
399
 
345
400
  return response
346
401
 
@@ -432,13 +487,9 @@ if __name__ == "__main__":
432
487
  log.debug(f"Processing prep: {prep}")
433
488
  trace = prep["trace"]
434
489
  span = prep["span"]
435
- command_response = prep["command_response"]
436
490
  vac_config: ConfigManager = prep["vac_config"]
437
491
  all_input = prep["all_input"]
438
492
 
439
- if command_response:
440
- return jsonify(command_response)
441
-
442
493
  try:
443
494
  if span:
444
495
  gen = span.generation(
@@ -536,8 +587,6 @@ if __name__ == "__main__":
536
587
  image_uri = None
537
588
  mime_type = None
538
589
 
539
-
540
-
541
590
  for msg in reversed(messages):
542
591
  if msg['role'] == 'user':
543
592
  if isinstance(msg['content'], list):
@@ -556,14 +605,6 @@ if __name__ == "__main__":
556
605
  else:
557
606
  log.info(f"User message: {user_message}")
558
607
 
559
- paired_messages = extract_chat_history_with_cache(chat_history)
560
-
561
- command_response = handle_special_commands(user_message, vector_name, paired_messages)
562
-
563
- if command_response is not None:
564
-
565
- return self.make_openai_response(user_message, vector_name, command_response)
566
-
567
608
  if image_uri:
568
609
  data["image_uri"] = image_uri
569
610
  data["mime"] = mime_type
@@ -673,78 +714,136 @@ if __name__ == "__main__":
673
714
  tags = tags,
674
715
  release = package_version
675
716
  )
717
+
718
+ def _create_langfuse_trace_background(self, request, vector_name, trace_id):
719
+ """Create Langfuse trace in background"""
720
+ try:
721
+ return self.create_langfuse_trace(request, vector_name, trace_id)
722
+ except Exception as e:
723
+ log.warning(f"Background trace creation failed: {e}")
724
+ return None
676
725
 
726
+ def _handle_file_upload_background(self, file, vector_name):
727
+ """Handle file upload in background thread"""
728
+ try:
729
+ # Save with timestamp to avoid conflicts
730
+ temp_filename = f"temp_{int(time.time() * 1000)}_{file.filename}"
731
+ file.save(temp_filename)
732
+
733
+ # Upload to GCS
734
+ image_uri = add_file_to_gcs(temp_filename, vector_name)
735
+
736
+ # Clean up
737
+ os.remove(temp_filename)
738
+
739
+ return {"image_uri": image_uri, "mime": file.mimetype}
740
+ except Exception as e:
741
+ log.error(f"Background file upload failed: {e}")
742
+ return {}
743
+
677
744
  def prep_vac(self, request, vector_name):
745
+ start_time = time.time()
746
+
747
+ # Fast request parsing
748
+ try:
749
+ if request.content_type.startswith('application/json'):
750
+ data = request.get_json()
751
+ elif request.content_type.startswith('multipart/form-data'):
752
+ data = request.form.to_dict()
753
+ # Handle file upload in background if present
754
+ if 'file' in request.files:
755
+ file = request.files['file']
756
+ if file.filename != '':
757
+ log.info(f"Found file: {file.filename} - uploading in background")
758
+ # Start file upload in background, don't block
759
+ upload_future = _thread_pool.submit(self._handle_file_upload_background, file, vector_name)
760
+ data["_upload_future"] = upload_future
761
+ else:
762
+ return {"error": "Unsupported content type"}, 400
763
+ except Exception as e:
764
+ return {"error": f"Request parsing error: {str(e)}"}, 400
678
765
 
679
- if request.content_type.startswith('application/json'):
680
- data = request.get_json()
681
- elif request.content_type.startswith('multipart/form-data'):
682
- data = request.form.to_dict()
683
- if 'file' in request.files:
684
- file = request.files['file']
685
- if file.filename != '':
686
- log.info(f"Found file: {file.filename} to upload to GCS")
687
- try:
688
- image_uri, mime_type = self.handle_file_upload(file, vector_name)
689
- data["image_uri"] = image_uri
690
- data["mime"] = mime_type
691
- except Exception as e:
692
- log.error(traceback.format_exc())
693
- return jsonify({'error': str(e), 'traceback': traceback.format_exc()}), 500
694
- else:
695
- log.error("No file selected")
696
- return jsonify({"error": "No file selected"}), 400
697
- else:
698
- return jsonify({"error": "Unsupported content type"}), 400
766
+ log.info(f"vac/{vector_name} got data keys: {list(data.keys())}")
699
767
 
700
- log.info(f"vac/{vector_name} got data: {data}")
768
+ # Extract essential data first
769
+ try:
770
+ user_input = data.pop('user_input').strip()
771
+ stream_wait_time = data.pop('stream_wait_time', 7)
772
+ stream_timeout = data.pop('stream_timeout', 120)
773
+ chat_history = data.pop('chat_history', None)
774
+ eval_percent = data.pop('eval_percent', 0.01)
775
+ vector_name_param = data.pop('vector_name', vector_name)
776
+ trace_id = data.pop('trace_id', None)
777
+
778
+ if not user_input:
779
+ return {"error": "No user input provided"}, 400
780
+
781
+ except Exception as e:
782
+ return {"error": f"Required field missing: {str(e)}"}, 400
701
783
 
702
- trace = None
703
- span = None
704
- if self.add_langfuse_eval:
705
- trace_id = data.get('trace_id')
706
- trace = self.create_langfuse_trace(request, vector_name, trace_id)
707
- log.info(f"Using existing langfuse trace: {trace_id}")
708
-
709
- #config, _ = load_config("config/llm_config.yaml")
784
+ # Get config from cache (should be very fast)
710
785
  try:
711
- vac_config = ConfigManager(vector_name)
786
+ vac_config = self._get_cached_config(vector_name)
712
787
  except Exception as e:
713
- raise ValueError(f"Unable to find vac_config for {vector_name} - {str(e)}")
788
+ log.error(f"Config error: {e}")
789
+ return {"error": f"Unable to find vac_config for {vector_name} - {str(e)}"}, 500
714
790
 
715
- if trace:
716
- this_vac_config = vac_config.configs_by_kind.get("vacConfig")
717
- metadata_config=None
718
- if this_vac_config:
719
- metadata_config = this_vac_config.get(vector_name)
791
+ # Process chat history with caching (should be fast)
792
+ paired_messages = extract_chat_history_with_cache(chat_history)
720
793
 
721
- trace.update(input=data, metadata=metadata_config)
794
+ # Start tracing in background (don't block)
795
+ trace = None
796
+ span = None
797
+ if self.add_langfuse_eval:
798
+ trace_future = _thread_pool.submit(self._create_langfuse_trace_background, request, vector_name, trace_id)
799
+ # We'll get the trace result later if needed
722
800
 
723
- user_input = data.pop('user_input').strip()
724
- stream_wait_time = data.pop('stream_wait_time', 7)
725
- stream_timeout = data.pop('stream_timeout', 120)
726
- chat_history = data.pop('chat_history', None)
727
- eval_percent = data.pop('eval_percent', 0.01)
728
- vector_name = data.pop('vector_name', vector_name)
729
- data.pop('trace_id', None) # to ensure not in kwargs
801
+ # Wait for file upload if it was started (with timeout)
802
+ if "_upload_future" in data:
803
+ try:
804
+ upload_result = data["_upload_future"].result(timeout=3.0) # 3 sec max wait
805
+ data.update(upload_result)
806
+ log.info(f"File upload completed: {upload_result.get('image_uri', 'no uri')}")
807
+ except Exception as e:
808
+ log.warning(f"File upload failed or timed out: {e}")
809
+ finally:
810
+ data.pop("_upload_future", None)
730
811
 
731
- paired_messages = extract_chat_history_with_cache(chat_history)
812
+ # Build final input
813
+ all_input = {
814
+ 'user_input': user_input,
815
+ 'vector_name': vector_name_param,
816
+ 'chat_history': paired_messages,
817
+ 'stream_wait_time': stream_wait_time,
818
+ 'stream_timeout': stream_timeout,
819
+ 'eval_percent': eval_percent,
820
+ 'kwargs': data
821
+ }
732
822
 
733
- all_input = {'user_input': user_input,
734
- 'vector_name': vector_name,
735
- 'chat_history': paired_messages,
736
- 'stream_wait_time': stream_wait_time,
737
- 'stream_timeout': stream_timeout,
738
- 'eval_percent': eval_percent,
739
- 'kwargs': data}
823
+ # Try to get trace result if available (don't block long)
824
+ if self.add_langfuse_eval:
825
+ try:
826
+ trace = trace_future.result(timeout=0.5) # 500ms max wait
827
+ if trace:
828
+ this_vac_config = vac_config.configs_by_kind.get("vacConfig")
829
+ metadata_config = None
830
+ if this_vac_config:
831
+ metadata_config = this_vac_config.get(vector_name)
832
+ trace.update(input=data, metadata=metadata_config)
833
+
834
+ span = trace.span(
835
+ name="VAC",
836
+ metadata=vac_config.configs_by_kind,
837
+ input=all_input
838
+ )
839
+ except Exception as e:
840
+ log.warning(f"Langfuse trace creation timed out or failed: {e}")
841
+ trace = None
842
+ span = None
843
+
844
+ prep_time = time.time() - start_time
845
+ log.info(f"prep_vac completed in {prep_time:.3f}s")
740
846
 
741
- if trace:
742
- span = trace.span(
743
- name="VAC",
744
- metadata=vac_config.configs_by_kind,
745
- input = all_input
746
- )
747
-
748
847
  return {
749
848
  "trace": trace,
750
849
  "span": span,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sunholo
3
- Version: 0.140.5
3
+ Version: 0.140.7
4
4
  Summary: AI DevOps - a package to help deploy GenAI to the Cloud.
5
5
  Author-email: Holosun ApS <multivac@sunholo.com>
6
6
  License: Apache License, Version 2.0
@@ -1,22 +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
- def create_app(name):
15
- from flask import Flask
16
-
17
- app = Flask(name)
18
-
19
- app.config['TRAP_HTTP_EXCEPTIONS'] = True
20
- app.config['PROPAGATE_EXCEPTIONS'] = True
21
-
22
- return app
File without changes
File without changes
File without changes
File without changes