UNPKG

murmuraba

Version:

Real-time audio noise reduction with advanced chunked processing for web applications

49 lines (48 loc) 4.8 kB
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import React, { useMemo } from 'react'; import { ResponsiveContainer, AreaChart, Area, XAxis, YAxis, CartesianGrid, Tooltip } from 'recharts'; export const VadTimeline = React.memo(function VadTimeline({ vadData, chunkId }) { // Show loading state while data is being processed if (!vadData || vadData.length === 0) { return (_jsxs("div", { className: "details__section", children: [_jsx("h4", { className: "section__title", children: "\uD83D\uDCC8 Voice Activity Detection (VAD) Timeline" }), _jsxs("div", { className: "vad-loading-container", children: [_jsxs("div", { className: "vad-loading-spinner", children: [_jsx("div", { className: "spinner-dot" }), _jsx("div", { className: "spinner-dot" }), _jsx("div", { className: "spinner-dot" })] }), _jsx("p", { className: "vad-loading-text", children: "Analizando actividad de voz, por favor espera..." })] })] })); } const stats = useMemo(() => { const voiceDetectedPercentage = (vadData.filter(d => d.vad > 0.5).length / vadData.length) * 100; const peakVad = Math.max(...vadData.map(d => d.vad)); const minVad = Math.min(...vadData.map(d => d.vad)); return { voiceDetectedPercentage, peakVad, minVad }; }, [vadData]); return (_jsxs("div", { className: "details__section", children: [_jsx("h4", { className: "section__title", children: "\uD83D\uDCC8 Voice Activity Detection (VAD) Timeline" }), _jsxs("div", { className: "vad-chart-container vad-chart-fade-in", children: [vadData && vadData.length > 0 ? (_jsx("div", { style: { height: '200px', width: '100%', minHeight: '200px', minWidth: '300px', position: 'relative' }, children: _jsx(ResponsiveContainer, { width: "100%", height: "100%", minWidth: 300, minHeight: 200, children: _jsxs(AreaChart, { data: vadData, children: [_jsx("defs", { children: _jsxs("linearGradient", { id: `vadGradient-${chunkId}`, x1: "0", y1: "0", x2: "0", y2: "1", children: [_jsx("stop", { offset: "5%", stopColor: "#7ED321", stopOpacity: 0.8 }), _jsx("stop", { offset: "95%", stopColor: "#7ED321", stopOpacity: 0.1 })] }) }), _jsx(CartesianGrid, { strokeDasharray: "3 3", stroke: "#3b3c5a", opacity: 0.5 }), _jsx(XAxis, { dataKey: "time", stroke: "#a0a0a0", tickFormatter: (value) => `${value.toFixed(1)}s` }), _jsx(YAxis, { domain: [0, 1], stroke: "#a0a0a0", ticks: [0, 0.25, 0.5, 0.75, 1], tickFormatter: (value) => value.toFixed(2) }), _jsx(Tooltip, { contentStyle: { backgroundColor: 'rgba(36, 37, 58, 0.95)', border: '1px solid #3b3c5a', borderRadius: '8px', color: '#e0e0e0' }, formatter: (value) => [`VAD: ${value.toFixed(3)}`, ''], labelFormatter: (label) => `Time: ${label}s` }), _jsx(Area, { type: "monotone", dataKey: "vad", stroke: "#7ED321", fill: `url(#vadGradient-${chunkId})`, fillOpacity: 1, strokeWidth: 2, isAnimationActive: false })] }) }) })) : (_jsx("div", { style: { height: '200px', display: 'flex', alignItems: 'center', justifyContent: 'center' }, children: _jsx("p", { children: "No VAD data available" }) })), vadData && vadData.length > 0 && (_jsxs("div", { className: "vad-stats", children: [_jsxs("span", { className: "vad-stat", children: [_jsx("strong", { children: "Voice Detected:" }), " ", stats.voiceDetectedPercentage.toFixed(1), "%"] }), _jsxs("span", { className: "vad-stat", children: [_jsx("strong", { children: "Peak VAD:" }), " ", stats.peakVad.toFixed(3)] }), _jsxs("span", { className: "vad-stat", children: [_jsx("strong", { children: "Min VAD:" }), " ", stats.minVad.toFixed(3)] })] }))] })] })); }, (prevProps, nextProps) => { // Custom comparison to prevent unnecessary re-renders if (prevProps.chunkId !== nextProps.chunkId) return false; if (!prevProps.vadData && !nextProps.vadData) return true; if (!prevProps.vadData || !nextProps.vadData) return false; if (prevProps.vadData.length !== nextProps.vadData.length) return false; // Deep comparison of first and last few data points const checkPoints = [0, 1, prevProps.vadData.length - 2, prevProps.vadData.length - 1]; for (const i of checkPoints) { if (i >= 0 && i < prevProps.vadData.length) { if (prevProps.vadData[i]?.time !== nextProps.vadData[i]?.time || prevProps.vadData[i]?.vad !== nextProps.vadData[i]?.vad) { return false; } } } return true; });