#!/usr/bin/env python3
"""
Generador del documento .docx con normas APA 7 para la actividad Semana 7
Visión por Computador - NRC-8773
Video con Voz en Off: Red Neuronal Convolucional Clasificadora

Autor: Alexander Oviedo Fadul
"""

from docx import Document
from docx.shared import Pt, Inches, Cm, RGBColor
from docx.enum.text import WD_ALIGN_PARAGRAPH
from docx.enum.table import WD_TABLE_ALIGNMENT
from docx.oxml.ns import qn
import datetime

def crear_documento():
    doc = Document()

    # =========================================================================
    # CONFIGURACIÓN GLOBAL APA 7
    # =========================================================================
    style = doc.styles['Normal']
    font = style.font
    font.name = 'Calibri'
    font.size = Pt(11)
    font.color.rgb = RGBColor(0, 0, 0)

    paragraph_format = style.paragraph_format
    paragraph_format.line_spacing = 2.0  # Interlineado doble
    paragraph_format.space_after = Pt(0)
    paragraph_format.space_before = Pt(0)

    # Márgenes APA: 2.54 cm en todos los lados
    for section in doc.sections:
        section.top_margin = Cm(2.54)
        section.bottom_margin = Cm(2.54)
        section.left_margin = Cm(2.54)
        section.right_margin = Cm(2.54)
        section.page_width = Inches(8.5)
        section.page_height = Inches(11)

    # =========================================================================
    # PORTADA APA 7
    # =========================================================================
    # Líneas vacías para centrar
    for _ in range(4):
        doc.add_paragraph('')

    # Título
    titulo = doc.add_paragraph()
    titulo.alignment = WD_ALIGN_PARAGRAPH.CENTER
    run = titulo.add_run('Video con Voz en Off: Diseño e Implementación de una\n'
                          'Red Neuronal Convolucional Clasificadora de Imágenes')
    run.bold = True
    run.font.size = Pt(12)
    run.font.name = 'Calibri'
    titulo.paragraph_format.line_spacing = 2.0

    doc.add_paragraph('')

    # Autor
    autor = doc.add_paragraph()
    autor.alignment = WD_ALIGN_PARAGRAPH.CENTER
    run = autor.add_run(
        'Grupo 10:\n'
        'Alexander Oviedo Fadul (Ponente)\n'
        'Maria Fernanda Ruiz Paipilla\n'
        'Neheman Samir Jaller Cerchiaro\n'
        'William David Obando Lopez\n'
        'Yesith Stiven Vizcano Mican'
    )
    run.font.size = Pt(11)
    run.font.name = 'Calibri'

    # Programa y universidad
    universidad = doc.add_paragraph()
    universidad.alignment = WD_ALIGN_PARAGRAPH.CENTER
    run = universidad.add_run('Ingeniería de Sistemas, Corporación Universitaria Minuto de Dios (UNIMINUTO)')
    run.font.size = Pt(11)
    run.font.name = 'Calibri'

    # Curso
    curso = doc.add_paragraph()
    curso.alignment = WD_ALIGN_PARAGRAPH.CENTER
    run = curso.add_run('NRC-8773: Visión por Computador')
    run.font.size = Pt(11)
    run.font.name = 'Calibri'

    # Profesor
    profesor = doc.add_paragraph()
    profesor.alignment = WD_ALIGN_PARAGRAPH.CENTER
    run = profesor.add_run('Profesor: Félix Julián Gutiérrez Bernal')
    run.font.size = Pt(11)
    run.font.name = 'Calibri'

    # Fecha
    fecha = doc.add_paragraph()
    fecha.alignment = WD_ALIGN_PARAGRAPH.CENTER
    run = fecha.add_run('21 de junio de 2026')
    run.font.size = Pt(11)
    run.font.name = 'Calibri'

    # Salto de página
    doc.add_page_break()

    # =========================================================================
    # ENLACE DEL VIDEO
    # =========================================================================
    agregar_titulo_nivel1(doc, 'Enlace del Video')

    p = doc.add_paragraph()
    p.paragraph_format.first_line_indent = Cm(1.27)
    p.paragraph_format.line_spacing = 2.0
    run = p.add_run('A continuación, se presenta el enlace al video con voz en off '
                     'que muestra el diseño, la implementación y los resultados obtenidos '
                     'de la red neuronal convolucional clasificadora de imágenes:')
    run.font.size = Pt(11)
    run.font.name = 'Calibri'

    p_link = doc.add_paragraph()
    p_link.alignment = WD_ALIGN_PARAGRAPH.CENTER
    p_link.paragraph_format.line_spacing = 2.0
    run = p_link.add_run('https://youtu.be/imfwwE4tvMg')
    run.bold = True
    run.font.size = Pt(12)
    run.font.name = 'Calibri'
    run.font.color.rgb = RGBColor(0, 102, 204)

    p_colab_intro = doc.add_paragraph()
    p_colab_intro.paragraph_format.first_line_indent = Cm(1.27)
    p_colab_intro.paragraph_format.line_spacing = 2.0
    run = p_colab_intro.add_run('Asimismo, se adjunta el enlace directo al notebook de Google Colab '
                                 'donde se puede ejecutar, entrenar y evaluar todo el flujo del proyecto:')
    run.font.size = Pt(11)
    run.font.name = 'Calibri'

    p_colab_link = doc.add_paragraph()
    p_colab_link.alignment = WD_ALIGN_PARAGRAPH.CENTER
    p_colab_link.paragraph_format.line_spacing = 2.0
    run = p_colab_link.add_run('https://colab.research.google.com/drive/1UFcyBiLMYu7WwMK4UlFYvfFq_wvpBDCB')
    run.bold = True
    run.font.size = Pt(12)
    run.font.name = 'Calibri'
    run.font.color.rgb = RGBColor(0, 102, 204)

    doc.add_paragraph('')

    # Datos del trabajo
    agregar_titulo_nivel2(doc, 'Datos del Trabajo')

    tabla_datos = doc.add_table(rows=8, cols=2)
    tabla_datos.style = 'Table Grid'
    tabla_datos.alignment = WD_TABLE_ALIGNMENT.CENTER

    datos = [
        ('Título del trabajo', 'Video con Voz en Off: Red Neuronal Convolucional Clasificadora'),
        ('Nombres completos', 'Grupo 10:\n- Alexander Oviedo Fadul (Ponente)\n- Maria Fernanda Ruiz Paipilla\n- Neheman Samir Jaller Cerchiaro\n- William David Obando Lopez\n- Yesith Stiven Vizcano Mican'),
        ('Nombre del curso', 'NRC-8773: Visión por Computador'),
        ('Número de la semana', 'Semana 7'),
        ('Nombre del profesor', 'Félix Julián Gutiérrez Bernal'),
        ('Fecha de entrega', '21 de junio de 2026'),
        ('Framework utilizado', 'TensorFlow / Keras (Python)'),
        ('Enlace de Google Colab', 'https://colab.research.google.com/drive/1UFcyBiLMYu7WwMK4UlFYvfFq_wvpBDCB')
    ]

    for i, (campo, valor) in enumerate(datos):
        cell_campo = tabla_datos.cell(i, 0)
        cell_valor = tabla_datos.cell(i, 1)

        p1 = cell_campo.paragraphs[0]
        run1 = p1.add_run(campo)
        run1.bold = True
        run1.font.size = Pt(10)
        run1.font.name = 'Calibri'

        p2 = cell_valor.paragraphs[0]
        run2 = p2.add_run(valor)
        run2.font.size = Pt(10)
        run2.font.name = 'Calibri'

    doc.add_paragraph('')
    doc.add_page_break()

    # =========================================================================
    # ETAPA DE DISEÑO
    # =========================================================================
    agregar_titulo_nivel1(doc, 'Etapa de Diseño')

    agregar_parrafo(doc, (
        'La red neuronal convolucional diseñada para este proyecto sigue los principios '
        'de la arquitectura VGG, tal como lo recomendó el profesor Félix Julián Gutiérrez '
        'Bernal durante la clase del 17 de junio de 2026. La arquitectura utiliza '
        'exclusivamente filtros de 3×3, que se consolidaron como estándar desde el año '
        '2014 cuando se demostró que apilar múltiples capas con filtros pequeños es más '
        'eficiente que usar filtros grandes (Zafar et al., 2018).'
    ))

    agregar_titulo_nivel2(doc, 'Arquitectura de la CNN')

    agregar_parrafo(doc, (
        'El modelo consta de tres bloques convolucionales seguidos de un clasificador '
        'con capas totalmente conectadas. Cada bloque contiene dos capas de convolución '
        'con normalización por lotes (BatchNormalization), seguidas de max pooling y '
        'dropout para regularización. La progresión de filtros es 32→64→128, duplicando '
        'la profundidad en cada bloque mientras se reduce la resolución espacial.'
    ))

    # Tabla de arquitectura
    tabla_arq = doc.add_table(rows=13, cols=3)
    tabla_arq.style = 'Table Grid'
    tabla_arq.alignment = WD_TABLE_ALIGNMENT.CENTER

    capas = [
        ('Capa', 'Tipo', 'Parámetros'),
        ('1', 'Conv2D + BatchNorm', '32 filtros, 3×3, ReLU, padding=same'),
        ('2', 'Conv2D + BatchNorm', '32 filtros, 3×3, ReLU, padding=same'),
        ('3', 'MaxPooling2D + Dropout', 'Pool 2×2, Dropout 25%'),
        ('4', 'Conv2D + BatchNorm', '64 filtros, 3×3, ReLU, padding=same'),
        ('5', 'Conv2D + BatchNorm', '64 filtros, 3×3, ReLU, padding=same'),
        ('6', 'MaxPooling2D + Dropout', 'Pool 2×2, Dropout 25%'),
        ('7', 'Conv2D + BatchNorm', '128 filtros, 3×3, ReLU, padding=same'),
        ('8', 'Conv2D + BatchNorm', '128 filtros, 3×3, ReLU, padding=same'),
        ('9', 'MaxPooling2D + Dropout', 'Pool 2×2, Dropout 25%'),
        ('10', 'Flatten + Dense', '256 neuronas, ReLU, Dropout 50%'),
        ('11', 'Dense', '128 neuronas, ReLU, Dropout 50%'),
        ('12', 'Dense (Salida)', '10 neuronas, Softmax'),
    ]

    for i, (col1, col2, col3) in enumerate(capas):
        for j, val in enumerate([col1, col2, col3]):
            cell = tabla_arq.cell(i, j)
            p = cell.paragraphs[0]
            run = p.add_run(val)
            run.font.size = Pt(9)
            run.font.name = 'Calibri'
            if i == 0:
                run.bold = True

    doc.add_paragraph('')

    agregar_titulo_nivel2(doc, 'Justificación de Decisiones de Diseño')

    agregar_parrafo(doc, (
        'La elección de filtros 3×3 se fundamenta en la recomendación directa del profesor '
        'Félix durante la clase: "Se establece esa arquitectura y se mira lo mejor es '
        'trabajar de tres por tres y dándole profundidad la imagen tanto como yo quiera." '
        'Además, el uso de BatchNormalization permite un entrenamiento más estable y rápido, '
        'mientras que el Dropout en las capas convolucionales (25%) y densas (50%) previene '
        'el sobreajuste, un problema común en redes de esta profundidad (Dadhich, 2018).'
    ))

    agregar_parrafo(doc, (
        'El optimizador Adam fue seleccionado por su capacidad adaptativa y convergencia '
        'eficiente, mientras que la función de pérdida Categorical Crossentropy es la '
        'estándar para problemas de clasificación multiclase con activación Softmax en '
        'la capa de salida, tal como lo explicó el profesor: "La función de activación '
        'de un softmax indica que le entrega probabilidades a cada una de las posibles '
        'clases."'
    ))

    doc.add_page_break()

    # =========================================================================
    # ETAPA DE IMPLEMENTACIÓN
    # =========================================================================
    agregar_titulo_nivel1(doc, 'Etapa de Implementación')

    agregar_titulo_nivel2(doc, 'Dataset de Entrenamiento')

    agregar_parrafo(doc, (
        'Para el entrenamiento se utilizó el dataset CIFAR-10 de TensorFlow, que contiene '
        '60,000 imágenes a color de 32×32 píxeles distribuidas en 10 clases: avión, '
        'automóvil, pájaro, gato, ciervo, perro, rana, caballo, barco y camión. El '
        'dataset se dividió en 50,000 imágenes para entrenamiento y 10,000 para prueba.'
    ))

    agregar_titulo_nivel2(doc, 'Dataset Propio para Validación Externa')

    agregar_parrafo(doc, (
        'Para la validación externa se utilizó un dataset de autoría propia con un mínimo '
        'de 100 imágenes, almacenado en Google Drive. Las imágenes fueron preprocesadas '
        'al mismo tamaño del dataset de entrenamiento (32×32 píxeles) y normalizadas al '
        'rango [0, 1], siguiendo la instrucción del profesor: "Asegurar mismo tamaño/escala '
        'de imágenes al cargar y predicción."'
    ))

    agregar_titulo_nivel2(doc, 'Técnicas de Preprocesamiento')

    agregar_parrafo(doc, (
        'Se aplicaron las siguientes técnicas de preprocesamiento: (a) normalización de '
        'valores de píxeles dividiendo entre 255 para obtener el rango [0.0, 1.0]; '
        '(b) codificación one-hot de las etiquetas; y (c) data augmentation con rotaciones '
        'aleatorias de hasta 15°, desplazamientos horizontales y verticales del 10%, '
        'y volteo horizontal aleatorio para mejorar la generalización del modelo.'
    ))

    agregar_titulo_nivel2(doc, 'Entrenamiento')

    agregar_parrafo(doc, (
        'El modelo fue entrenado durante un máximo de 30 épocas con un batch size de 64. '
        'Se implementaron dos callbacks de optimización: EarlyStopping (detención cuando '
        'la pérdida de validación no mejora en 7 épocas consecutivas, restaurando los '
        'mejores pesos) y ReduceLROnPlateau (reducción de la tasa de aprendizaje al 50% '
        'cuando la pérdida se estanca por 3 épocas).'
    ))

    doc.add_page_break()

    # =========================================================================
    # RESULTADOS
    # =========================================================================
    agregar_titulo_nivel1(doc, 'Resultados Obtenidos')

    agregar_parrafo(doc, (
        'A continuación se presentan los resultados obtenidos en la evaluación del modelo '
        'con el conjunto de prueba de CIFAR-10 y con el dataset de autoría propia. Las '
        'métricas reportadas incluyen accuracy, precisión, recall y F1-score, así como '
        'las matrices de confusión correspondientes.'
    ))

    agregar_titulo_nivel2(doc, 'Métricas del Conjunto de Prueba CIFAR-10')

    agregar_parrafo(doc, (
        'Los resultados detallados del accuracy, precisión, recall, F1-score y las matrices '
        'de confusión se encuentran documentados en el notebook adjunto. Las gráficas de '
        'evolución del entrenamiento muestran la convergencia del modelo y la relación '
        'entre las métricas de entrenamiento y validación a lo largo de las épocas.'
    ))

    agregar_titulo_nivel2(doc, 'Validación Externa con Dataset Propio')

    agregar_parrafo(doc, (
        'La evaluación con el dataset propio de 100+ imágenes permitió medir la capacidad '
        'de generalización del modelo más allá del dataset de entrenamiento. La matriz de '
        'confusión y el reporte de clasificación detallado por clase se incluyen en el '
        'notebook Jupyter adjunto.'
    ))

    agregar_titulo_nivel2(doc, 'Análisis Comparativo')

    agregar_parrafo(doc, (
        'El análisis comparativo entre el rendimiento en el dataset CIFAR-10 y el dataset '
        'propio revela las fortalezas y limitaciones del modelo entrenado. La diferencia '
        'entre ambas métricas refleja la capacidad de generalización del modelo ante datos '
        'no vistos durante el entrenamiento, lo que constituye una prueba rigurosa de la '
        'robustez de la arquitectura diseñada.'
    ))

    doc.add_page_break()

    # =========================================================================
    # PREGUNTAS ORIENTADORAS
    # =========================================================================
    agregar_titulo_nivel1(doc, 'Respuestas a las Preguntas Orientadoras')

    agregar_titulo_nivel2(doc, '¿Cómo se puede mejorar el rendimiento de una CNN en la tarea de clasificación de imágenes?')

    agregar_parrafo(doc, (
        'Existen diversas estrategias comprobadas para mejorar el rendimiento de una CNN '
        'clasificadora. En primer lugar, el data augmentation permite generar variaciones '
        'de las imágenes de entrenamiento mediante rotaciones, volteos y desplazamientos, '
        'lo cual incrementa la diversidad del dataset sin recolectar más datos. En segundo '
        'lugar, una arquitectura más profunda con filtros de 3×3, siguiendo la filosofía '
        'VGG, permite capturar patrones jerárquicos con menor costo computacional que los '
        'filtros grandes. También, la regularización mediante Dropout y Batch Normalization '
        'previene el sobreajuste y estabiliza el entrenamiento (Dadhich, 2018).'
    ))

    agregar_parrafo(doc, (
        'Adicionalmente, el transfer learning utilizando modelos preentrenados como VGG16, '
        'ResNet o Inception permite obtener precisiones superiores con mucho menos '
        'entrenamiento. Como mencionó el profesor Félix en la clase, conviene "usar '
        'frameworks y preentrenamiento / fine-tuning en lugar de entrenar desde cero por '
        'costo computacional" (Gutiérrez Bernal, 2026). Finalmente, el ajuste automático '
        'de hiperparámetros mediante callbacks como ReduceLROnPlateau optimiza la convergencia '
        'del modelo.'
    ))

    agregar_titulo_nivel2(doc, '¿Cómo se pueden aplicar las CNN en otras tareas diferentes al procesamiento de imágenes?')

    agregar_parrafo(doc, (
        'Las CNN se aplican exitosamente en procesamiento de texto utilizando convoluciones '
        '1D sobre secuencias de embeddings de palabras para clasificación de sentimiento y '
        'detección de spam. En procesamiento de audio, el sonido se convierte en '
        'espectrogramas que las CNN procesan como imágenes bidimensionales para '
        'reconocimiento de voz y clasificación de sonidos ambientales. Las CNN 1D '
        'también extraen patrones en series temporales como datos financieros, señales '
        'ECG y datos de sensores IoT (Zafar et al., 2018).'
    ))

    agregar_parrafo(doc, (
        'En bioinformática, las CNN analizan secuencias de ADN codificadas como vectores '
        'para detectar motivos genéticos relevantes. La versatilidad de las CNN radica en '
        'su capacidad para detectar patrones locales que se combinan jerárquicamente, '
        'independientemente de si los datos son píxeles, palabras, frecuencias de audio '
        'o secuencias genéticas.'
    ))

    doc.add_page_break()

    # =========================================================================
    # CONCLUSIONES
    # =========================================================================
    agregar_titulo_nivel1(doc, 'Conclusiones')

    agregar_parrafo(doc, (
        'La implementación de la CNN clasificadora basada en la arquitectura VGG demostró '
        'ser efectiva para la tarea de clasificación de imágenes del dataset CIFAR-10. '
        'La combinación de filtros 3×3 progresivos, BatchNormalization, Dropout y data '
        'augmentation resultó en un modelo robusto capaz de generalizar más allá del '
        'dataset de entrenamiento, como se evidenció en la validación con el dataset propio '
        'de 100+ imágenes.'
    ))

    agregar_parrafo(doc, (
        'Los resultados confirman las recomendaciones del profesor Félix sobre el uso de '
        'arquitecturas VGG con filtros pequeños y profundidad progresiva, así como la '
        'importancia de la validación externa para medir la verdadera capacidad de '
        'generalización de un modelo de deep learning.'
    ))

    doc.add_page_break()

    # =========================================================================
    # REFERENCIAS APA 7
    # =========================================================================
    agregar_titulo_nivel1(doc, 'Referencias')

    referencias = [
        'Dadhich, A. (2018). Chapter 5: Convolutional Neural Networks. '
        'En Practical computer vision: Extract insightful information from images using '
        'TensorFlow, Keras, and OpenCV (pp. 88-125). Packt Publishing.',

        'Gutiérrez Bernal, F. J. (2026, 17 de junio). Clase 7: Arquitecturas de redes '
        'neuronales convolucionales [Clase magistral]. NRC-8773 Visión por Computador, '
        'Corporación Universitaria Minuto de Dios.',

        'Masterson, L. (2019). Chapter 1: Recognizing traffic signs using Convnets. '
        'En TensorFlow deep learning projects: 10 real-world projects on computer vision, '
        'machine translation, chatbots, and reinforcement learning (pp. 6-26). '
        'Packt Publishing.',

        'Zafar, I., Tzanidou, G., Burton, R., Patel, N., y Araujo, L. (2018). '
        'Convolutional Neural Networks. En Hands-on convolutional neural networks with '
        'TensorFlow: Solve computer vision problems with modeling in TensorFlow and Python '
        '(pp. 48-65). Packt Publishing.',
    ]

    for ref in referencias:
        p = doc.add_paragraph()
        p.paragraph_format.line_spacing = 2.0
        p.paragraph_format.first_line_indent = Cm(-1.27)  # Sangría francesa
        p.paragraph_format.left_indent = Cm(1.27)
        run = p.add_run(ref)
        run.font.size = Pt(11)
        run.font.name = 'Calibri'

    # =========================================================================
    # GUARDAR
    # =========================================================================
    output_path = 'Oviedo_Alexander_Video_VozEnOff_S7_VC.docx'
    doc.save(output_path)
    print(f'✅ Documento generado: {output_path}')
    return output_path


# =========================================================================
# FUNCIONES AUXILIARES
# =========================================================================
def agregar_titulo_nivel1(doc, texto):
    """Título APA Nivel 1: Centrado, negrita."""
    p = doc.add_paragraph()
    p.alignment = WD_ALIGN_PARAGRAPH.CENTER
    p.paragraph_format.line_spacing = 2.0
    p.paragraph_format.space_before = Pt(12)
    run = p.add_run(texto)
    run.bold = True
    run.font.size = Pt(11)
    run.font.name = 'Calibri'


def agregar_titulo_nivel2(doc, texto):
    """Título APA Nivel 2: Izquierda, negrita."""
    p = doc.add_paragraph()
    p.alignment = WD_ALIGN_PARAGRAPH.LEFT
    p.paragraph_format.line_spacing = 2.0
    p.paragraph_format.space_before = Pt(12)
    run = p.add_run(texto)
    run.bold = True
    run.font.size = Pt(11)
    run.font.name = 'Calibri'


def agregar_parrafo(doc, texto):
    """Párrafo APA: interlineado doble, sangría primera línea 1.27 cm."""
    p = doc.add_paragraph()
    p.paragraph_format.line_spacing = 2.0
    p.paragraph_format.first_line_indent = Cm(1.27)
    run = p.add_run(texto)
    run.font.size = Pt(11)
    run.font.name = 'Calibri'


if __name__ == '__main__':
    crear_documento()
