Merge branch 'staging' of http://github.com/cohee1207/SillyTavern into staging

This commit is contained in:
Cohee1207 2023-07-30 16:20:05 +03:00
commit 1b7973ec13
13 changed files with 240 additions and 32 deletions

View File

@ -291,7 +291,6 @@ SillyTavern 会将 API 密钥保存在目录中的 `secrets.json` 文件内。
* RossAscends' additions: AGPL v3 * RossAscends' additions: AGPL v3
* Portions of CncAnon's TavernAITurbo mod: Unknown license * Portions of CncAnon's TavernAITurbo mod: Unknown license
* kingbri's various commits and suggestions (https://github.com/bdashore3) * kingbri's various commits and suggestions (https://github.com/bdashore3)
* BlipRanger's miscellaneous UI & extension modifications (https://github.com/BlipRanger)
* Waifu mode inspired by the work of PepperTaco (https://github.com/peppertaco/Tavern/) * Waifu mode inspired by the work of PepperTaco (https://github.com/peppertaco/Tavern/)
* Thanks Pygmalion University for being awesome testers and suggesting cool features! * Thanks Pygmalion University for being awesome testers and suggesting cool features!
* Thanks oobabooga for compiling presets for TextGen * Thanks oobabooga for compiling presets for TextGen

2
.github/readme.md vendored
View File

@ -293,7 +293,6 @@ GNU Affero General Public License for more details.**
* RossAscends' additions: AGPL v3 * RossAscends' additions: AGPL v3
* Portions of CncAnon's TavernAITurbo mod: Unknown license * Portions of CncAnon's TavernAITurbo mod: Unknown license
* kingbri's various commits and suggestions (<https://github.com/bdashore3>) * kingbri's various commits and suggestions (<https://github.com/bdashore3>)
* BlipRanger's miscellaneous UI & extension modifications (<https://github.com/BlipRanger>)
* Waifu mode inspired by the work of PepperTaco (<https://github.com/peppertaco/Tavern/>) * Waifu mode inspired by the work of PepperTaco (<https://github.com/peppertaco/Tavern/>)
* Thanks Pygmalion University for being awesome testers and suggesting cool features! * Thanks Pygmalion University for being awesome testers and suggesting cool features!
* Thanks oobabooga for compiling presets for TextGen * Thanks oobabooga for compiling presets for TextGen
@ -306,3 +305,4 @@ GNU Affero General Public License for more details.**
* 10K Discord Users Celebratory Background by @kallmeflocc * 10K Discord Users Celebratory Background by @kallmeflocc
* Default content (characters and lore books) provided by @OtisAlejandro, @RossAscends and @kallmeflocc * Default content (characters and lore books) provided by @OtisAlejandro, @RossAscends and @kallmeflocc
* Korean translation by @doloroushyeonse * Korean translation by @doloroushyeonse
* k_euler_a support for Horde by <https://github.com/Teashrock>

1
.gitignore vendored
View File

@ -26,4 +26,5 @@ secrets.json
/dist /dist
/backups/ /backups/
public/movingUI/ public/movingUI/
public/QuickReplies/
content.log content.log

4
package-lock.json generated
View File

@ -1,12 +1,12 @@
{ {
"name": "sillytavern", "name": "sillytavern",
"version": "1.9.2", "version": "1.9.3",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "sillytavern", "name": "sillytavern",
"version": "1.9.2", "version": "1.9.3",
"license": "AGPL-3.0", "license": "AGPL-3.0",
"dependencies": { "dependencies": {
"@dqbd/tiktoken": "^1.0.2", "@dqbd/tiktoken": "^1.0.2",

View File

@ -51,7 +51,7 @@
"type": "git", "type": "git",
"url": "https://github.com/SillyTavern/SillyTavern.git" "url": "https://github.com/SillyTavern/SillyTavern.git"
}, },
"version": "1.9.2", "version": "1.9.3",
"scripts": { "scripts": {
"start": "node server.js", "start": "node server.js",
"pkg": "pkg --compress Gzip --no-bytecode --public ." "pkg": "pkg --compress Gzip --no-bytecode --public ."

View File

@ -0,0 +1,23 @@
{
"name": "Default",
"quickReplyEnabled": true,
"quickReplySlots": [
{
"mes": "/?",
"label": "HELP",
"enabled": true
},
{
"mes": "/newchat",
"label": "New Chat",
"enabled": true
},
{
"mes": "/bgcol",
"label": "Match UI to Background",
"enabled": true
}
],
"numberOfSlots": 3,
"selectedPreset": "Default"
}

View File

@ -683,6 +683,14 @@
</div> </div>
</div> </div>
</div> </div>
<div class="range-block" data-source="claude">
<div class="range-block-title" data-i18n="Assistant Prefill">
Assistant Prefill
</div>
<div class="wide100p">
<input type="text" id="claude_assistant_prefill" class="text_pole" placeholder="Start Claude's answer with...">
</div>
</div>
</div> </div>
<hr> <hr>
</div> </div>

View File

@ -737,6 +737,9 @@ let token;
var PromptArrayItemForRawPromptDisplay; var PromptArrayItemForRawPromptDisplay;
export let active_character = ""
export let active_group = ""
export function getRequestHeaders() { export function getRequestHeaders() {
return { return {
"Content-Type": "application/json", "Content-Type": "application/json",
@ -786,6 +789,14 @@ function checkOnlineStatus() {
} }
} }
export function setActiveCharacter(character) {
active_character = character;
}
export function setActiveGroup(group) {
active_group = group;
}
async function getStatus() { async function getStatus() {
if (is_get_status) { if (is_get_status) {
if (main_api == "koboldhorde") { if (main_api == "koboldhorde") {
@ -5009,6 +5020,10 @@ async function getSettings(type) {
highlightSelectedAvatar(); highlightSelectedAvatar();
setPersonaDescription(); setPersonaDescription();
//Load the active character and group
active_character = settings.active_character;
active_group = settings.active_group;
//Load the API server URL from settings //Load the API server URL from settings
api_server = settings.api_server; api_server = settings.api_server;
$("#api_url_text").val(api_server); $("#api_url_text").val(api_server);
@ -5049,6 +5064,8 @@ async function saveSettings(type) {
data: JSON.stringify({ data: JSON.stringify({
firstRun: firstRun, firstRun: firstRun,
username: name1, username: name1,
active_character: active_character,
active_group: active_group,
api_server: api_server, api_server: api_server,
api_server_textgenerationwebui: api_server_textgenerationwebui, api_server_textgenerationwebui: api_server_textgenerationwebui,
preset_settings: preset_settings, preset_settings: preset_settings,

View File

@ -13,6 +13,10 @@ import {
menu_type, menu_type,
max_context, max_context,
saveSettingsDebounced, saveSettingsDebounced,
active_group,
active_character,
setActiveGroup,
setActiveCharacter,
} from "../script.js"; } from "../script.js";
import { import {
@ -330,11 +334,21 @@ export function RA_CountCharTokens() {
characterStatsHandler(characters, this_chid); characterStatsHandler(characters, this_chid);
}); });
} }
//Auto Load Last Charcter -- (fires when active_character is defined and auto_load_chat is true) /**
* Auto load chat with the last active character or group.
* Fires when active_character is defined and auto_load_chat is true.
* The function first tries to find a character with a specific ID from the global settings.
* If it doesn't exist, it tries to find a group with a specific grid from the global settings.
* If the character list hadn't been loaded yet, it calls itself again after 100ms delay.
* The character or group is selected (clicked) if it is found.
*/
async function RA_autoloadchat() { async function RA_autoloadchat() {
if (document.getElementById('CharID0') !== null) { if (document.getElementById('CharID0') !== null) {
var charToAutoLoad = document.getElementById('CharID' + LoadLocal('ActiveChar')); // active character is the name, we should look it up in the character list and get the id
let groupToAutoLoad = document.querySelector(`.group_select[grid="${LoadLocal('ActiveGroup')}"]`); let active_character_id = Object.keys(characters).find(key => characters[key].avatar === active_character);
var charToAutoLoad = document.getElementById('CharID' + active_character_id);
let groupToAutoLoad = document.querySelector(`.group_select[grid="${active_group}"]`);
if (charToAutoLoad != null) { if (charToAutoLoad != null) {
$(charToAutoLoad).click(); $(charToAutoLoad).click();
} }
@ -342,7 +356,7 @@ async function RA_autoloadchat() {
$(groupToAutoLoad).click(); $(groupToAutoLoad).click();
} }
// if the charcter list hadn't been loaded yet, try again. // if the character list hadn't been loaded yet, try again.
} else { setTimeout(RA_autoloadchat, 100); } } else { setTimeout(RA_autoloadchat, 100); }
} }
@ -903,16 +917,22 @@ $("document").ready(function () {
$("#rm_button_characters").click(function () { SaveLocal('SelectedNavTab', 'rm_button_characters'); }); $("#rm_button_characters").click(function () { SaveLocal('SelectedNavTab', 'rm_button_characters'); });
// when a char is selected from the list, save them as the auto-load character for next page load // when a char is selected from the list, save them as the auto-load character for next page load
// when a char is selected from the list, save their name as the auto-load character for next page load
$(document).on("click", ".character_select", function () { $(document).on("click", ".character_select", function () {
SaveLocal('ActiveChar', $(this).attr('chid')); setActiveCharacter($(this).find('.avatar').attr('title'));
SaveLocal('ActiveGroup', null); setActiveGroup(null);
saveSettingsDebounced();
}); });
$(document).on("click", ".group_select", function () { $(document).on("click", ".group_select", function () {
SaveLocal('ActiveChar', null); setActiveCharacter(null);
SaveLocal('ActiveGroup', $(this).data('id')); setActiveGroup($(this).data('id'));
saveSettingsDebounced();
}); });
//this makes the chat input text area resize vertically to match the text size (limited by CSS at 50% window height) //this makes the chat input text area resize vertically to match the text size (limited by CSS at 50% window height)
$('#send_textarea').on('input', function () { $('#send_textarea').on('input', function () {
this.style.height = '40px'; this.style.height = '40px';

View File

@ -1,19 +1,48 @@
import { saveSettingsDebounced } from "../../../script.js"; import { saveSettingsDebounced, callPopup, getRequestHeaders } from "../../../script.js";
import { getContext, extension_settings } from "../../extensions.js"; import { getContext, extension_settings } from "../../extensions.js";
import { initScrollHeight, resetScrollHeight } from "../../utils.js"; import { initScrollHeight, resetScrollHeight } from "../../utils.js";
export { MODULE_NAME }; export { MODULE_NAME };
const MODULE_NAME = 'quick-reply'; const MODULE_NAME = 'quick-reply';
const UPDATE_INTERVAL = 1000; const UPDATE_INTERVAL = 1000;
let presets = [];
let selected_preset = '';
const defaultSettings = { const defaultSettings = {
quickReplyEnabled: false, quickReplyEnabled: true,
numberOfSlots: 5, numberOfSlots: 5,
quickReplySlots: [], quickReplySlots: [],
} }
async function loadSettings() { //method from worldinfo
async function updateQuickReplyPresetList() {
var result = await fetch("/getsettings", {
method: "POST",
headers: getRequestHeaders(),
body: JSON.stringify({}),
});
if (result.ok) {
var data = await result.json();
presets = data.quickReplyPresets?.length ? data.quickReplyPresets : [];
console.log(presets)
$("#quickReplyPresets").find('option[value!=""]').remove();
if (presets !== undefined) {
presets.forEach((item, i) => {
$("#quickReplyPresets").append(`<option value='${item.name}'${selected_preset.includes(item.name) ? ' selected' : ''}>${item.name}</option>`);
});
}
}
}
async function loadSettings(type) {
if (type === 'init') {
await updateQuickReplyPresetList()
}
if (Object.keys(extension_settings.quickReply).length === 0) { if (Object.keys(extension_settings.quickReply).length === 0) {
Object.assign(extension_settings.quickReply, defaultSettings); Object.assign(extension_settings.quickReply, defaultSettings);
} }
@ -111,6 +140,51 @@ async function moduleWorker() {
if (extension_settings.quickReply.quickReplyEnabled === true) { if (extension_settings.quickReply.quickReplyEnabled === true) {
$('#quickReplyBar').toggle(getContext().onlineStatus !== 'no_connection'); $('#quickReplyBar').toggle(getContext().onlineStatus !== 'no_connection');
} }
if (extension_settings.quickReply.selectedPreset) {
selected_preset = extension_settings.quickReply.selectedPreset;
}
}
async function saveQuickReplyPreset() {
const name = await callPopup('Enter a name for the Quick Reply Preset:', 'input');
if (!name) {
return;
}
const quickReplyPreset = {
name: name,
quickReplyEnabled: extension_settings.quickReply.quickReplyEnabled,
quickReplySlots: extension_settings.quickReply.quickReplySlots,
numberOfSlots: extension_settings.quickReply.numberOfSlots,
selectedPreset: name
}
const response = await fetch('/savequickreply', {
method: 'POST',
headers: getRequestHeaders(),
body: JSON.stringify(quickReplyPreset)
});
if (response.ok) {
const quickReplyPresetIndex = presets.findIndex(x => x.name == name);
if (quickReplyPresetIndex == -1) {
presets.push(quickReplyPreset);
const option = document.createElement('option');
option.selected = true;
option.value = name;
option.innerText = name;
$('#quickReplyPresets').append(option);
}
else {
presets[quickReplyPresetIndex] = quickReplyPreset;
$(`#quickReplyPresets option[value="${name}"]`).attr('selected', true);
}
saveSettingsDebounced();
} else {
toastr.warning('Failed to save Quick Reply Preset.')
}
} }
async function onQuickReplyNumberOfSlotsInput() { async function onQuickReplyNumberOfSlotsInput() {
@ -178,6 +252,27 @@ function generateQuickReplyElements() {
}); });
} }
async function applyQuickReplyPreset(name) {
const quickReplyPreset = presets.find(x => x.name == name);
if (!quickReplyPreset) {
console.log(`error, QR preset '${name}' not found`)
return;
}
extension_settings.quickReply = quickReplyPreset;
extension_settings.quickReply.selectedPreset = name;
saveSettingsDebounced()
loadSettings('init')
addQuickReplyBar();
moduleWorker();
$(`#quickReplyPresets option[value="${name}"]`).attr('selected', true);
console.debug('QR Preset applied: ' + name);
//loadMovingUIState()
}
jQuery(async () => { jQuery(async () => {
moduleWorker(); moduleWorker();
@ -190,11 +285,18 @@ jQuery(async () => {
<div class="inline-drawer-icon fa-solid fa-circle-chevron-down down"></div> <div class="inline-drawer-icon fa-solid fa-circle-chevron-down down"></div>
</div> </div>
<div class="inline-drawer-content"> <div class="inline-drawer-content">
<label class="checkbox_label marginBot10"> <div class="flex-container ">
<label class="checkbox_label marginBot10 wide100p flexnowrap">
<input id="quickReplyEnabled" type="checkbox" /> <input id="quickReplyEnabled" type="checkbox" />
Enable Quick Replies Enable Quick Replies
</label> </label>
<div class="flex-container flexnowrap wide100p">
<select id="quickReplyPresets" name="quickreply-preset">
</select>
<i id="quickReplyPresetSaveButton" class="fa-solid fa-save"></i>
</div>
<label for="quickReplyNumberOfSlots">Number of slots:</label> <label for="quickReplyNumberOfSlots">Number of slots:</label>
</div>
<div class="flex-container flexGap5 flexnowrap"> <div class="flex-container flexGap5 flexnowrap">
<input id="quickReplyNumberOfSlots" class="text_pole" type="number" min="1" max="100" value="" /> <input id="quickReplyNumberOfSlots" class="text_pole" type="number" min="1" max="100" value="" />
<div class="menu_button menu_button_icon" id="quickReplyNumberOfSlotsApply"> <div class="menu_button menu_button_icon" id="quickReplyNumberOfSlotsApply">
@ -212,8 +314,17 @@ jQuery(async () => {
$('#quickReplyEnabled').on('input', onQuickReplyEnabledInput); $('#quickReplyEnabled').on('input', onQuickReplyEnabledInput);
$('#quickReplyNumberOfSlotsApply').on('click', onQuickReplyNumberOfSlotsInput); $('#quickReplyNumberOfSlotsApply').on('click', onQuickReplyNumberOfSlotsInput);
$("#quickReplyPresetSaveButton").on('click', saveQuickReplyPreset);
await loadSettings(); $("#quickReplyPresets").on('change', async function () {
const quickReplyPresetSelected = $(this).find(':selected').val();
extension_settings.quickReplyPreset = quickReplyPresetSelected;
applyQuickReplyPreset(quickReplyPresetSelected);
saveSettingsDebounced();
});
await loadSettings('init');
addQuickReplyBar(); addQuickReplyBar();
}); });

View File

@ -90,13 +90,6 @@ function loadNovelSettings(settings) {
nai_settings.cfg_scale = settings.cfg_scale; nai_settings.cfg_scale = settings.cfg_scale;
nai_settings.streaming_novel = !!settings.streaming_novel; nai_settings.streaming_novel = !!settings.streaming_novel;
loadNovelSettingsUi(nai_settings); loadNovelSettingsUi(nai_settings);
// reload the preset to migrate any new settings
for (const key of Object.keys(nai_settings)) {
if (typeof nai_settings[key] === 'number' && Number.isNaN(nai_settings[key])) {
$("#settings_perset_novel").trigger("change");
}
}
} }
const phraseRepPenStrings = [ const phraseRepPenStrings = [
@ -109,7 +102,7 @@ const phraseRepPenStrings = [
] ]
function getPhraseRepPenString(phraseRepPenCounter) { function getPhraseRepPenString(phraseRepPenCounter) {
if (phraseRepPenCounter < 1 || phraseRepPenCounter > F5) { if (phraseRepPenCounter < 1 || phraseRepPenCounter > 5) {
return null; return null;
} else { } else {
return phraseRepPenStrings[phraseRepPenCounter]; return phraseRepPenStrings[phraseRepPenCounter];

View File

@ -143,6 +143,7 @@ const default_settings = {
api_url_scale: '', api_url_scale: '',
show_external_models: false, show_external_models: false,
proxy_password: '', proxy_password: '',
assistant_prefill: '',
}; };
const oai_settings = { const oai_settings = {
@ -180,6 +181,7 @@ const oai_settings = {
api_url_scale: '', api_url_scale: '',
show_external_models: false, show_external_models: false,
proxy_password: '', proxy_password: '',
assistant_prefill: '',
}; };
let openai_setting_names; let openai_setting_names;
@ -775,6 +777,7 @@ async function sendOpenAIRequest(type, openai_msgs_tosend, signal) {
if (isClaude) { if (isClaude) {
generate_data['use_claude'] = true; generate_data['use_claude'] = true;
generate_data['top_k'] = parseFloat(oai_settings.top_k_openai); generate_data['top_k'] = parseFloat(oai_settings.top_k_openai);
generate_data['assistant_prefill'] = substituteParams(oai_settings.assistant_prefill);
} }
if (isOpenRouter) { if (isOpenRouter) {
@ -1109,6 +1112,7 @@ function loadOpenAISettings(data, settings) {
oai_settings.api_url_scale = settings.api_url_scale ?? default_settings.api_url_scale; oai_settings.api_url_scale = settings.api_url_scale ?? default_settings.api_url_scale;
oai_settings.show_external_models = settings.show_external_models ?? default_settings.show_external_models; oai_settings.show_external_models = settings.show_external_models ?? default_settings.show_external_models;
oai_settings.proxy_password = settings.proxy_password ?? default_settings.proxy_password; oai_settings.proxy_password = settings.proxy_password ?? default_settings.proxy_password;
oai_settings.assistant_prefill = settings.assistant_prefill ?? default_settings.assistant_prefill;
if (settings.nsfw_toggle !== undefined) oai_settings.nsfw_toggle = !!settings.nsfw_toggle; if (settings.nsfw_toggle !== undefined) oai_settings.nsfw_toggle = !!settings.nsfw_toggle;
if (settings.keep_example_dialogue !== undefined) oai_settings.keep_example_dialogue = !!settings.keep_example_dialogue; if (settings.keep_example_dialogue !== undefined) oai_settings.keep_example_dialogue = !!settings.keep_example_dialogue;
@ -1121,6 +1125,7 @@ function loadOpenAISettings(data, settings) {
$('#stream_toggle').prop('checked', oai_settings.stream_openai); $('#stream_toggle').prop('checked', oai_settings.stream_openai);
$('#api_url_scale').val(oai_settings.api_url_scale); $('#api_url_scale').val(oai_settings.api_url_scale);
$('#openai_proxy_password').val(oai_settings.proxy_password); $('#openai_proxy_password').val(oai_settings.proxy_password);
$('#claude_assistant_prefill').val(oai_settings.assistant_prefill);
$('#model_openai_select').val(oai_settings.openai_model); $('#model_openai_select').val(oai_settings.openai_model);
$(`#model_openai_select option[value="${oai_settings.openai_model}"`).attr('selected', true); $(`#model_openai_select option[value="${oai_settings.openai_model}"`).attr('selected', true);
@ -1323,6 +1328,7 @@ async function saveOpenAIPreset(name, settings) {
stream_openai: settings.stream_openai, stream_openai: settings.stream_openai,
api_url_scale: settings.api_url_scale, api_url_scale: settings.api_url_scale,
show_external_models: settings.show_external_models, show_external_models: settings.show_external_models,
assistant_prefill: settings.assistant_prefill,
}; };
const savePresetSettings = await fetch(`/savepreset_openai?name=${name}`, { const savePresetSettings = await fetch(`/savepreset_openai?name=${name}`, {
@ -1656,6 +1662,7 @@ function onSettingsPresetChange() {
api_url_scale: ['#api_url_scale', 'api_url_scale', false], api_url_scale: ['#api_url_scale', 'api_url_scale', false],
show_external_models: ['#openai_show_external_models', 'show_external_models', true], show_external_models: ['#openai_show_external_models', 'show_external_models', true],
proxy_password: ['#openai_proxy_password', 'proxy_password', false], proxy_password: ['#openai_proxy_password', 'proxy_password', false],
assistant_prefill: ['#claude_assistant_prefill', 'assistant_prefill', false],
}; };
for (const [key, [selector, setting, isCheckbox]] of Object.entries(settingsToUpdate)) { for (const [key, [selector, setting, isCheckbox]] of Object.entries(settingsToUpdate)) {
@ -2206,6 +2213,11 @@ $(document).ready(function () {
saveSettingsDebounced(); saveSettingsDebounced();
}); });
$('#claude_assistant_prefill').on('input', function () {
oai_settings.assistant_prefill = $(this).val();
saveSettingsDebounced();
});
$("#api_button_openai").on("click", onConnectButtonClick); $("#api_button_openai").on("click", onConnectButtonClick);
$("#openai_reverse_proxy").on("input", onReverseProxyInput); $("#openai_reverse_proxy").on("input", onReverseProxyInput);
$("#model_openai_select").on("change", onModelChange); $("#model_openai_select").on("change", onModelChange);

View File

@ -290,6 +290,7 @@ const directories = {
instruct: 'public/instruct', instruct: 'public/instruct',
context: 'public/context', context: 'public/context',
backups: 'backups/', backups: 'backups/',
quickreplies: 'public/QuickReplies'
}; };
// CSRF Protection // // CSRF Protection //
@ -1600,6 +1601,8 @@ app.post('/getsettings', jsonParser, (request, response) => {
const themes = readAndParseFromDirectory(directories.themes); const themes = readAndParseFromDirectory(directories.themes);
const movingUIPresets = readAndParseFromDirectory(directories.movingUI); const movingUIPresets = readAndParseFromDirectory(directories.movingUI);
const quickReplyPresets = readAndParseFromDirectory(directories.quickreplies);
const instruct = readAndParseFromDirectory(directories.instruct); const instruct = readAndParseFromDirectory(directories.instruct);
const context = readAndParseFromDirectory(directories.context); const context = readAndParseFromDirectory(directories.context);
@ -1616,6 +1619,7 @@ app.post('/getsettings', jsonParser, (request, response) => {
textgenerationwebui_preset_names, textgenerationwebui_preset_names,
themes, themes,
movingUIPresets, movingUIPresets,
quickReplyPresets,
instruct, instruct,
context, context,
enable_extensions: enableExtensions, enable_extensions: enableExtensions,
@ -1672,6 +1676,17 @@ app.post('/savemovingui', jsonParser, (request, response) => {
return response.sendStatus(200); return response.sendStatus(200);
}); });
app.post('/savequickreply', jsonParser, (request, response) => {
if (!request.body || !request.body.name) {
return response.sendStatus(400);
}
const filename = path.join(directories.quickreplies, sanitize(request.body.name) + '.json');
fs.writeFileSync(filename, JSON.stringify(request.body, null, 4), 'utf8');
return response.sendStatus(200);
});
function convertWorldInfoToCharacterBook(name, entries) { function convertWorldInfoToCharacterBook(name, entries) {
const result = { entries: [], name }; const result = { entries: [], name };
@ -3077,7 +3092,12 @@ async function sendClaudeRequest(request, response) {
controller.abort(); controller.abort();
}); });
const requestPrompt = convertClaudePrompt(request.body.messages, true, true); let requestPrompt = convertClaudePrompt(request.body.messages, true, true);
if (request.body.assistant_prefill) {
requestPrompt += request.body.assistant_prefill;
}
console.log('Claude request:', requestPrompt); console.log('Claude request:', requestPrompt);
const generateResponse = await fetch(api_url + '/complete', { const generateResponse = await fetch(api_url + '/complete', {
@ -3260,6 +3280,10 @@ app.post("/generate_openai", jsonParser, function (request, response_generate_op
message = 'API key disabled or exhausted'; message = 'API key disabled or exhausted';
console.log(message); console.log(message);
break; break;
case 451:
message = error?.response?.data?.error?.message || 'Unavailable for legal reasons';
console.log(message);
break;
} }
const quota_error = error?.response?.status === 429 && error?.response?.data?.error?.type === 'insufficient_quota'; const quota_error = error?.response?.status === 429 && error?.response?.data?.error?.type === 'insufficient_quota';