@cachly-dev/mcp-server 0.10.123 → 0.10.125
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/dist/index.d.ts +1 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/src/aussetzer.d.ts +67 -0
- package/dist/src/aussetzer.js +82 -0
- package/dist/src/aussetzer.js.map +1 -0
- package/dist/src/autor-abzeichen.d.ts +41 -0
- package/dist/src/autor-abzeichen.js +56 -0
- package/dist/src/autor-abzeichen.js.map +1 -0
- package/dist/src/autor.d.ts +101 -0
- package/dist/src/autor.js +136 -0
- package/dist/src/autor.js.map +1 -0
- package/dist/src/bauabdruck-daten.generiert.json +5 -0
- package/dist/src/bauabdruck.d.ts +38 -0
- package/dist/src/bauabdruck.js +93 -0
- package/dist/src/bauabdruck.js.map +1 -0
- package/dist/src/bedeutung.d.ts +175 -0
- package/dist/src/bedeutung.js +254 -0
- package/dist/src/bedeutung.js.map +1 -0
- package/dist/src/brain-export.d.ts +24 -0
- package/dist/src/brain-export.js +31 -1
- package/dist/src/brain-export.js.map +1 -1
- package/dist/src/deutsch.d.ts +98 -0
- package/dist/src/deutsch.js +223 -0
- package/dist/src/deutsch.js.map +1 -0
- package/dist/src/eingaenge-nachruesten.d.ts +41 -0
- package/dist/src/eingaenge-nachruesten.js +290 -0
- package/dist/src/eingaenge-nachruesten.js.map +1 -0
- package/dist/src/eingaenge.d.ts +135 -0
- package/dist/src/eingaenge.js +228 -0
- package/dist/src/eingaenge.js.map +1 -0
- package/dist/src/geliefert.d.ts +63 -0
- package/dist/src/geliefert.js +114 -0
- package/dist/src/geliefert.js.map +1 -0
- package/dist/src/handlers/advanced.js +7 -3
- package/dist/src/handlers/advanced.js.map +1 -1
- package/dist/src/handlers/brain.d.ts +19 -0
- package/dist/src/handlers/brain.js +492 -48
- package/dist/src/handlers/brain.js.map +1 -1
- package/dist/src/handlers/instances.d.ts +24 -0
- package/dist/src/handlers/instances.js +49 -1
- package/dist/src/handlers/instances.js.map +1 -1
- package/dist/src/handlers/team.js +105 -0
- package/dist/src/handlers/team.js.map +1 -1
- package/dist/src/index.d.ts +20 -0
- package/dist/src/index.js +282 -36
- package/dist/src/index.js.map +1 -1
- package/dist/src/lesson-preview.d.ts +81 -0
- package/dist/src/lesson-preview.js +133 -0
- package/dist/src/lesson-preview.js.map +1 -0
- package/dist/src/rangfolge.d.ts +169 -0
- package/dist/src/rangfolge.js +214 -0
- package/dist/src/rangfolge.js.map +1 -0
- package/dist/src/raumkorrektur.d.ts +100 -0
- package/dist/src/raumkorrektur.js +197 -0
- package/dist/src/raumkorrektur.js.map +1 -0
- package/dist/src/recall-tiefe.d.ts +48 -0
- package/dist/src/recall-tiefe.js +42 -0
- package/dist/src/recall-tiefe.js.map +1 -0
- package/dist/src/rerank.d.ts +0 -14
- package/dist/src/rerank.js +39 -2
- package/dist/src/rerank.js.map +1 -1
- package/dist/src/search.d.ts +56 -17
- package/dist/src/search.js +335 -73
- package/dist/src/search.js.map +1 -1
- package/dist/src/seltenheitsbestand.d.ts +53 -0
- package/dist/src/seltenheitsbestand.js +92 -0
- package/dist/src/seltenheitsbestand.js.map +1 -0
- package/dist/src/spuren.d.ts +97 -0
- package/dist/src/spuren.js +150 -0
- package/dist/src/spuren.js.map +1 -0
- package/dist/src/tools.js +1 -1
- package/dist/src/tools.js.map +1 -1
- package/dist/src/vorspann.d.ts +73 -0
- package/dist/src/vorspann.js +146 -0
- package/dist/src/vorspann.js.map +1 -0
- package/dist/src/werkzeug-nutzung.d.ts +62 -0
- package/dist/src/werkzeug-nutzung.js +72 -0
- package/dist/src/werkzeug-nutzung.js.map +1 -0
- package/dist/src/wertbeitrag.d.ts +57 -0
- package/dist/src/wertbeitrag.js +73 -0
- package/dist/src/wertbeitrag.js.map +1 -0
- package/glama.json +1 -1
- package/package.json +12 -4
- package/server.json +2 -2
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Raumkorrektur: den Einbettungsraum brauchbar machen, bevor man darin sucht.
|
|
3
|
+
*
|
|
4
|
+
* ── Drei Übel, drei Gegenmittel ─────────────────────────────────────────────
|
|
5
|
+
*
|
|
6
|
+
* Ein Einbettungsraum ist nicht neutral. Er hat Eigenschaften, die das Sortieren
|
|
7
|
+
* verderben — alle drei am 19.08.2026 an 499 echten Lektionen gemessen:
|
|
8
|
+
*
|
|
9
|
+
* 1. GEMEINSAME GRUNDRICHTUNG (Anisotropie). Ein durchschnittlicher Vektor
|
|
10
|
+
* zeigt zu 69,8 Prozent in Richtung des Schwerpunkts aller Vektoren. Dieser
|
|
11
|
+
* Anteil ist in JEDEM Vergleich derselbe und sagt daher nichts — er hebt nur
|
|
12
|
+
* alle Werte an und drückt die Unterschiede zusammen. Gemessen liegen alle
|
|
13
|
+
* Ähnlichkeiten zwischen 0,42 und 0,61.
|
|
14
|
+
*
|
|
15
|
+
* 2. RICHTUNGEN, DIE NUR SCHREIBSTIL SIND. Nach dem Schwerpunkt bleiben ein
|
|
16
|
+
* paar Hauptrichtungen übrig, die keine Bedeutung tragen, sondern Textsorte:
|
|
17
|
+
* "ist eine Fehlermeldung", "enthält Codeschnipsel", "ist auf Deutsch".
|
|
18
|
+
* Sie sind stark und lenken die Rangfolge.
|
|
19
|
+
*
|
|
20
|
+
* 3. NABEN. Manche Vektoren liegen einfach nahe an vielem. Sie erscheinen als
|
|
21
|
+
* Treffer für Fragen, mit denen sie nichts zu tun haben. Belegt: die Lektion
|
|
22
|
+
* `forge:arbeitskopie-nach-dem-merge-sofort-abraeumen` stand bei "Ich beende
|
|
23
|
+
* den Prozess, kurz darauf ist er neu da" UND bei "Wenn der Zwischenspeicher
|
|
24
|
+
* abläuft, schlagen alle Anfragen durch" auf Platz 1. Zwei Fragen ohne
|
|
25
|
+
* Berührungspunkt, dieselbe falsche Antwort.
|
|
26
|
+
*
|
|
27
|
+
* ── Die Gegenmittel ─────────────────────────────────────────────────────────
|
|
28
|
+
*
|
|
29
|
+
* Zu 1 und 2: Schwerpunkt abziehen und die stärksten verbleibenden
|
|
30
|
+
* Hauptrichtungen entfernen. Was danach übrig bleibt, ist das, worin sich die
|
|
31
|
+
* Texte inhaltlich unterscheiden.
|
|
32
|
+
*
|
|
33
|
+
* Zu 3: jedem Vektor seine eigene "Geselligkeit" ausrechnen — wie nah liegt er
|
|
34
|
+
* im Mittel an seinen nächsten Nachbarn. Wer überall nah dran ist, bekommt
|
|
35
|
+
* einen Abzug. Das ist die Idee hinter CSLS aus der Wortübersetzung, hier auf
|
|
36
|
+
* den Fall übertragen, dass zur Bauzeit keine Fragen vorliegen: die Nachbarn
|
|
37
|
+
* sind die anderen Lektionen.
|
|
38
|
+
*
|
|
39
|
+
* Entscheidend für den Betrieb: ALLES DAVON WIRD EINMAL AUSGERECHNET. Zur
|
|
40
|
+
* Fragezeit bleibt ein Skalarprodukt und eine Subtraktion. Die Rangfolge wird
|
|
41
|
+
* besser, ohne dass jemand länger wartet.
|
|
42
|
+
*/
|
|
43
|
+
/** Skalarprodukt. */
|
|
44
|
+
export declare function punktprodukt(a: number[], b: number[]): number;
|
|
45
|
+
export declare function laenge(v: number[]): number;
|
|
46
|
+
/** Auf Länge 1 bringen. Ein Nullvektor bleibt, was er ist. */
|
|
47
|
+
export declare function normiere(v: number[]): number[];
|
|
48
|
+
/** Der Schwerpunkt — die gemeinsame Grundrichtung aller Vektoren. */
|
|
49
|
+
export declare function schwerpunkt(vs: number[][]): number[];
|
|
50
|
+
/**
|
|
51
|
+
* Die stärksten Hauptrichtungen, über Potenziteration mit Deflation.
|
|
52
|
+
*
|
|
53
|
+
* Warum von Hand statt einer Bibliothek: es sind rund zwanzig Zeilen, läuft
|
|
54
|
+
* einmal, und eine Abhängigkeit für zwanzig Zeilen ist eine Abhängigkeit, die
|
|
55
|
+
* jemand pflegen muss.
|
|
56
|
+
*
|
|
57
|
+
* Die Vektoren müssen bereits zentriert sein — sonst ist die erste
|
|
58
|
+
* Hauptrichtung nur der Schwerpunkt, den wir gerade abgezogen haben.
|
|
59
|
+
*/
|
|
60
|
+
export declare function hauptrichtungen(zentriert: number[][], anzahl: number, schritte?: number): number[][];
|
|
61
|
+
/** Was von einem Vektor bleibt, wenn Schwerpunkt und Hauptrichtungen weg sind. */
|
|
62
|
+
export declare function bereinige(v: number[], mitte: number[], richtungen: number[][]): number[];
|
|
63
|
+
/**
|
|
64
|
+
* Die "Geselligkeit" jedes Vektors: mittlere Ähnlichkeit zu seinen k nächsten
|
|
65
|
+
* Nachbarn im selben Bestand.
|
|
66
|
+
*
|
|
67
|
+
* Ein hoher Wert heißt: dieser Vektor liegt in einer dichten Gegend und ist
|
|
68
|
+
* vielem nah. Solche Naben erscheinen als Treffer für Fragen, mit denen sie
|
|
69
|
+
* nichts zu tun haben — nicht weil sie passen, sondern weil sie überall
|
|
70
|
+
* passen.
|
|
71
|
+
*
|
|
72
|
+
* Der Wert wird EINMAL berechnet und beim Suchen abgezogen. Kosten zur
|
|
73
|
+
* Fragezeit: eine Subtraktion.
|
|
74
|
+
*/
|
|
75
|
+
export declare function geselligkeit(normierte: number[][], k?: number): number[];
|
|
76
|
+
/**
|
|
77
|
+
* Ein fertig vorbereiteter Raum: bereinigte Vektoren plus Nabenabzug.
|
|
78
|
+
*
|
|
79
|
+
* Alles hier ist Bauzeit. Zur Fragezeit ruft man `bewerte` — ein Skalarprodukt
|
|
80
|
+
* je Lektion und eine Subtraktion.
|
|
81
|
+
*/
|
|
82
|
+
export interface Raum {
|
|
83
|
+
mitte: number[];
|
|
84
|
+
richtungen: number[][];
|
|
85
|
+
vektoren: number[][];
|
|
86
|
+
abzug: number[];
|
|
87
|
+
beta: number;
|
|
88
|
+
}
|
|
89
|
+
export declare function baueRaum(roh: Array<number[] | null>, optionen?: {
|
|
90
|
+
richtungen?: number;
|
|
91
|
+
nachbarn?: number;
|
|
92
|
+
beta?: number;
|
|
93
|
+
}): Raum;
|
|
94
|
+
/**
|
|
95
|
+
* Bewertet eine Frage gegen alle Lektionen des Raums.
|
|
96
|
+
*
|
|
97
|
+
* `2 * cos - abzug` ist die Form aus CSLS. Der Faktor 2 sorgt dafür, dass der
|
|
98
|
+
* Abzug die Ähnlichkeit dämpft und nicht überstimmt.
|
|
99
|
+
*/
|
|
100
|
+
export declare function bewerteImRaum(raum: Raum, frage: number[]): number[];
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Raumkorrektur: den Einbettungsraum brauchbar machen, bevor man darin sucht.
|
|
3
|
+
*
|
|
4
|
+
* ── Drei Übel, drei Gegenmittel ─────────────────────────────────────────────
|
|
5
|
+
*
|
|
6
|
+
* Ein Einbettungsraum ist nicht neutral. Er hat Eigenschaften, die das Sortieren
|
|
7
|
+
* verderben — alle drei am 19.08.2026 an 499 echten Lektionen gemessen:
|
|
8
|
+
*
|
|
9
|
+
* 1. GEMEINSAME GRUNDRICHTUNG (Anisotropie). Ein durchschnittlicher Vektor
|
|
10
|
+
* zeigt zu 69,8 Prozent in Richtung des Schwerpunkts aller Vektoren. Dieser
|
|
11
|
+
* Anteil ist in JEDEM Vergleich derselbe und sagt daher nichts — er hebt nur
|
|
12
|
+
* alle Werte an und drückt die Unterschiede zusammen. Gemessen liegen alle
|
|
13
|
+
* Ähnlichkeiten zwischen 0,42 und 0,61.
|
|
14
|
+
*
|
|
15
|
+
* 2. RICHTUNGEN, DIE NUR SCHREIBSTIL SIND. Nach dem Schwerpunkt bleiben ein
|
|
16
|
+
* paar Hauptrichtungen übrig, die keine Bedeutung tragen, sondern Textsorte:
|
|
17
|
+
* "ist eine Fehlermeldung", "enthält Codeschnipsel", "ist auf Deutsch".
|
|
18
|
+
* Sie sind stark und lenken die Rangfolge.
|
|
19
|
+
*
|
|
20
|
+
* 3. NABEN. Manche Vektoren liegen einfach nahe an vielem. Sie erscheinen als
|
|
21
|
+
* Treffer für Fragen, mit denen sie nichts zu tun haben. Belegt: die Lektion
|
|
22
|
+
* `forge:arbeitskopie-nach-dem-merge-sofort-abraeumen` stand bei "Ich beende
|
|
23
|
+
* den Prozess, kurz darauf ist er neu da" UND bei "Wenn der Zwischenspeicher
|
|
24
|
+
* abläuft, schlagen alle Anfragen durch" auf Platz 1. Zwei Fragen ohne
|
|
25
|
+
* Berührungspunkt, dieselbe falsche Antwort.
|
|
26
|
+
*
|
|
27
|
+
* ── Die Gegenmittel ─────────────────────────────────────────────────────────
|
|
28
|
+
*
|
|
29
|
+
* Zu 1 und 2: Schwerpunkt abziehen und die stärksten verbleibenden
|
|
30
|
+
* Hauptrichtungen entfernen. Was danach übrig bleibt, ist das, worin sich die
|
|
31
|
+
* Texte inhaltlich unterscheiden.
|
|
32
|
+
*
|
|
33
|
+
* Zu 3: jedem Vektor seine eigene "Geselligkeit" ausrechnen — wie nah liegt er
|
|
34
|
+
* im Mittel an seinen nächsten Nachbarn. Wer überall nah dran ist, bekommt
|
|
35
|
+
* einen Abzug. Das ist die Idee hinter CSLS aus der Wortübersetzung, hier auf
|
|
36
|
+
* den Fall übertragen, dass zur Bauzeit keine Fragen vorliegen: die Nachbarn
|
|
37
|
+
* sind die anderen Lektionen.
|
|
38
|
+
*
|
|
39
|
+
* Entscheidend für den Betrieb: ALLES DAVON WIRD EINMAL AUSGERECHNET. Zur
|
|
40
|
+
* Fragezeit bleibt ein Skalarprodukt und eine Subtraktion. Die Rangfolge wird
|
|
41
|
+
* besser, ohne dass jemand länger wartet.
|
|
42
|
+
*/
|
|
43
|
+
/** Skalarprodukt. */
|
|
44
|
+
export function punktprodukt(a, b) {
|
|
45
|
+
let s = 0;
|
|
46
|
+
for (let i = 0; i < a.length; i++)
|
|
47
|
+
s += a[i] * b[i];
|
|
48
|
+
return s;
|
|
49
|
+
}
|
|
50
|
+
export function laenge(v) {
|
|
51
|
+
return Math.sqrt(punktprodukt(v, v));
|
|
52
|
+
}
|
|
53
|
+
/** Auf Länge 1 bringen. Ein Nullvektor bleibt, was er ist. */
|
|
54
|
+
export function normiere(v) {
|
|
55
|
+
const l = laenge(v);
|
|
56
|
+
return l > 1e-12 ? v.map((x) => x / l) : v.slice();
|
|
57
|
+
}
|
|
58
|
+
/** Der Schwerpunkt — die gemeinsame Grundrichtung aller Vektoren. */
|
|
59
|
+
export function schwerpunkt(vs) {
|
|
60
|
+
const d = vs[0]?.length ?? 0;
|
|
61
|
+
const m = new Array(d).fill(0);
|
|
62
|
+
for (const v of vs)
|
|
63
|
+
for (let i = 0; i < d; i++)
|
|
64
|
+
m[i] += v[i];
|
|
65
|
+
for (let i = 0; i < d; i++)
|
|
66
|
+
m[i] /= Math.max(1, vs.length);
|
|
67
|
+
return m;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Die stärksten Hauptrichtungen, über Potenziteration mit Deflation.
|
|
71
|
+
*
|
|
72
|
+
* Warum von Hand statt einer Bibliothek: es sind rund zwanzig Zeilen, läuft
|
|
73
|
+
* einmal, und eine Abhängigkeit für zwanzig Zeilen ist eine Abhängigkeit, die
|
|
74
|
+
* jemand pflegen muss.
|
|
75
|
+
*
|
|
76
|
+
* Die Vektoren müssen bereits zentriert sein — sonst ist die erste
|
|
77
|
+
* Hauptrichtung nur der Schwerpunkt, den wir gerade abgezogen haben.
|
|
78
|
+
*/
|
|
79
|
+
export function hauptrichtungen(zentriert, anzahl, schritte = 30) {
|
|
80
|
+
const d = zentriert[0]?.length ?? 0;
|
|
81
|
+
const rest = zentriert.map((v) => v.slice());
|
|
82
|
+
const aus = [];
|
|
83
|
+
for (let k = 0; k < anzahl; k++) {
|
|
84
|
+
// Startvektor: fest, nicht zufällig — sonst liefert derselbe Bestand bei
|
|
85
|
+
// jedem Lauf leicht andere Richtungen, und niemand kann eine Messung
|
|
86
|
+
// wiederholen.
|
|
87
|
+
let u = new Array(d).fill(0).map((_, i) => Math.sin(i * (k + 1) * 0.7));
|
|
88
|
+
u = normiere(u);
|
|
89
|
+
for (let s = 0; s < schritte; s++) {
|
|
90
|
+
const neu = new Array(d).fill(0);
|
|
91
|
+
for (const v of rest) {
|
|
92
|
+
const p = punktprodukt(v, u);
|
|
93
|
+
for (let i = 0; i < d; i++)
|
|
94
|
+
neu[i] += p * v[i];
|
|
95
|
+
}
|
|
96
|
+
const l = laenge(neu);
|
|
97
|
+
if (l < 1e-12)
|
|
98
|
+
break;
|
|
99
|
+
for (let i = 0; i < d; i++)
|
|
100
|
+
neu[i] /= l;
|
|
101
|
+
u = neu;
|
|
102
|
+
}
|
|
103
|
+
aus.push(u);
|
|
104
|
+
// Deflation: den gefundenen Anteil aus allen Vektoren entfernen, damit die
|
|
105
|
+
// nächste Iteration eine ANDERE Richtung findet.
|
|
106
|
+
for (const v of rest) {
|
|
107
|
+
const p = punktprodukt(v, u);
|
|
108
|
+
for (let i = 0; i < d; i++)
|
|
109
|
+
v[i] -= p * u[i];
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return aus;
|
|
113
|
+
}
|
|
114
|
+
/** Was von einem Vektor bleibt, wenn Schwerpunkt und Hauptrichtungen weg sind. */
|
|
115
|
+
export function bereinige(v, mitte, richtungen) {
|
|
116
|
+
const w = v.map((x, i) => x - mitte[i]);
|
|
117
|
+
for (const u of richtungen) {
|
|
118
|
+
const p = punktprodukt(w, u);
|
|
119
|
+
for (let i = 0; i < w.length; i++)
|
|
120
|
+
w[i] -= p * u[i];
|
|
121
|
+
}
|
|
122
|
+
return normiere(w);
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Die "Geselligkeit" jedes Vektors: mittlere Ähnlichkeit zu seinen k nächsten
|
|
126
|
+
* Nachbarn im selben Bestand.
|
|
127
|
+
*
|
|
128
|
+
* Ein hoher Wert heißt: dieser Vektor liegt in einer dichten Gegend und ist
|
|
129
|
+
* vielem nah. Solche Naben erscheinen als Treffer für Fragen, mit denen sie
|
|
130
|
+
* nichts zu tun haben — nicht weil sie passen, sondern weil sie überall
|
|
131
|
+
* passen.
|
|
132
|
+
*
|
|
133
|
+
* Der Wert wird EINMAL berechnet und beim Suchen abgezogen. Kosten zur
|
|
134
|
+
* Fragezeit: eine Subtraktion.
|
|
135
|
+
*/
|
|
136
|
+
export function geselligkeit(normierte, k = 10) {
|
|
137
|
+
const n = normierte.length;
|
|
138
|
+
const aus = new Array(n).fill(0);
|
|
139
|
+
for (let i = 0; i < n; i++) {
|
|
140
|
+
// Die k besten Ähnlichkeiten sammeln, ohne alles zu sortieren.
|
|
141
|
+
const beste = [];
|
|
142
|
+
for (let j = 0; j < n; j++) {
|
|
143
|
+
if (i === j)
|
|
144
|
+
continue;
|
|
145
|
+
const s = punktprodukt(normierte[i], normierte[j]);
|
|
146
|
+
if (beste.length < k) {
|
|
147
|
+
beste.push(s);
|
|
148
|
+
if (beste.length === k)
|
|
149
|
+
beste.sort((a, b) => a - b);
|
|
150
|
+
}
|
|
151
|
+
else if (s > beste[0]) {
|
|
152
|
+
beste[0] = s;
|
|
153
|
+
beste.sort((a, b) => a - b);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
aus[i] = beste.length ? beste.reduce((a, b) => a + b, 0) / beste.length : 0;
|
|
157
|
+
}
|
|
158
|
+
return aus;
|
|
159
|
+
}
|
|
160
|
+
export function baueRaum(roh, optionen = {}) {
|
|
161
|
+
const anzahlRichtungen = optionen.richtungen ?? 3;
|
|
162
|
+
const nachbarn = optionen.nachbarn ?? 10;
|
|
163
|
+
const beta = optionen.beta ?? 0.5;
|
|
164
|
+
const da = roh.filter(Boolean);
|
|
165
|
+
const mitte = schwerpunkt(da);
|
|
166
|
+
const zentriert = da.map((v) => v.map((x, i) => x - mitte[i]));
|
|
167
|
+
const richtungen = anzahlRichtungen > 0 ? hauptrichtungen(zentriert, anzahlRichtungen) : [];
|
|
168
|
+
// Bereinigte Vektoren in der ursprünglichen Reihenfolge — Lücken bleiben
|
|
169
|
+
// Lücken, damit ein fehlender Vektor nicht still zu einem Nullvektor wird,
|
|
170
|
+
// der zu allem gleich weit entfernt ist.
|
|
171
|
+
const vektoren = [];
|
|
172
|
+
const gueltigeIndizes = [];
|
|
173
|
+
for (const [i, v] of roh.entries()) {
|
|
174
|
+
if (!v) {
|
|
175
|
+
vektoren.push([]);
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
vektoren.push(bereinige(v, mitte, richtungen));
|
|
179
|
+
gueltigeIndizes.push(i);
|
|
180
|
+
}
|
|
181
|
+
const abzug = new Array(roh.length).fill(0);
|
|
182
|
+
const nurGueltige = gueltigeIndizes.map((i) => vektoren[i]);
|
|
183
|
+
const g = geselligkeit(nurGueltige, nachbarn);
|
|
184
|
+
gueltigeIndizes.forEach((idx, k) => { abzug[idx] = g[k]; });
|
|
185
|
+
return { mitte, richtungen, vektoren, abzug, beta };
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Bewertet eine Frage gegen alle Lektionen des Raums.
|
|
189
|
+
*
|
|
190
|
+
* `2 * cos - abzug` ist die Form aus CSLS. Der Faktor 2 sorgt dafür, dass der
|
|
191
|
+
* Abzug die Ähnlichkeit dämpft und nicht überstimmt.
|
|
192
|
+
*/
|
|
193
|
+
export function bewerteImRaum(raum, frage) {
|
|
194
|
+
const f = bereinige(frage, raum.mitte, raum.richtungen);
|
|
195
|
+
return raum.vektoren.map((v, i) => v.length === 0 ? -2 : 2 * punktprodukt(f, v) - raum.beta * raum.abzug[i]);
|
|
196
|
+
}
|
|
197
|
+
//# sourceMappingURL=raumkorrektur.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"raumkorrektur.js","sourceRoot":"","sources":["../../src/raumkorrektur.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wie viele Treffer zeigt `smart_recall` — und wie viele haelt es zurueck?
|
|
3
|
+
*
|
|
4
|
+
* Eigenes Modul, weil hier ein Versprechen eingeloest wird, das vorher nur im
|
|
5
|
+
* Kommentar stand. Der Kommentar am Teaser-Gate sagte seit jeher:
|
|
6
|
+
*
|
|
7
|
+
* "the magic moment is sacred ... never an access wall: the #1 result is
|
|
8
|
+
* always returned"
|
|
9
|
+
*
|
|
10
|
+
* Der Code sagte `visibleCount = gateActive ? 0 : 8` — also NULL Treffer,
|
|
11
|
+
* sobald ein Frei-Konto sein Monatskontingent ueberschritten hat. Der Nutzer
|
|
12
|
+
* las die Ueberschrift "Results (23 — hybrid)", darunter keine einzige Zeile
|
|
13
|
+
* und dann eine Kaufaufforderung. Das sieht nicht aus wie eine Rechnung,
|
|
14
|
+
* sondern wie ein kaputtes Werkzeug — besonders bei Ambient Recall, das bei
|
|
15
|
+
* jedem Prompt feuert und das Kontingent in Tagen aufbraucht.
|
|
16
|
+
*
|
|
17
|
+
* Fehlerklasse: eine Zusage an zwei Orten gepflegt (Kommentar und Zweig).
|
|
18
|
+
* Deshalb ist die Regel jetzt eine Funktion mit Tests, nicht ein Satz Prosa.
|
|
19
|
+
*/
|
|
20
|
+
/** Der eine Treffer, den auch ein ueberzogenes Frei-Konto immer sieht. */
|
|
21
|
+
export declare const TIEFE_UEBER_LIMIT = 1;
|
|
22
|
+
/** Volle Tiefe bei einer einzelnen Frage. */
|
|
23
|
+
export declare const TIEFE_VOLL = 8;
|
|
24
|
+
/** Volle Tiefe, wenn die Frage in Unterfragen zerfaellt (mehr Themen, mehr Platz). */
|
|
25
|
+
export declare const TIEFE_VOLL_MEHRTHEMIG = 12;
|
|
26
|
+
export interface RecallTiefeEingabe {
|
|
27
|
+
/** Frei-Konto ueber seinem Monatskontingent? */
|
|
28
|
+
ueberLimit: boolean;
|
|
29
|
+
/** Wie viele Treffer stehen ueberhaupt zur Verfuegung. */
|
|
30
|
+
gesamt: number;
|
|
31
|
+
/** Tiefe ohne Limit — TIEFE_VOLL oder TIEFE_VOLL_MEHRTHEMIG. */
|
|
32
|
+
volleTiefe?: number;
|
|
33
|
+
}
|
|
34
|
+
export interface RecallTiefe {
|
|
35
|
+
/** So viele Treffer werden ausgegeben. */
|
|
36
|
+
sichtbar: number;
|
|
37
|
+
/** So viele bleiben hinter dem Kontingent — 0, solange niemand ueber dem Limit ist. */
|
|
38
|
+
zurueckgehalten: number;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Nie eine Mauer, immer eine Bremse: ueber dem Limit bleibt genau der beste
|
|
42
|
+
* Treffer sichtbar, der Rest wird gezaehlt und benannt.
|
|
43
|
+
*
|
|
44
|
+
* Bei null Treffern gibt es nichts zu zeigen und nichts zurueckzuhalten — ein
|
|
45
|
+
* leeres Ergebnis darf nie als "hinter der Bezahlschranke" erscheinen, sonst
|
|
46
|
+
* verkauft die Meldung etwas, das gar nicht existiert.
|
|
47
|
+
*/
|
|
48
|
+
export declare function recallTiefe({ ueberLimit, gesamt, volleTiefe }: RecallTiefeEingabe): RecallTiefe;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wie viele Treffer zeigt `smart_recall` — und wie viele haelt es zurueck?
|
|
3
|
+
*
|
|
4
|
+
* Eigenes Modul, weil hier ein Versprechen eingeloest wird, das vorher nur im
|
|
5
|
+
* Kommentar stand. Der Kommentar am Teaser-Gate sagte seit jeher:
|
|
6
|
+
*
|
|
7
|
+
* "the magic moment is sacred ... never an access wall: the #1 result is
|
|
8
|
+
* always returned"
|
|
9
|
+
*
|
|
10
|
+
* Der Code sagte `visibleCount = gateActive ? 0 : 8` — also NULL Treffer,
|
|
11
|
+
* sobald ein Frei-Konto sein Monatskontingent ueberschritten hat. Der Nutzer
|
|
12
|
+
* las die Ueberschrift "Results (23 — hybrid)", darunter keine einzige Zeile
|
|
13
|
+
* und dann eine Kaufaufforderung. Das sieht nicht aus wie eine Rechnung,
|
|
14
|
+
* sondern wie ein kaputtes Werkzeug — besonders bei Ambient Recall, das bei
|
|
15
|
+
* jedem Prompt feuert und das Kontingent in Tagen aufbraucht.
|
|
16
|
+
*
|
|
17
|
+
* Fehlerklasse: eine Zusage an zwei Orten gepflegt (Kommentar und Zweig).
|
|
18
|
+
* Deshalb ist die Regel jetzt eine Funktion mit Tests, nicht ein Satz Prosa.
|
|
19
|
+
*/
|
|
20
|
+
/** Der eine Treffer, den auch ein ueberzogenes Frei-Konto immer sieht. */
|
|
21
|
+
export const TIEFE_UEBER_LIMIT = 1;
|
|
22
|
+
/** Volle Tiefe bei einer einzelnen Frage. */
|
|
23
|
+
export const TIEFE_VOLL = 8;
|
|
24
|
+
/** Volle Tiefe, wenn die Frage in Unterfragen zerfaellt (mehr Themen, mehr Platz). */
|
|
25
|
+
export const TIEFE_VOLL_MEHRTHEMIG = 12;
|
|
26
|
+
/**
|
|
27
|
+
* Nie eine Mauer, immer eine Bremse: ueber dem Limit bleibt genau der beste
|
|
28
|
+
* Treffer sichtbar, der Rest wird gezaehlt und benannt.
|
|
29
|
+
*
|
|
30
|
+
* Bei null Treffern gibt es nichts zu zeigen und nichts zurueckzuhalten — ein
|
|
31
|
+
* leeres Ergebnis darf nie als "hinter der Bezahlschranke" erscheinen, sonst
|
|
32
|
+
* verkauft die Meldung etwas, das gar nicht existiert.
|
|
33
|
+
*/
|
|
34
|
+
export function recallTiefe({ ueberLimit, gesamt, volleTiefe = TIEFE_VOLL }) {
|
|
35
|
+
const vorhanden = Number.isFinite(gesamt) && gesamt > 0 ? Math.floor(gesamt) : 0;
|
|
36
|
+
if (vorhanden === 0)
|
|
37
|
+
return { sichtbar: 0, zurueckgehalten: 0 };
|
|
38
|
+
const obergrenze = ueberLimit ? TIEFE_UEBER_LIMIT : Math.max(0, Math.floor(volleTiefe));
|
|
39
|
+
const sichtbar = Math.min(vorhanden, obergrenze);
|
|
40
|
+
return { sichtbar, zurueckgehalten: ueberLimit ? vorhanden - sichtbar : 0 };
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=recall-tiefe.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recall-tiefe.js","sourceRoot":"","sources":["../../src/recall-tiefe.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,0EAA0E;AAC1E,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC;AACnC,6CAA6C;AAC7C,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,CAAC;AAC5B,sFAAsF;AACtF,MAAM,CAAC,MAAM,qBAAqB,GAAG,EAAE,CAAC;AAkBxC;;;;;;;GAOG;AACH,MAAM,UAAU,WAAW,CAAC,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,GAAG,UAAU,EAAsB;IAC7F,MAAM,SAAS,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACjF,IAAI,SAAS,KAAK,CAAC;QAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,eAAe,EAAE,CAAC,EAAE,CAAC;IAEhE,MAAM,UAAU,GAAG,UAAU,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC;IACxF,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;IACjD,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,UAAU,CAAC,CAAC,CAAC,SAAS,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AAC9E,CAAC"}
|
package/dist/src/rerank.d.ts
CHANGED
|
@@ -45,18 +45,4 @@ export interface RerankedMatch extends KeywordMatch {
|
|
|
45
45
|
export declare function qualityMultiplier(lesson: LessonQuality | null): number;
|
|
46
46
|
/** Extract the quality signal from a match, if its content is a stored lesson. */
|
|
47
47
|
export declare function extractLessonQuality(match: Pick<KeywordMatch, 'key' | 'content'>): LessonQuality | null;
|
|
48
|
-
/**
|
|
49
|
-
* Rerank BM25 keyword matches by lesson quality.
|
|
50
|
-
*
|
|
51
|
-
* BM25 scores are compressed with a 0.3-power root before quality is applied.
|
|
52
|
-
* Compression is the key: a distractor lesson whose `what_failed` contains the
|
|
53
|
-
* exact query phrase can score 5–6× higher in BM25 than the correct success lesson.
|
|
54
|
-
* A linear quality multiplier of ±40% cannot overcome that gap; after ^0.3
|
|
55
|
-
* compression the ratio shrinks to ~1.5×, well within the quality range.
|
|
56
|
-
*
|
|
57
|
-
* The formula compressed_score * (0.4 + 0.6 * boost) gives quality 60% weight
|
|
58
|
-
* on the compressed axis. A failure lesson (boost ≈ 0.5) retains 70% of its
|
|
59
|
-
* compressed score; a senior-confirmed success (boost ≈ 1.8) gets 148%.
|
|
60
|
-
* Ties are broken by the raw BM25 score (stable, deterministic).
|
|
61
|
-
*/
|
|
62
48
|
export declare function rerankByQuality(matches: KeywordMatch[]): RerankedMatch[];
|
package/dist/src/rerank.js
CHANGED
|
@@ -101,14 +101,51 @@ export function extractLessonQuality(match) {
|
|
|
101
101
|
* compressed score; a senior-confirmed success (boost ≈ 1.8) gets 148%.
|
|
102
102
|
* Ties are broken by the raw BM25 score (stable, deterministic).
|
|
103
103
|
*/
|
|
104
|
+
/**
|
|
105
|
+
* Wie stark Qualitaetsmerkmale die Rangfolge bewegen duerfen.
|
|
106
|
+
*
|
|
107
|
+
* Bleibt bei 0.6 — dem Wert von vorher. Die Messreihe vom 19.08.2026 zeigt,
|
|
108
|
+
* dass dieser Wert auf echten Daten NICHTS kostet: bei ungestauchter Relevanz
|
|
109
|
+
* liefern 0.6, 0.3 und 0.15 dasselbe Ergebnis (30 Prozent auf Platz 1).
|
|
110
|
+
*
|
|
111
|
+
* Das ist der Grund, hier nichts zu aendern. Der Schaden kam allein von der
|
|
112
|
+
* Stauchung darunter. Wer zwei Dinge gleichzeitig verstellt, weiss hinterher
|
|
113
|
+
* nicht, welches gewirkt hat.
|
|
114
|
+
*/
|
|
115
|
+
const QUALITAETS_GEWICHT = 0.6;
|
|
104
116
|
export function rerankByQuality(matches) {
|
|
105
117
|
if (matches.length === 0)
|
|
106
118
|
return [];
|
|
107
119
|
const reranked = matches.map(m => {
|
|
108
|
-
|
|
120
|
+
// ── Die Relevanz wird NICHT mehr plattgedrueckt ─────────────────────────
|
|
121
|
+
//
|
|
122
|
+
// Hier stand `Math.pow(score, 0.3)`. Das war Absicht: die Relevanz wurde
|
|
123
|
+
// zusammengestaucht, damit die Qualitaetsmerkmale (Zuversicht, Abnahme,
|
|
124
|
+
// Zustimmungen) die Rangfolge mitbestimmen koennen. Aus einem
|
|
125
|
+
// zehnfachen Relevanzvorsprung wurde ein doppelter.
|
|
126
|
+
//
|
|
127
|
+
// Auf dem Pruefstand mit 17 Lektionen war das ein Gewinn: 92,3 statt
|
|
128
|
+
// 69,2 Prozent. Genau diese Zahl steht seit Monaten auf der Landingpage.
|
|
129
|
+
//
|
|
130
|
+
// Auf 498 echten Lektionen, am 19.08.2026 gemessen, ist es der Verlust:
|
|
131
|
+
//
|
|
132
|
+
// Stauchung echter Bestand Pruefstand
|
|
133
|
+
// ^0.3 15 % 92,3 %
|
|
134
|
+
// ^0.6 25 % 76,9 %
|
|
135
|
+
// ^1.0 (keine) 30 % 69,2 %
|
|
136
|
+
//
|
|
137
|
+
// Der gesamte gemessene Vorteil auf dem Pruefstand IST der Schaden auf
|
|
138
|
+
// echten Daten. Bei 17 Lektionen ist der richtige Treffer so eindeutig,
|
|
139
|
+
// dass er auch gestaucht gewinnt. Bei 498 ist die Relevanz das knappe
|
|
140
|
+
// Gut, und wer sie staucht, wirft weg, was er hat.
|
|
141
|
+
const compressed = Math.max(0, m.score);
|
|
109
142
|
const lesson = extractLessonQuality(m);
|
|
110
143
|
const boost = qualityMultiplier(lesson);
|
|
111
|
-
|
|
144
|
+
// Qualitaet wirkt unveraendert auf die UNGESTAUCHTE Relevanz. Damit kann
|
|
145
|
+
// sie einen knappen Textvorsprung noch drehen (eine belegte Loesung schlaegt
|
|
146
|
+
// einen etwas besser passenden Fehlversuch), einen deutlichen aber nicht
|
|
147
|
+
// mehr.
|
|
148
|
+
const finalScore = compressed * (1 - QUALITAETS_GEWICHT + QUALITAETS_GEWICHT * boost);
|
|
112
149
|
return { ...m, finalScore, qualityBoost: boost };
|
|
113
150
|
});
|
|
114
151
|
reranked.sort((a, b) => (b.finalScore - a.finalScore) || (b.score - a.score));
|
package/dist/src/rerank.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rerank.js","sourceRoot":"","sources":["../../src/rerank.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"rerank.js","sourceRoot":"","sources":["../../src/rerank.ts"],"names":[],"mappings":"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"}
|
package/dist/src/search.d.ts
CHANGED
|
@@ -20,11 +20,6 @@ declare function katakanaToRomaji(kata: string): string;
|
|
|
20
20
|
*/
|
|
21
21
|
declare function arabicLightStem(word: string): string;
|
|
22
22
|
declare const CROSS_LINGUAL_MAP: Map<string, string[]>;
|
|
23
|
-
/**
|
|
24
|
-
* Expand a token to its cross-lingual synonyms.
|
|
25
|
-
* Returns synonyms to be added to the token stream (pre-tokenized).
|
|
26
|
-
* CJK synonyms are NOT pre-bigram'd here — caller handles that.
|
|
27
|
-
*/
|
|
28
23
|
declare function expandCrossLingual(token: string): string[];
|
|
29
24
|
/**
|
|
30
25
|
* Tokenize text into meaningful keywords.
|
|
@@ -93,21 +88,65 @@ declare function levenshtein(a: string, b: string): number;
|
|
|
93
88
|
/** Extract a timestamp from JSON content (looks for "ts" or "created" fields). */
|
|
94
89
|
declare function extractTimestamp(content: string): number | undefined;
|
|
95
90
|
/** Recency multiplier: 1.0 for now, 0.5 after half-life days, exponential decay. */
|
|
91
|
+
/**
|
|
92
|
+
* Frische als STICHENTSCHEID, nicht als Treiber.
|
|
93
|
+
*
|
|
94
|
+
* ── Was hier schiefging, und wie lange ──────────────────────────────────────
|
|
95
|
+
*
|
|
96
|
+
* Bis zum 19.08.2026 lag der Bereich bei [0.5, 1.5]. Eine ganz frische Lektion
|
|
97
|
+
* bekam damit das DREIFACHE einer 79 Tage alten — unabhaengig davon, wie gut
|
|
98
|
+
* sie zur Frage passt. Bei einem Bestand, in dem viele Datensaetze aehnlich
|
|
99
|
+
* mittelmaessig passen, entscheidet ein solcher Faktor die Rangfolge allein.
|
|
100
|
+
*
|
|
101
|
+
* Gemessen an 498 echten Lektionen mit 20 Fragen. Nur diesen Bereich zu
|
|
102
|
+
* verschmaelern, sonst nichts:
|
|
103
|
+
*
|
|
104
|
+
* Bereich auf Platz 1 Median-Platz
|
|
105
|
+
* [0.5, 1.5] 1/20 101
|
|
106
|
+
* [0.75, 1.25] 2/20 53
|
|
107
|
+
* [0.9, 1.1] 3/20 39
|
|
108
|
+
* [0.95, 1.05] 5/20 36
|
|
109
|
+
* ohne Frische 6/20 29
|
|
110
|
+
*
|
|
111
|
+
* ── Warum trotzdem nicht ganz weg ───────────────────────────────────────────
|
|
112
|
+
*
|
|
113
|
+
* Weil Lektionen einander korrigieren. kanzlei:coach-timeout-root-cause traegt
|
|
114
|
+
* woertlich "korrigiert eine frueher falsch gespeicherte Lesson". Ohne jede
|
|
115
|
+
* Frische gewinnt bei gleichwertigem Text die falsche alte Fassung, und zwar
|
|
116
|
+
* fuer immer.
|
|
117
|
+
*
|
|
118
|
+
* ±5 Prozent heisst in der Praxis: die Reihenfolge aendert sich nur zwischen
|
|
119
|
+
* Datensaetzen, die ohnehin fast gleich gut passen. Genau das soll ein
|
|
120
|
+
* Stichentscheid tun.
|
|
121
|
+
*
|
|
122
|
+
* Ohne Frische mass sich um EINE Frage besser. Bei 20 Fragen ist das kein
|
|
123
|
+
* Unterschied, auf den man eine Entscheidung stuetzt.
|
|
124
|
+
*
|
|
125
|
+
* ── Warum es Monate unentdeckt blieb ────────────────────────────────────────
|
|
126
|
+
*
|
|
127
|
+
* Der Fixture-Bench hat 17 Lektionen, mit Zeitstempeln und fast derselben
|
|
128
|
+
* Altersspanne (2,7x gegen 3,0x). Am fehlenden Zeitstempel lag es also NICHT.
|
|
129
|
+
* Es lag an der Menge: bei 16 Mitbewerbern gewinnt der Textabgleich auch gegen
|
|
130
|
+
* den Faktor 3, weil ein seltenes Wort rund zehnmal so schwer wiegt wie ein
|
|
131
|
+
* haeufiges. Bei 497 Mitbewerbern gibt es genug Datensaetze mit aehnlichem
|
|
132
|
+
* Textwert — und dann entscheidet der Faktor.
|
|
133
|
+
*
|
|
134
|
+
* Ein Fehler, der erst ab einer gewissen Menge auftritt, ist auf einem kleinen
|
|
135
|
+
* Pruefstand unsichtbar. Nicht schwer zu finden. Unsichtbar.
|
|
136
|
+
*/
|
|
96
137
|
declare function recencyBoost(timestampMs: number | undefined): number;
|
|
97
138
|
/**
|
|
98
|
-
*
|
|
99
|
-
*
|
|
100
|
-
*
|
|
101
|
-
*
|
|
102
|
-
*
|
|
103
|
-
*
|
|
104
|
-
*
|
|
105
|
-
* │ ↓ for each sub-query │
|
|
106
|
-
* │ Tokenize → BM25+ score per doc → Bigram boost → Fuzzy match │
|
|
107
|
-
* │ ↓ merge & deduplicate │
|
|
108
|
-
* │ Recency boost → Sort → Top-K │
|
|
109
|
-
* └─────────────────────────────────────────────────────────────────┘
|
|
139
|
+
* Wirft alle Bestaende weg. Ruft der Schreibpfad auf, wenn eine Lektion neu
|
|
140
|
+
* geschrieben wurde — ohne das waere sie bis zu eine Minute unsichtbar.
|
|
141
|
+
*
|
|
142
|
+
* Absichtlich ALLE und nicht nur die betroffene Verbindung: der Aufrufer
|
|
143
|
+
* kennt die Verbindung an dieser Stelle nicht immer, und ein Bestand zu viel
|
|
144
|
+
* neu zu bauen kostet eine Sekunde. Einen zu wenig zu entwerten kostet eine
|
|
145
|
+
* Minute Unsichtbarkeit.
|
|
110
146
|
*/
|
|
147
|
+
export declare function wortindexEntwerten(): void;
|
|
148
|
+
/** Nur fuer Tests: wie viele Bestaende seit dem letzten Entwerten stehen. */
|
|
149
|
+
export declare function wortindexStand(): number;
|
|
111
150
|
declare function keywordSearch(redis: Redis, patterns: string[], query: string, topK?: number): Promise<KeywordMatch[]>;
|
|
112
151
|
export { tokenize, splitMultiQuery, levenshtein, recencyBoost, extractTimestamp, STOPWORDS, katakanaToRomaji, arabicLightStem, expandCrossLingual, CROSS_LINGUAL_MAP };
|
|
113
152
|
export type { KeywordMatch };
|