食谱翻译机应用


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

一、项目概述

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

1.1 应用简介

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

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

1.2 核心功能

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

1.3 扫描状态

序号状态名称图标颜色说明
1准备扫描camera_alt灰色 #6B7280等待用户开始扫描
2正在识别camera橙色 #F59E0BAI正在分析图像
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 / iOSAPI 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 字体规范

元素字号字重颜色
应用标题20pxBold#FFFFFF
状态文字20pxBold状态色
食材标签14pxRegular#000000
菜谱名称16pxBold#000000
菜谱信息13pxRegular#666666
匹配度标签12pxMedium#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-072024-01-142024-01-212024-01-282024-02-042024-02-112024-02-182024-02-252024-03-032024-03-102024-03-172024-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
鸿蒙OSAPI 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) - 完整应用代码

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

更多推荐