告诉我你冰箱里有什么,我帮你做一桌好菜:云厨 YunChef 具身交互智能食谱顾问

打开冰箱,挑几样食材,一位住在屏幕里的暖厨姐姐立刻帮你搭配菜谱,还能一步步语音教你做菜------这不是美食 App 的幻想,而是具身交互智能走进厨房的真实落地。本文以一道完整菜谱的上菜流程为线索,从魔珐星云控制台配置到 React + Vite 工程源码,拆解云厨 YunChef 如何让数字人「小厨」成为你的私人食谱顾问。

魔珐星云PC端官方链接https://xingyun3d.com?utm_campaign=daily\&utm_source=CSDNwanfen3\&utm_medium=\&utm_term=\&utm_content=


一、开胃前菜 · 为什么厨房需要一位数字人厨师

1.1 冰箱里的食材,缺一个会说话的菜谱

每个人打开冰箱时都经历过同样的困境:西红柿、鸡蛋、一块豆腐、半颗洋葱------这些食材能做什么?搜索引擎给你一千条菜谱链接,每条都要你自己读完再判断。你真正需要的,不是另一篇图文教程,而是一个站在你旁边、看到你手里的食材、直接告诉你「先做这个、再做那个」的人。

具身交互智能解决的正是这个「最后一公里」。所谓「具身」,是指数字人不只是一段语音或一个头像,而是拥有完整形象、肢体动作和口型同步的虚拟实体;所谓「交互智能」,是指她能实时响应用户操作,将菜谱数据转化为自然语言讲解,配合手势和表情输出,形成「看得见人、听得到声、跟得上节奏」的沉浸式烹饪体验。

本项目中,数字人暖厨姐姐「小厨」会在用户点击任意菜谱时,主动播报完整的做法步骤和烹饪技巧------不是冷冰冰的文字列表,而是一位温暖的姐姐在手把手教你做菜。

1.2 核心能力一览

能力模块 说明
食材匹配 23 种常见食材库,勾选后智能匹配推荐菜谱
分类浏览 家常菜 / 快手菜 / 汤羹 / 主食 / 甜品,5 大分类
菜谱详情 12 道菜谱,含食材、步骤、技巧、标签
语音讲解 点击「小厨讲解」,数字人实时播报完整做法
实时打断 讲解过程中可随时切换菜谱,数字人立即响应
暖厨视觉 奶油基底 + 琥珀橙主题色,温暖的厨房氛围

1.3 技术栈

层级 技术选型
前端框架 React 18 + Vite 6
图标库 lucide-react
数字人 SDK 魔珐 XmovAvatar(参数流架构)
样式系统 纯 CSS 令牌驱动(暖厨主题)
开发端口 localhost:5281

二、食材备料 · 魔珐星云控制台配置

做一道好菜,先把食材备齐。数字人项目的第一步,是在魔珐星云控制台完成形象配置。魔珐星云是具身交互智能的底座平台------数字人的形象、音色、动作都在这里定义,前端 SDK 只负责渲染和驱动。以下 5 个步骤完成后,你就拥有了一个可以在前端调用的数字人实例。

步骤1:创建驱动应用

登录魔珐星云控制台,创建一个新的驱动应用,获取 appId 和 appSecret。

步骤2:形象配置

选择或上传数字人形象,配置外观参数。云厨项目选择了一位温暖亲切的女性形象,契合「暖厨姐姐」的定位。

步骤3:场景配置

设置数字人渲染的场景背景,确保与项目的暖色视觉主题协调。

步骤4:音色配置

选择温暖、亲切的音色。小厨的开场白是:「欢迎来到云厨,我是你的暖厨姐姐小厨。告诉我你冰箱里有什么食材,我来帮你推荐好吃的菜谱。」

步骤5:表演配置

配置数字人的肢体动作和表情参数,确保播报菜谱时动作自然流畅。


三、热锅起灶 · 数字人容器与 SDK 集成

灶台搭好,才能开火。控制台配置完成后,下一步是在前端搭建数字人的运行环境。核心架构是静态 HTML 容器 + IIFE 封装的数字人服务。

3.1 静态 HTML 容器

数字人的渲染容器必须在 index.html 中静态存在,确保 avatar.js 运行时能立即找到 DOM 节点。这是具身交互智能落地的第一个工程要点------SDK 需要挂载到一个已经存在的容器上。

js 复制代码
<!-- 数字人舞台容器(静态 HTML,确保 avatar.js 运行时存在) -->
<div class="avatar-stage" id="avatar-stage-wrapper">
  <div class="avatar-stage__halo"></div>
  <div class="avatar-stage__frame">
    <div class="avatar-stage__box">
      <div id="xmov-avatar-container" class="avatar-stage__sdk"></div>
    </div>
    <div class="avatar-stage__loading" id="avatar-loading" style="display:none;">
      <div class="avatar-stage__rings">
        <span></span><span></span><span></span>
      </div>
      <p>小厨 准备中...</p>
    </div>
  </div>
  <div class="avatar-stage__nameplate">
    <span class="avatar-stage__name">小厨</span>
    <span class="avatar-stage__role">暖厨姐姐 · 在线</span>
  </div>
  <div class="avatar-stage__subtitle" id="avatar-subtitle"></div>
</div>

<script type="module" src="/src/main.jsx"></script>
<!-- 魔珐 XmovAvatar SDK -->
<script src="https://media.xingyun3d.com/xingyun3d/general/litesdk/xmovAvatar@latest.js"></script>
<script src="/avatar.js"></script>

关键设计:

  • avatar-stage__frame 是数字人的毛玻璃框体,280x420 固定右下角
  • avatar-stage__nameplate 悬浮在框内顶部,显示数字人名字和角色
  • avatar-stage__subtitle 悬浮在框内底部,显示播报字幕
  • SDK 通过 CDN 加载,avatar.js 放在 public 目录,确保 Vite 构建后可访问

3.2 数字人服务核心(avatar.js)

avatar.js 采用 IIFE 封装,通过 window.AvatarService 暴露全局接口。这是具身交互智能的第二个工程要点------将 SDK 的复杂连接、播报、打断逻辑封装为简洁的 API,业务组件只需调用 speakText() 即可。

js 复制代码
/* ============================================================
 * 云厨 YunChef · 数字人暖厨姐姐服务(原生 JS 版)
 * 复用魔珐 XmovAvatar SDK,提供连接/播报/字幕/打断能力
 * ============================================================ */

(() => {
  'use strict';

  /* ============== 配置 ============== */
  const AVATAR_CONFIG = {
    appId: 'your_avatar_app_id',
    appSecret: 'your_avatar_app_secret',
    gatewayUrl: 'https://nebula-agent.xingyun3d.com/user/v1/ttsa/session',
    dataSource: '2',
    customId: 'demo',
  };

  const AVATAR_IDENTITY = {
    name: '小厨',
    role: '暖厨姐姐',
    greeting: '欢迎来到云厨,我是你的暖厨姐姐小厨。告诉我你冰箱里有什么食材,我来帮你推荐好吃的菜谱,一步步教你做出美味佳肴。',
  };

  /* ============== 状态 ============== */
  const avatarState = {
    connected: false,
    connecting: false,
    instance: null,
    subtitle: '',
    avatarState: '',
    listeners: new Set(),
  };

  /* ============== 订阅机制 ============== */
  function subscribe(listener) {
    avatarState.listeners.add(listener);
    return () => avatarState.listeners.delete(listener);
  }

  function notify() {
    avatarState.listeners.forEach(l => l());
  }

  function patch(partial) {
    Object.assign(avatarState, partial);
    notify();
  }

  /* ============== DOM 引用 ============== */
  const $ = (sel) => document.querySelector(sel);
  const containerId = 'xmov-avatar-container';

  function getSubtitleEl() { return $('#avatar-subtitle'); }
  function getLoadingEl() { return $('#avatar-loading'); }

  /* ============== 连接 ============== */
  async function connect() {
    if (avatarState.connected || avatarState.connecting) return;

    const containerEl = document.getElementById(containerId);
    if (!containerEl) {
      console.error('[Avatar] 容器不存在:', containerId);
      return;
    }

    patch({ connecting: true });
    updateLoadingUI(true);

    try {
      const url = new URL(AVATAR_CONFIG.gatewayUrl);
      url.searchParams.append('data_source', AVATAR_CONFIG.dataSource);
      url.searchParams.append('custom_id', AVATAR_CONFIG.customId);

      let resolveConnect;
      let rejectConnect;
      const connectPromise = new Promise((res, rej) => {
        resolveConnect = res;
        rejectConnect = rej;
      });

      const options = {
        containerId: `#${containerId}`,
        appId: AVATAR_CONFIG.appId,
        appSecret: AVATAR_CONFIG.appSecret,
        enableDebugger: false,
        gatewayServer: url.toString(),
        onProxyWidgetEvent: (event) => console.log('[Avatar SDK事件]', event),
        onStateChange: (state) => {
          patch({ avatarState: state });
        },
        onMessage: async (error) => {
          if (!avatarState.connected) {
            rejectConnect(new Error(error.message || 'SDK连接失败'));
          }
        },
        onVoiceStateChange: (status) => {
          if (status.includes('end')) {
            patch({ avatarState: 'interactive_idle' });
          }
        },
      };

      const avatar = new window.XmovAvatar(options);
      await new Promise(r => setTimeout(r, 3000));

      await avatar.init({
        onDownloadProgress: (progress) => {
          if (progress >= 100) {
            resolveConnect(true);
          }
        },
        onClose: () => {
          patch({ avatarState: '', connected: false });
        },
      });

      const timeout = new Promise((_, rej) => setTimeout(() => rej(new Error('连接超时')), 15000));
      try {
        await Promise.race([connectPromise, timeout]);
      } catch (e) {
        console.warn('[Avatar] 连接等待结束:', e.message);
      }

      avatarState.instance = avatar;
      patch({ connected: true, connecting: false });
      updateLoadingUI(false);
      console.log('[Avatar] 连接成功');

      setTimeout(() => {
        speakText(AVATAR_IDENTITY.greeting);
      }, 800);

    } catch (err) {
      console.error('[Avatar] 连接失败:', err);
      patch({ connected: false, connecting: false });
      updateLoadingUI(false);
    }
  }

  function disconnect() {
    if (avatarState.instance) {
      try {
        avatarState.instance.stop();
        avatarState.instance.destroy();
      } catch (e) {
        console.error('[Avatar] 断开失败:', e);
      }
      avatarState.instance = null;
      patch({ connected: false, avatarState: '' });
    }
  }

  /* ============== 播报 ============== */
  function speakText(text) {
    if (!avatarState.instance || !text) return;
    const ssml = `<speak>${text}</speak>`;
    avatarState.instance.speak(ssml, true, true);
    patch({ avatarState: 'speak' });
  }

  function interrupt() {
    if (!avatarState.instance) return;
    try {
      if (typeof avatarState.instance.interactiveidle === 'function') {
        avatarState.instance.interactiveidle();
      } else if (typeof avatarState.instance.interrupt === 'function') {
        avatarState.instance.interrupt();
      }
      patch({ avatarState: 'interactive_idle' });
    } catch (e) {
      console.error('[Avatar] 打断失败:', e);
    }
  }

  /* ============== 字幕 ============== */
  function setSubtitle(text) {
    patch({ subtitle: text });
    const el = getSubtitleEl();
    if (el) {
      el.textContent = text;
      el.classList.toggle('is-on', !!text);
    }
  }

  /* ============== UI 更新 ============== */
  function updateLoadingUI(show) {
    const el = getLoadingEl();
    if (el) {
      el.style.display = show ? 'flex' : 'none';
    }
  }

  /* ============== 初始化 ============== */
  function init() {
    console.log('[Avatar] 初始化数字人服务');
    connect();
  }

  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', init);
  } else {
    init();
  }

  /* ============== 暴露全局接口 ============== */
  window.AvatarService = {
    connect,
    disconnect,
    speakText,
    interrupt,
    setSubtitle,
    subscribe,
    getState: () => ({
      connected: avatarState.connected,
      connecting: avatarState.connecting,
      subtitle: avatarState.subtitle,
      avatarState: avatarState.avatarState,
    }),
    IDENTITY: AVATAR_IDENTITY,
  };

})();

这段代码的设计要点:

  1. IIFE 单例模式 :整个服务包裹在立即执行函数中,避免全局污染,只通过 window.AvatarService 暴露必要接口
  2. 订阅-通知机制subscribe/notify/patch 三件套,让 React 组件可以监听数字人状态变化
  3. 连接容错:15 秒超时 + Promise.race,避免 SDK 卡死导致页面白屏
  4. 播报与打断speakText 使用 SSML 格式,interrupt 支持实时打断切换

四、调味配比 · 菜谱数据建模

一道好菜,调味是关键。数字人已经就位,接下来需要准备她讲解的内容------菜谱数据。云厨的菜谱数据采用结构化 JSON 建模,每道菜谱包含完整的烹饪信息。

4.1 分类与食材库

js 复制代码
export const categories = [
  { id: 'all', name: '全部菜谱', icon: 'UtensilsCrossed' },
  { id: 'home', name: '家常菜', icon: 'Home' },
  { id: 'quick', name: '快手菜', icon: 'Zap' },
  { id: 'soup', name: '汤羹', icon: 'CupSoda' },
  { id: 'staple', name: '主食', icon: 'Wheat' },
  { id: 'dessert', name: '甜品', icon: 'Cherry' },
];

export const ingredientPool = [
  '鸡蛋', '西红柿', '土豆', '黄瓜', '豆腐', '猪肉', '鸡肉', '牛肉',
  '虾', '鱼', '白菜', '茄子', '青椒', '洋葱', '胡萝卜', '玉米',
  '米饭', '面条', '面粉', '牛奶', '苹果', '香蕉', '芒果',
];

4.2 菜谱数据结构

以「西红柿炒鸡蛋」为例,每道菜谱包含 id、名称、分类、难度、时长、食材列表、标签、描述、步骤、技巧共 10 个字段:

js 复制代码
{
  id: 'tomato_egg',
  name: '西红柿炒鸡蛋',
  category: 'home',
  difficulty: '简单',
  time: 15,
  ingredients: ['西红柿', '鸡蛋'],
  tags: ['经典', '下饭', '新手友好'],
  description: '国民家常菜,酸甜的西红柿配上嫩滑的鸡蛋,简单却百吃不厌。几乎每个中国家庭的餐桌上都少不了这道菜。',
  steps: [
    '西红柿切块,鸡蛋打散加少许盐搅匀',
    '热锅凉油,倒入蛋液炒至凝固盛出',
    '锅中再加少许油,放入西红柿翻炒出汁',
    '加入炒好的鸡蛋,加盐、少许糖调味',
    '翻炒均匀,撒葱花出锅',
  ],
  tips: '鸡蛋不要炒太老,七分凝固就盛出。西红柿要炒出红油才香,可以加一点点糖提鲜。',
},

4.3 食材匹配算法

用户勾选食材后,系统自动匹配包含这些食材的菜谱,按匹配度排序:

js 复制代码
export function matchRecipes(selectedIngredients) {
  if (!selectedIngredients.length) return recipes;
  return recipes
    .map((recipe) => {
      const matchCount = recipe.ingredients.filter((i) =>
        selectedIngredients.includes(i)
      ).length;
      return { ...recipe, matchCount };
    })
    .filter((r) => r.matchCount > 0)
    .sort((a, b) => b.matchCount - a.matchCount);
}

4.4 播报文案生成

将菜谱数据转化为自然语言播报文案,供数字人语音输出:

js 复制代码
export function generateRecipeBrief(recipe) {
  let brief = `${recipe.name},${recipe.difficulty}难度,大约需要${recipe.time}分钟。`;
  brief += recipe.description;
  brief += `需要准备的食材有:${recipe.ingredients.join('、')}。`;
  brief += `做法步骤:${recipe.steps.join(',然后')}。`;
  if (recipe.tips) {
    brief += `小厨提醒你:${recipe.tips}`;
  }
  return brief;
}

五、大火翻炒 · 前端组件架构

食材备好了,灶台也热了,现在把所有元素组合到一起。前端组件负责将菜谱数据呈现给用户,并在关键交互节点触发数字人播报------它是数据层与具身交互智能之间的桥梁。

5.1 主页面 App.jsx

App 组件管理三个核心状态:当前分类、已选食材、当前菜谱。通过 useMemo 实现响应式过滤:

js 复制代码
export default function App() {
  const [activeCategory, setActiveCategory] = useState('all');
  const [selectedIngredients, setSelectedIngredients] = useState([]);
  const [selectedRecipe, setSelectedRecipe] = useState(null);

  const toggleIngredient = (item) => {
    setSelectedIngredients((prev) =>
      prev.includes(item) ? prev.filter((i) => i !== item) : [...prev, item]
    );
  };

  const filteredRecipes = useMemo(() => {
    let result = activeCategory === 'all'
      ? recipes
      : recipes.filter((r) => r.category === activeCategory);

    if (selectedIngredients.length > 0) {
      result = matchRecipes(selectedIngredients);
      if (activeCategory !== 'all') {
        result = result.filter((r) => r.category === activeCategory);
      }
    }

    return result;
  }, [activeCategory, selectedIngredients]);

  return (
    <div className="app">
      <header className="app-header">
        <div className="app-header__brand">
          <ChefHat size={28} />
          <div>
            <h1>云厨 YunChef</h1>
            <p>具身交互智能食谱顾问 · 暖厨姐姐小厨</p>
          </div>
        </div>
        <CategoryNav categories={categories} active={activeCategory} onChange={setActiveCategory} />
      </header>

      <main className="app-main">
        <IngredientInput selected={selectedIngredients} onToggle={toggleIngredient} />

        {selectedIngredients.length > 0 && (
          <div className="match-banner">
            <span>🍳 根据你选择的 <strong>{selectedIngredients.join('、')}</strong>,小厨为你推荐了 {filteredRecipes.length} 道菜谱</span>
          </div>
        )}

        <div className="recipe-grid">
          {filteredRecipes.map((recipe) => (
            <RecipeCard key={recipe.id} recipe={recipe} matchCount={recipe.matchCount || 0} onClick={setSelectedRecipe} />
          ))}
        </div>

        {selectedRecipe && (
          <RecipeDetail recipe={selectedRecipe} onClose={() => setSelectedRecipe(null)} />
        )}
      </main>
    </div>
  );
}

5.2 菜谱详情与语音联动

RecipeDetail 组件是具身交互智能的核心交互点------点击「小厨讲解」按钮,触发数字人语音播报:

js 复制代码
export default function RecipeDetail({ recipe, onClose }) {
  if (!recipe) return null;

  const diff = difficultyConfig[recipe.difficulty] || difficultyConfig['简单'];

  const handleSpeak = () => {
    const brief = generateRecipeBrief(recipe);
    if (window.AvatarService) {
      window.AvatarService.interrupt?.();
      setTimeout(() => window.AvatarService.speakText(brief), 300);
    }
  };

  return (
    <div className="recipe-detail">
      <div className="recipe-detail__header">
        <div className="recipe-detail__title-row">
          <span className="recipe-detail__difficulty" style={{ color: diff.color, background: diff.bg }}>
            {recipe.difficulty}
          </span>
          <h2 className="recipe-detail__name">{recipe.name}</h2>
          <span className="recipe-detail__time">
            <Clock size={14} /> {recipe.time}分钟
          </span>
        </div>
        <div className="recipe-detail__actions">
          <button className="recipe-detail__speak-btn" onClick={handleSpeak} title="让小厨讲解菜谱">
            <Volume2 size={16} />
            <span>小厨讲解</span>
          </button>
          <button className="recipe-detail__close-btn" onClick={onClose}>
            <X size={18} />
          </button>
        </div>
      </div>

      <p className="recipe-detail__desc">{recipe.description}</p>

      <div className="recipe-detail__ingredients">
        <h4>🧄 所需食材</h4>
        <div className="recipe-detail__ingredient-list">
          {recipe.ingredients.map((ing) => (
            <span key={ing} className="recipe-detail__ingredient">{ing}</span>
          ))}
        </div>
      </div>

      <div className="recipe-detail__steps">
        <h4>👩🍳 做法步骤</h4>
        <ol className="recipe-detail__step-list">
          {recipe.steps.map((step, i) => (
            <li key={i} className="recipe-detail__step">
              <span className="recipe-detail__step-num">{i + 1}</span>
              <p>{step}</p>
            </li>
          ))}
        </ol>
      </div>

      {recipe.tips && (
        <div className="recipe-detail__tips">
          <h4>💡 小厨提醒</h4>
          <p>{recipe.tips}</p>
        </div>
      )}

      <div className="recipe-detail__tags">
        {recipe.tags?.map((tag) => (
          <span key={tag} className="recipe-detail__tag">{tag}</span>
        ))}
      </div>
    </div>
  );
}

交互流程:

  1. 用户点击菜谱卡片 → 左侧滑入详情面板
  2. 点击「小厨讲解」→ 先调用 interrupt() 打断当前播报
  3. 等待 300ms → 调用 speakText(brief) 开始新播报
  4. 数字人同步口型、手势,右下角框体内实时显示

六、精致摆盘 · 暖厨视觉设计系统

一道好菜,色香味俱全。功能已经跑通,最后一步是用视觉系统为整个项目定调------暖色奶油基底 + 琥珀橙主题色,营造温馨的厨房氛围。

6.1 CSS 令牌体系

js 复制代码
:root {
  --bg-base: #faf6f0;
  --bg-card: #ffffff;
  --bg-warm: #fff8f0;
  --bg-input: #fef3e2;

  --text-primary: #2d1b0e;
  --text-secondary: #6b4c35;
  --text-muted: #9c7a5f;
  --text-light: #c4a88a;

  --accent: #e67e22;
  --accent-light: #f59e0b;
  --accent-soft: rgba(230, 126, 34, 0.12);
  --accent-glow: rgba(230, 126, 34, 0.25);

  --green: #22c55e;
  --green-soft: rgba(34, 197, 94, 0.12);
  --red: #ef4444;
  --red-soft: rgba(239, 68, 68, 0.12);

  --border: rgba(205, 170, 130, 0.25);
  --border-strong: rgba(205, 170, 130, 0.45);

  --shadow-sm: 0 1px 3px rgba(139, 90, 43, 0.06);
  --shadow-md: 0 4px 12px rgba(139, 90, 43, 0.08);
  --shadow-lg: 0 8px 32px rgba(139, 90, 43, 0.12);

  --radius-sm: 8px;
  --radius-md: 12px;
  --radius-lg: 16px;
  --radius-xl: 20px;

  --font: 'Inter', 'PingFang SC', 'Microsoft YaHei', sans-serif;
}

6.2 数字人舞台样式

数字人框体采用毛玻璃效果,固定右下角,与菜谱详情面板(左侧)互不遮挡:

js 复制代码
.avatar-stage {
  position: fixed;
  right: 32px;
  bottom: 32px;
  width: 280px;
  height: 420px;
  z-index: 1000;
  pointer-events: none;
}

.avatar-stage__frame {
  position: relative;
  width: 100%;
  height: 100%;
  border-radius: 20px;
  background: rgba(255, 248, 240, 0.6);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  border: 1px solid rgba(230, 126, 34, 0.18);
  box-shadow:
    0 20px 60px -12px rgba(230, 126, 34, 0.12),
    0 8px 24px -8px rgba(0, 0, 0, 0.3);
  overflow: hidden;
  z-index: 1;
  pointer-events: auto;
}

.avatar-stage__box {
  position: absolute;
  inset: 0;
  overflow: visible;
}

.avatar-stage__sdk {
  width: 100%;
  height: 100%;
  overflow: visible;
}

/* SDK canvas 样式 */
.avatar-stage__sdk canvas,
.avatar-stage__sdk video {
  display: block !important;
  max-width: 130% !important;
  max-height: 100% !important;
  width: auto !important;
  height: auto !important;
  margin: 0 auto !important;
  position: relative !important;
  z-index: 3 !important;
  left: 0 !important;
  right: 0 !important;
}

.avatar-stage__sdk > div {
  overflow: visible !important;
}

关键设计:

  • overflow: visible 贯穿 box、sdk、内部 div,避免裁剪数字人肢体动作
  • max-width: 130% 为手臂抬起等动态动作预留显示空间
  • 详情面板在左侧滑入,数字人在右下角,布局互不干扰

七、上菜收尾 · 项目复盘与工程总结

菜已上桌,趁热复盘。云厨 YunChef 是一个基于 React 18 + Vite 6 构建的具身交互智能食谱顾问应用,从魔珐星云控制台配置数字人形象,到前端 IIFE 封装 SDK 服务,再到菜谱数据建模与语音播报联动,完整走通了具身交互智能在厨房场景的落地全链路------用户不再面对冷冰冰的菜谱列表,而是有一位温暖的暖厨姐姐站在旁边,看你冰箱里有什么就推荐什么,一步步教你做菜。回顾整个项目,具身交互智能在厨房场景的价值可以归纳为以下几点:

  • 从「搜索」到「对话」:用户不再需要在海量菜谱中筛选,告诉数字人你有什么食材,她直接推荐并讲解
  • 从「文字」到「陪伴」:菜谱不再是冷冰冰的步骤列表,而是一位温暖的姐姐在手把手教你做菜
  • 从「工具」到「伙伴」:数字人不是一次性使用的工具,而是一位可以反复请教、随时打断、永远耐心的烹饪伙伴
  • 食材驱动推荐:23 种食材库,勾选后智能匹配 12 道菜谱,按匹配度排序
  • 数字人语音讲解:点击「小厨讲解」,暖厨姐姐实时播报做法步骤,支持打断切换
  • 暖厨视觉系统:奶油基底 #faf6f0 + 琥珀橙 #e67e22,毛玻璃框体,温暖的厨房氛围

魔珐星云PC端官方链接https://xingyun3d.com?utm_campaign=daily\&utm_source=CSDNwanfen3\&utm_medium=\&utm_term=\&utm_content=

相关推荐
wei_shuo19 天前
具身交互智能播客生成器实战:TTS从零搭建双人对谈系统
具身交互智能
wei_shuo2 个月前
吃出健康新生活——魔珐星云AI具身交互智能营养师,您的私人膳食管理专家
具身交互智能
wei_shuo2 个月前
从零搭建枕月・MBTI人格分析师:魔珐星云具身交互智能数字人机身交互智能开发实战
数字人·具身交互智能