import streamlit as st import os import base64 from io import BytesIO from PIL import Image import time # Import Modular components from backend.rag import RAGEngine from backend.parser import EnrichedRagParser import tempfile # ========================================== # 1. Page Configuration & Professional CSS # ========================================== st.set_page_config( page_title="Multimodal RAG Assistant", page_icon="๐ค", layout="wide", initial_sidebar_state="expanded" ) # Production-ready CSS st.markdown(""" """, unsafe_allow_html=True) # ========================================== # 2. Initialization & Helper Functions # ========================================== @st.cache_resource def initialize_rag_system(force_clean: bool = True): """Initialize the RAG system with caching.""" return RAGEngine(use_hybrid=True, force_clean=force_clean) def display_image_from_base64(base64_str: str, caption: str = "", width: int = 300): """Helper to decode and display base64 images.""" try: img_data = base64.b64decode(base64_str) img = Image.open(BytesIO(img_data)) st.image(img, caption=caption, width=width) except Exception as e: st.error(f"Failed to display image: {e}") # ========================================== # 3. Main Application # ========================================== def main(): # --- State Management --- if "messages" not in st.session_state: st.session_state.messages = [] if "suggested_questions" not in st.session_state: st.session_state.suggested_questions = [] # Initialize Backend if "rag" not in st.session_state: with st.spinner("๐ Booting up AI System..."): st.session_state.rag = initialize_rag_system() rag: RAGEngine = st.session_state.rag # ========================================== # SIDEBAR: Control Panel # ========================================== with st.sidebar: st.header("๐ง RAG Control Panel") # --- PDF Document Upload --- with st.expander("๐ Knowledge Base", expanded=True): uploaded_file = st.file_uploader( "Upload Document (PDF)", type=["pdf"], label_visibility="collapsed" ) if uploaded_file: # Temporary save for parsing # temp_dir = "/tmp" # os.makedirs(temp_dir, exist_ok=True) # save_path = os.path.join(temp_dir, uploaded_file.name) # with open(save_path, "wb") as f: # f.write(uploaded_file.getbuffer()) with tempfile.NamedTemporaryFile(delete=False) as tmp: tmp.write(uploaded_file.read()) file_path = tmp.name if st.button("๐ Process PDF", type="primary", use_container_width=True): try: with st.spinner("Analyzing PDF with Docling..."): parser = EnrichedRagParser() parsed_data = parser.process_document(file_path) with st.spinner("Ingesting into MongoDB..."): rag.ingest_data(parsed_data) # Generate Suggestions suggestions = rag.generate_suggested_questions(num_questions=6) st.session_state.suggested_questions = suggestions st.success(f"Processed: {uploaded_file.name}") st.rerun() except Exception as e: st.error(f"โ Error: {str(e)}") finally: # # โ Always cleanup temp file # if os.path.exists(file_path): # os.remove(file_path) print("๐งน Temp file deleted") st.rerun() st.markdown("---") # --- Suggested Questions --- if st.session_state.suggested_questions: st.subheader("๐ก Quick Questions") for idx, q in enumerate(st.session_state.suggested_questions): if st.button(q, key=f"sugg_{idx}", use_container_width=True): st.session_state.messages.append({"role": "user", "content": q}) st.rerun() st.markdown("---") # --- Settings --- with st.expander("โ๏ธ Search Settings"): top_k = st.slider("Max Results", 1, 10, 5) min_score = st.slider("Confidence Threshold", 0.0, 1.0, 0.6) use_images = st.toggle("Enable Image Search", value=True) # --- System Stats --- count = rag.collection.count_documents({}) st.markdown( f"""
Upload a PDF in the sidebar to start.