Spaces:
Sleeping
Sleeping
File size: 7,086 Bytes
666da3c 05e4803 666da3c 42cfc50 666da3c e9b0b1d 666da3c bc7f431 666da3c 9a28e83 05e4803 42cfc50 1e8a63b 05e4803 42cfc50 1e8a63b 05e4803 1e8a63b 42cfc50 9a28e83 1e8a63b 05e4803 42cfc50 9a28e83 e20f745 9a28e83 fa5ac5b c46ef81 05e4803 c46ef81 9a28e83 4107262 fa5ac5b 9a28e83 4107262 4a85256 4107262 05e4803 9496c54 63de6bf 9496c54 05e4803 e20f745 618bbac e20f745 618bbac e20f745 05e4803 e20f745 8383ea4 e20f745 8383ea4 e20f745 5b0dcf0 05e4803 e20f745 05e4803 8383ea4 e20f745 8383ea4 618bbac 52d7c28 e20f745 05e4803 8383ea4 e20f745 8383ea4 618bbac 52d7c28 e20f745 52d7c28 e20f745 da2b4bd 8383ea4 52d7c28 da2b4bd 05e4803 618bbac 52d7c28 8383ea4 e20f745 52d7c28 da2b4bd 52d7c28 da2b4bd 05e4803 52d7c28 5b0dcf0 618bbac 5b0dcf0 05e4803 e20f745 05e4803 e20f745 9cee69c 5b0dcf0 e20f745 9cee69c 05e4803 2dd7c87 1e8a63b 05e4803 9cee69c 5b0dcf0 05e4803 4a85256 05e4803 a603dd8 05e4803 52d7c28 e20f745 05e4803 9cee69c 05e4803 da2b4bd 52d7c28 05e4803 9cee69c 52d7c28 05e4803 52d7c28 05e4803 9cee69c 4a85256 e20f745 52d7c28 9cee69c 52d7c28 9cee69c 05e4803 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 | # ---- 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("""
<style>
.block-container {
padding-top: 2rem;
padding-bottom: 2rem;
max-width: 800px;
margin: auto;
}
.title {
font-size: 3rem;
font-weight: bold;
color: #4A90E2;
text-align: center;
margin-bottom: 1.5rem;
}
.main-container {
max-width: 800px;
margin: 0 auto;
padding: 1rem;
}
.chat-history {
max-height: 450px;
overflow-y: auto;
background-color: #F9F9F9;
border-radius: 12px;
padding: 1rem;
border: 1px solid #DDD;
margin-bottom: 1rem;
min-height: 100px;
}
.message-user {
background-color: #DDF3FF;
color: #000;
padding: 0.8rem;
border-radius: 12px;
margin-bottom: 0.5rem;
text-align: left;
word-wrap: break-word;
}
.message-bot {
background-color: #E3FFE1;
color: #000;
padding: 0.8rem;
border-radius: 12px;
margin-bottom: 0.5rem;
text-align: left;
word-wrap: break-word;
}
.stTextInput > div > div > input {
font-size: 1rem;
padding: 0.75rem;
border-radius: 8px;
border: 1px solid #DDD;
height: 48px;
min-height: 48px;
}
.stButton > button {
border-radius: 8px;
background-color: #4A90E2;
color: white;
border: none;
padding: 0.75rem 1rem;
font-weight: bold;
width: 100%;
height: 48px;
min-height: 48px;
}
.stButton > button:hover {
background-color: #357ABD;
}
.stFileUploader > div {
padding: 1rem;
border: 2px dashed #4A90E2;
border-radius: 8px;
text-align: center;
margin-bottom: 1rem;
}
.sidebar-logo {
text-align: center;
margin-bottom: 1rem;
}
.input-row {
display: flex;
gap: 0.5rem;
align-items: end;
margin-top: 1rem;
}
.empty-chat {
text-align: center;
color: #888;
font-style: italic;
padding: 1rem;
}
</style>
""", unsafe_allow_html=True)
# ---- Sidebar ----
with st.sidebar:
st.markdown("<div class='sidebar-logo'><img src='https://cdn-icons-png.flaticon.com/512/4712/4712027.png' width='100'></div>", 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("<div class='title'>π Multimodal Chat Assistant</div>", unsafe_allow_html=True)
# ---- Main container ----
st.markdown("<div class='main-container'>", unsafe_allow_html=True)
# Upload UI
uploaded_file = st.file_uploader("π€ Upload a PDF file", type=["pdf"])
if uploaded_file:
with st.spinner("π Ingesting document..."):
ingest_pdf(uploaded_file.read(), uploaded_file.name)
st.success("β
Document ingested successfully! You can now ask questions.")
# Initialize chat history
if "chat_history" not in st.session_state:
st.session_state.chat_history = []
# Chat history display
if st.session_state.chat_history:
st.markdown("<div class='chat-history'>", unsafe_allow_html=True)
for msg in st.session_state.chat_history:
if msg["role"] == "user":
st.markdown(f"<div class='message-user'><b>π§ You:</b> {msg['content']}</div>", unsafe_allow_html=True)
else:
st.markdown(f"<div class='message-bot'><b>π€ Assistant:</b> {msg['content']}</div>", unsafe_allow_html=True)
st.markdown("</div>", unsafe_allow_html=True)
# Input & button
col1, col2 = st.columns([5, 1])
with col1:
prompt = st.text_input("π¬ Type your question", placeholder="Ask about your PDF...", label_visibility="collapsed")
with col2:
send_clicked = st.button("Send β‘οΈ", use_container_width=True)
# Response handling
if (prompt and send_clicked) or (prompt and st.session_state.get('last_prompt', '') != prompt):
if prompt.strip():
st.session_state.chat_history.append({"role": "user", "content": prompt})
with st.spinner("π€ Thinking..."):
try:
response = qa_chain.run(prompt)
st.session_state.chat_history.append({"role": "assistant", "content": response})
except Exception as e:
error_msg = f"Sorry, I encountered an error: {str(e)}"
st.session_state.chat_history.append({"role": "assistant", "content": error_msg})
st.session_state.last_prompt = prompt
st.rerun()
st.markdown("</div>", unsafe_allow_html=True)
|