Merge remote-tracking branch 'upstream/staging' into quad-sample
This commit is contained in:
commit
9c33a04806
|
@ -746,48 +746,6 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<hr data-source="openai,claude">
|
||||
<div class="range-block" data-source="openai,claude">
|
||||
<div class="range-block-title justifyLeft" data-i18n="OpenAI Reverse Proxy">
|
||||
OpenAI / Claude Reverse Proxy
|
||||
</div>
|
||||
<div class="toggle-description justifyLeft">
|
||||
<span data-i18n="Alternative server URL (leave empty to use the default value).">
|
||||
Alternative server URL (leave empty to use the default value).<br>
|
||||
</span>
|
||||
<div id="ReverseProxyWarningMessage" class="reverse_proxy_warning">
|
||||
<b data-i18n="Remove your real OAI API Key from the API panel BEFORE typing anything into this box">
|
||||
Remove your real OAI API Key from the API panel BEFORE typing anything
|
||||
into this box.
|
||||
</b>
|
||||
<hr>
|
||||
<b data-i18n="We cannot provide support for problems encountered while using an unofficial OpenAI proxy">
|
||||
We cannot provide support for problems encountered while using an
|
||||
unofficial OpenAI proxy.
|
||||
</b>
|
||||
</div>
|
||||
</div>
|
||||
<div class="wide100p">
|
||||
<input id="openai_reverse_proxy" type="text" class="text_pole" placeholder="https://api.openai.com/v1" maxlength="500" />
|
||||
<small class="reverse_proxy_warning">
|
||||
Doesn't work? Try adding <code>/v1</code> at the end!
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="range-block" data-source="openai,claude">
|
||||
<div class="range-block-title justifyLeft" data-i18n="Proxy Password">
|
||||
Proxy Password
|
||||
</div>
|
||||
<div class="toggle-description justifyLeft">
|
||||
<span data-i18n="Will be used as a password for the proxy instead of API key.">
|
||||
Will be used as a password for the proxy instead of API key.<br>
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex-container width100p">
|
||||
<input id="openai_proxy_password" type="password" class="text_pole flex1" placeholder="" maxlength="500" form="openai_form" />
|
||||
<div id="openai_proxy_password_show" title="Peek a password" class="menu_button fa-solid fa-eye-slash fa-fw"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div data-newbie-hidden class="range-block" data-source="openai,openrouter,mistralai,custom">
|
||||
<div class="range-block-title justifyLeft" data-i18n="Seed">
|
||||
Seed
|
||||
|
@ -2094,6 +2052,76 @@
|
|||
<option value="mistralai">MistralAI</option>
|
||||
<option value="custom">Custom (OpenAI-compatible)</option>
|
||||
</select>
|
||||
<div data-newbie-hidden class="inline-drawer wide100p" data-source="openai,claude,mistralai">
|
||||
<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>
|
||||
</div>
|
||||
<div class="inline-drawer-content">
|
||||
<div class="range-block-title justifyLeft" data-i18n="Proxy Presets">
|
||||
Proxy Presets
|
||||
</div>
|
||||
<div class="toggle-description justifyLeft">
|
||||
<span data-i18n="Saved addresses and passwords.">
|
||||
Saved addresses and passwords.<br>
|
||||
</span>
|
||||
</div>
|
||||
<div class="openai_logit_bias_preset_form">
|
||||
<select id="openai_proxy_preset">
|
||||
</select>
|
||||
<i id="save_proxy" class="menu_button fa-solid fa-save" title="Save Proxy" data-i18n="[title]Save Proxy"></i>
|
||||
<i id="delete_proxy" class="menu_button fa-solid fa-trash" title="Delete Proxy" data-i18n="[title]Delete Proxy"></i>
|
||||
</div>
|
||||
<div class="range-block-title justifyLeft" data-i18n="Proxy Name">
|
||||
Proxy Name
|
||||
</div>
|
||||
<div class="toggle-description justifyLeft">
|
||||
<span data-i18n="This will show up as your saved preset.">
|
||||
This will show up as your saved preset.<br>
|
||||
</span>
|
||||
</div>
|
||||
<div class="wide100p">
|
||||
<input id="openai_reverse_proxy_name" type="text" class="text_pole" placeholder="..." maxlength="100" />
|
||||
</div>
|
||||
<div class="range-block-title justifyLeft" data-i18n="Proxy Server URL">
|
||||
Proxy Server URL
|
||||
</div>
|
||||
<div class="toggle-description justifyLeft wide100p">
|
||||
<span data-i18n="Alternative server URL (leave empty to use the default value).">
|
||||
Alternative server URL (leave empty to use the default value).<br>
|
||||
</span>
|
||||
<div id="ReverseProxyWarningMessage" class="reverse_proxy_warning">
|
||||
<b data-i18n="Remove your real OAI API Key from the API panel BEFORE typing anything into this box">
|
||||
Remove your real OAI API Key from the API panel BEFORE typing anything
|
||||
into this box.
|
||||
</b>
|
||||
<hr>
|
||||
<b data-i18n="We cannot provide support for problems encountered while using an unofficial OpenAI proxy">
|
||||
We cannot provide support for problems encountered while using an
|
||||
unofficial OpenAI proxy.
|
||||
</b>
|
||||
</div>
|
||||
</div>
|
||||
<div class="wide100p">
|
||||
<input id="openai_reverse_proxy" type="text" class="text_pole" placeholder="https://api.openai.com/v1" maxlength="500" />
|
||||
<small class="reverse_proxy_warning">
|
||||
Doesn't work? Try adding <code>/v1</code> at the end!
|
||||
</small>
|
||||
</div>
|
||||
<div class="range-block-title justifyLeft" data-i18n="Proxy Password">
|
||||
Proxy Password
|
||||
</div>
|
||||
<div class="toggle-description justifyLeft">
|
||||
<span data-i18n="Will be used as a password for the proxy instead of API key.">
|
||||
Will be used as a password for the proxy instead of API key.<br>
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex-container width100p">
|
||||
<input id="openai_proxy_password" type="password" class="text_pole flex1" placeholder="" maxlength="500" form="openai_form" />
|
||||
<div id="openai_proxy_password_show" title="Peek a password" class="menu_button fa-solid fa-eye-slash fa-fw"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<form id="openai_form" data-source="openai" action="javascript:void(null);" method="post" enctype="multipart/form-data">
|
||||
<h4><span data-i18n="OpenAI API key">OpenAI API key</span></h4>
|
||||
<div>
|
||||
|
|
|
@ -93,6 +93,9 @@ import {
|
|||
chat_completion_sources,
|
||||
getChatCompletionModel,
|
||||
isOpenRouterWithInstruct,
|
||||
proxies,
|
||||
loadProxyPresets,
|
||||
selected_proxy,
|
||||
} from './scripts/openai.js';
|
||||
|
||||
import {
|
||||
|
@ -5664,6 +5667,9 @@ async function getSettings() {
|
|||
// Load background
|
||||
loadBackgroundSettings(settings);
|
||||
|
||||
// Load proxy presets
|
||||
loadProxyPresets(settings);
|
||||
|
||||
// Allow subscribers to mutate settings
|
||||
eventSource.emit(event_types.SETTINGS_LOADED_AFTER, settings);
|
||||
|
||||
|
@ -5742,7 +5748,6 @@ async function saveSettings(type) {
|
|||
}
|
||||
|
||||
//console.log('Entering settings with name1 = '+name1);
|
||||
|
||||
return jQuery.ajax({
|
||||
type: 'POST',
|
||||
url: '/api/settings/save',
|
||||
|
@ -5770,6 +5775,8 @@ async function saveSettings(type) {
|
|||
kai_settings: kai_settings,
|
||||
oai_settings: oai_settings,
|
||||
background: background_settings,
|
||||
proxies: proxies,
|
||||
selected_proxy: selected_proxy,
|
||||
}, null, 4),
|
||||
beforeSend: function () { },
|
||||
cache: false,
|
||||
|
|
|
@ -374,6 +374,11 @@ function withVirtualWhitespace(text, span) {
|
|||
* @param {string | null} continueFrom - for 'continue' generations, the prompt
|
||||
*/
|
||||
export function saveLogprobsForActiveMessage(logprobs, continueFrom) {
|
||||
if (!logprobs) {
|
||||
// non-streaming APIs could return null data
|
||||
return;
|
||||
}
|
||||
|
||||
convertTokenIdLogprobsToText(logprobs);
|
||||
|
||||
const msgId = chat.length - 1;
|
||||
|
|
|
@ -317,6 +317,15 @@ const oai_settings = {
|
|||
seed: -1,
|
||||
};
|
||||
|
||||
export let proxies = [
|
||||
{
|
||||
name: 'None',
|
||||
url: '',
|
||||
password: '',
|
||||
},
|
||||
];
|
||||
export let selected_proxy = proxies[0];
|
||||
|
||||
let openai_setting_names;
|
||||
let openai_settings;
|
||||
|
||||
|
@ -1596,8 +1605,8 @@ async function sendOpenAIRequest(type, messages, signal) {
|
|||
delete generate_data.stop;
|
||||
}
|
||||
|
||||
// Proxy is only supported for Claude and OpenAI
|
||||
if (oai_settings.reverse_proxy && [chat_completion_sources.CLAUDE, chat_completion_sources.OPENAI].includes(oai_settings.chat_completion_source)) {
|
||||
// Proxy is only supported for Claude, OpenAI and Mistral
|
||||
if (oai_settings.reverse_proxy && [chat_completion_sources.CLAUDE, chat_completion_sources.OPENAI, chat_completion_sources.MISTRALAI].includes(oai_settings.chat_completion_source)) {
|
||||
validateReverseProxy();
|
||||
generate_data['reverse_proxy'] = oai_settings.reverse_proxy;
|
||||
generate_data['proxy_password'] = oai_settings.proxy_password;
|
||||
|
@ -3803,6 +3812,110 @@ export function isImageInliningSupported() {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Proxy stuff
|
||||
*/
|
||||
export function loadProxyPresets(settings) {
|
||||
let proxyPresets = settings.proxies;
|
||||
selected_proxy = settings.selected_proxy || selected_proxy;
|
||||
if (!Array.isArray(proxyPresets) || proxyPresets.length === 0) {
|
||||
proxyPresets = proxies;
|
||||
} else {
|
||||
proxies = proxyPresets;
|
||||
}
|
||||
|
||||
$('#openai_proxy_preset').empty();
|
||||
|
||||
for (const preset of proxyPresets) {
|
||||
const option = document.createElement('option');
|
||||
option.innerText = preset.name;
|
||||
option.value = preset.name;
|
||||
option.selected = preset.name === 'None';
|
||||
$('#openai_proxy_preset').append(option);
|
||||
}
|
||||
$('#openai_proxy_preset').val(selected_proxy.name);
|
||||
setProxyPreset(selected_proxy.name, selected_proxy.url, selected_proxy.password);
|
||||
}
|
||||
|
||||
function setProxyPreset(name, url, password) {
|
||||
const preset = proxies.find(p => p.name === name);
|
||||
if (preset) {
|
||||
preset.url = url;
|
||||
preset.password = password;
|
||||
selected_proxy = preset;
|
||||
} else {
|
||||
let new_proxy = { name, url, password };
|
||||
proxies.push(new_proxy);
|
||||
selected_proxy = new_proxy;
|
||||
}
|
||||
|
||||
$('#openai_reverse_proxy_name').val(name);
|
||||
oai_settings.reverse_proxy = url;
|
||||
$('#openai_reverse_proxy').val(oai_settings.reverse_proxy);
|
||||
oai_settings.proxy_password = password;
|
||||
$('#openai_proxy_password').val(oai_settings.proxy_password);
|
||||
reconnectOpenAi();
|
||||
}
|
||||
|
||||
function onProxyPresetChange() {
|
||||
const value = String($('#openai_proxy_preset').find(':selected').val());
|
||||
const selectedPreset = proxies.find(preset => preset.name === value);
|
||||
|
||||
if (selectedPreset) {
|
||||
setProxyPreset(selectedPreset.name, selectedPreset.url, selectedPreset.password);
|
||||
} else {
|
||||
console.error(`Proxy preset "${value}" not found in proxies array.`);
|
||||
}
|
||||
saveSettingsDebounced();
|
||||
}
|
||||
|
||||
$('#save_proxy').on('click', async function () {
|
||||
const presetName = $('#openai_reverse_proxy_name').val();
|
||||
const reverseProxy = $('#openai_reverse_proxy').val();
|
||||
const proxyPassword = $('#openai_proxy_password').val();
|
||||
|
||||
setProxyPreset(presetName, reverseProxy, proxyPassword);
|
||||
saveSettingsDebounced();
|
||||
toastr.success('Proxy Saved');
|
||||
if($('#openai_proxy_preset').val() !== presetName) {
|
||||
const option = document.createElement('option');
|
||||
option.text = presetName;
|
||||
option.value = presetName;
|
||||
|
||||
$('#openai_proxy_preset').append(option);
|
||||
}
|
||||
$('#openai_proxy_preset').val(presetName);
|
||||
});
|
||||
|
||||
$('#delete_proxy').on('click', async function () {
|
||||
const presetName = $('#openai_reverse_proxy_name').val();
|
||||
const index = proxies.findIndex(preset => preset.name === presetName);
|
||||
|
||||
if (index !== -1) {
|
||||
proxies.splice(index, 1);
|
||||
$('#openai_proxy_preset option[value="' + presetName + '"]').remove();
|
||||
|
||||
if (proxies.length > 0) {
|
||||
const newIndex = Math.max(0, index - 1);
|
||||
selected_proxy = proxies[newIndex];
|
||||
} else {
|
||||
selected_proxy = { name: 'None', url: '', password: '' };
|
||||
}
|
||||
|
||||
$('#openai_reverse_proxy_name').val(selected_proxy.name);
|
||||
oai_settings.reverse_proxy = selected_proxy.url;
|
||||
$('#openai_reverse_proxy').val(selected_proxy.url);
|
||||
oai_settings.proxy_password = selected_proxy.password;
|
||||
$('#openai_proxy_password').val(selected_proxy.password);
|
||||
|
||||
saveSettingsDebounced();
|
||||
$('#openai_proxy_preset').val(selected_proxy.name);
|
||||
toastr.success('Proxy Deleted');
|
||||
} else {
|
||||
toastr.error(`Could not find proxy with name "${presetName}"`);
|
||||
}
|
||||
});
|
||||
|
||||
$(document).ready(async function () {
|
||||
$('#test_api_button').on('click', testApiConnection);
|
||||
|
||||
|
@ -4183,4 +4296,5 @@ $(document).ready(async function () {
|
|||
$('#import_oai_preset').on('click', onImportPresetClick);
|
||||
$('#openai_proxy_password_show').on('click', onProxyPasswordShowClick);
|
||||
$('#customize_additional_parameters').on('click', onCustomizeParametersClick);
|
||||
$('#openai_proxy_preset').on('change', onProxyPresetChange);
|
||||
});
|
||||
|
|
|
@ -12,7 +12,7 @@ const { getTokenizerModel, getSentencepiceTokenizer, getTiktokenTokenizer, sente
|
|||
|
||||
const API_OPENAI = 'https://api.openai.com/v1';
|
||||
const API_CLAUDE = 'https://api.anthropic.com/v1';
|
||||
|
||||
const API_MISTRAL = 'https://api.mistral.ai/v1';
|
||||
/**
|
||||
* Sends a request to Claude API.
|
||||
* @param {express.Request} request Express request
|
||||
|
@ -436,7 +436,8 @@ async function sendAI21Request(request, response) {
|
|||
* @param {express.Response} response Express response
|
||||
*/
|
||||
async function sendMistralAIRequest(request, response) {
|
||||
const apiKey = readSecret(SECRET_KEYS.MISTRALAI);
|
||||
const apiUrl = new URL(request.body.reverse_proxy || API_MISTRAL).toString();
|
||||
const apiKey = request.body.reverse_proxy ? request.body.proxy_password : readSecret(SECRET_KEYS.MISTRALAI);
|
||||
|
||||
if (!apiKey) {
|
||||
console.log('MistralAI API key is missing.');
|
||||
|
@ -500,7 +501,7 @@ async function sendMistralAIRequest(request, response) {
|
|||
|
||||
console.log('MisralAI request:', requestBody);
|
||||
|
||||
const generateResponse = await fetch('https://api.mistral.ai/v1/chat/completions', config);
|
||||
const generateResponse = await fetch(apiUrl + '/chat/completions', config);
|
||||
if (request.body.stream) {
|
||||
forwardFetchResponse(generateResponse, response);
|
||||
} else {
|
||||
|
@ -543,8 +544,8 @@ router.post('/status', jsonParser, async function (request, response_getstatus_o
|
|||
// OpenRouter needs to pass the referer: https://openrouter.ai/docs
|
||||
headers = { 'HTTP-Referer': request.headers.referer };
|
||||
} else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.MISTRALAI) {
|
||||
api_url = 'https://api.mistral.ai/v1';
|
||||
api_key_openai = readSecret(SECRET_KEYS.MISTRALAI);
|
||||
api_url = new URL(request.body.reverse_proxy || API_MISTRAL).toString();
|
||||
api_key_openai = request.body.reverse_proxy ? request.body.proxy_password : readSecret(SECRET_KEYS.MISTRALAI);
|
||||
headers = {};
|
||||
} else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.CUSTOM) {
|
||||
api_url = request.body.custom_url;
|
||||
|
|
Loading…
Reference in New Issue