chatgraph 0.6.0__tar.gz → 0.6.2__tar.gz

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 (25) hide show
  1. {chatgraph-0.6.0 → chatgraph-0.6.2}/PKG-INFO +1 -1
  2. {chatgraph-0.6.0 → chatgraph-0.6.2}/chatgraph/__init__.py +2 -2
  3. {chatgraph-0.6.0 → chatgraph-0.6.2}/chatgraph/bot/chatbot_model.py +32 -2
  4. chatgraph-0.6.2/chatgraph/bot/default_functions.py +24 -0
  5. {chatgraph-0.6.0 → chatgraph-0.6.2}/chatgraph/gRPC/gRPCCall.py +57 -19
  6. {chatgraph-0.6.0 → chatgraph-0.6.2}/chatgraph/pb/router.proto +12 -5
  7. chatgraph-0.6.2/chatgraph/pb/router_pb2.py +79 -0
  8. {chatgraph-0.6.0 → chatgraph-0.6.2}/chatgraph/pb/router_pb2_grpc.py +47 -0
  9. {chatgraph-0.6.0 → chatgraph-0.6.2}/chatgraph/types/end_types.py +17 -2
  10. chatgraph-0.6.2/chatgraph/types/image.py +92 -0
  11. {chatgraph-0.6.0 → chatgraph-0.6.2}/chatgraph/types/request_types.py +42 -12
  12. {chatgraph-0.6.0 → chatgraph-0.6.2}/chatgraph/types/route.py +17 -12
  13. {chatgraph-0.6.0 → chatgraph-0.6.2}/pyproject.toml +1 -1
  14. chatgraph-0.6.0/chatgraph/pb/router_pb2.py +0 -81
  15. chatgraph-0.6.0/chatgraph/types/image.py +0 -36
  16. {chatgraph-0.6.0 → chatgraph-0.6.2}/LICENSE +0 -0
  17. {chatgraph-0.6.0 → chatgraph-0.6.2}/README.md +0 -0
  18. {chatgraph-0.6.0 → chatgraph-0.6.2}/chatgraph/auth/credentials.py +0 -0
  19. {chatgraph-0.6.0 → chatgraph-0.6.2}/chatgraph/bot/chatbot_router.py +0 -0
  20. {chatgraph-0.6.0 → chatgraph-0.6.2}/chatgraph/cli/__init__.py +0 -0
  21. {chatgraph-0.6.0 → chatgraph-0.6.2}/chatgraph/error/chatbot_error.py +0 -0
  22. {chatgraph-0.6.0 → chatgraph-0.6.2}/chatgraph/error/route_error.py +0 -0
  23. {chatgraph-0.6.0 → chatgraph-0.6.2}/chatgraph/messages/message_consumer.py +0 -0
  24. {chatgraph-0.6.0 → chatgraph-0.6.2}/chatgraph/types/background_task.py +0 -0
  25. {chatgraph-0.6.0 → chatgraph-0.6.2}/chatgraph/types/message_types.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: chatgraph
3
- Version: 0.6.0
3
+ Version: 0.6.2
4
4
  Summary: A user-friendly chatbot library
5
5
  Home-page: https://github.com/irissonnlima/chatgraph
6
6
  License: MIT
@@ -12,7 +12,7 @@ from .types.end_types import (
12
12
  from .types.message_types import Message, Button
13
13
  from .types.route import Route
14
14
  from .types.background_task import BackgroundTask
15
- from .types.image import ImageData, SendImage
15
+ from .types.image import ImageData, ImageMessage
16
16
 
17
17
  __all__ = [
18
18
  "ChatbotApp",
@@ -32,5 +32,5 @@ __all__ = [
32
32
  "Button",
33
33
  "BackgroundTask",
34
34
  "ImageData",
35
- "SendImage",
35
+ "ImageMessage",
36
36
  ]
@@ -2,6 +2,7 @@ import inspect
2
2
  from functools import wraps
3
3
  from logging import debug, error
4
4
  import asyncio
5
+ import re
5
6
 
6
7
  from ..error.chatbot_error import ChatbotMessageError
7
8
  from ..messages.message_consumer import MessageConsumer
@@ -16,6 +17,11 @@ from ..types.end_types import (
16
17
  from ..types.route import Route
17
18
  from .chatbot_router import ChatbotRouter
18
19
  from ..types.background_task import BackgroundTask
20
+ from .default_functions import voltar
21
+
22
+ DEFAULT_FUNCTION: dict[str, callable] = {
23
+ r"^\s*(voltar)\s*$": voltar,
24
+ }
19
25
 
20
26
 
21
27
  class ChatbotApp:
@@ -23,16 +29,22 @@ class ChatbotApp:
23
29
  Classe principal para a aplicação do chatbot, gerencia as rotas e a lógica de processamento de mensagens.
24
30
  """
25
31
 
26
- def __init__(self, message_consumer: MessageConsumer = None):
32
+ def __init__(
33
+ self,
34
+ message_consumer: MessageConsumer = None,
35
+ default_functions: dict[str, callable] = DEFAULT_FUNCTION,
36
+ ):
27
37
  """
28
38
  Inicializa a classe ChatbotApp com um estado de usuário e um consumidor de mensagens.
29
39
 
30
40
  Args:
31
41
  message_consumer (MessageConsumer): O consumidor de mensagens que lida com a entrada de mensagens no sistema.
42
+ default_functions (dict[str, callable]): Dicionário de funções padrão que podem ser usadas antes das rotas.
32
43
  """
33
44
  if not message_consumer:
34
45
  message_consumer = MessageConsumer.load_dotenv()
35
46
 
47
+ self.default_functions = default_functions
36
48
  self.__message_consumer = message_consumer
37
49
  self.__routes = {}
38
50
 
@@ -106,7 +118,20 @@ class ChatbotApp:
106
118
  route = userCall.route.lower()
107
119
  route_handler = route.split(".")[-1]
108
120
 
109
- handler = self.__routes.get(route_handler, None)
121
+ matchDefault = False
122
+
123
+ for regex, func in self.default_functions.items():
124
+ if re.match(regex, userCall.content_message):
125
+ matchDefault = True
126
+ debug(f"Função padrão encontrada: {func.__name__} para a rota {route}")
127
+ handler = {
128
+ "function": func,
129
+ "params": {UserCall: "userCall", Route: "route"},
130
+ }
131
+ break
132
+
133
+ if not matchDefault:
134
+ handler = self.__routes.get(route_handler, None)
110
135
 
111
136
  if not handler:
112
137
  raise ChatbotMessageError(user_id, f"Rota não encontrada para {route}!")
@@ -127,6 +152,9 @@ class ChatbotApp:
127
152
  loop = asyncio.get_running_loop()
128
153
  userCall_response = await loop.run_in_executor(None, lambda: func(**kwargs))
129
154
 
155
+ if matchDefault:
156
+ userCall.content_message = ""
157
+
130
158
  if isinstance(userCall_response, (list, tuple)):
131
159
  for response in userCall_response:
132
160
  await self.__process_func_response(response, userCall, route=route)
@@ -166,6 +194,7 @@ class ChatbotApp:
166
194
  userCall.end_chat,
167
195
  userCall_response.observations,
168
196
  userCall_response.tabulation_id,
197
+ userCall_response.tabulation_name,
169
198
  )
170
199
  return
171
200
 
@@ -175,6 +204,7 @@ class ChatbotApp:
175
204
  userCall.transfer_to_human,
176
205
  userCall_response.observations,
177
206
  userCall_response.campaign_id,
207
+ userCall_response.campaign_name,
178
208
  )
179
209
  return
180
210
 
@@ -0,0 +1,24 @@
1
+ from ..types.request_types import UserCall
2
+ from ..types.message_types import Message, Button
3
+ from ..types.end_types import (
4
+ RedirectResponse,
5
+ EndChatResponse,
6
+ TransferToHuman,
7
+ TransferToMenu,
8
+ )
9
+ from ..types.route import Route
10
+
11
+
12
+ async def voltar(route: Route, userCall: UserCall) -> tuple:
13
+ """
14
+ Função para voltar à rota anterior.
15
+ Args:
16
+ route (Route): A rota atual do chatbot.
17
+ usercall (UserCall): O objeto UserCall associado à chamada do usuário.
18
+ """
19
+
20
+ previous = route.get_previous()
21
+ userCall.console.print(
22
+ f"Voltando rota. ({route.current}) -> ({previous.current})", style="bold yellow"
23
+ )
24
+ return RedirectResponse(previous.current_node)
@@ -1,6 +1,7 @@
1
1
  import os
2
2
  import grpc
3
3
  import json
4
+ from rich.console import Console
4
5
 
5
6
  import chatgraph.pb.router_pb2 as chatbot_pb2
6
7
  import chatgraph.pb.router_pb2_grpc as chatbot_pb2_grpc
@@ -22,15 +23,22 @@ class RouterServiceClient:
22
23
  self.transfer_stub = chatbot_pb2_grpc.TransferStub(self.channel)
23
24
  self.end_chat_stub = chatbot_pb2_grpc.EndChatStub(self.channel)
24
25
 
26
+ self.console = Console()
27
+
25
28
  def insert_update_user_state(self, user_state_data):
26
29
  request = chatbot_pb2.UserState(**user_state_data)
27
30
  try:
28
31
  response = self.user_state_stub.InsertUpdateUserState(request)
29
32
  if not response.status:
30
- print(f"Erro ao chamar SendMessage: {response.message}")
33
+ self.console.print(
34
+ f"Erro ao chamar InsertUpdateUserState: {response.message}",
35
+ style="bold red",
36
+ )
31
37
  return response
32
38
  except grpc.RpcError as e:
33
- print(f"Erro ao chamar InsertUpdateUserState: {e}")
39
+ self.console.print(
40
+ f"Erro ao chamar InsertUpdateUserState: {e}", style="bold red"
41
+ )
34
42
  return None
35
43
 
36
44
  def delete_user_state(self, chat_id_data):
@@ -38,10 +46,12 @@ class RouterServiceClient:
38
46
  try:
39
47
  response = self.user_state_stub.DeleteUserState(request)
40
48
  if not response.status:
41
- print(f"Erro ao chamar SendMessage: {response.message}")
49
+ self.console.print(
50
+ f"Erro ao chamar SendMessage: {response.message}", style="bold red"
51
+ )
42
52
  return response
43
53
  except grpc.RpcError as e:
44
- print(f"Erro ao chamar DeleteUserState: {e}")
54
+ self.console.print(f"Erro ao chamar DeleteUserState: {e}", style="bold red")
45
55
  return None
46
56
 
47
57
  def get_user_state(self, chat_id_data):
@@ -50,7 +60,7 @@ class RouterServiceClient:
50
60
  response = self.user_state_stub.GetUserState(request)
51
61
  return response
52
62
  except grpc.RpcError as e:
53
- print(f"Erro ao chamar GetUserState: {e}")
63
+ self.console.print(f"Erro ao chamar GetUserState: {e}", style="bold red")
54
64
  return None
55
65
 
56
66
  def send_message(self, message_data):
@@ -61,10 +71,12 @@ class RouterServiceClient:
61
71
  try:
62
72
  response = self.send_message_stub.SendMessage(request)
63
73
  if not response.status:
64
- print(f"Erro ao chamar SendMessage: {response.message}")
74
+ self.console.print(
75
+ f"Erro ao chamar SendMessage: {response.message}", style="bold red"
76
+ )
65
77
  return response
66
78
  except grpc.RpcError as e:
67
- print(f"Erro ao chamar SendMessage: {e}")
79
+ self.console.print(f"Erro ao chamar SendMessage: {e}", style="bold red")
68
80
  return None
69
81
 
70
82
  def send_image(self, message_data):
@@ -74,11 +86,28 @@ class RouterServiceClient:
74
86
 
75
87
  try:
76
88
  response = self.send_message_stub.SendImage(request)
89
+ if not response.status and response.message != "arquivo não encontrado":
90
+ self.console.print(
91
+ f"Erro ao chamar SendImage: {response.message}", style="bold red"
92
+ )
93
+ elif response.message == "arquivo não encontrado":
94
+ print("Arquivo não encontrado, Carregando arquivo...")
95
+ return response
96
+ except grpc.RpcError as e:
97
+ self.console.print(f"Erro ao chamar SendImage: {e}", style="bold red")
98
+ return None
99
+
100
+ def upload_file(self, file_data):
101
+ request = chatbot_pb2.UploadFileRequest(**file_data)
102
+ try:
103
+ response = self.send_message_stub.UploadFile(request)
77
104
  if not response.status:
78
- print(f"Erro ao chamar SendImage: {response.message}")
105
+ self.console.print(
106
+ f"Erro ao chamar UploadFile: {response.message}", style="bold red"
107
+ )
79
108
  return response
80
109
  except grpc.RpcError as e:
81
- print(f"Erro ao chamar SendImage: {e}")
110
+ self.console.print(f"Erro ao chamar UploadFile: {e}", style="bold red")
82
111
  return None
83
112
 
84
113
  def transfer_to_human(self, transfer_request_data):
@@ -86,10 +115,12 @@ class RouterServiceClient:
86
115
  try:
87
116
  response = self.transfer_stub.TransferToHuman(request)
88
117
  if not response.status:
89
- print(f"Erro ao chamar SendMessage: {response.message}")
118
+ self.console.print(
119
+ f"Erro ao chamar SendMessage: {response.message}", style="bold red"
120
+ )
90
121
  return response
91
122
  except grpc.RpcError as e:
92
- print(f"Erro ao chamar TransferToHuman: {e}")
123
+ self.console.print(f"Erro ao chamar TransferToHuman: {e}", style="bold red")
93
124
  return None
94
125
 
95
126
  def transfer_to_menu(self, transfer_request_data):
@@ -97,10 +128,13 @@ class RouterServiceClient:
97
128
  try:
98
129
  response = self.transfer_stub.TransferToMenu(request)
99
130
  if not response.status:
100
- print(f"Erro ao chamar TransferToMenu: {response.message}")
131
+ self.console.print(
132
+ f"Erro ao chamar TransferToMenu: {response.message}",
133
+ style="bold red",
134
+ )
101
135
  return response
102
136
  except grpc.RpcError as e:
103
- print(f"Erro ao chamar TransferToMenu: {e}")
137
+ self.console.print(f"Erro ao chamar TransferToMenu: {e}", style="bold red")
104
138
  return None
105
139
 
106
140
  def end_chat(self, end_chat_request_data):
@@ -108,10 +142,12 @@ class RouterServiceClient:
108
142
  try:
109
143
  response = self.end_chat_stub.EndChat(request)
110
144
  if not response.status:
111
- print(f"Erro ao chamar SendMessage: {response.message}")
145
+ self.console.print(
146
+ f"Erro ao chamar SendMessage: {response.message}", style="bold red"
147
+ )
112
148
  return response
113
149
  except grpc.RpcError as e:
114
- print(f"Erro ao chamar EndChat: {e}")
150
+ self.console.print(f"Erro ao chamar EndChat: {e}", style="bold red")
115
151
  return None
116
152
 
117
153
  def get_campaign_id(self, campaign_name):
@@ -120,7 +156,7 @@ class RouterServiceClient:
120
156
  response = self.transfer_stub.GetCampaignID(request)
121
157
  return response
122
158
  except grpc.RpcError as e:
123
- print(f"Erro ao chamar GetCampaignID: {e}")
159
+ self.console.print(f"Erro ao chamar GetCampaignID: {e}", style="bold red")
124
160
  return None
125
161
 
126
162
  def get_all_campaigns(self):
@@ -129,7 +165,7 @@ class RouterServiceClient:
129
165
  response = self.transfer_stub.GetAllCampaigns(request)
130
166
  return response
131
167
  except grpc.RpcError as e:
132
- print(f"Erro ao chamar GetAllCampaigns: {e}")
168
+ self.console.print(f"Erro ao chamar GetAllCampaigns: {e}", style="bold red")
133
169
  return None
134
170
 
135
171
  def get_tabulation_id(self, tabulation_name):
@@ -138,7 +174,7 @@ class RouterServiceClient:
138
174
  response = self.end_chat_stub.GetTabulationID(request)
139
175
  return response
140
176
  except grpc.RpcError as e:
141
- print(f"Erro ao chamar GetTabulationID: {e}")
177
+ self.console.print(f"Erro ao chamar GetTabulationID: {e}", style="bold red")
142
178
  return None
143
179
 
144
180
  def get_all_tabulations(self):
@@ -147,5 +183,7 @@ class RouterServiceClient:
147
183
  response = self.end_chat_stub.GetAllTabulations(request)
148
184
  return response
149
185
  except grpc.RpcError as e:
150
- print(f"Erro ao chamar GetAllTabulations: {e}")
186
+ self.console.print(
187
+ f"Erro ao chamar GetAllTabulations: {e}", style="bold red"
188
+ )
151
189
  return None
@@ -7,6 +7,7 @@ option go_package = "./chatbot";
7
7
  ///// Serviços de Estado do Usuário /////
8
8
  service UserStateService {
9
9
  rpc InsertUpdateUserState(UserState) returns (RequestStatus);
10
+ rpc SetRoute(RouteRequest) returns (RequestStatus);
10
11
  rpc DeleteUserState(ChatID) returns (RequestStatus);
11
12
  rpc GetUserState(ChatID) returns (UserState);
12
13
  rpc GetAllUserStates(Void) returns (UserStateList);
@@ -60,6 +61,10 @@ message UserStateList {
60
61
  repeated UserState user_states = 1;
61
62
  }
62
63
 
64
+ message RouteRequest {
65
+ ChatID chat_id = 1;
66
+ string route = 2;
67
+ }
63
68
  ///// Mensagens para Serviços de Mensagens /////
64
69
  message TextMessage {
65
70
  string type = 1;
@@ -89,10 +94,11 @@ message FileMessage {
89
94
  }
90
95
 
91
96
  message UploadFileRequest {
92
- string file_id = 1;
93
- string file_url = 2;
94
- string file_type = 3;
95
- bytes file_content = 4;
97
+ string file_url = 1;
98
+ string file_type = 2;
99
+ string file_extension = 3;
100
+ string expiration = 4;
101
+ bytes file_content = 5;
96
102
  }
97
103
 
98
104
  ///// Mensagens para Serviços de Transfer /////
@@ -105,7 +111,8 @@ message TransferToHumanRequest{
105
111
  message TransferToMenuRequest{
106
112
  ChatID chat_id = 1;
107
113
  string menu = 2;
108
- string user_message = 3;
114
+ string route = 3;
115
+ string user_message = 4;
109
116
  }
110
117
 
111
118
  message TabulationName{
@@ -0,0 +1,79 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
3
+ # NO CHECKED-IN PROTOBUF GENCODE
4
+ # source: router.proto
5
+ # Protobuf Python Version: 6.31.0
6
+ """Generated protocol buffer code."""
7
+ from google.protobuf import descriptor as _descriptor
8
+ from google.protobuf import descriptor_pool as _descriptor_pool
9
+ from google.protobuf import runtime_version as _runtime_version
10
+ from google.protobuf import symbol_database as _symbol_database
11
+ from google.protobuf.internal import builder as _builder
12
+
13
+ _runtime_version.ValidateProtobufRuntimeVersion(
14
+ _runtime_version.Domain.PUBLIC, 6, 31, 0, "", "router.proto"
15
+ )
16
+ # @@protoc_insertion_point(imports)
17
+
18
+ _sym_db = _symbol_database.Default()
19
+
20
+
21
+ DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(
22
+ b'\n\x0crouter.proto\x12\x07\x63hatbot"\x06\n\x04Void"0\n\rRequestStatus\x12\x0e\n\x06status\x18\x01 \x01(\x08\x12\x0f\n\x07message\x18\x02 \x01(\t"-\n\x06\x43hatID\x12\x0f\n\x07user_id\x18\x01 \x01(\t\x12\x12\n\ncompany_id\x18\x02 \x01(\t"q\n\tUserState\x12 \n\x07\x63hat_id\x18\x01 \x01(\x0b\x32\x0f.chatbot.ChatID\x12\x0c\n\x04menu\x18\x02 \x01(\t\x12\r\n\x05route\x18\x03 \x01(\t\x12\x10\n\x08protocol\x18\x04 \x01(\t\x12\x13\n\x0bobservation\x18\x05 \x01(\t"8\n\rUserStateList\x12\'\n\x0buser_states\x18\x01 \x03(\x0b\x32\x12.chatbot.UserState"?\n\x0cRouteRequest\x12 \n\x07\x63hat_id\x18\x01 \x01(\x0b\x32\x0f.chatbot.ChatID\x12\r\n\x05route\x18\x02 \x01(\t"j\n\x0bTextMessage\x12\x0c\n\x04type\x18\x01 \x01(\t\x12\x0b\n\x03url\x18\x02 \x01(\t\x12\x10\n\x08\x66ilename\x18\x03 \x01(\t\x12\r\n\x05title\x18\x04 \x01(\t\x12\x0e\n\x06\x64\x65tail\x18\x05 \x01(\t\x12\x0f\n\x07\x63\x61ption\x18\x06 \x01(\t"5\n\x06\x42utton\x12\x0c\n\x04type\x18\x01 \x01(\t\x12\r\n\x05title\x18\x02 \x01(\t\x12\x0e\n\x06\x64\x65tail\x18\x03 \x01(\t"\x9d\x01\n\x07Message\x12 \n\x07\x63hat_id\x18\x01 \x01(\x0b\x32\x0f.chatbot.ChatID\x12%\n\x07message\x18\x02 \x01(\x0b\x32\x14.chatbot.TextMessage\x12 \n\x07\x62uttons\x18\x03 \x03(\x0b\x32\x0f.chatbot.Button\x12\'\n\x0e\x64isplay_button\x18\x04 \x01(\x0b\x32\x0f.chatbot.Button"A\n\x0b\x46ileMessage\x12!\n\x07message\x18\x01 \x01(\x0b\x32\x10.chatbot.Message\x12\x0f\n\x07\x66ile_id\x18\x02 \x01(\t"z\n\x11UploadFileRequest\x12\x10\n\x08\x66ile_url\x18\x01 \x01(\t\x12\x11\n\tfile_type\x18\x02 \x01(\t\x12\x16\n\x0e\x66ile_extension\x18\x03 \x01(\t\x12\x12\n\nexpiration\x18\x04 \x01(\t\x12\x14\n\x0c\x66ile_content\x18\x05 \x01(\x0c"d\n\x16TransferToHumanRequest\x12 \n\x07\x63hat_id\x18\x01 \x01(\x0b\x32\x0f.chatbot.ChatID\x12\x13\n\x0b\x63\x61mpaign_id\x18\x02 \x01(\t\x12\x13\n\x0bobservation\x18\x03 \x01(\t"l\n\x15TransferToMenuRequest\x12 \n\x07\x63hat_id\x18\x01 \x01(\x0b\x32\x0f.chatbot.ChatID\x12\x0c\n\x04menu\x18\x02 \x01(\t\x12\r\n\x05route\x18\x03 \x01(\t\x12\x14\n\x0cuser_message\x18\x04 \x01(\t"\x1e\n\x0eTabulationName\x12\x0c\n\x04name\x18\x01 \x01(\t"B\n\x11TabulationDetails\x12\n\n\x02id\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x13\n\x0blast_update\x18\x03 \x01(\t"B\n\x0fTabulationsList\x12/\n\x0btabulations\x18\x01 \x03(\x0b\x32\x1a.chatbot.TabulationDetails"^\n\x0e\x45ndChatRequest\x12 \n\x07\x63hat_id\x18\x01 \x01(\x0b\x32\x0f.chatbot.ChatID\x12\x15\n\rtabulation_id\x18\x02 \x01(\t\x12\x13\n\x0bobservation\x18\x03 \x01(\t"\x1c\n\x0c\x43\x61mpaignName\x12\x0c\n\x04name\x18\x01 \x01(\t"@\n\x0f\x43\x61mpaignDetails\x12\n\n\x02id\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x13\n\x0blast_update\x18\x03 \x01(\t"<\n\rCampaignsList\x12+\n\tcampaigns\x18\x01 \x03(\x0b\x32\x18.chatbot.CampaignDetails2\xbe\x02\n\x10UserStateService\x12\x43\n\x15InsertUpdateUserState\x12\x12.chatbot.UserState\x1a\x16.chatbot.RequestStatus\x12\x39\n\x08SetRoute\x12\x15.chatbot.RouteRequest\x1a\x16.chatbot.RequestStatus\x12:\n\x0f\x44\x65leteUserState\x12\x0f.chatbot.ChatID\x1a\x16.chatbot.RequestStatus\x12\x33\n\x0cGetUserState\x12\x0f.chatbot.ChatID\x1a\x12.chatbot.UserState\x12\x39\n\x10GetAllUserStates\x12\r.chatbot.Void\x1a\x16.chatbot.UserStateList2\xfd\x01\n\x0bSendMessage\x12\x37\n\x0bSendMessage\x12\x10.chatbot.Message\x1a\x16.chatbot.RequestStatus\x12\x39\n\tSendImage\x12\x14.chatbot.FileMessage\x1a\x16.chatbot.RequestStatus\x12\x38\n\x08SendFile\x12\x14.chatbot.FileMessage\x1a\x16.chatbot.RequestStatus\x12@\n\nUploadFile\x12\x1a.chatbot.UploadFileRequest\x1a\x16.chatbot.RequestStatus2\x9c\x02\n\x08Transfer\x12\x38\n\x0fGetAllCampaigns\x12\r.chatbot.Void\x1a\x16.chatbot.CampaignsList\x12@\n\rGetCampaignID\x12\x15.chatbot.CampaignName\x1a\x18.chatbot.CampaignDetails\x12J\n\x0fTransferToHuman\x12\x1f.chatbot.TransferToHumanRequest\x1a\x16.chatbot.RequestStatus\x12H\n\x0eTransferToMenu\x12\x1e.chatbot.TransferToMenuRequest\x1a\x16.chatbot.RequestStatus2\xcb\x01\n\x07\x45ndChat\x12<\n\x11GetAllTabulations\x12\r.chatbot.Void\x1a\x18.chatbot.TabulationsList\x12\x46\n\x0fGetTabulationID\x12\x17.chatbot.TabulationName\x1a\x1a.chatbot.TabulationDetails\x12:\n\x07\x45ndChat\x12\x17.chatbot.EndChatRequest\x1a\x16.chatbot.RequestStatusB\x0bZ\t./chatbotb\x06proto3'
23
+ )
24
+
25
+ _globals = globals()
26
+ _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
27
+ _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, "router_pb2", _globals)
28
+ if not _descriptor._USE_C_DESCRIPTORS:
29
+ _globals["DESCRIPTOR"]._loaded_options = None
30
+ _globals["DESCRIPTOR"]._serialized_options = b"Z\t./chatbot"
31
+ _globals["_VOID"]._serialized_start = 25
32
+ _globals["_VOID"]._serialized_end = 31
33
+ _globals["_REQUESTSTATUS"]._serialized_start = 33
34
+ _globals["_REQUESTSTATUS"]._serialized_end = 81
35
+ _globals["_CHATID"]._serialized_start = 83
36
+ _globals["_CHATID"]._serialized_end = 128
37
+ _globals["_USERSTATE"]._serialized_start = 130
38
+ _globals["_USERSTATE"]._serialized_end = 243
39
+ _globals["_USERSTATELIST"]._serialized_start = 245
40
+ _globals["_USERSTATELIST"]._serialized_end = 301
41
+ _globals["_ROUTEREQUEST"]._serialized_start = 303
42
+ _globals["_ROUTEREQUEST"]._serialized_end = 366
43
+ _globals["_TEXTMESSAGE"]._serialized_start = 368
44
+ _globals["_TEXTMESSAGE"]._serialized_end = 474
45
+ _globals["_BUTTON"]._serialized_start = 476
46
+ _globals["_BUTTON"]._serialized_end = 529
47
+ _globals["_MESSAGE"]._serialized_start = 532
48
+ _globals["_MESSAGE"]._serialized_end = 689
49
+ _globals["_FILEMESSAGE"]._serialized_start = 691
50
+ _globals["_FILEMESSAGE"]._serialized_end = 756
51
+ _globals["_UPLOADFILEREQUEST"]._serialized_start = 758
52
+ _globals["_UPLOADFILEREQUEST"]._serialized_end = 880
53
+ _globals["_TRANSFERTOHUMANREQUEST"]._serialized_start = 882
54
+ _globals["_TRANSFERTOHUMANREQUEST"]._serialized_end = 982
55
+ _globals["_TRANSFERTOMENUREQUEST"]._serialized_start = 984
56
+ _globals["_TRANSFERTOMENUREQUEST"]._serialized_end = 1092
57
+ _globals["_TABULATIONNAME"]._serialized_start = 1094
58
+ _globals["_TABULATIONNAME"]._serialized_end = 1124
59
+ _globals["_TABULATIONDETAILS"]._serialized_start = 1126
60
+ _globals["_TABULATIONDETAILS"]._serialized_end = 1192
61
+ _globals["_TABULATIONSLIST"]._serialized_start = 1194
62
+ _globals["_TABULATIONSLIST"]._serialized_end = 1260
63
+ _globals["_ENDCHATREQUEST"]._serialized_start = 1262
64
+ _globals["_ENDCHATREQUEST"]._serialized_end = 1356
65
+ _globals["_CAMPAIGNNAME"]._serialized_start = 1358
66
+ _globals["_CAMPAIGNNAME"]._serialized_end = 1386
67
+ _globals["_CAMPAIGNDETAILS"]._serialized_start = 1388
68
+ _globals["_CAMPAIGNDETAILS"]._serialized_end = 1452
69
+ _globals["_CAMPAIGNSLIST"]._serialized_start = 1454
70
+ _globals["_CAMPAIGNSLIST"]._serialized_end = 1514
71
+ _globals["_USERSTATESERVICE"]._serialized_start = 1517
72
+ _globals["_USERSTATESERVICE"]._serialized_end = 1835
73
+ _globals["_SENDMESSAGE"]._serialized_start = 1838
74
+ _globals["_SENDMESSAGE"]._serialized_end = 2091
75
+ _globals["_TRANSFER"]._serialized_start = 2094
76
+ _globals["_TRANSFER"]._serialized_end = 2378
77
+ _globals["_ENDCHAT"]._serialized_start = 2381
78
+ _globals["_ENDCHAT"]._serialized_end = 2584
79
+ # @@protoc_insertion_point(module_scope)
@@ -43,6 +43,12 @@ class UserStateServiceStub(object):
43
43
  response_deserializer=router__pb2.RequestStatus.FromString,
44
44
  _registered_method=True,
45
45
  )
46
+ self.SetRoute = channel.unary_unary(
47
+ "/chatbot.UserStateService/SetRoute",
48
+ request_serializer=router__pb2.RouteRequest.SerializeToString,
49
+ response_deserializer=router__pb2.RequestStatus.FromString,
50
+ _registered_method=True,
51
+ )
46
52
  self.DeleteUserState = channel.unary_unary(
47
53
  "/chatbot.UserStateService/DeleteUserState",
48
54
  request_serializer=router__pb2.ChatID.SerializeToString,
@@ -72,6 +78,12 @@ class UserStateServiceServicer(object):
72
78
  context.set_details("Method not implemented!")
73
79
  raise NotImplementedError("Method not implemented!")
74
80
 
81
+ def SetRoute(self, request, context):
82
+ """Missing associated documentation comment in .proto file."""
83
+ context.set_code(grpc.StatusCode.UNIMPLEMENTED)
84
+ context.set_details("Method not implemented!")
85
+ raise NotImplementedError("Method not implemented!")
86
+
75
87
  def DeleteUserState(self, request, context):
76
88
  """Missing associated documentation comment in .proto file."""
77
89
  context.set_code(grpc.StatusCode.UNIMPLEMENTED)
@@ -98,6 +110,11 @@ def add_UserStateServiceServicer_to_server(servicer, server):
98
110
  request_deserializer=router__pb2.UserState.FromString,
99
111
  response_serializer=router__pb2.RequestStatus.SerializeToString,
100
112
  ),
113
+ "SetRoute": grpc.unary_unary_rpc_method_handler(
114
+ servicer.SetRoute,
115
+ request_deserializer=router__pb2.RouteRequest.FromString,
116
+ response_serializer=router__pb2.RequestStatus.SerializeToString,
117
+ ),
101
118
  "DeleteUserState": grpc.unary_unary_rpc_method_handler(
102
119
  servicer.DeleteUserState,
103
120
  request_deserializer=router__pb2.ChatID.FromString,
@@ -157,6 +174,36 @@ class UserStateService(object):
157
174
  _registered_method=True,
158
175
  )
159
176
 
177
+ @staticmethod
178
+ def SetRoute(
179
+ request,
180
+ target,
181
+ options=(),
182
+ channel_credentials=None,
183
+ call_credentials=None,
184
+ insecure=False,
185
+ compression=None,
186
+ wait_for_ready=None,
187
+ timeout=None,
188
+ metadata=None,
189
+ ):
190
+ return grpc.experimental.unary_unary(
191
+ request,
192
+ target,
193
+ "/chatbot.UserStateService/SetRoute",
194
+ router__pb2.RouteRequest.SerializeToString,
195
+ router__pb2.RequestStatus.FromString,
196
+ options,
197
+ channel_credentials,
198
+ insecure,
199
+ call_credentials,
200
+ compression,
201
+ wait_for_ready,
202
+ timeout,
203
+ metadata,
204
+ _registered_method=True,
205
+ )
206
+
160
207
  @staticmethod
161
208
  def DeleteUserState(
162
209
  request,
@@ -25,11 +25,20 @@ class EndChatResponse:
25
25
  observations (str): As observações finais do chatbot.
26
26
  """
27
27
 
28
- def __init__(self, tabulation_id: str, observations: str) -> None:
28
+ def __init__(
29
+ self,
30
+ tabulation_id: str,
31
+ tabulation_name: str | None = None,
32
+ observations: str | None = None,
33
+ ) -> None:
29
34
  """
30
35
  Finzaliza e tabula as informações do chatbot.
31
36
  """
37
+ if not tabulation_id and not tabulation_name:
38
+ raise ValueError("tabulation_id or tabulation_name must be provided.")
39
+
32
40
  self.tabulation_id = tabulation_id
41
+ self.tabulation_name = tabulation_name
33
42
  self.observations = observations
34
43
 
35
44
 
@@ -38,11 +47,17 @@ class TransferToHuman:
38
47
  Representa uma transferencia para um atendente humano.
39
48
  """
40
49
 
41
- def __init__(self, campaign_id: str, observations: str) -> None:
50
+ def __init__(
51
+ self,
52
+ campaign_id: str,
53
+ campaign_name: str | None = None,
54
+ observations: str | None = None,
55
+ ) -> None:
42
56
  """
43
57
  Finzaliza e tabula as informações do chatbot.
44
58
  """
45
59
  self.campaign_id = campaign_id
60
+ self.campaign_name = campaign_name
46
61
  self.observations = observations
47
62
 
48
63
 
@@ -0,0 +1,92 @@
1
+ from datetime import datetime, timedelta
2
+ import hashlib
3
+ import base64
4
+ from chatgraph.types.message_types import Message
5
+
6
+
7
+ class ImageData:
8
+ """
9
+ Representa dados de uma imagem, seja por URL ou arquivo local. Caso fornecido um url e um caminho de arquivo, o url será utilizado.
10
+ Atributos:
11
+ type (str): Tipo de imagem, "link" para URL ou "file" para arquivo local.
12
+ url (str): URL da imagem, se aplicável.
13
+ image_path (str): Caminho do arquivo de imagem, se aplicável.
14
+ expiration (int): Tempo de expiração em minutos, 0 para sem expiração.
15
+ """
16
+
17
+ def __init__(self, *, url: str = None, image_path: str = None, expiration: int = 0):
18
+
19
+ if not url and not image_path:
20
+ raise ValueError("URL or image path must be provided.")
21
+
22
+ self.type = "link" if url else "file"
23
+ self.url = url
24
+ self.expiration = expiration
25
+
26
+ self.image_bytes = None
27
+ self.file_extension = None
28
+ if self.type == "file":
29
+ if not image_path:
30
+ raise ValueError("Image path must be provided for file type.")
31
+ self.file_extension = image_path.split(".")[-1]
32
+ with open(image_path, "rb") as f:
33
+ self.image_bytes = f.read()
34
+
35
+ # Create hash of image bytes if available, otherwise use URL
36
+ hash_input = self.image_bytes if self.image_bytes else url.encode("utf-8")
37
+
38
+ # Create SHA-256 hash and encode in base64
39
+ self.image_id = base64.b64encode(hashlib.sha256(hash_input).digest()).decode(
40
+ "utf-8"
41
+ )
42
+
43
+ def get_upload_dict(self):
44
+ dict_data = {}
45
+ if self.expiration > 0:
46
+ now = datetime.now()
47
+ expiration_time = now + timedelta(minutes=self.expiration)
48
+ dict_data["expiration"] = expiration_time.strftime("%Y-%m-%d %H:%M:%S")
49
+
50
+ if self.type == "file":
51
+ dict_data["file_type"] = self.type
52
+ dict_data["file_content"] = self.image_bytes
53
+ dict_data["file_extension"] = self.file_extension
54
+ else:
55
+ dict_data["file_type"] = self.type
56
+ dict_data["file_url"] = self.url
57
+
58
+ return dict_data
59
+
60
+ def get_dict(self):
61
+ dict_data = {
62
+ "image_id": self.image_id,
63
+ "file_type": self.type,
64
+ }
65
+ if self.type == "file":
66
+ dict_data["file_content"] = self.image_bytes
67
+ dict_data["file_extension"] = self.file_extension
68
+ else:
69
+ dict_data["file_url"] = self.url
70
+ return dict_data
71
+
72
+
73
+ class ImageMessage:
74
+ def __init__(self, image: ImageData, message: Message = None):
75
+ if not isinstance(image, ImageData):
76
+ raise TypeError("Expected an instance of ImageData.")
77
+
78
+ self.type = "image"
79
+ self.image = image
80
+ self.message = message
81
+
82
+ def to_dict(self):
83
+ if not self.message:
84
+ return {
85
+ "file_id": self.image.image_id,
86
+ "message": {},
87
+ }
88
+
89
+ return {
90
+ "file_id": self.image.image_id,
91
+ "message": self.message.to_dict(),
92
+ }
@@ -1,9 +1,10 @@
1
1
  from chatgraph.gRPC.gRPCCall import RouterServiceClient
2
- from chatgraph.types.image import ImageData, SendImage
2
+ from chatgraph.types.image import ImageData, ImageMessage
3
3
  from chatgraph.types.message_types import Message, Button, MessageTypes, messageTypes
4
4
  from typing import Optional
5
5
  from datetime import datetime
6
6
  import json, os
7
+ from rich.console import Console
7
8
 
8
9
 
9
10
  class ChatID:
@@ -155,6 +156,7 @@ class UserCall:
155
156
  self.__grpc_uri = grpc_uri
156
157
 
157
158
  self.__router_client = RouterServiceClient(self.__grpc_uri)
159
+ self.console = Console()
158
160
 
159
161
  def __str__(self):
160
162
  return f"UserCall({self.type}, {self.__type_message}, {self.__content_message}, {self.__user_state})"
@@ -176,25 +178,37 @@ class UserCall:
176
178
  )
177
179
 
178
180
  if isinstance(message, ImageData):
179
- message = SendImage(
181
+ message = ImageMessage(
180
182
  image=message,
181
- message=Message(type="message", detail=""),
182
183
  )
183
184
 
184
185
  if isinstance(message, Message):
185
186
  self.__send(message)
186
- elif isinstance(message, SendImage):
187
+ elif isinstance(message, ImageMessage):
187
188
  self.__send_image(message)
188
189
  else:
189
190
  raise ValueError("Tipo de mensagem inválido.")
190
191
 
191
- def __send_image(self, message: SendImage) -> None:
192
+ def __upload_file(self, image: ImageData) -> None:
193
+ dict_image = image.get_upload_dict()
194
+ response = self.__router_client.upload_file(dict_image)
195
+
196
+ if not response.status:
197
+ raise ValueError("Erro ao fazer upload do arquivo.")
198
+ else:
199
+ print("Arquivo enviado com sucesso.")
200
+
201
+ def __send_image(self, message: ImageMessage) -> None:
192
202
  dict_message = message.to_dict()
193
203
  dict_message["message"]["chat_id"] = self.__user_state.chatID.to_dict()
194
204
  response = self.__router_client.send_image(dict_message)
195
205
 
196
- if not response.status:
206
+ if not response.status and response.message != "arquivo não encontrado":
197
207
  raise ValueError("Erro ao enviar imagem.")
208
+ elif response.message == "arquivo não encontrado":
209
+ self.__upload_file(message.image)
210
+ print("tentando enviar imagem novamente...")
211
+ self.__send_image(message)
198
212
 
199
213
  def __send(self, message: Message) -> None:
200
214
 
@@ -208,14 +222,20 @@ class UserCall:
208
222
  if not response.status:
209
223
  raise ValueError("Erro ao enviar mensagem de botões.")
210
224
 
211
- def transfer_to_human(self, message: str, campaign_name: str) -> None:
225
+ def transfer_to_human(
226
+ self, message: str, campaign_id: str = None, campaign_name: str = None
227
+ ) -> None:
212
228
 
213
- campaign = self.__router_client.get_campaign_id({"name": campaign_name})
229
+ if campaign_id is None and campaign_name is None:
230
+ raise ValueError("Você deve informar o ID ou o nome da campanha.")
231
+ if not campaign_id:
232
+ campaign = self.__router_client.get_campaign_id({"name": campaign_name})
233
+ campaign_id = campaign.id
214
234
 
215
235
  response = self.__router_client.transfer_to_human(
216
236
  {
217
237
  "chat_id": self.__user_state.chatID.to_dict(),
218
- "campaign_id": campaign.id,
238
+ "campaign_id": campaign_id,
219
239
  "observation": message,
220
240
  }
221
241
  )
@@ -236,13 +256,19 @@ class UserCall:
236
256
  if not response.status:
237
257
  raise ValueError("Erro ao transferir chat para menu.")
238
258
 
239
- def end_chat(self, message: str, tabulation_name: str) -> None:
240
- tabulation = self.__router_client.get_tabulation_id({"name": tabulation_name})
259
+ def end_chat(self, message: str, tabulation_id: str, tabulation_name: str) -> None:
260
+ if tabulation_id is None and tabulation_name is None:
261
+ raise ValueError("Você deve informar o ID ou o nome da tabulação.")
262
+ if not tabulation_id:
263
+ tabulation = self.__router_client.get_tabulation_id(
264
+ {"name": tabulation_name}
265
+ )
266
+ tabulation_id = tabulation.id
241
267
 
242
268
  response = self.__router_client.end_chat(
243
269
  {
244
270
  "chat_id": self.__user_state.chatID.to_dict(),
245
- "tabulation_id": tabulation.id,
271
+ "tabulation_id": tabulation_id,
246
272
  "observation": message,
247
273
  }
248
274
  )
@@ -328,3 +354,7 @@ class UserCall:
328
354
  self.update_user_state(
329
355
  self.__user_state.menu, self.__user_state.route, observation
330
356
  )
357
+
358
+ @content_message.setter
359
+ def content_message(self, content_message: str):
360
+ self.__content_message = content_message
@@ -10,7 +10,7 @@ class Route:
10
10
  routes (list[str]): A lista de todas as rotas disponíveis no fluxo.
11
11
  """
12
12
 
13
- def __init__(self, current: str, routes: list[str], separator:str='.'):
13
+ def __init__(self, current: str, routes: list[str], separator: str = "."):
14
14
  """
15
15
  Inicializa a rota com a rota atual e a lista de rotas disponíveis.
16
16
 
@@ -24,20 +24,20 @@ class Route:
24
24
  self.separator = separator
25
25
 
26
26
  @property
27
- def previous(self)->'Route':
27
+ def previous(self) -> "Route":
28
28
  """
29
29
  Retorna a rota anterior a atual do usuário
30
30
  """
31
31
  return self.get_previous()
32
-
32
+
33
33
  @property
34
- def current_node(self)->str:
34
+ def current_node(self) -> str:
35
35
  """
36
36
  Retorna o nó atual do usuário
37
37
  """
38
38
  return self.current.split(self.separator)[-1]
39
-
40
- def get_previous(self) -> 'Route':
39
+
40
+ def get_previous(self) -> "Route":
41
41
  """
42
42
  Retorna o caminho anterior ao caminho atual.
43
43
 
@@ -47,13 +47,18 @@ class Route:
47
47
  Returns:
48
48
  str: O caminho anterior à rota atual.
49
49
  """
50
- if self.current == 'start':
50
+ if self.current == "start":
51
51
  return Route(self.current, self.routes, self.separator)
52
52
 
53
- previous_route = self.separator.join(self.current.split(self.separator)[:-1])
53
+ rotas_dedup = self.separator.join(
54
+ dict.fromkeys(self.current.split(self.separator))
55
+ )
56
+
57
+ previous_route = self.separator.join(rotas_dedup.split(self.separator)[:-1])
58
+
54
59
  return Route(previous_route, self.routes, self.separator)
55
60
 
56
- def get_next(self, next_part: str) -> 'Route':
61
+ def get_next(self, next_part: str) -> "Route":
57
62
  """
58
63
  Monta e retorna o próximo caminho com base na parte fornecida.
59
64
 
@@ -69,8 +74,8 @@ class Route:
69
74
  next_part = next_part.strip().lower()
70
75
  next_route = f"{self.current.rstrip(self.separator)}.{next_part}"
71
76
  if next_part not in self.routes:
72
- raise RouteError(f'Rota não encontrada: {next_part}')
73
-
77
+ raise RouteError(f"Rota não encontrada: {next_part}")
78
+
74
79
  return Route(next_route, self.routes, self.separator)
75
80
 
76
81
  def __str__(self):
@@ -80,7 +85,7 @@ class Route:
80
85
  Returns:
81
86
  str: A representação em string da rota atual.
82
87
  """
83
- return f'Route(current={self.current})'
88
+ return f"Route(current={self.current})"
84
89
 
85
90
  def __repr__(self):
86
91
  """
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "chatgraph"
3
- version = "0.6.0"
3
+ version = "0.6.2"
4
4
  description = "A user-friendly chatbot library"
5
5
  authors = ["Irisson N. Lima <irisson.lima@verdecard.com.br>"]
6
6
  readme = "README.md"
@@ -1,81 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
- # Generated by the protocol buffer compiler. DO NOT EDIT!
3
- # NO CHECKED-IN PROTOBUF GENCODE
4
- # source: router.proto
5
- # Protobuf Python Version: 6.31.0
6
- """Generated protocol buffer code."""
7
- from google.protobuf import descriptor as _descriptor
8
- from google.protobuf import descriptor_pool as _descriptor_pool
9
- from google.protobuf import runtime_version as _runtime_version
10
- from google.protobuf import symbol_database as _symbol_database
11
- from google.protobuf.internal import builder as _builder
12
- _runtime_version.ValidateProtobufRuntimeVersion(
13
- _runtime_version.Domain.PUBLIC,
14
- 6,
15
- 31,
16
- 0,
17
- '',
18
- 'router.proto'
19
- )
20
- # @@protoc_insertion_point(imports)
21
-
22
- _sym_db = _symbol_database.Default()
23
-
24
-
25
-
26
-
27
- DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0crouter.proto\x12\x07\x63hatbot\"\x06\n\x04Void\"0\n\rRequestStatus\x12\x0e\n\x06status\x18\x01 \x01(\x08\x12\x0f\n\x07message\x18\x02 \x01(\t\"-\n\x06\x43hatID\x12\x0f\n\x07user_id\x18\x01 \x01(\t\x12\x12\n\ncompany_id\x18\x02 \x01(\t\"q\n\tUserState\x12 \n\x07\x63hat_id\x18\x01 \x01(\x0b\x32\x0f.chatbot.ChatID\x12\x0c\n\x04menu\x18\x02 \x01(\t\x12\r\n\x05route\x18\x03 \x01(\t\x12\x10\n\x08protocol\x18\x04 \x01(\t\x12\x13\n\x0bobservation\x18\x05 \x01(\t\"8\n\rUserStateList\x12\'\n\x0buser_states\x18\x01 \x03(\x0b\x32\x12.chatbot.UserState\"j\n\x0bTextMessage\x12\x0c\n\x04type\x18\x01 \x01(\t\x12\x0b\n\x03url\x18\x02 \x01(\t\x12\x10\n\x08\x66ilename\x18\x03 \x01(\t\x12\r\n\x05title\x18\x04 \x01(\t\x12\x0e\n\x06\x64\x65tail\x18\x05 \x01(\t\x12\x0f\n\x07\x63\x61ption\x18\x06 \x01(\t\"5\n\x06\x42utton\x12\x0c\n\x04type\x18\x01 \x01(\t\x12\r\n\x05title\x18\x02 \x01(\t\x12\x0e\n\x06\x64\x65tail\x18\x03 \x01(\t\"\x9d\x01\n\x07Message\x12 \n\x07\x63hat_id\x18\x01 \x01(\x0b\x32\x0f.chatbot.ChatID\x12%\n\x07message\x18\x02 \x01(\x0b\x32\x14.chatbot.TextMessage\x12 \n\x07\x62uttons\x18\x03 \x03(\x0b\x32\x0f.chatbot.Button\x12\'\n\x0e\x64isplay_button\x18\x04 \x01(\x0b\x32\x0f.chatbot.Button\"A\n\x0b\x46ileMessage\x12!\n\x07message\x18\x01 \x01(\x0b\x32\x10.chatbot.Message\x12\x0f\n\x07\x66ile_id\x18\x02 \x01(\t\"_\n\x11UploadFileRequest\x12\x0f\n\x07\x66ile_id\x18\x01 \x01(\t\x12\x10\n\x08\x66ile_url\x18\x02 \x01(\t\x12\x11\n\tfile_type\x18\x03 \x01(\t\x12\x14\n\x0c\x66ile_content\x18\x04 \x01(\x0c\"d\n\x16TransferToHumanRequest\x12 \n\x07\x63hat_id\x18\x01 \x01(\x0b\x32\x0f.chatbot.ChatID\x12\x13\n\x0b\x63\x61mpaign_id\x18\x02 \x01(\t\x12\x13\n\x0bobservation\x18\x03 \x01(\t\"]\n\x15TransferToMenuRequest\x12 \n\x07\x63hat_id\x18\x01 \x01(\x0b\x32\x0f.chatbot.ChatID\x12\x0c\n\x04menu\x18\x02 \x01(\t\x12\x14\n\x0cuser_message\x18\x03 \x01(\t\"\x1e\n\x0eTabulationName\x12\x0c\n\x04name\x18\x01 \x01(\t\"B\n\x11TabulationDetails\x12\n\n\x02id\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x13\n\x0blast_update\x18\x03 \x01(\t\"B\n\x0fTabulationsList\x12/\n\x0btabulations\x18\x01 \x03(\x0b\x32\x1a.chatbot.TabulationDetails\"^\n\x0e\x45ndChatRequest\x12 \n\x07\x63hat_id\x18\x01 \x01(\x0b\x32\x0f.chatbot.ChatID\x12\x15\n\rtabulation_id\x18\x02 \x01(\t\x12\x13\n\x0bobservation\x18\x03 \x01(\t\"\x1c\n\x0c\x43\x61mpaignName\x12\x0c\n\x04name\x18\x01 \x01(\t\"@\n\x0f\x43\x61mpaignDetails\x12\n\n\x02id\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x13\n\x0blast_update\x18\x03 \x01(\t\"<\n\rCampaignsList\x12+\n\tcampaigns\x18\x01 \x03(\x0b\x32\x18.chatbot.CampaignDetails2\x83\x02\n\x10UserStateService\x12\x43\n\x15InsertUpdateUserState\x12\x12.chatbot.UserState\x1a\x16.chatbot.RequestStatus\x12:\n\x0f\x44\x65leteUserState\x12\x0f.chatbot.ChatID\x1a\x16.chatbot.RequestStatus\x12\x33\n\x0cGetUserState\x12\x0f.chatbot.ChatID\x1a\x12.chatbot.UserState\x12\x39\n\x10GetAllUserStates\x12\r.chatbot.Void\x1a\x16.chatbot.UserStateList2\xfd\x01\n\x0bSendMessage\x12\x37\n\x0bSendMessage\x12\x10.chatbot.Message\x1a\x16.chatbot.RequestStatus\x12\x39\n\tSendImage\x12\x14.chatbot.FileMessage\x1a\x16.chatbot.RequestStatus\x12\x38\n\x08SendFile\x12\x14.chatbot.FileMessage\x1a\x16.chatbot.RequestStatus\x12@\n\nUploadFile\x12\x1a.chatbot.UploadFileRequest\x1a\x16.chatbot.RequestStatus2\x9c\x02\n\x08Transfer\x12\x38\n\x0fGetAllCampaigns\x12\r.chatbot.Void\x1a\x16.chatbot.CampaignsList\x12@\n\rGetCampaignID\x12\x15.chatbot.CampaignName\x1a\x18.chatbot.CampaignDetails\x12J\n\x0fTransferToHuman\x12\x1f.chatbot.TransferToHumanRequest\x1a\x16.chatbot.RequestStatus\x12H\n\x0eTransferToMenu\x12\x1e.chatbot.TransferToMenuRequest\x1a\x16.chatbot.RequestStatus2\xcb\x01\n\x07\x45ndChat\x12<\n\x11GetAllTabulations\x12\r.chatbot.Void\x1a\x18.chatbot.TabulationsList\x12\x46\n\x0fGetTabulationID\x12\x17.chatbot.TabulationName\x1a\x1a.chatbot.TabulationDetails\x12:\n\x07\x45ndChat\x12\x17.chatbot.EndChatRequest\x1a\x16.chatbot.RequestStatusB\x0bZ\t./chatbotb\x06proto3')
28
-
29
- _globals = globals()
30
- _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
31
- _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'router_pb2', _globals)
32
- if not _descriptor._USE_C_DESCRIPTORS:
33
- _globals['DESCRIPTOR']._loaded_options = None
34
- _globals['DESCRIPTOR']._serialized_options = b'Z\t./chatbot'
35
- _globals['_VOID']._serialized_start=25
36
- _globals['_VOID']._serialized_end=31
37
- _globals['_REQUESTSTATUS']._serialized_start=33
38
- _globals['_REQUESTSTATUS']._serialized_end=81
39
- _globals['_CHATID']._serialized_start=83
40
- _globals['_CHATID']._serialized_end=128
41
- _globals['_USERSTATE']._serialized_start=130
42
- _globals['_USERSTATE']._serialized_end=243
43
- _globals['_USERSTATELIST']._serialized_start=245
44
- _globals['_USERSTATELIST']._serialized_end=301
45
- _globals['_TEXTMESSAGE']._serialized_start=303
46
- _globals['_TEXTMESSAGE']._serialized_end=409
47
- _globals['_BUTTON']._serialized_start=411
48
- _globals['_BUTTON']._serialized_end=464
49
- _globals['_MESSAGE']._serialized_start=467
50
- _globals['_MESSAGE']._serialized_end=624
51
- _globals['_FILEMESSAGE']._serialized_start=626
52
- _globals['_FILEMESSAGE']._serialized_end=691
53
- _globals['_UPLOADFILEREQUEST']._serialized_start=693
54
- _globals['_UPLOADFILEREQUEST']._serialized_end=788
55
- _globals['_TRANSFERTOHUMANREQUEST']._serialized_start=790
56
- _globals['_TRANSFERTOHUMANREQUEST']._serialized_end=890
57
- _globals['_TRANSFERTOMENUREQUEST']._serialized_start=892
58
- _globals['_TRANSFERTOMENUREQUEST']._serialized_end=985
59
- _globals['_TABULATIONNAME']._serialized_start=987
60
- _globals['_TABULATIONNAME']._serialized_end=1017
61
- _globals['_TABULATIONDETAILS']._serialized_start=1019
62
- _globals['_TABULATIONDETAILS']._serialized_end=1085
63
- _globals['_TABULATIONSLIST']._serialized_start=1087
64
- _globals['_TABULATIONSLIST']._serialized_end=1153
65
- _globals['_ENDCHATREQUEST']._serialized_start=1155
66
- _globals['_ENDCHATREQUEST']._serialized_end=1249
67
- _globals['_CAMPAIGNNAME']._serialized_start=1251
68
- _globals['_CAMPAIGNNAME']._serialized_end=1279
69
- _globals['_CAMPAIGNDETAILS']._serialized_start=1281
70
- _globals['_CAMPAIGNDETAILS']._serialized_end=1345
71
- _globals['_CAMPAIGNSLIST']._serialized_start=1347
72
- _globals['_CAMPAIGNSLIST']._serialized_end=1407
73
- _globals['_USERSTATESERVICE']._serialized_start=1410
74
- _globals['_USERSTATESERVICE']._serialized_end=1669
75
- _globals['_SENDMESSAGE']._serialized_start=1672
76
- _globals['_SENDMESSAGE']._serialized_end=1925
77
- _globals['_TRANSFER']._serialized_start=1928
78
- _globals['_TRANSFER']._serialized_end=2212
79
- _globals['_ENDCHAT']._serialized_start=2215
80
- _globals['_ENDCHAT']._serialized_end=2418
81
- # @@protoc_insertion_point(module_scope)
@@ -1,36 +0,0 @@
1
- import hashlib
2
- import base64
3
- from chatgraph.types.message_types import Message
4
-
5
-
6
- class ImageData:
7
- def __init__(self, url: str, image_bytes: bytes = None):
8
- if not url and not image_bytes:
9
- raise ValueError("URL or image bytes must be provided.")
10
-
11
- self.url = url
12
- self.image_bytes = image_bytes
13
-
14
- # Create hash of image bytes if available, otherwise use URL
15
- hash_input = image_bytes if image_bytes else url.encode("utf-8")
16
-
17
- # Create SHA-256 hash and encode in base64
18
- self.image_id = base64.b64encode(hashlib.sha256(hash_input).digest()).decode(
19
- "utf-8"
20
- )
21
-
22
-
23
- class SendImage:
24
- def __init__(self, image: ImageData, message: Message):
25
- if not isinstance(image, ImageData):
26
- raise TypeError("Expected an instance of ImageData.")
27
-
28
- self.type = "image"
29
- self.image = image
30
- self.message = message
31
-
32
- def to_dict(self):
33
- return {
34
- "file_id": self.image.image_id,
35
- "message": self.message.to_dict(),
36
- }
File without changes
File without changes