@@ -47,6 +47,75 @@ function readNumber(value: unknown, fallback = 0) {
|
||||
return typeof value === 'number' && Number.isFinite(value) ? value : fallback;
|
||||
}
|
||||
|
||||
function countKeywordMatches(text: string, keywords: string[]) {
|
||||
return keywords.reduce(
|
||||
(count, keyword) => (text.includes(keyword) ? count + 1 : count),
|
||||
0,
|
||||
);
|
||||
}
|
||||
|
||||
function clampAffinityDelta(value: number) {
|
||||
return Math.max(-3, Math.min(3, value));
|
||||
}
|
||||
|
||||
function computeNpcChatAffinityDelta(params: {
|
||||
playerMessage: string;
|
||||
npcReply: string;
|
||||
chattedCount: number;
|
||||
}) {
|
||||
const playerMessage = params.playerMessage.trim();
|
||||
const npcReply = params.npcReply.trim();
|
||||
const positiveKeywords = [
|
||||
'谢谢',
|
||||
'辛苦',
|
||||
'抱歉',
|
||||
'理解',
|
||||
'相信',
|
||||
'放心',
|
||||
'一起',
|
||||
'帮你',
|
||||
'在意',
|
||||
'关心',
|
||||
];
|
||||
const negativeKeywords = [
|
||||
'闭嘴',
|
||||
'滚',
|
||||
'少废话',
|
||||
'威胁',
|
||||
'骗',
|
||||
'不信',
|
||||
'别装',
|
||||
'快说',
|
||||
'审问',
|
||||
'怀疑',
|
||||
];
|
||||
const warmReplyKeywords = ['可以', '愿意', '放心', '谢谢', '明白', '好'];
|
||||
const coldReplyKeywords = ['没必要', '不想', '别问', '与你无关', '算了', '住口'];
|
||||
|
||||
const positiveScore =
|
||||
countKeywordMatches(playerMessage, positiveKeywords) +
|
||||
countKeywordMatches(npcReply, warmReplyKeywords);
|
||||
const negativeScore =
|
||||
countKeywordMatches(playerMessage, negativeKeywords) +
|
||||
countKeywordMatches(npcReply, coldReplyKeywords);
|
||||
|
||||
if (positiveScore === 0 && negativeScore === 0) {
|
||||
return params.chattedCount === 0 ? 1 : 0;
|
||||
}
|
||||
|
||||
if (positiveScore > negativeScore) {
|
||||
const baseDelta =
|
||||
positiveScore - negativeScore + (params.chattedCount <= 1 ? 1 : 0);
|
||||
return clampAffinityDelta(baseDelta);
|
||||
}
|
||||
|
||||
if (negativeScore > positiveScore) {
|
||||
return clampAffinityDelta(positiveScore - negativeScore);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
function describeAffinityShift(affinityDelta: number) {
|
||||
if (affinityDelta >= 8) return '态度明显软化了下来。';
|
||||
if (affinityDelta >= 5) return '态度比刚才亲近了一些。';
|
||||
@@ -153,7 +222,11 @@ export async function streamNpcChatTurnFromOrchestrator(
|
||||
const suggestions = parseLineListContent(suggestionText, 3);
|
||||
const npcState = readRecord(params.payload.npcState);
|
||||
const chattedCount = readNumber(npcState?.chattedCount, 0);
|
||||
const affinityDelta = Math.max(2, 6 - chattedCount);
|
||||
const affinityDelta = computeNpcChatAffinityDelta({
|
||||
playerMessage: params.payload.playerMessage,
|
||||
npcReply: npcReply || streamedReply,
|
||||
chattedCount,
|
||||
});
|
||||
|
||||
writeSseEvent(params.response, 'complete', {
|
||||
npcReply: npcReply || streamedReply,
|
||||
|
||||
@@ -353,7 +353,7 @@ export function buildCharacterPanelChatSummaryPrompt(
|
||||
}
|
||||
|
||||
function buildNpcDialoguePromptBase(
|
||||
payload: NpcChatDialogueRequest | NpcRecruitDialogueRequest,
|
||||
payload: NpcChatDialogueRequest | NpcChatTurnRequest | NpcRecruitDialogueRequest,
|
||||
) {
|
||||
const encounter = describeEncounter(payload.encounter);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user