""" 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() 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") @cli.command() @click.option('--host', '-h', default='0.0.0.0', help='FTP server host') @click.option('--port', '-p', default=21, type=int, help='FTP server port') def ftp(host: str, port: int): """Start FTP server""" config = Config() config.ftp.host = host config.ftp.port = port ftp_manager = FTPServerManager(config.ftp) # Add current directory as allowed directory current_dir = os.path.abspath('.') ftp_manager.add_allowed_directory(current_dir) try: ftp_manager.start_server() 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_server() 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()