mirror of
https://github.com/gbessoni/seobuild-onpage.git
synced 2026-06-23 11:58:37 +02:00
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>
161 lines
5.3 KiB
Python
161 lines
5.3 KiB
Python
#!/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()
|