Skip to content

Price history charts: matplotlib visualization with ASCII fallback #489

@kovtcharov

Description

@kovtcharov

Summary

Add price history visualization tools that generate price-over-time charts as PNG images (via matplotlib) with an ASCII chart fallback for pure CLI environments.

Motivation

CamelCamelCamel's most iconic feature is its price history charts. Visualizing price trends makes it immediately obvious whether a product is at a good price, trending up, or at an all-time low. An ASCII fallback ensures the feature works everywhere, even without matplotlib installed.

Design

Chart Tool

# src/gaia/agents/deals/tools/chart_tools.py
class ChartToolsMixin:
    def register_chart_tools(self) -> None:
        from gaia.agents.base.tools import tool

        @tool
        def show_price_history(product_name: str, days: int = 90, format: str = "auto") -> Dict:
            """Display a price history chart for a tracked product.

            Args:
                product_name: Name of the product to chart
                days: Number of days of history to show (default 90)
                format: Chart format: "auto" (PNG if matplotlib, else ASCII), "png", "ascii"

            Returns:
                Chart file path (PNG) or ASCII chart string
            """

        @tool
        def compare_price_charts(product_names: str, days: int = 90) -> Dict:
            """Compare price histories of multiple products on one chart.

            Args:
                product_names: Comma-separated product names to compare
                days: Number of days of history (default 90)
            """

Matplotlib Chart

def _generate_matplotlib_chart(self, product_id, days, output_path):
    import matplotlib.pyplot as plt
    import matplotlib.dates as mdates

    history = self.get_price_history(product_id, days)
    dates = [h["recorded_at"] for h in history]
    prices = [h["price"] for h in history]

    fig, ax = plt.subplots(figsize=(10, 4))
    ax.plot(dates, prices, "b-", linewidth=2)
    ax.fill_between(dates, prices, alpha=0.1)

    # Mark min/max
    min_idx = prices.index(min(prices))
    max_idx = prices.index(max(prices))
    ax.annotate(f"${prices[min_idx]:.2f}", xy=(dates[min_idx], prices[min_idx]),
                color="green", fontweight="bold")
    ax.annotate(f"${prices[max_idx]:.2f}", xy=(dates[max_idx], prices[max_idx]),
                color="red", fontweight="bold")

    ax.set_title(f"Price History — {product_name}")
    ax.set_ylabel("Price ($)")
    ax.xaxis.set_major_formatter(mdates.DateFormatter("%b %d"))
    ax.grid(True, alpha=0.3)
    fig.tight_layout()
    fig.savefig(output_path, dpi=100)
    plt.close(fig)

ASCII Chart Fallback

Price History: MacBook Pro M3 (Last 90 Days)
$1,599 ┤
$1,499 ┤         ╭──╮
$1,399 ┤    ╭────╯  ╰──╮
$1,299 ┤───╯            ╰───── ◀ Current: $1,299
$1,199 ┤                            Target: $1,200
        └──────────────────────────
         Dec    Jan    Feb    Mar
   Low: $1,249 (Jan 15)  High: $1,549 (Dec 3)  Avg: $1,389

Uses simple box-drawing characters, no external dependencies.

CLI Integration

gaia deals history "MacBook Pro"              # Auto-detect format
gaia deals history "MacBook Pro" --ascii      # Force ASCII
gaia deals history "MacBook Pro" --png        # Force PNG, open in viewer
gaia deals history "MacBook Pro" --days 365   # Full year

Acceptance Criteria

  • show_price_history generates PNG chart with matplotlib (when available)
  • ASCII chart fallback works without matplotlib installed
  • Charts show: price line, min/max annotations, current price, target price
  • compare_price_charts overlays multiple products on one chart
  • PNG saved to ~/.gaia/deals/charts/ with timestamped filename
  • CLI gaia deals history subcommand works
  • matplotlib is optional dependency (in deals extras group)
  • Unit tests with mock price data verify chart generation

Phase

Phase 3 — Visualization & Intelligence

Dependencies

  • Price history schema (Phase 1)
  • Watchlist management (Phase 2)

New Dependencies

Package Version License Purpose
matplotlib >=3.7 PSF Price history chart generation (optional)

Metadata

Metadata

Assignees

No one assigned

    Labels

    agentdealsDealAgent: price tracking and deal discoveryenhancementNew feature or requestp2low priority

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions