2023-09-16 17:48:06 +02:00
|
|
|
/**
|
|
|
|
* Convert a prompt from the ChatML objects to the format used by Claude.
|
|
|
|
* @param {object[]} messages Array of messages
|
|
|
|
* @param {boolean} addHumanPrefix Add Human prefix
|
|
|
|
* @param {boolean} addAssistantPostfix Add Assistant postfix
|
2023-11-21 21:11:26 +01:00
|
|
|
* @param {boolean} withSystemPrompt Build system prompt before "\n\nHuman: "
|
2023-09-16 17:48:06 +02:00
|
|
|
* @returns {string} Prompt for Claude
|
|
|
|
* @copyright Prompt Conversion script taken from RisuAI by kwaroran (GPLv3).
|
|
|
|
*/
|
2023-11-21 21:11:26 +01:00
|
|
|
function convertClaudePrompt(messages, addHumanPrefix, addAssistantPostfix, withSystemPrompt) {
|
2023-09-16 17:48:06 +02:00
|
|
|
// Claude doesn't support message names, so we'll just add them to the message content.
|
|
|
|
for (const message of messages) {
|
2023-12-02 19:04:51 +01:00
|
|
|
if (message.name && message.role !== 'system') {
|
|
|
|
message.content = message.name + ': ' + message.content;
|
2023-09-16 17:48:06 +02:00
|
|
|
delete message.name;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-21 21:11:26 +01:00
|
|
|
let systemPrompt = '';
|
|
|
|
if (withSystemPrompt) {
|
2023-11-24 21:58:20 +01:00
|
|
|
let lastSystemIdx = -1;
|
|
|
|
|
|
|
|
for (let i = 0; i < messages.length - 1; i++) {
|
|
|
|
const message = messages[i];
|
2023-12-02 19:04:51 +01:00
|
|
|
if (message.role === 'system' && !message.name) {
|
2023-11-21 21:11:26 +01:00
|
|
|
systemPrompt += message.content + '\n\n';
|
|
|
|
} else {
|
2023-11-24 21:58:20 +01:00
|
|
|
lastSystemIdx = i - 1;
|
2023-11-21 21:11:26 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2023-11-24 21:58:20 +01:00
|
|
|
if (lastSystemIdx >= 0) {
|
|
|
|
messages.splice(0, lastSystemIdx + 1);
|
|
|
|
}
|
2023-11-21 21:11:26 +01:00
|
|
|
}
|
|
|
|
|
2023-09-16 17:48:06 +02:00
|
|
|
let requestPrompt = messages.map((v) => {
|
|
|
|
let prefix = '';
|
|
|
|
switch (v.role) {
|
2023-12-02 19:04:51 +01:00
|
|
|
case 'assistant':
|
|
|
|
prefix = '\n\nAssistant: ';
|
2023-12-02 20:11:06 +01:00
|
|
|
break;
|
2023-12-02 19:04:51 +01:00
|
|
|
case 'user':
|
|
|
|
prefix = '\n\nHuman: ';
|
2023-12-02 20:11:06 +01:00
|
|
|
break;
|
2023-12-02 19:04:51 +01:00
|
|
|
case 'system':
|
2023-09-16 17:48:06 +02:00
|
|
|
// According to the Claude docs, H: and A: should be used for example conversations.
|
2023-12-02 19:04:51 +01:00
|
|
|
if (v.name === 'example_assistant') {
|
|
|
|
prefix = '\n\nA: ';
|
|
|
|
} else if (v.name === 'example_user') {
|
|
|
|
prefix = '\n\nH: ';
|
2023-09-16 17:48:06 +02:00
|
|
|
} else {
|
2023-12-02 19:04:51 +01:00
|
|
|
prefix = '\n\n';
|
2023-09-16 17:48:06 +02:00
|
|
|
}
|
2023-12-02 20:11:06 +01:00
|
|
|
break;
|
2023-09-16 17:48:06 +02:00
|
|
|
}
|
|
|
|
return prefix + v.content;
|
|
|
|
}).join('');
|
|
|
|
|
|
|
|
if (addHumanPrefix) {
|
2023-12-02 19:04:51 +01:00
|
|
|
requestPrompt = '\n\nHuman: ' + requestPrompt;
|
2023-09-16 17:48:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (addAssistantPostfix) {
|
|
|
|
requestPrompt = requestPrompt + '\n\nAssistant: ';
|
|
|
|
}
|
|
|
|
|
2023-11-21 21:11:26 +01:00
|
|
|
if (withSystemPrompt) {
|
|
|
|
requestPrompt = systemPrompt + requestPrompt;
|
|
|
|
}
|
|
|
|
|
2023-09-16 17:48:06 +02:00
|
|
|
return requestPrompt;
|
|
|
|
}
|
|
|
|
|
2023-12-14 16:28:54 +01:00
|
|
|
function convertGooglePrompt(messages, type) {
|
2023-12-14 06:49:50 +01:00
|
|
|
const contents = [];
|
|
|
|
let lastRole = '';
|
|
|
|
let currentText = '';
|
2023-12-14 16:28:54 +01:00
|
|
|
|
|
|
|
const isMultimodal = type === 'gemini-pro-vision';
|
|
|
|
|
|
|
|
if (isMultimodal) {
|
|
|
|
const combinedText = messages.map((message) => {
|
|
|
|
const role = message.role === 'assistant' ? 'MODEL: ' : 'USER: ';
|
|
|
|
return role + message.content;
|
|
|
|
}).join('\n\n').trim();
|
|
|
|
|
|
|
|
const imageEntry = messages.find((message) => message.content[1]?.image_url);
|
|
|
|
contents.push({
|
|
|
|
parts: [
|
|
|
|
{ text: combinedText },
|
|
|
|
{
|
|
|
|
inlineData: {
|
|
|
|
mimeType: 'image/png',
|
|
|
|
data: imageEntry.content[1].image_url.url ?? '',
|
|
|
|
},
|
|
|
|
},
|
|
|
|
],
|
|
|
|
role: 'user',
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
messages.forEach((message, index) => {
|
|
|
|
const role = message.role === 'assistant' ? 'model' : 'user';
|
|
|
|
if (lastRole === role) {
|
|
|
|
currentText += '\n\n' + message.content;
|
|
|
|
} else {
|
|
|
|
if (currentText !== '') {
|
|
|
|
contents.push({
|
|
|
|
parts: [{ text: currentText.trim() }],
|
|
|
|
role: lastRole,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
currentText = message.content;
|
|
|
|
lastRole = role;
|
|
|
|
}
|
|
|
|
if (index === messages.length - 1) {
|
2023-12-14 06:49:50 +01:00
|
|
|
contents.push({
|
|
|
|
parts: [{ text: currentText.trim() }],
|
|
|
|
role: lastRole,
|
|
|
|
});
|
|
|
|
}
|
2023-12-14 16:28:54 +01:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2023-12-14 06:49:50 +01:00
|
|
|
return contents;
|
|
|
|
}
|
|
|
|
|
2023-12-14 15:00:17 +01:00
|
|
|
/**
|
|
|
|
* Convert a prompt from the ChatML objects to the format used by Text Completion API.
|
|
|
|
* @param {object[]} messages Array of messages
|
|
|
|
* @returns {string} Prompt for Text Completion API
|
|
|
|
*/
|
|
|
|
function convertTextCompletionPrompt(messages) {
|
|
|
|
if (typeof messages === 'string') {
|
|
|
|
return messages;
|
|
|
|
}
|
|
|
|
|
|
|
|
const messageStrings = [];
|
|
|
|
messages.forEach(m => {
|
|
|
|
if (m.role === 'system' && m.name === undefined) {
|
|
|
|
messageStrings.push('System: ' + m.content);
|
|
|
|
}
|
|
|
|
else if (m.role === 'system' && m.name !== undefined) {
|
|
|
|
messageStrings.push(m.name + ': ' + m.content);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
messageStrings.push(m.role + ': ' + m.content);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
return messageStrings.join('\n') + '\nassistant:';
|
|
|
|
}
|
|
|
|
|
2023-09-16 17:48:06 +02:00
|
|
|
module.exports = {
|
|
|
|
convertClaudePrompt,
|
2023-12-14 06:49:50 +01:00
|
|
|
convertGooglePrompt,
|
2023-12-14 15:00:17 +01:00
|
|
|
convertTextCompletionPrompt,
|
2023-12-02 20:11:06 +01:00
|
|
|
};
|