-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit b24e980
Showing
14 changed files
with
921 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
.venv/ | ||
__pycache__/ | ||
.DS_Store | ||
#secrets.toml | ||
venv |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
api_key = 'add your api_key' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
This folder contains the chat history from the ChatBuddy conversations. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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> | ||
''' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() |
Oops, something went wrong.