diff --git "a/app.py" "b/app.py" --- "a/app.py" +++ "b/app.py" @@ -4,182 +4,19 @@ import json import time import uuid from datetime import datetime +from groq import Groq import pandas as pd from typing import Dict, List, Tuple, Optional import re import hashlib import sqlite3 -# Mock classes for missing dependencies -class DiagramGenerator: - def generate_single_line_diagram(self, params): - return """ - - Single Line Diagram Placeholder - """ - - def generate_fault_analysis_diagram(self, fault_type): - return f""" - - {fault_type.replace('_', ' ').title()} Fault Analysis - """ - - def generate_protection_coordination_diagram(self): - return """ - - Protection Coordination Curves - """ - - def generate_phasor_diagram(self, condition): - return f""" - - {condition.title()} Phasor Diagram - """ - - def generate_impedance_diagram(self): - return """ - - Impedance Diagram - """ - -class EnhancedRAGSystem: - def retrieve_context(self, query): - return f"Context for query: {query}" - -class MockGroq: - def __init__(self, api_key=None): - self.api_key = api_key - - @property - def chat(self): - return MockChat() - -class MockChat: - @property - def completions(self): - return MockCompletions() - -class MockCompletions: - def create(self, **kwargs): - query = kwargs.get('messages', [])[-1].get('content', '') if kwargs.get('messages') else '' - - # Generate contextual responses based on query - if 'fault' in query.lower(): - response_text = """For fault analysis in power systems: - -1. **Three-Phase Fault**: The most severe but simplest fault - - Current: I_fault = V_nominal / Z_total - - All phases short-circuited to ground - -2. **Line-to-Ground Fault**: Most common fault (80-85%) - - Current: I_fault = 3 × V_nominal / (Z1 + Z2 + Z0) - - Uses sequence impedances - -3. **Line-to-Line Fault**: Less common but significant - - Current: I_fault = √3 × V_nominal / (Z1 + Z2) - - No zero-sequence component - -Key considerations: -- Use appropriate safety factors -- Consider transformer connections -- Apply proper coordination with protection devices""" - - elif 'protection' in query.lower(): - response_text = """Protection system design fundamentals: - -**Overcurrent Protection:** -- Pickup setting: 1.25-1.5 × Full Load Current -- Time-current curves: Inverse, very inverse, extremely inverse -- Coordination interval: 0.2-0.5 seconds - -**Distance Protection:** -- Zone 1: 80-90% of line length (instantaneous) -- Zone 2: 120% of protected line + 50% of next line -- Zone 3: Backup protection - -**Differential Protection:** -- Based on Kirchhoff's current law -- High sensitivity and selectivity -- Used for transformers, generators, buses - -Standards reference: IEEE C37.2 for device numbers""" - - elif 'diagram' in query.lower(): - response_text = """I can generate various power systems diagrams: - -1. **Single Line Diagrams** - System topology -2. **Fault Analysis Diagrams** - Fault current paths -3. **Protection Coordination Curves** - Time-current characteristics -4. **Phasor Diagrams** - Voltage/current relationships -5. **Impedance Diagrams** - Distance protection zones - -These diagrams are automatically generated based on your specific requirements and help visualize complex power system concepts.""" - - elif 'transformer' in query.lower(): - response_text = """Transformer fundamentals: - -**Basic Equations:** -- V1/V2 = N1/N2 = I2/I1 (turns ratio) -- S = √3 × V × I (apparent power) - -**Connection Types:** -- Wye-Wye: Common for distribution -- Delta-Wye: Most common for power transmission -- Wye-Delta: Step-down applications - -**Protection Requirements:** -- Differential protection for internal faults -- Overcurrent protection for external faults -- Buchholz relay for gas detection -- Temperature monitoring - -**Standards:** -- IEEE C57.12.00: General requirements -- IEC 60076: International standards""" - - else: - response_text = f"""Thank you for your power systems question about: {query} - -As your AI Power Systems Consultant, I can help with: - -🔧 **Technical Analysis** -- Fault calculations and analysis -- Protection system design -- Load flow studies -- Stability analysis - -📊 **Engineering Tools** -- Professional diagram generation -- Standards interpretation -- Formula references -- Calculation assistance - -📚 **Learning Support** -- Practice problem generation -- Concept explanations -- Exam preparation -- Study materials - -Please ask specific questions about power systems topics, request diagrams, or let me know what calculations you need help with!""" - - return MockResponse(response_text) - -class MockResponse: - def __init__(self, content): - self.choices = [MockChoice(content)] - -class MockChoice: - def __init__(self, content): - self.message = MockMessage(content) - -class MockMessage: - def __init__(self, content): - self.content = content - # Initialize components def get_groq_client(): - api_key = os.getenv("GROQ_API_KEY", "mock_key") - return MockGroq(api_key=api_key) + api_key = os.getenv("GROQ_API_KEY") + if not api_key: + raise ValueError("GROQ_API_KEY environment variable not set") + return Groq(api_key=api_key) class UserManager: def __init__(self): @@ -274,7 +111,6 @@ class UserManager: user = cursor.fetchone() if user: - # Update last login cursor.execute( "UPDATE users SET last_login = CURRENT_TIMESTAMP WHERE id = ?", (user[0],) @@ -295,86 +131,58 @@ class UserManager: except Exception as e: return False, None - - def get_user_sessions(self, user_id: int) -> List[Dict]: - """Get chat sessions for user""" - try: - conn = sqlite3.connect(self.db_path) - cursor = conn.cursor() - - cursor.execute( - "SELECT session_id, title, created_at FROM chat_sessions WHERE user_id = ? ORDER BY updated_at DESC", - (user_id,) - ) - - sessions = cursor.fetchall() - conn.close() - - return [ - { - 'session_id': session[0], - 'title': session[1] or f"Chat {session[0][:8]}", - 'created_at': session[2] - } - for session in sessions - ] - - except Exception as e: - return [] + +class DiagramGenerator: + def generate_single_line_diagram(self, config: Dict) -> str: + """Generate single line diagram SVG""" + return f""" + + + + Single Line Diagram + + + G + + + T1 + + + L1 + + + Load + + """ class PowerSystemsConsultant: def __init__(self): self.groq_client = get_groq_client() - self.rag_system = EnhancedRAGSystem() self.diagram_generator = DiagramGenerator() self.user_manager = UserManager() self.current_user = None self.current_session = None def generate_response(self, user_query: str, chat_history: List[Tuple[str, str]], session_id: str = None) -> Tuple[str, str]: - """Generate response using Groq LLM with RAG context""" + """Generate response using Groq LLM""" try: # Check if query is asking for a diagram - diagram_type = self.detect_diagram_request(user_query) diagram_svg = None - - if diagram_type: - diagram_svg = self.generate_diagram(diagram_type, user_query) - - # Retrieve relevant context - context = self.rag_system.retrieve_context(user_query) + if any(keyword in user_query.lower() for keyword in ['diagram', 'single line', 'drawing', 'circuit']): + diagram_svg = self.diagram_generator.generate_single_line_diagram({}) # Prepare system prompt - system_prompt = f"""You are a Power Systems Mini-Consultant AI assistant specializing in electrical power systems. - You help with: - 1. Fault analysis and calculations - 2. Protection system design - 3. Standards interpretation (IEEE, IEC, ANSI) - 4. Study materials and exam preparation - 5. Practice problem generation - 6. Engineering diagrams and visualizations - - Use the following context from the knowledge base: - {context} - - Provide clear, technical explanations with practical examples. Include relevant formulas, standards references, and safety considerations when appropriate. - - If a user asks for diagrams or visual representations, mention that you can generate professional engineering diagrams including: - - Single line diagrams - - Fault analysis diagrams - - Protection coordination curves - - Phasor diagrams - - Impedance diagrams - """ + system_prompt = """You are a Power Systems Expert AI assistant specializing in electrical power systems. + You help with fault analysis, protection systems, standards interpretation, and engineering calculations. + Provide clear, technical explanations with practical examples and safety considerations.""" # Prepare conversation context messages = [{"role": "system", "content": system_prompt}] - # Add chat history - for human_msg, ai_msg in chat_history[-5:]: # Last 5 exchanges - if human_msg and ai_msg: - messages.append({"role": "user", "content": human_msg}) - messages.append({"role": "assistant", "content": ai_msg}) + # Add chat history (last 5 exchanges) + for human_msg, ai_msg in chat_history[-5:]: + messages.append({"role": "user", "content": human_msg}) + messages.append({"role": "assistant", "content": ai_msg}) # Add current query messages.append({"role": "user", "content": user_query}) @@ -389,96 +197,20 @@ class PowerSystemsConsultant: text_response = response.choices[0].message.content - # Save to database if session exists - if session_id and self.current_user: - self.save_message(session_id, "user", user_query) - self.save_message(session_id, "assistant", text_response) - return text_response, diagram_svg except Exception as e: - error_msg = f"Error generating response: {str(e)}. Using mock response." - # Provide a helpful fallback response - fallback_response = f"""I understand you're asking about: {user_query} - -As your Power Systems Consultant, I'm here to help with electrical power system analysis and design. - -Some areas I can assist with: -- Fault calculations and analysis -- Protection system coordination -- Power flow studies -- Equipment sizing and selection -- Standards compliance (IEEE, IEC) -- Professional diagram generation - -Please feel free to ask specific technical questions or request engineering diagrams!""" - return fallback_response, None - - def detect_diagram_request(self, query: str) -> Optional[str]: - """Detect if user is requesting a diagram""" - query_lower = query.lower() - - diagram_keywords = { - 'single line': 'single_line', - 'single-line': 'single_line', - 'fault analysis': 'fault_analysis', - 'fault diagram': 'fault_analysis', - 'protection coordination': 'protection_coordination', - 'coordination curve': 'protection_coordination', - 'phasor diagram': 'phasor', - 'phasor': 'phasor', - 'impedance diagram': 'impedance', - 'distance protection': 'impedance', - 'r-x diagram': 'impedance' - } - - for keyword, diagram_type in diagram_keywords.items(): - if keyword in query_lower: - return diagram_type - - return None - - def generate_diagram(self, diagram_type: str, query: str) -> str: - """Generate appropriate diagram based on type""" - try: - if diagram_type == 'single_line': - return self.diagram_generator.generate_single_line_diagram({}) - elif diagram_type == 'fault_analysis': - fault_type = 'line_to_ground' - if 'line to line' in query.lower() or 'l-l' in query.lower(): - fault_type = 'line_to_line' - elif 'three phase' in query.lower() or '3-phase' in query.lower(): - fault_type = 'three_phase' - return self.diagram_generator.generate_fault_analysis_diagram(fault_type) - elif diagram_type == 'protection_coordination': - return self.diagram_generator.generate_protection_coordination_diagram() - elif diagram_type == 'phasor': - condition = 'balanced' - if 'unbalanced' in query.lower() or 'fault' in query.lower(): - condition = 'unbalanced' - return self.diagram_generator.generate_phasor_diagram(condition) - elif diagram_type == 'impedance': - return self.diagram_generator.generate_impedance_diagram() - except Exception as e: - return f"Error generating diagram: {str(e)}" - - return None + error_msg = f"Error generating response: {str(e)}. Please check your GROQ_API_KEY and try again." + return error_msg, None def generate_practice_pack(self, topic: str, difficulty: str, num_questions: int) -> str: """Generate practice questions pack""" try: practice_prompt = f"""Generate {num_questions} power systems practice questions about {topic} at {difficulty} level. - Format the response with: - 1. Question number and statement - 2. Multiple choice options (A, B, C, D) when appropriate - 3. Detailed solution with step-by-step calculations - 4. Key concepts and formulas used - 5. References to relevant standards - - Focus on practical engineering scenarios and include numerical calculations where applicable.""" + Format with numbered questions, multiple choice options, and detailed solutions.""" messages = [ - {"role": "system", "content": "You are an expert power systems engineer creating practice questions for students and professionals."}, + {"role": "system", "content": "You are an expert power systems engineer creating practice questions."}, {"role": "user", "content": practice_prompt} ] @@ -492,50 +224,16 @@ Please feel free to ask specific technical questions or request engineering diag return response.choices[0].message.content except Exception as e: - # Provide sample practice questions as fallback - return f"""# {topic} Practice Questions - {difficulty} Level - -## Question 1: Three-Phase Fault Analysis -A 13.8 kV system has a total impedance of 0.5 + j2.0 ohms. Calculate the three-phase fault current. - -**Solution:** -- Line-to-line voltage = 13.8 kV -- Phase voltage = 13.8 kV / √3 = 7.967 kV -- Total impedance magnitude = √(0.5² + 2.0²) = 2.06 ohms -- Fault current = 7967 V / 2.06 ohms = 3867 A - -**Key Concepts:** Three-phase fault analysis, impedance calculations -**Standards:** IEEE 141 - Recommended Practice for Electric Power Distribution - -## Question 2: Overcurrent Protection Setting -For a 500 kVA transformer with 4% impedance, determine the appropriate overcurrent relay pickup setting. - -**Solution:** -- Full load current = 500 kVA / (√3 × 13.8 kV) = 20.9 A -- Pickup setting = 1.25 × 20.9 A = 26.1 A (minimum) -- Consider coordination requirements for final setting - -**Key Concepts:** Protection coordination, transformer protection -**Standards:** IEEE C37.91 - Guide for Protective Relay Applications - -Continue with additional questions...""" + return f"Error generating practice pack: {str(e)}" def explain_standard(self, standard: str) -> str: """Explain power systems standard""" try: - standard_prompt = f"""Provide a comprehensive explanation of the {standard} standard including: - 1. Purpose and scope of the standard - 2. Key requirements and specifications - 3. Practical applications in power systems - 4. Important clauses and sections - 5. Relationship to other standards - 6. Implementation considerations - 7. Common misconceptions or challenges - - Make it practical and useful for power systems engineers.""" + standard_prompt = f"""Provide a comprehensive explanation of the {standard} standard including + purpose, key requirements, practical applications, and implementation considerations.""" messages = [ - {"role": "system", "content": "You are an expert in power systems standards and regulations with deep knowledge of IEEE, IEC, and ANSI standards."}, + {"role": "system", "content": "You are an expert in power systems standards."}, {"role": "user", "content": standard_prompt} ] @@ -549,46 +247,7 @@ Continue with additional questions...""" return response.choices[0].message.content except Exception as e: - # Provide detailed standard explanation as fallback - return f"""# {standard} Standard Explanation - -## Overview -This standard provides comprehensive guidelines for power systems applications. - -## Key Sections: - -### Scope and Purpose -- Defines the framework for electrical power system design -- Establishes safety and performance criteria -- Provides testing and certification requirements - -### Technical Requirements -- Voltage and frequency specifications -- Equipment ratings and classifications -- Installation and maintenance guidelines - -### Application Guidelines -- System design considerations -- Protection and control requirements -- Coordination with other equipment - -### Implementation Notes -- Compliance verification procedures -- Documentation requirements -- Inspection and testing protocols - -## Related Standards: -- IEEE 1547: Interconnection standards -- IEEE 519: Harmonic control -- IEC 61850: Communication protocols - -## Practical Applications: -- Utility system design -- Industrial power systems -- Renewable energy integration -- Protection system coordination - -For detailed information, consult the complete standard document.""" + return f"Error explaining standard: {str(e)}" def create_chat_session(self, user_id: int, title: str = None) -> str: """Create new chat session""" @@ -609,65 +268,7 @@ For detailed information, consult the complete standard document.""" return session_id except Exception as e: - return str(uuid.uuid4()) # Fallback to temporary session - - def save_message(self, session_id: str, role: str, content: str): - """Save message to database""" - try: - conn = sqlite3.connect(self.user_manager.db_path) - cursor = conn.cursor() - - cursor.execute( - "INSERT INTO messages (session_id, role, content) VALUES (?, ?, ?)", - (session_id, role, content) - ) - - # Update session timestamp - cursor.execute( - "UPDATE chat_sessions SET updated_at = CURRENT_TIMESTAMP WHERE session_id = ?", - (session_id,) - ) - - conn.commit() - conn.close() - - except Exception as e: - pass # Continue without saving if database error - - def load_chat_history(self, session_id: str) -> List[Tuple[str, str]]: - """Load chat history from database""" - try: - conn = sqlite3.connect(self.user_manager.db_path) - cursor = conn.cursor() - - cursor.execute( - "SELECT role, content FROM messages WHERE session_id = ? ORDER BY timestamp", - (session_id,) - ) - - messages = cursor.fetchall() - conn.close() - - # Convert to chat history format - history = [] - current_pair = [None, None] - - for role, content in messages: - if role == "user": - if current_pair[0] is not None: - history.append((current_pair[0], current_pair[1] or "")) - current_pair = [content, None] - elif role == "assistant": - current_pair[1] = content - - # Add the last pair if complete - if current_pair[0] is not None: - history.append((current_pair[0], current_pair[1] or "")) - - return history - - except Exception as e: - return [] + return str(uuid.uuid4()) # Initialize the consultant try: @@ -677,42 +278,38 @@ except Exception as e: consultant = None initialization_status = f"❌ Initialization failed: {str(e)}" -# Enhanced CSS with lighter background +# Updated CSS with lighter background and fixed animations ENHANCED_CSS = """ -@import url('https://fonts.googleapis.com/css2?family=Inter:wght@100;200;300;400;500;600;700;800;900&display=swap'); -@import url('https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css'); +@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&display=swap'); * { font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif; box-sizing: border-box; } -/* Modern Color Palette - Lighter */ :root { - --primary: #2563eb; - --primary-light: #3b82f6; - --primary-dark: #1d4ed8; + --primary: #3b82f6; + --primary-light: #60a5fa; + --primary-dark: #2563eb; --secondary: #10b981; --secondary-light: #34d399; - --secondary-dark: #059669; --accent: #8b5cf6; - --accent-light: #a78bfa; --warning: #f59e0b; --danger: #ef4444; --success: #10b981; - --bg-primary: #f1f5f9; - --bg-secondary: #e2e8f0; - --bg-tertiary: #cbd5e1; - --bg-card: rgba(255, 255, 255, 0.9); - --bg-glass: rgba(255, 255, 255, 0.7); + --bg-primary: #f8fafc; + --bg-secondary: #f1f5f9; + --bg-tertiary: #e2e8f0; + --bg-card: rgba(255, 255, 255, 0.95); + --bg-glass: rgba(255, 255, 255, 0.8); - --text-primary: #1e293b; + --text-primary: #0f172a; --text-secondary: #475569; --text-muted: #64748b; --border: rgba(148, 163, 184, 0.3); - --border-light: rgba(148, 163, 184, 0.1); + --border-light: rgba(148, 163, 184, 0.2); --shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05); --shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1); @@ -721,55 +318,37 @@ ENHANCED_CSS = """ --shadow-2xl: 0 25px 50px -12px rgba(0, 0, 0, 0.25); } -/* Root styling */ +/* Dark mode for specific elements only */ +.dark-section { + --bg-primary: #0f172a; + --bg-secondary: #1e293b; + --bg-tertiary: #334155; + --bg-card: rgba(30, 41, 59, 0.9); + --text-primary: #f8fafc; + --text-secondary: #cbd5e1; + --text-muted: #94a3b8; + --border: rgba(255, 255, 255, 0.1); +} + .gradio-container { - background: linear-gradient(135deg, var(--bg-primary) 0%, var(--bg-secondary) 100%); + background: linear-gradient(135deg, var(--bg-primary) 0%, var(--bg-secondary) 50%, var(--bg-tertiary) 100%); color: var(--text-primary); min-height: 100vh; padding: 0; } -/* Page transition animations */ -.page-enter { - animation: pageEnter 0.6s cubic-bezier(0.16, 1, 0.3, 1) forwards; -} - -.page-exit { - animation: pageExit 0.4s cubic-bezier(0.16, 1, 0.3, 1) forwards; -} - -@keyframes pageEnter { - from { opacity: 0; transform: translateY(20px) scale(0.95); } - to { opacity: 1; transform: translateY(0) scale(1); } -} - -@keyframes pageExit { - from { opacity: 1; transform: translateY(0) scale(1); } - to { opacity: 0; transform: translateY(-20px) scale(0.95); } -} - -/* Splash animation */ -.splash-animation { - animation: splash 0.8s cubic-bezier(0.16, 1, 0.3, 1); -} - -@keyframes splash { - 0% { transform: scale(1); opacity: 1; } - 50% { transform: scale(1.05); opacity: 0.8; } - 100% { transform: scale(0.95); opacity: 0; } -} - -/* Cover Page Styling */ +/* Fixed cover page styling */ .cover-page { min-height: 100vh; background: linear-gradient(135deg, - var(--bg-primary) 0%, - var(--bg-secondary) 50%, - var(--bg-tertiary) 100%); - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; + #f8fafc 0%, + #e2e8f0 30%, + #cbd5e1 60%, + #94a3b8 100%); + display: flex !important; + flex-direction: column !important; + align-items: center !important; + justify-content: center !important; text-align: center; padding: 2rem; position: relative; @@ -784,21 +363,17 @@ ENHANCED_CSS = """ right: 0; bottom: 0; background: - radial-gradient(circle at 20% 80%, rgba(37, 99, 235, 0.1) 0%, transparent 50%), + radial-gradient(circle at 20% 80%, rgba(59, 130, 246, 0.1) 0%, transparent 50%), radial-gradient(circle at 80% 20%, rgba(139, 92, 246, 0.1) 0%, transparent 50%), - radial-gradient(circle at 40% 40%, rgba(16, 185, 129, 0.08) 0%, transparent 50%); - animation: backgroundShift 20s ease-in-out infinite; -} - -@keyframes backgroundShift { - 0%, 100% { opacity: 1; transform: scale(1); } - 50% { opacity: 0.8; transform: scale(1.1); } + radial-gradient(circle at 40% 40%, rgba(16, 185, 129, 0.05) 0%, transparent 50%); + pointer-events: none; } .cover-hero { z-index: 10; max-width: 800px; margin-bottom: 4rem; + position: relative; } .cover-icon { @@ -807,26 +382,23 @@ ENHANCED_CSS = """ -webkit-background-clip: text; -webkit-text-fill-color: transparent; margin-bottom: 2rem; - animation: float 3s ease-in-out infinite; -} - -@keyframes float { - 0%, 100% { transform: translateY(0px); } - 50% { transform: translateY(-10px); } + display: block; + line-height: 1; } .cover-title { - font-size: clamp(3rem, 8vw, 5rem); - font-weight: 900; + font-size: clamp(2.5rem, 6vw, 4.5rem); + font-weight: 800; background: linear-gradient(135deg, var(--text-primary), var(--text-secondary)); -webkit-background-clip: text; -webkit-text-fill-color: transparent; margin-bottom: 1.5rem; line-height: 1.1; + position: relative; } .cover-subtitle { - font-size: clamp(1.1rem, 3vw, 1.5rem); + font-size: clamp(1rem, 2.5vw, 1.25rem); color: var(--text-secondary); margin-bottom: 3rem; line-height: 1.6; @@ -841,6 +413,7 @@ ENHANCED_CSS = """ flex-wrap: wrap; justify-content: center; z-index: 10; + position: relative; } .cover-btn { @@ -850,12 +423,17 @@ ENHANCED_CSS = """ border-radius: 50px !important; border: none !important; cursor: pointer !important; - transition: all 0.3s cubic-bezier(0.16, 1, 0.3, 1) !important; + transition: all 0.3s ease !important; text-transform: uppercase !important; letter-spacing: 0.5px !important; position: relative !important; overflow: hidden !important; min-width: 200px !important; + text-decoration: none !important; + display: inline-flex !important; + align-items: center !important; + justify-content: center !important; + gap: 0.5rem !important; } .cover-btn-primary { @@ -875,25 +453,10 @@ ENHANCED_CSS = """ box-shadow: var(--shadow-xl) !important; } -.cover-btn::before { - content: ''; - position: absolute; - top: 0; - left: -100%; - width: 100%; - height: 100%; - background: linear-gradient(90deg, transparent, rgba(255,255,255,0.2), transparent); - transition: left 0.5s; -} - -.cover-btn:hover::before { - left: 100%; -} - /* Authentication Pages */ .auth-page { min-height: 100vh; - background: linear-gradient(135deg, var(--bg-primary), var(--bg-secondary)); + background: linear-gradient(135deg, #f8fafc, #e2e8f0); display: flex; align-items: center; justify-content: center; @@ -909,20 +472,6 @@ ENHANCED_CSS = """ width: 100%; max-width: 450px; box-shadow: var(--shadow-2xl); - position: relative; -} - -.auth-container::before { - content: ''; - position: absolute; - top: -1px; - left: -1px; - right: -1px; - bottom: -1px; - background: linear-gradient(135deg, var(--primary), var(--accent)); - border-radius: 24px; - z-index: -1; - opacity: 0.2; } .auth-header { @@ -950,63 +499,10 @@ ENHANCED_CSS = """ font-size: 0.95rem; } -/* Enhanced Form Inputs */ -.form-group { - margin-bottom: 1.5rem; -} - -.form-label { - display: block; - font-size: 0.875rem; - font-weight: 500; - color: var(--text-secondary); - margin-bottom: 0.5rem; -} - -.gradio-textbox { - background: rgba(255, 255, 255, 0.8) !important; - border: 2px solid var(--border) !important; - border-radius: 12px !important; - padding: 1rem !important; - color: var(--text-primary) !important; - font-size: 1rem !important; - transition: all 0.3s ease !important; - backdrop-filter: blur(10px) !important; - width: 100% !important; -} - -.gradio-textbox:focus { - border-color: var(--primary) !important; - box-shadow: 0 0 0 4px rgba(37, 99, 235, 0.1) !important; - background: rgba(255, 255, 255, 0.95) !important; -} - -.gradio-button { - background: linear-gradient(135deg, var(--primary), var(--primary-light)) !important; - border: none !important; - border-radius: 12px !important; - padding: 1rem 2rem !important; - font-weight: 600 !important; - font-size: 1rem !important; - color: white !important; - cursor: pointer !important; - transition: all 0.3s ease !important; - text-transform: uppercase !important; - letter-spacing: 0.5px !important; - width: 100% !important; - box-shadow: var(--shadow-lg) !important; -} - -.gradio-button:hover { - transform: translateY(-2px) !important; - box-shadow: var(--shadow-xl) !important; - background: linear-gradient(135deg, var(--primary-light), var(--primary)) !important; -} - -/* Service Selection Page */ +/* Services Page */ .services-page { min-height: 100vh; - background: linear-gradient(135deg, var(--bg-primary), var(--bg-secondary)); + background: linear-gradient(135deg, #f8fafc, #e2e8f0, #cbd5e1); padding: 2rem; } @@ -1045,7 +541,7 @@ ENHANCED_CSS = """ .services-grid { display: grid; - grid-template-columns: repeat(auto-fit, minmax(350px, 1fr)); + grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 2rem; max-width: 1200px; margin: 0 auto; @@ -1058,7 +554,7 @@ ENHANCED_CSS = """ border-radius: 20px; padding: 2.5rem; text-align: center; - transition: all 0.4s cubic-bezier(0.16, 1, 0.3, 1); + transition: all 0.4s ease; cursor: pointer; position: relative; overflow: hidden; @@ -1081,7 +577,7 @@ ENHANCED_CSS = """ } .service-card:hover { - transform: translateY(-8px) scale(1.02); + transform: translateY(-8px); border-color: var(--primary); box-shadow: var(--shadow-2xl); } @@ -1092,7 +588,7 @@ ENHANCED_CSS = """ -webkit-background-clip: text; -webkit-text-fill-color: transparent; margin-bottom: 1.5rem; - animation: pulse 2s ease-in-out infinite; + display: block; } .service-title { @@ -1126,426 +622,71 @@ ENHANCED_CSS = """ box-shadow: var(--shadow-lg) !important; } -/* Chatbot Interface */ -.chatbot-page { - min-height: 100vh; +/* Chat Interface */ +.dark-section .chatbot-page { background: linear-gradient(135deg, var(--bg-primary), var(--bg-secondary)); + min-height: 100vh; display: flex; flex-direction: column; } -.chatbot-header { +.dark-section .chatbot-header { background: var(--bg-card); backdrop-filter: blur(20px); border-bottom: 1px solid var(--border); padding: 1.5rem 2rem; - display: flex; - justify-content: between; - align-items: center; - position: sticky; - top: 0; - z-index: 100; -} - -.chatbot-title { - font-size: 1.5rem; - font-weight: 700; color: var(--text-primary); - display: flex; - align-items: center; - gap: 1rem; -} - -.chatbot-container { - flex: 1; - display: grid; - grid-template-columns: 300px 1fr; - gap: 0; - height: calc(100vh - 80px); -} - -.chatbot-sidebar { - background: var(--bg-card); - backdrop-filter: blur(20px); - border-right: 1px solid var(--border); - padding: 2rem; - overflow-y: auto; } -.sidebar-header { - margin-bottom: 2rem; +/* Enhanced Form Inputs */ +.gradio-textbox input, .gradio-textbox textarea { + background: rgba(255, 255, 255, 0.95) !important; + border: 2px solid var(--border) !important; + border-radius: 12px !important; + padding: 1rem !important; + color: var(--text-primary) !important; + font-size: 1rem !important; + transition: all 0.3s ease !important; } -.sidebar-title { - font-size: 1.2rem; - font-weight: 600; - color: var(--text-primary); - margin-bottom: 1rem; - display: flex; - align-items: center; - gap: 0.5rem; +.gradio-textbox input:focus, .gradio-textbox textarea:focus { + border-color: var(--primary) !important; + box-shadow: 0 0 0 4px rgba(59, 130, 246, 0.1) !important; + background: white !important; } -.new-chat-btn { - width: 100% !important; - background: linear-gradient(135deg, var(--secondary), var(--secondary-light)) !important; +.gradio-button { + background: linear-gradient(135deg, var(--primary), var(--primary-light)) !important; border: none !important; border-radius: 12px !important; - padding: 1rem !important; - color: white !important; + padding: 1rem 2rem !important; font-weight: 600 !important; + font-size: 1rem !important; + color: white !important; cursor: pointer !important; transition: all 0.3s ease !important; - margin-bottom: 2rem !important; text-transform: uppercase !important; letter-spacing: 0.5px !important; } -.new-chat-btn:hover { +.gradio-button:hover { transform: translateY(-2px) !important; - box-shadow: var(--shadow-lg) !important; -} - -.chat-history { - display: flex; - flex-direction: column; - gap: 0.5rem; -} - -.chat-history-item { - background: rgba(148, 163, 184, 0.1); - border: 1px solid var(--border-light); - border-radius: 8px; - padding: 0.75rem; - cursor: pointer; - transition: all 0.3s ease; - font-size: 0.9rem; - color: var(--text-secondary); -} - -.chat-history-item:hover { - background: rgba(148, 163, 184, 0.2); - border-color: var(--primary); - color: var(--text-primary); -} - -.chat-history-item.active { - background: rgba(37, 99, 235, 0.1); - border-color: var(--primary); - color: var(--text-primary); + box-shadow: var(--shadow-xl) !important; + background: linear-gradient(135deg, var(--primary-light), var(--primary)) !important; } -.chatbot-main { - display: flex; - flex-direction: column; - background: var(--bg-primary); +/* Page visibility fixes */ +.gradio-column { + display: flex !important; + flex-direction: column !important; } -.chat-area { - flex: 1; - padding: 2rem; - overflow-y: auto; - display: flex; - flex-direction: column; -} - -.chat-messages { - flex: 1; - margin-bottom: 2rem; -} - -.gradio-chatbot { - background: transparent !important; - border: none !important; - height: 500px !important; -} - -.chat-input-area { - background: var(--bg-card); - backdrop-filter: blur(20px); - border-top: 1px solid var(--border); - padding: 2rem; - position: sticky; - bottom: 0; -} - -.chat-input-container { - display: flex; - gap: 1rem; - align-items: flex-end; - max-width: 1000px; - margin: 0 auto; -} - -.chat-input { - flex: 1; - background: rgba(255, 255, 255, 0.8) !important; - border: 2px solid var(--border) !important; - border-radius: 20px !important; - padding: 1rem 1.5rem !important; - color: var(--text-primary) !important; - font-size: 1rem !important; - resize: none !important; - min-height: 60px !important; - max-height: 150px !important; - transition: all 0.3s ease !important; -} - -.chat-input:focus { - border-color: var(--primary) !important; - box-shadow: 0 0 0 4px rgba(37, 99, 235, 0.1) !important; -} - -.chat-send-btn { - background: linear-gradient(135deg, var(--primary), var(--primary-light)) !important; - border: none !important; - border-radius: 50% !important; - width: 60px !important; - height: 60px !important; - display: flex !important; - align-items: center !important; - justify-content: center !important; - cursor: pointer !important; - transition: all 0.3s ease !important; - font-size: 1.2rem !important; - color: white !important; -} - -.chat-send-btn:hover { - transform: translateY(-2px) scale(1.1) !important; - box-shadow: var(--shadow-lg) !important; -} - -.chat-clear-btn { - background: rgba(239, 68, 68, 0.1) !important; - border: 2px solid rgba(239, 68, 68, 0.3) !important; - border-radius: 12px !important; - padding: 0.875rem 1.5rem !important; - color: var(--danger) !important; - cursor: pointer !important; - transition: all 0.3s ease !important; - font-weight: 500 !important; -} - -.chat-clear-btn:hover { - background: rgba(239, 68, 68, 0.2) !important; - border-color: var(--danger) !important; - transform: translateY(-1px) !important; -} - -/* Diagram Display */ -.diagram-container { - background: var(--bg-card); - backdrop-filter: blur(20px); - border: 1px solid var(--border); - border-radius: 16px; - padding: 2rem; - margin: 2rem 0; - text-align: center; - box-shadow: var(--shadow-lg); -} - -.diagram-placeholder { - color: var(--text-muted); - padding: 3rem; - border: 2px dashed var(--border); - border-radius: 12px; - background: rgba(148,163,184,0.05); -} - -/* Practice Page */ -.practice-page { - min-height: 100vh; - background: linear-gradient(135deg, var(--bg-primary), var(--bg-secondary)); - padding: 2rem; -} - -.practice-container { - max-width: 1200px; - margin: 0 auto; -} - -.practice-header { - text-align: center; - margin-bottom: 3rem; -} - -.practice-title { - font-size: 3rem; - font-weight: 800; - background: linear-gradient(135deg, var(--text-primary), var(--text-secondary)); - -webkit-background-clip: text; - -webkit-text-fill-color: transparent; - margin-bottom: 1rem; -} - -.practice-content { - display: grid; - grid-template-columns: 1fr 2fr; - gap: 3rem; - margin-top: 2rem; -} - -.practice-controls { - background: var(--bg-card); - backdrop-filter: blur(20px); - border: 1px solid var(--border); - border-radius: 20px; - padding: 2.5rem; - height: fit-content; -} - -.practice-output { - background: var(--bg-card); - backdrop-filter: blur(20px); - border: 1px solid var(--border); - border-radius: 20px; - padding: 2.5rem; - min-height: 600px; -} - -.gradio-dropdown { - background: rgba(255, 255, 255, 0.8) !important; - border: 2px solid var(--border) !important; - border-radius: 12px !important; - color: var(--text-primary) !important; - padding: 1rem !important; -} - -.gradio-radio { - background: transparent !important; -} - -.gradio-slider { - background: transparent !important; -} - -/* Standards Page */ -.standards-page { - min-height: 100vh; - background: linear-gradient(135deg, var(--bg-primary), var(--bg-secondary)); - padding: 2rem; -} - -.standards-container { - max-width: 1200px; - margin: 0 auto; -} - -.standards-content { - display: grid; - grid-template-columns: 1fr 2fr; - gap: 3rem; - margin-top: 2rem; -} - -/* Study Resources Page */ -.study-page { - min-height: 100vh; - background: linear-gradient(135deg, var(--bg-primary), var(--bg-secondary)); - padding: 2rem; -} - -.study-container { - max-width: 1200px; - margin: 0 auto; -} - -.formula-box { - background: rgba(37, 99, 235, 0.1); - border: 1px solid rgba(37, 99, 235, 0.3); - border-radius: 16px; - padding: 2rem; - margin: 1.5rem 0; - position: relative; -} - -.formula-title { - font-size: 1.25rem; - font-weight: 700; - color: var(--primary); - margin-bottom: 1rem; - display: flex; - align-items: center; - gap: 0.75rem; -} - -.formula-code { - background: rgba(0,0,0,0.1); - border-radius: 8px; - padding: 0.75rem 1rem; - font-family: 'Monaco', 'Courier New', monospace; - color: var(--text-primary); - border-left: 4px solid var(--primary); - margin: 0.5rem 0; - display: block; - overflow-x: auto; -} - -/* Animations */ -@keyframes pulse { - 0%, 100% { opacity: 1; transform: scale(1); } - 50% { opacity: 0.8; transform: scale(1.05); } -} - -@keyframes slideInUp { - from { opacity: 0; transform: translateY(30px); } - to { opacity: 1; transform: translateY(0); } -} - -@keyframes fadeIn { - from { opacity: 0; } - to { opacity: 1; } -} - -/* Back button */ -.back-btn { - position: fixed !important; - top: 2rem !important; - left: 2rem !important; - z-index: 1000 !important; - background: var(--bg-card) !important; - backdrop-filter: blur(20px) !important; - border: 1px solid var(--border) !important; - border-radius: 50px !important; - padding: 0.875rem 1.5rem !important; - color: var(--text-primary) !important; - cursor: pointer !important; - transition: all 0.3s ease !important; - display: flex !important; - align-items: center !important; - gap: 0.5rem !important; - font-weight: 500 !important; -} - -.back-btn:hover { - transform: translateX(-5px) !important; - background: var(--primary) !important; - color: white !important; +.gradio-row { + display: flex !important; } /* Responsive Design */ -@media (max-width: 1024px) { - .chatbot-container { - grid-template-columns: 250px 1fr; - } - - .practice-content, - .standards-content { - grid-template-columns: 1fr; - gap: 2rem; - } -} - @media (max-width: 768px) { - .chatbot-container { - grid-template-columns: 1fr; - } - - .chatbot-sidebar { - display: none; - } - .cover-buttons { flex-direction: column; align-items: center; @@ -1560,15 +701,6 @@ ENHANCED_CSS = """ grid-template-columns: 1fr; gap: 1.5rem; } - - .chat-input-container { - flex-direction: column; - gap: 1rem; - } - - .chat-send-btn { - align-self: flex-end !important; - } } /* Loading states */ @@ -1596,22 +728,17 @@ ENHANCED_CSS = """ 100% { transform: translate(-50%, -50%) rotate(360deg); } } -/* Scrollbar styling */ -::-webkit-scrollbar { - width: 6px; -} - -::-webkit-scrollbar-track { - background: var(--bg-secondary); -} - -::-webkit-scrollbar-thumb { - background: var(--primary); - border-radius: 3px; +/* Prevent unwanted animations */ +.cover-page .cover-hero { + position: relative !important; + transform: none !important; + animation: none !important; } -::-webkit-scrollbar-thumb:hover { - background: var(--primary-light); +.cover-page .cover-title { + position: relative !important; + transform: none !important; + animation: none !important; } """ @@ -1621,7 +748,7 @@ def create_multipage_app(): theme=gr.themes.Soft( primary_hue=gr.themes.colors.blue, secondary_hue=gr.themes.colors.green, - neutral_hue=gr.themes.colors.gray, + neutral_hue=gr.themes.colors.slate, ), title="⚡ Power Systems Consultant", css=ENHANCED_CSS @@ -1632,26 +759,35 @@ def create_multipage_app(): user_state = gr.State(None) session_state = gr.State(None) - # Page 1: Cover Page + # Page visibility management + page_visibility = gr.State({ + "cover": True, + "signin": False, + "signup": False, + "services": False, + "chatbot": False, + "practice": False, + "standards": False, + "study": False + }) + + # Page 1: Cover Page (Always visible initially) with gr.Column(visible=True, elem_classes=["cover-page"]) as cover_page: - gr.HTML(""" -
-
-

Power Systems Consultant

-

- Advanced AI-powered platform for electrical power systems analysis, fault calculations, - protection design, and engineering excellence. Experience the future of power systems consulting. -

-
-
- - -
- """) + with gr.HTML() as cover_content: + gr.HTML(""" +
+
+

Power Systems Consultant

+

+ Advanced AI-powered platform for electrical power systems analysis, fault calculations, + protection design, and engineering excellence. Experience the future of power systems consulting. +

+
+ """) + + with gr.Row(): + signin_nav_btn = gr.Button("🔐 Sign In", elem_classes=["cover-btn", "cover-btn-primary"]) + signup_nav_btn = gr.Button("🚀 Create Account", elem_classes=["cover-btn", "cover-btn-secondary"]) # Page 2: Sign In Page with gr.Column(visible=False, elem_classes=["auth-page"]) as signin_page: @@ -1666,25 +802,17 @@ def create_multipage_app(): login_username = gr.Textbox( label="Username", - placeholder="Enter your username", - elem_classes=["auth-input"] + placeholder="Enter your username" ) login_password = gr.Textbox( label="Password", type="password", - placeholder="Enter your password", - elem_classes=["auth-input"] + placeholder="Enter your password" ) - signin_btn = gr.Button("Sign In", elem_classes=["auth-btn"]) + with gr.Row(): + signin_btn = gr.Button("Sign In", variant="primary") + back_cover_signin = gr.Button("← Back", variant="secondary") signin_status = gr.Textbox(label="Status", interactive=False, visible=False) - - gr.HTML(""" -
- -
- """) # Page 3: Sign Up Page with gr.Column(visible=False, elem_classes=["auth-page"]) as signup_page: @@ -1699,41 +827,30 @@ def create_multipage_app(): reg_username = gr.Textbox( label="Username", - placeholder="Choose a unique username", - elem_classes=["auth-input"] + placeholder="Choose a unique username" ) reg_email = gr.Textbox( label="Email", - placeholder="your.email@domain.com", - elem_classes=["auth-input"] + placeholder="your.email@domain.com" ) reg_full_name = gr.Textbox( label="Full Name", - placeholder="Your full name", - elem_classes=["auth-input"] + placeholder="Your full name" ) reg_password = gr.Textbox( label="Password", type="password", - placeholder="Create a strong password (min 6 chars)", - elem_classes=["auth-input"] + placeholder="Create a strong password (min 6 chars)" ) reg_confirm_password = gr.Textbox( label="Confirm Password", type="password", - placeholder="Confirm your password", - elem_classes=["auth-input"] + placeholder="Confirm your password" ) - signup_btn = gr.Button("Create Account", elem_classes=["auth-btn"]) + with gr.Row(): + signup_btn = gr.Button("Create Account", variant="primary") + back_cover_signup = gr.Button("← Back", variant="secondary") signup_status = gr.Textbox(label="Status", interactive=False, visible=False) - - gr.HTML(""" -
- -
- """) # Page 4: Services Selection Page with gr.Column(visible=False, elem_classes=["services-page"]) as services_page: @@ -1742,609 +859,358 @@ def create_multipage_app():

Power Systems Workspace

Choose your engineering tool and start analyzing power systems

- -
- - """) - - gr.HTML(""" -
-
-
🤖
-

AI Consultant

-

- Interactive chat with AI expert for fault analysis, protection systems, - calculations, and engineering guidance with diagram generation. -

- -
- -
-
📚
-

Practice Generator

-

- Generate customized practice questions with detailed solutions, - step-by-step calculations, and standards references for exam prep. -

- -
- -
-
📋
-

Standards Explorer

-

- Comprehensive explanations of IEEE, IEC, and international standards - with practical applications and implementation guidelines. -

- -
- -
-
🎓
-

Study Resources

-

- Essential formulas, concepts, calculations, and comprehensive - exam preparation materials for power systems engineering. -

- +
+
+ 👤 +
+
+

Welcome to Power Systems!

+

Ready to tackle power systems challenges?

+
+
""") - gr.HTML(""" -
- -
- """) - - # Page 5: Chatbot Interface - with gr.Column(visible=False, elem_classes=["chatbot-page"]) as chatbot_page: - # Header - gr.HTML(""" -
-
- - AI Power Systems Consultant -
- -
- """) + with gr.Row(): + with gr.Column(elem_classes=["service-card"]): + gr.HTML(""" +
+
🤖
+

AI Consultant

+

+ Interactive chat with AI expert for fault analysis, protection systems, + calculations, and engineering guidance with diagram generation. +

+
+ """) + chatbot_service_btn = gr.Button("Launch Consultant", elem_classes=["service-button"]) + + with gr.Column(elem_classes=["service-card"]): + gr.HTML(""" +
+
📚
+

Practice Generator

+

+ Generate customized practice questions with detailed solutions, + step-by-step calculations, and standards references for exam prep. +

+
+ """) + practice_service_btn = gr.Button("Generate Practice", elem_classes=["service-button"]) - # Main container - with gr.Row(elem_classes=["chatbot-container"]): - # Sidebar - with gr.Column(elem_classes=["chatbot-sidebar"], scale=1): + with gr.Row(): + with gr.Column(elem_classes=["service-card"]): gr.HTML(""" -