mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-02-22 15:07:42 +01:00
Merge pull request #2434 from DarokCx/release
Added featherless to the list of providers
This commit is contained in:
commit
1ab674ba28
@ -2029,6 +2029,7 @@
|
||||
<option value="ooba" data-i18n="Default (completions compatible)">Default [OpenAI /completions compatible: oobabooga, LM Studio, etc.]</option>
|
||||
<option value="aphrodite">Aphrodite</option>
|
||||
<option value="dreamgen">DreamGen</option>
|
||||
<option value="featherless">Featherless</option>
|
||||
<option value="huggingface">HuggingFace (Inference Endpoint)</option>
|
||||
<option value="infermaticai">InfermaticAI</option>
|
||||
<option value="koboldcpp">KoboldCpp</option>
|
||||
@ -2183,6 +2184,27 @@
|
||||
</div>
|
||||
<input id="custom_model_textgenerationwebui" class="text_pole wide100p" maxlength="500" placeholder="Custom model (optional)" data-i18n="[placeholder]Custom model (optional)" type="text">
|
||||
</div>
|
||||
<div data-tg-type="featherless" class="flex-container flexFlowColumn">
|
||||
<div class="flex-container flexFlowColumn">
|
||||
<a href="https://featherless.ai/models/" target="_blank" rel="noopener noreferrer">
|
||||
featherless.ai
|
||||
</a>
|
||||
</div>
|
||||
<h4 data-i18n="API key (optional)">API key</h4>
|
||||
<div class="flex-container">
|
||||
<input id="api_key_featherless" name="api_key_featherless" class="text_pole flex1 wide100p" maxlength="500" size="35" type="text" autocomplete="off">
|
||||
<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_featherless">
|
||||
</div>
|
||||
</div>
|
||||
<div data-for="api_key_featherless" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you reload the page.">
|
||||
For privacy reasons, your API key will be hidden after you reload the page.
|
||||
</div>
|
||||
<select id="featherless_model">
|
||||
<option data-i18n="-- Connect to the API --">
|
||||
-- Connect to the API --
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<div data-tg-type="vllm">
|
||||
<div class="flex-container flexFlowColumn">
|
||||
<a href="https://github.com/vllm-project/vllm" target="_blank" data-i18n="vllm-project/vllm">
|
||||
|
@ -22,7 +22,7 @@ import {
|
||||
parseTabbyLogprobs,
|
||||
} from './scripts/textgen-settings.js';
|
||||
|
||||
const { MANCER, TOGETHERAI, OOBA, VLLM, APHRODITE, TABBY, OLLAMA, INFERMATICAI, DREAMGEN, OPENROUTER } = textgen_types;
|
||||
const { MANCER, TOGETHERAI, OOBA, VLLM, APHRODITE, TABBY, OLLAMA, INFERMATICAI, DREAMGEN, OPENROUTER, FEATHERLESS } = textgen_types;
|
||||
|
||||
import {
|
||||
world_info,
|
||||
@ -223,7 +223,7 @@ import {
|
||||
import { getBackgrounds, initBackgrounds, loadBackgroundSettings, background_settings } from './scripts/backgrounds.js';
|
||||
import { hideLoader, showLoader } from './scripts/loader.js';
|
||||
import { BulkEditOverlay, CharacterContextMenu } from './scripts/BulkEditOverlay.js';
|
||||
import { loadMancerModels, loadOllamaModels, loadTogetherAIModels, loadInfermaticAIModels, loadOpenRouterModels, loadVllmModels, loadAphroditeModels, loadDreamGenModels } from './scripts/textgen-models.js';
|
||||
import { loadFeatherlessModels, loadMancerModels, loadOllamaModels, loadTogetherAIModels, loadInfermaticAIModels, loadOpenRouterModels, loadVllmModels, loadAphroditeModels, loadDreamGenModels } from './scripts/textgen-models.js';
|
||||
import { appendFileContent, hasPendingFileAttachment, populateFileAttachment, decodeStyleTags, encodeStyleTags, isExternalMediaAllowed, getCurrentEntityId } from './scripts/chats.js';
|
||||
import { initPresetManager } from './scripts/preset-manager.js';
|
||||
import { MacrosParser, evaluateMacros } from './scripts/macros.js';
|
||||
@ -1160,6 +1160,9 @@ async function getStatusTextgen() {
|
||||
} else if (textgen_settings.type === APHRODITE) {
|
||||
loadAphroditeModels(data?.data);
|
||||
setOnlineStatus(textgen_settings.aphrodite_model);
|
||||
} else if (textgen_settings.type === FEATHERLESS) {
|
||||
loadFeatherlessModels(data?.data);
|
||||
setOnlineStatus(textgen_settings.featherless_model);
|
||||
} else {
|
||||
setOnlineStatus(data?.result);
|
||||
}
|
||||
@ -9476,6 +9479,7 @@ jQuery(async function () {
|
||||
{ id: 'api_key_openrouter-tg', secret: SECRET_KEYS.OPENROUTER },
|
||||
{ id: 'api_key_koboldcpp', secret: SECRET_KEYS.KOBOLDCPP },
|
||||
{ id: 'api_key_llamacpp', secret: SECRET_KEYS.LLAMACPP },
|
||||
{ id: 'api_key_featherless', secret: SECRET_KEYS.FEATHERLESS },
|
||||
{ id: 'api_key_huggingface', secret: SECRET_KEYS.HUGGINGFACE },
|
||||
];
|
||||
|
||||
|
@ -360,6 +360,7 @@ function RA_autoconnect(PrevApi) {
|
||||
|| (textgen_settings.type === textgen_types.INFERMATICAI && secret_state[SECRET_KEYS.INFERMATICAI])
|
||||
|| (textgen_settings.type === textgen_types.DREAMGEN && secret_state[SECRET_KEYS.DREAMGEN])
|
||||
|| (textgen_settings.type === textgen_types.OPENROUTER && secret_state[SECRET_KEYS.OPENROUTER])
|
||||
|| (textgen_settings.type === textgen_types.FEATHERLESS && secret_state[SECRET_KEYS.FEATHERLESS])
|
||||
) {
|
||||
$('#api_button_textgenerationwebui').trigger('click');
|
||||
}
|
||||
|
@ -329,6 +329,7 @@ class PresetManager {
|
||||
'infermaticai_model',
|
||||
'dreamgen_model',
|
||||
'openrouter_model',
|
||||
'featherless_model',
|
||||
'max_tokens_second',
|
||||
'openrouter_providers',
|
||||
];
|
||||
|
@ -28,6 +28,7 @@ export const SECRET_KEYS = {
|
||||
PERPLEXITY: 'api_key_perplexity',
|
||||
GROQ: 'api_key_groq',
|
||||
AZURE_TTS: 'api_key_azure_tts',
|
||||
FEATHERLESS: 'api_key_featherless',
|
||||
ZEROONEAI: 'api_key_01ai',
|
||||
HUGGINGFACE: 'api_key_huggingface',
|
||||
};
|
||||
@ -58,6 +59,7 @@ const INPUT_MAP = {
|
||||
[SECRET_KEYS.COHERE]: '#api_key_cohere',
|
||||
[SECRET_KEYS.PERPLEXITY]: '#api_key_perplexity',
|
||||
[SECRET_KEYS.GROQ]: '#api_key_groq',
|
||||
[SECRET_KEYS.FEATHERLESS]: '#api_key_featherless',
|
||||
[SECRET_KEYS.ZEROONEAI]: '#api_key_01ai',
|
||||
[SECRET_KEYS.HUGGINGFACE]: '#api_key_huggingface',
|
||||
};
|
||||
|
@ -9,6 +9,7 @@ let infermaticAIModels = [];
|
||||
let dreamGenModels = [];
|
||||
let vllmModels = [];
|
||||
let aphroditeModels = [];
|
||||
let featherlessModels = [];
|
||||
export let openRouterModels = [];
|
||||
|
||||
/**
|
||||
@ -233,6 +234,35 @@ export async function loadAphroditeModels(data) {
|
||||
}
|
||||
}
|
||||
|
||||
export async function loadFeatherlessModels(data) {
|
||||
if (!Array.isArray(data)) {
|
||||
console.error('Invalid Featherless models data', data);
|
||||
return;
|
||||
}
|
||||
|
||||
featherlessModels = data;
|
||||
|
||||
if (!data.find(x => x.id === textgen_settings.featherless_model)) {
|
||||
textgen_settings.featherless_model = data[0]?.id || '';
|
||||
}
|
||||
|
||||
$('#featherless_model').empty();
|
||||
for (const model of data) {
|
||||
const option = document.createElement('option');
|
||||
option.value = model.id;
|
||||
option.text = model.id;
|
||||
option.selected = model.id === textgen_settings.featherless_model;
|
||||
$('#featherless_model').append(option);
|
||||
}
|
||||
}
|
||||
|
||||
function onFeatherlessModelSelect() {
|
||||
const modelId = String($('#featherless_model').val());
|
||||
textgen_settings.featherless_model = modelId;
|
||||
$('#api_button_textgenerationwebui').trigger('click');
|
||||
}
|
||||
|
||||
|
||||
function onMancerModelSelect() {
|
||||
const modelId = String($('#mancer_model').val());
|
||||
textgen_settings.mancer_model = modelId;
|
||||
@ -507,6 +537,7 @@ jQuery(function () {
|
||||
$('#ollama_download_model').on('click', downloadOllamaModel);
|
||||
$('#vllm_model').on('change', onVllmModelSelect);
|
||||
$('#aphrodite_model').on('change', onAphroditeModelSelect);
|
||||
$('#featherless_model').on('change', onFeatherlessModelSelect);
|
||||
|
||||
const providersSelect = $('.openrouter_providers');
|
||||
for (const provider of OPENROUTER_PROVIDERS) {
|
||||
@ -572,6 +603,12 @@ jQuery(function () {
|
||||
width: '100%',
|
||||
templateResult: getAphroditeModelTemplate,
|
||||
});
|
||||
$('#featherless_model').select2({
|
||||
placeholder: 'Select a model',
|
||||
searchInputPlaceholder: 'Search models...',
|
||||
searchInputCssClass: 'text_pole',
|
||||
width: '100%',
|
||||
});
|
||||
providersSelect.select2({
|
||||
sorter: data => data.sort((a, b) => a.text.localeCompare(b.text)),
|
||||
placeholder: 'Select providers. No selection = all providers.',
|
||||
|
@ -38,6 +38,7 @@ export const textgen_types = {
|
||||
INFERMATICAI: 'infermaticai',
|
||||
DREAMGEN: 'dreamgen',
|
||||
OPENROUTER: 'openrouter',
|
||||
FEATHERLESS: 'featherless',
|
||||
HUGGINGFACE: 'huggingface',
|
||||
};
|
||||
|
||||
@ -55,6 +56,7 @@ const {
|
||||
OPENROUTER,
|
||||
KOBOLDCPP,
|
||||
HUGGINGFACE,
|
||||
FEATHERLESS,
|
||||
} = textgen_types;
|
||||
|
||||
const LLAMACPP_DEFAULT_ORDER = [
|
||||
@ -90,6 +92,7 @@ let TOGETHERAI_SERVER = 'https://api.together.xyz';
|
||||
let INFERMATICAI_SERVER = 'https://api.totalgpt.ai';
|
||||
let DREAMGEN_SERVER = 'https://dreamgen.com';
|
||||
let OPENROUTER_SERVER = 'https://openrouter.ai/api';
|
||||
let FEATHERLESS_SERVER = 'https://api.featherless.ai/v1';
|
||||
|
||||
const SERVER_INPUTS = {
|
||||
[textgen_types.OOBA]: '#textgenerationwebui_api_url_text',
|
||||
@ -281,6 +284,8 @@ export function validateTextGenUrl() {
|
||||
|
||||
export function getTextGenServer() {
|
||||
switch (settings.type) {
|
||||
case FEATHERLESS:
|
||||
return FEATHERLESS_SERVER;
|
||||
case MANCER:
|
||||
return MANCER_SERVER;
|
||||
case TOGETHERAI:
|
||||
@ -1025,6 +1030,8 @@ export function getTextGenModel() {
|
||||
throw new Error('No Ollama model selected');
|
||||
}
|
||||
return settings.ollama_model;
|
||||
case FEATHERLESS:
|
||||
return settings.featherless_model;
|
||||
case HUGGINGFACE:
|
||||
return 'tgi';
|
||||
default:
|
||||
|
@ -147,6 +147,19 @@ function getKoboldCppHeaders(directories) {
|
||||
}) : {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the headers for the Featherless API.
|
||||
* @param {import('./users').UserDirectoryList} directories
|
||||
* @returns {object} Headers for the request
|
||||
*/
|
||||
function getFeatherlessHeaders(directories) {
|
||||
const apiKey = readSecret(directories, SECRET_KEYS.FEATHERLESS);
|
||||
|
||||
return apiKey ? ({
|
||||
'Authorization': `Bearer ${apiKey}`,
|
||||
}) : {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the headers for the HuggingFace API.
|
||||
* @param {import('./users').UserDirectoryList} directories
|
||||
@ -200,6 +213,7 @@ function setAdditionalHeadersByType(requestHeaders, type, server, directories) {
|
||||
[TEXTGEN_TYPES.OPENROUTER]: getOpenRouterHeaders,
|
||||
[TEXTGEN_TYPES.KOBOLDCPP]: getKoboldCppHeaders,
|
||||
[TEXTGEN_TYPES.LLAMACPP]: getLlamaCppHeaders,
|
||||
[TEXTGEN_TYPES.FEATHERLESS]: getFeatherlessHeaders,
|
||||
[TEXTGEN_TYPES.HUGGINGFACE]: getHuggingFaceHeaders,
|
||||
};
|
||||
|
||||
|
@ -216,6 +216,7 @@ const TEXTGEN_TYPES = {
|
||||
INFERMATICAI: 'infermaticai',
|
||||
DREAMGEN: 'dreamgen',
|
||||
OPENROUTER: 'openrouter',
|
||||
FEATHERLESS: 'featherless',
|
||||
HUGGINGFACE: 'huggingface',
|
||||
};
|
||||
|
||||
@ -242,6 +243,49 @@ const INFERMATICAI_KEYS = [
|
||||
'logprobs',
|
||||
];
|
||||
|
||||
const FEATHERLESS_KEYS = [
|
||||
'model',
|
||||
'prompt',
|
||||
'best_of',
|
||||
'echo',
|
||||
'frequency_penalty',
|
||||
'logit_bias',
|
||||
'logprobs',
|
||||
'max_tokens',
|
||||
'n',
|
||||
'presence_penalty',
|
||||
'seed',
|
||||
'stop',
|
||||
'stream',
|
||||
'suffix',
|
||||
'temperature',
|
||||
'top_p',
|
||||
'user',
|
||||
|
||||
'use_beam_search',
|
||||
'top_k',
|
||||
'min_p',
|
||||
'repetition_penalty',
|
||||
'length_penalty',
|
||||
'early_stopping',
|
||||
'stop_token_ids',
|
||||
'ignore_eos',
|
||||
'min_tokens',
|
||||
'skip_special_tokens',
|
||||
'spaces_between_special_tokens',
|
||||
'truncate_prompt_tokens',
|
||||
|
||||
'include_stop_str_in_output',
|
||||
'response_format',
|
||||
'guided_json',
|
||||
'guided_regex',
|
||||
'guided_choice',
|
||||
'guided_grammar',
|
||||
'guided_decoding_backend',
|
||||
'guided_whitespace_pattern',
|
||||
];
|
||||
|
||||
|
||||
// https://dreamgen.com/docs/api#openai-text
|
||||
const DREAMGEN_KEYS = [
|
||||
'model',
|
||||
@ -383,4 +427,5 @@ module.exports = {
|
||||
OPENROUTER_HEADERS,
|
||||
OPENROUTER_KEYS,
|
||||
VLLM_KEYS,
|
||||
FEATHERLESS_KEYS,
|
||||
};
|
||||
|
@ -4,7 +4,7 @@ const _ = require('lodash');
|
||||
const Readable = require('stream').Readable;
|
||||
|
||||
const { jsonParser } = require('../../express-common');
|
||||
const { TEXTGEN_TYPES, TOGETHERAI_KEYS, OLLAMA_KEYS, INFERMATICAI_KEYS, OPENROUTER_KEYS, VLLM_KEYS, DREAMGEN_KEYS } = require('../../constants');
|
||||
const { TEXTGEN_TYPES, TOGETHERAI_KEYS, OLLAMA_KEYS, INFERMATICAI_KEYS, OPENROUTER_KEYS, VLLM_KEYS, DREAMGEN_KEYS, FEATHERLESS_KEYS } = require('../../constants');
|
||||
const { forwardFetchResponse, trimV1 } = require('../../util');
|
||||
const { setAdditionalHeaders } = require('../../additional-headers');
|
||||
|
||||
@ -127,6 +127,9 @@ router.post('/status', jsonParser, async function (request, response) {
|
||||
case TEXTGEN_TYPES.OLLAMA:
|
||||
url += '/api/tags';
|
||||
break;
|
||||
case TEXTGEN_TYPES.FEATHERLESS:
|
||||
url += '/v1/models';
|
||||
break;
|
||||
case TEXTGEN_TYPES.HUGGINGFACE:
|
||||
url += '/info';
|
||||
break;
|
||||
@ -243,6 +246,7 @@ router.post('/generate', jsonParser, async function (request, response) {
|
||||
} else {
|
||||
switch (request.body.api_type) {
|
||||
case TEXTGEN_TYPES.VLLM:
|
||||
case TEXTGEN_TYPES.FEATHERLESS:
|
||||
case TEXTGEN_TYPES.APHRODITE:
|
||||
case TEXTGEN_TYPES.OOBA:
|
||||
case TEXTGEN_TYPES.TABBY:
|
||||
@ -290,6 +294,11 @@ router.post('/generate', jsonParser, async function (request, response) {
|
||||
args.body = JSON.stringify(request.body);
|
||||
}
|
||||
|
||||
if (request.body.api_type === TEXTGEN_TYPES.FEATHERLESS) {
|
||||
request.body = _.pickBy(request.body, (_, key) => FEATHERLESS_KEYS.includes(key));
|
||||
args.body = JSON.stringify(request.body);
|
||||
}
|
||||
|
||||
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.
|
||||
|
@ -40,6 +40,7 @@ const SECRET_KEYS = {
|
||||
PERPLEXITY: 'api_key_perplexity',
|
||||
GROQ: 'api_key_groq',
|
||||
AZURE_TTS: 'api_key_azure_tts',
|
||||
FEATHERLESS: 'api_key_featherless',
|
||||
ZEROONEAI: 'api_key_01ai',
|
||||
HUGGINGFACE: 'api_key_huggingface',
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user