MudabbirAI / visuals.py
youssefleb's picture
Update visuals.py
2166333 verified
# visuals.py
# Handles all data visualization logic for MudabbirAI
import pandas as pd
import plotly.graph_objects as go
import config # Import config to access specific model names
def create_progress_chart(log_data):
"""
Generates a Radar Chart comparing the initial draft scores vs. the final scores.
"""
if not log_data or "trace" not in log_data:
return None
attempts = [step for step in log_data["trace"] if step["step_type"] == "attempt"]
if not attempts:
return None
categories = ["Novelty", "Usefulness_Feasibility", "Flexibility", "Elaboration", "Cultural_Appropriateness"]
fig = go.Figure()
for i, attempt in enumerate(attempts):
scores = attempt.get("scores", {})
values = [scores.get(cat, 0) for cat in categories]
# Close the loop for radar chart
values += [values[0]]
radar_categories = categories + [categories[0]]
name = f"Initial Draft" if i == 0 else f"Improved Draft (Loop {i})"
color = "red" if i == 0 else "green"
fig.add_trace(go.Scatterpolar(
r=values,
theta=radar_categories,
fill='toself',
name=name,
line_color=color
))
fig.update_layout(
polar=dict(
radialaxis=dict(
visible=True,
range=[0, 5]
)),
showlegend=True,
title="Evolution of Solution Quality"
)
return fig
def create_calibration_table(log_data):
"""
Generates a Pandas DataFrame showing the 'Audition Scores' for the calibration phase.
"""
if not log_data or "trace" not in log_data:
return None
calibration_step = next((step for step in log_data["trace"] if step["step_type"] == "calibration"), None)
if not calibration_step or "details" not in calibration_step:
return None
details = calibration_step["details"]
data = []
for item in details:
role = item["role"]
model_provider = item["llm"] # e.g., "Gemini", "Anthropic"
score_data = item.get("score", {})
score = 0
if isinstance(score_data, dict):
if role == "Plant":
score = score_data.get("Novelty", {}).get("score", 0)
elif role == "Implementer":
score = score_data.get("Usefulness_Feasibility", {}).get("score", 0)
elif role == "Monitor":
score = score_data.get("Cultural_Appropriateness", {}).get("score", 0)
# --- NEW: Retrieve specific model name from config for transparency ---
specific_model_name = config.MODELS.get(model_provider, {}).get("default", "")
if specific_model_name:
# Format: "Anthropic\n(claude-3-5-haiku...)"
display_name = f"{model_provider}\n({specific_model_name})"
else:
display_name = model_provider
data.append({"Role": role, "Model": display_name, "Score": score})
if not data: return None
df = pd.DataFrame(data)
pivot_df = df.pivot(index="Role", columns="Model", values="Score").reset_index()
return pivot_df
def create_cost_summary(log_data):
"""
Creates a Markdown summary of costs based on usage data found in the log.
"""
if not log_data or "financial_report" not in log_data:
return "### ⚠️ Financial Data Unavailable\n*Could not retrieve usage statistics.*"
fin = log_data["financial_report"]
total = fin.get("total_cost", 0.0)
calib = fin.get("calibration_cost", 0.0)
gen = fin.get("generation_cost", 0.0)
# Calculate Total Tokens
breakdown = fin.get("usage_breakdown", [])
total_input = sum(u.get("input", 0) for u in breakdown)
total_output = sum(u.get("output", 0) for u in breakdown)
# Model Usage Breakdown
models_used = {}
for u in breakdown:
m = u.get("model", "Unknown")
models_used[m] = models_used.get(m, 0) + 1
if not models_used:
model_str = "None recorded"
else:
model_str = ", ".join([f"{k} ({v} calls)" for k,v in models_used.items()])
md = f"""
### 💰 Financial Intelligence Report
| **Category** | **Cost (USD)** | **Details** |
| :--- | :--- | :--- |
| **Total Investment** | **${total:.6f}** | **Total execution cost** |
| Calibration Phase | ${calib:.6f} | Auditing models to pick the best team |
| Solution Phase | ${gen:.6f} | Drafting, refining, and judging |
---
**Operational Metrics:**
* **Total Tokens:** {total_input + total_output:,} ({total_input:,} in / {total_output:,} out)
* **Models Deployed:** {model_str}
"""
return md