Spaces:
Running
Running
| """ | |
| Data loader for benchmark results. | |
| Supports both JSON and JSONL formats. | |
| """ | |
| import json | |
| from pathlib import Path | |
| from dataclasses import dataclass | |
| from functools import lru_cache | |
| class BenchmarkResult: | |
| agent: str | |
| start: str | |
| target: str | |
| won: bool | |
| clicks: int | |
| time_seconds: float | |
| path: list[str] | |
| error: str | |
| tokens_used: int | |
| class AgentSummary: | |
| agent: str | |
| games_played: int | |
| wins: int | |
| win_rate: float | |
| avg_clicks: float | |
| avg_time: float | |
| total_tokens: int | |
| agent_type: str # "llm" or "embedding" | |
| def get_data_path() -> Path: | |
| """Get path to data directory.""" | |
| return Path(__file__).parent.parent.parent / "data" | |
| def _load_jsonl_results() -> list[dict]: | |
| """Load benchmark results from JSONL file.""" | |
| jsonl_path = get_data_path() / "benchmark_results.jsonl" | |
| if not jsonl_path.exists(): | |
| return [] | |
| results = [] | |
| with open(jsonl_path, encoding="utf-8") as f: | |
| for line in f: | |
| line = line.strip() | |
| if line: | |
| try: | |
| results.append(json.loads(line)) | |
| except json.JSONDecodeError: | |
| continue | |
| return results | |
| def load_benchmark_results() -> dict: | |
| """Load benchmark results from JSON or JSONL file.""" | |
| # Try JSONL first (more likely to have recent data) | |
| jsonl_results = _load_jsonl_results() | |
| if jsonl_results: | |
| return {"results": jsonl_results, "summaries": [], "test_cases": []} | |
| # Fall back to JSON | |
| results_path = get_data_path() / "benchmark_results.json" | |
| if not results_path.exists(): | |
| return {"results": [], "summaries": [], "test_cases": []} | |
| with open(results_path, encoding="utf-8") as f: | |
| data = json.load(f) | |
| # Handle both formats | |
| if "results" in data: | |
| return data | |
| elif "test_cases" in data: | |
| return {"results": [], "summaries": [], "test_cases": data["test_cases"]} | |
| else: | |
| return {"results": [], "summaries": [], "test_cases": []} | |
| def load_benchmark_problems() -> dict: | |
| """Load benchmark problems from JSON file.""" | |
| problems_path = get_data_path() / "benchmark_problems.json" | |
| if not problems_path.exists(): | |
| return {"problems": []} | |
| with open(problems_path, encoding="utf-8") as f: | |
| data = json.load(f) | |
| # Handle different formats | |
| if "problems" in data: | |
| return data | |
| elif isinstance(data, list): | |
| return {"problems": data} | |
| else: | |
| return {"problems": []} | |
| def get_results() -> list[BenchmarkResult]: | |
| """Get all benchmark results as dataclass instances.""" | |
| data = load_benchmark_results() | |
| results = [] | |
| for r in data.get("results", []): | |
| results.append(BenchmarkResult( | |
| agent=r.get("agent", ""), | |
| start=r.get("start", ""), | |
| target=r.get("target", ""), | |
| won=r.get("won", False), | |
| clicks=r.get("clicks", 0), | |
| time_seconds=r.get("time_seconds", 0), | |
| path=r.get("path", []), | |
| error=r.get("error", ""), | |
| tokens_used=r.get("tokens_used", 0), | |
| )) | |
| return results | |
| def get_agent_summaries() -> list[AgentSummary]: | |
| """Compute agent summaries from results.""" | |
| results = get_results() | |
| # Group by agent | |
| agent_data: dict[str, list[BenchmarkResult]] = {} | |
| for r in results: | |
| if r.agent not in agent_data: | |
| agent_data[r.agent] = [] | |
| agent_data[r.agent].append(r) | |
| summaries = [] | |
| for agent, games in agent_data.items(): | |
| wins = [g for g in games if g.won] | |
| win_clicks = [g.clicks for g in wins] if wins else [0] | |
| # Determine agent type | |
| agent_type = "embedding" if agent.startswith("live-") else "llm" | |
| summaries.append(AgentSummary( | |
| agent=agent, | |
| games_played=len(games), | |
| wins=len(wins), | |
| win_rate=len(wins) / len(games) * 100 if games else 0, | |
| avg_clicks=sum(win_clicks) / len(win_clicks) if win_clicks else 0, | |
| avg_time=sum(g.time_seconds for g in games) / len(games) if games else 0, | |
| total_tokens=sum(g.tokens_used for g in games), | |
| agent_type=agent_type, | |
| )) | |
| # Sort by win rate, then avg clicks | |
| summaries.sort(key=lambda s: (-s.win_rate, s.avg_clicks)) | |
| return summaries | |
| def get_problems() -> list[dict]: | |
| """Get all benchmark problems.""" | |
| data = load_benchmark_problems() | |
| return data.get("problems", []) | |
| def get_results_by_difficulty() -> dict[str, list[BenchmarkResult]]: | |
| """Group results by problem difficulty.""" | |
| problems = {p["start"] + "→" + p["target"]: p["difficulty"] | |
| for p in get_problems()} | |
| results = get_results() | |
| by_difficulty: dict[str, list[BenchmarkResult]] = { | |
| "easy": [], "medium": [], "hard": [] | |
| } | |
| for r in results: | |
| key = r.start + "→" + r.target | |
| difficulty = problems.get(key, "unknown") | |
| if difficulty in by_difficulty: | |
| by_difficulty[difficulty].append(r) | |
| return by_difficulty | |
| def get_path_data() -> list[dict]: | |
| """Get path data for network visualization.""" | |
| results = get_results() | |
| paths = [] | |
| for r in results: | |
| if r.won and r.path: | |
| paths.append({ | |
| "agent": r.agent, | |
| "start": r.start, | |
| "target": r.target, | |
| "path": r.path, | |
| "clicks": r.clicks, | |
| }) | |
| return paths | |
| def load_model_pricing() -> dict[str, float]: | |
| """Load OpenRouter model pricing (cost per 1M input tokens).""" | |
| models_path = get_data_path() / "openrouter_models.json" | |
| if not models_path.exists(): | |
| return {} | |
| with open(models_path, encoding="utf-8") as f: | |
| models = json.load(f) | |
| # Map model ID to price per 1M input tokens | |
| pricing = {} | |
| for m in models: | |
| price_str = m.get("pricing", {}).get("prompt", "0") | |
| pricing[m["id"]] = float(price_str) * 1_000_000 | |
| return pricing | |
| def _agent_to_model_id(agent: str) -> str | None: | |
| """Map agent name to OpenRouter model ID.""" | |
| if not agent.startswith("llm-"): | |
| return None | |
| model_part = agent.replace("llm-", "") | |
| pricing = load_model_pricing() | |
| # Try exact match first | |
| for mid in pricing: | |
| # Handle truncated agent names (e.g., "llm-llama-3.3-70b-instruct...") | |
| if model_part.rstrip(".") in mid or mid.endswith(model_part.rstrip(".")): | |
| return mid | |
| # Handle common patterns | |
| short_mid = mid.split("/")[-1] if "/" in mid else mid | |
| if model_part.startswith(short_mid) or short_mid.startswith(model_part.rstrip(".")): | |
| return mid | |
| return None | |
| class AgentCostSummary: | |
| """Agent summary with cost information for Pareto analysis.""" | |
| agent: str | |
| agent_type: str | |
| win_rate: float | |
| avg_clicks: float | |
| avg_time: float | |
| total_tokens: int | |
| total_cost: float | |
| cost_per_game: float | |
| games_played: int | |
| wins: int | |
| def get_agent_cost_summaries() -> list[AgentCostSummary]: | |
| """Get agent summaries with cost data for Pareto frontier analysis.""" | |
| summaries = get_agent_summaries() | |
| pricing = load_model_pricing() | |
| cost_summaries = [] | |
| for s in summaries: | |
| model_id = _agent_to_model_id(s.agent) | |
| price_per_1m = pricing.get(model_id, 0) if model_id else 0 | |
| # Cost = (tokens / 1M) * price_per_1M | |
| total_cost = (s.total_tokens / 1_000_000) * price_per_1m | |
| cost_per_game = total_cost / s.games_played if s.games_played > 0 else 0 | |
| cost_summaries.append(AgentCostSummary( | |
| agent=s.agent, | |
| agent_type=s.agent_type, | |
| win_rate=s.win_rate, | |
| avg_clicks=s.avg_clicks, | |
| avg_time=s.avg_time, | |
| total_tokens=s.total_tokens, | |
| total_cost=total_cost, | |
| cost_per_game=cost_per_game, | |
| games_played=s.games_played, | |
| wins=s.wins, | |
| )) | |
| return cost_summaries | |
| def get_problem_difficulty() -> list[dict]: | |
| """ | |
| Compute empirical difficulty for each problem based on benchmark results. | |
| Difficulty score combines: | |
| - Failure rate: what % of agents failed this problem | |
| - Average clicks: more clicks = harder (even for successful runs) | |
| - Click variance: high variance suggests tricky navigation | |
| """ | |
| results = get_results() | |
| # Group results by problem | |
| problem_stats: dict[str, dict] = {} | |
| for r in results: | |
| key = f"{r.start} -> {r.target}" | |
| if key not in problem_stats: | |
| problem_stats[key] = { | |
| "start": r.start, | |
| "target": r.target, | |
| "attempts": 0, | |
| "wins": 0, | |
| "clicks": [], | |
| "times": [], | |
| "failed_agents": [], | |
| } | |
| problem_stats[key]["attempts"] += 1 | |
| if r.won: | |
| problem_stats[key]["wins"] += 1 | |
| problem_stats[key]["clicks"].append(r.clicks) | |
| problem_stats[key]["times"].append(r.time_seconds) | |
| else: | |
| problem_stats[key]["failed_agents"].append(r.agent) | |
| # Compute difficulty metrics | |
| difficulties = [] | |
| for key, stats in problem_stats.items(): | |
| attempts = stats["attempts"] | |
| wins = stats["wins"] | |
| clicks = stats["clicks"] | |
| # Failure rate (0-1, higher = harder) | |
| failure_rate = 1 - (wins / attempts) if attempts > 0 else 0 | |
| # Average clicks for wins (higher = harder) | |
| avg_clicks = sum(clicks) / len(clicks) if clicks else 25 # max if no wins | |
| # Click variance (higher variance = trickier) | |
| if len(clicks) > 1: | |
| mean_clicks = avg_clicks | |
| variance = sum((c - mean_clicks) ** 2 for c in clicks) / len(clicks) | |
| click_std = variance ** 0.5 | |
| else: | |
| click_std = 0 | |
| # Combined difficulty score (0-100) | |
| # Weight: 50% failure rate, 35% avg clicks (normalized), 15% variance | |
| normalized_clicks = min(avg_clicks / 25, 1) # 25 is max | |
| normalized_std = min(click_std / 10, 1) # cap at 10 | |
| difficulty_score = ( | |
| failure_rate * 50 + | |
| normalized_clicks * 35 + | |
| normalized_std * 15 | |
| ) | |
| difficulties.append({ | |
| "start": stats["start"], | |
| "target": stats["target"], | |
| "attempts": attempts, | |
| "wins": wins, | |
| "failure_rate": failure_rate * 100, | |
| "avg_clicks": avg_clicks, | |
| "click_std": click_std, | |
| "difficulty_score": difficulty_score, | |
| "failed_agents": stats["failed_agents"], | |
| "difficulty_label": ( | |
| "Easy" if difficulty_score < 20 else | |
| "Medium" if difficulty_score < 40 else | |
| "Hard" if difficulty_score < 60 else | |
| "Very Hard" | |
| ), | |
| }) | |
| # Sort by difficulty score (hardest first) | |
| difficulties.sort(key=lambda x: -x["difficulty_score"]) | |
| return difficulties | |
| def get_failure_analysis() -> list[dict]: | |
| """Get analysis of failed games grouped by problem (uses difficulty calculation).""" | |
| difficulties = get_problem_difficulty() | |
| # Filter to only problems with failures | |
| failures = [d for d in difficulties if d["failure_rate"] > 0] | |
| # Convert to expected format | |
| return [ | |
| { | |
| "start": d["start"], | |
| "target": d["target"], | |
| "failure_count": len(d["failed_agents"]), | |
| "failed_agents": d["failed_agents"], | |
| "difficulty_score": d["difficulty_score"], | |
| "difficulty_label": d["difficulty_label"], | |
| "avg_clicks": d["avg_clicks"], | |
| } | |
| for d in failures | |
| ] | |
| def get_dashboard_stats() -> dict: | |
| """Get summary statistics for dashboard cards.""" | |
| results = get_results() | |
| summaries = get_agent_summaries() | |
| cost_summaries = get_agent_cost_summaries() | |
| total_games = len(results) | |
| total_wins = sum(1 for r in results if r.won) | |
| # Best agent by win rate | |
| best_agent = summaries[0] if summaries else None | |
| # Cheapest agent with 95%+ win rate | |
| high_performers = [s for s in cost_summaries if s.win_rate >= 95] | |
| cheapest_good = min(high_performers, key=lambda s: s.cost_per_game) if high_performers else None | |
| # Hardest problem (most failures) | |
| failures = get_failure_analysis() | |
| hardest = failures[0] if failures else None | |
| return { | |
| "total_games": total_games, | |
| "total_wins": total_wins, | |
| "win_rate": total_wins / total_games * 100 if total_games > 0 else 0, | |
| "agents_tested": len(summaries), | |
| "best_agent": best_agent.agent if best_agent else "N/A", | |
| "best_win_rate": best_agent.win_rate if best_agent else 0, | |
| "cheapest_good_agent": cheapest_good.agent if cheapest_good else "N/A", | |
| "cheapest_good_cost": cheapest_good.cost_per_game if cheapest_good else 0, | |
| "hardest_problem": f"{hardest['start']} -> {hardest['target']}" if hardest else "N/A", | |
| "hardest_failure_count": hardest["failure_count"] if hardest else 0, | |
| } | |