diff --git a/.streamlit/config.toml b/.streamlit/config.toml index 92bba9912891fb44e75f07a0750be9891cc36154..990efbcfacbb86d2d6d25a45acbb742093bb1819 100644 --- a/.streamlit/config.toml +++ b/.streamlit/config.toml @@ -1,3 +1,6 @@ [theme] +font = "sans serif" + +[client] +toolbarMode = "developer" -base = 'light' \ No newline at end of file diff --git a/README.md b/README.md index eb8150fd115db8ba0e81fbddf83a00ed3f3bd32c..e219f3ed747568a3d3527cad7e3a863288cc4a7e 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ --- -title: Chatbot Carometro -emoji: 👁 -colorFrom: blue +title: Chatbot Carometro Staging +emoji: 💻 +colorFrom: yellow colorTo: pink sdk: docker pinned: false --- -Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference \ No newline at end of file +Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference diff --git a/app.py b/app.py index c0a7865177b1e526595fd0f64dbb6d0f2dcdcf31..8ae536d3b46286681f91c2d22102cb1365ef2cad 100644 --- a/app.py +++ b/app.py @@ -1,15 +1,61 @@ import streamlit as st import requests -from PIL import Image -import base64 +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): - # URL do backend (Flask) + # 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 = "Chatbot Carômetro" - self.description = "Este assistente virtual pode te ajudar com informações sobre carômetros da Sicoob." + 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): """ @@ -30,73 +76,106 @@ class ChatbotApp: 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): """ - Exibe opções na barra lateral e renderiza a logo do Sicoob. + Adiciona links ao texto com base no padrão ||texto||. """ - st.sidebar.title("Configuração de LLM") - sidebar_option = st.sidebar.radio("Selecione o LLM", ["gpt-3.5-turbo"]) - if sidebar_option != "gpt-3.5-turbo": - raise Exception("Opção de LLM inválida!") - - # Exibe a logo do Sicoob na barra lateral - with open("sicoob-logo.png", "rb") as f: - data = base64.b64encode(f.read()).decode("utf-8") - st.sidebar.markdown( - f""" -
- -
- """, - unsafe_allow_html=True, - ) + return re.sub(r'\|\|(.*?)\|\|', lambda match: f'
Fonte: {match.group(1)}', text) def render(self): """ Renderiza a interface do chatbot. """ - # Configura título, ícone e layout da página - im = Image.open("pngegg.png") - st.set_page_config(page_title="Chatbot Carômetro", page_icon=im, layout="wide") - - # Renderiza a barra lateral - self.render_sidebar() - - # Título e descrição - st.title(self.title) - st.write(self.description) - - # 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.write(text.strip()) - - # Captura o input do usuário - user_input = st.chat_input("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 = "" - - # 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 + "▌") - - # Atualiza o placeholder com a mensagem final - message_placeholder.markdown(assistant_message) - st.session_state.chat_history.append(f"assistant: {assistant_message}") + 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__": diff --git a/chatbot_server.py b/chatbot_server.py index 8f17b755be77bc2d8dc0aef2e739a32fda9ef95d..c0769bd6af25449e128634003d058e8a17715dc0 100644 --- a/chatbot_server.py +++ b/chatbot_server.py @@ -1,144 +1,140 @@ -import os -import logging -import sys - -from flask import Flask, request, jsonify, Response -# Inicializa o Flask -app = Flask(__name__) - -logging.basicConfig(stream=sys.stdout, level=logging.INFO) - -from llama_index.llms.openai import OpenAI -from llama_index.embeddings.openai import OpenAIEmbedding -from llama_index.core import ( - Settings, - SimpleDirectoryReader, - StorageContext, - Document, -) - -Settings.llm = OpenAI(model="gpt-3.5-turbo") -Settings.embed_model = OpenAIEmbedding(model_name="text-embedding-3-small") -directory_path = "documentos" -from llama_index.readers.file import PDFReader #concatenar todo o documento já vem nativo no pdfreader -file_extractor = {".pdf": PDFReader(return_full_document = True)} -from drive_downloader import GoogleDriveDownloader - -# ID da pasta no Drive e caminho local -folder_id = "1n34bmh9rlbOtCvE_WPZRukQilKeabWsN" -local_path = directory_path - -GoogleDriveDownloader().download_from_folder(folder_id, local_path) - -documents = SimpleDirectoryReader( - input_dir=directory_path, - file_extractor=file_extractor, - filename_as_id=True, - recursive=True -).load_data() - -from document_creator import create_single_document_with_filenames -document = create_single_document_with_filenames(directory_path = directory_path) -documents.append(document) - -from llama_index.core.ingestion import IngestionPipeline -#ingestion pipeline vai entrar em uso quando adicionar o extrator de metadados -from llama_index.core.node_parser import SentenceSplitter -splitter = SentenceSplitter(chunk_size=1024, chunk_overlap=128) -nodes = splitter.get_nodes_from_documents(documents) -#from llama_index.core.extractors import ( -# SummaryExtractor, -#) -#summary = SummaryExtractor(llm = OpenAI(model="gpt-3.5-turbo", system_prompt "Sempre escreva e responda em português brasileiro.")) -#pipeline = IngestionPipeline( -# transformations=[splitter, summary] -#) - -#nodes = pipeline.run( - # documents=documents, - # in_place=True, -# show_progress=True, -#) - -from llama_index.core.storage.docstore import SimpleDocumentStore -docstore = SimpleDocumentStore() -docstore.add_documents(nodes) - -from llama_index.core import VectorStoreIndex, StorageContext -from llama_index.vector_stores.chroma import ChromaVectorStore -import chromadb - -db = chromadb.PersistentClient(path="./storage/chroma_db") -chroma_collection = db.get_or_create_collection("dense_vectors") -vector_store = ChromaVectorStore(chroma_collection=chroma_collection) -storage_context = StorageContext.from_defaults( - docstore=docstore, vector_store=vector_store - ) -index = VectorStoreIndex(nodes = nodes, storage_context=storage_context, show_progress = True) - -storage_context.docstore.persist("./storage/docstore.json") - -index_retriever = index.as_retriever(similarity_top_k=2) -import nest_asyncio -nest_asyncio.apply() -from llama_index.retrievers.bm25 import BM25Retriever -bm25_retriever = BM25Retriever.from_defaults( - docstore=index.docstore, - similarity_top_k=2, - language = "portuguese", - verbose=True, - ) - -from llama_index.core.retrievers import QueryFusionRetriever - -retriever = QueryFusionRetriever( - [index_retriever, bm25_retriever], - num_queries=1, #desativado = 1 - mode="reciprocal_rerank", - use_async=True, - verbose=True, -) - -from llama_index.core.storage.chat_store import SimpleChatStore -from llama_index.core.memory import ChatMemoryBuffer -chat_store = SimpleChatStore() -chat_memory = ChatMemoryBuffer.from_defaults( - token_limit=3000, - chat_store=chat_store, - chat_store_key="user1", -) -from llama_index.core.query_engine import RetrieverQueryEngine -query_engine = RetrieverQueryEngine.from_args(retriever) -from llama_index.core.chat_engine import CondensePlusContextChatEngine -chat_engine = CondensePlusContextChatEngine.from_defaults( - query_engine, - memory=chat_memory, - context_prompt=( - "Você é um assistente virtual capaz de interagir normalmente, além de" - " fornecer informações sobre organogramas e listar funcionários." - " Aqui estão os documentos relevantes para o contexto:\n" - "{context_str}" - "\nInstrução: Use o histórico da conversa anterior, ou o contexto acima, para responder." - ), -) - - - -@app.route("/chat", methods=["POST"]) -def chat(): - user_input = request.json.get("message", "") - if not user_input: - return jsonify({"error": "Mensagem vazia"}), 400 - - def generate_response(): - try: - response = chat_engine.stream_chat(user_input) - for token in response.response_gen: - yield token # Envia cada token - chat_store.persist(persist_path="./storage/chat_store.json") - except Exception as e: - yield f"Erro: {str(e)}" - - return Response(generate_response(), content_type="text/plain") -if __name__ == "__main__": - app.run(port=5001, debug=False) +import os +import logging +import sys + +from flask import Flask, request, jsonify, Response +# Inicializa o Flask +app = Flask(__name__) + +logging.basicConfig(stream=sys.stdout, level=logging.INFO) + +from llama_index.llms.openai import OpenAI +from llama_index.embeddings.openai import OpenAIEmbedding +from llama_index.core import ( + Settings, + SimpleDirectoryReader, + StorageContext, + Document, +) + +Settings.llm = OpenAI(model="gpt-3.5-turbo") +Settings.embed_model = OpenAIEmbedding(model_name="text-embedding-3-small") +directory_path = "documentos" +from llama_index.readers.file import PDFReader #concatenar todo o documento já vem nativo no pdfreader +file_extractor = {".pdf": PDFReader(return_full_document = True)} +from drive_downloader import GoogleDriveDownloader + +# ID da pasta no Drive e caminho local +folder_id = "1n34bmh9rlbOtCvE_WPZRukQilKeabWsN" +local_path = directory_path + +GoogleDriveDownloader().download_from_folder(folder_id, local_path) + +documents = SimpleDirectoryReader( + input_dir=directory_path, + file_extractor=file_extractor, + filename_as_id=True, + recursive=True +).load_data() + +from document_creator import create_single_document_with_filenames +document = create_single_document_with_filenames(directory_path = directory_path) +documents.append(document) + +#from llama_index.core.ingestion import IngestionPipeline +#ingestion pipeline vai entrar em uso quando adicionar o extrator de metadados +from llama_index.core.node_parser import SentenceSplitter +splitter = SentenceSplitter(chunk_size=1024, chunk_overlap=128) +nodes = splitter.get_nodes_from_documents(documents) + +from llama_index.core.storage.docstore import SimpleDocumentStore +docstore = SimpleDocumentStore() +docstore.add_documents(nodes) + +from llama_index.core import VectorStoreIndex, StorageContext +from llama_index.vector_stores.chroma import ChromaVectorStore +import chromadb + +db = chromadb.PersistentClient(path="chroma_db") +chroma_collection = db.get_or_create_collection("dense_vectors") +vector_store = ChromaVectorStore(chroma_collection=chroma_collection) +storage_context = StorageContext.from_defaults( + docstore=docstore, vector_store=vector_store + ) +index = VectorStoreIndex(nodes = nodes, storage_context=storage_context, show_progress = True) + +storage_context.docstore.persist("./docstore.json") + +index_retriever = index.as_retriever(similarity_top_k=2) +import nest_asyncio +nest_asyncio.apply() +from llama_index.retrievers.bm25 import BM25Retriever +bm25_retriever = BM25Retriever.from_defaults( + docstore=index.docstore, + similarity_top_k=2, + language = "portuguese", + verbose=True, + ) + +from llama_index.core.retrievers import QueryFusionRetriever + +retriever = QueryFusionRetriever( + [index_retriever, bm25_retriever], + num_queries=1, #desativado = 1 + mode="reciprocal_rerank", + use_async=True, + verbose=True, +) + + +from llama_index.core.memory import ChatMemoryBuffer +from mysqlchatstore import MySQLChatStore +chat_store = MySQLChatStore.from_params( + host=os.getenv("MYSQL_HOST"), + port=os.getenv("MYSQL_PORT"), + user=os.getenv("MYSQL_USER"), + password=os.getenv("MYSQL_PASSWORD"), + database=os.getenv("MYSQL_DATABASE"), + table_name=os.getenv("MYSQL_TABLE") +) +chat_memory = ChatMemoryBuffer.from_defaults( + token_limit=3000, + chat_store=chat_store, + chat_store_key="Sicoob", #Tendo algumas dificuldades ainda pra passar o user +) +from llama_index.core.query_engine import RetrieverQueryEngine +query_engine = RetrieverQueryEngine.from_args(retriever) +from llama_index.core.chat_engine import CondensePlusContextChatEngine +chat_engine = CondensePlusContextChatEngine.from_defaults( + query_engine, + memory=chat_memory, + context_prompt=( + "Você é um assistente virtual capaz de interagir normalmente, além de" + " fornecer informações sobre organogramas e listar funcionários." + " Aqui estão os documentos relevantes para o contexto:\n" + "{context_str}" + "\nInstrução: Use o histórico da conversa anterior, ou o contexto acima, para responder." + "No final da resposta, depois de uma quebra de linha escreva o nome do documento que contém a informação entre dois ||, como ||Documento Nome||" + + ), +) + + + +@app.route("/chat", methods=["POST"]) +def chat(): + user_input = request.json.get("message", "") + if not user_input: + return jsonify({"error": "Mensagem vazia"}), 400 + + def generate_response(): + try: + response = chat_engine.stream_chat(user_input) + for token in response.response_gen: + yield token # Envia cada token + except Exception as e: + yield f"Erro: {str(e)}" + + return Response(generate_response(), content_type="text/plain") +if __name__ == "__main__": + app.run(port=5001, debug=False) diff --git a/config.yaml b/config.yaml new file mode 100644 index 0000000000000000000000000000000000000000..37d5611b7830e0ff36e1924f09191e35e7d8db23 --- /dev/null +++ b/config.yaml @@ -0,0 +1,38 @@ +cookie: + expiry_days: 30 + key: some_signature_key + name: some_cookie_name +credentials: + usernames: + akcit_root: + email: akcit_root@mail.com + failed_login_attempts: 0 + first_name: akcit + last_name: root + logged_in: false + password: $2b$12$wd1lg1DTs4qEDRmohdptDegeSJhGstxqgCaTitfRQ0IGN.rnr51aG + roles: + - admin + - editor + - viewer + sicoob_central: + email: sicoob_central@mail.com + failed_login_attempts: 0 + first_name: sicoob + last_name: central + logged_in: false + password: $2b$12$Y5tHfGABzVP9dm510HuHHuUbeZvNqUibUgj4TYH40rglhZGLPZ8rK + roles: + - viewer + sicoob_unidade: + email: sicoob_unidade@mail.com + failed_login_attempts: 0 + first_name: sicoob + last_name: unidade + logged_in: false + password: $2b$12$h8U7XrVfACkHJaqGqcwR0OzDO.YorKF21lHpG/9MVa4K/98AbXtG. + roles: + - viewer +pre-authorized: + emails: + - akcit_root@mail.com diff --git a/drive_search.py b/drive_search.py new file mode 100644 index 0000000000000000000000000000000000000000..436844def8d98b585b85cc1386338c25604d099f --- /dev/null +++ b/drive_search.py @@ -0,0 +1,77 @@ +from googleapiclient.discovery import build +from google.oauth2.service_account import Credentials +from fuzzywuzzy import process # Importando a biblioteca fuzzywuzzy +import os + +SCOPES = ["https://www.googleapis.com/auth/drive.readonly"] +FOLDER_ID = "1hqfPQnsVL2Ld8hu0GRIqcuOp-eDz-CAX" # ID da pasta que você quer buscar + +SERVICE_ACCOUNT_FILE = os.path.join(os.getcwd(), "./files/credenciais.json") +def authenticate_drive(): + """Autentica no Google Drive usando uma conta de serviço.""" + credentials = Credentials.from_service_account_file(SERVICE_ACCOUNT_FILE, scopes=SCOPES) + service = build("drive", "v3", credentials=credentials) + return service + +def list_files_recursive(service, folder_id, path=""): + """Lista todos os arquivos e subpastas no Google Drive de forma recursiva.""" + query = f"'{folder_id}' in parents and trashed = false" + response = service.files().list( + q=query, + spaces="drive", + fields="files(id, name, mimeType, parents)", + ).execute() + + files = response.get("files", []) + all_files = [] + + for file in files: + # caminho completo + current_path = f"{path}/{file['name']}" + all_files.append({"id": file["id"], "name": file["name"], "path": current_path}) + + # buscar recursivamente + if file["mimeType"] == "application/vnd.google-apps.folder": + all_files.extend(list_files_recursive(service, file["id"], current_path)) + + return all_files + +def find_file_by_name(files, search_name): + """Encontra um arquivo com nome aproximado utilizando fuzzy matching.""" + # Usando fuzzywuzzy para encontrar o arquivo mais próximo + file_names = [file["name"] for file in files] + best_match, score = process.extractOne(search_name, file_names) + + if score >= 80: # Ajuste a pontuação mínima de correspondência (por exemplo, 80%) + matching_files = [file for file in files if file["name"] == best_match] + return matching_files + else: + return [] + +def search_file_in_drive(search_name): + """Procura o arquivo mais relevante no Google Drive e retorna o link.""" + service = authenticate_drive() + print("Autenticado com sucesso no Google Drive!") + + # Listar arquivos na pasta e subpastas + files = list_files_recursive(service, FOLDER_ID) + + if not files: + print("Nenhum arquivo encontrado na pasta!") + return None # Retorna None se nenhum arquivo for encontrado + + print(f"Total de arquivos encontrados: {len(files)}") + + # Encontrar o arquivo com nome aproximado + matching_files = find_file_by_name(files, search_name) + + if matching_files: + best_file = matching_files[0] # Pega o arquivo mais relevante (primeiro da lista) + link = f"https://drive.google.com/file/d/{best_file['id']}/view" + print(f"Arquivo encontrado: {best_file['name']}") + print(f"Link: {link}") + return link # Retorna o link do arquivo encontrado + else: + print(f"Nenhum arquivo encontrado com nome aproximado '{search_name}'.") + return None # Retorna None se nenhum arquivo for encontrado + diff --git a/feedback_manager.py b/feedback_manager.py new file mode 100644 index 0000000000000000000000000000000000000000..edd3decbe67fbbb556d2a805c07109eb469e4229 --- /dev/null +++ b/feedback_manager.py @@ -0,0 +1,67 @@ +import json +from datetime import datetime +from pathlib import Path +import streamlit as st + + +class FeedbackManager: + def __init__(self, feedback_dir="./feedback"): + self.feedback_dir = Path(feedback_dir) + self.feedback_dir.mkdir(exist_ok=True) + if "feedback_submitted" not in st.session_state: + st.session_state.feedback_submitted = set() + + def save_feedback(self, feedback_type: str, user_input: str, assistant_response: str, message_id: str): + if message_id in st.session_state.feedback_submitted: + st.toast("Feedback já enviado para está mensagem.", icon="ℹ️") + return False + feedback_file = self.feedback_dir / f"feedback_{feedback_type}.json" + try: + data = [] + if feedback_file.exists(): + with open(feedback_file, 'r', encoding='utf-8') as f: + data = json.load(f) + feedback_entry = { + "message_id": message_id, + "timestamp": datetime.now().isoformat(), + "feedback_type": feedback_type, + "user_input": user_input, + "assistant_response": assistant_response, + } + data.append(feedback_entry) + with open(feedback_file, 'w', encoding='utf-8') as f: + json.dump(data, f, ensure_ascii=False, indent=2) + st.session_state.feedback_submitted.add(message_id) + emoji = "👍" if feedback_type == "positive" else "👎" + st.toast(f"Obrigado por seu Feedback! {emoji}", icon="✅") + return True + except Exception as e: + st.error(f"Error ao salvar feedback: {str(e)}") + return False + + def handle_feedback_click(self, feedback_type: str, message_id: str, user_input: str, assistant_response: str): + self.save_feedback( + feedback_type=feedback_type, + user_input=user_input, + assistant_response=assistant_response, + message_id=message_id + ) + + def render_feedback_buttons(self, message_id: str, user_input: str, assistant_response: str): + col1, col2 = st.columns(2, gap="small") + + with col1: + st.button( + "👍 Gostei", + key=f"positive_{message_id}", + on_click=self.handle_feedback_click, + args=("positive", message_id, user_input, assistant_response) + ) + + with col2: + st.button( + "👎 Não Gostei", + key=f"negative_{message_id}", + on_click=self.handle_feedback_click, + args=("negative", message_id, user_input, assistant_response) + ) diff --git a/files/config.yaml b/files/config.yaml new file mode 100644 index 0000000000000000000000000000000000000000..37d5611b7830e0ff36e1924f09191e35e7d8db23 --- /dev/null +++ b/files/config.yaml @@ -0,0 +1,38 @@ +cookie: + expiry_days: 30 + key: some_signature_key + name: some_cookie_name +credentials: + usernames: + akcit_root: + email: akcit_root@mail.com + failed_login_attempts: 0 + first_name: akcit + last_name: root + logged_in: false + password: $2b$12$wd1lg1DTs4qEDRmohdptDegeSJhGstxqgCaTitfRQ0IGN.rnr51aG + roles: + - admin + - editor + - viewer + sicoob_central: + email: sicoob_central@mail.com + failed_login_attempts: 0 + first_name: sicoob + last_name: central + logged_in: false + password: $2b$12$Y5tHfGABzVP9dm510HuHHuUbeZvNqUibUgj4TYH40rglhZGLPZ8rK + roles: + - viewer + sicoob_unidade: + email: sicoob_unidade@mail.com + failed_login_attempts: 0 + first_name: sicoob + last_name: unidade + logged_in: false + password: $2b$12$h8U7XrVfACkHJaqGqcwR0OzDO.YorKF21lHpG/9MVa4K/98AbXtG. + roles: + - viewer +pre-authorized: + emails: + - akcit_root@mail.com diff --git a/files/credenciais.json b/files/credenciais.json new file mode 100644 index 0000000000000000000000000000000000000000..aa1e37606e97e89c9e8a1bb735067c2af0f63934 --- /dev/null +++ b/files/credenciais.json @@ -0,0 +1,13 @@ +{ + "type": "service_account", + "project_id": "light-processor-374314", + "private_key_id": "a207b3d84c4dfdf97eef75f442a78b79a9af7e4a", + "private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCcU0q1HO5hdzVK\nGcVGnOaZ/Eedjqr+g70yrOylrE1Ke794vXAOFynbq2OifjwjuTJQD0ZSP2KGQC7x\np1jHolEgP7GHsusnCZeb6lPyQCvkk8M6EzxdiSY5cOm4xJAzEENZ0aFB5qMdtR/t\ndjO4YwK8eHGUXAWeL7OezC7xzLpbkFnOJYo44CQVgbIWoROQY/7MNqcw67/z/HS9\nETKyB9+lgv+w1f+1HG9XBvHKjoI79fa4njmJBGu66DN0afp9lYrdqbX24j3fieaB\nyhJOq6w0U16t/nvfLhzxixAVafMQSvuENh6DjXfQ5wCy+U2osALH5zEOqkOmNWo1\neWMPQiwVAgMBAAECggEAENdmWonB4s05eAC7wKZBr8A+pOpMYLwno3B+1EByWT5o\nu+TI0DPNpiVaSBTKfNzEX1yt6kl631TF2fH5/hPuIofKJADyFZQSedEudxBTyj3j\nD/wnijou3IxeGbJPiLjNUL1lXpiu5RHw3R/ZZZmBH3XoYp/hWQ/xjX+Y5SL1xsxk\nuslv+xGmFjAWCzCSFMIosyRl8evElFyuWeEU9IGM8h9JKs/aLTkdkN+X7o77L9pi\ndhQj5RemmKtzm7MStwVFGT2zdkMk3LCnXYi+VbuIi+wHJuZbxn+xP7nhnsu4vLcQ\nNzZKouk/7dK2px2zkaclnu8kNTQy3ONAfFrYZb3BQQKBgQDUICD7aIaA/cBlI5Ph\nifrtsyRKdWMhU2Sobe7qtX2s+azgcX7o57wxIo/dnG/2IG1rFBFbUO6Qv8UcfS9B\n9KNIdfV1+YnudOYn7TaFAhQfudWF9HrTsWZaIHpHS5yyzcpHoXvehKcU6MXy4vMj\nirY4dbx8daeiaBbkJHMtOKJZdQKBgQC8qJdWwjkSW0eJoqnNYP4SHtCo056S6Ufp\n8qkBBrpnnq85jJGzXJ71fWR3pgvGXLRjYSk2t3Csy3S7lwe6G9iszdBloHdTEQb7\nEfPpmE23m+s3YQIL0jY2UdTRrudtmk8RYpwEKZ22fz9d1x4pIBIlU2Pcc26j4uhu\nZ3zbC4mUIQKBgQDEb+RbLRaxyUsr3eCKUg6vpN+MnFxqdiGW4AcKD3wMfUIcrr3J\nzR+3mLwFi2MbWDg7mt/f4niqTwyoLz1eJMA40BO5ZpbW3iZs/v0n+x7LqnoTjK1Z\n8MRJ3h2efGTmKDCUWPSuwcVAVbdKD+T9Gu1YJ5+e2g2dFitsplyKmhGuKQKBgQCx\nPSpBBeMcTckdk0Y3fwHzACREF9wIZUV8ks8X+bwyETDJvjg7664jMBStG8BAMWP/\nYY6YqyoeDF60xiUqQXMEla9Nar3vujV2tt0R/lY1QzRuKKMFfA4WZjasb8dYfvn9\neUjd2EMk6tMbVDgvpsOlcXyF5aRyL4DyCCOSnno4QQKBgQC92jVM7MkDSzlMT6zt\nJ2HQAvKR/uzxz0GQJrqx8YPUsmGUDJDcMXbjVNCSw2UfJkdlZIfZQrbpQJACewqA\nWLfWbsGvoyZk5AnkVVQqcIrRVdk85cL5EG32VSQIyAlH+m5f4DwcEHdVUFysS6BB\nYglZoVNfDeElMat1FZR9dhXo9w==\n-----END PRIVATE KEY-----\n", + "client_email": "mydriveapi@light-processor-374314.iam.gserviceaccount.com", + "client_id": "115319015910729374958", + "auth_uri": "https://accounts.google.com/o/oauth2/auth", + "token_uri": "https://oauth2.googleapis.com/token", + "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", + "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/mydriveapi%40light-processor-374314.iam.gserviceaccount.com", + "universe_domain": "googleapis.com" +} diff --git a/logos/ChangelogUser.md b/logos/ChangelogUser.md new file mode 100644 index 0000000000000000000000000000000000000000..f96a1a0b5a940706d2cae0dc1dae37b96bf68e5b --- /dev/null +++ b/logos/ChangelogUser.md @@ -0,0 +1,31 @@ +# Changelog - Versão 0.4.0 + +## Novos Recursos + +- **Suporte a múltiplos manuais**: O chatbot agora pode acessar e fornecer informações de diversos manuais. + - Manuais disponíveis nesta versão: + - Manual de Normatização + - Manual de Riscos Sociais, Ambientais e Climáticos + - Manual de Supervisão Auxiliar + - Manual de Controles Internos e Conformidade + - Manual de Crédito + - Manual de Boas Práticas Legais e Tributárias nas Campanhas e Promoções + - Manual de Gerenciamento do Risco de Mercado e do IRRBB + - Manual de Seguro Vida Prestamista + - Manual do Produto Pix + - Manual de Câmbio - Operações de Crédito + - ... + +## Melhorias + +- **Qualidade de resposta aprimorada**: Refinamento nos modelos de resposta para oferecer informações mais precisas e relevantes. +- **Otimização de consultas**: Melhorias no tempo de resposta ao buscar informações em documentos. + +## Alterações e Remoções + +- **Remoção temporária de respostas sobre o organograma**: Devido a ajustes internos, informações sobre a estrutura organizacional foram temporariamente desativadas. Previsto para retorno na versão 0.5.0. + +## Próximos Passos + +- **Expansão do suporte a mais manuais e documentos internos.** +- **Reintegração das informações sobre o organograma na versão 0.5.0.** diff --git a/logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-Black.eot b/logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-Black.eot new file mode 100644 index 0000000000000000000000000000000000000000..145ad633e9a0906fc07ed08f5fd99de7788a9dd0 Binary files /dev/null and b/logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-Black.eot differ diff --git a/logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-BlackItalic.eot b/logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-BlackItalic.eot new file mode 100644 index 0000000000000000000000000000000000000000..9dfed35b84bf259e11facc103156d19aa7906b25 Binary files /dev/null and b/logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-BlackItalic.eot differ diff --git a/logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-Bold.eot b/logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-Bold.eot new file mode 100644 index 0000000000000000000000000000000000000000..6279ec0d28a831782a159e5c23de39e807d7813a Binary files /dev/null and b/logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-Bold.eot differ diff --git a/logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-BoldItalic.eot b/logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-BoldItalic.eot new file mode 100644 index 0000000000000000000000000000000000000000..91a2b1451a28ad2591f49dabd7af2d216aa73a24 Binary files /dev/null and b/logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-BoldItalic.eot differ diff --git a/logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-Extrabold.eot b/logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-Extrabold.eot new file mode 100644 index 0000000000000000000000000000000000000000..c9ffb0eed07443271f3edd6207c167bbe98634a8 Binary files /dev/null and b/logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-Extrabold.eot differ diff --git a/logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-ExtraboldItalic.eot b/logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-ExtraboldItalic.eot new file mode 100644 index 0000000000000000000000000000000000000000..2ba4907844a9b179af55d54a536bc94f0d108a0b Binary files /dev/null and b/logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-ExtraboldItalic.eot differ diff --git a/logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-Extralight.eot b/logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-Extralight.eot new file mode 100644 index 0000000000000000000000000000000000000000..b55584d3c8321012e4c85592f90bd0421dd2f5b2 Binary files /dev/null and b/logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-Extralight.eot differ diff --git a/logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-ExtralightItalic.eot b/logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-ExtralightItalic.eot new file mode 100644 index 0000000000000000000000000000000000000000..567a34f14f19a09bcee2b48ee1162222d52699b9 Binary files /dev/null and b/logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-ExtralightItalic.eot differ diff --git a/logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-Italic.eot b/logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-Italic.eot new file mode 100644 index 0000000000000000000000000000000000000000..a1db412ef08f2203065e4b7adc9b22b4625a1b0c Binary files /dev/null and b/logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-Italic.eot differ diff --git a/logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-Light.eot b/logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-Light.eot new file mode 100644 index 0000000000000000000000000000000000000000..257f8d39bbc595a20b081702db2086c98b5be7c1 Binary files /dev/null and b/logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-Light.eot differ diff --git a/logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-LightItalic.eot b/logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-LightItalic.eot new file mode 100644 index 0000000000000000000000000000000000000000..633cd7cce1fce44942935a717aad8b4e290fed8f Binary files /dev/null and b/logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-LightItalic.eot differ diff --git a/logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-Medium.eot b/logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-Medium.eot new file mode 100644 index 0000000000000000000000000000000000000000..b55c14d4d71cd61ee82ce234931237d77e94c253 Binary files /dev/null and b/logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-Medium.eot differ diff --git a/logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-MediumItalic.eot b/logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-MediumItalic.eot new file mode 100644 index 0000000000000000000000000000000000000000..db5e9e712fcac5da46f140feae3b2611330703ae Binary files /dev/null and b/logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-MediumItalic.eot differ diff --git a/logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-Regular.eot b/logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-Regular.eot new file mode 100644 index 0000000000000000000000000000000000000000..0c1d45ca5d9aa3ca573fae9132b2eb149936383c Binary files /dev/null and b/logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-Regular.eot differ diff --git a/logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-Semibold.eot b/logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-Semibold.eot new file mode 100644 index 0000000000000000000000000000000000000000..cad82cda40cc51ccb67ef8f07af5f9689bbe81cf Binary files /dev/null and b/logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-Semibold.eot differ diff --git a/logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-SemiboldItalic.eot b/logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-SemiboldItalic.eot new file mode 100644 index 0000000000000000000000000000000000000000..5ffe47ff04348a5e550962cf45dbfb82f3cd0769 Binary files /dev/null and b/logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-SemiboldItalic.eot differ diff --git a/logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-Thin.eot b/logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-Thin.eot new file mode 100644 index 0000000000000000000000000000000000000000..1bdfd67221c4144fd6688668526ef0facf511d85 Binary files /dev/null and b/logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-Thin.eot differ diff --git a/logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-ThinItalic.eot b/logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-ThinItalic.eot new file mode 100644 index 0000000000000000000000000000000000000000..9edfe7ad5669430109e0a9f7912e37941a0d1e59 Binary files /dev/null and b/logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-ThinItalic.eot differ diff --git a/logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-Black.ttf b/logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-Black.ttf new file mode 100644 index 0000000000000000000000000000000000000000..3d8b6aa2def0f79e350c038e21a3cf9b4df934c9 Binary files /dev/null and b/logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-Black.ttf differ diff --git a/logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-BlackItalic.ttf b/logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-BlackItalic.ttf new file mode 100644 index 0000000000000000000000000000000000000000..49d1177de13c9f68cf1b952bff432dce771ac5e8 Binary files /dev/null and b/logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-BlackItalic.ttf differ diff --git a/logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-Bold.ttf b/logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-Bold.ttf new file mode 100644 index 0000000000000000000000000000000000000000..bff6f1f2d93f68ee439bd6c2f3cf8c48133ee610 Binary files /dev/null and b/logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-Bold.ttf differ diff --git a/logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-BoldItalic.ttf b/logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-BoldItalic.ttf new file mode 100644 index 0000000000000000000000000000000000000000..bbf6bfa8b3e73c3ecbd4d9137174f4fb3723fd4e Binary files /dev/null and b/logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-BoldItalic.ttf differ diff --git a/logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-Extrabold.ttf b/logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-Extrabold.ttf new file mode 100644 index 0000000000000000000000000000000000000000..6d2087a4dccde5b75df2c012ab9ca7832cf5b9c7 Binary files /dev/null and b/logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-Extrabold.ttf differ diff --git a/logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-ExtraboldItalic.ttf b/logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-ExtraboldItalic.ttf new file mode 100644 index 0000000000000000000000000000000000000000..4abc82ab4d42c8d583f246439f7687f9c0a64b16 Binary files /dev/null and b/logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-ExtraboldItalic.ttf differ diff --git a/logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-Extralight.ttf b/logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-Extralight.ttf new file mode 100644 index 0000000000000000000000000000000000000000..b620be257ddf4cc94a1ecdc913c5ff0925788ccf Binary files /dev/null and b/logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-Extralight.ttf differ diff --git a/logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-ExtralightItalic.ttf b/logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-ExtralightItalic.ttf new file mode 100644 index 0000000000000000000000000000000000000000..9471a1ee1bb09af7a3dd8de70f3d1cc80f4a29d9 Binary files /dev/null and b/logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-ExtralightItalic.ttf differ diff --git a/logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-Italic.ttf b/logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-Italic.ttf new file mode 100644 index 0000000000000000000000000000000000000000..eb4313504884f51516c0a854d5b67137649b5fbe Binary files /dev/null and b/logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-Italic.ttf differ diff --git a/logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-Light.ttf b/logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-Light.ttf new file mode 100644 index 0000000000000000000000000000000000000000..482a304f15873f630a0c3eb1b09ab2148e45c188 Binary files /dev/null and b/logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-Light.ttf differ diff --git a/logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-LightItalic.ttf b/logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-LightItalic.ttf new file mode 100644 index 0000000000000000000000000000000000000000..fbb98d234fa88afa55914278994b49ca045f40d8 Binary files /dev/null and b/logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-LightItalic.ttf differ diff --git a/logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-Medium.ttf b/logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-Medium.ttf new file mode 100644 index 0000000000000000000000000000000000000000..2db4107ac92e4f0cf1b286297e84d25081d518da Binary files /dev/null and b/logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-Medium.ttf differ diff --git a/logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-MediumItalic.ttf b/logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-MediumItalic.ttf new file mode 100644 index 0000000000000000000000000000000000000000..89a850aa87c7882ba6977d5d5869dcf0f1889c6b Binary files /dev/null and b/logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-MediumItalic.ttf differ diff --git a/logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-Regular.ttf b/logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-Regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..b289b5117c4bd571e8f3c02426ebd88ba62352a2 Binary files /dev/null and b/logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-Regular.ttf differ diff --git a/logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-Semibold.ttf b/logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-Semibold.ttf new file mode 100644 index 0000000000000000000000000000000000000000..627f9b2ad8312dc7eacc0aaf9f8baf437827decd Binary files /dev/null and b/logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-Semibold.ttf differ diff --git a/logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-SemiboldItalic.ttf b/logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-SemiboldItalic.ttf new file mode 100644 index 0000000000000000000000000000000000000000..773a9028602f122e8422ef6ce3a20db38e95054b Binary files /dev/null and b/logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-SemiboldItalic.ttf differ diff --git a/logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-Thin.ttf b/logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-Thin.ttf new file mode 100644 index 0000000000000000000000000000000000000000..0fbc7ac7932b32f1c1085281a21a3e697bc94827 Binary files /dev/null and b/logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-Thin.ttf differ diff --git a/logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-ThinItalic.ttf b/logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-ThinItalic.ttf new file mode 100644 index 0000000000000000000000000000000000000000..94d4f48c96e54a17232ede815da191cc4e91e932 Binary files /dev/null and b/logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-ThinItalic.ttf differ diff --git a/logos/fonts/Sicoob_Sans/WOFF/SicoobSansRC3-Black.woff b/logos/fonts/Sicoob_Sans/WOFF/SicoobSansRC3-Black.woff new file mode 100644 index 0000000000000000000000000000000000000000..63a6b2d04138289fbd2da97c6e15dda60e8c2357 Binary files /dev/null and b/logos/fonts/Sicoob_Sans/WOFF/SicoobSansRC3-Black.woff differ diff --git a/logos/fonts/Sicoob_Sans/WOFF/SicoobSansRC3-BlackItalic.woff b/logos/fonts/Sicoob_Sans/WOFF/SicoobSansRC3-BlackItalic.woff new file mode 100644 index 0000000000000000000000000000000000000000..ac7ed163ade5047cb72a444b8f521d1e15976d4c Binary files /dev/null and b/logos/fonts/Sicoob_Sans/WOFF/SicoobSansRC3-BlackItalic.woff differ diff --git a/logos/fonts/Sicoob_Sans/WOFF/SicoobSansRC3-Bold.woff b/logos/fonts/Sicoob_Sans/WOFF/SicoobSansRC3-Bold.woff new file mode 100644 index 0000000000000000000000000000000000000000..63155ac36d0f686c44bc56b29c756ec988f8508b Binary files /dev/null and b/logos/fonts/Sicoob_Sans/WOFF/SicoobSansRC3-Bold.woff differ diff --git a/logos/fonts/Sicoob_Sans/WOFF/SicoobSansRC3-BoldItalic.woff b/logos/fonts/Sicoob_Sans/WOFF/SicoobSansRC3-BoldItalic.woff new file mode 100644 index 0000000000000000000000000000000000000000..69f4b9785021ce0a477a554418029be8c6035616 Binary files /dev/null and b/logos/fonts/Sicoob_Sans/WOFF/SicoobSansRC3-BoldItalic.woff differ diff --git a/logos/fonts/Sicoob_Sans/WOFF/SicoobSansRC3-Extrabold.woff b/logos/fonts/Sicoob_Sans/WOFF/SicoobSansRC3-Extrabold.woff new file mode 100644 index 0000000000000000000000000000000000000000..7a3e51494905bb9735d339c8aa7526d40232c8ea Binary files /dev/null and b/logos/fonts/Sicoob_Sans/WOFF/SicoobSansRC3-Extrabold.woff differ diff --git a/logos/fonts/Sicoob_Sans/WOFF/SicoobSansRC3-ExtraboldItalic.woff b/logos/fonts/Sicoob_Sans/WOFF/SicoobSansRC3-ExtraboldItalic.woff new file mode 100644 index 0000000000000000000000000000000000000000..722136ce32bf4a770d6e17e9822738c7f29de53f Binary files /dev/null and b/logos/fonts/Sicoob_Sans/WOFF/SicoobSansRC3-ExtraboldItalic.woff differ diff --git a/logos/fonts/Sicoob_Sans/WOFF/SicoobSansRC3-Extralight.woff b/logos/fonts/Sicoob_Sans/WOFF/SicoobSansRC3-Extralight.woff new file mode 100644 index 0000000000000000000000000000000000000000..d19683abca589021b7d8d3aa66bccda5c281ecad Binary files /dev/null and b/logos/fonts/Sicoob_Sans/WOFF/SicoobSansRC3-Extralight.woff differ diff --git a/logos/fonts/Sicoob_Sans/WOFF/SicoobSansRC3-ExtralightItalic.woff b/logos/fonts/Sicoob_Sans/WOFF/SicoobSansRC3-ExtralightItalic.woff new file mode 100644 index 0000000000000000000000000000000000000000..77409c4a2f459b20ed97d17fb0b0be53b01b09e8 Binary files /dev/null and b/logos/fonts/Sicoob_Sans/WOFF/SicoobSansRC3-ExtralightItalic.woff differ diff --git a/logos/fonts/Sicoob_Sans/WOFF/SicoobSansRC3-Italic.woff b/logos/fonts/Sicoob_Sans/WOFF/SicoobSansRC3-Italic.woff new file mode 100644 index 0000000000000000000000000000000000000000..ab62e375fc844a0ca4ec6fce4a786afc07315866 Binary files /dev/null and b/logos/fonts/Sicoob_Sans/WOFF/SicoobSansRC3-Italic.woff differ diff --git a/logos/fonts/Sicoob_Sans/WOFF/SicoobSansRC3-Light.woff b/logos/fonts/Sicoob_Sans/WOFF/SicoobSansRC3-Light.woff new file mode 100644 index 0000000000000000000000000000000000000000..da1e33f97b3f0505d093f4296db4b83e0096edfc Binary files /dev/null and b/logos/fonts/Sicoob_Sans/WOFF/SicoobSansRC3-Light.woff differ diff --git a/logos/fonts/Sicoob_Sans/WOFF/SicoobSansRC3-LightItalic.woff b/logos/fonts/Sicoob_Sans/WOFF/SicoobSansRC3-LightItalic.woff new file mode 100644 index 0000000000000000000000000000000000000000..7ec907e8e88d0ebaaad2fdf8b74ed854b320b9af Binary files /dev/null and b/logos/fonts/Sicoob_Sans/WOFF/SicoobSansRC3-LightItalic.woff differ diff --git a/logos/fonts/Sicoob_Sans/WOFF/SicoobSansRC3-Medium.woff b/logos/fonts/Sicoob_Sans/WOFF/SicoobSansRC3-Medium.woff new file mode 100644 index 0000000000000000000000000000000000000000..c56e5ec55a1c6806c606a76b939beeb58310e344 Binary files /dev/null and b/logos/fonts/Sicoob_Sans/WOFF/SicoobSansRC3-Medium.woff differ diff --git a/logos/fonts/Sicoob_Sans/WOFF/SicoobSansRC3-MediumItalic.woff b/logos/fonts/Sicoob_Sans/WOFF/SicoobSansRC3-MediumItalic.woff new file mode 100644 index 0000000000000000000000000000000000000000..992e4702446bb288c1b6b34738e0f4a4d660e25e Binary files /dev/null and b/logos/fonts/Sicoob_Sans/WOFF/SicoobSansRC3-MediumItalic.woff differ diff --git a/logos/fonts/Sicoob_Sans/WOFF/SicoobSansRC3-Regular.woff b/logos/fonts/Sicoob_Sans/WOFF/SicoobSansRC3-Regular.woff new file mode 100644 index 0000000000000000000000000000000000000000..1d0ab1f847afe568e49addbd3d50589f33b3694c Binary files /dev/null and b/logos/fonts/Sicoob_Sans/WOFF/SicoobSansRC3-Regular.woff differ diff --git a/logos/fonts/Sicoob_Sans/WOFF/SicoobSansRC3-Semibold.woff b/logos/fonts/Sicoob_Sans/WOFF/SicoobSansRC3-Semibold.woff new file mode 100644 index 0000000000000000000000000000000000000000..6724d151920115bbda1cc464893f7bae9e3f4018 Binary files /dev/null and b/logos/fonts/Sicoob_Sans/WOFF/SicoobSansRC3-Semibold.woff differ diff --git a/logos/fonts/Sicoob_Sans/WOFF/SicoobSansRC3-SemiboldItalic.woff b/logos/fonts/Sicoob_Sans/WOFF/SicoobSansRC3-SemiboldItalic.woff new file mode 100644 index 0000000000000000000000000000000000000000..be04e9447dd3dd6426d37f0a937737b2d1e84e3e Binary files /dev/null and b/logos/fonts/Sicoob_Sans/WOFF/SicoobSansRC3-SemiboldItalic.woff differ diff --git a/logos/fonts/Sicoob_Sans/WOFF/SicoobSansRC3-Thin.woff b/logos/fonts/Sicoob_Sans/WOFF/SicoobSansRC3-Thin.woff new file mode 100644 index 0000000000000000000000000000000000000000..c283fa08d8262922e7ec3da99d011f27bbd4bddc Binary files /dev/null and b/logos/fonts/Sicoob_Sans/WOFF/SicoobSansRC3-Thin.woff differ diff --git a/logos/fonts/Sicoob_Sans/WOFF/SicoobSansRC3-ThinItalic.woff b/logos/fonts/Sicoob_Sans/WOFF/SicoobSansRC3-ThinItalic.woff new file mode 100644 index 0000000000000000000000000000000000000000..a3faa231ad8d2d6d535205be153af98c58d0f604 Binary files /dev/null and b/logos/fonts/Sicoob_Sans/WOFF/SicoobSansRC3-ThinItalic.woff differ diff --git a/logos/fonts/Sicoob_Sans/WOFF2/SicoobSansRC3-Black.woff2 b/logos/fonts/Sicoob_Sans/WOFF2/SicoobSansRC3-Black.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..481b396b1ddb9b4be8f10bf9d7ca65ee84a4eda7 Binary files /dev/null and b/logos/fonts/Sicoob_Sans/WOFF2/SicoobSansRC3-Black.woff2 differ diff --git a/logos/fonts/Sicoob_Sans/WOFF2/SicoobSansRC3-BlackItalic.woff2 b/logos/fonts/Sicoob_Sans/WOFF2/SicoobSansRC3-BlackItalic.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..34ca9464e0f17d54c02d1b6e3ffd75a2550b8f1f Binary files /dev/null and b/logos/fonts/Sicoob_Sans/WOFF2/SicoobSansRC3-BlackItalic.woff2 differ diff --git a/logos/fonts/Sicoob_Sans/WOFF2/SicoobSansRC3-Bold.woff2 b/logos/fonts/Sicoob_Sans/WOFF2/SicoobSansRC3-Bold.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..13f4f133d80feffe7b38e9853bf895d5d1f4dbcb Binary files /dev/null and b/logos/fonts/Sicoob_Sans/WOFF2/SicoobSansRC3-Bold.woff2 differ diff --git a/logos/fonts/Sicoob_Sans/WOFF2/SicoobSansRC3-BoldItalic.woff2 b/logos/fonts/Sicoob_Sans/WOFF2/SicoobSansRC3-BoldItalic.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..7b53ee9185c612a356169f70f937842aa147d8e5 Binary files /dev/null and b/logos/fonts/Sicoob_Sans/WOFF2/SicoobSansRC3-BoldItalic.woff2 differ diff --git a/logos/fonts/Sicoob_Sans/WOFF2/SicoobSansRC3-Extrabold.woff2 b/logos/fonts/Sicoob_Sans/WOFF2/SicoobSansRC3-Extrabold.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..0e05f912f2ee2dec53521cbdf672a03245a409bc Binary files /dev/null and b/logos/fonts/Sicoob_Sans/WOFF2/SicoobSansRC3-Extrabold.woff2 differ diff --git a/logos/fonts/Sicoob_Sans/WOFF2/SicoobSansRC3-ExtraboldItalic.woff2 b/logos/fonts/Sicoob_Sans/WOFF2/SicoobSansRC3-ExtraboldItalic.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..78f18048f462d36303bab1bc4dae8c60036654a4 Binary files /dev/null and b/logos/fonts/Sicoob_Sans/WOFF2/SicoobSansRC3-ExtraboldItalic.woff2 differ diff --git a/logos/fonts/Sicoob_Sans/WOFF2/SicoobSansRC3-Extralight.woff2 b/logos/fonts/Sicoob_Sans/WOFF2/SicoobSansRC3-Extralight.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..d58d9fd1968b10dd484092e6ff9b410bc1133339 Binary files /dev/null and b/logos/fonts/Sicoob_Sans/WOFF2/SicoobSansRC3-Extralight.woff2 differ diff --git a/logos/fonts/Sicoob_Sans/WOFF2/SicoobSansRC3-ExtralightItalic.woff2 b/logos/fonts/Sicoob_Sans/WOFF2/SicoobSansRC3-ExtralightItalic.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..49577468068fec589f80d0bf2439b9bc336c6836 Binary files /dev/null and b/logos/fonts/Sicoob_Sans/WOFF2/SicoobSansRC3-ExtralightItalic.woff2 differ diff --git a/logos/fonts/Sicoob_Sans/WOFF2/SicoobSansRC3-Italic.woff2 b/logos/fonts/Sicoob_Sans/WOFF2/SicoobSansRC3-Italic.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..c4cde0f300bbf4dfeddb01338058db20f153721a Binary files /dev/null and b/logos/fonts/Sicoob_Sans/WOFF2/SicoobSansRC3-Italic.woff2 differ diff --git a/logos/fonts/Sicoob_Sans/WOFF2/SicoobSansRC3-Light.woff2 b/logos/fonts/Sicoob_Sans/WOFF2/SicoobSansRC3-Light.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..875f15f87d3e4ab9ec3d749a203c5b331512a67d Binary files /dev/null and b/logos/fonts/Sicoob_Sans/WOFF2/SicoobSansRC3-Light.woff2 differ diff --git a/logos/fonts/Sicoob_Sans/WOFF2/SicoobSansRC3-LightItalic.woff2 b/logos/fonts/Sicoob_Sans/WOFF2/SicoobSansRC3-LightItalic.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..7491d8eae2cb7396acbc06a7e1311ecb18ff0c65 Binary files /dev/null and b/logos/fonts/Sicoob_Sans/WOFF2/SicoobSansRC3-LightItalic.woff2 differ diff --git a/logos/fonts/Sicoob_Sans/WOFF2/SicoobSansRC3-Medium.woff2 b/logos/fonts/Sicoob_Sans/WOFF2/SicoobSansRC3-Medium.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..f8ba90e499c55470ea19d634b43e7e7d28b1ffed Binary files /dev/null and b/logos/fonts/Sicoob_Sans/WOFF2/SicoobSansRC3-Medium.woff2 differ diff --git a/logos/fonts/Sicoob_Sans/WOFF2/SicoobSansRC3-MediumItalic.woff2 b/logos/fonts/Sicoob_Sans/WOFF2/SicoobSansRC3-MediumItalic.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..b6cc40cab44efcc0126a26e029ea57126668a9cc Binary files /dev/null and b/logos/fonts/Sicoob_Sans/WOFF2/SicoobSansRC3-MediumItalic.woff2 differ diff --git a/logos/fonts/Sicoob_Sans/WOFF2/SicoobSansRC3-Regular.woff2 b/logos/fonts/Sicoob_Sans/WOFF2/SicoobSansRC3-Regular.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..7fd1b532b564acc7895da8e4c2e107d6ac14fe63 Binary files /dev/null and b/logos/fonts/Sicoob_Sans/WOFF2/SicoobSansRC3-Regular.woff2 differ diff --git a/logos/fonts/Sicoob_Sans/WOFF2/SicoobSansRC3-Semibold.woff2 b/logos/fonts/Sicoob_Sans/WOFF2/SicoobSansRC3-Semibold.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..d149f33e7437921c12bdb92bccd277ee414e0718 Binary files /dev/null and b/logos/fonts/Sicoob_Sans/WOFF2/SicoobSansRC3-Semibold.woff2 differ diff --git a/logos/fonts/Sicoob_Sans/WOFF2/SicoobSansRC3-SemiboldItalic.woff2 b/logos/fonts/Sicoob_Sans/WOFF2/SicoobSansRC3-SemiboldItalic.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..bec215107a46d9d554d0f4f32e637968d7658b8a Binary files /dev/null and b/logos/fonts/Sicoob_Sans/WOFF2/SicoobSansRC3-SemiboldItalic.woff2 differ diff --git a/logos/fonts/Sicoob_Sans/WOFF2/SicoobSansRC3-Thin.woff2 b/logos/fonts/Sicoob_Sans/WOFF2/SicoobSansRC3-Thin.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..1ff8a18f2958faea25cde09b3c9b2db75a24a5f2 Binary files /dev/null and b/logos/fonts/Sicoob_Sans/WOFF2/SicoobSansRC3-Thin.woff2 differ diff --git a/logos/fonts/Sicoob_Sans/WOFF2/SicoobSansRC3-ThinItalic.woff2 b/logos/fonts/Sicoob_Sans/WOFF2/SicoobSansRC3-ThinItalic.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..5d0fdf388bbd26845ceb1286fee7946df5dd11f4 Binary files /dev/null and b/logos/fonts/Sicoob_Sans/WOFF2/SicoobSansRC3-ThinItalic.woff2 differ diff --git a/logos/sicoob-ico.ico b/logos/sicoob-ico.ico new file mode 100644 index 0000000000000000000000000000000000000000..35eae4583397e474ff61e7719f3652c15747875c Binary files /dev/null and b/logos/sicoob-ico.ico differ diff --git a/logos/sicoob-logo-horizontal-dark.png b/logos/sicoob-logo-horizontal-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..dd4c5eda12bba6c8b5c59990f4f632fc81fc97ff Binary files /dev/null and b/logos/sicoob-logo-horizontal-dark.png differ diff --git a/logos/sicoob-logo-horizontal-light.png b/logos/sicoob-logo-horizontal-light.png new file mode 100644 index 0000000000000000000000000000000000000000..66d7269e6160ad78fc23ab0241543d35fd8b5a57 Binary files /dev/null and b/logos/sicoob-logo-horizontal-light.png differ diff --git a/logos/sicoob-logo-vertical-lg.png b/logos/sicoob-logo-vertical-lg.png new file mode 100644 index 0000000000000000000000000000000000000000..ba1b8d4a08b87024f8fc7e501f672ef0c4190537 Binary files /dev/null and b/logos/sicoob-logo-vertical-lg.png differ diff --git a/logos/sicoob-logo-vertical-md.png b/logos/sicoob-logo-vertical-md.png new file mode 100644 index 0000000000000000000000000000000000000000..aaf630c7eed40fb71a80f297a4a7f4d81d137ada Binary files /dev/null and b/logos/sicoob-logo-vertical-md.png differ diff --git a/logos/sicoob-logo-vertical-sm.png b/logos/sicoob-logo-vertical-sm.png new file mode 100644 index 0000000000000000000000000000000000000000..83b372e7d025ccb0f0254ed223a119c74a5f1732 Binary files /dev/null and b/logos/sicoob-logo-vertical-sm.png differ diff --git a/logos/styles/base.css b/logos/styles/base.css new file mode 100644 index 0000000000000000000000000000000000000000..3079a8b116cad6acb9ac005cfa454c6785b799ca --- /dev/null +++ b/logos/styles/base.css @@ -0,0 +1,99 @@ +@font-face { + font-family: "sicoob-sans-regular"; + src: url("../fonts/Sicoob_Sans/WOFF2/SicoobSansRC3-Regular.woff2") format("woff2"), + url("../fonts/Sicoob_Sans/WOFF/SicoobSansRC3-Regular.woff") format("woff"), + url("../fonts/Sicoob_Sans/TTF/SicoobSansRC3-Regular.ttf") format("truetype"), + url("../fonts/Sicoob_Sans/EOT/SicoobSansRC3-Regular.eot") format("embedded-opentype"); + font-weight: 400; + font-style: normal; +} +@font-face { + font-family: "sicoob-sans-medium"; + src: url("../fonts/Sicoob_Sans/WOFF2/SicoobSansRC3-Medium.woff2") format("woff2"), + url("../fonts/Sicoob_Sans/WOFF/SicoobSansRC3-Medium.woff") format("woff"), + url("../fonts/Sicoob_Sans/TTF/SicoobSansRC3-Medium.ttf") format("truetype"), + url("../fonts/Sicoob_Sans/EOT/SicoobSansRC3-Medium.eot") format("embedded-opentype"); + font-weight: 600; + font-style: normal; +} +@font-face { + font-family: "sicoob-sans-semibold"; + src: url("../fonts/Sicoob_Sans/WOFF2/SicoobSansRC3-Semibold.woff2") format("woff2"), + url("../fonts/Sicoob_Sans/WOFF/SicoobSansRC3-Semibold.woff") format("woff"), + url("../fonts/Sicoob_Sans/TTF/SicoobSansRC3-Semibold.ttf") format("truetype"), + url("../fonts/Sicoob_Sans/EOT/SicoobSansRC3-Semibold.eot") format("embedded-opentype"); + font-weight: 600; + font-style: normal; +} +@font-face { + font-family: "sicoob-sans-bold"; + src: url("../fonts/Sicoob_Sans/WOFF2/SicoobSansRC3-Bold.woff2") format("woff2"), + url("../fonts/Sicoob_Sans/WOFF/SicoobSansRC3-Bold.woff") format("woff"), + url("../fonts/Sicoob_Sans/TTF/SicoobSansRC3-Bold.ttf") format("truetype"), + url("../fonts/Sicoob_Sans/EOT/SicoobSansRC3-Bold.eot") format("embedded-opentype"); + font-weight: 700; + font-style: normal; +} + + +body * { + font-family: "sicoob-sans-regular", sans-serif; + font-weight: 400; + transition: all 0.1s ease-in-out; +} + +.stButton > button > div > p { + font-family: "sicoob-sans-medium", sans-serif !important; + font-weight: 500; +} + + +.st-emotion-cache-kgpedg img { + height: 100% !important; +} + +h1 { + font-family: "sicoob-sans-bold", sans-serif !important; + font-weight: 700; +} + +a { + font-family: "sicoob-sans-semibold", sans-serif !important; + font-weight: 600; +} + + +.stTextInput > label { + font-family: "sicoob-sans-medium", sans-serif !important; + font-weight: 500; +} + +[data-testid="stToast"] { + font-family: "sicoob-sans-medium", sans-serif !important; + font-weight: 500; +} + +.stDecoration { + display: none; +} + +[data-testid="stIconMaterial"] { + font-family: "Material Symbols Rounded" !important; + font-weight: 400; + font-style: normal; +} + +.MuiStack-root { + background-color: transparent; +} + +[data-testid="stDialog"] > div > div > div > div { + max-height: 400px !important; + overflow: scroll; +} + +[data-testid="stExpanderIcon"] { + font-family: "Material Symbols Rounded" !important; + font-weight: 400; + font-style: normal; +} \ No newline at end of file diff --git a/logos/styles/dark.css b/logos/styles/dark.css new file mode 100644 index 0000000000000000000000000000000000000000..d5504257eb4045aa4481478b59b2ac54df365d75 --- /dev/null +++ b/logos/styles/dark.css @@ -0,0 +1,196 @@ +.stMain, .stAppHeader, .st-emotion-cache-hzygls { + background-color: #003641 !important; +} + +.stAppHeader, .st-emotion-cache-hzygls, .stBottomBlockContainer { + background-color: #002025 !important; +} + +[data-testid="stChatInputSubmitButton"] { + background-color: transparent !important; + border-radius: 10px; +} + +[data-testid="stChatInputSubmitButton"]:hover { + background-color: #002025 !important; +} + +.stSidebar { + background-color: #002530; + border-color: #7DB61C; + color: #FAFAFA +} + +[data-testid="stChatInputSubmitButton"] > svg { + fill: #7DB61C; +} + +[data-testid="stChatInputSubmitButton"]:hover { + background-color: #49479D; + border-radius: 10px; +} + +.stButton > button { + background-color: #7DB61C; + color: #FAFAFA; +} +.stButton > button:hover { + background-color: #7DB61C; + border-color: #49479D; + color: #FAFAFA; +} + +.stButton > button:active , .stButton > button:focus, .stButton > button:focus-visible, .stButton > button:focus:not(:active) { + background-color: #49479D; + border-color: #7DB61C; + color: #FAFAFA; +} + +.stChatInput { + border: none; + background-color: transparent; +} + +[data-testid="stChatInput"] > div > div { + border: none; + border-radius: 10px; +} + +[data-testid="stChatInput"] > div > div > div > textarea { + background-color: #002530; + border-radius: 10px; + border: 1px solid #7DB61C; + overflow: hidden; +} + +[data-testid="stChatInput"] > div > div > div > textarea:focus { + border-bottom-color: #49479D !important; + border-top-color: #49479D !important; + border-right-color: #49479D !important; + border-left-color: #49479D !important; +} + +a { + color: #C9D200 !important; +} + +a:hover { + color: #7DB61C !important; +} + +.stMarkdown h1 { + color: #FAFAFA !important +} + +body, .stMarkdown, .stText, .stTitle, .stHeader, .stSubheader { + color: #FAFAFA !important +} + +[data-testid="stChatMessageAvatarUser"] { + fill: #7DB61C !important; + background-color: #7DB61C !important; + width: 35px; + height: 35px; + border-radius: 50%; + padding: 5px; +} + +[data-testid="stChatMessageAvatarUser"] > svg { + color: #49479D +} + +[data-testid="stChatMessageAvatarAssistant"] { + fill: #C9D200 !important; + background-color: #C9D200 !important; + width: 35px; + height: 35px; + border-radius: 50%; + padding: 5px; +} + +[data-testid="stChatMessageAvatarAssistant"] > svg { + color: #49479D +} + +.st-key-Logout > div > button { + background-color: transparent !important; + border: none; + color: #7DB61C; +} + +hr { + background-color: #FAFAFA !important; +} + +[data-testid="stDialog"] > div > div > div > div { + color: #002025 !important; +} + +[data-testid="stDialog"] > div > div > div { + background-color: #00AE9D !important; + border-top-left-radius: 0px; + border-top-right-radius: 0px; + border-bottom-left-radius: 10px; + border-bottom-right-radius: 10px; +} + + +[data-testid="stDialog"] > div > div > div > .stMarkdown { + color: #002530 !important; +} + +[data-testid="stDialog"] > div > div > div:first-child { + background-color: #002530 !important; + border-top-left-radius: 10px; + border-top-right-radius: 10px; + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; +} + +[data-testid="stBaseButton-borderlessIcon"] { + color: #49479D; +} + +.stChatMessage:has([data-testid="stChatMessageAvatarUser"]) { + background-color: #002530 !important; + border-radius: 10px; +} + +[data-testid="stTextInputRootElement"] > div { + background-color: transparent; +} + +[data-testid="stTextInputRootElement"] { + background-color: #002530; + border-radius: 10px; + border: 1px solid #49479D; + color: #FAFAFA !important; +} + +.stTextInput > label { + color: #FAFAFA !important; +} + +.stTextInput > div > div > input { + color: #FAFAFA !important; +} + +[data-testid="stTextInputRootElement"]:hover { + border: 1px solid #7DB61C; +} + +.stFormSubmitButton > button { + background-color: #7DB61C; + color: #FAFAFA; +} + +.stFormSubmitButton > button:hover { + background-color: #7DB61C; + border-color: #49479D; + color: #49479D; +} + +.stFormSubmitButton > button:active , .stFormSubmitButton > button:focus, .stFormSubmitButton > button:focus-visible, .stFormSubmitButton > button:focus:not(:active) { + background-color: #49479D; + border-color: #7DB61C; + color: #FAFAFA; \ No newline at end of file diff --git a/logos/styles/light.css b/logos/styles/light.css new file mode 100644 index 0000000000000000000000000000000000000000..9ec8a703a127217d07016fd8286d0c72cd91d574 --- /dev/null +++ b/logos/styles/light.css @@ -0,0 +1,245 @@ +.stMain, .stAppHeader, .st-emotion-cache-hzygls { + background-color: white !important; +} + +.stAppHeader, .st-emotion-cache-hzygls, .stBottomBlockContainer { + background-color: #f3f3f3 !important; +} + +[data-testid="stChatInputSubmitButton"] { + background-color: transparent !important; + border-radius: 10px; +} + +[data-testid="stChatInputSubmitButton"]:hover { + background-color: #00AE9D !important; +} + +.stSidebar { + background-color: #ebebeb; + border-color: #7DB61C; + color: #FAFAFA +} + +.stHeading { + color: #003641 !important; +} + +[data-testid="stChatInputSubmitButton"] > svg { + fill: #00AE9D; +} + +[data-testid="stChatInputSubmitButton"]:hover { + background-color: #003641 !important; + border-radius: 10px; +} + +.stButton > button { + background-color: #003641; + color: #FAFAFA; +} + +.stButton > button:hover { + background-color: #003641; + border-color: #00AE9D; + color: #00AE9D; +} + +.stButton > button:active , .stButton > button:focus, .stButton > button:focus-visible, .stButton > button:focus:not(:active) { + background-color: #00AE9D; + border-color: #003641; + color: #FAFAFA; +} + +.stChatInput { + border: none; + background-color: transparent; +} + +[data-testid="stChatInput"] textarea::placeholder { + color: #999999 !important; + opacity: 1; +} + +[data-testid="stChatInput"] > div > div { + border: none; + border-radius: 10px; +} + +[data-testid="stChatInput"] > div > div > div > textarea { + background-color: white; + border-radius: 10px; + border: 1px solid #00AE9D; + color: #003641 !important; + overflow: hidden; +} + +[data-testid="stChatInput"] > div > div > div > textarea:focus { + border-bottom-color: #003641 !important; + border-top-color: #003641 !important; + border-right-color: #003641 !important; + border-left-color: #003641 !important; +} + +a { + color: #003641 !important; +} + +a:hover { + color: #00AE9D !important; +} + +.stMarkdown h1 { + color: #003641 !important +} + +body, .stMarkdown, .stText, .stTitle, .stHeader, .stSubheader { + color: #003641 !important +} + +[data-testid="stChatMessageAvatarUser"] { + fill: #002530 !important; + background-color: #002530 !important; + width: 35px; + height: 35px; + border-radius: 50%; + padding: 5px; +} + +[data-testid="stChatMessageAvatarUser"] > svg { + color: #FAFAFA +} + +[data-testid="stChatMessageAvatarAssistant"] { + fill: #002530 !important; + background-color: #002530 !important; + width: 35px; + height: 35px; + border-radius: 50%; + padding: 5px; +} + +[data-testid="stChatMessageAvatarAssistant"] > svg { + color: #FAFAFA +} + +.stMarkdown hr { + background-color: #002530 !important; +} + +.stSidebarHeader > div > button { + fill: #002530; +} + +.stSidebarHeader > div > button > svg { + fill: #C9D200; +} + +.stChatMessage:has([data-testid="stChatMessageAvatarUser"]) { + background-color: #008679; + color: #FAFAFA; + border-radius: 10px; + border: 0.5px solid #00AE9D; +} + +.stChatMessage:has([data-testid="stChatMessageAvatarUser"]) { + background-color: #ebfffd !important; + border-radius: 10px; + border-color: #007F73; +} + +.st-key-Logout > div > button { + background-color: transparent !important; + border: none; + color: #002530; + text-decoration: underline; +} + +.st-key-Logout > div > button:hover { + color: #00AE9D; +} + +[data-testid="stDialog"] > div > div > div > div { + background-color: #ebebeb; +} + +[data-testid="stDialog"] > div > div > div { + background-color: #ebebeb; + border-top-left-radius: 0px; + border-top-right-radius: 0px; + border-bottom-left-radius: 10px; + border-bottom-right-radius: 10px; +} + +[data-testid="stDialog"] > div > div > div:first-child { + background-color: #002530; + border-top-left-radius: 10px; + border-top-right-radius: 10px; + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; + color: #FAFAFA; +} + + +[data-testid="stAlertContainer"] p { + color: #ebebeb !important; +} + +[data-testid="stAlertContainer"] { + background-color: #00AE9D; +} + +[data-testid="stToast"] { + background-color: #ebfffd; + color: #002530; + border: 0.5px solid #00AE9D; + box-shadow: none; +} + +.stTextInput > label { + color: #002530 !important; + font-weight: bold; +} + +.stTextInput > div > div > input { + color: #999999; + background-color: transparent; + font-weight: 500; +} + +.stTextInput > div > div > input:not(:placeholder-shown) { + color: #003641 !important; + background-color: transparent; +} + +[data-testid="stTextInputRootElement"] > div { + background-color: transparent; +} + +[data-testid="stTextInputRootElement"] { + background-color: transparent; + border-radius: 10px; + border-color: #999999; + color: #999999 !important; +} + +.stFormSubmitButton > button { + background-color: #00AE9D; + color: #FAFAFA; +} + +.stFormSubmitButton > button:hover { + background-color: #00AE9D; + border-color: #003641; + color: #FAFAFA; +} + +.stFormSubmitButton > button:active , .stFormSubmitButton > button:focus, .stFormSubmitButton > button:focus-visible, .stFormSubmitButton > button:focus:not(:active) { + background-color: #003641; + border-color: #00AE9D; + color: #00AE9D; +} + +[data-testid="stBaseButton-borderlessIcon"] { + color: #7DB61C; +} \ No newline at end of file diff --git a/mysqlchatstore.py b/mysqlchatstore.py new file mode 100644 index 0000000000000000000000000000000000000000..44d6d665159923acf4ce7cea74e547cb235d61da --- /dev/null +++ b/mysqlchatstore.py @@ -0,0 +1,278 @@ +from typing import Optional, Any +from sqlalchemy import create_engine, text +from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession +from sqlalchemy.orm import sessionmaker +from pydantic import Field +import pymysql + +from llama_index.core.storage.chat_store import BaseChatStore +from llama_index.core.llms import ChatMessage +from llama_index.core.memory import ChatMemoryBuffer + + + +class MySQLChatStore(BaseChatStore): + """ + Implementação de um ChatStore que armazena mensagens em uma tabela MySQL, + unindo a pergunta do usuário e a resposta do assistente na mesma linha. + """ + table_name: Optional[str] = Field(default="chatstore", description="Nome da tabela MySQL.") + + _session: Optional[sessionmaker] = None + _async_session: Optional[sessionmaker] = None + + def __init__(self, session: sessionmaker, async_session: sessionmaker, table_name: str): + super().__init__(table_name=table_name.lower()) + self._session = session + self._async_session = async_session + self._initialize() + + @classmethod + def from_params(cls, host: str, port: str, database: str, user: str, password: str, table_name: str = "chatstore") -> "MySQLChatStore": + """ + Cria o sessionmaker síncrono e assíncrono, retornando a instância da classe. + """ + conn_str = f"mysql+pymysql://{user}:{password}@{host}:{port}/{database}" + async_conn_str = f"mysql+aiomysql://{user}:{password}@{host}:{port}/{database}" + session, async_session = cls._connect(conn_str, async_conn_str) + return cls(session=session, async_session=async_session, table_name=table_name) + + @classmethod + def _connect(cls, connection_string: str, async_connection_string: str) -> tuple[sessionmaker, sessionmaker]: + """ + Cria e retorna um sessionmaker síncrono e um sessionmaker assíncrono. + """ + engine = create_engine(connection_string, echo=False) + session = sessionmaker(bind=engine) + + async_engine = create_async_engine(async_connection_string) + async_session = sessionmaker(bind=async_engine, class_=AsyncSession) + + return session, async_session + + def _initialize(self): + """ + Garante que a tabela exista, com colunas para armazenar user_input e response. + """ + with self._session() as session: + session.execute(text(f""" + CREATE TABLE IF NOT EXISTS {self.table_name} ( + id INT AUTO_INCREMENT PRIMARY KEY, + chat_store_key VARCHAR(255) NOT NULL, + user_input TEXT, + response TEXT, + timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP + ) + """)) + session.commit() + + def get_keys(self) -> list[str]: + """ + Retorna todas as chaves armazenadas. + """ + with self._session() as session: + result = session.execute(text(f""" + SELECT DISTINCT chat_store_key FROM {self.table_name} + """)) + return [row[0] for row in result.fetchall()] + + def get_messages(self, key: str) -> list[ChatMessage]: + """ + Retorna a conversa inteira (perguntas e respostas), na ordem de inserção (id). + Cada linha pode conter o user_input, o response ou ambos (caso já respondido). + """ + with self._session() as session: + rows = session.execute(text(f""" + SELECT user_input, response + FROM {self.table_name} + WHERE chat_store_key = :key + ORDER BY id + """), {"key": key}).fetchall() + + messages = [] + for user_in, resp in rows: + if user_in is not None: + messages.append(ChatMessage(role='user', content=user_in)) + if resp is not None: + messages.append(ChatMessage(role='assistant', content=resp)) + return messages + + def set_messages(self, key: str, messages: list[ChatMessage]) -> None: + """ + Sobrescreve o histórico de mensagens de uma chave (apaga tudo e insere novamente). + Se quiser somente acrescentar, use add_message. + + Aqui, cada pergunta do usuário gera uma nova linha. + Assim que encontrar uma mensagem de assistente, atualiza essa mesma linha. + Se houver assistentes sem usuários, insere normalmente. + """ + with self._session() as session: + # Limpa histórico anterior + session.execute(text(f""" + DELETE FROM {self.table_name} WHERE chat_store_key = :key + """), {"key": key}) + + # Reinsere na ordem + current_id = None + for msg in messages: + if msg.role == 'user': + # Cria nova linha com user_input + result = session.execute(text(f""" + INSERT INTO {self.table_name} (chat_store_key, user_input) + VALUES (:key, :ui) + """), {"key": key, "ui": msg.content}) + # Pega o id do insert + current_id = result.lastrowid + + else: + # Tenta atualizar a última linha se existir + if current_id is not None: + session.execute(text(f""" + UPDATE {self.table_name} + SET response = :resp + WHERE id = :id + """), {"resp": msg.content, "id": current_id}) + # Depois de atualizar a linha, zera o current_id + current_id = None + else: + # Se não houver pergunta pendente, insere como nova linha + session.execute(text(f""" + INSERT INTO {self.table_name} (chat_store_key, response) + VALUES (:key, :resp) + """), {"key": key, "resp": msg.content}) + + session.commit() + + def add_message(self, key: str, message: ChatMessage) -> None: + """ + Acrescenta uma nova mensagem no fluxo. Se for do usuário, insere nova linha; + se for do assistente, tenta preencher a linha pendente que não tenha resposta. + """ + + with self._session() as session: + if message.role == 'user': + # Sempre cria uma nova linha para mensagens de usuário + insert_stmt = text(f""" + INSERT INTO {self.table_name} (chat_store_key, user_input) + VALUES (:key, :ui) + """) + session.execute(insert_stmt, { + "key": key, + "ui": message.content + }) + else: + # Tenta encontrar a última linha sem resposta + + row = session.execute(text(f""" + SELECT id + FROM {self.table_name} + WHERE chat_store_key = :key + AND user_input IS NOT NULL + AND response IS NULL + ORDER BY id DESC + LIMIT 1 + """), {"key": key}).fetchone() + + if row: + # Atualiza com a resposta + msg_id = row[0] + + update_stmt = text(f""" + UPDATE {self.table_name} + SET response = :resp + WHERE id = :id + """) + session.execute(update_stmt, { + "resp": message.content, + "id": msg_id + }) + else: + # Se não achar linha pendente, insere como nova + + insert_stmt = text(f""" + INSERT INTO {self.table_name} (chat_store_key, response) + VALUES (:key, :resp) + """) + session.execute(insert_stmt, { + "key": key, + "resp": message.content + }) + + session.commit() + + + + def delete_messages(self, key: str) -> None: + """ + Remove todas as linhas associadas a 'key'. + """ + with self._session() as session: + session.execute(text(f""" + DELETE FROM {self.table_name} WHERE chat_store_key = :key + """), {"key": key}) + session.commit() + + def delete_last_message(self, key: str) -> Optional[ChatMessage]: + """ + Apaga a última mensagem da conversa (considerando a ordem de inserção). + Se a última linha tiver pergunta e resposta, remove primeiro a resposta; + caso não exista resposta, remove a linha inteira. + """ + with self._session() as session: + # Localiza a última linha + row = session.execute(text(f""" + SELECT id, user_input, response + FROM {self.table_name} + WHERE chat_store_key = :key + ORDER BY id DESC + LIMIT 1 + """), {"key": key}).fetchone() + + if not row: + return None + + row_id, user_in, resp = row + + # Se a linha tiver somente pergunta, apagamos a linha inteira. + # Se tiver também a resposta, apagamos só a parte do assistente. + if user_in and resp: + # Remove a resposta + session.execute(text(f""" + UPDATE {self.table_name} + SET response = NULL + WHERE id = :id + """), {"id": row_id}) + session.commit() + return ChatMessage(role='assistant', content=resp) + else: + # Deleta a linha inteira + session.execute(text(f""" + DELETE FROM {self.table_name} + WHERE id = :id + """), {"id": row_id}) + session.commit() + + if user_in: + return ChatMessage(role='user', content=user_in) + elif resp: + return ChatMessage(role='assistant', content=resp) + else: + return None + + def delete_message(self, key: str, idx: int) -> Optional[ChatMessage]: + """ + Deleta a mensagem com base na ordem total do histórico. O índice 'idx' é + calculado após reconstruir a lista de ChatMessages (user e assistant). + """ + messages = self.get_messages(key) + if idx < 0 or idx >= len(messages): + return None + + removed = messages[idx] + + # Agora precisamos traduzir 'idx' para saber qual registro no banco será modificado. + # É mais simples recriar todos os dados com set_messages sem a mensagem em 'idx': + messages.pop(idx) + self.set_messages(key, messages) + + return removed diff --git a/pngegg.png b/pngegg.png deleted file mode 100644 index cde32140e3363edd04af41495fd9ce192e85c8b8..0000000000000000000000000000000000000000 Binary files a/pngegg.png and /dev/null differ diff --git a/requirements.txt b/requirements.txt index cd05c0ed606033902698586d36f402344d5183b4..2e907b936bd7f6e88874895046c5edeba79b378f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,4 +4,10 @@ llama-index-vector-stores-chroma==0.4.1 llama-index-readers-google==0.6.0 openpyxl==3.1.5 flask==3.1.0 -streamlit==1.41.1 \ No newline at end of file +streamlit==1.41.1 +streamlit-authenticator==0.4.1 +python-levenshtein==0.26.1 +streamlit_feedback +fuzzywuzzy +pymysql==1.1.1 +aiomysql==0.2.0 \ No newline at end of file diff --git a/sicoob-logo.png b/sicoob-logo.png deleted file mode 100644 index cfed18fac82f33b9f0a3cd021cf1f2b708051f38..0000000000000000000000000000000000000000 Binary files a/sicoob-logo.png and /dev/null differ