diff --git a/backend/internal/gemini/client.go b/backend/internal/gemini/client.go index 95044e6..96788cf 100644 --- a/backend/internal/gemini/client.go +++ b/backend/internal/gemini/client.go @@ -18,7 +18,7 @@ const ( groqModel = "llama-3.3-70b-versatile" // groqVisionModel supports image inputs in OpenAI vision format. - groqVisionModel = "llama-3.2-11b-vision-preview" + groqVisionModel = "meta-llama/llama-4-scout-17b-16e-instruct" maxRetries = 3 ) diff --git a/client/lib/core/api/api_client.dart b/client/lib/core/api/api_client.dart index de79512..0864f71 100644 --- a/client/lib/core/api/api_client.dart +++ b/client/lib/core/api/api_client.dart @@ -9,7 +9,7 @@ class ApiClient { _dio = Dio(BaseOptions( baseUrl: baseUrl, connectTimeout: const Duration(seconds: 10), - receiveTimeout: const Duration(seconds: 30), + receiveTimeout: const Duration(seconds: 120), headers: {'Content-Type': 'application/json'}, )); diff --git a/client/lib/features/scan/recognition_service.dart b/client/lib/features/scan/recognition_service.dart index b57487c..456bcf9 100644 --- a/client/lib/features/scan/recognition_service.dart +++ b/client/lib/features/scan/recognition_service.dart @@ -1,5 +1,6 @@ import 'dart:convert'; -import 'dart:io'; + +import 'package:image_picker/image_picker.dart'; import '../../core/api/api_client.dart'; @@ -108,7 +109,7 @@ class RecognitionService { final ApiClient _client; /// Recognizes food items from a receipt photo. - Future recognizeReceipt(File image) async { + Future recognizeReceipt(XFile image) async { final payload = await _buildImagePayload(image); final data = await _client.post('/ai/recognize-receipt', data: payload); return ReceiptResult( @@ -122,7 +123,7 @@ class RecognitionService { } /// Recognizes food items from 1–3 product photos. - Future> recognizeProducts(List images) async { + Future> recognizeProducts(List images) async { final imageList = await Future.wait(images.map(_buildImagePayload)); final data = await _client.post( '/ai/recognize-products', @@ -134,17 +135,18 @@ class RecognitionService { } /// Recognizes a dish and estimates its nutritional content. - Future recognizeDish(File image) async { + Future recognizeDish(XFile image) async { final payload = await _buildImagePayload(image); final data = await _client.post('/ai/recognize-dish', data: payload); return DishResult.fromJson(data); } - Future> _buildImagePayload(File image) async { + Future> _buildImagePayload(XFile image) async { final bytes = await image.readAsBytes(); final base64Data = base64Encode(bytes); - final ext = image.path.split('.').last.toLowerCase(); - final mimeType = ext == 'png' ? 'image/png' : 'image/jpeg'; + // XFile.mimeType may be null on some platforms; fall back to path extension. + final mimeType = image.mimeType ?? + (image.path.toLowerCase().endsWith('.png') ? 'image/png' : 'image/jpeg'); return {'image_base64': base64Data, 'mime_type': mimeType}; } } diff --git a/client/lib/features/scan/scan_screen.dart b/client/lib/features/scan/scan_screen.dart index 8efe38d..9e96765 100644 --- a/client/lib/features/scan/scan_screen.dart +++ b/client/lib/features/scan/scan_screen.dart @@ -1,5 +1,4 @@ -import 'dart:io'; - +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; @@ -70,19 +69,28 @@ class ScanScreen extends ConsumerWidget { ) async { final picker = ImagePicker(); - List files = []; + List files = []; if (mode == _Mode.products) { // Allow up to 3 images. - final picked = await picker.pickMultiImage(imageQuality: 70); + final picked = await picker.pickMultiImage( + imageQuality: 70, + maxWidth: 1024, + maxHeight: 1024, + ); if (picked.isEmpty) return; - files = picked.take(3).map((x) => File(x.path)).toList(); + files = picked.take(3).toList(); } else { final source = await _chooseSource(context); if (source == null) return; - final picked = await picker.pickImage(source: source, imageQuality: 70); + final picked = await picker.pickImage( + source: source, + imageQuality: 70, + maxWidth: 1024, + maxHeight: 1024, + ); if (picked == null) return; - files = [File(picked.path)]; + files = [picked]; } if (!context.mounted) return; @@ -116,7 +124,8 @@ class ScanScreen extends ConsumerWidget { context.push('/scan/dish', extra: dish); } } - } catch (e) { + } catch (e, s) { + debugPrint('Recognition error: $e\n$s'); if (context.mounted) { Navigator.pop(context); // close loading ScaffoldMessenger.of(context).showSnackBar(