Seed
diff --git a/public/scripts/openai.js b/public/scripts/openai.js
index 8e2dae2e2..e4ba08ae0 100644
--- a/public/scripts/openai.js
+++ b/public/scripts/openai.js
@@ -1812,6 +1812,7 @@ async function sendOpenAIRequest(type, messages, signal) {
const isPerplexity = oai_settings.chat_completion_source == chat_completion_sources.PERPLEXITY;
const isGroq = oai_settings.chat_completion_source == chat_completion_sources.GROQ;
const is01AI = oai_settings.chat_completion_source == chat_completion_sources.ZEROONEAI;
+ const isNano = oai_settings.chat_completion_source == chat_completion_sources.NANOGPT;
const isTextCompletion = isOAI && textCompletionModels.includes(oai_settings.openai_model);
const isQuiet = type === 'quiet';
const isImpersonate = type === 'impersonate';
@@ -1971,7 +1972,7 @@ async function sendOpenAIRequest(type, messages, signal) {
delete generate_data.stop;
}
- if ((isOAI || isOpenRouter || isMistral || isCustom || isCohere) && oai_settings.seed >= 0) {
+ if ((isOAI || isOpenRouter || isMistral || isCustom || isCohere || isNano) && oai_settings.seed >= 0) {
generate_data['seed'] = oai_settings.seed;
}
From 79700fd983a3297407807848755e5a003886b165 Mon Sep 17 00:00:00 2001
From: Cohee <18619528+Cohee1207@users.noreply.github.com>
Date: Wed, 4 Dec 2024 00:44:50 +0200
Subject: [PATCH 4/8] Add Kobold Lite chats import
---
public/script.js | 54 +++++++++++---------
public/scripts/group-chats.js | 56 +++++++++++----------
src/endpoints/chats.js | 93 +++++++++++++++++++++++++----------
3 files changed, 129 insertions(+), 74 deletions(-)
diff --git a/public/script.js b/public/script.js
index 6f34c2440..5205a27cd 100644
--- a/public/script.js
+++ b/public/script.js
@@ -7754,25 +7754,31 @@ export async function saveChatConditional() {
}
}
-async function importCharacterChat(formData) {
- await jQuery.ajax({
- type: 'POST',
- url: '/api/chats/import',
- data: formData,
- beforeSend: function () {
- },
- cache: false,
- contentType: false,
- processData: false,
- success: async function (data) {
- if (data.res) {
- await displayPastChats();
- }
- },
- error: function () {
- $('#create_button').removeAttr('disabled');
- },
+/**
+ * Saves the chat to the server.
+ * @param {FormData} formData Form data to send to the server.
+ * @param {EventTarget} eventTarget Event target to trigger the event on.
+ */
+async function importCharacterChat(formData, eventTarget) {
+ const headers = getRequestHeaders();
+ delete headers['Content-Type'];
+ const fetchResult = await fetch('/api/chats/import', {
+ method: 'POST',
+ body: formData,
+ headers: headers,
+ cache: 'no-cache',
});
+
+ if (fetchResult.ok) {
+ const data = await fetchResult.json();
+ if (data.res) {
+ await displayPastChats();
+ }
+ }
+
+ if (eventTarget instanceof HTMLInputElement) {
+ eventTarget.value = '';
+ }
}
function updateViewMessageIds(startFromZero = false) {
@@ -10829,13 +10835,13 @@ jQuery(async function () {
});
$('#chat_import_file').on('change', async function (e) {
- var file = e.target.files[0];
+ const file = e.target.files[0];
if (!file) {
return;
}
- var ext = file.name.match(/\.(\w+)$/);
+ const ext = file.name.match(/\.(\w+)$/);
if (
!ext ||
(ext[1].toLowerCase() != 'json' && ext[1].toLowerCase() != 'jsonl')
@@ -10848,17 +10854,17 @@ jQuery(async function () {
return;
}
- var format = ext[1].toLowerCase();
+ const format = ext[1].toLowerCase();
$('#chat_import_file_type').val(format);
- var formData = new FormData($('#form_import_chat').get(0));
+ const formData = new FormData($('#form_import_chat').get(0));
formData.append('user_name', name1);
$('#select_chat_div').html('');
if (selected_group) {
- await importGroupChat(formData);
+ await importGroupChat(formData, e.originalEvent.target);
} else {
- await importCharacterChat(formData);
+ await importCharacterChat(formData, e.originalEvent.target);
}
});
diff --git a/public/scripts/group-chats.js b/public/scripts/group-chats.js
index a74ef0d72..0195b1d8d 100644
--- a/public/scripts/group-chats.js
+++ b/public/scripts/group-chats.js
@@ -1863,32 +1863,38 @@ export async function deleteGroupChat(groupId, chatId) {
}
}
-export async function importGroupChat(formData) {
- await jQuery.ajax({
- type: 'POST',
- url: '/api/chats/group/import',
- data: formData,
- beforeSend: function () {
- },
- cache: false,
- contentType: false,
- processData: false,
- success: async function (data) {
- if (data.res) {
- const chatId = data.res;
- const group = groups.find(x => x.id == selected_group);
-
- if (group) {
- group.chats.push(chatId);
- await editGroup(selected_group, true, true);
- await displayPastChats();
- }
- }
- },
- error: function () {
- $('#create_button').removeAttr('disabled');
- },
+/**
+ * Imports a group chat from a file and adds it to the group.
+ * @param {FormData} formData Form data to send to the server
+ * @param {EventTarget} eventTarget Element that triggered the import
+ */
+export async function importGroupChat(formData, eventTarget) {
+ const headers = getRequestHeaders();
+ delete headers['Content-Type'];
+ const fetchResult = await fetch('/api/chats/group/import', {
+ method: 'POST',
+ headers: headers,
+ body: formData,
+ cache: 'no-cache',
});
+
+ if (fetchResult.ok) {
+ const data = await fetchResult.json();
+ if (data.res) {
+ const chatId = data.res;
+ const group = groups.find(x => x.id == selected_group);
+
+ if (group) {
+ group.chats.push(chatId);
+ await editGroup(selected_group, true, true);
+ await displayPastChats();
+ }
+ }
+ }
+
+ if (eventTarget instanceof HTMLInputElement) {
+ eventTarget.value = '';
+ }
}
export async function saveGroupBookmarkChat(groupId, name, metadata, mesId) {
diff --git a/src/endpoints/chats.js b/src/endpoints/chats.js
index aec0ba6e4..dd12adf5b 100644
--- a/src/endpoints/chats.js
+++ b/src/endpoints/chats.js
@@ -190,6 +190,44 @@ function importCAIChat(userName, characterName, jsonData) {
return newChats;
}
+/**
+ * Imports a chat from Kobold Lite format.
+ * @param {string} _userName User name
+ * @param {string} _characterName Character name
+ * @param {object} data JSON data
+ * @returns {string} Chat data
+ */
+function importKoboldLiteChat(_userName, _characterName, data) {
+ const inputToken = '{{[INPUT]}}';
+ const outputToken = '{{[OUTPUT]}}';
+
+ /** @type {function(string): object} */
+ function processKoboldMessage(msg) {
+ const isUser = msg.includes(inputToken) || msg.includes(outputToken);
+ return {
+ name: isUser ? header.user_name : header.character_name,
+ is_user: isUser,
+ mes: msg.replace(inputToken, '').replace(outputToken, '').trim(),
+ send_date: Date.now(),
+ };
+ }
+
+ // Create the header
+ const header = {
+ user_name: data.savedsettings.chatname,
+ character_name: data.savedsettings.chatopponent,
+ };
+ // Format messages
+ const formattedMessages = data.actions.map(processKoboldMessage);
+ // Add prompt if available
+ if (data.prompt) {
+ formattedMessages.unshift(processKoboldMessage(data.prompt));
+ }
+ // Combine header and messages
+ const chatData = [header, ...formattedMessages];
+ return chatData.map(obj => JSON.stringify(obj)).join('\n');
+}
+
/**
* Flattens `msg` and `swipes` data from Chub Chat format.
* Only changes enough to make it compatible with the standard chat serialization format.
@@ -413,7 +451,7 @@ router.post('/import', urlencodedParser, function (request, response) {
const format = request.body.file_type;
const avatarUrl = (request.body.avatar_url).replace('.png', '');
const characterName = request.body.character_name;
- const userName = request.body.user_name || 'You';
+ const userName = request.body.user_name || 'User';
if (!request.file) {
return response.sendStatus(400);
@@ -426,33 +464,38 @@ router.post('/import', urlencodedParser, function (request, response) {
if (format === 'json') {
fs.unlinkSync(pathToUpload);
const jsonData = JSON.parse(data);
- if (jsonData.histories !== undefined) {
- // CAI Tools format
- const chats = importCAIChat(userName, characterName, jsonData);
- for (const chat of chats) {
- const fileName = `${characterName} - ${humanizedISO8601DateTime()} imported.jsonl`;
- const filePath = path.join(request.user.directories.chats, avatarUrl, fileName);
- writeFileAtomicSync(filePath, chat, 'utf8');
- }
- return response.send({ res: true });
- } else if (Array.isArray(jsonData.data_visible)) {
- // oobabooga's format
- const chat = importOobaChat(userName, characterName, jsonData);
- const fileName = `${characterName} - ${humanizedISO8601DateTime()} imported.jsonl`;
- const filePath = path.join(request.user.directories.chats, avatarUrl, fileName);
- writeFileAtomicSync(filePath, chat, 'utf8');
- return response.send({ res: true });
- } else if (Array.isArray(jsonData.messages)) {
- // Agnai format
- const chat = importAgnaiChat(userName, characterName, jsonData);
- const fileName = `${characterName} - ${humanizedISO8601DateTime()} imported.jsonl`;
- const filePath = path.join(request.user.directories.chats, avatarUrl, fileName);
- writeFileAtomicSync(filePath, chat, 'utf8');
- return response.send({ res: true });
- } else {
+
+ /** @type {function(string, string, object): string|string[]} */
+ let importFunc;
+
+ if (jsonData.savedsettings !== undefined) { // Kobold Lite format
+ importFunc = importKoboldLiteChat;
+ } else if (jsonData.histories !== undefined) { // CAI Tools format
+ importFunc = importCAIChat;
+ } else if (Array.isArray(jsonData.data_visible)) { // oobabooga's format
+ importFunc = importOobaChat;
+ } else if (Array.isArray(jsonData.messages)) { // Agnai's format
+ importFunc = importAgnaiChat;
+ } else { // Unknown format
console.log('Incorrect chat format .json');
return response.send({ error: true });
}
+
+ const handleChat = (chat) => {
+ const fileName = `${characterName} - ${humanizedISO8601DateTime()} imported.jsonl`;
+ const filePath = path.join(request.user.directories.chats, avatarUrl, fileName);
+ writeFileAtomicSync(filePath, chat, 'utf8');
+ };
+
+ const chat = importFunc(userName, characterName, jsonData);
+
+ if (Array.isArray(chat)) {
+ chat.forEach(handleChat);
+ } else {
+ handleChat(chat);
+ }
+
+ return response.send({ res: true });
}
if (format === 'jsonl') {
From 8ef49b40b230a50b70a92d1eee245f76978efbb9 Mon Sep 17 00:00:00 2001
From: Cohee <18619528+Cohee1207@users.noreply.github.com>
Date: Wed, 4 Dec 2024 01:05:14 +0200
Subject: [PATCH 5/8] Add error handling to group parsing in chat search
---
src/endpoints/chats.js | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/src/endpoints/chats.js b/src/endpoints/chats.js
index aec0ba6e4..95bdfaa17 100644
--- a/src/endpoints/chats.js
+++ b/src/endpoints/chats.js
@@ -561,10 +561,14 @@ router.post('/search', jsonParser, function (request, response) {
let targetGroup;
for (const groupFile of groupFiles) {
- const groupData = JSON.parse(fs.readFileSync(path.join(groupDir, groupFile), 'utf8'));
- if (groupData.id === group_id) {
- targetGroup = groupData;
- break;
+ try {
+ const groupData = JSON.parse(fs.readFileSync(path.join(groupDir, groupFile), 'utf8'));
+ if (groupData.id === group_id) {
+ targetGroup = groupData;
+ break;
+ }
+ } catch (error) {
+ console.error(groupFile, 'group file is corrupted:', error);
}
}
From e6be28acea70ea6899f415d51aa8d78848909206 Mon Sep 17 00:00:00 2001
From: Cohee <18619528+Cohee1207@users.noreply.github.com>
Date: Wed, 4 Dec 2024 01:32:27 +0200
Subject: [PATCH 6/8] llama.cpp: Don't send empty DRY sequence breakers Fixes
#3048
---
public/scripts/textgen-settings.js | 3 +++
1 file changed, 3 insertions(+)
diff --git a/public/scripts/textgen-settings.js b/public/scripts/textgen-settings.js
index 0dfae364f..27b32aa6c 100644
--- a/public/scripts/textgen-settings.js
+++ b/public/scripts/textgen-settings.js
@@ -1339,6 +1339,9 @@ export function getTextGenGenerationData(finalPrompt, maxTokens, isImpersonate,
'dry_sequence_breakers': sequenceBreakers,
};
params = Object.assign(params, llamaCppParams);
+ if (!Array.isArray(sequenceBreakers) || sequenceBreakers.length === 0) {
+ delete params.dry_sequence_breakers;
+ }
}
eventSource.emitAndWait(event_types.TEXT_COMPLETION_SETTINGS_READY, params);
From e9fc488661571f67e38fc7e8f6499eed836c6e7e Mon Sep 17 00:00:00 2001
From: Cohee <18619528+Cohee1207@users.noreply.github.com>
Date: Wed, 4 Dec 2024 12:53:34 +0000
Subject: [PATCH 7/8] Properly check for -0
---
public/scripts/slash-commands.js | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/public/scripts/slash-commands.js b/public/scripts/slash-commands.js
index a5ef925d9..bf54f55e5 100644
--- a/public/scripts/slash-commands.js
+++ b/public/scripts/slash-commands.js
@@ -3025,7 +3025,7 @@ async function sendUserMessageCallback(args, text) {
let insertAt = Number(args?.at);
// Convert possible depth parameter to index
- if (!isNaN(insertAt) && (insertAt < 0 || insertAt === Number(-0))) {
+ if (!isNaN(insertAt) && (insertAt < 0 || Object.is(insertAt, -0))) {
// Negative value means going back from current chat length. (E.g.: 8 messages, Depth 1 means insert at index 7)
insertAt = chat.length + insertAt;
}
@@ -3399,7 +3399,7 @@ export async function sendMessageAs(args, text) {
let insertAt = Number(args.at);
// Convert possible depth parameter to index
- if (!isNaN(insertAt) && (insertAt < 0 || insertAt === Number(-0))) {
+ if (!isNaN(insertAt) && (insertAt < 0 || Object.is(insertAt, -0))) {
// Negative value means going back from current chat length. (E.g.: 8 messages, Depth 1 means insert at index 7)
insertAt = chat.length + insertAt;
}
@@ -3453,7 +3453,7 @@ export async function sendNarratorMessage(args, text) {
let insertAt = Number(args.at);
// Convert possible depth parameter to index
- if (!isNaN(insertAt) && (insertAt < 0 || insertAt === Number(-0))) {
+ if (!isNaN(insertAt) && (insertAt < 0 || Object.is(insertAt, -0))) {
// Negative value means going back from current chat length. (E.g.: 8 messages, Depth 1 means insert at index 7)
insertAt = chat.length + insertAt;
}
@@ -3542,7 +3542,7 @@ async function sendCommentMessage(args, text) {
let insertAt = Number(args.at);
// Convert possible depth parameter to index
- if (!isNaN(insertAt) && (insertAt < 0 || insertAt === Number(-0))) {
+ if (!isNaN(insertAt) && (insertAt < 0 || Object.is(insertAt, -0))) {
// Negative value means going back from current chat length. (E.g.: 8 messages, Depth 1 means insert at index 7)
insertAt = chat.length + insertAt;
}
From 23e59a1189dda4a665a66c6ff290a3575fb4947b Mon Sep 17 00:00:00 2001
From: Cohee <18619528+Cohee1207@users.noreply.github.com>
Date: Wed, 4 Dec 2024 12:57:02 +0000
Subject: [PATCH 8/8] Document that -0 is supported
---
public/scripts/slash-commands.js | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/public/scripts/slash-commands.js b/public/scripts/slash-commands.js
index bf54f55e5..a36cdce2e 100644
--- a/public/scripts/slash-commands.js
+++ b/public/scripts/slash-commands.js
@@ -269,7 +269,7 @@ export function initDefaultSlashCommands() {
}),
SlashCommandNamedArgument.fromProps({
name: 'at',
- description: 'position to insert the message (index-based, corresponding to message id). If not set, the message will be inserted at the end of the chat.\nNegative values are accepted and will work similarly to how \'depth\' usually works. For example, -1 will insert the message right before the last message in chat.',
+ description: 'position to insert the message (index-based, corresponding to message id). If not set, the message will be inserted at the end of the chat.\nNegative values (including -0) are accepted and will work similarly to how \'depth\' usually works. For example, -1 will insert the message right before the last message in chat.',
typeList: [ARGUMENT_TYPE.NUMBER],
enumProvider: commonEnumProviders.messages({ allowIdAfter: true }),
}),
@@ -325,7 +325,7 @@ export function initDefaultSlashCommands() {
),
SlashCommandNamedArgument.fromProps({
name: 'at',
- description: 'position to insert the message (index-based, corresponding to message id). If not set, the message will be inserted at the end of the chat.\nNegative values are accepted and will work similarly to how \'depth\' usually works. For example, -1 will insert the message right before the last message in chat.',
+ description: 'position to insert the message (index-based, corresponding to message id). If not set, the message will be inserted at the end of the chat.\nNegative values (including -0) are accepted and will work similarly to how \'depth\' usually works. For example, -1 will insert the message right before the last message in chat.',
typeList: [ARGUMENT_TYPE.NUMBER],
enumProvider: commonEnumProviders.messages({ allowIdAfter: true }),
}),
@@ -388,7 +388,7 @@ export function initDefaultSlashCommands() {
),
SlashCommandNamedArgument.fromProps({
name: 'at',
- description: 'position to insert the message (index-based, corresponding to message id). If not set, the message will be inserted at the end of the chat.\nNegative values are accepted and will work similarly to how \'depth\' usually works. For example, -1 will insert the message right before the last message in chat.',
+ description: 'position to insert the message (index-based, corresponding to message id). If not set, the message will be inserted at the end of the chat.\nNegative values (including -0) are accepted and will work similarly to how \'depth\' usually works. For example, -1 will insert the message right before the last message in chat.',
typeList: [ARGUMENT_TYPE.NUMBER],
enumProvider: commonEnumProviders.messages({ allowIdAfter: true }),
}),
@@ -606,7 +606,7 @@ export function initDefaultSlashCommands() {
),
SlashCommandNamedArgument.fromProps({
name: 'at',
- description: 'position to insert the message (index-based, corresponding to message id). If not set, the message will be inserted at the end of the chat.\nNegative values are accepted and will work similarly to how \'depth\' usually works. For example, -1 will insert the message right before the last message in chat.',
+ description: 'position to insert the message (index-based, corresponding to message id). If not set, the message will be inserted at the end of the chat.\nNegative values (including -0) are accepted and will work similarly to how \'depth\' usually works. For example, -1 will insert the message right before the last message in chat.',
typeList: [ARGUMENT_TYPE.NUMBER],
enumProvider: commonEnumProviders.messages({ allowIdAfter: true }),
}),