Hive_2 / app.py
Paulhayes's picture
Create app.py
705d649 verified
raw
history blame
8.12 kB
import gradio as gr
import os
import json
import numpy as np
import soundfile as sf
from pathlib import Path
import threading
import time
# Set up Hive home
os.environ["HIVE_HOME"] = "/data/hive_data"
HIVE_HOME = Path(os.environ["HIVE_HOME"])
HIVE_HOME.mkdir(parents=True, exist_ok=True)
# Global state
voice_authenticated = False
current_user = "guest"
hive_instance = None
# Lazy initialization
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
# Authentication functions
def login(username, password, audio):
global voice_authenticated, current_user
try:
hive = get_hive()
# Check password
if not hive.security.auth.check_password(username, password):
return "❌ Invalid credentials", False, False
# Check voice for owner
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
# Voice processing
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])
# Authenticate or identify
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."
# Transcribe
text = hive.voice.asr.transcribe(audio_path)
return text
except Exception as e:
return f"❌ Voice error: {str(e)}"
# Chat function
def chat(message, history, audio_input):
global current_user
# Process voice if provided
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():
# Start enrollment
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
# Admin functions
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)}"
# Build UI
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:
# State
logged_in = gr.State(False)
# Login section
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)
# Main chat interface
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")
# Event handlers
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]
)
# Chat events
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
)
# Admin events
rollback_btn.click(admin_rollback, outputs=admin_status)
snapshot_btn.click(admin_snapshot, outputs=admin_status)
refresh_logs.click(admin_logs, outputs=logs)
# Launch
if __name__ == "__main__":
demo.launch(server_name="0.0.0.0", server_port=7860, share=False)