letschatty 0.1.44__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/__init__.py +2 -0
- letschatty/models/__init__.py +4 -0
- letschatty/models/company/empresa.py +11 -0
- letschatty/models/events/__init__.py +6 -0
- letschatty/models/events/base.py +45 -0
- letschatty/models/events/contact_point.py +18 -0
- letschatty/models/events/event_types.py +11 -0
- letschatty/models/events/new_chat.py +11 -0
- letschatty/models/events/quality_scoring.py +16 -0
- letschatty/models/events/sale.py +16 -0
- letschatty/models/events/template.py +19 -0
- letschatty/models/messages/__init__.py +2 -0
- letschatty/models/messages/chatty_messages/__init__.py +17 -0
- letschatty/models/messages/chatty_messages/audio.py +7 -0
- letschatty/models/messages/chatty_messages/base/__init__.py +1 -0
- letschatty/models/messages/chatty_messages/base/chatty_message_json.py +22 -0
- letschatty/models/messages/chatty_messages/base/message_base.py +117 -0
- letschatty/models/messages/chatty_messages/button.py +7 -0
- letschatty/models/messages/chatty_messages/central_notification.py +8 -0
- letschatty/models/messages/chatty_messages/contact.py +7 -0
- letschatty/models/messages/chatty_messages/document.py +7 -0
- letschatty/models/messages/chatty_messages/image.py +7 -0
- letschatty/models/messages/chatty_messages/interactive.py +6 -0
- letschatty/models/messages/chatty_messages/location.py +7 -0
- letschatty/models/messages/chatty_messages/reaction.py +7 -0
- letschatty/models/messages/chatty_messages/schema/__init__.py +18 -0
- letschatty/models/messages/chatty_messages/schema/chatty_content/content_audio.py +6 -0
- letschatty/models/messages/chatty_messages/schema/chatty_content/content_central.py +5 -0
- letschatty/models/messages/chatty_messages/schema/chatty_content/content_contacts.py +21 -0
- letschatty/models/messages/chatty_messages/schema/chatty_content/content_document.py +8 -0
- letschatty/models/messages/chatty_messages/schema/chatty_content/content_image.py +4 -0
- letschatty/models/messages/chatty_messages/schema/chatty_content/content_location.py +5 -0
- letschatty/models/messages/chatty_messages/schema/chatty_content/content_media.py +8 -0
- letschatty/models/messages/chatty_messages/schema/chatty_content/content_reaction.py +4 -0
- letschatty/models/messages/chatty_messages/schema/chatty_content/content_sticker.py +6 -0
- letschatty/models/messages/chatty_messages/schema/chatty_content/content_text.py +5 -0
- letschatty/models/messages/chatty_messages/schema/chatty_content/content_video.py +5 -0
- letschatty/models/messages/chatty_messages/schema/chatty_context/__init__.py +0 -0
- letschatty/models/messages/chatty_messages/schema/chatty_context/chatty_context.py +22 -0
- letschatty/models/messages/chatty_messages/schema/chatty_referal/__init__.py +0 -0
- letschatty/models/messages/chatty_messages/schema/chatty_referal/chatty_referal.py +37 -0
- letschatty/models/messages/chatty_messages/sticker.py +7 -0
- letschatty/models/messages/chatty_messages/text.py +7 -0
- letschatty/models/messages/chatty_messages/unknown.py +6 -0
- letschatty/models/messages/chatty_messages/unsupported.py +5 -0
- letschatty/models/messages/chatty_messages/video.py +7 -0
- letschatty/models/messages/messages_request/__init__.py +1 -0
- letschatty/models/messages/messages_request/message_request.py +22 -0
- letschatty/models/messages/meta_message_model/meta_base_notification_json.py +64 -0
- letschatty/models/messages/meta_message_model/meta_error_json.py +10 -0
- letschatty/models/messages/meta_message_model/meta_inexistent_json.py +5 -0
- letschatty/models/messages/meta_message_model/meta_message_json.py +142 -0
- letschatty/models/messages/meta_message_model/meta_message_types.py +126 -0
- letschatty/models/messages/meta_message_model/meta_status_json.py +85 -0
- letschatty/models/messages/meta_message_model/meta_unknown_json.py +5 -0
- letschatty/models/metrics/__init_.py +5 -0
- letschatty/models/metrics/daily_contact_points.py +21 -0
- letschatty/models/metrics/daily_new_chats.py +12 -0
- letschatty/models/metrics/daily_sent_templates_grouped.py +21 -0
- letschatty/models/metrics/sales_roadmap.py +15 -0
- letschatty/models/metrics/sent_templates.py +19 -0
- letschatty/models/utils/__init__.py +1 -0
- letschatty/models/utils/types/__init__.py +8 -0
- letschatty/models/utils/types/channel_types.py +5 -0
- letschatty/models/utils/types/country.py +20 -0
- letschatty/models/utils/types/identifier.py +15 -0
- letschatty/models/utils/types/message_status_types.py +8 -0
- letschatty/models/utils/types/message_types.py +20 -0
- letschatty/models/utils/types/phone_number.py +14 -0
- letschatty/models/utils/types/source_types.py +9 -0
- letschatty/models/utils/types/typealiases.py +1 -0
- letschatty/services/factories/__init__.py +1 -0
- letschatty/services/factories/child_chatty_message_factory.py +1 -0
- letschatty/services/factories/child_db_message_factory.py +108 -0
- letschatty/services/factories/child_request_message.py +97 -0
- letschatty/services/factories/parent_message_factory.py +18 -0
- letschatty-0.1.44.dist-info/LICENSE +18 -0
- letschatty-0.1.44.dist-info/METADATA +37 -0
- letschatty-0.1.44.dist-info/RECORD +80 -0
- letschatty-0.1.44.dist-info/WHEEL +4 -0
letschatty/__init__.py
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
from pydantic import BaseModel, Field
|
|
2
|
+
from typing import Optional
|
|
3
|
+
|
|
4
|
+
class Empresa(BaseModel):
|
|
5
|
+
name: str
|
|
6
|
+
phone_number_id: str = Field(alias="company_id")
|
|
7
|
+
bussiness_account_id: str
|
|
8
|
+
photo_url: str
|
|
9
|
+
meta_token: str
|
|
10
|
+
slack_channel_id: Optional[str] = Field(default=None)
|
|
11
|
+
phone_numbers_for_testing: list[str] = Field(default=[])
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
from pydantic import BaseModel, Field
|
|
2
|
+
from enum import StrEnum
|
|
3
|
+
from bson import ObjectId
|
|
4
|
+
from datetime import datetime, timezone
|
|
5
|
+
from typing import Dict, Any
|
|
6
|
+
from .event_types import EventType
|
|
7
|
+
from ..utils.types.identifier import StrObjectId
|
|
8
|
+
import re
|
|
9
|
+
|
|
10
|
+
class ChattyCloudEvent(BaseModel):
|
|
11
|
+
id: StrObjectId = Field(default_factory=lambda: str(ObjectId()), alias="_id")
|
|
12
|
+
source: str = Field(..., pattern=r"com\.chatty/[a-z-]+/[a-zA-Z0-9-]+")
|
|
13
|
+
specversion: str = Field(default="1.0")
|
|
14
|
+
type: EventType
|
|
15
|
+
time: datetime = Field(default_factory=lambda: datetime.now(tz=timezone.utc))
|
|
16
|
+
datacontenttype: str = Field(default="application/json")
|
|
17
|
+
data: Dict[str, Any]
|
|
18
|
+
|
|
19
|
+
class ClientEvent(ChattyCloudEvent):
|
|
20
|
+
"""Used for client related events, either management wise like an agent event or a business logic event like a new_chat."""
|
|
21
|
+
source: str = Field(..., pattern=r"com\.chatty/clients/[a-zA-Z0-9-]+")
|
|
22
|
+
|
|
23
|
+
@property
|
|
24
|
+
def client_id(self) -> str:
|
|
25
|
+
match = re.search(r"com\.chatty/clients/([a-zA-Z0-9-]+)", self.source)
|
|
26
|
+
if match:
|
|
27
|
+
return match.group(1)
|
|
28
|
+
raise ValueError("Invalid source format")
|
|
29
|
+
|
|
30
|
+
class InternalEvent(ChattyCloudEvent):
|
|
31
|
+
"""Used for internal events such as a new client, some billing, etc."""
|
|
32
|
+
source: str = Field(..., pattern=r"com\.chatty/internal/[a-z-]+")
|
|
33
|
+
|
|
34
|
+
class BusinessLogicEvent(ClientEvent):
|
|
35
|
+
"""Used for business logic events, such as a quality scoring."""
|
|
36
|
+
source: str = Field(..., pattern=r"com\.chatty/business-logic/[a-zA-Z0-9-]+")
|
|
37
|
+
|
|
38
|
+
class BusinessLogicEventData(BaseModel):
|
|
39
|
+
channel_id : str
|
|
40
|
+
chat_id : StrObjectId
|
|
41
|
+
client_channel_user_id : str = Field(..., alias="waid")
|
|
42
|
+
company_phone_number_id : str
|
|
43
|
+
subtype : StrEnum
|
|
44
|
+
|
|
45
|
+
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
from .base import BusinessLogicEventData, BusinessLogicEvent
|
|
2
|
+
from .event_types import EventType
|
|
3
|
+
from ..utils.types.identifier import StrObjectId
|
|
4
|
+
from enum import StrEnum
|
|
5
|
+
|
|
6
|
+
class CPSubtype(StrEnum):
|
|
7
|
+
CREATED = "created"
|
|
8
|
+
UPDATED = "updated"
|
|
9
|
+
DELETED = "deleted"
|
|
10
|
+
|
|
11
|
+
class ContactPointData(BusinessLogicEventData):
|
|
12
|
+
source_id: StrObjectId
|
|
13
|
+
new_chat : bool
|
|
14
|
+
|
|
15
|
+
class ContactPointEvent(BusinessLogicEvent):
|
|
16
|
+
"""Used for client related events, such as a new chat, a touchpoint, etc."""
|
|
17
|
+
type: EventType = EventType.CONTACT_POINT
|
|
18
|
+
data: ContactPointData
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
from .base import BusinessLogicEventData, BusinessLogicEvent
|
|
2
|
+
from .event_types import EventType
|
|
3
|
+
from enum import StrEnum
|
|
4
|
+
|
|
5
|
+
class NewChatData(BusinessLogicEventData):
|
|
6
|
+
is_inbound : bool
|
|
7
|
+
|
|
8
|
+
class NewChatEvent(BusinessLogicEvent):
|
|
9
|
+
"""Used for client related events, such as a new chat, a touchpoint, etc."""
|
|
10
|
+
type: EventType = EventType.NEW_CHAT
|
|
11
|
+
data: NewChatData
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from .base import BusinessLogicEventData, BusinessLogicEvent
|
|
2
|
+
from .event_types import EventType
|
|
3
|
+
from enum import StrEnum
|
|
4
|
+
|
|
5
|
+
class QualityScore(StrEnum):
|
|
6
|
+
BAD = "bad"
|
|
7
|
+
GOOD = "good"
|
|
8
|
+
NEUTRAL = "neutral"
|
|
9
|
+
|
|
10
|
+
class QualityScoringData(BusinessLogicEventData):
|
|
11
|
+
score : QualityScore
|
|
12
|
+
|
|
13
|
+
class QualityScoringEvent(BusinessLogicEvent):
|
|
14
|
+
"""Used for client related events, such as a new chat, a touchpoint, etc."""
|
|
15
|
+
type: EventType = EventType.QUALITY_SCORING
|
|
16
|
+
data: QualityScoringData
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from .base import BusinessLogicEventData, BusinessLogicEvent
|
|
2
|
+
from .event_types import EventType
|
|
3
|
+
from enum import StrEnum
|
|
4
|
+
|
|
5
|
+
class SaleSubtype(StrEnum):
|
|
6
|
+
CREATED = "created"
|
|
7
|
+
UPDATED = "updated"
|
|
8
|
+
DELETED = "deleted"
|
|
9
|
+
|
|
10
|
+
class SaleData(BusinessLogicEventData):
|
|
11
|
+
sale_id: str
|
|
12
|
+
|
|
13
|
+
class SaleEvent(BusinessLogicEvent):
|
|
14
|
+
"""Used for client related events, such as a new chat, a touchpoint, etc."""
|
|
15
|
+
type: EventType = EventType.SALE
|
|
16
|
+
data: SaleData
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
from .base import BusinessLogicEventData, BusinessLogicEvent
|
|
2
|
+
from .event_types import EventType
|
|
3
|
+
from enum import StrEnum
|
|
4
|
+
|
|
5
|
+
class TemplateSubtype(StrEnum):
|
|
6
|
+
WAITING = "waiting"
|
|
7
|
+
SENT = "sent"
|
|
8
|
+
DELIVERED = "delivered"
|
|
9
|
+
FAILED = "failed"
|
|
10
|
+
READ = "read"
|
|
11
|
+
|
|
12
|
+
class TemplateData(BusinessLogicEventData):
|
|
13
|
+
message_id: str
|
|
14
|
+
template_name: str
|
|
15
|
+
|
|
16
|
+
class TemplateEvent(BusinessLogicEvent):
|
|
17
|
+
"""Used for client related events, such as a new chat, a touchpoint, etc."""
|
|
18
|
+
type: EventType = EventType.TEMPLATE
|
|
19
|
+
data: TemplateData
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from typing import Union, TypeAlias
|
|
2
|
+
from .audio import AudioMessage
|
|
3
|
+
from .document import DocumentMessage
|
|
4
|
+
from .image import ImageMessage
|
|
5
|
+
from .location import LocationMessage
|
|
6
|
+
from .sticker import StickerMessage
|
|
7
|
+
from .text import TextMessage
|
|
8
|
+
from .video import VideoMessage
|
|
9
|
+
from .unsupported import UnsupportedMessage
|
|
10
|
+
from .reaction import ReactionMessage
|
|
11
|
+
from .central_notification import CentralNotification
|
|
12
|
+
from .contact import ContactMessage
|
|
13
|
+
from .base import ChattyMessageJson
|
|
14
|
+
# from .button import ButtonMessage
|
|
15
|
+
|
|
16
|
+
ChattyMessage : TypeAlias = Union[AudioMessage, DocumentMessage, ImageMessage, LocationMessage, StickerMessage, TextMessage, VideoMessage, UnsupportedMessage, ReactionMessage, CentralNotification, ContactMessage]
|
|
17
|
+
ChattyMediaMessage : TypeAlias = Union[AudioMessage, ImageMessage, VideoMessage, StickerMessage, DocumentMessage]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .chatty_message_json import ChattyMessageJson
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
from pydantic import BaseModel, Field
|
|
2
|
+
from typing import Optional, Dict, Any
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
from ....utils.types.message_types import MessageType, MessageSubtype
|
|
5
|
+
from ....utils.types.message_status_types import Status
|
|
6
|
+
|
|
7
|
+
class Content(BaseModel):
|
|
8
|
+
pass
|
|
9
|
+
|
|
10
|
+
class ChattyMessageJson(BaseModel):
|
|
11
|
+
"""This is the database message model"""
|
|
12
|
+
id: str
|
|
13
|
+
created_at: datetime
|
|
14
|
+
updated_at: datetime
|
|
15
|
+
type: MessageType
|
|
16
|
+
status: Status
|
|
17
|
+
is_incoming_message: bool
|
|
18
|
+
content: Dict[str, Any]
|
|
19
|
+
sent_by: Optional[str] = Field(default=None)
|
|
20
|
+
referral: Optional[Dict] = Field(default=None)
|
|
21
|
+
context: Optional[Dict] = Field(default=None)
|
|
22
|
+
subtype: Optional[str] = Field(default="")
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
from pydantic import BaseModel, Field, field_validator, ValidationInfo
|
|
2
|
+
from datetime import datetime, timezone
|
|
3
|
+
from zoneinfo import ZoneInfo, ZoneInfoNotFoundError
|
|
4
|
+
from typing import Dict, Any, Optional
|
|
5
|
+
|
|
6
|
+
from bson import ObjectId
|
|
7
|
+
from ....utils import MessageType, Status, MessageSubtype
|
|
8
|
+
from ..schema import ChattyContent, ChattyContext, ChattyReferral
|
|
9
|
+
|
|
10
|
+
class Message(BaseModel):
|
|
11
|
+
created_at: datetime
|
|
12
|
+
updated_at: datetime
|
|
13
|
+
type: MessageType
|
|
14
|
+
content: ChattyContent
|
|
15
|
+
status: Status
|
|
16
|
+
is_incoming_message: bool
|
|
17
|
+
id: str = Field(default_factory=lambda: str(ObjectId()),description="Unique identifier for the message. In case it's a central notification or a message request (still not confirmed by external API) we'll use an object id as default. Also known as wamid form Meta")
|
|
18
|
+
sent_by: Optional[str] = Field(description="Email of the agent who sent the message. If it's incoming, it'll be None")
|
|
19
|
+
starred: bool = Field(default=False)
|
|
20
|
+
subtype: MessageSubtype = Field(default_factory=lambda: MessageSubtype.NONE)
|
|
21
|
+
referral: ChattyReferral = Field(default_factory=lambda: ChattyReferral.default())
|
|
22
|
+
context: ChattyContext = Field(default_factory=lambda: ChattyContext.default())
|
|
23
|
+
|
|
24
|
+
def model_dump(self, *args, **kwargs) -> Dict[str, Any]:
|
|
25
|
+
"""
|
|
26
|
+
Dump the message to a dictionary, with the option to convert datetimes to a specific timezone.
|
|
27
|
+
"""
|
|
28
|
+
timezone = kwargs.pop('timezone', None)
|
|
29
|
+
data = super().model_dump(*args, **kwargs)
|
|
30
|
+
if timezone:
|
|
31
|
+
try:
|
|
32
|
+
tz = ZoneInfo(timezone)
|
|
33
|
+
data['created_at'] = self.created_at.astimezone(tz).isoformat()
|
|
34
|
+
data['updated_at'] = self.updated_at.astimezone(tz).isoformat()
|
|
35
|
+
except ZoneInfoNotFoundError:
|
|
36
|
+
raise ValueError(f"Invalid timezone: {timezone}")
|
|
37
|
+
return data
|
|
38
|
+
|
|
39
|
+
class ConfigDict:
|
|
40
|
+
validate_assignment = True
|
|
41
|
+
|
|
42
|
+
@field_validator('sent_by', mode='before')
|
|
43
|
+
def validate_sent_by(cls, v: Optional[str], info: ValidationInfo) -> Optional[str]:
|
|
44
|
+
"""Ensure that the sent_by field is not required for incoming messages, and that it's a valid email for outgoing messages."""
|
|
45
|
+
is_incoming = info.data.get('is_incoming_message', False)
|
|
46
|
+
if is_incoming:
|
|
47
|
+
return None
|
|
48
|
+
if not is_incoming and not v:
|
|
49
|
+
raise ValueError("sent_by is required for outgoing messages")
|
|
50
|
+
return v
|
|
51
|
+
|
|
52
|
+
@field_validator('status', mode='before')
|
|
53
|
+
def validate_status(cls, v: Optional[str], info: ValidationInfo) -> Status:
|
|
54
|
+
"""Status should be validated always, both instantiation and assignment"""
|
|
55
|
+
if isinstance(v, str):
|
|
56
|
+
return Status(v)
|
|
57
|
+
return v
|
|
58
|
+
|
|
59
|
+
@field_validator('subtype', mode='before')
|
|
60
|
+
def validate_subtype(cls, v: Optional[str], info: ValidationInfo) -> MessageSubtype:
|
|
61
|
+
"""If there's no subtype, we'll use the subtype NONE."""
|
|
62
|
+
if v is None or v == "":
|
|
63
|
+
return MessageSubtype.NONE
|
|
64
|
+
return v
|
|
65
|
+
|
|
66
|
+
@field_validator('referral', mode='before')
|
|
67
|
+
def validate_referral(cls, v: Optional[Dict], info: ValidationInfo) -> ChattyReferral:
|
|
68
|
+
"""If there's no referral, we'll use the referral default."""
|
|
69
|
+
if v is None or v == {}:
|
|
70
|
+
return ChattyReferral.default()
|
|
71
|
+
return v
|
|
72
|
+
|
|
73
|
+
@field_validator('context', mode='before')
|
|
74
|
+
def validate_context(cls, v: Optional[Dict], info: ValidationInfo) -> ChattyContext:
|
|
75
|
+
"""If there's no context, we'll use the context default."""
|
|
76
|
+
if v is None or v == {}:
|
|
77
|
+
return ChattyContext.default()
|
|
78
|
+
return v
|
|
79
|
+
|
|
80
|
+
@field_validator('context', mode='after')
|
|
81
|
+
def validate_context_based_on_subtype(cls, v: ChattyContext, info: ValidationInfo) -> ChattyContext:
|
|
82
|
+
"""We'll validate the context based on the subtype.
|
|
83
|
+
And if there's no context, we'll use the context default."""
|
|
84
|
+
subtype = info.data.get('subtype')
|
|
85
|
+
if subtype == MessageSubtype.TEMPLATE:
|
|
86
|
+
if v.template_name is None:
|
|
87
|
+
raise ValueError("template_name is required for template messages")
|
|
88
|
+
elif subtype == MessageSubtype.CHATTY_RESPONSE:
|
|
89
|
+
if v.response_id is None:
|
|
90
|
+
raise ValueError("response_id is required for chatty_response messages")
|
|
91
|
+
return v
|
|
92
|
+
|
|
93
|
+
@field_validator('created_at', 'updated_at')
|
|
94
|
+
def ensure_utc(cls, v):
|
|
95
|
+
if isinstance(v, datetime):
|
|
96
|
+
return v.replace(tzinfo=timezone.utc) if v.tzinfo is None else v.astimezone(timezone.utc)
|
|
97
|
+
raise ValueError('must be a datetime')
|
|
98
|
+
|
|
99
|
+
def _update_status(self, new_status: Status):
|
|
100
|
+
self.status = new_status
|
|
101
|
+
self.updated_at = datetime.now(timezone.utc)
|
|
102
|
+
|
|
103
|
+
def mark_as_read(self):
|
|
104
|
+
"""Mark the message as read if not already failed."""
|
|
105
|
+
self._update_status(Status.READ)
|
|
106
|
+
|
|
107
|
+
def mark_as_delivered(self):
|
|
108
|
+
"""Mark the message as delivered if it was sent."""
|
|
109
|
+
self._update_status(Status.DELIVERED)
|
|
110
|
+
|
|
111
|
+
def mark_as_failed(self):
|
|
112
|
+
"""Mark the message as failed."""
|
|
113
|
+
self._update_status(Status.FAILED)
|
|
114
|
+
|
|
115
|
+
def mark_as_sent(self):
|
|
116
|
+
"""Mark the message as sent."""
|
|
117
|
+
self._update_status(Status.SENT)
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
from typing import TypeAlias, Union
|
|
2
|
+
from .chatty_content.content_image import ChattyContentImage
|
|
3
|
+
from .chatty_content.content_text import ChattyContentText
|
|
4
|
+
from .chatty_content.content_video import ChattyContentVideo
|
|
5
|
+
from .chatty_content.content_audio import ChattyContentAudio
|
|
6
|
+
from .chatty_content.content_reaction import ChattyContentReaction
|
|
7
|
+
from .chatty_content.content_location import ChattyContentLocation
|
|
8
|
+
from .chatty_content.content_contacts import ChattyContentContacts
|
|
9
|
+
from .chatty_content.content_document import ChattyContentDocument
|
|
10
|
+
from .chatty_content.content_sticker import ChattyContentSticker
|
|
11
|
+
from .chatty_content.content_central import ChattyContentCentral
|
|
12
|
+
|
|
13
|
+
from .chatty_context.chatty_context import ChattyContext
|
|
14
|
+
from .chatty_referal.chatty_referal import ChattyReferral
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
ChattyContent : TypeAlias = Union[ChattyContentImage, ChattyContentText, ChattyContentVideo, ChattyContentAudio, ChattyContentReaction, ChattyContentLocation, ChattyContentContacts, ChattyContentDocument, ChattyContentSticker, ChattyContentCentral]
|
|
18
|
+
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from pydantic import BaseModel
|
|
2
|
+
from typing import Dict, Any, List, Optional
|
|
3
|
+
|
|
4
|
+
class ChattyContentContacts(BaseModel):
|
|
5
|
+
full_name: str #Meta Formatted name
|
|
6
|
+
phone_number: str #Meta waid
|
|
7
|
+
name_details: Optional[Dict[str, Any]] = None
|
|
8
|
+
phones: Optional[List[Dict[str, Any]]] = None
|
|
9
|
+
addresses: Optional[List[Dict[str, Any]]] = None
|
|
10
|
+
birthday: Optional[str] = None
|
|
11
|
+
emails: Optional[List[Dict[str, Any]]] = None
|
|
12
|
+
org: Optional[Dict[str, Any]] = None
|
|
13
|
+
urls: Optional[List[Dict[str, Any]]] = None
|
|
14
|
+
|
|
15
|
+
def model_dump(self) -> Dict[str, Any]:
|
|
16
|
+
data = super().model_dump(exclude_none=True)
|
|
17
|
+
return data
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
from pydantic import BaseModel, Field
|
|
2
|
+
from typing import Optional
|
|
3
|
+
class ChattyContentMedia(BaseModel):
|
|
4
|
+
id: Optional[str] = Field(description="Unique identifier for the image. Also known as media_id")
|
|
5
|
+
url: str = Field(description="URL of the media from S3")
|
|
6
|
+
caption: str = Field(default="", description="Caption of the media that goes as a text below the media")
|
|
7
|
+
mime_type: str
|
|
8
|
+
sha256: str
|
|
File without changes
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from pydantic import BaseModel
|
|
3
|
+
from typing import Optional
|
|
4
|
+
|
|
5
|
+
from ....meta_message_model.meta_message_json import MetaContext
|
|
6
|
+
|
|
7
|
+
class ChattyContext(BaseModel):
|
|
8
|
+
message_id: str
|
|
9
|
+
template_name: Optional[str] = None
|
|
10
|
+
response_id: Optional[str] = None
|
|
11
|
+
|
|
12
|
+
def model_dump(self, *args, **kwargs):
|
|
13
|
+
kwargs['exclude_unset'] = True
|
|
14
|
+
return super().model_dump(*args, **kwargs)
|
|
15
|
+
|
|
16
|
+
@classmethod
|
|
17
|
+
def from_meta(cls, meta_context: MetaContext) -> ChattyContext:
|
|
18
|
+
return cls(message_id=meta_context.id)
|
|
19
|
+
|
|
20
|
+
@classmethod
|
|
21
|
+
def default(cls) -> ChattyContext:
|
|
22
|
+
return cls(message_id="")
|
|
File without changes
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from typing import Optional, TYPE_CHECKING
|
|
3
|
+
|
|
4
|
+
from pydantic import BaseModel
|
|
5
|
+
|
|
6
|
+
if TYPE_CHECKING:
|
|
7
|
+
from ....meta_message_model.meta_message_json import MetaReferral
|
|
8
|
+
|
|
9
|
+
class ChattyReferral(BaseModel):
|
|
10
|
+
source_url: str
|
|
11
|
+
source_id: str
|
|
12
|
+
source_type: str
|
|
13
|
+
headline: Optional[str] = None
|
|
14
|
+
body: Optional[str] = None
|
|
15
|
+
media_type: Optional[str] = None
|
|
16
|
+
image_url: Optional[str] = None
|
|
17
|
+
video_url: Optional[str] = None
|
|
18
|
+
thumbnail_url: Optional[str] = None
|
|
19
|
+
ctwa_clid: Optional[str] = None
|
|
20
|
+
|
|
21
|
+
@property
|
|
22
|
+
def is_default(self) -> bool:
|
|
23
|
+
return self.source_url == "" and self.source_id == "" and self.source_type == ""
|
|
24
|
+
|
|
25
|
+
@classmethod
|
|
26
|
+
def from_meta(cls, meta_referral: MetaReferral) -> ChattyReferral:
|
|
27
|
+
if meta_referral.context is None:
|
|
28
|
+
return cls.default()
|
|
29
|
+
return cls(**meta_referral.model_dump())
|
|
30
|
+
|
|
31
|
+
@classmethod
|
|
32
|
+
def default(cls) -> ChattyReferral:
|
|
33
|
+
return cls(
|
|
34
|
+
source_url="",
|
|
35
|
+
source_id="",
|
|
36
|
+
source_type=""
|
|
37
|
+
)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .message_request import MessageRequest
|