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