From 2a2a63c52c3bef1e27f20e98df698824b6bca462 Mon Sep 17 00:00:00 2001 From: Cohee <18619528+Cohee1207@users.noreply.github.com> Date: Sat, 20 Apr 2024 00:09:38 +0300 Subject: [PATCH] Add Perplexity as Chat Completion source --- public/img/perplexity.svg | 3 + public/index.html | 38 ++++++++++-- public/script.js | 7 ++- public/scripts/RossAscends-mods.js | 1 + public/scripts/openai.js | 69 +++++++++++++++++++++- public/scripts/secrets.js | 2 + public/scripts/slash-commands.js | 1 + public/scripts/tokenizers.js | 9 +++ src/constants.js | 1 + src/endpoints/backends/chat-completions.js | 9 ++- src/endpoints/secrets.js | 1 + 11 files changed, 132 insertions(+), 9 deletions(-) create mode 100644 public/img/perplexity.svg diff --git a/public/img/perplexity.svg b/public/img/perplexity.svg new file mode 100644 index 00000000..1c10790e --- /dev/null +++ b/public/img/perplexity.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/index.html b/public/index.html index 73136c6d..ccd952fc 100644 --- a/public/index.html +++ b/public/index.html @@ -470,7 +470,7 @@ -
+
Temperature
@@ -483,7 +483,7 @@
-
+
Frequency Penalty
@@ -496,7 +496,7 @@
-
+
Presence Penalty
@@ -522,7 +522,7 @@
-
+
Top K
@@ -535,7 +535,7 @@
-
+
Top P
@@ -2306,6 +2306,7 @@ + @@ -2704,6 +2705,33 @@
+
+

Perplexity API Key

+
+ + +
+
+ For privacy reasons, your API key will be hidden after you reload the page. +
+

Perplexity Model

+ +

Cohere API Key

diff --git a/public/script.js b/public/script.js index 13be91c6..1d7318e7 100644 --- a/public/script.js +++ b/public/script.js @@ -8243,10 +8243,15 @@ const CONNECT_API_MAP = { source: chat_completion_sources.CUSTOM, }, 'cohere': { - selected: 'cohere', + selected: 'openai', button: '#api_button_openai', source: chat_completion_sources.COHERE, }, + 'perplexity': { + selected: 'openai', + button: '#api_button_openai', + source: chat_completion_sources.PERPLEXITY, + }, 'infermaticai': { selected: 'textgenerationwebui', button: '#api_button_textgenerationwebui', diff --git a/public/scripts/RossAscends-mods.js b/public/scripts/RossAscends-mods.js index 57c135fb..7c371b00 100644 --- a/public/scripts/RossAscends-mods.js +++ b/public/scripts/RossAscends-mods.js @@ -376,6 +376,7 @@ function RA_autoconnect(PrevApi) { || (secret_state[SECRET_KEYS.MAKERSUITE] && oai_settings.chat_completion_source == chat_completion_sources.MAKERSUITE) || (secret_state[SECRET_KEYS.MISTRALAI] && oai_settings.chat_completion_source == chat_completion_sources.MISTRALAI) || (secret_state[SECRET_KEYS.COHERE] && oai_settings.chat_completion_source == chat_completion_sources.COHERE) + || (secret_state[SECRET_KEYS.PERPLEXITY] && oai_settings.chat_completion_source == chat_completion_sources.PERPLEXITY) || (isValidUrl(oai_settings.custom_url) && oai_settings.chat_completion_source == chat_completion_sources.CUSTOM) ) { $('#api_button_openai').trigger('click'); diff --git a/public/scripts/openai.js b/public/scripts/openai.js index 41c9b24a..bc9ccc06 100644 --- a/public/scripts/openai.js +++ b/public/scripts/openai.js @@ -172,6 +172,7 @@ export const chat_completion_sources = { MISTRALAI: 'mistralai', CUSTOM: 'custom', COHERE: 'cohere', + PERPLEXITY: 'perplexity', }; const character_names_behavior = { @@ -238,6 +239,7 @@ const default_settings = { ai21_model: 'j2-ultra', mistralai_model: 'mistral-medium-latest', cohere_model: 'command-r', + perplexity_model: 'llama-3-70b-instruct', custom_model: '', custom_url: '', custom_include_body: '', @@ -310,6 +312,7 @@ const oai_settings = { ai21_model: 'j2-ultra', mistralai_model: 'mistral-medium-latest', cohere_model: 'command-r', + perplexity_model: 'llama-3-70b-instruct', custom_model: '', custom_url: '', custom_include_body: '', @@ -1410,6 +1413,8 @@ function getChatCompletionModel() { return oai_settings.custom_model; case chat_completion_sources.COHERE: return oai_settings.cohere_model; + case chat_completion_sources.PERPLEXITY: + return oai_settings.perplexity_model; default: throw new Error(`Unknown chat completion source: ${oai_settings.chat_completion_source}`); } @@ -1630,6 +1635,7 @@ async function sendOpenAIRequest(type, messages, signal) { const isMistral = oai_settings.chat_completion_source == chat_completion_sources.MISTRALAI; const isCustom = oai_settings.chat_completion_source == chat_completion_sources.CUSTOM; const isCohere = oai_settings.chat_completion_source == chat_completion_sources.COHERE; + const isPerplexity = oai_settings.chat_completion_source == chat_completion_sources.PERPLEXITY; const isTextCompletion = (isOAI && textCompletionModels.includes(oai_settings.openai_model)) || (isOpenRouter && oai_settings.openrouter_force_instruct && power_user.instruct.enabled); const isQuiet = type === 'quiet'; const isImpersonate = type === 'impersonate'; @@ -1777,6 +1783,16 @@ async function sendOpenAIRequest(type, messages, signal) { generate_data['websearch'] = oai_settings.websearch_cohere; } + if (isPerplexity) { + generate_data['top_k'] = Number(oai_settings.top_k_openai); + // Normalize values. 1 == disabled. 0 == is usual disabled state in OpenAI. + generate_data['frequency_penalty'] = Math.max(0, Number(oai_settings.freq_pen_openai)) + 1; + generate_data['presence_penalty'] = Number(oai_settings.pres_pen_openai); + + // YEAH BRO JUST USE OPENAI CLIENT BRO + delete generate_data['stop']; + } + if ((isOAI || isOpenRouter || isMistral || isCustom || isCohere) && oai_settings.seed >= 0) { generate_data['seed'] = oai_settings.seed; } @@ -1847,7 +1863,7 @@ function getStreamingReply(data) { } else if (oai_settings.chat_completion_source == chat_completion_sources.MAKERSUITE) { return data?.candidates?.[0]?.content?.parts?.[0]?.text || ''; } else { - return data.choices[0]?.delta?.content || data.choices[0]?.message?.content || data.choices[0]?.text || ''; + return data.choices[0]?.delta?.content ?? data.choices[0]?.message?.content ?? data.choices[0]?.text ?? ''; } } @@ -2643,6 +2659,7 @@ function loadOpenAISettings(data, settings) { oai_settings.ai21_model = settings.ai21_model ?? default_settings.ai21_model; oai_settings.mistralai_model = settings.mistralai_model ?? default_settings.mistralai_model; oai_settings.cohere_model = settings.cohere_model ?? default_settings.cohere_model; + oai_settings.perplexity_model = settings.perplexity_model ?? default_settings.perplexity_model; oai_settings.custom_model = settings.custom_model ?? default_settings.custom_model; oai_settings.custom_url = settings.custom_url ?? default_settings.custom_url; oai_settings.custom_include_body = settings.custom_include_body ?? default_settings.custom_include_body; @@ -2708,6 +2725,8 @@ function loadOpenAISettings(data, settings) { $(`#model_mistralai_select option[value="${oai_settings.mistralai_model}"`).attr('selected', true); $('#model_cohere_select').val(oai_settings.cohere_model); $(`#model_cohere_select option[value="${oai_settings.cohere_model}"`).attr('selected', true); + $('#model_perplexity_select').val(oai_settings.perplexity_model); + $(`#model_perplexity_select option[value="${oai_settings.perplexity_model}"`).attr('selected', true); $('#custom_model_id').val(oai_settings.custom_model); $('#custom_api_url_text').val(oai_settings.custom_url); $('#openai_max_context').val(oai_settings.openai_max_context); @@ -2857,7 +2876,7 @@ async function getStatusOpen() { return resultCheckStatus(); } - const noValidateSources = [chat_completion_sources.SCALE, chat_completion_sources.CLAUDE, chat_completion_sources.AI21, chat_completion_sources.MAKERSUITE]; + const noValidateSources = [chat_completion_sources.SCALE, chat_completion_sources.CLAUDE, chat_completion_sources.AI21, chat_completion_sources.MAKERSUITE, chat_completion_sources.PERPLEXITY]; if (noValidateSources.includes(oai_settings.chat_completion_source)) { let status = 'Unable to verify key; press "Test Message" to validate.'; setOnlineStatus(status); @@ -2948,6 +2967,7 @@ async function saveOpenAIPreset(name, settings, triggerUi = true) { ai21_model: settings.ai21_model, mistralai_model: settings.mistralai_model, cohere_model: settings.cohere_model, + perplexity_model: settings.perplexity_model, custom_model: settings.custom_model, custom_url: settings.custom_url, custom_include_body: settings.custom_include_body, @@ -3340,6 +3360,7 @@ function onSettingsPresetChange() { ai21_model: ['#model_ai21_select', 'ai21_model', false], mistralai_model: ['#model_mistralai_select', 'mistralai_model', false], cohere_model: ['#model_cohere_select', 'cohere_model', false], + perplexity_model: ['#model_perplexity_select', 'perplexity_model', false], custom_model: ['#custom_model_id', 'custom_model', false], custom_url: ['#custom_api_url_text', 'custom_url', false], custom_include_body: ['#custom_include_body', 'custom_include_body', false], @@ -3563,6 +3584,11 @@ async function onModelChange() { oai_settings.cohere_model = value; } + if ($(this).is('#model_perplexity_select')) { + console.log('Perplexity model changed to', value); + oai_settings.perplexity_model = value; + } + if (value && $(this).is('#model_custom_select')) { console.log('Custom model changed to', value); oai_settings.custom_model = value; @@ -3706,6 +3732,28 @@ async function onModelChange() { $('#openai_max_context').val(oai_settings.openai_max_context).trigger('input'); } + if (oai_settings.chat_completion_source === chat_completion_sources.PERPLEXITY) { + if (oai_settings.max_context_unlocked) { + $('#openai_max_context').attr('max', unlocked_max); + } + else if (['sonar-small-chat', 'sonar-medium-chat', 'codellama-70b-instruct', 'mistral-7b-instruct', 'mixtral-8x7b-instruct', 'mixtral-8x22b-instruct'].includes(oai_settings.perplexity_model)) { + $('#openai_max_context').attr('max', max_16k); + } + else if (['llama-3-8b-instruct', 'llama-3-70b-instruct'].includes(oai_settings.perplexity_model)) { + $('#openai_max_context').attr('max', max_8k); + } + else if (['sonar-small-online', 'sonar-medium-online'].includes(oai_settings.perplexity_model)) { + $('#openai_max_context').attr('max', 12000); + } + else { + $('#openai_max_context').attr('max', max_4k); + } + oai_settings.openai_max_context = Math.min(Number($('#openai_max_context').attr('max')), oai_settings.openai_max_context); + $('#openai_max_context').val(oai_settings.openai_max_context).trigger('input'); + oai_settings.temp_openai = Math.min(oai_max_temp, oai_settings.temp_openai); + $('#temp_openai').attr('max', oai_max_temp).val(oai_settings.temp_openai).trigger('input'); + } + if (oai_settings.chat_completion_source == chat_completion_sources.AI21) { if (oai_settings.max_context_unlocked) { $('#openai_max_context').attr('max', unlocked_max); @@ -3912,6 +3960,19 @@ async function onConnectButtonClick(e) { } } + if (oai_settings.chat_completion_source == chat_completion_sources.PERPLEXITY) { + const api_key_perplexity = String($('#api_key_perplexity').val()).trim(); + + if (api_key_perplexity.length) { + await writeSecret(SECRET_KEYS.PERPLEXITY, api_key_perplexity); + } + + if (!secret_state[SECRET_KEYS.PERPLEXITY]) { + console.log('No secret key saved for Perplexity'); + return; + } + } + startStatusLoading(); saveSettingsDebounced(); await getStatusOpen(); @@ -3950,6 +4011,9 @@ function toggleChatCompletionForms() { else if (oai_settings.chat_completion_source == chat_completion_sources.COHERE) { $('#model_cohere_select').trigger('change'); } + else if (oai_settings.chat_completion_source == chat_completion_sources.PERPLEXITY) { + $('#model_perplexity_select').trigger('change'); + } else if (oai_settings.chat_completion_source == chat_completion_sources.CUSTOM) { $('#model_custom_select').trigger('change'); } @@ -4619,6 +4683,7 @@ $(document).ready(async function () { $('#model_ai21_select').on('change', onModelChange); $('#model_mistralai_select').on('change', onModelChange); $('#model_cohere_select').on('change', onModelChange); + $('#model_perplexity_select').on('change', onModelChange); $('#model_custom_select').on('change', onModelChange); $('#settings_preset_openai').on('change', onSettingsPresetChange); $('#new_oai_preset').on('click', onNewPresetClick); diff --git a/public/scripts/secrets.js b/public/scripts/secrets.js index a6bed105..f6ebd1f2 100644 --- a/public/scripts/secrets.js +++ b/public/scripts/secrets.js @@ -24,6 +24,7 @@ export const SECRET_KEYS = { KOBOLDCPP: 'api_key_koboldcpp', LLAMACPP: 'api_key_llamacpp', COHERE: 'api_key_cohere', + PERPLEXITY: 'api_key_perplexity', }; const INPUT_MAP = { @@ -49,6 +50,7 @@ const INPUT_MAP = { [SECRET_KEYS.KOBOLDCPP]: '#api_key_koboldcpp', [SECRET_KEYS.LLAMACPP]: '#api_key_llamacpp', [SECRET_KEYS.COHERE]: '#api_key_cohere', + [SECRET_KEYS.PERPLEXITY]: '#api_key_perplexity', }; async function clearSecret() { diff --git a/public/scripts/slash-commands.js b/public/scripts/slash-commands.js index 215295e3..f02c086c 100644 --- a/public/scripts/slash-commands.js +++ b/public/scripts/slash-commands.js @@ -1682,6 +1682,7 @@ function modelCallback(_, model) { { id: 'model_mistralai_select', api: 'openai', type: chat_completion_sources.MISTRALAI }, { id: 'model_custom_select', api: 'openai', type: chat_completion_sources.CUSTOM }, { id: 'model_cohere_select', api: 'openai', type: chat_completion_sources.COHERE }, + { id: 'model_perplexity_select', api: 'openai', type: chat_completion_sources.PERPLEXITY }, { id: 'model_novel_select', api: 'novel', type: null }, { id: 'horde_model', api: 'koboldhorde', type: null }, ]; diff --git a/public/scripts/tokenizers.js b/public/scripts/tokenizers.js index 7e9fc785..3c44fdd1 100644 --- a/public/scripts/tokenizers.js +++ b/public/scripts/tokenizers.js @@ -497,6 +497,15 @@ export function getTokenizerModel() { return oai_settings.custom_model; } + if (oai_settings.chat_completion_source === chat_completion_sources.PERPLEXITY) { + if (oai_settings.perplexity_model.includes('llama')) { + return llamaTokenizer; + } + if (oai_settings.perplexity_model.includes('mistral')) { + return mistralTokenizer; + } + } + // Default to Turbo 3.5 return turboTokenizer; } diff --git a/src/constants.js b/src/constants.js index e7831bf4..d733f2b3 100644 --- a/src/constants.js +++ b/src/constants.js @@ -163,6 +163,7 @@ const CHAT_COMPLETION_SOURCES = { MISTRALAI: 'mistralai', CUSTOM: 'custom', COHERE: 'cohere', + PERPLEXITY: 'perplexity', }; const UPLOADS_PATH = './uploads'; diff --git a/src/endpoints/backends/chat-completions.js b/src/endpoints/backends/chat-completions.js index 494282a5..01545772 100644 --- a/src/endpoints/backends/chat-completions.js +++ b/src/endpoints/backends/chat-completions.js @@ -14,6 +14,7 @@ const API_OPENAI = 'https://api.openai.com/v1'; const API_CLAUDE = 'https://api.anthropic.com/v1'; const API_MISTRAL = 'https://api.mistral.ai/v1'; const API_COHERE = 'https://api.cohere.ai/v1'; +const API_PERPLEXITY = 'https://api.perplexity.ai'; /** * Applies a post-processing step to the generated messages. @@ -439,7 +440,7 @@ async function sendAI21Request(request, response) { } else { console.log(r.completions[0].data.text); } - const reply = { choices: [{ 'message': { 'content': r.completions[0].data.text } }] }; + const reply = { choices: [{ 'message': { 'content': r.completions?.[0]?.data?.text } }] }; return response.send(reply); }) .catch(err => { @@ -894,6 +895,12 @@ router.post('/generate', jsonParser, function (request, response) { request.body.char_name, request.body.user_name); } + } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.PERPLEXITY) { + apiUrl = API_PERPLEXITY; + apiKey = readSecret(SECRET_KEYS.PERPLEXITY); + headers = {}; + bodyParams = {}; + request.body.messages = postProcessPrompt(request.body.messages, 'claude', request.body.char_name, request.body.user_name); } else { console.log('This chat completion source is not supported yet.'); return response.status(400).send({ error: true }); diff --git a/src/endpoints/secrets.js b/src/endpoints/secrets.js index afd41a1f..79e8cda8 100644 --- a/src/endpoints/secrets.js +++ b/src/endpoints/secrets.js @@ -36,6 +36,7 @@ const SECRET_KEYS = { KOBOLDCPP: 'api_key_koboldcpp', LLAMACPP: 'api_key_llamacpp', COHERE: 'api_key_cohere', + PERPLEXITY: 'api_key_perplexity', }; // These are the keys that are safe to expose, even if allowKeysExposure is false