enpaiva's picture
Update app.py
e18dfa2 verified
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<init_texts_rows_state), interactive=True )
textboxes.append(textbox_l)
with gr.Column(scale=1, min_width=160):
if i == 0:
textbox_r = gr.Textbox("Fecha: " + datetime.now().strftime("%d/%m/%Y"), show_label=False, elem_classes="text-box", visible = (i<init_texts_rows_state), interactive=False )
else:
textbox_r = gr.Textbox("Título: Descripción", show_label=False, elem_classes="text-box", visible = (i<init_texts_rows_state), interactive=True )
textboxes.append(textbox_r)
with gr.Row():
with gr.Column(scale=1, min_width=160):
plus_button = gr.Button("+")
with gr.Column(scale=1, min_width=160):
minus_button = gr.Button("-")
def variable_outputs_plus(k):
k = int(k)
k = min(max_texts_elements, k + 1)
return [gr.Textbox(visible=True)]*(k) + [gr.Textbox(visible=False)]*(max_texts_elements-k) + [k]
def variable_outputs_minus(k):
k = int(k)
k = max(1, k - 1)
return [gr.Textbox(visible=True)]*(k) + [gr.Textbox(visible=False)]*(max_texts_elements-k) + [k]
plus_button.click(variable_outputs_plus, texts_state, textboxes + [texts_state])
minus_button.click(variable_outputs_minus, texts_state, textboxes + [texts_state])
gr.Markdown("---")
# -----------------------------------------------------------------------------------------------------
gr.Markdown("## Plantilla de Resultados")
gr.Markdown("### Ingrese los resultados con imagen y descripción.")
gr.Markdown("### (Agregue campos con el botón '+', remueva campos con el botón '-')")
images_description_state = gr.State(0)
img_desc_boxes = []
for i in range(max_img_desc_rows):
with gr.Row():
with gr.Column(scale=1, min_width=160):
image = gr.Image(label=f"Imagen {i}", interactive=True, mirror_webcam=False, sources="upload", elem_classes="image-upload", container = True, visible = (i<init_img_desc_rows_state))
img_desc_boxes.append(image)
with gr.Column(scale=1, min_width=160):
description = gr.TextArea("Describa su muestra ... ", label=f"Descripción", visible=(i<init_img_desc_rows_state), elem_classes="description", interactive=True, max_lines=10 )
img_desc_boxes.append(description)
with gr.Row():
with gr.Column(scale=1, min_width=160):
plus_img_desc_button = gr.Button("+")
with gr.Column(scale=1, min_width=160):
minus_img_desc_button = gr.Button("-")
def variable_outputs_plus_img_desc(k):
k = int(k)
k = min(max_img_desc_rows, k + 1)
return [gr.Image(visible=True), gr.TextArea(visible=True)]*k + [gr.Image(visible=False), gr.TextArea(visible=False)]*(max_img_desc_rows-k) + [k]
def variable_outputs_minus_img_desc(k):
k = int(k)
k = max(0, k - 1)
return [gr.TextArea(visible=True)]*(2*k) + [gr.TextArea(visible=False)]*(2*(max_texts_rows-k)) + [k]
plus_img_desc_button.click(variable_outputs_plus_img_desc, images_description_state, img_desc_boxes + [images_description_state])
minus_img_desc_button.click(variable_outputs_minus_img_desc, images_description_state, img_desc_boxes + [images_description_state])
gr.Markdown("---")
# -----------------------------------------------------------------------------------------------------
state_data = gr.State([])
with gr.Row():
submit_button = gr.DownloadButton (label="Generar Reporte")
file_output = gr.File(interactive=False, visible=False)
# Función para mantener la relación de aspecto de la imagen
def get_aspect_ratio_image_size(img, max_width, max_height):
width, height = img.size
aspect_ratio = width / height
if width > 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)