.
This commit is contained in:
@@ -1,21 +1,21 @@
|
||||
import logging
|
||||
from uuid import uuid4
|
||||
from datetime import datetime, timedelta
|
||||
from uuid import uuid4
|
||||
|
||||
from ..config import Settings
|
||||
from ..models import (
|
||||
from capa_de_integracion.config import Settings
|
||||
from capa_de_integracion.models import (
|
||||
ConversationEntry,
|
||||
ConversationRequest,
|
||||
ConversationSession,
|
||||
DetectIntentResponse,
|
||||
QueryResult,
|
||||
ConversationSession,
|
||||
ConversationEntry,
|
||||
)
|
||||
from .redis_service import RedisService
|
||||
from .firestore_service import FirestoreService
|
||||
from .dlp_service import DLPService
|
||||
from .rag_service import RAGService
|
||||
from .quick_reply_content import QuickReplyContentService
|
||||
|
||||
from .dlp_service import DLPService
|
||||
from .firestore_service import FirestoreService
|
||||
from .quick_reply_content import QuickReplyContentService
|
||||
from .rag_service import RAGService
|
||||
from .redis_service import RedisService
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -35,7 +35,7 @@ class ConversationManagerService:
|
||||
redis_service: RedisService,
|
||||
firestore_service: FirestoreService,
|
||||
dlp_service: DLPService,
|
||||
):
|
||||
) -> None:
|
||||
"""Initialize conversation manager."""
|
||||
self.settings = settings
|
||||
self.rag_service = rag_service
|
||||
@@ -47,16 +47,16 @@ class ConversationManagerService:
|
||||
logger.info("ConversationManagerService initialized successfully")
|
||||
|
||||
async def manage_conversation(
|
||||
self, request: ConversationRequest
|
||||
self, request: ConversationRequest,
|
||||
) -> DetectIntentResponse:
|
||||
"""
|
||||
Main entry point for managing conversations.
|
||||
"""Main entry point for managing conversations.
|
||||
|
||||
Args:
|
||||
request: External conversation request from client
|
||||
|
||||
Returns:
|
||||
Detect intent response from Dialogflow
|
||||
|
||||
"""
|
||||
try:
|
||||
# Step 1: DLP obfuscation
|
||||
@@ -75,7 +75,7 @@ class ConversationManagerService:
|
||||
session_id = str(uuid4())
|
||||
user_id = f"user_by_phone_{telefono.replace(' ', '').replace('-', '')}"
|
||||
session = await self.firestore_service.create_session(
|
||||
session_id, user_id, telefono
|
||||
session_id, user_id, telefono,
|
||||
)
|
||||
await self.redis_service.save_session(session)
|
||||
|
||||
@@ -85,10 +85,10 @@ class ConversationManagerService:
|
||||
if self._is_pantalla_context_valid(session.lastModified):
|
||||
logger.info(
|
||||
f"Detected 'pantallaContexto' in session: {session.pantallaContexto}. "
|
||||
f"Delegating to QuickReplies flow."
|
||||
f"Delegating to QuickReplies flow.",
|
||||
)
|
||||
response = await self._manage_quick_reply_conversation(
|
||||
request, session.pantallaContexto
|
||||
request, session.pantallaContexto,
|
||||
)
|
||||
if response:
|
||||
# Save user message to Firestore
|
||||
@@ -101,7 +101,7 @@ class ConversationManagerService:
|
||||
canal=getattr(request, "canal", None),
|
||||
)
|
||||
await self.firestore_service.save_entry(
|
||||
session.sessionId, user_entry
|
||||
session.sessionId, user_entry,
|
||||
)
|
||||
|
||||
# Save quick reply response to Firestore
|
||||
@@ -119,7 +119,7 @@ class ConversationManagerService:
|
||||
canal=getattr(request, "canal", None),
|
||||
)
|
||||
await self.firestore_service.save_entry(
|
||||
session.sessionId, assistant_entry
|
||||
session.sessionId, assistant_entry,
|
||||
)
|
||||
|
||||
# Update session with last message and timestamp
|
||||
@@ -131,14 +131,14 @@ class ConversationManagerService:
|
||||
return response
|
||||
else:
|
||||
logger.info(
|
||||
"Detected STALE 'pantallaContexto'. Ignoring and proceeding with normal flow."
|
||||
"Detected STALE 'pantallaContexto'. Ignoring and proceeding with normal flow.",
|
||||
)
|
||||
|
||||
# Step 3: Continue with standard conversation flow
|
||||
nickname = request.usuario.nickname
|
||||
|
||||
logger.info(
|
||||
f"Primary Check (Redis): Looking up session for phone: {telefono}"
|
||||
f"Primary Check (Redis): Looking up session for phone: {telefono}",
|
||||
)
|
||||
|
||||
# Step 3a: Load conversation history from Firestore
|
||||
@@ -165,7 +165,7 @@ class ConversationManagerService:
|
||||
logger.info("Sending query to RAG service")
|
||||
assistant_response = await self.rag_service.query(messages)
|
||||
logger.info(
|
||||
f"Received response from RAG service: {assistant_response[:100]}..."
|
||||
f"Received response from RAG service: {assistant_response[:100]}...",
|
||||
)
|
||||
|
||||
# Step 3e: Save user message to Firestore
|
||||
@@ -205,7 +205,7 @@ class ConversationManagerService:
|
||||
logger.info(f"Marked {len(notifications)} notifications as processed")
|
||||
|
||||
# Step 3i: Return response object
|
||||
response = DetectIntentResponse(
|
||||
return DetectIntentResponse(
|
||||
responseId=str(uuid4()),
|
||||
queryResult=QueryResult(
|
||||
responseText=assistant_response,
|
||||
@@ -214,10 +214,9 @@ class ConversationManagerService:
|
||||
quick_replies=None,
|
||||
)
|
||||
|
||||
return response
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error managing conversation: {str(e)}", exc_info=True)
|
||||
logger.error(f"Error managing conversation: {e!s}", exc_info=True)
|
||||
raise
|
||||
|
||||
def _is_pantalla_context_valid(self, last_modified: datetime) -> bool:
|
||||
@@ -252,17 +251,16 @@ class ConversationManagerService:
|
||||
# If no match, use first question as default or delegate to normal flow
|
||||
if not matched_answer:
|
||||
logger.warning(
|
||||
f"No matching quick reply found for message: '{request.mensaje}'."
|
||||
f"No matching quick reply found for message: '{request.mensaje}'.",
|
||||
)
|
||||
|
||||
# Create response with the matched quick reply answer
|
||||
response = DetectIntentResponse(
|
||||
return DetectIntentResponse(
|
||||
responseId=str(uuid4()),
|
||||
queryResult=QueryResult(responseText=matched_answer, parameters=None),
|
||||
quick_replies=quick_reply_screen,
|
||||
)
|
||||
|
||||
return response
|
||||
|
||||
async def _get_active_notifications(self, telefono: str) -> list:
|
||||
"""Retrieve active notifications for a user from Redis or Firestore.
|
||||
@@ -272,20 +270,21 @@ class ConversationManagerService:
|
||||
|
||||
Returns:
|
||||
List of active Notification objects
|
||||
|
||||
"""
|
||||
try:
|
||||
# Try Redis first
|
||||
notification_session = await self.redis_service.get_notification_session(
|
||||
telefono
|
||||
telefono,
|
||||
)
|
||||
|
||||
# If not in Redis, try Firestore
|
||||
if not notification_session:
|
||||
# Firestore uses phone as document ID for notifications
|
||||
from ..models.notification import NotificationSession
|
||||
from capa_de_integracion.models.notification import NotificationSession
|
||||
|
||||
doc_ref = self.firestore_service.db.collection(
|
||||
self.firestore_service.notifications_collection
|
||||
self.firestore_service.notifications_collection,
|
||||
).document(telefono)
|
||||
doc = await doc_ref.get()
|
||||
|
||||
@@ -295,18 +294,17 @@ class ConversationManagerService:
|
||||
|
||||
# Filter for active notifications only
|
||||
if notification_session and notification_session.notificaciones:
|
||||
active_notifications = [
|
||||
return [
|
||||
notif
|
||||
for notif in notification_session.notificaciones
|
||||
if notif.status == "active"
|
||||
]
|
||||
return active_notifications
|
||||
|
||||
return []
|
||||
|
||||
except Exception as e:
|
||||
logger.error(
|
||||
f"Error retrieving notifications for {telefono}: {str(e)}",
|
||||
f"Error retrieving notifications for {telefono}: {e!s}",
|
||||
exc_info=True,
|
||||
)
|
||||
return []
|
||||
@@ -330,6 +328,7 @@ class ConversationManagerService:
|
||||
|
||||
Returns:
|
||||
List of messages in OpenAI format [{"role": "...", "content": "..."}]
|
||||
|
||||
"""
|
||||
messages = []
|
||||
|
||||
@@ -341,7 +340,7 @@ class ConversationManagerService:
|
||||
{
|
||||
"role": "system",
|
||||
"content": f"Historial de conversación:\n{conversation_context}",
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
# Add system message with notifications if available
|
||||
@@ -355,7 +354,7 @@ class ConversationManagerService:
|
||||
{
|
||||
"role": "system",
|
||||
"content": f"Notificaciones pendientes para el usuario:\n{notifications_text}",
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
# Add system message with user context
|
||||
@@ -372,11 +371,12 @@ class ConversationManagerService:
|
||||
|
||||
Args:
|
||||
telefono: User phone number
|
||||
|
||||
"""
|
||||
try:
|
||||
# Update status in Firestore
|
||||
await self.firestore_service.update_notification_status(
|
||||
telefono, "processed"
|
||||
telefono, "processed",
|
||||
)
|
||||
|
||||
# Update or delete from Redis
|
||||
@@ -386,7 +386,7 @@ class ConversationManagerService:
|
||||
|
||||
except Exception as e:
|
||||
logger.error(
|
||||
f"Error marking notifications as processed for {telefono}: {str(e)}",
|
||||
f"Error marking notifications as processed for {telefono}: {e!s}",
|
||||
exc_info=True,
|
||||
)
|
||||
|
||||
@@ -408,13 +408,14 @@ class ConversationManagerService:
|
||||
|
||||
Returns:
|
||||
Formatted conversation text
|
||||
|
||||
"""
|
||||
if not entries:
|
||||
return ""
|
||||
|
||||
# Filter by date (30 days)
|
||||
cutoff_date = datetime.now() - timedelta(
|
||||
days=self.settings.conversation_context_days_limit
|
||||
days=self.settings.conversation_context_days_limit,
|
||||
)
|
||||
recent_entries = [
|
||||
e for e in entries if e.timestamp and e.timestamp >= cutoff_date
|
||||
@@ -439,6 +440,7 @@ class ConversationManagerService:
|
||||
|
||||
Returns:
|
||||
Formatted text, truncated if necessary
|
||||
|
||||
"""
|
||||
if not entries:
|
||||
return ""
|
||||
@@ -470,6 +472,7 @@ class ConversationManagerService:
|
||||
|
||||
Returns:
|
||||
Formatted string (e.g., "User: hello", "Assistant: hi there")
|
||||
|
||||
"""
|
||||
# Map entity to prefix (fixed bug from Java port!)
|
||||
prefix = "User: " if entry.entity == "user" else "Assistant: "
|
||||
|
||||
Reference in New Issue
Block a user