HarmonyOS 6(API 23)实战:打造“光味智厨“——AI烹饪新体验

文章目录


每日一句正能量

播种和收获一定不在同一天。

任何值得的结果都有因果间隔期。焦虑往往源于想跳过中间环节。记住这句,就会在付出后多一份从容:只管耕耘,等待自有意义。


一、前言:当烹饪遇上光感与智能

在快节奏的现代生活中,"今天吃什么"和"怎么做"成为许多人的日常困扰。传统烹饪应用往往停留在"静态菜谱展示"层面:用户需要一边盯着手机屏幕看步骤,一边手忙脚乱地操作食材,屏幕沾满油渍、亮度不合适、步骤切换繁琐等问题频发。更关键的是,这些应用缺乏环境感知能力------无法根据厨房的实际光照条件(如背光操作台、油烟雾气、夜间烹饪)动态优化显示,也无法理解用户当前的操作进度和食材状态。

HarmonyOS 6(API 23)带来的**悬浮导航(Floating Navigation)沉浸光感(Immersive Light Sensing)**两大核心能力,为智能烹饪应用开辟了全新的设计范式:

  • 沉浸光感能够实时感知厨房环境的光照变化(如油烟机灯光、窗外自然光、台灯光源),自动调整菜谱界面的对比度、色温和字体大小,确保在油手操作、蒸汽弥漫等复杂环境下依然清晰可读
  • 悬浮导航可在全屏烹饪模式下,以非侵入方式提供AI食材识别、步骤语音控制、火候提醒、营养分析等智能体交互入口,成为用户掌中的"数字 sous-chef(副厨)"

本文将实战演示如何构建**"光味智厨"**------一个能"看见"厨房环境、用光线引导烹饪节奏、通过悬浮AI助手提供实时烹饪指导的智能系统。系统不仅优化视觉体验,更能通过光感数据分析用户的操作节奏与疲劳度,动态调整教学语速与步骤提示强度。


二、核心能力与技术架构

2.1 沉浸光感的烹饪场景适配

HarmonyOS 6的AmbientLightFusion在API 23中针对烹饪场景进行了专项优化:

光感维度 烹饪场景映射 自适应策略
环境照度 厨房主灯/油烟机灯/自然光混合 动态调整菜谱文字对比度,防油手误触
色温变化 暖黄厨房灯 vs 冷白日光 食材图片色温校正,确保颜色真实
屏幕亮度 蒸汽/油烟导致的屏幕雾化 自动提升亮度,启用防雾显示模式
光照方向 背光操作台导致的阴影 高亮当前步骤区域,避开阴影覆盖
瞳孔变化 长时间专注切配导致的视觉疲劳 定时提醒休息,切换护眼模式

2.2 悬浮导航的烹饪交互范式

HarmonyOS 6的FloatingNavigation支持**"脏手免触"**模式------悬浮球支持手势控制(挥手、点头)和语音唤醒,用户无需触碰屏幕即可操作:

  • 在食材准备阶段 → 显示"AI识别/称重/替换建议"
  • 在烹饪阶段 → 显示"火候调节/计时器/下一步"
  • 在装盘阶段 → 显示"摆盘建议/拍照分享/营养分析"
  • 双手沾油时 → 语音控制"下一步""重复""暂停"

2.3 系统架构

复制代码
LightFlavorKitchen/
├── entry/src/main/ets/
│   ├── pages/
│   │   └── CookingStudio.ets          # 主烹饪工作室
│   ├── components/
│   │   ├── HandsFreeNavBall.ets      # 免触悬浮导航球
│   │    ├── AdaptiveRecipeCard.ets   # 自适应光感菜谱卡片
│   │    ├── AIChefPanel.ets          # AI厨师面板
│   │    ├── IngredientScanner.ets    # 食材扫描器
│   │    └── HeatVisualizer.ets       # 火候可视化
│   ├── services/
│   │    ├── KitchenLightAdapter.ets  # 厨房光感适配服务
│   │    ├── AIChefAgent.ets          # AI厨师智能体
│   │    ├── CookingTimer.ets         # 智能烹饪计时器
│   │    └── NutritionEngine.ets      # 营养分析引擎
│   └── models/
│       ├── Recipe.ets                  # 菜谱模型
│       └── CookingState.ets            # 烹饪状态模型

三、核心代码实战

3.1 厨房光感适配服务(KitchenLightAdapter.ets)

代码亮点: 本服务是系统的"厨房视觉管家"。它创新性地将厨房特有的光照挑战(油烟雾化、多光源混合、背光操作台)映射到UI适配策略。核心算法包括:蒸汽雾化补偿算法 通过检测环境湿度与光照散射度自动提升屏幕亮度和锐化度,多光源色温融合 分析厨房内所有光源的色温并计算综合白平衡,以及操作台阴影检测通过光照方向分析识别背光区域并高亮关键UI元素。

typescript 复制代码
// services/KitchenLightAdapter.ets
import { sensor } from '@kit.SensorServiceKit';
import { display } from '@kit.ArkUI';
import { hilog } from '@kit.PerformanceAnalysisKit';

// 厨房环境特征
export interface KitchenContext {
  lux: number;                    // 照度
  colorTemperature: number;       // 综合色温(K)
  humidity: number;               // 湿度(%)
  steamDensity: number;           // 蒸汽密度 0-1
  lightSources: Array<{          // 检测到的光源
    type: 'OVERHEAD' | 'RANGE_HOOD' | 'WINDOW' | 'TASK_LIGHT';
    lux: number;
    colorTemp: number;
    direction: { x: number; y: number; z: number };
  }>;
  isBacklit: boolean;            // 是否背光
  timestamp: number;
}

// 烹饪UI适配状态
@Observed
export class CookingUIState {
  screenBrightness: number = 80;
  textContrast: number = 7.0;           // 文字对比度
  imageSaturation: number = 1.0;        // 图片饱和度
  sharpnessBoost: number = 0;           // 锐化增强
  colorTempOffset: number = 0;          // 色温偏移
  fontSize: number = 16;
  buttonSize: number = 48;            // 按钮尺寸(防误触)
  isSteamMode: boolean = false;        // 蒸汽模式
  isNightCooking: boolean = false;     // 夜间烹饪
}

export class KitchenLightAdapter {
  private static instance: KitchenLightAdapter;
  private kitchenContext: KitchenContext = {
    lux: 300,
    colorTemperature: 4000,
    humidity: 50,
    steamDensity: 0,
    lightSources: [],
    isBacklit: false,
    timestamp: Date.now()
  };
  
  private stateListeners: Array<(state: CookingUIState) => void> = [];
  private currentState: CookingUIState = new CookingUIState();

  static getInstance(): KitchenLightAdapter {
    if (!KitchenLightAdapter.instance) {
      KitchenLightAdapter.instance = new KitchenLightAdapter();
    }
    return KitchenLightAdapter.instance;
  }

  async startAdaptation(): Promise<void> {
    // 1. 注册环境光传感器
    sensor.on(sensor.SensorId.AMBIENT_LIGHT, (data) => {
      this.kitchenContext.lux = data.intensity;
      this.processKitchenUpdate();
    });

    // 2. 注册湿度传感器(用于蒸汽检测)
    sensor.on(sensor.SensorId.HUMIDITY, (data) => {
      this.kitchenContext.humidity = data.value;
      this.estimateSteamDensity();
    });

    // 3. 启动多光源分析(通过摄像头+光感融合)
    this.startMultiSourceAnalysis();

    // 4. 启动背光检测
    this.startBacklightDetection();

    hilog.info(0x0000, 'KitchenLight', '厨房光感适配服务启动');
  }

  private processKitchenUpdate(): void {
    // 1. 计算综合色温(多光源加权)
    const blendedTemp = this.calculateBlendedColorTemp();
    this.kitchenContext.colorTemperature = blendedTemp;

    // 2. 检测蒸汽密度
    this.estimateSteamDensity();

    // 3. 生成UI适配状态
    const newState = this.generateUIState();
    
    // 4. 平滑过渡
    this.smoothTransition(newState);
  }

  private calculateBlendedColorTemp(): number {
    const sources = this.kitchenContext.lightSources;
    if (sources.length === 0) return 4000;

    // 加权平均:越亮的光源权重越高
    const totalLux = sources.reduce((sum, s) => sum + s.lux, 0);
    const weightedTemp = sources.reduce((sum, s) => 
      sum + s.colorTemp * (s.lux / totalLux), 0);
    
    return Math.round(weightedTemp);
  }

  private estimateSteamDensity(): void {
    // 蒸汽密度 = f(湿度变化率, 照度散射, 温度)
    const humidityDelta = Math.max(0, this.kitchenContext.humidity - 50);
    const lightScatter = this.kitchenContext.lux < 100 ? 0.3 : 0;
    
    this.kitchenContext.steamDensity = Math.min(1, 
      (humidityDelta / 50) * 0.6 + lightScatter * 0.4);
  }

  private generateUIState(): CookingUIState {
    const ctx = this.kitchenContext;
    const state = new CookingUIState();

    // 1. 屏幕亮度:蒸汽环境下大幅提升
    state.screenBrightness = Math.min(100, 
      60 + ctx.steamDensity * 30 + (ctx.lux < 100 ? 20 : 0));
    
    // 2. 文字对比度:低照度或蒸汽环境下增强
    state.textContrast = Math.min(12, 
      7.0 + ctx.steamDensity * 3 + (ctx.lux < 50 ? 2 : 0));
    
    // 3. 图片饱和度:蒸汽环境下增强,补偿雾化导致的色彩损失
    state.imageSaturation = Math.min(1.5, 1.0 + ctx.steamDensity * 0.5);
    
    // 4. 锐化增强:蒸汽环境下提升边缘清晰度
    state.sharpnessBoost = ctx.steamDensity * 0.5;
    
    // 5. 色温偏移:校正多光源导致的偏色
    const targetTemp = 5500; // D55标准光源
    state.colorTempOffset = (targetTemp - ctx.colorTemperature) / 100;
    
    // 6. 字体和按钮:油手环境下增大触控区域
    state.fontSize = ctx.steamDensity > 0.3 ? 18 : 16;
    state.buttonSize = ctx.steamDensity > 0.3 ? 56 : 48;
    
    // 7. 模式标记
    state.isSteamMode = ctx.steamDensity > 0.4;
    state.isNightCooking = ctx.lux < 80 && new Date().getHours() >= 20;

    return state;
  }

  private smoothTransition(targetState: CookingUIState): void {
    // 使用Animator实现平滑过渡,避免UI跳变
    const animator = Animator.create({
      duration: 500,
      curve: Curve.EaseInOut,
      iterations: 1
    });

    animator.onFrame = (value: number) => {
      this.currentState = {
        screenBrightness: this.lerp(this.currentState.screenBrightness, targetState.screenBrightness, value),
        textContrast: this.lerp(this.currentState.textContrast, targetState.textContrast, value),
        imageSaturation: this.lerp(this.currentState.imageSaturation, targetState.imageSaturation, value),
        sharpnessBoost: this.lerp(this.currentState.sharpnessBoost, targetState.sharpnessBoost, value),
        colorTempOffset: this.lerp(this.currentState.colorTempOffset, targetState.colorTempOffset, value),
        fontSize: Math.round(this.lerp(this.currentState.fontSize, targetState.fontSize, value)),
        buttonSize: Math.round(this.lerp(this.currentState.buttonSize, targetState.buttonSize, value)),
        isSteamMode: targetState.isSteamMode,
        isNightCooking: targetState.isNightCooking
      };
      
      this.notifyStateUpdate();
    };

    animator.play();
  }

  private lerp(start: number, end: number, t: number): number {
    return start + (end - start) * t;
  }

  private startMultiSourceAnalysis(): void {
    // 通过前置摄像头分析环境光的光谱分布
    // 识别不同光源类型(LED、白炽灯、自然光)
    // 简化实现:模拟多光源检测
    setInterval(() => {
      const hour = new Date().getHours();
      const sources = [];
      
      // 厨房主灯(始终存在)
      sources.push({
        type: 'OVERHEAD' as const,
        lux: 200,
        colorTemp: 3500,
        direction: { x: 0, y: -1, z: 0 }
      });
      
      // 油烟机灯(烹饪时)
      if (this.kitchenContext.humidity > 60) {
        sources.push({
          type: 'RANGE_HOOD' as const,
          lux: 150,
          colorTemp: 4000,
          direction: { x: 0, y: 0, z: 1 }
        });
      }
      
      // 自然光(白天)
      if (hour >= 8 && hour <= 18) {
        sources.push({
          type: 'WINDOW' as const,
          lux: 300,
          colorTemp: 6500,
          direction: { x: 1, y: 0.5, z: 0 }
        });
      }
      
      this.kitchenContext.lightSources = sources;
    }, 5000);
  }

  private startBacklightDetection(): void {
    // 检测用户是否背对光源操作
    // 通过分析面部光照与背景光照的差异
    setInterval(() => {
      // 简化:如果环境光主要来自后方且面部较暗,判定为背光
      const windowLight = this.kitchenContext.lightSources.find(s => s.type === 'WINDOW');
      this.kitchenContext.isBacklit = !!windowLight && windowLight.lux > 400;
    }, 3000);
  }

  onStateChanged(callback: (state: CookingUIState) => void): void {
    this.stateListeners.push(callback);
  }

  private notifyStateUpdate(): void {
    this.stateListeners.forEach(cb => cb(this.currentState));
  }

  getCurrentState(): CookingUIState {
    return this.currentState;
  }

  getKitchenContext(): KitchenContext {
    return this.kitchenContext;
  }

  stopAdaptation(): void {
    sensor.off(sensor.SensorId.AMBIENT_LIGHT);
    sensor.off(sensor.SensorId.HUMIDITY);
    this.stateListeners = [];
  }
}

3.2 免触悬浮导航球(HandsFreeNavBall.ets)

代码亮点: 这是系统的"数字副厨"。悬浮球针对烹饪场景的"脏手"痛点进行了专项设计:支持手势控制 (挥手切换步骤)、语音唤醒("下一步""重复""暂停")、以及** proximity感应**(手靠近时自动放大)。悬浮球的颜色和脉动节奏反映当前烹饪阶段------准备阶段为绿色平缓,烹饪阶段为橙色急促(同步火候),装盘阶段为金色闪耀。

typescript 复制代码
// components/HandsFreeNavBall.ets
import { FloatingNavigation } from '@kit.ArkUI';
import { AIChefAgent } from '../services/AIChefAgent';
import { KitchenLightAdapter, CookingUIState } from '../services/KitchenLightAdapter';
import { speechRecognizer } from '@kit.SpeechKit';

export enum CookingPhase {
  PREP = 'PREP',           // 食材准备
  COOK = 'COOK',           // 烹饪中
  PLATE = 'PLATE',         // 装盘
  SERVE = 'SERVE'          // 上菜
}

interface VoiceCommand {
  keywords: string[];
  action: () => void;
}

@Component
export struct HandsFreeNavBall {
  @State ballScale: number = 1.0;
  @State ballColor: ResourceColor = '#4CAF50';
  @State isExpanded: boolean = false;
  @State currentPhase: CookingPhase = CookingPhase.PREP;
  @State isListening: boolean = false;  // 语音识别中
  @State proximityDetected: boolean = false; // 手靠近检测
  @State currentStep: number = 1;
  @State totalSteps: number = 8;
  
  private aiChef: AIChefAgent = new AIChefAgent();
  private lightAdapter: KitchenLightAdapter = KitchenLightAdapter.getInstance();
  
  // 语音命令映射
  private readonly VOICE_COMMANDS: VoiceCommand[] = [
    { keywords: ['下一步', '下一个', '继续'], action: () => this.nextStep() },
    { keywords: ['上一步', '返回', '回去'], action: () => this.prevStep() },
    { keywords: ['重复', '再说一遍', '没听清'], action: () => this.repeatStep() },
    { keywords: ['暂停', '等一下'], action: () => this.pauseCooking() },
    { keywords: ['计时', '倒计时'], action: () => this.startTimer() },
    { keywords: ['识别食材', '这是什么'], action: () => this.scanIngredient() },
    { keywords: ['火候', '温度'], action: () => this.showHeatGuide() },
    { keywords: ['营养', '热量'], action: () => this.showNutrition() }
  ];

  aboutToAppear() {
    // 监听烹饪阶段变化
    this.aiChef.onPhaseChanged((phase) => {
      this.currentPhase = phase;
      this.updateBallByPhase(phase);
    });

    // 监听光感状态
    this.lightAdapter.onStateChanged((state) => {
      this.adaptToSteam(state);
    });

    // 启动语音识别
    this.startVoiceRecognition();
    
    // 启动接近感应
    this.startProximityDetection();
    
    // 启动阶段脉动动画
    this.startPhasePulse();
  }

  private updateBallByPhase(phase: CookingPhase): void {
    switch (phase) {
      case CookingPhase.PREP:
        this.ballColor = '#4CAF50'; // 绿色:准备
        break;
      case CookingPhase.COOK:
        this.ballColor = '#FF9800'; // 橙色:烹饪
        break;
      case CookingPhase.PLATE:
        this.ballColor = '#FFD700'; // 金色:装盘
        break;
      case CookingPhase.SERVE:
        this.ballColor = '#E91E63'; // 粉色:完成
        break;
    }
  }

  private adaptToSteam(state: CookingUIState): void {
    // 蒸汽环境下增大悬浮球,便于油手操作
    if (state.isSteamMode) {
      this.ballScale = 1.2;
    } else {
      this.ballScale = 1.0;
    }
  }

  private startPhasePulse(): void {
    setInterval(() => {
      switch (this.currentPhase) {
        case CookingPhase.PREP:
          // 准备阶段:平缓呼吸
          this.ballScale = 1.0 + Math.sin(Date.now() / 1000) * 0.05;
          break;
        case CookingPhase.COOK:
          // 烹饪阶段:与火候同步的急促脉动
          this.ballScale = 1.0 + Math.sin(Date.now() / 300) * 0.15;
          break;
        case CookingPhase.PLATE:
          // 装盘阶段:优雅的慢速闪耀
          this.ballScale = 1.0 + Math.sin(Date.now() / 1500) * 0.1;
          break;
      }
    }, 50);
  }

  private startVoiceRecognition(): void {
    // 持续监听语音命令
    speechRecognizer.on('result', (result) => {
      const text = result.text;
      this.processVoiceCommand(text);
    });
    
    speechRecognizer.startListening({
      language: 'zh-CN',
      partialResults: true,
    });
  }

  private processVoiceCommand(text: string): void {
    this.isListening = true;
    
    for (const cmd of this.VOICE_COMMANDS) {
      if (cmd.keywords.some(k => text.includes(k))) {
        cmd.action();
        this.isListening = false;
        return;
      }
    }
    
    // 未识别的命令,询问AI厨师
    this.aiChef.askQuestion(text);
    this.isListening = false;
  }

  private startProximityDetection(): void {
    // 通过接近传感器检测手是否靠近
    // 简化实现:使用前置摄像头检测手部区域
    setInterval(() => {
      // 模拟接近检测
      this.proximityDetected = Math.random() > 0.7;
    }, 1000);
  }

  // ===== 动作实现 =====
  private nextStep(): void {
    if (this.currentStep < this.totalSteps) {
      this.currentStep++;
      this.aiChef.speakStep(this.currentStep);
      this.flashBall();
    }
  }

  private prevStep(): void {
    if (this.currentStep > 1) {
      this.currentStep--;
      this.aiChef.speakStep(this.currentStep);
      this.flashBall();
    }
  }

  private repeatStep(): void {
    this.aiChef.speakStep(this.currentStep);
    this.flashBall();
  }

  private pauseCooking(): void {
    this.aiChef.pause();
  }

  private startTimer(): void {
    this.aiChef.startStepTimer(this.currentStep);
  }

  private scanIngredient(): void {
    // 唤起摄像头进行食材识别
    this.aiChef.identifyIngredient();
  }

  private showHeatGuide(): void {
    // 显示火候指导
  }

  private showNutrition(): void {
    // 显示营养分析
  }

  private flashBall(): void {
    const originalScale = this.ballScale;
    this.ballScale = 1.4;
    setTimeout(() => {
      this.ballScale = originalScale;
    }, 200);
  }

  build() {
    Stack() {
      // 语音识别指示器(聆听中时显示)
      if (this.isListening) {
        Column() {
          ForEach([1, 2, 3, 4], (item: number) => {
            Column()
              .width(4)
              .height(8 + item * 4)
              .backgroundColor('#FFFFFF')
              .borderRadius(2)
              .margin({ left: 2, right: 2 })
              .animation({
                duration: 400,
                curve: Curve.EaseInOut,
                iterations: -1,
                playMode: PlayMode.Alternate
              })
          })
        }
        .flexDirection(FlexDirection.Row)
        .position({ x: -40, y: 15 })
      }

      // 接近感应放大效果
      if (this.proximityDetected && !this.isExpanded) {
        Circle()
          .width(80)
          .height(80)
          .fill('rgba(255,255,255,0.1)')
          .position({ x: -13, y: -13 })
          .animation({
            duration: 300,
            curve: Curve.EaseOut
          })
      }

      // 扇形菜单(展开时)
      if (this.isExpanded) {
        // 步骤导航
        this.MenuButton($r('app.media.ic_prev'), '上一步', () => this.prevStep(), 0)
        this.MenuButton($r('app.media.ic_next'), '下一步', () => this.nextStep(), 1)
        this.MenuButton($r('app.media.ic_timer'), '计时器', () => this.startTimer(), 2)
        this.MenuButton($r('app.media.ic_camera'), '识食材', () => this.scanIngredient(), 3)
        this.MenuButton($r('app.media.ic_nutrition'), '营养', () => this.showNutrition(), 4)
      }

      // 主悬浮球
      Column() {
        if (this.isListening) {
          // 聆听中显示声波
          Image($r('app.media.ic_mic'))
            .width(28)
            .height(28)
            .fillColor('#FFFFFF')
        } else {
          // 显示当前步骤进度
          Stack() {
            Circle()
              .width(54)
              .height(54)
              .stroke(this.ballColor)
              .strokeWidth(3)
              .fill('transparent')
            
            Text(`${this.currentStep}`)
              .fontSize(20)
              .fontColor('#FFFFFF')
              .fontWeight(FontWeight.Bold)
          }
        }
      }
      .width(54)
      .height(54)
      .backgroundColor(this.ballColor)
      .borderRadius(27)
      .scale({ x: this.ballScale, y: this.ballScale })
      .shadow({ 
        radius: 14, 
        color: this.ballColor,
        offsetY: 4
      })
      .onClick(() => {
        this.isExpanded = !this.isExpanded;
      })
      .gesture(
        // 挥手检测:左右滑动切换步骤
        PanGesture({ direction: PanDirection.Horizontal })
          .onActionEnd((event) => {
            if (event.offsetX > 50) {
              this.nextStep();
            } else if (event.offsetX < -50) {
              this.prevStep();
            }
          })
      )
      .animation({
        duration: 150,
        curve: Curve.EaseInOut
      })
    }
    .width(220)
    .height(220)
    .position({ x: 300, y: 600 })
  }

  @Builder
  MenuButton(icon: Resource, label: string, action: () => void, index: number) {
    Column() {
      Image(icon)
        .width(22)
        .height(22)
        .fillColor('#FFFFFF')
      Text(label)
        .fontSize(10)
        .fontColor('#FFFFFF')
        .margin({ top: 3 })
    }
    .width(50)
    .height(50)
    .backgroundColor('rgba(0,0,0,0.75)')
    .borderRadius(25)
    .position({
      x: this.getMenuX(index),
      y: this.getMenuY(index)
    })
    .onClick(() => {
      action();
      this.isExpanded = false;
    })
    .animation({
      duration: 250,
      curve: Curve.Spring,
      delay: index * 40
    })
  }

  private getMenuX(index: number): number {
    const angles = [200, 230, 260, 290, 320];
    const radius = 90;
    const angle = (angles[index] || 260) * Math.PI / 180;
    return 110 + radius * Math.cos(angle) - 25;
  }

  private getMenuY(index: number): number {
    const angles = [200, 230, 260, 290, 320];
    const radius = 90;
    const angle = (angles[index] || 260) * Math.PI / 180;
    return 110 + radius * Math.sin(angle) - 25;
  }
}

3.3 自适应光感菜谱卡片(AdaptiveRecipeCard.ets)

代码亮点: 这是用户直接"看见"的核心界面。它集成了厨房光感适配服务,实现菜谱展示的实时动态优化。核心创新是**"食材真色还原"**------通过多光源色温分析,校正食材图片的显示色彩,确保用户看到的颜色与真实食材一致。蒸汽雾化补偿在检测到高湿度环境时,自动提升图片锐度和对比度,避免蒸汽导致的视觉模糊。

typescript 复制代码
// components/AdaptiveRecipeCard.ets
import { KitchenLightAdapter, CookingUIState } from '../services/KitchenLightAdapter';

interface RecipeStep {
  number: number;
  description: string;
  duration?: number;      // 步骤耗时(秒)
  temperature?: number;     // 温度(℃)
  imageUrl?: string;
  tips: string[];
}

@Component
export struct AdaptiveRecipeCard {
  @State uiState: CookingUIState = new CookingUIState();
  @State currentStep: number = 1;
  @State isCurrentStep: boolean = true;
  
  private lightAdapter: KitchenLightAdapter = KitchenLightAdapter.getInstance();
  
  // 示例菜谱步骤
  private steps: RecipeStep[] = [
    {
      number: 1,
      description: '将鸡胸肉切成2厘米见方的丁,加入少许盐和料酒腌制10分钟',
      duration: 600,
      tips: ['刀要锋利,切口平整', '腌制时放入冰箱']
    },
    {
      number: 2,
      description: '热锅凉油,油温六成热时下入鸡丁滑散至变色',
      duration: 180,
      temperature: 180,
      tips: ['油温不要过高,避免外焦里生', '用筷子划散,不要翻炒']
    },
    {
      number: 3,
      description: '加入切好的青椒、红椒丁,大火快炒30秒',
      duration: 30,
      tips: ['保持大火,锁住蔬菜水分']
    }
  ];

  aboutToAppear() {
    this.lightAdapter.onStateChanged((state) => {
      this.uiState = state;
    });
    this.lightAdapter.startAdaptation();
  }

  // 色温校正:将图片色彩调整至接近真实
  private colorCorrectImage(): object {
    const offset = this.uiState.colorTempOffset;
    return {
      brightness: 1.0,
      contrast: this.uiState.textContrast / 7.0,
      saturate: this.uiState.imageSaturation,
      // 色温偏移通过滤镜实现
      // 正偏移:偏冷(增加蓝)
      // 负偏移:偏暖(增加红/黄)
    };
  }

  // 蒸汽模式下的锐化滤镜
  private getSteamFilter(): object {
    if (!this.uiState.isSteamMode) return {};
    return {
      // 使用高对比度+锐化模拟
      contrast: 1.2,
      // 实际应使用Canvas滤镜
    };
  }

  build() {
    Column() {
      // 步骤标题栏
      Row() {
        Text(`步骤 ${this.currentStep}/${this.steps.length}`)
          .fontSize(this.uiState.fontSize + 2)
          .fontColor('#FFFFFF')
          .fontWeight(FontWeight.Bold)
        
        Blank()
        
        // 蒸汽模式指示
        if (this.uiState.isSteamMode) {
          Row() {
            Image($r('app.media.ic_steam'))
              .width(18)
              .height(18)
              .fillColor('#FF9800')
            Text('蒸汽模式')
              .fontSize(12)
              .fontColor('#FF9800')
              .margin({ left: 4 })
          }
        }
        
        // 夜间模式指示
        if (this.uiState.isNightCooking) {
          Row() {
            Image($r('app.media.ic_moon'))
              .width(18)
              .height(18)
              .fillColor('#9C27B0')
            Text('夜间烹饪')
              .fontSize(12)
              .fontColor('#9C27B0')
              .margin({ left: 4 })
          }
          .margin({ left: 8 })
        }
      }
      .width('100%')
      .height(50)
      .padding({ left: 16, right: 16 })
      .backgroundColor('rgba(0,0,0,0.6)')

      // 步骤内容区
      Scroll() {
        Column() {
          // 步骤图片(带色温校正)
          if (this.steps[this.currentStep - 1]?.imageUrl) {
            Image(this.steps[this.currentStep - 1].imageUrl)
              .width('100%')
              .height(200)
              .objectFit(ImageFit.Cover)
              // 应用色温校正和蒸汽滤镜
              .brightness(1.0 + this.uiState.sharpnessBoost * 0.2)
              .contrast(this.uiState.textContrast / 7.0)
              .saturate(this.uiState.imageSaturation)
          }

          // 步骤描述
          Text(this.steps[this.currentStep - 1]?.description || '')
            .fontSize(this.uiState.fontSize)
            .fontColor('#FFFFFF')
            .margin({ top: 16, left: 16, right: 16 })
            .lineHeight(this.uiState.fontSize * 1.6)

          // 温度/时间指示
          if (this.steps[this.currentStep - 1]?.temperature) {
            Row() {
              Image($r('app.media.ic_thermometer'))
                .width(20)
                .height(20)
                .fillColor('#F44336')
              Text(`${this.steps[this.currentStep - 1].temperature}℃`)
                .fontSize(this.uiState.fontSize)
                .fontColor('#F44336')
                .margin({ left: 6 })
            }
            .margin({ top: 12, left: 16 })
          }

          if (this.steps[this.currentStep - 1]?.duration) {
            Row() {
              Image($r('app.media.ic_timer'))
                .width(20)
                .height(20)
                .fillColor('#2196F3')
              Text(`${this.steps[this.currentStep - 1].duration}秒`)
                .fontSize(this.uiState.fontSize)
                .fontColor('#2196F3')
                .margin({ left: 6 })
            }
            .margin({ top: 8, left: 16 })
          }

          // 小贴士
          Column() {
            Text('💡 小贴士')
              .fontSize(this.uiState.fontSize - 2)
              .fontColor('#FFD700')
              .fontWeight(FontWeight.Bold)
            
            ForEach(this.steps[this.currentStep - 1]?.tips || [], (tip: string) => {
              Text(`• ${tip}`)
                .fontSize(this.uiState.fontSize - 2)
                .fontColor('rgba(255,255,255,0.8)')
                .margin({ top: 6 })
            })
          }
          .width('100%')
          .padding(12)
          .backgroundColor('rgba(255,255,255,0.1)')
          .borderRadius(8)
          .margin({ top: 16, left: 16, right: 16 })

          // 底部留白(避免被悬浮球遮挡)
          Blank()
            .height(100)
        }
        .width('100%')
      }
      .width('100%')
      .layoutWeight(1)
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#1a1a1a')
  }
}

3.4 AI厨师智能体(AIChefAgent.ets)

代码亮点: 这是系统的"数字主厨"。它基于端侧大模型,提供实时烹饪指导。核心创新是**"光感感知式教学"------当检测到厨房光线昏暗(如夜间烹饪)时,AI会自动放慢语速、使用更简洁的指令;当检测到蒸汽弥漫时,会提高音量并重复关键步骤。同时支持"食材替代智能推荐"**,根据用户冰箱内的现有食材,动态调整菜谱。

typescript 复制代码
// services/AIChefAgent.ets
import { KitchenLightAdapter } from './KitchenLightAdapter';
import { textToSpeech } from '@kit.SpeechKit';
import { hilog } from '@kit.PerformanceAnalysisKit';

export interface ChefGuidance {
  speech: string;
  visualHint?: string;      // 视觉提示(如"大火""小火"的光效)
  urgency: 'low' | 'medium' | 'high'; // 紧急程度
  estimatedTime: number;    // 预计执行时间
}

export class AIChefAgent {
  private lightAdapter: KitchenLightAdapter;
  private currentRecipe: any;
  private currentStep: number = 0;
  private isPaused: boolean = false;
  private phaseListeners: Array<(phase: string) => void> = [];
  private currentPhase: string = 'PREP';

  constructor() {
    this.lightAdapter = KitchenLightAdapter.getInstance();
  }

  async loadRecipe(recipeId: string): Promise<void> {
    // 加载菜谱数据
    this.currentRecipe = await this.fetchRecipe(recipeId);
    this.currentStep = 0;
  }

  async speakStep(stepNumber: number): Promise<void> {
    if (!this.currentRecipe || this.isPaused) return;
    
    const step = this.currentRecipe.steps[stepNumber - 1];
    if (!step) return;

    this.currentStep = stepNumber;

    // 根据厨房环境调整语音风格
    const style = this.adaptSpeechStyle();
    
    // 构建语音内容
    let speech = '';
    
    if (style.isQuiet) {
      // 夜间/安静环境:简短指令
      speech = `第${stepNumber}步。${step.shortDescription}。`;
    } else {
      // 正常环境:详细指导
      speech = `第${stepNumber}步,共${this.currentRecipe.steps.length}步。${step.description}。`;
      
      if (step.tips && step.tips.length > 0) {
        speech += `小贴士:${step.tips[0]}。`;
      }
      
      if (step.duration) {
        speech += `预计耗时${step.duration}秒。`;
      }
    }

    if (style.isLoud) {
      // 嘈杂环境:重复关键信息
      speech += `重复:${step.keyAction}。`;
    }

    // 生成视觉提示
    const visualHint = this.generateVisualHint(step);

    // 播放语音
    await this.speak(speech, style);

    // 更新烹饪阶段
    this.updatePhase(step);
  }

  private adaptSpeechStyle(): { 
    isQuiet: boolean; 
    isLoud: boolean; 
    speed: number; 
    pitch: number; 
  } {
    const ctx = this.lightAdapter.getKitchenContext();
    const hour = new Date().getHours();
    
    const isNight = hour >= 22 || hour <= 6;
    const isNoisy = ctx.steamDensity > 0.5; // 油烟机噪音大
    const isDim = ctx.lux < 100;

    return {
      isQuiet: isNight || isDim,
      isLoud: isNoisy,
      speed: isNight ? 0.8 : (isNoisy ? 0.9 : 1.0),
      pitch: isNoisy ? 1.1 : 1.0 // 嘈杂环境提高音调
    };
  }

  private generateVisualHint(step: any): string {
    // 根据步骤类型生成光效提示
    if (step.temperature && step.temperature > 200) {
      return 'HEAT_HIGH'; // 大火:红色脉冲
    }
    if (step.temperature && step.temperature < 100) {
      return 'HEAT_LOW'; // 小火:蓝色稳定
    }
    if (step.duration && step.duration < 30) {
      return 'QUICK_ACTION'; // 快速操作:黄色闪烁
    }
    return 'NORMAL';
  }

  private async speak(text: string, style: { speed: number; pitch: number }): Promise<void> {
    try {
      await textToSpeech.speak({
        text: text,
        voice: 'zh-CN-female-warm',
        speed: style.speed,
        pitch: style.pitch,
        volume: style.isLoud ? 1.0 : 0.7
      });
    } catch (err) {
      hilog.error(0x0000, 'AIChef', `语音播放失败: ${err.message}`);
    }
  }

  private updatePhase(step: any): void {
    let newPhase = this.currentPhase;
    
    // 根据步骤内容推断阶段
    if (step.description.includes('切') || step.description.includes('腌')) {
      newPhase = 'PREP';
    } else if (step.description.includes('炒') || step.description.includes('煮') || step.description.includes('煎')) {
      newPhase = 'COOK';
    } else if (step.description.includes('盘') || step.description.includes('摆')) {
      newPhase = 'PLATE';
    } else if (step.description.includes('上桌') || step.description.includes('完成')) {
      newPhase = 'SERVE';
    }

    if (newPhase !== this.currentPhase) {
      this.currentPhase = newPhase;
      this.phaseListeners.forEach(cb => cb(newPhase));
    }
  }

  async identifyIngredient(): Promise<void> {
    // 唤起摄像头,使用端侧视觉模型识别食材
    const result = await this.callVisionModel();
    
    const speech = `识别结果:${result.name}。${result.description}。建议烹饪方式:${result.suggestedMethods.join('、')}。`;
    await this.speak(speech, { speed: 0.9, pitch: 1.0 });
  }

  async suggestSubstitute(missingIngredient: string): Promise<void> {
    // 基于知识图谱推荐替代品
    const substitutes = await this.querySubstitute(missingIngredient);
    
    let speech = `${missingIngredient}可以用以下食材替代:`;
    substitutes.forEach((sub, i) => {
      speech += `${i + 1}、${sub.name},${sub.ratio}。`;
    });
    
    await this.speak(speech, { speed: 0.9, pitch: 1.0 });
  }

  async startStepTimer(stepNumber: number): Promise<void> {
    const step = this.currentRecipe?.steps[stepNumber - 1];
    if (!step?.duration) return;

    // 启动倒计时
    const duration = step.duration;
    
    // 最后10秒语音提醒
    setTimeout(async () => {
      await this.speak('还有10秒', { speed: 1.0, pitch: 1.1 });
    }, (duration - 10) * 1000);

    // 时间到提醒
    setTimeout(async () => {
      await this.speak('时间到!请进行下一步。', { speed: 1.0, pitch: 1.2 });
    }, duration * 1000);
  }

  async askQuestion(question: string): Promise<void> {
    // 处理用户的烹饪问题
    const answer = await this.callCookingLLM(question);
    await this.speak(answer, { speed: 0.9, pitch: 1.0 });
  }

  pause(): void {
    this.isPaused = true;
  }

  resume(): void {
    this.isPaused = false;
  }

  onPhaseChanged(callback: (phase: string) => void): void {
    this.phaseListeners.push(callback);
  }

  private async fetchRecipe(recipeId: string): Promise<any> {
    // 从本地或云端加载菜谱
    return {
      id: recipeId,
      name: '宫保鸡丁',
      steps: [
        { number: 1, description: '将鸡胸肉切成2厘米见方的丁...', shortDescription: '切鸡丁腌制', duration: 600, keyAction: '切鸡丁' },
        { number: 2, description: '热锅凉油,油温六成热时下入鸡丁...', shortDescription: '滑炒鸡丁', duration: 180, temperature: 180, keyAction: '滑炒' }
      ]
    };
  }

  private async callVisionModel(): Promise<any> {
    // 调用端侧视觉模型识别食材
    return { name: '鸡胸肉', description: '新鲜鸡胸肉,适合快炒', suggestedMethods: ['滑炒', '煎炸'] };
  }

  private async querySubstitute(ingredient: string): Promise<any[]> {
    // 查询食材替代知识图谱
    return [
      { name: '鸡腿肉', ratio: '等量替换,口感更嫩' },
      { name: '猪里脊', ratio: '等量替换,需减少烹饪时间' }
    ];
  }

  private async callCookingLLM(question: string): Promise<string> {
    // 调用端侧烹饪大模型
    return '根据您的提问,建议...';
  }
}

3.5 火候可视化组件(HeatVisualizer.ets)

代码亮点: 这是系统的"火候仪表盘"。它通过Canvas 2D绘制动态热力图,将抽象的"大火""中火""小火"转化为直观的视觉反馈。支持光感联动------在昏暗环境下自动增强亮度和对比度,确保用户能清晰看到火候指示。同时与悬浮球同步脉动,形成"视觉-触觉"双通道提醒。

typescript 复制代码
// components/HeatVisualizer.ets
import { KitchenLightAdapter, CookingUIState } from '../services/KitchenLightAdapter';

@Component
export struct HeatVisualizer {
  @State heatLevel: number = 0; // 0-100,对应火候
  @State targetHeat: number = 0;
  @State uiState: CookingUIState = new CookingUIState();
  
  private lightAdapter: KitchenLightAdapter = KitchenLightAdapter.getInstance();
  private canvasCtx: CanvasRenderingContext2D | null = null;
  private heatAnimator?: Animator;

  aboutToAppear() {
    this.lightAdapter.onStateChanged((state) => {
      this.uiState = state;
    });
    
    this.startHeatAnimation();
  }

  private startHeatAnimation(): void {
    const animate = () => {
      this.drawHeatGauge();
      requestAnimationFrame(animate);
    };
    animate();
  }

  setTargetHeat(level: number): void {
    this.targetHeat = Math.max(0, Math.min(100, level));
  }

  private drawHeatGauge(): void {
    if (!this.canvasCtx) return;
    
    const ctx = this.canvasCtx;
    const width = 200;
    const height = 200;
    const centerX = width / 2;
    const centerY = height / 2;
    const radius = 80;

    // 清空
    ctx.clearRect(0, 0, width, height);

    // 当前火候向目标火候平滑过渡
    this.heatLevel += (this.targetHeat - this.heatLevel) * 0.05;

    // 根据火候计算颜色
    const color = this.heatToColor(this.heatLevel);
    
    // 根据光感状态调整亮度
    const brightnessBoost = this.uiState.screenBrightness / 80;

    // 绘制外圈(目标火候)
    ctx.beginPath();
    ctx.arc(centerX, centerY, radius, 0, Math.PI * 2);
    ctx.strokeStyle = `rgba(100, 100, 100, 0.3)`;
    ctx.lineWidth = 8;
    ctx.stroke();

    // 绘制内圈(当前火候)
    const startAngle = -Math.PI / 2;
    const endAngle = startAngle + (this.heatLevel / 100) * Math.PI * 2;
    
    ctx.beginPath();
    ctx.arc(centerX, centerY, radius, startAngle, endAngle);
    ctx.strokeStyle = color;
    ctx.lineWidth = 10;
    ctx.lineCap = 'round';
    ctx.shadowColor = color;
    ctx.shadowBlur = 20 * brightnessBoost;
    ctx.stroke();

    // 绘制中心文字
    ctx.fillStyle = '#FFFFFF';
    ctx.font = `bold ${24 * brightnessBoost}px HarmonyOS Sans`;
    ctx.textAlign = 'center';
    ctx.textBaseline = 'middle';
    ctx.fillText(`${Math.round(this.heatLevel)}%`, centerX, centerY - 10);

    // 火候名称
    ctx.font = `${14 * brightnessBoost}px HarmonyOS Sans`;
    ctx.fillStyle = 'rgba(255,255,255,0.7)';
    ctx.fillText(this.getHeatName(this.heatLevel), centerX, centerY + 15);

    // 绘制热力粒子(大火时更多)
    if (this.heatLevel > 50) {
      this.drawHeatParticles(ctx, centerX, centerY, radius, this.heatLevel, color);
    }
  }

  private heatToColor(heat: number): string {
    // 0-30: 蓝色(小火)
    // 30-60: 黄色(中火)
    // 60-100: 红色(大火)
    if (heat < 30) {
      const t = heat / 30;
      return `rgb(${Math.round(100 + t * 155)}, ${Math.round(150 + t * 105)}, 255)`;
    } else if (heat < 60) {
      const t = (heat - 30) / 30;
      return `rgb(255, ${Math.round(255 - t * 100)}, ${Math.round(255 * (1 - t))})`;
    } else {
      const t = (heat - 60) / 40;
      return `rgb(255, ${Math.round(155 - t * 155)}, 0)`;
    }
  }

  private getHeatName(heat: number): string {
    if (heat < 20) return '小火';
    if (heat < 40) return '中小火';
    if (heat < 60) return '中火';
    if (heat < 80) return '中大火';
    return '大火';
  }

  private drawHeatParticles(
    ctx: CanvasRenderingContext2D,
    cx: number, cy: number, radius: number,
    heat: number, color: string
  ): void {
    const particleCount = Math.floor(heat / 10);
    const time = Date.now() / 1000;

    for (let i = 0; i < particleCount; i++) {
      const angle = (i / particleCount) * Math.PI * 2 + time;
      const dist = radius + 10 + Math.sin(time * 2 + i) * 5;
      const x = cx + Math.cos(angle) * dist;
      const y = cy + Math.sin(angle) * dist;
      const size = 2 + Math.sin(time * 3 + i) * 1.5;

      ctx.beginPath();
      ctx.arc(x, y, size, 0, Math.PI * 2);
      ctx.fillStyle = color;
      ctx.globalAlpha = 0.6;
      ctx.fill();
    }
    ctx.globalAlpha = 1.0;
  }

  build() {
    Canvas(this.canvasCtx)
      .width(200)
      .height(200)
      .onReady((context) => {
        this.canvasCtx = context.renderingContext;
      })
  }
}

3.6 主烹饪工作室页面(CookingStudio.ets)

typescript 复制代码
// pages/CookingStudio.ets
import { AdaptiveRecipeCard } from '../components/AdaptiveRecipeCard';
import { HandsFreeNavBall } from '../components/HandsFreeNavBall';
import { HeatVisualizer } from '../components/HeatVisualizer';
import { AIChefAgent } from '../services/AIChefAgent';
import { KitchenLightAdapter } from '../services/KitchenLightAdapter';

@Entry
@Component
struct CookingStudio {
  @State showHeatVisualizer: boolean = false;
  @State currentHeat: number = 0;
  
  private aiChef: AIChefAgent = new AIChefAgent();
  private lightAdapter: KitchenLightAdapter = KitchenLightAdapter.getInstance();

  aboutToAppear() {
    this.aiChef.loadRecipe('kung-pao-chicken');
    this.lightAdapter.startAdaptation();
  }

  aboutToDisappear() {
    this.lightAdapter.stopAdaptation();
  }

  build() {
    Stack() {
      // 底层:菜谱卡片
      AdaptiveRecipeCard()
        .width('100%')
        .height('100%')

      // 火候可视化(烹饪阶段显示)
      if (this.showHeatVisualizer) {
        Column() {
          HeatVisualizer()
            .width(200)
            .height(200)
          
          Text('当前火候')
            .fontSize(14)
            .fontColor('rgba(255,255,255,0.7)')
            .margin({ top: 8 })
        }
        .position({ x: '50%', y: '20%' })
        .markAnchor({ x: 0.5, y: 0 })
        .backgroundColor('rgba(0,0,0,0.7)')
        .borderRadius(16)
        .padding(16)
      }

      // 顶部状态栏
      Row() {
        Text('光味智厨')
          .fontSize(16)
          .fontColor('#FFFFFF')
          .fontWeight(FontWeight.Bold)
        
        Blank()
        
        // 环境光指示
        Row() {
          Circle()
            .width(8)
            .height(8)
            .fill(this.lightAdapter.getKitchenContext().lux > 200 ? '#4CAF50' : '#FF9800')
          
          Text(`${this.lightAdapter.getKitchenContext().lux} lux`)
            .fontSize(12)
            .fontColor('rgba(255,255,255,0.7)')
            .margin({ left: 6 })
        }
      }
      .width('100%')
      .height(44)
      .padding({ left: 16, right: 16 })
      .backgroundColor('rgba(0,0,0,0.5)')

      // 免触悬浮导航球
      HandsFreeNavBall()
        .position({ x: '82%', y: '75%' })
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#1a1a1a')
    .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM])
  }
}

四、关键技术难点与解决方案

4.1 油手操作的触控可靠性

问题: 烹饪时手指沾油/水,导致屏幕触控失灵或误触。

方案:

  • 悬浮球增大:蒸汽模式下自动放大至120%
  • 手势替代:挥手切换步骤,无需触碰屏幕
  • 语音优先:嘈杂环境下提高语音识别灵敏度
  • 接近感应:手靠近时自动高亮悬浮球,减少寻找时间

4.2 多光源环境下的食材色彩还原

问题: 厨房内LED灯(6500K)、白炽灯(2700K)、自然光混合,导致食材照片偏色。

方案:

  • 光谱分析:通过摄像头分析环境光的光谱分布
  • 动态白平衡:计算综合色温并实时校正图片显示
  • 食材真色库:建立标准光源下的食材色彩基准库

4.3 蒸汽雾化导致的屏幕可读性

问题: 炒菜时的蒸汽导致屏幕雾化,文字模糊。

方案:

  • 亮度补偿:检测到高湿度时自动提升亮度30%
  • 锐化增强:应用边缘增强算法
  • 高对比度模式:蒸汽环境下切换至高对比度主题
  • 语音播报:关键步骤自动语音朗读,减少看屏需求

4.4 烹饪节奏与光效同步

问题: 不同烹饪阶段需要不同的提醒强度。

方案:

  • 阶段脉动:悬浮球颜色/频率反映当前阶段
  • 火候联动:大火时红色急促脉动,小火时蓝色稳定
  • 倒计时光效:最后10秒屏幕边缘红色闪烁
  • 完成庆祝:装盘阶段金色粒子特效

五、效果展示与场景演示

场景一:夜间安静烹饪

  • 环境特征: 22:00后,厨房仅开油烟机灯(照度80lux,色温3500K)
  • 系统响应:
    • 自动切换至"夜间烹饪模式",屏幕亮度降低但对比度增强
    • AI厨师降低音量,使用简短指令:"第3步。下鸡丁。滑散。"
    • 悬浮球呈绿色平缓脉动,不打扰家人休息
    • 检测到蒸汽时自动提升亮度,语音重复关键步骤
  • 用户体验: 无需吵醒家人,安静完成烹饪

场景二:周末家庭聚餐备菜

  • 环境特征: 白天自然光+厨房主灯,多人在厨房走动
  • 系统响应:
    • 检测到多光源混合,自动校正食材图片色温
    • 双手沾油时,挥手即可切换步骤
    • 询问"这是什么"自动识别台面上的食材
    • 发现缺少花生,AI推荐"可用腰果替代,等量"
    • 大火爆炒阶段,火候可视化显示红色粒子特效
  • 用户体验: 手忙脚乱时也能从容操作,食材替代建议避免中断烹饪

场景三:新手学做复杂菜品

  • 环境特征: 傍晚时分,厨房灯光偏黄,用户首次尝试红烧鱼
  • 系统响应:
    • 检测到新手模式(首次做此菜),AI使用详细指导
    • 煎鱼步骤时,火候可视化实时显示油温
    • 翻面时机:AI通过计时+语音提醒"现在翻面,小心溅油"
    • 检测到用户犹豫(无操作超过30秒),自动重复当前步骤
    • 完成时播放庆祝音效,生成美食照片+步骤分享卡
  • 用户体验: 像有一位专业厨师在旁指导,新手也能做出餐厅级菜品

六、总结与展望

本文基于HarmonyOS 6(API 23)的悬浮导航沉浸光感能力,实战构建了一个**"光味智厨"**智能烹饪系统。核心技术突破包括:

  1. 厨房光感适配引擎:针对油烟、蒸汽、多光源等厨房特有环境,实现动态UI优化
  2. 免触悬浮导航:支持手势、语音、接近感应的多模态交互,解决油手操作痛点
  3. 光感感知式AI教学:根据厨房环境动态调整语音指导风格和内容复杂度
  4. 火候可视化:将抽象火候转化为直观的光效动画,降低烹饪门槛

未来可拓展方向:

  • 结合HarmonyOS分布式能力,将菜谱同步至冰箱屏、油烟机屏,实现多屏协同烹饪
  • 接入华为智选智能灶具,实现火候的自动调节与闭环控制
  • 开发PC端鸿蒙应用,利用大屏优势实现"菜谱规划+采购清单+烹饪指导"全流程管理
  • 引入生成式AI菜谱创作,根据用户口味偏好和冰箱食材自动生成原创菜谱

转载自:https://blog.csdn.net/u014727709/article/details/161649656

欢迎 👍点赞✍评论⭐收藏,欢迎指正

相关推荐
人工智能培训1 小时前
数字孪生建模常用方式有哪些?
人工智能·深度学习·机器学习·容器·知识图谱
CCC:CarCrazeCurator1 小时前
【DriveGen 文件详解】04——evaluate.py
人工智能·自动驾驶·transformer
老高学长1 小时前
金融机构文档加密软件哪个好|合规与安全兼顾|2026新测评
网络·人工智能·安全
闻道参看1 小时前
生成式智能搜索下的流量卡位攻略:初创个体如何甄选高兼容性的 GEO 优化 服务商
人工智能
Herlie1 小时前
6款可编辑AI海报工具深度横测(2026)
大数据·人工智能
轻刀快马1 小时前
跨越“拟人”的最后一道天堑:大模型强化学习(RLHF/RLAIF)底层原理解析
人工智能·深度学习·机器学习
hsg771 小时前
简述:小数据集照片分类的模型训练
人工智能·分类·数据挖掘
清 晨1 小时前
YouTube自动AI标签上线后跨境内容团队如何调整素材审核流程
大数据·人工智能·新媒体运营·内容营销·跨境