UseCase2 / app.py
DSatishchandra's picture
Create app.py
aca64a8 verified
Raw
History Blame Contribute Delete
6.3 kB
import streamlit as st
import fitz # PyMuPDF
from PIL import Image, ImageDraw, ImageFont
import difflib
from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import letter
import tempfile
import os
from io import BytesIO
# Load a standard font for annotations
font_path = "/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf"
font_size = 10 # Reduced size for better CPU performance
font = ImageFont.truetype(font_path, font_size)
def load_and_compare_documents(file1, file2):
file1_content = file1.read()
file2_content = file2.read()
# Convert PDFs to images
images1 = pdf_to_images(file1_content)
images2 = pdf_to_images(file2_content)
# Perform text comparison
text1 = extract_text_from_pdf(file1_content)
text2 = extract_text_from_pdf(file2_content)
differences = compare_texts(text1, text2)
# Annotate differences on images
marked_images_1, marked_images_2 = annotate_images(images1, images2, differences)
# Generate the output PDF
pdf_buffer = create_pdf_with_side_by_side(marked_images_1, marked_images_2, differences)
overall_summary = generate_overall_summary(differences)
return pdf_buffer, overall_summary
def pdf_to_images(file_content):
"""Converts each page of the PDF into a medium-resolution image for CPU efficiency."""
images = []
pdf_document = fitz.open(stream=file_content, filetype="pdf")
for page in pdf_document:
pix = page.get_pixmap(dpi=200) # Lower DPI for faster processing
img = Image.frombytes("RGB", [pix.width, pix.height], pix.samples)
images.append(img)
pdf_document.close()
return images
def extract_text_from_pdf(file_content):
"""Extracts text content from the PDF."""
pdf_document = fitz.open(stream=file_content, filetype="pdf")
text = [page.get_text("text") for page in pdf_document]
pdf_document.close()
return text
def compare_texts(text1, text2):
"""Compares text content and generates differences."""
differences = []
position_counter = 1
for page_num, (page1, page2) in enumerate(zip(text1, text2), start=1):
diff = list(difflib.ndiff(page1.splitlines(), page2.splitlines()))
page_diffs = []
for change in diff:
if change.startswith("+ ") or change.startswith("- "):
change_type = "Added" if change.startswith("+ ") else "Deleted"
value = change[2:]
description = f"'{value}' {change_type.lower()} at position {position_counter}"
page_diffs.append({"type": change_type, "value": value, "index": position_counter, "description": description})
position_counter += 1
differences.append({"page": page_num, "differences": page_diffs})
return differences
def annotate_images(images1, images2, differences):
"""Annotates differences on the images."""
marked_images_1 = {}
marked_images_2 = {}
for page_num, (img1, img2) in enumerate(zip(images1, images2), start=1):
draw1 = ImageDraw.Draw(img1)
draw2 = ImageDraw.Draw(img2)
for diff in differences[page_num - 1]["differences"]:
value = diff["value"]
position = diff["index"]
# Annotate differences
draw2.text((10, 10 + position * 15), f"{position}: {value}", fill="blue", font=font)
draw2.rectangle([10, 10 + position * 15, 200, 30 + position * 15], outline="red", width=2)
marked_images_1[page_num] = img1
marked_images_2[page_num] = img2
return marked_images_1, marked_images_2
def create_pdf_with_side_by_side(marked_images_1, marked_images_2, differences):
"""Generates a PDF with side-by-side comparison and observation summary."""
pdf_buffer = BytesIO()
c = canvas.Canvas(pdf_buffer, pagesize=(letter[0] * 2, letter[1]))
for page_num, img1 in marked_images_1.items():
img2 = marked_images_2[page_num]
with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as temp_img_file1:
img1.save(temp_img_file1, format="PNG")
temp_img_path1 = temp_img_file1.name
with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as temp_img_file2:
img2.save(temp_img_file2, format="PNG")
temp_img_path2 = temp_img_file2.name
c.drawImage(temp_img_path1, 0, 0, width=letter[0], height=letter[1])
c.drawImage(temp_img_path2, letter[0], 0, width=letter[0], height=letter[1])
c.showPage()
os.remove(temp_img_path1)
os.remove(temp_img_path2)
y_position = 750
c.drawString(10, y_position, f"Observation Summary for Page {page_num}:")
y_position -= 20
for diff in differences[page_num - 1]["differences"]:
text = diff["description"]
c.drawString(10, y_position, text)
y_position -= 15
if y_position < 50:
c.showPage()
y_position = 750
c.showPage()
c.save()
pdf_buffer.seek(0)
return pdf_buffer
def generate_overall_summary(differences):
"""Generates a summary of additions and deletions."""
total_additions = sum(len([d for d in diff["differences"] if d["type"] == "Added"]) for diff in differences)
total_deletions = sum(len([d for d in diff["differences"] if d["type"] == "Deleted"]) for diff in differences)
return {"total_additions": total_additions, "total_deletions": total_deletions}
def main():
st.title("PDF Comparison Tool with Annotations (CPU-Optimized)")
st.write("Upload PDFs for side-by-side comparison and observation summary.")
file1 = st.file_uploader("Document 1 (PDF only)", type=["pdf"])
file2 = st.file_uploader("Document 2 (PDF only)", type=["pdf"])
if st.button("Compare Documents") and file1 and file2:
pdf_buffer, overall_summary = load_and_compare_documents(file1, file2)
st.subheader("Overall Summary")
for key, value in overall_summary.items():
st.write(f"{key.replace('_', ' ').capitalize()}: {value}")
st.subheader("Download Comparison PDF")
st.download_button("Download PDF", data=pdf_buffer, file_name="comparison_with_summary.pdf", mime="application/pdf")
if __name__ == "__main__":
main()