leandroaraujodev commited on
Commit
4c3e2c0
·
verified ·
1 Parent(s): 155f78c

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +264 -0
app.py ADDED
@@ -0,0 +1,264 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import streamlit as st
3
+ from llama_index.core import Settings, SimpleDirectoryReader, VectorStoreIndex, StorageContext
4
+ from llama_index.core.storage.docstore import SimpleDocumentStore
5
+ from llama_index.llms.ollama import Ollama
6
+ from llama_index.embeddings.ollama import OllamaEmbedding
7
+ from llama_index.core.node_parser import LangchainNodeParser
8
+ from langchain.text_splitter import RecursiveCharacterTextSplitter
9
+ from llama_index.core.storage.chat_store import SimpleChatStore
10
+ from llama_index.core.memory import ChatMemoryBuffer
11
+ from llama_index.core.query_engine import RetrieverQueryEngine
12
+ from llama_index.core.chat_engine import CondensePlusContextChatEngine
13
+ from llama_index.retrievers.bm25 import BM25Retriever
14
+ from llama_index.core.retrievers import QueryFusionRetriever
15
+ from llama_index.vector_stores.chroma import ChromaVectorStore
16
+ import chromadb
17
+ import nest_asyncio
18
+
19
+ import os
20
+ from llama_index.core import VectorStoreIndex, SimpleDirectoryReader
21
+ from llama_index.llms.huggingface import HuggingFaceLLM
22
+ from llama_index.llms.huggingface_api import HuggingFaceInferenceAPI
23
+ from llama_index.core import Settings
24
+ from typing import List, Optional
25
+ from llama_index.core import PromptTemplate
26
+ import torch
27
+ from llama_index.embeddings.huggingface import HuggingFaceEmbedding
28
+
29
+
30
+ import logging
31
+ import sys
32
+ from PIL import Image
33
+
34
+ #Configuração da imagem da aba
35
+
36
+ im = Image.open("pngegg.png")
37
+ st.set_page_config(page_title = "Chatbot Carômetro", page_icon=im, layout = "wide")
38
+
39
+ #Removido loop e adicionado os.makedirs
40
+ os.makedirs("bm25_retriever", exist_ok=True)
41
+ os.makedirs("chat_store", exist_ok=True)
42
+ os.makedirs("chroma_db", exist_ok=True)
43
+ os.makedirs("documentos", exist_ok=True)
44
+ os.makedirs("curadoria", exist_ok=True)
45
+ os.makedirs("chroma_db_curadoria", exist_ok=True)
46
+
47
+ # Configuração do Streamlit
48
+ st.sidebar.title("Configuração de LLM")
49
+ sidebar_option = st.sidebar.radio("Selecione o LLM", ["gpt-3.5-turbo", "NuExtract-1.5"])
50
+ # logo_url = 'app\logos\logo-sicoob.jpg'
51
+ # st.sidebar.image(logo_url)
52
+ import base64
53
+
54
+ #Configuração da imagem da sidebar
55
+ with open("sicoob-logo.png", "rb") as f:
56
+ data = base64.b64encode(f.read()).decode("utf-8")
57
+
58
+ st.sidebar.markdown(
59
+ f"""
60
+ <div style="display:table;margin-top:-80%;margin-left:0%;">
61
+ <img src="data:image/png;base64,{data}" width="250" height="70">
62
+ </div>
63
+ """,
64
+ unsafe_allow_html=True,
65
+ )
66
+
67
+
68
+ #if sidebar_option == "Ollama":
69
+ # Settings.llm = Ollama(model="llama3.2:latest", request_timeout=500.0, num_gpu=1)
70
+ # Settings.embed_model = OllamaEmbedding(model_name="nomic-embed-text:latest")
71
+ if sidebar_option == "gpt-3.5-turbo":
72
+ from llama_index.llms.openai import OpenAI
73
+ from llama_index.embeddings.openai import OpenAIEmbedding
74
+ Settings.llm = OpenAI(model="gpt-3.5-turbo")
75
+ Settings.embed_model = OpenAIEmbedding(model_name="text-embedding-ada-002")
76
+ elif sidebar_option == 'NuExtract-1.5':
77
+
78
+ logging.basicConfig(stream=sys.stdout, level=logging.INFO)
79
+ logging.getLogger().addHandler(logging.StreamHandler(stream=sys.stdout))
80
+
81
+ #Embedding do huggingface
82
+ Settings.embed_model = HuggingFaceEmbedding(
83
+ model_name="BAAI/bge-small-en-v1.5"
84
+ )
85
+ #Carregamento do modelo local, descomentar o modelo desejado
86
+
87
+ llm = HuggingFaceLLM(
88
+ context_window=2048,
89
+ max_new_tokens=256,
90
+ generate_kwargs={"do_sample": False},
91
+ #query_wrapper_prompt=query_wrapper_prompt,
92
+ #model_name="Qwen/Qwen2.5-Coder-32B-Instruct",
93
+ #model_name="Qwen/Qwen2.5-14B-Instruct",
94
+ # model_name="meta-llama/Llama-3.2-3B",
95
+ #model_name="HuggingFaceH4/zephyr-7b-beta",
96
+ # model_name="meta-llama/Meta-Llama-3-8B",
97
+ model_name="numind/NuExtract-1.5",
98
+ #model_name="meta-llama/Llama-3.2-3B",
99
+
100
+ tokenizer_name="numind/NuExtract-1.5",
101
+ device_map="auto",
102
+ tokenizer_kwargs={"max_length": 2048},
103
+ # uncomment this if using CUDA to reduce memory usage
104
+ model_kwargs={"torch_dtype": torch.bfloat16},
105
+ )
106
+ chat = [
107
+
108
+ {"role": "user", "content": "Hello, how are you?"},
109
+
110
+ {"role": "assistant", "content": "I'm doing great. How can I help you today?"},
111
+
112
+ {"role": "user", "content": "I'd like to show off how chat templating works!"},
113
+
114
+ ]
115
+
116
+ from transformers import AutoTokenizer
117
+
118
+ tokenizer = AutoTokenizer.from_pretrained("numind/NuExtract-1.5")
119
+
120
+ tokenizer.apply_chat_template(chat, tokenize=False)
121
+
122
+
123
+ Settings.chunk_size = 512
124
+ Settings.llm = llm
125
+
126
+ else:
127
+ raise Exception("Opção de LLM inválida!")
128
+
129
+ # Diretórios configurados pelo usuário
130
+ chat_store_path = os.path.join("chat_store", "chat_store.json")
131
+ documents_path = os.path.join("documentos")
132
+ chroma_storage_path = os.path.join("chroma_db") # Diretório para persistência do Chroma
133
+ chroma_storage_path_curadoria = os.path.join("chroma_db_curadoria") # Diretório para 'curadoria'
134
+ bm25_persist_path = os.path.join("bm25_retriever")
135
+ curadoria_path = os.path.join("curadoria")
136
+
137
+
138
+ # Configuração de leitura de documentos
139
+ documents = SimpleDirectoryReader(input_dir=documents_path).load_data()
140
+
141
+ # Configuração do Chroma e BM25 com persistência
142
+ docstore = SimpleDocumentStore()
143
+ docstore.add_documents(documents)
144
+
145
+ db = chromadb.PersistentClient(path=chroma_storage_path)
146
+ chroma_collection = db.get_or_create_collection("dense_vectors")
147
+ vector_store = ChromaVectorStore(chroma_collection=chroma_collection)
148
+
149
+ # Configuração do StorageContext
150
+ storage_context = StorageContext.from_defaults(
151
+ docstore=docstore, vector_store=vector_store
152
+ )
153
+
154
+ # Criação/Recarregamento do índice com embeddings
155
+ if os.path.exists(chroma_storage_path):
156
+ index = VectorStoreIndex.from_vector_store(vector_store)
157
+ else:
158
+ splitter = LangchainNodeParser(
159
+ RecursiveCharacterTextSplitter(chunk_size=512, chunk_overlap=64)
160
+ )
161
+ index = VectorStoreIndex.from_documents(
162
+ documents, storage_context=storage_context, transformations=[splitter]
163
+ )
164
+ vector_store.persist()
165
+
166
+ # Criação/Recarregamento do BM25 Retriever
167
+ if os.path.exists(os.path.join(bm25_persist_path, "params.index.json")):
168
+ bm25_retriever = BM25Retriever.from_persist_dir(bm25_persist_path)
169
+ else:
170
+ bm25_retriever = BM25Retriever.from_defaults(
171
+ docstore=docstore,
172
+ similarity_top_k=2,
173
+ language="portuguese", # Idioma ajustado para seu caso
174
+ )
175
+ os.makedirs(bm25_persist_path, exist_ok=True)
176
+ bm25_retriever.persist(bm25_persist_path)
177
+
178
+ #Adicionado documentos na pasta curadoria, foi setado para 1200 o chunk pra receber pergunta, contexto e resposta
179
+ curadoria_documents = SimpleDirectoryReader(input_dir=curadoria_path).load_data()
180
+
181
+ curadoria_docstore = SimpleDocumentStore()
182
+ curadoria_docstore.add_documents(curadoria_documents)
183
+
184
+ db_curadoria = chromadb.PersistentClient(path=chroma_storage_path_curadoria)
185
+ chroma_collection_curadoria = db_curadoria.get_or_create_collection("dense_vectors_curadoria")
186
+ vector_store_curadoria = ChromaVectorStore(chroma_collection=chroma_collection_curadoria)
187
+
188
+ # Configuração do StorageContext para 'curadoria'
189
+ storage_context_curadoria = StorageContext.from_defaults(
190
+ docstore=curadoria_docstore, vector_store=vector_store_curadoria
191
+ )
192
+
193
+ # Criação/Recarregamento do índice com embeddings para 'curadoria'
194
+ if os.path.exists(chroma_storage_path_curadoria):
195
+ curadoria_index = VectorStoreIndex.from_vector_store(vector_store_curadoria)
196
+ else:
197
+ curadoria_splitter = LangchainNodeParser(
198
+ RecursiveCharacterTextSplitter(chunk_size=1200, chunk_overlap=100)
199
+ )
200
+ curadoria_index = VectorStoreIndex.from_documents(
201
+ curadoria_documents, storage_context=storage_context_curadoria, transformations=[curadoria_splitter]
202
+ )
203
+ vector_store_curadoria.persist()
204
+
205
+ curadoria_retriever = curadoria_index.as_retriever(similarity_top_k=2)
206
+
207
+ # Combinação de Retrievers (Embeddings + BM25)
208
+ vector_retriever = index.as_retriever(similarity_top_k=2)
209
+ retriever = QueryFusionRetriever(
210
+ [vector_retriever, bm25_retriever, curadoria_retriever],
211
+ similarity_top_k=2,
212
+ num_queries=4,
213
+ mode="reciprocal_rerank",
214
+ use_async=True,
215
+ verbose=True,
216
+ query_gen_prompt=(
217
+ "Gere {num_queries} perguntas de busca relacionadas à seguinte pergunta. "
218
+ "Priorize o significado da pergunta sobre qualquer histórico de conversa. "
219
+ "Se o histórico não for relevante para a pergunta, ignore-o. "
220
+ "Não adicione explicações, notas ou introduções. Apenas escreva as perguntas. "
221
+ "Pergunta: {query}\n\n"
222
+ "Perguntas:\n"
223
+ ),
224
+ )
225
+
226
+ # Configuração do chat engine
227
+ nest_asyncio.apply()
228
+ memory = ChatMemoryBuffer.from_defaults(token_limit=3900)
229
+ query_engine = RetrieverQueryEngine.from_args(retriever)
230
+ chat_engine = CondensePlusContextChatEngine.from_defaults(
231
+ query_engine,
232
+ memory=memory,
233
+ context_prompt=(
234
+ "Você é um assistente virtual capaz de interagir normalmente, além de"
235
+ " fornecer informações sobre organogramas e listar funcionários."
236
+ " Aqui estão os documentos relevantes para o contexto:\n"
237
+ "{context_str}"
238
+ "\nInstrução: Use o histórico da conversa anterior, ou o contexto acima, para responder."
239
+ ),
240
+ verbose=True,
241
+ )
242
+
243
+ # Armazenamento do chat
244
+ chat_store = SimpleChatStore()
245
+ if os.path.exists(chat_store_path):
246
+ chat_store = SimpleChatStore.from_persist_path(persist_path=chat_store_path)
247
+ else:
248
+ chat_store.persist(persist_path=chat_store_path)
249
+
250
+ # Interface do Chatbot
251
+ st.title("Chatbot Carômetro")
252
+ st.write("Este chatbot pode te ajudar a conseguir informações relevantes sobre os carômetros da Sicoob.")
253
+ if "chat_history" not in st.session_state:
254
+ st.session_state.chat_history = []
255
+
256
+ user_input = st.chat_input("Digite sua pergunta")
257
+ if user_input:
258
+ response = chat_engine.chat(user_input)
259
+ st.session_state.chat_history.append(f"user: {user_input}")
260
+ st.session_state.chat_history.append(f"assistant: {response}")
261
+ for message in st.session_state.chat_history:
262
+ role, text = message.split(":", 1)
263
+ with st.chat_message(role.strip().lower()):
264
+ st.write(text.strip())