leandroaraujodev commited on
Commit
4e15376
·
verified ·
1 Parent(s): 1545bf8

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +155 -0
app.py ADDED
@@ -0,0 +1,155 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+
20
+
21
+ import os
22
+
23
+ # Lista de pastas que precisam ser criadas
24
+ pastas = ["bm25_retriever", "chat_store", "chroma_db", "documentos"]
25
+
26
+ # Criar cada pasta caso não exista
27
+ for pasta in pastas:
28
+ if not os.path.exists(pasta):
29
+ os.makedirs(pasta)
30
+ print(f"Pasta '{pasta}' criada com sucesso.")
31
+ else:
32
+ print(f"Pasta '{pasta}' já existe.")
33
+
34
+
35
+
36
+ # Configuração do Streamlit
37
+ st.sidebar.title("Configuração de LLM")
38
+ sidebar_option = st.sidebar.radio("Selecione o LLM", ["Ollama", "OpenAI"])
39
+
40
+ if sidebar_option == "Ollama":
41
+ Settings.llm = Ollama(model="llama3.2:latest", request_timeout=500.0, num_gpu=1)
42
+ Settings.embed_model = OllamaEmbedding(model_name="nomic-embed-text:latest")
43
+ elif sidebar_option == "OpenAI":
44
+ from llama_index.llms.openai import OpenAI
45
+ from llama_index.embeddings.openai import OpenAIEmbedding
46
+ os.environ["OPENAI_API_KEY"] = "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"
47
+ Settings.llm = OpenAI(model="gpt-3.5-turbo")
48
+ Settings.embed_model = OpenAIEmbedding(model_name="text-embedding-ada-002")
49
+ else:
50
+ raise Exception("Opção de LLM inválida!")
51
+
52
+ # Diretórios configurados pelo usuário
53
+ chat_store_path = os.path.join("chat_store", "chat_store.json")
54
+ documents_path = os.path.join("documentos")
55
+ chroma_storage_path = os.path.join("chroma_db") # Diretório para persistência do Chroma
56
+ bm25_persist_path = os.path.join("bm25_retriever")
57
+
58
+ # Configuração de leitura de documentos
59
+ documents = SimpleDirectoryReader(input_dir=documents_path).load_data()
60
+
61
+ # Configuração do Chroma e BM25 com persistência
62
+ docstore = SimpleDocumentStore()
63
+ docstore.add_documents(documents)
64
+
65
+ db = chromadb.PersistentClient(path=chroma_storage_path)
66
+ chroma_collection = db.get_or_create_collection("dense_vectors")
67
+ vector_store = ChromaVectorStore(chroma_collection=chroma_collection)
68
+
69
+ # Configuração do StorageContext
70
+ storage_context = StorageContext.from_defaults(
71
+ docstore=docstore, vector_store=vector_store
72
+ )
73
+
74
+ # Criação/Recarregamento do índice com embeddings
75
+ if os.path.exists(chroma_storage_path):
76
+ index = VectorStoreIndex.from_vector_store(vector_store)
77
+ else:
78
+ splitter = LangchainNodeParser(
79
+ RecursiveCharacterTextSplitter(chunk_size=512, chunk_overlap=64)
80
+ )
81
+ index = VectorStoreIndex.from_documents(
82
+ documents, storage_context=storage_context, transformations=[splitter]
83
+ )
84
+ vector_store.persist()
85
+
86
+ # Criação/Recarregamento do BM25 Retriever
87
+ if os.path.exists(os.path.join(bm25_persist_path, "params.index.json")):
88
+ bm25_retriever = BM25Retriever.from_persist_dir(bm25_persist_path)
89
+ else:
90
+ bm25_retriever = BM25Retriever.from_defaults(
91
+ docstore=docstore,
92
+ similarity_top_k=2,
93
+ language="portuguese", # Idioma ajustado para seu caso
94
+ )
95
+ os.makedirs(bm25_persist_path, exist_ok=True)
96
+ bm25_retriever.persist(bm25_persist_path)
97
+
98
+ # Combinação de Retrievers (Embeddings + BM25)
99
+ vector_retriever = index.as_retriever(similarity_top_k=2)
100
+ retriever = QueryFusionRetriever(
101
+ [vector_retriever, bm25_retriever],
102
+ similarity_top_k=2,
103
+ num_queries=4,
104
+ mode="reciprocal_rerank",
105
+ use_async=True,
106
+ verbose=True,
107
+ query_gen_prompt=(
108
+ "Gere {num_queries} perguntas de busca relacionadas à seguinte pergunta. "
109
+ "Priorize o significado da pergunta sobre qualquer histórico de conversa. "
110
+ "Se o histórico não for relevante para a pergunta, ignore-o. "
111
+ "Não adicione explicações, notas ou introduções. Apenas escreva as perguntas. "
112
+ "Pergunta: {query}\n\n"
113
+ "Perguntas:\n"
114
+ ),
115
+ )
116
+
117
+ # Configuração do chat engine
118
+ nest_asyncio.apply()
119
+ memory = ChatMemoryBuffer.from_defaults(token_limit=3900)
120
+ query_engine = RetrieverQueryEngine.from_args(retriever)
121
+ chat_engine = CondensePlusContextChatEngine.from_defaults(
122
+ query_engine,
123
+ memory=memory,
124
+ context_prompt=(
125
+ "Você é um assistente virtual capaz de interagir normalmente, além de"
126
+ " fornecer informações sobre organogramas e listar funcionários."
127
+ " Aqui estão os documentos relevantes para o contexto:\n"
128
+ "{context_str}"
129
+ "\nInstrução: Use o histórico da conversa anterior, ou o contexto acima, para responder."
130
+ ),
131
+ verbose=True,
132
+ )
133
+
134
+ # Armazenamento do chat
135
+ chat_store = SimpleChatStore()
136
+ if os.path.exists(chat_store_path):
137
+ chat_store = SimpleChatStore.from_persist_path(persist_path=chat_store_path)
138
+ else:
139
+ chat_store.persist(persist_path=chat_store_path)
140
+
141
+ # Interface do Chatbot
142
+ st.title("Chatbot Local")
143
+ st.write("Este chatbot utiliza RAG Fusion e técnicas de re-ranking para responder com informações relevantes.")
144
+ if "chat_history" not in st.session_state:
145
+ st.session_state.chat_history = []
146
+
147
+ user_input = st.chat_input("Digite sua pergunta")
148
+ if user_input:
149
+ response = chat_engine.chat(user_input)
150
+ st.session_state.chat_history.append(f"user: {user_input}")
151
+ st.session_state.chat_history.append(f"assistant: {response}")
152
+ for message in st.session_state.chat_history:
153
+ role, text = message.split(":", 1)
154
+ with st.chat_message(role.strip().lower()):
155
+ st.write(text.strip())