fccoelho aider (anthropic/claude-sonnet-4-20250514) commited on
Commit
64597df
·
1 Parent(s): 32d9fa7

feat: adicionar extração de referências por regex e segunda tabela

Browse files

Co-authored-by: aider (anthropic/claude-sonnet-4-20250514) <aider@aider.chat>

Files changed (1) hide show
  1. app.py +119 -13
app.py CHANGED
@@ -116,36 +116,131 @@ def extract_references_with_llm(text, model_name):
116
  except Exception as e:
117
  return [{"error": f"Erro ao processar com LLM ({model_name}): {str(e)}"}]
118
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
119
  def process_pdf(pdf_file, model_name):
120
  """Função principal que processa o PDF e retorna resultados"""
121
  if pdf_file is None:
122
- return {"error": "Nenhum arquivo enviado"}, pd.DataFrame()
123
 
124
  # Extrair texto do PDF
125
  text, metadata = extract_pdf_text(pdf_file)
126
 
127
  if text is None:
128
- return metadata, pd.DataFrame()
129
 
130
  # Adicionar modelo selecionado aos metadados
131
  metadata["modelo_usado"] = model_name
132
 
133
  # Extrair referências com LLM
134
- references = extract_references_with_llm(text, model_name)
 
 
 
 
 
 
 
 
 
135
 
136
- # Converter para DataFrame
137
- if references and not any("error" in ref for ref in references):
138
- df = pd.DataFrame(references)
139
  else:
140
- df = pd.DataFrame({"Erro": ["Não foi possível extrair referências"]})
141
 
142
- return metadata, df
 
 
 
 
 
 
143
 
144
  def create_interface():
145
  """Cria a interface Gradio"""
146
  with gr.Blocks(title="Extrator de Referências") as interface:
147
  gr.Markdown("# 📚 Extrator de Referências de Artigos Científicos")
148
- gr.Markdown("Faça upload de um PDF de artigo científico para extrair automaticamente a lista de referências.")
149
 
150
  with gr.Row():
151
  with gr.Column():
@@ -171,22 +266,33 @@ def create_interface():
171
 
172
  extract_btn = gr.Button("🔍 Extrair Referências", variant="primary")
173
 
 
 
 
174
  with gr.Row():
175
  with gr.Column():
176
- metadata_output = gr.JSON(label="📋 Metadados do Artigo")
 
 
 
 
 
 
177
  with gr.Column():
178
- references_output = gr.Dataframe(
179
- label="📖 Lista de Referências",
180
  row_count=(10,'dynamic'),
181
  show_copy_button=True,
182
  show_fullscreen_button=True,
183
  wrap=True
184
  )
185
 
 
 
186
  extract_btn.click(
187
  process_pdf,
188
  inputs=[pdf_input, model_dropdown],
189
- outputs=[metadata_output, references_output]
190
  )
191
 
192
  return interface
 
116
  except Exception as e:
117
  return [{"error": f"Erro ao processar com LLM ({model_name}): {str(e)}"}]
118
 
119
+ def extract_references_with_regex(text):
120
+ """Extrai referências usando expressões regulares"""
121
+ try:
122
+ # Encontrar a seção de referências
123
+ references_section = ""
124
+
125
+ # Padrões para identificar início da seção de referências
126
+ ref_patterns = [
127
+ r'(?i)references?\s*\n',
128
+ r'(?i)bibliography\s*\n',
129
+ r'(?i)literatura\s+citada\s*\n',
130
+ r'(?i)referências\s+bibliográficas\s*\n'
131
+ ]
132
+
133
+ for pattern in ref_patterns:
134
+ match = re.search(pattern, text)
135
+ if match:
136
+ references_section = text[match.end():]
137
+ break
138
+
139
+ if not references_section:
140
+ # Se não encontrou seção específica, usar últimos 30% do texto
141
+ references_section = text[int(len(text) * 0.7):]
142
+
143
+ # Padrões para extrair referências individuais
144
+ # Padrão básico: Autor(es). (Ano). Título. Journal/Editora.
145
+ ref_pattern = r'([A-Z][^.]*?)\.\s*\((\d{4})\)\.\s*([^.]+)\.\s*([^.]+?)(?:\.|$)'
146
+
147
+ # Padrão alternativo para referências numeradas
148
+ numbered_pattern = r'\[\d+\]\s*([A-Z][^.]*?)\.\s*\((\d{4})\)\.\s*([^.]+)\.\s*([^.]+?)(?:\.|$)'
149
+
150
+ # Padrão para referências com formato diferente
151
+ alt_pattern = r'([A-Z][A-Za-z\s,&]+)\s+\((\d{4})\)[.,]\s*([^.]+)[.,]\s*([^.]+?)(?:\.|$)'
152
+
153
+ references = []
154
+
155
+ # Tentar diferentes padrões
156
+ for pattern in [ref_pattern, numbered_pattern, alt_pattern]:
157
+ matches = re.findall(pattern, references_section, re.MULTILINE | re.DOTALL)
158
+
159
+ for match in matches:
160
+ if len(match) >= 4:
161
+ # Limpar e processar os dados extraídos
162
+ authors = match[0].strip()
163
+ year = match[1].strip()
164
+ title = match[2].strip()
165
+ journal = match[3].strip()
166
+
167
+ # Extrair DOI se presente
168
+ doi_match = re.search(r'doi[:\s]*([^\s]+)', journal, re.IGNORECASE)
169
+ doi = doi_match.group(1) if doi_match else ""
170
+
171
+ # Extrair volume e páginas
172
+ vol_pages_match = re.search(r'(\d+)\s*\(?\d*\)?\s*[,:]\s*(\d+[-–]\d+)', journal)
173
+ volume = vol_pages_match.group(1) if vol_pages_match else ""
174
+ pages = vol_pages_match.group(2) if vol_pages_match else ""
175
+
176
+ references.append({
177
+ "authors": authors,
178
+ "title": title,
179
+ "journal": journal,
180
+ "year": year,
181
+ "volume": volume,
182
+ "pages": pages,
183
+ "doi": doi
184
+ })
185
+
186
+ # Remover duplicatas baseadas no título
187
+ seen_titles = set()
188
+ unique_references = []
189
+ for ref in references:
190
+ title_key = ref["title"].lower().strip()
191
+ if title_key not in seen_titles and len(title_key) > 10:
192
+ seen_titles.add(title_key)
193
+ unique_references.append(ref)
194
+
195
+ return unique_references[:50] # Limitar a 50 referências para evitar ruído
196
+
197
+ except Exception as e:
198
+ return [{"error": f"Erro na extração por regex: {str(e)}"}]
199
+
200
  def process_pdf(pdf_file, model_name):
201
  """Função principal que processa o PDF e retorna resultados"""
202
  if pdf_file is None:
203
+ return {"error": "Nenhum arquivo enviado"}, pd.DataFrame(), pd.DataFrame(), "❌ Nenhum arquivo enviado"
204
 
205
  # Extrair texto do PDF
206
  text, metadata = extract_pdf_text(pdf_file)
207
 
208
  if text is None:
209
+ return metadata, pd.DataFrame(), pd.DataFrame(), "❌ Erro ao processar PDF"
210
 
211
  # Adicionar modelo selecionado aos metadados
212
  metadata["modelo_usado"] = model_name
213
 
214
  # Extrair referências com LLM
215
+ llm_references = extract_references_with_llm(text, model_name)
216
+
217
+ # Extrair referências com Regex
218
+ regex_references = extract_references_with_regex(text)
219
+
220
+ # Converter para DataFrames
221
+ if llm_references and not any("error" in ref for ref in llm_references):
222
+ llm_df = pd.DataFrame(llm_references)
223
+ else:
224
+ llm_df = pd.DataFrame({"Erro": ["Não foi possível extrair referências com LLM"]})
225
 
226
+ if regex_references and not any("error" in ref for ref in regex_references):
227
+ regex_df = pd.DataFrame(regex_references)
 
228
  else:
229
+ regex_df = pd.DataFrame({"Erro": ["Não foi possível extrair referências com Regex"]})
230
 
231
+ # Criar status
232
+ llm_count = len(llm_references) if llm_references and not any("error" in ref for ref in llm_references) else 0
233
+ regex_count = len(regex_references) if regex_references and not any("error" in ref for ref in regex_references) else 0
234
+
235
+ status = f"📊 **Resultados da Extração:**\n- LLM ({model_name}): {llm_count} referências\n- Regex: {regex_count} referências"
236
+
237
+ return metadata, llm_df, regex_df, status
238
 
239
  def create_interface():
240
  """Cria a interface Gradio"""
241
  with gr.Blocks(title="Extrator de Referências") as interface:
242
  gr.Markdown("# 📚 Extrator de Referências de Artigos Científicos")
243
+ gr.Markdown("Faça upload de um PDF de artigo científico para extrair automaticamente a lista de referências usando IA e expressões regulares.")
244
 
245
  with gr.Row():
246
  with gr.Column():
 
266
 
267
  extract_btn = gr.Button("🔍 Extrair Referências", variant="primary")
268
 
269
+ with gr.Row():
270
+ metadata_output = gr.JSON(label="📋 Metadados do Artigo")
271
+
272
  with gr.Row():
273
  with gr.Column():
274
+ llm_references_output = gr.Dataframe(
275
+ label="🤖 Referências Extraídas por IA",
276
+ row_count=(10,'dynamic'),
277
+ show_copy_button=True,
278
+ show_fullscreen_button=True,
279
+ wrap=True
280
+ )
281
  with gr.Column():
282
+ regex_references_output = gr.Dataframe(
283
+ label="🔍 Referências Extraídas por Regex",
284
  row_count=(10,'dynamic'),
285
  show_copy_button=True,
286
  show_fullscreen_button=True,
287
  wrap=True
288
  )
289
 
290
+ status_output = gr.Markdown(label="📊 Status da Extração")
291
+
292
  extract_btn.click(
293
  process_pdf,
294
  inputs=[pdf_input, model_dropdown],
295
+ outputs=[metadata_output, llm_references_output, regex_references_output, status_output]
296
  )
297
 
298
  return interface