Streamlit 使用记录

基础

安装

# 虚拟环境构建
conda create -n stenv python=3.9
conda activate stenv # source activate stenv
# 安装
pip install streamlit
# 查看是否安装成功
streamlit hello

简单运行

# file 001.py
import streamlit as st
st.write('Hello world!')

Run

streamlit run 001.py

使用

常用导入

import streamlit as st
import pandas as pd
import numpy as np
import altair as alt

大部分的基础操作可在 Cheet Sheet , API Reference , Streamlit Magic Cheat Sheets中找到

显示

用于页面显示的常用组件

文本

st.write('Hello')
st.markdown("# This is a Markdown Title")

# st.tiltle / st.header / st.subheader / st.text / st.caption / st.divider

数字

st.write(1234)

公式

st.latex(r''' e^{i\pi} + 1 = 0 ''')

代码块

st.code("""
for i in range(8): 
    foo()
""")

dataframe

df = pd.DataFrame({'a': [1, 2, 3, 4], 'b': [10, 20, 30, 40]})
st.dataframe(df)

指标卡

st.metric(label="Temperature", value="70 °F",delta="1.2 °F", delta_color="inverse")

# 一行3列
col1, col2, col3 = st.columns(3)
col1.metric("Temperature", "70 °F", "1.2 °F")
col2.metric("Wind", "9 mph", "-8%")
col3.metric("Humidity", "86%", "4%")

绘图

c = alt.Chart(df).mark_circle().encode(x='a', y='b', tooltip=['a', 'b'])
st.write(c)

多媒体

st.image('./header.png',width=200)
st.audio(data)
st.video(data)

布局

页面初始设置

# Setting page layout
st.set_page_config(
    page_title="ZJun",
    page_icon="🤖",
    layout="wide",
    initial_sidebar_state="expanded"
)

侧边栏

with st.sidebar:
    st.write("This is a sidebar")

多列

col1, col2, col3 = st.columns(3)

with col1:
   st.xxx
with col2:
   st.xxx
with col3:
   st.xxx

多Tab

tab1, tab2, tab3 = st.tabs(["Cat", "Dog", "Owl"])

with tab1:
	st.xxx
with tab2:
	st.xxx
with tab3:
	st.xxx

展开

	with st.expander("See More"):
	    st.write("test")

容器

with st.container():
   st.write("This is inside the container")

st.write("This is outside the container")

多页面

- 001.py
- pages
	- 002.py
	- 003.py

类似如上目录结构,然后运行最外围的 001.py 即可

操作

用户和页面的交互

按钮

c = st.button("Click me")

跳转

st.link_button("Go to gallery", "https://streamlit.io/gallery")

滑块

age = st.slider('How old are you?', 0, 130, 25) 
# 最小值、最大值和默认数值

单选

option = st.selectbox('What is your favorite color?',('Blue', 'Red', 'Green'))

#圈圈

genre = st.radio(
    "What is your favorite color?",
    ['Blue', 'Red', 'Green'],
    index=None,
)

多选

options = st.multiselect('Do select',['Green', 'Yellow', 'Red', 'Blue'],['Yellow', 'Red'])

确认框

coffee = st.checkbox('Coffee')

开关

st.toggle("Enable")

编辑dataframe

df = pd.DataFrame({'a': [1, 2, 3, 4], 'b': [10, 20, 30, 40]})
edited_df = st.data_editor(df)
st.markdown(f"[0,1] is  **{edited_df.iloc[0,1]}**")

输入

文本

text_input = st.text_input("Enter some text",
                           label_visibility="visible",
                           disabled=False,
                           placeholder='Placeholder text')
                           
st.text_area("Text to translate")

number = st.number_input("Insert a number", value=None, placeholder="Type a number...")

日期

d = st.date_input("When's your birthday", value=None)
st.write('Your birthday is:', d)

颜色

st.color_picker("Pick a color")
# return color like #76b776

填报

import streamlit as st

with st.form("my_form"):
   st.write("Inside the form")
   slider_val = st.slider("Form slider")
   checkbox_val = st.checkbox("Form checkbox")

   # Every form must have a submit button.
   submitted = st.form_submit_button("Submit")
   if submitted:
       st.write("slider", slider_val, "checkbox", checkbox_val)

st.write("Outside the form")

文件

uploaded_file = st.file_uploader("Choose a file")
if uploaded_file is not None:
    stringio = StringIO(uploaded_file.getvalue().decode("utf-8"))
    string_data = stringio.read()
    st.write(string_data)


uploaded_file_csv = st.file_uploader("Choose a csv file", type=["csv"])
if uploaded_file_csv is not None:
    dataframe = pd.read_csv(uploaded_file_csv)
    st.write(dataframe)

图片 (使用的小案例 代码 | 体验)

from PIL import Image
from io import BytesIO

image_file = st.file_uploader("Upload Images", type=["png", "jpg", "jpeg"])
if image_file:
    st.image(Image.open(image_file), width=250)

# 使用函数(转化为字节流保存)
def convert_image(img):
    buf = BytesIO()
    img.save(buf, format="PNG")
    byte_im = buf.getvalue()
    return byte_im

可点击图片

# pip install st-clickable-images
import streamlit as st
from st_clickable_images import clickable_images

clicked = clickable_images(
    [
        "https://images.unsplash.com/photo-1565130838609-c3a86655db61?w=700",
        "https://images.unsplash.com/photo-1565372195458-9de0b320ef04?w=700",
        "https://images.unsplash.com/photo-1582550945154-66ea8fff25e1?w=700",
        "https://images.unsplash.com/photo-1591797442444-039f23ddcc14?w=700",
        "https://images.unsplash.com/photo-1518727818782-ed5341dbd476?w=700",
    ],
    titles=[f"Image #{str(i)}" for i in range(5)],
    div_style={"display": "flex", "justify-content": "center", "flex-wrap": "wrap"},
    img_style={"margin": "5px", "height": "200px"},
)

st.markdown(f"Image #{clicked} clicked" if clicked > -1 else "No image clicked")

视频

img_file_buffer = st.camera_input("Take a picture")

if img_file_buffer is not None:
    # To read image file buffer as a PIL Image:
    st.image(Image.open(img_file_buffer))

音频

import streamlit as st
import numpy as np

### 读取

audio_file = open('myaudio.ogg', 'rb')
audio_bytes = audio_file.read()

st.audio(audio_bytes, format='audio/ogg')

### 处理构建

sample_rate = 44100  # 44100 samples per second
seconds = 2  # Note duration of 2 seconds
frequency_la = 440  # Our played note will be 440 Hz
# Generate array with seconds*sample_rate steps, ranging between 0 and seconds
t = np.linspace(0, seconds, seconds * sample_rate, False)
# Generate a 440 Hz sine wave
note_la = np.sin(frequency_la * t * 2 * np.pi)

st.audio(note_la, sample_rate=sample_rate)

下载

表格

import streamlit as st

@st.cache
def convert_df(df):
    # IMPORTANT: Cache the conversion to prevent computation on every rerun
    return df.to_csv().encode('utf-8')

csv = convert_df(my_large_df)

st.download_button(
    label="Download data as CSV",
    data=csv,
    file_name='large_df.csv',
    mime='text/csv',
)

文本

import streamlit as st

text_contents = '''This is some text'''
st.download_button('Download some text', text_contents)
Copy

图片

import streamlit as st

with open("flower.png", "rb") as file:
    btn = st.download_button(
            label="Download image",
            data=file,
            file_name="flower.png",
            mime="image/png"
          )


# file same as uploaded_file type (字节流)
image_file = st.file_uploader("Upload Images", type=["png", "jpg", "jpeg"])
if image_file:
    st.image(Image.open(image_file), width=250)
    btn = st.download_button(
        label="Download image",
        data=image_file,
        file_name="flower.png",
        mime="image/png"
    )

辅助

进度条

import time

progress_text = "Operation in progress. Please wait."
my_bar = st.progress(0, text=progress_text)

for percent_complete in range(100):
    time.sleep(0.01)
    my_bar.progress(percent_complete + 1, text=progress_text)
time.sleep(1)
my_bar.empty()

st.button("Rerun")

进度加载

import time

with st.spinner('Wait for it...'):
    time.sleep(5)
st.success('Done!')

error / info / warning / success

st.error('This is an error', icon="🚨")
st.info('This is a purely informational message', icon="ℹ️")
st.warning('This is a warning', icon="⚠️")
st.success('This is a success message!', icon="✅")

数据缓存 @st.cache_data

import streamlit as st

@st.cache_data
def fetch_and_clean_data(url):
    # Fetch data from URL here, and then clean it up.
    return data

d1 = fetch_and_clean_data(DATA_URL_1)
# Actually executes the function, since this is the first time it was
# encountered.

d2 = fetch_and_clean_data(DATA_URL_1)
# Does not execute the function. Instead, returns its previously computed
# value. This means that now the data in d1 is the same as in d2.

d3 = fetch_and_clean_data(DATA_URL_2)
# This is a different URL, so the function executes.

Session State

Session State is a way to share variables between reruns, for each user session. In addition to the ability to store and persist state, Streamlit also exposes the ability to manipulate state using Callbacks. Session state also persists across apps inside a multipage app.

st.write(st.session_state)

if 'count' not in st.session_state:
    st.session_state.count = 0
st.session_state.count += 1

# Every widget with a key is automatically added to Session State:
st.text_input("Your name", key="name")
# This exists now:
st.session_state.name

简单问答模式 (不含对话历史)

import streamlit as st
from langchain.llms import Ollama
llm = Ollama(model="mistral")

# Initialize chat history
if "messages" not in st.session_state:
    st.session_state.messages = []

# Display chat messages from history on app rerun
for message in st.session_state.messages:
    with st.chat_message(message["role"]):
        st.markdown(message["content"])

if prompt := st.chat_input():
    st.chat_message("user").write(prompt)
	st.session_state.messages.append({"role": "user", "content": prompt})
    response = llm.stream(prompt)
    with st.chat_message("assistant"):
        placeholder = st.empty()
        full_response = ''
        for item in response:
            full_response += item
            placeholder.markdown(full_response)
        placeholder.markdown(full_response)
    st.session_state.messages.append({"role": "assistant", "content": full_response})


Components

Components are third-party modules that extend what’s possible with Streamlit. Built by creators, for the community

部署

案例

参考