ai-agent-book 精选快照(<2MB 代码与文档,来自 github.com/bojieli/ai-agent-book)
Build latest book artifacts / build (push) Canceled after 0s
dependency resolution / resolve (3.11) (push) Canceled after 0s
dependency resolution / resolve (3.13) (push) Canceled after 0s
deploy-pages / build (push) Canceled after 0s
deploy-pages / deploy (push) Canceled after 0s
i18n consistency check / check (push) Canceled after 0s
provider adoption tests / test (chapter2/context-compression) (push) Canceled after 0s
provider adoption tests / test (chapter2/prompt-injection) (push) Canceled after 0s
provider adoption tests / test (chapter2/system-hint) (push) Canceled after 0s
provider adoption tests / test (chapter3/log-sanitization) (push) Canceled after 0s
web-search-agent tests / test (push) Canceled after 0s
web-search-agent tests / agentbook (push) Canceled after 0s

This commit is contained in:
2026-08-20 13:12:50 +00:00
commit b119135836
10275 changed files with 3284984 additions and 0 deletions
+436
View File
@@ -0,0 +1,436 @@
"""
Create animated bar chart race showing leaderboard evolution over time
"""
import pandas as pd
import numpy as np
from typing import List, Tuple
import json
import os
def prepare_animation_data(history_df: pd.DataFrame, top_n: int = 15) -> dict:
"""
Prepare data for D3.js bar chart race animation.
Args:
history_df: DataFrame with columns: date, model, rating, rank
top_n: Number of top models to show at each time point
Returns:
Dictionary with animation data
"""
# Convert date column to Timestamp to support ISO date strings and date objects
if history_df is not None and len(history_df) > 0 and 'date' in history_df.columns:
history_df = history_df.copy()
history_df['date'] = pd.to_datetime(history_df['date'])
# Get all unique dates
dates = sorted(history_df['date'].unique())
if len(dates) == 0:
return {
'frames': [],
'total_frames': 0,
'top_n': top_n,
'start_date': None,
'end_date': None,
}
# For each date, get top N models
frames = []
for date in dates:
date_data = history_df[history_df['date'] == date].nlargest(top_n, 'rating')
frame = {
'date': date.strftime('%Y-%m-%d'),
'timestamp': int(date.timestamp()),
'models': []
}
for rank, row in enumerate(date_data.itertuples(), 1):
frame['models'].append({
'rank': rank,
'name': row.model,
'rating': float(row.rating),
'matches': int(row.matches),
'wins': float(row.wins)
})
frames.append(frame)
animation_data = {
'frames': frames,
'total_frames': len(frames),
'top_n': top_n,
'start_date': dates[0].strftime('%Y-%m-%d'),
'end_date': dates[-1].strftime('%Y-%m-%d')
}
return animation_data
def generate_html_animation(animation_data: dict, output_path: str = "leaderboard_animation.html"):
"""
Generate standalone HTML file with D3.js bar chart race animation.
Args:
animation_data: Dictionary from prepare_animation_data
output_path: Path to save HTML file
"""
html_template = """<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Model Leaderboard Evolution</title>
<script src="https://d3js.org/d3.v7.min.js"></script>
<style>
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
margin: 0;
padding: 20px;
background: #f5f5f5;
}
#container {
max-width: 1200px;
margin: 0 auto;
background: white;
padding: 30px;
border-radius: 10px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
h1 {
text-align: center;
color: #333;
margin-bottom: 10px;
}
#date-display {
text-align: center;
font-size: 24px;
font-weight: bold;
color: #666;
margin-bottom: 20px;
}
#chart {
margin: 20px 0;
}
.bar {
fill: steelblue;
cursor: pointer;
transition: fill 0.3s;
}
.bar:hover {
fill: #4682b4;
}
.bar-label {
font-size: 14px;
fill: white;
font-weight: bold;
}
.bar-value {
font-size: 12px;
fill: #333;
}
.rank-label {
font-size: 18px;
fill: #666;
font-weight: bold;
}
#controls {
text-align: center;
margin-top: 30px;
}
button {
padding: 10px 20px;
margin: 0 5px;
font-size: 16px;
cursor: pointer;
border: none;
border-radius: 5px;
background: #4CAF50;
color: white;
transition: background 0.3s;
}
button:hover {
background: #45a049;
}
button:disabled {
background: #ccc;
cursor: not-allowed;
}
#progress-bar {
width: 100%;
height: 5px;
background: #e0e0e0;
margin-top: 20px;
border-radius: 3px;
overflow: hidden;
}
#progress {
height: 100%;
background: #4CAF50;
width: 0%;
transition: width 0.5s;
}
#speed-control {
margin-top: 20px;
text-align: center;
}
#speed-slider {
width: 300px;
margin: 0 10px;
}
.info-box {
background: #f9f9f9;
padding: 15px;
border-radius: 5px;
margin-top: 20px;
font-size: 14px;
color: #666;
}
</style>
</head>
<body>
<div id="container">
<h1>🏆 Model Leaderboard Evolution</h1>
<div id="date-display">Loading...</div>
<div id="chart"></div>
<div id="controls">
<button id="play-btn">▶ Play</button>
<button id="pause-btn" disabled>⏸ Pause</button>
<button id="reset-btn">↺ Reset</button>
</div>
<div id="progress-bar">
<div id="progress"></div>
</div>
<div id="speed-control">
<label>Speed: </label>
<input type="range" id="speed-slider" min="1" max="10" value="5">
<span id="speed-value">5x</span>
</div>
<div class="info-box">
<strong>About:</strong> This animation shows the evolution of model rankings based on Elo ratings
calculated from Chatbot Arena voting data. Each frame represents a snapshot in time,
with models ranked by their current Elo rating. Bars show the rating value,
and the animation reveals how models compete and evolve over time.
</div>
</div>
<script>
const data = """ + json.dumps(animation_data, indent=2) + """;
// Configuration
const margin = {top: 20, right: 100, bottom: 40, left: 50};
const width = 1100 - margin.left - margin.right;
const height = 600 - margin.top - margin.bottom;
const barHeight = height / data.top_n - 5;
// Create SVG
const svg = d3.select("#chart")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", `translate(${margin.left},${margin.top})`);
// Scales
const xScale = d3.scaleLinear()
.domain([0, d3.max(data.frames.flatMap(f => f.models.map(m => m.rating)))])
.range([0, width - 200]);
// Color scale
const colorScale = d3.scaleOrdinal(d3.schemeCategory10);
// Animation state
let currentFrame = 0;
let isPlaying = false;
let animationInterval = null;
let animationSpeed = 500; // milliseconds per frame
// Update speed based on slider
d3.select("#speed-slider").on("input", function() {
const speed = +this.value;
animationSpeed = 1000 / speed;
d3.select("#speed-value").text(`${speed}x`);
if (isPlaying) {
stopAnimation();
startAnimation();
}
});
function updateChart(frameIndex) {
const frame = data.frames[frameIndex];
// Update date display
d3.select("#date-display").text(frame.date);
// Update progress bar
const progress = ((frameIndex + 1) / data.total_frames) * 100;
d3.select("#progress").style("width", `${progress}%`);
// Update max value for scale
const maxRating = d3.max(frame.models, d => d.rating);
xScale.domain([0, maxRating * 1.1]);
// Bind data
const bars = svg.selectAll(".bar-group")
.data(frame.models, d => d.name);
// Remove old bars
bars.exit()
.transition()
.duration(animationSpeed * 0.8)
.style("opacity", 0)
.remove();
// Add new bars
const enter = bars.enter()
.append("g")
.attr("class", "bar-group")
.style("opacity", 0);
enter.append("rect")
.attr("class", "bar")
.attr("height", barHeight);
enter.append("text")
.attr("class", "bar-label")
.attr("x", 10)
.attr("y", barHeight / 2)
.attr("dy", "0.35em");
enter.append("text")
.attr("class", "bar-value")
.attr("y", barHeight / 2)
.attr("dy", "0.35em");
enter.append("text")
.attr("class", "rank-label")
.attr("x", -40)
.attr("y", barHeight / 2)
.attr("dy", "0.35em")
.attr("text-anchor", "middle");
// Update all bars
const merged = enter.merge(bars);
merged.transition()
.duration(animationSpeed * 0.8)
.style("opacity", 1)
.attr("transform", (d, i) => `translate(0,${i * (barHeight + 5)})`);
merged.select(".bar")
.transition()
.duration(animationSpeed * 0.8)
.attr("width", d => xScale(d.rating))
.attr("fill", d => colorScale(d.name));
merged.select(".bar-label")
.text(d => d.name);
merged.select(".bar-value")
.transition()
.duration(animationSpeed * 0.8)
.attr("x", d => xScale(d.rating) + 10)
.text(d => `${Math.round(d.rating)} (${d.matches} matches)`);
merged.select(".rank-label")
.text(d => `#${d.rank}`);
}
function startAnimation() {
if (currentFrame >= data.total_frames - 1) {
currentFrame = 0;
}
isPlaying = true;
d3.select("#play-btn").property("disabled", true);
d3.select("#pause-btn").property("disabled", false);
animationInterval = setInterval(() => {
updateChart(currentFrame);
currentFrame++;
if (currentFrame >= data.total_frames) {
stopAnimation();
currentFrame = data.total_frames - 1;
}
}, animationSpeed);
}
function stopAnimation() {
isPlaying = false;
d3.select("#play-btn").property("disabled", false);
d3.select("#pause-btn").property("disabled", true);
if (animationInterval) {
clearInterval(animationInterval);
animationInterval = null;
}
}
function resetAnimation() {
stopAnimation();
currentFrame = 0;
updateChart(currentFrame);
d3.select("#progress").style("width", "0%");
}
// Button handlers
d3.select("#play-btn").on("click", startAnimation);
d3.select("#pause-btn").on("click", stopAnimation);
d3.select("#reset-btn").on("click", resetAnimation);
// Initialize with first frame
updateChart(0);
// Auto-play on load
setTimeout(startAnimation, 1000);
</script>
</body>
</html>"""
# Keep generated evidence friendly to `git diff --check` and deterministic
# across editors that otherwise strip indentation-only lines.
html_template = "\n".join(line.rstrip() for line in html_template.splitlines()) + "\n"
# Write to file
with open(output_path, 'w', encoding='utf-8') as f:
f.write(html_template)
print(f"Generated animation HTML at: {output_path}")
print(f"Open the file in a web browser to view the animation.")
def create_simple_animation(history_df: pd.DataFrame, output_path: str = "leaderboard_animation.html", top_n: int = 15):
"""
Convenience function to create animation in one step.
Args:
history_df: DataFrame with rating history
output_path: Path to save HTML file
top_n: Number of top models to show
"""
print("Preparing animation data...")
animation_data = prepare_animation_data(history_df, top_n)
print(f"Generating HTML animation with {animation_data['total_frames']} frames...")
generate_html_animation(animation_data, output_path)
return output_path