From 722d7dc57d2647bfc2d68910b49946193d27e6c9 Mon Sep 17 00:00:00 2001
From: zhenghu <1831829219@qq.com>
Date: Tue, 14 Apr 2026 18:03:22 +0800
Subject: [PATCH] =?UTF-8?q?refactor(app):=20=E4=BD=BF=E7=94=A8=20Streamlit?=
=?UTF-8?q?=20=E5=8E=9F=E7=94=9F=E7=BB=84=E4=BB=B6=E6=9B=BF=E6=8D=A2?=
=?UTF-8?q?=E8=87=AA=E5=AE=9A=E4=B9=89=20HTML/CSS?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
移除大量自定义样式定义,改用 st.header/caption/subheader/badge/info/divider 等原生组件,
简化 UI 代码并提升可维护性。
---
app.py | 293 +++++++++------------------------------------------------
1 file changed, 46 insertions(+), 247 deletions(-)
diff --git a/app.py b/app.py
index 82eb89c..1d80157 100644
--- a/app.py
+++ b/app.py
@@ -25,187 +25,11 @@ st.set_page_config(
initial_sidebar_state="expanded",
)
-# ─── Custom CSS ──────────────────────────────────────────────────────────────
+# ─── Minimal CSS ─────────────────────────────────────────────────────────────
st.markdown("""
""", unsafe_allow_html=True)
@@ -423,11 +247,11 @@ def build_index() -> tuple[list[dict], list[str], list[str]]:
# ─── Sidebar ─────────────────────────────────────────────────────────────────
with st.sidebar:
- st.markdown('
', unsafe_allow_html=True)
- st.markdown('', unsafe_allow_html=True)
- st.markdown("
", unsafe_allow_html=True)
+ st.header("🌿 病虫害以图搜图")
+ st.caption("上传图片,智能识别相似病虫害")
+ st.divider()
- st.markdown('', unsafe_allow_html=True)
+ st.subheader("🖼️ 输入方式")
input_mode = st.radio("", ["上传本地图片", "输入图片 URL", "选择示例图片"], label_visibility="collapsed")
# 初始化 session_state
@@ -453,7 +277,7 @@ with st.sidebar:
if query_url.strip():
query_source = query_url.strip()
else:
- st.markdown('点击选择示例
', unsafe_allow_html=True)
+ st.caption("点击选择示例")
cols = st.columns(2)
for idx, (name, url) in enumerate(EXAMPLE_IMAGES):
with cols[idx % 2]:
@@ -466,42 +290,32 @@ with st.sidebar:
query_source = query_url
st.image(query_url, use_container_width=True)
- st.markdown('', unsafe_allow_html=True)
+ st.subheader("⚙️ 搜索设置")
top_k = st.slider("返回条数", 1, min(12, len(PEST_KNOWLEDGE)), 5)
- st.markdown("
", unsafe_allow_html=True)
search_clicked = st.button("开始搜索", type="primary", use_container_width=True)
- st.markdown("
", unsafe_allow_html=True)
- st.markdown("""
-
- 使用说明
- 1. 上传病虫害患处图片
- 2. 系统自动提取图像特征
- 3. 与知识库比对返回相似结果
- 4. 参考症状与防治建议
-
- """, unsafe_allow_html=True)
+ st.divider()
+ st.info(
+ "**使用说明**\n\n"
+ "1. 上传病虫害患处图片\n"
+ "2. 系统自动提取图像特征\n"
+ "3. 与知识库比对返回相似结果\n"
+ "4. 参考症状与防治建议"
+ )
# ─── Build Index ─────────────────────────────────────────────────────────────
index_items, succeeded, failed = build_index()
# ─── Main Layout ─────────────────────────────────────────────────────────────
-st.markdown("""
-
-基于 CLIP 视觉模型的病虫害相似度检索与防治建议
-""", unsafe_allow_html=True)
+st.title("🌿 病虫害以图搜图")
+st.caption("基于 CLIP 视觉模型的病虫害相似度检索与防治建议")
# Status badges
-badges = []
if succeeded:
- badges.append(f'📚 知识库 {len(succeeded)} 种')
+ st.badge(f"📚 知识库 {len(succeeded)} 种", color="blue")
if failed:
- badges.append(f'⚠️ 索引失败 {len(failed)} 种')
-if badges:
- st.markdown(f"{''.join(badges)}
", unsafe_allow_html=True)
+ st.badge(f"⚠️ 索引失败 {len(failed)} 种", color="red")
st.markdown("
", unsafe_allow_html=True)
@@ -516,11 +330,11 @@ if search_clicked:
if query_img is not None:
col_query, col_preview = st.columns([1, 3])
with col_query:
- st.markdown('', unsafe_allow_html=True)
+ st.subheader("🔍 查询图片")
st.image(query_img, use_container_width=True)
with col_preview:
- st.markdown('', unsafe_allow_html=True)
+ st.subheader("⏳ 正在分析...")
progress = st.progress(0, text="提取图像特征...")
embedder = get_embedder()
@@ -536,7 +350,7 @@ if search_clicked:
progress.progress(100, text="搜索完成")
progress.empty()
- st.markdown(f'', unsafe_allow_html=True)
+ st.subheader(f"🏆 搜索结果(Top-{len(results)})")
# Similarity bar chart
names = [f"{r[1]['name']}" for r in results]
@@ -566,49 +380,34 @@ if search_clicked:
st.plotly_chart(fig_bar, use_container_width=True)
# Result cards below
- st.markdown('', unsafe_allow_html=True)
+ st.subheader("📋 详细结果")
for rank, (sim, item) in enumerate(results, 1):
- with st.container():
- st.markdown(f"""
-
-
-
-

-
-
-
- {rank}
- {item['name']}
- 相似度 {sim*100:.1f}%
-
-
- {item['crop']}
- {item['category']}
-
-
- 症状:{item['symptoms']}
- 防治:{item['treatment']}
-
-
-
-
- """, unsafe_allow_html=True)
+ with st.container(border=True):
+ c1, c2 = st.columns([1, 4])
+ with c1:
+ st.image(item["url"], use_container_width=True)
+ with c2:
+ header_col, score_col = st.columns([3, 1])
+ header_col.markdown(f"**#{rank} {item['name']}**")
+ score_col.markdown(f"相似度 {sim*100:.1f}%
", unsafe_allow_html=True)
+
+ badge_cols = st.columns([1, 1, 4])
+ badge_cols[0].caption(f"🌾 {item['crop']}")
+ badge_cols[1].caption(f"🐛 {item['category']}" if item["category"] == "虫害" else f"🍃 {item['category']}")
+
+ st.markdown(f"**症状:** {item['symptoms']}")
+ st.markdown(f"**防治:** {item['treatment']}")
# Advisory summary
if results:
best = results[0][1]
- st.markdown('', unsafe_allow_html=True)
- st.markdown(f"""
-
- 系统判断该图片与 {best['name']}({best['crop']}{best['category']})最为相似,相似度 {results[0][0]*100:.1f}%。
- 建议结合田间实际情况进一步确认,参考防治方案:{best['treatment']}
-
- """, unsafe_allow_html=True)
+ st.subheader("💡 初步建议")
+ st.info(
+ f"系统判断该图片与 **{best['name']}**({best['crop']}{best['category']})最为相似,"
+ f"相似度 **{results[0][0]*100:.1f}%**。\n\n"
+ f"建议结合田间实际情况进一步确认,参考防治方案:**{best['treatment']}**"
+ )
# ─── Footer ───────────────────────────────────────────────────────────────────
-st.markdown("
", unsafe_allow_html=True)
-st.markdown("""
-
- 病虫害以图搜图 · 基于 CLIP 视觉模型 · 结果仅供参考,请结合田间实际情况判断
-
-""", unsafe_allow_html=True)
+st.divider()
+st.caption("病虫害以图搜图 · 基于 CLIP 视觉模型 · 结果仅供参考,请结合田间实际情况判断")