实现与PDF进行聊天!(利用 Pinata、OpenAI 和 Streamlit等技术)

发布于:2024-10-18 ⋅ 阅读:(8) ⋅ 点赞:(0)

最近在GitHub上发现一个有趣的项目,由用户@ Jagroop2001开发的【chat-with-pdf】这个project!

我为此项目写了一个介绍和readme,感兴趣的可以点击链接:
https://github.com/Hyone-soul/chat-with-pdf/

在本教程中,我们将构建一个简单的聊天界面,允许用户上传PDF文件,使用OpenAI的API检索其内容,并在类似聊天的界面中显示响应。我们还将使用@pinata上传和存储PDF文件。

我们即将构建的项目预览:

前提条件:

  • 基本的Python知识
  • Pinata API密钥(用于上传PDF)
  • OpenAI API密钥(用于生成响应)
  • 安装了Streamlit(用于构建用户界面)

第1步:项目设置

首先创建一个新的Python项目目录:

mkdir chat-with-pdf
cd chat-with-pdf
python3 -m venv venv
source venv/bin/activate
pip install streamlit openai requests PyPDF2

接着,在项目的根目录创建一个.env文件,并添加以下环境变量:

PINATA_API_KEY=<你的Pinata API密钥>
PINATA_SECRET_API_KEY=<你的Pinata密钥>
OPENAI_API_KEY=<你的OpenAI API密钥>

你需要自己管理OPENAI_API_KEY,因为它是付费的。接下来,我们将讲解如何在Pinata中创建API密钥。

皮纳塔(Pinata)是什么?

Pinata是一个为IPFS(星际文件系统)提供文件存储和管理的平台,是一种去中心化的分布式文件存储系统。

  • 去中心化存储:Pinata帮助你在IPFS上存储文件,这是一个去中心化的网络。
  • 易于使用:它提供了用户友好的工具和API进行文件管理。
  • 文件可用性:Pinata通过将文件固定在IPFS上确保它们的可访问性。
  • NFT支持:非常适合存储NFT和Web3应用的元数据。
  • 经济实惠:相比传统云存储,Pinata可能是一种更具性价比的选择。

第2步:使用Pinata上传PDF

我们将使用Pinata的API来上传PDF文件,并获取每个文件的哈希值(CID)。创建一个名为pinata_helper.py的文件,用于处理PDF上传。

import os
import requests
from dotenv import load_dotenv

# 加载环境变量
load_dotenv()

# Pinata API URL,用于将文件固定到IPFS
PINATA_API_URL = "https://api.pinata.cloud/pinning/pinFileToIPFS"

# 从环境变量中获取Pinata API密钥
PINATA_API_KEY = os.getenv("PINATA_API_KEY")
PINATA_SECRET_API_KEY = os.getenv("PINATA_SECRET_API_KEY")

def upload_pdf_to_pinata(file_path):
    headers = {
        "pinata_api_key": PINATA_API_KEY,
        "pinata_secret_api_key": PINATA_SECRET_API_KEY
    }

    with open(file_path, 'rb') as file:
        response = requests.post(PINATA_API_URL, files={'file': file}, headers=headers)

        if response.status_code == 200:
            print("文件上传成功")
            return response.json()['IpfsHash']
        else:
            print(f"错误: {response.text}")
            return None

第3步:设置OpenAI

接下来,我们将创建一个函数,使用OpenAI的API与从PDF提取的文本进行交互。创建一个名为openai_helper.py的文件:

import os
from openai import OpenAI
from dotenv import load_dotenv

load_dotenv()

OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
client = OpenAI(api_key=OPENAI_API_KEY)

def get_openai_response(text, pdf_text):
    try:
        messages = [
            {"role": "system", "content": "你是一名帮助回答PDF问题的助手。"},
            {"role": "user", "content": pdf_text},
            {"role": "user", "content": text}
        ]

        response = client.chat.completions.create(
            model="gpt-4",
            messages=messages,
            max_tokens=100,
            temperature=0.7
        )

        return response.choices[0].message.content
    except Exception as e:
        return f"错误: {str(e)}"

第4步:构建Streamlit界面

现在,我们已经准备好辅助函数,接下来构建一个Streamlit应用,用于上传PDF文件、从OpenAI获取响应并显示聊天。

创建一个名为app.py的文件:

import streamlit as st
import os
import time
from pinata_helper import upload_pdf_to_pinata
from openai_helper import get_openai_response
from PyPDF2 import PdfReader
from dotenv import load_dotenv

# 加载环境变量
load_dotenv()

st.set_page_config(page_title="与PDF聊天", layout="centered")

st.title("使用OpenAI和Pinata与PDF聊天")

uploaded_file = st.file_uploader("上传你的PDF文件", type="pdf")

if "chat_history" not in st.session_state:
    st.session_state.chat_history = []
if "loading" not in st.session_state:
    st.session_state.loading = False

if uploaded_file is not None:
    file_path = os.path.join("temp", uploaded_file.name)
    with open(file_path, "wb") as f:
        f.write(uploaded_file.getbuffer())

    st.write("正在将PDF上传到Pinata...")
    pdf_cid = upload_pdf_to_pinata(file_path)

    if pdf_cid:
        st.write(f"文件已上传到IPFS,CID为: {pdf_cid}")

        reader = PdfReader(file_path)
        pdf_text = ""
        for page in reader.pages:
            pdf_text += page.extract_text()

        if pdf_text:
            st.text_area("PDF内容", pdf_text, height=200)

            user_input = st.text_input("向PDF提问:", disabled=st.session_state.loading)

            if st.button("发送", disabled=st.session_state.loading):
                if user_input:
                    st.session_state.loading = True

                    with st.spinner("AI思考中..."):
                        time.sleep(1)
                        response = get_openai_response(user_input, pdf_text)

                    st.session_state.chat_history.append({"user": user_input, "ai": response})

                    st.session_state.input_text = ""
                    st.session_state.loading = False

            if st.session_state.chat_history:
                for chat in st.session_state.chat_history:
                    st.write(f"**你:** {chat['user']}")
                    st.write(f"**AI:** {chat['ai']}")
        else:
            st.error("无法从PDF中提取文本。")
    else:
        st.error("PDF上传到Pinata失败。")

第5步:运行应用

使用以下命令在本地运行应用:

streamlit run app.py

第6步:代码解析

  • Pinata上传:用户上传PDF文件后,临时保存到本地,并通过upload_pdf_to_pinata函数上传到Pinata,Pinata返回一个表示文件在IPFS上的哈希值(CID)。
  • PDF提取:上传成功后,使用PyPDF2提取PDF内容并显示在文本区域。
  • OpenAI交互:用户可以通过输入框向PDF内容提问,get_openai_response函数将用户问题和PDF内容发送到OpenAI,并返回相关的响应。