from langchain.llms import HuggingFacePipeline, CTransformers
import langchain
from ingest import load_db
from langchain.cache import InMemoryCache
from langchain.schema import prompt
from langchain.chains import RetrievalQA
from langchain.callbacks import StdOutCallbackHandler
from langchain import PromptTemplate
import chainlit as cl
DB_FAISS_PATH = 'vectorstoredb/db_faiss'


langchain.llm_cache = InMemoryCache()

PROMPT_TEMPLATE = '''
Use the following pieces of information to answer the user's question.
If you don't know the answer, just say that you don't know, don't try to make up an answer.

Context: {context}
Question: {question}
Do provide only helpful answers

Helpful answer:
'''
handler = StdOutCallbackHandler()
def set_custom_prompt():
    input_variables = ['context', 'question']
    prompt = PromptTemplate(template=PROMPT_TEMPLATE, input_variables=input_variables)
    return prompt

def load_retriever():
    return load_db()

def load_llm():
    llm = CTransformers(model="models/mistral-7b-instruct-v0.1.Q2_K.gguf", config={'max_new_tokens': 128, 'temperature': 0.01})
    return llm

def retrieval_qa_chain(llm, prompt, db):
    qa_chain = RetrievalQA.from_chain_type(
    llm=llm,
    chain_type="stuff",
    retriever = db,
    verbose=True,
    callbacks=[handler],
    chain_type_kwargs={"prompt": prompt},
    return_source_documents=True
    )  
    return qa_chain

def qa_bot():
    db = load_retriever()
    llm = load_llm()
    qa_prompt = set_custom_prompt()
    qa = retrieval_qa_chain(llm, qa_prompt, db)
    return qa

def final_result(query):
    qa_result = qa_bot()
    response = qa_result({"query": query})
    return response

@cl.on_chat_start
async def start():
    chain = qa_bot()
    msg = cl.Message(content="Starting the bot...")
    await msg.send()
    msg.content = "Hi, Welcome to Medical Bot. What is your query?"
    await msg.update()

    cl.user_session.set("chain", chain)

@cl.on_message
async def main(message: cl.Message):
    chain = cl.user_session.get("chain") 
    cb = cl.AsyncLangchainCallbackHandler(
        stream_final_answer=True, answer_prefix_tokens=["FINAL", "ANSWER"]
    )
    cb.answer_reached = True
    res = await chain.acall(message.content, callbacks=[cb])
    answer = res["result"]
    sources = res["source_documents"]

    if sources:
        answer += f"\nSources:" + str(sources)
    else:
        answer += "\nNo sources found"

    await cl.Message(content=answer).send()




langchain.chains.RetrievalQA.from_chain_type langchain.llms.CTransformers langchain.callbacks.StdOutCallbackHandler langchain.cache.InMemoryCache langchain.PromptTemplate
[((403, 418), 'langchain.cache.InMemoryCache', 'InMemoryCache', ([], {}), '()\n', (416, 418), False, 'from langchain.cache import InMemoryCache\n'), ((709, 732), 'langchain.callbacks.StdOutCallbackHandler', 'StdOutCallbackHandler', ([], {}), '()\n', (730, 732), False, 'from langchain.callbacks import StdOutCallbackHandler\n'), ((817, 890), 'langchain.PromptTemplate', 'PromptTemplate', ([], {'template': 'PROMPT_TEMPLATE', 'input_variables': 'input_variables'}), '(template=PROMPT_TEMPLATE, input_variables=input_variables)\n', (831, 890), False, 'from langchain import PromptTemplate\n'), ((943, 952), 'ingest.load_db', 'load_db', ([], {}), '()\n', (950, 952), False, 'from ingest import load_db\n'), ((980, 1102), 'langchain.llms.CTransformers', 'CTransformers', ([], {'model': '"""models/mistral-7b-instruct-v0.1.Q2_K.gguf"""', 'config': "{'max_new_tokens': 128, 'temperature': 0.01}"}), "(model='models/mistral-7b-instruct-v0.1.Q2_K.gguf', config={\n    'max_new_tokens': 128, 'temperature': 0.01})\n", (993, 1102), False, 'from langchain.llms import HuggingFacePipeline, CTransformers\n'), ((1170, 1351), 'langchain.chains.RetrievalQA.from_chain_type', 'RetrievalQA.from_chain_type', ([], {'llm': 'llm', 'chain_type': '"""stuff"""', 'retriever': 'db', 'verbose': '(True)', 'callbacks': '[handler]', 'chain_type_kwargs': "{'prompt': prompt}", 'return_source_documents': '(True)'}), "(llm=llm, chain_type='stuff', retriever=db,\n    verbose=True, callbacks=[handler], chain_type_kwargs={'prompt': prompt},\n    return_source_documents=True)\n", (1197, 1351), False, 'from langchain.chains import RetrievalQA\n'), ((1745, 1786), 'chainlit.Message', 'cl.Message', ([], {'content': '"""Starting the bot..."""'}), "(content='Starting the bot...')\n", (1755, 1786), True, 'import chainlit as cl\n'), ((1904, 1939), 'chainlit.user_session.set', 'cl.user_session.set', (['"""chain"""', 'chain'], {}), "('chain', chain)\n", (1923, 1939), True, 'import chainlit as cl\n'), ((2005, 2033), 'chainlit.user_session.get', 'cl.user_session.get', (['"""chain"""'], {}), "('chain')\n", (2024, 2033), True, 'import chainlit as cl\n'), ((2044, 2148), 'chainlit.AsyncLangchainCallbackHandler', 'cl.AsyncLangchainCallbackHandler', ([], {'stream_final_answer': '(True)', 'answer_prefix_tokens': "['FINAL', 'ANSWER']"}), "(stream_final_answer=True,\n    answer_prefix_tokens=['FINAL', 'ANSWER'])\n", (2076, 2148), True, 'import chainlit as cl\n'), ((2438, 2464), 'chainlit.Message', 'cl.Message', ([], {'content': 'answer'}), '(content=answer)\n', (2448, 2464), True, 'import chainlit as cl\n')]