22
33import { CloseIcon } from "@/components/CloseIcon" ;
44import { NoAgentNotification } from "@/components/NoAgentNotification" ;
5+ import TranscriptionView from "@/components/TranscriptionView" ;
56import {
6- AgentState ,
77 BarVisualizer ,
88 DisconnectButton ,
99 RoomAudioRenderer ,
@@ -18,8 +18,6 @@ import { useCallback, useEffect, useState } from "react";
1818import type { ConnectionDetails } from "./api/connection-details/route" ;
1919
2020export default function Page ( ) {
21- const [ agentState , setAgentState ] = useState < AgentState > ( "disconnected" ) ;
22-
2321 const [ room ] = useState ( new Room ( ) ) ;
2422
2523 const onConnectButtonClicked = useCallback ( async ( ) => {
@@ -54,36 +52,46 @@ export default function Page() {
5452 return (
5553 < main data-lk-theme = "default" className = "h-full grid content-center bg-[var(--lk-bg)]" >
5654 < RoomContext . Provider value = { room } >
57- < div className = "lk-room-container grid grid-rows-[2fr_1fr] items-center" >
58- < SimpleVoiceAssistant onStateChange = { setAgentState } />
59- < ControlBar onConnectButtonClicked = { onConnectButtonClicked } agentState = { agentState } />
60- < RoomAudioRenderer />
61- < NoAgentNotification state = { agentState } />
55+ < div className = "lk-room-container max-h-[90vh]" >
56+ < SimpleVoiceAssistant onConnectButtonClicked = { onConnectButtonClicked } />
6257 </ div >
6358 </ RoomContext . Provider >
6459 </ main >
6560 ) ;
6661}
6762
68- function SimpleVoiceAssistant ( props : { onStateChange : ( state : AgentState ) => void } ) {
69- const { state, audioTrack } = useVoiceAssistant ( ) ;
70- useEffect ( ( ) => {
71- props . onStateChange ( state ) ;
72- } , [ props , state ] ) ;
63+ function SimpleVoiceAssistant ( props : { onConnectButtonClicked : ( ) => void } ) {
64+ const { state : agentState } = useVoiceAssistant ( ) ;
7365 return (
74- < div className = "h-[300px] max-w-[90vw] mx-auto" >
75- < BarVisualizer
76- state = { state }
77- barCount = { 5 }
78- trackRef = { audioTrack }
79- className = "agent-visualizer"
80- options = { { minHeight : 24 } }
81- />
82- </ div >
66+ < >
67+ < AnimatePresence >
68+ { agentState === "disconnected" && (
69+ < motion . button
70+ initial = { { opacity : 0 , top : 0 } }
71+ animate = { { opacity : 1 } }
72+ exit = { { opacity : 0 , top : "-10px" } }
73+ transition = { { duration : 1 , ease : [ 0.09 , 1.04 , 0.245 , 1.055 ] } }
74+ className = "uppercase absolute left-1/2 -translate-x-1/2 px-4 py-2 bg-white text-black rounded-md"
75+ onClick = { ( ) => props . onConnectButtonClicked ( ) }
76+ >
77+ Start a conversation
78+ </ motion . button >
79+ ) }
80+ < div className = "w-3/4 lg:w-1/2 mx-auto h-full" >
81+ < TranscriptionView />
82+ </ div >
83+ </ AnimatePresence >
84+
85+ < RoomAudioRenderer />
86+ < NoAgentNotification state = { agentState } />
87+ < div className = "fixed bottom-0 w-full px-4 py-2" >
88+ < ControlBar />
89+ </ div >
90+ </ >
8391 ) ;
8492}
8593
86- function ControlBar ( props : { onConnectButtonClicked : ( ) => void ; agentState : AgentState } ) {
94+ function ControlBar ( ) {
8795 /**
8896 * Use Krisp background noise reduction when available.
8997 * Note: This is only available on Scale plan, see {@link https://livekit.io/pricing | LiveKit Pricing} for more details.
@@ -93,35 +101,32 @@ function ControlBar(props: { onConnectButtonClicked: () => void; agentState: Age
93101 krisp . setNoiseFilterEnabled ( true ) ;
94102 } , [ ] ) ;
95103
104+ const { state : agentState , audioTrack } = useVoiceAssistant ( ) ;
105+
96106 return (
97107 < div className = "relative h-[100px]" >
98108 < AnimatePresence >
99- { props . agentState === "disconnected" && (
100- < motion . button
101- initial = { { opacity : 0 , top : 0 } }
102- animate = { { opacity : 1 } }
103- exit = { { opacity : 0 , top : "-10px" } }
104- transition = { { duration : 1 , ease : [ 0.09 , 1.04 , 0.245 , 1.055 ] } }
105- className = "uppercase absolute left-1/2 -translate-x-1/2 px-4 py-2 bg-white text-black rounded-md"
106- onClick = { ( ) => props . onConnectButtonClicked ( ) }
107- >
108- Start a conversation
109- </ motion . button >
110- ) }
111- </ AnimatePresence >
112- < AnimatePresence >
113- { props . agentState !== "disconnected" && props . agentState !== "connecting" && (
109+ { agentState !== "disconnected" && agentState !== "connecting" && (
114110 < motion . div
115111 initial = { { opacity : 0 , top : "10px" } }
116112 animate = { { opacity : 1 , top : 0 } }
117113 exit = { { opacity : 0 , top : "-10px" } }
118114 transition = { { duration : 0.4 , ease : [ 0.09 , 1.04 , 0.245 , 1.055 ] } }
119- className = "flex h-8 absolute left-1/2 -translate-x-1/2 justify-center "
115+ className = "flex absolute w-full h-full justify-between px-8 sm:px-4 "
120116 >
121- < VoiceAssistantControlBar controls = { { leave : false } } />
122- < DisconnectButton >
123- < CloseIcon />
124- </ DisconnectButton >
117+ < BarVisualizer
118+ state = { agentState }
119+ barCount = { 5 }
120+ trackRef = { audioTrack }
121+ className = "agent-visualizer w-24 gap-2"
122+ options = { { minHeight : 12 } }
123+ />
124+ < div className = "flex items-center" >
125+ < VoiceAssistantControlBar controls = { { leave : false } } />
126+ < DisconnectButton >
127+ < CloseIcon />
128+ </ DisconnectButton >
129+ </ div >
125130 </ motion . div >
126131 ) }
127132 </ AnimatePresence >
0 commit comments