mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-06-05 21:59:27 +02:00
Compare commits
1 Commits
1.12.14
...
update-tra
Author | SHA1 | Date | |
---|---|---|---|
|
ba1c69d7a7 |
3
.github/workflows/pr-auto-manager.yml
vendored
3
.github/workflows/pr-auto-manager.yml
vendored
@@ -30,8 +30,7 @@ jobs:
|
||||
# https://github.com/marketplace/actions/checkout
|
||||
uses: actions/checkout@v4.2.2
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
repository: ${{ github.event.pull_request.head.repo.full_name }}
|
||||
ref: ${{ github.head_ref }}
|
||||
|
||||
- name: Setup Node.js
|
||||
# Setup Node.js environment
|
||||
|
@@ -155,7 +155,6 @@ whitelistImportDomains:
|
||||
- cdn.discordapp.com
|
||||
- files.catbox.moe
|
||||
- raw.githubusercontent.com
|
||||
- char-archive.evulid.cc
|
||||
# API request overrides (for KoboldAI and Text Completion APIs)
|
||||
## Note: host includes the port number if it's not the default (80 or 443)
|
||||
## Format is an array of objects:
|
||||
|
1500
package-lock.json
generated
1500
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -3,6 +3,7 @@
|
||||
"@adobe/css-tools": "^4.4.2",
|
||||
"@agnai/sentencepiece-js": "^1.1.1",
|
||||
"@agnai/web-tokenizers": "^0.1.3",
|
||||
"@huggingface/transformers": "^3.4.2",
|
||||
"@iconfu/svg-inject": "^1.2.3",
|
||||
"@jimp/core": "^1.6.0",
|
||||
"@jimp/js-bmp": "^1.6.0",
|
||||
@@ -74,7 +75,6 @@
|
||||
"sanitize-filename": "^1.6.3",
|
||||
"seedrandom": "^3.0.5",
|
||||
"showdown": "^2.1.0",
|
||||
"sillytavern-transformers": "2.14.6",
|
||||
"simple-git": "^3.27.0",
|
||||
"slidetoggle": "^4.0.0",
|
||||
"tiktoken": "^1.0.20",
|
||||
@@ -100,6 +100,9 @@
|
||||
},
|
||||
"node-fetch": {
|
||||
"whatwg-url": "^14.0.0"
|
||||
},
|
||||
"@huggingface/transformers": {
|
||||
"onnxruntime-node": "https://github.com/Cohee1207/onnxruntime/releases/download/1.20.1/onnxruntime-node-1.20.1.tgz"
|
||||
}
|
||||
},
|
||||
"name": "sillytavern",
|
||||
@@ -109,7 +112,7 @@
|
||||
"type": "git",
|
||||
"url": "https://github.com/SillyTavern/SillyTavern.git"
|
||||
},
|
||||
"version": "1.12.14",
|
||||
"version": "1.12.13",
|
||||
"scripts": {
|
||||
"start": "node server.js",
|
||||
"debug": "node --inspect server.js",
|
||||
|
@@ -332,7 +332,7 @@ try {
|
||||
// 1. Create default config files
|
||||
createDefaultFiles();
|
||||
// 2. Copy transformers WASM binaries from node_modules
|
||||
copyWasmFiles();
|
||||
// copyWasmFiles();
|
||||
// 3. Add missing config values
|
||||
addMissingConfigValues();
|
||||
} catch (error) {
|
||||
|
@@ -1419,7 +1419,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div data-tg-type="aphrodite, ooba, koboldcpp, tabby, llamacpp, dreamgen" id="dryBlock" class="wide100p">
|
||||
<div data-tg-type="aphrodite, ooba, koboldcpp, tabby, llamacpp" id="dryBlock" class="wide100p">
|
||||
<h4 class="wide100p textAlignCenter" title="DRY penalizes tokens that would extend the end of the input into a sequence that has previously occurred in the input. Set multiplier to 0 to disable." data-i18n="[title]DRY_Repetition_Penalty_desc">
|
||||
<label data-i18n="DRY Repetition Penalty">DRY Repetition Penalty</label>
|
||||
<a href="https://github.com/oobabooga/text-generation-webui/pull/5677" target="_blank">
|
||||
@@ -1574,7 +1574,7 @@
|
||||
<div class="fa-solid fa-circle-info opacity50p " data-i18n="[title]Add the bos_token to the beginning of prompts. Disabling this can make the replies more creative" title="Add the bos_token to the beginning of prompts. Disabling this can make the replies more creative."></div>
|
||||
</label>
|
||||
</label>
|
||||
<label data-tg-type="ooba, llamacpp, tabby, koboldcpp, dreamgen" class="checkbox_label flexGrow flexShrink" for="ban_eos_token_textgenerationwebui">
|
||||
<label data-tg-type="ooba, llamacpp, tabby, koboldcpp" class="checkbox_label flexGrow flexShrink" for="ban_eos_token_textgenerationwebui">
|
||||
<input type="checkbox" id="ban_eos_token_textgenerationwebui" />
|
||||
<label>
|
||||
<small data-i18n="Ban EOS Token">Ban EOS Token</small>
|
||||
@@ -2762,7 +2762,7 @@
|
||||
<option value="xai">xAI (Grok)</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
<div class="inline-drawer wide100p" data-source="openai,claude,mistralai,makersuite,deepseek,xai">
|
||||
<div class="inline-drawer wide100p" data-source="openai,claude,mistralai,makersuite,deepseek">
|
||||
<div class="inline-drawer-toggle inline-drawer-header">
|
||||
<b data-i18n="Reverse Proxy">Reverse Proxy</b>
|
||||
<div class="fa-solid fa-circle-chevron-down inline-drawer-icon down"></div>
|
||||
@@ -2825,7 +2825,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="ReverseProxyWarningMessage" data-source="openai,claude,mistralai,makersuite,deepseek,xai">
|
||||
<div id="ReverseProxyWarningMessage" data-source="openai,claude,mistralai,makersuite,deepseek">
|
||||
<div class="reverse_proxy_warning">
|
||||
<b>
|
||||
<div data-i18n="Using a proxy that you're not running yourself is a risk to your data privacy.">
|
||||
@@ -2897,7 +2897,7 @@
|
||||
<option value="gpt-4.1-nano">gpt-4.1-nano</option>
|
||||
<option value="gpt-4.1-nano-2025-04-14">gpt-4.1-nano-2025-04-14</option>
|
||||
</optgroup>
|
||||
<optgroup label="o1">
|
||||
<optgroup label="o1 and o1-mini">
|
||||
<option value="o1">o1</option>
|
||||
<option value="o1-2024-12-17">o1-2024-12-17</option>
|
||||
<option value="o1-mini">o1-mini</option>
|
||||
@@ -2906,15 +2906,9 @@
|
||||
<option value="o1-preview-2024-09-12">o1-preview-2024-09-12</option>
|
||||
</optgroup>
|
||||
<optgroup label="o3">
|
||||
<option value="o3">o3</option>
|
||||
<option value="o3-2025-04-16">o3-2025-04-16</option>
|
||||
<option value="o3-mini">o3-mini</option>
|
||||
<option value="o3-mini-2025-01-31">o3-mini-2025-01-31</option>
|
||||
</optgroup>
|
||||
<optgroup label="o4">
|
||||
<option value="o4-mini">o4-mini</option>
|
||||
<option value="o4-mini-2025-04-16">o4-mini-2025-04-16</option>
|
||||
</optgroup>
|
||||
<optgroup label="GPT-4.5">
|
||||
<option value="gpt-4.5-preview">gpt-4.5-preview</option>
|
||||
<option value="gpt-4.5-preview-2025-02-27">gpt-4.5-preview-2025-02-27</option>
|
||||
@@ -3162,7 +3156,6 @@
|
||||
<option value="gemini-2.5-pro-exp-03-25">Gemini 2.5 Pro Experimental 2025-03-25</option>
|
||||
<option value="gemini-2.0-pro-exp">Gemini 2.0 Pro Experimental</option>
|
||||
<option value="gemini-2.0-pro-exp-02-05">Gemini 2.0 Pro Experimental 2025-02-05</option>
|
||||
<option value="gemini-2.5-flash-preview-04-17">Gemini 2.5 Flash Preview 2025-04-17</option>
|
||||
<option value="gemini-2.0-flash-lite-preview">Gemini 2.0 Flash-Lite Preview</option>
|
||||
<option value="gemini-2.0-flash-lite-preview-02-05">Gemini 2.0 Flash-Lite Preview 2025-02-05</option>
|
||||
<option value="gemini-2.0-flash-001">Gemini 2.0 Flash [001]</option>
|
||||
|
@@ -11847,8 +11847,8 @@ jQuery(async function () {
|
||||
return;
|
||||
}
|
||||
const drawer = $(this).closest('.inline-drawer');
|
||||
const icon = drawer.find('>.inline-drawer-header .inline-drawer-icon');
|
||||
const drawerContent = drawer.find('>.inline-drawer-content');
|
||||
const icon = drawer.find('.inline-drawer-icon');
|
||||
const drawerContent = drawer.find('.inline-drawer-content');
|
||||
icon.toggleClass('down up');
|
||||
icon.toggleClass('fa-circle-chevron-down fa-circle-chevron-up');
|
||||
drawerContent.stop().slideToggle({
|
||||
|
@@ -39,7 +39,7 @@ To install a single 3rd party extension, use the "Install Extensions"
|
||||
<span data-i18n="Characters">Characters</span>
|
||||
</div>
|
||||
</div>
|
||||
<div id="assets_menu">
|
||||
<div class="inline-drawer-content" id="assets_menu">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -60,10 +60,6 @@
|
||||
<option data-type="openai" value="chatgpt-4o-latest">chatgpt-4o-latest</option>
|
||||
<option data-type="openai" value="o1">o1</option>
|
||||
<option data-type="openai" value="o1-2024-12-17">o1-2024-12-17</option>
|
||||
<option data-type="openai" value="o3">o3</option>
|
||||
<option data-type="openai" value="o3-2025-04-16">o3-2025-04-16</option>
|
||||
<option data-type="openai" value="o4-mini">o4-mini</option>
|
||||
<option data-type="openai" value="o4-mini-2025-04-16">o4-mini-2025-04-16</option>
|
||||
<option data-type="openai" value="gpt-4.5-preview">gpt-4.5-preview</option>
|
||||
<option data-type="openai" value="gpt-4.5-preview-2025-02-27">gpt-4.5-preview-2025-02-27</option>
|
||||
<option data-type="anthropic" value="claude-3-7-sonnet-latest">claude-3-7-sonnet-latest</option>
|
||||
@@ -80,7 +76,6 @@
|
||||
<option data-type="google" value="gemini-2.5-pro-exp-03-25">gemini-2.5-pro-exp-03-25</option>
|
||||
<option data-type="google" value="gemini-2.0-pro-exp">gemini-2.0-pro-exp</option>
|
||||
<option data-type="google" value="gemini-2.0-pro-exp-02-05">gemini-2.0-pro-exp-02-05</option>
|
||||
<option data-type="google" value="gemini-2.5-flash-preview-04-17">gemini-2.5-flash-preview-04-17</option>
|
||||
<option data-type="google" value="gemini-2.0-flash-lite-preview">gemini-2.0-flash-lite-preview</option>
|
||||
<option data-type="google" value="gemini-2.0-flash-lite-preview-02-05">gemini-2.0-flash-lite-preview-02-05</option>
|
||||
<option data-type="google" value="gemini-2.0-flash">gemini-2.0-flash</option>
|
||||
|
@@ -76,7 +76,7 @@
|
||||
<div id="tts_voicemap_block">
|
||||
</div>
|
||||
<hr>
|
||||
<form id="tts_provider_settings">
|
||||
<form id="tts_provider_settings" class="inline-drawer-content">
|
||||
</form>
|
||||
<div class="tts_buttons">
|
||||
<input id="tts_voices" class="menu_button" type="submit" value="Available voices" />
|
||||
|
@@ -79,10 +79,6 @@ class SystemTtsProvider {
|
||||
// Config //
|
||||
//########//
|
||||
|
||||
// Static constants for the simulated default voice
|
||||
static BROWSER_DEFAULT_VOICE_ID = '__browser_default__';
|
||||
static BROWSER_DEFAULT_VOICE_NAME = 'System Default Voice';
|
||||
|
||||
settings;
|
||||
ready = false;
|
||||
voices = [];
|
||||
@@ -172,97 +168,51 @@ class SystemTtsProvider {
|
||||
//#################//
|
||||
fetchTtsVoiceObjects() {
|
||||
if (!('speechSynthesis' in window)) {
|
||||
return Promise.resolve([]);
|
||||
return [];
|
||||
}
|
||||
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
let voices = speechSynthesis.getVoices();
|
||||
const voices = speechSynthesis
|
||||
.getVoices()
|
||||
.sort((a, b) => a.lang.localeCompare(b.lang) || a.name.localeCompare(b.name))
|
||||
.map(x => ({ name: x.name, voice_id: x.voiceURI, preview_url: false, lang: x.lang }));
|
||||
|
||||
if (voices.length === 0) {
|
||||
// Edge compat: Provide default when voices empty
|
||||
console.warn('SystemTTS: getVoices() returned empty list. Providing browser default option.');
|
||||
const defaultVoice = {
|
||||
name: SystemTtsProvider.BROWSER_DEFAULT_VOICE_NAME,
|
||||
voice_id: SystemTtsProvider.BROWSER_DEFAULT_VOICE_ID,
|
||||
preview_url: false,
|
||||
lang: navigator.language || 'en-US',
|
||||
};
|
||||
resolve([defaultVoice]);
|
||||
} else {
|
||||
const mappedVoices = voices
|
||||
.sort((a, b) => a.lang.localeCompare(b.lang) || a.name.localeCompare(b.name))
|
||||
.map(x => ({ name: x.name, voice_id: x.voiceURI, preview_url: false, lang: x.lang }));
|
||||
resolve(mappedVoices);
|
||||
}
|
||||
}, 50);
|
||||
resolve(voices);
|
||||
}, 1);
|
||||
});
|
||||
}
|
||||
|
||||
previewTtsVoice(voiceId) {
|
||||
if (!('speechSynthesis' in window)) {
|
||||
throw new Error('Speech synthesis API is not supported');
|
||||
throw 'Speech synthesis API is not supported';
|
||||
}
|
||||
|
||||
let voice = null;
|
||||
if (voiceId !== SystemTtsProvider.BROWSER_DEFAULT_VOICE_ID) {
|
||||
const voices = speechSynthesis.getVoices();
|
||||
voice = voices.find(x => x.voiceURI === voiceId);
|
||||
const voice = speechSynthesis.getVoices().find(x => x.voiceURI === voiceId);
|
||||
|
||||
if (!voice && voices.length > 0) {
|
||||
console.warn(`SystemTTS Preview: Voice ID "${voiceId}" not found among available voices. Using browser default.`);
|
||||
} else if (!voice && voices.length === 0) {
|
||||
console.warn('SystemTTS Preview: Voice list is empty. Using browser default.');
|
||||
}
|
||||
} else {
|
||||
console.log('SystemTTS Preview: Using browser default voice as requested.');
|
||||
if (!voice) {
|
||||
throw `TTS Voice id ${voiceId} not found`;
|
||||
}
|
||||
|
||||
speechSynthesis.cancel();
|
||||
const langForPreview = voice ? voice.lang : (navigator.language || 'en-US');
|
||||
const text = getPreviewString(langForPreview);
|
||||
const text = getPreviewString(voice.lang);
|
||||
const utterance = new SpeechSynthesisUtterance(text);
|
||||
|
||||
if (voice) {
|
||||
utterance.voice = voice;
|
||||
}
|
||||
|
||||
utterance.voice = voice;
|
||||
utterance.rate = this.settings.rate || 1;
|
||||
utterance.pitch = this.settings.pitch || 1;
|
||||
|
||||
utterance.onerror = (event) => {
|
||||
console.error(`SystemTTS Preview Error: ${event.error}`, event);
|
||||
};
|
||||
|
||||
speechSynthesis.speak(utterance);
|
||||
}
|
||||
|
||||
async getVoice(voiceName) {
|
||||
if (!('speechSynthesis' in window)) {
|
||||
return { voice_id: null, name: 'API Not Supported' };
|
||||
}
|
||||
|
||||
if (voiceName === SystemTtsProvider.BROWSER_DEFAULT_VOICE_NAME) {
|
||||
return {
|
||||
voice_id: SystemTtsProvider.BROWSER_DEFAULT_VOICE_ID,
|
||||
name: SystemTtsProvider.BROWSER_DEFAULT_VOICE_NAME,
|
||||
};
|
||||
return { voice_id: null };
|
||||
}
|
||||
|
||||
const voices = speechSynthesis.getVoices();
|
||||
|
||||
if (voices.length === 0) {
|
||||
console.warn('SystemTTS: Empty voice list, using default fallback');
|
||||
return {
|
||||
voice_id: SystemTtsProvider.BROWSER_DEFAULT_VOICE_ID,
|
||||
name: SystemTtsProvider.BROWSER_DEFAULT_VOICE_NAME,
|
||||
};
|
||||
}
|
||||
|
||||
const match = voices.find(x => x.name == voiceName);
|
||||
|
||||
if (!match) {
|
||||
throw new Error(`SystemTTS getVoice: TTS Voice name "${voiceName}" not found`);
|
||||
throw `TTS Voice name ${voiceName} not found`;
|
||||
}
|
||||
|
||||
return { voice_id: match.voiceURI, name: match.name };
|
||||
@@ -287,6 +237,7 @@ class SystemTtsProvider {
|
||||
speechUtteranceChunker(utterance, {
|
||||
chunkLength: 200,
|
||||
}, function () {
|
||||
//some code to execute when done
|
||||
resolve(silence);
|
||||
console.log('System TTS done');
|
||||
});
|
||||
|
@@ -55,8 +55,6 @@ const getBatchSize = () => ['transformers', 'palm', 'ollama'].includes(settings.
|
||||
const settings = {
|
||||
// For both
|
||||
source: 'transformers',
|
||||
alt_endpoint_url: '',
|
||||
use_alt_endpoint: false,
|
||||
include_wi: false,
|
||||
togetherai_model: 'togethercomputer/m2-bert-80M-32k-retrieval',
|
||||
openai_model: 'text-embedding-ada-002',
|
||||
@@ -111,7 +109,6 @@ const settings = {
|
||||
const moduleWorker = new ModuleWorkerWrapper(synchronizeChat);
|
||||
const webllmProvider = new WebLlmVectorProvider();
|
||||
const cachedSummaries = new Map();
|
||||
const vectorApiRequiresUrl = ['llamacpp', 'vllm', 'ollama', 'koboldcpp'];
|
||||
|
||||
/**
|
||||
* Gets the Collection ID for a file embedded in the chat.
|
||||
@@ -780,14 +777,14 @@ function getVectorsRequestBody(args = {}) {
|
||||
break;
|
||||
case 'ollama':
|
||||
body.model = extension_settings.vectors.ollama_model;
|
||||
body.apiUrl = settings.use_alt_endpoint ? settings.alt_endpoint_url : textgenerationwebui_settings.server_urls[textgen_types.OLLAMA];
|
||||
body.apiUrl = textgenerationwebui_settings.server_urls[textgen_types.OLLAMA];
|
||||
body.keep = !!extension_settings.vectors.ollama_keep;
|
||||
break;
|
||||
case 'llamacpp':
|
||||
body.apiUrl = settings.use_alt_endpoint ? settings.alt_endpoint_url : textgenerationwebui_settings.server_urls[textgen_types.LLAMACPP];
|
||||
body.apiUrl = textgenerationwebui_settings.server_urls[textgen_types.LLAMACPP];
|
||||
break;
|
||||
case 'vllm':
|
||||
body.apiUrl = settings.use_alt_endpoint ? settings.alt_endpoint_url : textgenerationwebui_settings.server_urls[textgen_types.VLLM];
|
||||
body.apiUrl = textgenerationwebui_settings.server_urls[textgen_types.VLLM];
|
||||
body.model = extension_settings.vectors.vllm_model;
|
||||
break;
|
||||
case 'webllm':
|
||||
@@ -886,18 +883,11 @@ function throwIfSourceInvalid() {
|
||||
throw new Error('Vectors: API key missing', { cause: 'api_key_missing' });
|
||||
}
|
||||
|
||||
if (vectorApiRequiresUrl.includes(settings.source) && settings.use_alt_endpoint) {
|
||||
if (!settings.alt_endpoint_url) {
|
||||
throw new Error('Vectors: API URL missing', { cause: 'api_url_missing' });
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (settings.source === 'ollama' && !textgenerationwebui_settings.server_urls[textgen_types.OLLAMA] ||
|
||||
settings.source === 'vllm' && !textgenerationwebui_settings.server_urls[textgen_types.VLLM] ||
|
||||
settings.source === 'koboldcpp' && !textgenerationwebui_settings.server_urls[textgen_types.KOBOLDCPP] ||
|
||||
settings.source === 'llamacpp' && !textgenerationwebui_settings.server_urls[textgen_types.LLAMACPP]) {
|
||||
throw new Error('Vectors: API URL missing', { cause: 'api_url_missing' });
|
||||
}
|
||||
if (settings.source === 'ollama' && !textgenerationwebui_settings.server_urls[textgen_types.OLLAMA] ||
|
||||
settings.source === 'vllm' && !textgenerationwebui_settings.server_urls[textgen_types.VLLM] ||
|
||||
settings.source === 'koboldcpp' && !textgenerationwebui_settings.server_urls[textgen_types.KOBOLDCPP] ||
|
||||
settings.source === 'llamacpp' && !textgenerationwebui_settings.server_urls[textgen_types.LLAMACPP]) {
|
||||
throw new Error('Vectors: API URL missing', { cause: 'api_url_missing' });
|
||||
}
|
||||
|
||||
if (settings.source === 'ollama' && !settings.ollama_model || settings.source === 'vllm' && !settings.vllm_model) {
|
||||
@@ -1097,7 +1087,6 @@ function toggleSettings() {
|
||||
$('#webllm_vectorsModel').toggle(settings.source === 'webllm');
|
||||
$('#koboldcpp_vectorsModel').toggle(settings.source === 'koboldcpp');
|
||||
$('#google_vectorsModel').toggle(settings.source === 'palm');
|
||||
$('#vector_altEndpointUrl').toggle(vectorApiRequiresUrl.includes(settings.source));
|
||||
if (settings.source === 'webllm') {
|
||||
loadWebLlmModels();
|
||||
}
|
||||
@@ -1176,7 +1165,7 @@ async function createKoboldCppEmbeddings(items) {
|
||||
headers: getRequestHeaders(),
|
||||
body: JSON.stringify({
|
||||
items: items,
|
||||
server: settings.use_alt_endpoint ? settings.alt_endpoint_url : textgenerationwebui_settings.server_urls[textgen_types.KOBOLDCPP],
|
||||
server: textgenerationwebui_settings.server_urls[textgen_types.KOBOLDCPP],
|
||||
}),
|
||||
});
|
||||
|
||||
@@ -1478,16 +1467,6 @@ jQuery(async () => {
|
||||
saveSettingsDebounced();
|
||||
toggleSettings();
|
||||
});
|
||||
$('#vector_altEndpointUrl_enabled').prop('checked', settings.use_alt_endpoint).on('input', () => {
|
||||
settings.use_alt_endpoint = $('#vector_altEndpointUrl_enabled').prop('checked');
|
||||
Object.assign(extension_settings.vectors, settings);
|
||||
saveSettingsDebounced();
|
||||
});
|
||||
$('#vector_altEndpoint_address').val(settings.alt_endpoint_url).on('change', () => {
|
||||
settings.alt_endpoint_url = String($('#vector_altEndpoint_address').val());
|
||||
Object.assign(extension_settings.vectors, settings);
|
||||
saveSettingsDebounced();
|
||||
});
|
||||
$('#api_key_nomicai').on('click', async () => {
|
||||
const popupText = 'NomicAI API Key:';
|
||||
const key = await callGenericPopup(popupText, POPUP_TYPE.INPUT, '', {
|
||||
|
@@ -25,16 +25,6 @@
|
||||
<option value="webllm" data-i18n="WebLLM Extension">WebLLM Extension</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="flex-container flexFlowColumn" id="vector_altEndpointUrl">
|
||||
<label class="checkbox_label" for="vector_altEndpointUrl_enabled" title="Enable secondary endpoint URL usage, instead of the main one.">
|
||||
<input id="vector_altEndpointUrl_enabled" type="checkbox" class="checkbox">
|
||||
<span data-i18n="Use secondary URL">Use secondary URL</span>
|
||||
</label>
|
||||
<label for="vector_altEndpoint_address" data-i18n="Secondary Embedding endpoint URL">
|
||||
Secondary Embedding endpoint URL
|
||||
</label>
|
||||
<input id="vector_altEndpoint_address" class="text_pole" type="text" placeholder="e.g. http://localhost:5001" />
|
||||
</div>
|
||||
<div class="flex-container flexFlowColumn" id="webllm_vectorsModel">
|
||||
<label for="vectors_webllm_model" data-i18n="Vectorization Model">
|
||||
Vectorization Model
|
||||
|
@@ -1412,9 +1412,9 @@ export async function prepareOpenAIMessages({
|
||||
await populateChatCompletion(prompts, chatCompletion, { bias, quietPrompt, quietImage, type, cyclePrompt, messages, messageExamples });
|
||||
} catch (error) {
|
||||
if (error instanceof TokenBudgetExceededError) {
|
||||
toastr.error(t`Mandatory prompts exceed the context size.`);
|
||||
chatCompletion.log('Mandatory prompts exceed the context size.');
|
||||
promptManager.error = t`Not enough free tokens for mandatory prompts. Raise your token limit or disable custom prompts.`;
|
||||
toastr.error(t`An error occurred while counting tokens: Token budget exceeded.`);
|
||||
chatCompletion.log('Token budget exceeded.');
|
||||
promptManager.error = t`Not enough free tokens for mandatory prompts. Raise your token Limit or disable custom prompts.`;
|
||||
} else if (error instanceof InvalidCharacterNameError) {
|
||||
toastr.warning(t`An error occurred while counting tokens: Invalid character name`);
|
||||
chatCompletion.log('Invalid character name');
|
||||
@@ -2039,7 +2039,7 @@ async function sendOpenAIRequest(type, messages, signal) {
|
||||
}
|
||||
|
||||
// Proxy is only supported for Claude, OpenAI, Mistral, and Google MakerSuite
|
||||
if (oai_settings.reverse_proxy && [chat_completion_sources.CLAUDE, chat_completion_sources.OPENAI, chat_completion_sources.MISTRALAI, chat_completion_sources.MAKERSUITE, chat_completion_sources.DEEPSEEK, chat_completion_sources.XAI].includes(oai_settings.chat_completion_source)) {
|
||||
if (oai_settings.reverse_proxy && [chat_completion_sources.CLAUDE, chat_completion_sources.OPENAI, chat_completion_sources.MISTRALAI, chat_completion_sources.MAKERSUITE, chat_completion_sources.DEEPSEEK].includes(oai_settings.chat_completion_source)) {
|
||||
await validateReverseProxy();
|
||||
generate_data['reverse_proxy'] = oai_settings.reverse_proxy;
|
||||
generate_data['proxy_password'] = oai_settings.proxy_password;
|
||||
@@ -2180,27 +2180,25 @@ async function sendOpenAIRequest(type, messages, signal) {
|
||||
generate_data['seed'] = oai_settings.seed;
|
||||
}
|
||||
|
||||
if (isOAI && /^(o1|o3|o4)/.test(oai_settings.openai_model)) {
|
||||
if (isOAI && (oai_settings.openai_model.startsWith('o1') || oai_settings.openai_model.startsWith('o3'))) {
|
||||
generate_data.messages.forEach((msg) => {
|
||||
if (msg.role === 'system') {
|
||||
msg.role = 'user';
|
||||
}
|
||||
});
|
||||
generate_data.max_completion_tokens = generate_data.max_tokens;
|
||||
delete generate_data.max_tokens;
|
||||
delete generate_data.logprobs;
|
||||
delete generate_data.top_logprobs;
|
||||
delete generate_data.stop;
|
||||
delete generate_data.logit_bias;
|
||||
delete generate_data.n;
|
||||
delete generate_data.temperature;
|
||||
delete generate_data.top_p;
|
||||
delete generate_data.frequency_penalty;
|
||||
delete generate_data.presence_penalty;
|
||||
if (oai_settings.openai_model.startsWith('o1')) {
|
||||
generate_data.messages.forEach((msg) => {
|
||||
if (msg.role === 'system') {
|
||||
msg.role = 'user';
|
||||
}
|
||||
});
|
||||
delete generate_data.n;
|
||||
delete generate_data.tools;
|
||||
delete generate_data.tool_choice;
|
||||
}
|
||||
delete generate_data.tools;
|
||||
delete generate_data.tool_choice;
|
||||
delete generate_data.stop;
|
||||
delete generate_data.logit_bias;
|
||||
}
|
||||
|
||||
await eventSource.emit(event_types.CHAT_COMPLETION_SETTINGS_READY, generate_data);
|
||||
@@ -2236,8 +2234,7 @@ async function sendOpenAIRequest(type, messages, signal) {
|
||||
|
||||
if (Array.isArray(parsed?.choices) && parsed?.choices?.[0]?.index > 0) {
|
||||
const swipeIndex = parsed.choices[0].index - 1;
|
||||
// FIXME: state.reasoning should be an array to support multi-swipe
|
||||
swipes[swipeIndex] = (swipes[swipeIndex] || '') + getStreamingReply(parsed, state, { overrideShowThoughts: false });
|
||||
swipes[swipeIndex] = (swipes[swipeIndex] || '') + getStreamingReply(parsed, state);
|
||||
} else {
|
||||
text += getStreamingReply(parsed, state);
|
||||
}
|
||||
@@ -3548,7 +3545,7 @@ async function getStatusOpen() {
|
||||
chat_completion_source: oai_settings.chat_completion_source,
|
||||
};
|
||||
|
||||
if (oai_settings.reverse_proxy && [chat_completion_sources.CLAUDE, chat_completion_sources.OPENAI, chat_completion_sources.MISTRALAI, chat_completion_sources.MAKERSUITE, chat_completion_sources.DEEPSEEK, chat_completion_sources.XAI].includes(oai_settings.chat_completion_source)) {
|
||||
if (oai_settings.reverse_proxy && [chat_completion_sources.CLAUDE, chat_completion_sources.OPENAI, chat_completion_sources.MISTRALAI, chat_completion_sources.MAKERSUITE, chat_completion_sources.DEEPSEEK].includes(oai_settings.chat_completion_source)) {
|
||||
await validateReverseProxy();
|
||||
}
|
||||
|
||||
@@ -4131,12 +4128,9 @@ function getMaxContextOpenAI(value) {
|
||||
else if (value.includes('gpt-4.1')) {
|
||||
return max_1mil;
|
||||
}
|
||||
else if (value.startsWith('o1')) {
|
||||
else if (value.startsWith('o1') || value.startsWith('o3')) {
|
||||
return max_128k;
|
||||
}
|
||||
else if (value.startsWith('o4') || value.startsWith('o3')) {
|
||||
return max_200k;
|
||||
}
|
||||
else if (value.includes('chatgpt-4o-latest') || value.includes('gpt-4-turbo') || value.includes('gpt-4o') || value.includes('gpt-4-1106') || value.includes('gpt-4-0125') || value.includes('gpt-4-vision')) {
|
||||
return max_128k;
|
||||
}
|
||||
@@ -4451,7 +4445,7 @@ async function onModelChange() {
|
||||
$('#openai_max_context').attr('max', max_32k);
|
||||
} else if (value.includes('gemini-1.5-pro') || value.includes('gemini-exp-1206') || value.includes('gemini-2.0-pro')) {
|
||||
$('#openai_max_context').attr('max', max_2mil);
|
||||
} else if (value.includes('gemini-1.5-flash') || value.includes('gemini-2.0-flash') || value.includes('gemini-2.5-flash-preview-04-17') || value.includes('gemini-2.5-pro-exp-03-25') || value.includes('gemini-2.5-pro-preview-03-25')) {
|
||||
} else if (value.includes('gemini-1.5-flash') || value.includes('gemini-2.0-flash') || value.includes('gemini-2.5-pro-exp-03-25') || value.includes('gemini-2.5-pro-preview-03-25')) {
|
||||
$('#openai_max_context').attr('max', max_1mil);
|
||||
} else if (value.includes('gemini-1.0-pro') || value === 'gemini-pro') {
|
||||
$('#openai_max_context').attr('max', max_32k);
|
||||
@@ -4949,7 +4943,7 @@ async function onConnectButtonClick(e) {
|
||||
await writeSecret(SECRET_KEYS.XAI, api_key_xai);
|
||||
}
|
||||
|
||||
if (!secret_state[SECRET_KEYS.XAI] && !oai_settings.reverse_proxy) {
|
||||
if (!secret_state[SECRET_KEYS.XAI]) {
|
||||
console.log('No secret key saved for XAI');
|
||||
return;
|
||||
}
|
||||
@@ -5103,7 +5097,6 @@ export function isImageInliningSupported() {
|
||||
'gemini-2.5-pro-preview-03-25',
|
||||
'gemini-2.0-pro-exp',
|
||||
'gemini-2.0-pro-exp-02-05',
|
||||
'gemini-2.5-flash-preview-04-17',
|
||||
'gemini-2.0-flash-lite-preview',
|
||||
'gemini-2.0-flash-lite-preview-02-05',
|
||||
'gemini-2.0-flash',
|
||||
@@ -5156,15 +5149,11 @@ export function isImageInliningSupported() {
|
||||
'grok-2-vision',
|
||||
'grok-vision',
|
||||
'gpt-4.1',
|
||||
'o3',
|
||||
'o3-2025-04-16',
|
||||
'o4-mini',
|
||||
'o4-mini-2025-04-16',
|
||||
];
|
||||
|
||||
switch (oai_settings.chat_completion_source) {
|
||||
case chat_completion_sources.OPENAI:
|
||||
return visionSupportedModels.some(model => oai_settings.openai_model.includes(model) && !oai_settings.openai_model.includes('gpt-4-turbo-preview') && !oai_settings.openai_model.includes('o3-mini'));
|
||||
return visionSupportedModels.some(model => oai_settings.openai_model.includes(model) && !oai_settings.openai_model.includes('gpt-4-turbo-preview'));
|
||||
case chat_completion_sources.MAKERSUITE:
|
||||
return visionSupportedModels.some(model => oai_settings.google_model.includes(model));
|
||||
case chat_completion_sources.CLAUDE:
|
||||
|
@@ -928,10 +928,6 @@ export function getCurrentDreamGenModelTokenizer() {
|
||||
return tokenizers.YI;
|
||||
} else if (model.id.startsWith('opus-v1-xl')) {
|
||||
return tokenizers.LLAMA;
|
||||
} else if (model.id.startsWith('lucid-v1-medium')) {
|
||||
return tokenizers.NEMO;
|
||||
} else if (model.id.startsWith('lucid-v1-extra-large')) {
|
||||
return tokenizers.LLAMA3;
|
||||
} else {
|
||||
return tokenizers.MISTRAL;
|
||||
}
|
||||
|
@@ -1338,18 +1338,6 @@ function registerWorldInfoSlashCommands() {
|
||||
}
|
||||
}
|
||||
|
||||
async function getGlobalBooksCallback() {
|
||||
if (!selected_world_info?.length) {
|
||||
return JSON.stringify([]);
|
||||
}
|
||||
|
||||
let entries = selected_world_info.slice();
|
||||
|
||||
console.debug(`[WI] Selected global world info has ${entries.length} entries`, selected_world_info);
|
||||
|
||||
return JSON.stringify(entries);
|
||||
}
|
||||
|
||||
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
||||
name: 'world',
|
||||
callback: onWorldInfoChange,
|
||||
@@ -1391,13 +1379,6 @@ function registerWorldInfoSlashCommands() {
|
||||
],
|
||||
aliases: ['getchatlore', 'getchatwi'],
|
||||
}));
|
||||
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
||||
name: 'getglobalbooks',
|
||||
callback: getGlobalBooksCallback,
|
||||
returns: 'list of selected lorebook names',
|
||||
helpString: 'Get a list of names of the selected global lorebooks and pass it down the pipe.',
|
||||
aliases: ['getgloballore', 'getglobalwi'],
|
||||
}));
|
||||
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
||||
name: 'getpersonabook',
|
||||
callback: getPersonaBookCallback,
|
||||
|
@@ -268,6 +268,23 @@ export const FEATHERLESS_KEYS = [
|
||||
'guided_whitespace_pattern',
|
||||
];
|
||||
|
||||
// https://dreamgen.com/docs/api#openai-text
|
||||
export const DREAMGEN_KEYS = [
|
||||
'model',
|
||||
'prompt',
|
||||
'max_tokens',
|
||||
'temperature',
|
||||
'top_p',
|
||||
'top_k',
|
||||
'min_p',
|
||||
'repetition_penalty',
|
||||
'frequency_penalty',
|
||||
'presence_penalty',
|
||||
'stop',
|
||||
'stream',
|
||||
'minimum_message_content_tokens',
|
||||
];
|
||||
|
||||
// https://docs.together.ai/reference/completions
|
||||
export const TOGETHERAI_KEYS = [
|
||||
'model',
|
||||
|
@@ -250,7 +250,7 @@ async function sendClaudeRequest(request, response) {
|
||||
if (!generateResponse.ok) {
|
||||
const generateResponseText = await generateResponse.text();
|
||||
console.warn(color.red(`Claude API returned error: ${generateResponse.status} ${generateResponse.statusText}\n${generateResponseText}\n${divider}`));
|
||||
return response.status(500).send({ error: true });
|
||||
return response.status(generateResponse.status).send({ error: true });
|
||||
}
|
||||
|
||||
/** @type {any} */
|
||||
@@ -366,7 +366,6 @@ async function sendMakerSuiteRequest(request, response) {
|
||||
|
||||
const useSystemPrompt = !useMultiModal && (
|
||||
model.includes('gemini-2.5-pro') ||
|
||||
model.includes('gemini-2.5-flash') ||
|
||||
model.includes('gemini-2.0-pro') ||
|
||||
model.includes('gemini-2.0-flash') ||
|
||||
model.includes('gemini-2.0-flash-thinking-exp') ||
|
||||
@@ -464,7 +463,7 @@ async function sendMakerSuiteRequest(request, response) {
|
||||
} else {
|
||||
if (!generateResponse.ok) {
|
||||
console.warn(`Google AI Studio API returned error: ${generateResponse.status} ${generateResponse.statusText} ${await generateResponse.text()}`);
|
||||
return response.status(500).send({ error: true });
|
||||
return response.status(generateResponse.status).send({ error: true });
|
||||
}
|
||||
|
||||
/** @type {any} */
|
||||
@@ -831,100 +830,6 @@ async function sendDeepSeekRequest(request, response) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a request to XAI API.
|
||||
* @param {express.Request} request Express request
|
||||
* @param {express.Response} response Express response
|
||||
*/
|
||||
async function sendXaiRequest(request, response) {
|
||||
const apiUrl = new URL(request.body.reverse_proxy || API_XAI).toString();
|
||||
const apiKey = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.XAI);
|
||||
|
||||
if (!apiKey && !request.body.reverse_proxy) {
|
||||
console.warn('xAI API key is missing.');
|
||||
return response.status(400).send({ error: true });
|
||||
}
|
||||
|
||||
const controller = new AbortController();
|
||||
request.socket.removeAllListeners('close');
|
||||
request.socket.on('close', function () {
|
||||
controller.abort();
|
||||
});
|
||||
|
||||
try {
|
||||
let bodyParams = {};
|
||||
|
||||
if (request.body.logprobs > 0) {
|
||||
bodyParams['top_logprobs'] = request.body.logprobs;
|
||||
bodyParams['logprobs'] = true;
|
||||
}
|
||||
|
||||
if (Array.isArray(request.body.tools) && request.body.tools.length > 0) {
|
||||
bodyParams['tools'] = request.body.tools;
|
||||
bodyParams['tool_choice'] = request.body.tool_choice;
|
||||
}
|
||||
|
||||
if (Array.isArray(request.body.stop) && request.body.stop.length > 0) {
|
||||
bodyParams['stop'] = request.body.stop;
|
||||
}
|
||||
|
||||
if (['grok-3-mini-beta', 'grok-3-mini-fast-beta'].includes(request.body.model)) {
|
||||
bodyParams['reasoning_effort'] = request.body.reasoning_effort === 'high' ? 'high' : 'low';
|
||||
}
|
||||
|
||||
const processedMessages = request.body.messages = convertXAIMessages(request.body.messages, getPromptNames(request));
|
||||
|
||||
const requestBody = {
|
||||
'messages': processedMessages,
|
||||
'model': request.body.model,
|
||||
'temperature': request.body.temperature,
|
||||
'max_tokens': request.body.max_tokens,
|
||||
'max_completion_tokens': request.body.max_completion_tokens,
|
||||
'stream': request.body.stream,
|
||||
'presence_penalty': request.body.presence_penalty,
|
||||
'frequency_penalty': request.body.frequency_penalty,
|
||||
'top_p': request.body.top_p,
|
||||
'seed': request.body.seed,
|
||||
'n': request.body.n,
|
||||
...bodyParams,
|
||||
};
|
||||
|
||||
const config = {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': 'Bearer ' + apiKey,
|
||||
},
|
||||
body: JSON.stringify(requestBody),
|
||||
signal: controller.signal,
|
||||
};
|
||||
|
||||
console.debug('xAI request:', requestBody);
|
||||
|
||||
const generateResponse = await fetch(apiUrl + '/chat/completions', config);
|
||||
|
||||
if (request.body.stream) {
|
||||
forwardFetchResponse(generateResponse, response);
|
||||
} else {
|
||||
if (!generateResponse.ok) {
|
||||
const errorText = await generateResponse.text();
|
||||
console.warn(`xAI API returned error: ${generateResponse.status} ${generateResponse.statusText} ${errorText}`);
|
||||
const errorJson = tryParse(errorText) ?? { error: true };
|
||||
return response.status(500).send(errorJson);
|
||||
}
|
||||
const generateResponseJson = await generateResponse.json();
|
||||
console.debug('xAI response:', generateResponseJson);
|
||||
return response.send(generateResponseJson);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error communicating with xAI API: ', error);
|
||||
if (!response.headersSent) {
|
||||
response.send({ error: true });
|
||||
} else {
|
||||
response.end();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const router = express.Router();
|
||||
|
||||
@@ -970,9 +875,8 @@ router.post('/status', async function (request, response_getstatus_openai) {
|
||||
api_key_openai = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.DEEPSEEK);
|
||||
headers = {};
|
||||
} else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.XAI) {
|
||||
api_url = new URL(request.body.reverse_proxy || API_XAI);
|
||||
api_key_openai = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.XAI);
|
||||
headers = {};
|
||||
api_url = API_XAI;
|
||||
api_key_openai = readSecret(request.user.directories, SECRET_KEYS.XAI);
|
||||
} else {
|
||||
console.warn('This chat completion source is not supported yet.');
|
||||
return response_getstatus_openai.status(400).send({ error: true });
|
||||
@@ -1140,7 +1044,6 @@ router.post('/generate', function (request, response) {
|
||||
case CHAT_COMPLETION_SOURCES.MISTRALAI: return sendMistralAIRequest(request, response);
|
||||
case CHAT_COMPLETION_SOURCES.COHERE: return sendCohereRequest(request, response);
|
||||
case CHAT_COMPLETION_SOURCES.DEEPSEEK: return sendDeepSeekRequest(request, response);
|
||||
case CHAT_COMPLETION_SOURCES.XAI: return sendXaiRequest(request, response);
|
||||
}
|
||||
|
||||
let apiUrl;
|
||||
@@ -1252,6 +1155,12 @@ router.post('/generate', function (request, response) {
|
||||
apiKey = readSecret(request.user.directories, SECRET_KEYS.ZEROONEAI);
|
||||
headers = {};
|
||||
bodyParams = {};
|
||||
} else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.XAI) {
|
||||
apiUrl = API_XAI;
|
||||
apiKey = readSecret(request.user.directories, SECRET_KEYS.XAI);
|
||||
headers = {};
|
||||
bodyParams = {};
|
||||
request.body.messages = convertXAIMessages(request.body.messages, getPromptNames(request));
|
||||
} else {
|
||||
console.warn('This chat completion source is not supported yet.');
|
||||
return response.status(400).send({ error: true });
|
||||
@@ -1259,11 +1168,17 @@ router.post('/generate', function (request, response) {
|
||||
|
||||
// A few of OpenAIs reasoning models support reasoning effort
|
||||
if ([CHAT_COMPLETION_SOURCES.CUSTOM, CHAT_COMPLETION_SOURCES.OPENAI].includes(request.body.chat_completion_source)) {
|
||||
if (['o1', 'o3-mini', 'o3-mini-2025-01-31', 'o4-mini', 'o4-mini-2025-04-16', 'o3', 'o3-2025-04-16'].includes(request.body.model)) {
|
||||
if (['o1', 'o3-mini', 'o3-mini-2025-01-31'].includes(request.body.model)) {
|
||||
bodyParams['reasoning_effort'] = request.body.reasoning_effort;
|
||||
}
|
||||
}
|
||||
|
||||
if ([CHAT_COMPLETION_SOURCES.XAI].includes(request.body.chat_completion_source)) {
|
||||
if (['grok-3-mini-beta', 'grok-3-mini-fast-beta'].includes(request.body.model)) {
|
||||
bodyParams['reasoning_effort'] = request.body.reasoning_effort === 'high' ? 'high' : 'low';
|
||||
}
|
||||
}
|
||||
|
||||
if (!apiKey && !request.body.reverse_proxy && request.body.chat_completion_source !== CHAT_COMPLETION_SOURCES.CUSTOM) {
|
||||
console.warn('OpenAI API key is missing.');
|
||||
return response.status(400).send({ error: true });
|
||||
|
@@ -10,6 +10,7 @@ import {
|
||||
INFERMATICAI_KEYS,
|
||||
OPENROUTER_KEYS,
|
||||
VLLM_KEYS,
|
||||
DREAMGEN_KEYS,
|
||||
FEATHERLESS_KEYS,
|
||||
OPENAI_KEYS,
|
||||
} from '../../constants.js';
|
||||
@@ -339,6 +340,9 @@ router.post('/generate', async function (request, response) {
|
||||
}
|
||||
|
||||
if (request.body.api_type === TEXTGEN_TYPES.DREAMGEN) {
|
||||
request.body = _.pickBy(request.body, (_, key) => DREAMGEN_KEYS.includes(key));
|
||||
// NOTE: DreamGen sometimes get confused by the unusual formatting in the character cards.
|
||||
request.body.stop?.push('### User', '## User');
|
||||
args.body = JSON.stringify(request.body);
|
||||
}
|
||||
|
||||
@@ -446,7 +450,7 @@ ollama.post('/download', async function (request, response) {
|
||||
|
||||
if (!fetchResponse.ok) {
|
||||
console.error('Download error:', fetchResponse.status, fetchResponse.statusText);
|
||||
return response.status(500).send({ error: true });
|
||||
return response.status(fetchResponse.status).send({ error: true });
|
||||
}
|
||||
|
||||
console.debug('Ollama pull response:', await fetchResponse.json());
|
||||
@@ -655,14 +659,14 @@ tabby.post('/download', async function (request, response) {
|
||||
}
|
||||
} else {
|
||||
console.error('API Permission error:', permissionResponse.status, permissionResponse.statusText);
|
||||
return response.status(500).send({ error: true });
|
||||
return response.status(permissionResponse.status).send({ error: true });
|
||||
}
|
||||
|
||||
const fetchResponse = await fetch(`${baseUrl}/v1/download`, args);
|
||||
|
||||
if (!fetchResponse.ok) {
|
||||
console.error('Download error:', fetchResponse.status, fetchResponse.statusText);
|
||||
return response.status(500).send({ error: true });
|
||||
return response.status(fetchResponse.status).send({ error: true });
|
||||
}
|
||||
|
||||
return response.send({ ok: true });
|
||||
|
@@ -540,21 +540,9 @@ async function downloadGenericPng(url) {
|
||||
|
||||
if (result.ok) {
|
||||
const buffer = Buffer.from(await result.arrayBuffer());
|
||||
let fileName = sanitize(result.url.split('?')[0].split('/').reverse()[0]);
|
||||
const fileName = sanitize(result.url.split('?')[0].split('/').reverse()[0]);
|
||||
const contentType = result.headers.get('content-type') || 'image/png'; //yoink it from AICC function lol
|
||||
|
||||
// The `importCharacter()` function detects the MIME (content-type) of the file
|
||||
// using its file extension. The problem is that not all third-party APIs serve
|
||||
// their cards with a `.png` extension. To support more third-party sites,
|
||||
// dynamically append the `.png` extension to the filename if it doesn't
|
||||
// already have a file extension.
|
||||
if (contentType === 'image/png') {
|
||||
const ext = fileName.match(/\.(\w+)$/); // Same regex used by `importCharacter()`
|
||||
if (!ext) {
|
||||
fileName += '.png';
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
buffer: buffer,
|
||||
fileName: fileName,
|
||||
@@ -706,11 +694,10 @@ router.post('/importURL', async (request, response) => {
|
||||
type = 'character';
|
||||
result = await downloadRisuCharacter(uuid);
|
||||
} else if (isGeneric) {
|
||||
console.info('Downloading from generic url:', url);
|
||||
console.info('Downloading from generic url.');
|
||||
type = 'character';
|
||||
result = await downloadGenericPng(url);
|
||||
} else {
|
||||
console.error(`Received an import for "${getHostFromUrl(url)}", but site is not whitelisted. This domain must be added to the config key "whitelistImportDomains" to allow import from this source.`);
|
||||
return response.sendStatus(404);
|
||||
}
|
||||
|
||||
|
@@ -45,7 +45,7 @@ router.post('/caption-image', async (request, response) => {
|
||||
if (!result.ok) {
|
||||
const error = await result.json();
|
||||
console.error(`Google AI Studio API returned error: ${result.status} ${result.statusText}`, error);
|
||||
return response.status(500).send({ error: true });
|
||||
return response.status(result.status).send({ error: true });
|
||||
}
|
||||
|
||||
/** @type {any} */
|
||||
|
@@ -270,7 +270,7 @@ router.post('/generate', async function (req, res) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
return res.status(500).send({ error: { message } });
|
||||
return res.status(response.status).send({ error: { message } });
|
||||
}
|
||||
|
||||
/** @type {any} */
|
||||
|
@@ -407,10 +407,6 @@ export function getTokenizerModel(requestModel) {
|
||||
return 'o1';
|
||||
}
|
||||
|
||||
if (requestModel.includes('o3') || requestModel.includes('o4-mini')) {
|
||||
return 'o1';
|
||||
}
|
||||
|
||||
if (requestModel.includes('gpt-4o') || requestModel.includes('chatgpt-4o-latest')) {
|
||||
return 'gpt-4o';
|
||||
}
|
||||
|
@@ -364,7 +364,6 @@ export function convertGooglePrompt(messages, model, useSysPrompt, names) {
|
||||
'gemini-2.5-pro-exp-03-25',
|
||||
'gemini-2.0-pro-exp',
|
||||
'gemini-2.0-pro-exp-02-05',
|
||||
'gemini-2.5-flash-preview-04-17',
|
||||
'gemini-2.0-flash-lite-preview',
|
||||
'gemini-2.0-flash-lite-preview-02-05',
|
||||
'gemini-2.0-flash',
|
||||
@@ -509,12 +508,7 @@ export function convertGooglePrompt(messages, model, useSysPrompt, names) {
|
||||
if (index > 0 && message.role === contents[contents.length - 1].role) {
|
||||
parts.forEach((part) => {
|
||||
if (part.text) {
|
||||
const textPart = contents[contents.length - 1].parts.find(p => typeof p.text === 'string');
|
||||
if (textPart) {
|
||||
textPart.text += '\n\n' + part.text;
|
||||
} else {
|
||||
contents[contents.length - 1].parts.push(part);
|
||||
}
|
||||
contents[contents.length - 1].parts[0].text += '\n\n' + part.text;
|
||||
}
|
||||
if (part.inlineData || part.functionCall || part.functionResponse) {
|
||||
contents[contents.length - 1].parts.push(part);
|
||||
|
@@ -3,16 +3,16 @@ import fs from 'node:fs';
|
||||
import process from 'node:process';
|
||||
import { Buffer } from 'node:buffer';
|
||||
|
||||
import { pipeline, env, RawImage } from 'sillytavern-transformers';
|
||||
import { pipeline, env, RawImage } from '@huggingface/transformers';
|
||||
import { getConfigValue } from './util.js';
|
||||
|
||||
configureTransformers();
|
||||
|
||||
function configureTransformers() {
|
||||
// Limit the number of threads to 1 to avoid issues on Android
|
||||
env.backends.onnx.wasm.numThreads = 1;
|
||||
// env.backends.onnx.wasm.numThreads = 1;
|
||||
// Use WASM from a local folder to avoid CDN connections
|
||||
env.backends.onnx.wasm.wasmPaths = path.join(process.cwd(), 'dist') + path.sep;
|
||||
// env.backends.onnx.wasm.wasmPaths = path.join(process.cwd(), 'dist') + path.sep;
|
||||
}
|
||||
|
||||
const tasks = {
|
||||
@@ -115,9 +115,9 @@ async function migrateCacheToDataDir() {
|
||||
|
||||
/**
|
||||
* Gets the transformers.js pipeline for a given task.
|
||||
* @param {import('sillytavern-transformers').PipelineType} task The task to get the pipeline for
|
||||
* @param {import('@huggingface/transformers').PipelineType} task The task to get the pipeline for
|
||||
* @param {string} forceModel The model to use for the pipeline, if any
|
||||
* @returns {Promise<import('sillytavern-transformers').Pipeline>} The transformers.js pipeline
|
||||
* @returns {Promise<import('@huggingface/transformers').Pipeline>} The transformers.js pipeline
|
||||
*/
|
||||
export async function getPipeline(task, forceModel = '') {
|
||||
await migrateCacheToDataDir();
|
||||
|
Reference in New Issue
Block a user