feat: 实现多 OCR 提供商架构和完整设置页面
## 主要变更 ### OCR 架构 - 新增多提供商 OCR 系统 (Tesseract.js, Baidu OCR, RapidOCR) - 添加 Provider 基类接口和工厂模式 - 支持 provider 自动选择和降级处理 - 新增 RapidOCR Python HTTP 服务 (端口 8080) ### 路径修复 - 修复 Windows 平台路径解析问题 - 统一路径处理工具 (lib/path.ts) - 修复 uploads 目录定位问题 ### 设置页面重构 - 三个标签页:API 配置、OCR 配置、AI 配置 - API 服务器地址配置 - OCR 服务商配置(Tesseract.js, RapidOCR, 百度 OCR) - AI 服务商配置(智谱 GLM, MiniMax, DeepSeek, Kimi, OpenAI, Anthropic) ### 端口配置 - 前端端口: 13056 - 后端端口: 13057 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
127
backend/src/services/ocr-providers/base.provider.ts
Normal file
127
backend/src/services/ocr-providers/base.provider.ts
Normal file
@@ -0,0 +1,127 @@
|
||||
/**
|
||||
* OCR Provider Base Interface
|
||||
* OCR 提供商基础接口
|
||||
*/
|
||||
|
||||
import { resolveImagePath } from '../../lib/path';
|
||||
|
||||
export interface OCRRecognitionResult {
|
||||
/** 识别的文本内容 */
|
||||
text: string;
|
||||
/** 置信度 (0-1) */
|
||||
confidence: number;
|
||||
/** 处理耗时 (毫秒) */
|
||||
duration?: number;
|
||||
/** 额外信息 */
|
||||
extra?: Record<string, unknown>;
|
||||
}
|
||||
|
||||
export interface OCRProviderConfig {
|
||||
/** 超时时间 (毫秒) */
|
||||
timeout?: number;
|
||||
/** 语言代码 (chi_sim, eng 等) */
|
||||
language?: string;
|
||||
/** 额外配置 */
|
||||
extras?: Record<string, unknown>;
|
||||
}
|
||||
|
||||
export interface IImageSource {
|
||||
/** 图片本地路径 */
|
||||
path?: string;
|
||||
/** 图片 Buffer */
|
||||
buffer?: Buffer;
|
||||
/** 图片 Base64 */
|
||||
base64?: string;
|
||||
/** 图片 URL */
|
||||
url?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* OCR Provider 抽象基类
|
||||
* 所有 OCR 提供商都需要实现此接口
|
||||
*/
|
||||
export abstract class BaseOCRProvider {
|
||||
protected config: OCRProviderConfig;
|
||||
|
||||
constructor(config: OCRProviderConfig = {}) {
|
||||
this.config = {
|
||||
timeout: 30000,
|
||||
language: 'chi_sim+eng',
|
||||
...config,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Provider 名称
|
||||
*/
|
||||
abstract getName(): string;
|
||||
|
||||
/**
|
||||
* Provider 类型 (local | cloud)
|
||||
*/
|
||||
abstract getType(): 'local' | 'cloud';
|
||||
|
||||
/**
|
||||
* 检查 Provider 是否可用
|
||||
*/
|
||||
abstract isAvailable(): Promise<boolean> | boolean;
|
||||
|
||||
/**
|
||||
* 执行 OCR 识别
|
||||
* @param source 图片来源 (路径/Buffer/Base64/URL)
|
||||
* @param options 可选配置
|
||||
*/
|
||||
abstract recognize(
|
||||
source: IImageSource,
|
||||
options?: OCRProviderConfig
|
||||
): Promise<OCRRecognitionResult>;
|
||||
|
||||
/**
|
||||
* 批量识别
|
||||
*/
|
||||
async batchRecognize(
|
||||
sources: IImageSource[],
|
||||
options?: OCRProviderConfig
|
||||
): Promise<OCRRecognitionResult[]> {
|
||||
const results: OCRRecognitionResult[] = [];
|
||||
|
||||
for (const source of sources) {
|
||||
try {
|
||||
const result = await this.recognize(source, options);
|
||||
results.push(result);
|
||||
} catch (error) {
|
||||
results.push({
|
||||
text: '',
|
||||
confidence: 0,
|
||||
duration: 0,
|
||||
extra: { error: error instanceof Error ? error.message : String(error) },
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取推荐配置
|
||||
*/
|
||||
getRecommendations(): {
|
||||
maxImageSize?: number;
|
||||
supportedFormats?: string[];
|
||||
notes?: string;
|
||||
} {
|
||||
return {
|
||||
maxImageSize: 10 * 1024 * 1024, // 10MB
|
||||
supportedFormats: ['jpg', 'jpeg', 'png', 'webp', 'bmp', 'gif'],
|
||||
notes: '建议图片分辨率不低于 300dpi',
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析图片路径
|
||||
* 将数据库路径转换为绝对路径
|
||||
*/
|
||||
protected resolveImagePath(imagePath: string): string {
|
||||
return resolveImagePath(imagePath);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user