chatgraph 0.3.0__py3-none-any.whl → 0.3.4__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.

Potentially problematic release.


This version of chatgraph might be problematic. Click here for more details.

@@ -1,212 +1,108 @@
1
- from ..gRPC.gRPCCall import WhatsappServiceClient, UserStateServiceClient
1
+ from typing import Optional, Union
2
2
 
3
- from dataclasses import dataclass
4
- from typing import Optional
5
- import json
3
+ messageTypes = Union[str, float, int]
4
+ MessageTypes = (str, float, int)
6
5
 
7
- @dataclass
8
- class UserState:
6
+ class Message:
9
7
  """
10
- Representa o estado de um usuário.
8
+ Representa uma mensagem enviada ou recebida pelo chatbot.
11
9
 
12
10
  Atributos:
13
- customer_id (str): O ID do cliente.
14
- menu (str): O menu atual.
15
- lst_update (str): A última atualização do menu.
16
- obs (dict): Observações adicionais sobre o estado do usuário.
11
+ message (str): O conteúdo textual da mensagem.
12
+ absolute_text (bool): Se True, o texto não será modificado.
17
13
  """
18
- customer_id: str
19
- menu: str
20
- route: str
21
- lst_update: str
22
- obs: Optional[dict] = None
23
-
24
-
25
- @dataclass
26
- class Element:
27
- """
28
- Representa um elemento de uma lista de opções.
29
14
 
30
- Atributos:
31
- title (str): O título do elemento.
32
- description (str): A descrição do elemento.
33
- """
34
- title: str
35
- description: Optional[str] = None
36
-
37
- class UserCall:
38
- """
39
- Representa uma mensagem recebida ou enviada pelo chatbot.
40
-
41
- Atributos:
42
- type (str): O tipo da mensagem (por exemplo, texto, imagem, etc.).
43
- text (str): O conteúdo textual da mensagem.
44
- UserState (UserState): O estado do usuário.
45
- channel (str): O canal pelo qual a mensagem foi enviada ou recebida (por exemplo, WhatsApp, SMS, etc.).
46
- customer_phone (str): O número de telefone do cliente.
47
- company_phone (str): O número de telefone da empresa que está enviando ou recebendo a mensagem.
48
- status (Optional[str]): O status da mensagem (por exemplo, enviada, recebida, lida, etc.). Este campo é opcional.
49
- """
50
15
  def __init__(
51
- self,
52
- type: str,
53
- text: str,
54
- user_state: UserState,
55
- channel: str,
56
- customer_phone: str,
57
- company_phone: str,
58
- grpc_uri: str,
59
- status: Optional[str] = None,
60
- ) -> None:
16
+ self,
17
+ text:str,
18
+ absolute_text: bool = False,
19
+ ) -> None:
20
+ self.absolute_text = absolute_text
61
21
 
62
- self.type = type
22
+ if not absolute_text:
23
+ text = text.replace('\t', '')
24
+
63
25
  self.text = text
64
- self.__user_state = user_state
65
- self.channel = channel
66
- self.customer_phone = customer_phone
67
- self.company_phone = company_phone
68
- self.status = status
69
-
70
- self.grpc_uri = grpc_uri
71
-
72
- self.__wpp_server_client = WhatsappServiceClient(self.grpc_uri)
73
- self.__user_state_client = UserStateServiceClient(self.grpc_uri)
74
26
 
75
- def send_text(self, text:str) -> None:
76
-
77
- response = self.__wpp_server_client.send_text(
78
- {
79
- "hook_id": self.company_phone,
80
- "enterprise_id": self.customer_phone,
81
- "unique_customer_id": self.__user_state.customer_id,
82
- "message_text": text
83
- }
84
- )
85
-
86
- if not response.status:
87
- raise ValueError("Erro ao enviar mensagem de texto.")
27
+ class Button:
28
+ """
29
+ Representa uma lista rápida de botões.
88
30
 
89
- def send_button(
31
+ Atributos:
32
+ text (str): O texto da mensagem.
33
+ buttons (list[str]): A lista de botões.
34
+ title (str): O título da mensagem.
35
+ caption (str): A legenda da mensagem.
36
+ absolute_text (bool): Se True, o texto não será modificado.
37
+
38
+ Limitações:
39
+ O número máximo de botões é 3.
40
+ O texto do botão deve ter no máximo 20 caracteres.
41
+ """
42
+ def __init__(
90
43
  self,
91
44
  text:str,
92
- buttons:list,
93
- title: str|None = None,
94
- caption: str|None = None,
45
+ buttons: list[str],
46
+ title: Optional[str] = None,
47
+ caption: Optional[str] = None,
48
+ absolute_text: bool = False,
95
49
  ) -> None:
96
- if len(buttons) > 3:
97
- raise ValueError("O número máximo de botões é 3.")
50
+ self.absolute_text = absolute_text
98
51
 
99
- response = self.__wpp_server_client.send_button(
100
- {
101
- "hook_id": self.company_phone,
102
- "enterprise_id": self.customer_phone,
103
- "unique_customer_id": self.__user_state.customer_id,
104
- "message_text": text,
105
- "button_title": title,
106
- "message_caption": caption,
107
- "message_title": title,
108
- "options": [{"title": b} for b in buttons],
109
- }
110
- )
111
-
112
- if not response.status:
113
- raise ValueError("Erro ao enviar mensagem de botões.")
114
-
115
- def send_list(
116
- self,
117
- text:str,
118
- title: str|None = None,
119
- button_title: str|None = None,
120
- element_list: list[Element] = None,
121
- caption: str|None = None,
122
- ) -> None:
52
+ if not absolute_text:
53
+ text = text.replace('\t', '')
123
54
 
124
- if len(element_list) > 20:
125
- raise ValueError("O número máximo de elementos é 20.")
55
+ assert len(buttons) <= 3, "O número máximo de botões é 3."
126
56
 
127
- response = self.__wpp_server_client.send_list(
128
- {
129
- "hook_id": self.company_phone,
130
- "enterprise_id": self.customer_phone,
131
- "unique_customer_id": self.__user_state.customer_id,
132
- "message_text": text,
133
- "button_title": button_title,
134
- "message_caption": caption,
135
- "message_title": title,
136
- "options": [{"title": e.title, "description": e.description} for e in element_list],
137
- }
138
- )
57
+ for button in buttons:
58
+ assert len(button) <= 20, "O texto do botão deve ter no máximo 20 caracteres."
59
+
60
+ self.text = text
61
+ self.buttons = buttons
62
+ self.title = title
63
+ self.caption = caption
139
64
 
140
- if not response.status:
141
- raise ValueError("Erro ao enviar mensagem de lista.")
65
+ class ListElements:
66
+ """
67
+ Representa uma lista de elementos.
142
68
 
143
- def delete_user_state(self) -> None:
144
- response = self.__user_state_client.delete_user_state(self.__user_state.customer_id)
145
-
146
- if not response.status:
147
- raise ValueError("Erro ao deletar estado do usuário.")
148
-
149
- def update_user_state(
69
+ atributos:
70
+ text (str): O texto da mensagem.
71
+ title (str): O título da mensagem.
72
+ button_title (str): O título do botão.
73
+ elements (list[dict]): A lista de elementos.
74
+ caption (str): A legenda da mensagem.
75
+ absolute_text (bool): Se True, o texto não será modificado.
76
+
77
+ Limitações:
78
+ O número máximo de elementos é 10.
79
+ O título do elemento deve ter no máximo 24 caracteres.
80
+ A descrição do elemento deve ter no máximo 72 caracteres.
81
+ """
82
+ def __init__(
150
83
  self,
151
- menu: str,
152
- route: str,
153
- obs: dict,
84
+ text:str,
85
+ title: Optional[str] = None,
86
+ button_title: Optional[str] = None,
87
+ elements: list[dict] = None,
88
+ caption: Optional[str] = None,
89
+ absolute_text: bool = False,
154
90
  ) -> None:
91
+ self.absolute_text = absolute_text
155
92
 
156
- response = self.__user_state_client.update_user_state({
157
- "user_id": self.__user_state.customer_id,
158
- "menu_id": menu,
159
- "route": route,
160
- "obs": json.dumps(obs),
161
- })
162
-
163
- if not response.status:
164
- raise ValueError("Erro ao atualizar estado do usuário.")
165
-
166
- self.__user_state.menu = menu
167
- self.__user_state.route = route
168
- self.__user_state.obs = obs
169
-
170
- @property
171
- def menu(self):
172
- return self.__user_state.menu
173
-
174
- @property
175
- def route(self):
176
- return self.__user_state.route
177
-
178
- @property
179
- def obs(self):
180
- return self.__user_state.obs
181
-
182
- @property
183
- def customer_id(self):
184
- return self.__user_state.customer_id
185
-
186
- @menu.setter
187
- def menu(self, menu):
93
+ if not absolute_text:
94
+ text = text.replace('\t', '')
188
95
 
189
- self.update_user_state(
190
- menu,
191
- self.__user_state.route,
192
- self.__user_state.obs
193
- )
194
-
195
- @route.setter
196
- def route(self, route):
96
+ assert len(elements) <= 10, "O número máximo de elementos é 10."
197
97
 
198
- self.update_user_state(
199
- self.__user_state.menu,
200
- route,
201
- self.__user_state.obs
202
- )
203
-
204
- @obs.setter
205
- def obs(self, obs):
98
+ for key, value in elements.items():
99
+ assert len(key) <= 24, "O título do elemento deve ter no máximo 24 caracteres."
100
+ assert len(value) <= 72, "A descrição do elemento deve ter no máximo 72 caracteres."
206
101
 
207
- self.update_user_state(
208
- self.__user_state.menu,
209
- self.__user_state.route,
210
- obs
211
- )
212
-
102
+ self.text = text
103
+ self.title = title
104
+ self.button_title = button_title
105
+ self.elements = elements
106
+ self.caption = caption
107
+
108
+
@@ -0,0 +1,265 @@
1
+ from ..gRPC.gRPCCall import WhatsappServiceClient, UserStateServiceClient
2
+ from .message_types import Message, Button, ListElements, messageTypes, MessageTypes
3
+ from dataclasses import dataclass
4
+ from typing import Optional
5
+ import json
6
+
7
+ @dataclass
8
+ class UserState:
9
+ """
10
+ Representa o estado de um usuário.
11
+
12
+ Atributos:
13
+ customer_id (str): O ID do cliente.
14
+ menu (str): O menu atual.
15
+ lst_update (str): A última atualização do menu.
16
+ obs (dict): Observações adicionais sobre o estado do usuário.
17
+ """
18
+ customer_id: str
19
+ menu: str
20
+ route: str
21
+ lst_update: str
22
+ obs: Optional[dict] = None
23
+
24
+
25
+ class UserCall:
26
+ """
27
+ Representa uma mensagem recebida ou enviada pelo chatbot.
28
+
29
+ Atributos:
30
+ type (str): O tipo da mensagem (por exemplo, texto, imagem, etc.).
31
+ text (str): O conteúdo textual da mensagem.
32
+ UserState (UserState): O estado do usuário.
33
+ channel (str): O canal pelo qual a mensagem foi enviada ou recebida (por exemplo, WhatsApp, SMS, etc.).
34
+ customer_phone (str): O número de telefone do cliente.
35
+ company_phone (str): O número de telefone da empresa que está enviando ou recebendo a mensagem.
36
+ status (Optional[str]): O status da mensagem (por exemplo, enviada, recebida, lida, etc.). Este campo é opcional.
37
+ """
38
+ def __init__(
39
+ self,
40
+ type: str,
41
+ text: str,
42
+ user_state: UserState,
43
+ channel: str,
44
+ customer_phone: str,
45
+ company_phone: str,
46
+ grpc_uri: str,
47
+ status: Optional[str] = None,
48
+ ) -> None:
49
+
50
+ self.type = type
51
+ self.text = text
52
+ self.__user_state = user_state
53
+ self.channel = channel
54
+ self.customer_phone = customer_phone
55
+ self.company_phone = company_phone
56
+ self.status = status
57
+
58
+ self.grpc_uri = grpc_uri
59
+
60
+ self.__wpp_server_client = WhatsappServiceClient(self.grpc_uri)
61
+ self.__user_state_client = UserStateServiceClient(self.grpc_uri)
62
+
63
+ def send(self, message: messageTypes|Message|Button|ListElements) -> None:
64
+ """
65
+ Envia uma mensagem ao cliente.
66
+
67
+ Args:
68
+ message (Message|Button|ListElements): A mensagem a ser enviada.
69
+ """
70
+ if isinstance(message, MessageTypes):
71
+ message = Message(message)
72
+
73
+ if isinstance(message, Message):
74
+ self.__send_text(message.text, message.absolute_text)
75
+
76
+ elif isinstance(message, Button):
77
+ self.__send_button(
78
+ message.text,
79
+ message.buttons,
80
+ message.title,
81
+ message.caption
82
+ )
83
+
84
+ elif isinstance(message, ListElements):
85
+ self.__send_list(
86
+ message.text,
87
+ message.title,
88
+ message.button_title,
89
+ message.element_list,
90
+ message.caption
91
+ )
92
+ else:
93
+ raise ValueError("Tipo de mensagem inválido.")
94
+
95
+ def __send_text(self, text:str, abs_text:bool=False) -> None:
96
+ if not abs_text:
97
+ text = text.replace('\t', '')
98
+
99
+ response = self.__wpp_server_client.send_text(
100
+ {
101
+ "hook_id": self.company_phone,
102
+ "enterprise_id": self.customer_phone,
103
+ "unique_customer_id": self.__user_state.customer_id,
104
+ "message_text": text,
105
+ "platform": self.channel,
106
+ }
107
+ )
108
+
109
+ if not response.status:
110
+ raise ValueError("Erro ao enviar mensagem de texto.")
111
+
112
+ def __send_button(
113
+ self,
114
+ text:str,
115
+ buttons:list,
116
+ title: str|None = None,
117
+ caption: str|None = None,
118
+ ) -> None:
119
+ if len(buttons) > 3:
120
+ raise ValueError("O número máximo de botões é 3.")
121
+
122
+ response = self.__wpp_server_client.send_button(
123
+ {
124
+ "hook_id": self.company_phone,
125
+ "enterprise_id": self.customer_phone,
126
+ "unique_customer_id": self.__user_state.customer_id,
127
+ "message_text": text,
128
+ "button_title": title,
129
+ "message_caption": caption,
130
+ "message_title": title,
131
+ "options": [{"title": b} for b in buttons],
132
+ }
133
+ )
134
+
135
+ if not response.status:
136
+ raise ValueError("Erro ao enviar mensagem de botões.")
137
+
138
+ def __send_list(
139
+ self,
140
+ text:str,
141
+ title: str|None = None,
142
+ button_title: str|None = None,
143
+ element_list: list[dict] = None,
144
+ caption: str|None = None,
145
+ ) -> None:
146
+
147
+ if len(element_list) > 20:
148
+ raise ValueError("O número máximo de elementos é 20.")
149
+
150
+ response = self.__wpp_server_client.send_list(
151
+ {
152
+ "hook_id": self.company_phone,
153
+ "enterprise_id": self.customer_phone,
154
+ "unique_customer_id": self.__user_state.customer_id,
155
+ "message_text": text,
156
+ "button_title": button_title,
157
+ "message_caption": caption,
158
+ "message_title": title,
159
+ "options": [{"title": k, "description": v} for k,v in element_list],
160
+ }
161
+ )
162
+
163
+ if not response.status:
164
+ raise ValueError("Erro ao enviar mensagem de lista.")
165
+
166
+ def transfer_to_human(self, message:str, campaign_name:str) -> None:
167
+ response = self.__wpp_server_client.transfer_to_human(
168
+ {
169
+ "hook_id": self.company_phone,
170
+ "enterprise_id": self.customer_phone,
171
+ "unique_customer_id": self.__user_state.customer_id,
172
+ "message_text": message,
173
+ "platform": self.channel,
174
+ campaign_name: campaign_name,
175
+ }
176
+ )
177
+
178
+ if not response.status:
179
+ raise ValueError("Erro ao transferir chat para humano.")
180
+
181
+ def end_chat(self, message:str, campaign_name:str) -> None:
182
+ response = self.__wpp_server_client.end_chat(
183
+ {
184
+ "hook_id": self.company_phone,
185
+ "enterprise_id": self.customer_phone,
186
+ "unique_customer_id": self.__user_state.customer_id,
187
+ "message_text": message,
188
+ "platform": self.channel,
189
+ campaign_name: campaign_name,
190
+ }
191
+ )
192
+
193
+ if not response.status:
194
+ raise ValueError("Erro ao encerrar chat.")
195
+
196
+ def delete_user_state(self) -> None:
197
+ response = self.__user_state_client.delete_user_state(self.__user_state.customer_id)
198
+
199
+ if not response.status:
200
+ raise ValueError("Erro ao deletar estado do usuário.")
201
+
202
+ def update_user_state(
203
+ self,
204
+ menu: str,
205
+ route: str,
206
+ obs: dict,
207
+ ) -> None:
208
+
209
+ response = self.__user_state_client.update_user_state({
210
+ "user_id": self.__user_state.customer_id,
211
+ "menu_id": menu,
212
+ "route": route,
213
+ "obs": json.dumps(obs),
214
+ })
215
+
216
+ if not response.status:
217
+ raise ValueError("Erro ao atualizar estado do usuário.")
218
+
219
+ self.__user_state.menu = menu
220
+ self.__user_state.route = route
221
+ self.__user_state.obs = obs
222
+
223
+ @property
224
+ def menu(self):
225
+ return self.__user_state.menu
226
+
227
+ @property
228
+ def route(self):
229
+ return self.__user_state.route
230
+
231
+ @property
232
+ def obs(self):
233
+ return self.__user_state.obs
234
+
235
+ @property
236
+ def customer_id(self):
237
+ return self.__user_state.customer_id
238
+
239
+ @menu.setter
240
+ def menu(self, menu):
241
+
242
+ self.update_user_state(
243
+ menu,
244
+ self.__user_state.route,
245
+ self.__user_state.obs
246
+ )
247
+
248
+ @route.setter
249
+ def route(self, route):
250
+
251
+ self.update_user_state(
252
+ self.__user_state.menu,
253
+ route,
254
+ self.__user_state.obs
255
+ )
256
+
257
+ @obs.setter
258
+ def obs(self, obs):
259
+
260
+ self.update_user_state(
261
+ self.__user_state.menu,
262
+ self.__user_state.route,
263
+ obs
264
+ )
265
+
chatgraph/types/route.py CHANGED
@@ -23,6 +23,13 @@ class Route:
23
23
  self.routes = routes
24
24
  self.separator = separator
25
25
 
26
+ @property
27
+ def previous(self)->str:
28
+ """
29
+ Retorna a rota anterior a atual do usuário
30
+ """
31
+ return self.get_previous()
32
+
26
33
  def get_previous(self) -> str:
27
34
  """
28
35
  Retorna o caminho anterior ao caminho atual.
@@ -39,7 +46,7 @@ class Route:
39
46
  previous_route = self.separator.join(self.current.split(self.separator)[:-1])
40
47
  return previous_route
41
48
 
42
- def get_next(self, next_part: str) -> str:
49
+ def get_next(self, next_part: str) -> 'Route':
43
50
  """
44
51
  Monta e retorna o próximo caminho com base na parte fornecida.
45
52
 
@@ -50,13 +57,14 @@ class Route:
50
57
  RouteError: Se a próxima rota montada não estiver na lista de rotas disponíveis.
51
58
 
52
59
  Returns:
53
- str: O próximo caminho construído a partir da rota atual e da parte fornecida.
60
+ Route: O próximo caminho montado.
54
61
  """
55
62
  next_part = next_part.strip().lower()
56
63
  next_route = f"{self.current.rstrip(self.separator)}{next_part}"
57
64
  if next_route not in self.routes:
58
65
  raise RouteError(f'Rota não encontrada: {next_route}')
59
- return next_route
66
+
67
+ return Route(next_route, self.routes, self.separator)
60
68
 
61
69
  def __str__(self):
62
70
  """