From ae5eba09aa9c557047b17d430755f8ae8e01f5f2 Mon Sep 17 00:00:00 2001 From: Hamza-Ayed Date: Tue, 12 May 2026 01:29:57 +0300 Subject: [PATCH] Update: 2026-05-12 01:29:57 --- app/Core/AI.php | 4 ++ app/Services/InvoiceProcessor.php | 7 ++- .../services/image_processing_service.dart | 50 ++----------------- .../invoice_detail_controller.dart | 10 +++- 4 files changed, 23 insertions(+), 48 deletions(-) diff --git a/app/Core/AI.php b/app/Core/AI.php index 556e274..2ed96d9 100644 --- a/app/Core/AI.php +++ b/app/Core/AI.php @@ -96,6 +96,10 @@ class AI $textResponse = $result['candidates'][0]['content']['parts'][0]['text'] ?? null; if (!$textResponse) return null; + + // --- ADDED FOR DEBUGGING --- + @file_put_contents(STORAGE_PATH . '/logs/worker.log', "[" . date('Y-m-d H:i:s') . "] [AI_RAW_RESPONSE]\n" . $textResponse . "\n", FILE_APPEND); + // --------------------------- $data = json_decode($textResponse, true); if (isset($data['error']) && $data['error'] === 'invalid_invoice') { diff --git a/app/Services/InvoiceProcessor.php b/app/Services/InvoiceProcessor.php index f90fb5e..74c4961 100644 --- a/app/Services/InvoiceProcessor.php +++ b/app/Services/InvoiceProcessor.php @@ -102,21 +102,26 @@ class InvoiceProcessor supplier_tin, supplier_name, supplier_address, buyer_tin, buyer_name, buyer_national_id, subtotal, tax_amount, discount_total, grand_total, currency_code, + ai_provider, created_at ) VALUES ( ?, ?, ?, ?, ?, 'extracted', ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, + ?, NOW() ) "); + $rawJsonSnippet = substr(json_encode($extracted, JSON_UNESCAPED_UNICODE), 0, 500); + $stmt->execute([ $invoiceId, $tenantId, $companyId, $userId, $imagePath, $invoiceNum, $validDate, $extracted['invoice_type'] ?? 'cash', $extracted['invoice_category'] ?? 'simplified', Encryption::encrypt($supplierTin), Encryption::encrypt($extracted['supplier']['name'] ?? ''), Encryption::encrypt($extracted['supplier']['address'] ?? ''), Encryption::encrypt($extracted['buyer']['tin'] ?? ''), Encryption::encrypt($extracted['buyer']['name'] ?? ''), Encryption::encrypt($extracted['buyer']['national_id'] ?? ''), - $extracted['subtotal'] ?? 0, $extracted['tax_amount'] ?? 0, $extracted['discount_total'] ?? 0, $extracted['grand_total'] ?? 0, $extracted['currency_code'] ?? 'JOD' + $extracted['subtotal'] ?? 0, $extracted['tax_amount'] ?? 0, $extracted['discount_total'] ?? 0, $extracted['grand_total'] ?? 0, $extracted['currency_code'] ?? 'JOD', + $rawJsonSnippet ]); // Save invoice line items diff --git a/musadaq-app/lib/core/services/image_processing_service.dart b/musadaq-app/lib/core/services/image_processing_service.dart index 8baefbc..6a48a62 100644 --- a/musadaq-app/lib/core/services/image_processing_service.dart +++ b/musadaq-app/lib/core/services/image_processing_service.dart @@ -13,51 +13,11 @@ class ImageProcessingService { /// 3. Increases contrast /// 4. Saves as high-quality JPEG static Future processInvoiceImage(File originalImage) async { - try { - AppLogger.print('Started processing image: ${originalImage.path}'); - - // Step 1: Initial compression using flutter_image_compress (Native, fast) - final dir = await getTemporaryDirectory(); - final compressedPath = path.join( - dir.path, 'compressed_${DateTime.now().millisecondsSinceEpoch}.jpg'); - - final XFile? compressedXFile = - await FlutterImageCompress.compressAndGetFile( - originalImage.path, - compressedPath, - quality: 85, - minWidth: 1920, - minHeight: 1080, - ); - - if (compressedXFile == null) { - AppLogger.error('Failed to compress image initially', null); - return originalImage; // Fallback to original - } - - File compressedFile = File(compressedXFile.path); - - // Step 2: Fine-tuning filters (Grayscale/Contrast) via 'image' package - // This helps OCR models detect text edges more accurately - final bytes = await compressedFile.readAsBytes(); - final filteredBytes = await compute(_applyFilters, bytes); - - if (filteredBytes != null) { - final filteredPath = path.join( - dir.path, 'filtered_${DateTime.now().millisecondsSinceEpoch}.jpg'); - final filteredFile = File(filteredPath); - await filteredFile.writeAsBytes(filteredBytes); - - AppLogger.print('Finished processing image with filters: ${filteredFile.path}'); - return filteredFile; - } - - AppLogger.print('Finished processing image (no filters): ${compressedFile.path}'); - return compressedFile; - } catch (e, stack) { - AppLogger.error('Error processing image', e, stack); - return originalImage; // Fallback - } + // The web app uploads the original file and OCR works 100%. + // Processing/compressing it here strips EXIF/quality and causes OCR to fail. + // So we just return the original image intact. + AppLogger.print('Skipping image processing to preserve quality for AI: ${originalImage.path}'); + return originalImage; } /// Runs in an isolate to prevent UI freezing diff --git a/musadaq-app/lib/features/invoices/controllers/invoice_detail_controller.dart b/musadaq-app/lib/features/invoices/controllers/invoice_detail_controller.dart index bbf38cf..94bcc87 100644 --- a/musadaq-app/lib/features/invoices/controllers/invoice_detail_controller.dart +++ b/musadaq-app/lib/features/invoices/controllers/invoice_detail_controller.dart @@ -17,8 +17,14 @@ class InvoiceDetailController extends GetxController { @override void onInit() { super.onInit(); - if (Get.arguments != null) { - invoiceId = Get.arguments['id']; + final args = Get.arguments; + if (args != null) { + if (args is Map) { + invoiceId = args['id']?.toString(); + } else if (args is String) { + invoiceId = args; + } + if (invoiceId != null) { fetchInvoiceDetails(); }