sunholo 0.140.6__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.6/src/sunholo.egg-info → sunholo-0.140.7}/PKG-INFO +1 -1
  2. {sunholo-0.140.6 → 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.6 → sunholo-0.140.7}/src/sunholo/agents/flask/vac_routes.py +191 -73
  5. {sunholo-0.140.6 → sunholo-0.140.7/src/sunholo.egg-info}/PKG-INFO +1 -1
  6. sunholo-0.140.6/src/sunholo/agents/flask/base.py +0 -22
  7. {sunholo-0.140.6 → sunholo-0.140.7}/LICENSE.txt +0 -0
  8. {sunholo-0.140.6 → sunholo-0.140.7}/MANIFEST.in +0 -0
  9. {sunholo-0.140.6 → sunholo-0.140.7}/README.md +0 -0
  10. {sunholo-0.140.6 → sunholo-0.140.7}/setup.cfg +0 -0
  11. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/__init__.py +0 -0
  12. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/agents/__init__.py +0 -0
  13. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/agents/chat_history.py +0 -0
  14. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/agents/dispatch_to_qa.py +0 -0
  15. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/agents/fastapi/__init__.py +0 -0
  16. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/agents/fastapi/base.py +0 -0
  17. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/agents/fastapi/qna_routes.py +0 -0
  18. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/agents/flask/__init__.py +0 -0
  19. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/agents/langserve.py +0 -0
  20. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/agents/pubsub.py +0 -0
  21. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/agents/route.py +0 -0
  22. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/agents/special_commands.py +0 -0
  23. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/agents/swagger.py +0 -0
  24. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/archive/__init__.py +0 -0
  25. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/archive/archive.py +0 -0
  26. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/auth/__init__.py +0 -0
  27. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/auth/gcloud.py +0 -0
  28. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/auth/refresh.py +0 -0
  29. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/auth/run.py +0 -0
  30. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/azure/__init__.py +0 -0
  31. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/azure/auth.py +0 -0
  32. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/azure/blobs.py +0 -0
  33. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/azure/event_grid.py +0 -0
  34. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/bots/__init__.py +0 -0
  35. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/bots/discord.py +0 -0
  36. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/bots/github_webhook.py +0 -0
  37. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/bots/webapp.py +0 -0
  38. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/chunker/__init__.py +0 -0
  39. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/chunker/azure.py +0 -0
  40. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/chunker/doc_handling.py +0 -0
  41. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/chunker/encode_metadata.py +0 -0
  42. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/chunker/images.py +0 -0
  43. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/chunker/loaders.py +0 -0
  44. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/chunker/message_data.py +0 -0
  45. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/chunker/pdfs.py +0 -0
  46. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/chunker/process_chunker_data.py +0 -0
  47. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/chunker/publish.py +0 -0
  48. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/chunker/pubsub.py +0 -0
  49. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/chunker/splitter.py +0 -0
  50. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/cli/__init__.py +0 -0
  51. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/cli/chat_vac.py +0 -0
  52. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/cli/cli.py +0 -0
  53. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/cli/cli_init.py +0 -0
  54. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/cli/configs.py +0 -0
  55. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/cli/deploy.py +0 -0
  56. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/cli/embedder.py +0 -0
  57. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/cli/merge_texts.py +0 -0
  58. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/cli/run_proxy.py +0 -0
  59. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/cli/sun_rich.py +0 -0
  60. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/cli/swagger.py +0 -0
  61. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/cli/vertex.py +0 -0
  62. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/components/__init__.py +0 -0
  63. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/components/llm.py +0 -0
  64. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/components/retriever.py +0 -0
  65. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/components/vectorstore.py +0 -0
  66. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/custom_logging.py +0 -0
  67. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/database/__init__.py +0 -0
  68. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/database/alloydb.py +0 -0
  69. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/database/alloydb_client.py +0 -0
  70. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/database/database.py +0 -0
  71. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/database/lancedb.py +0 -0
  72. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/database/sql/sb/create_function.sql +0 -0
  73. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/database/sql/sb/create_function_time.sql +0 -0
  74. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/database/sql/sb/create_table.sql +0 -0
  75. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/database/sql/sb/delete_source_row.sql +0 -0
  76. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/database/sql/sb/return_sources.sql +0 -0
  77. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/database/sql/sb/setup.sql +0 -0
  78. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/database/static_dbs.py +0 -0
  79. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/database/uuid.py +0 -0
  80. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/discovery_engine/__init__.py +0 -0
  81. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/discovery_engine/chunker_handler.py +0 -0
  82. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/discovery_engine/cli.py +0 -0
  83. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/discovery_engine/create_new.py +0 -0
  84. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/discovery_engine/discovery_engine_client.py +0 -0
  85. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/discovery_engine/get_ai_search_chunks.py +0 -0
  86. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/embedder/__init__.py +0 -0
  87. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/embedder/embed_chunk.py +0 -0
  88. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/embedder/embed_metadata.py +0 -0
  89. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/excel/__init__.py +0 -0
  90. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/excel/plugin.py +0 -0
  91. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/gcs/__init__.py +0 -0
  92. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/gcs/add_file.py +0 -0
  93. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/gcs/download_folder.py +0 -0
  94. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/gcs/download_gcs_text.py +0 -0
  95. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/gcs/download_url.py +0 -0
  96. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/gcs/extract_and_sign.py +0 -0
  97. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/gcs/metadata.py +0 -0
  98. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/genai/__init__.py +0 -0
  99. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/genai/file_handling.py +0 -0
  100. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/genai/genaiv2.py +0 -0
  101. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/genai/images.py +0 -0
  102. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/genai/init.py +0 -0
  103. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/genai/process_funcs_cls.py +0 -0
  104. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/genai/safety.py +0 -0
  105. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/invoke/__init__.py +0 -0
  106. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/invoke/async_class.py +0 -0
  107. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/invoke/direct_vac_func.py +0 -0
  108. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/invoke/invoke_vac_utils.py +0 -0
  109. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/langchain_types.py +0 -0
  110. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/langfuse/__init__.py +0 -0
  111. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/langfuse/callback.py +0 -0
  112. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/langfuse/evals.py +0 -0
  113. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/langfuse/prompts.py +0 -0
  114. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/llamaindex/__init__.py +0 -0
  115. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/llamaindex/get_files.py +0 -0
  116. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/llamaindex/import_files.py +0 -0
  117. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/llamaindex/llamaindex_class.py +0 -0
  118. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/llamaindex/user_history.py +0 -0
  119. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/lookup/__init__.py +0 -0
  120. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/lookup/model_lookup.yaml +0 -0
  121. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/mcp/__init__.py +0 -0
  122. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/mcp/cli.py +0 -0
  123. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/ollama/__init__.py +0 -0
  124. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/ollama/ollama_images.py +0 -0
  125. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/pubsub/__init__.py +0 -0
  126. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/pubsub/process_pubsub.py +0 -0
  127. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/pubsub/pubsub_manager.py +0 -0
  128. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/qna/__init__.py +0 -0
  129. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/qna/parsers.py +0 -0
  130. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/qna/retry.py +0 -0
  131. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/senses/__init__.py +0 -0
  132. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/senses/stream_voice.py +0 -0
  133. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/streaming/__init__.py +0 -0
  134. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/streaming/content_buffer.py +0 -0
  135. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/streaming/langserve.py +0 -0
  136. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/streaming/stream_lookup.py +0 -0
  137. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/streaming/streaming.py +0 -0
  138. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/summarise/__init__.py +0 -0
  139. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/summarise/summarise.py +0 -0
  140. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/templates/agent/__init__.py +0 -0
  141. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/templates/agent/agent_service.py +0 -0
  142. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/templates/agent/app.py +0 -0
  143. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/templates/agent/my_log.py +0 -0
  144. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/templates/agent/tools/__init__.py +0 -0
  145. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/templates/agent/tools/your_agent.py +0 -0
  146. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/templates/agent/vac_service.py +0 -0
  147. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/templates/project/__init__.py +0 -0
  148. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/templates/project/app.py +0 -0
  149. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/templates/project/my_log.py +0 -0
  150. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/templates/project/vac_service.py +0 -0
  151. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/templates/system_services/__init__.py +0 -0
  152. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/templates/system_services/app.py +0 -0
  153. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/templates/system_services/my_log.py +0 -0
  154. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/terraform/__init__.py +0 -0
  155. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/terraform/tfvars_editor.py +0 -0
  156. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/tools/__init__.py +0 -0
  157. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/tools/web_browser.py +0 -0
  158. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/utils/__init__.py +0 -0
  159. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/utils/api_key.py +0 -0
  160. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/utils/big_context.py +0 -0
  161. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/utils/config.py +0 -0
  162. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/utils/config_class.py +0 -0
  163. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/utils/config_schema.py +0 -0
  164. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/utils/gcp.py +0 -0
  165. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/utils/gcp_project.py +0 -0
  166. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/utils/mime.py +0 -0
  167. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/utils/parsers.py +0 -0
  168. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/utils/timedelta.py +0 -0
  169. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/utils/user_ids.py +0 -0
  170. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/utils/version.py +0 -0
  171. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/vertex/__init__.py +0 -0
  172. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/vertex/extensions_call.py +0 -0
  173. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/vertex/extensions_class.py +0 -0
  174. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/vertex/genai_functions.py +0 -0
  175. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/vertex/init.py +0 -0
  176. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/vertex/memory_tools.py +0 -0
  177. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/vertex/safety.py +0 -0
  178. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo/vertex/type_dict_to_json.py +0 -0
  179. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo.egg-info/SOURCES.txt +0 -0
  180. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo.egg-info/dependency_links.txt +0 -0
  181. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo.egg-info/entry_points.txt +0 -0
  182. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo.egg-info/requires.txt +0 -0
  183. {sunholo-0.140.6 → sunholo-0.140.7}/src/sunholo.egg-info/top_level.txt +0 -0
  184. {sunholo-0.140.6 → sunholo-0.140.7}/tests/test_async.py +0 -0
  185. {sunholo-0.140.6 → sunholo-0.140.7}/tests/test_async_genai2.py +0 -0
  186. {sunholo-0.140.6 → sunholo-0.140.7}/tests/test_chat_history.py +0 -0
  187. {sunholo-0.140.6 → sunholo-0.140.7}/tests/test_config.py +0 -0
  188. {sunholo-0.140.6 → sunholo-0.140.7}/tests/test_genai2.py +0 -0
  189. {sunholo-0.140.6 → 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.6
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.6"
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,6 +6,10 @@ 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
14
  from ..chat_history import extract_chat_history_with_cache, extract_chat_history_async_cached
11
15
  from ...qna.parsers import parse_output
@@ -32,6 +36,11 @@ except ImportError:
32
36
  # Cache dictionary to store validated API keys
33
37
  api_key_cache = {}
34
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
+
35
44
 
36
45
  class VACRoutes:
37
46
  """
@@ -69,8 +78,37 @@ if __name__ == "__main__":
69
78
  self.additional_routes = additional_routes if additional_routes is not None else []
70
79
  self.async_stream = async_stream
71
80
  self.add_langfuse_eval = add_langfuse_eval
81
+
82
+ # Pre-warm common configs
83
+ self._preload_common_configs()
84
+
72
85
  self.register_routes()
73
-
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
74
112
 
75
113
  def vac_interpreter_default(self, question: str, vector_name: str, chat_history=[], **kwargs):
76
114
  # Create a callback that does nothing for streaming if you don't want intermediate outputs
@@ -228,22 +266,43 @@ if __name__ == "__main__":
228
266
 
229
267
  log.info(f"OpenAI response: {openai_response}")
230
268
  return jsonify(openai_response)
231
-
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
+
232
281
  def handle_stream_vac(self, vector_name):
282
+ request_start = time.time()
233
283
  observed_stream_interpreter = self.stream_interpreter
234
284
  is_async = inspect.iscoroutinefunction(self.stream_interpreter)
235
285
 
236
286
  if is_async:
237
287
  log.info(f"Stream interpreter is async: {observed_stream_interpreter}")
238
288
 
289
+ # Fast prep
239
290
  prep = self.prep_vac(request, vector_name)
240
- log.info(f"Processing prep: {prep}")
241
- trace = prep["trace"]
242
- span = prep["span"]
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")
243
301
  vac_config = prep["vac_config"]
244
302
  all_input = prep["all_input"]
245
303
 
246
- log.info(f'Streaming data with: {all_input}')
304
+ log.info(f'Starting stream with: {all_input["user_input"][:100]}...')
305
+
247
306
  if span:
248
307
  span.update(
249
308
  name="start_streaming_chat",
@@ -254,7 +313,7 @@ if __name__ == "__main__":
254
313
  def generate_response_content():
255
314
  try:
256
315
  if is_async:
257
- from queue import Queue, Empty
316
+ from queue import Queue
258
317
  result_queue = Queue()
259
318
  import threading
260
319
 
@@ -271,7 +330,7 @@ if __name__ == "__main__":
271
330
  trace_id=trace.id if trace else None,
272
331
  **all_input["kwargs"]
273
332
  )
274
- log.info(f"{async_gen=}")
333
+
275
334
  async for chunk in async_gen:
276
335
  if isinstance(chunk, dict) and 'answer' in chunk:
277
336
  if trace:
@@ -287,6 +346,7 @@ if __name__ == "__main__":
287
346
  result_queue.put(f"Streaming Error: {str(e)} {traceback.format_exc()}")
288
347
  finally:
289
348
  result_queue.put(None) # Sentinel
349
+
290
350
  asyncio.run(process_async())
291
351
 
292
352
  thread = threading.Thread(target=run_async)
@@ -301,7 +361,7 @@ if __name__ == "__main__":
301
361
 
302
362
  thread.join()
303
363
  else:
304
- log.info("sync streaming response")
364
+ log.info("Starting sync streaming response")
305
365
  for chunk in start_streaming_chat(
306
366
  question=all_input["user_input"],
307
367
  vector_name=vector_name,
@@ -327,15 +387,15 @@ if __name__ == "__main__":
327
387
  except Exception as e:
328
388
  yield f"Streaming Error: {str(e)} {traceback.format_exc()}"
329
389
 
330
- # Here, the generator function will handle streaming the content to the client.
390
+ # Create streaming response
331
391
  response = Response(generate_response_content(), content_type='text/plain; charset=utf-8')
332
392
  response.headers['Transfer-Encoding'] = 'chunked'
333
393
 
334
- log.debug(f"streaming response: {response}")
394
+ log.debug(f"Streaming response created in {time.time() - request_start:.3f}s")
395
+
335
396
  if trace:
336
- span.end(output=response)
337
- trace.update(output=response)
338
- 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)
339
399
 
340
400
  return response
341
401
 
@@ -654,78 +714,136 @@ if __name__ == "__main__":
654
714
  tags = tags,
655
715
  release = package_version
656
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
657
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
+
658
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
659
765
 
660
- if request.content_type.startswith('application/json'):
661
- data = request.get_json()
662
- elif request.content_type.startswith('multipart/form-data'):
663
- data = request.form.to_dict()
664
- if 'file' in request.files:
665
- file = request.files['file']
666
- if file.filename != '':
667
- log.info(f"Found file: {file.filename} to upload to GCS")
668
- try:
669
- image_uri, mime_type = self.handle_file_upload(file, vector_name)
670
- data["image_uri"] = image_uri
671
- data["mime"] = mime_type
672
- except Exception as e:
673
- log.error(traceback.format_exc())
674
- return jsonify({'error': str(e), 'traceback': traceback.format_exc()}), 500
675
- else:
676
- log.error("No file selected")
677
- return jsonify({"error": "No file selected"}), 400
678
- else:
679
- return jsonify({"error": "Unsupported content type"}), 400
766
+ log.info(f"vac/{vector_name} got data keys: {list(data.keys())}")
680
767
 
681
- 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
682
783
 
683
- trace = None
684
- span = None
685
- if self.add_langfuse_eval:
686
- trace_id = data.get('trace_id')
687
- trace = self.create_langfuse_trace(request, vector_name, trace_id)
688
- log.info(f"Using existing langfuse trace: {trace_id}")
689
-
690
- #config, _ = load_config("config/llm_config.yaml")
784
+ # Get config from cache (should be very fast)
691
785
  try:
692
- vac_config = ConfigManager(vector_name)
786
+ vac_config = self._get_cached_config(vector_name)
693
787
  except Exception as e:
694
- 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
695
790
 
696
- if trace:
697
- this_vac_config = vac_config.configs_by_kind.get("vacConfig")
698
- metadata_config=None
699
- if this_vac_config:
700
- 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)
793
+
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
701
800
 
702
- trace.update(input=data, metadata=metadata_config)
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)
703
811
 
704
- user_input = data.pop('user_input').strip()
705
- stream_wait_time = data.pop('stream_wait_time', 7)
706
- stream_timeout = data.pop('stream_timeout', 120)
707
- chat_history = data.pop('chat_history', None)
708
- eval_percent = data.pop('eval_percent', 0.01)
709
- vector_name = data.pop('vector_name', vector_name)
710
- data.pop('trace_id', None) # to ensure not in kwargs
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
+ }
711
822
 
712
- paired_messages = extract_chat_history_with_cache(chat_history)
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
713
843
 
714
- all_input = {'user_input': user_input,
715
- 'vector_name': vector_name,
716
- 'chat_history': paired_messages,
717
- 'stream_wait_time': stream_wait_time,
718
- 'stream_timeout': stream_timeout,
719
- 'eval_percent': eval_percent,
720
- 'kwargs': data}
844
+ prep_time = time.time() - start_time
845
+ log.info(f"prep_vac completed in {prep_time:.3f}s")
721
846
 
722
- if trace:
723
- span = trace.span(
724
- name="VAC",
725
- metadata=vac_config.configs_by_kind,
726
- input = all_input
727
- )
728
-
729
847
  return {
730
848
  "trace": trace,
731
849
  "span": span,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sunholo
3
- Version: 0.140.6
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
File without changes