warpvector 0.1.0 → 0.1.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 +263 -98
- package/dist/index.d.mts +908 -46
- package/dist/index.d.ts +908 -46
- package/dist/index.js +2879 -321
- package/dist/index.mjs +2904 -347
- package/package.json +16 -1
package/dist/index.js
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __commonJS = (cb, mod) => function __require() {
|
|
9
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
10
|
+
};
|
|
6
11
|
var __export = (target, all) => {
|
|
7
12
|
for (var name in all)
|
|
8
13
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
@@ -15,26 +20,617 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
15
20
|
}
|
|
16
21
|
return to;
|
|
17
22
|
};
|
|
23
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
24
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
25
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
26
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
27
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
28
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
29
|
+
mod
|
|
30
|
+
));
|
|
18
31
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
32
|
|
|
33
|
+
// node_modules/eventemitter3/index.js
|
|
34
|
+
var require_eventemitter3 = __commonJS({
|
|
35
|
+
"node_modules/eventemitter3/index.js"(exports2, module2) {
|
|
36
|
+
"use strict";
|
|
37
|
+
var has = Object.prototype.hasOwnProperty;
|
|
38
|
+
var prefix = "~";
|
|
39
|
+
function Events() {
|
|
40
|
+
}
|
|
41
|
+
if (Object.create) {
|
|
42
|
+
Events.prototype = /* @__PURE__ */ Object.create(null);
|
|
43
|
+
if (!new Events().__proto__) prefix = false;
|
|
44
|
+
}
|
|
45
|
+
function EE(fn, context, once) {
|
|
46
|
+
this.fn = fn;
|
|
47
|
+
this.context = context;
|
|
48
|
+
this.once = once || false;
|
|
49
|
+
}
|
|
50
|
+
function addListener(emitter, event, fn, context, once) {
|
|
51
|
+
if (typeof fn !== "function") {
|
|
52
|
+
throw new TypeError("The listener must be a function");
|
|
53
|
+
}
|
|
54
|
+
var listener = new EE(fn, context || emitter, once), evt = prefix ? prefix + event : event;
|
|
55
|
+
if (!emitter._events[evt]) emitter._events[evt] = listener, emitter._eventsCount++;
|
|
56
|
+
else if (!emitter._events[evt].fn) emitter._events[evt].push(listener);
|
|
57
|
+
else emitter._events[evt] = [emitter._events[evt], listener];
|
|
58
|
+
return emitter;
|
|
59
|
+
}
|
|
60
|
+
function clearEvent(emitter, evt) {
|
|
61
|
+
if (--emitter._eventsCount === 0) emitter._events = new Events();
|
|
62
|
+
else delete emitter._events[evt];
|
|
63
|
+
}
|
|
64
|
+
function EventEmitter() {
|
|
65
|
+
this._events = new Events();
|
|
66
|
+
this._eventsCount = 0;
|
|
67
|
+
}
|
|
68
|
+
EventEmitter.prototype.eventNames = function eventNames() {
|
|
69
|
+
var names = [], events, name;
|
|
70
|
+
if (this._eventsCount === 0) return names;
|
|
71
|
+
for (name in events = this._events) {
|
|
72
|
+
if (has.call(events, name)) names.push(prefix ? name.slice(1) : name);
|
|
73
|
+
}
|
|
74
|
+
if (Object.getOwnPropertySymbols) {
|
|
75
|
+
return names.concat(Object.getOwnPropertySymbols(events));
|
|
76
|
+
}
|
|
77
|
+
return names;
|
|
78
|
+
};
|
|
79
|
+
EventEmitter.prototype.listeners = function listeners(event) {
|
|
80
|
+
var evt = prefix ? prefix + event : event, handlers = this._events[evt];
|
|
81
|
+
if (!handlers) return [];
|
|
82
|
+
if (handlers.fn) return [handlers.fn];
|
|
83
|
+
for (var i = 0, l = handlers.length, ee = new Array(l); i < l; i++) {
|
|
84
|
+
ee[i] = handlers[i].fn;
|
|
85
|
+
}
|
|
86
|
+
return ee;
|
|
87
|
+
};
|
|
88
|
+
EventEmitter.prototype.listenerCount = function listenerCount(event) {
|
|
89
|
+
var evt = prefix ? prefix + event : event, listeners = this._events[evt];
|
|
90
|
+
if (!listeners) return 0;
|
|
91
|
+
if (listeners.fn) return 1;
|
|
92
|
+
return listeners.length;
|
|
93
|
+
};
|
|
94
|
+
EventEmitter.prototype.emit = function emit(event, a1, a2, a3, a4, a5) {
|
|
95
|
+
var evt = prefix ? prefix + event : event;
|
|
96
|
+
if (!this._events[evt]) return false;
|
|
97
|
+
var listeners = this._events[evt], len = arguments.length, args, i;
|
|
98
|
+
if (listeners.fn) {
|
|
99
|
+
if (listeners.once) this.removeListener(event, listeners.fn, void 0, true);
|
|
100
|
+
switch (len) {
|
|
101
|
+
case 1:
|
|
102
|
+
return listeners.fn.call(listeners.context), true;
|
|
103
|
+
case 2:
|
|
104
|
+
return listeners.fn.call(listeners.context, a1), true;
|
|
105
|
+
case 3:
|
|
106
|
+
return listeners.fn.call(listeners.context, a1, a2), true;
|
|
107
|
+
case 4:
|
|
108
|
+
return listeners.fn.call(listeners.context, a1, a2, a3), true;
|
|
109
|
+
case 5:
|
|
110
|
+
return listeners.fn.call(listeners.context, a1, a2, a3, a4), true;
|
|
111
|
+
case 6:
|
|
112
|
+
return listeners.fn.call(listeners.context, a1, a2, a3, a4, a5), true;
|
|
113
|
+
}
|
|
114
|
+
for (i = 1, args = new Array(len - 1); i < len; i++) {
|
|
115
|
+
args[i - 1] = arguments[i];
|
|
116
|
+
}
|
|
117
|
+
listeners.fn.apply(listeners.context, args);
|
|
118
|
+
} else {
|
|
119
|
+
var length = listeners.length, j;
|
|
120
|
+
for (i = 0; i < length; i++) {
|
|
121
|
+
if (listeners[i].once) this.removeListener(event, listeners[i].fn, void 0, true);
|
|
122
|
+
switch (len) {
|
|
123
|
+
case 1:
|
|
124
|
+
listeners[i].fn.call(listeners[i].context);
|
|
125
|
+
break;
|
|
126
|
+
case 2:
|
|
127
|
+
listeners[i].fn.call(listeners[i].context, a1);
|
|
128
|
+
break;
|
|
129
|
+
case 3:
|
|
130
|
+
listeners[i].fn.call(listeners[i].context, a1, a2);
|
|
131
|
+
break;
|
|
132
|
+
case 4:
|
|
133
|
+
listeners[i].fn.call(listeners[i].context, a1, a2, a3);
|
|
134
|
+
break;
|
|
135
|
+
default:
|
|
136
|
+
if (!args) for (j = 1, args = new Array(len - 1); j < len; j++) {
|
|
137
|
+
args[j - 1] = arguments[j];
|
|
138
|
+
}
|
|
139
|
+
listeners[i].fn.apply(listeners[i].context, args);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
return true;
|
|
144
|
+
};
|
|
145
|
+
EventEmitter.prototype.on = function on(event, fn, context) {
|
|
146
|
+
return addListener(this, event, fn, context, false);
|
|
147
|
+
};
|
|
148
|
+
EventEmitter.prototype.once = function once(event, fn, context) {
|
|
149
|
+
return addListener(this, event, fn, context, true);
|
|
150
|
+
};
|
|
151
|
+
EventEmitter.prototype.removeListener = function removeListener(event, fn, context, once) {
|
|
152
|
+
var evt = prefix ? prefix + event : event;
|
|
153
|
+
if (!this._events[evt]) return this;
|
|
154
|
+
if (!fn) {
|
|
155
|
+
clearEvent(this, evt);
|
|
156
|
+
return this;
|
|
157
|
+
}
|
|
158
|
+
var listeners = this._events[evt];
|
|
159
|
+
if (listeners.fn) {
|
|
160
|
+
if (listeners.fn === fn && (!once || listeners.once) && (!context || listeners.context === context)) {
|
|
161
|
+
clearEvent(this, evt);
|
|
162
|
+
}
|
|
163
|
+
} else {
|
|
164
|
+
for (var i = 0, events = [], length = listeners.length; i < length; i++) {
|
|
165
|
+
if (listeners[i].fn !== fn || once && !listeners[i].once || context && listeners[i].context !== context) {
|
|
166
|
+
events.push(listeners[i]);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
if (events.length) this._events[evt] = events.length === 1 ? events[0] : events;
|
|
170
|
+
else clearEvent(this, evt);
|
|
171
|
+
}
|
|
172
|
+
return this;
|
|
173
|
+
};
|
|
174
|
+
EventEmitter.prototype.removeAllListeners = function removeAllListeners(event) {
|
|
175
|
+
var evt;
|
|
176
|
+
if (event) {
|
|
177
|
+
evt = prefix ? prefix + event : event;
|
|
178
|
+
if (this._events[evt]) clearEvent(this, evt);
|
|
179
|
+
} else {
|
|
180
|
+
this._events = new Events();
|
|
181
|
+
this._eventsCount = 0;
|
|
182
|
+
}
|
|
183
|
+
return this;
|
|
184
|
+
};
|
|
185
|
+
EventEmitter.prototype.off = EventEmitter.prototype.removeListener;
|
|
186
|
+
EventEmitter.prototype.addListener = EventEmitter.prototype.on;
|
|
187
|
+
EventEmitter.prefixed = prefix;
|
|
188
|
+
EventEmitter.EventEmitter = EventEmitter;
|
|
189
|
+
if ("undefined" !== typeof module2) {
|
|
190
|
+
module2.exports = EventEmitter;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
// node_modules/p-finally/index.js
|
|
196
|
+
var require_p_finally = __commonJS({
|
|
197
|
+
"node_modules/p-finally/index.js"(exports2, module2) {
|
|
198
|
+
"use strict";
|
|
199
|
+
module2.exports = (promise, onFinally) => {
|
|
200
|
+
onFinally = onFinally || (() => {
|
|
201
|
+
});
|
|
202
|
+
return promise.then(
|
|
203
|
+
(val) => new Promise((resolve) => {
|
|
204
|
+
resolve(onFinally());
|
|
205
|
+
}).then(() => val),
|
|
206
|
+
(err) => new Promise((resolve) => {
|
|
207
|
+
resolve(onFinally());
|
|
208
|
+
}).then(() => {
|
|
209
|
+
throw err;
|
|
210
|
+
})
|
|
211
|
+
);
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
// node_modules/p-timeout/index.js
|
|
217
|
+
var require_p_timeout = __commonJS({
|
|
218
|
+
"node_modules/p-timeout/index.js"(exports2, module2) {
|
|
219
|
+
"use strict";
|
|
220
|
+
var pFinally = require_p_finally();
|
|
221
|
+
var TimeoutError = class extends Error {
|
|
222
|
+
constructor(message) {
|
|
223
|
+
super(message);
|
|
224
|
+
this.name = "TimeoutError";
|
|
225
|
+
}
|
|
226
|
+
};
|
|
227
|
+
var pTimeout = (promise, milliseconds, fallback) => new Promise((resolve, reject2) => {
|
|
228
|
+
if (typeof milliseconds !== "number" || milliseconds < 0) {
|
|
229
|
+
throw new TypeError("Expected `milliseconds` to be a positive number");
|
|
230
|
+
}
|
|
231
|
+
if (milliseconds === Infinity) {
|
|
232
|
+
resolve(promise);
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
const timer = setTimeout(() => {
|
|
236
|
+
if (typeof fallback === "function") {
|
|
237
|
+
try {
|
|
238
|
+
resolve(fallback());
|
|
239
|
+
} catch (error) {
|
|
240
|
+
reject2(error);
|
|
241
|
+
}
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
const message = typeof fallback === "string" ? fallback : `Promise timed out after ${milliseconds} milliseconds`;
|
|
245
|
+
const timeoutError = fallback instanceof Error ? fallback : new TimeoutError(message);
|
|
246
|
+
if (typeof promise.cancel === "function") {
|
|
247
|
+
promise.cancel();
|
|
248
|
+
}
|
|
249
|
+
reject2(timeoutError);
|
|
250
|
+
}, milliseconds);
|
|
251
|
+
pFinally(
|
|
252
|
+
// eslint-disable-next-line promise/prefer-await-to-then
|
|
253
|
+
promise.then(resolve, reject2),
|
|
254
|
+
() => {
|
|
255
|
+
clearTimeout(timer);
|
|
256
|
+
}
|
|
257
|
+
);
|
|
258
|
+
});
|
|
259
|
+
module2.exports = pTimeout;
|
|
260
|
+
module2.exports.default = pTimeout;
|
|
261
|
+
module2.exports.TimeoutError = TimeoutError;
|
|
262
|
+
}
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
// node_modules/p-queue/dist/lower-bound.js
|
|
266
|
+
var require_lower_bound = __commonJS({
|
|
267
|
+
"node_modules/p-queue/dist/lower-bound.js"(exports2) {
|
|
268
|
+
"use strict";
|
|
269
|
+
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
270
|
+
function lowerBound(array, value, comparator) {
|
|
271
|
+
let first = 0;
|
|
272
|
+
let count = array.length;
|
|
273
|
+
while (count > 0) {
|
|
274
|
+
const step = count / 2 | 0;
|
|
275
|
+
let it = first + step;
|
|
276
|
+
if (comparator(array[it], value) <= 0) {
|
|
277
|
+
first = ++it;
|
|
278
|
+
count -= step + 1;
|
|
279
|
+
} else {
|
|
280
|
+
count = step;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
return first;
|
|
284
|
+
}
|
|
285
|
+
exports2.default = lowerBound;
|
|
286
|
+
}
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
// node_modules/p-queue/dist/priority-queue.js
|
|
290
|
+
var require_priority_queue = __commonJS({
|
|
291
|
+
"node_modules/p-queue/dist/priority-queue.js"(exports2) {
|
|
292
|
+
"use strict";
|
|
293
|
+
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
294
|
+
var lower_bound_1 = require_lower_bound();
|
|
295
|
+
var PriorityQueue = class {
|
|
296
|
+
constructor() {
|
|
297
|
+
this._queue = [];
|
|
298
|
+
}
|
|
299
|
+
enqueue(run, options) {
|
|
300
|
+
options = Object.assign({ priority: 0 }, options);
|
|
301
|
+
const element = {
|
|
302
|
+
priority: options.priority,
|
|
303
|
+
run
|
|
304
|
+
};
|
|
305
|
+
if (this.size && this._queue[this.size - 1].priority >= options.priority) {
|
|
306
|
+
this._queue.push(element);
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
const index = lower_bound_1.default(this._queue, element, (a, b) => b.priority - a.priority);
|
|
310
|
+
this._queue.splice(index, 0, element);
|
|
311
|
+
}
|
|
312
|
+
dequeue() {
|
|
313
|
+
const item = this._queue.shift();
|
|
314
|
+
return item === null || item === void 0 ? void 0 : item.run;
|
|
315
|
+
}
|
|
316
|
+
filter(options) {
|
|
317
|
+
return this._queue.filter((element) => element.priority === options.priority).map((element) => element.run);
|
|
318
|
+
}
|
|
319
|
+
get size() {
|
|
320
|
+
return this._queue.length;
|
|
321
|
+
}
|
|
322
|
+
};
|
|
323
|
+
exports2.default = PriorityQueue;
|
|
324
|
+
}
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
// node_modules/p-queue/dist/index.js
|
|
328
|
+
var require_dist = __commonJS({
|
|
329
|
+
"node_modules/p-queue/dist/index.js"(exports2) {
|
|
330
|
+
"use strict";
|
|
331
|
+
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
332
|
+
var EventEmitter = require_eventemitter3();
|
|
333
|
+
var p_timeout_1 = require_p_timeout();
|
|
334
|
+
var priority_queue_1 = require_priority_queue();
|
|
335
|
+
var empty = () => {
|
|
336
|
+
};
|
|
337
|
+
var timeoutError = new p_timeout_1.TimeoutError();
|
|
338
|
+
var PQueue = class extends EventEmitter {
|
|
339
|
+
constructor(options) {
|
|
340
|
+
var _a, _b, _c, _d;
|
|
341
|
+
super();
|
|
342
|
+
this._intervalCount = 0;
|
|
343
|
+
this._intervalEnd = 0;
|
|
344
|
+
this._pendingCount = 0;
|
|
345
|
+
this._resolveEmpty = empty;
|
|
346
|
+
this._resolveIdle = empty;
|
|
347
|
+
options = Object.assign({ carryoverConcurrencyCount: false, intervalCap: Infinity, interval: 0, concurrency: Infinity, autoStart: true, queueClass: priority_queue_1.default }, options);
|
|
348
|
+
if (!(typeof options.intervalCap === "number" && options.intervalCap >= 1)) {
|
|
349
|
+
throw new TypeError(`Expected \`intervalCap\` to be a number from 1 and up, got \`${(_b = (_a = options.intervalCap) === null || _a === void 0 ? void 0 : _a.toString()) !== null && _b !== void 0 ? _b : ""}\` (${typeof options.intervalCap})`);
|
|
350
|
+
}
|
|
351
|
+
if (options.interval === void 0 || !(Number.isFinite(options.interval) && options.interval >= 0)) {
|
|
352
|
+
throw new TypeError(`Expected \`interval\` to be a finite number >= 0, got \`${(_d = (_c = options.interval) === null || _c === void 0 ? void 0 : _c.toString()) !== null && _d !== void 0 ? _d : ""}\` (${typeof options.interval})`);
|
|
353
|
+
}
|
|
354
|
+
this._carryoverConcurrencyCount = options.carryoverConcurrencyCount;
|
|
355
|
+
this._isIntervalIgnored = options.intervalCap === Infinity || options.interval === 0;
|
|
356
|
+
this._intervalCap = options.intervalCap;
|
|
357
|
+
this._interval = options.interval;
|
|
358
|
+
this._queue = new options.queueClass();
|
|
359
|
+
this._queueClass = options.queueClass;
|
|
360
|
+
this.concurrency = options.concurrency;
|
|
361
|
+
this._timeout = options.timeout;
|
|
362
|
+
this._throwOnTimeout = options.throwOnTimeout === true;
|
|
363
|
+
this._isPaused = options.autoStart === false;
|
|
364
|
+
}
|
|
365
|
+
get _doesIntervalAllowAnother() {
|
|
366
|
+
return this._isIntervalIgnored || this._intervalCount < this._intervalCap;
|
|
367
|
+
}
|
|
368
|
+
get _doesConcurrentAllowAnother() {
|
|
369
|
+
return this._pendingCount < this._concurrency;
|
|
370
|
+
}
|
|
371
|
+
_next() {
|
|
372
|
+
this._pendingCount--;
|
|
373
|
+
this._tryToStartAnother();
|
|
374
|
+
this.emit("next");
|
|
375
|
+
}
|
|
376
|
+
_resolvePromises() {
|
|
377
|
+
this._resolveEmpty();
|
|
378
|
+
this._resolveEmpty = empty;
|
|
379
|
+
if (this._pendingCount === 0) {
|
|
380
|
+
this._resolveIdle();
|
|
381
|
+
this._resolveIdle = empty;
|
|
382
|
+
this.emit("idle");
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
_onResumeInterval() {
|
|
386
|
+
this._onInterval();
|
|
387
|
+
this._initializeIntervalIfNeeded();
|
|
388
|
+
this._timeoutId = void 0;
|
|
389
|
+
}
|
|
390
|
+
_isIntervalPaused() {
|
|
391
|
+
const now = Date.now();
|
|
392
|
+
if (this._intervalId === void 0) {
|
|
393
|
+
const delay = this._intervalEnd - now;
|
|
394
|
+
if (delay < 0) {
|
|
395
|
+
this._intervalCount = this._carryoverConcurrencyCount ? this._pendingCount : 0;
|
|
396
|
+
} else {
|
|
397
|
+
if (this._timeoutId === void 0) {
|
|
398
|
+
this._timeoutId = setTimeout(() => {
|
|
399
|
+
this._onResumeInterval();
|
|
400
|
+
}, delay);
|
|
401
|
+
}
|
|
402
|
+
return true;
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
return false;
|
|
406
|
+
}
|
|
407
|
+
_tryToStartAnother() {
|
|
408
|
+
if (this._queue.size === 0) {
|
|
409
|
+
if (this._intervalId) {
|
|
410
|
+
clearInterval(this._intervalId);
|
|
411
|
+
}
|
|
412
|
+
this._intervalId = void 0;
|
|
413
|
+
this._resolvePromises();
|
|
414
|
+
return false;
|
|
415
|
+
}
|
|
416
|
+
if (!this._isPaused) {
|
|
417
|
+
const canInitializeInterval = !this._isIntervalPaused();
|
|
418
|
+
if (this._doesIntervalAllowAnother && this._doesConcurrentAllowAnother) {
|
|
419
|
+
const job = this._queue.dequeue();
|
|
420
|
+
if (!job) {
|
|
421
|
+
return false;
|
|
422
|
+
}
|
|
423
|
+
this.emit("active");
|
|
424
|
+
job();
|
|
425
|
+
if (canInitializeInterval) {
|
|
426
|
+
this._initializeIntervalIfNeeded();
|
|
427
|
+
}
|
|
428
|
+
return true;
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
return false;
|
|
432
|
+
}
|
|
433
|
+
_initializeIntervalIfNeeded() {
|
|
434
|
+
if (this._isIntervalIgnored || this._intervalId !== void 0) {
|
|
435
|
+
return;
|
|
436
|
+
}
|
|
437
|
+
this._intervalId = setInterval(() => {
|
|
438
|
+
this._onInterval();
|
|
439
|
+
}, this._interval);
|
|
440
|
+
this._intervalEnd = Date.now() + this._interval;
|
|
441
|
+
}
|
|
442
|
+
_onInterval() {
|
|
443
|
+
if (this._intervalCount === 0 && this._pendingCount === 0 && this._intervalId) {
|
|
444
|
+
clearInterval(this._intervalId);
|
|
445
|
+
this._intervalId = void 0;
|
|
446
|
+
}
|
|
447
|
+
this._intervalCount = this._carryoverConcurrencyCount ? this._pendingCount : 0;
|
|
448
|
+
this._processQueue();
|
|
449
|
+
}
|
|
450
|
+
/**
|
|
451
|
+
Executes all queued functions until it reaches the limit.
|
|
452
|
+
*/
|
|
453
|
+
_processQueue() {
|
|
454
|
+
while (this._tryToStartAnother()) {
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
get concurrency() {
|
|
458
|
+
return this._concurrency;
|
|
459
|
+
}
|
|
460
|
+
set concurrency(newConcurrency) {
|
|
461
|
+
if (!(typeof newConcurrency === "number" && newConcurrency >= 1)) {
|
|
462
|
+
throw new TypeError(`Expected \`concurrency\` to be a number from 1 and up, got \`${newConcurrency}\` (${typeof newConcurrency})`);
|
|
463
|
+
}
|
|
464
|
+
this._concurrency = newConcurrency;
|
|
465
|
+
this._processQueue();
|
|
466
|
+
}
|
|
467
|
+
/**
|
|
468
|
+
Adds a sync or async task to the queue. Always returns a promise.
|
|
469
|
+
*/
|
|
470
|
+
async add(fn, options = {}) {
|
|
471
|
+
return new Promise((resolve, reject2) => {
|
|
472
|
+
const run = async () => {
|
|
473
|
+
this._pendingCount++;
|
|
474
|
+
this._intervalCount++;
|
|
475
|
+
try {
|
|
476
|
+
const operation = this._timeout === void 0 && options.timeout === void 0 ? fn() : p_timeout_1.default(Promise.resolve(fn()), options.timeout === void 0 ? this._timeout : options.timeout, () => {
|
|
477
|
+
if (options.throwOnTimeout === void 0 ? this._throwOnTimeout : options.throwOnTimeout) {
|
|
478
|
+
reject2(timeoutError);
|
|
479
|
+
}
|
|
480
|
+
return void 0;
|
|
481
|
+
});
|
|
482
|
+
resolve(await operation);
|
|
483
|
+
} catch (error) {
|
|
484
|
+
reject2(error);
|
|
485
|
+
}
|
|
486
|
+
this._next();
|
|
487
|
+
};
|
|
488
|
+
this._queue.enqueue(run, options);
|
|
489
|
+
this._tryToStartAnother();
|
|
490
|
+
this.emit("add");
|
|
491
|
+
});
|
|
492
|
+
}
|
|
493
|
+
/**
|
|
494
|
+
Same as `.add()`, but accepts an array of sync or async functions.
|
|
495
|
+
|
|
496
|
+
@returns A promise that resolves when all functions are resolved.
|
|
497
|
+
*/
|
|
498
|
+
async addAll(functions, options) {
|
|
499
|
+
return Promise.all(functions.map(async (function_) => this.add(function_, options)));
|
|
500
|
+
}
|
|
501
|
+
/**
|
|
502
|
+
Start (or resume) executing enqueued tasks within concurrency limit. No need to call this if queue is not paused (via `options.autoStart = false` or by `.pause()` method.)
|
|
503
|
+
*/
|
|
504
|
+
start() {
|
|
505
|
+
if (!this._isPaused) {
|
|
506
|
+
return this;
|
|
507
|
+
}
|
|
508
|
+
this._isPaused = false;
|
|
509
|
+
this._processQueue();
|
|
510
|
+
return this;
|
|
511
|
+
}
|
|
512
|
+
/**
|
|
513
|
+
Put queue execution on hold.
|
|
514
|
+
*/
|
|
515
|
+
pause() {
|
|
516
|
+
this._isPaused = true;
|
|
517
|
+
}
|
|
518
|
+
/**
|
|
519
|
+
Clear the queue.
|
|
520
|
+
*/
|
|
521
|
+
clear() {
|
|
522
|
+
this._queue = new this._queueClass();
|
|
523
|
+
}
|
|
524
|
+
/**
|
|
525
|
+
Can be called multiple times. Useful if you for example add additional items at a later time.
|
|
526
|
+
|
|
527
|
+
@returns A promise that settles when the queue becomes empty.
|
|
528
|
+
*/
|
|
529
|
+
async onEmpty() {
|
|
530
|
+
if (this._queue.size === 0) {
|
|
531
|
+
return;
|
|
532
|
+
}
|
|
533
|
+
return new Promise((resolve) => {
|
|
534
|
+
const existingResolve = this._resolveEmpty;
|
|
535
|
+
this._resolveEmpty = () => {
|
|
536
|
+
existingResolve();
|
|
537
|
+
resolve();
|
|
538
|
+
};
|
|
539
|
+
});
|
|
540
|
+
}
|
|
541
|
+
/**
|
|
542
|
+
The difference with `.onEmpty` is that `.onIdle` guarantees that all work from the queue has finished. `.onEmpty` merely signals that the queue is empty, but it could mean that some promises haven't completed yet.
|
|
543
|
+
|
|
544
|
+
@returns A promise that settles when the queue becomes empty, and all promises have completed; `queue.size === 0 && queue.pending === 0`.
|
|
545
|
+
*/
|
|
546
|
+
async onIdle() {
|
|
547
|
+
if (this._pendingCount === 0 && this._queue.size === 0) {
|
|
548
|
+
return;
|
|
549
|
+
}
|
|
550
|
+
return new Promise((resolve) => {
|
|
551
|
+
const existingResolve = this._resolveIdle;
|
|
552
|
+
this._resolveIdle = () => {
|
|
553
|
+
existingResolve();
|
|
554
|
+
resolve();
|
|
555
|
+
};
|
|
556
|
+
});
|
|
557
|
+
}
|
|
558
|
+
/**
|
|
559
|
+
Size of the queue.
|
|
560
|
+
*/
|
|
561
|
+
get size() {
|
|
562
|
+
return this._queue.size;
|
|
563
|
+
}
|
|
564
|
+
/**
|
|
565
|
+
Size of the queue, filtered by the given options.
|
|
566
|
+
|
|
567
|
+
For example, this can be used to find the number of items remaining in the queue with a specific priority level.
|
|
568
|
+
*/
|
|
569
|
+
sizeBy(options) {
|
|
570
|
+
return this._queue.filter(options).length;
|
|
571
|
+
}
|
|
572
|
+
/**
|
|
573
|
+
Number of pending promises.
|
|
574
|
+
*/
|
|
575
|
+
get pending() {
|
|
576
|
+
return this._pendingCount;
|
|
577
|
+
}
|
|
578
|
+
/**
|
|
579
|
+
Whether the queue is currently paused.
|
|
580
|
+
*/
|
|
581
|
+
get isPaused() {
|
|
582
|
+
return this._isPaused;
|
|
583
|
+
}
|
|
584
|
+
get timeout() {
|
|
585
|
+
return this._timeout;
|
|
586
|
+
}
|
|
587
|
+
/**
|
|
588
|
+
Set the timeout for future operations.
|
|
589
|
+
*/
|
|
590
|
+
set timeout(milliseconds) {
|
|
591
|
+
this._timeout = milliseconds;
|
|
592
|
+
}
|
|
593
|
+
};
|
|
594
|
+
exports2.default = PQueue;
|
|
595
|
+
}
|
|
596
|
+
});
|
|
597
|
+
|
|
20
598
|
// src/index.ts
|
|
21
599
|
var index_exports = {};
|
|
22
600
|
__export(index_exports, {
|
|
601
|
+
ColbertAdapter: () => ColbertAdapter,
|
|
602
|
+
InfoNCETrainer: () => InfoNCETrainer,
|
|
23
603
|
IntentAdapter: () => IntentAdapter,
|
|
24
604
|
IntentTrainer: () => IntentTrainer,
|
|
25
605
|
LoraIntentAdapter: () => LoraIntentAdapter,
|
|
26
606
|
MigrationTrainer: () => MigrationTrainer,
|
|
607
|
+
MlpAdapter: () => MlpAdapter,
|
|
27
608
|
ProjectionAdapter: () => ProjectionAdapter,
|
|
609
|
+
QuantizationAdapter: () => QuantizationAdapter,
|
|
610
|
+
TaskArithmetic: () => TaskArithmetic,
|
|
611
|
+
TripletTrainer: () => TripletTrainer,
|
|
28
612
|
VectorDBAdapter: () => VectorDBAdapter,
|
|
613
|
+
VsaAdapter: () => VsaAdapter,
|
|
614
|
+
WarpEmbeddings: () => WarpEmbeddings,
|
|
615
|
+
WarpLlamaIndexEmbeddings: () => WarpLlamaIndexEmbeddings,
|
|
616
|
+
WarpPipeline: () => WarpPipeline,
|
|
617
|
+
WhiteningAdapter: () => WhiteningAdapter,
|
|
618
|
+
addScaledVector: () => addScaledVector,
|
|
29
619
|
applyActivationToVector: () => applyActivationToVector,
|
|
620
|
+
applyAffine: () => applyAffine,
|
|
30
621
|
assertDimension: () => assertDimension,
|
|
31
622
|
cosineSimilarity: () => cosineSimilarity,
|
|
32
623
|
flattenMatrix: () => flattenMatrix,
|
|
624
|
+
getFlatMatrixAndBias: () => getFlatMatrixAndBias,
|
|
33
625
|
innerProduct: () => innerProduct,
|
|
626
|
+
integrations: () => integrations_exports,
|
|
34
627
|
normalize: () => normalize,
|
|
35
628
|
reject: () => reject,
|
|
629
|
+
rrf: () => rrf,
|
|
630
|
+
rsf: () => rsf,
|
|
36
631
|
slerp: () => slerp,
|
|
37
|
-
softmax: () => softmax
|
|
632
|
+
softmax: () => softmax,
|
|
633
|
+
withWarpVector: () => withWarpVector
|
|
38
634
|
});
|
|
39
635
|
module.exports = __toCommonJS(index_exports);
|
|
40
636
|
|
|
@@ -106,6 +702,15 @@ function innerProduct(v1, v2) {
|
|
|
106
702
|
}
|
|
107
703
|
return dot;
|
|
108
704
|
}
|
|
705
|
+
function addScaledVector(target, source, scale = 1) {
|
|
706
|
+
const dim = target.length;
|
|
707
|
+
if (dim !== source.length) {
|
|
708
|
+
throw new Error("Vectors must have the same dimension.");
|
|
709
|
+
}
|
|
710
|
+
for (let i = 0; i < dim; i++) {
|
|
711
|
+
target[i] += scale * source[i];
|
|
712
|
+
}
|
|
713
|
+
}
|
|
109
714
|
function cosineSimilarity(v1, v2) {
|
|
110
715
|
const dim = v1.length;
|
|
111
716
|
if (dim !== v2.length) {
|
|
@@ -149,7 +754,7 @@ function reject(baseVector, negativeVector) {
|
|
|
149
754
|
return result;
|
|
150
755
|
}
|
|
151
756
|
function applyActivationToVector(vector, activation) {
|
|
152
|
-
if (!activation) return;
|
|
757
|
+
if (!activation || activation === "linear") return;
|
|
153
758
|
const dim = vector.length;
|
|
154
759
|
if (activation === "relu") {
|
|
155
760
|
for (let i = 0; i < dim; i++) {
|
|
@@ -202,17 +807,34 @@ function assertDimension(vector, expectedDimension, contextName = "Vector") {
|
|
|
202
807
|
);
|
|
203
808
|
}
|
|
204
809
|
}
|
|
810
|
+
function getFlatMatrixAndBias(weights, dim, contextName = "Weights") {
|
|
811
|
+
let flatMatrix;
|
|
812
|
+
if (weights.matrix instanceof Float32Array) {
|
|
813
|
+
flatMatrix = new Float32Array(weights.matrix);
|
|
814
|
+
} else {
|
|
815
|
+
flatMatrix = flattenMatrix(weights.matrix, dim, dim, contextName);
|
|
816
|
+
}
|
|
817
|
+
const bias = new Float32Array(weights.bias);
|
|
818
|
+
return { flatMatrix, bias };
|
|
819
|
+
}
|
|
820
|
+
function applyAffine(matrix, bias, vector, result, inDim, outDim = inDim) {
|
|
821
|
+
for (let i = 0; i < outDim; i++) {
|
|
822
|
+
let sum = bias ? bias[i] : 0;
|
|
823
|
+
const rowOffset = i * inDim;
|
|
824
|
+
for (let j = 0; j < inDim; j++) {
|
|
825
|
+
sum += matrix[rowOffset + j] * vector[j];
|
|
826
|
+
}
|
|
827
|
+
result[i] = sum;
|
|
828
|
+
}
|
|
829
|
+
}
|
|
205
830
|
|
|
206
831
|
// src/wasm/wasm-binary.ts
|
|
207
|
-
var wasmBase64 = "
|
|
832
|
+
var wasmBase64 = "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";
|
|
208
833
|
|
|
209
834
|
// src/wasm/wasm-loader.ts
|
|
210
835
|
var wasmInstance = null;
|
|
211
836
|
var wasmMemory = null;
|
|
212
837
|
var initPromise = null;
|
|
213
|
-
function getWasmMemory() {
|
|
214
|
-
return wasmMemory;
|
|
215
|
-
}
|
|
216
838
|
function getWasmInstance() {
|
|
217
839
|
return wasmInstance;
|
|
218
840
|
}
|
|
@@ -245,9 +867,37 @@ function ensureWasmMemory(requiredBytes) {
|
|
|
245
867
|
return false;
|
|
246
868
|
}
|
|
247
869
|
}
|
|
870
|
+
var globalOffset = 65536;
|
|
871
|
+
function allocateWasmMemory(bytes) {
|
|
872
|
+
const ptr = globalOffset;
|
|
873
|
+
globalOffset += bytes;
|
|
874
|
+
if (globalOffset % 4 !== 0) {
|
|
875
|
+
globalOffset += 4 - globalOffset % 4;
|
|
876
|
+
}
|
|
877
|
+
ensureWasmMemory(globalOffset);
|
|
878
|
+
return ptr;
|
|
879
|
+
}
|
|
880
|
+
function getWasmAllocatorOffset() {
|
|
881
|
+
return globalOffset;
|
|
882
|
+
}
|
|
883
|
+
function setWasmAllocatorOffset(offset) {
|
|
884
|
+
globalOffset = offset;
|
|
885
|
+
}
|
|
886
|
+
function writeFloat32ArrayToWasm(memory, data, byteOffset) {
|
|
887
|
+
const f32 = new Float32Array(memory.buffer);
|
|
888
|
+
const floatOffset = byteOffset / 4;
|
|
889
|
+
if (data instanceof Float32Array) {
|
|
890
|
+
f32.set(data, floatOffset);
|
|
891
|
+
} else {
|
|
892
|
+
for (let i = 0; i < data.length; i++) {
|
|
893
|
+
f32[floatOffset + i] = data[i];
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
}
|
|
248
897
|
|
|
249
898
|
// src/IntentAdapter.ts
|
|
250
|
-
var IntentAdapter = class {
|
|
899
|
+
var IntentAdapter = class _IntentAdapter {
|
|
900
|
+
weightsMap = /* @__PURE__ */ new Map();
|
|
251
901
|
dimension;
|
|
252
902
|
matrices;
|
|
253
903
|
biases;
|
|
@@ -290,6 +940,7 @@ var IntentAdapter = class {
|
|
|
290
940
|
*/
|
|
291
941
|
addIntent(intentName, weights) {
|
|
292
942
|
const { matrix, bias, routingVector } = weights;
|
|
943
|
+
this.weightsMap.set(intentName, weights);
|
|
293
944
|
assertDimension(bias, this.dimension, `Intent '${intentName}' Bias`);
|
|
294
945
|
let flatMatrix;
|
|
295
946
|
if (matrix instanceof Float32Array) {
|
|
@@ -328,27 +979,9 @@ var IntentAdapter = class {
|
|
|
328
979
|
this.matrices.delete(intentName);
|
|
329
980
|
this.biases.delete(intentName);
|
|
330
981
|
this.routingVectors.delete(intentName);
|
|
982
|
+
this.weightsMap.delete(intentName);
|
|
331
983
|
}
|
|
332
|
-
|
|
333
|
-
* 行列とバイアスを用いてベクトルにアフィン変換を適用する内部関数 (x' = W * x + b)
|
|
334
|
-
*
|
|
335
|
-
* @param {Float32Array} matrix - フラット化された変換行列
|
|
336
|
-
* @param {Float32Array} bias - バイアスベクトル
|
|
337
|
-
* @param {number[] | Float32Array} vector - 変換元の入力ベクトル
|
|
338
|
-
* @param {Float32Array} result - 計算結果を格納する配列 (出力先)
|
|
339
|
-
* @returns {void}
|
|
340
|
-
*/
|
|
341
|
-
applyAffine(matrix, bias, vector, result) {
|
|
342
|
-
const dim = this.dimension;
|
|
343
|
-
for (let i = 0; i < dim; i++) {
|
|
344
|
-
let sum = 0;
|
|
345
|
-
const rowOffset = i * dim;
|
|
346
|
-
for (let j = 0; j < dim; j++) {
|
|
347
|
-
sum += matrix[rowOffset + j] * vector[j];
|
|
348
|
-
}
|
|
349
|
-
result[i] = sum + bias[i];
|
|
350
|
-
}
|
|
351
|
-
}
|
|
984
|
+
// (Private applyAffine was removed in favor of utils.ts applyAffine)
|
|
352
985
|
/**
|
|
353
986
|
* 複数の意図を指定された重みでブレンドした一時的な行列とバイアスを計算します。
|
|
354
987
|
* W_blend = Σ(w_i * W_i), b_blend = Σ(w_i * b_i)
|
|
@@ -367,13 +1000,8 @@ var IntentAdapter = class {
|
|
|
367
1000
|
if (!matrix || !bias) {
|
|
368
1001
|
throw new Error(`Intent '${intentName}' not found during blending.`);
|
|
369
1002
|
}
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
const rowOffset = i * dim;
|
|
373
|
-
for (let j = 0; j < dim; j++) {
|
|
374
|
-
blendedMatrix[rowOffset + j] += matrix[rowOffset + j] * weight;
|
|
375
|
-
}
|
|
376
|
-
}
|
|
1003
|
+
addScaledVector(blendedBias, bias, weight);
|
|
1004
|
+
addScaledVector(blendedMatrix, matrix, weight);
|
|
377
1005
|
}
|
|
378
1006
|
return { matrix: blendedMatrix, bias: blendedBias };
|
|
379
1007
|
}
|
|
@@ -395,7 +1023,7 @@ var IntentAdapter = class {
|
|
|
395
1023
|
throw new Error(`Intent '${intent}' not found.`);
|
|
396
1024
|
}
|
|
397
1025
|
const result = new Float32Array(this.dimension);
|
|
398
|
-
|
|
1026
|
+
applyAffine(matrix, bias, baseVector, result, this.dimension);
|
|
399
1027
|
applyActivationToVector(result, activation);
|
|
400
1028
|
return result;
|
|
401
1029
|
}
|
|
@@ -419,35 +1047,39 @@ var IntentAdapter = class {
|
|
|
419
1047
|
const instance = getWasmInstance();
|
|
420
1048
|
const requiredBytes = (this.dimension * this.dimension + this.dimension + batchSize * this.dimension * 2) * 4;
|
|
421
1049
|
if (instance && ensureWasmMemory(requiredBytes)) {
|
|
422
|
-
const
|
|
423
|
-
const f32Mem = new Float32Array(wasmMem.buffer);
|
|
1050
|
+
const memory = instance.exports.memory;
|
|
424
1051
|
let ptr = 0;
|
|
425
1052
|
const matrixPtr = ptr;
|
|
426
|
-
|
|
427
|
-
ptr += this.dimension * this.dimension;
|
|
1053
|
+
writeFloat32ArrayToWasm(memory, matrix, ptr);
|
|
1054
|
+
ptr += this.dimension * this.dimension * 4;
|
|
428
1055
|
const biasPtr = ptr;
|
|
429
|
-
|
|
430
|
-
ptr += this.dimension;
|
|
1056
|
+
writeFloat32ArrayToWasm(memory, bias, ptr);
|
|
1057
|
+
ptr += this.dimension * 4;
|
|
431
1058
|
const vectorsPtr = ptr;
|
|
432
1059
|
for (let k = 0; k < batchSize; k++) {
|
|
433
|
-
|
|
1060
|
+
writeFloat32ArrayToWasm(
|
|
1061
|
+
memory,
|
|
1062
|
+
baseVectors[k],
|
|
1063
|
+
ptr + k * this.dimension * 4
|
|
1064
|
+
);
|
|
434
1065
|
}
|
|
435
|
-
ptr += batchSize * this.dimension;
|
|
1066
|
+
ptr += batchSize * this.dimension * 4;
|
|
436
1067
|
const resultsPtr = ptr;
|
|
437
1068
|
const tuneBatchWasm = instance.exports.tuneBatchWasm;
|
|
438
1069
|
tuneBatchWasm(
|
|
439
|
-
matrixPtr
|
|
440
|
-
biasPtr
|
|
441
|
-
vectorsPtr
|
|
442
|
-
resultsPtr
|
|
1070
|
+
matrixPtr,
|
|
1071
|
+
biasPtr,
|
|
1072
|
+
vectorsPtr,
|
|
1073
|
+
resultsPtr,
|
|
443
1074
|
this.dimension,
|
|
444
1075
|
batchSize
|
|
445
1076
|
);
|
|
446
1077
|
const results2 = new Array(batchSize);
|
|
1078
|
+
const outF32Mem = new Float32Array(memory.buffer);
|
|
447
1079
|
for (let k = 0; k < batchSize; k++) {
|
|
448
|
-
const res =
|
|
449
|
-
resultsPtr + k * this.dimension,
|
|
450
|
-
resultsPtr + (k + 1) * this.dimension
|
|
1080
|
+
const res = outF32Mem.slice(
|
|
1081
|
+
resultsPtr / 4 + k * this.dimension,
|
|
1082
|
+
resultsPtr / 4 + (k + 1) * this.dimension
|
|
451
1083
|
);
|
|
452
1084
|
applyActivationToVector(res, activation);
|
|
453
1085
|
results2[k] = res;
|
|
@@ -459,7 +1091,7 @@ var IntentAdapter = class {
|
|
|
459
1091
|
const baseVector = baseVectors[k];
|
|
460
1092
|
assertDimension(baseVector, this.dimension, `Base vector at index ${k}`);
|
|
461
1093
|
const result = new Float32Array(this.dimension);
|
|
462
|
-
|
|
1094
|
+
applyAffine(matrix, bias, baseVector, result, this.dimension);
|
|
463
1095
|
applyActivationToVector(result, activation);
|
|
464
1096
|
results[k] = result;
|
|
465
1097
|
}
|
|
@@ -478,7 +1110,7 @@ var IntentAdapter = class {
|
|
|
478
1110
|
assertDimension(baseVector, this.dimension, "Base vector");
|
|
479
1111
|
const { matrix, bias } = this.computeBlendedWeights(blendWeights);
|
|
480
1112
|
const result = new Float32Array(this.dimension);
|
|
481
|
-
|
|
1113
|
+
applyAffine(matrix, bias, baseVector, result, this.dimension);
|
|
482
1114
|
applyActivationToVector(result, activation);
|
|
483
1115
|
return result;
|
|
484
1116
|
}
|
|
@@ -498,35 +1130,39 @@ var IntentAdapter = class {
|
|
|
498
1130
|
const instance = getWasmInstance();
|
|
499
1131
|
const requiredBytes = (this.dimension * this.dimension + this.dimension + batchSize * this.dimension * 2) * 4;
|
|
500
1132
|
if (instance && ensureWasmMemory(requiredBytes)) {
|
|
501
|
-
const
|
|
502
|
-
const f32Mem = new Float32Array(wasmMem.buffer);
|
|
1133
|
+
const memory = instance.exports.memory;
|
|
503
1134
|
let ptr = 0;
|
|
504
1135
|
const matrixPtr = ptr;
|
|
505
|
-
|
|
506
|
-
ptr += this.dimension * this.dimension;
|
|
1136
|
+
writeFloat32ArrayToWasm(memory, matrix, ptr);
|
|
1137
|
+
ptr += this.dimension * this.dimension * 4;
|
|
507
1138
|
const biasPtr = ptr;
|
|
508
|
-
|
|
509
|
-
ptr += this.dimension;
|
|
1139
|
+
writeFloat32ArrayToWasm(memory, bias, ptr);
|
|
1140
|
+
ptr += this.dimension * 4;
|
|
510
1141
|
const vectorsPtr = ptr;
|
|
511
1142
|
for (let k = 0; k < batchSize; k++) {
|
|
512
|
-
|
|
1143
|
+
writeFloat32ArrayToWasm(
|
|
1144
|
+
memory,
|
|
1145
|
+
baseVectors[k],
|
|
1146
|
+
ptr + k * this.dimension * 4
|
|
1147
|
+
);
|
|
513
1148
|
}
|
|
514
|
-
ptr += batchSize * this.dimension;
|
|
1149
|
+
ptr += batchSize * this.dimension * 4;
|
|
515
1150
|
const resultsPtr = ptr;
|
|
516
1151
|
const tuneBatchWasm = instance.exports.tuneBatchWasm;
|
|
517
1152
|
tuneBatchWasm(
|
|
518
|
-
matrixPtr
|
|
519
|
-
biasPtr
|
|
520
|
-
vectorsPtr
|
|
521
|
-
resultsPtr
|
|
1153
|
+
matrixPtr,
|
|
1154
|
+
biasPtr,
|
|
1155
|
+
vectorsPtr,
|
|
1156
|
+
resultsPtr,
|
|
522
1157
|
this.dimension,
|
|
523
1158
|
batchSize
|
|
524
1159
|
);
|
|
525
1160
|
const results2 = new Array(batchSize);
|
|
1161
|
+
const outF32Mem = new Float32Array(memory.buffer);
|
|
526
1162
|
for (let k = 0; k < batchSize; k++) {
|
|
527
|
-
const res =
|
|
528
|
-
resultsPtr + k * this.dimension,
|
|
529
|
-
resultsPtr + (k + 1) * this.dimension
|
|
1163
|
+
const res = outF32Mem.slice(
|
|
1164
|
+
resultsPtr / 4 + k * this.dimension,
|
|
1165
|
+
resultsPtr / 4 + (k + 1) * this.dimension
|
|
530
1166
|
);
|
|
531
1167
|
applyActivationToVector(res, activation);
|
|
532
1168
|
results2[k] = res;
|
|
@@ -538,7 +1174,7 @@ var IntentAdapter = class {
|
|
|
538
1174
|
const baseVector = baseVectors[k];
|
|
539
1175
|
assertDimension(baseVector, this.dimension, `Base vector at index ${k}`);
|
|
540
1176
|
const result = new Float32Array(this.dimension);
|
|
541
|
-
|
|
1177
|
+
applyAffine(matrix, bias, baseVector, result, this.dimension);
|
|
542
1178
|
applyActivationToVector(result, activation);
|
|
543
1179
|
results[k] = result;
|
|
544
1180
|
}
|
|
@@ -669,10 +1305,42 @@ var IntentAdapter = class {
|
|
|
669
1305
|
this.routingVectors.set(intentName, routingVector);
|
|
670
1306
|
}
|
|
671
1307
|
}
|
|
1308
|
+
/**
|
|
1309
|
+
* 現在の IntentAdapter の全状態(全インテント)を JSON としてシリアライズしてエクスポートします。
|
|
1310
|
+
* (WarpPipeline 等の統合管理用)
|
|
1311
|
+
*/
|
|
1312
|
+
exportState() {
|
|
1313
|
+
const intents = {};
|
|
1314
|
+
for (const [name, matrix] of this.matrices.entries()) {
|
|
1315
|
+
const bias = this.biases.get(name);
|
|
1316
|
+
const routing = this.routingVectors.get(name);
|
|
1317
|
+
intents[name] = {
|
|
1318
|
+
matrix: Array.from(matrix),
|
|
1319
|
+
bias: Array.from(bias),
|
|
1320
|
+
routingVector: routing ? Array.from(routing) : void 0
|
|
1321
|
+
};
|
|
1322
|
+
}
|
|
1323
|
+
return JSON.stringify({ dimension: this.dimension, intents });
|
|
1324
|
+
}
|
|
1325
|
+
/**
|
|
1326
|
+
* エクスポートされた JSON 状態から IntentAdapter を復元します。
|
|
1327
|
+
*/
|
|
1328
|
+
static importState(stateJson) {
|
|
1329
|
+
const data = JSON.parse(stateJson);
|
|
1330
|
+
const adapter = new _IntentAdapter(data.dimension);
|
|
1331
|
+
for (const [name, intent] of Object.entries(data.intents)) {
|
|
1332
|
+
adapter.addIntent(name, {
|
|
1333
|
+
matrix: new Float32Array(intent.matrix),
|
|
1334
|
+
bias: new Float32Array(intent.bias),
|
|
1335
|
+
routingVector: intent.routingVector ? new Float32Array(intent.routingVector) : void 0
|
|
1336
|
+
});
|
|
1337
|
+
}
|
|
1338
|
+
return adapter;
|
|
1339
|
+
}
|
|
672
1340
|
};
|
|
673
1341
|
|
|
674
1342
|
// src/LoraIntentAdapter.ts
|
|
675
|
-
var LoraIntentAdapter = class {
|
|
1343
|
+
var LoraIntentAdapter = class _LoraIntentAdapter {
|
|
676
1344
|
dimension;
|
|
677
1345
|
rank;
|
|
678
1346
|
// フラット化されたAとBの行列、およびバイアスを保存
|
|
@@ -759,30 +1427,114 @@ var LoraIntentAdapter = class {
|
|
|
759
1427
|
}
|
|
760
1428
|
const result = new Float32Array(this.dimension);
|
|
761
1429
|
const y = new Float32Array(this.rank);
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
1430
|
+
applyAffine(matB, null, baseVector, y, this.dimension, this.rank);
|
|
1431
|
+
applyAffine(matA, bias, y, result, this.rank, this.dimension);
|
|
1432
|
+
addScaledVector(result, baseVector, 1);
|
|
1433
|
+
return result;
|
|
1434
|
+
}
|
|
1435
|
+
/**
|
|
1436
|
+
* 現在の LoraIntentAdapter の全状態を JSON としてエクスポートします。
|
|
1437
|
+
*/
|
|
1438
|
+
exportState() {
|
|
1439
|
+
const intents = {};
|
|
1440
|
+
for (const [name, flatA] of this.matricesA.entries()) {
|
|
1441
|
+
const flatB = this.matricesB.get(name);
|
|
1442
|
+
const bias = this.biases.get(name);
|
|
1443
|
+
intents[name] = {
|
|
1444
|
+
matrixA: Array.from(flatA),
|
|
1445
|
+
// export as flattened for simplicity during import
|
|
1446
|
+
matrixB: Array.from(flatB),
|
|
1447
|
+
bias: Array.from(bias)
|
|
1448
|
+
};
|
|
1449
|
+
}
|
|
1450
|
+
return JSON.stringify({
|
|
1451
|
+
dimension: this.dimension,
|
|
1452
|
+
rank: this.rank,
|
|
1453
|
+
intents
|
|
1454
|
+
});
|
|
1455
|
+
}
|
|
1456
|
+
/**
|
|
1457
|
+
* エクスポートされた JSON 状態から LoraIntentAdapter を復元します。
|
|
1458
|
+
*/
|
|
1459
|
+
static importState(stateJson) {
|
|
1460
|
+
const data = JSON.parse(stateJson);
|
|
1461
|
+
const adapter = new _LoraIntentAdapter(data.dimension, data.rank);
|
|
1462
|
+
for (const [name, intent] of Object.entries(data.intents)) {
|
|
1463
|
+
adapter.matricesA.set(name, new Float32Array(intent.matrixA));
|
|
1464
|
+
adapter.matricesB.set(name, new Float32Array(intent.matrixB));
|
|
1465
|
+
adapter.biases.set(name, new Float32Array(intent.bias));
|
|
1466
|
+
}
|
|
1467
|
+
return adapter;
|
|
1468
|
+
}
|
|
1469
|
+
};
|
|
1470
|
+
|
|
1471
|
+
// src/fusion/rrf.ts
|
|
1472
|
+
function rrf(resultSets, k = 60) {
|
|
1473
|
+
const scoreMap = /* @__PURE__ */ new Map();
|
|
1474
|
+
for (const resultSet of resultSets) {
|
|
1475
|
+
for (let i = 0; i < resultSet.length; i++) {
|
|
1476
|
+
const item = resultSet[i];
|
|
1477
|
+
const rank = item.rank !== void 0 ? item.rank : i + 1;
|
|
1478
|
+
const rrfScore = 1 / (k + rank);
|
|
1479
|
+
if (scoreMap.has(item.id)) {
|
|
1480
|
+
const existing = scoreMap.get(item.id);
|
|
1481
|
+
existing.score += rrfScore;
|
|
1482
|
+
existing.metadata = { ...existing.metadata, ...item.metadata };
|
|
1483
|
+
} else {
|
|
1484
|
+
scoreMap.set(item.id, {
|
|
1485
|
+
id: item.id,
|
|
1486
|
+
score: rrfScore,
|
|
1487
|
+
metadata: item.metadata
|
|
1488
|
+
});
|
|
767
1489
|
}
|
|
768
|
-
y[i] = sum;
|
|
769
1490
|
}
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
1491
|
+
}
|
|
1492
|
+
return Array.from(scoreMap.values()).sort((a, b) => b.score - a.score);
|
|
1493
|
+
}
|
|
1494
|
+
|
|
1495
|
+
// src/fusion/rsf.ts
|
|
1496
|
+
function rsf(resultSets, weights) {
|
|
1497
|
+
if (weights && weights.length !== resultSets.length) {
|
|
1498
|
+
throw new Error("Weights array length must match resultSets length");
|
|
1499
|
+
}
|
|
1500
|
+
const scoreMap = /* @__PURE__ */ new Map();
|
|
1501
|
+
for (let sIdx = 0; sIdx < resultSets.length; sIdx++) {
|
|
1502
|
+
const resultSet = resultSets[sIdx];
|
|
1503
|
+
const weight = weights ? weights[sIdx] : 1;
|
|
1504
|
+
if (resultSet.length === 0) continue;
|
|
1505
|
+
let min = Infinity;
|
|
1506
|
+
let max = -Infinity;
|
|
1507
|
+
for (const item of resultSet) {
|
|
1508
|
+
const score = item.score !== void 0 ? item.score : 0;
|
|
1509
|
+
if (score < min) min = score;
|
|
1510
|
+
if (score > max) max = score;
|
|
1511
|
+
}
|
|
1512
|
+
const range = max - min;
|
|
1513
|
+
for (const item of resultSet) {
|
|
1514
|
+
const score = item.score !== void 0 ? item.score : 0;
|
|
1515
|
+
const normalizedScore = range === 0 ? 1 : (score - min) / range;
|
|
1516
|
+
const weightedScore = normalizedScore * weight;
|
|
1517
|
+
if (scoreMap.has(item.id)) {
|
|
1518
|
+
const existing = scoreMap.get(item.id);
|
|
1519
|
+
existing.score += weightedScore;
|
|
1520
|
+
existing.metadata = { ...existing.metadata, ...item.metadata };
|
|
1521
|
+
} else {
|
|
1522
|
+
scoreMap.set(item.id, {
|
|
1523
|
+
id: item.id,
|
|
1524
|
+
score: weightedScore,
|
|
1525
|
+
metadata: item.metadata
|
|
1526
|
+
});
|
|
775
1527
|
}
|
|
776
|
-
result[i] = baseVector[i] + sum + bias[i];
|
|
777
1528
|
}
|
|
778
|
-
return result;
|
|
779
1529
|
}
|
|
780
|
-
|
|
1530
|
+
return Array.from(scoreMap.values()).sort((a, b) => b.score - a.score);
|
|
1531
|
+
}
|
|
781
1532
|
|
|
782
1533
|
// src/ProjectionAdapter.ts
|
|
783
|
-
var ProjectionAdapter = class {
|
|
1534
|
+
var ProjectionAdapter = class _ProjectionAdapter {
|
|
784
1535
|
inDimension;
|
|
785
1536
|
outDimension;
|
|
1537
|
+
wasmInstance = null;
|
|
786
1538
|
// フラット化された射影行列とバイアスを保存
|
|
787
1539
|
matrices;
|
|
788
1540
|
biases;
|
|
@@ -844,79 +1596,1305 @@ var ProjectionAdapter = class {
|
|
|
844
1596
|
this.biases.delete(name);
|
|
845
1597
|
}
|
|
846
1598
|
/**
|
|
847
|
-
*
|
|
848
|
-
*
|
|
1599
|
+
* ベクトルの次元削減(射影)を実行します。
|
|
1600
|
+
* (WarpAdapter の実装として project の代わりに tune を提供します)
|
|
849
1601
|
*
|
|
850
|
-
* @param
|
|
851
|
-
* @param
|
|
852
|
-
* @returns
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
const
|
|
1602
|
+
* @param vector 変換前のベクトル (例: 1536次元)
|
|
1603
|
+
* @param version 適用する変換バージョンの識別子 (オプション)
|
|
1604
|
+
* @returns 変換後のベクトル (例: 512次元)
|
|
1605
|
+
*/
|
|
1606
|
+
tune(vector, version = "default") {
|
|
1607
|
+
assertDimension(vector, this.inDimension, "Base vector");
|
|
1608
|
+
const matrix = this.matrices.get(version);
|
|
1609
|
+
const bias = this.biases.get(version);
|
|
858
1610
|
if (!matrix) {
|
|
859
|
-
throw new Error(`Projection '${
|
|
1611
|
+
throw new Error(`Projection '${version}' not found.`);
|
|
860
1612
|
}
|
|
861
|
-
const
|
|
862
|
-
const
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
1613
|
+
const instance = getWasmInstance();
|
|
1614
|
+
const matrixSize = this.inDimension * this.outDimension * 4;
|
|
1615
|
+
const biasSize = bias ? this.outDimension * 4 : 0;
|
|
1616
|
+
const vectorSize = this.inDimension * 4;
|
|
1617
|
+
const outputSize = this.outDimension * 4;
|
|
1618
|
+
const requiredBytes = matrixSize + biasSize + vectorSize + outputSize;
|
|
1619
|
+
if (instance && instance.exports.projectWasm && ensureWasmMemory(requiredBytes)) {
|
|
1620
|
+
const memory = instance.exports.memory;
|
|
1621
|
+
let offset = 0;
|
|
1622
|
+
const matrixPtr = offset;
|
|
1623
|
+
offset += matrixSize;
|
|
1624
|
+
const biasPtr = bias ? offset : 0;
|
|
1625
|
+
if (bias) offset += biasSize;
|
|
1626
|
+
const inputPtr = offset;
|
|
1627
|
+
offset += vectorSize;
|
|
1628
|
+
const outputPtr = offset;
|
|
1629
|
+
offset += outputSize;
|
|
1630
|
+
writeFloat32ArrayToWasm(memory, matrix, matrixPtr);
|
|
1631
|
+
if (bias) writeFloat32ArrayToWasm(memory, bias, biasPtr);
|
|
1632
|
+
writeFloat32ArrayToWasm(memory, vector, inputPtr);
|
|
1633
|
+
const projectWasm = instance.exports.projectWasm;
|
|
1634
|
+
projectWasm(
|
|
1635
|
+
matrixPtr,
|
|
1636
|
+
biasPtr,
|
|
1637
|
+
inputPtr,
|
|
1638
|
+
outputPtr,
|
|
1639
|
+
this.inDimension,
|
|
1640
|
+
this.outDimension
|
|
1641
|
+
);
|
|
1642
|
+
const result2 = new Float32Array(this.outDimension);
|
|
1643
|
+
const outF32 = new Float32Array(memory.buffer);
|
|
1644
|
+
const outIdx = outputPtr / 4;
|
|
1645
|
+
for (let i = 0; i < this.outDimension; i++) {
|
|
1646
|
+
result2[i] = outF32[outIdx + i];
|
|
868
1647
|
}
|
|
869
|
-
|
|
1648
|
+
return result2;
|
|
870
1649
|
}
|
|
1650
|
+
const result = new Float32Array(this.outDimension);
|
|
1651
|
+
applyAffine(
|
|
1652
|
+
matrix,
|
|
1653
|
+
bias,
|
|
1654
|
+
vector,
|
|
1655
|
+
result,
|
|
1656
|
+
this.inDimension,
|
|
1657
|
+
this.outDimension
|
|
1658
|
+
);
|
|
871
1659
|
return result;
|
|
872
1660
|
}
|
|
1661
|
+
/**
|
|
1662
|
+
* 現在の射影行列の状態をシリアライズしてエクスポートします。
|
|
1663
|
+
*/
|
|
1664
|
+
exportState() {
|
|
1665
|
+
const projections = {};
|
|
1666
|
+
for (const [name, matrix] of this.matrices.entries()) {
|
|
1667
|
+
const bias = this.biases.get(name);
|
|
1668
|
+
projections[name] = {
|
|
1669
|
+
matrix: Array.from(matrix),
|
|
1670
|
+
bias: bias ? Array.from(bias) : void 0
|
|
1671
|
+
};
|
|
1672
|
+
}
|
|
1673
|
+
return JSON.stringify({
|
|
1674
|
+
inDimension: this.inDimension,
|
|
1675
|
+
outDimension: this.outDimension,
|
|
1676
|
+
projections
|
|
1677
|
+
});
|
|
1678
|
+
}
|
|
1679
|
+
/**
|
|
1680
|
+
* エクスポートされた状態から ProjectionAdapter を復元します。
|
|
1681
|
+
* 注意: 保存されている matrix は既にフラット化された 1D 配列であることを前提としています。
|
|
1682
|
+
*/
|
|
1683
|
+
static importState(stateJson) {
|
|
1684
|
+
const data = JSON.parse(stateJson);
|
|
1685
|
+
const adapter = new _ProjectionAdapter(data.inDimension, data.outDimension);
|
|
1686
|
+
for (const [name, proj] of Object.entries(data.projections)) {
|
|
1687
|
+
adapter.matrices.set(name, new Float32Array(proj.matrix));
|
|
1688
|
+
if (proj.bias) {
|
|
1689
|
+
adapter.biases.set(name, new Float32Array(proj.bias));
|
|
1690
|
+
}
|
|
1691
|
+
}
|
|
1692
|
+
return adapter;
|
|
1693
|
+
}
|
|
873
1694
|
};
|
|
874
1695
|
|
|
875
|
-
// src/
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
1696
|
+
// src/MlpAdapter.ts
|
|
1697
|
+
function getActivationId(activation) {
|
|
1698
|
+
switch (activation) {
|
|
1699
|
+
case "linear":
|
|
1700
|
+
return 0;
|
|
1701
|
+
case "relu":
|
|
1702
|
+
return 1;
|
|
1703
|
+
case "sigmoid":
|
|
1704
|
+
return 2;
|
|
1705
|
+
case "tanh":
|
|
1706
|
+
return 3;
|
|
1707
|
+
default:
|
|
1708
|
+
return 0;
|
|
1709
|
+
}
|
|
1710
|
+
}
|
|
1711
|
+
var MlpAdapter = class _MlpAdapter {
|
|
1712
|
+
layers;
|
|
1713
|
+
wasmInstance = null;
|
|
1714
|
+
// WASMのポインタと設定値
|
|
1715
|
+
isWasmReady = false;
|
|
1716
|
+
inputDim = 0;
|
|
1717
|
+
outputDim = 0;
|
|
1718
|
+
numLayers = 0;
|
|
1719
|
+
inputPtr = 0;
|
|
1720
|
+
outputPtr = 0;
|
|
1721
|
+
weightsPtr = 0;
|
|
1722
|
+
layerDimsPtr = 0;
|
|
1723
|
+
activationsPtr = 0;
|
|
1724
|
+
bufferPtr = 0;
|
|
1725
|
+
bufBPtr = 0;
|
|
1726
|
+
constructor(layers) {
|
|
1727
|
+
if (layers.length === 0) {
|
|
1728
|
+
throw new Error("MlpAdapter requires at least one layer.");
|
|
1729
|
+
}
|
|
1730
|
+
this.layers = layers;
|
|
1731
|
+
this.numLayers = layers.length;
|
|
1732
|
+
}
|
|
879
1733
|
/**
|
|
880
|
-
*
|
|
881
|
-
*
|
|
1734
|
+
* WASMの初期化と、MLP構造をWASMメモリに書き込む準備を行います。
|
|
1735
|
+
* インスタンス作成後に必ず呼び出してください。
|
|
1736
|
+
*/
|
|
1737
|
+
async init() {
|
|
1738
|
+
this.wasmInstance = await initWasm();
|
|
1739
|
+
if (!this.wasmInstance) {
|
|
1740
|
+
throw new Error("Failed to initialize WASM for MlpAdapter.");
|
|
1741
|
+
}
|
|
1742
|
+
const memory = this.wasmInstance.exports.memory;
|
|
1743
|
+
let sDim = 0;
|
|
1744
|
+
let tDim = 0;
|
|
1745
|
+
let maxDim = 0;
|
|
1746
|
+
let totalWeights = 0;
|
|
1747
|
+
const layerDims = [];
|
|
1748
|
+
const activations = [];
|
|
1749
|
+
for (let i = 0; i < this.layers.length; i++) {
|
|
1750
|
+
const layer = this.layers[i];
|
|
1751
|
+
let rows, cols;
|
|
1752
|
+
if (layer.matrix instanceof Float32Array) {
|
|
1753
|
+
rows = layer.bias.length;
|
|
1754
|
+
cols = layer.matrix.length / rows;
|
|
1755
|
+
} else {
|
|
1756
|
+
rows = layer.matrix.length;
|
|
1757
|
+
cols = layer.matrix[0].length;
|
|
1758
|
+
}
|
|
1759
|
+
if (i === 0) {
|
|
1760
|
+
sDim = cols;
|
|
1761
|
+
layerDims.push(sDim);
|
|
1762
|
+
} else if (cols !== tDim) {
|
|
1763
|
+
throw new Error(
|
|
1764
|
+
`Dimension mismatch at layer ${i}: expected input dim ${tDim}, got ${cols}`
|
|
1765
|
+
);
|
|
1766
|
+
}
|
|
1767
|
+
tDim = rows;
|
|
1768
|
+
layerDims.push(tDim);
|
|
1769
|
+
if (sDim > maxDim) maxDim = sDim;
|
|
1770
|
+
if (tDim > maxDim) maxDim = tDim;
|
|
1771
|
+
totalWeights += rows * cols + rows;
|
|
1772
|
+
activations.push(getActivationId(layer.activation));
|
|
1773
|
+
}
|
|
1774
|
+
this.inputDim = layerDims[0];
|
|
1775
|
+
this.outputDim = layerDims[layerDims.length - 1];
|
|
1776
|
+
this.inputPtr = allocateWasmMemory(this.inputDim * 4);
|
|
1777
|
+
this.outputPtr = allocateWasmMemory(this.outputDim * 4);
|
|
1778
|
+
this.layerDimsPtr = allocateWasmMemory((this.numLayers + 1) * 4);
|
|
1779
|
+
this.activationsPtr = allocateWasmMemory(this.numLayers * 4);
|
|
1780
|
+
this.weightsPtr = allocateWasmMemory(totalWeights * 4);
|
|
1781
|
+
this.bufferPtr = allocateWasmMemory(maxDim * 4);
|
|
1782
|
+
this.bufBPtr = allocateWasmMemory(maxDim * 4);
|
|
1783
|
+
const memoryBuffer = memory.buffer;
|
|
1784
|
+
const f32 = new Float32Array(memoryBuffer);
|
|
1785
|
+
const i32 = new Int32Array(memoryBuffer);
|
|
1786
|
+
for (let i = 0; i < layerDims.length; i++) {
|
|
1787
|
+
i32[this.layerDimsPtr / 4 + i] = layerDims[i];
|
|
1788
|
+
}
|
|
1789
|
+
for (let i = 0; i < activations.length; i++) {
|
|
1790
|
+
i32[this.activationsPtr / 4 + i] = activations[i];
|
|
1791
|
+
}
|
|
1792
|
+
let wIdx = this.weightsPtr / 4;
|
|
1793
|
+
for (let i = 0; i < this.numLayers; i++) {
|
|
1794
|
+
const layer = this.layers[i];
|
|
1795
|
+
let rows, cols;
|
|
1796
|
+
if (layer.matrix instanceof Float32Array) {
|
|
1797
|
+
rows = layer.bias.length;
|
|
1798
|
+
cols = layer.matrix.length / rows;
|
|
1799
|
+
for (let r = 0; r < rows; r++) {
|
|
1800
|
+
for (let c = 0; c < cols; c++) {
|
|
1801
|
+
f32[wIdx++] = layer.matrix[r * cols + c];
|
|
1802
|
+
}
|
|
1803
|
+
f32[wIdx++] = layer.bias[r];
|
|
1804
|
+
}
|
|
1805
|
+
} else {
|
|
1806
|
+
rows = layer.matrix.length;
|
|
1807
|
+
cols = layer.matrix[0].length;
|
|
1808
|
+
for (let r = 0; r < rows; r++) {
|
|
1809
|
+
for (let c = 0; c < cols; c++) {
|
|
1810
|
+
f32[wIdx++] = layer.matrix[r][c];
|
|
1811
|
+
}
|
|
1812
|
+
f32[wIdx++] = layer.bias[r];
|
|
1813
|
+
}
|
|
1814
|
+
}
|
|
1815
|
+
}
|
|
1816
|
+
this.isWasmReady = true;
|
|
1817
|
+
}
|
|
1818
|
+
/**
|
|
1819
|
+
* ニューラルネットワークの順伝播を実行し、結果を返します。
|
|
1820
|
+
* (WarpAdapter の実装として、predict の代わりに tune を提供します)
|
|
882
1821
|
*
|
|
883
|
-
* @param
|
|
884
|
-
* @
|
|
1822
|
+
* @param input 入力ベクトル
|
|
1823
|
+
* @returns 推論結果ベクトル
|
|
885
1824
|
*/
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
if (source.length !== this.sourceDimension) {
|
|
1825
|
+
tune(input) {
|
|
1826
|
+
if (!this.isWasmReady || !this.wasmInstance) {
|
|
889
1827
|
throw new Error(
|
|
890
|
-
|
|
1828
|
+
"MlpAdapter is not initialized. Call await init() first."
|
|
891
1829
|
);
|
|
892
1830
|
}
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
1831
|
+
assertDimension(input, this.inputDim, "MlpAdapter.tune");
|
|
1832
|
+
const memory = this.wasmInstance.exports.memory;
|
|
1833
|
+
writeFloat32ArrayToWasm(memory, input, this.inputPtr);
|
|
1834
|
+
const mlpInferenceWasm = this.wasmInstance.exports.mlpInferenceWasm;
|
|
1835
|
+
mlpInferenceWasm(
|
|
1836
|
+
this.inputPtr,
|
|
1837
|
+
this.outputPtr,
|
|
1838
|
+
this.weightsPtr,
|
|
1839
|
+
this.layerDimsPtr,
|
|
1840
|
+
this.activationsPtr,
|
|
1841
|
+
this.numLayers,
|
|
1842
|
+
this.bufferPtr,
|
|
1843
|
+
this.bufBPtr
|
|
1844
|
+
);
|
|
1845
|
+
const result = new Float32Array(this.outputDim);
|
|
1846
|
+
const outF32 = new Float32Array(memory.buffer);
|
|
1847
|
+
const outIdx = this.outputPtr / 4;
|
|
1848
|
+
for (let i = 0; i < this.outputDim; i++) {
|
|
1849
|
+
result[i] = outF32[outIdx + i];
|
|
897
1850
|
}
|
|
898
|
-
|
|
1851
|
+
return result;
|
|
899
1852
|
}
|
|
900
1853
|
/**
|
|
901
|
-
*
|
|
902
|
-
* 指定されたエポック数だけ SGD + Momentum によるパラメータ更新を行います。
|
|
903
|
-
* パフォーマンスのため、可能であれば内部で WebAssembly (WASM) を使用します。
|
|
904
|
-
*
|
|
905
|
-
* @param {BaseTrainingOptions} [options={}] 学習のハイパーパラメータオプション
|
|
906
|
-
* @returns {Promise<TResult>} 学習済みの重みを返します。
|
|
907
|
-
* @throws {Error} サンプルデータが追加されていない場合にスローされます。
|
|
1854
|
+
* 現在のMLP構造と重みをシリアライズして出力します。
|
|
908
1855
|
*/
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
1856
|
+
exportState() {
|
|
1857
|
+
return JSON.stringify({
|
|
1858
|
+
layers: this.layers.map((layer) => {
|
|
1859
|
+
let matrix;
|
|
1860
|
+
if (layer.matrix instanceof Float32Array) {
|
|
1861
|
+
matrix = Array.from(layer.matrix);
|
|
1862
|
+
} else {
|
|
1863
|
+
matrix = layer.matrix;
|
|
1864
|
+
}
|
|
1865
|
+
return {
|
|
1866
|
+
matrix,
|
|
1867
|
+
bias: Array.from(layer.bias),
|
|
1868
|
+
activation: layer.activation
|
|
1869
|
+
};
|
|
1870
|
+
})
|
|
1871
|
+
});
|
|
1872
|
+
}
|
|
1873
|
+
/**
|
|
1874
|
+
* シリアライズされた状態から MlpAdapter を復元します。
|
|
1875
|
+
* 注意: 復元後、再度 `await init()` を呼び出してWASMメモリを初期化する必要があります。
|
|
1876
|
+
*/
|
|
1877
|
+
static importState(stateJson) {
|
|
1878
|
+
const data = JSON.parse(stateJson);
|
|
1879
|
+
const layers = data.layers.map((l) => ({
|
|
1880
|
+
// Float32Array に戻すか、そのまま2D配列として扱う
|
|
1881
|
+
matrix: Array.isArray(l.matrix[0]) ? l.matrix : new Float32Array(l.matrix),
|
|
1882
|
+
bias: new Float32Array(l.bias),
|
|
1883
|
+
activation: l.activation
|
|
1884
|
+
}));
|
|
1885
|
+
return new _MlpAdapter(layers);
|
|
1886
|
+
}
|
|
1887
|
+
};
|
|
1888
|
+
|
|
1889
|
+
// src/WhiteningAdapter.ts
|
|
1890
|
+
var WhiteningAdapter = class _WhiteningAdapter {
|
|
1891
|
+
dim;
|
|
1892
|
+
mean;
|
|
1893
|
+
components;
|
|
1894
|
+
count = 0;
|
|
1895
|
+
learningRate;
|
|
1896
|
+
numComponents;
|
|
1897
|
+
componentsPtr = 0;
|
|
1898
|
+
xResidualPtr = 0;
|
|
1899
|
+
isWasmReady = false;
|
|
1900
|
+
async init() {
|
|
1901
|
+
const instance = await initWasm();
|
|
1902
|
+
if (instance) {
|
|
1903
|
+
const componentsSize = this.numComponents * this.dim * 4;
|
|
1904
|
+
const xResidualSize = this.dim * 4;
|
|
1905
|
+
this.componentsPtr = allocateWasmMemory(componentsSize);
|
|
1906
|
+
this.xResidualPtr = allocateWasmMemory(xResidualSize);
|
|
1907
|
+
this.isWasmReady = true;
|
|
913
1908
|
}
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
1909
|
+
}
|
|
1910
|
+
/**
|
|
1911
|
+
* 新しい WhiteningAdapter を作成します。
|
|
1912
|
+
* @param dim ベクトルの次元数
|
|
1913
|
+
* @param config 設定オプション
|
|
1914
|
+
*/
|
|
1915
|
+
constructor(dim, config = {}) {
|
|
1916
|
+
this.dim = dim;
|
|
1917
|
+
this.learningRate = config.learningRate ?? 0.01;
|
|
1918
|
+
this.numComponents = config.numComponents ?? 1;
|
|
1919
|
+
this.mean = new Float32Array(dim);
|
|
1920
|
+
this.components = [];
|
|
1921
|
+
for (let k = 0; k < this.numComponents; k++) {
|
|
1922
|
+
const pc = new Float32Array(dim);
|
|
1923
|
+
for (let i = 0; i < dim; i++) {
|
|
1924
|
+
pc[i] = Math.random() * 2 - 1;
|
|
1925
|
+
}
|
|
1926
|
+
this.components.push(normalize(pc));
|
|
917
1927
|
}
|
|
918
|
-
|
|
919
|
-
|
|
1928
|
+
}
|
|
1929
|
+
/**
|
|
1930
|
+
* 入力ベクトルを用いて、平均と主成分をオンライン更新します。
|
|
1931
|
+
* (Oja's Rule + Generalized Hebbian Algorithm)
|
|
1932
|
+
*
|
|
1933
|
+
* @param vector 学習用の入力ベクトル
|
|
1934
|
+
*/
|
|
1935
|
+
update(vector) {
|
|
1936
|
+
assertDimension(vector, this.dim, "WhiteningAdapter.update");
|
|
1937
|
+
if (this.count === 0) {
|
|
1938
|
+
for (let i = 0; i < this.dim; i++) {
|
|
1939
|
+
this.mean[i] = vector[i];
|
|
1940
|
+
}
|
|
1941
|
+
} else {
|
|
1942
|
+
for (let i = 0; i < this.dim; i++) {
|
|
1943
|
+
this.mean[i] = (1 - this.learningRate) * this.mean[i] + this.learningRate * vector[i];
|
|
1944
|
+
}
|
|
1945
|
+
}
|
|
1946
|
+
this.count++;
|
|
1947
|
+
const x = new Float32Array(this.dim);
|
|
1948
|
+
for (let i = 0; i < this.dim; i++) {
|
|
1949
|
+
x[i] = vector[i] - this.mean[i];
|
|
1950
|
+
}
|
|
1951
|
+
const x_residual = new Float32Array(x);
|
|
1952
|
+
const instance = getWasmInstance();
|
|
1953
|
+
if (instance && instance.exports.sangerUpdateWasm) {
|
|
1954
|
+
if (!this.isWasmReady) {
|
|
1955
|
+
const componentsSize = this.numComponents * this.dim * 4;
|
|
1956
|
+
const xResidualSize = this.dim * 4;
|
|
1957
|
+
this.componentsPtr = allocateWasmMemory(componentsSize);
|
|
1958
|
+
this.xResidualPtr = allocateWasmMemory(xResidualSize);
|
|
1959
|
+
this.isWasmReady = true;
|
|
1960
|
+
}
|
|
1961
|
+
const memory = instance.exports.memory;
|
|
1962
|
+
const componentsPtr = this.componentsPtr;
|
|
1963
|
+
const xResidualPtr = this.xResidualPtr;
|
|
1964
|
+
const f32 = new Float32Array(memory.buffer);
|
|
1965
|
+
for (let k = 0; k < this.numComponents; k++) {
|
|
1966
|
+
const comp = this.components[k];
|
|
1967
|
+
for (let i = 0; i < this.dim; i++) {
|
|
1968
|
+
f32[componentsPtr / 4 + k * this.dim + i] = comp[i];
|
|
1969
|
+
}
|
|
1970
|
+
}
|
|
1971
|
+
writeFloat32ArrayToWasm(memory, x_residual, xResidualPtr);
|
|
1972
|
+
const sangerUpdateWasm = instance.exports.sangerUpdateWasm;
|
|
1973
|
+
sangerUpdateWasm(
|
|
1974
|
+
componentsPtr,
|
|
1975
|
+
xResidualPtr,
|
|
1976
|
+
this.dim,
|
|
1977
|
+
this.numComponents,
|
|
1978
|
+
this.learningRate
|
|
1979
|
+
);
|
|
1980
|
+
for (let k = 0; k < this.numComponents; k++) {
|
|
1981
|
+
for (let i = 0; i < this.dim; i++) {
|
|
1982
|
+
this.components[k][i] = f32[componentsPtr / 4 + k * this.dim + i];
|
|
1983
|
+
}
|
|
1984
|
+
}
|
|
1985
|
+
} else {
|
|
1986
|
+
for (let k = 0; k < this.numComponents; k++) {
|
|
1987
|
+
const w = this.components[k];
|
|
1988
|
+
let y = innerProduct(w, x_residual);
|
|
1989
|
+
addScaledVector(w, x_residual, this.learningRate * y);
|
|
1990
|
+
addScaledVector(w, w, -this.learningRate * y * y);
|
|
1991
|
+
this.components[k] = normalize(w);
|
|
1992
|
+
addScaledVector(x_residual, this.components[k], -y);
|
|
1993
|
+
}
|
|
1994
|
+
}
|
|
1995
|
+
}
|
|
1996
|
+
/**
|
|
1997
|
+
* 推論 (Whitening の適用):
|
|
1998
|
+
* 入力ベクトルから平均を引き、偏りの原因である上位主成分を除去します (All-but-the-Top)。
|
|
1999
|
+
*
|
|
2000
|
+
* @param vector 推論・補正対象のベクトル
|
|
2001
|
+
* @returns 等方化・ゼロセンタリングされた新しいベクトル
|
|
2002
|
+
*/
|
|
2003
|
+
tune(vector) {
|
|
2004
|
+
assertDimension(vector, this.dim, "WhiteningAdapter.tune");
|
|
2005
|
+
let result = new Float32Array(this.dim);
|
|
2006
|
+
for (let i = 0; i < this.dim; i++) {
|
|
2007
|
+
result[i] = vector[i] - this.mean[i];
|
|
2008
|
+
}
|
|
2009
|
+
for (let k = 0; k < this.numComponents; k++) {
|
|
2010
|
+
const w = this.components[k];
|
|
2011
|
+
let dot = innerProduct(result, w);
|
|
2012
|
+
addScaledVector(result, w, -dot);
|
|
2013
|
+
}
|
|
2014
|
+
return result;
|
|
2015
|
+
}
|
|
2016
|
+
/**
|
|
2017
|
+
* 現在の学習状態(平均ベクトル、主成分ベクトルなど)をシリアライズして出力します。
|
|
2018
|
+
* エッジ環境でのインスタンス再構築時に役立ちます。
|
|
2019
|
+
*/
|
|
2020
|
+
exportState() {
|
|
2021
|
+
return JSON.stringify({
|
|
2022
|
+
dim: this.dim,
|
|
2023
|
+
count: this.count,
|
|
2024
|
+
learningRate: this.learningRate,
|
|
2025
|
+
numComponents: this.numComponents,
|
|
2026
|
+
mean: Array.from(this.mean),
|
|
2027
|
+
components: this.components.map((c) => Array.from(c))
|
|
2028
|
+
});
|
|
2029
|
+
}
|
|
2030
|
+
/**
|
|
2031
|
+
* シリアライズされた学習状態から WhiteningAdapter を復元します。
|
|
2032
|
+
*/
|
|
2033
|
+
static importState(stateJson) {
|
|
2034
|
+
const data = JSON.parse(stateJson);
|
|
2035
|
+
const adapter = new _WhiteningAdapter(data.dim, {
|
|
2036
|
+
learningRate: data.learningRate,
|
|
2037
|
+
numComponents: data.numComponents
|
|
2038
|
+
});
|
|
2039
|
+
adapter.count = data.count;
|
|
2040
|
+
adapter.mean = new Float32Array(data.mean);
|
|
2041
|
+
adapter.components = data.components.map(
|
|
2042
|
+
(c) => new Float32Array(c)
|
|
2043
|
+
);
|
|
2044
|
+
return adapter;
|
|
2045
|
+
}
|
|
2046
|
+
};
|
|
2047
|
+
|
|
2048
|
+
// src/ColbertAdapter.ts
|
|
2049
|
+
var ColbertAdapter = class {
|
|
2050
|
+
wasm;
|
|
2051
|
+
constructor() {
|
|
2052
|
+
this.wasm = getWasmInstance();
|
|
2053
|
+
}
|
|
2054
|
+
/**
|
|
2055
|
+
* 単一のクエリと単一のドキュメント間の Late Interaction (MaxSim) スコアを計算します。
|
|
2056
|
+
*
|
|
2057
|
+
* @param queryTokens クエリのトークンベクトル行列 (要素数 = queryLength * dim の平坦化された配列)
|
|
2058
|
+
* @param documentTokens ドキュメントのトークンベクトル行列
|
|
2059
|
+
* @param dim ベクトルの次元数
|
|
2060
|
+
* @returns MaxSimスコア
|
|
2061
|
+
*/
|
|
2062
|
+
score(queryTokens, documentTokens, dim) {
|
|
2063
|
+
const numQueryTokens = queryTokens.length / dim;
|
|
2064
|
+
const numDocTokens = documentTokens.length / dim;
|
|
2065
|
+
if (numQueryTokens % 1 !== 0) {
|
|
2066
|
+
throw new Error(
|
|
2067
|
+
`Invalid queryTokens length. Must be a multiple of dim (${dim})`
|
|
2068
|
+
);
|
|
2069
|
+
}
|
|
2070
|
+
if (numDocTokens % 1 !== 0) {
|
|
2071
|
+
throw new Error(
|
|
2072
|
+
`Invalid documentTokens length. Must be a multiple of dim (${dim})`
|
|
2073
|
+
);
|
|
2074
|
+
}
|
|
2075
|
+
const { memory, colbertMaxSimWasm } = this.wasm.exports;
|
|
2076
|
+
const queryBytes = queryTokens.byteLength;
|
|
2077
|
+
const docBytes = documentTokens.byteLength;
|
|
2078
|
+
const initialOffset = getWasmAllocatorOffset();
|
|
2079
|
+
try {
|
|
2080
|
+
const queryPtr = allocateWasmMemory(queryBytes);
|
|
2081
|
+
const docPtr = allocateWasmMemory(docBytes);
|
|
2082
|
+
writeFloat32ArrayToWasm(memory, queryTokens, queryPtr);
|
|
2083
|
+
writeFloat32ArrayToWasm(memory, documentTokens, docPtr);
|
|
2084
|
+
return colbertMaxSimWasm(
|
|
2085
|
+
queryPtr,
|
|
2086
|
+
docPtr,
|
|
2087
|
+
numQueryTokens,
|
|
2088
|
+
numDocTokens,
|
|
2089
|
+
dim
|
|
2090
|
+
);
|
|
2091
|
+
} finally {
|
|
2092
|
+
setWasmAllocatorOffset(initialOffset);
|
|
2093
|
+
}
|
|
2094
|
+
}
|
|
2095
|
+
/**
|
|
2096
|
+
* クエリと複数のドキュメント間の MaxSim スコアを計算し、スコアの降順にソートして返します。
|
|
2097
|
+
*
|
|
2098
|
+
* @param queryTokens クエリのトークンベクトル行列
|
|
2099
|
+
* @param documentTokensArray ドキュメントのトークンベクトル行列の配列
|
|
2100
|
+
* @param dim ベクトルの次元数
|
|
2101
|
+
* @returns スコアの降順にソートされたドキュメントのインデックスとスコアの配列
|
|
2102
|
+
*/
|
|
2103
|
+
rank(queryTokens, documentTokensArray, dim) {
|
|
2104
|
+
const numQueryTokens = queryTokens.length / dim;
|
|
2105
|
+
if (numQueryTokens % 1 !== 0) {
|
|
2106
|
+
throw new Error(
|
|
2107
|
+
`Invalid queryTokens length. Must be a multiple of dim (${dim})`
|
|
2108
|
+
);
|
|
2109
|
+
}
|
|
2110
|
+
const { memory, colbertMaxSimWasm } = this.wasm.exports;
|
|
2111
|
+
let maxDocLen = 0;
|
|
2112
|
+
for (const doc of documentTokensArray) {
|
|
2113
|
+
if (doc.length > maxDocLen) maxDocLen = doc.length;
|
|
2114
|
+
}
|
|
2115
|
+
const queryBytes = queryTokens.byteLength;
|
|
2116
|
+
const maxDocBytes = maxDocLen * Float32Array.BYTES_PER_ELEMENT;
|
|
2117
|
+
const initialOffset = getWasmAllocatorOffset();
|
|
2118
|
+
try {
|
|
2119
|
+
const queryPtr = allocateWasmMemory(queryBytes);
|
|
2120
|
+
const docPtr = allocateWasmMemory(maxDocBytes);
|
|
2121
|
+
writeFloat32ArrayToWasm(memory, queryTokens, queryPtr);
|
|
2122
|
+
const results = documentTokensArray.map((doc, index) => {
|
|
2123
|
+
const numDocTokens = doc.length / dim;
|
|
2124
|
+
if (numDocTokens % 1 !== 0) {
|
|
2125
|
+
throw new Error(`Invalid documentTokens length at index ${index}`);
|
|
2126
|
+
}
|
|
2127
|
+
writeFloat32ArrayToWasm(memory, doc, docPtr);
|
|
2128
|
+
const score = colbertMaxSimWasm(
|
|
2129
|
+
queryPtr,
|
|
2130
|
+
docPtr,
|
|
2131
|
+
numQueryTokens,
|
|
2132
|
+
numDocTokens,
|
|
2133
|
+
dim
|
|
2134
|
+
);
|
|
2135
|
+
return { index, score };
|
|
2136
|
+
});
|
|
2137
|
+
return results.sort((a, b) => b.score - a.score);
|
|
2138
|
+
} finally {
|
|
2139
|
+
setWasmAllocatorOffset(initialOffset);
|
|
2140
|
+
}
|
|
2141
|
+
}
|
|
2142
|
+
};
|
|
2143
|
+
|
|
2144
|
+
// src/integrations/prisma.ts
|
|
2145
|
+
var import_extension = require("@prisma/client/extension");
|
|
2146
|
+
|
|
2147
|
+
// src/db.ts
|
|
2148
|
+
var VectorDBAdapter = class {
|
|
2149
|
+
/**
|
|
2150
|
+
* PostgreSQL (pgvector) 用のクエリ文字列表現を生成します。
|
|
2151
|
+
* INSERT や SELECT の際に使用できる形式です。
|
|
2152
|
+
*
|
|
2153
|
+
* @example
|
|
2154
|
+
* const sql = `SELECT * FROM items ORDER BY embedding <-> '${VectorDBAdapter.toPgvector(warpedVector)}' LIMIT 5`;
|
|
2155
|
+
*
|
|
2156
|
+
* @param {number[] | Float32Array} vector ワープ変換後のベクトル
|
|
2157
|
+
* @returns {string} `'[0.1, 0.2, 0.3]'` のような文字列表現
|
|
2158
|
+
*/
|
|
2159
|
+
static toPgvector(vector) {
|
|
2160
|
+
if (vector instanceof Uint8Array) {
|
|
2161
|
+
let bitString = "";
|
|
2162
|
+
for (let i = 0; i < vector.length; i++) {
|
|
2163
|
+
bitString += vector[i].toString(2).padStart(8, "0");
|
|
2164
|
+
}
|
|
2165
|
+
return bitString;
|
|
2166
|
+
}
|
|
2167
|
+
return `[${Array.from(vector).join(", ")}]`;
|
|
2168
|
+
}
|
|
2169
|
+
/**
|
|
2170
|
+
* Pinecone 用のクエリオブジェクトを生成します。
|
|
2171
|
+
* Pinecone クライアントに直接渡せる形式のオブジェクトを返します。
|
|
2172
|
+
*
|
|
2173
|
+
* @example
|
|
2174
|
+
* const query = VectorDBAdapter.toPineconeQuery(warpedVector, 10, { genre: "comedy" });
|
|
2175
|
+
* await index.query(query);
|
|
2176
|
+
*
|
|
2177
|
+
* @param {number[] | Float32Array} vector 検索クエリベクトル
|
|
2178
|
+
* @param {number} topK 取得する件数 (デフォルト: 10)
|
|
2179
|
+
* @param {Record<string, any>} [filter] メタデータフィルタ(オプション)
|
|
2180
|
+
* @returns {Record<string, any>} Pineconeのqueryメソッド用オブジェクト
|
|
2181
|
+
*/
|
|
2182
|
+
static toPineconeQuery(vector, topK = 10, filter) {
|
|
2183
|
+
return {
|
|
2184
|
+
vector: Array.from(vector),
|
|
2185
|
+
topK,
|
|
2186
|
+
...filter ? { filter } : {}
|
|
2187
|
+
};
|
|
2188
|
+
}
|
|
2189
|
+
/**
|
|
2190
|
+
* Redis (RediSearch) のベクトルフィールド用に、
|
|
2191
|
+
* Float32Array をバイナリ(Uint8Array)に変換します。
|
|
2192
|
+
* Node.js環境では Buffer.from() を使って Buffer に変換して渡してください。
|
|
2193
|
+
*
|
|
2194
|
+
* @example
|
|
2195
|
+
* const blob = Buffer.from(VectorDBAdapter.toRedis(warpedVector));
|
|
2196
|
+
* await redis.call('FT.SEARCH', 'idx', '*=>[KNN 5 @embedding $BLOB]', 'PARAMS', '2', 'BLOB', blob, 'DIALECT', '2');
|
|
2197
|
+
*
|
|
2198
|
+
* @param {number[] | Float32Array} vector ワープ変換後のベクトル
|
|
2199
|
+
* @returns {Uint8Array} バイナリデータ (Float32のバイト表現)
|
|
2200
|
+
*/
|
|
2201
|
+
static toRedis(vector) {
|
|
2202
|
+
const f32Array = vector instanceof Float32Array ? vector : new Float32Array(Array.from(vector));
|
|
2203
|
+
return new Uint8Array(
|
|
2204
|
+
f32Array.buffer.slice(
|
|
2205
|
+
f32Array.byteOffset,
|
|
2206
|
+
f32Array.byteOffset + f32Array.byteLength
|
|
2207
|
+
)
|
|
2208
|
+
);
|
|
2209
|
+
}
|
|
2210
|
+
};
|
|
2211
|
+
|
|
2212
|
+
// src/integrations/prisma.ts
|
|
2213
|
+
var withWarpVector = (config) => {
|
|
2214
|
+
const vectorField = config.vectorField ?? "embedding";
|
|
2215
|
+
const distanceOp = config.distanceOperator ?? "<->";
|
|
2216
|
+
return import_extension.Prisma.defineExtension((client) => {
|
|
2217
|
+
return client.$extends({
|
|
2218
|
+
name: "warpvector",
|
|
2219
|
+
model: {
|
|
2220
|
+
$allModels: {
|
|
2221
|
+
/**
|
|
2222
|
+
* 生のベクトルを受け取り、WarpVectorで変換した後に pgvector 検索を行います。
|
|
2223
|
+
*
|
|
2224
|
+
* @param args.vector 生のベクトル (変換前)
|
|
2225
|
+
* @param args.topK 取得する最大件数 (デフォルト: 10)
|
|
2226
|
+
* @param args.where 追加のフィルタリング条件 (例: "category = 'science'")
|
|
2227
|
+
*/
|
|
2228
|
+
async searchByVector(args) {
|
|
2229
|
+
const context = import_extension.Prisma.getExtensionContext(this);
|
|
2230
|
+
const tableName = context.$name || "document";
|
|
2231
|
+
if (!/^[a-zA-Z0-9_]+$/.test(tableName)) {
|
|
2232
|
+
throw new Error(`Invalid table name: ${tableName}`);
|
|
2233
|
+
}
|
|
2234
|
+
if (!/^[a-zA-Z0-9_]+$/.test(vectorField)) {
|
|
2235
|
+
throw new Error(`Invalid vector field name: ${vectorField}`);
|
|
2236
|
+
}
|
|
2237
|
+
if (!["<->", "<#>", "<=>"].includes(distanceOp)) {
|
|
2238
|
+
throw new Error(`Invalid distance operator: ${distanceOp}`);
|
|
2239
|
+
}
|
|
2240
|
+
let whereClause = "";
|
|
2241
|
+
if (args.where) {
|
|
2242
|
+
const trimmedWhere = args.where.trim();
|
|
2243
|
+
if (/;|--|\/\*/.test(trimmedWhere)) {
|
|
2244
|
+
throw new Error("Potential SQL injection detected in where clause.");
|
|
2245
|
+
}
|
|
2246
|
+
whereClause = `WHERE ${trimmedWhere}`;
|
|
2247
|
+
}
|
|
2248
|
+
const limit = args.topK ?? 10;
|
|
2249
|
+
if (typeof limit !== "number" || isNaN(limit) || limit < 0) {
|
|
2250
|
+
throw new Error("Invalid topK value.");
|
|
2251
|
+
}
|
|
2252
|
+
const tunedVector = config.adapter.tune(args.vector);
|
|
2253
|
+
const pgVectorStr = VectorDBAdapter.toPgvector(tunedVector);
|
|
2254
|
+
const sql = `
|
|
2255
|
+
SELECT *
|
|
2256
|
+
FROM "${tableName}"
|
|
2257
|
+
${whereClause}
|
|
2258
|
+
ORDER BY "${vectorField}" ${distanceOp} '${pgVectorStr}'::vector
|
|
2259
|
+
LIMIT ${limit};
|
|
2260
|
+
`.trim();
|
|
2261
|
+
return client.$queryRawUnsafe(sql);
|
|
2262
|
+
}
|
|
2263
|
+
}
|
|
2264
|
+
}
|
|
2265
|
+
});
|
|
2266
|
+
});
|
|
2267
|
+
};
|
|
2268
|
+
|
|
2269
|
+
// node_modules/@langchain/core/dist/utils/signal.js
|
|
2270
|
+
function getAbortSignalError(signal) {
|
|
2271
|
+
if (signal?.reason instanceof Error) return signal.reason;
|
|
2272
|
+
if (typeof signal?.reason === "string") return new Error(signal.reason);
|
|
2273
|
+
return /* @__PURE__ */ new Error("Aborted");
|
|
2274
|
+
}
|
|
2275
|
+
|
|
2276
|
+
// node_modules/@langchain/core/dist/utils/is-network-error/index.js
|
|
2277
|
+
var objectToString = Object.prototype.toString;
|
|
2278
|
+
var isError = (value) => objectToString.call(value) === "[object Error]";
|
|
2279
|
+
var errorMessages = /* @__PURE__ */ new Set([
|
|
2280
|
+
"network error",
|
|
2281
|
+
"Failed to fetch",
|
|
2282
|
+
"NetworkError when attempting to fetch resource.",
|
|
2283
|
+
"The Internet connection appears to be offline.",
|
|
2284
|
+
"Network request failed",
|
|
2285
|
+
"fetch failed",
|
|
2286
|
+
"terminated",
|
|
2287
|
+
" A network error occurred.",
|
|
2288
|
+
"Network connection lost"
|
|
2289
|
+
]);
|
|
2290
|
+
function isNetworkError(error) {
|
|
2291
|
+
if (!(error && isError(error) && error.name === "TypeError" && typeof error.message === "string")) return false;
|
|
2292
|
+
const { message, stack } = error;
|
|
2293
|
+
if (message === "Load failed") return stack === void 0 || "__sentry_captured__" in error;
|
|
2294
|
+
if (message.startsWith("error sending request for url")) return true;
|
|
2295
|
+
return errorMessages.has(message);
|
|
2296
|
+
}
|
|
2297
|
+
|
|
2298
|
+
// node_modules/@langchain/core/dist/utils/p-retry/index.js
|
|
2299
|
+
function validateRetries(retries) {
|
|
2300
|
+
if (typeof retries === "number") {
|
|
2301
|
+
if (retries < 0) throw new TypeError("Expected `retries` to be a non-negative number.");
|
|
2302
|
+
if (Number.isNaN(retries)) throw new TypeError("Expected `retries` to be a valid number or Infinity, got NaN.");
|
|
2303
|
+
} else if (retries !== void 0) throw new TypeError("Expected `retries` to be a number or Infinity.");
|
|
2304
|
+
}
|
|
2305
|
+
function validateNumberOption(name, value, { min = 0, allowInfinity = false } = {}) {
|
|
2306
|
+
if (value === void 0) return;
|
|
2307
|
+
if (typeof value !== "number" || Number.isNaN(value)) throw new TypeError(`Expected \`${name}\` to be a number${allowInfinity ? " or Infinity" : ""}.`);
|
|
2308
|
+
if (!allowInfinity && !Number.isFinite(value)) throw new TypeError(`Expected \`${name}\` to be a finite number.`);
|
|
2309
|
+
if (value < min) throw new TypeError(`Expected \`${name}\` to be \u2265 ${min}.`);
|
|
2310
|
+
}
|
|
2311
|
+
var AbortError = class extends Error {
|
|
2312
|
+
constructor(message) {
|
|
2313
|
+
super();
|
|
2314
|
+
if (message instanceof Error) {
|
|
2315
|
+
this.originalError = message;
|
|
2316
|
+
({ message } = message);
|
|
2317
|
+
} else {
|
|
2318
|
+
this.originalError = new Error(message);
|
|
2319
|
+
this.originalError.stack = this.stack;
|
|
2320
|
+
}
|
|
2321
|
+
this.name = "AbortError";
|
|
2322
|
+
this.message = message;
|
|
2323
|
+
}
|
|
2324
|
+
};
|
|
2325
|
+
function calculateDelay(retriesConsumed, options) {
|
|
2326
|
+
const attempt = Math.max(1, retriesConsumed + 1);
|
|
2327
|
+
const random = options.randomize ? Math.random() + 1 : 1;
|
|
2328
|
+
let timeout = Math.round(random * options.minTimeout * options.factor ** (attempt - 1));
|
|
2329
|
+
timeout = Math.min(timeout, options.maxTimeout);
|
|
2330
|
+
return timeout;
|
|
2331
|
+
}
|
|
2332
|
+
function calculateRemainingTime(start, max) {
|
|
2333
|
+
if (!Number.isFinite(max)) return max;
|
|
2334
|
+
return max - (performance.now() - start);
|
|
2335
|
+
}
|
|
2336
|
+
async function onAttemptFailure({ error, attemptNumber, retriesConsumed, startTime, options }) {
|
|
2337
|
+
const normalizedError = error instanceof Error ? error : /* @__PURE__ */ new TypeError(`Non-error was thrown: "${error}". You should only throw errors.`);
|
|
2338
|
+
if (normalizedError instanceof AbortError) throw normalizedError.originalError;
|
|
2339
|
+
const retriesLeft = Number.isFinite(options.retries) ? Math.max(0, options.retries - retriesConsumed) : options.retries;
|
|
2340
|
+
const maxRetryTime = options.maxRetryTime ?? Number.POSITIVE_INFINITY;
|
|
2341
|
+
const context = Object.freeze({
|
|
2342
|
+
error: normalizedError,
|
|
2343
|
+
attemptNumber,
|
|
2344
|
+
retriesLeft,
|
|
2345
|
+
retriesConsumed
|
|
2346
|
+
});
|
|
2347
|
+
await options.onFailedAttempt(context);
|
|
2348
|
+
if (calculateRemainingTime(startTime, maxRetryTime) <= 0) throw normalizedError;
|
|
2349
|
+
const consumeRetry = await options.shouldConsumeRetry(context);
|
|
2350
|
+
const remainingTime = calculateRemainingTime(startTime, maxRetryTime);
|
|
2351
|
+
if (remainingTime <= 0 || retriesLeft <= 0) throw normalizedError;
|
|
2352
|
+
if (normalizedError instanceof TypeError && !isNetworkError(normalizedError)) {
|
|
2353
|
+
if (consumeRetry) throw normalizedError;
|
|
2354
|
+
options.signal?.throwIfAborted();
|
|
2355
|
+
return false;
|
|
2356
|
+
}
|
|
2357
|
+
if (!await options.shouldRetry(context)) throw normalizedError;
|
|
2358
|
+
if (!consumeRetry) {
|
|
2359
|
+
options.signal?.throwIfAborted();
|
|
2360
|
+
return false;
|
|
2361
|
+
}
|
|
2362
|
+
const delayTime = calculateDelay(retriesConsumed, options);
|
|
2363
|
+
const finalDelay = Math.min(delayTime, remainingTime);
|
|
2364
|
+
if (finalDelay > 0) await new Promise((resolve, reject2) => {
|
|
2365
|
+
const onAbort = () => {
|
|
2366
|
+
clearTimeout(timeoutToken);
|
|
2367
|
+
options.signal?.removeEventListener("abort", onAbort);
|
|
2368
|
+
reject2(options.signal.reason);
|
|
2369
|
+
};
|
|
2370
|
+
const timeoutToken = setTimeout(() => {
|
|
2371
|
+
options.signal?.removeEventListener("abort", onAbort);
|
|
2372
|
+
resolve();
|
|
2373
|
+
}, finalDelay);
|
|
2374
|
+
if (options.unref) timeoutToken.unref?.();
|
|
2375
|
+
options.signal?.addEventListener("abort", onAbort, { once: true });
|
|
2376
|
+
});
|
|
2377
|
+
options.signal?.throwIfAborted();
|
|
2378
|
+
return true;
|
|
2379
|
+
}
|
|
2380
|
+
async function pRetry(input, options = {}) {
|
|
2381
|
+
options = { ...options };
|
|
2382
|
+
validateRetries(options.retries);
|
|
2383
|
+
if (Object.hasOwn(options, "forever")) throw new Error("The `forever` option is no longer supported. For many use-cases, you can set `retries: Infinity` instead.");
|
|
2384
|
+
options.retries ??= 10;
|
|
2385
|
+
options.factor ??= 2;
|
|
2386
|
+
options.minTimeout ??= 1e3;
|
|
2387
|
+
options.maxTimeout ??= Number.POSITIVE_INFINITY;
|
|
2388
|
+
options.maxRetryTime ??= Number.POSITIVE_INFINITY;
|
|
2389
|
+
options.randomize ??= false;
|
|
2390
|
+
options.onFailedAttempt ??= () => {
|
|
2391
|
+
};
|
|
2392
|
+
options.shouldRetry ??= () => true;
|
|
2393
|
+
options.shouldConsumeRetry ??= () => true;
|
|
2394
|
+
validateNumberOption("factor", options.factor, {
|
|
2395
|
+
min: 0,
|
|
2396
|
+
allowInfinity: false
|
|
2397
|
+
});
|
|
2398
|
+
validateNumberOption("minTimeout", options.minTimeout, {
|
|
2399
|
+
min: 0,
|
|
2400
|
+
allowInfinity: false
|
|
2401
|
+
});
|
|
2402
|
+
validateNumberOption("maxTimeout", options.maxTimeout, {
|
|
2403
|
+
min: 0,
|
|
2404
|
+
allowInfinity: true
|
|
2405
|
+
});
|
|
2406
|
+
validateNumberOption("maxRetryTime", options.maxRetryTime, {
|
|
2407
|
+
min: 0,
|
|
2408
|
+
allowInfinity: true
|
|
2409
|
+
});
|
|
2410
|
+
if (!(options.factor > 0)) options.factor = 1;
|
|
2411
|
+
options.signal?.throwIfAborted();
|
|
2412
|
+
let attemptNumber = 0;
|
|
2413
|
+
let retriesConsumed = 0;
|
|
2414
|
+
const startTime = performance.now();
|
|
2415
|
+
while (Number.isFinite(options.retries) ? retriesConsumed <= options.retries : true) {
|
|
2416
|
+
attemptNumber++;
|
|
2417
|
+
try {
|
|
2418
|
+
options.signal?.throwIfAborted();
|
|
2419
|
+
const result = await input(attemptNumber);
|
|
2420
|
+
options.signal?.throwIfAborted();
|
|
2421
|
+
return result;
|
|
2422
|
+
} catch (error) {
|
|
2423
|
+
if (await onAttemptFailure({
|
|
2424
|
+
error,
|
|
2425
|
+
attemptNumber,
|
|
2426
|
+
retriesConsumed,
|
|
2427
|
+
startTime,
|
|
2428
|
+
options
|
|
2429
|
+
})) retriesConsumed++;
|
|
2430
|
+
}
|
|
2431
|
+
}
|
|
2432
|
+
throw new Error("Retry attempts exhausted without throwing an error.");
|
|
2433
|
+
}
|
|
2434
|
+
|
|
2435
|
+
// node_modules/@langchain/core/dist/utils/async_caller.js
|
|
2436
|
+
var import_p_queue = __toESM(require_dist(), 1);
|
|
2437
|
+
var STATUS_NO_RETRY = [
|
|
2438
|
+
400,
|
|
2439
|
+
401,
|
|
2440
|
+
402,
|
|
2441
|
+
403,
|
|
2442
|
+
404,
|
|
2443
|
+
405,
|
|
2444
|
+
406,
|
|
2445
|
+
407,
|
|
2446
|
+
409
|
|
2447
|
+
];
|
|
2448
|
+
var defaultFailedAttemptHandler = (error) => {
|
|
2449
|
+
if (typeof error !== "object" || error === null) return;
|
|
2450
|
+
if ("message" in error && typeof error.message === "string" && (error.message.startsWith("Cancel") || error.message.startsWith("AbortError")) || "name" in error && typeof error.name === "string" && error.name === "AbortError") throw error;
|
|
2451
|
+
if ("code" in error && typeof error.code === "string" && error.code === "ECONNABORTED") throw error;
|
|
2452
|
+
const responseStatus = "response" in error && typeof error.response === "object" && error.response !== null && "status" in error.response && typeof error.response.status === "number" ? error.response.status : void 0;
|
|
2453
|
+
const directStatus = "status" in error && typeof error.status === "number" ? error.status : void 0;
|
|
2454
|
+
const status = responseStatus ?? directStatus;
|
|
2455
|
+
if (status && STATUS_NO_RETRY.includes(+status)) throw error;
|
|
2456
|
+
if (("error" in error && typeof error.error === "object" && error.error !== null && "code" in error.error && typeof error.error.code === "string" ? error.error.code : void 0) === "insufficient_quota") {
|
|
2457
|
+
const err = new Error("message" in error && typeof error.message === "string" ? error.message : "Insufficient quota");
|
|
2458
|
+
err.name = "InsufficientQuotaError";
|
|
2459
|
+
throw err;
|
|
2460
|
+
}
|
|
2461
|
+
};
|
|
2462
|
+
var AsyncCaller = class {
|
|
2463
|
+
maxConcurrency;
|
|
2464
|
+
maxRetries;
|
|
2465
|
+
onFailedAttempt;
|
|
2466
|
+
queue;
|
|
2467
|
+
constructor(params) {
|
|
2468
|
+
this.maxConcurrency = params.maxConcurrency ?? Infinity;
|
|
2469
|
+
this.maxRetries = params.maxRetries ?? 6;
|
|
2470
|
+
this.onFailedAttempt = params.onFailedAttempt ?? defaultFailedAttemptHandler;
|
|
2471
|
+
const PQueue = "default" in import_p_queue.default ? import_p_queue.default.default : import_p_queue.default;
|
|
2472
|
+
this.queue = new PQueue({ concurrency: this.maxConcurrency });
|
|
2473
|
+
}
|
|
2474
|
+
async call(callable, ...args) {
|
|
2475
|
+
return this.queue.add(() => pRetry(() => callable(...args).catch((error) => {
|
|
2476
|
+
if (error instanceof Error) throw error;
|
|
2477
|
+
else throw new Error(error);
|
|
2478
|
+
}), {
|
|
2479
|
+
onFailedAttempt: ({ error }) => this.onFailedAttempt?.(error),
|
|
2480
|
+
retries: this.maxRetries,
|
|
2481
|
+
randomize: true
|
|
2482
|
+
}), { throwOnTimeout: true });
|
|
2483
|
+
}
|
|
2484
|
+
callWithOptions(options, callable, ...args) {
|
|
2485
|
+
if (options.signal) {
|
|
2486
|
+
let listener;
|
|
2487
|
+
return Promise.race([this.call(callable, ...args), new Promise((_, reject2) => {
|
|
2488
|
+
listener = () => {
|
|
2489
|
+
reject2(getAbortSignalError(options.signal));
|
|
2490
|
+
};
|
|
2491
|
+
options.signal?.addEventListener("abort", listener, { once: true });
|
|
2492
|
+
})]).finally(() => {
|
|
2493
|
+
if (options.signal && listener) options.signal.removeEventListener("abort", listener);
|
|
2494
|
+
});
|
|
2495
|
+
}
|
|
2496
|
+
return this.call(callable, ...args);
|
|
2497
|
+
}
|
|
2498
|
+
fetch(...args) {
|
|
2499
|
+
return this.call(() => fetch(...args).then((res) => res.ok ? res : Promise.reject(res)));
|
|
2500
|
+
}
|
|
2501
|
+
};
|
|
2502
|
+
|
|
2503
|
+
// node_modules/@langchain/core/dist/embeddings.js
|
|
2504
|
+
var Embeddings = class {
|
|
2505
|
+
/**
|
|
2506
|
+
* The async caller should be used by subclasses to make any async calls,
|
|
2507
|
+
* which will thus benefit from the concurrency and retry logic.
|
|
2508
|
+
*/
|
|
2509
|
+
caller;
|
|
2510
|
+
constructor(params) {
|
|
2511
|
+
this.caller = new AsyncCaller(params ?? {});
|
|
2512
|
+
}
|
|
2513
|
+
};
|
|
2514
|
+
|
|
2515
|
+
// src/integrations/langchain.ts
|
|
2516
|
+
var WarpEmbeddings = class extends Embeddings {
|
|
2517
|
+
baseEmbeddings;
|
|
2518
|
+
adapter;
|
|
2519
|
+
intentName;
|
|
2520
|
+
activation;
|
|
2521
|
+
autoBlend;
|
|
2522
|
+
constructor(options) {
|
|
2523
|
+
super(options);
|
|
2524
|
+
this.baseEmbeddings = options.baseEmbeddings;
|
|
2525
|
+
this.adapter = options.adapter;
|
|
2526
|
+
this.intentName = options.intentName;
|
|
2527
|
+
this.activation = options.activation;
|
|
2528
|
+
this.autoBlend = options.autoBlend ?? false;
|
|
2529
|
+
}
|
|
2530
|
+
/**
|
|
2531
|
+
* 実行時にアクティブな意図(インテント)を動的に切り替えます。
|
|
2532
|
+
*/
|
|
2533
|
+
setIntent(intentName, activation) {
|
|
2534
|
+
this.intentName = intentName;
|
|
2535
|
+
this.activation = activation;
|
|
2536
|
+
this.autoBlend = false;
|
|
2537
|
+
}
|
|
2538
|
+
/**
|
|
2539
|
+
* 自己アテンション型の動的意図合成(Auto-blending)を有効化または無効化します。
|
|
2540
|
+
*/
|
|
2541
|
+
setAutoBlend(enabled) {
|
|
2542
|
+
this.autoBlend = enabled;
|
|
2543
|
+
}
|
|
2544
|
+
/**
|
|
2545
|
+
* ベースの embeddings モデルを使用して、ドキュメントを通常通り埋め込みます。
|
|
2546
|
+
* VectorDB には客観的な空間データを含める必要があるため、インデックスされるドキュメントはワープ(変換)しません。
|
|
2547
|
+
*/
|
|
2548
|
+
async embedDocuments(documents) {
|
|
2549
|
+
return this.baseEmbeddings.embedDocuments(documents);
|
|
2550
|
+
}
|
|
2551
|
+
/**
|
|
2552
|
+
* ユーザーのクエリを埋め込み、WarpVector によるアフィン変換を適用します。
|
|
2553
|
+
*/
|
|
2554
|
+
async embedQuery(document) {
|
|
2555
|
+
const baseVector = await this.baseEmbeddings.embedQuery(document);
|
|
2556
|
+
let warped;
|
|
2557
|
+
if (this.autoBlend) {
|
|
2558
|
+
warped = this.adapter.tuneAutoBlended(baseVector, this.activation);
|
|
2559
|
+
} else {
|
|
2560
|
+
if (!this.intentName) {
|
|
2561
|
+
throw new Error(
|
|
2562
|
+
"WarpEmbeddings: intentName \u304C\u8A2D\u5B9A\u3055\u308C\u3066\u304A\u3089\u305A\u3001autoBlend \u3082 false \u3067\u3059\u3002setIntent() \u3092\u547C\u3073\u51FA\u3059\u304B autoBlend \u3092\u6709\u52B9\u306B\u3057\u3066\u304F\u3060\u3055\u3044\u3002"
|
|
2563
|
+
);
|
|
2564
|
+
}
|
|
2565
|
+
warped = this.adapter.tune(baseVector, this.intentName, this.activation);
|
|
2566
|
+
}
|
|
2567
|
+
return Array.from(warped);
|
|
2568
|
+
}
|
|
2569
|
+
};
|
|
2570
|
+
|
|
2571
|
+
// src/integrations/llama-index.ts
|
|
2572
|
+
var WarpLlamaIndexEmbeddings = class {
|
|
2573
|
+
baseEmbeddings;
|
|
2574
|
+
adapter;
|
|
2575
|
+
intentName;
|
|
2576
|
+
activation;
|
|
2577
|
+
autoBlend;
|
|
2578
|
+
constructor(options) {
|
|
2579
|
+
this.baseEmbeddings = options.baseEmbeddings;
|
|
2580
|
+
this.adapter = options.adapter;
|
|
2581
|
+
this.intentName = options.intentName;
|
|
2582
|
+
this.activation = options.activation;
|
|
2583
|
+
this.autoBlend = options.autoBlend ?? false;
|
|
2584
|
+
}
|
|
2585
|
+
setIntent(intentName, activation) {
|
|
2586
|
+
this.intentName = intentName;
|
|
2587
|
+
this.activation = activation;
|
|
2588
|
+
this.autoBlend = false;
|
|
2589
|
+
}
|
|
2590
|
+
setAutoBlend(enabled) {
|
|
2591
|
+
this.autoBlend = enabled;
|
|
2592
|
+
}
|
|
2593
|
+
/**
|
|
2594
|
+
* ドキュメントの埋め込み(インデックス作成用)は変換を行いません。
|
|
2595
|
+
*/
|
|
2596
|
+
async getTextEmbedding(text) {
|
|
2597
|
+
return this.baseEmbeddings.getTextEmbedding(text);
|
|
2598
|
+
}
|
|
2599
|
+
/**
|
|
2600
|
+
* 複数ドキュメントの埋め込み
|
|
2601
|
+
*/
|
|
2602
|
+
async getTextEmbeddings(texts) {
|
|
2603
|
+
if (this.baseEmbeddings.getTextEmbeddings) {
|
|
2604
|
+
return this.baseEmbeddings.getTextEmbeddings(texts);
|
|
2605
|
+
}
|
|
2606
|
+
return Promise.all(texts.map((t) => this.getTextEmbedding(t)));
|
|
2607
|
+
}
|
|
2608
|
+
/**
|
|
2609
|
+
* クエリの埋め込み(検索用)にのみ WarpVector 変換を適用します。
|
|
2610
|
+
*/
|
|
2611
|
+
async getQueryEmbedding(query) {
|
|
2612
|
+
const baseVector = await this.baseEmbeddings.getQueryEmbedding(query);
|
|
2613
|
+
let warped;
|
|
2614
|
+
if (this.autoBlend) {
|
|
2615
|
+
warped = this.adapter.tuneAutoBlended(baseVector, this.activation);
|
|
2616
|
+
} else {
|
|
2617
|
+
if (!this.intentName) {
|
|
2618
|
+
throw new Error(
|
|
2619
|
+
"WarpLlamaIndexEmbeddings: intentName \u304C\u8A2D\u5B9A\u3055\u308C\u3066\u304A\u3089\u305A\u3001autoBlend \u3082 false \u3067\u3059\u3002"
|
|
2620
|
+
);
|
|
2621
|
+
}
|
|
2622
|
+
warped = this.adapter.tune(baseVector, this.intentName, this.activation);
|
|
2623
|
+
}
|
|
2624
|
+
return Array.from(warped);
|
|
2625
|
+
}
|
|
2626
|
+
};
|
|
2627
|
+
|
|
2628
|
+
// src/QuantizationAdapter.ts
|
|
2629
|
+
var QuantizationAdapter = class _QuantizationAdapter {
|
|
2630
|
+
type;
|
|
2631
|
+
dim;
|
|
2632
|
+
dynamic;
|
|
2633
|
+
constructor(config) {
|
|
2634
|
+
this.type = config.type;
|
|
2635
|
+
this.dim = config.dim;
|
|
2636
|
+
this.dynamic = config.dynamic ?? false;
|
|
2637
|
+
if (this.type === "binary" && this.dim % 8 !== 0) {
|
|
2638
|
+
throw new Error(
|
|
2639
|
+
`Binary quantization requires dimension to be a multiple of 8. Got ${this.dim}`
|
|
2640
|
+
);
|
|
2641
|
+
}
|
|
2642
|
+
}
|
|
2643
|
+
tune(vector) {
|
|
2644
|
+
assertDimension(vector, this.dim, "QuantizationAdapter.tune");
|
|
2645
|
+
if (this.type === "int8") {
|
|
2646
|
+
if (this.dynamic) {
|
|
2647
|
+
let maxVal = 1e-8;
|
|
2648
|
+
for (let i = 0; i < this.dim; i++) {
|
|
2649
|
+
const abs = Math.abs(vector[i]);
|
|
2650
|
+
if (abs > maxVal) maxVal = abs;
|
|
2651
|
+
}
|
|
2652
|
+
const scale = 127 / maxVal;
|
|
2653
|
+
const result = new Int8Array(this.dim + 4);
|
|
2654
|
+
for (let i = 0; i < this.dim; i++) {
|
|
2655
|
+
let val = Math.round(vector[i] * scale);
|
|
2656
|
+
if (val > 127) val = 127;
|
|
2657
|
+
if (val < -128) val = -128;
|
|
2658
|
+
result[i] = val;
|
|
2659
|
+
}
|
|
2660
|
+
const view = new DataView(result.buffer, result.byteOffset, result.byteLength);
|
|
2661
|
+
view.setFloat32(this.dim, maxVal, true);
|
|
2662
|
+
return result;
|
|
2663
|
+
} else {
|
|
2664
|
+
const result = new Int8Array(this.dim);
|
|
2665
|
+
for (let i = 0; i < this.dim; i++) {
|
|
2666
|
+
let val = Math.round(vector[i] * 127);
|
|
2667
|
+
if (val > 127) val = 127;
|
|
2668
|
+
if (val < -128) val = -128;
|
|
2669
|
+
result[i] = val;
|
|
2670
|
+
}
|
|
2671
|
+
return result;
|
|
2672
|
+
}
|
|
2673
|
+
} else if (this.type === "binary") {
|
|
2674
|
+
const bytesLength = this.dim / 8;
|
|
2675
|
+
const result = new Uint8Array(bytesLength);
|
|
2676
|
+
for (let i = 0; i < this.dim; i++) {
|
|
2677
|
+
if (vector[i] > 0) {
|
|
2678
|
+
const byteIndex = Math.floor(i / 8);
|
|
2679
|
+
const bitIndex = i % 8;
|
|
2680
|
+
result[byteIndex] |= 1 << 7 - bitIndex;
|
|
2681
|
+
}
|
|
2682
|
+
}
|
|
2683
|
+
return result;
|
|
2684
|
+
}
|
|
2685
|
+
throw new Error(`Unknown quantization type: ${this.type}`);
|
|
2686
|
+
}
|
|
2687
|
+
/**
|
|
2688
|
+
* Binary量子化された2つのベクトル間のハミング距離を計算します。
|
|
2689
|
+
* ハミング距離が小さいほど類似度が高いことを意味します。
|
|
2690
|
+
*/
|
|
2691
|
+
static hammingDistance(a, b) {
|
|
2692
|
+
if (a.length !== b.length) throw new Error("Length mismatch");
|
|
2693
|
+
let distance = 0;
|
|
2694
|
+
for (let i = 0; i < a.length; i++) {
|
|
2695
|
+
let xor = a[i] ^ b[i];
|
|
2696
|
+
while (xor > 0) {
|
|
2697
|
+
distance++;
|
|
2698
|
+
xor &= xor - 1;
|
|
2699
|
+
}
|
|
2700
|
+
}
|
|
2701
|
+
return distance;
|
|
2702
|
+
}
|
|
2703
|
+
/**
|
|
2704
|
+
* Int8量子化された2つのベクトル間のドット積(内積)を計算します。
|
|
2705
|
+
* 動的スケーリングが埋め込まれている場合はスケールを戻して計算します。
|
|
2706
|
+
*/
|
|
2707
|
+
static int8DotProduct(a, b) {
|
|
2708
|
+
if (a.length !== b.length) throw new Error("Length mismatch");
|
|
2709
|
+
const hasScaleBytes = a.length > 4;
|
|
2710
|
+
let isDynamic = false;
|
|
2711
|
+
let maxA = 1;
|
|
2712
|
+
let maxB = 1;
|
|
2713
|
+
if (hasScaleBytes) {
|
|
2714
|
+
const dim = a.length - 4;
|
|
2715
|
+
try {
|
|
2716
|
+
const viewA = new DataView(a.buffer, a.byteOffset, a.byteLength);
|
|
2717
|
+
const viewB = new DataView(b.buffer, b.byteOffset, b.byteLength);
|
|
2718
|
+
maxA = viewA.getFloat32(dim, true);
|
|
2719
|
+
maxB = viewB.getFloat32(dim, true);
|
|
2720
|
+
if (!isNaN(maxA) && !isNaN(maxB) && maxA > 0 && maxA < 1e3 && maxB > 0 && maxB < 1e3) {
|
|
2721
|
+
isDynamic = true;
|
|
2722
|
+
}
|
|
2723
|
+
} catch (e) {
|
|
2724
|
+
isDynamic = false;
|
|
2725
|
+
}
|
|
2726
|
+
}
|
|
2727
|
+
if (isDynamic) {
|
|
2728
|
+
const dim = a.length - 4;
|
|
2729
|
+
let dot = 0;
|
|
2730
|
+
for (let i = 0; i < dim; i++) {
|
|
2731
|
+
dot += a[i] * b[i];
|
|
2732
|
+
}
|
|
2733
|
+
return dot * (maxA / 127) * (maxB / 127);
|
|
2734
|
+
} else {
|
|
2735
|
+
let dot = 0;
|
|
2736
|
+
for (let i = 0; i < a.length; i++) {
|
|
2737
|
+
dot += a[i] * b[i];
|
|
2738
|
+
}
|
|
2739
|
+
return dot;
|
|
2740
|
+
}
|
|
2741
|
+
}
|
|
2742
|
+
exportState() {
|
|
2743
|
+
return JSON.stringify({ type: this.type, dim: this.dim, dynamic: this.dynamic });
|
|
2744
|
+
}
|
|
2745
|
+
static importState(stateJson) {
|
|
2746
|
+
const config = JSON.parse(stateJson);
|
|
2747
|
+
return new _QuantizationAdapter(config);
|
|
2748
|
+
}
|
|
2749
|
+
};
|
|
2750
|
+
|
|
2751
|
+
// src/BaseTrainer.ts
|
|
2752
|
+
var AbstractAdamTrainer = class {
|
|
2753
|
+
t = 0;
|
|
2754
|
+
mW;
|
|
2755
|
+
vW;
|
|
2756
|
+
mb;
|
|
2757
|
+
vb;
|
|
2758
|
+
initAdamState(sDim, tDim) {
|
|
2759
|
+
if (!this.mW || this.mW.length !== sDim * tDim) {
|
|
2760
|
+
this.mW = new Float32Array(sDim * tDim);
|
|
2761
|
+
this.vW = new Float32Array(sDim * tDim);
|
|
2762
|
+
this.mb = new Float32Array(tDim);
|
|
2763
|
+
this.vb = new Float32Array(tDim);
|
|
2764
|
+
this.t = 0;
|
|
2765
|
+
}
|
|
2766
|
+
assertDimension(this.mW, sDim * tDim, "AdamState mW");
|
|
2767
|
+
}
|
|
2768
|
+
/**
|
|
2769
|
+
* アフィンレイヤー (matrix, bias) に対する Adam のパラメータ更新を適用します。
|
|
2770
|
+
* InfoNCE や Triplet など、様々な損失関数で計算された勾配(outputGradients)を元に更新を行います。
|
|
2771
|
+
*/
|
|
2772
|
+
applyAdamToAffine(matrix, bias, mMatrix, vMatrix, mBias, vBias, input, outputGradients, lr, reg, t) {
|
|
2773
|
+
const tDim = bias.length;
|
|
2774
|
+
const sDim = input.length;
|
|
2775
|
+
const beta1 = 0.9;
|
|
2776
|
+
const beta2 = 0.999;
|
|
2777
|
+
const epsilon = 1e-8;
|
|
2778
|
+
const instance = getWasmInstance();
|
|
2779
|
+
if (instance && instance.exports.adamUpdateWasm) {
|
|
2780
|
+
const memory = instance.exports.memory;
|
|
2781
|
+
const matrixBytes = matrix.byteLength;
|
|
2782
|
+
const biasBytes = bias.byteLength;
|
|
2783
|
+
const inputBytes = sDim * 4;
|
|
2784
|
+
const gradBytes = tDim * 4;
|
|
2785
|
+
const initialOffset = getWasmAllocatorOffset();
|
|
2786
|
+
try {
|
|
2787
|
+
const matrixPtr = allocateWasmMemory(matrixBytes);
|
|
2788
|
+
const biasPtr = allocateWasmMemory(biasBytes);
|
|
2789
|
+
const mMatrixPtr = allocateWasmMemory(matrixBytes);
|
|
2790
|
+
const vMatrixPtr = allocateWasmMemory(matrixBytes);
|
|
2791
|
+
const mBiasPtr = allocateWasmMemory(biasBytes);
|
|
2792
|
+
const vBiasPtr = allocateWasmMemory(biasBytes);
|
|
2793
|
+
const inputPtr = allocateWasmMemory(inputBytes);
|
|
2794
|
+
const gradPtr = allocateWasmMemory(gradBytes);
|
|
2795
|
+
writeFloat32ArrayToWasm(memory, matrix, matrixPtr);
|
|
2796
|
+
writeFloat32ArrayToWasm(memory, bias, biasPtr);
|
|
2797
|
+
writeFloat32ArrayToWasm(memory, mMatrix, mMatrixPtr);
|
|
2798
|
+
writeFloat32ArrayToWasm(memory, vMatrix, vMatrixPtr);
|
|
2799
|
+
writeFloat32ArrayToWasm(memory, mBias, mBiasPtr);
|
|
2800
|
+
writeFloat32ArrayToWasm(memory, vBias, vBiasPtr);
|
|
2801
|
+
writeFloat32ArrayToWasm(memory, input, inputPtr);
|
|
2802
|
+
writeFloat32ArrayToWasm(memory, outputGradients, gradPtr);
|
|
2803
|
+
const adamUpdateWasm = instance.exports.adamUpdateWasm;
|
|
2804
|
+
adamUpdateWasm(
|
|
2805
|
+
matrixPtr,
|
|
2806
|
+
biasPtr,
|
|
2807
|
+
mMatrixPtr,
|
|
2808
|
+
vMatrixPtr,
|
|
2809
|
+
mBiasPtr,
|
|
2810
|
+
vBiasPtr,
|
|
2811
|
+
inputPtr,
|
|
2812
|
+
gradPtr,
|
|
2813
|
+
lr,
|
|
2814
|
+
reg,
|
|
2815
|
+
beta1,
|
|
2816
|
+
beta2,
|
|
2817
|
+
epsilon,
|
|
2818
|
+
t,
|
|
2819
|
+
sDim,
|
|
2820
|
+
tDim
|
|
2821
|
+
);
|
|
2822
|
+
const f32 = new Float32Array(memory.buffer);
|
|
2823
|
+
matrix.set(f32.subarray(matrixPtr / 4, matrixPtr / 4 + matrix.length));
|
|
2824
|
+
bias.set(f32.subarray(biasPtr / 4, biasPtr / 4 + bias.length));
|
|
2825
|
+
mMatrix.set(f32.subarray(mMatrixPtr / 4, mMatrixPtr / 4 + mMatrix.length));
|
|
2826
|
+
vMatrix.set(f32.subarray(vMatrixPtr / 4, vMatrixPtr / 4 + vMatrix.length));
|
|
2827
|
+
mBias.set(f32.subarray(mBiasPtr / 4, mBiasPtr / 4 + mBias.length));
|
|
2828
|
+
vBias.set(f32.subarray(vBiasPtr / 4, vBiasPtr / 4 + vBias.length));
|
|
2829
|
+
} finally {
|
|
2830
|
+
setWasmAllocatorOffset(initialOffset);
|
|
2831
|
+
}
|
|
2832
|
+
} else {
|
|
2833
|
+
for (let i = 0; i < tDim; i++) {
|
|
2834
|
+
const bGrad = outputGradients[i];
|
|
2835
|
+
mBias[i] = beta1 * mBias[i] + (1 - beta1) * bGrad;
|
|
2836
|
+
vBias[i] = beta2 * vBias[i] + (1 - beta2) * (bGrad * bGrad);
|
|
2837
|
+
const mHatB = mBias[i] / (1 - Math.pow(beta1, t));
|
|
2838
|
+
const vHatB = vBias[i] / (1 - Math.pow(beta2, t));
|
|
2839
|
+
bias[i] -= lr * mHatB / (Math.sqrt(vHatB) + epsilon);
|
|
2840
|
+
const rowOffset = i * sDim;
|
|
2841
|
+
for (let j = 0; j < sDim; j++) {
|
|
2842
|
+
const wIdx = rowOffset + j;
|
|
2843
|
+
const wGrad = bGrad * input[j] + reg * matrix[wIdx];
|
|
2844
|
+
mMatrix[wIdx] = beta1 * mMatrix[wIdx] + (1 - beta1) * wGrad;
|
|
2845
|
+
vMatrix[wIdx] = beta2 * vMatrix[wIdx] + (1 - beta2) * (wGrad * wGrad);
|
|
2846
|
+
const mHatW = mMatrix[wIdx] / (1 - Math.pow(beta1, t));
|
|
2847
|
+
const vHatW = vMatrix[wIdx] / (1 - Math.pow(beta2, t));
|
|
2848
|
+
matrix[wIdx] -= lr * mHatW / (Math.sqrt(vHatW) + epsilon);
|
|
2849
|
+
}
|
|
2850
|
+
}
|
|
2851
|
+
}
|
|
2852
|
+
}
|
|
2853
|
+
};
|
|
2854
|
+
var BaseTrainer = class extends AbstractAdamTrainer {
|
|
2855
|
+
/** 学習用サンプルの配列 */
|
|
2856
|
+
examples = [];
|
|
2857
|
+
/**
|
|
2858
|
+
* 学習用のサンプルデータを追加します。
|
|
2859
|
+
* 次元数がソース/ターゲットと一致しない場合はエラーとなります。
|
|
2860
|
+
*
|
|
2861
|
+
* @param {TExample} example 追加するサンプルデータ
|
|
2862
|
+
* @throws {Error} 次元数が一致しない場合にスローされます。
|
|
2863
|
+
*/
|
|
2864
|
+
addExample(example) {
|
|
2865
|
+
const { source, target } = this.getInputs(example);
|
|
2866
|
+
assertDimension(
|
|
2867
|
+
source,
|
|
2868
|
+
this.sourceDimension,
|
|
2869
|
+
"BaseTrainer.addExample source"
|
|
2870
|
+
);
|
|
2871
|
+
assertDimension(
|
|
2872
|
+
target,
|
|
2873
|
+
this.targetDimension,
|
|
2874
|
+
"BaseTrainer.addExample target"
|
|
2875
|
+
);
|
|
2876
|
+
this.examples.push(example);
|
|
2877
|
+
}
|
|
2878
|
+
/**
|
|
2879
|
+
* 追加されたサンプルデータを用いて学習を実行します。
|
|
2880
|
+
* 指定されたエポック数だけ SGD + Momentum によるパラメータ更新を行います。
|
|
2881
|
+
* パフォーマンスのため、可能であれば内部で WebAssembly (WASM) を使用します。
|
|
2882
|
+
*
|
|
2883
|
+
* @param {BaseTrainingOptions} [options={}] 学習のハイパーパラメータオプション
|
|
2884
|
+
* @returns {Promise<TResult>} 学習済みの重みを返します。
|
|
2885
|
+
* @throws {Error} サンプルデータが追加されていない場合にスローされます。
|
|
2886
|
+
*/
|
|
2887
|
+
async train(options = {}) {
|
|
2888
|
+
await initWasm();
|
|
2889
|
+
if (this.examples.length === 0) {
|
|
2890
|
+
throw new Error("No training examples provided.");
|
|
2891
|
+
}
|
|
2892
|
+
if (options.autoTune) {
|
|
2893
|
+
options.learningRate = this.findBestLearningRate(options);
|
|
2894
|
+
options.autoTune = false;
|
|
2895
|
+
}
|
|
2896
|
+
const lr = options.learningRate ?? 0.01;
|
|
2897
|
+
const epochs = options.epochs ?? 100;
|
|
920
2898
|
const reg = options.regularization ?? 1e-3;
|
|
921
2899
|
const momentum = options.momentum ?? 0.9;
|
|
922
2900
|
const sDim = this.sourceDimension;
|
|
@@ -928,21 +2906,23 @@ var BaseTrainer = class {
|
|
|
928
2906
|
}
|
|
929
2907
|
}
|
|
930
2908
|
const bias = new Float32Array(tDim);
|
|
931
|
-
|
|
932
|
-
const vBias = new Float32Array(tDim);
|
|
2909
|
+
this.initAdamState(sDim, tDim);
|
|
933
2910
|
for (let epoch = 0; epoch < epochs; epoch++) {
|
|
934
2911
|
for (const example of this.examples) {
|
|
2912
|
+
this.t++;
|
|
935
2913
|
const { source, target } = this.getInputs(example);
|
|
936
|
-
this.
|
|
2914
|
+
this.adamStep(
|
|
937
2915
|
flatMatrix,
|
|
938
2916
|
bias,
|
|
939
|
-
|
|
940
|
-
|
|
2917
|
+
this.mW,
|
|
2918
|
+
this.vW,
|
|
2919
|
+
this.mb,
|
|
2920
|
+
this.vb,
|
|
941
2921
|
source,
|
|
942
2922
|
target,
|
|
943
2923
|
lr,
|
|
944
2924
|
reg,
|
|
945
|
-
|
|
2925
|
+
this.t
|
|
946
2926
|
);
|
|
947
2927
|
}
|
|
948
2928
|
}
|
|
@@ -970,21 +2950,27 @@ var BaseTrainer = class {
|
|
|
970
2950
|
if (i < sDim) flatMatrix[i * sDim + i] = 1;
|
|
971
2951
|
}
|
|
972
2952
|
const bias = new Float32Array(tDim);
|
|
2953
|
+
const mMatrix = new Float32Array(tDim * sDim);
|
|
973
2954
|
const vMatrix = new Float32Array(tDim * sDim);
|
|
2955
|
+
const mBias = new Float32Array(tDim);
|
|
974
2956
|
const vBias = new Float32Array(tDim);
|
|
2957
|
+
let t = 0;
|
|
975
2958
|
for (let epoch = 0; epoch < testEpochs; epoch++) {
|
|
976
2959
|
for (const example of this.examples) {
|
|
2960
|
+
t++;
|
|
977
2961
|
const { source, target } = this.getInputs(example);
|
|
978
|
-
this.
|
|
2962
|
+
this.adamStep(
|
|
979
2963
|
flatMatrix,
|
|
980
2964
|
bias,
|
|
2965
|
+
mMatrix,
|
|
981
2966
|
vMatrix,
|
|
2967
|
+
mBias,
|
|
982
2968
|
vBias,
|
|
983
2969
|
source,
|
|
984
2970
|
target,
|
|
985
2971
|
lr,
|
|
986
2972
|
reg,
|
|
987
|
-
|
|
2973
|
+
t
|
|
988
2974
|
);
|
|
989
2975
|
}
|
|
990
2976
|
}
|
|
@@ -992,12 +2978,8 @@ var BaseTrainer = class {
|
|
|
992
2978
|
for (const example of this.examples) {
|
|
993
2979
|
const { source, target } = this.getInputs(example);
|
|
994
2980
|
const pred = new Float32Array(tDim);
|
|
2981
|
+
applyAffine(flatMatrix, bias, source, pred, sDim, tDim);
|
|
995
2982
|
for (let i = 0; i < tDim; i++) {
|
|
996
|
-
let sum = 0;
|
|
997
|
-
for (let j = 0; j < sDim; j++) {
|
|
998
|
-
sum += flatMatrix[i * sDim + j] * source[j];
|
|
999
|
-
}
|
|
1000
|
-
pred[i] = sum + bias[i];
|
|
1001
2983
|
const diff = pred[i] - target[i];
|
|
1002
2984
|
currentLoss += diff * diff;
|
|
1003
2985
|
}
|
|
@@ -1007,170 +2989,304 @@ var BaseTrainer = class {
|
|
|
1007
2989
|
bestLr = lr;
|
|
1008
2990
|
}
|
|
1009
2991
|
}
|
|
1010
|
-
return bestLr;
|
|
2992
|
+
return bestLr;
|
|
2993
|
+
}
|
|
2994
|
+
/**
|
|
2995
|
+
* Adam オプティマイザによる1ステップのパラメータ更新を実行します。
|
|
2996
|
+
* In-place (破壊的) に `matrix` と `bias` を更新します。
|
|
2997
|
+
* WASM 版の Adam 実装ができるまではネイティブ JS で処理します。
|
|
2998
|
+
*/
|
|
2999
|
+
adamStep(matrix, bias, mMatrix, vMatrix, mBias, vBias, x, y, lr, reg, t) {
|
|
3000
|
+
const sDim = this.sourceDimension;
|
|
3001
|
+
const tDim = this.targetDimension;
|
|
3002
|
+
const beta1 = 0.9;
|
|
3003
|
+
const beta2 = 0.999;
|
|
3004
|
+
const epsilon = 1e-8;
|
|
3005
|
+
const pred = new Float32Array(tDim);
|
|
3006
|
+
applyAffine(matrix, bias, x, pred, sDim, tDim);
|
|
3007
|
+
const outputGradients = new Float32Array(tDim);
|
|
3008
|
+
for (let i = 0; i < tDim; i++) {
|
|
3009
|
+
outputGradients[i] = pred[i] - y[i];
|
|
3010
|
+
}
|
|
3011
|
+
this.applyAdamToAffine(
|
|
3012
|
+
matrix,
|
|
3013
|
+
bias,
|
|
3014
|
+
mMatrix,
|
|
3015
|
+
vMatrix,
|
|
3016
|
+
mBias,
|
|
3017
|
+
vBias,
|
|
3018
|
+
x,
|
|
3019
|
+
outputGradients,
|
|
3020
|
+
lr,
|
|
3021
|
+
reg,
|
|
3022
|
+
t
|
|
3023
|
+
);
|
|
3024
|
+
}
|
|
3025
|
+
};
|
|
3026
|
+
|
|
3027
|
+
// src/trainer.ts
|
|
3028
|
+
var IntentTrainer = class extends BaseTrainer {
|
|
3029
|
+
dimension;
|
|
3030
|
+
/**
|
|
3031
|
+
* IntentTrainer のインスタンスを作成します。
|
|
3032
|
+
* @param {number} dimension ベクトルの次元数(入力・出力ともに同じ次元数となります)
|
|
3033
|
+
*/
|
|
3034
|
+
constructor(dimension) {
|
|
3035
|
+
super();
|
|
3036
|
+
this.dimension = dimension;
|
|
3037
|
+
this.initAdamState(dimension, dimension);
|
|
3038
|
+
}
|
|
3039
|
+
get sourceDimension() {
|
|
3040
|
+
return this.dimension;
|
|
3041
|
+
}
|
|
3042
|
+
get targetDimension() {
|
|
3043
|
+
return this.dimension;
|
|
3044
|
+
}
|
|
3045
|
+
getInputs(example) {
|
|
3046
|
+
return { source: example.input, target: example.target };
|
|
3047
|
+
}
|
|
3048
|
+
toWeights(flatMatrix, bias) {
|
|
3049
|
+
return {
|
|
3050
|
+
matrix: flatMatrix,
|
|
3051
|
+
// 変換のオーバーヘッドを避けるためネイティブ配列のまま返す
|
|
3052
|
+
bias
|
|
3053
|
+
};
|
|
3054
|
+
}
|
|
3055
|
+
/**
|
|
3056
|
+
* オンライン学習 (フィードバックループ) 用のメソッド。
|
|
3057
|
+
* ユーザーのクリックなどの 1 回のフィードバックからリアルタイムに重みを微調整します。
|
|
3058
|
+
*
|
|
3059
|
+
* @param {IntentWeights} currentWeights - 現在の重み
|
|
3060
|
+
* @param {TrainingExample} example - アンカー、正解を含む学習データ
|
|
3061
|
+
* @param {IntentOnlineOptions} [options={}] - 学習オプション
|
|
3062
|
+
* @returns {IntentWeights} 微調整された新しい重み
|
|
3063
|
+
*/
|
|
3064
|
+
async updateOnline(currentWeights, example, options = {}) {
|
|
3065
|
+
const learningRate = options.learningRate ?? 0.01;
|
|
3066
|
+
const regularization = options.regularization ?? 1e-3;
|
|
3067
|
+
await initWasm();
|
|
3068
|
+
assertDimension(
|
|
3069
|
+
example.input,
|
|
3070
|
+
this.dimension,
|
|
3071
|
+
"IntentTrainer.addExample input"
|
|
3072
|
+
);
|
|
3073
|
+
assertDimension(
|
|
3074
|
+
example.target,
|
|
3075
|
+
this.dimension,
|
|
3076
|
+
"IntentTrainer.addExample target"
|
|
3077
|
+
);
|
|
3078
|
+
const dim = this.dimension;
|
|
3079
|
+
const { flatMatrix, bias } = getFlatMatrixAndBias(
|
|
3080
|
+
currentWeights,
|
|
3081
|
+
dim,
|
|
3082
|
+
"updateOnline Matrix"
|
|
3083
|
+
);
|
|
3084
|
+
const warpedInput = new Float32Array(dim);
|
|
3085
|
+
applyAffine(flatMatrix, bias, example.input, warpedInput, dim);
|
|
3086
|
+
const outputGradients = new Float32Array(dim);
|
|
3087
|
+
for (let i = 0; i < dim; i++) {
|
|
3088
|
+
outputGradients[i] = warpedInput[i] - example.target[i];
|
|
3089
|
+
}
|
|
3090
|
+
this.t++;
|
|
3091
|
+
this.applyAdamToAffine(
|
|
3092
|
+
flatMatrix,
|
|
3093
|
+
bias,
|
|
3094
|
+
this.mW,
|
|
3095
|
+
this.vW,
|
|
3096
|
+
this.mb,
|
|
3097
|
+
this.vb,
|
|
3098
|
+
example.input,
|
|
3099
|
+
outputGradients,
|
|
3100
|
+
learningRate,
|
|
3101
|
+
regularization,
|
|
3102
|
+
this.t
|
|
3103
|
+
);
|
|
3104
|
+
const newWeights = this.toWeights(flatMatrix, bias);
|
|
3105
|
+
if (currentWeights.routingVector) {
|
|
3106
|
+
newWeights.routingVector = [...currentWeights.routingVector];
|
|
3107
|
+
}
|
|
3108
|
+
return newWeights;
|
|
1011
3109
|
}
|
|
3110
|
+
};
|
|
3111
|
+
|
|
3112
|
+
// src/TripletTrainer.ts
|
|
3113
|
+
var TripletTrainer = class extends AbstractAdamTrainer {
|
|
3114
|
+
dimension;
|
|
1012
3115
|
/**
|
|
1013
|
-
*
|
|
1014
|
-
*
|
|
3116
|
+
* TripletTrainer のインスタンスを作成します。
|
|
3117
|
+
* @param {number} dimension ベクトルの次元数
|
|
3118
|
+
*/
|
|
3119
|
+
constructor(dimension) {
|
|
3120
|
+
super();
|
|
3121
|
+
this.dimension = dimension;
|
|
3122
|
+
this.initAdamState(dimension, dimension);
|
|
3123
|
+
}
|
|
3124
|
+
toWeights(flatMatrix, bias) {
|
|
3125
|
+
return {
|
|
3126
|
+
matrix: flatMatrix,
|
|
3127
|
+
// 変換のオーバーヘッドを避けるためネイティブ配列のまま返す
|
|
3128
|
+
bias
|
|
3129
|
+
};
|
|
3130
|
+
}
|
|
3131
|
+
/**
|
|
3132
|
+
* オンライン学習 (フィードバックループ) 用のメソッド。
|
|
3133
|
+
* 1つのトリプレットデータからリアルタイムに重みを微調整します。
|
|
1015
3134
|
*
|
|
1016
|
-
* @param {
|
|
1017
|
-
* @param {
|
|
1018
|
-
* @param {
|
|
1019
|
-
* @
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
sgdMomentumStepWasm(
|
|
1057
|
-
matrixOffset * 4,
|
|
1058
|
-
biasOffset * 4,
|
|
1059
|
-
vMatrixOffset * 4,
|
|
1060
|
-
vBiasOffset * 4,
|
|
1061
|
-
xOffset * 4,
|
|
1062
|
-
yOffset * 4,
|
|
1063
|
-
lr,
|
|
1064
|
-
reg,
|
|
1065
|
-
momentum,
|
|
1066
|
-
sDim,
|
|
1067
|
-
tDim,
|
|
1068
|
-
predOffset * 4
|
|
1069
|
-
);
|
|
1070
|
-
matrix.set(f32Mem.subarray(matrixOffset, matrixOffset + sDim * tDim));
|
|
1071
|
-
bias.set(f32Mem.subarray(biasOffset, biasOffset + tDim));
|
|
1072
|
-
vMatrix.set(f32Mem.subarray(vMatrixOffset, vMatrixOffset + sDim * tDim));
|
|
1073
|
-
vBias.set(f32Mem.subarray(vBiasOffset, vBiasOffset + tDim));
|
|
1074
|
-
return;
|
|
1075
|
-
}
|
|
1076
|
-
const pred = new Float32Array(tDim);
|
|
1077
|
-
for (let i = 0; i < tDim; i++) {
|
|
1078
|
-
let sum = 0;
|
|
1079
|
-
const rowOffset = i * sDim;
|
|
1080
|
-
for (let j = 0; j < sDim; j++) {
|
|
1081
|
-
sum += matrix[rowOffset + j] * x[j];
|
|
3135
|
+
* @param {IntentWeights} currentWeights - 現在の重み
|
|
3136
|
+
* @param {TripletExample} example - アンカー、正解、不正解を含むトリプレットデータ
|
|
3137
|
+
* @param {TripletOnlineOptions} [options={}] - 学習オプション
|
|
3138
|
+
* @returns {Promise<IntentWeights>} 微調整された新しい重み
|
|
3139
|
+
*/
|
|
3140
|
+
async updateOnline(currentWeights, example, options = {}) {
|
|
3141
|
+
const learningRate = options.learningRate ?? 0.01;
|
|
3142
|
+
const margin = options.margin ?? 0.1;
|
|
3143
|
+
const regularization = options.regularization ?? 1e-3;
|
|
3144
|
+
assertDimension(
|
|
3145
|
+
example.anchor,
|
|
3146
|
+
this.dimension,
|
|
3147
|
+
"TripletTrainer.train anchor"
|
|
3148
|
+
);
|
|
3149
|
+
assertDimension(
|
|
3150
|
+
example.positive,
|
|
3151
|
+
this.dimension,
|
|
3152
|
+
"TripletTrainer.train positive"
|
|
3153
|
+
);
|
|
3154
|
+
assertDimension(
|
|
3155
|
+
example.negative,
|
|
3156
|
+
this.dimension,
|
|
3157
|
+
"TripletTrainer.train negative"
|
|
3158
|
+
);
|
|
3159
|
+
const dim = this.dimension;
|
|
3160
|
+
const { flatMatrix, bias } = getFlatMatrixAndBias(
|
|
3161
|
+
currentWeights,
|
|
3162
|
+
dim,
|
|
3163
|
+
"updateOnline Matrix"
|
|
3164
|
+
);
|
|
3165
|
+
const warpedAnchor = new Float32Array(dim);
|
|
3166
|
+
applyAffine(flatMatrix, bias, example.anchor, warpedAnchor, dim);
|
|
3167
|
+
const posScore = innerProduct(warpedAnchor, example.positive);
|
|
3168
|
+
const negScore = innerProduct(warpedAnchor, example.negative);
|
|
3169
|
+
const loss = margin + negScore - posScore;
|
|
3170
|
+
if (loss > 0) {
|
|
3171
|
+
this.t += 1;
|
|
3172
|
+
const outputGradients = new Float32Array(dim);
|
|
3173
|
+
for (let i = 0; i < dim; i++) {
|
|
3174
|
+
outputGradients[i] = example.negative[i] - example.positive[i];
|
|
1082
3175
|
}
|
|
1083
|
-
|
|
3176
|
+
this.applyAdamToAffine(
|
|
3177
|
+
flatMatrix,
|
|
3178
|
+
bias,
|
|
3179
|
+
this.mW,
|
|
3180
|
+
this.vW,
|
|
3181
|
+
this.mb,
|
|
3182
|
+
this.vb,
|
|
3183
|
+
example.anchor,
|
|
3184
|
+
outputGradients,
|
|
3185
|
+
learningRate,
|
|
3186
|
+
regularization,
|
|
3187
|
+
this.t
|
|
3188
|
+
);
|
|
1084
3189
|
}
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
vBias[i] = momentum * vBias[i] - lr * bGrad;
|
|
1089
|
-
bias[i] += vBias[i];
|
|
1090
|
-
const rowOffset = i * sDim;
|
|
1091
|
-
for (let j = 0; j < sDim; j++) {
|
|
1092
|
-
const wIdx = rowOffset + j;
|
|
1093
|
-
const wGrad = error * x[j] + reg * matrix[wIdx];
|
|
1094
|
-
vMatrix[wIdx] = momentum * vMatrix[wIdx] - lr * wGrad;
|
|
1095
|
-
matrix[wIdx] += vMatrix[wIdx];
|
|
1096
|
-
}
|
|
3190
|
+
const newWeights = this.toWeights(flatMatrix, bias);
|
|
3191
|
+
if (currentWeights.routingVector) {
|
|
3192
|
+
newWeights.routingVector = [...currentWeights.routingVector];
|
|
1097
3193
|
}
|
|
3194
|
+
return newWeights;
|
|
1098
3195
|
}
|
|
1099
3196
|
};
|
|
1100
3197
|
|
|
1101
|
-
// src/
|
|
1102
|
-
var
|
|
3198
|
+
// src/InfoNCETrainer.ts
|
|
3199
|
+
var InfoNCETrainer = class extends AbstractAdamTrainer {
|
|
1103
3200
|
dimension;
|
|
1104
3201
|
/**
|
|
1105
|
-
*
|
|
1106
|
-
* @param {number} dimension
|
|
3202
|
+
* InfoNCETrainer のインスタンスを作成します。
|
|
3203
|
+
* @param {number} dimension ベクトルの次元数
|
|
1107
3204
|
*/
|
|
1108
3205
|
constructor(dimension) {
|
|
1109
3206
|
super();
|
|
1110
3207
|
this.dimension = dimension;
|
|
1111
|
-
|
|
1112
|
-
get sourceDimension() {
|
|
1113
|
-
return this.dimension;
|
|
1114
|
-
}
|
|
1115
|
-
get targetDimension() {
|
|
1116
|
-
return this.dimension;
|
|
1117
|
-
}
|
|
1118
|
-
getInputs(example) {
|
|
1119
|
-
return { source: example.input, target: example.target };
|
|
3208
|
+
this.initAdamState(dimension, dimension);
|
|
1120
3209
|
}
|
|
1121
3210
|
toWeights(flatMatrix, bias) {
|
|
1122
|
-
const dim = this.dimension;
|
|
1123
|
-
const outMatrix = new Array(dim);
|
|
1124
|
-
for (let i = 0; i < dim; i++) {
|
|
1125
|
-
const row = new Array(dim);
|
|
1126
|
-
const rowOffset = i * dim;
|
|
1127
|
-
for (let j = 0; j < dim; j++) {
|
|
1128
|
-
row[j] = flatMatrix[rowOffset + j];
|
|
1129
|
-
}
|
|
1130
|
-
outMatrix[i] = row;
|
|
1131
|
-
}
|
|
1132
3211
|
return {
|
|
1133
|
-
matrix:
|
|
1134
|
-
|
|
3212
|
+
matrix: flatMatrix,
|
|
3213
|
+
// ネイティブ配列のまま返す
|
|
3214
|
+
bias
|
|
1135
3215
|
};
|
|
1136
3216
|
}
|
|
1137
3217
|
/**
|
|
1138
3218
|
* オンライン学習 (フィードバックループ) 用のメソッド。
|
|
1139
|
-
*
|
|
3219
|
+
* 1つのクエリ(Anchor)、1つのクリック(Positive)、複数のスルー(Negatives)から重みを微調整します。
|
|
1140
3220
|
*
|
|
1141
3221
|
* @param {IntentWeights} currentWeights - 現在の重み
|
|
1142
|
-
* @param {
|
|
1143
|
-
* @param {
|
|
1144
|
-
* @
|
|
1145
|
-
* @param {number} regularization - L2正則化の強さ (デフォルト: 0.001)
|
|
1146
|
-
* @returns {IntentWeights} 微調整された新しい重み
|
|
3222
|
+
* @param {InfoNCEExample} example - アンカー、正解、複数の不正解を含むデータ
|
|
3223
|
+
* @param {InfoNCEOnlineOptions} [options={}] - 学習オプション
|
|
3224
|
+
* @returns {Promise<IntentWeights>} 微調整された新しい重み
|
|
1147
3225
|
*/
|
|
1148
|
-
async updateOnline(currentWeights,
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
}
|
|
3226
|
+
async updateOnline(currentWeights, example, options = {}) {
|
|
3227
|
+
const learningRate = options.learningRate ?? 0.01;
|
|
3228
|
+
const temperature = options.temperature ?? 0.1;
|
|
3229
|
+
const regularization = options.regularization ?? 1e-3;
|
|
1153
3230
|
const dim = this.dimension;
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
3231
|
+
assertDimension(example.anchor, dim, "InfoNCETrainer.train anchor");
|
|
3232
|
+
assertDimension(example.positive, dim, "InfoNCETrainer.train positive");
|
|
3233
|
+
if (example.negatives.length === 0) {
|
|
3234
|
+
throw new Error("InfoNCETrainer requires at least one negative example.");
|
|
3235
|
+
}
|
|
3236
|
+
for (const neg of example.negatives) {
|
|
3237
|
+
assertDimension(neg, dim, "InfoNCETrainer.train negative");
|
|
1159
3238
|
}
|
|
1160
|
-
const bias =
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
3239
|
+
const { flatMatrix, bias } = getFlatMatrixAndBias(
|
|
3240
|
+
currentWeights,
|
|
3241
|
+
dim,
|
|
3242
|
+
"updateOnline Matrix"
|
|
3243
|
+
);
|
|
3244
|
+
const warpedAnchor = new Float32Array(dim);
|
|
3245
|
+
applyAffine(flatMatrix, bias, example.anchor, warpedAnchor, dim);
|
|
3246
|
+
const posScore = innerProduct(warpedAnchor, example.positive);
|
|
3247
|
+
const negScores = new Float32Array(example.negatives.length);
|
|
3248
|
+
for (let n = 0; n < example.negatives.length; n++) {
|
|
3249
|
+
negScores[n] = innerProduct(warpedAnchor, example.negatives[n]);
|
|
3250
|
+
}
|
|
3251
|
+
let maxScore = posScore / temperature;
|
|
3252
|
+
for (let n = 0; n < example.negatives.length; n++) {
|
|
3253
|
+
const s = negScores[n] / temperature;
|
|
3254
|
+
if (s > maxScore) maxScore = s;
|
|
3255
|
+
}
|
|
3256
|
+
const expPos = Math.exp(posScore / temperature - maxScore);
|
|
3257
|
+
const expNegs = new Float32Array(example.negatives.length);
|
|
3258
|
+
let sumExp = expPos;
|
|
3259
|
+
for (let n = 0; n < example.negatives.length; n++) {
|
|
3260
|
+
const expN = Math.exp(negScores[n] / temperature - maxScore);
|
|
3261
|
+
expNegs[n] = expN;
|
|
3262
|
+
sumExp += expN;
|
|
3263
|
+
}
|
|
3264
|
+
const pPos = expPos / sumExp;
|
|
3265
|
+
const pNegs = new Float32Array(example.negatives.length);
|
|
3266
|
+
for (let n = 0; n < example.negatives.length; n++) {
|
|
3267
|
+
pNegs[n] = expNegs[n] / sumExp;
|
|
3268
|
+
}
|
|
3269
|
+
this.t += 1;
|
|
3270
|
+
const outputGradients = new Float32Array(dim);
|
|
3271
|
+
for (let i = 0; i < dim; i++) {
|
|
3272
|
+
let gradA_i = (pPos - 1) * example.positive[i];
|
|
3273
|
+
for (let n = 0; n < example.negatives.length; n++) {
|
|
3274
|
+
gradA_i += pNegs[n] * example.negatives[n][i];
|
|
3275
|
+
}
|
|
3276
|
+
outputGradients[i] = gradA_i / temperature;
|
|
3277
|
+
}
|
|
3278
|
+
this.applyAdamToAffine(
|
|
1164
3279
|
flatMatrix,
|
|
1165
3280
|
bias,
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
3281
|
+
this.mW,
|
|
3282
|
+
this.vW,
|
|
3283
|
+
this.mb,
|
|
3284
|
+
this.vb,
|
|
3285
|
+
example.anchor,
|
|
3286
|
+
outputGradients,
|
|
1170
3287
|
learningRate,
|
|
1171
3288
|
regularization,
|
|
1172
|
-
|
|
1173
|
-
// no momentum for 1-shot online update
|
|
3289
|
+
this.t
|
|
1174
3290
|
);
|
|
1175
3291
|
const newWeights = this.toWeights(flatMatrix, bias);
|
|
1176
3292
|
if (currentWeights.routingVector) {
|
|
@@ -1221,78 +3337,520 @@ var MigrationTrainer = class extends BaseTrainer {
|
|
|
1221
3337
|
}
|
|
1222
3338
|
};
|
|
1223
3339
|
|
|
1224
|
-
// src/
|
|
1225
|
-
var
|
|
3340
|
+
// src/integrations/index.ts
|
|
3341
|
+
var integrations_exports = {};
|
|
3342
|
+
__export(integrations_exports, {
|
|
3343
|
+
WarpEmbeddings: () => WarpEmbeddings,
|
|
3344
|
+
withWarpVector: () => withWarpVector
|
|
3345
|
+
});
|
|
3346
|
+
|
|
3347
|
+
// src/VsaAdapter.ts
|
|
3348
|
+
var VsaAdapter = class _VsaAdapter {
|
|
1226
3349
|
/**
|
|
1227
|
-
*
|
|
1228
|
-
*
|
|
3350
|
+
* ベクトルのバンドリング (Bundling / Superposition)
|
|
3351
|
+
* 複数のベクトルを足し合わせ(重ね合わせ)て1つのベクトルに統合します。
|
|
3352
|
+
* 「A と B の両方の概念を含む」ベクトルを作成する際に使用します。
|
|
1229
3353
|
*
|
|
1230
|
-
* @
|
|
1231
|
-
*
|
|
3354
|
+
* @param vectors 束ねるベクトルの配列
|
|
3355
|
+
* @param options 演算オプション
|
|
3356
|
+
* @returns 束ねられた新しいベクトル
|
|
3357
|
+
*/
|
|
3358
|
+
static bundle(vectors, options = {}) {
|
|
3359
|
+
if (vectors.length === 0) {
|
|
3360
|
+
throw new Error("Cannot bundle an empty array of vectors.");
|
|
3361
|
+
}
|
|
3362
|
+
const dim = vectors[0].length;
|
|
3363
|
+
const result = new Float32Array(dim);
|
|
3364
|
+
for (let i = 0; i < vectors.length; i++) {
|
|
3365
|
+
const vec = vectors[i];
|
|
3366
|
+
assertDimension(vec, dim, `Vector at index ${i}`);
|
|
3367
|
+
addScaledVector(result, vec, 1);
|
|
3368
|
+
}
|
|
3369
|
+
const shouldNormalize = options.shouldNormalize ?? true;
|
|
3370
|
+
if (shouldNormalize) {
|
|
3371
|
+
return normalize(result);
|
|
3372
|
+
}
|
|
3373
|
+
return result;
|
|
3374
|
+
}
|
|
3375
|
+
/**
|
|
3376
|
+
* ベクトルのバインディング (Binding / Hadamard Product)
|
|
3377
|
+
* アダマール積(要素ごとの積)を用いて、2つのベクトルを「結合」します。
|
|
3378
|
+
* 例: キー(ユーザーID)と値(好み)を掛け合わせ、特有の「ユーザーの好み」ベクトルを生成します。
|
|
1232
3379
|
*
|
|
1233
|
-
* @param
|
|
1234
|
-
* @
|
|
3380
|
+
* @param vec1 バインドするベクトル1
|
|
3381
|
+
* @param vec2 バインドするベクトル2
|
|
3382
|
+
* @param options 演算オプション
|
|
3383
|
+
* @returns バインドされた新しいベクトル
|
|
1235
3384
|
*/
|
|
1236
|
-
static
|
|
1237
|
-
|
|
3385
|
+
static bind(vec1, vec2, options = {}) {
|
|
3386
|
+
const dim = vec1.length;
|
|
3387
|
+
assertDimension(vec2, dim, "Vector 2");
|
|
3388
|
+
const result = new Float32Array(dim);
|
|
3389
|
+
for (let i = 0; i < dim; i++) {
|
|
3390
|
+
result[i] = vec1[i] * vec2[i];
|
|
3391
|
+
}
|
|
3392
|
+
const shouldNormalize = options.shouldNormalize ?? true;
|
|
3393
|
+
if (shouldNormalize) {
|
|
3394
|
+
return normalize(result);
|
|
3395
|
+
}
|
|
3396
|
+
return result;
|
|
1238
3397
|
}
|
|
1239
3398
|
/**
|
|
1240
|
-
*
|
|
1241
|
-
*
|
|
3399
|
+
* ベクトルのアンバインディング (Unbinding)
|
|
3400
|
+
* バインドされたベクトルから、片方のベクトル(キー)を使って元の値(バリュー)を取り出します。
|
|
3401
|
+
* アダマール積によるバインディングの逆演算(要素ごとの除算)を行います。
|
|
1242
3402
|
*
|
|
1243
|
-
* @
|
|
1244
|
-
*
|
|
1245
|
-
*
|
|
3403
|
+
* @param boundVec バインド済みのベクトル
|
|
3404
|
+
* @param keyVec 抽出に使用するキーベクトル
|
|
3405
|
+
* @param options 演算オプション
|
|
3406
|
+
* @returns アンバインドされて抽出されたベクトル
|
|
3407
|
+
*/
|
|
3408
|
+
static unbind(boundVec, keyVec, options = {}) {
|
|
3409
|
+
const dim = boundVec.length;
|
|
3410
|
+
assertDimension(keyVec, dim, "Key Vector");
|
|
3411
|
+
const result = new Float32Array(dim);
|
|
3412
|
+
for (let i = 0; i < dim; i++) {
|
|
3413
|
+
const val = keyVec[i] === 0 ? 1e-8 : keyVec[i];
|
|
3414
|
+
result[i] = boundVec[i] / val;
|
|
3415
|
+
}
|
|
3416
|
+
const shouldNormalize = options.shouldNormalize ?? true;
|
|
3417
|
+
if (shouldNormalize) {
|
|
3418
|
+
return normalize(result);
|
|
3419
|
+
}
|
|
3420
|
+
return result;
|
|
3421
|
+
}
|
|
3422
|
+
/**
|
|
3423
|
+
* ---------------------------------------------------------
|
|
3424
|
+
* Binary VSA (バイナリベクトル・シンボリック・アーキテクチャ)
|
|
3425
|
+
* ---------------------------------------------------------
|
|
3426
|
+
* QuantizationAdapter で 1-bit (Binary) 量子化された Uint8Array ベクトルに
|
|
3427
|
+
* 対する超次元計算を行います。XOR 演算により、超高速・極小メモリでの処理が可能です。
|
|
3428
|
+
*/
|
|
3429
|
+
/**
|
|
3430
|
+
* バイナリベクトルのバインディング (Binary Binding / XOR)
|
|
3431
|
+
* XOR (排他的論理和) を用いて2つのバイナリベクトルを結合します。
|
|
3432
|
+
* Binary VSA において、XOR は情報を結合するための標準的な演算です。
|
|
1246
3433
|
*
|
|
1247
|
-
* @param
|
|
1248
|
-
* @param
|
|
1249
|
-
* @
|
|
1250
|
-
* @returns {Record<string, any>} Pineconeのqueryメソッド用オブジェクト
|
|
3434
|
+
* @param bin1 バインドするバイナリベクトル1 (Uint8Array)
|
|
3435
|
+
* @param bin2 バインドするバイナリベクトル2 (Uint8Array)
|
|
3436
|
+
* @returns バインドされた新しいバイナリベクトル (Uint8Array)
|
|
1251
3437
|
*/
|
|
1252
|
-
static
|
|
3438
|
+
static bindBinary(bin1, bin2) {
|
|
3439
|
+
if (bin1.length !== bin2.length) {
|
|
3440
|
+
throw new Error("Binary vectors must have the same length in bytes.");
|
|
3441
|
+
}
|
|
3442
|
+
const len = bin1.length;
|
|
3443
|
+
const result = new Uint8Array(len);
|
|
3444
|
+
for (let i = 0; i < len; i++) {
|
|
3445
|
+
result[i] = bin1[i] ^ bin2[i];
|
|
3446
|
+
}
|
|
3447
|
+
return result;
|
|
3448
|
+
}
|
|
3449
|
+
/**
|
|
3450
|
+
* バイナリベクトルのアンバインディング (Binary Unbinding / XOR)
|
|
3451
|
+
* XOR の自己逆性 (A ^ B ^ B = A) を利用して、キーを用いて元の値を抽出します。
|
|
3452
|
+
* 内部的には bindBinary と全く同じ処理です。
|
|
3453
|
+
*
|
|
3454
|
+
* @param boundBin バインド済みのバイナリベクトル (Uint8Array)
|
|
3455
|
+
* @param keyBin 抽出に使用するキーバイナリベクトル (Uint8Array)
|
|
3456
|
+
* @returns アンバインドされて抽出されたバイナリベクトル (Uint8Array)
|
|
3457
|
+
*/
|
|
3458
|
+
static unbindBinary(boundBin, keyBin) {
|
|
3459
|
+
return _VsaAdapter.bindBinary(boundBin, keyBin);
|
|
3460
|
+
}
|
|
3461
|
+
/**
|
|
3462
|
+
* バイナリベクトルのバンドリング (Binary Bundling / Majority Vote)
|
|
3463
|
+
* 複数のバイナリベクトルを重ね合わせます。各ビット位置で 1 と 0 の出現回数をカウントし、
|
|
3464
|
+
* 多数決 (Majority Vote) で最終的なビットを決定します。
|
|
3465
|
+
*
|
|
3466
|
+
* @param bins 束ねるバイナリベクトルの配列 (Uint8Arrayの配列)
|
|
3467
|
+
* @returns 束ねられた新しいバイナリベクトル (Uint8Array)
|
|
3468
|
+
*/
|
|
3469
|
+
static bundleBinary(bins) {
|
|
3470
|
+
if (bins.length === 0) {
|
|
3471
|
+
throw new Error("Cannot bundle an empty array of binary vectors.");
|
|
3472
|
+
}
|
|
3473
|
+
const numVectors = bins.length;
|
|
3474
|
+
const len = bins[0].length;
|
|
3475
|
+
const result = new Uint8Array(len);
|
|
3476
|
+
for (let i = 0; i < len; i++) {
|
|
3477
|
+
let resultByte = 0;
|
|
3478
|
+
for (let bit = 0; bit < 8; bit++) {
|
|
3479
|
+
let onesCount = 0;
|
|
3480
|
+
const mask = 1 << bit;
|
|
3481
|
+
for (let v = 0; v < numVectors; v++) {
|
|
3482
|
+
if (bins[v].length !== len) {
|
|
3483
|
+
throw new Error(
|
|
3484
|
+
`Binary vector at index ${v} has mismatched length.`
|
|
3485
|
+
);
|
|
3486
|
+
}
|
|
3487
|
+
if ((bins[v][i] & mask) !== 0) {
|
|
3488
|
+
onesCount++;
|
|
3489
|
+
}
|
|
3490
|
+
}
|
|
3491
|
+
if (onesCount > numVectors / 2) {
|
|
3492
|
+
resultByte |= mask;
|
|
3493
|
+
} else if (onesCount === numVectors / 2) {
|
|
3494
|
+
resultByte |= mask;
|
|
3495
|
+
}
|
|
3496
|
+
}
|
|
3497
|
+
result[i] = resultByte;
|
|
3498
|
+
}
|
|
3499
|
+
return result;
|
|
3500
|
+
}
|
|
3501
|
+
};
|
|
3502
|
+
|
|
3503
|
+
// src/TaskArithmetic.ts
|
|
3504
|
+
var TaskArithmetic = class {
|
|
3505
|
+
/**
|
|
3506
|
+
* 複数のタスク(IntentWeights)を合成し、新しい IntentWeights を作成します。
|
|
3507
|
+
* 数式: W_new = W_base + Σ scale_i * (W_i - W_base)
|
|
3508
|
+
*
|
|
3509
|
+
* @param tasks 合成するタスクのリスト(IntentWeights と スケールのペア)
|
|
3510
|
+
* @param baseIntent 基準となる IntentWeights。省略された場合は恒等行列(Identity)とゼロバイアスがベースになります。
|
|
3511
|
+
* @returns 完全にマージされた新しい IntentWeights
|
|
3512
|
+
*/
|
|
3513
|
+
static merge(tasks, baseIntent) {
|
|
3514
|
+
if (tasks.length === 0) {
|
|
3515
|
+
throw new Error("No tasks provided to merge.");
|
|
3516
|
+
}
|
|
3517
|
+
const dim = tasks[0].weights.bias.length;
|
|
3518
|
+
let baseMatrix;
|
|
3519
|
+
let baseBias;
|
|
3520
|
+
if (baseIntent) {
|
|
3521
|
+
assertDimension(baseIntent.bias, dim, "Base bias");
|
|
3522
|
+
baseBias = new Float32Array(baseIntent.bias);
|
|
3523
|
+
if (baseIntent.matrix instanceof Float32Array) {
|
|
3524
|
+
assertDimension(baseIntent.matrix, dim * dim, "Base matrix");
|
|
3525
|
+
baseMatrix = new Float32Array(baseIntent.matrix);
|
|
3526
|
+
} else {
|
|
3527
|
+
baseMatrix = flattenMatrix(baseIntent.matrix, dim, dim, "Base matrix");
|
|
3528
|
+
}
|
|
3529
|
+
} else {
|
|
3530
|
+
baseMatrix = new Float32Array(dim * dim);
|
|
3531
|
+
for (let i = 0; i < dim; i++) {
|
|
3532
|
+
baseMatrix[i * dim + i] = 1;
|
|
3533
|
+
}
|
|
3534
|
+
baseBias = new Float32Array(dim);
|
|
3535
|
+
}
|
|
3536
|
+
const newMatrix = new Float32Array(baseMatrix);
|
|
3537
|
+
const newBias = new Float32Array(baseBias);
|
|
3538
|
+
for (let t = 0; t < tasks.length; t++) {
|
|
3539
|
+
const { weights, scale } = tasks[t];
|
|
3540
|
+
assertDimension(weights.bias, dim, `Task ${t} bias`);
|
|
3541
|
+
const taskBias = new Float32Array(weights.bias);
|
|
3542
|
+
let taskMatrix;
|
|
3543
|
+
if (weights.matrix instanceof Float32Array) {
|
|
3544
|
+
assertDimension(weights.matrix, dim * dim, `Task ${t} matrix`);
|
|
3545
|
+
taskMatrix = weights.matrix;
|
|
3546
|
+
} else {
|
|
3547
|
+
taskMatrix = flattenMatrix(
|
|
3548
|
+
weights.matrix,
|
|
3549
|
+
dim,
|
|
3550
|
+
dim,
|
|
3551
|
+
`Task ${t} matrix`
|
|
3552
|
+
);
|
|
3553
|
+
}
|
|
3554
|
+
addScaledVector(newMatrix, taskMatrix, scale);
|
|
3555
|
+
addScaledVector(newMatrix, baseMatrix, -scale);
|
|
3556
|
+
addScaledVector(newBias, taskBias, scale);
|
|
3557
|
+
addScaledVector(newBias, baseBias, -scale);
|
|
3558
|
+
}
|
|
1253
3559
|
return {
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
...filter ? { filter } : {}
|
|
3560
|
+
matrix: newMatrix,
|
|
3561
|
+
bias: newBias
|
|
1257
3562
|
};
|
|
1258
3563
|
}
|
|
3564
|
+
};
|
|
3565
|
+
|
|
3566
|
+
// src/WarpPipeline.ts
|
|
3567
|
+
var WarpPipeline = class _WarpPipeline {
|
|
3568
|
+
constructor(inputDim) {
|
|
3569
|
+
this.inputDim = inputDim;
|
|
3570
|
+
}
|
|
3571
|
+
inputDim;
|
|
3572
|
+
steps = [];
|
|
1259
3573
|
/**
|
|
1260
|
-
*
|
|
1261
|
-
*
|
|
1262
|
-
|
|
3574
|
+
* アダプタの復元関数を保持するレジストリ。
|
|
3575
|
+
* カスタムアダプタをパイプラインで利用・復元可能にするために使用します。
|
|
3576
|
+
*/
|
|
3577
|
+
static adapterRegistry = /* @__PURE__ */ new Map();
|
|
3578
|
+
/**
|
|
3579
|
+
* カスタムアダプタをパイプラインのレジストリに登録します。
|
|
3580
|
+
* これにより importState でカスタムアダプタを復元可能になります。
|
|
1263
3581
|
*
|
|
1264
|
-
* @
|
|
1265
|
-
*
|
|
1266
|
-
|
|
3582
|
+
* @param type アダプタの識別子 (例: "MyCustomAdapter")
|
|
3583
|
+
* @param importFn 状態オブジェクトからアダプタインスタンスを復元する関数
|
|
3584
|
+
*/
|
|
3585
|
+
static registerAdapter(type, importFn) {
|
|
3586
|
+
_WarpPipeline.adapterRegistry.set(type, importFn);
|
|
3587
|
+
}
|
|
3588
|
+
/**
|
|
3589
|
+
* フォーマット変換ロジックを保持するレジストリ。
|
|
3590
|
+
*/
|
|
3591
|
+
static formatRegistry = /* @__PURE__ */ new Map();
|
|
3592
|
+
/**
|
|
3593
|
+
* カスタムの出力フォーマットを登録します。
|
|
3594
|
+
* これにより、ユーザー独自のDB形式(Milvus, Weaviateなど)への変換を動的に追加できます。
|
|
1267
3595
|
*
|
|
1268
|
-
* @param
|
|
1269
|
-
* @
|
|
3596
|
+
* @param format フォーマット名 (例: "pgvector")
|
|
3597
|
+
* @param formatFn 変換を行うコールバック関数
|
|
1270
3598
|
*/
|
|
1271
|
-
static
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
3599
|
+
static registerFormat(format, formatFn) {
|
|
3600
|
+
_WarpPipeline.formatRegistry.set(format, formatFn);
|
|
3601
|
+
}
|
|
3602
|
+
/**
|
|
3603
|
+
* IntentAdapter (意図による線形変換) をパイプラインに追加します。
|
|
3604
|
+
*/
|
|
3605
|
+
addIntent(intents) {
|
|
3606
|
+
const adapter = new IntentAdapter(intents || this.inputDim);
|
|
3607
|
+
this.steps.push({ type: "IntentAdapter", adapter });
|
|
3608
|
+
return this;
|
|
3609
|
+
}
|
|
3610
|
+
/**
|
|
3611
|
+
* LoraIntentAdapter (低ランク適応による線形変換) をパイプラインに追加します。
|
|
3612
|
+
*/
|
|
3613
|
+
addLoraIntent(rank, intents) {
|
|
3614
|
+
const adapter = new LoraIntentAdapter(this.inputDim, rank, intents);
|
|
3615
|
+
this.steps.push({ type: "LoraIntentAdapter", adapter });
|
|
3616
|
+
return this;
|
|
3617
|
+
}
|
|
3618
|
+
/**
|
|
3619
|
+
* WhiteningAdapter (PCAによる空間的偏りの除去) をパイプラインに追加します。
|
|
3620
|
+
*/
|
|
3621
|
+
addWhitening(options) {
|
|
3622
|
+
const adapter = new WhiteningAdapter(this.inputDim, options);
|
|
3623
|
+
this.steps.push({ type: "WhiteningAdapter", adapter });
|
|
3624
|
+
return this;
|
|
3625
|
+
}
|
|
3626
|
+
/**
|
|
3627
|
+
* ProjectionAdapter (次元圧縮) をパイプラインに追加します。
|
|
3628
|
+
*/
|
|
3629
|
+
addProjection(outputDim, projections) {
|
|
3630
|
+
const adapter = new ProjectionAdapter(
|
|
3631
|
+
this.inputDim,
|
|
3632
|
+
outputDim,
|
|
3633
|
+
projections
|
|
1278
3634
|
);
|
|
3635
|
+
this.steps.push({ type: "ProjectionAdapter", adapter });
|
|
3636
|
+
this.inputDim = outputDim;
|
|
3637
|
+
return this;
|
|
3638
|
+
}
|
|
3639
|
+
/**
|
|
3640
|
+
* MlpAdapter (多層ニューラルネットワーク / 非線形推論) をパイプラインに追加します。
|
|
3641
|
+
*/
|
|
3642
|
+
addMlp(layers) {
|
|
3643
|
+
const adapter = new MlpAdapter(layers);
|
|
3644
|
+
this.steps.push({ type: "MlpAdapter", adapter });
|
|
3645
|
+
const lastLayer = layers[layers.length - 1];
|
|
3646
|
+
if (lastLayer.matrix instanceof Float32Array) {
|
|
3647
|
+
this.inputDim = lastLayer.bias.length;
|
|
3648
|
+
} else {
|
|
3649
|
+
this.inputDim = lastLayer.matrix.length;
|
|
3650
|
+
}
|
|
3651
|
+
return this;
|
|
3652
|
+
}
|
|
3653
|
+
/**
|
|
3654
|
+
* QuantizationAdapter (ベクトル量子化 / 圧縮) をパイプラインに追加します。
|
|
3655
|
+
* これは通常、パイプラインの最後のステップとして使用されます。
|
|
3656
|
+
*/
|
|
3657
|
+
quantize(type) {
|
|
3658
|
+
const adapter = new QuantizationAdapter({ type, dim: this.inputDim });
|
|
3659
|
+
this.steps.push({ type: "QuantizationAdapter", adapter });
|
|
3660
|
+
return this;
|
|
3661
|
+
}
|
|
3662
|
+
/**
|
|
3663
|
+
* カスタムアダプタを直接パイプラインの末尾に追加します。
|
|
3664
|
+
* (ビルダーパターンで独自の拡張アダプタを組み込む際に使用します)
|
|
3665
|
+
*
|
|
3666
|
+
* @param type アダプタの識別子(レジストリ登録名と一致させることを推奨)
|
|
3667
|
+
* @param adapter WarpAdapterを実装したインスタンス
|
|
3668
|
+
*/
|
|
3669
|
+
addStep(type, adapter) {
|
|
3670
|
+
this.steps.push({ type, adapter });
|
|
3671
|
+
return this;
|
|
3672
|
+
}
|
|
3673
|
+
/**
|
|
3674
|
+
* パイプライン内に WASM などの非同期初期化を必要とするアダプタが含まれている場合、
|
|
3675
|
+
* それらを一括でセットアップします。
|
|
3676
|
+
*/
|
|
3677
|
+
async init() {
|
|
3678
|
+
for (const step of this.steps) {
|
|
3679
|
+
if (typeof step.adapter.init === "function") {
|
|
3680
|
+
await step.adapter.init();
|
|
3681
|
+
}
|
|
3682
|
+
}
|
|
3683
|
+
}
|
|
3684
|
+
/**
|
|
3685
|
+
* パイプラインを順次実行し、入力ベクトルを最終的な表現に変換します。
|
|
3686
|
+
*
|
|
3687
|
+
* @param vector 変換元のベースベクトル
|
|
3688
|
+
* @param context インテントやバージョンなどのコンテキスト情報
|
|
3689
|
+
* @returns パイプラインを通過した最終的なベクトル (Float32Array または Uint8Array/Int8Array)
|
|
3690
|
+
*/
|
|
3691
|
+
run(vector, context) {
|
|
3692
|
+
let currentVector = vector;
|
|
3693
|
+
for (const step of this.steps) {
|
|
3694
|
+
currentVector = step.adapter.tune(
|
|
3695
|
+
currentVector,
|
|
3696
|
+
context?.intent || "default"
|
|
3697
|
+
);
|
|
3698
|
+
}
|
|
3699
|
+
return currentVector;
|
|
3700
|
+
}
|
|
3701
|
+
/**
|
|
3702
|
+
* 複数のベクトル(バッチ)を一括でパイプラインに通します。
|
|
3703
|
+
* 内部の tuneBatch が実装されているアダプタでは WASM/SIMD による高速処理が適用されます。
|
|
3704
|
+
*
|
|
3705
|
+
* @param vectors 変換元のベースベクトルの配列
|
|
3706
|
+
* @param context インテントやバージョンなどのコンテキスト情報
|
|
3707
|
+
* @returns 変換されたベクトルの配列
|
|
3708
|
+
*/
|
|
3709
|
+
runBatch(vectors, context) {
|
|
3710
|
+
let currentVectors = vectors;
|
|
3711
|
+
for (const step of this.steps) {
|
|
3712
|
+
if (typeof step.adapter.tuneBatch === "function") {
|
|
3713
|
+
currentVectors = step.adapter.tuneBatch(
|
|
3714
|
+
currentVectors,
|
|
3715
|
+
context?.intent || "default"
|
|
3716
|
+
);
|
|
3717
|
+
} else {
|
|
3718
|
+
currentVectors = currentVectors.map(
|
|
3719
|
+
(vec) => step.adapter.tune(vec, context?.intent || "default")
|
|
3720
|
+
);
|
|
3721
|
+
}
|
|
3722
|
+
}
|
|
3723
|
+
return currentVectors;
|
|
3724
|
+
}
|
|
3725
|
+
/**
|
|
3726
|
+
* ベクトル変換から特定データベース向けのフォーマットまでを1回の呼び出しで行います。
|
|
3727
|
+
*
|
|
3728
|
+
* @param vector 変換元のベースベクトル
|
|
3729
|
+
* @param dbOptions フォーマットの指定オプション
|
|
3730
|
+
* @param context パイプラインのコンテキスト
|
|
3731
|
+
* @returns 指定されたデータベース形式のオブジェクトや文字列
|
|
3732
|
+
*/
|
|
3733
|
+
runAndFormat(vector, dbOptions, context) {
|
|
3734
|
+
const tunedVector = this.run(vector, context);
|
|
3735
|
+
const formatFn = _WarpPipeline.formatRegistry.get(dbOptions.format);
|
|
3736
|
+
if (!formatFn) {
|
|
3737
|
+
throw new Error(
|
|
3738
|
+
`Unknown format: ${dbOptions.format}. Did you forget to register it?`
|
|
3739
|
+
);
|
|
3740
|
+
}
|
|
3741
|
+
return formatFn(tunedVector, dbOptions);
|
|
3742
|
+
}
|
|
3743
|
+
/**
|
|
3744
|
+
* パイプライン内の全アダプタの状態(学習済みの重みなど)を JSON 化可能な配列として出力します。
|
|
3745
|
+
* これにより、DBやRedis等への永続化が容易になります。
|
|
3746
|
+
*/
|
|
3747
|
+
exportState() {
|
|
3748
|
+
return this.steps.map((step) => {
|
|
3749
|
+
const state = typeof step.adapter.exportState === "function" ? step.adapter.exportState() : null;
|
|
3750
|
+
return {
|
|
3751
|
+
type: step.type,
|
|
3752
|
+
state
|
|
3753
|
+
};
|
|
3754
|
+
});
|
|
3755
|
+
}
|
|
3756
|
+
/**
|
|
3757
|
+
* エクスポートされた JSON 状態から、パイプラインを完全に復元(再構築)します。
|
|
3758
|
+
* @param states exportState で出力された配列
|
|
3759
|
+
* @returns 復元された新しい WarpPipeline インスタンス
|
|
3760
|
+
*/
|
|
3761
|
+
static importState(states) {
|
|
3762
|
+
if (!states || states.length === 0) {
|
|
3763
|
+
throw new Error("No states provided to import.");
|
|
3764
|
+
}
|
|
3765
|
+
const pipeline = new _WarpPipeline(0);
|
|
3766
|
+
for (const step of states) {
|
|
3767
|
+
const importFn = _WarpPipeline.adapterRegistry.get(step.type);
|
|
3768
|
+
if (!importFn) {
|
|
3769
|
+
throw new Error(
|
|
3770
|
+
`Unknown adapter type: ${step.type}. Did you forget to register it via WarpPipeline.registerAdapter?`
|
|
3771
|
+
);
|
|
3772
|
+
}
|
|
3773
|
+
const adapter = importFn(step.state);
|
|
3774
|
+
pipeline.steps.push({ type: step.type, adapter });
|
|
3775
|
+
}
|
|
3776
|
+
if (pipeline.steps.length > 0) {
|
|
3777
|
+
}
|
|
3778
|
+
return pipeline;
|
|
1279
3779
|
}
|
|
1280
3780
|
};
|
|
3781
|
+
WarpPipeline.registerAdapter(
|
|
3782
|
+
"IntentAdapter",
|
|
3783
|
+
(state) => IntentAdapter.importState(state)
|
|
3784
|
+
);
|
|
3785
|
+
WarpPipeline.registerAdapter(
|
|
3786
|
+
"LoraIntentAdapter",
|
|
3787
|
+
(state) => LoraIntentAdapter.importState(state)
|
|
3788
|
+
);
|
|
3789
|
+
WarpPipeline.registerAdapter(
|
|
3790
|
+
"WhiteningAdapter",
|
|
3791
|
+
(state) => WhiteningAdapter.importState(state)
|
|
3792
|
+
);
|
|
3793
|
+
WarpPipeline.registerAdapter(
|
|
3794
|
+
"ProjectionAdapter",
|
|
3795
|
+
(state) => ProjectionAdapter.importState(state)
|
|
3796
|
+
);
|
|
3797
|
+
WarpPipeline.registerAdapter(
|
|
3798
|
+
"MlpAdapter",
|
|
3799
|
+
(state) => MlpAdapter.importState(state)
|
|
3800
|
+
);
|
|
3801
|
+
WarpPipeline.registerAdapter(
|
|
3802
|
+
"QuantizationAdapter",
|
|
3803
|
+
(state) => QuantizationAdapter.importState(state)
|
|
3804
|
+
);
|
|
3805
|
+
WarpPipeline.registerFormat(
|
|
3806
|
+
"pgvector",
|
|
3807
|
+
(vec, _opts) => VectorDBAdapter.toPgvector(vec)
|
|
3808
|
+
);
|
|
3809
|
+
WarpPipeline.registerFormat(
|
|
3810
|
+
"pinecone",
|
|
3811
|
+
(vec, opts) => VectorDBAdapter.toPineconeQuery(
|
|
3812
|
+
vec,
|
|
3813
|
+
opts.topK,
|
|
3814
|
+
opts.filter
|
|
3815
|
+
)
|
|
3816
|
+
);
|
|
3817
|
+
WarpPipeline.registerFormat(
|
|
3818
|
+
"redis",
|
|
3819
|
+
(vec, _opts) => VectorDBAdapter.toRedis(vec)
|
|
3820
|
+
);
|
|
1281
3821
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1282
3822
|
0 && (module.exports = {
|
|
3823
|
+
ColbertAdapter,
|
|
3824
|
+
InfoNCETrainer,
|
|
1283
3825
|
IntentAdapter,
|
|
1284
3826
|
IntentTrainer,
|
|
1285
3827
|
LoraIntentAdapter,
|
|
1286
3828
|
MigrationTrainer,
|
|
3829
|
+
MlpAdapter,
|
|
1287
3830
|
ProjectionAdapter,
|
|
3831
|
+
QuantizationAdapter,
|
|
3832
|
+
TaskArithmetic,
|
|
3833
|
+
TripletTrainer,
|
|
1288
3834
|
VectorDBAdapter,
|
|
3835
|
+
VsaAdapter,
|
|
3836
|
+
WarpEmbeddings,
|
|
3837
|
+
WarpLlamaIndexEmbeddings,
|
|
3838
|
+
WarpPipeline,
|
|
3839
|
+
WhiteningAdapter,
|
|
3840
|
+
addScaledVector,
|
|
1289
3841
|
applyActivationToVector,
|
|
3842
|
+
applyAffine,
|
|
1290
3843
|
assertDimension,
|
|
1291
3844
|
cosineSimilarity,
|
|
1292
3845
|
flattenMatrix,
|
|
3846
|
+
getFlatMatrixAndBias,
|
|
1293
3847
|
innerProduct,
|
|
3848
|
+
integrations,
|
|
1294
3849
|
normalize,
|
|
1295
3850
|
reject,
|
|
3851
|
+
rrf,
|
|
3852
|
+
rsf,
|
|
1296
3853
|
slerp,
|
|
1297
|
-
softmax
|
|
3854
|
+
softmax,
|
|
3855
|
+
withWarpVector
|
|
1298
3856
|
});
|