# 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)