add avatar/voice examples, session start error handling
This commit is contained in:
135
app/lib/constants.ts
Normal file
135
app/lib/constants.ts
Normal 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,
|
||||
},
|
||||
];
|
||||
@@ -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}
|
||||
|
||||
Reference in New Issue
Block a user