jjeampierjs commited on
Commit
a68eb9b
·
verified ·
1 Parent(s): bf1eed1

Upload 5 files

Browse files
Files changed (5) hide show
  1. .gitignore +173 -0
  2. .streamlit/secrets.toml +5 -0
  3. README.md +274 -20
  4. app.py +442 -0
  5. requirements.txt +5 -3
.gitignore ADDED
@@ -0,0 +1,173 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ share/python-wheels/
24
+ *.egg-info/
25
+ .installed.cfg
26
+ *.egg
27
+ MANIFEST
28
+
29
+ # PyInstaller
30
+ *.manifest
31
+ *.spec
32
+
33
+ # Installer logs
34
+ pip-log.txt
35
+ pip-delete-this-directory.txt
36
+
37
+ # Unit test / coverage reports
38
+ htmlcov/
39
+ .tox/
40
+ .nox/
41
+ .coverage
42
+ .coverage.*
43
+ .cache
44
+ nosetests.xml
45
+ coverage.xml
46
+ *.cover
47
+ *.py,cover
48
+ .hypothesis/
49
+ .pytest_cache/
50
+ cover/
51
+
52
+ # Translations
53
+ *.mo
54
+ *.pot
55
+
56
+ # Django stuff:
57
+ *.log
58
+ local_settings.py
59
+ db.sqlite3
60
+ db.sqlite3-journal
61
+
62
+ # Flask stuff:
63
+ instance/
64
+ .webassets-cache
65
+
66
+ # Scrapy stuff:
67
+ .scrapy
68
+
69
+ # Sphinx documentation
70
+ docs/_build/
71
+
72
+ # PyBuilder
73
+ .pybuilder/
74
+ target/
75
+
76
+ # Jupyter Notebook
77
+ .ipynb_checkpoints
78
+
79
+ # IPython
80
+ profile_default/
81
+ ipython_config.py
82
+
83
+ # pyenv
84
+ .python-version
85
+
86
+ # pipenv
87
+ Pipfile.lock
88
+
89
+ # poetry
90
+ poetry.lock
91
+
92
+ # pdm
93
+ .pdm.toml
94
+
95
+ # PEP 582
96
+ __pypackages__/
97
+
98
+ # Celery stuff
99
+ celerybeat-schedule
100
+ celerybeat.pid
101
+
102
+ # SageMath parsed files
103
+ *.sage.py
104
+
105
+ # Environments
106
+ .env
107
+ .venv
108
+ env/
109
+ venv/
110
+ ENV/
111
+ env.bak/
112
+ venv.bak/
113
+
114
+ # Spyder project settings
115
+ .spyderproject
116
+ .spyproject
117
+
118
+ # Rope project settings
119
+ .ropeproject
120
+
121
+ # mkdocs documentation
122
+ /site
123
+
124
+ # mypy
125
+ .mypy_cache/
126
+ .dmypy.json
127
+ dmypy.json
128
+
129
+ # Pyre type checker
130
+ .pyre/
131
+
132
+ # pytype static type analyzer
133
+ .pytype/
134
+
135
+ # Cython debug symbols
136
+ cython_debug/
137
+
138
+ # PyCharm
139
+ .idea/
140
+
141
+ # VS Code
142
+ .vscode/
143
+
144
+ # Streamlit specific
145
+ .streamlit/secrets.toml
146
+
147
+ # AWS credentials
148
+ .aws/
149
+ aws-credentials.json
150
+
151
+ # Test files
152
+ test_*.py
153
+ *_test.py
154
+ tests/
155
+
156
+ # Temporary files
157
+ *.tmp
158
+ *.temp
159
+ temp/
160
+ tmp/
161
+
162
+ # OS specific
163
+ .DS_Store
164
+ .DS_Store?
165
+ ._*
166
+ .Spotlight-V100
167
+ .Trashes
168
+ ehthumbs.db
169
+ Thumbs.db
170
+
171
+ # Uploaded files for testing
172
+ uploads/
173
+ test_files/
.streamlit/secrets.toml ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ [aws]
2
+ AWS_ACCESS_KEY_ID = "AKIA6IYSQD72LEVVXE6J"
3
+ AWS_SECRET_ACCESS_KEY = "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"
4
+ AWS_DEFAULT_REGION = "us-east-1"
5
+
README.md CHANGED
@@ -1,20 +1,274 @@
1
- ---
2
- title: Jose Test Deploy
3
- emoji: 🚀
4
- colorFrom: red
5
- colorTo: red
6
- sdk: docker
7
- app_port: 8501
8
- tags:
9
- - streamlit
10
- pinned: false
11
- short_description: desc
12
- license: mit
13
- ---
14
-
15
- # Welcome to Streamlit!
16
-
17
- Edit `/src/streamlit_app.py` to customize this app to your heart's desire. :heart:
18
-
19
- If you have any questions, checkout our [documentation](https://docs.streamlit.io) and [community
20
- forums](https://discuss.streamlit.io).
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 🏦 Analizador de Comprobantes Bancarios
2
+
3
+ ## 📋 Descripción del Proyecto
4
+
5
+ Esta aplicación web desarrollada en **Streamlit** permite extraer información específica de comprobantes bancarios utilizando **Amazon Textract**, un servicio de AWS especializado en extracción de texto y análisis de documentos. La aplicación puede procesar imágenes de comprobantes y extraer automáticamente datos como montos, números de operación, fechas, y más información relevante.
6
+
7
+ ## 🎯 Funcionalidades Principales
8
+
9
+ - ✅ Extracción automática de texto de comprobantes bancarios
10
+ - ✅ Análisis inteligente de formularios y tablas
11
+ - ✅ Reconocimiento de patrones específicos bancarios
12
+ - ✅ Exportación de datos extraídos en formato JSON
13
+ - ✅ Interfaz web intuitiva con vista previa de documentos
14
+
15
+ ## 🛠️ Tecnologías Utilizadas
16
+
17
+ ### Librerías Principales
18
+
19
+ - **Streamlit**: Framework para crear aplicaciones web interactivas
20
+ - **boto3**: SDK oficial de AWS para Python (interacción con servicios AWS)
21
+ - **PIL (Pillow)**: Procesamiento y manipulación de imágenes
22
+ - **pandas**: Manipulación y análisis de datos estructurados
23
+ - **re**: Expresiones regulares para extracción de patrones
24
+
25
+ ### Servicios AWS
26
+
27
+ - **Amazon Textract**: Servicio de extracción de texto y análisis de documentos
28
+
29
+ ## 📁 Estructura del Código
30
+
31
+ ### 1. Clase `BankingReceiptAnalyzer`
32
+
33
+ **Propósito**: Gestiona la comunicación con AWS Textract para el análisis de documentos.
34
+
35
+ #### Método `__init__(self)`
36
+ ```python
37
+ def __init__(self):
38
+ ```
39
+ - **Función**: Constructor que inicializa la conexión con AWS Textract
40
+ - **Consumo de librería**: Utiliza `boto3.client()` para crear cliente de Textract
41
+ - **Configuración**: Lee credenciales desde `st.secrets` (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_DEFAULT_REGION)
42
+ - **Manejo de errores**: Valida credenciales y maneja excepciones de conexión
43
+
44
+ #### Método `analyze_document_with_forms(self, image_bytes)`
45
+ ```python
46
+ def analyze_document_with_forms(self, image_bytes: bytes) -> Dict[str, Any]:
47
+ ```
48
+ - **Función**: Análisis avanzado de documentos con reconocimiento de formularios y tablas
49
+ - **Consumo AWS**: Utiliza `textract.analyze_document()` con características:
50
+ - `FORMS`: Detecta pares clave-valor en formularios
51
+ - `TABLES`: Reconoce estructuras tabulares
52
+ - **Parámetros**: Recibe bytes de la imagen del documento
53
+ - **Retorno**: Diccionario con bloques de texto estructurados o mensaje de error
54
+
55
+ #### Método `extract_text_simple(self, image_bytes)`
56
+ ```python
57
+ def extract_text_simple(self, image_bytes: bytes) -> Dict[str, Any]:
58
+ ```
59
+ - **Función**: Extracción básica de texto línea por línea
60
+ - **Consumo AWS**: Utiliza `textract.detect_document_text()` (método más simple)
61
+ - **Procesamiento**: Filtra bloques de tipo 'LINE' para obtener texto legible
62
+ - **Uso**: Ideal para documentos con texto simple sin estructura compleja
63
+
64
+ ### 2. Clase `BankingDataExtractor`
65
+
66
+ **Propósito**: Procesa el texto extraído y identifica campos específicos bancarios usando patrones.
67
+
68
+ #### Método `extract_banking_fields(text)`
69
+ ```python
70
+ @staticmethod
71
+ def extract_banking_fields(text: str) -> Dict[str, str]:
72
+ ```
73
+ - **Función**: Extrae información bancaria específica usando expresiones regulares
74
+ - **Consumo de librería**: Utiliza `re.search()` para patrones regex
75
+ - **Campos detectables**:
76
+ - 💰 Importe enviado (S/ XXX.XX)
77
+ - 🏦 Entidad destino (nombre del banco)
78
+ - 💳 Comisión (S/ X.XX)
79
+ - 📊 ITF (Impuesto a las Transacciones Financieras)
80
+ - 🔢 Número de operación
81
+ - 📝 Tipo de operación
82
+ - 📅 Fecha y hora
83
+ - ✅ Estado de operación
84
+
85
+ **Patrones de Búsqueda Ejemplo**:
86
+ ```python
87
+ 'importe_enviado': [
88
+ r'Importe enviado\s*S/\s*(\d+\.?\d*)',
89
+ r'S/\s*(\d+\.?\d*)',
90
+ r'Monto\s*S/\s*(\d+\.?\d*)'
91
+ ]
92
+ ```
93
+
94
+ #### Método `_extract_account_numbers(text, fields)`
95
+ ```python
96
+ @staticmethod
97
+ def _extract_account_numbers(text: str, fields: Dict[str, str]) -> None:
98
+ ```
99
+ - **Función**: Identifica números de cuenta origen y destino
100
+ - **Patrones**: Busca formatos como "•1234", "Cuenta 123456789"
101
+ - **Lógica**: Asigna primera cuenta como origen y segunda como destino
102
+
103
+ #### Método `_extract_bank_names(text, fields)`
104
+ ```python
105
+ @staticmethod
106
+ def _extract_bank_names(text: str, fields: Dict[str, str]) -> None:
107
+ ```
108
+ - **Función**: Detecta nombres de bancos peruanos comunes
109
+ - **Bancos soportados**: BBVA, Plin, BCP, Interbank, Scotiabank, BanBif
110
+ - **Método**: Búsqueda case-insensitive en el texto
111
+
112
+ ### 3. Función `display_extracted_banking_data(fields)`
113
+
114
+ **Propósito**: Presenta los datos extraídos en una interfaz visual organizada.
115
+
116
+ - **Consumo Streamlit**: Utiliza `st.metric()`, `st.dataframe()`, `st.columns()`
117
+ - **Funcionalidades**:
118
+ - Métricas destacadas (importe, entidad, estado)
119
+ - Tabla detallada con todos los campos
120
+ - Indicadores de estado (detectado/no detectado)
121
+ - Botón de descarga en formato JSON
122
+ - **Exportación**: Genera archivo JSON con timestamp y estadísticas de completitud
123
+
124
+ ### 4. Función `process_banking_receipt(uploaded_file, analyzer)`
125
+
126
+ **Propósito**: Orquesta el proceso completo de análisis de un comprobante.
127
+
128
+ - **Consumo PIL**: Utiliza `Image.open()` para mostrar vista previa
129
+ - **Funcionalidades**:
130
+ - Vista previa del documento subido
131
+ - Dos métodos de análisis (Tabs):
132
+ - Análisis avanzado con formularios
133
+ - Extracción simple de texto
134
+ - Procesamiento de bytes del archivo
135
+ - Manejo de errores y estados de carga
136
+
137
+ ### 5. Función `main()`
138
+
139
+ **Propósito**: Función principal que construye la interfaz de usuario completa.
140
+
141
+ - **Consumo Streamlit**: Utiliza múltiples componentes:
142
+ - `st.title()`, `st.markdown()`: Títulos y contenido
143
+ - `st.sidebar`: Panel lateral informativo
144
+ - `st.file_uploader()`: Subida de archivos
145
+ - `st.columns()`: Layout en columnas
146
+ - **Validaciones**: Verifica credenciales AWS antes de continuar
147
+ - **Tipos de archivo**: Soporta JPG, PNG, PDF
148
+
149
+ ## FUNCIONAMIENTO
150
+
151
+
152
+ ## 🧠 **Dos "servicios" o capas distintas en el proceso**
153
+
154
+ ### 🔹 1. **OCR con IA** → *Textract (`extract_text_simple`)*
155
+
156
+ * Es el **servicio de reconocimiento de texto (OCR)** de [AWS Textract](w).
157
+ * Detecta el **texto visual** en una imagen escaneada (como un comprobante bancario).
158
+ * **No interpreta** lo que ese texto significa, solo lo reconoce y lo devuelve como líneas o palabras.
159
+ * Es como un escáner con **visión artificial inteligente**, que ve:
160
+
161
+ ```
162
+ "Importe enviado S/ 1250.00"
163
+ ```
164
+
165
+ ---
166
+
167
+ ### 🔹 2. **Servicio tipo “tag” semántico** → *`BankingDataExtractor`*
168
+
169
+ * Es un **servicio personalizado**, hecho por ti (o el desarrollador).
170
+ * Usa expresiones regulares para **“etiquetar” o clasificar** partes del texto como:
171
+
172
+ * `importe_enviado`, `fecha`, `comisión`, etc.
173
+ * Es como un **motor de reglas semánticas** que dice:
174
+
175
+ > `Importe enviado S/ X`, eso es el campo `importe_enviado`.”
176
+
177
+ ---
178
+
179
+ ## 🧪 Definicion:
180
+
181
+ > AWS Textract es como un lector que **lee** el contenido de una carta (OCR),
182
+ > `BankingDataExtractor` es un asistente que **resalta lo importante** con marcadores: el nombre del remitente, la fecha, el asunto, etc.
183
+
184
+ ---
185
+
186
+ ## 🧩 Diagrama:
187
+
188
+ ```
189
+ 🖼️ Imagen JPG/PDF
190
+
191
+
192
+ 🧠 AWS Textract (OCR IA)
193
+ └──▶ Texto plano
194
+
195
+
196
+ 🧾 BankingDataExtractor (Regex/tagger)
197
+ └──▶ Datos estructurados clave-valor
198
+ ```
199
+
200
+ ---
201
+
202
+ ## ✅ Conclusión:
203
+
204
+ > Se usan 2 servicios: uno (Textract) es como un **OCR con inteligencia artificial** que extrae el texto visible, y el otro (el extractor con regex) **etiqueta o clasifica semánticamente** ese texto para obtener información útil y estructurada.
205
+
206
+
207
+
208
+ ## 🔧 Configuración y Uso
209
+
210
+ ### 1. Configuración de AWS
211
+
212
+ **Archivo**: `secrets.toml` (Streamlit)
213
+ ```toml
214
+ [aws]
215
+ AWS_ACCESS_KEY_ID = "tu_access_key"
216
+ AWS_SECRET_ACCESS_KEY = "tu_secret_key"
217
+ AWS_DEFAULT_REGION = "us-east-1"
218
+ ```
219
+
220
+ ### 2. Instalación de Dependencias
221
+
222
+ ```bash
223
+ pip install streamlit boto3 pillow pandas
224
+ ```
225
+
226
+ ### 3. Ejecución
227
+
228
+ ```bash
229
+ streamlit run app.py
230
+ ```
231
+
232
+ ## 📊 Flujo de Trabajo
233
+
234
+ 1. **Carga de Documento**: Usuario sube imagen del comprobante
235
+ 2. **Procesamiento AWS**: Textract extrae texto y estructura
236
+ 3. **Análisis de Patrones**: Regex identifica campos bancarios específicos
237
+ 4. **Visualización**: Streamlit muestra datos extraídos
238
+ 5. **Exportación**: Descarga opcional en JSON
239
+
240
+ ## 🎯 Casos de Uso
241
+
242
+ - ✅ Automatización de contabilidad empresarial
243
+ - ✅ Reconciliación bancaria automatizada
244
+ - ✅ Digitalización de comprobantes físicos
245
+ - ✅ Auditorías y reportes financieros
246
+ - ✅ Integración con sistemas ERP
247
+
248
+ ## ⚠️ Consideraciones Importantes
249
+
250
+ ### Limitaciones de AWS Textract
251
+ - **Costo**: Servicio pagado por documento procesado
252
+ - **Calidad**: Requiere imágenes claras y bien iluminadas
253
+ - **Idioma**: Optimizado para texto en español/inglés
254
+
255
+ ### Seguridad
256
+ - Credenciales AWS deben mantenerse seguras
257
+ - Los documentos se procesan temporalmente en AWS
258
+ - No se almacenan datos permanentemente
259
+
260
+ ## 🚀 Mejoras Futuras
261
+
262
+ - 🔄 Procesamiento por lotes (múltiples comprobantes)
263
+ - 🤖 Machine Learning personalizado para patrones específicos
264
+ - 📱 Versión móvil optimizada
265
+ - 🔐 Autenticación de usuarios
266
+ - 📈 Dashboard de estadísticas
267
+
268
+ ## 📞 Soporte
269
+
270
+ Para consultas técnicas o mejoras al código, contactar al desarrollador: [@JoseJeampierJaraSalas1997](https://github.com/JoseJeampierJaraSalas1997)
271
+
272
+ ---
273
+
274
+ **Nota**: Este proyecto utiliza Amazon Textract, no Amazon Rekognition. Textract está especializado en extracción de texto y análisis de documentos, mientras que Rekognition se enfoca en reconocimiento de imágenes, caras y objetos.
app.py ADDED
@@ -0,0 +1,442 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import boto3
3
+ from botocore.exceptions import ClientError, NoCredentialsError
4
+ import json
5
+ from PIL import Image
6
+ import io
7
+ import base64
8
+ from typing import Dict, List, Any, Optional, Tuple
9
+ import pandas as pd
10
+ import re
11
+ from datetime import datetime
12
+
13
+ # Configuración de la página
14
+ st.set_page_config(
15
+ page_title="Analizador de Comprobantes Bancarios",
16
+ page_icon="🏦",
17
+ layout="wide",
18
+ initial_sidebar_state="expanded"
19
+ )
20
+
21
+ class BankingReceiptAnalyzer:
22
+ """Clase para analizar comprobantes bancarios usando AWS Textract"""
23
+
24
+ def __init__(self):
25
+ """Inicializa el cliente de AWS Textract"""
26
+ try:
27
+ # Cargar credenciales desde secrets.toml
28
+ aws_access_key = st.secrets["aws"]["AWS_ACCESS_KEY_ID"]
29
+ aws_secret_key = st.secrets["aws"]["AWS_SECRET_ACCESS_KEY"]
30
+ aws_region = st.secrets["aws"]["AWS_DEFAULT_REGION"]
31
+
32
+ # Inicializar cliente AWS Textract
33
+ self.textract = boto3.client(
34
+ 'textract',
35
+ aws_access_key_id=aws_access_key,
36
+ aws_secret_access_key=aws_secret_key,
37
+ region_name=aws_region
38
+ )
39
+
40
+ self.credentials_valid = True
41
+
42
+ except KeyError as e:
43
+ st.error(f"❌ Credencial AWS faltante: {e}")
44
+ self.credentials_valid = False
45
+ except Exception as e:
46
+ st.error(f"❌ Error al inicializar AWS: {str(e)}")
47
+ self.credentials_valid = False
48
+
49
+ def analyze_document_with_forms(self, image_bytes: bytes) -> Dict[str, Any]:
50
+ """Analiza un documento usando Textract con análisis de formularios"""
51
+ try:
52
+ response = self.textract.analyze_document(
53
+ Document={'Bytes': image_bytes},
54
+ FeatureTypes=['FORMS', 'TABLES']
55
+ )
56
+ return {"success": True, "blocks": response['Blocks']}
57
+ except ClientError as e:
58
+ return {"success": False, "error": f"Error de AWS: {e.response['Error']['Message']}"}
59
+ except Exception as e:
60
+ return {"success": False, "error": f"Error inesperado: {str(e)}"}
61
+
62
+ def extract_text_simple(self, image_bytes: bytes) -> Dict[str, Any]:
63
+ """Extrae texto simple del documento"""
64
+ try:
65
+ response = self.textract.detect_document_text(
66
+ Document={'Bytes': image_bytes}
67
+ )
68
+
69
+ # Extraer texto línea por línea
70
+ text_blocks = []
71
+ for block in response['Blocks']:
72
+ if block['BlockType'] == 'LINE':
73
+ text_blocks.append(block['Text'])
74
+
75
+ return {
76
+ "success": True,
77
+ "text": '\n'.join(text_blocks),
78
+ "blocks": response['Blocks']
79
+ }
80
+ except ClientError as e:
81
+ return {"success": False, "error": f"Error de AWS: {e.response['Error']['Message']}"}
82
+ except Exception as e:
83
+ return {"success": False, "error": f"Error inesperado: {str(e)}"}
84
+
85
+ class BankingDataExtractor:
86
+ """Clase para extraer información específica de comprobantes bancarios"""
87
+
88
+ @staticmethod
89
+ def extract_banking_fields(text: str) -> Dict[str, str]:
90
+ """
91
+ Extrae campos específicos del texto del comprobante bancario
92
+ usando expresiones regulares y patrones
93
+ """
94
+ fields = {
95
+ 'importe_enviado': '',
96
+ 'entidad_destino': '',
97
+ 'comision': '',
98
+ 'itf': '',
99
+ 'numero_operacion': '',
100
+ 'tipo_operacion': '',
101
+ 'fecha': '',
102
+ 'cuenta_origen': '',
103
+ 'cuenta_destino': '',
104
+ 'estado_operacion': ''
105
+ }
106
+
107
+ # Patrones de búsqueda
108
+ patterns = {
109
+ 'importe_enviado': [
110
+ r'Importe enviado\s*S/\s*(\d+\.?\d*)',
111
+ r'S/\s*(\d+\.?\d*)',
112
+ r'Monto\s*S/\s*(\d+\.?\d*)',
113
+ r'Importe\s*S/\s*(\d+\.?\d*)'
114
+ ],
115
+ 'entidad_destino': [
116
+ r'Entidad destino\s*([^\n]+)',
117
+ r'Destino\s*([^\n]+)',
118
+ r'Banco destino\s*([^\n]+)'
119
+ ],
120
+ 'comision': [
121
+ r'Comisión\s*S/\s*(\d+\.?\d*)',
122
+ r'Comision\s*S/\s*(\d+\.?\d*)'
123
+ ],
124
+ 'itf': [
125
+ r'ITF\s*S/\s*(\d+\.?\d*)'
126
+ ],
127
+ 'numero_operacion': [
128
+ r'Número de operación\s*(\d+)',
129
+ r'Numero de operacion\s*(\d+)',
130
+ r'Operación\s*(\d+)',
131
+ r'Nro\.\s*operación\s*(\d+)'
132
+ ],
133
+ 'tipo_operacion': [
134
+ r'Tipo de operación\s*([^\n]+)',
135
+ r'Tipo de operacion\s*([^\n]+)',
136
+ r'Operación\s*([^\n]+)'
137
+ ],
138
+ 'fecha': [
139
+ r'(\d{1,2}\s+\w+\s+\d{4},?\s+\d{1,2}:\d{2}\s*h?)',
140
+ r'(\d{1,2}/\d{1,2}/\d{4}\s+\d{1,2}:\d{2})',
141
+ r'(\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2})'
142
+ ],
143
+ 'estado_operacion': [
144
+ r'(Operación exitosa)',
145
+ r'(Operacion exitosa)',
146
+ r'(Exitosa)',
147
+ r'(Completada)',
148
+ r'(Aprobada)'
149
+ ]
150
+ }
151
+
152
+ # Buscar cada patrón en el texto
153
+ for field, pattern_list in patterns.items():
154
+ for pattern in pattern_list:
155
+ match = re.search(pattern, text, re.IGNORECASE)
156
+ if match:
157
+ fields[field] = match.group(1).strip()
158
+ break
159
+
160
+ # Búsquedas adicionales específicas
161
+ BankingDataExtractor._extract_account_numbers(text, fields)
162
+ BankingDataExtractor._extract_bank_names(text, fields)
163
+
164
+ return fields
165
+
166
+ @staticmethod
167
+ def _extract_account_numbers(text: str, fields: Dict[str, str]) -> None:
168
+ """Extrae números de cuenta del texto"""
169
+ # Buscar patrones de cuentas
170
+ account_patterns = [
171
+ r'•(\d{4})',
172
+ r'Cuenta\s*(\d+)',
173
+ r'Cta\.\s*(\d+)'
174
+ ]
175
+
176
+ accounts = []
177
+ for pattern in account_patterns:
178
+ matches = re.findall(pattern, text)
179
+ accounts.extend(matches)
180
+
181
+ if len(accounts) >= 2:
182
+ fields['cuenta_origen'] = accounts[0]
183
+ fields['cuenta_destino'] = accounts[1]
184
+ elif len(accounts) == 1:
185
+ fields['cuenta_origen'] = accounts[0]
186
+
187
+ @staticmethod
188
+ def _extract_bank_names(text: str, fields: Dict[str, str]) -> None:
189
+ """Extrae nombres de bancos del texto"""
190
+ bank_names = ['BBVA', 'Plin', 'BCP', 'Interbank', 'Scotiabank', 'BanBif']
191
+
192
+ for bank in bank_names:
193
+ if bank.lower() in text.lower():
194
+ if not fields['entidad_destino']:
195
+ fields['entidad_destino'] = bank
196
+ break
197
+
198
+ def display_extracted_banking_data(fields: Dict[str, str]) -> None:
199
+ """Muestra los datos extraídos del comprobante bancario de forma estructurada"""
200
+ st.subheader("🏦 Información Extraída del Comprobante")
201
+
202
+ # Crear métricas principales
203
+ col1, col2, col3 = st.columns(3)
204
+
205
+ with col1:
206
+ if fields['importe_enviado']:
207
+ st.metric(
208
+ label="💰 Importe Enviado",
209
+ value=f"S/ {fields['importe_enviado']}" if fields['importe_enviado'] else "No detectado"
210
+ )
211
+
212
+ with col2:
213
+ if fields['entidad_destino']:
214
+ st.metric(
215
+ label="🏦 Entidad Destino",
216
+ value=fields['entidad_destino'] or "No detectado"
217
+ )
218
+
219
+ with col3:
220
+ if fields['estado_operacion']:
221
+ st.metric(
222
+ label="✅ Estado",
223
+ value=fields['estado_operacion'] or "No detectado"
224
+ )
225
+ st.subheader("📋 Detalle Completo")
226
+
227
+ data_rows = []
228
+ field_labels = {
229
+ 'importe_enviado': '💰 Importe Enviado',
230
+ 'entidad_destino': '🏦 Entidad Destino',
231
+ 'comision': '💳 Comisión',
232
+ 'itf': '📊 ITF',
233
+ 'numero_operacion': '🔢 Número de Operación',
234
+ 'tipo_operacion': '📝 Tipo de Operación',
235
+ 'fecha': '📅 Fecha y Hora',
236
+ 'cuenta_origen': '📤 Cuenta Origen',
237
+ 'cuenta_destino': '📥 Cuenta Destino',
238
+ 'estado_operacion': '✅ Estado Operación'
239
+ }
240
+
241
+ for field, label in field_labels.items():
242
+ value = fields.get(field, '')
243
+ status = "✅ Detectado" if value else "❌ No detectado"
244
+ data_rows.append({
245
+ 'Campo': label,
246
+ 'Valor': value or 'No encontrado',
247
+ 'Estado': status
248
+ })
249
+
250
+ df = pd.DataFrame(data_rows)
251
+
252
+ # Mostrar tabla con colores
253
+ st.dataframe(
254
+ df,
255
+ use_container_width=True,
256
+ hide_index=True,
257
+ column_config={
258
+ "Campo": st.column_config.TextColumn("Campo", width="medium"),
259
+ "Valor": st.column_config.TextColumn("Valor Extraído", width="large"),
260
+ "Estado": st.column_config.TextColumn("Estado", width="small")
261
+ }
262
+ )
263
+
264
+ if any(fields.values()):
265
+ # Crear JSON con los datos extraídos
266
+ export_data = {
267
+ 'timestamp': datetime.now().isoformat(),
268
+ 'campos_extraidos': fields,
269
+ 'resumen': {
270
+ 'total_campos': len(field_labels),
271
+ 'campos_detectados': len([v for v in fields.values() if v]),
272
+ 'porcentaje_completitud': len([v for v in fields.values() if v]) / len(field_labels) * 100
273
+ }
274
+ }
275
+
276
+ st.download_button(
277
+ label="📥 Descargar Datos Extraídos (JSON)",
278
+ data=json.dumps(export_data, indent=2, ensure_ascii=False),
279
+ file_name=f"comprobante_bancario_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json",
280
+ mime="application/json"
281
+ )
282
+
283
+ def process_banking_receipt(uploaded_file, analyzer: BankingReceiptAnalyzer) -> None:
284
+ """Procesa un comprobante bancario completo"""
285
+ try:
286
+ # Leer bytes del archivo
287
+ image_bytes = uploaded_file.read()
288
+
289
+ # Mostrar vista previa
290
+ st.subheader("🖼️ Vista Previa del Comprobante")
291
+ image = Image.open(io.BytesIO(image_bytes))
292
+ st.image(image, caption=f"Comprobante: {uploaded_file.name}", width=300)
293
+
294
+ # Crear tabs para diferentes métodos de análisis
295
+ tab1, tab2 = st.tabs(["📄 Análisis con Textract", "🔍 Extracción Simple"])
296
+
297
+ # Tab 1: Análisis con Textract Forms
298
+ with tab1:
299
+ st.info("📋 Usando Amazon Textract con análisis de formularios")
300
+ if st.button("Analizar con Textract", key="textract_btn", type="primary"):
301
+ with st.spinner("Analizando estructura del documento..."):
302
+ result = analyzer.analyze_document_with_forms(image_bytes)
303
+
304
+ if result["success"]:
305
+ st.success("✅ Análisis completado")
306
+
307
+ # Extraer texto de los bloques
308
+ text_blocks = []
309
+ for block in result["blocks"]:
310
+ if block['BlockType'] == 'LINE':
311
+ text_blocks.append(block['Text'])
312
+
313
+ full_text = '\n'.join(text_blocks)
314
+
315
+ # Extraer campos bancarios
316
+ banking_fields = BankingDataExtractor.extract_banking_fields(full_text)
317
+ display_extracted_banking_data(banking_fields)
318
+
319
+ # Mostrar texto completo en expandible
320
+ with st.expander("Ver texto completo extraído"):
321
+ st.text_area("Texto detectado:", full_text, height=300)
322
+ else:
323
+ st.error(f"❌ Error: {result['error']}")
324
+
325
+ # Tab 2: Extracción simple
326
+ with tab2:
327
+ st.info("🔍 Extracción simple de texto y análisis con patrones")
328
+ if st.button("Extracción Simple", key="simple_btn"):
329
+ with st.spinner("Extrayendo texto..."):
330
+ result = analyzer.extract_text_simple(image_bytes)
331
+
332
+ if result["success"]:
333
+ st.success("✅ Extracción completada")
334
+
335
+ # Extraer campos bancarios
336
+ banking_fields = BankingDataExtractor.extract_banking_fields(result["text"])
337
+ display_extracted_banking_data(banking_fields)
338
+
339
+ # Mostrar texto original
340
+ with st.expander("Ver texto extraído"):
341
+ st.text_area("Texto:", result["text"], height=200)
342
+ else:
343
+ st.error(f"❌ Error: {result['error']}")
344
+
345
+ except Exception as e:
346
+ st.error(f"❌ Error al procesar comprobante: {str(e)}")
347
+
348
+ def main():
349
+ """Función principal de la aplicación"""
350
+
351
+ # Título y descripción
352
+ st.title("🏦 Analizador de Comprobantes Bancarios")
353
+ st.markdown("""
354
+ Esta aplicación especializada extrae información específica de comprobantes bancarios usando:
355
+ - 📄 **Amazon Textract** con análisis de formularios
356
+ - 🔍 **Patrones de reconocimiento** específicos para datos bancarios
357
+ """)
358
+
359
+ # Inicializar analizador
360
+ analyzer = BankingReceiptAnalyzer()
361
+
362
+ if not analyzer.credentials_valid:
363
+ st.error("❌ No se pudieron cargar las credenciales de AWS")
364
+ st.stop()
365
+
366
+ # Sidebar con información
367
+ with st.sidebar:
368
+ st.header("🎯 Campos Detectables")
369
+ st.markdown("""
370
+ **Información Financiera:**
371
+ - 💰 Importe enviado
372
+ - 💳 Comisión
373
+ - 📊 ITF
374
+
375
+ **Datos de Operación:**
376
+ - 🔢 Número de operación
377
+ - 📝 Tipo de operación
378
+ - 📅 Fecha y hora
379
+ - ✅ Estado de operación
380
+
381
+ **Información de Cuentas:**
382
+ - 🏦 Entidad destino
383
+ - 📤 Cuenta origen
384
+ - 📥 Cuenta destino
385
+ """)
386
+
387
+ # Subida de archivos
388
+ st.header("📤 Subir Comprobante Bancario")
389
+ uploaded_file = st.file_uploader(
390
+ "Selecciona una imagen del comprobante bancario:",
391
+ type=['jpg', 'jpeg', 'png', 'pdf'],
392
+ help="Sube una imagen clara del comprobante para extraer la información automáticamente"
393
+ )
394
+
395
+ if uploaded_file is not None:
396
+ # Procesar archivo
397
+ if uploaded_file.type.startswith('image/'):
398
+ process_banking_receipt(uploaded_file, analyzer)
399
+ elif uploaded_file.type == 'application/pdf':
400
+ st.warning("⚠️ Los PDFs se procesarán como imágenes. Para mejores resultados, usa imágenes JPG/PNG.")
401
+ process_banking_receipt(uploaded_file, analyzer)
402
+ else:
403
+ st.error("❌ Formato no soportado. Usa JPG, PNG o PDF.")
404
+
405
+ # Información adicional
406
+ st.markdown("---")
407
+ st.header("📚 Información Adicional")
408
+
409
+ col1, col2 = st.columns(2)
410
+
411
+ with col1:
412
+ st.subheader("🏦 Bancos Soportados")
413
+ st.markdown("""
414
+ - BBVA
415
+ - Plin
416
+ - BCP
417
+ - Interbank
418
+ - Scotiabank
419
+ - BanBif
420
+ - Y otros...
421
+ """)
422
+
423
+ with col2:
424
+ st.subheader("📋 Tipos de Operación")
425
+ st.markdown("""
426
+ - Envío a contactos
427
+ - Transferencias
428
+ - Pagos de servicios
429
+ - Recargas
430
+ - Y otros...
431
+ """)
432
+
433
+ # Footer
434
+ st.markdown("---")
435
+ st.markdown("""
436
+ <div style='text-align: center; color: #666;'>
437
+ <p>🏦 Analizador de Comprobantes Bancarios - Desarrollado con Streamlit y AWS por <a href="https://github.com/JoseJeampierJaraSalas1997" target="_blank">@JoseJeampierJaraSalas1997</a></p>
438
+ </div>
439
+ """, unsafe_allow_html=True)
440
+
441
+ if __name__ == "__main__":
442
+ main()
requirements.txt CHANGED
@@ -1,3 +1,5 @@
1
- altair
2
- pandas
3
- streamlit
 
 
 
1
+ streamlit
2
+ boto3
3
+ botocore
4
+ Pillow
5
+ PyPDF2