File size: 8,717 Bytes
e0b339d
 
d35e97b
d56556d
e0b339d
 
 
 
 
 
 
 
 
 
 
 
 
fda1a93
e0b339d
 
 
 
 
 
 
 
 
b226794
e0b339d
 
 
 
 
 
2e0d094
 
 
 
 
 
e0b339d
 
 
 
d56556d
e0b339d
 
d56556d
 
93a5ed3
d56556d
b226794
 
d56556d
 
b226794
 
 
d56556d
 
b226794
d56556d
b226794
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d56556d
2e0d094
d56556d
b226794
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d56556d
b226794
 
 
 
d56556d
b226794
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d56556d
2e0d094
 
b226794
 
 
 
e0b339d
b226794
e0b339d
 
 
 
d35e97b
 
 
 
b226794
 
 
 
 
 
 
 
 
 
 
 
 
 
fda1a93
b226794
d56556d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2e0d094
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
193
194
195
196
197
198
199
200
201
202
203
204
205
import tempfile
import time
from gradio_client import Client, handle_file
import re 

async def imageToTemp(image):

    try:
        with tempfile.NamedTemporaryFile(delete=False, suffix=f"_{image.filename}") as tmp_file:
            contents = await image.read()
            tmp_file.write(contents)
            temp_file_path = tmp_file.name
        
        print(f"Archivo temporal guardado en: {temp_file_path}")
        return temp_file_path

    except Exception as e:
        print(f"Error al procesar la imagen: {e}")
        return {"error": "Error al procesar la imagen"}
    

def listaTextosExtraidos(dict_recibido):

    result = dict_recibido['data']
    print("Datos extraídos (acceso directo):")
    
    textos_extraidos = [] 
    
    for item in result:
        texto = item[1][0] 
        print(texto)
        textos_extraidos.append(texto)
    return textos_extraidos

def simplificaTextos(textos_extraidos):
    textos_extraidos_simplificados = [texto.lower().replace(" ", "") for texto in textos_extraidos]   
    print("Textos extraídos simplificados:")
    print(textos_extraidos_simplificados)
    return textos_extraidos_simplificados

#Herramientas para DNI Panamá.

def buscaIndexPalabra(arreglo, palabra):
    palabra_limpia = palabra.lower().replace(" ", "")
    for i, texto_limpio in enumerate(arreglo):
        if palabra_limpia in texto_limpio:
            return i
    return None # Cambiado de 'error' a None

def buscaIndexMultiplesPalabras(arreglo_textos, conceptos_requeridos):
    """
    Busca el índice de la primera línea que contiene todas las palabras requeridas (o sus alternativas)
    y devuelve la línea con las alternativas corregidas a su forma preferida.

    Args:
        arreglo (list): Lista de strings de texto extraído (limpios).
        conceptos_requeridos (list): Lista de diccionarios, donde cada diccionario define un concepto:
                                     Ej: {'preferida': 'nacimiento', 'alternativas': ['nacimento', 'nacimuento']}

    Returns:
        tuple: (índice, línea_corregida) si se encuentra, o (None, None) si no se encuentra.
    """
    print(f"\n--- Iniciando búsqueda y corrección ---")
    
    # Paso 1: Normalizar los conceptos y prepararlos para la búsqueda y corrección
    conceptos_preparados = []
    for concepto in conceptos_requeridos:
        preferida = concepto['preferida'].lower().replace(" ", "")
        alternativas = [alt.lower().replace(" ", "") for alt in concepto.get('alternativas', [])]
        
        # Combinamos la preferida con las alternativas para la búsqueda
        todas_las_formas = [preferida] + alternativas
        
        conceptos_preparados.append({
            'preferida': preferida,
            'todas_las_formas': todas_las_formas,
            'alternativas': alternativas  # Solo las alternativas para saber cuáles corregir
        })

    for i, texto_linea in enumerate(arreglo_textos):
        texto_linea_lower = texto_linea.lower()
        
        # Variables para seguir el rastro de la línea actual
        es_coincidencia_completa = True
        palabras_encontradas_en_linea = {} # Almacena {forma_encontrada: forma_preferida}

        # Paso 2: Verificar si TODAS las condiciones se cumplen en esta línea
        for concepto in conceptos_preparados:
            encontrado_en_esta_linea = False
            
            # Buscamos si alguna forma (preferida o alternativa) está en la línea
            for forma in concepto['todas_las_formas']:
                if forma in texto_linea_lower:
                    encontrado_en_esta_linea = True
                    
                    # Guardamos qué forma se encontró y cuál es la preferida
                    palabras_encontradas_en_linea[forma] = concepto['preferida']
                    
                    # Hemos encontrado una forma para este concepto, pasamos al siguiente concepto
                    break 
            
            if not encontrado_en_esta_linea:
                es_coincidencia_completa = False
                print(f"Fallo en línea {i}: No se encontró el concepto '{concepto['preferida']}' ni sus alternativas.")
                break # Si falta un concepto, pasamos a la siguiente línea del arreglo

        # Paso 3: Si se encontró una coincidencia completa, corregimos la línea y la retornamos
        if es_coincidencia_completa:
            print(f"ÉXITO: Coincidencia completa en el índice {i}.")
            print(f"Texto linea es: {texto_linea}")

            linea_corregida = texto_linea
            
            for forma_encontrada, forma_preferida in palabras_encontradas_en_linea.items():
                # Nota: Esta corrección simple asume que la palabra encontrada está exactamente igual que en la lista de alternativas (minusculas y sin espacios)
                # Para un OCR más variable, necesitarías una lógica de reemplazo más avanzada (ej. re.sub), 
                # pero para tu caso de "nacimento" a "nacimiento" esto funciona si la palabra se encuentra exactamente.

                # Usamos re.sub para reemplazar la palabra encontrada con la preferida, insensible a mayúsculas/minúsculas
                # (re.escape para manejar caracteres especiales si los hubiera)
                patron_reemplazo = re.compile(re.escape(forma_encontrada), re.IGNORECASE)
                
                # Reemplazamos la palabra encontrada en la línea original con la forma preferida
                linea_corregida = patron_reemplazo.sub(forma_preferida, linea_corregida, count=1)

            print(f"Línea corregida: '{linea_corregida}'")
            # Ahora corregimos la línea original usando la información de las palabras encontradas
            
            arreglo_textos[i] = linea_corregida             
            return i, arreglo_textos
    
    print(f"\n--- Búsqueda finalizada ---")
    print("Ninguna línea contiene todas las palabras requeridas.")
    return None, None

########################################################################
def buscarPatronCedula(lista_textos):    
    for i, texto in enumerate(lista_textos):
        if texto and texto[0].isdigit() and '-' in texto:     
            return i 
    return 'error'

async def procesaImagen(image):

    try:
        temp_image = await imageToTemp(image)
        client = Client("BuzzwordMx/ai_ocr")
        dict_recibido = client.predict(
                img=handle_file(temp_image),
                lang="en",
                api_name="/predict"
        )
                   
        #Aquí es donde personalizo el proceso:
        textos_extraidos = listaTextosExtraidos(dict_recibido) 
        return textos_extraidos
    except Exception as e:
        print(f"Error al procesar el archivo: {e}")
        return 'Error'
    

def obtener_fecha(texto):
    # El patrón busca:
    # - "FECHADENACIMIENTO" (insensible a mayúsculas/minúsculas)
    # - Seguido opcionalmente de CERO o MÁS caracteres que NO SEAN UN DÍGITO (lo que inicia la fecha).
    #   Esto cubrirá ':', '.', espacios, o cualquier otro carácter de separación.
    # - Captura el patrón de fecha: \d{1,2}-[A-Za-z0-9]{3}-\d{4}
    patron = r"FECHADENACIMIENTO[^\d]*(\d{1,2}-[A-Za-z0-9]{3}-\d{4})"
    
    match = re.search(patron, texto, re.IGNORECASE)
    
    fecha_encontrada = None
    if match:
        fecha_encontrada = match.group(1)
        
        if fecha_encontrada:
            partes_fecha = fecha_encontrada.split('-')
            if len(partes_fecha) == 3:
                dia = partes_fecha[0]
                mes = partes_fecha[1].lower() # Convierte el mes a minúsculas
                año = partes_fecha[2]
                return f"{dia}-{mes}-{año}"
            else:
                # Esto se ejecutaría si el formato de la fecha extraída no es el esperado (ej. 2 partes)
                return fecha_encontrada 
    
    return None # Si no se encontró el patrón de fecha

def obtener_sexo(texto):
    # El patrón ahora busca "Sexo" O "Seno" (insensible a mayúsculas/minúsculas)
    # Seguido opcionalmente de un ":"
    # Seguido opcionalmente de espacios en blanco
    # Captura la siguiente letra
    patron = r"(Sexo|Seno):?\s*([A-Za-z])"
    
    # re.search busca la primera ocurrencia del patrón en el texto
    # re.IGNORECASE hace que la búsqueda sea insensible a mayúsculas/minúsculas para "Sexo" y "Seno"
    match = re.search(patron, texto, re.IGNORECASE)
    
    if match:
        # match.group(2) devuelve lo que se capturó en el SEGUNDO grupo de paréntesis,
        # que es la letra del sexo/seno. match.group(1) sería "Sexo" o "Seno".
        return match.group(2)
    else:
        return None