功能扩充:构建了一个功能完善的侧边栏会话管理系统。它不仅能创建新对话,还能列出历史会话并提供加载和删除的入口。可以把它看作一个聊天应用的“文件管理器”,让你能保存、回顾和整理不同的对话。

代码扩充:

# 生成会话标识函数
def generate_session_name():
    return datetime.now().strftime("%Y-%m-%d_%H-%M-%S")

# 保存会话信息函数
def save_session():
    if st.session_state.current_session:
        # 构建新的会话对象
        session_data = {
            "nick_name": st.session_state.nick_name,
            "nature": st.session_state.nature,
            "current_session": st.session_state.current_session,
            "messages": st.session_state.messages
        }

        # 如果 sessions 目录不存在, 则创建
        if not os.path.exists("sessions"):
            os.mkdir("sessions")

        # 保存会话数据
        with open(f"sessions/{st.session_state.current_session}.json", "w", encoding="utf-8") as f:
            json.dump(session_data, f, ensure_ascii=False, indent=2)

# 加载所有的会话列表信息
def load_sessions():
    session_list = []
    # 加载sessions目录下的文件
    if os.path.exists("sessions"):
        file_list = os.listdir("sessions")
        for filename in file_list:
            if filename.endswith(".json"):
                session_list.append(filename[:-5])
    return session_list


# 会话标识
if "current_session" not in st.session_state:
    st.session_state.current_session = generate_session_name()

with st.sidebar:
    # 会话信息
    st.subheader("AI控制面板")

    # 新建会话
    if st.button("新建会话", width="stretch", icon="✏️"):
        # 1. 保存当前会话信息
        save_session()

        # 2. 创建新的会话
        if st.session_state.messages: # 如果聊天信息非空, True; 否则,  False
            st.session_state.messages = []
            st.session_state.current_session = generate_session_name()
            save_session()
            st.rerun()  # 重新运行当前页面

    # 会话历史
    st.text("会话历史")
    session_list = load_sessions()
    for session in session_list:
        col1,col2 = st.columns([4,1])
        with col1:
           # 加载会话信息
           if st.button(session, width="stretch", icon="📄", key=f"load_{session}"):
               pass
        with col2:
            # 删除会话信息
            if st.button("", width="stretch", icon="❌️", key=f"delete_{session}"):
                pass

(1)创建侧边栏和标题

with st.sidebar:
    st.subheader("AI控制面板")
  • with st.sidebar::这行代码定义了一个上下文管理器。所有缩进在它下面的代码都会被放置在应用界面左侧的侧边栏中,而不是主区域。
  • st.subheader("AI控制面板"):在侧边栏顶部添加一个副标题,作为这个区域的标识。

(2)“新建会话”按钮的逻辑

with st.sidebar:
    st.subheader("AI控制面板")
    if st.button("新建会话", width="stretch", icon="✏️"):
        save_session()
        if st.session_state.messages:
            st.session_state.messages = []
            st.session_state.current_session = generate_session_name()
            save_session()
            st.rerun()

1) if st.button(...):检测用户是否点击了“新建会话”按钮。

2) save_session()先保存当前对话。在开始新话题前,把正在进行中的对话保存到历史记录里,防止内容丢失。

3) if st.session_state.messages::检查当前是否真的有对话内容。如果当前就是空的,就没必要执行后面的清空操作。

4) st.session_state.messages = []清空当前对话。将存储聊天记录的列表重置为空,相当于擦掉黑板,准备开始新的对话。

5) st.session_state.current_session = generate_session_name()为新会话命名。调用一个函数(generate_session_name())来生成一个新会话的名称,比如“新对话 1”、“新对话 2”等。

6) save_session()保存新会话的元数据。将新会话的名称等信息保存到持久化存储(如文件或数据库)中,这样它才会出现在下方的历史列表里。

7) st.rerun()强制刷新页面。这是最关键的一步。它会立即重新运行整个脚本,让用户能立刻看到一个干净的聊天界面和更新后的历史会话列表。

(3) “遍历列表 -> 创建行 -> 分割列 -> 放置按钮”

st.text("会话历史")
    session_list = load_sessions()
    for session in session_list:
        col1,col2 = st.columns([4,1])
        with col1:
            if st.button(session, width="stretch", icon="📄", key=f"load_{session}"):
                pass
        with col2:
            if st.button("", width="stretch", icon="❌️", key=f"delete_{session}"):
                pass

1)标题与数据获取

st.text("会话历史")
session_list = load_sessions()
  • st.text("会话历史"):在界面上显示一个简单的文本标题,告诉用户下面这一堆按钮是什么。
  • session_list = load_sessions():调用一个自定义函数(通常是从本地文件或数据库中)获取所有已保存的会话名称列表。比如返回 ['对话1', '对话2']

2)循环渲染每一行

for session in session_list:

3)创建左右布局 (核心技巧)

    col1, col2 = st.columns([4, 1])
  • st.columns([4, 1]):这是 Streamlit 的布局魔法。它把当前行分成了两列。
    • [4, 1]:这是宽度比例。
    • col1 (占 4 份宽):用来放“会话名称”按钮,占据大部分空间。
    • col2 (占 1 份宽):用来放“删除”按钮,只占很小一块地方,像个图标按钮。

4).左侧:加载按钮

    with col1:
        if st.button(session, width="stretch", icon="📄", key=f"load_{session}"):
            pass
  • with col1::表示接下来的代码都在左边这个宽列里。
  • st.button(session, ...):创建一个按钮。
    • session:按钮上显示的文字,就是会话的名字(比如“对话1”)。
    • width="stretch":让按钮宽度填满整个 col1 容器,看起来整齐美观。
    • icon="📄":给按钮加一个文档图标,增加辨识度。
    • key=f"load_{session}"非常重要!
      • Streamlit 要求每个组件必须有唯一的 key
      • 如果不加这个,当你有多个会话时,Streamlit 会报错(因为会有多个按钮都叫“对话1”)。
      • 加上 f"load_" 前缀,确保了 key 的唯一性(如 load_对话1)。
  • if ...: pass:这里目前是空的。实际开发中,你会在这里写 load_session(session) 代码,实现点击后加载该会话历史的功能。

5).右侧:删除按钮

    with col2:
        if st.button("", width="stretch", icon="❌️", key=f"delete_{session}"):
            pass
  • with col2::表示接下来的代码都在右边这个窄列里。
  • st.button("", ...):创建一个按钮。
    • "":按钮文字为空,只显示图标。
    • icon="❌️":显示一个红色的叉号图标,代表删除。
    • key=f"delete_{session}":同样,为了防止冲突,删除按钮的 key 必须也是唯一的(如 delete_对话1)。
  • if ...: pass:这里也是空的。实际开发中,你会在这里写 delete_session(session) 代码,实现点击后删除该会话文件的功能。

(4)保存会话信息函数

# 保存会话信息函数
def save_session():
    if st.session_state.current_session:
        # 构建新的会话对象
        session_data = {
            "nick_name": st.session_state.nick_name,
            "nature": st.session_state.nature,
            "current_session": st.session_state.current_session,
            "messages": st.session_state.messages
        }

        # 如果 sessions 目录不存在, 则创建
        if not os.path.exists("sessions"):
            os.mkdir("sessions")

        # 保存会话数据
        with open(f"sessions/{st.session_state.current_session}.json", "w", encoding="utf-8") as f:
            json.dump(session_data, f, ensure_ascii=False, indent=2)

1)存盘

        with open(f"sessions/{st.session_state.current_session}.json", "w", encoding="utf-8") as f:
            json.dump(session_data, f, ensure_ascii=False, indent=2)
  • open(..., "w", ...):以写入模式打开一个文件。
    • 文件名f"sessions/{st.session_state.current_session}.json"。这意味着文件会保存在 sessions 文件夹里,且文件名就是当前的会话 ID(例如 2024-04-11_21-00.json)。
    • encoding="utf-8":指定编码格式,这对支持中文至关重要。
  • json.dump(session_data, f, ...)
    • session_data:刚才打包好的字典数据。
    • f:刚才打开的文件对象。
    • ensure_ascii=False关键参数! 如果不加这个,中文字符会被转成 \u4e2d\u6587 这种乱码格式。设为 False 后,中文就能正常显示在文件里。
    • indent=2:格式化输出。它会让 JSON 文件里的内容自动换行并缩进 2 格,让人类阅读起来更舒服(否则所有数据会挤在一行)。

json.dump的核心作用是将 Python 数据直接保存为 JSON 格式的文件。简单来说,它的作用就是“把内存里的数据(字典、列表等)写入到硬盘上的文件中”,并且自动转换成标准的 JSON格式。它是 Python 中实现数据持久化(让数据在程序关闭后不丢失)最常用的方法之一。

(5)加载所有的会话列表信息

def load_sessions():
    session_list = []
    # 加载sessions目录下的文件
    if os.path.exists("sessions"):
        file_list = os.listdir("sessions")
        for filename in file_list:
            if filename.endswith(".json"):
                session_list.append(filename[:-5])
    return session_list

1)filename[:-5]清洗(切片操作)

  • 文件名通常是 会话名称.json
  • [:-5] 的意思是:去掉最后 5 个字符(即去掉 .json 这 5 个字符)。
Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐