## 主要变更 ### 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>
85 lines
2.3 KiB
TypeScript
85 lines
2.3 KiB
TypeScript
/**
|
||
* 路径解析工具
|
||
* 解决开发环境下路径解析问题
|
||
*/
|
||
|
||
import path from 'path';
|
||
import fs from 'fs';
|
||
import { fileURLToPath } from 'url';
|
||
|
||
/**
|
||
* 获取项目根目录
|
||
* 通过从当前文件向上查找 package.json 来确定
|
||
*/
|
||
export function getProjectRoot(): string {
|
||
// 在开发环境使用 tsx 时,使用 process.cwd()
|
||
// 在构建后的环境,使用 __dirname 的方式
|
||
let currentDir: string;
|
||
|
||
try {
|
||
// ESM 模式下获取当前文件目录
|
||
const __filename = fileURLToPath(import.meta.url);
|
||
currentDir = path.dirname(__filename);
|
||
} catch {
|
||
// 回退到 process.cwd()
|
||
currentDir = process.cwd();
|
||
}
|
||
|
||
// Windows 路径处理(去除开头的 /)
|
||
if (process.platform === 'win32' && currentDir.startsWith('/') && /^[a-zA-Z]:/.test(currentDir.slice(1))) {
|
||
currentDir = currentDir.substring(1);
|
||
}
|
||
|
||
// 从当前目录向上查找 package.json
|
||
let searchDir = currentDir;
|
||
for (let i = 0; i < 10; i++) {
|
||
const pkgPath = path.join(searchDir, 'package.json');
|
||
if (fs.existsSync(pkgPath)) {
|
||
return searchDir;
|
||
}
|
||
searchDir = path.dirname(searchDir);
|
||
}
|
||
|
||
// 如果找不到,回退到 process.cwd()
|
||
return process.cwd();
|
||
}
|
||
|
||
/**
|
||
* 获取上传目录的绝对路径
|
||
*/
|
||
export function getUploadsDir(): string {
|
||
const projectRoot = getProjectRoot();
|
||
return path.join(projectRoot, 'uploads');
|
||
}
|
||
|
||
/**
|
||
* 解析图片路径
|
||
* 将数据库中存储的路径 (/uploads/xxx.png) 解析为绝对路径
|
||
*/
|
||
export function resolveImagePath(imagePath: string): string {
|
||
// 在 Windows 上,path.isAbsolute 会将 /uploads/... 认为是绝对路径
|
||
// 但这实际上是 Unix 风格的相对路径,需要特殊处理
|
||
const isWindowsAbsPath = process.platform === 'win32'
|
||
? /^[a-zA-Z]:\\/.test(imagePath) // Windows 真正的绝对路径如 C:\
|
||
: path.isAbsolute(imagePath);
|
||
|
||
if (isWindowsAbsPath) {
|
||
return imagePath;
|
||
}
|
||
|
||
// 处理 /uploads/ 开头的相对路径
|
||
if (imagePath.startsWith('/uploads/')) {
|
||
return path.join(getUploadsDir(), imagePath.replace('/uploads/', ''));
|
||
}
|
||
|
||
// 其他相对路径,使用项目根目录
|
||
return path.join(getProjectRoot(), imagePath);
|
||
}
|
||
|
||
/**
|
||
* 生成存储到数据库的路径
|
||
*/
|
||
export function generateDbPath(filename: string): string {
|
||
return `/uploads/${filename}`;
|
||
}
|