Spaces:
Sleeping
Sleeping
| import os | |
| import uuid | |
| import tempfile | |
| import pandas as pd | |
| from openai import OpenAI | |
| from utils.utils import preparar_bloques_json, preparar_bloques_texto_redes, markdown_a_word_docx, validar_y_leer_excel_encuesta, validar_y_leer_excel_redes, combinar_archivos_docx, clean_text, generar_resumenes_por_red_social | |
| from analysis.global_summary import generar_resumen_global | |
| from datetime import datetime | |
| # Inicializar cliente OpenAI | |
| openai = OpenAI(api_key=os.getenv("OPENAI_API_KEY")) | |
| def cargar_prompt(path): | |
| with open(path, "r", encoding="utf-8") as f: | |
| return f.read() | |
| def analizar_excel_encuesta_y_generar_pdf(archivo_excel, informe): | |
| try: | |
| if archivo_excel is None: | |
| yield [], "❌ Por favor, sube un archivo Excel válido antes de generar el análisis.", None | |
| return | |
| df, error_msg = validar_y_leer_excel_encuesta(archivo_excel) | |
| if error_msg: | |
| yield [], error_msg, None | |
| return | |
| nombre_excel = archivo_excel.name | |
| if informe == "Análisis General de Opiniones y Sentimientos": | |
| system_prompt = "Eres un analista especializado en interpretación de encuestas abiertas." | |
| user_prompt = cargar_prompt("prompts/general_analysis.txt") | |
| elif informe == "Análisis Focalizado por Pregunta": | |
| system_prompt = ( | |
| "Eres un experto en generación de prompts para analizar encuestas abiertas. " | |
| "Tu tarea es crear un prompt completo que combine dos cosas:\n" | |
| "1. Una estructura sugerida del informe (capítulos y subtítulos) basada en las preguntas de la encuesta.\n" | |
| "2. Una instrucción para analizar respuestas siguiendo esa estructura, en formato Markdown, con ejemplos y síntesis final." | |
| ) | |
| preguntas = [str(col).strip() for col in df.columns if col.strip() != ""] | |
| lista_preguntas = "\n".join(f"- {p}" for p in preguntas) | |
| prompt_generador = cargar_prompt("prompts/focused_analysis_generator.txt").replace("{{PREGUNTAS}}", lista_preguntas) | |
| response_prompt = openai.chat.completions.create( | |
| model="gpt-4o-mini", | |
| messages=[ | |
| {"role": "system", "content": system_prompt}, | |
| {"role": "user", "content": prompt_generador} | |
| ], | |
| temperature=0.4 | |
| ) | |
| prompt_generado = response_prompt.choices[0].message.content | |
| if prompt_generado.strip().startswith("```markdown"): | |
| prompt_generado = prompt_generado.split("```markdown", 1)[-1].strip() | |
| user_prompt = prompt_generado.split("```json")[0].strip() | |
| user_prompt += ( | |
| "\n\nPor favor, desarrolla cada sección con profundidad. " | |
| "Incluye al menos tres párrafos por capítulo, con análisis detallado, patrones observados, inferencias, ejemplos y reflexiones que ayuden a comprender mejor el pensamiento de los encuestados. " | |
| "No resumas, sino expande cada punto." | |
| ) | |
| bloques_json = preparar_bloques_json(nombre_excel) | |
| session_id = str(uuid.uuid4())[:8] | |
| temp_dir = os.path.join(tempfile.gettempdir(), f"resumenes_{session_id}") | |
| os.makedirs(temp_dir, exist_ok=True) | |
| resumenes_dir = os.path.join(temp_dir, "resumenes_bloques") | |
| os.makedirs(resumenes_dir, exist_ok=True) | |
| resumenes_texto = "" | |
| for i, bloque_json in enumerate(bloques_json, start=1): | |
| response = openai.chat.completions.create( | |
| model="gpt-4o-mini", | |
| messages=[ | |
| {"role": "system", "content": system_prompt}, | |
| {"role": "user", "content": user_prompt + "\n\n```json\n" + str(bloque_json) + "\n```"} | |
| ], | |
| temperature=0.4 | |
| ) | |
| resumen = response.choices[0].message.content | |
| resumenes_texto += f"\n\n🧩 **Resumen del bloque {i}/{len(bloques_json)} generado**{'-'*80}" | |
| with open(os.path.join(resumenes_dir, f"resumen_bloque_{i}.md"), "w", encoding="utf-8") as f: | |
| f.write(resumen) | |
| yield None, None, resumenes_texto | |
| resumen_global_md = os.path.join(temp_dir, "resumen_global.md") | |
| generar_resumen_global(resumenes_dir, resumen_global_md) | |
| base_name = os.path.splitext(os.path.basename(nombre_excel))[0] | |
| archivo_docx = os.path.join(temp_dir, f"{base_name}_resumen_global.docx") | |
| markdown_a_word_docx(resumen_global_md, archivo_docx) | |
| if os.path.exists(archivo_docx): | |
| yield [archivo_docx], "✅ Análisis completado correctamente.", "✅ Todos los resumenes generados" | |
| else: | |
| yield [], "⚠️ No se pudo generar el archivo Word.", None | |
| except Exception as e: | |
| yield [], f"⚠️ Error inesperado: {str(e)}", None | |
| def analizar_excel_redes_y_generar_pdf(archivo_excel, informe, nombre_cliente=None): | |
| try: | |
| if archivo_excel is None: | |
| yield [], "❌ Por favor, sube un archivo Excel válido antes de generar el análisis.", None | |
| return | |
| df, error_msg = validar_y_leer_excel_redes(archivo_excel) | |
| if error_msg: | |
| yield [], error_msg, None | |
| return | |
| df["texto"] = df["texto"].apply(clean_text) | |
| redes_presentes = sorted(df["red_social"].dropna().unique().tolist()) | |
| lista_redes = ", ".join(redes_presentes) | |
| if informe == "¿Cuál fue HOY mi desempeño en las Redes?": | |
| if not nombre_cliente: | |
| yield [], "⚠️ Por favor, ingrese un nombre de Cliente.", None | |
| return | |
| prompts = { | |
| "desempeno": { | |
| "nombre": "Desempeño", | |
| "system": "Eres un analista que evalúa el impacto de contenidos en redes sociales.", | |
| # "user": cargar_prompt("prompts/redes_desempeno.txt").replace("{{CLIENTE}}", nombre_cliente) | |
| "user_path": cargar_prompt("prompts/redes_desempeno.txt") \ | |
| .replace("{{CLIENTE}}", nombre_cliente) \ | |
| .replace("{{REDES_PRESENTES}}", lista_redes) | |
| }, | |
| "foda": { | |
| "nombre": "FODA", | |
| "system": "Eres un analista que identifica fortalezas, oportunidades, debilidades y amenazas en el discurso de redes sociales.", | |
| "user_path": cargar_prompt("prompts/redes_foda.txt").replace("{{CLIENTE}}", nombre_cliente) | |
| }, | |
| "recomendaciones": { | |
| "nombre": "Recomendaciones", | |
| "system": "Eres un asesor político que genera recomendaciones estratégicas a partir de comentarios en redes.", | |
| "user_path": cargar_prompt("prompts/redes_recomendaciones.txt").replace("{{CLIENTE}}", nombre_cliente) | |
| } | |
| } | |
| elif informe == "Fortalezas y Debilidades en Redes Sociales": | |
| prompts = { | |
| "diagnostico": { | |
| "nombre": "Diagnostico-Global", | |
| "system": "Eres un asesor político que genera recomendaciones estratégicas a partir de comentarios en redes.", | |
| "user_path": cargar_prompt("prompts/redes_diagnostico_global_fyd.txt") | |
| }, | |
| "fyd": { | |
| "nombre": "Fortalezas-Debilidades", | |
| "system": "Eres un analista experto en comunicación política y análisis de redes sociales. Tu tarea es elaborar informes extensos, profesionales y bien estructurados, únicamente en base al contenido textual que se te proporciona. No debes inventar información ni usar conocimientos externos. Tu objetivo es detectar y explicar fortalezas, debilidades, el desempeño de figuras mencionadas y diferencias entre redes sociales. Siempre trabaja con subtítulos claros por red social, un diagnóstico global y justificaciones basadas en los textos reales. Mantén un tono analítico, claro y profesional.", | |
| "user_path": cargar_prompt("prompts/redes_analisis_fortalezas_debilidades.txt") | |
| }, | |
| "figuras": { | |
| "nombre": "Figuras-Principales", | |
| "system": "Eres un analista que evalúa el impacto de contenidos en redes sociales.", | |
| "user_path": cargar_prompt("prompts/redes_analisis_principales_figuras.txt") | |
| } | |
| } | |
| grouped = df.groupby("red_social")["texto"].apply(list) | |
| session_id = str(uuid.uuid4())[:8] | |
| temp_dir = os.path.join(tempfile.gettempdir(), f"resumenes_{session_id}") | |
| os.makedirs(temp_dir, exist_ok=True) | |
| archivos_finales = [] | |
| for red, textos in grouped.items(): | |
| yield None, None, f"📊 Generando análisis para {red}..." | |
| resumen_dir_red = os.path.join(temp_dir, red.lower()) | |
| os.makedirs(resumen_dir_red, exist_ok=True) | |
| # resumenes_por_prompt = generar_resumenes_por_red_social(red, textos, prompts) | |
| bloques = preparar_bloques_texto_redes(textos) | |
| for clave, prompt_info in prompts.items(): | |
| resumen_dir_clave = os.path.join(resumen_dir_red, f"resumenes_{clave}") | |
| os.makedirs(resumen_dir_clave, exist_ok=True) | |
| resumenes_texto = "" | |
| for i, bloque in enumerate(bloques, start=1): | |
| try: | |
| response = openai.chat.completions.create( | |
| model="gpt-4o-mini", | |
| messages=[ | |
| {"role": "system", "content": prompt_info["system"]}, | |
| {"role": "user", "content": prompt_info["user_path"].replace("{{REDES_PRESENTES}}", red) + "\n\n```json\n" + str(bloque) + "\n```"} | |
| ], | |
| temperature=0.4 | |
| ) | |
| resumen = response.choices[0].message.content | |
| except Exception as e: | |
| resumen = f"⚠️ Error al generar el resumen del bloque {i}: {str(e)}" | |
| resumenes_texto += f"\n\n🧩 **Resumen del bloque {i}/{len(bloques)} de la red social ({red}) generado ({prompt_info['nombre']})**{'-'*80}" | |
| with open(os.path.join(resumen_dir_clave, f"resumen_bloque_{i}.md"), "w", encoding="utf-8") as f: | |
| f.write(resumen) | |
| yield None, None, resumenes_texto | |
| resumen_md = os.path.join(resumen_dir_red, f"{clave}_resumen.md") | |
| generar_resumen_global(resumen_dir_clave, resumen_md) | |
| # ✅ Concatenar todos los .md de esta red en resumen_final_red | |
| resumen_final_red = os.path.join(resumen_dir_red, f"resumen_final_{red.lower()}.md") | |
| with open(resumen_final_red, "w", encoding="utf-8") as f_final: | |
| f_final.write(f"# 🧾 Análisis de {red.capitalize()}\n\n") | |
| for clave in prompts.keys(): | |
| resumen_md = os.path.join(resumen_dir_red, f"{clave}_resumen.md") | |
| if os.path.exists(resumen_md): | |
| with open(resumen_md, "r", encoding="utf-8") as f_in: | |
| contenido = f_in.read() | |
| f_final.write(f"\n\n## 📌 Resumen ({clave.upper()})\n\n") | |
| f_final.write(contenido) | |
| docx_file = os.path.join(resumen_dir_red, f"{red}_resumen.docx") | |
| markdown_a_word_docx(resumen_final_red, docx_file) | |
| archivos_finales.append(docx_file) | |
| # ✅ Combinar los 3 Word en uno solo | |
| fecha = datetime.today().strftime("%Y%m%d") | |
| nombre_archivo = f"Análisis_{informe.replace(' ', '_')}_{fecha}.docx" | |
| archivo_docx_unico = os.path.join(temp_dir, nombre_archivo) | |
| combinar_archivos_docx(archivos_finales, archivo_docx_unico) | |
| archivos_finales.append(archivo_docx_unico) | |
| if all(os.path.exists(f) for f in archivos_finales): | |
| yield archivos_finales, "✅ Análisis completo con FODA, desempeño y recomendaciones.", "✅ Documentos generados" | |
| else: | |
| yield [], "⚠️ Faltan uno o más archivos. Revisa errores.", None | |
| except Exception as e: | |
| yield [], f"⚠️ Error inesperado: {str(e)}", None | |