File size: 12,317 Bytes
3f7e7e6
d3d8124
3f7e7e6
d3d8124
3f7e7e6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29fefec
3f7e7e6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d3d8124
3f7e7e6
 
 
 
d3d8124
3f7e7e6
 
d3d8124
3f7e7e6
 
 
 
 
 
 
d3d8124
3f7e7e6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
227fa34
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
# UI.py
import gradio as gr
import numpy as np # Necesario para np.inf en los valores por defecto de los l铆mites

def create_interface(process_function_for_button):
    """
    Crea la interfaz de usuario completa para el modelado de bioprocesos.
    Conecta el bot贸n de submit a la 'process_function_for_button' proporcionada.
    """
    
    # Usar un tema est谩ndar de Gradio para mayor compatibilidad.
    # theme='gradio/soft' es una buena opci贸n. Puedes cambiarlo si tienes un tema personalizado que funcione.
    with gr.Blocks(theme='gradio/soft') as demo: 
        gr.Markdown("# Modelado de Bioprocesos con Ecuaciones Personalizadas y An谩lisis por IA")
        gr.Markdown(
            "Sube un archivo Excel con columnas 'Tiempo', 'Biomasa', 'Sustrato', 'Producto'. "
            "Ingresa tus propias ecuaciones (usando 't' para tiempo y 'X_val' para X(t) en ecuaciones de S/P), "
            "los nombres de sus par谩metros, y sus l铆mites. El sistema ajustar谩 los modelos y un LLM analizar谩 los resultados."
        )

        with gr.Row():
            with gr.Column(scale=2):
                gr.Markdown("### 1. Carga de Datos y Configuraci贸n General del Gr谩fico")
                file_input = gr.File(label="Subir archivo Excel (.xlsx)", file_types=[".xlsx"])
                
                show_legend_ui = gr.Checkbox(label="Mostrar leyenda en gr谩ficos", value=True)
                show_params_ui = gr.Checkbox(label="Mostrar par谩metros ajustados en gr谩ficos", value=True)
                legend_position_ui = gr.Dropdown(
                    label="Posici贸n de la leyenda",
                    choices=['best', 'upper right', 'upper left', 'lower right', 'lower left', 'center left', 'center right', 'lower center', 'upper center', 'center'],
                    value='best', # String value, esto est谩 bien
                    type="value" 
                )
            with gr.Column(scale=1):
                gr.Markdown("### 2. Conteo de Ecuaciones a Probar")
                gr.Markdown("Define cu谩ntas ecuaciones diferentes quieres probar para cada componente (1 a 3).")
                # Usar floats para gr.Number, Gradio los maneja bien incluso con precision=0
                biomass_eq_count_ui = gr.Number(label="Ecuaciones de Biomasa:", value=1.0, minimum=1.0, maximum=3.0, step=1.0, precision=0)
                substrate_eq_count_ui = gr.Number(label="Ecuaciones de Sustrato:", value=1.0, minimum=1.0, maximum=3.0, step=1.0, precision=0)
                product_eq_count_ui = gr.Number(label="Ecuaciones de Producto:", value=1.0, minimum=1.0, maximum=3.0, step=1.0, precision=0)

        # --- Secci贸n de Biomasa ---
        with gr.Accordion("3. Definici贸n de Modelos de Biomasa", open=True):
            gr.Markdown("Ingresa la ecuaci贸n (ej: `Xm*(1 - exp(-um*(t - t_lag)))`), los nombres de los par谩metros (ej: `Xm, um, t_lag`), y los l铆mites de los par谩metros (ej: `(0, np.inf), (0, 5), (0, 100)`). Usa `t` como la variable de tiempo.")
            with gr.Row():
                with gr.Column(): # Columna 1 para Biomasa (siempre visible)
                    biomass_eq1_ui = gr.Textbox(label="Ecuaci贸n de Biomasa 1", value="Xm * (1 - exp(-um * (t - t_lag)))", lines=2)
                    biomass_param1_ui = gr.Textbox(label="Par谩metros Biomasa 1", value="Xm, um, t_lag")
                    biomass_bound1_ui = gr.Textbox(label="L铆mites Biomasa 1", value="(0, np.inf), (0, np.inf), (0, np.inf)")
                
                # Columna 2 para Biomasa
                biomass_col2_container = gr.Column(visible=False) 
                with biomass_col2_container:
                    biomass_eq2_ui = gr.Textbox(label="Ecuaci贸n de Biomasa 2", value="X0 * exp(um * t)", lines=2) # Ejemplo: Crecimiento exponencial
                    biomass_param2_ui = gr.Textbox(label="Par谩metros Biomasa 2", value="X0, um")
                    biomass_bound2_ui = gr.Textbox(label="L铆mites Biomasa 2", value="(0, np.inf), (0, np.inf)")
                
                # Columna 3 para Biomasa
                biomass_col3_container = gr.Column(visible=False)
                with biomass_col3_container:
                    biomass_eq3_ui = gr.Textbox(label="Ecuaci贸n de Biomasa 3", lines=2, value="", placeholder="Ej: (X0 * Xm * exp(um * t)) / (Xm - X0 + X0 * exp(um * t))") # Log铆stica
                    biomass_param3_ui = gr.Textbox(label="Par谩metros Biomasa 3", value="", placeholder="X0, Xm, um")
                    biomass_bound3_ui = gr.Textbox(label="L铆mites Biomasa 3", value="", placeholder="(0,np.inf),(0,np.inf),(0,np.inf)")
        
        # --- Secci贸n de Sustrato ---
        with gr.Accordion("4. Definici贸n de Modelos de Sustrato", open=True):
            gr.Markdown("Para Sustrato/Producto, si tu ecuaci贸n depende de la concentraci贸n de biomasa X(t) calculada por un modelo de biomasa, usa `X_val` en tu ecuaci贸n. Ejemplo: `S0 - (X_val / YXS)`.")
            with gr.Row():
                with gr.Column():
                    substrate_eq1_ui = gr.Textbox(label="Ecuaci贸n de Sustrato 1", value="S0 - (X_val / YXS) - mS * t", lines=2)
                    substrate_param1_ui = gr.Textbox(label="Par谩metros Sustrato 1", value="S0, YXS, mS")
                    substrate_bound1_ui = gr.Textbox(label="L铆mites Sustrato 1", value="(0, np.inf), (1e-9, np.inf), (0, np.inf)") # YXS > 0
                
                substrate_col2_container = gr.Column(visible=False)
                with substrate_col2_container:
                    substrate_eq2_ui = gr.Textbox(label="Ecuaci贸n de Sustrato 2", lines=2, value="")
                    substrate_param2_ui = gr.Textbox(label="Par谩metros Sustrato 2", value="")
                    substrate_bound2_ui = gr.Textbox(label="L铆mites Sustrato 2", value="")
                
                substrate_col3_container = gr.Column(visible=False)
                with substrate_col3_container:
                    substrate_eq3_ui = gr.Textbox(label="Ecuaci贸n de Sustrato 3", lines=2, value="")
                    substrate_param3_ui = gr.Textbox(label="Par谩metros Sustrato 3", value="")
                    substrate_bound3_ui = gr.Textbox(label="L铆mites Sustrato 3", value="")

        # --- Secci贸n de Producto ---
        with gr.Accordion("5. Definici贸n de Modelos de Producto", open=True):
            gr.Markdown("Similar a Sustrato, usa `X_val` para la dependencia de la biomasa X(t).")
            with gr.Row():
                with gr.Column():
                    product_eq1_ui = gr.Textbox(label="Ecuaci贸n de Producto 1", value="P0 + YPX * X_val + mP * t", lines=2)
                    product_param1_ui = gr.Textbox(label="Par谩metros Producto 1", value="P0, YPX, mP")
                    product_bound1_ui = gr.Textbox(label="L铆mites Producto 1", value="(0, np.inf), (0, np.inf), (0, np.inf)")
                
                product_col2_container = gr.Column(visible=False)
                with product_col2_container:
                    product_eq2_ui = gr.Textbox(label="Ecuaci贸n de Producto 2", lines=2, value="")
                    product_param2_ui = gr.Textbox(label="Par谩metros Producto 2", value="")
                    product_bound2_ui = gr.Textbox(label="L铆mites Producto 2", value="")
                
                product_col3_container = gr.Column(visible=False)
                with product_col3_container:
                    product_eq3_ui = gr.Textbox(label="Ecuaci贸n de Producto 3", lines=2, value="")
                    product_param3_ui = gr.Textbox(label="Par谩metros Producto 3", value="")
                    product_bound3_ui = gr.Textbox(label="L铆mites Producto 3", value="")

        # L贸gica para mostrar/ocultar campos de ecuaci贸n din谩micamente
        def update_eq_visibility(count_value):
            try:
                # El valor de gr.Number puede ser None si el usuario lo borra
                if count_value is None:
                    count = 0 # O 1, dependiendo de c贸mo quieras manejarlo. 0 ocultar谩 todo.
                else:
                    count = int(float(count_value)) # Convertir a float primero, luego a int
            except ValueError:
                count = 0 # Si la conversi贸n falla, asumir 0
            
            # gr.update es la forma can贸nica de actualizar propiedades
            return gr.update(visible=count >= 2), gr.update(visible=count >= 3)

        # Conectar eventos .change() de los contadores a la funci贸n de visibilidad
        biomass_eq_count_ui.change(fn=update_eq_visibility, inputs=biomass_eq_count_ui, outputs=[biomass_col2_container, biomass_col3_container])
        substrate_eq_count_ui.change(fn=update_eq_visibility, inputs=substrate_eq_count_ui, outputs=[substrate_col2_container, substrate_col3_container])
        product_eq_count_ui.change(fn=update_eq_visibility, inputs=product_eq_count_ui, outputs=[product_col2_container, product_col3_container])
        
        # Bot贸n de env铆o
        submit_button = gr.Button("Procesar y Analizar Modelos", variant="primary", scale=1, elem_id="submit_button_main")
        
        # Salidas
        gr.Markdown("## Resultados del An谩lisis y Modelado")
        with gr.Row():
            # Para la imagen, type="pil" es bueno si tu funci贸n devuelve un objeto PIL.Image
            image_output = gr.Image(label="Gr谩fico Generado de Ajustes", type="pil", scale=2, show_download_button=True, height=750)
            with gr.Column(scale=3):
                analysis_output = gr.Markdown(label="An谩lisis del Modelo por IA")
        
        # Lista de todos los inputs para el bot贸n de submit
        all_inputs_for_button = [
            file_input,
            biomass_eq1_ui, biomass_eq2_ui, biomass_eq3_ui,
            biomass_param1_ui, biomass_param2_ui, biomass_param3_ui,
            biomass_bound1_ui, biomass_bound2_ui, biomass_bound3_ui,
            substrate_eq1_ui, substrate_eq2_ui, substrate_eq3_ui,
            substrate_param1_ui, substrate_param2_ui, substrate_param3_ui,
            substrate_bound1_ui, substrate_bound2_ui, substrate_bound3_ui,
            product_eq1_ui, product_eq2_ui, product_eq3_ui,
            product_param1_ui, product_param2_ui, product_param3_ui,
            product_bound1_ui, product_bound2_ui, product_bound3_ui,
            legend_position_ui,
            show_legend_ui,
            show_params_ui,
            biomass_eq_count_ui,
            substrate_eq_count_ui,
            product_eq_count_ui
        ]
        outputs_for_button = [image_output, analysis_output]

        # Conexi贸n del bot贸n DENTRO del contexto de Blocks
        submit_button.click(
            fn=process_function_for_button, # Usa la funci贸n pasada como argumento
            inputs=all_inputs_for_button,
            outputs=outputs_for_button,
            # api_name="process_data" # Opcional, para nombrar el endpoint de la API
        )

        # Inicializar visibilidad usando demo.load para que se aplique al cargar la UI
        def set_initial_visibility_on_load_wrapper(b_c_val, s_c_val, p_c_val):
            # Obtener los valores iniciales de los gr.Number components y aplicar la l贸gica de visibilidad.
            # Los valores de los Number inputs pueden ser float, convertirlos a int.
            b_c_int = int(float(b_c_val)) if b_c_val is not None else 0
            s_c_int = int(float(s_c_val)) if s_c_val is not None else 0
            p_c_int = int(float(p_c_val)) if p_c_val is not None else 0
            
            b_vis2_upd, b_vis3_upd = update_eq_visibility(b_c_int)
            s_vis2_upd, s_vis3_upd = update_eq_visibility(s_c_int)
            p_vis2_upd, p_vis3_upd = update_eq_visibility(p_c_int)
            
            # Devolver los resultados de gr.update para cada componente de salida del demo.load
            return b_vis2_upd, b_vis3_upd, s_vis2_upd, s_vis3_upd, p_vis2_upd, p_vis3_upd

        demo.load(
            fn=set_initial_visibility_on_load_wrapper, 
            inputs=[biomass_eq_count_ui, substrate_eq_count_ui, product_eq_count_ui], 
            outputs=[
                biomass_col2_container, biomass_col3_container, 
                substrate_col2_container, substrate_col3_container, 
                product_col2_container, product_col3_container
            ]
        )
    return demo