defragmentation / app.py
cjo93's picture
Update app.py
f10675d verified
import gradio as gr
from defrag_engine import DefragDeepCompute
import os
from elevenlabs.client import ElevenLabs
# --- CONFIGURATION ---
# IMPORTANT: Add ELEVENLABS_API_KEY to your Space's 'Settings > Secrets'
ELEVEN_KEY = os.getenv("ELEVENLABS_API_KEY")
client = ElevenLabs(api_key=ELEVEN_KEY) if ELEVEN_KEY else None
# Initialize Defrag Engine
engine = DefragDeepCompute()
# --- AUDIO ENGINE ---
def generate_audio(text):
"""Generates audio via ElevenLabs and returns the file path."""
if not ELEVEN_KEY or not client:
return None # Silent mode if no key
try:
# Using a default calm voice (e.g., 'Rachel' or similar stable voice)
# You can swap this ID for a specific custom voice
audio_stream = client.generate(
text=text,
voice="Rachel",
model="eleven_monolingual_v1"
)
# Save to temp file for Gradio
save_path = "response.mp3"
with open(save_path, "wb") as f:
for chunk in audio_stream:
if chunk:
f.write(chunk)
return save_path
except Exception as e:
print(f"Audio Error: {e}")
return None
# --- CHAT LOGIC ---
def chat_interaction(user_message, history):
"""
1. Run Deep Compute on user input.
2. Generate System Admin response.
3. Update Visuals.
4. Generate Audio.
"""
# Hardcoded profile for prototype (In prod, fetch from session)
birth_data = { "name": "User", "year": 1990, "month": 1, "day": 1, "hour": 12, "minute": 0, "city": "Los Angeles", "country": "US" }
# 1. RUN DEEP COMPUTE
soul_log = engine.execute_defrag(birth_data, user_message)
vector = soul_log['computed_vector']
# 2. CONSTRUCT RESPONSE (The Translation Layer)
friction = vector['friction_level']
p_day = soul_log['hardware']['numerology']['personal_day']
element = soul_log['weather']['astro']['dominant_element'].title()
if friction == "CRITICAL":
prefix = "⚠️ HIGH INTERFERENCE DETECTED."
body = f"You are navigating a Resistance Pattern on Personal Day {p_day}. The {element} energy in your chart is currently blocked."
directive = "DIRECTIVE: Pause. Do not initiate. Allow the signal to clear."
else:
prefix = "✓ SIGNAL CLEAR."
body = f"Your internal rhythm is aligned. Supported by {element} Energy."
directive = "DIRECTIVE: Proceed with intent."
bot_response = f"{prefix}\n\n{body}\n\n**{directive}**"
# 3. GENERATE AUDIO
# We speak only the body and directive, not the technical prefix
audio_path = generate_audio(f"{body}. {directive}")
# 4. PREPARE VISUAL DATA
# [HexCode, Petals, Element, Stability, IsSpeaking]
visual_args = [
vector['visual_code'],
vector['visual_seed'],
vector['visual_element'],
0.3 if friction == "CRITICAL" else 1.0,
True # Trigger "Speaking" pulse in mandala
]
return bot_response, audio_path, visual_args
# --- THE UI ---
css = """
/* ====== DEFRAG.APP PREMIUM UI ====== */
* { margin: 0; padding: 0; box-sizing: border-box; }
body, html {
background: #0a0a0f;
color: #e0e4e8;
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
overflow: hidden;
}
/* Main Container - Mobile First */
.gradio-container {
max-width: 480px !important;
margin: 0 auto !important;
padding: 0 !important;
background: linear-gradient(135deg, #0a0a0f 0%, #141420 100%);
min-height: 100vh !important;
}
/* Mandala Visual Frame - Glassmorphism */
#monitor-frame {
width: 100%;
height: 350px;
border: none;
border-radius: 0;
background: radial-gradient(circle at 50% 50%, rgba(80, 120, 255, 0.08) 0%, rgba(10, 10, 15, 0.95) 70%);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
position: relative;
overflow: hidden;
box-shadow: inset 0 1px 0 rgba(255,255,255,0.03), 0 20px 60px rgba(0,0,0,0.4);
}
#monitor-frame::before {
content: '';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 300px;
height: 300px;
background: radial-gradient(circle, rgba(100, 150, 255, 0.15) 0%, transparent 70%);
filter: blur(40px);
animation: subtleGlow 4s ease-in-out infinite;
pointer-events: none;
}
@keyframes subtleGlow {
0%, 100% { opacity: 0.3; transform: translate(-50%, -50%) scale(1); }
50% { opacity: 0.6; transform: translate(-50%, -50%) scale(1.1); }
}
/* Audio Player - Hidden but Functional */
.audio-container {
display: none !important;
}
/* Chat Interface - ChatGPT Style Glassmorphism */
.chatbot-container {
background: rgba(20, 20, 32, 0.6) !important;
backdrop-filter: blur(30px) !important;
-webkit-backdrop-filter: blur(30px) !important;
border: 1px solid rgba(255,255,255,0.06) !important;
border-radius: 16px !important;
box-shadow: 0 8px 32px rgba(0,0,0,0.3), inset 0 1px 0 rgba(255,255,255,0.03) !important;
max-height: 450px !important;
overflow-y: auto !important;
padding: 20px !important;
}
.chat-window {
height: 450px !important;
overflow-y: auto !important;
scroll-behavior: smooth;
scrollbar-width: thin;
scrollbar-color: rgba(100,150,255,0.3) transparent;
}
.chat-window::-webkit-scrollbar {
width: 6px;
}
.chat-window::-webkit-scrollbar-track {
background: transparent;
}
.chat-window::-webkit-scrollbar-thumb {
background: rgba(100,150,255,0.3);
border-radius: 10px;
}
/* Message Bubbles - Premium Styling */
.message {
background: rgba(255,255,255,0.04) !important;
backdrop-filter: blur(10px);
border: 1px solid rgba(255,255,255,0.05);
border-radius: 12px;
padding: 12px 16px;
margin: 8px 0;
box-shadow: 0 4px 12px rgba(0,0,0,0.2);
}
.user-message {
background: linear-gradient(135deg, rgba(80,120,255,0.15), rgba(100,150,255,0.1)) !important;
border: 1px solid rgba(100,150,255,0.2);
}
.bot-message {
background: rgba(255,255,255,0.03) !important;
border: 1px solid rgba(255,255,255,0.06);
}
/* Input Box - Glassmorphism */
textarea, input[type="text"] {
background: rgba(30,30,45,0.8) !important;
border: 1px solid rgba(100,150,255,0.2) !important;
border-radius: 14px !important;
color: #e0e4e8 !important;
padding: 14px 18px !important;
font-size: 15px !important;
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
box-shadow: inset 0 2px 8px rgba(0,0,0,0.2), 0 4px 16px rgba(0,0,0,0.1) !important;
transition: all 0.3s ease;
}
textarea:focus, input[type="text"]:focus {
outline: none !important;
border-color: rgba(100,150,255,0.5) !important;
box-shadow: inset 0 2px 8px rgba(0,0,0,0.2), 0 0 0 3px rgba(100,150,255,0.1), 0 4px 20px rgba(100,150,255,0.2) !important;
}
/* Buttons - Premium Glassmorphism */
button {
background: linear-gradient(135deg, rgba(80,120,255,0.2), rgba(100,150,255,0.15)) !important;
border: 1px solid rgba(100,150,255,0.3) !important;
border-radius: 12px !important;
color: #e0e4e8 !important;
padding: 12px 24px !important;
font-weight: 500 !important;
backdrop-filter: blur(20px) !important;
-webkit-backdrop-filter: blur(20px) !important;
box-shadow: 0 4px 16px rgba(100,150,255,0.15), inset 0 1px 0 rgba(255,255,255,0.1) !important;
transition: all 0.3s ease !important;
cursor: pointer !important;
}
button:hover {
background: linear-gradient(135deg, rgba(80,120,255,0.3), rgba(100,150,255,0.25)) !important;
border-color: rgba(100,150,255,0.5) !important;
box-shadow: 0 6px 24px rgba(100,150,255,0.25), inset 0 1px 0 rgba(255,255,255,0.15) !important;
transform: translateY(-1px);
}
button:active {
transform: translateY(0);
box-shadow: 0 2px 8px rgba(100,150,255,0.2) !important;
}
/* Labels - Subtle Typography */
label {
color: rgba(224, 228, 232, 0.7) !important;
font-size: 13px !important;
font-weight: 500 !important;
text-transform: uppercase !important;
letter-spacing: 1.2px !important;
margin-bottom: 8px !important;
}
/* Remove Gradio Footer */
footer { display: none !important; }
/* Mobile Responsive */
@media (max-width: 480px) {
#monitor-frame { height: 300px; }
.chat-window { height: 400px !important; }
}
/* Subtle Animations */
@keyframes fadeIn {
from { opacity: 0; transform: translateY(10px); }
to { opacity: 1; transform: translateY(0); }
}
.message {
animation: fadeIn 0.3s ease;
}
"""
with gr.Blocks(title="DEFRAG NODE") as demo:
# 1. VISUAL LAYER (Top)
with open("mandala_component.html", "r") as f:
html_content = f.read()
# Container for the mandala
mandala_view = gr.HTML(html_content, elem_id="monitor-frame")
# 2. AUDIO LAYER (Hidden Player - Autoplay via JS if possible, or manual click)
audio_player = gr.Audio(label="System Voice", visible=True, interactive=False)
# 3. CHAT LAYER (Bottom)
chatbot = gr.Chatbot(label="DEFRAG // LOG", elem_classes="chat-window")
msg = gr.Textbox(placeholder="Input System Status...", show_label=False)
# Hidden Data Bridge
visual_data = gr.JSON(visible=False)
# --- EVENT WIRING ---
def respond(message, chat_history):
# Run logic
bot_msg, audio, viz_data = chat_interaction(message, chat_history)
# Update history
chat_history.append((message, bot_msg))
return "", chat_history, audio, viz_data
msg.submit(respond, [msg, chatbot], [msg, chatbot, audio_player, visual_data])
# JS Bridge to update Canvas
js_bridge = """
(args) => {
if (window.hexa) {
// args = [hex, petals, elem, stability, speaking]
window.hexa.updateParams(args[0], args[1], args[2], args[3], args[4]);
// Stop speaking pulse after 5 seconds
setTimeout(() => {
window.hexa.updateParams(args[0], args[1], args[2], args[3], false);
}, 5000);
}
return args;
}
"""
visual_data.change(None, [visual_data], None, js=js_bridge)
if __name__ == "__main__":
demo.launch(theme=gr.themes.Base(), css=css)