File size: 7,174 Bytes
9634b36 c7a5739 9634b36 b3bb65b ad0b1f7 7998543 9323459 b3bb65b 69c287e c7a5739 b3bb65b 7998543 06449e7 b3bb65b 69c287e b3bb65b c7a5739 06449e7 7998543 c7a5739 b3bb65b c7a5739 b3bb65b 7998543 c7a5739 b3bb65b 9433534 b3bb65b 9433534 b3bb65b c8cd30b 9433534 b3bb65b c7a5739 06449e7 b3bb65b c7a5739 43a7a2a 69c287e 43a7a2a 69c287e 43a7a2a 69c287e 43a7a2a 69c287e 43a7a2a 69c287e 43a7a2a 69c287e |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 |
import gradio as gr
import pandas as pd
import fitz # PyMuPDF
import os
import re
from huggingface_hub import HfApi
from huggingface_hub.utils import HfHubHTTPError
import time
def extract_full_paper_with_labels(pdf_path, progress=None):
print(f"📝 Starting PDF Processing: {os.path.basename(pdf_path)}")
doc = fitz.open(pdf_path)
content = ""
# Initialize metadata
title = ""
authors = ""
year = ""
doi = ""
abstract = ""
footnotes = ""
references = ""
sources = ""
total_pages = len(doc)
max_iterations = total_pages * 2 # To prevent infinite loops
iteration_count = 0
# Regex patterns for detection
doi_pattern = r"\b10\.\d{4,9}/[-._;()/:A-Z0-9]+\b"
year_pattern = r'\b(19|20)\d{2}\b'
code_pattern = r"(def\s+\w+\s*\(|class\s+\w+|import\s+\w+|for\s+\w+\s+in|if\s+\w+|while\s+\w+|try:|except|{|}|;)"
reference_keywords = ['reference', 'bibliography', 'sources']
financial_keywords = ['p/e', 'volatility', 'market cap', 'roi', 'sharpe', 'drawdown']
for page_num, page in enumerate(doc):
iteration_count += 1
if iteration_count > max_iterations:
raise Exception("⚠️ PDF processing exceeded iteration limit. Possible malformed PDF.")
if progress is not None:
progress((page_num + 1) / total_pages, desc=f"Processing Page {page_num + 1}/{total_pages}")
blocks = page.get_text("dict")["blocks"]
for block in blocks:
if "lines" in block:
text = ""
max_font_size = 0
for line in block["lines"]:
for span in line["spans"]:
text += span["text"] + " "
if span["size"] > max_font_size:
max_font_size = span["size"]
text = text.strip()
# Title (First Page, Largest Font)
if page_num == 0 and max_font_size > 15 and not title:
title = text
content += f"<TITLE>{title}</TITLE>\n"
# Authors
elif re.search(r'author|by', text, re.IGNORECASE) and not authors:
authors = text
content += f"<AUTHORS>{authors}</AUTHORS>\n"
# Year
elif re.search(year_pattern, text) and not year:
year = re.search(year_pattern, text).group(0)
content += f"<YEAR>{year}</YEAR>\n"
# DOI
elif re.search(doi_pattern, text) and not doi:
doi = re.search(doi_pattern, text).group(0)
content += f"<DOI>{doi}</DOI>\n"
# Abstract
elif "abstract" in text.lower() and not abstract:
abstract = text
content += f"<ABSTRACT>{abstract}</ABSTRACT>\n"
# Footnotes (small fonts)
elif max_font_size < 10:
footnotes += text + " "
# References
elif any(keyword in text.lower() for keyword in reference_keywords):
references += text + " "
# Tables
elif re.search(r"table\s*\d+", text, re.IGNORECASE):
content += f"<TABLE>{text}</TABLE>\n"
# Figures
elif re.search(r"figure\s*\d+", text, re.IGNORECASE):
content += f"<FIGURE>{text}</FIGURE>\n"
# Equations (look for math symbols)
elif re.search(r"=|∑|√|±|×|π|μ|σ", text):
content += f"<EQUATION>{text}</EQUATION>\n"
# ✅ Improved Code Block Detection
elif re.search(code_pattern, text) and len(text.split()) <= 50:
content += f"<CODE>{text}</CODE>\n"
# Financial Metrics
elif any(fin_kw in text.lower() for fin_kw in financial_keywords):
content += f"<FINANCIAL_METRIC>{text}</FINANCIAL_METRIC>\n"
# Regular Paragraph
else:
content += f"<PARAGRAPH>{text}</PARAGRAPH>\n"
# Append Footnotes and References
if footnotes:
content += f"<FOOTNOTE>{footnotes.strip()}</FOOTNOTE>\n"
if references:
content += f"<REFERENCE>{references.strip()}</REFERENCE>\n"
print(f"✅ Finished Processing PDF: {os.path.basename(pdf_path)}")
return {
"filename": os.path.basename(pdf_path),
"content": content
}
def process_pdf_file(pdf_file, api_key, repo_address):
if pdf_file is None:
return None, "No PDF file uploaded."
# Extract content from PDF.
# pdf_file can be a file-like object or a dict depending on how Gradio returns it.
file_path = pdf_file.name if hasattr(pdf_file, "name") else pdf_file['name']
result = extract_full_paper_with_labels(file_path)
# Convert the result dictionary into a DataFrame and write it to a parquet file.
df = pd.DataFrame([result])
base = os.path.splitext(result['filename'])[0]
parquet_filename = f"{base}.parquet"
df.to_parquet(parquet_filename, index=False)
repo_status = ""
# If API key and repo address are provided, attempt to upload the parquet file.
if api_key and repo_address:
api = HfApi()
try:
api.upload_file(
path_or_fileobj=parquet_filename,
path_in_repo=parquet_filename,
repo_id=repo_address,
token=api_key
)
repo_status = f"File uploaded to repo {repo_address} successfully."
except Exception as e:
repo_status = f"Failed to upload to repo: {str(e)}"
else:
repo_status = "API key or repo address not provided, skipping repo upload."
# Return the parquet file for local download and the status message.
return parquet_filename, repo_status
# Function to clear only file-related inputs/outputs, preserving the API key and repo address.
def clear_files():
return None, None, ""
# Gradio interface setup
with gr.Blocks() as demo:
with gr.Row():
api_key_input = gr.Textbox(label="API Key", placeholder="Enter API Key")
repo_address_input = gr.Textbox(label="Repo Address", placeholder="Enter Repo Address")
with gr.Row():
pdf_file_input = gr.File(label="Upload PDF")
convert_button = gr.Button("Convert to Parquet")
clear_button = gr.Button("Clear Files")
with gr.Row():
download_file_output = gr.File(label="Download Parquet File")
repo_status_output = gr.Textbox(label="Repo Upload Status")
convert_button.click(
process_pdf_file,
inputs=[pdf_file_input, api_key_input, repo_address_input],
outputs=[download_file_output, repo_status_output]
)
# The clear button now only clears file-related components; API key and Repo Address remain unchanged.
clear_button.click(
clear_files,
inputs=None,
outputs=[pdf_file_input, download_file_output, repo_status_output]
)
demo.launch()
|