| | import gradio as gr |
| | import os |
| | import json |
| | import numpy as np |
| | import soundfile as sf |
| | from pathlib import Path |
| | import threading |
| | import time |
| |
|
| | |
| | os.environ["HIVE_HOME"] = "/data/hive_data" |
| | HIVE_HOME = Path(os.environ["HIVE_HOME"]) |
| | HIVE_HOME.mkdir(parents=True, exist_ok=True) |
| |
|
| | |
| | voice_authenticated = False |
| | current_user = "guest" |
| | hive_instance = None |
| |
|
| | |
| | def get_hive(): |
| | global hive_instance |
| | if hive_instance is None: |
| | from hive.core.bootstrap import Bootstrap |
| | config_path = HIVE_HOME / "system" / "config.json" |
| | bootstrap = Bootstrap(str(config_path)) |
| | hive_instance = bootstrap.run() |
| | return hive_instance |
| |
|
| | |
| | def login(username, password, audio): |
| | global voice_authenticated, current_user |
| | try: |
| | hive = get_hive() |
| | |
| | |
| | if not hive.security.auth.check_password(username, password): |
| | return "β Invalid credentials", False, False |
| | |
| | |
| | if username == "owner": |
| | if audio is None: |
| | return "π€ Please speak to verify voice", False, False |
| | audio_path = HIVE_HOME / "voice" / "verify.wav" |
| | sf.write(str(audio_path), audio[1], audio[0]) |
| | score = hive.voice.voiceprint.verify(audio_path, username) |
| | if score < 0.7: |
| | return f"β Voice match: {score:.2f} < 0.7", False, False |
| | |
| | voice_authenticated = True |
| | current_user = username |
| | return f"β
Logged in as {username}", True, False |
| | except Exception as e: |
| | return f"β Error: {str(e)}", False, False |
| |
|
| | def logout(): |
| | global voice_authenticated, current_user |
| | voice_authenticated = False |
| | current_user = "guest" |
| | return "π Logged out", False, True |
| |
|
| | |
| | def process_voice(audio): |
| | global current_user |
| | if audio is None: |
| | return None |
| | |
| | try: |
| | hive = get_hive() |
| | audio_path = HIVE_HOME / "voice" / "input.wav" |
| | sf.write(str(audio_path), audio[1], audio[0]) |
| | |
| | |
| | if not voice_authenticated: |
| | user_id = hive.voice.voiceprint.identify(audio_path) |
| | if user_id: |
| | current_user = user_id |
| | return f"ποΈ Welcome back, {user_id}!" |
| | else: |
| | return "ποΈ Unknown speaker. Say 'enroll' to register." |
| | |
| | |
| | text = hive.voice.asr.transcribe(audio_path) |
| | return text |
| | except Exception as e: |
| | return f"β Voice error: {str(e)}" |
| |
|
| | |
| | def chat(message, history, audio_input): |
| | global current_user |
| | |
| | |
| | if audio_input is not None: |
| | voice_result = process_voice(audio_input) |
| | if voice_result and not voice_result.startswith("ποΈ"): |
| | history = history + [[None, voice_result]] |
| | yield history |
| | return |
| | |
| | if voice_result and not voice_result.startswith("ποΈ Welcome"): |
| | message = voice_result |
| | elif voice_result and "enroll" in voice_result.lower(): |
| | |
| | hive = get_hive() |
| | enroll_audio = HIVE_HOME / "voice" / "enroll.wav" |
| | sf.write(str(enroll_audio), audio_input[1], audio_input[0]) |
| | new_user_id = f"user_{int(time.time())}" |
| | hive.voice.voiceprint.enroll(enroll_audio, new_user_id) |
| | current_user = new_user_id |
| | history = history + [[None, f"β
Enrolled as {new_user_id}"]] |
| | yield history |
| | return |
| | |
| | if not message or not message.strip(): |
| | return history |
| | |
| | try: |
| | hive = get_hive() |
| | response = hive.convo.dialogue_manager.submit_turn( |
| | session_id="default", |
| | user_id=current_user, |
| | raw_input={"text": message} |
| | ) |
| | |
| | response_text = response.postprocessed_output.get("text", "Sorry, I couldn't process that.") |
| | history = history + [[message, response_text]] |
| | yield history |
| | except Exception as e: |
| | history = history + [[message, f"β Error: {str(e)}"]] |
| | yield history |
| |
|
| | |
| | def admin_rollback(): |
| | try: |
| | hive = get_hive() |
| | result = hive.persistence.rollback() |
| | return f"β
Rollback: {result}" |
| | except Exception as e: |
| | return f"β Rollback failed: {str(e)}" |
| |
|
| | def admin_snapshot(): |
| | try: |
| | hive = get_hive() |
| | result = hive.persistence.save_snapshot() |
| | return f"β
Snapshot: {result}" |
| | except Exception as e: |
| | return f"β Snapshot failed: {str(e)}" |
| |
|
| | def admin_logs(): |
| | try: |
| | logs_path = HIVE_HOME / "admin" / "audit.jsonl" |
| | if logs_path.exists(): |
| | return logs_path.read_text() |
| | return "No logs found" |
| | except Exception as e: |
| | return f"β Error reading logs: {str(e)}" |
| |
|
| | |
| | with gr.Blocks(title="π Hive β Local AI Tutor", css=""" |
| | .login-box { background: #f0f0f0; padding: 20px; border-radius: 10px; margin: 10px; } |
| | .admin-tab { background: #fff3cd; } |
| | """) as demo: |
| | |
| | |
| | logged_in = gr.State(False) |
| | |
| | |
| | with gr.Row(): |
| | with gr.Column(scale=3): |
| | gr.Markdown("# π Hive β Your Private AI Tutor") |
| | gr.Markdown("*Voice-first, offline-capable AI assistant with self-optimizing memory*") |
| | with gr.Column(scale=1): |
| | with gr.Group(elem_classes=["login-box"]): |
| | username = gr.Textbox(label="Username", value="owner") |
| | password = gr.Textbox(label="Password", type="password", value="Fehr2008") |
| | login_audio = gr.Audio(source="microphone", type="numpy", label="Verify voice (owner)") |
| | login_btn = gr.Button("Login", variant="primary") |
| | logout_btn = gr.Button("Logout", visible=False) |
| | status = gr.Text(label="Status", interactive=False) |
| | |
| | |
| | with gr.Row(): |
| | with gr.Column(scale=4): |
| | chatbot = gr.Chatbot(height=500, label="Conversation") |
| | with gr.Row(): |
| | msg = gr.Textbox(label="Message", placeholder="Type or speak...") |
| | audio = gr.Audio(source="microphone", type="numpy", label="π€") |
| | send = gr.Button("Send") |
| | with gr.Column(scale=1, visible=False) as admin_col: |
| | with gr.Tab("Admin", elem_classes=["admin-tab"]): |
| | gr.Markdown("### π Admin Controls") |
| | with gr.Row(): |
| | rollback_btn = gr.Button("βͺ Force Rollback", variant="secondary") |
| | snapshot_btn = gr.Button("πΎ Save Snapshot", variant="secondary") |
| | admin_status = gr.Text(label="Result") |
| | gr.Markdown("### π Audit Logs") |
| | logs = gr.TextArea(label="Logs", lines=20, max_lines=30) |
| | refresh_logs = gr.Button("π Refresh") |
| | |
| | |
| | login_btn.click( |
| | login, |
| | inputs=[username, password, login_audio], |
| | outputs=[status, logged_in, admin_col] |
| | ).then( |
| | lambda: (gr.update(visible=False), gr.update(visible=True)), |
| | outputs=[login_btn, logout_btn] |
| | ) |
| | |
| | logout_btn.click( |
| | logout, |
| | outputs=[status, logged_in, admin_col] |
| | ).then( |
| | lambda: (gr.update(visible=True), gr.update(visible=False)), |
| | outputs=[login_btn, logout_btn] |
| | ) |
| | |
| | |
| | msg.submit(chat, [msg, chatbot, audio], chatbot).then(lambda: "", outputs=msg) |
| | send.click(chat, [msg, chatbot, audio], chatbot).then(lambda: "", outputs=msg) |
| | audio.stop_recording( |
| | chat, [msg, chatbot, audio], chatbot |
| | ) |
| | |
| | |
| | rollback_btn.click(admin_rollback, outputs=admin_status) |
| | snapshot_btn.click(admin_snapshot, outputs=admin_status) |
| | refresh_logs.click(admin_logs, outputs=logs) |
| |
|
| | |
| | if __name__ == "__main__": |
| | demo.launch(server_name="0.0.0.0", server_port=7860, share=False) |