当前位置: 首页 > news >正文

构建个人大模型问答助手(基于Streamlit +gpt-4o/o1-mini):全面解析与实现

在当今人工智能迅猛发展的时代,构建一个个人化的大模型问答助手不仅能够提高工作效率,还能为日常生活带来便利。本篇博客将详细解析如何使用Python和Streamlit框架,结合OpenAI的API,搭建一个类似于ChatGPT的问答系统。我们将分步骤介绍代码实现,同时确保敏感信息的安全性。

基于ManyiAPI聚合接口站:https://api.manyi88.top, ManyiAPI注册链接(注册优惠) 可以直接调用国内外语言大模型,实现自己的问答助手,效果如图:

在这里插入图片描述

项目代码地址:
https://gitcode.com/sequoia00/appChat_streamlit/overview

目录

  1. 项目概述
  2. 环境准备
  3. 代码实现详解
    • 导入必要的库
    • API密钥与模型配置
    • 界面构建
    • 数据管理
    • 历史记录管理
    • 聊天功能实现
    • 辅助功能
  4. 安全性与隐私保护
  5. 总结
  6. 参考资料

项目概述

本项目旨在通过Python和Streamlit框架,结合OpenAI的API,构建一个个人化的问答助手。该助手允许用户选择不同的语言模型,与之进行对话,同时管理聊天历史记录,实现保存、加载、备份和删除功能。通过这一项目,用户可以体验到类似于ChatGPT的对话体验,并根据需求进行定制。

环境准备

在开始编码之前,确保你的开发环境中已经安装了以下软件和库:

  • Python 3.7+
  • Streamlit:用于构建Web应用的框架。
  • OpenAI Python SDK:用于与OpenAI的API进行交互。
  • 其他辅助库:如json, os, glob, re, shutil等。

可以使用以下命令安装必要的库:

pip install streamlit openai

代码实现详解

下面,我们将对整个代码进行逐段详细解析,帮助读者深入理解每一部分的功能与实现。

导入必要的库

from openai import OpenAI
import streamlit as st
import json
import os
import glob
import re
import shutil  # 用于文件移动

解析:

这些库为项目提供了必要的功能支持:

  • openai:与OpenAI API交互。
  • streamlit:构建用户界面。
  • json:处理JSON数据格式。
  • os, glob, re, shutil:文件和目录管理。

API密钥与模型配置

# 示例:模型和相应的 API 密钥
default_key = "sk-***"  # 默认令牌
sale_key = "sk-***"  # 自定义默认1.0
guan_key = "sk-***"  # 管转令牌3倍
az_key = "sk-***"  # 纯AZ,1.5倍
claude_key = "sk-***"  # claude 8倍
guan5_key = "sk-***"  # 管转令牌5倍model_keys = {"gpt-4o-mini-2024-07-18": az_key,  #1.5"o1-mini": guan5_key,    #3"gpt-4o-2024-08-06": az_key,"claude-3-5-sonnet-20240620": claude_key
}

解析:

  • API密钥管理:为不同的模型配置不同的API密钥,以实现对不同服务的调用和控制。
  • 模型选择:通过model_keys字典,将模型名称与对应的API密钥关联,方便用户在界面上选择。

安全建议:

将API密钥硬编码在代码中存在安全风险。建议使用环境变量或配置文件来存储这些密钥,并在代码中通过读取环境变量的方式获取,以避免泄露风险。

界面构建

为了方便调用模型,可以访问ManyiAPI聚合接口站:https://api.manyi88.top, ManyiAPI注册链接(注册优惠)

st.title("ChatGPT-like Clone")
selected_model = st.sidebar.selectbox("选择模型", list(model_keys.keys()))
api_key = model_keys[selected_model]
api_url = "https://api.manyi88.top/v1" #ManyiAPI聚合接口站:https://api.manyi88.topclient = OpenAI(api_key=api_key, base_url=api_url)

解析:

  • 标题设置:通过st.title函数设置应用的标题。
  • 模型选择:在侧边栏提供一个下拉菜单,用户可以选择不同的模型。
  • API客户端初始化:根据用户选择的模型,获取对应的API密钥和API URL,初始化OpenAI客户端。

数据管理

data_dir = "data"
backup_dir = "data_bak"
if not os.path.exists(data_dir):os.makedirs(data_dir)
if not os.path.exists(backup_dir):os.makedirs(backup_dir)

解析:

  • 数据目录data_dir用于存储聊天记录。
  • 备份目录backup_dir用于备份历史聊天记录。
  • 目录检查与创建:如果目录不存在,自动创建,确保文件操作的顺利进行。

会话ID管理

session_id_file = os.path.join(data_dir, "session_id.txt")def load_session_id():if os.path.exists(session_id_file):with open(session_id_file, "r") as f:return int(f.read().strip())return 0def save_session_id(session_id):with open(session_id_file, "w") as f:f.write(str(session_id))

解析:

  • 会话ID文件:用于存储当前会话的ID。
  • 加载会话ID:如果文件存在,读取当前的会话ID;否则,初始化为0。
  • 保存会话ID:在新会话开始时,将会话ID保存到文件中,确保会话的持续性和唯一性。

历史记录管理

加载历史记录
def load_history(file_path):match = re.search(r'chat_history_(\\d+)\\.json', os.path.basename(file_path))if match:st.session_state.session_id = int(match.group(1))with open(file_path, "r") as f:st.session_state.messages = json.load(f)

解析:

  • 文件名匹配:通过正则表达式提取会话ID。
  • 加载消息:从JSON文件中读取聊天记录,更新会话状态。
加载最新历史
def load_latest_history():history_files = sorted(glob.glob(os.path.join(data_dir, "*.json")), key=os.path.getmtime)if history_files:latest_file = history_files[-1]load_history(latest_file)

解析:

  • 获取所有历史文件:使用glob获取data_dir目录下所有JSON文件。
  • 排序与加载:按修改时间排序,加载最新的聊天记录。

聊天记录展示

def get_chat_title(messages):if messages:first_message = messages[0]["content"]title = first_message if first_message else "空的聊天"return title[:12]return "空的聊天"[:12]

解析:

  • 标题生成:根据聊天记录的第一条消息生成聊天标题,截取前12个字符。

历史文件展示与管理

def show_history_files(page=0, page_size=10):history_files = [(f, os.path.getmtime(f)) for f in glob.glob(os.path.join(data_dir, "*.json"))]history_files.sort(key=lambda x: x[1], reverse=True)total_files = len(history_files)total_pages = (total_files // page_size) + (1 if total_files % page_size > 0 else 0)start = page * page_sizeend = start + page_sizedisplay_files = history_files[start:end]with st.sidebar.expander("历史聊天记录"):for index, (file_path, _) in enumerate(display_files):with open(file_path, "r") as f:chat_history = json.load(f)file_name = get_chat_title(chat_history)col1, col2, col3 = st.sidebar.columns([4, 1, 1])  # 创建三列with col1:if st.button(file_name, key=f"load_{index}"):load_history(file_path)st.rerun()with col2:if st.button("📦", key=f"move_{index}", help="移动到备份文件夹"):move_history(file_path)st.success(f"{file_name} 已移动到备份。")st.rerun()with col3:if st.button("❌", key=f"delete_{index}", help="删除"):delete_history(file_path)st.success(f"{file_name} 已删除。")st.rerun()# 分页if page > 0:if st.button("上一页"):st.session_state.current_page -= 1st.rerun()if page < total_pages - 1:if st.button("下一页"):st.session_state.current_page += 1st.rerun()

解析:

  • 文件排序:按修改时间降序排列聊天记录文件。
  • 分页展示:每页显示10个文件,提供“上一页”和“下一页”按钮进行导航。
  • 文件操作
    • 加载:点击文件名按钮加载对应的聊天记录。
    • 移动:将文件移动到备份文件夹。
    • 删除:删除指定的聊天记录文件。

聊天界面与输入

for message in st.session_state.messages:with st.chat_message(message["role"]):st.markdown(message["content"])output_mode = st.sidebar.selectbox("选择输出模式", ["流式输出 (Stream)", "非流式输出 (Non-stream)"])

解析:

  • 消息展示:遍历st.session_state.messages,根据消息角色(用户或助手)展示对应内容。
  • 输出模式选择:用户可选择使用流式输出(即时显示)或非流式输出(一次性显示)的模式。

历史数量选择

# 初始化 session_state 中的历史数量
if "history_count" not in st.session_state:st.session_state.history_count = 0# 在侧边栏添加滑动条
if len(st.session_state.messages) == 0:max_history_count = 10
else:max_history_count = len(st.session_state.messages)st.sidebar.slider("选择使用的历史消息数量(共" + str(len(st.session_state.messages)) + "条)",min_value=0,max_value=max_history_count,value=st.session_state.history_count,  # 默认值key="history_count"  # 使用一个唯一的键来存储选择值
)# 显示当前选择的历史消息数量
st.sidebar.write(f"您选择的历史消息数量是: {st.session_state.history_count}")

解析:

  • 历史消息数量选择:通过滑动条让用户选择使用的历史消息数量,以影响生成新回复时的上下文范围。
  • 默认值与限制:如果当前无消息,最大历史数量设为10;否则,最大值为现有消息数量。

聊天输入与响应

prompt = st.chat_input("What is up?")
if prompt:st.session_state.messages.append({"role": "user", "content": prompt})with st.chat_message("user"):st.markdown(prompt)with st.chat_message("assistant"):client.api_key = model_keys[selected_model]stream = output_mode == "流式输出 (Stream)"try:if st.session_state.history_count > 0:messages_to_send = ([{"role": m["role"], "content": m["content"]}for m in st.session_state.messages[-st.session_state.history_count:]])else:messages_to_send = [{"role": "user", "content": prompt}]res = client.chat.completions.create(model=selected_model,messages=messages_to_send,stream=stream,)if stream:assistant_message = st.write_stream(res)if assistant_message:st.session_state.messages.append({"role": "assistant", "content": assistant_message})else:st.warning("收到空响应。")else:       if len(res.choices) > 0:assistant_message = res.choices[0].message.contentif assistant_message:st.markdown(assistant_message)st.session_state.messages.append({"role": "assistant", "content": assistant_message})else:st.warning("收到空响应。")else:st.warning("响应格式不正确,未找到有效消息。")save_history()except Exception as e:st.error(f"发生错误:{e}")

解析:

  1. 用户输入

    • 获取用户通过st.chat_input输入的文本。
    • 将用户消息添加到st.session_state.messages中,并在界面上展示。
  2. 助手响应

    • 根据用户选择的输出模式,设置是否采用流式输出。
    • 构建发送给API的消息列表:
      • 如果选择使用历史消息,则提取最新的history_count条消息。
      • 否则,仅发送当前的用户输入。
    • 调用OpenAI API生成回应:
      • 流式输出:逐步显示助手的回复。
      • 非流式输出:一次性显示完整的回复。
    • 将助手的回复添加到st.session_state.messages中,并保存聊天记录。
  3. 错误处理

    • 捕获并显示在请求过程中发生的任何异常,确保用户能够及时了解问题。

辅助功能实现

新建聊天会话
st.sidebar.header("操作")
if st.sidebar.button("New Chat"):st.session_state.messages = []  # 清空当前会话st.session_state.session_id = load_session_id()st.session_state.session_id += 1save_session_id(st.session_state.session_id)st.success("当前会话已清空。")

解析:

  • 按钮功能:点击“New Chat”按钮,清空当前的聊天记录,并生成一个新的会话ID。
  • 状态更新:更新st.session_state.messagesst.session_state.session_id,并提示用户会话已重置。
历史对话展示
st.sidebar.header("历史对话")
show_history_files(st.session_state.current_page)

解析:

  • 展示历史对话:调用之前定义的show_history_files函数,在侧边栏展示历史聊天记录,并提供相应的管理操作(加载、移动、删除)。

安全性与隐私保护

在构建和部署个人问答助手时,安全性和隐私保护至关重要。以下是一些关键点:

  1. API密钥管理

    • 避免硬编码:API密钥不应直接写在代码中,尤其是在版本控制系统中。
    • 使用环境变量:推荐将密钥存储在环境变量中,通过代码读取,增强安全性。
      import os
      api_key = os.getenv("OPENAI_API_KEY")
      
    • 配置文件:另一个选择是使用配置文件,将敏感信息存储在外部配置文件中,并在.gitignore中排除该文件。
  2. 数据存储

    • 加密:敏感的聊天记录应进行加密存储,防止未经授权的访问。
    • 访问控制:确保只有授权用户能够访问和操作聊天记录。
  3. 错误处理

    • 详细信息:在生产环境中,不应向用户展示过于详细的错误信息,以防泄露系统内部信息。
    • 日志记录:将错误信息记录在安全的日志系统中,便于后续分析。
  4. 用户隐私

    • 数据最小化:仅收集和存储必要的用户数据,避免冗余信息的存储。
    • 用户同意:在收集和使用用户数据前,需获得用户明确的同意,并提供隐私政策说明。

总结

本文详细介绍了如何使用Python和Streamlit框架,结合OpenAI的API,构建一个个人化的大模型问答助手。从环境准备、代码结构解析到具体实现步骤,我们逐步解析了每一部分的功能与实现细节。同时,强调了在开发过程中需注意的安全性与隐私保护措施,确保项目的稳健和可靠性。

通过这一项目,读者不仅可以学习到如何搭建一个高效的问答系统,还能深入理解如何管理API密钥、处理数据存储以及实现用户界面交互。希望本篇博客能为您的AI项目提供有价值的参考和指导。

参考资料

  • ManyiAPI注册链接(注册优惠)
  • Streamlit 官方文档
  • OpenAI API 文档
  • Python 官方文档

注意事项

感谢您的阅读和支持。在代码实施过程中,请务必确保API密钥和其他敏感信息的安全,避免意外泄露。如发现密钥泄露,请立即撤销并生成新的密钥,以保障您的账户安全。


http://www.mrgr.cn/news/79240.html

相关文章:

  • mysql密码配置
  • Linux系统的内核、根文件系统、Bootloader之间的关系是怎么样的?并附根文件系统的详细解释。
  • 3.反转链表
  • 【C#】int? , C# 中的可空类型(Nullable Types)
  • C++的一些经典算法
  • HTA8998 实时音频跟踪的高效内置升压2x10W免电感立体声ABID类音频功放
  • 小程序 —— Day1
  • 青岛鼎信Java开发面试题及参考答案(3万字长文,多张原理图)
  • 全能单行url解码器
  • ainiworth 在分布式目标的方程中 与正常互易性可以形成的方程不同 多引入了协方差元素未知 但可解,因为此时只有一个串扰参数且已经解出来了
  • vue3 vite ts day1
  • C#—交错数组
  • 12.05排错日志
  • CTFshowPHP特性
  • STL算法之merge sort
  • 【Python教程】Python基础篇之历史
  • 决策树:ID3、C4.5和CART特征选择方式
  • EasyExcel注解使用
  • 安装 Zookeeper 和 Kafka
  • 【LLMs】用LM Studio本地部署离线大语言模型
  • Python酷库之旅-第三方库Pandas(259)
  • 什么是IndexedDB?有什么特点
  • 【代码随想录day49】【C++复健】 99. 岛屿数量dfs;99. 岛屿数量bfs; 100. 岛屿的最大面积
  • 青岛鼎信Java开发面试题及参考答案
  • 思科模拟器路由器的基本配置
  • 【Pip】配置和优化 `pip` 安装源:提升 Python 包管理体验的全面指南