Moibe commited on
Commit
b226794
·
1 Parent(s): d56556d

Capacidad de procesar imagenes sin texto

Browse files
__pycache__/app.cpython-311.pyc CHANGED
Binary files a/__pycache__/app.cpython-311.pyc and b/__pycache__/app.cpython-311.pyc differ
 
__pycache__/funciones.cpython-311.pyc CHANGED
Binary files a/__pycache__/funciones.cpython-311.pyc and b/__pycache__/funciones.cpython-311.pyc differ
 
app.py CHANGED
@@ -30,19 +30,10 @@ async def echo_image(image: UploadFile = File(...)):
30
  return StreamingResponse(BytesIO(contents), media_type=image.content_type)
31
 
32
  @app.post(
33
- "/procesa_dni/",
34
  tags=["Rapicash"],
35
  summary="Procesamiento de DNI")
36
- async def procesa_dni(image: UploadFile = File(...)):
37
  if not image.content_type.startswith("image/"):
38
  return {"error": "El archivo no es una imagen"}
39
- return await funciones.procesa_dni(image)
40
-
41
- @app.post(
42
- "/procesa_pasaporte/",
43
- tags=["Rapicash"],
44
- summary="Procesamiento de DNI")
45
- async def procesa_pasaporte(image: UploadFile = File(...)):
46
- if not image.content_type.startswith("image/"):
47
- return {"error": "El archivo no es una imagen"}
48
- return await funciones.procesa_pasaporte(image)
 
30
  return StreamingResponse(BytesIO(contents), media_type=image.content_type)
31
 
32
  @app.post(
33
+ "/procesa_documento/",
34
  tags=["Rapicash"],
35
  summary="Procesamiento de DNI")
36
+ async def procesa_documento(image: UploadFile = File(...)):
37
  if not image.content_type.startswith("image/"):
38
  return {"error": "El archivo no es una imagen"}
39
+ return await funciones.procesa_documento(image)
 
 
 
 
 
 
 
 
 
funciones.py CHANGED
@@ -2,15 +2,22 @@ import herramientas
2
  import documentos
3
  import time
4
 
5
-
6
- async def procesa_dni(image):
7
 
8
  textos_extraidos = await herramientas.procesaImagen(image)
9
-
10
- #Campos DNI Panamá.
11
- nombre, apellido, identificacion, fecha_nacimiento, sexo = await documentos.dni(textos_extraidos)
12
-
13
- return {
 
 
 
 
 
 
 
 
14
  "nombre": nombre,
15
  "apellido": apellido,
16
  "identificacion": identificacion,
@@ -18,15 +25,31 @@ async def procesa_dni(image):
18
  "sexo": sexo
19
  }
20
 
21
- async def procesa_pasaporte(image):
22
-
23
- textos_extraidos = await herramientas.procesaImagen(image)
24
-
25
- #Campos DNI Panamá.
26
- nombre, apellido, identificacion = await documentos.pasaporte(textos_extraidos)
27
 
28
- return {
 
29
  "nombre": nombre,
30
  "apellido": apellido,
31
- "identificacion": identificacion
32
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
  import documentos
3
  import time
4
 
5
+ async def procesa_documento(image):
 
6
 
7
  textos_extraidos = await herramientas.procesaImagen(image)
8
+ print("Textos extraídos: ")
9
+ print(textos_extraidos)
10
+
11
+ documento = herramientas.define_documento(textos_extraidos)
12
+ print("El documento fue: ", documento)
13
+
14
+ if documento == 'dni':
15
+ # Llama a la función 'dni' si el documento es un DNI
16
+ nombre, apellido, identificacion, fecha_nacimiento, sexo = await documentos.dni(textos_extraidos)
17
+ print("Procesado como DNI.")
18
+
19
+ return {
20
+ "documento": documento,
21
  "nombre": nombre,
22
  "apellido": apellido,
23
  "identificacion": identificacion,
 
25
  "sexo": sexo
26
  }
27
 
28
+ elif documento == 'pasaporte':
29
+ # Llama a la función 'pasaporte' si el documento es un pasaporte
30
+ #nombre, apellido, identificacion, fecha_nacimiento, sexo = await documentos.pasaporte(textos_extraidos)
31
+ nombre, apellido, identificacion, pasaporte, fecha_nacimiento, sexo, fecha_expedicion, fecha_vencimiento = 'pasaporte', 'pasaporte', 'pasaporte', 'pasaporte', 'pasaporte', 'pasaporte', 'pasaporte', 'pasaporte'
32
+ print("Procesado como Pasaporte.")
 
33
 
34
+ return {
35
+ "documento": documento,
36
  "nombre": nombre,
37
  "apellido": apellido,
38
+ "identificacion": identificacion,
39
+ "pasaporte": pasaporte,
40
+ "fecha_nacimiento": fecha_nacimiento,
41
+ "sexo": sexo,
42
+ "fecha_expedicion": fecha_expedicion,
43
+ "fecha_vencimiento": fecha_vencimiento
44
+ }
45
+
46
+ else:
47
+ # Maneja cualquier otro caso no esperado
48
+ print(f"Tipo de documento no reconocido: {documento}")
49
+ # Podrías asignar None a las variables o levantar un error aquí
50
+ #nombre, apellido, identificacion, fecha_nacimiento, sexo = None, None, None, None, None
51
+ return {
52
+ "error": "El documento no es un dni o pasaporte válido o requiere ser más legible.",
53
+ }
54
+
55
+
herramientas.py CHANGED
@@ -25,7 +25,7 @@ def listaTextosExtraidos(dict_recibido):
25
  print("Datos extraídos (acceso directo):")
26
 
27
  textos_extraidos = []
28
- print("Líneas encontradas con modelo IA:")
29
  for item in result:
30
  texto = item[1][0]
31
  print(texto)
@@ -41,45 +41,93 @@ def buscaIndexPalabra(arreglo, palabra):
41
  return i
42
  return None # Cambiado de 'error' a None
43
 
44
- def buscaIndexMultiplesPalabras(arreglo, palabras_requeridas):
45
  """
46
- Busca el índice de la primera línea en un arreglo de textos
47
- que contenga TODAS las palabras especificadas en palabras_requeridas.
48
 
49
  Args:
50
- arreglo (list): Una lista de strings (los textos limpios).
51
- palabras_requeridas (list): Una lista de strings, donde cada string
52
- es una palabra que debe estar presente en la línea.
53
- La búsqueda es insensible a mayúsculas/minúsculas
54
- y limpia espacios en las palabras requeridas.
55
 
56
  Returns:
57
- int: El índice de la primera línea que contiene todas las palabras,
58
- o None si ninguna línea las contiene.
59
  """
60
-
61
- print("Estoy en busca palabras múltiples.")
62
-
63
-
64
- # Limpiar y normalizar todas las palabras requeridas de una vez
65
- palabras_requeridas_limpias = [p.lower().replace(" ", "") for p in palabras_requeridas]
66
-
67
- print("Las palabras requeridas límpias son: ", palabras_requeridas_limpias)
 
 
 
 
 
 
 
 
68
 
69
  for i, texto_linea in enumerate(arreglo):
70
- # Convertir la línea actual a minúsculas para una comparación insensible a mayúsculas/minúsculas
71
  texto_linea_lower = texto_linea.lower()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72
 
73
- print("La línea que estoy analizando es: ", texto_linea_lower)
 
 
 
74
 
75
- # Verificar si TODAS las palabras requeridas están en la línea actual
76
- # Usamos 'all()' para asegurarnos de que CADA palabra_limpia esté en texto_linea_lower
77
- if all(palabra_limpia in texto_linea_lower for palabra_limpia in palabras_requeridas_limpias):
78
- print(f"Todas las palabras están en la línea {i}")
79
- return i # Retorna el índice de la primera línea que cumple la condición
 
 
 
 
 
 
 
 
 
 
 
80
 
81
- return None # Si ninguna línea contiene todas las palabras
 
 
 
 
 
82
 
 
83
  def buscarPatronCedula(lista_textos):
84
  for i, texto in enumerate(lista_textos):
85
  if texto and texto[0].isdigit() and '-' in texto:
@@ -88,17 +136,21 @@ def buscarPatronCedula(lista_textos):
88
 
89
  async def procesaImagen(image):
90
 
91
- temp_image = await imageToTemp(image)
92
-
93
- client = Client("BuzzwordMx/ai_ocr")
94
- dict_recibido = client.predict(
95
- img=handle_file(temp_image),
96
- lang="en",
97
- api_name="/predict"
98
- )
99
- #Aquí es donde personalizo el proceso:
100
- textos_extraidos = listaTextosExtraidos(dict_recibido)
101
- return textos_extraidos
 
 
 
 
102
 
103
  def obtener_fecha(texto):
104
  # El patrón busca:
@@ -143,4 +195,35 @@ def obtener_sexo(texto):
143
  # que es la letra del sexo/seno. match.group(1) sería "Sexo" o "Seno".
144
  return match.group(2)
145
  else:
146
- return None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
  print("Datos extraídos (acceso directo):")
26
 
27
  textos_extraidos = []
28
+
29
  for item in result:
30
  texto = item[1][0]
31
  print(texto)
 
41
  return i
42
  return None # Cambiado de 'error' a None
43
 
44
+ def buscaIndexMultiplesPalabras_Corregida(arreglo, conceptos_requeridos):
45
  """
46
+ Busca el índice de la primera línea que contiene todas las palabras requeridas (o sus alternativas)
47
+ y devuelve la línea con las alternativas corregidas a su forma preferida.
48
 
49
  Args:
50
+ arreglo (list): Lista de strings de texto extraído (limpios).
51
+ conceptos_requeridos (list): Lista de diccionarios, donde cada diccionario define un concepto:
52
+ Ej: {'preferida': 'nacimiento', 'alternativas': ['nacimento', 'nacimuento']}
 
 
53
 
54
  Returns:
55
+ tuple: (índice, línea_corregida) si se encuentra, o (None, None) si no se encuentra.
 
56
  """
57
+ print(f"\n--- Iniciando búsqueda y corrección ---")
58
+
59
+ # Paso 1: Normalizar los conceptos y prepararlos para la búsqueda y corrección
60
+ conceptos_preparados = []
61
+ for concepto in conceptos_requeridos:
62
+ preferida = concepto['preferida'].lower().replace(" ", "")
63
+ alternativas = [alt.lower().replace(" ", "") for alt in concepto.get('alternativas', [])]
64
+
65
+ # Combinamos la preferida con las alternativas para la búsqueda
66
+ todas_las_formas = [preferida] + alternativas
67
+
68
+ conceptos_preparados.append({
69
+ 'preferida': preferida,
70
+ 'todas_las_formas': todas_las_formas,
71
+ 'alternativas': alternativas # Solo las alternativas para saber cuáles corregir
72
+ })
73
 
74
  for i, texto_linea in enumerate(arreglo):
 
75
  texto_linea_lower = texto_linea.lower()
76
+
77
+ # Variables para seguir el rastro de la línea actual
78
+ es_coincidencia_completa = True
79
+ palabras_encontradas_en_linea = {} # Almacena {forma_encontrada: forma_preferida}
80
+
81
+ # Paso 2: Verificar si TODAS las condiciones se cumplen en esta línea
82
+ for concepto in conceptos_preparados:
83
+ encontrado_en_esta_linea = False
84
+
85
+ # Buscamos si alguna forma (preferida o alternativa) está en la línea
86
+ for forma in concepto['todas_las_formas']:
87
+ if forma in texto_linea_lower:
88
+ encontrado_en_esta_linea = True
89
+
90
+ # Guardamos qué forma se encontró y cuál es la preferida
91
+ palabras_encontradas_en_linea[forma] = concepto['preferida']
92
+
93
+ # Hemos encontrado una forma para este concepto, pasamos al siguiente concepto
94
+ break
95
+
96
+ if not encontrado_en_esta_linea:
97
+ es_coincidencia_completa = False
98
+ print(f"Fallo en línea {i}: No se encontró el concepto '{concepto['preferida']}' ni sus alternativas.")
99
+ break # Si falta un concepto, pasamos a la siguiente línea del arreglo
100
 
101
+ # Paso 3: Si se encontró una coincidencia completa, corregimos la línea y la retornamos
102
+ if es_coincidencia_completa:
103
+ print(f"ÉXITO: Coincidencia completa en el índice {i}.")
104
+ print(f"Texto linea es: {texto_linea}")
105
 
106
+ linea_corregida = texto_linea
107
+
108
+ for forma_encontrada, forma_preferida in palabras_encontradas_en_linea.items():
109
+ # Nota: Esta corrección simple asume que la palabra encontrada está exactamente igual que en la lista de alternativas (minusculas y sin espacios)
110
+ # Para un OCR más variable, necesitarías una lógica de reemplazo más avanzada (ej. re.sub),
111
+ # pero para tu caso de "nacimento" a "nacimiento" esto funciona si la palabra se encuentra exactamente.
112
+
113
+ # Usamos re.sub para reemplazar la palabra encontrada con la preferida, insensible a mayúsculas/minúsculas
114
+ # (re.escape para manejar caracteres especiales si los hubiera)
115
+ patron_reemplazo = re.compile(re.escape(forma_encontrada), re.IGNORECASE)
116
+
117
+ # Reemplazamos la palabra encontrada en la línea original con la forma preferida
118
+ linea_corregida = patron_reemplazo.sub(forma_preferida, linea_corregida, count=1)
119
+
120
+ print(f"Línea corregida: '{linea_corregida}'")
121
+ # Ahora corregimos la línea original usando la información de las palabras encontradas
122
 
123
+ arreglo[i] = linea_corregida
124
+ return i, arreglo
125
+
126
+ print(f"\n--- Búsqueda finalizada ---")
127
+ print("Ninguna línea contiene todas las palabras requeridas.")
128
+ return None, None
129
 
130
+ ########################################################################
131
  def buscarPatronCedula(lista_textos):
132
  for i, texto in enumerate(lista_textos):
133
  if texto and texto[0].isdigit() and '-' in texto:
 
136
 
137
  async def procesaImagen(image):
138
 
139
+ try:
140
+ temp_image = await imageToTemp(image)
141
+ client = Client("BuzzwordMx/ai_ocr")
142
+ dict_recibido = client.predict(
143
+ img=handle_file(temp_image),
144
+ lang="en",
145
+ api_name="/predict"
146
+ )
147
+
148
+ #Aquí es donde personalizo el proceso:
149
+ textos_extraidos = listaTextosExtraidos(dict_recibido)
150
+ return textos_extraidos
151
+ except Exception as e:
152
+ print(f"Error al procesar el archivo: {e}")
153
+
154
 
155
  def obtener_fecha(texto):
156
  # El patrón busca:
 
195
  # que es la letra del sexo/seno. match.group(1) sería "Sexo" o "Seno".
196
  return match.group(2)
197
  else:
198
+ return None
199
+
200
+ def define_documento(textos_extraidos):
201
+
202
+ #Definiré si el documento subido es un pasaporte o un dni.
203
+ textos_extraidos_simplificados = [texto.lower().replace(" ", "") for texto in textos_extraidos]
204
+
205
+ #Busqueda de DNI
206
+ conceptos_busqueda_dni = [
207
+ {'preferida': 'nombre', 'alternativas': []},
208
+ {'preferida': 'usual', 'alternativas': []}
209
+ ]
210
+
211
+ indice, textos_extraidos_corregidos = buscaIndexMultiplesPalabras_Corregida(textos_extraidos_simplificados, conceptos_busqueda_dni)
212
+ if indice is not None:
213
+ print("Si es dni...")
214
+ return 'dni'
215
+ else:
216
+ #Revisar si es pasaporte.
217
+ #Busqueda de DNI
218
+ conceptos_busqueda_pasaporte = [
219
+ {'preferida': 'pasaporte', 'alternativas': ['passport']},
220
+ #{'preferida': 'identidad', 'alternativas': []}
221
+ ]
222
+ indice, textos_extraidos_corregidos = buscaIndexMultiplesPalabras_Corregida(textos_extraidos_simplificados, conceptos_busqueda_pasaporte)
223
+
224
+ if indice is not None:
225
+ print("Si es pasaporte...")
226
+ return 'pasaporte'
227
+ else:
228
+ print("No es pasaporte ni dni.")
229
+ return None
obtenCampo.py CHANGED
@@ -2,19 +2,26 @@ import herramientas
2
 
3
 
4
  #Campos para DNI.
5
- def Nombre(textos_extraidos, textos_extraidos_limpios):
6
- indice = herramientas.buscaIndexPalabra(textos_extraidos_limpios, 'usual')
7
  nombre = textos_extraidos[indice-2]
8
  apellido = textos_extraidos[indice-1]
9
  return nombre, apellido
10
 
11
- def Identificacion(textos_extraidos, textos_extraidos_limpios):
12
- indice = herramientas.buscarPatronCedula(textos_extraidos_limpios)
13
  identificacion = textos_extraidos[indice]
14
  return identificacion
15
 
16
  def Fecha_Nacimiento(textos_extraidos, textos_extraidos_limpios):
17
- indice = herramientas.buscaIndexMultiplesPalabras(textos_extraidos_limpios, ['fecha', 'nacimiento'])
 
 
 
 
 
 
 
18
  print("El índice de la fecha de nacimiento es: ", indice)
19
  texto_fecha_nacimiento = textos_extraidos_limpios[indice] #En ésta ocasión estoy usando el texto limpio para que el patrón lo identifique más fácilmente.
20
  print("Y su correspondiente texto es: " , texto_fecha_nacimiento)
@@ -23,18 +30,18 @@ def Fecha_Nacimiento(textos_extraidos, textos_extraidos_limpios):
23
 
24
  def Sexo(textos_extraidos, textos_extraidos_limpios):
25
 
26
- indice = herramientas.buscaIndexPalabra(textos_extraidos_limpios, 'sexo')
 
 
 
 
 
27
 
28
- if indice is None: # Comprobamos si el resultado es None (no encontrado)
29
- indice = herramientas.buscaIndexPalabra(textos_extraidos_limpios, 'seno')
30
- if indice is not None:
31
- print(f"Se encontró una variación de sexo en el índice: {indice}")
32
- else:
33
- print("No se encontró ninguna forma de la palabra sexo.")
34
- return None
35
- else:
36
- print(f"Se encontró palabra directamente.")
37
 
38
- texto_campo_sexo = textos_extraidos[indice]
39
- sexo = herramientas.obtener_sexo(texto_campo_sexo)
 
 
40
  return sexo
 
2
 
3
 
4
  #Campos para DNI.
5
+ def Nombre(textos_extraidos, textos_extraidos_simplificados):
6
+ indice = herramientas.buscaIndexPalabra(textos_extraidos_simplificados, 'usual')
7
  nombre = textos_extraidos[indice-2]
8
  apellido = textos_extraidos[indice-1]
9
  return nombre, apellido
10
 
11
+ def Identificacion(textos_extraidos, textos_extraidos_simplificados):
12
+ indice = herramientas.buscarPatronCedula(textos_extraidos_simplificados)
13
  identificacion = textos_extraidos[indice]
14
  return identificacion
15
 
16
  def Fecha_Nacimiento(textos_extraidos, textos_extraidos_limpios):
17
+
18
+ conceptos_busqueda = [
19
+ {'preferida': 'fecha', 'alternativas': []},
20
+ {'preferida': 'nacimiento', 'alternativas': ['nacimento']} ]
21
+
22
+ indice, textos_extraidos_corregidos = herramientas.buscaIndexMultiplesPalabras_Corregida(textos_extraidos_limpios, conceptos_busqueda)
23
+ print("182 Ésto es textos extraídos corregidos: ", textos_extraidos_corregidos)
24
+ textos_extraidos_limpios = textos_extraidos_corregidos
25
  print("El índice de la fecha de nacimiento es: ", indice)
26
  texto_fecha_nacimiento = textos_extraidos_limpios[indice] #En ésta ocasión estoy usando el texto limpio para que el patrón lo identifique más fácilmente.
27
  print("Y su correspondiente texto es: " , texto_fecha_nacimiento)
 
30
 
31
  def Sexo(textos_extraidos, textos_extraidos_limpios):
32
 
33
+ conceptos_busqueda = [
34
+ {'preferida': 'sexo', 'alternativas': ['sex', 'seno', 'sen']},
35
+ #{'preferida': 'sangre', 'alternativas': []}
36
+ ]
37
+
38
+ indice, textos_extraidos_corregidos = herramientas.buscaIndexMultiplesPalabras_Corregida(textos_extraidos_limpios, conceptos_busqueda)
39
 
40
+ textos_extraidos_limpios = textos_extraidos_corregidos
41
+ print("El índice de genero es: ", indice)
 
 
 
 
 
 
 
42
 
43
+ texto_genero = textos_extraidos_limpios[indice]
44
+ print("Y su correspondiente texto es: " , texto_genero)
45
+
46
+ sexo = herramientas.obtener_sexo(texto_genero)
47
  return sexo