Files
Orchestrator/privat/NoteGraph/ingestion/cli.py
T
ankn a5f8fb49ab Migrate all repos into monorepo context folders
Bahn: aisupport, Analyse-O2C-C2S, awesome-bahn-mcp-servers, beam-mcp,
      Confluence_Bot, db-planet-mcp-server, O2C-Harness, project-audit,
      Projekt-KIQ-HP, teamlandkarte-mcp
Dhive: Jury-Voting
Privat: CV, NoteGraph (NOTE: NoteGraph needs complete redo after consolidation)
Shared: AI-Orchestrator, OrgMyLife, power_skills_and_more
Shared/references: symphony (read-only)

Bahn repos remain available as independent remotes - this monorepo
pulls them in via subtree, the originals are untouched.
2026-06-30 20:39:52 +02:00

170 lines
4.9 KiB
Python

"""Click-based CLI for the NoteGraph ingestion pipeline.
Subcommands:
import - Import files or directories into NoteGraph
watch - Start drop-folder watcher for continuous ingestion
sync - One-shot Nextcloud inbox sync
upload - Start web upload server
"""
import logging
import sys
from pathlib import Path
import click
from ingestion.config import IngestionConfig
def _setup_logging(verbose: bool) -> None:
"""Configure logging based on verbosity."""
level = logging.DEBUG if verbose else logging.INFO
logging.basicConfig(
level=level,
format="%(asctime)s [%(levelname)s] %(name)s: %(message)s",
datefmt="%H:%M:%S",
)
@click.group()
@click.version_option(version="0.1.0", prog_name="notegraph-ingest")
def cli():
"""NoteGraph Ingestion — import documents into your knowledge base."""
pass
@cli.command("import")
@click.argument("path", type=click.Path(exists=True))
@click.option("--output-dir", "-o", type=click.Path(), default=None, help="Override output directory")
@click.option("--create-tasks", is_flag=True, help="Create OrgMyLife tasks for action items")
@click.option("--provider", type=str, default=None, help="Override LLM provider (openai, anthropic, etc.)")
@click.option("--dry-run", is_flag=True, help="Show what would be created without writing files")
@click.option("--no-commit", is_flag=True, help="Skip git auto-commit")
@click.option("--verbose", "-v", is_flag=True, help="Enable debug logging")
def import_cmd(path, output_dir, create_tasks, provider, dry_run, no_commit, verbose):
"""Import files or directories into NoteGraph.
PATH can be a single file or a directory to scan recursively.
"""
_setup_logging(verbose)
config = IngestionConfig()
if provider:
config.llm_provider = provider
config.validate_api_key()
from ingestion.discovery import discover_files
from ingestion.pipeline import process_batch
source_path = Path(path)
files = discover_files(source_path)
if not files:
click.echo("No supported files found.")
sys.exit(0)
click.echo(f"Found {len(files)} file(s) to process.")
if dry_run:
click.echo("[DRY RUN] No files will be written.\n")
def progress(current, total, filename):
click.echo(f" [{current}/{total}] {filename}")
result = process_batch(
paths=files,
config=config,
dry_run=dry_run,
no_commit=no_commit,
create_tasks=create_tasks,
output_dir=Path(output_dir) if output_dir else None,
progress_callback=progress,
)
# Summary
click.echo("")
click.echo(f"Done! Processed {result.total} file(s):")
click.echo(f" ✓ Success: {result.success}")
if result.failed:
click.echo(f" ✗ Failed: {result.failed}")
@cli.command("watch")
@click.option("--verbose", "-v", is_flag=True, help="Enable debug logging")
def watch_cmd(verbose):
"""Start drop-folder watcher for continuous ingestion."""
_setup_logging(verbose)
from ingestion.watcher import start_watcher
config = IngestionConfig()
config.validate_api_key()
click.echo(f"Watching inbox: {config.inbox_dir}")
click.echo("Press Ctrl+C to stop.\n")
try:
start_watcher(config)
except KeyboardInterrupt:
click.echo("\nWatcher stopped.")
@cli.command("sync")
@click.option("--verbose", "-v", is_flag=True, help="Enable debug logging")
def sync_cmd(verbose):
"""One-shot Nextcloud inbox sync."""
_setup_logging(verbose)
from ingestion.integrations.nextcloud import NextcloudInboxSync
config = IngestionConfig()
if not config.nextcloud_inbox_url:
click.echo("ERROR: NEXTCLOUD_INBOX_URL not configured.")
sys.exit(1)
config.validate_api_key()
sync = NextcloudInboxSync(config)
downloaded = sync.poll()
if not downloaded:
click.echo("No new files in Nextcloud inbox.")
return
click.echo(f"Downloaded {len(downloaded)} file(s) from Nextcloud.")
# Process downloaded files
from ingestion.pipeline import process_batch
result = process_batch(
paths=downloaded,
config=config,
)
# Mark processed files on Nextcloud
for r in result.results:
if r.success:
sync.mark_processed(r.source_file.name)
click.echo(f"Processed: {result.success} success, {result.failed} failed.")
@cli.command("upload")
@click.option("--host", default="0.0.0.0", help="Bind host")
@click.option("--port", default=8001, type=int, help="Bind port")
@click.option("--verbose", "-v", is_flag=True, help="Enable debug logging")
def upload_cmd(host, port, verbose):
"""Start web upload server for mobile file ingestion."""
_setup_logging(verbose)
import uvicorn
click.echo(f"Starting upload server on {host}:{port}")
uvicorn.run("ingestion.web.upload:app", host=host, port=port, log_level="info")
if __name__ == "__main__":
cli()