ashhal/Power_Systems_Mini-Consultant
0
1def create_multipage_app():2 with gr.Blocks(3 theme=gr.themes.Soft(4 primary_hue=gr.themes.colors.blue,5 secondary_hue=gr.themes.colors.green,6 neutral_hue=gr.themes.colors.slate,7 ),8 title="⚡ Power Systems Consultant - Enhanced",9 css=ENHANCED_CSS10 ) as app:11 12 # Global state management13 current_page = gr.State("cover")14 user_state = gr.State(None)15 session_state = gr.State(None)16 17 # Page 1: Cover Page (Always visible initially)18 with gr.Column(visible=True, elem_classes=["cover-page"]) as cover_page:19 with gr.HTML() as cover_content:20 gr.HTML("""21 <div class="cover-hero">22 <div class="cover-icon">⚡</div>23 <h1 class="cover-title">Power Systems Consultant</h1>24 <p class="cover-subtitle">25 Advanced AI-powered platform for electrical power systems analysis, fault calculations, 26 protection design, and engineering excellence. Experience the future of power systems consulting.27 </p>28 </div>29 """)30 31 with gr.Row():32 signin_nav_btn = gr.Button("🔐 Sign Inimport gradio as gr33import os34import json35import time36import uuid37from datetime import datetime38from groq import Groq39import pandas as pd40from typing import Dict, List, Tuple, Optional41import re42import hashlib43import sqlite344import sys45 46# Add utils directory to path47sys.path.append(os.path.join(os.path.dirname(__file__), 'utils'))48 49# Import your external utilities50try:51 from utils.diagram_generator import DiagramGenerator as ExternalDiagramGenerator52 from utils.rag_system import RAGSystem53 EXTERNAL_UTILS_AVAILABLE = True54 print("✅ External utilities loaded successfully!")55except ImportError as e:56 print(f"⚠️ External utilities not found: {e}")57 print(" Using internal implementations...")58 EXTERNAL_UTILS_AVAILABLE = False59 60# Initialize components with better error handling61def get_groq_client():62 api_key = os.getenv("GROQ_API_KEY")63 if not api_key:64 print("⚠️ GROQ_API_KEY not found. Using demo mode.")65 return None66 try:67 return Groq(api_key=api_key)68 except Exception as e:69 print(f"❌ Groq client initialization failed: {e}")70 return None71 72class UserManager:73 def __init__(self):74 self.db_path = 'users.db'75 self.init_database()76 77 def init_database(self):78 """Initialize SQLite database for users"""79 try:80 conn = sqlite3.connect(self.db_path)81 cursor = conn.cursor()82 83 cursor.execute('''84 CREATE TABLE IF NOT EXISTS users (85 id INTEGER PRIMARY KEY AUTOINCREMENT,86 username TEXT UNIQUE NOT NULL,87 email TEXT UNIQUE NOT NULL,88 password_hash TEXT NOT NULL,89 full_name TEXT,90 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,91 last_login TIMESTAMP92 )93 ''')94 95 cursor.execute('''96 CREATE TABLE IF NOT EXISTS chat_sessions (97 id INTEGER PRIMARY KEY AUTOINCREMENT,98 user_id INTEGER,99 session_id TEXT UNIQUE,100 title TEXT,101 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,102 updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,103 FOREIGN KEY (user_id) REFERENCES users (id)104 )105 ''')106 107 cursor.execute('''108 CREATE TABLE IF NOT EXISTS messages (109 id INTEGER PRIMARY KEY AUTOINCREMENT,110 session_id TEXT,111 role TEXT,112 content TEXT,113 timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP,114 FOREIGN KEY (session_id) REFERENCES chat_sessions (session_id)115 )116 ''')117 118 conn.commit()119 conn.close()120 print("✅ Database initialized successfully")121 except Exception as e:122 print(f"❌ Database initialization failed: {e}")123 124 def hash_password(self, password: str) -> str:125 """Hash password using SHA-256"""126 return hashlib.sha256(password.encode()).hexdigest()127 128 def create_user(self, username: str, email: str, password: str, full_name: str = "") -> Tuple[bool, str]:129 """Create new user account"""130 try:131 conn = sqlite3.connect(self.db_path)132 cursor = conn.cursor()133 134 password_hash = self.hash_password(password)135 cursor.execute(136 "INSERT INTO users (username, email, password_hash, full_name) VALUES (?, ?, ?, ?)",137 (username, email, password_hash, full_name)138 )139 140 conn.commit()141 conn.close()142 return True, "Account created successfully!"143 144 except sqlite3.IntegrityError as e:145 if "username" in str(e):146 return False, "Username already exists"147 elif "email" in str(e):148 return False, "Email already registered"149 else:150 return False, "Registration failed"151 except Exception as e:152 return False, f"Error: {str(e)}"153 154 def authenticate_user(self, username: str, password: str) -> Tuple[bool, Optional[Dict]]:155 """Authenticate user login"""156 try:157 conn = sqlite3.connect(self.db_path)158 cursor = conn.cursor()159 160 password_hash = self.hash_password(password)161 cursor.execute(162 "SELECT id, username, email, full_name FROM users WHERE username = ? AND password_hash = ?",163 (username, password_hash)164 )165 166 user = cursor.fetchone()167 168 if user:169 cursor.execute(170 "UPDATE users SET last_login = CURRENT_TIMESTAMP WHERE id = ?",171 (user[0],)172 )173 conn.commit()174 175 user_data = {176 'id': user[0],177 'username': user[1],178 'email': user[2],179 'full_name': user[3] or user[1]180 }181 conn.close()182 return True, user_data183 184 conn.close()185 return False, None186 187 except Exception as e:188 print(f"Authentication error: {e}")189 return False, None190 191# Enhanced diagram generator with more diagram types192class InternalDiagramGenerator:193 def generate_single_line_diagram(self, config: Dict) -> str:194 """Generate single line diagram SVG"""195 return f"""196 <svg width="800" height="500" viewBox="0 0 800 500" xmlns="http://www.w3.org/2000/svg">197 <!-- Background -->198 <rect width="800" height="500" fill="#f8fafc" stroke="#cbd5e1" stroke-width="2" rx="10"/>199 <text x="400" y="30" text-anchor="middle" font-family="Arial" font-size="20" font-weight="bold" fill="#1e293b">200 Single Line Diagram - Power System201 </text>202 203 <!-- Generator -->204 <circle cx="100" cy="250" r="40" fill="none" stroke="#3b82f6" stroke-width="3"/>205 <text x="100" y="255" text-anchor="middle" font-family="Arial" font-size="14" font-weight="bold" fill="#3b82f6">G</text>206 <text x="100" y="300" text-anchor="middle" font-family="Arial" font-size="10" fill="#3b82f6">Generator</text>207 208 <!-- Connection to Transformer 1 -->209 <line x1="140" y1="250" x2="200" y2="250" stroke="#1e293b" stroke-width="3"/>210 211 <!-- Transformer 1 -->212 <circle cx="220" cy="230" r="15" fill="none" stroke="#ef4444" stroke-width="2"/>213 <circle cx="220" cy="270" r="15" fill="none" stroke="#ef4444" stroke-width="2"/>214 <line x1="205" y1="250" x2="235" y2="250" stroke="#ef4444" stroke-width="2"/>215 <text x="220" y="205" text-anchor="middle" font-family="Arial" font-size="12" font-weight="bold" fill="#ef4444">T1</text>216 <text x="220" y="300" text-anchor="middle" font-family="Arial" font-size="9" fill="#ef4444">25kV/138kV</text>217 218 <!-- Connection to Bus -->219 <line x1="235" y1="250" x2="320" y2="250" stroke="#1e293b" stroke-width="3"/>220 221 <!-- Main Bus -->222 <rect x="320" y="240" width="160" height="20" fill="none" stroke="#10b981" stroke-width="4"/>223 <text x="400" y="235" text-anchor="middle" font-family="Arial" font-size="12" font-weight="bold" fill="#10b981">138kV Bus</text>224 225 <!-- Transmission Line 1 -->226 <line x1="480" y1="250" x2="550" y2="250" stroke="#1e293b" stroke-width="3"/>227 <line x1="515" y1="235" x2="515" y2="265" stroke="#8b5cf6" stroke-width="2"/>228 <line x1="510" y1="240" x2="520" y2="240" stroke="#8b5cf6" stroke-width="2"/>229 <line x1="510" y1="260" x2="520" y2="260" stroke="#8b5cf6" stroke-width="2"/>230 <text x="515" y="220" text-anchor="middle" font-family="Arial" font-size="10" fill="#8b5cf6">Line 1</text>231 232 <!-- Load Bus -->233 <circle cx="600" cy="250" r="25" fill="none" stroke="#f59e0b" stroke-width="3"/>234 <text x="600" y="255" text-anchor="middle" font-family="Arial" font-size="12" font-weight="bold" fill="#f59e0b">Load</text>235 <text x="600" y="285" text-anchor="middle" font-family="Arial" font-size="9" fill="#f59e0b">Industrial</text>236 237 <!-- Protection Elements -->238 <rect x="170" y="240" width="20" height="20" fill="none" stroke="#dc2626" stroke-width="2"/>239 <text x="180" y="252" text-anchor="middle" font-family="Arial" font-size="8" fill="#dc2626">CB</text>240 241 <rect x="290" y="240" width="20" height="20" fill="none" stroke="#dc2626" stroke-width="2"/>242 <text x="300" y="252" text-anchor="middle" font-family="Arial" font-size="8" fill="#dc2626">CB</text>243 244 <!-- Legend -->245 <rect x="20" y="350" width="200" height="120" fill="white" stroke="#cbd5e1" stroke-width="1" rx="5"/>246 <text x="120" y="370" text-anchor="middle" font-family="Arial" font-size="12" font-weight="bold" fill="#1e293b">Legend</text>247 248 <circle cx="40" cy="390" r="8" fill="none" stroke="#3b82f6" stroke-width="2"/>249 <text x="55" y="395" font-family="Arial" font-size="10" fill="#1e293b">Generator</text>250 251 <rect x="32" y="405" width="16" height="10" fill="none" stroke="#dc2626" stroke-width="1"/>252 <text x="55" y="413" font-family="Arial" font-size="10" fill="#1e293b">Circuit Breaker</text>253 254 <circle cx="35" cy="430" r="5" fill="none" stroke="#ef4444" stroke-width="1"/>255 <circle cx="45" cy="430" r="5" fill="none" stroke="#ef4444" stroke-width="1"/>256 <text x="55" y="435" font-family="Arial" font-size="10" fill="#1e293b">Transformer</text>257 258 <rect x="32" y="445" width="16" height="8" fill="none" stroke="#10b981" stroke-width="2"/>259 <text x="55" y="452" font-family="Arial" font-size="10" fill="#1e293b">Bus</text>260 </svg>261 """262 263 def generate_protection_diagram(self, config: Dict) -> str:264 """Generate protection scheme diagram"""265 return """266 <svg width="900" height="600" viewBox="0 0 900 600" xmlns="http://www.w3.org/2000/svg">267 <!-- Background -->268 <rect width="900" height="600" fill="#f8fafc" stroke="#cbd5e1" stroke-width="2" rx="10"/>269 <text x="450" y="30" text-anchor="middle" font-family="Arial" font-size="20" font-weight="bold" fill="#1e293b">270 Power System Protection Scheme271 </text>272 273 <!-- Generator and Protection -->274 <g transform="translate(50,100)">275 <!-- Generator -->276 <circle cx="60" cy="100" r="40" fill="none" stroke="#3b82f6" stroke-width="3"/>277 <text x="60" y="105" text-anchor="middle" font-family="Arial" font-size="14" fill="#3b82f6">G</text>278 279 <!-- Generator Protection -->280 <rect x="40" y="50" width="40" height="25" fill="#fef3c7" stroke="#f59e0b" stroke-width="2" rx="3"/>281 <text x="60" y="67" text-anchor="middle" font-family="Arial" font-size="9" fill="#92400e">87G</text>282 283 <!-- Overcurrent Relay -->284 <rect x="110" y="85" width="30" height="30" fill="#ddd6fe" stroke="#8b5cf6" stroke-width="2" rx="3"/>285 <text x="125" y="105" text-anchor="middle" font-family="Arial" font-size="10" fill="#6b46c1">51</text>286 287 <!-- Circuit Breaker -->288 <rect x="150" y="90" width="20" height="20" fill="none" stroke="#dc2626" stroke-width="3"/>289 <line x1="155" y1="95" x2="165" y2="105" stroke="#dc2626" stroke-width="2"/>290 <text x="160" y="125" text-anchor="middle" font-family="Arial" font-size="8" fill="#dc2626">52G</text>291 </g>292 293 <!-- Transformer and Protection -->294 <g transform="translate(300,100)">295 <!-- Transformer -->296 <circle cx="40" cy="80" r="20" fill="none" stroke="#ef4444" stroke-width="2"/>297 <circle cx="40" cy="120" r="20" fill="none" stroke="#ef4444" stroke-width="2"/>298 <text x="40" y="65" text-anchor="middle" font-family="Arial" font-size="12" fill="#ef4444">T1</text>299 300 <!-- Differential Protection -->301 <rect x="15" y="40" width="50" height="20" fill="#fef3c7" stroke="#f59e0b" stroke-width="2" rx="3"/>302 <text x="40" y="53" text-anchor="middle" font-family="Arial" font-size="10" fill="#92400e">87T</text>303 304 <!-- Buchholz Relay -->305 <rect x="70" y="90" width="35" height="20" fill="#dcfce7" stroke="#16a34a" stroke-width="2" rx="3"/>306 <text x="87" y="103" text-anchor="middle" font-family="Arial" font-size="9" fill="#15803d">63</text>307 308 <!-- OLTC Protection -->309 <rect x="15" y="150" width="50" height="20" fill="#dbeafe" stroke="#2563eb" stroke-width="2" rx="3"/>310 <text x="40" y="163" text-anchor="middle" font-family="Arial" font-size="9" fill="#1d4ed8">OLTC</text>311 </g>312 313 <!-- Transmission Line and Protection -->314 <g transform="translate(450,100)">315 <!-- Line -->316 <line x1="0" y1="100" x2="150" y2="100" stroke="#1e293b" stroke-width="3"/>317 <line x1="75" y1="85" x2="75" y2="115" stroke="#8b5cf6" stroke-width="2"/>318 319 <!-- Distance Protection -->320 <rect x="30" y="60" width="30" height="25" fill="#fde68a" stroke="#f59e0b" stroke-width="2" rx="3"/>321 <text x="45" y="77" text-anchor="middle" font-family="Arial" font-size="10" fill="#92400e">21</text>322 323 <!-- Pilot Protection -->324 <rect x="90" y="60" width="30" height="25" fill="#fecaca" stroke="#ef4444" stroke-width="2" rx="3"/>325 <text x="105" y="77" text-anchor="middle" font-family="Arial" font-size="10" fill="#dc2626">85</text>326 327 <!-- Communication -->328 <path d="M 45 60 L 105 60" stroke="#6b7280" stroke-width="1" stroke-dasharray="3,3"/>329 <text x="75" y="45" text-anchor="middle" font-family="Arial" font-size="8" fill="#6b7280">Pilot Wire</text>330 </g>331 332 <!-- Bus Protection -->333 <g transform="translate(650,100)">334 <!-- Bus -->335 <rect x="0" y="90" width="100" height="20" fill="none" stroke="#10b981" stroke-width="4"/>336 <text x="50" y="85" text-anchor="middle" font-family="Arial" font-size="12" fill="#10b981">Main Bus</text>337 338 <!-- Bus Differential -->339 <rect x="25" y="50" width="50" height="25" fill="#fef3c7" stroke="#f59e0b" stroke-width="2" rx="3"/>340 <text x="50" y="67" text-anchor="middle" font-family="Arial" font-size="10" fill="#92400e">87B</text>341 342 <!-- Bus Protection -->343 <rect x="25" y="130" width="50" height="25" fill="#e0e7ff" stroke="#6366f1" stroke-width="2" rx="3"/>344 <text x="50" y="147" text-anchor="middle" font-family="Arial" font-size="10" fill="#4f46e5">50BF</text>345 </g>346 347 <!-- Protection Coordination Chart -->348 <g transform="translate(50,350)">349 <rect x="0" y="0" width="400" height="200" fill="white" stroke="#cbd5e1" stroke-width="2" rx="5"/>350 <text x="200" y="20" text-anchor="middle" font-family="Arial" font-size="14" font-weight="bold" fill="#1e293b">351 Time-Current Coordination352 </text>353 354 <!-- Axes -->355 <line x1="50" y1="180" x2="350" y2="180" stroke="#374151" stroke-width="2"/>356 <line x1="50" y1="50" x2="50" y2="180" stroke="#374151" stroke-width="2"/>357 358 <!-- Labels -->359 <text x="200" y="200" text-anchor="middle" font-family="Arial" font-size="10" fill="#374151">Current (A)</text>360 <text x="20" y="115" text-anchor="middle" font-family="Arial" font-size="10" fill="#374151" transform="rotate(-90, 20, 115)">Time (s)</text>361 362 <!-- Curves -->363 <path d="M 70 160 Q 150 120 250 80 Q 300 60 330 50" stroke="#ef4444" stroke-width="2" fill="none"/>364 <text x="270" y="70" font-family="Arial" font-size="8" fill="#ef4444">Generator (51G)</text>365 366 <path d="M 90 170 Q 180 130 280 90 Q 320 70 340 60" stroke="#8b5cf6" stroke-width="2" fill="none"/>367 <text x="290" y="90" font-family="Arial" font-size="8" fill="#8b5cf6">Feeder (51F)</text>368 </g>369 370 <!-- Device Legend -->371 <rect x="500" y="350" width="350" height="200" fill="white" stroke="#cbd5e1" stroke-width="2" rx="5"/>372 <text x="675" y="370" text-anchor="middle" font-family="Arial" font-size="14" font-weight="bold" fill="#1e293b">373 IEEE Device Numbers374 </text>375 376 <g transform="translate(520,380)">377 <text x="0" y="15" font-family="Arial" font-size="11" font-weight="bold" fill="#ef4444">21 - Distance Relay</text>378 <text x="0" y="35" font-family="Arial" font-size="11" font-weight="bold" fill="#8b5cf6">51 - AC Time Overcurrent</text>379 <text x="0" y="55" font-family="Arial" font-size="11" font-weight="bold" fill="#dc2626">52 - AC Circuit Breaker</text>380 <text x="0" y="75" font-family="Arial" font-size="11" font-weight="bold" fill="#16a34a">63 - Pressure Switch</text>381 <text x="0" y="95" font-family="Arial" font-size="11" font-weight="bold" fill="#ef4444">85 - Carrier/Pilot Relay</text>382 383 <text x="170" y="15" font-family="Arial" font-size="11" font-weight="bold" fill="#f59e0b">87 - Differential Relay</text>384 <text x="170" y="35" font-family="Arial" font-size="11" font-weight="bold" fill="#f59e0b">87G - Generator Differential</text>385 <text x="170" y="55" font-family="Arial" font-size="11" font-weight="bold" fill="#f59e0b">87T - Transformer Differential</text>386 <text x="170" y="75" font-family="Arial" font-size="11" font-weight="bold" fill="#f59e0b">87B - Bus Differential</text>387 <text x="170" y="95" font-family="Arial" font-size="11" font-weight="bold" fill="#6366f1">50BF - Breaker Failure</text>388 </g>389 390 <text x="450" y="580" text-anchor="middle" font-family="Arial" font-size="10" fill="#64748b">391 Comprehensive protection scheme with coordination and backup protection392 </text>393 </svg>394 """395 396class PowerSystemsConsultant:397 def __init__(self):398 self.groq_client = get_groq_client()399 400 # Initialize diagram generator (external or internal)401 if EXTERNAL_UTILS_AVAILABLE:402 try:403 self.diagram_generator = ExternalDiagramGenerator()404 print("✅ Using external DiagramGenerator")405 except Exception as e:406 print(f"⚠️ External DiagramGenerator failed: {e}")407 self.diagram_generator = InternalDiagramGenerator()408 print(" Falling back to internal DiagramGenerator")409 else:410 self.diagram_generator = InternalDiagramGenerator()411 print("📐 Using internal DiagramGenerator")412 413 # Initialize RAG system if available414 if EXTERNAL_UTILS_AVAILABLE:415 try:416 self.rag_system = RAGSystem()417 print("✅ RAG System initialized successfully")418 self.has_rag = True419 except Exception as e:420 print(f"⚠️ RAG System initialization failed: {e}")421 print(" Continuing without RAG capabilities")422 self.rag_system = None423 self.has_rag = False424 else:425 self.rag_system = None426 self.has_rag = False427 print("📚 RAG System not available")428 429 try:430 self.user_manager = UserManager()431 except Exception as e:432 print(f"❌ UserManager initialization failed: {e}")433 self.user_manager = None434 435 self.current_user = None436 self.current_session = None437 438 def generate_demo_response(self, user_query: str, chat_history: List[Tuple[str, str]]) -> Tuple[str, str]:439 """Generate demo response when Groq API is not available"""440 demo_responses = {441 "fault": "**Fault Analysis Demo Response:**\n\nFor a three-phase fault, the fault current is calculated as:\n\n`I_fault = V_nominal / Z_total`\n\nWhere:\n- V_nominal is the system nominal voltage\n- Z_total is the total impedance to the fault point\n\nThis includes positive sequence impedance of generators, transformers, and lines up to the fault location.",442 "protection": "**Protection System Demo Response:**\n\nPower system protection involves multiple layers:\n\n1. **Primary Protection**: Fastest, most selective (e.g., differential relays)\n2. **Backup Protection**: Slower but covers larger area (e.g., overcurrent relays)\n3. **Emergency Protection**: Last resort (e.g., under-frequency load shedding)\n\nCoordination ensures proper sequence and selectivity between protection devices.",443 "transformer": "**Transformer Demo Response:**\n\nTransformer protection typically includes:\n\n- **87T**: Differential protection (primary)\n- **51**: Overcurrent protection (backup)\n- **63**: Buchholz relay (gas accumulation)\n- **26**: Thermal protection\n- **71**: Gas density relay (SF6)\n\nThe transformer equivalent circuit uses T or π models for analysis.",444 "default": "**Power Systems AI Consultant (Demo Mode):**\n\nI can help with fault analysis, protection systems, load flow studies, stability analysis, and more. This is demo mode - please set GROQ_API_KEY for full functionality.\n\n**Common Topics:**\n- Short circuit calculations\n- Protection coordination\n- Power quality analysis\n- Equipment sizing\n- Standards interpretation"445 }446 447 # Simple keyword matching for demo448 query_lower = user_query.lower()449 if any(word in query_lower for word in ['fault', 'short circuit']):450 response = demo_responses["fault"]451 elif any(word in query_lower for word in ['protection', 'relay', 'coordination']):452 response = demo_responses["protection"]453 elif any(word in query_lower for word in ['transformer', 'differential']):454 response = demo_responses["transformer"]455 else:456 response = demo_responses["default"]457 458 # Check for diagram request459 diagram_svg = None460 if any(keyword in query_lower for keyword in ['diagram', 'single line', 'drawing', 'circuit', 'protection scheme']):461 try:462 if 'protection' in query_lower:463 diagram_svg = self.diagram_generator.generate_protection_diagram({})464 else:465 diagram_svg = self.diagram_generator.generate_single_line_diagram({})466 except Exception as e:467 print(f"Demo diagram generation error: {e}")468 469 return response, diagram_svg470 471 def generate_response(self, user_query: str, chat_history: List[Tuple[str, str]], session_id: str = None) -> Tuple[str, str]:472 """Generate response using Groq LLM with optional RAG enhancement"""473 # Use demo mode if Groq client is not available474 if not self.groq_client:475 return self.generate_demo_response(user_query, chat_history)476 477 try:478 # Check if query is asking for a diagram479 diagram_svg = None480 diagram_requested = any(keyword in user_query.lower() for keyword in 481 ['diagram', 'single line', 'drawing', 'circuit', 'protection scheme'])482 483 if diagram_requested:484 try:485 # Try different diagram types based on query486 if 'protection' in user_query.lower():487 if hasattr(self.diagram_generator, 'generate_protection_diagram'):488 diagram_svg = self.diagram_generator.generate_protection_diagram({})489 else:490 diagram_svg = self.diagram_generator.generate_single_line_diagram({})491 else:492 diagram_svg = self.diagram_generator.generate_single_line_diagram({})493 except Exception as e:494 print(f"Diagram generation error: {e}")495 diagram_svg = None496 497 # Enhanced system prompt498 system_prompt = """You are a Power Systems Expert AI assistant specializing in electrical power systems. 499 You help with fault analysis, protection systems, standards interpretation, and engineering calculations.500 Provide clear, technical explanations with practical examples and safety considerations.501 502 When users request diagrams, explain that diagrams are being generated separately.503 Focus on providing detailed technical explanations alongside visual representations."""504 505 # Use RAG for enhanced context if available506 if self.has_rag and self.rag_system:507 try:508 # Get relevant context from RAG system509 relevant_docs = self.rag_system.query(user_query, top_k=3)510 if relevant_docs:511 context = "\n".join([doc['content'] for doc in relevant_docs])512 system_prompt += f"\n\nRelevant technical context:\n{context}"513 except Exception as e:514 print(f"RAG query error: {e}")515 516 # Prepare conversation context517 messages = [{"role": "system", "content": system_prompt}]518 519 # Add chat history (last 5 exchanges)520 for human_msg, ai_msg in chat_history[-5:]:521 if human_msg and ai_msg: # Ensure messages are not None522 messages.append({"role": "user", "content": human_msg})523 messages.append({"role": "assistant", "content": ai_msg})524 525 # Add current query526 messages.append({"role": "user", "content": user_query})527 528 # Generate response using Groq529 response = self.groq_client.chat.completions.create(530 model="llama3-70b-8192",531 messages=messages,532 max_tokens=2000,533 temperature=0.8534 )535 536 text_response = response.choices[0].message.content537 538 # Add RAG attribution if used539 if self.has_rag and any(keyword in user_query.lower() for keyword in ['standard', 'code', 'regulation']):540 text_response += "\n\n*Enhanced with technical documentation database*"541 542 return text_response, diagram_svg543 544 except Exception as e:545 error_msg = f"Error generating response: {str(e)}. Falling back to demo mode."546 print(error_msg)547 return self.generate_demo_response(user_query, chat_history)548 549 def generate_practice_pack(self, topic: str, difficulty: str, num_questions: int) -> str:550 """Generate practice questions pack with optional RAG enhancement"""551 if not self.groq_client:552 return self.generate_demo_practice_pack(topic, difficulty, num_questions)553 554 try:555 # Enhanced prompt with RAG context if available556 practice_prompt = f"""Generate {num_questions} power systems practice questions about {topic} at {difficulty} level.557 Format with numbered questions, multiple choice options, and detailed solutions."""558 559 # Add RAG context for practice questions if available560 if self.has_rag and self.rag_system:561 try:562 topic_docs = self.rag_system.query(f"{topic} practice questions examples", top_k=2)563 if topic_docs:564 context = "\n".join([doc['content'][:500] for doc in topic_docs])565 practice_prompt += f"\n\nReference context:\n{context}"566 except Exception as e:567 print(f"RAG practice enhancement error: {e}")568 569 messages = [570 {"role": "system", "content": "You are an expert power systems engineer creating practice questions."},571 {"role": "user", "content": practice_prompt}572 ]573 574 response = self.groq_client.chat.completions.create(575 model="llama3-70b-8192",576 messages=messages,577 max_tokens=3000,578 temperature=0.7579 )580 581 result = response.choices[0].message.content582 583 if self.has_rag:584 result += "\n\n*Practice questions enhanced with technical documentation*"585 586 return result587 588 except Exception as e:589 print(f"Practice generation error: {e}")590 return self.generate_demo_practice_pack(topic, difficulty, num_questions)591 592 def generate_demo_practice_pack(self, topic: str, difficulty: str, num_questions: int) -> str:593 """Generate demo practice questions when API is not available"""594 demo_questions = {595 "Fault Analysis": f"""596# {topic} Practice Pack - {difficulty} Level (Demo Mode)597 598## Question 1: Three-Phase Fault Analysis599A three-phase fault occurs at a bus with the following system data:600- System voltage: 138 kV601- Generator reactance: j0.15 pu602- Transformer reactance: j0.10 pu603- Line reactance: j0.08 pu604 605**Calculate the fault current in amperes.**606 607**Options:**608A) 12,500 A609B) 15,240 A 610C) 18,960 A611D) 21,340 A612 613**Solution:**614Total reactance = 0.15 + 0.10 + 0.08 = 0.33 pu615Base current = 100 MVA / (√3 × 138 kV) = 418.4 A616Fault current = 418.4 / 0.33 = 12,677 A ≈ **12,500 A (Answer: A)**617 618---619 620## Question 2: Symmetrical Components621For an unbalanced system with line currents:622- Ia = 100∠0° A623- Ib = 80∠-130° A 624- Ic = 60∠110° A625 626**Calculate the positive sequence current I₁.**627 628**Solution:**629I₁ = (1/3)[Ia + a×Ib + a²×Ic]630Where a = 1∠120°631 632This is a demo version. Set GROQ_API_KEY for complete practice packs.633 """,634 "Protection Systems": f"""635# {topic} Practice Pack - {difficulty} Level (Demo Mode)636 637## Question 1: Overcurrent Relay Coordination638Two overcurrent relays are installed in series:639- Relay A: CT ratio 800:5, Time dial 0.5640- Relay B: CT ratio 400:5, Time dial 0.3641- Coordination time interval: 0.3 seconds642 643**For a fault current of 6000 A, calculate the operating time of each relay.**644 645**Solution:**646Primary current through Relay A = 6000 A647Secondary current = 6000 × (5/800) = 37.5 A648Using standard inverse curve equation...649 650This is a demo version. Set GROQ_API_KEY for complete solutions.651 652---653 654## Question 2: Distance Relay Zones655A 100-mile transmission line has the following protection zones:656- Zone 1: 80% of line657- Zone 2: 120% of line + 50% of next line658- Zone 3: 200% of line659 660**Calculate the reach settings for each zone if line impedance is 0.8 Ω/mile.**661 662This is a demo version with {num_questions} questions requested.663 """664 }665 666 return demo_questions.get(topic, f"""667# {topic} Practice Pack - {difficulty} Level (Demo Mode)668 669## Demo Content670This is a demo version of the practice pack generator.671 672**Topics Available:**673- Fault Analysis674- Protection Systems 675- Power Flow Studies676- Stability Analysis677- Harmonics & Power Quality678 679**To unlock full functionality:**6801. Set your GROQ_API_KEY environment variable6812. Restart the application6823. Generate comprehensive practice packs with detailed solutions683 684**Demo Features:**685- {num_questions} questions requested686- {difficulty} difficulty level687- Topic: {topic}688 689Set GROQ_API_KEY for complete practice generation!690 """)691 692 def explain_standard(self, standard: str) -> str:693 """Explain power systems standard with RAG enhancement"""694 if not self.groq_client:695 return self.generate_demo_standard_explanation(standard)696 697 try:698 standard_prompt = f"""Provide a comprehensive explanation of the {standard} standard including 699 purpose, key requirements, practical applications, and implementation considerations."""700 701 # Enhanced with RAG if available702 if self.has_rag and self.rag_system:703 try:704 standard_docs = self.rag_system.query(f"{standard} standard explanation", top_k=3)705 if standard_docs:706 context = "\n".join([doc['content'] for doc in standard_docs])707 standard_prompt += f"\n\nTechnical documentation context:\n{context}"708 except Exception as e:709 print(f"RAG standard enhancement error: {e}")710 711 messages = [712 {"role": "system", "content": "You are an expert in power systems standards."},713 {"role": "user", "content": standard_prompt}714 ]715 716 response = self.groq_client.chat.completions.create(717 model="llama3-70b-8192",718 messages=messages,719 max_tokens=2500,720 temperature=0.6721 )722 723 result = response.choices[0].message.content724 725 if self.has_rag:726 result += "\n\n*Enhanced with official standards documentation*"727 728 return result729 730 except Exception as e:731 print(f"Standard explanation error: {e}")732 return self.generate_demo_standard_explanation(standard)733 734 def generate_demo_standard_explanation(self, standard: str) -> str:735 """Generate demo standard explanation when API is not available"""736 demo_standards = {737 "IEEE C37.2 - Device Function Numbers": """738# IEEE C37.2 - Device Function Numbers (Demo Mode)739 740## Purpose741IEEE C37.2 defines standard device function numbers and contact designations for power system devices. This standard provides a universal numbering system for protective and control devices.742 743## Key Device Numbers744 745### Protection Devices746- **21** - Distance Relay747- **50** - Instantaneous Overcurrent748- **51** - Time Overcurrent 749- **67** - Directional Overcurrent750- **87** - Differential Relay751 752### Control & Monitoring753- **25** - Synchronizing Check754- **27** - Undervoltage Relay755- **59** - Overvoltage Relay756- **81** - Frequency Relay757 758### Circuit Breakers & Switches759- **52** - AC Circuit Breaker760- **89** - Line Switch761- **94** - Tripping Relay762 763## Practical Applications764- Standardized protection schemes765- Universal documentation766- Simplified maintenance767- International compatibility768 769**This is demo mode. Set GROQ_API_KEY for comprehensive standard explanations.**770 """,771 "IEEE 1547 - Distributed Generation": """772# IEEE 1547 - Distributed Generation (Demo Mode)773 774## Purpose775IEEE 1547 establishes criteria and requirements for interconnection of distributed resources (DR) with electric power systems (EPS).776 777## Key Requirements778### Voltage Regulation779- Voltage ride-through capabilities780- Power factor requirements781- Harmonic limits782 783### Protection Requirements 784- Anti-islanding protection785- Overvoltage/undervoltage protection786- Frequency protection787 788### Power Quality789- Total harmonic distortion limits790- Flicker requirements791- DC injection limits792 793**This is demo mode. Set GROQ_API_KEY for detailed standard analysis.**794 """795 }796 797 return demo_standards.get(standard, f"""798# {standard} (Demo Mode)799 800## Standard Overview801This standard covers important aspects of power system design, operation, or protection.802 803## Demo Content Available804The full explanation of {standard} would include:805 806- **Purpose & Scope**: Why this standard exists807- **Key Requirements**: Technical specifications808- **Applications**: Where and how it's used809- **Implementation**: Practical guidance810- **Updates**: Recent revisions and changes811 812## Access Full Content813Set GROQ_API_KEY environment variable to access:814- Comprehensive explanations815- Detailed technical requirements816- Implementation examples817- Related standards references818- Practical applications819 820**Demo mode provides limited information.**821 """)822 823 def create_chat_session(self, user_id: int, title: str = None) -> str:824 """Create new chat session"""825 session_id = str(uuid.uuid4())826 827 if not self.user_manager:828 return session_id829 830 try:831 conn = sqlite3.connect(self.user_manager.db_path)832 cursor = conn.cursor()833 834 cursor.execute(835 "INSERT INTO chat_sessions (user_id, session_id, title) VALUES (?, ?, ?)",836 (user_id, session_id, title or f"Chat {datetime.now().strftime('%m/%d %H:%M')}")837 )838 839 conn.commit()840 conn.close()841 842 return session_id843 844 except Exception as e:845 print(f"Session creation error: {e}")846 return session_id847 848# Initialize the consultant with enhanced error handling849try:850 consultant = PowerSystemsConsultant()851 if EXTERNAL_UTILS_AVAILABLE:852 if consultant.groq_client:853 initialization_status = "✅ Power Systems Consultant initialized with full functionality!"854 else:855 initialization_status = "⚠️ Power Systems Consultant initialized in demo mode (no GROQ_API_KEY)"856 else:857 initialization_status = "✅ Power Systems Consultant initialized with internal utilities!"858except Exception as e:859 consultant = None860 initialization_status = f"❌ Initialization failed: {str(e)}"861 862# Enhanced CSS with better responsiveness and accessibility863ENHANCED_CSS = """864@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&display=swap');865 866* {867 font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;868 box-sizing: border-box;869}870 871:root {872 --primary: #3b82f6;873 --primary-light: #60a5fa;874 --primary-dark: #2563eb;875 --secondary: #10b981;876 --secondary-light: #34d399;877 --accent: #8b5cf6;878 --warning: #f59e0b;879 --danger: #ef4444;880 --success: #10b981;881 882 --bg-primary: #f8fafc;883 --bg-secondary: #f1f5f9;884 --bg-tertiary: #e2e8f0;885 --bg-card: rgba(255, 255, 255, 0.95);886 --bg-glass: rgba(255, 255, 255, 0.8);887 888 --text-primary: #0f172a;889 --text-secondary: #475569;890 --text-muted: #64748b;891 892 --border: rgba(148, 163, 184, 0.3);893 --border-light: rgba(148, 163, 184, 0.2);894 895 --shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);896 --shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);897 --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1);898 --shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.1);899 --shadow-2xl: 0 25px 50px -12px rgba(0, 0, 0, 0.25);900}901 902/* Enhanced accessibility */903*:focus {904 outline: 2px solid var(--primary);905 outline-offset: 2px;906}907 908.gradio-container {909 background: linear-gradient(135deg, var(--bg-primary) 0%, var(--bg-secondary) 50%, var(--bg-tertiary) 100%);910 color: var(--text-primary);911 min-height: 100vh;912 padding: 0;913}914 915/* Cover page with fixed positioning */916.cover-page {917 min-height: 100vh;918 background: linear-gradient(135deg, 919 #f8fafc 0%, 920 #e2e8f0 30%,921 #cbd5e1 60%,922 #94a3b8 100%);923 display: flex !important;924 flex-direction: column !important;925 align-items: center !important;926 justify-content: center !important;927 text-align: center;928 padding: 2rem;929 position: relative;930 overflow: hidden;931}932 933.cover-page::before {934 content: '';935 position: absolute;936 top: 0;937 left: 0;938 right: 0;939 bottom: 0;940 background: 941 radial-gradient(circle at 20% 80%, rgba(59, 130, 246, 0.1) 0%, transparent 50%),942 radial-gradient(circle at 80% 20%, rgba(139, 92, 246, 0.1) 0%, transparent 50%),943 radial-gradient(circle at 40% 40%, rgba(16, 185, 129, 0.05) 0%, transparent 50%);944 pointer-events: none;945}946 947.cover-hero {948 z-index: 10;949 max-width: 800px;950 margin-bottom: 4rem;951 position: relative;952}953 954.cover-icon {955 font-size: 6rem;956 background: linear-gradient(135deg, var(--primary), var(--accent));957 -webkit-background-clip: text;958 -webkit-text-fill-color: transparent;959 margin-bottom: 2rem;960 display: block;961 line-height: 1;962 animation: pulse 2s ease-in-out infinite alternate;963}964 965@keyframes pulse {966 0% { transform: scale(1); }967 100% { transform: scale(1.05); }968}969 970.cover-title {971 font-size: clamp(2.5rem, 6vw, 4.5rem);972 font-weight: 800;973 background: linear-gradient(135deg, var(--text-primary), var(--text-secondary));974 -webkit-background-clip: text;975 -webkit-text-fill-color: transparent;976 margin-bottom: 1.5rem;977 line-height: 1.1;978 position: relative;979}980 981.cover-subtitle {982 font-size: clamp(1rem, 2.5vw, 1.25rem);983 color: var(--text-secondary);984 margin-bottom: 3rem;985 line-height: 1.6;986 max-width: 600px;987 margin-left: auto;988 margin-right: auto;989}990 991.cover-buttons {992 display: flex;993 gap: 2rem;994 flex-wrap: wrap;995 justify-content: center;996 z-index: 10;997 position: relative;998}999 1000.cover-btn {1001 padding: 1.25rem 3rem !important;1002 font-size: 1.1rem !important;1003 font-weight: 600 !important;1004 border-radius: 50px !important;1005 border: none !important;1006 cursor: pointer !important;1007 transition: all 0.3s ease !important;1008 text-transform: uppercase !important;1009 letter-spacing: 0.5px !important;1010 position: relative !important;1011 overflow: hidden !important;1012 min-width: 200px !important;1013 text-decoration: none !important;1014 display: inline-flex !important;1015 align-items: center !important;1016 justify-content: center !important;1017 gap: 0.5rem !important;1018}1019 1020.cover-btn-primary {1021 background: linear-gradient(135deg, var(--primary), var(--primary-light)) !important;1022 color: white !important;1023 box-shadow: var(--shadow-lg) !important;1024}1025 1026.cover-btn-secondary {1027 background: linear-gradient(135deg, var(--secondary), var(--secondary-light)) !important;1028 color: white !important;1029 box-shadow: var(--shadow-lg) !important;1030}1031 1032.cover-btn:hover {1033 transform: translateY(-3px) scale(1.05) !important;1034 box-shadow: var(--shadow-xl) !important;1035}1036 1037.cover-btn:active {1038 transform: translateY(-1px) scale(1.02) !important;1039}1040 1041/* Authentication Pages */1042.auth-page {1043 min-height: 100vh;1044 background: linear-gradient(135deg, #f8fafc, #e2e8f0);1045 display: flex;1046 align-items: center;1047 justify-content: center;1048 padding: 2rem;1049}1050 1051.auth-container {1052 background: var(--bg-card);1053 backdrop-filter: blur(20px);1054 border: 1px solid var(--border);1055 border-radius: 24px;1056 padding: 3rem;1057 width: 100%;1058 max-width: 450px;1059 box-shadow: var(--shadow-2xl);1060}1061 1062.auth-header {1063 text-align: center;1064 margin-bottom: 2.5rem;1065}1066 1067.auth-icon {1068 font-size: 3rem;1069 background: linear-gradient(135deg, var(--primary), var(--accent));1070 -webkit-background-clip: text;1071 -webkit-text-fill-color: transparent;1072 margin-bottom: 1rem;1073}1074 1075.auth-title {1076 font-size: 2rem;1077 font-weight: 700;1078 color: var(--text-primary);1079 margin-bottom: 0.5rem;1080}1081 1082.auth-subtitle {1083 color: var(--text-secondary);1084 font-size: 0.95rem;1085}1086 1087/* Services Page */1088.services-page {1089 min-height: 100vh;1090 background: linear-gradient(135deg, #f8fafc, #e2e8f0, #cbd5e1);1091 padding: 2rem;1092}1093 1094.services-header {1095 text-align: center;1096 margin-bottom: 4rem;1097 max-width: 800px;1098 margin-left: auto;1099 margin-right: auto;1100}1101 1102.services-title {1103 font-size: clamp(2.5rem, 6vw, 4rem);1104 font-weight: 800;1105 background: linear-gradient(135deg, var(--text-primary), var(--text-secondary));1106 -webkit-background-clip: text;1107 -webkit-text-fill-color: transparent;1108 margin-bottom: 1rem;1109}1110 1111.services-subtitle {1112 font-size: 1.2rem;1113 color: var(--text-secondary);1114 margin-bottom: 2rem;1115}1116 1117.user-welcome {1118 background: var(--bg-card);1119 border: 1px solid var(--border);1120 border-radius: 16px;1121 padding: 1.5rem;1122 margin-bottom: 2rem;1123 text-align: center;1124 backdrop-filter: blur(20px);1125 animation: fadeIn 0.5s ease-out;1126}1127 1128@keyframes fadeIn {1129 0% { opacity: 0; transform: translateY(20px); }1130 100% { opacity: 1; transform: translateY(0); }1131}1132 1133.services-grid {1134 display: grid;1135 grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));1136 gap: 2rem;1137 max-width: 1200px;1138 margin: 0 auto;1139}1140 1141.service-card {1142 background: var(--bg-card);1143 backdrop-filter: blur(20px);1144 border: 1px solid var(--border);1145 border-radius: 20px;1146 padding: 2.5rem;1147 text-align: center;1148 transition: all 0.4s ease;1149 cursor: pointer;1150 position: relative;1151 overflow: hidden;1152 animation: slideIn 0.6s ease-out;1153}1154 1155@keyframes slideIn {1156 0% { opacity: 0; transform: translateY(30px); }1157 100% { opacity: 1; transform: translateY(0); }1158}1159 1160.service-card::before {1161 content: '';1162 position: absolute;1163 top: 0;1164 left: 0;1165 right: 0;1166 height: 4px;1167 background: linear-gradient(135deg, var(--primary), var(--accent));1168 transform: scaleX(0);1169 transition: transform 0.3s ease;1170}1171 1172.service-card:hover::before {1173 transform: scaleX(1);1174}1175 1176.service-card:hover {1177 transform: translateY(-8px);1178 border-color: var(--primary);1179 box-shadow: var(--shadow-2xl);1180}1181 1182.service-icon {1183 font-size: 4rem;1184 background: linear-gradient(135deg, var(--primary), var(--accent));1185 -webkit-background-clip: text;1186 -webkit-text-fill-color: transparent;1187 margin-bottom: 1.5rem;1188 display: block;1189 transition: transform 0.3s ease;1190}1191 1192.service-card:hover .service-icon {1193 transform: scale(1.1) rotate(5deg);1194}1195 1196.service-title {1197 font-size: 1.5rem;1198 font-weight: 700;1199 color: var(--text-primary);1200 margin-bottom: 1rem;