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";

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 type="module">
import XingyunAvatarAgent from "@xmov/avatar/agent";

const agent = new XingyunAvatarAgent({
container: document.getElementById("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);
},
},
});

agent.init({
onDownloadProgress(progress) {
console.log("加载进度", progress.toFixed(0) + "%");
},
});

window.addEventListener("beforeunload", () => {
void agent.destroy("page_unload");
});
</script>
</body>
</html>

Vue 3

<script setup>
import { ref, onBeforeUnmount } from "vue";
import XingyunAvatarAgent from "@xmov/avatar/agent";

const container = ref(null);
const agent = ref(null);

onBeforeUnmount(async () => {
await agent.value?.destroy("component_unmount");
});

async function init() {
agent.value = new XingyunAvatarAgent({
container: container.value,
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);
},
},
});

await agent.value.init({
onDownloadProgress(progress) {
console.log("加载进度", progress.toFixed(0) + "%");
},
});
}

init();
</script>

<template>
<div
ref="container"
style="width: min(100%, 405px); aspect-ratio: 9 / 16; overflow: hidden; background: #000;"
></div>
</template>

注意:Vue 中建议使用 container(DOM 元素)而非 containerId,避免组件多实例复用同一 id;卸载时务必调用 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 agent = new XingyunAvatarAgent({
container: containerRef.current,
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");
}
}

init();

return () => {
destroyed = true;
void agentRef.current?.destroy("component_unmounted");
};
}, []);

return (
<div
ref={containerRef}
style={{
width: "min(100%, 405px)",
aspectRatio: "9 / 16",
overflow: "hidden",
background: "#000",
}}
/>
);
}

export default AvatarComponent;

注意:React 18+ 开发环境(Strict Mode)会双调用 useEffect,示例通过 destroyed 标记保证只销毁一次并避免泄漏;请用 container 挂载到 ref,不要在多个组件实例间共享同一个 containerId