ok now the textuak iput wokrs bit i eant to extend this apps feature  by like if camera is on and audio is on then take the last videos screen short convert it to base64 and input it ot he server  with the transcribes input and like have image input and get audio like please make it good and wokr oiwt h the backend good and no buggy i want perfefct and comelte and best
"""
'use client'

import { useState, useEffect, useRef, useCallback } from 'react'
import { Mic, MicOff, Video, VideoOff, PhoneOff, RefreshCw } from 'lucide-react'
import ChatDisplay from '@/components/chatBox'
import { useRouter } from 'next/navigation'
import AudioStreamPlayer from '@/components/AudioStreamPlayer';

export default function VideoRoom() {
const router = useRouter()
const [localStream, setLocalStream] = useState(null)
const [isAudioMuted, setIsAudioMuted] = useState(true)
const [isVideoOff, setIsVideoOff] = useState(true)
const [isCameraLoading, setIsCameraLoading] = useState(false)
const [error, setError] = useState(null)
const [transcript, setTranscript] = useState('')
const [finalTranscript, setFinalTranscript] = useState('hello boss')
const [isTranscribing, setIsTranscribing] = useState(false)
const [audioLevel, setAudioLevel] = useState(0)
const [recognitionErrors, setRecognitionErrors] = useState(0)
const [ isProcessing, setIsProcessing] = useState(false)
const [meetingData, setMeetingData] = useState({ meetingId: '', context: '' })

const localVideoRef = useRef(null)
const streamCleanupRef = useRef(null)
const recognitionRef = useRef(null)
const pauseTimeoutRef = useRef(null)
const audioContextRef = useRef(null)
const audioAnalyserRef = useRef(null)
const audioDataRef = useRef(new Uint8Array(1024))
const recognitionRetryTimeoutRef = useRef(null)

const MAX_RECOGNITION_RETRIES = 3
const NOISE_THRESHOLD = 30
const PAUSE_THRESHOLD = 1250

useEffect(() => {
try {
const userData = sessionStorage.getItem('userData')
if (userData) {
const parsedData = JSON.parse(userData)
setMeetingData({
meetingId: parsedData.meetingId || '',
context: parsedData.context || ''
})
}
} catch (err) {
console.error('Error accessing session storage:', err)
setError('Failed to load meeting data')
}
}, [])

const setupAudioAnalyser = useCallback((stream) => {
try {
if (!stream) return


  // Cleanup existing audio context
  if (audioContextRef.current) {
    audioContextRef.current.close()
  }

  const audioContext = new (window.AudioContext || window.webkitAudioContext)()
  const analyser = audioContext.createAnalyser()
  const source = audioContext.createMediaStreamSource(stream)
  
  analyser.fftSize = 2048
  analyser.smoothingTimeConstant = 0.8
  source.connect(analyser)
  
  audioContextRef.current = audioContext
  audioAnalyserRef.current = analyser

  // Start monitoring audio levels
  const checkAudioLevel = () => {
    if (audioAnalyserRef.current && !isAudioMuted) {
      audioAnalyserRef.current.getByteFrequencyData(audioDataRef.current)
      const average = audioDataRef.current.reduce((a, b) => a + b) / audioDataRef.current.length
      setAudioLevel(average)
      
      // Use audio level for intelligent pause detection
      if (average < NOISE_THRESHOLD) {
        startPauseDetection()
      }
    }
    requestAnimationFrame(checkAudioLevel)
  }
  
  checkAudioLevel()
} catch (err) {
  console.error('Error setting up audio analyser:', err)
}
}, [isAudioMuted])

const startPauseDetection = useCallback(() => {
if (pauseTimeoutRef.current) {
clearTimeout(pauseTimeoutRef.current)
}


pauseTimeoutRef.current = setTimeout(() => {
  if (transcript.trim()) {
    console.log('Natural pause detected, finalizing transcript:', transcript)
    
    // send the transcript to the endpoint /api/ai/stream the transcription should be passes in the data frield of this and the streamed audio should be handled as soon as it comes, it should play and interact with the AIWaitingAnimation which has a animation that responds to the audio 
  }
}, PAUSE_THRESHOLD)
}, [transcript])

const errorMessages = {
NotAllowedError: 'Camera access denied. Please allow camera and microphone access in your browser settings.',
NotFoundError: 'No camera or microphone found. Please check your device connections.',
NotReadableError: 'Camera or microphone is already in use by another application.',
OverconstrainedError: 'Your device does not support the requested video quality.',
TypeError: 'Your browser does not support video calls. Please use a modern browser.',
SecurityError: 'Security error occurred. Please ensure you're using HTTPS.',
}

const initializeSpeechRecognition = useCallback(() => {
if (!('webkitSpeechRecognition' in window)) {
console.error('Speech recognition not supported')
setError('Speech recognition not supported in this browser')
return
}


const recognition = new window.webkitSpeechRecognition()
recognition.continuous = true
recognition.interimResults = true
recognition.lang = 'en-US'

recognition.onstart = () => {
  setIsTranscribing(true)
  setRecognitionErrors(0)
  console.log('Speech recognition started')
}

recognition.onerror = (event) => {
  console.error('Speech recognition error:', event.error)
  setRecognitionErrors(prev => prev + 1)

  if (event.error === 'not-allowed') {
    setError('Microphone access denied for transcription')
  } else if (event.error === 'audio-capture') {
    setError('No microphone detected')
  } else if (recognitionErrors < MAX_RECOGNITION_RETRIES) {
    // Attempt to restart recognition after error
      recognitionRetryTimeoutRef.current = setTimeout(() => {
        if (!isAudioMuted && recognitionRef.current) {
          console.log('Attempting to restart speech recognition')
            recognition.start()
        }
      }, 1000)
  } else {
    setError('Speech recognition failed multiple times. Please refresh the page.')
  }
}

recognition.onend = () => {
  setIsTranscribing(false)
  console.log('Speech recognition ended')

  // Restart if not manually stopped and mic is still on
  if (!isAudioMuted && recognitionRef.current && recognitionErrors < MAX_RECOGNITION_RETRIES) {
    console.log('Restarting speech recognition')
    try {
      recognition.start()
    } catch (err) {
      console.error('Failed to restart recognition:', err)
    }
  }
}

recognition.onresult = (event) => {
  let interimTranscript = ''
  let finalTranscript = ''

  // Process results with confidence scores
  for (let i = event.resultIndex; i < event.results.length; i++) {
    const transcript = event.results[i][0].transcript
    const confidence = event.results[i][0].confidence

    if (confidence > 0.7) { // Only accept high-confidence results
      if (event.results[i].isFinal) {
        finalTranscript += addPunctuation(transcript)
      } else {
        interimTranscript += transcript
      }
    }
  }

  const currentTranscript = finalTranscript || interimTranscript
  setTranscript(currentTranscript)

  if (finalTranscript) {
    console.log('Final transcript:', finalTranscript)
    setFinalTranscript(finalTranscript)
    setIsProcessing((prev) => !prev)
    setTimeout(() => {
      setIsAudioMuted(true);
    }, PAUSE_THRESHOLD)
  }
}

recognitionRef.current = recognition
console.log('Speech recognition initialized')

// Start recognition if audio is not muted
if (!isAudioMuted) {
  try {
    recognition.start()
  } catch (err) {
    console.error('Failed to start recognition:', err)
  }
}
}, [isAudioMuted])


// Helper function to add basic punctuation
const addPunctuation = (text) => {
    // Add period if sentence ends without punctuation
    text = text.trim()
    if (!/[.!?]$/.test(text)) {
        text += '.'
    }
    // Capitalize first letter
    return text.charAt(0).toUpperCase() + text.slice(1)
    }
// Clean up function
const cleanupSpeechRecognition = useCallback(() => {
if (recognitionRef.current) {
recognitionRef.current.stop()
recognitionRef.current = null
}


    if (recognitionRetryTimeoutRef.current) {
      clearTimeout(recognitionRetryTimeoutRef.current)
    }

    if (pauseTimeoutRef.current) {
      clearTimeout(pauseTimeoutRef.current)
    }

    if (audioContextRef.current) {
      audioContextRef.current.close()
      audioContextRef.current = null
    }

    setTranscript('')
    setIsTranscribing(false)
    setAudioLevel(0)
    setRecognitionErrors(0)
  }, [])
  
const stopMediaTracks = useCallback(() => {
console.log('Stopping media tracks')
if (streamCleanupRef.current) {
streamCleanupRef.current.getTracks().forEach(track => {
console.log(Stopping track: ${track.kind})
track.stop()
})
streamCleanupRef.current = null
setLocalStream(null)
}


if (recognitionRef.current) {
  console.log('Stopping speech recognition')
  recognitionRef.current.stop()
  recognitionRef.current = null
}

if (pauseTimeoutRef.current) {
  console.log('Clearing pause timeout')
  clearTimeout(pauseTimeoutRef.current)
}
}, [])

const getMediaConstraints = (includeVideo = true, includeAudio = true) => {
const constraints = {
video: includeVideo ? {
width: { ideal: 1280 },
height: { ideal: 720 },
facingMode: 'user',
frameRate: { ideal: 30 }
} : false,
audio: includeAudio ? {
echoCancellation: true,
noiseSuppression: true,
autoGainControl: true
} : false
}
console.log('Media constraints:', constraints)
return constraints
}

useEffect(() => {
if (!localStream || !localVideoRef.current) return


console.log('Setting up video element with local stream')
const videoElement = localVideoRef.current
videoElement.srcObject = localStream
videoElement.muted = true

const playVideo = async () => {
  try {
    await videoElement.play()
    console.log('Video playback started successfully')
  } catch (err) {
    console.error('Failed to play video:', err)
    setError('Failed to play video stream')
  }
}

videoElement.onloadedmetadata = playVideo

return () => {
  console.log('Cleaning up video element')
  videoElement.srcObject = null
}
}, [localStream])


// Effect for handling audio state changes
useEffect(() => {
    if (!isAudioMuted) {
      initializeSpeechRecognition()
      if (localStream) {
        setupAudioAnalyser(localStream)
      }
    } else {
      cleanupSpeechRecognition()
    }

    return cleanupSpeechRecognition
  }, [isAudioMuted, localStream, initializeSpeechRecognition, setupAudioAnalyser, cleanupSpeechRecognition])
const startLocalStream = useCallback(async (withVideo = true, withAudio = true) => {
console.log('Starting local stream:', { withVideo, withAudio })
if (!navigator.mediaDevices?.getUserMedia) {
console.error('getUserMedia not supported')
setError('Your browser does not support video calls')
return
}


try {
  setIsCameraLoading(true)
  setError(null)
  stopMediaTracks()

  if (withVideo || withAudio) {
    console.log('Requesting media access')
    const stream = await navigator.mediaDevices.getUserMedia(getMediaConstraints(withVideo, withAudio))
    console.log('Media access granted')
    streamCleanupRef.current = stream
    setLocalStream(stream)
  } else {
    console.log('No media requested, clearing stream')
    streamCleanupRef.current = null
    setLocalStream(null)
  }
  
  setIsVideoOff(!withVideo)
  setIsAudioMuted(!withAudio)

} catch (error) {
  console.error('Media access error:', error)
  setError(errorMessages[error.name] || error.message || 'Failed to start media devices')
  setIsVideoOff(true)
  setIsAudioMuted(true)
  streamCleanupRef.current = null
  setLocalStream(null)
} finally {
  setIsCameraLoading(false)
}
}, [stopMediaTracks])

useEffect(() => {
console.log('Initial stream setup')
startLocalStream(!isVideoOff, !isAudioMuted)
return stopMediaTracks
}, [startLocalStream, stopMediaTracks])

const toggleAudio = useCallback(() => {
console.log('Toggling audio:', { currentState: isAudioMuted })
startLocalStream(!isVideoOff, isAudioMuted)
}, [isVideoOff, isAudioMuted, startLocalStream])

const toggleVideo = useCallback(() => {
console.log('Toggling video:', { currentState: isVideoOff })
startLocalStream(isVideoOff, !isAudioMuted)
}, [isVideoOff, isAudioMuted, startLocalStream])

return (



{error && (
<button
onClick={() => {
console.log('Retrying media access')
startLocalStream(!isVideoOff, !isAudioMuted)
}}
className="bg-blue-500 hover:bg-blue-400 text-white p-2 rounded-full transition-colors duration-200 focus:outline-none focus:ring-2 focus:ring-blue-400"
aria-label="Retry camera"
>


)}




{isCameraLoading ? (



) : error ? (


Camera Error


{error}


<button
onClick={() => startLocalStream(!isVideoOff, !isAudioMuted)}
className="mt-4 bg-blue-500 hover:bg-blue-400 text-white px-4 py-2 rounded-full text-sm"
>
Retry



) : isVideoOff ? (


You


) : (


      <ChatDisplay userTranscript = {transcript} isProcessing={isProcessing} />
      <AudioStreamPlayer meetingId={meetingData.meetingId} context={meetingData.context} transcript={finalTranscript} />
      </div>
    </div>
    <div className="bg-gray-800 bg-opacity-75 backdrop-blur-md p-6">
      <div className="flex justify-center space-x-6">
        <button
          onClick={toggleAudio}
          disabled={isCameraLoading}
          className={`p-4 rounded-full transition-all duration-200 transform hover:scale-110 focus:outline-none focus:ring-2 focus:ring-blue-400 ${
            isAudioMuted ? 'bg-red-500 hover:bg-red-600' : 'bg-blue-500 hover:bg-blue-600'
          } ${isCameraLoading && 'opacity-50 cursor-not-allowed'}`}
          aria-label={isAudioMuted ? 'Unmute audio' : 'Mute audio'}
        >
          {isAudioMuted ? <MicOff size={24} /> : <Mic size={24} />}
        </button>
        <button
          onClick={toggleVideo}
          disabled={isCameraLoading}
          className={`p-4 rounded-full transition-all duration-200 transform hover:scale-110 focus:outline-none focus:ring-2 focus:ring-blue-400 ${
            isVideoOff ? 'bg-red-500 hover:bg-red-600' : 'bg-blue-500 hover:bg-blue-600'
          } ${isCameraLoading && 'opacity-50 cursor-not-allowed'}`}
          aria-label={isVideoOff ? 'Turn on video' : 'Turn off video'}
        >
          {isVideoOff ? <VideoOff size={24} /> : <Video size={24} />}
        </button>
        <button
          onClick={() => {
            console.log('Ending call and navigating to home')
            stopMediaTracks()
            router.push('/')
          }}
          className="bg-red-500 hover:bg-red-600 text-white p-4 rounded-full transition-all duration-200 transform hover:scale-110 focus:outline-none focus:ring-2 focus:ring-red-400"
          aria-label="End call"
        >
          <PhoneOff size={24} />
        </button>
      </div>
    </div>
  </div>
</div>
)
}
"""
"""
import express from 'express';
import AIVoiceStreamService from '../openaiElevenLabs/AIVoiceStreamService';
import { UserMessage } from '../helpers/types';
import Conversation from '../db/schema';
import { system_prompt_natural } from '../helpers/constant';
import { OpenAI } from 'openai';
import validator from 'validator';

const router = express.Router();
const aiVoiceService = new AIVoiceStreamService();

// Initialize OpenAI
const openaiApiKey = process.env.OPENAI_API_KEY;
if (!openaiApiKey) {
throw new Error('Missing OpenAI API Key');
}

const openai = new OpenAI({
apiKey: openaiApiKey,
});

router.post('/stream', async (req: any, res: any) => {
try {
const { data, meetingId, context } = req.body;
if (!data || !meetingId) {
return res.status(400).json({ error: 'Invalid message or user ID' });
}
const userMessage: UserMessage = { role: 'user', content: data };


let existingConversation = await Conversation.findOne({ meetingId });

if (existingConversation) {
  existingConversation.messages.push(userMessage);
  const response: string = await aiVoiceService.generateVoiceStream(existingConversation.messages, res, JSON.stringify(context) || "");
  console.log(response)
  existingConversation.messages.push({ role: 'assistant', content: response || "" });
  await existingConversation.save();
  console.log('Conversation saved successfully!');

} else {
  res.status(401).json({ error: 'Meeting room not Found' });
}
} catch (error) {
console.error('Streaming error:', error);
if (!res.headersSent) {
res.status(500).json({ error: error instanceof Error ? error.message : 'Unknown error' });
}
}
});

// Helper function to validate image URLs
const isValidImageUrl = (url: string): boolean => {
return validator.isURL(url) && /.(jpeg|jpg|png|webp|gif)$/i.test(url);
};

router.post('/analyze-image-stream', async (req: any, res: any) => {
try {
const { images, meetingId, context, question } = req.body;


// Validate input
if (!images || !Array.isArray(images) || images.length === 0) {
  return res.status(400).json({ error: 'Invalid or missing images array' });
}

if (!question || typeof question !== 'string') {
  return res.status(400).json({ error: 'Invalid or missing question' });
}

if (!meetingId) {
  return res.status(400).json({ error: 'Missing meetingId' });
}

// Prepare content blocks
const content: any = [{ type: 'text', text: question }];

images.forEach((img: any, index: number) => {
  if (img.url) {
    if (!isValidImageUrl(img.url)) {
      throw new Error(`Invalid or unsupported image URL at index ${index}: ${img.url}`);
    }
    content.push({
      type: 'image_url',
      image_url: {
        url: img.url,
        detail: img.detail || 'auto',
      },
    });
  } else if (img.base64) {
    if (img.base64.length > (20 * 1024 * 1024 * 4 / 3)) { // Approx. 27MB base64 string
      throw new Error(`Base64 image at index ${index} is too large`);
    }

    // Optionally, validate base64 format
    if (!validator.isBase64(img.base64)) {
      throw new Error(`Invalid base64 image string at index ${index}`);
    }

    // Determine image MIME type (optional, default to jpeg)
    const mimeType = img.mimeType && typeof img.mimeType === 'string' ? img.mimeType : 'image/jpeg';

    content.push({
      type: 'image_url',
      image_url: {
        url: `data:${mimeType};base64,${img.base64}`,
        detail: img.detail || 'auto',
      },
    });
  } else {
    throw new Error(`Each image must have either a 'url' or 'base64' field at index ${index}`);
  }
});

// Construct user message
const userMessage: UserMessage = {
  role: 'user',
  content: content,
};

// Retrieve existing conversation
let existingConversation = await Conversation.findOne({ meetingId });

if (!existingConversation) {
  return res.status(404).json({ error: 'Meeting room not found' });
}

// Append user message
existingConversation.messages.push(userMessage);

// Optionally, store image metadata
existingConversation.images = existingConversation.images || [];
images.forEach((img: any) => {
  if (img.url) {
    existingConversation.images.push({
      url: img.url,
      detail: img.detail || 'auto',
    });
  } else if (img.base64) {
    const mimeType = img.mimeType && typeof img.mimeType === 'string' ? img.mimeType : 'image/jpeg';
    existingConversation.images.push({
      url: `data:${mimeType};base64,${img.base64}`,
      detail: img.detail || 'auto',
    });
  }
});

// Save the conversation with the new message
await existingConversation.save();

// Construct messages for OpenAI
const fullMessages = [
  { role: 'system', content: system_prompt_natural(context) },
  ...existingConversation.messages,
];

// Set streaming headers for the response
res.setHeader('Content-Type', 'audio/mpeg');
res.setHeader('Transfer-Encoding', 'chunked');

// Initialize variables for streaming
const voiceOptions = {
  openaiModel: 'gpt-4o-mini',
  stability: 0.75,
  similarityBoost: 0.85,
  voiceId: 'Xb7hH8MSUJpSbSDYk0k2',
};

// Generate voice stream based on the OpenAI stream
const textMessages = fullMessages;

// Invoke the existing AIVoiceStreamService to handle streaming
await aiVoiceService.generateVoiceStream(textMessages, res, context || '', voiceOptions);
} catch (error: any) {
console.error('Image analysis and audio streaming error:', error);
if (!res.headersSent) {
res.status(500).json({ error: error.message || 'Unknown error' });
}
}
});

export default router;
"""
"""
"""
import React, { useEffect, useRef, useState } from 'react';

const AudioStreamPlayer = ({ transcript, meetingId, context }) => {
  const [audioData, setAudioData] = useState(new Array(32).fill(100));
  const [isProcessing, setIsProcessing] = useState(false);
  const audioContextRef = useRef(null);
  const sourceNodeRef = useRef(null);
  const analyzerRef = useRef(null);
  const mediaSourceRef = useRef(null);
  const audioBufferRef = useRef(null);
  const visualizerFrameRef = useRef(null);

  useEffect(() => {
    const initializeAudio = () => {
      if (!audioContextRef.current) {
        audioContextRef.current = new (window.AudioContext || window.webkitAudioContext)();
        analyzerRef.current = audioContextRef.current.createAnalyser();
        analyzerRef.current.fftSize = 64;
        analyzerRef.current.connect(audioContextRef.current.destination);
      }

      // Ensure AudioContext is resumed on user interaction
      const resumeAudioContext = () => {
        if (audioContextRef.current.state === 'suspended') {
          audioContextRef.current.resume().catch((error) => {
            console.error('Failed to resume audio context:', error);
          });
        }
      };

      // Add event listeners for user interaction
      document.addEventListener('mousedown', resumeAudioContext, { once: true });
      document.addEventListener('touchstart', resumeAudioContext, { once: true });
    };

    const startStreaming = async () => {
      if (!transcript || !meetingId) return;
      
      try {
        setIsProcessing(true);
        initializeAudio();
        
        const response = await fetch('http://localhost:3000/api/ai/stream', {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
          },
          body: JSON.stringify({
            data: transcript,
            meetingId,
            context
          })
        });

        if (!response.ok) {
          throw new Error(`Stream request failed: ${response.status}`);
        }

        mediaSourceRef.current = new MediaSource();
        audioBufferRef.current = new Audio();
        audioBufferRef.current.src = URL.createObjectURL(mediaSourceRef.current);

        const reader = response.body.getReader();
        let sourceBuffer;

        mediaSourceRef.current.addEventListener('sourceopen', () => {
          sourceBuffer = mediaSourceRef.current.addSourceBuffer('audio/mpeg');
          processStream(reader, sourceBuffer);
        });

        audioBufferRef.current.play().catch(error => {
          console.error('Audio playback failed:', error);
        });

      } catch (error) {
        console.error('Streaming error:', error);
        setIsProcessing(false);
      }
    };

    const processStream = async (reader, sourceBuffer) => {
      const processChunk = async () => {
        try {
          const { value, done } = await reader.read();
          
          if (done) {
            mediaSourceRef.current.endOfStream();
            setIsProcessing(false);
            return;
          }

          if (value && value.length > 0) {
            await appendBuffer(sourceBuffer, value);
            await processAudioData(value);
          }

          processChunk();
        } catch (error) {
          console.error('Error processing chunk:', error);
          setIsProcessing(false);
        }
      };

      processChunk();
    };

    const appendBuffer = (sourceBuffer, chunk) => {
      return new Promise((resolve, reject) => {
        if (!sourceBuffer.updating) {
          sourceBuffer.appendBuffer(chunk);
          sourceBuffer.addEventListener('updateend', resolve, { once: true });
          sourceBuffer.addEventListener('error', reject, { once: true });
        } else {
          sourceBuffer.addEventListener('updateend', () => {
            sourceBuffer.appendBuffer(chunk);
            sourceBuffer.addEventListener('updateend', resolve, { once: true });
            sourceBuffer.addEventListener('error', reject, { once: true });
          }, { once: true });
        }
      });
    };

    const processAudioData = async (chunk) => {
      try {
        const audioBuffer = await audioContextRef.current.decodeAudioData(chunk.buffer.slice());
        sourceNodeRef.current = audioContextRef.current.createBufferSource();
        sourceNodeRef.current.buffer = audioBuffer;
        sourceNodeRef.current.connect(analyzerRef.current);
        sourceNodeRef.current.start(0);

        updateVisualizer();
      } catch (error) {
        console.error('Error processing audio data:', error);
      }
    };

    const updateVisualizer = () => {
      if (!analyzerRef.current) return;

      const dataArray = new Uint8Array(analyzerRef.current.frequencyBinCount);
      analyzerRef.current.getByteFrequencyData(dataArray);
      
      setAudioData(Array.from(dataArray).map(value => (value / 255) * 100));
      
      visualizerFrameRef.current = requestAnimationFrame(updateVisualizer);
    };

    startStreaming();

    return () => {
      if (visualizerFrameRef.current) {
        cancelAnimationFrame(visualizerFrameRef.current);
      }
      if (sourceNodeRef.current) {
        sourceNodeRef.current.disconnect();
      }
      if (analyzerRef.current) {
        analyzerRef.current.disconnect();
      }
      if (audioContextRef.current) {
        audioContextRef.current.close();
      }
      if (mediaSourceRef.current && audioBufferRef.current) {
        URL.revokeObjectURL(audioBufferRef.current.src);
      }
    };
  }, [transcript, meetingId, context]);

  return (
    <div className="audio-visualizer">
      <div className="visualization-bars" style={{ display: 'flex', alignItems: 'flex-end', height: '50px' }}>
        {audioData.map((value, index) => (
          <div
            key={index}
            style={{
              width: '3px',
              height: `${value}%`,
              backgroundColor: '#4CAF50',
              margin: '0 1px',
              transition: 'height 0.1s ease'
            }}
          />
        ))}
      </div>
      {isProcessing && <div className="processing-indicator">Processing audio...</div>}
    </div>
  );
};

export default AudioStreamPlayer;

"""

please make it perfect and wokring