一、前言介绍
AI 从“有大脑”升级到“有身体”,像真人一样自然表达交互! 目前各种大模型快速发展,AI 的“大脑”在某些领域上已经接近真人或者超远真人了,但是就目前而言,AI 并没有拥有过“身体”。 偶然情况下了解到了魔珐星云-具身智能数字人,它可以让大模型不再只是文字或者语音,而是有形象的 AI。抱着好奇心来体验了一下,着实让我十分的震撼! 接下来,就让我给你们介绍一下魔珐星云是什么吧,以及如何使用魔珐星云为你的 AI 赋予“身体”。 魔珐星云官网地址:魔珐星云具身智能3D数字人开放平台 - 全球领先的3D具身智能体基础设施
二、魔珐星云初体验
具身驱动
在魔珐星云平台可以通过文本输入,可以实时生成 3D 数字人的语音、表情、眼神、手势和身体动作等,进而达到能够像真人一样自然表达和交互。 交互界面的右下角提供了不同模型的选择。 成功连接后就可以与其进行交流了,除了文本交流外还可以直接进行电话沟通。不得不说这个动漫数字人的建模和声音确实好评,爱了爱了!快来亲自上手体验一下吧!
除了二次元数字人外,也提供了很多不同角色的数字人。
具身智能交互新生态
六大核心能力
魔珐星云具有六大核心能力
- 高质量 逼真 3D 形象,实时生成自然生动的声音、表情与动作,赋予人物真实可信的表达力。
- 低延时 500ms 驱动响应,交互实时流畅自然;支持随时打断,贴近真人对话体验。
- 低成本 百元级芯片即可运行,大幅降低部署门槛,支持大规模普及。
- 高并发 支持千万级设备同时驱动,轻松应对批量化接入,保障体验稳定可靠。
- 多风格 覆盖超写实、二次元、卡通、美型等多样角色风格和人设,场景和角色可灵活选择。
- 多终端 全面适配手机、车机、Pad、PC、电视与大屏,兼容 Android、iOS、鸿蒙等主流系统。
魔珐星云通过文生3D多模态大模型和AI端渲和解算,真正的打破了3D数字人生成的质量、成本、延时不可能三角,从而真正的支持了AI具身智能大规模应用!
三、如何进行应用创建、配置、管理和调试
- 找到 应用管理,然后点击 创建新应用。
- 输入你的应用名称以及应用备注,并选择预览模式。
- 挑选自己喜欢的形象、场景、音色、表演动作。
- 保存后可以自己进行测试。
选择驱动指令为:ssml 然后可以在中写入自己希望数字人能说的话
四、如果使用SDK进行快速配置开发应用
上一步我们已经在魔珐星云平台上创建了自己的应用,接下来,我们就要通过 SDK 的方式快速开发应用。 我们以 JS SDK 为例 Android 版本的同理。 详细文档:具身驱动SDK(JS版本)接入说明
1. 快速开始
1.1 主要功能
- 实时 3D 数字人渲染与驱动
- 语音合成(SSML 支持)与口型同步
- 多状态行为控制(Idle / Listen / Speak 等)
- Widget 组件展示(图片、字幕、视频等)
- 可自定义事件回调与日志系统
1.2 浏览器版本要求
1.3 引入依赖
<!DOCTYPE html>
<html lang="en">
<body>
<div style="width: 400px;height: 600px">
<div id="sdk"></div>
</div>
<script src="https://media.xingyun3d.com/xingyun3d/general/litesdk/xmovAvatar@latest.js"></script>
</body>
</html>
1.4 创建实例
const LiteSDK = new XmovAvatar({
containerId: '#sdk',
appId: '',
appSecret: '',
gatewayServer: 'https://nebula-agent.xingyun3d.com/user/v1/ttsa/session',
// 自定义渲染器,传递该方法,所有事件sdk均返回,由该方法定义所以类型事件的实现逻辑
onWidgetEvent(data) {
// 处理widget事件
console.log('Widget事件:', data)
},
// 代理渲染器,sdk默认支持subtitle_on、subtitle_off和widget_pic事件。通过代理,
// 可以修改默认事件,业务侧也可实现各种其他事件。
proxyWidget: {
"widget_slideshow": (data: any) => {
console.log("widget_slideshow", data);
},
"widget_video": (data: any) => {
console.log("widget_video", data);
},
},
onNetworkInfo(networkInfo) {
console.log('networkInfo:', networkInfo)
},
onMessage(message) {
console.log('SDK message:', message);
},
onStateChange(state: string) {
console.log('SDK State Change:', state);
},
onStatusChange(status) {
console.log('SDK Status Change:', status);
},
onStateRenderChange(state: string, duration: number) {
console.log('SDK State Change Render:', state, duration);
},
onVoiceStateChange(status:string) {
console.log("sdk voice status", status);
},
enableLogger: false, // 不展示sdk log,默认为false
})
appId、appSecret 需要去应用中查看
1.5 详细参数说明
enum EErrorCode {
// 容器不存在
CONTAINER_NOT_FOUND = 10001,
// socket连接错误
CONNECT_SOCKET_ERROR = 10002,
// 会话错误,start_session进入catch(/api/session的接口数据异常,均使用response.error_code)
START_SESSION_ERROR = 10003,
// 会话错误,stop_session进入catch
STOP_SESSION_ERROR = 10004,
VIDEO_FRAME_EXTRACT_ERROR = 20001, // 视频抽帧错误
INIT_WORKER_ERROR = 20002, // 初始化视频抽帧WORKER错误
PROCESS_VIDEO_STREAM_ERROR = 20003, // 抽帧视频流处理错误
FACE_PROCESSING_ERROR = 20004, // 表情处理错误
BACKGROUND_IMAGE_LOAD_ERROR = 30001, // 背景图片加载错误
FACE_BIN_LOAD_ERROR = 30002, // 表情数据加载错误
INVALID_BODY_NAME = 30003, // body数据无Name
VIDEO_DOWNLOAD_ERROR = 30004, // 视频下载错误
AUDIO_DECODE_ERROR = 40001, // 音频解码错误
FACE_DECODE_ERROR = 40002, // 表情解码错误
VIDEO_DECODE_ERROR = 40003, // 身体视频解码错误
EVENT_DECODE_ERROR = 40004, // 事件解码错误
INVALID_DATA_STRUCTURE = 40005, // ttsa返回数据类型错误,非audio、body、face、event等
TTSA_ERROR = 40006, // ttsa下行发送异常信息
NETWORK_DOWN = 50001, // 离线模式
NETWORK_UP = 50002, // 在线模式
NETWORK_RETRY = 50003, // 网络重试
NETWORK_BREAK = 50004, // 网络断开
}
interface SDKMessage {
code: EErrorCode
message: string
timestamp: number
originalError?: string
}
interface SDKNetworkInfo {
rtt: number // 延迟,毫秒
downlink: number // 下载速率(MB/s)
}
enum SDKStatus {
online = 0,
offline = 1,
network_on = 2,
network_off = 3,
close = 4,
}
1.6 初始化连接房间
初始化 SDK,加载必要资源。
async init({
onDownloadProgress?: (progress: number) => void,
onError: (error: SDKError) => void,
// socket断开
onClose: () => void,
}): Promise<void>
参数说明:
- onDownloadProgress:资源下载进度回调,progress取值范围[0, 100],首次连接bin资源或首个视频资源加载失败时,进度均不会达到100,且内部会调用stopSession。防止用户无法重新连接。
1.7 驱动数字人说话
控制虚拟人说话
speak(ssml: string, is_start: boolean, is_end: boolean): void
参数说明:
- ssml: 可以直接传入需要数字人说的内容,也可以传入SSML格式的标记语言用以指定数字人做出KA动作,详见进阶接入。 非流式调用
speak("欢迎使用魔珐星云", is_start = true, is_end = true)
1.8 销毁实例
销毁SDK实例,断开连接。
destroy(): void
2. 进阶接入
2.1 状态切换
- 语义 KA 指令
<speak>
热烈
<ue4event>
<type>ka_intent</type>
<data><ka_intent>Welcome</ka_intent></data>
</ue4event>
欢迎各位贵宾在百忙之中拨冗莅临指导!您的到来如春风拂面,为我们带来宝贵的经验与智慧,这份肯定与支持让我们备受鼓舞。期待在您的指点下,我们能收获更多成长与启发,共同书写更精彩的篇章!
</speak>
- 技能 KA 指令
<speak>
<ue4event>
<type>ka</type>
<data><action_semantic>dance</action_semantic></data>
</ue4event>
</speak>
- Speak KA 指令
<speak>
<ue4event>
<type>ka</type>
<data><action_semantic>Hello</action_semantic></data>
</ue4event>
欢迎来到星云具身 3D 数字人平台,这里有超多精彩内容等你发现~
</speak>
2.2 声音控制
setVolume(volume: number): void
2.3 调试信息
# 显示调试信息
showDebugInfo(): void
# 隐藏调试信息
hideDebugInfo(): void
3. 快速使用SDK接入3D数字人
3.1 先看效果
进入页面,输入自己创建的应用的 AppID 和 App Secret 点击连接后就可以连接到你在平台上创建的应用了。 可以选择“打招呼”、“聊天气”、“自我介绍”、“祝福语”等一些列的内置内容。 还可以选择状态:待机、聆听。 最下面还可以选择是否展示调试工具。
3.2 完整代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>魔珐星云 - 3D数字人Demo</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Microsoft YaHei', sans-serif;
background: linear-gradient(135deg, #1a1a2e 0%, #16213e 50%, #0f3460 100%);
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
padding: 20px;
}
h1 {
color: #fff;
margin-bottom: 20px;
text-shadow: 0 0 10px rgba(100, 200, 255, 0.5);
}
.container {
display: flex;
gap: 20px;
flex-wrap: wrap;
justify-content: center;
max-width: 1200px;
width: 100%;
}
/* 数字人容器 */
.avatar-container {
width: 500px;
height: 600px;
background: rgba(255, 255, 255, 0.1);
border-radius: 16px;
overflow: hidden;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
position: relative;
}
#avatar-wrapper {
width: 100%;
height: 100%;
}
.loading-overlay {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.7);
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
color: #fff;
z-index: 10;
}
.loading-overlay.hidden {
display: none;
}
.progress-bar {
width: 80%;
height: 8px;
background: rgba(255, 255, 255, 0.2);
border-radius: 4px;
margin-top: 15px;
overflow: hidden;
}
.progress-fill {
height: 100%;
background: linear-gradient(90deg, #00d4ff, #7b2cbf);
border-radius: 4px;
transition: width 0.3s ease;
width: 0%;
}
/* 控制面板 */
.control-panel {
width: 400px;
background: rgba(255, 255, 255, 0.1);
border-radius: 16px;
padding: 24px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
}
.section {
margin-bottom: 20px;
}
.section-title {
color: #00d4ff;
font-size: 14px;
margin-bottom: 12px;
text-transform: uppercase;
letter-spacing: 1px;
}
.input-group {
margin-bottom: 12px;
}
.input-group label {
display: block;
color: #aaa;
font-size: 12px;
margin-bottom: 6px;
}
.input-group input {
width: 100%;
padding: 10px 14px;
border: 1px solid rgba(255, 255, 255, 0.2);
border-radius: 8px;
background: rgba(255, 255, 255, 0.1);
color: #fff;
font-size: 14px;
transition: border-color 0.3s;
}
.input-group input:focus {
outline: none;
border-color: #00d4ff;
}
textarea {
width: 100%;
height: 100px;
padding: 12px;
border: 1px solid rgba(255, 255, 255, 0.2);
border-radius: 8px;
background: rgba(255, 255, 255, 0.1);
color: #fff;
font-size: 14px;
resize: vertical;
font-family: inherit;
}
textarea:focus {
outline: none;
border-color: #00d4ff;
}
.btn-group {
display: flex;
gap: 10px;
flex-wrap: wrap;
}
.btn {
flex: 1;
min-width: 80px;
padding: 12px 16px;
border: none;
border-radius: 8px;
font-size: 14px;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
}
.btn-primary {
background: linear-gradient(135deg, #00d4ff, #7b2cbf);
color: #fff;
}
.btn-primary:hover {
transform: translateY(-2px);
box-shadow: 0 4px 15px rgba(0, 212, 255, 0.4);
}
.btn-secondary {
background: rgba(255, 255, 255, 0.2);
color: #fff;
}
.btn-secondary:hover {
background: rgba(255, 255, 255, 0.3);
}
.btn-danger {
background: #e74c3c;
color: #fff;
}
.btn-danger:hover {
background: #c0392b;
}
.btn:disabled {
opacity: 0.5;
cursor: not-allowed;
transform: none !important;
}
/* 状态指示 */
.status-bar {
display: flex;
align-items: center;
gap: 8px;
padding: 10px 14px;
background: rgba(0, 0, 0, 0.3);
border-radius: 8px;
margin-bottom: 16px;
}
.status-dot {
width: 10px;
height: 10px;
border-radius: 50%;
background: #e74c3c;
}
.status-dot.connected {
background: #2ecc71;
animation: pulse 2s infinite;
}
@keyframes pulse {
0%,
100% {
opacity: 1;
}
50% {
opacity: 0.5;
}
}
.status-text {
color: #fff;
font-size: 13px;
}
/* 快捷短语 */
.quick-phrases {
display: flex;
flex-wrap: wrap;
gap: 8px;
margin-top: 12px;
}
.phrase-btn {
padding: 8px 14px;
background: rgba(255, 255, 255, 0.15);
border: 1px solid rgba(255, 255, 255, 0.2);
border-radius: 20px;
color: #fff;
font-size: 12px;
cursor: pointer;
transition: all 0.3s;
}
.phrase-btn:hover {
background: rgba(0, 212, 255, 0.3);
border-color: #00d4ff;
}
/* 音量控制 */
.volume-control {
display: flex;
align-items: center;
gap: 12px;
}
.volume-control input[type="range"] {
flex: 1;
-webkit-appearance: none;
height: 6px;
background: rgba(255, 255, 255, 0.2);
border-radius: 3px;
outline: none;
}
.volume-control input[type="range"]::-webkit-slider-thumb {
-webkit-appearance: none;
width: 16px;
height: 16px;
background: #00d4ff;
border-radius: 50%;
cursor: pointer;
}
.volume-value {
color: #fff;
font-size: 12px;
min-width: 40px;
}
/* 日志面板 */
.log-panel {
margin-top: 20px;
max-width: 920px;
width: 100%;
}
.log-content {
height: 150px;
background: rgba(0, 0, 0, 0.5);
border-radius: 8px;
padding: 12px;
overflow-y: auto;
font-family: 'Consolas', monospace;
font-size: 12px;
color: #0f0;
}
.log-entry {
margin-bottom: 4px;
padding: 2px 0;
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}
.log-entry.error {
color: #e74c3c;
}
.log-entry.warning {
color: #f39c12;
}
.log-entry.info {
color: #3498db;
}
</style>
</head>
<body>
<h1>🌟 魔珐星云 3D数字人 Demo</h1>
<div class="container">
<!-- 数字人显示区域 -->
<div class="avatar-container">
<div id="avatar-wrapper"></div>
<div class="loading-overlay" id="loading-overlay">
<div>正在加载数字人资源...</div>
<div class="progress-bar">
<div class="progress-fill" id="progress-fill"></div>
</div>
<div id="progress-text" style="margin-top: 10px; font-size: 14px;">0%</div>
</div>
</div>
<!-- 控制面板 -->
<div class="control-panel">
<!-- 状态栏 -->
<div class="status-bar">
<div class="status-dot" id="status-dot"></div>
<span class="status-text" id="status-text">未连接</span>
</div>
<!-- 配置区域 -->
<div class="section">
<div class="section-title">📝 应用配置</div>
<div class="input-group">
<label>App ID</label>
<input type="text" id="appId" placeholder="请输入您的 App ID">
</div>
<div class="input-group">
<label>App Secret</label>
<input type="password" id="appSecret" placeholder="请输入您的 App Secret">
</div>
<div class="btn-group">
<button class="btn btn-primary" id="btn-connect">连接</button>
<button class="btn btn-danger" id="btn-disconnect" disabled>断开</button>
</div>
</div>
<!-- 说话控制 -->
<div class="section">
<div class="section-title">💬 让数字人说话</div>
<textarea id="speak-text" placeholder="输入要让数字人说的话...">欢迎使用魔珐星云3D数字人平台!这里有超多精彩内容等你发现。</textarea>
<div class="btn-group" style="margin-top: 12px;">
<button class="btn btn-primary" id="btn-speak" disabled>开始说话</button>
<button class="btn btn-secondary" id="btn-stop-speak" disabled>停止</button>
</div>
<!-- 快捷短语 -->
<div class="quick-phrases">
<span class="phrase-btn" data-text="你好,很高兴认识你!">👋 打招呼</span>
<span class="phrase-btn" data-text="今天天气真不错,适合出去走走。">🌤️ 聊天气</span>
<span class="phrase-btn" data-text="我是魔珐星云的3D数字人,有什么可以帮助你的吗?">🤖 自我介绍</span>
<span class="phrase-btn" data-text="祝你工作顺利,生活愉快!">🎉 祝福语</span>
</div>
</div>
<!-- 状态切换 -->
<div class="section">
<div class="section-title">🎭 状态控制</div>
<div class="btn-group">
<button class="btn btn-secondary" id="btn-idle" disabled>待机</button>
<button class="btn btn-secondary" id="btn-listen" disabled>聆听</button>
</div>
</div>
<!-- 音量控制 -->
<div class="section">
<div class="section-title">🔊 音量控制</div>
<div class="volume-control">
<span style="color: #aaa;">🔈</span>
<input type="range" id="volume-slider" min="0" max="100" value="80">
<span class="volume-value" id="volume-value">80%</span>
</div>
</div>
<!-- 调试 -->
<div class="section">
<div class="section-title">🔧 调试工具</div>
<div class="btn-group">
<button class="btn btn-secondary" id="btn-show-debug" disabled>显示调试</button>
<button class="btn btn-secondary" id="btn-hide-debug" disabled>隐藏调试</button>
</div>
</div>
</div>
</div>
<!-- 日志面板 -->
<div class="log-panel">
<div class="section-title" style="color: #00d4ff; margin-bottom: 8px;">📋 运行日志</div>
<div class="log-content" id="log-content"></div>
</div>
<!-- 引入魔珐星云SDK -->
<script src="https://media.xingyun3d.com/xingyun3d/general/litesdk/xmovAvatar@latest.js"></script>
<script>
// ==================== 日志系统 ====================
const logContent = document.getElementById('log-content');
function log(message, type = 'info') {
const time = new Date().toLocaleTimeString();
const entry = document.createElement('div');
entry.className = `log-entry ${type}`;
entry.textContent = `[${time}] ${message}`;
logContent.appendChild(entry);
logContent.scrollTop = logContent.scrollHeight;
}
// ==================== DOM元素 ====================
const elements = {
appId: document.getElementById('appId'),
appSecret: document.getElementById('appSecret'),
btnConnect: document.getElementById('btn-connect'),
btnDisconnect: document.getElementById('btn-disconnect'),
btnSpeak: document.getElementById('btn-speak'),
btnStopSpeak: document.getElementById('btn-stop-speak'),
btnIdle: document.getElementById('btn-idle'),
btnListen: document.getElementById('btn-listen'),
btnShowDebug: document.getElementById('btn-show-debug'),
btnHideDebug: document.getElementById('btn-hide-debug'),
speakText: document.getElementById('speak-text'),
volumeSlider: document.getElementById('volume-slider'),
volumeValue: document.getElementById('volume-value'),
statusDot: document.getElementById('status-dot'),
statusText: document.getElementById('status-text'),
loadingOverlay: document.getElementById('loading-overlay'),
progressFill: document.getElementById('progress-fill'),
progressText: document.getElementById('progress-text'),
};
// ==================== SDK实例 ====================
let avatarSDK = null;
let isConnected = false;
// ==================== 更新UI状态 ====================
function updateUIState(connected) {
isConnected = connected;
elements.btnConnect.disabled = connected;
elements.btnDisconnect.disabled = !connected;
elements.btnSpeak.disabled = !connected;
elements.btnStopSpeak.disabled = !connected;
elements.btnIdle.disabled = !connected;
elements.btnListen.disabled = !connected;
elements.btnShowDebug.disabled = !connected;
elements.btnHideDebug.disabled = !connected;
elements.statusDot.classList.toggle('connected', connected);
elements.statusText.textContent = connected ? '已连接' : '未连接';
}
// ==================== 连接SDK ====================
async function connectSDK() {
const appId = elements.appId.value.trim();
const appSecret = elements.appSecret.value.trim();
if (!appId || !appSecret) {
log('请输入 App ID 和 App Secret', 'error');
alert('请输入 App ID 和 App Secret');
return;
}
log('正在创建SDK实例...', 'info');
elements.loadingOverlay.classList.remove('hidden');
try {
// 创建SDK实例
avatarSDK = new XmovAvatar({
containerId: '#avatar-wrapper',
appId: appId,
appSecret: appSecret,
gatewayServer: 'https://nebula-agent.xingyun3d.com/user/v1/ttsa/session',
// Widget事件回调
onWidgetEvent(data) {
log(`Widget事件: ${JSON.stringify(data)}`, 'info');
},
// 错误回调
onError(error) {
log(`错误: ${JSON.stringify(error)}`, 'error');
},
// 语音状态变化回调
onVoiceStateChange(state) {
log(`语音状态: ${state}`, 'info');
if (state === 'voice_start') {
elements.statusText.textContent = '正在说话...';
} else if (state === 'voice_end') {
elements.statusText.textContent = '已连接';
}
},
// 连接状态回调
onConnectionStateChange(state) {
log(`连接状态: ${state}`, 'info');
}
});
log('正在初始化SDK...', 'info');
// 初始化SDK
await avatarSDK.init({
onDownloadProgress: (progress) => {
elements.progressFill.style.width = `${progress}%`;
elements.progressText.textContent = `${Math.round(progress)}%`;
log(`资源下载进度: ${Math.round(progress)}%`, 'info');
}
});
elements.loadingOverlay.classList.add('hidden');
updateUIState(true);
log('SDK初始化成功!数字人已就绪', 'info');
// 设置初始音量
const volume = elements.volumeSlider.value / 100;
avatarSDK.setVolume(volume);
} catch (error) {
elements.loadingOverlay.classList.add('hidden');
log(`连接失败: ${error.message || error}`, 'error');
alert('连接失败,请检查 App ID 和 App Secret 是否正确');
}
}
// ==================== 断开连接 ====================
function disconnectSDK() {
if (avatarSDK) {
avatarSDK.destroy();
avatarSDK = null;
log('已断开连接', 'warning');
}
updateUIState(false);
}
// ==================== 让数字人说话 ====================
function speak() {
if (!avatarSDK || !isConnected) return;
const text = elements.speakText.value.trim();
if (!text) {
log('请输入要说的内容', 'warning');
return;
}
log(`数字人开始说话: ${text}`, 'info');
avatarSDK.speak(text, true, true);
}
// ==================== 停止说话 ====================
function stopSpeak() {
if (!avatarSDK || !isConnected) return;
// 切换到待机状态来停止说话
avatarSDK.interactive_idle();
log('已停止说话', 'info');
}
// ==================== 状态切换 ====================
function setIdle() {
if (!avatarSDK || !isConnected) return;
avatarSDK.interactive_idle();
log('切换到待机状态', 'info');
}
function setListen() {
if (!avatarSDK || !isConnected) return;
avatarSDK.listen();
log('切换到聆听状态', 'info');
}
// ==================== 音量控制 ====================
function updateVolume() {
const volume = elements.volumeSlider.value / 100;
elements.volumeValue.textContent = `${elements.volumeSlider.value}%`;
if (avatarSDK && isConnected) {
avatarSDK.setVolume(volume);
log(`音量设置为: ${elements.volumeSlider.value}%`, 'info');
}
}
// ==================== 调试工具 ====================
function showDebug() {
if (avatarSDK && isConnected) {
avatarSDK.showDebugInfo();
log('已显示调试信息', 'info');
}
}
function hideDebug() {
if (avatarSDK && isConnected) {
avatarSDK.hideDebugInfo();
log('已隐藏调试信息', 'info');
}
}
// ==================== 快捷短语 ====================
function handleQuickPhrase(e) {
if (e.target.classList.contains('phrase-btn')) {
const text = e.target.dataset.text;
elements.speakText.value = text;
if (isConnected) {
speak();
}
}
}
// ==================== 事件绑定 ====================
elements.btnConnect.addEventListener('click', connectSDK);
elements.btnDisconnect.addEventListener('click', disconnectSDK);
elements.btnSpeak.addEventListener('click', speak);
elements.btnStopSpeak.addEventListener('click', stopSpeak);
elements.btnIdle.addEventListener('click', setIdle);
elements.btnListen.addEventListener('click', setListen);
elements.btnShowDebug.addEventListener('click', showDebug);
elements.btnHideDebug.addEventListener('click', hideDebug);
elements.volumeSlider.addEventListener('input', updateVolume);
document.querySelector('.quick-phrases').addEventListener('click', handleQuickPhrase);
// 页面卸载时清理资源
window.addEventListener('beforeunload', () => {
if (avatarSDK) {
avatarSDK.destroy();
}
});
// 初始化日志
log('页面加载完成,请输入 App ID 和 App Secret 后点击连接', 'info');
log('提示:请在 https://xingyun3d.com/ 创建应用获取凭证', 'info');
</script>
</body>
</html>
可以在git仓库中找到哦! github地址:github.com/Worldfickle…
五、常见问题及解决方案
- 确保容器元素具有明确的宽高,否则可能影响渲染效果
- 初始化时必须提供所有必填参数
- 使用destroy()方法时会清理所有资源并断开连接
- 建议在开发环境使用showDebugInfo()辅助调试
六、总结
体验下来,魔珐星云的具身智能确实不错,提供了一个 3D 数字人开发的平台,更提供了 SDK 来方便开发者快速开发应用。我们不能可以在星云平台上快速构建具身智能应用,从虚拟陪伴到机器人交互,从桌面小助手到车载交互界面,都可以快速的实现。 如果你也感兴趣的话,那就快来体验一下吧!
可以通过下方专属链接进行体验喔 专属链接:xingyun3d.com/?utm_campai…