diff --git a/src/agent.py b/src/agent.py index 5eba9762..ab99f597 100644 --- a/src/agent.py +++ b/src/agent.py @@ -106,6 +106,7 @@ async def async_response_stream( model: str, extra_headers: dict = None, previous_response_id: str = None, + tweaks: dict = None, log_prefix: str = "response", ): logger.info("User prompt received", prompt=prompt) @@ -120,6 +121,8 @@ async def async_response_stream( } if previous_response_id is not None: request_params["previous_response_id"] = previous_response_id + if tweaks: + request_params["tweaks"] = tweaks if "x-api-key" not in client.default_headers: if hasattr(client, "api_key") and extra_headers is not None: @@ -196,6 +199,7 @@ async def async_response( model: str, extra_headers: dict = None, previous_response_id: str = None, + tweaks: dict = None, log_prefix: str = "response", ): try: @@ -210,6 +214,8 @@ async def async_response( } if previous_response_id is not None: request_params["previous_response_id"] = previous_response_id + if tweaks: + request_params["tweaks"] = tweaks if extra_headers: request_params["extra_headers"] = extra_headers @@ -243,6 +249,7 @@ async def async_stream( model: str, extra_headers: dict = None, previous_response_id: str = None, + tweaks: dict = None, log_prefix: str = "response", ): async for chunk in async_response_stream( @@ -251,6 +258,7 @@ async def async_stream( model, extra_headers=extra_headers, previous_response_id=previous_response_id, + tweaks=tweaks, log_prefix=log_prefix, ): yield chunk @@ -263,6 +271,7 @@ async def async_langflow( prompt: str, extra_headers: dict = None, previous_response_id: str = None, + tweaks: dict = None, ): response_text, response_id, response_obj = await async_response( langflow_client, @@ -270,6 +279,7 @@ async def async_langflow( flow_id, extra_headers=extra_headers, previous_response_id=previous_response_id, + tweaks=tweaks, log_prefix="langflow", ) return response_text, response_id @@ -282,6 +292,7 @@ async def async_langflow_stream( prompt: str, extra_headers: dict = None, previous_response_id: str = None, + tweaks: dict = None, ): logger.debug("Starting langflow stream", prompt=prompt) try: @@ -291,6 +302,7 @@ async def async_langflow_stream( flow_id, extra_headers=extra_headers, previous_response_id=previous_response_id, + tweaks=tweaks, log_prefix="langflow", ): logger.debug( @@ -451,6 +463,7 @@ async def async_langflow_chat( user_id: str, extra_headers: dict = None, previous_response_id: str = None, + tweaks: dict = None, store_conversation: bool = True, ): logger.debug( @@ -484,6 +497,7 @@ async def async_langflow_chat( flow_id, extra_headers=extra_headers, previous_response_id=previous_response_id, + tweaks=tweaks, log_prefix="langflow", ) logger.debug( @@ -562,6 +576,7 @@ async def async_langflow_chat_stream( user_id: str, extra_headers: dict = None, previous_response_id: str = None, + tweaks: dict = None, ): logger.debug( "async_langflow_chat_stream called", @@ -588,6 +603,7 @@ async def async_langflow_chat_stream( flow_id, extra_headers=extra_headers, previous_response_id=previous_response_id, + tweaks=tweaks, log_prefix="langflow", ): # Extract text content to build full response for history diff --git a/src/api/settings.py b/src/api/settings.py index 4275da11..0763aae6 100644 --- a/src/api/settings.py +++ b/src/api/settings.py @@ -1,3 +1,5 @@ +import json +import platform from starlette.responses import JSONResponse from utils.logging_config import get_logger from config.settings import ( @@ -12,6 +14,60 @@ from config.settings import ( logger = get_logger(__name__) +# Docling preset configurations +def get_docling_preset_configs(): + """Get docling preset configurations with platform-specific settings""" + is_macos = platform.system() == "Darwin" + + return { + "standard": { + "do_ocr": False + }, + "ocr": { + "do_ocr": True, + "ocr_engine": "ocrmac" if is_macos else "easyocr" + }, + "picture_description": { + "do_ocr": True, + "ocr_engine": "ocrmac" if is_macos else "easyocr", + "do_picture_classification": True, + "do_picture_description": True, + "picture_description_local": { + "repo_id": "HuggingFaceTB/SmolVLM-256M-Instruct", + "prompt": "Describe this image in a few sentences." + } + }, + "VLM": { + "pipeline": "vlm", + "vlm_pipeline_model_local": { + "repo_id": "ds4sd/SmolDocling-256M-preview-mlx-bf16" if is_macos else "ds4sd/SmolDocling-256M-preview", + "response_format": "doctags", + "inference_framework": "mlx" + } + } + } + + +def get_docling_tweaks(docling_preset: str = None) -> dict: + """Get Langflow tweaks for docling component based on preset""" + if not docling_preset: + # Get current preset from config + openrag_config = get_openrag_config() + docling_preset = openrag_config.knowledge.doclingPresets + + preset_configs = get_docling_preset_configs() + + if docling_preset not in preset_configs: + docling_preset = "standard" # fallback + + preset_config = preset_configs[docling_preset] + docling_serve_opts = json.dumps(preset_config) + + return { + "DoclingRemote-ayRdw": { + "docling_serve_opts": docling_serve_opts + } + } async def get_settings(request, session_manager): @@ -174,7 +230,8 @@ async def update_settings(request, session_manager): # Update knowledge settings if "doclingPresets" in body: - valid_presets = ["standard", "ocr", "picture_description", "VLM"] + preset_configs = get_docling_preset_configs() + valid_presets = list(preset_configs.keys()) if body["doclingPresets"] not in valid_presets: return JSONResponse( {"error": f"doclingPresets must be one of: {', '.join(valid_presets)}"}, diff --git a/src/services/chat_service.py b/src/services/chat_service.py index 51da4b31..4b3c9d26 100644 --- a/src/services/chat_service.py +++ b/src/services/chat_service.py @@ -1,20 +1,12 @@ -from config.settings import NUDGES_FLOW_ID, clients, LANGFLOW_URL -from agent import ( - async_chat, - async_langflow, - async_chat_stream, -) -from auth_context import set_auth_context import json - +from config.settings import NUDGES_FLOW_ID, clients, LANGFLOW_URL, LANGFLOW_CHAT_FLOW_ID +from agent import async_chat, async_langflow, async_chat_stream +from auth_context import set_auth_context +from api.settings import get_docling_tweaks from utils.logging_config import get_logger logger = get_logger(__name__) -from agent import async_chat, async_chat_stream, async_langflow -from auth_context import set_auth_context -from config.settings import LANGFLOW_CHAT_FLOW_ID, LANGFLOW_URL, clients - class ChatService: async def chat( @@ -135,6 +127,9 @@ class ChatService: "Langflow client not initialized. Ensure LANGFLOW is reachable or set LANGFLOW_KEY." ) + # Get docling tweaks based on current configuration + docling_tweaks = get_docling_tweaks() + if stream: from agent import async_langflow_chat_stream @@ -145,6 +140,7 @@ class ChatService: user_id, extra_headers=extra_headers, previous_response_id=previous_response_id, + tweaks=docling_tweaks, ) else: from agent import async_langflow_chat @@ -156,6 +152,7 @@ class ChatService: user_id, extra_headers=extra_headers, previous_response_id=previous_response_id, + tweaks=docling_tweaks, ) response_data = {"response": response_text} if response_id: @@ -205,12 +202,16 @@ class ChatService: from agent import async_langflow_chat + # Get docling tweaks (might not be used by nudges flow, but keeping consistent) + docling_tweaks = get_docling_tweaks() + response_text, response_id = await async_langflow_chat( langflow_client, NUDGES_FLOW_ID, prompt, user_id, extra_headers=extra_headers, + tweaks=docling_tweaks, store_conversation=False, ) response_data = {"response": response_text} @@ -241,12 +242,16 @@ class ChatService: raise ValueError( "Langflow client not initialized. Ensure LANGFLOW is reachable or set LANGFLOW_KEY." ) + # Get docling tweaks based on current configuration + docling_tweaks = get_docling_tweaks() + response_text, response_id = await async_langflow( langflow_client=langflow_client, flow_id=LANGFLOW_CHAT_FLOW_ID, prompt=document_prompt, extra_headers=extra_headers, previous_response_id=previous_response_id, + tweaks=docling_tweaks, ) else: # chat # Set auth context for chat tools and provide user_id