## 主要变更 ### 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>
128 lines
2.7 KiB
TypeScript
128 lines
2.7 KiB
TypeScript
/**
|
|
* 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);
|
|
}
|
|
}
|