import { Injectable, Logger } from '@nestjs/common'; import { createWorker, Worker } from 'tesseract.js'; import { I18nService } from '../i18n/i18n.service'; @Injectable() export class OcrService { private readonly logger = new Logger(OcrService.name); constructor(private readonly i18n: I18nService) {} async extractTextFromImage(imageBuffer: Buffer): Promise { this.logger.log( `Starting OCR extraction from image (${imageBuffer.length} bytes)...`, ); // Create worker for this request to ensure stability let worker: any = null; try { worker = await createWorker('chi_sim+eng+jpn'); const { data: { text }, } = await worker.recognize(imageBuffer); this.logger.log( `OCR extraction completed. ${text.length} characters extracted.`, ); if (text.length === 0) { this.logger.warn('OCR returned empty text.'); } await worker.terminate(); return text.trim(); } catch (error) { this.logger.error(`OCR text extraction failed: ${error.message}`); if (worker) { try { await worker.terminate(); } catch (e) {} } throw new Error( this.i18n.formatMessage('ocrFailed', { message: error.message }), ); } } async extractTextWithConfidence(imageBuffer: Buffer): Promise<{ text: string; confidence: number; }> { this.logger.log( `Starting OCR extraction with confidence (${imageBuffer.length} bytes)...`, ); let worker: any = null; try { worker = await createWorker('chi_sim+eng+jpn'); const { data } = await worker.recognize(imageBuffer); this.logger.log( `OCR extraction completed. Confidence: ${data.confidence}%`, ); await worker.terminate(); return { text: data.text.trim(), confidence: data.confidence, }; } catch (error) { this.logger.error(`OCR text extraction failed: ${error.message}`); if (worker) { try { await worker.terminate(); } catch (e) {} } throw new Error( this.i18n.formatMessage('ocrFailed', { message: error.message }), ); } } }