#!/usr/bin/env python3
"""
Generador de la presentación de diapositivas (.pptx) para la actividad Semana 7
Machine Learning Avanzado - NRC-8772
Automatización de procesos para el flujo de trabajo en Machine Learning

Autor: Grupo 10
"""

import sys
import os

# Intentar importar python-pptx, si no está instalado, sugerir su instalación o intentar instalar
try:
    from pptx import Presentation
    from pptx.util import Inches, Pt
    from pptx.enum.text import PP_ALIGN
    from pptx.dml.color import RGBColor
    from pptx.enum.shapes import MSO_SHAPE
except ImportError:
    print("⚠️ python-pptx no está instalado. Instalándolo vía pip...")
    import subprocess
    subprocess.check_call([sys.executable, "-m", "pip", "install", "python-pptx"])
    from pptx import Presentation
    from pptx.util import Inches, Pt
    from pptx.enum.text import PP_ALIGN
    from pptx.dml.color import RGBColor
    from pptx.enum.shapes import MSO_SHAPE

def crear_presentacion():
    prs = Presentation()
    
    # Configurar dimensiones de diapositiva a 16:9 (estándar moderno)
    prs.slide_width = Inches(13.33)
    prs.slide_height = Inches(7.5)
    
    # Definir colores de paleta profesional
    COLOR_PRIMARY = RGBColor(30, 41, 59)      # Gris pizarra oscuro (#1e293b)
    COLOR_SECONDARY = RGBColor(14, 116, 144)  # Azul cian oscuro (#0e7490)
    COLOR_TEXT = RGBColor(51, 65, 85)         # Gris texto (#334155)
    COLOR_WHITE = RGBColor(255, 255, 255)
    COLOR_HIGHLIGHT = RGBColor(249, 115, 22)   # Naranja de contraste (#f97316)
    
    blank_layout = prs.slide_layouts[6]  # Diapositiva en blanco para control total
    
    # =========================================================================
    # DIAPOSITIVA 1: PORTADA
    # =========================================================================
    slide = prs.slides.add_slide(blank_layout)
    
    # Fondo decorativo izquierdo (azul cian)
    left_panel = slide.shapes.add_shape(
        MSO_SHAPE.RECTANGLE, 0, 0, Inches(4.5), Inches(7.5)
    )
    left_panel.fill.solid()
    left_panel.fill.fore_color.rgb = COLOR_SECONDARY
    left_panel.line.fill.background()
    
    # Texto en el panel izquierdo (Universidad e Integrantes)
    left_box = slide.shapes.add_textbox(Inches(0.5), Inches(1.5), Inches(3.5), Inches(5.0))
    tf_left = left_box.text_frame
    tf_left.word_wrap = True
    
    p_uni = tf_left.paragraphs[0]
    p_uni.text = "CORPORACIÓN UNIVERSITARIA\nMINUTO DE DIOS"
    p_uni.font.name = 'Calibri'
    p_uni.font.size = Pt(14)
    p_uni.font.bold = True
    p_uni.font.color.rgb = COLOR_WHITE
    p_uni.space_after = Pt(24)
    
    p_int = tf_left.add_paragraph()
    p_int.text = "GRUPO 10:\n- Alexander Oviedo Fadul\n  (Ponente)\n- Maria Fernanda Ruiz Paipilla\n- Neheman Samir Jaller Cerchiaro\n- William David Obando Lopez"
    p_int.font.name = 'Calibri'
    p_int.font.size = Pt(13)
    p_int.font.color.rgb = COLOR_WHITE
    p_int.space_after = Pt(20)
    
    p_cur = tf_left.add_paragraph()
    p_cur.text = "Machine Learning Avanzado\nNRC-8772"
    p_cur.font.name = 'Calibri'
    p_cur.font.size = Pt(12)
    p_cur.font.bold = True
    p_cur.font.color.rgb = COLOR_WHITE
    
    # Texto en el panel derecho (Título del Proyecto)
    right_box = slide.shapes.add_textbox(Inches(5.0), Inches(1.8), Inches(7.8), Inches(4.0))
    tf_right = right_box.text_frame
    tf_right.word_wrap = True
    
    p_title = tf_right.paragraphs[0]
    p_title.text = "AUTOMATIZACIÓN DE PROCESOS EN EL FLUJO DE TRABAJO DE MACHINE LEARNING"
    p_title.font.name = 'Calibri'
    p_title.font.size = Pt(28)
    p_title.font.bold = True
    p_title.font.color.rgb = COLOR_PRIMARY
    p_title.space_after = Pt(14)
    
    p_subtitle = tf_right.add_paragraph()
    p_subtitle.text = "Predicción de Supervivencia en el Titanic aplicando Pipelines, GridSearch y Validación Cruzada"
    p_subtitle.font.name = 'Calibri'
    p_subtitle.font.size = Pt(16)
    p_subtitle.font.color.rgb = COLOR_SECONDARY
    p_subtitle.space_after = Pt(20)
    
    p_prof = tf_right.add_paragraph()
    p_prof.text = "Profesor: Leonardo Valderrama García\nFecha: 21 de junio de 2026"
    p_prof.font.name = 'Calibri'
    p_prof.font.size = Pt(12)
    p_prof.font.color.rgb = COLOR_TEXT
    
    # Enlaces destacados
    p_links = tf_right.add_paragraph()
    p_links.text = "Colab: https://colab.research.google.com/drive/1UFcyBiLMYu7WwMK4UlFYvfFq_wvpBDCB"
    p_links.font.name = 'Calibri'
    p_links.font.size = Pt(10)
    p_links.font.color.rgb = COLOR_SECONDARY
    p_links.space_before = Pt(10)

    # =========================================================================
    # DIAPOSITIVA 2: INTRODUCCIÓN
    # =========================================================================
    slide = prs.slides.add_slide(blank_layout)
    agregar_cabecera(slide, "Introducción: Contexto de MLOps y el Dataset", COLOR_PRIMARY, COLOR_SECONDARY)
    
    # Caja de texto principal
    tb = slide.shapes.add_textbox(Inches(1.0), Inches(2.0), Inches(11.3), Inches(4.5))
    tf = tb.text_frame
    tf.word_wrap = True
    
    agregar_punto_clave(tf, "El Desafío de MLOps", 
                        "La transición de modelos de ML desde scripts experimentales aislados a entornos productivos requiere "
                        "estricta reproducibilidad, consistencia y trazabilidad. Automatizar los flujos es clave (Janiesch et al., 2021).", 
                        COLOR_SECONDARY, COLOR_TEXT)
    
    agregar_punto_clave(tf, "Fuga de Datos (Data Leakage)", 
                        "Uno de los errores más comunes consiste en aplicar transformaciones a todo el dataset antes de la validación. "
                        "Esto permite que información del conjunto de test se filtre al entrenamiento, inflando artificialmente el rendimiento.", 
                        COLOR_SECONDARY, COLOR_TEXT)
    
    agregar_punto_clave(tf, "El Dataset del Titanic", 
                        "Utilizamos los datos históricos del Titanic para demostrar la viabilidad y robustez de un flujo de trabajo "
                        "limpio y estructurado mediante Pipelines y ColumnTransformers de scikit-learn.", 
                        COLOR_SECONDARY, COLOR_TEXT)

    # =========================================================================
    # DIAPOSITIVA 3: ARQUITECTURA DEL PIPELINE
    # =========================================================================
    slide = prs.slides.add_slide(blank_layout)
    agregar_cabecera(slide, "Arquitectura del Pipeline de Modelado", COLOR_PRIMARY, COLOR_SECONDARY)
    
    tb = slide.shapes.add_textbox(Inches(1.0), Inches(2.0), Inches(11.3), Inches(4.5))
    tf = tb.text_frame
    tf.word_wrap = True
    
    agregar_punto_clave(tf, "ColumnTransformer (Preprocesamiento Diferenciado)", 
                        "Permite aplicar transformaciones por tipo de datos simultáneamente:\n"
                        "  • Variables Numéricas: Imputación por mediana y normalización estándar (StandardScaler).\n"
                        "  • Variables Categóricas: Imputación por la moda (most_frequent) y codificación One-Hot.", 
                        COLOR_SECONDARY, COLOR_TEXT)
    
    agregar_punto_clave(tf, "Encapsulamiento en un Pipeline Unificado", 
                        "El ColumnTransformer y el clasificador final se acoplan en un solo pipeline de scikit-learn. "
                        "El preprocesamiento se ejecuta de forma aislada e independiente en cada pliegue de entrenamiento.", 
                        COLOR_SECONDARY, COLOR_TEXT)
    
    agregar_punto_clave(tf, "Optimización de Hiperparámetros y CV", 
                        "El ajuste fino de parámetros con GridSearchCV se realiza directamente sobre el objeto Pipeline. "
                        "Se implementa una Validación Cruzada de 5 pliegues (5-Fold CV) para medir el rendimiento de manera realista.", 
                        COLOR_SECONDARY, COLOR_TEXT)

    # =========================================================================
    # DIAPOSITIVA 4: INGENIERÍA DE CARACTERÍSTICAS
    # =========================================================================
    slide = prs.slides.add_slide(blank_layout)
    agregar_cabecera(slide, "Ingeniería de Características Personalizada", COLOR_PRIMARY, COLOR_SECONDARY)
    
    tb = slide.shapes.add_textbox(Inches(1.0), Inches(2.0), Inches(11.3), Inches(4.5))
    tf = tb.text_frame
    tf.word_wrap = True
    
    agregar_punto_clave(tf, "Extracción de Títulos (Title)", 
                        "Se procesan los nombres para extraer títulos como 'Mr.', 'Mrs.', 'Miss.', 'Master.', etc. "
                        "Los títulos raros o de la nobleza se agrupan en categorías genéricas o en 'Rare'. Representa un proxy del estatus social y la edad.", 
                        COLOR_SECONDARY, COLOR_TEXT)
    
    agregar_punto_clave(tf, "Tamaño de la Familia (Family Size)", 
                        "Se crea la característica 'family_size' combinando el número de hermanos/cónyuges (SibSp) y "
                        "padres/hijos (Parch) a bordo, sumando 1 (el propio pasajero). Ayuda a modelar dinámicas familiares.", 
                        COLOR_SECONDARY, COLOR_TEXT)
    
    agregar_punto_clave(tf, "Pasajero Solitario (Is Alone)", 
                        "Variable binaria calculada directamente de la familia. Toma el valor de 1 si 'family_size' es igual a 1, "
                        "y 0 en caso contrario. Aísla estadísticamente a quienes viajaban de manera independiente.", 
                        COLOR_SECONDARY, COLOR_TEXT)

    # =========================================================================
    # DIAPOSITIVA 5: CLASIFICADOR 1 - RANDOM FOREST
    # =========================================================================
    slide = prs.slides.add_slide(blank_layout)
    agregar_cabecera(slide, "Resultados: Random Forest Classifier", COLOR_PRIMARY, COLOR_SECONDARY)
    
    tb = slide.shapes.add_textbox(Inches(1.0), Inches(2.0), Inches(11.3), Inches(4.5))
    tf = tb.text_frame
    tf.word_wrap = True
    
    agregar_punto_clave(tf, "Espacio de Búsqueda de Hiperparámetros", 
                        "Se optimizaron mediante GridSearchCV:\n"
                        "  • n_estimators: [100, 200, 300]\n"
                        "  • max_depth: [5, 10, None]\n"
                        "  • min_samples_split: [2, 5, 10]", 
                        COLOR_SECONDARY, COLOR_TEXT)
    
    agregar_punto_clave(tf, "Desempeño en Validación Cruzada (CV)", 
                        "• Accuracy Promedio: 81.46%\n"
                        "• F1-score Promedio: 75.92%\n"
                        "• Precision Promedio: 77.84% | Recall Promedio: 74.20%", 
                        COLOR_SECONDARY, COLOR_TEXT)
    
    agregar_punto_clave(tf, "Ventajas Observadas", 
                        "Alta robustez frente a sobreajuste gracias al ensamble y un buen comportamiento de precisión, "
                        "reduciendo falsos positivos.", 
                        COLOR_SECONDARY, COLOR_TEXT)

    # =========================================================================
    # DIAPOSITIVA 6: CLASIFICADOR 2 - SUPPORT VECTOR MACHINE (SVM)
    # =========================================================================
    slide = prs.slides.add_slide(blank_layout)
    agregar_cabecera(slide, "Resultados: Support Vector Machine (SVM)", COLOR_PRIMARY, COLOR_SECONDARY)
    
    tb = slide.shapes.add_textbox(Inches(1.0), Inches(2.0), Inches(11.3), Inches(4.5))
    tf = tb.text_frame
    tf.word_wrap = True
    
    agregar_punto_clave(tf, "Configuración del Modelo SVM", 
                        "• Kernel: RBF (Función de Base Radial)\n"
                        "• Hiperparámetros optimizados en cuadrícula: C (parámetro de penalización) y gamma (coeficiente del kernel).", 
                        COLOR_SECONDARY, COLOR_TEXT)
    
    agregar_punto_clave(tf, "Desempeño en Validación Cruzada (CV)", 
                        "• Accuracy Promedio: 81.60%\n"
                        "• F1-score Promedio: 76.15%\n"
                        "• Precision Promedio: 76.32% | Recall Promedio: 76.01%", 
                        COLOR_SECONDARY, COLOR_TEXT)
    
    agregar_punto_clave(tf, "Comparativa vs Random Forest", 
                        "SVM logra un F1-score ligeramente superior (76.15% vs 75.92%) debido a un mejor balance de Recall, "
                        "lo que significa que es más sensible para capturar supervivientes reales.", 
                        COLOR_SECONDARY, COLOR_TEXT)

    # =========================================================================
    # DIAPOSITIVA 7: ÉTICA DE LA IA Y SESGO ALGORÍTMICO
    # =========================================================================
    slide = prs.slides.add_slide(blank_layout)
    agregar_cabecera(slide, "Gobernanza Algorítmica y Sesgo en IA", COLOR_PRIMARY, COLOR_SECONDARY)
    
    tb = slide.shapes.add_textbox(Inches(1.0), Inches(2.0), Inches(11.3), Inches(4.5))
    tf = tb.text_frame
    tf.word_wrap = True
    
    agregar_punto_clave(tf, "Sesgo Histórico (Historical Bias)", 
                        "La supervivencia del Titanic estuvo fuertemente ligada a factores sociales de 1912: la regla implícita de "
                        "'mujeres y niños primero' y el acceso privilegiado de la primera clase frente a la clase trabajadora.", 
                        COLOR_SECONDARY, COLOR_TEXT)
    
    agregar_punto_clave(tf, "Perpetuación de Desigualdades", 
                        "Si un algoritmo moderno de salvamento marítimo se entrena directamente con estos datos históricos sin auditoría, "
                        "aprenderá que salvar a los hombres y a las clases trabajadoras es una prioridad estadística menor, discriminándolos activamente.", 
                        COLOR_SECONDARY, COLOR_TEXT)
    
    agregar_punto_clave(tf, "Necesidad de Ética de Datos", 
                        "La toma de decisiones automatizada no es neutra (Béranger, 2018; Carsten, 2020). Los científicos de datos "
                        "deben auditar e intervenir los datasets para mitigar la discriminación algorítmica y asegurar la equidad (fairness).", 
                        COLOR_SECONDARY, COLOR_TEXT)

    # =========================================================================
    # DIAPOSITIVA 8: CONCLUSIONES Y RECOMENDACIONES
    # =========================================================================
    slide = prs.slides.add_slide(blank_layout)
    agregar_cabecera(slide, "Conclusiones y Lecciones Aprendidas", COLOR_PRIMARY, COLOR_SECONDARY)
    
    tb = slide.shapes.add_textbox(Inches(1.0), Inches(2.0), Inches(11.3), Inches(4.5))
    tf = tb.text_frame
    tf.word_wrap = True
    
    agregar_punto_clave(tf, "1. Robustez Técnica del Pipeline", 
                        "El uso de ColumnTransformer y Pipeline de scikit-learn garantizó una estructura limpia y escalable. "
                        "Prevenir la fuga de datos es indispensable para obtener métricas realistas y listas para producción.", 
                        COLOR_SECONDARY, COLOR_TEXT)
    
    agregar_punto_clave(tf, "2. Resultados Competitivos y Complementarios", 
                        "Random Forest demostró mayor precisión (menos falsos positivos), mientras que SVM demostró mayor sensibilidad (Recall). "
                        "Ambos modelos mantuvieron un accuracy sólido del 81%.", 
                        COLOR_SECONDARY, COLOR_TEXT)
    
    agregar_punto_clave(tf, "3. El Rol de la Ética en Machine Learning", 
                        "Los algoritmos de IA no solo procesan números, reproducen contextos sociales. La automatización sin "
                        "principios de equidad puede dar lugar a la institucionalización tecnológica de sesgos discriminatorios.", 
                        COLOR_SECONDARY, COLOR_TEXT)
    
    output_path = 'Grupo10_MLA_Automatizacion_S7.pptx'
    prs.save(output_path)
    print(f'✅ Presentación generada: {output_path}')
    return output_path

# =========================================================================
# FUNCIONES AUXILIARES
# =========================================================================
def agregar_cabecera(slide, titulo_texto, color_primary, color_secondary):
    # Agregar barra de color en la cabecera
    bar = slide.shapes.add_shape(
        MSO_SHAPE.RECTANGLE, 0, 0, Inches(13.33), Inches(1.2)
    )
    bar.fill.solid()
    bar.fill.fore_color.rgb = color_primary
    bar.line.fill.background()
    
    # Agregar título
    txBox = slide.shapes.add_textbox(Inches(0.5), Inches(0.2), Inches(12.33), Inches(0.8))
    tf = txBox.text_frame
    tf.word_wrap = True
    p = tf.paragraphs[0]
    p.text = titulo_texto
    p.font.name = 'Calibri'
    p.font.size = Pt(24)
    p.font.bold = True
    p.font.color.rgb = color_secondary

def agregar_punto_clave(tf, titulo, detalle, color_titulo, color_detalle):
    p = tf.add_paragraph() if len(tf.paragraphs[0].text) > 0 else tf.paragraphs[0]
    p.space_before = Pt(14)
    p.space_after = Pt(2)
    
    run_t = p.add_run()
    run_t.text = f"📍 {titulo}: "
    run_t.font.name = 'Calibri'
    run_t.font.size = Pt(16)
    run_t.font.bold = True
    run_t.font.color.rgb = color_titulo
    
    run_d = p.add_run()
    run_d.text = detalle
    run_d.font.name = 'Calibri'
    run_d.font.size = Pt(14)
    run_d.font.color.rgb = color_detalle

if __name__ == '__main__':
    crear_presentacion()
