chatgraph 0.6.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.
- chatgraph/__init__.py +35 -0
- chatgraph/auth/credentials.py +71 -0
- chatgraph/bot/chatbot_model.py +238 -0
- chatgraph/bot/chatbot_router.py +85 -0
- chatgraph/bot/default_functions.py +24 -0
- chatgraph/cli/__init__.py +187 -0
- chatgraph/error/chatbot_error.py +57 -0
- chatgraph/error/route_error.py +26 -0
- chatgraph/gRPC/gRPCCall.py +189 -0
- chatgraph/messages/message_consumer.py +212 -0
- chatgraph/models/actions.py +138 -0
- chatgraph/models/message.py +350 -0
- chatgraph/models/userstate.py +214 -0
- chatgraph/pb/router.proto +151 -0
- chatgraph/pb/router_pb2.py +79 -0
- chatgraph/pb/router_pb2_grpc.py +902 -0
- chatgraph/services/__init__.py +0 -0
- chatgraph/services/router_http_client.py +451 -0
- chatgraph/types/background_task.py +27 -0
- chatgraph/types/end_types.py +75 -0
- chatgraph/types/route.py +104 -0
- chatgraph/types/usercall.py +229 -0
- chatgraph-0.6.4.dist-info/METADATA +521 -0
- chatgraph-0.6.4.dist-info/RECORD +27 -0
- chatgraph-0.6.4.dist-info/WHEEL +4 -0
- chatgraph-0.6.4.dist-info/entry_points.txt +3 -0
- chatgraph-0.6.4.dist-info/licenses/LICENSE +21 -0
|
File without changes
|
|
@@ -0,0 +1,451 @@
|
|
|
1
|
+
from typing import Any, Dict, Optional
|
|
2
|
+
|
|
3
|
+
import httpx
|
|
4
|
+
|
|
5
|
+
from ..models.userstate import UserState, ChatID
|
|
6
|
+
from ..models.message import Message, File
|
|
7
|
+
from ..models.actions import EndAction
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class RouterHTTPClient:
|
|
11
|
+
"""
|
|
12
|
+
Cliente HTTP para serviços de roteamento de mensagens.
|
|
13
|
+
|
|
14
|
+
Utiliza httpx.AsyncClient para comunicação assíncrona com o backend
|
|
15
|
+
do sistema de chatbot, incluindo envio de mensagens, gerenciamento
|
|
16
|
+
de estado e transferências de chat.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
def __init__(
|
|
20
|
+
self,
|
|
21
|
+
base_url: str,
|
|
22
|
+
username: Optional[str] = None,
|
|
23
|
+
password: Optional[str] = None,
|
|
24
|
+
timeout: float = 30.0,
|
|
25
|
+
):
|
|
26
|
+
"""
|
|
27
|
+
Inicializa o cliente HTTP.
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
base_url: URL base da API (ex: "https://api.example.com")
|
|
31
|
+
username: Nome de usuário para autenticação (opcional)
|
|
32
|
+
password: Senha para autenticação (opcional)
|
|
33
|
+
timeout: Timeout para requisições em segundos (padrão: 30.0)
|
|
34
|
+
"""
|
|
35
|
+
self.base_url = base_url.rstrip('/')
|
|
36
|
+
self.timeout = timeout
|
|
37
|
+
|
|
38
|
+
# Configurar autenticação básica se fornecida
|
|
39
|
+
auth = None
|
|
40
|
+
if username and password:
|
|
41
|
+
auth = httpx.BasicAuth(username, password)
|
|
42
|
+
|
|
43
|
+
# Criar cliente assíncrono
|
|
44
|
+
self._client = httpx.AsyncClient(
|
|
45
|
+
base_url=self.base_url,
|
|
46
|
+
auth=auth,
|
|
47
|
+
timeout=httpx.Timeout(timeout),
|
|
48
|
+
headers={
|
|
49
|
+
'Accept': 'application/json',
|
|
50
|
+
# 'Content-Type': 'application/json',
|
|
51
|
+
},
|
|
52
|
+
verify=False,
|
|
53
|
+
trust_env=True,
|
|
54
|
+
follow_redirects=True,
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
async def close(self):
|
|
58
|
+
"""Fecha a conexão do cliente HTTP."""
|
|
59
|
+
await self._client.aclose()
|
|
60
|
+
|
|
61
|
+
async def __aenter__(self):
|
|
62
|
+
"""Context manager entry."""
|
|
63
|
+
return self
|
|
64
|
+
|
|
65
|
+
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
|
66
|
+
"""Context manager exit."""
|
|
67
|
+
await self.close()
|
|
68
|
+
|
|
69
|
+
# Sessions Methods
|
|
70
|
+
async def get_all_sessions(self) -> list[UserState]:
|
|
71
|
+
"""
|
|
72
|
+
Obtém todas as sessões ativas.
|
|
73
|
+
|
|
74
|
+
Returns:
|
|
75
|
+
Lista de UserState com todas as sessões ativas.
|
|
76
|
+
|
|
77
|
+
Raises:
|
|
78
|
+
Exception: Se houver erro na comunicação.
|
|
79
|
+
"""
|
|
80
|
+
endpoint = '/session/'
|
|
81
|
+
|
|
82
|
+
response = await self._client.get(endpoint)
|
|
83
|
+
response.raise_for_status()
|
|
84
|
+
response_data = response.json()
|
|
85
|
+
status = response_data.get('status')
|
|
86
|
+
message = response_data.get('message')
|
|
87
|
+
sessions_data = response_data.get('data', [])
|
|
88
|
+
|
|
89
|
+
if not status:
|
|
90
|
+
raise Exception(f'Erro ao buscar as Sessões: {message}')
|
|
91
|
+
|
|
92
|
+
sessions = [UserState.from_dict(item) for item in sessions_data]
|
|
93
|
+
return sessions
|
|
94
|
+
|
|
95
|
+
async def get_session_by_chat_id(
|
|
96
|
+
self,
|
|
97
|
+
chat_id: ChatID,
|
|
98
|
+
) -> Optional[UserState]:
|
|
99
|
+
endpoint = '/session/'
|
|
100
|
+
params = {
|
|
101
|
+
'user_id': chat_id.user_id,
|
|
102
|
+
'company_id': chat_id.company_id,
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
response = await self._client.get(endpoint, params=params)
|
|
106
|
+
response.raise_for_status()
|
|
107
|
+
response_data = response.json()
|
|
108
|
+
status = response_data.get('status')
|
|
109
|
+
message = response_data.get('message')
|
|
110
|
+
session_data = response_data.get('data')
|
|
111
|
+
|
|
112
|
+
if not status:
|
|
113
|
+
raise Exception(f'Erro ao buscar a Sessão: {message}')
|
|
114
|
+
|
|
115
|
+
return UserState.from_dict(session_data)
|
|
116
|
+
|
|
117
|
+
async def start_session(self, user_state: UserState) -> Any:
|
|
118
|
+
"""
|
|
119
|
+
Inicia uma nova sessão de chat.
|
|
120
|
+
|
|
121
|
+
Args:
|
|
122
|
+
user_state: Estado inicial do usuário.
|
|
123
|
+
|
|
124
|
+
Returns:
|
|
125
|
+
Objeto de resposta com atributo 'status' indicando sucesso/falha.
|
|
126
|
+
|
|
127
|
+
Raises:
|
|
128
|
+
Exception: Se houver erro na comunicação.
|
|
129
|
+
"""
|
|
130
|
+
endpoint = '/session/start/'
|
|
131
|
+
|
|
132
|
+
response = await self._client.post(
|
|
133
|
+
endpoint,
|
|
134
|
+
json=user_state.to_dict(),
|
|
135
|
+
)
|
|
136
|
+
response.raise_for_status()
|
|
137
|
+
response_data = response.json()
|
|
138
|
+
status = response_data.get('status')
|
|
139
|
+
message = response_data.get('message')
|
|
140
|
+
|
|
141
|
+
if not status:
|
|
142
|
+
raise Exception(f'Erro ao iniciar sessão: {message}')
|
|
143
|
+
|
|
144
|
+
return response_data
|
|
145
|
+
|
|
146
|
+
async def set_session_route(self, chat_id: ChatID, route: str) -> Any:
|
|
147
|
+
"""
|
|
148
|
+
Atualiza a rota da sessão de chat.
|
|
149
|
+
|
|
150
|
+
Args:
|
|
151
|
+
chat_id: Identificador do chat.
|
|
152
|
+
route: Nova rota para a sessão.
|
|
153
|
+
|
|
154
|
+
Returns:
|
|
155
|
+
Objeto de resposta com atributo 'status' indicando sucesso/falha.
|
|
156
|
+
|
|
157
|
+
Raises:
|
|
158
|
+
Exception: Se houver erro na comunicação.
|
|
159
|
+
"""
|
|
160
|
+
endpoint = '/session/route/'
|
|
161
|
+
|
|
162
|
+
payload = {
|
|
163
|
+
'chat_id': chat_id.to_dict(),
|
|
164
|
+
'route': route,
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
response = await self._client.post(
|
|
168
|
+
endpoint,
|
|
169
|
+
json=payload,
|
|
170
|
+
)
|
|
171
|
+
response.raise_for_status()
|
|
172
|
+
response_data = response.json()
|
|
173
|
+
status = response_data.get('status')
|
|
174
|
+
message = response_data.get('message')
|
|
175
|
+
|
|
176
|
+
if not status:
|
|
177
|
+
raise Exception(f'Erro ao atualizar rota da sessão: {message}')
|
|
178
|
+
|
|
179
|
+
return response_data
|
|
180
|
+
|
|
181
|
+
async def update_session_observation(
|
|
182
|
+
self,
|
|
183
|
+
chat_id: ChatID,
|
|
184
|
+
observation: str,
|
|
185
|
+
) -> Any:
|
|
186
|
+
"""
|
|
187
|
+
Atualiza a observação da sessão de chat.
|
|
188
|
+
|
|
189
|
+
Args:
|
|
190
|
+
chat_id: Identificador do chat.
|
|
191
|
+
observation: Nova observação para a sessão.
|
|
192
|
+
|
|
193
|
+
Returns:
|
|
194
|
+
Objeto de resposta com atributo 'status' indicando sucesso/falha.
|
|
195
|
+
|
|
196
|
+
Raises:
|
|
197
|
+
Exception: Se houver erro na comunicação.
|
|
198
|
+
"""
|
|
199
|
+
endpoint = '/session/observation/'
|
|
200
|
+
|
|
201
|
+
payload = {
|
|
202
|
+
'chat_id': chat_id.to_dict(),
|
|
203
|
+
'observation': observation,
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
response = await self._client.post(
|
|
207
|
+
endpoint,
|
|
208
|
+
json=payload,
|
|
209
|
+
)
|
|
210
|
+
response.raise_for_status()
|
|
211
|
+
response_data = response.json()
|
|
212
|
+
status = response_data.get('status')
|
|
213
|
+
message = response_data.get('message')
|
|
214
|
+
|
|
215
|
+
if not status:
|
|
216
|
+
raise Exception(
|
|
217
|
+
f'Erro ao atualizar observação da sessão: {message}'
|
|
218
|
+
)
|
|
219
|
+
|
|
220
|
+
return response_data
|
|
221
|
+
|
|
222
|
+
# Messages Methods
|
|
223
|
+
async def send_message(
|
|
224
|
+
self,
|
|
225
|
+
message_data: Message,
|
|
226
|
+
user_state: UserState,
|
|
227
|
+
) -> Any:
|
|
228
|
+
"""
|
|
229
|
+
Envia uma mensagem de texto ao usuário.
|
|
230
|
+
|
|
231
|
+
Args:
|
|
232
|
+
message_data: Dicionário contendo os dados da mensagem:
|
|
233
|
+
- chat_id: ID do chat (user_id, company_id)
|
|
234
|
+
- type: Tipo da mensagem
|
|
235
|
+
- detail: Conteúdo da mensagem
|
|
236
|
+
|
|
237
|
+
Returns:
|
|
238
|
+
Objeto de resposta com atributo 'status' indicando sucesso/falha.
|
|
239
|
+
|
|
240
|
+
Raises:
|
|
241
|
+
Exception: Se houver erro na comunicação.
|
|
242
|
+
"""
|
|
243
|
+
endpoint = '/messages/send/'
|
|
244
|
+
|
|
245
|
+
payload = {
|
|
246
|
+
'message': message_data.to_dict(),
|
|
247
|
+
'user_state': user_state.to_dict(),
|
|
248
|
+
}
|
|
249
|
+
response = await self._client.post(
|
|
250
|
+
endpoint,
|
|
251
|
+
json=payload,
|
|
252
|
+
)
|
|
253
|
+
response.raise_for_status()
|
|
254
|
+
response_data = response.json()
|
|
255
|
+
status = response_data.get('status')
|
|
256
|
+
message = response_data.get('message')
|
|
257
|
+
|
|
258
|
+
if not status:
|
|
259
|
+
raise Exception(f'Erro ao enviar mensagem: {message}')
|
|
260
|
+
|
|
261
|
+
return response_data
|
|
262
|
+
|
|
263
|
+
# Files Methods
|
|
264
|
+
async def get_file(self, file_id: str) -> File:
|
|
265
|
+
"""
|
|
266
|
+
Obtém um arquivo (imagem) pelo ID.
|
|
267
|
+
|
|
268
|
+
Args:
|
|
269
|
+
file_id: ID único do arquivo.
|
|
270
|
+
|
|
271
|
+
Returns:
|
|
272
|
+
Objeto de resposta com atributos 'status' e 'file_content'.
|
|
273
|
+
|
|
274
|
+
Raises:
|
|
275
|
+
Exception: Se houver erro na comunicação.
|
|
276
|
+
"""
|
|
277
|
+
endpoint = f'/files/{file_id}/'
|
|
278
|
+
|
|
279
|
+
response = await self._client.get(endpoint)
|
|
280
|
+
response.raise_for_status()
|
|
281
|
+
response_data = response.json()
|
|
282
|
+
status = response_data.get('status')
|
|
283
|
+
message = response_data.get('message')
|
|
284
|
+
file_data = response_data.get('data')
|
|
285
|
+
|
|
286
|
+
if not status:
|
|
287
|
+
raise Exception(f'Erro ao buscar arquivo: {message}')
|
|
288
|
+
|
|
289
|
+
return File.from_dict(file_data)
|
|
290
|
+
|
|
291
|
+
async def upload_file(self, file_data: bytes) -> File:
|
|
292
|
+
"""
|
|
293
|
+
Faz upload de um arquivo (imagem) para o servidor.
|
|
294
|
+
|
|
295
|
+
Args:
|
|
296
|
+
file_data: Dicionário contendo os dados do arquivo:
|
|
297
|
+
- file_type: Tipo do arquivo ("file" ou "link")
|
|
298
|
+
- file_content: Bytes do arquivo (se type="file")
|
|
299
|
+
- file_extension: Extensão do arquivo (se type="file")
|
|
300
|
+
- file_url: URL do arquivo (se type="link")
|
|
301
|
+
- expiration: Data de expiração (opcional)
|
|
302
|
+
|
|
303
|
+
Returns:
|
|
304
|
+
Objeto de resposta com atributo 'status' indicando sucesso/falha.
|
|
305
|
+
|
|
306
|
+
Raises:
|
|
307
|
+
Exception: Se houver erro na comunicação.
|
|
308
|
+
"""
|
|
309
|
+
endpoint = '/files/upload/'
|
|
310
|
+
|
|
311
|
+
payload = {
|
|
312
|
+
'content': file_data,
|
|
313
|
+
}
|
|
314
|
+
response = await self._client.post(
|
|
315
|
+
endpoint,
|
|
316
|
+
files=payload,
|
|
317
|
+
)
|
|
318
|
+
response.raise_for_status()
|
|
319
|
+
response_data = response.json()
|
|
320
|
+
status = response_data.get('status')
|
|
321
|
+
message = response_data.get('message')
|
|
322
|
+
response_data = response_data.get('data')
|
|
323
|
+
|
|
324
|
+
if not status:
|
|
325
|
+
raise Exception(f'Erro ao fazer upload do arquivo: {message}')
|
|
326
|
+
|
|
327
|
+
file = File.from_dict(response_data)
|
|
328
|
+
return file
|
|
329
|
+
|
|
330
|
+
async def delete_file(self, file_id: str) -> Any:
|
|
331
|
+
"""
|
|
332
|
+
Deleta um arquivo (imagem) pelo ID.
|
|
333
|
+
|
|
334
|
+
Args:
|
|
335
|
+
file_id: ID único do arquivo.
|
|
336
|
+
|
|
337
|
+
Returns:
|
|
338
|
+
Objeto de resposta com atributo 'status' indicando sucesso/falha.
|
|
339
|
+
|
|
340
|
+
Raises:
|
|
341
|
+
Exception: Se houver erro na comunicação.
|
|
342
|
+
"""
|
|
343
|
+
endpoint = f'/files/{file_id}'
|
|
344
|
+
|
|
345
|
+
response = await self._client.delete(endpoint)
|
|
346
|
+
response.raise_for_status()
|
|
347
|
+
response_data = response.json()
|
|
348
|
+
status = response_data.get('status')
|
|
349
|
+
message = response_data.get('message')
|
|
350
|
+
|
|
351
|
+
if not status:
|
|
352
|
+
raise Exception(f'Erro ao deletar arquivo: {message}')
|
|
353
|
+
|
|
354
|
+
return response_data
|
|
355
|
+
|
|
356
|
+
# EndAction Methods
|
|
357
|
+
async def end_chat(
|
|
358
|
+
self,
|
|
359
|
+
chat_id: ChatID,
|
|
360
|
+
end_action: EndAction,
|
|
361
|
+
origin: str,
|
|
362
|
+
) -> Any:
|
|
363
|
+
"""
|
|
364
|
+
Encerra o atendimento com tabulação.
|
|
365
|
+
|
|
366
|
+
Args:
|
|
367
|
+
end_data: Dicionário contendo:
|
|
368
|
+
- chat_id: ID do chat (user_id, company_id)
|
|
369
|
+
- end_action: ID da tabulação de encerramento
|
|
370
|
+
- observation: Observação sobre o encerramento
|
|
371
|
+
|
|
372
|
+
Returns:
|
|
373
|
+
Objeto de resposta com atributo 'status' indicando sucesso/falha.
|
|
374
|
+
|
|
375
|
+
Raises:
|
|
376
|
+
Exception: Se houver erro na comunicação.
|
|
377
|
+
"""
|
|
378
|
+
endpoint = '/session/end/'
|
|
379
|
+
payload = {
|
|
380
|
+
'chat_id': chat_id.to_dict(),
|
|
381
|
+
'end_action': end_action.to_dict(),
|
|
382
|
+
'origin': origin,
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
response = await self._client.post(
|
|
386
|
+
endpoint,
|
|
387
|
+
json=payload,
|
|
388
|
+
)
|
|
389
|
+
response.raise_for_status()
|
|
390
|
+
response_data = response.json()
|
|
391
|
+
status = response_data.get('status')
|
|
392
|
+
message = response_data.get('message')
|
|
393
|
+
|
|
394
|
+
if not status:
|
|
395
|
+
raise Exception(f'Erro ao encerrar chat: {message}')
|
|
396
|
+
|
|
397
|
+
return response_data
|
|
398
|
+
|
|
399
|
+
async def get_end_action(
|
|
400
|
+
self,
|
|
401
|
+
end_action_id: str = '',
|
|
402
|
+
end_action_name: str = '',
|
|
403
|
+
) -> Any:
|
|
404
|
+
"""
|
|
405
|
+
Obtém uma ação de encerramento pelo ID.
|
|
406
|
+
|
|
407
|
+
Args:
|
|
408
|
+
end_action_id: ID único da ação de encerramento.
|
|
409
|
+
|
|
410
|
+
Returns:
|
|
411
|
+
Objeto de resposta com atributos 'status' e 'end_action'.
|
|
412
|
+
|
|
413
|
+
Raises:
|
|
414
|
+
Exception: Se houver erro na comunicação.
|
|
415
|
+
"""
|
|
416
|
+
endpoint = '/end_actions/'
|
|
417
|
+
params = {
|
|
418
|
+
'id': end_action_id,
|
|
419
|
+
'name': end_action_name,
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
response = await self._client.get(endpoint, params=params)
|
|
423
|
+
response.raise_for_status()
|
|
424
|
+
response_data = response.json()
|
|
425
|
+
status = response_data.get('status')
|
|
426
|
+
message = response_data.get('message')
|
|
427
|
+
end_action_data = response_data.get('data')
|
|
428
|
+
|
|
429
|
+
if not status:
|
|
430
|
+
raise Exception(f'Erro ao buscar ação de encerramento: {message}')
|
|
431
|
+
|
|
432
|
+
return EndAction.from_dict(end_action_data)
|
|
433
|
+
|
|
434
|
+
# ToDo Methods
|
|
435
|
+
async def transfer_to_menu(self, transfer_data: Dict[str, Any]) -> Any:
|
|
436
|
+
"""
|
|
437
|
+
Transfere o chat para outro menu do fluxo.
|
|
438
|
+
|
|
439
|
+
Args:
|
|
440
|
+
transfer_data: Dicionário contendo:
|
|
441
|
+
- chat_id: ID do chat (user_id, company_id)
|
|
442
|
+
- menu: Nome do menu de destino
|
|
443
|
+
- user_message: Mensagem do usuário
|
|
444
|
+
|
|
445
|
+
Returns:
|
|
446
|
+
Objeto de resposta com atributo 'status' indicando sucesso/falha.
|
|
447
|
+
|
|
448
|
+
Raises:
|
|
449
|
+
Exception: Se houver erro na comunicação.
|
|
450
|
+
"""
|
|
451
|
+
pass
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
from typing import Any, Callable
|
|
3
|
+
import threading
|
|
4
|
+
|
|
5
|
+
class BackgroundTask:
|
|
6
|
+
def __init__(self, func: Callable, *args: Any, **kwargs: Any) -> None:
|
|
7
|
+
"""
|
|
8
|
+
Inicia uma função de forma assíncrona em segundo plano e printa sua saída.
|
|
9
|
+
|
|
10
|
+
Args:
|
|
11
|
+
func (Callable): A função a ser executada.
|
|
12
|
+
args (Any): Argumentos posicionais a serem passados para a função.
|
|
13
|
+
kwargs (Any): Argumentos nomeados a serem passados para a função.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
if not asyncio.iscoroutinefunction(func):
|
|
17
|
+
raise TypeError("A função fornecida deve ser uma coroutine (async def).")
|
|
18
|
+
|
|
19
|
+
self.args = args
|
|
20
|
+
self.kwargs = kwargs
|
|
21
|
+
self.func = func
|
|
22
|
+
|
|
23
|
+
async def run(self):
|
|
24
|
+
"""
|
|
25
|
+
Executa a função em segundo plano.
|
|
26
|
+
"""
|
|
27
|
+
return await self.func(*self.args, **self.kwargs)
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
class RedirectResponse:
|
|
2
|
+
"""
|
|
3
|
+
Representa uma resposta que redireciona o fluxo do chatbot para uma nova rota.
|
|
4
|
+
|
|
5
|
+
Atributos:
|
|
6
|
+
route (str): A rota para a qual o chatbot deve redirecionar.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
def __init__(self, route: str) -> None:
|
|
10
|
+
"""
|
|
11
|
+
Inicializa a resposta de redirecionamento com a rota especificada.
|
|
12
|
+
|
|
13
|
+
Args:
|
|
14
|
+
route (str): A rota para a qual o chatbot deve redirecionar.
|
|
15
|
+
"""
|
|
16
|
+
self.route = route
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class EndChatResponse:
|
|
20
|
+
"""
|
|
21
|
+
Representa uma resposta que indica o fim do chatbot.
|
|
22
|
+
|
|
23
|
+
Atributos:
|
|
24
|
+
end_chat_id (str): O ID do fim do chatbot.
|
|
25
|
+
end_chat_name (str): O nome da ação de encerramento.
|
|
26
|
+
observations (str): As observações finais do chatbot.
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
def __init__(
|
|
30
|
+
self,
|
|
31
|
+
end_chat_id: str,
|
|
32
|
+
end_chat_name: str = '',
|
|
33
|
+
observations: str = '',
|
|
34
|
+
) -> None:
|
|
35
|
+
"""
|
|
36
|
+
Finzaliza e tabula as informações do chatbot.
|
|
37
|
+
"""
|
|
38
|
+
if not end_chat_id and not end_chat_name:
|
|
39
|
+
raise ValueError('end_chat_id or end_chat_name must be provided.')
|
|
40
|
+
|
|
41
|
+
self.end_chat_id = end_chat_id
|
|
42
|
+
self.end_chat_name = end_chat_name
|
|
43
|
+
self.observations = observations
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class TransferToHuman:
|
|
47
|
+
"""
|
|
48
|
+
Representa uma transferencia para um atendente humano.
|
|
49
|
+
"""
|
|
50
|
+
|
|
51
|
+
def __init__(
|
|
52
|
+
self,
|
|
53
|
+
campaign_id: str | None = None,
|
|
54
|
+
campaign_name: str | None = None,
|
|
55
|
+
observations: str | None = None,
|
|
56
|
+
) -> None:
|
|
57
|
+
"""
|
|
58
|
+
Finzaliza e tabula as informações do chatbot.
|
|
59
|
+
"""
|
|
60
|
+
self.campaign_id = campaign_id
|
|
61
|
+
self.campaign_name = campaign_name
|
|
62
|
+
self.observations = observations
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class TransferToMenu:
|
|
66
|
+
"""
|
|
67
|
+
Representa uma transferencia para outro Menu.
|
|
68
|
+
"""
|
|
69
|
+
|
|
70
|
+
def __init__(self, menu: str, user_message: str) -> None:
|
|
71
|
+
"""
|
|
72
|
+
Finzaliza e tabula as informações do chatbot.
|
|
73
|
+
"""
|
|
74
|
+
self.menu = menu.lower()
|
|
75
|
+
self.user_message = user_message
|
chatgraph/types/route.py
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
from ..error.route_error import RouteError
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class Route:
|
|
5
|
+
"""
|
|
6
|
+
Representa uma rota no sistema do chatbot, gerenciando a navegação entre diferentes partes do fluxo.
|
|
7
|
+
|
|
8
|
+
Atributos:
|
|
9
|
+
current (str): A rota atual.
|
|
10
|
+
routes (list[str]): A lista de todas as rotas disponíveis no fluxo.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
def __init__(
|
|
14
|
+
self,
|
|
15
|
+
current: str,
|
|
16
|
+
routes: list[str] | None = None,
|
|
17
|
+
separator: str = '.',
|
|
18
|
+
):
|
|
19
|
+
"""
|
|
20
|
+
Inicializa a rota com a rota atual e a lista de rotas disponíveis.
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
current (str): A rota atual.
|
|
24
|
+
routes (list[str]): A lista de todas as rotas disponíveis no fluxo.
|
|
25
|
+
separator (str): O separador de partes de rota. Padrão é '.'.
|
|
26
|
+
"""
|
|
27
|
+
self.current = current
|
|
28
|
+
self.routes = routes
|
|
29
|
+
self.separator = separator
|
|
30
|
+
|
|
31
|
+
@property
|
|
32
|
+
def previous(self) -> 'Route':
|
|
33
|
+
"""
|
|
34
|
+
Retorna a rota anterior a atual do usuário
|
|
35
|
+
"""
|
|
36
|
+
return self.get_previous()
|
|
37
|
+
|
|
38
|
+
@property
|
|
39
|
+
def current_node(self) -> str:
|
|
40
|
+
"""
|
|
41
|
+
Retorna o nó atual do usuário
|
|
42
|
+
"""
|
|
43
|
+
return self.current.split(self.separator)[-1]
|
|
44
|
+
|
|
45
|
+
def get_previous(self) -> 'Route':
|
|
46
|
+
"""
|
|
47
|
+
Retorna o caminho anterior ao caminho atual.
|
|
48
|
+
|
|
49
|
+
Raises:
|
|
50
|
+
RouteError: Se a rota atual for 'start', indicando que não há caminho anterior.
|
|
51
|
+
|
|
52
|
+
Returns:
|
|
53
|
+
str: O caminho anterior à rota atual.
|
|
54
|
+
"""
|
|
55
|
+
if self.current == 'start':
|
|
56
|
+
return Route(self.current, self.routes, self.separator)
|
|
57
|
+
|
|
58
|
+
rotas_dedup = self.separator.join(
|
|
59
|
+
dict.fromkeys(self.current.split(self.separator))
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
previous_route = self.separator.join(
|
|
63
|
+
rotas_dedup.split(self.separator)[:-1]
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
return Route(previous_route, self.routes, self.separator)
|
|
67
|
+
|
|
68
|
+
def get_next(self, next_part: str) -> 'Route':
|
|
69
|
+
"""
|
|
70
|
+
Monta e retorna o próximo caminho com base na parte fornecida.
|
|
71
|
+
|
|
72
|
+
Args:
|
|
73
|
+
next_part (str): A parte do caminho a ser adicionada à rota atual.
|
|
74
|
+
|
|
75
|
+
Raises:
|
|
76
|
+
RouteError: Se a próxima rota montada não estiver na lista de rotas disponíveis.
|
|
77
|
+
|
|
78
|
+
Returns:
|
|
79
|
+
Route: O próximo caminho montado.
|
|
80
|
+
"""
|
|
81
|
+
next_part = next_part.strip().lower()
|
|
82
|
+
next_route = f'{self.current.rstrip(self.separator)}.{next_part}'
|
|
83
|
+
if next_part not in self.routes:
|
|
84
|
+
raise RouteError(f'Rota não encontrada: {next_part}')
|
|
85
|
+
|
|
86
|
+
return Route(next_route, self.routes, self.separator)
|
|
87
|
+
|
|
88
|
+
def __str__(self):
|
|
89
|
+
"""
|
|
90
|
+
Retorna uma representação em string da rota atual.
|
|
91
|
+
|
|
92
|
+
Returns:
|
|
93
|
+
str: A representação em string da rota atual.
|
|
94
|
+
"""
|
|
95
|
+
return f'Route(current={self.current})'
|
|
96
|
+
|
|
97
|
+
def __repr__(self):
|
|
98
|
+
"""
|
|
99
|
+
Retorna a representação oficial da rota, que é a mesma que a representação em string.
|
|
100
|
+
|
|
101
|
+
Returns:
|
|
102
|
+
str: A representação oficial da rota.
|
|
103
|
+
"""
|
|
104
|
+
return self.__str__()
|