sunholo 0.139.1__tar.gz → 0.140.4__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.
- {sunholo-0.139.1/src/sunholo.egg-info → sunholo-0.140.4}/PKG-INFO +1 -1
- {sunholo-0.139.1 → sunholo-0.140.4}/pyproject.toml +1 -1
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/agents/__init__.py +1 -1
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/agents/chat_history.py +63 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/agents/flask/__init__.py +0 -1
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/agents/flask/vac_routes.py +118 -7
- {sunholo-0.139.1 → sunholo-0.140.4/src/sunholo.egg-info}/PKG-INFO +1 -1
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo.egg-info/SOURCES.txt +0 -1
- sunholo-0.139.1/src/sunholo/agents/flask/qna_routes.py +0 -604
- {sunholo-0.139.1 → sunholo-0.140.4}/LICENSE.txt +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/MANIFEST.in +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/README.md +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/setup.cfg +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/__init__.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/agents/dispatch_to_qa.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/agents/fastapi/__init__.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/agents/fastapi/base.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/agents/fastapi/qna_routes.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/agents/flask/base.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/agents/langserve.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/agents/pubsub.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/agents/route.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/agents/special_commands.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/agents/swagger.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/archive/__init__.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/archive/archive.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/auth/__init__.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/auth/gcloud.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/auth/refresh.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/auth/run.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/azure/__init__.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/azure/auth.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/azure/blobs.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/azure/event_grid.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/bots/__init__.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/bots/discord.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/bots/github_webhook.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/bots/webapp.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/chunker/__init__.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/chunker/azure.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/chunker/doc_handling.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/chunker/encode_metadata.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/chunker/images.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/chunker/loaders.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/chunker/message_data.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/chunker/pdfs.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/chunker/process_chunker_data.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/chunker/publish.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/chunker/pubsub.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/chunker/splitter.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/cli/__init__.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/cli/chat_vac.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/cli/cli.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/cli/cli_init.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/cli/configs.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/cli/deploy.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/cli/embedder.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/cli/merge_texts.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/cli/run_proxy.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/cli/sun_rich.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/cli/swagger.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/cli/vertex.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/components/__init__.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/components/llm.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/components/retriever.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/components/vectorstore.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/custom_logging.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/database/__init__.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/database/alloydb.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/database/alloydb_client.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/database/database.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/database/lancedb.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/database/sql/sb/create_function.sql +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/database/sql/sb/create_function_time.sql +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/database/sql/sb/create_table.sql +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/database/sql/sb/delete_source_row.sql +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/database/sql/sb/return_sources.sql +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/database/sql/sb/setup.sql +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/database/static_dbs.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/database/uuid.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/discovery_engine/__init__.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/discovery_engine/chunker_handler.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/discovery_engine/cli.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/discovery_engine/create_new.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/discovery_engine/discovery_engine_client.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/discovery_engine/get_ai_search_chunks.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/embedder/__init__.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/embedder/embed_chunk.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/embedder/embed_metadata.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/excel/__init__.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/excel/plugin.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/gcs/__init__.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/gcs/add_file.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/gcs/download_folder.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/gcs/download_gcs_text.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/gcs/download_url.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/gcs/extract_and_sign.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/gcs/metadata.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/genai/__init__.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/genai/file_handling.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/genai/genaiv2.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/genai/images.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/genai/init.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/genai/process_funcs_cls.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/genai/safety.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/invoke/__init__.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/invoke/async_class.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/invoke/direct_vac_func.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/invoke/invoke_vac_utils.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/langchain_types.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/langfuse/__init__.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/langfuse/callback.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/langfuse/evals.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/langfuse/prompts.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/llamaindex/__init__.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/llamaindex/get_files.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/llamaindex/import_files.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/llamaindex/llamaindex_class.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/llamaindex/user_history.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/lookup/__init__.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/lookup/model_lookup.yaml +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/mcp/__init__.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/mcp/cli.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/ollama/__init__.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/ollama/ollama_images.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/pubsub/__init__.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/pubsub/process_pubsub.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/pubsub/pubsub_manager.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/qna/__init__.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/qna/parsers.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/qna/retry.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/senses/__init__.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/senses/stream_voice.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/streaming/__init__.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/streaming/content_buffer.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/streaming/langserve.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/streaming/stream_lookup.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/streaming/streaming.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/summarise/__init__.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/summarise/summarise.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/templates/agent/__init__.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/templates/agent/agent_service.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/templates/agent/app.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/templates/agent/my_log.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/templates/agent/tools/__init__.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/templates/agent/tools/your_agent.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/templates/agent/vac_service.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/templates/project/__init__.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/templates/project/app.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/templates/project/my_log.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/templates/project/vac_service.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/templates/system_services/__init__.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/templates/system_services/app.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/templates/system_services/my_log.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/terraform/__init__.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/terraform/tfvars_editor.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/tools/__init__.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/tools/web_browser.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/utils/__init__.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/utils/api_key.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/utils/big_context.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/utils/config.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/utils/config_class.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/utils/config_schema.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/utils/gcp.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/utils/gcp_project.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/utils/mime.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/utils/parsers.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/utils/timedelta.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/utils/user_ids.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/utils/version.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/vertex/__init__.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/vertex/extensions_call.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/vertex/extensions_class.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/vertex/genai_functions.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/vertex/init.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/vertex/memory_tools.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/vertex/safety.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo/vertex/type_dict_to_json.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo.egg-info/dependency_links.txt +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo.egg-info/entry_points.txt +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo.egg-info/requires.txt +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/src/sunholo.egg-info/top_level.txt +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/tests/test_async.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/tests/test_async_genai2.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/tests/test_chat_history.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/tests/test_config.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/tests/test_genai2.py +0 -0
- {sunholo-0.139.1 → sunholo-0.140.4}/tests/test_unstructured.py +0 -0
@@ -2,6 +2,6 @@ from .chat_history import extract_chat_history
|
|
2
2
|
from .dispatch_to_qa import send_to_qa, send_to_qa_async
|
3
3
|
from .pubsub import process_pubsub
|
4
4
|
from .special_commands import handle_special_commands, app_to_store, handle_files
|
5
|
-
from .flask import
|
5
|
+
from .flask import create_app, VACRoutes
|
6
6
|
from .fastapi import register_qna_fastapi_routes, create_fastapi_app
|
7
7
|
from .swagger import config_to_swagger
|
@@ -1,6 +1,69 @@
|
|
1
1
|
import json
|
2
2
|
from ..custom_logging import log
|
3
3
|
|
4
|
+
|
5
|
+
async def extract_chat_history_async(chat_history=None):
|
6
|
+
"""
|
7
|
+
Extracts paired chat history between human and AI messages.
|
8
|
+
|
9
|
+
For this lightweight processing, we use a simpler approach that minimizes overhead.
|
10
|
+
|
11
|
+
Args:
|
12
|
+
chat_history (list): List of chat messages.
|
13
|
+
|
14
|
+
Returns:
|
15
|
+
list: List of tuples with paired human and AI messages.
|
16
|
+
"""
|
17
|
+
if not chat_history:
|
18
|
+
log.info("No chat history found")
|
19
|
+
return []
|
20
|
+
|
21
|
+
log.info(f"Extracting chat history: {chat_history}")
|
22
|
+
paired_messages = []
|
23
|
+
|
24
|
+
# Handle special case of initial bot message
|
25
|
+
if chat_history and is_bot(chat_history[0]):
|
26
|
+
first_message = chat_history[0]
|
27
|
+
log.info(f"Extracting first_message: {first_message}")
|
28
|
+
blank_human_message = {"name": "Human", "content": "", "embeds": []}
|
29
|
+
|
30
|
+
# Since create_message_element is so lightweight, we don't need async here
|
31
|
+
blank_element = create_message_element(blank_human_message)
|
32
|
+
bot_element = create_message_element(first_message)
|
33
|
+
|
34
|
+
paired_messages.append((blank_element, bot_element))
|
35
|
+
chat_history = chat_history[1:]
|
36
|
+
|
37
|
+
# Pre-process all messages in one batch (more efficient than one-by-one)
|
38
|
+
message_types = []
|
39
|
+
message_contents = []
|
40
|
+
|
41
|
+
for message in chat_history:
|
42
|
+
is_human_msg = is_human(message)
|
43
|
+
is_bot_msg = is_bot(message)
|
44
|
+
|
45
|
+
# Extract content for all messages at once
|
46
|
+
content = create_message_element(message)
|
47
|
+
|
48
|
+
message_types.append((is_human_msg, is_bot_msg))
|
49
|
+
message_contents.append(content)
|
50
|
+
|
51
|
+
# Pair messages efficiently
|
52
|
+
last_human_message = ""
|
53
|
+
for i, ((is_human_msg, is_bot_msg), content) in enumerate(zip(message_types, message_contents)):
|
54
|
+
if is_human_msg:
|
55
|
+
last_human_message = content
|
56
|
+
log.info(f"Extracted human message: {last_human_message}")
|
57
|
+
elif is_bot_msg:
|
58
|
+
ai_message = content
|
59
|
+
log.info(f"Extracted AI message: {ai_message}")
|
60
|
+
paired_messages.append((last_human_message, ai_message))
|
61
|
+
last_human_message = ""
|
62
|
+
|
63
|
+
log.info(f"Paired messages: {paired_messages}")
|
64
|
+
return paired_messages
|
65
|
+
|
66
|
+
|
4
67
|
def extract_chat_history(chat_history=None):
|
5
68
|
"""
|
6
69
|
Extracts paired chat history between human and AI messages.
|
@@ -8,6 +8,7 @@ import inspect
|
|
8
8
|
import asyncio
|
9
9
|
|
10
10
|
from ...agents import extract_chat_history, handle_special_commands
|
11
|
+
from ..chat_history import extract_chat_history_async
|
11
12
|
from ...qna.parsers import parse_output
|
12
13
|
from ...streaming import start_streaming_chat, start_streaming_chat_async
|
13
14
|
from ...archive import archive_qa
|
@@ -57,11 +58,12 @@ if __name__ == "__main__":
|
|
57
58
|
```
|
58
59
|
|
59
60
|
"""
|
60
|
-
def __init__(self, app, stream_interpreter, vac_interpreter=None, additional_routes=None):
|
61
|
+
def __init__(self, app, stream_interpreter: callable, vac_interpreter:callable=None, additional_routes:dict=None, async_stream:bool=False):
|
61
62
|
self.app = app
|
62
63
|
self.stream_interpreter = stream_interpreter
|
63
64
|
self.vac_interpreter = vac_interpreter or partial(self.vac_interpreter_default)
|
64
65
|
self.additional_routes = additional_routes if additional_routes is not None else []
|
66
|
+
self.async_stream = async_stream
|
65
67
|
self.register_routes()
|
66
68
|
|
67
69
|
|
@@ -94,12 +96,16 @@ if __name__ == "__main__":
|
|
94
96
|
# Basic routes
|
95
97
|
self.app.route("/", methods=['GET'])(self.home)
|
96
98
|
self.app.route("/health", methods=['GET'])(self.health)
|
97
|
-
|
98
|
-
#
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
99
|
+
|
100
|
+
if self.async_stream: # Use async treatment
|
101
|
+
log.info("async_stream enabled")
|
102
|
+
self.app.route('/vac/streaming/<vector_name>',
|
103
|
+
methods=['POST'],
|
104
|
+
provide_automatic_options=False)(self.handle_stream_vac_async)
|
105
|
+
else:
|
106
|
+
self.app.route('/vac/streaming/<vector_name>',
|
107
|
+
methods=['POST'],
|
108
|
+
provide_automatic_options=False)(self.handle_stream_vac)
|
103
109
|
# Static VAC
|
104
110
|
self.app.route('/vac/<vector_name>',
|
105
111
|
methods=['POST'],
|
@@ -332,6 +338,51 @@ if __name__ == "__main__":
|
|
332
338
|
|
333
339
|
return response
|
334
340
|
|
341
|
+
async def handle_stream_vac_async(self, vector_name):
|
342
|
+
observed_stream_interpreter = self.stream_interpreter
|
343
|
+
is_async = inspect.iscoroutinefunction(self.stream_interpreter)
|
344
|
+
|
345
|
+
if not is_async:
|
346
|
+
raise ValueError(f"Stream interpreter must be async: {observed_stream_interpreter}")
|
347
|
+
|
348
|
+
# Use the async version of prep_vac
|
349
|
+
prep = await self.prep_vac_async(request, vector_name)
|
350
|
+
log.info(f"Processing async prep: {prep}")
|
351
|
+
all_input = prep["all_input"]
|
352
|
+
|
353
|
+
log.info(f'Streaming async data with: {all_input}')
|
354
|
+
|
355
|
+
async def generate_response_content():
|
356
|
+
try:
|
357
|
+
# Direct async handling without the queue/thread approach
|
358
|
+
async_gen = start_streaming_chat_async(
|
359
|
+
question=all_input["user_input"],
|
360
|
+
vector_name=vector_name,
|
361
|
+
qna_func_async=observed_stream_interpreter,
|
362
|
+
chat_history=all_input["chat_history"],
|
363
|
+
wait_time=all_input["stream_wait_time"],
|
364
|
+
timeout=all_input["stream_timeout"],
|
365
|
+
**all_input["kwargs"]
|
366
|
+
)
|
367
|
+
|
368
|
+
log.info(f"{async_gen=}")
|
369
|
+
async for chunk in async_gen:
|
370
|
+
if isinstance(chunk, dict) and 'answer' in chunk:
|
371
|
+
await archive_qa(chunk, vector_name)
|
372
|
+
yield json.dumps(chunk)
|
373
|
+
else:
|
374
|
+
yield chunk
|
375
|
+
|
376
|
+
except Exception as e:
|
377
|
+
yield f"Streaming async Error: {str(e)} {traceback.format_exc()}"
|
378
|
+
|
379
|
+
response = Response(generate_response_content(), content_type='text/plain; charset=utf-8')
|
380
|
+
response.headers['Transfer-Encoding'] = 'chunked'
|
381
|
+
|
382
|
+
log.debug(f"streaming async response: {response}")
|
383
|
+
|
384
|
+
return response
|
385
|
+
|
335
386
|
@staticmethod
|
336
387
|
async def _async_generator_to_stream(async_gen_func):
|
337
388
|
"""Helper function to stream the async generator's values to the client."""
|
@@ -699,6 +750,66 @@ if __name__ == "__main__":
|
|
699
750
|
"vac_config": vac_config
|
700
751
|
}
|
701
752
|
|
753
|
+
async def prep_vac_async(self, request, vector_name):
|
754
|
+
"""Async version of prep_vac."""
|
755
|
+
# Parse request data
|
756
|
+
if request.content_type.startswith('application/json'):
|
757
|
+
data = request.get_json()
|
758
|
+
elif request.content_type.startswith('multipart/form-data'):
|
759
|
+
data = request.form.to_dict()
|
760
|
+
if 'file' in request.files:
|
761
|
+
file = request.files['file']
|
762
|
+
if file.filename != '':
|
763
|
+
log.info(f"Found file: {file.filename} to upload to GCS")
|
764
|
+
try:
|
765
|
+
# Make file upload async if possible
|
766
|
+
image_uri, mime_type = await self.handle_file_upload_async(file, vector_name)
|
767
|
+
data["image_uri"] = image_uri
|
768
|
+
data["mime"] = mime_type
|
769
|
+
except Exception as e:
|
770
|
+
log.error(traceback.format_exc())
|
771
|
+
return jsonify({'error': str(e), 'traceback': traceback.format_exc()}), 500
|
772
|
+
else:
|
773
|
+
log.error("No file selected")
|
774
|
+
return jsonify({"error": "No file selected"}), 400
|
775
|
+
else:
|
776
|
+
return jsonify({"error": "Unsupported content type"}), 400
|
777
|
+
|
778
|
+
log.info(f"vac/{vector_name} got data: {data}")
|
779
|
+
|
780
|
+
# Run these operations concurrently
|
781
|
+
tasks = []
|
782
|
+
|
783
|
+
# Extract other data while configs load
|
784
|
+
user_input = data.pop('user_input').strip()
|
785
|
+
stream_wait_time = data.pop('stream_wait_time', 7)
|
786
|
+
stream_timeout = data.pop('stream_timeout', 120)
|
787
|
+
chat_history = data.pop('chat_history', None)
|
788
|
+
vector_name_param = data.pop('vector_name', vector_name)
|
789
|
+
data.pop('trace_id', None) # to ensure not in kwargs
|
790
|
+
|
791
|
+
# Task 3: Process chat history
|
792
|
+
chat_history_task = asyncio.create_task(extract_chat_history_async(chat_history))
|
793
|
+
tasks.append(chat_history_task)
|
794
|
+
|
795
|
+
# Await all tasks concurrently
|
796
|
+
results = await asyncio.gather(*tasks, return_exceptions=True)
|
797
|
+
|
798
|
+
paired_messages = results[0] if not isinstance(results[0], Exception) else []
|
799
|
+
|
800
|
+
# Only create span after we have trace
|
801
|
+
all_input = {
|
802
|
+
'user_input': user_input,
|
803
|
+
'vector_name': vector_name_param,
|
804
|
+
'chat_history': paired_messages,
|
805
|
+
'stream_wait_time': stream_wait_time,
|
806
|
+
'stream_timeout': stream_timeout,
|
807
|
+
'kwargs': data
|
808
|
+
}
|
809
|
+
|
810
|
+
return {
|
811
|
+
"all_input": all_input
|
812
|
+
}
|
702
813
|
|
703
814
|
def handle_file_upload(self, file, vector_name):
|
704
815
|
try:
|
@@ -24,7 +24,6 @@ src/sunholo/agents/fastapi/base.py
|
|
24
24
|
src/sunholo/agents/fastapi/qna_routes.py
|
25
25
|
src/sunholo/agents/flask/__init__.py
|
26
26
|
src/sunholo/agents/flask/base.py
|
27
|
-
src/sunholo/agents/flask/qna_routes.py
|
28
27
|
src/sunholo/agents/flask/vac_routes.py
|
29
28
|
src/sunholo/archive/__init__.py
|
30
29
|
src/sunholo/archive/archive.py
|