引言
在大模型(LLM)狂飙突进的时代,我们已经习惯了与ChatGPT聊诗词歌赋,用Midjourney生成精美图片。但作为一名开发者,你是否也有一种感觉:AI似乎还缺了点什么?
它们大多还只是活在服务器里的"大脑",或者是屏幕上的一行行文字。它们听不到、看不见,更无法像人一样用表情和动作回应你。今天,我将带大家探索一个可能会成为"具身智能iPhone时刻"的平台——魔珐星云(Xingyun 3D) 。它能让大模型真正拥有"身体",成为可交互、可感知、可行动的智能体。
编辑
体验注册地址:
xingyun3d.com?utm_campaign=daily&utm_source=jixinghuiKoc25
一、魔珐星云平台概述:具身智能的基础设施
魔珐星云是魔珐科技推出的具身智能3D数字人开发平台,致力于让大模型拥有"身体",真正成为可交互、可感知、可行动的智能体。开发者可以在星云平台快速构建具身智能应用,从虚拟陪伴到机器人交互,从桌面小助手到车载交互界面,均可轻松实现。
作为全球首个让AI具备"身体表达力"的基础设施,魔珐星云把"语言→语音/表情/手势/动作"的生成能力封装为通用接口,帮助开发者在任何终端快速实现"能看、能说、能动"的实时数字人交互。
编辑
二、魔珐星云平台使用配置流程
2.1 平台应用管理创建、配置和调试
2.1.1 注册与登录
魔珐星云平台目前对所有用户免费开放,注册即可免费获得100积分,如有邀请码可获得1000积分使用并体验额外权益。
- 访问魔珐星云官网:xingyun3d.com/?utm_campai…
- 点击右上角的"登录/注册"按钮
- 选择合适的注册方式完成注册
2.1.2 创建应用
登录后,进入开发者中心,点击"应用管理",然后点击"创建应用"按钮。
编辑
编辑
2.1.3 角色选择
平台内置了多种高精度的3D角色库,涵盖超写实、二次元、卡通、美型等多样角色风格。根据应用场景选择合适的角色。
编辑
2.1.4 动作调试
进入"调试"面板,在右侧代码框中输入指令,测试数字人的渲染效果。例如,输入一段开场白,观察数字人的语音、表情、手势是否自然流畅。
编辑
2.2 SDK使用配置并开发应用
2.2.1 开发准备
- 依赖环境:前端框架Vue3 + TypeScript,构建工具Vite
- 获取SDK:在应用管理中找到创建的应用,获取SDK连接参数(App ID和密钥)
下文为核心代码,完整源码见(已开源,免费下载):
2.2.2 本地部署环境准备
VSCode创建项目,运行以下命令安装依赖并启动开发服务器:
# 安装项目依赖
npm i
# 启动开发服务器
npm run dev
项目结构如下:
src/
├── App.vue # 应用主组件
├── main.ts # 应用入口
├── style.css # 全局样式
├── components/
│ ├── AvatarRender.vue # 虚拟人渲染组件
│ └── ConfigPanel.vue # 配置面板组件
├── services/
│ ├── avatar.ts # 虚拟人SDK服务
│ └── llm.ts # 大语言模型服务
└── utils/
└── sdk-loader.ts # SDK加载器
编辑
然后我们在浏览器输入:http://localhost:5173/ 即可访问数字人交互平台了
编辑
2.2.3 配置SDK连接参数
在应用中,找到SDK配置面板,输入从平台获取的App ID和密钥进行连接。
编辑
2.2.4 接入语音识别和大模型
- 语音识别配置:选择ASR服务商(如腾讯云ASR),输入相应的连接参数(App ID、Secret ID、Secret Key)
- 大语言模型配置:选择大模型服务商(如火山方舟),输入大模型版本和密钥
编辑
编辑
三.难忘面试官数字人-原创可复现
在现代求职过程中,面试不仅考察专业能力,更考察沟通表达和临场应变能力。为了帮助求职者更好地准备面试,我们可以基于魔珐星云搭建一个“难忘面试官对话助手”,通过模拟真实面试场景,提供智能问答和即时反馈,让用户在安全环境中练习回答问题、优化表达,从而提升面试自信与表现。
"难忘面试官数字人"是一款基于 Vue 3 + TypeScript + Vite 构建的原创智能虚拟人面试系统,为用户提供沉浸式的面试模拟体验。
-
面试技能训练:提供真实面试场景模拟
-
职业素养提升:通过数字人面试官进行面试技巧指导
-
教育机构教学:作为就业指导课程的实践工具
-
企业招聘前测:帮助企业筛选合适的候选人
编辑
编辑
编辑
编辑
3.1消息输入区域组件
创建新的MessageInput组件,用于底部的消息输入区域,实现用户交互体验。
<template>
<div class="message-input-container">
<div class="message-input-wrapper">
<textarea
v-model="appState.ui.text"
class="message-textarea"
rows="2"
placeholder="请输入您的问题或回答..."
@keydown.enter.prevent="handleSendMessage"
/>
<div class="button-group">
<button
@click="handleVoiceInput"
:disabled="!appState.avatar.connected || appState.asr.isListening"
class="voice-button"
>
<span class="voice-icon">{{ appState.asr.isListening ? '🔴' : '🎤' }}</span>
<span class="voice-text">{{ appState.asr.isListening ? '正在听...' : '语音' }}</span>
</button>
<button
@click="handleSendMessage"
:disabled="!appState.avatar.connected || !appState.ui.text.trim() || isSending"
class="send-button"
>
{{ isSending ? '发送中...' : '发送' }}
</button>
</div>
</div>
<div class="connection-status" :class="{ 'connected': appState.avatar.connected }">
<span class="status-indicator"></span>
<span class="status-text">{{ appState.avatar.connected ? '已连接' : '未连接' }}</span>
</div>
</div>
</template>
<script setup lang="ts">
import { inject, ref } from 'vue'
import { useAsr } from '../composables/useAsr'
import type { AppState, AppStore } from '../types'
// 注入全局状态和方法
const appState = inject<AppState>('appState')!
const appStore = inject<AppStore>('appStore')!
// 组件状态
const isSending = ref(false)
// 发送消息
async function handleSendMessage() {
if (isSending.value || !appState.ui.text.trim()) return
isSending.value = true
try {
await appStore.sendMessage()
// 发送成功后清空输入框
appState.ui.text = ''
} catch (error) {
console.error('发送消息失败:', error)
alert('发送消息失败,请重试')
} finally {
isSending.value = false
}
}
// 语音输入
function handleVoiceInput() {
if (appState.asr.isListening) {
return
}
// 验证ASR配置
const { appId, secretId, secretKey } = appState.asr
if (!appId || !secretId || !secretKey) {
alert('请先配置ASR信息(App ID、Secret ID、Secret Key)')
return
}
// 创建新的ASR实例(使用当前配置)
const { start: startAsrWithConfig, stop: stopAsrWithConfig } = useAsr({
provider: 'tx',
appId: appState.asr.appId,
secretId: appState.asr.secretId,
secretKey: appState.asr.secretKey
})
appStore.startVoiceInput({
onFinished: (text: string) => {
appState.ui.text = text
stopAsrWithConfig()
appStore.stopVoiceInput()
},
onError: (error: any) => {
console.error('语音识别错误:', error)
stopAsrWithConfig()
appStore.stopVoiceInput()
}
})
startAsrWithConfig({
onFinished: (text: string) => {
appState.ui.text = text
appStore.stopVoiceInput()
},
onError: (error: any) => {
console.error('语音识别错误:', error)
appStore.stopVoiceInput()
}
})
}
</script>
<style scoped>
.message-input-container {
max-width: 1200px;
margin: 0 auto;
width: 100%;
}
.message-input-wrapper {
display: flex;
gap: 1rem;
align-items: flex-end;
}
.message-textarea {
flex: 1;
padding: 0.75rem 1rem;
border: 1px solid #e2e8f0;
border-radius: 8px;
resize: vertical;
min-height: 44px;
font-size: 1rem;
transition: border-color 0.2s, box-shadow 0.2s;
}
.message-textarea:focus {
outline: none;
border-color: #4299e1;
box-shadow: 0 0 0 3px rgba(66, 153, 225, 0.1);
}
.button-group {
display: flex;
gap: 0.75rem;
flex-shrink: 0;
}
.voice-button,
.send-button {
padding: 0.75rem 1.5rem;
border: none;
border-radius: 8px;
font-size: 0.9rem;
font-weight: 500;
cursor: pointer;
transition: all 0.2s;
display: flex;
align-items: center;
gap: 0.5rem;
}
.voice-button {
background-color: #22c55e;
color: white;
}
.voice-button:hover:not(:disabled) {
background-color: #16a34a;
}
.send-button {
background-color: #3b82f6;
color: white;
}
.send-button:hover:not(:disabled) {
background-color: #2563eb;
}
.voice-button:disabled,
.send-button:disabled {
opacity: 0.6;
cursor: not-allowed;
}
.connection-status {
margin-top: 0.5rem;
display: flex;
align-items: center;
gap: 0.5rem;
font-size: 0.8rem;
color: #64748b;
}
.connection-status.connected {
color: #16a34a;
}
.status-indicator {
width: 8px;
height: 8px;
border-radius: 50%;
background-color: #64748b;
}
.connection-status.connected .status-indicator {
background-color: #16a34a;
}
/* 响应式设计 */
@media (max-width: 768px) {
.message-input-container {
padding: 0 1rem;
}
.button-group {
flex-direction: column;
}
.voice-button,
.send-button {
width: 100%;
justify-content: center;
}
}
</style>
3.2 配置中心
<template>
<div class="config-panel">
<div class="config-header">
<h2 class="panel-title">配置中心</h2>
</div>
<!-- 虚拟人配置 -->
<section class="config-section">
<h3 class="section-title">虚拟人配置</h3>
<div class="form-group">
<label>APP ID</label>
<input
v-model="appState.avatar.appId"
type="text"
placeholder="请输入 APP ID"
/>
</div>
<div class="form-group">
<label>APP Secret</label>
<input
v-model="appState.avatar.appSecret"
type="password"
placeholder="请输入 APP Secret"
/>
</div>
</section>
<!-- 大语言模型配置 -->
<section class="config-section">
<h3 class="section-title">AI 配置</h3>
<div class="form-group">
<label>API Key</label>
<input
v-model="appState.llm.apiKey"
type="password"
placeholder="请输入 API Key"
/>
</div>
</section>
<!-- 控制按钮 -->
<section class="control-section">
<div class="button-group">
<button
@click="handleConnect"
:disabled="isConnecting || appState.avatar.connected"
class="btn btn-primary"
>
{{ isConnecting ? '连接中...' : '连接虚拟人' }}
</button>
<button
@click="handleDisconnect"
:disabled="!appState.avatar.connected"
class="btn btn-secondary"
>
断开连接
</button>
</div>
<div class="connection-status" :class="{ 'connected': appState.avatar.connected }">
{{ appState.avatar.connected ? '✓ 虚拟人已连接' : '✗ 虚拟人未连接' }}
</div>
</section>
</div>
</template>
<script setup lang="ts">
import { inject, ref } from 'vue'
import type { AppState, AppStore } from '../types'
// 注入全局状态和方法
const appState = inject<AppState>('appState')!
const appStore = inject<AppStore>('appStore')!
// 组件状态
const isConnecting = ref(false)
// 事件处理函数
async function handleConnect() {
if (isConnecting.value) return
isConnecting.value = true
try {
await appStore.connectAvatar()
} catch (error) {
console.error('连接失败:', error)
alert('连接失败,请检查配置信息')
} finally {
isConnecting.value = false
}
}
function handleDisconnect() {
appStore.disconnectAvatar()
}
</script>
<style scoped>
.config-panel {
width: 100%;
height: 100%;
overflow-y: auto;
padding: 20px;
background: #ffffff;
display: flex;
flex-direction: column;
gap: 20px;
}
.config-header {
text-align: center;
border-bottom: 2px solid #e2e8f0;
padding-bottom: 15px;
}
.panel-title {
margin: 0;
font-size: 1.2rem;
font-weight: 600;
color: #1a365d;
}
.config-section,
.control-section {
border: 1px solid #e2e8f0;
border-radius: 8px;
padding: 16px;
background: #f8fafc;
}
.section-title {
margin: 0 0 12px 0;
font-size: 14px;
font-weight: 600;
color: #475569;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.form-group {
margin-bottom: 14px;
}
.form-group:last-child {
margin-bottom: 0;
}
label {
display: block;
margin-bottom: 5px;
font-size: 13px;
font-weight: 500;
color: #64748b;
}
input,
select {
width: 100%;
padding: 9px 12px;
border: 1px solid #cbd5e1;
border-radius: 6px;
font-size: 14px;
transition: all 0.2s;
background-color: white;
}
input:focus,
select:focus {
outline: none;
border-color: #3b82f6;
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
}
.button-group {
display: flex;
gap: 10px;
justify-content: center;
margin-bottom: 12px;
}
.btn {
padding: 10px 20px;
border: none;
border-radius: 6px;
font-size: 14px;
font-weight: 500;
cursor: pointer;
transition: all 0.2s;
min-width: 100px;
}
.btn:disabled {
opacity: 0.6;
cursor: not-allowed;
}
.btn-primary {
background: #3b82f6;
color: white;
}
.btn-primary:hover:not(:disabled) {
background: #2563eb;
transform: translateY(-1px);
box-shadow: 0 4px 6px -1px rgba(59, 130, 246, 0.1);
}
.btn-secondary {
background: #64748b;
color: white;
}
.btn-secondary:hover:not(:disabled) {
background: #475569;
transform: translateY(-1px);
box-shadow: 0 4px 6px -1px rgba(100, 116, 139, 0.1);
}
.connection-status {
text-align: center;
font-size: 13px;
padding: 8px;
border-radius: 4px;
background-color: #fef2f2;
color: #dc2626;
}
.connection-status.connected {
background-color: #f0fdf4;
color: #16a34a;
}
/* 滚动条美化 */
.config-panel::-webkit-scrollbar {
width: 6px;
}
.config-panel::-webkit-scrollbar-track {
background: #f1f5f9;
}
.config-panel::-webkit-scrollbar-thumb {
background: #cbd5e1;
border-radius: 3px;
}
.config-panel::-webkit-scrollbar-thumb:hover {
background: #94a3b8;
}
</style>
3.3 数字人渲染区域
<template>
<div class="avatar-render-container">
<div class="avatar-wrapper">
<div class="avatar-container">
<div :id="containerId" class="avatar-dom"></div>
<div v-if="!appState.avatar.connected" class="avatar-overlay">
<div class="overlay-content">
<h3>面试官数字人</h3>
<p>请在配置中心连接虚拟人</p>
<div class="status-indicator">
<span class="status-dot"></span>
<span class="status-text">未连接</span>
</div>
</div>
</div>
</div>
<div class="subtitle-container">
<div v-if="appState.ui.subTitleText" class="subtitle">
{{ appState.ui.subTitleText }}
</div>
<div v-else-if="appState.avatar.connected" class="subtitle placeholder">
面试官正在思考...
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { inject, computed, onMounted, onBeforeUnmount, watch } from 'vue'
import { avatarService } from '../services/avatar'
import type { AppState } from '../types'
// 注入全局状态
const appState = inject<AppState>('appState')!
// 获取容器ID
const containerId = computed(() => avatarService.getContainerId())
// 监听连接状态变化,重置渲染状态
watch(() => appState.avatar.connected, (connected) => {
if (connected) {
// 连接成功时的处理
console.log('Avatar connected')
} else {
// 断开连接时的处理
console.log('Avatar disconnected')
}
})
// 组件生命周期
onMounted(() => {
// 组件挂载时的初始化操作
})
onBeforeUnmount(() => {
// 组件卸载前的清理操作
})
</script>
<style scoped>
.avatar-render-container {
flex: 1;
display: flex;
justify-content: center;
align-items: center;
padding: 20px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
overflow: hidden;
}
.avatar-wrapper {
width: 100%;
max-width: 900px;
height: 100%;
max-height: 700px;
display: flex;
flex-direction: column;
gap: 16px;
}
.avatar-container {
flex: 1;
background-color: #000;
border-radius: 12px;
overflow: hidden;
position: relative;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2);
transition: all 0.3s ease;
}
.avatar-container:hover {
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.3);
}
.avatar-dom {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
}
.avatar-overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.7);
display: flex;
justify-content: center;
align-items: center;
transition: opacity 0.3s ease;
}
.avatar-overlay:hover {
background: rgba(0, 0, 0, 0.65);
}
.overlay-content {
text-align: center;
color: white;
padding: 0 20px;
}
.overlay-content h3 {
margin: 0 0 10px 0;
font-size: 1.8rem;
font-weight: 700;
color: #f8fafc;
}
.overlay-content p {
margin: 0 0 20px 0;
font-size: 1rem;
color: #cbd5e1;
}
.status-indicator {
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
}
.status-dot {
width: 10px;
height: 10px;
border-radius: 50%;
background-color: #ef4444;
animation: pulse 1.5s infinite;
}
.status-text {
font-size: 0.9rem;
color: #cbd5e1;
}
@keyframes pulse {
0% {
opacity: 1;
transform: scale(1);
}
50% {
opacity: 0.5;
transform: scale(1.2);
}
100% {
opacity: 1;
transform: scale(1);
}
}
.subtitle-container {
background: white;
border-radius: 12px;
padding: 18px 24px;
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
min-height: 80px;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.3s ease;
}
.subtitle-container:hover {
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.15);
}
.subtitle {
font-size: 16px;
line-height: 1.6;
color: #334155;
text-align: center;
margin: 0;
max-width: 100%;
word-wrap: break-word;
animation: fadeIn 0.3s ease;
}
.subtitle.placeholder {
color: #94a3b8;
font-style: italic;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(5px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* 响应式设计 */
@media (max-width: 768px) {
.avatar-render-container {
padding: 10px;
}
.avatar-wrapper {
max-height: none;
}
.overlay-content h3 {
font-size: 1.5rem;
}
.subtitle {
font-size: 14px;
}
}
</style>
优化数字人渲染区域,使其与新的UI设计风格一致。
向星云 3D 数字人服务端发送一个带签名认证的请求。程序会先用 appId、appSecret、请求方法、接口路径、请求数据等信息拼成原始字符串,再用 MD5 算法生成摘要,作为最终的 X-TOKEN,一起放到请求头里。服务端通过这个签名来验证请求是否可信。最后程序用 requests 发起接口调用并打印结果。
3.4 常量配置
// 应用常量
export const APP_CONFIG = {
CONTAINER_PREFIX: 'CONTAINER_',
DEFAULT_VAD_SILENCE_TIME: 300,
AVATAR_INIT_TIMEOUT: 3000,
SPEAK_INTERRUPT_DELAY: 2000
} as const
// LLM配置
export const LLM_CONFIG = {
BASE_URL: 'https://ark.cn-beijing.volces.com/api/v3',
DEFAULT_MODEL: 'doubao-1-5-pro-32k-250115',
SYSTEM_PROMPT: '你是人工智能助手'
} as const
// ASR配置
export const ASR_CONFIG = {
ENGINE_MODEL_TYPE: '16k_zh',
VOICE_FORMAT: 1,
FILTER_DIRTY: 1,
FILTER_MODAL: 1,
FILTER_PUNC: 1,
CONVERT_NUM_MODE: 1,
WORD_INFO: 2,
NEEDVAD: 1
} as const
// SDK配置
export const SDK_CONFIG = {
GATEWAY_URL: 'https://nebula-agent.xingyun3d.com/user/v1/ttsa/session',
DATA_SOURCE: '2',
CUSTOM_ID: 'demo'
} as const
// 支持的LLM模型列表
export const SUPPORTED_LLM_MODELS = [
'doubao-1-5-pro-32k-250115'
] as const
// 支持的ASR提供商
export const SUPPORTED_ASR_PROVIDERS = [
{ value: 'tx', label: '腾讯' }
] as const
配置完成后,运行即可与数字人进行交互:
- 文字交互:在输入框中输入文字,数字人会根据文字内容生成语音、表情和动作
- 语音交互:点击语音按钮,直接与数字人进行语音对话
编辑
编辑
编辑
编辑
编辑
四、魔珐星云产品体验分享
4.1 六大核心特点
魔珐星云通过技术创新,实现了打破3D数字人生成的质量、成本、延时不可能三角的目标,具有以下六大核心特点:
- 高质量:呈现电影级的3D视觉效果,微表情丰富,口型同步准确,支持超写实、二次元等多种风格
- 低延时(可随时打断) :端到端小于500ms,实现"开口即回",支持全双工对话,用户可以随时插话,数字人能即时反应
- 高并发:云端架构优化,支持大规模用户同时在线,适合企业级应用场景
- 低成本:支持免显卡端渲染,无需昂贵的算力服务器,端侧模块可在RK3566等嵌入式芯片上运行
- 多终端支持:iOS、Android、Web、Windows、Linux全覆盖,真正实现"每一块屏幕都能有智能交互"
- 信创支持:完全适配国产化软硬件环境,满足政企项目的合规需求,支持公共云/私有化/本地化部署
4.2 技术突破:打破不可能三角
魔珐星云通过两大核心技术突破了数字人开发领域的"不可能三角":
- 文生3D多模态动作大模型:直接将文本/语音转换为语音、动作、表情、手势等多模态的3D表达信号,让数字人能够理解语义,自动生成自然的表情和动作
- AI端渲与解算技术:云-端拆分架构,云端只生成轻量级的动作和语音参数,端侧通过AI解算模块实时转化为画面,大幅降低对终端硬件的要求
这种技术架构不仅实现了高质量的视觉效果和低延时的交互体验,还大大降低了部署成本,使具身智能应用能够大规模商业化应用。
4.3 使用场景
魔珐星云的通用性使其可以应用在各行各业,以下是几个典型的应用场景:
1)公共服务屏
在酒店大堂、银行、医院、车站等场所部署24/7全天候服务的数字人,提供信息查询、业务导办等服务,提升服务效率和用户体验。
编辑
2)零售/营销屏
在商场、门店、数字标牌等场所部署主动与顾客交流的数字人,提供产品介绍、促销信息、导购服务等,增强顾客参与感和购买意愿。
编辑
3)个人设备
将手机、电视、车机屏等变成日常的AI伙伴,提供个性化的陪伴、信息查询、日程管理等服务,让AI真正融入日常生活。
编辑
4)沉浸式场景
在AR/VR/MR头显等设备中部署数字人,打造沉浸式的交互体验,迈向人机交互的下一代入口。
5)人形机器人
驱动人形机器人,让人形机器人从会动会操作的蓝领,升级为能理解、会交流的智能白领,拓展机器人的应用领域。
6)虚拟IP活化
让游戏NPC、虚拟明星等IP拥有灵魂,从固定脚本升级为能思考、会互动的角色,为粉丝提供更真实的互动体验。
编辑
五、总结
魔珐星云作为具身智能的基础设施,通过技术创新打破了3D数字人生成的质量、成本、延时不可能三角,为开发者提供了简单易用的SDK和API,让大模型真正拥有了"身体表达力"。
无论你是希望为现有的App增加数字人功能,还是计划开发全新的AI原生应用,魔珐星云都是一个值得尝试的平台。它将复杂的3D图形学、动作捕捉、AI渲染技术封装成了一套极简的SDK,让每一位开发者都能轻松构建高质量的具身智能应用。
加入魔珐星云生态,让每一块屏幕都能"活"起来,让大模型真正拥有身体,实现更自然、更智能的人机交互体验!
官方网站:xingyun3d.com?utm_campaign=daily&utm_source=jixinghuiKoc25