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.
Files changed (80) hide show
  1. letschatty/__init__.py +2 -0
  2. letschatty/models/__init__.py +4 -0
  3. letschatty/models/company/empresa.py +11 -0
  4. letschatty/models/events/__init__.py +6 -0
  5. letschatty/models/events/base.py +45 -0
  6. letschatty/models/events/contact_point.py +18 -0
  7. letschatty/models/events/event_types.py +11 -0
  8. letschatty/models/events/new_chat.py +11 -0
  9. letschatty/models/events/quality_scoring.py +16 -0
  10. letschatty/models/events/sale.py +16 -0
  11. letschatty/models/events/template.py +19 -0
  12. letschatty/models/messages/__init__.py +2 -0
  13. letschatty/models/messages/chatty_messages/__init__.py +17 -0
  14. letschatty/models/messages/chatty_messages/audio.py +7 -0
  15. letschatty/models/messages/chatty_messages/base/__init__.py +1 -0
  16. letschatty/models/messages/chatty_messages/base/chatty_message_json.py +22 -0
  17. letschatty/models/messages/chatty_messages/base/message_base.py +117 -0
  18. letschatty/models/messages/chatty_messages/button.py +7 -0
  19. letschatty/models/messages/chatty_messages/central_notification.py +8 -0
  20. letschatty/models/messages/chatty_messages/contact.py +7 -0
  21. letschatty/models/messages/chatty_messages/document.py +7 -0
  22. letschatty/models/messages/chatty_messages/image.py +7 -0
  23. letschatty/models/messages/chatty_messages/interactive.py +6 -0
  24. letschatty/models/messages/chatty_messages/location.py +7 -0
  25. letschatty/models/messages/chatty_messages/reaction.py +7 -0
  26. letschatty/models/messages/chatty_messages/schema/__init__.py +18 -0
  27. letschatty/models/messages/chatty_messages/schema/chatty_content/content_audio.py +6 -0
  28. letschatty/models/messages/chatty_messages/schema/chatty_content/content_central.py +5 -0
  29. letschatty/models/messages/chatty_messages/schema/chatty_content/content_contacts.py +21 -0
  30. letschatty/models/messages/chatty_messages/schema/chatty_content/content_document.py +8 -0
  31. letschatty/models/messages/chatty_messages/schema/chatty_content/content_image.py +4 -0
  32. letschatty/models/messages/chatty_messages/schema/chatty_content/content_location.py +5 -0
  33. letschatty/models/messages/chatty_messages/schema/chatty_content/content_media.py +8 -0
  34. letschatty/models/messages/chatty_messages/schema/chatty_content/content_reaction.py +4 -0
  35. letschatty/models/messages/chatty_messages/schema/chatty_content/content_sticker.py +6 -0
  36. letschatty/models/messages/chatty_messages/schema/chatty_content/content_text.py +5 -0
  37. letschatty/models/messages/chatty_messages/schema/chatty_content/content_video.py +5 -0
  38. letschatty/models/messages/chatty_messages/schema/chatty_context/__init__.py +0 -0
  39. letschatty/models/messages/chatty_messages/schema/chatty_context/chatty_context.py +22 -0
  40. letschatty/models/messages/chatty_messages/schema/chatty_referal/__init__.py +0 -0
  41. letschatty/models/messages/chatty_messages/schema/chatty_referal/chatty_referal.py +37 -0
  42. letschatty/models/messages/chatty_messages/sticker.py +7 -0
  43. letschatty/models/messages/chatty_messages/text.py +7 -0
  44. letschatty/models/messages/chatty_messages/unknown.py +6 -0
  45. letschatty/models/messages/chatty_messages/unsupported.py +5 -0
  46. letschatty/models/messages/chatty_messages/video.py +7 -0
  47. letschatty/models/messages/messages_request/__init__.py +1 -0
  48. letschatty/models/messages/messages_request/message_request.py +22 -0
  49. letschatty/models/messages/meta_message_model/meta_base_notification_json.py +64 -0
  50. letschatty/models/messages/meta_message_model/meta_error_json.py +10 -0
  51. letschatty/models/messages/meta_message_model/meta_inexistent_json.py +5 -0
  52. letschatty/models/messages/meta_message_model/meta_message_json.py +142 -0
  53. letschatty/models/messages/meta_message_model/meta_message_types.py +126 -0
  54. letschatty/models/messages/meta_message_model/meta_status_json.py +85 -0
  55. letschatty/models/messages/meta_message_model/meta_unknown_json.py +5 -0
  56. letschatty/models/metrics/__init_.py +5 -0
  57. letschatty/models/metrics/daily_contact_points.py +21 -0
  58. letschatty/models/metrics/daily_new_chats.py +12 -0
  59. letschatty/models/metrics/daily_sent_templates_grouped.py +21 -0
  60. letschatty/models/metrics/sales_roadmap.py +15 -0
  61. letschatty/models/metrics/sent_templates.py +19 -0
  62. letschatty/models/utils/__init__.py +1 -0
  63. letschatty/models/utils/types/__init__.py +8 -0
  64. letschatty/models/utils/types/channel_types.py +5 -0
  65. letschatty/models/utils/types/country.py +20 -0
  66. letschatty/models/utils/types/identifier.py +15 -0
  67. letschatty/models/utils/types/message_status_types.py +8 -0
  68. letschatty/models/utils/types/message_types.py +20 -0
  69. letschatty/models/utils/types/phone_number.py +14 -0
  70. letschatty/models/utils/types/source_types.py +9 -0
  71. letschatty/models/utils/types/typealiases.py +1 -0
  72. letschatty/services/factories/__init__.py +1 -0
  73. letschatty/services/factories/child_chatty_message_factory.py +1 -0
  74. letschatty/services/factories/child_db_message_factory.py +108 -0
  75. letschatty/services/factories/child_request_message.py +97 -0
  76. letschatty/services/factories/parent_message_factory.py +18 -0
  77. letschatty-0.1.44.dist-info/LICENSE +18 -0
  78. letschatty-0.1.44.dist-info/METADATA +37 -0
  79. letschatty-0.1.44.dist-info/RECORD +80 -0
  80. letschatty-0.1.44.dist-info/WHEEL +4 -0
letschatty/__init__.py ADDED
@@ -0,0 +1,2 @@
1
+ from .models import *
2
+ from .services import *
@@ -0,0 +1,4 @@
1
+ from .messages import *
2
+ from .events import *
3
+ from .metrics import *
4
+ from .utils import *
@@ -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,6 @@
1
+ from .event_types import EventType
2
+ from .contact_point import ContactPointEvent
3
+ from .new_chat import NewChatEvent
4
+ from .quality_scoring import QualityScoringEvent
5
+ from .sale import SaleEvent
6
+ from .template import TemplateEvent
@@ -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 enum import StrEnum
2
+
3
+ class EventType(StrEnum):
4
+ CONTACT_POINT = "contact_point"
5
+ NEW_CHAT = "new_chat"
6
+ TEMPLATE = "template"
7
+ QUALITY_SCORING = "quality_scoring"
8
+ SALE = "sale"
9
+
10
+
11
+
@@ -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,2 @@
1
+ from .chatty_messages import *
2
+ from .messages_request import *
@@ -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,7 @@
1
+ from .base.message_base import Message
2
+ from .schema import ChattyContentAudio
3
+ from ...utils.types.message_types import MessageType
4
+
5
+ class AudioMessage(Message):
6
+ type: MessageType = MessageType.AUDIO
7
+ content: ChattyContentAudio
@@ -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,7 @@
1
+ from .base.message_base import Message
2
+ from ...utils.types.message_types import MessageType
3
+
4
+
5
+ class ButtonMessage(Message):
6
+ #TODO: Implementar
7
+ pass
@@ -0,0 +1,8 @@
1
+ from .base.message_base import Message
2
+ from ...utils.types.message_types import MessageType
3
+ from .schema import ChattyContentCentral
4
+
5
+ class CentralNotification(Message):
6
+ type: str = MessageType.CENTRAL
7
+ content: ChattyContentCentral
8
+
@@ -0,0 +1,7 @@
1
+ from .base.message_base import Message
2
+ from ...utils.types.message_types import MessageType
3
+ from .schema import ChattyContentContacts
4
+
5
+ class ContactMessage(Message):
6
+ type: MessageType = MessageType.CONTACT
7
+ content: ChattyContentContacts
@@ -0,0 +1,7 @@
1
+ from .base.message_base import Message
2
+ from ...utils.types.message_types import MessageType
3
+ from .schema import ChattyContentDocument
4
+
5
+ class DocumentMessage(Message):
6
+ type: MessageType = MessageType.DOCUMENT
7
+ content: ChattyContentDocument
@@ -0,0 +1,7 @@
1
+ from .base.message_base import Message
2
+ from ...utils.types.message_types import MessageType
3
+ from .schema import ChattyContentImage
4
+
5
+ class ImageMessage(Message):
6
+ type: MessageType = MessageType.IMAGE
7
+ content: ChattyContentImage
@@ -0,0 +1,6 @@
1
+ from .base.message_base import Message
2
+ from ...utils.types.message_types import MessageType
3
+
4
+ class InteractiveMessage(Message):
5
+ #TODO: Implementar
6
+ pass
@@ -0,0 +1,7 @@
1
+ from .base.message_base import Message
2
+ from ...utils.types.message_types import MessageType
3
+ from .schema import ChattyContentLocation
4
+
5
+ class LocationMessage(Message):
6
+ type: str = MessageType.LOCATION.value
7
+ content: ChattyContentLocation
@@ -0,0 +1,7 @@
1
+ from .base.message_base import Message
2
+ from ...utils.types.message_types import MessageType
3
+ from .schema import ChattyContentReaction
4
+
5
+ class ReactionMessage(Message):
6
+ type: MessageType = MessageType.REACTION
7
+ content: ChattyContentReaction
@@ -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,6 @@
1
+ from pydantic import BaseModel, Field
2
+
3
+ class ChattyContentAudio(BaseModel):
4
+ url: str = Field(description="URL of the media from S3")
5
+ mime_type: str
6
+ sha256: str
@@ -0,0 +1,5 @@
1
+ from pydantic import BaseModel
2
+
3
+ # Soolo se generan DESDE LA BASE DE DATOS
4
+ class ChattyContentCentral(BaseModel):
5
+ body: str
@@ -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 .content_media import ChattyContentMedia
3
+
4
+ class ChattyContentDocument(ChattyContentMedia):
5
+ filename: str = Field(description="Name of the document")
6
+
7
+
8
+
@@ -0,0 +1,4 @@
1
+ from .content_media import ChattyContentMedia
2
+
3
+ class ChattyContentImage(ChattyContentMedia):
4
+ pass
@@ -0,0 +1,5 @@
1
+ from pydantic import BaseModel
2
+
3
+ class ChattyContentLocation(BaseModel):
4
+ latitude: float
5
+ longitude: float
@@ -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
@@ -0,0 +1,4 @@
1
+ from pydantic import BaseModel
2
+
3
+ class ChattyContentReaction(BaseModel):
4
+ emoji: str
@@ -0,0 +1,6 @@
1
+ from pydantic import BaseModel, Field
2
+
3
+ class ChattyContentSticker(BaseModel):
4
+ url: str = Field(description="URL of the media from S3")
5
+ mime_type: str
6
+ sha256: str
@@ -0,0 +1,5 @@
1
+ from pydantic import BaseModel
2
+
3
+ class ChattyContentText(BaseModel):
4
+ body: str
5
+ preview_url: bool = False
@@ -0,0 +1,5 @@
1
+ from .content_media import ChattyContentMedia
2
+
3
+ class ChattyContentVideo(ChattyContentMedia):
4
+ pass
5
+
@@ -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="")
@@ -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,7 @@
1
+ from .base.message_base import Message
2
+ from ...utils.types.message_types import MessageType
3
+ from .schema import ChattyContentSticker
4
+
5
+ class StickerMessage(Message):
6
+ type: MessageType = MessageType.STICKER
7
+ content: ChattyContentSticker
@@ -0,0 +1,7 @@
1
+ from .base.message_base import Message
2
+ from ...utils.types.message_types import MessageType
3
+ from .schema import ChattyContentText
4
+
5
+ class TextMessage(Message):
6
+ type: MessageType = MessageType.TEXT
7
+ content: ChattyContentText
@@ -0,0 +1,6 @@
1
+ from .base.message_base import Message
2
+ from ...utils.types.message_types import MessageType
3
+
4
+ class UnknownMessage(Message):
5
+ #TODO: Implementar
6
+ type: str = MessageType.UNSUPPORTED
@@ -0,0 +1,5 @@
1
+ from .base.message_base import Message
2
+ from ...utils.types.message_types import MessageType
3
+
4
+ class UnsupportedMessage(Message):
5
+ type: str = MessageType.UNSUPPORTED
@@ -0,0 +1,7 @@
1
+ from .base.message_base import Message
2
+ from ...utils.types.message_types import MessageType
3
+ from .schema import ChattyContentVideo
4
+
5
+ class VideoMessage(Message):
6
+ type: MessageType = MessageType.VIDEO
7
+ content: ChattyContentVideo
@@ -0,0 +1 @@
1
+ from .message_request import MessageRequest