介紹
在今天繁忙的工作環境中,快速獲取資訊非常重要。面對這麼多文件,找到所需的資料可能會很困難。PDF問答機器人可以幫助你,特別是當它與Slack這個流行的團隊溝通工具一起使用時。這個機器人讓你可以詢問PDF文件的問題,並獲得即時答案,讓你更容易找到所需的資訊。
Langchain是一個強大的工具,用於建立能理解自然語言的應用程式。透過使用先進的模型,我們可以完成複雜的自然語言處理任務,如文本生成、問題回答和語言翻譯,從而開發出高度互動和智能的應用程式。
ChatGPT非常擅長理解和生成類似人類的文本,這使得它在摘要文本、翻譯語言和情感分析等任務中非常有用。對於我們的PDF問答機器人,ChatGPT將通過在PDF文件中查找相關資訊來回答問題。
通過將這個機器人與Slack整合,用戶可以輕鬆地在Slack頻道中詢問有關他們文件的問題並獲得即時答案,從而簡化工作流程。
在這篇文章中,我們將探索如何建立一個使用ChatGPT從PDF文件中提供答案的Slack機器人。
步驟1:創建一個Slack機器人
第一步是在Slack中設置一個機器人,請遵循我們的部落格文章《使用Python創建Slack機器人》的步驟1到23。
在繼續之前,請確保你遵循部落格的指示。
步驟2:設置接收來自Slack的消息
在設置Slack機器人後,我們需要修改腳本以接收來自Slack伺服器的消息。
請確保你已安裝所有所需的庫:
pip install flask
pip install slackeventsapi
pip install requests
首先,創建一個名為「app.py」的Python文件,並添加所有所需的庫:
import time
import slack
from flask import Flask
from slackeventsapi import SlackEventAdapter
import requests
from flask import Flask, request, jsonify
from slack.errors import SlackApiError
SLACK_TOKEN=””
SIGNING_SECRET=””
app = Flask(__name__)
slack_event_adapter = SlackEventAdapter(SIGNING_SECRET, ‘/slack/events’, app)
client = slack.WebClient(token=SLACK_TOKEN)
將你的Slack機器人令牌替換為<YOUR SLACK TOKEN>,將簽名密鑰替換為<YOUR SIGNING SECRET>。現在,我們需要創建一個路由來接收用戶發送的消息,並創建一個可以處理這些消息的函數。
def message(payload):
# 檢查進來的HTTP請求的資訊
response = request.environ
print(payload)
# 檢查HTTP請求計數
if “HTTP_X_SLACK_RETRY_NUM” not in response:
text=””
# 只有用戶發送的消息才會回應,不包括機器人
event, channel_id, user_id, sentence, file_name, bot_profile, file_url, file_id, block_id, file_size, file_type, subtype = slack_messege(payload)
if bot_profile == None:
# 當機器人加入頻道時的回應
if subtype == ‘channel_join’:
text=””
”’
在每一秒都很重要的世界裡, 不要浪費寶貴的時間在冗長的PDF中篩選。
嗨! 我是你的友好問答機器人,隨時準備幫助你解答有關PDF文件的問題。只需上傳你的PDF即可開始,讓我們一起深入細節!
迫不及待想要幫助你!
”’
# 機器人對用戶的回應
client.chat_postMessage(channel=channel_id,text=text)
# 你可以通過檢測用戶的回應來添加自定義消息
elif sentence == “hi” or sentence == ‘hello’:
text = “嗨!要開始,請提供PDF文件。讓我們開始對話!”
client.chat_postMessage(channel=channel_id,text=text)
if __name__ == “__main__”:
app.run(debug=True)
注意:根據Slack的斜線命令文檔,你需要在3000毫秒(3秒)內回應。如果你的命令花費的時間更長,則會出現超時錯誤,然後Slack伺服器會對相同的查詢發出另一個請求。
為了解決這個問題,請確保所有代碼都寫在「if “HTTP_X_SLACK_RETRY_NUM” not in response」條件內。這裡「response = request.environ」用於HTTP請求計數。
確保所有條件都放在「bot_profile == None」區塊內。否則,如果使用了「else」條件,機器人可能會對單個用戶請求無限回應。
在添加「slack_messege(payload)」函數之前,請不要運行此文件,否則會出現錯誤。
要從「payload」中提取數據,請添加「slack_messege(payload)」函數:
# 從payload中提取數據
file_name=””
bot_profile=””
file_url=””
file_id = ”
block_id = ”
text=””
file_size=””
file_type=””
subtype=””
event = payload.get(‘event’, {})
channel_id = event.get(‘channel’)
user_id = event.get(‘user’)
text = event.get(‘text’)
bot_profile = event.get(‘bot_profile’)
if “subtype” in event:
subtype = event.get(‘subtype’)
if ‘files’ in event:
files = event.get(‘files’,{})
file_name = files[0].get(‘name’)
file_url = files[0].get(‘url_private_download’)
file_id = files[0].get(‘id’)
file_size = files[0].get(‘size’)
file_type = files[0].get(‘mimetype’)
if ‘blocks’ in event:
blocks = event.get(‘blocks’,{})
block_id = blocks[0].get(“block_id”)
return event, channel_id, user_id, text, file_name,bot_profile, file_url, file_id, block_id, file_size, file_type, subtype
當PDF發送到機器人時,你可以檢查終端以查看JSON回應,如下圖所示:

我們需要獲取文件名稱和URL,這些在「slack_messege()」函數中已經提取。
為了檢測機器人何時接收到PDF文件,我們需要添加一個附加條件來檢查該文件。這個條件應該與處理用戶發送的歡迎消息的條件放在一起。
if file_type == “application/pdf”: # 檢查用戶提供的文件是否為PDF
if file_size > 10000000:
text = “請上傳一個小於10MB的文件。”
else:
text = “你的PDF已成功保存! 現在你可以問任何問題。讓我們開始吧!
“
# 下載PDF
download_pdf(file_url, file_name)
print(“\nuser_id\n”,user_id)
# 函數用於將PDF分塊並添加到chromadb中。
pdf_added_to_database(file_name,user_id)
else:
text = “抱歉,僅支持上傳PDF格式的文件。如果你有PDF文件,請隨時上傳,我將很高興進一步協助你。”
client.chat_postMessage(channel=channel_id,text=text)
else:
if sentence:
# 檢查用戶是否上傳了PDF
document_list=get_all_documents(user_id)
if len(document_list) == 0:
text = “請先上傳PDF,然後我才能幫助你解答問題。“
elif sentence:
# 向ChatGPT發出請求,詢問用戶的問題。
text = ask_question(sentence, user_id)
else:
text = “抱歉,似乎你嘗試上傳的媒體不受支持。請確保你正在嘗試上傳PDF文件,因為僅支持PDF格式的文檔上傳。”
client.chat_postMessage(channel=channel_id,text=text)
如果用戶輸入的任何文本不是「hi」,機器人將不會回應靜態消息,因為為每個可能的輸入提供特定回應是不切實際的。相反,當用戶提出問題時,輸入將由else條件處理,這將觸發「ask_question(sentence, user_id)」函數。
「ask_question(sentence, user_id)」函數向OpenAI發出請求,以從PDF中檢索答案。
這裡「get_all_documents(channel_id)」函數檢查ChromaDB向量數據庫,用戶是否上傳了他們的PDF,如果未上傳,則給他們回應,例如「請先上傳PDF」。別擔心,我們將在接下來的步驟中添加此功能。
我們使用了「pdf_added_to_database(file_name,user_id)」函數,該函數將PDF分塊並將這些分塊存儲在ChromaDB中,別擔心,我們將在接下來的步驟中添加此功能。
在對PDF進行分塊之前,我們需要下載PDF,為此我們使用了「download_pdf(file_url, file_name)」函數,請添加此函數以下載PDF文件。
headers = {
‘Authorization’: f’Bearer {SLACK_TOKEN}’
}
response = requests.get(file_url, headers=headers)
if response.status_code == 200:
# 將PDF保存到文件
with open(file_name, ‘wb’) as file:
file.write(response.content)
print(‘下載完成。’)
else:
print(f’下載文件失敗。狀態碼:{response.status_code}’)
步驟3:設置Langchain和OpenAI
為了設置Langchain和OpenAI,首先創建一個新的Python文件,名為「test_pdf_reader.py」
並遵循我們的《使用OpenAI和Langchain的RAG教程》部落格中的步驟1-7。
請確保你已安裝所有所需的庫:
pip install langchain_openai
pip install langchain_community
pip install pysqlite3
現在,我們需要修改主腳本,以自動化將PDF上傳到ChromaDB並進行問答的過程。
首先,添加所有代碼所需的庫:
from langchain_openai import OpenAIEmbeddings
from langchain_community.vectorstores import Chroma
from langchain_openai import ChatOpenAI
from langchain_community.document_loaders import PyPDFLoader
from langchain.chains.question_answering import load_qa_chain
import os
openai_key = ”
model_name = “gpt-4o”
將你的OpenAI密鑰替換為<YOUR-OPENAI-KEY>
我們使用了「gpt-4o」模型來進行嵌入和生成答案,但你也可以使用其他OpenAI模型,如「gpt-3.5-turbo」等。
要嵌入PDF文件,請添加此函數:
os.environ[‘OPENAI_API_KEY’] = openai_key
embeddings_model = OpenAIEmbeddings()
llm = ChatOpenAI(model_name = model_name, openai_api_key = openai_key, max_tokens = 400)
return embeddings_model, llm
對於問答,我們需要添加請求問題到ChatGPT並從PDF中生成答案的函數,因此添加「ask_question(question, chat_id)」函數,這在「app.py」中已經定義。
embeddings_model, llm = get_initialize()
vectordb = Chroma(persist_directory=str(chat_id), embedding_function = embeddings_model)
retriever = vectordb.as_retriever(search_kwargs = {“k” : 3})
chain = load_qa_chain(llm, chain_type=”stuff”)
context = retriever.get_relevant_documents(question)
answer = (chain({“input_documents”: context, “question”: f”你是一個問答機器人。用戶將上傳文件並詢問有關上傳文件的問題,你需要提供答案。如果用戶說謝謝,那麼請回謝謝用戶,並告訴他們在需要任何問題幫助時隨時聯繫我們。如果答案有不完整的句子,則從回應中刪除不完整的句子,並嘗試在前一句中涵蓋它。這是問題:{question}”}, return_only_outputs=True))[‘output_text’]
return answer
接下來,我們需要將PDF數據分塊並添加到ChromaDB中,為此添加此函數:
embeddings_model, llm = get_initialize()
loader = PyPDFLoader(pdf_name, extract_images=False)
pages = loader.load_and_split()
text_splitter = RecursiveCharacterTextSplitter(
chunk_size = 4000,
chunk_overlap = 20,
length_function = len,
add_start_index = True,
)
chunks = text_splitter.split_documents(pages)
__import__(‘pysqlite3’)
db = Chroma.from_documents(chunks, embedding = embeddings_model, persist_directory=str(chat_id))
db.persist()
return “你的PDF已上傳並保存!”
我們需要首先檢查ChromaDB以確保它是否為空,如果ChromaDB為空,則給出回應,請先上傳PDF。為此,我們需要添加此函數:
documents = []
documents_set = set()
db = Chroma(persist_directory=str(chat_id))
metadata = db.get()[“metadatas”]
for index,data in enumerate(metadata):
documents_set.add(data[“source”])
print(“documentset”,documents_set)
for doc in documents_set:
documents.append({
“type”: “button”,
“text”: {
“type”: “plain_text”,
“text”: doc
},
“style”: “primary”,
“action_id”: doc
},)
return documents
為了確保所有函數在運行「app.py」文件之前可用,請在「app.py」文件的開頭添加以下行,該行繼承了來自「test_pdf_reader」的所有所需函數。
在終端運行Ngrok:ngrok http 5000
步驟4:測試Slack機器人
在這篇文章中,我們使用了一篇PDF格式的研究論文來進行問答(Q&A)任務。該研究論文的標題為「Google Gemini作為下一代AI教育工具:新興教育技術的回顧」,可以通過以下鏈接訪問。你可以從那裡下載PDF。
https://slejournal.springeropen.com/articles/10.1186/s40561-024-00310-z
當我們添加PDF並根據其內容提出問題時,我們得到了這樣的結果:

結論:
創建一個用於Slack的PDF問答機器人,使用Langchain和OpenAI可以顯著提高資訊的可獲取性並改善團隊效率。這個機器人將使用戶能夠直接在Slack中查詢PDF文件,提供即時答案,節省寶貴的時間。
本文由 AI 台灣 運用 AI 技術編撰,內容僅供參考,請自行核實相關資訊。
歡迎加入我們的 AI TAIWAN 台灣人工智慧中心 FB 社團,
隨時掌握最新 AI 動態與實用資訊!