Normalize mistaken user owners across extraction and cognition

This commit is contained in:
Youzini-afk
2026-04-09 23:38:14 +08:00
parent d1b07d8cbb
commit 5c9a8a9df1
7 changed files with 512 additions and 98 deletions

View File

@@ -4,6 +4,10 @@
import { getNodeColors } from './themes.js';
import { getGraphNodeLabel, getNodeDisplayName } from '../graph/node-labels.js';
import { normalizeMemoryScope } from '../graph/memory-scope.js';
import {
aliasSetMatchesValue,
buildUserPovAliasNormalizedSet,
} from '../runtime/user-alias-utils.js';
/**
* @typedef {Object} GraphNode
@@ -95,83 +99,10 @@ function normalizeKeyForPartition(value) {
return String(value ?? '').trim().toLowerCase();
}
/**
* 宿主别名与 POV owner 比对:忽略大小写、多空格、常见中英文标点/符号差NFKC
* 不用于 charMap 主键,仅用于「是否同一用户」的宽松匹配。
*/
function normalizeAliasMatchKey(value) {
let s = String(value ?? '');
if (typeof s.normalize === 'function') {
try {
s = s.normalize('NFKC');
} catch {
/* ignore */
}
}
s = s.trim().toLowerCase();
// 标点、间隔号、各类空白等统一成空格,再压成单空格
s = s.replace(
/[\s!"#$%&'()*+,\-./:;<=>?@[\\\]^_`{|}~\u00b7\u3000-\u303f\uff01-\uff0f\uff1a-\uff20\uff3b-\uff40\uff5b-\uff65\u2000-\u206f\u2e00-\u2e7f]+/g,
' ',
);
s = s.replace(/\s+/g, ' ').trim();
return s;
}
/** 同一名称的多种可比形式(兼容老数据只做了 trim+lower */
function collectAliasMatchVariants(raw) {
const variants = [];
const leg = normalizeKeyForPartition(raw);
if (leg) variants.push(leg);
const soft = normalizeAliasMatchKey(raw);
if (soft) {
variants.push(soft);
const compact = soft.replace(/\s/g, '');
if (compact && compact !== soft) variants.push(compact);
}
return variants;
}
function addAliasMatchVariantsToSet(set, raw) {
for (const k of collectAliasMatchVariants(raw)) {
if (k) set.add(k);
}
}
/**
* 将宿主侧「用户显示名」候选归一为分区用 Set用于把误标为 character 的用户 POV 拉回用户区。
* @param {string|string[]|{name1?:string,userName?:string,personaName?:string,aliases?:string[]}|null|undefined} hints
* @returns {Set<string>}
*/
export function buildUserPovAliasNormalizedSet(hints) {
const set = new Set();
if (hints == null) return set;
const ingest = (v) => addAliasMatchVariantsToSet(set, v);
if (typeof hints === 'string') {
ingest(hints);
return set;
}
if (Array.isArray(hints)) {
for (const item of hints) ingest(item);
return set;
}
if (typeof hints === 'object') {
ingest(hints.name1);
ingest(hints.userName);
ingest(hints.personaName);
if (Array.isArray(hints.aliases)) {
for (const a of hints.aliases) ingest(a);
}
}
return set;
}
function scopeMatchesHostUserAliases(scope, aliasSet) {
if (!(aliasSet instanceof Set) || aliasSet.size === 0) return false;
for (const field of [scope.ownerName, scope.ownerId]) {
for (const k of collectAliasMatchVariants(field)) {
if (k && aliasSet.has(k)) return true;
}
if (aliasSetMatchesValue(aliasSet, field)) return true;
}
return false;
}

View File

@@ -1,6 +1,5 @@
// ST-BME: 操控面板交互逻辑
import { getContext } from "../../../../extensions.js";
import { GraphRenderer } from "./graph-renderer.js";
import { getNodeDisplayName } from "../graph/node-labels.js";
import {
@@ -9,6 +8,7 @@ import {
normalizeMemoryScope,
} from "../graph/memory-scope.js";
import { listKnowledgeOwners } from "../graph/knowledge-state.js";
import { getHostUserAliasHints } from "../runtime/user-alias-utils.js";
import {
describeNodeStoryTime,
describeStoryTime,
@@ -2862,16 +2862,7 @@ function _getInjectionSectionFlavor(title = "") {
/** SillyTavern 用户显示名name1用于图谱分区误标为角色的用户 POV 强制归用户区 */
function _hostUserPovAliasHintsForGraph() {
try {
const ctx = typeof getContext === "function" ? getContext() : null;
const out = [];
if (ctx?.name1 && String(ctx.name1).trim()) {
out.push(String(ctx.name1).trim());
}
return out;
} catch {
return [];
}
return getHostUserAliasHints();
}
function _refreshGraph() {