add avatar/voice examples, session start error handling

This commit is contained in:
annie
2024-07-01 12:13:56 -07:00
parent 47522ddc97
commit 5d0cf3821c
2 changed files with 216 additions and 32 deletions

135
app/lib/constants.ts Normal file
View File

@@ -0,0 +1,135 @@
export const AVATARS = [
{
avatar_id: "Eric_public_pro2_20230608",
name: "Edward in Blue Shirt",
},
{
avatar_id: "Tyler-incasualsuit-20220721",
name: "Tyler in Casual Suit",
},
{
avatar_id: "Anna_public_3_20240108",
name: "Anna in Brown T-shirt",
},
{
avatar_id: "Susan_public_2_20240328",
name: "Susan in Black Shirt",
},
{
avatar_id: "josh_lite3_20230714",
name: "Joshua Heygen CEO",
},
];
export const VOICES = [
{
voice_id: "077ab11b14f04ce0b49b5f6e5cc20979",
language: "English",
gender: "Male",
name: "Paul - Natural",
preview_audio:
"https://static.heygen.ai/voice_preview/k6dKrFe85PisZ3FMLeppUM.mp3",
support_pause: true,
emotion_support: false,
},
{
voice_id: "131a436c47064f708210df6628ef8f32",
language: "English",
gender: "Female",
name: "Amber - Friendly",
preview_audio:
"https://static.heygen.ai/voice_preview/5HHGT48B6g6aSg2buYcBvw.wav",
support_pause: true,
emotion_support: false,
},
{
voice_id: "0ebe70d83b2349529e56492c002c9572",
language: "English",
gender: "Male",
name: "Antoni - Friendly",
preview_audio:
"https://static.heygen.ai/voice_preview/TwupgZ2az5RiTnmAifPmmS.mp3",
support_pause: true,
emotion_support: false,
},
{
voice_id: "1bd001e7e50f421d891986aad5158bc8",
language: "English",
gender: "Female",
name: "Sara - Cheerful",
preview_audio:
"https://static.heygen.ai/voice_preview/func8CFnfVLKF2VzGDCDCR.wav",
support_pause: true,
emotion_support: false,
},
{
voice_id: "001cc6d54eae4ca2b5fb16ca8e8eb9bb",
language: "Spanish",
gender: "Male",
name: "Elias - Natural",
preview_audio:
"https://static.heygen.ai/voice_preview/JmCb3rgMZnCjCAA9aacnGj.wav",
support_pause: false,
emotion_support: false,
},
{
voice_id: "00988b7d451d0722635ff7b2b9540a7b",
language: "Portuguese",
gender: "Female",
name: "Brenda - Professional",
preview_audio:
"https://static.heygen.ai/voice_preview/fec6396adb73461c9997b2c0d7759b7b.wav",
support_pause: true,
emotion_support: false,
},
{
voice_id: "00c8fd447ad7480ab1785825978a2215",
language: "Chinese",
gender: "Female",
name: "Xiaoxuan - Serious",
preview_audio:
"https://static.heygen.ai/voice_preview/909633f8d34e408a9aaa4e1b60586865.wav",
support_pause: true,
emotion_support: false,
},
{
voice_id: "00ed77fac8b84ffcb2ab52739b9dccd3",
language: "Latvian",
gender: "Male",
name: "Nils - Affinity",
preview_audio:
"https://static.heygen.ai/voice_preview/KwTwAz3R4aBFN69fEYQFdX.wav",
support_pause: true,
emotion_support: false,
},
{
voice_id: "02bec3b4cb514722a84e4e18d596fddf",
language: "Arabic",
gender: "Female",
name: "Fatima - Professional",
preview_audio:
"https://static.heygen.ai/voice_preview/930a245487fe42158c810ac76b8ddbab.wav",
support_pause: true,
emotion_support: false,
},
{
voice_id: "04e95f5bcb8b4620a2c4ef45b8a4481a",
language: "Ukrainian",
gender: "Female",
name: "Polina - Professional",
preview_audio:
"https://static.heygen.ai/voice_preview/ntekV94yFpvv4RgBVPqW7c.wav",
support_pause: true,
emotion_support: false,
},
{
voice_id: "071d6bea6a7f455b82b6364dab9104a2",
language: "German",
gender: "Male",
name: "Jan - Natural",
preview_audio:
"https://static.heygen.ai/voice_preview/fa3728bed81a4d11b8ccef10506af5f4.wav",
support_pause: true,
emotion_support: false,
},
];

View File

@@ -1,3 +1,4 @@
import { AVATARS, VOICES } from "@/app/lib/constants";
import {
Configuration,
NewSessionData,
@@ -10,6 +11,8 @@ import {
CardFooter,
Divider,
Input,
Select,
SelectItem,
Spinner,
Tooltip,
} from "@nextui-org/react";
@@ -103,10 +106,13 @@ export default function StreamingAvatar() {
);
setData(res);
setStream(avatar.current.mediaStream);
setIsLoadingSession(false);
} catch (error) {
console.error("Error starting avatar session:", error);
setDebug(
`There was an error starting the session. ${voiceId ? "This custom voice ID may not be supported." : ""}`
);
}
setIsLoadingSession(false);
}
async function updateToken() {
@@ -133,12 +139,14 @@ export default function StreamingAvatar() {
async function handleInterrupt() {
if (!initialized || !avatar.current) {
setDebug('Avatar API not initialized');
setDebug("Avatar API not initialized");
return;
}
await avatar.current.interrupt({ interruptRequest: { sessionId: data?.sessionId } }).catch((e) => {
setDebug(e.message);
});
await avatar.current
.interrupt({ interruptRequest: { sessionId: data?.sessionId } })
.catch((e) => {
setDebug(e.message);
});
}
async function endSession() {
@@ -259,35 +267,76 @@ export default function StreamingAvatar() {
>
<track kind="captions" />
</video>
<Button
size="md"
onClick={handleInterrupt}
className="bg-gradient-to-tr from-indigo-500 to-indigo-300 absolute bottom-20 right-3 text-white rounded-lg"
variant="shadow"
>
Interrupt task
</Button>
<Button
size="md"
onClick={endSession}
className="bg-gradient-to-tr from-indigo-500 to-indigo-300 absolute bottom-3 right-3 text-white rounded-lg"
variant="shadow"
>
End session
</Button>
<div className="flex flex-col gap-2 absolute bottom-3 right-3">
<Button
size="md"
onClick={handleInterrupt}
className="bg-gradient-to-tr from-indigo-500 to-indigo-300 text-white rounded-lg"
variant="shadow"
>
Interrupt task
</Button>
<Button
size="md"
onClick={endSession}
className="bg-gradient-to-tr from-indigo-500 to-indigo-300 text-white rounded-lg"
variant="shadow"
>
End session
</Button>
</div>
</div>
) : !isLoadingSession ? (
<div className="h-full justify-center items-center flex flex-col gap-4 w-96 self-center">
<Input
value={avatarId}
onChange={(e) => setAvatarId(e.target.value)}
placeholder="Custom Avatar ID (optional)"
/>
<Input
value={voiceId}
onChange={(e) => setVoiceId(e.target.value)}
placeholder="Custom Voice ID (optional)"
/>
<div className="h-full justify-center items-center flex flex-col gap-8 w-[500px] self-center">
<div className="flex flex-col gap-2 w-full">
<p className="text-sm font-medium leading-none">
Custom Avatar ID (optional)
</p>
<Input
value={avatarId}
onChange={(e) => setAvatarId(e.target.value)}
placeholder="Enter a custom avatar ID"
/>
<Select
placeholder="Or select one from these example avatars"
size="md"
onChange={(e) => {
setAvatarId(e.target.value);
}}
>
{AVATARS.map((avatar) => (
<SelectItem
key={avatar.avatar_id}
textValue={avatar.avatar_id}
>
{avatar.name}
</SelectItem>
))}
</Select>
</div>
<div className="flex flex-col gap-2 w-full">
<p className="text-sm font-medium leading-none">
Custom Voice ID (optional)
</p>
<Input
value={voiceId}
onChange={(e) => setVoiceId(e.target.value)}
placeholder="Enter a custom voice ID"
/>
<Select
placeholder="Or select one from these example voices"
size="md"
onChange={(e) => {
setVoiceId(e.target.value);
}}
>
{VOICES.map((voice) => (
<SelectItem key={voice.voice_id} textValue={voice.voice_id}>
{voice.name} | {voice.language} | {voice.gender}
</SelectItem>
))}
</Select>
</div>
<Button
size="md"
onClick={startSession}