Spaces:
Running on Zero
Running on Zero
Download cli_chat.py from Shree-Lms-Developers2025/NovaAI: direct link, hf CLI and curl.
- Browser
- Download file 21 kB
-
https://huggingface.co/spaces/Shree-Lms-Developers2025/NovaAI/resolve/main/cli_chat.py
- Command line
-
hf download hf://spaces/Shree-Lms-Developers2025/NovaAI/cli_chat.py
-
curl -L -o cli_chat.py https://huggingface.co/spaces/Shree-Lms-Developers2025/NovaAI/resolve/main/cli_chat.py
21 kB
| """ | |
| Interactive CLI Chat Interface for Nova AI - ChatGPT Astra Edition. | |
| Rich-powered terminal interface featuring live token streaming, Astra Deep Reasoning, | |
| token vault management, multimodal generation (/image, /web), and session controls. | |
| """ | |
| import os | |
| import sys | |
| from pathlib import Path | |
| from typing import List, Dict, Any | |
| # Ensure UTF-8 output on Windows consoles | |
| if sys.platform == "win32": | |
| try: | |
| if sys.stdout and hasattr(sys.stdout, "reconfigure"): | |
| sys.stdout.reconfigure(encoding="utf-8") | |
| if sys.stderr and hasattr(sys.stderr, "reconfigure"): | |
| sys.stderr.reconfigure(encoding="utf-8") | |
| except Exception: | |
| pass | |
| # Ensure project root in sys.path | |
| PROJECT_ROOT = Path(__file__).resolve().parent | |
| if str(PROJECT_ROOT) not in sys.path: | |
| sys.path.insert(0, str(PROJECT_ROOT)) | |
| from rich.console import Console | |
| from rich.panel import Panel | |
| from rich.table import Table | |
| from rich.markdown import Markdown | |
| from rich.prompt import Prompt | |
| from src.config import config, AVAILABLE_MODELS, SYSTEM_PROMPT_PRESETS, GenerationConfig | |
| from src.model_engine import engine | |
| from src.token_system import token_vault, TOKEN_COSTS | |
| from src.multimodal import generate_ai_image, generate_ai_website | |
| from src.web_search import search_live_web | |
| from src.utils import ( | |
| format_chat_as_markdown, | |
| format_chat_as_json, | |
| format_chat_as_html, | |
| enhance_prompt_with_astra, | |
| get_system_hardware_info | |
| ) | |
| from src.domain_registry import domain_registry | |
| console = Console(legacy_windows=False) | |
| def print_banner(reasoning_mode: bool = False, grounding_mode: bool = False, active_domain: str = None): | |
| active_model = engine.model_id or config.default_model_id | |
| reasoning_status = "[bold green]ENABLED[/bold green]" if reasoning_mode else "[dim]DISABLED[/dim]" | |
| grounding_status = "[bold green]ENABLED[/bold green]" if grounding_mode else "[dim]DISABLED[/dim]" | |
| domain_status = f"[bold magenta]{active_domain}[/bold magenta]" if active_domain else f"[bold green]{domain_registry.total_count:,} Domains[/bold green] [dim](Auto-Detect)[/dim]" | |
| balance = token_vault.get_balance() | |
| hw = get_system_hardware_info() | |
| banner_text = ( | |
| "[bold cyan]🌟 NOVA AI — Flagship ChatGPT Astra Enterprise Suite[/bold cyan]\n" | |
| "[dim]Full 7B/8B Foundation Models • NVIDIA ZeroGPU & CUDA • Deep Reasoning • Multimodal Studio[/dim]\n\n" | |
| f"• Active Model: [bold yellow]{active_model}[/bold yellow]\n" | |
| f"• Hardware Engine: [bold green]{hw.get('hardware_badge')}[/bold green]\n" | |
| f"• Astra Tokens: [bold cyan]🪙 {balance} ASTRA[/bold cyan]\n" | |
| f"• Specialization: {domain_status}\n" | |
| f"• Deep Reasoning: {reasoning_status}\n" | |
| f"• Web Grounding: {grounding_status}\n\n" | |
| "[dim]Commands: [bold cyan]/help[/bold cyan], [bold yellow]/think[/bold yellow], [bold blue]/domains[/bold blue], [bold magenta]/image[/bold magenta], [bold blue]/web[/bold blue], [bold green]/tokens[/bold green], [bold red]/quit[/bold red][/dim]" | |
| ) | |
| console.print(Panel(banner_text, border_style="cyan", title="[bold magenta]Astra Flagship Console[/bold magenta]")) | |
| def print_help(): | |
| help_md = """ | |
| ### 🌟 Nova Astra CLI Commands: | |
| - `/help` - Display this command reference | |
| - `/domains` - Browse and search 1,000+ domain specializations (1,425 available) | |
| - `/domain` - Lock into a specific domain specialization (e.g. `/domain upi` or `/domain auto`) | |
| - `/train` - Launch AI/ML Fine-Tuning Studio (PEFT LoRA + Weight Merging) | |
| - `/tokens` - View Astra token balance & transaction history | |
| - `/think` - Toggle Astra Deep Reasoning Mode (5 ASTRA) | |
| - `/search` - Live web search with DuckDuckGo & Wikipedia (3 ASTRA) | |
| - `/ground` - Toggle automatic real-time web grounding for chat | |
| - `/image` - Generate an AI Image with FLUX / SDXL (15 ASTRA) | |
| - `/web` - Generate a full responsive HTML5 website (20 ASTRA) | |
| - `/spark` - Enhance a prompt with Astra Spark Optimizer | |
| - `/persona` - Switch ChatGPT Astra persona mode | |
| - `/model` - Switch active model architecture | |
| - `/stats` - View hardware profiler & session statistics | |
| - `/export` - Export dialogue transcript to Markdown, JSON, or HTML | |
| - `/clear` - Reset active conversation history | |
| - `/quit` - Exit interactive session | |
| """ | |
| console.print(Markdown(help_md)) | |
| def cli_web_search(): | |
| query = Prompt.ask("\n[bold cyan]🌐 Enter search query[/bold cyan]").strip() | |
| if not query: | |
| return | |
| with console.status("[bold cyan]Searching live web with DuckDuckGo & Wikipedia (3 ASTRA)...[/bold cyan]"): | |
| res = search_live_web(query) | |
| if res.get("status") == "success": | |
| results = res.get("results", []) | |
| console.print(f"[bold green]✓ Found {len(results)} live web sources:[/bold green]") | |
| for idx, r in enumerate(results, 1): | |
| console.print(f"[bold cyan][{idx}][/bold cyan] [bold white]{r['title']}[/bold white] [dim]({r['source']})[/dim]") | |
| console.print(f" 🔗 [link={r['url']}]{r['url']}[/link]") | |
| console.print(f" 📄 [dim]{r['snippet'][:180]}...[/dim]\n") | |
| console.print(f"🪙 Remaining Balance: [bold cyan]{res['remaining_tokens']} ASTRA[/bold cyan]") | |
| else: | |
| console.print(f"[bold red]Search error:[/bold red] {res.get('message')}") | |
| def show_tokens(): | |
| bal = token_vault.get_balance() | |
| history = token_vault.get_transaction_history() | |
| table = Table(title=f"🪙 Astra Token Vault (Balance: {bal} ASTRA)", border_style="cyan") | |
| table.add_column("Date", style="dim") | |
| table.add_column("Action", style="bold") | |
| table.add_column("Amount", justify="right") | |
| table.add_column("Balance After", justify="right", style="bold green") | |
| for t in history[:8]: | |
| amt_color = "green" if t.get("amount", 0) > 0 else "red" | |
| table.add_row( | |
| t.get("date", ""), | |
| t.get("action", ""), | |
| f"[{amt_color}]{t.get('amount', 0):+d}[/{amt_color}]", | |
| str(t.get("balance_after", "")) | |
| ) | |
| console.print(table) | |
| def cli_image_generator(): | |
| prompt = Prompt.ask("\n[bold magenta]🎨 Enter image description[/bold magenta]").strip() | |
| if not prompt: | |
| return | |
| with console.status("[bold cyan]Synthesizing image with Astra FLUX neural engine (15 ASTRA)...[/bold cyan]"): | |
| res = generate_ai_image(prompt) | |
| if res.get("status") == "success": | |
| console.print(f"[bold green]✓ Image generated successfully![/bold green]") | |
| console.print(f"📁 Local File: [link={res['file_path']}]{res['file_path']}[/link]") | |
| console.print(f"🪙 Remaining Balance: [bold cyan]{res['remaining_tokens']} ASTRA[/bold cyan]") | |
| else: | |
| console.print(f"[bold red]Generation error:[/bold red] {res.get('message')}") | |
| def cli_website_generator(): | |
| prompt = Prompt.ask("\n[bold blue]🌐 Enter React & Next.js website concept[/bold blue]").strip() | |
| if not prompt: | |
| return | |
| with console.status("[bold cyan]Synthesizing React.js & Next.js project with Nova Astra WebCoder-V1 (20 ASTRA)...[/bold cyan]"): | |
| res = generate_ai_website(prompt) | |
| if res.get("status") == "success": | |
| console.print(f"[bold green]✓ React & Next.js Project generated successfully![/bold green]") | |
| console.print(f"📦 Auto ZIP Archive: [bold yellow]{res.get('zip_path')}[/bold yellow]") | |
| console.print(f"⚛️ React Component: [bold cyan]{res.get('jsx_path')}[/bold cyan]") | |
| console.print(f"⚡ Next.js Page: [bold magenta]{res.get('tsx_path')}[/bold magenta]") | |
| console.print(f"🌐 Live Sandbox: [link={res['file_path']}]{res['file_path']}[/link]") | |
| console.print(f"🪙 Remaining Balance: [bold cyan]{res['remaining_tokens']} ASTRA[/bold cyan]") | |
| else: | |
| console.print(f"[bold red]Generation error:[/bold red] {res.get('message')}") | |
| def cli_fine_tuning(): | |
| from src.fine_tune import run_lora_finetuning | |
| from src.dataset_builder import compile_huge_training_dataset, HUGE_DATASET_FILE | |
| console.print(Panel( | |
| "[bold cyan]🧠 Nova Astra AI/ML Fine-Tuning Studio[/bold cyan]\n" | |
| "[dim]LoRA Parameter-Efficient Fine-Tuning on Huge Multi-Turn Datasets (React, Fintech INR, Multimodal, Reasoning)[/dim]", | |
| border_style="magenta" | |
| )) | |
| choice = Prompt.ask( | |
| "\n[bold yellow]Select Training Dataset Scope[/bold yellow]\n" | |
| " [1] Quick LoRA Trial (10 samples, ~1-2 min)\n" | |
| " [2] High-Yield Benchmark (50 samples, ~5 min)\n" | |
| " [3] Massive Dataset (All 610 samples)\n" | |
| " [4] Recompile / Verify Huge Dataset JSONL\n" | |
| "Choice", | |
| choices=["1", "2", "3", "4"], | |
| default="1" | |
| ) | |
| if choice == "4": | |
| with console.status("[bold cyan]Compiling 600+ sample multi-turn dataset...[/bold cyan]"): | |
| d_res = compile_huge_training_dataset(target_count=600) | |
| console.print(f"[bold green]✓ Dataset compiled successfully:[/bold green] {d_res['sample_count']} samples (~{d_res['estimated_tokens']:,} tokens)") | |
| console.print(f"📁 Location: {d_res['file_path']}") | |
| return | |
| sample_map = {"1": 10, "2": 50, "3": None} | |
| max_samples = sample_map[choice] | |
| active_model = engine.model_id or config.default_model_id | |
| console.print(f"\n[bold cyan]Starting LoRA Fine-Tuning on {active_model} (samples: {max_samples or 'ALL'})...[/bold cyan]") | |
| with console.status("[bold green]Executing PEFT LoRA training loop & weight merging...[/bold green]"): | |
| res = run_lora_finetuning( | |
| base_model_id=active_model, | |
| epochs=1, | |
| batch_size=1, | |
| max_samples=max_samples, | |
| export_merged=True | |
| ) | |
| if res.get("status") == "success": | |
| console.print("\n[bold green]🎉 Fine-Tuning & Weight Export Succeeded![/bold green]") | |
| console.print(f" • Trained Samples: [bold white]{res.get('samples_trained')}[/bold white]") | |
| console.print(f" • Training Loss: [bold cyan]{res.get('train_loss')}[/bold cyan]") | |
| console.print(f" • Time Elapsed: [bold yellow]{res.get('training_time_seconds')}s[/bold yellow]") | |
| console.print(f" • Adapter Dir: [dim]{res.get('adapter_dir')}[/dim]") | |
| console.print(f" • Merged Safetensors: [bold green]{res.get('exported_model_dir')}[/bold green]") | |
| else: | |
| console.print(f"[bold red]❌ Training failed:[/bold red] {res.get('message')}") | |
| def cli_domain_browser(): | |
| console.print(Panel( | |
| f"[bold cyan]🌐 Nova Astra 1000+ Domain Specializations Hub[/bold cyan]\n" | |
| f"[dim]Total Available: {domain_registry.total_count:,} domains across {len(domain_registry.get_all_categories())} categories.[/dim]", | |
| border_style="cyan" | |
| )) | |
| search_q = Prompt.ask("[bold yellow]Enter keyword to search domains (or press Enter to list categories)[/bold yellow]", default="").strip() | |
| if search_q: | |
| results = domain_registry.search_domains(search_q, limit=12) | |
| if not results: | |
| console.print("[yellow]No exact match found. Showing closest matches.[/yellow]") | |
| table = Table(title=f"Domain Search Results for '{search_q}'", border_style="magenta") | |
| table.add_column("ID", style="dim") | |
| table.add_column("Domain Specialization", style="bold cyan") | |
| table.add_column("Category", style="green") | |
| table.add_column("Scope Summary") | |
| for d in results: | |
| table.add_row(d.id, d.name, d.category, d.description[:60] + "...") | |
| console.print(table) | |
| else: | |
| cats = domain_registry.get_all_categories() | |
| table = Table(title="1,000+ Domain Categories", border_style="cyan") | |
| table.add_column("#", style="dim") | |
| table.add_column("Category", style="bold white") | |
| table.add_column("Domains Count", style="bold yellow") | |
| for i, c in enumerate(cats, 1): | |
| count = len(domain_registry.get_domains_by_category(c)) | |
| table.add_row(str(i), c, f"{count} domains") | |
| console.print(table) | |
| console.print("[dim]Tip: Type '/domain <id_or_keyword>' to lock into any domain, or '/domain auto' to restore auto-detect.[/dim]") | |
| def cli_main(): | |
| reasoning_mode = False | |
| grounding_mode = False | |
| active_domain = None | |
| active_domain_name = None | |
| print_banner(reasoning_mode, grounding_mode, active_domain_name) | |
| with console.status("[bold green]🌟 Initializing Nova Astra Engine...[/bold green]"): | |
| try: | |
| engine.load_model() | |
| except Exception as e: | |
| console.print(f"[bold red]Initialization failed:[/bold red] {e}") | |
| return | |
| system_prompt = SYSTEM_PROMPT_PRESETS["ChatGPT Astra Core (Omniscient & Empathetic)"] | |
| messages: List[Dict[str, str]] = [] | |
| while True: | |
| try: | |
| user_input = Prompt.ask(f"\n[bold green]👤 You[/bold green] [dim]({token_vault.get_balance()} ASTRA)[/dim]").strip() | |
| except (KeyboardInterrupt, EOFError): | |
| console.print("\n[bold yellow]Exiting Nova AI. Farewell![/bold yellow]") | |
| break | |
| if not user_input: | |
| continue | |
| if user_input.startswith("/"): | |
| cmd = user_input.lower().split()[0] | |
| if cmd in ("/quit", "/exit"): | |
| console.print("[bold yellow]Exiting Nova AI. Farewell![/bold yellow]") | |
| break | |
| elif cmd == "/help": | |
| print_help() | |
| continue | |
| elif cmd == "/tokens": | |
| show_tokens() | |
| continue | |
| elif cmd == "/domains": | |
| cli_domain_browser() | |
| continue | |
| elif cmd == "/domain": | |
| parts = user_input.split(maxsplit=1) | |
| if len(parts) < 2 or parts[1].strip().lower() in ("auto", "none", "reset"): | |
| active_domain = None | |
| active_domain_name = None | |
| console.print("[bold green]✓ Domain specialization reset to: AUTO-DETECT (1,425 domains active).[/bold green]") | |
| else: | |
| query = parts[1].strip() | |
| matched = domain_registry.get_domain(query) | |
| if not matched: | |
| matches = domain_registry.search_domains(query, limit=1) | |
| if matches: | |
| matched = matches[0] | |
| if matched: | |
| active_domain = matched.id | |
| active_domain_name = f"{matched.name} ({matched.category})" | |
| console.print(f"[bold green]✓ Specialization locked to:[/bold green] [bold cyan]{active_domain_name}[/bold cyan]") | |
| else: | |
| console.print(f"[bold red]Domain '{query}' not found. Type '/domains' to search 1,000+ domains.[/bold red]") | |
| continue | |
| elif cmd == "/train": | |
| cli_fine_tuning() | |
| continue | |
| elif cmd in ("/search", "/websearch"): | |
| cli_web_search() | |
| continue | |
| elif cmd == "/ground": | |
| grounding_mode = not grounding_mode | |
| status_str = "ENABLED" if grounding_mode else "DISABLED" | |
| console.print(f"[bold cyan]🌐 Real-Time Web Grounding:[/bold cyan] {status_str}") | |
| continue | |
| elif cmd == "/image": | |
| cli_image_generator() | |
| continue | |
| elif cmd == "/web": | |
| cli_website_generator() | |
| continue | |
| elif cmd == "/think": | |
| reasoning_mode = not reasoning_mode | |
| status_str = "ENABLED (Chain-of-Thought active)" if reasoning_mode else "DISABLED" | |
| console.print(f"[bold cyan]🧠 Astra Deep Reasoning Mode:[/bold cyan] {status_str}") | |
| continue | |
| elif cmd == "/spark": | |
| raw_query = Prompt.ask("[bold cyan]Enter query to enhance[/bold cyan]") | |
| enhanced = enhance_prompt_with_astra(raw_query) | |
| console.print(Panel(enhanced, title="[bold magenta]✨ Astra Spark[/bold magenta]", border_style="magenta")) | |
| continue | |
| elif cmd == "/clear": | |
| messages.clear() | |
| console.print("[bold yellow]✓ Conversation cleared.[/bold yellow]") | |
| continue | |
| elif cmd == "/stats": | |
| hw = get_system_hardware_info() | |
| table = Table(title="Astra Runtime Telemetry", border_style="cyan") | |
| table.add_column("Metric", style="bold") | |
| table.add_column("Value") | |
| table.add_row("Active Model", str(engine.model_id)) | |
| table.add_row("Astra Balance", f"{token_vault.get_balance()} ASTRA") | |
| table.add_row("Device", engine.device.upper()) | |
| table.add_row("RAM", f"{hw.get('available_ram_gb')} GB / {hw.get('total_ram_gb')} GB") | |
| console.print(table) | |
| continue | |
| else: | |
| console.print(f"[bold red]Unknown command:[/bold red] {user_input}. Type [bold yellow]/help[/bold yellow].") | |
| continue | |
| # Check and deduct tokens for chat | |
| action = "deep_reasoning" if reasoning_mode else "chat_query" | |
| total_cost = TOKEN_COSTS[action] + (TOKEN_COSTS["web_search"] if grounding_mode else 0) | |
| if token_vault.get_balance() < total_cost: | |
| console.print(f"[bold red]Insufficient tokens. Requires {total_cost} ASTRA, but you have {token_vault.get_balance()} ASTRA.[/bold red]") | |
| continue | |
| success, msg, remaining = token_vault.deduct_tokens(action) | |
| if not success: | |
| console.print(f"[bold red]{msg}[/bold red]") | |
| continue | |
| grounded_context = "" | |
| citations_summary = [] | |
| if grounding_mode: | |
| token_vault.deduct_tokens("web_search") | |
| with console.status("[bold cyan]Querying live web sources...[/bold cyan]"): | |
| search_res = search_live_web(user_input, max_results=3, deduct_tokens=False) | |
| if search_res.get("status") == "success" and search_res.get("results"): | |
| grounded_context = search_res.get("grounding_context", "") | |
| citations_summary = search_res.get("results", []) | |
| messages.append({"role": "user", "content": user_input}) | |
| gen_messages = [] | |
| if system_prompt: | |
| gen_messages.append({"role": "system", "content": system_prompt}) | |
| for m in messages[:-1]: | |
| gen_messages.append({"role": m["role"], "content": m["content"]}) | |
| if grounded_context: | |
| gen_messages.append({"role": "user", "content": f"{grounded_context}\n\nUser Question: {user_input}"}) | |
| else: | |
| gen_messages.append({"role": "user", "content": user_input}) | |
| gen_cfg = GenerationConfig( | |
| max_new_tokens=config.gen_config.max_new_tokens, | |
| temperature=config.gen_config.temperature, | |
| deep_reasoning=reasoning_mode, | |
| domain_id=active_domain, | |
| auto_detect_domain=(active_domain is None) | |
| ) | |
| rem_bal = token_vault.get_balance() | |
| ground_tag = " | 🌐 Web Grounded" if grounding_mode else "" | |
| domain_tag = f" | 🎓 {active_domain_name}" if active_domain_name else "" | |
| console.print(f"\n[bold magenta]🌟 Nova Astra:[/bold magenta] [dim](-{total_cost} ASTRA{ground_tag}{domain_tag} | Bal: {rem_bal})[/dim]") | |
| full_response = "" | |
| last_metrics = {} | |
| try: | |
| for partial_text, metrics in engine.stream_chat(gen_messages, gen_cfg): | |
| new_chunk = partial_text[len(full_response):] | |
| console.print(new_chunk, end="", style="white") | |
| full_response = partial_text | |
| last_metrics = metrics | |
| console.print() | |
| if citations_summary: | |
| console.print("\n[bold cyan]🌐 Verified Live Sources:[/bold cyan]") | |
| for idx, r in enumerate(citations_summary, 1): | |
| console.print(f" [cyan][{idx}][/cyan] {r['title']} [dim]({r['url']})[/dim]") | |
| messages.append({"role": "assistant", "content": full_response}) | |
| tps = last_metrics.get("tokens_per_second", 0.0) | |
| ttft = last_metrics.get("time_to_first_token_ms", 0.0) | |
| tokens = last_metrics.get("tokens_generated", 0) | |
| lat = last_metrics.get("total_latency_seconds", 0.0) | |
| detected_domain = last_metrics.get("active_domain") | |
| domain_info = f" | 🎓 Specialization: {detected_domain}" if detected_domain else "" | |
| console.print( | |
| f"[dim]⚡ Speed: {tps} tps | TTFT: {ttft}ms | Tokens: {tokens} | Latency: {lat}s{domain_info} | Tokens Rem: {rem_bal} ASTRA[/dim]" | |
| ) | |
| except Exception as e: | |
| console.print(f"\n[bold red]Error during generation:[/bold red] {e}") | |
| if __name__ == "__main__": | |
| cli_main() | |