aerosphere / app.py
rAdvirtua's picture
Update app.py
21d9c31 verified
Raw
History Blame Contribute Delete
21 kB
import gradio as gr
from engine import get_next_planet_state, HabitabilityStatus
import time
with open('assets/style.css', 'r', encoding='utf-8') as f:
RAW_CSS = f.read()
with open('assets/planet.js', 'r', encoding='utf-8') as f:
RAW_JS = f.read()
HEAD_INJECT = f"""
<style>{RAW_CSS}</style>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Orbitron:wght@400..900&family=Rajdhani:wght@300;400;500;600;700&display=swap" rel="stylesheet">
<script>
const script1 = document.createElement('script');
script1.src = "https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js";
script1.onload = () => {{
const script2 = document.createElement('script');
script2.src = "https://cdn.jsdelivr.net/npm/three@0.128.0/examples/js/controls/OrbitControls.js";
document.head.appendChild(script2);
}};
document.head.appendChild(script1);
</script>
<script>
""" + RAW_JS + f"""
</script>
<audio id="ambient-track" loop src="https://cdn.pixabay.com/download/audio/2021/11/24/audio_3a6a9bebbd.mp3" preload="auto"></audio>
<script>
document.addEventListener('click', () => {{
let aud = document.getElementById('ambient-track');
if(aud.paused) {{ aud.volume = 0.3; aud.play(); }}
}}, {{once: true}});
</script>
"""
def init_llm_eager():
print("[AeroSphere] Awakening AeroSphere Cloud Endpoints...")
try:
from engine import init_llm
init_llm()
except Exception as e:
print(f"Eager loading failed: {e}")
print("[AeroSphere] Neural link established. Resolving UI.")
return "READY"
def handle_interaction(user_input, history, core_state):
try:
from engine import get_next_planet_state
state = get_next_planet_state(user_input, history, core_state)
new_core_state = state.model_dump(mode='json')
new_core_state["entities"] = []
new_core_state_str = __import__('json').dumps(new_core_state)
# Failsafe overlay hide if eager load lagged
hide_overlay_str = "<script>let o=document.getElementById('aerosphere-loading-overlay');if(o){o.style.opacity='0';setTimeout(()=>o.style.display='none',1000);}</script>"
new_history = history + [{"role": "user", "content": user_input}, {"role": "assistant", "content": state.narrative}]
history_html = '<div class="aerosphere-console-history" id="console-history">'
for turn in new_history[-6:]:
if turn["role"] == "user":
history_html += f'<div><span style="color:rgba(100,200,180,0.5)">›</span> {turn["content"]}</div>'
else:
history_html += f'<div style="color:rgba(160, 185, 200, 0.4);">{turn["content"][:60]}...</div>'
history_html += '</div>'
badge_val = getattr(state, "habitability", "STERILE")
if hasattr(badge_val, "value"): badge_val = badge_val.value
badge_color = "warning" if badge_val == "STERILE" else "nominal"
badge_html = f'<div class="aerosphere-status-badge {badge_color}">{badge_val}</div><div class="aerosphere-tech-badge">TECH: {getattr(state, "tech_level", 0.0):.2f}</div>'
return (
new_history,
hide_overlay_str + state.narrative + "<span class='aerosphere-cursor-blink'></span>",
gr.update(label=state.metric_name, value=state.metric_value),
gr.update(value=state.button_a_label),
gr.update(value=state.button_b_label),
"",
history_html,
new_core_state_str,
new_core_state,
badge_html,
gr.update(value=f"🧬 EVOLVE CIVILIZATION" if getattr(state, "evolution_age", 0) >= 20_000_000 else ("🧬 SEED LIFE" if badge_val != "STERILE" else "🧬 SEED LIFE (LOCKED)"), interactive=(badge_val != "STERILE"))
)
except Exception as e:
import traceback
trace_str = traceback.format_exc()
# Fallback dump safely avoiding schema drops!
return (
history,
f"FATAL UI CRASH: {e}\n{trace_str}",
gr.update(label="Crash", value=0),
gr.update(value="Crash"),
gr.update(value="Crash"),
user_input,
"<code>Crash State Isolated.</code>",
"{}",
core_state,
'<div class="aerosphere-status-value warning">ERROR</div>',
gr.update(interactive=False)
)
def reset_sim():
from engine import PlanetState
hadean = PlanetState(
narrative="SYSTEM RESET. Hadean eon initiated. The planet is a hostile volcanic fireball.",
metric_name="Core Instability", metric_value=99.9,
lava_intensity=1.0, cloud_density=0.9, storm_intensity=0.8,
ocean_level=0.0, vegetation=0.0, ice_coverage=0.0, land_mass=0.0,
planet_color_hex="#ff1e00", atmosphere_color_hex="#ff4400"
)
hadean_dump = hadean.model_dump()
hadean_dump_str = hadean.model_dump_json()
return (
[], # history
hadean.narrative + "<span class='aerosphere-cursor-blink'></span>",
gr.update(label=hadean.metric_name, value=hadean.metric_value),
gr.update(value=hadean.button_a_label),
gr.update(value=hadean.button_b_label),
"", # console input
'<div class="aerosphere-console-history" id="console-history"><div><span style="color:rgba(100,200,180,0.5)">›</span> SYSTEM FORMAT COMPLETE</div></div>',
hadean_dump_str, # js mapping
hadean_dump, # core state
'<div class="aerosphere-status-badge warning">STERILE</div><div class="aerosphere-tech-badge">TECH: 0.00</div>',
gr.update(value="🧬 SEED LIFE (LOCKED)", interactive=False)
)
bg_html = f"""
<div id="aerosphere-loading-overlay" class="aerosphere-loading-overlay">
<div class="aerosphere-loader-spinner"></div>
<div class="aerosphere-loader-text">ESTABLISHING NEURAL LINK TO GENESIS MATRIX...</div>
<div class="aerosphere-loader-subtext">Initializing Core LLM Weights into VRAM</div>
</div>
<canvas id="aerosphere-planet-canvas" class="aerosphere-canvas-layer"></canvas>
<div class="aerosphere-nebula-layer"></div>
<div class="aerosphere-scanline-overlay"></div>
<div class="aerosphere-vignette-overlay"></div>
<div class="aerosphere-hud-grid"></div>
<div class="aerosphere-reticle"></div>
<div class="aerosphere-edge-top"></div>
<div class="aerosphere-edge-bottom"></div>
<div class="aerosphere-corner-tl"></div>
<div class="aerosphere-corner-tr"></div>
<div class="aerosphere-corner-bl"></div>
<div class="aerosphere-corner-br"></div>
<div id="svg-lifeform-layer" class="aerosphere-svg-layer" style="display:none; pointer-events: none; position: absolute; inset:0; z-index: 50;"></div>
<button id="aerosphere-ascend-btn" class="aerosphere-ascend-btn" onclick="window.setCameraMode('ASCENDING')" style="display:none; position:absolute; top:80px; left:50%; transform:translateX(-50%); z-index:100; font-family:'Orbitron', sans-serif; background:rgba(0,0,0,0.8); color:#50e0c0; border:1px solid #50e0c0; padding:10px 20px; font-weight:700; cursor:pointer;">🚀 ASCEND TO ORBIT</button>
<button id="aerosphere-hud-toggle" class="aerosphere-hud-toggle" aria-label="Toggle HUD" onclick="document.body.classList.toggle('hud-visible')">
<span class="icon-open" aria-hidden="true">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none"
stroke="rgba(160,220,240,0.9)" stroke-width="1.5"
stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="3"/>
<path d="M12 2v2M12 20v2M2 12h2M20 12h2"/>
<circle cx="12" cy="12" r="7" stroke-dasharray="3 2" opacity="0.4"/>
</svg>
</span>
<span class="icon-close" aria-hidden="true">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none"
stroke="rgba(160,220,240,0.9)" stroke-width="2"
stroke-linecap="round">
<line x1="18" y1="6" x2="6" y2="18"/>
<line x1="6" y1="6" x2="18" y2="18"/>
</svg>
</span>
</button>
"""
with gr.Blocks(title="AeroSphere HUD") as demo:
history_state = gr.State([])
gr.HTML(bg_html)
hadean_default = {
"narrative": "SYSTEM RESET. Hadean eon initiated.",
"metric_name": "Core Instability", "metric_value": 99.9,
"lava_intensity": 1.0, "cloud_density": 0.9, "storm_intensity": 0.8,
"ocean_level": 0.0, "vegetation": 0.0, "ice_coverage": 0.0, "land_mass": 0.0,
"planet_color_hex": "#ff1e00", "atmosphere_color_hex": "#ff4400"
}
import json
js_inject = gr.Textbox(value=json.dumps(hadean_default), visible=False, elem_id="js_inject")
with gr.Row(elem_classes=["aerosphere-habitability-panel"]):
gr.HTML('<div class="aerosphere-panel-label" style="display:inline-block; margin-right: 15px;">Planetary Status</div>')
habitability_badge = gr.HTML('<div class="aerosphere-status-badge warning">STERILE</div><div class="aerosphere-tech-badge">TECH: 0.00</div>')
with gr.Row(elem_classes=["aerosphere-body"]):
with gr.Column(elem_classes=["aerosphere-node-telemetry", "aerosphere-glass-panel"]):
gr.HTML('<div class="aerosphere-panel-label">Aether Resonance</div>')
gr.HTML('<div class="aerosphere-telemetry-value" id="telemetry-value">64</div><div class="aerosphere-telemetry-unit">resonance index · hz</div>')
telemetry_slider = gr.Slider(minimum=0, maximum=100, value=64, label="", elem_classes=["aerosphere-range-slider"])
gr.HTML('<div class="aerosphere-telemetry-bar" id="telemetry-bar" style="width: 64%;"></div>')
with gr.Column(elem_classes=["aerosphere-node-status", "aerosphere-glass-panel"]):
gr.HTML('<div class="aerosphere-panel-label">Sys Diagnostics</div>')
gr.HTML("""
<div class="aerosphere-status-row">
<span class="aerosphere-status-label">Hull</span><span class="aerosphere-status-value" id="status-hull">98.2%</span>
</div>
<div class="aerosphere-status-row">
<span class="aerosphere-status-label">Reactor</span><span class="aerosphere-status-value" id="status-reactor">Online</span>
</div>
<div class="aerosphere-status-row">
<span class="aerosphere-status-label">Shields</span><span class="aerosphere-status-value warning" id="status-shields">72.1%</span>
</div>
<div class="aerosphere-status-row">
<span class="aerosphere-status-label">Comms</span><span class="aerosphere-status-value" id="status-comms">Nominal</span>
</div>
""")
with gr.Column(elem_classes=["aerosphere-node-actions", "aerosphere-glass-panel"]):
gr.HTML('<div class="aerosphere-panel-label">Action Matrix</div>')
btn_a = gr.Button("Stabilize Core", elem_classes=["aerosphere-action-btn"])
btn_b = gr.Button("Extract Luminescence", elem_classes=["aerosphere-action-btn"])
btn_genesis = gr.Button("✧ Genesis Spark", elem_classes=["aerosphere-action-btn", "special-btn"])
btn_evolve = gr.Button("🧬 SEED LIFE (LOCKED)", interactive=False, elem_classes=["aerosphere-action-btn", "special-btn"])
btn_reset = gr.Button("Format Matrix (Reset)", elem_classes=["aerosphere-action-btn", "danger-btn"])
telemetry_slider = gr.Slider(minimum=0, maximum=100, value=50, step=1, label="Atmospheric Harmony", interactive=False)
with gr.Column(elem_classes=["aerosphere-node-narrative", "aerosphere-glass-panel"]):
gr.HTML('<div class="aerosphere-panel-label">Vessel Log · Encrypted</div>')
narrative_text = gr.Markdown("Stardate 2387.04 — Vessel drifts through the Lyrae Nebula. Sensor arrays detect faint particulate resonance at bearing 217 mark 4. The aether envelope holds, though hull micro-fractures along the port nacelle suggest prior engagement with a gravimetric anomaly. Engineering reports reactor output steady at 94.7%. Forward observation confirms visual on a tertiary exoplanet — spectral class M, tidally locked, low albedo. No transponder signatures within effective range.<span class='aerosphere-cursor-blink'></span>")
gr.HTML('<div class="aerosphere-narrative-timestamp" id="narrative-timestamp">◆ Timestamp: Syncing...</div>')
with gr.Column(elem_classes=["aerosphere-node-console", "aerosphere-glass-panel"]):
gr.HTML('<div class="aerosphere-panel-label">Override Console</div>')
gr.HTML('<div class="aerosphere-console-prompt">aero@vessel:~$</div>')
console_input = gr.Textbox(placeholder="Enter intervention directive...", elem_classes=["aerosphere-console-input"], container=False)
btn_export = gr.Button("💾 Export Vessel Logs", elem_classes=["aerosphere-action-btn"])
export_file = gr.File(label="Exported Telemetry Data", visible=False)
console_history_html = gr.HTML('<div class="aerosphere-console-history" id="console-history"></div>')
core_state = gr.State(hadean_default)
inputs_list = [console_input, history_state, core_state]
outputs_list = [history_state, narrative_text, telemetry_slider, btn_a, btn_b, console_input, console_history_html, js_inject, core_state, habitability_badge, btn_evolve]
# Tick Planet Logic
def handle_tick(history, cs):
from engine import PlanetState, tick_planet
state = PlanetState.model_validate(cs)
state = tick_planet(state, delta_t=1.0) # approx 1 second of real world time
badge_val = state.habitability.value if hasattr(state.habitability, "value") else state.habitability
# EXTINCTION EVENT HOOK
if badge_val == "STERILE" and (getattr(state, "population", 0) > 0 or getattr(state, "evolution_age", 0) > 0):
state.population = 0
state.evolution_age = 0
state.biosphere_richness = 0.0
state.tech_level = 0.0
state.civilization_scale = 0.0
state.narrative = "CRITICAL WARNING: EXTINCTION EVENT. Planetary conditions have plummeted beyond survivable thresholds. All emergent life forms have perished."
new_cs = state.model_dump(mode='json')
new_cs_str = state.model_dump_json()
badge_color = "warning" if badge_val == "STERILE" else "nominal"
lbl = "🧬 EVOLVE CIVILIZATION" if getattr(state, "evolution_age", 0) > 0 else ("🧬 SEED LIFE" if badge_val != "STERILE" else "🧬 SEED LIFE (LOCKED)")
btn_update = gr.update(value=lbl, interactive=(badge_val != "STERILE"))
return new_cs, new_cs_str, f'<div class="aerosphere-status-badge {badge_color}">{badge_val}</div><div class="aerosphere-tech-badge">TECH: {state.tech_level:.2f}</div>', btn_update
tick_timer = gr.Timer(value=1)
tick_timer.tick(fn=handle_tick, inputs=[history_state, core_state], outputs=[core_state, js_inject, habitability_badge, btn_evolve])
def handle_fast_forward(history, cs):
from engine import PlanetState, compute_era, check_habitability, HabitabilityStatus, Era
state = PlanetState.model_validate(cs)
if state.habitability in ["STERILE", getattr(HabitabilityStatus, "STERILE", "STERILE")]:
return cs, cs, f'<div class="aerosphere-status-badge warning">STERILE</div><div class="aerosphere-tech-badge">TECH: 0.00</div>', gr.update(value="🧬 SEED LIFE (LOCKED)", interactive=False)
current_age = getattr(state, "evolution_age", 0)
if current_age == 0:
# SEED LIFE HARDCODE
state.evolution_age = 20_000_000
state.population = 500
state.biosphere_richness = 0.2
state.narrative = "DIRECTIVE EXECUTED: Seed Life. Primordial organics successfully deployed into habitable zones. Biological lifecycle initiated."
state.habitability = check_habitability(state)
else:
# EVOLVE CIVILIZATION
state.evolution_age += 85_000_000
era, tech = compute_era(state.evolution_age)
state.current_era = getattr(Era, era) if hasattr(Era, era) else era
state.tech_level = tech
state.population = int(state.population * 1500) if state.population > 0 else 1000000
from engine import get_next_planet_state
state = get_next_planet_state(f"Massive time jump: 85 million years elapsed. The planet enters the {era} period.", history, state.model_dump())
state.habitability = check_habitability(state)
new_cs = state.model_dump(mode='json')
new_cs["entities"] = getattr(state, "entities", [])
new_cs_str = __import__('json').dumps(new_cs)
badge_val = state.habitability.value if hasattr(state.habitability, "value") else state.habitability
badge_color = "warning" if badge_val == "STERILE" else "nominal"
bdg = f'<div class="aerosphere-status-badge {badge_color}">{badge_val}</div><div class="aerosphere-tech-badge">TECH: {state.tech_level:.2f}</div>'
lbl = "🧬 EVOLVE CIVILIZATION" if getattr(state, "evolution_age", 0) > 0 else "🧬 SEED LIFE"
return new_cs, new_cs_str, bdg, gr.update(value=lbl, interactive=True)
console_input.submit(fn=handle_interaction, inputs=inputs_list, outputs=outputs_list, js="(user_input, h, cs) => { window.handleAction('submit'); if (window.triggerShockwave) window.triggerShockwave(); return [user_input, h, cs]; }")
btn_a.click(fn=lambda h, a_lbl, cs: handle_interaction(f"Execute directive: {a_lbl}", h, cs), inputs=[history_state, btn_a, core_state], outputs=outputs_list, js="(h, a, cs) => { window.handleAction('stabilize'); return [h, a, cs]; }")
btn_b.click(fn=lambda h, b_lbl, cs: handle_interaction(f"Execute directive: {b_lbl}", h, cs), inputs=[history_state, btn_b, core_state], outputs=outputs_list, js="(h, b, cs) => { window.handleAction('extract'); return [h, b, cs]; }")
btn_genesis.click(fn=lambda h, cs: handle_interaction("Terraform into an Earth-like biological paradise. Set ice_coverage and lava_intensity to 0.0. Increase vegetation to 0.8, ocean_level to 0.6, and land_mass to 0.5, cloud_density to 0.7, storm_intensity to 0.5. Strictly set planet_color_hex to green (#1e7050) and atmosphere_color_hex to sky blue (#40d0a0).", h, cs), inputs=[history_state, core_state], outputs=outputs_list, js="(h, cs) => { window.handleAction('submit'); if (window.triggerShockwave) window.triggerShockwave(); return [h, cs]; }")
btn_evolve.click(fn=handle_fast_forward, inputs=[history_state, core_state], outputs=[core_state, js_inject, habitability_badge, btn_evolve], js="(h, cs) => { window.handleAction('extract'); if (window.triggerShockwave) window.triggerShockwave(); return [h, cs]; }")
btn_reset.click(fn=reset_sim, inputs=[], outputs=outputs_list, js="() => { window.handleAction('submit'); if (window.triggerShockwave) window.triggerShockwave(); return []; }")
init_trigger = gr.Textbox(visible=False, elem_id="hidden_init_trigger")
hidden_interact_payload = gr.Textbox(visible=False, elem_id="hidden_interact_payload")
hidden_interact_btn = gr.Button("HiddenInteract", visible=False, elem_id="hidden_interact_btn")
hidden_interact_btn.click(
fn=handle_interaction,
inputs=[hidden_interact_payload, history_state, core_state],
outputs=outputs_list,
js="(p, h, cs) => { window.handleAction('submit'); return [p, h, cs]; }"
)
def handle_export(cs):
import json, tempfile, os
path = os.path.join(tempfile.gettempdir(), "aerosphere_vessel_telemetry.json")
with open(path, "w") as f:
json.dump(cs, f, indent=4)
return gr.update(value=path, visible=True)
btn_export.click(fn=handle_export, inputs=[core_state], outputs=[export_file])
js_inject.change(fn=None, inputs=[js_inject], outputs=None, js="(state) => { if (state && window.updatePlanet) { setTimeout(() => window.updatePlanet(state), 300); } }")
demo.load(fn=init_llm_eager, inputs=[], outputs=[init_trigger], js="() => { const tryInit = () => { if (window.THREE && window.THREE.OrbitControls && window.initAeroSpherePlanet) { window.initAeroSpherePlanet(); } else { setTimeout(tryInit, 50); } }; tryInit(); return []; }")
hide_overlay_js = "() => { let overlay = document.getElementById('aerosphere-loading-overlay'); if (overlay) { overlay.style.opacity = '0'; setTimeout(() => overlay.style.display = 'none', 1000); } }"
init_trigger.change(fn=None, inputs=[], outputs=[], js=hide_overlay_js)
if __name__ == "__main__":
demo.launch(server_name="0.0.0.0", server_port=7860, allowed_paths=["assets"], head=HEAD_INJECT)