Streamlit 页面处理流程
截至目前,所有和大模型相关的范例,都运行在本地的控制台上。但在实际的应用场景中,很多时候是以对话窗口的形式,通过网页UI来进行交互:提出问题,显示结果。开发网页,涉及到前端的Html、CSS、JavaScript 等许多的开发,这部分虽然属于“非核心”部分,但同样需要花费掉不少时间。除此以外,开发RAG应用,其前端UI和交互大同小异,个性化程度不高。因此,Streamlit应运而生,它特别适用于开发数据应用,使用纯后端python脚本,生成web界面,使得开发人员可以专注于数据的检索和应用。
Streamlit的官方地址是:https://streamlit.io/。这篇文章主要验证Streamlit最核心的概念,即页面渲染的流程。
在streamlit中,widget即是和用户进行交互的UI控件。不同的widget触发时机不同,对于大多数表单型的widget而言,其在失去焦点(状态变化时)时触发。而widget的触发,会造成页面的重绘,页面的重绘机制相当于重新运行整个脚本。
像st.form或者 st.chat_input这样的widget,在失去焦点时并不会触发重绘,而是在用户提交表单,或者发送聊天内容(按enter键)时。
重新运行脚本是很重的操作,可能带来下面这3个方面的问题:
- 脚本在首次运行时(初始化),可能需要执行一些例如数据加载这样的函数,这些函数执行时间可能比较久、资源消耗也比较高
- 页面上也有很多组件是固定不变的
- 很多的状态,比如说页面浏览次数 或者 其他类似的计数器,需要在每次重新运行脚本时保留
streamlit通过下面3个机制来解决对应的问题(本文不做更详细的介绍,感兴趣可以直接参考官方文档):
- 通过 Cache 对函数进行标记,以进行缓存
- 通过 Frament 机制减少固定组件的刷新
- 通过 session 机制来维持状态
接下里,我们通过下面的脚本,来理解Streamlit页面处理的这一流程。通过 pip install streamlit
安装好streamlit后,编写脚本 simply.py,执行 streamlit run simply.py
,将会运行脚本,同时会启动本地电脑的默认浏览器,显示运行结果:
import streamlit as st if "couter" not in st.session_state: st.session_state.couter = 1 else: st.session_state.couter += 1 title = f'script runs {st.session_state.couter} times' st.title(title) # 打印历史消息 if "msgs" not in st.session_state: st.session_state.msgs = [] container = st.container() for msg in st.session_state.msgs: container.write(msg) print(f'contents:{ st.session_state.msgs }') msg = st.text_input("请输入消息") print(f'input:{ msg }') # 打印最新消息 if msg: container.write(msg) st.session_state.msgs.append(msg) # 加入列表,下次渲染时使用
在输入框依次输入a、b、c。每输入一次后,点击一下widget外的界面(使widget失去焦点触发页面重绘),界面显示结果如下所示:
控制台输出如下所示:
contents:[] input: contents:[] input:a contents:['a'] input:b contents:['a', 'b'] input:c
可以看到页面总共执行了4次:
- 第1次执行:此时没有用户交互,纯粹是显示界面。contents(历史记录为空),input为空
- 第2次执行:输入a,离开焦点后,触发了第2次执行。此时的contents依然为空,text_input返回了a,并通过st.write显示在了页面上。最后才将a添加到了contents中,用于第3次执行脚本时,进行显示。
感谢阅读,希望这篇文章能给你带来帮助!