mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-06-05 21:59:27 +02:00
Merge branch 'staging' into geminiStructured
This commit is contained in:
@@ -1,8 +1,6 @@
|
||||
# -- DATA CONFIGURATION --
|
||||
# Root directory for user data storage
|
||||
dataRoot: ./data
|
||||
# The maximum amount of memory that parsed character cards can use in MB
|
||||
cardsCacheCapacity: 100
|
||||
# -- SERVER CONFIGURATION --
|
||||
# Listen for incoming connections
|
||||
listen: false
|
||||
@@ -135,6 +133,14 @@ thumbnails:
|
||||
# Maximum thumbnail dimensions per type [width, height]
|
||||
dimensions: { 'bg': [160, 90], 'avatar': [96, 144] }
|
||||
|
||||
# PERFORMANCE-RELATED CONFIGURATION
|
||||
performance:
|
||||
# Enables lazy loading of character cards. Improves performances with large card libraries.
|
||||
# May have compatibility issues with some extensions.
|
||||
lazyLoadCharacters: false
|
||||
# The maximum amount of memory that parsed character cards can use. Set to 0 to disable memory caching.
|
||||
memoryCacheCapacity: '100mb'
|
||||
|
||||
# Allow secret keys exposure via API
|
||||
allowKeysExposure: false
|
||||
# Skip new default content checks
|
||||
|
34
index.d.ts
vendored
34
index.d.ts
vendored
@@ -1,8 +1,36 @@
|
||||
import { UserDirectoryList, User } from "./src/users";
|
||||
import { CommandLineArguments } from "./src/command-line";
|
||||
import { CsrfSyncedToken } from "csrf-sync";
|
||||
import { EventEmitter } from 'node:events';
|
||||
import { CsrfSyncedToken } from 'csrf-sync';
|
||||
import { UserDirectoryList, User } from './src/users.js';
|
||||
import { CommandLineArguments } from './src/command-line.js';
|
||||
import { EVENT_NAMES } from './src/server-events.js';
|
||||
|
||||
/**
|
||||
* Event payload for SERVER_STARTED event.
|
||||
*/
|
||||
export interface ServerStartedEvent {
|
||||
/**
|
||||
* The URL the server is listening on.
|
||||
*/
|
||||
url: URL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Map of all server events to their payload types.
|
||||
*/
|
||||
export interface ServerEventMap {
|
||||
[EVENT_NAMES.SERVER_STARTED]: [ServerStartedEvent];
|
||||
}
|
||||
|
||||
declare global {
|
||||
declare namespace NodeJS {
|
||||
export interface Process {
|
||||
/**
|
||||
* A global instance of the server events emitter.
|
||||
*/
|
||||
serverEvents: EventEmitter<ServerEventMap>;
|
||||
}
|
||||
}
|
||||
|
||||
declare namespace CookieSessionInterfaces {
|
||||
export interface CookieSessionObject {
|
||||
/**
|
||||
|
12
package-lock.json
generated
12
package-lock.json
generated
@@ -21,6 +21,7 @@
|
||||
"bing-translate-api": "^4.0.2",
|
||||
"body-parser": "^1.20.2",
|
||||
"bowser": "^2.11.0",
|
||||
"bytes": "^3.1.2",
|
||||
"chalk": "^5.4.1",
|
||||
"command-exists": "^1.2.9",
|
||||
"compression": "^1.8.0",
|
||||
@@ -83,6 +84,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/archiver": "^6.0.3",
|
||||
"@types/bytes": "^3.1.5",
|
||||
"@types/command-exists": "^1.2.3",
|
||||
"@types/compression": "^1.7.5",
|
||||
"@types/cookie-parser": "^1.4.8",
|
||||
@@ -1105,6 +1107,13 @@
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/bytes": {
|
||||
"version": "3.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/bytes/-/bytes-3.1.5.tgz",
|
||||
"integrity": "sha512-VgZkrJckypj85YxEsEavcMmmSOIzkUHqWmM4CCyia5dc54YwsXzJ5uT4fYxBQNEXx+oF1krlhgCbvfubXqZYsQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/cacheable-request": {
|
||||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz",
|
||||
@@ -3399,6 +3408,9 @@
|
||||
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
|
||||
"integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"get-intrinsic": "^1.2.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
|
@@ -11,6 +11,7 @@
|
||||
"bing-translate-api": "^4.0.2",
|
||||
"body-parser": "^1.20.2",
|
||||
"bowser": "^2.11.0",
|
||||
"bytes": "^3.1.2",
|
||||
"chalk": "^5.4.1",
|
||||
"command-exists": "^1.2.9",
|
||||
"compression": "^1.8.0",
|
||||
@@ -92,7 +93,8 @@
|
||||
"version": "1.12.12",
|
||||
"scripts": {
|
||||
"start": "node server.js",
|
||||
"debug": "node server.js --inspect",
|
||||
"debug": "node --inspect server.js",
|
||||
"electron": "electron ./src/electron",
|
||||
"start:deno": "deno run --allow-run --allow-net --allow-read --allow-write --allow-sys --allow-env server.js",
|
||||
"start:bun": "bun server.js",
|
||||
"start:no-csrf": "node server.js --disableCsrf",
|
||||
@@ -112,6 +114,7 @@
|
||||
"main": "server.js",
|
||||
"devDependencies": {
|
||||
"@types/archiver": "^6.0.3",
|
||||
"@types/bytes": "^3.1.5",
|
||||
"@types/command-exists": "^1.2.3",
|
||||
"@types/compression": "^1.7.5",
|
||||
"@types/cookie-parser": "^1.4.8",
|
||||
|
@@ -96,6 +96,11 @@ const keyMigrationMap = [
|
||||
newKey: 'logging.minLogLevel',
|
||||
migrate: (value) => value,
|
||||
},
|
||||
{
|
||||
oldKey: 'cardsCacheCapacity',
|
||||
newKey: 'performance.memoryCacheCapacity',
|
||||
migrate: (value) => `${value}mb`,
|
||||
},
|
||||
// uncomment one release after 1.12.13
|
||||
/*
|
||||
{
|
||||
|
@@ -1951,7 +1951,18 @@
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="range-block" data-source="openai,cohere,mistralai,custom,claude,openrouter,groq,deepseek">
|
||||
<div class="range-block" data-source="makersuite,openrouter">
|
||||
<label for="openai_enable_web_search" class="checkbox_label flexWrap widthFreeExpand">
|
||||
<input id="openai_enable_web_search" type="checkbox" />
|
||||
<span data-i18n="Enable web search">Enable web search</span>
|
||||
</label>
|
||||
<div class="flexBasis100p toggle-description justifyLeft">
|
||||
<span>
|
||||
Use search capabilities provided by the backend.
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="range-block" data-source="openai,cohere,mistralai,custom,claude,openrouter,groq,deepseek,makersuite">
|
||||
<label for="openai_function_calling" class="checkbox_label flexWrap widthFreeExpand">
|
||||
<input id="openai_function_calling" type="checkbox" />
|
||||
<span data-i18n="Enable function calling">Enable function calling</span>
|
||||
|
@@ -453,6 +453,8 @@ export const event_types = {
|
||||
MESSAGE_DELETED: 'message_deleted',
|
||||
MESSAGE_UPDATED: 'message_updated',
|
||||
MESSAGE_FILE_EMBEDDED: 'message_file_embedded',
|
||||
MESSAGE_REASONING_EDITED: 'message_reasoning_edited',
|
||||
MESSAGE_REASONING_DELETED: 'message_reasoning_deleted',
|
||||
MORE_MESSAGES_LOADED: 'more_messages_loaded',
|
||||
IMPERSONATE_READY: 'impersonate_ready',
|
||||
CHAT_CHANGED: 'chat_id_changed',
|
||||
@@ -1780,9 +1782,7 @@ export async function getCharacters() {
|
||||
const response = await fetch('/api/characters/all', {
|
||||
method: 'POST',
|
||||
headers: getRequestHeaders(),
|
||||
body: JSON.stringify({
|
||||
'': '',
|
||||
}),
|
||||
body: JSON.stringify({}),
|
||||
});
|
||||
if (response.ok === true) {
|
||||
characters.splice(0, characters.length);
|
||||
@@ -3678,6 +3678,9 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro
|
||||
setGenerationProgress(0);
|
||||
generation_started = new Date();
|
||||
|
||||
// Prevent generation from shallow characters
|
||||
await unshallowCharacter(this_chid);
|
||||
|
||||
// Occurs every time, even if the generation is aborted due to slash commands execution
|
||||
await eventSource.emit(event_types.GENERATION_STARTED, type, { automatic_trigger, force_name2, quiet_prompt, quietToLoud, skipWIAN, force_chid, signal, quietImage }, dryRun);
|
||||
|
||||
@@ -6724,9 +6727,43 @@ export function buildAvatarList(block, entities, { templateId = 'inline_avatar_t
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all the data of a shallow character.
|
||||
* @param {string|undefined} characterId Array index
|
||||
* @returns {Promise<void>} Promise that resolves when the character is unshallowed
|
||||
*/
|
||||
export async function unshallowCharacter(characterId) {
|
||||
if (characterId === undefined) {
|
||||
console.warn('Undefined character cannot be unshallowed');
|
||||
return;
|
||||
}
|
||||
|
||||
/** @type {import('./scripts/char-data.js').v1CharData} */
|
||||
const character = characters[characterId];
|
||||
if (!character) {
|
||||
console.warn('Character not found:', characterId);
|
||||
return;
|
||||
}
|
||||
|
||||
// Character is not shallow
|
||||
if (!character.shallow) {
|
||||
return;
|
||||
}
|
||||
|
||||
const avatar = character.avatar;
|
||||
if (!avatar) {
|
||||
console.warn('Character has no avatar field:', characterId);
|
||||
return;
|
||||
}
|
||||
|
||||
await getOneCharacter(avatar);
|
||||
}
|
||||
|
||||
export async function getChat() {
|
||||
//console.log('/api/chats/get -- entered for -- ' + characters[this_chid].name);
|
||||
try {
|
||||
await unshallowCharacter(this_chid);
|
||||
|
||||
const response = await $.ajax({
|
||||
type: 'POST',
|
||||
url: '/api/chats/get',
|
||||
|
@@ -316,7 +316,10 @@ export async function favsToHotswap() {
|
||||
const entities = getEntitiesList({ doFilter: false });
|
||||
const container = $('#right-nav-panel .hotswap');
|
||||
|
||||
const favs = entities.filter(x => x.item.fav || x.item.fav == 'true');
|
||||
// Hard limit is required because even if all hotswaps don't fit the screen, their images would still be loaded
|
||||
// 25 is roughly calculated as the maximum number of favs that can fit an ultrawide monitor with the default theme
|
||||
const FAVS_LIMIT = 25;
|
||||
const favs = entities.filter(x => x.item.fav || x.item.fav == 'true').slice(0, FAVS_LIMIT);
|
||||
|
||||
//helpful instruction message if no characters are favorited
|
||||
if (favs.length == 0) {
|
||||
|
@@ -113,5 +113,6 @@
|
||||
* @property {string} chat - name of the current chat file chat
|
||||
* @property {string} avatar - file name of the avatar image (acts as a unique identifier)
|
||||
* @property {string} json_data - the full raw JSON data of the character
|
||||
* @property {boolean?} shallow - if the data is shallow (lazy-loaded)
|
||||
*/
|
||||
export default 0;// now this file is a module
|
||||
|
@@ -11,6 +11,7 @@ import {
|
||||
} from '../../../script.js';
|
||||
import { extension_settings, getContext, renderExtensionTemplateAsync } from '../../extensions.js';
|
||||
import { POPUP_RESULT, POPUP_TYPE, callGenericPopup } from '../../popup.js';
|
||||
import { updateReasoningUI } from '../../reasoning.js';
|
||||
import { findSecret, secret_state, writeSecret } from '../../secrets.js';
|
||||
import { SlashCommand } from '../../slash-commands/SlashCommand.js';
|
||||
import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from '../../slash-commands/SlashCommandArgument.js';
|
||||
@@ -172,21 +173,38 @@ function loadSettings() {
|
||||
showKeysButton();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the swipe is being generated for a message.
|
||||
* @param {string|number} messageId Message ID
|
||||
* @returns {boolean} Whether the swipe is being generated
|
||||
*/
|
||||
function isGeneratingSwipe(messageId) {
|
||||
return $(`#chat .mes[mesid="${messageId}"] .mes_text`).text() === '...';
|
||||
}
|
||||
|
||||
async function translateImpersonate(text) {
|
||||
const translatedText = await translate(text, extension_settings.translate.target_language);
|
||||
$('#send_textarea').val(translatedText);
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates the contents of an incoming message.
|
||||
* @param {string | number} messageId Message ID
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async function translateIncomingMessage(messageId) {
|
||||
const context = getContext();
|
||||
const message = context.chat[messageId];
|
||||
|
||||
if (!message) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof message.extra !== 'object') {
|
||||
message.extra = {};
|
||||
}
|
||||
|
||||
// New swipe is being generated. Don't translate that
|
||||
if ($(`#chat .mes[mesid="${messageId}"] .mes_text`).text() == '...') {
|
||||
if (isGeneratingSwipe(messageId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -194,7 +212,36 @@ async function translateIncomingMessage(messageId) {
|
||||
const translation = await translate(textToTranslate, extension_settings.translate.target_language);
|
||||
message.extra.display_text = translation;
|
||||
|
||||
updateMessageBlock(messageId, message);
|
||||
updateMessageBlock(Number(messageId), message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates the reasoning of an incoming message.
|
||||
* @param {string | number} messageId
|
||||
* @returns {Promise<boolean>} translated or not
|
||||
*/
|
||||
async function translateIncomingMessageReasoning(messageId) {
|
||||
const context = getContext();
|
||||
const message = context.chat[messageId];
|
||||
|
||||
if (!message) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof message.extra !== 'object') {
|
||||
message.extra = {};
|
||||
}
|
||||
|
||||
if (!message.extra.reasoning || isGeneratingSwipe(messageId)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const textToTranslate = substituteParams(message.extra.reasoning, context.name1, message.name);
|
||||
const translation = await translate(textToTranslate, extension_settings.translate.target_language);
|
||||
message.extra.reasoning_display_text = translation;
|
||||
|
||||
updateReasoningUI(Number(messageId));
|
||||
return true;
|
||||
}
|
||||
|
||||
async function translateProviderOneRing(text, lang) {
|
||||
@@ -535,6 +582,7 @@ async function onTranslateChatClick() {
|
||||
toastr.info(`${chat.length} message(s) queued for translation.`, 'Please wait...');
|
||||
|
||||
for (let i = 0; i < chat.length; i++) {
|
||||
await translateIncomingMessageReasoning(i);
|
||||
await translateIncomingMessage(i);
|
||||
}
|
||||
|
||||
@@ -561,6 +609,7 @@ async function onTranslationsClearClick() {
|
||||
for (const mes of chat) {
|
||||
if (mes.extra) {
|
||||
delete mes.extra.display_text;
|
||||
delete mes.extra.reasoning_display_text;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -573,12 +622,47 @@ async function translateMessageEdit(messageId) {
|
||||
const chat = context.chat;
|
||||
const message = chat[messageId];
|
||||
|
||||
if (message.is_system || extension_settings.translate.auto_mode == autoModeOptions.NONE) {
|
||||
return;
|
||||
let anyChange = false;
|
||||
if (message.is_system || (extension_settings.translate.auto_mode == autoModeOptions.NONE && message.extra?.display_text)) {
|
||||
delete message.extra.display_text;
|
||||
updateMessageBlock(messageId, message);
|
||||
anyChange = true;
|
||||
} else if ((message.is_user && shouldTranslate(outgoingTypes)) || (!message.is_user && shouldTranslate(incomingTypes))) {
|
||||
await translateIncomingMessage(messageId);
|
||||
anyChange = true;
|
||||
}
|
||||
|
||||
if ((message.is_user && shouldTranslate(outgoingTypes)) || (!message.is_user && shouldTranslate(incomingTypes))) {
|
||||
await translateIncomingMessage(messageId);
|
||||
if (anyChange) {
|
||||
await context.saveChat();
|
||||
}
|
||||
}
|
||||
|
||||
async function translateMessageReasoningEdit(messageId) {
|
||||
const context = getContext();
|
||||
const chat = context.chat;
|
||||
const message = chat[messageId];
|
||||
|
||||
let anyChange = false;
|
||||
if (message.is_system || (extension_settings.translate.auto_mode == autoModeOptions.NONE && message.extra?.reasoning_display_text)) {
|
||||
delete message.extra.reasoning_display_text;
|
||||
updateReasoningUI(Number(messageId));
|
||||
anyChange = true;
|
||||
} else if ((message.is_user && shouldTranslate(outgoingTypes)) || (!message.is_user && shouldTranslate(incomingTypes))) {
|
||||
anyChange = await translateIncomingMessageReasoning(messageId);
|
||||
}
|
||||
|
||||
if (anyChange) {
|
||||
await context.saveChat();
|
||||
}
|
||||
}
|
||||
|
||||
async function removeReasoningDisplayText(messageId) {
|
||||
const context = getContext();
|
||||
const message = context.chat[messageId];
|
||||
if (message.extra?.reasoning_display_text) {
|
||||
delete message.extra.reasoning_display_text;
|
||||
updateReasoningUI(Number(messageId));
|
||||
await context.saveChat();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -588,22 +672,36 @@ async function onMessageTranslateClick() {
|
||||
const message = context.chat[messageId];
|
||||
|
||||
// If the message is already translated, revert it back to the original text
|
||||
let alreadyTranslated = false;
|
||||
if (message?.extra?.display_text) {
|
||||
delete message.extra.display_text;
|
||||
updateMessageBlock(messageId, message);
|
||||
updateMessageBlock(Number(messageId), message);
|
||||
alreadyTranslated = true;
|
||||
}
|
||||
if (message?.extra?.reasoning_display_text) {
|
||||
delete message.extra.reasoning_display_text;
|
||||
updateReasoningUI(Number(messageId));
|
||||
alreadyTranslated = true;
|
||||
}
|
||||
|
||||
// If the message is not translated, translate it
|
||||
else {
|
||||
if (!alreadyTranslated) {
|
||||
await translateIncomingMessageReasoning(messageId);
|
||||
await translateIncomingMessage(messageId);
|
||||
}
|
||||
|
||||
await context.saveChat();
|
||||
}
|
||||
|
||||
const handleIncomingMessage = createEventHandler(translateIncomingMessage, () => shouldTranslate(incomingTypes));
|
||||
const handleIncomingMessage = createEventHandler(async (messageId) => {
|
||||
await translateIncomingMessageReasoning(messageId);
|
||||
await translateIncomingMessage(messageId);
|
||||
}, () => shouldTranslate(incomingTypes));
|
||||
const handleOutgoingMessage = createEventHandler(translateOutgoingMessage, () => shouldTranslate(outgoingTypes));
|
||||
const handleImpersonateReady = createEventHandler(translateImpersonate, () => shouldTranslate(incomingTypes));
|
||||
const handleMessageEdit = createEventHandler(translateMessageEdit, () => true);
|
||||
const handleMessageReasoningEdit = createEventHandler(translateMessageReasoningEdit, () => true);
|
||||
const handleMessageReasoningDelete = createEventHandler(removeReasoningDisplayText, () => true);
|
||||
|
||||
globalThis.translate = translate;
|
||||
|
||||
@@ -717,6 +815,8 @@ jQuery(async () => {
|
||||
eventSource.on(event_types.MESSAGE_SWIPED, handleIncomingMessage);
|
||||
eventSource.on(event_types.IMPERSONATE_READY, handleImpersonateReady);
|
||||
eventSource.on(event_types.MESSAGE_UPDATED, handleMessageEdit);
|
||||
eventSource.on(event_types.MESSAGE_REASONING_EDITED, handleMessageReasoningEdit);
|
||||
eventSource.on(event_types.MESSAGE_REASONING_DELETED, handleMessageReasoningDelete);
|
||||
|
||||
document.body.classList.add('translate');
|
||||
|
||||
|
@@ -72,6 +72,7 @@ import {
|
||||
animation_duration,
|
||||
depth_prompt_role_default,
|
||||
shouldAutoContinue,
|
||||
unshallowCharacter,
|
||||
} from '../script.js';
|
||||
import { printTagList, createTagMapFromList, applyTagsOnCharacterSelect, tag_map, applyTagsOnGroupSelect } from './tags.js';
|
||||
import { FILTER_TYPES, FilterHelper } from './filters.js';
|
||||
@@ -216,6 +217,7 @@ export async function getGroupChat(groupId, reload = false) {
|
||||
|
||||
// Run validation before any loading
|
||||
validateGroup(group);
|
||||
await unshallowGroupMembers(groupId);
|
||||
|
||||
const chat_id = group.chat_id;
|
||||
const data = await loadGroupChat(chat_id);
|
||||
@@ -824,6 +826,8 @@ async function generateGroupWrapper(by_auto_mode, type = null, params = {}) {
|
||||
}
|
||||
|
||||
try {
|
||||
await unshallowGroupMembers(selected_group);
|
||||
|
||||
throwIfAborted();
|
||||
hideSwipeButtons();
|
||||
is_group_generating = true;
|
||||
@@ -1137,6 +1141,29 @@ export async function editGroup(id, immediately, reload = true) {
|
||||
saveGroupDebounced(group, reload);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unshallows all definitions of group members.
|
||||
* @param {string} groupId Id of the group
|
||||
* @returns {Promise<void>} Promise that resolves when all group members are unshallowed
|
||||
*/
|
||||
export async function unshallowGroupMembers(groupId) {
|
||||
const group = groups.find(x => x.id == groupId);
|
||||
if (!group) {
|
||||
return;
|
||||
}
|
||||
const members = group.members;
|
||||
if (!Array.isArray(members)) {
|
||||
return;
|
||||
}
|
||||
for (const member of members) {
|
||||
const index = characters.findIndex(x => x.avatar === member);
|
||||
if (index === -1) {
|
||||
continue;
|
||||
}
|
||||
await unshallowCharacter(String(index));
|
||||
}
|
||||
}
|
||||
|
||||
let groupAutoModeAbortController = null;
|
||||
|
||||
async function groupChatAutoModeWorker() {
|
||||
@@ -1158,9 +1185,9 @@ async function groupChatAutoModeWorker() {
|
||||
await generateGroupWrapper(true, 'auto', { signal: groupAutoModeAbortController.signal });
|
||||
}
|
||||
|
||||
async function modifyGroupMember(chat_id, groupMember, isDelete) {
|
||||
async function modifyGroupMember(groupId, groupMember, isDelete) {
|
||||
const id = groupMember.data('id');
|
||||
const thisGroup = groups.find((x) => x.id == chat_id);
|
||||
const thisGroup = groups.find((x) => x.id == groupId);
|
||||
const membersArray = thisGroup?.members ?? newGroupMembers;
|
||||
|
||||
if (isDelete) {
|
||||
@@ -1173,6 +1200,7 @@ async function modifyGroupMember(chat_id, groupMember, isDelete) {
|
||||
}
|
||||
|
||||
if (openGroupId) {
|
||||
await unshallowGroupMembers(openGroupId);
|
||||
await editGroup(openGroupId, false, false);
|
||||
updateGroupAvatar(thisGroup);
|
||||
}
|
||||
@@ -1638,7 +1666,7 @@ async function onGroupActionClick(event) {
|
||||
}
|
||||
|
||||
if (action === 'view') {
|
||||
openCharacterDefinition(member);
|
||||
await openCharacterDefinition(member);
|
||||
}
|
||||
|
||||
if (action === 'speak') {
|
||||
@@ -1690,7 +1718,7 @@ export async function openGroupById(groupId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
function openCharacterDefinition(characterSelect) {
|
||||
async function openCharacterDefinition(characterSelect) {
|
||||
if (is_group_generating) {
|
||||
toastr.warning(t`Can't peek a character while group reply is being generated`);
|
||||
console.warn('Can\'t peek a character def while group reply is being generated');
|
||||
@@ -1703,6 +1731,7 @@ function openCharacterDefinition(characterSelect) {
|
||||
return;
|
||||
}
|
||||
|
||||
await unshallowCharacter(chid);
|
||||
setCharacterId(chid);
|
||||
select_selected_character(chid);
|
||||
// Gentle nudge to recalculate tokens
|
||||
|
@@ -300,6 +300,7 @@ export const settingsToUpdate = {
|
||||
function_calling: ['#openai_function_calling', 'function_calling', true],
|
||||
show_thoughts: ['#openai_show_thoughts', 'show_thoughts', true],
|
||||
reasoning_effort: ['#openai_reasoning_effort', 'reasoning_effort', false],
|
||||
enable_web_search: ['#openai_enable_web_search', 'enable_web_search', true],
|
||||
seed: ['#seed_openai', 'seed', false],
|
||||
n: ['#n_openai', 'n', false],
|
||||
bypass_status_check: ['#openai_bypass_status_check', 'bypass_status_check', true],
|
||||
@@ -380,6 +381,7 @@ const default_settings = {
|
||||
custom_prompt_post_processing: custom_prompt_post_processing_types.NONE,
|
||||
show_thoughts: true,
|
||||
reasoning_effort: 'medium',
|
||||
enable_web_search: false,
|
||||
seed: -1,
|
||||
n: 1,
|
||||
};
|
||||
@@ -459,6 +461,7 @@ const oai_settings = {
|
||||
custom_prompt_post_processing: custom_prompt_post_processing_types.NONE,
|
||||
show_thoughts: true,
|
||||
reasoning_effort: 'medium',
|
||||
enable_web_search: false,
|
||||
seed: -1,
|
||||
n: 1,
|
||||
};
|
||||
@@ -2000,6 +2003,7 @@ async function sendOpenAIRequest(type, messages, signal) {
|
||||
'group_names': getGroupNames(),
|
||||
'include_reasoning': Boolean(oai_settings.show_thoughts),
|
||||
'reasoning_effort': String(oai_settings.reasoning_effort),
|
||||
'enable_web_search': Boolean(oai_settings.enable_web_search),
|
||||
};
|
||||
|
||||
if (!canMultiSwipe && ToolManager.canPerformToolCalls(type)) {
|
||||
@@ -3222,6 +3226,7 @@ function loadOpenAISettings(data, settings) {
|
||||
oai_settings.bypass_status_check = settings.bypass_status_check ?? default_settings.bypass_status_check;
|
||||
oai_settings.show_thoughts = settings.show_thoughts ?? default_settings.show_thoughts;
|
||||
oai_settings.reasoning_effort = settings.reasoning_effort ?? default_settings.reasoning_effort;
|
||||
oai_settings.enable_web_search = settings.enable_web_search ?? default_settings.enable_web_search;
|
||||
oai_settings.seed = settings.seed ?? default_settings.seed;
|
||||
oai_settings.n = settings.n ?? default_settings.n;
|
||||
|
||||
@@ -3349,6 +3354,7 @@ function loadOpenAISettings(data, settings) {
|
||||
$('#seed_openai').val(oai_settings.seed);
|
||||
$('#n_openai').val(oai_settings.n);
|
||||
$('#openai_show_thoughts').prop('checked', oai_settings.show_thoughts);
|
||||
$('#openai_enable_web_search').prop('checked', oai_settings.enable_web_search);
|
||||
|
||||
$('#openai_reasoning_effort').val(oai_settings.reasoning_effort);
|
||||
$(`#openai_reasoning_effort option[value="${oai_settings.reasoning_effort}"]`).prop('selected', true);
|
||||
@@ -3613,6 +3619,7 @@ async function saveOpenAIPreset(name, settings, triggerUi = true) {
|
||||
function_calling: settings.function_calling,
|
||||
show_thoughts: settings.show_thoughts,
|
||||
reasoning_effort: settings.reasoning_effort,
|
||||
enable_web_search: settings.enable_web_search,
|
||||
seed: settings.seed,
|
||||
n: settings.n,
|
||||
};
|
||||
@@ -5572,6 +5579,11 @@ export function initOpenAI() {
|
||||
saveSettingsDebounced();
|
||||
});
|
||||
|
||||
$('#openai_enable_web_search').on('input', function () {
|
||||
oai_settings.enable_web_search = !!$(this).prop('checked');
|
||||
saveSettingsDebounced();
|
||||
});
|
||||
|
||||
if (!CSS.supports('field-sizing', 'content')) {
|
||||
$(document).on('input', '#openai_settings .autoSetHeight', function () {
|
||||
resetScrollHeight($(this));
|
||||
|
@@ -167,6 +167,8 @@ export class ReasoningHandler {
|
||||
this.type = null;
|
||||
/** @type {string} The reasoning output */
|
||||
this.reasoning = '';
|
||||
/** @type {string?} The reasoning output display in case of translate or other */
|
||||
this.reasoningDisplayText = null;
|
||||
/** @type {Date} When the reasoning started */
|
||||
this.startTime = null;
|
||||
/** @type {Date} When the reasoning ended */
|
||||
@@ -234,6 +236,7 @@ export class ReasoningHandler {
|
||||
|
||||
this.type = extra?.reasoning_type;
|
||||
this.reasoning = extra?.reasoning ?? '';
|
||||
this.reasoningDisplayText = extra?.reasoning_display_text ?? null;
|
||||
|
||||
if (this.state !== ReasoningState.None) {
|
||||
this.initialTime = new Date(chat[messageId].gen_started);
|
||||
@@ -249,6 +252,7 @@ export class ReasoningHandler {
|
||||
this.state = this.#isHiddenReasoningModel ? ReasoningState.Thinking : ReasoningState.None;
|
||||
this.type = null;
|
||||
this.reasoning = '';
|
||||
this.reasoningDisplayText = null;
|
||||
this.initialTime = new Date();
|
||||
this.startTime = null;
|
||||
this.endTime = null;
|
||||
@@ -434,7 +438,7 @@ export class ReasoningHandler {
|
||||
setDatasetProperty(this.messageReasoningDetailsDom, 'type', this.type);
|
||||
|
||||
// Update the reasoning message
|
||||
const reasoning = trimSpaces(this.reasoning);
|
||||
const reasoning = trimSpaces(this.reasoningDisplayText ?? this.reasoning);
|
||||
const displayReasoning = messageFormatting(reasoning, '', false, false, messageId, {}, true);
|
||||
this.messageReasoningContentDom.innerHTML = displayReasoning;
|
||||
|
||||
@@ -888,12 +892,17 @@ function setReasoningEventHandlers() {
|
||||
}
|
||||
|
||||
const textarea = messageBlock.find('.reasoning_edit_textarea');
|
||||
updateReasoningFromValue(message, String(textarea.val()));
|
||||
const newReasoning = String(textarea.val());
|
||||
textarea.remove();
|
||||
if (newReasoning === message.extra.reasoning) {
|
||||
return;
|
||||
}
|
||||
updateReasoningFromValue(message, newReasoning);
|
||||
await saveChatConditional();
|
||||
updateMessageBlock(messageId, message);
|
||||
textarea.remove();
|
||||
|
||||
messageBlock.find('.mes_edit_done:visible').trigger('click');
|
||||
await eventSource.emit(event_types.MESSAGE_REASONING_EDITED, messageId);
|
||||
});
|
||||
|
||||
$(document).on('click', '.mes_reasoning_edit_cancel', function (e) {
|
||||
@@ -955,6 +964,7 @@ function setReasoningEventHandlers() {
|
||||
updateMessageBlock(messageId, message);
|
||||
const textarea = messageBlock.find('.reasoning_edit_textarea');
|
||||
textarea.remove();
|
||||
await eventSource.emit(event_types.MESSAGE_REASONING_DELETED, messageId);
|
||||
});
|
||||
|
||||
$(document).on('pointerup', '.mes_reasoning_copy', async function () {
|
||||
|
@@ -137,9 +137,14 @@ async function* parseStreamData(json) {
|
||||
else if (Array.isArray(json.candidates)) {
|
||||
for (let i = 0; i < json.candidates.length; i++) {
|
||||
const isNotPrimary = json.candidates?.[0]?.index > 0;
|
||||
const hasToolCalls = json?.candidates?.[0]?.content?.parts?.some(p => p?.functionCall);
|
||||
if (isNotPrimary || json.candidates.length === 0) {
|
||||
return null;
|
||||
}
|
||||
if (hasToolCalls) {
|
||||
yield { data: json, chunk: '' };
|
||||
return;
|
||||
}
|
||||
if (typeof json.candidates[0].content === 'object' && Array.isArray(json.candidates[i].content.parts)) {
|
||||
for (let j = 0; j < json.candidates[i].content.parts.length; j++) {
|
||||
if (typeof json.candidates[i].content.parts[j].text === 'string') {
|
||||
|
@@ -47,6 +47,7 @@ import {
|
||||
updateMessageBlock,
|
||||
printMessages,
|
||||
clearChat,
|
||||
unshallowCharacter,
|
||||
} from '../script.js';
|
||||
import {
|
||||
extension_settings,
|
||||
@@ -55,7 +56,7 @@ import {
|
||||
renderExtensionTemplateAsync,
|
||||
writeExtensionField,
|
||||
} from './extensions.js';
|
||||
import { groups, openGroupChat, selected_group } from './group-chats.js';
|
||||
import { groups, openGroupChat, selected_group, unshallowGroupMembers } from './group-chats.js';
|
||||
import { addLocaleData, getCurrentLocale, t, translate } from './i18n.js';
|
||||
import { hideLoader, showLoader } from './loader.js';
|
||||
import { MacrosParser } from './macros.js';
|
||||
@@ -78,6 +79,7 @@ import { timestampToMoment, uuidv4 } from './utils.js';
|
||||
import { getGlobalVariable, getLocalVariable, setGlobalVariable, setLocalVariable } from './variables.js';
|
||||
import { convertCharacterBook, loadWorldInfo, saveWorldInfo, updateWorldInfoList } from './world-info.js';
|
||||
import { ChatCompletionService, TextCompletionService } from './custom-request.js';
|
||||
import { updateReasoningUI } from './reasoning.js';
|
||||
|
||||
export function getContext() {
|
||||
return {
|
||||
@@ -210,6 +212,9 @@ export function getContext() {
|
||||
clearChat,
|
||||
ChatCompletionService,
|
||||
TextCompletionService,
|
||||
updateReasoningUI,
|
||||
unshallowCharacter,
|
||||
unshallowGroupMembers,
|
||||
};
|
||||
}
|
||||
|
||||
|
@@ -506,6 +506,26 @@ export class ToolManager {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Array.isArray(parsed?.candidates)) {
|
||||
for (let choiceIndex = 0; choiceIndex < parsed.candidates.length; choiceIndex++) {
|
||||
const candidate = parsed.candidates[choiceIndex];
|
||||
if (Array.isArray(candidate?.content?.parts)) {
|
||||
for (let toolCallIndex = 0; toolCallIndex < candidate.content.parts.length; toolCallIndex++) {
|
||||
const part = candidate.content.parts[toolCallIndex];
|
||||
if (part.functionCall) {
|
||||
if (!Array.isArray(toolCalls[choiceIndex])) {
|
||||
toolCalls[choiceIndex] = [];
|
||||
}
|
||||
if (toolCalls[choiceIndex][toolCallIndex] === undefined) {
|
||||
toolCalls[choiceIndex][toolCallIndex] = {};
|
||||
}
|
||||
const targetToolCall = toolCalls[choiceIndex][toolCallIndex];
|
||||
ToolManager.#applyToolCallDelta(targetToolCall, part.functionCall);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -564,6 +584,7 @@ export class ToolManager {
|
||||
chat_completion_sources.GROQ,
|
||||
chat_completion_sources.COHERE,
|
||||
chat_completion_sources.DEEPSEEK,
|
||||
chat_completion_sources.MAKERSUITE,
|
||||
];
|
||||
return supportedSources.includes(oai_settings.chat_completion_source);
|
||||
}
|
||||
@@ -585,8 +606,11 @@ export class ToolManager {
|
||||
* @returns {any[]} Tool calls from the response data
|
||||
*/
|
||||
static #getToolCallsFromData(data) {
|
||||
const getRandomId = () => Math.random().toString(36).substring(2);
|
||||
const isClaudeToolCall = c => Array.isArray(c) ? c.filter(x => x).every(isClaudeToolCall) : c?.input && c?.name && c?.id;
|
||||
const isGoogleToolCall = c => Array.isArray(c) ? c.filter(x => x).every(isGoogleToolCall) : c?.name && c?.args;
|
||||
const convertClaudeToolCall = c => ({ id: c.id, function: { name: c.name, arguments: c.input } });
|
||||
const convertGoogleToolCall = (c) => ({ id: getRandomId(), function: { name: c.name, arguments: c.args } });
|
||||
|
||||
// Parsed tool calls from streaming data
|
||||
if (Array.isArray(data) && data.length > 0 && Array.isArray(data[0])) {
|
||||
@@ -594,6 +618,10 @@ export class ToolManager {
|
||||
return data[0].filter(x => x).map(convertClaudeToolCall);
|
||||
}
|
||||
|
||||
if (isGoogleToolCall(data[0])) {
|
||||
return data[0].filter(x => x).map(convertGoogleToolCall);
|
||||
}
|
||||
|
||||
if (typeof data[0]?.[0]?.tool_calls === 'object') {
|
||||
return Array.isArray(data[0]?.[0]?.tool_calls) ? data[0][0].tool_calls : [data[0][0].tool_calls];
|
||||
}
|
||||
@@ -601,6 +629,11 @@ export class ToolManager {
|
||||
return data[0];
|
||||
}
|
||||
|
||||
// Google AI Studio tool calls
|
||||
if (Array.isArray(data?.responseContent?.parts)) {
|
||||
return data.responseContent.parts.filter(p => p.functionCall).map(p => convertGoogleToolCall(p.functionCall));
|
||||
}
|
||||
|
||||
// Parsed tool calls from non-streaming data
|
||||
if (Array.isArray(data?.choices)) {
|
||||
// Find a choice with 0-index
|
||||
|
@@ -20,6 +20,7 @@ import bodyParser from 'body-parser';
|
||||
import open from 'open';
|
||||
|
||||
// local library imports
|
||||
import { serverEvents, EVENT_NAMES } from './src/server-events.js';
|
||||
import { CommandLineParser } from './src/command-line.js';
|
||||
import { loadPlugins } from './src/plugin-loader.js';
|
||||
import {
|
||||
@@ -348,6 +349,7 @@ async function postSetupTasks(result) {
|
||||
console.log('\n' + getSeparator(plainGoToLog.length) + '\n');
|
||||
|
||||
setupLogLevel();
|
||||
serverEvents.emit(EVENT_NAMES.SERVER_STARTED, { url: autorunUrl });
|
||||
}
|
||||
|
||||
/**
|
||||
|
6
src/electron/Start.bat
Normal file
6
src/electron/Start.bat
Normal file
@@ -0,0 +1,6 @@
|
||||
@echo off
|
||||
pushd %~dp0
|
||||
call npm install --no-audit --no-fund --loglevel=error --no-progress --omit=dev
|
||||
npm run start server.js %*
|
||||
pause
|
||||
popd
|
62
src/electron/index.js
Normal file
62
src/electron/index.js
Normal file
@@ -0,0 +1,62 @@
|
||||
import { app, BrowserWindow } from 'electron';
|
||||
import path from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
import yargs from 'yargs';
|
||||
import { serverEvents, EVENT_NAMES } from '../server-events.js';
|
||||
|
||||
const cliArguments = yargs(process.argv)
|
||||
.usage('Usage: <your-start-script> [options]')
|
||||
.option('width', {
|
||||
type: 'number',
|
||||
default: 800,
|
||||
describe: 'The width of the window',
|
||||
})
|
||||
.option('height', {
|
||||
type: 'number',
|
||||
default: 600,
|
||||
describe: 'The height of the window',
|
||||
})
|
||||
.parseSync();
|
||||
|
||||
/** @type {string} The URL to load in the window. */
|
||||
let appUrl;
|
||||
|
||||
function createSillyTavernWindow() {
|
||||
if (!appUrl) {
|
||||
console.error('The server has not started yet.');
|
||||
return;
|
||||
}
|
||||
new BrowserWindow({
|
||||
height: cliArguments.height,
|
||||
width: cliArguments.width,
|
||||
}).loadURL(appUrl);
|
||||
}
|
||||
|
||||
function startServer() {
|
||||
return new Promise((_resolve, _reject) => {
|
||||
serverEvents.addListener(EVENT_NAMES.SERVER_STARTED, ({ url }) => {
|
||||
appUrl = url.toString();
|
||||
createSillyTavernWindow();
|
||||
});
|
||||
const sillyTavernRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..');
|
||||
process.chdir(sillyTavernRoot);
|
||||
|
||||
import('../../server.js');
|
||||
});
|
||||
}
|
||||
|
||||
app.whenReady().then(() => {
|
||||
app.on('activate', () => {
|
||||
if (BrowserWindow.getAllWindows().length === 0) {
|
||||
createSillyTavernWindow();
|
||||
}
|
||||
});
|
||||
|
||||
startServer();
|
||||
});
|
||||
|
||||
app.on('window-all-closed', () => {
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit();
|
||||
}
|
||||
});
|
802
src/electron/package-lock.json
generated
Normal file
802
src/electron/package-lock.json
generated
Normal file
@@ -0,0 +1,802 @@
|
||||
{
|
||||
"name": "sillytavern-electron",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "sillytavern-electron",
|
||||
"version": "1.0.0",
|
||||
"license": "AGPL-3.0",
|
||||
"dependencies": {
|
||||
"electron": "^35.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@electron/get": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@electron/get/-/get-2.0.3.tgz",
|
||||
"integrity": "sha512-Qkzpg2s9GnVV2I2BjRksUi43U5e6+zaQMcjoJy0C+C5oxaKl+fmckGDQFtRpZpZV0NQekuZZ+tGz7EA9TVnQtQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"debug": "^4.1.1",
|
||||
"env-paths": "^2.2.0",
|
||||
"fs-extra": "^8.1.0",
|
||||
"got": "^11.8.5",
|
||||
"progress": "^2.0.3",
|
||||
"semver": "^6.2.0",
|
||||
"sumchecker": "^3.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"global-agent": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@sindresorhus/is": {
|
||||
"version": "4.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz",
|
||||
"integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sindresorhus/is?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/@szmarczak/http-timer": {
|
||||
"version": "4.0.6",
|
||||
"resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz",
|
||||
"integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"defer-to-connect": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/cacheable-request": {
|
||||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz",
|
||||
"integrity": "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/http-cache-semantics": "*",
|
||||
"@types/keyv": "^3.1.4",
|
||||
"@types/node": "*",
|
||||
"@types/responselike": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/http-cache-semantics": {
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz",
|
||||
"integrity": "sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/keyv": {
|
||||
"version": "3.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz",
|
||||
"integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "22.13.9",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.9.tgz",
|
||||
"integrity": "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"undici-types": "~6.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/responselike": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.3.tgz",
|
||||
"integrity": "sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/yauzl": {
|
||||
"version": "2.10.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz",
|
||||
"integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/boolean": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/boolean/-/boolean-3.2.0.tgz",
|
||||
"integrity": "sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==",
|
||||
"deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.",
|
||||
"license": "MIT",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/buffer-crc32": {
|
||||
"version": "0.2.13",
|
||||
"resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
|
||||
"integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/cacheable-lookup": {
|
||||
"version": "5.0.4",
|
||||
"resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz",
|
||||
"integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/cacheable-request": {
|
||||
"version": "7.0.4",
|
||||
"resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.4.tgz",
|
||||
"integrity": "sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"clone-response": "^1.0.2",
|
||||
"get-stream": "^5.1.0",
|
||||
"http-cache-semantics": "^4.0.0",
|
||||
"keyv": "^4.0.0",
|
||||
"lowercase-keys": "^2.0.0",
|
||||
"normalize-url": "^6.0.1",
|
||||
"responselike": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/clone-response": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz",
|
||||
"integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"mimic-response": "^1.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/debug": {
|
||||
"version": "4.4.0",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
|
||||
"integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ms": "^2.1.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"supports-color": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/decompress-response": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz",
|
||||
"integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"mimic-response": "^3.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/decompress-response/node_modules/mimic-response": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz",
|
||||
"integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/defer-to-connect": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz",
|
||||
"integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/define-data-property": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
|
||||
"integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"es-define-property": "^1.0.0",
|
||||
"es-errors": "^1.3.0",
|
||||
"gopd": "^1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/define-properties": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz",
|
||||
"integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"define-data-property": "^1.0.1",
|
||||
"has-property-descriptors": "^1.0.0",
|
||||
"object-keys": "^1.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/detect-node": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz",
|
||||
"integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==",
|
||||
"license": "MIT",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/electron": {
|
||||
"version": "35.0.0",
|
||||
"resolved": "https://registry.npmjs.org/electron/-/electron-35.0.0.tgz",
|
||||
"integrity": "sha512-mwNQNktYLPnUWZVR8iNkfWCBjmM5e2/CmB1rhACwE9ASDbVU7CYPgp/jLUB3bj/LyQsfSuubD82OUite6SN8Uw==",
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@electron/get": "^2.0.0",
|
||||
"@types/node": "^22.7.7",
|
||||
"extract-zip": "^2.0.1"
|
||||
},
|
||||
"bin": {
|
||||
"electron": "cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 12.20.55"
|
||||
}
|
||||
},
|
||||
"node_modules/end-of-stream": {
|
||||
"version": "1.4.4",
|
||||
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
|
||||
"integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"once": "^1.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/env-paths": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz",
|
||||
"integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/es-define-property": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
|
||||
"integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/es-errors": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
|
||||
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/es6-error": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz",
|
||||
"integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==",
|
||||
"license": "MIT",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/escape-string-regexp": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
|
||||
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/extract-zip": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz",
|
||||
"integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==",
|
||||
"license": "BSD-2-Clause",
|
||||
"dependencies": {
|
||||
"debug": "^4.1.1",
|
||||
"get-stream": "^5.1.0",
|
||||
"yauzl": "^2.10.0"
|
||||
},
|
||||
"bin": {
|
||||
"extract-zip": "cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 10.17.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@types/yauzl": "^2.9.1"
|
||||
}
|
||||
},
|
||||
"node_modules/fd-slicer": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz",
|
||||
"integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"pend": "~1.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/fs-extra": {
|
||||
"version": "8.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
|
||||
"integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"graceful-fs": "^4.2.0",
|
||||
"jsonfile": "^4.0.0",
|
||||
"universalify": "^0.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6 <7 || >=8"
|
||||
}
|
||||
},
|
||||
"node_modules/get-stream": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz",
|
||||
"integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"pump": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/global-agent": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/global-agent/-/global-agent-3.0.0.tgz",
|
||||
"integrity": "sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q==",
|
||||
"license": "BSD-3-Clause",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"boolean": "^3.0.1",
|
||||
"es6-error": "^4.1.1",
|
||||
"matcher": "^3.0.0",
|
||||
"roarr": "^2.15.3",
|
||||
"semver": "^7.3.2",
|
||||
"serialize-error": "^7.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/global-agent/node_modules/semver": {
|
||||
"version": "7.7.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz",
|
||||
"integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==",
|
||||
"license": "ISC",
|
||||
"optional": true,
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/globalthis": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz",
|
||||
"integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"define-properties": "^1.2.1",
|
||||
"gopd": "^1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/gopd": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
|
||||
"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/got": {
|
||||
"version": "11.8.6",
|
||||
"resolved": "https://registry.npmjs.org/got/-/got-11.8.6.tgz",
|
||||
"integrity": "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@sindresorhus/is": "^4.0.0",
|
||||
"@szmarczak/http-timer": "^4.0.5",
|
||||
"@types/cacheable-request": "^6.0.1",
|
||||
"@types/responselike": "^1.0.0",
|
||||
"cacheable-lookup": "^5.0.3",
|
||||
"cacheable-request": "^7.0.2",
|
||||
"decompress-response": "^6.0.0",
|
||||
"http2-wrapper": "^1.0.0-beta.5.2",
|
||||
"lowercase-keys": "^2.0.0",
|
||||
"p-cancelable": "^2.0.0",
|
||||
"responselike": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.19.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sindresorhus/got?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/graceful-fs": {
|
||||
"version": "4.2.11",
|
||||
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
|
||||
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/has-property-descriptors": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
|
||||
"integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"es-define-property": "^1.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/http-cache-semantics": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz",
|
||||
"integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==",
|
||||
"license": "BSD-2-Clause"
|
||||
},
|
||||
"node_modules/http2-wrapper": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz",
|
||||
"integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"quick-lru": "^5.1.1",
|
||||
"resolve-alpn": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.19.0"
|
||||
}
|
||||
},
|
||||
"node_modules/json-buffer": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
|
||||
"integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/json-stringify-safe": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
|
||||
"integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==",
|
||||
"license": "ISC",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/jsonfile": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
|
||||
"integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==",
|
||||
"license": "MIT",
|
||||
"optionalDependencies": {
|
||||
"graceful-fs": "^4.1.6"
|
||||
}
|
||||
},
|
||||
"node_modules/keyv": {
|
||||
"version": "4.5.4",
|
||||
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
|
||||
"integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"json-buffer": "3.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/lowercase-keys": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz",
|
||||
"integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/matcher": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/matcher/-/matcher-3.0.0.tgz",
|
||||
"integrity": "sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"escape-string-regexp": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/mimic-response": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz",
|
||||
"integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/normalize-url": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz",
|
||||
"integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/object-keys": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
|
||||
"integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/once": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"node_modules/p-cancelable": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz",
|
||||
"integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/pend": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
|
||||
"integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/progress": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
|
||||
"integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/pump": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz",
|
||||
"integrity": "sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"end-of-stream": "^1.1.0",
|
||||
"once": "^1.3.1"
|
||||
}
|
||||
},
|
||||
"node_modules/quick-lru": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz",
|
||||
"integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/resolve-alpn": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz",
|
||||
"integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/responselike": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz",
|
||||
"integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"lowercase-keys": "^2.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/roarr": {
|
||||
"version": "2.15.4",
|
||||
"resolved": "https://registry.npmjs.org/roarr/-/roarr-2.15.4.tgz",
|
||||
"integrity": "sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A==",
|
||||
"license": "BSD-3-Clause",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"boolean": "^3.0.1",
|
||||
"detect-node": "^2.0.4",
|
||||
"globalthis": "^1.0.1",
|
||||
"json-stringify-safe": "^5.0.1",
|
||||
"semver-compare": "^1.0.0",
|
||||
"sprintf-js": "^1.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/semver": {
|
||||
"version": "6.3.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
|
||||
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
|
||||
"license": "ISC",
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
}
|
||||
},
|
||||
"node_modules/semver-compare": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz",
|
||||
"integrity": "sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==",
|
||||
"license": "MIT",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/serialize-error": {
|
||||
"version": "7.0.1",
|
||||
"resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-7.0.1.tgz",
|
||||
"integrity": "sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"type-fest": "^0.13.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/sprintf-js": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz",
|
||||
"integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==",
|
||||
"license": "BSD-3-Clause",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/sumchecker": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/sumchecker/-/sumchecker-3.0.1.tgz",
|
||||
"integrity": "sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"debug": "^4.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/type-fest": {
|
||||
"version": "0.13.1",
|
||||
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz",
|
||||
"integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==",
|
||||
"license": "(MIT OR CC0-1.0)",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/undici-types": {
|
||||
"version": "6.20.0",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
|
||||
"integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/universalify": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
|
||||
"integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/wrappy": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/yauzl": {
|
||||
"version": "2.10.0",
|
||||
"resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz",
|
||||
"integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"buffer-crc32": "~0.2.3",
|
||||
"fd-slicer": "~1.1.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
16
src/electron/package.json
Normal file
16
src/electron/package.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "sillytavern-electron",
|
||||
"version": "1.0.0",
|
||||
"description": "Electron server for SillyTavern",
|
||||
"license": "AGPL-3.0",
|
||||
"author": "",
|
||||
"type": "module",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"start": "electron ."
|
||||
},
|
||||
"dependencies": {
|
||||
"electron": "^35.0.0"
|
||||
}
|
||||
}
|
11
src/electron/start.sh
Executable file
11
src/electron/start.sh
Executable file
@@ -0,0 +1,11 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Make sure pwd is the directory of the script
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
echo "Assuming nodejs and npm is already installed. If you haven't installed them already, do so now"
|
||||
echo "Installing Electron Wrapper's Node Modules..."
|
||||
npm i --no-audit --no-fund --loglevel=error --no-progress --omit=dev
|
||||
|
||||
echo "Starting Electron Wrapper..."
|
||||
npm run start -- "$@"
|
@@ -98,6 +98,21 @@ function getOpenRouterTransforms(request) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets OpenRouter plugins based on the request.
|
||||
* @param {import('express').Request} request
|
||||
* @returns {any[]} OpenRouter plugins
|
||||
*/
|
||||
function getOpenRouterPlugins(request) {
|
||||
const plugins = [];
|
||||
|
||||
if (request.body.enable_web_search) {
|
||||
plugins.push({ 'id': 'web' });
|
||||
}
|
||||
|
||||
return plugins;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a request to Claude API.
|
||||
* @param {express.Request} request Express request
|
||||
@@ -323,6 +338,7 @@ async function sendMakerSuiteRequest(request, response) {
|
||||
|
||||
const model = String(request.body.model);
|
||||
const stream = Boolean(request.body.stream);
|
||||
const enableWebSearch = Boolean(request.body.enable_web_search);
|
||||
const isThinking = model.includes('thinking');
|
||||
|
||||
const generationConfig = {
|
||||
@@ -350,6 +366,7 @@ async function sendMakerSuiteRequest(request, response) {
|
||||
model.startsWith('gemini-exp')
|
||||
) && request.body.use_makersuite_sysprompt;
|
||||
|
||||
const tools = [];
|
||||
const prompt = convertGooglePrompt(request.body.messages, model, should_use_system_prompt, getPromptNames(request));
|
||||
let safetySettings = GEMINI_SAFETY;
|
||||
|
||||
@@ -363,6 +380,26 @@ async function sendMakerSuiteRequest(request, response) {
|
||||
}
|
||||
// Most of the other models allow for setting the threshold of filters, except for HARM_CATEGORY_CIVIC_INTEGRITY, to OFF.
|
||||
|
||||
if (enableWebSearch) {
|
||||
const searchTool = model.includes('1.5') || model.includes('1.0')
|
||||
? ({ google_search_retrieval: {} })
|
||||
: ({ google_search: {} });
|
||||
tools.push(searchTool);
|
||||
}
|
||||
|
||||
if (Array.isArray(request.body.tools) && request.body.tools.length > 0) {
|
||||
const functionDeclarations = [];
|
||||
for (const tool of request.body.tools) {
|
||||
if (tool.type === 'function') {
|
||||
if (tool.function.parameters?.$schema) {
|
||||
delete tool.function.parameters.$schema;
|
||||
}
|
||||
functionDeclarations.push(tool.function);
|
||||
}
|
||||
}
|
||||
tools.push({ function_declarations: functionDeclarations });
|
||||
}
|
||||
|
||||
let body = {
|
||||
contents: prompt.contents,
|
||||
safetySettings: safetySettings,
|
||||
@@ -374,6 +411,10 @@ async function sendMakerSuiteRequest(request, response) {
|
||||
body.systemInstruction = prompt.system_instruction;
|
||||
}
|
||||
|
||||
if (tools.length) {
|
||||
body.tools = tools;
|
||||
}
|
||||
|
||||
return body;
|
||||
}
|
||||
|
||||
@@ -429,10 +470,11 @@ async function sendMakerSuiteRequest(request, response) {
|
||||
}
|
||||
|
||||
const responseContent = candidates[0].content ?? candidates[0].output;
|
||||
const functionCall = (candidates?.[0]?.content?.parts ?? []).some(part => part.functionCall);
|
||||
console.warn('Google AI Studio response:', responseContent);
|
||||
|
||||
const responseText = typeof responseContent === 'string' ? responseContent : responseContent?.parts?.filter(part => !part.thought)?.map(part => part.text)?.join('\n\n');
|
||||
if (!responseText) {
|
||||
if (!responseText && !functionCall) {
|
||||
let message = 'Google AI Studio Candidate text empty';
|
||||
console.warn(message, generateResponseJson);
|
||||
return response.send({ error: { message } });
|
||||
@@ -1017,6 +1059,7 @@ router.post('/generate', jsonParser, function (request, response) {
|
||||
headers = { ...OPENROUTER_HEADERS };
|
||||
bodyParams = {
|
||||
'transforms': getOpenRouterTransforms(request),
|
||||
'plugins': getOpenRouterPlugins(request),
|
||||
'include_reasoning': Boolean(request.body.include_reasoning),
|
||||
};
|
||||
|
||||
@@ -1185,6 +1228,7 @@ router.post('/generate', jsonParser, function (request, response) {
|
||||
*/
|
||||
async function makeRequest(config, response, request, retries = 5, timeout = 5000) {
|
||||
try {
|
||||
controller.signal.throwIfAborted();
|
||||
const fetchResponse = await fetch(endpointUrl, config);
|
||||
|
||||
if (request.body.stream) {
|
||||
|
@@ -23,12 +23,13 @@ import { invalidateThumbnail } from './thumbnails.js';
|
||||
import { importRisuSprites } from './sprites.js';
|
||||
const defaultAvatarPath = './public/img/ai4.png';
|
||||
|
||||
// KV-store for parsed character data
|
||||
const cacheCapacity = Number(getConfigValue('cardsCacheCapacity', 100, 'number')); // MB
|
||||
// With 100 MB limit it would take roughly 3000 characters to reach this limit
|
||||
const characterDataCache = new MemoryLimitedMap(1024 * 1024 * cacheCapacity);
|
||||
const memoryCacheCapacity = getConfigValue('performance.memoryCacheCapacity', '100mb');
|
||||
const memoryCache = new MemoryLimitedMap(memoryCacheCapacity);
|
||||
// Some Android devices require tighter memory management
|
||||
const isAndroid = process.platform === 'android';
|
||||
// Use shallow character data for the character list
|
||||
const useShallowCharacters = !!getConfigValue('performance.lazyLoadCharacters', false, 'boolean');
|
||||
|
||||
/**
|
||||
* Reads the character card from the specified image file.
|
||||
@@ -39,12 +40,12 @@ const isAndroid = process.platform === 'android';
|
||||
async function readCharacterData(inputFile, inputFormat = 'png') {
|
||||
const stat = fs.statSync(inputFile);
|
||||
const cacheKey = `${inputFile}-${stat.mtimeMs}`;
|
||||
if (characterDataCache.has(cacheKey)) {
|
||||
return characterDataCache.get(cacheKey);
|
||||
if (memoryCache.has(cacheKey)) {
|
||||
return memoryCache.get(cacheKey);
|
||||
}
|
||||
|
||||
const result = parse(inputFile, inputFormat);
|
||||
!isAndroid && characterDataCache.set(cacheKey, result);
|
||||
!isAndroid && memoryCache.set(cacheKey, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -60,12 +61,12 @@ async function readCharacterData(inputFile, inputFormat = 'png') {
|
||||
async function writeCharacterData(inputFile, data, outputFile, request, crop = undefined) {
|
||||
try {
|
||||
// Reset the cache
|
||||
for (const key of characterDataCache.keys()) {
|
||||
for (const key of memoryCache.keys()) {
|
||||
if (Buffer.isBuffer(inputFile)) {
|
||||
break;
|
||||
}
|
||||
if (key.startsWith(inputFile)) {
|
||||
characterDataCache.delete(key);
|
||||
memoryCache.delete(key);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -200,14 +201,45 @@ const calculateDataSize = (data) => {
|
||||
return typeof data === 'object' ? Object.values(data).reduce((acc, val) => acc + String(val).length, 0) : 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Only get fields that are used to display the character list.
|
||||
* @param {object} character Character object
|
||||
* @returns {{shallow: true, [key: string]: any}} Shallow character
|
||||
*/
|
||||
const toShallow = (character) => {
|
||||
return {
|
||||
shallow: true,
|
||||
name: character.name,
|
||||
avatar: character.avatar,
|
||||
chat: character.chat,
|
||||
fav: character.fav,
|
||||
date_added: character.date_added,
|
||||
create_date: character.create_date,
|
||||
date_last_chat: character.date_last_chat,
|
||||
chat_size: character.chat_size,
|
||||
data_size: character.data_size,
|
||||
data: {
|
||||
name: _.get(character, 'data.name', ''),
|
||||
character_version: _.get(character, 'data.character_version', ''),
|
||||
creator: _.get(character, 'data.creator', ''),
|
||||
creator_notes: _.get(character, 'data.creator_notes', ''),
|
||||
extensions: {
|
||||
fav: _.get(character, 'data.extensions.fav', false),
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* processCharacter - Process a given character, read its data and calculate its statistics.
|
||||
*
|
||||
* @param {string} item The name of the character.
|
||||
* @param {import('../users.js').UserDirectoryList} directories User directories
|
||||
* @param {object} options Options for the character processing
|
||||
* @param {boolean} options.shallow If true, only return the core character's metadata
|
||||
* @return {Promise<object>} A Promise that resolves when the character processing is done.
|
||||
*/
|
||||
const processCharacter = async (item, directories) => {
|
||||
const processCharacter = async (item, directories, { shallow }) => {
|
||||
try {
|
||||
const imgFile = path.join(directories.characters, item);
|
||||
const imgData = await readCharacterData(imgFile);
|
||||
@@ -226,7 +258,7 @@ const processCharacter = async (item, directories) => {
|
||||
character['chat_size'] = chatSize;
|
||||
character['date_last_chat'] = dateLastChat;
|
||||
character['data_size'] = calculateDataSize(jsonObject?.data);
|
||||
return character;
|
||||
return shallow ? toShallow(character) : character;
|
||||
}
|
||||
catch (err) {
|
||||
console.error(`Could not process character: ${item}`);
|
||||
@@ -993,7 +1025,7 @@ router.post('/all', jsonParser, async function (request, response) {
|
||||
try {
|
||||
const files = fs.readdirSync(request.user.directories.characters);
|
||||
const pngFiles = files.filter(file => file.endsWith('.png'));
|
||||
const processingPromises = pngFiles.map(file => processCharacter(file, request.user.directories));
|
||||
const processingPromises = pngFiles.map(file => processCharacter(file, request.user.directories, { shallow: useShallowCharacters }));
|
||||
const data = (await Promise.all(processingPromises)).filter(c => c.name);
|
||||
return response.send(data);
|
||||
} catch (err) {
|
||||
@@ -1012,7 +1044,7 @@ router.post('/get', jsonParser, validateAvatarUrlMiddleware, async function (req
|
||||
return response.sendStatus(404);
|
||||
}
|
||||
|
||||
const data = await processCharacter(item, request.user.directories);
|
||||
const data = await processCharacter(item, request.user.directories, { shallow: false });
|
||||
|
||||
return response.send(data);
|
||||
} catch (err) {
|
||||
@@ -1022,11 +1054,11 @@ router.post('/get', jsonParser, validateAvatarUrlMiddleware, async function (req
|
||||
});
|
||||
|
||||
router.post('/chats', jsonParser, validateAvatarUrlMiddleware, async function (request, response) {
|
||||
if (!request.body) return response.sendStatus(400);
|
||||
|
||||
const characterDirectory = (request.body.avatar_url).replace('.png', '');
|
||||
|
||||
try {
|
||||
if (!request.body) return response.sendStatus(400);
|
||||
|
||||
const characterDirectory = (request.body.avatar_url).replace('.png', '');
|
||||
|
||||
const chatsDirectory = path.join(request.user.directories.chats, characterDirectory);
|
||||
|
||||
if (!fs.existsSync(chatsDirectory)) {
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import crypto from 'node:crypto';
|
||||
import { getConfigValue } from './util.js';
|
||||
import { getConfigValue, tryParse } from './util.js';
|
||||
|
||||
const PROMPT_PLACEHOLDER = getConfigValue('promptPlaceholder', 'Let\'s get started.');
|
||||
|
||||
@@ -411,11 +411,12 @@ export function convertGooglePrompt(messages, model, useSysPrompt, names) {
|
||||
}
|
||||
|
||||
const system_instruction = { parts: { text: sys_prompt.trim() } };
|
||||
const toolNameMap = {};
|
||||
|
||||
const contents = [];
|
||||
messages.forEach((message, index) => {
|
||||
// fix the roles
|
||||
if (message.role === 'system') {
|
||||
if (message.role === 'system' || message.role === 'tool') {
|
||||
message.role = 'user';
|
||||
} else if (message.role === 'assistant') {
|
||||
message.role = 'model';
|
||||
@@ -423,7 +424,21 @@ export function convertGooglePrompt(messages, model, useSysPrompt, names) {
|
||||
|
||||
// Convert the content to an array of parts
|
||||
if (!Array.isArray(message.content)) {
|
||||
message.content = [{ type: 'text', text: String(message.content ?? '') }];
|
||||
const content = (() => {
|
||||
const hasToolCalls = Array.isArray(message.tool_calls) && message.tool_calls.length > 0;
|
||||
const hasToolCallId = typeof message.tool_call_id === 'string' && message.tool_call_id.length > 0;
|
||||
|
||||
if (hasToolCalls) {
|
||||
return { type: 'tool_calls', tool_calls: message.tool_calls };
|
||||
}
|
||||
|
||||
if (hasToolCallId) {
|
||||
return { type: 'tool_call_id', tool_call_id: message.tool_call_id, content: String(message.content ?? '') };
|
||||
}
|
||||
|
||||
return { type: 'text', text: String(message.content ?? '') };
|
||||
})();
|
||||
message.content = [content];
|
||||
}
|
||||
|
||||
// similar story as claude
|
||||
@@ -455,6 +470,25 @@ export function convertGooglePrompt(messages, model, useSysPrompt, names) {
|
||||
message.content.forEach((part) => {
|
||||
if (part.type === 'text') {
|
||||
parts.push({ text: part.text });
|
||||
} else if (part.type === 'tool_call_id') {
|
||||
const name = toolNameMap[part.tool_call_id] ?? 'unknown';
|
||||
parts.push({
|
||||
functionResponse: {
|
||||
name: name,
|
||||
response: { name: name, content: part.content },
|
||||
},
|
||||
});
|
||||
} else if (part.type === 'tool_calls') {
|
||||
part.tool_calls.forEach((toolCall) => {
|
||||
parts.push({
|
||||
functionCall: {
|
||||
name: toolCall.function.name,
|
||||
args: tryParse(toolCall.function.arguments) ?? toolCall.function.arguments,
|
||||
},
|
||||
});
|
||||
|
||||
toolNameMap[toolCall.id] = toolCall.function.name;
|
||||
});
|
||||
} else if (part.type === 'image_url' && isMultimodal) {
|
||||
const mimeType = part.image_url.url.split(';')[0].split(':')[1];
|
||||
const base64Data = part.image_url.url.split(',')[1];
|
||||
@@ -473,7 +507,7 @@ export function convertGooglePrompt(messages, model, useSysPrompt, names) {
|
||||
if (part.text) {
|
||||
contents[contents.length - 1].parts[0].text += '\n\n' + part.text;
|
||||
}
|
||||
if (part.inlineData) {
|
||||
if (part.inlineData || part.functionCall || part.functionResponse) {
|
||||
contents[contents.length - 1].parts.push(part);
|
||||
}
|
||||
});
|
||||
|
21
src/server-events.js
Normal file
21
src/server-events.js
Normal file
@@ -0,0 +1,21 @@
|
||||
import EventEmitter from 'node:events';
|
||||
import process from 'node:process';
|
||||
|
||||
/**
|
||||
* @typedef {import('../index').ServerEventMap} ServerEventMap
|
||||
* @type {EventEmitter<ServerEventMap>} The default event source.
|
||||
*/
|
||||
export const serverEvents = new EventEmitter();
|
||||
process.serverEvents = serverEvents;
|
||||
export default serverEvents;
|
||||
|
||||
/**
|
||||
* @enum {string}
|
||||
* @readonly
|
||||
*/
|
||||
export const EVENT_NAMES = Object.freeze({
|
||||
/**
|
||||
* Emitted when the server has started.
|
||||
*/
|
||||
SERVER_STARTED: 'server-started',
|
||||
});
|
15
src/util.js
15
src/util.js
@@ -16,6 +16,7 @@ import mime from 'mime-types';
|
||||
import { default as simpleGit } from 'simple-git';
|
||||
import chalk from 'chalk';
|
||||
import { LOG_LEVELS } from './constants.js';
|
||||
import bytes from 'bytes';
|
||||
|
||||
/**
|
||||
* Parsed config object.
|
||||
@@ -856,14 +857,10 @@ export function setupLogLevel() {
|
||||
export class MemoryLimitedMap {
|
||||
/**
|
||||
* Creates an instance of MemoryLimitedMap.
|
||||
* @param {number} maxMemoryInBytes - The maximum allowed memory in bytes for string values.
|
||||
* @param {string} cacheCapacity - Maximum memory usage in human-readable format (e.g., '1 GB').
|
||||
*/
|
||||
constructor(maxMemoryInBytes) {
|
||||
if (typeof maxMemoryInBytes !== 'number' || maxMemoryInBytes <= 0 || isNaN(maxMemoryInBytes)) {
|
||||
console.warn('Invalid maxMemoryInBytes, using a fallback value of 1 GB.');
|
||||
maxMemoryInBytes = 1024 * 1024 * 1024; // 1 GB
|
||||
}
|
||||
this.maxMemory = maxMemoryInBytes;
|
||||
constructor(cacheCapacity) {
|
||||
this.maxMemory = bytes.parse(cacheCapacity) ?? 0;
|
||||
this.currentMemory = 0;
|
||||
this.map = new Map();
|
||||
this.queue = [];
|
||||
@@ -886,6 +883,10 @@ export class MemoryLimitedMap {
|
||||
* @param {string} value
|
||||
*/
|
||||
set(key, value) {
|
||||
if (this.maxMemory <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof key !== 'string' || typeof value !== 'string') {
|
||||
return;
|
||||
}
|
||||
|
Reference in New Issue
Block a user