- cpp/:liblocalllm.so NAPI 骨架(loadModel/chat/benchmark/release),预置 libMNN.so 3.6.1 鸿蒙包(已验证含 createLLM 符号;.gitignore 挡预编译库与 models/,获取方式见任务文档) - LocalLlm.ets:native 调用的 ets 封装;LlmTestPage:模型从局域网服务器下载→加载→首 token/速度 benchmark - scripts/serve-models.mjs:开发期局域网模型文件服务器(Qwen3-0.6B-MNN 456MB,SHA256 与 ModelScope 官方清单逐文件核对) - build-profile.json5 接 externalNativeOptions(arm64-v8a);ProfileContent 加「端侧LLM调试」入口(内部调试用) - docs/开发任务包/T18-端侧小模型SPIKE.md:目标/验证项/回退线;真机 benchmark 数据回来后写 T18-REPORT 三问三答
118 lines
3.7 KiB
C++
118 lines
3.7 KiB
C++
/**
|
||
* T18 端侧小模型 SPIKE · N-API 桥接
|
||
*
|
||
* ArkTS 侧用法:import localllm from 'liblocalllm.so'
|
||
* 耗时接口(loadModel/generate)一律 async work + Promise,不阻塞 UI 线程。
|
||
*/
|
||
#include "local_llm.h"
|
||
|
||
#include <napi/native_api.h>
|
||
#include <string>
|
||
|
||
namespace {
|
||
|
||
struct AsyncTask {
|
||
napi_async_work work = nullptr;
|
||
napi_deferred deferred = nullptr;
|
||
std::string arg; // loadModel: modelDir;generate: prompt
|
||
int maxNewTokens = 256; // 仅 generate 用
|
||
std::string result; // 返回值(空串或 JSON)
|
||
bool isLoad = true; // true=loadModel,false=generate
|
||
};
|
||
|
||
napi_value ResolveString(napi_env env, napi_deferred deferred, const std::string &value) {
|
||
napi_value js;
|
||
napi_create_string_utf8(env, value.c_str(), value.size(), &js);
|
||
napi_resolve_deferred(env, deferred, js);
|
||
return js;
|
||
}
|
||
|
||
void TaskExecute(napi_env /*env*/, void *data) {
|
||
auto *task = static_cast<AsyncTask *>(data);
|
||
if (task->isLoad) {
|
||
task->result = LocalLlm::instance().load(task->arg); // 空串=成功
|
||
} else {
|
||
task->result = LocalLlm::instance().generate(task->arg, task->maxNewTokens);
|
||
}
|
||
}
|
||
|
||
void TaskComplete(napi_env env, napi_status /*status*/, void *data) {
|
||
auto *task = static_cast<AsyncTask *>(data);
|
||
ResolveString(env, task->deferred, task->result);
|
||
napi_delete_async_work(env, task->work);
|
||
delete task;
|
||
}
|
||
|
||
napi_value RunAsync(napi_env env, napi_callback_info info, bool isLoad) {
|
||
size_t argc = 2;
|
||
napi_value argv[2] = {nullptr, nullptr};
|
||
napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
|
||
|
||
auto *task = new AsyncTask();
|
||
task->isLoad = isLoad;
|
||
|
||
char buf[8192];
|
||
size_t len = 0;
|
||
napi_get_value_string_utf8(env, argv[0], buf, sizeof(buf), &len);
|
||
task->arg.assign(buf, len);
|
||
if (!isLoad && argc >= 2) {
|
||
napi_get_value_int32(env, argv[1], &task->maxNewTokens);
|
||
}
|
||
|
||
napi_value promise;
|
||
napi_create_promise(env, &task->deferred, &promise);
|
||
napi_value name;
|
||
napi_create_string_utf8(env, isLoad ? "loadModel" : "generate", NAPI_AUTO_LENGTH, &name);
|
||
napi_create_async_work(env, nullptr, name, TaskExecute, TaskComplete, task, &task->work);
|
||
napi_queue_async_work(env, task->work);
|
||
return promise;
|
||
}
|
||
|
||
napi_value LoadModel(napi_env env, napi_callback_info info) {
|
||
return RunAsync(env, info, true);
|
||
}
|
||
|
||
napi_value Generate(napi_env env, napi_callback_info info) {
|
||
return RunAsync(env, info, false);
|
||
}
|
||
|
||
napi_value UnloadModel(napi_env env, napi_callback_info /*info*/) {
|
||
LocalLlm::instance().unload();
|
||
napi_value ret;
|
||
napi_get_undefined(env, &ret);
|
||
return ret;
|
||
}
|
||
|
||
napi_value IsLoaded(napi_env env, napi_callback_info /*info*/) {
|
||
napi_value ret;
|
||
napi_get_boolean(env, LocalLlm::instance().loaded(), &ret);
|
||
return ret;
|
||
}
|
||
|
||
napi_value Init(napi_env env, napi_value exports) {
|
||
napi_property_descriptor desc[] = {
|
||
{"loadModel", nullptr, LoadModel, nullptr, nullptr, nullptr, napi_default, nullptr},
|
||
{"generate", nullptr, Generate, nullptr, nullptr, nullptr, napi_default, nullptr},
|
||
{"unloadModel", nullptr, UnloadModel, nullptr, nullptr, nullptr, napi_default, nullptr},
|
||
{"isLoaded", nullptr, IsLoaded, nullptr, nullptr, nullptr, napi_default, nullptr},
|
||
};
|
||
napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
|
||
return exports;
|
||
}
|
||
|
||
} // namespace
|
||
|
||
static napi_module localllmModule = {
|
||
.nm_version = 1,
|
||
.nm_flags = 0,
|
||
.nm_filename = nullptr,
|
||
.nm_register_func = Init,
|
||
.nm_modname = "localllm",
|
||
.nm_priv = nullptr,
|
||
.reserved = {0},
|
||
};
|
||
|
||
extern "C" __attribute__((constructor)) void RegisterLocalllmModule() {
|
||
napi_module_register(&localllmModule);
|
||
}
|