250 lines
8.3 KiB
Python
250 lines
8.3 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
PPT Master - Examples Index Generator
|
|
|
|
Automatically scans the examples directory and generates a README.md index file.
|
|
|
|
Usage:
|
|
python3 scripts/generate_examples_index.py
|
|
python3 scripts/generate_examples_index.py examples
|
|
"""
|
|
|
|
import sys
|
|
from pathlib import Path
|
|
from datetime import datetime
|
|
from collections import defaultdict
|
|
|
|
from console_encoding import configure_utf8_stdio
|
|
|
|
configure_utf8_stdio()
|
|
|
|
try:
|
|
from project_utils import find_all_projects, get_project_info, CANVAS_FORMATS
|
|
except ImportError:
|
|
print("Error: Cannot import the project_utils module")
|
|
print("Please ensure project_utils.py is in the same directory")
|
|
sys.exit(1)
|
|
|
|
|
|
def generate_examples_index(examples_dir: str = 'examples') -> str:
|
|
"""
|
|
Generate a README.md index for the examples directory
|
|
|
|
Args:
|
|
examples_dir: Path to the examples directory
|
|
|
|
Returns:
|
|
Generated README.md content
|
|
"""
|
|
examples_path = Path(examples_dir)
|
|
|
|
if not examples_path.exists():
|
|
print(f"[ERROR] Directory not found: {examples_dir}")
|
|
return ""
|
|
|
|
print(f"[SCAN] Scanning directory: {examples_dir}")
|
|
|
|
# Find all projects
|
|
projects = find_all_projects(examples_dir)
|
|
|
|
if not projects:
|
|
print("[WARN] No projects found")
|
|
return ""
|
|
|
|
print(f"Found {len(projects)} project(s)")
|
|
|
|
# Collect project information
|
|
projects_info = []
|
|
for project_path in projects:
|
|
info = get_project_info(str(project_path))
|
|
projects_info.append(info)
|
|
|
|
# Sort by date (newest first)
|
|
projects_info.sort(key=lambda x: x['date'], reverse=True)
|
|
|
|
# Group by format
|
|
by_format = defaultdict(list)
|
|
for info in projects_info:
|
|
by_format[info['format']].append(info)
|
|
|
|
# Generate README content
|
|
content = []
|
|
content.append("# PPT Master Example Projects Index\n")
|
|
content.append("> This file is auto-generated by `skills/ppt-master/scripts/generate_examples_index.py`\n")
|
|
content.append(f"> Last updated: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n")
|
|
|
|
# Overview statistics
|
|
content.append("## [Stats] Overview\n")
|
|
content.append(f"- **Total projects**: {len(projects_info)}")
|
|
content.append(f"- **Canvas formats**: {len(by_format)} type(s)")
|
|
|
|
total_svgs = sum(info['svg_count'] for info in projects_info)
|
|
content.append(f"- **SVG files**: {total_svgs}")
|
|
|
|
# Statistics by format
|
|
content.append("\n### Format Distribution\n")
|
|
for fmt_key in sorted(by_format.keys(), key=lambda x: len(by_format[x]), reverse=True):
|
|
count = len(by_format[fmt_key])
|
|
fmt_name = CANVAS_FORMATS.get(fmt_key, {}).get('name', fmt_key)
|
|
content.append(f"- **{fmt_name}**: {count} project(s)")
|
|
|
|
# Recently updated
|
|
content.append("\n## [New] Recently Updated\n")
|
|
for info in projects_info[:5]:
|
|
content.append(
|
|
f"- **{info['name']}** ({info['format_name']}) - {info['date_formatted']}")
|
|
|
|
# Project list by format
|
|
content.append("\n## [List] Project List\n")
|
|
|
|
# Define format display order
|
|
format_order = ['ppt169', 'ppt43', 'wechat',
|
|
'xiaohongshu', 'moments', 'story', 'banner', 'a4']
|
|
|
|
for fmt_key in format_order:
|
|
if fmt_key not in by_format:
|
|
continue
|
|
|
|
fmt_info = CANVAS_FORMATS.get(fmt_key, {})
|
|
fmt_name = fmt_info.get('name', fmt_key)
|
|
dimensions = fmt_info.get('dimensions', '')
|
|
|
|
content.append(f"\n### {fmt_name} ({dimensions})\n")
|
|
|
|
projects_list = by_format[fmt_key]
|
|
# Sort by date
|
|
projects_list.sort(key=lambda x: x['date'], reverse=True)
|
|
|
|
for info in projects_list:
|
|
# Project name and link
|
|
project_link = f"./{info['dir_name']}"
|
|
|
|
# Build project entry
|
|
line = f"- **[{info['name']}]({project_link})**"
|
|
|
|
# Add date
|
|
line += f" - {info['date_formatted']}"
|
|
|
|
# Add SVG count
|
|
line += f" - {info['svg_count']} page(s)"
|
|
|
|
content.append(line)
|
|
|
|
# Other uncategorized formats
|
|
other_formats = set(by_format.keys()) - set(format_order)
|
|
if other_formats:
|
|
content.append("\n### Other Formats\n")
|
|
for fmt_key in sorted(other_formats):
|
|
projects_list = by_format[fmt_key]
|
|
for info in projects_list:
|
|
project_link = f"./{info['dir_name']}"
|
|
line = f"- **[{info['name']}]({project_link})**"
|
|
line += f" ({info['format_name']}) - {info['date_formatted']}"
|
|
line += f" - {info['svg_count']} page(s)"
|
|
content.append(line)
|
|
|
|
# Usage instructions
|
|
content.append("\n## [Docs] Usage Instructions\n")
|
|
content.append("### Preview Projects\n")
|
|
content.append("Each project contains the following files:\n")
|
|
content.append("- `README.md` - Project documentation")
|
|
content.append("- `Design Spec & Content Outline.md` - Full design specification")
|
|
content.append("- `svg_output/` - SVG output files\n")
|
|
|
|
content.append("**Method 1: Using an HTTP server (recommended)**\n")
|
|
content.append("```bash")
|
|
content.append(
|
|
"python3 -m http.server --directory examples/<project_name>/svg_output 8000")
|
|
content.append("# Visit http://localhost:8000")
|
|
content.append("```\n")
|
|
|
|
content.append("**Method 2: Open SVG directly**\n")
|
|
content.append("```bash")
|
|
content.append(
|
|
"open examples/<project_name>/svg_output/slide_01_cover.svg")
|
|
content.append("```\n")
|
|
|
|
# Create new project
|
|
content.append("### Create a New Project\n")
|
|
content.append("Refer to existing project structures, or use the project management tool:\n")
|
|
content.append("```bash")
|
|
content.append(
|
|
"python3 scripts/project_manager.py init my_project --format ppt169")
|
|
content.append("```\n")
|
|
|
|
# Contribution guidelines
|
|
content.append("## [Contribute] Contributing Example Projects\n")
|
|
content.append("We welcome you to share your projects in the examples directory!\n")
|
|
content.append("### Project Requirements\n")
|
|
content.append("1. Follow the standard project structure")
|
|
content.append("2. Include a complete README.md and design specification")
|
|
content.append("3. SVG files must comply with technical specifications")
|
|
content.append("4. Directory naming format: `{project_name}_{format}_{YYYYMMDD}`\n")
|
|
|
|
content.append("### Submission Process\n")
|
|
content.append("1. Create a project under the `examples/` directory")
|
|
content.append(
|
|
"2. Validate the project: `python3 scripts/project_manager.py validate examples/<project>`")
|
|
content.append("3. Update the index: `python3 scripts/generate_examples_index.py`")
|
|
content.append("4. Submit a Pull Request\n")
|
|
|
|
# Related resources
|
|
content.append("## [Resources] Related Resources\n")
|
|
content.append("- [Quick Start](../README.md)")
|
|
content.append("- [Workflow Tutorial](../../AGENTS.md)")
|
|
content.append("- [Canvas Formats](../references/canvas-formats.md)")
|
|
content.append("- [Role Definitions](../references/)")
|
|
content.append("- [Chart Templates](../templates/charts/README.md)\n")
|
|
|
|
# Footer
|
|
content.append("---\n")
|
|
content.append(
|
|
f"*Auto-generated on {datetime.now().strftime('%Y-%m-%d %H:%M:%S')} by PPT Master*")
|
|
|
|
return "\n".join(content)
|
|
|
|
|
|
def main() -> None:
|
|
"""Run the CLI entry point."""
|
|
examples_dir = 'examples'
|
|
|
|
if len(sys.argv) > 1:
|
|
if sys.argv[1] in {'-h', '--help', 'help'}:
|
|
print(__doc__)
|
|
sys.exit(0)
|
|
|
|
examples_dir = sys.argv[1]
|
|
|
|
print("=" * 80)
|
|
print("PPT Master - Examples Index Generator")
|
|
print("=" * 80 + "\n")
|
|
|
|
# Generate index content
|
|
content = generate_examples_index(examples_dir)
|
|
|
|
if not content:
|
|
print("\n[ERROR] Generation failed")
|
|
sys.exit(1)
|
|
|
|
# Write to file
|
|
output_file = Path(examples_dir) / 'README.md'
|
|
|
|
try:
|
|
with open(output_file, 'w', encoding='utf-8') as f:
|
|
f.write(content)
|
|
|
|
print(f"\n[OK] Index file generated: {output_file}")
|
|
print(f" Contains {len(content.splitlines())} lines")
|
|
|
|
# Display statistics
|
|
projects_count = content.count('- **[')
|
|
print(f" Indexed {projects_count} project(s)")
|
|
|
|
except Exception as e:
|
|
print(f"\n[ERROR] Failed to write file: {e}")
|
|
sys.exit(1)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|