Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -92,17 +92,13 @@ def extraer_precio(texto, operacion):
|
|
| 92 |
return 0
|
| 93 |
|
| 94 |
def extraer_ubicacion(texto):
|
| 95 |
-
# Separa por saltos de línea y busca la que parezca una dirección real
|
| 96 |
lineas = [l.strip() for l in texto.split('\n') if len(l.strip()) > 4]
|
| 97 |
for linea in lineas:
|
| 98 |
-
# Si tiene precio, o dice hab/baño, la ignoramos
|
| 99 |
if "$" in linea or re.search(r'(?i)(hab|baño|m2|m²)', linea): continue
|
| 100 |
-
# Si tiene una coma (ej: La Concepcion, Barranquilla) es la ubicación
|
| 101 |
if "," in linea or " en " in linea.lower():
|
| 102 |
limpio = re.sub(r'(?i)(apartamento|casa|bodega|lote|oficina)\s+en\s+(arriendo|venta)\s+(en\s+)?', '', linea)
|
| 103 |
return limpio[:60].strip()
|
| 104 |
|
| 105 |
-
# Respaldo si no encuentra coma
|
| 106 |
for linea in lineas[1:4]:
|
| 107 |
if "$" not in linea and not re.search(r'\d', linea):
|
| 108 |
return linea[:60]
|
|
@@ -113,10 +109,8 @@ def es_inmueble_valido(href, portal):
|
|
| 113 |
if not href or "javascript" in href or "blog" in href or "proyectos" in href:
|
| 114 |
return False
|
| 115 |
if portal == "FR":
|
| 116 |
-
# Valida que termine en un ID numérico largo (ej: /193374728)
|
| 117 |
if re.search(r'/\d{7,10}$', href) or "arriendo-en" in href or "venta-en" in href: return True
|
| 118 |
elif portal == "MC":
|
| 119 |
-
# Valida que sea un inmueble de metrocuadrado
|
| 120 |
if "/inmueble/" in href or "-id-" in href: return True
|
| 121 |
return False
|
| 122 |
|
|
@@ -124,7 +118,7 @@ def es_inmueble_valido(href, portal):
|
|
| 124 |
def motor_tramitia_visual(operacion, barrio, ciudad, area, m2_min, m2_max, tipo, hab, ban, park, antiguedad, ascensor, piscina):
|
| 125 |
resultados = []
|
| 126 |
log_visible = ""
|
| 127 |
-
urls_vistas = set()
|
| 128 |
|
| 129 |
try:
|
| 130 |
url_fr, url_mc = construir_urls_final(operacion, barrio, ciudad, tipo, hab, ban, park, antiguedad, m2_min, m2_max, ascensor, piscina)
|
|
@@ -153,13 +147,11 @@ def motor_tramitia_visual(operacion, barrio, ciudad, area, m2_min, m2_max, tipo,
|
|
| 153 |
if cont_fr >= 12: break
|
| 154 |
try:
|
| 155 |
href = el.get_attribute("href")
|
| 156 |
-
# FILTRO SNIPER: Si es blog o basura, lo salta al instante
|
| 157 |
if not es_inmueble_valido(href, "FR"): continue
|
| 158 |
|
| 159 |
full_url = f"https://www.fincaraiz.com.co{href}" if href.startswith("/") else href
|
| 160 |
-
if full_url in urls_vistas: continue
|
| 161 |
|
| 162 |
-
# CAPTURA LA TARJETA COMPLETA LIMPIAMENTE
|
| 163 |
card = el.evaluate_handle("el => el.closest('article') || el.closest('[class*=\"card\"]') || el.parentElement.parentElement")
|
| 164 |
if not card: continue
|
| 165 |
|
|
@@ -212,7 +204,6 @@ def motor_tramitia_visual(operacion, barrio, ciudad, area, m2_min, m2_max, tipo,
|
|
| 212 |
full_url = f"https://www.metrocuadrado.com{href}" if href.startswith("/") else href
|
| 213 |
if full_url in urls_vistas: continue
|
| 214 |
|
| 215 |
-
# CAPTURA LA TARJETA COMPLETA DE MC
|
| 216 |
card = el.evaluate_handle("el => el.closest('li') || el.closest('[class*=\"card\"]') || el.closest('[class*=\"property\"]') || el.parentElement.parentElement.parentElement")
|
| 217 |
if not card: continue
|
| 218 |
|
|
@@ -247,7 +238,7 @@ def motor_tramitia_visual(operacion, barrio, ciudad, area, m2_min, m2_max, tipo,
|
|
| 247 |
if not resultados:
|
| 248 |
return f"{log_visible}\n❌ NO SE ENCONTRARON DATOS. (Filtros muy estrictos)", pd.DataFrame(), None, "---"
|
| 249 |
|
| 250 |
-
# --- SELECCIÓN FINAL
|
| 251 |
df_final_completo = pd.DataFrame(resultados)
|
| 252 |
|
| 253 |
df_fr = df_final_completo[df_final_completo['Portal'] == 'Finca Raiz'].head(6)
|
|
@@ -259,7 +250,7 @@ def motor_tramitia_visual(operacion, barrio, ciudad, area, m2_min, m2_max, tipo,
|
|
| 259 |
|
| 260 |
log_visible += f"\n✨ PROCESANDO PDF CON {len(df_final)} INMUEBLES REALES..."
|
| 261 |
|
| 262 |
-
# --- PDF VISUAL
|
| 263 |
pdf_path = f"Reporte_Visual_{int(time.time())}.pdf"
|
| 264 |
pdf = FPDF()
|
| 265 |
pdf.add_page()
|
|
@@ -323,7 +314,7 @@ def motor_tramitia_visual(operacion, barrio, ciudad, area, m2_min, m2_max, tipo,
|
|
| 323 |
|
| 324 |
pdf.output(pdf_path)
|
| 325 |
|
| 326 |
-
# --- CÁLCULOS
|
| 327 |
promedio = df_final['Precio_M2'].mean() * area
|
| 328 |
resumen = (
|
| 329 |
f"💰 **ESTIMACIÓN DE {operacion.upper()}**\n"
|
|
@@ -333,8 +324,12 @@ def motor_tramitia_visual(operacion, barrio, ciudad, area, m2_min, m2_max, tipo,
|
|
| 333 |
f"📈 Máximo en Zona: ${df_final['Precio'].max():,.0f}"
|
| 334 |
)
|
| 335 |
|
| 336 |
-
#
|
| 337 |
-
df_mostrar = df_final[['Portal', 'Precio', 'Precio_M2', 'Ubicacion', 'Descripcion', 'URL']]
|
|
|
|
|
|
|
|
|
|
|
|
|
| 338 |
|
| 339 |
return f"{log_visible}\n✅ PDF Generado Exitosamente.", df_mostrar, pdf_path, resumen
|
| 340 |
|
|
@@ -344,7 +339,7 @@ def motor_tramitia_visual(operacion, barrio, ciudad, area, m2_min, m2_max, tipo,
|
|
| 344 |
|
| 345 |
# --- INTERFAZ GRÁFICA ---
|
| 346 |
with gr.Blocks() as demo:
|
| 347 |
-
gr.Markdown("## 📸 TramitIA Pro: Generador Visual (
|
| 348 |
|
| 349 |
with gr.Row():
|
| 350 |
with gr.Column(scale=1):
|
|
|
|
| 92 |
return 0
|
| 93 |
|
| 94 |
def extraer_ubicacion(texto):
|
|
|
|
| 95 |
lineas = [l.strip() for l in texto.split('\n') if len(l.strip()) > 4]
|
| 96 |
for linea in lineas:
|
|
|
|
| 97 |
if "$" in linea or re.search(r'(?i)(hab|baño|m2|m²)', linea): continue
|
|
|
|
| 98 |
if "," in linea or " en " in linea.lower():
|
| 99 |
limpio = re.sub(r'(?i)(apartamento|casa|bodega|lote|oficina)\s+en\s+(arriendo|venta)\s+(en\s+)?', '', linea)
|
| 100 |
return limpio[:60].strip()
|
| 101 |
|
|
|
|
| 102 |
for linea in lineas[1:4]:
|
| 103 |
if "$" not in linea and not re.search(r'\d', linea):
|
| 104 |
return linea[:60]
|
|
|
|
| 109 |
if not href or "javascript" in href or "blog" in href or "proyectos" in href:
|
| 110 |
return False
|
| 111 |
if portal == "FR":
|
|
|
|
| 112 |
if re.search(r'/\d{7,10}$', href) or "arriendo-en" in href or "venta-en" in href: return True
|
| 113 |
elif portal == "MC":
|
|
|
|
| 114 |
if "/inmueble/" in href or "-id-" in href: return True
|
| 115 |
return False
|
| 116 |
|
|
|
|
| 118 |
def motor_tramitia_visual(operacion, barrio, ciudad, area, m2_min, m2_max, tipo, hab, ban, park, antiguedad, ascensor, piscina):
|
| 119 |
resultados = []
|
| 120 |
log_visible = ""
|
| 121 |
+
urls_vistas = set()
|
| 122 |
|
| 123 |
try:
|
| 124 |
url_fr, url_mc = construir_urls_final(operacion, barrio, ciudad, tipo, hab, ban, park, antiguedad, m2_min, m2_max, ascensor, piscina)
|
|
|
|
| 147 |
if cont_fr >= 12: break
|
| 148 |
try:
|
| 149 |
href = el.get_attribute("href")
|
|
|
|
| 150 |
if not es_inmueble_valido(href, "FR"): continue
|
| 151 |
|
| 152 |
full_url = f"https://www.fincaraiz.com.co{href}" if href.startswith("/") else href
|
| 153 |
+
if full_url in urls_vistas: continue
|
| 154 |
|
|
|
|
| 155 |
card = el.evaluate_handle("el => el.closest('article') || el.closest('[class*=\"card\"]') || el.parentElement.parentElement")
|
| 156 |
if not card: continue
|
| 157 |
|
|
|
|
| 204 |
full_url = f"https://www.metrocuadrado.com{href}" if href.startswith("/") else href
|
| 205 |
if full_url in urls_vistas: continue
|
| 206 |
|
|
|
|
| 207 |
card = el.evaluate_handle("el => el.closest('li') || el.closest('[class*=\"card\"]') || el.closest('[class*=\"property\"]') || el.parentElement.parentElement.parentElement")
|
| 208 |
if not card: continue
|
| 209 |
|
|
|
|
| 238 |
if not resultados:
|
| 239 |
return f"{log_visible}\n❌ NO SE ENCONTRARON DATOS. (Filtros muy estrictos)", pd.DataFrame(), None, "---"
|
| 240 |
|
| 241 |
+
# --- SELECCIÓN FINAL ---
|
| 242 |
df_final_completo = pd.DataFrame(resultados)
|
| 243 |
|
| 244 |
df_fr = df_final_completo[df_final_completo['Portal'] == 'Finca Raiz'].head(6)
|
|
|
|
| 250 |
|
| 251 |
log_visible += f"\n✨ PROCESANDO PDF CON {len(df_final)} INMUEBLES REALES..."
|
| 252 |
|
| 253 |
+
# --- PDF VISUAL ---
|
| 254 |
pdf_path = f"Reporte_Visual_{int(time.time())}.pdf"
|
| 255 |
pdf = FPDF()
|
| 256 |
pdf.add_page()
|
|
|
|
| 314 |
|
| 315 |
pdf.output(pdf_path)
|
| 316 |
|
| 317 |
+
# --- CÁLCULOS Y FORMATO DE TABLA ---
|
| 318 |
promedio = df_final['Precio_M2'].mean() * area
|
| 319 |
resumen = (
|
| 320 |
f"💰 **ESTIMACIÓN DE {operacion.upper()}**\n"
|
|
|
|
| 324 |
f"📈 Máximo en Zona: ${df_final['Precio'].max():,.0f}"
|
| 325 |
)
|
| 326 |
|
| 327 |
+
# Creamos una copia para formatear solo lo que se ve en pantalla
|
| 328 |
+
df_mostrar = df_final[['Portal', 'Precio', 'Precio_M2', 'Ubicacion', 'Descripcion', 'URL']].copy()
|
| 329 |
+
|
| 330 |
+
# Formateamos como moneda ($X,XXX) para que se vea impecable
|
| 331 |
+
df_mostrar['Precio'] = df_mostrar['Precio'].apply(lambda x: f"${x:,.0f}")
|
| 332 |
+
df_mostrar['Precio_M2'] = df_mostrar['Precio_M2'].apply(lambda x: f"${x:,.0f}")
|
| 333 |
|
| 334 |
return f"{log_visible}\n✅ PDF Generado Exitosamente.", df_mostrar, pdf_path, resumen
|
| 335 |
|
|
|
|
| 339 |
|
| 340 |
# --- INTERFAZ GRÁFICA ---
|
| 341 |
with gr.Blocks() as demo:
|
| 342 |
+
gr.Markdown("## 📸 TramitIA Pro: Generador Visual (Tabla Formateada)")
|
| 343 |
|
| 344 |
with gr.Row():
|
| 345 |
with gr.Column(scale=1):
|