mirror of
https://github.com/alam00000/bentopdf.git
synced 2026-10-01 22:24:50 +02:00
- 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.
129 lines
4.0 KiB
TypeScript
129 lines
4.0 KiB
TypeScript
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
|
|
const { createWorker } = vi.hoisted(() => ({
|
|
createWorker: vi.fn(),
|
|
}));
|
|
|
|
vi.mock('tesseract.js', () => ({
|
|
default: {
|
|
createWorker,
|
|
},
|
|
}));
|
|
|
|
import {
|
|
buildTesseractWorkerOptions,
|
|
createConfiguredTesseractWorker,
|
|
getIncompleteTesseractOverrideKeys,
|
|
hasCompleteTesseractOverrides,
|
|
hasConfiguredTesseractOverrides,
|
|
resolveTesseractAssetConfig,
|
|
} from '../js/utils/tesseract-runtime';
|
|
import {
|
|
assertTesseractLanguagesAvailable,
|
|
getAvailableTesseractLanguageEntries,
|
|
getUnavailableTesseractLanguages,
|
|
UnsupportedOcrLanguageError,
|
|
} from '../js/utils/tesseract-language-availability';
|
|
|
|
describe('tesseract-runtime', () => {
|
|
beforeEach(() => {
|
|
createWorker.mockReset();
|
|
});
|
|
|
|
it('normalizes self-hosted OCR asset URLs', () => {
|
|
const config = resolveTesseractAssetConfig({
|
|
VITE_TESSERACT_WORKER_URL:
|
|
'https://internal.example.com/ocr/worker.min.js/',
|
|
VITE_TESSERACT_CORE_URL: 'https://internal.example.com/ocr/core/',
|
|
VITE_TESSERACT_LANG_URL: 'https://internal.example.com/ocr/lang-data/',
|
|
});
|
|
|
|
expect(config).toEqual({
|
|
workerPath: 'https://internal.example.com/ocr/worker.min.js',
|
|
corePath: 'https://internal.example.com/ocr/core',
|
|
langPath: 'https://internal.example.com/ocr/lang-data',
|
|
});
|
|
expect(hasConfiguredTesseractOverrides(config)).toBe(true);
|
|
expect(hasCompleteTesseractOverrides(config)).toBe(true);
|
|
});
|
|
|
|
it('returns logger-only options when no self-hosted OCR assets are configured', () => {
|
|
const logger = vi.fn();
|
|
|
|
expect(buildTesseractWorkerOptions(logger, {})).toEqual({ logger });
|
|
expect(
|
|
hasConfiguredTesseractOverrides(resolveTesseractAssetConfig({}))
|
|
).toBe(false);
|
|
});
|
|
|
|
it('throws on partial OCR asset configuration', () => {
|
|
const env = {
|
|
VITE_TESSERACT_WORKER_URL:
|
|
'https://internal.example.com/ocr/worker.min.js',
|
|
VITE_TESSERACT_CORE_URL: 'https://internal.example.com/ocr/core',
|
|
};
|
|
|
|
expect(
|
|
getIncompleteTesseractOverrideKeys(resolveTesseractAssetConfig(env))
|
|
).toEqual(['VITE_TESSERACT_LANG_URL']);
|
|
expect(() => buildTesseractWorkerOptions(undefined, env)).toThrow(
|
|
'Self-hosted OCR assets are partially configured'
|
|
);
|
|
});
|
|
|
|
it('passes configured OCR asset URLs to Tesseract.createWorker', async () => {
|
|
const logger = vi.fn();
|
|
createWorker.mockResolvedValue({ id: 'worker' });
|
|
|
|
await createConfiguredTesseractWorker('eng', 1, logger, {
|
|
VITE_TESSERACT_WORKER_URL:
|
|
'https://internal.example.com/ocr/worker.min.js',
|
|
VITE_TESSERACT_CORE_URL: 'https://internal.example.com/ocr/core',
|
|
VITE_TESSERACT_LANG_URL: 'https://internal.example.com/ocr/lang-data',
|
|
});
|
|
|
|
expect(createWorker).toHaveBeenCalledWith('eng', 1, {
|
|
logger,
|
|
workerPath: 'https://internal.example.com/ocr/worker.min.js',
|
|
corePath: 'https://internal.example.com/ocr/core',
|
|
langPath: 'https://internal.example.com/ocr/lang-data',
|
|
gzip: true,
|
|
});
|
|
});
|
|
|
|
it('filters OCR language entries when the build restricts bundled languages', () => {
|
|
expect(
|
|
getAvailableTesseractLanguageEntries({
|
|
VITE_TESSERACT_AVAILABLE_LANGUAGES: 'eng,deu',
|
|
})
|
|
).toEqual([
|
|
['eng', 'English'],
|
|
['deu', 'German'],
|
|
]);
|
|
});
|
|
|
|
it('reports unavailable OCR languages for restricted air-gap builds', () => {
|
|
expect(
|
|
getUnavailableTesseractLanguages('eng+fra', {
|
|
VITE_TESSERACT_AVAILABLE_LANGUAGES: 'eng,deu',
|
|
})
|
|
).toEqual(['fra']);
|
|
|
|
expect(() =>
|
|
assertTesseractLanguagesAvailable('eng+fra', {
|
|
VITE_TESSERACT_AVAILABLE_LANGUAGES: 'eng,deu',
|
|
})
|
|
).toThrow(UnsupportedOcrLanguageError);
|
|
});
|
|
|
|
it('blocks worker creation when OCR requests an unbundled language', async () => {
|
|
await expect(
|
|
createConfiguredTesseractWorker('fra', 1, undefined, {
|
|
VITE_TESSERACT_AVAILABLE_LANGUAGES: 'eng,deu',
|
|
})
|
|
).rejects.toThrow('This BentoPDF build only bundles OCR data for');
|
|
|
|
expect(createWorker).not.toHaveBeenCalled();
|
|
});
|
|
});
|