chatgraph 0.4.0__py3-none-any.whl → 0.5.0__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.
- chatgraph/__init__.py +4 -3
- chatgraph/bot/chatbot_model.py +11 -8
- chatgraph/gRPC/gRPCCall.py +61 -145
- chatgraph/messages/message_consumer.py +74 -138
- chatgraph/pb/router.proto +127 -0
- chatgraph/pb/router_pb2.py +77 -0
- chatgraph/pb/router_pb2_grpc.py +669 -0
- chatgraph/types/message_types.py +79 -76
- chatgraph/types/request_types.py +182 -235
- chatgraph/types/route.py +7 -0
- {chatgraph-0.4.0.dist-info → chatgraph-0.5.0.dist-info}/METADATA +1 -1
- chatgraph-0.5.0.dist-info/RECORD +21 -0
- chatgraph/pb/userstate.proto +0 -41
- chatgraph/pb/userstate_pb2.py +0 -47
- chatgraph/pb/userstate_pb2_grpc.py +0 -269
- chatgraph/pb/voll.proto +0 -90
- chatgraph/pb/voll_pb2.py +0 -63
- chatgraph/pb/voll_pb2_grpc.py +0 -470
- chatgraph-0.4.0.dist-info/RECORD +0 -24
- {chatgraph-0.4.0.dist-info → chatgraph-0.5.0.dist-info}/LICENSE +0 -0
- {chatgraph-0.4.0.dist-info → chatgraph-0.5.0.dist-info}/WHEEL +0 -0
- {chatgraph-0.4.0.dist-info → chatgraph-0.5.0.dist-info}/entry_points.txt +0 -0
chatgraph/__init__.py
CHANGED
|
@@ -2,9 +2,9 @@ from .auth.credentials import Credential
|
|
|
2
2
|
from .bot.chatbot_model import ChatbotApp
|
|
3
3
|
from .bot.chatbot_router import ChatbotRouter
|
|
4
4
|
from .messages.message_consumer import MessageConsumer
|
|
5
|
-
from .types.request_types import UserCall, UserState
|
|
5
|
+
from .types.request_types import UserCall, UserState, ChatID
|
|
6
6
|
from .types.end_types import RedirectResponse, EndChatResponse, TransferToHuman
|
|
7
|
-
from .types.message_types import Message, Button
|
|
7
|
+
from .types.message_types import Message, Button
|
|
8
8
|
from .types.route import Route
|
|
9
9
|
|
|
10
10
|
__all__ = [
|
|
@@ -18,8 +18,9 @@ __all__ = [
|
|
|
18
18
|
'Route',
|
|
19
19
|
'EndChatResponse',
|
|
20
20
|
'TransferToHuman',
|
|
21
|
+
'ChatID',
|
|
21
22
|
'UserState',
|
|
22
23
|
'Message',
|
|
23
24
|
'Button',
|
|
24
|
-
|
|
25
|
+
|
|
25
26
|
]
|
chatgraph/bot/chatbot_model.py
CHANGED
|
@@ -2,12 +2,13 @@ import inspect
|
|
|
2
2
|
from functools import wraps
|
|
3
3
|
from logging import debug
|
|
4
4
|
import json
|
|
5
|
+
import asyncio
|
|
5
6
|
from logging import error
|
|
6
7
|
|
|
7
|
-
from ..error.chatbot_error import
|
|
8
|
+
from ..error.chatbot_error import ChatbotMessageError
|
|
8
9
|
from ..messages.message_consumer import MessageConsumer
|
|
9
10
|
from ..types.request_types import UserCall
|
|
10
|
-
from ..types.message_types import
|
|
11
|
+
from ..types.message_types import Message, Button
|
|
11
12
|
from ..types.end_types import RedirectResponse, EndChatResponse, TransferToHuman
|
|
12
13
|
from ..types.route import Route
|
|
13
14
|
from .chatbot_router import ChatbotRouter
|
|
@@ -88,8 +89,10 @@ class ChatbotApp:
|
|
|
88
89
|
"""
|
|
89
90
|
Inicia o consumo de mensagens pelo chatbot, processando cada mensagem recebida.
|
|
90
91
|
"""
|
|
92
|
+
|
|
93
|
+
|
|
91
94
|
self.__message_consumer.reprer()
|
|
92
|
-
self.__message_consumer.start_consume(self.process_message)
|
|
95
|
+
asyncio.run(self.__message_consumer.start_consume(self.process_message))
|
|
93
96
|
|
|
94
97
|
def process_message(self, userCall: UserCall):
|
|
95
98
|
"""
|
|
@@ -105,16 +108,16 @@ class ChatbotApp:
|
|
|
105
108
|
Returns:
|
|
106
109
|
str: A resposta gerada pela função da rota, que pode ser uma mensagem ou o resultado de uma redireção.
|
|
107
110
|
"""
|
|
108
|
-
|
|
111
|
+
user_id = userCall.user_id
|
|
109
112
|
route = userCall.route.lower()
|
|
110
113
|
route_handler = route.split('.')[-1]
|
|
111
114
|
menu = userCall.menu.lower()
|
|
112
|
-
|
|
115
|
+
observation = userCall.observation
|
|
113
116
|
handler = self.__routes.get(route_handler, None)
|
|
114
117
|
|
|
115
118
|
if not handler:
|
|
116
119
|
raise ChatbotMessageError(
|
|
117
|
-
|
|
120
|
+
user_id, f'Rota não encontrada para {route}!'
|
|
118
121
|
)
|
|
119
122
|
|
|
120
123
|
func = handler['function']
|
|
@@ -138,14 +141,14 @@ class ChatbotApp:
|
|
|
138
141
|
def __process_func_response(self, userCall_response, userCall: UserCall, route: str):
|
|
139
142
|
|
|
140
143
|
if isinstance(userCall_response, (str, float, int)):
|
|
141
|
-
userCall.send(Message(
|
|
144
|
+
userCall.send(Message(userCall_response))
|
|
142
145
|
return
|
|
143
146
|
|
|
144
147
|
elif isinstance(userCall_response, Route):
|
|
145
148
|
userCall.route = userCall_response.current
|
|
146
149
|
return
|
|
147
150
|
|
|
148
|
-
elif isinstance(userCall_response, (Message, Button
|
|
151
|
+
elif isinstance(userCall_response, (Message, Button)):
|
|
149
152
|
userCall.send(userCall_response)
|
|
150
153
|
|
|
151
154
|
return
|
chatgraph/gRPC/gRPCCall.py
CHANGED
|
@@ -1,210 +1,126 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import grpc
|
|
3
|
-
import
|
|
4
|
-
import chatgraph.pb.userstate_pb2_grpc as userstate_pb2_grpc
|
|
3
|
+
import json
|
|
5
4
|
|
|
6
|
-
import chatgraph.pb.
|
|
7
|
-
import chatgraph.pb.
|
|
5
|
+
import chatgraph.pb.router_pb2 as chatbot_pb2
|
|
6
|
+
import chatgraph.pb.router_pb2_grpc as chatbot_pb2_grpc
|
|
8
7
|
|
|
9
|
-
|
|
8
|
+
|
|
9
|
+
class RouterServiceClient:
|
|
10
10
|
def __init__(self, grpc_uri=None):
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
if not grpc_uri:
|
|
15
|
-
self.grpc_uri = os.getenv('GRPC_URI')
|
|
16
|
-
|
|
11
|
+
self.grpc_uri = grpc_uri or os.getenv("GRPC_URI")
|
|
12
|
+
|
|
17
13
|
if not self.grpc_uri:
|
|
18
14
|
raise ValueError("A variável de ambiente 'GRPC_URI' não está definida.")
|
|
19
|
-
|
|
15
|
+
|
|
20
16
|
# Cria o canal gRPC
|
|
21
17
|
self.channel = grpc.insecure_channel(self.grpc_uri)
|
|
22
|
-
|
|
23
|
-
# Cria o stub (client) para o serviço gRPC
|
|
24
|
-
self.stub = whatsapp_pb2_grpc.MessageServiceStub(self.channel)
|
|
25
|
-
self.actions_stub = whatsapp_pb2_grpc.ActionsServiceStub(self.channel)
|
|
26
|
-
|
|
27
|
-
def send_button(self, message_data):
|
|
28
|
-
# Cria o request para o método SendButton
|
|
29
|
-
request = whatsapp_pb2.MessageRequest(**message_data)
|
|
30
|
-
|
|
31
|
-
# Faz a chamada ao serviço gRPC
|
|
32
|
-
try:
|
|
33
|
-
response = self.stub.SendButton(request)
|
|
34
|
-
return response
|
|
35
|
-
except grpc.RpcError as e:
|
|
36
|
-
print(f"Erro ao fazer a requisição gRPC SendButton: {e}")
|
|
37
|
-
return None
|
|
38
18
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
19
|
+
# Cria os stubs para os serviços gRPC
|
|
20
|
+
self.user_state_stub = chatbot_pb2_grpc.UserStateServiceStub(self.channel)
|
|
21
|
+
self.send_message_stub = chatbot_pb2_grpc.SendMessageStub(self.channel)
|
|
22
|
+
self.transfer_stub = chatbot_pb2_grpc.TransferStub(self.channel)
|
|
23
|
+
self.end_chat_stub = chatbot_pb2_grpc.EndChatStub(self.channel)
|
|
42
24
|
|
|
43
|
-
|
|
25
|
+
def insert_update_user_state(self, user_state_data):
|
|
26
|
+
request = chatbot_pb2.UserState(**user_state_data)
|
|
44
27
|
try:
|
|
45
|
-
response = self.
|
|
28
|
+
response = self.user_state_stub.InsertUpdateUserState(request)
|
|
46
29
|
return response
|
|
47
30
|
except grpc.RpcError as e:
|
|
48
|
-
print(f"Erro ao
|
|
31
|
+
print(f"Erro ao chamar InsertUpdateUserState: {e}")
|
|
49
32
|
return None
|
|
50
33
|
|
|
51
|
-
def
|
|
52
|
-
|
|
53
|
-
request = whatsapp_pb2.MessageRequest(**message_data)
|
|
54
|
-
|
|
55
|
-
# Faz a chamada ao serviço gRPC
|
|
34
|
+
def delete_user_state(self, chat_id_data):
|
|
35
|
+
request = chatbot_pb2.ChatID(**chat_id_data)
|
|
56
36
|
try:
|
|
57
|
-
response = self.
|
|
37
|
+
response = self.user_state_stub.DeleteUserState(request)
|
|
58
38
|
return response
|
|
59
39
|
except grpc.RpcError as e:
|
|
60
|
-
print(f"Erro ao
|
|
40
|
+
print(f"Erro ao chamar DeleteUserState: {e}")
|
|
61
41
|
return None
|
|
62
|
-
|
|
63
|
-
def transfer_to_human(self, message_data):
|
|
64
|
-
# Cria o request para o método TransferToHuman
|
|
65
|
-
request = whatsapp_pb2.MessageRequest(**message_data)
|
|
66
42
|
|
|
67
|
-
|
|
43
|
+
def get_user_state(self, chat_id_data):
|
|
44
|
+
request = chatbot_pb2.ChatID(**chat_id_data)
|
|
68
45
|
try:
|
|
69
|
-
response = self.
|
|
46
|
+
response = self.user_state_stub.GetUserState(request)
|
|
70
47
|
return response
|
|
71
48
|
except grpc.RpcError as e:
|
|
72
|
-
print(f"Erro ao
|
|
49
|
+
print(f"Erro ao chamar GetUserState: {e}")
|
|
73
50
|
return None
|
|
74
|
-
|
|
75
|
-
def end_chat(self, message_data):
|
|
76
|
-
# Cria o request para o método EndChat
|
|
77
|
-
request = whatsapp_pb2.MessageRequest(**message_data)
|
|
78
51
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
except grpc.RpcError as e:
|
|
84
|
-
print(f"Erro ao fazer a requisição gRPC EndChat: {e}")
|
|
85
|
-
return None
|
|
86
|
-
|
|
87
|
-
def get_campaign_id(self, campaign_name):
|
|
88
|
-
# Cria o request para o método GetCampaignID
|
|
89
|
-
request = whatsapp_pb2.CampaignName(campaign_name=campaign_name)
|
|
90
|
-
|
|
91
|
-
# Faz a chamada ao serviço gRPC
|
|
92
|
-
try:
|
|
93
|
-
response = self.actions_stub.GetCampaignID(request)
|
|
94
|
-
return response
|
|
95
|
-
except grpc.RpcError as e:
|
|
96
|
-
print(f"Erro ao fazer a requisição gRPC GetCampaignID: {e}")
|
|
97
|
-
return None
|
|
52
|
+
def send_message(self, message_data):
|
|
53
|
+
print(json.dumps(message_data))
|
|
54
|
+
|
|
55
|
+
request = chatbot_pb2.Message(**message_data)
|
|
98
56
|
|
|
99
|
-
def get_tabulation_id(self, tabulation_name):
|
|
100
|
-
# Cria o request para o método GetTabulationID
|
|
101
|
-
request = whatsapp_pb2.TabulationName(tabulation_name=tabulation_name)
|
|
102
|
-
|
|
103
|
-
# Faz a chamada ao serviço gRPC
|
|
104
57
|
try:
|
|
105
|
-
response = self.
|
|
58
|
+
response = self.send_message_stub.SendMessage(request)
|
|
106
59
|
return response
|
|
107
60
|
except grpc.RpcError as e:
|
|
108
|
-
print(f"Erro ao
|
|
61
|
+
print(f"Erro ao chamar SendMessage: {e}")
|
|
109
62
|
return None
|
|
110
63
|
|
|
111
|
-
def
|
|
112
|
-
|
|
113
|
-
request = whatsapp_pb2.Void()
|
|
114
|
-
|
|
115
|
-
# Faz a chamada ao serviço gRPC
|
|
64
|
+
def transfer_to_human(self, transfer_request_data):
|
|
65
|
+
request = chatbot_pb2.TransferToHumanRequest(**transfer_request_data)
|
|
116
66
|
try:
|
|
117
|
-
response = self.
|
|
67
|
+
response = self.transfer_stub.TransferToHuman(request)
|
|
118
68
|
return response
|
|
119
69
|
except grpc.RpcError as e:
|
|
120
|
-
print(f"Erro ao
|
|
70
|
+
print(f"Erro ao chamar TransferToHuman: {e}")
|
|
121
71
|
return None
|
|
122
|
-
|
|
123
|
-
def get_all_tabulations(self):
|
|
124
|
-
# Cria o request para o método GetAllTabulations
|
|
125
|
-
request = whatsapp_pb2.Void()
|
|
126
72
|
|
|
127
|
-
|
|
73
|
+
def transfer_to_menu(self, transfer_request_data):
|
|
74
|
+
request = chatbot_pb2.TransferToMenuRequest(**transfer_request_data)
|
|
128
75
|
try:
|
|
129
|
-
response = self.
|
|
76
|
+
response = self.transfer_stub.TransferToMenu(request)
|
|
130
77
|
return response
|
|
131
78
|
except grpc.RpcError as e:
|
|
132
|
-
print(f"Erro ao
|
|
79
|
+
print(f"Erro ao chamar TransferToMenu: {e}")
|
|
133
80
|
return None
|
|
134
81
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
self.grpc_uri = grpc_uri
|
|
139
|
-
|
|
140
|
-
if not grpc_uri:
|
|
141
|
-
self.grpc_uri = os.getenv('GRPC_URI')
|
|
142
|
-
|
|
143
|
-
if not self.grpc_uri:
|
|
144
|
-
raise ValueError("A variável de ambiente 'GRPC_URI' não está definida.")
|
|
145
|
-
|
|
146
|
-
# Cria o canal gRPC
|
|
147
|
-
self.channel = grpc.insecure_channel(self.grpc_uri)
|
|
148
|
-
|
|
149
|
-
# Cria o stub (client) para o serviço gRPC
|
|
150
|
-
self.stub = userstate_pb2_grpc.UserStateServiceStub(self.channel)
|
|
151
|
-
|
|
152
|
-
def select_user_state(self, user_id):
|
|
153
|
-
# Cria o request para o método SelectUserState
|
|
154
|
-
request = userstate_pb2.UserStateId(user_id=user_id)
|
|
155
|
-
|
|
156
|
-
# Faz a chamada ao serviço gRPC
|
|
82
|
+
def end_chat(self, end_chat_request_data):
|
|
83
|
+
request = chatbot_pb2.EndChatRequest(**end_chat_request_data)
|
|
157
84
|
try:
|
|
158
|
-
response = self.
|
|
85
|
+
response = self.end_chat_stub.EndChat(request)
|
|
159
86
|
return response
|
|
160
87
|
except grpc.RpcError as e:
|
|
161
|
-
print(f"Erro ao
|
|
88
|
+
print(f"Erro ao chamar EndChat: {e}")
|
|
162
89
|
return None
|
|
163
90
|
|
|
164
|
-
def
|
|
165
|
-
|
|
166
|
-
request = userstate_pb2.UserState(**user_state_data)
|
|
167
|
-
|
|
168
|
-
# Faz a chamada ao serviço gRPC
|
|
91
|
+
def get_campaign_id(self, campaign_name):
|
|
92
|
+
request = chatbot_pb2.CampaignName(**campaign_name)
|
|
169
93
|
try:
|
|
170
|
-
response = self.
|
|
94
|
+
response = self.transfer_stub.GetCampaignID(request)
|
|
95
|
+
print(response)
|
|
171
96
|
return response
|
|
172
97
|
except grpc.RpcError as e:
|
|
173
|
-
print(f"Erro ao
|
|
98
|
+
print(f"Erro ao chamar GetCampaignID: {e}")
|
|
174
99
|
return None
|
|
175
100
|
|
|
176
|
-
def
|
|
177
|
-
|
|
178
|
-
request = userstate_pb2.UserState(**user_state_data)
|
|
179
|
-
|
|
180
|
-
# Faz a chamada ao serviço gRPC
|
|
101
|
+
def get_all_campaigns(self):
|
|
102
|
+
request = chatbot_pb2.Void()
|
|
181
103
|
try:
|
|
182
|
-
response = self.
|
|
104
|
+
response = self.transfer_stub.GetAllCampaigns(request)
|
|
183
105
|
return response
|
|
184
106
|
except grpc.RpcError as e:
|
|
185
|
-
print(f"Erro ao
|
|
107
|
+
print(f"Erro ao chamar GetAllCampaigns: {e}")
|
|
186
108
|
return None
|
|
187
109
|
|
|
188
|
-
def
|
|
189
|
-
|
|
190
|
-
request = userstate_pb2.UserStateId(user_id=user_id)
|
|
191
|
-
|
|
192
|
-
# Faz a chamada ao serviço gRPC
|
|
110
|
+
def get_tabulation_id(self, tabulation_name):
|
|
111
|
+
request = chatbot_pb2.TabulationName(**tabulation_name)
|
|
193
112
|
try:
|
|
194
|
-
response = self.
|
|
113
|
+
response = self.end_chat_stub.GetTabulationID(request)
|
|
195
114
|
return response
|
|
196
115
|
except grpc.RpcError as e:
|
|
197
|
-
print(f"Erro ao
|
|
116
|
+
print(f"Erro ao chamar GetTabulationID: {e}")
|
|
198
117
|
return None
|
|
199
|
-
|
|
200
|
-
def get_all_user_states(self):
|
|
201
|
-
# Cria o request para o método GetAllUserStates
|
|
202
|
-
request = userstate_pb2.Void()
|
|
203
118
|
|
|
204
|
-
|
|
119
|
+
def get_all_tabulations(self):
|
|
120
|
+
request = chatbot_pb2.Void()
|
|
205
121
|
try:
|
|
206
|
-
response = self.
|
|
122
|
+
response = self.end_chat_stub.GetAllTabulations(request)
|
|
207
123
|
return response
|
|
208
124
|
except grpc.RpcError as e:
|
|
209
|
-
print(f"Erro ao
|
|
210
|
-
return None
|
|
125
|
+
print(f"Erro ao chamar GetAllTabulations: {e}")
|
|
126
|
+
return None
|
|
@@ -1,27 +1,18 @@
|
|
|
1
1
|
import json
|
|
2
|
+
import asyncio
|
|
2
3
|
from logging import debug, info
|
|
3
4
|
import os
|
|
4
|
-
import
|
|
5
|
+
import aio_pika
|
|
5
6
|
from typing import Callable
|
|
6
7
|
from ..auth.credentials import Credential
|
|
7
|
-
from ..types.request_types import UserCall, UserState
|
|
8
|
+
from ..types.request_types import UserCall, UserState, ChatID
|
|
8
9
|
from rich.console import Console
|
|
9
10
|
from rich.table import Table
|
|
10
11
|
from rich.text import Text
|
|
11
12
|
from rich.panel import Panel
|
|
13
|
+
from urllib.parse import quote
|
|
12
14
|
|
|
13
15
|
class MessageConsumer:
|
|
14
|
-
"""
|
|
15
|
-
Implementação de MessageConsumer para consumir mensagens de uma fila RabbitMQ.
|
|
16
|
-
|
|
17
|
-
Atributos:
|
|
18
|
-
__virtual_host (str): O host virtual usado para a conexão RabbitMQ.
|
|
19
|
-
__prefetch_count (int): O número de mensagens pré-carregadas que o consumidor pode processar.
|
|
20
|
-
__queue_consume (str): O nome da fila de consumo.
|
|
21
|
-
__amqp_url (str): A URL de conexão AMQP do RabbitMQ.
|
|
22
|
-
__credentials (pika.PlainCredentials): Credenciais do RabbitMQ para autenticação.
|
|
23
|
-
"""
|
|
24
|
-
|
|
25
16
|
def __init__(
|
|
26
17
|
self,
|
|
27
18
|
credential: Credential,
|
|
@@ -29,65 +20,36 @@ class MessageConsumer:
|
|
|
29
20
|
grpc_uri: str,
|
|
30
21
|
queue_consume: str,
|
|
31
22
|
prefetch_count: int = 1,
|
|
32
|
-
virtual_host: str =
|
|
23
|
+
virtual_host: str = "/",
|
|
33
24
|
) -> None:
|
|
34
|
-
"""
|
|
35
|
-
Inicializa o consumidor de mensagens RabbitMQ com as configurações fornecidas.
|
|
36
|
-
|
|
37
|
-
Args:
|
|
38
|
-
credential (Credential): Credenciais de autenticação para o RabbitMQ.
|
|
39
|
-
amqp_url (str): A URL de conexão AMQP do RabbitMQ.
|
|
40
|
-
queue_consume (str): O nome da fila de consumo.
|
|
41
|
-
prefetch_count (int, opcional): O número de mensagens pré-carregadas. Padrão é 1.
|
|
42
|
-
virtual_host (str, opcional): O host virtual do RabbitMQ. Padrão é '/'.
|
|
43
|
-
"""
|
|
44
25
|
self.__virtual_host = virtual_host
|
|
45
26
|
self.__prefetch_count = prefetch_count
|
|
46
27
|
self.__queue_consume = queue_consume
|
|
47
28
|
self.__amqp_url = amqp_url
|
|
48
29
|
self.__grpc_uri = grpc_uri
|
|
49
|
-
self.__credentials =
|
|
50
|
-
credential.username, credential.password
|
|
51
|
-
)
|
|
30
|
+
self.__credentials = credential
|
|
52
31
|
|
|
53
32
|
@classmethod
|
|
54
33
|
def load_dotenv(
|
|
55
34
|
cls,
|
|
56
|
-
user_env: str =
|
|
57
|
-
pass_env: str =
|
|
58
|
-
uri_env: str =
|
|
59
|
-
queue_env: str =
|
|
60
|
-
prefetch_env: str =
|
|
61
|
-
vhost_env: str =
|
|
62
|
-
grpc_uri: str =
|
|
63
|
-
) ->
|
|
64
|
-
"""
|
|
65
|
-
Carrega as configurações do RabbitMQ a partir de variáveis de ambiente e retorna uma instância de RabbitMessageConsumer.
|
|
66
|
-
|
|
67
|
-
Args:
|
|
68
|
-
user_env (str): Nome da variável de ambiente para o usuário do RabbitMQ. Padrão é 'RABBIT_USER'.
|
|
69
|
-
pass_env (str): Nome da variável de ambiente para a senha do RabbitMQ. Padrão é 'RABBIT_PASS'.
|
|
70
|
-
uri_env (str): Nome da variável de ambiente para a URL do RabbitMQ. Padrão é 'RABBIT_URI'.
|
|
71
|
-
queue_env (str): Nome da variável de ambiente para a fila de consumo do RabbitMQ. Padrão é 'RABBIT_QUEUE'.
|
|
72
|
-
prefetch_env (str): Nome da variável de ambiente para o prefetch count. Padrão é 'RABBIT_PREFETCH'.
|
|
73
|
-
vhost_env (str): Nome da variável de ambiente para o host virtual do RabbitMQ. Padrão é 'RABBIT_VHOST'.
|
|
74
|
-
|
|
75
|
-
Raises:
|
|
76
|
-
ValueError: Se qualquer uma das variáveis de ambiente necessárias não estiver definida.
|
|
77
|
-
|
|
78
|
-
Returns:
|
|
79
|
-
RabbitMessageConsumer: Uma instância configurada do RabbitMessageConsumer.
|
|
80
|
-
"""
|
|
35
|
+
user_env: str = "RABBIT_USER",
|
|
36
|
+
pass_env: str = "RABBIT_PASS",
|
|
37
|
+
uri_env: str = "RABBIT_URI",
|
|
38
|
+
queue_env: str = "RABBIT_QUEUE",
|
|
39
|
+
prefetch_env: str = "RABBIT_PREFETCH",
|
|
40
|
+
vhost_env: str = "RABBIT_VHOST",
|
|
41
|
+
grpc_uri: str = "GRPC_URI",
|
|
42
|
+
) -> "MessageConsumer":
|
|
81
43
|
username = os.getenv(user_env)
|
|
82
44
|
password = os.getenv(pass_env)
|
|
83
45
|
url = os.getenv(uri_env)
|
|
84
46
|
queue = os.getenv(queue_env)
|
|
85
47
|
prefetch = os.getenv(prefetch_env, 1)
|
|
86
|
-
vhost = os.getenv(vhost_env,
|
|
48
|
+
vhost = os.getenv(vhost_env, "/")
|
|
87
49
|
grpc = os.getenv(grpc_uri)
|
|
88
50
|
|
|
89
51
|
if not username or not password or not url or not queue or not grpc:
|
|
90
|
-
raise ValueError(
|
|
52
|
+
raise ValueError("Corrija as variáveis de ambiente!")
|
|
91
53
|
|
|
92
54
|
return cls(
|
|
93
55
|
credential=Credential(username=username, password=password),
|
|
@@ -98,105 +60,80 @@ class MessageConsumer:
|
|
|
98
60
|
grpc_uri=grpc,
|
|
99
61
|
)
|
|
100
62
|
|
|
101
|
-
def start_consume(self, process_message: Callable)
|
|
102
|
-
"""
|
|
103
|
-
Inicia o consumo de mensagens da fila RabbitMQ e processa cada mensagem usando a função fornecida.
|
|
104
|
-
|
|
105
|
-
Args:
|
|
106
|
-
process_message (Callable): Função de callback que processa cada mensagem recebida.
|
|
107
|
-
|
|
108
|
-
Raises:
|
|
109
|
-
pika.exceptions.StreamLostError: Se a conexão com o RabbitMQ for perdida, tentará reconectar automaticamente.
|
|
110
|
-
"""
|
|
63
|
+
async def start_consume(self, process_message: Callable):
|
|
111
64
|
try:
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
ch.basic_ack(delivery_tag=method.delivery_tag)
|
|
65
|
+
user = quote(self.__credentials.username)
|
|
66
|
+
pwd = quote(self.__credentials.password)
|
|
67
|
+
vhost = quote(self.__virtual_host)
|
|
68
|
+
uri = self.__amqp_url
|
|
69
|
+
amqp_url = f"amqp://{user}:{pwd}@{uri}/{vhost}"
|
|
70
|
+
connection = await aio_pika.connect_robust(amqp_url)
|
|
71
|
+
|
|
72
|
+
async with connection:
|
|
73
|
+
channel = await connection.channel()
|
|
74
|
+
await channel.set_qos(prefetch_count=self.__prefetch_count)
|
|
75
|
+
|
|
76
|
+
try:
|
|
77
|
+
queue = await channel.get_queue(self.__queue_consume, ensure=True)
|
|
78
|
+
except aio_pika.exceptions.ChannelNotFoundEntity:
|
|
79
|
+
arguments = {
|
|
80
|
+
"x-dead-letter-exchange": "log_error", # Dead Letter Exchange
|
|
81
|
+
"x-expires": 86400000, # Expiração da fila (em milissegundos)
|
|
82
|
+
"x-message-ttl": 300000 # Tempo de vida das mensagens (em milissegundos)
|
|
83
|
+
}
|
|
84
|
+
queue = await channel.declare_queue(self.__queue_consume, durable=True, arguments=arguments)
|
|
85
|
+
|
|
86
|
+
info("[x] Server inicializado! Aguardando solicitações RPC")
|
|
87
|
+
|
|
88
|
+
async for message in queue:
|
|
89
|
+
async with message.process():
|
|
90
|
+
await self.on_request(message.body, process_message)
|
|
91
|
+
except Exception as e:
|
|
92
|
+
print(f"Erro durante o consumo de mensagens: {e}")
|
|
93
|
+
# Reiniciar a conexão em caso de falha
|
|
94
|
+
# await self.start_consume(process_message)
|
|
95
|
+
|
|
96
|
+
async def on_request(self, body: bytes, process_message: Callable):
|
|
97
|
+
try:
|
|
98
|
+
message = body.decode()
|
|
99
|
+
message_json = json.loads(message)
|
|
100
|
+
pure_message = self.__transform_message(message_json)
|
|
101
|
+
await process_message(pure_message)
|
|
102
|
+
except Exception as e:
|
|
103
|
+
print(f"Erro ao processar mensagem: {e}")
|
|
152
104
|
|
|
153
105
|
def __transform_message(self, message: dict) -> UserCall:
|
|
154
|
-
""
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
message (dict): Dicionário contendo os dados da mensagem.
|
|
106
|
+
user_state = message.get("user_state", {})
|
|
107
|
+
observation = user_state.get("observation", {})
|
|
108
|
+
if isinstance(observation, str):
|
|
109
|
+
observation = json.loads(observation)
|
|
159
110
|
|
|
160
|
-
|
|
161
|
-
Message: Uma instância da classe Message com os dados extraídos do dicionário.
|
|
162
|
-
"""
|
|
163
|
-
|
|
164
|
-
user_state = message.get('user_state', {})
|
|
165
|
-
obs = user_state.get('obs', {})
|
|
166
|
-
if isinstance(obs, str):
|
|
167
|
-
obs = json.loads(obs)
|
|
168
|
-
|
|
169
|
-
return UserCall(
|
|
170
|
-
type=message.get('type', ''),
|
|
171
|
-
text=message.get('text', ''),
|
|
111
|
+
usercall = UserCall(
|
|
172
112
|
user_state=UserState(
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
113
|
+
chatID=ChatID(
|
|
114
|
+
user_id=user_state['chat_id'].get("user_id", ""),
|
|
115
|
+
company_id=user_state['chat_id'].get("company_id", ""),
|
|
116
|
+
),
|
|
117
|
+
menu=user_state.get("menu", ""),
|
|
118
|
+
route=user_state.get("route", ""),
|
|
119
|
+
protocol=user_state.get("protocol", ""),
|
|
120
|
+
observation=observation,
|
|
181
121
|
),
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
company_phone=message.get('company_phone', ''),
|
|
185
|
-
status=message.get('status'),
|
|
122
|
+
type_message=message.get("type_message", ""),
|
|
123
|
+
content_message=message.get("content_message", ""),
|
|
186
124
|
grpc_uri=self.__grpc_uri,
|
|
187
125
|
)
|
|
126
|
+
|
|
127
|
+
return usercall
|
|
188
128
|
|
|
189
129
|
def reprer(self):
|
|
190
130
|
console = Console()
|
|
191
131
|
|
|
192
|
-
# Título "ChatGraph" destacado em vermelho e negrito dentro de um painel
|
|
193
132
|
title_text = Text("ChatGraph", style="bold red", justify="center")
|
|
194
133
|
title_panel = Panel.fit(title_text, title=" ", border_style="bold red", padding=(1, 4))
|
|
195
134
|
|
|
196
|
-
# Linha separadora com emojis
|
|
197
135
|
separator = Text("🐇🐇🐇 RabbitMessageConsumer 📨📨📨", style="cyan", justify="center")
|
|
198
136
|
|
|
199
|
-
# Criação da tabela com os atributos
|
|
200
137
|
table = Table(show_header=True, header_style="bold magenta", title="RabbitMQ Consumer")
|
|
201
138
|
table.add_column("Atributo", justify="center", style="cyan", no_wrap=True)
|
|
202
139
|
table.add_column("Valor", justify="center", style="magenta")
|
|
@@ -206,9 +143,8 @@ class MessageConsumer:
|
|
|
206
143
|
table.add_row("Queue Consume", self.__queue_consume)
|
|
207
144
|
table.add_row("AMQP URL", self.__amqp_url)
|
|
208
145
|
table.add_row("Username", self.__credentials.username)
|
|
209
|
-
table.add_row("Password", "******")
|
|
146
|
+
table.add_row("Password", "******")
|
|
210
147
|
|
|
211
|
-
# Imprime o título, separador e a tabela centralizada
|
|
212
148
|
console.print(title_panel, justify="center")
|
|
213
149
|
console.print(separator, justify="center")
|
|
214
150
|
console.print(table, justify="center")
|