Files
seo/scripts/seo-cli.py
Kevin Bataille 8c7cd24685 Refactor SEO automation into unified CLI application
Major refactoring to create a clean, integrated CLI application:

### New Features:
- Unified CLI executable (./seo) with simple command structure
- All commands accept optional CSV file arguments
- Auto-detection of latest files when no arguments provided
- Simplified output directory structure (output/ instead of output/reports/)
- Cleaner export filename format (all_posts_YYYY-MM-DD.csv)

### Commands:
- export: Export all posts from WordPress sites
- analyze [csv]: Analyze posts with AI (optional CSV input)
- recategorize [csv]: Recategorize posts with AI
- seo_check: Check SEO quality
- categories: Manage categories across sites
- approve [files]: Review and approve recommendations
- full_pipeline: Run complete workflow
- analytics, gaps, opportunities, report, status

### Changes:
- Moved all scripts to scripts/ directory
- Created config.yaml for configuration
- Updated all scripts to use output/ directory
- Deprecated old seo-cli.py in favor of new ./seo
- Added AGENTS.md and CHANGELOG.md documentation
- Consolidated README.md with updated usage

### Technical:
- Added PyYAML dependency
- Removed hardcoded configuration values
- All scripts now properly integrated
- Better error handling and user feedback

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-02-16 14:24:44 +01:00

389 lines
14 KiB
Python
Executable File

#!/usr/bin/env python3
"""
DEPRECATED: SEO Automation CLI
This script is deprecated. Please use the new unified CLI:
- ./seo export
- ./seo analyze
- ./seo seo_check
- ./seo categories
- ./seo full_pipeline
To see all commands: ./seo help
"""
import sys
import subprocess
import argparse
from pathlib import Path
from config import Config
import os
class SEOCLI:
"""DEPRECATED: Main CLI orchestrator for SEO workflows. Use new ./seo CLI instead."""
def __init__(self):
"""Initialize CLI."""
print("⚠️ DEPRECATION WARNING: This CLI is deprecated. Use ./seo instead.")
print(" Run './seo help' to see new commands.")
self.scripts_dir = Path(__file__).parent
self.project_dir = self.scripts_dir.parent
self.output_dir = self.project_dir / 'output' / 'reports'
def run_command(self, command, description):
"""Run a command and show progress."""
print(f"\n{'='*70}")
print(f"{description}")
print(f"{'='*70}\n")
try:
result = subprocess.run(command, shell=True, cwd=self.project_dir)
if result.returncode != 0:
print(f"\n❌ Error running: {description}")
return False
print(f"\n{description} completed successfully")
return True
except Exception as e:
print(f"\n❌ Error: {e}")
return False
def get_latest_file(self, pattern):
"""Get most recent file matching pattern."""
import glob
# Support both old and new naming patterns
files = glob.glob(str(self.output_dir / pattern))
if not files:
# Try new pattern
files = glob.glob(str(self.output_dir / "all_posts_*.csv"))
if not files:
return None
return max(files, key=os.path.getctime)
def export_posts(self):
"""Export all posts to CSV."""
cmd = f"python {self.scripts_dir}/export_posts_for_ai_decision.py"
return self.run_command(cmd, "STEP 1: Export All Posts")
def analyze_with_ai(self, csv_file=None):
"""Analyze exported posts with AI."""
if not csv_file:
csv_file = self.get_latest_file("all_posts_for_ai_decision_*.csv")
if not csv_file:
print("\n❌ No exported CSV found. Run 'seo-cli export' first.")
return False
cmd = f"python {self.scripts_dir}/ai_analyze_posts_for_decisions.py \"{csv_file}\""
return self.run_command(cmd, "STEP 2: Analyze with AI")
def recategorize_with_ai(self, csv_file=None):
"""Recategorize posts using AI."""
if not csv_file:
csv_file = self.get_latest_file("all_posts_for_ai_decision_*.csv")
if not csv_file:
print("\n❌ No exported CSV found. Run 'seo-cli export' first.")
return False
cmd = f"python {self.scripts_dir}/ai_recategorize_posts.py \"{csv_file}\""
return self.run_command(cmd, "Recategorizing Posts with AI")
def seo_check(self, top_n=None):
"""Check SEO quality of titles and meta descriptions."""
cmd = f"python {self.scripts_dir}/multi_site_seo_analyzer.py"
if top_n:
cmd += f" --top-n {top_n}"
return self.run_command(cmd, f"SEO Quality Check (Top {top_n or 'All'} posts)")
def import_analytics(self, ga_export, gsc_export, posts_csv=None):
"""Import analytics data."""
if not posts_csv:
posts_csv = self.get_latest_file("all_posts_for_ai_decision_*.csv")
if not posts_csv:
print("\n❌ No posts CSV found. Run 'seo-cli export' first.")
return False
cmd = (
f"python {self.scripts_dir}/analytics_importer.py "
f"--ga-export \"{ga_export}\" "
f"--gsc-export \"{gsc_export}\" "
f"--posts-csv \"{posts_csv}\" "
f"--output output/posts_with_analytics.csv"
)
return self.run_command(cmd, "STEP: Import Analytics Data")
def full_pipeline(self, analyze=True, seo=True):
"""Run complete pipeline: export → analyze → seo check."""
steps = [
("Export", self.export_posts),
]
if analyze:
steps.append(("Analyze", self.analyze_with_ai))
if seo:
steps.append(("SEO Check", self.seo_check))
print("\n" + "="*70)
print("🚀 STARTING FULL PIPELINE")
print("="*70)
print(f"\nSteps to run: {', '.join([s[0] for s in steps])}\n")
completed = 0
for name, func in steps:
if func():
completed += 1
else:
print(f"\n⚠️ Pipeline stopped at: {name}")
return False
print("\n" + "="*70)
print(f"✓ PIPELINE COMPLETE - All {completed} steps succeeded!")
print("="*70)
print("\nNext steps:")
print("1. Review results in output/reports/")
print("2. Check: posts_with_ai_recommendations_*.csv")
print("3. Follow AI recommendations to optimize your content")
return True
def manage_categories(self):
"""Run category management with AI recommendations."""
cmd = f"python {self.scripts_dir}/category_manager.py"
return self.run_command(cmd, "Category Management with AI Recommendations")
def approve_recommendations(self, csv_files=None):
"""Approve recommendations from CSV files."""
if not csv_files:
print("\n❌ No CSV files provided for approval.")
return False
# Join the CSV files into a single command argument
csv_files_str = " ".join(f'"{csv_file}"' for csv_file in csv_files)
cmd = f"python {self.scripts_dir}/user_approval.py {csv_files_str}"
return self.run_command(cmd, f"Approving Recommendations from {len(csv_files)} files")
def show_status(self):
"""Show status of output files."""
print("\n" + "="*70)
print("📊 OUTPUT FILES STATUS")
print("="*70 + "\n")
import glob
files = glob.glob(str(self.output_dir / "*"))
if not files:
print("No output files yet. Run 'seo-cli export' to get started.\n")
return
# Sort by date
files.sort(key=os.path.getctime, reverse=True)
for file in files[:10]: # Show last 10 files
size = os.path.getsize(file) / 1024 # KB
mtime = os.path.getmtime(file)
from datetime import datetime
date = datetime.fromtimestamp(mtime).strftime('%Y-%m-%d %H:%M:%S')
filename = os.path.basename(file)
print(f" {filename}")
print(f" Size: {size:.1f} KB | Modified: {date}")
print()
def list_workflows(self):
"""List available workflows."""
workflows = {
'export': {
'description': 'Export all posts from your 3 WordPress sites',
'command': 'seo-cli export',
'time': '5-10 min',
'cost': 'Free'
},
'analyze': {
'description': 'Analyze exported posts with Claude AI',
'command': 'seo-cli analyze',
'time': '5-15 min',
'cost': '$1.50-2.00'
},
'recategorize': {
'description': 'Re-categorize posts for better organization',
'command': 'seo-cli recategorize',
'time': '5-15 min',
'cost': '$1.50-2.00'
},
'seo-check': {
'description': 'Check SEO quality of titles and descriptions',
'command': 'seo-cli seo-check [--top-n 50]',
'time': '3-5 min',
'cost': 'Free or $0.20-0.50'
},
'analytics': {
'description': 'Combine Google Analytics & Search Console data',
'command': 'seo-cli analytics GA4.csv GSC.csv',
'time': '5 min',
'cost': 'Free'
},
'full-pipeline': {
'description': 'Run complete pipeline: export → analyze → seo-check',
'command': 'seo-cli full-pipeline',
'time': '15-30 min',
'cost': '$1.50-2.50'
},
'categories': {
'description': 'Manage categories across all sites with AI recommendations',
'command': 'seo-cli categories',
'time': '10-20 min',
'cost': '$0.50-1.00'
},
'approve': {
'description': 'Review and approve SEO recommendations',
'command': 'seo-cli approve [csv_file1] [csv_file2]',
'time': 'Variable',
'cost': 'Free'
}
}
print("\n" + "="*70)
print("📋 AVAILABLE WORKFLOWS")
print("="*70 + "\n")
for name, info in workflows.items():
print(f"🔹 {name.upper()}")
print(f" {info['description']}")
print(f" Command: {info['command']}")
print(f" Time: {info['time']} | Cost: {info['cost']}")
print()
def show_help(self):
"""Show help message."""
print("\n" + "="*70)
print("🚀 SEO AUTOMATION CLI - Workflow Orchestrator")
print("="*70 + "\n")
print("QUICK START:")
print(" seo-cli full-pipeline Run complete workflow")
print(" seo-cli export Export all posts")
print(" seo-cli analyze Analyze with AI")
print(" seo-cli recategorize Re-categorize posts with AI")
print(" seo-cli seo-check Check SEO quality")
print()
print("CHAINING WORKFLOWS:")
print(" seo-cli export && seo-cli analyze && seo-cli seo-check")
print()
print("ADVANCED:")
print(" seo-cli seo-check --top-n 50 Check top 50 posts")
print(" seo-cli analytics GA4.csv GSC.csv Import analytics data")
print(" seo-cli status Show output files")
print(" seo-cli list List all workflows")
print()
print("Learn more:")
print(" Read: WORKFLOWS.md (complete guide)")
print(" Read: scripts/*/README.md (workflow details)")
print()
def main():
"""Main entry point."""
cli = SEOCLI()
parser = argparse.ArgumentParser(
description='SEO Automation CLI - Chain workflows together',
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
Examples:
seo-cli export # Export posts
seo-cli full-pipeline # Export + Analyze + SEO check
seo-cli export && seo-cli analyze # Chain commands
seo-cli seo-check --top-n 50 # Check top 50 posts
seo-cli analytics ga4.csv gsc.csv # Import analytics
seo-cli status # Show output files
"""
)
subparsers = parser.add_subparsers(dest='command', help='Workflow to run')
# Export workflow
subparsers.add_parser('export', help='Export all posts from WordPress sites')
# Analyze workflow
subparsers.add_parser('analyze', help='Analyze exported posts with Claude AI')
# Recategorize workflow
subparsers.add_parser('recategorize', help='Re-categorize posts with Claude AI')
# SEO check workflow
seo_parser = subparsers.add_parser('seo-check', help='Check SEO quality of titles/descriptions')
seo_parser.add_argument('--top-n', type=int, help='Analyze top N posts with AI (costs money)')
# Analytics workflow
analytics_parser = subparsers.add_parser('analytics', help='Import Google Analytics & Search Console')
analytics_parser.add_argument('ga_export', help='Path to GA4 export CSV')
analytics_parser.add_argument('gsc_export', help='Path to Search Console export CSV')
# Full pipeline
full_parser = subparsers.add_parser('full-pipeline', help='Complete pipeline: export → analyze → seo-check')
full_parser.add_argument('--no-analyze', action='store_true', help='Skip AI analysis')
full_parser.add_argument('--no-seo', action='store_true', help='Skip SEO check')
# Category management
subparsers.add_parser('categories', help='Manage categories with AI recommendations')
# Approval system
approval_parser = subparsers.add_parser('approve', help='Approve recommendations from CSV files')
approval_parser.add_argument('csv_files', nargs='*', help='CSV files containing recommendations to approve')
# Utilities
subparsers.add_parser('status', help='Show status of output files')
subparsers.add_parser('list', help='List all available workflows')
subparsers.add_parser('help', help='Show this help message')
args = parser.parse_args()
# If no command, show help
if not args.command:
cli.show_help()
return 0
# Route to appropriate command
if args.command == 'export':
success = cli.export_posts()
elif args.command == 'analyze':
success = cli.analyze_with_ai()
elif args.command == 'recategorize':
success = cli.recategorize_with_ai()
elif args.command == 'seo-check':
success = cli.seo_check(top_n=args.top_n)
elif args.command == 'analytics':
success = cli.import_analytics(args.ga_export, args.gsc_export)
elif args.command == 'full-pipeline':
success = cli.full_pipeline(
analyze=not args.no_analyze,
seo=not args.no_seo
)
elif args.command == 'categories':
success = cli.manage_categories()
elif args.command == 'approve':
success = cli.approve_recommendations(args.csv_files)
elif args.command == 'status':
cli.show_status()
success = True
elif args.command == 'list':
cli.list_workflows()
success = True
elif args.command == 'help':
cli.show_help()
success = True
else:
cli.show_help()
success = False
return 0 if success else 1
if __name__ == '__main__':
sys.exit(main())