前言
既然我们在之前的文章中实现了调用大模型获取答案的过程,接下来我们也将多个页面整合起来,最终实现一个总览的效果。因此,本文通过每个页面维护一个历史记录字典,则可以实现跨页面记忆。
在全局字典上建立局部字典
在streamlit
里面,全局字典就是st.session_state
。这个全局字典每个页面都可以灵活访问。也正因如此,局部字典的建立也就有了依托。
我们先建立一个页面:
1 2 3 4 5 6 7 8 9
| import streamlit as st st.session_state["dashscope"] = { "messages": [ { "role": "system", "content": "You are a helpful assistant." } ] }
|
看上去不错。但考虑到用户在这个页面上多次对话的时候,循环又循环地执行的时候,往往会重新给dashscope
这个字典赋值,导致每次对话都是第一次。我们可以再加一点鲁棒:
1 2 3 4 5 6 7 8 9
| if "dashscope" not in st.session_state: st.session_state["dashscope"] = {} if "messages" not in st.session_state["dashscope"]: st.session_state["dashscope"]["messages"] = [ { "role": "system", "content": "You are a helpful assistant." } ]
|
看上去更不错了。
多页面兼容
当然,光这样是不行的,直接复制这段代码到另外一个页面也是不行的。因为这样的话,其他页面将直接访问到上一个页面中的历史记录。
一打开页面:这TM给我干哪儿来了?
如果你爱收拾,代码文件都分类整理好,那就更好办了。通过文件夹的名称与页面文件的名称,可以决定一个页面的代码文件。毕竟,操作系统中就不允许有两个重名(带后缀)的文件。所以呢,我们借助一点Python
给我们留下来的魔法:__file__
。
就好比说,我在tongyi
文件加下建立了一个文件名叫test.py
,那么我们就可以借助Path
这样做:
1 2 3 4 5 6 7 8 9 10 11 12
| from pathlib import Path parent_path = Path(__file__).parent.name current_path = Path(__file__).stem if parent_path not in st.session_state: st.session_state[parent_path] = {} if current_path not in st.session_state[parent_path]: st.session_state[parent_path] = { current_path: [ "role": "system", "content": "you are a helpful assistant." ] }
|
P.S.:需要注意的是,如果你只使用Path(__file__).parent
,那么你获取到的并不是文件夹的名字,而是文件夹的绝对路径。
看上去完善了。
但是每个页面整这么大一段似乎也有点怪怪的。
但很可惜的是,streamlit
本身并没有什么自动注入机制。所以,我们能做的就是尽可能保证文件存放位置的规范性,然后用统一的代码调度:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| from pathlib import Path from typing import Optional def init_page_state( path: str | Path = __file__, default_welcome_message: Optional[str | None] = None ): p = Path(path) parent_path, current_path = ( p.parent.name, p.stem ) PAGE_KEY = (parent_path, current_path) if parent_path not in st.session_state: st.session_state[parent_path] = {} if current_path not in st.session_state[parent_path]: st.session_state[parent_path] = { current_path: [ "role": "system", "content": ( default_welcome_message or "you are a helpful assistant." ) ] } return PAGE_KEY
|
P.S.:这里返回PAGE_KEY
主要是为了之前定义的ChatRender
类用于前端的对话历史渲染。
看上去没问题。
页面应用
到这一步基本就完成了。每一页都可以写上两句话就可以了:
1 2
| from utils import init_page_state init_page_state(path = __file__)
|
或者说你为了表现出不一样的内容,可以这么做:
1 2 3 4 5
| from utils import init_page_state init_page_state( path = __file__, default_welcome_message = "你是一个,一个,一个,智能体啊啊啊啊啊啊啊啊啊啊啊啊" )
|
目前看来还没有更简单的方案。