JARVIS-UI / app.py
nRTAGROUP's picture
Update app.py
af1587a verified
Raw
History Blame Contribute Delete
12.7 kB
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("""
<div id="jarvis-header">
<div id="jarvis-logo">JARVIS</div>
<div id="jarvis-tagline">Just A Rather Very Intelligent System</div>
</div>
<div id="jarvis-divider"><span>◈ NEURAL LINK ESTABLISHED ◈</span></div>
""")
status_bar = gr.Markdown("◈ Connecting to JARVIS core...", elem_id="status-bar")
with gr.Column(elem_classes="chat-wrap"):
gr.HTML('<div id="corner-tl"></div><div id="corner-tr"></div><div id="corner-bl"></div><div id="corner-br"></div>')
# 🟢 ফিক্স: 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("""
<div style="text-align:center; margin-top:16px; font-family:'Share Tech Mono',monospace;
font-size:0.6rem; color:rgba(0,212,255,0.2); letter-spacing:0.3em;">
◈ JARVIS AI SYSTEM v1.0 &nbsp;|&nbsp; MULTI-BRAIN ENGINE &nbsp;|&nbsp; ENCRYPTED CHANNEL ◈
</div>
""")
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)