Update app.py
Browse files
app.py
CHANGED
|
@@ -1656,10 +1656,15 @@ def launch_ui(bootstrap_instance: "Bootstrap"):
|
|
| 1656 |
if hive_instance.lite_mode:
|
| 1657 |
# Lite mode: direct, non-streaming response.
|
| 1658 |
reply = hive_instance.chat(sanitized_m, eff, current_user_id)
|
| 1659 |
-
messages_hist.append({"role": "assistant", "content": reply})
|
| 1660 |
yield messages_hist, gr.Textbox(value="", interactive=True)
|
| 1661 |
else:
|
| 1662 |
# Full mode uses the DialogueManager for a streaming response.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1663 |
full_reply = ""
|
| 1664 |
messages_hist.append({"role": "assistant", "content": ""}) # Placeholder for the stream
|
| 1665 |
try:
|
|
@@ -1744,17 +1749,21 @@ def launch_ui(bootstrap_instance: "Bootstrap"):
|
|
| 1744 |
def get_hive_instance():
|
| 1745 |
global HIVE_INSTANCE
|
| 1746 |
|
| 1747 |
-
# If the full hive is ready, ensure we are using it.
|
| 1748 |
if bootstrap_instance.hive_ready.is_set():
|
| 1749 |
-
if HIVE_INSTANCE is None or HIVE_INSTANCE.lite_mode:
|
| 1750 |
HIVE_INSTANCE = bootstrap_instance.hive_instance
|
| 1751 |
print("[UI] Full Hive instance attached.")
|
| 1752 |
return HIVE_INSTANCE
|
| 1753 |
|
| 1754 |
# Otherwise, use the lite instance.
|
| 1755 |
if HIVE_INSTANCE is None:
|
| 1756 |
-
|
| 1757 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1758 |
return HIVE_INSTANCE
|
| 1759 |
|
| 1760 |
|
|
@@ -1781,11 +1790,15 @@ def launch_ui(bootstrap_instance: "Bootstrap"):
|
|
| 1781 |
gr.Markdown("✅ Camera ready." if video_ready else "Camera disabled or not found.", visible=True),
|
| 1782 |
gr.Image(interactive=video_ready), # video_out
|
| 1783 |
)
|
| 1784 |
-
demo.load(wait_for_voice_features, None, [voice_status_md, ptt_audio_in, ptt_transcript, ptt_transcribe_btn, ptt_chat_btn, vocal_chat_btn, enroll_audio, enroll_btn, who_btn, camera_status_md, video_out])
|
| 1785 |
def stream_video():
|
| 1786 |
"""Streams video frames from the VideoService to the UI."""
|
| 1787 |
hive_instance = get_hive_instance()
|
| 1788 |
-
if not
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1789 |
yield None
|
| 1790 |
return
|
| 1791 |
|
|
@@ -1793,7 +1806,7 @@ def launch_ui(bootstrap_instance: "Bootstrap"):
|
|
| 1793 |
while not video_service.stop_event.is_set():
|
| 1794 |
frame = video_service.get_frame()
|
| 1795 |
if frame is not None:
|
| 1796 |
-
yield frame
|
| 1797 |
time.sleep(0.05) # ~20 fps
|
| 1798 |
demo.load(stream_video, None, video_out)
|
| 1799 |
|
|
@@ -2021,17 +2034,21 @@ def launch_ui(bootstrap_instance: "Bootstrap"):
|
|
| 2021 |
return msg
|
| 2022 |
mem_compress_btn.click(lambda: compress_memory(get_hive_instance()), [], [compress_status])
|
| 2023 |
|
| 2024 |
-
def do_hotpatch(patch_json): # type: ignore
|
| 2025 |
"""
|
| 2026 |
Applies a runtime hotpatch from the admin console.
|
| 2027 |
"""
|
|
|
|
|
|
|
| 2028 |
try: patch=json.loads(patch_json)
|
| 2029 |
except Exception as e: return f"Invalid JSON: {e}"
|
| 2030 |
-
|
| 2031 |
-
|
| 2032 |
-
|
| 2033 |
-
|
| 2034 |
-
|
|
|
|
|
|
|
| 2035 |
|
| 2036 |
# This state will hold the session hash for guest users.
|
| 2037 |
session_id_state = gr.State(None)
|
|
@@ -2135,13 +2152,21 @@ class Bootstrap:
|
|
| 2135 |
|
| 2136 |
def full_init_task():
|
| 2137 |
"""Initializes the full Hive instance."""
|
| 2138 |
-
|
| 2139 |
-
|
| 2140 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2141 |
|
| 2142 |
def self_optimize_task():
|
| 2143 |
"""Kicks off the self-optimization process after full initialization."""
|
| 2144 |
self.hive_ready.wait() # Wait for the full hive to be ready
|
|
|
|
|
|
|
|
|
|
| 2145 |
if self.hive_instance and hasattr(self.hive_instance, 'selfopt'):
|
| 2146 |
print("[Bootstrap] Triggering initial self-optimization cycle.")
|
| 2147 |
self.hive_instance.selfopt.trigger_once()
|
|
@@ -2149,8 +2174,13 @@ class Bootstrap:
|
|
| 2149 |
def voice_init_task():
|
| 2150 |
"""Initializes voice models in a separate thread."""
|
| 2151 |
asr_thread.join()
|
| 2152 |
-
tts_thread.join()
|
| 2153 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2154 |
|
| 2155 |
# --- Launch Background Initialization Tasks ---
|
| 2156 |
tasks = {
|
|
@@ -2171,14 +2201,22 @@ class Bootstrap:
|
|
| 2171 |
|
| 2172 |
def _init_lite_core(self):
|
| 2173 |
"""Initializes the fast, responsive lite core."""
|
| 2174 |
-
|
| 2175 |
-
|
| 2176 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2177 |
|
| 2178 |
def soft_restart(self):
|
| 2179 |
"""Performs a hot-reload of the application logic without restarting the process."""
|
| 2180 |
print("[Bootstrap] Performing soft restart (hot-reload)...")
|
| 2181 |
self.hive_ready.clear()
|
|
|
|
|
|
|
| 2182 |
if self.hive_instance:
|
| 2183 |
self.hive_instance.module_manager.stop_all()
|
| 2184 |
if self.app and hasattr(self.app, 'close'): # type: ignore
|
|
|
|
| 1656 |
if hive_instance.lite_mode:
|
| 1657 |
# Lite mode: direct, non-streaming response.
|
| 1658 |
reply = hive_instance.chat(sanitized_m, eff, current_user_id)
|
| 1659 |
+
messages_hist.append({"role": "assistant", "content": reply or "[No response from model]"})
|
| 1660 |
yield messages_hist, gr.Textbox(value="", interactive=True)
|
| 1661 |
else:
|
| 1662 |
# Full mode uses the DialogueManager for a streaming response.
|
| 1663 |
+
if not hasattr(hive_instance, 'dialogue_manager'):
|
| 1664 |
+
error_msg = "Dialogue Manager not available. Full core may still be initializing."
|
| 1665 |
+
messages_hist.append({"role": "assistant", "content": error_msg})
|
| 1666 |
+
yield messages_hist, gr.Textbox(value="", interactive=True)
|
| 1667 |
+
return
|
| 1668 |
full_reply = ""
|
| 1669 |
messages_hist.append({"role": "assistant", "content": ""}) # Placeholder for the stream
|
| 1670 |
try:
|
|
|
|
| 1749 |
def get_hive_instance():
|
| 1750 |
global HIVE_INSTANCE
|
| 1751 |
|
| 1752 |
+
# If the full hive is ready, ensure we are using it, and it's a valid instance.
|
| 1753 |
if bootstrap_instance.hive_ready.is_set():
|
| 1754 |
+
if bootstrap_instance.hive_instance is not None and (HIVE_INSTANCE is None or HIVE_INSTANCE.lite_mode):
|
| 1755 |
HIVE_INSTANCE = bootstrap_instance.hive_instance
|
| 1756 |
print("[UI] Full Hive instance attached.")
|
| 1757 |
return HIVE_INSTANCE
|
| 1758 |
|
| 1759 |
# Otherwise, use the lite instance.
|
| 1760 |
if HIVE_INSTANCE is None:
|
| 1761 |
+
if bootstrap_instance.lite_core_ready.is_set() and bootstrap_instance.hive_lite_instance is not None:
|
| 1762 |
+
HIVE_INSTANCE = bootstrap_instance.hive_lite_instance
|
| 1763 |
+
print("[UI] Using Lite Hive instance while full core initializes.")
|
| 1764 |
+
else:
|
| 1765 |
+
# Neither lite nor full is ready.
|
| 1766 |
+
return None
|
| 1767 |
return HIVE_INSTANCE
|
| 1768 |
|
| 1769 |
|
|
|
|
| 1790 |
gr.Markdown("✅ Camera ready." if video_ready else "Camera disabled or not found.", visible=True),
|
| 1791 |
gr.Image(interactive=video_ready), # video_out
|
| 1792 |
)
|
| 1793 |
+
demo.load(wait_for_voice_features, None, [voice_status_md, ptt_audio_in, ptt_transcript, ptt_transcribe_btn, ptt_chat_btn, vocal_chat_btn, enroll_audio, enroll_btn, who_btn, camera_status_md, video_out], show_progress="hidden")
|
| 1794 |
def stream_video():
|
| 1795 |
"""Streams video frames from the VideoService to the UI."""
|
| 1796 |
hive_instance = get_hive_instance()
|
| 1797 |
+
if not (
|
| 1798 |
+
hive_instance and not hive_instance.lite_mode and
|
| 1799 |
+
hasattr(hive_instance, 'video_service') and hive_instance.video_service and
|
| 1800 |
+
CFG["VIDEO_ENABLED"]
|
| 1801 |
+
):
|
| 1802 |
yield None
|
| 1803 |
return
|
| 1804 |
|
|
|
|
| 1806 |
while not video_service.stop_event.is_set():
|
| 1807 |
frame = video_service.get_frame()
|
| 1808 |
if frame is not None:
|
| 1809 |
+
yield cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
|
| 1810 |
time.sleep(0.05) # ~20 fps
|
| 1811 |
demo.load(stream_video, None, video_out)
|
| 1812 |
|
|
|
|
| 2034 |
return msg
|
| 2035 |
mem_compress_btn.click(lambda: compress_memory(get_hive_instance()), [], [compress_status])
|
| 2036 |
|
| 2037 |
+
def do_hotpatch(mode, role, patch_json): # type: ignore
|
| 2038 |
"""
|
| 2039 |
Applies a runtime hotpatch from the admin console.
|
| 2040 |
"""
|
| 2041 |
+
if not is_admin(mode, role):
|
| 2042 |
+
return "Hotpatching is an admin-only feature."
|
| 2043 |
try: patch=json.loads(patch_json)
|
| 2044 |
except Exception as e: return f"Invalid JSON: {e}"
|
| 2045 |
+
|
| 2046 |
+
hive_instance = get_hive_instance()
|
| 2047 |
+
if hive_instance.lite_mode or not hasattr(hive_instance, 'overlay'):
|
| 2048 |
+
return "Hotpatching is not available in Lite Mode."
|
| 2049 |
+
ok, msg = hive_instance.overlay.patch(patch, actor_role=role)
|
| 2050 |
+
return msg
|
| 2051 |
+
hotpatch_apply.click(do_hotpatch,[mode_state, role_state, hotpatch_patch],[hotpatch_status])
|
| 2052 |
|
| 2053 |
# This state will hold the session hash for guest users.
|
| 2054 |
session_id_state = gr.State(None)
|
|
|
|
| 2152 |
|
| 2153 |
def full_init_task():
|
| 2154 |
"""Initializes the full Hive instance."""
|
| 2155 |
+
try:
|
| 2156 |
+
llm_thread.join() # Wait for the LLM to be loaded
|
| 2157 |
+
get_hive_instance(lite=False) # This will replace the lite instance with the full one
|
| 2158 |
+
self.hive_ready.set()
|
| 2159 |
+
except Exception as e:
|
| 2160 |
+
print(f"[ERROR] Failed to initialize Full Hive Core: {e}")
|
| 2161 |
+
traceback.print_exc()
|
| 2162 |
+
# Do not set hive_ready on failure, so app stays in lite mode.
|
| 2163 |
|
| 2164 |
def self_optimize_task():
|
| 2165 |
"""Kicks off the self-optimization process after full initialization."""
|
| 2166 |
self.hive_ready.wait() # Wait for the full hive to be ready
|
| 2167 |
+
if not self.hive_instance or self.hive_instance.lite_mode:
|
| 2168 |
+
print("[Bootstrap] Skipping self-optimization as full core is not available.")
|
| 2169 |
+
return
|
| 2170 |
if self.hive_instance and hasattr(self.hive_instance, 'selfopt'):
|
| 2171 |
print("[Bootstrap] Triggering initial self-optimization cycle.")
|
| 2172 |
self.hive_instance.selfopt.trigger_once()
|
|
|
|
| 2174 |
def voice_init_task():
|
| 2175 |
"""Initializes voice models in a separate thread."""
|
| 2176 |
asr_thread.join()
|
| 2177 |
+
tts_thread.join() # Wait for both ASR and TTS threads
|
| 2178 |
+
try:
|
| 2179 |
+
# Additional checks can be added here if needed
|
| 2180 |
+
self.voice_ready.set()
|
| 2181 |
+
except Exception as e:
|
| 2182 |
+
print(f"[ERROR] Voice initialization failed: {e}")
|
| 2183 |
+
traceback.print_exc()
|
| 2184 |
|
| 2185 |
# --- Launch Background Initialization Tasks ---
|
| 2186 |
tasks = {
|
|
|
|
| 2201 |
|
| 2202 |
def _init_lite_core(self):
|
| 2203 |
"""Initializes the fast, responsive lite core."""
|
| 2204 |
+
try:
|
| 2205 |
+
# This now correctly creates the initial lite instance via the global function
|
| 2206 |
+
get_hive_instance(lite=True, caps=self.caps)
|
| 2207 |
+
self.lite_core_ready.set()
|
| 2208 |
+
except Exception as e:
|
| 2209 |
+
print(f"[ERROR] Failed to initialize Lite Hive Core: {e}")
|
| 2210 |
+
traceback.print_exc()
|
| 2211 |
+
# Still set the event so the UI doesn't hang, but it will show an error.
|
| 2212 |
+
self.lite_core_ready.set()
|
| 2213 |
|
| 2214 |
def soft_restart(self):
|
| 2215 |
"""Performs a hot-reload of the application logic without restarting the process."""
|
| 2216 |
print("[Bootstrap] Performing soft restart (hot-reload)...")
|
| 2217 |
self.hive_ready.clear()
|
| 2218 |
+
self.lite_core_ready.clear()
|
| 2219 |
+
self.voice_ready.clear()
|
| 2220 |
if self.hive_instance:
|
| 2221 |
self.hive_instance.module_manager.stop_all()
|
| 2222 |
if self.app and hasattr(self.app, 'close'): # type: ignore
|