Spaces:
Sleeping
Sleeping
File size: 5,677 Bytes
0a6b0fb |
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 |
# dollar_correction.py
# Proceso independiente para correcci贸n de confusi贸n $ vs 8
import re
from typing import Dict, List
class DollarSignCorrectionProcessor:
"""
Proceso independiente para corregir confusiones del OCR entre $ y 8.
Similar al proceso multilinea, puede ser aplicado a cualquier proveedor.
"""
def __init__(self, config: Dict = None):
"""
Args:
config: Configuraci贸n del procesador
- aggressive: bool - Si True, aplica correcciones m谩s agresivas
- context_aware: bool - Si True, usa contexto para decidir correcciones
- min_confidence: float - Confianza m铆nima para aplicar correcci贸n
"""
self.config = config or {}
self.aggressive = self.config.get("aggressive", False)
self.context_aware = self.config.get("context_aware", True)
self.min_confidence = self.config.get("min_confidence", 0.7)
def process(self, text_blocks: List[Dict]) -> List[Dict]:
"""
Procesa los bloques de texto y corrige confusiones entre $ y 8.
Args:
text_blocks: Lista de bloques de texto del OCR
Returns:
Lista de bloques de texto corregidos
"""
corrected_blocks = []
corrections_made = 0
for block in text_blocks:
original_text = block['text']
corrected_text = self._correct_text(original_text, block)
if corrected_text != original_text:
corrections_made += 1
print(f"DEBUG: Correcci贸n $ vs 8: '{original_text}' -> '{corrected_text}'")
# Crear nuevo bloque con texto corregido
corrected_block = block.copy()
corrected_block['text'] = corrected_text
corrected_block['was_corrected'] = True
corrected_block['original_text'] = original_text
corrected_blocks.append(corrected_block)
else:
corrected_blocks.append(block)
print(f"INFO: Correcciones $ vs 8 aplicadas: {corrections_made} de {len(text_blocks)} bloques")
return corrected_blocks
def _correct_text(self, text: str, block: Dict) -> str:
"""
Aplica correcciones al texto bas谩ndose en patrones y contexto.
Args:
text: Texto a corregir
block: Bloque de texto con metadata (posici贸n, confianza, etc.)
Returns:
Texto corregido
"""
corrected = text
# Patr贸n 1: "8" seguido de n煤meros (probablemente es "$")
# Ejemplo: "8 12.99" -> "$ 12.99"
# Ejemplo: "812.99" -> "$12.99"
corrected = re.sub(
r'\b8\s*(\d+\.?\d*)\b',
lambda m: f"$ {m.group(1)}" if self._is_likely_price(m.group(1)) else m.group(0),
corrected
)
# Patr贸n 2: "8" al inicio de l铆nea seguido de espacio y n煤meros
# Ejemplo: "8 Total" -> "$ Total"
if self.context_aware:
corrected = re.sub(
r'^8\s+(Total|Subtotal|HST|Tax|Amount|Price)',
r'$ \1',
corrected,
flags=re.IGNORECASE
)
# Patr贸n 3: "8" en contexto de moneda (despu茅s de palabras clave)
# Ejemplo: "Total 8 123.45" -> "Total $ 123.45"
corrected = re.sub(
r'(Total|Subtotal|HST|Tax|Amount|Price|Cost)\s+8\s*(\d+\.?\d*)',
r'\1 $ \2',
corrected,
flags=re.IGNORECASE
)
# Patr贸n 4: M煤ltiples "8" en secuencia (probablemente "$")
# Ejemplo: "88" -> "$$" (raro pero posible)
if self.aggressive:
corrected = re.sub(r'88', '$$', corrected)
# Patr贸n 5: "8" entre espacios y n煤meros decimales
# Ejemplo: "Item 8 12.99 8 24.98" -> "Item $ 12.99 $ 24.98"
corrected = re.sub(
r'\s8\s+(\d+\.\d{2})\b',
r' $ \1',
corrected
)
# Patr贸n 6: "8" al final de palabra seguido de n煤meros
# Ejemplo: "Price8123.45" -> "Price$123.45"
corrected = re.sub(
r'([a-zA-Z])8(\d+\.?\d*)',
lambda m: f"{m.group(1)}${m.group(2)}" if self._is_likely_price(m.group(2)) else m.group(0),
corrected
)
# Patr贸n 7: "8" solo seguido de espacio y d铆gitos con decimales
# Ejemplo: "8 1.99" -> "$ 1.99"
corrected = re.sub(
r'\b8\s+(\d+\.\d{2})\b',
r'$ \1',
corrected
)
# Patr贸n 8: L铆neas que empiezan con "8" y tienen formato de precio
# Ejemplo: "8123.45" -> "$123.45"
corrected = re.sub(
r'^8(\d+\.\d{2})\b',
r'$\1',
corrected,
flags=re.MULTILINE
)
return corrected
def _is_likely_price(self, number_str: str) -> bool:
"""
Determina si un n煤mero es probablemente un precio.
Args:
number_str: String con el n煤mero
Returns:
True si parece un precio
"""
try:
value = float(number_str)
# Precios t铆picos: entre 0.01 y 10000
if value < 0.01 or value > 10000:
return False
# Si tiene 2 decimales, muy probable que sea precio
if '.' in number_str and len(number_str.split('.')[1]) == 2:
return True
# Si es un n煤mero redondo peque帽o, menos probable
if value < 10 and '.' not in number_str:
return False
return True
except ValueError:
return False |