CoolFace
Apppublic

dawood/PDFChatGpt

sourceHugging Faceafl-3.0updated 3y agoView on Hugging Face
1likes
app.py205 linesDownload Raw Back to root
1import urllib.request2import fitz3import re4import numpy as np5import tensorflow_hub as hub6import openai7import gradio as gr8import os9from sklearn.neighbors import NearestNeighbors10 11def download_pdf(url, output_path):12    urllib.request.urlretrieve(url, output_path)13 14 15def preprocess(text):16    text = text.replace('\n', ' ')17    text = re.sub('\s+', ' ', text)18    return text19 20 21def pdf_to_text(path, start_page=1, end_page=None):22    doc = fitz.open(path)23    total_pages = doc.page_count24 25    if end_page is None:26        end_page = total_pages27 28    text_list = []29 30    for i in range(start_page-1, end_page):31        text = doc.load_page(i).get_text("text")32        text = preprocess(text)33        text_list.append(text)34 35    doc.close()36    return text_list37 38 39def text_to_chunks(texts, word_length=150, start_page=1):40    text_toks = [t.split(' ') for t in texts]41    page_nums = []42    chunks = []43    44    for idx, words in enumerate(text_toks):45        for i in range(0, len(words), word_length):46            chunk = words[i:i+word_length]47            if (i+word_length) > len(words) and (len(chunk) < word_length) and (48                len(text_toks) != (idx+1)):49                text_toks[idx+1] = chunk + text_toks[idx+1]50                continue51            chunk = ' '.join(chunk).strip()52            chunk = f'[{idx+start_page}]' + ' ' + '"' + chunk + '"'53            chunks.append(chunk)54    return chunks55 56 57class SemanticSearch:58    59    def __init__(self):60        self.use = hub.load('https://tfhub.dev/google/universal-sentence-encoder/4')61        self.fitted = False62    63    64    def fit(self, data, batch=1000, n_neighbors=5):65        self.data = data66        self.embeddings = self.get_text_embedding(data, batch=batch)67        n_neighbors = min(n_neighbors, len(self.embeddings))68        self.nn = NearestNeighbors(n_neighbors=n_neighbors)69        self.nn.fit(self.embeddings)70        self.fitted = True71    72    73    def __call__(self, text, return_data=True):74        inp_emb = self.use([text])75        neighbors = self.nn.kneighbors(inp_emb, return_distance=False)[0]76        77        if return_data:78            return [self.data[i] for i in neighbors]79        else:80            return neighbors81    82    83    def get_text_embedding(self, texts, batch=1000):84        embeddings = []85        for i in range(0, len(texts), batch):86            text_batch = texts[i:(i+batch)]87            emb_batch = self.use(text_batch)88            embeddings.append(emb_batch)89        embeddings = np.vstack(embeddings)90        return embeddings91 92 93 94def load_recommender(path, start_page=1):95    global recommender96    texts = pdf_to_text(path, start_page=start_page)97    chunks = text_to_chunks(texts, start_page=start_page)98    recommender.fit(chunks)99    return 'Corpus Loaded.'100 101 102def generate_text(openAI_key,prompt, engine="text-davinci-003"):103    openai.api_key = openAI_key104    completions = openai.Completion.create(105        engine=engine,106        prompt=prompt,107        max_tokens=512,108        n=1,109        stop=None,110        temperature=0.7,111    )112    message = completions.choices[0].text113    return message114 115 116def generate_answer(question,openAI_key):117    topn_chunks = recommender(question)118    prompt = ""119    prompt += 'search results:\n\n'120    for c in topn_chunks:121        prompt += c + '\n\n'122        123    prompt += "Instructions: Compose a comprehensive reply to the query using the search results given. "\124              "Cite each reference using [number] notation (every result has this number at the beginning). "\125              "Citation should be done at the end of each sentence. If the search results mention multiple subjects "\126              "with the same name, create separate answers for each. Only include information found in the results and "\127              "don't add any additional information. Make sure the answer is correct and don't output false content. "\128              "If the text does not relate to the query, simply state 'Found Nothing'. Ignore outlier "\129              "search results which has nothing to do with the question. Only answer what is asked. The "\130              "answer should be short and concise.\n\nQuery: {question}\nAnswer: "131    132    prompt += f"Query: {question}\nAnswer:"133    answer = generate_text(openAI_key, prompt,"text-davinci-003")134    return answer135 136 137def question_answer(url, question,openAI_key):138    if openAI_key.strip()=='':139        return '[ERROR]: Please enter you Open AI Key. Get your key here : https://platform.openai.com/account/api-keys'140    if url.strip() != '':141        glob_url = url142        download_pdf(glob_url, 'corpus.pdf')143        load_recommender('corpus.pdf')144 145    if question.strip() == '':146        return '[ERROR]: Question field is empty'147 148    return generate_answer(question,openAI_key)149 150 151recommender = SemanticSearch()152 153title = 'PDF GPT'154description = """ What is PDF GPT ?1551. The problem is that Open AI has a 4K token limit and cannot take an entire PDF file as input. Additionally, it sometimes returns irrelevant responses due to poor embeddings. ChatGPT cannot directly talk to external data. The solution is PDF GPT, which allows you to chat with an uploaded PDF file using GPT functionalities. The application breaks the document into smaller chunks and generates embeddings using a powerful Deep Averaging Network Encoder. A semantic search is performed on your query, and the top relevant chunks are used to generate a response.1562. The returned response can even cite the page number in square brackets([]) where the information is located, adding credibility to the responses and helping to locate pertinent information quickly. The Responses are much better than the naive responses by Open AI."""157 158with gr.Blocks() as demo:159 160    gr.Markdown(f'<center><h1>{title}</h1></center>')161    gr.Markdown(description)162 163    with gr.Row():164        165        with gr.Group():166            gr.Markdown(f'<p style="text-align:center">Get your Open AI API key <a href="https://platform.openai.com/account/api-keys">here</a></p>')167            openAI_key=gr.Textbox(label='Enter your OpenAI API key here')168            url = gr.Textbox(label='Enter PDF URL here')169            gr.Markdown("<center><h4>OR<h4></center>")170            question = gr.Textbox(label='Enter your question here')171            btn = gr.Button(value='Submit')172            btn.style(full_width=True)173 174        with gr.Group():175            answer = gr.Textbox(label='The answer to your question is :')176 177        btn.click(question_answer, inputs=[url, question,openAI_key], outputs=[answer], api_name="ask")178#openai.api_key = os.getenv('Your_Key_Here') 179demo.launch()180 181 182# import streamlit as st183 184# #Define the app layout185# st.markdown(f'<center><h1>{title}</h1></center>', unsafe_allow_html=True)186# st.markdown(description)187 188# col1, col2 = st.columns(2)189 190# # Define the inputs in the first column191# with col1:192#     url = st.text_input('URL')193#     st.markdown("<center><h6>or<h6></center>", unsafe_allow_html=True)194#     file = st.file_uploader('PDF', type='pdf')195#     question = st.text_input('question')196#     btn = st.button('Submit')197 198# # Define the output in the second column199# with col2:200#     answer = st.text_input('answer')201 202# # Define the button action203# if btn:204#     answer_value = question_answer(url, file, question)205#     answer.value = answer_value