| import streamlit as st |
| import requests |
| import json |
| import uuid |
| from datetime import datetime |
| from typing import Optional, List, Dict |
| import os |
|
|
| |
| st.set_page_config( |
| page_title="RAG Document Assistant", |
| page_icon="π", |
| layout="wide" |
| ) |
|
|
| |
| API_BASE_URL = "https://ajoy0071998-multilingual-rag.hf.space" |
|
|
| |
| def init_session_state(): |
| if "token" not in st.session_state: |
| st.session_state.token = None |
| if "user" not in st.session_state: |
| st.session_state.user = None |
| if "documents" not in st.session_state: |
| st.session_state.documents = [] |
| if "conversation_id" not in st.session_state: |
| st.session_state.conversation_id = None |
| if "messages" not in st.session_state: |
| st.session_state.messages = [] |
| if "current_doc_ids" not in st.session_state: |
| st.session_state.current_doc_ids = [] |
| if "selected_docs" not in st.session_state: |
| st.session_state.selected_docs = [] |
|
|
| |
| def api_request(method: str, endpoint: str, data: Optional[Dict] = None, files: Optional[Dict] = None): |
| """Make API requests with authentication""" |
| headers = {} |
| if st.session_state.token: |
| headers["Authorization"] = f"Bearer {st.session_state.token}" |
| |
| url = f"{API_BASE_URL}{endpoint}" |
| |
| try: |
| if method == "GET": |
| response = requests.get(url, headers=headers) |
| elif method == "POST": |
| if files: |
| response = requests.post(url, headers=headers, files=files, data=data) |
| else: |
| response = requests.post(url, headers=headers, json=data) |
| elif method == "DELETE": |
| response = requests.delete(url, headers=headers) |
| else: |
| return None |
| |
| return response |
| except requests.exceptions.ConnectionError: |
| st.error("β Cannot connect to server. Please make sure the server is running.") |
| return None |
|
|
| def login(email: str, password: str): |
| """Login user and get token""" |
| response = api_request("POST", "/auth/login", {"email": email, "password": password}) |
| if response and response.status_code == 200: |
| data = response.json() |
| st.session_state.token = data["access_token"] |
| return True |
| return False |
|
|
| def register_user(username: str, email: str, password: str): |
| """Register new user""" |
| response = api_request("POST", "/auth/register", { |
| "username": username, |
| "email": email, |
| "password": password |
| }) |
| return response and response.status_code == 200 |
|
|
| def get_user_info(): |
| """Get current user info""" |
| response = api_request("GET", "/auth/me") |
| if response and response.status_code == 200: |
| return response.json() |
| return None |
|
|
| def get_user_documents(): |
| """Get user's documents""" |
| response = api_request("GET", "/api/v1/documents/") |
| if response and response.status_code == 200: |
| data = response.json() |
| return data.get("documents", []) |
| return [] |
|
|
| def upload_document(file): |
| """Upload a document""" |
| files = {"file": file} |
| response = api_request("POST", "/api/v1/rag/ingest", files=files) |
| if response and response.status_code == 200: |
| return response.json() |
| return None |
|
|
| def delete_document(document_id: str): |
| """Delete a document""" |
| response = api_request("DELETE", f"/api/v1/documents/{document_id}") |
| return response and response.status_code == 200 |
|
|
| def send_query(query: str, doc_ids: List[str], conversation_id: Optional[str] = None): |
| """Send a query to the RAG system""" |
| data = { |
| "query": query, |
| "doc_ids": doc_ids, |
| "conversation_id": conversation_id |
| } |
| response = api_request("POST", "/api/v1/rag/response", data) |
| if response and response.status_code == 200: |
| return response.json() |
| return None |
|
|
| |
| def show_login_page(): |
| st.title("π RAG Document Assistant") |
| st.subheader("Login or Register") |
| |
| tab1, tab2 = st.tabs(["Login", "Register"]) |
| |
| with tab1: |
| with st.form("login_form"): |
| email = st.text_input("Email") |
| password = st.text_input("Password", type="password") |
| submitted = st.form_submit_button("Login") |
| |
| if submitted: |
| if email and password: |
| with st.spinner("Logging in..."): |
| if login(email, password): |
| user_info = get_user_info() |
| if user_info: |
| st.session_state.user = user_info |
| st.rerun() |
| else: |
| st.error("Invalid email or password") |
| else: |
| st.warning("Please fill all fields") |
| |
| with tab2: |
| with st.form("register_form"): |
| username = st.text_input("Username") |
| email = st.text_input("Email") |
| password = st.text_input("Password", type="password") |
| confirm_password = st.text_input("Confirm Password", type="password") |
| submitted = st.form_submit_button("Register") |
| |
| if submitted: |
| if username and email and password and confirm_password: |
| if password != confirm_password: |
| st.error("Passwords do not match") |
| else: |
| with st.spinner("Registering..."): |
| if register_user(username, email, password): |
| st.success("Registration successful! Please login.") |
| else: |
| st.error("Registration failed. User might already exist.") |
| else: |
| st.warning("Please fill all fields") |
|
|
| |
| def main(): |
| init_session_state() |
| |
| |
| if not st.session_state.token: |
| show_login_page() |
| return |
| |
| |
| if not st.session_state.user: |
| user_info = get_user_info() |
| if user_info: |
| st.session_state.user = user_info |
| else: |
| |
| st.session_state.token = None |
| st.rerun() |
| |
| |
| with st.sidebar: |
| st.header(f"π€ {st.session_state.user.get('username', 'User')}") |
| st.caption(f"π§ {st.session_state.user.get('email', '')}") |
| |
| st.divider() |
| |
| |
| st.subheader("π€ Upload Document") |
| uploaded_file = st.file_uploader( |
| "Choose a file", |
| type=["pdf", "doc", "docx"], |
| help="Supported formats: PDF, DOC, DOCX" |
| ) |
| |
| if uploaded_file: |
| if st.button("Upload", type="primary", use_container_width=True): |
| with st.spinner("Uploading document..."): |
| result = upload_document(uploaded_file) |
| if result: |
| st.success("Document uploaded successfully!") |
| st.session_state.documents = get_user_documents() |
| st.rerun() |
| else: |
| st.error("Failed to upload document") |
| |
| st.divider() |
| |
| |
| st.subheader("π Your Documents") |
| |
| |
| if st.button("π Refresh List", use_container_width=True): |
| st.session_state.documents = get_user_documents() |
| st.rerun() |
| |
| |
| if not st.session_state.documents: |
| st.session_state.documents = get_user_documents() |
| |
| if st.session_state.documents: |
| for doc in st.session_state.documents: |
| col1, col2 = st.columns([4, 1]) |
| with col1: |
| |
| doc_id = str(doc["id"]) |
| is_selected = doc_id in st.session_state.selected_docs |
| if st.checkbox( |
| f"π {doc['file_name']}", |
| value=is_selected, |
| key=f"doc_{doc_id}" |
| ): |
| if doc_id not in st.session_state.selected_docs: |
| st.session_state.selected_docs.append(doc_id) |
| else: |
| if doc_id in st.session_state.selected_docs: |
| st.session_state.selected_docs.remove(doc_id) |
| |
| with col2: |
| |
| if st.button("ποΈ", key=f"del_{doc_id}", help="Delete document"): |
| if delete_document(doc_id): |
| st.success(f"Deleted {doc['file_name']}") |
| st.session_state.documents = get_user_documents() |
| if doc_id in st.session_state.selected_docs: |
| st.session_state.selected_docs.remove(doc_id) |
| st.rerun() |
| else: |
| st.error("Failed to delete document") |
| |
| |
| with st.expander(f"βΉοΈ Details - {doc['file_name']}"): |
| st.caption(f"π Size: {doc['file_size'] / 1024:.1f} KB") |
| st.caption(f"π Chunks: {doc.get('chunks', 0)}") |
| st.caption(f"π Language: {doc.get('primary_language', 'unknown')}") |
| st.caption(f"π
Uploaded: {doc.get('created_at', '')[:10]}") |
| else: |
| st.info("No documents uploaded yet") |
| |
| st.divider() |
| |
| |
| if st.button("πͺ Logout", use_container_width=True): |
| st.session_state.clear() |
| st.rerun() |
| |
| |
| |
| col1, col2, col3 = st.columns([2, 2, 1]) |
| with col1: |
| st.title("π¬ RAG Chat") |
| with col2: |
| if st.session_state.conversation_id: |
| st.info(f"Conversation: {st.session_state.conversation_id[:8]}...") |
| with col3: |
| if st.button("π New Conversation", use_container_width=True): |
| st.session_state.messages = [] |
| st.session_state.conversation_id = None |
| st.rerun() |
| |
| |
| if st.session_state.selected_docs: |
| selected_count = len(st.session_state.selected_docs) |
| st.info(f"π Querying across {selected_count} selected document(s)") |
| else: |
| st.warning("β οΈ Please select at least one document to query") |
| |
| st.divider() |
| |
| |
| chat_container = st.container() |
| with chat_container: |
| for message in st.session_state.messages: |
| with st.chat_message(message["role"]): |
| st.markdown(message["content"]) |
| if "timestamp" in message: |
| st.caption(message["timestamp"]) |
| |
| |
| if st.session_state.selected_docs: |
| user_input = st.chat_input("Ask a question about your documents...") |
| |
| if user_input: |
| |
| st.session_state.messages.append({ |
| "role": "user", |
| "content": user_input, |
| "timestamp": datetime.now().strftime("%H:%M") |
| }) |
| |
| |
| with st.chat_message("user"): |
| st.markdown(user_input) |
| |
| |
| with st.chat_message("assistant"): |
| with st.spinner("Thinking..."): |
| response = send_query( |
| query=user_input, |
| doc_ids=st.session_state.selected_docs, |
| conversation_id=st.session_state.conversation_id |
| ) |
| |
| if response: |
| |
| if "conversation_id" in response: |
| st.session_state.conversation_id = response["conversation_id"] |
| |
| |
| st.markdown(response["answer"]) |
| |
| |
| st.session_state.messages.append({ |
| "role": "assistant", |
| "content": response["answer"], |
| "timestamp": datetime.now().strftime("%H:%M") |
| }) |
| else: |
| st.error("Failed to get response. Please check if the server is running.") |
| else: |
| st.info("π Select documents from the sidebar to start asking questions") |
|
|
| if __name__ == "__main__": |
| main() |