mcap/modules/OCR/fetch_models.jai

76 lines
3.6 KiB
Plaintext

// Downloads the files models.config names into models/, checking each one's SHA-256. The models
// are not in git; run this after cloning. Files already there with the right hash are skipped.
//
// jai fetch_models.jai every model
// jai fetch_models.jai - mobile only the files ppocr-v5-mobile needs (about 22 MB)
//
// From RapidOCR's conversions of PaddleOCR's PP-OCRv5 (both Apache 2.0):
// https://www.modelscope.cn/models/RapidAI/RapidOCR
SOURCE :: "https://www.modelscope.cn/models/RapidAI/RapidOCR/resolve/master";
Model_File :: struct { name: string; source_path: string; sha256: string; server: bool; }
FILES :: Model_File.[
.{"ch_PP-OCRv5_det_mobile.onnx", "onnx/PP-OCRv5/det/ch_PP-OCRv5_det_mobile.onnx", "4d97c44a20d30a81aad087d6a396b08f786c4635742afc391f6621f5c6ae78ae", false},
.{"ch_PP-OCRv5_rec_mobile.onnx", "onnx/PP-OCRv5/rec/ch_PP-OCRv5_rec_mobile.onnx", "5825fc7ebf84ae7a412be049820b4d86d77620f204a041697b0494669b1742c5", false},
.{"ppocrv5_dict.txt", "paddle/PP-OCRv5/rec/ch_PP-OCRv5_rec_mobile/ppocrv5_dict.txt", "d1979e9f794c464c0d2e0b70a7fe14dd978e9dc644c0e71f14158cdf8342af1b", false},
.{"ch_PP-LCNet_x0_25_textline_ori_cls_mobile.onnx", "onnx/PP-OCRv5/cls/ch_PP-LCNet_x0_25_textline_ori_cls_mobile.onnx", "54379ae5174d026780215fc748a7f31910dee36818e63d49e17dc598ecc82df7", false},
.{"ch_PP-OCRv5_det_server.onnx", "onnx/PP-OCRv5/det/ch_PP-OCRv5_det_server.onnx", "0f8846b1d4bba223a2a2f9d9b44022fbc22cc019051a602b41a7fda9667e4cad", true},
.{"ch_PP-OCRv5_rec_server.onnx", "onnx/PP-OCRv5/rec/ch_PP-OCRv5_rec_server.onnx", "e09385400eaaaef34ceff54aeb7c4f0f1fe014c27fa8b9905d4709b65746562a", true},
];
#run,stallable { if !fetch() exit(1); }
fetch :: () -> bool {
set_build_options_dc(.{do_output = false});
mobile_only := array_find(get_build_options().compile_time_command_line, "mobile");
here := trim_right(path_strip_filename(#file), "/\\");
folder := tprint("%/models", here);
make_directory_if_it_does_not_exist(folder);
for FILES {
if mobile_only && it.server continue;
path := tprint("%/%", folder, it.name);
if file_exists(path) && sha256_of(path) == it.sha256 { log("% is already here.", it.name); continue; }
url := tprint("%/%", SOURCE, it.source_path);
log("Downloading %...", url);
result := run_command("curl", "-L", "--fail", "--progress-bar", "-o", path, url);
if result.exit_code != 0 { log_error("curl failed for % (exit code %).", it.name, result.exit_code); return false; }
hash := sha256_of(path);
if hash != it.sha256 {
log_error("% has SHA-256 %, expected %; it was deleted.", it.name, hash, it.sha256);
file_delete(path);
return false;
}
}
log("The models are in %.", folder);
return true;
}
// Lowercase hex, or "" when it could not be worked out.
sha256_of :: (path: string) -> string {
#if OS == .WINDOWS {
result, output := run_command("certutil", "-hashfile", path, "SHA256", capture_and_return_output = true);
if result.exit_code != 0 return "";
lines := split(output, "\n");
if lines.count < 2 return "";
return to_lower_copy(replace(trim(lines[1]), " ", "")); // line 2 is the hash
} else {
#if OS == .MACOS command := string.["shasum", "-a", "256", path];
else command := string.["sha256sum", path];
result, output := run_command(..command, capture_and_return_output = true);
if result.exit_code != 0 return "";
return to_lower_copy(trim(split(output, " ")[0]));
}
}
#import "Basic";
#import "Compiler";
#import "File";
#import "File_Utilities";
#import "Process";
#import "String";