Lukeetah commited on
Commit
d53f7a9
·
verified ·
1 Parent(s): 8b89aed

Upload 4 files

Browse files
Files changed (3) hide show
  1. .gitignore +26 -0
  2. README.md +49 -56
  3. app.py +236 -27
.gitignore ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Archivos de datos
2
+ datos_promesas.json
3
+ datos_gastos.json
4
+ datos_proyectos.json
5
+
6
+ # Python
7
+ __pycache__/
8
+ *.py[cod]
9
+ *$py.class
10
+ *.so
11
+ .Python
12
+ env/
13
+ venv/
14
+ ENV/
15
+ .venv
16
+
17
+ # IDEs
18
+ .vscode/
19
+ .idea/
20
+ *.swp
21
+ *.swo
22
+
23
+ # OS
24
+ .DS_Store
25
+ Thumbs.db
26
+
README.md CHANGED
@@ -1,56 +1,49 @@
1
- ---
2
- title: Político Incorruptible - Argentina
3
- sdk: gradio
4
- emoji: 🌍
5
- colorFrom: red
6
- colorTo: green
7
- short_description: Una aplicación web completa para el seguimiento transparente
8
- ---
9
- # 🇦🇷 Político Incorruptible - Argentina
10
-
11
- ## Sistema de Transparencia y Rendición de Cuentas
12
-
13
- Una aplicación web completa para el seguimiento transparente de promesas políticas, gastos públicos y proyectos gubernamentales.
14
-
15
- ## 🎯 Características
16
-
17
- - ✅ **Seguimiento de Promesas**: Monitoreo público de todas las promesas de campaña con estados y progreso
18
- - 💰 **Transparencia de Gastos**: Visualización detallada de gastos públicos por categoría y mes
19
- - 📊 **Dashboard Interactivo**: Métricas en tiempo real con visualizaciones avanzadas
20
- - 🏗️ **Gestión de Proyectos**: Seguimiento de proyectos activos con presupuestos y beneficiarios
21
- - 📈 **Análisis Avanzado**: Métricas de cumplimiento y eficiencia presupuestaria
22
-
23
- ## 🚀 Instalación
24
-
25
- ```bash
26
- pip install -r requirements.txt
27
- ```
28
-
29
- ## 💻 Uso
30
-
31
- ```bash
32
- python app.py
33
- ```
34
-
35
- La aplicación estará disponible en `http://localhost:7860`
36
-
37
- ## 📦 Despliegue en Hugging Face Spaces
38
-
39
- 1. Crea un nuevo Space en Hugging Face
40
- 2. Sube los archivos `app.py` y `requirements.txt`
41
- 3. El Space se desplegará automáticamente
42
-
43
- ## 🛠️ Tecnologías
44
-
45
- - **Gradio**: Framework para interfaces web interactivas
46
- - **Plotly**: Visualizaciones de datos avanzadas
47
- - **Pandas**: Análisis y manipulación de datos
48
- - **Python**: Backend
49
-
50
- ## 📝 Licencia
51
-
52
- Este proyecto es de código abierto y está disponible para uso público.
53
-
54
- ---
55
-
56
- *Desarrollado para una Argentina más transparente y eficiente* 🇦🇷
 
1
+ # 🇦🇷 Político Incorruptible - Argentina
2
+
3
+ ## Sistema de Transparencia y Rendición de Cuentas
4
+
5
+ Una aplicación web completa para el seguimiento transparente de promesas políticas, gastos públicos y proyectos gubernamentales.
6
+
7
+ ## 🎯 Características
8
+
9
+ - **Seguimiento de Promesas**: Monitoreo público de todas las promesas de campaña con estados y progreso
10
+ - 💰 **Transparencia de Gastos**: Visualización detallada de gastos públicos por categoría y mes
11
+ - 📊 **Dashboard Interactivo**: Métricas en tiempo real con visualizaciones avanzadas
12
+ - 🏗️ **Gestión de Proyectos**: Seguimiento de proyectos activos con presupuestos y beneficiarios
13
+ - 📈 **Análisis Avanzado**: Métricas de cumplimiento y eficiencia presupuestaria
14
+
15
+ ## 🚀 Instalación
16
+
17
+ ```bash
18
+ pip install -r requirements.txt
19
+ ```
20
+
21
+ ## 💻 Uso
22
+
23
+ ```bash
24
+ python app.py
25
+ ```
26
+
27
+ La aplicación estará disponible en `http://localhost:7860`
28
+
29
+ ## 📦 Despliegue en Hugging Face Spaces
30
+
31
+ 1. Crea un nuevo Space en Hugging Face
32
+ 2. Sube los archivos `app.py` y `requirements.txt`
33
+ 3. El Space se desplegará automáticamente
34
+
35
+ ## 🛠️ Tecnologías
36
+
37
+ - **Gradio**: Framework para interfaces web interactivas
38
+ - **Plotly**: Visualizaciones de datos avanzadas
39
+ - **Pandas**: Análisis y manipulación de datos
40
+ - **Python**: Backend
41
+
42
+ ## 📝 Licencia
43
+
44
+ Este proyecto es de código abierto y está disponible para uso público.
45
+
46
+ ---
47
+
48
+ *Desarrollado para una Argentina más transparente y eficiente* 🇦🇷
49
+
 
 
 
 
 
 
 
app.py CHANGED
@@ -140,18 +140,62 @@ class PoliticoIncorruptible:
140
  promesas_en_progreso = sum(1 for p in self.promesas if p["estado"] == "En progreso")
141
  promedio_progreso = sum(p["progreso"] for p in self.promesas) / total_promesas if total_promesas > 0 else 0
142
 
 
 
 
 
 
 
143
  total_gastos = sum(g["monto"] for g in self.gastos)
144
  total_presupuesto = sum(g["presupuesto"] for g in self.gastos)
145
  eficiencia = (1 - (total_gastos / total_presupuesto)) * 100 if total_presupuesto > 0 else 0
146
 
 
 
 
147
  return {
148
  "total_promesas": total_promesas,
149
  "promesas_completadas": promesas_completadas,
150
  "promesas_en_progreso": promesas_en_progreso,
 
151
  "promedio_progreso": promedio_progreso,
152
  "total_gastos": total_gastos,
153
- "eficiencia_presupuestaria": eficiencia
 
154
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
155
 
156
  # Instancia global
157
  politico = PoliticoIncorruptible()
@@ -159,6 +203,13 @@ politico = PoliticoIncorruptible()
159
  def crear_dashboard_promesas():
160
  df = pd.DataFrame(politico.promesas)
161
 
 
 
 
 
 
 
 
162
  # Gráfico de barras por estado
163
  fig_estado = px.bar(
164
  df.groupby("estado").size().reset_index(name="cantidad"),
@@ -168,7 +219,7 @@ def crear_dashboard_promesas():
168
  color="estado",
169
  color_discrete_map={"Completado": "#2ecc71", "En progreso": "#f39c12", "Pendiente": "#e74c3c"}
170
  )
171
- fig_estado.update_layout(showlegend=False, height=300)
172
 
173
  # Gráfico de progreso promedio por categoría
174
  df_categoria = df.groupby("categoria")["progreso"].mean().reset_index()
@@ -180,7 +231,7 @@ def crear_dashboard_promesas():
180
  color="progreso",
181
  color_continuous_scale="Viridis"
182
  )
183
- fig_categoria.update_layout(height=300)
184
 
185
  # Gráfico circular de distribución
186
  fig_pie = px.pie(
@@ -189,9 +240,38 @@ def crear_dashboard_promesas():
189
  title="Distribución de Promesas por Categoría",
190
  hole=0.4
191
  )
192
- fig_pie.update_layout(height=300)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
193
 
194
- return fig_estado, fig_categoria, fig_pie
 
 
 
 
 
 
 
 
 
195
 
196
  def crear_dashboard_gastos():
197
  df = pd.DataFrame(politico.gastos)
@@ -266,6 +346,14 @@ def crear_tabla_proyectos():
266
 
267
  def actualizar_estadisticas():
268
  stats = politico.obtener_estadisticas()
 
 
 
 
 
 
 
 
269
  return f"""
270
  ## 📊 Estadísticas Generales
271
 
@@ -273,16 +361,24 @@ def actualizar_estadisticas():
273
  - Total: {stats['total_promesas']}
274
  - Completadas: {stats['promesas_completadas']} ✅
275
  - En Progreso: {stats['promesas_en_progreso']} 🔄
 
276
  - Progreso Promedio: {stats['promedio_progreso']:.1f}%
277
 
278
  **Gestión Presupuestaria:**
279
  - Total Gastado: ${stats['total_gastos']:,.0f}
280
  - Eficiencia: {stats['eficiencia_presupuestaria']:.2f}%
 
 
 
 
281
  """
282
 
283
  def agregar_promesa(titulo, categoria, descripcion, fecha_limite):
 
 
 
284
  nueva_promesa = {
285
- "id": len(politico.promesas) + 1,
286
  "titulo": titulo,
287
  "fecha_compromiso": datetime.now().strftime("%Y-%m-%d"),
288
  "fecha_limite": fecha_limite,
@@ -292,8 +388,59 @@ def agregar_promesa(titulo, categoria, descripcion, fecha_limite):
292
  "descripcion": descripcion
293
  }
294
  politico.promesas.append(nueva_promesa)
 
295
  return "✅ Promesa agregada exitosamente", crear_tabla_promesas()
296
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
297
  # Interfaz Gradio
298
  with gr.Blocks(theme=gr.themes.Soft(), title="Político Incorruptible - Argentina") as app:
299
  gr.Markdown("""
@@ -318,10 +465,11 @@ with gr.Blocks(theme=gr.themes.Soft(), title="Político Incorruptible - Argentin
318
  with gr.Row():
319
  with gr.Column():
320
  gr.Markdown("### Promesas de Campa��a")
321
- fig_promesa_estado, fig_promesa_categoria, fig_promesa_pie = crear_dashboard_promesas()
322
  gr.Plot(fig_promesa_estado)
323
  gr.Plot(fig_promesa_categoria)
324
  gr.Plot(fig_promesa_pie)
 
325
 
326
  with gr.Column():
327
  gr.Markdown("### Gestión de Gastos Públicos")
@@ -329,14 +477,59 @@ with gr.Blocks(theme=gr.themes.Soft(), title="Político Incorruptible - Argentin
329
  gr.Plot(fig_gastos)
330
  gr.Plot(fig_eficiencia)
331
  gr.Plot(fig_timeline)
 
 
 
 
 
 
 
332
 
333
  with gr.Tab("📋 Promesas de Campaña"):
334
  gr.Markdown("### Seguimiento Detallado de Promesas")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
335
  tabla_promesas = gr.Dataframe(
336
  crear_tabla_promesas(),
337
  headers=["Título", "Categoría", "Estado", "Progreso", "Fecha Límite"],
338
  interactive=False,
339
- wrap=True
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
340
  )
341
 
342
  with gr.Accordion("➕ Agregar Nueva Promesa", open=False):
@@ -355,6 +548,9 @@ with gr.Blocks(theme=gr.themes.Soft(), title="Político Incorruptible - Argentin
355
  fn=agregar_promesa,
356
  inputs=[titulo_promesa, categoria_promesa, descripcion_promesa, fecha_limite_promesa],
357
  outputs=[resultado_promesa, tabla_promesas]
 
 
 
358
  )
359
 
360
  with gr.Tab("💰 Gastos Públicos"):
@@ -382,31 +578,44 @@ with gr.Blocks(theme=gr.themes.Soft(), title="Político Incorruptible - Argentin
382
  with gr.Tab("📈 Análisis Avanzado"):
383
  gr.Markdown("### Métricas y Análisis Detallados")
384
 
 
 
 
385
  with gr.Row():
386
  with gr.Column():
387
- gr.Markdown("""
388
  #### 🎯 Cumplimiento de Promesas
389
- - Tasa de cumplimiento: {:.1f}%
390
- - Promesas en tiempo: {}
391
- - Promesas atrasadas: {}
392
- """.format(
393
- (politico.obtener_estadisticas()["promesas_completadas"] /
394
- politico.obtener_estadisticas()["total_promesas"] * 100) if politico.obtener_estadisticas()["total_promesas"] > 0 else 0,
395
- sum(1 for p in politico.promesas if p["estado"] == "Completado"),
396
- sum(1 for p in politico.promesas if datetime.strptime(p["fecha_limite"], "%Y-%m-%d") < datetime.now() and p["estado"] != "Completado")
397
- ))
398
 
399
  with gr.Column():
400
- gr.Markdown("""
401
  #### 💵 Eficiencia Presupuestaria
402
- - Ahorro total: ${:,.0f}
403
- - Eficiencia promedio: {:.2f}%
404
- - Categorías bajo presupuesto: {}
405
- """.format(
406
- sum(g["presupuesto"] for g in politico.gastos) - sum(g["monto"] for g in politico.gastos),
407
- politico.obtener_estadisticas()["eficiencia_presupuestaria"],
408
- len([g for g in politico.gastos if g["monto"] < g["presupuesto"]])
409
- ))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
410
 
411
  with gr.Tab("ℹ️ Sobre el Sistema"):
412
  gr.Markdown("""
 
140
  promesas_en_progreso = sum(1 for p in self.promesas if p["estado"] == "En progreso")
141
  promedio_progreso = sum(p["progreso"] for p in self.promesas) / total_promesas if total_promesas > 0 else 0
142
 
143
+ # Promesas vencidas
144
+ hoy = datetime.now()
145
+ promesas_vencidas = sum(1 for p in self.promesas
146
+ if datetime.strptime(p["fecha_limite"], "%Y-%m-%d") < hoy
147
+ and p["estado"] != "Completado")
148
+
149
  total_gastos = sum(g["monto"] for g in self.gastos)
150
  total_presupuesto = sum(g["presupuesto"] for g in self.gastos)
151
  eficiencia = (1 - (total_gastos / total_presupuesto)) * 100 if total_presupuesto > 0 else 0
152
 
153
+ # Beneficiarios totales
154
+ total_beneficiarios = sum(p["beneficiarios"] for p in self.proyectos)
155
+
156
  return {
157
  "total_promesas": total_promesas,
158
  "promesas_completadas": promesas_completadas,
159
  "promesas_en_progreso": promesas_en_progreso,
160
+ "promesas_vencidas": promesas_vencidas,
161
  "promedio_progreso": promedio_progreso,
162
  "total_gastos": total_gastos,
163
+ "eficiencia_presupuestaria": eficiencia,
164
+ "total_beneficiarios": total_beneficiarios
165
  }
166
+
167
+ def buscar_promesas(self, busqueda, categoria_filtro, estado_filtro):
168
+ """Busca y filtra promesas"""
169
+ resultados = self.promesas.copy()
170
+
171
+ if busqueda:
172
+ busqueda_lower = busqueda.lower()
173
+ resultados = [p for p in resultados
174
+ if busqueda_lower in p["titulo"].lower()
175
+ or busqueda_lower in p["descripcion"].lower()]
176
+
177
+ if categoria_filtro and categoria_filtro != "Todas":
178
+ resultados = [p for p in resultados if p["categoria"] == categoria_filtro]
179
+
180
+ if estado_filtro and estado_filtro != "Todos":
181
+ resultados = [p for p in resultados if p["estado"] == estado_filtro]
182
+
183
+ return resultados
184
+
185
+ def actualizar_progreso_promesa(self, promesa_id, nuevo_progreso):
186
+ """Actualiza el progreso de una promesa"""
187
+ for promesa in self.promesas:
188
+ if promesa["id"] == promesa_id:
189
+ promesa["progreso"] = nuevo_progreso
190
+ if nuevo_progreso >= 100:
191
+ promesa["estado"] = "Completado"
192
+ elif nuevo_progreso > 0:
193
+ promesa["estado"] = "En progreso"
194
+ else:
195
+ promesa["estado"] = "Pendiente"
196
+ self.guardar_datos()
197
+ return True
198
+ return False
199
 
200
  # Instancia global
201
  politico = PoliticoIncorruptible()
 
203
  def crear_dashboard_promesas():
204
  df = pd.DataFrame(politico.promesas)
205
 
206
+ if df.empty:
207
+ # Crear gráficos vacíos si no hay datos
208
+ fig_empty = go.Figure()
209
+ fig_empty.add_annotation(text="No hay datos disponibles", showarrow=False)
210
+ fig_empty.update_layout(height=300)
211
+ return fig_empty, fig_empty, fig_empty
212
+
213
  # Gráfico de barras por estado
214
  fig_estado = px.bar(
215
  df.groupby("estado").size().reset_index(name="cantidad"),
 
219
  color="estado",
220
  color_discrete_map={"Completado": "#2ecc71", "En progreso": "#f39c12", "Pendiente": "#e74c3c"}
221
  )
222
+ fig_estado.update_layout(showlegend=False, height=300, template="plotly_white")
223
 
224
  # Gráfico de progreso promedio por categoría
225
  df_categoria = df.groupby("categoria")["progreso"].mean().reset_index()
 
231
  color="progreso",
232
  color_continuous_scale="Viridis"
233
  )
234
+ fig_categoria.update_layout(height=300, template="plotly_white")
235
 
236
  # Gráfico circular de distribución
237
  fig_pie = px.pie(
 
240
  title="Distribución de Promesas por Categoría",
241
  hole=0.4
242
  )
243
+ fig_pie.update_layout(height=300, template="plotly_white")
244
+
245
+ # Timeline de promesas
246
+ df_timeline = df.copy()
247
+ df_timeline["fecha_limite_dt"] = pd.to_datetime(df_timeline["fecha_limite"])
248
+ df_timeline = df_timeline.sort_values("fecha_limite_dt")
249
+
250
+ fig_timeline = go.Figure()
251
+ colores = {"Completado": "#2ecc71", "En progreso": "#f39c12", "Pendiente": "#e74c3c"}
252
+
253
+ for estado in df_timeline["estado"].unique():
254
+ df_estado = df_timeline[df_timeline["estado"] == estado]
255
+ fig_timeline.add_trace(go.Scatter(
256
+ x=df_estado["fecha_limite_dt"],
257
+ y=df_estado["progreso"],
258
+ mode='markers+lines',
259
+ name=estado,
260
+ marker=dict(size=10, color=colores.get(estado, "#95a5a6")),
261
+ text=df_estado["titulo"],
262
+ hovertemplate='<b>%{text}</b><br>Fecha: %{x}<br>Progreso: %{y}%<extra></extra>'
263
+ ))
264
 
265
+ fig_timeline.update_layout(
266
+ title="Timeline de Promesas",
267
+ xaxis_title="Fecha Límite",
268
+ yaxis_title="Progreso (%)",
269
+ height=300,
270
+ template="plotly_white",
271
+ hovermode='closest'
272
+ )
273
+
274
+ return fig_estado, fig_categoria, fig_pie, fig_timeline
275
 
276
  def crear_dashboard_gastos():
277
  df = pd.DataFrame(politico.gastos)
 
346
 
347
  def actualizar_estadisticas():
348
  stats = politico.obtener_estadisticas()
349
+ alertas = obtener_alertas()
350
+
351
+ alertas_html = ""
352
+ if alertas:
353
+ alertas_html = "\n\n**🚨 Alertas:**\n"
354
+ for alerta in alertas[:5]: # Mostrar máximo 5 alertas
355
+ alertas_html += f"- {alerta['tipo']}: {alerta['mensaje']}\n"
356
+
357
  return f"""
358
  ## 📊 Estadísticas Generales
359
 
 
361
  - Total: {stats['total_promesas']}
362
  - Completadas: {stats['promesas_completadas']} ✅
363
  - En Progreso: {stats['promesas_en_progreso']} 🔄
364
+ - Vencidas: {stats['promesas_vencidas']} ⚠️
365
  - Progreso Promedio: {stats['promedio_progreso']:.1f}%
366
 
367
  **Gestión Presupuestaria:**
368
  - Total Gastado: ${stats['total_gastos']:,.0f}
369
  - Eficiencia: {stats['eficiencia_presupuestaria']:.2f}%
370
+
371
+ **Impacto Social:**
372
+ - Beneficiarios Totales: {stats['total_beneficiarios']:,} personas
373
+ {alertas_html}
374
  """
375
 
376
  def agregar_promesa(titulo, categoria, descripcion, fecha_limite):
377
+ if not titulo or not categoria or not fecha_limite:
378
+ return "❌ Por favor completa todos los campos obligatorios", crear_tabla_promesas()
379
+
380
  nueva_promesa = {
381
+ "id": max([p["id"] for p in politico.promesas], default=0) + 1,
382
  "titulo": titulo,
383
  "fecha_compromiso": datetime.now().strftime("%Y-%m-%d"),
384
  "fecha_limite": fecha_limite,
 
388
  "descripcion": descripcion
389
  }
390
  politico.promesas.append(nueva_promesa)
391
+ politico.guardar_datos()
392
  return "✅ Promesa agregada exitosamente", crear_tabla_promesas()
393
 
394
+ def buscar_y_filtrar_promesas(busqueda, categoria, estado):
395
+ resultados = politico.buscar_promesas(busqueda, categoria, estado)
396
+ if not resultados:
397
+ return pd.DataFrame(columns=["Título", "Categoría", "Estado", "Progreso", "Fecha Límite"])
398
+
399
+ df = pd.DataFrame(resultados)
400
+ df_display = df[["titulo", "categoria", "estado", "progreso", "fecha_limite"]].copy()
401
+ df_display["progreso"] = df_display["progreso"].apply(lambda x: f"{x}%")
402
+ df_display.columns = ["Título", "Categoría", "Estado", "Progreso", "Fecha Límite"]
403
+ return df_display
404
+
405
+ def obtener_alertas():
406
+ """Genera alertas sobre promesas vencidas o en riesgo"""
407
+ hoy = datetime.now()
408
+ alertas = []
409
+
410
+ for promesa in politico.promesas:
411
+ fecha_limite = datetime.strptime(promesa["fecha_limite"], "%Y-%m-%d")
412
+ dias_restantes = (fecha_limite - hoy).days
413
+
414
+ if fecha_limite < hoy and promesa["estado"] != "Completado":
415
+ alertas.append({
416
+ "tipo": "⚠️ VENCIDA",
417
+ "mensaje": f"'{promesa['titulo']}' está vencida desde hace {abs(dias_restantes)} días",
418
+ "prioridad": "alta"
419
+ })
420
+ elif dias_restantes <= 30 and promesa["estado"] != "Completado":
421
+ alertas.append({
422
+ "tipo": "🔔 PRÓXIMA A VENCER",
423
+ "mensaje": f"'{promesa['titulo']}' vence en {dias_restantes} días",
424
+ "prioridad": "media"
425
+ })
426
+
427
+ return alertas
428
+
429
+ def exportar_datos():
430
+ """Exporta todos los datos a formato CSV"""
431
+ try:
432
+ df_promesas = pd.DataFrame(politico.promesas)
433
+ df_gastos = pd.DataFrame(politico.gastos)
434
+ df_proyectos = pd.DataFrame(politico.proyectos)
435
+
436
+ return {
437
+ "promesas": df_promesas.to_csv(index=False),
438
+ "gastos": df_gastos.to_csv(index=False),
439
+ "proyectos": df_proyectos.to_csv(index=False)
440
+ }
441
+ except Exception as e:
442
+ return {"error": str(e)}
443
+
444
  # Interfaz Gradio
445
  with gr.Blocks(theme=gr.themes.Soft(), title="Político Incorruptible - Argentina") as app:
446
  gr.Markdown("""
 
465
  with gr.Row():
466
  with gr.Column():
467
  gr.Markdown("### Promesas de Campa��a")
468
+ fig_promesa_estado, fig_promesa_categoria, fig_promesa_pie, fig_promesa_timeline = crear_dashboard_promesas()
469
  gr.Plot(fig_promesa_estado)
470
  gr.Plot(fig_promesa_categoria)
471
  gr.Plot(fig_promesa_pie)
472
+ gr.Plot(fig_promesa_timeline)
473
 
474
  with gr.Column():
475
  gr.Markdown("### Gestión de Gastos Públicos")
 
477
  gr.Plot(fig_gastos)
478
  gr.Plot(fig_eficiencia)
479
  gr.Plot(fig_timeline)
480
+
481
+ def refrescar_dashboard():
482
+ politico.cargar_datos()
483
+ return actualizar_estadisticas()
484
+
485
+ btn_refrescar = gr.Button("🔄 Actualizar Estadísticas", variant="secondary", size="sm")
486
+ btn_refrescar.click(fn=refrescar_dashboard, outputs=stats_display)
487
 
488
  with gr.Tab("📋 Promesas de Campaña"):
489
  gr.Markdown("### Seguimiento Detallado de Promesas")
490
+
491
+ with gr.Row():
492
+ busqueda_promesa = gr.Textbox(
493
+ label="🔍 Buscar promesas",
494
+ placeholder="Buscar por título o descripción...",
495
+ scale=3
496
+ )
497
+ categoria_filtro = gr.Dropdown(
498
+ choices=["Todas", "Economía", "Empleo", "Educación", "Salud", "Seguridad", "Infraestructura", "Transparencia", "Medio Ambiente"],
499
+ value="Todas",
500
+ label="Categoría",
501
+ scale=2
502
+ )
503
+ estado_filtro = gr.Dropdown(
504
+ choices=["Todos", "Pendiente", "En progreso", "Completado"],
505
+ value="Todos",
506
+ label="Estado",
507
+ scale=2
508
+ )
509
+
510
  tabla_promesas = gr.Dataframe(
511
  crear_tabla_promesas(),
512
  headers=["Título", "Categoría", "Estado", "Progreso", "Fecha Límite"],
513
  interactive=False,
514
+ wrap=True,
515
+ height=400
516
+ )
517
+
518
+ # Actualizar tabla cuando cambian los filtros
519
+ busqueda_promesa.change(
520
+ fn=buscar_y_filtrar_promesas,
521
+ inputs=[busqueda_promesa, categoria_filtro, estado_filtro],
522
+ outputs=tabla_promesas
523
+ )
524
+ categoria_filtro.change(
525
+ fn=buscar_y_filtrar_promesas,
526
+ inputs=[busqueda_promesa, categoria_filtro, estado_filtro],
527
+ outputs=tabla_promesas
528
+ )
529
+ estado_filtro.change(
530
+ fn=buscar_y_filtrar_promesas,
531
+ inputs=[busqueda_promesa, categoria_filtro, estado_filtro],
532
+ outputs=tabla_promesas
533
  )
534
 
535
  with gr.Accordion("➕ Agregar Nueva Promesa", open=False):
 
548
  fn=agregar_promesa,
549
  inputs=[titulo_promesa, categoria_promesa, descripcion_promesa, fecha_limite_promesa],
550
  outputs=[resultado_promesa, tabla_promesas]
551
+ ).then(
552
+ fn=lambda: "",
553
+ outputs=busqueda_promesa
554
  )
555
 
556
  with gr.Tab("💰 Gastos Públicos"):
 
578
  with gr.Tab("📈 Análisis Avanzado"):
579
  gr.Markdown("### Métricas y Análisis Detallados")
580
 
581
+ stats = politico.obtener_estadisticas()
582
+ alertas = obtener_alertas()
583
+
584
  with gr.Row():
585
  with gr.Column():
586
+ gr.Markdown(f"""
587
  #### 🎯 Cumplimiento de Promesas
588
+ - Tasa de cumplimiento: {(stats['promesas_completadas'] / stats['total_promesas'] * 100) if stats['total_promesas'] > 0 else 0:.1f}%
589
+ - Promesas completadas: {stats['promesas_completadas']}
590
+ - Promesas vencidas: {stats['promesas_vencidas']} ⚠️
591
+ - Promesas en progreso: {stats['promesas_en_progreso']}
592
+ """)
 
 
 
 
593
 
594
  with gr.Column():
595
+ gr.Markdown(f"""
596
  #### 💵 Eficiencia Presupuestaria
597
+ - Ahorro total: ${sum(g['presupuesto'] for g in politico.gastos) - sum(g['monto'] for g in politico.gastos):,.0f}
598
+ - Eficiencia promedio: {stats['eficiencia_presupuestaria']:.2f}%
599
+ - Categorías bajo presupuesto: {len([g for g in politico.gastos if g['monto'] < g['presupuesto']])}
600
+ """)
601
+
602
+ if alertas:
603
+ with gr.Accordion("🚨 Alertas y Notificaciones", open=True):
604
+ alertas_texto = "\n".join([f"**{a['tipo']}**: {a['mensaje']}" for a in alertas])
605
+ gr.Markdown(alertas_texto)
606
+
607
+ with gr.Accordion("📥 Exportar Datos", open=False):
608
+ gr.Markdown("### Descargar datos en formato CSV")
609
+ btn_exportar = gr.Button("Exportar Todos los Datos", variant="secondary")
610
+ export_result = gr.Markdown()
611
+
612
+ def exportar():
613
+ datos = exportar_datos()
614
+ if "error" in datos:
615
+ return f"❌ Error: {datos['error']}"
616
+ return "✅ Datos exportados exitosamente. Los archivos CSV están listos para descargar."
617
+
618
+ btn_exportar.click(fn=exportar, outputs=export_result)
619
 
620
  with gr.Tab("ℹ️ Sobre el Sistema"):
621
  gr.Markdown("""