"""
AI Economic Pulse — Interactive Explorer for the Anthropic Economic Index
Built by nicovlr | Data: Anthropic (CC-BY)
Explore how AI is reshaping the global economy using real-world data
from millions of Claude conversations.
"""
import gradio as gr
import pandas as pd
import plotly.graph_objects as go
import plotly.express as px
import numpy as np
from huggingface_hub import hf_hub_download
from rapidfuzz import process, fuzz
# ============================================================================
# DESIGN SYSTEM
# ============================================================================
COLORS = {
"primary": "#D97757",
"primary_light": "#f0c4b0",
"secondary": "#1a1a2e",
"accent": "#e8ddd3",
"bg": "#fafaf8",
"card": "#ffffff",
"text": "#2d2d2d",
"muted": "#8b8b8b",
"success": "#2ecc71",
"warning": "#f39c12",
"danger": "#e74c3c",
"info": "#3498db",
}
PLOTLY_DEFAULTS = dict(
font=dict(family="Inter, system-ui, -apple-system, sans-serif", color=COLORS["text"]),
paper_bgcolor="white",
plot_bgcolor="#fafafa",
colorway=[
COLORS["primary"], COLORS["info"], COLORS["success"],
"#9b59b6", COLORS["warning"], COLORS["danger"],
"#1abc9c", "#e67e22", "#2c3e50", "#f1c40f",
],
)
DEFAULT_MARGIN = dict(l=60, r=30, t=50, b=50)
def apply_layout(fig, **overrides):
"""Apply consistent layout with optional overrides (margin, title, etc.)."""
layout = {**PLOTLY_DEFAULTS, "margin": DEFAULT_MARGIN, **overrides}
fig.update_layout(**layout)
return fig
def styled_card(title, value, subtitle="", color=COLORS["primary"]):
"""Generate HTML for a styled metric card."""
return f"""
{title}
{value}
{subtitle}
"""
def risk_badge(score):
"""Return HTML badge for exposure risk level."""
if score >= 0.5:
level, color, emoji = "Very High", COLORS["danger"], "!!"
elif score >= 0.3:
level, color, emoji = "High", COLORS["warning"], "!"
elif score >= 0.15:
level, color, emoji = "Moderate", COLORS["info"], "~"
else:
level, color, emoji = "Low", COLORS["success"], ""
return f"""
{emoji} {level} Exposure
"""
# ============================================================================
# DATA LOADING
# ============================================================================
print("=" * 60)
print(" AI Economic Pulse — Loading data...")
print("=" * 60)
DATASET_ID = "Anthropic/EconomicIndex"
def load_dataset_file(path):
"""Download and load a CSV from the Anthropic Economic Index."""
local = hf_hub_download(repo_id=DATASET_ID, filename=path, repo_type="dataset")
return pd.read_csv(local)
print("[1/4] Loading job exposure data...")
df_jobs = load_dataset_file("labor_market_impacts/job_exposure.csv")
df_jobs["exposure_pct"] = (df_jobs["observed_exposure"] * 100).round(1)
df_jobs["rank"] = df_jobs["observed_exposure"].rank(ascending=False, method="min").astype(int)
total_jobs = len(df_jobs)
job_titles = df_jobs["title"].tolist()
print(f" {total_jobs} occupations loaded.")
print("[2/4] Loading task penetration data...")
df_tasks = load_dataset_file("labor_market_impacts/task_penetration.csv")
print(f" {len(df_tasks)} task records loaded.")
print("[3/4] Loading Claude.ai usage data (this may take a moment)...")
df_claude = load_dataset_file(
"release_2026_03_24/data/aei_raw_claude_ai_2026-02-05_to_2026-02-12.csv"
)
print(f" {len(df_claude):,} rows loaded.")
print("[4/4] Loading API usage data...")
df_api = load_dataset_file(
"release_2026_03_24/data/aei_raw_1p_api_2026-02-05_to_2026-02-12.csv"
)
print(f" {len(df_api):,} rows loaded.")
# ============================================================================
# DATA PRE-PROCESSING
# ============================================================================
print("Pre-processing data...")
# --- Global summaries from Claude.ai data ---
def get_global_facet(df, facet_name, variable_suffix="_pct"):
"""Extract global-level data for a given facet."""
mask = (
(df["facet"] == facet_name)
& (df["geography"] == "global")
& (df["variable"].str.endswith(variable_suffix))
)
subset = df[mask][["cluster_name", "value"]].copy()
subset = subset[subset["cluster_name"] != "not_classified"]
subset = subset.sort_values("value", ascending=False)
return subset
def get_global_numeric(df, facet_name):
"""Extract global numeric stats (mean, median) for a facet."""
mask = (
(df["facet"] == facet_name)
& (df["geography"] == "global")
& (df["variable"].str.contains("_mean$|_median$", regex=True))
)
return df[mask][["variable", "cluster_name", "value"]].copy()
# Collaboration patterns
collab_data = get_global_facet(df_claude, "collaboration")
# Use case breakdown
usecase_data = get_global_facet(df_claude, "use_case")
# Task success
success_data = get_global_facet(df_claude, "task_success")
# Request complexity
request_data = get_global_facet(df_claude, "request")
# AI autonomy stats
autonomy_stats = get_global_numeric(df_claude, "ai_autonomy")
# Time data
time_human = get_global_numeric(df_claude, "human_only_time")
time_ai = get_global_numeric(df_claude, "human_with_ai_time")
# --- Country-level data ---
country_usage = df_claude[
(df_claude["facet"] == "country")
& (df_claude["geography"] == "global")
& (df_claude["variable"] == "usage_pct")
].copy()
country_usage = country_usage[country_usage["cluster_name"] != "not_classified"]
# O*NET task data from Claude usage
onet_usage = get_global_facet(df_claude, "onet_task")
# --- Task penetration processing ---
task_cols = df_tasks.columns.tolist()
print("Data ready!")
print("=" * 60)
# ============================================================================
# CHART GENERATORS
# ============================================================================
def make_gauge(score, title="AI Exposure"):
"""Create a gauge chart for exposure score."""
if score >= 0.5:
bar_color = COLORS["danger"]
elif score >= 0.3:
bar_color = COLORS["warning"]
elif score >= 0.15:
bar_color = COLORS["info"]
else:
bar_color = COLORS["success"]
fig = go.Figure(go.Indicator(
mode="gauge+number",
value=score * 100,
number={"suffix": "%", "font": {"size": 48, "color": COLORS["text"]}},
gauge={
"axis": {"range": [0, 100], "tickwidth": 1, "tickcolor": COLORS["muted"]},
"bar": {"color": bar_color, "thickness": 0.7},
"bgcolor": "#f5f0eb",
"borderwidth": 0,
"steps": [
{"range": [0, 15], "color": "rgba(46,204,113,0.08)"},
{"range": [15, 30], "color": "rgba(52,152,219,0.08)"},
{"range": [30, 50], "color": "rgba(243,156,18,0.08)"},
{"range": [50, 100], "color": "rgba(231,76,60,0.08)"},
],
},
))
apply_layout(fig, height=280, margin=dict(l=30, r=30, t=30, b=10))
return fig
def make_top_bottom_chart(df, n=20, show_top=True):
"""Horizontal bar chart of top or bottom N jobs by exposure."""
if show_top:
subset = df.nlargest(n, "observed_exposure")
title = f"Top {n} Most Exposed Occupations"
else:
subset = df[df["observed_exposure"] > 0].nsmallest(n, "observed_exposure")
title = f"Top {n} Least Exposed Occupations"
subset = subset.sort_values("observed_exposure", ascending=True)
colors = [
COLORS["danger"] if v >= 0.5
else COLORS["warning"] if v >= 0.3
else COLORS["info"] if v >= 0.15
else COLORS["success"]
for v in subset["observed_exposure"]
]
fig = go.Figure(go.Bar(
x=subset["observed_exposure"] * 100,
y=subset["title"],
orientation="h",
marker_color=colors,
text=[f"{v:.1f}%" for v in subset["observed_exposure"] * 100],
textposition="outside",
))
apply_layout(fig,
title=dict(text=title, font=dict(size=16)),
xaxis_title="Exposure Score (%)",
yaxis_title="",
height=max(400, n * 28),
margin=dict(l=300, r=60, t=50, b=50),
)
return fig
def make_comparison_chart(jobs_data):
"""Bar chart comparing multiple jobs."""
fig = go.Figure()
colors = [COLORS["primary"], COLORS["info"], COLORS["success"], "#9b59b6", COLORS["warning"]]
for i, (_, row) in enumerate(jobs_data.iterrows()):
color = colors[i % len(colors)]
fig.add_trace(go.Bar(
x=[row["title"]],
y=[row["observed_exposure"] * 100],
name=row["title"],
marker_color=color,
text=[f"{row['observed_exposure']*100:.1f}%"],
textposition="outside",
))
apply_layout(fig,
title=dict(text="Job Exposure Comparison", font=dict(size=16)),
yaxis_title="Exposure Score (%)",
yaxis_range=[0, max(jobs_data["observed_exposure"] * 100) * 1.3 + 5],
showlegend=False,
height=400,
)
return fig
def make_world_map():
"""Choropleth map of AI usage by country."""
map_data = country_usage.copy()
map_data = map_data.rename(columns={"cluster_name": "country_code", "value": "usage_pct"})
map_data["usage_pct"] = map_data["usage_pct"] * 100
fig = px.choropleth(
map_data,
locations="country_code",
color="usage_pct",
color_continuous_scale=[
[0, "#fef3ee"],
[0.25, COLORS["primary_light"]],
[0.5, COLORS["primary"]],
[0.75, "#c0553a"],
[1, COLORS["secondary"]],
],
labels={"usage_pct": "AI Usage Share (%)"},
)
apply_layout(fig,
title=dict(text="Global AI Adoption (Claude.ai Usage by Country)", font=dict(size=16)),
height=500,
geo=dict(
showframe=False,
showcoastlines=True,
coastlinecolor="#ddd",
projection_type="natural earth",
bgcolor="#fafaf8",
),
margin=dict(l=0, r=0, t=50, b=0),
)
return fig
def make_donut(data, title, hole=0.55):
"""Donut chart from a cluster_name/value dataframe."""
data = data.head(10) # limit to top 10 categories
fig = go.Figure(go.Pie(
labels=data["cluster_name"],
values=data["value"],
hole=hole,
textinfo="label+percent",
textposition="outside",
marker=dict(colors=PLOTLY_DEFAULTS["colorway"][:len(data)]),
))
apply_layout(fig,
title=dict(text=title, font=dict(size=16)),
height=420,
showlegend=True,
legend=dict(orientation="h", yanchor="bottom", y=-0.3, xanchor="center", x=0.5),
)
return fig
def make_bar_facet(data, title, x_label="Category", y_label="Share (%)"):
"""Vertical bar chart from facet data."""
data = data.head(15)
fig = go.Figure(go.Bar(
x=data["cluster_name"],
y=data["value"] * 100,
marker_color=COLORS["primary"],
text=[f"{v:.1f}%" for v in data["value"] * 100],
textposition="outside",
))
apply_layout(fig,
title=dict(text=title, font=dict(size=16)),
xaxis_title=x_label,
yaxis_title=y_label,
height=400,
xaxis_tickangle=-35,
)
return fig
def make_distribution_chart():
"""Show the distribution of exposure scores across all jobs."""
fig = go.Figure()
bins = [0, 0.05, 0.10, 0.15, 0.20, 0.30, 0.50, 1.0]
labels = ["0-5%", "5-10%", "10-15%", "15-20%", "20-30%", "30-50%", "50%+"]
counts = pd.cut(df_jobs["observed_exposure"], bins=bins, labels=labels).value_counts()
counts = counts.reindex(labels)
colors_dist = [
COLORS["success"], COLORS["success"], COLORS["info"],
COLORS["info"], COLORS["warning"], COLORS["warning"], COLORS["danger"],
]
fig.add_trace(go.Bar(
x=labels,
y=counts.values,
marker_color=colors_dist,
text=counts.values,
textposition="outside",
))
apply_layout(fig,
title=dict(text="Distribution of AI Exposure Across All Occupations", font=dict(size=16)),
xaxis_title="Exposure Score Range",
yaxis_title="Number of Occupations",
height=380,
)
return fig
# ============================================================================
# SEARCH & INTERACTION LOGIC
# ============================================================================
def search_job(query):
"""Fuzzy search for a job title."""
if not query or len(query.strip()) < 2:
return gr.update(choices=[], value=None)
matches = process.extract(query, job_titles, scorer=fuzz.WRatio, limit=8)
results = [m[0] for m in matches if m[1] > 40]
return gr.update(choices=results, value=results[0] if results else None)
def analyze_job(job_title):
"""Generate full analysis for a selected job."""
if not job_title:
empty = go.Figure()
apply_layout(empty, height=100)
return (
"Search for a job above
",
empty, "", ""
)
try:
row = df_jobs[df_jobs["title"] == job_title]
if row.empty:
empty = go.Figure()
apply_layout(empty, height=100)
return (
"Job not found
",
empty, "", ""
)
row = row.iloc[0]
score = float(row["observed_exposure"])
rank = int(row["rank"])
occ_code = str(row["occ_code"])
# Percentile
percentile = (total_jobs - rank) / total_jobs * 100
# Find similar jobs (same 2-digit SOC code)
soc_prefix = occ_code[:2]
similar = df_jobs[
(df_jobs["occ_code"].str.startswith(soc_prefix))
& (df_jobs["title"] != job_title)
].head(5)
# Risk color
if score >= 0.5:
score_color = COLORS["danger"]
elif score >= 0.3:
score_color = COLORS["warning"]
elif score >= 0.15:
score_color = COLORS["info"]
else:
score_color = COLORS["success"]
# Build cards HTML
badge = risk_badge(score)
card1 = styled_card("AI Exposure Score", f"{score*100:.1f}%", f"Rank #{rank} of {total_jobs}", score_color)
card2 = styled_card("Percentile", f"{percentile:.0f}th", "Higher = more exposed than other jobs", COLORS["primary"])
card3 = styled_card("Risk Level", badge, "", COLORS["text"])
cards_html = f"""
{card1}
{card2}
{card3}
{job_title}
O*NET Code: {occ_code}
"""
# Gauge chart
gauge = make_gauge(score)
# Similar jobs comparison
if not similar.empty:
similar_html = "Related Occupations
"
similar_html += "| Occupation | Exposure |
"
for _, s in similar.iterrows():
bar_width = float(s["observed_exposure"]) * 100
similar_html += f"""
| {s['title']} |
|
"""
similar_html += "
"
else:
similar_html = ""
# Interpretation
if score >= 0.5:
interp = "This occupation has very high AI exposure. A significant portion of its tasks are already being performed with AI assistance. Workers in this field should actively develop AI collaboration skills."
elif score >= 0.3:
interp = "This occupation has high AI exposure. Many of its tasks intersect with AI capabilities. Embracing AI tools can significantly boost productivity."
elif score >= 0.15:
interp = "This occupation has moderate AI exposure. Some tasks are being augmented by AI, but core functions still require substantial human expertise."
else:
interp = "This occupation has low AI exposure. Most of its tasks are not significantly impacted by current AI capabilities, though this may change over time."
interp_html = f"""
Interpretation: {interp}
"""
return cards_html, gauge, similar_html, interp_html
except Exception as e:
import traceback
err = traceback.format_exc()
print(f"Error in analyze_job: {err}")
empty = go.Figure()
apply_layout(empty, height=100)
return (
f"Error analyzing job: {str(e)}
",
empty, "", ""
)
# ============================================================================
# KEY METRICS
# ============================================================================
avg_exposure = df_jobs["observed_exposure"].mean()
median_exposure = df_jobs["observed_exposure"].median()
high_exposure_jobs = len(df_jobs[df_jobs["observed_exposure"] >= 0.3])
zero_exposure_jobs = len(df_jobs[df_jobs["observed_exposure"] == 0])
# ============================================================================
# GRADIO UI
# ============================================================================
CSS = """
.gradio-container {
max-width: 1200px !important;
margin: auto;
background: #fafaf8 !important;
}
.header-banner {
background: white;
color: #1a1a2e;
border: 1px solid #f0ece8;
box-shadow: 0 2px 12px rgba(0,0,0,0.06);
padding: 48px 40px;
border-radius: 20px;
margin-bottom: 24px;
text-align: center;
}
.header-banner h1 {
font-size: 2.6em !important;
font-weight: 800;
margin: 0 0 8px 0;
letter-spacing: -0.02em;
}
.header-banner p {
font-size: 1.15em;
color: #666;
margin: 0;
max-width: 700px;
margin: 0 auto;
}
.metric-row {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
gap: 16px;
margin: 20px 0;
}
.tab-content { padding: 8px 0; }
.source-badge {
display: inline-block;
background: #f0ece8;
color: #666;
padding: 4px 12px;
border-radius: 12px;
font-size: 0.8em;
margin-top: 8px;
}
"""
with gr.Blocks(
theme=gr.themes.Soft(
primary_hue="orange",
secondary_hue="gray",
neutral_hue="gray",
font=("Inter", "system-ui", "-apple-system", "sans-serif"),
),
title="AI Economic Pulse",
css=CSS,
analytics_enabled=True,
) as demo:
# --- Header ---
gr.HTML("""
""")
# --- Key Metrics Bar ---
gr.HTML(f"""
{styled_card("Occupations Tracked", f"{total_jobs:,}", "O*NET classifications")}
{styled_card("Avg Exposure", f"{avg_exposure*100:.1f}%", "Across all occupations", COLORS['info'])}
{styled_card("High Exposure Jobs", f"{high_exposure_jobs}", f"Score >= 30%", COLORS['warning'])}
{styled_card("Data Period", "Feb 2026", "Latest release (5th)", COLORS['muted'])}
""")
# === TABS ===
with gr.Tabs():
# ────────────────────────────────────────────────────────
# TAB 1: SEARCH YOUR JOB
# ────────────────────────────────────────────────────────
with gr.Tab("Search Your Job", id="search"):
gr.Markdown(
"### Find your occupation and see how AI is impacting it\n"
"Search among 800+ O*NET occupations to get a personalized exposure report."
)
with gr.Row():
search_input = gr.Textbox(
label="Search for your job",
placeholder="e.g. Software Developer, Nurse, Marketing Manager...",
scale=3,
)
search_btn = gr.Button("Search", variant="primary", scale=1)
job_dropdown = gr.Dropdown(
label="Select your occupation",
choices=[],
interactive=True,
)
cards_output = gr.HTML()
with gr.Row():
gauge_output = gr.Plot(label="Exposure Gauge")
similar_output = gr.HTML()
interp_output = gr.HTML()
search_btn.click(
fn=search_job,
inputs=[search_input],
outputs=[job_dropdown],
)
search_input.submit(
fn=search_job,
inputs=[search_input],
outputs=[job_dropdown],
)
job_dropdown.change(
fn=analyze_job,
inputs=[job_dropdown],
outputs=[cards_output, gauge_output, similar_output, interp_output],
)
# ────────────────────────────────────────────────────────
# TAB 2: RANKINGS
# ────────────────────────────────────────────────────────
with gr.Tab("Rankings", id="rankings"):
gr.Markdown(
"### Which jobs are most and least exposed to AI?\n"
"Rankings based on observed AI usage for each occupation's tasks."
)
distribution_plot = gr.Plot(value=make_distribution_chart(), label="Distribution")
with gr.Row():
n_jobs = gr.Slider(
minimum=10, maximum=50, value=20, step=5,
label="Number of jobs to show",
)
show_mode = gr.Radio(
choices=["Most Exposed", "Least Exposed"],
value="Most Exposed",
label="Show",
)
ranking_plot = gr.Plot(
value=make_top_bottom_chart(df_jobs, 20, True),
label="Rankings",
)
def update_ranking(n, mode):
return make_top_bottom_chart(df_jobs, int(n), mode == "Most Exposed")
n_jobs.change(fn=update_ranking, inputs=[n_jobs, show_mode], outputs=[ranking_plot])
show_mode.change(fn=update_ranking, inputs=[n_jobs, show_mode], outputs=[ranking_plot])
# Full table
with gr.Accordion("Full data table (all occupations)", open=False):
table_df = df_jobs[["occ_code", "title", "observed_exposure", "rank"]].copy()
table_df.columns = ["Code", "Occupation", "Exposure Score", "Rank"]
table_df = table_df.sort_values("Rank")
gr.Dataframe(
value=table_df,
label="All Occupations",
interactive=False,
wrap=True,
)
# ────────────────────────────────────────────────────────
# TAB 3: WORLD MAP
# ────────────────────────────────────────────────────────
with gr.Tab("Global Map", id="map"):
gr.Markdown(
"### Where in the world is AI being adopted?\n"
"Geographic distribution of Claude.ai usage across countries."
)
world_map = gr.Plot(value=make_world_map(), label="World Map")
gr.Markdown(
f'Source: Claude.ai usage data, Feb 5-12 2026'
)
# Top countries table
if not country_usage.empty:
top_countries = country_usage.nlargest(20, "value").copy()
top_countries["value"] = (top_countries["value"] * 100).round(2)
top_countries = top_countries[["cluster_name", "value"]]
top_countries.columns = ["Country Code", "Usage Share (%)"]
with gr.Accordion("Top 20 countries by AI usage share", open=False):
gr.Dataframe(value=top_countries, interactive=False)
# ────────────────────────────────────────────────────────
# TAB 4: AI USAGE PATTERNS
# ────────────────────────────────────────────────────────
with gr.Tab("AI Usage Patterns", id="patterns"):
gr.Markdown(
"### How are people using AI?\n"
"Breakdown of human-AI collaboration patterns, use cases, and task characteristics."
)
with gr.Row():
with gr.Column():
if not collab_data.empty:
gr.Plot(
value=make_donut(collab_data, "Human-AI Collaboration Patterns"),
label="Collaboration",
)
with gr.Column():
if not usecase_data.empty:
gr.Plot(
value=make_donut(usecase_data, "Use Cases"),
label="Use Cases",
)
with gr.Row():
with gr.Column():
if not success_data.empty:
gr.Plot(
value=make_donut(success_data, "Task Completion Success"),
label="Task Success",
)
with gr.Column():
if not request_data.empty:
gr.Plot(
value=make_bar_facet(
request_data,
"Request Complexity Distribution",
"Complexity Level",
),
label="Request Complexity",
)
# O*NET task usage
if not onet_usage.empty:
gr.Markdown("### Most Common AI-Assisted Tasks (O*NET)")
gr.Plot(
value=make_bar_facet(
onet_usage.head(20),
"Top 20 O*NET Tasks in AI Conversations",
"Task",
"Share (%)",
),
label="O*NET Tasks",
)
# ────────────────────────────────────────────────────────
# TAB 5: API INSIGHTS
# ────────────────────────────────────────────────────────
with gr.Tab("API & Enterprise", id="api"):
gr.Markdown(
"### How enterprises use AI via the API\n"
"Insights from first-party API usage — cost patterns, token usage, "
"and task distribution in production deployments."
)
# API collaboration
api_collab = get_global_facet(df_api, "collaboration")
api_usecase = get_global_facet(df_api, "use_case")
api_tasks = get_global_facet(df_api, "onet_task")
with gr.Row():
with gr.Column():
if not api_collab.empty:
gr.Plot(
value=make_donut(api_collab, "API: Collaboration Patterns"),
)
with gr.Column():
if not api_usecase.empty:
gr.Plot(
value=make_donut(api_usecase, "API: Use Cases"),
)
if not api_tasks.empty:
gr.Markdown("### Top API Tasks (O*NET)")
gr.Plot(
value=make_bar_facet(
api_tasks.head(20),
"Top 20 O*NET Tasks in API Usage",
"Task", "Share (%)",
),
)
# API vs Claude.ai comparison
if not api_collab.empty and not collab_data.empty:
gr.Markdown("### Claude.ai vs API Usage Comparison")
gr.Markdown(
"The API is primarily used for production/enterprise workloads, "
"while Claude.ai serves direct consumer and professional use cases. "
"Compare the collaboration patterns above to see the difference."
)
# ────────────────────────────────────────────────────────
# TAB 6: ABOUT
# ────────────────────────────────────────────────────────
with gr.Tab("About", id="about"):
gr.Markdown("""
### About this Dashboard
**AI Economic Pulse** is an interactive explorer for the
[Anthropic Economic Index](https://www.anthropic.com/economic-index) —
the most comprehensive dataset on real-world AI usage in the economy.
#### What makes this data unique
Unlike theoretical predictions about AI's economic impact, the Anthropic Economic
Index is based on **observed usage** from millions of real Claude conversations.
It measures what people actually use AI for, not what researchers think AI could do.
#### Data sources
| Dataset | Description | Size |
|---------|-------------|------|
| Job Exposure | 800+ occupations with AI exposure scores | 37 KB |
| Task Penetration | O*NET task-level penetration rates | 1.9 MB |
| Claude.ai Usage | Consumer usage by geography, task, collaboration pattern | 96 MB |
| API Usage | Enterprise/developer usage with cost & token metrics | 44 MB |
#### Methodology
- **Exposure scores** are derived from mapping O*NET occupational tasks to observed
AI conversation topics
- **Geographic data** uses ISO 3166-1 (country) and ISO 3166-2 (region) codes
- **Privacy**: minimum 200 conversations per country, 100 per region
- **Time period**: February 5-12, 2026 (latest release)
#### Citation
```bibtex
@misc{anthropic2025economicindex,
title={The Anthropic Economic Index},
author={Anthropic},
year={2025},
url={https://www.anthropic.com/economic-index}
}
```
#### Credits
- **Data**: [Anthropic](https://anthropic.com) (CC-BY license)
- **Dashboard**: Built by [nicovlr](https://huggingface.co/nicovlr)
- **Tech**: Gradio, Plotly, Pandas
---
""")
# --- Footer ---
gr.HTML(f"""
AI Economic Pulse by
nicovlr
• Data: Anthropic Economic Index (CC-BY)
• Not affiliated with Anthropic
""")
if __name__ == "__main__":
demo.launch()