gauravlochab
feat: refactore code and add corrected apr and roi values
174e0f0
"""
Main dashboard UI for the Modius Agent Performance application.
"""
import gradio as gr
import plotly.graph_objects as go
import logging
from typing import Tuple, Optional
from ..data.data_processor import DataProcessor
from ..visualization.apr_charts import generate_apr_visualizations, generate_apr_vs_agent_hash_visualizations
from ..visualization.roi_charts import generate_roi_visualizations
from ..visualization.volume_charts import generate_volume_visualizations
from ..utils.logging_config import get_logger
logger = get_logger(__name__)
class ModiusDashboard:
"""Main dashboard class for the Modius Agent Performance application."""
def __init__(self):
self.data_processor = DataProcessor()
self.global_df = None
self.global_roi_df = None
self.global_volume_df = None
def create_dashboard(self) -> gr.Blocks:
"""Create the main dashboard interface."""
with gr.Blocks() as demo:
gr.Markdown("# Average Modius Agent Performance")
# Create tabs for different metrics
with gr.Tabs():
# APR Metrics tab
with gr.Tab("APR Metrics"):
apr_tab = self._create_apr_tab()
# ROI Metrics tab
with gr.Tab("ROI Metrics"):
roi_tab = self._create_roi_tab()
# Volume Metrics tab - COMMENTED OUT
# with gr.Tab("Volume Metrics"):
# volume_tab = self._create_volume_tab()
# Performance Graph tab - COMMENTED OUT
# with gr.Tab("Performance Graph"):
# performance_tab = self._create_performance_tab()
# Add custom CSS for responsive design
self._add_custom_css()
return demo
def _create_apr_tab(self) -> gr.Column:
"""Create the APR metrics tab."""
with gr.Column() as apr_tab:
refresh_apr_btn = gr.Button("Refresh APR Data")
with gr.Column():
combined_apr_graph = gr.Plot(label="APR for All Agents", elem_id="responsive_apr_plot")
# Toggle controls
with gr.Row(visible=True):
gr.Markdown("##### Toggle Graph Lines", elem_id="apr_toggle_title")
with gr.Row():
with gr.Column():
with gr.Row(elem_id="apr_toggle_container"):
with gr.Column(scale=1, min_width=150):
apr_toggle = gr.Checkbox(label="APR Average (7-Day MA)", value=True, elem_id="apr_toggle")
with gr.Column(scale=1, min_width=150):
adjusted_apr_toggle = gr.Checkbox(label="ETH Adjusted APR Average (7-Day MA)", value=True, elem_id="adjusted_apr_toggle")
apr_status_text = gr.Textbox(label="Status", value="Ready", interactive=False)
# Set up event handlers
self._setup_apr_events(refresh_apr_btn, combined_apr_graph, apr_toggle, adjusted_apr_toggle, apr_status_text)
# Initialize with placeholder
apr_placeholder_fig = self._create_placeholder_chart("Click 'Refresh APR Data' to load APR graph")
combined_apr_graph.value = apr_placeholder_fig
return apr_tab
def _create_roi_tab(self) -> gr.Column:
"""Create the ROI metrics tab."""
with gr.Column() as roi_tab:
refresh_roi_btn = gr.Button("Refresh ROI Data")
with gr.Column():
combined_roi_graph = gr.Plot(label="ROI for All Agents", elem_id="responsive_roi_plot")
# Toggle controls
with gr.Row(visible=True):
gr.Markdown("##### Toggle Graph Lines", elem_id="roi_toggle_title")
with gr.Row():
with gr.Column():
with gr.Row(elem_id="roi_toggle_container"):
with gr.Column(scale=1, min_width=150):
roi_toggle = gr.Checkbox(label="ROI Average (7-Day MA)", value=True, elem_id="roi_toggle")
roi_status_text = gr.Textbox(label="Status", value="Ready", interactive=False)
# Set up event handlers
self._setup_roi_events(refresh_roi_btn, combined_roi_graph, roi_toggle, roi_status_text)
# Initialize with placeholder
roi_placeholder_fig = self._create_placeholder_chart("Click 'Refresh ROI Data' to load ROI graph")
combined_roi_graph.value = roi_placeholder_fig
return roi_tab
def _create_volume_tab(self) -> gr.Column:
"""Create the Volume metrics tab."""
with gr.Column() as volume_tab:
refresh_volume_btn = gr.Button("Refresh Volume Data")
with gr.Column():
combined_volume_graph = gr.Plot(label="Daily Volume Change (%) with 7-Day SMA", elem_id="responsive_volume_plot")
# Toggle controls
with gr.Row(visible=True):
gr.Markdown("##### Toggle Chart Display", elem_id="volume_toggle_title")
with gr.Row():
with gr.Column():
with gr.Row(elem_id="volume_toggle_container"):
with gr.Column(scale=1, min_width=150):
volume_bars_toggle = gr.Checkbox(label="Daily Volume Bars", value=True, elem_id="volume_bars_toggle")
with gr.Column(scale=1, min_width=150):
volume_sma_toggle = gr.Checkbox(label="7-Day SMA Line", value=True, elem_id="volume_sma_toggle")
volume_status_text = gr.Textbox(label="Status", value="Ready", interactive=False)
# Set up event handlers
self._setup_volume_events(refresh_volume_btn, combined_volume_graph, volume_bars_toggle, volume_sma_toggle, volume_status_text)
# Initialize with placeholder
volume_placeholder_fig = self._create_placeholder_chart("Click 'Refresh Volume Data' to load Volume graph")
combined_volume_graph.value = volume_placeholder_fig
return volume_tab
def _create_performance_tab(self) -> gr.Column:
"""Create the Performance Graph tab."""
with gr.Column() as performance_tab:
refresh_apr_hash_btn = gr.Button("Refresh APR vs Agent Hash Data")
with gr.Column():
apr_vs_agent_hash_graph = gr.Plot(label="APR vs Agent Hash", elem_id="responsive_apr_hash_plot")
apr_hash_status_text = gr.Textbox(label="Status", value="Ready", interactive=False)
# Set up event handlers
self._setup_performance_events(refresh_apr_hash_btn, apr_vs_agent_hash_graph, apr_hash_status_text)
# Initialize with placeholder
apr_hash_placeholder_fig = self._create_placeholder_chart("Click 'Refresh APR vs Agent Hash Data' to load APR vs Agent Hash graph")
apr_vs_agent_hash_graph.value = apr_hash_placeholder_fig
return performance_tab
def _setup_apr_events(self, refresh_btn, graph, apr_toggle, adjusted_apr_toggle, status_text):
"""Set up event handlers for APR tab."""
def update_apr_graph(show_apr_ma=True, show_adjusted_apr_ma=True):
try:
combined_fig, _ = generate_apr_visualizations(self.data_processor)
# Update visibility of traces based on toggle values
for trace in combined_fig.data:
if 'Average APR (7d window)' in trace.name and 'Adjusted' not in trace.name:
trace.visible = show_apr_ma
elif 'Average ETH Adjusted APR (7d window)' in trace.name:
trace.visible = show_adjusted_apr_ma
return combined_fig
except Exception as e:
logger.exception("Error generating APR visualization")
return self._create_error_chart(f"Error: {str(e)}")
def refresh_apr_data():
try:
logger.info("Manually refreshing APR data...")
self.global_df, self.global_roi_df = self.data_processor.fetch_apr_data_from_db()
if self.global_df is None or len(self.global_df) == 0:
logger.error("Failed to fetch APR data")
return graph.value, "Error: Failed to fetch APR data. Check the logs for details."
logger.info("Generating new APR visualization...")
new_graph = update_apr_graph(apr_toggle.value, adjusted_apr_toggle.value)
return new_graph, "APR data refreshed successfully"
except Exception as e:
logger.error(f"Error refreshing APR data: {e}")
return graph.value, f"Error: {str(e)}"
# Set up event handlers
refresh_btn.click(
fn=refresh_apr_data,
inputs=[],
outputs=[graph, status_text]
)
apr_toggle.change(
fn=update_apr_graph,
inputs=[apr_toggle, adjusted_apr_toggle],
outputs=[graph]
)
adjusted_apr_toggle.change(
fn=update_apr_graph,
inputs=[apr_toggle, adjusted_apr_toggle],
outputs=[graph]
)
def _setup_roi_events(self, refresh_btn, graph, roi_toggle, status_text):
"""Set up event handlers for ROI tab."""
def update_roi_graph(show_roi_ma=True):
try:
combined_fig, _ = generate_roi_visualizations(self.data_processor)
# Update visibility of traces based on toggle values
for trace in combined_fig.data:
if trace.name == 'Average ROI (3d window)':
trace.visible = show_roi_ma
return combined_fig
except Exception as e:
logger.exception("Error generating ROI visualization")
return self._create_error_chart(f"Error: {str(e)}")
def refresh_roi_data():
try:
logger.info("Manually refreshing ROI data...")
self.global_df, self.global_roi_df = self.data_processor.fetch_apr_data_from_db()
if self.global_roi_df is None or len(self.global_roi_df) == 0:
logger.error("Failed to fetch ROI data")
return graph.value, "Error: Failed to fetch ROI data. Check the logs for details."
logger.info("Generating new ROI visualization...")
new_graph = update_roi_graph(roi_toggle.value)
return new_graph, "ROI data refreshed successfully"
except Exception as e:
logger.error(f"Error refreshing ROI data: {e}")
return graph.value, f"Error: {str(e)}"
# Set up event handlers
refresh_btn.click(
fn=refresh_roi_data,
inputs=[],
outputs=[graph, status_text]
)
roi_toggle.change(
fn=update_roi_graph,
inputs=[roi_toggle],
outputs=[graph]
)
def _setup_volume_events(self, refresh_btn, graph, volume_bars_toggle, volume_sma_toggle, status_text):
"""Set up event handlers for Volume tab."""
def update_volume_graph(show_bars=True, show_sma=True):
try:
combined_fig, _ = generate_volume_visualizations(self.data_processor)
# Update visibility of traces based on toggle values
for trace in combined_fig.data:
if trace.name == 'Daily Volume Change':
trace.visible = show_bars
elif trace.name == '7-Day SMA':
trace.visible = show_sma
return combined_fig
except Exception as e:
logger.exception("Error generating Volume visualization")
return self._create_error_chart(f"Error: {str(e)}")
def refresh_volume_data():
try:
logger.info("Manually refreshing volume data...")
self.global_df, _ = self.data_processor.fetch_apr_data_from_db()
if self.global_df is None or len(self.global_df) == 0:
logger.error("Failed to fetch volume data")
return graph.value, "Error: Failed to fetch volume data. Check the logs for details."
logger.info("Generating new volume visualization...")
new_graph = update_volume_graph(volume_bars_toggle.value, volume_sma_toggle.value)
return new_graph, "Volume data refreshed successfully"
except Exception as e:
logger.error(f"Error refreshing volume data: {e}")
return graph.value, f"Error: {str(e)}"
# Set up event handlers
refresh_btn.click(
fn=refresh_volume_data,
inputs=[],
outputs=[graph, status_text]
)
volume_bars_toggle.change(
fn=update_volume_graph,
inputs=[volume_bars_toggle, volume_sma_toggle],
outputs=[graph]
)
volume_sma_toggle.change(
fn=update_volume_graph,
inputs=[volume_bars_toggle, volume_sma_toggle],
outputs=[graph]
)
def _setup_performance_events(self, refresh_btn, graph, status_text):
"""Set up event handlers for Performance tab."""
def update_apr_vs_agent_hash_graph():
try:
if self.global_df is None or self.global_df.empty:
return self._create_error_chart("No data available. Please refresh APR data first.")
fig, _ = generate_apr_vs_agent_hash_visualizations(self.global_df)
return fig
except Exception as e:
logger.exception("Error generating APR vs Agent Hash visualization")
return self._create_error_chart(f"Error: {str(e)}")
def refresh_apr_vs_agent_hash_data():
try:
logger.info("Manually refreshing APR vs Agent Hash data...")
if self.global_df is None or self.global_df.empty:
self.global_df, _ = self.data_processor.fetch_apr_data_from_db()
if self.global_df is None or len(self.global_df) == 0:
logger.error("Failed to fetch APR data for APR vs Agent Hash visualization")
return graph.value, "Error: Failed to fetch APR data. Check the logs for details."
if 'agent_hash' not in self.global_df.columns:
logger.error("agent_hash column not found in DataFrame")
return graph.value, "Error: agent_hash column not found in data. Check the logs for details."
logger.info("Generating new APR vs Agent Hash visualization...")
new_graph = update_apr_vs_agent_hash_graph()
return new_graph, "APR vs Agent Hash data refreshed successfully"
except Exception as e:
logger.error(f"Error refreshing APR vs Agent Hash data: {e}")
return graph.value, f"Error: {str(e)}"
# Set up event handlers
refresh_btn.click(
fn=refresh_apr_vs_agent_hash_data,
inputs=[],
outputs=[graph, status_text]
)
def _create_placeholder_chart(self, message: str) -> go.Figure:
"""Create a placeholder chart with a message."""
fig = go.Figure()
fig.add_annotation(
text=message,
x=0.5, y=0.5,
showarrow=False,
font=dict(size=15)
)
return fig
def _create_error_chart(self, message: str) -> go.Figure:
"""Create an error chart with a message."""
fig = go.Figure()
fig.add_annotation(
text=message,
x=0.5, y=0.5,
showarrow=False,
font=dict(size=15, color="red")
)
return fig
def _add_custom_css(self):
"""Add custom CSS for responsive design."""
gr.HTML("""
<style>
/* Make plots responsive */
#responsive_apr_plot, #responsive_roi_plot, #responsive_volume_plot, #responsive_apr_hash_plot {
width: 100% !important;
max-width: 100% !important;
}
#responsive_apr_plot > div, #responsive_roi_plot > div, #responsive_volume_plot > div, #responsive_apr_hash_plot > div {
width: 100% !important;
height: auto !important;
min-height: 500px !important;
}
/* Toggle checkbox styling */
#apr_toggle .gr-checkbox {
accent-color: #e74c3c !important;
}
#adjusted_apr_toggle .gr-checkbox {
accent-color: #2ecc71 !important;
}
#roi_toggle .gr-checkbox {
accent-color: #3498db !important;
}
#volume_toggle .gr-checkbox {
accent-color: #9b59b6 !important;
}
/* Make the toggle section more compact */
#apr_toggle_title, #roi_toggle_title, #volume_toggle_title {
margin-bottom: 0;
margin-top: 10px;
}
#apr_toggle_container, #roi_toggle_container, #volume_toggle_container {
margin-top: 5px;
}
/* Style the checkbox labels */
.gr-form.gr-box {
border: none !important;
background: transparent !important;
}
/* Make checkboxes and labels appear on the same line */
.gr-checkbox-container {
display: flex !important;
align-items: center !important;
}
/* Add colored indicators */
#apr_toggle .gr-checkbox-label::before {
content: "●";
color: #e74c3c;
margin-right: 5px;
}
#adjusted_apr_toggle .gr-checkbox-label::before {
content: "●";
color: #2ecc71;
margin-right: 5px;
}
#roi_toggle .gr-checkbox-label::before {
content: "●";
color: #3498db;
margin-right: 5px;
}
#volume_toggle .gr-checkbox-label::before {
content: "●";
color: #9b59b6;
margin-right: 5px;
}
</style>
""")
def create_dashboard() -> gr.Blocks:
"""Create and return the dashboard."""
dashboard = ModiusDashboard()
return dashboard.create_dashboard()