#!/usr/bin/env python3 """ JARVIS — HuggingFace Space App Gradio chat interface for JARVIS personal AI assistant. Runs entirely locally on HuggingFace Spaces (CPU or GPU) with 16 GB RAM. Launch: python app.py Or via HuggingFace Spaces (auto-detected from README.md sdk: gradio). """ import os import io import json import threading import gradio as gr # ── Init subsystems ────────────────────────────────────────────────────────── import memory import thinking import brain memory.init_db() thinking.start_thinking_engine() # Warm-up model in background so UI loads instantly _warmup_thread = brain.warmup() # ── TTS helper ──────────────────────────────────────────────────────────────── def _speak(text: str): """Return audio bytes for Gradio Audio component, or None.""" try: from voice_tts import tts_bytes return tts_bytes(text) except Exception: return None # ── Core chat logic ──────────────────────────────────────────────────────────── def chat(user_message: str, history: list[list[str]], audio_reply: bool): """ Main chat handler — called by Gradio. history: [[user_msg, bot_msg], ...] Returns: (updated_history, status_text, audio_or_None) """ if not user_message.strip(): return history, "Say something, sir.", None lower = user_message.lower().strip() # ── Built-in commands ────────────────────────────────────────────────── if lower in ("status", "jarvis status"): facts = memory.get_all_facts() reply = ( f"Status: Online. " f"Memory: {len(facts)} facts. " f"Model: {brain.HF_MODEL}. " f"TTS: {'ON' if audio_reply else 'OFF'}." ) history.append([user_message, reply]) audio = _speak(reply) if audio_reply else None return history, "Ready.", audio if lower in ("anticipate", "what are you thinking"): ants = thinking.get_anticipations() reply = "Thinking ahead: " + (", ".join(ants[:3]) if ants else "No predictions yet.") history.append([user_message, reply]) audio = _speak(reply) if audio_reply else None return history, "Ready.", audio if lower.startswith("remember ") and " is " in lower: try: part = user_message[9:] # strip "remember " key, val = part.split(" is ", 1) memory.save_fact(key.strip().lower().replace(" ", "_"), val.strip()) reply = f"Remembered: {key.strip()} is {val.strip()}." except Exception as e: reply = f"Couldn't remember that: {e}" history.append([user_message, reply]) audio = _speak(reply) if audio_reply else None return history, "Memory updated.", audio # ── Normal brain query ───────────────────────────────────────────────── hist_flat = [ {"role": "user", "message": pair[0]} for pair in history if pair[0] ] + [ {"role": "jarvis", "message": pair[1]} for pair in history if len(pair) > 1 and pair[1] ] # interleave properly hist_pairs = [] for pair in history: if pair[0]: hist_pairs.append({"role": "user", "message": pair[0]}) if len(pair) > 1 and pair[1]: hist_pairs.append({"role": "jarvis", "message": pair[1]}) reply = brain.ask(user_message, hist_pairs) history.append([user_message, reply]) audio = _speak(reply) if audio_reply else None return history, "Ready.", audio def remember_fact(key: str, value: str): """Directly save a fact via the sidebar form.""" if not key.strip() or not value.strip(): return "Please fill in both fields." memory.save_fact(key.strip().lower().replace(" ", "_"), value.strip()) return f"Saved: {key.strip()} = {value.strip()}" def load_facts(): facts = memory.get_all_facts() if not facts: return "No facts stored yet." return "\n".join(f"**{k}**: {v}" for k, v in facts.items()) def load_anticipations(): ants = thinking.get_anticipations() if not ants: return "No predictions yet. JARVIS thinks every hour." return "\n".join(f"• {a}" for a in ants[:5]) # ── Build Gradio UI ──────────────────────────────────────────────────────────── def build_ui() -> gr.Blocks: css = """ #jarvis-header { text-align: center; margin-bottom: 8px; } #jarvis-header h1 { font-size: 2.4em; font-weight: 800; letter-spacing: 2px; } #jarvis-header p { color: #888; margin-top: -8px; } .gradio-container { max-width: 900px !important; margin: auto; } """ with gr.Blocks(title="JARVIS – Personal AI", css=css, theme=gr.themes.Soft()) as demo: # ── Header ────────────────────────────────────────────────────────── with gr.Row(elem_id="jarvis-header"): gr.HTML( "
Just A Rather Very Intelligent System — Your Personal AI Agent
" ""
f"Powered by: {brain.HF_MODEL} · 16 GB RAM optimised · Local inference"
"