This commit is contained in:
2026-02-19 17:50:14 +00:00
committed by Anibal Angulo
parent b63a1ae4a7
commit 41ba38495b
171 changed files with 7281 additions and 1144 deletions

View File

@@ -0,0 +1,173 @@
"""
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-related data models.
"""
from datetime import datetime
from enum import Enum
from typing import Any
from pydantic import BaseModel, Field, field_validator
class MessageType(str, Enum):
"""Message type enumeration."""
USER = "USER"
AGENT = "AGENT"
class ConversationEntryType(str, Enum):
"""Conversation entry type enumeration."""
INICIO = "INICIO"
CONVERSACION = "CONVERSACION"
LLM = "LLM"
class UsuarioDTO(BaseModel):
"""User information."""
telefono: str = Field(..., min_length=1)
nickname: str | None = None
class TextInputDTO(BaseModel):
"""Text input for queries."""
text: str
class EventInputDTO(BaseModel):
"""Event input for queries."""
event: str
class QueryParamsDTO(BaseModel):
"""Query parameters for Dialogflow requests."""
parameters: dict[str, Any] | None = None
class QueryInputDTO(BaseModel):
"""Query input combining text or event."""
text: TextInputDTO | None = None
event: EventInputDTO | None = None
language_code: str = "es"
@field_validator("text", "event")
@classmethod
def check_at_least_one(cls, v, info):
"""Ensure either text or event is provided."""
if info.field_name == "event" and v is None:
# Check if text was provided
if not info.data.get("text"):
raise ValueError("Either text or event must be provided")
return v
class DetectIntentRequestDTO(BaseModel):
"""Dialogflow detect intent request."""
query_input: QueryInputDTO
query_params: QueryParamsDTO | None = None
class QueryResultDTO(BaseModel):
"""Query result from Dialogflow."""
responseText: str | None = Field(None, alias="responseText")
parameters: dict[str, Any] | None = Field(None, alias="parameters")
model_config = {"populate_by_name": True}
class DetectIntentResponseDTO(BaseModel):
"""Dialogflow detect intent response."""
responseId: str | None = Field(None, alias="responseId")
queryResult: QueryResultDTO | None = Field(None, alias="queryResult")
quick_replies: Any | None = None # QuickReplyDTO from quick_replies module
model_config = {"populate_by_name": True}
class ExternalConvRequestDTO(BaseModel):
"""External conversation request from client."""
mensaje: str = Field(..., alias="mensaje")
usuario: UsuarioDTO = Field(..., alias="usuario")
canal: str = Field(..., alias="canal")
tipo: ConversationEntryType = Field(..., alias="tipo")
pantalla_contexto: str | None = Field(None, alias="pantallaContexto")
model_config = {"populate_by_name": True}
class ConversationMessageDTO(BaseModel):
"""Single conversation message."""
type: str = Field(..., alias="type") # Maps to MessageType
timestamp: datetime = Field(default_factory=datetime.now, alias="timestamp")
text: str = Field(..., alias="text")
parameters: dict[str, Any] | None = Field(None, alias="parameters")
canal: str | None = Field(None, alias="canal")
model_config = {"populate_by_name": True}
class ConversationEntryDTO(BaseModel):
"""Single conversation entry."""
entity: str = Field(..., alias="entity") # "USUARIO", "AGENTE", "SISTEMA", "LLM"
type: str = Field(..., alias="type") # "INICIO", "CONVERSACION", "LLM"
timestamp: datetime = Field(default_factory=datetime.now, alias="timestamp")
text: str = Field(..., alias="text")
parameters: dict[str, Any] | None = Field(None, alias="parameters")
canal: str | None = Field(None, alias="canal")
model_config = {"populate_by_name": True}
class ConversationSessionDTO(BaseModel):
"""Conversation session metadata."""
sessionId: str = Field(..., alias="sessionId")
userId: str = Field(..., alias="userId")
telefono: str = Field(..., alias="telefono")
createdAt: datetime = Field(default_factory=datetime.now, alias="createdAt")
lastModified: datetime = Field(default_factory=datetime.now, alias="lastModified")
lastMessage: str | None = Field(None, alias="lastMessage")
pantallaContexto: str | None = Field(None, alias="pantallaContexto")
model_config = {"populate_by_name": True}
@classmethod
def create(
cls, session_id: str, user_id: str, telefono: str
) -> "ConversationSessionDTO":
"""Create a new conversation session."""
now = datetime.now()
return cls(
sessionId=session_id,
userId=user_id,
telefono=telefono,
createdAt=now,
lastModified=now,
)
def with_last_message(self, last_message: str) -> "ConversationSessionDTO":
"""Create copy with updated last message."""
return self.model_copy(
update={"lastMessage": last_message, "lastModified": datetime.now()}
)
def with_pantalla_contexto(
self, pantalla_contexto: str
) -> "ConversationSessionDTO":
"""Create copy with updated pantalla contexto."""
return self.model_copy(update={"pantallaContexto": pantalla_contexto})