""" kerdos_rag/cli.py Command-line interface for the Kerdos RAG engine. kerdos-rag serve # start Gradio UI (default port 7860) kerdos-rag api # start FastAPI REST server (default port 8000) kerdos-rag index # index documents from terminal """ from __future__ import annotations import argparse import sys def _cmd_serve(args: argparse.Namespace) -> None: """Launch the Gradio web UI.""" import importlib.util, os os.environ.setdefault("GRADIO_SERVER_PORT", str(args.port)) os.environ.setdefault("GRADIO_SERVER_NAME", args.host) # app.py lives at the repo root — import it as a module spec = importlib.util.spec_from_file_location("app", _repo_root() / "app.py") mod = importlib.util.module_from_spec(spec) spec.loader.exec_module(mod) mod.demo.queue() mod.demo.launch(css=mod.CSS, theme=__import__("gradio").themes.Soft()) def _cmd_api(args: argparse.Namespace) -> None: """Launch the FastAPI REST server.""" import uvicorn from kerdos_rag.server import app # noqa: F401 print(f"[kerdos-rag] Starting REST API on http://{args.host}:{args.port}") uvicorn.run( "kerdos_rag.server:app", host=args.host, port=args.port, reload=args.reload, log_level="info", ) def _cmd_index(args: argparse.Namespace) -> None: """Index documents from the command line and print a summary.""" from kerdos_rag import KerdosRAG engine = KerdosRAG() # token not needed for pure indexing result = engine.index(args.files) if result["indexed"]: print(f"✅ Indexed: {', '.join(result['indexed'])}") if result["skipped"]: print(f"⚠️ Skipped (already indexed): {', '.join(result['skipped'])}") print(f"📦 Total chunks: {result['chunk_count']}") if args.save: engine.save(args.save) print(f"💾 Index saved to: {args.save}") def _repo_root(): """Return the directory containing this package.""" from pathlib import Path return Path(__file__).resolve().parent.parent def main(argv: list[str] | None = None) -> None: parser = argparse.ArgumentParser( prog="kerdos-rag", description="Kerdos RAG — Enterprise Document Q&A engine", ) sub = parser.add_subparsers(dest="command", required=True) # ── serve ──────────────────────────────────────────────────────────────── p_serve = sub.add_parser("serve", help="Start the Gradio web UI") p_serve.add_argument("--host", default="0.0.0.0") p_serve.add_argument("--port", type=int, default=7860) p_serve.set_defaults(func=_cmd_serve) # ── api ────────────────────────────────────────────────────────────────── p_api = sub.add_parser("api", help="Start the FastAPI REST server") p_api.add_argument("--host", default="0.0.0.0") p_api.add_argument("--port", type=int, default=8000) p_api.add_argument("--reload", action="store_true", help="Enable auto-reload (dev only)") p_api.set_defaults(func=_cmd_api) # ── index ───────────────────────────────────────────────────────────────── p_idx = sub.add_parser("index", help="Index documents from the terminal") p_idx.add_argument("files", nargs="+", metavar="FILE") p_idx.add_argument("--save", metavar="DIR", default="", help="Save index to directory") p_idx.set_defaults(func=_cmd_index) args = parser.parse_args(argv) args.func(args) if __name__ == "__main__": main()