mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-06-05 21:59:27 +02:00
Support Window.ai extension
This commit is contained in:
@ -1118,7 +1118,14 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="openai_api" style="display: none;position: relative;">
|
<div id="openai_api" style="display: none;position: relative;">
|
||||||
<form action="javascript:void(null);" method="post" enctype="multipart/form-data">
|
<label for="use_window_ai" class="checkbox_label">
|
||||||
|
<input id="use_window_ai" type="checkbox" />
|
||||||
|
Use Window.ai
|
||||||
|
<a href="/notes#windowai" class="notes-link" target="_blank">
|
||||||
|
<span class="note-link-span">?</span>
|
||||||
|
</a>
|
||||||
|
</label>
|
||||||
|
<form id="openai_form" action="javascript:void(null);" method="post" enctype="multipart/form-data">
|
||||||
<h4>API key </h4>
|
<h4>API key </h4>
|
||||||
<span>
|
<span>
|
||||||
<ol>
|
<ol>
|
||||||
@ -1135,24 +1142,24 @@
|
|||||||
<div class="neutral_warning">For privacy reasons, your API key will be hidden after you reload the page.</div>
|
<div class="neutral_warning">For privacy reasons, your API key will be hidden after you reload the page.</div>
|
||||||
<input id="api_button_openai" class="menu_button" type="submit" value="Connect">
|
<input id="api_button_openai" class="menu_button" type="submit" value="Connect">
|
||||||
<div id="api_loading_openai" class=" api-load-icon fa-solid fa-hourglass fa-spin"></div>
|
<div id="api_loading_openai" class=" api-load-icon fa-solid fa-hourglass fa-spin"></div>
|
||||||
|
<div class="online_status4">
|
||||||
|
<div class="online_status_indicator4"></div>
|
||||||
|
<div class="online_status_text4">No connection...</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h4>OpenAI Model</h4>
|
||||||
|
<select id="model_openai_select">
|
||||||
|
<option value="gpt-3.5-turbo">gpt-3.5-turbo</option>
|
||||||
|
<option value="gpt-3.5-turbo-0301">gpt-3.5-turbo-0301</option>
|
||||||
|
<option value="gpt-4">gpt-4</option>
|
||||||
|
<option value="gpt-4-0314">gpt-4-0314</option>
|
||||||
|
<option value="gpt-4-32k">gpt-4-32k</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<a id="openai_api_usage" href="javascript:void(0);">View API Usage Metrics</a>
|
||||||
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<div class="online_status4">
|
|
||||||
<div class="online_status_indicator4"></div>
|
|
||||||
<div class="online_status_text4">No connection...</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<h4>OpenAI Model</h4>
|
|
||||||
<select id="model_openai_select">
|
|
||||||
<option value="gpt-3.5-turbo">gpt-3.5-turbo</option>
|
|
||||||
<option value="gpt-3.5-turbo-0301">gpt-3.5-turbo-0301</option>
|
|
||||||
<option value="gpt-4">gpt-4</option>
|
|
||||||
<option value="gpt-4-0314">gpt-4-0314</option>
|
|
||||||
<option value="gpt-4-32k">gpt-4-32k</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<a id="openai_api_usage" href="javascript:void(0);">View API Usage Metrics</a>
|
|
||||||
</div>
|
|
||||||
<br>
|
<br>
|
||||||
</div>
|
</div>
|
||||||
<div id="poe_api">
|
<div id="poe_api">
|
||||||
|
@ -388,6 +388,15 @@ If your subscription tier is Paper, Tablet or Scroll use only Euterpe model othe
|
|||||||
|
|
||||||
_Lost API keys can't be restored! Make sure to keep it safe!_
|
_Lost API keys can't be restored! Make sure to keep it safe!_
|
||||||
|
|
||||||
|
### Window.ai
|
||||||
|
|
||||||
|
You can use window.ai browser extension to access AI models with SillyTavern.
|
||||||
|
|
||||||
|
1. Install a browser extension from: [windowai.io](https://windowai.io/)
|
||||||
|
2. Create an OpenRouter account: [openrouter.ai](https://openrouter.ai/)
|
||||||
|
3. Select OpenRouter as a provider in Window.ai extension.
|
||||||
|
4. Use OpenAI API provider and enable "Use Window.ai" option in SillyTavern
|
||||||
|
|
||||||
## Poe
|
## Poe
|
||||||
|
|
||||||
### API key
|
### API key
|
||||||
|
@ -3724,6 +3724,10 @@ function changeMainAPI() {
|
|||||||
main_api = selectedVal;
|
main_api = selectedVal;
|
||||||
online_status = "no_connection";
|
online_status = "no_connection";
|
||||||
|
|
||||||
|
if (main_api == 'openai' && oai_settings.use_window_ai) {
|
||||||
|
$('#api_button_openai').trigger('click');
|
||||||
|
}
|
||||||
|
|
||||||
if (main_api == "koboldhorde") {
|
if (main_api == "koboldhorde") {
|
||||||
is_get_status = true;
|
is_get_status = true;
|
||||||
getStatus();
|
getStatus();
|
||||||
|
@ -104,6 +104,7 @@ const default_settings = {
|
|||||||
jailbreak_system: false,
|
jailbreak_system: false,
|
||||||
reverse_proxy: '',
|
reverse_proxy: '',
|
||||||
legacy_streaming: false,
|
legacy_streaming: false,
|
||||||
|
use_window_ai: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
const oai_settings = {
|
const oai_settings = {
|
||||||
@ -129,6 +130,7 @@ const oai_settings = {
|
|||||||
jailbreak_system: false,
|
jailbreak_system: false,
|
||||||
reverse_proxy: '',
|
reverse_proxy: '',
|
||||||
legacy_streaming: false,
|
legacy_streaming: false,
|
||||||
|
use_window_ai: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
let openai_setting_names;
|
let openai_setting_names;
|
||||||
@ -550,6 +552,41 @@ async function sendOpenAIRequest(type, openai_msgs_tosend, signal) {
|
|||||||
"logit_bias": logit_bias,
|
"logit_bias": logit_bias,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (oai_settings.use_window_ai) {
|
||||||
|
if (!('ai' in window)) {
|
||||||
|
return showWindowExtensionError();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function* windowStreamingFunction(res) {
|
||||||
|
yield (res?.message?.content || '');
|
||||||
|
}
|
||||||
|
|
||||||
|
const generatePromise = window.ai.generateText(
|
||||||
|
{
|
||||||
|
messages: openai_msgs_tosend,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
temperature: parseFloat(oai_settings.temp_openai),
|
||||||
|
maxTokens: oai_settings.openai_max_tokens,
|
||||||
|
onStreamResult: windowStreamingFunction,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (stream) {
|
||||||
|
return windowStreamingFunction;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const [{ message }] = await generatePromise;
|
||||||
|
windowStreamingFunction(message);
|
||||||
|
return message?.content;
|
||||||
|
} catch (err) {
|
||||||
|
const text = parseWindowError(err);
|
||||||
|
toastr.error(text, 'Window.ai returned an error');
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const generate_url = '/generate_openai';
|
const generate_url = '/generate_openai';
|
||||||
const response = await fetch(generate_url, {
|
const response = await fetch(generate_url, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
@ -614,6 +651,30 @@ async function sendOpenAIRequest(type, openai_msgs_tosend, signal) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function parseWindowError(err) {
|
||||||
|
let text = 'Unknown error';
|
||||||
|
|
||||||
|
switch (err) {
|
||||||
|
case "NOT_AUTHENTICATED":
|
||||||
|
text = 'Incorrect API key / auth';
|
||||||
|
break;
|
||||||
|
case "MODEL_REJECTED_REQUEST":
|
||||||
|
text = 'AI model refused to fulfill a request';
|
||||||
|
break;
|
||||||
|
case "PERMISSION_DENIED":
|
||||||
|
text = 'User denied permission to the app';
|
||||||
|
break;
|
||||||
|
case "REQUEST_NOT_FOUND":
|
||||||
|
text = 'Permission request popup timed out';
|
||||||
|
break;
|
||||||
|
case "INVALID_REQUEST":
|
||||||
|
text = 'Malformed request';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
async function calculateLogitBias() {
|
async function calculateLogitBias() {
|
||||||
const body = JSON.stringify(oai_settings.bias_presets[oai_settings.bias_preset_selected]);
|
const body = JSON.stringify(oai_settings.bias_presets[oai_settings.bias_preset_selected]);
|
||||||
let result = {};
|
let result = {};
|
||||||
@ -813,10 +874,27 @@ function loadOpenAISettings(data, settings) {
|
|||||||
$('#openai_logit_bias_preset').append(option);
|
$('#openai_logit_bias_preset').append(option);
|
||||||
}
|
}
|
||||||
$('#openai_logit_bias_preset').trigger('change');
|
$('#openai_logit_bias_preset').trigger('change');
|
||||||
|
|
||||||
|
$('#use_window_ai').prop('checked', oai_settings.use_window_ai);
|
||||||
|
$('#openai_form').toggle(!oai_settings.use_window_ai);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getStatusOpen() {
|
async function getStatusOpen() {
|
||||||
if (is_get_status_openai) {
|
if (is_get_status_openai) {
|
||||||
|
if (oai_settings.use_window_ai) {
|
||||||
|
let status;
|
||||||
|
|
||||||
|
if ('ai' in window) {
|
||||||
|
status = 'Valid';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
showWindowExtensionError();
|
||||||
|
status = 'no_connection';
|
||||||
|
}
|
||||||
|
|
||||||
|
setOnlineStatus(status);
|
||||||
|
return resultCheckStatusOpen();
|
||||||
|
}
|
||||||
|
|
||||||
let data = {
|
let data = {
|
||||||
reverse_proxy: oai_settings.reverse_proxy,
|
reverse_proxy: oai_settings.reverse_proxy,
|
||||||
@ -851,6 +929,15 @@ async function getStatusOpen() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function showWindowExtensionError() {
|
||||||
|
toastr.error('Get it here: <a href="https://windowai.io/" target="_blank">windowai.io</a>', 'Extension is not installed', {
|
||||||
|
escapeHtml: false,
|
||||||
|
timeOut: 0,
|
||||||
|
extendedTimeOut: 0,
|
||||||
|
preventDuplicates: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function resultCheckStatusOpen() {
|
function resultCheckStatusOpen() {
|
||||||
is_api_button_press_openai = false;
|
is_api_button_press_openai = false;
|
||||||
checkOnlineStatus();
|
checkOnlineStatus();
|
||||||
@ -1221,6 +1308,13 @@ function onReverseProxyInput() {
|
|||||||
|
|
||||||
async function onConnectButtonClick(e) {
|
async function onConnectButtonClick(e) {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
|
||||||
|
if (oai_settings.use_window_ai) {
|
||||||
|
is_get_status_openai = true;
|
||||||
|
is_api_button_press_openai = true;
|
||||||
|
return await getStatusOpen();
|
||||||
|
}
|
||||||
|
|
||||||
const api_key_openai = $('#api_key_openai').val().trim();
|
const api_key_openai = $('#api_key_openai').val().trim();
|
||||||
|
|
||||||
if (api_key_openai.length) {
|
if (api_key_openai.length) {
|
||||||
@ -1386,6 +1480,15 @@ $(document).ready(function () {
|
|||||||
saveSettingsDebounced();
|
saveSettingsDebounced();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$('#use_window_ai').on('input', function() {
|
||||||
|
oai_settings.use_window_ai = !!$(this).prop('checked');
|
||||||
|
$('#openai_form').toggle(!oai_settings.use_window_ai);
|
||||||
|
setOnlineStatus('no_connection');
|
||||||
|
resultCheckStatusOpen();
|
||||||
|
$('#api_button_openai').trigger('click');
|
||||||
|
saveSettingsDebounced();
|
||||||
|
});
|
||||||
|
|
||||||
$("#api_button_openai").on("click", onConnectButtonClick);
|
$("#api_button_openai").on("click", onConnectButtonClick);
|
||||||
$("#openai_reverse_proxy").on("input", onReverseProxyInput);
|
$("#openai_reverse_proxy").on("input", onReverseProxyInput);
|
||||||
$("#model_openai_select").on("change", onModelChange);
|
$("#model_openai_select").on("change", onModelChange);
|
||||||
|
Reference in New Issue
Block a user