34 lines
1.2 KiB
JavaScript
34 lines
1.2 KiB
JavaScript
const SECRET_PATTERNS = [
|
|
/-----BEGIN (?:RSA |EC |OPENSSH )?PRIVATE KEY-----/i,
|
|
/\b(?:password|passwd|api[_ -]?key|access[_ -]?token|refresh[_ -]?token|bearer|client[_ -]?secret)\b/i,
|
|
/(?:密码|口令|令牌|密钥|私钥|验证码)/,
|
|
];
|
|
|
|
export function boundedText(value, maxLength) {
|
|
if (typeof value !== "string") return "";
|
|
return value.trim().slice(0, maxLength);
|
|
}
|
|
|
|
export function safeMemoryText(value, maxLength = 8_000) {
|
|
const text = boundedText(value, maxLength);
|
|
if (SECRET_PATTERNS.some((pattern) => pattern.test(text))) return "[敏感内容未写入记忆]";
|
|
return text;
|
|
}
|
|
|
|
export function words(value) {
|
|
const lowered = boundedText(value, 16_000).toLowerCase();
|
|
const terms = new Set(lowered.match(/[a-z0-9_-]{2,}|[\u3400-\u9fff]{2}/g) ?? []);
|
|
const cjk = [...lowered.matchAll(/[\u3400-\u9fff]/g)].map((match) => match[0]).join("");
|
|
for (let index = 0; index + 1 < cjk.length; index++) terms.add(cjk.slice(index, index + 2));
|
|
return terms;
|
|
}
|
|
|
|
export function similarity(left, right) {
|
|
const a = words(left);
|
|
const b = words(right);
|
|
if (!a.size || !b.size) return 0;
|
|
let overlap = 0;
|
|
for (const term of a) if (b.has(term)) overlap++;
|
|
return overlap / Math.sqrt(a.size * b.size);
|
|
}
|