mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-06-05 21:59:27 +02:00
Add Kobold Lite chats import
This commit is contained in:
@@ -7754,25 +7754,31 @@ export async function saveChatConditional() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function importCharacterChat(formData) {
|
/**
|
||||||
await jQuery.ajax({
|
* Saves the chat to the server.
|
||||||
type: 'POST',
|
* @param {FormData} formData Form data to send to the server.
|
||||||
url: '/api/chats/import',
|
* @param {EventTarget} eventTarget Event target to trigger the event on.
|
||||||
data: formData,
|
*/
|
||||||
beforeSend: function () {
|
async function importCharacterChat(formData, eventTarget) {
|
||||||
},
|
const headers = getRequestHeaders();
|
||||||
cache: false,
|
delete headers['Content-Type'];
|
||||||
contentType: false,
|
const fetchResult = await fetch('/api/chats/import', {
|
||||||
processData: false,
|
method: 'POST',
|
||||||
success: async function (data) {
|
body: formData,
|
||||||
|
headers: headers,
|
||||||
|
cache: 'no-cache',
|
||||||
|
});
|
||||||
|
|
||||||
|
if (fetchResult.ok) {
|
||||||
|
const data = await fetchResult.json();
|
||||||
if (data.res) {
|
if (data.res) {
|
||||||
await displayPastChats();
|
await displayPastChats();
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
error: function () {
|
|
||||||
$('#create_button').removeAttr('disabled');
|
if (eventTarget instanceof HTMLInputElement) {
|
||||||
},
|
eventTarget.value = '';
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateViewMessageIds(startFromZero = false) {
|
function updateViewMessageIds(startFromZero = false) {
|
||||||
@@ -10829,13 +10835,13 @@ jQuery(async function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
$('#chat_import_file').on('change', async function (e) {
|
$('#chat_import_file').on('change', async function (e) {
|
||||||
var file = e.target.files[0];
|
const file = e.target.files[0];
|
||||||
|
|
||||||
if (!file) {
|
if (!file) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var ext = file.name.match(/\.(\w+)$/);
|
const ext = file.name.match(/\.(\w+)$/);
|
||||||
if (
|
if (
|
||||||
!ext ||
|
!ext ||
|
||||||
(ext[1].toLowerCase() != 'json' && ext[1].toLowerCase() != 'jsonl')
|
(ext[1].toLowerCase() != 'json' && ext[1].toLowerCase() != 'jsonl')
|
||||||
@@ -10848,17 +10854,17 @@ jQuery(async function () {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var format = ext[1].toLowerCase();
|
const format = ext[1].toLowerCase();
|
||||||
$('#chat_import_file_type').val(format);
|
$('#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);
|
formData.append('user_name', name1);
|
||||||
$('#select_chat_div').html('');
|
$('#select_chat_div').html('');
|
||||||
|
|
||||||
if (selected_group) {
|
if (selected_group) {
|
||||||
await importGroupChat(formData);
|
await importGroupChat(formData, e.originalEvent.target);
|
||||||
} else {
|
} else {
|
||||||
await importCharacterChat(formData);
|
await importCharacterChat(formData, e.originalEvent.target);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@@ -1863,17 +1863,23 @@ export async function deleteGroupChat(groupId, chatId) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function importGroupChat(formData) {
|
/**
|
||||||
await jQuery.ajax({
|
* Imports a group chat from a file and adds it to the group.
|
||||||
type: 'POST',
|
* @param {FormData} formData Form data to send to the server
|
||||||
url: '/api/chats/group/import',
|
* @param {EventTarget} eventTarget Element that triggered the import
|
||||||
data: formData,
|
*/
|
||||||
beforeSend: function () {
|
export async function importGroupChat(formData, eventTarget) {
|
||||||
},
|
const headers = getRequestHeaders();
|
||||||
cache: false,
|
delete headers['Content-Type'];
|
||||||
contentType: false,
|
const fetchResult = await fetch('/api/chats/group/import', {
|
||||||
processData: false,
|
method: 'POST',
|
||||||
success: async function (data) {
|
headers: headers,
|
||||||
|
body: formData,
|
||||||
|
cache: 'no-cache',
|
||||||
|
});
|
||||||
|
|
||||||
|
if (fetchResult.ok) {
|
||||||
|
const data = await fetchResult.json();
|
||||||
if (data.res) {
|
if (data.res) {
|
||||||
const chatId = data.res;
|
const chatId = data.res;
|
||||||
const group = groups.find(x => x.id == selected_group);
|
const group = groups.find(x => x.id == selected_group);
|
||||||
@@ -1884,11 +1890,11 @@ export async function importGroupChat(formData) {
|
|||||||
await displayPastChats();
|
await displayPastChats();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
error: function () {
|
|
||||||
$('#create_button').removeAttr('disabled');
|
if (eventTarget instanceof HTMLInputElement) {
|
||||||
},
|
eventTarget.value = '';
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function saveGroupBookmarkChat(groupId, name, metadata, mesId) {
|
export async function saveGroupBookmarkChat(groupId, name, metadata, mesId) {
|
||||||
|
@@ -190,6 +190,44 @@ function importCAIChat(userName, characterName, jsonData) {
|
|||||||
return newChats;
|
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.
|
* Flattens `msg` and `swipes` data from Chub Chat format.
|
||||||
* Only changes enough to make it compatible with the standard chat serialization 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 format = request.body.file_type;
|
||||||
const avatarUrl = (request.body.avatar_url).replace('.png', '');
|
const avatarUrl = (request.body.avatar_url).replace('.png', '');
|
||||||
const characterName = request.body.character_name;
|
const characterName = request.body.character_name;
|
||||||
const userName = request.body.user_name || 'You';
|
const userName = request.body.user_name || 'User';
|
||||||
|
|
||||||
if (!request.file) {
|
if (!request.file) {
|
||||||
return response.sendStatus(400);
|
return response.sendStatus(400);
|
||||||
@@ -426,33 +464,38 @@ router.post('/import', urlencodedParser, function (request, response) {
|
|||||||
if (format === 'json') {
|
if (format === 'json') {
|
||||||
fs.unlinkSync(pathToUpload);
|
fs.unlinkSync(pathToUpload);
|
||||||
const jsonData = JSON.parse(data);
|
const jsonData = JSON.parse(data);
|
||||||
if (jsonData.histories !== undefined) {
|
|
||||||
// CAI Tools format
|
/** @type {function(string, string, object): string|string[]} */
|
||||||
const chats = importCAIChat(userName, characterName, jsonData);
|
let importFunc;
|
||||||
for (const chat of chats) {
|
|
||||||
const fileName = `${characterName} - ${humanizedISO8601DateTime()} imported.jsonl`;
|
if (jsonData.savedsettings !== undefined) { // Kobold Lite format
|
||||||
const filePath = path.join(request.user.directories.chats, avatarUrl, fileName);
|
importFunc = importKoboldLiteChat;
|
||||||
writeFileAtomicSync(filePath, chat, 'utf8');
|
} else if (jsonData.histories !== undefined) { // CAI Tools format
|
||||||
}
|
importFunc = importCAIChat;
|
||||||
return response.send({ res: true });
|
} else if (Array.isArray(jsonData.data_visible)) { // oobabooga's format
|
||||||
} else if (Array.isArray(jsonData.data_visible)) {
|
importFunc = importOobaChat;
|
||||||
// oobabooga's format
|
} else if (Array.isArray(jsonData.messages)) { // Agnai's format
|
||||||
const chat = importOobaChat(userName, characterName, jsonData);
|
importFunc = importAgnaiChat;
|
||||||
const fileName = `${characterName} - ${humanizedISO8601DateTime()} imported.jsonl`;
|
} else { // Unknown format
|
||||||
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 {
|
|
||||||
console.log('Incorrect chat format .json');
|
console.log('Incorrect chat format .json');
|
||||||
return response.send({ error: true });
|
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') {
|
if (format === 'jsonl') {
|
||||||
|
Reference in New Issue
Block a user