jcalbornoz commited on
Commit
9243314
·
verified ·
1 Parent(s): 9dd2bda

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +54 -35
app.py CHANGED
@@ -27,7 +27,7 @@ except ImportError:
27
  subprocess.run(["pip", "install", "fake-useragent"], check=True)
28
  from fake_useragent import UserAgent
29
 
30
- # --- URL DEL GOBIERNO (WIKIPEDIA - LIBRE DE BLOQUEOS ANTI-BOTS) ---
31
  URL_LOGO_GOBIERNO = "https://upload.wikimedia.org/wikipedia/commons/thumb/c/c3/Escudo_de_Colombia.svg/250px-Escudo_de_Colombia.svg.png"
32
 
33
  def descargar_recurso(url, nombre_archivo):
@@ -41,7 +41,6 @@ def descargar_recurso(url, nombre_archivo):
41
  return None
42
 
43
  def preparar_entorno_pdf():
44
- # Descarga el escudo de Colombia si no existe
45
  if not os.path.exists("logo_gob.png"):
46
  descargar_recurso(URL_LOGO_GOBIERNO, "logo_gob.png")
47
 
@@ -111,21 +110,16 @@ def es_inmueble_valido(href, portal):
111
  # --- CLASE PDF MANUAL SAE ACTUALIZADA ---
112
  class PDF_SAE(FPDF):
113
  def header(self):
114
- # Escudo de Colombia a la izquierda
115
  if os.path.exists("logo_gob.png"):
116
  try: self.image("logo_gob.png", x=15, y=8, h=16)
117
  except: pass
118
-
119
- # LOGO SAE (El que tú subiste) a la derecha
120
- # Busca primero en PNG, luego en JPG por si acaso
121
  if os.path.exists("logo_sae.png"):
122
  try: self.image("logo_sae.png", x=155, y=8, w=40)
123
  except: pass
124
  elif os.path.exists("logo_sae.jpg"):
125
  try: self.image("logo_sae.jpg", x=155, y=8, w=40)
126
  except: pass
127
-
128
- self.ln(25) # Espacio base debajo de la cabecera
129
 
130
  def footer(self):
131
  self.set_y(-25)
@@ -220,15 +214,22 @@ def motor_tramitia_visual(operacion, barrio, ciudad, area, m2_min, m2_max, tipo,
220
 
221
  if df_final.empty: return f"{log_visible}\n❌ DATOS VACÍOS.", pd.DataFrame(), None, "---"
222
 
223
- # CÁLCULOS TÉCNICOS
224
- margen_negociacion = 0.08
225
  mediana_m2 = df_final['Precio_M2'].median()
226
  promedio_m2 = df_final['Precio_M2'].mean()
227
- valor_tecnico_m2 = mediana_m2 * (1 - margen_negociacion)
228
- valor_total_sugerido = valor_tecnico_m2 * area
 
 
 
 
 
 
 
 
229
 
230
  # --- GENERACIÓN DEL PDF ---
231
- preparar_entorno_pdf() # Asegura que esté el logo del gobierno
232
 
233
  pdf_path = f"Estudio_Mercado_SAE_{int(time.time())}.pdf"
234
  pdf = PDF_SAE()
@@ -236,6 +237,8 @@ def motor_tramitia_visual(operacion, barrio, ciudad, area, m2_min, m2_max, tipo,
236
  COLOR_ROSADO = (254, 25, 120)
237
  COLOR_GRIS = (137, 137, 137)
238
  COLOR_NEGRO = (0, 0, 0)
 
 
239
 
240
  # PÁGINA 1
241
  pdf.add_page()
@@ -257,33 +260,48 @@ def motor_tramitia_visual(operacion, barrio, ciudad, area, m2_min, m2_max, tipo,
257
  pdf.ln(10)
258
 
259
  pdf.set_font("Arial", 'B', 12); pdf.set_text_color(*COLOR_ROSADO)
260
- pdf.cell(0, 10, sanear_texto("2. METODOLOGIA"), ln=True)
261
  pdf.set_font("Arial", '', 11); pdf.set_text_color(*COLOR_NEGRO)
262
- pdf.multi_cell(0, 5, sanear_texto("Estudio deducido mediante la comparacion sistematica de ofertas recientes de inmuebles similares en la zona. Se ha aplicado un factor de comercializacion (Margen de Negociacion) del 8% sobre los precios de oferta para estimar el valor real de cierre contractual."))
263
 
264
- # PÁGINA 2
265
  pdf.add_page()
266
  pdf.set_font("Arial", 'B', 12); pdf.set_fill_color(*COLOR_ROSADO); pdf.set_text_color(255, 255, 255)
267
- pdf.cell(0, 10, sanear_texto(" 3. RESULTADOS ESTADISTICOS"), ln=True, fill=True)
268
  pdf.set_text_color(*COLOR_NEGRO); pdf.ln(5); pdf.set_font("Arial", '', 11)
269
 
270
- pdf.cell(80, 8, sanear_texto("Total Testigos Analizados:"), border=1)
 
271
  pdf.cell(50, 8, sanear_texto(f"{len(df_final)}"), border=1, ln=True, align='C')
272
- pdf.cell(80, 8, sanear_texto("Mediana Mercado (Oferta M2):"), border=1)
273
- pdf.cell(50, 8, sanear_texto(f"${mediana_m2:,.0f}"), border=1, ln=True, align='C')
274
- pdf.cell(80, 8, sanear_texto("Margen Negociacion:"), border=1)
275
- pdf.cell(50, 8, sanear_texto("8.00%"), border=1, ln=True, align='C')
 
 
 
 
 
 
276
  pdf.ln(10)
277
 
278
- pdf.set_font("Arial", 'B', 14); pdf.set_text_color(0, 100, 0)
279
- pdf.cell(0, 10, sanear_texto(f"VALOR {operacion.upper()} SUGERIDO (M2): ${valor_tecnico_m2:,.0f}"), ln=True)
280
- pdf.set_font("Arial", 'B', 16)
281
- pdf.cell(0, 12, sanear_texto(f"VALOR TOTAL DEL INMUEBLE: ${valor_total_sugerido:,.0f} COP"), ln=True)
 
 
 
 
 
 
 
 
282
 
283
  pdf.set_text_color(*COLOR_GRIS); pdf.ln(15); pdf.set_font("Arial", '', 8)
284
- pdf.multi_cell(0, 4, sanear_texto("Documento generado analiticamente como anexo tecnico referencial comercial."))
285
 
286
- # PÁGINA 3+
287
  pdf.add_page()
288
  pdf.set_font("Arial", 'B', 12); pdf.set_fill_color(*COLOR_GRIS); pdf.set_text_color(255, 255, 255)
289
  pdf.cell(0, 10, sanear_texto(" 4. ANEXO TECNICO: TESTIGOS COMPARABLES"), ln=True, fill=True)
@@ -313,17 +331,18 @@ def motor_tramitia_visual(operacion, barrio, ciudad, area, m2_min, m2_max, tipo,
313
 
314
  # --- CÁLCULOS INTERFAZ ---
315
  resumen = (
316
- f"🏢 **ESTUDIO DE MERCADO INSTITUCIONAL**\n"
317
- f"🔹 **Mediana Mercado:** ${mediana_m2:,.0f} / m2\n"
318
- f"📉 **Margen Negociación:** -8%\n"
319
- f" **VALOR TOTAL SUGERIDO:** ${valor_total_sugerido:,.0f}"
 
320
  )
321
 
322
  df_mostrar = df_final[['Portal', 'Precio', 'Precio_M2', 'Ubicacion', 'Descripcion', 'URL']].copy()
323
  df_mostrar['Precio'] = df_mostrar['Precio'].apply(lambda x: f"${x:,.0f}")
324
  df_mostrar['Precio_M2'] = df_mostrar['Precio_M2'].apply(lambda x: f"${x:,.0f}")
325
 
326
- return f"{log_visible}\n✅ Reporte Institucional Generado.", df_mostrar, pdf_path, resumen
327
 
328
  except Exception as error_fatal:
329
  traza = traceback.format_exc()
@@ -331,7 +350,7 @@ def motor_tramitia_visual(operacion, barrio, ciudad, area, m2_min, m2_max, tipo,
331
 
332
  # --- INTERFAZ GRÁFICA ---
333
  with gr.Blocks() as demo:
334
- gr.Markdown("## 🏢 TramitIA Pro: Estudio de Mercado Institucional (SAE)")
335
 
336
  with gr.Row():
337
  with gr.Column(scale=1):
@@ -353,7 +372,7 @@ with gr.Blocks() as demo:
353
  btn = gr.Button("GENERAR REPORTE NORMATIVO", variant="primary")
354
 
355
  with gr.Column(scale=2):
356
- res_fin = gr.Markdown("### 💰 Resumen Financiero...")
357
  with gr.Tabs():
358
  with gr.TabItem("Descargar Estudio Técnico (PDF)"): out_pdf = gr.File()
359
  with gr.TabItem("Matriz de Datos"): out_df = gr.Dataframe()
 
27
  subprocess.run(["pip", "install", "fake-useragent"], check=True)
28
  from fake_useragent import UserAgent
29
 
30
+ # --- URL DEL GOBIERNO ---
31
  URL_LOGO_GOBIERNO = "https://upload.wikimedia.org/wikipedia/commons/thumb/c/c3/Escudo_de_Colombia.svg/250px-Escudo_de_Colombia.svg.png"
32
 
33
  def descargar_recurso(url, nombre_archivo):
 
41
  return None
42
 
43
  def preparar_entorno_pdf():
 
44
  if not os.path.exists("logo_gob.png"):
45
  descargar_recurso(URL_LOGO_GOBIERNO, "logo_gob.png")
46
 
 
110
  # --- CLASE PDF MANUAL SAE ACTUALIZADA ---
111
  class PDF_SAE(FPDF):
112
  def header(self):
 
113
  if os.path.exists("logo_gob.png"):
114
  try: self.image("logo_gob.png", x=15, y=8, h=16)
115
  except: pass
 
 
 
116
  if os.path.exists("logo_sae.png"):
117
  try: self.image("logo_sae.png", x=155, y=8, w=40)
118
  except: pass
119
  elif os.path.exists("logo_sae.jpg"):
120
  try: self.image("logo_sae.jpg", x=155, y=8, w=40)
121
  except: pass
122
+ self.ln(25)
 
123
 
124
  def footer(self):
125
  self.set_y(-25)
 
214
 
215
  if df_final.empty: return f"{log_visible}\n❌ DATOS VACÍOS.", pd.DataFrame(), None, "---"
216
 
217
+ # --- CÁLCULOS TÉCNICOS Y RANGOS DE NEGOCIACIÓN ---
 
218
  mediana_m2 = df_final['Precio_M2'].median()
219
  promedio_m2 = df_final['Precio_M2'].mean()
220
+
221
+ minimo_zona = df_final['Precio'].min()
222
+ maximo_zona = df_final['Precio'].max()
223
+
224
+ mediana_total = mediana_m2 * area
225
+
226
+ # Bandas de negociación (Aplicadas sobre la Mediana del mercado)
227
+ valor_maximo_neg = mediana_total * 0.95 # Techo (Castigo 5%)
228
+ valor_optimo_neg = mediana_total * 0.92 # Centro (Castigo 8%)
229
+ valor_minimo_neg = mediana_total * 0.90 # Piso (Castigo 10%)
230
 
231
  # --- GENERACIÓN DEL PDF ---
232
+ preparar_entorno_pdf()
233
 
234
  pdf_path = f"Estudio_Mercado_SAE_{int(time.time())}.pdf"
235
  pdf = PDF_SAE()
 
237
  COLOR_ROSADO = (254, 25, 120)
238
  COLOR_GRIS = (137, 137, 137)
239
  COLOR_NEGRO = (0, 0, 0)
240
+ COLOR_VERDE = (0, 128, 0)
241
+ COLOR_ROJO = (200, 0, 0)
242
 
243
  # PÁGINA 1
244
  pdf.add_page()
 
260
  pdf.ln(10)
261
 
262
  pdf.set_font("Arial", 'B', 12); pdf.set_text_color(*COLOR_ROSADO)
263
+ pdf.cell(0, 10, sanear_texto("2. METODOLOGIA Y COMERCIALIZACION"), ln=True)
264
  pdf.set_font("Arial", '', 11); pdf.set_text_color(*COLOR_NEGRO)
265
+ pdf.multi_cell(0, 5, sanear_texto("Estudio deducido mediante la comparacion sistematica de ofertas recientes de inmuebles similares en la zona. Para aislar los precios especulativos de oferta en internet y llegar al valor real de transaccion, se aplican bandas de negociacion sobre la mediana del mercado (Techo del -5%, Optimo del -8% y Piso del -10%)."))
266
 
267
+ # PÁGINA 2: CONCLUSIONES Y BANDAS DE NEGOCIACIÓN
268
  pdf.add_page()
269
  pdf.set_font("Arial", 'B', 12); pdf.set_fill_color(*COLOR_ROSADO); pdf.set_text_color(255, 255, 255)
270
+ pdf.cell(0, 10, sanear_texto(" 3. RESULTADOS ESTADISTICOS Y RANGOS"), ln=True, fill=True)
271
  pdf.set_text_color(*COLOR_NEGRO); pdf.ln(5); pdf.set_font("Arial", '', 11)
272
 
273
+ ancho_col = 80
274
+ pdf.cell(ancho_col, 8, sanear_texto("Total Testigos Analizados:"), border=1)
275
  pdf.cell(50, 8, sanear_texto(f"{len(df_final)}"), border=1, ln=True, align='C')
276
+
277
+ pdf.cell(ancho_col, 8, sanear_texto("Oferta mas economica de la zona:"), border=1)
278
+ pdf.cell(50, 8, sanear_texto(f"${minimo_zona:,.0f}"), border=1, ln=True, align='C')
279
+
280
+ pdf.cell(ancho_col, 8, sanear_texto("Oferta mas costosa de la zona:"), border=1)
281
+ pdf.cell(50, 8, sanear_texto(f"${maximo_zona:,.0f}"), border=1, ln=True, align='C')
282
+
283
+ pdf.set_font("Arial", 'B', 11)
284
+ pdf.cell(ancho_col, 8, sanear_texto("Mediana Bruta (Sin Descuentos):"), border=1)
285
+ pdf.cell(50, 8, sanear_texto(f"${mediana_total:,.0f}"), border=1, ln=True, align='C')
286
  pdf.ln(10)
287
 
288
+ # BLOQUE DE RANGOS DE NEGOCIACIÓN
289
+ pdf.set_font("Arial", 'B', 14); pdf.set_text_color(*COLOR_ROSADO)
290
+ pdf.cell(0, 10, sanear_texto("RANGOS DE NEGOCIACION AUTORIZADOS (CIERRE):"), ln=True)
291
+
292
+ pdf.set_font("Arial", 'B', 12); pdf.set_text_color(*COLOR_GRIS)
293
+ pdf.cell(0, 8, sanear_texto(f"TECHO MAXIMO ESPERADO (Castigo 5%): ${valor_maximo_neg:,.0f} COP"), ln=True)
294
+
295
+ pdf.set_font("Arial", 'B', 16); pdf.set_text_color(*COLOR_VERDE)
296
+ pdf.cell(0, 12, sanear_texto(f"VALOR OPTIMO SUGERIDO (Castigo 8%): ${valor_optimo_neg:,.0f} COP"), ln=True)
297
+
298
+ pdf.set_font("Arial", 'B', 12); pdf.set_text_color(*COLOR_ROJO)
299
+ pdf.cell(0, 8, sanear_texto(f"PISO MINIMO ACEPTABLE (Castigo 10%): ${valor_minimo_neg:,.0f} COP"), ln=True)
300
 
301
  pdf.set_text_color(*COLOR_GRIS); pdf.ln(15); pdf.set_font("Arial", '', 8)
302
+ pdf.multi_cell(0, 4, sanear_texto("Directriz Comercial: Ninguna propuesta por debajo del piso minimo aceptable debe ser tramitada sin revision especial del comite de avalúos."))
303
 
304
+ # PÁGINA 3+: ANEXOS
305
  pdf.add_page()
306
  pdf.set_font("Arial", 'B', 12); pdf.set_fill_color(*COLOR_GRIS); pdf.set_text_color(255, 255, 255)
307
  pdf.cell(0, 10, sanear_texto(" 4. ANEXO TECNICO: TESTIGOS COMPARABLES"), ln=True, fill=True)
 
331
 
332
  # --- CÁLCULOS INTERFAZ ---
333
  resumen = (
334
+ f"🏢 **DIRECTRIZ DE NEGOCIACIÓN SAE**\n"
335
+ f"📈 **Techo Máximo (-5%):** ${valor_maximo_neg:,.0f}\n"
336
+ f" **VALOR ÓPTIMO SUGERIDO (-8%):** ${valor_optimo_neg:,.0f}\n"
337
+ f"🛑 **Piso Mínimo Aceptable (-10%):** ${valor_minimo_neg:,.0f}\n\n"
338
+ f"📊 *Ofertas del Mercado: Min ${minimo_zona:,.0f} | Max ${maximo_zona:,.0f}*"
339
  )
340
 
341
  df_mostrar = df_final[['Portal', 'Precio', 'Precio_M2', 'Ubicacion', 'Descripcion', 'URL']].copy()
342
  df_mostrar['Precio'] = df_mostrar['Precio'].apply(lambda x: f"${x:,.0f}")
343
  df_mostrar['Precio_M2'] = df_mostrar['Precio_M2'].apply(lambda x: f"${x:,.0f}")
344
 
345
+ return f"{log_visible}\n✅ Reporte con Bandas Generado.", df_mostrar, pdf_path, resumen
346
 
347
  except Exception as error_fatal:
348
  traza = traceback.format_exc()
 
350
 
351
  # --- INTERFAZ GRÁFICA ---
352
  with gr.Blocks() as demo:
353
+ gr.Markdown("## 🏢 TramitIA Pro: Analizador Inmobiliario (Bandas SAE)")
354
 
355
  with gr.Row():
356
  with gr.Column(scale=1):
 
372
  btn = gr.Button("GENERAR REPORTE NORMATIVO", variant="primary")
373
 
374
  with gr.Column(scale=2):
375
+ res_fin = gr.Markdown("### 💰 Directriz de Negociación...")
376
  with gr.Tabs():
377
  with gr.TabItem("Descargar Estudio Técnico (PDF)"): out_pdf = gr.File()
378
  with gr.TabItem("Matriz de Datos"): out_df = gr.Dataframe()