""" CLI interface for FactsDB service Provides command line interface for onboarding directories """ import os import click from typing import Optional from .config import Config from .database import DatabaseManager from .file_processor import FileProcessor from .ai_processor import AIProcessor from .scheduler import FactExtractionScheduler, get_scheduler from .ftp_server import FTPServerManager @click.group() def cli(): """FactsDB - Service for extracting and storing facts from documents""" pass @cli.command() @click.option('--directory', '-d', required=True, help='Directory to onboard') @click.option('--table-name', '-t', required=True, help='Name of table to store facts') @click.option('--prompt', '-p', help='Custom prompt for AI extraction') @click.option('--model', '-m', default='gpt-oss', help='AI model to use (default: gpt-oss)') @click.option('--db-type', '-db', default='sqlite', help='Database type (default: sqlite)') def onboard(directory: str, table_name: str, prompt: Optional[str], model: str, db_type: str): """Onboard a directory for fact extraction""" click.echo(f"Onboarding directory: {directory}") click.echo(f"Table name: {table_name}") click.echo(f"AI model: {model}") # Validate directory exists if not os.path.exists(directory): click.echo(f"Error: Directory {directory} does not exist") return # Create configuration config = Config() # Setup components db_manager = DatabaseManager(config.database) file_processor = FileProcessor() ai_processor = AIProcessor(config.ai_endpoint) scheduler = get_scheduler(config) # Add job to scheduler scheduler.add_job(directory, table_name, prompt or "", model) click.echo(f"Successfully onboarded directory {directory} for fact extraction") click.echo(f"Job scheduled to run every 10 minutes") @cli.command() def status(): """Show current status and scheduled jobs""" config = Config() try: scheduler = get_scheduler(config) click.echo("FactsDB Service Status") click.echo("=" * 30) jobs = scheduler.get_jobs() if jobs: click.echo("Scheduled Jobs:") for i, job in enumerate(jobs, 1): click.echo(f" {i}. Directory: {job['directory_path']}") click.echo(f" Table: {job['table_name']}") click.echo(f" Model: {job['model']}") click.echo(f" Interval: {job['interval_minutes']} minutes") click.echo() else: click.echo("No scheduled jobs") except Exception as e: click.echo(f"Error getting scheduler status: {str(e)}") click.echo("Scheduler may not be initialized due to database configuration issues.") @cli.command() @click.option('--host', '-h', default='0.0.0.0', help='FTP server host') @click.option('--port', '-p', default=2122, type=int, help='FTP server port') def ftp(host: str, port: int): """Start FTP server""" config = Config() # Fix: Use the correct config structure - ftp_server instead of ftp config.ftp_server.host = host config.ftp_server.port = port # Fix: Pass the correct config object to FTPServerManager ftp_manager = FTPServerManager(config) # Add current directory as allowed directory current_dir = os.path.abspath('.') ftp_manager.add_onboarded_directory(current_dir) try: ftp_manager.start() click.echo(f"FTP Server started on {host}:{port}") click.echo("Press Ctrl+C to stop") # Keep running try: while True: import time time.sleep(1) except KeyboardInterrupt: ftp_manager.stop() click.echo("FTP Server stopped") except Exception as e: click.echo(f"Error starting FTP server: {str(e)}") @cli.command() def tables(): """Show all available tables and record counts""" config = Config() db_manager = DatabaseManager(config.database) tables = db_manager.get_all_tables() if not tables: click.echo("No tables found") return click.echo("Available Tables:") click.echo("=" * 40) for table in tables: click.echo(f"{table['table_name']}: {table['count']} records") if __name__ == '__main__': cli()