DHEIVER commited on
Commit
870c41d
·
verified ·
1 Parent(s): 9247698

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +202 -35
app.py CHANGED
@@ -1,38 +1,205 @@
1
  import gradio as gr
2
- from transformers import pipeline
3
  import PyPDF2
 
 
 
 
 
 
 
 
4
 
5
- # Carregar o modelo de linguagem gratuito da Hugging Face
6
- nlp = pipeline("question-answering", model="distilbert-base-cased-distilled-squad")
7
-
8
- def extract_text_from_pdf(pdf_file):
9
- with open(pdf_file.name, "rb") as file:
10
- reader = PyPDF2.PdfFileReader(file)
11
- text = ""
12
- for page_num in range(reader.numPages):
13
- page = reader.getPage(page_num)
14
- text += page.extract_text()
15
- return text
16
-
17
- def answer_question(pdf_file, question):
18
- # Extrair texto do PDF
19
- context = extract_text_from_pdf(pdf_file)
20
-
21
- # Usar o modelo para responder a pergunta
22
- result = nlp(question=question, context=context)
23
- return result['answer']
24
-
25
- # Interface Gradio
26
- iface = gr.Interface(
27
- fn=answer_question,
28
- inputs=[
29
- gr.File(label="Carregar PDF"),
30
- gr.Textbox(label="Pergunta")
31
- ],
32
- outputs=gr.Textbox(label="Resposta"),
33
- title="QA sobre PDF",
34
- description="Carregue um PDF e faça perguntas sobre o conteúdo."
35
- )
36
-
37
- # Iniciar a interface
38
- iface.launch()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import gradio as gr
2
+ from transformers import AutoModelForQuestionAnswering, AutoTokenizer, pipeline
3
  import PyPDF2
4
+ import torch
5
+ import re
6
+ from typing import List, Dict, Tuple
7
+ import nltk
8
+ from nltk.tokenize import sent_tokenize
9
+ import fitz # PyMuPDF
10
+ import logging
11
+ from tqdm import tqdm
12
 
13
+ # Configurar logging
14
+ logging.basicConfig(level=logging.INFO)
15
+ logger = logging.getLogger(__name__)
16
+
17
+ # Baixar recursos necessários do NLTK
18
+ try:
19
+ nltk.download('punkt', quiet=True)
20
+ except Exception as e:
21
+ logger.warning(f"Erro ao baixar recursos NLTK: {e}")
22
+
23
+ class PDFQuestionAnswering:
24
+ def __init__(self):
25
+ # Usar modelo multilíngue mais avançado
26
+ self.model_name = "deepset/roberta-base-squad2"
27
+ try:
28
+ self.tokenizer = AutoTokenizer.from_pretrained(self.model_name)
29
+ self.model = AutoModelForQuestionAnswering.from_pretrained(self.model_name)
30
+ self.nlp = pipeline('question-answering',
31
+ model=self.model,
32
+ tokenizer=self.tokenizer,
33
+ device=0 if torch.cuda.is_available() else -1)
34
+ logger.info(f"Modelo {self.model_name} carregado com sucesso")
35
+ except Exception as e:
36
+ logger.error(f"Erro ao carregar o modelo: {e}")
37
+ raise
38
+
39
+ def extract_text_from_pdf(self, pdf_file: str) -> Tuple[str, Dict[int, str]]:
40
+ """
41
+ Extrai texto do PDF usando PyMuPDF para melhor precisão
42
+ Retorna o texto completo e um dicionário mapeando números de página para texto
43
+ """
44
+ try:
45
+ doc = fitz.open(pdf_file)
46
+ full_text = ""
47
+ page_text = {}
48
+
49
+ for page_num in range(len(doc)):
50
+ page = doc[page_num]
51
+ text = page.get_text("text")
52
+ page_text[page_num] = text
53
+ full_text += text + "\n"
54
+
55
+ return full_text, page_text
56
+ except Exception as e:
57
+ logger.error(f"Erro na extração do PDF: {e}")
58
+ raise
59
+ finally:
60
+ if 'doc' in locals():
61
+ doc.close()
62
+
63
+ def preprocess_text(self, text: str) -> str:
64
+ """
65
+ Pré-processa o texto removendo caracteres especiais e formatação indesejada
66
+ """
67
+ # Remover quebras de linha extras
68
+ text = re.sub(r'\n+', ' ', text)
69
+ # Remover espaços múltiplos
70
+ text = re.sub(r'\s+', ' ', text)
71
+ # Remover caracteres especiais
72
+ text = re.sub(r'[^\w\s.,!?-]', '', text)
73
+ return text.strip()
74
+
75
+ def split_into_chunks(self, text: str, max_length: int = 512) -> List[str]:
76
+ """
77
+ Divide o texto em chunks menores respeitando limites de sentenças
78
+ """
79
+ sentences = sent_tokenize(text)
80
+ chunks = []
81
+ current_chunk = ""
82
+
83
+ for sentence in sentences:
84
+ if len(current_chunk) + len(sentence) < max_length:
85
+ current_chunk += sentence + " "
86
+ else:
87
+ chunks.append(current_chunk.strip())
88
+ current_chunk = sentence + " "
89
+
90
+ if current_chunk:
91
+ chunks.append(current_chunk.strip())
92
+
93
+ return chunks
94
+
95
+ def get_best_answer(self, question: str, chunks: List[str]) -> Dict:
96
+ """
97
+ Obtém a melhor resposta considerando todos os chunks de texto
98
+ """
99
+ try:
100
+ answers = []
101
+ for chunk in chunks:
102
+ result = self.nlp(question=question, context=chunk)
103
+ answers.append(result)
104
+
105
+ # Ordenar por score
106
+ best_answer = max(answers, key=lambda x: x['score'])
107
+
108
+ return {
109
+ 'answer': best_answer['answer'],
110
+ 'score': best_answer['score'],
111
+ 'context': best_answer['context']
112
+ }
113
+ except Exception as e:
114
+ logger.error(f"Erro ao processar resposta: {e}")
115
+ return {'answer': "Desculpe, não consegui processar sua pergunta.", 'score': 0, 'context': ""}
116
+
117
+ def answer_question(self, pdf_file: gr.File, question: str) -> Dict:
118
+ """
119
+ Processa o PDF e responde à pergunta
120
+ """
121
+ try:
122
+ # Extrair texto do PDF
123
+ full_text, page_text = self.extract_text_from_pdf(pdf_file.name)
124
+
125
+ # Pré-processar texto
126
+ processed_text = self.preprocess_text(full_text)
127
+
128
+ # Dividir em chunks
129
+ chunks = self.split_into_chunks(processed_text)
130
+
131
+ # Obter melhor resposta
132
+ result = self.get_best_answer(question, chunks)
133
+
134
+ # Adicionar informações extras
135
+ result['confidence'] = f"{result['score']*100:.2f}%"
136
+
137
+ return result
138
+ except Exception as e:
139
+ logger.error(f"Erro ao processar pergunta: {e}")
140
+ return {
141
+ 'answer': "Ocorreu um erro ao processar sua pergunta.",
142
+ 'score': 0,
143
+ 'confidence': "0%",
144
+ 'context': ""
145
+ }
146
+
147
+ def create_interface():
148
+ qa_system = PDFQuestionAnswering()
149
+
150
+ # Interface mais elaborada com Gradio
151
+ with gr.Blocks(title="Sistema Avançado de QA sobre PDFs") as iface:
152
+ gr.Markdown("""
153
+ # Sistema de Perguntas e Respostas sobre PDFs
154
+
155
+ Este sistema utiliza um modelo de linguagem avançado para responder perguntas sobre documentos PDF.
156
+ Carregue um PDF e faça suas perguntas!
157
+ """)
158
+
159
+ with gr.Row():
160
+ with gr.Column():
161
+ pdf_input = gr.File(
162
+ label="Carregar PDF",
163
+ file_types=[".pdf"]
164
+ )
165
+ question_input = gr.Textbox(
166
+ label="Sua Pergunta",
167
+ placeholder="Digite sua pergunta aqui..."
168
+ )
169
+ submit_btn = gr.Button("Obter Resposta", variant="primary")
170
+
171
+ with gr.Column():
172
+ answer_output = gr.Textbox(label="Resposta")
173
+ confidence_output = gr.Textbox(label="Confiança da Resposta")
174
+ context_output = gr.Textbox(
175
+ label="Contexto da Resposta",
176
+ lines=5
177
+ )
178
+
179
+ def process_question(pdf, question):
180
+ result = qa_system.answer_question(pdf, question)
181
+ return (
182
+ result['answer'],
183
+ result['confidence'],
184
+ result['context']
185
+ )
186
+
187
+ submit_btn.click(
188
+ fn=process_question,
189
+ inputs=[pdf_input, question_input],
190
+ outputs=[answer_output, confidence_output, context_output]
191
+ )
192
+
193
+ gr.Markdown("""
194
+ ### Dicas de Uso
195
+ - Faça perguntas específicas e diretas
196
+ - O sistema funciona melhor com PDFs bem formatados
197
+ - A confiança indica o quanto o sistema está seguro da resposta
198
+ """)
199
+
200
+ return iface
201
+
202
+ if __name__ == "__main__":
203
+ # Criar e iniciar a interface
204
+ demo = create_interface()
205
+ demo.launch(share=True, debug=True)