147 lines
5.7 KiB
Python
147 lines
5.7 KiB
Python
|
import pandas as pd
|
||
|
import os
|
||
|
import logging
|
||
|
import json
|
||
|
import PyLibrary.funciones_comunes as fc
|
||
|
from openai import OpenAI
|
||
|
from openai_api_key import openai_api_key
|
||
|
|
||
|
# Definir el logger a nivel de módulo
|
||
|
logger = None
|
||
|
|
||
|
def corregir_texto_batch(text_pairs, logger):
|
||
|
"""
|
||
|
Corrige errores de OCR en lotes de pares de texto usando GPT-4.
|
||
|
Cada par consiste en dos versiones del mismo texto en diferentes idiomas.
|
||
|
|
||
|
Args:
|
||
|
text_pairs: Lista de tuplas (texto1, texto2) donde cada texto es una lectura OCR
|
||
|
logger: Logger para registrar el proceso
|
||
|
"""
|
||
|
client = OpenAI(api_key=openai_api_key())
|
||
|
|
||
|
system_prompt = """You are an OCR correction specialist. For each pair of texts, which are OCR readings of the same text in different languages, analyze and correct any obvious OCR errors.
|
||
|
Pay special attention to:
|
||
|
- Incorrectly joined words (missing spaces)
|
||
|
- Wrong character recognition (0 vs O, 1 vs I, etc.)
|
||
|
- Extra or missing characters
|
||
|
Return the corrected versions maintaining the general structure and meaning.
|
||
|
|
||
|
Input format: List of text pairs
|
||
|
Expected output format: List of corrected pairs in the same order
|
||
|
Example input: [["PULSANTE DI STARTNASTRI", "START PUSHBUTTONTTOP"]]
|
||
|
Example output: [["PULSANTE DI START NASTRI", "START PUSH BUTTON TOP"]]"""
|
||
|
|
||
|
try:
|
||
|
# Convertir los pares de texto a formato JSON
|
||
|
request_payload = json.dumps({"pairs": text_pairs})
|
||
|
logger.info(f"Solicitando corrección para el lote de textos:\n{request_payload}")
|
||
|
|
||
|
response = client.chat.completions.create(
|
||
|
model="gpt-4",
|
||
|
messages=[
|
||
|
{"role": "system", "content": system_prompt},
|
||
|
{"role": "user", "content": request_payload},
|
||
|
],
|
||
|
max_tokens=2000,
|
||
|
temperature=0.3,
|
||
|
)
|
||
|
|
||
|
# Procesar la respuesta
|
||
|
corrections = json.loads(response.choices[0].message.content)
|
||
|
logger.info(f"Correcciones recibidas:\n{corrections}")
|
||
|
return corrections["pairs"]
|
||
|
except Exception as e:
|
||
|
logger.error(f"Error en la corrección por lotes: {str(e)}")
|
||
|
return None
|
||
|
|
||
|
def procesar_archivo(config, archivo_entrada):
|
||
|
"""
|
||
|
Procesa el archivo Excel con los textos OCR y genera un nuevo archivo con las correcciones.
|
||
|
"""
|
||
|
logger.info(f"Iniciando procesamiento de {archivo_entrada}")
|
||
|
|
||
|
try:
|
||
|
# Leer el archivo de entrada
|
||
|
df = fc.read_dataframe_with_cleanup_retries(archivo_entrada)
|
||
|
|
||
|
if config.columna_origen1 not in df.columns or config.columna_origen2 not in df.columns:
|
||
|
logger.error(f"Columnas requeridas no encontradas en el archivo")
|
||
|
print(f"Error: Las columnas {config.columna_origen1} y/o {config.columna_origen2} no existen en el archivo")
|
||
|
return
|
||
|
|
||
|
# Filtrar filas donde ambas columnas tienen contenido
|
||
|
df_filtered = df.dropna(subset=[config.columna_origen1, config.columna_origen2])
|
||
|
df_filtered = df_filtered[
|
||
|
(df_filtered[config.columna_origen1].astype(str).str.strip() != '') &
|
||
|
(df_filtered[config.columna_origen2].astype(str).str.strip() != '')
|
||
|
]
|
||
|
|
||
|
# Crear columnas para textos corregidos
|
||
|
df[f"{config.columna_origen1}_Corregido"] = df[config.columna_origen1]
|
||
|
df[f"{config.columna_origen2}_Corregido"] = df[config.columna_origen2]
|
||
|
|
||
|
# Procesar en lotes de 10 pares
|
||
|
batch_size = 10
|
||
|
total_rows = len(df_filtered)
|
||
|
|
||
|
progress_bar = fc.ProgressBar(
|
||
|
total_rows, prefix="Procesando textos:", suffix="Completado"
|
||
|
)
|
||
|
|
||
|
for i in range(0, total_rows, batch_size):
|
||
|
batch_df = df_filtered.iloc[i:i+batch_size]
|
||
|
|
||
|
# Preparar pares de textos para el lote
|
||
|
text_pairs = [
|
||
|
[str(row[config.columna_origen1]).strip(), str(row[config.columna_origen2]).strip()]
|
||
|
for _, row in batch_df.iterrows()
|
||
|
]
|
||
|
|
||
|
# Obtener correcciones para el lote
|
||
|
corrections = corregir_texto_batch(text_pairs, logger)
|
||
|
|
||
|
if corrections:
|
||
|
# Aplicar correcciones al DataFrame original
|
||
|
for j, correction in enumerate(corrections):
|
||
|
idx = batch_df.index[j]
|
||
|
df.at[idx, f"{config.columna_origen1}_Corregido"] = correction[0]
|
||
|
df.at[idx, f"{config.columna_origen2}_Corregido"] = correction[1]
|
||
|
|
||
|
progress_bar.update(min(i + batch_size, total_rows))
|
||
|
|
||
|
progress_bar.finish()
|
||
|
|
||
|
# Guardar resultados
|
||
|
output_path = config.get_output_path()
|
||
|
fc.save_dataframe_with_retries(df, output_path)
|
||
|
|
||
|
logger.info(f"Archivo procesado y guardado en: {output_path}")
|
||
|
print(f"\nArchivo procesado y guardado en: {output_path}")
|
||
|
print(f"Se procesaron {total_rows} pares de texto.")
|
||
|
|
||
|
except Exception as e:
|
||
|
logger.error(f"Error durante el procesamiento: {str(e)}")
|
||
|
print(f"Error durante el procesamiento: {str(e)}")
|
||
|
|
||
|
def run(config):
|
||
|
global logger
|
||
|
logger = fc.configurar_logger(config.work_dir)
|
||
|
script_name = os.path.basename(__file__)
|
||
|
print(f"\rIniciando: {script_name}\r")
|
||
|
|
||
|
# Solicitar archivo de entrada
|
||
|
from tkinter import filedialog
|
||
|
archivo_entrada = filedialog.askopenfilename(
|
||
|
title="Seleccione el archivo con textos OCR",
|
||
|
filetypes=[("Excel files", "*.xls*")]
|
||
|
)
|
||
|
|
||
|
if archivo_entrada:
|
||
|
procesar_archivo(config, archivo_entrada)
|
||
|
else:
|
||
|
print("No se seleccionó ningún archivo para procesar.")
|
||
|
|
||
|
if __name__ == "__main__":
|
||
|
import menu_ocr_correction
|
||
|
menu_ocr_correction.main()
|