import gradio as gr import requests import os JARVIS_API = os.getenv("JARVIS_API_URL", "https://jarvis-9vys.onrender.com") def chat_with_jarvis(message, history): if not message.strip(): return history, "" try: res = requests.post(f"{JARVIS_API}/chat", json={ "message": message, "force_offline": False, "text_only": False }, timeout=60) data = res.json() response = data.get("response", "কোনো সাড়া পাওয়া যায়নি") brain = data.get("brain_used", "Unknown") mode = data.get("mode", "normal") online = "🌐 Online" if data.get("online") else "📴 Offline" reply = f"{response}\n\n---\n🧠 `{brain}` | {online} | Mode: `{mode}`" except Exception as e: reply = f"⚠️ JARVIS Server connect করা যাচ্ছে না।\n\n`Error: {str(e)}`" history = history or [] # 🔴 ফিক্স: Gradio-এর নতুন 'messages' ফরম্যাট অনুযায়ী ডেটা সেভ করা হচ্ছে history.append({"role": "user", "content": message}) history.append({"role": "assistant", "content": reply}) return history, "" def get_status(): try: res = requests.get(f"{JARVIS_API}/status", timeout=60) data = res.json() cpu = data["resource"]["cpu_percent"] ram = data["resource"]["ram_percent"] # 🔴 ফিক্স: 'total_memories' এর বদলে সঠিক key ব্যবহার করা হলো mem = data["memory"].get("supabase_total_memories", data["memory"].get("json_memory", 0)) idle = data["resource"]["idle_minutes"] sleeping = data["resource"]["sleeping"] status = "😴 SLEEP MODE" if sleeping else "⚡ ACTIVE" return f"◈ SYSTEM STATUS: **{status}**   |   🖥️ CPU: **{cpu}%**   |   💾 RAM: **{ram}%**   |   🧠 MEMORIES: **{mem}**   |   ⏱️ IDLE: **{idle} min**" except Exception as e: # 🔴 ফিক্স: এখন থেকে সার্ভার অফলাইন হলে আসল কারণটাও (Error) লেখা উঠবে return f"◈ SYSTEM STATUS: **⚠️ SERVER OFFLINE** — Error: {str(e)}" custom_css = """ @import url('https://fonts.googleapis.com/css2?family=Orbitron:wght@400;500;700;900&family=Share+Tech+Mono&family=Exo+2:wght@300;400&display=swap'); *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; } body { background: #000510 !important; font-family: 'Share Tech Mono', monospace !important; overflow-x: hidden; } /* Animated grid background */ body::before { content: ''; position: fixed; top: 0; left: 0; right: 0; bottom: 0; background-image: linear-gradient(rgba(0, 212, 255, 0.03) 1px, transparent 1px), linear-gradient(90deg, rgba(0, 212, 255, 0.03) 1px, transparent 1px); background-size: 50px 50px; animation: gridMove 20s linear infinite; pointer-events: none; z-index: 0; } /* Scanlines */ body::after { content: ''; position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: repeating-linear-gradient( 0deg, transparent, transparent 2px, rgba(0, 212, 255, 0.012) 2px, rgba(0, 212, 255, 0.012) 4px ); pointer-events: none; z-index: 1; } @keyframes gridMove { 0% { transform: translateY(0); } 100% { transform: translateY(50px); } } .gradio-container { background: transparent !important; max-width: 960px !important; margin: 0 auto !important; position: relative; z-index: 2; padding: 20px !important; } /* ══ HEADER ══ */ #jarvis-header { text-align: center; padding: 40px 0 10px; position: relative; } #jarvis-header::before { content: ''; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 400px; height: 400px; background: radial-gradient(circle, rgba(0,100,255,0.08) 0%, transparent 70%); pointer-events: none; } #jarvis-logo { font-family: 'Orbitron', monospace; font-size: 4rem; font-weight: 900; background: linear-gradient(90deg, #00d4ff, #0066ff, #00ffcc, #00d4ff); background-size: 300%; -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; animation: shimmer 4s linear infinite; letter-spacing: 0.5em; text-indent: 0.5em; filter: drop-shadow(0 0 20px rgba(0, 212, 255, 0.4)); } #jarvis-tagline { font-family: 'Share Tech Mono', monospace; font-size: 0.65rem; color: rgba(0, 212, 255, 0.4); letter-spacing: 0.6em; text-transform: uppercase; margin-top: 4px; text-indent: 0.6em; } #jarvis-divider { display: flex; align-items: center; gap: 12px; margin: 20px 0; opacity: 0.4; } #jarvis-divider::before, #jarvis-divider::after { content: ''; flex: 1; height: 1px; background: linear-gradient(90deg, transparent, #00d4ff, transparent); } #jarvis-divider span { font-family: 'Orbitron', monospace; font-size: 0.5rem; color: #00d4ff; letter-spacing: 0.3em; } @keyframes shimmer { 0% { background-position: 0% } 100% { background-position: 300% } } /* ══ STATUS BAR ══ */ #status-bar { background: rgba(0, 20, 50, 0.6) !important; border: 1px solid rgba(0, 212, 255, 0.2) !important; border-radius: 6px !important; padding: 10px 20px !important; margin-bottom: 16px !important; font-family: 'Share Tech Mono', monospace !important; font-size: 0.72rem !important; color: rgba(0, 212, 255, 0.6) !important; text-align: center; letter-spacing: 0.05em; position: relative; overflow: hidden; } #status-bar::before { content: ''; position: absolute; top: 0; left: -100%; width: 60%; height: 100%; background: linear-gradient(90deg, transparent, rgba(0,212,255,0.05), transparent); animation: scan 4s linear infinite; } @keyframes scan { 0% { left: -60%; } 100% { left: 160%; } } /* ══ CHAT WINDOW ══ */ .chat-wrap { background: rgba(0, 10, 30, 0.85) !important; border: 1px solid rgba(0, 212, 255, 0.2) !important; border-radius: 12px !important; overflow: hidden !important; box-shadow: 0 0 40px rgba(0, 212, 255, 0.08), 0 0 80px rgba(0, 50, 200, 0.06), inset 0 0 40px rgba(0, 0, 20, 0.5) !important; position: relative; } .chat-wrap::before { content: 'NEURAL INTERFACE'; position: absolute; top: 10px; right: 16px; font-family: 'Orbitron', monospace; font-size: 0.45rem; color: rgba(0,212,255,0.2); letter-spacing: 0.3em; z-index: 10; } /* Messages */ .message { font-family: 'Share Tech Mono', monospace !important; font-size: 0.88rem !important; line-height: 1.6 !important; border-radius: 8px !important; padding: 12px 16px !important; } .message.user { background: rgba(0, 80, 200, 0.12) !important; border: 1px solid rgba(0, 100, 255, 0.25) !important; color: rgba(160, 210, 255, 0.9) !important; } .message.bot, .message.assistant { background: rgba(0, 212, 255, 0.06) !important; border: 1px solid rgba(0, 212, 255, 0.2) !important; color: rgba(220, 245, 255, 0.9) !important; } /* ══ INPUT AREA ══ */ textarea, input[type="text"] { background: rgba(0, 8, 24, 0.95) !important; border: 1px solid rgba(0, 212, 255, 0.3) !important; border-radius: 8px !important; color: #00d4ff !important; font-family: 'Share Tech Mono', monospace !important; font-size: 0.9rem !important; caret-color: #00d4ff !important; transition: all 0.3s !important; padding: 12px 16px !important; } textarea:focus, input[type="text"]:focus { border-color: rgba(0, 212, 255, 0.8) !important; box-shadow: 0 0 20px rgba(0, 212, 255, 0.2), inset 0 0 10px rgba(0,212,255,0.03) !important; outline: none !important; } textarea::placeholder { color: rgba(0, 212, 255, 0.25) !important; } /* ══ BUTTONS ══ */ button { font-family: 'Orbitron', monospace !important; letter-spacing: 0.15em !important; font-size: 0.65rem !important; border-radius: 6px !important; transition: all 0.3s ease !important; text-transform: uppercase !important; } button.primary { background: transparent !important; border: 1px solid rgba(0, 212, 255, 0.8) !important; color: #00d4ff !important; padding: 10px 20px !important; } button.primary:hover { background: rgba(0, 212, 255, 0.1) !important; box-shadow: 0 0 25px rgba(0, 212, 255, 0.3), inset 0 0 15px rgba(0,212,255,0.05) !important; border-color: #00d4ff !important; } button.secondary { background: transparent !important; border: 1px solid rgba(0, 100, 255, 0.4) !important; color: rgba(80, 150, 255, 0.8) !important; } button.secondary:hover { background: rgba(0, 80, 200, 0.1) !important; border-color: rgba(0, 150, 255, 0.7) !important; box-shadow: 0 0 15px rgba(0, 100, 255, 0.2) !important; } /* ══ LABELS ══ */ label, .label-wrap span { font-family: 'Share Tech Mono', monospace !important; font-size: 0.65rem !important; color: rgba(0, 212, 255, 0.35) !important; letter-spacing: 0.25em !important; text-transform: uppercase !important; } /* ══ SCROLLBAR ══ */ ::-webkit-scrollbar { width: 3px; height: 3px; } ::-webkit-scrollbar-track { background: rgba(0,5,16,0.5); } ::-webkit-scrollbar-thumb { background: linear-gradient(180deg, #00d4ff44, #0066ff44); border-radius: 2px; } /* ══ CORNER DECORATIONS ══ */ #corner-tl, #corner-tr, #corner-bl, #corner-br { position: absolute; width: 20px; height: 20px; pointer-events: none; opacity: 0.5; } #corner-tl { top: 0; left: 0; border-top: 1px solid #00d4ff; border-left: 1px solid #00d4ff; } #corner-tr { top: 0; right: 0; border-top: 1px solid #00d4ff; border-right: 1px solid #00d4ff; } #corner-bl { bottom: 0; left: 0; border-bottom: 1px solid #00d4ff; border-left: 1px solid #00d4ff; } #corner-br { bottom: 0; right: 0; border-bottom: 1px solid #00d4ff; border-right: 1px solid #00d4ff; } """ # 🟢 ফিক্স: Gradio 6.0 অনুযায়ী Blocks এ css পাঠানো যাবে না with gr.Blocks(title="J.A.R.V.I.S — AI System") as demo: gr.HTML("""
Just A Rather Very Intelligent System
◈ NEURAL LINK ESTABLISHED ◈
""") status_bar = gr.Markdown("◈ Connecting to JARVIS core...", elem_id="status-bar") with gr.Column(elem_classes="chat-wrap"): gr.HTML('
') # 🟢 ফিক্স: Chatbot এ 'type="messages"' এর দরকার নেই (এখন এটাই ডিফল্ট) chatbot = gr.Chatbot( label="NEURAL INTERFACE", height=480, show_label=False ) with gr.Row(): msg_input = gr.Textbox( placeholder="▸ Command input — JARVIS-কে যা বলতে চাও লেখো...", show_label=False, scale=6, container=False, lines=1 ) send_btn = gr.Button("⚡ EXECUTE", variant="primary", scale=1) clear_btn = gr.Button("⊘ CLEAR", variant="secondary", scale=1) gr.HTML("""
◈ JARVIS AI SYSTEM v1.0  |  MULTI-BRAIN ENGINE  |  ENCRYPTED CHANNEL ◈
""") send_btn.click(chat_with_jarvis, inputs=[msg_input, chatbot], outputs=[chatbot, msg_input]) msg_input.submit(chat_with_jarvis, inputs=[msg_input, chatbot], outputs=[chatbot, msg_input]) clear_btn.click(lambda: ([], ""), outputs=[chatbot, msg_input]) demo.load(get_status, outputs=status_bar) timer = gr.Timer(30) timer.tick(get_status, outputs=status_bar) # 🟢 ফিক্স: Gradio 6.0 অনুযায়ী css এখানে পাঠাতে হবে if __name__ == "__main__": demo.launch(css=custom_css)