File size: 5,389 Bytes
f82e529 d050c18 f82e529 d050c18 028d3bc d050c18 028d3bc f82e529 d050c18 f82e529 d050c18 f82e529 d050c18 0ac295f 0f73f4b f82e529 1ca5363 f82e529 d050c18 f82e529 d050c18 f82e529 1ca5363 f82e529 d050c18 faebfab d0c5be5 d050c18 1ca5363 d0c5be5 d050c18 f82e529 d050c18 f82e529 d050c18 f82e529 d050c18 f82e529 d050c18 46bcfd1 1ca5363 96e8c3f d050c18 46bcfd1 d050c18 46bcfd1 d050c18 f783696 d050c18 | 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 | import gradio as gr
import pandas as pd
from matplotlib.figure import Figure
from config import UI_UPDATE_INTERVAL_SECONDS, GAS_CHART_Y_LIM, GAS_CAL_SECONDS
from ai.face_id import FaceID
from ai.gas import EnvAI
from mqtt_client import MQTTService
def make_fig(df: pd.DataFrame):
# Dual-axis plot: Gas (left), Temp (right)
fig = Figure(figsize=(7.2, 3.4))
ax = fig.subplots()
x = df["T"].values
ax.plot(x, df["Gas"].values, color="#58a6ff", linewidth=1.6, label="Gas")
ax.set_ylim(GAS_CHART_Y_LIM)
ax.set_xlabel("Time (s)")
ax.set_ylabel("Gas (0–4095)")
ax.grid(True, alpha=0.25)
ax2 = ax.twinx()
ax2.plot(x, df["Temp"].values, color="#ffa657", linewidth=1.6, label="Temp")
ax2.set_ylabel("Temp (°C)")
ax2.set_ylim(0, 100)
ax.legend(loc="upper left")
ax2.legend(loc="upper right")
return fig
def build_app():
face = FaceID()
env = EnvAI()
mqtt = MQTTService(on_metrics_message=env.handle_metrics_json)
mqtt.start()
css = """
.gradio-container { background-color: #0b0f19 !important; color: white !important; }
#card { background: #161b22 !important; border: 1px solid #30363d !important; border-radius: 12px !important; padding: 20px !important; }
h1 { color: #58a6ff !important; text-shadow: 0 0 10px rgba(88, 166, 255, 0.3); }
"""
with gr.Blocks() as demo:
gr.HTML("<h1 style='text-align: center;'>🛡️ Smart Home AI Command Center</h1>")
timer = gr.Timer(UI_UPDATE_INTERVAL_SECONDS)
with gr.Row():
with gr.Column(elem_id="card", scale=1):
webcam = gr.Image(sources=["webcam"], type="numpy", label="Security Cam")
btn = gr.Button("🚀 NHẬN DIỆN", variant="primary")
name_out = gr.Textbox(label="Danh tính")
mqtt_out = gr.Textbox(label="Lệnh IoT")
tpl_file = gr.File(label="Tải template (.npz)", file_types=[".npz"])
tpl_status = gr.Textbox(label="Trạng thái Template", interactive=False)
with gr.Row():
blue_on = gr.Button("💡 Bật đèn Blue")
blue_off = gr.Button("💡 Tắt đèn Blue")
door_open = gr.Button("🔓 Mở cửa 30s")
door_lock = gr.Button("🔒 Khóa cửa")
gr.Markdown("### Gas IsolationForest Controls")
with gr.Row():
cal_btn = gr.Button(f"🧪 Calibrate Gas ({GAS_CAL_SECONDS}s)")
reset_btn = gr.Button("🔄 Reset Gas IF")
cal_status = gr.Textbox(label="IF Status", interactive=False)
gas_if_flag = gr.Checkbox(label="IF Gas Anomaly", interactive=False)
with gr.Column(elem_id="card", scale=2):
plot = gr.Plot(value=make_fig(pd.DataFrame({"T": [0.0], "Gas": [0.0], "Temp": [0.0]})),
label="Gas & Temperature")
with gr.Row():
num_out = gr.Number(label="Gas hiện tại", precision=0)
stat_out = gr.Textbox(label="Phân tích môi trường")
with gr.Row():
red_led = gr.Checkbox(label="Gas Alert (Red)", interactive=False)
green_led = gr.Checkbox(label="Temp Alert (Green)", interactive=False)
blue_led = gr.Checkbox(label="Blue LED", interactive=False)
special = gr.Checkbox(label="Special Danger", interactive=False)
# Timer tick
def ui_tick():
df, gas_val, summary, red, green, blue, spec, gas_if, cal_msg, calibrating = env.ui_snapshot()
fig = make_fig(df)
# If actively calibrating, show countdown message
status_msg = cal_msg if cal_msg else ("⏳ Đang hiệu chuẩn..." if calibrating else "")
return fig, gas_val, summary, bool(red), bool(green), bool(blue), bool(spec), bool(gas_if), status_msg
timer.tick(fn=ui_tick, outputs=[plot, num_out, stat_out, red_led, green_led, blue_led, special, gas_if_flag, cal_status])
# FaceID
def on_recognize(frame):
label, info, cmd = face.recognize(frame)
if cmd is not None:
mqtt.publish_door(cmd)
return label, info
btn.click(fn=on_recognize, inputs=webcam, outputs=[name_out, mqtt_out], concurrency_limit=1)
# Template upload
def on_template_uploaded(file):
if file is None:
return "❌ Chưa chọn file .npz"
return face.set_template_file(file.name)
tpl_file.change(fn=on_template_uploaded, inputs=tpl_file, outputs=tpl_status)
# Blue LED controls
blue_on.click(lambda: mqtt.publish_blue_led(True), outputs=[])
blue_off.click(lambda: mqtt.publish_blue_led(False), outputs=[])
# Door controls
door_open.click(lambda: mqtt.publish_door("OPEN"), outputs=[])
door_lock.click(lambda: mqtt.publish_door("LOCK"), outputs=[])
# Gas IF controls
def on_calibrate():
return env.start_gas_calibration(GAS_CAL_SECONDS)
def on_reset_if():
return env.reset_gas_if()
cal_btn.click(fn=on_calibrate, outputs=[cal_status])
reset_btn.click(fn=on_reset_if, outputs=[cal_status])
return demo, css |