涉及知识点
- 排版 columns :
c1 ,c2,c3 ,c4= st.columns([3,1, 1,1]) 使用with显示
- 单页面交互之button ,交互需要先定义函数 button按下后触发函数,然后使用
st.cache_data.clear() 清除缓存 st.rerun() 及返回,感觉就像AJAX交互一样
- HTML原始标签之markdown页面解析 a标签 img标签,且可以放DataFrame格式数据,以表格显示。
- 查询数据使用pd.DataFrame(rows,columns=cols),及使用lambda处理数据
df['path']=df['path'].apply( lambda name :f'<img src="{base_url}/{name}">' )
- 缓存 @st.cache_data(show_spinner=False, ttl=300) 会把查询信息保存到文件url相同的情况下,不去数据库读取,上面设置是300秒
坑点 A标签不能包裹button 需要CSS来修改
import streamlit as st
from datetime import datetime
import sqlite3
import pathlib
import json,time,os
import pandas as pd
if 'conn' not in st.session_state:
st.session_state.conn=sqlite3.connect(
'ocr.sqlite',
timeout=30.0,
check_same_thread=False
)
st.session_state.cursor=st.session_state.conn.cursor()
def get_id(id):
st.session_state.cursor.execute("SELECT id,done FROM pdf WHERE id=(?) AND done>0",(id,))
if st.session_state.cursor.fetchone():
st.session_state.cursor.execute("SELECT * FROM img WHERE pdf_id=(?)",(id,))
rows=st.session_state.cursor.fetchall()
cols=[desc[0] for desc in st.session_state.cursor.description]
# cols=[desc[0] for desc in st.session_state.cursor.description]#获取键名
return pd.DataFrame(rows,columns=cols)
return False
# streamlit.query_params.get(‘id’)
id=st.query_params.get('id')
if not id:
id=56
base_url = "/app/static/img"
df=get_id(id)
df['path']=df['path'].apply(
lambda name :f'<img src="{base_url}/{name}">'
)
st.markdown(
df.to_html(escape=False, index=False),
unsafe_allow_html=True
)
st.write()
更新代码
import streamlit as st
from datetime import datetime
import sqlite3, json, pathlib, time, os
import pandas as pd
# ---------- 数据库连接 ----------
if "conn" not in st.session_state:
st.session_state.conn = sqlite3.connect(
"ocr.sqlite", timeout=30.0, check_same_thread=False
)
st.session_state.cursor = st.session_state.conn.cursor()
# ---------- 工具函数 ----------
#@st.cache_data(show_spinner=False)
@st.cache_data(show_spinner=False, ttl=300) # 5 分钟后自动失效
def get_id(_id: int) -> pd.DataFrame:
"""根据 pdf.id 拉取所属 img 记录"""
cur = st.session_state.cursor
cur.execute("SELECT * FROM pdf WHERE id=? AND done>0", (_id,))
if not cur.fetchone():
return pd.DataFrame()
cur.execute(
"""SELECT id, path, CASE WHEN done>0 THEN datetime(done,'unixepoch','localtime') ELSE '未执行' END as 状态,
info, done
FROM img
WHERE pdf_id=?""",
(_id,),
)
rows = cur.fetchall()
cols = [desc[0] for desc in cur.description]
df = pd.DataFrame(rows, columns=cols)
# info 是 json 字符串,解析成 dict 方便后面展示
df["info"] = df["info"].apply(json.loads)
return df
def reset_done(img_id: int):
"""把单条 img 的 done 置 0"""
st.session_state.cursor.execute("UPDATE img SET done=0 WHERE id=?", (img_id,))
st.session_state.conn.commit()
# 让缓存失效,重新拉数据
st.cache_data.clear()
# ---------- 主流程 ----------
id = st.query_params.get("id")
if not id:
id = 56
else:
id = int(id)
df = get_id(id)
if df.empty:
st.warning("该 pdf 未找到已处理完成的图片")
st.stop()
# st.write(id)
base_url = "/app/static/img"
# ---------- 方案 A:每行一个按钮 ----------
st.subheader("逐行重置")
for _, row in df.iterrows():
c1 ,c2,c3 ,c4= st.columns([3,1, 1,1])
# 查看图片
with c1:
st.markdown(
f'<a href="{base_url}/{row["path"]}" target="_blank">查看图片</a>',
unsafe_allow_html=True,
)
# 当前 done
with c2:
st.write(row["done"])
with c3:
st.write(row['状态'])
# 重置按钮
with c4:
if st.button("重置", key=f"reset_{row['id']}"):
reset_done(row["id"])
st.rerun() # 立刻刷新页面
# 如果用户改过 done,点“保存”才生效
if st.button("保存修改"):
for _, r in edited.iterrows():
st.session_state.cursor.execute(
"UPDATE img SET done=? WHERE id=?", (r["done"], r["id"])
)
st.session_state.conn.commit()
st.success("已保存")
st.cache_data.clear()
st.rerun()