From d354ee16c950e5a605276e8255b3a7fb12060c03 Mon Sep 17 00:00:00 2001 From: Husain Baghwala Date: Tue, 30 Dec 2025 13:35:26 +0530 Subject: [PATCH 1/4] feat: integrate Hippocampus API for saving chatbot conversations --- config.py | 5 +- .../commonServices/baseService/utils.py | 12 ++++ .../queueService/queueLogService.py | 12 ++++ src/services/utils/hippocampus_utils.py | 55 +++++++++++++++++++ 4 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 src/services/utils/hippocampus_utils.py diff --git a/config.py b/config.py index 5a6e692f..08985296 100644 --- a/config.py +++ b/config.py @@ -56,4 +56,7 @@ class Config: DOCSTAR_COLLECTION_ID = os.getenv('DOCSTAR_COLLECTION_ID') AI_ML_APIKEY = os.getenv('AI_ML_APIKEY') AI_MIDDLEWARE_PAUTH_KEY = os.getenv('AI_MIDDLEWARE_PAUTH_KEY') - OPENAI_API_KEY_GPT_5_NANO = os.getenv('OPENAI_API_KEY_GPT_5_NANO') \ No newline at end of file + OPENAI_API_KEY_GPT_5_NANO = os.getenv('OPENAI_API_KEY_GPT_5_NANO') + HIPPOCAMPUS_API_URL = os.getenv('HIPPOCAMPUS_API_URL') + HIPPOCAMPUS_API_KEY = os.getenv('HIPPOCAMPUS_API_KEY') + HIPPOCAMPUS_COLLECTION_ID = os.getenv('HIPPOCAMPUS_COLLECTION_ID') \ No newline at end of file diff --git a/src/services/commonServices/baseService/utils.py b/src/services/commonServices/baseService/utils.py index 8acb0bab..3e167795 100644 --- a/src/services/commonServices/baseService/utils.py +++ b/src/services/commonServices/baseService/utils.py @@ -405,6 +405,11 @@ async def make_request_data(request: Request): async def make_request_data_and_publish_sub_queue(parsed_data, result, params, thread_info=None): suggestion_content = {'data': {'content': {}}} suggestion_content['data']['content'] = result.get('historyParams', {}).get('message') + + # Extract user and assistant messages for Hippocampus + user_message = parsed_data.get('user', '') + assistant_message = result.get('historyParams', {}).get('message', '') + data = { "save_sub_thread_id_and_name" : { "org_id" : parsed_data.get('org_id'), @@ -456,6 +461,13 @@ async def make_request_data_and_publish_sub_queue(parsed_data, result, params, t "check_chatbot_suggestions" : { "bridgeType" : parsed_data.get('bridgeType'), }, + "save_to_hippocampus" : { + "bridgeType" : parsed_data.get('bridgeType'), + "user_message" : user_message, + "assistant_message" : assistant_message, + "bridge_id" : parsed_data.get('bridge_id'), + "bridge_name" : parsed_data.get('name', '') + }, "type" : parsed_data.get('type'), "save_files_to_redis" : { "thread_id" : parsed_data.get('thread_id'), diff --git a/src/services/commonServices/queueService/queueLogService.py b/src/services/commonServices/queueService/queueLogService.py index bdfba14d..c1b76f25 100644 --- a/src/services/commonServices/queueService/queueLogService.py +++ b/src/services/commonServices/queueService/queueLogService.py @@ -10,6 +10,7 @@ from src.services.commonServices.baseService.utils import total_token_calculation, save_files_to_redis from src.controllers.conversationController import save_sub_thread_id_and_name from src.services.commonServices.queueService.baseQueue import BaseQueue +from src.services.utils.hippocampus_utils import save_conversation_to_hippocampus class Queue2(BaseQueue): @@ -33,6 +34,17 @@ async def process_messages(self, messages): # If message type is 'image', only run save_sub_thread_id_and_name if messages.get('type') == 'image': return + + # Save conversation to Hippocampus for chatbot bridge types + hippocampus_data = messages.get('save_to_hippocampus', {}) + if hippocampus_data.get('bridgeType'): + await save_conversation_to_hippocampus( + user_message=hippocampus_data.get('user_message', ''), + assistant_message=hippocampus_data.get('assistant_message', ''), + bridge_id=hippocampus_data.get('bridge_id', ''), + bridge_name=hippocampus_data.get('bridge_name', '') + ) + # await create(**messages['metrics_service']) await validateResponse(**messages['validateResponse']) await total_token_calculation(**messages['total_token_calculation']) diff --git a/src/services/utils/hippocampus_utils.py b/src/services/utils/hippocampus_utils.py new file mode 100644 index 00000000..e83fb084 --- /dev/null +++ b/src/services/utils/hippocampus_utils.py @@ -0,0 +1,55 @@ +from config import Config +from src.services.utils.logger import logger +from src.services.utils.apiservice import fetch + + +async def save_conversation_to_hippocampus(user_message, assistant_message, bridge_id, bridge_name=''): + """ + Save conversation to Hippocampus API for chatbot bridge types. + + Args: + user_message: The user's message content + assistant_message: The assistant's response content + bridge_id: The bridge/agent ID (used as ownerId) + bridge_name: The bridge/agent name (used as title) + """ + try: + if not Config.HIPPOCAMPUS_API_KEY or not Config.HIPPOCAMPUS_COLLECTION_ID: + logger.warning("Hippocampus API key or collection ID not configured") + return + + # Combine user and assistant messages as content + content = f"User: {user_message}\nAssistant: {assistant_message}" + + # Use bridge_name if available, otherwise fallback to bridge_id + title = bridge_name if bridge_name else bridge_id + + payload = { + "collectionId": Config.HIPPOCAMPUS_COLLECTION_ID, + "title": title, + "ownerId": bridge_id, + "content": content, + "settings": { + "strategy": "custom", + "chunkingUrl": "https://flow.sokt.io/func/scriQywSNndU", + "chunkSize": 1000 + } + } + + headers = { + "x-api-key": Config.HIPPOCAMPUS_API_KEY, + "Content-Type": "application/json" + } + + response_data, response_headers = await fetch( + url=Config.HIPPOCAMPUS_API_URL, + method="POST", + headers=headers, + json_body=payload + ) + + logger.info(f"Successfully saved conversation to Hippocampus for bridge_id: {bridge_id}") + + except Exception as e: + logger.error(f"Error saving conversation to Hippocampus: {str(e)}") + From b79159350f457ab7f589925cc9edc19c94808310 Mon Sep 17 00:00:00 2001 From: Husain Baghwala Date: Wed, 31 Dec 2025 15:48:07 +0530 Subject: [PATCH 2/4] refactor: update conversation saving to Hippocampus API with JSON format and increase chunk size --- src/services/utils/hippocampus_utils.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/services/utils/hippocampus_utils.py b/src/services/utils/hippocampus_utils.py index e83fb084..ce0747af 100644 --- a/src/services/utils/hippocampus_utils.py +++ b/src/services/utils/hippocampus_utils.py @@ -1,3 +1,4 @@ +import json from config import Config from src.services.utils.logger import logger from src.services.utils.apiservice import fetch @@ -18,8 +19,12 @@ async def save_conversation_to_hippocampus(user_message, assistant_message, brid logger.warning("Hippocampus API key or collection ID not configured") return - # Combine user and assistant messages as content - content = f"User: {user_message}\nAssistant: {assistant_message}" + # Create content as stringified JSON with question and answer + content_obj = { + "question": user_message, + "answer": assistant_message + } + content = json.dumps(content_obj) # Use bridge_name if available, otherwise fallback to bridge_id title = bridge_name if bridge_name else bridge_id @@ -32,7 +37,7 @@ async def save_conversation_to_hippocampus(user_message, assistant_message, brid "settings": { "strategy": "custom", "chunkingUrl": "https://flow.sokt.io/func/scriQywSNndU", - "chunkSize": 1000 + "chunkSize": 4000 } } From e05011cf64c65acb6d05a75c40d29e2895c4004e Mon Sep 17 00:00:00 2001 From: Husain Baghwala Date: Wed, 31 Dec 2025 17:10:59 +0530 Subject: [PATCH 3/4] feat: Introduce `chatbot_auto_answers` configuration to conditionally save conversations to Hippocampus using `agent_id`. --- .../commonServices/baseService/utils.py | 3 ++- .../queueService/queueLogService.py | 4 ++-- src/services/utils/common_utils.py | 1 + src/services/utils/getConfiguration.py | 3 ++- src/services/utils/hippocampus_utils.py | 20 +++++++++++-------- 5 files changed, 19 insertions(+), 12 deletions(-) diff --git a/src/services/commonServices/baseService/utils.py b/src/services/commonServices/baseService/utils.py index 3e167795..199815d0 100644 --- a/src/services/commonServices/baseService/utils.py +++ b/src/services/commonServices/baseService/utils.py @@ -466,7 +466,8 @@ async def make_request_data_and_publish_sub_queue(parsed_data, result, params, t "user_message" : user_message, "assistant_message" : assistant_message, "bridge_id" : parsed_data.get('bridge_id'), - "bridge_name" : parsed_data.get('name', '') + "bridge_name" : parsed_data.get('name', ''), + "chatbot_auto_answers": parsed_data.get('chatbot_auto_answers') }, "type" : parsed_data.get('type'), "save_files_to_redis" : { diff --git a/src/services/commonServices/queueService/queueLogService.py b/src/services/commonServices/queueService/queueLogService.py index c1b76f25..b74ac9a7 100644 --- a/src/services/commonServices/queueService/queueLogService.py +++ b/src/services/commonServices/queueService/queueLogService.py @@ -37,11 +37,11 @@ async def process_messages(self, messages): # Save conversation to Hippocampus for chatbot bridge types hippocampus_data = messages.get('save_to_hippocampus', {}) - if hippocampus_data.get('bridgeType'): + if hippocampus_data.get('bridgeType') and hippocampus_data.get('chatbot_auto_answers'): await save_conversation_to_hippocampus( user_message=hippocampus_data.get('user_message', ''), assistant_message=hippocampus_data.get('assistant_message', ''), - bridge_id=hippocampus_data.get('bridge_id', ''), + agent_id=hippocampus_data.get('bridge_id', ''), bridge_name=hippocampus_data.get('bridge_name', '') ) diff --git a/src/services/utils/common_utils.py b/src/services/utils/common_utils.py index f7925d79..09942eee 100644 --- a/src/services/utils/common_utils.py +++ b/src/services/utils/common_utils.py @@ -192,6 +192,7 @@ def parse_request_body(request_body): "transfer_request_id": body.get('transfer_request_id'), "orchestrator_flag": body.get('orchestrator_flag'), "batch_variables": body.get('batch_variables'), + "chatbot_auto_answers": body.get('chatbot_auto_answers') } diff --git a/src/services/utils/getConfiguration.py b/src/services/utils/getConfiguration.py index b0fb754d..40f638e2 100644 --- a/src/services/utils/getConfiguration.py +++ b/src/services/utils/getConfiguration.py @@ -173,7 +173,8 @@ async def _prepare_configuration_response(configuration, service, bridge_id, api "is_embed": result.get('bridges', {}).get("folder_type") == 'embed', "user_id": result.get("bridges", {}).get("user_id"), 'folder_id': result.get('bridges', {}).get('folder_id'), - 'web_search_filters': web_search_filters_value + 'web_search_filters': web_search_filters_value, + 'chatbot_auto_answers': result.get('bridges', {}).get('chatbot_auto_answers') } return None, base_config, result, resolved_bridge_id diff --git a/src/services/utils/hippocampus_utils.py b/src/services/utils/hippocampus_utils.py index ce0747af..94f132c0 100644 --- a/src/services/utils/hippocampus_utils.py +++ b/src/services/utils/hippocampus_utils.py @@ -4,14 +4,14 @@ from src.services.utils.apiservice import fetch -async def save_conversation_to_hippocampus(user_message, assistant_message, bridge_id, bridge_name=''): +async def save_conversation_to_hippocampus(user_message, assistant_message, agent_id, bridge_name=''): """ Save conversation to Hippocampus API for chatbot bridge types. Args: user_message: The user's message content assistant_message: The assistant's response content - bridge_id: The bridge/agent ID (used as ownerId) + agent_id: The bridge/agent ID (used as ownerId) bridge_name: The bridge/agent name (used as title) """ try: @@ -24,16 +24,19 @@ async def save_conversation_to_hippocampus(user_message, assistant_message, brid "question": user_message, "answer": assistant_message } - content = json.dumps(content_obj) + # content = json.dumps(content_obj) - # Use bridge_name if available, otherwise fallback to bridge_id - title = bridge_name if bridge_name else bridge_id + # Use bridge_name if available, otherwise fallback to agent_id + title = bridge_name if bridge_name else agent_id payload = { "collectionId": Config.HIPPOCAMPUS_COLLECTION_ID, "title": title, - "ownerId": bridge_id, - "content": content, + "ownerId": agent_id, + "content": content_obj, + + + "settings": { "strategy": "custom", "chunkingUrl": "https://flow.sokt.io/func/scriQywSNndU", @@ -46,6 +49,7 @@ async def save_conversation_to_hippocampus(user_message, assistant_message, brid "Content-Type": "application/json" } + response_data, response_headers = await fetch( url=Config.HIPPOCAMPUS_API_URL, method="POST", @@ -53,7 +57,7 @@ async def save_conversation_to_hippocampus(user_message, assistant_message, brid json_body=payload ) - logger.info(f"Successfully saved conversation to Hippocampus for bridge_id: {bridge_id}") + logger.info(f"Successfully saved conversation to Hippocampus for agent_id: {agent_id}") except Exception as e: logger.error(f"Error saving conversation to Hippocampus: {str(e)}") From a0e4316d2f766f20847216f3700202de7233f739 Mon Sep 17 00:00:00 2001 From: Husain Baghwala Date: Wed, 31 Dec 2025 17:40:40 +0530 Subject: [PATCH 4/4] fix: Validate `HIPPOCAMPUS_API_URL` configuration and send stringified JSON content to Hippocampus. --- src/services/utils/hippocampus_utils.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/services/utils/hippocampus_utils.py b/src/services/utils/hippocampus_utils.py index 94f132c0..220db856 100644 --- a/src/services/utils/hippocampus_utils.py +++ b/src/services/utils/hippocampus_utils.py @@ -15,8 +15,8 @@ async def save_conversation_to_hippocampus(user_message, assistant_message, agen bridge_name: The bridge/agent name (used as title) """ try: - if not Config.HIPPOCAMPUS_API_KEY or not Config.HIPPOCAMPUS_COLLECTION_ID: - logger.warning("Hippocampus API key or collection ID not configured") + if not Config.HIPPOCAMPUS_API_KEY or not Config.HIPPOCAMPUS_COLLECTION_ID or not Config.HIPPOCAMPUS_API_URL: + logger.warning("Hippocampus API key, collection ID, or API URL not configured") return # Create content as stringified JSON with question and answer @@ -24,7 +24,7 @@ async def save_conversation_to_hippocampus(user_message, assistant_message, agen "question": user_message, "answer": assistant_message } - # content = json.dumps(content_obj) + content = json.dumps(content_obj) # Use bridge_name if available, otherwise fallback to agent_id title = bridge_name if bridge_name else agent_id @@ -33,7 +33,7 @@ async def save_conversation_to_hippocampus(user_message, assistant_message, agen "collectionId": Config.HIPPOCAMPUS_COLLECTION_ID, "title": title, "ownerId": agent_id, - "content": content_obj, + "content": content,