Spaces:
Running
Running
Commit
·
e92e757
1
Parent(s):
a95e592
feat: bump version 0.4.0
Browse filesThis view is limited to 50 files because it contains too many changes.
See raw diff
- .streamlit/config.toml +4 -1
- README.md +4 -4
- app.py +143 -64
- chatbot_server.py +140 -144
- config.yaml +38 -0
- drive_search.py +77 -0
- feedback_manager.py +67 -0
- files/config.yaml +38 -0
- files/credenciais.json +13 -0
- logos/ChangelogUser.md +31 -0
- logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-Black.eot +0 -0
- logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-BlackItalic.eot +0 -0
- logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-Bold.eot +0 -0
- logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-BoldItalic.eot +0 -0
- logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-Extrabold.eot +0 -0
- logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-ExtraboldItalic.eot +0 -0
- logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-Extralight.eot +0 -0
- logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-ExtralightItalic.eot +0 -0
- logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-Italic.eot +0 -0
- logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-Light.eot +0 -0
- logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-LightItalic.eot +0 -0
- logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-Medium.eot +0 -0
- logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-MediumItalic.eot +0 -0
- logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-Regular.eot +0 -0
- logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-Semibold.eot +0 -0
- logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-SemiboldItalic.eot +0 -0
- logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-Thin.eot +0 -0
- logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-ThinItalic.eot +0 -0
- logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-Black.ttf +0 -0
- logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-BlackItalic.ttf +0 -0
- logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-Bold.ttf +0 -0
- logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-BoldItalic.ttf +0 -0
- logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-Extrabold.ttf +0 -0
- logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-ExtraboldItalic.ttf +0 -0
- logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-Extralight.ttf +0 -0
- logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-ExtralightItalic.ttf +0 -0
- logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-Italic.ttf +0 -0
- logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-Light.ttf +0 -0
- logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-LightItalic.ttf +0 -0
- logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-Medium.ttf +0 -0
- logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-MediumItalic.ttf +0 -0
- logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-Regular.ttf +0 -0
- logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-Semibold.ttf +0 -0
- logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-SemiboldItalic.ttf +0 -0
- logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-Thin.ttf +0 -0
- logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-ThinItalic.ttf +0 -0
- logos/fonts/Sicoob_Sans/WOFF/SicoobSansRC3-Black.woff +0 -0
- logos/fonts/Sicoob_Sans/WOFF/SicoobSansRC3-BlackItalic.woff +0 -0
- logos/fonts/Sicoob_Sans/WOFF/SicoobSansRC3-Bold.woff +0 -0
- logos/fonts/Sicoob_Sans/WOFF/SicoobSansRC3-BoldItalic.woff +0 -0
.streamlit/config.toml
CHANGED
@@ -1,3 +1,6 @@
|
|
1 |
[theme]
|
|
|
|
|
|
|
|
|
2 |
|
3 |
-
base = 'light'
|
|
|
1 |
[theme]
|
2 |
+
font = "sans serif"
|
3 |
+
|
4 |
+
[client]
|
5 |
+
toolbarMode = "developer"
|
6 |
|
|
README.md
CHANGED
@@ -1,10 +1,10 @@
|
|
1 |
---
|
2 |
-
title: Chatbot Carometro
|
3 |
-
emoji:
|
4 |
-
colorFrom:
|
5 |
colorTo: pink
|
6 |
sdk: docker
|
7 |
pinned: false
|
8 |
---
|
9 |
|
10 |
-
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
|
|
1 |
---
|
2 |
+
title: Chatbot Carometro Staging
|
3 |
+
emoji: 💻
|
4 |
+
colorFrom: yellow
|
5 |
colorTo: pink
|
6 |
sdk: docker
|
7 |
pinned: false
|
8 |
---
|
9 |
|
10 |
+
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
app.py
CHANGED
@@ -1,15 +1,61 @@
|
|
1 |
import streamlit as st
|
2 |
import requests
|
3 |
-
|
4 |
-
import
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
5 |
|
6 |
|
7 |
class ChatbotApp:
|
8 |
def __init__(self):
|
9 |
-
#
|
|
|
10 |
self.backend_url = "http://localhost:5001/chat"
|
11 |
-
self.title = "Chatbot
|
12 |
-
self.description = "Este assistente virtual pode te ajudar com informações sobre
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
13 |
|
14 |
def stream_chat(self, user_input):
|
15 |
"""
|
@@ -30,73 +76,106 @@ class ChatbotApp:
|
|
30 |
except Exception as e:
|
31 |
yield f"Erro ao conectar ao servidor: {e}"
|
32 |
|
|
|
|
|
|
|
|
|
33 |
def render_sidebar(self):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
34 |
"""
|
35 |
-
|
36 |
"""
|
37 |
-
|
38 |
-
sidebar_option = st.sidebar.radio("Selecione o LLM", ["gpt-3.5-turbo"])
|
39 |
-
if sidebar_option != "gpt-3.5-turbo":
|
40 |
-
raise Exception("Opção de LLM inválida!")
|
41 |
-
|
42 |
-
# Exibe a logo do Sicoob na barra lateral
|
43 |
-
with open("sicoob-logo.png", "rb") as f:
|
44 |
-
data = base64.b64encode(f.read()).decode("utf-8")
|
45 |
-
st.sidebar.markdown(
|
46 |
-
f"""
|
47 |
-
<div style="display:table;margin-top:-80%;margin-left:0%;">
|
48 |
-
<img src="data:image/png;base64,{data}" width="250" height="70">
|
49 |
-
</div>
|
50 |
-
""",
|
51 |
-
unsafe_allow_html=True,
|
52 |
-
)
|
53 |
|
54 |
def render(self):
|
55 |
"""
|
56 |
Renderiza a interface do chatbot.
|
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 |
-
st.session_state
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
#
|
98 |
-
|
99 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
100 |
|
101 |
|
102 |
if __name__ == "__main__":
|
|
|
1 |
import streamlit as st
|
2 |
import requests
|
3 |
+
import re
|
4 |
+
import streamlit_authenticator as stauth
|
5 |
+
import os
|
6 |
+
import yaml
|
7 |
+
from yaml.loader import SafeLoader
|
8 |
+
from pathlib import Path
|
9 |
+
from drive_search import search_file_in_drive
|
10 |
+
from datetime import datetime
|
11 |
+
from feedback_manager import FeedbackManager
|
12 |
|
13 |
|
14 |
class ChatbotApp:
|
15 |
def __init__(self):
|
16 |
+
# Configura título, ícone e layout da página
|
17 |
+
st.set_page_config(page_title="Sicoob Chatbot 🤖", page_icon="logos/sicoob-ico.ico", layout="wide")
|
18 |
self.backend_url = "http://localhost:5001/chat"
|
19 |
+
self.title = "Sicoob Chatbot"
|
20 |
+
self.description = "Este assistente virtual pode te ajudar com informações sobre documentos da Sicoob."
|
21 |
+
self.caption = "Confira as atualizações no botão 'Atualizações'."
|
22 |
+
self.style_dir = Path("./logos/styles")
|
23 |
+
self.load_styles()
|
24 |
+
self.feedback_manager = FeedbackManager()
|
25 |
+
st.session_state.first = False
|
26 |
+
if "theme" not in st.session_state:
|
27 |
+
st.session_state.theme = "light"
|
28 |
+
self.configyml = os.path.join(os.getcwd(), "./files/config.yaml")
|
29 |
+
if "feedback_submitted" not in st.session_state:
|
30 |
+
st.session_state.feedback_submitted = set()
|
31 |
+
|
32 |
+
def load_styles(self):
|
33 |
+
try:
|
34 |
+
self.base_style = (self.style_dir / "base.css").read_text()
|
35 |
+
self.light_style = (self.style_dir / "light.css").read_text()
|
36 |
+
self.dark_style = (self.style_dir / "dark.css").read_text()
|
37 |
+
except FileNotFoundError as e:
|
38 |
+
st.error(f"Error loading styles: {e}")
|
39 |
+
self.base_style = ""
|
40 |
+
self.light_style = ""
|
41 |
+
self.dark_style = ""
|
42 |
+
|
43 |
+
def change_style(self):
|
44 |
+
with st.sidebar:
|
45 |
+
if st.session_state.theme == "light":
|
46 |
+
st.logo("./logos/sicoob-logo-horizontal-light.png", icon_image="./logos/sicoob-logo-vertical-sm.png")
|
47 |
+
else:
|
48 |
+
st.logo("./logos/sicoob-logo-horizontal-dark.png", icon_image="./logos/sicoob-logo-vertical-sm.png")
|
49 |
+
st.session_state.theme = "dark" if st.session_state.theme == "light" else "light"
|
50 |
+
|
51 |
+
@st.dialog("📄 Atualizações Sicoob Chatbot", width="small")
|
52 |
+
def changelog_user(self):
|
53 |
+
with open("./logos/ChangelogUser.md", encoding="utf-8") as f:
|
54 |
+
st.markdown(f"{f.read()}", unsafe_allow_html=True)
|
55 |
+
|
56 |
+
def get_current_style(self):
|
57 |
+
theme_style = self.dark_style if st.session_state.theme == "dark" else self.light_style
|
58 |
+
return f"<style>{self.base_style}{theme_style}</style>"
|
59 |
|
60 |
def stream_chat(self, user_input):
|
61 |
"""
|
|
|
76 |
except Exception as e:
|
77 |
yield f"Erro ao conectar ao servidor: {e}"
|
78 |
|
79 |
+
def clear_chat_history(self):
|
80 |
+
st.session_state.chat_history = []
|
81 |
+
st.toast("Histórico limpo com sucesso!", icon="✅")
|
82 |
+
|
83 |
def render_sidebar(self):
|
84 |
+
"""Siderbar"""
|
85 |
+
with st.sidebar:
|
86 |
+
# st.button("Light/Dark Mode", on_click=self.change_style)
|
87 |
+
if st.session_state.theme == "light":
|
88 |
+
st.logo("./logos/sicoob-logo-horizontal-light.png", icon_image="./logos/sicoob-logo-vertical-sm.png")
|
89 |
+
else:
|
90 |
+
st.logo("./logos/sicoob-logo-horizontal-dark.png", icon_image="./logos/sicoob-logo-vertical-sm.png")
|
91 |
+
if st.button("Limpar Histórico", icon=":material/delete:"):
|
92 |
+
self.clear_chat_history()
|
93 |
+
st.button("Atualizações", icon=":material/info:", on_click=self.changelog_user)
|
94 |
+
st.divider()
|
95 |
+
|
96 |
+
def add_link_to_text(self, text):
|
97 |
"""
|
98 |
+
Adiciona links ao texto com base no padrão ||texto||.
|
99 |
"""
|
100 |
+
return re.sub(r'\|\|(.*?)\|\|', lambda match: f' <br>Fonte: <a href="{search_file_in_drive(match.group(1))}" target="_blank">{match.group(1)}</a>', text)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
101 |
|
102 |
def render(self):
|
103 |
"""
|
104 |
Renderiza a interface do chatbot.
|
105 |
"""
|
106 |
+
st.markdown(self.get_current_style(), unsafe_allow_html=True)
|
107 |
+
with open(self.configyml) as file:
|
108 |
+
config = yaml.load(file, Loader=SafeLoader)
|
109 |
+
|
110 |
+
authenticator = stauth.Authenticate(
|
111 |
+
config['credentials'],
|
112 |
+
config['cookie']['name'],
|
113 |
+
config['cookie']['key'],
|
114 |
+
config['cookie']['expiry_days']
|
115 |
+
)
|
116 |
+
|
117 |
+
with open('./config.yaml', 'w', encoding='utf-8') as file:
|
118 |
+
yaml.dump(config, file, default_flow_style=False)
|
119 |
+
|
120 |
+
authentication_status = authenticator.login(fields={'Form name': 'Autenticação', 'Username': 'Nome de Usuário', 'Password': 'Senha', 'Login': 'Entrar'})
|
121 |
+
|
122 |
+
if st.session_state["authentication_status"]:
|
123 |
+
# Renderiza a barra lateral
|
124 |
+
self.render_sidebar()
|
125 |
+
|
126 |
+
# Título e descrição
|
127 |
+
st.title(self.title)
|
128 |
+
st.write(self.description)
|
129 |
+
with st.sidebar:
|
130 |
+
st.caption(self.caption)
|
131 |
+
authenticator.logout('Sair', 'main')
|
132 |
+
# Inicializa o histórico na sessão
|
133 |
+
if "chat_history" not in st.session_state:
|
134 |
+
st.session_state.chat_history = []
|
135 |
+
|
136 |
+
# Renderiza as mensagens do histórico
|
137 |
+
for message in st.session_state.chat_history:
|
138 |
+
role, text = message.split(":", 1)
|
139 |
+
with st.chat_message(role.strip().lower()):
|
140 |
+
st.markdown(text.strip(), unsafe_allow_html=True)
|
141 |
+
|
142 |
+
# Captura o input do usuário
|
143 |
+
user_input = st.chat_input(placeholder="Digite sua pergunta...")
|
144 |
+
if user_input:
|
145 |
+
# Exibe a mensagem do usuário
|
146 |
+
with st.chat_message("user"):
|
147 |
+
st.write(user_input)
|
148 |
+
st.session_state.chat_history.append(f"user: {user_input}")
|
149 |
+
# Placeholder para a resposta do assistente
|
150 |
+
with st.chat_message("assistant"):
|
151 |
+
message_placeholder = st.empty()
|
152 |
+
assistant_message = ""
|
153 |
+
try:
|
154 |
+
# Gerando ID único para a mensagem
|
155 |
+
message_id = datetime.now().strftime("%Y%m%d_%H%M%S_%f")
|
156 |
+
print(f"Message ID gerado: {message_id}")
|
157 |
+
# Executa o streaming de tokens enquanto o backend responde
|
158 |
+
for token in self.stream_chat(user_input):
|
159 |
+
assistant_message += token
|
160 |
+
message_placeholder.markdown(assistant_message + "▌", unsafe_allow_html=True)
|
161 |
+
except Exception as e:
|
162 |
+
st.error(f"Erro durante o chat: {str(e)}")
|
163 |
+
print(f"Erro durante o chat: {str(e)}")
|
164 |
+
finally:
|
165 |
+
assistant_message_with_link = self.add_link_to_text(assistant_message)
|
166 |
+
message_placeholder.markdown(assistant_message_with_link, unsafe_allow_html=True)
|
167 |
+
# Feedback
|
168 |
+
self.feedback_manager.render_feedback_buttons(
|
169 |
+
message_id=message_id,
|
170 |
+
user_input=user_input,
|
171 |
+
assistant_response=assistant_message_with_link
|
172 |
+
)
|
173 |
+
# Adicionando hist��rico Streamlit
|
174 |
+
st.session_state.chat_history.append(f"assistant: {assistant_message_with_link}")
|
175 |
+
elif st.session_state["authentication_status"] == False:
|
176 |
+
st.error('Nome de Usuário/Senha incorreta.')
|
177 |
+
elif st.session_state["authentication_status"] == None:
|
178 |
+
st.warning('Por favor entre com seu nome de usuário e senha.')
|
179 |
|
180 |
|
181 |
if __name__ == "__main__":
|
chatbot_server.py
CHANGED
@@ -1,144 +1,140 @@
|
|
1 |
-
import os
|
2 |
-
import logging
|
3 |
-
import sys
|
4 |
-
|
5 |
-
from flask import Flask, request, jsonify, Response
|
6 |
-
# Inicializa o Flask
|
7 |
-
app = Flask(__name__)
|
8 |
-
|
9 |
-
logging.basicConfig(stream=sys.stdout, level=logging.INFO)
|
10 |
-
|
11 |
-
from llama_index.llms.openai import OpenAI
|
12 |
-
from llama_index.embeddings.openai import OpenAIEmbedding
|
13 |
-
from llama_index.core import (
|
14 |
-
Settings,
|
15 |
-
SimpleDirectoryReader,
|
16 |
-
StorageContext,
|
17 |
-
Document,
|
18 |
-
)
|
19 |
-
|
20 |
-
Settings.llm = OpenAI(model="gpt-3.5-turbo")
|
21 |
-
Settings.embed_model = OpenAIEmbedding(model_name="text-embedding-3-small")
|
22 |
-
directory_path = "documentos"
|
23 |
-
from llama_index.readers.file import PDFReader #concatenar todo o documento já vem nativo no pdfreader
|
24 |
-
file_extractor = {".pdf": PDFReader(return_full_document = True)}
|
25 |
-
from drive_downloader import GoogleDriveDownloader
|
26 |
-
|
27 |
-
# ID da pasta no Drive e caminho local
|
28 |
-
folder_id = "1n34bmh9rlbOtCvE_WPZRukQilKeabWsN"
|
29 |
-
local_path = directory_path
|
30 |
-
|
31 |
-
GoogleDriveDownloader().download_from_folder(folder_id, local_path)
|
32 |
-
|
33 |
-
documents = SimpleDirectoryReader(
|
34 |
-
input_dir=directory_path,
|
35 |
-
file_extractor=file_extractor,
|
36 |
-
filename_as_id=True,
|
37 |
-
recursive=True
|
38 |
-
).load_data()
|
39 |
-
|
40 |
-
from document_creator import create_single_document_with_filenames
|
41 |
-
document = create_single_document_with_filenames(directory_path = directory_path)
|
42 |
-
documents.append(document)
|
43 |
-
|
44 |
-
from llama_index.core.ingestion import IngestionPipeline
|
45 |
-
#ingestion pipeline vai entrar em uso quando adicionar o extrator de metadados
|
46 |
-
from llama_index.core.node_parser import SentenceSplitter
|
47 |
-
splitter = SentenceSplitter(chunk_size=1024, chunk_overlap=128)
|
48 |
-
nodes = splitter.get_nodes_from_documents(documents)
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
import
|
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 |
-
return Response(generate_response(), content_type="text/plain")
|
143 |
-
if __name__ == "__main__":
|
144 |
-
app.run(port=5001, debug=False)
|
|
|
1 |
+
import os
|
2 |
+
import logging
|
3 |
+
import sys
|
4 |
+
|
5 |
+
from flask import Flask, request, jsonify, Response
|
6 |
+
# Inicializa o Flask
|
7 |
+
app = Flask(__name__)
|
8 |
+
|
9 |
+
logging.basicConfig(stream=sys.stdout, level=logging.INFO)
|
10 |
+
|
11 |
+
from llama_index.llms.openai import OpenAI
|
12 |
+
from llama_index.embeddings.openai import OpenAIEmbedding
|
13 |
+
from llama_index.core import (
|
14 |
+
Settings,
|
15 |
+
SimpleDirectoryReader,
|
16 |
+
StorageContext,
|
17 |
+
Document,
|
18 |
+
)
|
19 |
+
|
20 |
+
Settings.llm = OpenAI(model="gpt-3.5-turbo")
|
21 |
+
Settings.embed_model = OpenAIEmbedding(model_name="text-embedding-3-small")
|
22 |
+
directory_path = "documentos"
|
23 |
+
from llama_index.readers.file import PDFReader #concatenar todo o documento já vem nativo no pdfreader
|
24 |
+
file_extractor = {".pdf": PDFReader(return_full_document = True)}
|
25 |
+
from drive_downloader import GoogleDriveDownloader
|
26 |
+
|
27 |
+
# ID da pasta no Drive e caminho local
|
28 |
+
folder_id = "1n34bmh9rlbOtCvE_WPZRukQilKeabWsN"
|
29 |
+
local_path = directory_path
|
30 |
+
|
31 |
+
GoogleDriveDownloader().download_from_folder(folder_id, local_path)
|
32 |
+
|
33 |
+
documents = SimpleDirectoryReader(
|
34 |
+
input_dir=directory_path,
|
35 |
+
file_extractor=file_extractor,
|
36 |
+
filename_as_id=True,
|
37 |
+
recursive=True
|
38 |
+
).load_data()
|
39 |
+
|
40 |
+
from document_creator import create_single_document_with_filenames
|
41 |
+
document = create_single_document_with_filenames(directory_path = directory_path)
|
42 |
+
documents.append(document)
|
43 |
+
|
44 |
+
#from llama_index.core.ingestion import IngestionPipeline
|
45 |
+
#ingestion pipeline vai entrar em uso quando adicionar o extrator de metadados
|
46 |
+
from llama_index.core.node_parser import SentenceSplitter
|
47 |
+
splitter = SentenceSplitter(chunk_size=1024, chunk_overlap=128)
|
48 |
+
nodes = splitter.get_nodes_from_documents(documents)
|
49 |
+
|
50 |
+
from llama_index.core.storage.docstore import SimpleDocumentStore
|
51 |
+
docstore = SimpleDocumentStore()
|
52 |
+
docstore.add_documents(nodes)
|
53 |
+
|
54 |
+
from llama_index.core import VectorStoreIndex, StorageContext
|
55 |
+
from llama_index.vector_stores.chroma import ChromaVectorStore
|
56 |
+
import chromadb
|
57 |
+
|
58 |
+
db = chromadb.PersistentClient(path="chroma_db")
|
59 |
+
chroma_collection = db.get_or_create_collection("dense_vectors")
|
60 |
+
vector_store = ChromaVectorStore(chroma_collection=chroma_collection)
|
61 |
+
storage_context = StorageContext.from_defaults(
|
62 |
+
docstore=docstore, vector_store=vector_store
|
63 |
+
)
|
64 |
+
index = VectorStoreIndex(nodes = nodes, storage_context=storage_context, show_progress = True)
|
65 |
+
|
66 |
+
storage_context.docstore.persist("./docstore.json")
|
67 |
+
|
68 |
+
index_retriever = index.as_retriever(similarity_top_k=2)
|
69 |
+
import nest_asyncio
|
70 |
+
nest_asyncio.apply()
|
71 |
+
from llama_index.retrievers.bm25 import BM25Retriever
|
72 |
+
bm25_retriever = BM25Retriever.from_defaults(
|
73 |
+
docstore=index.docstore,
|
74 |
+
similarity_top_k=2,
|
75 |
+
language = "portuguese",
|
76 |
+
verbose=True,
|
77 |
+
)
|
78 |
+
|
79 |
+
from llama_index.core.retrievers import QueryFusionRetriever
|
80 |
+
|
81 |
+
retriever = QueryFusionRetriever(
|
82 |
+
[index_retriever, bm25_retriever],
|
83 |
+
num_queries=1, #desativado = 1
|
84 |
+
mode="reciprocal_rerank",
|
85 |
+
use_async=True,
|
86 |
+
verbose=True,
|
87 |
+
)
|
88 |
+
|
89 |
+
|
90 |
+
from llama_index.core.memory import ChatMemoryBuffer
|
91 |
+
from mysqlchatstore import MySQLChatStore
|
92 |
+
chat_store = MySQLChatStore.from_params(
|
93 |
+
host=os.getenv("MYSQL_HOST"),
|
94 |
+
port=os.getenv("MYSQL_PORT"),
|
95 |
+
user=os.getenv("MYSQL_USER"),
|
96 |
+
password=os.getenv("MYSQL_PASSWORD"),
|
97 |
+
database=os.getenv("MYSQL_DATABASE"),
|
98 |
+
table_name=os.getenv("MYSQL_TABLE")
|
99 |
+
)
|
100 |
+
chat_memory = ChatMemoryBuffer.from_defaults(
|
101 |
+
token_limit=3000,
|
102 |
+
chat_store=chat_store,
|
103 |
+
chat_store_key="Sicoob", #Tendo algumas dificuldades ainda pra passar o user
|
104 |
+
)
|
105 |
+
from llama_index.core.query_engine import RetrieverQueryEngine
|
106 |
+
query_engine = RetrieverQueryEngine.from_args(retriever)
|
107 |
+
from llama_index.core.chat_engine import CondensePlusContextChatEngine
|
108 |
+
chat_engine = CondensePlusContextChatEngine.from_defaults(
|
109 |
+
query_engine,
|
110 |
+
memory=chat_memory,
|
111 |
+
context_prompt=(
|
112 |
+
"Você é um assistente virtual capaz de interagir normalmente, além de"
|
113 |
+
" fornecer informações sobre organogramas e listar funcionários."
|
114 |
+
" Aqui estão os documentos relevantes para o contexto:\n"
|
115 |
+
"{context_str}"
|
116 |
+
"\nInstrução: Use o histórico da conversa anterior, ou o contexto acima, para responder."
|
117 |
+
"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||"
|
118 |
+
|
119 |
+
),
|
120 |
+
)
|
121 |
+
|
122 |
+
|
123 |
+
|
124 |
+
@app.route("/chat", methods=["POST"])
|
125 |
+
def chat():
|
126 |
+
user_input = request.json.get("message", "")
|
127 |
+
if not user_input:
|
128 |
+
return jsonify({"error": "Mensagem vazia"}), 400
|
129 |
+
|
130 |
+
def generate_response():
|
131 |
+
try:
|
132 |
+
response = chat_engine.stream_chat(user_input)
|
133 |
+
for token in response.response_gen:
|
134 |
+
yield token # Envia cada token
|
135 |
+
except Exception as e:
|
136 |
+
yield f"Erro: {str(e)}"
|
137 |
+
|
138 |
+
return Response(generate_response(), content_type="text/plain")
|
139 |
+
if __name__ == "__main__":
|
140 |
+
app.run(port=5001, debug=False)
|
|
|
|
|
|
|
|
config.yaml
ADDED
@@ -0,0 +1,38 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
cookie:
|
2 |
+
expiry_days: 30
|
3 |
+
key: some_signature_key
|
4 |
+
name: some_cookie_name
|
5 |
+
credentials:
|
6 |
+
usernames:
|
7 |
+
akcit_root:
|
8 |
+
email: akcit_root@mail.com
|
9 |
+
failed_login_attempts: 0
|
10 |
+
first_name: akcit
|
11 |
+
last_name: root
|
12 |
+
logged_in: false
|
13 |
+
password: $2b$12$wd1lg1DTs4qEDRmohdptDegeSJhGstxqgCaTitfRQ0IGN.rnr51aG
|
14 |
+
roles:
|
15 |
+
- admin
|
16 |
+
- editor
|
17 |
+
- viewer
|
18 |
+
sicoob_central:
|
19 |
+
email: sicoob_central@mail.com
|
20 |
+
failed_login_attempts: 0
|
21 |
+
first_name: sicoob
|
22 |
+
last_name: central
|
23 |
+
logged_in: false
|
24 |
+
password: $2b$12$Y5tHfGABzVP9dm510HuHHuUbeZvNqUibUgj4TYH40rglhZGLPZ8rK
|
25 |
+
roles:
|
26 |
+
- viewer
|
27 |
+
sicoob_unidade:
|
28 |
+
email: sicoob_unidade@mail.com
|
29 |
+
failed_login_attempts: 0
|
30 |
+
first_name: sicoob
|
31 |
+
last_name: unidade
|
32 |
+
logged_in: false
|
33 |
+
password: $2b$12$h8U7XrVfACkHJaqGqcwR0OzDO.YorKF21lHpG/9MVa4K/98AbXtG.
|
34 |
+
roles:
|
35 |
+
- viewer
|
36 |
+
pre-authorized:
|
37 |
+
emails:
|
38 |
+
- akcit_root@mail.com
|
drive_search.py
ADDED
@@ -0,0 +1,77 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from googleapiclient.discovery import build
|
2 |
+
from google.oauth2.service_account import Credentials
|
3 |
+
from fuzzywuzzy import process # Importando a biblioteca fuzzywuzzy
|
4 |
+
import os
|
5 |
+
|
6 |
+
SCOPES = ["https://www.googleapis.com/auth/drive.readonly"]
|
7 |
+
FOLDER_ID = "1hqfPQnsVL2Ld8hu0GRIqcuOp-eDz-CAX" # ID da pasta que você quer buscar
|
8 |
+
|
9 |
+
SERVICE_ACCOUNT_FILE = os.path.join(os.getcwd(), "./files/credenciais.json")
|
10 |
+
def authenticate_drive():
|
11 |
+
"""Autentica no Google Drive usando uma conta de serviço."""
|
12 |
+
credentials = Credentials.from_service_account_file(SERVICE_ACCOUNT_FILE, scopes=SCOPES)
|
13 |
+
service = build("drive", "v3", credentials=credentials)
|
14 |
+
return service
|
15 |
+
|
16 |
+
def list_files_recursive(service, folder_id, path=""):
|
17 |
+
"""Lista todos os arquivos e subpastas no Google Drive de forma recursiva."""
|
18 |
+
query = f"'{folder_id}' in parents and trashed = false"
|
19 |
+
response = service.files().list(
|
20 |
+
q=query,
|
21 |
+
spaces="drive",
|
22 |
+
fields="files(id, name, mimeType, parents)",
|
23 |
+
).execute()
|
24 |
+
|
25 |
+
files = response.get("files", [])
|
26 |
+
all_files = []
|
27 |
+
|
28 |
+
for file in files:
|
29 |
+
# caminho completo
|
30 |
+
current_path = f"{path}/{file['name']}"
|
31 |
+
all_files.append({"id": file["id"], "name": file["name"], "path": current_path})
|
32 |
+
|
33 |
+
# buscar recursivamente
|
34 |
+
if file["mimeType"] == "application/vnd.google-apps.folder":
|
35 |
+
all_files.extend(list_files_recursive(service, file["id"], current_path))
|
36 |
+
|
37 |
+
return all_files
|
38 |
+
|
39 |
+
def find_file_by_name(files, search_name):
|
40 |
+
"""Encontra um arquivo com nome aproximado utilizando fuzzy matching."""
|
41 |
+
# Usando fuzzywuzzy para encontrar o arquivo mais próximo
|
42 |
+
file_names = [file["name"] for file in files]
|
43 |
+
best_match, score = process.extractOne(search_name, file_names)
|
44 |
+
|
45 |
+
if score >= 80: # Ajuste a pontuação mínima de correspondência (por exemplo, 80%)
|
46 |
+
matching_files = [file for file in files if file["name"] == best_match]
|
47 |
+
return matching_files
|
48 |
+
else:
|
49 |
+
return []
|
50 |
+
|
51 |
+
def search_file_in_drive(search_name):
|
52 |
+
"""Procura o arquivo mais relevante no Google Drive e retorna o link."""
|
53 |
+
service = authenticate_drive()
|
54 |
+
print("Autenticado com sucesso no Google Drive!")
|
55 |
+
|
56 |
+
# Listar arquivos na pasta e subpastas
|
57 |
+
files = list_files_recursive(service, FOLDER_ID)
|
58 |
+
|
59 |
+
if not files:
|
60 |
+
print("Nenhum arquivo encontrado na pasta!")
|
61 |
+
return None # Retorna None se nenhum arquivo for encontrado
|
62 |
+
|
63 |
+
print(f"Total de arquivos encontrados: {len(files)}")
|
64 |
+
|
65 |
+
# Encontrar o arquivo com nome aproximado
|
66 |
+
matching_files = find_file_by_name(files, search_name)
|
67 |
+
|
68 |
+
if matching_files:
|
69 |
+
best_file = matching_files[0] # Pega o arquivo mais relevante (primeiro da lista)
|
70 |
+
link = f"https://drive.google.com/file/d/{best_file['id']}/view"
|
71 |
+
print(f"Arquivo encontrado: {best_file['name']}")
|
72 |
+
print(f"Link: {link}")
|
73 |
+
return link # Retorna o link do arquivo encontrado
|
74 |
+
else:
|
75 |
+
print(f"Nenhum arquivo encontrado com nome aproximado '{search_name}'.")
|
76 |
+
return None # Retorna None se nenhum arquivo for encontrado
|
77 |
+
|
feedback_manager.py
ADDED
@@ -0,0 +1,67 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import json
|
2 |
+
from datetime import datetime
|
3 |
+
from pathlib import Path
|
4 |
+
import streamlit as st
|
5 |
+
|
6 |
+
|
7 |
+
class FeedbackManager:
|
8 |
+
def __init__(self, feedback_dir="./feedback"):
|
9 |
+
self.feedback_dir = Path(feedback_dir)
|
10 |
+
self.feedback_dir.mkdir(exist_ok=True)
|
11 |
+
if "feedback_submitted" not in st.session_state:
|
12 |
+
st.session_state.feedback_submitted = set()
|
13 |
+
|
14 |
+
def save_feedback(self, feedback_type: str, user_input: str, assistant_response: str, message_id: str):
|
15 |
+
if message_id in st.session_state.feedback_submitted:
|
16 |
+
st.toast("Feedback já enviado para está mensagem.", icon="ℹ️")
|
17 |
+
return False
|
18 |
+
feedback_file = self.feedback_dir / f"feedback_{feedback_type}.json"
|
19 |
+
try:
|
20 |
+
data = []
|
21 |
+
if feedback_file.exists():
|
22 |
+
with open(feedback_file, 'r', encoding='utf-8') as f:
|
23 |
+
data = json.load(f)
|
24 |
+
feedback_entry = {
|
25 |
+
"message_id": message_id,
|
26 |
+
"timestamp": datetime.now().isoformat(),
|
27 |
+
"feedback_type": feedback_type,
|
28 |
+
"user_input": user_input,
|
29 |
+
"assistant_response": assistant_response,
|
30 |
+
}
|
31 |
+
data.append(feedback_entry)
|
32 |
+
with open(feedback_file, 'w', encoding='utf-8') as f:
|
33 |
+
json.dump(data, f, ensure_ascii=False, indent=2)
|
34 |
+
st.session_state.feedback_submitted.add(message_id)
|
35 |
+
emoji = "👍" if feedback_type == "positive" else "👎"
|
36 |
+
st.toast(f"Obrigado por seu Feedback! {emoji}", icon="✅")
|
37 |
+
return True
|
38 |
+
except Exception as e:
|
39 |
+
st.error(f"Error ao salvar feedback: {str(e)}")
|
40 |
+
return False
|
41 |
+
|
42 |
+
def handle_feedback_click(self, feedback_type: str, message_id: str, user_input: str, assistant_response: str):
|
43 |
+
self.save_feedback(
|
44 |
+
feedback_type=feedback_type,
|
45 |
+
user_input=user_input,
|
46 |
+
assistant_response=assistant_response,
|
47 |
+
message_id=message_id
|
48 |
+
)
|
49 |
+
|
50 |
+
def render_feedback_buttons(self, message_id: str, user_input: str, assistant_response: str):
|
51 |
+
col1, col2 = st.columns(2, gap="small")
|
52 |
+
|
53 |
+
with col1:
|
54 |
+
st.button(
|
55 |
+
"👍 Gostei",
|
56 |
+
key=f"positive_{message_id}",
|
57 |
+
on_click=self.handle_feedback_click,
|
58 |
+
args=("positive", message_id, user_input, assistant_response)
|
59 |
+
)
|
60 |
+
|
61 |
+
with col2:
|
62 |
+
st.button(
|
63 |
+
"👎 Não Gostei",
|
64 |
+
key=f"negative_{message_id}",
|
65 |
+
on_click=self.handle_feedback_click,
|
66 |
+
args=("negative", message_id, user_input, assistant_response)
|
67 |
+
)
|
files/config.yaml
ADDED
@@ -0,0 +1,38 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
cookie:
|
2 |
+
expiry_days: 30
|
3 |
+
key: some_signature_key
|
4 |
+
name: some_cookie_name
|
5 |
+
credentials:
|
6 |
+
usernames:
|
7 |
+
akcit_root:
|
8 |
+
email: akcit_root@mail.com
|
9 |
+
failed_login_attempts: 0
|
10 |
+
first_name: akcit
|
11 |
+
last_name: root
|
12 |
+
logged_in: false
|
13 |
+
password: $2b$12$wd1lg1DTs4qEDRmohdptDegeSJhGstxqgCaTitfRQ0IGN.rnr51aG
|
14 |
+
roles:
|
15 |
+
- admin
|
16 |
+
- editor
|
17 |
+
- viewer
|
18 |
+
sicoob_central:
|
19 |
+
email: sicoob_central@mail.com
|
20 |
+
failed_login_attempts: 0
|
21 |
+
first_name: sicoob
|
22 |
+
last_name: central
|
23 |
+
logged_in: false
|
24 |
+
password: $2b$12$Y5tHfGABzVP9dm510HuHHuUbeZvNqUibUgj4TYH40rglhZGLPZ8rK
|
25 |
+
roles:
|
26 |
+
- viewer
|
27 |
+
sicoob_unidade:
|
28 |
+
email: sicoob_unidade@mail.com
|
29 |
+
failed_login_attempts: 0
|
30 |
+
first_name: sicoob
|
31 |
+
last_name: unidade
|
32 |
+
logged_in: false
|
33 |
+
password: $2b$12$h8U7XrVfACkHJaqGqcwR0OzDO.YorKF21lHpG/9MVa4K/98AbXtG.
|
34 |
+
roles:
|
35 |
+
- viewer
|
36 |
+
pre-authorized:
|
37 |
+
emails:
|
38 |
+
- akcit_root@mail.com
|
files/credenciais.json
ADDED
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"type": "service_account",
|
3 |
+
"project_id": "light-processor-374314",
|
4 |
+
"private_key_id": "a207b3d84c4dfdf97eef75f442a78b79a9af7e4a",
|
5 |
+
"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",
|
6 |
+
"client_email": "mydriveapi@light-processor-374314.iam.gserviceaccount.com",
|
7 |
+
"client_id": "115319015910729374958",
|
8 |
+
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
|
9 |
+
"token_uri": "https://oauth2.googleapis.com/token",
|
10 |
+
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
|
11 |
+
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/mydriveapi%40light-processor-374314.iam.gserviceaccount.com",
|
12 |
+
"universe_domain": "googleapis.com"
|
13 |
+
}
|
logos/ChangelogUser.md
ADDED
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Changelog - Versão 0.4.0
|
2 |
+
|
3 |
+
## Novos Recursos
|
4 |
+
|
5 |
+
- **Suporte a múltiplos manuais**: O chatbot agora pode acessar e fornecer informações de diversos manuais.
|
6 |
+
- Manuais disponíveis nesta versão:
|
7 |
+
- Manual de Normatização
|
8 |
+
- Manual de Riscos Sociais, Ambientais e Climáticos
|
9 |
+
- Manual de Supervisão Auxiliar
|
10 |
+
- Manual de Controles Internos e Conformidade
|
11 |
+
- Manual de Crédito
|
12 |
+
- Manual de Boas Práticas Legais e Tributárias nas Campanhas e Promoções
|
13 |
+
- Manual de Gerenciamento do Risco de Mercado e do IRRBB
|
14 |
+
- Manual de Seguro Vida Prestamista
|
15 |
+
- Manual do Produto Pix
|
16 |
+
- Manual de Câmbio - Operações de Crédito
|
17 |
+
- ...
|
18 |
+
|
19 |
+
## Melhorias
|
20 |
+
|
21 |
+
- **Qualidade de resposta aprimorada**: Refinamento nos modelos de resposta para oferecer informações mais precisas e relevantes.
|
22 |
+
- **Otimização de consultas**: Melhorias no tempo de resposta ao buscar informações em documentos.
|
23 |
+
|
24 |
+
## Alterações e Remoções
|
25 |
+
|
26 |
+
- **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.
|
27 |
+
|
28 |
+
## Próximos Passos
|
29 |
+
|
30 |
+
- **Expansão do suporte a mais manuais e documentos internos.**
|
31 |
+
- **Reintegração das informações sobre o organograma na versão 0.5.0.**
|
logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-Black.eot
ADDED
Binary file (36.8 kB). View file
|
|
logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-BlackItalic.eot
ADDED
Binary file (37.5 kB). View file
|
|
logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-Bold.eot
ADDED
Binary file (37.9 kB). View file
|
|
logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-BoldItalic.eot
ADDED
Binary file (38.8 kB). View file
|
|
logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-Extrabold.eot
ADDED
Binary file (38.3 kB). View file
|
|
logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-ExtraboldItalic.eot
ADDED
Binary file (39.1 kB). View file
|
|
logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-Extralight.eot
ADDED
Binary file (37.8 kB). View file
|
|
logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-ExtralightItalic.eot
ADDED
Binary file (38.3 kB). View file
|
|
logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-Italic.eot
ADDED
Binary file (37.9 kB). View file
|
|
logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-Light.eot
ADDED
Binary file (37.8 kB). View file
|
|
logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-LightItalic.eot
ADDED
Binary file (38.5 kB). View file
|
|
logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-Medium.eot
ADDED
Binary file (37.8 kB). View file
|
|
logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-MediumItalic.eot
ADDED
Binary file (38.4 kB). View file
|
|
logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-Regular.eot
ADDED
Binary file (37.1 kB). View file
|
|
logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-Semibold.eot
ADDED
Binary file (38 kB). View file
|
|
logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-SemiboldItalic.eot
ADDED
Binary file (38.8 kB). View file
|
|
logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-Thin.eot
ADDED
Binary file (35.4 kB). View file
|
|
logos/fonts/Sicoob_Sans/EOT/SicoobSansRC3-ThinItalic.eot
ADDED
Binary file (36.3 kB). View file
|
|
logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-Black.ttf
ADDED
Binary file (99 kB). View file
|
|
logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-BlackItalic.ttf
ADDED
Binary file (99.3 kB). View file
|
|
logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-Bold.ttf
ADDED
Binary file (100 kB). View file
|
|
logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-BoldItalic.ttf
ADDED
Binary file (101 kB). View file
|
|
logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-Extrabold.ttf
ADDED
Binary file (101 kB). View file
|
|
logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-ExtraboldItalic.ttf
ADDED
Binary file (102 kB). View file
|
|
logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-Extralight.ttf
ADDED
Binary file (100 kB). View file
|
|
logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-ExtralightItalic.ttf
ADDED
Binary file (101 kB). View file
|
|
logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-Italic.ttf
ADDED
Binary file (101 kB). View file
|
|
logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-Light.ttf
ADDED
Binary file (101 kB). View file
|
|
logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-LightItalic.ttf
ADDED
Binary file (101 kB). View file
|
|
logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-Medium.ttf
ADDED
Binary file (100 kB). View file
|
|
logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-MediumItalic.ttf
ADDED
Binary file (101 kB). View file
|
|
logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-Regular.ttf
ADDED
Binary file (100 kB). View file
|
|
logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-Semibold.ttf
ADDED
Binary file (101 kB). View file
|
|
logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-SemiboldItalic.ttf
ADDED
Binary file (102 kB). View file
|
|
logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-Thin.ttf
ADDED
Binary file (94.2 kB). View file
|
|
logos/fonts/Sicoob_Sans/TTF/SicoobSansRC3-ThinItalic.ttf
ADDED
Binary file (96.5 kB). View file
|
|
logos/fonts/Sicoob_Sans/WOFF/SicoobSansRC3-Black.woff
ADDED
Binary file (38.3 kB). View file
|
|
logos/fonts/Sicoob_Sans/WOFF/SicoobSansRC3-BlackItalic.woff
ADDED
Binary file (39.1 kB). View file
|
|
logos/fonts/Sicoob_Sans/WOFF/SicoobSansRC3-Bold.woff
ADDED
Binary file (39.3 kB). View file
|
|
logos/fonts/Sicoob_Sans/WOFF/SicoobSansRC3-BoldItalic.woff
ADDED
Binary file (40.1 kB). View file
|
|