All files / lib/awareness/collective/components NeuralVoiceHUD.tsx

98.55% Statements 68/69
68.18% Branches 15/22
100% Functions 2/2
98.55% Lines 68/69

Press n or j to go to the next uncovered block, b, p or k for the previous block.

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 1011x   1x 1x 1x 1x 1x 1x 1x   1x   1x 1x 9x 9x   9x 3x 3x 9x   9x   9x 3x 3x 9x   9x 9x 9x   9x 9x   9x 9x 3x 3x 9x   9x 9x 9x     9x 9x 9x 9x   9x 9x 9x 9x     9x 9x 9x 9x 9x 9x           9x 9x 450x 450x 450x 450x 450x 450x 450x 450x     450x 9x 9x 9x 9x   9x         9x 9x           9x  
"use client";
 
import React, { useEffect, useMemo, useState } from "react";
import { motion } from "framer-motion";
import { generateNeuralSummary } from "@/lib/awareness/collective/analysis/neural-summary-generator";
import { getEvolutionLogs } from "@/lib/evolution/history.collector";
import { useVoiceSynthesis } from "./hooks/useVoiceSynthesis";
import { HUDContainer } from "./hud/glass-effects";
import { DepthReactiveGlass } from "@/lib/awareness/collective/components/hud/hud.depth-sync";
 
/**
 * NeuralVoiceHUD — Phase 007.2 (Depth Sync + Ambient Glow)
 */
export const NeuralVoiceHUD: React.FC<{ onClose: () => void }> = ({ onClose }) => {
  const [logs, setLogs] = useState(() => getEvolutionLogs().slice(-15));
  const { speak, stop, isSpeaking } = useVoiceSynthesis();
 
  useEffect(() => {
    const timer = setInterval(() => setLogs(getEvolutionLogs().slice(-15)), 15000);
    return () => clearInterval(timer);
  }, []);
 
  const summary = useMemo(() => generateNeuralSummary(logs), [logs]);
 
  useEffect(() => {
    speak(summary);
    return () => stop();
  }, [summary]);
 
  const confidences = logs.map((l) => l.confidence);
  const avg = confidences.length
    ? confidences.reduce((s, c) => s + c, 0) / confidences.length
    : 0;
  const status =
    avg >= 0.7 ? "Stable" : avg >= 0.4 ? "Fluctuating" : "Critical";
 
  const [phase, setPhase] = useState(0);
  useEffect(() => {
    const anim = setInterval(() => setPhase((p) => (p + 1) % 360), 50);
    return () => clearInterval(anim);
  }, []);
 
  return (
    <motion.div
      className="fixed inset-0 flex items-center justify-center
                 bg-[rgba(0,8,20,0.65)] backdrop-blur-[24px] backdrop-saturate-[180%]
                 transition-all duration-500"
      style={{ zIndex: 2147483620, pointerEvents: "auto" }}
      initial={{ opacity: 0 }}
      animate={{ opacity: 1 }}
      exit={{ opacity: 0 }}
    >
      <DepthReactiveGlass strength={10}>
        <HUDContainer status={status}>
          <div className="flex justify-between items-center mb-5">
            <h2 className="text-[22px] font-bold text-cyan-300 drop-shadow-sm">
              Neural Voice HUD
            </h2>
            <motion.button
              onClick={() => { stop(); onClose(); }}
              whileHover={{ scale: 1.1 }}
              whileTap={{ scale: 0.9 }}
              className="px-4 py-1.5 text-sm border border-cyan-400/50 text-cyan-200 rounded-md hover:bg-cyan-500/10 transition"
            >
              Close
            </motion.button>
          </div>
 
          {/* Waveform */}
          <div className="relative h-[160px] flex items-center justify-center overflow-hidden">
            {[...Array(50)].map((_, i) => {
              const barHeight = Math.sin((i * 12 + phase) * 0.1) * 40 + 60;
              const opacity = isSpeaking ? 0.9 : 0.3;
              return (
                <motion.div
                  key={i}
                  className="w-[4px] mx-[2px] bg-gradient-to-t from-cyan-500 to-blue-300 rounded-full"
                  animate={{ height: barHeight, opacity }}
                  transition={{ duration: 0.1 }}
                />
              );
            })}
            <motion.div
              animate={{ opacity: isSpeaking ? [0.4, 1, 0.4] : 0.3, scale: isSpeaking ? [1, 1.03, 1] : 1 }}
              transition={{ duration: 1.2, repeat: Infinity }}
              className="absolute text-cyan-400 text-sm top-3"
            >
              {isSpeaking ? "🔊 Speaking summary..." : "Paused"}
            </motion.div>
          </div>
 
          {/* Summary */}
          <div className="mt-5 text-sm text-cyan-200/85 font-mono whitespace-pre-wrap border-t border-cyan-400/20 pt-3">
            {summary}
          </div>
        </HUDContainer>
      </DepthReactiveGlass>
    </motion.div>
  );
};