import gradio as gr import os 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 # Initialize components def get_groq_client(): 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): self.db_path = 'users.db' self.init_database() def init_database(self): """Initialize SQLite database for users""" conn = sqlite3.connect(self.db_path) cursor = conn.cursor() cursor.execute(''' CREATE TABLE IF NOT EXISTS users ( id INTEGER PRIMARY KEY AUTOINCREMENT, username TEXT UNIQUE NOT NULL, email TEXT UNIQUE NOT NULL, password_hash TEXT NOT NULL, full_name TEXT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, last_login TIMESTAMP ) ''') cursor.execute(''' CREATE TABLE IF NOT EXISTS chat_sessions ( id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER, session_id TEXT UNIQUE, title TEXT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (user_id) REFERENCES users (id) ) ''') cursor.execute(''' CREATE TABLE IF NOT EXISTS messages ( id INTEGER PRIMARY KEY AUTOINCREMENT, session_id TEXT, role TEXT, content TEXT, timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (session_id) REFERENCES chat_sessions (session_id) ) ''') conn.commit() conn.close() def hash_password(self, password: str) -> str: """Hash password using SHA-256""" return hashlib.sha256(password.encode()).hexdigest() def create_user(self, username: str, email: str, password: str, full_name: str = "") -> Tuple[bool, str]: """Create new user account""" try: conn = sqlite3.connect(self.db_path) cursor = conn.cursor() password_hash = self.hash_password(password) cursor.execute( "INSERT INTO users (username, email, password_hash, full_name) VALUES (?, ?, ?, ?)", (username, email, password_hash, full_name) ) conn.commit() conn.close() return True, "Account created successfully!" except sqlite3.IntegrityError as e: if "username" in str(e): return False, "Username already exists" elif "email" in str(e): return False, "Email already registered" else: return False, "Registration failed" except Exception as e: return False, f"Error: {str(e)}" def authenticate_user(self, username: str, password: str) -> Tuple[bool, Optional[Dict]]: """Authenticate user login""" try: conn = sqlite3.connect(self.db_path) cursor = conn.cursor() password_hash = self.hash_password(password) cursor.execute( "SELECT id, username, email, full_name FROM users WHERE username = ? AND password_hash = ?", (username, password_hash) ) user = cursor.fetchone() if user: cursor.execute( "UPDATE users SET last_login = CURRENT_TIMESTAMP WHERE id = ?", (user[0],) ) conn.commit() user_data = { 'id': user[0], 'username': user[1], 'email': user[2], 'full_name': user[3] or user[1] } conn.close() return True, user_data conn.close() return False, None except Exception as e: return False, None class DiagramGenerator: def generate_single_line_diagram(self, config: Dict) -> str: """Generate single line diagram SVG""" return f""" """ class PowerSystemsConsultant: def __init__(self): self.groq_client = get_groq_client() 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""" try: # Check if query is asking for a diagram diagram_svg = None 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 = """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 (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}) # Generate response using Groq response = self.groq_client.chat.completions.create( model="llama3-70b-8192", messages=messages, max_tokens=2000, temperature=0.8 ) text_response = response.choices[0].message.content return text_response, diagram_svg except Exception as e: 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 with numbered questions, multiple choice options, and detailed solutions.""" messages = [ {"role": "system", "content": "You are an expert power systems engineer creating practice questions."}, {"role": "user", "content": practice_prompt} ] response = self.groq_client.chat.completions.create( model="llama3-70b-8192", messages=messages, max_tokens=3000, temperature=0.7 ) return response.choices[0].message.content except Exception as e: 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 purpose, key requirements, practical applications, and implementation considerations.""" messages = [ {"role": "system", "content": "You are an expert in power systems standards."}, {"role": "user", "content": standard_prompt} ] response = self.groq_client.chat.completions.create( model="llama3-70b-8192", messages=messages, max_tokens=2500, temperature=0.6 ) return response.choices[0].message.content except Exception as e: return f"Error explaining standard: {str(e)}" def create_chat_session(self, user_id: int, title: str = None) -> str: """Create new chat session""" session_id = str(uuid.uuid4()) try: conn = sqlite3.connect(self.user_manager.db_path) cursor = conn.cursor() cursor.execute( "INSERT INTO chat_sessions (user_id, session_id, title) VALUES (?, ?, ?)", (user_id, session_id, title or f"Chat {datetime.now().strftime('%m/%d %H:%M')}") ) conn.commit() conn.close() return session_id except Exception as e: return str(uuid.uuid4()) # Initialize the consultant try: consultant = PowerSystemsConsultant() initialization_status = "✅ Power Systems Consultant initialized successfully!" except Exception as e: consultant = None initialization_status = f"❌ Initialization failed: {str(e)}" # Updated CSS with lighter background and fixed animations ENHANCED_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; } :root { --primary: #3b82f6; --primary-light: #60a5fa; --primary-dark: #2563eb; --secondary: #10b981; --secondary-light: #34d399; --accent: #8b5cf6; --warning: #f59e0b; --danger: #ef4444; --success: #10b981; --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: #0f172a; --text-secondary: #475569; --text-muted: #64748b; --border: rgba(148, 163, 184, 0.3); --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); --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1); --shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.1); --shadow-2xl: 0 25px 50px -12px rgba(0, 0, 0, 0.25); } /* 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) 50%, var(--bg-tertiary) 100%); color: var(--text-primary); min-height: 100vh; padding: 0; } /* Fixed cover page styling */ .cover-page { min-height: 100vh; background: linear-gradient(135deg, #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; overflow: hidden; } .cover-page::before { content: ''; position: absolute; top: 0; left: 0; right: 0; bottom: 0; background: 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.05) 0%, transparent 50%); pointer-events: none; } .cover-hero { z-index: 10; max-width: 800px; margin-bottom: 4rem; position: relative; } .cover-icon { font-size: 6rem; background: linear-gradient(135deg, var(--primary), var(--accent)); -webkit-background-clip: text; -webkit-text-fill-color: transparent; margin-bottom: 2rem; display: block; line-height: 1; } .cover-title { 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(1rem, 2.5vw, 1.25rem); color: var(--text-secondary); margin-bottom: 3rem; line-height: 1.6; max-width: 600px; margin-left: auto; margin-right: auto; } .cover-buttons { display: flex; gap: 2rem; flex-wrap: wrap; justify-content: center; z-index: 10; position: relative; } .cover-btn { padding: 1.25rem 3rem !important; font-size: 1.1rem !important; font-weight: 600 !important; border-radius: 50px !important; border: none !important; cursor: pointer !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 { background: linear-gradient(135deg, var(--primary), var(--primary-light)) !important; color: white !important; box-shadow: var(--shadow-lg) !important; } .cover-btn-secondary { background: linear-gradient(135deg, var(--secondary), var(--secondary-light)) !important; color: white !important; box-shadow: var(--shadow-lg) !important; } .cover-btn:hover { transform: translateY(-3px) scale(1.05) !important; box-shadow: var(--shadow-xl) !important; } /* Authentication Pages */ .auth-page { min-height: 100vh; background: linear-gradient(135deg, #f8fafc, #e2e8f0); display: flex; align-items: center; justify-content: center; padding: 2rem; } .auth-container { background: var(--bg-card); backdrop-filter: blur(20px); border: 1px solid var(--border); border-radius: 24px; padding: 3rem; width: 100%; max-width: 450px; box-shadow: var(--shadow-2xl); } .auth-header { text-align: center; margin-bottom: 2.5rem; } .auth-icon { font-size: 3rem; background: linear-gradient(135deg, var(--primary), var(--accent)); -webkit-background-clip: text; -webkit-text-fill-color: transparent; margin-bottom: 1rem; } .auth-title { font-size: 2rem; font-weight: 700; color: var(--text-primary); margin-bottom: 0.5rem; } .auth-subtitle { color: var(--text-secondary); font-size: 0.95rem; } /* Services Page */ .services-page { min-height: 100vh; background: linear-gradient(135deg, #f8fafc, #e2e8f0, #cbd5e1); padding: 2rem; } .services-header { text-align: center; margin-bottom: 4rem; max-width: 800px; margin-left: auto; margin-right: auto; } .services-title { font-size: clamp(2.5rem, 6vw, 4rem); 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; } .services-subtitle { font-size: 1.2rem; color: var(--text-secondary); margin-bottom: 2rem; } .user-welcome { background: var(--bg-card); border: 1px solid var(--border); border-radius: 16px; padding: 1.5rem; margin-bottom: 2rem; text-align: center; backdrop-filter: blur(20px); } .services-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 2rem; max-width: 1200px; margin: 0 auto; } .service-card { background: var(--bg-card); backdrop-filter: blur(20px); border: 1px solid var(--border); border-radius: 20px; padding: 2.5rem; text-align: center; transition: all 0.4s ease; cursor: pointer; position: relative; overflow: hidden; } .service-card::before { content: ''; position: absolute; top: 0; left: 0; right: 0; height: 4px; background: linear-gradient(135deg, var(--primary), var(--accent)); transform: scaleX(0); transition: transform 0.3s ease; } .service-card:hover::before { transform: scaleX(1); } .service-card:hover { transform: translateY(-8px); border-color: var(--primary); box-shadow: var(--shadow-2xl); } .service-icon { font-size: 4rem; background: linear-gradient(135deg, var(--primary), var(--accent)); -webkit-background-clip: text; -webkit-text-fill-color: transparent; margin-bottom: 1.5rem; display: block; } .service-title { font-size: 1.5rem; font-weight: 700; color: var(--text-primary); margin-bottom: 1rem; } .service-description { color: var(--text-secondary); line-height: 1.6; margin-bottom: 2rem; } .service-button { background: linear-gradient(135deg, var(--primary), var(--primary-light)) !important; border: none !important; border-radius: 50px !important; padding: 0.875rem 2rem !important; font-weight: 600 !important; color: white !important; text-transform: uppercase !important; letter-spacing: 0.5px !important; transition: all 0.3s ease !important; cursor: pointer !important; } .service-button:hover { transform: translateY(-2px) !important; box-shadow: var(--shadow-lg) !important; } /* Chat Interface */ .dark-section .chatbot-page { background: linear-gradient(135deg, var(--bg-primary), var(--bg-secondary)); min-height: 100vh; display: flex; flex-direction: column; } .dark-section .chatbot-header { background: var(--bg-card); backdrop-filter: blur(20px); border-bottom: 1px solid var(--border); padding: 1.5rem 2rem; color: var(--text-primary); } /* 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; } .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; } .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; } .gradio-button:hover { transform: translateY(-2px) !important; box-shadow: var(--shadow-xl) !important; background: linear-gradient(135deg, var(--primary-light), var(--primary)) !important; } /* Page visibility fixes */ .gradio-column { display: flex !important; flex-direction: column !important; } .gradio-row { display: flex !important; } /* Responsive Design */ @media (max-width: 768px) { .cover-buttons { flex-direction: column; align-items: center; } .cover-btn { width: 100% !important; max-width: 300px !important; } .services-grid { grid-template-columns: 1fr; gap: 1.5rem; } } /* Loading states */ .loading { opacity: 0.7; pointer-events: none; } .loading::after { content: ''; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 20px; height: 20px; border: 2px solid var(--primary); border-top: 2px solid transparent; border-radius: 50%; animation: spin 1s linear infinite; } @keyframes spin { 0% { transform: translate(-50%, -50%) rotate(0deg); } 100% { transform: translate(-50%, -50%) rotate(360deg); } } /* Prevent unwanted animations */ .cover-page .cover-hero { position: relative !important; transform: none !important; animation: none !important; } .cover-page .cover-title { position: relative !important; transform: none !important; animation: none !important; } """ # Create the multi-page application def create_multipage_app(): with gr.Blocks( theme=gr.themes.Soft( primary_hue=gr.themes.colors.blue, secondary_hue=gr.themes.colors.green, neutral_hue=gr.themes.colors.slate, ), title="⚡ Power Systems Consultant", css=ENHANCED_CSS ) as app: # Global state management current_page = gr.State("cover") user_state = gr.State(None) session_state = gr.State(None) # 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: with gr.HTML() as cover_content: gr.HTML("""
Advanced AI-powered platform for electrical power systems analysis, fault calculations, protection design, and engineering excellence. Experience the future of power systems consulting.
Sign in to your Power Systems workspace
Create your Power Systems workspace
Choose your engineering tool and start analyzing power systems
Ready to tackle power systems challenges?
Interactive chat with AI expert for fault analysis, protection systems, calculations, and engineering guidance with diagram generation.
Generate customized practice questions with detailed solutions, step-by-step calculations, and standards references for exam prep.
Comprehensive explanations of IEEE, IEC, and international standards with practical applications and implementation guidelines.
Essential formulas, concepts, calculations, and comprehensive exam preparation materials for power systems engineering.
Professional engineering diagrams will appear here
AI-generated practice questions with detailed solutions
Comprehensive power systems standards library
Essential formulas and exam preparation materials
I_fault = V_nominal / Z_total
I_fault = 3 × V_nominal / (Z1 + Z2 + Z0)
I_fault = √3 × V_nominal / (Z1 + Z2)
P = √3 × V × I × cos(φ)
Q = √3 × V × I × sin(φ)
Enter values and click Calculate
Professional engineering diagrams will appear here
Professional engineering diagrams will appear here
{p:.2f} kW
{q:.2f} kVAR
{s:.2f} kVA
Please enter valid values for all fields