Download knowledge_agent/cli.py from Viraj2307/JARVIS: direct link, hf CLI and curl.
- Browser
- Download file 7.5 kB
-
https://huggingface.co/spaces/Viraj2307/JARVIS/resolve/main/knowledge_agent/cli.py
- Command line
-
hf download hf://spaces/Viraj2307/JARVIS/knowledge_agent/cli.py
-
curl -L -o cli.py https://huggingface.co/spaces/Viraj2307/JARVIS/resolve/main/knowledge_agent/cli.py
7.5 kB
| """ | |
| cli.py β Command-line interface for the Knowledge Agent | |
| ======================================================= | |
| Usage examples: | |
| python cli.py index # index ./documents/ | |
| python cli.py index --dir ~/my_docs # index a custom folder | |
| python cli.py index --force # force re-index everything | |
| python cli.py ask "What is our pricing?" # one-shot Q&A | |
| python cli.py chat # interactive chat loop | |
| python cli.py list # list indexed documents | |
| python cli.py stats # show DB stats | |
| python cli.py delete report.pdf # remove a document | |
| """ | |
| import argparse | |
| import sys | |
| import os | |
| from typing import List, Dict | |
| # ββ Pretty printing helpers βββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| try: | |
| from rich.console import Console | |
| from rich.markdown import Markdown | |
| from rich.table import Table | |
| from rich.panel import Panel | |
| from rich import print as rprint | |
| RICH = True | |
| console = Console() | |
| except ImportError: | |
| RICH = False | |
| console = None | |
| from knowledge_api import ( | |
| query_knowledge, | |
| index_docs, | |
| index_single, | |
| get_knowledge_stats, | |
| list_indexed_docs, | |
| delete_doc, | |
| ) | |
| def print_answer(result: Dict): | |
| answer = result.get("answer", "") | |
| sources = result.get("sources", []) | |
| chunks = result.get("chunks_used", 0) | |
| if RICH: | |
| console.print(Panel( | |
| Markdown(answer), | |
| title="[bold cyan]Answer[/bold cyan]", | |
| border_style="cyan", | |
| )) | |
| if sources: | |
| console.print(f"[dim]Sources ({chunks} chunks): {', '.join(sources)}[/dim]") | |
| else: | |
| print("\n" + "="*60) | |
| print("ANSWER:") | |
| print(answer) | |
| if sources: | |
| print(f"\nSources ({chunks} chunks): {', '.join(sources)}") | |
| print("="*60 + "\n") | |
| def cmd_index(args): | |
| docs_dir = args.dir or "./documents" | |
| print(f"[Knowledge Agent] Indexing documents in: {docs_dir}") | |
| index_docs(docs_dir=docs_dir, force=args.force) | |
| def cmd_ask(args): | |
| question = " ".join(args.question) | |
| if RICH: | |
| console.print(f"\n[bold]Question:[/bold] {question}") | |
| else: | |
| print(f"\nQuestion: {question}") | |
| result = query_knowledge(question, top_k=args.top_k) | |
| print_answer(result) | |
| def cmd_chat(args): | |
| """Interactive REPL β keeps asking questions until the user exits.""" | |
| if RICH: | |
| console.print(Panel( | |
| "[bold cyan]Knowledge Agent β Interactive Chat[/bold cyan]\n" | |
| "Ask anything about your documents.\n" | |
| "Type [yellow]exit[/yellow] or [yellow]quit[/yellow] to stop.", | |
| border_style="cyan", | |
| )) | |
| else: | |
| print("\n" + "="*60) | |
| print(" Knowledge Agent β Interactive Chat") | |
| print(" Type 'exit' to quit.") | |
| print("="*60 + "\n") | |
| while True: | |
| try: | |
| if RICH: | |
| question = console.input("[bold green]You:[/bold green] ").strip() | |
| else: | |
| question = input("You: ").strip() | |
| except (KeyboardInterrupt, EOFError): | |
| print("\nGoodbye!") | |
| break | |
| if not question: | |
| continue | |
| if question.lower() in ("exit", "quit", "q", "bye"): | |
| print("Goodbye!") | |
| break | |
| # Special commands in chat mode | |
| if question.lower() == "/stats": | |
| cmd_stats(args) | |
| continue | |
| if question.lower() == "/list": | |
| cmd_list(args) | |
| continue | |
| if question.lower().startswith("/index "): | |
| path = question[7:].strip() | |
| index_single(path) | |
| continue | |
| result = query_knowledge(question, top_k=args.top_k if hasattr(args, "top_k") else 5) | |
| print_answer(result) | |
| def cmd_list(args): | |
| docs = list_indexed_docs() | |
| if not docs: | |
| print("No documents indexed yet.") | |
| return | |
| if RICH: | |
| table = Table(title="Indexed Documents", border_style="cyan") | |
| table.add_column("File", style="bold") | |
| table.add_column("Status") | |
| table.add_column("Path", style="dim") | |
| for d in docs: | |
| status = "[green]β exists[/green]" if d["exists"] else "[red]β missing[/red]" | |
| table.add_row(d["name"], status, d["path"]) | |
| console.print(table) | |
| else: | |
| print(f"\n{'File':<40} {'Status':<12} Path") | |
| print("-" * 80) | |
| for d in docs: | |
| status = "β exists" if d["exists"] else "β missing" | |
| print(f"{d['name']:<40} {status:<12} {d['path']}") | |
| def cmd_stats(args): | |
| stats = get_knowledge_stats() | |
| if RICH: | |
| console.print(Panel( | |
| f"[bold]Total chunks:[/bold] {stats['total_chunks']}\n" | |
| f"[bold]Indexed files:[/bold] {stats['indexed_files']}\n" | |
| f"[bold]Embed model:[/bold] {stats['embed_model']}\n" | |
| f"[bold]ChromaDB dir:[/bold] {stats['chroma_dir']}", | |
| title="[cyan]Knowledge Base Stats[/cyan]", | |
| border_style="cyan", | |
| )) | |
| else: | |
| print("\nKnowledge Base Stats:") | |
| for k, v in stats.items(): | |
| print(f" {k}: {v}") | |
| def cmd_delete(args): | |
| filename = args.filename | |
| confirm = input(f"Delete all chunks for '{filename}'? [y/N] ").strip().lower() | |
| if confirm == "y": | |
| delete_doc(filename) | |
| print(f"Deleted: {filename}") | |
| else: | |
| print("Cancelled.") | |
| # ββ Argument parser βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def main(): | |
| parser = argparse.ArgumentParser( | |
| prog="knowledge", | |
| description="Personal Knowledge Agent β RAG over your documents", | |
| ) | |
| subparsers = parser.add_subparsers(dest="command", required=True) | |
| # index | |
| p_index = subparsers.add_parser("index", help="Index documents into ChromaDB") | |
| p_index.add_argument("--dir", default=None, help="Documents directory (default: ./documents)") | |
| p_index.add_argument("--force", action="store_true", help="Force re-index all files") | |
| p_index.set_defaults(func=cmd_index) | |
| # ask | |
| p_ask = subparsers.add_parser("ask", help="Ask a one-shot question") | |
| p_ask.add_argument("question", nargs="+", help="Your question (in quotes or multiple words)") | |
| p_ask.add_argument("--top-k", dest="top_k", type=int, default=5, | |
| help="Number of chunks to retrieve (default: 5)") | |
| p_ask.set_defaults(func=cmd_ask) | |
| # chat | |
| p_chat = subparsers.add_parser("chat", help="Interactive chat loop") | |
| p_chat.add_argument("--top-k", dest="top_k", type=int, default=5) | |
| p_chat.set_defaults(func=cmd_chat) | |
| # list | |
| p_list = subparsers.add_parser("list", help="List indexed documents") | |
| p_list.set_defaults(func=cmd_list) | |
| # stats | |
| p_stats = subparsers.add_parser("stats", help="Show knowledge base statistics") | |
| p_stats.set_defaults(func=cmd_stats) | |
| # delete | |
| p_del = subparsers.add_parser("delete", help="Remove a document from the index") | |
| p_del.add_argument("filename", help="Filename to delete (e.g. report.pdf)") | |
| p_del.set_defaults(func=cmd_delete) | |
| args = parser.parse_args() | |
| args.func(args) | |
| if __name__ == "__main__": | |
| main() |