Compare commits

..

6 Commits

Author SHA1 Message Date
Eddy Kim
8a25c1d520 update streaming avatar sdk to 2.0.10, add optional api base url environment variable for testing 2025-03-17 14:34:07 -07:00
Joby
e0150f55b3 feat: change demo avatars (#56) 2025-02-24 19:19:15 -08:00
Joby
e259bdfe23 feat: update 2.0.9 (#51) 2025-01-17 17:57:29 -08:00
Joby
d012ef3e3c fix: remove unused package (#49) 2024-12-23 11:12:14 -08:00
Joby
e2763a2cb4 feat: add package lock (#46) 2024-12-19 11:42:12 -08:00
eddy-heygen
ba8fbf7be4 Merge pull request #43 from HeyGen-Official/deprecate-openai-example
remove deprecated openai example
2024-12-03 14:39:57 -08:00
7 changed files with 8623 additions and 38 deletions

3
.env
View File

@@ -1 +1,2 @@
HEYGEN_API_KEY=your Heygen API key HEYGEN_API_KEY="your Heygen API key"
NEXT_PUBLIC_BASE_API_URL=https://api.heygen.com

2
.npmrc
View File

@@ -1 +1 @@
package-lock=false

View File

@@ -5,18 +5,16 @@ export async function POST() {
if (!HEYGEN_API_KEY) { if (!HEYGEN_API_KEY) {
throw new Error("API key is missing from .env"); throw new Error("API key is missing from .env");
} }
const baseApiUrl = process.env.NEXT_PUBLIC_BASE_API_URL;
const res = await fetch( const res = await fetch(`${baseApiUrl}/v1/streaming.create_token`, {
"https://api.heygen.com/v1/streaming.create_token", method: "POST",
{ headers: {
method: "POST", "x-api-key": HEYGEN_API_KEY,
headers: {
"x-api-key": HEYGEN_API_KEY,
},
}, },
); });
const data = await res.json();
const data = await res.json();
return new Response(data.data.token, { return new Response(data.data.token, {
status: 200, status: 200,
}); });

View File

@@ -1,23 +1,23 @@
export const AVATARS = [ export const AVATARS = [
{ {
avatar_id: "Eric_public_pro2_20230608", avatar_id: "Ann_Therapist_public",
name: "Edward in Blue Shirt", name: "Ann Therapist",
}, },
{ {
avatar_id: "Tyler-incasualsuit-20220721", avatar_id: "Shawn_Therapist_public",
name: "Tyler in Casual Suit", name: "Shawn Therapist",
}, },
{ {
avatar_id: "Anna_public_3_20240108", avatar_id: "Bryan_FitnessCoach_public",
name: "Anna in Brown T-shirt", name: "Bryan Fitness Coach",
}, },
{ {
avatar_id: "Susan_public_2_20240328", avatar_id: "Dexter_Doctor_Standing2_public",
name: "Susan in Black Shirt", name: "Dexter Doctor Standing",
}, },
{ {
avatar_id: "josh_lite3_20230714", avatar_id: "Elenora_IT_Sitting_public",
name: "Joshua Heygen CEO", name: "Elenora Tech Expert",
}, },
]; ];

View File

@@ -2,7 +2,10 @@ import type { StartAvatarResponse } from "@heygen/streaming-avatar";
import StreamingAvatar, { import StreamingAvatar, {
AvatarQuality, AvatarQuality,
StreamingEvents, TaskMode, TaskType, VoiceEmotion, StreamingEvents,
TaskMode,
TaskType,
VoiceEmotion,
} from "@heygen/streaming-avatar"; } from "@heygen/streaming-avatar";
import { import {
Button, Button,
@@ -23,7 +26,7 @@ import { useMemoizedFn, usePrevious } from "ahooks";
import InteractiveAvatarTextInput from "./InteractiveAvatarTextInput"; import InteractiveAvatarTextInput from "./InteractiveAvatarTextInput";
import {AVATARS, STT_LANGUAGE_LIST} from "@/app/lib/constants"; import { AVATARS, STT_LANGUAGE_LIST } from "@/app/lib/constants";
export default function InteractiveAvatar() { export default function InteractiveAvatar() {
const [isLoadingSession, setIsLoadingSession] = useState(false); const [isLoadingSession, setIsLoadingSession] = useState(false);
@@ -32,7 +35,7 @@ export default function InteractiveAvatar() {
const [debug, setDebug] = useState<string>(); const [debug, setDebug] = useState<string>();
const [knowledgeId, setKnowledgeId] = useState<string>(""); const [knowledgeId, setKnowledgeId] = useState<string>("");
const [avatarId, setAvatarId] = useState<string>(""); const [avatarId, setAvatarId] = useState<string>("");
const [language, setLanguage] = useState<string>('en'); const [language, setLanguage] = useState<string>("en");
const [data, setData] = useState<StartAvatarResponse>(); const [data, setData] = useState<StartAvatarResponse>();
const [text, setText] = useState<string>(""); const [text, setText] = useState<string>("");
@@ -41,6 +44,10 @@ export default function InteractiveAvatar() {
const [chatMode, setChatMode] = useState("text_mode"); const [chatMode, setChatMode] = useState("text_mode");
const [isUserTalking, setIsUserTalking] = useState(false); const [isUserTalking, setIsUserTalking] = useState(false);
function baseApiUrl() {
return process.env.NEXT_PUBLIC_BASE_API_URL;
}
async function fetchAccessToken() { async function fetchAccessToken() {
try { try {
const response = await fetch("/api/get-access-token", { const response = await fetch("/api/get-access-token", {
@@ -64,6 +71,7 @@ export default function InteractiveAvatar() {
avatar.current = new StreamingAvatar({ avatar.current = new StreamingAvatar({
token: newToken, token: newToken,
basePath: baseApiUrl(),
}); });
avatar.current.on(StreamingEvents.AVATAR_START_TALKING, (e) => { avatar.current.on(StreamingEvents.AVATAR_START_TALKING, (e) => {
console.log("Avatar started talking", e); console.log("Avatar started talking", e);
@@ -95,6 +103,12 @@ export default function InteractiveAvatar() {
voice: { voice: {
rate: 1.5, // 0.5 ~ 1.5 rate: 1.5, // 0.5 ~ 1.5
emotion: VoiceEmotion.EXCITED, emotion: VoiceEmotion.EXCITED,
// elevenlabsSettings: {
// stability: 1,
// similarity_boost: 1,
// style: 1,
// use_speaker_boost: false,
// },
}, },
language: language, language: language,
disableIdleTimeout: true, disableIdleTimeout: true,
@@ -103,7 +117,7 @@ export default function InteractiveAvatar() {
setData(res); setData(res);
// default to voice mode // default to voice mode
await avatar.current?.startVoiceChat({ await avatar.current?.startVoiceChat({
useSilencePrompt: false useSilencePrompt: false,
}); });
setChatMode("voice_mode"); setChatMode("voice_mode");
} catch (error) { } catch (error) {
@@ -120,9 +134,11 @@ export default function InteractiveAvatar() {
return; return;
} }
// speak({ text: text, task_type: TaskType.REPEAT }) // speak({ text: text, task_type: TaskType.REPEAT })
await avatar.current.speak({ text: text, taskType: TaskType.REPEAT, taskMode: TaskMode.SYNC }).catch((e) => { await avatar.current
setDebug(e.message); .speak({ text: text, taskType: TaskType.REPEAT, taskMode: TaskMode.SYNC })
}); .catch((e) => {
setDebug(e.message);
});
setIsLoadingRepeat(false); setIsLoadingRepeat(false);
} }
async function handleInterrupt() { async function handleInterrupt() {
@@ -131,11 +147,9 @@ export default function InteractiveAvatar() {
return; return;
} }
await avatar.current await avatar.current.interrupt().catch((e) => {
.interrupt() setDebug(e.message);
.catch((e) => { });
setDebug(e.message);
});
} }
async function endSession() { async function endSession() {
await avatar.current?.stopAvatar(); await avatar.current?.stopAvatar();
@@ -261,9 +275,7 @@ export default function InteractiveAvatar() {
}} }}
> >
{STT_LANGUAGE_LIST.map((lang) => ( {STT_LANGUAGE_LIST.map((lang) => (
<SelectItem key={lang.key}> <SelectItem key={lang.key}>{lang.label}</SelectItem>
{lang.label}
</SelectItem>
))} ))}
</Select> </Select>
</div> </div>

View File

@@ -10,7 +10,7 @@
}, },
"dependencies": { "dependencies": {
"@ai-sdk/openai": "^0.0.34", "@ai-sdk/openai": "^0.0.34",
"@heygen/streaming-avatar": "^2.0.8", "@heygen/streaming-avatar": "^2.0.10",
"@nextui-org/button": "2.0.34", "@nextui-org/button": "2.0.34",
"@nextui-org/chip": "^2.0.32", "@nextui-org/chip": "^2.0.32",
"@nextui-org/code": "2.0.29", "@nextui-org/code": "2.0.29",
@@ -32,7 +32,6 @@
"ahooks": "^3.8.1", "ahooks": "^3.8.1",
"ai": "^3.2.15", "ai": "^3.2.15",
"clsx": "2.1.1", "clsx": "2.1.1",
"framer-motion": "~11.1.1",
"intl-messageformat": "^10.5.0", "intl-messageformat": "^10.5.0",
"next": "14.2.4", "next": "14.2.4",
"next-themes": "^0.2.1", "next-themes": "^0.2.1",

8575
pnpm-lock.yaml generated Normal file

File diff suppressed because it is too large Load Diff