115 行
3.6 KiB
JavaScript
115 行
3.6 KiB
JavaScript
|
|
// scripts/validate-models.js
|
||
|
|
import fs from 'fs-extra';
|
||
|
|
import path from 'path';
|
||
|
|
import { fileURLToPath } from 'url';
|
||
|
|
|
||
|
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||
|
|
|
||
|
|
class ModelValidator {
|
||
|
|
constructor() {
|
||
|
|
this.modelDir = path.join(process.cwd(), 'models', 'ocr');
|
||
|
|
this.requiredFiles = {
|
||
|
|
detection: path.join(this.modelDir, 'Det', '中文_OCRv3.onnx'),
|
||
|
|
recognition: path.join(this.modelDir, 'Rec', '中文简体_OCRv3.onnx'),
|
||
|
|
classification: path.join(this.modelDir, 'Cls', '原始分类器模型.onnx'),
|
||
|
|
keys: path.join(this.modelDir, 'Keys', '中文简体_OCRv3.txt')
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
async validateModels() {
|
||
|
|
console.log('🔍 验证模型文件...\n');
|
||
|
|
|
||
|
|
let allValid = true;
|
||
|
|
const results = [];
|
||
|
|
|
||
|
|
for (const [name, filePath] of Object.entries(this.requiredFiles)) {
|
||
|
|
const exists = await fs.pathExists(filePath);
|
||
|
|
const result = {
|
||
|
|
name: this.getDisplayName(name),
|
||
|
|
path: filePath,
|
||
|
|
exists,
|
||
|
|
size: 0,
|
||
|
|
valid: false
|
||
|
|
};
|
||
|
|
|
||
|
|
if (exists) {
|
||
|
|
try {
|
||
|
|
const stats = await fs.stat(filePath);
|
||
|
|
result.size = stats.size;
|
||
|
|
result.valid = this.validateFileSize(name, stats.size);
|
||
|
|
|
||
|
|
if (name === 'keys') {
|
||
|
|
result.valid = await this.validateKeysFile(filePath);
|
||
|
|
}
|
||
|
|
} catch (error) {
|
||
|
|
result.valid = false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
results.push(result);
|
||
|
|
allValid = allValid && result.valid;
|
||
|
|
}
|
||
|
|
|
||
|
|
// 显示验证结果
|
||
|
|
this.displayResults(results);
|
||
|
|
|
||
|
|
if (!allValid) {
|
||
|
|
console.log('\n❌ 模型文件不完整或损坏');
|
||
|
|
console.log('💡 运行以下命令重新下载:');
|
||
|
|
console.log(' yarn download-models');
|
||
|
|
process.exit(1);
|
||
|
|
} else {
|
||
|
|
console.log('\n✅ 所有模型文件验证通过!');
|
||
|
|
}
|
||
|
|
|
||
|
|
return allValid;
|
||
|
|
}
|
||
|
|
|
||
|
|
getDisplayName(name) {
|
||
|
|
const names = {
|
||
|
|
detection: '检测模型',
|
||
|
|
recognition: '识别模型',
|
||
|
|
classification: '分类模型',
|
||
|
|
keys: '字符集文件'
|
||
|
|
};
|
||
|
|
return names[name] || name;
|
||
|
|
}
|
||
|
|
|
||
|
|
validateFileSize(name, size) {
|
||
|
|
const minSizes = {
|
||
|
|
detection: 1000000, // 1MB
|
||
|
|
recognition: 5000000, // 5MB
|
||
|
|
classification: 1000000, // 1MB
|
||
|
|
keys: 1000 // 1KB
|
||
|
|
};
|
||
|
|
return size > (minSizes[name] || 0);
|
||
|
|
}
|
||
|
|
|
||
|
|
async validateKeysFile(filePath) {
|
||
|
|
try {
|
||
|
|
const content = await fs.readFile(filePath, 'utf8');
|
||
|
|
const lines = content.split('\n').filter(line => line.trim());
|
||
|
|
return lines.length > 1000; // 至少1000个字符
|
||
|
|
} catch {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
displayResults(results) {
|
||
|
|
results.forEach(result => {
|
||
|
|
const status = result.exists && result.valid ? '✅' : '❌';
|
||
|
|
const sizeInfo = result.exists ? ` (${(result.size / 1024 / 1024).toFixed(2)} MB)` : '';
|
||
|
|
console.log(`${status} ${result.name}${sizeInfo}`);
|
||
|
|
|
||
|
|
if (!result.exists) {
|
||
|
|
console.log(` 文件不存在: ${result.path}`);
|
||
|
|
} else if (!result.valid) {
|
||
|
|
console.log(` 文件可能损坏: ${result.path}`);
|
||
|
|
}
|
||
|
|
});
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// 执行验证
|
||
|
|
const validator = new ModelValidator();
|
||
|
|
validator.validateModels().catch(console.error);
|