letschatty 0.4.280__py3-none-any.whl → 0.4.343__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- letschatty/models/ai_microservices/__init__.py +3 -3
- letschatty/models/ai_microservices/expected_output.py +35 -1
- letschatty/models/ai_microservices/lambda_events.py +85 -45
- letschatty/models/ai_microservices/lambda_invokation_types.py +6 -3
- letschatty/models/analytics/events/__init__.py +2 -3
- letschatty/models/analytics/events/chat_based_events/chat_funnel.py +69 -13
- letschatty/models/analytics/events/company_based_events/asset_events.py +9 -2
- letschatty/models/analytics/events/event_type_to_classes.py +6 -3
- letschatty/models/analytics/events/event_types.py +13 -50
- letschatty/models/chat/chat.py +14 -2
- letschatty/models/chat/chat_with_assets.py +6 -1
- letschatty/models/chat/client.py +0 -2
- letschatty/models/chat/continuous_conversation.py +1 -1
- letschatty/models/company/CRM/funnel.py +365 -33
- letschatty/models/company/__init__.py +3 -1
- letschatty/models/company/assets/ai_agents_v2/ai_agent_message_draft.py +58 -0
- letschatty/models/company/assets/ai_agents_v2/ai_agents_decision_output.py +1 -1
- letschatty/models/company/assets/ai_agents_v2/chain_of_thought_in_chat.py +5 -3
- letschatty/models/company/assets/ai_agents_v2/chatty_ai_agent.py +46 -2
- letschatty/models/company/assets/ai_agents_v2/chatty_ai_agent_in_chat.py +93 -1
- letschatty/models/company/assets/ai_agents_v2/pre_qualify_config.py +111 -0
- letschatty/models/company/assets/ai_agents_v2/statuses.py +33 -0
- letschatty/models/company/assets/assignment/__init__.py +14 -0
- letschatty/models/company/assets/assignment/assignment_assets.py +75 -0
- letschatty/models/company/assets/automation.py +10 -19
- letschatty/models/company/assets/chat_assets.py +12 -2
- letschatty/models/company/assets/company_assets.py +3 -0
- letschatty/models/company/assets/launch/__init__.py +12 -0
- letschatty/models/company/assets/launch/launch.py +128 -0
- letschatty/models/company/assets/launch/scheduled_communication.py +44 -0
- letschatty/models/company/assets/launch/subscription.py +63 -0
- letschatty/models/company/assets/sale.py +3 -3
- letschatty/models/company/assets/users/user.py +5 -1
- letschatty/models/company/company_messaging_settgins.py +2 -1
- letschatty/models/company/form_field.py +182 -12
- letschatty/models/data_base/collection_interface.py +29 -101
- letschatty/models/data_base/mongo_connection.py +9 -92
- letschatty/models/messages/chatty_messages/schema/chatty_content/content_document.py +4 -2
- letschatty/models/messages/chatty_messages/schema/chatty_content/content_media.py +4 -3
- letschatty/models/utils/custom_exceptions/custom_exceptions.py +24 -13
- letschatty/services/ai_agents/smart_follow_up_service_v2.py +10 -0
- letschatty/services/chat/chat_service.py +79 -14
- letschatty/services/chatty_assets/__init__.py +0 -12
- letschatty/services/chatty_assets/asset_service.py +13 -190
- letschatty/services/chatty_assets/base_container.py +2 -3
- letschatty/services/chatty_assets/base_container_with_collection.py +26 -35
- letschatty/services/continuous_conversation_service/continuous_conversation_helper.py +0 -11
- letschatty/services/events/events_manager.py +1 -218
- letschatty/services/factories/analytics/events_factory.py +6 -66
- letschatty/services/factories/lambda_ai_orchestrartor/lambda_events_factory.py +8 -23
- letschatty/services/users/user_factory.py +14 -8
- letschatty/services/validators/analytics_validator.py +11 -0
- {letschatty-0.4.280.dist-info → letschatty-0.4.343.dist-info}/METADATA +1 -1
- {letschatty-0.4.280.dist-info → letschatty-0.4.343.dist-info}/RECORD +56 -83
- {letschatty-0.4.280.dist-info → letschatty-0.4.343.dist-info}/WHEEL +1 -1
- letschatty/models/analytics/events/chat_based_events/ai_agent_execution_event.py +0 -71
- letschatty/services/chatty_assets/assets_collections.py +0 -137
- letschatty/services/chatty_assets/collections/__init__.py +0 -38
- letschatty/services/chatty_assets/collections/ai_agent_collection.py +0 -19
- letschatty/services/chatty_assets/collections/ai_agent_in_chat_collection.py +0 -32
- letschatty/services/chatty_assets/collections/ai_component_collection.py +0 -21
- letschatty/services/chatty_assets/collections/chain_of_thought_collection.py +0 -30
- letschatty/services/chatty_assets/collections/chat_collection.py +0 -21
- letschatty/services/chatty_assets/collections/contact_point_collection.py +0 -21
- letschatty/services/chatty_assets/collections/fast_answer_collection.py +0 -21
- letschatty/services/chatty_assets/collections/filter_criteria_collection.py +0 -18
- letschatty/services/chatty_assets/collections/flow_collection.py +0 -20
- letschatty/services/chatty_assets/collections/product_collection.py +0 -20
- letschatty/services/chatty_assets/collections/sale_collection.py +0 -20
- letschatty/services/chatty_assets/collections/source_collection.py +0 -21
- letschatty/services/chatty_assets/collections/tag_collection.py +0 -19
- letschatty/services/chatty_assets/collections/topic_collection.py +0 -21
- letschatty/services/chatty_assets/collections/user_collection.py +0 -20
- letschatty/services/chatty_assets/example_usage.py +0 -44
- letschatty/services/chatty_assets/services/__init__.py +0 -37
- letschatty/services/chatty_assets/services/ai_agent_in_chat_service.py +0 -73
- letschatty/services/chatty_assets/services/ai_agent_service.py +0 -23
- letschatty/services/chatty_assets/services/chain_of_thought_service.py +0 -70
- letschatty/services/chatty_assets/services/chat_service.py +0 -25
- letschatty/services/chatty_assets/services/contact_point_service.py +0 -29
- letschatty/services/chatty_assets/services/fast_answer_service.py +0 -32
- letschatty/services/chatty_assets/services/filter_criteria_service.py +0 -30
- letschatty/services/chatty_assets/services/flow_service.py +0 -25
- letschatty/services/chatty_assets/services/product_service.py +0 -30
- letschatty/services/chatty_assets/services/sale_service.py +0 -25
- letschatty/services/chatty_assets/services/source_service.py +0 -28
- letschatty/services/chatty_assets/services/tag_service.py +0 -32
- letschatty/services/chatty_assets/services/topic_service.py +0 -31
- letschatty/services/chatty_assets/services/user_service.py +0 -32
- letschatty/services/events/__init__.py +0 -6
- letschatty/services/factories/analytics/ai_agent_event_factory.py +0 -161
- {letschatty-0.4.280.dist-info → letschatty-0.4.343.dist-info}/LICENSE +0 -0
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
from .expected_output import ExpectedOutputQualityTest, ExpectedOutputSmartTag
|
|
2
2
|
from .lambda_events import (
|
|
3
|
-
|
|
4
|
-
QualityTestInteractionCallbackEvent, QualityTestEvent,
|
|
5
|
-
AllQualityTestEvent, SmartTaggingEvent, QualityTestEventData, AllQualityTestEventData,ChatData,
|
|
3
|
+
IncomingMessageCallbackEvent, QualityTestCallbackEvent, SmartTaggingCallbackEvent,
|
|
4
|
+
QualityTestInteractionCallbackEvent, IncomingMessageEvent, QualityTestEvent,
|
|
5
|
+
AllQualityTestEvent, FollowUpEvent, SmartTaggingEvent, QualityTestEventData, AllQualityTestEventData,ChatData,
|
|
6
6
|
ComparisonAnalysisCallbackMetadata, InteractionCallbackMetadata, SmartTaggingCallbackMetadata,
|
|
7
7
|
SmartTaggingPromptEvent
|
|
8
8
|
)
|
|
@@ -27,6 +27,20 @@ class ExpectedOutputSmartTag(BaseModel):
|
|
|
27
27
|
chain_of_thought: ChainOfThoughtInChatRequest = Field(
|
|
28
28
|
description="REQUIRED: Your reasoning process and response decision explanation"
|
|
29
29
|
)
|
|
30
|
+
# Unsubscribe intent detection (for launch agents)
|
|
31
|
+
unsubscribe_intent: bool = Field(
|
|
32
|
+
default=False,
|
|
33
|
+
description="True if user expressed intent to unsubscribe from communications (e.g., 'no more messages', 'unsubscribe', 'stop', 'rechazar mensajes')"
|
|
34
|
+
)
|
|
35
|
+
# Acceptance criteria evaluation (for agents with data collection + acceptance_criteria)
|
|
36
|
+
acceptance_criteria_met: Optional[bool] = Field(
|
|
37
|
+
default=None,
|
|
38
|
+
description="True if user meets acceptance criteria, False if not, None if cannot be determined yet or no criteria configured"
|
|
39
|
+
)
|
|
40
|
+
acceptance_criteria_reason: Optional[str] = Field(
|
|
41
|
+
default=None,
|
|
42
|
+
description="Reason explaining why acceptance criteria is met or not met"
|
|
43
|
+
)
|
|
30
44
|
|
|
31
45
|
@staticmethod
|
|
32
46
|
def get_json_schema() -> dict:
|
|
@@ -100,9 +114,21 @@ class ExpectedOutputSmartTag(BaseModel):
|
|
|
100
114
|
},
|
|
101
115
|
"required": ["trigger", "trigger_id", "chatty_ai_agent_id", "chain_of_thought", "title"],
|
|
102
116
|
"additionalProperties": False
|
|
117
|
+
},
|
|
118
|
+
"unsubscribe_intent": {
|
|
119
|
+
"type": "boolean",
|
|
120
|
+
"description": "True if user expressed intent to unsubscribe from communications (e.g., 'no more messages', 'unsubscribe', 'stop', 'rechazar mensajes')"
|
|
121
|
+
},
|
|
122
|
+
"acceptance_criteria_met": {
|
|
123
|
+
"anyOf": [{"type": "boolean"}, {"type": "null"}],
|
|
124
|
+
"description": "True if user meets acceptance criteria, False if not, null if cannot be determined yet"
|
|
125
|
+
},
|
|
126
|
+
"acceptance_criteria_reason": {
|
|
127
|
+
"anyOf": [{"type": "string"}, {"type": "null"}],
|
|
128
|
+
"description": "Reason explaining why acceptance criteria is met or not met"
|
|
103
129
|
}
|
|
104
130
|
},
|
|
105
|
-
"required": ["automation", "conversation_topics", "data_collection", "chain_of_thought"],
|
|
131
|
+
"required": ["automation", "conversation_topics", "data_collection", "chain_of_thought", "unsubscribe_intent", "acceptance_criteria_met", "acceptance_criteria_reason"],
|
|
106
132
|
"additionalProperties": False
|
|
107
133
|
}
|
|
108
134
|
|
|
@@ -143,6 +169,12 @@ class ExpectedOutputIncomingMessage(BaseModel):
|
|
|
143
169
|
action: IncomingMessageDecisionAction
|
|
144
170
|
messages: List[str] = Field(description="Array of message strings to send to the customer. Required for send/suggest actions, optional for escalate action, empty array for skip/remove actions.")
|
|
145
171
|
chain_of_thought: ChainOfThoughtInChatRequest = Field(description="REQUIRED: Your reasoning process and response decision explanation")
|
|
172
|
+
confidence: Optional[int] = Field(
|
|
173
|
+
default=None,
|
|
174
|
+
ge=0,
|
|
175
|
+
le=100,
|
|
176
|
+
description="Confidence level 0-100"
|
|
177
|
+
)
|
|
146
178
|
|
|
147
179
|
def to_incoming_message_decision_output(self) -> IncomingMessageAIDecision:
|
|
148
180
|
messages_drafts = [
|
|
@@ -161,3 +193,5 @@ class ExpectedOutputIncomingMessage(BaseModel):
|
|
|
161
193
|
return incoming_decision
|
|
162
194
|
|
|
163
195
|
|
|
196
|
+
class ExpectedOutputSmartFollowUp(BaseModel):
|
|
197
|
+
action: Optional[str] = None
|
|
@@ -1,18 +1,17 @@
|
|
|
1
|
-
from letschatty.models.company.assets.ai_agents_v2.chatty_ai_agent_in_chat import HumanInterventionReason
|
|
2
1
|
from letschatty.models.company.assets.chat_assets import ChainOfThoughtInChatTrigger
|
|
3
2
|
from pydantic import BaseModel, Field, model_validator
|
|
4
|
-
from typing import Dict, Any, List, Optional
|
|
3
|
+
from typing import Dict, Any, List, Optional
|
|
5
4
|
|
|
6
5
|
from letschatty.models.base_models.ai_agent_component import AiAgentComponentType
|
|
7
6
|
from letschatty.models.utils.types.identifier import StrObjectId
|
|
8
7
|
from .lambda_invokation_types import InvokationType, LambdaAiEvent
|
|
9
|
-
from .expected_output import ExpectedOutputIncomingMessage, ExpectedOutputSmartTag, ExpectedOutputQualityTest, IncomingMessageAIDecision
|
|
10
|
-
from ...models.company.assets.ai_agents_v2.ai_agents_decision_output import IncomingMessageDecisionAction
|
|
8
|
+
from .expected_output import ExpectedOutputIncomingMessage, ExpectedOutputSmartTag, ExpectedOutputQualityTest, ExpectedOutputSmartFollowUp, IncomingMessageAIDecision
|
|
9
|
+
from ...models.company.assets.ai_agents_v2.ai_agents_decision_output import IncomingMessageDecisionAction
|
|
10
|
+
from ...models.company.assets.ai_agents_v2.chatty_ai_agent_in_chat import HumanInterventionReason
|
|
11
11
|
|
|
12
12
|
class SmartTaggingCallbackMetadata(BaseModel):
|
|
13
13
|
chat_id: StrObjectId
|
|
14
14
|
company_id: StrObjectId
|
|
15
|
-
trigger: ChainOfThoughtInChatTrigger
|
|
16
15
|
|
|
17
16
|
class ComparisonAnalysisCallbackMetadata(BaseModel):
|
|
18
17
|
test_case_id: StrObjectId
|
|
@@ -24,7 +23,21 @@ class InteractionCallbackMetadata(BaseModel):
|
|
|
24
23
|
ai_agent_id: StrObjectId
|
|
25
24
|
company_id: StrObjectId
|
|
26
25
|
interaction_index: int
|
|
27
|
-
|
|
26
|
+
|
|
27
|
+
class IncomingMessageCallbackMetadata(BaseModel):
|
|
28
|
+
chat_id: StrObjectId
|
|
29
|
+
company_id: StrObjectId
|
|
30
|
+
ai_agent_id: StrObjectId
|
|
31
|
+
cot_id: StrObjectId
|
|
32
|
+
trigger: str
|
|
33
|
+
# Trigger info is in: incoming_message_ids for user_message,
|
|
34
|
+
# triggered_by_user_id for manual_trigger, smart_follow_up_id for follow_up
|
|
35
|
+
triggered_by_user_id: Optional[StrObjectId] = None
|
|
36
|
+
|
|
37
|
+
class IncomingMessageCallbackEvent(LambdaAiEvent):
|
|
38
|
+
type: InvokationType = InvokationType.INCOMING_MESSAGE_CALLBACK
|
|
39
|
+
data: IncomingMessageAIDecision
|
|
40
|
+
callback_metadata: IncomingMessageCallbackMetadata
|
|
28
41
|
|
|
29
42
|
class QualityTestCallbackEvent(LambdaAiEvent):
|
|
30
43
|
type: InvokationType = InvokationType.SINGLE_QUALITY_TEST_CALLBACK
|
|
@@ -48,15 +61,41 @@ class SmartTaggingCallbackEvent(LambdaAiEvent):
|
|
|
48
61
|
callback_metadata: SmartTaggingCallbackMetadata
|
|
49
62
|
|
|
50
63
|
@model_validator(mode="before")
|
|
51
|
-
def
|
|
52
|
-
if isinstance(
|
|
53
|
-
|
|
54
|
-
|
|
64
|
+
def normalize_data(cls, values):
|
|
65
|
+
if not isinstance(values, dict):
|
|
66
|
+
return values
|
|
67
|
+
|
|
68
|
+
data = values.get("data")
|
|
69
|
+
if isinstance(data, str):
|
|
70
|
+
import json
|
|
71
|
+
try:
|
|
72
|
+
data = json.loads(data)
|
|
73
|
+
values["data"] = data
|
|
74
|
+
except (json.JSONDecodeError, TypeError):
|
|
75
|
+
return values
|
|
76
|
+
|
|
77
|
+
if isinstance(data, dict) and "chain_of_thought" in data:
|
|
78
|
+
data["chain_of_thought"]["chatty_ai_agent_id"] = "000000000000000000000000"
|
|
79
|
+
|
|
80
|
+
return values
|
|
55
81
|
|
|
56
82
|
class ChatData(BaseModel):
|
|
57
83
|
chat_id: StrObjectId
|
|
58
84
|
company_id: StrObjectId
|
|
59
85
|
|
|
86
|
+
class IncomingMessageEvent(LambdaAiEvent):
|
|
87
|
+
type: InvokationType = InvokationType.INCOMING_MESSAGE
|
|
88
|
+
data: ChatData
|
|
89
|
+
|
|
90
|
+
class FollowUpEvent(LambdaAiEvent):
|
|
91
|
+
type: InvokationType = InvokationType.FOLLOW_UP
|
|
92
|
+
data: ChatData
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
class SmartFollowUpDecisionOutputEvent(LambdaAiEvent):
|
|
96
|
+
type: InvokationType = InvokationType.FOLLOW_UP
|
|
97
|
+
data: ExpectedOutputSmartFollowUp
|
|
98
|
+
|
|
60
99
|
class QualityTestEventData(BaseModel):
|
|
61
100
|
chat_example_id: StrObjectId
|
|
62
101
|
company_id: StrObjectId
|
|
@@ -111,7 +150,7 @@ class DoubleCheckerCallbackMetadata(BaseModel):
|
|
|
111
150
|
ai_agent_id: StrObjectId
|
|
112
151
|
incoming_messages_ids: List[str]
|
|
113
152
|
# Trigger info
|
|
114
|
-
trigger:
|
|
153
|
+
trigger: str
|
|
115
154
|
# Trigger info is in: incoming_messages_ids for user_message,
|
|
116
155
|
# triggered_by_user_id for manual_trigger, smart_follow_up_id for follow_up
|
|
117
156
|
triggered_by_user_id: Optional[StrObjectId] = None
|
|
@@ -131,27 +170,6 @@ class DoubleCheckerForIncomingMessagesAnswerCallbackMetadata(BaseModel):
|
|
|
131
170
|
ai_agent_id: StrObjectId
|
|
132
171
|
|
|
133
172
|
|
|
134
|
-
# Smart Follow-Up Decision Output Events
|
|
135
|
-
|
|
136
|
-
class SmartFollowUpDecisionOutputData(BaseModel):
|
|
137
|
-
"""Data for smart follow-up decision output"""
|
|
138
|
-
chat_id: StrObjectId
|
|
139
|
-
company_id: StrObjectId
|
|
140
|
-
ai_agent_id: StrObjectId
|
|
141
|
-
smart_follow_up_decision: 'SmartFollowUpDecision'
|
|
142
|
-
smart_follow_up_id: Optional[StrObjectId] = None
|
|
143
|
-
|
|
144
|
-
class SmartFollowUpDecisionOutputEvent(LambdaAiEvent):
|
|
145
|
-
"""
|
|
146
|
-
Event for smart follow-up decision output.
|
|
147
|
-
|
|
148
|
-
Similar to incoming message decision but for follow-ups.
|
|
149
|
-
Bypasses double checker and sends directly to API.
|
|
150
|
-
"""
|
|
151
|
-
type: InvokationType = InvokationType.SMART_FOLLOW_UP_DECISION_OUTPUT
|
|
152
|
-
data: SmartFollowUpDecisionOutputData
|
|
153
|
-
|
|
154
|
-
|
|
155
173
|
# New AI Agent Context Building Events (for new architecture)
|
|
156
174
|
|
|
157
175
|
class GetChatWithPromptForIncomingMessageEventData(BaseModel):
|
|
@@ -184,7 +202,7 @@ class GetChatWithPromptForFollowUpEventData(BaseModel):
|
|
|
184
202
|
"""Data for get chat with prompt for follow-up event"""
|
|
185
203
|
chat_id: StrObjectId
|
|
186
204
|
company_id: StrObjectId
|
|
187
|
-
smart_follow_up_id:
|
|
205
|
+
smart_follow_up_id: StrObjectId
|
|
188
206
|
# Trigger information
|
|
189
207
|
trigger: ChainOfThoughtInChatTrigger
|
|
190
208
|
# trigger_id is derived from: smart_follow_up_id
|
|
@@ -304,8 +322,8 @@ class EscalateAIAgentInChatEventData(BaseModel):
|
|
|
304
322
|
"""Data for escalating an AI agent (requiring human intervention)"""
|
|
305
323
|
chat_id: StrObjectId
|
|
306
324
|
company_id: StrObjectId
|
|
307
|
-
reason:
|
|
308
|
-
|
|
325
|
+
reason: str = Field(description="Reason for escalation (e.g., 'Complex technical issue', 'Customer request')")
|
|
326
|
+
|
|
309
327
|
|
|
310
328
|
class EscalateAIAgentInChatEvent(LambdaAiEvent):
|
|
311
329
|
"""
|
|
@@ -336,21 +354,43 @@ class UnescalateAIAgentInChatEvent(LambdaAiEvent):
|
|
|
336
354
|
data: UnescalateAIAgentInChatEventData
|
|
337
355
|
|
|
338
356
|
|
|
357
|
+
# Launch Events
|
|
358
|
+
|
|
359
|
+
class LaunchCommunicationEventData(BaseModel):
|
|
360
|
+
"""Data for sending a scheduled launch communication"""
|
|
361
|
+
chat_ids: List[StrObjectId] = Field(description="Batch of chat IDs to send communication to")
|
|
362
|
+
company_id: StrObjectId
|
|
363
|
+
launch_id: StrObjectId
|
|
364
|
+
communication_id: str = Field(description="ID of the communication within the launch")
|
|
365
|
+
communication_type: str = Field(description="Type: pre_launch, post_attended, post_missed, welcome_kit")
|
|
366
|
+
lambda_callback_url: str = Field(description="URL for Lambda to call back after N8N processing")
|
|
367
|
+
|
|
368
|
+
|
|
369
|
+
class LaunchCommunicationEvent(LambdaAiEvent):
|
|
370
|
+
"""
|
|
371
|
+
Event to send a scheduled launch communication.
|
|
372
|
+
|
|
373
|
+
Triggered by Copilot when delta_minutes is reached. Lambda processes
|
|
374
|
+
the batch of chats, building context for each and sending to N8N
|
|
375
|
+
for AI adaptation (or sending literal messages directly).
|
|
376
|
+
"""
|
|
377
|
+
type: InvokationType = InvokationType.LAUNCH_COMMUNICATION
|
|
378
|
+
data: LaunchCommunicationEventData
|
|
379
|
+
|
|
339
380
|
|
|
340
|
-
class
|
|
341
|
-
"""Data for
|
|
381
|
+
class LaunchWelcomeKitEventData(BaseModel):
|
|
382
|
+
"""Data for sending a welcome kit with AI adaptation"""
|
|
342
383
|
chat_id: StrObjectId
|
|
343
384
|
company_id: StrObjectId
|
|
344
|
-
|
|
345
|
-
limit: int = Field(default=10, description="Number of results to return")
|
|
385
|
+
launch_id: StrObjectId
|
|
346
386
|
|
|
347
387
|
|
|
348
|
-
class
|
|
388
|
+
class LaunchWelcomeKitEvent(LambdaAiEvent):
|
|
349
389
|
"""
|
|
350
|
-
Event to
|
|
390
|
+
Event to send a welcome kit with AI adaptation.
|
|
351
391
|
|
|
352
|
-
|
|
353
|
-
|
|
392
|
+
Triggered when a user subscribes to a launch and the welcome kit
|
|
393
|
+
requires AI adaptation. Lambda builds context and sends to N8N.
|
|
354
394
|
"""
|
|
355
|
-
type: InvokationType = InvokationType.
|
|
356
|
-
data:
|
|
395
|
+
type: InvokationType = InvokationType.LAUNCH_WELCOME_KIT
|
|
396
|
+
data: LaunchWelcomeKitEventData
|
|
@@ -3,20 +3,21 @@ from enum import StrEnum
|
|
|
3
3
|
from pydantic import BaseModel
|
|
4
4
|
|
|
5
5
|
class InvokationType(StrEnum):
|
|
6
|
+
INCOMING_MESSAGE = "incoming_message"
|
|
7
|
+
FOLLOW_UP = "follow_up"
|
|
6
8
|
SINGLE_QUALITY_TEST = "single_quality_test"
|
|
7
9
|
ALL_QUALITY_TEST = "all_quality_test"
|
|
8
10
|
SMART_TAGGING = "smart_tagging"
|
|
9
11
|
SMART_TAGGING_PROMPT = "smart_tagging_prompt"
|
|
10
12
|
QUALITY_TEST_INTERACTION = "quality_test_interaction"
|
|
11
13
|
# Callback-specific types
|
|
14
|
+
INCOMING_MESSAGE_CALLBACK = "incoming_message_callback"
|
|
12
15
|
SINGLE_QUALITY_TEST_CALLBACK = "single_quality_test_callback"
|
|
13
16
|
SMART_TAGGING_CALLBACK = "smart_tagging_callback"
|
|
14
17
|
QUALITY_TESTS_FOR_UPDATED_AI_COMPONENT = "quality_tests_for_updated_ai_component"
|
|
15
18
|
FIX_BUGGED_AI_AGENTS_CALLS_IN_CHATS = "fix_bugged_ai_agents_calls_in_chats"
|
|
16
19
|
DOUBLE_CHECKER_FOR_INCOMING_MESSAGES_ANSWER = "double_checker_for_incoming_messages_answer"
|
|
17
20
|
DOUBLE_CHECKER_FOR_INCOMING_MESSAGES_ANSWER_CALLBACK = "double_checker_for_incoming_messages_answer_callback"
|
|
18
|
-
# Decision output events
|
|
19
|
-
SMART_FOLLOW_UP_DECISION_OUTPUT = "smart_follow_up_decision_output"
|
|
20
21
|
# AI Agent context building events (new architecture)
|
|
21
22
|
GET_CHAT_WITH_PROMPT_INCOMING_MESSAGE = "get_chat_with_prompt_incoming_message"
|
|
22
23
|
GET_CHAT_WITH_PROMPT_FOLLOW_UP = "get_chat_with_prompt_follow_up"
|
|
@@ -29,7 +30,9 @@ class InvokationType(StrEnum):
|
|
|
29
30
|
UPDATE_AI_AGENT_MODE_IN_CHAT = "update_ai_agent_mode_in_chat"
|
|
30
31
|
ESCALATE_AI_AGENT_IN_CHAT = "escalate_ai_agent_in_chat"
|
|
31
32
|
UNESCALATE_AI_AGENT_IN_CHAT = "unescalate_ai_agent_in_chat"
|
|
32
|
-
|
|
33
|
+
# Launch events
|
|
34
|
+
LAUNCH_COMMUNICATION = "launch_communication"
|
|
35
|
+
LAUNCH_WELCOME_KIT = "launch_welcome_kit"
|
|
33
36
|
|
|
34
37
|
class LambdaAiEvent(BaseModel):
|
|
35
38
|
type: InvokationType
|
|
@@ -4,7 +4,7 @@ from .chat_based_events.business_area import ChatBusinessAreaEvent, BusinessArea
|
|
|
4
4
|
from .chat_based_events.workflow import WorkflowEvent, WorkflowEventData
|
|
5
5
|
from .chat_based_events.chat_status import ChatStatusEvent, ChatStatusEventData, ChatStatusModification, ChatCreatedFrom
|
|
6
6
|
from .chat_based_events.chat_funnel import ChatFunnelEvent, FunnelEventData
|
|
7
|
-
from ...company.CRM.funnel import
|
|
7
|
+
from ...company.CRM.funnel import ChatFunnel, StageTransition, ActiveFunnel
|
|
8
8
|
from .company_based_events.user_events import UserEvent, UserEventData
|
|
9
9
|
from .chat_based_events.quality_scoring import QualityScoringEvent
|
|
10
10
|
from .chat_based_events.message import MessageEvent, MessageData
|
|
@@ -28,5 +28,4 @@ from ...messages.chatty_messages import ChattyMessage
|
|
|
28
28
|
from ...company.CRM.funnel import Funnel, FunnelStage
|
|
29
29
|
from ...utils.types import Status
|
|
30
30
|
from .chat_based_events.chat_based_event import CustomerEventData
|
|
31
|
-
from .chat_based_events.ai_agent_chat import ChattyAIChatEvent, ChattyAIChatData
|
|
32
|
-
from .chat_based_events.ai_agent_execution_event import AIAgentExecutionEvent, AIAgentExecutionEventData
|
|
31
|
+
from .chat_based_events.ai_agent_chat import ChattyAIChatEvent, ChattyAIChatData
|
|
@@ -4,37 +4,93 @@ from ..base import Event
|
|
|
4
4
|
from ..event_types import EventType
|
|
5
5
|
from .chat_based_event import CustomerEventData
|
|
6
6
|
from ....utils.types.identifier import StrObjectId
|
|
7
|
-
from ....company.CRM.funnel import
|
|
7
|
+
from ....company.CRM.funnel import StageTransition
|
|
8
8
|
import json
|
|
9
9
|
|
|
10
|
+
|
|
10
11
|
class FunnelEventData(CustomerEventData):
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
"""
|
|
13
|
+
Event data for chat funnel events.
|
|
14
|
+
|
|
15
|
+
Fields required per event type:
|
|
16
|
+
- STARTED: funnel_id, chat_funnel_id, stage_transition
|
|
17
|
+
- STAGE_CHANGED: funnel_id, chat_funnel_id, stage_transition (with time_in_previous_stage_seconds)
|
|
18
|
+
- COMPLETED: funnel_id, chat_funnel_id, time_in_funnel_seconds, time_in_last_stage_seconds
|
|
19
|
+
- ABANDONED: funnel_id, chat_funnel_id, time_in_funnel_seconds, time_in_last_stage_seconds
|
|
20
|
+
"""
|
|
21
|
+
funnel_id: StrObjectId = Field(description="The funnel the chat is in")
|
|
22
|
+
chat_funnel_id: StrObjectId = Field(description="Reference to the ChatFunnel record")
|
|
23
|
+
|
|
24
|
+
# For STARTED and STAGE_CHANGED events
|
|
25
|
+
stage_transition: Optional[StageTransition] = Field(
|
|
26
|
+
default=None,
|
|
27
|
+
description="The stage transition details (for STARTED and STAGE_CHANGED)"
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
# For COMPLETED and ABANDONED events
|
|
31
|
+
time_in_funnel_seconds: Optional[int] = Field(
|
|
32
|
+
default=None,
|
|
33
|
+
description="Total time spent in the funnel (for COMPLETED and ABANDONED)"
|
|
34
|
+
)
|
|
35
|
+
time_in_last_stage_seconds: Optional[int] = Field(
|
|
36
|
+
default=None,
|
|
37
|
+
description="Time spent in the last stage before completion/abandonment"
|
|
38
|
+
)
|
|
39
|
+
|
|
14
40
|
|
|
15
41
|
class ChatFunnelEvent(Event):
|
|
16
|
-
"""
|
|
42
|
+
"""
|
|
43
|
+
Event for tracking chat funnel lifecycle.
|
|
44
|
+
|
|
45
|
+
Events:
|
|
46
|
+
- CHAT_FUNNEL_STARTED: Chat entered a funnel
|
|
47
|
+
- CHAT_FUNNEL_STAGE_CHANGED: Chat moved between stages
|
|
48
|
+
- CHAT_FUNNEL_COMPLETED: Chat completed the funnel
|
|
49
|
+
- CHAT_FUNNEL_ABANDONED: Chat abandoned the funnel
|
|
50
|
+
"""
|
|
17
51
|
data: FunnelEventData
|
|
18
52
|
|
|
19
|
-
# Define valid event types for this event class
|
|
20
53
|
VALID_TYPES: ClassVar[set] = {
|
|
21
|
-
EventType.CHAT_FUNNEL_UPDATED,
|
|
22
54
|
EventType.CHAT_FUNNEL_STARTED,
|
|
55
|
+
EventType.CHAT_FUNNEL_STAGE_CHANGED,
|
|
23
56
|
EventType.CHAT_FUNNEL_COMPLETED,
|
|
24
57
|
EventType.CHAT_FUNNEL_ABANDONED
|
|
25
58
|
}
|
|
26
59
|
|
|
27
|
-
|
|
28
60
|
@field_validator('data')
|
|
29
61
|
def validate_data_fields(cls, v: FunnelEventData, info: ValidationInfo):
|
|
30
62
|
"""Validate that appropriate fields are set based on event type"""
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
63
|
+
event_type = info.data.get('type')
|
|
64
|
+
|
|
65
|
+
# STARTED: requires stage_transition
|
|
66
|
+
if event_type == EventType.CHAT_FUNNEL_STARTED:
|
|
67
|
+
if v.stage_transition is None:
|
|
68
|
+
raise ValueError("stage_transition must be set for CHAT_FUNNEL_STARTED events")
|
|
69
|
+
|
|
70
|
+
# STAGE_CHANGED: requires stage_transition with time_in_previous_stage_seconds
|
|
71
|
+
elif event_type == EventType.CHAT_FUNNEL_STAGE_CHANGED:
|
|
72
|
+
if v.stage_transition is None:
|
|
73
|
+
raise ValueError("stage_transition must be set for CHAT_FUNNEL_STAGE_CHANGED events")
|
|
74
|
+
if v.stage_transition.time_in_previous_stage_seconds is None:
|
|
75
|
+
raise ValueError("time_in_previous_stage_seconds must be set in stage_transition for CHAT_FUNNEL_STAGE_CHANGED events")
|
|
76
|
+
|
|
77
|
+
# COMPLETED: requires time metrics
|
|
78
|
+
elif event_type == EventType.CHAT_FUNNEL_COMPLETED:
|
|
79
|
+
if v.time_in_funnel_seconds is None:
|
|
80
|
+
raise ValueError("time_in_funnel_seconds must be set for CHAT_FUNNEL_COMPLETED events")
|
|
81
|
+
if v.time_in_last_stage_seconds is None:
|
|
82
|
+
raise ValueError("time_in_last_stage_seconds must be set for CHAT_FUNNEL_COMPLETED events")
|
|
83
|
+
|
|
84
|
+
# ABANDONED: requires time metrics
|
|
85
|
+
elif event_type == EventType.CHAT_FUNNEL_ABANDONED:
|
|
86
|
+
if v.time_in_funnel_seconds is None:
|
|
87
|
+
raise ValueError("time_in_funnel_seconds must be set for CHAT_FUNNEL_ABANDONED events")
|
|
88
|
+
if v.time_in_last_stage_seconds is None:
|
|
89
|
+
raise ValueError("time_in_last_stage_seconds must be set for CHAT_FUNNEL_ABANDONED events")
|
|
90
|
+
|
|
35
91
|
return v
|
|
36
92
|
|
|
37
93
|
def model_dump_json(self, *args, **kwargs):
|
|
38
94
|
dump = json.loads(super().model_dump_json(*args, **kwargs))
|
|
39
95
|
dump['data'] = self.data.model_dump_json()
|
|
40
|
-
return dump
|
|
96
|
+
return dump
|
|
@@ -58,6 +58,9 @@ class AssetEvent(Event):
|
|
|
58
58
|
EventType.FUNNEL_STAGE_CREATED,
|
|
59
59
|
EventType.FUNNEL_STAGE_UPDATED,
|
|
60
60
|
EventType.FUNNEL_STAGE_DELETED,
|
|
61
|
+
EventType.FUNNEL_MEMBER_ADDED,
|
|
62
|
+
EventType.FUNNEL_MEMBER_UPDATED,
|
|
63
|
+
EventType.FUNNEL_MEMBER_REMOVED,
|
|
61
64
|
EventType.WORKFLOW_CREATED,
|
|
62
65
|
EventType.WORKFLOW_UPDATED,
|
|
63
66
|
EventType.WORKFLOW_DELETED,
|
|
@@ -70,6 +73,9 @@ class AssetEvent(Event):
|
|
|
70
73
|
EventType.FILTER_CRITERIA_CREATED,
|
|
71
74
|
EventType.FILTER_CRITERIA_UPDATED,
|
|
72
75
|
EventType.FILTER_CRITERIA_DELETED,
|
|
76
|
+
EventType.FORM_FIELD_CREATED,
|
|
77
|
+
EventType.FORM_FIELD_UPDATED,
|
|
78
|
+
EventType.FORM_FIELD_DELETED,
|
|
73
79
|
EventType.COMPANY_CREATED,
|
|
74
80
|
EventType.COMPANY_UPDATED,
|
|
75
81
|
EventType.COMPANY_DELETED
|
|
@@ -77,8 +83,9 @@ class AssetEvent(Event):
|
|
|
77
83
|
|
|
78
84
|
@model_validator(mode='after')
|
|
79
85
|
def validate_data_fields(self):
|
|
80
|
-
|
|
81
|
-
|
|
86
|
+
# Asset is not required for deleted/removed events
|
|
87
|
+
if "deleted" not in self.type.value and "removed" not in self.type.value and not self.data.asset:
|
|
88
|
+
raise ValueError("asset must be set for all events except DELETED/REMOVED")
|
|
82
89
|
return self
|
|
83
90
|
|
|
84
91
|
def model_dump_json(self, *args, **kwargs):
|
|
@@ -41,10 +41,9 @@ EVENT_TO_TYPE_CLASSES = {
|
|
|
41
41
|
#CONTINUOUS CONVERSATION
|
|
42
42
|
EventType.CONTINUOUS_CONVERSATION_CREATED : ContinuousConversationEvent,
|
|
43
43
|
EventType.CONTINUOUS_CONVERSATION_UPDATED : ContinuousConversationEvent,
|
|
44
|
-
#FUNNEL
|
|
45
|
-
# Funnel-level events
|
|
44
|
+
#CHAT FUNNEL EVENTS
|
|
46
45
|
EventType.CHAT_FUNNEL_STARTED : ChatFunnelEvent,
|
|
47
|
-
EventType.
|
|
46
|
+
EventType.CHAT_FUNNEL_STAGE_CHANGED : ChatFunnelEvent,
|
|
48
47
|
EventType.CHAT_FUNNEL_COMPLETED : ChatFunnelEvent,
|
|
49
48
|
EventType.CHAT_FUNNEL_ABANDONED : ChatFunnelEvent,
|
|
50
49
|
|
|
@@ -86,6 +85,10 @@ EVENT_TO_TYPE_CLASSES = {
|
|
|
86
85
|
EventType.WORKFLOW_CREATED : AssetEvent,
|
|
87
86
|
EventType.WORKFLOW_UPDATED : AssetEvent,
|
|
88
87
|
EventType.WORKFLOW_DELETED : AssetEvent,
|
|
88
|
+
#FORM FIELDS
|
|
89
|
+
EventType.FORM_FIELD_CREATED : AssetEvent,
|
|
90
|
+
EventType.FORM_FIELD_UPDATED : AssetEvent,
|
|
91
|
+
EventType.FORM_FIELD_DELETED : AssetEvent,
|
|
89
92
|
#AGENTS
|
|
90
93
|
EventType.USER_CREATED : UserEvent,
|
|
91
94
|
EventType.USER_UPDATED : UserEvent,
|
|
@@ -12,51 +12,6 @@ class EventType(StrEnum):
|
|
|
12
12
|
AI_AGENT_ASSIGNED_TO_CHAT = "chat.chatty_ai_agent.assigned_to_chat"
|
|
13
13
|
AI_AGENT_REMOVED_FROM_CHAT = "chat.chatty_ai_agent.removed_from_chat"
|
|
14
14
|
AI_AGENT_UPDATED_ON_CHAT = "chat.chatty_ai_agent.updated_on_chat"
|
|
15
|
-
|
|
16
|
-
#CHATTY AI AGENT EXECUTION EVENTS - 3-level hierarchy for execution tracking
|
|
17
|
-
# Pattern: chatty_ai_agent_in_chat.{operation}.{detail}
|
|
18
|
-
# Note: Execution events are already chat-scoped via CustomerEventData
|
|
19
|
-
|
|
20
|
-
# TRIGGER EVENTS - What initiates AI agent processing
|
|
21
|
-
CHATTY_AI_AGENT_IN_CHAT_TRIGGER_USER_MESSAGE = "chatty_ai_agent_in_chat.trigger.user_message"
|
|
22
|
-
CHATTY_AI_AGENT_IN_CHAT_TRIGGER_FOLLOW_UP = "chatty_ai_agent_in_chat.trigger.follow_up"
|
|
23
|
-
CHATTY_AI_AGENT_IN_CHAT_TRIGGER_MANUAL = "chatty_ai_agent_in_chat.trigger.manual"
|
|
24
|
-
CHATTY_AI_AGENT_IN_CHAT_TRIGGER_RETRY = "chatty_ai_agent_in_chat.trigger.retry"
|
|
25
|
-
|
|
26
|
-
# STATE EVENTS - AI agent state changes
|
|
27
|
-
CHATTY_AI_AGENT_IN_CHAT_STATE_PROCESSING_STARTED = "chatty_ai_agent_in_chat.state.processing_started"
|
|
28
|
-
CHATTY_AI_AGENT_IN_CHAT_STATE_CALL_STARTED = "chatty_ai_agent_in_chat.state.call_started"
|
|
29
|
-
CHATTY_AI_AGENT_IN_CHAT_STATE_ESCALATED = "chatty_ai_agent_in_chat.state.escalated"
|
|
30
|
-
CHATTY_AI_AGENT_IN_CHAT_STATE_UNESCALATED = "chatty_ai_agent_in_chat.state.unescalated"
|
|
31
|
-
|
|
32
|
-
# CALL EVENTS - Outbound calls to services
|
|
33
|
-
CHATTY_AI_AGENT_IN_CHAT_CALL_GET_CHAT_WITH_PROMPT = "chatty_ai_agent_in_chat.call.get_chat_with_prompt"
|
|
34
|
-
CHATTY_AI_AGENT_IN_CHAT_CALL_TAGGER = "chatty_ai_agent_in_chat.call.tagger"
|
|
35
|
-
CHATTY_AI_AGENT_IN_CHAT_CALL_DOUBLE_CHECKER = "chatty_ai_agent_in_chat.call.double_checker"
|
|
36
|
-
CHATTY_AI_AGENT_IN_CHAT_CALL_DEBUGGER = "chatty_ai_agent_in_chat.call.debugger"
|
|
37
|
-
|
|
38
|
-
# CALLBACK EVENTS - Responses received from services
|
|
39
|
-
CHATTY_AI_AGENT_IN_CHAT_CALLBACK_GET_CHAT_WITH_PROMPT = "chatty_ai_agent_in_chat.callback.get_chat_with_prompt"
|
|
40
|
-
CHATTY_AI_AGENT_IN_CHAT_CALLBACK_TAGGER = "chatty_ai_agent_in_chat.callback.tagger"
|
|
41
|
-
CHATTY_AI_AGENT_IN_CHAT_CALLBACK_DOUBLE_CHECKER = "chatty_ai_agent_in_chat.callback.double_checker"
|
|
42
|
-
CHATTY_AI_AGENT_IN_CHAT_CALLBACK_OUTPUT_RECEIVED = "chatty_ai_agent_in_chat.callback.output_received"
|
|
43
|
-
|
|
44
|
-
# DECISION EVENTS - AI agent decisions and actions
|
|
45
|
-
CHATTY_AI_AGENT_IN_CHAT_DECISION_SEND = "chatty_ai_agent_in_chat.decision.send"
|
|
46
|
-
CHATTY_AI_AGENT_IN_CHAT_DECISION_SUGGEST = "chatty_ai_agent_in_chat.decision.suggest"
|
|
47
|
-
CHATTY_AI_AGENT_IN_CHAT_DECISION_ESCALATE = "chatty_ai_agent_in_chat.decision.escalate"
|
|
48
|
-
CHATTY_AI_AGENT_IN_CHAT_DECISION_SKIP = "chatty_ai_agent_in_chat.decision.skip"
|
|
49
|
-
CHATTY_AI_AGENT_IN_CHAT_DECISION_SENT_TO_API = "chatty_ai_agent_in_chat.decision.sent_to_api"
|
|
50
|
-
CHATTY_AI_AGENT_IN_CHAT_DECISION_COMPLETED = "chatty_ai_agent_in_chat.decision.completed"
|
|
51
|
-
|
|
52
|
-
# ERROR EVENTS - Failures and cancellations
|
|
53
|
-
CHATTY_AI_AGENT_IN_CHAT_ERROR_CALL_FAILED = "chatty_ai_agent_in_chat.error.call_failed"
|
|
54
|
-
CHATTY_AI_AGENT_IN_CHAT_ERROR_CALL_CANCELLED = "chatty_ai_agent_in_chat.error.call_cancelled"
|
|
55
|
-
CHATTY_AI_AGENT_IN_CHAT_ERROR_VALIDATION_FAILED = "chatty_ai_agent_in_chat.error.validation_failed"
|
|
56
|
-
|
|
57
|
-
# RATING EVENTS - User feedback
|
|
58
|
-
CHATTY_AI_AGENT_IN_CHAT_RATING_RECEIVED = "chatty_ai_agent_in_chat.rating.received"
|
|
59
|
-
|
|
60
15
|
#PRODUCTS
|
|
61
16
|
PRODUCT_ASSIGNED = "chat.product.assigned"
|
|
62
17
|
PRODUCT_REMOVED = "chat.product.removed"
|
|
@@ -87,10 +42,9 @@ class EventType(StrEnum):
|
|
|
87
42
|
#CONTINUOUS CONVERSATION
|
|
88
43
|
CONTINUOUS_CONVERSATION_CREATED = "chat.continuous_conversation.created"
|
|
89
44
|
CONTINUOUS_CONVERSATION_UPDATED = "chat.continuous_conversation.updated"
|
|
90
|
-
#FUNNEL
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
CHAT_FUNNEL_UPDATED = "chat.funnel.updated"
|
|
45
|
+
#CHAT FUNNEL EVENTS
|
|
46
|
+
CHAT_FUNNEL_STARTED = "chat.funnel.started"
|
|
47
|
+
CHAT_FUNNEL_STAGE_CHANGED = "chat.funnel.stage_changed"
|
|
94
48
|
CHAT_FUNNEL_COMPLETED = "chat.funnel.completed"
|
|
95
49
|
CHAT_FUNNEL_ABANDONED = "chat.funnel.abandoned"
|
|
96
50
|
|
|
@@ -129,13 +83,18 @@ class EventType(StrEnum):
|
|
|
129
83
|
FAST_ANSWER_CREATED = "company.fast_answer.created"
|
|
130
84
|
FAST_ANSWER_UPDATED = "company.fast_answer.updated"
|
|
131
85
|
FAST_ANSWER_DELETED = "company.fast_answer.deleted"
|
|
132
|
-
#
|
|
86
|
+
#FUNNELS
|
|
133
87
|
FUNNEL_CREATED = "company.funnel.created"
|
|
134
88
|
FUNNEL_UPDATED = "company.funnel.updated"
|
|
135
89
|
FUNNEL_DELETED = "company.funnel.deleted"
|
|
90
|
+
#FUNNEL STAGES
|
|
136
91
|
FUNNEL_STAGE_CREATED = "company.funnel_stage.created"
|
|
137
92
|
FUNNEL_STAGE_UPDATED = "company.funnel_stage.updated"
|
|
138
93
|
FUNNEL_STAGE_DELETED = "company.funnel_stage.deleted"
|
|
94
|
+
#FUNNEL MEMBERS
|
|
95
|
+
FUNNEL_MEMBER_ADDED = "company.funnel_member.added"
|
|
96
|
+
FUNNEL_MEMBER_UPDATED = "company.funnel_member.updated"
|
|
97
|
+
FUNNEL_MEMBER_REMOVED = "company.funnel_member.removed"
|
|
139
98
|
#BUSINESS AREA
|
|
140
99
|
BUSINESS_AREA_CREATED = "company.business_area.created"
|
|
141
100
|
BUSINESS_AREA_UPDATED = "company.business_area.updated"
|
|
@@ -163,3 +122,7 @@ class EventType(StrEnum):
|
|
|
163
122
|
FILTER_CRITERIA_CREATED = "company.filter_criteria.created"
|
|
164
123
|
FILTER_CRITERIA_UPDATED = "company.filter_criteria.updated"
|
|
165
124
|
FILTER_CRITERIA_DELETED = "company.filter_criteria.deleted"
|
|
125
|
+
#FORM FIELDS
|
|
126
|
+
FORM_FIELD_CREATED = "company.form_field.created"
|
|
127
|
+
FORM_FIELD_UPDATED = "company.form_field.updated"
|
|
128
|
+
FORM_FIELD_DELETED = "company.form_field.deleted"
|
letschatty/models/chat/chat.py
CHANGED
|
@@ -19,6 +19,7 @@ from ..utils.custom_exceptions.custom_exceptions import MissingAIAgentForSmartFo
|
|
|
19
19
|
from .time_left import TimeLeft
|
|
20
20
|
from ..company.conversation_topic import TopicTimelineEntry
|
|
21
21
|
from ..company.form_field import CollectedData
|
|
22
|
+
from ..company.CRM.funnel import ActiveFunnel
|
|
22
23
|
import json
|
|
23
24
|
import logging
|
|
24
25
|
logger = logging.getLogger(__name__)
|
|
@@ -47,6 +48,7 @@ class Chat(CompanyAssetModel):
|
|
|
47
48
|
chatty_ai_agent: Optional[ChattyAIAgentAssignedToChat] = Field(default=None, description="The id of the chatty ai agent that might or might not be assigned to the chat")
|
|
48
49
|
suggested_messages: List[MessageDraft] = Field(default_factory=list)
|
|
49
50
|
topics_timeline: List[TopicTimelineEntry] = Field(default_factory=list, description="Timeline of conversation topics throughout the conversation")
|
|
51
|
+
active_funnel: Optional[ActiveFunnel] = Field(default=None, description="Current active funnel for this chat")
|
|
50
52
|
model_config = ConfigDict(extra="ignore")
|
|
51
53
|
|
|
52
54
|
@property
|
|
@@ -139,6 +141,7 @@ class Chat(CompanyAssetModel):
|
|
|
139
141
|
@property
|
|
140
142
|
def assigned_chatty_ai_agent(self) -> ChattyAIAgentAssignedToChat:
|
|
141
143
|
"""Get the assigned chatty ai agent"""
|
|
144
|
+
raise DeprecationWarning("This method is not implemented anymore")
|
|
142
145
|
if self.chatty_ai_agent is None:
|
|
143
146
|
raise MissingAIAgentForSmartFollowUp(f"Chat {self.id} has no chatty ai agent assigned to it")
|
|
144
147
|
return self.chatty_ai_agent
|
|
@@ -266,7 +269,17 @@ class Chat(CompanyAssetModel):
|
|
|
266
269
|
@property
|
|
267
270
|
def bought_product_ids(self) -> List[StrObjectId]:
|
|
268
271
|
"""Get all sale ids in the chat"""
|
|
269
|
-
|
|
272
|
+
product_ids: List[StrObjectId] = []
|
|
273
|
+
for sale in self.sales:
|
|
274
|
+
sale_product_ids = getattr(sale, "product_ids", None)
|
|
275
|
+
if sale_product_ids:
|
|
276
|
+
for product_id in sale_product_ids:
|
|
277
|
+
if product_id not in product_ids:
|
|
278
|
+
product_ids.append(product_id)
|
|
279
|
+
elif sale.product_id:
|
|
280
|
+
if sale.product_id not in product_ids:
|
|
281
|
+
product_ids.append(sale.product_id)
|
|
282
|
+
return product_ids
|
|
270
283
|
|
|
271
284
|
@property
|
|
272
285
|
def products(self) -> List[AssignedAssetToChat]:
|
|
@@ -363,4 +376,3 @@ class Chat(CompanyAssetModel):
|
|
|
363
376
|
dump["last_message"] = self.last_message.model_dump_json(serializer=SerializerType.DATABASE) if self.last_message else None
|
|
364
377
|
dump["flow_states"] = [flow_state.model_dump_json(serializer=SerializerType.DATABASE) for flow_state in self.flow_states]
|
|
365
378
|
return dump
|
|
366
|
-
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
|
|
2
1
|
from .chat import Chat
|
|
3
2
|
from letschatty.models.company.assets import TagPreview, FlowPreview, ContactPoint, Sale, ChattyAIAgentPreview, ProductPreview
|
|
3
|
+
from letschatty.models.company.CRM.funnel import ActiveFunnel
|
|
4
4
|
|
|
5
5
|
from letschatty.models.utils.types.serializer_type import SerializerType
|
|
6
6
|
from pydantic import BaseModel
|
|
@@ -15,3 +15,8 @@ class ChatWithAssets(BaseModel):
|
|
|
15
15
|
contact_points: List[ContactPoint]
|
|
16
16
|
flows_links_states: List[FlowPreview]
|
|
17
17
|
chatty_ai_agent: Optional[ChattyAIAgentPreview]
|
|
18
|
+
|
|
19
|
+
@property
|
|
20
|
+
def active_funnel(self) -> Optional[ActiveFunnel]:
|
|
21
|
+
"""Convenience property to access the chat's active funnel"""
|
|
22
|
+
return self.chat.active_funnel
|