roundb commited on
Commit
1016335
·
verified ·
1 Parent(s): da2a921

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +57 -122
app.py CHANGED
@@ -1,129 +1,94 @@
1
  #!/usr/bin/env python3
2
  """
3
- RAG Chatbot – Gradio + FAISS + NVIDIA NIM
4
- Layout com cards automáticos usando examples do ChatInterface
5
  """
6
 
7
  import os
8
- import glob
9
- from typing import List
10
-
11
  import gradio as gr
12
- import pandas as pd
13
  from openai import OpenAI
14
 
15
- from langchain_core.documents import Document
16
  from langchain_community.vectorstores import FAISS
17
  from langchain_huggingface import HuggingFaceEmbeddings
18
- from langchain_text_splitters import RecursiveCharacterTextSplitter
19
 
20
- #
21
  # =========================
22
  # CONFIG
23
  # =========================
24
- DATA_DIR = os.getenv("DATA_DIR", "data")
25
-
26
  EMB_MODEL = "sentence-transformers/all-MiniLM-L6-v2"
27
- CHUNK_SIZE = 900
28
- CHUNK_OVERLAP = 150
29
  TOP_K = 6
30
  MAX_CONTEXT_CHARS = 4500
31
 
32
- NVIDIA_API_KEY = os.getenv("NVIDIA_API_KEY", "")
33
  NVIDIA_BASE_URL = "https://integrate.api.nvidia.com/v1"
34
  NVIDIA_MODEL = "meta/llama-3.3-70b-instruct"
35
 
36
- client = OpenAI(base_url=NVIDIA_BASE_URL, api_key=NVIDIA_API_KEY) if NVIDIA_API_KEY else None
 
 
 
37
 
38
- SYSTEM_PROMPT = """Você é um assistente que responde perguntas com base em documentos.
39
- Responda SOMENTE com base no CONTEXTO recuperado.
40
  Se não houver evidência suficiente, diga claramente.
41
  Seja objetivo.
42
  """
43
 
44
 
45
  # =========================
46
- # READ FILES
47
  # =========================
48
- SUPPORTED_EXT = {".pdf", ".docx", ".xlsx", ".xls", ".csv", ".txt"}
49
-
50
- def list_files(data_dir: str) -> List[str]:
51
- files = []
52
- for ext in SUPPORTED_EXT:
53
- files.extend(glob.glob(os.path.join(data_dir, f"**/*{ext}"), recursive=True))
54
- return sorted(set(files))
55
-
56
-
57
- def read_txt(path):
58
- try:
59
- with open(path, "r", encoding="utf-8", errors="ignore") as f:
60
- return f.read()
61
- except:
62
- return ""
63
-
64
-
65
- def read_csv(path):
66
- try:
67
- df = pd.read_csv(path)
68
- return df.head(1000).to_csv(index=False)
69
- except:
70
- return ""
71
-
72
-
73
- def read_docx(path):
74
- from docx import Document as DocxDocument
75
- doc = DocxDocument(path)
76
- return "\n".join([p.text for p in doc.paragraphs if p.text.strip()])
77
-
78
 
79
- def read_pdf(path):
80
- from pypdf import PdfReader
81
- reader = PdfReader(path)
82
- return "\n".join([p.extract_text() or "" for p in reader.pages])
 
 
 
 
 
 
83
 
84
 
85
  # =========================
86
- # BUILD VECTOR DATABASE
87
  # =========================
88
- def build_vectordb():
89
- files = list_files(DATA_DIR)
90
- if not files:
91
- raise FileNotFoundError("Nenhum arquivo encontrado na pasta data/")
92
-
93
- docs = []
94
- splitter = RecursiveCharacterTextSplitter(
95
- chunk_size=CHUNK_SIZE,
96
- chunk_overlap=CHUNK_OVERLAP
97
- )
98
 
99
- for path in files:
100
- ext = os.path.splitext(path)[1].lower()
101
- text = ""
102
 
103
- if ext == ".txt":
104
- text = read_txt(path)
105
- elif ext == ".csv":
106
- text = read_csv(path)
107
- elif ext in [".xlsx", ".xls"]:
108
- text = read_csv(path)
109
- elif ext == ".docx":
110
- text = read_docx(path)
111
- elif ext == ".pdf":
112
- text = read_pdf(path)
113
 
114
- for chunk in splitter.split_text(text):
115
- docs.append(Document(page_content=chunk, metadata={"source": path}))
116
 
117
- embedding = HuggingFaceEmbeddings(model_name=EMB_MODEL)
118
- db = FAISS.from_documents(docs, embedding)
119
- return db
120
 
 
 
 
 
 
 
 
 
 
121
 
122
- vectordb = build_vectordb()
123
 
124
 
125
  # =========================
126
- # SUGGESTIONS (CARDS)
127
  # =========================
128
  SUGGESTIONS = [
129
  "Resuma os principais pontos do documento.",
@@ -138,53 +103,23 @@ SUGGESTIONS = [
138
 
139
 
140
  # =========================
141
- # RAG FUNCTION
142
  # =========================
143
- def format_context(docs):
144
- context = "\n\n".join([d.page_content for d in docs])
145
- if len(context) > MAX_CONTEXT_CHARS:
146
- context = context[:MAX_CONTEXT_CHARS]
147
- return context
148
-
149
-
150
- def chat_rag_nvidia(message, history):
151
- if not client:
152
- return "❌ Configure NVIDIA_API_KEY."
153
-
154
- retrieved = vectordb.similarity_search(message, k=TOP_K)
155
- context = format_context(retrieved)
156
 
157
- messages = [
158
- {"role": "system", "content": SYSTEM_PROMPT},
159
- {"role": "user", "content": f"CONTEXTO:\n{context}\n\nPERGUNTA:\n{message}"}
160
- ]
161
 
162
- completion = client.chat.completions.create(
163
- model=NVIDIA_MODEL,
164
- messages=messages,
165
- temperature=0.3,
166
- max_tokens=800,
167
- )
168
-
169
- return completion.choices[0].message.content
170
-
171
-
172
- # =========================
173
- # UI (USANDO EXAMPLES NATIVOS)
174
- # =========================
175
- with gr.Blocks(title="Document RAG Assistant") as demo:
176
-
177
- gr.Markdown("""
178
- ## 📚 SOGETREL
179
- Faça perguntas sobre os documentos indexados.
180
  """)
181
 
182
  gr.ChatInterface(
183
- fn=chat_rag_nvidia,
184
- examples=SUGGESTIONS, # ← Aqui são gerados os cards automaticamente
185
  title="Assistant",
186
  description="Pergunte algo sobre os documentos."
187
  )
188
 
 
189
  if __name__ == "__main__":
190
- demo.launch()
 
1
  #!/usr/bin/env python3
2
  """
3
+ RAG Chatbot – Hugging Face Space
4
+ Carrega FAISS existente (sem rebuild)
5
  """
6
 
7
  import os
 
 
 
8
  import gradio as gr
 
9
  from openai import OpenAI
10
 
 
11
  from langchain_community.vectorstores import FAISS
12
  from langchain_huggingface import HuggingFaceEmbeddings
 
13
 
14
+
15
  # =========================
16
  # CONFIG
17
  # =========================
18
+ INDEX_DIR = "vectorstore_faiss"
 
19
  EMB_MODEL = "sentence-transformers/all-MiniLM-L6-v2"
20
+
 
21
  TOP_K = 6
22
  MAX_CONTEXT_CHARS = 4500
23
 
24
+ NVIDIA_API_KEY = os.getenv("NVIDIA_API_KEY")
25
  NVIDIA_BASE_URL = "https://integrate.api.nvidia.com/v1"
26
  NVIDIA_MODEL = "meta/llama-3.3-70b-instruct"
27
 
28
+ client = OpenAI(
29
+ base_url=NVIDIA_BASE_URL,
30
+ api_key=NVIDIA_API_KEY
31
+ ) if NVIDIA_API_KEY else None
32
 
33
+
34
+ SYSTEM_PROMPT = """Você responde perguntas usando apenas o CONTEXTO recuperado.
35
  Se não houver evidência suficiente, diga claramente.
36
  Seja objetivo.
37
  """
38
 
39
 
40
  # =========================
41
+ # LOAD FAISS EXISTENTE
42
  # =========================
43
+ embedding = HuggingFaceEmbeddings(model_name=EMB_MODEL)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44
 
45
+ try:
46
+ vectordb = FAISS.load_local(
47
+ INDEX_DIR,
48
+ embedding,
49
+ allow_dangerous_deserialization=True
50
+ )
51
+ STATUS = "✅ Índice FAISS carregado com sucesso."
52
+ except Exception as e:
53
+ vectordb = None
54
+ STATUS = f"❌ Erro ao carregar índice: {str(e)}"
55
 
56
 
57
  # =========================
58
+ # RAG FUNCTION
59
  # =========================
60
+ def format_context(docs):
61
+ context = "\n\n".join([d.page_content for d in docs])
62
+ if len(context) > MAX_CONTEXT_CHARS:
63
+ context = context[:MAX_CONTEXT_CHARS]
64
+ return context
 
 
 
 
 
65
 
 
 
 
66
 
67
+ def chat(message, history):
68
+ if not client:
69
+ return "❌ Configure NVIDIA_API_KEY em Settings → Secrets."
 
 
 
 
 
 
 
70
 
71
+ if not vectordb:
72
+ return " Índice FAISS não carregado."
73
 
74
+ docs = vectordb.similarity_search(message, k=TOP_K)
75
+ context = format_context(docs)
 
76
 
77
+ completion = client.chat.completions.create(
78
+ model=NVIDIA_MODEL,
79
+ messages=[
80
+ {"role": "system", "content": SYSTEM_PROMPT},
81
+ {"role": "user", "content": f"CONTEXTO:\n{context}\n\nPERGUNTA:\n{message}"}
82
+ ],
83
+ temperature=0.3,
84
+ max_tokens=800,
85
+ )
86
 
87
+ return completion.choices[0].message.content
88
 
89
 
90
  # =========================
91
+ # SUGGESTION CARDS
92
  # =========================
93
  SUGGESTIONS = [
94
  "Resuma os principais pontos do documento.",
 
103
 
104
 
105
  # =========================
106
+ # UI
107
  # =========================
108
+ with gr.Blocks(title="SOGETREL – RAG Assistant") as demo:
 
 
 
 
 
 
 
 
 
 
 
 
109
 
110
+ gr.Markdown(f"""
111
+ ## 📚 SOGETREL – Document Assistant
 
 
112
 
113
+ {STATUS}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
114
  """)
115
 
116
  gr.ChatInterface(
117
+ fn=chat,
118
+ examples=SUGGESTIONS,
119
  title="Assistant",
120
  description="Pergunte algo sobre os documentos."
121
  )
122
 
123
+
124
  if __name__ == "__main__":
125
+ demo.launch(server_name="0.0.0.0", server_port=7860)