{"_id":"@brinda_yawa/file-scanner","_rev":"3-b7ed34627c0bd8e1b827d41dc4519c8e","name":"@brinda_yawa/file-scanner","dist-tags":{"latest":"1.0.2"},"versions":{"1.0.0":{"name":"@brinda_yawa/file-scanner","version":"1.0.0","keywords":["ocr","invoice","google-genai","tesseract","pdf","file-scanner"],"author":{"name":"brinda_yawa","email":"mawuviwobrinda@gmail.com"},"license":"ISC","_id":"@brinda_yawa/file-scanner@1.0.0","maintainers":[{"name":"brinda_yawa","email":"mawuviwobrinda@gmail.com"}],"dist":{"shasum":"93159f657bd1a27dee81c0b1daf2cb1e9ac04135","tarball":"https://registry.npmjs.org/@brinda_yawa/file-scanner/-/file-scanner-1.0.0.tgz","fileCount":6,"integrity":"sha512-FYYGkC0rrT4wsGx2x6BCKN5hS4eHXBSxU/+E5fgYQX3X5USauTw77GQt/M15NHsQbYW5OXmntxxZKikTMPrbWQ==","signatures":[{"sig":"MEYCIQD1QHG41V0LdSNA8SDn8YhF0sjVcjFoGV4xcj1ZaNP5PgIhAIyWjP58hCkHmUASeGYuI0eYH9ueWuo9dnZq3dDLwLT9","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":2800284},"main":"dist/index.mjs","type":"module","scripts":{"lint":"eslint .","test":"node test/index.js","build":"rollup -c","prepare":"npm run build"},"_npmUser":{"name":"brinda_yawa","email":"mawuviwobrinda@gmail.com"},"_npmVersion":"10.9.2","description":"A Node.js package that scans files in a specified directory, extracts text using OCR, and generates summaries using the Google GenAI API.","directories":{},"_nodeVersion":"23.11.0","dependencies":{"dotenv":"^16.3.1","fs-extra":"^11.3.3","pdf-parse":"^2.4.5","tesseract.js":"^7.0.0","@google/genai":"^1.40.0"},"_hasShrinkwrap":false,"devDependencies":{"rollup":"^4.9.6","@rollup/plugin-terser":"^0.4.4","@rollup/plugin-commonjs":"^29.0.0","@rollup/plugin-node-resolve":"^16.0.3"},"_npmOperationalInternal":{"tmp":"tmp/file-scanner_1.0.0_1770893315352_0.3023670553975264","host":"s3://npm-registry-packages-npm-production"}},"1.0.1":{"name":"@brinda_yawa/file-scanner","version":"1.0.1","keywords":["ocr","invoice","google-genai","tesseract","pdf","file-scanner"],"author":{"name":"brinda_yawa","email":"mawuviwobrinda@gmail.com"},"license":"ISC","_id":"@brinda_yawa/file-scanner@1.0.1","maintainers":[{"name":"brinda_yawa","email":"mawuviwobrinda@gmail.com"}],"dist":{"shasum":"977bdc5bdec033043323c40e449aeb2d031fad4c","tarball":"https://registry.npmjs.org/@brinda_yawa/file-scanner/-/file-scanner-1.0.1.tgz","fileCount":6,"integrity":"sha512-7GYDzPZHr5e4jrcOxd08TZ2LTsuKj021W/QaxY3iOUFlLHeONuo1xIy0TH8jJI+4ITAQpjTBe7t2nzJp6XZacg==","signatures":[{"sig":"MEQCIAjLUzgdyZXjJqelrnJ23YyN41DWlsM0OUH48N7wtXCYAiAiA8kiBJ7ltFvREkTiJc585pWsIv6csbprvWFrzVl3CQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":2800546},"main":"dist/index.mjs","type":"module","scripts":{"lint":"eslint .","test":"node test/index.js","build":"rollup -c","prepare":"npm run build"},"_npmUser":{"name":"brinda_yawa","email":"mawuviwobrinda@gmail.com"},"_npmVersion":"10.9.2","description":"A Node.js package that scans files in a specified directory, extracts text using OCR, and generates summaries using the Google GenAI API.","directories":{},"_nodeVersion":"23.11.0","dependencies":{"dotenv":"^16.3.1","fs-extra":"^11.3.3","pdf-parse":"^2.4.5","tesseract.js":"^7.0.0","@google/genai":"^1.40.0"},"_hasShrinkwrap":false,"devDependencies":{"rollup":"^4.9.6","@rollup/plugin-terser":"^0.4.4","@rollup/plugin-commonjs":"^29.0.0","@rollup/plugin-node-resolve":"^16.0.3"},"_npmOperationalInternal":{"tmp":"tmp/file-scanner_1.0.1_1770893849558_0.040735307537619336","host":"s3://npm-registry-packages-npm-production"}},"1.0.2":{"name":"@brinda_yawa/file-scanner","version":"1.0.2","description":"A Node.js package that scans files in a specified directory, extracts text using OCR, and generates summaries using the Google GenAI API.","type":"module","main":"dist/index.mjs","scripts":{"build":"rollup -c","prepare":"npm run build","lint":"eslint .","test":"node test/index.js"},"keywords":["ocr","invoice","google-genai","tesseract","pdf","file-scanner"],"author":{"name":"brinda_yawa","email":"mawuviwobrinda@gmail.com"},"license":"ISC","dependencies":{"@google/genai":"^1.40.0","dotenv":"^16.3.1","fs-extra":"^11.3.3","pdf-parse":"^2.4.5","tesseract.js":"^7.0.0"},"devDependencies":{"@rollup/plugin-commonjs":"^29.0.0","@rollup/plugin-node-resolve":"^16.0.3","@rollup/plugin-terser":"^0.4.4","rollup":"^4.9.6"},"_id":"@brinda_yawa/file-scanner@1.0.2","_nodeVersion":"23.11.0","_npmVersion":"10.9.2","dist":{"integrity":"sha512-50Vt4yX4lgXKF0Ga2hZBO/5TKey8KlEPw3xdOVjT2NPIXVA2ITIwRLmcchD2GnYGaqvWYhH8ksGFADXVbP1MJQ==","shasum":"9eb26fe73138c0a9b441f665c5ceb4b4d822bcdb","tarball":"https://registry.npmjs.org/@brinda_yawa/file-scanner/-/file-scanner-1.0.2.tgz","fileCount":6,"unpackedSize":2800292,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIAMi9Q+TNe8cnJ2e34y6BESxsJEjj/dSaGQRluO2nereAiBLOejQ4D6izEEABpwBBNZ09P2Sju0QA5skCv6hJbvwuQ=="}]},"_npmUser":{"name":"brinda_yawa","email":"mawuviwobrinda@gmail.com"},"directories":{},"maintainers":[{"name":"brinda_yawa","email":"mawuviwobrinda@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/file-scanner_1.0.2_1770895038195_0.7061673934522754"},"_hasShrinkwrap":false}},"time":{"created":"2026-02-12T10:48:35.276Z","modified":"2026-02-12T11:17:18.576Z","1.0.0":"2026-02-12T10:48:35.541Z","1.0.1":"2026-02-12T10:57:29.756Z","1.0.2":"2026-02-12T11:17:18.445Z"},"author":{"name":"brinda_yawa","email":"mawuviwobrinda@gmail.com"},"license":"ISC","keywords":["ocr","invoice","google-genai","tesseract","pdf","file-scanner"],"description":"A Node.js package that scans files in a specified directory, extracts text using OCR, and generates summaries using the Google GenAI API.","maintainers":[{"name":"brinda_yawa","email":"mawuviwobrinda@gmail.com"}],"readme":"# 📄 @brinda_yawa/file-scanner\n\nA powerful Node.js package for extracting structured invoice data from PDF and image files using AI-powered OCR and vision models.\n\n## ✨ Features\n\n- 🤖 **AI-Powered Extraction** - Uses Google's Gemini AI for intelligent data extraction\n- 📄 **PDF Support** - Extract text from PDF documents\n- 🖼️ **Image Support** - OCR for PNG, JPG, JPEG, and WEBP image formats\n- 🔄 **Smart Fallback** - Automatically switches between text extraction and vision mode\n- 🎯 **Structured Output** - Returns clean, structured JSON data\n- 🔒 **Singleton Pattern** - Efficient resource management\n\n## 📦 Installation\n```bash\nnpm install @brinda_yawa/file-scanner\n```\n\n## 🚀 Quick Start\n```javascript\nimport InvoiceExtractor from '@brinda_yawa/file-scanner';\nimport fs from 'fs';\n\n// Initialize the extractor (singleton)\nconst extractor = InvoiceExtractor;\nextractor.init({ apiKey: 'YOUR API KEY', model: 'gemini-2.5-flash' });\n\n\n// Read your invoice file\nconst fileBuffer = fs.readFileSync('invoice.pdf');\n\n// Extract invoice data\nconst invoiceData = await extractor.extract(fileBuffer, '.pdf');\n```\n\n## 📖 API Reference\n\n### `InvoiceExtractor.init(options)`\n\nCreates or returns the singleton instance of the extractor.\n\n**Parameters:**\n- `options.apiKey` (string, required) - Your Google Gemini API key\n- `options.model` (string, optional) - The Gemini model to use. Default: `'gemini-2.5-flash'`\n\n**Returns:** `InvoiceExtractor` instance\n\n**Example:**\n```javascript\n\n// Initialize the singleton instance\nconst extractor = InvoiceExtractor;\nextractor.init({\n    apiKey: process.env.GEMINI_API_KEY,\n    model: 'gemini-2.5-flash' \n});\n\n// Read your invoice file\nconst fileBuffer = fs.readFileSync('invoice.pdf');\nconst invoiceData = await extractor.extract(fileBuffer, '.pdf');\nconsole.log(invoiceData);\n```\n\n### `extractor.extract(fileBuffer, extension)`\n\nExtracts structured data from an invoice file.\n\n**Parameters:**\n- `fileBuffer` (Buffer, required) - The file buffer to process\n- `extension` (string, required) - File extension (e.g., '.pdf', '.png', '.jpg')\n\n**Returns:** `Promise<Object|null>` - Extracted invoice data or null if extraction fails\n\n**Example:**\n```javascript\nconst invoiceData = await extractor.extract(fileBuffer, '.pdf');\n\n// Returns:\n{\n    invoiceNumber: \"INV-001\",\n    date: \"2024-01-15\", \n    supplier: \"Acme Corp\",\n    total: 1250.00,\n    items: [\n        {\n            description: \"Product A\",\n            quantity: 2,\n            unitPrice: 500.00,\n            total: 1000.00,\n            category: \"Electronics\"\n        }\n    ]\n    // ... more fields\n}\n```\n## 🎯 Supported File Types\n\n### Images\n- `.png` - PNG images\n- `.jpg`, `.jpeg` - JPEG images\n- `.gif` - GIF images\n- `.webp` - WebP images\n- `.bmp` - Bitmap images\n\n### Documents\n- `.pdf` - PDF documents\n\n### Environment Variables\n\nCreate a `.env` file in your project root:\n```env\nGEMINI_API_KEY=your_api_key_here\n```\n**Recommendation:** Use `gemini-2.5-flash` for development and production.\n\n## 💡 Advanced Usage\n\n### Handling Multiple Files\n```javascript\nimport InvoiceExtractor from '@brinda_yawa/file-scanner';\nimport fs from 'fs';\nimport path from 'path';\n\nconst extractor = InvoiceExtractor;\nextractor.init({\n    apiKey: process.env.GEMINI_API_KEY\n});\n\nasync function processInvoices(folderPath) {\n    const files = fs.readdirSync(folderPath);\n    const results = [];\n\n    for (const file of files) {\n        const ext = path.extname(file);\n        if (['.pdf', '.png', '.jpg', '.jpeg'].includes(ext)) {\n            const buffer = fs.readFileSync(path.join(folderPath, file));\n            const data = await extractor.extract(buffer, ext);\n            \n            if (data) {\n                results.push({ file, data });\n            }\n        }\n    }\n\n    return results;\n}\n\nconst invoices = await processInvoices('./invoices');\nconsole.log(`Processed ${invoices.length} invoices`);\n```\n\n### Error Handling\n```javascript\nconst extractor = InvoiceExtractor;\nextractor.init({\n    apiKey: process.env.GEMINI_API_KEY\n});\n\ntry {\n    const buffer = fs.readFileSync('invoice.pdf');\n    const data = await extractor.extract(buffer, '.pdf');\n    \n    if (!data) {\n        console.error('Failed to extract data from invoice');\n    } else {\n        console.log('Invoice extracted successfully:', data);\n    }\n} catch (error) {\n    if (error.message.includes('quota')) {\n        console.error('API quota exceeded. Please wait or upgrade your plan.');\n    } else if (error.message.includes('API key')) {\n        console.error('Invalid API key. Please check your credentials.');\n    } else {\n        console.error('Extraction error:', error.message);\n    }\n}\n```\n\n### Using with Express.js\n```javascript\nimport express from 'express';\nimport multer from 'multer';\nimport InvoiceExtractor from '@brinda_yawa/file-scanner';\n\nconst app = express();\nconst upload = multer({ storage: multer.memoryStorage() });\n\nconst extractor = InvoiceExtractor.getInstance({\n    apiKey: process.env.GEMINI_API_KEY\n});\n\napp.post('/extract', upload.single('invoice'), async (req, res) => {\n    try {\n        if (!req.file) {\n            return res.status(400).json({ error: 'No file uploaded' });\n        }\n\n        const ext = '.' + req.file.originalname.split('.').pop();\n        const data = await extractor.extract(req.file.buffer, ext);\n\n        if (!data) {\n            return res.status(500).json({ error: 'Extraction failed' });\n        }\n\n        res.json({ success: true, data });\n    } catch (error) {\n        res.status(500).json({ error: error.message });\n    }\n});\n\napp.listen(3000, () => {\n    console.log('Server running on port 3000');\n});\n```\n\n### Using with TypeScript\n```typescript\nimport InvoiceExtractor from '@brinda_yawa/file-scanner';\nimport * as fs from 'fs';\n\ninterface InvoiceData {\n    invoiceNumber: string;\n    date: string;\n    supplier: string;\n    total: number;\n    items: Array<{\n        description: string;\n        quantity: number;\n        unitPrice: number;\n        total: number;\n    }>;\n}\nconst extractor = InvoiceExtractor;\n\nextractor.init({\n    apiKey: process.env.GEMINI_API_KEY!,\n    model: 'gemini-2.5-flash'\n});\n\nasync function extractInvoice(filePath: string): Promise<InvoiceData | null> {\n    const buffer = fs.readFileSync(filePath);\n    const ext = filePath.substring(filePath.lastIndexOf('.'));\n    return await extractor.extract(buffer, ext) as InvoiceData;\n}\n\nconst data = await extractInvoice('invoice.pdf');\nif (data) {\n    console.log(`Invoice ${data.invoiceNumber} total: ${data.total}`);\n}\n```\n\n## 🧪 Testing\n```javascript\nimport InvoiceExtractor from '@brinda_yawa/file-scanner';\nimport fs from 'fs';\nimport assert from 'assert';\n\n// Reset instance before each test\nInvoiceExtractor.resetInstance();\nconst extractor = InvoiceExtractor;\n\nextractor.init({\n    apiKey: process.env.GEMINI_API_KEY\n});\n\n// Test PDF extraction\nconst pdfBuffer = fs.readFileSync('test/sample.pdf');\nconst pdfData = await extractor.extract(pdfBuffer, '.pdf');\nassert(pdfData !== null, 'PDF extraction failed');\nassert(pdfData.invoiceNumber, 'Invoice number not extracted');\n\n// Test image extraction\nconst imgBuffer = fs.readFileSync('test/sample.png');\nconst imgData = await extractor.extract(imgBuffer, '.png');\nassert(imgData !== null, 'Image extraction failed');\n\nconsole.log('✅ All tests passed');\n```\n\n\n\n### ⚠️ Common Issues\n\n#### Quota Exceeded Error\n```\nError: You exceeded your current quota\n```\n\n**Solutions:**\n1. Wait for quota reset (daily)\n2. Use a model with higher free tier quota (`gemini-1.5-flash`)\n3. Enable billing on your Google Cloud account\n\n### Invalid API Key\n```\nError: Gemini API key is required\n```\n\n**Solutions:**\n1. Check that your API key is set in `.env`\n2. Verify the API key is valid in Google AI Studio\n3. Make sure you're using the correct environment variable name\n\n### Extraction Returns Null\n\n**Possible causes:**\n1. File is corrupted or unreadable\n2. File format not supported\n3. API quota exceeded\n4. Poor image quality (for OCR)\n\n**Solutions:**\n1. Check file integrity\n2. Try a different file\n3. Increase image resolution\n4. Check API quota\n\nMade with ❤️ by Brinda Yawa","readmeFilename":"README.md"}