一文搞懂基于gradio的客服助手多用户隔离使用
·
最近在做智能客服的时候,编写的 chatbot 发现不同的人访问,上下文有点紊乱,最后发现是 gradio 默认不支持不同客户端对话的单独存储,于是整理了一下文章。
1. 利用 Gradio 的 Session State
import gradio as gr
def chatbot(input, history):
# 如果没有历史记录,则初始化为空列表
if history is None:
history = []
# 将当前输入添加到历史记录中
history.append(("User: " + input, "Bot: Response to " + input))
# 返回更新后的对话历史和状态
return history, history
# 创建 Gradio 界面
with gr.Blocks() as demo:
chat_history = gr.State([]) # 用于存储每个用户的对话历史
chatbot_output = gr.Chatbot() # 显示对话内容
user_input = gr.Textbox(label="输入你的问题")
# 用户提交输入时触发 chatbot 函数
user_input.submit(chatbot, inputs=[user_input, chat_history], outputs=[chatbot_output, chat_history])
demo.launch()
2. 为每个用户生成唯一的会话 ID
import gradio as gr
import uuid
# 存储所有用户的会话数据
session_data = {}
def get_session_id():
"""生成唯一会话 ID"""
return str(uuid.uuid4())
def chatbot(input, session_id):
# 如果是新用户,初始化会话数据
if session_id not in session_data:
session_data[session_id] = []
# 获取当前用户的会话历史
history = session_data[session_id]
# 更新会话历史
history.append(("User: " + input, "Bot: Response to " + input))
# 返回更新后的对话历史
return history
# 创建 Gradio 界面
with gr.Blocks() as demo:
session_id = gr.State(get_session_id()) # 为每个用户生成唯一会话 ID
chatbot_output = gr.Chatbot() # 显示对话内容
user_input = gr.Textbox(label="输入你的问题")
# 用户提交输入时触发 chatbot 函数
user_input.submit(chatbot, inputs=[user_input, session_id], outputs=[chatbot_output])
demo.launch()
3. 基于用户浏览器的 cook
import gradio as gr
import uuid
from http.cookies import SimpleCookie
# 存储所有用户的会话数据
session_data = {}
def get_or_create_session_id(cookies):
"""从 Cookie 中获取会话 ID,如果不存在则生成新的"""
cookie = SimpleCookie()
cookie.load(cookies)
if "session_id" in cookie:
session_id = cookie["session_id"].value
else:
session_id = str(uuid.uuid4()) # 生成唯一会话 ID
session_data[session_id] = [] # 初始化会话数据
return session_id
def chatbot(input, cookies):
# 获取或创建会话 ID
session_id = get_or_create_session_id(cookies)
# 获取当前用户的会话历史
history = session_data[session_id]
# 更新会话历史
history.append(("User: " + input, "Bot: Response to " + input))
# 返回更新后的对话历史和新的 Cookie
response_cookie = f"session_id={session_id}; Path=/; HttpOnly"
return history, response_cookie
# 创建 Gradio 界面
with gr.Blocks() as demo:
chatbot_output = gr.Chatbot() # 显示对话内容
user_input = gr.Textbox(label="输入你的问题")
cookies = gr.Textbox(label="Cookies", visible=False) # 隐藏的输入框,用于传递 Cookie
# 用户提交输入时触发 chatbot 函数
user_input.submit(chatbot, inputs=[user_input, cookies], outputs=[chatbot_output, cookies])
demo.launch()
在 Gradio 中,直接操作浏览器的 LocalStorage 或 IndexedDB 需要借助 JavaScript。Gradio 本身是一个 Python 框架,但可以通过 gr.HTML 或 gr.Javascript 组件嵌入自定义的 JavaScript 代码来实现对浏览器存储的操作。
4. 使用 LocalStorage 存储和读取数据
import gradio as gr
# 定义 JavaScript 代码
js_code = """
// 将数据保存到 LocalStorage
function saveToLocalStorage(key, value) {
localStorage.setItem(key, JSON.stringify(value));
}
// 从 LocalStorage 读取数据
function loadFromLocalStorage(key) {
const data = localStorage.getItem(key);
return data ? JSON.parse(data) : [];
}
"""
# 定义 Chatbot 的逻辑
def chatbot(input, history):
if history is None:
history = []
# 更新对话历史
history.append(("User: " + input, "Bot: Response to " + input))
return history, history
# 创建 Gradio 界面
with gr.Blocks() as demo:
# 嵌入 JavaScript 代码
gr.HTML(f"<script>{js_code}</script>")
# 定义组件
chatbot_output = gr.Chatbot()
user_input = gr.Textbox(label="输入你的问题")
history = gr.JSON(value=[], visible=False) # 用于传递历史记录
# 保存到 LocalStorage 的按钮
save_button = gr.Button("保存对话历史")
save_button.click(
None,
inputs=[history],
_js="(history) => saveToLocalStorage('chat_history', history)"
)
# 从 LocalStorage 加载对话历史的按钮
load_button = gr.Button("加载对话历史")
load_button.click(
None,
outputs=[history],
_js="() => loadFromLocalStorage('chat_history')"
)
# 用户提交输入时触发 chatbot 函数
user_input.submit(chatbot, inputs=[user_input, history], outputs=[chatbot_output, history])
demo.launch()
4.1. 代码解析
4.1.1. JavaScript 部分
saveToLocalStorage:将对话历史(JSON 格式)保存到浏览器的LocalStorage。loadFromLocalStorage:从LocalStorage中读取对话历史,并返回一个数组(如果不存在则返回空数组)。
4.1.2. Python 部分
gr.HTML:嵌入 JavaScript 代码,使浏览器能够执行saveToLocalStorage和loadFromLocalStorage函数。_js参数:Gradio 提供了_js参数,可以直接调用嵌入的 JavaScript 函数。
-
- 在
save_button.click中,通过_js调用saveToLocalStorage,将对话历史保存到LocalStorage。 - 在
load_button.click中,通过_js调用loadFromLocalStorage,从LocalStorage加载对话历史。
- 在
4.2. 流程说明
- 用户与 Chatbot 交互时,对话历史会实时更新并显示在界面上。
- 点击“保存对话历史”按钮时,当前的对话历史会被保存到浏览器的
LocalStorage。 - 点击“加载对话历史”按钮时,对话历史会从
LocalStorage加载并显示在界面上。
5. IndexedDB 示例(更复杂的数据存储)
IndexedDB 是一种更强大的客户端存储机制,适合存储大量结构化数据。
import gradio as gr
# 定义 JavaScript 代码
js_code = """
let db;
// 打开 IndexedDB 数据库
function openDatabase() {
return new Promise((resolve, reject) => {
const request = indexedDB.open("ChatHistoryDB", 1);
request.onerror = () => reject("数据库打开失败");
request.onsuccess = () => {
db = request.result;
resolve();
};
request.onupgradeneeded = (event) => {
const db = event.target.result;
if (!db.objectStoreNames.contains("history")) {
db.createObjectStore("history", { keyPath: "id" });
}
};
});
}
// 保存数据到 IndexedDB
function saveToIndexedDB(key, value) {
return new Promise((resolve, reject) => {
const transaction = db.transaction(["history"], "readwrite");
const store = transaction.objectStore("history");
const request = store.put({ id: key, data: value });
request.onsuccess = () => resolve();
request.onerror = () => reject("保存失败");
});
}
// 从 IndexedDB 读取数据
function loadFromIndexedDB(key) {
return new Promise((resolve, reject) => {
const transaction = db.transaction(["history"], "readonly");
const store = transaction.objectStore("history");
const request = store.get(key);
request.onsuccess = () => resolve(request.result ? request.result.data : []);
request.onerror = () => reject("读取失败");
});
}
"""
# 定义 Chatbot 的逻辑
def chatbot(input, history):
if history is None:
history = []
# 更新对话历史
history.append(("User: " + input, "Bot: Response to " + input))
return history, history
# 创建 Gradio 界面
with gr.Blocks() as demo:
# 嵌入 JavaScript 代码
gr.HTML(f"<script>{js_code}</script>")
# 定义组件
chatbot_output = gr.Chatbot()
user_input = gr.Textbox(label="输入你的问题")
history = gr.JSON(value=[], visible=False) # 用于传递历史记录
# 打开数据库
gr.HTML("<script>openDatabase();</script>")
# 保存到 IndexedDB 的按钮
save_button = gr.Button("保存对话历史")
save_button.click(
None,
inputs=[history],
_js="(history) => saveToIndexedDB('chat_history', history)"
)
# 从 IndexedDB 加载对话历史的按钮
load_button = gr.Button("加载对话历史")
load_button.click(
None,
outputs=[history],
_js="() => loadFromIndexedDB('chat_history')"
)
# 用户提交输入时触发 chatbot 函数
user_input.submit(chatbot, inputs=[user_input, history], outputs=[chatbot_output, history])
demo.launch()
6. 总结
LocalStorage:简单易用,适合存储小量数据(如对话历史)。IndexedDB:功能强大,适合存储大量结构化数据。- Gradio 结合 JavaScript:通过
_js参数调用自定义的 JavaScript 函数,可以轻松实现浏览器端的数据存储与读取。
无论是 LocalStorage 还是 IndexedDB,它们都提供了持久化存储的能力,确保用户在刷新页面或重新打开浏览器后仍能保留对话历史。
更多推荐



所有评论(0)