mirror of
https://github.com/gbessoni/seobuild-onpage.git
synced 2026-06-23 11:58:37 +02:00
seo-agi: The GEO framework skill for Claude Code + OpenClaw
GEO framework that writes pages ranking on Google AND getting cited by LLMs. 500-token chunk architecture, Reddit Test quality gates, verification tags, Not For You blocks, information gain enforcement. Data layer: DataForSEO, GSC, Ahrefs MCP, SEMRush MCP. 21 files, all tests passing. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,160 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
SEO-AGI setup script.
|
||||
Creates config directory, prompts for API keys, installs dependencies.
|
||||
|
||||
Usage:
|
||||
python3 setup.py
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import json
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
|
||||
CONFIG_DIR = Path.home() / ".config" / "seo-agi"
|
||||
ENV_FILE = CONFIG_DIR / ".env"
|
||||
CONFIG_FILE = CONFIG_DIR / "config.json"
|
||||
OUTPUT_DIR = Path.home() / "Documents" / "SEO-AGI"
|
||||
|
||||
|
||||
def main():
|
||||
print("=" * 50)
|
||||
print(" SEO-AGI Setup")
|
||||
print("=" * 50)
|
||||
print()
|
||||
|
||||
# Create directories
|
||||
CONFIG_DIR.mkdir(parents=True, exist_ok=True)
|
||||
for subdir in ["research", "briefs", "pages", "rewrites"]:
|
||||
(OUTPUT_DIR / subdir).mkdir(parents=True, exist_ok=True)
|
||||
|
||||
data_dir = Path.home() / ".local" / "share" / "seo-agi"
|
||||
for subdir in ["research", "cache"]:
|
||||
(data_dir / subdir).mkdir(parents=True, exist_ok=True)
|
||||
|
||||
print("[OK] Directories created")
|
||||
|
||||
# Install Python dependencies
|
||||
print("\nInstalling dependencies...")
|
||||
deps = ["requests"]
|
||||
try:
|
||||
subprocess.check_call(
|
||||
[sys.executable, "-m", "pip", "install", "--quiet"]
|
||||
+ deps
|
||||
+ ["--break-system-packages"],
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL,
|
||||
)
|
||||
print("[OK] Core dependencies installed (requests)")
|
||||
except subprocess.CalledProcessError:
|
||||
try:
|
||||
subprocess.check_call(
|
||||
[sys.executable, "-m", "pip", "install", "--quiet"] + deps,
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL,
|
||||
)
|
||||
print("[OK] Core dependencies installed (requests)")
|
||||
except subprocess.CalledProcessError:
|
||||
print("[WARN] Could not install requests. Install manually:")
|
||||
print(" pip install requests")
|
||||
|
||||
# API Keys
|
||||
print("\n--- API Keys ---")
|
||||
print("DataForSEO is REQUIRED. Get credentials at:")
|
||||
print(" https://app.dataforseo.com/api-dashboard\n")
|
||||
|
||||
existing_env = {}
|
||||
if ENV_FILE.exists():
|
||||
with open(ENV_FILE) as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if line and not line.startswith("#") and "=" in line:
|
||||
k, _, v = line.partition("=")
|
||||
existing_env[k.strip()] = v.strip()
|
||||
|
||||
# DataForSEO
|
||||
dfs_login = existing_env.get("DATAFORSEO_LOGIN", "")
|
||||
dfs_pass = existing_env.get("DATAFORSEO_PASSWORD", "")
|
||||
|
||||
if dfs_login:
|
||||
print(f"DataForSEO login found: {dfs_login[:4]}***")
|
||||
change = input("Update DataForSEO credentials? [y/N]: ").strip().lower()
|
||||
if change == "y":
|
||||
dfs_login = input("DataForSEO login (email): ").strip()
|
||||
dfs_pass = input("DataForSEO password: ").strip()
|
||||
else:
|
||||
dfs_login = input("DataForSEO login (email): ").strip()
|
||||
dfs_pass = input("DataForSEO password: ").strip()
|
||||
|
||||
# GSC (optional)
|
||||
print("\nGoogle Search Console (OPTIONAL - press Enter to skip)")
|
||||
gsc_path = existing_env.get("GSC_SERVICE_ACCOUNT_PATH", "")
|
||||
if gsc_path:
|
||||
print(f"GSC service account found: {gsc_path}")
|
||||
change = input("Update? [y/N]: ").strip().lower()
|
||||
if change == "y":
|
||||
gsc_path = input("Path to service account JSON: ").strip()
|
||||
else:
|
||||
gsc_path = input("Path to GSC service account JSON (or Enter to skip): ").strip()
|
||||
|
||||
# Write .env
|
||||
env_lines = [
|
||||
"# SEO-AGI Configuration",
|
||||
f"# Generated by setup.py on {__import__('datetime').datetime.now().isoformat()[:10]}",
|
||||
"",
|
||||
"# DataForSEO",
|
||||
f"DATAFORSEO_LOGIN={dfs_login}",
|
||||
f"DATAFORSEO_PASSWORD={dfs_pass}",
|
||||
"",
|
||||
"# Google Search Console",
|
||||
f"GSC_SERVICE_ACCOUNT_PATH={gsc_path}",
|
||||
"",
|
||||
"# Future integrations",
|
||||
f"AHREFS_API_KEY={existing_env.get('AHREFS_API_KEY', '')}",
|
||||
f"SEMRUSH_API_KEY={existing_env.get('SEMRUSH_API_KEY', '')}",
|
||||
"",
|
||||
"# Defaults",
|
||||
f"DEFAULT_LOCATION={existing_env.get('DEFAULT_LOCATION', '2840')}",
|
||||
f"DEFAULT_LANGUAGE={existing_env.get('DEFAULT_LANGUAGE', 'en')}",
|
||||
]
|
||||
|
||||
with open(ENV_FILE, "w") as f:
|
||||
f.write("\n".join(env_lines) + "\n")
|
||||
|
||||
print(f"\n[OK] Credentials saved to {ENV_FILE}")
|
||||
|
||||
# Write default config.json if not exists
|
||||
if not CONFIG_FILE.exists():
|
||||
default_config = {
|
||||
"default_location": 2840,
|
||||
"default_language": "en",
|
||||
"default_site": "",
|
||||
"serp_depth": 10,
|
||||
"save_research": True,
|
||||
"output_dir": str(OUTPUT_DIR),
|
||||
}
|
||||
with open(CONFIG_FILE, "w") as f:
|
||||
json.dump(default_config, f, indent=2)
|
||||
print(f"[OK] Config saved to {CONFIG_FILE}")
|
||||
|
||||
# Verify
|
||||
print("\n--- Setup Summary ---")
|
||||
print(f" DataForSEO: {'configured' if dfs_login else 'NOT SET'}")
|
||||
print(f" GSC: {'configured' if gsc_path else 'not configured (optional)'}")
|
||||
print(f" Output dir: {OUTPUT_DIR}")
|
||||
print(f" Config dir: {CONFIG_DIR}")
|
||||
|
||||
if dfs_login:
|
||||
print("\n[READY] Run a test:")
|
||||
print(f" python3 {Path(__file__).parent}/research.py \"test keyword\"")
|
||||
else:
|
||||
print("\n[WARN] DataForSEO credentials missing. The skill will fall")
|
||||
print(" back to Claude's web search for basic research.")
|
||||
|
||||
print()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user