@ariacompute/engine-ts 1.22.0 → 2.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -30
- package/dist/index.d.ts +9 -110
- package/dist/index.js +48 -636
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -1,35 +1,10 @@
|
|
|
1
1
|
# @ariacompute/engine-ts
|
|
2
2
|
|
|
3
|
-
```bash
|
|
4
|
-
npm i @ariacompute/engine-ts
|
|
5
|
-
```
|
|
6
|
-
|
|
7
|
-
`libaria_ffi` is resolved as `ARIA_FFI_LIB` → package-bundled `dist/lib/` → `~/.ariacompute/lib/` (same as `aria-engine upgrade`). If none exist, `Engine.open` downloads the latest stable `libaria_ffi_{ver}_{os}.tar.gz` from regional Releases. `ARIA_FFI_LIB` remains an optional override.
|
|
8
|
-
|
|
9
3
|
```ts
|
|
10
|
-
import {
|
|
11
|
-
const eng = new
|
|
12
|
-
|
|
13
|
-
eng.
|
|
4
|
+
import { AriaEngine } from "@ariacompute/engine-ts";
|
|
5
|
+
const eng = new AriaEngine("/path/to/checkpoint", "encoder");
|
|
6
|
+
const resp = eng.systemone({ state: {}, questions: { q1: { type: "noul", instructions: "ok?", criteria: {} } } });
|
|
7
|
+
eng.destroy();
|
|
14
8
|
```
|
|
15
9
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
`Engine.open(modelRef, { token, site })` accepts a local bundle path **or** an
|
|
19
|
-
Aria model name (e.g. `gemma-4-e2b-it_q4`). A value containing `/` or already on
|
|
20
|
-
disk is loaded directly; otherwise the SDK downloads it from the regional public
|
|
21
|
-
hub (same as `aria-engine download`: `.com` → Hugging Face, `.cn` → ModelScope;
|
|
22
|
-
`site` defaults to `https://ariacompute.com`) into `~/.ariacompute/models/{model}`
|
|
23
|
-
and then loads it. Dashboard is not used. A Dashboard `sk-` / `sk-bf-` token is
|
|
24
|
-
ignored for hub auth. Token is optional for public models. A valid cached bundle
|
|
25
|
-
is reused without re-downloading.
|
|
26
|
-
|
|
27
|
-
Gated files: call `eng.setup({ hf_token })` (`.com`) or `eng.setup({ modelscope_api_token, site_url })` (`.cn`) **before** `open`. Same keys as `aria-engine setup`. Instance-only; does not write `engine.yml`. If omitted, the SDK reads `~/.ariacompute/engine.yml`.
|
|
28
|
-
|
|
29
|
-
```ts
|
|
30
|
-
const eng = await Engine.open("gemma-4-e2b-it_q4");
|
|
31
|
-
|
|
32
|
-
const gated = new Engine();
|
|
33
|
-
gated.setup({ hf_token: "hf_..." });
|
|
34
|
-
await gated.open("gemma-4-e2b-it_q4");
|
|
35
|
-
```
|
|
10
|
+
Requires `libaria-engine_ffi` via `aria-engine upgrade` or `ARIA_FFI_LIB`.
|
package/dist/index.d.ts
CHANGED
|
@@ -1,112 +1,11 @@
|
|
|
1
|
-
export
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
stop?: string[];
|
|
7
|
-
response_format?: {
|
|
8
|
-
type: "text" | "json_object" | "json_schema";
|
|
9
|
-
json_schema?: unknown;
|
|
10
|
-
};
|
|
11
|
-
}
|
|
12
|
-
export interface Turn {
|
|
13
|
-
role: "system" | "user" | "assistant";
|
|
14
|
-
content: string;
|
|
15
|
-
}
|
|
16
|
-
export interface Generation {
|
|
17
|
-
success: boolean;
|
|
18
|
-
response: string;
|
|
19
|
-
error?: string;
|
|
20
|
-
tokens_used?: number;
|
|
21
|
-
finish_reason?: string;
|
|
22
|
-
}
|
|
23
|
-
export interface CompleteResult {
|
|
24
|
-
success: boolean;
|
|
25
|
-
response: string;
|
|
26
|
-
error?: string;
|
|
27
|
-
generation?: Generation;
|
|
28
|
-
}
|
|
29
|
-
export interface OpenOptions {
|
|
30
|
-
/** Legacy generic hub token. Dashboard sk-/sk-bf- keys are ignored. */
|
|
31
|
-
token?: string;
|
|
32
|
-
/** Hugging Face hub token (`.com`). Same field as `aria-engine setup` `hf_token`. */
|
|
33
|
-
hfToken?: string;
|
|
34
|
-
/** ModelScope hub token (`.cn`). Same field as `aria-engine setup` `modelscope_api_token`. */
|
|
35
|
-
modelscopeApiToken?: string;
|
|
36
|
-
/** Site used to pick the regional hub. Defaults to https://ariacompute.com (.com → HF, .cn → ModelScope). */
|
|
37
|
-
site?: string;
|
|
38
|
-
/** Explicit path to the FFI library. */
|
|
39
|
-
ffiLib?: string;
|
|
40
|
-
}
|
|
41
|
-
export declare const INTL_SITE = "https://ariacompute.com";
|
|
42
|
-
export declare const INTL_UPGRADE = "https://github.com/ariacompute";
|
|
43
|
-
export declare const CN_SITE = "https://ariacompute.cn";
|
|
44
|
-
export declare const CN_UPGRADE = "https://gitee.com/ariacompute";
|
|
45
|
-
export interface SetupConfig {
|
|
46
|
-
router: string;
|
|
47
|
-
/** sk-aria_ or sk-bf-; router associates by prefix */
|
|
48
|
-
router_api_key: string;
|
|
49
|
-
site_url: string;
|
|
50
|
-
upgrade_url: string;
|
|
51
|
-
compute: string;
|
|
52
|
-
hf_token: string;
|
|
53
|
-
modelscope_api_token: string;
|
|
54
|
-
}
|
|
55
|
-
export declare function defaultSetupConfig(): SetupConfig;
|
|
56
|
-
export declare function fillSetupUrls(cfg: SetupConfig): SetupConfig;
|
|
57
|
-
export declare function applySetup(existing: SetupConfig, updates: Partial<SetupConfig>): SetupConfig;
|
|
58
|
-
/** Parse `slug`/`quant` from a model name such as `gemma-4-e2b-it_q4`. */
|
|
59
|
-
export declare function parseBundleName(model: string): {
|
|
60
|
-
slug: string;
|
|
61
|
-
quant: string;
|
|
62
|
-
};
|
|
63
|
-
export declare function preferredPublicHub(site?: string): "huggingface" | "modelscope";
|
|
64
|
-
export declare function hubBearer(token?: string): string | undefined;
|
|
65
|
-
export declare function configYmlScalar(key: string): string | undefined;
|
|
66
|
-
export declare function resolveHubToken(source: "huggingface" | "modelscope", opts?: Pick<OpenOptions, "token" | "hfToken" | "modelscopeApiToken">): string | undefined;
|
|
67
|
-
export declare function hubFileUrls(source: "huggingface" | "modelscope", model: string, file: string, sdk?: string): string[];
|
|
68
|
-
/** Download `model` from the regional public hub into
|
|
69
|
-
* `~/.ariacompute/models/{model}` and return that directory.
|
|
70
|
-
* Matches aria-engine download: .com → Hugging Face, .cn → ModelScope.
|
|
71
|
-
* Dashboard is not used. Skips the download when a valid bundle is already cached. */
|
|
72
|
-
export declare function downloadModel(model: string, tokenOrOpts?: string | OpenOptions, site?: string): Promise<string>;
|
|
73
|
-
export declare function ffiLibName(platform?: string): string;
|
|
74
|
-
export declare function cachedFfiPath(platform?: string): string | undefined;
|
|
75
|
-
export declare function ffiAssetOs(platform?: string, arch?: string): string;
|
|
76
|
-
export declare function selectLatestStable(releases: Array<Record<string, unknown>>): string;
|
|
77
|
-
export declare function extractFfiArchive(archive: string, destDir: string, want?: string): string;
|
|
78
|
-
/** Return a path to libaria-engine_ffi, downloading the latest stable Release if needed. */
|
|
79
|
-
export declare function ensureFfiLib(site?: string): Promise<string>;
|
|
80
|
-
export declare function isLocalRef(modelRef: string): boolean;
|
|
81
|
-
export declare class Engine {
|
|
82
|
-
private lib;
|
|
1
|
+
export type Track = "encoder" | "decoder";
|
|
2
|
+
/** Load koffi binding when native lib is present; otherwise throw with install hint. */
|
|
3
|
+
export declare function loadFfi(): any;
|
|
4
|
+
export declare class AriaEngine {
|
|
5
|
+
private ffi;
|
|
83
6
|
private handle;
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
private fnEmbed;
|
|
88
|
-
private fnTranscribe;
|
|
89
|
-
private fnLastError;
|
|
90
|
-
private cfg;
|
|
91
|
-
private opts;
|
|
92
|
-
/** Empty construct, or a local bundle directory. */
|
|
93
|
-
constructor(bundle?: string, opts?: OpenOptions);
|
|
94
|
-
/** Set Config / Run fields on this instance only. Does not write engine.yml. */
|
|
95
|
-
setup(updates: Partial<SetupConfig>): this;
|
|
96
|
-
setupStatus(): SetupConfig;
|
|
97
|
-
/** Reset instance defaults. Does not delete ~/.ariacompute/engine.yml. */
|
|
98
|
-
setupClear(): this;
|
|
99
|
-
private bindAndInit;
|
|
100
|
-
/** Download (if needed) and load a model using instance setup. */
|
|
101
|
-
open(modelRef: string): Promise<this>;
|
|
102
|
-
/** Auto-detect: a value containing a separator or already on disk is a local
|
|
103
|
-
* path; otherwise it is a model name downloaded from the regional public hub. */
|
|
104
|
-
static open(modelRef: string, opts?: OpenOptions): Promise<Engine>;
|
|
105
|
-
complete(messages: Turn[], opts?: GenerateOptions): CompleteResult;
|
|
106
|
-
embed(text: string): number[];
|
|
107
|
-
transcribe(pcm: Uint8Array): string;
|
|
108
|
-
close(): void;
|
|
7
|
+
constructor(checkpoint: string, track?: Track);
|
|
8
|
+
systemone(request: object): object;
|
|
9
|
+
destroy(): void;
|
|
109
10
|
}
|
|
110
|
-
export
|
|
111
|
-
encoder: TextEncoder;
|
|
112
|
-
};
|
|
11
|
+
export default AriaEngine;
|
package/dist/index.js
CHANGED
|
@@ -33,654 +33,66 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.
|
|
37
|
-
exports.
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
exports.preferredPublicHub = preferredPublicHub;
|
|
42
|
-
exports.hubBearer = hubBearer;
|
|
43
|
-
exports.configYmlScalar = configYmlScalar;
|
|
44
|
-
exports.resolveHubToken = resolveHubToken;
|
|
45
|
-
exports.hubFileUrls = hubFileUrls;
|
|
46
|
-
exports.downloadModel = downloadModel;
|
|
47
|
-
exports.ffiLibName = ffiLibName;
|
|
48
|
-
exports.cachedFfiPath = cachedFfiPath;
|
|
49
|
-
exports.ffiAssetOs = ffiAssetOs;
|
|
50
|
-
exports.selectLatestStable = selectLatestStable;
|
|
51
|
-
exports.extractFfiArchive = extractFfiArchive;
|
|
52
|
-
exports.ensureFfiLib = ensureFfiLib;
|
|
53
|
-
exports.isLocalRef = isLocalRef;
|
|
54
|
-
const node_child_process_1 = require("node:child_process");
|
|
55
|
-
const fs = __importStar(require("node:fs"));
|
|
56
|
-
const os = __importStar(require("node:os"));
|
|
57
|
-
const path = __importStar(require("node:path"));
|
|
58
|
-
const promises_1 = require("node:stream/promises");
|
|
59
|
-
const node_stream_1 = require("node:stream");
|
|
60
|
-
const zlib = __importStar(require("node:zlib"));
|
|
61
|
-
const DEFAULT_SITE = "https://ariacompute.com";
|
|
62
|
-
exports.INTL_SITE = "https://ariacompute.com";
|
|
63
|
-
exports.INTL_UPGRADE = "https://github.com/ariacompute";
|
|
64
|
-
exports.CN_SITE = "https://ariacompute.cn";
|
|
65
|
-
exports.CN_UPGRADE = "https://gitee.com/ariacompute";
|
|
66
|
-
function defaultSetupConfig() {
|
|
67
|
-
return {
|
|
68
|
-
router: "",
|
|
69
|
-
router_api_key: "",
|
|
70
|
-
site_url: "",
|
|
71
|
-
upgrade_url: "",
|
|
72
|
-
compute: "auto",
|
|
73
|
-
hf_token: "",
|
|
74
|
-
modelscope_api_token: "",
|
|
75
|
-
};
|
|
76
|
-
}
|
|
77
|
-
function gatewayRegion(url) {
|
|
78
|
-
const lower = (url || "").toLowerCase();
|
|
79
|
-
if (lower.includes("ariacompute.cn") || lower.includes("gitee.com/ariacompute"))
|
|
80
|
-
return "cn";
|
|
81
|
-
if (lower.includes("ariacompute.com") || lower.includes("github.com/ariacompute"))
|
|
82
|
-
return "intl";
|
|
83
|
-
return undefined;
|
|
84
|
-
}
|
|
85
|
-
function pairUrls(region) {
|
|
86
|
-
return region === "cn" ? [exports.CN_SITE, exports.CN_UPGRADE] : [exports.INTL_SITE, exports.INTL_UPGRADE];
|
|
87
|
-
}
|
|
88
|
-
function fillSetupUrls(cfg) {
|
|
89
|
-
const out = { ...cfg };
|
|
90
|
-
const region = gatewayRegion(out.site_url) || gatewayRegion(out.upgrade_url);
|
|
91
|
-
if (!region)
|
|
92
|
-
return out;
|
|
93
|
-
const [site, upgrade] = pairUrls(region);
|
|
94
|
-
if (!out.site_url)
|
|
95
|
-
out.site_url = site;
|
|
96
|
-
if (!out.upgrade_url)
|
|
97
|
-
out.upgrade_url = upgrade;
|
|
98
|
-
return out;
|
|
99
|
-
}
|
|
100
|
-
function validateRouterApiKey(key) {
|
|
101
|
-
const t = (key || "").trim();
|
|
102
|
-
if (!t)
|
|
103
|
-
return;
|
|
104
|
-
if (t.startsWith("sk-aria_") || t.startsWith("sk-bf-"))
|
|
105
|
-
return;
|
|
106
|
-
throw new Error("router_api_key must start with sk-aria_ or sk-bf-");
|
|
107
|
-
}
|
|
108
|
-
function applySetup(existing, updates) {
|
|
109
|
-
const out = { ...existing };
|
|
110
|
-
for (const [k, v] of Object.entries(updates)) {
|
|
111
|
-
if (v === undefined)
|
|
112
|
-
continue;
|
|
113
|
-
out[k] = v;
|
|
114
|
-
}
|
|
115
|
-
if (!["auto", "cpu", "cuda"].includes(out.compute)) {
|
|
116
|
-
throw new Error(`invalid compute: ${out.compute}`);
|
|
117
|
-
}
|
|
118
|
-
validateRouterApiKey(out.router_api_key);
|
|
119
|
-
return fillSetupUrls(out);
|
|
120
|
-
}
|
|
121
|
-
const DEFAULT_SDK = "v1.0";
|
|
122
|
-
const HUB_REQUIRED = ["config.json", "weight.bin"];
|
|
123
|
-
const HUB_OPTIONAL = [
|
|
124
|
-
"tokenizer.json",
|
|
125
|
-
"tokenizer.model",
|
|
126
|
-
"tokenizer_config.json",
|
|
127
|
-
"special_tokens_map.json",
|
|
128
|
-
"vocab.json",
|
|
129
|
-
"merges.txt",
|
|
130
|
-
];
|
|
36
|
+
exports.AriaEngine = void 0;
|
|
37
|
+
exports.loadFfi = loadFfi;
|
|
38
|
+
const fs = __importStar(require("fs"));
|
|
39
|
+
const os = __importStar(require("os"));
|
|
40
|
+
const path = __importStar(require("path"));
|
|
131
41
|
function ariaHome() {
|
|
132
42
|
return process.env.ARIA_COMPUTE_HOME || path.join(os.homedir(), ".ariacompute");
|
|
133
43
|
}
|
|
134
|
-
function
|
|
135
|
-
return path.join(ariaHome(), "models", model);
|
|
136
|
-
}
|
|
137
|
-
/** Parse `slug`/`quant` from a model name such as `gemma-4-e2b-it_q4`. */
|
|
138
|
-
function parseBundleName(model) {
|
|
139
|
-
if (!model || model.includes("/") || model.includes("\\")) {
|
|
140
|
-
throw new Error(`invalid model name: ${model}`);
|
|
141
|
-
}
|
|
142
|
-
const idx = model.lastIndexOf("_q");
|
|
143
|
-
if (idx !== -1) {
|
|
144
|
-
const slug = model.slice(0, idx);
|
|
145
|
-
let suffix = model.slice(idx + 2);
|
|
146
|
-
if (suffix.endsWith("_channel") || suffix.endsWith("_group")) {
|
|
147
|
-
suffix = suffix.slice(0, suffix.lastIndexOf("_"));
|
|
148
|
-
}
|
|
149
|
-
const quant = suffix === "4"
|
|
150
|
-
? "int4"
|
|
151
|
-
: suffix === "8"
|
|
152
|
-
? "int8"
|
|
153
|
-
: suffix === "326" || suffix === "3.26"
|
|
154
|
-
? "int326"
|
|
155
|
-
: (() => {
|
|
156
|
-
throw new Error(`unknown quant suffix _q${suffix}`);
|
|
157
|
-
})();
|
|
158
|
-
if (!slug)
|
|
159
|
-
throw new Error(`invalid model name: ${model}`);
|
|
160
|
-
return { slug, quant };
|
|
161
|
-
}
|
|
162
|
-
return { slug: model, quant: "int4" };
|
|
163
|
-
}
|
|
164
|
-
function isValidBundle(dir) {
|
|
165
|
-
try {
|
|
166
|
-
if (!fs.statSync(path.join(dir, "weight.bin")).isFile())
|
|
167
|
-
return false;
|
|
168
|
-
const meta = JSON.parse(fs.readFileSync(path.join(dir, "config.json"), "utf8"));
|
|
169
|
-
return meta.format === "aria-quant-bundle";
|
|
170
|
-
}
|
|
171
|
-
catch {
|
|
172
|
-
return false;
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
function preferredPublicHub(site) {
|
|
176
|
-
if (site && site.toLowerCase().includes("ariacompute.cn"))
|
|
177
|
-
return "modelscope";
|
|
178
|
-
return "huggingface";
|
|
179
|
-
}
|
|
180
|
-
function hubBearer(token) {
|
|
181
|
-
const t = (token || "").trim();
|
|
182
|
-
if (!t)
|
|
183
|
-
return undefined;
|
|
184
|
-
const low = t.toLowerCase();
|
|
185
|
-
if (low.startsWith("sk-"))
|
|
186
|
-
return undefined;
|
|
187
|
-
return t;
|
|
188
|
-
}
|
|
189
|
-
function unquoteYaml(v) {
|
|
190
|
-
const t = v.trim();
|
|
191
|
-
if (t.length >= 2 && ((t.startsWith('"') && t.endsWith('"')) || (t.startsWith("'") && t.endsWith("'")))) {
|
|
192
|
-
return t.slice(1, -1);
|
|
193
|
-
}
|
|
194
|
-
return t;
|
|
195
|
-
}
|
|
196
|
-
function configYmlScalar(key) {
|
|
197
|
-
const home = ariaHome();
|
|
198
|
-
for (const name of ["engine.yml", "config.yml"]) {
|
|
199
|
-
try {
|
|
200
|
-
const raw = fs.readFileSync(path.join(home, name), "utf8");
|
|
201
|
-
for (const line of raw.split("\n")) {
|
|
202
|
-
if (line.startsWith(" ") || line.startsWith("\t"))
|
|
203
|
-
continue;
|
|
204
|
-
const s = line.trim();
|
|
205
|
-
if (!s || s.startsWith("#") || !s.includes(":"))
|
|
206
|
-
continue;
|
|
207
|
-
const idx = s.indexOf(":");
|
|
208
|
-
if (s.slice(0, idx).trim() !== key)
|
|
209
|
-
continue;
|
|
210
|
-
const v = unquoteYaml(s.slice(idx + 1));
|
|
211
|
-
if (v)
|
|
212
|
-
return v;
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
catch {
|
|
216
|
-
continue;
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
return undefined;
|
|
220
|
-
}
|
|
221
|
-
function resolveHubToken(source, opts = {}) {
|
|
222
|
-
const named = source === "modelscope" ? opts.modelscopeApiToken : opts.hfToken;
|
|
223
|
-
const field = source === "modelscope" ? "modelscope_api_token" : "hf_token";
|
|
224
|
-
for (const cand of [named, opts.token, configYmlScalar(field)]) {
|
|
225
|
-
const b = hubBearer(cand);
|
|
226
|
-
if (b)
|
|
227
|
-
return b;
|
|
228
|
-
}
|
|
229
|
-
return undefined;
|
|
230
|
-
}
|
|
231
|
-
function hubPathNames(model) {
|
|
232
|
-
const names = [model];
|
|
233
|
-
let lower = model.toLowerCase();
|
|
234
|
-
let core = model;
|
|
235
|
-
for (const suf of ["_channel", "_group"]) {
|
|
236
|
-
if (lower.endsWith(suf)) {
|
|
237
|
-
core = model.slice(0, -suf.length);
|
|
238
|
-
lower = core.toLowerCase();
|
|
239
|
-
break;
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
const stems = [core];
|
|
243
|
-
if (lower.endsWith("_q326"))
|
|
244
|
-
stems.push(`${core.slice(0, -5)}q3.26`);
|
|
245
|
-
else if (lower.endsWith("_q3.26"))
|
|
246
|
-
stems.push(`${core.slice(0, -6)}q326`);
|
|
247
|
-
for (const stem of stems) {
|
|
248
|
-
for (const share of ["", "_channel", "_group"]) {
|
|
249
|
-
const cand = `${stem}${share}`;
|
|
250
|
-
if (!names.includes(cand))
|
|
251
|
-
names.push(cand);
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
return names;
|
|
255
|
-
}
|
|
256
|
-
function hubFileUrls(source, model, file, sdk = DEFAULT_SDK) {
|
|
257
|
-
const urls = [];
|
|
258
|
-
for (const name of hubPathNames(model)) {
|
|
259
|
-
if (source === "modelscope") {
|
|
260
|
-
for (const repo of [`AriaCompute/${name}`, "AriaCompute/model"]) {
|
|
261
|
-
urls.push(`https://www.modelscope.cn/models/${repo}/resolve/master/${sdk}/${name}/${file}`);
|
|
262
|
-
urls.push(`https://modelscope.cn/models/${repo}/resolve/master/${sdk}/${name}/${file}`);
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
else {
|
|
266
|
-
for (const repo of [`ariacompute/${name}`, "ariacompute/model"]) {
|
|
267
|
-
urls.push(`https://huggingface.co/${repo}/resolve/main/${sdk}/${name}/${file}`);
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
return urls;
|
|
272
|
-
}
|
|
273
|
-
class HubHttpError extends Error {
|
|
274
|
-
constructor(status, message) {
|
|
275
|
-
super(message);
|
|
276
|
-
this.status = status;
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
async function fetchUrlToFile(url, dest, token) {
|
|
280
|
-
const headers = {};
|
|
281
|
-
if (token)
|
|
282
|
-
headers.Authorization = `Bearer ${token}`;
|
|
283
|
-
const resp = await fetch(url, { headers });
|
|
284
|
-
if (resp.status === 401 || resp.status === 403) {
|
|
285
|
-
throw new HubHttpError(resp.status, `HTTP ${resp.status}`);
|
|
286
|
-
}
|
|
287
|
-
if (!resp.ok)
|
|
288
|
-
throw new HubHttpError(resp.status, `HTTP ${resp.status}`);
|
|
289
|
-
if (!resp.body)
|
|
290
|
-
throw new Error("empty response body");
|
|
291
|
-
fs.mkdirSync(path.dirname(dest), { recursive: true });
|
|
292
|
-
await (0, promises_1.pipeline)(node_stream_1.Readable.fromWeb(resp.body), fs.createWriteStream(dest));
|
|
293
|
-
}
|
|
294
|
-
async function fetchHubFile(source, model, file, dest, token, required) {
|
|
295
|
-
let last;
|
|
296
|
-
for (const url of hubFileUrls(source, model, file)) {
|
|
297
|
-
try {
|
|
298
|
-
await fetchUrlToFile(url, dest, token);
|
|
299
|
-
return true;
|
|
300
|
-
}
|
|
301
|
-
catch (e) {
|
|
302
|
-
last = e;
|
|
303
|
-
if (e instanceof HubHttpError && (e.status === 401 || e.status === 403)) {
|
|
304
|
-
const field = source === "modelscope" ? "modelscope_api_token" : "hf_token";
|
|
305
|
-
throw new Error(`auth failed HTTP ${e.status}; set ${field} via aria-engine setup (do not pass a Dashboard sk-/sk-bf- key as the hub token)`);
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
if (required)
|
|
310
|
-
throw new Error(`${source}: missing ${file}${last ? `: ${last}` : ""}`);
|
|
311
|
-
return false;
|
|
312
|
-
}
|
|
313
|
-
const encoder = new TextEncoder();
|
|
314
|
-
/** Download `model` from the regional public hub into
|
|
315
|
-
* `~/.ariacompute/models/{model}` and return that directory.
|
|
316
|
-
* Matches aria-engine download: .com → Hugging Face, .cn → ModelScope.
|
|
317
|
-
* Dashboard is not used. Skips the download when a valid bundle is already cached. */
|
|
318
|
-
async function downloadModel(model, tokenOrOpts, site = DEFAULT_SITE) {
|
|
319
|
-
const opts = tokenOrOpts && typeof tokenOrOpts === "object"
|
|
320
|
-
? tokenOrOpts
|
|
321
|
-
: { token: tokenOrOpts, site };
|
|
322
|
-
parseBundleName(model);
|
|
323
|
-
const resolvedSite = opts.site ?? site ?? DEFAULT_SITE;
|
|
324
|
-
const source = preferredPublicHub(resolvedSite);
|
|
325
|
-
const hubToken = resolveHubToken(source, opts);
|
|
326
|
-
const cache = cacheDir(model);
|
|
327
|
-
if (fs.existsSync(cache) && isValidBundle(cache))
|
|
328
|
-
return cache;
|
|
329
|
-
const staging = path.join(ariaHome(), "models", `.${model}.partial`);
|
|
330
|
-
try {
|
|
331
|
-
if (fs.existsSync(staging))
|
|
332
|
-
fs.rmSync(staging, { recursive: true, force: true });
|
|
333
|
-
fs.mkdirSync(staging, { recursive: true });
|
|
334
|
-
for (const file of HUB_REQUIRED) {
|
|
335
|
-
await fetchHubFile(source, model, file, path.join(staging, file), hubToken, true);
|
|
336
|
-
}
|
|
337
|
-
for (const extra of HUB_OPTIONAL) {
|
|
338
|
-
try {
|
|
339
|
-
await fetchHubFile(source, model, extra, path.join(staging, extra), hubToken, false);
|
|
340
|
-
}
|
|
341
|
-
catch {
|
|
342
|
-
/* optional tokenizer sidecar */
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
if (!isValidBundle(staging)) {
|
|
346
|
-
throw new Error(`${source} fetch completed but bundle invalid (need weight.bin + aria-quant-bundle config.json)`);
|
|
347
|
-
}
|
|
348
|
-
if (fs.existsSync(cache))
|
|
349
|
-
fs.rmSync(cache, { recursive: true, force: true });
|
|
350
|
-
fs.renameSync(staging, cache);
|
|
351
|
-
return cache;
|
|
352
|
-
}
|
|
353
|
-
catch (e) {
|
|
354
|
-
if (fs.existsSync(staging))
|
|
355
|
-
fs.rmSync(staging, { recursive: true, force: true });
|
|
356
|
-
throw e;
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
const SDK_UA = "aria-engine-sdk/0.1.0";
|
|
360
|
-
function ffiLibName(platform = process.platform) {
|
|
361
|
-
if (platform === "win32" || platform.toLowerCase().startsWith("win"))
|
|
362
|
-
return "aria-engine_ffi.dll";
|
|
363
|
-
if (platform === "darwin")
|
|
364
|
-
return "libaria-engine_ffi.dylib";
|
|
365
|
-
return "libaria-engine_ffi.so";
|
|
366
|
-
}
|
|
367
|
-
function libDir() {
|
|
368
|
-
return path.join(ariaHome(), "lib");
|
|
369
|
-
}
|
|
370
|
-
function cachedFfiPath(platform = process.platform) {
|
|
371
|
-
const candidate = path.join(libDir(), ffiLibName(platform));
|
|
372
|
-
return fs.existsSync(candidate) ? candidate : undefined;
|
|
373
|
-
}
|
|
374
|
-
function bundledFfiPath() {
|
|
375
|
-
const candidate = path.join(__dirname, "lib", ffiLibName());
|
|
376
|
-
return fs.existsSync(candidate) ? candidate : undefined;
|
|
377
|
-
}
|
|
378
|
-
function ffiAssetOs(platform = process.platform, arch = process.arch) {
|
|
379
|
-
const p = platform.toLowerCase();
|
|
380
|
-
const a = arch.toLowerCase();
|
|
381
|
-
if (p === "linux" && (a === "x64" || a === "x86_64" || a === "amd64"))
|
|
382
|
-
return "linux_x86_64";
|
|
383
|
-
if (p === "linux" && (a === "arm64" || a === "aarch64"))
|
|
384
|
-
return "linux_arm64";
|
|
385
|
-
if (p === "darwin" || p === "macos")
|
|
386
|
-
return "macos";
|
|
387
|
-
if ((p === "win32" || p.startsWith("win")) && (a === "x64" || a === "x86_64" || a === "amd64")) {
|
|
388
|
-
return "windows_x86_64";
|
|
389
|
-
}
|
|
390
|
-
throw new Error(`unsupported platform ${platform}/${arch} for libaria-engine_ffi`);
|
|
391
|
-
}
|
|
392
|
-
function stripV(tag) {
|
|
393
|
-
const t = tag.trim();
|
|
394
|
-
return t.startsWith("v") || t.startsWith("V") ? t.slice(1) : t;
|
|
395
|
-
}
|
|
396
|
-
function parseSemver(tag) {
|
|
397
|
-
const core = stripV(tag).split("-", 1)[0].split("+", 1)[0];
|
|
398
|
-
const parts = core.split(".");
|
|
399
|
-
if (!parts.length || !/^\d+$/.test(parts[0]))
|
|
400
|
-
return undefined;
|
|
401
|
-
return [
|
|
402
|
-
Number(parts[0]),
|
|
403
|
-
parts[1] && /^\d+$/.test(parts[1]) ? Number(parts[1]) : 0,
|
|
404
|
-
parts[2] && /^\d+$/.test(parts[2]) ? Number(parts[2]) : 0,
|
|
405
|
-
];
|
|
406
|
-
}
|
|
407
|
-
function selectLatestStable(releases) {
|
|
408
|
-
let bestTag;
|
|
409
|
-
let bestKey = [-1, -1, -1];
|
|
410
|
-
for (const rel of releases) {
|
|
411
|
-
if (rel.draft || rel.prerelease)
|
|
412
|
-
continue;
|
|
413
|
-
const tag = String(rel.tag_name || rel.tag || "");
|
|
414
|
-
const parsed = parseSemver(tag);
|
|
415
|
-
if (!parsed)
|
|
416
|
-
continue;
|
|
417
|
-
if (parsed[0] > bestKey[0] ||
|
|
418
|
-
(parsed[0] === bestKey[0] && parsed[1] > bestKey[1]) ||
|
|
419
|
-
(parsed[0] === bestKey[0] && parsed[1] === bestKey[1] && parsed[2] > bestKey[2])) {
|
|
420
|
-
bestKey = parsed;
|
|
421
|
-
bestTag = tag;
|
|
422
|
-
}
|
|
423
|
-
}
|
|
424
|
-
if (!bestTag)
|
|
425
|
-
throw new Error("no stable release found for libaria-engine_ffi");
|
|
426
|
-
return stripV(bestTag);
|
|
427
|
-
}
|
|
428
|
-
function upgradeOrg(site) {
|
|
429
|
-
const cfg = configYmlScalar("upgrade_url");
|
|
430
|
-
if (cfg)
|
|
431
|
-
return cfg.replace(/\/$/, "");
|
|
432
|
-
const hint = (site || configYmlScalar("site_url") || DEFAULT_SITE).toLowerCase();
|
|
433
|
-
if (hint.includes("ariacompute.cn") || hint.includes("gitee.com")) {
|
|
434
|
-
return "https://gitee.com/ariacompute";
|
|
435
|
-
}
|
|
436
|
-
return "https://github.com/ariacompute";
|
|
437
|
-
}
|
|
438
|
-
function releasesApiUrl(org) {
|
|
439
|
-
const owner = org.replace(/\/$/, "").split("/").pop() || "ariacompute";
|
|
440
|
-
if (org.toLowerCase().includes("gitee.com")) {
|
|
441
|
-
return `https://gitee.com/api/v5/repos/${owner}/engine/releases?per_page=30`;
|
|
442
|
-
}
|
|
443
|
-
return `https://api.github.com/repos/${owner}/engine/releases?per_page=30`;
|
|
444
|
-
}
|
|
445
|
-
function extractFfiArchive(archive, destDir, want = ffiLibName()) {
|
|
446
|
-
const tar = zlib.gunzipSync(fs.readFileSync(archive));
|
|
447
|
-
let offset = 0;
|
|
448
|
-
while (offset + 512 <= tar.length) {
|
|
449
|
-
const header = tar.subarray(offset, offset + 512);
|
|
450
|
-
if (header.every((b) => b === 0))
|
|
451
|
-
break;
|
|
452
|
-
const name = header.subarray(0, 100).toString("utf8").replace(/\0.*$/, "");
|
|
453
|
-
const sizeOctal = header.subarray(124, 136).toString("utf8").replace(/\0/g, "").trim();
|
|
454
|
-
const size = Number.parseInt(sizeOctal, 8) || 0;
|
|
455
|
-
const typeFlag = header[156];
|
|
456
|
-
offset += 512;
|
|
457
|
-
const isFile = typeFlag === 0 || typeFlag === 48; // '\0' or '0'
|
|
458
|
-
if (isFile && path.basename(name) === want) {
|
|
459
|
-
fs.mkdirSync(destDir, { recursive: true });
|
|
460
|
-
const dest = path.join(destDir, want);
|
|
461
|
-
fs.writeFileSync(dest, tar.subarray(offset, offset + size));
|
|
462
|
-
try {
|
|
463
|
-
fs.chmodSync(dest, 0o755);
|
|
464
|
-
}
|
|
465
|
-
catch {
|
|
466
|
-
/* windows */
|
|
467
|
-
}
|
|
468
|
-
return dest;
|
|
469
|
-
}
|
|
470
|
-
offset += Math.ceil(size / 512) * 512;
|
|
471
|
-
}
|
|
472
|
-
throw new Error(`${want} not found in ${archive}`);
|
|
473
|
-
}
|
|
474
|
-
function httpGetBytesSync(url) {
|
|
475
|
-
const script = 'fetch(process.env.ARIA_FFI_URL,{headers:{"User-Agent":"aria-engine-sdk/0.1.0"},redirect:"follow"}).then(async r=>{if(!r.ok){process.stderr.write("HTTP "+r.status);process.exit(1)}process.stdout.write(Buffer.from(await r.arrayBuffer()))}).catch(e=>{process.stderr.write(String(e&&e.message||e));process.exit(1)})';
|
|
476
|
-
const r = (0, node_child_process_1.spawnSync)(process.execPath, ["-e", script], {
|
|
477
|
-
env: { ...process.env, ARIA_FFI_URL: url },
|
|
478
|
-
encoding: "buffer",
|
|
479
|
-
maxBuffer: 256 * 1024 * 1024,
|
|
480
|
-
});
|
|
481
|
-
if (r.status !== 0) {
|
|
482
|
-
throw new Error(`download failed: ${(r.stderr && r.stderr.toString()) || "exit " + r.status}`);
|
|
483
|
-
}
|
|
484
|
-
return r.stdout;
|
|
485
|
-
}
|
|
486
|
-
async function httpGetBytes(url) {
|
|
487
|
-
const resp = await fetch(url, { headers: { "User-Agent": SDK_UA }, redirect: "follow" });
|
|
488
|
-
if (!resp.ok)
|
|
489
|
-
throw new Error(`HTTP ${resp.status} ${url}`);
|
|
490
|
-
return Buffer.from(await resp.arrayBuffer());
|
|
491
|
-
}
|
|
492
|
-
function installFfiFromReleases(raw, archiveBytes) {
|
|
493
|
-
let releases;
|
|
494
|
-
try {
|
|
495
|
-
releases = JSON.parse(raw.toString("utf8"));
|
|
496
|
-
}
|
|
497
|
-
catch {
|
|
498
|
-
throw new Error("invalid releases JSON");
|
|
499
|
-
}
|
|
500
|
-
if (!Array.isArray(releases))
|
|
501
|
-
throw new Error("unexpected releases payload");
|
|
502
|
-
const ver = selectLatestStable(releases);
|
|
503
|
-
const assetName = `libaria-engine_ffi_${ver}_${ffiAssetOs()}.tar.gz`;
|
|
504
|
-
let url;
|
|
505
|
-
for (const rel of releases) {
|
|
506
|
-
const tag = String(rel.tag_name || rel.tag || "");
|
|
507
|
-
if (stripV(tag) !== ver)
|
|
508
|
-
continue;
|
|
509
|
-
const assets = rel.assets || [];
|
|
510
|
-
for (const asset of assets) {
|
|
511
|
-
if (asset.name === assetName) {
|
|
512
|
-
url = asset.browser_download_url || asset.direct_asset_url;
|
|
513
|
-
break;
|
|
514
|
-
}
|
|
515
|
-
}
|
|
516
|
-
if (url)
|
|
517
|
-
break;
|
|
518
|
-
}
|
|
519
|
-
if (!url)
|
|
520
|
-
throw new Error(`release asset not found: ${assetName}`);
|
|
521
|
-
const staging = path.join(ariaHome(), "tmp", `ffi-${ver}`);
|
|
522
|
-
fs.rmSync(staging, { recursive: true, force: true });
|
|
523
|
-
fs.mkdirSync(staging, { recursive: true });
|
|
524
|
-
const archive = path.join(staging, assetName);
|
|
525
|
-
try {
|
|
526
|
-
fs.writeFileSync(archive, archiveBytes(url));
|
|
527
|
-
return extractFfiArchive(archive, libDir(), ffiLibName());
|
|
528
|
-
}
|
|
529
|
-
finally {
|
|
530
|
-
fs.rmSync(staging, { recursive: true, force: true });
|
|
531
|
-
}
|
|
532
|
-
}
|
|
533
|
-
/** Return a path to libaria-engine_ffi, downloading the latest stable Release if needed. */
|
|
534
|
-
async function ensureFfiLib(site) {
|
|
44
|
+
function ffiCandidates() {
|
|
535
45
|
const env = process.env.ARIA_FFI_LIB;
|
|
536
|
-
if (env
|
|
537
|
-
return env;
|
|
538
|
-
const
|
|
539
|
-
if (
|
|
540
|
-
return
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
const
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
}
|
|
562
|
-
function loadLib(ffiLib, site) {
|
|
563
|
-
const libPath = ffiLib ||
|
|
564
|
-
process.env.ARIA_FFI_LIB ||
|
|
565
|
-
bundledFfiPath() ||
|
|
566
|
-
cachedFfiPath() ||
|
|
567
|
-
ensureFfiLibSync(site);
|
|
568
|
-
if (!libPath)
|
|
569
|
-
throw new Error("Cannot locate libaria-engine_ffi");
|
|
570
|
-
const koffiNS = require("koffi");
|
|
571
|
-
return koffiNS.load(libPath);
|
|
572
|
-
}
|
|
573
|
-
function isLocalRef(modelRef) {
|
|
574
|
-
return modelRef.includes("/") || modelRef.includes("\\") || fs.existsSync(modelRef);
|
|
46
|
+
if (env)
|
|
47
|
+
return [env];
|
|
48
|
+
const lib = path.join(ariaHome(), "lib");
|
|
49
|
+
if (process.platform === "win32")
|
|
50
|
+
return [path.join(lib, "aria-engine_ffi.dll")];
|
|
51
|
+
if (process.platform === "darwin")
|
|
52
|
+
return [path.join(lib, "libaria-engine_ffi.dylib")];
|
|
53
|
+
return [path.join(lib, "libaria-engine_ffi.so")];
|
|
54
|
+
}
|
|
55
|
+
/** Load koffi binding when native lib is present; otherwise throw with install hint. */
|
|
56
|
+
function loadFfi() {
|
|
57
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
58
|
+
const koffi = require("koffi");
|
|
59
|
+
const candidates = ffiCandidates();
|
|
60
|
+
const found = candidates.find((p) => fs.existsSync(p));
|
|
61
|
+
if (!found) {
|
|
62
|
+
throw new Error(`libaria-engine_ffi not found; run aria-engine upgrade or set ARIA_FFI_LIB (tried ${candidates.join(", ")})`);
|
|
63
|
+
}
|
|
64
|
+
const lib = koffi.load(found);
|
|
65
|
+
return {
|
|
66
|
+
path: found,
|
|
67
|
+
aria_last_error: lib.func("aria_last_error", "str", []),
|
|
68
|
+
aria_model_init: lib.func("aria_model_init", "void *", ["str", "str"]),
|
|
69
|
+
aria_model_destroy: lib.func("aria_model_destroy", "void", ["void *"]),
|
|
70
|
+
aria_systemone: lib.func("aria_systemone", "int", ["void *", "str", "char *", "size_t"]),
|
|
71
|
+
};
|
|
575
72
|
}
|
|
576
|
-
class
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
this.
|
|
580
|
-
this.handle = null;
|
|
581
|
-
this.cfg = defaultSetupConfig();
|
|
582
|
-
this.opts = {};
|
|
583
|
-
this.opts = opts;
|
|
584
|
-
if (opts.site || opts.hfToken || opts.modelscopeApiToken) {
|
|
585
|
-
this.setup({
|
|
586
|
-
site_url: opts.site,
|
|
587
|
-
hf_token: opts.hfToken,
|
|
588
|
-
modelscope_api_token: opts.modelscopeApiToken,
|
|
589
|
-
});
|
|
590
|
-
}
|
|
591
|
-
if (bundle)
|
|
592
|
-
this.bindAndInit(bundle, opts.ffiLib);
|
|
593
|
-
}
|
|
594
|
-
/** Set Config / Run fields on this instance only. Does not write engine.yml. */
|
|
595
|
-
setup(updates) {
|
|
596
|
-
this.cfg = applySetup(this.cfg, updates);
|
|
597
|
-
return this;
|
|
598
|
-
}
|
|
599
|
-
setupStatus() {
|
|
600
|
-
return { ...this.cfg };
|
|
601
|
-
}
|
|
602
|
-
/** Reset instance defaults. Does not delete ~/.ariacompute/engine.yml. */
|
|
603
|
-
setupClear() {
|
|
604
|
-
this.cfg = defaultSetupConfig();
|
|
605
|
-
return this;
|
|
606
|
-
}
|
|
607
|
-
bindAndInit(bundle, ffiLib) {
|
|
608
|
-
this.lib = loadLib(ffiLib || this.opts.ffiLib, this.cfg.site_url || this.opts.site);
|
|
609
|
-
this.fnInit = this.lib.func("aria_model_init", "void*", ["str"]);
|
|
610
|
-
this.fnDestroy = this.lib.func("aria_model_destroy", "void", ["void*"]);
|
|
611
|
-
this.fnComplete = this.lib.func("aria_complete", "int", ["void*", "str", "str", "str", "void*", "size_t"]);
|
|
612
|
-
this.fnEmbed = this.lib.func("aria_embed", "int", ["void*", "str", "void*", "size_t"]);
|
|
613
|
-
this.fnTranscribe = this.lib.func("aria_transcribe", "int", ["void*", "void*", "size_t", "str", "void*", "size_t"]);
|
|
614
|
-
this.fnLastError = this.lib.func("aria_last_error", "str", []);
|
|
615
|
-
this.handle = this.fnInit(bundle);
|
|
73
|
+
class AriaEngine {
|
|
74
|
+
constructor(checkpoint, track = "encoder") {
|
|
75
|
+
this.ffi = loadFfi();
|
|
76
|
+
this.handle = this.ffi.aria_model_init(checkpoint, track);
|
|
616
77
|
if (!this.handle) {
|
|
617
|
-
|
|
618
|
-
throw new Error(err || "init failed");
|
|
619
|
-
}
|
|
620
|
-
}
|
|
621
|
-
/** Download (if needed) and load a model using instance setup. */
|
|
622
|
-
async open(modelRef) {
|
|
623
|
-
await ensureFfiLib(this.cfg.site_url || this.opts.site);
|
|
624
|
-
const openOpts = {
|
|
625
|
-
...this.opts,
|
|
626
|
-
site: this.cfg.site_url || this.opts.site,
|
|
627
|
-
hfToken: this.cfg.hf_token || this.opts.hfToken,
|
|
628
|
-
modelscopeApiToken: this.cfg.modelscope_api_token || this.opts.modelscopeApiToken,
|
|
629
|
-
};
|
|
630
|
-
const bundle = isLocalRef(modelRef) ? modelRef : await downloadModel(modelRef, openOpts);
|
|
631
|
-
if (this.handle)
|
|
632
|
-
this.close();
|
|
633
|
-
this.bindAndInit(bundle, this.opts.ffiLib);
|
|
634
|
-
return this;
|
|
635
|
-
}
|
|
636
|
-
/** Auto-detect: a value containing a separator or already on disk is a local
|
|
637
|
-
* path; otherwise it is a model name downloaded from the regional public hub. */
|
|
638
|
-
static async open(modelRef, opts = {}) {
|
|
639
|
-
const eng = new Engine(undefined, opts);
|
|
640
|
-
await eng.open(modelRef);
|
|
641
|
-
return eng;
|
|
642
|
-
}
|
|
643
|
-
complete(messages, opts = {}) {
|
|
644
|
-
const messagesJson = JSON.stringify(messages);
|
|
645
|
-
const optionsJson = JSON.stringify(opts || { max_tokens: 16 });
|
|
646
|
-
const toolsJson = JSON.stringify([]);
|
|
647
|
-
const buf = Buffer.alloc(1 << 16);
|
|
648
|
-
const rc = this.fnComplete(this.handle, messagesJson, optionsJson, toolsJson, buf, buf.length);
|
|
649
|
-
if (rc !== 0) {
|
|
650
|
-
const err = this.fnLastError();
|
|
651
|
-
return { success: false, response: "", error: err || "complete failed" };
|
|
652
|
-
}
|
|
653
|
-
try {
|
|
654
|
-
const parsed = JSON.parse(buf.toString("utf8").replace(/\0+$/, ""));
|
|
655
|
-
return { success: true, response: parsed.response ?? "", generation: parsed };
|
|
656
|
-
}
|
|
657
|
-
catch {
|
|
658
|
-
return { success: true, response: buf.toString("utf8").replace(/\0+$/, "") };
|
|
78
|
+
throw new Error(this.ffi.aria_last_error() || "aria_model_init failed");
|
|
659
79
|
}
|
|
660
80
|
}
|
|
661
|
-
|
|
81
|
+
systemone(request) {
|
|
662
82
|
const buf = Buffer.alloc(1 << 20);
|
|
663
|
-
const rc = this.
|
|
83
|
+
const rc = this.ffi.aria_systemone(this.handle, JSON.stringify(request), buf, buf.length);
|
|
664
84
|
if (rc !== 0) {
|
|
665
|
-
|
|
666
|
-
throw new Error(err || "embed failed");
|
|
85
|
+
throw new Error(this.ffi.aria_last_error() || `aria_systemone rc=${rc}`);
|
|
667
86
|
}
|
|
668
|
-
|
|
87
|
+
const text = buf.toString("utf8").replace(/\0.*$/, "");
|
|
88
|
+
return JSON.parse(text);
|
|
669
89
|
}
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
const err = this.fnLastError();
|
|
675
|
-
throw new Error(err || "transcribe failed");
|
|
90
|
+
destroy() {
|
|
91
|
+
if (this.handle) {
|
|
92
|
+
this.ffi.aria_model_destroy(this.handle);
|
|
93
|
+
this.handle = null;
|
|
676
94
|
}
|
|
677
|
-
return buf.toString("utf8").replace(/\0+$/, "");
|
|
678
|
-
}
|
|
679
|
-
close() {
|
|
680
|
-
if (this.handle && this.fnDestroy)
|
|
681
|
-
this.fnDestroy(this.handle);
|
|
682
|
-
this.handle = null;
|
|
683
95
|
}
|
|
684
96
|
}
|
|
685
|
-
exports.
|
|
686
|
-
exports.
|
|
97
|
+
exports.AriaEngine = AriaEngine;
|
|
98
|
+
exports.default = AriaEngine;
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ariacompute/engine-ts",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "TypeScript/Node SDK for
|
|
3
|
+
"version": "2.0.2",
|
|
4
|
+
"description": "TypeScript/Node SDK for AFM-D System One (koffi over libaria-engine_ffi)",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"scripts": {
|
|
8
8
|
"build": "tsc -p .",
|
|
9
|
-
"test": "node --test test/binding.test.mjs
|
|
9
|
+
"test": "node --test test/binding.test.mjs"
|
|
10
10
|
},
|
|
11
11
|
"license": "MIT",
|
|
12
12
|
"dependencies": {
|