- Add CLI with server, db, worker, scan, setup commands - Add interactive setup wizard for first-run configuration - Add FastAPI application with lifespan management - Update requirements.txt with all dependencies
223 lines
5.6 KiB
Python
Executable File
223 lines
5.6 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""CLI entry point for TranscriptorIO backend."""
|
|
import argparse
|
|
import logging
|
|
import sys
|
|
import os
|
|
|
|
# Add parent directory to path to allow imports
|
|
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
|
|
|
|
import uvicorn
|
|
|
|
|
|
def main():
|
|
"""Main CLI entry point."""
|
|
|
|
parser = argparse.ArgumentParser(
|
|
description="TranscriptorIO - AI-powered subtitle transcription service"
|
|
)
|
|
|
|
# Subcommands
|
|
subparsers = parser.add_subparsers(dest="command", help="Command to run")
|
|
|
|
# Server command
|
|
server_parser = subparsers.add_parser("server", help="Run FastAPI server")
|
|
server_parser.add_argument(
|
|
"--host",
|
|
default="0.0.0.0",
|
|
help="Host to bind to (default: 0.0.0.0)"
|
|
)
|
|
server_parser.add_argument(
|
|
"--port",
|
|
type=int,
|
|
default=8000,
|
|
help="Port to bind to (default: 8000)"
|
|
)
|
|
server_parser.add_argument(
|
|
"--reload",
|
|
action="store_true",
|
|
help="Enable auto-reload for development"
|
|
)
|
|
server_parser.add_argument(
|
|
"--workers",
|
|
type=int,
|
|
default=1,
|
|
help="Number of worker processes (default: 1)"
|
|
)
|
|
server_parser.add_argument(
|
|
"--log-level",
|
|
choices=["debug", "info", "warning", "error", "critical"],
|
|
default="info",
|
|
help="Log level (default: info)"
|
|
)
|
|
|
|
# Database command
|
|
db_parser = subparsers.add_parser("db", help="Database operations")
|
|
db_parser.add_argument(
|
|
"action",
|
|
choices=["init", "migrate", "reset", "backup"],
|
|
help="Database action"
|
|
)
|
|
|
|
# Worker command
|
|
worker_parser = subparsers.add_parser("worker", help="Start standalone worker")
|
|
worker_parser.add_argument(
|
|
"--type",
|
|
choices=["cpu", "gpu"],
|
|
default="cpu",
|
|
help="Worker type (default: cpu)"
|
|
)
|
|
worker_parser.add_argument(
|
|
"--device-id",
|
|
type=int,
|
|
default=0,
|
|
help="GPU device ID (default: 0)"
|
|
)
|
|
|
|
# Scanner command
|
|
scan_parser = subparsers.add_parser("scan", help="Run library scan")
|
|
scan_parser.add_argument(
|
|
"paths",
|
|
nargs="+",
|
|
help="Paths to scan"
|
|
)
|
|
scan_parser.add_argument(
|
|
"--no-recursive",
|
|
action="store_true",
|
|
help="Don't scan subdirectories"
|
|
)
|
|
|
|
# Setup command
|
|
subparsers.add_parser("setup", help="Run setup wizard")
|
|
|
|
# Parse arguments
|
|
args = parser.parse_args()
|
|
|
|
if not args.command:
|
|
parser.print_help()
|
|
sys.exit(1)
|
|
|
|
# Execute command
|
|
if args.command == "server":
|
|
run_server(args)
|
|
elif args.command == "db":
|
|
run_db_command(args)
|
|
elif args.command == "worker":
|
|
run_worker(args)
|
|
elif args.command == "scan":
|
|
run_scan(args)
|
|
elif args.command == "setup":
|
|
run_setup()
|
|
|
|
|
|
def run_server(args):
|
|
"""Run FastAPI server."""
|
|
print(f"🚀 Starting TranscriptorIO server on {args.host}:{args.port}")
|
|
print(f"📖 API docs available at: http://{args.host}:{args.port}/docs")
|
|
|
|
uvicorn.run(
|
|
"backend.app:app",
|
|
host=args.host,
|
|
port=args.port,
|
|
reload=args.reload,
|
|
workers=args.workers if not args.reload else 1,
|
|
log_level=args.log_level,
|
|
)
|
|
|
|
|
|
def run_db_command(args):
|
|
"""Run database command."""
|
|
from backend.core.database import database
|
|
|
|
if args.action == "init":
|
|
print("Initializing database...")
|
|
database.init_db()
|
|
print("✅ Database initialized")
|
|
|
|
elif args.action == "reset":
|
|
print("⚠️ WARNING: This will delete all data!")
|
|
confirm = input("Type 'yes' to confirm: ")
|
|
|
|
if confirm.lower() == "yes":
|
|
print("Resetting database...")
|
|
database.reset_db()
|
|
print("✅ Database reset")
|
|
else:
|
|
print("❌ Cancelled")
|
|
|
|
elif args.action == "migrate":
|
|
print("❌ Migrations not yet implemented")
|
|
sys.exit(1)
|
|
|
|
elif args.action == "backup":
|
|
print("❌ Backup not yet implemented")
|
|
sys.exit(1)
|
|
|
|
|
|
def run_worker(args):
|
|
"""Run standalone worker."""
|
|
from backend.core.worker import Worker, WorkerType
|
|
import signal
|
|
|
|
worker_type = WorkerType.CPU if args.type == "cpu" else WorkerType.GPU
|
|
device_id = args.device_id if worker_type == WorkerType.GPU else None
|
|
|
|
worker_id = f"standalone-{args.type}"
|
|
if device_id is not None:
|
|
worker_id += f"-{device_id}"
|
|
|
|
print(f"🔧 Starting standalone worker: {worker_id}")
|
|
|
|
worker = Worker(worker_id, worker_type, device_id)
|
|
|
|
# Handle shutdown
|
|
def signal_handler(sig, frame):
|
|
print("\n⏹️ Stopping worker...")
|
|
worker.stop()
|
|
sys.exit(0)
|
|
|
|
signal.signal(signal.SIGINT, signal_handler)
|
|
signal.signal(signal.SIGTERM, signal_handler)
|
|
|
|
worker.start()
|
|
|
|
# Keep alive
|
|
try:
|
|
while True:
|
|
import time
|
|
time.sleep(1)
|
|
except KeyboardInterrupt:
|
|
worker.stop()
|
|
|
|
|
|
def run_scan(args):
|
|
"""Run library scan."""
|
|
from backend.scanning.library_scanner import library_scanner
|
|
|
|
print(f"🔍 Scanning {len(args.paths)} path(s)...")
|
|
|
|
result = library_scanner.scan_paths(
|
|
paths=args.paths,
|
|
recursive=not args.no_recursive
|
|
)
|
|
|
|
print(f"\n✅ Scan complete:")
|
|
print(f" 📁 Files scanned: {result['scanned_files']}")
|
|
print(f" ✅ Matched: {result['matched_files']}")
|
|
print(f" 📋 Jobs created: {result['jobs_created']}")
|
|
print(f" ⏭️ Skipped: {result['skipped_files']}")
|
|
|
|
|
|
def run_setup():
|
|
"""Run setup wizard."""
|
|
from backend.setup_wizard import SetupWizard
|
|
|
|
wizard = SetupWizard()
|
|
wizard.run()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|
|
|