jev-web 0.7.2 → 0.9.0
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/LICENSE +21 -21
- package/README.md +773 -502
- package/docs/demo-model-picker.png +0 -0
- package/package.json +64 -60
- package/src/answers.mjs +36 -36
- package/src/bekko.mjs +439 -439
- package/src/clef.mjs +498 -0
- package/src/config.mjs +65 -65
- package/src/decision2.mjs +382 -382
- package/src/decision3.mjs +571 -0
- package/src/encode.mjs +83 -83
- package/src/index.mjs +196 -112
- package/src/kev.mjs +296 -296
- package/src/laya.mjs +630 -630
- package/src/questions.mjs +46 -39
- package/src/registry.mjs +199 -155
- package/src/session.mjs +151 -151
- package/src/strands.mjs +718 -535
- package/src/vega.mjs +1125 -0
package/src/session.mjs
CHANGED
|
@@ -1,151 +1,151 @@
|
|
|
1
|
-
// jev-web — decider session: tokenizer + model + decide().
|
|
2
|
-
//
|
|
3
|
-
// transformers.js is an optional peer dependency, imported lazily so the
|
|
4
|
-
// package works anywhere and hosts can inject their own copy (tests, custom
|
|
5
|
-
// builds). Everything heavy stays out of module scope.
|
|
6
|
-
|
|
7
|
-
import { normalizeQuestions } from "./questions.mjs";
|
|
8
|
-
|
|
9
|
-
const now = () => (typeof performance !== "undefined" ? performance.now() : Date.now());
|
|
10
|
-
import { buildDecisionInput, typedMarkerIds } from "./encode.mjs";
|
|
11
|
-
import { answersFromScores } from "./answers.mjs";
|
|
12
|
-
import {
|
|
13
|
-
DEFAULT_MODEL,
|
|
14
|
-
DEFAULT_REVISION,
|
|
15
|
-
loadModelConfig,
|
|
16
|
-
resolveDevice,
|
|
17
|
-
resolveDtype,
|
|
18
|
-
detectWebGPU,
|
|
19
|
-
} from "./config.mjs";
|
|
20
|
-
|
|
21
|
-
export async function createDecider({
|
|
22
|
-
model = DEFAULT_MODEL,
|
|
23
|
-
revision = DEFAULT_REVISION,
|
|
24
|
-
dtype = "auto",
|
|
25
|
-
device = "auto",
|
|
26
|
-
temperature = null,
|
|
27
|
-
maxStateTokens = null,
|
|
28
|
-
onProgress = null,
|
|
29
|
-
transformers = null,
|
|
30
|
-
fetchImpl = fetch,
|
|
31
|
-
scope = globalThis,
|
|
32
|
-
// Directory (or CDN base) holding the onnxruntime-web wasm/loader files.
|
|
33
|
-
// Bundlers usually cannot ship the 26 MB asyncify wasm under static-host
|
|
34
|
-
// file-size limits; hosts that self-host a compressed copy set this to
|
|
35
|
-
// e.g. "/assets/". Defaults to the runtime's own resolution.
|
|
36
|
-
wasmPaths = null,
|
|
37
|
-
} = {}) {
|
|
38
|
-
const tf = transformers ?? (await import("@huggingface/transformers"));
|
|
39
|
-
if (wasmPaths) {
|
|
40
|
-
try {
|
|
41
|
-
tf.env.backends.onnx.wasm.wasmPaths = wasmPaths;
|
|
42
|
-
} catch { /* older runtime: ignore */ }
|
|
43
|
-
}
|
|
44
|
-
const remote = await loadModelConfig({ model, revision, fetchImpl });
|
|
45
|
-
const resolvedDevice = resolveDevice({ device, webgpu: await detectWebGPU(scope) });
|
|
46
|
-
const resolvedDtype = resolveDtype(resolvedDevice, dtype);
|
|
47
|
-
|
|
48
|
-
const report = (phase) => (p) =>
|
|
49
|
-
onProgress?.({
|
|
50
|
-
phase,
|
|
51
|
-
status: p?.status ?? null,
|
|
52
|
-
file: p?.file ?? null,
|
|
53
|
-
loaded: p?.loaded ?? null,
|
|
54
|
-
total: p?.total ?? null,
|
|
55
|
-
progress: p?.progress ?? null,
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
const tokenizer = await tf.AutoTokenizer.from_pretrained(model, {
|
|
59
|
-
revision,
|
|
60
|
-
progress_callback: report("tokenizer"),
|
|
61
|
-
});
|
|
62
|
-
const net = await tf.AutoModel.from_pretrained(model, {
|
|
63
|
-
revision,
|
|
64
|
-
dtype: resolvedDtype,
|
|
65
|
-
device: resolvedDevice,
|
|
66
|
-
progress_callback: report("model"),
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
const encode = (text) => Array.from(tokenizer(text, { add_special_tokens: false }).input_ids.data, Number);
|
|
70
|
-
const markers = typedMarkerIds(encode, { markers: remote.markers });
|
|
71
|
-
|
|
72
|
-
const effective = {
|
|
73
|
-
temperature: Number.isFinite(temperature) ? temperature : remote.temperature,
|
|
74
|
-
maxStateTokens: Number.isFinite(maxStateTokens) ? maxStateTokens : remote.maxStateTokens,
|
|
75
|
-
maxLen: remote.maxLen,
|
|
76
|
-
};
|
|
77
|
-
|
|
78
|
-
const i64 = (values, dims) => new tf.Tensor("int64", BigInt64Array.from(values, BigInt), dims);
|
|
79
|
-
|
|
80
|
-
return {
|
|
81
|
-
info: {
|
|
82
|
-
family: "open-jev",
|
|
83
|
-
model,
|
|
84
|
-
revision,
|
|
85
|
-
device: resolvedDevice,
|
|
86
|
-
dtype: resolvedDtype,
|
|
87
|
-
temperature: effective.temperature,
|
|
88
|
-
maxStateTokens: effective.maxStateTokens,
|
|
89
|
-
maxLen: effective.maxLen,
|
|
90
|
-
pool: remote.pool,
|
|
91
|
-
configSource: remote.source,
|
|
92
|
-
},
|
|
93
|
-
async decide(state, questions) {
|
|
94
|
-
const t0 = now();
|
|
95
|
-
const normalized = normalizeQuestions(questions);
|
|
96
|
-
const tokenized = normalized.map((q) => ({
|
|
97
|
-
type: q.type,
|
|
98
|
-
instructionIds: encode(q.instructions),
|
|
99
|
-
optionIds: q.options.map((option) => encode(option)),
|
|
100
|
-
}));
|
|
101
|
-
const stateIds = encode(String(state ?? ""));
|
|
102
|
-
const input = buildDecisionInput({
|
|
103
|
-
stateIds,
|
|
104
|
-
markers,
|
|
105
|
-
questions: tokenized,
|
|
106
|
-
maxStateTokens: effective.maxStateTokens,
|
|
107
|
-
maxLen: effective.maxLen,
|
|
108
|
-
});
|
|
109
|
-
const feeds = {
|
|
110
|
-
input_ids: i64(input.inputIds, [1, input.length]),
|
|
111
|
-
attention_mask: i64(input.inputIds.map(() => 1), [1, input.length]),
|
|
112
|
-
seg: i64(input.seg, [1, input.length]),
|
|
113
|
-
pair_q: i64(input.pairQ, [1, input.pairQ.length]),
|
|
114
|
-
pair_opt: i64(input.pairOpt, [1, input.pairOpt.length]),
|
|
115
|
-
};
|
|
116
|
-
const tInfer = now();
|
|
117
|
-
const out = await net(feeds);
|
|
118
|
-
const inferMs = now() - tInfer;
|
|
119
|
-
const logits = out?.logits;
|
|
120
|
-
if (!logits) throw new Error("model output has no `logits` — not a typed-decision export?");
|
|
121
|
-
const scores = Array.from(logits.to("float32").data, Number);
|
|
122
|
-
const answers = answersFromScores(scores, {
|
|
123
|
-
questions: normalized,
|
|
124
|
-
groups: input.groups,
|
|
125
|
-
temperature: effective.temperature,
|
|
126
|
-
});
|
|
127
|
-
// Exact view of the single fused sequence the graph consumed.
|
|
128
|
-
let prompt;
|
|
129
|
-
try {
|
|
130
|
-
prompt = tokenizer.decode(input.inputIds, { skip_special_tokens: false });
|
|
131
|
-
} catch {
|
|
132
|
-
prompt = input.inputIds.join(" ");
|
|
133
|
-
}
|
|
134
|
-
return {
|
|
135
|
-
answers,
|
|
136
|
-
truncated: input.truncated,
|
|
137
|
-
length: input.length,
|
|
138
|
-
prompts: [prompt],
|
|
139
|
-
timings: { totalMs: Math.round(now() - t0), inferMs: Math.round(inferMs) },
|
|
140
|
-
};
|
|
141
|
-
},
|
|
142
|
-
async decideMany(cases) {
|
|
143
|
-
const out = [];
|
|
144
|
-
for (const c of cases ?? []) out.push(await this.decide(c.state, c.questions));
|
|
145
|
-
return out;
|
|
146
|
-
},
|
|
147
|
-
dispose() {
|
|
148
|
-
net?.dispose?.();
|
|
149
|
-
},
|
|
150
|
-
};
|
|
151
|
-
}
|
|
1
|
+
// jev-web — decider session: tokenizer + model + decide().
|
|
2
|
+
//
|
|
3
|
+
// transformers.js is an optional peer dependency, imported lazily so the
|
|
4
|
+
// package works anywhere and hosts can inject their own copy (tests, custom
|
|
5
|
+
// builds). Everything heavy stays out of module scope.
|
|
6
|
+
|
|
7
|
+
import { normalizeQuestions } from "./questions.mjs";
|
|
8
|
+
|
|
9
|
+
const now = () => (typeof performance !== "undefined" ? performance.now() : Date.now());
|
|
10
|
+
import { buildDecisionInput, typedMarkerIds } from "./encode.mjs";
|
|
11
|
+
import { answersFromScores } from "./answers.mjs";
|
|
12
|
+
import {
|
|
13
|
+
DEFAULT_MODEL,
|
|
14
|
+
DEFAULT_REVISION,
|
|
15
|
+
loadModelConfig,
|
|
16
|
+
resolveDevice,
|
|
17
|
+
resolveDtype,
|
|
18
|
+
detectWebGPU,
|
|
19
|
+
} from "./config.mjs";
|
|
20
|
+
|
|
21
|
+
export async function createDecider({
|
|
22
|
+
model = DEFAULT_MODEL,
|
|
23
|
+
revision = DEFAULT_REVISION,
|
|
24
|
+
dtype = "auto",
|
|
25
|
+
device = "auto",
|
|
26
|
+
temperature = null,
|
|
27
|
+
maxStateTokens = null,
|
|
28
|
+
onProgress = null,
|
|
29
|
+
transformers = null,
|
|
30
|
+
fetchImpl = fetch,
|
|
31
|
+
scope = globalThis,
|
|
32
|
+
// Directory (or CDN base) holding the onnxruntime-web wasm/loader files.
|
|
33
|
+
// Bundlers usually cannot ship the 26 MB asyncify wasm under static-host
|
|
34
|
+
// file-size limits; hosts that self-host a compressed copy set this to
|
|
35
|
+
// e.g. "/assets/". Defaults to the runtime's own resolution.
|
|
36
|
+
wasmPaths = null,
|
|
37
|
+
} = {}) {
|
|
38
|
+
const tf = transformers ?? (await import("@huggingface/transformers"));
|
|
39
|
+
if (wasmPaths) {
|
|
40
|
+
try {
|
|
41
|
+
tf.env.backends.onnx.wasm.wasmPaths = wasmPaths;
|
|
42
|
+
} catch { /* older runtime: ignore */ }
|
|
43
|
+
}
|
|
44
|
+
const remote = await loadModelConfig({ model, revision, fetchImpl });
|
|
45
|
+
const resolvedDevice = resolveDevice({ device, webgpu: await detectWebGPU(scope) });
|
|
46
|
+
const resolvedDtype = resolveDtype(resolvedDevice, dtype);
|
|
47
|
+
|
|
48
|
+
const report = (phase) => (p) =>
|
|
49
|
+
onProgress?.({
|
|
50
|
+
phase,
|
|
51
|
+
status: p?.status ?? null,
|
|
52
|
+
file: p?.file ?? null,
|
|
53
|
+
loaded: p?.loaded ?? null,
|
|
54
|
+
total: p?.total ?? null,
|
|
55
|
+
progress: p?.progress ?? null,
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
const tokenizer = await tf.AutoTokenizer.from_pretrained(model, {
|
|
59
|
+
revision,
|
|
60
|
+
progress_callback: report("tokenizer"),
|
|
61
|
+
});
|
|
62
|
+
const net = await tf.AutoModel.from_pretrained(model, {
|
|
63
|
+
revision,
|
|
64
|
+
dtype: resolvedDtype,
|
|
65
|
+
device: resolvedDevice,
|
|
66
|
+
progress_callback: report("model"),
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
const encode = (text) => Array.from(tokenizer(text, { add_special_tokens: false }).input_ids.data, Number);
|
|
70
|
+
const markers = typedMarkerIds(encode, { markers: remote.markers });
|
|
71
|
+
|
|
72
|
+
const effective = {
|
|
73
|
+
temperature: Number.isFinite(temperature) ? temperature : remote.temperature,
|
|
74
|
+
maxStateTokens: Number.isFinite(maxStateTokens) ? maxStateTokens : remote.maxStateTokens,
|
|
75
|
+
maxLen: remote.maxLen,
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
const i64 = (values, dims) => new tf.Tensor("int64", BigInt64Array.from(values, BigInt), dims);
|
|
79
|
+
|
|
80
|
+
return {
|
|
81
|
+
info: {
|
|
82
|
+
family: "open-jev",
|
|
83
|
+
model,
|
|
84
|
+
revision,
|
|
85
|
+
device: resolvedDevice,
|
|
86
|
+
dtype: resolvedDtype,
|
|
87
|
+
temperature: effective.temperature,
|
|
88
|
+
maxStateTokens: effective.maxStateTokens,
|
|
89
|
+
maxLen: effective.maxLen,
|
|
90
|
+
pool: remote.pool,
|
|
91
|
+
configSource: remote.source,
|
|
92
|
+
},
|
|
93
|
+
async decide(state, questions) {
|
|
94
|
+
const t0 = now();
|
|
95
|
+
const normalized = normalizeQuestions(questions);
|
|
96
|
+
const tokenized = normalized.map((q) => ({
|
|
97
|
+
type: q.type,
|
|
98
|
+
instructionIds: encode(q.instructions),
|
|
99
|
+
optionIds: q.options.map((option) => encode(option)),
|
|
100
|
+
}));
|
|
101
|
+
const stateIds = encode(String(state ?? ""));
|
|
102
|
+
const input = buildDecisionInput({
|
|
103
|
+
stateIds,
|
|
104
|
+
markers,
|
|
105
|
+
questions: tokenized,
|
|
106
|
+
maxStateTokens: effective.maxStateTokens,
|
|
107
|
+
maxLen: effective.maxLen,
|
|
108
|
+
});
|
|
109
|
+
const feeds = {
|
|
110
|
+
input_ids: i64(input.inputIds, [1, input.length]),
|
|
111
|
+
attention_mask: i64(input.inputIds.map(() => 1), [1, input.length]),
|
|
112
|
+
seg: i64(input.seg, [1, input.length]),
|
|
113
|
+
pair_q: i64(input.pairQ, [1, input.pairQ.length]),
|
|
114
|
+
pair_opt: i64(input.pairOpt, [1, input.pairOpt.length]),
|
|
115
|
+
};
|
|
116
|
+
const tInfer = now();
|
|
117
|
+
const out = await net(feeds);
|
|
118
|
+
const inferMs = now() - tInfer;
|
|
119
|
+
const logits = out?.logits;
|
|
120
|
+
if (!logits) throw new Error("model output has no `logits` — not a typed-decision export?");
|
|
121
|
+
const scores = Array.from(logits.to("float32").data, Number);
|
|
122
|
+
const answers = answersFromScores(scores, {
|
|
123
|
+
questions: normalized,
|
|
124
|
+
groups: input.groups,
|
|
125
|
+
temperature: effective.temperature,
|
|
126
|
+
});
|
|
127
|
+
// Exact view of the single fused sequence the graph consumed.
|
|
128
|
+
let prompt;
|
|
129
|
+
try {
|
|
130
|
+
prompt = tokenizer.decode(input.inputIds, { skip_special_tokens: false });
|
|
131
|
+
} catch {
|
|
132
|
+
prompt = input.inputIds.join(" ");
|
|
133
|
+
}
|
|
134
|
+
return {
|
|
135
|
+
answers,
|
|
136
|
+
truncated: input.truncated,
|
|
137
|
+
length: input.length,
|
|
138
|
+
prompts: [prompt],
|
|
139
|
+
timings: { totalMs: Math.round(now() - t0), inferMs: Math.round(inferMs) },
|
|
140
|
+
};
|
|
141
|
+
},
|
|
142
|
+
async decideMany(cases) {
|
|
143
|
+
const out = [];
|
|
144
|
+
for (const c of cases ?? []) out.push(await this.decide(c.state, c.questions));
|
|
145
|
+
return out;
|
|
146
|
+
},
|
|
147
|
+
dispose() {
|
|
148
|
+
net?.dispose?.();
|
|
149
|
+
},
|
|
150
|
+
};
|
|
151
|
+
}
|