CoolFace
Apppublic

ashhal/Power_Systems_Mini-Consultant

sourceHugging Facemitupdated 1y agoView on Hugging Face
0likes
app.py2456 linesDownload Raw Back to root
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;

Showing the first 1,200 of 2456 lines. Download the file for the rest.