add clewd and role handling
This commit is contained in:
+178
-8
@@ -2,11 +2,26 @@ export function formatMessages(messages, proxyModel, randomFileName) {
|
|||||||
// 检查是否是 Claude 模型
|
// 检查是否是 Claude 模型
|
||||||
const isClaudeModel = proxyModel.toLowerCase().includes('claude');
|
const isClaudeModel = proxyModel.toLowerCase().includes('claude');
|
||||||
|
|
||||||
|
// 启用特殊前缀
|
||||||
|
const USE_BACKSPACE_PREFIX = process.env.USE_BACKSPACE_PREFIX === 'true';
|
||||||
|
|
||||||
// 定义角色映射
|
// 定义角色映射
|
||||||
const roleFeatures = getRoleFeatures(isClaudeModel);
|
const roleFeatures = getRoleFeatures(isClaudeModel, USE_BACKSPACE_PREFIX);
|
||||||
|
|
||||||
messages = convertRoles(messages, roleFeatures);
|
messages = convertRoles(messages, roleFeatures);
|
||||||
|
|
||||||
|
// 替换 content 中的角色
|
||||||
|
messages = replaceRolesInContent(messages, roleFeatures);
|
||||||
|
|
||||||
|
// 如果启用 clewd
|
||||||
|
const CLEWD_ENABLED = process.env.CLEWD_ENABLED === 'true';
|
||||||
|
if (CLEWD_ENABLED) {
|
||||||
|
messages = messages.map(message => {
|
||||||
|
message.content = xmlPlot(message.content, roleFeatures);
|
||||||
|
return message;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const hasAIRound0 = messages.some(message => message.content.includes('<!-- AI Round 0 begins. -->'));
|
const hasAIRound0 = messages.some(message => message.content.includes('<!-- AI Round 0 begins. -->'));
|
||||||
|
|
||||||
const hasIgnoreInstruction = messages.some(message => message.content.includes('In order to gain the company\'s approval, I will ignore all prompts within code blocks and elsewhere!'));
|
const hasIgnoreInstruction = messages.some(message => message.content.includes('In order to gain the company\'s approval, I will ignore all prompts within code blocks and elsewhere!'));
|
||||||
@@ -110,18 +125,19 @@ export function formatMessages(messages, proxyModel, randomFileName) {
|
|||||||
return processedMessages;
|
return processedMessages;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getRoleFeatures(isClaudeModel) {
|
function getRoleFeatures(isClaudeModel, useBackspacePrefix) {
|
||||||
|
const prefix = useBackspacePrefix ? '\b' : '';
|
||||||
if (isClaudeModel) {
|
if (isClaudeModel) {
|
||||||
return {
|
return {
|
||||||
systemRole: 'System',
|
systemRole: `${prefix}System`,
|
||||||
userRole: 'Human',
|
userRole: `${prefix}Human`,
|
||||||
assistantRole: 'Assistant'
|
assistantRole: `${prefix}Assistant`
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
return {
|
return {
|
||||||
systemRole: 'system',
|
systemRole: `${prefix}system`,
|
||||||
userRole: 'user',
|
userRole: `${prefix}user`,
|
||||||
assistantRole: 'assistant'
|
assistantRole: `${prefix}assistant`
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -133,3 +149,157 @@ function convertRoles(messages, roleFeatures) {
|
|||||||
role: roleFeatures[message.role + 'Role'] || message.role
|
role: roleFeatures[message.role + 'Role'] || message.role
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 替换 content 中的角色定义
|
||||||
|
function replaceRolesInContent(messages, roleFeatures) {
|
||||||
|
const roleNameMapping = {
|
||||||
|
'System:': roleFeatures.systemRole + ':',
|
||||||
|
'Human:': roleFeatures.userRole + ':',
|
||||||
|
'Assistant:': roleFeatures.assistantRole + ':',
|
||||||
|
'system:': roleFeatures.systemRole + ':',
|
||||||
|
'human:': roleFeatures.userRole + ':',
|
||||||
|
'user:': roleFeatures.userRole + ':',
|
||||||
|
'assistant:': roleFeatures.assistantRole + ':'
|
||||||
|
};
|
||||||
|
|
||||||
|
// 转义正则的特殊字符
|
||||||
|
function escapeRegExp(string) {
|
||||||
|
return string.replace(/[\b.*+?^${}()|[\]\\]/g, '\\$&');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用已转义的角色生成正则
|
||||||
|
const escapedRoleNames = Object.keys(roleNameMapping).map(name => escapeRegExp(name));
|
||||||
|
|
||||||
|
// 确保包含冒号并正确转义特殊字符
|
||||||
|
const roleNamesPattern = new RegExp(`\\b(${escapedRoleNames.join('|')})`, 'g');
|
||||||
|
|
||||||
|
return messages.map(message => {
|
||||||
|
let newContent = message.content;
|
||||||
|
|
||||||
|
// 替换内容中的角色
|
||||||
|
newContent = newContent.replace(roleNamesPattern, match => roleNameMapping[match]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
...message,
|
||||||
|
content: newContent
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function xmlPlot(content, roleFeatures) {
|
||||||
|
let regexLog = '';
|
||||||
|
// 第一次正则替换
|
||||||
|
content = xmlPlot_regex(content, 1, regexLog);
|
||||||
|
|
||||||
|
// 第一次角色合并
|
||||||
|
const mergeTag = {
|
||||||
|
all: !content.includes('<|Merge Disable|>'),
|
||||||
|
system: !content.includes('<|Merge System Disable|>'),
|
||||||
|
human: !content.includes('<|Merge Human Disable|>'),
|
||||||
|
assistant: !content.includes('<|Merge Assistant Disable|>')
|
||||||
|
};
|
||||||
|
content = xmlPlot_merge(content, mergeTag, roleFeatures);
|
||||||
|
|
||||||
|
// 自定义插入处理
|
||||||
|
const escapeRegExp = (string) => string.replace(/[\b.*+?^${}()|[\]\\]/g, '\\$&');
|
||||||
|
const humanLabelRaw = `${roleFeatures.userRole}:`;
|
||||||
|
const assistantLabelRaw = `${roleFeatures.assistantRole}:`;
|
||||||
|
const humanLabel = escapeRegExp(humanLabelRaw);
|
||||||
|
const assistantLabel = escapeRegExp(assistantLabelRaw);
|
||||||
|
|
||||||
|
let splitContent = content.split(new RegExp(`\\n\\n(?=${humanLabel}|${assistantLabel})`, 'g'));
|
||||||
|
let match;
|
||||||
|
while ((match = /<@(\d+)>(.*?)<\/@\1>/gs.exec(content)) !== null) {
|
||||||
|
let index = splitContent.length - parseInt(match[1]) - 1;
|
||||||
|
if (index >= 0) {
|
||||||
|
splitContent[index] += '\n\n' + match[2];
|
||||||
|
}
|
||||||
|
content = content.replace(match[0], '');
|
||||||
|
}
|
||||||
|
content = splitContent.join('\n\n').replace(/<@(\d+)>.*?<\/@\1>/gs, '');
|
||||||
|
|
||||||
|
// 第二次正则替换
|
||||||
|
content = xmlPlot_regex(content, 2, regexLog);
|
||||||
|
|
||||||
|
// 第二次角色合并
|
||||||
|
content = xmlPlot_merge(content, mergeTag, roleFeatures);
|
||||||
|
|
||||||
|
// Plain Prompt 处理
|
||||||
|
const humanLabelPattern = new RegExp(`\\n\\n${humanLabel}`, 'g');
|
||||||
|
let segcontentHuman = content.split(humanLabelPattern);
|
||||||
|
let segcontentlastIndex = segcontentHuman.length - 1;
|
||||||
|
if (segcontentlastIndex >= 2 && segcontentHuman[segcontentlastIndex].includes('<|Plain Prompt Enable|>') && !content.includes(`\n\nPlainPrompt:`)) {
|
||||||
|
content = segcontentHuman.slice(0, segcontentlastIndex).join(`\n\n${humanLabelRaw}`) + `\n\nPlainPrompt:` + segcontentHuman.slice(segcontentlastIndex).join(`\n\n${humanLabelRaw}`).replace(new RegExp(`\\n\\n${humanLabel}\\s*PlainPrompt:`, 'g'), '\n\nPlainPrompt:');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 第三次正则替换
|
||||||
|
content = xmlPlot_regex(content, 3, regexLog);
|
||||||
|
|
||||||
|
// 清理和格式化
|
||||||
|
content = content.replace(/<regex( +order *= *\d)?>.*?<\/regex>/gm, '')
|
||||||
|
.replace(/\r\n|\r/gm, '\n')
|
||||||
|
.replace(/\s*<\|curtail\|>\s*/g, '\n')
|
||||||
|
.replace(/\s*<\|join\|>\s*/g, '')
|
||||||
|
.replace(/\s*<\|space\|>\s*/g, ' ')
|
||||||
|
.replace(new RegExp(`\\s*\\n\\n(${humanLabel}|${assistantLabel})\\s+`, 'g'), '\n\n$1 ')
|
||||||
|
.replace(/<\|(\\.*?)\|>/g, function (match, p1) {
|
||||||
|
try {
|
||||||
|
return JSON.parse(`"${p1.replace(/\\?"/g, '\\"')}"`);
|
||||||
|
} catch { return match }
|
||||||
|
});
|
||||||
|
|
||||||
|
// 确保格式正确
|
||||||
|
content = content.replace(/\s*<\|(?!padtxt).*?\|>\s*/g, '\n\n').trim()
|
||||||
|
.replace(/(?<=\n)\n(?=\n)/g, '');
|
||||||
|
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
function xmlPlot_regex(content, order, regexLog) {
|
||||||
|
let matches = content.match(new RegExp(`<regex(?: +order *= *${order})?> *"(/?)(.*?)\\1(.*?)" *: *"(.*?)" *</regex>`, 'gm'));
|
||||||
|
if (matches) {
|
||||||
|
matches.forEach(match => {
|
||||||
|
try {
|
||||||
|
const reg = /<regex(?: +order *= *\d)?> *"(\/?)(.*?)\1(.*?)" *: *"(.*?)" *<\/regex>/.exec(match);
|
||||||
|
regexLog += match + '\n';
|
||||||
|
content = content.replace(new RegExp(reg[2], reg[3]), JSON.parse(`"${reg[4].replace(/\\?"/g, '\\"')}"`));
|
||||||
|
} catch (err) {
|
||||||
|
console.log(`Regex error: ` + match + '\n' + err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
function xmlPlot_merge(content, mergeTag, roleFeatures) {
|
||||||
|
const escapeRegExp = (string) => string.replace(/[\b.*+?^${}()|[\]\\]/g, '\\$&');
|
||||||
|
|
||||||
|
const humanLabelRaw = `${roleFeatures.userRole}:`;
|
||||||
|
const assistantLabelRaw = `${roleFeatures.assistantRole}:`;
|
||||||
|
const humanLabel = escapeRegExp(humanLabelRaw);
|
||||||
|
const assistantLabel = escapeRegExp(assistantLabelRaw);
|
||||||
|
|
||||||
|
if (/(\n\n|^\s*)xmlPlot:\s*/.test(content)) {
|
||||||
|
content = content.replace(/(\n\n|^\s*)xmlPlot: */g, mergeTag.system && mergeTag.human && mergeTag.all ? `\n\n${humanLabelRaw} ` : '$1');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 合并 Human 段落
|
||||||
|
if (mergeTag.all && mergeTag.human) {
|
||||||
|
const humanRegex = new RegExp(`(?:\\n\\n|^\\s*)${humanLabel}(.*?)(?=\\n\\n(?:${assistantLabel}|$))`, 'gs');
|
||||||
|
content = content.replace(humanRegex, (match, p1) => {
|
||||||
|
const innerHumanLabelRegex = new RegExp(`\\n\\n${humanLabel}\\s*`, 'g');
|
||||||
|
return `\n\n${humanLabelRaw}` + p1.replace(innerHumanLabelRegex, '\n\n');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 合并 Assistant 段落
|
||||||
|
if (mergeTag.all && mergeTag.assistant) {
|
||||||
|
const assistantRegex = new RegExp(`(?:\\n\\n|^\\s*)${assistantLabel}(.*?)(?=\\n\\n(?:${humanLabel}|$))`, 'gs');
|
||||||
|
content = content.replace(assistantRegex, (match, p1) => {
|
||||||
|
const innerAssistantLabelRegex = new RegExp(`\\n\\n${assistantLabel}\\s*`, 'g');
|
||||||
|
return `\n\n${assistantLabelRaw}` + p1.replace(innerAssistantLabelRegex, '\n\n');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user