File size: 5,705 Bytes
969d108
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# Imports
from langchain.document_loaders import PyPDFLoader
import os
from langchain.chains import RetrievalQA, ConversationalRetrievalChain
from langchain.indexes import VectorstoreIndexCreator
from langchain.text_splitter import CharacterTextSplitter, TokenTextSplitter
from langchain.embeddings import OpenAIEmbeddings, HuggingFaceEmbeddings
from langchain.vectorstores import Chroma
from langchain import HuggingFacePipeline
from langchain.chat_models import ChatOpenAI
from dotenv import load_dotenv
from langchain.memory import ConversationBufferMemory, ConversationTokenBufferMemory
import gradio as gr

# Funcion de carga de la api key
def process_key(api_key):
    os.environ['OPENAI_API_KEY'] = api_key

def load_pdf(file):
    name_file = file.name
    print(file.name)
    loader = PyPDFLoader(file.name)
    documents = loader.load()
    print(documents)
    # Creo el objeto que permite dividir el texto en chunks
    text_splitter = CharacterTextSplitter(chunk_size=1024, chunk_overlap=64)
    # Esto lo que hace es dividir el texto en chunks de 2048 caracteres con un overlap de 128 caracteres
    texts = text_splitter.split_documents(documents)
    # Genero el objeto que crea los embeddings
    # Nota: Estos embeddings son gratuitos a diferencia de los de OpenAI
    embeddings = HuggingFaceEmbeddings()
    # Defino el modelo de lenguaje
    llm = ChatOpenAI(model='gpt-3.5-turbo', temperature=0.0, max_tokens=1000)
    # Creo la base de datos de vectores
    global vectorstore
    vectorstore = Chroma.from_documents(texts, embeddings)
    # Defino la memoria
    
    global memory
    # La definicion de Memoria no es trivial, es bastante compleja de hecho se deben especificar bien todos los parameteros para que no de error
    memory = ConversationTokenBufferMemory(llm=llm, 
                                           memory_key="chat_history", 
                                           input_key='question', 
                                           output_key='answer', 
                                           max_token_limit=1000,
                                           return_messages=False)
    # Defino la cadena de qa
    global qa
    qa = ConversationalRetrievalChain.from_llm(llm, 
                                        vectorstore.as_retriever(search_kwargs={'k': 3}), # Este parametro especifica cuantos chunks se van a recuperar
                                        return_source_documents=True,
                                        verbose=True,
                                        chain_type='stuff',
                                        memory=memory,
                                        max_tokens_limit=2500,
                                        get_chat_history=lambda h: h)
    return 'Done'

# Funcion que ejecuta LLM y responde la pregunta
def answer_question(question):
    result = qa(inputs={'question': question})
    pages = [x.metadata['page'] for i, x in enumerate(result['source_documents'])]
    return result['answer'], pages

# Funcion que pega las respuestas anteriores en el objeto Chat bot
def bot(history):
    res = qa(
        {
            'question': history[-1][0],
            'chat_history': history[:-1]
        }
    )
    history[-1][1] = res['answer']
    return history

# Agrego el texto a la historia del chat
def add_text(history, text):
    history = history + [(text, None)]
    return history, ""

# Analizar como parsea las ecuaciones
with gr.Blocks() as demo:
    with gr.Tab(label='Load PDF'):
        with gr.Row():
            with gr.Column():
                open_ai_key = gr.Textbox(label='Ingresa tu api key de Open AI', type='password')
        with gr.Row():
            with gr.Column(scale=0.4):
                api_key_button = gr.Button('Enviar', variant='primary')
        with gr.Row():
            pdf_file = gr.File(label='PDF file')
            # Esta linea esta para probar si el calculo se realiza
            emb = gr.Textbox(label='Calculo de Embeddings, por favor espere...')
        # send_pdf = gr.Button(label='Load PDF').style(full_width=False)
        with gr.Row():
            with gr.Column(scale=0.50):
                send_pdf = gr.Button(label='Load PDF')
                send_pdf.click(load_pdf, pdf_file, emb)
    with gr.Tab(label='Galicia QA Demo'):
        chatbot = gr.Chatbot([], 
                             elem_id="chatbot",
                             label='Document GPT').style(height=500)
        with gr.Row():
            with gr.Column(scale=0.80):
                txt = gr.Textbox(
                    show_label=False,
                    placeholder="Enter text and press enter",
                ).style(container=False)

            with gr.Column(scale=0.10):
                submit_btn = gr.Button(
                    'Submit',
                    variant='primary'
                )
                
            with gr.Column(scale=0.10):
                clear_btn = gr.Button(
                    'Clear',
                    variant='stop'
                )
        # Tanto el submit (hacer enter en el campo de texto) como el submit_btn hacen la misma accion
        txt.submit(fn=add_text, inputs=[chatbot, txt], outputs=[chatbot, txt] # Cuando envio el submit hago esta funcion
                   ).then(fn=bot, inputs=chatbot, outputs=chatbot) # Luego hago esta otra funcion

        submit_btn.click(fn=add_text, inputs=[chatbot, txt], outputs=[chatbot, txt]
                         ).then(fn=bot, inputs=chatbot, outputs=chatbot)
        
        clear_btn.click(lambda: None, None, chatbot, queue=False)

        api_key_button.click(fn=process_key, inputs=[open_ai_key], outputs=None)

demo.launch(inline=False)