Hello everyone,
I’m developing an application in Streamlit that manages several inventory processes like Sales, Purchases, Inventory Replenishment, Warehouse Transfers, etc. However, when I select the “Warehouse Transfers” module, I notice the page takes a long time to load.
I would like to know what elements of Streamlit affect the efficiency of such applications and what I can optimize to reduce the loading time, I notice the page takes approximately 3 minutes to load
We have considered using multi threads, temporary tables, views, but we do not know which is the most optimal.
Steps to reproduce the issue:
- I enter the project folder using Anaconda with VS Code.
- Open the terminal.
- Run the command
streamlit run Gesnas.py
. - Wait for the app to load.
- Select the “Warehouse Transfers” module.
- The page takes a long time to load.
What could be causing this delay and how can I improve performance? What best practices exist to optimize loading times in Streamlit?
This is the code I am using :
import streamlit as st # Importa la librería Streamlit para crear aplicaciones web.
import pandas as pd # Importa pandas para el manejo de datos.
from SystemResources.GesnasDashBoard.DashBoard import DashControlador as DashControlador # Ajusta las rutas de importación si son necesarias
from SystemResources.GesnasDashBoard import TablaDatosControlador #maneja las funciones para graficar y para configuar las tablas de visor de datos
from SystemResources.GesnasDashBoard.Componentes import ComponenteTraslado
from SystemResources.GesnasDashBoard.ModuloTraslado import CalculadoraControlador as CalculadoraTraslado #controlador para realizar calculos de cantidades a trasladar
def main():
if st.session_state.get('estado', False):
st.experimental_rerun()
return
else:
startDate,endDate = ComponenteTraslado.obtenerFechas()
#print(f'{startDate},{endDate}')
almOrigen = ''
almDestino = ''
porcentaje_df = ComponenteTraslado.leer_porcentajes()
# Reemplaza las claves
porcentaje_df = {
"PORCENTAJE_BELLO_MONTE" if k == "Bello Monte" else "PORCENTAJE_VALENCIA" if k == "Valencia" else k: v
for k, v in porcentaje_df.items()
}
porcentaje_df = pd.DataFrame.from_dict([porcentaje_df]).reset_index()
porcentaje_df['PORCENTAJE_BELLO_MONTE'] = porcentaje_df['PORCENTAJE_BELLO_MONTE']/100
porcentaje_df['PORCENTAJE_VALENCIA'] = porcentaje_df['PORCENTAJE_VALENCIA']/100
reposicion = ['Productos Vendidos', f'% de traslado']
if 'filtro' not in st.session_state:
st.session_state['filtro'] = False
if 'recalcular' not in st.session_state:
st.session_state['recalcular'] = False
st.info(f'##### Módulo Traslado de Inventario') # Muestra un mensaje de bienvenida en la página.
listaAlmacenes= ComponenteTraslado.listar_almacenes() #carga la lista de los almacenes disponibles
# Variables para manejar las selecciones dependientes
almacen_valencia = "VALENCIA"
almacen_bello_monte = "BELLO MONTE"
porcentajeTraslado = 30
# Crear columnas para los selectboxes
col1, col2,col3 = st.columns(3)
# Inicialmente, se definen los valores por defecto
origen_default = "VALENCIA"
destino_default = "BELLO MONTE"
# Utilizamos el estado de sesión de Streamlit para manejar las selecciones
if 'origen' not in st.session_state:
st.session_state.origen = origen_default
if 'destino' not in st.session_state:
st.session_state.destino = destino_default
if 'tipo' not in st.session_state:
st.session_state.tipo = 'Seleccionar'
with col1:
#selector de tipos de reposición
tipoReposicion = st.selectbox('Tipo de reposicion',key='tipo_reposicion',options=reposicion)
#permuta los selectores en base al almacén origen o almacé destino seleccionada
with col2:
def update_destino():
#print("hola mundo")
# Lógica para actualizar el destino cuando se selecciona un nuevo origen
selected_origin = st.session_state['origen_select']
#verifica el origen seleccionado si es VALENCIA el destino es BELLO MONTE, y viceversa
if selected_origin == "BELLO MONTE":
st.session_state['seleccionado'] = reposicion[1]
st.session_state['tipo_reposicion'] = reposicion[1]
st.session_state['destino_select']= "VALENCIA"
elif selected_origin == "VALENCIA":
st.session_state['destino_select'] = "BELLO MONTE"
st.session_state['filtro'] = True
almOrigen = st.selectbox('Almacen Origen', options=listaAlmacenes,key='origen_select',on_change=update_destino,index=0)
with col3:
# Ajustar la lista de opciones para Almacen Destino dependiendo de la selección de Almacen Origen
if almOrigen == almacen_valencia:
opciones_destino = [almacen_bello_monte]
elif almOrigen == almacen_bello_monte:
opciones_destino = [almacen_valencia]
else:
opciones_destino = listaAlmacenes.copy()
if almOrigen in opciones_destino:
opciones_destino.remove(almOrigen)
def update_origen():
# Lógica para actualizar el origen cuando se selecciona un nuevo destino
selected_destino = st.session_state['destino_select']
if selected_destino == "BELLO MONTE":
st.session_state['origen_select'] = "VALENCIA"
elif selected_destino == "VALENCIA":
st.session_state['origen_select'] = "BELLO MONTE"
st.session_state['filtro'] = True
almDestino = st.selectbox('Almacen Destino', options=listaAlmacenes,index=1,key='destino_select',on_change=update_origen)
#valida el tipo de reposicion
if tipoReposicion=='Productos Vendidos':
# Añade un encabezado en la barra lateral para los filtros.
#st.subheader('Historial de Productos vendidos')
fechaCol1, fechaCol2 = st.columns((2)) # Crea dos columnas para entrada de fechas.
with fechaCol1:
fecha_desde = pd.to_datetime(st.date_input("###### Fecha Inicio:", startDate)) # Crea un selector de fecha de inicio.
if 'fecha_desde' not in st.session_state:
st.session_state.fecha_desde = startDate
if st.session_state.fecha_desde != fecha_desde:
print('entrando')
st.session_state['filtro'] = True
st.session_state['recalcular']=False
st.session_state.fecha_desde = fecha_desde
if ("FechaError" in st.session_state) and (st.session_state["FechaError"]):
st.error("Debe seleccionar una fecha de venta.")
with fechaCol2:
fecha_hasta = pd.to_datetime(st.date_input("###### Fecha Fin:", endDate)) # Crea un selector de fecha de finalización.
if 'fecha_hasta' not in st.session_state:
st.session_state.fecha_hasta= endDate
if st.session_state.fecha_hasta != fecha_hasta:
st.session_state['filtro'] = True
st.session_state['recalcular']=False
st.session_state.fecha_hasta = fecha_hasta
if ("FechaError" in st.session_state) and (st.session_state["FechaError"]):
st.error("Debe seleccionar una fecha de venta.")
# vendidos_df = ComponenteTraslado.productos_vendidos(fecha_desde,fecha_hasta,st.session_state['destino_select'])
#Despliega el slider de % de reposicion en caso de seleccionar % de reposicion
#convierte a dataframe
#reemplaza las claves
#porcentajeTraslado = st.slider("Seleccione el porcentaje de Traslado",min_value=0,max_value=100,value=30)
#porcentaje_df = ComponenteTraslado.obtener_rango_traslado(porcentajeTraslado)
if tipoReposicion=='Productos Vendidos':
print('calculando A TRASLADAR en base a productos mas vendidos')
_callback_arg = {}
_callback_proc = CalculadoraTraslado.traslado_enFuncHistVentas #callback para definir la funcion de traslado en base a los productos más vendidos
_callback_arg = { #parámetros necesarios
"origen" : almOrigen, #nombre del almacén origen
"destino" : almDestino, #nombre del almacén destino
# "ventas" : vendidos_df, #data frame de los productos más vendidos
"porcentajeTraslado": porcentajeTraslado #porcentaje de existencia actual, en caso que el almacen origen esté por debajo de ese porcentaje
}
else:
print('calculando A TRASLADAR en base al porcentaje de reposicion')
_callback_arg = {}
_callback_proc = CalculadoraTraslado.traslado_enFuncPorcReposicion #callback para definir la funcion de traslado en base al % de reposición
_callback_arg = { #parámetros necesarios
"origen" : almOrigen, #nombre del almacén origen
"destino" : almDestino, #nombre del almacén destino
"porcentaje_VA" : porcentaje_df["PORCENTAJE_VALENCIA"].iloc[0], #porcentaje de existencia actual aceptable en Valencia(por ejemplo 70%)
"porcentaje_BM" : porcentaje_df["PORCENTAJE_BELLO_MONTE"].iloc[0] #porcentaje de existencia actual aceptable en Bello Monte(por ejemplo 30%)
}
#realiza la funcion de calculo de traslacion de inventario y actualiza estos resultados
# en la columna de Cantidad_Trasladar en el visor de existencia actual de productos por depósito
#
if st.session_state['recalcular'] == False:
existencias_df = ComponenteTraslado.existencia_actual_productos(fecha_desde,fecha_hasta,st.session_state['destino_select'])
# existTabla_df = ComponenteTraslado.calcular(existencias_df,_callback_proc,_callback_arg)
existTabla_df = existencias_df
else:
existTabla_df = st.session_state['df_existTabla']
if tipoReposicion!=st.session_state['tipo']:
st.session_state['recalcular'] =True
st.session_state['tipo']=tipoReposicion
existTabla_df = existTabla_df[['CATEGORIA','CODIGO PRODUCTO','NOMBRE PRODUCTO','EXISTENCIA VA','EXISTENCIA BM','EXISTENCIA TOTAL','PESO','A TRASLADAR']]
#agregar columna 'PESO(Kg.)'
existTabla_df['PESO(Kg.)'] = existTabla_df['PESO'] * existTabla_df['A TRASLADAR']
#solo filtra en existTabla todos los que tienen A TRASLADAR mayor que 0
existTabla_df = existTabla_df[existTabla_df['A TRASLADAR'] > 0]
# Inicializar el DataFrame en session_state si no existe
st.session_state['df_existTabla'] = TablaDatosControlador.crearTablaExistencia(existTabla_df,'Existencia actual productos por deposito','Greens',filtrador="codigo_producto_existente",nombre_key="existencias")
TablaDatosControlador.exportarODB(st.session_state['df_existTabla'],arg={
"origen":almOrigen,
"destino":almDestino,
"porcentaje": porcentajeTraslado/100
})
Thank you in advance