# app.py import os import sqlite3 import tempfile import traceback from pathlib import Path from datetime import datetime import streamlit as st from langchain_community.document_loaders import PyPDFLoader # Add this import from components.chat import display_chat_interface, ensure_embeddings_initialized from utils.database import ( display_vector_store_info, handle_document_upload, create_connection, create_tables, insert_document # Make sure this is imported ) from utils.persistence import PersistenceManager from utils.document_chunker import DocumentChunker from backend import get_embeddings_model, initialize_qa_system, initialize_faiss import time def initialize_database(): """Initialize database connection and tables.""" try: if 'db_conn' not in st.session_state: data_dir = "data" if not os.path.exists(data_dir): os.makedirs(data_dir) db_path = os.path.join(data_dir, 'rfp_analysis.db') try: with open(db_path, 'a') as f: pass except IOError as e: return False conn = create_connection(db_path) if conn is not None: create_tables(conn) st.session_state.db_conn = conn return True else: return False else: return True except Exception: return False def initialize_embeddings(): """Initialize the embeddings model.""" try: if 'embeddings' not in st.session_state: with st.spinner("Initializing embeddings model..."): embeddings = get_embeddings_model() if embeddings is not None: st.session_state.embeddings = embeddings return True else: st.error("Failed to initialize embeddings model.") return False return True except Exception as e: st.error(f"Error initializing embeddings: {str(e)}") return False def display_header(): """Display application header with logo.""" header_col1, header_col2 = st.columns([1, 4]) with header_col1: if os.path.exists("img/logo.png"): st.image("img/logo.png", width=100) else: st.error("Logo not found at img/logo.png") with header_col2: st.title("Synaptyx.AI - RFP Analysis Agent") def display_example_questions(): """Return a list of example questions for RFP analysis.""" return [ "📊 Summarize the main points of the document", "📝 Draft a 'Why Us' section based on the document", "🎯 Extract key success metrics and outcomes", "💡 What are the innovative solutions mentioned?", "🤝 Analyze the partnership benefits described", "📈 What are the key performance requirements?", "💰 Extract budget and pricing information", "📅 What are the important deadlines and milestones?", "⚡ Identify the technical requirements", "🔍 What are the evaluation criteria?" ] def handle_document_upload(uploaded_files, persistence): """Handle document upload and processing.""" try: # Initialize progress indicators progress = st.progress(0) status = st.empty() # Initialize document chunker chunker = DocumentChunker( chunk_size=1000, chunk_overlap=200, max_tokens_per_chunk=2000 ) # Process each document progress_increment = 100 / len(uploaded_files) current_progress = 0 document_pairs = [] for idx, file in enumerate(uploaded_files): status.text(f"Processing document {idx + 1}/{len(uploaded_files)}: {file.name}") # Create temporary file with tempfile.NamedTemporaryFile(delete=False, suffix='.pdf') as tmp_file: tmp_file.write(file.getvalue()) tmp_file.flush() # Load and process document loader = PyPDFLoader(tmp_file.name) pages = loader.load() content = "\n".join(page.page_content for page in pages) # Store in database doc_id = insert_document(st.session_state.db_conn, file.name, content) if not doc_id: raise Exception(f"Failed to store document: {file.name}") document_pairs.append((content, file.name)) # Clean up temp file os.unlink(tmp_file.name) current_progress += progress_increment progress.progress(int(current_progress)) # Process documents with chunker status.text("Chunking documents...") chunks, chunk_metadatas = chunker.process_documents(document_pairs) # Generate session ID session_id = f"session_{datetime.now().strftime('%Y%m%d_%H%M%S')}" # Save chunks persistence.save_chunks(chunks, chunk_metadatas, session_id) # Initialize vector store status.text("Creating vector embeddings...") vector_store = initialize_faiss(st.session_state.embeddings, chunks, chunk_metadatas) if not vector_store: raise Exception("Failed to initialize vector store") # Save vector store persistence.save_vector_store(vector_store, session_id) # Initialize QA system status.text("Setting up QA system...") qa_system = initialize_qa_system(vector_store) if not qa_system: raise Exception("Failed to initialize QA system") # Update session state st.session_state.vector_store = vector_store st.session_state.qa_system = qa_system st.session_state.current_session_id = session_id progress.progress(100) status.empty() return True except Exception as e: st.error(f"Error processing documents: {str(e)}") return False def main(): # Set up the page configuration st.set_page_config(layout="wide", page_title="SYNAPTYX - RFP Analysis Agent") # Custom CSS for logo positioning st.markdown(""" """, unsafe_allow_html=True) # Initialize database and embeddings if not initialize_database(): st.error("Failed to initialize database. Please contact support.") return if not initialize_embeddings(): st.error("Failed to initialize embeddings model. Please try refreshing the page.") return # Initialize session state for UI control if 'chat_ready' not in st.session_state: st.session_state.chat_ready = False # Sidebar for document management with st.sidebar: st.title("📚 Document Manager") # Upload Section st.header("Upload Documents", anchor=False) uploaded_files = st.file_uploader( "Upload PDF documents", type=['pdf'], accept_multiple_files=True, help="Limit 200MB per file • PDF" ) # Process uploads if uploaded_files: if 'processed_files' not in st.session_state or uploaded_files != st.session_state.processed_files: try: with st.spinner("Processing documents..."): # Initialize components first if 'persistence' not in st.session_state: st.session_state.persistence = PersistenceManager() # Process documents success = handle_document_upload( uploaded_files=uploaded_files, persistence=st.session_state.persistence # Pass persistence manager as parameter ) if success: st.session_state.processed_files = uploaded_files st.session_state.chat_ready = True st.success("Documents processed successfully!") time.sleep(1) st.rerun() else: st.error("Failed to process documents. Please try again.") except Exception as e: st.error(f"Error during document processing: {str(e)}") st.error(traceback.format_exc()) # Knowledge Base Status if st.session_state.get('vector_store'): st.success("✅ Documents ready for analysis") display_vector_store_info() # Document List if uploaded_files: st.subheader("📑 Uploaded Documents") for doc in uploaded_files: st.write(f"• {doc.name}") # Main chat area if not st.session_state.chat_ready: # Welcome screen st.title("🤖 SYNAPTYX - RFP Analysis Agent") st.markdown("### Welcome to your AI-powered RFP analysis assistant!") col1, col2 = st.columns(2) with col1: st.markdown(""" #### Getting Started: 1. Upload your RFP documents using the sidebar 2. Wait for the processing to complete 3. Start chatting with your documents! """) with col2: st.markdown("#### Example Questions You Can Ask:") examples = display_example_questions() for example in examples: st.markdown(f"{example}") else: # Clean chat interface display_chat_interface() if __name__ == "__main__": main()