@p0llen/speaker-detector-client
Version:
React client for interfacing with the [speaker-detector](https://pypi.org/project/speaker-detector) Python backend. Supports real-time speaker identification, meeting transcription, and speaker enrollment.
116 lines (113 loc) • 3.88 kB
JavaScript
import React from "react";
import useMicCheck from "../hooks/useMicCheck";
/**
* MicStatus centralizes ALL status messaging:
* - microphone availability/health (from useMicCheck)
* - detection engine state (passed in as props from SpeakerStatus)
*
* SpeakerStatus must *not* render any status text.
* It should pass raw engine state into this component.
*/
var MicStatus = _ref => {
var {
backendOnline,
// boolean | null
status,
// engine status string from useSpeakerDetection
listeningMode,
// "off" | "single" | "multi"
isSpeaking,
// boolean
title = "🎤 Microphone & Detection Status"
} = _ref;
var {
micStatus,
// "pending" | "ok" | "silent" | "none" | "blocked" | "error"
micStatusLabel,
// human label derived from micStatus
devices,
selectedDeviceId,
setSelectedDeviceId,
checkMic
} = useMicCheck();
var combinedStatusLabel = () => {
// 1) Hard stop if backend is down
if (backendOnline === false) return "🔌 Backend unreachable — detection unavailable";
// 2) Mic problems take precedence (single source of truth for mic UX)
switch (micStatus) {
case "blocked":
return "🚫 Mic access blocked by browser — allow microphone to continue";
case "none":
return "❌ No microphone detected (unplugged or missing device)";
case "silent":
return "⚠️ Mic detected but no signal (muted/virtual/very low input)";
case "pending":
return "⏳ Checking microphone…";
case "error":
return "⚠️ Microphone check failed — retry or choose another input";
// "ok" falls through to engine checks below
default:
break;
}
// 3) Engine state (only shown when mic is "ok")
var s = (status || "").trim();
if (listeningMode === "off" || s === "disabled") {
return "🔇 Detection disabled";
}
if (s === "pending") {
return "⏳ Engine awaiting detection data…";
}
if (s === "listening") {
return isSpeaking ? "🎙 Voice detected" : "🕵️ Engine listening…";
}
if (backendOnline === null) {
return "🔎 Checking backend…";
}
return "ℹ️ Ready";
};
return /*#__PURE__*/React.createElement("div", {
className: "mic-status-panel"
}, /*#__PURE__*/React.createElement("h4", {
className: "speaker-heading"
}, title), /*#__PURE__*/React.createElement("p", null, /*#__PURE__*/React.createElement("strong", null, "Status:"), " ", combinedStatusLabel(), /*#__PURE__*/React.createElement("br", null), /*#__PURE__*/React.createElement("span", {
style: {
fontSize: 12,
color: "#9aa"
}
}, "Mic: ", micStatusLabel)), /*#__PURE__*/React.createElement("div", {
style: {
marginTop: 8
}
}, /*#__PURE__*/React.createElement("label", null, "Input device:\xA0", /*#__PURE__*/React.createElement("select", {
value: selectedDeviceId || "",
onChange: e => {
var id = e.target.value;
setSelectedDeviceId(id);
setTimeout(() => checkMic(id), 0);
},
style: {
background: "#222",
color: "#fff",
borderRadius: 4,
padding: 4
}
}, devices.length === 0 ? /*#__PURE__*/React.createElement("option", {
value: ""
}, "(no audio inputs)") : devices.map(d => /*#__PURE__*/React.createElement("option", {
key: d.deviceId,
value: d.deviceId
}, d.label || "Device ".concat(d.deviceId.slice(0, 6)))))), /*#__PURE__*/React.createElement("button", {
onClick: () => checkMic(selectedDeviceId || undefined),
style: {
marginLeft: 8,
background: "#2a2a2a",
color: "#fff",
border: "1px solid #555",
borderRadius: 6,
padding: "4px 8px",
cursor: "pointer"
},
title: "Re-run microphone check"
}, "\uD83D\uDD01 Recheck")));
};
export default MicStatus;