Spaces:
Sleeping
Sleeping
Pecximenes
commited on
Commit
•
f5c3f28
1
Parent(s):
da6635b
Adding new features: feedback and login/create acount
Browse files- config/edgedb/dbschema/initial.esdl +17 -7
- config/edgedb/dbschema/migrations/00004-m14umub.edgeql +16 -0
- config/edgedb/dbschema/migrations/00005-m13l5i4.edgeql +19 -0
- config/edgedb/dbschema/migrations/00006-m14njc2.edgeql +20 -0
- interface/app.py +28 -9
- interface/chatbot.py +152 -91
- interface/login.py +110 -0
- requirements.txt +1 -0
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
|
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 |
-
|
|
|
19 |
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
|
24 |
-
app.
|
|
|
25 |
|
26 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 |
-
|
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 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
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 |
-
|
|
|
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
|
75 |
-
"
|
76 |
"Dúvidas no reconhecimento facial.",
|
77 |
"Como recuperar minha conta gov.br",
|
78 |
-
"Dúvidas para aumentar o nível com a
|
79 |
]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
80 |
|
81 |
-
# Pergunta do usuário no chatbot
|
82 |
-
self.response = ""
|
83 |
|
84 |
-
|
|
|
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 |
-
|
97 |
-
|
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.
|
|
|
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.
|
121 |
-
|
122 |
-
|
123 |
-
|
|
|
|
|
|
|
124 |
|
125 |
def send_message_for_ai(self, prompt):
|
126 |
with st.spinner("Obtendo conteúdo da página..."):
|
127 |
-
embedding =
|
128 |
input=[prompt],
|
129 |
model=os.environ.get("OPENAI_MODEL_EMBEDDING")
|
130 |
).data[0].embedding
|
131 |
|
132 |
-
child_texts =
|
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 =
|
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 |
-
|
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.
|
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
|