본문 바로가기

Develop

MealLens 앱 소개: AI 기반 음식 분석 도우미

MealLens는 식사 기록과 영양 분석을 위한 스마트 모바일 애플리케이션입니다. 앱의 구조는 Flutter의 GetX 패턴을 따르며, 사용자 인터페이스와 비즈니스 로직이 명확하게 분리되어 있습니다. 메인 화면은 다음과 같이 구현되어 있습니다:

class HomeScreen extends StatelessWidget {
  // GetX 컨트롤러를 전역적으로 관리하여 상태 일관성 유지
  static final MealController controller = Get.put(MealController());

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Row(
          children: [
            // 앱의 브랜드 아이덴티티를 표현하는 로고
            Image.asset('assets/logo-app.png', height: 40),
            const Text('식사 렌즈'),
          ],
        ),
      ),
      // Obx를 사용하여 반응형 UI 구현
      body: Obx(() => ListView.builder(
        itemCount: controller.posts.length,
        itemBuilder: (context, index) {
          final post = controller.posts[index];
          return MealPostCard(post: post);
        },
      )),
      // 새로운 식사 기록을 추가하는 플로팅 버튼
      floatingActionButton: FloatingActionButton(
        onPressed: () => _showImageSourceDialog(context),
        child: const Icon(Icons.add),
      ),
    );
  }
}

 

2. 데이터 처리와 상태 관리

앱의 핵심 기능은 MealController에서 관리됩니다. 이 컨트롤러는 이미지 촬영, AI 분석, 데이터 저장의 전체 라이프사이클을 처리합니다:

class MealController extends GetxController {
  // 반응형 상태 관리를 위한 RxList 활용
  final RxList<MealPost> posts = <MealPost>[].obs;
  final RxBool isLoading = false.obs;

  // 이미지 분석 프로세스
  Future<void> pickAndAnalyzeImage(ImageSource source) async {
    try {
      isLoading.value = true;  // 사용자에게 진행 상태 표시

      // 1. 이미지 획득 및 전처리
      final XFile? image = await _picker.pickImage(source: source);
      if (image == null) return;

      // 2. 이미지 최적화 - API 호출을 위한 압축
      final compressedFile = await _compressImage(image.path);

      // 3. GPT Vision API를 통한 분석
      final analysis = await _openAIService.analyzeImage(compressedFile);

      // 4. 분석 결과 저장 및 UI 업데이트
      final newPost = MealPost(
        id: DateTime.now().toString(),
        imagePath: image.path,
        analysis: analysis,
        createdAt: DateTime.now(),
      );

      posts.add(newPost);
      await _savePosts();  // 로컬 스토리지에 영구 저장

    } catch (e) {
      _handleError(e);  // 에러 처리 및 사용자 피드백
    } finally {
      isLoading.value = false;
    }
  }
}

 

3. AI 통합 및 이미지 처리

이미지 분석은 OpenAI의 GPT-4 Vision API와 Flutter의 이미지 처리 기능을 결합하여 구현됩니다:

class OpenAIService {
  final String apiKey;

  Future<String> analyzeImage(File imageFile) async {
    try {
      // 1. 이미지를 base64로 인코딩
      final bytes = await imageFile.readAsBytes();
      final base64Image = base64Encode(bytes);

      // 2. GPT-4 Vision API 요청 구성
      final response = await http.post(
        Uri.parse('https://api.openai.com/v1/chat/completions'),
        headers: {
          'Authorization': 'Bearer $apiKey',
          'Content-Type': 'application/json',
        },
        body: jsonEncode({
          'model': 'gpt-4-vision-preview',
          'messages': [
            {
              'role': 'user',
              'content': [
                {'type': 'text', 'text': '이 음식 사진을 분석해주세요.'},
                {'type': 'image_url', 'url': 'data:image/jpeg;base64,$base64Image'}
              ]
            }
          ]
        }),
      );

      // 3. 응답 처리 및 결과 반환
      final data = jsonDecode(response.body);
      return data['choices'][0]['message']['content'];

    } catch (e) {
      throw Exception('이미지 분석 실패: $e');
    }
  }
}

4. 데이터 영속성과 보안

앱의 데이터는 SharedPreferences를 사용하여 로컬에 안전하게 저장되며, Firebase Analytics를 통해 사용자 행동을 분석합니다:

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  // 환경 변수 및 Firebase 초기화
  await dotenv.load();
  await Firebase.initializeApp();

  // Firebase Analytics 설정
  final analytics = FirebaseAnalytics.instance;

  runApp(MyApp(
    analyticsObserver: FirebaseAnalyticsObserver(analytics: analytics),
  ));
}

class MyApp extends StatelessWidget {
  final FirebaseAnalyticsObserver analyticsObserver;

  @override
  Widget build(BuildContext context) {
    return GetMaterialApp(
      title: 'MealLens',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.green),
        useMaterial3: true,
      ),
      navigatorObservers: [analyticsObserver],
      home: const HomeScreen(),
    );
  }
}

각각의 코드 블록은 특정 기능을 담당하며, 전체적으로 모듈화된 구조를 가지고 있습니다. 이러한 구조는 앱의 유지보수성을 높이고, 새로운 기능 추가를 용이하게 만듭니다. 특히 GetX를 활용한 상태 관리는 앱의 성능을 최적화하고, 사용자에게 부드러운 경험을 제공하는 데 큰 역할을 합니다.

앱의 보안과 성능은 안드로이드 설정을 통해 더욱 강화되었습니다. ProGuard 규칙을 적용하여 코드 난독화를 구현했으며, 멀티덱스 지원을 통해 큰 규모의 앱을 안정적으로 실행할 수 있도록 했습니다. 이러한 기술적 기반을 토대로, MealLens는 사용자들에게 안정적이고 효율적인 식단 관리 서비스를 제공하고 있습니다.

반응형