Spaces:
Sleeping
Sleeping
# UI COMPONENTS MODULE | |
import gradio as gr | |
import logging | |
from datetime import datetime | |
from modules.utils import ErrorManager, SystemState | |
# Configure logging | |
logging.basicConfig( | |
level=logging.INFO, | |
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s' | |
) | |
logger = logging.getLogger('ui_components') | |
def create_error_alert(): | |
"""Create the error alert UI component""" | |
with gr.Blocks() as error_container: | |
# Hidden error alert that will be shown when errors occur | |
error_display = gr.HTML( | |
value="", | |
visible=False, | |
elem_id="error-alert", | |
elem_classes="error-alert-component" | |
) | |
# CSS for error styling | |
gr.HTML(""" | |
<style> | |
.error-alert-container { | |
background-color: #FFF0F0; | |
border-left: 4px solid #FF5555; | |
padding: 12px 16px; | |
margin: 12px 0; | |
position: relative; | |
border-radius: 4px; | |
box-shadow: 0 2px 5px rgba(0,0,0,0.1); | |
animation: fadeIn 0.3s ease-in-out; | |
max-width: 100%; | |
word-break: break-word; | |
} | |
@keyframes fadeIn { | |
from { opacity: 0; transform: translateY(-10px); } | |
to { opacity: 1; transform: translateY(0); } | |
} | |
.error-alert-container h3 { | |
margin-top: 0; | |
color: #D32F2F; | |
padding-right: 20px; | |
} | |
.error-alert-container .close-error { | |
position: absolute; | |
right: 10px; | |
top: 10px; | |
background: none; | |
border: none; | |
font-size: 18px; | |
cursor: pointer; | |
color: #555; | |
padding: 0; | |
line-height: 1; | |
} | |
.error-alert-container .close-error:hover { | |
color: #000; | |
} | |
.error-alert-container pre { | |
background-color: #F8F8F8; | |
padding: 10px; | |
border-radius: 4px; | |
overflow-x: auto; | |
margin-top: 8px; | |
white-space: pre-wrap; | |
font-size: 12px; | |
color: #333; | |
} | |
</style> | |
""") | |
# JavaScript for interactive behavior | |
gr.HTML(""" | |
<script> | |
// Function to set up error alert click handlers | |
function setupErrorAlert() { | |
// Check every second if error alert exists and add the close button logic | |
const checkInterval = setInterval(function() { | |
const errorAlert = document.getElementById('error-alert'); | |
if (errorAlert) { | |
// Add event delegation for clicks on close button | |
errorAlert.addEventListener('click', function(e) { | |
if (e.target.classList.contains('close-error')) { | |
// Find the container and hide it | |
const container = e.target.closest('.error-alert-container'); | |
if (container) { | |
errorAlert.innerHTML = ''; | |
errorAlert.style.display = 'none'; | |
} | |
} | |
}); | |
// Clear interval once we've set up the handler | |
clearInterval(checkInterval); | |
} | |
}, 500); | |
} | |
// Set up when DOM is ready | |
if (document.readyState === 'loading') { | |
document.addEventListener('DOMContentLoaded', setupErrorAlert); | |
} else { | |
setupErrorAlert(); | |
} | |
</script> | |
""") | |
def update_error_display(error_obj): | |
"""Update the error display with an error object""" | |
if not error_obj: | |
return gr.HTML.update(value="", visible=False) | |
# Format the error as HTML | |
error_html = f""" | |
<div class="error-alert-container"> | |
<button class="close-error" title="Dismiss">✕</button> | |
<h3>⚠️ {error_obj['type']} in {error_obj['module'] or 'Unknown Module'}</h3> | |
<p><strong>Error:</strong> {error_obj['message']}</p> | |
<p style="margin: 4px 0; font-size: 0.9em; color: #777;">Time: {error_obj['timestamp']}</p> | |
<details> | |
<summary style="cursor: pointer; color: #0066CC;">Show Technical Details</summary> | |
<pre>{error_obj['details'] if error_obj['details'] else 'No additional details available'}</pre> | |
</details> | |
</div> | |
""" | |
# Update the display | |
return gr.HTML.update(value=error_html, visible=True) | |
# Register the update function to be called when errors occur | |
ErrorManager().add_listener(lambda err: error_display.update(update_error_display(err))) | |
return error_container | |
def create_status_bar(): | |
"""Create a status bar showing system status""" | |
system_state = SystemState() | |
with gr.Row(elem_classes="status-bar") as status_bar: | |
gr.HTML(""" | |
<style> | |
.status-bar { | |
background-color: #f5f5f5; | |
border-bottom: 1px solid #ddd; | |
padding: 8px 16px; | |
margin-bottom: 10px; | |
} | |
.status-indicator { | |
display: inline-block; | |
width: 12px; | |
height: 12px; | |
border-radius: 50%; | |
margin-right: 6px; | |
} | |
.status-online { | |
background-color: #4CAF50; | |
} | |
.status-offline { | |
background-color: #F44336; | |
} | |
.status-text { | |
font-size: 14px; | |
font-weight: 500; | |
} | |
</style> | |
""") | |
with gr.Column(scale=1): | |
status_indicator = gr.HTML( | |
value=f""" | |
<div> | |
<span class="status-indicator {'status-online' if system_state.online else 'status-offline'}"></span> | |
<span class="status-text">System {'Online' if system_state.online else 'Offline'}</span> | |
</div> | |
""" | |
) | |
with gr.Column(scale=1): | |
mode_indicator = gr.HTML( | |
value=f""" | |
<div> | |
<span class="status-text">Mode: {'Demo' if system_state.demo_mode else 'Production'}</span> | |
{' | <span class="status-text">Debug: On</span>' if system_state.debug_mode else ''} | |
</div> | |
""" | |
) | |
with gr.Column(scale=1): | |
time_indicator = gr.HTML( | |
value=f""" | |
<div> | |
<span class="status-text">Current Time: {datetime.now().strftime("%Y-%m-%d %H:%M:%S")}</span> | |
</div> | |
""" | |
) | |
# Hidden refresh buttons that get triggered by JavaScript | |
with gr.Row(visible=False): | |
status_refresh_btn = gr.Button("Refresh Status", elem_id="status_refresh_btn") | |
mode_refresh_btn = gr.Button("Refresh Mode", elem_id="mode_refresh_btn") | |
time_refresh_btn = gr.Button("Refresh Time", elem_id="time_refresh_btn") | |
# Connect refresh buttons to update functions | |
status_refresh_btn.click( | |
lambda: gr.HTML.update(value=f""" | |
<div> | |
<span class="status-indicator {'status-online' if SystemState().online else 'status-offline'}"></span> | |
<span class="status-text">System {'Online' if SystemState().online else 'Offline'}</span> | |
</div> | |
"""), | |
outputs=[status_indicator] | |
) | |
mode_refresh_btn.click( | |
lambda: gr.HTML.update(value=f""" | |
<div> | |
<span class="status-text">Mode: {'Demo' if SystemState().demo_mode else 'Production'}</span> | |
{' | <span class="status-text">Debug: On</span>' if SystemState().debug_mode else ''} | |
</div> | |
"""), | |
outputs=[mode_indicator] | |
) | |
time_refresh_btn.click( | |
lambda: gr.HTML.update(value=f""" | |
<div> | |
<span class="status-text">Current Time: {datetime.now().strftime("%Y-%m-%d %H:%M:%S")}</span> | |
</div> | |
"""), | |
outputs=[time_indicator] | |
) | |
# JavaScript to auto-update every 30 seconds | |
gr.HTML(""" | |
<script> | |
// Update time every 30 seconds | |
setInterval(function() { | |
try { | |
document.getElementById("status_refresh_btn").click(); | |
document.getElementById("mode_refresh_btn").click(); | |
document.getElementById("time_refresh_btn").click(); | |
} catch (e) { | |
console.error('Error refreshing status:', e); | |
} | |
}, 30000); | |
</script> | |
""") | |
return status_bar |