# ---- Standard libs ---- import os, tempfile, shutil, uuid from pathlib import Path from datetime import datetime import streamlit as st from dotenv import load_dotenv # ---- LangChain stack ---- from langchain_groq import ChatGroq from langchain_community.embeddings import HuggingFaceEmbeddings from langchain_community.vectorstores import Chroma from langchain.chains import RetrievalQA from langchain_community.document_loaders import UnstructuredFileLoader from langchain.text_splitter import RecursiveCharacterTextSplitter # ---- Load .env ---- load_dotenv() # ---- Session Management ---- if "session_id" not in st.session_state: st.session_state.session_id = str(uuid.uuid4()) def cleanup_session_data(): session_path = Path(f"./rag_db/{st.session_state.session_id}") if session_path.exists(): try: shutil.rmtree(session_path) except Exception as e: print(f"⚠️ Could not delete {session_path}: {e}") if "cleaned_up" not in st.session_state: cleanup_session_data() st.session_state["cleaned_up"] = True # ---- Initialize RAG Chain ---- @st.cache_resource(show_spinner=False) def init_rag_chain(): embedding = HuggingFaceEmbeddings(model_name="all-MiniLM-L6-v2") vectordb = Chroma( persist_directory=f"./rag_db/{st.session_state.session_id}", embedding_function=embedding ) llm = ChatGroq( groq_api_key=os.getenv("GROQ_API_KEY"), model="llama3-70b-8192", temperature=0.2, ) return RetrievalQA.from_chain_type( llm=llm, retriever=vectordb.as_retriever(search_kwargs={"k": 4}), return_source_documents=False ) qa_chain = init_rag_chain() def ingest_pdf(file_bytes: bytes, file_name: str): embedding = HuggingFaceEmbeddings(model_name="all-MiniLM-L6-v2") vectordb = Chroma( persist_directory=f"./rag_db/{st.session_state.session_id}", embedding_function=embedding ) with tempfile.NamedTemporaryFile(delete=False, suffix=".pdf") as tmp: tmp.write(file_bytes) tmp_path = tmp.name docs = UnstructuredFileLoader(tmp_path).load() splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200) chunks = splitter.split_documents(docs) if chunks: vectordb.add_documents(chunks) vectordb.persist() # ---- Streamlit Config ---- st.set_page_config( page_title="📄 Multimodal Chat Assistant", page_icon="🤖", layout="wide", initial_sidebar_state="expanded" ) # ---- Custom CSS ---- st.markdown(""" """, unsafe_allow_html=True) # ---- Sidebar ---- with st.sidebar: st.markdown("
", unsafe_allow_html=True) st.title("🤖 RAG Assistant") st.write("• Upload a PDF 📄") st.write("• Ask context-specific questions 💬") st.write("• Powered by **LLaMA 3 + Groq** ⚡") st.markdown("---") if st.button("🗑️ Clear Chat", use_container_width=True): cleanup_session_data() st.session_state.chat_history = [] st.rerun() # ---- Title ---- st.markdown("