This commit is contained in:
2026-02-19 21:36:58 +00:00
parent 6f629c53a6
commit 03292a635c
37 changed files with 625 additions and 2200 deletions

View File

@@ -1,14 +1,7 @@
"""
Copyright 2025 Google. This software is provided as-is, without warranty or
representation for any use or purpose. Your use of it is subject to your
agreement with Google.
Conversation manager service - central orchestrator for conversations.
"""
import logging
import uuid
from datetime import datetime, timedelta
from typing import Any
from ..config import Settings
from ..models import (
@@ -21,14 +14,10 @@ from ..models import (
TextInputDTO,
QueryParamsDTO,
)
from ..utils import SessionIdGenerator
from .dialogflow_client import DialogflowClientService
from .redis_service import RedisService
from .firestore_service import FirestoreService
from .dlp_service import DLPService
from .message_filter import MessageEntryFilter
from .notification_context_resolver import NotificationContextResolver
from .llm_response_tuner import LlmResponseTunerService
from .rag_service import RAGService
from .mappers import NotificationContextMapper, ConversationContextMapper
from .quick_reply_content import QuickReplyContentService
@@ -62,23 +51,17 @@ class ConversationManagerService:
def __init__(
self,
settings: Settings,
dialogflow_client: DialogflowClientService,
rag_service: RAGService,
redis_service: RedisService,
firestore_service: FirestoreService,
dlp_service: DLPService,
message_filter: MessageEntryFilter,
notification_context_resolver: NotificationContextResolver,
llm_response_tuner: LlmResponseTunerService,
):
"""Initialize conversation manager."""
self.settings = settings
self.dialogflow_client = dialogflow_client
self.rag_service = rag_service
self.redis_service = redis_service
self.firestore_service = firestore_service
self.dlp_service = dlp_service
self.message_filter = message_filter
self.notification_context_resolver = notification_context_resolver
self.llm_response_tuner = llm_response_tuner
# Initialize mappers
self.notification_mapper = NotificationContextMapper()
@@ -117,18 +100,10 @@ class ConversationManagerService:
request.mensaje,
self.settings.dlp_template_complete_flow,
)
obfuscated_request = ExternalConvRequestDTO(
mensaje=obfuscated_message,
usuario=request.usuario,
canal=request.canal,
tipo=request.tipo,
pantalla_contexto=request.pantalla_contexto,
)
request.mensaje = obfuscated_message
# Step 2: Check for pantallaContexto in existing session
telefono = request.usuario.telefono
existing_session = await self.redis_service.get_session(telefono)
existing_session = await self.redis_service.get_session(request.usuario.telefono)
if existing_session and existing_session.pantallaContexto:
# Check if pantallaContexto is stale (10 minutes)
@@ -137,16 +112,14 @@ class ConversationManagerService:
f"Detected 'pantallaContexto' in session: {existing_session.pantallaContexto}. "
f"Delegating to QuickReplies flow."
)
return await self._manage_quick_reply_conversation(
obfuscated_request, existing_session
)
return await self._manage_quick_reply_conversation(request, existing_session)
else:
logger.info(
"Detected STALE 'pantallaContexto'. Ignoring and proceeding with normal flow."
)
# Step 3: Continue with standard conversation flow
return await self._continue_managing_conversation(obfuscated_request)
return await self._continue_managing_conversation(request)
except Exception as e:
logger.error(f"Error managing conversation: {str(e)}", exc_info=True)
@@ -183,7 +156,10 @@ class ConversationManagerService:
)
# Add pantallaContexto to parameters
if dialogflow_request.query_params:
if (
dialogflow_request.query_params
and dialogflow_request.query_params.parameters
):
dialogflow_request.query_params.parameters["pantalla_contexto"] = (
session.pantallaContexto
)
@@ -395,9 +371,13 @@ class ConversationManagerService:
dialogflow_request = self._build_dialogflow_request(
request, new_session, request.mensaje
)
dialogflow_request.query_params.parameters[self.CONV_HISTORY_PARAM] = (
conversation_history
)
if (
dialogflow_request.query_params
and dialogflow_request.query_params.parameters
):
dialogflow_request.query_params.parameters[self.CONV_HISTORY_PARAM] = (
conversation_history
)
return await self._process_dialogflow_request(
new_session,
@@ -409,7 +389,7 @@ class ConversationManagerService:
async def _start_notification_conversation(
self,
request: ExternalConvRequestDTO,
notification: any,
notification: Any,
session: ConversationSessionDTO,
conversation_entries: list[ConversationEntryDTO],
) -> DetectIntentResponseDTO:
@@ -490,13 +470,23 @@ class ConversationManagerService:
conversation_history = self.conversation_mapper.to_text_with_limits(
session, firestore_entries
)
dialogflow_request.query_params.parameters[self.CONV_HISTORY_PARAM] = (
conversation_history
)
if (
dialogflow_request.query_params
and dialogflow_request.query_params.parameters
):
dialogflow_request.query_params.parameters[
self.CONV_HISTORY_PARAM
] = conversation_history
# Always add notification parameters
if notification.parametros:
dialogflow_request.query_params.parameters.update(notification.parametros)
if (
notification.parametros
and dialogflow_request.query_params
and dialogflow_request.query_params.parameters
):
dialogflow_request.query_params.parameters.update(
notification.parametros
)
response = await self.dialogflow_client.detect_intent(
session.sessionId, dialogflow_request
@@ -579,9 +569,13 @@ class ConversationManagerService:
dialogflow_request = self._build_dialogflow_request(
request, new_session, request.mensaje
)
dialogflow_request.query_params.parameters[self.CONV_HISTORY_PARAM] = (
conversation_history
)
if (
dialogflow_request.query_params
and dialogflow_request.query_params.parameters
):
dialogflow_request.query_params.parameters[self.CONV_HISTORY_PARAM] = (
conversation_history
)
return await self._process_dialogflow_request(
new_session,
@@ -720,12 +714,10 @@ class ConversationManagerService:
# Create conversation entry
response_text = ""
intent = None
parameters = None
if response.queryResult:
response_text = response.queryResult.text or ""
intent = response.queryResult.intent
response_text = response.queryResult.responseText or ""
parameters = response.queryResult.parameters
user_entry = ConversationEntryDTO(
@@ -734,7 +726,6 @@ class ConversationManagerService:
timestamp=datetime.now(),
text=user_message,
parameters=None,
intent=None,
)
agent_entry = ConversationEntryDTO(
@@ -743,7 +734,6 @@ class ConversationManagerService:
timestamp=datetime.now(),
text=response_text,
parameters=parameters,
intent=intent,
)
# Save to Redis (fast, blocking)
@@ -757,8 +747,12 @@ class ConversationManagerService:
async def save_to_firestore():
try:
await self.firestore_service.save_session(updated_session)
await self.firestore_service.save_entry(session.sessionId, user_entry)
await self.firestore_service.save_entry(session.sessionId, agent_entry)
await self.firestore_service.save_entry(
session.sessionId, user_entry
)
await self.firestore_service.save_entry(
session.sessionId, agent_entry
)
logger.debug(
f"Asynchronously (Write-Back): Entry successfully saved to Firestore for session: {session.sessionId}"
)
@@ -800,8 +794,7 @@ class ConversationManagerService:
type="CONVERSACION",
timestamp=datetime.now(),
text=user_message,
parameters=notification.parametros,
intent=None,
parameters=None,
)
llm_entry = ConversationEntryDTO(
@@ -810,7 +803,6 @@ class ConversationManagerService:
timestamp=datetime.now(),
text=llm_response,
parameters=None,
intent=None,
)
# Save to Redis (fast, blocking)
@@ -824,8 +816,12 @@ class ConversationManagerService:
async def save_to_firestore():
try:
await self.firestore_service.save_session(updated_session)
await self.firestore_service.save_entry(session.sessionId, user_entry)
await self.firestore_service.save_entry(session.sessionId, llm_entry)
await self.firestore_service.save_entry(
session.sessionId, user_entry
)
await self.firestore_service.save_entry(
session.sessionId, llm_entry
)
logger.debug(
f"Asynchronously (Write-Back): LLM entry successfully saved to Firestore for session: {session.sessionId}"
)