Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Receipt Scanner Laravel Package

ediazaro/receipt-scanner

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require helgesverre/receipt-scanner
    php artisan vendor:publish --tag="receipt-scanner-config"
    php artisan vendor:publish --provider="OpenAI\Laravel\OpenAIServiceProvider"
    

    Add OPENAI_API_KEY to .env.

  2. First Use Case: Extract data from a receipt image:

    use HelgeSverre\ReceiptScanner\Facades\ReceiptScanner;
    
    $result = ReceiptScanner::scanFromImage(public_path('receipt.png'));
    dd($result); // Returns structured array of receipt data
    

Where to Look First

  • Config File: config/receipt-scanner.php (adjust OpenAI model, temperature, and prompt settings).
  • Facade: HelgeSverre\ReceiptScanner\Facades\ReceiptScanner (primary entry point).
  • Supported Methods:
    • scanFromText(string $text)
    • scanFromImage(string $path)
    • scanFromPdf(string $path)
    • scanFromHtml(string $html)

Implementation Patterns

Core Workflows

  1. Receipt Processing Pipeline:

    // Handle file uploads (e.g., from a form)
    $file = request()->file('receipt');
    $path = $file->store('receipts');
    
    // Scan based on file type
    $result = match ($file->getClientOriginalExtension()) {
        'png', 'jpg', 'jpeg' => ReceiptScanner::scanFromImage($path),
        'pdf' => ReceiptScanner::scanFromPdf($path),
        default => ReceiptScanner::scanFromText(file_get_contents($path)),
    };
    
  2. Email Attachment Parsing:

    $email = Mail::getMessage(); // From Laravel Notifications or IncomingMail
    foreach ($email->attachments as $attachment) {
        $data = ReceiptScanner::scanFromImage(storage_path("app/{$attachment->getFilename()}"));
        // Store or process $data
    }
    
  3. Batch Processing:

    $files = Storage::disk('s3')->files('receipts/inbox');
    foreach ($files as $file) {
        $data = ReceiptScanner::scanFromPdf(storage_path("app/{$file}"));
        // Save to database or queue for async processing
    }
    

Integration Tips

  • Database Storage: Use Laravel’s HasMany/MorphTo to link receipt data to models (e.g., User, Invoice):

    // Migration
    Schema::create('receipts', function (Blueprint $table) {
        $table->id();
        $table->json('data'); // Structured output from scanner
        $table->string('source_path');
        $table->morphs('owner');
        $table->timestamps();
    });
    
  • Queue Jobs: Offload scanning to a queue (e.g., scanReceiptJob) to avoid timeouts:

    ScanReceiptJob::dispatch($filePath)->onQueue('receipts');
    
  • Validation: Validate OpenAI responses with a custom validator:

    use HelgeSverre\ReceiptScanner\Rules\ValidReceiptData;
    
    $request->validate([
        'receipt' => ['required', new ValidReceiptData],
    ]);
    
  • Fallback Logic: Handle OCR/Textract failures gracefully:

    try {
        $data = ReceiptScanner::scanFromImage($path);
    } catch (\Exception $e) {
        Log::error("OCR failed: {$e->getMessage()}");
        $data = ReceiptScanner::scanFromText(file_get_contents($path)); // Fallback
    }
    

Gotchas and Tips

Pitfalls

  1. OpenAI API Limits:

    • Rate Limits: Monitor usage via OpenAI::getRateLimit() to avoid hitting quotas.
    • Cost: Structured parsing can be expensive. Cache responses for identical inputs:
      $cacheKey = md5_file($path);
      $data = Cache::remember($cacheKey, now()->addHours(1), function () use ($path) {
          return ReceiptScanner::scanFromImage($path);
      });
      
  2. File Size Limits:

    • PDFs/Images: Large files may exceed OpenAI’s context window. Pre-process with:
      use HelgeSverre\ReceiptScanner\Services\Preprocessor;
      
      $text = Preprocessor::extractTextFromPdf($path, maxPages: 5);
      $data = ReceiptScanner::scanFromText($text);
      
  3. Prompt Sensitivity:

    • Custom Prompts: Override the default prompt in config/receipt-scanner.php if the package’s prompt misses fields (e.g., tax IDs). Test with edge cases (e.g., handwritten receipts).
  4. OCR Dependencies:

    • Textract: If using AWS Textract, ensure:
      • IAM permissions are configured.
      • The AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY are in .env.
      • Fallback to a local OCR tool (e.g., Tesseract) if Textract fails.
  5. Structured Data Schema:

    • The package returns a dynamic array. Normalize the schema in a model:
      class Receipt extends Model {
          protected $casts = [
              'data' => ReceiptData::class, // Custom cast for validation/access
          ];
      }
      

Debugging Tips

  1. Log Raw Responses: Enable debug mode in config/receipt-scanner.php to log OpenAI responses:

    'debug' => env('RECEIPT_SCANNER_DEBUG', false),
    

    Check logs at storage/logs/laravel.log.

  2. Validate Inputs: Sanitize inputs before scanning to avoid malformed data:

    $text = preg_replace('/[^a-zA-Z0-9\s.,-]/', '', $rawText);
    $data = ReceiptScanner::scanFromText($text);
    
  3. Test with Known Data: Use a sample receipt (e.g., from this repo’s tests) to verify accuracy.

Extension Points

  1. Custom Extractors: Extend the base scanner by creating a custom extractor:

    namespace App\Services;
    
    use HelgeSverre\ReceiptScanner\Contracts\Extractor;
    
    class CustomExtractor implements Extractor {
        public function extract($input): array {
            // Custom logic (e.g., regex + OpenAI hybrid)
            return $this->hybridParse($input);
        }
    }
    

    Register it in config/receipt-scanner.php:

    'extractors' => [
        'custom' => App\Services\CustomExtractor::class,
    ],
    
  2. Webhook Integration: Trigger scans via a webhook (e.g., from a cloud storage event):

    Route::post('/scan-webhook', function (Request $request) {
        $fileUrl = $request->input('file_url');
        $data = ReceiptScanner::scanFromImage(storage_path("temp/{$request->filename}"));
        // Process and return $data
    });
    
  3. Model Observers: Automatically scan uploads on model events:

    class ReceiptObserver {
        public function saved(Receipt $receipt) {
            if ($receipt->wasRecentlyCreated && $receipt->source_path) {
                $data = ReceiptScanner::scanFromImage($receipt->source_path);
                $receipt->update(['data' => $data]);
            }
        }
    }
    
  4. Prompt Tuning: Override the default prompt for domain-specific receipts (e.g., medical invoices):

    ReceiptScanner::setPrompt(file_get_contents(app_path('Prompts/medical-receipt-prompt.txt')));
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
jayeshmepani/jpl-moshier-ephemeris-php
elnasnato/laraliveui
labrodev/rest-sdk
sampaui/sampaui
babelqueue/php-sdk
facebook/capi-param-builder-php
babelqueue/symfony
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle