Pecximenes commited on
Commit
f5c3f28
1 Parent(s): da6635b

Adding new features: feedback and login/create acount

Browse files
config/edgedb/dbschema/initial.esdl CHANGED
@@ -34,16 +34,21 @@ module default {
34
  url -> str;
35
  }
36
 
 
 
 
 
 
 
 
37
  type Chat {
38
  required property created_at -> datetime {
39
  default := datetime_current();
40
  };
41
 
42
- required property user -> str;
43
-
44
- # Relacionamento com as mensagens
45
- multi link messages -> Message {
46
  constraint exclusive;
 
47
  };
48
  }
49
 
@@ -52,9 +57,12 @@ module default {
52
  default := datetime_current();
53
  };
54
  required property content -> str;
 
55
 
56
  # Relacionamento com o chat
57
- required link chat -> Chat;
 
 
58
 
59
  # Relacionamento com o feedback
60
  optional link feedback -> Feedback;
@@ -71,6 +79,8 @@ module default {
71
  };
72
 
73
  # Relacionamento com a mensagem
74
- required link message -> Message;
 
 
75
  }
76
- }
 
34
  url -> str;
35
  }
36
 
37
+ type User {
38
+ username -> str {
39
+ constraint exclusive;
40
+ };
41
+ password -> str;
42
+ }
43
+
44
  type Chat {
45
  required property created_at -> datetime {
46
  default := datetime_current();
47
  };
48
 
49
+ required link user -> User {
 
 
 
50
  constraint exclusive;
51
+ on target delete delete source;
52
  };
53
  }
54
 
 
57
  default := datetime_current();
58
  };
59
  required property content -> str;
60
+ required property role -> str;
61
 
62
  # Relacionamento com o chat
63
+ required link chat -> Chat {
64
+ on target delete delete source;
65
+ };
66
 
67
  # Relacionamento com o feedback
68
  optional link feedback -> Feedback;
 
79
  };
80
 
81
  # Relacionamento com a mensagem
82
+ required link message -> Message {
83
+ on target delete delete source;
84
+ };
85
  }
86
+ }
config/edgedb/dbschema/migrations/00004-m14umub.edgeql ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ CREATE MIGRATION m14umubvchh6dqfs7hxsh6sbq6frts3srp4hem3ste7x55725xfzca
2
+ ONTO m1i7x3r7aiqye7qwxi5glhcjdwaameqzw5myzghwlvyw6l4tlgiwqq
3
+ {
4
+ ALTER TYPE default::Chat {
5
+ DROP PROPERTY user;
6
+ };
7
+ CREATE TYPE default::User {
8
+ CREATE PROPERTY password: std::str;
9
+ CREATE PROPERTY username: std::str;
10
+ };
11
+ ALTER TYPE default::Chat {
12
+ CREATE REQUIRED LINK user: default::User {
13
+ SET REQUIRED USING (<default::User>{});
14
+ };
15
+ };
16
+ };
config/edgedb/dbschema/migrations/00005-m13l5i4.edgeql ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ CREATE MIGRATION m13l5i44vh6iltkc5kry2aywhsu6hsutbmuhrlkjic4bxdde25dyfq
2
+ ONTO m14umubvchh6dqfs7hxsh6sbq6frts3srp4hem3ste7x55725xfzca
3
+ {
4
+ ALTER TYPE default::Chat {
5
+ ALTER LINK user {
6
+ CREATE CONSTRAINT std::exclusive;
7
+ };
8
+ };
9
+ ALTER TYPE default::Message {
10
+ CREATE REQUIRED PROPERTY role: std::str {
11
+ SET REQUIRED USING (<std::str>{});
12
+ };
13
+ };
14
+ ALTER TYPE default::User {
15
+ ALTER PROPERTY username {
16
+ CREATE CONSTRAINT std::exclusive;
17
+ };
18
+ };
19
+ };
config/edgedb/dbschema/migrations/00006-m14njc2.edgeql ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ CREATE MIGRATION m14njc2voirnwk4thadcprrevsmlp2wljtwwcnirsya5bblwtljgla
2
+ ONTO m13l5i44vh6iltkc5kry2aywhsu6hsutbmuhrlkjic4bxdde25dyfq
3
+ {
4
+ ALTER TYPE default::Chat {
5
+ DROP LINK messages;
6
+ ALTER LINK user {
7
+ ON TARGET DELETE DELETE SOURCE;
8
+ };
9
+ };
10
+ ALTER TYPE default::Feedback {
11
+ ALTER LINK message {
12
+ ON TARGET DELETE DELETE SOURCE;
13
+ };
14
+ };
15
+ ALTER TYPE default::Message {
16
+ ALTER LINK chat {
17
+ ON TARGET DELETE DELETE SOURCE;
18
+ };
19
+ };
20
+ };
interface/app.py CHANGED
@@ -7,23 +7,42 @@ sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
7
 
8
  # Importando módulos necessários
9
  from interface.chatbot import Chatbot
 
10
 
11
 
12
  def main():
13
  app = Chatbot()
14
-
15
- with st.sidebar:
16
- app.create_sidebar()
17
 
18
- app.mount_chatbot()
 
19
 
20
- if app.response:
21
- app.add_to_history(app.response, role="user")
22
- st.chat_message("user").write(app.response)
23
 
24
- app.generate_answer(app.response)
 
25
 
26
- app.response = "" # Zerando a variável após uso
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
 
28
 
29
  if __name__ == "__main__":
 
7
 
8
  # Importando módulos necessários
9
  from interface.chatbot import Chatbot
10
+ from interface.login import Login
11
 
12
 
13
  def main():
14
  app = Chatbot()
15
+ login = Login()
 
 
16
 
17
+ if not st.session_state.user_authorized:
18
+ login.mount_login_page()
19
 
20
+ else:
21
+ with st.sidebar:
22
+ app.create_sidebar()
23
 
24
+ user_query = app.mount_chatbot() # Recebe o input de texto feito pelo usuário
25
+ app.display_chat()
26
 
27
+ if st.session_state.is_feedback_active:
28
+ app.display_feedback()
29
+
30
+ if app.user_button_input:
31
+ st.chat_message("user").write(app.user_button_input)
32
+
33
+ app.generate_answer(app.user_button_input)
34
+
35
+ app.user_button_input = "" # Zerando a variável após uso
36
+ st.session_state.is_feedback_active = True # Ativando o feedback
37
+ app.display_feedback()
38
+
39
+ if user_query:
40
+ # Escreve e armazena a mensagem do usuário
41
+ st.chat_message("user").write(user_query)
42
+
43
+ app.generate_answer(user_query) # Gera, envia e armazena a resposta do assistente
44
+ st.session_state.is_feedback_active = True # Ativando o feedback
45
+ app.display_feedback()
46
 
47
 
48
  if __name__ == "__main__":
interface/chatbot.py CHANGED
@@ -5,31 +5,15 @@ import edgedb
5
  from openai import OpenAI
6
  from qdrant_client import QdrantClient
7
  import streamlit as st
8
- import argparse
9
-
10
- from utils.util import clear_enviromnent_variables
11
 
12
  # Add the parent directory to the Python path
13
  sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
14
 
15
  from pipelines.message import send_message # noqa
16
 
17
- st.set_page_config(page_title="Carlos AI Agent")
18
-
19
- # Parser for command-line options
20
- parser = argparse.ArgumentParser(description="Argumento para setar qual variável de ambiente usar")
21
- parser.add_argument('--type_env', type=str, default="prod", help="Set 'dev' for use .env.development and 'prod' for .env")
22
-
23
- # Parsing arguments
24
- args = parser.parse_args()
25
 
26
- # Accessing the correct argument
27
- type_env = args.type_env
28
-
29
- if type_env == "prod":
30
- load_dotenv(dotenv_path=".env", override=True)
31
- else:
32
- load_dotenv(dotenv_path=".env.development", override=True)
33
 
34
  @st.cache_resource
35
  def connect_to_services():
@@ -37,78 +21,110 @@ def connect_to_services():
37
  api_key=os.environ.get("OPENAI_API_KEY")
38
  )
39
 
40
- edgedb_client = None
41
- qdrant_client = None
42
- if type_env == "prod":
43
- edgedb_client = edgedb.create_client()
44
- qdrant_client = QdrantClient(
45
- url=os.environ.get("QDRANT_URL"),
46
- api_key=os.environ.get("QDRANT_KEY")
47
- )
48
- else:
49
- edgedb_client = edgedb.create_client(
50
- host=os.environ.get("EDGEDB_HOST"),
51
- user=os.environ.get("EDGEDB_USER"),
52
- password=os.environ.get("EDGEDB_PASSWORD"),
53
- port=os.environ.get("EDGEDB_PORT"),
54
- tls_security="insecure"
55
- )
56
- qdrant_client = QdrantClient(
57
- host=os.environ.get("QDRANT_HOST"),
58
- port=os.environ.get("QDRANT_PORT")
59
- )
60
 
61
  return oa_client, qdrant_client, edgedb_client
62
 
63
- class Chatbot():
 
64
  def __init__(self):
65
- # Configuração inicial do histórico de chat
66
- if "chat_history" not in st.session_state:
67
- st.session_state.chat_history = [{
68
- "role": "assistant",
69
- "content": "Como eu posso ajudar?"
70
- }]
71
-
72
  # Conteúdo dos botões do sidebar
73
  if "topics" not in st.session_state:
74
- st.session_state["topics"] = [
75
- "Niveis da conta govbr.",
76
  "Dúvidas no reconhecimento facial.",
77
  "Como recuperar minha conta gov.br",
78
- "Dúvidas para aumentar o nível com a cin."
79
  ]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
80
 
81
- # Pergunta do usuário no chatbot
82
- self.response = ""
83
 
84
- self.oa_client, self.qdrant_client, self.edgedb_client = connect_to_services()
 
85
 
 
 
 
86
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
87
  def mount_chatbot(self):
88
  # Exibição do título e subtítulo
89
  st.title("Bem-vindo à ajuda do gov.br")
90
  st.caption("💬 Qual a sua dificuldade hoje? Estou aqui para ajudar!")
91
 
92
- self.display_chat(st.session_state.chat_history, jump_last_message=False)
93
-
94
  # Exibição do espaço para mandar mensagem
95
  if user_query := st.chat_input(placeholder="Digite sua mensagem"):
96
- self.add_to_history(user_query, role="user")
97
- st.chat_message("user").write(user_query)
98
-
99
- # Simulação de resposta do assistente
100
- self.generate_answer(user_query)
101
 
102
-
103
  def create_sidebar(self):
104
  st.image('https://www.gov.br/++theme++padrao_govbr/img/govbr-logo-large.png', width=200)
105
  st.header("Tópicos frequentes")
106
 
107
  for topic in st.session_state.topics:
108
  if st.button(topic, key=topic):
109
- self.response = topic
 
110
 
111
-
112
  # Espaços em branco para organização
113
  for _ in range(5):
114
  st.write("")
@@ -117,19 +133,22 @@ class Chatbot():
117
  col1, col2, col3 = st.columns([1, 2, 1])
118
  with col2:
119
  if st.button("LIMPAR HISTÓRICO"):
120
- st.session_state.chat_history = [{
121
- "role": "assistant",
122
- "content": "Como eu posso ajudar?",
123
- }]
 
 
 
124
 
125
  def send_message_for_ai(self, prompt):
126
  with st.spinner("Obtendo conteúdo da página..."):
127
- embedding = self.oa_client.embeddings.create(
128
  input=[prompt],
129
  model=os.environ.get("OPENAI_MODEL_EMBEDDING")
130
  ).data[0].embedding
131
 
132
- child_texts = self.qdrant_client.search(
133
  collection_name=os.environ.get("COLLECTION_NAME"),
134
  query_vector=embedding,
135
  limit=3
@@ -138,7 +157,7 @@ class Chatbot():
138
  contexts = []
139
 
140
  for child_text in child_texts:
141
- parent_text = self.edgedb_client.query('''
142
  SELECT Pattern {
143
  content,
144
  url,
@@ -152,37 +171,79 @@ class Chatbot():
152
  "parent_id": parent_text.parent_id
153
  }
154
  contexts.append(context)
155
-
156
 
 
 
 
 
157
  stream_response = send_message(
158
- self.oa_client,
159
  contexts,
160
  prompt,
161
- []
162
  )
163
 
164
  return stream_response
165
-
 
166
  def generate_answer(self, prompt):
167
-
168
  with st.chat_message("assistant"):
169
  stream_response = self.send_message_for_ai(prompt)
170
  response = st.write_stream(stream_response)
171
-
172
- self.add_to_history(response, role="assistant")
173
-
174
- def display_chat(self, messages_list, jump_last_message: bool = True):
175
- if jump_last_message:
176
- messages = messages_list[:-1] # Desconsidera o último item da lista
177
- else:
178
- messages = messages_list # Mostra todos os itens da lista original
179
-
180
- for message in messages:
181
- st.chat_message(message["role"]).write(message["content"])
182
-
183
- def add_to_history(self, message, role="user"):
184
- st.session_state.chat_history.append({
185
- "role": role,
186
- "content": message
187
- })
188
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
  from openai import OpenAI
6
  from qdrant_client import QdrantClient
7
  import streamlit as st
 
 
 
8
 
9
  # Add the parent directory to the Python path
10
  sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
11
 
12
  from pipelines.message import send_message # noqa
13
 
14
+ # st.set_page_config(page_title="Carlos AI Agent")
 
 
 
 
 
 
 
15
 
16
+ load_dotenv()
 
 
 
 
 
 
17
 
18
  @st.cache_resource
19
  def connect_to_services():
 
21
  api_key=os.environ.get("OPENAI_API_KEY")
22
  )
23
 
24
+ qdrant_client = QdrantClient(
25
+ url=os.environ.get("QDRANT_URL"),
26
+ api_key=os.environ.get("QDRANT_KEY")
27
+ )
28
+
29
+ edgedb_client = edgedb.create_client()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
 
31
  return oa_client, qdrant_client, edgedb_client
32
 
33
+
34
+ class Chatbot:
35
  def __init__(self):
 
 
 
 
 
 
 
36
  # Conteúdo dos botões do sidebar
37
  if "topics" not in st.session_state:
38
+ st.session_state.topics = [
39
+ "Níveis da conta govbr.",
40
  "Dúvidas no reconhecimento facial.",
41
  "Como recuperar minha conta gov.br",
42
+ "Dúvidas para aumentar o nível com a CIN."
43
  ]
44
+
45
+ if "services" not in st.session_state:
46
+ oa_client, qdrant_client, edgedb_client = connect_to_services()
47
+ st.session_state.services = {
48
+ "oa_client": oa_client,
49
+ "qdrant_client": qdrant_client,
50
+ "edgedb_client": edgedb_client
51
+ }
52
+
53
+ if "chat" not in st.session_state and st.session_state.get('username'):
54
+ chat = st.session_state.services["edgedb_client"].query('''
55
+ Select Chat {
56
+ id
57
+ } filter .user.username = <str>$username
58
+ ''', username=st.session_state.username)
59
+
60
+ if not chat:
61
+ chat = self._create_default_chat()
62
+ else:
63
+ chat = chat[0]
64
+ self.update_messages(chat)
65
+
66
+ st.session_state.chat = chat
67
+
68
 
 
 
69
 
70
+ if "is_feedback_active" not in st.session_state:
71
+ st.session_state.is_feedback_active = False
72
 
73
+
74
+ self.user_button_input = "" # Pergunta do usuário no chat
75
+ # self.is_feedback_active = False # Flag para ativar o feedback do o
76
 
77
+ def _create_default_chat(self):
78
+ chat = st.session_state.services["edgedb_client"].query('''
79
+ INSERT Chat {
80
+ user := (SELECT User FILTER .username = <str>$username)
81
+ }
82
+ ''', username=st.session_state.username)
83
+ message = st.session_state.services["edgedb_client"].query('''
84
+ SELECT (
85
+ INSERT Message {
86
+ content := "Como eu posso ajudar?",
87
+ role := "assistant",
88
+ chat := (SELECT Chat FILTER .id = <uuid>$chat_id)
89
+ }
90
+ ) {
91
+ content,
92
+ role
93
+ }
94
+ ''', chat_id=chat[0].id)
95
+ st.session_state.chat_history = message
96
+ return chat[0]
97
+
98
+ def _save_msg_to_db(self, msg, role):
99
+ st.session_state.services["edgedb_client"].query('''
100
+ INSERT Message {
101
+ content := <str>$content,
102
+ chat := (SELECT Chat FILTER .id = <uuid>$chat_id),
103
+ role := <str>$role
104
+ }
105
+ ''', content=msg, chat_id=st.session_state.chat.id, role=role)
106
+
107
+
108
  def mount_chatbot(self):
109
  # Exibição do título e subtítulo
110
  st.title("Bem-vindo à ajuda do gov.br")
111
  st.caption("💬 Qual a sua dificuldade hoje? Estou aqui para ajudar!")
112
 
 
 
113
  # Exibição do espaço para mandar mensagem
114
  if user_query := st.chat_input(placeholder="Digite sua mensagem"):
115
+ st.session_state.is_feedback_active = False # Desativando o feedback
116
+ return user_query
 
 
 
117
 
118
+
119
  def create_sidebar(self):
120
  st.image('https://www.gov.br/++theme++padrao_govbr/img/govbr-logo-large.png', width=200)
121
  st.header("Tópicos frequentes")
122
 
123
  for topic in st.session_state.topics:
124
  if st.button(topic, key=topic):
125
+ self.user_button_input = topic
126
+ st.session_state.is_feedback_active = False # Desativando o feedback
127
 
 
128
  # Espaços em branco para organização
129
  for _ in range(5):
130
  st.write("")
 
133
  col1, col2, col3 = st.columns([1, 2, 1])
134
  with col2:
135
  if st.button("LIMPAR HISTÓRICO"):
136
+ st.session_state.services["edgedb_client"].query('''
137
+ DELETE Chat
138
+ FILTER .id = <uuid>$chat_id;
139
+ ''', chat_id=st.session_state.chat.id)
140
+ st.session_state.chat = self._create_default_chat()
141
+ st.session_state.is_feedback_active = False # Desativando o feedback
142
+
143
 
144
  def send_message_for_ai(self, prompt):
145
  with st.spinner("Obtendo conteúdo da página..."):
146
+ embedding = st.session_state.services["oa_client"].embeddings.create(
147
  input=[prompt],
148
  model=os.environ.get("OPENAI_MODEL_EMBEDDING")
149
  ).data[0].embedding
150
 
151
+ child_texts = st.session_state.services["qdrant_client"].search(
152
  collection_name=os.environ.get("COLLECTION_NAME"),
153
  query_vector=embedding,
154
  limit=3
 
157
  contexts = []
158
 
159
  for child_text in child_texts:
160
+ parent_text = st.session_state.services["edgedb_client"].query('''
161
  SELECT Pattern {
162
  content,
163
  url,
 
171
  "parent_id": parent_text.parent_id
172
  }
173
  contexts.append(context)
 
174
 
175
+ formatted_messages = [{"content": msg.content, "role": msg.role} for msg in st.session_state.chat_history]
176
+
177
+ self._save_msg_to_db(prompt, "user")
178
+
179
  stream_response = send_message(
180
+ st.session_state.services["oa_client"],
181
  contexts,
182
  prompt,
183
+ formatted_messages
184
  )
185
 
186
  return stream_response
187
+
188
+
189
  def generate_answer(self, prompt):
 
190
  with st.chat_message("assistant"):
191
  stream_response = self.send_message_for_ai(prompt)
192
  response = st.write_stream(stream_response)
193
+ self._save_msg_to_db(response, "assistant")
194
+ self.update_messages(st.session_state.chat)
195
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
196
 
197
+ def display_chat(self):
198
+ for message in st.session_state.chat_history:
199
+ st.chat_message(message.role).write(message.content)
200
+
201
+ def update_messages(self, chat):
202
+ messages = st.session_state.services["edgedb_client"].query('''
203
+ SELECT Message {
204
+ id,
205
+ content,
206
+ role
207
+ }
208
+ FILTER .chat.id = <uuid>$chat_id
209
+ ORDER BY .created_at ASC;
210
+ ''', chat_id=chat.id)
211
+ st.session_state.chat_history = messages
212
+
213
+ def display_feedback(self):
214
+ user_input = st.session_state.chat_history[-2].content
215
+ bot_output = st.session_state.chat_history[-1].content
216
+
217
+ with st.expander("Avaliação do atendimento"):
218
+ st.write(f'O que achou da resposta para a pergunta "{user_input}"?')
219
+
220
+ rate = st.feedback("stars")
221
+ # rate = st.feedback("faces")
222
+
223
+ text_feedback = st.text_input("Comentários extras:")
224
+
225
+ # Botão para confirmar a avaliação
226
+ if rate is not None:
227
+ if st.button("Enviar Avaliação"):
228
+ try:
229
+ feedback_rate = rate + 1
230
+ st.session_state.services["edgedb_client"].query('''
231
+ INSERT Feedback {
232
+ rating := <int16>$rating,
233
+ content := <str>$content,
234
+ message := (SELECT Message FILTER .id = <uuid>$message_id)
235
+ }
236
+ ''',
237
+ message_id=st.session_state.chat_history[-1].id,
238
+ rating=feedback_rate,
239
+ content=text_feedback,
240
+ )
241
+ st.session_state.chat_history
242
+ st.success(f"Avaliação enviada!")
243
+ except Exception as e:
244
+ print(e)
245
+ st.error("Erro ao enviar avaliação!")
246
+
247
+ st.session_state.is_feedback_active = False # Desativando o feedback
248
+
249
+ # TODO Colocar nessa parte a estrutura para adicionar o feedback_data ao banco de dados
interface/login.py ADDED
@@ -0,0 +1,110 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import json
3
+ import sys
4
+ import os
5
+ import bcrypt
6
+
7
+ from interface.chatbot import connect_to_services
8
+
9
+ # Add the parent directory to the Python path
10
+ sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
11
+
12
+ class Login:
13
+ def __init__(self):
14
+ if "username" not in st.session_state:
15
+ st.session_state.username = ""
16
+
17
+ if "user_authorized" not in st.session_state:
18
+ st.session_state.user_authorized = False
19
+
20
+ if "services" not in st.session_state:
21
+ oa_client, qdrant_client, edgedb_client = connect_to_services()
22
+ st.session_state.services = {
23
+ "oa_client": oa_client,
24
+ "qdrant_client": qdrant_client,
25
+ "edgedb_client": edgedb_client
26
+ }
27
+
28
+
29
+ self.username = ""
30
+ self.password = ""
31
+
32
+
33
+ def mount_login_page(self):
34
+ # Exibição do título e subtítulo
35
+ st.title("Bem-vindo à ajuda do gov.br")
36
+ with st.form("login_form"):
37
+ st.title("Login")
38
+
39
+ username = st.text_input('E-mail:')
40
+ password = st.text_input('Senha:', type='password')
41
+ submitted = st.form_submit_button("Entrar")
42
+ st.text("Não possui uma conta?")
43
+ create_account = st.form_submit_button("Criar uma conta")
44
+
45
+ if create_account:
46
+ if not username:
47
+ st.warning("Digite um email para cadastrar a conta.")
48
+
49
+ if not password:
50
+ st.warning("Digite uma senha para cadastrar a conta.")
51
+
52
+ if username and password:
53
+ if "@" not in username:
54
+ st.warning("Digite um email válido para cadastrar a conta.")
55
+
56
+ else:
57
+ user = self.validate_credentials(username, password, return_just_user=True)
58
+ if user:
59
+ st.warning("Já existe uma conta usando este email")
60
+ else:
61
+ # Gerando senha encriptada
62
+ hashed_password = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt())
63
+ hashed_password_str = hashed_password.decode('utf-8')
64
+
65
+ st.session_state.services["edgedb_client"].query('''
66
+ INSERT User {
67
+ username := <str>$username,
68
+ password := <str>$password
69
+ }
70
+ ''',
71
+ username=username, \
72
+ password=hashed_password_str, \
73
+ )
74
+
75
+ st.success("Conta cadastrada com sucesso.")
76
+
77
+ if submitted:
78
+ if username and password:
79
+ checked = self.validate_credentials(username, password)
80
+ if checked:
81
+ st.success("Usuário logado!")
82
+ st.session_state.user_authorized = True
83
+ st.session_state.username = username
84
+ st.rerun()
85
+
86
+ else:
87
+ st.error("Nome de usuário ou senha inválidos.")
88
+
89
+ else:
90
+ st.warning("Digite o nome do usuário e a senha.")
91
+
92
+
93
+ def validate_credentials(self, username, password, return_just_user=False):
94
+ user = st.session_state.services["edgedb_client"].query('''
95
+ SELECT User {
96
+ username,
97
+ password
98
+ } FILTER .username = <str>$username
99
+ ''', username=username)
100
+
101
+ if return_just_user:
102
+ if not user:
103
+ return False
104
+
105
+ return True
106
+
107
+ if not user or not bcrypt.checkpw(password.encode('utf-8'), user[0].password.encode('utf-8')):
108
+ return False
109
+
110
+ return True
requirements.txt CHANGED
@@ -3,6 +3,7 @@ annotated-types==0.7.0
3
  anyio==4.5.0
4
  async-timeout==4.0.3
5
  attrs==24.2.0
 
6
  blinker==1.8.2
7
  cachetools==5.5.0
8
  certifi==2024.8.30
 
3
  anyio==4.5.0
4
  async-timeout==4.0.3
5
  attrs==24.2.0
6
+ bcrypt==4.2.0
7
  blinker==1.8.2
8
  cachetools==5.5.0
9
  certifi==2024.8.30