Compare commits

3 Commits
1.0.6 ... main

Author SHA1 Message Date
2d98a1c764 完善预编译插件自动下载工具 2025-03-21 12:40:49 +08:00
aab09dbb86 更新版本号 2025-03-21 08:53:37 +08:00
6cdf4cbcd6 增加下载工具 2025-03-20 18:24:12 +08:00
13 changed files with 124 additions and 10 deletions

View File

@ -38,6 +38,20 @@ if(CMAKE_JS_RESULT EQUAL 0)
)
endif()
# ReleaseVersion
if(CMAKE_JS_RESULT EQUAL 0)
execute_process(
COMMAND node ${CMAKE_SOURCE_DIR}/thirdpart/cmake-js-util.js --release
RESULT_VARIABLE CMAKE_JS_RESULT
OUTPUT_VARIABLE RELEASE_VERSION
OUTPUT_STRIP_TRAILING_WHITESPACE
)
if(CMAKE_JS_RESULT EQUAL 0)
message(STATUS "RELEASE_VERSION: ${RELEASE_VERSION}")
add_compile_definitions(RELEASE_VERSION="${RELEASE_VERSION}")
endif()
endif()
# NAPI
if(CMAKE_JS_RESULT EQUAL 0)
execute_process(

View File

@ -237,6 +237,9 @@ void InstallMNNAPI(Napi::Env env, Napi::Object exports)
#if defined(USE_MNN) && !defined(BUILD_MAIN_WORD)
static Object Init(Env env, Object exports)
{
#ifdef RELEASE_VERSION
exports.Set("__release__", Napi::String::New(env, RELEASE_VERSION));
#endif
InstallMNNAPI(env, exports);
return exports;
}

View File

@ -7,6 +7,9 @@ using namespace Napi;
#if defined(BUILD_MAIN_WORD)
Object Init(Env env, Object exports)
{
#ifdef RELEASE_VERSION
exports.Set("__release__", Napi::String::New(env, RELEASE_VERSION));
#endif
// OnnxRuntime
#ifdef USE_ONNXRUNTIME
InstallOrtAPI(env, exports);

View File

@ -308,6 +308,9 @@ void InstallOrtAPI(Napi::Env env, Napi::Object exports)
#if defined(USE_ONNXRUNTIME) && !defined(BUILD_MAIN_WORD)
static Object Init(Env env, Object exports)
{
#ifdef RELEASE_VERSION
exports.Set("__release__", Napi::String::New(env, RELEASE_VERSION));
#endif
InstallOrtAPI(env, exports);
return exports;
}

View File

@ -1,6 +1,6 @@
{
"name": "@yizhi/ai",
"version": "1.0.6",
"version": "1.0.8",
"releaseVersion": "1.0.6",
"main": "dist/index.js",
"types": "typing/index.d.ts",

View File

@ -1,6 +1,6 @@
import path from "path";
const defaultAddonDir = path.join(__dirname, "../build")
const defaultAddonDir = path.join(__dirname, "../../build")
const aiConfig = {
"MNN_ADDON_FILE": path.join(defaultAddonDir, "mnn.node"),

87
src/backend/download.ts Normal file
View File

@ -0,0 +1,87 @@
import os from "os";
import fs from "fs";
import path from "path";
import { getConfig } from "./config";
const URLS = {
GITHUB: "https://github.com/kangkang520/node-addons/releases/download/ai{{version}}/{{filename}}",
XXXXX: "http://git.urnas.cn:5200/yizhi-js-lib/ai-box/releases/download/{{version}}/{{filename}}",
}
function releaseVersion() { return require("../../package.json").releaseVersion }
function getURL(backend: "ort" | "mnn", template: string) {
const URL_DICT: Record<string, Record<string, string>> = {
"win32": {
"x64": `${backend}_windows_x64.node`
},
"linux": {
"x64": `${backend}_linux_x64.node`,
"arm64": `${backend}_linux_arm64.node`,
},
"darwin": {
"arm64": `${backend}_macos_arm64.node`,
}
}
const archConfig = URL_DICT[os.platform()];
if (!archConfig) throw new Error(`Unsupported platform: ${os.platform()}`);
const downloadName = archConfig[os.arch()];
if (!downloadName) throw new Error(`Unsupported arch: ${os.arch()}`);
return template.replaceAll("{{version}}", releaseVersion()).replaceAll("{{filename}}", downloadName);
}
async function getStream(backend: "mnn" | "ort") {
for (const [name, url] of Object.entries(URLS)) {
try {
return await fetch(getURL(backend, url)).then(res => {
if (res.status != 200) throw new Error("Failed to download addon.");
return res.blob().then(b => b.stream());
})
} catch (e) { }
}
throw new Error("Failed to download addon.");
}
export async function downloadBackend(backend: "ort" | "mnn", savename?: string) {
const backendConfigNameDict = { ort: "ORT_ADDON_FILE" as const, mnn: "MNN_ADDON_FILE" as const };
const defaultAddon = path.resolve(process.cwd(), getConfig(backendConfigNameDict[backend]));
const saveName = savename ? path.resolve(path.dirname(defaultAddon), savename) : defaultAddon;
if (fs.existsSync(saveName)) {
try {
const addon = require(saveName);
if (addon.__release__ === releaseVersion()) return saveName;
//清除缓存
delete require.cache[saveName];
} catch (err) { }
}
await fs.promises.mkdir(path.dirname(saveName), { recursive: true });
const stream = await getStream(backend);
const cacheFile = await new Promise<string>((resolve, reject) => {
const cacheFile = path.join(os.tmpdir(), Date.now() + ".cv.node");
let fsStream!: ReturnType<typeof fs.createWriteStream>;
stream.pipeTo(new WritableStream({
start(controller) {
fsStream = fs.createWriteStream(cacheFile);
},
async write(chunk, controller) {
await new Promise<void>((resolve, reject) => fsStream.write(chunk, err => err ? reject(err) : resolve()));
},
close() {
fsStream.end();
resolve(cacheFile);
},
abort() { }
})).catch(reject);
});
if (fs.existsSync(saveName)) await fs.promises.rm(saveName, { recursive: true, force: true });
await fs.promises.cp(cacheFile, saveName);
await fs.promises.rm(cacheFile);
return saveName;
}

View File

@ -1,3 +1,4 @@
export { SessionNodeInfo, DataTypeString, DataType, SessionNodeData, SessionRunInputOption, SessionRunOutput, CommonSession } from "./common";
export * as ort from "./ort";
export * as mnn from "./mnn";
export { downloadBackend } from "./download";

View File

@ -1,4 +1,4 @@
import { getConfig } from "../../config";
import { getConfig } from "../config";
import { CommonSession, dataTypeFrom, isTypedArray, SessionNodeData, SessionNodeInfo, SessionRunInputOption, SessionRunOutput } from "../common";
export class MNNSession extends CommonSession {

View File

@ -1,4 +1,4 @@
import { getConfig } from "../../config";
import { getConfig } from "../config";
import { CommonSession, dataTypeFrom, isTypedArray, SessionNodeData, SessionNodeInfo, SessionRunInputOption, SessionRunOutput } from "../common";
export class OrtSession extends CommonSession {

View File

@ -1,3 +1,3 @@
export { deploy } from "./deploy";
export { backend } from "./backend";
export { setConfig as config } from "./config";
export { setConfig as config } from "./backend/config";

View File

@ -4,6 +4,7 @@ import { deploy } from "./deploy";
import { faceidTestData } from "./test_data/faceid";
import path from "path";
import crypto from "crypto";
import ai from ".";
cv.config("ADDON_PATH", path.join(__dirname, "../build/cv.node"));
@ -152,9 +153,10 @@ async function testFaceAlign() {
}
async function test() {
await testGenderTest();
await testFaceID();
await testFaceAlign();
await ai.backend.downloadBackend("ort");
// await testGenderTest();
// await testFaceID();
// await testFaceAlign();
}
test().catch(err => {

View File

@ -16,3 +16,4 @@ if (args.includes("--include")) runCmakeJS(["print-cmakejs-include"]);
else if (args.includes("--src")) runCmakeJS(["print-cmakejs-src"]);
else if (args.includes("--lib")) runCmakeJS(["print-cmakejs-lib"]);
else if (args.includes("--napi")) console.log(require("node-addon-api").include.replace(/^"/, "").replace(/"$/, ""));
else if (args.includes("--release")) console.log(require("../package.json").releaseVersion);