NIApp / app.py
LayMui's picture
Create app.py
ccd3265 verified
# Add this import
import tempfile
from dotenv import load_dotenv
import os
from docling.document_converter import DocumentConverter
from langchain_community.document_loaders import TextLoader
from langchain.text_splitter import CharacterTextSplitter
from langchain.vectorstores import FAISS
from langchain.embeddings import HuggingFaceEmbeddings
from langchain_openai import ChatOpenAI
from langchain_community.chat_models import ChatAnthropic
from langchain.chains import RetrievalQA
import gradio as gr
import tempfile
llm = None
qa_chain = None
vectorstore = None
retriever = None
def process_pdf(file_path):
global vectorstore, retriever, qa_chain
# Parse PDF with Docling
converter = DocumentConverter()
result = converter.convert(file_path)
markdown_content = result.document.export_to_markdown()
# Save markdown temporarily
with tempfile.NamedTemporaryFile(delete=False, suffix=".md", mode="w", encoding="utf-8") as tmp_md:
tmp_md.write(markdown_content)
tmp_md_path = tmp_md.name
# Load and split documents
loader = TextLoader(tmp_md_path)
documents = loader.load()
splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=200)
docs = splitter.split_documents(documents)
embeddings = HuggingFaceEmbeddings(model_name="BAAI/bge-small-en-v1.5")
vectorstore = FAISS.from_documents(docs, embeddings)
retriever = vectorstore.as_retriever()
# Rebuild QA chain with current LLM
if llm is not None:
qa_chain = RetrievalQA.from_chain_type(llm=llm, chain_type="stuff", retriever=retriever)
def setup_chain(api_key, provider):
global llm, qa_chain
if provider.lower() == "anthropic":
os.environ["ANTHROPIC_API_KEY"] = api_key
llm = ChatAnthropic(model_name="claude-3-sonnet-20240229")
elif provider.lower() == "openai":
os.environ["OPENAI_API_KEY"] = api_key
llm = ChatOpenAI(model_name="gpt-4o")
else:
return "Unsupported provider. Please select 'openai' or 'anthropic'."
# If vectorstore and retriever are already set (PDF uploaded), rebuild qa_chain
global vectorstore, retriever
if retriever is not None:
qa_chain = RetrievalQA.from_chain_type(llm=llm, chain_type="stuff", retriever=retriever)
return "API key and provider set successfully. You can now upload a PDF and ask questions."
def answer_question(user_input):
if qa_chain is None:
return "Please upload a PDF and set your API key and provider first."
if user_input.strip() == "":
return "Please enter a question."
response = qa_chain.run(user_input)
return response
import gradio as gr
with gr.Blocks() as iface:
gr.Markdown("# PDF Chat App with Docling and LangChain\nAsk questions directly from your PDF document.")
with gr.Row():
api_key_input = gr.Textbox(label="API Key", type="password", placeholder="Enter your API Key")
provider_input = gr.Dropdown(choices=["openai", "anthropic"], label="Provider", value="openai")
set_api_button = gr.Button("Set API Key and Provider")
api_status = gr.Textbox(label="Status", interactive=False)
pdf_uploader = gr.File(label="Upload PDF", file_types=[".pdf"])
question_input = gr.Textbox(lines=2, placeholder="Ask a question about the PDF...")
ask_button = gr.Button("Ask")
answer_output = gr.Textbox(label="Answer", interactive=False)
set_api_button.click(fn=setup_chain, inputs=[api_key_input, provider_input], outputs=api_status)
pdf_uploader.change(fn=process_pdf, inputs=pdf_uploader, outputs=api_status)
ask_button.click(fn=answer_question, inputs=question_input, outputs=answer_output)
iface.launch(share=True)