Files
InteractiveAvatarNextJSDemo/components/logic/useStreamingAvatarSession.ts
Vlad Morozov a3cdf46210 update demo
2025-04-22 19:38:59 +03:00

159 lines
4.0 KiB
TypeScript

import StreamingAvatar, {
ConnectionQuality,
StartAvatarRequest,
StreamingEvents,
} from "@heygen/streaming-avatar";
import { useCallback } from "react";
import {
StreamingAvatarSessionState,
useStreamingAvatarContext,
} from "./context";
import { useVoiceChat } from "./useVoiceChat";
import { useMessageHistory } from "./useMessageHistory";
export const useStreamingAvatarSession = () => {
const {
avatarRef,
basePath,
sessionState,
setSessionState,
stream,
setStream,
setIsListening,
setIsUserTalking,
setIsAvatarTalking,
setConnectionQuality,
handleUserTalkingMessage,
handleStreamingTalkingMessage,
handleEndMessage,
clearMessages,
} = useStreamingAvatarContext();
const { stopVoiceChat } = useVoiceChat();
useMessageHistory();
const init = useCallback(
(token: string) => {
avatarRef.current = new StreamingAvatar({
token,
basePath: basePath,
});
return avatarRef.current;
},
[basePath, avatarRef],
);
const handleStream = useCallback(
({ detail }: { detail: MediaStream }) => {
setStream(detail);
setSessionState(StreamingAvatarSessionState.CONNECTED);
},
[setSessionState, setStream],
);
const stop = useCallback(async () => {
avatarRef.current?.off(StreamingEvents.STREAM_READY, handleStream);
avatarRef.current?.off(StreamingEvents.STREAM_DISCONNECTED, stop);
clearMessages();
stopVoiceChat();
setIsListening(false);
setIsUserTalking(false);
setIsAvatarTalking(false);
setStream(null);
await avatarRef.current?.stopAvatar();
setSessionState(StreamingAvatarSessionState.INACTIVE);
}, [
handleStream,
setSessionState,
setStream,
avatarRef,
setIsListening,
stopVoiceChat,
clearMessages,
setIsUserTalking,
setIsAvatarTalking,
]);
const start = useCallback(
async (config: StartAvatarRequest, token?: string) => {
if (sessionState !== StreamingAvatarSessionState.INACTIVE) {
throw new Error("There is already an active session");
}
if (!avatarRef.current) {
if (!token) {
throw new Error("Token is required");
}
init(token);
}
if (!avatarRef.current) {
throw new Error("Avatar is not initialized");
}
setSessionState(StreamingAvatarSessionState.CONNECTING);
avatarRef.current.on(StreamingEvents.STREAM_READY, handleStream);
avatarRef.current.on(StreamingEvents.STREAM_DISCONNECTED, stop);
avatarRef.current.on(
StreamingEvents.CONNECTION_QUALITY_CHANGED,
({ detail }: { detail: ConnectionQuality }) =>
setConnectionQuality(detail),
);
avatarRef.current.on(StreamingEvents.USER_START, () => {
setIsUserTalking(true);
});
avatarRef.current.on(StreamingEvents.USER_STOP, () => {
setIsUserTalking(false);
});
avatarRef.current.on(StreamingEvents.AVATAR_START_TALKING, () => {
setIsAvatarTalking(true);
});
avatarRef.current.on(StreamingEvents.AVATAR_STOP_TALKING, () => {
setIsAvatarTalking(false);
});
avatarRef.current.on(
StreamingEvents.USER_TALKING_MESSAGE,
handleUserTalkingMessage,
);
avatarRef.current.on(
StreamingEvents.AVATAR_TALKING_MESSAGE,
handleStreamingTalkingMessage,
);
avatarRef.current.on(StreamingEvents.USER_END_MESSAGE, handleEndMessage);
avatarRef.current.on(
StreamingEvents.AVATAR_END_MESSAGE,
handleEndMessage,
);
await avatarRef.current.createStartAvatar(config);
return avatarRef.current;
},
[
init,
handleStream,
stop,
setSessionState,
avatarRef,
sessionState,
setConnectionQuality,
setIsUserTalking,
handleUserTalkingMessage,
handleStreamingTalkingMessage,
handleEndMessage,
setIsAvatarTalking,
],
);
return {
avatarRef,
sessionState,
stream,
initAvatar: init,
startAvatar: start,
stopAvatar: stop,
};
};