I’m building a PDF chat system using langchain and need help with maintaining conversation history. My current setup has two main endpoints - one for uploading PDFs and another for processing questions. The upload part works fine where I extract text from PDFs and store it in a FAISS vector database. However, I’m struggling with the question processing part. I want the system to remember previous questions and answers so users can ask follow-up questions like “what was my previous question” or reference earlier parts of the conversation.
from flask import Flask, request, jsonify
from werkzeug.utils import secure_filename
import fitz # PyMuPDF
from langchain_openai import OpenAIEmbeddings
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_community.vectorstores import Chroma
from langchain.chains import ConversationalRetrievalChain
from langchain_openai import ChatOpenAI
from langchain.memory import ConversationBufferMemory
import os
app = Flask(__name__)
app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024 # 16MB max file size
def create_chat_chain(vectordb):
chat_memory = ConversationBufferMemory(
memory_key="chat_history",
return_messages=True,
output_key='answer'
)
llm_model = ChatOpenAI(temperature=0.3)
retriever_config = vectordb.as_retriever(
search_type="mmr",
search_kwargs={"k": 3, "fetch_k": 6}
)
chat_chain = ConversationalRetrievalChain.from_llm(
llm=llm_model,
retriever=retriever_config,
memory=chat_memory,
return_source_documents=True
)
return chat_chain
@app.route('/document_upload', methods=['POST'])
def document_upload():
global doc_vectorstore
doc_vectorstore = None
if 'document' not in request.files:
return jsonify({'error': 'No file uploaded'}), 400
uploaded_file = request.files['document']
try:
# Extract text using PyMuPDF
pdf_document = fitz.open(stream=uploaded_file.read(), filetype="pdf")
extracted_content = ""
for page_num in range(pdf_document.page_count):
current_page = pdf_document[page_num]
extracted_content += current_page.get_text()
# Split content into manageable pieces
content_splitter = RecursiveCharacterTextSplitter(
chunk_size=800,
chunk_overlap=150,
separators=["\n\n", "\n", " ", ""]
)
text_chunks = content_splitter.split_text(extracted_content)
# Create vector database
embedding_model = OpenAIEmbeddings()
doc_vectorstore = Chroma.from_texts(
texts=text_chunks,
embedding=embedding_model
)
return jsonify({'status': 'Document processed successfully'})
except Exception as error:
return jsonify({'error': str(error)}), 500
@app.route('/ask_question', methods=['POST'])
def ask_question():
global doc_vectorstore
try:
user_query = request.json.get('query')
conversation_handler = create_chat_chain(doc_vectorstore)
answer_response = conversation_handler({'question': user_query})
final_answer = answer_response['answer']
return jsonify({'answer': final_answer})
except Exception as error:
return jsonify({'error': str(error)}), 500
I’m particularly confused about how to properly set up the conversation memory so it maintains context between different API calls. Any guidance would be appreciated.