spharagusnet 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 J. Sebastian Miño
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,394 @@
1
+ Metadata-Version: 2.4
2
+ Name: spharagusnet
3
+ Version: 0.2.0
4
+ Summary: Neural document OCR for Chilean territorial planning documents
5
+ Author: J. Sebastian Miño
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/jsmdev/spharagusnet
8
+ Project-URL: Repository, https://github.com/jsmdev/spharagusnet
9
+ Project-URL: Issues, https://github.com/jsmdev/spharagusnet/issues
10
+ Keywords: ocr,neural-network,chile,urban-planning,document-extraction
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Intended Audience :: Science/Research
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Topic :: Scientific/Engineering :: Image Recognition
20
+ Classifier: Topic :: Text Processing :: General
21
+ Requires-Python: >=3.10
22
+ Description-Content-Type: text/markdown
23
+ License-File: LICENSE
24
+ Requires-Dist: Pillow>=10.0.0
25
+ Requires-Dist: pytesseract>=0.3.13
26
+ Requires-Dist: pymupdf>=1.24.0
27
+ Requires-Dist: torch>=2.2.0
28
+ Requires-Dist: requests>=2.31.0
29
+ Requires-Dist: tqdm>=4.66.0
30
+ Provides-Extra: train
31
+ Requires-Dist: pdfplumber>=0.11.0; extra == "train"
32
+ Requires-Dist: PyPDF2>=3.0.0; extra == "train"
33
+ Requires-Dist: python-Levenshtein>=0.25.0; extra == "train"
34
+ Requires-Dist: pandas>=2.0.0; extra == "train"
35
+ Requires-Dist: numpy>=1.26.0; extra == "train"
36
+ Provides-Extra: dev
37
+ Requires-Dist: spharagusnet[train]; extra == "dev"
38
+ Requires-Dist: build>=1.0.0; extra == "dev"
39
+ Requires-Dist: twine>=5.0.0; extra == "dev"
40
+ Dynamic: license-file
41
+
42
+ # SpharagusNet
43
+
44
+ ![SpharagusNet Logo](ChatGPT%20Image%20Mar%2011,%202026,%2002_30_29%20AM.png)
45
+
46
+ ## Sobre el Nombre
47
+
48
+ **SpharagusNet** combina dos figuras mitológicas que representan las capacidades del sistema:
49
+
50
+ - **Sphinx** (Esfinge): La criatura que lee enigmas y extrae significado. Representa la capacidad del sistema para procesar documentos complejos y extraer información relevante de textos escaneados, interpretando el contenido legal y normativo de los instrumentos de planificación territorial.
51
+
52
+ - **Argus** (Argos): El gigante de 100 ojos que todo lo ve. Representa la capacidad del sistema para observar y procesar múltiples fuentes de información simultáneamente.
53
+
54
+ Juntos, **SpharagusNet** es un sistema que observa todo (Argus) y extrae significado (Sphinx) de los documentos de planificación territorial de Chile.
55
+
56
+ ## ¿Por Qué no Solo OCR Convencional?
57
+
58
+ La diferencia es fundamental. **Tesseract OCR puro** extrae todo texto de una imagen: encabezados, números de página, pies, metadata, contenido real... **todo mezclado.**
59
+
60
+ Con documentos escaneados complejos, el resultado es **90% ruido, 10% contenido útil**.
61
+
62
+ ```
63
+ ┌─────────────────────────────────────────────┐
64
+ │ OCR CONVENCIONAL (Tesseract solo) │
65
+ ├─────────────────────────────────────────────┤
66
+ │ ES ÓN = PATA > Me A A E A AS │
67
+ │ 1 A sas "e . Cr, - . MN y │
68
+ │ Ps CINARIO SU TOC NTNURLICADE CHILE │
69
+ │ ; A Maries £5 de Septiémbre de 1990 Pág │
70
+ │ ... (caracteres aleatorios, basura) │
71
+ └─────────────────────────────────────────────┘
72
+ ❌ Inutilizable. 90% ruido, errores OCR severos.
73
+
74
+ ┌─────────────────────────────────────────────┐
75
+ │ CON RED NEURONAL (SpharagusNet) │
76
+ ├─────────────────────────────────────────────┤
77
+ │ Valparaíso, de Septiembre de Andrés Couve │
78
+ │ Rioseco, Subsecretario de Educación │
79
+ │ Ministerio de Educación AUTORIZA... │
80
+ │ Que es necesario establecer procedimientos │
81
+ │ que permitan una eficaz inserción de... │
82
+ └─────────────────────────────────────────────┘
83
+ ✅ Legible. 85% contenido relevante, 15% ruido residual.
84
+ ```
85
+
86
+ ### ¿Cómo? La red **aprende a clasificar**
87
+
88
+ La red neuronal no "mejora" Tesseract. En cambio:
89
+
90
+ 1. **Tesseract extrae** todo texto y metadatos
91
+ 2. **Red neuronal clasifica** cada bloque: ¿es relevante o basura?
92
+ 3. **Mantiene solo lo relevante**, descarta el resto
93
+
94
+ **Entrenada con 100+ documentos legislativos**, la red aprendió:
95
+ - Qué se parece a "Artículo", "inciso", "párrafo" (patrones legislativos)
96
+ - Qué es "Diario Oficial", "Página 5", números aislados (metadata)
97
+ - Qué es ruido puro (caracteres aleatorios, errores OCR)
98
+
99
+ ### Resultado: Texto Procesable
100
+
101
+ | Métrica | OCR Puro | SpharagusNet |
102
+ |---------|----------|--------------|
103
+ | **Contenido útil** | 10% | 85% |
104
+ | **Ruido/Basura** | 90% | 15% |
105
+ | **Usable para NLP** | ❌ No | ✅ Sí |
106
+ | **Extracción de datos** | ❌ Falla | ✅ Funciona |
107
+ | **Análisis sintáctico** | ❌ Imposible | ✅ Posible |
108
+ | **Buscabilidad** | ❌ Pobre | ✅ Excelente |
109
+
110
+ ### Ventajas Prácticas
111
+
112
+ ✅ **Mejor ratio signal-to-noise:** La red filtra ~80% del ruido antes de que salga del pipeline
113
+
114
+ ✅ **Dominio específico:** Entrenada en documentos legislativos chilenos (MINVU, LeyChile), entiende la estructura y vocabulario
115
+
116
+ ✅ **Adaptativo:** Con más datos de entrenamiento, la red mejora automáticamente. Las heurísticas hardcodeadas requieren cambios manuales
117
+
118
+ ✅ **Contextual:** Entiende que "Diario" en "Diario de Implementación" es relevante, pero "Diario Oficial" en header es basura
119
+
120
+ ✅ **Métricas medibles:** Accuracy, Precision, Recall, F1 por epoch. Sabes exactamente qué tan bien está funcionando
121
+
122
+ ## Instalación
123
+
124
+ ### 1. Dependencia de sistema: Tesseract OCR
125
+
126
+ `pytesseract` es solo un wrapper Python — el binario `tesseract` debe estar instalado en el sistema operativo:
127
+
128
+ **Ubuntu / Debian / WSL:**
129
+ ```bash
130
+ sudo apt install tesseract-ocr tesseract-ocr-spa
131
+ ```
132
+
133
+ **macOS:**
134
+ ```bash
135
+ brew install tesseract tesseract-lang
136
+ ```
137
+
138
+ **Windows (nativo):**
139
+ Descarga el instalador desde [UB-Mannheim/tesseract](https://github.com/UB-Mannheim/tesseract/wiki) y asegúrate de marcar el idioma **Spanish** durante la instalación.
140
+
141
+ Verifica que quedó bien instalado:
142
+ ```bash
143
+ tesseract --version
144
+ tesseract --list-langs # debe aparecer "spa"
145
+ ```
146
+
147
+ ### 2. Instalar el paquete
148
+
149
+ ```bash
150
+ pip install spharagusnet
151
+ ```
152
+
153
+ Primera vez — descargar el modelo pre-entrenado (~300 MB):
154
+
155
+ ```bash
156
+ spharagusnet download
157
+ ```
158
+
159
+ Para desarrollo local (editable):
160
+
161
+ ```bash
162
+ git clone https://github.com/jsmdev/spharagusnet.git
163
+ cd spharagusnet
164
+ pip install -e ".[train]"
165
+ ```
166
+
167
+ ## Uso
168
+
169
+ ### Como librería
170
+
171
+ ```python
172
+ import spharagusnet
173
+
174
+ # Descargar modelo (primera vez, después se cachea)
175
+ spharagusnet.download_model()
176
+
177
+ # Extraer texto
178
+ texto = spharagusnet.extract("documento_escaneado.pdf")
179
+ texto = spharagusnet.extract("documento.pdf", confidence=0.6)
180
+
181
+ # Verificar si el modelo está disponible
182
+ spharagusnet.model_is_available() # True/False
183
+ ```
184
+
185
+ ### CLI
186
+
187
+ ```bash
188
+ # Extraer texto de un PDF
189
+ spharagusnet extract documento.pdf
190
+ spharagusnet extract documento.pdf -o salida.txt
191
+ spharagusnet extract documento.pdf --confidence 0.6
192
+
193
+ # Descargar/actualizar modelo
194
+ spharagusnet download
195
+ spharagusnet download --force
196
+
197
+ # Info del paquete
198
+ spharagusnet info
199
+ ```
200
+
201
+ ### Buscar documentos en BCN vía SPARQL
202
+
203
+ ```bash
204
+ # Solo comunas de comunas_interes.txt
205
+ python scripts/bcn_sparql_planes.py
206
+
207
+ # Todas las comunas del CSV
208
+ python scripts/bcn_sparql_planes.py --todas
209
+ ```
210
+
211
+ > **Nota:** El script solo incluye registros cuya columna `urls_documentos` contenga un link de `instrumentosdeplanificacion.minvu.cl`. Registros sin URL de MINVU (en desarrollo, históricos sin digitalizar, o alojados en sitios municipales) se omiten del CSV de salida.
212
+
213
+ ### Preparar dataset y entrenar modelo
214
+
215
+ ```bash
216
+ # 1. Preparar dataset (descarga PDFs, genera imágenes, cachea OCR y etiqueta bloques)
217
+ python scripts/preparar_dataset_entrenamiento.py [--max-pares N]
218
+
219
+ # 2. Entrenar modelo (con métricas en consola)
220
+ python scripts/entrenar_modelo_extraccion.py
221
+
222
+ # 3. Extraer texto de un PDF escaneado (con modelo entrenado)
223
+ python scripts/extraer_texto_con_modelo.py <ruta_pdf> [salida.txt] [--confidence 0.5]
224
+ ```
225
+
226
+ ### Mejorar el modelo iterativamente
227
+
228
+ ```bash
229
+ # 1. Incrementar datos gradualmente (50 → 100 → 200 → todos)
230
+ python scripts/preparar_dataset_entrenamiento.py --max-pares 80
231
+
232
+ # 2. Entrenar sobre lo existente
233
+ python scripts/entrenar_modelo_extraccion.py --resume
234
+
235
+ # 3. Si el val-F1 mejora, genial. Si estanca:
236
+ # - Agregar más datos (paso 1 con más pares)
237
+ # - Regenerar labels: borrar los .labels.json y correr paso 1 de nuevo
238
+ # - Ajustar patience/epochs
239
+
240
+ # 4. Probar en un documento nuevo
241
+ python scripts/extraer_texto_con_modelo.py nuevo.pdf salida.txt
242
+ ```
243
+
244
+ #### `preparar_dataset_entrenamiento.py`
245
+ - `--max-pares N` limita la cantidad de filas a procesar (por defecto todas).
246
+ - **Incremental:** solo descarga/procesa pares nuevos; los ya existentes se saltan.
247
+ - **Cache OCR:** guarda bloques Tesseract como `.ocr.json` junto a cada imagen, así el entrenamiento posterior no re-corre OCR.
248
+ - **Etiquetado mejorado:** usa trigramas + similitud Levenshtein para decidir relevancia (en vez de overlap de palabras sueltas que matchea "de", "la", etc.).
249
+ - Convierte PDFs página por página a 200 DPI para evitar consumo de RAM excesivo en WSL.
250
+ - Exige par completo (PDF LeyChile + PDF MINVU + imágenes generadas); archivos huérfanos se eliminan automáticamente.
251
+
252
+ #### `entrenar_modelo_extraccion.py`
253
+ - `--resume`: carga el último checkpoint y continúa entrenando (no parte de cero). Expande el vocabulario automáticamente si hay palabras nuevas.
254
+ - `--epochs N`: número de epochs (default: 20).
255
+ - `--patience N`: early stopping patience (default: 5).
256
+ - **Carga desde cache:** lee `.labels.json` generados por `preparar_dataset_entrenamiento.py` en vez de re-correr OCR.
257
+ - **Métricas por epoch:** `Loss`, `Accuracy`, `Precision`, `Recall`, `F1` en train y validación.
258
+ - Guarda:
259
+ - `modelo_entrenado.pth` (mejor modelo por F1)
260
+ - `vocab.json` (vocabulario para tokenización)
261
+ - `historial_entrenamiento.json` (métricas para análisis)
262
+
263
+ **Arquitectura:**
264
+ - Embedding layer (vocab → 512-D vectors)
265
+ - Block classifier (2 capas FC con ReLU + dropout) → clasificación binaria {irrelevante, relevante}
266
+ - LSTM (generador de texto, para futuras extensiones)
267
+ - **Class weights** para compensar desbalance (más bloques irrelevantes que relevantes)
268
+
269
+ #### `extraer_texto_con_modelo.py`
270
+ **Flujo de inferencia:**
271
+ 1. PDF escaneado → OCR (Tesseract) extrae bloques de texto
272
+ 2. Cada bloque → Tokenización + Embedding + Red neuronal
273
+ 3. Red predice: 0 (irrelevante) ó 1 (relevante)
274
+ 4. Reconstruye documento solo con bloques relevantes
275
+
276
+ **Parámetros:**
277
+ - `--confidence THRESHOLD`: Umbral de confianza [0-1]
278
+ - Default: 0.5 (balance entre precision/recall)
279
+ - Menor threshold → más bloques (recall ↑, pero más falsos positivos)
280
+ - Mayor threshold → menos bloques (precision ↑, pero pierdes contenido)
281
+
282
+ **Fallback:** Si el modelo no está disponible, usa heurísticas (filtros manuales)
283
+
284
+ ### Visualizar pipeline completo
285
+
286
+ ```bash
287
+ python scripts/pipeline_completo.py
288
+ ```
289
+
290
+ Muestra documentación completa del flujo, arquitectura y ejemplos de ejecución.
291
+
292
+ ## Arquitectura de la Red Neuronal
293
+
294
+ ### Diagrama del Flujo de Inferencia
295
+
296
+ ```
297
+ ┌──────────────────────────────────────────────────────────┐
298
+ │ PDF MINVU (escaneado) │
299
+ └────────────────────────┬─────────────────────────────────┘
300
+
301
+ ┌────────────────▼────────────────┐
302
+ │ 1. CONVERSIÓN PDF → IMÁGENES │
303
+ │ (page-by-page, 200 DPI) │
304
+ └────────────────┬─────────────────┘
305
+
306
+ ┌────────────────▼────────────────────────────────┐
307
+ │ Para cada página: │
308
+ │ │
309
+ │ ┌─ 2. OCR (Tesseract) │
310
+ │ │ Imagen → bloques de texto + coordenadas │
311
+ │ │ (filtro: confianza > 30%) │
312
+ │ │ │
313
+ │ │ [ │
314
+ │ │ {"texto": "Artículo 1", ...}, │
315
+ │ │ {"texto": "Página 1", ...}, │
316
+ │ │ {...} │
317
+ │ │ ] │
318
+ │ │ │
319
+ │ └─ 3. CLASIFICACIÓN (MODELO NEURONAL) │
320
+ │ Para cada bloque: │
321
+ │ a) Tokenizar → [idx_1, idx_2, ...] │
322
+ │ b) Embedding → 512-D vectors │
323
+ │ c) Pooling → reducir a (512,) │
324
+ │ d) Block Classifier (2 FC layers) │
325
+ │ e) Softmax → prob(relevante) │
326
+ │ │
327
+ │ ┌─────────────────────────────┐ │
328
+ │ │ Clasificador Binario: │ │
329
+ │ │ │ │
330
+ │ │ FC(512 → 256) ─ ReLU ─ │ │
331
+ │ │ Dropout(0.1) ─ FC(256 → 2) │ │
332
+ │ │ │ │
333
+ │ │ Output: [logit_neg, logit_pos]│ │
334
+ │ │ Pred: argmax() → {0, 1} │ │
335
+ │ └─────────────────────────────┘ │
336
+ │ │
337
+ │ └─ 4. FILTRADO │
338
+ │ Si pred=1 AND confidence >= threshold: │
339
+ │ → MANTENER bloque │
340
+ │ Sino: │
341
+ │ → DESCARTAR bloque │
342
+ │ │
343
+ └─────────────────┬──────────────────────────────┘
344
+
345
+ ┌─────────────────▼──────────────┐
346
+ │ 5. RECONSTRUCCIÓN │
347
+ │ Unir bloques relevantes │
348
+ │ + limpieza de espacios │
349
+ │ + separar por páginas │
350
+ └─────────────────┬──────────────┘
351
+
352
+ ┌─────────────────▼──────────────┐
353
+ │ 📄 TEXTO LIMPIO (formato │
354
+ │ LeyChile, sin headers/pies) │
355
+ └───────────────────────────────┘
356
+ ```
357
+
358
+ ### Métricas Reportadas During Training
359
+
360
+ La tabla de entrenamiento muestra:
361
+
362
+ ```
363
+ Epoch │ Loss Acc Prec Rec F1 │ vLoss vAcc vPrec vRec vF1 │ t ETA
364
+ 1/20 │ 0.6932 0.650 0.580 0.720 0.642 │ 0.6801 0.670 0.600 0.700 0.646 │ 2.3s 41.4s
365
+ 2/20 │ 0.5234 0.710 0.620 0.750 0.680 │ 0.5102 0.725 0.640 0.770 0.700 │ 2.1s 39.2s
366
+ 3/20 │ 0.4521 0.760 0.680 0.800 0.735 │ 0.4398 0.770 0.690 0.810 0.745 │ 2.0s 37.0s
367
+ ```
368
+
369
+ **Columnas:**
370
+ - `Epoch`: Época actual / total
371
+ - `Loss` / `vLoss`: Pérdida de entrenamiento / validación (menor es mejor)
372
+ - `Acc`: Accuracy (% bloques clasificados correctamente)
373
+ - `Prec`: Precision (% de positivos predichos que son realmente positivos)
374
+ - `Rec`: Recall (% de positivos reales que fueron detectados)
375
+ - `F1`: Media armónica de Precision y Recall (métrica de balance)
376
+ - `t`: Tiempo que tardó la época
377
+ - `ETA`: Tiempo estimado para terminar
378
+
379
+ **Early Stopping:** El entrenamiento se detiene automáticamente si `val-F1` no mejora durante 5 epochs consecutivos, previniendo overfitting.
380
+
381
+ ## Publicar en PyPI
382
+
383
+ ```bash
384
+ # 1. Subir modelo a GitHub Releases (tag v0.2.0)
385
+ # - modelo_entrenado.pth
386
+ # - vocab.json
387
+
388
+ # 2. Build
389
+ pip install build twine
390
+ python -m build
391
+
392
+ # 3. Publicar
393
+ twine upload dist/*
394
+ ```