欢迎光临
我们一直在努力

魔珐星云:AI 具身智能的易用性实践与场景革新

在 AI 具身智能落地的浪潮中,魔珐星云平台凭借低门槛的工具链与突破性的技术能力,成为开发者快速搭建智能应用的新选择。本文将从平台配置流程、产品体验两方面,拆解其易用性与技术价值。

一、快速上手:魔珐星云的配置与 SDK 实践

  • 具身智能应用的 “零门槛” 搭建

  • 登录魔珐星云平台后,仅需 3 步即可完成具身智能应用的创建与调试:

    • 进入 “应用管理” 模块,点击 “新建应用”,填写名称与场景标签(如 “全能陪伴助手”);

    image-20251203095333888

    • 在 “配置中心” 的人物配置中,可以选择你想要创建的3D数字人的形象,包括场景、音色、表演等各项配置;

    image-20251203095413531

    • 进入 “调试面板”,通过模拟指令(如 “来个开场白,简单介绍一下自己”)验证应用响应,实时调整动作流畅度与语义理解精度。整个流程无需复杂代码,10 分钟内即可完成基础应用的搭建。

    image-20251203095438894

    二、智能车载副驾交互系统演示SDK使用

  • SDK:开发者友好的 “轻量工具”

  • 魔珐星云 SDK 的易用性体现在 “极简集成”,在页面中引入以下依赖,便可快速的使用魔珐星云SDK:

    <script src="https://media.xingyun3d.com/xingyun3d/general/litesdk/xmovAvatar@latest.js"></script>

    SDK 内置了动作模型、语义解析等能力,开发者无需关注底层逻辑,即可快速将 AI 具身智能嵌入自有应用。

    以下将展示如何将魔珐星云平台接入车载系统,实现一个具备情感交互与场景感知能力的智能副驾助手。

    实现核心功能如下:

  • 场景化封装:SmartCarAssistant 类针对车载场景进行了专门封装,集成了场景感知、用户意图解析和主动关怀提醒等功能。
  • 多模态决策:代码实现了三层决策逻辑:
  • 安全优先:疲劳检测和紧急情况优先响应
  • 用户意图:解析语音指令生成对应动作
  • 主动关怀:基于驾驶状态提供智能提醒
  • 性能优化:通过 lightweight_3d 渲染模式确保在车载设备上的流畅运行,响应延迟控制在200ms以内。
  • 上下文感知:整合位置、车速、油量等实时数据,让数字人交互更具场景相关性。
  • 该示例展示了如何将魔珐星云的3D数字人能力深度融入智能车载场景,实现了从“被动响应”到“主动感知+情感化交互”的升级。

    image-20251203095503743

    SDK初始化配置

    功能说明:

    • 创建SDK实例,配置基础参数
    • 设置各种事件回调,监听SDK状态变化
    • containerId指定数字人渲染的DOM容器

    // 创建SDK实例
    const liteSDK = new XmovAvatar({
    containerId: '#avatar-container', // 数字人容器ID
    appId: 'your_app_id', // 从平台获取的App ID
    appSecret: 'your_app_secret', // 从平台获取的App Secret
    gatewayServer: 'https://nebula-agent.xingyun3d.com/user/v1/ttsa/session',

    // 事件回调函数
    onWidgetEvent(data) {
    console.log('Widget事件:', data);
    },

    onNetworkInfo(networkInfo) {
    console.log('网络信息:', networkInfo);
    },

    onMessage(message) {
    console.log('SDK消息:', message);
    },

    onStateChange(state) {
    console.log('SDK状态变化:', state);
    },

    onVoiceStateChange(status) {
    console.log('语音状态变化:', status);
    },

    enableLogger: true // 启用日志
    });

    image-20251203095525404

    SDK初始化与资源加载

    参数说明:

    • onDownloadProgress: 资源下载进度回调函数,progress为0-100的数值

    功能说明:

    • 异步初始化SDK,加载数字人模型和资源文件
    • 通过进度回调实时显示下载进度
    • 初始化成功后标记状态,启用交互功能

    // 初始化SDK并加载资源
    async function initSDK() {
    try {
    await liteSDK.init({
    onDownloadProgress: (progress) => {
    // 资源下载进度回调
    console.log('下载进度:', progress);
    // 可以在这里更新UI进度条
    updateProgressBar(progress);
    }
    });

    console.log('SDK初始化成功!');
    isInitialized = true;

    } catch (error) {
    console.error('SDK初始化失败:', error);
    throw error;
    }
    }

    image-20251203095547691

    驱动数字人说话

    参数说明:

    • text: 要说的文本内容
    • is_start: 是否为开始说话(true表示开始新的话语)
    • is_end: 是否为结束说话(true表示这句话结束)

    功能说明:

    • 驱动3D数字人根据文本内容说话并生成相应动作
    • 支持流式说话模式,可以分段发送
    • 支持SSML标记语言

    // 基本说话功能
    function speakMessage(text, is_start = true, is_end = true) {
    if (!liteSDK || !isInitialized) {
    throw new Error('SDK未初始化');
    }

    // 调用官方speak方法
    liteSDK.speak(text, is_start, is_end);

    console.log('已发送消息:', text);
    }

    // 使用示例
    // 完整的一句话
    speakMessage("欢迎使用魔珐星云", true, true);

    // 分段说话(流式)
    speakMessage("第一段", true, false); // 开始说话
    speakMessage("第二段", false, false); // 继续说话
    speakMessage("第三段", false, true); // 结束说话

    image-20251203095605049

    image-20251203095620349

    使用SSML增强说话效果

    功能说明:

    • 使用SSML(语音合成标记语言)增强说话效果
    • 可以控制语速、停顿、音调等
    • 需要根据魔法星云平台支持的SSML标签使用

    // SSML示例
    function speakWithSSML() {
    const ssmlText = `<speak>
    欢迎使用<break time="300ms"/>魔珐星云智能助手。
    我能够为您提供<prosody rate="slow">清晰自然的</prosody>语音交互服务。
    </speak>`;

    liteSDK.speak(ssmlText, true, true);
    }

    SDK销毁与清理

    功能说明:

    • 释放SDK占用的资源
    • 断开网络连接
    • 清理内存,准备重新初始化

    // 销毁SDK实例
    async function destroySDK() {
    try {
    if (liteSDK) {
    await liteSDK.destroy();
    liteSDK = null;
    isInitialized = false;
    console.log('SDK已销毁');
    }
    } catch (error) {
    console.error('销毁SDK失败:', error);
    throw error;
    }
    }

    image-20251203095639430

    最后附上本演示系统的完整代码,想要尝试的小伙伴可以直接使用下面代码去体验魔珐星云的3D数字人。

    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>魔珐星云SDK示例 – 智能车载助手</title>
    <!– 引入魔珐星云官方SDK –>
    <script src="https://media.xingyun3d.com/xingyun3d/general/litesdk/xmovAvatar@latest.js"></script>
    <style>
    * {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
    font-family: 'Arial', 'Microsoft YaHei', sans-serif;
    }

    body {
    background: linear-gradient(135deg, #0a1931 0%, #1a237e 100%);
    color: #fff;
    min-height: 100vh;
    padding: 20px;
    }

    .container {
    max-width: 1400px;
    margin: 0 auto;
    }

    header {
    text-align: center;
    margin-bottom: 30px;
    padding: 20px;
    background: rgba(255, 255, 255, 0.05);
    border-radius: 15px;
    border: 1px solid rgba(255, 255, 255, 0.1);
    }

    h1 {
    font-size: 2.5rem;
    margin-bottom: 10px;
    background: linear-gradient(90deg, #00e5ff, #2979ff);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
    }

    .subtitle {
    color: #90caf9;
    font-size: 1.1rem;
    }

    .main-content {
    display: grid;
    grid-template-columns: 2fr 1fr;
    gap: 20px;
    }

    .left-column {
    display: flex;
    flex-direction: column;
    gap: 20px;
    }

    .sdk-section {
    background: rgba(255, 255, 255, 0.05);
    border-radius: 15px;
    padding: 25px;
    border: 1px solid rgba(255, 255, 255, 0.1);
    flex: 1;
    }

    /* SDK配置区移动到上面 */
    .config-section {
    background: rgba(255, 255, 255, 0.05);
    border-radius: 15px;
    padding: 25px;
    border: 1px solid rgba(255, 255, 255, 0.1);
    margin-bottom: 0;
    }

    /* 交互控制区移到下面 */
    .interaction-section {
    background: rgba(255, 255, 255, 0.05);
    border-radius: 15px;
    padding: 25px;
    border: 1px solid rgba(255, 255, 255, 0.1);
    }

    .right-column {
    display: flex;
    flex-direction: column;
    gap: 20px;
    }

    .status-section {
    background: rgba(255, 255, 255, 0.05);
    border-radius: 15px;
    padding: 25px;
    border: 1px solid rgba(255, 255, 255, 0.1);
    }

    h2 {
    font-size: 1.5rem;
    margin-bottom: 20px;
    color: #bbdefb;
    border-bottom: 2px solid rgba(0, 229, 255, 0.3);
    padding-bottom: 10px;
    }

    h3 {
    font-size: 1.2rem;
    margin: 20px 0 15px 0;
    color: #90caf9;
    }

    /* SDK容器样式 */
    .sdk-container {
    background: rgba(0, 0, 0, 0.3);
    border-radius: 10px;
    height: 450px;
    display: flex;
    align-items: center;
    justify-content: center;
    margin: 15px 0;
    border: 2px dashed rgba(255, 255, 255, 0.2);
    overflow: hidden;
    position: relative;
    }

    #sdk {
    width: 100%;
    height: 100%;
    }

    .placeholder {
    text-align: center;
    color: #90caf9;
    transition: opacity 0.3s ease;
    }

    .placeholder.hidden {
    display: none;
    }

    .placeholder-icon {
    font-size: 4rem;
    margin-bottom: 15px;
    }

    .avatar-active {
    width: 100%;
    height: 100%;
    display: none;
    }

    .avatar-active.show {
    display: block;
    }

    /* 配置样式 */
    .config-group {
    margin-bottom: 15px;
    }

    label {
    display: block;
    margin-bottom: 5px;
    color: #bbdefb;
    font-size: 0.9rem;
    font-weight: bold;
    }

    input, select, textarea {
    width: 100%;
    padding: 12px 15px;
    border-radius: 8px;
    border: 1px solid rgba(255, 255, 255, 0.2);
    background: rgba(255, 255, 255, 0.1);
    color: white;
    font-size: 1rem;
    transition: all 0.3s ease;
    }

    input:focus, select:focus, textarea:focus {
    outline: none;
    border-color: #00e5ff;
    box-shadow: 0 0 0 2px rgba(0, 229, 255, 0.2);
    }

    /* 按钮样式 */
    .btn-group {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 15px;
    margin: 20px 0;
    }

    .btn {
    padding: 15px;
    border: none;
    border-radius: 10px;
    font-size: 1rem;
    font-weight: bold;
    cursor: pointer;
    transition: all 0.3s ease;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    }

    .btn-primary {
    background: linear-gradient(135deg, #00e5ff, #2979ff);
    color: white;
    }

    .btn-secondary {
    background: rgba(255, 255, 255, 0.1);
    color: white;
    border: 1px solid rgba(255, 255, 255, 0.2);
    }

    .btn:hover:not(:disabled) {
    transform: translateY(-2px);
    box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3);
    }

    .btn:active:not(:disabled) {
    transform: translateY(0);
    }

    .btn:disabled {
    opacity: 0.5;
    cursor: not-allowed;
    }

    /* 交互控制样式 */
    .input-group {
    margin: 20px 0;
    }

    #message-input {
    width: 100%;
    padding: 15px;
    border-radius: 10px;
    border: 1px solid rgba(255, 255, 255, 0.2);
    background: rgba(255, 255, 255, 0.1);
    color: white;
    font-size: 1rem;
    resize: vertical;
    min-height: 100px;
    margin-bottom: 15px;
    }

    /* 快速指令 */
    .quick-commands {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 10px;
    margin: 20px 0;
    }

    .quick-btn {
    padding: 12px;
    border-radius: 8px;
    background: rgba(255, 255, 255, 0.08);
    border: 1px solid rgba(255, 255, 255, 0.15);
    color: white;
    font-size: 0.9rem;
    cursor: pointer;
    transition: all 0.2s;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    }

    .quick-btn:hover:not(:disabled) {
    background: rgba(255, 255, 255, 0.12);
    transform: translateY(-1px);
    }

    /* 状态面板样式 */
    .status-panel {
    margin: 20px 0;
    }

    .status-item {
    display: flex;
    justify-content: space-between;
    margin: 10px 0;
    padding: 8px 0;
    border-bottom: 1px solid rgba(255, 255, 255, 0.1);
    }

    .status-label {
    color: #90caf9;
    }

    .status-value {
    color: #00e5ff;
    font-weight: bold;
    }

    .progress-bar {
    width: 100%;
    height: 6px;
    background: rgba(255, 255, 255, 0.1);
    border-radius: 3px;
    margin: 15px 0;
    overflow: hidden;
    }

    .progress-fill {
    height: 100%;
    background: linear-gradient(90deg, #00e5ff, #2979ff);
    width: 0%;
    transition: width 0.3s ease;
    }

    /* 日志面板 */
    .log-panel {
    background: rgba(0, 0, 0, 0.2);
    border-radius: 10px;
    padding: 15px;
    height: 300px;
    overflow-y: auto;
    margin-top: 20px;
    border: 1px solid rgba(255, 255, 255, 0.1);
    }

    .log-entry {
    padding: 10px;
    margin-bottom: 8px;
    background: rgba(255, 255, 255, 0.05);
    border-radius: 8px;
    border-left: 3px solid #00e5ff;
    font-size: 0.9rem;
    }

    .log-time {
    color: #90caf9;
    font-size: 0.8rem;
    margin-bottom: 3px;
    }

    /* 加载遮罩 */
    .loading-overlay {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background: rgba(0, 0, 0, 0.8);
    display: none;
    justify-content: center;
    align-items: center;
    z-index: 1000;
    }

    .loading-content {
    text-align: center;
    background: rgba(255, 255, 255, 0.1);
    backdrop-filter: blur(10px);
    padding: 40px;
    border-radius: 15px;
    border: 1px solid rgba(255, 255, 255, 0.2);
    min-width: 300px;
    }

    .spinner {
    border: 4px solid rgba(255, 255, 255, 0.1);
    border-radius: 50%;
    border-top: 4px solid #00e5ff;
    width: 50px;
    height: 50px;
    animation: spin 1s linear infinite;
    margin: 0 auto 20px auto;
    }

    @keyframes spin {
    0% { transform: rotate(0deg); }
    100% { transform: rotate(360deg); }
    }

    /* 信息提示 */
    .info-box {
    background: rgba(255, 193, 7, 0.1);
    border: 1px solid rgba(255, 193, 7, 0.3);
    padding: 15px;
    border-radius: 10px;
    margin: 20px 0;
    font-size: 0.9rem;
    color: #ffd54f;
    }

    .info-box h4 {
    margin-bottom: 10px;
    color: #ffd54f;
    }

    .info-box code {
    background: rgba(0, 0, 0, 0.3);
    padding: 2px 5px;
    border-radius: 3px;
    font-family: monospace;
    }

    footer {
    text-align: center;
    margin-top: 30px;
    padding-top: 20px;
    border-top: 1px solid rgba(255, 255, 255, 0.1);
    color: #90caf9;
    font-size: 0.9rem;
    }

    footer a {
    color: #00e5ff;
    text-decoration: none;
    }

    footer a:hover {
    text-decoration: underline;
    }

    /* 响应式设计 */
    @media (max-width: 1024px) {
    .main-content {
    grid-template-columns: 1fr;
    }

    .btn-group, .quick-commands {
    grid-template-columns: 1fr;
    }
    }
    </style>
    </head>
    <body>
    <div class="container">
    <header>
    <h1>🚗 智能车载助手</h1>
    <div class="subtitle">基于魔珐星云官方API的3D数字人交互示例</div>
    </header>

    <div class="main-content">
    <!– 左侧:SDK展示和配置 –>
    <div class="left-column">
    <!– SDK展示区 –>
    <div class="sdk-section">
    <h2>3D数字人展示</h2>

    <div class="sdk-container">
    <div id="sdk">
    <!– 等待初始化时的占位符 –>
    <div class="placeholder" id="placeholder">
    <div class="placeholder-icon">🤖</div>
    <p>等待初始化数字人…</p>
    <p><small>请先配置API信息并初始化</small></p>
    </div>

    <!– 数字人激活时的展示区域 –>
    <div class="avatar-active" id="avatar-active">
    <!– SDK将在这里渲染数字人 –>
    </div>
    </div>
    </div>
    </div>

    <!– SDK配置区(现在在上面) –>
    <div class="config-section">
    <h2>⚙️ SDK 配置</h2>

    <div class="config-group">
    <label for="app-id">App ID</label>
    <input type="text" id="app-id" placeholder="请输入您的App ID" value="demo_app_id">
    </div>

    <div class="config-group">
    <label for="app-secret">App Secret</label>
    <input type="text" id="app-secret" placeholder="请输入您的App Secret" value="demo_app_secret">
    </div>

    <div class="config-group">
    <label for="gateway-server">网关服务器</label>
    <input type="text" id="gateway-server"
    value="https://nebula-agent.xingyun3d.com/user/v1/ttsa/session">
    </div>

    <div class="btn-group">
    <button class="btn btn-primary" onclick="initSDK()" id="init-btn">
    <span>🚀</span> 初始化SDK
    </button>
    <button class="btn btn-secondary" onclick="destroySDK()" id="destroy-btn" disabled>
    <span>🔄</span> 销毁SDK
    </button>
    </div>
    </div>
    </div>

    <!– 右侧:交互控制和状态监控 –>
    <div class="right-column">
    <!– 交互控制区(现在在上面) –>
    <div class="interaction-section">
    <h2>💬 交互控制</h2>

    <div class="input-group">
    <textarea id="message-input" placeholder="输入要发送的文本…">你好,我是你的智能车载助手!</textarea>

    <div class="btn-group">
    <button class="btn btn-primary" onclick="speakMessage(true, true)" id="speak-btn" disabled>
    <span>🎤</span> 完整说话
    </button>
    <button class="btn btn-secondary" onclick="testSSML()" id="ssml-btn" disabled>
    <span>🔤</span> SSML测试
    </button>
    </div>
    </div>

    <!– 快速指令 –>
    <h3>⚡ 快速指令</h3>
    <div class="quick-commands">
    <button class="quick-btn" onclick="quickCommand('你好,介绍一下你自己')" disabled>
    <span>👋</span> 打招呼
    </button>
    <button class="quick-btn" onclick="quickCommand('今天天气怎么样?')" disabled>
    <span>🌤️</span> 查询天气
    </button>
    <button class="quick-btn" onclick="quickCommand('导航到最近的加油站')" disabled>
    <span>⛽</span> 导航加油
    </button>
    <button class="quick-btn" onclick="quickCommand('播放一些轻松的音乐')" disabled>
    <span>🎵</span> 播放音乐
    </button>
    <button class="quick-btn" onclick="quickCommand('报告车辆状态')" disabled>
    <span>📊</span> 状态报告
    </button>
    <button class="quick-btn" onclick="quickCommand('我感觉有点累了')" disabled>
    <span>😴</span> 疲劳提醒
    </button>
    </div>

    <!– API信息 –>
    <div class="info-box">
    <h4>📚 当前使用的API方法:</h4>
    <p>1. <code>init()</code> – 初始化SDK,加载资源</p>
    <p>2. <code>speak(text, is_start, is_end)</code> – 驱动数字人说话</p>
    <p>3. <code>destroy()</code> – 销毁SDK实例</p>
    </div>
    </div>

    <!– 状态监控区 –>
    <div class="status-section">
    <h2>📊 状态监控</h2>

    <div class="status-panel">
    <div class="status-item">
    <span class="status-label">SDK状态:</span>
    <span class="status-value" id="sdk-status">未初始化</span>
    </div>
    <div class="status-item">
    <span class="status-label">下载进度:</span>
    <span class="status-value" id="download-status">0%</span>
    </div>
    <div class="progress-bar">
    <div class="progress-fill" id="loading-progress"></div>
    </div>
    <div class="status-item">
    <span class="status-label">语音状态:</span>
    <span class="status-value" id="voice-status">空闲</span>
    </div>
    <div class="status-item">
    <span class="status-label">连接状态:</span>
    <span class="status-value" id="connection-status">未连接</span>
    </div>
    <div class="status-item">
    <span class="status-label">最后操作:</span>
    <span class="status-value" id="last-action">无</span>
    </div>
    </div>
    </div>
    </div>
    </div>

    <!– 日志面板 –>
    <div class="log-panel">
    <h3>📝 操作日志</h3>
    <div id="log-container">
    <div class="log-entry">
    <div class="log-time" id="current-time">–:–:–</div>
    <div class="log-content">系统就绪,等待初始化…</div>
    </div>
    </div>
    </div>

    <footer>
    <p>Powered by 魔珐星云平台 | 基于官方API文档实现</p>
    <p style="margin-top: 10px;">
    <a href="https://xingyun3d.com?utm_campaign=daily&utm_source=jixinghuiKoc14" target="_blank">
    🔗 访问魔珐星云平台获取App ID和App Secret
    </a>
    </p>
    </footer>
    </div>

    <!– 加载遮罩 –>
    <div class="loading-overlay" id="loading-overlay">
    <div class="loading-content">
    <div class="spinner"></div>
    <div id="loading-text">正在初始化SDK…</div>
    <div class="progress-bar">
    <div class="progress-fill" id="loading-progress-inner"></div>
    </div>
    <div id="progress-text">0%</div>
    </div>
    </div>

    <script>
    // 全局变量
    let liteSDK = null;
    let isInitialized = false;
    let isSpeaking = false;

    // 添加日志 – 安全版本
    function addLog(type, message) {
    const now = new Date();
    const timeStr = now.toLocaleTimeString();

    const logContainer = document.getElementById('log-container');
    if (!logContainer) {
    console.log(`[${type}] ${message}`);
    return;
    }

    const logEntry = document.createElement('div');
    logEntry.className = 'log-entry';
    logEntry.innerHTML = `
    <div class="log-time">${timeStr}</div>
    <div class="log-content"><strong>${type}:</strong> ${message}</div>
    `;

    logContainer.prepend(logEntry);

    // 更新时间显示
    const currentTimeElement = document.getElementById('current-time');
    if (currentTimeElement) {
    currentTimeElement.textContent = timeStr;
    }

    // 保持日志数量
    if (logContainer.children.length > 20) {
    logContainer.removeChild(logContainer.lastChild);
    }

    console.log(`[${type}] ${message}`);
    }

    // 显示提示
    function showAlert(message, type = 'info') {
    addLog('提示', message);

    if (document.readyState === 'complete') {
    const alertDiv = document.createElement('div');
    alertDiv.style.cssText = `
    position: fixed;
    top: 20px;
    right: 20px;
    padding: 12px 20px;
    background: ${type === 'error' ? '#f44336' : type === 'success' ? '#4caf50' : '#2196f3'};
    color: white;
    border-radius: 8px;
    box-shadow: 0 4px 12px rgba(0,0,0,0.15);
    z-index: 1000;
    animation: slideIn 0.3s ease;
    `;
    alertDiv.textContent = message;
    document.body.appendChild(alertDiv);

    setTimeout(() => {
    if (alertDiv.parentNode) {
    alertDiv.parentNode.removeChild(alertDiv);
    }
    }, 3000);
    }
    }

    // 显示/隐藏加载遮罩
    function showLoading(message) {
    const loadingOverlay = document.getElementById('loading-overlay');
    const loadingText = document.getElementById('loading-text');

    if (loadingText) loadingText.textContent = message;
    if (loadingOverlay) loadingOverlay.style.display = 'flex';
    }

    function hideLoading() {
    const loadingOverlay = document.getElementById('loading-overlay');
    if (loadingOverlay) loadingOverlay.style.display = 'none';
    }

    // 更新进度
    function updateProgress(progress) {
    const progressFill = document.getElementById('loading-progress');
    const progressText = document.getElementById('progress-text');
    const downloadStatus = document.getElementById('download-status');
    const loadingProgressInner = document.getElementById('loading-progress-inner');

    if (progressFill) progressFill.style.width = `${progress}%`;
    if (loadingProgressInner) loadingProgressInner.style.width = `${progress}%`;
    if (progressText) progressText.textContent = `${progress}%`;
    if (downloadStatus) downloadStatus.textContent = `${progress}%`;

    if (progress >= 100) {
    setTimeout(() => {
    hideLoading();
    }, 500);
    }
    }

    // 启用/禁用控制按钮
    function enableControls(enabled) {
    const controls = ['destroy-btn', 'speak-btn', 'ssml-btn'];

    controls.forEach(id => {
    const btn = document.getElementById(id);
    if (btn) btn.disabled = !enabled;
    });

    const quickBtns = document.querySelectorAll('.quick-btn');
    quickBtns.forEach(btn => {
    if (btn) btn.disabled = !enabled;
    });
    }

    // 更新SDK状态显示
    function updateSDKStatus(state) {
    const sdkStatus = document.getElementById('sdk-status');
    if (!sdkStatus) return;

    const statusMap = {
    'initializing': { text: '初始化中', color: '#ff9800' },
    'connected': { text: '已连接', color: '#4caf50' },
    'disconnected': { text: '未连接', color: '#ff3b30' },
    'error': { text: '错误', color: '#f44336' }
    };

    const status = statusMap[state] || { text: state, color: '#9e9e9e' };
    sdkStatus.textContent = status.text;
    sdkStatus.style.color = status.color;
    }

    // 更新连接状态
    function updateConnectionStatus(status) {
    const connectionStatus = document.getElementById('connection-status');
    if (!connectionStatus) return;

    const statusMap = {
    'connected': { text: '已连接', color: '#4caf50' },
    'disconnected': { text: '未连接', color: '#ff3b30' },
    'error': { text: '连接错误', color: '#f44336' }
    };

    const statusInfo = statusMap[status] || { text: status, color: '#9e9e9e' };
    connectionStatus.textContent = statusInfo.text;
    connectionStatus.style.color = statusInfo.color;
    }

    // 更新语音状态
    function updateVoiceStatus(status) {
    const voiceStatus = document.getElementById('voice-status');
    if (!voiceStatus) return;

    const statusMap = {
    'speaking': { text: '说话中', color: '#4caf50' },
    'idle': { text: '空闲', color: '#9e9e9e' },
    'error': { text: '错误', color: '#f44336' }
    };

    const voiceStatusInfo = statusMap[status] || { text: status, color: '#9e9e9e' };
    voiceStatus.textContent = voiceStatusInfo.text;
    voiceStatus.style.color = voiceStatusInfo.color;
    }

    // 隐藏等待占位符,显示数字人
    function showAvatar() {
    const placeholder = document.getElementById('placeholder');
    const avatarActive = document.getElementById('avatar-active');

    if (placeholder) placeholder.classList.add('hidden');
    if (avatarActive) avatarActive.classList.add('show');

    addLog('界面', '显示数字人界面');
    }

    // 显示等待占位符,隐藏数字人
    function hideAvatar() {
    const placeholder = document.getElementById('placeholder');
    const avatarActive = document.getElementById('avatar-active');

    if (placeholder) placeholder.classList.remove('hidden');
    if (avatarActive) avatarActive.classList.remove('show');

    addLog('界面', '隐藏数字人界面');
    }

    // ============ 核心API函数 ============

    // 1. 初始化SDK
    async function initSDK() {
    const appId = document.getElementById('app-id');
    const appSecret = document.getElementById('app-secret');
    const gatewayServer = document.getElementById('gateway-server');

    if (!appId || !appSecret || !gatewayServer) {
    showAlert('请填写完整的配置信息', 'error');
    return;
    }

    const appIdValue = appId.value.trim();
    const appSecretValue = appSecret.value.trim();
    const gatewayServerValue = gatewayServer.value.trim();

    if (!appIdValue || !appSecretValue) {
    showAlert('请输入App ID和App Secret', 'error');
    return;
    }

    showLoading('正在初始化SDK…');
    addLog('系统', '开始初始化SDK');

    try {
    // 销毁旧的SDK实例
    if (liteSDK) {
    try {
    await destroySDK();
    } catch (e) {
    console.log('清理旧SDK实例时出错:', e);
    }
    }

    // 创建SDK实例
    liteSDK = new XmovAvatar({
    containerId: '#avatar-active', // 注意:这里指向avatar-active容器
    appId: appIdValue,
    appSecret: appSecretValue,
    gatewayServer: gatewayServerValue,

    // 事件回调
    onWidgetEvent(data) {
    console.log('Widget事件:', data);
    addLog('SDK', `Widget事件: ${data.type || '未知类型'}`);
    },

    onNetworkInfo(networkInfo) {
    console.log('网络信息:', networkInfo);
    addLog('SDK', '收到网络信息');
    },

    onMessage(message) {
    console.log('SDK消息:', message);
    if (message && typeof message === 'object') {
    addLog('SDK', `收到消息: ${JSON.stringify(message).substring(0, 100)}…`);
    } else {
    addLog('SDK', `收到消息: ${message}`);
    }
    },

    onStateChange(state) {
    console.log('SDK状态变化:', state);
    updateSDKStatus(state);
    updateConnectionStatus(state);
    addLog('SDK', `状态变化: ${state}`);

    if (state === 'connected') {
    onSDKConnected();
    } else if (state === 'disconnected') {
    onSDKDisconnected();
    }
    },

    onStatusChange(status) {
    console.log('SDK状态变更:', status);
    },

    onStateRenderChange(state, duration) {
    console.log('SDK渲染状态变化:', state, duration);
    },

    onVoiceStateChange(status) {
    console.log('语音状态变化:', status);
    updateVoiceStatus(status);
    },

    enableLogger: true
    });

    // 调用官方init方法
    await liteSDK.init({
    onDownloadProgress: (progress) => {
    console.log('下载进度:', progress);
    updateProgress(progress);
    if (progress % 25 === 0) {
    addLog('进度', `资源下载进度: ${progress}%`);
    }
    }
    });

    isInitialized = true;
    enableControls(true);

    updateSDKStatus('connected');
    updateConnectionStatus('connected');

    // 显示数字人,隐藏占位符
    showAvatar();

    showAlert('SDK初始化成功!', 'success');
    addLog('系统', 'SDK初始化成功');

    // 发送欢迎消息
    setTimeout(() => {
    speakMessage(true, true);
    }, 1000);

    } catch (error) {
    console.error('初始化失败:', error);
    showAlert(`初始化失败: ${error.message}`, 'error');
    addLog('错误', `初始化失败: ${error.message}`);
    isInitialized = false;
    updateSDKStatus('error');
    updateConnectionStatus('error');
    } finally {
    hideLoading();
    }
    }

    // SDK连接成功回调
    function onSDKConnected() {
    addLog('SDK', '连接成功');
    updateConnectionStatus('connected');
    }

    // SDK断开连接回调
    function onSDKDisconnected() {
    addLog('SDK', '连接断开');
    updateConnectionStatus('disconnected');
    }

    // 2. 驱动数字人说话
    function speakMessage(is_start = true, is_end = true) {
    if (!liteSDK || !isInitialized) {
    showAlert('请先初始化SDK', 'error');
    return;
    }

    if (isSpeaking) {
    showAlert('数字人正在说话,请稍候…', 'warning');
    return;
    }

    const messageInput = document.getElementById('message-input');
    if (!messageInput) {
    showAlert('找不到消息输入框', 'error');
    return;
    }

    const message = messageInput.value.trim();
    if (!message) {
    showAlert('请输入要发送的消息', 'warning');
    return;
    }

    try {
    isSpeaking = true;
    updateVoiceStatus('speaking');

    // 调用官方speak方法
    liteSDK.speak(message, is_start, is_end);

    // 更新最后操作显示
    const lastAction = document.getElementById('last-action');
    if (lastAction) {
    const shortMessage = message.length > 20 ? message.substring(0, 20) + '…' : message;
    lastAction.textContent = `发送: ${shortMessage}`;
    }

    addLog('发送', message);

    // 2秒后重置说话状态
    setTimeout(() => {
    isSpeaking = false;
    updateVoiceStatus('idle');
    }, 2000);

    } catch (error) {
    console.error('发送失败:', error);
    isSpeaking = false;
    updateVoiceStatus('error');
    showAlert(`发送失败: ${error.message}`, 'error');
    addLog('错误', `发送失败: ${error.message}`);
    }
    }

    // 3. 销毁SDK实例
    async function destroySDK() {
    if (!liteSDK) {
    showAlert('SDK未初始化', 'warning');
    return;
    }

    try {
    // 调用官方destroy方法
    await liteSDK.destroy();

    liteSDK = null;
    isInitialized = false;
    isSpeaking = false;

    enableControls(false);

    updateSDKStatus('disconnected');
    updateConnectionStatus('disconnected');
    updateVoiceStatus('idle');

    // 更新下载状态
    const downloadStatus = document.getElementById('download-status');
    if (downloadStatus) {
    downloadStatus.textContent = '0%';
    }

    // 更新最后操作
    const lastAction = document.getElementById('last-action');
    if (lastAction) {
    lastAction.textContent = '无';
    }

    // 隐藏数字人,显示占位符
    hideAvatar();

    showAlert('SDK已销毁', 'info');
    addLog('系统', 'SDK已销毁');

    } catch (error) {
    console.error('销毁失败:', error);
    showAlert(`销毁失败: ${error.message}`, 'error');
    addLog('错误', `销毁失败: ${error.message}`);
    }
    }

    // ============ 辅助函数 ============

    function quickCommand(command) {
    const messageInput = document.getElementById('message-input');
    if (messageInput) {
    messageInput.value = command;
    speakMessage(true, true);
    }
    }

    function testSSML() {
    // SSML示例
    const ssmlText = `<speak>
    欢迎使用<break time="300ms"/>魔珐星云智能助手。
    我能够为您提供<prosody rate="slow">清晰自然的</prosody>语音交互服务。
    </speak>`;

    const messageInput = document.getElementById('message-input');
    if (messageInput) {
    messageInput.value = ssmlText;
    showAlert('已加载SSML示例,点击"完整说话"按钮测试', 'info');
    }
    }

    // 页面初始化
    function initPage() {
    // 添加CSS动画
    if (!document.getElementById('animations')) {
    const style = document.createElement('style');
    style.id = 'animations';
    style.textContent = `
    @keyframes slideIn {
    from { transform: translateX(100%); opacity: 0; }
    to { transform: translateX(0); opacity: 1; }
    }
    `;
    document.head.appendChild(style);
    }

    addLog('系统', '页面加载完成');
    addLog('提示', '请使用真实的App ID和App Secret进行测试');
    }

    // 页面加载完成后初始化
    window.addEventListener('DOMContentLoaded', initPage);
    </script>
    </body>
    </html>

    三、产品价值:打破瓶颈的技术与场景落地

  • 6 大核心特点:兼顾性能与成本

  • 魔珐星云的核心优势可概括为 6 点:

    • 高质量:3D 数字人动作精度达毫米级,表情还原度超 95%;
    • 低延时:支持实时打断与指令切换,响应延迟<200ms;
    • 高并发:单节点可同时承载 1000 + 数字人实例;
    • 低成本:相比传统方案,开发与部署成本降低 60%;
    • 多终端:适配手机、AR 头显、人形机器人等 10 + 终端;
    • 信创支持:兼容国产芯片与操作系统,满足企业合规需求。
  • 打破 3D 数字人的 “不可能三角”

  • 传统 3D 数字人难以同时实现 “高质量、低成本、低延时”,而魔珐星云通过文生 3D 多模态动作大模型 + AI 端边协同解算,实现了三者的平衡:

    • 大模型生成高保真动作序列,端边设备分担解算压力,既保证了质量,又降低了云端成本与延时。

    四、结语:AI陪伴

    技术的终极意义,是让每个人都能享受创新的红利。无需复杂技术储备,从调用 SDK 生成第一个数字人动作开始,就能让 “有表情、有动作、懂情绪” 的智能陪伴,真正走进你的生活,让每一次交互都充满 “在场感” 的温暖。

    最后,以一个车载3D数字人的使用场景结尾吧。

    深夜高速,驾驶者略显疲惫,车载数字人感知到状态变化,主动调整车内灯光,用温和的声音说:“检测到您已连续驾驶3小时,前方2公里有服务区,建议休息片刻。想听首轻音乐放松一下吗?”同时呈现出一个关切的眼神和指引手势——这种无缝融合场景感知与情感交互的能力,正是魔法星云赋予开发者的创新利器。

    赞(0)
    未经允许不得转载:171主机测评 » 魔珐星云:AI 具身智能的易用性实践与场景革新
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址