226 lines
6.7 KiB
Python
226 lines
6.7 KiB
Python
"""
|
|
Odoo Directory CLI - Main entry point.
|
|
|
|
A Python CLI tool that generates static XML/HTML pages for Odoo partners,
|
|
integrating with the existing odoo-expertos.com static website.
|
|
|
|
Usage:
|
|
python -m directory.cli setup
|
|
python -m directory.cli plan --country DE --cities berlin muenchen
|
|
python -m directory.cli execute --plan <plan-id>
|
|
python -m directory.cli export --country DE
|
|
python -m directory.cli deploy
|
|
"""
|
|
|
|
import logging
|
|
from typing import List, Optional
|
|
|
|
import typer
|
|
from rich.console import Console
|
|
|
|
from .config import get_settings
|
|
from .utils.logger import setup_logging
|
|
from .commands.setup import setup_command, print_schema
|
|
from .commands.plan import plan_command, list_plans, show_plan
|
|
from .commands.execute import execute_command
|
|
from .commands.export import export_command
|
|
from .commands.deploy import deploy_command, status_command
|
|
|
|
# Create CLI app
|
|
app = typer.Typer(
|
|
name="odoo-directory",
|
|
help="Generate static pages for Odoo partner directory.",
|
|
add_completion=False,
|
|
)
|
|
|
|
console = Console()
|
|
|
|
|
|
# ==================== Setup Commands ====================
|
|
|
|
@app.command()
|
|
def setup(
|
|
seed_tags: bool = typer.Option(True, help="Seed default tags"),
|
|
seed_germany: bool = typer.Option(True, help="Seed Germany cities"),
|
|
schema: bool = typer.Option(False, "--schema", help="Print SQL schema only"),
|
|
):
|
|
"""
|
|
Initialize database with schema and seed data.
|
|
|
|
Run this once when setting up a new installation.
|
|
"""
|
|
setup_logging()
|
|
|
|
if schema:
|
|
print_schema()
|
|
return
|
|
|
|
setup_command(seed_tags=seed_tags, seed_germany=seed_germany)
|
|
|
|
|
|
# ==================== Plan Commands ====================
|
|
|
|
@app.command()
|
|
def plan(
|
|
country: str = typer.Option(..., "--country", "-c", help="Country code (e.g., DE)"),
|
|
cities: Optional[List[str]] = typer.Option(None, "--cities", help="City slugs to include"),
|
|
name: Optional[str] = typer.Option(None, "--name", "-n", help="Plan name"),
|
|
):
|
|
"""
|
|
Create an execution plan for a country.
|
|
|
|
Specify which cities to process with --cities or process all cities
|
|
in the country by default.
|
|
"""
|
|
setup_logging()
|
|
plan_command(country=country, cities=cities, name=name)
|
|
|
|
|
|
@app.command("plans")
|
|
def plans_list():
|
|
"""List all execution plans."""
|
|
setup_logging()
|
|
list_plans()
|
|
|
|
|
|
@app.command("plan-show")
|
|
def plan_show(
|
|
plan_id: str = typer.Argument(..., help="Plan UUID"),
|
|
):
|
|
"""Show details of a specific plan."""
|
|
setup_logging()
|
|
show_plan(plan_id)
|
|
|
|
|
|
# ==================== Execute Commands ====================
|
|
|
|
@app.command()
|
|
def execute(
|
|
plan_id: str = typer.Option(..., "--plan", "-p", help="Plan UUID"),
|
|
step: Optional[str] = typer.Option(None, "--step", "-s", help="Specific step: scrape, enrich, content"),
|
|
city: Optional[str] = typer.Option(None, "--city", help="Specific city slug"),
|
|
dry_run: bool = typer.Option(False, "--dry-run", help="Don't make actual API calls"),
|
|
):
|
|
"""
|
|
Execute a plan or specific step.
|
|
|
|
Runs the pipeline: scrape -> enrich -> content generation.
|
|
"""
|
|
setup_logging()
|
|
execute_command(plan_id=plan_id, step=step, city=city, dry_run=dry_run)
|
|
|
|
|
|
# ==================== Export Commands ====================
|
|
|
|
@app.command()
|
|
def export(
|
|
country: str = typer.Option(..., "--country", "-c", help="Country code"),
|
|
city: Optional[str] = typer.Option(None, "--city", help="Specific city slug"),
|
|
output: Optional[str] = typer.Option(None, "--output", "-o", help="Output directory"),
|
|
):
|
|
"""
|
|
Export static files for a country.
|
|
|
|
Generates HTML pages, sitemaps, and tag JSON files.
|
|
"""
|
|
setup_logging()
|
|
export_command(country=country, city=city, output_dir=output)
|
|
|
|
|
|
# ==================== Deploy Commands ====================
|
|
|
|
@app.command()
|
|
def deploy(
|
|
message: Optional[str] = typer.Option(None, "--message", "-m", help="Commit message"),
|
|
no_push: bool = typer.Option(False, "--no-push", help="Don't push to remote"),
|
|
):
|
|
"""
|
|
Deploy changes via Git.
|
|
|
|
Commits exported files and pushes to trigger Vercel deployment.
|
|
"""
|
|
setup_logging()
|
|
deploy_command(message=message, push=not no_push)
|
|
|
|
|
|
@app.command()
|
|
def status():
|
|
"""Show git status of the project."""
|
|
setup_logging()
|
|
status_command()
|
|
|
|
|
|
# ==================== Utility Commands ====================
|
|
|
|
@app.command()
|
|
def info():
|
|
"""Show configuration and environment info."""
|
|
setup_logging()
|
|
|
|
console.print("\n[bold blue]Odoo Directory CLI[/bold blue]\n")
|
|
|
|
try:
|
|
settings = get_settings()
|
|
|
|
console.print("[bold]Configuration:[/bold]")
|
|
console.print(f" Export directory: {settings.export_dir}")
|
|
console.print(f" Images directory: {settings.images_dir}")
|
|
console.print(f" Templates directory: {settings.templates_dir}")
|
|
console.print(f" Log level: {settings.log_level}")
|
|
console.print(f" Batch size: {settings.batch_size}")
|
|
|
|
console.print("\n[bold]API Status:[/bold]")
|
|
console.print(f" Supabase URL: {settings.supabase_url[:30]}...")
|
|
console.print(f" Supabase Key: {'*' * 10}... (configured)")
|
|
console.print(f" Apify Token: {'*' * 10}... (configured)")
|
|
console.print(f" Firecrawl Key: {'*' * 10}... (configured)")
|
|
console.print(f" Anthropic Key: {'*' * 10}... (configured)")
|
|
|
|
except Exception as e:
|
|
console.print(f"\n[red]Configuration error: {e}[/red]")
|
|
console.print("\nMake sure you have a .env file with all required variables.")
|
|
console.print("Copy .env.example to .env and fill in your API keys.")
|
|
|
|
|
|
@app.command()
|
|
def test_connection():
|
|
"""Test connections to all external services."""
|
|
setup_logging()
|
|
|
|
console.print("\n[bold blue]Testing Connections[/bold blue]\n")
|
|
|
|
# Test Supabase
|
|
console.print("Testing Supabase...")
|
|
try:
|
|
from .services.supabase import SupabaseService
|
|
db = SupabaseService()
|
|
regions = db.list_regions()
|
|
console.print(f" [green]Connected! Found {len(regions)} regions.[/green]")
|
|
except Exception as e:
|
|
console.print(f" [red]Failed: {e}[/red]")
|
|
|
|
# Test Anthropic
|
|
console.print("Testing Anthropic...")
|
|
try:
|
|
from anthropic import Anthropic
|
|
settings = get_settings()
|
|
client = Anthropic(api_key=settings.anthropic_api_key)
|
|
# Just verify the key format
|
|
console.print(" [green]API key configured.[/green]")
|
|
except Exception as e:
|
|
console.print(f" [red]Failed: {e}[/red]")
|
|
|
|
# Note about other services
|
|
console.print("\nNote: Apify and Firecrawl are tested during actual execution.")
|
|
|
|
|
|
# ==================== Main Entry ====================
|
|
|
|
def main():
|
|
"""Main entry point for the CLI."""
|
|
app()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|