diff --git a/packages/shared/config/constant.ts b/packages/shared/config/constant.ts index 9240bb73f5..82b78459a5 100644 --- a/packages/shared/config/constant.ts +++ b/packages/shared/config/constant.ts @@ -197,12 +197,6 @@ export enum FeedUrl { GITHUB_LATEST = 'https://github.com/CherryHQ/cherry-studio/releases/latest/download' } -export const tesseractLangs = ['chi_sim', 'chi_tra', 'eng'] -export enum TesseractLangsDownloadUrl { - CN = 'https://gitcode.com/beyondkmp/tessdata/releases/download/4.1.0/', - GLOBAL = 'https://github.com/tesseract-ocr/tessdata/raw/main/' -} - export enum UpgradeChannel { LATEST = 'latest', // 最新稳定版本 RC = 'rc', // 公测版本 diff --git a/src/main/services/ocr/OcrService.ts b/src/main/services/ocr/OcrService.ts index d709115b9c..73907574b2 100644 --- a/src/main/services/ocr/OcrService.ts +++ b/src/main/services/ocr/OcrService.ts @@ -1,13 +1,19 @@ -import { BuiltinOcrProviderIds, FileMetadata, OcrProvider, OcrResult, SupportedOcrFile } from '@types' +import { loggerService } from '@logger' +import { BuiltinOcrProviderIds, OcrProvider, OcrResult, SupportedOcrFile } from '@types' import { tesseractService } from './tesseract/TesseractService' -type OcrHandler = (file: FileMetadata) => Promise +type OcrHandler = (file: SupportedOcrFile) => Promise + +const logger = loggerService.withContext('OcrService') export class OcrService { private registry: Map = new Map() register(providerId: string, handler: OcrHandler): void { + if (this.registry.has(providerId)) { + logger.warn(`Provider ${providerId} has existing handler. Overwrited.`) + } this.registry.set(providerId, handler) } diff --git a/src/main/services/ocr/tesseract/TesseractService.ts b/src/main/services/ocr/tesseract/TesseractService.ts index 2472f02fba..77225d4afe 100644 --- a/src/main/services/ocr/tesseract/TesseractService.ts +++ b/src/main/services/ocr/tesseract/TesseractService.ts @@ -1,7 +1,7 @@ import { loggerService } from '@logger' import { getIpCountry } from '@main/utils/ipService' -import { MB, TesseractLangsDownloadUrl } from '@shared/config/constant' -import { FileMetadata, ImageFileMetadata, isImageFile, OcrResult } from '@types' +import { MB } from '@shared/config/constant' +import { ImageFileMetadata, isImageFile, OcrResult, SupportedOcrFile } from '@types' import { app } from 'electron' import fs from 'fs' import path from 'path' @@ -114,13 +114,21 @@ const logger = loggerService.withContext('TesseractService') // 'yi-us': 'yid' // } +// config +const MB_SIZE_THRESHOLD = 50 +const tesseractLangs = ['chi_sim', 'chi_tra', 'eng'] +enum TesseractLangsDownloadUrl { + CN = 'https://gitcode.com/beyondkmp/tessdata/releases/download/4.1.0/', + GLOBAL = 'https://github.com/tesseract-ocr/tessdata/raw/main/' +} + export class TesseractService { private worker: Tesseract.Worker | null = null async getWorker(): Promise { if (!this.worker) { // for now, only support limited languages - this.worker = await createWorker(['chi_sim', 'chi_tra', 'eng'], undefined, { + this.worker = await createWorker(tesseractLangs, undefined, { langPath: await this._getLangPath(), cachePath: await this._getCacheDir(), gzip: false, @@ -133,15 +141,15 @@ export class TesseractService { async imageOcr(file: ImageFileMetadata): Promise { const worker = await this.getWorker() const stat = await fs.promises.stat(file.path) - if (stat.size > 50 * MB) { - throw new Error('This image is too large (max 50MB)') + if (stat.size > MB_SIZE_THRESHOLD * MB) { + throw new Error(`This image is too large (max ${MB_SIZE_THRESHOLD}MB)`) } const buffer = await fs.promises.readFile(file.path) const result = await worker.recognize(buffer) return { text: result.data.text } } - async ocr(file: FileMetadata): Promise { + async ocr(file: SupportedOcrFile): Promise { if (!isImageFile(file)) { throw new Error('Only image files are supported currently') } diff --git a/src/renderer/src/types/ocr.ts b/src/renderer/src/types/ocr.ts index c7870a95f4..c7e53f24a6 100644 --- a/src/renderer/src/types/ocr.ts +++ b/src/renderer/src/types/ocr.ts @@ -21,7 +21,7 @@ export const isOcrProviderCapability = (cap: string): cap is OcrProviderCapabili return Object.hasOwn(OcrProviderCapabilities, cap) } -export type OcrProviderCapabilityRecord = Record +export type OcrProviderCapabilityRecord = Partial> export type OcrProvider = { id: string @@ -59,7 +59,7 @@ export type ImageOcrProvider = OcrProvider & { } export const isImageOcrProvider = (p: OcrProvider): p is ImageOcrProvider => { - return p.capabilities.image + return p.capabilities.image === true } export type SupportedOcrFile = ImageFileMetadata