infinite-agents-public/generate_index.py

402 lines
15 KiB
Python
Executable File

#!/usr/bin/env python3
"""
Generate index.html dashboard by scanning demo directories.
Automatically discovers all HTML demos and updates the dashboard.
Usage:
python3 generate_index.py
Or make executable and run:
chmod +x generate_index.py
./generate_index.py
"""
import os
import json
import re
from pathlib import Path
from datetime import datetime
def scan_directory(path, pattern="*.html"):
"""Scan directory for HTML files matching pattern."""
if not os.path.exists(path):
return []
files = sorted(Path(path).glob(pattern))
return [str(f.relative_to('.')) for f in files]
def extract_title_from_html(filepath):
"""Extract title from HTML file."""
try:
with open(filepath, 'r', encoding='utf-8') as f:
content = f.read(2000) # Read first 2KB
# Try to find title in various formats
title_match = re.search(r'<title>(.*?)</title>', content, re.IGNORECASE)
if title_match:
return title_match.group(1).strip()
# Try h1 tag
h1_match = re.search(r'<h1[^>]*>(.*?)</h1>', content, re.IGNORECASE)
if h1_match:
return h1_match.group(1).strip()
# Try h2 in info div
h2_match = re.search(r'<h2[^>]*>(.*?)</h2>', content, re.IGNORECASE)
if h2_match:
return h2_match.group(1).strip()
except Exception as e:
print(f"Warning: Could not read {filepath}: {e}")
return None
def extract_description_from_html(filepath):
"""Extract description from HTML file."""
try:
with open(filepath, 'r', encoding='utf-8') as f:
content = f.read(5000) # Read first 5KB
# Look for description in meta tag
meta_match = re.search(r'<meta name="description" content="(.*?)"', content, re.IGNORECASE)
if meta_match:
return meta_match.group(1).strip()
# Look for technique/learning in info panel
technique_match = re.search(r'<strong>Technique:</strong>\s*(.*?)</p>', content, re.IGNORECASE | re.DOTALL)
if technique_match:
return technique_match.group(1).strip()
# Look for first paragraph in info div
p_match = re.search(r'<div[^>]*id="info"[^>]*>.*?<p[^>]*>(.*?)</p>', content, re.IGNORECASE | re.DOTALL)
if p_match:
text = p_match.group(1).strip()
# Remove HTML tags
text = re.sub(r'<[^>]+>', '', text)
return text[:150]
except Exception as e:
print(f"Warning: Could not read {filepath}: {e}")
return "Interactive demo"
def generate_demo_data():
"""Generate demo data by scanning directories."""
demos = {
'threejs': [],
'sdg': [],
'd3': [],
'mapbox': [],
'vaccineTimeseries': [],
'claudeDevTools': [],
'uiSingle': [],
'uiModular': [],
'infiniteVariants': []
}
# Scan Three.js demos
threejs_files = scan_directory('threejs_viz', 'threejs_viz_*.html')
for i, filepath in enumerate(threejs_files, 1):
title = extract_title_from_html(filepath) or f"Three.js Viz {i}"
description = extract_description_from_html(filepath)
demos['threejs'].append({
'number': i,
'title': title.replace('Three.js - ', ''),
'description': description,
'path': filepath,
'type': 'Foundation' if i <= 5 else 'Intermediate' if i <= 12 else 'Advanced',
'techniques': []
})
# Scan SDG demos
sdg_files = scan_directory('sdg_viz', 'sdg_viz_*.html')
for i, filepath in enumerate(sdg_files, 1):
title = extract_title_from_html(filepath) or f"SDG Network Viz {i}"
description = extract_description_from_html(filepath)
demos['sdg'].append({
'number': i,
'title': title,
'description': description,
'path': filepath,
'type': 'Network',
'techniques': ['D3.js', 'Force Simulation']
})
# Scan D3 demos
d3_files = scan_directory('d3_test', 'd3_viz_*.html')
for i, filepath in enumerate(d3_files, 1):
title = extract_title_from_html(filepath) or f"D3 Viz {i}"
description = extract_description_from_html(filepath)
# Remove "D3 Visualization N: " prefix if present
if title.startswith('D3 Visualization'):
parts = title.split(':', 1)
if len(parts) > 1:
title = parts[1].strip()
demos['d3'].append({
'number': i,
'title': title,
'description': description,
'path': filepath,
'type': 'D3 Visualization',
'techniques': ['D3.js', 'Data Visualization', 'SVG']
})
# Scan Mapbox Globe demos
mapbox_dirs = sorted(Path('mapbox_test').glob('mapbox_globe_*/index.html')) if os.path.exists('mapbox_test') else []
for i, filepath in enumerate(mapbox_dirs, 1):
title = extract_title_from_html(str(filepath)) or f"Mapbox Globe {i}"
description = extract_description_from_html(str(filepath))
# Remove "Globe Viz N: " prefix if present
if title.startswith('Globe Viz'):
parts = title.split(':', 1)
if len(parts) > 1:
title = parts[1].strip()
demos['mapbox'].append({
'number': i,
'title': title,
'description': description,
'path': str(filepath),
'type': 'Globe Visualization',
'techniques': ['Mapbox GL JS', '3D Globe', 'GeoJSON']
})
# Scan Vaccine Time Series demos
vaccine_dirs = sorted(Path('vaccine_timeseries').glob('vaccine_timeseries_*/index.html')) if os.path.exists('vaccine_timeseries') else []
for i, filepath in enumerate(vaccine_dirs, 1):
title = extract_title_from_html(str(filepath)) or f"Vaccine Timeline {i}"
description = extract_description_from_html(str(filepath))
demos['vaccineTimeseries'].append({
'number': i,
'title': title,
'description': description,
'path': str(filepath),
'type': 'Timeline Visualization',
'techniques': ['Mapbox GL JS', 'Chart.js', 'Time Series', 'Public Health']
})
# Scan Claude Code DevTools demos
devtools_files = scan_directory('claude_code_devtools', 'claude_devtool_*.html')
for i, filepath in enumerate(devtools_files, 1):
title = extract_title_from_html(filepath) or f"DevTool {i}"
description = extract_description_from_html(filepath)
# Remove " - Claude Code DevTools" suffix if present
if ' - Claude Code DevTools' in title:
title = title.replace(' - Claude Code DevTools', '')
demos['claudeDevTools'].append({
'number': i,
'title': title,
'description': description,
'path': filepath,
'type': 'DevTool',
'techniques': ['Developer Tools', 'Web APIs']
})
# Scan UI Single File demos
src_files = scan_directory('src', 'ui_hybrid_*.html')
for i, filepath in enumerate(src_files, 1):
demos['uiSingle'].append({
'number': i,
'title': f"UI Hybrid {i}",
'description': 'Themed hybrid UI component combining multiple interface elements',
'path': filepath,
'type': 'Single File',
'techniques': ['Themed Design', 'Hybrid Components']
})
# Scan UI Infinite demos
src_infinite_files = scan_directory('src_infinite', 'ui_hybrid_*.html')
offset = len(demos['uiSingle'])
for i, filepath in enumerate(src_infinite_files, 1):
demos['uiSingle'].append({
'number': offset + i,
'title': f"UI Hybrid {i} (Infinite)",
'description': 'Infinite mode generated themed component',
'path': filepath,
'type': 'Single File (Infinite)',
'techniques': ['Infinite Generation', 'Progressive Complexity']
})
# Scan UI Modular demos
modular_dirs = sorted(Path('src_group').glob('ui_hybrid_*/index.html')) if os.path.exists('src_group') else []
for i, filepath in enumerate(modular_dirs, 1):
demos['uiModular'].append({
'number': i,
'title': f"UI Hybrid {i} (Modular)",
'description': 'Professional 3-file architecture with separated HTML, CSS, and JavaScript',
'path': str(filepath),
'type': 'Modular',
'techniques': ['Separation of Concerns', 'Modular Architecture']
})
# Scan Infinite Variants test outputs
if os.path.exists('infinite_variants'):
variant_dirs = sorted(Path('infinite_variants').glob('infinite_variant_*/test_output'))
for variant_dir in variant_dirs:
# Extract variant number
variant_match = re.search(r'infinite_variant_(\d+)', str(variant_dir))
variant_num = variant_match.group(1) if variant_match else '?'
# Variant names for better titles
variant_names = {
'1': 'Pattern Synthesis',
'2': 'Utility Commands',
'3': 'Pluggable Templates',
'4': 'Quality Evaluation',
'5': 'Config-Driven',
'6': 'State Management',
'7': 'Meta Self-Improvement'
}
variant_name = variant_names.get(variant_num, f'Variant {variant_num}')
# Scan HTML and JS files in this variant's test_output
variant_files = sorted(list(variant_dir.glob('*.html')) + list(variant_dir.glob('*.js')))
for filepath in variant_files:
# Extract title based on file type
if filepath.suffix == '.html':
title = extract_title_from_html(str(filepath)) or filepath.name
description = extract_description_from_html(str(filepath))
else:
# For .js files, use filename as title
title = filepath.stem.replace('_', ' ').title()
description = f"Meta-aware JavaScript code pattern"
demos['infiniteVariants'].append({
'number': len(demos['infiniteVariants']) + 1,
'title': title,
'description': f"[Variant {variant_num}: {variant_name}] {description}",
'path': str(filepath),
'type': variant_name,
'techniques': ['Infinite Loop Variant', variant_name]
})
return demos
def generate_index_html(demos):
"""Generate the complete index.html file."""
total_demos = sum(len(demos[cat]) for cat in demos)
threejs_count = len(demos['threejs'])
sdg_count = len(demos['sdg'])
d3_count = len(demos['d3'])
mapbox_count = len(demos['mapbox'])
vaccine_count = len(demos['vaccineTimeseries'])
devtools_count = len(demos['claudeDevTools'])
ui_count = len(demos['uiSingle']) + len(demos['uiModular'])
# Read template (current index.html structure)
template_path = 'index.html'
if os.path.exists(template_path):
with open(template_path, 'r', encoding='utf-8') as f:
template = f.read()
else:
print("Error: index.html template not found")
return None
# Replace the demos data in the JavaScript section
demos_json = json.dumps(demos, indent=8)
# Find and replace the demos object in the script
pattern = r'const demos = \{[\s\S]*?\};'
replacement = f'const demos = {demos_json};'
updated_html = re.sub(pattern, replacement, template)
# Update stats in HTML
updated_html = re.sub(
r'<div class="stat-number" id="totalDemos">\d+</div>',
f'<div class="stat-number" id="totalDemos">{total_demos}</div>',
updated_html
)
updated_html = re.sub(
r'<div class="stat-number" id="threejsCount">\d+</div>',
f'<div class="stat-number" id="threejsCount">{threejs_count}</div>',
updated_html
)
updated_html = re.sub(
r'<div class="stat-number" id="uiCount">\d+</div>',
f'<div class="stat-number" id="uiCount">{ui_count}</div>',
updated_html
)
# Update category counts
updated_html = re.sub(
r'(<div class="category-title">[\s\S]*?Three\.js 3D Visualizations[\s\S]*?</div>\s*<div class="category-count">)\d+ demos',
f'\\g<1>{threejs_count} demos',
updated_html
)
updated_html = re.sub(
r'(<div class="category-title">[\s\S]*?SDG Network Visualizations[\s\S]*?</div>\s*<div class="category-count">)\d+ demos',
f'\\g<1>{sdg_count} demos',
updated_html
)
updated_html = re.sub(
r'(<div class="category-title">[\s\S]*?Themed Hybrid UI Components[\s\S]*?</div>\s*<div class="category-count">)\d+ demos',
f'\\g<1>{len(demos["uiSingle"])} demos',
updated_html
)
updated_html = re.sub(
r'(<div class="category-title">[\s\S]*?Modular UI Components[\s\S]*?</div>\s*<div class="category-count">)\d+ demos',
f'\\g<1>{len(demos["uiModular"])} demos',
updated_html
)
# Add generation timestamp comment
timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
comment = f'<!-- Auto-generated: {timestamp} by generate_index.py -->\n'
updated_html = re.sub(r'<!DOCTYPE html>', f'{comment}<!DOCTYPE html>', updated_html)
return updated_html
def main():
"""Main execution."""
print("🔍 Scanning demo directories...")
demos = generate_demo_data()
# Print summary
print(f"\n📊 Found demos:")
print(f" • Three.js: {len(demos['threejs'])}")
print(f" • SDG Networks: {len(demos['sdg'])}")
print(f" • D3 Visualizations: {len(demos['d3'])}")
print(f" • Mapbox Globes: {len(demos['mapbox'])}")
print(f" • Vaccine Timeseries: {len(demos['vaccineTimeseries'])}")
print(f" • Claude DevTools: {len(demos['claudeDevTools'])}")
print(f" • UI Single File: {len(demos['uiSingle'])}")
print(f" • UI Modular: {len(demos['uiModular'])}")
print(f" • Infinite Variants: {len(demos['infiniteVariants'])}")
print(f" • Total: {sum(len(demos[cat]) for cat in demos)}")
print("\n✨ Generating index.html...")
html = generate_index_html(demos)
if html:
# Write updated index.html
with open('index.html', 'w', encoding='utf-8') as f:
f.write(html)
print("✅ index.html updated successfully!")
print("\n🚀 View dashboard: http://localhost:8889/")
else:
print("❌ Failed to generate index.html")
return 1
return 0
if __name__ == '__main__':
exit(main())