mirror of
https://github.com/alam00000/bentopdf.git
synced 2026-11-13 17:54:19 +01:00
feat: integrate Tesseract.js with improved language availability and font handling
- Refactored OCR page recognition to utilize a configured Tesseract worker. - Added functions to manage font URLs and asset filenames based on language. - Implemented language availability checks and error handling for unsupported languages. - Enhanced PDF workflow to display available OCR languages and handle user selections. - Introduced utility functions for resolving Tesseract asset configurations. - Added tests for OCR functionality, font loading, and Tesseract runtime behavior. - Updated global types to include environment variables for Tesseract and font configurations.
This commit is contained in:
1 parent
58c78b09d2
commit
77da6d7a7d
23 files changed
+1906
-564
No files matched your search
@@ -0,0 +1,130 @@
|
||||
import Tesseract from 'tesseract.js';
|
||||
import {
|
||||
assertTesseractLanguagesAvailable,
|
||||
TESSERACT_AVAILABLE_LANGUAGES_ENV_KEY,
|
||||
} from './tesseract-language-availability.js';
|
||||
|
||||
const TESSERACT_ENV_KEYS = [
|
||||
'VITE_TESSERACT_WORKER_URL',
|
||||
'VITE_TESSERACT_CORE_URL',
|
||||
'VITE_TESSERACT_LANG_URL',
|
||||
] as const;
|
||||
|
||||
const TESSERACT_RUNTIME_ENV_KEYS = [
|
||||
...TESSERACT_ENV_KEYS,
|
||||
TESSERACT_AVAILABLE_LANGUAGES_ENV_KEY,
|
||||
] as const;
|
||||
|
||||
type TesseractRuntimeEnvKey = (typeof TESSERACT_RUNTIME_ENV_KEYS)[number];
|
||||
|
||||
export type TesseractAssetEnv = Partial<
|
||||
Pick<ImportMetaEnv, TesseractRuntimeEnvKey>
|
||||
>;
|
||||
|
||||
export interface TesseractAssetConfig {
|
||||
workerPath?: string;
|
||||
corePath?: string;
|
||||
langPath?: string;
|
||||
}
|
||||
|
||||
export type TesseractLoggerMessage = Tesseract.LoggerMessage;
|
||||
export type TesseractWorkerOptions = Partial<Tesseract.WorkerOptions>;
|
||||
export type TesseractWorker = Tesseract.Worker;
|
||||
|
||||
function getDefaultTesseractAssetEnv(): TesseractAssetEnv {
|
||||
return import.meta.env;
|
||||
}
|
||||
|
||||
function normalizeDirectoryUrl(url?: string): string | undefined {
|
||||
const trimmed = url?.trim();
|
||||
if (!trimmed) return undefined;
|
||||
return trimmed.replace(/\/+$/, '');
|
||||
}
|
||||
|
||||
function normalizeFileUrl(url?: string): string | undefined {
|
||||
const trimmed = url?.trim();
|
||||
if (!trimmed) return undefined;
|
||||
return trimmed.replace(/\/+$/, '');
|
||||
}
|
||||
|
||||
export function resolveTesseractAssetConfig(
|
||||
env: TesseractAssetEnv = getDefaultTesseractAssetEnv()
|
||||
): TesseractAssetConfig {
|
||||
return {
|
||||
workerPath: normalizeFileUrl(env.VITE_TESSERACT_WORKER_URL),
|
||||
corePath: normalizeDirectoryUrl(env.VITE_TESSERACT_CORE_URL),
|
||||
langPath: normalizeDirectoryUrl(env.VITE_TESSERACT_LANG_URL),
|
||||
};
|
||||
}
|
||||
|
||||
export function hasConfiguredTesseractOverrides(
|
||||
config: TesseractAssetConfig = resolveTesseractAssetConfig()
|
||||
): boolean {
|
||||
return Boolean(config.workerPath || config.corePath || config.langPath);
|
||||
}
|
||||
|
||||
export function hasCompleteTesseractOverrides(
|
||||
config: TesseractAssetConfig = resolveTesseractAssetConfig()
|
||||
): boolean {
|
||||
return Boolean(config.workerPath && config.corePath && config.langPath);
|
||||
}
|
||||
|
||||
export function getIncompleteTesseractOverrideKeys(
|
||||
config: TesseractAssetConfig = resolveTesseractAssetConfig()
|
||||
): Array<(typeof TESSERACT_ENV_KEYS)[number]> {
|
||||
if (!hasConfiguredTesseractOverrides(config)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return TESSERACT_ENV_KEYS.filter((key) => {
|
||||
switch (key) {
|
||||
case 'VITE_TESSERACT_WORKER_URL':
|
||||
return !config.workerPath;
|
||||
case 'VITE_TESSERACT_CORE_URL':
|
||||
return !config.corePath;
|
||||
case 'VITE_TESSERACT_LANG_URL':
|
||||
return !config.langPath;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function buildTesseractWorkerOptions(
|
||||
logger?: TesseractWorkerOptions['logger'],
|
||||
env: TesseractAssetEnv = getDefaultTesseractAssetEnv()
|
||||
): TesseractWorkerOptions {
|
||||
const config = resolveTesseractAssetConfig(env);
|
||||
|
||||
if (!hasConfiguredTesseractOverrides(config)) {
|
||||
return logger ? { logger } : {};
|
||||
}
|
||||
|
||||
if (!hasCompleteTesseractOverrides(config)) {
|
||||
const missing = getIncompleteTesseractOverrideKeys(config).join(', ');
|
||||
throw new Error(
|
||||
`Self-hosted OCR assets are partially configured. Set ${missing} together with the other Tesseract asset URLs.`
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
...(logger ? { logger } : {}),
|
||||
workerPath: config.workerPath,
|
||||
corePath: config.corePath,
|
||||
langPath: config.langPath,
|
||||
gzip: true,
|
||||
};
|
||||
}
|
||||
|
||||
export async function createConfiguredTesseractWorker(
|
||||
language: string,
|
||||
oem: Tesseract.OEM,
|
||||
logger?: TesseractWorkerOptions['logger'],
|
||||
env: TesseractAssetEnv = getDefaultTesseractAssetEnv()
|
||||
): Promise<TesseractWorker> {
|
||||
assertTesseractLanguagesAvailable(language, env);
|
||||
|
||||
return Tesseract.createWorker(
|
||||
language,
|
||||
oem,
|
||||
buildTesseractWorkerOptions(logger, env)
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user