#!/usr/bin/env python3
"""
Genera el documento .docx complementario para la actividad Semana 5 de PNL.
Formato APA 7 según docs/Normas_APA_7_UNIMINUTO.md

Grupo 7: Alexander Oviedo Fadul, María Fernanda Ruiz Paipilla,
         Neheman Samir Jaller Cerchiaro, William David Obando López
Docente: Nathalia Orozco Morales
"""

from docx import Document
from docx.shared import Pt, Cm, Inches, RGBColor
from docx.enum.text import WD_ALIGN_PARAGRAPH
from docx.enum.section import WD_ORIENT
import os

# ====================================================================
# CONFIGURACIÓN APA 7
# ====================================================================
FONT_NAME = "Calibri"
FONT_SIZE = Pt(11)
MARGIN = Cm(2.54)
LINE_SPACING = 2.0  # Interlineado doble
FIRST_LINE_INDENT = Cm(1.27)

COLAB_LINK = "https://colab.research.google.com/drive/1PEx-RH8_uAU_oEhLstqdjz98gGAOMylV?usp=sharing"

def set_normal_style(doc):
    """Configura el estilo Normal con APA 7."""
    style = doc.styles["Normal"]
    style.font.name = FONT_NAME
    style.font.size = FONT_SIZE
    style.paragraph_format.line_spacing = LINE_SPACING
    style.paragraph_format.space_after = Pt(0)
    style.paragraph_format.space_before = Pt(0)

def set_margins(doc):
    """Configura márgenes APA 7."""
    for section in doc.sections:
        section.top_margin = MARGIN
        section.bottom_margin = MARGIN
        section.left_margin = MARGIN
        section.right_margin = MARGIN

def add_centered_text(doc, text, bold=False, size=None, space_after=0):
    """Agrega texto centrado."""
    p = doc.add_paragraph()
    p.alignment = WD_ALIGN_PARAGRAPH.CENTER
    run = p.add_run(text)
    run.bold = bold
    if size:
        run.font.size = size
    p.paragraph_format.space_after = Pt(space_after)
    return p

def add_body_text(doc, text, indent=True):
    """Agrega texto de cuerpo con sangría APA."""
    p = doc.add_paragraph(text)
    if indent:
        p.paragraph_format.first_line_indent = FIRST_LINE_INDENT
    return p

def add_heading_apa(doc, text, level=1):
    """Agrega encabezados en formato APA 7."""
    p = doc.add_paragraph()
    if level == 1:
        p.alignment = WD_ALIGN_PARAGRAPH.CENTER
        run = p.add_run(text)
        run.bold = True
        run.font.size = FONT_SIZE
    elif level == 2:
        p.alignment = WD_ALIGN_PARAGRAPH.LEFT
        run = p.add_run(text)
        run.bold = True
        run.font.size = FONT_SIZE
    elif level == 3:
        p.alignment = WD_ALIGN_PARAGRAPH.LEFT
        run = p.add_run(text)
        run.bold = True
        run.italic = True
        run.font.size = FONT_SIZE
    p.paragraph_format.space_before = Pt(12)
    p.paragraph_format.space_after = Pt(6)
    return p

# ====================================================================
# CONSTRUIR DOCUMENTO
# ====================================================================
doc = Document()
set_normal_style(doc)
set_margins(doc)

# ------- PORTADA -------
doc.add_paragraph()  # Espacio superior
doc.add_paragraph()
doc.add_paragraph()

add_centered_text(doc, "Reporte de Práctica — Semana 5", bold=True, size=Pt(14), space_after=12)
add_centered_text(doc, "Análisis de Sentimientos y Clasificación Automática de Texto", bold=True, size=Pt(13), space_after=24)
add_centered_text(doc, "Procesamiento Natural del Lenguaje (NRC-8774)", size=Pt(11), space_after=6)
add_centered_text(doc, "Especialización en Inteligencia Artificial", size=Pt(11), space_after=6)
add_centered_text(doc, "Corporación Universitaria Minuto de Dios — UNIMINUTO", size=Pt(11), space_after=24)

add_centered_text(doc, "Grupo 7", bold=True, size=Pt(11), space_after=6)
add_centered_text(doc, "Alexander Oviedo Fadul", size=Pt(11), space_after=3)
add_centered_text(doc, "María Fernanda Ruiz Paipilla", size=Pt(11), space_after=3)
add_centered_text(doc, "Neheman Samir Jaller Cerchiaro", size=Pt(11), space_after=3)
add_centered_text(doc, "William David Obando López", size=Pt(11), space_after=18)

add_centered_text(doc, "Docente: Nathalia Orozco Morales", size=Pt(11), space_after=24)
add_centered_text(doc, "Julio de 2026", size=Pt(11))

doc.add_page_break()

# ------- ENLACE AL NOTEBOOK -------
add_heading_apa(doc, "Enlace al Notebook en Google Colab", level=1)
p = add_body_text(doc, "El notebook completo con el código reproducible, gráficos y análisis detallado se encuentra disponible en el siguiente enlace de Google Colab:", indent=False)

p_link = doc.add_paragraph()
p_link.alignment = WD_ALIGN_PARAGRAPH.CENTER
run_link = p_link.add_run(COLAB_LINK)
run_link.font.color.rgb = RGBColor(0x1A, 0x5F, 0x7A)
run_link.underline = True
p_link.paragraph_format.space_after = Pt(12)

# ------- INTRODUCCIÓN -------
add_heading_apa(doc, "Introducción", level=1)

add_body_text(doc, (
    "El presente reporte documenta los resultados del laboratorio práctico de la Semana 5 "
    "de Procesamiento Natural del Lenguaje, cuyo objetivo fue aplicar técnicas de clasificación "
    "de texto y análisis de sentimientos mediante modelos supervisados y herramientas preentrenadas. "
    "La actividad se desarrolló en dos partes: primero, un análisis de sentimientos sobre el corpus "
    "movie_reviews de NLTK comparando Naive Bayes con TextBlob; segundo, la clasificación automática "
    "de tickets de soporte basada en el caso de estudio de Nexo Digital presentado por la profesora "
    "Nathalia Orozco Morales durante la clase."
))

add_body_text(doc, (
    "El caso Nexo Digital resulta particularmente relevante porque refleja un problema real que "
    "enfrentan muchas organizaciones: la clasificación manual de solicitudes de soporte genera "
    "cuellos de botella operativos, errores de asignación (22% según la auditoría del caso) y retrasos "
    "en la atención al cliente. La implementación de pipelines de PLN basados en TF-IDF con n-gramas "
    "de caracteres y umbrales de abstención permite automatizar el enrutamiento con alta precisión "
    "y optimizar la carga de trabajo del equipo de atención."
))

# ------- MARCO TEÓRICO -------
add_heading_apa(doc, "Marco Teórico", level=1)

add_heading_apa(doc, "Análisis de sentimientos", level=2)
add_body_text(doc, (
    "El análisis de sentimientos es una subdisciplina del procesamiento de lenguaje natural que "
    "busca determinar la actitud, opinión o emoción expresada en un texto (Srinivasa-Desikan, 2018). "
    "Los enfoques principales incluyen métodos basados en lexicón, que utilizan diccionarios de "
    "palabras con polaridad preasignada, y métodos supervisados que aprenden patrones a partir de "
    "datos etiquetados."
))

add_heading_apa(doc, "TF-IDF y representación vectorial", level=2)
add_body_text(doc, (
    "TF-IDF (Term Frequency–Inverse Document Frequency) es una técnica de vectorización que pondera "
    "la importancia de cada término en función de su frecuencia en el documento y su rareza en el "
    "corpus (Ganegedara, 2018). Cuando se combina con n-gramas de caracteres, permite capturar "
    "raíces morfológicas y variantes ortográficas, lo cual es especialmente útil en español donde "
    "las palabras flexionan ampliamente (cancelar, cancelación, cancélenlo)."
))

add_heading_apa(doc, "Clasificación supervisada", level=2)
add_body_text(doc, (
    "Naive Bayes multinomial y la regresión logística son modelos lineales ampliamente utilizados "
    "como baseline en tareas de clasificación de texto (Rajput, 2020). Naive Bayes asume independencia "
    "condicional entre las features dada la clase, lo que, aunque es una suposición fuerte, suele "
    "funcionar sorprendentemente bien en la práctica para datos de texto de alta dimensionalidad."
))

add_heading_apa(doc, "Umbrales de confianza", level=2)
add_body_text(doc, (
    "En sistemas de clasificación automática, el umbral de confianza determina el punto a partir del "
    "cual el modelo clasifica automáticamente un caso o lo deriva a revisión humana. Como discutimos "
    "en clase, un umbral del 45% puede ofrecer ~70% de cobertura automática con ~91% de exactitud "
    "en los casos clasificados, pero este balance debe ajustarse según la sensibilidad del dominio."
))

# ------- METODOLOGÍA -------
add_heading_apa(doc, "Metodología", level=1)

add_heading_apa(doc, "Parte 1: Análisis de sentimientos", level=2)
add_body_text(doc, (
    "Se utilizó el corpus movie_reviews de NLTK (2.000 reseñas de cine, 1.000 positivas y 1.000 "
    "negativas). El preprocesamiento incluyó conversión a minúsculas, eliminación de caracteres "
    "especiales y stopwords, y tokenización. Se entrenó un clasificador Naive Bayes multinomial sobre "
    "vectores TF-IDF (max_features=10.000, sublinear_tf=True), con división 75/25 estratificada y "
    "semilla 42. Se realizó validación cruzada con 5 folds. Los resultados se compararon con TextBlob, "
    "un analizador de sentimiento basado en lexicón preentrenado."
))

add_heading_apa(doc, "Parte 2: Clasificación de tickets", level=2)
add_body_text(doc, (
    "Se utilizó el dataset tickets_soporte.csv proporcionado en clase, con 150 tickets balanceados "
    "en 5 categorías (facturación, soporte técnico, ventas, cancelación, reclamo). Se compararon dos "
    "modelos: (A) TF-IDF de palabras completas con regresión logística como baseline, y (B) TF-IDF de "
    "n-gramas de caracteres (3-5) con regresión logística. Ambos se evaluaron con validación cruzada "
    "estratificada de 5 folds y F1-macro como métrica principal. Se implementó trazabilidad por ticket "
    "(texto, etiqueta real, predicción, confianza) y análisis de umbrales (30%-70%)."
))

# ------- RESULTADOS -------
add_heading_apa(doc, "Resultados", level=1)

add_heading_apa(doc, "Análisis de sentimientos", level=2)
add_body_text(doc, (
    "El modelo Naive Bayes con TF-IDF alcanzó un desempeño robusto sobre el corpus movie_reviews, "
    "superando consistentemente al análisis basado en lexicón de TextBlob. La validación cruzada de "
    "5 folds confirmó la estabilidad del modelo. TextBlob, por su parte, clasificó un porcentaje "
    "significativo de reseñas como neutras, reduciendo su cobertura efectiva. Los detalles numéricos "
    "de precision, recall y F1 por clase se encuentran en el notebook adjunto."
))

add_heading_apa(doc, "Clasificación de tickets", level=2)
add_body_text(doc, (
    "El Modelo B (TF-IDF de n-gramas 3-5) superó consistentemente al Modelo A (TF-IDF de palabras). "
    "Este resultado coincide con la demostración de clase donde la profesora mostró una mejora del F1 "
    "de 0.69 a 0.82. Los n-gramas de caracteres capturan raíces compartidas entre variantes "
    "morfológicas, lo que resulta particularmente útil para tickets en español donde los usuarios "
    "escriben con errores tipográficos y variaciones léxicas."
))

add_body_text(doc, (
    "El análisis de umbrales mostró que con un umbral de 0.45, el modelo puede clasificar "
    "automáticamente una fracción significativa de los tickets con alta exactitud, derivando los casos "
    "ambiguos a revisión humana. Esto es directamente aplicable al caso Nexo Digital, donde la "
    "coordinadora podría reducir su carga de 3h40min diarios a una fracción, enfocándose solo en los "
    "tickets de baja confianza."
))

# ------- CONCLUSIONES -------
add_heading_apa(doc, "Conclusiones", level=1)

add_body_text(doc, (
    "Los modelos supervisados (Naive Bayes, regresión logística) superan consistentemente a las "
    "herramientas basadas en lexicón (TextBlob) cuando se dispone de datos etiquetados, confirmando "
    "la importancia de invertir en la construcción de corpus de calidad específicos para cada dominio."
))

add_body_text(doc, (
    "La representación TF-IDF con n-gramas de caracteres (3-5) es una técnica sencilla pero poderosa "
    "para clasificación de texto en español, donde la flexión morfológica y los errores tipográficos "
    "son comunes. Esta técnica ofrece una mejora significativa sobre el TF-IDF de palabras completas "
    "sin requerir recursos computacionales adicionales."
))

add_body_text(doc, (
    "El sistema de umbrales de confianza con derivación a revisión humana (human-in-the-loop) es "
    "la estrategia operativa adecuada para entornos empresariales como Nexo Digital, donde el costo "
    "de un error de clasificación varía por categoría (los reclamos mal asignados tienen mayor impacto "
    "que las consultas de ventas). La trazabilidad por ticket es indispensable para auditoría, "
    "re-entrenamiento y mejora continua del modelo."
))

add_body_text(doc, (
    "En síntesis, el Grupo 7 concluye que el valor operativo del Procesamiento del Lenguaje Natural "
    "radica en la construcción de sistemas híbridos y adaptativos. La combinación de vectorización "
    "subpalabras (n-gramas 3-5) y políticas de abstención supervisadas (Human-in-the-Loop) permite "
    "que organizaciones con alto volumen de solicitudes, como Nexo Digital, automaticen la atención "
    "con alta certeza y canalicen adecuadamente los casos complejos hacia la revisión humana."
))

# ------- REFERENCIAS -------
add_heading_apa(doc, "Referencias", level=1)

referencias = [
    "Bird, S., Klein, E., & Loper, E. (2009). Natural Language Processing with Python. O'Reilly Media.",
    "Ganegedara, T. (2018). Natural Language Processing with TensorFlow: Teach language to machines using Python's deep learning library. Packt Publishing.",
    "Rajput, A. (2020). Hands-On Natural Language Processing with Python: A practical guide to applying deep learning architectures to your NLP applications. Packt Publishing.",
    "Srinivasa-Desikan, B. (2018). Natural Language Processing and Computational Linguistics: A practical guide to text analysis with Python, Gensim, spaCy, and Keras. Packt Publishing.",
]

for ref in referencias:
    p = doc.add_paragraph(ref)
    p.paragraph_format.first_line_indent = Cm(-1.27)  # Sangría francesa
    p.paragraph_format.left_indent = Cm(1.27)
    p.paragraph_format.space_after = Pt(6)

# ------- GUARDAR -------
output_dir = "/Volumes/NVMe1TB/GitHub/UNIMINUTO/2do CUATRIMESTRE/NRC-8774-Procesamiento Natural Lenguaje/ACTIVIDADES/MA Semana 5"
output_path = os.path.join(output_dir, "Oviedo_Alexander_Reporte_S5_PNL.docx")

doc.save(output_path)
print(f"✅ Documento generado: {output_path}")
