|
|
import gradio as gr |
|
|
import requests |
|
|
import fitz |
|
|
from fpdf import FPDF |
|
|
import os |
|
|
import tempfile |
|
|
import math |
|
|
|
|
|
|
|
|
MODEL_ID = "sshleifer/distilbart-cnn-12-6" |
|
|
API_URL = f"https://api-inference.huggingface.co/models/{MODEL_ID}" |
|
|
HF_API_TOKEN = os.environ.get("HF_API_TOKEN") |
|
|
|
|
|
|
|
|
|
|
|
def extract_text_from_pdf(pdf_file): |
|
|
"""Extract text from uploaded PDF file.""" |
|
|
try: |
|
|
doc = fitz.open(stream=pdf_file.read(), filetype="pdf") |
|
|
full_text = "" |
|
|
for page in doc: |
|
|
full_text += page.get_text() |
|
|
doc.close() |
|
|
return full_text.strip() |
|
|
except Exception as e: |
|
|
raise gr.Error(f"Failed to read PDF. Is it valid? Error: {e}") |
|
|
|
|
|
def chunk_text(text, max_tokens=1000): |
|
|
"""Split text into chunks of approximately max_tokens words.""" |
|
|
words = text.split() |
|
|
for i in range(0, len(words), max_tokens): |
|
|
yield " ".join(words[i:i+max_tokens]) |
|
|
|
|
|
def summarize_text(text_to_summarize): |
|
|
"""Send text to Hugging Face API for summarization, chunking if too long.""" |
|
|
if not HF_API_TOKEN: |
|
|
raise gr.Error("Hugging Face API token is not set. Add it as an environment variable.") |
|
|
|
|
|
headers = {"Authorization": f"Bearer {HF_API_TOKEN}"} |
|
|
final_summary = [] |
|
|
|
|
|
for chunk in chunk_text(text_to_summarize, max_tokens=500): |
|
|
payload = { |
|
|
"inputs": chunk, |
|
|
"parameters": {"min_length": 50, "max_length": 250, "do_sample": False} |
|
|
} |
|
|
response = requests.post(API_URL, headers=headers, json=payload) |
|
|
if response.status_code == 200: |
|
|
final_summary.append(response.json()[0]["summary_text"]) |
|
|
else: |
|
|
error_details = response.json().get('error', response.text) |
|
|
raise gr.Error(f"Model API Error: {error_details}") |
|
|
|
|
|
return " ".join(final_summary) |
|
|
|
|
|
def save_text_to_pdf(text): |
|
|
"""Save summarized text to a new PDF and return its path.""" |
|
|
pdf = FPDF() |
|
|
pdf.add_page() |
|
|
pdf.set_font("Arial", "B", 16) |
|
|
pdf.cell(0, 10, "Tweaked Document Summary", ln=1, align='C') |
|
|
pdf.ln(10) |
|
|
|
|
|
pdf.set_font("Arial", size=12) |
|
|
cleaned_text = text.encode('latin-1', 'replace').decode('latin-1') |
|
|
pdf.multi_cell(0, 10, cleaned_text) |
|
|
|
|
|
tmp_file = tempfile.NamedTemporaryFile(delete=False, suffix=".pdf") |
|
|
pdf.output(tmp_file.name) |
|
|
tmp_file.close() |
|
|
return tmp_file.name |
|
|
|
|
|
|
|
|
|
|
|
def tweak_pdf_workflow(uploaded_pdf): |
|
|
if uploaded_pdf is None: |
|
|
raise gr.Error("Please upload a PDF first.") |
|
|
|
|
|
|
|
|
original_text = extract_text_from_pdf(uploaded_pdf) |
|
|
if not original_text.strip(): |
|
|
raise gr.Error("PDF contains no extractable text.") |
|
|
|
|
|
|
|
|
tweaked_text = summarize_text(original_text) |
|
|
|
|
|
|
|
|
output_pdf_path = save_text_to_pdf(tweaked_text) |
|
|
return output_pdf_path |
|
|
|
|
|
|
|
|
|
|
|
with gr.Blocks(theme=gr.themes.Soft()) as iface: |
|
|
gr.Markdown( |
|
|
""" |
|
|
# 📄 PDF Document Tweaker (TL;DR) |
|
|
Upload a PDF and get a summarized, tweaked PDF using Hugging Face's `distilbart-cnn-12-6`. |
|
|
""" |
|
|
) |
|
|
with gr.Row(): |
|
|
pdf_input = gr.File(label="Upload Your PDF", file_types=[".pdf"]) |
|
|
pdf_output = gr.File(label="Download Tweaked PDF") |
|
|
submit_button = gr.Button("Tweak My Document!", variant="primary") |
|
|
submit_button.click(fn=tweak_pdf_workflow, inputs=pdf_input, outputs=pdf_output) |
|
|
|
|
|
if __name__ == "__main__": |
|
|
iface.launch(server_name="0.0.0.0", server_port=7860) |
|
|
|