- 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 三问三答
52 lines
1.8 KiB
JavaScript
52 lines
1.8 KiB
JavaScript
#!/usr/bin/env node
|
||
/**
|
||
* T18 调试期局域网模型服务器(零依赖,Node 18+)。
|
||
*
|
||
* 用法:node scripts/serve-models.mjs [端口=8080]
|
||
* 手机与电脑连同一 Wi-Fi,App 内模型地址填 http://<电脑局域网IP>:<端口>
|
||
*
|
||
* 服务内容:models/ 目录下的 manifest.json 与模型文件。
|
||
* 调试阶段一次性整包下载即可;断点续传(Range)留待商用阶段接 CDN 时再做。
|
||
*/
|
||
import { createServer } from 'node:http';
|
||
import { createReadStream, existsSync, statSync } from 'node:fs';
|
||
import { networkInterfaces } from 'node:os';
|
||
import { extname, join, normalize } from 'node:path';
|
||
import { fileURLToPath } from 'node:url';
|
||
|
||
const root = normalize(join(fileURLToPath(import.meta.url), '..', '..', 'models'));
|
||
const port = Number(process.argv[2] ?? 8080);
|
||
|
||
const MIME = {
|
||
'.json': 'application/json; charset=utf-8',
|
||
'.txt': 'text/plain; charset=utf-8',
|
||
'.mnn': 'application/octet-stream',
|
||
'.weight': 'application/octet-stream',
|
||
};
|
||
|
||
const server = createServer((req, res) => {
|
||
const urlPath = decodeURIComponent((req.url ?? '/').split('?')[0]);
|
||
// 防目录穿越:规范化后必须仍落在 root 内
|
||
const filePath = normalize(join(root, urlPath));
|
||
if (!filePath.startsWith(root) || !existsSync(filePath) || !statSync(filePath).isFile()) {
|
||
res.writeHead(404).end('not found');
|
||
return;
|
||
}
|
||
res.writeHead(200, {
|
||
'Content-Type': MIME[extname(filePath)] ?? 'application/octet-stream',
|
||
'Content-Length': statSync(filePath).size,
|
||
});
|
||
createReadStream(filePath).pipe(res);
|
||
});
|
||
|
||
server.listen(port, '0.0.0.0', () => {
|
||
console.log(`serving ${root}`);
|
||
for (const [name, addrs] of Object.entries(networkInterfaces())) {
|
||
for (const a of addrs ?? []) {
|
||
if (a.family === 'IPv4' && !a.internal) {
|
||
console.log(` http://${a.address}:${port}/ (${name})`);
|
||
}
|
||
}
|
||
}
|
||
});
|