Chainlit+LlamaIndex 实战4:大模型存储聊天记录功能(全程干货)+ postgreSQL安装(详解)
本文介绍了如何实现聊天记录持久化存储的方案。主要内容包括:1)安装PostgreSQL数据库并创建相关表结构来存储用户、聊天线程、消息步骤等数据;2)使用PostgreSQLDataLayer类实现数据持久化层,处理聊天数据的存储和检索;3)集成Minio文件存储服务器管理上传文件;4)通过Chainlit框架实现设置持久化和聊天历史恢复功能。该方案实现了完整的聊天记录保存机制,包括文本消息和文件

第四阶段主要是将各种聊天记录保存下来,包括文件,图片,文本。当然也不仅仅是放在一个数据库中
接下来我们给它做一个聊天记录,但是聊天记录放哪里呢?(其实是chainlit自带的)但是我们用pgadmin4来存储:详细的pgadmin4先教你安装:
pgadmin4安装:
打开官方文档:https://www.postgresql.org/download/windows/
点击这里进行下载,大家注意选择对应的需要版本,同时下载可以打开梯,这样下载速度会快很多。
然后逐步运行安装exe软件即可。
不要勾选这个选项
这样我们就安装完成了,接下来我们打开PostgreSQL
创建数据库:
创建数据脚本:
拷贝项目所需的SQL到脚本中并执行语句
CREATE TABLE users (
"id" UUID PRIMARY KEY,
"identifier" TEXT NOT NULL UNIQUE,
"metadata" JSONB NOT NULL,
"createdAt" TEXT
);
CREATE TABLE IF NOT EXISTS threads (
"id" UUID PRIMARY KEY,
"createdAt" TEXT,
"name" TEXT,
"userId" UUID,
"userIdentifier" TEXT,
"tags" TEXT[],
"metadata" JSONB,
FOREIGN KEY ("userId") REFERENCES users("id") ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS steps (
"id" UUID PRIMARY KEY,
"name" TEXT NOT NULL,
"type" TEXT NOT NULL,
"threadId" UUID NOT NULL,
"parentId" UUID,
"disableFeedback" BOOLEAN NOT NULL DEFAULT true,
"streaming" BOOLEAN NOT NULL,
"waitForAnswer" BOOLEAN,
"isError" BOOLEAN,
"metadata" JSONB,
"tags" TEXT[],
"input" TEXT,
"output" TEXT,
"createdAt" TEXT,
"start" TEXT,
"end" TEXT,
"generation" JSONB,
"showInput" TEXT,
"language" TEXT,
"indent" INT
);
CREATE TABLE IF NOT EXISTS elements (
"id" UUID PRIMARY KEY,
"threadId" UUID,
"type" TEXT,
"url" TEXT,
"chainlitKey" TEXT,
"name" TEXT NOT NULL,
"display" TEXT,
"objectKey" TEXT,
"size" TEXT,
"page" INT,
"language" TEXT,
"forId" UUID,
"mime" TEXT
);
CREATE TABLE IF NOT EXISTS feedbacks (
"id" UUID PRIMARY KEY,
"forId" UUID NOT NULL,
"threadId" UUID NOT NULL,
"value" INT NOT NULL,
"comment" TEXT
);
接下来我们使用Navicat Premium来连接它


接下来我们完成聊天记录保存到数据库
封装聊天数据缓存类及⽅法:persistent/postgresql_data_layer.py

postgresql_data_layer.py
这个Python文件 postgresql_data_layer.py 是一个用于Chainlit应用程序的数据持久化层实现,主要作用是将聊天数据存储到PostgreSQL数据库中。让我详细解释它的功能:
主要作用
- 数据持久化层实现
这个文件实现了 PostgreSQLDataLayer 类,它是Chainlit框架的 BaseDataLayer 的具体实现,用于将聊天应用的各种数据持久化存储到PostgreSQL数据库中。- 核心功能模块
数据库连接管理
使用SQLAlchemy创建异步数据库引擎
支持SSL连接配置
提供会话管理机制
数据操作功能
用户管理: 创建、获取、更新用户信息
线程管理: 创建、更新、删除、查询对话线程
步骤管理: 记录每个对话步骤的详细信息
反馈管理: 存储用户对AI回答的反馈
元素管理: 管理文件、图片等附件元素
辅助功能
SQL查询执行和结果处理
数据清理和格式化
UUID处理
错误处理和日志记录- 与存储客户端集成
该类与 MinioStorageClient 配合使用,将文件存储在Minio中,同时在数据库中保存文件的元数据和引用信息。- 特殊装饰器使用
使用了 @queue_until_user_message() 装饰器,确保某些操作(如创建元素)仅在收到用户消息后才执行,这有助于优化性能和确保数据一致性。- 数据结构映射
将Chainlit的数据结构(如 ThreadDict、StepDict、ElementDict 等)映射到数据库表结构,实现数据的持久化存储和检索。
总结
这个文件是整个聊天应用数据持久化的核心组件,负责将对话历史、用户信息、反馈数据等存储到PostgreSQL数据库中,确保应用重启后数据不会丢失,并支持后续的数据分析和检索功能。minio文件管理服务器:存储上传的文件


接下来我们创建.env文件用来放密钥

接下来我们要实现聊天记录功能
在chainlit在出现聊天记录需要两个硬性要求(要求登录)(文件持久化)
# 实现聊天数据与文件持久化
import chainlit.data as cl_data
# 创建一个Minio存储客户端实例,用于与Minio服务器进行通信
storage_client = MinioStorageClient()
# 初始化数据层实例,使用从环境变量中获取的连接字符串和之前创建的存储客户端
# 这里使用的是PostgreSQL数据层,它不仅负责数据的存储和检索,还通过存储客户端与Minio服务器交互,处理对象存储需求
cl_data._data_layer = PostgreSQLDataLayer(
conninfo=os.environ['PG_CONNECTION_STRING'], # 使用环境变量中的连接字符串创建PostgreSQL数据层实例
storage_provider=storage_client) # 将存储客户端实例存储到数据层实例中

这段代码可能有点麻烦,但是还好,注意理解,接下来是一个pnf文件预览
# 查看PDF文件
async def view_pdf(elements: List[ElementBased]):
"""
查看PDF文件
此函数接收一个元素列表,从中筛选出名称以.pdf结尾的元素,
并创建Pdf对象用于显示。它将这些PDF文件以消息的形式发送出来,
并在消息内容中包含PDF文件的名称。
参数:
- elements: List[ElementBased] -- 一个包含各种元素的列表,其中可能包括PDF文件
返回:
此函数没有返回值,但会发送包含PDF文件和它们名称的消息
"""
# 初始化两个空列表,分别用于存储Pdf对象和PDF文件名
files = []
contents = []
# 遍历元素列表,寻找名称以.pdf结尾的元素
for element in elements:
if element.name.endswith(".pdf"):
# 为每个找到的PDF文件创建Pdf对象,并添加到files列表中
pdf = cl.Pdf(name=element.name, display="side", path=element.path)
files.append(pdf)
# 将PDF文件名添加到contents列表中
contents.append(element.name)
# 如果没有找到任何PDF文件,则不执行任何操作直接返回
if len(files) == 0:
return
# 构造消息内容,包含所有PDF文件名,并将消息和PDF文件作为元素发送
await cl.Message(content=f"查看PDF文件:" + ",".join(contents), elements=files).send()

注意哟,你单单写个方法在这里可是没有用的(如果有文件,我们就通过这个方法预览)

使用 Chainlit 框架开发聊天应用时的两个核心回调函数(callback),用于实现 设置持久化 和 聊天历史恢复
@cl.on_settings_update
async def setup_settings(settings):
"""
当用户在前端更新设置时触发,将新设置保存到用户会话中。
"""
cl.user_session.set("settings", settings)
@cl.on_chat_resume
async def on_chat_resume(thread: ThreadDict):
"""
当用户恢复历史聊天会话时,重新构建聊天历史并恢复聊天引擎。
"""
# 创建一个新的聊天引擎实例
chat_engine = SimpleChatEngine.from_defaults()
# 遍历聊天历史中的每一步(step)
for step in thread.get("steps", []):
# 处理用户消息
if step["type"] == "user_message":
chat_engine.chat_history.append(
ChatMessage(content=step["output"], role="user")
)
# 处理助手消息
elif step["type"] == "assistant_message":
chat_engine.chat_history.append(
ChatMessage(content=step["output"], role="assistant")
)
# 将恢复好的聊天引擎存入用户会话,供后续交互使用
cl.user_session.set("chat_engine", chat_engine)
到这里我们的实战四到这里就结束了

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐














所有评论(0)