import streamlit as st import requests import re import streamlit_authenticator as stauth import os import yaml from yaml.loader import SafeLoader from pathlib import Path from drive_search import search_file_in_drive from datetime import datetime from feedback_manager import FeedbackManager class ChatbotApp: def __init__(self): # Configura título, ícone e layout da página st.set_page_config(page_title="Sicoob Chatbot 🤖", page_icon="logos/sicoob-ico.ico", layout="wide") self.backend_url = "http://localhost:5001/chat" self.title = "Sicoob Chatbot" self.description = "Este assistente virtual pode te ajudar com informações sobre documentos da Sicoob." self.caption = "Confira as atualizações no botão 'Atualizações'." self.style_dir = Path("./logos/styles") self.load_styles() self.feedback_manager = FeedbackManager() st.session_state.first = False if "theme" not in st.session_state: st.session_state.theme = "light" self.configyml = os.path.join(os.getcwd(), "./files/config.yaml") if "feedback_submitted" not in st.session_state: st.session_state.feedback_submitted = set() def load_styles(self): try: self.base_style = (self.style_dir / "base.css").read_text() self.light_style = (self.style_dir / "light.css").read_text() self.dark_style = (self.style_dir / "dark.css").read_text() except FileNotFoundError as e: st.error(f"Error loading styles: {e}") self.base_style = "" self.light_style = "" self.dark_style = "" def change_style(self): with st.sidebar: if st.session_state.theme == "light": st.logo("./logos/sicoob-logo-horizontal-light.png", icon_image="./logos/sicoob-logo-vertical-sm.png") else: st.logo("./logos/sicoob-logo-horizontal-dark.png", icon_image="./logos/sicoob-logo-vertical-sm.png") st.session_state.theme = "dark" if st.session_state.theme == "light" else "light" @st.dialog("📄 Atualizações Sicoob Chatbot", width="small") def changelog_user(self): with open("./logos/ChangelogUser.md", encoding="utf-8") as f: st.markdown(f"{f.read()}", unsafe_allow_html=True) def get_current_style(self): theme_style = self.dark_style if st.session_state.theme == "dark" else self.light_style return f"" def stream_chat(self, user_input): """ Faz a comunicação com o backend e retorna a resposta como streaming de tokens. """ try: response = requests.post( self.backend_url, json={"message": user_input}, stream=True # Ativa o streaming ) response.raise_for_status() # Gera os tokens conforme chegam no streaming for chunk in response.iter_content(chunk_size=512): if chunk: yield chunk.decode("utf-8") except Exception as e: yield f"Erro ao conectar ao servidor: {e}" def clear_chat_history(self): st.session_state.chat_history = [] st.toast("Histórico limpo com sucesso!", icon="✅") def render_sidebar(self): """Siderbar""" with st.sidebar: # st.button("Light/Dark Mode", on_click=self.change_style) if st.session_state.theme == "light": st.logo("./logos/sicoob-logo-horizontal-light.png", icon_image="./logos/sicoob-logo-vertical-sm.png") else: st.logo("./logos/sicoob-logo-horizontal-dark.png", icon_image="./logos/sicoob-logo-vertical-sm.png") if st.button("Limpar Histórico", icon=":material/delete:"): self.clear_chat_history() st.button("Atualizações", icon=":material/info:", on_click=self.changelog_user) st.divider() def add_link_to_text(self, text): """ Adiciona links ao texto com base no padrão ||texto||. """ return re.sub(r'\|\|(.*?)\|\|', lambda match: f'
Fonte: {match.group(1)}', text) def render(self): """ Renderiza a interface do chatbot. """ st.markdown(self.get_current_style(), unsafe_allow_html=True) with open(self.configyml) as file: config = yaml.load(file, Loader=SafeLoader) authenticator = stauth.Authenticate( config['credentials'], config['cookie']['name'], config['cookie']['key'], config['cookie']['expiry_days'] ) with open('./config.yaml', 'w', encoding='utf-8') as file: yaml.dump(config, file, default_flow_style=False) authentication_status = authenticator.login(fields={'Form name': 'Autenticação', 'Username': 'Nome de Usuário', 'Password': 'Senha', 'Login': 'Entrar'}) if st.session_state["authentication_status"]: # Renderiza a barra lateral self.render_sidebar() # Título e descrição st.title(self.title) st.write(self.description) with st.sidebar: st.caption(self.caption) authenticator.logout('Sair', 'main') # Inicializa o histórico na sessão if "chat_history" not in st.session_state: st.session_state.chat_history = [] # Renderiza as mensagens do histórico for message in st.session_state.chat_history: role, text = message.split(":", 1) with st.chat_message(role.strip().lower()): st.markdown(text.strip(), unsafe_allow_html=True) # Captura o input do usuário user_input = st.chat_input(placeholder="Digite sua pergunta...") if user_input: # Exibe a mensagem do usuário with st.chat_message("user"): st.write(user_input) st.session_state.chat_history.append(f"user: {user_input}") # Placeholder para a resposta do assistente with st.chat_message("assistant"): message_placeholder = st.empty() assistant_message = "" try: # Gerando ID único para a mensagem message_id = datetime.now().strftime("%Y%m%d_%H%M%S_%f") print(f"Message ID gerado: {message_id}") # Executa o streaming de tokens enquanto o backend responde for token in self.stream_chat(user_input): assistant_message += token message_placeholder.markdown(assistant_message + "▌", unsafe_allow_html=True) except Exception as e: st.error(f"Erro durante o chat: {str(e)}") print(f"Erro durante o chat: {str(e)}") finally: assistant_message_with_link = self.add_link_to_text(assistant_message) message_placeholder.markdown(assistant_message_with_link, unsafe_allow_html=True) # Feedback self.feedback_manager.render_feedback_buttons( message_id=message_id, user_input=user_input, assistant_response=assistant_message_with_link ) # Adicionando histórico Streamlit st.session_state.chat_history.append(f"assistant: {assistant_message_with_link}") elif st.session_state["authentication_status"] == False: st.error('Nome de Usuário/Senha incorreta.') elif st.session_state["authentication_status"] == None: st.warning('Por favor entre com seu nome de usuário e senha.') if __name__ == "__main__": chatbot_app = ChatbotApp() chatbot_app.render()