
本教程详细阐述了如何在Streamlit仪表板中实现健壮的状态持久化,通过结合Pydantic模型定义应用状态,并利用其高效的JSON序列化能力。我们将探讨如何将Pydantic模型与Streamlit的会话状态(st.session_state)集成,并通过回调函数在用户交互时自动保存状态到JSON文件,确保应用刷新或重新访问时能无缝加载先前配置。
在开发交互式Streamlit仪表板时,管理和持久化应用状态是一个核心挑战。用户对参数进行调整、选择不同选项后,期望这些更改能在页面刷新或重新访问时得以保留。传统的Python变量在Streamlit应用重新运行时会重置,因此需要一种机制来保存这些状态。本教程将介绍如何利用Pydantic模型定义结构化的应用状态,并通过JSON文件实现其持久化,同时结合Streamlit的内置会话状态和回调机制,构建一个高效且易于维护的状态管理系统。
Pydantic是一个强大的数据验证和设置管理库,非常适合用于定义Streamlit应用中的复杂状态结构。它允许我们以类型安全的方式定义数据模型,并提供了便捷的序列化/反序列化功能。
定义Pydantic模型:
首先,我们定义代表应用不同部分状态的Pydantic模型。例如,一个包含相机选择、裁剪参数和处理流程的仪表板状态可以这样定义:
import os
import json
from typing import List, Optional
from pydantic import BaseModel, Field
# 定义状态文件路径
STATE_PATH = os.path.join(os.getcwd(), 'application_state.json')
class SelectCameraState(BaseModel):
"""相机选择状态模型"""
selected_cameras: List[str] = Field(default_factory=list)
class CropState(BaseModel):
"""裁剪参数状态模型"""
crop_type: str = "Anchor" # Anchor / Fixed
bbox: List[int] = Field(default_factory=lambda: [0, 0, 100, 100])
anchor_class: str = "default_class"
anchor_position: List[int] = Field(default_factory=lambda: [50, 50])
class ProcessState(BaseModel):
"""处理流程状态模型"""
feature_extractor: str = "ResNet"
embedding_processor: str = "PCA"
outlier_detector: str = "IsolationForest"
class ApplicationState(BaseModel):
"""整个应用的全局状态模型"""
camera_select_state: SelectCameraState = Field(default_factory=SelectCameraState)
crop_state: CropState = Field(default_factory=CropState)
process_state: ProcessState = Field(default_factory=ProcessState)
class Config:
validate_assignment = True # 启用赋值验证Pydantic的序列化优势:
Pydantic模型的一个关键优势是其内置的JSON序列化方法。与尝试在root_validator中手动处理可变对象(如列表)的更改不同,Pydantic提供了model_dump_json()方法,能够将整个模型及其嵌套的可变对象正确地序列化为JSON字符串。
# 示例:创建一个ApplicationState实例并序列化 initial_state = ApplicationState() initial_state.camera_select_state.selected_cameras = ["Camera A", "Camera B"] json_output = initial_state.model_dump_json(indent=2) print(json_output)
为了实现状态持久化,我们需要将Pydantic模型序列化后的JSON字符串写入文件,并在应用启动时从该文件加载状态。
Easily find JSON paths within JSON objects using our intuitive Json Path Finder
30
状态加载函数:
def load_application_state() -> ApplicationState:
"""从JSON文件加载应用状态,如果文件不存在则返回默认状态。"""
if os.path.exists(STATE_PATH):
try:
with open(STATE_PATH, 'r') as f:
state_data = json.load(f)
return ApplicationState.model_validate(state_data) # 使用model_validate进行反序列化
except Exception as e:
st.error(f"加载状态文件失败: {e},将使用默认状态。")
return ApplicationState()
return ApplicationState() # 文件不存在,返回默认状态状态保存函数:
def save_application_state(state: ApplicationState):
"""将应用状态保存到JSON文件。"""
try:
with open(STATE_PATH, 'w') as f:
f.write(state.model_dump_json(indent=2)) # 使用model_dump_json进行序列化
except Exception as e:
st.error(f"保存状态文件失败: {e}")Streamlit提供了st.session_state作为内置的会话状态管理机制,它在用户会话期间保持数据不变。我们可以将Pydantic模型实例存储在st.session_state中,并通过Streamlit组件的on_change回调函数触发状态的保存。
集成流程:
完整示例:
import streamlit as st
import os
import json
from typing import List, Optional
from pydantic import BaseModel, Field
# 定义状态文件路径 (与前面相同)
STATE_PATH = os.path.join(os.getcwd(), 'application_state.json')
# 定义Pydantic模型 (与前面相同)
class SelectCameraState(BaseModel):
selected_cameras: List[str] = Field(default_factory=list)
class CropState(BaseModel):
crop_type: str = "Anchor"
bbox: List[int] = Field(default_factory=lambda: [0, 0, 100, 100])
anchor_class: str = "default_class"
anchor_position: List[int] = Field(default_factory=lambda: [50, 50])
class ProcessState(BaseModel):
feature_extractor: str = "ResNet"
embedding_processor: str = "PCA"
outlier_detector: str = "IsolationForest"
class ApplicationState(BaseModel):
camera_select_state: SelectCameraState = Field(default_factory=SelectCameraState)
crop_state: CropState = Field(default_factory=CropState)
process_state: ProcessState = Field(default_factory=ProcessState)
class Config:
validate_assignment = True
# 状态加载和保存函数 (与前面相同)
def load_application_state() -> ApplicationState:
if os.path.exists(STATE_PATH):
try:
with open(STATE_PATH, 'r') as f:
state_data = json.load(f)
return ApplicationState.model_validate(state_data)
except Exception as e:
st.error(f"加载状态文件失败: {e},将使用默认状态。")
return ApplicationState()
return ApplicationState()
def save_application_state_callback():
"""用于Streamlit on_change的回调函数,保存当前会话状态。"""
if 'app_state' in st.session_state:
save_application_state(st.session_state.app_state)
# --- Streamlit 应用主逻辑 ---
# 1. 初始化或加载应用状态到st.session_state
if 'app_state' not in st.session_state:
st.session_state.app_state = load_application_state()
st.title("Streamlit仪表板状态持久化示例")
# 2. 显示和修改相机选择状态
st.header("相机选择")
available_cameras = ["Camera A", "Camera B", "Camera C", "Camera D"]
selected_cameras = st.multiselect(
"选择相机",
options=available_cameras,
default=st.session_state.app_state.camera_select_state.selected_cameras,
on_change=save_application_state_callback, # 绑定保存回调
key="camera_multiselect" # 确保每个组件有唯一的key
)
# 更新Pydantic模型中的状态
st.session_state.app_state.camera_select_state.selected_cameras = selected_cameras
# 3. 显示和修改裁剪参数状态
st.header("裁剪参数")
crop_type_options = ["Anchor", "Fixed"]
crop_type = st.radio(
"裁剪类型",
options=crop_type_options,
index=crop_type_options.index(st.session_state.app_state.crop_state.crop_type),
on_change=save_application_state_callback, # 绑定保存回调
key="crop_type_radio"
)
st.session_state.app_state.crop_state.crop_type = crop_type
bbox_col1, bbox_col2, bbox_col3, bbox_col4 = st.columns(4)
with bbox_col1:
bbox_x = st.number_input("BBox X", value=st.session_state.app_state.crop_state.bbox[0], on_change=save_application_state_callback, key="bbox_x")
with bbox_col2:
bbox_y = st.number_input("BBox Y", value=st.session_state.app_state.crop_state.bbox[1], on_change=save_application_state_callback, key="bbox_y")
with bbox_col3:
bbox_w = st.number_input("BBox Width", value=st.session_state.app_state.crop_state.bbox[2], on_change=save_application_state_callback, key="bbox_w")
with bbox_col4:
bbox_h = st.number_input("BBox Height", value=st.session_state.app_state.crop_state.bbox[3], on_change=save_application_state_callback, key="bbox_h")
st.session_state.app_state.crop_state.bbox = [bbox_x, bbox_y, bbox_w, bbox_h]
# 4. 显示和修改处理流程状态
st.header("处理流程")
feature_extractor = st.selectbox(
"特征提取器",
options=["ResNet", "VGG", "EfficientNet"],
index=["ResNet", "VGG", "EfficientNet"].index(st.session_state.app_state.process_state.feature_extractor),
on_change=save_application_state_callback,
key="feature_extractor_select"
)
st.session_state.app_state.process_state.feature_extractor = feature_extractor
# 5. 显示当前完整状态 (用于调试)
st.subheader("当前应用状态 (实时更新)")
st.json(st.session_state.app_state.model_dump())
# 每次Streamlit脚本重新运行时,都会从st.session_state中获取状态,
# 而st.session_state在用户会话期间是持久的。
# 当用户改变UI组件时,on_change回调会触发,将最新的Pydantic模型保存到JSON文件。通过结合Pydantic模型、JSON文件持久化以及Streamlit的会话状态和回调机制,我们能够构建一个强大且可靠的Streamlit应用状态管理系统。这种方法不仅保证了应用状态在刷新后的持久性,还通过Pydantic提供了类型安全和清晰的状态结构定义,极大地提高了代码的可维护性和健壮性。遵循本教程的指导,开发者可以有效地为他们的Streamlit仪表板添加高级状态持久化功能。
以上就是在Streamlit中实现基于Pydantic和JSON的状态持久化教程的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号