Spaces:
Running
Running
File size: 6,234 Bytes
40a6f2f |
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 190 191 192 |
import gradio as gr
import os
import shutil
import fitz
from PIL import Image
import numpy as np
import cv2
import pytesseract
from pytesseract import Output
import zipfile
from pdf2image import convert_from_path
# [Keep all the helper functions from the original code]
def convert_to_rgb(image_path):
img = Image.open(image_path)
rgb_img = img.convert("RGB")
return rgb_img
def preprocess_image(image):
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
_, binary = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
denoised = cv2.fastNlMeansDenoising(binary, None, 30, 7, 21)
resized = cv2.resize(denoised, None, fx=2, fy=2, interpolation=cv2.INTER_CUBIC)
return resized
def extract_vertical_blocks(image):
image_np = np.array(image)
data = pytesseract.image_to_data(image_np, lang='fra', output_type=Output.DICT)
blocks = []
current_block = ""
current_block_coords = [float('inf'), float('inf'), 0, 0]
last_bottom = -1
line_height = 0
for i in range(len(data['text'])):
if int(data['conf'][i]) > 0:
text = data['text'][i]
x, y, w, h = data['left'][i], data['top'][i], data['width'][i], data['height'][i]
if line_height == 0:
line_height = h * 1.2
if y > last_bottom + line_height:
if current_block:
blocks.append({
"text": current_block.strip(),
"coords": current_block_coords
})
current_block = ""
current_block_coords = [float('inf'), float('inf'), 0, 0]
current_block += text + " "
current_block_coords[0] = min(current_block_coords[0], x)
current_block_coords[1] = min(current_block_coords[1], y)
current_block_coords[2] = max(current_block_coords[2], x + w)
current_block_coords[3] = max(current_block_coords[3], y + h)
last_bottom = y + h
if current_block:
blocks.append({
"text": current_block.strip(),
"coords": current_block_coords
})
return blocks
def draw_blocks_on_image(image_path, blocks, output_path):
image = cv2.imread(image_path)
for block in blocks:
coords = block['coords']
cv2.rectangle(image, (coords[0], coords[1]), (coords[2], coords[3]), (0, 0, 255), 2)
cv2.imwrite(output_path, image)
return output_path
def process_image(image, output_folder, page_number):
image = convert_to_rgb(image)
blocks = extract_vertical_blocks(image)
base_name = f'page_{page_number + 1}.png'
image_path = os.path.join(output_folder, base_name)
image.save(image_path)
annotated_image_path = os.path.join(output_folder, f'annotated_{base_name}')
annotated_image_path = draw_blocks_on_image(image_path, blocks, annotated_image_path)
return blocks, annotated_image_path
def save_extracted_text(blocks, page_number, output_folder):
text_file_path = os.path.join(output_folder, 'extracted_text.txt')
with open(text_file_path, 'a', encoding='utf-8') as f:
f.write(f"[PAGE {page_number}]\n")
for block in blocks:
f.write(block['text'] + "\n")
f.write(f"[FIN DE PAGE {page_number}]\n\n")
return text_file_path
# Modified process_pdf function with better temp file handling
def process_pdf(pdf_file):
# Create unique temporary working directory
temp_dir = os.path.join(os.getcwd(), "temp_processing")
output_dir = os.path.join(temp_dir, 'output_images')
# Clean up any existing temp directories
if os.path.exists(temp_dir):
shutil.rmtree(temp_dir)
os.makedirs(output_dir, exist_ok=True)
try:
# Convert PDF to images
images = convert_from_path(pdf_file.name)
# Process each image
annotated_images = []
for i, img in enumerate(images):
# Save temporary image
temp_img_path = os.path.join(temp_dir, f'temp_page_{i}.png')
img.save(temp_img_path)
# Process the image
blocks, annotated_image_path = process_image(temp_img_path, output_dir, i)
annotated_images.append(annotated_image_path)
save_extracted_text(blocks, i + 1, output_dir)
# Create ZIP file of annotated images
zip_path = os.path.join(temp_dir, "annotated_images.zip")
with zipfile.ZipFile(zip_path, 'w') as zipf:
for img_path in annotated_images:
zipf.write(img_path, os.path.basename(img_path))
# Get the text file
text_file_path = os.path.join(output_dir, 'extracted_text.txt')
# Read the files into memory before cleanup
with open(text_file_path, 'rb') as f:
text_content = f.read()
with open(zip_path, 'rb') as f:
zip_content = f.read()
return (text_file_path, zip_path)
except Exception as e:
raise gr.Error(f"Error processing PDF: {str(e)}")
finally:
# Clean up will be handled by Hugging Face Spaces
pass
# Create Gradio interface with theme and better styling
css = """
.gradio-container {
font-family: 'IBM Plex Sans', sans-serif;
}
.gr-button {
color: white;
border-radius: 8px;
background: linear-gradient(45deg, #7928CA, #FF0080);
border: none;
}
"""
# Create Gradio interface
demo = gr.Interface(
fn=process_pdf,
inputs=[
gr.File(
label="Upload PDF Document",
file_types=[".pdf"],
type="filepath"
)
],
outputs=[
gr.File(label="Extracted Text (TXT)"),
gr.File(label="Annotated Images (ZIP)")
],
title="PDF Text Extraction and Annotation",
description="""
Upload a PDF document to:
1. Extract text content
2. Get annotated images showing detected text blocks
Supports multiple pages and French language text.
""",
article="Created by [Your Name] - [Your GitHub/Profile Link]",
css=css,
examples=[], # Add example PDFs if you have any
cache_examples=False,
theme=gr.themes.Soft()
)
# Launch the app
if __name__ == "__main__":
demo.launch() |