Merge pull request #3181 from SillyTavern/tc-split-generic Add generic text completion API type (100% OAI compatible)

8811010c7396911e6b035a4862d3c963e935dd69

Cohee <18619528+Cohee1207@users.noreply.github.com>

Signed
11 files changed, +117 -12Ignore whitespace
public/index.html+30 -10
@@ -1235,7 +1235,8 @@
1235 <input class="neo-range-slider" type="range" id="temp_textgenerationwebui" name="volume" min="0.0" max="5.0" step="0.01" x-setting-id="temp">1235 <input class="neo-range-slider" type="range" id="temp_textgenerationwebui" name="volume" min="0.0" max="5.0" step="0.01" x-setting-id="temp">
1236 <input class="neo-range-input" type="number" min="0.0" max="5.0" step="0.01" data-for="temp_textgenerationwebui" id="temp_counter_textgenerationwebui">1236 <input class="neo-range-input" type="number" min="0.0" max="5.0" step="0.01" data-for="temp_textgenerationwebui" id="temp_counter_textgenerationwebui">
1237 </div>1237 </div>
1238 <div class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0">1238 <!-- Note: "except" mode = show for all BUT types in data-tg-type -->
1239 <div data-tg-type-mode="except" data-tg-type="generic" class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0">
1239 <small>1240 <small>
1240 <span data-i18n="Top K">Top K</span>1241 <span data-i18n="Top K">Top K</span>
1241 <div class="fa-solid fa-circle-info opacity50p" title="Top K sets a maximum amount of top tokens that can be chosen from.&#13;E.g Top K is 20, this means only the 20 highest ranking tokens will be kept (regardless of their probabilities being diverse or limited).&#13;Set to 0 (or -1, depending on your backend) to disable." data-i18n="[title]Top_K_desc"></div>1242 <div class="fa-solid fa-circle-info opacity50p" title="Top K sets a maximum amount of top tokens that can be chosen from.&#13;E.g Top K is 20, this means only the 20 highest ranking tokens will be kept (regardless of their probabilities being diverse or limited).&#13;Set to 0 (or -1, depending on your backend) to disable." data-i18n="[title]Top_K_desc"></div>
@@ -1251,7 +1252,7 @@
1251 <input class="neo-range-slider" type="range" id="top_p_textgenerationwebui" name="volume" min="0" max="1" step="0.01">1252 <input class="neo-range-slider" type="range" id="top_p_textgenerationwebui" name="volume" min="0" max="1" step="0.01">
1252 <input class="neo-range-input" type="number" min="0" max="1" step="0.01" data-for="top_p_textgenerationwebui" id="top_p_counter_textgenerationwebui">1253 <input class="neo-range-input" type="number" min="0" max="1" step="0.01" data-for="top_p_textgenerationwebui" id="top_p_counter_textgenerationwebui">
1253 </div>1254 </div>
1254 <div class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0">1255 <div data-tg-type-mode="except" data-tg-type="generic" class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0">
1255 <small>1256 <small>
1256 <span data-i18n="Typical P">Typical P</span>1257 <span data-i18n="Typical P">Typical P</span>
1257 <div class="fa-solid fa-circle-info opacity50p" title="Typical P Sampling prioritizes tokens based on their deviation from the average entropy of the set.&#13;It maintains tokens whose cumulative probability is close to a predefined threshold (e.g., 0.5), emphasizing those with average information content.&#13;Set to 1.0 to disable." data-i18n="[title]Typical_P_desc"></div>1258 <div class="fa-solid fa-circle-info opacity50p" title="Typical P Sampling prioritizes tokens based on their deviation from the average entropy of the set.&#13;It maintains tokens whose cumulative probability is close to a predefined threshold (e.g., 0.5), emphasizing those with average information content.&#13;Set to 1.0 to disable." data-i18n="[title]Typical_P_desc"></div>
@@ -1259,7 +1260,7 @@
1259 <input class="neo-range-slider" type="range" id="typical_p_textgenerationwebui" name="volume" min="0" max="1" step="0.01">1260 <input class="neo-range-slider" type="range" id="typical_p_textgenerationwebui" name="volume" min="0" max="1" step="0.01">
1260 <input class="neo-range-input" type="number" min="0" max="1" step="0.01" data-for="typical_p_textgenerationwebui" id="typical_p_counter_textgenerationwebui">1261 <input class="neo-range-input" type="number" min="0" max="1" step="0.01" data-for="typical_p_textgenerationwebui" id="typical_p_counter_textgenerationwebui">
1261 </div>1262 </div>
1262 <div class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0">1263 <div data-tg-type-mode="except" data-tg-type="generic" class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0">
1263 <small>1264 <small>
1264 <span data-i18n="Min P">Min P</span>1265 <span data-i18n="Min P">Min P</span>
1265 <div class="fa-solid fa-circle-info opacity50p" data-i18n="[title]Min_P_desc" title="Min P sets a base minimum probability. This is scaled according to the top token's probability.&#13;E.g If Top token is 80% probability, and Min P is 0.1, only tokens higher than 8% would be considered.&#13;Set to 0 to disable."></div>1266 <div class="fa-solid fa-circle-info opacity50p" data-i18n="[title]Min_P_desc" title="Min P sets a base minimum probability. This is scaled according to the top token's probability.&#13;E.g If Top token is 80% probability, and Min P is 0.1, only tokens higher than 8% would be considered.&#13;Set to 0 to disable."></div>
@@ -1267,7 +1268,7 @@
1267 <input class="neo-range-slider" type="range" id="min_p_textgenerationwebui" name="volume" min="0" max="1" step="0.001">1268 <input class="neo-range-slider" type="range" id="min_p_textgenerationwebui" name="volume" min="0" max="1" step="0.001">
1268 <input class="neo-range-input" type="number" min="0" max="1" step="0.001" data-for="min_p_textgenerationwebui" id="min_p_counter_textgenerationwebui">1269 <input class="neo-range-input" type="number" min="0" max="1" step="0.001" data-for="min_p_textgenerationwebui" id="min_p_counter_textgenerationwebui">
1269 </div>1270 </div>
1270 <div class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0">1271 <div data-tg-type-mode="except" data-tg-type="generic" class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0">
1271 <small>1272 <small>
1272 <span data-i18n="Top A">Top A</span>1273 <span data-i18n="Top A">Top A</span>
1273 <div class="fa-solid fa-circle-info opacity50p" title="Top A sets a threshold for token selection based on the square of the highest token probability.&#13;E.g if the Top-A value is 0.2 and the top token's probability is 50%, tokens with probabilities below 5% (0.2 * 0.5^2) are excluded.&#13;Set to 0 to disable." data-i18n="[title]Top_A_desc"></div>1274 <div class="fa-solid fa-circle-info opacity50p" title="Top A sets a threshold for token selection based on the square of the highest token probability.&#13;E.g if the Top-A value is 0.2 and the top token's probability is 50%, tokens with probabilities below 5% (0.2 * 0.5^2) are excluded.&#13;Set to 0 to disable." data-i18n="[title]Top_A_desc"></div>
@@ -1275,7 +1276,7 @@
1275 <input class="neo-range-slider" type="range" id="top_a_textgenerationwebui" name="volume" min="0" max="1" step="0.01">1276 <input class="neo-range-slider" type="range" id="top_a_textgenerationwebui" name="volume" min="0" max="1" step="0.01">
1276 <input class="neo-range-input" type="number" min="0" max="1" step="0.01" data-for="top_a_textgenerationwebui" id="top_a_counter_textgenerationwebui">1277 <input class="neo-range-input" type="number" min="0" max="1" step="0.01" data-for="top_a_textgenerationwebui" id="top_a_counter_textgenerationwebui">
1277 </div>1278 </div>
1278 <div class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0">1279 <div data-tg-type-mode="except" data-tg-type="generic" class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0">
1279 <small>1280 <small>
1280 <span data-i18n="TFS">TFS</span>1281 <span data-i18n="TFS">TFS</span>
1281 <div class="fa-solid fa-circle-info opacity50p" data-i18n="[title]Tail_Free_Sampling_desc" title="Tail-Free Sampling (TFS) searches for a tail of low-probability tokens in the distribution,&#13;by analyzing the rate of change in token probabilities using derivatives. It retains tokens up to a threshold (e.g., 0.3) based on the normalized second derivative.&#13;The closer to 0, the more discarded tokens. Set to 1.0 to disable."></div>1282 <div class="fa-solid fa-circle-info opacity50p" data-i18n="[title]Tail_Free_Sampling_desc" title="Tail-Free Sampling (TFS) searches for a tail of low-probability tokens in the distribution,&#13;by analyzing the rate of change in token probabilities using derivatives. It retains tokens up to a threshold (e.g., 0.3) based on the normalized second derivative.&#13;The closer to 0, the more discarded tokens. Set to 1.0 to disable."></div>
@@ -1307,7 +1308,7 @@
1307 <input class="neo-range-slider" type="range" id="eta_cutoff_textgenerationwebui" name="volume" min="0" max="20" step="0.01">1308 <input class="neo-range-slider" type="range" id="eta_cutoff_textgenerationwebui" name="volume" min="0" max="20" step="0.01">
1308 <input class="neo-range-input" type="number" min="0" max="20" step="0.01" data-for="eta_cutoff_textgenerationwebui" id="eta_cutoff_counter_textgenerationwebui">1309 <input class="neo-range-input" type="number" min="0" max="20" step="0.01" data-for="eta_cutoff_textgenerationwebui" id="eta_cutoff_counter_textgenerationwebui">
1309 </div>1310 </div>
1310 <div class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0">1311 <div data-tg-type-mode="except" data-tg-type="generic" class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0">
1311 <small data-i18n="rep.pen">Repetition Penalty</small>1312 <small data-i18n="rep.pen">Repetition Penalty</small>
1312 <input class="neo-range-slider" type="range" id="rep_pen_textgenerationwebui" name="volume" min="1" max="3" step="0.01">1313 <input class="neo-range-slider" type="range" id="rep_pen_textgenerationwebui" name="volume" min="1" max="3" step="0.01">
1313 <input class="neo-range-input" type="number" min="1" max="3" step="0.01" data-for="rep_pen_textgenerationwebui" id="rep_pen_counter_textgenerationwebui">1314 <input class="neo-range-input" type="number" min="1" max="3" step="0.01" data-for="rep_pen_textgenerationwebui" id="rep_pen_counter_textgenerationwebui">
@@ -1569,7 +1570,7 @@
1569 <small data-i18n="Ignore EOS Token">Ignore EOS Token</small>1570 <small data-i18n="Ignore EOS Token">Ignore EOS Token</small>
1570 <div class="fa-solid fa-circle-info opacity50p " data-i18n="[title]Ignore the EOS Token even if it generates." title="Ignore the EOS Token even if it generates."></div>1571 <div class="fa-solid fa-circle-info opacity50p " data-i18n="[title]Ignore the EOS Token even if it generates." title="Ignore the EOS Token even if it generates."></div>
1571 </label>1572 </label>
1572 <label class="checkbox_label flexGrow flexShrink" for="skip_special_tokens_textgenerationwebui">1573 <label data-tg-type-mode="except" data-tg-type="generic" class="checkbox_label flexGrow flexShrink" for="skip_special_tokens_textgenerationwebui">
1573 <input type="checkbox" id="skip_special_tokens_textgenerationwebui" />1574 <input type="checkbox" id="skip_special_tokens_textgenerationwebui" />
1574 <small data-i18n="Skip Special Tokens">Skip Special Tokens</small>1575 <small data-i18n="Skip Special Tokens">Skip Special Tokens</small>
1575 </label>1576 </label>
@@ -1594,14 +1595,14 @@
1594 </label>1595 </label>
1595 </div>1596 </div>
1596 </div>1597 </div>
1597 <div data-tg-type="mancer, ooba, koboldcpp, vllm, aphrodite, llamacpp, ollama, infermaticai, huggingface" class="flex-container flexFlowColumn alignitemscenter flexBasis48p flexGrow flexShrink gap0">1598 <div data-tg-type="mancer, ooba, koboldcpp, vllm, aphrodite, llamacpp, ollama, infermaticai, huggingface, generic" class="flex-container flexFlowColumn alignitemscenter flexBasis48p flexGrow flexShrink gap0">
1598 <label>1599 <label>
1599 <small data-i18n="Seed">Seed</small>1600 <small data-i18n="Seed">Seed</small>
1600 <div class="fa-solid fa-circle-info opacity50p " data-i18n="[title]Seed_desc" title="A random seed to use for deterministic and reproducable outputs. Set to -1 to use a random seed."></div>1601 <div class="fa-solid fa-circle-info opacity50p " data-i18n="[title]Seed_desc" title="A random seed to use for deterministic and reproducable outputs. Set to -1 to use a random seed."></div>
1601 </label>1602 </label>
1602 <input type="number" id="seed_textgenerationwebui" class="text_pole textAlignCenter" min="-1" value="-1" />1603 <input type="number" id="seed_textgenerationwebui" class="text_pole textAlignCenter" min="-1" value="-1" />
1603 </div>1604 </div>
1604 <div id="banned_tokens_block_ooba" class="wide100p">1605 <div data-tg-type-mode="except" data-tg-type="generic" id="banned_tokens_block_ooba" class="wide100p">
1605 <hr class="width100p">1606 <hr class="width100p">
1606 <h4 class="range-block-title justifyCenter">1607 <h4 class="range-block-title justifyCenter">
1607 <span data-i18n="Banned Tokens">Banned Tokens/Strings</span>1608 <span data-i18n="Banned Tokens">Banned Tokens/Strings</span>
@@ -2187,10 +2188,10 @@
2187 <div>2188 <div>
2188 <h4 data-i18n="API Type">API Type</h4>2189 <h4 data-i18n="API Type">API Type</h4>
2189 <select id="textgen_type">2190 <select id="textgen_type">
2190 <option value="ooba" data-i18n="Default (completions compatible)">Default [OpenAI /completions compatible: oobabooga, LM Studio, etc.]</option>
2191 <option value="aphrodite">Aphrodite</option>2191 <option value="aphrodite">Aphrodite</option>
2192 <option value="dreamgen">DreamGen</option>2192 <option value="dreamgen">DreamGen</option>
2193 <option value="featherless">Featherless</option>2193 <option value="featherless">Featherless</option>
2194 <option value="generic" data-i18n="Generic (OpenAI-compatible) [LM Studio, LiteLLM, etc.]">Generic (OpenAI-compatible) [LM Studio, LiteLLM, etc.]</option>
2194 <option value="huggingface">HuggingFace (Inference Endpoint)</option>2195 <option value="huggingface">HuggingFace (Inference Endpoint)</option>
2195 <option value="infermaticai">InfermaticAI</option>2196 <option value="infermaticai">InfermaticAI</option>
2196 <option value="koboldcpp">KoboldCpp</option>2197 <option value="koboldcpp">KoboldCpp</option>
@@ -2199,6 +2200,7 @@
2199 <option value="ollama">Ollama</option>2200 <option value="ollama">Ollama</option>
2200 <option value="openrouter">OpenRouter</option>2201 <option value="openrouter">OpenRouter</option>
2201 <option value="tabby">TabbyAPI</option>2202 <option value="tabby">TabbyAPI</option>
2203 <option value="ooba">Text Generation WebUI (oobabooga)</option>
2202 <option value="togetherai">TogetherAI</option>2204 <option value="togetherai">TogetherAI</option>
2203 <option value="vllm">vLLM</option>2205 <option value="vllm">vLLM</option>
2204 </select>2206 </select>
@@ -2321,6 +2323,24 @@
2321 </select>2323 </select>
2322 </div>2324 </div>
2323 </div>2325 </div>
2326 <div data-tg-type="generic" class="flex-container flexFlowColumn">
2327 <h4 data-i18n="API key (optional)">API key (optional)</h4>
2328 <div class="flex-container">
2329 <input id="api_key_generic" name="api_key_generic" class="text_pole flex1 wide100p" type="text" autocomplete="off">
2330 <div title="Clear your API key" data-i18n="[title]Clear your API key" class="menu_button fa-solid fa-circle-xmark clear-api-key" data-key="api_key_generic">
2331 </div>
2332 </div>
2333 <div data-for="api_key_generic" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you reload the page.">
2334 For privacy reasons, your API key will be hidden after you reload the page.
2335 </div>
2336 <div class="flex1">
2337 <h4 data-i18n="Server url">Server URL</h4>
2338 <small data-i18n="Example: 127.0.0.1:5000">Example: http://127.0.0.1:5000</small>
2339 <input id="generic_api_url_text" name="generic_api_url" class="text_pole wide100p" value="" autocomplete="off" data-server-history="generic">
2340 </div>
2341 <datalist id="generic_model_fill"></datalist>
2342 <input id="generic_model_textgenerationwebui" list="generic_model_fill" class="text_pole wide100p" placeholder="Model ID (optional)" data-i18n="[placeholder]Model ID (optional)" type="text">
2343 </div>
2324 <div data-tg-type="ooba" class="flex-container flexFlowColumn">2344 <div data-tg-type="ooba" class="flex-container flexFlowColumn">
2325 <div class="flex-container flexFlowColumn">2345 <div class="flex-container flexFlowColumn">
2326 <a href="https://github.com/oobabooga/text-generation-webui" target="_blank">2346 <a href="https://github.com/oobabooga/text-generation-webui" target="_blank">
public/script.js+5 -1
@@ -234,7 +234,7 @@ import {
234import { getBackgrounds, initBackgrounds, loadBackgroundSettings, background_settings } from './scripts/backgrounds.js';234import { getBackgrounds, initBackgrounds, loadBackgroundSettings, background_settings } from './scripts/backgrounds.js';
235import { hideLoader, showLoader } from './scripts/loader.js';235import { hideLoader, showLoader } from './scripts/loader.js';
236import { BulkEditOverlay, CharacterContextMenu } from './scripts/BulkEditOverlay.js';236import { BulkEditOverlay, CharacterContextMenu } from './scripts/BulkEditOverlay.js';
237import { loadFeatherlessModels, loadMancerModels, loadOllamaModels, loadTogetherAIModels, loadInfermaticAIModels, loadOpenRouterModels, loadVllmModels, loadAphroditeModels, loadDreamGenModels, initTextGenModels, loadTabbyModels } from './scripts/textgen-models.js';237import { loadFeatherlessModels, loadMancerModels, loadOllamaModels, loadTogetherAIModels, loadInfermaticAIModels, loadOpenRouterModels, loadVllmModels, loadAphroditeModels, loadDreamGenModels, initTextGenModels, loadTabbyModels, loadGenericModels } from './scripts/textgen-models.js';
238import { appendFileContent, hasPendingFileAttachment, populateFileAttachment, decodeStyleTags, encodeStyleTags, isExternalMediaAllowed, getCurrentEntityId, preserveNeutralChat, restoreNeutralChat } from './scripts/chats.js';238import { appendFileContent, hasPendingFileAttachment, populateFileAttachment, decodeStyleTags, encodeStyleTags, isExternalMediaAllowed, getCurrentEntityId, preserveNeutralChat, restoreNeutralChat } from './scripts/chats.js';
239import { getPresetManager, initPresetManager } from './scripts/preset-manager.js';239import { getPresetManager, initPresetManager } from './scripts/preset-manager.js';
240import { evaluateMacros, getLastMessageId, initMacros } from './scripts/macros.js';240import { evaluateMacros, getLastMessageId, initMacros } from './scripts/macros.js';
@@ -1221,6 +1221,9 @@ async function getStatusTextgen() {
1221 } else if (textgen_settings.type === textgen_types.TABBY) {1221 } else if (textgen_settings.type === textgen_types.TABBY) {
1222 loadTabbyModels(data?.data);1222 loadTabbyModels(data?.data);
1223 setOnlineStatus(textgen_settings.tabby_model || data?.result);1223 setOnlineStatus(textgen_settings.tabby_model || data?.result);
1224 } else if (textgen_settings.type === textgen_types.GENERIC) {
1225 loadGenericModels(data?.data);
1226 setOnlineStatus(textgen_settings.generic_model || 'Connected');
1224 } else {1227 } else {
1225 setOnlineStatus(data?.result);1228 setOnlineStatus(data?.result);
1226 }1229 }
@@ -10042,6 +10045,7 @@ jQuery(async function () {
10042 { id: 'api_key_llamacpp', secret: SECRET_KEYS.LLAMACPP },10045 { id: 'api_key_llamacpp', secret: SECRET_KEYS.LLAMACPP },
10043 { id: 'api_key_featherless', secret: SECRET_KEYS.FEATHERLESS },10046 { id: 'api_key_featherless', secret: SECRET_KEYS.FEATHERLESS },
10044 { id: 'api_key_huggingface', secret: SECRET_KEYS.HUGGINGFACE },10047 { id: 'api_key_huggingface', secret: SECRET_KEYS.HUGGINGFACE },
10048 { id: 'api_key_generic', secret: SECRET_KEYS.GENERIC },
10045 ];10049 ];
1004610050
10047 for (const key of keys) {10051 for (const key of keys) {
public/scripts/preset-manager.js+1 -0
@@ -585,6 +585,7 @@ class PresetManager {
585 'openrouter_allow_fallbacks',585 'openrouter_allow_fallbacks',
586 'tabby_model',586 'tabby_model',
587 'derived',587 'derived',
588 'generic_model',
588 ];589 ];
589 const settings = Object.assign({}, getSettingsByApiId(this.apiId));590 const settings = Object.assign({}, getSettingsByApiId(this.apiId));
590591
public/scripts/secrets.js+2 -0
@@ -38,6 +38,7 @@ export const SECRET_KEYS = {
38 NANOGPT: 'api_key_nanogpt',38 NANOGPT: 'api_key_nanogpt',
39 TAVILY: 'api_key_tavily',39 TAVILY: 'api_key_tavily',
40 BFL: 'api_key_bfl',40 BFL: 'api_key_bfl',
41 GENERIC: 'api_key_generic',
41};42};
4243
43const INPUT_MAP = {44const INPUT_MAP = {
@@ -71,6 +72,7 @@ const INPUT_MAP = {
71 [SECRET_KEYS.HUGGINGFACE]: '#api_key_huggingface',72 [SECRET_KEYS.HUGGINGFACE]: '#api_key_huggingface',
72 [SECRET_KEYS.BLOCKENTROPY]: '#api_key_blockentropy',73 [SECRET_KEYS.BLOCKENTROPY]: '#api_key_blockentropy',
73 [SECRET_KEYS.NANOGPT]: '#api_key_nanogpt',74 [SECRET_KEYS.NANOGPT]: '#api_key_nanogpt',
75 [SECRET_KEYS.GENERIC]: '#api_key_generic',
74};76};
7577
76async function clearSecret() {78async function clearSecret() {
public/scripts/slash-commands.js+1 -0
@@ -3743,6 +3743,7 @@ function setBackgroundCallback(_, bg) {
3743function getModelOptions(quiet) {3743function getModelOptions(quiet) {
3744 const nullResult = { control: null, options: null };3744 const nullResult = { control: null, options: null };
3745 const modelSelectMap = [3745 const modelSelectMap = [
3746 { id: 'generic_model_textgenerationwebui', api: 'textgenerationwebui', type: textgen_types.GENERIC },
3746 { id: 'custom_model_textgenerationwebui', api: 'textgenerationwebui', type: textgen_types.OOBA },3747 { id: 'custom_model_textgenerationwebui', api: 'textgenerationwebui', type: textgen_types.OOBA },
3747 { id: 'model_togetherai_select', api: 'textgenerationwebui', type: textgen_types.TOGETHERAI },3748 { id: 'model_togetherai_select', api: 'textgenerationwebui', type: textgen_types.TOGETHERAI },
3748 { id: 'openrouter_model', api: 'textgenerationwebui', type: textgen_types.OPENROUTER },3749 { id: 'openrouter_model', api: 'textgenerationwebui', type: textgen_types.OPENROUTER },
public/scripts/textgen-models.js+18 -0
@@ -160,6 +160,24 @@ export async function loadInfermaticAIModels(data) {
160 }160 }
161}161}
162162
163export function loadGenericModels(data) {
164 if (!Array.isArray(data)) {
165 console.error('Invalid Generic models data', data);
166 return;
167 }
168
169 data.sort((a, b) => a.id.localeCompare(b.id));
170 const dataList = $('#generic_model_fill');
171 dataList.empty();
172
173 for (const model of data) {
174 const option = document.createElement('option');
175 option.value = model.id;
176 option.text = model.id;
177 dataList.append(option);
178 }
179}
180
163export async function loadDreamGenModels(data) {181export async function loadDreamGenModels(data) {
164 if (!Array.isArray(data)) {182 if (!Array.isArray(data)) {
165 console.error('Invalid DreamGen models data', data);183 console.error('Invalid DreamGen models data', data);
public/scripts/textgen-settings.js+17 -0
@@ -33,9 +33,11 @@ export const textgen_types = {
33 OPENROUTER: 'openrouter',33 OPENROUTER: 'openrouter',
34 FEATHERLESS: 'featherless',34 FEATHERLESS: 'featherless',
35 HUGGINGFACE: 'huggingface',35 HUGGINGFACE: 'huggingface',
36 GENERIC: 'generic',
36};37};
3738
38const {39const {
40 GENERIC,
39 MANCER,41 MANCER,
40 VLLM,42 VLLM,
41 APHRODITE,43 APHRODITE,
@@ -120,6 +122,7 @@ export const SERVER_INPUTS = {
120 [textgen_types.LLAMACPP]: '#llamacpp_api_url_text',122 [textgen_types.LLAMACPP]: '#llamacpp_api_url_text',
121 [textgen_types.OLLAMA]: '#ollama_api_url_text',123 [textgen_types.OLLAMA]: '#ollama_api_url_text',
122 [textgen_types.HUGGINGFACE]: '#huggingface_api_url_text',124 [textgen_types.HUGGINGFACE]: '#huggingface_api_url_text',
125 [textgen_types.GENERIC]: '#generic_api_url_text',
123};126};
124127
125const KOBOLDCPP_ORDER = [6, 0, 1, 3, 4, 2, 5];128const KOBOLDCPP_ORDER = [6, 0, 1, 3, 4, 2, 5];
@@ -205,6 +208,7 @@ const settings = {
205 xtc_probability: 0,208 xtc_probability: 0,
206 nsigma: 0.0,209 nsigma: 0.0,
207 featherless_model: '',210 featherless_model: '',
211 generic_model: '',
208};212};
209213
210export {214export {
@@ -282,6 +286,7 @@ export const setting_names = [
282 'xtc_threshold',286 'xtc_threshold',
283 'xtc_probability',287 'xtc_probability',
284 'nsigma',288 'nsigma',
289 'generic_model',
285];290];
286291
287const DYNATEMP_BLOCK = document.getElementById('dynatemp_block_ooba');292const DYNATEMP_BLOCK = document.getElementById('dynatemp_block_ooba');
@@ -833,7 +838,14 @@ jQuery(function () {
833838
834function showTypeSpecificControls(type) {839function showTypeSpecificControls(type) {
835 $('[data-tg-type]').each(function () {840 $('[data-tg-type]').each(function () {
841 const mode = String($(this).attr('data-tg-type-mode') ?? '').toLowerCase().trim();
836 const tgTypes = $(this).attr('data-tg-type').split(',').map(x => x.trim());842 const tgTypes = $(this).attr('data-tg-type').split(',').map(x => x.trim());
843
844 if (mode === 'except') {
845 $(this)[tgTypes.includes(type) ? 'hide' : 'show']();
846 return;
847 }
848
837 for (const tgType of tgTypes) {849 for (const tgType of tgTypes) {
838 if (tgType === type || tgType == 'all') {850 if (tgType === type || tgType == 'all') {
839 $(this).show();851 $(this).show();
@@ -1100,6 +1112,11 @@ export function getTextGenModel() {
1100 return settings.custom_model;1112 return settings.custom_model;
1101 }1113 }
1102 break;1114 break;
1115 case GENERIC:
1116 if (settings.generic_model) {
1117 return settings.generic_model;
1118 }
1119 break;
1103 case MANCER:1120 case MANCER:
1104 return settings.mancer_model;1121 return settings.mancer_model;
1105 case TOGETHERAI:1122 case TOGETHERAI:
src/additional-headers.js+14 -0
@@ -172,6 +172,19 @@ function getHuggingFaceHeaders(directories) {
172 }) : {};172 }) : {};
173}173}
174174
175/**
176 * Gets the headers for the Generic text completion API.
177 * @param {import('./users.js').UserDirectoryList} directories
178 * @returns {object} Headers for the request
179 */
180function getGenericHeaders(directories) {
181 const apiKey = readSecret(directories, SECRET_KEYS.GENERIC);
182
183 return apiKey ? ({
184 'Authorization': `Bearer ${apiKey}`,
185 }) : {};
186}
187
175export function getOverrideHeaders(urlHost) {188export function getOverrideHeaders(urlHost) {
176 const requestOverrides = getConfigValue('requestOverrides', []);189 const requestOverrides = getConfigValue('requestOverrides', []);
177 const overrideHeaders = requestOverrides?.find((e) => e.hosts?.includes(urlHost))?.headers;190 const overrideHeaders = requestOverrides?.find((e) => e.hosts?.includes(urlHost))?.headers;
@@ -214,6 +227,7 @@ export function setAdditionalHeadersByType(requestHeaders, type, server, directo
214 [TEXTGEN_TYPES.LLAMACPP]: getLlamaCppHeaders,227 [TEXTGEN_TYPES.LLAMACPP]: getLlamaCppHeaders,
215 [TEXTGEN_TYPES.FEATHERLESS]: getFeatherlessHeaders,228 [TEXTGEN_TYPES.FEATHERLESS]: getFeatherlessHeaders,
216 [TEXTGEN_TYPES.HUGGINGFACE]: getHuggingFaceHeaders,229 [TEXTGEN_TYPES.HUGGINGFACE]: getHuggingFaceHeaders,
230 [TEXTGEN_TYPES.GENERIC]: getGenericHeaders,
217 };231 };
218232
219 const getHeaders = headerGetters[type];233 const getHeaders = headerGetters[type];
src/constants.js+19 -0
@@ -225,6 +225,7 @@ export const TEXTGEN_TYPES = {
225 OPENROUTER: 'openrouter',225 OPENROUTER: 'openrouter',
226 FEATHERLESS: 'featherless',226 FEATHERLESS: 'featherless',
227 HUGGINGFACE: 'huggingface',227 HUGGINGFACE: 'huggingface',
228 GENERIC: 'generic',
228};229};
229230
230export const INFERMATICAI_KEYS = [231export const INFERMATICAI_KEYS = [
@@ -346,6 +347,24 @@ export const OLLAMA_KEYS = [
346 'min_p',347 'min_p',
347];348];
348349
350// https://platform.openai.com/docs/api-reference/completions
351export const OPENAI_KEYS = [
352 'model',
353 'prompt',
354 'stream',
355 'temperature',
356 'top_p',
357 'frequency_penalty',
358 'presence_penalty',
359 'stop',
360 'seed',
361 'logit_bias',
362 'logprobs',
363 'max_tokens',
364 'n',
365 'best_of',
366];
367
349export const AVATAR_WIDTH = 512;368export const AVATAR_WIDTH = 512;
350export const AVATAR_HEIGHT = 768;369export const AVATAR_HEIGHT = 768;
351370
src/endpoints/backends/text-completions.js+9 -1
@@ -13,6 +13,7 @@ import {
13 VLLM_KEYS,13 VLLM_KEYS,
14 DREAMGEN_KEYS,14 DREAMGEN_KEYS,
15 FEATHERLESS_KEYS,15 FEATHERLESS_KEYS,
16 OPENAI_KEYS,
16} from '../../constants.js';17} from '../../constants.js';
17import { forwardFetchResponse, trimV1, getConfigValue } from '../../util.js';18import { forwardFetchResponse, trimV1, getConfigValue } from '../../util.js';
18import { setAdditionalHeaders } from '../../additional-headers.js';19import { setAdditionalHeaders } from '../../additional-headers.js';
@@ -113,8 +114,8 @@ router.post('/status', jsonParser, async function (request, response) {
113 let url = baseUrl;114 let url = baseUrl;
114 let result = '';115 let result = '';
115116
116
117 switch (apiType) {117 switch (apiType) {
118 case TEXTGEN_TYPES.GENERIC:
118 case TEXTGEN_TYPES.OOBA:119 case TEXTGEN_TYPES.OOBA:
119 case TEXTGEN_TYPES.VLLM:120 case TEXTGEN_TYPES.VLLM:
120 case TEXTGEN_TYPES.APHRODITE:121 case TEXTGEN_TYPES.APHRODITE:
@@ -287,6 +288,7 @@ router.post('/generate', jsonParser, async function (request, response) {
287 let url = trimV1(baseUrl);288 let url = trimV1(baseUrl);
288289
289 switch (request.body.api_type) {290 switch (request.body.api_type) {
291 case TEXTGEN_TYPES.GENERIC:
290 case TEXTGEN_TYPES.VLLM:292 case TEXTGEN_TYPES.VLLM:
291 case TEXTGEN_TYPES.FEATHERLESS:293 case TEXTGEN_TYPES.FEATHERLESS:
292 case TEXTGEN_TYPES.APHRODITE:294 case TEXTGEN_TYPES.APHRODITE:
@@ -347,6 +349,12 @@ router.post('/generate', jsonParser, async function (request, response) {
347 args.body = JSON.stringify(request.body);349 args.body = JSON.stringify(request.body);
348 }350 }
349351
352 if (request.body.api_type === TEXTGEN_TYPES.GENERIC) {
353 request.body = _.pickBy(request.body, (_, key) => OPENAI_KEYS.includes(key));
354 if (Array.isArray(request.body.stop)) { request.body.stop = request.body.stop.slice(0, 4); }
355 args.body = JSON.stringify(request.body);
356 }
357
350 if (request.body.api_type === TEXTGEN_TYPES.OPENROUTER) {358 if (request.body.api_type === TEXTGEN_TYPES.OPENROUTER) {
351 if (Array.isArray(request.body.provider) && request.body.provider.length > 0) {359 if (Array.isArray(request.body.provider) && request.body.provider.length > 0) {
352 request.body.provider = {360 request.body.provider = {
src/endpoints/secrets.js+1 -0
@@ -50,6 +50,7 @@ export const SECRET_KEYS = {
50 TAVILY: 'api_key_tavily',50 TAVILY: 'api_key_tavily',
51 NANOGPT: 'api_key_nanogpt',51 NANOGPT: 'api_key_nanogpt',
52 BFL: 'api_key_bfl',52 BFL: 'api_key_bfl',
53 GENERIC: 'api_key_generic',
53};54};
5455
55// These are the keys that are safe to expose, even if allowKeysExposure is false56// These are the keys that are safe to expose, even if allowKeysExposure is false