Automatizacion de informes mensuales · CULTIVA IA
# NutriPlan — Generador de informes mensuales from reportlab.lib.pagesizes import A4 from reportlab.platypus import ( SimpleDocTemplate, Paragraph, Table, TableStyle, Spacer ) from reportlab.lib import colors from reportlab.lib.styles import getSampleStyleSheet import pandas as pd from datetime import datetime def crear_informe_clinica(csv_path, clinica, mes): df = pd.read_csv(csv_path) df_clinica = df[df['clinica'] == clinica] doc = SimpleDocTemplate( f"informes/{clinica}_{mes}.pdf", pagesize=A4, topMargin=36 ) styles = getSampleStyleSheet() story = [] # Portada story.append(Paragraph( f"Informe NutriPlan — {mes}", styles['Title'] )) story.append(Paragraph( clinica, styles['Heading2'] )) story.append(Spacer(1, 20)) # Tabla de pacientes data = [['Paciente','Objetivo','Adherencia','Delta']] for _, row in df_clinica.iterrows(): data.append([ row['nombre'], row['objetivo'], f"{row['adherencia']}%", f"{row['delta_kg']:+.1f} kg" ]) t = Table(data, colWidths=[160,80,80,70]) t.setStyle(TableStyle([ ('BACKGROUND',(0,0),(-1,0),colors.HexColor('#2563eb')), ('TEXTCOLOR',(0,0),(-1,0),colors.white), ('ROWBACKGROUNDS',(0,1),(-1,-1), [colors.white, colors.HexColor('#f0f9ff')]) ])) story.append(t) doc.build(story) return f"informes/{clinica}_{mes}.pdf"
# Fusionar parciales y cifrar con contraseña from pypdf import PdfWriter, PdfReader from pathlib import Path import secrets, json def fusionar_pdfs(archivos: list[str], salida: str): """Une varios PDFs en uno.""" writer = PdfWriter() for archivo in archivos: reader = PdfReader(archivo) for page in reader.pages: writer.add_page(page) with open(salida, 'wb') as f: writer.write(f) return salida def cifrar_pdf(entrada: str, clinica_id: str) -> dict: """Cifra PDF y devuelve ruta + contraseña.""" password = secrets.token_urlsafe(12) salida = entrada.replace('.pdf', '_secure.pdf') reader = PdfReader(entrada) writer = PdfWriter() for page in reader.pages: writer.add_page(page) writer.encrypt(password, algorithm="AES-256") with open(salida, 'wb') as f: writer.write(f) # Guardar contraseña de forma segura credentials = json.load(open('credentials.json')) credentials[clinica_id] = { 'pdf': salida, 'pwd': password, 'generado': datetime.now().isoformat() } json.dump(credentials, open('credentials.json','w')) return {'archivo': salida, 'password': password} # Uso en produccion if __name__ == '__main__': clinicas = ['centro-salud-mediterraneo', 'clinica-bienestar-norte'] for c in clinicas: pdf = fusionar_pdfs( [f"informes/{c}_parcial_{i}.pdf" for i in range(1,4)], f"output/{c}_mayo2026.pdf" ) resultado = cifrar_pdf(pdf, c) print(f"✓ {c}: {resultado['archivo']}")
# Conciliacion automatica de facturas PDF import pdfplumber import pandas as pd from pathlib import Path def extraer_tablas_factura(pdf_path: str) -> pd.DataFrame: """Extrae todas las tablas de un PDF de factura.""" tablas = [] with pdfplumber.open(pdf_path) as pdf: for n_pag, pag in enumerate(pdf.pages, 1): for tabla in pag.extract_tables(): if tabla and len(tabla) > 1: df = pd.DataFrame( tabla[1:], columns=tabla[0] ) df['fuente_pdf'] = Path(pdf_path).stem df['pagina'] = n_pag tablas.append(df) return pd.concat(tablas, ignore_index=True) if tablas else pd.DataFrame() def conciliar_facturas(carpeta: str) -> None: """Procesa todos los PDFs de una carpeta.""" pdfs = list(Path(carpeta).glob('*.pdf')) print(f"Procesando {len(pdfs)} facturas...") resultados = [] for pdf in pdfs: try: df = extraer_tablas_factura(str(pdf)) resultados.append(df) print(f" ✓ {pdf.name}: {len(df)} filas") except Exception as e: print(f" ✗ {pdf.name}: {e}") combined = pd.concat(resultados, ignore_index=True) combined.to_excel( "conciliacion_mayo2026.xlsx", index=False, sheet_name="Facturas" ) print(f"\n✅ Excel generado: {len(combined)} filas totales")
# OCR para PDFs escaneados (ej. analíticas antiguas) import pytesseract from pdf2image import convert_from_path from PIL import Image import re def ocr_pdf(pdf_path: str, idioma: str = 'spa') -> str: """Extrae texto de PDF escaneado via OCR.""" imagenes = convert_from_path( pdf_path, dpi=300, # Alta resolución = mejor OCR thread_count=4 # Paralelizar conversión ) texto_completo = [] for i, img in enumerate(imagenes, 1): # Preprocesar: escala grises + contraste img_gray = img.convert('L') texto = pytesseract.image_to_string( img_gray, lang=idioma, config='--psm 6' # Asumir bloque de texto ) texto_completo.append(f"\n--- Página {i} ---\n{texto}") return "\n".join(texto_completo) def extraer_valores(texto: str) -> dict: """Parsea texto OCR buscando métricas de salud.""" patrones = { 'peso': r'Peso[:\s]+(\d+\.?\d*)\s*kg', 'imc': r'IMC[:\s]+(\d+\.?\d*)', 'glucosa': r'Glucosa[:\s]+(\d+)\s*mg', } return { k: re.search(v, texto, re.I).group(1) if re.search(v, texto, re.I) else None for k, v in patrones.items() }
| # | Paciente | Objetivo | Adherencia al plan | Delta peso | Estado |
|---|---|---|---|---|---|
| 01 | Ana Torres | Perdida de peso | -2.4 kg | En objetivo | |
| 02 | Carlos Medina | Control glucemico | -1.1 kg | En objetivo | |
| 03 | Maria Ruiz | Ganancia muscular | +0.3 kg | Seguimiento | |
| 04 | Pedro Alonso | Perdida de peso | +0.8 kg | Alerta | |
| 05 | Sofia Navarro | Colesterol | -1.9 kg | En objetivo | |
| 06 | Luis Garcia | Mantenimiento | +0.1 kg | En objetivo |
# Instalar todas las dependencias Python pip install pypdf pdfplumber reportlab pytesseract pdf2image pandas openpyxl # macOS: herramientas CLI + Tesseract OCR brew install poppler qpdf tesseract tesseract-lang # Verificar instalacion python -c "import pypdf, pdfplumber, reportlab; print('✅ Listo')"