import { AvatarQuality, StreamingEvents, VoiceChatTransport, VoiceEmotion, StartAvatarRequest, STTProvider, ElevenLabsModel, } from "@heygen/streaming-avatar"; import { useEffect, useRef, useState } from "react"; import { useMemoizedFn, useUnmount } from "ahooks"; import { Button } from "./Button"; import { AvatarConfig } from "./AvatarConfig"; import { AvatarVideo } from "./AvatarSession/AvatarVideo"; import { useStreamingAvatarSession } from "./logic/useStreamingAvatarSession"; import { AvatarControls } from "./AvatarSession/AvatarControls"; import { useVoiceChat } from "./logic/useVoiceChat"; import { StreamingAvatarProvider, StreamingAvatarSessionState } from "./logic"; import { LoadingIcon } from "./Icons"; import { MessageHistory } from "./AvatarSession/MessageHistory"; import { AVATARS } from "@/app/lib/constants"; const DEFAULT_CONFIG: StartAvatarRequest = { quality: AvatarQuality.Low, avatarName: AVATARS[0].avatar_id, knowledgeId: undefined, voice: { rate: 1.5, emotion: VoiceEmotion.EXCITED, model: ElevenLabsModel.eleven_flash_v2_5, }, language: "en", disableIdleTimeout: true, voiceChatTransport: VoiceChatTransport.LIVEKIT, sttSettings: { provider: STTProvider.DEEPGRAM, }, }; function InteractiveAvatar() { const { initAvatar, startAvatar, stopAvatar, sessionState, stream } = useStreamingAvatarSession(); const { startVoiceChat } = useVoiceChat(); const [config, setConfig] = useState(DEFAULT_CONFIG); const mediaStream = useRef(null); async function fetchAccessToken() { try { const response = await fetch("/api/get-access-token", { method: "POST", }); const token = await response.text(); console.log("Access Token:", token); // Log the token to verify return token; } catch (error) { console.error("Error fetching access token:", error); throw error; } } const startSessionV2 = useMemoizedFn(async (isVoiceChat: boolean) => { try { const newToken = await fetchAccessToken(); const avatar = initAvatar(newToken); avatar.on(StreamingEvents.AVATAR_START_TALKING, (e) => { console.log("Avatar started talking", e); }); avatar.on(StreamingEvents.AVATAR_STOP_TALKING, (e) => { console.log("Avatar stopped talking", e); }); avatar.on(StreamingEvents.STREAM_DISCONNECTED, () => { console.log("Stream disconnected"); }); avatar.on(StreamingEvents.STREAM_READY, (event) => { console.log(">>>>> Stream ready:", event.detail); }); avatar.on(StreamingEvents.USER_START, (event) => { console.log(">>>>> User started talking:", event); }); avatar.on(StreamingEvents.USER_STOP, (event) => { console.log(">>>>> User stopped talking:", event); }); avatar.on(StreamingEvents.USER_END_MESSAGE, (event) => { console.log(">>>>> User end message:", event); }); avatar.on(StreamingEvents.USER_TALKING_MESSAGE, (event) => { console.log(">>>>> User talking message:", event); }); avatar.on(StreamingEvents.AVATAR_TALKING_MESSAGE, (event) => { console.log(">>>>> Avatar talking message:", event); }); avatar.on(StreamingEvents.AVATAR_END_MESSAGE, (event) => { console.log(">>>>> Avatar end message:", event); }); await startAvatar(config); if (isVoiceChat) { await startVoiceChat(); } } catch (error) { console.error("Error starting avatar session:", error); } }); useUnmount(() => { stopAvatar(); }); useEffect(() => { if (stream && mediaStream.current) { mediaStream.current.srcObject = stream; mediaStream.current.onloadedmetadata = () => { mediaStream.current!.play(); }; } }, [mediaStream, stream]); return (
{sessionState !== StreamingAvatarSessionState.INACTIVE ? ( ) : ( )}
{sessionState === StreamingAvatarSessionState.CONNECTED ? ( ) : sessionState === StreamingAvatarSessionState.INACTIVE ? (
) : ( )}
{sessionState === StreamingAvatarSessionState.CONNECTED && ( )}
); } export default function InteractiveAvatarWrapper() { return ( ); }