from huggingface_hub import hf_hub_download import pickle import os import re import numpy as np import pandas as pd import gradio as gr from transformers import pipeline from huggingface_hub import hf_hub_download import subprocess import sys try: from transformers import pipeline except ModuleNotFoundError: subprocess.run([sys.executable, "-m", "pip", "install", "transformers"]) from transformers import pipeline # Vuelve a importar después de la instalación # 🚀 Cargar modelo principal o usar Hugging Face como alternativa def cargar_modelo(): try: modelo_path = hf_hub_download(repo_id="ElDoctor/contractor", filename="modelo.pkl") with open(modelo_path, 'rb') as f: return pickle.load(f) except Exception: return pipeline("text-classification", model="distilbert-base-uncased-finetuned-sst-2-english") modelo = cargar_modelo() def predecir_con_modelo_original(precio): try: entrada = torch.tensor([float(precio)], dtype=torch.float32) # type: ignore with torch.no_grad(): # type: ignore # type: ignore resultado = modelo_original(entrada) # type: ignore # Explicitly check for torch.Tensor or numbers return resultado.item() if isinstance(resultado, (torch.Tensor, int, float, np.ndarray)) else resultado # type: ignore except Exception as e: print(f"Error en predicción con modelo original: {e}") return None # 🔍 Detección automática de la columna de precios def detectar_columna_precios(df): nombres = ['tender price', 'precio', 'monto', 'valor', 'costo', 'importe', 'amount', 'price', 'contract value', 'cost'] for columna in df.columns: if any(nombre in columna.lower() for nombre in nombres): if pd.to_numeric(df[columna], errors='coerce').notna().sum() > 0.5 * len(df): return columna return None # 🧹 Limpieza de precios def limpiar_precio(valor): if pd.isna(valor): return np.nan if isinstance(valor, str): valor = re.sub(r'[^\d.,]', '', valor).replace(',', '.') try: return float(valor) except: return np.nan # 📤 Cargar archivo CSV def cargar_contrataciones(archivo_csv): try: df = pd.read_csv(archivo_csv.name) columna_precio = detectar_columna_precios(df) if not columna_precio: return None, "⚠️ No se encontró una columna con precios." df['Precio_Procesado'] = df[columna_precio].apply(limpiar_precio) df.dropna(subset=['Precio_Procesado'], inplace=True) df.to_csv("archivo_completo.csv", index=False) return "archivo_completo.csv", f"✅ {len(df)} contrataciones cargadas." except Exception as e: return None, f"❌ Error al procesar: {e}" def aplicar_color(val): color = 'green' if val > 90 else 'red' if val < 10 else 'orange' return f'color: {color}' # 📊 Analizar contrataciones # 🎨 Ajuste de colores basado en valores altos = más rojo def aplicar_estilo(df): return df.style.background_gradient( cmap="Reds", subset=["Precio_Procesado", "Confianza Ajustada"] ).set_properties(**{"text-align": "center"}) # 📊 Analizar contrataciones def analizar_contrataciones(n_filas): try: if not os.path.exists("archivo_completo.csv"): return None, "⚠️ Carga un archivo primero.", None df = pd.read_csv("archivo_completo.csv") columna_precio = detectar_columna_precios(df) if not columna_precio: return None, "⚠️ No se encontró una columna de precios.", None df['Precio_Procesado'] = df[columna_precio].apply(limpiar_precio) df.dropna(subset=['Precio_Procesado'], inplace=True) n_filas = min(max(1, int(n_filas)), len(df)) df = df.sample(n=n_filas) # 🔮 Predicción con el modelo if callable(modelo): # Verifica si el modelo es una función (Hugging Face o PyTorch) if "transformers.pipelines" in str(type(modelo)): # Modelo Hugging Face textos = [f"El precio del contrato es {precio}" for precio in df['Precio_Procesado'].astype(str)] resultados = modelo(textos) df['Etiqueta'] = [r["label"] for r in resultados] df['Confianza'] = [r["score"] for r in resultados] else: # Modelo PyTorch df['Confianza'] = df['Precio_Procesado'].apply(lambda x: modelo(torch.tensor([x], dtype=torch.float32)).item()) # type: ignore #DEBEMOS AJUSTAR EL VALOR PARA QUE TENGA MAYOR COHERENCIA # 📊 Ajuste de datos df['Confianza Ajustada'] = df['Confianza'] * 100000 # 🗑️ Eliminar la columna Precio_Formatado df.drop(columns=["Precio_Formatado"], errors="ignore", inplace=True) # 🎨 Aplicar estilo de colores df_styled = df.style.background_gradient( cmap="Reds", subset=["Precio_Procesado", "Confianza Ajustada"] ).set_properties(**{"text-align": "center"}) df.to_csv("resultados.csv", index=False) return "resultados.csv", f"✅ Analizadas {len(df)} filas.", df_styled.to_html() except Exception as e: return None, f"❌ Error: {e}", None # 🌟 Interfaz en Gradio with gr.Blocks(title="Análisis de Contratos Públicos") as app: # type: ignore gr.Markdown("# 📢 Análisis de Contratos Públicos 🚀") # type: ignore archivo_input = gr.File(label="📂 Sube tu archivo CSV") # type: ignore btn_cargar = gr.Button("📋 Cargar") # type: ignore estado_carga = gr.Text(label="Estado de carga") # type: ignore archivo_descargar = gr.File(label="📥 Descargar datos cargados", visible=False) # type: ignore btn_cargar.click(cargar_contrataciones, inputs=[archivo_input], outputs=[archivo_descargar, estado_carga]) gr.Markdown("## 🔍 Análisis") # type: ignore num_filas = gr.Number(label="Filas a analizar", value=500) # type: ignore btn_analizar = gr.Button("🔎 Analizar") # type: ignore estado_analisis = gr.Text(label="Estado del análisis") # type: ignore archivo_resultado = gr.File(label="📥 Descargar Resultados") # type: ignore tabla_resultados = gr.HTML(label="📊 Resultados") # type: ignore btn_analizar.click(analizar_contrataciones, inputs=[num_filas], outputs=[archivo_resultado, estado_analisis, tabla_resultados]) app.launch(share=True) # Moved inside the with gr.blocks() statement