Spaces:
Runtime error
Runtime error
| """Chat interface UI component and logic.""" | |
| import gradio as gr | |
| import logging | |
| from src.core.logging_config import get_logger | |
| from src.rag import rag_chat_service | |
| from src.services.data_clearing_service import data_clearing_service | |
| logger = get_logger(__name__) | |
| def handle_chat_message(message, history): | |
| """Handle a new chat message with streaming response.""" | |
| if not message or not message.strip(): | |
| return "", history, gr.update() | |
| try: | |
| # Add user message to history | |
| history = history or [] | |
| history.append({"role": "user", "content": message}) | |
| # Add assistant message placeholder | |
| history.append({"role": "assistant", "content": ""}) | |
| # Get response from RAG service | |
| response_text = "" | |
| for chunk in rag_chat_service.chat_stream(message): | |
| response_text += chunk | |
| # Update the last message in history with the current response | |
| history[-1]["content"] = response_text | |
| # Update status in real-time during streaming | |
| updated_status = get_chat_status() | |
| yield "", history, updated_status | |
| logger.info(f"Chat response completed for message: {message[:50]}...") | |
| # Final status update after message completion | |
| final_status = get_chat_status() | |
| yield "", history, final_status | |
| except Exception as e: | |
| error_msg = f"Error generating response: {str(e)}" | |
| logger.error(error_msg) | |
| if history and len(history) > 0: | |
| history[-1]["content"] = f"β {error_msg}" | |
| else: | |
| history = [ | |
| {"role": "user", "content": message}, | |
| {"role": "assistant", "content": f"β {error_msg}"} | |
| ] | |
| # Update status even on error | |
| error_status = get_chat_status() | |
| yield "", history, error_status | |
| def start_new_chat_session(): | |
| """Start a new chat session.""" | |
| try: | |
| session_id = rag_chat_service.start_new_session() | |
| logger.info(f"Started new chat session: {session_id}") | |
| return [], f"β New chat session started: {session_id}" | |
| except Exception as e: | |
| error_msg = f"Error starting new session: {str(e)}" | |
| logger.error(error_msg) | |
| return [], f"β {error_msg}" | |
| def handle_clear_all_data(): | |
| """Handle clearing all RAG data (vector store + chat history).""" | |
| try: | |
| # Clear all data using the data clearing service | |
| success, message, stats = data_clearing_service.clear_all_data() | |
| if success: | |
| # Reset chat session after clearing data | |
| session_id = rag_chat_service.start_new_session() | |
| # Get updated status | |
| updated_status = get_chat_status() | |
| # Create success message with stats | |
| if stats.get("total_cleared_documents", 0) > 0 or stats.get("total_cleared_files", 0) > 0: | |
| clear_msg = f"β {message}" | |
| session_msg = f"π Started new session: {session_id}" | |
| combined_msg = f'{clear_msg}<br/><div class="session-info">{session_msg}</div>' | |
| else: | |
| combined_msg = f'βΉοΈ {message}<br/><div class="session-info">π Started new session: {session_id}</div>' | |
| logger.info(f"Data cleared successfully: {message}") | |
| return [], combined_msg, updated_status | |
| else: | |
| error_msg = f"β {message}" | |
| logger.error(f"Data clearing failed: {message}") | |
| # Still get updated status even on error | |
| updated_status = get_chat_status() | |
| return None, f'<div class="session-info">{error_msg}</div>', updated_status | |
| except Exception as e: | |
| error_msg = f"Error clearing data: {str(e)}" | |
| logger.error(error_msg) | |
| # Get current status | |
| current_status = get_chat_status() | |
| return None, f'<div class="session-info">β {error_msg}</div>', current_status | |
| def get_chat_status(): | |
| """Get current chat system status.""" | |
| try: | |
| # Check ingestion status | |
| from src.rag import document_ingestion_service | |
| from src.services.data_clearing_service import data_clearing_service | |
| ingestion_status = document_ingestion_service.get_ingestion_status() | |
| # Check usage stats | |
| usage_stats = rag_chat_service.get_usage_stats() | |
| # Get data status for additional context | |
| data_status = data_clearing_service.get_data_status() | |
| # Get environment info | |
| import os | |
| env_type = "Hugging Face Space" if os.getenv("SPACE_ID") else "Local Development" | |
| # Modern status card design with better styling | |
| status_html = f""" | |
| <div class="status-card"> | |
| <div class="status-header"> | |
| <h3>π¬ Chat System Status</h3> | |
| <div class="status-indicator {'status-ready' if ingestion_status.get('system_ready', False) else 'status-not-ready'}"> | |
| {'π’ READY' if ingestion_status.get('system_ready', False) else 'π΄ NOT READY'} | |
| </div> | |
| </div> | |
| <div class="status-grid"> | |
| <div class="status-item"> | |
| <div class="status-label">Vector Store Docs</div> | |
| <div class="status-value">{data_status.get('vector_store', {}).get('document_count', 0)}</div> | |
| </div> | |
| <div class="status-item"> | |
| <div class="status-label">Chat History Files</div> | |
| <div class="status-value">{data_status.get('chat_history', {}).get('file_count', 0)}</div> | |
| </div> | |
| <div class="status-item"> | |
| <div class="status-label">Session Usage</div> | |
| <div class="status-value">{usage_stats.get('session_messages', 0)}/{usage_stats.get('session_limit', 50)}</div> | |
| </div> | |
| <div class="status-item"> | |
| <div class="status-label">Environment</div> | |
| <div class="status-value">{'HF Space' if data_status.get('environment') == 'hf_space' else 'Local'}</div> | |
| </div> | |
| </div> | |
| <div class="status-services"> | |
| <div class="service-status {'service-ready' if ingestion_status.get('embedding_model_available', False) else 'service-error'}"> | |
| <span class="service-icon">π§ </span> | |
| <span>Embedding Model</span> | |
| <span class="service-indicator">{'β ' if ingestion_status.get('embedding_model_available', False) else 'β'}</span> | |
| </div> | |
| <div class="service-status {'service-ready' if ingestion_status.get('vector_store_available', False) else 'service-error'}"> | |
| <span class="service-icon">ποΈ</span> | |
| <span>Vector Store</span> | |
| <span class="service-indicator">{'β ' if ingestion_status.get('vector_store_available', False) else 'β'}</span> | |
| </div> | |
| </div> | |
| </div> | |
| """ | |
| return status_html | |
| except Exception as e: | |
| error_msg = f"Error getting chat status: {str(e)}" | |
| logger.error(error_msg) | |
| return f""" | |
| <div class="status-card status-error"> | |
| <div class="status-header"> | |
| <h3>β System Error</h3> | |
| </div> | |
| <p class="error-message">{error_msg}</p> | |
| </div> | |
| """ | |
| def create_chat_interface_tab(): | |
| """Create the chat interface tab UI.""" | |
| with gr.TabItem("π¬ Chat with Documents"): | |
| with gr.Column(elem_classes=["chat-tab-container"]): | |
| # Header | |
| gr.HTML(""" | |
| <div class="chat-header"> | |
| <h2>π¬ Chat with your converted documents</h2> | |
| <p>Ask questions about your documents using advanced RAG technology</p> | |
| </div> | |
| """) | |
| # Status monitoring | |
| status_display = gr.HTML(value=get_chat_status()) | |
| # Control buttons | |
| with gr.Row(elem_classes=["control-buttons"]): | |
| refresh_btn = gr.Button("π Refresh Status", elem_classes=["control-btn", "btn-refresh"]) | |
| new_session_btn = gr.Button("π New Session", elem_classes=["control-btn", "btn-new-session"]) | |
| clear_data_btn = gr.Button("ποΈ Clear All Data", elem_classes=["control-btn", "btn-clear-data"], variant="stop") | |
| # Chat interface | |
| with gr.Column(elem_classes=["chat-main-container"]): | |
| chatbot = gr.Chatbot( | |
| elem_classes=["chat-container"], | |
| height=500, | |
| show_label=False, | |
| show_share_button=False, | |
| bubble_full_width=False, | |
| type="messages", | |
| placeholder="Start a conversation by asking questions about your documents..." | |
| ) | |
| with gr.Row(elem_classes=["input-row"]): | |
| msg_input = gr.Textbox( | |
| placeholder="Ask questions about your documents...", | |
| show_label=False, | |
| scale=5, | |
| lines=1, | |
| max_lines=3, | |
| elem_classes=["message-input"] | |
| ) | |
| send_btn = gr.Button("Submit", elem_classes=["send-button"], scale=0) | |
| # Session info display | |
| session_info = gr.HTML( | |
| value='<div class="session-info">No active session - Click "New Session" to start</div>' | |
| ) | |
| # Event handlers for chat | |
| def clear_input(): | |
| return "" | |
| # Send message when button clicked or Enter pressed | |
| msg_input.submit( | |
| fn=handle_chat_message, | |
| inputs=[msg_input, chatbot], | |
| outputs=[msg_input, chatbot, status_display] | |
| ) | |
| send_btn.click( | |
| fn=handle_chat_message, | |
| inputs=[msg_input, chatbot], | |
| outputs=[msg_input, chatbot, status_display] | |
| ) | |
| # Control button handlers | |
| refresh_btn.click( | |
| fn=get_chat_status, | |
| inputs=[], | |
| outputs=[status_display] | |
| ) | |
| # New session handler with improved feedback | |
| def enhanced_new_session(): | |
| history, info = start_new_chat_session() | |
| session_html = f'<div class="session-info">{info}</div>' | |
| updated_status = get_chat_status() | |
| return history, session_html, updated_status | |
| new_session_btn.click( | |
| fn=enhanced_new_session, | |
| inputs=[], | |
| outputs=[chatbot, session_info, status_display] | |
| ) | |
| clear_data_btn.click( | |
| handle_clear_all_data, | |
| outputs=[chatbot, session_info, status_display] | |
| ) |