1.3 安装与集成
本节说明 XingyunAvatarAgent 的安装与引入方式,以及原生 JS、Vue、React 三类项目的集成示例。
安装
使用包管理器安装:
# npm
npm install @xmov/avatar@latest
# pnpm
pnpm add @xmov/avatar@latest
# yarn
yarn add @xmov/avatar@latest
ESM 引入
安装后在代码中按需导入:
import XingyunAvatarAgent from "@xmov/avatar/agent";
包名形式的 ESM 导入适用于 Vite 等构建工具管理的项目。直接由浏览器加载的原生 HTML 页面,请使用下方 CDN 示例;如果使用包名导入,需要另行配置 import map。参见 MDN JavaScript 模块说明。
以下框架示例适用于浏览器客户端。SSR 项目应将 SDK 的加载和实例创建放在客户端执行。
SDK 2.4.1 的类型定义仍要求 containerId。使用有效的 container DOM 元素时,SDK 优先使用该元素;下方 Vue、React 示例传入 containerId: "" 以满足当前类型定义,并在创建实例前确认 DOM ref 已存在。
CDN / UMD 引入
端到端对话页面也可通过 <script> 加载自包含构建,直接使用全局构造器 XingyunAvatarAgent,无需预先加载其它 SDK 文件:
<script src="https://media.xingyun3d.com/xingyun3d/general/litesdk/xmovAvatar_e2e@latest.js"></script>
<script>
const agent = new window.XingyunAvatarAgent({
// 配置项见 3.1 构造参数
});
</script>
注意:上述 CDN 地址为固定地址,
@latest为浮动标签。生产环境建议加载锁定版本的文件(如xmovAvatar_e2e.<version>.js)。
无论 ESM 还是 UMD 方式,具身智能体容器都必须有明确宽高,否则画布可能折叠为零尺寸。
集成示例
原生 JS(Vanilla)
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>具身智能体集成</title>
<style>
#agent-avatar {
width: min(100%, 405px);
aspect-ratio: 9 / 16;
overflow: hidden;
background: #000;
}
</style>
</head>
<body>
<div id="agent-avatar"></div>
<script src="https://media.xingyun3d.com/xingyun3d/general/litesdk/xmovAvatar_e2e@latest.js"></script>
<script>
const agent = new window.XingyunAvatarAgent({
containerId: "#agent-avatar",
appId: "your-app-id",
appSecret: "your-app-secret",
gatewayServer: "https://nebula-agent.xingyun3d.com/user/v1/ttsa_v2/session",
onMessage(error) {
console.error(error.code, error.message);
},
agentCallbacks: {
onError(error) {
console.error(error.code, error.message);
},
},
});
async function initialize() {
await agent.init({
onDownloadProgress(progress) {
console.log("加载进度", progress.toFixed(0) + "%");
},
});
// init 完成后,可调用 ask()、speak() 或 startASR()。
console.log("Agent 已就绪", agent.getAgentState());
}
void initialize().catch(console.error);
window.addEventListener("beforeunload", () => {
void agent.destroy("page_unload").catch(console.error);
});
</script>
</body>
</html>
Vue 3
在 onMounted 中取得容器 DOM,再创建 SDK 实例。SDK 实例使用普通变量保存,组件卸载时调用 destroy()。Vue 的 DOM 挂载时机见 官方生命周期说明。
<script setup lang="ts">
import { ref, onMounted, onBeforeUnmount } from "vue";
import XingyunAvatarAgent from "@xmov/avatar/agent";
const container = ref<HTMLDivElement | null>(null);
let agent: XingyunAvatarAgent | null = null;
let unmounted = false;
onMounted(async () => {
const element = container.value;
if (!element) return;
const instance = new XingyunAvatarAgent({
containerId: "",
container: element,
appId: "your-app-id",
appSecret: "your-app-secret",
gatewayServer: "https://nebula-agent.xingyun3d.com/user/v1/ttsa_v2/session",
onMessage(error) {
console.error(error.code, error.message);
},
agentCallbacks: {
onError(error) {
console.error(error.code, error.message);
},
},
});
agent = instance;
try {
await instance.init({
onDownloadProgress(progress) {
console.log("加载进度", progress.toFixed(0) + "%");
},
});
} catch (error) {
if (!unmounted) {
console.error("初始化失败", error);
}
await instance.destroy("init_failed").catch(console.error);
}
});
onBeforeUnmount(() => {
unmounted = true;
const instance = agent;
agent = null;
void instance?.destroy("component_unmount").catch(console.error);
});
</script>
<template>
<div
ref="container"
style="width: min(100%, 405px); aspect-ratio: 9 / 16; overflow: hidden; background: #000;"
></div>
</template>
创建实例前应确认容器 ref 已取得有效 DOM。每个组件实例使用自己的 DOM ref;初始化完成后再开放交互。组件卸载时即使初始化尚未完成,也应调用
destroy()取消初始化并释放资源。Vue 不会等待卸载钩子中的异步清理完成,业务若需要等待完整释放,应主动await destroy()。
React
import { useEffect, useRef } from "react";
import XingyunAvatarAgent from "@xmov/avatar/agent";
function AvatarComponent() {
const containerRef = useRef(null);
const agentRef = useRef(null);
useEffect(() => {
let destroyed = false;
async function init() {
const element = containerRef.current;
if (!element) return;
const agent = new XingyunAvatarAgent({
containerId: "",
container: element,
appId: "your-app-id",
appSecret: "your-app-secret",
gatewayServer: "https://nebula-agent.xingyun3d.com/user/v1/ttsa_v2/session",
onMessage(error) {
console.error(error.code, error.message);
},
agentCallbacks: {
onError(error) {
console.error(error.code, error.message);
},
},
});
agentRef.current = agent;
await agent.init({
onDownloadProgress(progress) {
console.log("加载进度", progress.toFixed(0) + "%");
},
});
if (destroyed) {
await agent.destroy("component_unmounted");
}
}
void init().catch((error) => {
if (!destroyed) {
console.error("初始化失败", error);
}
});
return () => {
destroyed = true;
void agentRef.current?.destroy("component_unmounted").catch(console.error);
};
}, []);
return (
<div
ref={containerRef}
style={{
width: "min(100%, 405px)",
aspectRatio: "9 / 16",
overflow: "hidden",
background: "#000",
}}
/>
);
}
export default AvatarComponent;
开发环境的 Strict Mode 可能重复执行 effect 的创建与清理。
destroyed标记用于处理初始化期间发生的卸载;同一实例的destroy()支持重复调用。应在 effect 的 cleanup 中释放该次创建的实例,并捕获初始化和销毁过程中的 Promise 拒绝。