import gradio as gr from fpdf import FPDF from PIL import Image from groq import Groq from datetime import datetime, timezone import base64 from io import BytesIO import time, os max_texts_rows = 5 max_texts_elements = 10 max_img_desc_rows = 5 init_texts_rows_state = 1 init_img_desc_rows_state = 0 custom_css = """ html { height: 100%; margin: 0; display: flex; justify-content: center; align-items: center; } body { min-height: 50vh; aspect-ratio: 1 / 1.414; /* A4 aspect ratio */ width: 100%; /* Full width */ max-width: 210mm; /* Max width for A4 */ max-height: 297mm; /* Max height for A4 */ padding: 10px; /* Optional padding */ box-sizing: border-box; margin: 0 auto; /* Center the block */ overflow: auto; /* Ensure content is scrollable if it exceeds the block size */ gap: 10px; /* Add gap between elements */ border: 1px solid #000; } .gradio-container{ background-color: white; } #logo-upload { min-height: 100px; max-height: 100px; } #text-empresa { min-height: 100px; max-height: 100px; } .text-box { } .image-upload{ min-height: 300px; max-height: 300px; } img { object-fit: contain; } .description { min-height: 300px; max-height: 300px; } h1, h2, h3 { color: rgb(60, 60, 60); } """ api_key = os.getenv("GROQ_API_KEY") client = Groq( api_key=api_key, ) with gr.Blocks(css=custom_css) as demo: gr.Markdown("# Plataforma de Generación de Informes de ViLAB", elem_id="title") gr.Markdown("Importante: Plataforma de prueba experimental, se limita solo al uso didáctico.") gr.Markdown("### Ingrese el nombre de su empresa y su logo [opcional].", elem_id="subtitle") header_items = [] with gr.Row(equal_height=True): with gr.Column(scale=1, min_width=160): nombre_empresa = gr.Textbox("Nombre de la Empresa", label=None, visible = True, container = False, elem_id="text-empresa", interactive=True) header_items.append(nombre_empresa) with gr.Column(scale=1, min_width=160): logo = gr.Image(label="Logo", elem_id="logo-upload", visible=True, interactive=True, mirror_webcam=False, sources="upload") header_items.append(logo) gr.Markdown("---") # ----------------------------------------------------------------------------------------------------- gr.Markdown("## Plantilla de Informes") gr.Markdown("### Ingrese los datos para el informe.") gr.Markdown("### (Agregue campos con el botón '+', remueva campos con el botón '-')") texts_state = gr.State(2) textboxes = [] for i in range(max_texts_rows): with gr.Row(): with gr.Column(scale=1, min_width=160): textbox_l = gr.Textbox("Título: Descripción", show_label=False, elem_classes="text-box", visible = (i max_width or height > max_height: if width / max_width > height / max_height: width = max_width height = width / aspect_ratio else: height = max_height width = height * aspect_ratio return width, height class PDF(FPDF): def __init__(self, datos, *args, **kwargs): super().__init__(*args, **kwargs) self.datos = datos def set_text(self, datos): self.datos = datos def footer(self): self.set_y(-15) self.set_font('Helvetica', '', 8) self.cell(0, 10, 'Página %s' % self.page_no(), 0, new_x='RIGHT', new_y='TOP', align='C') def body(self): # Datos de la Empresa nombre_empresa = "Nombre de la Empresa: " + self.datos[0][0] logo_path = self.datos[0][1] if logo_path is not None: image = Image.fromarray(logo_path) logo_width, logo_height = get_aspect_ratio_image_size(image, 30, 30) self.image(image, 10, self.get_y(), logo_width, logo_height) self.ln(logo_height + 5) self.set_font('Helvetica', '', 12) self.cell(0, 10, nombre_empresa, 0, new_x='LMARGIN', new_y='NEXT', align='L') # Línea horizontal divisoria self.line(10, self.get_y(), self.w - 10, self.get_y()) self.ln(5) # Datos del Informe self.set_font('Helvetica', '', 11) for i in range(len(self.datos[1])): if i%2 != 0: if self.datos[1][i] != "Título: Descripción": self.cell(self.w / 2 - 10, 10, self.datos[1][i], 0, new_x='LMARGIN', new_y='NEXT', align='L') if i%2 == 0: if self.datos[1][i] != "Título: Descripción": self.cell(self.w / 2 - 10, 10, self.datos[1][i], 0, new_x='RIGHT', new_y='TOP', align='L') # Línea horizontal divisoria self.ln(10) self.line(10, self.get_y(), self.w - 10, self.get_y()) self.ln(5) # Datos del Resultado for i in range(len(self.datos[2])): if self.datos[2][i] is not None: image = Image.fromarray(self.datos[2][i]) img_width, img_height = get_aspect_ratio_image_size(image, self.w / 2 - 20, 100) if self.get_y() + img_height + 10 > self.h - 30: self.add_page() self.image(image, 10, self.get_y(), img_width, img_height) if self.datos[3][i] != "Describa su muestra ... ": self.set_font('Helvetica', '', 10) self.set_xy(self.w / 2 + 10, self.get_y()) self.multi_cell(self.w / 2 - 20, None, self.datos[3][i]) self.ln(img_height + 5) else: if self.datos[3][i] != "Describa su muestra ... ": self.set_font('Helvetica', '', 10) if self.get_y() + 10 > self.h - 30: self.add_page() self.set_xy(self.w / 2 + 10, self.get_y()) self.multi_cell(self.w / 2 - 20, None, self.datos[3][i]) # Resumen del Informe self.set_font('Helvetica', '', 10) self.ln(10) # Añadir espacio antes del resumen self.multi_cell(0, 6, "Resumen - Historial Clínico: " + self.datos[4], 0, 'L') def get_values(*args): n_args = len(args) data = [ list(args[0:2]), list(args[2:2+max_texts_elements-1]), list(args[2+max_texts_elements:n_args:2]), list(args[2+max_texts_elements+1:n_args+1:2]) ] nombre_empresa = data[0][0] datos_informe = [i for i in data[1] if i != "Título: Descripción"] resultados_informe = [i for i in data[3] if i != "Describa su muestra ... "] prompt = f"""Eres un narrador del historial clínico en español basado en el siguiente contexto: ------------------------------- Nombre de la empresa: {nombre_empresa} {' - '.join(datos_informe)} Descripciones según las imágenes digitalizadas con ViLAB desde el microscopio: {' - '.join(resultados_informe)} ------------------------------- - Nunca generes información extra fuera del contexto. - Añade informaciones útiles Solo presenta el resumen del historial clínico en un párrafo. Resumen:""" chat_completion = client.chat.completions.create( messages=[ { "role": "user", "content": prompt, } ], model="llama3-70b-8192", ) data.append(chat_completion.choices[0].message.content) # Crear PDF pdf = PDF(data) pdf.add_page() pdf.body() pdf_path = "./documento_generado.pdf" pdf.output(pdf_path) return gr.File(pdf_path, interactive=False, visible=True) submit_button.click(get_values, header_items + textboxes + img_desc_boxes, file_output) if __name__ == "__main__": demo.launch(share=False)