chatbot / backend.py
smile11914's picture
Changed backend.py
8618ff0 verified
Raw
History Blame Contribute Delete
6.19 kB
import os
from prompt import rag_system_prompt,rag_history_prompt,chat_prompt
from langchain_community.chat_message_histories import ChatMessageHistory
import uuid
from langchain_huggingface import HuggingFaceEndpoint,ChatHuggingFace
import time
import json
from langchain_core.chat_history import (
BaseChatMessageHistory,
InMemoryChatMessageHistory,
)
from langchain_openai import ChatOpenAI
from langchain.chains.combine_documents import create_stuff_documents_chain
from langchain_core.runnables.history import RunnableWithMessageHistory
from langchain.chains import create_history_aware_retriever,create_retrieval_chain
from langchain_community.document_loaders import PyPDFLoader
from langchain_core.runnables.history import RunnableWithMessageHistory
from functools import wraps
from langchain_experimental.text_splitter import SemanticChunker
from dotenv import load_dotenv
from utils import create_retriever
from langchain_core.messages import HumanMessage
# from utils import indexing,retrieval,time_it
import os
from langchain_core.globals import set_debug,get_debug
#Setting up Enviroment Variables
api_key = os.getenv('OPENAI_API_KEY')
set_debug(False)
load_dotenv()
HUGGINGFACEHUB_API_TOKEN = os.getenv('HUGGINGFACEHUB_API_TOKEN')
"""
Todos:
-- Use multithreading to speed up the process
-- Add more comments
-- add the ability to work with more resources
-- how to handle chat history(if it just grows and grows)
-- slinding context window?
-- Streaming integration with langchain (this one is too slow and we shouldn't be doing this)
-- Improve prompt to only use context if needed
"""
class Chat:
"""
A class representing a chatbot.
Attributes:
- file_path (str): The path to the file containing the source data.
- model (str): The name or ID of the Hugging Face model to use for chat generation.
- embedding (str): The type of embedding to use for the chat model.
- chunking_method (str): The method used for semantic chunking.
Methods:
- __init__(self, file_path=None, model="mistralai/Mistral-7B-Instruct-v0.2", embedding="", chunking_method="semantic_chunking"): Initializes a Chat instance.
- add_source(self, file_path): Adds a source file for the chatbot to use.
- get_session_history(self, session_id): Retrieves the chat message history for a given session ID.
- run(self, query, username="Usman"): Runs the chatbot with the given query and username.
"""
def __init__(self,file_path=None,model="mistralai/Mistral-7B-Instruct-v0.2",embedding="",chunking_method="semantic_chunking"):
self.file_path = file_path
self.llm = HuggingFaceEndpoint(repo_id=model,temperature=0.5,huggingfacehub_api_token=HUGGINGFACEHUB_API_TOKEN,max_new_tokens=4096)
self.session_id = str(uuid.uuid4())
self.store = {}
self.file_uploaded = False
self.current_file = None
self.db = None
self.retriever = None
self.chunking_method = chunking_method
self.chat_model = ChatOpenAI(
model="mistralai/Mistral-7B-Instruct-v0.2",
base_url="https://api-inference.huggingface.co/v1",
api_key=os.environ.get('HUGGINGFACEHUB_API_TOKEN'),max_tokens=1000)
self.retriever_chain = None
self.chat_chain = None
# add the source file and create the relevent chains
def add_source(self,file_path):
print(f"Adding the following source: {file_path}")
self.file_uploaded = True
self.current_file = file_path
self.qa_chain = create_stuff_documents_chain(self.chat_model,rag_system_prompt)
data = create_retriever(file_path,self.chunking_method)
self.retriever = data['retriever']
self.db = data['vectordb']
self.history_retriever = create_history_aware_retriever(self.llm,self.retriever,rag_history_prompt)
self.source_chain = create_retrieval_chain(self.history_retriever,self.qa_chain)
# Used to retrieve the chat session history
def get_session_history(self,session_id):
if session_id not in self.store:
self.store[session_id] = InMemoryChatMessageHistory()
return self.store[session_id]
# Used to invoke the chain and generate response
def run(self,query,username="Usman"):
if self.file_uploaded == True:
# Goes in this block if the user has uploaded the file/source
print("RETURNED FROM FILE 1")
response = self.source_chain.invoke({"input":query,'username':username})
analysis = []
for data in response['context']:
data = {'metadata':[data.metadata],'page_content':[data.page_content]}
analysis.append(data)
with open("documents.json", "w") as file:
json.dump(analysis, file, indent=4)
print(f"response returned is {response['context']}")
return response['answer']
else:
#Change this so it only creates the chain if it hasnt created before
if self.chat_chain:
response = self.simple_chain.invoke({"input":query,'username':username},{'configurable':{"session_id":self.session_id}})
print(response)
return response.content
else:
self.chat_chain = chat_prompt | self.chat_model
self.simple_chain = RunnableWithMessageHistory(
self.chat_chain,
self.get_session_history,
history_messages_key="messages"
)
response = self.simple_chain.invoke({"input":query,'username':username},{'configurable':{"session_id":self.session_id}})
print(response)
return response.content
if __name__ == "__main__":
bot = Chat()
user_inp = input("User:")
while user_inp != "n":
start_time = time.time()
asd = bot.run(user_inp)
end_time = time.time()
response_time = end_time - start_time
print(asd)
print(f"(Response generated in {response_time:.2f} seconds)")
user_inp = input("User:")