Skip to content

Commit

Permalink
adding project files
Browse files Browse the repository at this point in the history
  • Loading branch information
SaurabhBadole committed Jun 25, 2024
0 parents commit b24e980
Show file tree
Hide file tree
Showing 14 changed files with 921 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .env
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
ASSEMBLYAI_API_KEY= #get yours from https://www.assemblyai.com/
HF_API_TOKEN= #get yours from https://huggingface.co/settings/tokens
NVIDIA_API_KEY= #get yours from https://build.nvidia.com/explore/discover#llama3-70b
api_key = #get yours from https://openai.com/
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.venv/
__pycache__/
.DS_Store
#secrets.toml
venv
1 change: 1 addition & 0 deletions .streamlit/secrets.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
api_key = 'add your api_key'
135 changes: 135 additions & 0 deletions Chatbuddy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
from openai import OpenAI
import streamlit as st
import json
from datetime import datetime
import base64
from fpdf import FPDF

# Sidebar configuration
with st.sidebar:
st.title(":orange[Welcome to ChatBuddy!]")
openai_api_key = st.text_input("OpenAI API Key", key="chatbot_api_key", type="password")
st.markdown("[Get an OpenAI API key](https://platform.openai.com/account/api-keys)")

st.sidebar.caption("""
### Get Started
1. **Enter your OpenAI API Key**: To start chatting with ChatBuddy, you'll need to enter your OpenAI API key.
2. **Chat with ChatBuddy**: Once you've entered your API key, you can start a conversation with ChatBuddy. Ask questions, seek advice, or just chat!
3. **Download Your Conversation**: After your chat session, you have the option to download the entire conversation in PDF format.
### How to Enter Your API Key
- Paste your OpenAI API key in the input box below.
- Click on "Submit chat query" to validate and start your session.
### Privacy Notice
- Your API key is stored securely during your session and is not shared with anyone.
- Conversations are stored temporarily and can be downloaded in PDF format for your records.
### Tips
- Make sure your API key is active and has sufficient quota.
- For best results, be clear and concise with your questions.
:rainbow[Enjoy your conversation with ChatBuddy!]
""")



# Main chat interface
st.markdown(
"""
<style>
.chat-header {
font-size: 2em;
font-weight: bold;
color: #333;
animation: fadeIn 2s;
}
@keyframes fadeIn {
0% { opacity: 0; }
100% { opacity: 1; }
}
.chat-input {
margin-top: 20px;
}
.download-button {
background-color: #1D1D1D;
color: white;
padding: 10px 20px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 16px;
margin: 4px 2px;
border-radius: 8px;
cursor: pointer;
}
.download-button:hover {
background-color: #000000;
}
</style>
""",
unsafe_allow_html=True
)

st.title("Your ChatBuddy🙋🏻💭")
st.caption("#### :rainbow[**ChatBuddy powered by Streamlit x OpenAI**]")

# Initialize session state if not already present
if "messages" not in st.session_state:
st.session_state["messages"] = [{"role": "assistant", "content": "Hey Buddy! How can I help you today?"}]

# Display messages in chat container
st.markdown('<div class="chat-container">', unsafe_allow_html=True)
for msg in st.session_state.messages:
st.chat_message(msg["role"]).write(msg["content"])
st.markdown('</div>', unsafe_allow_html=True)

# Handle user input
if prompt := st.chat_input(placeholder="Type your message..."):
if not openai_api_key:
st.info("Please add your OpenAI API key to continue.")
st.stop()

client = OpenAI(api_key=openai_api_key)
st.session_state.messages.append({"role": "user", "content": prompt})
st.chat_message("user").write(prompt)

# Simulate loading state
with st.spinner('Generating response...'):
response = client.chat.completions.create(model="gpt-3.5-turbo", messages=st.session_state.messages)
msg = response.choices[0].message.content
st.session_state.messages.append({"role": "assistant", "content": msg})
st.chat_message("assistant").write(msg)

# Function to download chat history as PDF
def download_chat_history_pdf():
pdf = FPDF()
pdf.add_page()
pdf.set_font("Arial", size=12)

for msg in st.session_state.messages:
if msg["role"] == "user":
pdf.set_text_color(0, 0, 255) # Blue for user messages
pdf.multi_cell(0, 10, f'User: {msg["content"]}')
else:
pdf.set_text_color(255, 0, 0) # Red for assistant messages
pdf.multi_cell(0, 10, f'Assistant: {msg["content"]}')

pdf_output = f"chat_history/chat_history_{datetime.now().strftime('%Y%m%d_%H%M%S')}.pdf"
pdf.output(pdf_output)

with open(pdf_output, "rb") as f:
b64 = base64.b64encode(f.read()).decode()

href = f'<a href="data:application/octet-stream;base64,{b64}" download="{pdf_output}">Download PDF</a>'
return href

# Download button
st.markdown('<div class="chat-input">', unsafe_allow_html=True)
st.markdown(f'<button class="download-button">{download_chat_history_pdf()}</button>', unsafe_allow_html=True)
st.markdown('</div>', unsafe_allow_html=True)

# Clear chat button
if st.button('Clear Chat'):
st.session_state["messages"] = [{"role": "assistant", "content": ""}]
st.experimental_rerun()
1 change: 1 addition & 0 deletions DocAI_history/readme.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
This folder contains conversations from the DocAI Q&A RAG application in PDF format.
1 change: 1 addition & 0 deletions chat_history/readme.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
This folder contains the chat history from the ChatBuddy conversations.
35 changes: 35 additions & 0 deletions htmltemplates.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
css = '''
<style>
.chat-message {
padding: 1.5rem;
border-radius: 0.5rem;
margin-bottom: 1rem;
display: flex;
}
.chat-message.user {
background-color: #2b313e;
}
.chat-message.bot {
background-color: #475063;
}
.chat-message .message {
width: 100%; /* Changed to 100% to fill the space previously occupied by the avatar */
padding: 0 1.5rem;
color: #fff;
}
</style>
'''

bot_template = '''
<!-- Bot Template -->
<div class="chat-message bot">
<div class="message">{{MSG}}</div>
</div>
'''

user_template = '''
<!-- User Template -->
<div class="chat-message user">
<div class="message">{{MSG}}</div>
</div>
'''
201 changes: 201 additions & 0 deletions pages/1_RAG_DocAI_Q&A.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
import streamlit as st
from dotenv import load_dotenv
from PyPDF2 import PdfReader
from langchain_nvidia_ai_endpoints import NVIDIAEmbeddings, ChatNVIDIA
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_community.vectorstores import FAISS
from langchain.memory import ConversationBufferMemory
from langchain.chains import ConversationalRetrievalChain
from reportlab.lib.pagesizes import letter
from reportlab.lib import colors
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer
from reportlab.lib.styles import getSampleStyleSheet
import base64
import tempfile
import os
from htmltemplates import *
from datetime import datetime



def get_pdf_text(pdf_docs):
text = ""
for pdf in pdf_docs:
pdf_reader = PdfReader(pdf)
for page in pdf_reader.pages:
text += page.extract_text()
return text

def get_text_chunks(text):
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=1000,
chunk_overlap=200,
)
chunks = text_splitter.split_text(text)
return chunks

def get_vectorstore(text_chunks):
embeddings = NVIDIAEmbeddings()
vectorstore = FAISS.from_texts(texts=text_chunks, embedding=embeddings)
return vectorstore

def get_conversation_chain(vectorstore):
llm = ChatNVIDIA(model="meta/llama3-70b-instruct")
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

def save_chat_session(chat_history):
with tempfile.NamedTemporaryFile(delete=False, suffix=".txt") as temp_file:
for message in chat_history:
temp_file.write(message.content.encode("utf-8") + b"\n")
return temp_file.name

def handle_userinput(user_question):
response = st.session_state.conversation({'question': user_question})
st.session_state.chat_history = response['chat_history']

for i, message in enumerate(st.session_state.chat_history):
if i % 2 == 0:
st.markdown(user_template.replace("{{MSG}}", message.content), unsafe_allow_html=True)
else:
st.markdown(bot_template.replace("{{MSG}}", message.content), unsafe_allow_html=True)

def download_pdf(chat_history):
pdf_filename = "chat_session.pdf"
doc = SimpleDocTemplate(pdf_filename, pagesize=letter)
styles = getSampleStyleSheet()
story = []

is_user_message = True
for message in chat_history:
if is_user_message:
paragraph = Paragraph(message.content, styles["Normal"])
else:
paragraph = Paragraph(message.content, styles["Normal"])
paragraph.textColor = colors.blue
story.append(paragraph)
story.append(Spacer(1, 12))
is_user_message = not is_user_message

doc.build(story)
with open(pdf_filename, "rb") as pdf_file:
pdf_contents = pdf_file.read()
return pdf_contents

##---------------------------------------------------------------------------
## V1 without using the file rename format.

# def main():
# load_dotenv()
# st.set_page_config(page_title="Your Personalized Document Chatbot", page_icon=":books:")

# if "conversation" not in st.session_state:
# st.session_state.conversation = None
# if "chat_history" not in st.session_state:
# st.session_state.chat_history = None

# st.header("Your Personalized Document Chatbot :books:")
# st.markdown(css, unsafe_allow_html=True) # Applying custom CSS

# user_question = st.text_input("Ask a question about your documents:")
# if user_question:
# handle_userinput(user_question)

# with st.sidebar:
# st.subheader("Your documents")
# pdf_docs = st.file_uploader("Upload your PDFs here and click on 'Process'", accept_multiple_files=True)
# if st.button("Process"):
# with st.spinner("Processing"):
# raw_text = get_pdf_text(pdf_docs)
# text_chunks = get_text_chunks(raw_text)
# vectorstore = get_vectorstore(text_chunks)
# st.session_state.conversation = get_conversation_chain(vectorstore)
# st.success("Vector Store DB Is Ready")

# if st.session_state.chat_history is not None:
# pdf_contents = download_pdf(st.session_state.chat_history)
# st.download_button(
# "Download above Conversation",
# pdf_contents,
# "chat_session.pdf",
# "application/pdf",
# key="download"
# )


##---------------------------------------------------------------------------

def generate_file_name():
now = datetime.now()
return now.strftime("chat_session_%Y%m%d_%H%M%S.pdf")

def save_pdf_to_folder(pdf_content, folder_path):
if not os.path.exists(folder_path):
os.makedirs(folder_path)
file_name = generate_file_name()
file_path = os.path.join(folder_path, file_name)
with open(file_path, "wb") as f:
f.write(pdf_content)
return file_path

def main():
load_dotenv()
st.set_page_config(page_title="Your Personalized Document Chatbot", page_icon=":books:")

if "conversation" not in st.session_state:
st.session_state.conversation = None
if "chat_history" not in st.session_state:
st.session_state.chat_history = None

st.header("Your Personalized Document Chatbot :books:")
st.caption("**Harness the power of Retrieval-Augmented Generation to answer questions from your documents with AI precision and efficiency.**")
st.markdown(css, unsafe_allow_html=True) # Applying custom CSS

user_question = st.text_input("Ask a question about your documents:")
if user_question:
handle_userinput(user_question)

with st.sidebar:
st.sidebar.caption(""" ### :orange[Welcome to DocAI Q&A!] """)
st.sidebar.caption("""Harness the power of Retrieval-Augmented Generation to answer questions from your documents with AI precision and efficiency.""")
pdf_docs = st.file_uploader("Upload your PDFs here and click on 'Process'", accept_multiple_files=True)
if st.button("Process"):
with st.spinner("Processing"):
raw_text = get_pdf_text(pdf_docs)
text_chunks = get_text_chunks(raw_text)
vectorstore = get_vectorstore(text_chunks)
st.session_state.conversation = get_conversation_chain(vectorstore)
st.success("Vector Store DB Is Ready")



st.sidebar.caption("""
### How to Use
1. **Upload Your Documents**: Easily upload your documents to the app.
2. **Ask Questions**: Query the content of your documents using natural language.
3. **Get Accurate Answers**: Receive precise and relevant answers generated by AI.
4. **Download Conversations**: Save your query and answer sessions by downloading them in PDF format.
:rainbow[Enjoy a seamless and intelligent way to interact with your documents!]
""")


if st.session_state.chat_history is not None:
pdf_contents = download_pdf(st.session_state.chat_history)
save_folder = os.path.join(os.getcwd(), "DocAI_history")
saved_file_path = save_pdf_to_folder(pdf_contents, save_folder)

st.download_button(
"Download above Conversation",
pdf_contents,
saved_file_path,
"application/pdf",
key="download"
)
if __name__ == '__main__':
main()
Loading

0 comments on commit b24e980

Please sign in to comment.