send em complete code of or corrected code for this 'use client'
import { AnimatePresence, motion } from 'framer-motion'
import {
LiveKitRoom,
useVoiceAssistant,
BarVisualizer,
RoomAudioRenderer,
VoiceAssistantControlBar,
AgentState,
DisconnectButton,
} from '@livekit/components-react'
import { useCallback, useEffect, useState } from 'react'
import { MediaDeviceFailure } from 'livekit-client'
import type { ConnectionDetails } from './api/connection-details/route'
import { NoAgentNotification } from '@/components/NoAgentNotification'
import { CloseIcon } from '@/components/CloseIcon'
import { useKrispNoiseFilter } from '@livekit/components-react/krisp'
export default function Page() {
const [connectionDetails, updateConnectionDetails] = useState<
ConnectionDetails | undefined
>(undefined)
const [agentState, setAgentState] = useState<AgentState>('disconnected')
// const onConnectButtonClicked = useCallback(async () => {
// // Generate room connection details, including:
// // - A random Room name
// // - A random Participant name
// // - An Access Token to permit the participant to join the room
// // - The URL of the LiveKit server to connect to
// //
// // In real-world application, you would likely allow the user to specify their
// // own participant name, and possibly to choose from existing rooms to join.
// const url = new URL(
// process.env.NEXT_PUBLIC_CONN_DETAILS_ENDPOINT ??
// '/api/connection-details',
// window.location.origin,
// )
// const response = await fetch(url.toString())
// const connectionDetailsData = await response.json()
// updateConnectionDetails(connectionDetailsData)
// }, [])
// return (
// <main
// data-lk-theme="default"
// className="h-full grid content-center bg-[var(--lk-bg)]"
// >
// <LiveKitRoom
// token={connectionDetails?.participantToken}
// serverUrl={connectionDetails?.serverUrl}
// connect={connectionDetails !== undefined}
// audio={true}
// video={false}
// onMediaDeviceFailure={onDeviceFailure}
// onDisconnected={() => {
// updateConnectionDetails(undefined)
// }}
// className="grid grid-rows-[2fr_1fr] items-center"
// >
// <SimpleVoiceAssistant onStateChange={setAgentState} />
// <ControlBar
// onConnectButtonClicked={onConnectButtonClicked}
// agentState={agentState}
// />
// <RoomAudioRenderer />
// <NoAgentNotification state={agentState} />
// </LiveKitRoom>
// </main>
// )
// }
import { useEffect } from 'react';
import { useKrispNoiseFilter } from '@livekit/components-react/krisp';
import { TrackToggle } from '@livekit/components-react';
function CustomControlBar({ onConnectButtonClicked, agentState }) {
const krisp = useKrispNoiseFilter();
useEffect(() => {
krisp.setNoiseFilterEnabled(true);
}, [krisp]);
return (
<div className="relative h-[100px] absolute bottom-0 w-full">
<AnimatePresence>
{agentState === 'disconnected' && (
<motion.button
initial={{ opacity: 0, top: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0, top: '-10px' }}
transition={{ duration: 1, ease: [0.09, 1.04, 0.245, 1.055] }}
className="uppercase absolute left-1/2 -translate-x-1/2 px-4 py-2 bg-white text-black rounded-md"
onClick={onConnectButtonClicked}
>
Start a conversation
</motion.button>
)}
</AnimatePresence>
<AnimatePresence>
{agentState !== 'disconnected' && agentState !== 'connecting' && (
<motion.div
initial={{ opacity: 0, top: '10px' }}
animate={{ opacity: 1, top: 0 }}
exit={{ opacity: 0, top: '-10px' }}
transition={{ duration: 0.4, ease: [0.09, 1.04, 0.245, 1.055] }}
className="flex h-8 absolute left-1/2 -translate-x-1/2 justify-center"
>
<TrackToggle source={Track.Source.Microphone} />
<button className="custom-mic-button">
<img src="/microphone.png" alt="Mic Logo" />
</button>
</motion.div>
)}
</AnimatePresence>
</div>
);
}
function SimpleVoiceAssistant(props: {
onStateChange: (state: AgentState) => void
}) {
const { state, audioTrack } = useVoiceAssistant()
useEffect(() => {
props.onStateChange(state)
}, [props, state])
return (
<div className="h-[300px] max-w-[90vw] mx-auto">
<BarVisualizer
state={state}
barCount={5}
trackRef={audioTrack}
className="agent-visualizer"
options={{ minHeight: 24 }}
/>
</div>
)
}
// function ControlBar(props: {
// onConnectButtonClicked: () => void
// agentState: AgentState
// }) {
// /**
// * Use Krisp background noise reduction when available.
// * Note: This is only available on Scale plan, see {@link
https://livekit.io/pricing | LiveKit Pricing} for more details.
// */
// const krisp = useKrispNoiseFilter()
// useEffect(() => {
// krisp.setNoiseFilterEnabled(true)
// }, [])
// return (
// <div className="relative h-[100px]">
// <AnimatePresence>
// {props.agentState === 'disconnected' && (
// <motion.button
// initial={{ opacity: 0, top: 0 }}
// animate={{ opacity: 1 }}
// exit={{ opacity: 0, top: '-10px' }}
// transition={{ duration: 1, ease: [0.09, 1.04, 0.245, 1.055] }}
// className="uppercase absolute left-1/2 -translate-x-1/2 px-4 py-2 bg-white text-black rounded-md"
// onClick={() => props.onConnectButtonClicked()}
// >
// Start a conversation
// </motion.button>
// )}
// </AnimatePresence>
// <AnimatePresence>
// {props.agentState !== 'disconnected' &&
// props.agentState !== 'connecting' && (
// <motion.div
// initial={{ opacity: 0, top: '10px' }}
// animate={{ opacity: 1, top: 0 }}
// exit={{ opacity: 0, top: '-10px' }}
// transition={{ duration: 0.4, ease: [0.09, 1.04, 0.245, 1.055] }}
// className="flex h-8 absolute left-1/2 -translate-x-1/2 justify-center"
// >
// <VoiceAssistantControlBar controls={{ leave: false }} />
// <DisconnectButton>
// <CloseIcon />
// </DisconnectButton>
// </motion.div>
// )}
// </AnimatePresence>
// </div>
// )
// }
function ControlBar(props: {
onConnectButtonClicked: () => void
agentState: AgentState
}) {
const krisp = useKrispNoiseFilter()
useEffect(() => {
krisp.setNoiseFilterEnabled(true)
}, [])
return (
<div className="relative h-[100px] absolute bottom-0 w-full">
<AnimatePresence>
{props.agentState === 'disconnected' && (
<motion.button
initial={{ opacity: 0, top: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0, top: '-10px' }}
transition={{ duration: 1, ease: [0.09, 1.04, 0.245, 1.055] }}
className="uppercase absolute left-1/2 -translate-x-1/2 px-4 py-2 bg-white text-black rounded-md"
onClick={() => props.onConnectButtonClicked()}
>
Start a conversation
</motion.button>
)}
</AnimatePresence>
<AnimatePresence>
{props.agentState !== 'disconnected' &&
props.agentState !== 'connecting' && (
<motion.div
initial={{ opacity: 0, top: '10px' }}
animate={{ opacity: 1, top: 0 }}
exit={{ opacity: 0, top: '-10px' }}
transition={{ duration: 0.4, ease: [0.09, 1.04, 0.245, 1.055] }}
className="flex h-8 absolute left-1/2 -translate-x-1/2 justify-center"
>
<VoiceAssistantControlBar controls={{ leave: false }} />
<DisconnectButton>
<CloseIcon />
</DisconnectButton>
{/* Custom Mic Button */}
<button className="custom-mic-button">
<img src="/microphone.png" alt="Mic Logo" />
</button>
</motion.div>
)}
</AnimatePresence>
</div>
)
}
function onDeviceFailure(error?: MediaDeviceFailure) {
console.error(error)
alert(
'Error acquiring camera or microphone permissions. Please make sure you grant the necessary permissions in your browser and reload the tab',
)
}
@millions-hair-24956