data-analyst-mcp / tools.py
sekpona kokou
add mcp support, fix requirements and tools
927e380
import re
import matplotlib.pyplot as plt
import matplotlib
matplotlib.use("Agg")
import seaborn as sns
sns.set_theme(style="whitegrid", palette="muted")
from typing import List
from pathlib import Path
from smolagents import tool
CHARTS_DIR = Path(__file__).parent / "charts"
CHARTS_DIR.mkdir(exist_ok=True)
LAST_CHART: dict = {"path": None}
AGENT_STEPS: list = []
@tool
def generate_chart(
labels: List[str],
values: List[float],
chart_type: str,
title: str,
xlabel: str = "",
ylabel: str = "",
) -> str:
"""
Generate a bar, pie, or line chart from data and save it as a PNG file.
Call this whenever the data contains a distribution, ranking, comparison,
count breakdown, or proportion that would be clearer as a visual.
Args:
labels: List of category labels (strings).
values: List of numeric values matching each label.
chart_type: 'bar' for counts/rankings/comparisons, 'pie' for proportions, 'line' for trends.
title: Title displayed on the chart.
xlabel: X-axis label (bar / line only).
ylabel: Y-axis label (bar / line only).
Returns:
The file path of the saved PNG image.
"""
fig, ax = plt.subplots(figsize=(10, 5))
if chart_type == "pie":
ax.pie(values, labels=labels, autopct="%1.1f%%", startangle=140,
colors=sns.color_palette("muted", len(labels)))
ax.axis("equal")
elif chart_type == "line":
sns.lineplot(x=labels, y=values, marker="o", linewidth=2.5, ax=ax)
ax.set_xlabel(xlabel)
ax.set_ylabel(ylabel)
plt.xticks(rotation=45, ha="right")
else:
sns.barplot(x=labels, y=values, hue=labels, palette="muted", legend=False, ax=ax)
ax.set_xlabel(xlabel)
ax.set_ylabel(ylabel)
plt.xticks(rotation=45, ha="right")
for p in ax.patches:
ax.annotate(f"{p.get_height():.0f}",
(p.get_x() + p.get_width() / 2, p.get_height()),
ha="center", va="bottom", fontsize=9)
ax.set_title(title, fontsize=13, fontweight="bold", pad=12)
fig.tight_layout()
safe_title = re.sub(r"[^\w\s-]", "", title[:40]).strip().replace(" ", "_")
filename = str(CHARTS_DIR / f"chart_{safe_title}.png")
plt.savefig(filename, dpi=150)
plt.close()
LAST_CHART["path"] = filename
return f"Chart saved → {filename}"