### Start Langchain-Serve API Server Source: https://context7.com/bhaskatripathi/pdfgpt/llms.txt Deploys the API locally, listening on port 8080 by default. This command starts the service that handles PDF querying. ```bash # Start the API server lc-serve deploy local api # Server running at http://localhost:8080 ``` -------------------------------- ### Docker Compose for pdfGPT Services Source: https://context7.com/bhaskatripathi/pdfgpt/llms.txt This section provides Docker Compose commands to manage the pdfGPT services. Use `docker-compose up --build` to start both the API backend and Gradio frontend. Individual services can be started or stopped using specific service names. ```bash # Build and start both services docker-compose -f docker-compose.yaml up --build # Services: # langchain-serve → http://localhost:8080 (REST API) # pdf-gpt → http://localhost:7860 (Gradio UI) # Run only the API backend docker-compose up langchain-serve # Run only the Gradio frontend (requires API to be running) docker-compose up pdf-gpt # Stop all services docker-compose down ``` -------------------------------- ### Query PDF from URL via API Source: https://context7.com/bhaskatripathi/pdfgpt/llms.txt Sends a POST request to the `/ask_url` endpoint to get an answer about a PDF located at a given URL. Requires the URL and question, with optional environment variables like API keys. ```bash # Query a publicly accessible PDF by URL curl -X POST "http://localhost:8080/ask_url" \ -H "Content-Type: application/json" \ -d '{ "url": "https://arxiv.org/pdf/1706.03762.pdf", "question": "What attention mechanism is proposed?", "envs": { "OPENAI_API_KEY": "sk-..." } }' # Expected response: # { # "result": "The paper proposes the Scaled Dot-Product Attention mechanism [Page 3]. # Multi-Head Attention is built on top of this by running attention in parallel [Page 4]." # } ``` -------------------------------- ### Query Uploaded PDF File via API Source: https://context7.com/bhaskatripathi/pdfgpt/llms.txt Sends a POST request to the `/ask_file` endpoint to get an answer about a local PDF file. Accepts a multipart file upload and JSON-encoded input data containing the question and API key. ```bash # Upload a local PDF and ask a question curl -X POST "http://localhost:8080/ask_file" \ --form "file=@/path/to/your/document.pdf" \ --get \ --data-urlencode 'input_data={"question": "What are the key findings?", "envs": {"OPENAI_API_KEY": "sk-..."}}' # Expected response: # { # "result": "The key findings include a 15% improvement in accuracy [Page 7] # and a reduction in inference time by 30% [Page 8]." # } ``` -------------------------------- ### Simulate Gradio Button Click with API Call Source: https://context7.com/bhaskatripathi/pdfgpt/llms.txt This function simulates the backend API call triggered by a Gradio button click. It handles validation for URL or file input and makes a POST request to the specified API host. Ensure the API host starts with 'http' and only one input source (URL or file) is provided. ```python def ask_api(lcserve_host, url, file, question, openAI_key): if not lcserve_host.startswith('http'): return '[ERROR]: Invalid API Host' if url.strip() == '' and file is None: return '[ERROR]: Both URL and PDF is empty. Provide at least one.' if url.strip() != '' and file is not None: return '[ERROR]: Both URL and PDF is provided. Please provide only one.' if question.strip() == '': return '[ERROR]: Question field is empty' _data = {'question': question, 'envs': {'OPENAI_API_KEY': openAI_key}} if url.strip() != '': r = requests.post(f'{lcserve_host}/ask_url', json={'url': url, **_data}) else: with open(file.name, 'rb') as f: r = requests.post( f'{lcserve_host}/ask_file', params={'input_data': json.dumps(_data)}, files={'file': f}, ) if r.status_code != 200: raise ValueError(f'[ERROR]: {r.text}') return r.json()['result'] ``` ```python result = ask_api( lcserve_host="http://localhost:8080", url="https://arxiv.org/pdf/1706.03762.pdf", file=None, question="What is the model architecture?", openAI_key="sk-..." ) print(result) ``` -------------------------------- ### Extract Text from PDF Pages Source: https://context7.com/bhaskatripathi/pdfgpt/llms.txt Extracts plain text from a specified page range of a PDF file using PyMuPDF. Preprocesses text by collapsing whitespace. Ensure PyMuPDF is installed (`pip install pymupdf`). ```python import fitz import re def preprocess(text): text = text.replace('\n', ' ') text = re.sub('\s+', ' ', text) return text def pdf_to_text(path, start_page=1, end_page=None): doc = fitz.open(path) total_pages = doc.page_count if end_page is None: end_page = total_pages text_list = [] for i in range(start_page - 1, end_page): text = doc.load_page(i).get_text("text") text = preprocess(text) text_list.append(text) doc.close() return text_list # Usage pages = pdf_to_text("research_paper.pdf", start_page=1, end_page=10) print(f"Extracted {len(pages)} pages") # Output: Extracted 10 pages print(pages[0][:200]) # Output: "Abstract This paper presents a novel approach to ..." ``` -------------------------------- ### load_recommender: Initialize global SemanticSearch instance for PDF Source: https://context7.com/bhaskatripathi/pdfgpt/llms.txt Manages a module-level singleton `recommender`. If not yet instantiated, creates a new `SemanticSearch`. Converts the PDF to text, chunks it, and fits the KNN index. Re-calling with a different PDF replaces the index. ```python recommender = None # module-level singleton def load_recommender(path, start_page=1): global recommender if recommender is None: recommender = SemanticSearch() texts = pdf_to_text(path, start_page=start_page) chunks = text_to_chunks(texts, start_page=start_page) recommender.fit(chunks) return 'Corpus Loaded.' # Usage status = load_recommender("annual_report.pdf", start_page=1) print(status) # Output: Corpus Loaded. ``` -------------------------------- ### POST /ask_url Source: https://context7.com/bhaskatripathi/pdfgpt/llms.txt Answer a question about a PDF retrieved from a URL. This endpoint downloads a PDF from a given URL, loads it into the recommender, and returns a cited answer. ```APIDOC ## `POST /ask_url` — Answer a question about a PDF retrieved from a URL ### Description Downloads a PDF from a given URL to `corpus.pdf`, loads it into the recommender, and returns a cited answer. Deployed via `lc-serve deploy local api` and listens on port `8080` by default. ### Method POST ### Endpoint `/ask_url` ### Request Body - **url** (string) - Required - The URL of the PDF document. - **question** (string) - Required - The question to ask about the PDF. - **envs** (object) - Optional - Environment variables, including `OPENAI_API_KEY`. - **OPENAI_API_KEY** (string) - Required - The OpenAI API key. ### Request Example ```bash curl -X POST "http://localhost:8080/ask_url" \ -H "Content-Type: application/json" \ -d '{ "url": "https://arxiv.org/pdf/1706.03762.pdf", "question": "What attention mechanism is proposed?", "envs": { "OPENAI_API_KEY": "sk-..." } }' ``` ### Response #### Success Response (200) - **result** (string) - The cited answer to the question. #### Response Example ```json { "result": "The paper proposes the Scaled Dot-Product Attention mechanism [Page 3]. Multi-Head Attention is built on top of this by running attention in parallel [Page 4]." } ``` ``` -------------------------------- ### generate_text: Send prompt to OpenAI-compatible model via LiteLLM Source: https://context7.com/bhaskatripathi/pdfgpt/llms.txt Wraps LiteLLM's `completion()` to send a chat-style prompt to supported models. Returns the model's reply as a string. On API errors, returns an error message string prefixed with `API Error:`. ```python from litellm import completion def generate_text(openAI_key, prompt, engine="text-davinci-003"): try: messages = [{"content": prompt, "role": "user"}] completions = completion( model=engine, messages=messages, max_tokens=512, n=1, stop=None, temperature=0.7, api_key=openAI_key, ) message = completions['choices'][0]['message']['content'] except Exception as e: message = f'API Error: {str(e)}' return message # Usage answer = generate_text( openAI_key="sk-...", prompt="What is the capital of France?\nAnswer:", engine="gpt-3.5-turbo" ) print(answer) # Output: "The capital of France is Paris." ``` -------------------------------- ### generate_answer Source: https://context7.com/bhaskatripathi/pdfgpt/llms.txt Orchestrates the full RAG pipeline: queries the fitted recommender for the top-5 relevant chunks, assembles them into a structured prompt with citation instructions, and calls generate_text. ```APIDOC ## `generate_answer` — Retrieve top chunks and generate a cited answer ### Description Orchestrates the full RAG pipeline: queries the fitted `recommender` for the top-5 relevant chunks, assembles them into a structured prompt with citation instructions, and calls `generate_text`. The instruction set directs the model to cite page numbers in `[Page Number]` notation after each sentence, avoid fabrication, and respond concisely step-by-step. ### Parameters - **question** (string) - The user's question about the PDF. - **openAI_key** (string) - The OpenAI API key for text generation. ### Returns - (string) - A cited answer to the question. ### Example ```python # Usage — assumes load_recommender() was already called load_recommender("machine_learning_paper.pdf") answer = generate_answer( question="What optimizer was used during training?", openAI_key="sk-..." ) print(answer) # Output: "The authors used the Adam optimizer with a learning rate of 0.001 [Page 5]. # A warmup schedule of 4000 steps was applied [Page 5]." ``` ``` -------------------------------- ### Generate Cited Answer from PDF Chunks Source: https://context7.com/bhaskatripathi/pdfgpt/llms.txt Orchestrates the RAG pipeline by retrieving relevant chunks and generating a cited answer. Ensure `recommender` is loaded before use. ```python def generate_answer(question, openAI_key): topn_chunks = recommender(question) prompt = 'search results:\n\n' for c in topn_chunks: prompt += c + '\n\n' prompt += ( "Instructions: Compose a comprehensive reply to the query using the search results given. " "Cite each reference using [ Page Number] notation (every result has this number at the beginning). " "Citation should be done at the end of each sentence. If the search results mention multiple subjects " "with the same name, create separate answers for each. Only include information found in the results and " "don't add any additional information. Make sure the answer is correct and don't output false content. " "If the text does not relate to the PDF, simply state 'Text Not Found in PDF'. Ignore outlier " "search results which has nothing to do with the question. Only answer what is asked. The " "answer should be short and concise. Answer step-by-step. \n\nQuery: {question}\nAnswer: " ) prompt += f"Query: {question}\nAnswer:" return generate_text(openAI_key, prompt, "text-davinci-003") # Usage — assumes load_recommender() was already called load_recommender("machine_learning_paper.pdf") answer = generate_answer( question="What optimizer was used during training?", openAI_key="sk-..." ) print(answer) # Output: "The authors used the Adam optimizer with a learning rate of 0.001 [Page 5]. # A warmup schedule of 4000 steps was applied [Page 5]." ``` -------------------------------- ### POST /ask_file Source: https://context7.com/bhaskatripathi/pdfgpt/llms.txt Answer a question about an uploaded PDF file. Accepts a multipart file upload and a JSON-encoded input_data parameter containing the question and OpenAI API key. ```APIDOC ## `POST /ask_file` — Answer a question about an uploaded PDF file ### Description Accepts a multipart file upload alongside a JSON-encoded `input_data` query parameter containing the question and OpenAI API key. The file is saved to a named temporary file, loaded into the recommender, and answered with page citations. ### Method POST ### Endpoint `/ask_file` ### Parameters #### Form Data - **file** (file) - Required - The PDF file to upload. #### Query Parameters - **input_data** (string) - Required - JSON-encoded string containing: - **question** (string) - Required - The question to ask about the PDF. - **envs** (object) - Optional - Environment variables, including `OPENAI_API_KEY`. - **OPENAI_API_KEY** (string) - Required - The OpenAI API key. ### Request Example ```bash # Upload a local PDF and ask a question curl -X POST "http://localhost:8080/ask_file" \ --form "file=@/path/to/your/document.pdf" \ --get \ --data-urlencode 'input_data={"question": "What are the key findings?", "envs": { "OPENAI_API_KEY": "sk-..." }}' ``` ### Response #### Success Response (200) - **result** (string) - The cited answer to the question. #### Response Example ```json { "result": "The key findings include a 15% improvement in accuracy [Page 7] and a reduction in inference time by 30% [Page 8]." } ``` ``` -------------------------------- ### Split Text into Word Chunks with Citations Source: https://context7.com/bhaskatripathi/pdfgpt/llms.txt Splits preprocessed text into fixed-size word chunks, preserving page number citations. Handles merging short trailing chunks into the next page's tokens. Useful for preparing text for LLM context windows. ```python def text_to_chunks(texts, word_length=150, start_page=1): text_toks = [t.split(' ') for t in texts] chunks = [] for idx, words in enumerate(text_toks): for i in range(0, len(words), word_length): chunk = words[i: i + word_length] if ( (i + word_length) > len(words) and (len(chunk) < word_length) and (len(text_toks) != (idx + 1)) ): text_toks[idx + 1] = chunk + text_toks[idx + 1] continue chunk = ' '.join(chunk).strip() chunk = f'[Page no. {idx + start_page}]' + ' ' + '"' + chunk + '"' chunks.append(chunk) return chunks # Usage texts = pdf_to_text("research_paper.pdf") chunks = text_to_chunks(texts, word_length=150, start_page=1) print(f"Total chunks: {len(chunks)}") # Output: Total chunks: 47 print(chunks[0]) # Output: '[Page no. 1] "Abstract This paper presents a novel approach ..."' ``` -------------------------------- ### SemanticSearch: Fit KNN index on embeddings and query Source: https://context7.com/bhaskatripathi/pdfgpt/llms.txt Wraps Universal Sentence Encoder and NearestNeighbors for semantic search. Call the instance with a query string to find semantically similar chunks. No external vector database is required. ```python import tensorflow_hub as hub import numpy as np from sklearn.neighbors import NearestNeighbors class SemanticSearch: def __init__(self): self.use = hub.load('https://tfhub.dev/google/universal-sentence-encoder/4') self.fitted = False def fit(self, data, batch=1000, n_neighbors=5): self.data = data self.embeddings = self.get_text_embedding(data, batch=batch) n_neighbors = min(n_neighbors, len(self.embeddings)) self.nn = NearestNeighbors(n_neighbors=n_neighbors) self.nn.fit(self.embeddings) self.fitted = True def __call__(self, text, return_data=True): inp_emb = self.use([text]) neighbors = self.nn.kneighbors(inp_emb, return_distance=False)[0] if return_data: return [self.data[i] for i in neighbors] else: return neighbors def get_text_embedding(self, texts, batch=1000): embeddings = [] for i in range(0, len(texts), batch): text_batch = texts[i: (i + batch)] emb_batch = self.use(text_batch) embeddings.append(emb_batch) embeddings = np.vstack(embeddings) return embeddings # Usage searcher = SemanticSearch() chunks = text_to_chunks(pdf_to_text("paper.pdf")) searcher.fit(chunks, n_neighbors=5) results = searcher("What methodology was used?") for r in results: print(r) # Output: # '[Page no. 3] "... we employed a mixed-methods approach combining ..."' # '[Page no. 4] "... the methodology section describes three phases ..."' # ... ``` -------------------------------- ### Proxy API Calls from Gradio Frontend Source: https://context7.com/bhaskatripathi/pdfgpt/llms.txt Python function used by the Gradio UI to validate inputs and route requests to the backend API (`/ask_url` or `/ask_file`). Returns the answer or an error message. ```python import requests import json ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.