pdfchat / app.py
kamau1's picture
Update app.py
93a997b verified
raw
history blame
7.64 kB
"""
creator: Lewis Kamau Kimaru
Function: chat with pdf documents in different languages
"""
from langchain.text_splitter import CharacterTextSplitter
from langchain.embeddings import HuggingFaceBgeEmbeddings
from langchain.vectorstores import FAISS
from langchain.chat_models import ChatOpenAI
from langchain.memory import ConversationBufferMemory
from langchain.chains import ConversationalRetrievalChain
from langchain.llms import HuggingFaceHub
from typing import Union
from dotenv import load_dotenv
from PyPDF2 import PdfReader
import streamlit as st
import requests
import json
import os
# Authentication
import streamlit_authenticator as stauth
import yaml
from yaml.loader import SafeLoader
with open('config.yaml') as file:
config = yaml.load(file, Loader=SafeLoader)
authenticator = stauth.Authenticate(
config['credentials'],
config['cookie']['name'],
config['cookie']['key'],
config['cookie']['expiry_days'],
config['preauthorized']
)
name, authentication_status, username = authenticator.login('Login', 'main')
if authentication_status:
authenticator.logout('Logout', 'main', key='unique_key')
st.write(f'Welcome *{name}*')
st.title('Some content')
elif authentication_status is False:
st.error('Username/password is incorrect')
elif authentication_status is None:
st.warning('Please enter your username and password')
if authentication_status:
try:
if authenticator.reset_password(username, 'Reset password'):
st.success('Password modified successfully')
except Exception as e:
st.error(e)
try:
if authenticator.register_user('Register user', preauthorization=False):
st.success('User registered successfully')
except Exception as e:
st.error(e)
try:
username_forgot_pw, email_forgot_password, random_password = authenticator.forgot_password('Forgot password')
if username_forgot_pw:
st.success('New password sent securely')
# Random password to be transferred to the user securely
else:
st.error('Username not found')
except Exception as e:
st.error(e)
try:
username_forgot_username, email_forgot_username = authenticator.forgot_username('Forgot username')
if username_forgot_username:
st.success('Username sent securely')
# Username to be transferred to the user securely
else:
st.error('Email not found')
except Exception as e:
st.error(e)
if authentication_status:
try:
if authenticator.update_user_details(username, 'Update user details'):
st.success('Entries updated successfully')
except Exception as e:
st.error(e)
with open('config.yaml', 'w') as file:
yaml.dump(config, file, default_flow_style=False)
# set this key as an environment variable
os.environ["HUGGINGFACEHUB_API_TOKEN"] = st.secrets['huggingface_token']
# Page configuration
st.set_page_config(page_title="SemaNaPDF", page_icon="📚",)
# Sema Translator
Public_Url = 'https://lewiskimaru-helloworld.hf.space' #endpoint
def translate(userinput, target_lang, source_lang=None):
if source_lang:
url = f"{Public_Url}/translate_enter/"
data = {
"userinput": userinput,
"source_lang": source_lang,
"target_lang": target_lang,
}
response = requests.post(url, json=data)
result = response.json()
print(type(result))
source_lange = source_lang
translation = result['translated_text']
else:
url = f"{Public_Url}/translate_detect/"
data = {
"userinput": userinput,
"target_lang": target_lang,
}
response = requests.post(url, json=data)
result = response.json()
source_lange = result['source_language']
translation = result['translated_text']
return source_lange, translation
def get_pdf_text(pdf : Union[str, bytes, bytearray]) -> str:
reader = PdfReader(pdf)
pdf_text = ''
for page in (reader.pages):
text = page.extract_text()
if text:
pdf_text += text
return text
def get_text_chunks(text:str) ->list:
text_splitter = CharacterTextSplitter(
separator="\n", chunk_size=1500, chunk_overlap=300, length_function=len
)
chunks = text_splitter.split_text(text)
return chunks
def get_vectorstore(text_chunks : list) -> FAISS:
model = "sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2"
encode_kwargs = {
"normalize_embeddings": True
} # set True to compute cosine similarity
embeddings = HuggingFaceBgeEmbeddings(
model_name=model, encode_kwargs=encode_kwargs, model_kwargs={"device": "cpu"}
)
vectorstore = FAISS.from_texts(texts=text_chunks, embedding=embeddings)
return vectorstore
def get_conversation_chain(vectorstore:FAISS) -> ConversationalRetrievalChain:
llm = HuggingFaceHub(
repo_id="mistralai/Mixtral-8x7B-Instruct-v0.1",
#repo_id="TheBloke/Mixtral-8x7B-Instruct-v0.1-GGUF"
model_kwargs={"temperature": 0.5, "max_length": 1048},
)
memory = ConversationBufferMemory(memory_key="chat_history", return_messages=True)
conversation_chain = ConversationalRetrievalChain.from_llm(
llm=llm, retriever=vectorstore.as_retriever(), memory=memory
)
return conversation_chain
st.markdown ("""
<style> div.stSpinner > div {
text-align:center;
text-align:center;
align-items: center;
justify-content: center;
}
</style>""", unsafe_allow_html=True)
def main():
st.title("SemaNaPDF📚")
# upload file
pdf = st.file_uploader("Upload a PDF Document", type="pdf")
if pdf is not None:
with st.spinner(""):
# get pdf text
raw_text = get_pdf_text(pdf)
# get the text chunks
text_chunks = get_text_chunks(raw_text)
# create vector store
vectorstore = get_vectorstore(text_chunks)
# create conversation chain
st.session_state.conversation = get_conversation_chain(vectorstore)
st.info("done")
#user_question = st.text_input("chat with your pdf ...")
# show user input
if "messages" not in st.session_state:
st.session_state.messages = []
for message in st.session_state.messages:
with st.chat_message(message["role"]):
st.markdown(message["content"])
if user_question := st.chat_input("Ask your document anything ......?"):
with st.chat_message("user"):
st.markdown(user_question)
user_langd, Queryd = translate(user_question, 'eng_Latn')
st.session_state.messages.append({"role": "user", "content": user_question})
response = st.session_state.conversation({"question": Queryd}) #Queryd
st.session_state.chat_history = response["chat_history"]
output = translate(response['answer'], user_langd, 'eng_Latn')[1] # translated response
with st.chat_message("assistant"):
#st.markdown(response['answer'])
st.markdown(output)
st.session_state.messages.append({"role": "assistant", "content": response['answer']})
# Signature
st.markdown(
"""
<div style="position: fixed; bottom: 0; right: 0; padding: 10px;">
<a href="https://kamaukimaru.vercel.app" target="_blank" style="font-size: 12px; color: #269129; text-decoration: none;">©2023 Lewis Kimaru. All rights reserved.</a>
</div>
""",
unsafe_allow_html=True
)
if __name__ == '__main__':
main()