食谱翻译机应用


欢迎加入开源鸿蒙跨平台社区:
https://openharmonycrossplatform.csdn.net

一、项目概述

运行效果图
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

1.1 应用简介

"食谱翻译机"是一款智能烹饪助手应用,核心理念是拍照识别食材,自动推荐能做的菜谱。用户只需对准冰箱里的食材拍照,应用就能自动识别食材种类,并根据现有食材智能推荐可以制作的菜谱,解决"今天吃什么"的难题。

应用以绿色为主色调,传递新鲜、健康、自然的饮食理念。通过AI图像识别技术(模拟),快速识别食材,智能匹配菜谱,让烹饪变得简单有趣。

1.2 核心功能

功能模块 功能描述 实现方式
食材扫描 拍照识别食材种类 模拟AI识别 + Random数据
智能推荐 根据食材推荐菜谱 匹配算法计算匹配度
菜谱详情 查看菜谱详细信息和步骤 底部弹窗展示
收藏功能 收藏喜欢的菜谱 心形按钮 + 列表管理
扫描历史 查看过往扫描记录 ExpansionTile展开
全部菜谱 浏览所有可用菜谱 ListView列表

1.3 扫描状态

序号 状态名称 图标 颜色 说明
1 准备扫描 camera_alt 灰色 #6B7280 等待用户开始扫描
2 正在识别 camera 橙色 #F59E0B AI正在分析图像
3 识别完成 check_circle 绿色 #22C55E 成功识别食材
4 未识别到 error_outline 红色 #EF4444 未识别到食材

1.4 食材分类

序号 分类名称 图标 颜色 示例食材
1 蔬菜 eco 绿色 #22C55E 西红柿、土豆、黄瓜
2 肉类 restaurant 红色 #EF4444 猪肉、牛肉、鸡肉
3 海鲜 water 蓝色 #3B82F6 鱼、虾、蟹
4 主食 grain 黄色 #F59E0B 米饭、面条、面包
5 调料 local_fire_department 紫色 #8B5CF6 盐、糖、酱油
6 水果 apple 粉色 #EC4899 苹果、香蕉、橙子
7 乳制品 egg 黄色 #FCD34D 鸡蛋、牛奶、奶酪
8 其他 help_outline 灰色 #6B7280 其他食材

1.5 技术栈

技术领域 技术选型 版本要求
开发框架 Flutter >= 3.0.0
编程语言 Dart >= 2.17.0
设计规范 Material Design 3 -
状态管理 setState -
随机数据 dart:math -
目标平台 鸿蒙OS / Android / iOS API 21+

二、系统架构

2.1 整体架构图

Data Layer

Presentation Layer

主页面
RecipeTranslatorHomePage

扫描页面

全部菜谱

扫描历史

我的收藏

扫描区域

识别结果

推荐菜谱

开始扫描

扫描动画

重新扫描

Ingredient
食材

Recipe
菜谱

ScanHistory
扫描历史

ScanStatus
扫描状态

2.2 类图设计

manages

manages

manages

uses

uses

has

has

has

RecipeTranslatorApp

+Widget build()

«enumeration»

ScanStatus

+String label

+IconData icon

+Color color

+idle

+scanning

+recognized

+noMatch

«enumeration»

IngredientCategory

+String label

+IconData icon

+Color color

+vegetable

+meat

+seafood

+grain

+seasoning

+fruit

+dairy

+other

Ingredient

+String id

+String name

+String emoji

+IngredientCategory category

+double confidence

Recipe

+String id

+String name

+String emoji

+String cuisine

+int cookTime

+String difficulty

+List<String> requiredIngredients

+List<String> optionalIngredients

+int matchCount

+double matchRate

+String description

+bool isFavorite

+Recipe copyWith()

ScanHistory

+String id

+DateTime scanTime

+List<Ingredient> ingredients

+List<Recipe> recommendedRecipes

RecipeTranslatorHomePage

-int _selectedIndex

-ScanStatus _scanStatus

-List<Ingredient> _recognizedIngredients

-List<Recipe> _recommendedRecipes

-List<ScanHistory> _scanHistory

-List<Recipe> _favoriteRecipes

+void _startScan()

+void _getMatchingRecipes()

+void _toggleRecipeFavorite()

+void _resetScan()

2.3 页面导航流程

扫描

菜谱

历史

收藏

准备扫描

正在识别

识别完成

应用启动

扫描页面

底部导航

扫描食材

全部菜谱

扫描历史

我的收藏

扫描状态

显示扫描按钮

显示加载动画

显示识别结果

点击开始扫描

模拟扫描2秒

显示推荐菜谱

点击菜谱

显示菜谱详情

点击重新扫描

2.4 扫描流程图

匹配算法 数据生成 扫描页面 用户 匹配算法 数据生成 扫描页面 用户 等待2秒模拟识别 点击开始扫描 更新状态为scanning 显示加载动画 随机选择食材类别 返回Ingredient列表 传入识别到的食材 计算匹配度 返回Recipe列表 更新状态为recognized 保存到扫描历史 显示识别结果和推荐菜谱

三、核心模块设计

3.1 数据模型设计

3.1.1 扫描状态枚举 (ScanStatus)
enum ScanStatus {
  idle('准备扫描', Icons.camera_alt, Color(0xFF6B7280)),
  scanning('正在识别', Icons.camera, Color(0xFFF59E0B)),
  recognized('识别完成', Icons.check_circle, Color(0xFF22C55E)),
  noMatch('未识别到食材', Icons.error_outline, Color(0xFFEF4444));

  final String label;
  final IconData icon;
  final Color color;
  const ScanStatus(this.label, this.icon, this.color);
}
3.1.2 食材分类枚举 (IngredientCategory)
enum IngredientCategory {
  vegetable('蔬菜', Icons.eco, Color(0xFF22C55E)),
  meat('肉类', Icons.restaurant, Color(0xFFEF4444)),
  seafood('海鲜', Icons.water, Color(0xFF3B82F6)),
  grain('主食', Icons.grain, Color(0xFFF59E0B)),
  seasoning('调料', Icons.local_fire_department, Color(0xFF8B5CF6)),
  fruit('水果', Icons.apple, Color(0xFFEC4899)),
  dairy('乳制品', Icons.egg, Color(0xFFFCD34D)),
  other('其他', Icons.help_outline, Color(0xFF6B7280));

  final String label;
  final IconData icon;
  final Color color;
  const IngredientCategory(this.label, this.icon, this.color);
}
3.1.3 食材模型 (Ingredient)
class Ingredient {
  final String id;
  final String name;
  final String emoji;
  final IngredientCategory category;
  final double confidence;

  Ingredient({
    required this.id,
    required this.name,
    required this.emoji,
    required this.category,
    this.confidence = 0.95,
  });
}
3.1.4 菜谱模型 (Recipe)
class Recipe {
  final String id;
  final String name;
  final String emoji;
  final String cuisine;
  final int cookTime;
  final String difficulty;
  final List<String> requiredIngredients;
  final List<String> optionalIngredients;
  final int matchCount;
  final double matchRate;
  final String description;
  final bool isFavorite;

  Recipe({
    required this.id,
    required this.name,
    required this.emoji,
    required this.cuisine,
    required this.cookTime,
    required this.difficulty,
    required this.requiredIngredients,
    this.optionalIngredients = const [],
    this.matchCount = 0,
    this.matchRate = 0.0,
    required this.description,
    this.isFavorite = false,
  });

  Recipe copyWith({bool? isFavorite}) {
    return Recipe(
      id: id,
      name: name,
      emoji: emoji,
      cuisine: cuisine,
      cookTime: cookTime,
      difficulty: difficulty,
      requiredIngredients: requiredIngredients,
      optionalIngredients: optionalIngredients,
      matchCount: matchCount,
      matchRate: matchRate,
      description: description,
      isFavorite: isFavorite ?? this.isFavorite,
    );
  }
}

3.2 页面结构设计

3.2.1 扫描页面布局

准备扫描

正在识别

识别完成

扫描页面

SliverAppBar

扫描区域卡片

识别结果卡片

推荐菜谱卡片

绿色渐变背景

应用标题

扫描状态

相机图标+扫描按钮

加载动画

成功图标+重新扫描

食材标签列表

Chip组件展示

菜谱列表

匹配度标签

3.2.2 菜谱详情弹窗

菜谱详情

大图标

菜谱名称

描述

信息栏

食材列表

开始烹饪按钮

烹饪时间

菜系

难度

必需食材

可选食材

3.3 匹配算法设计

获取识别到的食材

提取食材名称集合

遍历所有菜谱

计算匹配数量

计算匹配率

匹配数量>0?

保留菜谱

过滤掉

按匹配率排序

返回推荐列表


四、UI设计规范

4.1 配色方案

应用采用绿色为主色调,传递新鲜、健康、自然的饮食理念:

颜色类型 色值 用途
主色 #22C55E (Green) 导航、强调元素
辅色 #16A34A (Dark Green) 渐变背景
准备扫描 #6B7280 (Gray) 初始状态
正在识别 #F59E0B (Amber) 加载状态
识别完成 #22C55E (Green) 成功状态
未识别到 #EF4444 (Red) 错误状态

4.2 字体规范

元素 字号 字重 颜色
应用标题 20px Bold #FFFFFF
状态文字 20px Bold 状态色
食材标签 14px Regular #000000
菜谱名称 16px Bold #000000
菜谱信息 13px Regular #666666
匹配度标签 12px Medium #22C55E

4.3 组件规范

4.3.1 扫描区域
┌─────────────────────────────────────────┐
│                                         │
│         ┌─────────────┐                │
│         │   📷        │  状态边框      │
│         │  (图标)     │                │
│         └─────────────┘                │
│                                         │
│         准备扫描 / 正在识别             │
│    对准食材拍照,AI自动识别并推荐菜谱   │
│                                         │
│         [    开始扫描    ]              │
│                                         │
└─────────────────────────────────────────┘
4.3.2 食材标签
┌─────────────────────────────────────────┐
│  识别到的食材                           │
│                                         │
│  🍅 西红柿  🥔 土豆  🥩 猪肉            │
│                                         │
└─────────────────────────────────────────┘
4.3.3 推荐菜谱项
┌─────────────────────────────────────────┐
│  ┌────┐                                 │
│  │ 🍳 │  西红柿炒蛋                     │
│  └────┘  家常菜 · 10分钟 · 简单         │
│          ┌────────┐    [♡]             │
│          │ 100%匹配 │                   │
│          └────────┘                     │
└─────────────────────────────────────────┘

五、核心功能实现

5.1 扫描功能

void _startScan() {
  setState(() => _scanStatus = ScanStatus.scanning);

  // 模拟扫描过程
  Future.delayed(const Duration(seconds: 2), () {
    final random = Random();
    final categories = _ingredientDatabase.keys.toList();
    final selectedCategories = categories.sublist(0, random.nextInt(3) + 2);
    
    final recognizedIngredients = <Ingredient>[];
    for (var category in selectedCategories) {
      final ingredients = _ingredientDatabase[category]!;
      recognizedIngredients.add(ingredients[random.nextInt(ingredients.length)]);
    }

    final recommendedRecipes = _getMatchingRecipes(recognizedIngredients);

    setState(() {
      _recognizedIngredients = recognizedIngredients;
      _recommendedRecipes = recommendedRecipes;
      _scanStatus = recognizedIngredients.isEmpty 
          ? ScanStatus.noMatch 
          : ScanStatus.recognized;
    });

    if (recognizedIngredients.isNotEmpty) {
      _scanHistory.insert(0, ScanHistory(
        id: 'scan_${DateTime.now().millisecondsSinceEpoch}',
        scanTime: DateTime.now(),
        ingredients: recognizedIngredients,
        recommendedRecipes: recommendedRecipes,
      ));
    }
  });
}

5.2 匹配算法

List<Recipe> _getMatchingRecipes(List<Ingredient> ingredients) {
  final ingredientNames = ingredients.map((i) => i.name).toSet();
  
  return _recipeDatabase.map((recipe) {
    final matchedIngredients = recipe.requiredIngredients
        .where((ing) => ingredientNames.contains(ing))
        .toList();
    
    final matchCount = matchedIngredients.length;
    final matchRate = recipe.requiredIngredients.isEmpty 
        ? 0.0 
        : matchCount / recipe.requiredIngredients.length;

    return Recipe(
      id: recipe.id,
      name: recipe.name,
      emoji: recipe.emoji,
      cuisine: recipe.cuisine,
      cookTime: recipe.cookTime,
      difficulty: recipe.difficulty,
      requiredIngredients: recipe.requiredIngredients,
      optionalIngredients: recipe.optionalIngredients,
      matchCount: matchCount,
      matchRate: matchRate,
      description: recipe.description,
      isFavorite: recipe.isFavorite,
    );
  }).where((recipe) => recipe.matchCount > 0)
    .toList()
    ..sort((a, b) => b.matchRate.compareTo(a.matchRate));
}

5.3 收藏功能

void _toggleRecipeFavorite(Recipe recipe) {
  setState(() {
    final index = _recommendedRecipes.indexWhere((r) => r.id == recipe.id);
    if (index != -1) {
      _recommendedRecipes[index] = _recommendedRecipes[index].copyWith(
        isFavorite: !_recommendedRecipes[index].isFavorite,
      );
      
      if (_recommendedRecipes[index].isFavorite) {
        _favoriteRecipes.add(_recommendedRecipes[index]);
      } else {
        _favoriteRecipes.removeWhere((r) => r.id == recipe.id);
      }
    }
  });
}

5.4 菜谱详情弹窗

void _showRecipeDetail(Recipe recipe) {
  showModalBottomSheet(
    context: context,
    isScrollControlled: true,
    builder: (context) => DraggableScrollableSheet(
      initialChildSize: 0.8,
      maxChildSize: 0.95,
      minChildSize: 0.5,
      expand: false,
      builder: (context, scrollController) => Container(
        padding: const EdgeInsets.all(24),
        child: ListView(
          controller: scrollController,
          children: [
            Center(child: Text(recipe.emoji, style: const TextStyle(fontSize: 80))),
            const SizedBox(height: 16),
            Text(recipe.name, 
                 style: const TextStyle(fontSize: 28, fontWeight: FontWeight.bold),
                 textAlign: TextAlign.center),
            const SizedBox(height: 24),
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: [
                _buildInfoItem(Icons.timer, '${recipe.cookTime}分钟'),
                _buildInfoItem(Icons.restaurant, recipe.cuisine),
                _buildInfoItem(Icons.trending_up, recipe.difficulty),
              ],
            ),
            const SizedBox(height: 24),
            const Text('所需食材', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
            ...recipe.requiredIngredients.map((ing) => ListTile(
              leading: const Icon(Icons.check_circle, color: Color(0xFF22C55E)),
              title: Text(ing),
            )),
            FilledButton.icon(
              onPressed: () {},
              icon: const Icon(Icons.play_circle),
              label: const Text('开始烹饪'),
            ),
          ],
        ),
      ),
    ),
  );
}

六、状态管理流程

6.1 扫描状态流转

应用启动/重新扫描

点击开始扫描

识别成功

识别失败

点击重新扫描

点击重新扫描

显示相机图标和扫描按钮

显示加载动画

显示识别结果和推荐菜谱

显示错误提示


七、扩展功能规划

7.1 后续版本规划

2024-01-07 2024-01-14 2024-01-21 2024-01-28 2024-02-04 2024-02-11 2024-02-18 2024-02-25 2024-03-03 2024-03-10 2024-03-17 2024-03-24 食材扫描 智能推荐 菜谱详情 收藏功能 真实AI识别 烹饪步骤 营养分析 购物清单 社区分享 智能冰箱联动 V1.0 基础版本 V1.1 增强版本 V1.2 进阶版本 食谱翻译机应用开发计划

7.2 功能扩展建议

7.2.1 真实AI识别
  • 集成TensorFlow Lite模型
  • 支持离线识别
  • 提高识别准确率
7.2.2 烹饪步骤
  • 详细的烹饪步骤
  • 图文/视频教程
  • 计时器功能
7.2.3 营养分析
  • 卡路里计算
  • 营养成分分析
  • 健康饮食建议

八、注意事项

8.1 开发注意事项

  1. 模拟数据:当前使用Random模拟识别结果,实际应用需接入AI模型
  2. 状态管理:扫描状态变化需及时更新UI
  3. 匹配算法:根据实际需求调整匹配度计算方式
  4. 性能优化:菜谱数据量大时需考虑分页加载

8.2 常见问题

问题 原因 解决方案
识别结果不准确 模拟随机数据 接入真实AI模型
推荐菜谱太少 食材匹配度低 降低匹配阈值
收藏状态不同步 状态未更新 检查setState调用

九、运行说明

9.1 环境要求

环境 版本要求
Flutter SDK >= 3.0.0
Dart SDK >= 2.17.0
鸿蒙OS API 21+

9.2 运行命令

# 查看可用设备
flutter devices

# 运行到Web服务器
flutter run -d web-server -t lib/main_recipe_translator.dart --web-port 8098

# 运行到鸿蒙设备
flutter run -d 127.0.0.1:5555 lib/main_recipe_translator.dart

# 运行到Windows
flutter run -d windows -t lib/main_recipe_translator.dart

# 代码分析
flutter analyze lib/main_recipe_translator.dart

十、总结

"食谱翻译机"应用通过智能食材识别和菜谱推荐,解决用户"今天吃什么"的难题。应用采用 Flutter + Material Design 3 技术栈,具有简洁美观的界面和流畅的交互体验。核心功能包括食材扫描、智能推荐、菜谱详情和收藏功能,让烹饪变得简单有趣。

技术亮点

  1. 智能匹配算法:根据食材自动计算匹配度
  2. 状态驱动UI:四种扫描状态清晰展示
  3. 丰富的食材库:8大分类,22种常见食材
  4. 完整的菜谱数据:8道经典菜谱,详细信息
  5. 流畅的用户体验:扫描动画、推荐列表、详情弹窗

核心代码文件

  • [main_recipe_translator.dart](file:///f:/Flutter/flutter_harmonyos/lib/main_recipe_translator.dart) - 完整应用代码

拍照识食材,智能推荐菜谱

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐