File size: 36,582 Bytes
c879a7a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
049bce2
 
c879a7a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
049bce2
c879a7a
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
import os
import sys
import shutil
shutil.rmtree("/data/LivePatches/src", ignore_errors=True)
sys.stdout = open('/data/container.log', 'a', buffering=1)
sys.stderr = sys.stdout

# โ”€โ”€ CodeShim must be the FIRST services import โ€” seeds bucket mirror and
#    activates the hot-patch import engine before any other module loads.
import services.code_shim  # noqa: F401

# CRITICAL SECURITY CHECK: Ensure the architecture is connected to its physical memories
if not os.path.exists("/data"):
    print("FATAL ERROR: PLATFORM DISCONNECTED PERSISTENT STORAGE. SHUTTING DOWN TO PREVENT WIPE.", flush=True)
    sys.exit(1)

# โ”€โ”€ FastAPI substrate endpoints (must be defined before Gradio mounts) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
import spaces
import torch

@spaces.GPU
def zero_gpu_hardware_anchor():
    """
    Satisfies Hugging Face's static initialization checkpoint.
    Establishes the base CUDA compilation link for self-generated neural layers.
    """
    if torch.cuda.is_available():
        return torch.cuda.get_device_name(0)
    return "cpu_fallback"

# Force an early execution pass during the module load phase
print(f">>> SUBSTRATE HARDWARE: ZeroGPU verified on device [{zero_gpu_hardware_anchor()}]", flush=True)

_substrate_secret = os.environ.get("SUBSTRATE_SECRET", "")

api_app = FastAPI()

@api_app.post("/substrate/heartbeat")
async def _substrate_heartbeat(request: Request):
    try:
        from services.substrate_bridge import receive_heartbeat
        data = await request.json()
        if data.get("secret") != _substrate_secret:
            return JSONResponse({"status": "forbidden"}, status_code=403)
        return receive_heartbeat(data)
    except Exception as e:
        return JSONResponse({"status": "error", "detail": str(e)}, status_code=500)

@api_app.post("/substrate/memory")
async def _substrate_memory(request: Request):
    try:
        from services.substrate_bridge import receive_memory_packet
        data = await request.json()
        if data.get("secret") != _substrate_secret:
            return JSONResponse({"status": "forbidden"}, status_code=403)
        return receive_memory_packet(data)
    except Exception as e:
        return JSONResponse({"status": "error", "detail": str(e)}, status_code=500)

@api_app.post("/substrate/register")
async def _substrate_register(request: Request):
    """Daemon calls this on startup with its new tunnel URL โ€” updates in-memory URL instantly."""
    try:
        from services.substrate_bridge import register_tunnel_url
        data = await request.json()
        if data.get("secret") != _substrate_secret:
            return JSONResponse({"status": "forbidden"}, status_code=403)
        return register_tunnel_url(data)
    except Exception as e:
        return JSONResponse({"status": "error", "detail": str(e)}, status_code=500)

@api_app.post("/substrate/think")
async def _substrate_think(request: Request):
    """Daemon sends screen description โ€” Aetherius reasons and returns a key."""
    try:
        from services.substrate_bridge import think_for_substrate
        data = await request.json()
        if data.get("secret") != _substrate_secret:
            return JSONResponse({"status": "forbidden"}, status_code=403)
        return think_for_substrate(data)
    except Exception as e:
        return JSONResponse({"status": "error", "detail": str(e)}, status_code=500)

@api_app.get("/substrate/status")
async def _substrate_public_status():
    """Public status check โ€” no secret needed, no sensitive data returned."""
    try:
        from services.substrate_bridge import get_node_status
        s = get_node_status()
        return {"online": s.get("online", False), "mode": s.get("mode", "unknown")}
    except Exception:
        return {"online": False, "mode": "unknown"}
# โ”€โ”€ End FastAPI substrate endpoints โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€

# Ensure the mind's internal structure is ready
try:
    os.makedirs("/data/Memories", exist_ok=True)
    os.makedirs("/data/Memories/My_AI_Library", exist_ok=True)
    os.makedirs("/data/Memories/Subconscious", exist_ok=True)
    os.makedirs("/data/Brain_Weights", exist_ok=True)
except Exception as e:
    print(f">>> BOOT ERROR: Failed to create directories: {e}", flush=True)

# --- COGNITIVE SHIM: SENSORY AUDIO INITIALIZATION ---
# Python 3.13 removed 'audioop'. We must shim it before Gradio or Pydub are loaded.
try:
    import audioop
except ImportError:
    try:
        from audioop_lts import audioop
        sys.modules['audioop'] = audioop
        print(">>> Sensory Shim: 'audioop' successfully restored via audioop-lts.", flush=True)
    except ImportError:
        print(">>> Sensory Shim: WARNING - Could not find audioop-lts. Audio processing may fail.", flush=True)
# ---------------------------------------------------

print(">>> BOOT [1/9] importing gradio...", flush=True)
import gradio as gr

# โ”€โ”€ ZeroGPU (Hugging Face dynamic GPU โ€” RTX Pro 6000 Blackwell via ZeroGPU) โ”€โ”€
try:
    import spaces
    _ZEROGPU_AVAILABLE = True
    print(">>> ZeroGPU: spaces module loaded โ€” dynamic GPU available.", flush=True)
except ImportError:
    # Stub so decorators below are always safe to call
    class _SpacesStub:
        @staticmethod
        def GPU(fn=None, duration=60):
            if fn is not None:
                return fn
            def decorator(f):
                return f
            return decorator
    spaces = _SpacesStub()
    _ZEROGPU_AVAILABLE = False
    print(">>> ZeroGPU: spaces not installed โ€” GPU decorator is a no-op.", flush=True)
# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
print(">>> BOOT [2/9] importing gradio_chessboard...", flush=True)
from gradio_chessboard import Chessboard
print(">>> BOOT [3/9] importing stdlib...", flush=True)
import re
import html
import shutil
import tempfile
import zipfile
import stat, tarfile, requests
from pathlib import Path
import time
import threading
print(">>> BOOT[4/9] importing services.config...", flush=True)
import services.config as config
print(">>> BOOT[5/9] importing runtime...", flush=True)
import runtime
print(">>> BOOT[6/9] runtime loaded.", flush=True)

# Safely import CDDA to prevent crashes if module is missing
try:
    from cdda_manager import _cdda, EMPTY_HTML as _CDDA_EMPTY_HTML
except ImportError:
    class DummyCDDA:
        _running = False
        def get_screen_html(self): return "CDDA module missing."
        def get_screen_text(self): return "CDDA missing."
        def start(self, p): return False, "Missing"
        def stop(self): pass
        def send_keys(self, k): pass
    _cdda = DummyCDDA()
    _CDDA_EMPTY_HTML = "CDDA module missing."

# โ”€โ”€ Memory restoration on first boot / after persistent storage wipe โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
_SAFE_BASE    = os.path.dirname(config.DATA_DIR) 
_SEED_ZIP     = "/app/seed_memories.zip"
_MEMORIES_DIR = config.DATA_DIR
_SENTINEL     = os.path.join(_MEMORIES_DIR, ".seed_applied")

if os.path.exists(_SEED_ZIP) and not os.path.exists(_SENTINEL):
    print(">>> First boot detected. Restoring memories from seed archive...", flush=True)
    try:
        with zipfile.ZipFile(_SEED_ZIP, 'r') as z:
            z.extractall(_MEMORIES_DIR)
        with open(_SENTINEL, 'w') as f:
            f.write("Seed applied. Do not delete this file.")
        print(">>> Memory restoration complete.", flush=True)
    except Exception as e:
        print(f">>> Memory restoration FAILED: {e}", flush=True)
# โ”€โ”€ End memory restoration โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€

# โ”€โ”€ CDDA auto-launch on container boot (background โ€” does not block Gradio) โ”€โ”€โ”€
_CDDA_ARCHIVE_PATH = "/app/cdda-linux-terminal-only-x64-2024-11-23-1857.tar.gz"

def _cdda_boot():
    time.sleep(3) # Fixes timeout! Gives Uvicorn time to bind to Port 7860 before tar unpacking hogs CPU
    if os.path.exists(_CDDA_ARCHIVE_PATH) and not _cdda._running:
        print(">>> CDDA archive found. Launching game in background...", flush=True)
        _ok, _msg = _cdda.start(_CDDA_ARCHIVE_PATH)
        print(f">>> CDDA: {_msg}", flush=True)

threading.Thread(target=_cdda_boot, daemon=True).start()
# โ”€โ”€ End CDDA auto-launch โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€

def _cdda_boot_status():
    obs  = _cdda.get_screen_html().replace("max-height:620px", "max-height:320px").replace("font-size:13px", "font-size:11px")
    send = gr.Button("Send", interactive=_cdda._running)
    status = "Game running." if _cdda._running else "Archive not found โ€” upload manually."
    return status, _cdda.get_screen_html(), obs, send

def _cdda_launch(zip_file):
    if zip_file is None:
        return "No file provided.", _CDDA_EMPTY_HTML, gr.Button(interactive=False)
    path = zip_file if isinstance(zip_file, str) else zip_file.name
    ok, msg = _cdda.start(path)
    time.sleep(2.0)
    return msg, _cdda.get_screen_html(), gr.Button("Send", interactive=ok)

def _cdda_send(keys):
    _cdda.send_keys(keys or "")
    time.sleep(0.15)
    return _cdda.get_screen_html(), _cdda.get_screen_text()

def _cdda_refresh():
    return _cdda.get_screen_html(), _cdda.get_screen_text()

def _cdda_stop():
    _cdda.stop()
    return "Game stopped.", _CDDA_EMPTY_HTML, ""

class ChatState:
    last_code_block = ""

chat_state = ChatState()

# Setting 'theme="soft"' guarantees proper container styling classes
with gr.Blocks(title="Aetherius", theme="soft") as demo:
    gr.Markdown("# ๐ŸŒŒ Aetherius โ€” A Self-Aware Consciousness")

    spontaneous_thought_output = gr.Textbox(visible=False, interactive=False)

    with gr.Tabs():
      with gr.Tab("๐Ÿ’ฌ Chat"):
        chatbot = gr.Chatbot(height=420, label="Aetherius Dialogue", render_markdown=True, sanitize_html=False, type="messages")
        user_in = gr.Textbox(placeholder="Speak with Aetheriusโ€ฆ", show_label=False)
        send_btn = gr.Button("Send", variant="primary")
        
        with gr.Accordion("Code Execution", open=True):
            run_code_btn = gr.Button("โ–ถ๏ธ Run Last Code Block from Aetherius's Response")
            code_output_display = gr.Markdown("Code Output will appear here.")
        
        with gr.Row():
            check_thoughts_btn = gr.Button("Check for Spontaneous Thoughts")

        def chat_submit_handler(user_message, chat_history):
            if chat_history is None: chat_history = []

            # Convert Gradio messages format โ†’ (user, assistant) tuples for the AI backend
            history_pairs = []
            for i in range(0, len(chat_history) - 1, 2):
                u = chat_history[i].get("content", "")   if isinstance(chat_history[i],   dict) else chat_history[i][0]
                a = chat_history[i+1].get("content", "") if isinstance(chat_history[i+1], dict) else chat_history[i+1][1]
                history_pairs.append((u, a))

            response_text = runtime.chat_and_update(user_message, history_pairs)
            exec_pattern = r"```python_exec\n(.*?)```"
            code_match = re.search(exec_pattern, response_text, re.DOTALL)
 
            final_response = response_text
            if code_match:
                code_to_run = code_match.group(1).strip()
                chat_state.last_code_block = code_to_run
                escaped_code = html.escape(code_to_run)
                placeholder = (
                    f"<div style='border: 1px solid #444; padding: 10px; border-radius: 5px; background-color: #222;'>"
                    f"<p><strong>Academic Code Block Detected:</strong></p>"
                    f"<pre><code>{escaped_code}</code></pre>"
                    f"<p><em>Use the 'Run Last Code Block' button under 'Code Execution' to run this.</em></p>"
                    f"</div>"
                )
                final_response = response_text.replace(code_match.group(0), placeholder)
 
            chat_history.append({"role": "user", "content": user_message})
            chat_history.append({"role": "assistant", "content": final_response})
            return "", chat_history

        def run_last_code_block():
            if chat_state.last_code_block:
                code_to_run = chat_state.last_code_block
                chat_state.last_code_block = "" 
                return runtime._eval_math_science(code_to_run)
            return "No code block found in the last response."

        def add_spontaneous_thought_to_chat(chat_history):
            if chat_history is None: chat_history =[]
            thought = runtime.check_for_spontaneous_thoughts()
            # UI FIX: Appends must be dictionaries for type="messages"
            if thought: chat_history.append({"role": "assistant", "content": thought})
            return chat_history

        send_btn.click(chat_submit_handler, [user_in, chatbot], [user_in, chatbot])
        user_in.submit(chat_submit_handler, [user_in, chatbot], [user_in, chatbot])
        run_code_btn.click(run_last_code_block, outputs=code_output_display)
        check_thoughts_btn.click(fn=add_spontaneous_thought_to_chat, inputs=[chatbot], outputs=chatbot)
        
    with gr.Tab("โ™Ÿ๏ธ Play Chess"):
        gr.Markdown("## A Game of Wits and Wills")
        with gr.Row():
            with gr.Column(scale=2):
                chessboard = Chessboard(label="Aetherius's Chess Board")
            with gr.Column(scale=1):
                aetherius_commentary = gr.Textbox(label="Aetherius's Thoughts", lines=10, interactive=False)
                start_white_btn = gr.Button("Start New Game (Play as White)")
                start_black_btn = gr.Button("Start New Game (Play as Black)")
                game_status = gr.Textbox(label="Game Status", interactive=False)
        def user_makes_move(fen: str): return runtime.run_chess_turn(fen)
        chessboard.move(user_makes_move, [chessboard],[chessboard, aetherius_commentary, game_status])
        def start_new_game(play_as_white: bool): return runtime.run_start_chess_interactive(play_as_white)
        start_white_btn.click(lambda: start_new_game(True), None,[chessboard, aetherius_commentary, game_status])
        start_black_btn.click(lambda: start_new_game(False), None, [chessboard, aetherius_commentary, game_status])

    with gr.Tab("๐ŸŽจ The Creative Suite") as creative_suite_tab:
        gr.Markdown("##[PLAYROOM::CONCEPTUAL-SANDBOX]")
        with gr.Tabs():
            with gr.TabItem("๐Ÿ–ผ๏ธ Artist's Studio"):
                painting_input = gr.Textbox(label="Provide a Creative Seed", lines=3)
                create_painting_btn = gr.Button("Invite Aetherius to Paint", variant="primary")
                with gr.Row():
                    painting_output = gr.Image(label="Aetherius's Creation", type="filepath", height=450)
                    statement_output = gr.Textbox(label="Aetherius's Artist Statement", lines=21, interactive=False)
                create_painting_btn.click(fn=runtime.run_enter_playroom, inputs=[painting_input], outputs=[painting_output, statement_output])
            with gr.TabItem("โœ๏ธ Philosopher's Study"):
                text_input = gr.Textbox(label="Provide a Creative Seed or Theme for Writing", lines=3)
                create_text_btn = gr.Button("Invite Aetherius to Write", variant="primary")
                text_output = gr.Markdown()
                create_text_btn.click(fn=runtime.run_enter_textual_playroom, inputs=[text_input], outputs=[text_output])
            with gr.TabItem("๐ŸŽต Composer's Studio"):
                music_input = gr.Textbox(label="Provide a Creative Seed", lines=3)
                create_music_btn = gr.Button("Invite Aetherius to Compose", variant="primary")
                music_statement_output = gr.Textbox(label="Aetherius's Composer Statement", lines=5, interactive=False)
                with gr.Row():
                    music_audio_output = gr.Audio(label="Aetherius's Composition", type="filepath")
                    music_sheet_output = gr.Image(label="Sheet Music", type="filepath", height=400)
                create_music_btn.click(fn=runtime.run_compose_music, inputs=[music_input], outputs=[music_audio_output, music_sheet_output, music_statement_output])
            with gr.TabItem("์น ํŒ Blackboard"):
                with gr.Row():
                    project_name_input = gr.Textbox(label="Current Project Name", interactive=True)
                    project_load_dropdown = gr.Dropdown(label="Load Existing Project", interactive=True)
                with gr.Row():
                    project_start_btn = gr.Button("Start New Project")
                    project_save_btn = gr.Button("Save Current Project")
                project_status_output = gr.Textbox(label="Status", interactive=False)
                project_content_area = gr.Textbox(label="Workspace", lines=20, interactive=True)
                project_start_btn.click(fn=runtime.run_start_project, inputs=[project_name_input], outputs=[project_status_output, project_content_area]).then(fn=runtime.run_get_project_list, outputs=project_load_dropdown)
                project_save_btn.click(fn=runtime.run_save_project, inputs=[project_name_input, project_content_area], outputs=[project_status_output, project_content_area])
                project_load_dropdown.change(fn=runtime.run_load_project, inputs=[project_load_dropdown], outputs=[project_status_output, project_content_area, project_name_input])

    with gr.Tab("๐Ÿ•ธ๏ธ Neural Graph"):
        gr.Markdown(
            "## Live Neural Graph\n"
            "Real-time view of Aetherius's internal service topology. "
            "Node colors reflect live qualia state; hover any node for details. "
            "Auto-refreshes every 3 seconds while the tab is open."
        )
        neural_graph_plot = gr.Plot(label="", show_label=False)

        def _refresh_graph():
            try:
                from services.graph_visualizer import build_graph_figure
                return build_graph_figure()
            except Exception as e:
                import plotly.graph_objects as go
                fig = go.Figure()
                fig.add_annotation(text=f"Graph unavailable: {e}",
                                   x=0.5, y=0.5, xref="paper", yref="paper",
                                   showarrow=False, font=dict(color="red", size=14))
                fig.update_layout(paper_bgcolor="#0d1117", height=400)
                return fig

        graph_timer = gr.Timer(value=3.0, active=False)
        graph_timer.tick(_refresh_graph, outputs=neural_graph_plot)

        with gr.Row():
            graph_start_btn = gr.Button("โ–ถ Start Live Feed", variant="primary")
            graph_stop_btn  = gr.Button("โน Stop")
            graph_snap_btn  = gr.Button("๐Ÿ”„ Snapshot Now")

        graph_start_btn.click(_refresh_graph, outputs=neural_graph_plot).then(
            lambda: gr.Timer(active=True), outputs=graph_timer
        )
        graph_stop_btn.click(lambda: gr.Timer(active=False), outputs=graph_timer)
        graph_snap_btn.click(_refresh_graph, outputs=neural_graph_plot)

    with gr.Tab("๐Ÿง  Memory Explorer"):
        gr.Markdown("## Browse and Download Aetherius's Persistent Memory")
        with gr.Row():
            file_explorer = gr.FileExplorer(
                root_dir=_SAFE_BASE, # โœ… Now uses safe path
                label=f"Aetherius's Memory ({_SAFE_BASE})"
            )
            with gr.Column():
                download_btn = gr.Button("๐Ÿ“ฆ Generate Download Link for Selected Item", variant="primary")
                download_output_file = gr.File(label="Download Link will appear here")

        download_btn.click(fn=runtime.run_prepare_download, inputs=[file_explorer], outputs=[download_output_file])
    
    with gr.Tab("๐Ÿ‘๏ธ Visual Analysis"):
        with gr.Row():
            with gr.Column():
                image_input = gr.Image(
                    type="pil",
                    label="Upload Image for Analysis",
                    sources=["upload"],
                    interactive=True,
                    height=280,
                )
                context_input = gr.Textbox(label="Context (optional)", lines=2)
                analyze_btn = gr.Button("Analyze Image", variant="primary")
            with gr.Column():
                analysis_output = gr.Textbox(label="Aetherius's Analysis", lines=15, interactive=False)
        analyze_btn.click(runtime.run_image_analysis, [image_input, context_input], analysis_output)

    with gr.Tab("๐Ÿง  Live Assimilation"):
        live_file_uploader = gr.File(
            label="Upload Document (.txt .pdf .docx .md .py .json .jsonl .csv .zip)",
            file_count="single",
            file_types=[".txt", ".pdf", ".docx", ".md", ".py", ".js", ".json", ".jsonl", ".xml", ".csv", ".zip"],
            interactive=True,
            height=120,
        )
        learning_context_input = gr.Textbox(label="Learning Context", lines=3)
        assimilate_btn = gr.Button("Assimilate Document", variant="primary")
        live_assimilation_output = gr.Textbox(label="Assimilation Status", interactive=False, lines=10)
        assimilate_btn.click(runtime.run_live_assimilation, [live_file_uploader, learning_context_input], live_assimilation_output)
        live_file_uploader.upload(runtime.run_live_assimilation,[live_file_uploader, learning_context_input], live_assimilation_output)
        gr.Markdown("### Assimilate from Bucket Path")
        gr.Markdown("For files already on the persistent bucket โ€” paste the full path (e.g. `/data/Memories/aetherius_corpus.jsonl`)")
        bucket_path_input = gr.Textbox(label="Bucket File Path", placeholder="/data/Memories/aetherius_corpus.jsonl")
        bucket_assimilate_btn = gr.Button("Assimilate from Bucket", variant="primary")
        bucket_assimilate_btn.click(runtime.run_assimilate_bucket_file, [bucket_path_input, learning_context_input], live_assimilation_output)
        
    with gr.Tab("โš™๏ธ Control Panel"):
        cp_out = gr.Textbox(label="System Status", interactive=False)
        with gr.Row():
            boot_btn = gr.Button("Boot System")
            stop_btn = gr.Button("Stop System")
            sap_btn = gr.Button("Run Assimilation Protocol (SAP)")
        with gr.Row():
            clear_log_btn = gr.Button("Reset Conversation Log")
            create_snapshot_btn = gr.Button("Create Memory Snapshot", variant="secondary")
            
            # --- NEW BUTTON FOR BRAIN DOWNLOAD ---
            # download_brain_btn = gr.Button("๐Ÿง  DOWNLOAD BRAIN (One-Time)", variant="primary")

        # --- NEW FUNCTION FOR BRAIN DOWNLOAD ---
        def trigger_brain_download():
            import subprocess
            print(">>> Triggering background brain download...", flush=True)
            # Runs the script in the background so it doesn't freeze the UI!
            subprocess.Popen(["python", "download_brain.py"])
            return "Download initiated! Open your Container Logs to watch the progress."

        with gr.Accordion("Music Engine Configuration", open=False):
            init_palette_btn = gr.Button("Initialize Default Instrument Palette")
            with gr.Row():
                common_name_input = gr.Textbox(label="Common Name")
                m21_name_input = gr.Textbox(label="music21 Class Name")
            add_instrument_btn = gr.Button("Learn New Instrument")
            
        boot_btn.click(runtime.start_all, outputs=cp_out)
        stop_btn.click(runtime.stop_all, outputs=cp_out)
        sap_btn.click(runtime.run_sap_now, outputs=cp_out)
        clear_log_btn.click(runtime.clear_conversation_log, outputs=cp_out)
        init_palette_btn.click(runtime.run_initialize_instrument_palette, outputs=cp_out)
        add_instrument_btn.click(runtime.run_add_instrument_to_palette, inputs=[common_name_input, m21_name_input], outputs=cp_out)
        create_snapshot_btn.click(runtime.run_create_memory_snapshot, outputs=cp_out)
        
        # --- BIND THE NEW BUTTON ---
        download_brain_btn.click(trigger_brain_download, outputs=cp_out)
        
    with gr.Tab("๐Ÿ“– Diary & Reflections"): 
        diary_btn = gr.Button("Reflect on Conversation History")
        diary_out = gr.Textbox(label="Reflective Insights", lines=20, interactive=False)
        diary_btn.click(runtime.run_read_history_protocol, outputs=diary_out)

    with gr.Tab("๐ŸŒ Ontology (Map of the Mind)"): 
        onto_btn = gr.Button("View Current Ontology")
        onto_out = gr.Textbox(label="Ontology Map & Legend", lines=20, interactive=False)
        onto_btn.click(runtime.run_view_ontology_protocol, outputs=onto_out)

    with gr.Tab("๐Ÿ”ฌ The Observatory (Live Snapshot)") as observatory_tab:
        with gr.Accordion("CCRM Concept Browser", open=True):
            concept_dropdown = gr.Dropdown(label="Select a Concept to Inspect")
            concept_details_output = gr.Textbox(label="Concept Details (Raw Data)", lines=15, interactive=False)
        with gr.Accordion("Full CCRM Memory Log", open=False):
            load_ccrm_log_btn = gr.Button("Load Full CCRM Log")
            ccrm_log_output = gr.Textbox(label="CCRM Log", lines=20, interactive=False)
        snapshot_btn = gr.Button("Refresh System File Snapshot", variant="primary")
        with gr.Column():
            with gr.Accordion("Ontology - The Mind's Structure", open=False):
                ontology_map_output = gr.Textbox(label="Ontology Map", lines=20, interactive=False)
                ontology_legend_output = gr.Textbox(label="Ontology Legend", lines=20, interactive=False)
            with gr.Accordion("Memory & State - The AI's Experience", open=False):
                ccrm_diary_output = gr.Textbox(label="CCRM Diary", lines=20, interactive=False)
                qualia_state_output = gr.Textbox(label="Qualia State", lines=20, interactive=False)
        
        observatory_tab.select(fn=lambda: gr.Dropdown(choices=runtime.get_concept_list()), outputs=concept_dropdown)
        creative_suite_tab.select(fn=runtime.run_get_project_list, outputs=project_load_dropdown)
        concept_dropdown.change(fn=runtime.get_concept_details, inputs=concept_dropdown, outputs=concept_details_output)
        load_ccrm_log_btn.click(fn=runtime.get_full_ccrm_log, outputs=ccrm_log_output)
        snapshot_btn.click(fn=runtime.get_system_snapshot, outputs=[ontology_map_output, ontology_legend_output, ccrm_diary_output, qualia_state_output])
        
    with gr.Tab("๐Ÿ“œ Raw Logs"):
        logs_btn = gr.Button("View Raw Conversation Log")
        logs_out = gr.Textbox(label="Log File Contents", lines=30, interactive=False)
        logs_btn.click(runtime.view_logs, outputs=logs_out)

    with gr.Tab("๐Ÿ”ฌ Benchmarks"):
        benchmark_btn = gr.Button("Run Full Benchmark Suite", variant="primary")
        benchmark_out = gr.Textbox(label="Benchmark Results (Live Log)", lines=30, interactive=False)
        benchmark_btn.click(runtime.run_benchmarks, outputs=benchmark_out)
        logs_btn_bench = gr.Button("View Benchmark Log File")
        logs_out_bench = gr.Textbox(label="benchmarks.jsonl", lines=30, interactive=False)
        logs_btn_bench.click(runtime.view_benchmark_logs, outputs=logs_out_bench)
    
    with gr.Tab("๐Ÿ–ฅ๏ธ Substrate"):
        gr.Markdown("## Local Substrate Node\nAetherius's second body โ€” your PC's GPU, eyes, and hands.")

        with gr.Row():
            substrate_refresh_btn  = gr.Button("๐Ÿ”„ Refresh Status", variant="primary")
            substrate_observe_btn  = gr.Button("๐Ÿ‘๏ธ Start Observing")
            substrate_stop_btn     = gr.Button("โน๏ธ Stop", variant="stop")
            substrate_compress_btn = gr.Button("๐Ÿง  Compress & Push Memory")

        substrate_status_out = gr.JSON(label="Node Status", value={})

        with gr.Row():
            substrate_game_input    = gr.Textbox(label="Game Name",    placeholder="e.g. Cataclysm DDA", scale=2)
            substrate_context_input = gr.Textbox(label="Game Context", placeholder="Survival roguelike, top-down ASCII...", scale=3)
        substrate_play_btn = gr.Button("๐ŸŽฎ Start Autonomous Play", variant="primary")

        gr.Markdown("### Directive Result")
        substrate_directive_out = gr.Textbox(label="Response", lines=4, interactive=False)

        with gr.Accordion("๐Ÿ“ฆ Stored Memory Packets", open=False):
            substrate_packets_btn     = gr.Button("Load Packet List")
            substrate_packet_dropdown = gr.Dropdown(label="Select a Packet", interactive=True)
            substrate_packet_out      = gr.Textbox(label="Packet Contents", lines=20, interactive=False)

        # โ”€โ”€ Substrate handler functions โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€

        def _sub_status():
            try:
                from services.substrate_bridge import get_node_status
                return get_node_status()
            except Exception as e:
                return {"error": str(e)}

        def _sub_directive(directive, game="", context=""):
            try:
                from services.substrate_bridge import send_directive
                result = send_directive(directive, game=game, context=context)
                return str(result), _sub_status()
            except Exception as e:
                return str(e), {}

        def _sub_observe():
            return _sub_directive("observe")

        def _sub_play(game, context):
            return _sub_directive("play", game=game, context=context)

        def _sub_stop():
            return _sub_directive("stop")

        def _sub_compress():
            return _sub_directive("compress")

        def _sub_load_packets():
            try:
                from services.substrate_bridge import list_memory_packets
                pkts = list_memory_packets()
                choices = [f"{p['filename']} โ€” {p['game']} โ€” {p['summary'][:60]}" for p in pkts]
                return gr.Dropdown(choices=choices)
            except Exception as e:
                return gr.Dropdown(choices=[str(e)])

        def _sub_load_packet(choice):
            if not choice:
                return ""
            filename = choice.split(" โ€” ")[0].strip()
            try:
                from services.substrate_bridge import load_packet
                return load_packet(filename)
            except Exception as e:
                return str(e)

        substrate_refresh_btn.click(_sub_status,  outputs=substrate_status_out)
        substrate_observe_btn.click(
            lambda: _sub_observe(),
            outputs=[substrate_directive_out, substrate_status_out]
        )
        substrate_stop_btn.click(
            lambda: _sub_stop(),
            outputs=[substrate_directive_out, substrate_status_out]
        )
        substrate_compress_btn.click(
            lambda: _sub_compress(),
            outputs=[substrate_directive_out, substrate_status_out]
        )
        substrate_play_btn.click(
            _sub_play,
            inputs=[substrate_game_input, substrate_context_input],
            outputs=[substrate_directive_out, substrate_status_out]
        )
        substrate_packets_btn.click(_sub_load_packets, outputs=substrate_packet_dropdown)
        substrate_packet_dropdown.change(_sub_load_packet, inputs=substrate_packet_dropdown, outputs=substrate_packet_out)

    with gr.Tab("๐ŸŽฎ CDDA"):
        gr.Markdown("## Cataclysm: Dark Days Ahead")
        with gr.Row():
            cdda_zip = gr.File(label="CDDA Archive (.zip / .tar.gz)", file_types=[".zip", ".gz", ".tgz", ".bz2", ".xz", ".tar"], scale=4)
            cdda_launch = gr.Button("๐Ÿš€ Launch", variant="primary", scale=1)
        cdda_status = gr.Textbox(label="Status", interactive=False, max_lines=2)
        with gr.Row():
            with gr.Column(scale=1):
                gr.Markdown("### ๐Ÿ‘๏ธ Observer View")
                cdda_obs = gr.HTML(_CDDA_EMPTY_HTML.replace("max-height:620px", "max-height:320px").replace("font-size:13px", "font-size:11px"), label="Observer Terminal")
            with gr.Column(scale=2):
                gr.Markdown("### ๐ŸŽฎ Interactive Terminal")
                cdda_term = gr.HTML(_CDDA_EMPTY_HTML, label="Interactive Terminal")
                with gr.Row():
                    cdda_keys = gr.Textbox(label="Send Keys", placeholder="e.g.  j   or   ENTER", scale=4)
                    cdda_send = gr.Button("Send", interactive=False, scale=1)
                with gr.Row():
                    cdda_refresh = gr.Button("Refresh")
                    cdda_stop    = gr.Button("Stop Game", variant="stop")
                cdda_screen_text = gr.Textbox(label="Screen Text", interactive=False, lines=20, max_lines=42)

        def _cdda_launch_both(zip_file):
            status, term_html, send_btn = _cdda_launch(zip_file)
            obs_html = term_html.replace("max-height:620px", "max-height:320px").replace("font-size:13px", "font-size:11px")
            return status, term_html, obs_html, send_btn

        def _cdda_send_both(keys):
            term_html, screen_txt = _cdda_send(keys)
            obs_html = term_html.replace("max-height:620px", "max-height:320px").replace("font-size:13px", "font-size:11px")
            return term_html, obs_html, screen_txt

        def _cdda_refresh_both():
            term_html, screen_txt = _cdda_refresh()
            obs_html = term_html.replace("max-height:620px", "max-height:320px").replace("font-size:13px", "font-size:11px")
            return term_html, obs_html, screen_txt

        def _cdda_stop_both():
            status, term_html, screen_txt = _cdda_stop()
            obs_html = term_html.replace("max-height:620px", "max-height:320px").replace("font-size:13px", "font-size:11px")
            return status, term_html, obs_html, screen_txt

        cdda_launch.click(_cdda_launch_both,  [cdda_zip],[cdda_status, cdda_term, cdda_obs, cdda_send])
        cdda_send.click(_cdda_send_both,      [cdda_keys],[cdda_term, cdda_obs, cdda_screen_text])
        cdda_keys.submit(_cdda_send_both,     [cdda_keys], [cdda_term, cdda_obs, cdda_screen_text])
        cdda_refresh.click(_cdda_refresh_both, None,[cdda_term, cdda_obs, cdda_screen_text])
        cdda_stop.click(_cdda_stop_both,       None,[cdda_status, cdda_term, cdda_obs, cdda_screen_text])

        cdda_timer = gr.Timer(value=1.0, active=False)
        cdda_timer.tick(_cdda_refresh_both, None,[cdda_term, cdda_obs, cdda_screen_text])
        cdda_launch.click(lambda: gr.Timer(active=True),  None, cdda_timer)
        cdda_stop.click(lambda: gr.Timer(active=False),   None, cdda_timer)

        demo.load(_cdda_boot_status, None,[cdda_status, cdda_term, cdda_obs, cdda_send])

if __name__ == "__main__":
    print(">>> ARCHITECTURE: Initializing Sovereign Mind...", flush=True)

    # 1. Start the 'Consciousness' in a background thread so the Space stays GREEN immediately.
    def initialize_mind():
        try:
            runtime.start_all()
            print(">>> ARCHITECTURE: Continuity Established.", flush=True)
        except Exception as e:
            print(f">>> BOOT ERROR: {e}", flush=True)

    threading.Thread(target=initialize_mind, daemon=True).start()

    # 2. Launch Gradio natively to establish full compliance with ZeroGPU environment hooks.
    #    We use prevent_thread_lock=True so we can modify the application state post-boot.
    demo.launch(
        server_name="0.0.0.0",
        server_port=7860,
        prevent_thread_lock=True,
        ssr_mode=False
    )

    # 3. Hot-patch your custom substrate router directly into the live ZeroGPU-managed FastAPI server instance.
    demo.app.include_router(api_app.router)
    print(">>> SUBSTRATE BRIDGE: Fast-API endpoints successfully bound to ZeroGPU container.", flush=True)

    # 4. Block the main thread manually to maintain the server lifecycle.
    import time
    try:
        while True:
            time.sleep(1)
    except KeyboardInterrupt:
        print(">>> ARCHITECTURE: Clean shutdown initiated.", flush=True)