Python PDF IA Local

Procesamiento completo de PDFs con Python: extracción, limpieza, traducción y exportación de imágenes

Construye una pipeline práctica para trabajar con documentos PDF: separa y guarda el texto por página, limpia saltos innecesarios, traduce de forma automática con Ollama y exporta todas las imágenes incrustadas.

Resumen

En este artículo implementamos una solución integral para procesar PDFs en cuatro etapas:

  1. Extracción de texto por página con PyPDF2.
  2. Limpieza de saltos de línea y normalización con re.
  3. Traducción del inglés al español usando Ollama y un modelo local (llama3.1:8b).
  4. Extracción de imágenes incrustadas con PyMuPDF / fitz.

Requisitos

pip install PyPDF2 pymupdf ollama

Además, instala y levanta Ollama y ten disponible el modelo llama3.1:8b.

Estructura de carpetas (resultado)

./paginas/              # Texto por página (crudo)
./paginas_limpias/      # Texto limpio
./paginas_traducidas/   # Texto traducido
./imagen_pdf/           # Imágenes extraídas

Índice

Paso 1 · Extraer texto con PyPDF2

Extraemos el texto de cada página y lo guardamos en archivos .txt independientes dentro de ./paginas.

import PyPDF2
import os


def crearTxt(numero: int, texto: str) -> bool:
    """
    Crea un archivo de texto con el contenido dado.

    Args:
        numero (int): El número de página para el nombre del archivo.
        texto (str): El texto a escribir en el archivo.

    Returns:
        bool: True si el archivo se creó correctamente.
    """
    with open(f'./paginas/{numero}.txt', 'w', encoding='utf-8') as f:
        f.write(texto)
    return True


def extraerTexto(pdf: str) -> str:
    """
    Extrae el texto de un archivo PDF y lo guarda en archivos de texto individuales.

    Args:
        pdf (str): La ruta al archivo PDF.

    Returns:
        str: El texto concatenado de todas las páginas del PDF.
    """
    texto = ''
    contador = 1
    with open(pdf, 'rb') as f:
        pdf_reader = PyPDF2.PdfReader(f)
        for page in pdf_reader.pages:
            texto_pagina = page.extract_text()
            crearTxt(contador, texto_pagina)
            texto += texto_pagina
            contador += 1
    return texto


def main():
    """
    Función principal del programa.
    Extrae el texto de un PDF y lo guarda en archivos de texto.
    """
    pdf = 'a-christmas-carol-charles-dickens.pdf'
    extraerTexto(pdf)


if __name__ == '__main__':
    main()

Salida esperada: archivos numerados 1.txt, 2.txt, … en ./paginas.

Paso 2 · Limpiar y normalizar texto

Eliminamos saltos de línea problemáticos y conservamos una versión más legible en ./paginas_limpias.

import os
import re

RUTA_ORIGEN = './paginas'
RUTA_DESTINO = './paginas_limpias'


os.makedirs(RUTA_DESTINO, exist_ok=True)


def guardarTexto(texto: str, nombre_archivo: str) -> None:
    """
    Guarda el texto en un archivo.

    Args:
        texto (str): El texto a guardar.
        nombre_archivo (str): El nombre del archivo.
    """
    with open(os.path.join(RUTA_DESTINO, nombre_archivo), 'w', encoding='utf-8') as f:
        f.write(texto)
def limparTexto(texto: str, file: str) -> None:
    """
    Limpia el texto eliminando saltos de línea innecesarios y guarda el resultado.

    Args:
        texto (str): El texto a limpiar.
        file (str): El nombre del archivo.
    """
    texto = re.sub(r" \n", " ", texto)
    guardarTexto(texto, file)


def main():
    """
    Función principal del programa.
    Recorre los archivos de texto en la ruta de origen, los limpia y los guarda en la ruta de destino.
    """
    for root, _, files in os.walk(RUTA_ORIGEN):
        for file in files:
            if file.endswith('.txt'):
                file_path = os.path.join(root, file)
                with open(file_path, 'r', encoding='utf-8') as f:
                    texto = f.read()
                    limparTexto(texto, file)


if __name__ == '__main__':
    main()

Salida esperada: mismos nombres de archivo, pero en ./paginas_limpias.

Paso 3 · Traducir con Ollama

Traducimos línea por línea usando el modelo local llama3.1:8b con Ollama, y guardamos el resultado en ./paginas_traducidas.

import os
import ollama

RUTA_ORIGEN = './paginas_limpias'
RUTA_DESTINO = './paginas_traducidas'

os.makedirs(RUTA_DESTINO, exist_ok=True)


def traducir(texto: str) -> str:
    """
    Traduce un texto del inglés al español utilizando el modelo de Ollama.

    Args:
        texto (str): El texto a traducir.

    Returns:
        str: El texto traducido.
    """
    response = ollama.chat(
        model='llama3.1:8b',
        messages=[
            {
                'role': 'user',
                'content': 'Te voy a proporciona un texto para traducir del ingles al espanol. Solo traduce. No respondas ni hagas comentarios. El texto es posible que contenga errores o fragmentos de codigo. En ese caso, ignora los mismos.' + texto,
            },
        ],
    )
    return response['message']['content']


def main():
    """
    Función principal del programa.
    Recorre los archivos de texto en la ruta de origen, los traduce y los guarda en la ruta de destino.
    """
    for root, _, files in os.walk(RUTA_ORIGEN):
        for file in files:
            texto_a_insertar = ""
            if file.endswith('.txt'):
                file_path = os.path.join(root, file)
                with open(file_path, 'r', encoding='utf-8') as f:
                    texto = f.readlines()
                    for linea in texto:
                        traduccion = traducir(linea)
                        texto_a_insertar += traduccion

                with open(os.path.join(RUTA_DESTINO, file), 'w', encoding='utf-8') as f:
                    f.write(texto_a_insertar)


if __name__ == '__main__':
    main()

Salida esperada: un archivo traducido por cada entrada en ./paginas_traducidas.

Paso 4 · Extraer imágenes con PyMuPDF (fitz)

Exportamos todas las imágenes incrustadas del PDF a .png, guardándolas en ./imagen_pdf.

import fitz
import os

RUTA_DESTINO_IMAGENES = './imagen_pdf'

os.makedirs(RUTA_DESTINO_IMAGENES, exist_ok=True)


def extraerImagenesPdf(pdf: str) -> None:
    """
    Extrae las imágenes de un archivo PDF y las guarda como archivos PNG.

    Args:
        pdf (str): La ruta al archivo PDF.
    """
    pdf_document = fitz.open(pdf)
    for page_index in range(len(pdf_document)):
        page = pdf_document[page_index]
        image_list = page.get_images()
        for image_index, img in enumerate(image_list, start=1):
            xref = img[0]
            base_image = pdf_document.extract_image(xref)
            image_data = base_image["image"]
            if len(image_list) > 1:
                nombre_archivo = f"imagen_{page_index}_{image_index}.png"
            else:
                nombre_archivo = f"imagen_{page_index}.png"
            ruta_archivo = os.path.join(RUTA_DESTINO_IMAGENES, nombre_archivo)
            with open(ruta_archivo, "wb") as fp:
                fp.write(image_data)


def main():
    """
    Función principal del programa.
    Extrae las imágenes de un PDF específico.
    """
    extraerImagenesPdf("Deep Reinforcement Learning with Python (2024).pdf")


if __name__ == "__main__":
    main()

Salida esperada: un conjunto de archivos PNG por cada página o imagen encontrada.

Mejoras y buenas prácticas

Repositorio del proyecto en GitHub