ElDoctor commited on
Commit
3a1fd6e
·
verified ·
1 Parent(s): 7458922

upload app

Browse files
Files changed (1) hide show
  1. app.py +142 -0
app.py ADDED
@@ -0,0 +1,142 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from huggingface_hub import hf_hub_download
2
+ import pickle
3
+ import os
4
+ import re
5
+ import numpy as np
6
+ from transformers import pipeline
7
+ import pandas as pd
8
+ import gradio as gr
9
+
10
+ # 🚀 Cargar modelo principal o usar Hugging Face como alternativa
11
+ def cargar_modelo():
12
+ try:
13
+ modelo_path = hf_hub_download(repo_id="ElDoctor/contractor", filename="modelo.pkl")
14
+ with open(modelo_path, 'rb') as f:
15
+ return pickle.load(f)
16
+ except Exception:
17
+ return pipeline("text-classification", model="distilbert-base-uncased-finetuned-sst-2-english")
18
+
19
+ modelo = cargar_modelo()
20
+
21
+ def predecir_con_modelo_original(precio):
22
+ try:
23
+ entrada = torch.tensor([float(precio)], dtype=torch.float32) # type: ignore
24
+ with torch.no_grad(): # type: ignore # type: ignore
25
+ resultado = modelo_original(entrada) # type: ignore
26
+ # Explicitly check for torch.Tensor or numbers
27
+ return resultado.item() if isinstance(resultado, (torch.Tensor, int, float, np.ndarray)) else resultado # type: ignore
28
+ except Exception as e:
29
+ print(f"Error en predicción con modelo original: {e}")
30
+ return None
31
+
32
+ # 🔍 Detección automática de la columna de precios
33
+ def detectar_columna_precios(df):
34
+ nombres = ['tender price', 'precio', 'monto', 'valor', 'costo', 'importe', 'amount', 'price', 'contract value', 'cost']
35
+ for columna in df.columns:
36
+ if any(nombre in columna.lower() for nombre in nombres):
37
+ if pd.to_numeric(df[columna], errors='coerce').notna().sum() > 0.5 * len(df):
38
+ return columna
39
+ return None
40
+
41
+ # 🧹 Limpieza de precios
42
+ def limpiar_precio(valor):
43
+ if pd.isna(valor):
44
+ return np.nan
45
+ if isinstance(valor, str):
46
+ valor = re.sub(r'[^\d.,]', '', valor).replace(',', '.')
47
+ try:
48
+ return float(valor)
49
+ except:
50
+ return np.nan
51
+
52
+ # 📤 Cargar archivo CSV
53
+ def cargar_contrataciones(archivo_csv):
54
+ try:
55
+ df = pd.read_csv(archivo_csv.name)
56
+ columna_precio = detectar_columna_precios(df)
57
+ if not columna_precio:
58
+ return None, "⚠️ No se encontró una columna con precios."
59
+ df['Precio_Procesado'] = df[columna_precio].apply(limpiar_precio)
60
+ df.dropna(subset=['Precio_Procesado'], inplace=True)
61
+ df.to_csv("archivo_completo.csv", index=False)
62
+ return "archivo_completo.csv", f"✅ {len(df)} contrataciones cargadas."
63
+ except Exception as e:
64
+ return None, f"❌ Error al procesar: {e}"
65
+
66
+ def aplicar_color(val):
67
+ color = 'green' if val > 90 else 'red' if val < 10 else 'orange'
68
+ return f'color: {color}'
69
+
70
+ # 📊 Analizar contrataciones
71
+ # 🎨 Ajuste de colores basado en valores altos = más rojo
72
+ def aplicar_estilo(df):
73
+ return df.style.background_gradient(
74
+ cmap="Reds", subset=["Precio_Procesado", "Confianza Ajustada"]
75
+ ).set_properties(**{"text-align": "center"})
76
+
77
+ # 📊 Analizar contrataciones
78
+ def analizar_contrataciones(n_filas):
79
+ try:
80
+ if not os.path.exists("archivo_completo.csv"):
81
+ return None, "⚠️ Carga un archivo primero.", None
82
+
83
+ df = pd.read_csv("archivo_completo.csv")
84
+ columna_precio = detectar_columna_precios(df)
85
+ if not columna_precio:
86
+ return None, "⚠️ No se encontró una columna de precios.", None
87
+
88
+ df['Precio_Procesado'] = df[columna_precio].apply(limpiar_precio)
89
+ df.dropna(subset=['Precio_Procesado'], inplace=True)
90
+
91
+ n_filas = min(max(1, int(n_filas)), len(df))
92
+ df = df.sample(n=n_filas)
93
+
94
+ # 🔮 Predicción con el modelo
95
+ if callable(modelo): # Verifica si el modelo es una función (Hugging Face o PyTorch)
96
+ if "transformers.pipelines" in str(type(modelo)): # Modelo Hugging Face
97
+ textos = [f"El precio del contrato es {precio}" for precio in df['Precio_Procesado'].astype(str)]
98
+ resultados = modelo(textos)
99
+ df['Etiqueta'] = [r["label"] for r in resultados]
100
+ df['Confianza'] = [r["score"] for r in resultados]
101
+ else: # Modelo PyTorch
102
+ df['Confianza'] = df['Precio_Procesado'].apply(lambda x: modelo(torch.tensor([x], dtype=torch.float32)).item()) # type: ignore
103
+ #DEBEMOS AJUSTAR EL VALOR PARA QUE TENGA MAYOR COHERENCIA
104
+ # 📊 Ajuste de datos
105
+ df['Confianza Ajustada'] = df['Confianza'] * 100000
106
+
107
+ # 🗑️ Eliminar la columna Precio_Formatado
108
+ df.drop(columns=["Precio_Formatado"], errors="ignore", inplace=True)
109
+
110
+ # 🎨 Aplicar estilo de colores
111
+ df_styled = df.style.background_gradient(
112
+ cmap="Reds", subset=["Precio_Procesado", "Confianza Ajustada"]
113
+ ).set_properties(**{"text-align": "center"})
114
+
115
+ df.to_csv("resultados.csv", index=False)
116
+ return "resultados.csv", f"✅ Analizadas {len(df)} filas.", df_styled.to_html()
117
+
118
+ except Exception as e:
119
+ return None, f"❌ Error: {e}", None
120
+
121
+
122
+ # 🌟 Interfaz en Gradio
123
+ with gr.Blocks(title="Análisis de Contratos Públicos") as app: # type: ignore
124
+ gr.Markdown("# 📢 Análisis de Contratos Públicos 🚀") # type: ignore
125
+
126
+ archivo_input = gr.File(label="📂 Sube tu archivo CSV") # type: ignore
127
+ btn_cargar = gr.Button("📋 Cargar") # type: ignore
128
+ estado_carga = gr.Text(label="Estado de carga") # type: ignore
129
+ archivo_descargar = gr.File(label="📥 Descargar datos cargados", visible=False) # type: ignore
130
+
131
+ btn_cargar.click(cargar_contrataciones, inputs=[archivo_input], outputs=[archivo_descargar, estado_carga])
132
+
133
+ gr.Markdown("## 🔍 Análisis") # type: ignore
134
+ num_filas = gr.Number(label="Filas a analizar", value=500) # type: ignore
135
+ btn_analizar = gr.Button("🔎 Analizar") # type: ignore
136
+ estado_analisis = gr.Text(label="Estado del análisis") # type: ignore
137
+ archivo_resultado = gr.File(label="📥 Descargar Resultados") # type: ignore
138
+ tabla_resultados = gr.HTML(label="📊 Resultados") # type: ignore
139
+
140
+ btn_analizar.click(analizar_contrataciones, inputs=[num_filas], outputs=[archivo_resultado, estado_analisis, tabla_resultados])
141
+
142
+ app.launch(share=True) # Moved inside the with gr.blocks() statement