Spaces:
Runtime error
Runtime error
import gradio as gr | |
import os | |
import json | |
import time | |
import uuid | |
from datetime import datetime | |
from groq import Groq | |
import pandas as pd | |
from typing import Dict, List, Tuple, Optional | |
import re | |
import hashlib | |
import sqlite3 | |
# Initialize components | |
def get_groq_client(): | |
api_key = os.getenv("GROQ_API_KEY") | |
if not api_key: | |
raise ValueError("GROQ_API_KEY environment variable not set") | |
return Groq(api_key=api_key) | |
class UserManager: | |
def __init__(self): | |
self.db_path = 'users.db' | |
self.init_database() | |
def init_database(self): | |
"""Initialize SQLite database for users""" | |
conn = sqlite3.connect(self.db_path) | |
cursor = conn.cursor() | |
cursor.execute(''' | |
CREATE TABLE IF NOT EXISTS users ( | |
id INTEGER PRIMARY KEY AUTOINCREMENT, | |
username TEXT UNIQUE NOT NULL, | |
email TEXT UNIQUE NOT NULL, | |
password_hash TEXT NOT NULL, | |
full_name TEXT, | |
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, | |
last_login TIMESTAMP | |
) | |
''') | |
cursor.execute(''' | |
CREATE TABLE IF NOT EXISTS chat_sessions ( | |
id INTEGER PRIMARY KEY AUTOINCREMENT, | |
user_id INTEGER, | |
session_id TEXT UNIQUE, | |
title TEXT, | |
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, | |
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, | |
FOREIGN KEY (user_id) REFERENCES users (id) | |
) | |
''') | |
cursor.execute(''' | |
CREATE TABLE IF NOT EXISTS messages ( | |
id INTEGER PRIMARY KEY AUTOINCREMENT, | |
session_id TEXT, | |
role TEXT, | |
content TEXT, | |
timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP, | |
FOREIGN KEY (session_id) REFERENCES chat_sessions (session_id) | |
) | |
''') | |
conn.commit() | |
conn.close() | |
def hash_password(self, password: str) -> str: | |
"""Hash password using SHA-256""" | |
return hashlib.sha256(password.encode()).hexdigest() | |
def create_user(self, username: str, email: str, password: str, full_name: str = "") -> Tuple[bool, str]: | |
"""Create new user account""" | |
try: | |
conn = sqlite3.connect(self.db_path) | |
cursor = conn.cursor() | |
password_hash = self.hash_password(password) | |
cursor.execute( | |
"INSERT INTO users (username, email, password_hash, full_name) VALUES (?, ?, ?, ?)", | |
(username, email, password_hash, full_name) | |
) | |
conn.commit() | |
conn.close() | |
return True, "Account created successfully!" | |
except sqlite3.IntegrityError as e: | |
if "username" in str(e): | |
return False, "Username already exists" | |
elif "email" in str(e): | |
return False, "Email already registered" | |
else: | |
return False, "Registration failed" | |
except Exception as e: | |
return False, f"Error: {str(e)}" | |
def authenticate_user(self, username: str, password: str) -> Tuple[bool, Optional[Dict]]: | |
"""Authenticate user login""" | |
try: | |
conn = sqlite3.connect(self.db_path) | |
cursor = conn.cursor() | |
password_hash = self.hash_password(password) | |
cursor.execute( | |
"SELECT id, username, email, full_name FROM users WHERE username = ? AND password_hash = ?", | |
(username, password_hash) | |
) | |
user = cursor.fetchone() | |
if user: | |
cursor.execute( | |
"UPDATE users SET last_login = CURRENT_TIMESTAMP WHERE id = ?", | |
(user[0],) | |
) | |
conn.commit() | |
user_data = { | |
'id': user[0], | |
'username': user[1], | |
'email': user[2], | |
'full_name': user[3] or user[1] | |
} | |
conn.close() | |
return True, user_data | |
conn.close() | |
return False, None | |
except Exception as e: | |
return False, None | |
class DiagramGenerator: | |
def generate_single_line_diagram(self, config: Dict) -> str: | |
"""Generate single line diagram SVG""" | |
return f""" | |
<svg width="600" height="400" viewBox="0 0 600 400" xmlns="http://www.w3.org/2000/svg"> | |
<rect width="600" height="400" fill="#f8fafc" stroke="#cbd5e1" stroke-width="2" rx="10"/> | |
<text x="300" y="30" text-anchor="middle" font-family="Arial" font-size="18" font-weight="bold" fill="#1e293b"> | |
Single Line Diagram | |
</text> | |
<circle cx="100" cy="200" r="30" fill="none" stroke="#3b82f6" stroke-width="3"/> | |
<text x="100" y="205" text-anchor="middle" font-family="Arial" font-size="12" fill="#3b82f6">G</text> | |
<line x1="130" y1="200" x2="200" y2="200" stroke="#1e293b" stroke-width="2"/> | |
<rect x="200" y="180" width="60" height="40" fill="none" stroke="#ef4444" stroke-width="2"/> | |
<text x="230" y="205" text-anchor="middle" font-family="Arial" font-size="12" fill="#ef4444">T1</text> | |
<line x1="260" y1="200" x2="340" y2="200" stroke="#1e293b" stroke-width="2"/> | |
<rect x="340" y="180" width="60" height="40" fill="none" stroke="#10b981" stroke-width="2"/> | |
<text x="370" y="205" text-anchor="middle" font-family="Arial" font-size="12" fill="#10b981">L1</text> | |
<line x1="400" y1="200" x2="470" y2="200" stroke="#1e293b" stroke-width="2"/> | |
<circle cx="500" cy="200" r="20" fill="none" stroke="#8b5cf6" stroke-width="2"/> | |
<text x="500" y="205" text-anchor="middle" font-family="Arial" font-size="10" fill="#8b5cf6">Load</text> | |
</svg> | |
""" | |
class PowerSystemsConsultant: | |
def __init__(self): | |
self.groq_client = get_groq_client() | |
self.diagram_generator = DiagramGenerator() | |
self.user_manager = UserManager() | |
self.current_user = None | |
self.current_session = None | |
def generate_response(self, user_query: str, chat_history: List[Tuple[str, str]], session_id: str = None) -> Tuple[str, str]: | |
"""Generate response using Groq LLM""" | |
try: | |
# Check if query is asking for a diagram | |
diagram_svg = None | |
if any(keyword in user_query.lower() for keyword in ['diagram', 'single line', 'drawing', 'circuit']): | |
diagram_svg = self.diagram_generator.generate_single_line_diagram({}) | |
# Prepare system prompt | |
system_prompt = """You are a Power Systems Expert AI assistant specializing in electrical power systems. | |
You help with fault analysis, protection systems, standards interpretation, and engineering calculations. | |
Provide clear, technical explanations with practical examples and safety considerations.""" | |
# Prepare conversation context | |
messages = [{"role": "system", "content": system_prompt}] | |
# Add chat history (last 5 exchanges) | |
for human_msg, ai_msg in chat_history[-5:]: | |
messages.append({"role": "user", "content": human_msg}) | |
messages.append({"role": "assistant", "content": ai_msg}) | |
# Add current query | |
messages.append({"role": "user", "content": user_query}) | |
# Generate response using Groq | |
response = self.groq_client.chat.completions.create( | |
model="llama3-70b-8192", | |
messages=messages, | |
max_tokens=2000, | |
temperature=0.8 | |
) | |
text_response = response.choices[0].message.content | |
return text_response, diagram_svg | |
except Exception as e: | |
error_msg = f"Error generating response: {str(e)}. Please check your GROQ_API_KEY and try again." | |
return error_msg, None | |
def generate_practice_pack(self, topic: str, difficulty: str, num_questions: int) -> str: | |
"""Generate practice questions pack""" | |
try: | |
practice_prompt = f"""Generate {num_questions} power systems practice questions about {topic} at {difficulty} level. | |
Format with numbered questions, multiple choice options, and detailed solutions.""" | |
messages = [ | |
{"role": "system", "content": "You are an expert power systems engineer creating practice questions."}, | |
{"role": "user", "content": practice_prompt} | |
] | |
response = self.groq_client.chat.completions.create( | |
model="llama3-70b-8192", | |
messages=messages, | |
max_tokens=3000, | |
temperature=0.7 | |
) | |
return response.choices[0].message.content | |
except Exception as e: | |
return f"Error generating practice pack: {str(e)}" | |
def explain_standard(self, standard: str) -> str: | |
"""Explain power systems standard""" | |
try: | |
standard_prompt = f"""Provide a comprehensive explanation of the {standard} standard including | |
purpose, key requirements, practical applications, and implementation considerations.""" | |
messages = [ | |
{"role": "system", "content": "You are an expert in power systems standards."}, | |
{"role": "user", "content": standard_prompt} | |
] | |
response = self.groq_client.chat.completions.create( | |
model="llama3-70b-8192", | |
messages=messages, | |
max_tokens=2500, | |
temperature=0.6 | |
) | |
return response.choices[0].message.content | |
except Exception as e: | |
return f"Error explaining standard: {str(e)}" | |
def create_chat_session(self, user_id: int, title: str = None) -> str: | |
"""Create new chat session""" | |
session_id = str(uuid.uuid4()) | |
try: | |
conn = sqlite3.connect(self.user_manager.db_path) | |
cursor = conn.cursor() | |
cursor.execute( | |
"INSERT INTO chat_sessions (user_id, session_id, title) VALUES (?, ?, ?)", | |
(user_id, session_id, title or f"Chat {datetime.now().strftime('%m/%d %H:%M')}") | |
) | |
conn.commit() | |
conn.close() | |
return session_id | |
except Exception as e: | |
return str(uuid.uuid4()) | |
# Initialize the consultant | |
try: | |
consultant = PowerSystemsConsultant() | |
initialization_status = "✅ Power Systems Consultant initialized successfully!" | |
except Exception as e: | |
consultant = None | |
initialization_status = f"❌ Initialization failed: {str(e)}" | |
# Updated CSS with lighter background and fixed animations | |
ENHANCED_CSS = """ | |
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&display=swap'); | |
* { | |
font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif; | |
box-sizing: border-box; | |
} | |
:root { | |
--primary: #3b82f6; | |
--primary-light: #60a5fa; | |
--primary-dark: #2563eb; | |
--secondary: #10b981; | |
--secondary-light: #34d399; | |
--accent: #8b5cf6; | |
--warning: #f59e0b; | |
--danger: #ef4444; | |
--success: #10b981; | |
--bg-primary: #f8fafc; | |
--bg-secondary: #f1f5f9; | |
--bg-tertiary: #e2e8f0; | |
--bg-card: rgba(255, 255, 255, 0.95); | |
--bg-glass: rgba(255, 255, 255, 0.8); | |
--text-primary: #0f172a; | |
--text-secondary: #475569; | |
--text-muted: #64748b; | |
--border: rgba(148, 163, 184, 0.3); | |
--border-light: rgba(148, 163, 184, 0.2); | |
--shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05); | |
--shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1); | |
--shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1); | |
--shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.1); | |
--shadow-2xl: 0 25px 50px -12px rgba(0, 0, 0, 0.25); | |
} | |
/* Dark mode for specific elements only */ | |
.dark-section { | |
--bg-primary: #0f172a; | |
--bg-secondary: #1e293b; | |
--bg-tertiary: #334155; | |
--bg-card: rgba(30, 41, 59, 0.9); | |
--text-primary: #f8fafc; | |
--text-secondary: #cbd5e1; | |
--text-muted: #94a3b8; | |
--border: rgba(255, 255, 255, 0.1); | |
} | |
.gradio-container { | |
background: linear-gradient(135deg, var(--bg-primary) 0%, var(--bg-secondary) 50%, var(--bg-tertiary) 100%); | |
color: var(--text-primary); | |
min-height: 100vh; | |
padding: 0; | |
} | |
/* Fixed cover page styling */ | |
.cover-page { | |
min-height: 100vh; | |
background: linear-gradient(135deg, | |
#f8fafc 0%, | |
#e2e8f0 30%, | |
#cbd5e1 60%, | |
#94a3b8 100%); | |
display: flex !important; | |
flex-direction: column !important; | |
align-items: center !important; | |
justify-content: center !important; | |
text-align: center; | |
padding: 2rem; | |
position: relative; | |
overflow: hidden; | |
} | |
.cover-page::before { | |
content: ''; | |
position: absolute; | |
top: 0; | |
left: 0; | |
right: 0; | |
bottom: 0; | |
background: | |
radial-gradient(circle at 20% 80%, rgba(59, 130, 246, 0.1) 0%, transparent 50%), | |
radial-gradient(circle at 80% 20%, rgba(139, 92, 246, 0.1) 0%, transparent 50%), | |
radial-gradient(circle at 40% 40%, rgba(16, 185, 129, 0.05) 0%, transparent 50%); | |
pointer-events: none; | |
} | |
.cover-hero { | |
z-index: 10; | |
max-width: 800px; | |
margin-bottom: 4rem; | |
position: relative; | |
} | |
.cover-icon { | |
font-size: 6rem; | |
background: linear-gradient(135deg, var(--primary), var(--accent)); | |
-webkit-background-clip: text; | |
-webkit-text-fill-color: transparent; | |
margin-bottom: 2rem; | |
display: block; | |
line-height: 1; | |
} | |
.cover-title { | |
font-size: clamp(2.5rem, 6vw, 4.5rem); | |
font-weight: 800; | |
background: linear-gradient(135deg, var(--text-primary), var(--text-secondary)); | |
-webkit-background-clip: text; | |
-webkit-text-fill-color: transparent; | |
margin-bottom: 1.5rem; | |
line-height: 1.1; | |
position: relative; | |
} | |
.cover-subtitle { | |
font-size: clamp(1rem, 2.5vw, 1.25rem); | |
color: var(--text-secondary); | |
margin-bottom: 3rem; | |
line-height: 1.6; | |
max-width: 600px; | |
margin-left: auto; | |
margin-right: auto; | |
} | |
.cover-buttons { | |
display: flex; | |
gap: 2rem; | |
flex-wrap: wrap; | |
justify-content: center; | |
z-index: 10; | |
position: relative; | |
} | |
.cover-btn { | |
padding: 1.25rem 3rem !important; | |
font-size: 1.1rem !important; | |
font-weight: 600 !important; | |
border-radius: 50px !important; | |
border: none !important; | |
cursor: pointer !important; | |
transition: all 0.3s ease !important; | |
text-transform: uppercase !important; | |
letter-spacing: 0.5px !important; | |
position: relative !important; | |
overflow: hidden !important; | |
min-width: 200px !important; | |
text-decoration: none !important; | |
display: inline-flex !important; | |
align-items: center !important; | |
justify-content: center !important; | |
gap: 0.5rem !important; | |
} | |
.cover-btn-primary { | |
background: linear-gradient(135deg, var(--primary), var(--primary-light)) !important; | |
color: white !important; | |
box-shadow: var(--shadow-lg) !important; | |
} | |
.cover-btn-secondary { | |
background: linear-gradient(135deg, var(--secondary), var(--secondary-light)) !important; | |
color: white !important; | |
box-shadow: var(--shadow-lg) !important; | |
} | |
.cover-btn:hover { | |
transform: translateY(-3px) scale(1.05) !important; | |
box-shadow: var(--shadow-xl) !important; | |
} | |
/* Authentication Pages */ | |
.auth-page { | |
min-height: 100vh; | |
background: linear-gradient(135deg, #f8fafc, #e2e8f0); | |
display: flex; | |
align-items: center; | |
justify-content: center; | |
padding: 2rem; | |
} | |
.auth-container { | |
background: var(--bg-card); | |
backdrop-filter: blur(20px); | |
border: 1px solid var(--border); | |
border-radius: 24px; | |
padding: 3rem; | |
width: 100%; | |
max-width: 450px; | |
box-shadow: var(--shadow-2xl); | |
} | |
.auth-header { | |
text-align: center; | |
margin-bottom: 2.5rem; | |
} | |
.auth-icon { | |
font-size: 3rem; | |
background: linear-gradient(135deg, var(--primary), var(--accent)); | |
-webkit-background-clip: text; | |
-webkit-text-fill-color: transparent; | |
margin-bottom: 1rem; | |
} | |
.auth-title { | |
font-size: 2rem; | |
font-weight: 700; | |
color: var(--text-primary); | |
margin-bottom: 0.5rem; | |
} | |
.auth-subtitle { | |
color: var(--text-secondary); | |
font-size: 0.95rem; | |
} | |
/* Services Page */ | |
.services-page { | |
min-height: 100vh; | |
background: linear-gradient(135deg, #f8fafc, #e2e8f0, #cbd5e1); | |
padding: 2rem; | |
} | |
.services-header { | |
text-align: center; | |
margin-bottom: 4rem; | |
max-width: 800px; | |
margin-left: auto; | |
margin-right: auto; | |
} | |
.services-title { | |
font-size: clamp(2.5rem, 6vw, 4rem); | |
font-weight: 800; | |
background: linear-gradient(135deg, var(--text-primary), var(--text-secondary)); | |
-webkit-background-clip: text; | |
-webkit-text-fill-color: transparent; | |
margin-bottom: 1rem; | |
} | |
.services-subtitle { | |
font-size: 1.2rem; | |
color: var(--text-secondary); | |
margin-bottom: 2rem; | |
} | |
.user-welcome { | |
background: var(--bg-card); | |
border: 1px solid var(--border); | |
border-radius: 16px; | |
padding: 1.5rem; | |
margin-bottom: 2rem; | |
text-align: center; | |
backdrop-filter: blur(20px); | |
} | |
.services-grid { | |
display: grid; | |
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); | |
gap: 2rem; | |
max-width: 1200px; | |
margin: 0 auto; | |
} | |
.service-card { | |
background: var(--bg-card); | |
backdrop-filter: blur(20px); | |
border: 1px solid var(--border); | |
border-radius: 20px; | |
padding: 2.5rem; | |
text-align: center; | |
transition: all 0.4s ease; | |
cursor: pointer; | |
position: relative; | |
overflow: hidden; | |
} | |
.service-card::before { | |
content: ''; | |
position: absolute; | |
top: 0; | |
left: 0; | |
right: 0; | |
height: 4px; | |
background: linear-gradient(135deg, var(--primary), var(--accent)); | |
transform: scaleX(0); | |
transition: transform 0.3s ease; | |
} | |
.service-card:hover::before { | |
transform: scaleX(1); | |
} | |
.service-card:hover { | |
transform: translateY(-8px); | |
border-color: var(--primary); | |
box-shadow: var(--shadow-2xl); | |
} | |
.service-icon { | |
font-size: 4rem; | |
background: linear-gradient(135deg, var(--primary), var(--accent)); | |
-webkit-background-clip: text; | |
-webkit-text-fill-color: transparent; | |
margin-bottom: 1.5rem; | |
display: block; | |
} | |
.service-title { | |
font-size: 1.5rem; | |
font-weight: 700; | |
color: var(--text-primary); | |
margin-bottom: 1rem; | |
} | |
.service-description { | |
color: var(--text-secondary); | |
line-height: 1.6; | |
margin-bottom: 2rem; | |
} | |
.service-button { | |
background: linear-gradient(135deg, var(--primary), var(--primary-light)) !important; | |
border: none !important; | |
border-radius: 50px !important; | |
padding: 0.875rem 2rem !important; | |
font-weight: 600 !important; | |
color: white !important; | |
text-transform: uppercase !important; | |
letter-spacing: 0.5px !important; | |
transition: all 0.3s ease !important; | |
cursor: pointer !important; | |
} | |
.service-button:hover { | |
transform: translateY(-2px) !important; | |
box-shadow: var(--shadow-lg) !important; | |
} | |
/* Chat Interface */ | |
.dark-section .chatbot-page { | |
background: linear-gradient(135deg, var(--bg-primary), var(--bg-secondary)); | |
min-height: 100vh; | |
display: flex; | |
flex-direction: column; | |
} | |
.dark-section .chatbot-header { | |
background: var(--bg-card); | |
backdrop-filter: blur(20px); | |
border-bottom: 1px solid var(--border); | |
padding: 1.5rem 2rem; | |
color: var(--text-primary); | |
} | |
/* Enhanced Form Inputs */ | |
.gradio-textbox input, .gradio-textbox textarea { | |
background: rgba(255, 255, 255, 0.95) !important; | |
border: 2px solid var(--border) !important; | |
border-radius: 12px !important; | |
padding: 1rem !important; | |
color: var(--text-primary) !important; | |
font-size: 1rem !important; | |
transition: all 0.3s ease !important; | |
} | |
.gradio-textbox input:focus, .gradio-textbox textarea:focus { | |
border-color: var(--primary) !important; | |
box-shadow: 0 0 0 4px rgba(59, 130, 246, 0.1) !important; | |
background: white !important; | |
} | |
.gradio-button { | |
background: linear-gradient(135deg, var(--primary), var(--primary-light)) !important; | |
border: none !important; | |
border-radius: 12px !important; | |
padding: 1rem 2rem !important; | |
font-weight: 600 !important; | |
font-size: 1rem !important; | |
color: white !important; | |
cursor: pointer !important; | |
transition: all 0.3s ease !important; | |
text-transform: uppercase !important; | |
letter-spacing: 0.5px !important; | |
} | |
.gradio-button:hover { | |
transform: translateY(-2px) !important; | |
box-shadow: var(--shadow-xl) !important; | |
background: linear-gradient(135deg, var(--primary-light), var(--primary)) !important; | |
} | |
/* Page visibility fixes */ | |
.gradio-column { | |
display: flex !important; | |
flex-direction: column !important; | |
} | |
.gradio-row { | |
display: flex !important; | |
} | |
/* Responsive Design */ | |
@media (max-width: 768px) { | |
.cover-buttons { | |
flex-direction: column; | |
align-items: center; | |
} | |
.cover-btn { | |
width: 100% !important; | |
max-width: 300px !important; | |
} | |
.services-grid { | |
grid-template-columns: 1fr; | |
gap: 1.5rem; | |
} | |
} | |
/* Loading states */ | |
.loading { | |
opacity: 0.7; | |
pointer-events: none; | |
} | |
.loading::after { | |
content: ''; | |
position: absolute; | |
top: 50%; | |
left: 50%; | |
transform: translate(-50%, -50%); | |
width: 20px; | |
height: 20px; | |
border: 2px solid var(--primary); | |
border-top: 2px solid transparent; | |
border-radius: 50%; | |
animation: spin 1s linear infinite; | |
} | |
@keyframes spin { | |
0% { transform: translate(-50%, -50%) rotate(0deg); } | |
100% { transform: translate(-50%, -50%) rotate(360deg); } | |
} | |
/* Prevent unwanted animations */ | |
.cover-page .cover-hero { | |
position: relative !important; | |
transform: none !important; | |
animation: none !important; | |
} | |
.cover-page .cover-title { | |
position: relative !important; | |
transform: none !important; | |
animation: none !important; | |
} | |
""" | |
# Create the multi-page application | |
def create_multipage_app(): | |
with gr.Blocks( | |
theme=gr.themes.Soft( | |
primary_hue=gr.themes.colors.blue, | |
secondary_hue=gr.themes.colors.green, | |
neutral_hue=gr.themes.colors.slate, | |
), | |
title="⚡ Power Systems Consultant", | |
css=ENHANCED_CSS | |
) as app: | |
# Global state management | |
current_page = gr.State("cover") | |
user_state = gr.State(None) | |
session_state = gr.State(None) | |
# Page visibility management | |
page_visibility = gr.State({ | |
"cover": True, | |
"signin": False, | |
"signup": False, | |
"services": False, | |
"chatbot": False, | |
"practice": False, | |
"standards": False, | |
"study": False | |
}) | |
# Page 1: Cover Page (Always visible initially) | |
with gr.Column(visible=True, elem_classes=["cover-page"]) as cover_page: | |
with gr.HTML() as cover_content: | |
gr.HTML(""" | |
<div class="cover-hero"> | |
<div class="cover-icon">⚡</div> | |
<h1 class="cover-title">Power Systems Consultant</h1> | |
<p class="cover-subtitle"> | |
Advanced AI-powered platform for electrical power systems analysis, fault calculations, | |
protection design, and engineering excellence. Experience the future of power systems consulting. | |
</p> | |
</div> | |
""") | |
with gr.Row(): | |
signin_nav_btn = gr.Button("🔐 Sign In", elem_classes=["cover-btn", "cover-btn-primary"]) | |
signup_nav_btn = gr.Button("🚀 Create Account", elem_classes=["cover-btn", "cover-btn-secondary"]) | |
# Page 2: Sign In Page | |
with gr.Column(visible=False, elem_classes=["auth-page"]) as signin_page: | |
with gr.Column(elem_classes=["auth-container"]): | |
gr.HTML(""" | |
<div class="auth-header"> | |
<div class="auth-icon">🔐</div> | |
<h2 class="auth-title">Welcome Back</h2> | |
<p class="auth-subtitle">Sign in to your Power Systems workspace</p> | |
</div> | |
""") | |
login_username = gr.Textbox( | |
label="Username", | |
placeholder="Enter your username" | |
) | |
login_password = gr.Textbox( | |
label="Password", | |
type="password", | |
placeholder="Enter your password" | |
) | |
with gr.Row(): | |
signin_btn = gr.Button("Sign In", variant="primary") | |
back_cover_signin = gr.Button("← Back", variant="secondary") | |
signin_status = gr.Textbox(label="Status", interactive=False, visible=False) | |
# Page 3: Sign Up Page | |
with gr.Column(visible=False, elem_classes=["auth-page"]) as signup_page: | |
with gr.Column(elem_classes=["auth-container"]): | |
gr.HTML(""" | |
<div class="auth-header"> | |
<div class="auth-icon">🚀</div> | |
<h2 class="auth-title">Join Our Community</h2> | |
<p class="auth-subtitle">Create your Power Systems workspace</p> | |
</div> | |
""") | |
reg_username = gr.Textbox( | |
label="Username", | |
placeholder="Choose a unique username" | |
) | |
reg_email = gr.Textbox( | |
label="Email", | |
placeholder="[email protected]" | |
) | |
reg_full_name = gr.Textbox( | |
label="Full Name", | |
placeholder="Your full name" | |
) | |
reg_password = gr.Textbox( | |
label="Password", | |
type="password", | |
placeholder="Create a strong password (min 6 chars)" | |
) | |
reg_confirm_password = gr.Textbox( | |
label="Confirm Password", | |
type="password", | |
placeholder="Confirm your password" | |
) | |
with gr.Row(): | |
signup_btn = gr.Button("Create Account", variant="primary") | |
back_cover_signup = gr.Button("← Back", variant="secondary") | |
signup_status = gr.Textbox(label="Status", interactive=False, visible=False) | |
# Page 4: Services Selection Page | |
with gr.Column(visible=False, elem_classes=["services-page"]) as services_page: | |
gr.HTML(""" | |
<div class="services-header"> | |
<h1 class="services-title">Power Systems Workspace</h1> | |
<p class="services-subtitle">Choose your engineering tool and start analyzing power systems</p> | |
<div class="user-welcome" id="user-welcome-display"> | |
<div style="display: flex; align-items: center; justify-content: center; gap: 1rem;"> | |
<div style="background: linear-gradient(135deg, var(--success), var(--secondary-light)); border-radius: 50%; width: 50px; height: 50px; display: flex; align-items: center; justify-content: center;"> | |
<i class="fas fa-user" style="color: white; font-size: 1.2rem;">👤</i> | |
</div> | |
<div> | |
<h3 style="margin: 0; color: var(--text-primary);">Welcome to Power Systems!</h3> | |
<p style="margin: 0; color: var(--text-secondary); font-size: 0.9rem;">Ready to tackle power systems challenges?</p> | |
</div> | |
</div> | |
</div> | |
</div> | |
""") | |
with gr.Row(): | |
with gr.Column(elem_classes=["service-card"]): | |
gr.HTML(""" | |
<div style="text-align: center;"> | |
<div class="service-icon">🤖</div> | |
<h3 class="service-title">AI Consultant</h3> | |
<p class="service-description"> | |
Interactive chat with AI expert for fault analysis, protection systems, | |
calculations, and engineering guidance with diagram generation. | |
</p> | |
</div> | |
""") | |
chatbot_service_btn = gr.Button("Launch Consultant", elem_classes=["service-button"]) | |
with gr.Column(elem_classes=["service-card"]): | |
gr.HTML(""" | |
<div style="text-align: center;"> | |
<div class="service-icon">📚</div> | |
<h3 class="service-title">Practice Generator</h3> | |
<p class="service-description"> | |
Generate customized practice questions with detailed solutions, | |
step-by-step calculations, and standards references for exam prep. | |
</p> | |
</div> | |
""") | |
practice_service_btn = gr.Button("Generate Practice", elem_classes=["service-button"]) | |
with gr.Row(): | |
with gr.Column(elem_classes=["service-card"]): | |
gr.HTML(""" | |
<div style="text-align: center;"> | |
<div class="service-icon">📋</div> | |
<h3 class="service-title">Standards Explorer</h3> | |
<p class="service-description"> | |
Comprehensive explanations of IEEE, IEC, and international standards | |
with practical applications and implementation guidelines. | |
</p> | |
</div> | |
""") | |
standards_service_btn = gr.Button("Explore Standards", elem_classes=["service-button"]) | |
with gr.Column(elem_classes=["service-card"]): | |
gr.HTML(""" | |
<div style="text-align: center;"> | |
<div class="service-icon">🎓</div> | |
<h3 class="service-title">Study Resources</h3> | |
<p class="service-description"> | |
Essential formulas, concepts, calculations, and comprehensive | |
exam preparation materials for power systems engineering. | |
</p> | |
</div> | |
""") | |
study_service_btn = gr.Button("Access Resources", elem_classes=["service-button"]) | |
with gr.Row(): | |
logout_btn = gr.Button("🚪 Sign Out", variant="secondary") | |
# Page 5: Chatbot Interface | |
with gr.Column(visible=False, elem_classes=["dark-section"]) as chatbot_page: | |
with gr.Column(elem_classes=["chatbot-page"]): | |
gr.HTML(""" | |
<div class="chatbot-header"> | |
<h2 style="color: var(--text-primary); margin: 0;">🤖 AI Power Systems Consultant</h2> | |
</div> | |
""") | |
with gr.Row(): | |
back_services_chat = gr.Button("← Back to Services", variant="secondary") | |
new_chat_btn = gr.Button("➕ New Chat", variant="primary") | |
# Chat interface | |
chatbot = gr.Chatbot( | |
height=400, | |
show_label=False, | |
avatar_images=("👤", "🤖") | |
) | |
# Diagram display | |
diagram_display = gr.HTML(""" | |
<div style="background: var(--bg-card); border: 1px solid var(--border); border-radius: 16px; padding: 2rem; margin: 1rem 0; text-align: center;"> | |
<div style="color: var(--text-muted); padding: 2rem;"> | |
<div style="font-size: 3rem; margin-bottom: 1rem;">📐</div> | |
<p>Professional engineering diagrams will appear here</p> | |
</div> | |
</div> | |
""") | |
# Input area | |
with gr.Row(): | |
msg = gr.Textbox( | |
placeholder="Ask about faults, protection, calculations, or request diagrams...", | |
show_label=False, | |
lines=3, | |
scale=4 | |
) | |
with gr.Column(scale=1): | |
submit_btn = gr.Button("🚀 Send", variant="primary") | |
clear_btn = gr.Button("🗑️ Clear", variant="secondary") | |
# Page 6: Practice Generator | |
with gr.Column(visible=False, elem_classes=["services-page"]) as practice_page: | |
gr.HTML(""" | |
<div class="services-header"> | |
<h1 class="services-title">📚 Practice Generator</h1> | |
<p class="services-subtitle">AI-generated practice questions with detailed solutions</p> | |
</div> | |
""") | |
back_services_practice = gr.Button("← Back to Services", variant="secondary") | |
with gr.Row(): | |
with gr.Column(scale=1): | |
gr.HTML('<h3 style="color: var(--text-primary); margin-bottom: 2rem;">⚙️ Customize Practice Pack</h3>') | |
topic_input = gr.Dropdown( | |
choices=[ | |
"Fault Analysis", "Protection Systems", "Power Flow", | |
"Stability Studies", "Relay Coordination", "Transformers", | |
"Transmission Lines", "Load Flow", "Short Circuit Analysis", | |
"Harmonics", "Power Quality", "SCADA Systems" | |
], | |
label="Select Topic", | |
value="Fault Analysis" | |
) | |
difficulty_input = gr.Radio( | |
choices=["Beginner", "Intermediate", "Advanced"], | |
label="Difficulty Level", | |
value="Intermediate" | |
) | |
num_questions_input = gr.Slider( | |
minimum=5, | |
maximum=20, | |
step=1, | |
value=10, | |
label="Number of Questions" | |
) | |
generate_btn = gr.Button("Generate Practice Pack", variant="primary") | |
with gr.Column(scale=2): | |
practice_output = gr.Textbox( | |
label="Generated Practice Pack", | |
lines=25, | |
placeholder="Your customized practice questions will appear here...", | |
show_label=False | |
) | |
# Page 7: Standards Explorer | |
with gr.Column(visible=False, elem_classes=["services-page"]) as standards_page: | |
gr.HTML(""" | |
<div class="services-header"> | |
<h1 class="services-title">📋 Standards Explorer</h1> | |
<p class="services-subtitle">Comprehensive power systems standards library</p> | |
</div> | |
""") | |
back_services_standards = gr.Button("← Back to Services", variant="secondary") | |
with gr.Row(): | |
with gr.Column(scale=1): | |
gr.HTML('<h3 style="color: var(--text-primary); margin-bottom: 2rem;">📖 Explore Standards</h3>') | |
standard_input = gr.Dropdown( | |
choices=[ | |
"IEEE C37.2 - Device Function Numbers", | |
"IEEE 1547 - Distributed Generation", | |
"IEEE 519 - Harmonic Control", | |
"IEEE C57.12.00 - Transformers", | |
"IEC 61850 - Substation Automation", | |
"IEC 60909 - Short-Circuit Calculations", | |
"IEC 61131 - PLC Programming", | |
"IEC 60255 - Electrical Relays", | |
"ANSI C84.1 - Voltage Ratings", | |
"IEEE 242 - Protection & Coordination", | |
"IEEE 399 - Industrial Power Systems", | |
"IEEE C37.010 - Application Guide" | |
], | |
label="Select Standard", | |
value="IEEE C37.2 - Device Function Numbers" | |
) | |
explain_btn = gr.Button("Explain Standard", variant="primary") | |
with gr.Column(scale=2): | |
standard_output = gr.Textbox( | |
label="Standard Explanation", | |
lines=25, | |
placeholder="Detailed standard explanation will appear here...", | |
show_label=False | |
) | |
# Page 8: Study Resources | |
with gr.Column(visible=False, elem_classes=["services-page"]) as study_page: | |
gr.HTML(""" | |
<div class="services-header"> | |
<h1 class="services-title">🎓 Study Resources</h1> | |
<p class="services-subtitle">Essential formulas and exam preparation materials</p> | |
</div> | |
""") | |
back_services_study = gr.Button("← Back to Services", variant="secondary") | |
with gr.Accordion("⚡ Fault Analysis Formulas", open=True): | |
gr.HTML(""" | |
<div style="background: rgba(59, 130, 246, 0.1); border: 1px solid rgba(59, 130, 246, 0.3); border-radius: 16px; padding: 2rem; margin: 1.5rem 0;"> | |
<h4 style="color: var(--primary); margin-bottom: 1rem; display: flex; align-items: center; gap: 0.75rem;"> | |
⚡ Three-Phase Fault Current | |
</h4> | |
<code style="background: rgba(0,0,0,0.1); border-radius: 8px; padding: 0.75rem 1rem; color: var(--primary); border-left: 4px solid var(--primary); margin: 0.5rem 0; display: block;"> | |
I_fault = V_nominal / Z_total | |
</code> | |
<h4 style="color: var(--primary); margin: 2rem 0 1rem 0; display: flex; align-items: center; gap: 0.75rem;"> | |
⚠️ Line-to-Ground Fault | |
</h4> | |
<code style="background: rgba(0,0,0,0.1); border-radius: 8px; padding: 0.75rem 1rem; color: var(--primary); border-left: 4px solid var(--primary); margin: 0.5rem 0; display: block;"> | |
I_fault = 3 × V_nominal / (Z1 + Z2 + Z0) | |
</code> | |
<h4 style="color: var(--primary); margin: 2rem 0 1rem 0; display: flex; align-items: center; gap: 0.75rem;"> | |
↔️ Line-to-Line Fault | |
</h4> | |
<code style="background: rgba(0,0,0,0.1); border-radius: 8px; padding: 0.75rem 1rem; color: var(--primary); border-left: 4px solid var(--primary); margin: 0.5rem 0; display: block;"> | |
I_fault = √3 × V_nominal / (Z1 + Z2) | |
</code> | |
</div> | |
""") | |
with gr.Accordion("🛡️ Protection System Principles", open=False): | |
gr.HTML(""" | |
<div style="background: rgba(139, 92, 246, 0.1); border: 1px solid rgba(139, 92, 246, 0.3); border-radius: 16px; padding: 2rem; margin: 1.5rem 0;"> | |
<h4 style="color: var(--accent); margin-bottom: 1rem;">🛡️ Overcurrent Protection</h4> | |
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 2rem; margin: 1.5rem 0;"> | |
<div style="background: rgba(59, 130, 246, 0.1); padding: 1.5rem; border-radius: 10px;"> | |
<h6 style="color: var(--primary); margin: 0 0 1rem 0;">Time Characteristics</h6> | |
<ul style="color: var(--text-secondary); line-height: 1.8; margin: 0; padding-left: 1.5rem;"> | |
<li>Inverse Time Curves</li> | |
<li>Coordination Intervals (0.2-0.5s)</li> | |
<li>Pickup Settings (1.25-1.5 × FLA)</li> | |
<li>Time Dial Adjustments</li> | |
</ul> | |
</div> | |
<div style="background: rgba(16, 185, 129, 0.1); padding: 1.5rem; border-radius: 10px;"> | |
<h6 style="color: var(--secondary); margin: 0 0 1rem 0;">Curve Types</h6> | |
<ul style="color: var(--text-secondary); line-height: 1.8; margin: 0; padding-left: 1.5rem;"> | |
<li>Standard Inverse (SI)</li> | |
<li>Very Inverse (VI)</li> | |
<li>Extremely Inverse (EI)</li> | |
<li>Definite Time</li> | |
</ul> | |
</div> | |
</div> | |
</div> | |
""") | |
with gr.Accordion("📐 Power System Calculations", open=False): | |
gr.HTML(""" | |
<div style="background: rgba(16, 185, 129, 0.1); border: 1px solid rgba(16, 185, 129, 0.3); border-radius: 16px; padding: 2rem; margin: 1.5rem 0;"> | |
<h4 style="color: var(--secondary); margin-bottom: 1rem;">🧮 Three-Phase Power Formulas</h4> | |
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 2rem; margin: 2rem 0;"> | |
<div> | |
<h6 style="color: var(--secondary); margin: 0 0 1rem 0;">Real Power</h6> | |
<code style="background: rgba(0,0,0,0.1); border-radius: 8px; padding: 0.75rem 1rem; color: var(--secondary); border-left: 4px solid var(--secondary); display: block;">P = √3 × V × I × cos(φ)</code> | |
</div> | |
<div> | |
<h6 style="color: var(--secondary); margin: 0 0 1rem 0;">Reactive Power</h6> | |
<code style="background: rgba(0,0,0,0.1); border-radius: 8px; padding: 0.75rem 1rem; color: var(--secondary); border-left: 4px solid var(--secondary); display: block;">Q = √3 × V × I × sin(φ)</code> | |
</div> | |
</div> | |
</div> | |
""") | |
# Interactive Calculator | |
gr.HTML(""" | |
<div style="background: var(--bg-card); border: 1px solid var(--border); border-radius: 20px; padding: 2.5rem; margin: 2rem 0;"> | |
<h3 style="color: var(--text-primary); margin-bottom: 2rem; text-align: center;"> | |
🧮 Power Systems Calculator | |
</h3> | |
</div> | |
""") | |
with gr.Row(): | |
with gr.Column(): | |
calc_voltage = gr.Number(label="Voltage (V)", value=480) | |
calc_current = gr.Number(label="Current (A)", value=100) | |
calc_pf = gr.Slider(0.1, 1.0, 0.85, label="Power Factor", step=0.01) | |
calc_btn = gr.Button("Calculate Power", variant="primary") | |
with gr.Column(): | |
calc_results = gr.HTML(""" | |
<div style="background: var(--bg-card); padding: 2rem; border-radius: 15px; border: 1px solid var(--border); min-height: 200px; display: flex; align-items: center; justify-content: center;"> | |
<div style="text-align: center; color: var(--text-secondary);"> | |
<div style="font-size: 3rem; margin-bottom: 1rem; opacity: 0.5;">🧮</div> | |
<p>Enter values and click Calculate</p> | |
</div> | |
</div> | |
""") | |
# Event handler functions | |
def show_page(target_page, current_visibility): | |
"""Update page visibility""" | |
new_visibility = {key: False for key in current_visibility.keys()} | |
new_visibility[target_page] = True | |
return new_visibility | |
def handle_signin(username, password): | |
if not consultant: | |
return gr.update(), gr.update(), gr.update(), gr.update(), None, "System not initialized" | |
if not username or not password: | |
return gr.update(), gr.update(), gr.update(), gr.update(), None, "Please enter both username and password" | |
success, user_data = consultant.user_manager.authenticate_user(username, password) | |
if success: | |
return ( | |
gr.update(visible=False), # Hide signin page | |
gr.update(visible=False), # Hide signup page | |
gr.update(visible=False), # Hide cover page | |
gr.update(visible=True), # Show services page | |
user_data, # Store user data | |
f"Welcome back, {user_data['full_name']}!" | |
) | |
else: | |
return gr.update(), gr.update(), gr.update(), gr.update(), None, "Invalid credentials" | |
def handle_signup(username, email, password, confirm_password, full_name): | |
if not consultant: | |
return gr.update(), gr.update(), gr.update(), gr.update(), None, "System not initialized" | |
if not all([username, email, password, confirm_password]): | |
return gr.update(), gr.update(), gr.update(), gr.update(), None, "Please fill all fields" | |
if password != confirm_password: | |
return gr.update(), gr.update(), gr.update(), gr.update(), None, "Passwords do not match" | |
if len(password) < 6: | |
return gr.update(), gr.update(), gr.update(), gr.update(), None, "Password must be at least 6 characters" | |
success, message = consultant.user_manager.create_user(username, email, password, full_name) | |
if success: | |
# Auto-login after successful registration | |
success, user_data = consultant.user_manager.authenticate_user(username, password) | |
if success: | |
return ( | |
gr.update(visible=False), # Hide signin page | |
gr.update(visible=False), # Hide signup page | |
gr.update(visible=False), # Hide cover page | |
gr.update(visible=True), # Show services page | |
user_data, # Store user data | |
"Account created and logged in successfully!" | |
) | |
return gr.update(), gr.update(), gr.update(), gr.update(), None, message | |
def handle_new_chat(user_data): | |
if not consultant or not user_data: | |
return None, [] | |
session_id = consultant.create_chat_session(user_data['id']) | |
return session_id, [] | |
def handle_chat_message(message, history, user_data, session_id): | |
if not consultant or not user_data: | |
return history, "", None | |
if not message.strip(): | |
return history, message, None | |
try: | |
response, diagram_svg = consultant.generate_response(message, history, session_id) | |
new_history = history + [[message, response]] | |
# Update diagram display if available | |
if diagram_svg: | |
diagram_html = f'<div style="background: white; padding: 1rem; border-radius: 8px; margin: 1rem 0;">{diagram_svg}</div>' | |
else: | |
diagram_html = """ | |
<div style="background: var(--bg-card); border: 1px solid var(--border); border-radius: 16px; padding: 2rem; margin: 1rem 0; text-align: center;"> | |
<div style="color: var(--text-muted); padding: 2rem;"> | |
<div style="font-size: 3rem; margin-bottom: 1rem;">📐</div> | |
<p>Professional engineering diagrams will appear here</p> | |
</div> | |
</div> | |
""" | |
return new_history, "", diagram_html | |
except Exception as e: | |
return history + [[message, f"Error: {str(e)}"]], "", None | |
def clear_chat(): | |
return [], "", """ | |
<div style="background: var(--bg-card); border: 1px solid var(--border); border-radius: 16px; padding: 2rem; margin: 1rem 0; text-align: center;"> | |
<div style="color: var(--text-muted); padding: 2rem;"> | |
<div style="font-size: 3rem; margin-bottom: 1rem;">📐</div> | |
<p>Professional engineering diagrams will appear here</p> | |
</div> | |
</div> | |
""" | |
def handle_practice_generation(topic, difficulty, num_questions, user_data): | |
if not consultant or not user_data: | |
return "Please log in to access this feature." | |
try: | |
return consultant.generate_practice_pack(topic, difficulty, int(num_questions)) | |
except Exception as e: | |
return f"Error generating practice pack: {str(e)}" | |
def handle_standard_explanation(standard, user_data): | |
if not consultant or not user_data: | |
return "Please log in to access this feature." | |
try: | |
return consultant.explain_standard(standard) | |
except Exception as 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 | |
s = (3**0.5) * voltage * current / 1000 # kVA | |
return f""" | |
<div style="background: var(--bg-card); padding: 2rem; border-radius: 15px; border: 1px solid var(--border);"> | |
<h4 style="color: var(--text-primary); margin-bottom: 2rem; text-align: center;"> | |
📊 Calculation Results | |
</h4> | |
<div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 1.5rem;"> | |
<div style="background: rgba(16, 185, 129, 0.1); padding: 1.5rem; border-radius: 10px; text-align: center;"> | |
<h6 style="color: var(--secondary); margin: 0 0 0.5rem 0;">Real Power</h6> | |
<p style="font-size: 1.5rem; font-weight: 700; margin: 0; color: var(--text-primary);">{p:.2f} kW</p> | |
</div> | |
<div style="background: rgba(245, 158, 11, 0.1); padding: 1.5rem; border-radius: 10px; text-align: center;"> | |
<h6 style="color: var(--warning); margin: 0 0 0.5rem 0;">Reactive Power</h6> | |
<p style="font-size: 1.5rem; font-weight: 700; margin: 0; color: var(--text-primary);">{q:.2f} kVAR</p> | |
</div> | |
<div style="background: rgba(59, 130, 246, 0.1); padding: 1.5rem; border-radius: 10px; text-align: center;"> | |
<h6 style="color: var(--primary); margin: 0 0 0.5rem 0;">Apparent Power</h6> | |
<p style="font-size: 1.5rem; font-weight: 700; margin: 0; color: var(--text-primary);">{s:.2f} kVA</p> | |
</div> | |
</div> | |
</div> | |
""" | |
else: | |
return """ | |
<div style="background: var(--bg-card); padding: 2rem; border-radius: 15px; border: 1px solid var(--border); text-align: center;"> | |
<div style="font-size: 3rem; color: var(--warning); margin-bottom: 1rem;">⚠️</div> | |
<p>Please enter valid values for all fields</p> | |
</div> | |
""" | |
# Navigation event handlers | |
signin_nav_btn.click( | |
fn=lambda: (gr.update(visible=False), gr.update(visible=True), gr.update(visible=False)), | |
outputs=[cover_page, signin_page, signup_page] | |
) | |
signup_nav_btn.click( | |
fn=lambda: (gr.update(visible=False), gr.update(visible=False), gr.update(visible=True)), | |
outputs=[cover_page, signin_page, signup_page] | |
) | |
back_cover_signin.click( | |
fn=lambda: (gr.update(visible=True), gr.update(visible=False), gr.update(visible=False)), | |
outputs=[cover_page, signin_page, signup_page] | |
) | |
back_cover_signup.click( | |
fn=lambda: (gr.update(visible=True), gr.update(visible=False), gr.update(visible=False)), | |
outputs=[cover_page, signin_page, signup_page] | |
) | |
# Authentication event handlers | |
signin_btn.click( | |
fn=handle_signin, | |
inputs=[login_username, login_password], | |
outputs=[signin_page, signup_page, cover_page, services_page, user_state, signin_status] | |
) | |
signup_btn.click( | |
fn=handle_signup, | |
inputs=[reg_username, reg_email, reg_password, reg_confirm_password, reg_full_name], | |
outputs=[signin_page, signup_page, cover_page, services_page, user_state, signup_status] | |
) | |
# Service navigation | |
chatbot_service_btn.click( | |
fn=lambda: (gr.update(visible=False), gr.update(visible=True)), | |
outputs=[services_page, chatbot_page] | |
) | |
practice_service_btn.click( | |
fn=lambda: (gr.update(visible=False), gr.update(visible=True)), | |
outputs=[services_page, practice_page] | |
) | |
standards_service_btn.click( | |
fn=lambda: (gr.update(visible=False), gr.update(visible=True)), | |
outputs=[services_page, standards_page] | |
) | |
study_service_btn.click( | |
fn=lambda: (gr.update(visible=False), gr.update(visible=True)), | |
outputs=[services_page, study_page] | |
) | |
# Back to services navigation | |
back_services_chat.click( | |
fn=lambda: (gr.update(visible=True), gr.update(visible=False)), | |
outputs=[services_page, chatbot_page] | |
) | |
back_services_practice.click( | |
fn=lambda: (gr.update(visible=True), gr.update(visible=False)), | |
outputs=[services_page, practice_page] | |
) | |
back_services_standards.click( | |
fn=lambda: (gr.update(visible=True), gr.update(visible=False)), | |
outputs=[services_page, standards_page] | |
) | |
back_services_study.click( | |
fn=lambda: (gr.update(visible=True), gr.update(visible=False)), | |
outputs=[services_page, study_page] | |
) | |
# Logout handler | |
logout_btn.click( | |
fn=lambda: (gr.update(visible=True), gr.update(visible=False), None, None), | |
outputs=[cover_page, services_page, user_state, session_state] | |
) | |
# Chat functionality | |
new_chat_btn.click( | |
fn=handle_new_chat, | |
inputs=[user_state], | |
outputs=[session_state, chatbot] | |
) | |
submit_btn.click( | |
fn=handle_chat_message, | |
inputs=[msg, chatbot, user_state, session_state], | |
outputs=[chatbot, msg, diagram_display] | |
) | |
msg.submit( | |
fn=handle_chat_message, | |
inputs=[msg, chatbot, user_state, session_state], | |
outputs=[chatbot, msg, diagram_display] | |
) | |
clear_btn.click( | |
fn=clear_chat, | |
outputs=[chatbot, msg, diagram_display] | |
) | |
# Practice generator functionality | |
generate_btn.click( | |
fn=handle_practice_generation, | |
inputs=[topic_input, difficulty_input, num_questions_input, user_state], | |
outputs=[practice_output] | |
) | |
# Standards explorer functionality | |
explain_btn.click( | |
fn=handle_standard_explanation, | |
inputs=[standard_input, user_state], | |
outputs=[standard_output] | |
) | |
# Calculator functionality | |
calc_btn.click( | |
fn=calculate_power, | |
inputs=[calc_voltage, calc_current, calc_pf], | |
outputs=[calc_results] | |
) | |
return app | |
# Launch the application | |
if __name__ == "__main__": | |
app = create_multipage_app() | |
# Enhanced startup information | |
print("⚡" * 60) | |
print("🚀 POWER SYSTEMS MULTI-PAGE CONSULTANT v4.0 - FIXED") | |
print("⚡" * 60) | |
print() | |
print("🔧 FIXES IMPLEMENTED:") | |
print(" ✅ Fixed disappearing title issue on cover page") | |
print(" ✅ Lightened background - no more dark theme") | |
print(" ✅ Fixed page movement and scroll issues") | |
print(" ✅ Improved page visibility management") | |
print(" ✅ Enhanced navigation between pages") | |
print(" ✅ Fixed CSS animations and transitions") | |
print(" ✅ Better responsive design") | |
print(" ✅ Cleaner authentication flow") | |
print() | |
print("🎨 MODERN MULTI-PAGE INTERFACE:") | |
print(" ✨ Stable cover page with proper title display") | |
print(" 🔐 Separate authentication pages (Sign In/Sign Up)") | |
print(" 🎯 Interactive service selection dashboard") | |
print(" 💬 Dedicated chatbot interface with diagrams") | |
print(" 📚 Full-featured practice generator") | |
print(" 📋 Comprehensive standards explorer") | |
print(" 🎓 Interactive study resources with calculator") | |
print(" 🌊 Smooth and stable page transitions") | |
print() | |
print("🔧 CORE FEATURES:") | |
print(" 🤖 AI-powered chat consultant with diagram generation") | |
print(" 📊 Professional engineering diagrams (SVG)") | |
print(" 🎯 Customizable practice question generator") | |
print(" 📋 Standards library with detailed explanations") | |
print(" 🧮 Built-in power systems calculator") | |
print(" 💾 User authentication & persistent sessions") | |
print(" 📜 Chat history management") | |
print(" ⌨️ Enhanced keyboard shortcuts") | |
print() | |
print("🎨 DESIGN HIGHLIGHTS:") | |
print(" 🌈 Light, modern color palette (blue/green/purple accents)") | |
print(" ✨ Glass-morphism effects and clean borders") | |
print(" 📱 Fully responsive design") | |
print(" 🎭 Stable page transitions without content jumping") | |
print(" 💫 Interactive hover effects") | |
print(" 🌊 Professional gradient backgrounds") | |
print() | |
if consultant is None: | |
print("⚠️ WARNING: System not fully initialized") | |
print(" Please ensure GROQ_API_KEY is set in environment") | |
print(" Some features may be limited without API access") | |
else: | |
print("✅ SYSTEM STATUS: All systems operational!") | |
print() | |
print("🌐 ACCESS INFORMATION:") | |
print(" 📍 Local URL: http://localhost:7860") | |
print(" 🔒 Start with cover page → Sign In/Sign Up") | |
print(" 🎯 Choose your service from dashboard") | |
print(" 💬 Experience the enhanced chatbot interface") | |
print() | |
print("🚀 USAGE FLOW:") | |
print(" 1️⃣ Cover Page: Welcome screen with navigation") | |
print(" 2️⃣ Authentication: Sign in or create account") | |
print(" 3️⃣ Services Dashboard: Choose your tool") | |
print(" 4️⃣ Service Pages: Use AI consultant, practice, etc.") | |
print(" 5️⃣ Navigation: Easy back buttons to return") | |
print() | |
print("💡 KEY IMPROVEMENTS:") | |
print(" 🎯 Fixed title disappearing after 2 seconds") | |
print(" 🎯 Stopped page content from moving down") | |
print(" 🎯 Lighter, more professional appearance") | |
print(" 🎯 Better error handling and user feedback") | |
print(" 🎯 Improved responsive design for mobile") | |
print(" 🎯 Cleaner code structure and organization") | |
print() | |
print("💫 Experience the stable, professional power systems platform!") | |
print("⚡" * 60) | |
try: | |
app.launch( | |
server_name="0.0.0.0", | |
server_port=7860, | |
share=False, | |
show_api=False, | |
show_error=True, | |
quiet=False, | |
favicon_path=None, | |
ssl_verify=False | |
) | |
except Exception as e: | |
print(f"❌ Launch Error: {str(e)}") | |
print("💡 Try running with different port or check firewall settings") |