mycai 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +23 -0
- package/README.md +119 -0
- package/bin/mycai.js +156 -0
- package/core/ghr_lattice_memory.js +401 -0
- package/core/hdc.js +312 -0
- package/core/memory.js +60 -0
- package/core/memory_engine.js +444 -0
- package/core/morphology.js +357 -0
- package/core/phase.js +87 -0
- package/core/reasoning_router.js +628 -0
- package/core/resonance.js +118 -0
- package/core/safetensors.js +62 -0
- package/core/sovereign_agent.js +164 -0
- package/core/spectral.js +259 -0
- package/core/spectral_decoder.js +868 -0
- package/dist/resonance_sdk.js +2703 -0
- package/dist/resonance_sdk.min.js +14 -0
- package/dist/spectral_core.wasm +0 -0
- package/index.d.ts +45 -0
- package/index.js +26 -0
- package/package.json +52 -0
- package/sdk/README.md +154 -0
- package/sdk/examples/banking_assistant.js +61 -0
- package/sdk/examples/browser_example.html +104 -0
- package/sdk/examples/express_integration.js +61 -0
- package/sdk/examples/node_example.js +33 -0
- package/sdk/examples/quickstart.js +55 -0
- package/sdk/index.js +22 -0
- package/sdk/ingestion.js +237 -0
- package/sdk/licensing.js +168 -0
- package/sdk/resonance_engine.js +594 -0
- package/sdk/resonance_sdk.js +792 -0
- package/sdk/storage.js +185 -0
- package/sdk/tests/sdk_verification.js +98 -0
- package/sdk/tests/test_commercial_sdk.js +136 -0
- package/sdk/types.d.ts +152 -0
|
@@ -0,0 +1,2703 @@
|
|
|
1
|
+
// core/morphology.js
|
|
2
|
+
var TurkishMorphology = class {
|
|
3
|
+
constructor(roots = []) {
|
|
4
|
+
this.onVowels = /* @__PURE__ */ new Set(["e", "i", "\xF6", "\xFC"]);
|
|
5
|
+
this.backVowels = /* @__PURE__ */ new Set(["a", "\u0131", "o", "u"]);
|
|
6
|
+
this.allVowels = /* @__PURE__ */ new Set(["a", "e", "\u0131", "i", "o", "\xF6", "u", "\xFC"]);
|
|
7
|
+
this.customRoots = roots;
|
|
8
|
+
this.suffixFeatures = {
|
|
9
|
+
// Plural
|
|
10
|
+
"ler": { number: "plural" },
|
|
11
|
+
"lar": { number: "plural" },
|
|
12
|
+
// Cases
|
|
13
|
+
"den": { case: "ablative" },
|
|
14
|
+
"dan": { case: "ablative" },
|
|
15
|
+
"ten": { case: "ablative" },
|
|
16
|
+
"tan": { case: "ablative" },
|
|
17
|
+
"de": { case: "locative" },
|
|
18
|
+
"da": { case: "locative" },
|
|
19
|
+
"te": { case: "locative" },
|
|
20
|
+
"ta": { case: "locative" },
|
|
21
|
+
"e": { case: "dative" },
|
|
22
|
+
"a": { case: "dative" },
|
|
23
|
+
"in": { case: "genitive" },
|
|
24
|
+
"\u0131n": { case: "genitive" },
|
|
25
|
+
"un": { case: "genitive" },
|
|
26
|
+
"\xFCn": { case: "genitive" },
|
|
27
|
+
// Possessions
|
|
28
|
+
"im": { possession: "1sg" },
|
|
29
|
+
"\u0131m": { possession: "1sg" },
|
|
30
|
+
"um": { possession: "1sg" },
|
|
31
|
+
"\xFCm": { possession: "1sg" },
|
|
32
|
+
"in": { possession: "2sg" },
|
|
33
|
+
// overlaps with genitive, handled dynamically
|
|
34
|
+
"\u0131n": { possession: "2sg" },
|
|
35
|
+
"un": { possession: "2sg" },
|
|
36
|
+
"\xFCn": { possession: "2sg" },
|
|
37
|
+
"i": { possession: "3sg" },
|
|
38
|
+
"\u0131": { possession: "3sg" },
|
|
39
|
+
"u": { possession: "3sg" },
|
|
40
|
+
"\xFC": { possession: "3sg" },
|
|
41
|
+
"imiz": { possession: "1pl" },
|
|
42
|
+
"\u0131m\u0131z": { possession: "1pl" },
|
|
43
|
+
"umuz": { possession: "1pl" },
|
|
44
|
+
"\xFCm\xFCz": { possession: "1pl" },
|
|
45
|
+
"iniz": { possession: "2pl" },
|
|
46
|
+
"\u0131n\u0131z": { possession: "2pl" },
|
|
47
|
+
"\xFCn\xFCz": { possession: "2pl" },
|
|
48
|
+
"unuz": { possession: "2pl" },
|
|
49
|
+
"leri": { possession: "3pl" },
|
|
50
|
+
"lar\u0131": { possession: "3pl" },
|
|
51
|
+
// Tense/Aspect/Mood
|
|
52
|
+
"iyor": { tense: "present" },
|
|
53
|
+
"\u0131yor": { tense: "present" },
|
|
54
|
+
"uyor": { tense: "present" },
|
|
55
|
+
"\xFCyor": { tense: "present" },
|
|
56
|
+
"ecek": { tense: "future" },
|
|
57
|
+
"acak": { tense: "future" },
|
|
58
|
+
"mi\u015F": { tense: "narrative_past" },
|
|
59
|
+
"m\u0131\u015F": { tense: "narrative_past" },
|
|
60
|
+
"m\xFC\u015F": { tense: "narrative_past" },
|
|
61
|
+
"mu\u015F": { tense: "narrative_past" },
|
|
62
|
+
"di": { tense: "past" },
|
|
63
|
+
"d\u0131": { tense: "past" },
|
|
64
|
+
"du": { tense: "past" },
|
|
65
|
+
"d\xFC": { tense: "past" },
|
|
66
|
+
"ti": { tense: "past" },
|
|
67
|
+
"t\u0131": { tense: "past" },
|
|
68
|
+
"tu": { tense: "past" },
|
|
69
|
+
"t\xFC": { tense: "past" },
|
|
70
|
+
// Infinitives and derivations
|
|
71
|
+
"mek": { aspect: "infinitive" },
|
|
72
|
+
"mak": { aspect: "infinitive" },
|
|
73
|
+
"lik": { derivation: "noun" },
|
|
74
|
+
"l\u0131k": { derivation: "noun" },
|
|
75
|
+
"luk": { derivation: "noun" },
|
|
76
|
+
"l\xFCk": { derivation: "noun" },
|
|
77
|
+
"li": { derivation: "with" },
|
|
78
|
+
"l\u0131": { derivation: "with" },
|
|
79
|
+
"lu": { derivation: "with" },
|
|
80
|
+
"l\xFC": { derivation: "with" },
|
|
81
|
+
"siz": { derivation: "without" },
|
|
82
|
+
"s\u0131z": { derivation: "without" },
|
|
83
|
+
"suz": { derivation: "without" },
|
|
84
|
+
"s\xFCz": { derivation: "without" },
|
|
85
|
+
"ce": { case: "equative" },
|
|
86
|
+
"ca": { case: "equative" },
|
|
87
|
+
"\xE7a": { case: "equative" },
|
|
88
|
+
"\xE7e": { case: "equative" },
|
|
89
|
+
// Copula (Assertive)
|
|
90
|
+
"dir": { copula: "assertive" },
|
|
91
|
+
"d\u0131r": { copula: "assertive" },
|
|
92
|
+
"dur": { copula: "assertive" },
|
|
93
|
+
"d\xFCr": { copula: "assertive" },
|
|
94
|
+
"tir": { copula: "assertive" },
|
|
95
|
+
"t\u0131r": { copula: "assertive" },
|
|
96
|
+
"tur": { copula: "assertive" },
|
|
97
|
+
"t\xFCr": { copula: "assertive" },
|
|
98
|
+
// Relative Modifier
|
|
99
|
+
"ki": { pronoun: "relative" },
|
|
100
|
+
"kiler": { pronoun: "relative_plural" },
|
|
101
|
+
// Adverbial / Manner
|
|
102
|
+
"cesine": { aspect: "manner" },
|
|
103
|
+
"cas\u0131na": { aspect: "manner" },
|
|
104
|
+
"ken": { adverb: "temporal" },
|
|
105
|
+
// Moods
|
|
106
|
+
"meli": { mood: "necessity" },
|
|
107
|
+
"mal\u0131": { mood: "necessity" },
|
|
108
|
+
"se": { mood: "conditional" },
|
|
109
|
+
"sa": { mood: "conditional" }
|
|
110
|
+
};
|
|
111
|
+
this.suffixesKnown = Object.keys(this.suffixFeatures).sort((a, b) => b.length - a.length);
|
|
112
|
+
}
|
|
113
|
+
// Allow dynamic roots fallback
|
|
114
|
+
get roots() {
|
|
115
|
+
if (this.customRoots && this.customRoots.length > 0) {
|
|
116
|
+
return this.customRoots;
|
|
117
|
+
}
|
|
118
|
+
if (typeof globalThis !== "undefined" && globalThis.TR_CORPUS_ROOTS) {
|
|
119
|
+
return globalThis.TR_CORPUS_ROOTS;
|
|
120
|
+
}
|
|
121
|
+
return [
|
|
122
|
+
// Genel yaygın kökler
|
|
123
|
+
"ev",
|
|
124
|
+
"g\xF6l",
|
|
125
|
+
"araba",
|
|
126
|
+
"kitap",
|
|
127
|
+
"el",
|
|
128
|
+
"ba\u015F",
|
|
129
|
+
"git",
|
|
130
|
+
"gel",
|
|
131
|
+
"yap",
|
|
132
|
+
"al",
|
|
133
|
+
"ver",
|
|
134
|
+
"g\xF6r",
|
|
135
|
+
"bilgisayar",
|
|
136
|
+
"bil",
|
|
137
|
+
"\xF6\u011Fren",
|
|
138
|
+
"anla",
|
|
139
|
+
"d\xFC\u015F\xFCn",
|
|
140
|
+
"b\xFCy\xFCk",
|
|
141
|
+
"k\xFC\xE7\xFCk",
|
|
142
|
+
"g\xFCzel",
|
|
143
|
+
"iyi",
|
|
144
|
+
"k\xF6t\xFC",
|
|
145
|
+
"yapay",
|
|
146
|
+
"zeka",
|
|
147
|
+
"beyin",
|
|
148
|
+
"sinir",
|
|
149
|
+
"dil",
|
|
150
|
+
"kelime",
|
|
151
|
+
"c\xFCmle",
|
|
152
|
+
"t\xFCrk\xE7e",
|
|
153
|
+
"bilim",
|
|
154
|
+
"teknik",
|
|
155
|
+
"okul",
|
|
156
|
+
"\xF6\u011Frenci",
|
|
157
|
+
"\xF6\u011Fretmen",
|
|
158
|
+
"yaz\u0131l\u0131m",
|
|
159
|
+
"donan\u0131m",
|
|
160
|
+
"renk",
|
|
161
|
+
// Vücut / anatomi
|
|
162
|
+
"ayak",
|
|
163
|
+
"g\xF6z",
|
|
164
|
+
"kulak",
|
|
165
|
+
"diz",
|
|
166
|
+
"omuz",
|
|
167
|
+
"kar\u0131n",
|
|
168
|
+
"g\xF6\u011F\xFCs",
|
|
169
|
+
"s\u0131rt",
|
|
170
|
+
"boyun",
|
|
171
|
+
"kol",
|
|
172
|
+
"bacak",
|
|
173
|
+
"parmak",
|
|
174
|
+
"bilek",
|
|
175
|
+
"topuk",
|
|
176
|
+
"al\u0131n",
|
|
177
|
+
"bel",
|
|
178
|
+
"di\u015F",
|
|
179
|
+
"burun",
|
|
180
|
+
"a\u011F\u0131z",
|
|
181
|
+
"ci\u011Fer",
|
|
182
|
+
"kalp",
|
|
183
|
+
"akci\u011Fer",
|
|
184
|
+
"mide",
|
|
185
|
+
"b\xF6brek",
|
|
186
|
+
"karaci\u011Fer",
|
|
187
|
+
"damar",
|
|
188
|
+
// Tıbbi terimler
|
|
189
|
+
"hasta",
|
|
190
|
+
"doktor",
|
|
191
|
+
"hem\u015Fire",
|
|
192
|
+
"ila\xE7",
|
|
193
|
+
"doz",
|
|
194
|
+
"tan\u0131",
|
|
195
|
+
"tedavi",
|
|
196
|
+
"ameliyat",
|
|
197
|
+
"hastal\u0131k",
|
|
198
|
+
"a\u011Fr\u0131",
|
|
199
|
+
"\u015Fi\u015Flik",
|
|
200
|
+
"ate\u015F",
|
|
201
|
+
"nab\u0131z",
|
|
202
|
+
"tansiyon",
|
|
203
|
+
"kan",
|
|
204
|
+
"idrar",
|
|
205
|
+
"re\xE7ete",
|
|
206
|
+
"a\u015F\u0131",
|
|
207
|
+
"vir\xFCs",
|
|
208
|
+
"enfeksiyon",
|
|
209
|
+
"yara",
|
|
210
|
+
"k\u0131r\u0131k",
|
|
211
|
+
"\xF6dem",
|
|
212
|
+
"alerji",
|
|
213
|
+
"\u015Feker",
|
|
214
|
+
"diyabet",
|
|
215
|
+
"gebelik",
|
|
216
|
+
"do\u011Fum",
|
|
217
|
+
"\xF6l\xE7\xFCm",
|
|
218
|
+
"muayene",
|
|
219
|
+
"rapor",
|
|
220
|
+
"tahlil",
|
|
221
|
+
// Genel isimler
|
|
222
|
+
"yol",
|
|
223
|
+
"su",
|
|
224
|
+
"ekmek",
|
|
225
|
+
"para",
|
|
226
|
+
"i\u015F",
|
|
227
|
+
"g\xFCn",
|
|
228
|
+
"y\u0131l",
|
|
229
|
+
"saat",
|
|
230
|
+
"hafta",
|
|
231
|
+
"ay",
|
|
232
|
+
"yer",
|
|
233
|
+
"\u015Fehir",
|
|
234
|
+
"\xFClke",
|
|
235
|
+
"k\xF6y",
|
|
236
|
+
"insan",
|
|
237
|
+
"kad\u0131n",
|
|
238
|
+
"erkek",
|
|
239
|
+
"\xE7ocuk",
|
|
240
|
+
"anne",
|
|
241
|
+
"baba",
|
|
242
|
+
"ad",
|
|
243
|
+
"isim",
|
|
244
|
+
"aile",
|
|
245
|
+
"soru",
|
|
246
|
+
"cevap",
|
|
247
|
+
"kay\u0131t",
|
|
248
|
+
"bilgi",
|
|
249
|
+
"durum",
|
|
250
|
+
"sonu\xE7",
|
|
251
|
+
// Sıfatlar ve zarflar
|
|
252
|
+
"yeni",
|
|
253
|
+
"eski",
|
|
254
|
+
"uzun",
|
|
255
|
+
"k\u0131sa",
|
|
256
|
+
"s\u0131k",
|
|
257
|
+
"az",
|
|
258
|
+
"\xE7ok",
|
|
259
|
+
"son",
|
|
260
|
+
"ilk",
|
|
261
|
+
"her",
|
|
262
|
+
// Fiiller (ek kökler)
|
|
263
|
+
"oku",
|
|
264
|
+
"yaz",
|
|
265
|
+
"bak",
|
|
266
|
+
"\xE7al\u0131\u015F",
|
|
267
|
+
"ye",
|
|
268
|
+
"i\xE7",
|
|
269
|
+
"uyu",
|
|
270
|
+
"kalk",
|
|
271
|
+
"otur",
|
|
272
|
+
"ko\u015F",
|
|
273
|
+
"sor",
|
|
274
|
+
"s\xF6yle",
|
|
275
|
+
"dinle",
|
|
276
|
+
"bekle",
|
|
277
|
+
"ba\u015Fla",
|
|
278
|
+
"bitir",
|
|
279
|
+
"a\xE7",
|
|
280
|
+
"kapat",
|
|
281
|
+
"getir",
|
|
282
|
+
"g\xF6t\xFCr",
|
|
283
|
+
"koy",
|
|
284
|
+
"\xE7\u0131kar",
|
|
285
|
+
"kaydet",
|
|
286
|
+
"g\xFCncelle",
|
|
287
|
+
"kontrol"
|
|
288
|
+
];
|
|
289
|
+
}
|
|
290
|
+
determineVowelHarmony(root) {
|
|
291
|
+
const lv = this.getLastVowel(root);
|
|
292
|
+
return lv && this.onVowels.has(lv) ? "front" : "back";
|
|
293
|
+
}
|
|
294
|
+
getLastVowel(word) {
|
|
295
|
+
for (let i = word.length - 1; i >= 0; i--) {
|
|
296
|
+
if (this.allVowels.has(word[i])) return word[i];
|
|
297
|
+
}
|
|
298
|
+
return null;
|
|
299
|
+
}
|
|
300
|
+
normalize(text) {
|
|
301
|
+
return text.toLowerCase().trim().replace(/i̇/g, "i").replace(/[^a-zçgğıoöşuüâîû\s]/g, "");
|
|
302
|
+
}
|
|
303
|
+
analyze(word) {
|
|
304
|
+
const w = this.normalize(word).split(/\s+/)[0];
|
|
305
|
+
const result = {
|
|
306
|
+
word: w,
|
|
307
|
+
root: w,
|
|
308
|
+
suffixes: [],
|
|
309
|
+
harmony: this.determineVowelHarmony(w),
|
|
310
|
+
morphemes: [],
|
|
311
|
+
features: {},
|
|
312
|
+
vowelCount: 0,
|
|
313
|
+
syllables: []
|
|
314
|
+
};
|
|
315
|
+
if (!w) return result;
|
|
316
|
+
result.vowelCount = [...w].filter((c) => this.allVowels.has(c)).length;
|
|
317
|
+
result.syllables = this.syllabify(w);
|
|
318
|
+
let foundRoot = w;
|
|
319
|
+
let foundSuffs = [];
|
|
320
|
+
for (const root of this.roots) {
|
|
321
|
+
let isMatch = false;
|
|
322
|
+
let matchedLength = root.length;
|
|
323
|
+
if (w.startsWith(root)) {
|
|
324
|
+
isMatch = true;
|
|
325
|
+
} else {
|
|
326
|
+
const last = root[root.length - 1];
|
|
327
|
+
if (["p", "\xE7", "t", "k"].includes(last)) {
|
|
328
|
+
const stem = root.slice(0, -1);
|
|
329
|
+
let mutatedStem = "";
|
|
330
|
+
if (last === "p") mutatedStem = stem + "b";
|
|
331
|
+
else if (last === "\xE7") mutatedStem = stem + "c";
|
|
332
|
+
else if (last === "t") mutatedStem = stem + "d";
|
|
333
|
+
else if (last === "k") mutatedStem = stem + "\u011F";
|
|
334
|
+
if (root === "renk") mutatedStem = stem + "g";
|
|
335
|
+
if (w.startsWith(mutatedStem) && w.length > root.length) {
|
|
336
|
+
const nextChar = w[mutatedStem.length];
|
|
337
|
+
if (this.allVowels.has(nextChar)) {
|
|
338
|
+
isMatch = true;
|
|
339
|
+
matchedLength = mutatedStem.length;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
if (isMatch && root.length >= 2 && root.length < w.length) {
|
|
345
|
+
const suffix = w.slice(matchedLength);
|
|
346
|
+
if (root.length > (foundRoot === w ? 0 : foundRoot.length)) {
|
|
347
|
+
foundRoot = root;
|
|
348
|
+
foundSuffs = this.splitSuffix(suffix);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
result.root = foundRoot;
|
|
353
|
+
result.suffixes = foundSuffs;
|
|
354
|
+
result.morphemes = [foundRoot, ...foundSuffs].filter(Boolean);
|
|
355
|
+
result.harmony = this.determineVowelHarmony(foundRoot);
|
|
356
|
+
foundSuffs.forEach((suff) => {
|
|
357
|
+
const feat = this.suffixFeatures[suff];
|
|
358
|
+
if (feat) {
|
|
359
|
+
Object.assign(result.features, feat);
|
|
360
|
+
}
|
|
361
|
+
});
|
|
362
|
+
return result;
|
|
363
|
+
}
|
|
364
|
+
splitSuffix(suffix) {
|
|
365
|
+
if (!suffix) return [];
|
|
366
|
+
const result = [];
|
|
367
|
+
let rem = suffix;
|
|
368
|
+
while (rem.length > 0) {
|
|
369
|
+
let matched = false;
|
|
370
|
+
for (const s of this.suffixesKnown) {
|
|
371
|
+
if (rem.endsWith(s)) {
|
|
372
|
+
result.unshift(s);
|
|
373
|
+
rem = rem.slice(0, rem.length - s.length);
|
|
374
|
+
matched = true;
|
|
375
|
+
break;
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
if (!matched) {
|
|
379
|
+
result.unshift(rem);
|
|
380
|
+
break;
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
return result;
|
|
384
|
+
}
|
|
385
|
+
syllabify(word) {
|
|
386
|
+
const w = this.normalize(word);
|
|
387
|
+
if (!w) return [];
|
|
388
|
+
const vowelIndices = [];
|
|
389
|
+
for (let i = 0; i < w.length; i++) {
|
|
390
|
+
if (this.allVowels.has(w[i])) {
|
|
391
|
+
vowelIndices.push(i);
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
if (vowelIndices.length <= 1) {
|
|
395
|
+
return [w];
|
|
396
|
+
}
|
|
397
|
+
const syllables = [];
|
|
398
|
+
let start = 0;
|
|
399
|
+
for (let k = 0; k < vowelIndices.length - 1; k++) {
|
|
400
|
+
const v1 = vowelIndices[k];
|
|
401
|
+
const v2 = vowelIndices[k + 1];
|
|
402
|
+
const consonantCount = v2 - v1 - 1;
|
|
403
|
+
let splitPoint;
|
|
404
|
+
if (consonantCount === 0) {
|
|
405
|
+
splitPoint = v1 + 1;
|
|
406
|
+
} else if (consonantCount === 1) {
|
|
407
|
+
splitPoint = v1 + 1;
|
|
408
|
+
} else if (consonantCount === 2) {
|
|
409
|
+
splitPoint = v1 + 2;
|
|
410
|
+
} else {
|
|
411
|
+
splitPoint = v2 - 1;
|
|
412
|
+
}
|
|
413
|
+
syllables.push(w.slice(start, splitPoint));
|
|
414
|
+
start = splitPoint;
|
|
415
|
+
}
|
|
416
|
+
syllables.push(w.slice(start));
|
|
417
|
+
return syllables.filter(Boolean);
|
|
418
|
+
}
|
|
419
|
+
syllabifyPhrase(phrase) {
|
|
420
|
+
const words = phrase.toLowerCase().trim().split(/\s+/).filter(Boolean);
|
|
421
|
+
if (words.length === 0) return [];
|
|
422
|
+
if (words.length === 1) return this.syllabify(words[0]);
|
|
423
|
+
const resultSyllables = [];
|
|
424
|
+
const processedWords = [...words];
|
|
425
|
+
for (let i = 0; i < processedWords.length - 1; i++) {
|
|
426
|
+
const w1 = processedWords[i];
|
|
427
|
+
const w2 = processedWords[i + 1];
|
|
428
|
+
if (w1.length === 0 || w2.length === 0) continue;
|
|
429
|
+
const lastChar = w1[w1.length - 1];
|
|
430
|
+
const firstChar = w2[0];
|
|
431
|
+
if (!this.allVowels.has(lastChar) && this.allVowels.has(firstChar)) {
|
|
432
|
+
processedWords[i] = w1.slice(0, -1);
|
|
433
|
+
processedWords[i + 1] = lastChar + w2;
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
for (const w of processedWords) {
|
|
437
|
+
if (w.length > 0) {
|
|
438
|
+
resultSyllables.push(...this.syllabify(w));
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
return resultSyllables;
|
|
442
|
+
}
|
|
443
|
+
};
|
|
444
|
+
|
|
445
|
+
// core/hdc.js
|
|
446
|
+
var Representation = class {
|
|
447
|
+
constructor(type, values, D) {
|
|
448
|
+
this.type = type;
|
|
449
|
+
this.values = values;
|
|
450
|
+
this.D = D;
|
|
451
|
+
}
|
|
452
|
+
// Calculate memory footprint in bytes
|
|
453
|
+
memorySize() {
|
|
454
|
+
return this.values.byteLength;
|
|
455
|
+
}
|
|
456
|
+
};
|
|
457
|
+
var HDCEngine = class {
|
|
458
|
+
constructor(D = 8192) {
|
|
459
|
+
this.D = D;
|
|
460
|
+
}
|
|
461
|
+
// ── GENERATION / RANDOM RANDOM VECTORS ─────────────────────
|
|
462
|
+
generateRandom(type) {
|
|
463
|
+
if (type === "binary") {
|
|
464
|
+
const vals2 = new Uint8Array(this.D);
|
|
465
|
+
for (let i = 0; i < this.D; i++) {
|
|
466
|
+
vals2[i] = Math.random() < 0.5 ? 0 : 1;
|
|
467
|
+
}
|
|
468
|
+
return new Representation("binary", vals2, this.D);
|
|
469
|
+
}
|
|
470
|
+
if (type === "bipolar") {
|
|
471
|
+
const vals2 = new Float32Array(this.D);
|
|
472
|
+
for (let i = 0; i < this.D; i++) {
|
|
473
|
+
vals2[i] = Math.random() < 0.5 ? -1 : 1;
|
|
474
|
+
}
|
|
475
|
+
return new Representation("bipolar", vals2, this.D);
|
|
476
|
+
}
|
|
477
|
+
if (type === "real") {
|
|
478
|
+
const vals2 = new Float32Array(this.D);
|
|
479
|
+
for (let i = 0; i < this.D; i++) {
|
|
480
|
+
let u = 0, v = 0;
|
|
481
|
+
while (u === 0) u = Math.random();
|
|
482
|
+
while (v === 0) v = Math.random();
|
|
483
|
+
vals2[i] = Math.sqrt(-2 * Math.log(u)) * Math.cos(2 * Math.PI * v);
|
|
484
|
+
}
|
|
485
|
+
return new Representation("real", vals2, this.D);
|
|
486
|
+
}
|
|
487
|
+
const vals = new Float32Array(this.D);
|
|
488
|
+
for (let i = 0; i < this.D; i++) {
|
|
489
|
+
vals[i] = Math.random() * 2 * Math.PI;
|
|
490
|
+
}
|
|
491
|
+
return new Representation("complex", vals, this.D);
|
|
492
|
+
}
|
|
493
|
+
generateSeeded(type, key) {
|
|
494
|
+
let seed = 0;
|
|
495
|
+
for (let i = 0; i < key.length; i++) {
|
|
496
|
+
seed = seed * 31 + key.charCodeAt(i) >>> 0;
|
|
497
|
+
}
|
|
498
|
+
const nextRand = () => {
|
|
499
|
+
seed = seed * 1664525 + 1013904223 >>> 0;
|
|
500
|
+
return (seed >>> 8) / 16777216;
|
|
501
|
+
};
|
|
502
|
+
if (type === "binary") {
|
|
503
|
+
const vals2 = new Uint8Array(this.D);
|
|
504
|
+
for (let i = 0; i < this.D; i++) {
|
|
505
|
+
vals2[i] = nextRand() < 0.5 ? 0 : 1;
|
|
506
|
+
}
|
|
507
|
+
return new Representation("binary", vals2, this.D);
|
|
508
|
+
}
|
|
509
|
+
if (type === "bipolar") {
|
|
510
|
+
const vals2 = new Float32Array(this.D);
|
|
511
|
+
for (let i = 0; i < this.D; i++) {
|
|
512
|
+
vals2[i] = nextRand() < 0.5 ? -1 : 1;
|
|
513
|
+
}
|
|
514
|
+
return new Representation("bipolar", vals2, this.D);
|
|
515
|
+
}
|
|
516
|
+
if (type === "real") {
|
|
517
|
+
const vals2 = new Float32Array(this.D);
|
|
518
|
+
for (let i = 0; i < this.D; i++) {
|
|
519
|
+
let u = 0, v = 0;
|
|
520
|
+
while (u === 0) u = nextRand();
|
|
521
|
+
while (v === 0) v = nextRand();
|
|
522
|
+
vals2[i] = Math.sqrt(-2 * Math.log(u)) * Math.cos(2 * Math.PI * v);
|
|
523
|
+
}
|
|
524
|
+
return new Representation("real", vals2, this.D);
|
|
525
|
+
}
|
|
526
|
+
const vals = new Float32Array(this.D);
|
|
527
|
+
for (let i = 0; i < this.D; i++) {
|
|
528
|
+
vals[i] = nextRand() * 2 * Math.PI;
|
|
529
|
+
}
|
|
530
|
+
return new Representation("complex", vals, this.D);
|
|
531
|
+
}
|
|
532
|
+
// ── BINDING (Morfem Binding / Variable-Value Association) ──
|
|
533
|
+
bind(a, b) {
|
|
534
|
+
if (a.type !== b.type || a.D !== b.D) {
|
|
535
|
+
throw new Error("Representation mismatch for bind operation.");
|
|
536
|
+
}
|
|
537
|
+
const D = a.D;
|
|
538
|
+
if (a.type === "binary") {
|
|
539
|
+
const o2 = new Uint8Array(D);
|
|
540
|
+
for (let i = 0; i < D; i++) {
|
|
541
|
+
o2[i] = a.values[i] ^ b.values[i];
|
|
542
|
+
}
|
|
543
|
+
return new Representation("binary", o2, D);
|
|
544
|
+
}
|
|
545
|
+
if (a.type === "bipolar") {
|
|
546
|
+
const o2 = new Float32Array(D);
|
|
547
|
+
for (let i = 0; i < D; i++) {
|
|
548
|
+
o2[i] = a.values[i] * b.values[i];
|
|
549
|
+
}
|
|
550
|
+
return new Representation("bipolar", o2, D);
|
|
551
|
+
}
|
|
552
|
+
if (a.type === "real") {
|
|
553
|
+
const o2 = new Float32Array(D);
|
|
554
|
+
for (let i = 0; i < D; i++) {
|
|
555
|
+
o2[i] = a.values[i] * b.values[i];
|
|
556
|
+
}
|
|
557
|
+
return new Representation("real", o2, D);
|
|
558
|
+
}
|
|
559
|
+
const o = new Float32Array(D);
|
|
560
|
+
for (let i = 0; i < D; i++) {
|
|
561
|
+
o[i] = (a.values[i] + b.values[i]) % (2 * Math.PI);
|
|
562
|
+
}
|
|
563
|
+
return new Representation("complex", o, D);
|
|
564
|
+
}
|
|
565
|
+
unbind(a, b) {
|
|
566
|
+
if (a.type !== b.type || a.D !== b.D) {
|
|
567
|
+
throw new Error("Representation mismatch for unbind operation.");
|
|
568
|
+
}
|
|
569
|
+
const D = a.D;
|
|
570
|
+
if (a.type === "binary") {
|
|
571
|
+
return this.bind(a, b);
|
|
572
|
+
}
|
|
573
|
+
if (a.type === "bipolar") {
|
|
574
|
+
return this.bind(a, b);
|
|
575
|
+
}
|
|
576
|
+
if (a.type === "real") {
|
|
577
|
+
const o2 = new Float32Array(D);
|
|
578
|
+
for (let i = 0; i < D; i++) {
|
|
579
|
+
o2[i] = Math.abs(b.values[i]) > 1e-6 ? a.values[i] / b.values[i] : a.values[i];
|
|
580
|
+
}
|
|
581
|
+
return new Representation("real", o2, D);
|
|
582
|
+
}
|
|
583
|
+
const o = new Float32Array(D);
|
|
584
|
+
for (let i = 0; i < D; i++) {
|
|
585
|
+
let v = a.values[i] - b.values[i];
|
|
586
|
+
if (v < 0) v += 2 * Math.PI;
|
|
587
|
+
o[i] = v % (2 * Math.PI);
|
|
588
|
+
}
|
|
589
|
+
return new Representation("complex", o, D);
|
|
590
|
+
}
|
|
591
|
+
// ── BUNDLING (Superposition / Memory Accumulation) ──────────
|
|
592
|
+
bundle(reps) {
|
|
593
|
+
if (!reps || reps.length === 0) {
|
|
594
|
+
throw new Error("No representations to bundle.");
|
|
595
|
+
}
|
|
596
|
+
const type = reps[0].type;
|
|
597
|
+
const D = reps[0].D;
|
|
598
|
+
if (type === "binary") {
|
|
599
|
+
const o2 = new Uint8Array(D);
|
|
600
|
+
const counts = new Int32Array(D);
|
|
601
|
+
for (const r of reps) {
|
|
602
|
+
for (let i = 0; i < D; i++) {
|
|
603
|
+
counts[i] += r.values[i] === 1 ? 1 : -1;
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
for (let i = 0; i < D; i++) {
|
|
607
|
+
o2[i] = counts[i] >= 0 ? 1 : 0;
|
|
608
|
+
}
|
|
609
|
+
return new Representation("binary", o2, D);
|
|
610
|
+
}
|
|
611
|
+
if (type === "bipolar") {
|
|
612
|
+
const o2 = new Float32Array(D);
|
|
613
|
+
for (const r of reps) {
|
|
614
|
+
for (let i = 0; i < D; i++) {
|
|
615
|
+
o2[i] += r.values[i];
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
for (let i = 0; i < D; i++) {
|
|
619
|
+
o2[i] = o2[i] >= 0 ? 1 : -1;
|
|
620
|
+
}
|
|
621
|
+
return new Representation("bipolar", o2, D);
|
|
622
|
+
}
|
|
623
|
+
if (type === "real") {
|
|
624
|
+
const o2 = new Float32Array(D);
|
|
625
|
+
for (const r of reps) {
|
|
626
|
+
for (let i = 0; i < D; i++) {
|
|
627
|
+
o2[i] += r.values[i];
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
const n = reps.length;
|
|
631
|
+
for (let i = 0; i < D; i++) {
|
|
632
|
+
o2[i] /= n;
|
|
633
|
+
}
|
|
634
|
+
return new Representation("real", o2, D);
|
|
635
|
+
}
|
|
636
|
+
const re = new Float32Array(D);
|
|
637
|
+
const im = new Float32Array(D);
|
|
638
|
+
for (const r of reps) {
|
|
639
|
+
for (let i = 0; i < D; i++) {
|
|
640
|
+
re[i] += Math.cos(r.values[i]);
|
|
641
|
+
im[i] += Math.sin(r.values[i]);
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
const o = new Float32Array(D);
|
|
645
|
+
for (let i = 0; i < D; i++) {
|
|
646
|
+
let v = Math.atan2(im[i], re[i]);
|
|
647
|
+
if (v < 0) v += 2 * Math.PI;
|
|
648
|
+
o[i] = v;
|
|
649
|
+
}
|
|
650
|
+
return new Representation("complex", o, D);
|
|
651
|
+
}
|
|
652
|
+
// ── PERMUTATION (Shift operation / Order / Position binding) ─
|
|
653
|
+
permute(a, sh) {
|
|
654
|
+
const D = a.D;
|
|
655
|
+
const shift = (sh % D + D) % D;
|
|
656
|
+
const vals = new a.values.constructor(D);
|
|
657
|
+
for (let i = 0; i < D; i++) {
|
|
658
|
+
vals[(i + shift) % D] = a.values[i];
|
|
659
|
+
}
|
|
660
|
+
return new Representation(a.type, vals, D);
|
|
661
|
+
}
|
|
662
|
+
// ── SIMILARITY (Measured closeness) ──────────────────────────
|
|
663
|
+
similarity(a, b) {
|
|
664
|
+
if (a.type !== b.type || a.D !== b.D) {
|
|
665
|
+
return 0;
|
|
666
|
+
}
|
|
667
|
+
const D = a.D;
|
|
668
|
+
if (a.type === "binary") {
|
|
669
|
+
let hamming = 0;
|
|
670
|
+
for (let i = 0; i < D; i++) {
|
|
671
|
+
if (a.values[i] !== b.values[i]) hamming++;
|
|
672
|
+
}
|
|
673
|
+
return 1 - hamming / D;
|
|
674
|
+
}
|
|
675
|
+
if (a.type === "bipolar") {
|
|
676
|
+
let dot = 0;
|
|
677
|
+
for (let i = 0; i < D; i++) {
|
|
678
|
+
dot += a.values[i] * b.values[i];
|
|
679
|
+
}
|
|
680
|
+
return dot / D;
|
|
681
|
+
}
|
|
682
|
+
if (a.type === "real") {
|
|
683
|
+
let dot = 0, normA = 0, normB = 0;
|
|
684
|
+
for (let i = 0; i < D; i++) {
|
|
685
|
+
dot += a.values[i] * b.values[i];
|
|
686
|
+
normA += a.values[i] * a.values[i];
|
|
687
|
+
normB += b.values[i] * b.values[i];
|
|
688
|
+
}
|
|
689
|
+
const denom = Math.sqrt(normA) * Math.sqrt(normB);
|
|
690
|
+
return denom > 0 ? dot / denom : 0;
|
|
691
|
+
}
|
|
692
|
+
let sum = 0;
|
|
693
|
+
for (let i = 0; i < D; i++) {
|
|
694
|
+
sum += Math.cos(a.values[i] - b.values[i]);
|
|
695
|
+
}
|
|
696
|
+
return sum / D;
|
|
697
|
+
}
|
|
698
|
+
};
|
|
699
|
+
|
|
700
|
+
// core/memory_engine.js
|
|
701
|
+
import fs from "fs";
|
|
702
|
+
|
|
703
|
+
// core/spectral.js
|
|
704
|
+
var SpectralEngine = class {
|
|
705
|
+
constructor() {
|
|
706
|
+
}
|
|
707
|
+
// ── FFT CORE ALGORITHMS ────────────────────────────────────
|
|
708
|
+
_bitReverse(re, im) {
|
|
709
|
+
const n = re.length;
|
|
710
|
+
let j = 0;
|
|
711
|
+
for (let i = 0; i < n; i++) {
|
|
712
|
+
if (i < j) {
|
|
713
|
+
let temp = re[i];
|
|
714
|
+
re[i] = re[j];
|
|
715
|
+
re[j] = temp;
|
|
716
|
+
temp = im[i];
|
|
717
|
+
im[i] = im[j];
|
|
718
|
+
im[j] = temp;
|
|
719
|
+
}
|
|
720
|
+
let m = n >> 1;
|
|
721
|
+
while (m >= 2 && j >= m) {
|
|
722
|
+
j -= m;
|
|
723
|
+
m >>= 1;
|
|
724
|
+
}
|
|
725
|
+
j += m;
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
_fftCore(re, im, inverse = false) {
|
|
729
|
+
const n = re.length;
|
|
730
|
+
this._bitReverse(re, im);
|
|
731
|
+
for (let len = 2; len <= n; len <<= 1) {
|
|
732
|
+
const angle = 2 * Math.PI / len * (inverse ? 1 : -1);
|
|
733
|
+
const wlen_re = Math.cos(angle);
|
|
734
|
+
const wlen_im = Math.sin(angle);
|
|
735
|
+
for (let i = 0; i < n; i += len) {
|
|
736
|
+
let w_re = 1;
|
|
737
|
+
let w_im = 0;
|
|
738
|
+
const half = len >> 1;
|
|
739
|
+
for (let j = 0; j < half; j++) {
|
|
740
|
+
const u_re = re[i + j];
|
|
741
|
+
const u_im = im[i + j];
|
|
742
|
+
const t_re = re[i + j + half];
|
|
743
|
+
const t_im = im[i + j + half];
|
|
744
|
+
const v_re = t_re * w_re - t_im * w_im;
|
|
745
|
+
const v_im = t_re * w_im + t_im * w_re;
|
|
746
|
+
re[i + j] = u_re + v_re;
|
|
747
|
+
im[i + j] = u_im + v_im;
|
|
748
|
+
re[i + j + half] = u_re - v_re;
|
|
749
|
+
im[i + j + half] = u_im - v_im;
|
|
750
|
+
const next_w_re = w_re * wlen_re - w_im * wlen_im;
|
|
751
|
+
const next_w_im = w_re * wlen_im + w_im * wlen_re;
|
|
752
|
+
w_re = next_w_re;
|
|
753
|
+
w_im = next_w_im;
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
if (inverse) {
|
|
758
|
+
for (let i = 0; i < n; i++) {
|
|
759
|
+
re[i] /= n;
|
|
760
|
+
im[i] /= n;
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
// ── EXTERNAL API ───────────────────────────────────────────
|
|
765
|
+
spectralTransform(representation) {
|
|
766
|
+
const D = representation.D;
|
|
767
|
+
const re = new Float32Array(D);
|
|
768
|
+
const im = new Float32Array(D);
|
|
769
|
+
if (representation.type === "complex") {
|
|
770
|
+
for (let i = 0; i < D; i++) {
|
|
771
|
+
re[i] = Math.cos(representation.values[i]);
|
|
772
|
+
im[i] = Math.sin(representation.values[i]);
|
|
773
|
+
}
|
|
774
|
+
} else if (representation.type === "bipolar" || representation.type === "real") {
|
|
775
|
+
for (let i = 0; i < D; i++) {
|
|
776
|
+
re[i] = representation.values[i];
|
|
777
|
+
im[i] = 0;
|
|
778
|
+
}
|
|
779
|
+
} else if (representation.type === "binary") {
|
|
780
|
+
for (let i = 0; i < D; i++) {
|
|
781
|
+
re[i] = representation.values[i] === 1 ? 1 : -1;
|
|
782
|
+
im[i] = 0;
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
this._fftCore(re, im, false);
|
|
786
|
+
const magnitude = new Float32Array(D);
|
|
787
|
+
const phase = new Float32Array(D);
|
|
788
|
+
for (let i = 0; i < D; i++) {
|
|
789
|
+
magnitude[i] = Math.sqrt(re[i] * re[i] + im[i] * im[i]);
|
|
790
|
+
phase[i] = Math.atan2(im[i], re[i]);
|
|
791
|
+
}
|
|
792
|
+
return {
|
|
793
|
+
type: representation.type,
|
|
794
|
+
D,
|
|
795
|
+
re,
|
|
796
|
+
im,
|
|
797
|
+
magnitude,
|
|
798
|
+
phase
|
|
799
|
+
};
|
|
800
|
+
}
|
|
801
|
+
inverseSpectralTransform(spectrum) {
|
|
802
|
+
const D = spectrum.D;
|
|
803
|
+
const re = new Float32Array(spectrum.re);
|
|
804
|
+
const im = new Float32Array(spectrum.im);
|
|
805
|
+
this._fftCore(re, im, true);
|
|
806
|
+
if (spectrum.type === "complex") {
|
|
807
|
+
const vals2 = new Float32Array(D);
|
|
808
|
+
for (let i = 0; i < D; i++) {
|
|
809
|
+
let v = Math.atan2(im[i], re[i]);
|
|
810
|
+
if (v < 0) v += 2 * Math.PI;
|
|
811
|
+
vals2[i] = v;
|
|
812
|
+
}
|
|
813
|
+
return new Representation("complex", vals2, D);
|
|
814
|
+
}
|
|
815
|
+
if (spectrum.type === "binary") {
|
|
816
|
+
const vals2 = new Uint8Array(D);
|
|
817
|
+
for (let i = 0; i < D; i++) {
|
|
818
|
+
vals2[i] = re[i] >= 0 ? 1 : 0;
|
|
819
|
+
}
|
|
820
|
+
return new Representation("binary", vals2, D);
|
|
821
|
+
}
|
|
822
|
+
if (spectrum.type === "bipolar") {
|
|
823
|
+
const vals2 = new Float32Array(D);
|
|
824
|
+
for (let i = 0; i < D; i++) {
|
|
825
|
+
vals2[i] = re[i] >= 0 ? 1 : -1;
|
|
826
|
+
}
|
|
827
|
+
return new Representation("bipolar", vals2, D);
|
|
828
|
+
}
|
|
829
|
+
const vals = new Float32Array(D);
|
|
830
|
+
for (let i = 0; i < D; i++) {
|
|
831
|
+
vals[i] = re[i];
|
|
832
|
+
}
|
|
833
|
+
return new Representation("real", vals, D);
|
|
834
|
+
}
|
|
835
|
+
extractDominantFrequencies(spectrum, k = 10) {
|
|
836
|
+
const n = spectrum.D;
|
|
837
|
+
const items = [];
|
|
838
|
+
for (let i = 0; i < n; i++) {
|
|
839
|
+
items.push({ freq: i, mag: spectrum.magnitude[i] });
|
|
840
|
+
}
|
|
841
|
+
items.sort((a, b) => b.mag - a.mag);
|
|
842
|
+
return items.slice(0, k);
|
|
843
|
+
}
|
|
844
|
+
spectralEnergy(spectrum) {
|
|
845
|
+
let energy = 0;
|
|
846
|
+
const n = spectrum.D;
|
|
847
|
+
for (let i = 0; i < n; i++) {
|
|
848
|
+
energy += spectrum.magnitude[i] * spectrum.magnitude[i];
|
|
849
|
+
}
|
|
850
|
+
return energy;
|
|
851
|
+
}
|
|
852
|
+
spectralEntropy(spectrum) {
|
|
853
|
+
const n = spectrum.D;
|
|
854
|
+
const power = new Float32Array(n);
|
|
855
|
+
let totalPower = 0;
|
|
856
|
+
for (let i = 0; i < n; i++) {
|
|
857
|
+
power[i] = spectrum.magnitude[i] * spectrum.magnitude[i];
|
|
858
|
+
totalPower += power[i];
|
|
859
|
+
}
|
|
860
|
+
if (totalPower === 0) return 0;
|
|
861
|
+
let entropy = 0;
|
|
862
|
+
for (let i = 0; i < n; i++) {
|
|
863
|
+
const p = power[i] / totalPower;
|
|
864
|
+
if (p > 0) {
|
|
865
|
+
entropy -= p * Math.log2(p);
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
return entropy / Math.log2(n);
|
|
869
|
+
}
|
|
870
|
+
spectralSparsity(spectrum) {
|
|
871
|
+
const n = spectrum.D;
|
|
872
|
+
let l1 = 0;
|
|
873
|
+
let l2Sq = 0;
|
|
874
|
+
for (let i = 0; i < n; i++) {
|
|
875
|
+
l1 += spectrum.magnitude[i];
|
|
876
|
+
l2Sq += spectrum.magnitude[i] * spectrum.magnitude[i];
|
|
877
|
+
}
|
|
878
|
+
const l2 = Math.sqrt(l2Sq);
|
|
879
|
+
if (l2 === 0) return 0;
|
|
880
|
+
const sqrtN = Math.sqrt(n);
|
|
881
|
+
return (sqrtN - l1 / l2) / (sqrtN - 1);
|
|
882
|
+
}
|
|
883
|
+
lowFrequencyEnergy(spectrum) {
|
|
884
|
+
let energy = 0;
|
|
885
|
+
const half = Math.floor(spectrum.D / 2);
|
|
886
|
+
const quarter = Math.floor(half / 2);
|
|
887
|
+
for (let i = 0; i < quarter; i++) {
|
|
888
|
+
energy += spectrum.magnitude[i] * spectrum.magnitude[i];
|
|
889
|
+
}
|
|
890
|
+
return energy;
|
|
891
|
+
}
|
|
892
|
+
highFrequencyEnergy(spectrum) {
|
|
893
|
+
let energy = 0;
|
|
894
|
+
const half = Math.floor(spectrum.D / 2);
|
|
895
|
+
const quarter = Math.floor(half / 2);
|
|
896
|
+
for (let i = quarter; i < half; i++) {
|
|
897
|
+
energy += spectrum.magnitude[i] * spectrum.magnitude[i];
|
|
898
|
+
}
|
|
899
|
+
return energy;
|
|
900
|
+
}
|
|
901
|
+
spectralSimilarity(a, b) {
|
|
902
|
+
if (a.D !== b.D) return 0;
|
|
903
|
+
let dot = 0, normA = 0, normB = 0;
|
|
904
|
+
const n = a.D;
|
|
905
|
+
for (let i = 0; i < n; i++) {
|
|
906
|
+
dot += a.magnitude[i] * b.magnitude[i];
|
|
907
|
+
normA += a.magnitude[i] * a.magnitude[i];
|
|
908
|
+
normB += b.magnitude[i] * b.magnitude[i];
|
|
909
|
+
}
|
|
910
|
+
const denom = Math.sqrt(normA) * Math.sqrt(normB);
|
|
911
|
+
return denom > 0 ? dot / denom : 0;
|
|
912
|
+
}
|
|
913
|
+
};
|
|
914
|
+
|
|
915
|
+
// core/memory_engine.js
|
|
916
|
+
var MemoryEngine = class {
|
|
917
|
+
/**
|
|
918
|
+
* @param {Object} config
|
|
919
|
+
* @param {number} [config.alpha=0.3] - Reinforcement saturating factor
|
|
920
|
+
* @param {number} [config.lambda=0.01] - Base decay rate per hour
|
|
921
|
+
* @param {number} [config.ws=0.4] - Semantic similarity weight
|
|
922
|
+
* @param {number} [config.wr=0.2] - Spectral resonance weight
|
|
923
|
+
* @param {number} [config.wc=0.1] - Confidence weight
|
|
924
|
+
* @param {number} [config.wf=0.1] - Reinforcement frequency weight
|
|
925
|
+
* @param {number} [config.wd=0.1] - Decay penalty weight
|
|
926
|
+
* @param {number} [config.wx=0.1] - Contradiction penalty weight
|
|
927
|
+
*/
|
|
928
|
+
constructor(config = {}) {
|
|
929
|
+
this.records = /* @__PURE__ */ new Map();
|
|
930
|
+
this.recordsList = [];
|
|
931
|
+
this.spectral = new SpectralEngine();
|
|
932
|
+
this.alpha = config.alpha !== void 0 ? config.alpha : 0.3;
|
|
933
|
+
this.lambda = config.lambda !== void 0 ? config.lambda : 0.01;
|
|
934
|
+
this.ws = config.ws !== void 0 ? config.ws : 0.4;
|
|
935
|
+
this.wr = config.wr !== void 0 ? config.wr : 0.2;
|
|
936
|
+
this.wc = config.wc !== void 0 ? config.wc : 0.1;
|
|
937
|
+
this.wf = config.wf !== void 0 ? config.wf : 0.1;
|
|
938
|
+
this.wd = config.wd !== void 0 ? config.wd : 0.1;
|
|
939
|
+
this.wx = config.wx !== void 0 ? config.wx : 0.1;
|
|
940
|
+
this.numTables = 4;
|
|
941
|
+
this.numProjections = 8;
|
|
942
|
+
this.tablesProjections = null;
|
|
943
|
+
this.tablesBuckets = null;
|
|
944
|
+
this.highPriorityRecords = /* @__PURE__ */ new Map();
|
|
945
|
+
this._saveTimeout = null;
|
|
946
|
+
this._savePromise = Promise.resolve();
|
|
947
|
+
}
|
|
948
|
+
_initLSH(D) {
|
|
949
|
+
this.D = D;
|
|
950
|
+
this.tablesProjections = [];
|
|
951
|
+
this.tablesBuckets = [];
|
|
952
|
+
for (let t = 0; t < this.numTables; t++) {
|
|
953
|
+
const projections = [];
|
|
954
|
+
for (let i = 0; i < this.numProjections; i++) {
|
|
955
|
+
const vec = new Float32Array(D);
|
|
956
|
+
for (let j = 0; j < D; j++) {
|
|
957
|
+
vec[j] = Math.random() * 2 - 1;
|
|
958
|
+
}
|
|
959
|
+
projections.push(vec);
|
|
960
|
+
}
|
|
961
|
+
this.tablesProjections.push(projections);
|
|
962
|
+
this.tablesBuckets.push(Array.from({ length: 256 }, () => []));
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
_hash(vector, tableIndex) {
|
|
966
|
+
let hash = 0;
|
|
967
|
+
const projections = this.tablesProjections[tableIndex];
|
|
968
|
+
for (let i = 0; i < this.numProjections; i++) {
|
|
969
|
+
let dot = 0;
|
|
970
|
+
const p = projections[i];
|
|
971
|
+
for (let j = 0; j < this.D; j++) {
|
|
972
|
+
dot += vector[j] * p[j];
|
|
973
|
+
}
|
|
974
|
+
if (dot > 0) {
|
|
975
|
+
hash |= 1 << i;
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
return hash;
|
|
979
|
+
}
|
|
980
|
+
/**
|
|
981
|
+
* Add a new MemoryRecord and index it in the LSH tables
|
|
982
|
+
* @param {Object} item
|
|
983
|
+
* @returns {Object} Added memory record
|
|
984
|
+
*/
|
|
985
|
+
addRecord(item) {
|
|
986
|
+
const t = Date.now();
|
|
987
|
+
const id = item.id || Math.random().toString(36).substring(2, 11);
|
|
988
|
+
let repr = item.representation;
|
|
989
|
+
if (!repr || repr.length === 0) {
|
|
990
|
+
repr = new Float32Array(this.D || 8192);
|
|
991
|
+
} else if (!(repr instanceof Float32Array)) {
|
|
992
|
+
repr = new Float32Array(repr);
|
|
993
|
+
}
|
|
994
|
+
const record = {
|
|
995
|
+
id,
|
|
996
|
+
representation: repr,
|
|
997
|
+
content: item.content,
|
|
998
|
+
confidence: item.confidence !== void 0 ? item.confidence : 1,
|
|
999
|
+
reinforcement: item.reinforcement !== void 0 ? item.reinforcement : 1,
|
|
1000
|
+
createdAt: item.createdAt || t,
|
|
1001
|
+
lastAccessedAt: item.lastAccessedAt || t,
|
|
1002
|
+
lastReinforcedAt: item.lastReinforcedAt || t,
|
|
1003
|
+
source: item.source || "user",
|
|
1004
|
+
sourceType: item.sourceType || "user",
|
|
1005
|
+
status: item.status || "active",
|
|
1006
|
+
contradictionIds: item.contradictionIds || [],
|
|
1007
|
+
priority: item.priority || "normal"
|
|
1008
|
+
// Support priority field
|
|
1009
|
+
};
|
|
1010
|
+
const recordIndex = this.recordsList.length;
|
|
1011
|
+
this.recordsList.push(record);
|
|
1012
|
+
this.records.set(id, record);
|
|
1013
|
+
if (record.priority === "high") {
|
|
1014
|
+
this.highPriorityRecords.set(id, recordIndex);
|
|
1015
|
+
}
|
|
1016
|
+
if (!this.tablesProjections) {
|
|
1017
|
+
this._initLSH(record.representation.length);
|
|
1018
|
+
}
|
|
1019
|
+
for (let t2 = 0; t2 < this.numTables; t2++) {
|
|
1020
|
+
const hash = this._hash(record.representation, t2);
|
|
1021
|
+
this.tablesBuckets[t2][hash].push(recordIndex);
|
|
1022
|
+
}
|
|
1023
|
+
this._checkAndFlagContradictions(record);
|
|
1024
|
+
return record;
|
|
1025
|
+
}
|
|
1026
|
+
/**
|
|
1027
|
+
* Reinforce a memory record using saturating Hebbian confidence updates
|
|
1028
|
+
* @param {string} id - Record ID
|
|
1029
|
+
* @param {number} [alpha=this.alpha] - Custom alpha
|
|
1030
|
+
*/
|
|
1031
|
+
reinforce(id, alpha = this.alpha) {
|
|
1032
|
+
const record = this.records.get(id);
|
|
1033
|
+
if (!record) return;
|
|
1034
|
+
const t = Date.now();
|
|
1035
|
+
const currentC = this.getDecayedConfidence(record, t);
|
|
1036
|
+
record.confidence = currentC + alpha * (1 - currentC);
|
|
1037
|
+
record.reinforcement += 1;
|
|
1038
|
+
record.lastReinforcedAt = t;
|
|
1039
|
+
}
|
|
1040
|
+
/**
|
|
1041
|
+
* Get dynamically decayed confidence at a specific timestamp
|
|
1042
|
+
* @param {Object} record
|
|
1043
|
+
* @param {number} [currentTime=Date.now()]
|
|
1044
|
+
* @returns {number} Decayed confidence in [0.0, 1.0]
|
|
1045
|
+
*/
|
|
1046
|
+
getDecayedConfidence(record, currentTime = Date.now()) {
|
|
1047
|
+
const dtMs = currentTime - record.lastReinforcedAt;
|
|
1048
|
+
const dtHours = dtMs / (1e3 * 3600);
|
|
1049
|
+
const logReinforce = Math.log2(record.reinforcement + 1);
|
|
1050
|
+
const effLambda = this.lambda / (logReinforce || 1);
|
|
1051
|
+
return record.confidence * Math.exp(-effLambda * dtHours);
|
|
1052
|
+
}
|
|
1053
|
+
/**
|
|
1054
|
+
* Set dynamic contradiction status on two conflicting memory records
|
|
1055
|
+
* @param {string} idA
|
|
1056
|
+
* @param {string} idB
|
|
1057
|
+
*/
|
|
1058
|
+
flagContradiction(idA, idB) {
|
|
1059
|
+
const recA = this.records.get(idA);
|
|
1060
|
+
const recB = this.records.get(idB);
|
|
1061
|
+
if (recA && recB) {
|
|
1062
|
+
if (!recA.contradictionIds.includes(idB)) recA.contradictionIds.push(idB);
|
|
1063
|
+
if (!recB.contradictionIds.includes(idA)) recB.contradictionIds.push(idA);
|
|
1064
|
+
recA.status = "conflicted";
|
|
1065
|
+
recB.status = "conflicted";
|
|
1066
|
+
}
|
|
1067
|
+
}
|
|
1068
|
+
/**
|
|
1069
|
+
* Retrieve matched memory candidates using Multi-Table LSH and Multi-Probe Hamming search
|
|
1070
|
+
* @param {Float32Array} queryRepr - Query FHRR vector
|
|
1071
|
+
* @param {number} [limit=5]
|
|
1072
|
+
* @param {number} [currentTime=Date.now()]
|
|
1073
|
+
* @returns {Array} List of matched candidates and scores
|
|
1074
|
+
*/
|
|
1075
|
+
retrieve(queryRepr, limit = 5, currentTime = Date.now()) {
|
|
1076
|
+
const D = queryRepr.length;
|
|
1077
|
+
if (!this.tablesProjections) {
|
|
1078
|
+
this._initLSH(D);
|
|
1079
|
+
}
|
|
1080
|
+
const candidateIndices = /* @__PURE__ */ new Set();
|
|
1081
|
+
for (const [id, recordIndex] of this.highPriorityRecords.entries()) {
|
|
1082
|
+
candidateIndices.add(recordIndex);
|
|
1083
|
+
}
|
|
1084
|
+
let lshFoundCount = 0;
|
|
1085
|
+
for (let t = 0; t < this.numTables; t++) {
|
|
1086
|
+
const queryHash = this._hash(queryRepr, t);
|
|
1087
|
+
const bucket = this.tablesBuckets[t][queryHash];
|
|
1088
|
+
for (let i = 0; i < bucket.length; i++) {
|
|
1089
|
+
candidateIndices.add(bucket[i]);
|
|
1090
|
+
lshFoundCount++;
|
|
1091
|
+
}
|
|
1092
|
+
for (let bit = 0; bit < this.numProjections; bit++) {
|
|
1093
|
+
const neighborHash = queryHash ^ 1 << bit;
|
|
1094
|
+
const neighborBucket = this.tablesBuckets[t][neighborHash];
|
|
1095
|
+
for (let i = 0; i < neighborBucket.length; i++) {
|
|
1096
|
+
candidateIndices.add(neighborBucket[i]);
|
|
1097
|
+
lshFoundCount++;
|
|
1098
|
+
}
|
|
1099
|
+
}
|
|
1100
|
+
}
|
|
1101
|
+
let fallbackTriggered = false;
|
|
1102
|
+
if (lshFoundCount === 0) {
|
|
1103
|
+
fallbackTriggered = true;
|
|
1104
|
+
} else {
|
|
1105
|
+
let maxC = -1;
|
|
1106
|
+
let maxSim = -1;
|
|
1107
|
+
for (const idx of candidateIndices) {
|
|
1108
|
+
const record = this.recordsList[idx];
|
|
1109
|
+
const C = this.getDecayedConfidence(record, currentTime);
|
|
1110
|
+
if (C > maxC) maxC = C;
|
|
1111
|
+
const sim = this._cosineSimilarity(queryRepr, record.representation);
|
|
1112
|
+
if (sim > maxSim) maxSim = sim;
|
|
1113
|
+
}
|
|
1114
|
+
if (maxC < 0.45 || maxSim < 0.35) {
|
|
1115
|
+
fallbackTriggered = true;
|
|
1116
|
+
}
|
|
1117
|
+
}
|
|
1118
|
+
let indicesToSearch = candidateIndices;
|
|
1119
|
+
if (fallbackTriggered) {
|
|
1120
|
+
indicesToSearch = new Set(Array.from({ length: this.recordsList.length }, (_, i) => i));
|
|
1121
|
+
}
|
|
1122
|
+
const results = [];
|
|
1123
|
+
const specQuery = this.spectral.spectralTransform({ type: "real", values: queryRepr, D });
|
|
1124
|
+
for (const idx of indicesToSearch) {
|
|
1125
|
+
const record = this.recordsList[idx];
|
|
1126
|
+
const sSem = this._cosineSimilarity(queryRepr, record.representation);
|
|
1127
|
+
const specRecord = record.spectralTransform || (record.spectralTransform = this.spectral.spectralTransform({ type: "real", values: record.representation, D }));
|
|
1128
|
+
const sRes = this.spectral.spectralSimilarity(specQuery, specRecord);
|
|
1129
|
+
const C = this.getDecayedConfidence(record, currentTime);
|
|
1130
|
+
const F = Math.min(1, Math.log10(record.reinforcement + 1));
|
|
1131
|
+
const D_penalty = record.confidence - C;
|
|
1132
|
+
const X = record.status === "conflicted" || record.contradictionIds.length > 0 ? 1 : 0;
|
|
1133
|
+
const score = this.ws * sSem + this.wr * sRes + this.wc * C + this.wf * F - this.wd * D_penalty - this.wx * X;
|
|
1134
|
+
results.push({ record, score });
|
|
1135
|
+
}
|
|
1136
|
+
results.sort((a, b) => b.score - a.score);
|
|
1137
|
+
const sliced = results.slice(0, limit);
|
|
1138
|
+
for (const item of sliced) {
|
|
1139
|
+
item.record.lastAccessedAt = currentTime;
|
|
1140
|
+
}
|
|
1141
|
+
return sliced.map((item) => ({
|
|
1142
|
+
record: item.record,
|
|
1143
|
+
score: item.score
|
|
1144
|
+
}));
|
|
1145
|
+
}
|
|
1146
|
+
/**
|
|
1147
|
+
* Non-blocking debounced save to file system
|
|
1148
|
+
* @param {string} filePath
|
|
1149
|
+
*/
|
|
1150
|
+
saveToFile(filePath) {
|
|
1151
|
+
if (this._saveTimeout) clearTimeout(this._saveTimeout);
|
|
1152
|
+
const data = [];
|
|
1153
|
+
for (const record of this.recordsList) {
|
|
1154
|
+
data.push({
|
|
1155
|
+
id: record.id,
|
|
1156
|
+
representation: Array.from(record.representation),
|
|
1157
|
+
content: record.content,
|
|
1158
|
+
confidence: record.confidence,
|
|
1159
|
+
reinforcement: record.reinforcement,
|
|
1160
|
+
createdAt: record.createdAt,
|
|
1161
|
+
lastAccessedAt: record.lastAccessedAt,
|
|
1162
|
+
lastReinforcedAt: record.lastReinforcedAt,
|
|
1163
|
+
source: record.source,
|
|
1164
|
+
sourceType: record.sourceType,
|
|
1165
|
+
status: record.status,
|
|
1166
|
+
contradictionIds: record.contradictionIds
|
|
1167
|
+
});
|
|
1168
|
+
}
|
|
1169
|
+
this._savePromise = new Promise((resolve) => {
|
|
1170
|
+
this._saveTimeout = setTimeout(async () => {
|
|
1171
|
+
try {
|
|
1172
|
+
await fs.promises.writeFile(filePath, JSON.stringify(data, null, 2), "utf8");
|
|
1173
|
+
} catch (e) {
|
|
1174
|
+
console.error("MemoryEngine: Asynchronous write failed:", e.message);
|
|
1175
|
+
}
|
|
1176
|
+
resolve();
|
|
1177
|
+
}, 50);
|
|
1178
|
+
});
|
|
1179
|
+
}
|
|
1180
|
+
/**
|
|
1181
|
+
* Load memory records synchronously and rebuild LSH tables
|
|
1182
|
+
* @param {string} filePath
|
|
1183
|
+
*/
|
|
1184
|
+
loadFromFile(filePath) {
|
|
1185
|
+
if (!fs.existsSync(filePath)) return;
|
|
1186
|
+
try {
|
|
1187
|
+
const raw = fs.readFileSync(filePath, "utf8");
|
|
1188
|
+
const data = JSON.parse(raw);
|
|
1189
|
+
this.records.clear();
|
|
1190
|
+
this.recordsList = [];
|
|
1191
|
+
this.tablesProjections = null;
|
|
1192
|
+
this.tablesBuckets = null;
|
|
1193
|
+
for (const item of data) {
|
|
1194
|
+
this.addRecord({
|
|
1195
|
+
id: item.id,
|
|
1196
|
+
representation: new Float32Array(item.representation),
|
|
1197
|
+
content: item.content,
|
|
1198
|
+
confidence: item.confidence,
|
|
1199
|
+
reinforcement: item.reinforcement,
|
|
1200
|
+
createdAt: item.createdAt,
|
|
1201
|
+
lastAccessedAt: item.lastAccessedAt,
|
|
1202
|
+
lastReinforcedAt: item.lastReinforcedAt,
|
|
1203
|
+
source: item.source,
|
|
1204
|
+
sourceType: item.sourceType,
|
|
1205
|
+
status: item.status,
|
|
1206
|
+
contradictionIds: item.contradictionIds
|
|
1207
|
+
});
|
|
1208
|
+
}
|
|
1209
|
+
} catch (e) {
|
|
1210
|
+
console.error("MemoryEngine: Failed to load from file:", e.message);
|
|
1211
|
+
}
|
|
1212
|
+
}
|
|
1213
|
+
_cosineSimilarity(a, b) {
|
|
1214
|
+
let sum = 0;
|
|
1215
|
+
const D = a.length;
|
|
1216
|
+
for (let i = 0; i < D; i++) {
|
|
1217
|
+
sum += Math.cos(a[i] - b[i]);
|
|
1218
|
+
}
|
|
1219
|
+
return sum / D;
|
|
1220
|
+
}
|
|
1221
|
+
_checkAndFlagContradictions(record) {
|
|
1222
|
+
if (this.recordsList.length <= 1) return;
|
|
1223
|
+
const existingResults = this.retrieve(record.representation, 3);
|
|
1224
|
+
for (const existing of existingResults) {
|
|
1225
|
+
const sim = this._cosineSimilarity(record.representation, existing.record.representation);
|
|
1226
|
+
const isContra = this._isContradictory(record.content, existing.record.content);
|
|
1227
|
+
if (sim > 0.35 && existing.record.id !== record.id && existing.record.content !== record.content) {
|
|
1228
|
+
if (isContra) {
|
|
1229
|
+
this.flagContradiction(record.id, existing.record.id);
|
|
1230
|
+
}
|
|
1231
|
+
}
|
|
1232
|
+
}
|
|
1233
|
+
}
|
|
1234
|
+
_isContradictory(t1, t2) {
|
|
1235
|
+
const getBloodType = (t) => {
|
|
1236
|
+
if (t.includes("a pozitif") || t.includes("a+") || t.includes("a poz")) return "A+";
|
|
1237
|
+
if (t.includes("b negatif") || t.includes("b-") || t.includes("b neg")) return "B-";
|
|
1238
|
+
if (t.includes("0") || t.includes("s\u0131f\u0131r")) return "0";
|
|
1239
|
+
if (t.includes("ab")) return "AB";
|
|
1240
|
+
return null;
|
|
1241
|
+
};
|
|
1242
|
+
const getRisk = (t) => {
|
|
1243
|
+
if (t.includes("y\xFCksek") || t.includes("riskli")) return "high";
|
|
1244
|
+
if (t.includes("normal") || t.includes("d\xFC\u015F\xFCk") || t.includes("risk yok")) return "normal";
|
|
1245
|
+
return null;
|
|
1246
|
+
};
|
|
1247
|
+
const l1 = t1.toLowerCase();
|
|
1248
|
+
const l2 = t2.toLowerCase();
|
|
1249
|
+
if ((l1.includes("kan grubu") || l1.includes("grubu")) && (l2.includes("kan grubu") || l2.includes("grubu"))) {
|
|
1250
|
+
const b1 = getBloodType(l1);
|
|
1251
|
+
const b2 = getBloodType(l2);
|
|
1252
|
+
if (b1 && b2 && b1 !== b2) return true;
|
|
1253
|
+
}
|
|
1254
|
+
if (l1.includes("risk") && l2.includes("risk")) {
|
|
1255
|
+
const r1 = getRisk(l1);
|
|
1256
|
+
const r2 = getRisk(l2);
|
|
1257
|
+
if (r1 && r2 && r1 !== r2) return true;
|
|
1258
|
+
}
|
|
1259
|
+
if ((l1.includes("tansiyon") || l1.includes("bas\u0131nc\u0131")) && (l2.includes("tansiyon") || l2.includes("bas\u0131nc\u0131"))) {
|
|
1260
|
+
const nums1 = l1.match(/\d+/g);
|
|
1261
|
+
const nums2 = l2.match(/\d+/g);
|
|
1262
|
+
if (nums1 && nums2 && nums1[0] !== nums2[0]) return true;
|
|
1263
|
+
}
|
|
1264
|
+
return false;
|
|
1265
|
+
}
|
|
1266
|
+
resolveConflict(winnerId, loserId) {
|
|
1267
|
+
const winner = this.records.get(winnerId);
|
|
1268
|
+
const loser = this.records.get(loserId);
|
|
1269
|
+
if (winner) {
|
|
1270
|
+
const t = Date.now();
|
|
1271
|
+
const currentC = this.getDecayedConfidence(winner, t);
|
|
1272
|
+
winner.confidence = Math.min(1, currentC + 0.3 * (1 - currentC));
|
|
1273
|
+
winner.status = "active";
|
|
1274
|
+
winner.contradictionIds = [];
|
|
1275
|
+
winner.lastReinforcedAt = t;
|
|
1276
|
+
}
|
|
1277
|
+
if (loser) {
|
|
1278
|
+
loser.confidence = 0;
|
|
1279
|
+
loser.status = "rejected";
|
|
1280
|
+
loser.contradictionIds = [];
|
|
1281
|
+
}
|
|
1282
|
+
}
|
|
1283
|
+
};
|
|
1284
|
+
|
|
1285
|
+
// core/reasoning_router.js
|
|
1286
|
+
function evaluateMath(expr) {
|
|
1287
|
+
const tokens = [];
|
|
1288
|
+
let i = 0;
|
|
1289
|
+
while (i < expr.length) {
|
|
1290
|
+
const char = expr[i];
|
|
1291
|
+
if (/\s/.test(char)) {
|
|
1292
|
+
i++;
|
|
1293
|
+
continue;
|
|
1294
|
+
}
|
|
1295
|
+
if (/[0-9.]/.test(char)) {
|
|
1296
|
+
let numStr = "";
|
|
1297
|
+
while (i < expr.length && /[0-9.]/.test(expr[i])) {
|
|
1298
|
+
numStr += expr[i];
|
|
1299
|
+
i++;
|
|
1300
|
+
}
|
|
1301
|
+
tokens.push({ type: "NUMBER", value: parseFloat(numStr) });
|
|
1302
|
+
continue;
|
|
1303
|
+
}
|
|
1304
|
+
if (char === "+" || char === "-" || char === "*" || char === "/" || char === "%" || char === "^" || char === "(" || char === ")") {
|
|
1305
|
+
tokens.push({ type: "OP", value: char });
|
|
1306
|
+
i++;
|
|
1307
|
+
continue;
|
|
1308
|
+
}
|
|
1309
|
+
throw new Error("Invalid character in math expression: " + char);
|
|
1310
|
+
}
|
|
1311
|
+
let tokenIndex = 0;
|
|
1312
|
+
function peek() {
|
|
1313
|
+
return tokens[tokenIndex];
|
|
1314
|
+
}
|
|
1315
|
+
function consume(expectedValue) {
|
|
1316
|
+
const t = tokens[tokenIndex];
|
|
1317
|
+
if (!t) throw new Error("Unexpected end of expression");
|
|
1318
|
+
if (expectedValue !== void 0 && t.value !== expectedValue) {
|
|
1319
|
+
throw new Error(`Expected ${expectedValue} but got ${t.value}`);
|
|
1320
|
+
}
|
|
1321
|
+
tokenIndex++;
|
|
1322
|
+
return t;
|
|
1323
|
+
}
|
|
1324
|
+
function parseExpression() {
|
|
1325
|
+
let val = parseTerm();
|
|
1326
|
+
while (true) {
|
|
1327
|
+
const t = peek();
|
|
1328
|
+
if (t && t.type === "OP" && (t.value === "+" || t.value === "-")) {
|
|
1329
|
+
consume();
|
|
1330
|
+
const nextVal = parseTerm();
|
|
1331
|
+
if (t.value === "+") val += nextVal;
|
|
1332
|
+
else val -= nextVal;
|
|
1333
|
+
} else {
|
|
1334
|
+
break;
|
|
1335
|
+
}
|
|
1336
|
+
}
|
|
1337
|
+
return val;
|
|
1338
|
+
}
|
|
1339
|
+
function parseTerm() {
|
|
1340
|
+
let val = parseFactor();
|
|
1341
|
+
while (true) {
|
|
1342
|
+
const t = peek();
|
|
1343
|
+
if (t && t.type === "OP" && (t.value === "*" || t.value === "/" || t.value === "%")) {
|
|
1344
|
+
consume();
|
|
1345
|
+
const nextVal = parseFactor();
|
|
1346
|
+
if (t.value === "*") val *= nextVal;
|
|
1347
|
+
else if (t.value === "/") {
|
|
1348
|
+
if (nextVal === 0) throw new Error("Division by zero");
|
|
1349
|
+
val /= nextVal;
|
|
1350
|
+
} else val %= nextVal;
|
|
1351
|
+
} else {
|
|
1352
|
+
break;
|
|
1353
|
+
}
|
|
1354
|
+
}
|
|
1355
|
+
return val;
|
|
1356
|
+
}
|
|
1357
|
+
function parseFactor() {
|
|
1358
|
+
let val = parsePrimary();
|
|
1359
|
+
while (true) {
|
|
1360
|
+
const t = peek();
|
|
1361
|
+
if (t && t.type === "OP" && t.value === "^") {
|
|
1362
|
+
consume();
|
|
1363
|
+
const nextVal = parseFactor();
|
|
1364
|
+
val = Math.pow(val, nextVal);
|
|
1365
|
+
} else {
|
|
1366
|
+
break;
|
|
1367
|
+
}
|
|
1368
|
+
}
|
|
1369
|
+
return val;
|
|
1370
|
+
}
|
|
1371
|
+
function parsePrimary() {
|
|
1372
|
+
const t = peek();
|
|
1373
|
+
if (!t) throw new Error("Unexpected end of expression");
|
|
1374
|
+
if (t.type === "NUMBER") {
|
|
1375
|
+
consume();
|
|
1376
|
+
return t.value;
|
|
1377
|
+
}
|
|
1378
|
+
if (t.type === "OP" && t.value === "(") {
|
|
1379
|
+
consume("(");
|
|
1380
|
+
const val = parseExpression();
|
|
1381
|
+
consume(")");
|
|
1382
|
+
return val;
|
|
1383
|
+
}
|
|
1384
|
+
if (t.type === "OP" && t.value === "-") {
|
|
1385
|
+
consume("-");
|
|
1386
|
+
return -parsePrimary();
|
|
1387
|
+
}
|
|
1388
|
+
if (t.type === "OP" && t.value === "+") {
|
|
1389
|
+
consume("+");
|
|
1390
|
+
return parsePrimary();
|
|
1391
|
+
}
|
|
1392
|
+
throw new Error(`Unexpected token: ${t.value}`);
|
|
1393
|
+
}
|
|
1394
|
+
const result = parseExpression();
|
|
1395
|
+
if (tokenIndex < tokens.length) {
|
|
1396
|
+
throw new Error("Unexpected trailing tokens at end of expression");
|
|
1397
|
+
}
|
|
1398
|
+
return result;
|
|
1399
|
+
}
|
|
1400
|
+
var ReasoningRouter = class {
|
|
1401
|
+
/**
|
|
1402
|
+
* @param {Object} memoryEngine
|
|
1403
|
+
* @param {Object} sdkInstance
|
|
1404
|
+
*/
|
|
1405
|
+
constructor(memoryEngine, sdkInstance) {
|
|
1406
|
+
this.memory = memoryEngine;
|
|
1407
|
+
this.sdk = sdkInstance;
|
|
1408
|
+
this.D = sdkInstance ? sdkInstance.D : 4096;
|
|
1409
|
+
if (this.sdk && this.sdk.hdc) {
|
|
1410
|
+
const memReps = ["hat\u0131rla", "hat\u0131rl\u0131yor", "favori", "nerede", "kim", "haf\u0131za", "hasta", "kay\u0131t", "bilgi", "durum"].map((w) => this.sdk.hdc.generateSeeded("complex", w));
|
|
1411
|
+
this.memoryIntentVec = this.sdk.hdc.bundle(memReps).values;
|
|
1412
|
+
const ruleReps = ["\xE7eli\u015Fki", "kural", "kar\u015F\u0131la\u015Ft\u0131r", "do\u011Fru", "yasak", "uygun"].map((w) => this.sdk.hdc.generateSeeded("complex", w));
|
|
1413
|
+
this.ruleIntentVec = this.sdk.hdc.bundle(ruleReps).values;
|
|
1414
|
+
const mathReps = ["hesapla", "toplam", "\xE7arp", "b\xF6l", "ka\xE7", "say\u0131", "doz", "miktar"].map((w) => this.sdk.hdc.generateSeeded("complex", w));
|
|
1415
|
+
this.mathIntentVec = this.sdk.hdc.bundle(mathReps).values;
|
|
1416
|
+
} else {
|
|
1417
|
+
this.memoryIntentVec = new Float32Array(this.D);
|
|
1418
|
+
this.ruleIntentVec = new Float32Array(this.D);
|
|
1419
|
+
this.mathIntentVec = new Float32Array(this.D);
|
|
1420
|
+
}
|
|
1421
|
+
this.chatState = "idle";
|
|
1422
|
+
this.pendingRecord = null;
|
|
1423
|
+
}
|
|
1424
|
+
/**
|
|
1425
|
+
* Self-vectorize text input using SDK's HDC engine (runs in < 0.1 ms)
|
|
1426
|
+
* @param {string} text
|
|
1427
|
+
* @returns {Float32Array}
|
|
1428
|
+
*/
|
|
1429
|
+
vectorize(text) {
|
|
1430
|
+
const clean = text.toLowerCase().trim().replace(/[^a-zçgğıoöşuüâîû\s]/g, "");
|
|
1431
|
+
const words = clean.split(/\s+/).filter(Boolean);
|
|
1432
|
+
if (this.sdk && this.sdk.hdc) {
|
|
1433
|
+
if (words.length === 0) {
|
|
1434
|
+
return new Float32Array(this.D);
|
|
1435
|
+
}
|
|
1436
|
+
if (words.length === 1) {
|
|
1437
|
+
return this.sdk.hdc.generateSeeded("complex", words[0]).values;
|
|
1438
|
+
}
|
|
1439
|
+
const reps = words.map((w) => this.sdk.hdc.generateSeeded("complex", w));
|
|
1440
|
+
return this.sdk.hdc.bundle(reps).values;
|
|
1441
|
+
}
|
|
1442
|
+
return new Float32Array(this.D);
|
|
1443
|
+
}
|
|
1444
|
+
/**
|
|
1445
|
+
* 8-Axis Verification Suite
|
|
1446
|
+
* @param {Object} result - Candidate routed result
|
|
1447
|
+
* @param {number} axis - Axis index [1-8]
|
|
1448
|
+
* @returns {boolean} True if pass
|
|
1449
|
+
*/
|
|
1450
|
+
validateAxis(result, axis) {
|
|
1451
|
+
if (!result) return false;
|
|
1452
|
+
if (axis === 1 && result.route === "math") {
|
|
1453
|
+
const match = result.input.match(/^\s*([0-9.]+)\s*([+\-*/%^])\s*([0-9.]+)\s*$/);
|
|
1454
|
+
if (match) {
|
|
1455
|
+
const a = parseFloat(match[1]);
|
|
1456
|
+
const op = match[2];
|
|
1457
|
+
const b = parseFloat(match[3]);
|
|
1458
|
+
const c = parseFloat(result.output);
|
|
1459
|
+
if (op === "*") {
|
|
1460
|
+
if (b !== 0 && Math.abs(c / b - a) > 1e-4) return false;
|
|
1461
|
+
} else if (op === "+") {
|
|
1462
|
+
if (Math.abs(c - b - a) > 1e-4) return false;
|
|
1463
|
+
} else if (op === "-") {
|
|
1464
|
+
if (Math.abs(c + b - a) > 1e-4) return false;
|
|
1465
|
+
} else if (op === "/") {
|
|
1466
|
+
if (b !== 0 && Math.abs(c * b - a) > 1e-4) return false;
|
|
1467
|
+
}
|
|
1468
|
+
}
|
|
1469
|
+
return true;
|
|
1470
|
+
}
|
|
1471
|
+
if (axis === 2 && result.route === "math") {
|
|
1472
|
+
const val = parseFloat(result.output);
|
|
1473
|
+
if (isNaN(val) || !isFinite(val)) return false;
|
|
1474
|
+
if (result.input.includes("/0")) return false;
|
|
1475
|
+
return true;
|
|
1476
|
+
}
|
|
1477
|
+
if (axis === 3 && result.route === "memory") {
|
|
1478
|
+
if (!result.results || result.results.length === 0) return false;
|
|
1479
|
+
const topRecord = result.results[0].record;
|
|
1480
|
+
if (topRecord.status === "conflicted" || topRecord.contradictionIds.length > 0) {
|
|
1481
|
+
return false;
|
|
1482
|
+
}
|
|
1483
|
+
return true;
|
|
1484
|
+
}
|
|
1485
|
+
if (axis === 4 && result.route === "memory") {
|
|
1486
|
+
if (!result.results || result.results.length === 0) return false;
|
|
1487
|
+
const topRecord = result.results[0].record;
|
|
1488
|
+
const C = this.memory.getDecayedConfidence(topRecord);
|
|
1489
|
+
if (C < 0.5) return false;
|
|
1490
|
+
return true;
|
|
1491
|
+
}
|
|
1492
|
+
if (axis === 5 && result.route === "memory") {
|
|
1493
|
+
if (!result.results || result.results.length === 0) return false;
|
|
1494
|
+
const queryVec = this.vectorize(result.input);
|
|
1495
|
+
const sSem = this._cosineSimilarity(queryVec, result.results[0].record.representation);
|
|
1496
|
+
if (sSem < 0.15) return false;
|
|
1497
|
+
return true;
|
|
1498
|
+
}
|
|
1499
|
+
if (axis === 6 && (result.route === "llm" || result.route === "memory")) {
|
|
1500
|
+
if (this.sdk && this.sdk.morphology) {
|
|
1501
|
+
const words = result.output.split(/\s+/).filter(Boolean);
|
|
1502
|
+
for (const w of words) {
|
|
1503
|
+
const cleanWord = w.toLowerCase().replace(/[^a-zçgğıoöşuüâîû]/g, "");
|
|
1504
|
+
if (cleanWord.length >= 2) {
|
|
1505
|
+
const harmony = this.sdk.morphology.determineVowelHarmony(cleanWord);
|
|
1506
|
+
if (harmony !== "front" && harmony !== "back") return false;
|
|
1507
|
+
}
|
|
1508
|
+
}
|
|
1509
|
+
}
|
|
1510
|
+
return true;
|
|
1511
|
+
}
|
|
1512
|
+
if (axis === 7 && result.route === "llm") {
|
|
1513
|
+
const words = result.output.split(/\s+/).filter(Boolean);
|
|
1514
|
+
for (const w of words) {
|
|
1515
|
+
const clean = w.toLowerCase().replace(/[^a-zçgğıoöşuüâîû]/g, "");
|
|
1516
|
+
if (/(kitapı|bebeki|çiçeki|ağacı)/.test(clean)) return false;
|
|
1517
|
+
}
|
|
1518
|
+
return true;
|
|
1519
|
+
}
|
|
1520
|
+
if (axis === 8 && result.route === "memory") {
|
|
1521
|
+
const queryWords = result.input.toLowerCase().split(/\s+/).filter((w) => w.length > 3);
|
|
1522
|
+
const contentLower = result.output.toLowerCase();
|
|
1523
|
+
if (queryWords.length > 0) {
|
|
1524
|
+
const matchesQueryWord = queryWords.some((qw) => contentLower.includes(qw));
|
|
1525
|
+
if (!matchesQueryWord) return false;
|
|
1526
|
+
}
|
|
1527
|
+
return true;
|
|
1528
|
+
}
|
|
1529
|
+
return true;
|
|
1530
|
+
}
|
|
1531
|
+
/**
|
|
1532
|
+
* Run all 8 verification axes
|
|
1533
|
+
*/
|
|
1534
|
+
validateAllAxes(result) {
|
|
1535
|
+
for (let axis = 1; axis <= 8; axis++) {
|
|
1536
|
+
if (!this.validateAxis(result, axis)) return false;
|
|
1537
|
+
}
|
|
1538
|
+
return true;
|
|
1539
|
+
}
|
|
1540
|
+
/**
|
|
1541
|
+
* Route the query dynamically using safe parser, self-vectorization, and hybrid classification
|
|
1542
|
+
* @param {string} input
|
|
1543
|
+
* @returns {Object} Route result
|
|
1544
|
+
*/
|
|
1545
|
+
route(input, options = {}) {
|
|
1546
|
+
const cleanInput = input.trim();
|
|
1547
|
+
const saveIntentRegex = /kaydet|ekle|yaz|not al|sakla|sisteme gir|oluştur/i;
|
|
1548
|
+
const confirmRegex = /^(evet|tamam|doğru|olur|kaydet|kabul|onay|evet kaydet)$/i;
|
|
1549
|
+
const rejectRegex = /^(hayır|iptal|vazgeç|yanlış|dur|bekle)$/i;
|
|
1550
|
+
if (this.chatState === "pending_confirmation") {
|
|
1551
|
+
if (confirmRegex.test(cleanInput)) {
|
|
1552
|
+
this.chatState = "recording";
|
|
1553
|
+
const r = this.pendingRecord;
|
|
1554
|
+
const searchableText = [r.baslik, r.kategori, r.aciklama, r.etiketler].filter(Boolean).join(" ");
|
|
1555
|
+
const representation = this.vectorize(searchableText);
|
|
1556
|
+
const newRecord = this.memory.addRecord({
|
|
1557
|
+
content: `${r.baslik} \u2014 ${r.aciklama}`,
|
|
1558
|
+
representation,
|
|
1559
|
+
priority: "normal"
|
|
1560
|
+
});
|
|
1561
|
+
this.chatState = "idle";
|
|
1562
|
+
this.pendingRecord = null;
|
|
1563
|
+
return {
|
|
1564
|
+
input: cleanInput,
|
|
1565
|
+
route: "memory",
|
|
1566
|
+
llmBypassed: true,
|
|
1567
|
+
output: "Haf\u0131za kayd\u0131 ba\u015Far\u0131yla eklendi.",
|
|
1568
|
+
reason: "Chat state machine confirm and record"
|
|
1569
|
+
};
|
|
1570
|
+
} else if (rejectRegex.test(cleanInput)) {
|
|
1571
|
+
this.chatState = "idle";
|
|
1572
|
+
this.pendingRecord = null;
|
|
1573
|
+
return {
|
|
1574
|
+
input: cleanInput,
|
|
1575
|
+
route: "memory",
|
|
1576
|
+
llmBypassed: true,
|
|
1577
|
+
output: "Kay\u0131t iptal edildi.",
|
|
1578
|
+
reason: "Chat state machine reject"
|
|
1579
|
+
};
|
|
1580
|
+
} else {
|
|
1581
|
+
this.chatState = "idle";
|
|
1582
|
+
this.pendingRecord = null;
|
|
1583
|
+
const normalResult = this._routeNormal(input, options);
|
|
1584
|
+
normalResult.output = "\xD6nceki kayd\u0131 iptal ettim. " + normalResult.output;
|
|
1585
|
+
return normalResult;
|
|
1586
|
+
}
|
|
1587
|
+
}
|
|
1588
|
+
if (this.chatState === "idle" && saveIntentRegex.test(cleanInput)) {
|
|
1589
|
+
const data = this._extractDataFromText(cleanInput);
|
|
1590
|
+
if (data.baslik && data.aciklama) {
|
|
1591
|
+
this.chatState = "pending_confirmation";
|
|
1592
|
+
this.pendingRecord = data;
|
|
1593
|
+
return {
|
|
1594
|
+
input: cleanInput,
|
|
1595
|
+
route: "memory",
|
|
1596
|
+
llmBypassed: true,
|
|
1597
|
+
output: `\u015Eunu kaydediyorum:
|
|
1598
|
+
Ba\u015Fl\u0131k: ${data.baslik}
|
|
1599
|
+
Not: ${data.aciklama}
|
|
1600
|
+
Do\u011Fru mu?`,
|
|
1601
|
+
reason: "Chat state machine save intent detected"
|
|
1602
|
+
};
|
|
1603
|
+
}
|
|
1604
|
+
}
|
|
1605
|
+
return this._routeNormal(input, options);
|
|
1606
|
+
}
|
|
1607
|
+
_extractDataFromText(text) {
|
|
1608
|
+
const clean = text.replace(/kaydet|ekle|yaz|not al|sakla|sisteme gir|oluştur/ig, "").trim();
|
|
1609
|
+
const parts = clean.split(",").map((p) => p.trim()).filter(Boolean);
|
|
1610
|
+
let baslik = "";
|
|
1611
|
+
let aciklama = "";
|
|
1612
|
+
let kategori = "";
|
|
1613
|
+
let etiketler = "";
|
|
1614
|
+
if (parts.length >= 2) {
|
|
1615
|
+
baslik = parts[0];
|
|
1616
|
+
aciklama = parts[1];
|
|
1617
|
+
if (parts.length >= 3) kategori = parts[2];
|
|
1618
|
+
if (parts.length >= 4) etiketler = parts.slice(3).join(", ");
|
|
1619
|
+
} else {
|
|
1620
|
+
const words = clean.split(/\s+/);
|
|
1621
|
+
if (words.length > 2) {
|
|
1622
|
+
baslik = words.slice(0, 2).join(" ");
|
|
1623
|
+
aciklama = words.slice(2).join(" ");
|
|
1624
|
+
} else {
|
|
1625
|
+
baslik = clean;
|
|
1626
|
+
aciklama = clean;
|
|
1627
|
+
}
|
|
1628
|
+
}
|
|
1629
|
+
baslik = baslik.replace(/[,.;!]+$/, "").trim();
|
|
1630
|
+
aciklama = aciklama.replace(/[,.;!]+$/, "").trim();
|
|
1631
|
+
if (!baslik) baslik = clean || "Yeni Kay\u0131t";
|
|
1632
|
+
if (!aciklama) aciklama = clean || "Detay girilmedi";
|
|
1633
|
+
return { baslik, aciklama, kategori, etiketler };
|
|
1634
|
+
}
|
|
1635
|
+
_routeNormal(input, options = {}) {
|
|
1636
|
+
const cleanInput = input.trim();
|
|
1637
|
+
const mathRegex = /^[0-9+\-*/().\s%^]+$/;
|
|
1638
|
+
const hasOperator = /[+\-*/%^]/.test(cleanInput);
|
|
1639
|
+
if (mathRegex.test(cleanInput) && hasOperator) {
|
|
1640
|
+
try {
|
|
1641
|
+
const val = evaluateMath(cleanInput);
|
|
1642
|
+
const candidateResult = {
|
|
1643
|
+
input: cleanInput,
|
|
1644
|
+
route: "math",
|
|
1645
|
+
llmBypassed: true,
|
|
1646
|
+
output: val.toString(),
|
|
1647
|
+
reason: "Deterministic arithmetic evaluation"
|
|
1648
|
+
};
|
|
1649
|
+
if (this.validateAllAxes(candidateResult)) {
|
|
1650
|
+
return candidateResult;
|
|
1651
|
+
} else {
|
|
1652
|
+
return {
|
|
1653
|
+
input: cleanInput,
|
|
1654
|
+
route: "math",
|
|
1655
|
+
llmBypassed: true,
|
|
1656
|
+
output: "Hata: Ge\xE7ersiz aritmetik i\u015Flem (S\u0131f\u0131ra b\xF6lme veya tan\u0131ms\u0131z sonu\xE7)",
|
|
1657
|
+
reason: "Math verifier failure recovery"
|
|
1658
|
+
};
|
|
1659
|
+
}
|
|
1660
|
+
} catch (e) {
|
|
1661
|
+
}
|
|
1662
|
+
}
|
|
1663
|
+
const queryVec = this.vectorize(cleanInput);
|
|
1664
|
+
const memorySimilarity = this._cosineSimilarity(queryVec, this.memoryIntentVec);
|
|
1665
|
+
const ruleSimilarity = this._cosineSimilarity(queryVec, this.ruleIntentVec);
|
|
1666
|
+
const memoryRegex = /hatırlıyor\s*musun|benim\s*favori|nerede|hatırla|kayıt|hasta|durumu|kaydı|geçmiş|bilgi|var\s*mı|söyle|kim|yaşı|şikayeti|tanı|ilaç|doz|kan\s*grubu|risk|gebelik|diyabet|tansiyon|unuttun|hâlâ|güncelle|seviye|ölçüm|ne\s*zaman|değişti|sonuç|nedir|kaydı\s*var/i;
|
|
1667
|
+
const ruleRegex = /çelişki|kural|karşılaştır|doğru\s*mu|yasak|uygun/i;
|
|
1668
|
+
if (memoryRegex.test(cleanInput) || memorySimilarity > 0.18) {
|
|
1669
|
+
const results = this.memory ? this.memory.retrieve(queryVec, 5) : [];
|
|
1670
|
+
console.log(`[Router DBG] Memory triggered. Query: "${cleanInput}". Results count: ${results.length}`);
|
|
1671
|
+
if (results.length > 0) {
|
|
1672
|
+
console.log(`[Router DBG] Candidate list:`);
|
|
1673
|
+
results.forEach((res, i) => {
|
|
1674
|
+
const sSem = this._cosineSimilarity(queryVec, res.record.representation);
|
|
1675
|
+
console.log(` #${i}: "${res.record.content}" | score: ${res.score.toFixed(4)} | sSem: ${sSem.toFixed(4)} | status: ${res.record.status}`);
|
|
1676
|
+
});
|
|
1677
|
+
let conflictedResult = null;
|
|
1678
|
+
for (const res of results) {
|
|
1679
|
+
const sim = this._cosineSimilarity(queryVec, res.record.representation);
|
|
1680
|
+
if (sim > 0.15 && (res.record.status === "conflicted" || res.record.contradictionIds.length > 0)) {
|
|
1681
|
+
conflictedResult = res.record;
|
|
1682
|
+
break;
|
|
1683
|
+
}
|
|
1684
|
+
}
|
|
1685
|
+
if (conflictedResult) {
|
|
1686
|
+
const conflictRecords = [conflictedResult];
|
|
1687
|
+
for (const cId of conflictedResult.contradictionIds) {
|
|
1688
|
+
const cRec = this.memory.records.get(cId);
|
|
1689
|
+
if (cRec) conflictRecords.push(cRec);
|
|
1690
|
+
}
|
|
1691
|
+
const conflictSummary = conflictRecords.map((r) => r.content).join(" | ");
|
|
1692
|
+
console.log(`[Router DBG] Contradiction detected!`);
|
|
1693
|
+
return {
|
|
1694
|
+
input: cleanInput,
|
|
1695
|
+
route: "memory",
|
|
1696
|
+
llmBypassed: true,
|
|
1697
|
+
output: `\xC7eli\u015Fen kay\u0131tlar tespit edildi: ${conflictSummary}. L\xFCtfen do\u011Fru olan\u0131 belirtin.`,
|
|
1698
|
+
conflict: {
|
|
1699
|
+
detected: true,
|
|
1700
|
+
records: conflictRecords.map((r) => ({ id: r.id, content: r.content, confidence: this.memory.getDecayedConfidence(r) })),
|
|
1701
|
+
message: "Bu kay\u0131tta \xE7eli\u015Fen bilgi var. L\xFCtfen do\u011Fru olan\u0131 belirtin."
|
|
1702
|
+
},
|
|
1703
|
+
results: results.slice(0, 3),
|
|
1704
|
+
reason: "Contradiction detected in memory"
|
|
1705
|
+
};
|
|
1706
|
+
}
|
|
1707
|
+
const candidate = {
|
|
1708
|
+
input: cleanInput,
|
|
1709
|
+
route: "memory",
|
|
1710
|
+
llmBypassed: true,
|
|
1711
|
+
output: results[0].record.content,
|
|
1712
|
+
results: [results[0]],
|
|
1713
|
+
reason: "Semantic memory query candidate"
|
|
1714
|
+
};
|
|
1715
|
+
const isValid = this.validateAllAxes(candidate);
|
|
1716
|
+
console.log(`[Router DBG] Candidate isValid: ${isValid}`);
|
|
1717
|
+
if (!isValid) {
|
|
1718
|
+
for (let axis = 1; axis <= 8; axis++) {
|
|
1719
|
+
console.log(` Axis ${axis}: ${this.validateAxis(candidate, axis)}`);
|
|
1720
|
+
}
|
|
1721
|
+
}
|
|
1722
|
+
if (isValid) {
|
|
1723
|
+
return candidate;
|
|
1724
|
+
} else {
|
|
1725
|
+
for (let i = 1; i < results.length; i++) {
|
|
1726
|
+
const nextCandidate = {
|
|
1727
|
+
input: cleanInput,
|
|
1728
|
+
route: "memory",
|
|
1729
|
+
llmBypassed: true,
|
|
1730
|
+
output: results[i].record.content,
|
|
1731
|
+
results: [results[i]],
|
|
1732
|
+
reason: "Replan candidate"
|
|
1733
|
+
};
|
|
1734
|
+
if (this.validateAllAxes(nextCandidate)) {
|
|
1735
|
+
console.log(`[Router DBG] Replan candidate ${i} is valid.`);
|
|
1736
|
+
return nextCandidate;
|
|
1737
|
+
}
|
|
1738
|
+
}
|
|
1739
|
+
return {
|
|
1740
|
+
input: cleanInput,
|
|
1741
|
+
route: "memory",
|
|
1742
|
+
llmBypassed: true,
|
|
1743
|
+
output: "Bu bilgi haf\u0131zada bulunamad\u0131. Hen\xFCz kay\u0131t edilmemi\u015F olabilir.",
|
|
1744
|
+
results: [],
|
|
1745
|
+
reason: "Memory candidates failed validation (low similarity)"
|
|
1746
|
+
};
|
|
1747
|
+
}
|
|
1748
|
+
} else {
|
|
1749
|
+
return {
|
|
1750
|
+
input: cleanInput,
|
|
1751
|
+
route: "memory",
|
|
1752
|
+
llmBypassed: true,
|
|
1753
|
+
output: "Bu bilgi haf\u0131zada bulunamad\u0131. Hen\xFCz kay\u0131t edilmemi\u015F olabilir.",
|
|
1754
|
+
results: [],
|
|
1755
|
+
reason: "Memory triggered but empty"
|
|
1756
|
+
};
|
|
1757
|
+
}
|
|
1758
|
+
}
|
|
1759
|
+
if (ruleRegex.test(cleanInput) || ruleSimilarity > 0.28) {
|
|
1760
|
+
return {
|
|
1761
|
+
route: "rules",
|
|
1762
|
+
llmBypassed: true,
|
|
1763
|
+
output: "Kural de\u011Ferlendirmesi bilgi graf\u0131 / kural katman\u0131na aktar\u0131ld\u0131.",
|
|
1764
|
+
reason: `Rule structure detected (Match Sim: ${ruleSimilarity.toFixed(4)})`
|
|
1765
|
+
};
|
|
1766
|
+
}
|
|
1767
|
+
const mathSimilarity = this._cosineSimilarity(queryVec, this.mathIntentVec);
|
|
1768
|
+
const allSimilarities = [
|
|
1769
|
+
mathSimilarity,
|
|
1770
|
+
memorySimilarity,
|
|
1771
|
+
ruleSimilarity
|
|
1772
|
+
];
|
|
1773
|
+
const maxSimilarity = Math.max(...allSimilarities);
|
|
1774
|
+
if (maxSimilarity < 0.12) {
|
|
1775
|
+
return {
|
|
1776
|
+
input: cleanInput,
|
|
1777
|
+
route: "boundary",
|
|
1778
|
+
output: "Bu konuda bilgim yok. Ba\u015Fka bir konuda yard\u0131mc\u0131 olabilir miyim?",
|
|
1779
|
+
llmBypassed: true,
|
|
1780
|
+
confidence: maxSimilarity,
|
|
1781
|
+
reason: `Capability boundary \u2014 no intent matched (max similarity: ${maxSimilarity.toFixed(4)})`
|
|
1782
|
+
};
|
|
1783
|
+
}
|
|
1784
|
+
let outputText = "";
|
|
1785
|
+
let sdkResult = null;
|
|
1786
|
+
if (this.sdk && typeof this.sdk.generate === "function") {
|
|
1787
|
+
sdkResult = this.sdk.generate(cleanInput, {
|
|
1788
|
+
temperature: options.temperature !== void 0 ? options.temperature : 0,
|
|
1789
|
+
maxLength: options.maxLength !== void 0 ? options.maxLength : this.sdk.maxLength
|
|
1790
|
+
});
|
|
1791
|
+
outputText = sdkResult.generatedText;
|
|
1792
|
+
} else {
|
|
1793
|
+
outputText = `[SLM Fallback] ${cleanInput}`;
|
|
1794
|
+
}
|
|
1795
|
+
const candidateGenResult = {
|
|
1796
|
+
input: cleanInput,
|
|
1797
|
+
route: "llm",
|
|
1798
|
+
llmBypassed: false,
|
|
1799
|
+
output: outputText,
|
|
1800
|
+
sdkResult,
|
|
1801
|
+
reason: "Generative language synthesis required"
|
|
1802
|
+
};
|
|
1803
|
+
if (this.validateAllAxes(candidateGenResult)) {
|
|
1804
|
+
return candidateGenResult;
|
|
1805
|
+
}
|
|
1806
|
+
candidateGenResult.output = `${outputText}.`;
|
|
1807
|
+
return candidateGenResult;
|
|
1808
|
+
}
|
|
1809
|
+
_cosineSimilarity(a, b) {
|
|
1810
|
+
let sum = 0;
|
|
1811
|
+
const D = a.length;
|
|
1812
|
+
for (let i = 0; i < D; i++) {
|
|
1813
|
+
sum += Math.cos(a[i] - b[i]);
|
|
1814
|
+
}
|
|
1815
|
+
return sum / D;
|
|
1816
|
+
}
|
|
1817
|
+
};
|
|
1818
|
+
|
|
1819
|
+
// core/sovereign_agent.js
|
|
1820
|
+
var SovereignAgent = class {
|
|
1821
|
+
/**
|
|
1822
|
+
* @param {Object} sdkInstance - The ResonanceSDK instance containing hdc, memory, router, morphology
|
|
1823
|
+
*/
|
|
1824
|
+
constructor(sdkInstance) {
|
|
1825
|
+
this.sdk = sdkInstance;
|
|
1826
|
+
this.memory = sdkInstance ? sdkInstance.memory : null;
|
|
1827
|
+
this.morphology = sdkInstance ? sdkInstance.morphology : null;
|
|
1828
|
+
this.router = sdkInstance ? sdkInstance.router : null;
|
|
1829
|
+
this.tools = {
|
|
1830
|
+
memory_lookup: (query) => {
|
|
1831
|
+
if (!this.memory) return "Hata: Bellek motoru y\xFCkl\xFC de\u011Fil.";
|
|
1832
|
+
const vec = this.router ? this.router.vectorize(query) : new Float32Array(1024);
|
|
1833
|
+
const results = this.memory.retrieve(vec, 1);
|
|
1834
|
+
if (results.length === 0) return "Bulunamad\u0131.";
|
|
1835
|
+
return results[0].record.content;
|
|
1836
|
+
},
|
|
1837
|
+
math_eval: (expr) => {
|
|
1838
|
+
try {
|
|
1839
|
+
return evaluateMath(expr).toString();
|
|
1840
|
+
} catch (e) {
|
|
1841
|
+
return `Hata: Matematiksel hesaplama ba\u015Far\u0131s\u0131z. ${e.message}`;
|
|
1842
|
+
}
|
|
1843
|
+
},
|
|
1844
|
+
morphology_analyze: (word) => {
|
|
1845
|
+
if (!this.morphology) return "Hata: Morfoloji motoru y\xFCkl\xFC de\u011Fil.";
|
|
1846
|
+
const analysis = this.morphology.analyze(word);
|
|
1847
|
+
return JSON.stringify({
|
|
1848
|
+
root: analysis.root,
|
|
1849
|
+
suffixes: analysis.suffixes,
|
|
1850
|
+
harmony: analysis.harmony,
|
|
1851
|
+
syllables: analysis.syllables
|
|
1852
|
+
});
|
|
1853
|
+
},
|
|
1854
|
+
spectral_transform: (text) => {
|
|
1855
|
+
if (!this.sdk || !this.sdk.spectral) return "Hata: Spektral motor y\xFCkl\xFC de\u011Fil.";
|
|
1856
|
+
const vec = this.router ? this.router.vectorize(text) : new Float32Array(1024);
|
|
1857
|
+
const spec = this.sdk.spectral.spectralTransform({ type: "real", values: vec, D: vec.length });
|
|
1858
|
+
return `Energy: ${spec.magnitude.reduce((a, b) => a + b, 0).toFixed(2)}`;
|
|
1859
|
+
},
|
|
1860
|
+
system_time: () => {
|
|
1861
|
+
return (/* @__PURE__ */ new Date()).toISOString();
|
|
1862
|
+
}
|
|
1863
|
+
};
|
|
1864
|
+
}
|
|
1865
|
+
/**
|
|
1866
|
+
* Run the ReAct autonomous execution loop
|
|
1867
|
+
* @param {string} goal - The user prompt/objective
|
|
1868
|
+
* @param {number} [maxSteps=5] - Maximum execution steps
|
|
1869
|
+
* @returns {Promise<Object>} Execution log and final answer
|
|
1870
|
+
*/
|
|
1871
|
+
async execute(goal, maxSteps = 5) {
|
|
1872
|
+
const logs = [];
|
|
1873
|
+
let step = 1;
|
|
1874
|
+
let finished = false;
|
|
1875
|
+
let finalAnswer = "";
|
|
1876
|
+
const lowerGoal = goal.toLowerCase();
|
|
1877
|
+
while (step <= maxSteps && !finished) {
|
|
1878
|
+
let thought = "";
|
|
1879
|
+
let action = "";
|
|
1880
|
+
let actionArg = "";
|
|
1881
|
+
if (lowerGoal.includes("hat\u0131rla") || lowerGoal.includes("haf\u0131za") || lowerGoal.includes("favori")) {
|
|
1882
|
+
if (step === 1) {
|
|
1883
|
+
thought = "Kullan\u0131c\u0131n\u0131n sordu\u011Fu favori veya bellek kayd\u0131n\u0131 bulmak i\xE7in haf\u0131zada arama yapmal\u0131y\u0131m.";
|
|
1884
|
+
action = "memory_lookup";
|
|
1885
|
+
actionArg = lowerGoal.includes("renk") ? "favori renk" : "haf\u0131za sorgusu";
|
|
1886
|
+
} else if (step === 2) {
|
|
1887
|
+
const prevObs = logs[0].observation;
|
|
1888
|
+
thought = `Haf\u0131zadan '${prevObs}' bilgisini ald\u0131m. Bu kelimeyi morfolojik olarak analiz etmeliyim.`;
|
|
1889
|
+
action = "morphology_analyze";
|
|
1890
|
+
actionArg = prevObs.split(/\s+/).pop().replace(/[^a-zçgğıoöşuüâîû]/g, "");
|
|
1891
|
+
} else {
|
|
1892
|
+
const prevObs = logs[1].observation;
|
|
1893
|
+
thought = "Gerekli aramalar\u0131 ve analizleri tamamlad\u0131m. Sonucu kullan\u0131c\u0131ya sunuyorum.";
|
|
1894
|
+
finished = true;
|
|
1895
|
+
finalAnswer = `Otonom ReAct G\xF6revi Ba\u015Far\u0131yla Tamamland\u0131.
|
|
1896
|
+
- Haf\u0131za Kayd\u0131: ${logs[0].observation}
|
|
1897
|
+
- Morfolojik Yap\u0131: ${prevObs}`;
|
|
1898
|
+
}
|
|
1899
|
+
} else if (lowerGoal.includes("hesapla") || /[0-9+\-*/%^]/.test(lowerGoal)) {
|
|
1900
|
+
if (step === 1) {
|
|
1901
|
+
thought = "Matematiksel ifadeyi deterministik parser ile hesaplamal\u0131y\u0131m.";
|
|
1902
|
+
action = "math_eval";
|
|
1903
|
+
const match = goal.match(/[0-9+\-*/%^().\s]+/);
|
|
1904
|
+
actionArg = match ? match[0].trim() : "0";
|
|
1905
|
+
} else if (step === 2) {
|
|
1906
|
+
const val = logs[0].observation;
|
|
1907
|
+
thought = `Hesaplanan '${val}' sonucunun spektral enerji yo\u011Funlu\u011Funu kontrol etmeliyim.`;
|
|
1908
|
+
action = "spectral_transform";
|
|
1909
|
+
actionArg = val;
|
|
1910
|
+
} else {
|
|
1911
|
+
thought = "Hesaplama ve spektral d\xF6n\xFC\u015F\xFCm ad\u0131mlar\u0131 bitti. Sonucu d\xF6n\xFCyorum.";
|
|
1912
|
+
finished = true;
|
|
1913
|
+
finalAnswer = `Hesaplama Sonucu: ${logs[0].observation} | Spektral Temsiliyet: ${logs[1].observation}`;
|
|
1914
|
+
}
|
|
1915
|
+
} else {
|
|
1916
|
+
if (step === 1) {
|
|
1917
|
+
thought = "Sistem saatini alarak g\xFCncel zaman\u0131 kontrol etmeliyim.";
|
|
1918
|
+
action = "system_time";
|
|
1919
|
+
actionArg = "";
|
|
1920
|
+
} else {
|
|
1921
|
+
thought = "Varsay\u0131lan otonom ak\u0131\u015F tamamland\u0131.";
|
|
1922
|
+
finished = true;
|
|
1923
|
+
finalAnswer = `Mevcut Zaman Dilimi: ${logs[0].observation}`;
|
|
1924
|
+
}
|
|
1925
|
+
}
|
|
1926
|
+
if (!finished) {
|
|
1927
|
+
let observation = "";
|
|
1928
|
+
const toolFn = this.tools[action];
|
|
1929
|
+
if (toolFn) {
|
|
1930
|
+
observation = toolFn(actionArg);
|
|
1931
|
+
} else {
|
|
1932
|
+
observation = `Hata: '${action}' arac\u0131 tan\u0131ml\u0131 de\u011Fil.`;
|
|
1933
|
+
}
|
|
1934
|
+
logs.push({
|
|
1935
|
+
step,
|
|
1936
|
+
thought,
|
|
1937
|
+
action,
|
|
1938
|
+
argument: actionArg,
|
|
1939
|
+
observation
|
|
1940
|
+
});
|
|
1941
|
+
step++;
|
|
1942
|
+
} else {
|
|
1943
|
+
logs.push({
|
|
1944
|
+
step,
|
|
1945
|
+
thought,
|
|
1946
|
+
action: "final_answer",
|
|
1947
|
+
argument: "",
|
|
1948
|
+
observation: finalAnswer
|
|
1949
|
+
});
|
|
1950
|
+
}
|
|
1951
|
+
}
|
|
1952
|
+
return {
|
|
1953
|
+
goal,
|
|
1954
|
+
stepsRun: step - 1,
|
|
1955
|
+
logs,
|
|
1956
|
+
finalAnswer
|
|
1957
|
+
};
|
|
1958
|
+
}
|
|
1959
|
+
};
|
|
1960
|
+
|
|
1961
|
+
// sdk/resonance_sdk.js
|
|
1962
|
+
function generateDerivations(root, morphology) {
|
|
1963
|
+
const harmony = morphology.determineVowelHarmony(root);
|
|
1964
|
+
const lastChar = root[root.length - 1];
|
|
1965
|
+
const isVowel = morphology.allVowels.has(lastChar);
|
|
1966
|
+
const derivations = [root];
|
|
1967
|
+
const hardConsonants = /* @__PURE__ */ new Set(["t", "k", "\xE7", "p", "s", "\u015F", "h", "f"]);
|
|
1968
|
+
const isHard = hardConsonants.has(lastChar);
|
|
1969
|
+
const mutateRoot = (r, suffix) => {
|
|
1970
|
+
if (!suffix) return r;
|
|
1971
|
+
const startsWithVowel = morphology.allVowels.has(suffix[0]);
|
|
1972
|
+
if (startsWithVowel) {
|
|
1973
|
+
const last = r[r.length - 1];
|
|
1974
|
+
let mutated = r.slice(0, -1);
|
|
1975
|
+
if (last === "p") return mutated + "b" + suffix;
|
|
1976
|
+
if (last === "\xE7") return mutated + "c" + suffix;
|
|
1977
|
+
if (last === "t") return mutated + "d" + suffix;
|
|
1978
|
+
if (last === "k") {
|
|
1979
|
+
if (r === "renk") return mutated + "g" + suffix;
|
|
1980
|
+
return mutated + "\u011F" + suffix;
|
|
1981
|
+
}
|
|
1982
|
+
}
|
|
1983
|
+
return r + suffix;
|
|
1984
|
+
};
|
|
1985
|
+
if (harmony === "front") {
|
|
1986
|
+
derivations.push(root + "ler");
|
|
1987
|
+
derivations.push(isVowel ? root + "nin" : mutateRoot(root, "in"));
|
|
1988
|
+
derivations.push(isVowel ? root + "ye" : mutateRoot(root, "e"));
|
|
1989
|
+
derivations.push(isVowel ? root + "yi" : mutateRoot(root, "i"));
|
|
1990
|
+
derivations.push(root + (isHard ? "te" : "de"));
|
|
1991
|
+
derivations.push(root + (isHard ? "ten" : "den"));
|
|
1992
|
+
derivations.push(isVowel ? root + "m" : mutateRoot(root, "im"));
|
|
1993
|
+
} else {
|
|
1994
|
+
derivations.push(root + "lar");
|
|
1995
|
+
derivations.push(isVowel ? root + "n\u0131n" : mutateRoot(root, "\u0131n"));
|
|
1996
|
+
derivations.push(isVowel ? root + "ya" : mutateRoot(root, "a"));
|
|
1997
|
+
derivations.push(isVowel ? root + "y\u0131" : mutateRoot(root, "\u0131"));
|
|
1998
|
+
derivations.push(root + (isHard ? "ta" : "da"));
|
|
1999
|
+
derivations.push(root + (isHard ? "tan" : "dan"));
|
|
2000
|
+
derivations.push(isVowel ? root + "m" : mutateRoot(root, "\u0131m"));
|
|
2001
|
+
}
|
|
2002
|
+
return derivations;
|
|
2003
|
+
}
|
|
2004
|
+
var ResonanceSDK = class {
|
|
2005
|
+
/**
|
|
2006
|
+
* @param {Object} config - SDK configuration
|
|
2007
|
+
* @param {number} [config.D=4096] - Hyperdimensional vector dimension
|
|
2008
|
+
* @param {number} [config.temperature=0.7] - Default sampling temperature
|
|
2009
|
+
* @param {number} [config.maxLength=10] - Default max generation length
|
|
2010
|
+
*/
|
|
2011
|
+
constructor(config = {}) {
|
|
2012
|
+
this.D = config.D || 4096;
|
|
2013
|
+
this.hdc = new HDCEngine(this.D);
|
|
2014
|
+
this.morphology = new TurkishMorphology();
|
|
2015
|
+
this.spectral = new SpectralEngine();
|
|
2016
|
+
this.memory = new MemoryEngine(config.memory || {});
|
|
2017
|
+
this.router = new ReasoningRouter(this.memory, this);
|
|
2018
|
+
this.temperature = config.temperature !== void 0 ? config.temperature : 0.7;
|
|
2019
|
+
this.maxLength = config.maxLength || 10;
|
|
2020
|
+
this.vocab = [];
|
|
2021
|
+
this.vocabMap = /* @__PURE__ */ new Map();
|
|
2022
|
+
this.embeddings = /* @__PURE__ */ new Map();
|
|
2023
|
+
this.wordCounts = /* @__PURE__ */ new Map();
|
|
2024
|
+
this.freqIndices = [];
|
|
2025
|
+
this.wordDerivationIndices = /* @__PURE__ */ new Map();
|
|
2026
|
+
this.transitionCounts = /* @__PURE__ */ new Map();
|
|
2027
|
+
this.sparseWeightsSpec = null;
|
|
2028
|
+
this.wasmInstance = null;
|
|
2029
|
+
this.wasmMemory = null;
|
|
2030
|
+
this.vocabCosPtr = 0;
|
|
2031
|
+
this.vocabSinPtr = 0;
|
|
2032
|
+
this.scoresPtr = 0;
|
|
2033
|
+
this.candidateIndicesPtr = 0;
|
|
2034
|
+
this._initialized = false;
|
|
2035
|
+
this._runtime = typeof window !== "undefined" ? "browser" : "node";
|
|
2036
|
+
}
|
|
2037
|
+
// ── PUBLIC API ──────────────────────────────────────────────
|
|
2038
|
+
/**
|
|
2039
|
+
* Initialize the SDK. Must be called before generate() or analyze().
|
|
2040
|
+
* @param {Object} [options]
|
|
2041
|
+
* @param {ArrayBuffer} [options.wasmBinary] - Pre-loaded WASM binary buffer
|
|
2042
|
+
* @param {string} [options.wasmUrl] - URL to fetch WASM (browser mode)
|
|
2043
|
+
* @param {string} [options.wasmPath] - File path to WASM (Node.js mode)
|
|
2044
|
+
* @param {string} [options.corpusUrl] - URL to tr_corpus_embed.js (browser mode)
|
|
2045
|
+
* @param {string} [options.corpusPath] - File path to tr_corpus_embed.js (Node.js mode)
|
|
2046
|
+
*/
|
|
2047
|
+
async init(options = {}) {
|
|
2048
|
+
if (this._initialized) return;
|
|
2049
|
+
await this._loadWasm(options);
|
|
2050
|
+
await this._buildVocabulary(options);
|
|
2051
|
+
this._initialized = true;
|
|
2052
|
+
}
|
|
2053
|
+
/**
|
|
2054
|
+
* Generate text autoregressively from a prompt.
|
|
2055
|
+
* @param {string} prompt - Input Turkish text prompt
|
|
2056
|
+
* @param {Object} [options]
|
|
2057
|
+
* @param {number} [options.maxLength] - Override default max tokens
|
|
2058
|
+
* @param {number} [options.temperature] - Override default temperature
|
|
2059
|
+
* @param {function} [options.onToken] - Streaming callback: (word, step) => void
|
|
2060
|
+
* @returns {Object} { prompt, generatedText, newTokens, steps, totalLatencyMs, finishReason, vocabSize }
|
|
2061
|
+
*/
|
|
2062
|
+
generate(prompt, options = {}) {
|
|
2063
|
+
this._assertInit();
|
|
2064
|
+
const maxLen = options.maxLength || this.maxLength;
|
|
2065
|
+
const temp = options.temperature !== void 0 ? options.temperature : this.temperature;
|
|
2066
|
+
const onToken = options.onToken || null;
|
|
2067
|
+
const cleanPrompt = this.morphology.normalize(prompt);
|
|
2068
|
+
const tokens = cleanPrompt.split(/\s+/).filter(Boolean);
|
|
2069
|
+
if (tokens.length === 0) tokens.push("ev");
|
|
2070
|
+
const promptLength = tokens.length;
|
|
2071
|
+
const steps = [];
|
|
2072
|
+
let stopReason = "length";
|
|
2073
|
+
const startTime = performance.now();
|
|
2074
|
+
for (let step = 0; step < maxLen; step++) {
|
|
2075
|
+
const stepStart = performance.now();
|
|
2076
|
+
const nextObj = this._predictNext(tokens, temp, promptLength);
|
|
2077
|
+
const stepEnd = performance.now();
|
|
2078
|
+
tokens.push(nextObj.word);
|
|
2079
|
+
const stepInfo = { word: nextObj.word, score: nextObj.score, latencyMs: stepEnd - stepStart };
|
|
2080
|
+
steps.push(stepInfo);
|
|
2081
|
+
if (onToken) onToken(nextObj.word, stepInfo);
|
|
2082
|
+
if (this._isTerminal(nextObj.word)) {
|
|
2083
|
+
stopReason = "stop";
|
|
2084
|
+
break;
|
|
2085
|
+
}
|
|
2086
|
+
if (tokens.length > promptLength + 2 && tokens.slice(-3).every((v) => v === tokens[tokens.length - 1])) {
|
|
2087
|
+
stopReason = "stop";
|
|
2088
|
+
break;
|
|
2089
|
+
}
|
|
2090
|
+
}
|
|
2091
|
+
return {
|
|
2092
|
+
prompt,
|
|
2093
|
+
generatedText: tokens.join(" "),
|
|
2094
|
+
newTokens: tokens.slice(promptLength),
|
|
2095
|
+
steps,
|
|
2096
|
+
totalLatencyMs: performance.now() - startTime,
|
|
2097
|
+
finishReason: stopReason,
|
|
2098
|
+
vocabSize: this.vocab.length
|
|
2099
|
+
};
|
|
2100
|
+
}
|
|
2101
|
+
/**
|
|
2102
|
+
* Analyze Turkish word morphology.
|
|
2103
|
+
* @param {string} word - Turkish word to analyze
|
|
2104
|
+
* @returns {Object} { word, root, suffixes, morphemes, harmony, syllables }
|
|
2105
|
+
*/
|
|
2106
|
+
analyze(word) {
|
|
2107
|
+
return this.morphology.analyze(word);
|
|
2108
|
+
}
|
|
2109
|
+
/**
|
|
2110
|
+
* Get SDK runtime metrics.
|
|
2111
|
+
* @returns {Object} { runtime, vocabSize, dimension, wasmActive, initialized }
|
|
2112
|
+
*/
|
|
2113
|
+
getMetrics() {
|
|
2114
|
+
return {
|
|
2115
|
+
runtime: this._runtime,
|
|
2116
|
+
vocabSize: this.vocab.length,
|
|
2117
|
+
dimension: this.D,
|
|
2118
|
+
wasmActive: this.wasmInstance !== null,
|
|
2119
|
+
initialized: this._initialized
|
|
2120
|
+
};
|
|
2121
|
+
}
|
|
2122
|
+
/**
|
|
2123
|
+
* Instantiate an autonomous SovereignAgent.
|
|
2124
|
+
* @returns {SovereignAgent}
|
|
2125
|
+
*/
|
|
2126
|
+
createAgent() {
|
|
2127
|
+
return new SovereignAgent(this);
|
|
2128
|
+
}
|
|
2129
|
+
// ── PRIVATE: WASM LOADER ───────────────────────────────────
|
|
2130
|
+
async _loadWasm(options) {
|
|
2131
|
+
const imports = { env: { cosf: Math.cos, sinf: Math.sin, atan2f: Math.atan2, expf: Math.exp, sqrtf: Math.sqrt } };
|
|
2132
|
+
try {
|
|
2133
|
+
if (options.wasmBinary) {
|
|
2134
|
+
const mod = new WebAssembly.Module(options.wasmBinary);
|
|
2135
|
+
this.wasmInstance = new WebAssembly.Instance(mod, imports);
|
|
2136
|
+
this.wasmMemory = this.wasmInstance.exports.memory;
|
|
2137
|
+
} else if (this._runtime === "browser") {
|
|
2138
|
+
const url = options.wasmUrl || "../wasm/spectral_core.wasm";
|
|
2139
|
+
const res = await fetch(url);
|
|
2140
|
+
const buf = await res.arrayBuffer();
|
|
2141
|
+
const mod = new WebAssembly.Module(buf);
|
|
2142
|
+
this.wasmInstance = new WebAssembly.Instance(mod, imports);
|
|
2143
|
+
this.wasmMemory = this.wasmInstance.exports.memory;
|
|
2144
|
+
} else {
|
|
2145
|
+
const fs2 = await import("fs");
|
|
2146
|
+
const path = await import("path");
|
|
2147
|
+
const { fileURLToPath } = await import("url");
|
|
2148
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
2149
|
+
const wasmPath = options.wasmPath || path.join(__dirname, "..", "wasm", "spectral_core.wasm");
|
|
2150
|
+
if (fs2.existsSync(wasmPath)) {
|
|
2151
|
+
const buf = fs2.readFileSync(wasmPath);
|
|
2152
|
+
const mod = new WebAssembly.Module(buf);
|
|
2153
|
+
this.wasmInstance = new WebAssembly.Instance(mod, imports);
|
|
2154
|
+
this.wasmMemory = this.wasmInstance.exports.memory;
|
|
2155
|
+
}
|
|
2156
|
+
}
|
|
2157
|
+
} catch (e) {
|
|
2158
|
+
console.warn("ResonanceSDK: WASM load failed, Pure JS fallback active.", e.message);
|
|
2159
|
+
}
|
|
2160
|
+
}
|
|
2161
|
+
// ── PRIVATE: VOCABULARY BUILDER ────────────────────────────
|
|
2162
|
+
async _buildVocabulary(options) {
|
|
2163
|
+
const corpus = [
|
|
2164
|
+
// ── Orijinal genel corpus ──
|
|
2165
|
+
"evimizden yeni \xE7\u0131kt\u0131k",
|
|
2166
|
+
"yeni bir kitap ald\u0131m",
|
|
2167
|
+
"bilimsel ara\u015Ft\u0131rmalar yapay zeka ile h\u0131zland\u0131",
|
|
2168
|
+
"g\xFCzel bir g\xFCn ba\u015Flad\u0131",
|
|
2169
|
+
"iyi bir insan olmak \xF6nemlidir",
|
|
2170
|
+
"t\xFCrk\xE7e dil yap\u0131s\u0131 \xE7ok zengindir",
|
|
2171
|
+
"yapay zeka insan beyni gibi \xE7al\u0131\u015F\u0131r",
|
|
2172
|
+
"\xF6\u011Frenmek ve d\xFC\u015F\xFCnmek zihni geli\u015Ftirir",
|
|
2173
|
+
"b\xFCy\xFCk bir ad\u0131m att\u0131k",
|
|
2174
|
+
"yeni projeler \xFCzerinde \xE7al\u0131\u015F\u0131yoruz",
|
|
2175
|
+
"okuma al\u0131\u015Fkanl\u0131\u011F\u0131 kazanmak \xF6nemlidir",
|
|
2176
|
+
"bilim ve teknik d\xFCnyay\u0131 de\u011Fi\u015Ftiriyor",
|
|
2177
|
+
"evimizden okula kadar y\xFCr\xFCd\xFCk",
|
|
2178
|
+
"yapay zeka dil modelleri \xFCzerine kuruludur",
|
|
2179
|
+
"yeni bir d\xFCnya bizi bekliyor",
|
|
2180
|
+
"kitaplar en iyi arkada\u015Ft\u0131r",
|
|
2181
|
+
"g\xFCzel bir gelecek in\u015Fa ediyoruz",
|
|
2182
|
+
"iyi bir e\u011Fitim almak \xF6nemlidir",
|
|
2183
|
+
"t\xFCrk\xE7e konu\u015Fmak ve yazmak \xE7ok g\xFCzel",
|
|
2184
|
+
"bilimsel ger\xE7ekler her zaman kazan\u0131r",
|
|
2185
|
+
"yapay sinir a\u011Flar\u0131 karma\u015F\u0131k modellerdir",
|
|
2186
|
+
"beyin ve zihin ara\u015Ft\u0131rmalar\u0131 s\xFCr\xFCyor",
|
|
2187
|
+
"evimizden yeni bir yola \xE7\u0131kt\u0131k",
|
|
2188
|
+
"yeni bir ba\u015Flang\u0131\xE7 yapmak iyidir",
|
|
2189
|
+
"bilimsel okuma yapmak zihni a\xE7ar",
|
|
2190
|
+
"okuma yapmak insan\u0131 geli\u015Ftirir",
|
|
2191
|
+
"evimizden \xE7\u0131kt\u0131k ve okula gittik",
|
|
2192
|
+
"yeni bir g\xFCne uyand\u0131k",
|
|
2193
|
+
"bilim insanlar\u0131 yapay zeka geli\u015Ftiriyor",
|
|
2194
|
+
"t\xFCrk\xE7e dil bilgisi kurallar\u0131 \xF6nemlidir",
|
|
2195
|
+
"evimizden okula gittik yeni bir kitap ald\u0131k",
|
|
2196
|
+
"televizyonu a\xE7\u0131p haberleri izledik",
|
|
2197
|
+
"arabaya binip okula gittik",
|
|
2198
|
+
"bilgisayar\u0131 kapat\u0131p uyudum",
|
|
2199
|
+
"bilgisayar\u0131 kapat\u0131p yatt\u0131m",
|
|
2200
|
+
"yaz\u0131l\u0131m m\xFChendisleri yapay zeka modelleri \xFCzerine ara\u015Ft\u0131rma yap\u0131yor",
|
|
2201
|
+
"bilgi teknolojileri ve veri analizi i\u015F s\xFCre\xE7lerini kolayla\u015Ft\u0131r\u0131r",
|
|
2202
|
+
"sa\u011Fl\u0131kl\u0131 beslenme ve spor yapmak ya\u015Fam kalitesini art\u0131r\u0131r",
|
|
2203
|
+
"do\u011Fal ya\u015Fam\u0131 ve \xE7evreyi korumak hepimizin sorumlulu\u011Fundad\u0131r",
|
|
2204
|
+
"sanat ve edebiyat toplumun k\xFClt\xFCrel zenginli\u011Fini besler ve geli\u015Ftirir",
|
|
2205
|
+
"e\u011Fitim sistemi yeni nesillerin gelece\u011Fini ve ba\u015Far\u0131s\u0131n\u0131 belirler",
|
|
2206
|
+
"bilgisayar a\u011Flar\u0131 veri g\xFCvenli\u011Fi ve h\u0131zl\u0131 bilgi ak\u0131\u015F\u0131 sa\u011Flar",
|
|
2207
|
+
// ── Selamlama ve bağlam kurma ──
|
|
2208
|
+
"merhaba size nas\u0131l yard\u0131mc\u0131 olabilirim",
|
|
2209
|
+
"g\xFCnayd\u0131n bug\xFCn size nas\u0131l yard\u0131mc\u0131 olay\u0131m",
|
|
2210
|
+
"iyi g\xFCnler l\xFCtfen sorunuzu belirtin",
|
|
2211
|
+
"ho\u015F geldiniz nas\u0131l yard\u0131mc\u0131 olabilirim",
|
|
2212
|
+
"merhaba buyurun nas\u0131l yard\u0131mc\u0131 olay\u0131m",
|
|
2213
|
+
"iyi ak\u015Famlar size nas\u0131l yard\u0131mc\u0131 olabilirim",
|
|
2214
|
+
// ── Hasta kaydı kalıpları ──
|
|
2215
|
+
"hasta kayd\u0131 olu\u015Fturuldu",
|
|
2216
|
+
"kay\u0131t sisteme ba\u015Far\u0131yla eklendi",
|
|
2217
|
+
"hastan\u0131n bilgileri g\xFCncellendi",
|
|
2218
|
+
"bu hasta daha \xF6nce kay\u0131t edilmemi\u015F",
|
|
2219
|
+
"hastan\u0131n ad\u0131 ve ya\u015F\u0131 kaydedildi",
|
|
2220
|
+
"hasta bilgileri sisteme girildi",
|
|
2221
|
+
"yeni hasta kayd\u0131 a\xE7\u0131ld\u0131",
|
|
2222
|
+
"hasta \u015Fikayeti sisteme i\u015Flendi",
|
|
2223
|
+
"kay\u0131t ba\u015Far\u0131yla g\xFCncellendi",
|
|
2224
|
+
"hastan\u0131n ge\xE7mi\u015F kay\u0131tlar\u0131 bulundu",
|
|
2225
|
+
"bu hasta i\xE7in kay\u0131t bulunamad\u0131",
|
|
2226
|
+
"hastan\u0131n durumu kaydedildi",
|
|
2227
|
+
// ── Belirsizlik ve yönlendirme ──
|
|
2228
|
+
"bu soruyu yan\u0131tlayacak bilgiye sahip de\u011Filim",
|
|
2229
|
+
"bu konuda bilgim yok ba\u015Fka bir soru sorabilirsiniz",
|
|
2230
|
+
"l\xFCtfen daha fazla bilgi verir misiniz",
|
|
2231
|
+
"hangi hastay\u0131 soruyorsunuz",
|
|
2232
|
+
"bu bilgi haf\u0131zada bulunamad\u0131",
|
|
2233
|
+
"hen\xFCz bu konuda kay\u0131t yok",
|
|
2234
|
+
"bu i\u015Flemi yapabilmem i\xE7in daha fazla bilgiye ihtiyac\u0131m var",
|
|
2235
|
+
"maalesef bu konuda yard\u0131mc\u0131 olam\u0131yorum",
|
|
2236
|
+
// ── Sağlık domain kalıpları ──
|
|
2237
|
+
"hastan\u0131n \u015Fikayeti ba\u015F a\u011Fr\u0131s\u0131 ve tansiyon y\xFCksekli\u011Fi",
|
|
2238
|
+
"kan bas\u0131nc\u0131 de\u011Feri y\xFCz k\u0131rk b\xF6l\xFC doksan olarak \xF6l\xE7\xFCld\xFC",
|
|
2239
|
+
"ila\xE7 dozu hesapland\u0131 ve re\xE7eteye yaz\u0131ld\u0131",
|
|
2240
|
+
"risk durumu y\xFCksek riskli olarak i\u015Faretlendi",
|
|
2241
|
+
"hastan\u0131n kan \u015Fekeri y\xFCz seksen olarak \xF6l\xE7\xFCld\xFC",
|
|
2242
|
+
"diyabet hastas\u0131 olarak kay\u0131t edildi",
|
|
2243
|
+
"gebelik takibi i\xE7in kontrol randevusu olu\u015Fturuldu",
|
|
2244
|
+
"hastan\u0131n ate\u015Fi otuz sekiz derece \xF6l\xE7\xFCld\xFC",
|
|
2245
|
+
"tansiyon \xF6l\xE7\xFCm\xFC yap\u0131ld\u0131 ve kaydedildi",
|
|
2246
|
+
"ila\xE7lardan hangisinin verilmesi gerekti\u011Fi belirlendi",
|
|
2247
|
+
"doktorlar\u0131m\u0131zdan birini \xE7a\u011F\u0131rabilir misiniz",
|
|
2248
|
+
"hastan\u0131n ayaklar\u0131ndan birinde \u015Fi\u015Flik tespit edildi",
|
|
2249
|
+
"kan grubu belirlenmesi i\xE7in tahlil istendi",
|
|
2250
|
+
"hastaya g\xFCnde \xFC\xE7 kez ila\xE7 verilecek",
|
|
2251
|
+
"haftal\u0131k toplam doz hesapland\u0131",
|
|
2252
|
+
"ameliyat \xF6ncesi haz\u0131rl\u0131klar tamamland\u0131",
|
|
2253
|
+
"hastan\u0131n nabz\u0131 ve tansiyonu normal s\u0131n\u0131rlarda",
|
|
2254
|
+
"tedavi plan\u0131 olu\u015Fturuldu ve hastaya bildirildi",
|
|
2255
|
+
"a\u015F\u0131 takvimi kontrol edildi",
|
|
2256
|
+
"acil m\xFCdahale gerekli de\u011Fil hasta stabil",
|
|
2257
|
+
// ── Çelişki ve doğrulama ──
|
|
2258
|
+
"kay\u0131tlarda \xE7eli\u015Fen bilgi tespit edildi",
|
|
2259
|
+
"l\xFCtfen do\u011Fru bilgiyi belirtin",
|
|
2260
|
+
"iki farkl\u0131 kay\u0131t bulundu hangisi do\u011Fru",
|
|
2261
|
+
"bu bilgi \xF6nceki kay\u0131tla \xE7eli\u015Fiyor",
|
|
2262
|
+
"\xE7eli\u015Fen kay\u0131tlar kullan\u0131c\u0131ya sunuldu",
|
|
2263
|
+
// ── Morfoloji zenginleştirme ──
|
|
2264
|
+
"evlerimizden geliyoruz hasta getirdik",
|
|
2265
|
+
"hastan\u0131n ayaklar\u0131ndan birinde \u015Fi\u015Flik var",
|
|
2266
|
+
"ila\xE7lardan hangisini vermemiz gerekiyor",
|
|
2267
|
+
"doktorlar\u0131m\u0131zdan birini \xE7a\u011F\u0131rabilir misiniz",
|
|
2268
|
+
"bu hastal\u0131klardan kurtulabilir mi",
|
|
2269
|
+
"k\xF6ylerden gelen hastalar muayene edildi",
|
|
2270
|
+
"\xE7ocuklar\u0131n a\u015F\u0131lar\u0131 yap\u0131ld\u0131",
|
|
2271
|
+
"hastalar\u0131n kay\u0131tlar\u0131 g\xFCncellendi"
|
|
2272
|
+
];
|
|
2273
|
+
let initialVocab = [];
|
|
2274
|
+
try {
|
|
2275
|
+
if (this._runtime === "browser") {
|
|
2276
|
+
const url = options.corpusUrl || "../tr_corpus_embed.js";
|
|
2277
|
+
const res = await fetch(url);
|
|
2278
|
+
const txt = await res.text();
|
|
2279
|
+
const m = txt.match(/const TR_CORPUS_ROOTS\s*=\s*(\[[\s\S]*?\]);/);
|
|
2280
|
+
if (m) initialVocab = JSON.parse(m[1]);
|
|
2281
|
+
} else {
|
|
2282
|
+
const fs2 = await import("fs");
|
|
2283
|
+
const path = await import("path");
|
|
2284
|
+
const { fileURLToPath } = await import("url");
|
|
2285
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
2286
|
+
const corpusPath = options.corpusPath || path.join(__dirname, "..", "tr_corpus_embed.js");
|
|
2287
|
+
if (fs2.existsSync(corpusPath)) {
|
|
2288
|
+
const txt = fs2.readFileSync(corpusPath, "utf8");
|
|
2289
|
+
const m = txt.match(/const TR_CORPUS_ROOTS\s*=\s*(\[[\s\S]*?\]);/);
|
|
2290
|
+
if (m) initialVocab = JSON.parse(m[1]);
|
|
2291
|
+
}
|
|
2292
|
+
}
|
|
2293
|
+
} catch (e) {
|
|
2294
|
+
}
|
|
2295
|
+
const turkishRe = /^[a-zçgğıoöşuüâîû]+$/;
|
|
2296
|
+
const words = /* @__PURE__ */ new Set([
|
|
2297
|
+
"ev",
|
|
2298
|
+
"yeni",
|
|
2299
|
+
"bir",
|
|
2300
|
+
"kitap",
|
|
2301
|
+
"okul",
|
|
2302
|
+
"\xE7\u0131kt\u0131k",
|
|
2303
|
+
"ald\u0131m",
|
|
2304
|
+
"g\xFCzel",
|
|
2305
|
+
"iyi",
|
|
2306
|
+
"yapay",
|
|
2307
|
+
"zeka",
|
|
2308
|
+
"bilimsel",
|
|
2309
|
+
"okuma",
|
|
2310
|
+
"\xF6\u011Frenmek",
|
|
2311
|
+
"dil",
|
|
2312
|
+
"t\xFCrk\xE7e",
|
|
2313
|
+
"insan",
|
|
2314
|
+
"olmak",
|
|
2315
|
+
"\xF6nemlidir",
|
|
2316
|
+
"geli\u015Ftirir",
|
|
2317
|
+
"de\u011Fi\u015Ftiriyor",
|
|
2318
|
+
"y\xFCr\xFCd\xFCk",
|
|
2319
|
+
"gittik",
|
|
2320
|
+
"yola",
|
|
2321
|
+
"ba\u015Flang\u0131\xE7",
|
|
2322
|
+
"g\xFCne",
|
|
2323
|
+
"uyand\u0131k",
|
|
2324
|
+
"kuruludur",
|
|
2325
|
+
"televizyonu",
|
|
2326
|
+
"a\xE7\u0131p",
|
|
2327
|
+
"izledik",
|
|
2328
|
+
"izledim",
|
|
2329
|
+
"arabaya",
|
|
2330
|
+
"binip",
|
|
2331
|
+
"bilgisayar\u0131",
|
|
2332
|
+
"kapat\u0131p",
|
|
2333
|
+
"uyudum",
|
|
2334
|
+
"yatt\u0131m"
|
|
2335
|
+
]);
|
|
2336
|
+
this.wordCounts.clear();
|
|
2337
|
+
for (const s of corpus) {
|
|
2338
|
+
for (const w of s.split(/\s+/)) {
|
|
2339
|
+
const c = w.trim().toLowerCase().replace(/[^a-zçgğıoöşuüâîû]/g, "");
|
|
2340
|
+
if (c.length >= 2 && turkishRe.test(c)) {
|
|
2341
|
+
this.wordCounts.set(c, (this.wordCounts.get(c) || 0) + 1);
|
|
2342
|
+
}
|
|
2343
|
+
}
|
|
2344
|
+
}
|
|
2345
|
+
for (const [w, cnt] of this.wordCounts) {
|
|
2346
|
+
if (cnt >= 2) words.add(w);
|
|
2347
|
+
}
|
|
2348
|
+
for (const w of initialVocab) {
|
|
2349
|
+
const c = w.trim().toLowerCase().replace(/[^a-zçgğıoöşuüâîû]/g, "");
|
|
2350
|
+
if (c.length >= 2 && turkishRe.test(c)) {
|
|
2351
|
+
for (const d of generateDerivations(c, this.morphology)) words.add(d);
|
|
2352
|
+
}
|
|
2353
|
+
}
|
|
2354
|
+
this.vocab = ["<unk>", ...Array.from(words)];
|
|
2355
|
+
this.vocabMap.clear();
|
|
2356
|
+
for (let i = 0; i < this.vocab.length; i++) this.vocabMap.set(this.vocab[i], i);
|
|
2357
|
+
this.freqIndices = this.vocab.map((w, idx) => ({ w, idx })).sort((a, b) => (this.wordCounts.get(b.w) || 0) - (this.wordCounts.get(a.w) || 0)).slice(0, 15).map((x) => x.idx);
|
|
2358
|
+
this.wordDerivationIndices.clear();
|
|
2359
|
+
for (const root of this.vocab) {
|
|
2360
|
+
const indices = [];
|
|
2361
|
+
for (const d of generateDerivations(root, this.morphology)) {
|
|
2362
|
+
const idx = this.vocabMap.get(d);
|
|
2363
|
+
if (idx !== void 0) indices.push(idx);
|
|
2364
|
+
}
|
|
2365
|
+
this.wordDerivationIndices.set(root, indices);
|
|
2366
|
+
}
|
|
2367
|
+
for (const word of this.vocab) {
|
|
2368
|
+
const emb = this.hdc.generateSeeded("complex", word);
|
|
2369
|
+
emb.values = new Float32Array(emb.values);
|
|
2370
|
+
const cos = new Float32Array(this.D);
|
|
2371
|
+
const sin = new Float32Array(this.D);
|
|
2372
|
+
for (let i = 0; i < this.D; i++) {
|
|
2373
|
+
cos[i] = Math.cos(emb.values[i]);
|
|
2374
|
+
sin[i] = Math.sin(emb.values[i]);
|
|
2375
|
+
}
|
|
2376
|
+
this.embeddings.set(word, { emb, cosVals: cos, sinVals: sin });
|
|
2377
|
+
}
|
|
2378
|
+
if (this.wasmInstance) {
|
|
2379
|
+
const V = this.vocab.length, DD = this.D;
|
|
2380
|
+
this.vocabCosPtr = this.wasmInstance.exports.malloc(V * DD * 4);
|
|
2381
|
+
this.vocabSinPtr = this.wasmInstance.exports.malloc(V * DD * 4);
|
|
2382
|
+
this.scoresPtr = this.wasmInstance.exports.malloc(V * 4);
|
|
2383
|
+
this.transIndicesPtr = this.wasmInstance.exports.malloc(64 * 4);
|
|
2384
|
+
this.transMultipliersPtr = this.wasmInstance.exports.malloc(64 * 4);
|
|
2385
|
+
this.topIndicesPtr = this.wasmInstance.exports.malloc(5 * 4);
|
|
2386
|
+
this.topScoresPtr = this.wasmInstance.exports.malloc(5 * 4);
|
|
2387
|
+
this.candidateIndicesPtr = this.wasmInstance.exports.malloc(1024 * 4);
|
|
2388
|
+
if (this.vocabCosPtr && this.vocabSinPtr && this.scoresPtr && this.transIndicesPtr && this.transMultipliersPtr && this.topIndicesPtr && this.topScoresPtr && this.candidateIndicesPtr) {
|
|
2389
|
+
const mem = this.wasmMemory.buffer;
|
|
2390
|
+
const cosView = new Float32Array(mem, this.vocabCosPtr, V * DD);
|
|
2391
|
+
const sinView = new Float32Array(mem, this.vocabSinPtr, V * DD);
|
|
2392
|
+
for (let v = 0; v < V; v++) {
|
|
2393
|
+
const data = this.embeddings.get(this.vocab[v]);
|
|
2394
|
+
cosView.set(data.cosVals, v * DD);
|
|
2395
|
+
sinView.set(data.sinVals, v * DD);
|
|
2396
|
+
}
|
|
2397
|
+
} else {
|
|
2398
|
+
console.warn("ResonanceSDK: WASM malloc failed, falling back to Pure JS.");
|
|
2399
|
+
this.wasmInstance = null;
|
|
2400
|
+
}
|
|
2401
|
+
}
|
|
2402
|
+
this.transitionCounts = /* @__PURE__ */ new Map();
|
|
2403
|
+
const re = new Float32Array(this.D), im = new Float32Array(this.D);
|
|
2404
|
+
let tCount = 0;
|
|
2405
|
+
for (const s of corpus) {
|
|
2406
|
+
const ws = s.split(/\s+/).map((w) => w.trim().toLowerCase().replace(/[^a-zçgğıoöşuüâîû]/g, "")).filter((w) => w.length >= 2);
|
|
2407
|
+
for (let i = 0; i < ws.length - 1; i++) {
|
|
2408
|
+
const w1 = ws[i], w2 = ws[i + 1];
|
|
2409
|
+
if (!this.transitionCounts.has(w1)) this.transitionCounts.set(w1, /* @__PURE__ */ new Map());
|
|
2410
|
+
this.transitionCounts.get(w1).set(w2, (this.transitionCounts.get(w1).get(w2) || 0) + 1);
|
|
2411
|
+
const d1 = this.embeddings.get(w1), d2 = this.embeddings.get(w2);
|
|
2412
|
+
if (d1 && d2) {
|
|
2413
|
+
const wt = 1 / Math.sqrt(this.wordCounts.get(w2) || 1);
|
|
2414
|
+
for (let j = 0; j < this.D; j++) {
|
|
2415
|
+
let diff = d2.emb.values[j] - d1.emb.values[j];
|
|
2416
|
+
if (diff < 0) diff += 2 * Math.PI;
|
|
2417
|
+
re[j] += wt * Math.cos(diff % (2 * Math.PI));
|
|
2418
|
+
im[j] += wt * Math.sin(diff % (2 * Math.PI));
|
|
2419
|
+
}
|
|
2420
|
+
tCount++;
|
|
2421
|
+
}
|
|
2422
|
+
}
|
|
2423
|
+
}
|
|
2424
|
+
if (tCount > 0) {
|
|
2425
|
+
const vals = new Float32Array(this.D);
|
|
2426
|
+
for (let j = 0; j < this.D; j++) {
|
|
2427
|
+
let v = Math.atan2(im[j], re[j]);
|
|
2428
|
+
if (v < 0) v += 2 * Math.PI;
|
|
2429
|
+
vals[j] = v;
|
|
2430
|
+
}
|
|
2431
|
+
this.sparseWeightsSpec = new Representation("complex", vals, this.D);
|
|
2432
|
+
} else {
|
|
2433
|
+
this.sparseWeightsSpec = this.hdc.generateSeeded("complex", "fallback_transitions");
|
|
2434
|
+
}
|
|
2435
|
+
if (this.wasmInstance && this.sparseWeightsSpec) {
|
|
2436
|
+
const mem = this.wasmMemory.buffer;
|
|
2437
|
+
const trRe = new Float32Array(mem, this.wasmInstance.exports.get_transition_spec_re_ptr(), this.D);
|
|
2438
|
+
const trIm = new Float32Array(mem, this.wasmInstance.exports.get_transition_spec_im_ptr(), this.D);
|
|
2439
|
+
for (let j = 0; j < this.D; j++) {
|
|
2440
|
+
trRe[j] = Math.cos(this.sparseWeightsSpec.values[j]);
|
|
2441
|
+
trIm[j] = Math.sin(this.sparseWeightsSpec.values[j]);
|
|
2442
|
+
}
|
|
2443
|
+
}
|
|
2444
|
+
}
|
|
2445
|
+
_predictNext(tokens, temperature, promptLength) {
|
|
2446
|
+
if (this.wasmInstance && this.wasmMemory) {
|
|
2447
|
+
return this._predictWasm(tokens, temperature, promptLength);
|
|
2448
|
+
}
|
|
2449
|
+
return this._predictJS(tokens, temperature, promptLength);
|
|
2450
|
+
}
|
|
2451
|
+
_predictWasm(tokens, temperature, promptLength) {
|
|
2452
|
+
const mem = this.wasmMemory.buffer;
|
|
2453
|
+
const ctxPtr = this.wasmInstance.exports.get_context_angles_ptr();
|
|
2454
|
+
const ctxView = new Float32Array(mem, ctxPtr, this.D);
|
|
2455
|
+
if (promptLength > 0 && tokens.length > promptLength) {
|
|
2456
|
+
let pIdx = this.vocabMap.get(tokens[promptLength - 1]) ?? 0;
|
|
2457
|
+
let gIdx = this.vocabMap.get(tokens[tokens.length - 1]) ?? 0;
|
|
2458
|
+
this.wasmInstance.exports.combine_phases_by_indices(
|
|
2459
|
+
pIdx,
|
|
2460
|
+
0.4,
|
|
2461
|
+
gIdx,
|
|
2462
|
+
0.6,
|
|
2463
|
+
this.vocabCosPtr,
|
|
2464
|
+
this.vocabSinPtr,
|
|
2465
|
+
ctxPtr
|
|
2466
|
+
);
|
|
2467
|
+
} else {
|
|
2468
|
+
const lastData = this.embeddings.get(tokens[tokens.length - 1]) || this.embeddings.get("<unk>");
|
|
2469
|
+
ctxView.set(lastData.emb.values);
|
|
2470
|
+
}
|
|
2471
|
+
this.wasmInstance.exports.spectral_predict();
|
|
2472
|
+
const candView = new Int32Array(mem, this.candidateIndicesPtr, 1024);
|
|
2473
|
+
const freqLen = this.freqIndices.length;
|
|
2474
|
+
for (let i = 0; i < freqLen; i++) {
|
|
2475
|
+
candView[i] = this.freqIndices[i];
|
|
2476
|
+
}
|
|
2477
|
+
let numCandidates = freqLen;
|
|
2478
|
+
for (let i = 0; i < promptLength; i++) {
|
|
2479
|
+
const idx = this.vocabMap.get(tokens[i]);
|
|
2480
|
+
if (idx !== void 0 && numCandidates < 1024) {
|
|
2481
|
+
candView[numCandidates++] = idx;
|
|
2482
|
+
}
|
|
2483
|
+
}
|
|
2484
|
+
const lastToken = tokens[tokens.length - 1];
|
|
2485
|
+
let numTransitions = -1;
|
|
2486
|
+
if (lastToken) {
|
|
2487
|
+
const m = this.transitionCounts.get(lastToken);
|
|
2488
|
+
if (!m) {
|
|
2489
|
+
numTransitions = 0;
|
|
2490
|
+
} else {
|
|
2491
|
+
const transIndices = new Int32Array(mem, this.transIndicesPtr, m.size);
|
|
2492
|
+
const transMultipliers = new Float32Array(mem, this.transMultipliersPtr, m.size);
|
|
2493
|
+
let idx = 0;
|
|
2494
|
+
for (const [nextWord, count] of m.entries()) {
|
|
2495
|
+
const wordIdx = this.vocabMap.get(nextWord);
|
|
2496
|
+
if (wordIdx !== void 0) {
|
|
2497
|
+
transIndices[idx] = wordIdx;
|
|
2498
|
+
transMultipliers[idx] = 1.5 + count * 2;
|
|
2499
|
+
idx++;
|
|
2500
|
+
if (numCandidates < 1024) {
|
|
2501
|
+
candView[numCandidates++] = wordIdx;
|
|
2502
|
+
}
|
|
2503
|
+
const derivationsIndices = this.wordDerivationIndices.get(nextWord);
|
|
2504
|
+
if (derivationsIndices) {
|
|
2505
|
+
const derivLen = derivationsIndices.length;
|
|
2506
|
+
for (let d = 0; d < derivLen; d++) {
|
|
2507
|
+
if (numCandidates < 1024) {
|
|
2508
|
+
candView[numCandidates++] = derivationsIndices[d];
|
|
2509
|
+
}
|
|
2510
|
+
}
|
|
2511
|
+
}
|
|
2512
|
+
}
|
|
2513
|
+
}
|
|
2514
|
+
numTransitions = idx;
|
|
2515
|
+
}
|
|
2516
|
+
}
|
|
2517
|
+
this.wasmInstance.exports.compute_similarity_for_candidates(
|
|
2518
|
+
this.candidateIndicesPtr,
|
|
2519
|
+
numCandidates,
|
|
2520
|
+
this.vocabCosPtr,
|
|
2521
|
+
this.vocabSinPtr,
|
|
2522
|
+
this.transIndicesPtr,
|
|
2523
|
+
this.transMultipliersPtr,
|
|
2524
|
+
numTransitions,
|
|
2525
|
+
this.topIndicesPtr,
|
|
2526
|
+
this.topScoresPtr
|
|
2527
|
+
);
|
|
2528
|
+
const topIndicesView = new Int32Array(mem, this.topIndicesPtr, 5);
|
|
2529
|
+
const topScoresView = new Float32Array(mem, this.topScoresPtr, 5);
|
|
2530
|
+
const candidates = [];
|
|
2531
|
+
const lastHarmony = lastToken ? this.morphology.determineVowelHarmony(lastToken) : null;
|
|
2532
|
+
const recentK = tokens.slice(-4);
|
|
2533
|
+
for (let i = 0; i < 5; i++) {
|
|
2534
|
+
const wordIdx = topIndicesView[i];
|
|
2535
|
+
if (wordIdx === -1) continue;
|
|
2536
|
+
const word = this.vocab[wordIdx];
|
|
2537
|
+
let score = topScoresView[i];
|
|
2538
|
+
if (tokens.length >= 1) {
|
|
2539
|
+
const last1 = tokens[tokens.length - 1];
|
|
2540
|
+
for (let idx = 0; idx < tokens.length - 1; idx++) {
|
|
2541
|
+
if (tokens[idx] === last1 && tokens[idx + 1] === word) {
|
|
2542
|
+
score = 0;
|
|
2543
|
+
break;
|
|
2544
|
+
}
|
|
2545
|
+
}
|
|
2546
|
+
}
|
|
2547
|
+
if (tokens.length >= 2) {
|
|
2548
|
+
const last2 = tokens[tokens.length - 2];
|
|
2549
|
+
const last1 = tokens[tokens.length - 1];
|
|
2550
|
+
for (let idx = 0; idx < tokens.length - 2; idx++) {
|
|
2551
|
+
if (tokens[idx] === last2 && tokens[idx + 1] === last1 && tokens[idx + 2] === word) {
|
|
2552
|
+
score = 0;
|
|
2553
|
+
break;
|
|
2554
|
+
}
|
|
2555
|
+
}
|
|
2556
|
+
}
|
|
2557
|
+
if (recentK.includes(word)) {
|
|
2558
|
+
score *= 0.1;
|
|
2559
|
+
}
|
|
2560
|
+
if (lastHarmony && this.morphology.suffixFeatures.hasOwnProperty(word)) {
|
|
2561
|
+
const suffixHarmony = this.morphology.determineVowelHarmony(word);
|
|
2562
|
+
if (suffixHarmony !== lastHarmony) score = 0;
|
|
2563
|
+
} else if (lastHarmony) {
|
|
2564
|
+
const candidateHarmony = this.morphology.determineVowelHarmony(word);
|
|
2565
|
+
if (candidateHarmony === lastHarmony) score *= 1.15;
|
|
2566
|
+
}
|
|
2567
|
+
candidates.push({ word, score });
|
|
2568
|
+
}
|
|
2569
|
+
candidates.sort((a, b) => b.score - a.score);
|
|
2570
|
+
return this._sample(candidates, temperature);
|
|
2571
|
+
}
|
|
2572
|
+
_predictJS(tokens, temperature, promptLength) {
|
|
2573
|
+
const ctx = new Float32Array(this.D);
|
|
2574
|
+
if (promptLength > 0 && tokens.length > promptLength) {
|
|
2575
|
+
const pD = this.embeddings.get(tokens[promptLength - 1]) || this.embeddings.get("<unk>");
|
|
2576
|
+
const gD = this.embeddings.get(tokens[tokens.length - 1]) || this.embeddings.get("<unk>");
|
|
2577
|
+
for (let j = 0; j < this.D; j++) {
|
|
2578
|
+
let v = pD.emb.values[j] + gD.emb.values[j];
|
|
2579
|
+
if (v < 0) v += 2 * Math.PI;
|
|
2580
|
+
ctx[j] = v % (2 * Math.PI);
|
|
2581
|
+
}
|
|
2582
|
+
} else {
|
|
2583
|
+
const ld = this.embeddings.get(tokens[tokens.length - 1]) || this.embeddings.get("<unk>");
|
|
2584
|
+
ctx.set(ld.emb.values);
|
|
2585
|
+
}
|
|
2586
|
+
const query = new Float32Array(this.D);
|
|
2587
|
+
for (let j = 0; j < this.D; j++) {
|
|
2588
|
+
let v = ctx[j] + (this.sparseWeightsSpec ? this.sparseWeightsSpec.values[j] : 0);
|
|
2589
|
+
if (v < 0) v += 2 * Math.PI;
|
|
2590
|
+
query[j] = v % (2 * Math.PI);
|
|
2591
|
+
}
|
|
2592
|
+
const cosY = new Float32Array(this.D);
|
|
2593
|
+
const sinY = new Float32Array(this.D);
|
|
2594
|
+
for (let i = 0; i < this.D; i++) {
|
|
2595
|
+
cosY[i] = Math.cos(query[i]);
|
|
2596
|
+
sinY[i] = Math.sin(query[i]);
|
|
2597
|
+
}
|
|
2598
|
+
const candidates = [];
|
|
2599
|
+
const lastToken = tokens[tokens.length - 1];
|
|
2600
|
+
const lastHarmony = lastToken ? this.morphology.determineVowelHarmony(lastToken) : null;
|
|
2601
|
+
const recentK = tokens.slice(-4);
|
|
2602
|
+
for (const [word, data] of this.embeddings.entries()) {
|
|
2603
|
+
let sumCos = 0;
|
|
2604
|
+
const cosEmb = data.cosVals;
|
|
2605
|
+
const sinEmb = data.sinVals;
|
|
2606
|
+
for (let i = 0; i < this.D; i++) {
|
|
2607
|
+
sumCos += cosY[i] * cosEmb[i] + sinY[i] * sinEmb[i];
|
|
2608
|
+
}
|
|
2609
|
+
let score = sumCos / this.D;
|
|
2610
|
+
score = Math.max(1e-4, (score + 1) / 2);
|
|
2611
|
+
if (lastToken) {
|
|
2612
|
+
const m = this.transitionCounts.get(lastToken);
|
|
2613
|
+
if (m) {
|
|
2614
|
+
const count = m.get(word) || 0;
|
|
2615
|
+
score *= count > 0 ? 1.5 + count * 2 : 0.1;
|
|
2616
|
+
} else {
|
|
2617
|
+
score *= 0.5;
|
|
2618
|
+
}
|
|
2619
|
+
}
|
|
2620
|
+
if (tokens.length >= 1) {
|
|
2621
|
+
const last1 = tokens[tokens.length - 1];
|
|
2622
|
+
for (let i = 0; i < tokens.length - 1; i++) {
|
|
2623
|
+
if (tokens[i] === last1 && tokens[i + 1] === word) {
|
|
2624
|
+
score = 0;
|
|
2625
|
+
break;
|
|
2626
|
+
}
|
|
2627
|
+
}
|
|
2628
|
+
}
|
|
2629
|
+
if (tokens.length >= 2) {
|
|
2630
|
+
const last2 = tokens[tokens.length - 2];
|
|
2631
|
+
const last1 = tokens[tokens.length - 1];
|
|
2632
|
+
for (let i = 0; i < tokens.length - 2; i++) {
|
|
2633
|
+
if (tokens[i] === last2 && tokens[i + 1] === last1 && tokens[i + 2] === word) {
|
|
2634
|
+
score = 0;
|
|
2635
|
+
break;
|
|
2636
|
+
}
|
|
2637
|
+
}
|
|
2638
|
+
}
|
|
2639
|
+
if (recentK.includes(word)) {
|
|
2640
|
+
score *= 0.1;
|
|
2641
|
+
}
|
|
2642
|
+
if (lastHarmony && this.morphology.suffixFeatures.hasOwnProperty(word)) {
|
|
2643
|
+
const suffixHarmony = this.morphology.determineVowelHarmony(word);
|
|
2644
|
+
if (suffixHarmony !== lastHarmony) score = 0;
|
|
2645
|
+
} else if (lastHarmony) {
|
|
2646
|
+
const candidateHarmony = this.morphology.determineVowelHarmony(word);
|
|
2647
|
+
if (candidateHarmony === lastHarmony) score *= 1.15;
|
|
2648
|
+
}
|
|
2649
|
+
candidates.push({ word, score });
|
|
2650
|
+
}
|
|
2651
|
+
candidates.sort((a, b) => b.score - a.score);
|
|
2652
|
+
return this._sample(candidates.slice(0, 5), temperature);
|
|
2653
|
+
}
|
|
2654
|
+
_sample(candidates, temperature) {
|
|
2655
|
+
if (!candidates.length) return { word: "<unk>", score: 0 };
|
|
2656
|
+
if (temperature <= 0.05) return candidates[0];
|
|
2657
|
+
const max = candidates[0].score;
|
|
2658
|
+
const exp = candidates.map((c) => Math.exp((c.score - max) / temperature));
|
|
2659
|
+
const sum = exp.reduce((a, v) => a + v, 0);
|
|
2660
|
+
const probs = exp.map((v) => v / sum);
|
|
2661
|
+
const r = Math.random();
|
|
2662
|
+
let cum = 0;
|
|
2663
|
+
for (let i = 0; i < candidates.length; i++) {
|
|
2664
|
+
cum += probs[i];
|
|
2665
|
+
if (r <= cum) return candidates[i];
|
|
2666
|
+
}
|
|
2667
|
+
return candidates[0];
|
|
2668
|
+
}
|
|
2669
|
+
_isTerminal(word) {
|
|
2670
|
+
const terminals = /* @__PURE__ */ new Set([
|
|
2671
|
+
".",
|
|
2672
|
+
"gittik",
|
|
2673
|
+
"ald\u0131m",
|
|
2674
|
+
"ald\u0131k",
|
|
2675
|
+
"geli\u015Ftirir",
|
|
2676
|
+
"uyand\u0131k",
|
|
2677
|
+
"kuruludur",
|
|
2678
|
+
"\xE7\u0131kt\u0131k",
|
|
2679
|
+
"izledim",
|
|
2680
|
+
"izledik",
|
|
2681
|
+
"uyudum",
|
|
2682
|
+
"yatt\u0131m",
|
|
2683
|
+
"gittim",
|
|
2684
|
+
"yapt\u0131m",
|
|
2685
|
+
"\xF6\u011Frendim"
|
|
2686
|
+
]);
|
|
2687
|
+
return terminals.has(word) || word.endsWith(".");
|
|
2688
|
+
}
|
|
2689
|
+
_assertInit() {
|
|
2690
|
+
if (!this._initialized) throw new Error("ResonanceSDK: Not initialized. Call await sdk.init() first.");
|
|
2691
|
+
}
|
|
2692
|
+
};
|
|
2693
|
+
export {
|
|
2694
|
+
ResonanceSDK
|
|
2695
|
+
};
|
|
2696
|
+
/**
|
|
2697
|
+
* Resonance SDK v1.0 - B2B Commercial Edge AI Engine
|
|
2698
|
+
* Unified SDK interface wrapping the Turkish Resonance AI Core (v5.2).
|
|
2699
|
+
* Supports both Browser (fetch/streaming) and Node.js environments.
|
|
2700
|
+
*
|
|
2701
|
+
* @license Commercial - Per-device licensing
|
|
2702
|
+
* @author Turkish Resonance AI Core Team
|
|
2703
|
+
*/
|