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) {
throw new Error("API key is missing from .env");
}
const baseApiUrl = process.env.NEXT_PUBLIC_BASE_API_URL;
const res = await fetch(
"https://api.heygen.com/v1/streaming.create_token",
{
method: "POST",
headers: {
"x-api-key": HEYGEN_API_KEY,
},
const res = await fetch(`${baseApiUrl}/v1/streaming.create_token`, {
method: "POST",
headers: {
"x-api-key": HEYGEN_API_KEY,
},
);
const data = await res.json();
});
const data = await res.json();
return new Response(data.data.token, {
status: 200,
});

View File

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

View File

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

View File

@@ -10,7 +10,7 @@
},
"dependencies": {
"@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/chip": "^2.0.32",
"@nextui-org/code": "2.0.29",
@@ -32,7 +32,6 @@
"ahooks": "^3.8.1",
"ai": "^3.2.15",
"clsx": "2.1.1",
"framer-motion": "~11.1.1",
"intl-messageformat": "^10.5.0",
"next": "14.2.4",
"next-themes": "^0.2.1",

8575
pnpm-lock.yaml generated Normal file

File diff suppressed because it is too large Load Diff