File size: 9,866 Bytes
686cd95
 
 
 
 
 
 
 
 
 
 
 
 
247406d
 
686cd95
 
0746d2c
686cd95
 
 
 
 
 
 
 
 
 
247406d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
686cd95
 
 
0746d2c
686cd95
 
0746d2c
686cd95
 
0746d2c
 
 
686cd95
 
 
247406d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
686cd95
 
0746d2c
686cd95
 
0746d2c
 
686cd95
 
 
 
 
 
0746d2c
 
686cd95
 
 
 
 
 
 
 
 
0746d2c
686cd95
 
0746d2c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f7fe723
0746d2c
 
 
 
 
 
 
 
686cd95
0746d2c
686cd95
 
 
 
0746d2c
 
 
 
 
686cd95
 
0746d2c
686cd95
 
 
 
 
 
 
0746d2c
 
 
 
686cd95
0746d2c
686cd95
0746d2c
686cd95
 
0746d2c
686cd95
0746d2c
 
 
 
 
247406d
 
 
 
 
 
 
 
 
 
 
 
 
 
0746d2c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
247406d
 
0746d2c
 
247406d
 
 
 
 
 
 
 
 
 
 
 
 
0746d2c
 
 
 
 
 
247406d
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
import streamlit as st
import sys
import os

# Configuração do caminho para incluir as pastas necessárias
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

from pipelines.message import send_message
from agent import pipeline
from interface.auxiliary_functions import (
    extract_content,
    extract_links,
    fetch_webpage_content,
    url_to_suggestion,
    connect_to_services
)

class Chatbot:
    def __init__(self):
        # Configuração inicial do histórico de chat
        if "chat_history" not in st.session_state:
            st.session_state.chat_history = [{
                "type": "text",
                "role": "assistant",
                "content": "Como eu posso ajudar?",
                "links": []
            }]
        
        if "chat" not in st.session_state and st.session_state.get('username'):
            chat = st.session_state.services["edgedb_client"].query('''
                Select Chat {
                    id
                } filter .user.username = <str>$username and .prototipo.id = <uuid>$prototipo_id
                ''',
                username=st.session_state.username,
                prototipo_id=st.session_state.prototipo_id
            )

            if not chat:
                chat = self._create_default_chat()
            else:
                chat = chat[0]
                self.update_messages(chat)
            
            st.session_state.chat = chat
        
        # Conteúdo dos botões do sidebar
        if "topics" not in st.session_state:
            st.session_state["topics"] = [
                "Níveis da conta govbr.",
                "Dúvidas no reconhecimento facial.",
                "Como recuperar minha conta gov.br",
                "Dúvidas para aumentar o nível com a CIN."
            ]
        
        if "is_feedback_active" not in st.session_state:
            st.session_state.is_feedback_active = False

        # Pergunta do usuário no chatbot
        self.response = ""
        self.links = []
    
    def _create_default_chat(self):
        chat = st.session_state.services["edgedb_client"].query('''
                    INSERT Chat {
                        user := (SELECT User FILTER .username = <str>$username),
                        prototipo := (SELECT Prototipo FILTER .id = <uuid>$prototipo_id)
                    }
                    ''',
                    username=st.session_state.username,
                    prototipo_id=st.session_state.prototipo_id
                )
        message = st.session_state.services["edgedb_client"].query('''
            SELECT (
                INSERT Message {
                    content := "Como eu posso ajudar?",
                    role := "assistant",
                    chat := (SELECT Chat FILTER .id = <uuid>$chat_id)
                }
            ) {
                content,
                role                                             
            }
        ''', chat_id=chat[0].id)
        # st.session_state.chat_history = message
        return chat[0]
    
    def update_messages(self, chat):
        messages = st.session_state.services["edgedb_client"].query('''
            SELECT Message {
                id,
                content,
                role
            } 
            FILTER .chat.id = <uuid>$chat_id
            ORDER BY .created_at ASC;
        ''', chat_id=chat.id)
        # st.session_state.chat_history = messages

    def create_sidebar(self):
        """Cria o sidebar com tópicos e opções."""
        st.image('https://www.gov.br/++theme++padrao_govbr/img/govbr-logo-large.png', width=200)
        st.header("Tópicos frequentes")

        for topic in st.session_state["topics"]:
            if st.button(topic, key=topic):
                self.response = topic

        # Espaços em branco para organização
        for _ in range(5):
            st.write("")

        # Botão centralizado para limpar histórico
        col1, col2, col3 = st.columns([1, 2, 1])
        with col2:
            if st.button("LIMPAR HISTÓRICO"):
                st.session_state.chat_history = [{
                    "type": "text",
                    "role": "assistant",
                    "content": "Como eu posso ajudar?",
                    "links": []
                }]
                st.session_state.is_feedback_active = False


    def display_suggestions(self, links):
        """Exibe as sugestões de links no chat."""
        if links:
            st.subheader("Você pode acessar a página na web em:")
            st.write(links[0])  # O primeiro link será o da página principal

            st.subheader("Próximos Passos:")
            suggestions = [(link, url_to_suggestion(link)) for link in links[1:] if url_to_suggestion(link)]

            if suggestions:
                st.write("Você também pode se interessar em:")
                for link, suggestion in suggestions:
                    st.write(f"- [{suggestion}]({link})")  # Exibe os links clicáveis no formato Markdown
            else:
                st.write("Não há sugestões de navegação adicionais.")
        else:
            st.write("Não há links disponíveis para exibição.")

    def mount_chatbot(self):
        """Configura o chatbot com título, subtítulo e espaço de entrada."""
        st.title("Bem-vindo à ajuda do projeto TED 16/2024")
        st.caption("💬 Qual a sua dificuldade hoje? Estou aqui para ajudar!")

        # Exibição do espaço para mandar mensagem
        if user_query := st.chat_input(placeholder="Digite sua mensagem"):
            st.session_state.chat_history.append({"type": "text", "role": "user", "content": user_query})
            self.generate_answer(user_query)
            st.session_state.is_feedback_active = True   # Ativando o feedback
    
    def add_to_history(self, message, role="user", type="text"):
        """Adiciona uma mensagem ao histórico de chat."""
        st.session_state.chat_history.append({
            "role": role, 
            "type": type,
            "content": message
        })

    def generate_answer(self, input_message):
        """Gera uma resposta para a consulta do usuário."""
        # Chama o pipeline para obter a resposta
        response_text = send_message(input_message, pipeline)

        # Armazena a resposta do agente com a tag <path>
        self.add_to_history(response_text, role="assistant")

        # Extração do caminho da resposta do bot
        path = extract_content(response_text, "path")
        if path:
            base_url = "https://www.gov.br/governodigital/pt-br/"
            full_url = base_url + path

            # Armazena o link principal
            self.links = [full_url]

            with st.spinner("Obtendo conteúdo da página..."):
                content, original_links = fetch_webpage_content(full_url)  # Agora retornando também os links desativados

            # Adiciona o conteúdo da página ao histórico do chatbot
            self.add_to_history(content, role="assistant", type="page")

            # Extrai links ativos do conteúdo da página e armazena para sugestões
            extracted_links = extract_links(content)
            
            # Combinar links ativos e links inibidos
            all_links = extracted_links + original_links
            self.links.extend(all_links)

    def _save_msg_to_db(self, msg, role):
        message = st.session_state.services["edgedb_client"].query('''
            SELECT (
                INSERT Message {
                    content := <str>$content,
                    chat := (SELECT Chat FILTER .id = <uuid>$chat_id),
                    role := <str>$role
                }
            ) {
                id
            }
        ''', content=msg, chat_id=st.session_state.chat.id, role=role)
        return message

    def display_feedback(self):
        user_input = st.session_state.chat_history[-2]["content"]
        bot_output = st.session_state.chat_history[-1]["content"]

        with st.expander("Avaliação do atendimento"):
            # st.write(f'O que achou da resposta para a pergunta "{user_input}"?')
            st.write(f'O que achou da resposta para a pergunta?')
            
            rate = st.feedback("stars")
            # rate = st.feedback("faces")

            text_feedback = st.text_input("Comentários extras:")

            # Botão para confirmar a avaliação
            if rate is not None:
                if st.button("Enviar Avaliação"):
                    try:
                        msg = self._save_msg_to_db(bot_output, "assistant")

                        feedback_rate = rate + 1
                        # TODO Colocar nessa parte a estrutura para adicionar o feedback_data ao banco de dados
                        st.session_state.services["edgedb_client"].query('''
                            INSERT Feedback {
                                rating := <int16>$rating,
                                content := <str>$content,
                                message := (SELECT Message FILTER .id = <uuid>$message_id),
                                prototipo := (SELECT Prototipo FILTER .id = <uuid>$prototipo_id)
                            }
                        ''',
                        message_id=msg[-1].id,
                        rating=feedback_rate,
                        content=text_feedback,
                        prototipo_id=st.session_state.prototipo_id
                        )
                        # st.session_state.chat_history
                        st.success(f"Avaliação enviada!")
                    except Exception as e:
                        print(e)
                        st.error("Erro ao enviar avaliação!")

                    st.session_state.is_feedback_active = False # Desativando o feedback