Compare commits
6 Commits
deprecate-
...
update-ava
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8a25c1d520 | ||
|
|
e0150f55b3 | ||
|
|
e259bdfe23 | ||
|
|
d012ef3e3c | ||
|
|
e2763a2cb4 | ||
|
|
ba8fbf7be4 |
3
.env
3
.env
@@ -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
|
||||||
|
|||||||
@@ -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,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -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",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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
8575
pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user