Upload 3 files
Browse files- UI.py +68 -50
- app.py +9 -9
- requirements.txt +4 -1
UI.py
CHANGED
@@ -1,44 +1,52 @@
|
|
1 |
# UI.py
|
2 |
import gradio as gr
|
|
|
3 |
|
4 |
def create_interface(process_function_for_button):
|
5 |
-
with gr.Blocks(theme='
|
6 |
gr.Markdown("# Modelado de Bioprocesos con Ecuaciones Personalizadas y Análisis por IA")
|
7 |
|
8 |
with gr.Row():
|
9 |
with gr.Column(scale=2):
|
10 |
gr.Markdown("### Carga de Datos y Configuración General")
|
11 |
file_input = gr.File(label="Subir archivo Excel (.xlsx)", file_types=[".xlsx"])
|
|
|
12 |
show_legend_ui = gr.Checkbox(label="Mostrar leyenda en gráficos", value=True)
|
13 |
show_params_ui = gr.Checkbox(label="Mostrar parámetros ajustados en gráficos", value=True)
|
14 |
legend_position_ui = gr.Dropdown(
|
15 |
label="Posición de la leyenda",
|
16 |
choices=['best', 'upper right', 'upper left', 'lower right', 'lower left', 'center left', 'center right', 'lower center', 'upper center', 'center'],
|
17 |
-
value='best'
|
18 |
)
|
19 |
with gr.Column(scale=1):
|
20 |
gr.Markdown("### Conteo de Ecuaciones a Probar")
|
21 |
-
|
22 |
-
|
23 |
-
|
|
|
24 |
|
|
|
25 |
with gr.Accordion("Ecuaciones y Parámetros de Biomasa", open=True):
|
26 |
with gr.Row():
|
27 |
-
with gr.Column():
|
28 |
biomass_eq1_ui = gr.Textbox(label="Ecuación de Biomasa 1", value="Xm * (1 - exp(-um * (t - t_lag)))", lines=2, placeholder="Ej: Xm * (1 - exp(-um * (t - t_lag)))")
|
29 |
-
biomass_param1_ui = gr.Textbox(label="Parámetros Biomasa 1", value="Xm, um, t_lag", info="Nombres
|
30 |
-
biomass_bound1_ui = gr.Textbox(label="Límites Biomasa 1", value="(0, np.inf), (0, np.inf), (0, np.inf)", info="Formato: (low,high)
|
31 |
-
|
32 |
-
with
|
|
|
|
|
33 |
biomass_eq2_ui = gr.Textbox(label="Ecuación de Biomasa 2", value="X0 * exp(um * t)", lines=2)
|
34 |
biomass_param2_ui = gr.Textbox(label="Parámetros Biomasa 2", value="X0, um")
|
35 |
biomass_bound2_ui = gr.Textbox(label="Límites Biomasa 2", value="(0, np.inf), (0, np.inf)")
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
|
|
41 |
|
|
|
42 |
with gr.Accordion("Ecuaciones y Parámetros de Sustrato", open=True):
|
43 |
gr.Markdown("Para Sustrato/Producto, usa `X_val` para X(t). Ejemplo: `S0 - (X_val / YXS)` donde YXS es un parámetro.")
|
44 |
with gr.Row():
|
@@ -46,48 +54,56 @@ def create_interface(process_function_for_button):
|
|
46 |
substrate_eq1_ui = gr.Textbox(label="Ecuación de Sustrato 1", value="S0 - (X_val / YXS) - mS * t", lines=2)
|
47 |
substrate_param1_ui = gr.Textbox(label="Parámetros Sustrato 1", value="S0, YXS, mS")
|
48 |
substrate_bound1_ui = gr.Textbox(label="Límites Sustrato 1", value="(0, np.inf), (1e-9, np.inf), (0, np.inf)")
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
|
|
|
|
59 |
|
|
|
60 |
with gr.Accordion("Ecuaciones y Parámetros de Producto", open=True):
|
61 |
with gr.Row():
|
62 |
with gr.Column():
|
63 |
product_eq1_ui = gr.Textbox(label="Ecuación de Producto 1", value="P0 + YPX * X_val + mP * t", lines=2)
|
64 |
product_param1_ui = gr.Textbox(label="Parámetros Producto 1", value="P0, YPX, mP")
|
65 |
product_bound1_ui = gr.Textbox(label="Límites Producto 1", value="(0, np.inf), (0, np.inf), (0, np.inf)")
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
|
|
|
|
76 |
|
77 |
-
|
|
|
|
|
|
|
78 |
return gr.update(visible=count >= 2), gr.update(visible=count >= 3)
|
79 |
|
80 |
-
biomass_eq_count_ui.change(fn=
|
81 |
-
substrate_eq_count_ui.change(fn=
|
82 |
-
product_eq_count_ui.change(fn=
|
83 |
|
84 |
submit_button = gr.Button("Procesar y Analizar", variant="primary", scale=1)
|
85 |
|
86 |
gr.Markdown("## Resultados del Análisis")
|
87 |
with gr.Row():
|
88 |
-
image_output = gr.Image(label="Gráfico Generado", type="pil",
|
89 |
with gr.Column(scale=3):
|
90 |
-
analysis_output = gr.Markdown(label="Análisis del Modelo por IA")
|
91 |
|
92 |
all_inputs_for_button = [
|
93 |
file_input,
|
@@ -116,19 +132,21 @@ def create_interface(process_function_for_button):
|
|
116 |
)
|
117 |
|
118 |
# Inicializar visibilidad usando demo.load para que se aplique al cargar la UI
|
119 |
-
def
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
|
|
|
|
124 |
|
125 |
demo.load(
|
126 |
-
fn=
|
127 |
inputs=[biomass_eq_count_ui, substrate_eq_count_ui, product_eq_count_ui],
|
128 |
outputs=[
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
]
|
133 |
)
|
134 |
return demo
|
|
|
1 |
# UI.py
|
2 |
import gradio as gr
|
3 |
+
import numpy as np # Importar numpy para np.inf
|
4 |
|
5 |
def create_interface(process_function_for_button):
|
6 |
+
with gr.Blocks(theme='gradio/soft') as demo: # Usar un theme común de Gradio
|
7 |
gr.Markdown("# Modelado de Bioprocesos con Ecuaciones Personalizadas y Análisis por IA")
|
8 |
|
9 |
with gr.Row():
|
10 |
with gr.Column(scale=2):
|
11 |
gr.Markdown("### Carga de Datos y Configuración General")
|
12 |
file_input = gr.File(label="Subir archivo Excel (.xlsx)", file_types=[".xlsx"])
|
13 |
+
|
14 |
show_legend_ui = gr.Checkbox(label="Mostrar leyenda en gráficos", value=True)
|
15 |
show_params_ui = gr.Checkbox(label="Mostrar parámetros ajustados en gráficos", value=True)
|
16 |
legend_position_ui = gr.Dropdown(
|
17 |
label="Posición de la leyenda",
|
18 |
choices=['best', 'upper right', 'upper left', 'lower right', 'lower left', 'center left', 'center right', 'lower center', 'upper center', 'center'],
|
19 |
+
value='best' # String value, esto está bien
|
20 |
)
|
21 |
with gr.Column(scale=1):
|
22 |
gr.Markdown("### Conteo de Ecuaciones a Probar")
|
23 |
+
# Asegurar que los valores son numéricos y dentro del rango
|
24 |
+
biomass_eq_count_ui = gr.Number(label="Biomasa (1-3)", value=1, minimum=1, maximum=3, step=1, precision=0)
|
25 |
+
substrate_eq_count_ui = gr.Number(label="Sustrato (1-3)", value=1, minimum=1, maximum=3, step=1, precision=0)
|
26 |
+
product_eq_count_ui = gr.Number(label="Producto (1-3)", value=1, minimum=1, maximum=3, step=1, precision=0)
|
27 |
|
28 |
+
# --- Sección de Biomasa ---
|
29 |
with gr.Accordion("Ecuaciones y Parámetros de Biomasa", open=True):
|
30 |
with gr.Row():
|
31 |
+
with gr.Column(): # Columna 1 siempre visible
|
32 |
biomass_eq1_ui = gr.Textbox(label="Ecuación de Biomasa 1", value="Xm * (1 - exp(-um * (t - t_lag)))", lines=2, placeholder="Ej: Xm * (1 - exp(-um * (t - t_lag)))")
|
33 |
+
biomass_param1_ui = gr.Textbox(label="Parámetros Biomasa 1", value="Xm, um, t_lag", info="Nombres, coma sep. 't' para tiempo. 'X_val' para X(t) en S/P.")
|
34 |
+
biomass_bound1_ui = gr.Textbox(label="Límites Biomasa 1", value="(0, np.inf), (0, np.inf), (0, np.inf)", info="Formato: (low,high). Use np.inf o None.")
|
35 |
+
|
36 |
+
# Definir Columnas 2 y 3 fuera del `with` si se manipula su visibilidad programáticamente
|
37 |
+
biomass_col2_container = gr.Column(visible=False)
|
38 |
+
with biomass_col2_container:
|
39 |
biomass_eq2_ui = gr.Textbox(label="Ecuación de Biomasa 2", value="X0 * exp(um * t)", lines=2)
|
40 |
biomass_param2_ui = gr.Textbox(label="Parámetros Biomasa 2", value="X0, um")
|
41 |
biomass_bound2_ui = gr.Textbox(label="Límites Biomasa 2", value="(0, np.inf), (0, np.inf)")
|
42 |
+
|
43 |
+
biomass_col3_container = gr.Column(visible=False)
|
44 |
+
with biomass_col3_container:
|
45 |
+
biomass_eq3_ui = gr.Textbox(label="Ecuación de Biomasa 3", lines=2, value="") # Explicit empty string
|
46 |
+
biomass_param3_ui = gr.Textbox(label="Parámetros Biomasa 3", value="")
|
47 |
+
biomass_bound3_ui = gr.Textbox(label="Límites Biomasa 3", value="")
|
48 |
|
49 |
+
# --- Sección de Sustrato ---
|
50 |
with gr.Accordion("Ecuaciones y Parámetros de Sustrato", open=True):
|
51 |
gr.Markdown("Para Sustrato/Producto, usa `X_val` para X(t). Ejemplo: `S0 - (X_val / YXS)` donde YXS es un parámetro.")
|
52 |
with gr.Row():
|
|
|
54 |
substrate_eq1_ui = gr.Textbox(label="Ecuación de Sustrato 1", value="S0 - (X_val / YXS) - mS * t", lines=2)
|
55 |
substrate_param1_ui = gr.Textbox(label="Parámetros Sustrato 1", value="S0, YXS, mS")
|
56 |
substrate_bound1_ui = gr.Textbox(label="Límites Sustrato 1", value="(0, np.inf), (1e-9, np.inf), (0, np.inf)")
|
57 |
+
|
58 |
+
substrate_col2_container = gr.Column(visible=False)
|
59 |
+
with substrate_col2_container:
|
60 |
+
substrate_eq2_ui = gr.Textbox(label="Ecuación de Sustrato 2", lines=2, value="")
|
61 |
+
substrate_param2_ui = gr.Textbox(label="Parámetros Sustrato 2", value="")
|
62 |
+
substrate_bound2_ui = gr.Textbox(label="Límites Sustrato 2", value="")
|
63 |
+
|
64 |
+
substrate_col3_container = gr.Column(visible=False)
|
65 |
+
with substrate_col3_container:
|
66 |
+
substrate_eq3_ui = gr.Textbox(label="Ecuación de Sustrato 3", lines=2, value="")
|
67 |
+
substrate_param3_ui = gr.Textbox(label="Parámetros Sustrato 3", value="")
|
68 |
+
substrate_bound3_ui = gr.Textbox(label="Límites Sustrato 3", value="")
|
69 |
|
70 |
+
# --- Sección de Producto ---
|
71 |
with gr.Accordion("Ecuaciones y Parámetros de Producto", open=True):
|
72 |
with gr.Row():
|
73 |
with gr.Column():
|
74 |
product_eq1_ui = gr.Textbox(label="Ecuación de Producto 1", value="P0 + YPX * X_val + mP * t", lines=2)
|
75 |
product_param1_ui = gr.Textbox(label="Parámetros Producto 1", value="P0, YPX, mP")
|
76 |
product_bound1_ui = gr.Textbox(label="Límites Producto 1", value="(0, np.inf), (0, np.inf), (0, np.inf)")
|
77 |
+
|
78 |
+
product_col2_container = gr.Column(visible=False)
|
79 |
+
with product_col2_container:
|
80 |
+
product_eq2_ui = gr.Textbox(label="Ecuación de Producto 2", lines=2, value="")
|
81 |
+
product_param2_ui = gr.Textbox(label="Parámetros Producto 2", value="")
|
82 |
+
product_bound2_ui = gr.Textbox(label="Límites Producto 2", value="")
|
83 |
+
|
84 |
+
product_col3_container = gr.Column(visible=False)
|
85 |
+
with product_col3_container:
|
86 |
+
product_eq3_ui = gr.Textbox(label="Ecuación de Producto 3", lines=2, value="")
|
87 |
+
product_param3_ui = gr.Textbox(label="Parámetros Producto 3", value="")
|
88 |
+
product_bound3_ui = gr.Textbox(label="Límites Producto 3", value="")
|
89 |
|
90 |
+
# Lógica para mostrar/ocultar campos de ecuación dinámicamente
|
91 |
+
def update_eq_visibility(count_value):
|
92 |
+
# count_value es float si viene de gr.Number, convertir a int
|
93 |
+
count = int(count_value)
|
94 |
return gr.update(visible=count >= 2), gr.update(visible=count >= 3)
|
95 |
|
96 |
+
biomass_eq_count_ui.change(fn=update_eq_visibility, inputs=biomass_eq_count_ui, outputs=[biomass_col2_container, biomass_col3_container])
|
97 |
+
substrate_eq_count_ui.change(fn=update_eq_visibility, inputs=substrate_eq_count_ui, outputs=[substrate_col2_container, substrate_col3_container])
|
98 |
+
product_eq_count_ui.change(fn=update_eq_visibility, inputs=product_eq_count_ui, outputs=[product_col2_container, product_col3_container])
|
99 |
|
100 |
submit_button = gr.Button("Procesar y Analizar", variant="primary", scale=1)
|
101 |
|
102 |
gr.Markdown("## Resultados del Análisis")
|
103 |
with gr.Row():
|
104 |
+
image_output = gr.Image(label="Gráfico Generado", type="pil", scale=2, show_download_button=True, height=600) # Ajustar altura
|
105 |
with gr.Column(scale=3):
|
106 |
+
analysis_output = gr.Markdown(label="Análisis del Modelo por IA") # Usar Markdown para mejor formato
|
107 |
|
108 |
all_inputs_for_button = [
|
109 |
file_input,
|
|
|
132 |
)
|
133 |
|
134 |
# Inicializar visibilidad usando demo.load para que se aplique al cargar la UI
|
135 |
+
def set_initial_visibility_on_load_wrapper(b_c, s_c, p_c):
|
136 |
+
# Convertir a int, ya que el valor inicial de gr.Number puede ser float
|
137 |
+
b_c_int, s_c_int, p_c_int = int(b_c), int(s_c), int(p_c)
|
138 |
+
b_vis2_upd, b_vis3_upd = update_eq_visibility(b_c_int)
|
139 |
+
s_vis2_upd, s_vis3_upd = update_eq_visibility(s_c_int)
|
140 |
+
p_vis2_upd, p_vis3_upd = update_eq_visibility(p_c_int)
|
141 |
+
return b_vis2_upd, b_vis3_upd, s_vis2_upd, s_vis3_upd, p_vis2_upd, p_vis3_upd
|
142 |
|
143 |
demo.load(
|
144 |
+
fn=set_initial_visibility_on_load_wrapper,
|
145 |
inputs=[biomass_eq_count_ui, substrate_eq_count_ui, product_eq_count_ui],
|
146 |
outputs=[
|
147 |
+
biomass_col2_container, biomass_col3_container,
|
148 |
+
substrate_col2_container, substrate_col3_container,
|
149 |
+
product_col2_container, product_col3_container
|
150 |
]
|
151 |
)
|
152 |
return demo
|
app.py
CHANGED
@@ -1,8 +1,4 @@
|
|
1 |
# app.py
|
2 |
-
import os
|
3 |
-
|
4 |
-
os.system("pip install --upgrade gradio")
|
5 |
-
|
6 |
import sys
|
7 |
from pathlib import Path
|
8 |
|
@@ -11,15 +7,16 @@ if str(CURRENT_DIR) not in sys.path:
|
|
11 |
sys.path.insert(0, str(CURRENT_DIR))
|
12 |
|
13 |
try:
|
14 |
-
import decorators
|
15 |
from UI import create_interface
|
16 |
import interface as app_interface_module
|
17 |
except ImportError as e:
|
18 |
print(f"Error crítico de importación en app.py: {e}. Asegúrate de que todos los archivos .py estén en el mismo directorio o en PYTHONPATH.")
|
|
|
19 |
sys.exit(1)
|
20 |
|
21 |
|
22 |
-
if decorators.was_real_spaces_gpu_imported():
|
23 |
print("INFO (app.py): El decorador GPU de 'spaces' parece estar disponible.")
|
24 |
print("INFO (app.py): Se definirá una función dummy decorada para satisfacer el chequeo de Gradio si es necesario.")
|
25 |
|
@@ -35,16 +32,19 @@ def main():
|
|
35 |
demo_instance = create_interface(process_function_for_button=app_interface_module.process_and_plot)
|
36 |
|
37 |
print("INFO (app.py): Lanzando la interfaz Gradio localmente...")
|
38 |
-
# Si el error de localhost persiste, prueba con share=True
|
39 |
-
# Esto es más probable si estás en un entorno contenedorizado incluso para "local"
|
40 |
try:
|
41 |
demo_instance.launch()
|
42 |
except ValueError as ve:
|
43 |
-
if "shareable link must be created" in str(ve):
|
44 |
print("ADVERTENCIA (app.py): Falló el lanzamiento local directo, intentando con share=True...")
|
45 |
demo_instance.launch(share=True)
|
46 |
else:
|
|
|
|
|
47 |
raise ve
|
|
|
|
|
|
|
48 |
|
49 |
|
50 |
if __name__ == "__main__":
|
|
|
1 |
# app.py
|
|
|
|
|
|
|
|
|
2 |
import sys
|
3 |
from pathlib import Path
|
4 |
|
|
|
7 |
sys.path.insert(0, str(CURRENT_DIR))
|
8 |
|
9 |
try:
|
10 |
+
import decorators
|
11 |
from UI import create_interface
|
12 |
import interface as app_interface_module
|
13 |
except ImportError as e:
|
14 |
print(f"Error crítico de importación en app.py: {e}. Asegúrate de que todos los archivos .py estén en el mismo directorio o en PYTHONPATH.")
|
15 |
+
print(f"sys.path actual: {sys.path}")
|
16 |
sys.exit(1)
|
17 |
|
18 |
|
19 |
+
if decorators.was_real_spaces_gpu_imported():
|
20 |
print("INFO (app.py): El decorador GPU de 'spaces' parece estar disponible.")
|
21 |
print("INFO (app.py): Se definirá una función dummy decorada para satisfacer el chequeo de Gradio si es necesario.")
|
22 |
|
|
|
32 |
demo_instance = create_interface(process_function_for_button=app_interface_module.process_and_plot)
|
33 |
|
34 |
print("INFO (app.py): Lanzando la interfaz Gradio localmente...")
|
|
|
|
|
35 |
try:
|
36 |
demo_instance.launch()
|
37 |
except ValueError as ve:
|
38 |
+
if "shareable link must be created" in str(ve).lower() or "localhost is not accessible" in str(ve).lower():
|
39 |
print("ADVERTENCIA (app.py): Falló el lanzamiento local directo, intentando con share=True...")
|
40 |
demo_instance.launch(share=True)
|
41 |
else:
|
42 |
+
# Si es otro ValueError, lo relanzamos para verlo completo
|
43 |
+
print(f"Error inesperado de ValueError durante launch(): {ve}")
|
44 |
raise ve
|
45 |
+
except Exception as e_launch:
|
46 |
+
print(f"Error inesperado durante demo.launch(): {e_launch}")
|
47 |
+
raise e_launch
|
48 |
|
49 |
|
50 |
if __name__ == "__main__":
|
requirements.txt
CHANGED
@@ -1,4 +1,7 @@
|
|
1 |
-
|
|
|
|
|
|
|
2 |
numpy
|
3 |
pandas
|
4 |
matplotlib
|
|
|
1 |
+
# requirements.txt
|
2 |
+
gradio==4.29.0
|
3 |
+
# OTRA VERSIÓN ESTABLE RECIENTE DE GRADIO 4.X, por ejemplo, gradio==4.31.0
|
4 |
+
# ¡¡NO uses gradio sin especificar versión si te está instalando la 5.x !!
|
5 |
numpy
|
6 |
pandas
|
7 |
matplotlib
|