Geoeasy commited on
Commit
f141c0f
·
verified ·
1 Parent(s): cbb597c

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +68 -70
app.py CHANGED
@@ -2,31 +2,15 @@ import os
2
  from pathlib import Path
3
  import gradio as gr
4
  import numpy as np
5
- from sentence_transformers import SentenceTransformer
6
  import faiss
7
- from openai import OpenAI, OpenAIError
8
- from langchain_community.document_loaders import PyPDFLoader
9
- from langchain.text_splitter import RecursiveCharacterTextSplitter
10
-
11
- # ----------------------------
12
- # NVIDIA API Key (set via Space Variables & Secrets)
13
- # ----------------------------
14
- NV_API_KEY = os.environ.get("NV_API_KEY")
15
- if not NV_API_KEY:
16
- raise RuntimeError(
17
- "🔒 NV_API_KEY not set. "
18
- "In your Hugging Face Space, go to Settings → Variables & Secrets and create a variable named NV_API_KEY with your NVIDIA key."
19
- )
20
 
21
- # NVIDIA-compatible OpenAI client
22
- client = OpenAI(
23
- base_url="https://integrate.api.nvidia.com/v1",
24
- api_key=NV_API_KEY
25
- )
26
- CHAT_MODEL = "meta/llama3-8b-instruct"
27
 
28
  # ----------------------------
29
- # Application configuration
30
  # ----------------------------
31
  APP_TITLE = "CVchat – Ronaldo Menezes"
32
  INTRO = (
@@ -47,80 +31,93 @@ SUGGESTION_QUESTIONS = [
47
  "Certificações?",
48
  ]
49
 
 
50
  INDEX_FILE = "r_docs.index"
51
  CHUNKS_FILE = "r_chunks.npy"
52
  PDF_PATH = "CV-Ronaldo_Menezes_2025_06.pdf"
53
 
54
- # verify index files exist
55
  if not Path(INDEX_FILE).exists() or not Path(CHUNKS_FILE).exists():
56
- raise FileNotFoundError(
57
- "Index not found. Please run first:\n python build_index.py"
58
- )
59
 
60
- # load FAISS index and chunks
61
  index = faiss.read_index(INDEX_FILE)
62
  chunks = np.load(CHUNKS_FILE, allow_pickle=True)
63
 
64
- # sentence-transformer embedding model
65
  embedding_model = SentenceTransformer('all-MiniLM-L6-v2')
66
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
67
  def retrieve_context(query: str, k: int = 4) -> str:
68
- q_emb = embedding_model.encode([query], convert_to_numpy=True)
69
  _, I = index.search(q_emb, k)
70
  return "\n---\n".join(chunks[i] for i in I[0])
71
 
72
- # maintain dialog history
73
  dialog_history: list[tuple[str, str]] = []
74
 
 
 
 
75
  def chatbot(user_input, temperature, top_p, max_tokens):
76
  global dialog_history
77
  if not user_input:
78
  return dialog_history, ""
79
 
80
- # retrieve context
81
  context = retrieve_context(user_input)
82
- system_msg = {
83
- "role": "system",
84
- "content": (
85
- "You are an assistant specialized in R packages. "
86
- "Use only the context below to answer. If you don't know, say so.\n\n"
87
- f"=== Retrieved Context ===\n{context}\n\n"
88
- )
89
- }
90
-
91
- # build messages
92
- messages = [system_msg]
93
- for u, a in dialog_history:
94
- messages.append({"role": "user", "content": u})
95
- messages.append({"role": "assistant", "content": a})
96
- messages.append({"role": "user", "content": user_input})
97
-
98
- assistant_reply = ""
99
  try:
100
- stream = client.chat.completions.create(
101
- model=CHAT_MODEL,
102
- messages=messages,
103
  temperature=temperature,
104
  top_p=top_p,
105
- max_tokens=max_tokens,
106
- stream=True
107
- )
108
- for chunk in stream:
109
- delta = chunk.choices[0].delta
110
- if hasattr(delta, "content") and delta.content:
111
- assistant_reply += delta.content
112
- except OpenAIError as e:
113
- assistant_reply = f"⚠️ API Error: {e.__class__.__name__}: {e}"
114
 
115
  dialog_history.append((user_input, assistant_reply))
116
  return dialog_history, ""
117
 
118
- def clear_history():
119
  global dialog_history
120
  dialog_history = []
121
- return [], ""
122
 
123
- # Custom CSS
 
 
124
  custom_css = r"""
125
  :root {
126
  --primary: #4a90e2;
@@ -144,23 +141,25 @@ with gr.Blocks(title=APP_TITLE, css=custom_css, theme=gr.themes.Base()) as demo:
144
  gr.Markdown(INTRO)
145
 
146
  with gr.Row():
147
- # main chat column
148
  with gr.Column(scale=3):
149
- chatbot_ui = gr.Chatbot(type="tuples", elem_id="chat-window")
150
  with gr.Row(elem_id="input-area"):
151
  txt = gr.Textbox(placeholder="Digite sua pergunta…", lines=2, elem_id="user-input")
152
  btn = gr.Button("Enviar", elem_id="send-button")
153
- #btn.click(chatbot, [txt, gr.Slider(0,1,0.6), gr.Slider(0,1,0.95), gr.Slider(64,2048,512)], [chatbot_ui, txt])
154
- txt.submit(chatbot, [txt, gr.Slider(0,1,0.6), gr.Slider(0,1,0.95), gr.Slider(64,2048,512)], [chatbot_ui, txt])
155
- gr.Button("Limpar").click(clear_history, [], [chatbot_ui, txt])
 
 
 
 
156
 
157
- # sidebar: PDF & suggestions
158
  with gr.Column(scale=1, elem_classes="sidebar"):
159
  if Path(PDF_PATH).exists():
160
  gr.Markdown(f"[📄 Baixar CV em PDF](/file={PDF_PATH})")
161
  gr.Markdown("### Sugestões de Perguntas")
162
  for q in SUGGESTION_QUESTIONS:
163
- gr.Button(q).click(lambda suggestion=q: suggestion, outputs=[txt])
164
  gr.Markdown("---")
165
  gr.Markdown("### Dicas de Exploração do PDF")
166
  gr.Markdown("• Use palavras-chave como 'Process Mining' ou 'GIS' para ir direto à seção relevante.")
@@ -168,4 +167,3 @@ with gr.Blocks(title=APP_TITLE, css=custom_css, theme=gr.themes.Base()) as demo:
168
 
169
  if __name__ == "__main__":
170
  demo.launch(server_name="0.0.0.0", server_port=7860)
171
-
 
2
  from pathlib import Path
3
  import gradio as gr
4
  import numpy as np
5
+ import torch
6
  import faiss
 
 
 
 
 
 
 
 
 
 
 
 
 
7
 
8
+ from sentence_transformers import SentenceTransformer
9
+ from transformers import AutoTokenizer, AutoModelForCausalLM, pipeline
10
+ from huggingface_hub import login
 
 
 
11
 
12
  # ----------------------------
13
+ # Configurações da aplicação
14
  # ----------------------------
15
  APP_TITLE = "CVchat – Ronaldo Menezes"
16
  INTRO = (
 
31
  "Certificações?",
32
  ]
33
 
34
+ # Caminhos dos arquivos de índice
35
  INDEX_FILE = "r_docs.index"
36
  CHUNKS_FILE = "r_chunks.npy"
37
  PDF_PATH = "CV-Ronaldo_Menezes_2025_06.pdf"
38
 
39
+ # Verificação dos arquivos
40
  if not Path(INDEX_FILE).exists() or not Path(CHUNKS_FILE).exists():
41
+ raise FileNotFoundError("Index not found. Por favor, execute: python build_index.py")
 
 
42
 
43
+ # Carrega o índice FAISS e os trechos
44
  index = faiss.read_index(INDEX_FILE)
45
  chunks = np.load(CHUNKS_FILE, allow_pickle=True)
46
 
47
+ # Modelo de embeddings
48
  embedding_model = SentenceTransformer('all-MiniLM-L6-v2')
49
 
50
+ # ----------------------------
51
+ # Carregamento do modelo LLM local
52
+ # ----------------------------
53
+ hf_token = os.getenv("HF_TOKEN")
54
+ if hf_token is None:
55
+ raise ValueError("Token Hugging Face não encontrado. Defina como segredo 'HF_TOKEN' nos Settings do Space.")
56
+
57
+ # Autenticação
58
+ login(token=hf_token)
59
+
60
+ MODEL_NAME = "microsoft/phi-2"
61
+ tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME, token=hf_token)
62
+ model = AutoModelForCausalLM.from_pretrained(
63
+ MODEL_NAME,
64
+ torch_dtype=torch.float16 if torch.cuda.is_available() else torch.float32,
65
+ device_map="auto",
66
+ token=hf_token
67
+ )
68
+ llm_pipeline = pipeline("text-generation", model=model, tokenizer=tokenizer)
69
+
70
+ # ----------------------------
71
+ # Recuperação de contexto com FAISS
72
+ # ----------------------------
73
  def retrieve_context(query: str, k: int = 4) -> str:
74
+ q_emb = embedding_model.encode([query], convert_to_numpy=True, show_progress_bar=False)
75
  _, I = index.search(q_emb, k)
76
  return "\n---\n".join(chunks[i] for i in I[0])
77
 
 
78
  dialog_history: list[tuple[str, str]] = []
79
 
80
+ # ----------------------------
81
+ # Função do chatbot
82
+ # ----------------------------
83
  def chatbot(user_input, temperature, top_p, max_tokens):
84
  global dialog_history
85
  if not user_input:
86
  return dialog_history, ""
87
 
 
88
  context = retrieve_context(user_input)
89
+
90
+ prompt = (
91
+ f"### System:\nVocê é um assistente especializado em pacotes R. "
92
+ f"Use somente o contexto abaixo para responder. Se não souber, diga isso.\n\n"
93
+ f"=== Retrieved Context ===\n{context}\n\n"
94
+ f"### User:\n{user_input}\n\n### Assistant:\n"
95
+ )
96
+
 
 
 
 
 
 
 
 
 
97
  try:
98
+ result = llm_pipeline(
99
+ prompt[:model.config.max_position_embeddings],
100
+ max_new_tokens=max_tokens,
101
  temperature=temperature,
102
  top_p=top_p,
103
+ do_sample=True
104
+ )[0]
105
+ assistant_reply = result.get('generated_text') or result.get('text') or "⚠️ Resposta não gerada."
106
+ assistant_reply = assistant_reply.split("### Assistant:")[-1].strip()
107
+ except Exception as e:
108
+ assistant_reply = f"⚠️ Erro local: {e}"
 
 
 
109
 
110
  dialog_history.append((user_input, assistant_reply))
111
  return dialog_history, ""
112
 
113
+ def clear_all():
114
  global dialog_history
115
  dialog_history = []
116
+ return [], "", 0.6, 0.95, 512
117
 
118
+ # ----------------------------
119
+ # Interface Gradio
120
+ # ----------------------------
121
  custom_css = r"""
122
  :root {
123
  --primary: #4a90e2;
 
141
  gr.Markdown(INTRO)
142
 
143
  with gr.Row():
 
144
  with gr.Column(scale=3):
145
+ chatbot_ui = gr.Chatbot(type="tuples", elem_id="chat-window", render_markdown=True)
146
  with gr.Row(elem_id="input-area"):
147
  txt = gr.Textbox(placeholder="Digite sua pergunta…", lines=2, elem_id="user-input")
148
  btn = gr.Button("Enviar", elem_id="send-button")
149
+ temp = gr.Slider(0, 1, 0.6, label="Temperatura")
150
+ topp = gr.Slider(0, 1, 0.95, label="Top-p")
151
+ maxtok = gr.Slider(64, 1024, 512, label="Tokens Máximos")
152
+
153
+ btn.click(chatbot, [txt, temp, topp, maxtok], [chatbot_ui, txt])
154
+ txt.submit(chatbot, [txt, temp, topp, maxtok], [chatbot_ui, txt])
155
+ gr.Button("Limpar").click(clear_all, [], [chatbot_ui, txt, temp, topp, maxtok])
156
 
 
157
  with gr.Column(scale=1, elem_classes="sidebar"):
158
  if Path(PDF_PATH).exists():
159
  gr.Markdown(f"[📄 Baixar CV em PDF](/file={PDF_PATH})")
160
  gr.Markdown("### Sugestões de Perguntas")
161
  for q in SUGGESTION_QUESTIONS:
162
+ gr.Button(q).click(lambda q=q: (q, *chatbot(q, 0.6, 0.95, 512)), outputs=[txt, chatbot_ui, txt])
163
  gr.Markdown("---")
164
  gr.Markdown("### Dicas de Exploração do PDF")
165
  gr.Markdown("• Use palavras-chave como 'Process Mining' ou 'GIS' para ir direto à seção relevante.")
 
167
 
168
  if __name__ == "__main__":
169
  demo.launch(server_name="0.0.0.0", server_port=7860)