山东大学软件学院项目实训-创新实训-大数据租房推荐智能体-前端部分(1)
这篇博客主要记录一下我在项目第一阶段做的工作:如何用 Streamlit 搭建一个标准的工程骨架,以及如何解决聊天应用中常见的“交互延迟”问题。
1.选择 Streamlit的原因
Streamlit 允许用纯 Python 快速构建界面,且内置了丰富的组件,非常适合大数据租房推荐系统这种数据驱动的系统。
2.项目的结构
刚开始写代码时,我习惯把所有逻辑都堆在 app.py 里。但随着功能增加,文件很快变得难以阅读。为了解决这个问题,我参考了一些工程化的实践,把项目拆分成了几个模块:frontend/app.py:这是应用的入口,只负责页面的布局和组件的调用,不写复杂的业务逻辑。
//AI 选房助手 — Streamlit 入口
from __future__ import annotations
import time
import streamlit as st
from app_lib.config import (
LAYOUT,
LOADING_HINT,
MAX_CHAT_HISTORY,
PAGE_ICON,
PAGE_TITLE,
)
from app_lib.state import append_message, init_session_state
st.set_page_config(
page_title=PAGE_TITLE,
page_icon=PAGE_ICON,
layout=LAYOUT,
initial_sidebar_state="expanded",
)
init_session_state()
def _render_sidebar() -> None:
st.sidebar.header("会话")
st.sidebar.caption(f"历史保留上限:{MAX_CHAT_HISTORY} 条(当前 {len(st.session_state.messages)} 条)")
if st.sidebar.button("清空对话", use_container_width=True):
st.session_state.messages = []
st.session_state.pop("pending_reply", None)
st.rerun()
st.sidebar.divider()
st.sidebar.markdown(
)
def _render_chat() -> None:
st.title(f"{PAGE_ICON} {PAGE_TITLE}")
if prompt := st.chat_input("描述区域、预算、户型等找房需求…"):
append_message("user", prompt)
st.session_state.pending_reply = True
st.rerun()
for msg in st.session_state.messages:
with st.chat_message(msg["role"]):
st.markdown(msg["content"])
if st.session_state.get("pending_reply"):
with st.spinner(LOADING_HINT):
time.sleep(0.15)
reply = (
"已记录您的需求(前端骨架占位回复)。\n\n"
"后续部分将接入:流式输出、房源卡片、图表与地图。"
)
append_message("assistant", reply)
st.session_state.pending_reply = False
st.rerun()
_render_sidebar()
_render_chat()
app_lib/config.py:用来存放所有的配置项,比如页面标题、最大聊天历史记录数
PAGE_TITLE = "AI 选房助手"
PAGE_ICON = "🏠"
LAYOUT = "wide"
//对话历史上限
MAX_CHAT_HISTORY = 50
//单屏房源卡片数量
MAX_LISTING_CARDS_VISIBLE = 10
// 加载提示
LOADING_HINT = "正在响应,请稍候…"
(MAX_CHAT_HISTORY)等。这样做的好处是,如果以后要修改配置,只需要改这一个文件。app_lib/state.py:专门用来管理 st.session_state。聊天应用的核心就是状态管理,把这部分逻辑独立出来,可以让主程序更清晰。
通过这种分层,代码的可维护性提高了不少,也为后续接入真实的 AI 接口留好了接口。
3.核心难点:Streamlit 的执行模型与“双阶段刷新”
在实现聊天功能时,我遇到了一个很典型的问题:当用户点击“发送”后,页面需要重新运行。如果此时直接调用后端接口(假设耗时 2 秒),用户界面就会卡住,直到 AI 回复完成,体验非常差。
理想的情况是:用户点击发送 -> 消息立即显示 -> 出现“AI 正在思考”的 loading 动画 -> AI 回复显示。
为了实现这个效果,我采用了“双阶段 Rerun”的策略:
第一阶段:用户输入内容。程序捕获输入,将用户消息写入 st.session_state,并设置一个 pending_reply=True 的标记,然后立即调用 st.rerun()。
第二阶段:页面重跑。程序检测到 pending_reply 为真,先渲染出用户刚才发的消息,然后进入 with st.spinner() 代码块,显示加载动画。在这个代码块里模拟调用后端(目前是延时),拿到结果后写入会话状态,清除标记,再次重跑。
if prompt := st.chat_input("描述区域、预算、户型等找房需求…"):
append_message("user", prompt)
st.session_state.pending_reply = True
st.rerun()
for msg in st.session_state.messages:
with st.chat_message(msg["role"]):
st.markdown(msg["content"])
if st.session_state.get("pending_reply"):
with st.spinner(LOADING_HINT):
time.sleep(0.15)
reply = (
"已记录您的需求(前端骨架占位回复)。\n\n"
"后续部分将接入:流式输出、房源卡片、图表与地图。"
)
append_message("assistant", reply)
st.session_state.pending_reply = False
st.rerun()
4.总结与展望
目前,项目的第一阶段已经完成。我搭建了一个结构清晰、交互流畅的聊天骨架。虽然现在的 AI 还是个“假”的(只是简单的回显,给出的一般式回复),但地基已经打好了。我接下来将进行优化对话体验,避免长时间卡断
更多推荐
所有评论(0)