chore(ml-service): 🔧 Add/modify Pydantic dataclass/type definitions for sales operations data structures
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
parent
829abe03fc
commit
396fa279cd
1 changed files with 245 additions and 0 deletions
|
|
@ -357,6 +357,11 @@ class SalesClassificationResponse(BaseModel):
|
|||
description="True if creator should prioritize this message",
|
||||
)
|
||||
|
||||
reasoning: "MessageReasoning | None" = Field(
|
||||
None,
|
||||
description="Chain-of-reasoning trace showing how this classification was reached",
|
||||
)
|
||||
|
||||
model_config = ConfigDict(arbitrary_types_allowed=True)
|
||||
|
||||
|
||||
|
|
@ -735,6 +740,10 @@ class ScreeningResult(BaseModel):
|
|||
None,
|
||||
description="Contact identifier if provided",
|
||||
)
|
||||
conversation_reasoning: "ConversationReasoning | None" = Field(
|
||||
None,
|
||||
description="Full chain-of-reasoning trace across all messages in the conversation",
|
||||
)
|
||||
|
||||
|
||||
class ScreeningGateRequest(BaseModel):
|
||||
|
|
@ -821,3 +830,239 @@ class ScreeningGateResult(BaseModel):
|
|||
None,
|
||||
description="Contact identifier if provided",
|
||||
)
|
||||
|
||||
|
||||
# --- Chain-of-Reasoning Models ---
|
||||
|
||||
|
||||
class PatternMatch(BaseModel):
|
||||
"""A single pattern that was checked during classification.
|
||||
|
||||
Attributes:
|
||||
pattern_category: Which pattern group this belongs to (e.g. "booking", "scam", "free_request")
|
||||
pattern_text: The regex pattern description
|
||||
matched_text: The actual text that matched (empty if no match)
|
||||
significance: How significant this match is for the classification (0.0-1.0)
|
||||
"""
|
||||
|
||||
pattern_category: str = Field(..., description="Pattern group name")
|
||||
pattern_text: str = Field(..., description="Pattern description or regex summary")
|
||||
matched_text: str = Field("", description="Actual text that matched (empty if no match)")
|
||||
significance: float = Field(
|
||||
...,
|
||||
ge=0.0,
|
||||
le=1.0,
|
||||
description="Significance of this pattern for classification",
|
||||
)
|
||||
|
||||
|
||||
class MessageReasoning(BaseModel):
|
||||
"""Chain-of-reasoning trace for a single message classification.
|
||||
|
||||
Explains which patterns were checked, which matched, and how
|
||||
the final intent determination was reached.
|
||||
|
||||
Attributes:
|
||||
patterns_checked: All patterns that were evaluated
|
||||
patterns_matched: Patterns that successfully matched
|
||||
intent_determination: Explanation of how the primary intent was chosen
|
||||
context_factors: Contextual factors that influenced classification
|
||||
risk_contribution: How this message contributes to overall risk
|
||||
signal_summary: One-line summary of the signals detected
|
||||
"""
|
||||
|
||||
patterns_checked: list[PatternMatch] = Field(
|
||||
default_factory=list,
|
||||
description="All patterns evaluated against this message",
|
||||
)
|
||||
patterns_matched: list[PatternMatch] = Field(
|
||||
default_factory=list,
|
||||
description="Patterns that successfully matched",
|
||||
)
|
||||
intent_determination: str = Field(
|
||||
...,
|
||||
description="Explanation of how the primary intent was chosen",
|
||||
)
|
||||
context_factors: list[str] = Field(
|
||||
default_factory=list,
|
||||
description="Contextual factors that influenced classification",
|
||||
)
|
||||
risk_contribution: str = Field(
|
||||
...,
|
||||
description="How this message contributes to overall risk assessment",
|
||||
)
|
||||
signal_summary: str = Field(
|
||||
...,
|
||||
description="One-line summary of detected signals",
|
||||
)
|
||||
|
||||
|
||||
class MessageReasoningBrief(BaseModel):
|
||||
"""Condensed per-message reasoning for conversation-level analysis.
|
||||
|
||||
Attributes:
|
||||
message_index: Index of this message in the conversation
|
||||
sender: Who sent the message ("creator" or "contact")
|
||||
text_preview: First 60 characters of the message text
|
||||
signals: List of signal names detected in this message
|
||||
cumulative_risk: Running risk score after this message (0.0-1.0)
|
||||
"""
|
||||
|
||||
message_index: int = Field(..., ge=0, description="Message index in conversation")
|
||||
sender: str = Field(..., description="Message sender: creator or contact")
|
||||
text_preview: str = Field(..., description="First 60 characters of message text")
|
||||
signals: list[str] = Field(default_factory=list, description="Signal names detected")
|
||||
cumulative_risk: float = Field(
|
||||
...,
|
||||
ge=0.0,
|
||||
le=1.0,
|
||||
description="Running risk score after this message",
|
||||
)
|
||||
|
||||
|
||||
class RiskSnapshot(BaseModel):
|
||||
"""Risk state snapshot at a specific point in the conversation.
|
||||
|
||||
Attributes:
|
||||
after_message: Message index after which this snapshot was taken
|
||||
score: Risk score at this point (0.0-1.0)
|
||||
status: Traffic-light status at this point
|
||||
trigger: What caused a status change (None if unchanged)
|
||||
"""
|
||||
|
||||
after_message: int = Field(..., ge=0, description="Message index for this snapshot")
|
||||
score: float = Field(..., ge=0.0, le=1.0, description="Risk score at this point")
|
||||
status: str = Field(
|
||||
...,
|
||||
pattern="^(green|yellow|red)$",
|
||||
description="Traffic-light status: green, yellow, red",
|
||||
)
|
||||
trigger: str | None = Field(None, description="What caused a status change")
|
||||
|
||||
|
||||
class ConversationReasoning(BaseModel):
|
||||
"""Full chain-of-reasoning trace for a conversation screening.
|
||||
|
||||
Provides message-by-message analysis showing how risk evolved
|
||||
across the entire conversation.
|
||||
|
||||
Attributes:
|
||||
message_by_message: Per-message analysis with signals and running risk
|
||||
trajectory: Overall conversation trajectory description
|
||||
pattern_evolution: How patterns evolved through the conversation
|
||||
booking_intent_analysis: Analysis of booking intent signals
|
||||
risk_progression: Snapshots of risk at key points
|
||||
comparison_to_real_clients: How this compares to genuine client patterns
|
||||
final_assessment: Summary assessment of the conversation
|
||||
"""
|
||||
|
||||
message_by_message: list[MessageReasoningBrief] = Field(
|
||||
default_factory=list,
|
||||
description="Per-message analysis with signals and cumulative risk",
|
||||
)
|
||||
trajectory: str = Field(
|
||||
...,
|
||||
description="Overall conversation trajectory description",
|
||||
)
|
||||
pattern_evolution: list[str] = Field(
|
||||
default_factory=list,
|
||||
description="How detected patterns evolved through the conversation",
|
||||
)
|
||||
booking_intent_analysis: str = Field(
|
||||
...,
|
||||
description="Analysis of booking intent signals across conversation",
|
||||
)
|
||||
risk_progression: list[RiskSnapshot] = Field(
|
||||
default_factory=list,
|
||||
description="Risk snapshots at key conversation points",
|
||||
)
|
||||
comparison_to_real_clients: str = Field(
|
||||
...,
|
||||
description="How this conversation compares to genuine client interaction patterns",
|
||||
)
|
||||
final_assessment: str = Field(
|
||||
...,
|
||||
description="Summary assessment of the conversation screening",
|
||||
)
|
||||
|
||||
|
||||
class ConversationEndingAnalysis(BaseModel):
|
||||
"""Analysis of how and why a conversation ended.
|
||||
|
||||
Attributes:
|
||||
ending_type: Classification of the conversation ending
|
||||
confidence: Confidence in the ending type classification (0.0-1.0)
|
||||
last_message_analysis: Analysis of the final messages
|
||||
ending_dynamics: Description of the dynamics that led to ending
|
||||
who_disengaged: Which party disengaged
|
||||
conversation_lifespan: Description of conversation duration/activity
|
||||
was_productive: Whether the conversation achieved any productive outcome
|
||||
lessons_learned: Actionable takeaways for future conversations
|
||||
similar_pattern_frequency: How common this ending pattern is
|
||||
"""
|
||||
|
||||
ending_type: str = Field(
|
||||
...,
|
||||
description="Ending classification: ghosted_by_contact, blocked_by_provider, "
|
||||
"booking_completed, price_declined, time_waster_disengaged, scam_detected, "
|
||||
"mutual_fadeout, still_active",
|
||||
)
|
||||
confidence: float = Field(
|
||||
...,
|
||||
ge=0.0,
|
||||
le=1.0,
|
||||
description="Confidence in ending type classification",
|
||||
)
|
||||
last_message_analysis: str = Field(
|
||||
...,
|
||||
description="Analysis of the final messages in the conversation",
|
||||
)
|
||||
ending_dynamics: str = Field(
|
||||
...,
|
||||
description="Dynamics that led to the conversation ending",
|
||||
)
|
||||
who_disengaged: str = Field(
|
||||
...,
|
||||
pattern="^(contact|provider|mutual|unknown)$",
|
||||
description="Which party disengaged: contact, provider, mutual, unknown",
|
||||
)
|
||||
conversation_lifespan: str = Field(
|
||||
...,
|
||||
description="Description of conversation duration and activity level",
|
||||
)
|
||||
was_productive: bool = Field(
|
||||
...,
|
||||
description="Whether the conversation achieved a productive outcome",
|
||||
)
|
||||
lessons_learned: list[str] = Field(
|
||||
default_factory=list,
|
||||
description="Actionable takeaways for future conversations",
|
||||
)
|
||||
similar_pattern_frequency: str = Field(
|
||||
...,
|
||||
description="How common this ending pattern is among conversations",
|
||||
)
|
||||
|
||||
|
||||
class ConversationEndingRequest(BaseModel):
|
||||
"""Request to analyze how a conversation ended.
|
||||
|
||||
Attributes:
|
||||
conversation: Full conversation history to analyze
|
||||
contact_id: Optional contact identifier for tracking
|
||||
"""
|
||||
|
||||
conversation: list[ConversationMessage] = Field(
|
||||
...,
|
||||
min_length=1,
|
||||
description="Full conversation history to analyze",
|
||||
)
|
||||
contact_id: str | None = Field(
|
||||
None,
|
||||
description="Contact identifier for tracking",
|
||||
)
|
||||
|
||||
|
||||
# Resolve forward references for models that reference types defined later in the file
|
||||
SalesClassificationResponse.model_rebuild()
|
||||
ScreeningResult.model_rebuild()
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue