| import gradio as gr |
| import urllib.request |
| import fitz |
| import re |
| from tqdm import tqdm |
| from openai import OpenAI |
| import faiss |
| import numpy as np |
| from sentence_transformers import SentenceTransformer |
|
|
| |
| |
| |
|
|
| |
| |
|
|
| |
| |
|
|
| 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 or end_page > total_pages: |
| end_page = total_pages |
|
|
| text_list = [] |
|
|
| for i in tqdm(range(start_page-1, end_page), desc="Extracting text from PDF"): |
| text = doc.load_page(i).get_text("text") |
| text = preprocess(text) |
| text_list.append(text) |
|
|
| doc.close() |
| return text_list |
|
|
| |
| |
| |
| |
| |
| |
| |
|
|
| def text_to_chunks(texts, word_length=150, start_page=1): |
| chunks = [] |
| buffer = [] |
|
|
| for idx, text in enumerate(texts): |
| words = text.split(' ') |
| for word in words: |
| buffer.append(word) |
| if len(buffer) >= word_length: |
| chunk = ' '.join(buffer).strip() |
| chunks.append(f'Page {idx+start_page}: "{chunk}"') |
| buffer = [] |
|
|
| |
| if len(buffer) >= word_length: |
| chunk = ' '.join(buffer).strip() |
| chunks.append(f'Page {idx+start_page}: "{chunk}"') |
| buffer = [] |
|
|
| return chunks |
|
|
| |
| |
|
|
| |
|
|
| model = SentenceTransformer('all-MiniLM-L6-v2') |
|
|
| |
| |
|
|
| |
| |
| |
|
|
|
|
| |
| |
| |
|
|
| def search(query, k=5): |
| query_embedding = model.encode([query])[0].astype(np.float32) |
| distances, indices = index.search(np.array([query_embedding]), k) |
| return [chunks[idx] for idx in indices[0]] |
|
|
|
|
| |
|
|
| client = OpenAI(api_key='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') |
|
|
|
|
| |
| |
| def generate_response_from_chunks(chunks, user_query, max_tokens=250): |
| |
| prompt = "search results:\n\n" |
| for i, chunk in enumerate(chunks, start=1): |
| prompt += f"{i}. {chunk}\n\n" |
|
|
| prompt += "Instructions: Compose a comprehensive reply to the query using the search results given. " \ |
| "Cite each reference using [number] notation (every result has a 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 query, simply state 'Found Nothing'. Don't write 'Answer:' " \ |
| "Directly start the answer.\n" |
|
|
| prompt += f"Query: {user_query}\n\n" |
|
|
| |
| response = client.chat.completions.create(model="gpt-4", |
| messages=[ |
| {"role": "system", "content": prompt}, |
| {"role": "user", "content": "Please provide a response based on the above instructions."} |
| ], |
| temperature=0.7, |
| max_tokens=max_tokens, |
| top_p=1.0, |
| frequency_penalty=0.0, |
| presence_penalty=0.0) |
|
|
| |
| return response.choices[0].message.content.strip() |
|
|
|
|
| |
|
|
| |
| |
|
|
|
|
| |
| |
| |
| def process_pdf(pdf_path, user_query): |
| texts = pdf_to_text(pdf_path, start_page=1) |
| chunks = text_to_chunks(texts, word_length=150) |
| relevant_chunks = search(user_query) |
| response = generate_response_from_chunks(relevant_chunks, user_query) |
| return response |
|
|
| title = 'BookGPT' |
| description = "BookGPT allows you to input an entire book and ask questions about its contents. This app uses GPT-3 to generate answers based on the book's information. BookGPT has ability to add reference to the specific page number from where the information was found. This adds credibility to the answers generated also helps you locate the relevant information in the book." |
|
|
| with gr.Blocks() as demo: |
|
|
| gr.Markdown(f'<center><h1>{title}</h1></center>') |
| gr.Markdown(description) |
| gr.Markdown("Thank you for all the support this space has received! Unfortunately, my OpenAI $18 grant has been exhausted, so you'll need to enter your own OpenAI API Key to use the app. Sorry for inconvenience :-(.") |
|
|
| with gr.Row(): |
| |
| with gr.Group(): |
|
|
| file = 'GANPaper.pdf' |
| question = gr.Textbox(label='question') |
| btn = gr.Button(value='Submit') |
|
|
| with gr.Group(): |
| answer = gr.Textbox(label='answer') |
|
|
| btn.click(process_pdf, inputs=[file, question], outputs=[answer]) |
|
|
| demo.launch() |