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
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from chatgraph.services.router_http_client import RouterHTTPClient
|
|
3
|
+
from chatgraph.models.userstate import UserState
|
|
4
|
+
from chatgraph.models.message import (
|
|
5
|
+
Message,
|
|
6
|
+
File,
|
|
7
|
+
MessageTypes,
|
|
8
|
+
)
|
|
9
|
+
from typing import Optional
|
|
10
|
+
from rich.console import Console
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class UserCall:
|
|
14
|
+
"""
|
|
15
|
+
Representa uma mensagem recebida ou enviada pelo chatbot.
|
|
16
|
+
|
|
17
|
+
Atributos:
|
|
18
|
+
type (str): O tipo da mensagem (por exemplo, texto, imagem, etc.).
|
|
19
|
+
text (str): O conteúdo textual da mensagem.
|
|
20
|
+
UserState (UserState): O estado do usuário.
|
|
21
|
+
channel (str): O canal pelo qual a mensagem foi enviada ou recebida (por exemplo, WhatsApp, SMS, etc.).
|
|
22
|
+
customer_phone (str): O número de telefone do cliente.
|
|
23
|
+
company_phone (str): O número de telefone da empresa que está enviando ou recebendo a mensagem.
|
|
24
|
+
status (Optional[str]): O status da mensagem (por exemplo, enviada, recebida, lida, etc.). Este campo é opcional.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
def __init__(
|
|
28
|
+
self,
|
|
29
|
+
user_state: UserState,
|
|
30
|
+
message: Message,
|
|
31
|
+
router_client: RouterHTTPClient,
|
|
32
|
+
) -> None:
|
|
33
|
+
self.type = type
|
|
34
|
+
self.__message = message
|
|
35
|
+
self.__user_state = user_state
|
|
36
|
+
self.__router_client = router_client
|
|
37
|
+
self.__content_message = self.__message.text_message.detail
|
|
38
|
+
self.console = Console()
|
|
39
|
+
|
|
40
|
+
def __str__(self):
|
|
41
|
+
return (
|
|
42
|
+
f'UserCall(UserState={self.__user_state}, '
|
|
43
|
+
f'Message={self.__message})'
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
async def __get_file_from_server(self, hash_id: str) -> Optional[File]:
|
|
47
|
+
try:
|
|
48
|
+
file = await self.__router_client.get_file(hash_id)
|
|
49
|
+
if not file.url:
|
|
50
|
+
return None
|
|
51
|
+
return file
|
|
52
|
+
except Exception as e:
|
|
53
|
+
self.console.print(f'Erro ao obter arquivo do servidor: {e}')
|
|
54
|
+
return None
|
|
55
|
+
|
|
56
|
+
async def __upload_file(
|
|
57
|
+
self, file_data: bytes
|
|
58
|
+
) -> tuple[bool, str, Optional[File]]:
|
|
59
|
+
try:
|
|
60
|
+
file = await self.__router_client.upload_file(file_data)
|
|
61
|
+
return True, 'Upload successful', file
|
|
62
|
+
except Exception as e:
|
|
63
|
+
self.console.print(f'Erro ao enviar arquivo para o servidor: {e}')
|
|
64
|
+
return False, str(e), None
|
|
65
|
+
|
|
66
|
+
async def __check_file_for_send(self, path_file: str) -> File:
|
|
67
|
+
try:
|
|
68
|
+
file = File(name=path_file)
|
|
69
|
+
await file.load_file()
|
|
70
|
+
except Exception as e:
|
|
71
|
+
raise ValueError('Erro ao criar File: ' + str(e))
|
|
72
|
+
|
|
73
|
+
if not file.hash_id:
|
|
74
|
+
raise ValueError('Hash do arquivo não gerado.')
|
|
75
|
+
|
|
76
|
+
if not file.bytes_data:
|
|
77
|
+
raise ValueError('Dados do arquivo em bytes não carregados.')
|
|
78
|
+
|
|
79
|
+
existing_file = await self.__get_file_from_server(file.hash_id)
|
|
80
|
+
if existing_file:
|
|
81
|
+
return existing_file
|
|
82
|
+
|
|
83
|
+
status, msg, uploaded = await self.__upload_file(file.bytes_data)
|
|
84
|
+
if not status or not uploaded:
|
|
85
|
+
raise ValueError('Erro ao enviar arquivo: ' + msg)
|
|
86
|
+
|
|
87
|
+
return uploaded
|
|
88
|
+
|
|
89
|
+
async def __send(self, message: Message) -> None:
|
|
90
|
+
try:
|
|
91
|
+
response = await self.__router_client.send_message(
|
|
92
|
+
message, self.__user_state
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
if response:
|
|
96
|
+
self.console.print(f'Mensagem enviada com sucesso: {response}')
|
|
97
|
+
|
|
98
|
+
except Exception as e:
|
|
99
|
+
raise Exception(f'Erro ao enviar mensagem: {e}')
|
|
100
|
+
|
|
101
|
+
async def send(
|
|
102
|
+
self,
|
|
103
|
+
message: MessageTypes | Message | File,
|
|
104
|
+
) -> None:
|
|
105
|
+
"""
|
|
106
|
+
Envia uma mensagem ao cliente.
|
|
107
|
+
|
|
108
|
+
Args:
|
|
109
|
+
message (Message|Button|ListElements): A mensagem a ser enviada.
|
|
110
|
+
"""
|
|
111
|
+
if isinstance(message, MessageTypes):
|
|
112
|
+
msg = Message(str(message))
|
|
113
|
+
await self.__send(msg)
|
|
114
|
+
return
|
|
115
|
+
|
|
116
|
+
if isinstance(message, Message):
|
|
117
|
+
if message.has_file() and message.file:
|
|
118
|
+
message.file = await self.__check_file_for_send(
|
|
119
|
+
message.file.name
|
|
120
|
+
)
|
|
121
|
+
await self.__send(message)
|
|
122
|
+
return
|
|
123
|
+
|
|
124
|
+
if isinstance(message, File):
|
|
125
|
+
file = await self.__check_file_for_send(message.name)
|
|
126
|
+
file_message = Message(file=file)
|
|
127
|
+
await self.__send(file_message)
|
|
128
|
+
return
|
|
129
|
+
|
|
130
|
+
raise ValueError('Tipo de mensagem inválido.')
|
|
131
|
+
|
|
132
|
+
async def end_chat(
|
|
133
|
+
self, end_action_id: str = '', end_action_name: str = ''
|
|
134
|
+
) -> None:
|
|
135
|
+
try:
|
|
136
|
+
end_action = await self.__router_client.get_end_action(
|
|
137
|
+
end_action_id,
|
|
138
|
+
end_action_name,
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
await self.__router_client.end_chat(
|
|
142
|
+
self.__user_state.chat_id,
|
|
143
|
+
end_action,
|
|
144
|
+
'chatgraph',
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
except Exception as e:
|
|
148
|
+
raise ValueError(
|
|
149
|
+
'Erro ao realizar ação de encerramento: ' + str(e)
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
async def set_observation(self, observation: str = '') -> None:
|
|
153
|
+
try:
|
|
154
|
+
if not observation and self.__user_state.observation:
|
|
155
|
+
observation = self.__user_state.observation
|
|
156
|
+
|
|
157
|
+
await self.__router_client.update_session_observation(
|
|
158
|
+
self.__user_state.chat_id,
|
|
159
|
+
observation,
|
|
160
|
+
)
|
|
161
|
+
except Exception as e:
|
|
162
|
+
self.console.print(f'Erro ao atualizar observação: {e}')
|
|
163
|
+
|
|
164
|
+
async def add_observation(self, observation: dict) -> None:
|
|
165
|
+
try:
|
|
166
|
+
current_observation = self.observation
|
|
167
|
+
current_observation.update(observation)
|
|
168
|
+
self.__user_state.observation = json.dumps(current_observation)
|
|
169
|
+
await self.set_observation()
|
|
170
|
+
except Exception as e:
|
|
171
|
+
raise ValueError(f'Erro ao adicionar observação: {e}')
|
|
172
|
+
|
|
173
|
+
async def set_route(self, current_route: str):
|
|
174
|
+
try:
|
|
175
|
+
if not current_route:
|
|
176
|
+
raise ValueError('Rota atual não pode ser vazia.')
|
|
177
|
+
|
|
178
|
+
if not self.__user_state.route:
|
|
179
|
+
self.__user_state.route = 'start'
|
|
180
|
+
|
|
181
|
+
self.__user_state.route += f'.{current_route}'
|
|
182
|
+
await self.__router_client.set_session_route(
|
|
183
|
+
self.__user_state.chat_id,
|
|
184
|
+
current_route,
|
|
185
|
+
)
|
|
186
|
+
except Exception as e:
|
|
187
|
+
raise ValueError(f'Erro ao atualizar rota: {e}')
|
|
188
|
+
|
|
189
|
+
async def transfer_to_menu(self, menu: str, user_message: str) -> None:
|
|
190
|
+
raise NotImplementedError(
|
|
191
|
+
'transfer_to_menu method is not implemented yet.'
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
@property
|
|
195
|
+
def chatID(self):
|
|
196
|
+
return self.__user_state.chat_id
|
|
197
|
+
|
|
198
|
+
@property
|
|
199
|
+
def user_id(self):
|
|
200
|
+
return self.__user_state.chat_id.user_id
|
|
201
|
+
|
|
202
|
+
@property
|
|
203
|
+
def company_id(self):
|
|
204
|
+
return self.__user_state.chat_id.company_id
|
|
205
|
+
|
|
206
|
+
@property
|
|
207
|
+
def menu(self):
|
|
208
|
+
return self.__user_state.menu
|
|
209
|
+
|
|
210
|
+
@property
|
|
211
|
+
def route(self):
|
|
212
|
+
return self.__user_state.route
|
|
213
|
+
|
|
214
|
+
@property
|
|
215
|
+
def observation(self):
|
|
216
|
+
return self.__user_state.observation_dict
|
|
217
|
+
|
|
218
|
+
@property
|
|
219
|
+
def content_message(self):
|
|
220
|
+
return self.__content_message
|
|
221
|
+
|
|
222
|
+
@observation.setter
|
|
223
|
+
async def observation(self, observation: dict):
|
|
224
|
+
self.__user_state.observation = json.dumps(observation)
|
|
225
|
+
await self.set_observation()
|
|
226
|
+
|
|
227
|
+
@content_message.setter
|
|
228
|
+
def content_message(self, content_message: str):
|
|
229
|
+
self.__content_message = content_message
|