├── .env ├── .gitignore ├── .streamlit └── secrets.toml ├── Chatbuddy.py ├── DocAI_history └── readme.txt ├── LICENSE ├── README.md ├── chat_history └── readme.txt ├── htmltemplates.py ├── pages ├── 1_RAG_DocAI_Q&A.py ├── 2_Chat_with_search.py ├── 3_AudioVideo Transcriber.py ├── 4_YouTube_Transcriber.py └── 5_MoM_Generator.py ├── requirements.txt └── utils.py /.env: -------------------------------------------------------------------------------- 1 | ASSEMBLYAI_API_KEY= #get yours from https://www.assemblyai.com/ 2 | HF_API_TOKEN= #get yours from https://huggingface.co/settings/tokens 3 | NVIDIA_API_KEY= #get yours from https://build.nvidia.com/explore/discover#llama3-70b 4 | api_key = #get yours from https://openai.com/ -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .venv/ 2 | __pycache__/ 3 | .DS_Store 4 | #secrets.toml 5 | venv -------------------------------------------------------------------------------- /.streamlit/secrets.toml: -------------------------------------------------------------------------------- 1 | api_key = 'add your api_key' -------------------------------------------------------------------------------- /Chatbuddy.py: -------------------------------------------------------------------------------- 1 | from openai import OpenAI 2 | import streamlit as st 3 | import json 4 | from datetime import datetime 5 | import base64 6 | from fpdf import FPDF 7 | 8 | # Sidebar configuration 9 | with st.sidebar: 10 | st.title(":orange[Welcome to ChatBuddy!]") 11 | openai_api_key = st.text_input("OpenAI API Key", key="chatbot_api_key", type="password") 12 | st.markdown("[Get an OpenAI API key](https://platform.openai.com/account/api-keys)") 13 | 14 | st.sidebar.caption(""" 15 | ### Get Started 16 | 1. **Enter your OpenAI API Key**: To start chatting with ChatBuddy, you'll need to enter your OpenAI API key. 17 | 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! 18 | 3. **Download Your Conversation**: After your chat session, you have the option to download the entire conversation in PDF format. 19 | 20 | ### How to Enter Your API Key 21 | - Paste your OpenAI API key in the input box below. 22 | - Click on "Submit chat query" to validate and start your session. 23 | 24 | ### Privacy Notice 25 | - Your API key is stored securely during your session and is not shared with anyone. 26 | - Conversations are stored temporarily and can be downloaded in PDF format for your records. 27 | 28 | ### Tips 29 | - Make sure your API key is active and has sufficient quota. 30 | - For best results, be clear and concise with your questions. 31 | 32 | :rainbow[Enjoy your conversation with ChatBuddy!] 33 | """) 34 | 35 | 36 | 37 | # Main chat interface 38 | st.markdown( 39 | """ 40 | 70 | """, 71 | unsafe_allow_html=True 72 | ) 73 | 74 | st.title("Your ChatBuddy🙋🏻💭") 75 | st.caption("#### :rainbow[**ChatBuddy powered by Streamlit x OpenAI**]") 76 | 77 | # Initialize session state if not already present 78 | if "messages" not in st.session_state: 79 | st.session_state["messages"] = [{"role": "assistant", "content": "Hey Buddy! How can I help you today?"}] 80 | 81 | # Display messages in chat container 82 | st.markdown('
', unsafe_allow_html=True) 83 | for msg in st.session_state.messages: 84 | st.chat_message(msg["role"]).write(msg["content"]) 85 | st.markdown('
', unsafe_allow_html=True) 86 | 87 | # Handle user input 88 | if prompt := st.chat_input(placeholder="Type your message..."): 89 | if not openai_api_key: 90 | st.info("Please add your OpenAI API key to continue.") 91 | st.stop() 92 | 93 | client = OpenAI(api_key=openai_api_key) 94 | st.session_state.messages.append({"role": "user", "content": prompt}) 95 | st.chat_message("user").write(prompt) 96 | 97 | # Simulate loading state 98 | with st.spinner('Generating response...'): 99 | response = client.chat.completions.create(model="gpt-3.5-turbo", messages=st.session_state.messages) 100 | msg = response.choices[0].message.content 101 | st.session_state.messages.append({"role": "assistant", "content": msg}) 102 | st.chat_message("assistant").write(msg) 103 | 104 | # Function to download chat history as PDF 105 | def download_chat_history_pdf(): 106 | pdf = FPDF() 107 | pdf.add_page() 108 | pdf.set_font("Arial", size=12) 109 | 110 | for msg in st.session_state.messages: 111 | if msg["role"] == "user": 112 | pdf.set_text_color(0, 0, 255) # Blue for user messages 113 | pdf.multi_cell(0, 10, f'User: {msg["content"]}') 114 | else: 115 | pdf.set_text_color(255, 0, 0) # Red for assistant messages 116 | pdf.multi_cell(0, 10, f'Assistant: {msg["content"]}') 117 | 118 | pdf_output = f"chat_history/chat_history_{datetime.now().strftime('%Y%m%d_%H%M%S')}.pdf" 119 | pdf.output(pdf_output) 120 | 121 | with open(pdf_output, "rb") as f: 122 | b64 = base64.b64encode(f.read()).decode() 123 | 124 | href = f'Download PDF' 125 | return href 126 | 127 | # Download button 128 | st.markdown('
', unsafe_allow_html=True) 129 | st.markdown(f'', unsafe_allow_html=True) 130 | st.markdown('
', unsafe_allow_html=True) 131 | 132 | # Clear chat button 133 | if st.button('Clear Chat'): 134 | st.session_state["messages"] = [{"role": "assistant", "content": ""}] 135 | st.experimental_rerun() 136 | -------------------------------------------------------------------------------- /DocAI_history/readme.txt: -------------------------------------------------------------------------------- 1 | This folder contains conversations from the DocAI Q&A RAG application in PDF format. -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Saurabh Badole 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LLM Toolbox Suite 2 | 3 | Welcome to the **LLM Toolbox Suite**, a powerful and versatile set of tools designed to harness the capabilities of large language models for various productive tasks. This suite is built using Streamlit and integrates APIs from OpenAI, AssemblyAI, and NVIDIA. 4 | 5 | ## Overview 6 | 7 | **LLM Toolbox Suite** is designed to provide users with an interactive and user-friendly interface to **chat with AI, chat with multiple Documents, chat with WebSearch, effortlessly transcribe, analyze, and chat with multi-speaker audio/video conversations amd even generate Meeting of Minutes with main themes!** 8 | 9 | The suite includes: 10 | 11 | - **ChatBuddy** : An interactive chatbot powered by OpenAI's GPT and Streamlit.![Chatbuddy](https://github.com/SaurabhBadole/llm-toolbox-suite/assets/132877393/f5c2e146-005f-4df5-95bc-1d5e54a2f5d8) 12 | 13 | 14 | 15 | - **RAG DocAI Q&A**: Harness the power of Retrieval-Augmented Generation to answer questions from your documents with AI precision and efficiency.![RAG_DocAI_Q A](https://github.com/SaurabhBadole/llm-toolbox-suite/assets/132877393/1cdb4435-1c0a-47a2-b257-62a80bc0f3e9) 16 | 17 | 18 | - **Chat with Search**: Enhance your conversations with integrated search capabilities, providing instant answers and information from the web.![Chat_with_search](https://github.com/SaurabhBadole/llm-toolbox-suite/assets/132877393/4111a594-d53e-4b65-bd8b-2c9d4fc4c9f4) 19 | 20 | 21 | 22 | - **AudioVideo Transcriber**: Effortlessly transcribe, analyze, and chat with multi-speaker audio/video conversations.![AudioVideo_Transcriber](https://github.com/SaurabhBadole/llm-toolbox-suite/assets/132877393/0a1067e1-d72b-45b4-95d6-f5edcabedb4c) 23 | 24 | 25 | 26 | - **YouTube Transcriber**: Easily convert YouTube videos into text with detailed transcripts for better comprehension and analysis.![YouTube_Transcriber](https://github.com/SaurabhBadole/llm-toolbox-suite/assets/132877393/9fe1ebec-5894-4ae3-8f32-835f30d2f70f) 27 | 28 | 29 | 30 | - **MoM Generator**: Transform your meeting recordings into detailed, categorized summaries and downloadable transcripts effortlessly.![MoM_Generator](https://github.com/SaurabhBadole/llm-toolbox-suite/assets/132877393/ac76befa-4552-43f4-ac8e-e70c63d12b3d) 31 | 32 | 33 | 34 | ## Features 35 | 36 | 37 | - **Interactive and Responsive Design**: Enjoy a user-friendly and visually appealing interface. 38 | - **API Integration**: Seamlessly integrates with OpenAI, AssemblyAI, and NVIDIA APIs. 39 | - **Chat Interface**: Engage in conversations with an AI assistant for seamless interaction. 40 | - **Retrieval-Augmented Generation (RAG)**: Leverage advanced AI to provide precise answers to questions from documents using retrieval-augmented generation techniques. 41 | - **Integrated Search Capabilities**: Enhance conversations with instant access to web-based information and answers. 42 | - **Audio/Video Transcription**: Effortlessly transcribe and analyze multi-speaker audio and video conversations. 43 | - **YouTube Video Transcription**: Convert YouTube videos into detailed text transcripts for improved comprehension and analysis. 44 | - **Meeting Summary Generation**: Automatically generate detailed, categorized summaries and downloadable transcripts from meeting audio recordings. 45 | - **PDF Export**: Download your conversation as a PDF file. 46 | 47 | ## Getting Started 48 | 49 | ### Prerequisites 50 | 51 | Ensure you have the following installed: 52 | 53 | - Python 3.8 or higher 54 | - Streamlit 55 | - OpenAI API Key 56 | - AssemblyAI API Key 57 | - NVIDIA API Key 58 | 59 | ### Installation 60 | 61 | 1. Clone the repository: 62 | ```sh 63 | git clone https://github.com/SaurabhBadole/llm-toolbox-suite.git 64 | cd llm-toolbox-suite 65 | ``` 66 | 67 | 2. Create and activate a virtual environment: 68 | ```sh 69 | python -m venv venv 70 | source venv/bin/activate # On Windows use `venv\Scripts\activate` 71 | ``` 72 | 73 | 3. Install the required dependencies: 74 | ```sh 75 | pip install -r requirements.txt 76 | ``` 77 | 78 | 4. Set up your environment variables by creating a `.env` file in the root directory and adding your API keys: 79 | ```sh 80 | ASSEMBLYAI_API_KEY=your_assemblyai_api_key 81 | HF_API_TOKEN=your_huggingface_api_token 82 | NVIDIA_API_KEY=your_nvidia_api_key 83 | OPENAI_API_KEY=your_openai_api_key 84 | ``` 85 | 86 | ### Running the Application 87 | 88 | Run the main file to start the application: 89 | ```sh 90 | streamlit run Chatbuddy.py 91 | ``` 92 | 93 | ## Project Structure 94 | 95 | Here's an overview of the project's structure: 96 | 97 | ``` 98 | llm-toolbox-suite/ 99 | │ 100 | ├──pages/ 101 | | └──1_RAG_DocAI_Q&A.py # application file for having conversation with an AI bot while can also download the conversation as PDF 102 | | └──2_Chat_with_search.py # application file for having conversations with WebSearch 103 | | └──3_AudioVideo_Transcriber.py # application file for transcribing, analyzing, and chatting with multi-speaker audio/video conversations 104 | | └──4_YouTube_Transcriber.py # application file for convert YouTube videos into text with detailed transcripts 105 | | └──5_MoM_Generator.py # application file for Meeting of Minutes generator with Main Themes and time stamps 106 | ├── .env # Environment variables 107 | ├── Chatbuddy.py # Main application file starting with main page ChatBuddy 108 | ├── htmltemplates.py # HTML templates for RAG DocAI Q&A Streamlit Interface 109 | ├── requirements.txt # Python dependencies 110 | ├── README.md # Project documentation 111 | ├── utils.py # Utility functions 112 | ├── chat_history/ # Directory for saving chat history for ChatBuddy 113 | ├── DocAI_history/ # Directory for saving DocAI RAG conversations 114 | ``` 115 | 116 | ### Detailed Description of Files 117 | 118 | - **pages/RAG_DocAI_Q&A.py**: 119 | - This file provides functionality for users to interact with an AI bot, allowing them to ask questions and receive detailed responses. Additionally, it includes an option to download the entire conversation as a PDF for record-keeping or review purposes. 120 | 121 | - **pages/Chat_with_search.py**: 122 | - This file enables users to engage in conversations with an AI that has integrated web search capabilities. The AI can fetch and provide real-time information from the web, enhancing the quality and relevance of the responses. 123 | 124 | - **pages/AudioVideo_Transcriber.py**: 125 | - This file is designed to handle audio and video files, transcribing the spoken content into text. It can analyze multi-speaker conversations, providing insights and the ability to chat about the content. It's ideal for reviewing and interacting with recorded meetings or interviews. 126 | 127 | - **pages/YouTube_Transcriber.py**: 128 | - This file allows users to convert YouTube videos into text. It generates detailed transcripts, making it easier to analyze and extract information from video content. This can be useful for content creators, researchers, and anyone needing text versions of video material. 129 | 130 | - **pages/MoM_Generator.py**: 131 | - This file is aimed at generating Minutes of Meetings (MoM). It extracts the main themes and provides timestamps, making it a valuable tool for summarizing meetings and ensuring that important points are documented and easily accessible. 132 | - **.env**: Stores API keys and other environment variables. 133 | - **Chatbuddy.py**: The main Streamlit application file. Contains the core logic for the chat interface and PDF download functionality. 134 | - **htmltemplates.py**: Defines the HTML and CSS templates used for styling the chat interface. 135 | - **requirements.txt**: Lists all the required Python packages. 136 | - **utils.py**: Contains utility functions for time conversion, file reading, and chat session management. 137 | - **chat_history/**: Directory for saving chat history files. 138 | - **DocAI_history/**: Directory for saving DocAI RAG conversations 139 | 140 | ## Usage 141 | 142 | 1. **Enter API Keys**: Start the application and enter your API keys for tools wherever the api key is asked in the sidebar. 143 | 2. **Chat with multiple tools**: Begin chatting with the AI assistant by typing your message and then download conversations in pdf format. 144 | 3. **Download Conversation**: After your session, download the chat history in PDF format. 145 | 4. **Download Transcripts**: After transcribing the YT videos, you can downlownload it in txt and SRT format. 146 | 5. **Clear Chat**: Use the 'Clear Chat' button to start a new session. 147 | 148 | 149 | ## Acknowledgments 150 | 151 | - [Streamlit](https://streamlit.io/) 152 | - [OpenAI](https://openai.com/) 153 | - [AssemblyAI](https://www.assemblyai.com/) 154 | - [NVIDIA](https://www.nvidia.com/) 155 | 156 | ## Contact 157 | 158 | For any inquiries, please contact [Saurabh Khushal Badole](mailto:saurabhbadole25.98@gmail.com). 159 | 160 | --- 161 | 162 | -------------------------------------------------------------------------------- /chat_history/readme.txt: -------------------------------------------------------------------------------- 1 | This folder contains the chat history from the ChatBuddy conversations. -------------------------------------------------------------------------------- /htmltemplates.py: -------------------------------------------------------------------------------- 1 | css = ''' 2 | 21 | ''' 22 | 23 | bot_template = ''' 24 | 25 |
26 |
{{MSG}}
27 |
28 | ''' 29 | 30 | user_template = ''' 31 | 32 |
33 |
{{MSG}}
34 |
35 | ''' 36 | -------------------------------------------------------------------------------- /pages/1_RAG_DocAI_Q&A.py: -------------------------------------------------------------------------------- 1 | import streamlit as st 2 | from dotenv import load_dotenv 3 | from PyPDF2 import PdfReader 4 | from langchain_nvidia_ai_endpoints import NVIDIAEmbeddings, ChatNVIDIA 5 | from langchain.text_splitter import RecursiveCharacterTextSplitter 6 | from langchain_community.vectorstores import FAISS 7 | from langchain.memory import ConversationBufferMemory 8 | from langchain.chains import ConversationalRetrievalChain 9 | from reportlab.lib.pagesizes import letter 10 | from reportlab.lib import colors 11 | from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer 12 | from reportlab.lib.styles import getSampleStyleSheet 13 | import base64 14 | import tempfile 15 | import os 16 | from htmltemplates import * 17 | from datetime import datetime 18 | 19 | 20 | 21 | def get_pdf_text(pdf_docs): 22 | text = "" 23 | for pdf in pdf_docs: 24 | pdf_reader = PdfReader(pdf) 25 | for page in pdf_reader.pages: 26 | text += page.extract_text() 27 | return text 28 | 29 | def get_text_chunks(text): 30 | text_splitter = RecursiveCharacterTextSplitter( 31 | chunk_size=1000, 32 | chunk_overlap=200, 33 | ) 34 | chunks = text_splitter.split_text(text) 35 | return chunks 36 | 37 | def get_vectorstore(text_chunks): 38 | embeddings = NVIDIAEmbeddings() 39 | vectorstore = FAISS.from_texts(texts=text_chunks, embedding=embeddings) 40 | return vectorstore 41 | 42 | def get_conversation_chain(vectorstore): 43 | llm = ChatNVIDIA(model="meta/llama3-70b-instruct") 44 | memory = ConversationBufferMemory(memory_key='chat_history', return_messages=True) 45 | conversation_chain = ConversationalRetrievalChain.from_llm( 46 | llm=llm, 47 | retriever=vectorstore.as_retriever(), 48 | memory=memory 49 | ) 50 | return conversation_chain 51 | 52 | def save_chat_session(chat_history): 53 | with tempfile.NamedTemporaryFile(delete=False, suffix=".txt") as temp_file: 54 | for message in chat_history: 55 | temp_file.write(message.content.encode("utf-8") + b"\n") 56 | return temp_file.name 57 | 58 | def handle_userinput(user_question): 59 | response = st.session_state.conversation({'question': user_question}) 60 | st.session_state.chat_history = response['chat_history'] 61 | 62 | for i, message in enumerate(st.session_state.chat_history): 63 | if i % 2 == 0: 64 | st.markdown(user_template.replace("{{MSG}}", message.content), unsafe_allow_html=True) 65 | else: 66 | st.markdown(bot_template.replace("{{MSG}}", message.content), unsafe_allow_html=True) 67 | 68 | def download_pdf(chat_history): 69 | pdf_filename = "chat_session.pdf" 70 | doc = SimpleDocTemplate(pdf_filename, pagesize=letter) 71 | styles = getSampleStyleSheet() 72 | story = [] 73 | 74 | is_user_message = True 75 | for message in chat_history: 76 | if is_user_message: 77 | paragraph = Paragraph(message.content, styles["Normal"]) 78 | else: 79 | paragraph = Paragraph(message.content, styles["Normal"]) 80 | paragraph.textColor = colors.blue 81 | story.append(paragraph) 82 | story.append(Spacer(1, 12)) 83 | is_user_message = not is_user_message 84 | 85 | doc.build(story) 86 | with open(pdf_filename, "rb") as pdf_file: 87 | pdf_contents = pdf_file.read() 88 | return pdf_contents 89 | 90 | ##--------------------------------------------------------------------------- 91 | ## V1 without using the file rename format. 92 | 93 | # def main(): 94 | # load_dotenv() 95 | # st.set_page_config(page_title="Your Personalized Document Chatbot", page_icon=":books:") 96 | 97 | # if "conversation" not in st.session_state: 98 | # st.session_state.conversation = None 99 | # if "chat_history" not in st.session_state: 100 | # st.session_state.chat_history = None 101 | 102 | # st.header("Your Personalized Document Chatbot :books:") 103 | # st.markdown(css, unsafe_allow_html=True) # Applying custom CSS 104 | 105 | # user_question = st.text_input("Ask a question about your documents:") 106 | # if user_question: 107 | # handle_userinput(user_question) 108 | 109 | # with st.sidebar: 110 | # st.subheader("Your documents") 111 | # pdf_docs = st.file_uploader("Upload your PDFs here and click on 'Process'", accept_multiple_files=True) 112 | # if st.button("Process"): 113 | # with st.spinner("Processing"): 114 | # raw_text = get_pdf_text(pdf_docs) 115 | # text_chunks = get_text_chunks(raw_text) 116 | # vectorstore = get_vectorstore(text_chunks) 117 | # st.session_state.conversation = get_conversation_chain(vectorstore) 118 | # st.success("Vector Store DB Is Ready") 119 | 120 | # if st.session_state.chat_history is not None: 121 | # pdf_contents = download_pdf(st.session_state.chat_history) 122 | # st.download_button( 123 | # "Download above Conversation", 124 | # pdf_contents, 125 | # "chat_session.pdf", 126 | # "application/pdf", 127 | # key="download" 128 | # ) 129 | 130 | 131 | ##--------------------------------------------------------------------------- 132 | 133 | def generate_file_name(): 134 | now = datetime.now() 135 | return now.strftime("chat_session_%Y%m%d_%H%M%S.pdf") 136 | 137 | def save_pdf_to_folder(pdf_content, folder_path): 138 | if not os.path.exists(folder_path): 139 | os.makedirs(folder_path) 140 | file_name = generate_file_name() 141 | file_path = os.path.join(folder_path, file_name) 142 | with open(file_path, "wb") as f: 143 | f.write(pdf_content) 144 | return file_path 145 | 146 | def main(): 147 | load_dotenv() 148 | st.set_page_config(page_title="Your Personalized Document Chatbot", page_icon=":books:") 149 | 150 | if "conversation" not in st.session_state: 151 | st.session_state.conversation = None 152 | if "chat_history" not in st.session_state: 153 | st.session_state.chat_history = None 154 | 155 | st.header("Your Personalized Document Chatbot :books:") 156 | st.caption("**Harness the power of Retrieval-Augmented Generation to answer questions from your documents with AI precision and efficiency.**") 157 | st.markdown(css, unsafe_allow_html=True) # Applying custom CSS 158 | 159 | user_question = st.text_input("Ask a question about your documents:") 160 | if user_question: 161 | handle_userinput(user_question) 162 | 163 | with st.sidebar: 164 | st.sidebar.caption(""" ### :orange[Welcome to DocAI Q&A!] """) 165 | st.sidebar.caption("""Harness the power of Retrieval-Augmented Generation to answer questions from your documents with AI precision and efficiency.""") 166 | pdf_docs = st.file_uploader("Upload your PDFs here and click on 'Process'", accept_multiple_files=True) 167 | if st.button("Process"): 168 | with st.spinner("Processing"): 169 | raw_text = get_pdf_text(pdf_docs) 170 | text_chunks = get_text_chunks(raw_text) 171 | vectorstore = get_vectorstore(text_chunks) 172 | st.session_state.conversation = get_conversation_chain(vectorstore) 173 | st.success("Vector Store DB Is Ready") 174 | 175 | 176 | 177 | st.sidebar.caption(""" 178 | ### How to Use 179 | 1. **Upload Your Documents**: Easily upload your documents to the app. 180 | 2. **Ask Questions**: Query the content of your documents using natural language. 181 | 3. **Get Accurate Answers**: Receive precise and relevant answers generated by AI. 182 | 4. **Download Conversations**: Save your query and answer sessions by downloading them in PDF format. 183 | 184 | :rainbow[Enjoy a seamless and intelligent way to interact with your documents!] 185 | """) 186 | 187 | 188 | if st.session_state.chat_history is not None: 189 | pdf_contents = download_pdf(st.session_state.chat_history) 190 | save_folder = os.path.join(os.getcwd(), "DocAI_history") 191 | saved_file_path = save_pdf_to_folder(pdf_contents, save_folder) 192 | 193 | st.download_button( 194 | "Download above Conversation", 195 | pdf_contents, 196 | saved_file_path, 197 | "application/pdf", 198 | key="download" 199 | ) 200 | if __name__ == '__main__': 201 | main() 202 | -------------------------------------------------------------------------------- /pages/2_Chat_with_search.py: -------------------------------------------------------------------------------- 1 | import streamlit as st 2 | 3 | from langchain.agents import initialize_agent, AgentType 4 | from langchain_community.callbacks.streamlit import StreamlitCallbackHandler 5 | from langchain_community.chat_models import ChatOpenAI 6 | from langchain_community.tools import DuckDuckGoSearchRun 7 | 8 | st.sidebar.caption(""" 9 | ### :orange[Chat with search🔍]""") 10 | st.sidebar.caption("""Enhance your conversations with integrated search capabilities, providing instant answers and information from the web.""") 11 | 12 | 13 | with st.sidebar: 14 | openai_api_key = st.text_input( 15 | "OpenAI API Key", key="langchain_search_api_key_openai", type="password" 16 | ) 17 | "[Get an OpenAI API key](https://platform.openai.com/account/api-keys)" 18 | 19 | 20 | st.sidebar.caption(""" 21 | ### Get Started 22 | 1. **Enter your OpenAI API Key**: To start, please enter your OpenAI API key above. 23 | 2. **Chat and Search**: Engage in conversations and use the integrated search to get real-time information and answers. 24 | 3. **Enjoy Enhanced Interactions**: Experience more informative and dynamic conversations. 25 | 26 | 27 | ### Privacy Notice 28 | - Your API key is stored securely during your session and is not shared with anyone. 29 | - Conversations and search queries are handled with care to ensure your privacy. 30 | 31 | :rainbow[Enhance your conversations with Chat with search!] 32 | """) 33 | 34 | 35 | st.title("Chat with search🔍") 36 | st.caption("**Enhance your conversations with integrated search capabilities, providing instant answers and information from the web.**") 37 | 38 | if "messages" not in st.session_state: 39 | st.session_state["messages"] = [ 40 | {"role": "assistant", "content": "Hello! I'm here to assist you by searching the web. What can I find for you today?"} 41 | ] 42 | 43 | for msg in st.session_state.messages: 44 | st.chat_message(msg["role"]).write(msg["content"]) 45 | 46 | if prompt := st.chat_input(placeholder="What is the current exchange rate for USD to EUR?"): 47 | st.session_state.messages.append({"role": "user", "content": prompt}) 48 | st.chat_message("user").write(prompt) 49 | 50 | if not openai_api_key: 51 | st.info("Please add your OpenAI API key to continue.") 52 | st.stop() 53 | 54 | llm = ChatOpenAI(model_name="gpt-3.5-turbo", openai_api_key=openai_api_key, streaming=True) 55 | search = DuckDuckGoSearchRun(name="Search") 56 | search_agent = initialize_agent( 57 | [search], llm, agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, handle_parsing_errors=True 58 | ) 59 | with st.chat_message("assistant"): 60 | st_cb = StreamlitCallbackHandler(st.container(), expand_new_thoughts=False) 61 | response = search_agent.run(st.session_state.messages, callbacks=[st_cb]) 62 | st.session_state.messages.append({"role": "assistant", "content": response}) 63 | st.write(response) 64 | -------------------------------------------------------------------------------- /pages/3_AudioVideo Transcriber.py: -------------------------------------------------------------------------------- 1 | import os 2 | import streamlit as st 3 | import base64 4 | from haystack.components.writers import DocumentWriter 5 | from haystack.components.preprocessors import DocumentSplitter 6 | from haystack.components.embedders import SentenceTransformersDocumentEmbedder 7 | from haystack import Pipeline 8 | from haystack.document_stores.in_memory import InMemoryDocumentStore 9 | from assemblyai_haystack.transcriber import AssemblyAITranscriber 10 | from haystack.document_stores.types import DuplicatePolicy 11 | from haystack.utils import ComponentDevice 12 | from haystack.components.builders.prompt_builder import PromptBuilder 13 | from haystack.components.generators import HuggingFaceAPIGenerator 14 | from haystack.components.embedders import SentenceTransformersTextEmbedder 15 | from haystack.components.retrievers.in_memory import InMemoryEmbeddingRetriever 16 | from time import sleep 17 | import requests 18 | 19 | 20 | def audiovideomodule(): 21 | 22 | with st.sidebar: 23 | st.caption("### :orange[Welcome to Audio/Video Transcriber!]") 24 | st.caption("Effortlessly transcribe, analyze, and chat with multi-speaker audio/video conversations.") 25 | 26 | ASSEMBLYAI_API_KEY = st.text_input("Enter your ASSEMBLYAI_API_KEY: ", type="password") 27 | st.markdown("[Get your your AssemblyAI API key ](https://www.assemblyai.com/app/account)") 28 | 29 | HF_API_TOKEN = st.text_input("Enter your HF_API_TOKEN: ", type="password") 30 | st.markdown("[Get your Hugging Face API key](https://huggingface.co/settings/tokens)") 31 | 32 | 33 | st.sidebar.caption(""" 34 | 35 | 36 | ### Get Started 37 | 1. **Enter your API Keys**: To begin, please enter your AssemblyAI API key and Hugging Face API token above. 38 | 2. **Upload Your Audio/Video Files**: Easily upload your files for transcription. 39 | 3. **Transcribe and Analyze**: Automatically transcribe and analyze your multi-speaker conversations. 40 | 4. **Chat with Transcriptions**: Engage in interactive chats based on the transcribed content. 41 | 42 | ### Privacy Notice 43 | - Your API keys are stored securely during your session and are not shared with anyone. 44 | - Uploaded files and transcriptions are handled with care to ensure your privacy. 45 | 46 | :rainbow[Enhance your transcription experience with our powerful tools!] 47 | """) 48 | 49 | 50 | def get_api_keys(): 51 | os.environ["ASSEMBLYAI_API_KEY"] = ASSEMBLYAI_API_KEY 52 | os.environ["HF_API_TOKEN"] = HF_API_TOKEN 53 | return ASSEMBLYAI_API_KEY, HF_API_TOKEN 54 | 55 | def read_file(filename, chunk_size=5242880): 56 | with open(filename, 'rb') as _file: 57 | while True: 58 | data = _file.read(chunk_size) 59 | if not data: 60 | break 61 | yield data 62 | 63 | # Set up Streamlit interface 64 | st.title("Audio/Video Transcriber") 65 | st.caption("**Effortlessly transcribe, analyze, and chat with multi-speaker audio/video conversations**") 66 | 67 | # Get API keys 68 | ASSEMBLYAI_API_KEY, HF_API_TOKEN = get_api_keys() 69 | 70 | # File uploader 71 | uploaded_file = st.file_uploader("Upload Audio/Video File", type=["mp3", "mp4", "wav", "m4a"]) 72 | 73 | transcript_text = "" 74 | 75 | # Check if a file is uploaded and API keys are provided 76 | if uploaded_file is not None and ASSEMBLYAI_API_KEY and HF_API_TOKEN: 77 | with open("temp_file", "wb") as f: 78 | f.write(uploaded_file.getbuffer()) 79 | 80 | # Initialize components 81 | speaker_document_store = InMemoryDocumentStore() 82 | transcriber = AssemblyAITranscriber(api_key=ASSEMBLYAI_API_KEY) 83 | speaker_splitter = DocumentSplitter(split_by="sentence", split_length=10, split_overlap=1) 84 | speaker_embedder = SentenceTransformersDocumentEmbedder(device=ComponentDevice.from_str("cpu")) 85 | speaker_writer = DocumentWriter(speaker_document_store, policy=DuplicatePolicy.SKIP) 86 | 87 | # Create the indexing pipeline 88 | indexing_pipeline = Pipeline() 89 | indexing_pipeline.add_component(instance=transcriber, name="transcriber") 90 | indexing_pipeline.add_component(instance=speaker_splitter, name="speaker_splitter") 91 | indexing_pipeline.add_component(instance=speaker_embedder, name="speaker_embedder") 92 | indexing_pipeline.add_component(instance=speaker_writer, name="speaker_writer") 93 | 94 | indexing_pipeline.connect("transcriber.speaker_labels", "speaker_splitter") 95 | indexing_pipeline.connect("speaker_splitter", "speaker_embedder") 96 | indexing_pipeline.connect("speaker_embedder", "speaker_writer") 97 | 98 | # Transcribe the file 99 | st.write("Transcribing the file...") 100 | bar = st.progress(0) 101 | 102 | result = indexing_pipeline.run( 103 | { 104 | "transcriber": { 105 | "file_path": "temp_file", 106 | "summarization": None, 107 | "speaker_labels": True 108 | }, 109 | } 110 | ) 111 | bar.progress(50) 112 | st.success("Transcription complete!") 113 | 114 | # # Extract the transcript text 115 | # transcript_docs = speaker_document_store.get_all_documents_generator() 116 | # transcript_text = "\n".join([doc.content for doc in transcript_docs]) 117 | 118 | bar.progress(100) 119 | 120 | # Provide options for downloading or interacting with the transcript 121 | st.header('Output') 122 | tab1, tab2 = st.tabs(["Download Transcript", "Chat with Transcript"]) 123 | 124 | with tab1: 125 | st.write("Download the transcribed text:") 126 | b64 = base64.b64encode(transcript_text.encode()).decode() 127 | href = f'Download Transcript' 128 | st.markdown(href, unsafe_allow_html=True) 129 | 130 | with tab2: 131 | st.write("Ask questions about the transcript:") 132 | 133 | open_chat_prompt = """ 134 | GPT4 Correct User: You will be provided with a transcription of a recording with each sentence or group of sentences attributed to a Speaker by the word "Speaker" followed by a letter representing the person uttering that sentence. Answer the given question based on the given context. 135 | If you think that given transcription is not enough to answer the question, say so. 136 | 137 | Transcription: 138 | {% for doc in documents %} 139 | {% if doc.meta["speaker"] %} Speaker {{doc.meta["speaker"]}}: {% endif %}{{doc.content}} 140 | {% endfor %} 141 | Question: {{ question }} 142 | 143 | GPT4 Correct Assistant: 144 | """ 145 | 146 | retriever = InMemoryEmbeddingRetriever(speaker_document_store) 147 | text_embedder = SentenceTransformersTextEmbedder(device=ComponentDevice.from_str("cpu")) 148 | answer_generator = HuggingFaceAPIGenerator( 149 | api_type="serverless_inference_api", 150 | api_params={"model": "openchat/openchat-3.5-0106"}, 151 | generation_kwargs={"max_new_tokens":500} 152 | ) 153 | prompt_builder = PromptBuilder(template=open_chat_prompt) 154 | 155 | speaker_rag_pipe = Pipeline() 156 | speaker_rag_pipe.add_component("text_embedder", text_embedder) 157 | speaker_rag_pipe.add_component("retriever", retriever) 158 | speaker_rag_pipe.add_component("prompt_builder", prompt_builder) 159 | speaker_rag_pipe.add_component("llm", answer_generator) 160 | 161 | speaker_rag_pipe.connect("text_embedder.embedding", "retriever.query_embedding") 162 | speaker_rag_pipe.connect("retriever.documents", "prompt_builder.documents") 163 | speaker_rag_pipe.connect("prompt_builder.prompt", "llm.prompt") 164 | 165 | question = st.text_input("Enter your question:", "") 166 | 167 | if st.button("Get Answer") and question: 168 | result = speaker_rag_pipe.run({ 169 | "prompt_builder": {"question": question}, 170 | "text_embedder": {"text": question}, 171 | "retriever": {"top_k": 10} 172 | }) 173 | st.write(result["llm"]["replies"][0]) 174 | 175 | if __name__ == "__main__": 176 | audiovideomodule() 177 | -------------------------------------------------------------------------------- /pages/4_YouTube_Transcriber.py: -------------------------------------------------------------------------------- 1 | import os 2 | import requests 3 | import streamlit as st 4 | from pytube import YouTube 5 | from zipfile import ZipFile 6 | from utils import read_file 7 | # from time import sleep 8 | 9 | 10 | def youtube_transcription(): 11 | st.markdown('# **YouTube Transcriber ▶️**') 12 | st.caption("**Easily convert YouTube videos into text with detailed transcripts for better comprehension and analysis.**") 13 | st.sidebar.caption(""" 14 | ### :orange[Welcome to YouTube Transcriber!] 15 | Easily convert YouTube videos into text with detailed transcripts for better comprehension and analysis.""") 16 | 17 | URL = st.sidebar.text_input('Enter URL of YouTube video:') 18 | submit_button = st.sidebar.button('Go') 19 | 20 | st.sidebar.caption(""" 21 | 22 | ### Get Started 23 | 1. **Enter YouTube Video URL**: Simply paste the URL of the YouTube video you want to transcribe. 24 | 2. **Generate Transcript**: Click "Go" to convert the video into a detailed text transcript. 25 | 3. **Analyze and Comprehend**: Use the transcript for better understanding and analysis of the video's content. 26 | 27 | ### Privacy Notice 28 | - Your video URL is used solely for the purpose of generating the transcript and is not shared with anyone. 29 | - Generated transcripts are stored temporarily and can be downloaded for your records. 30 | 31 | :rainbow[Start transcribing your YouTube videos now!] 32 | """) 33 | 34 | if submit_button and URL: 35 | api_key = st.secrets['api_key'] 36 | headers = {"authorization": api_key, "content-type": "application/json"} 37 | bar = st.progress(0) 38 | 39 | # Function to download YouTube audio 40 | def get_yt_audio(url): 41 | video = YouTube(url) 42 | yt = video.streams.get_audio_only() 43 | yt.download() 44 | bar.progress(10) 45 | return yt.default_filename 46 | 47 | # Function to transcribe audio 48 | def transcribe_yt(filename): 49 | bar.progress(20) 50 | response = requests.post('https://api.assemblyai.com/v2/upload', headers=headers, data=read_file(filename)) 51 | audio_url = response.json()['upload_url'] 52 | bar.progress(30) 53 | 54 | json = {"audio_url": audio_url} 55 | transcript_response = requests.post('https://api.assemblyai.com/v2/transcript', json=json, headers=headers) 56 | transcript_id = transcript_response.json()["id"] 57 | bar.progress(50) 58 | 59 | endpoint = f"https://api.assemblyai.com/v2/transcript/{transcript_id}" 60 | status = 'processing' 61 | with st.spinner('Transcription is processing...'): 62 | while status != 'completed': 63 | response = requests.get(endpoint, headers=headers) 64 | status = response.json()['status'] 65 | 66 | bar.progress(100) 67 | return response.json()["text"], endpoint 68 | 69 | # Main transcription process 70 | try: 71 | filename = get_yt_audio(URL) 72 | transcript_text, transcript_endpoint = transcribe_yt(filename) 73 | 74 | st.subheader('Transcription Output') 75 | st.success(transcript_text) 76 | 77 | # Save the transcript in text and srt formats 78 | with open('yt.txt', 'w') as yt_txt: 79 | yt_txt.write(transcript_text) 80 | 81 | srt_response = requests.get(transcript_endpoint + "/srt", headers=headers) 82 | with open("yt.srt", "w") as srt_file: 83 | srt_file.write(srt_response.text) 84 | 85 | # Create a zip file of the transcripts 86 | with ZipFile('transcription.zip', 'w') as zip_file: 87 | zip_file.write('yt.txt') 88 | zip_file.write('yt.srt') 89 | 90 | # Download button for the zip file 91 | with open("transcription.zip", "rb") as zip_download: 92 | st.download_button("Download ZIP", zip_download, "transcription.zip", "application/zip") 93 | 94 | except Exception as e: 95 | st.error(f"An error occurred: {e}") 96 | 97 | if __name__ == '__main__': 98 | youtube_transcription() 99 | -------------------------------------------------------------------------------- /pages/5_MoM_Generator.py: -------------------------------------------------------------------------------- 1 | import streamlit as st 2 | import pandas as pd 3 | import requests 4 | import time 5 | import json 6 | 7 | # Constants 8 | AUTH_TOKEN = "3e10e0448d754962ac0491334562f21f" 9 | HEADERS = { 10 | "authorization": AUTH_TOKEN, 11 | "content-type": "application/json" 12 | } 13 | TRANSCRIPT_ENDPOINT = "https://api.assemblyai.com/v2/transcript" 14 | UPLOAD_ENDPOINT = 'https://api.assemblyai.com/v2/upload' 15 | 16 | def mom(): 17 | def upload_audio_to_assemblyai(audio_file): 18 | """Upload audio file to AssemblyAI and get the upload URL.""" 19 | try: 20 | response = requests.post(UPLOAD_ENDPOINT, headers=HEADERS, data=audio_file) 21 | response.raise_for_status() 22 | audio_url = response.json()['upload_url'] 23 | return audio_url 24 | except requests.exceptions.RequestException as e: 25 | st.error(f"Error uploading audio: {e}") 26 | return None 27 | 28 | def request_transcription(audio_url): 29 | """Request transcription from AssemblyAI.""" 30 | json_payload = { 31 | "audio_url": audio_url, 32 | "iab_categories": True, 33 | "auto_chapters": True, 34 | "speaker_labels": True # Enable speaker labels for detailed summary 35 | } 36 | try: 37 | response = requests.post(TRANSCRIPT_ENDPOINT, json=json_payload, headers=HEADERS) 38 | response.raise_for_status() 39 | transcript_id = response.json()['id'] 40 | return transcript_id 41 | except requests.exceptions.RequestException as e: 42 | st.error(f"Error requesting transcription: {e}") 43 | return None 44 | 45 | def poll_transcription_status(transcript_id): 46 | """Poll the transcription status until it's completed.""" 47 | polling_endpoint = f"{TRANSCRIPT_ENDPOINT}/{transcript_id}" 48 | while True: 49 | try: 50 | response = requests.get(polling_endpoint, headers=HEADERS) 51 | response.raise_for_status() 52 | status = response.json()['status'] 53 | if status == 'completed': 54 | return response.json() 55 | elif status == 'failed': 56 | st.error("Transcription failed.") 57 | return None 58 | time.sleep(5) 59 | except requests.exceptions.RequestException as e: 60 | st.error(f"Error polling transcription status: {e}") 61 | return None 62 | 63 | def convert_millis_to_time_format(millis): 64 | """Convert milliseconds to HH:MM:SS or MM:SS format.""" 65 | seconds = int((millis / 1000) % 60) 66 | minutes = int((millis / (1000 * 60)) % 60) 67 | hours = int((millis / (1000 * 60 * 60)) % 24) 68 | return f'{hours:02d}:{minutes:02d}:{seconds:02d}' if hours > 0 else f'{minutes:02d}:{seconds:02d}' 69 | 70 | def display_transcription_results(results): 71 | """Display the transcription results including themes, chapter summaries, and detailed transcript.""" 72 | st.subheader('Main Themes') 73 | with st.expander('Themes'): 74 | categories = results.get('iab_categories_result', {}).get('summary', []) 75 | for category in categories: 76 | st.markdown(f"* {category}") 77 | 78 | st.subheader('Summary Notes') 79 | chapters = results.get('chapters', []) 80 | chapters_df = pd.DataFrame(chapters) 81 | chapters_df['start_str'] = chapters_df['start'].apply(convert_millis_to_time_format) 82 | chapters_df['end_str'] = chapters_df['end'].apply(convert_millis_to_time_format) 83 | 84 | for _, row in chapters_df.iterrows(): 85 | with st.expander(row['gist']): 86 | st.write(row['summary']) 87 | st.button(row['start_str'], on_click=lambda start=row['start']: update_start(start)) 88 | 89 | st.subheader('Detailed Transcript') 90 | with st.expander('Transcript'): 91 | transcript = results.get('text', '') 92 | st.text_area('Transcript', value=transcript, height=300) 93 | st.download_button( 94 | label="Download Transcript", 95 | data=transcript, 96 | file_name="transcript.txt", 97 | mime="text/plain" 98 | ) 99 | 100 | def update_start(start): 101 | """Update the start point for audio playback.""" 102 | st.session_state['start_point'] = int(start / 1000) 103 | 104 | # Streamlit App Layout 105 | st.markdown('# **Automated Minutes of Meetings (MoM) Generator 📝**') 106 | st.caption("**Transform your meeting recordings into detailed, categorized summaries and downloadable transcripts effortlessly.**") 107 | 108 | # Initialize session state 109 | if 'start_point' not in st.session_state: 110 | st.session_state['start_point'] = 0 111 | 112 | # Sidebar for file upload 113 | 114 | st.sidebar.caption("""### :orange[Welcome to MoM Generator!]""") 115 | st.sidebar.caption("Transform your meeting recordings into detailed, categorized summaries and downloadable transcripts effortlessly.") 116 | 117 | st.sidebar.subheader('Input for Summarization below') 118 | uploaded_file = st.sidebar.file_uploader('Upload a file for summarization') 119 | 120 | st.sidebar.caption(""" 121 | ### How to Use 122 | 1. **Upload Your Audio File**: Simply upload your meeting audio recording. 123 | 2. **Generate Summaries**: The app will process the audio to create detailed minutes and summaries. 124 | 3. **Download Transcripts**: Get a downloadable transcript of your meeting for easy reference. 125 | 126 | ### Features 127 | - **Detailed Summaries**: Get comprehensive and categorized summaries of your meetings. 128 | - **Effortless Transcription**: Transform audio recordings into written transcripts quickly. 129 | - **Easy Downloads**: Download the meeting minutes and transcripts for future use. 130 | 131 | :rainbow[Streamline your meeting documentation with ease!] 132 | """) 133 | 134 | 135 | if uploaded_file is not None: 136 | st.audio(uploaded_file, start_time=st.session_state['start_point']) 137 | 138 | with st.spinner('Uploading audio...'): 139 | audio_url = upload_audio_to_assemblyai(uploaded_file) 140 | 141 | if audio_url: 142 | with st.spinner('Requesting transcription...'): 143 | transcript_id = request_transcription(audio_url) 144 | 145 | if transcript_id: 146 | with st.spinner('Transcribing...'): 147 | transcription_results = poll_transcription_status(transcript_id) 148 | 149 | if transcription_results: 150 | display_transcription_results(transcription_results) 151 | if __name__ == '__main__': 152 | mom() -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | langchain>=0.0.217 2 | duckduckgo-search 3 | streamlit-feedback 4 | assemblyai 5 | openai 6 | langchain_nvidia_ai_endpoints 7 | langchain_community 8 | faiss-cpu 9 | python-dotenv 10 | streamlit 11 | pypdf 12 | haystack 13 | assemblyai-haystack 14 | sentence-transformers 15 | huggingface_hub 16 | pytube 17 | requests 18 | PyPDF2==3.0.1 19 | reportlab 20 | fpdf -------------------------------------------------------------------------------- /utils.py: -------------------------------------------------------------------------------- 1 | # utils.py 2 | 3 | import os 4 | 5 | def convertMillis(start_ms): 6 | seconds = int((start_ms / 1000) % 60) 7 | minutes = int((start_ms / (1000 * 60)) % 60) 8 | hours = int((start_ms / (1000 * 60 * 60)) % 24) 9 | btn_txt = '' 10 | if hours > 0: 11 | btn_txt += f'{hours:02d}:{minutes:02d}:{seconds:02d}' 12 | else: 13 | btn_txt += f'{minutes:02d}:{seconds:02d}' 14 | return btn_txt 15 | 16 | def read_file(filename, chunk_size=5242880): 17 | with open(filename, 'rb') as _file: 18 | while True: 19 | data = _file.read(chunk_size) 20 | if not data: 21 | break 22 | yield data 23 | 24 | def save_chat_session(chat_history): 25 | import tempfile 26 | with tempfile.NamedTemporaryFile(delete=False, suffix=".txt") as temp_file: 27 | for message in chat_history: 28 | temp_file.write(message.content.encode("utf-8") + b"\n") 29 | return temp_file.name 30 | --------------------------------------------------------------------------------