2023-07-20 19:32:15 +02:00
/ *
* CODE FOR OPENAI SUPPORT
* By CncAnon ( @ CncAnon1 )
* https : //github.com/CncAnon1/TavernAITurbo
* /
import {
saveSettingsDebounced ,
substituteParams ,
checkOnlineStatus ,
setOnlineStatus ,
getExtensionPrompt ,
name1 ,
name2 ,
extension _prompt _types ,
characters ,
this _chid ,
callPopup ,
getRequestHeaders ,
system _message _types ,
replaceBiasMarkup ,
is _send _press ,
2023-06-01 18:28:21 +02:00
saveSettings ,
2023-07-20 19:32:15 +02:00
main _api ,
} from "../script.js" ;
2023-05-28 15:55:03 +02:00
import { groups , selected _group } from "./group-chats.js" ;
import {
defaultPromptManagerSettings ,
openAiDefaultPromptLists ,
openAiDefaultPrompts ,
PromptManagerModule as PromptManager
} from "./PromptManager.js" ;
2023-07-20 19:32:15 +02:00
import {
power _user ,
} from "./power-user.js" ;
import {
SECRET _KEYS ,
secret _state ,
writeSecret ,
} from "./secrets.js" ;
import {
delay ,
download ,
getFileText ,
getStringHash ,
parseJsonFile ,
stringFormat ,
} from "./utils.js" ;
export {
is _get _status _openai ,
openai _msgs ,
openai _messages _count ,
oai _settings ,
loadOpenAISettings ,
setOpenAIMessages ,
setOpenAIMessageExamples ,
2023-05-28 15:55:03 +02:00
setupOpenAIPromptManager ,
2023-07-20 19:32:15 +02:00
generateOpenAIPromptCache ,
prepareOpenAIMessages ,
sendOpenAIRequest ,
setOpenAIOnlineStatus ,
getChatCompletionModel ,
2023-05-28 15:56:42 +02:00
countTokens
2023-07-20 19:32:15 +02:00
}
let openai _msgs = [ ] ;
let openai _msgs _example = [ ] ;
let openai _messages _count = 0 ;
let openai _narrator _messages _count = 0 ;
let is _get _status _openai = false ;
let is _api _button _press _openai = false ;
const default _impersonation _prompt = "[Write your next reply from the point of view of {{user}}, using the chat history so far as a guideline for the writing style of {{user}}. Write 1 reply only in internet RP style. Don't write as {{char}} or system. Don't describe actions of {{char}}.]" ;
const default _nsfw _avoidance _prompt = 'Avoid writing a NSFW/Smut reply. Creatively write around it NSFW/Smut scenarios in character.' ;
const default _wi _format = '[Details of the fictional world the RP is set in:\n{0}]\n' ;
const default _bias = 'Default (none)' ;
const default _bias _presets = {
[ default _bias ] : [ ] ,
'Anti-bond' : [
{ text : ' bond' , value : - 50 } ,
{ text : ' future' , value : - 50 } ,
{ text : ' bonding' , value : - 50 } ,
{ text : ' connection' , value : - 25 } ,
]
} ;
const max _2k = 2047 ;
const max _4k = 4095 ;
const max _8k = 8191 ;
const max _16k = 16383 ;
const max _32k = 32767 ;
const scale _max = 7900 ; // Probably more. Save some for the system prompt defined on Scale site.
const claude _max = 8000 ; // We have a proper tokenizer, so theoretically could be larger (up to 9k)
const palm2 _max = 7500 ; // The real context window is 8192, spare some for padding due to using turbo tokenizer
const claude _100k _max = 99000 ;
const unlocked _max = 100 * 1024 ;
const oai _max _temp = 2.0 ;
const claude _max _temp = 1.0 ;
const openrouter _website _model = 'OR_Website' ;
let biasCache = undefined ;
let model _list = [ ] ;
const tokenCache = { } ;
export const chat _completion _sources = {
OPENAI : 'openai' ,
WINDOWAI : 'windowai' ,
CLAUDE : 'claude' ,
SCALE : 'scale' ,
OPENROUTER : 'openrouter' ,
} ;
const default _settings = {
preset _settings _openai : 'Default' ,
temp _openai : 0.9 ,
freq _pen _openai : 0.7 ,
pres _pen _openai : 0.7 ,
top _p _openai : 1.0 ,
top _k _openai : 0 ,
stream _openai : false ,
openai _max _context : max _4k ,
openai _max _tokens : 300 ,
enhance _definitions : false ,
wrap _in _quotes : false ,
2023-05-28 15:53:59 +02:00
... openAiDefaultPrompts ,
... openAiDefaultPromptLists ,
... defaultPromptManagerSettings ,
2023-07-20 19:32:15 +02:00
send _if _empty : '' ,
impersonation _prompt : default _impersonation _prompt ,
bias _preset _selected : default _bias ,
bias _presets : default _bias _presets ,
wi _format : default _wi _format ,
openai _model : 'gpt-3.5-turbo' ,
claude _model : 'claude-instant-v1' ,
windowai _model : '' ,
openrouter _model : openrouter _website _model ,
jailbreak _system : false ,
reverse _proxy : '' ,
legacy _streaming : false ,
chat _completion _source : chat _completion _sources . OPENAI ,
max _context _unlocked : false ,
api _url _scale : '' ,
2023-07-21 12:35:39 +02:00
show _external _models : false ,
2023-07-28 20:33:29 +02:00
proxy _password : '' ,
2023-07-30 00:51:59 +02:00
assistant _prefill : '' ,
2023-07-20 19:32:15 +02:00
} ;
const oai _settings = {
preset _settings _openai : 'Default' ,
temp _openai : 1.0 ,
freq _pen _openai : 0 ,
pres _pen _openai : 0 ,
top _p _openai : 1.0 ,
top _k _openai : 0 ,
stream _openai : false ,
openai _max _context : max _4k ,
openai _max _tokens : 300 ,
enhance _definitions : false ,
wrap _in _quotes : false ,
2023-05-28 15:53:59 +02:00
... openAiDefaultPrompts ,
... openAiDefaultPromptLists ,
... defaultPromptManagerSettings ,
2023-07-20 19:32:15 +02:00
send _if _empty : '' ,
impersonation _prompt : default _impersonation _prompt ,
bias _preset _selected : default _bias ,
bias _presets : default _bias _presets ,
wi _format : default _wi _format ,
openai _model : 'gpt-3.5-turbo' ,
claude _model : 'claude-instant-v1' ,
windowai _model : '' ,
openrouter _model : openrouter _website _model ,
jailbreak _system : false ,
reverse _proxy : '' ,
legacy _streaming : false ,
chat _completion _source : chat _completion _sources . OPENAI ,
max _context _unlocked : false ,
api _url _scale : '' ,
2023-07-21 12:35:39 +02:00
show _external _models : false ,
2023-07-28 20:33:29 +02:00
proxy _password : '' ,
2023-07-30 00:51:59 +02:00
assistant _prefill : '' ,
2023-07-20 19:32:15 +02:00
} ;
let openai _setting _names ;
let openai _settings ;
export function getTokenCountOpenAI ( text ) {
const message = { role : 'system' , content : text } ;
return countTokens ( message , true ) ;
}
2023-05-28 15:55:03 +02:00
let promptManager = null ;
2023-07-20 19:32:15 +02:00
function validateReverseProxy ( ) {
if ( ! oai _settings . reverse _proxy ) {
return ;
}
try {
new URL ( oai _settings . reverse _proxy ) ;
}
catch ( err ) {
toastr . error ( 'Entered reverse proxy address is not a valid URL' ) ;
setOnlineStatus ( 'no_connection' ) ;
resultCheckStatusOpen ( ) ;
throw err ;
}
}
function setOpenAIOnlineStatus ( value ) {
is _get _status _openai = value ;
}
function setOpenAIMessages ( chat ) {
let j = 0 ;
// clean openai msgs
openai _msgs = [ ] ;
openai _narrator _messages _count = 0 ;
for ( let i = chat . length - 1 ; i >= 0 ; i -- ) {
let role = chat [ j ] [ 'is_user' ] ? 'user' : 'assistant' ;
let content = chat [ j ] [ 'mes' ] ;
// 100% legal way to send a message as system
if ( chat [ j ] . extra ? . type === system _message _types . NARRATOR ) {
role = 'system' ;
openai _narrator _messages _count ++ ;
}
// for groups or sendas command - prepend a character's name
if ( selected _group || ( chat [ j ] . force _avatar && chat [ j ] . name !== name1 && chat [ j ] . extra ? . type !== system _message _types . NARRATOR ) ) {
content = ` ${ chat [ j ] . name } : ${ content } ` ;
}
content = replaceBiasMarkup ( content ) ;
// remove caret return (waste of tokens)
content = content . replace ( /\r/gm , '' ) ;
// Apply the "wrap in quotes" option
if ( role == 'user' && oai _settings . wrap _in _quotes ) content = ` " ${ content } " ` ;
openai _msgs [ i ] = { "role" : role , "content" : content } ;
j ++ ;
}
// Add chat injections, 100 = maximum depth of injection. (Why would you ever need more?)
for ( let i = 0 ; i < 100 ; i ++ ) {
const anchor = getExtensionPrompt ( extension _prompt _types . IN _CHAT , i ) ;
if ( anchor && anchor . length ) {
openai _msgs . splice ( i , 0 , { "role" : 'system' , 'content' : anchor . trim ( ) } )
}
}
}
function setOpenAIMessageExamples ( mesExamplesArray ) {
// get a nice array of all blocks of all example messages = array of arrays (important!)
openai _msgs _example = [ ] ;
for ( let item of mesExamplesArray ) {
// remove <START> {Example Dialogue:} and replace \r\n with just \n
let replaced = item . replace ( /<START>/i , "{Example Dialogue:}" ) . replace ( /\r/gm , '' ) ;
let parsed = parseExampleIntoIndividual ( replaced ) ;
// add to the example message blocks array
openai _msgs _example . push ( parsed ) ;
}
}
2023-05-28 15:55:03 +02:00
function setupOpenAIPromptManager ( settings ) {
promptManager = new PromptManager ( ) ;
const configuration = {
prefix : 'openai_' ,
containerIdentifier : 'openai_prompt_manager' ,
listIdentifier : 'openai_prompt_manager_list' ,
draggable : true
} ;
promptManager . saveServiceSettings = ( ) => {
saveSettingsDebounced ( ) ;
}
promptManager . init ( configuration , settings , default _settings ) ;
promptManager . render ( ) ;
}
2023-07-20 19:32:15 +02:00
function generateOpenAIPromptCache ( ) {
openai _msgs = openai _msgs . reverse ( ) ;
openai _msgs . forEach ( function ( msg , i , arr ) {
let item = msg [ "content" ] ;
msg [ "content" ] = item ;
openai _msgs [ i ] = msg ;
} ) ;
}
function parseExampleIntoIndividual ( messageExampleString ) {
let result = [ ] ; // array of msgs
let tmp = messageExampleString . split ( "\n" ) ;
let cur _msg _lines = [ ] ;
let in _user = false ;
let in _bot = false ;
// DRY my cock and balls
function add _msg ( name , role , system _name ) {
// join different newlines (we split them by \n and join by \n)
// remove char name
// strip to remove extra spaces
let parsed _msg = cur _msg _lines . join ( "\n" ) . replace ( name + ":" , "" ) . trim ( ) ;
if ( selected _group && role == 'assistant' ) {
parsed _msg = ` ${ name } : ${ parsed _msg } ` ;
}
result . push ( { "role" : role , "content" : parsed _msg , "name" : system _name } ) ;
cur _msg _lines = [ ] ;
}
// skip first line as it'll always be "This is how {bot name} should talk"
for ( let i = 1 ; i < tmp . length ; i ++ ) {
let cur _str = tmp [ i ] ;
// if it's the user message, switch into user mode and out of bot mode
// yes, repeated code, but I don't care
if ( cur _str . startsWith ( name1 + ":" ) ) {
in _user = true ;
// we were in the bot mode previously, add the message
if ( in _bot ) {
add _msg ( name2 , "system" , "example_assistant" ) ;
}
in _bot = false ;
} else if ( cur _str . startsWith ( name2 + ":" ) ) {
in _bot = true ;
// we were in the user mode previously, add the message
if ( in _user ) {
add _msg ( name1 , "system" , "example_user" ) ;
}
in _user = false ;
}
// push the current line into the current message array only after checking for presence of user/bot
cur _msg _lines . push ( cur _str ) ;
}
// Special case for last message in a block because we don't have a new message to trigger the switch
if ( in _user ) {
add _msg ( name1 , "system" , "example_user" ) ;
} else if ( in _bot ) {
add _msg ( name2 , "system" , "example_assistant" ) ;
}
return result ;
}
function formatWorldInfo ( value ) {
if ( ! value ) {
return '' ;
}
if ( ! oai _settings . wi _format ) {
return value ;
}
return stringFormat ( oai _settings . wi _format , value ) ;
}
async function prepareOpenAIMessages ( { systemPrompt , name2 , storyString , worldInfoBefore , worldInfoAfter , extensionPrompt , bias , type , quietPrompt , jailbreakPrompt , cyclePrompt } = { } ) {
2023-06-01 18:55:20 +02:00
const chatCompletion = promptManager . getChatCompletion ( ) ;
2023-07-20 19:32:15 +02:00
2023-06-01 18:55:20 +02:00
// Prepare messages
const enhanceDefinitionMessage = chatCompletion . makeSystemMessage ( substituteParams ( 'If you have more knowledge of {{char}}, add to the character\'s lore and personality to enhance them but keep the Character Sheet\'s definitions absolute.' ) ) ;
const worldInfoBeforeMessage = chatCompletion . makeSystemMessage ( formatWorldInfo ( worldInfoBefore ) ) ;
const worldInfoAfterMessage = chatCompletion . makeSystemMessage ( formatWorldInfo ( worldInfoAfter ) ) ;
const characterInfoMessages = chatCompletion . makeSystemMessage ( substituteParams ( storyString ) ) ;
const newChatMessage = chatCompletion . makeSystemMessage ( '[Start new chat]' ) ;
const chatMessages = openai _msgs ;
const biasMessage = chatCompletion . makeSystemMessage ( bias . trim ( ) ) ;
// Prepare context
chatCompletion
. replace ( 'worldInfoBefore' , worldInfoBeforeMessage )
. replace ( 'worldInfoAfter' , worldInfoAfterMessage )
. replace ( 'characterInfo' , characterInfoMessages )
. replace ( 'newExampleChat' , newChatMessage )
. replace ( 'newMainChat' , newChatMessage )
. replace ( 'chatHistory' , chatMessages )
// Hande group chats
if ( selected _group ) {
const names = getGroupMembers ( groups ) ;
const groupChatMessage = chatCompletion . makeSystemMessage ( ` [Start a new group chat. Group members: ${ names } ] ` ) ;
const groupNudgeMessage = chatCompletion . makeSystemMessage ( ` [Write the next reply only as ${ name2 } ] ` ) ;
chatCompletion . replace ( 'newMainChat' , groupChatMessage )
chatCompletion . insertAfter ( 'newMainChat' , 'groupNudgeMessage' , groupNudgeMessage ) ;
2023-07-20 19:32:15 +02:00
}
2023-06-01 19:10:18 +02:00
// Handle enhanced definitions
2023-06-01 18:55:20 +02:00
if ( oai _settings . enhance _definitions ) chatCompletion . insertAfter ( 'characterInfo' , 'enhancedDefinitions' , enhanceDefinitionMessage ) ;
2023-06-01 19:10:18 +02:00
// Handle extension prompt
2023-06-01 18:55:20 +02:00
if ( extensionPrompt ) chatCompletion . insertAfter ( 'worldInfoAfter' , 'extensionPrompt' , extensionPrompt ) ;
2023-06-01 19:10:18 +02:00
// Handle bias settings
2023-06-01 18:55:20 +02:00
if ( bias && bias . trim ( ) . length ) chatCompletion . add ( biasMessage ) ;
2023-05-28 15:55:52 +02:00
2023-06-02 19:14:00 +02:00
// Handle impersonation
if ( type === "impersonate" ) chatCompletion . replace ( 'main' , substituteParams ( oai _settings . impersonation _prompt ) ) ;
2023-06-01 19:10:18 +02:00
// Handle chat examples
2023-06-01 18:55:20 +02:00
const exampleMessages = prepareExampleMessages ( openai _msgs , openai _msgs _example , power _user . pin _examples ) ;
if ( exampleMessages . length ) chatCompletion . replace ( 'dialogueExamples' , exampleMessages ) ;
2023-07-20 19:32:15 +02:00
2023-06-01 19:10:18 +02:00
// Handle quiet prompt
if ( quietPrompt ) {
const quietPromptMessage = chatCompletion . makeSystemMessage ( quietPrompt ) ;
chatCompletion . insertAfter ( 'main' , quietPromptMessage )
}
2023-06-01 18:55:20 +02:00
promptManager . updatePrompts ( chatCompletion . getPromptsWithTokenCount ( ) ) ;
2023-07-20 19:32:15 +02:00
2023-06-01 18:55:20 +02:00
// Save settings with updated token calculation and return context
return promptManager . saveServiceSettings ( ) . then ( ( ) => {
promptManager . render ( ) ;
2023-07-20 19:32:15 +02:00
2023-06-01 18:55:20 +02:00
const openai _msgs _tosend = chatCompletion . getChat ( ) ;
openai _messages _count = openai _msgs _tosend . filter ( x => x . role === "user" || x . role === "assistant" ) . length ;
2023-07-20 19:32:15 +02:00
2023-06-01 18:55:20 +02:00
console . log ( openai _msgs _tosend ) ;
2023-07-20 19:32:15 +02:00
2023-06-02 19:14:29 +02:00
return [ openai _msgs _tosend , false ] ;
2023-06-01 18:55:20 +02:00
} ) ;
}
2023-07-20 19:32:15 +02:00
2023-06-01 18:55:20 +02:00
function getGroupMembers ( activeGroup ) {
const groupMembers = activeGroup . find ( x => x . id === selected _group ) ? . members ;
let names = '' ;
if ( Array . isArray ( groupMembers ) ) {
names = groupMembers . map ( member => characters . find ( c => c . avatar === member ) ) . filter ( x => x ) . map ( x => x . name ) ;
names = names . join ( ', ' )
}
2023-07-20 19:32:15 +02:00
// recount tokens for new start message
total _count -= start _chat _count
handler _instance . uncount ( start _chat _count , 'start_chat' ) ;
start _chat _count = handler _instance . count ( [ new _chat _msg ] , true ) ;
await delay ( 1 ) ;
total _count += start _chat _count ;
}
const jailbreak = power _user . prefer _character _jailbreak && jailbreakPrompt ? jailbreakPrompt : oai _settings . jailbreak _prompt ;
if ( oai _settings . jailbreak _system && jailbreak ) {
2023-07-22 15:50:34 +02:00
const jbContent = substituteParams ( jailbreak , name1 , name2 , oai _settings . jailbreak _prompt ) . replace ( /\r/gm , '' ) . trim ( ) ;
const jailbreakMessage = { "role" : "system" , "content" : jbContent } ;
2023-07-20 19:32:15 +02:00
openai _msgs . push ( jailbreakMessage ) ;
2023-05-28 15:57:47 +02:00
total _count += handler _instance . count ( [ impersonateMessage ] , true , 'impersonate' ) ;
2023-07-20 19:32:15 +02:00
await delay ( 1 ) ;
}
if ( quietPrompt ) {
const quietPromptMessage = { role : 'system' , content : quietPrompt } ;
total _count += handler _instance . count ( [ quietPromptMessage ] , true , 'quiet' ) ;
openai _msgs . push ( quietPromptMessage ) ;
}
if ( isImpersonate ) {
const impersonateMessage = { "role" : "system" , "content" : substituteParams ( oai _settings . impersonation _prompt ) } ;
openai _msgs . push ( impersonateMessage ) ;
total _count += handler _instance . count ( [ impersonateMessage ] , true , 'impersonate' ) ;
await delay ( 1 ) ;
}
if ( type == 'continue' ) {
const continueNudge = { "role" : "system" , "content" : stringFormat ( '[Continue the following message. Do not include ANY parts of the original message. Use capitalization and punctuation as if your reply is a part of the original message:\n\n{0}]' , cyclePrompt || '' ) } ;
openai _msgs . push ( continueNudge ) ;
total _count += handler _instance . count ( [ continueNudge ] , true , 'continue' ) ;
await delay ( 1 ) ;
}
2023-06-01 18:55:20 +02:00
function prepareExampleMessages ( messages , exampleMessages , includeAll = false , ) {
2023-07-20 19:32:15 +02:00
// The user wants to always have all example messages in the context
2023-06-01 18:55:20 +02:00
let examples _tosend = [ ] ;
let total _count = 0 ;
const new _chat _msg = { role : 'system' , content : '[Start new chat]' }
if ( includeAll ) {
2023-07-20 19:32:15 +02:00
// first we send *all* example messages
// we don't check their token size since if it's bigger than the context, the user is fucked anyway
// and should've have selected that option (maybe have some warning idk, too hard to add)
2023-06-01 18:55:20 +02:00
for ( const element of exampleMessages ) {
2023-07-20 19:32:15 +02:00
// get the current example block with multiple user/bot messages
let example _block = element ;
for ( const example of example _block ) {
// add all the messages from the example
examples _tosend . push ( example ) ;
}
}
2023-06-01 18:55:20 +02:00
2023-07-20 19:32:15 +02:00
// go from newest message to oldest, because we want to delete the older ones from the context
2023-06-01 18:55:20 +02:00
for ( let j = messages . length - 1 ; j >= 0 ; j -- ) {
let item = messages [ j ] ;
2023-06-02 19:14:29 +02:00
let item _count = countTokens ( item ) ;
2023-07-20 19:32:15 +02:00
// If we have enough space for this message, also account for the max assistant reply size
2023-06-01 18:55:20 +02:00
if ( ( total _count + item _count ) < ( oai _settings . openai _max _context - oai _settings . openai _max _tokens ) ) {
messages . push ( item ) ;
} else {
2023-07-20 19:32:15 +02:00
// early break since if we still have more messages, they just won't fit anyway
break ;
}
}
} else {
2023-06-01 18:55:20 +02:00
for ( let j = messages . length - 1 ; j >= 0 ; j -- ) {
let item = messages [ j ] ;
2023-06-02 19:14:29 +02:00
let item _count = countTokens ( item ) ;
2023-07-20 19:32:15 +02:00
// If we have enough space for this message, also account for the max assistant reply size
2023-06-01 18:55:20 +02:00
if ( ( total _count + item _count ) < ( oai _settings . openai _max _context - oai _settings . openai _max _tokens ) ) {
messages . push ( item ) ;
} else {
2023-07-20 19:32:15 +02:00
// early break since if we still have more messages, they just won't fit anyway
break ;
}
}
// each example block contains multiple user/bot messages
2023-06-01 18:55:20 +02:00
for ( let example _block of exampleMessages ) {
if ( example _block . length == 0 ) {
continue ;
}
2023-07-20 19:32:15 +02:00
// add the block only if there is enough space for all its messages
2023-06-02 19:14:29 +02:00
const example _count = countTokens ( example _block )
2023-06-01 18:55:20 +02:00
if ( ( total _count + example _count ) < ( oai _settings . openai _max _context - oai _settings . openai _max _tokens ) ) {
2023-07-20 19:32:15 +02:00
examples _tosend . push ( ... example _block )
2023-06-01 18:55:20 +02:00
} else {
2023-07-20 19:32:15 +02:00
// early break since more examples probably won't fit anyway
break ;
}
}
}
2023-06-01 18:55:20 +02:00
return examples _tosend ;
2023-07-20 19:32:15 +02:00
}
function tryParseStreamingError ( response , decoded ) {
try {
const data = JSON . parse ( decoded ) ;
if ( ! data ) {
return ;
}
checkQuotaError ( data ) ;
if ( data . error ) {
toastr . error ( data . error . message || response . statusText , 'API returned an error' ) ;
throw new Error ( data ) ;
}
}
catch {
// No JSON. Do nothing.
}
}
function checkQuotaError ( data ) {
const errorText = ` <h3>Encountered an error while processing your request.<br>
Check you have credits available on your
< a href = "https://platform.openai.com/account/usage" target = "_blank" > OpenAI account < / a > . < b r >
If you have sufficient credits , please try again later . < / h 3 > ` ;
if ( ! data ) {
return ;
}
if ( data . quota _error ) {
callPopup ( errorText , 'text' ) ;
throw new Error ( data ) ;
}
}
async function sendWindowAIRequest ( openai _msgs _tosend , signal , stream ) {
if ( ! ( 'ai' in window ) ) {
return showWindowExtensionError ( ) ;
}
let content = '' ;
let lastContent = '' ;
let finished = false ;
const currentModel = await window . ai . getCurrentModel ( ) ;
let temperature = parseFloat ( oai _settings . temp _openai ) ;
if ( ( currentModel . includes ( 'claude' ) || currentModel . includes ( 'palm-2' ) ) && temperature > claude _max _temp ) {
console . warn ( ` Claude and PaLM models only supports temperature up to ${ claude _max _temp } . Clamping ${ temperature } to ${ claude _max _temp } . ` ) ;
temperature = claude _max _temp ;
}
async function * windowStreamingFunction ( ) {
while ( true ) {
if ( signal . aborted ) {
return ;
}
// unhang UI thread
await delay ( 1 ) ;
if ( lastContent !== content ) {
yield content ;
}
lastContent = content ;
if ( finished ) {
return ;
}
}
}
const onStreamResult = ( res , err ) => {
if ( err ) {
return ;
}
const thisContent = res ? . message ? . content ;
if ( res ? . isPartial ) {
content += thisContent ;
}
else {
content = thisContent ;
}
}
const generatePromise = window . ai . generateText (
{
messages : openai _msgs _tosend ,
} ,
{
temperature : temperature ,
maxTokens : oai _settings . openai _max _tokens ,
model : oai _settings . windowai _model || null ,
onStreamResult : onStreamResult ,
}
) ;
const handleGeneratePromise = ( resolve , reject ) => {
generatePromise
. then ( ( res ) => {
content = res [ 0 ] ? . message ? . content ;
finished = true ;
resolve && resolve ( content ) ;
} )
. catch ( ( err ) => {
finished = true ;
reject && reject ( err ) ;
handleWindowError ( err ) ;
} ) ;
} ;
if ( stream ) {
handleGeneratePromise ( ) ;
return windowStreamingFunction ;
} else {
return new Promise ( ( resolve , reject ) => {
signal . addEventListener ( 'abort' , ( reason ) => {
reject ( reason ) ;
} ) ;
handleGeneratePromise ( resolve , reject ) ;
} ) ;
}
}
function getChatCompletionModel ( ) {
switch ( oai _settings . chat _completion _source ) {
case chat _completion _sources . CLAUDE :
return oai _settings . claude _model ;
case chat _completion _sources . OPENAI :
return oai _settings . openai _model ;
case chat _completion _sources . WINDOWAI :
return oai _settings . windowai _model ;
case chat _completion _sources . SCALE :
return '' ;
case chat _completion _sources . OPENROUTER :
return oai _settings . openrouter _model !== openrouter _website _model ? oai _settings . openrouter _model : null ;
default :
throw new Error ( ` Unknown chat completion source: ${ oai _settings . chat _completion _source } ` ) ;
}
}
2023-08-09 20:59:34 +02:00
function calculateOpenRouterCost ( ) {
if ( oai _settings . chat _completion _source !== chat _completion _sources . OPENROUTER ) {
return ;
}
let cost = 'Unknown' ;
const model = model _list . find ( x => x . id === oai _settings . openrouter _model ) ;
if ( model ? . pricing ) {
const completionCost = Number ( model . pricing . completion ) ;
const promptCost = Number ( model . pricing . prompt ) ;
const completionTokens = oai _settings . openai _max _tokens ;
const promptTokens = ( oai _settings . openai _max _context - completionTokens ) ;
const totalCost = ( completionCost * completionTokens ) + ( promptCost * promptTokens ) ;
if ( ! isNaN ( totalCost ) ) {
2023-08-10 12:01:55 +02:00
cost = '$' + totalCost . toFixed ( 3 ) ;
2023-08-09 20:59:34 +02:00
}
}
$ ( '#openrouter_max_prompt_cost' ) . text ( cost ) ;
}
2023-07-20 19:32:15 +02:00
function saveModelList ( data ) {
2023-08-09 20:59:34 +02:00
model _list = data . map ( ( model ) => ( { id : model . id , context _length : model . context _length , pricing : model . pricing } ) ) ;
2023-07-21 12:35:39 +02:00
model _list . sort ( ( a , b ) => a ? . id && b ? . id && a . id . localeCompare ( b . id ) ) ;
2023-07-20 19:32:15 +02:00
if ( oai _settings . chat _completion _source == chat _completion _sources . OPENROUTER ) {
$ ( '#model_openrouter_select' ) . empty ( ) ;
$ ( '#model_openrouter_select' ) . append ( $ ( '<option>' , { value : openrouter _website _model , text : 'Use OpenRouter website setting' } ) ) ;
model _list . forEach ( ( model ) => {
2023-08-10 21:13:24 +02:00
let tokens _dollar = parseFloat ( 1 / ( 1000 * model . pricing . prompt ) ) ;
let tokens _rounded = ( Math . round ( tokens _dollar * 1000 ) / 1000 ) . toFixed ( 0 ) ;
let model _description = ` ${ model . id } | ${ tokens _rounded } k t/ $ | ${ model . context _length } ctx ` ;
2023-07-20 19:32:15 +02:00
$ ( '#model_openrouter_select' ) . append (
$ ( '<option>' , {
value : model . id ,
2023-08-10 06:11:03 +02:00
text : model _description ,
2023-07-20 19:32:15 +02:00
} ) ) ;
} ) ;
$ ( '#model_openrouter_select' ) . val ( oai _settings . openrouter _model ) . trigger ( 'change' ) ;
}
2023-07-21 12:35:39 +02:00
if ( oai _settings . chat _completion _source == chat _completion _sources . OPENAI ) {
$ ( '#openai_external_category' ) . empty ( ) ;
model _list . forEach ( ( model ) => {
$ ( '#openai_external_category' ) . append (
$ ( '<option>' , {
value : model . id ,
text : model . id ,
} ) ) ;
} ) ;
// If the selected model is not in the list, revert to default
2023-07-21 22:40:12 +02:00
if ( oai _settings . show _external _models ) {
const model = model _list . findIndex ( ( model ) => model . id == oai _settings . openai _model ) !== - 1 ? oai _settings . openai _model : default _settings . openai _model ;
$ ( '#model_openai_select' ) . val ( model ) . trigger ( 'change' ) ;
2023-07-21 12:35:39 +02:00
}
}
2023-07-20 19:32:15 +02:00
}
async function sendOpenAIRequest ( type , openai _msgs _tosend , signal ) {
// Provide default abort signal
if ( ! signal ) {
signal = new AbortController ( ) . signal ;
}
let logit _bias = { } ;
const isClaude = oai _settings . chat _completion _source == chat _completion _sources . CLAUDE ;
const isOpenRouter = oai _settings . chat _completion _source == chat _completion _sources . OPENROUTER ;
const isScale = oai _settings . chat _completion _source == chat _completion _sources . SCALE ;
const isTextCompletion = oai _settings . chat _completion _source == chat _completion _sources . OPENAI && ( oai _settings . openai _model . startsWith ( 'text-' ) || oai _settings . openai _model . startsWith ( 'code-' ) ) ;
const stream = type !== 'quiet' && oai _settings . stream _openai && ! isScale ;
2023-08-11 16:23:03 +02:00
const isQuiet = type === 'quiet' ;
2023-07-20 19:32:15 +02:00
// If we're using the window.ai extension, use that instead
// Doesn't support logit bias yet
if ( oai _settings . chat _completion _source == chat _completion _sources . WINDOWAI ) {
return sendWindowAIRequest ( openai _msgs _tosend , signal , stream ) ;
}
const logitBiasSources = [ chat _completion _sources . OPENAI , chat _completion _sources . OPENROUTER ] ;
if ( oai _settings . bias _preset _selected
&& logitBiasSources . includes ( oai _settings . chat _completion _source )
&& Array . isArray ( oai _settings . bias _presets [ oai _settings . bias _preset _selected ] )
&& oai _settings . bias _presets [ oai _settings . bias _preset _selected ] . length ) {
logit _bias = biasCache || await calculateLogitBias ( ) ;
biasCache = logit _bias ;
}
const model = getChatCompletionModel ( ) ;
const generate _data = {
"messages" : openai _msgs _tosend ,
"model" : model ,
"temperature" : parseFloat ( oai _settings . temp _openai ) ,
"frequency_penalty" : parseFloat ( oai _settings . freq _pen _openai ) ,
"presence_penalty" : parseFloat ( oai _settings . pres _pen _openai ) ,
"top_p" : parseFloat ( oai _settings . top _p _openai ) ,
"max_tokens" : oai _settings . openai _max _tokens ,
"stream" : stream ,
"logit_bias" : logit _bias ,
} ;
// 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 ) ) {
validateReverseProxy ( ) ;
generate _data [ 'reverse_proxy' ] = oai _settings . reverse _proxy ;
2023-07-28 20:33:29 +02:00
generate _data [ 'proxy_password' ] = oai _settings . proxy _password ;
2023-07-20 19:32:15 +02:00
}
if ( isClaude ) {
generate _data [ 'use_claude' ] = true ;
generate _data [ 'top_k' ] = parseFloat ( oai _settings . top _k _openai ) ;
2023-08-11 16:23:03 +02:00
// Don't add a prefill on quiet gens (summarization)
if ( ! isQuiet ) {
generate _data [ 'assistant_prefill' ] = substituteParams ( oai _settings . assistant _prefill ) ;
}
2023-07-20 19:32:15 +02:00
}
if ( isOpenRouter ) {
generate _data [ 'use_openrouter' ] = true ;
generate _data [ 'top_k' ] = parseFloat ( oai _settings . top _k _openai ) ;
}
if ( isScale ) {
generate _data [ 'use_scale' ] = true ;
generate _data [ 'api_url_scale' ] = oai _settings . api _url _scale ;
}
const generate _url = '/generate_openai' ;
const response = await fetch ( generate _url , {
method : 'POST' ,
body : JSON . stringify ( generate _data ) ,
headers : getRequestHeaders ( ) ,
signal : signal ,
} ) ;
if ( stream ) {
return async function * streamData ( ) {
const decoder = new TextDecoder ( ) ;
const reader = response . body . getReader ( ) ;
let getMessage = "" ;
let messageBuffer = "" ;
while ( true ) {
const { done , value } = await reader . read ( ) ;
let decoded = decoder . decode ( value ) ;
// Claude's streaming SSE messages are separated by \r
if ( oai _settings . chat _completion _source == chat _completion _sources . CLAUDE ) {
decoded = decoded . replace ( /\r/g , "" ) ;
}
tryParseStreamingError ( response , decoded ) ;
let eventList = [ ] ;
// ReadableStream's buffer is not guaranteed to contain full SSE messages as they arrive in chunks
// We need to buffer chunks until we have one or more full messages (separated by double newlines)
if ( ! oai _settings . legacy _streaming ) {
messageBuffer += decoded ;
eventList = messageBuffer . split ( "\n\n" ) ;
// Last element will be an empty string or a leftover partial message
messageBuffer = eventList . pop ( ) ;
} else {
eventList = decoded . split ( "\n" ) ;
}
for ( let event of eventList ) {
if ( event . startsWith ( 'event: completion' ) ) {
event = event . split ( "\n" ) [ 1 ] ;
}
if ( typeof event !== 'string' || ! event . length )
continue ;
if ( ! event . startsWith ( "data" ) )
continue ;
if ( event == "data: [DONE]" ) {
return ;
}
let data = JSON . parse ( event . substring ( 6 ) ) ;
// the first and last messages are undefined, protect against that
getMessage = getStreamingReply ( getMessage , data ) ;
yield getMessage ;
}
if ( done ) {
return ;
}
}
}
}
else {
const data = await response . json ( ) ;
checkQuotaError ( data ) ;
if ( data . error ) {
toastr . error ( data . error . message || response . statusText , 'API returned an error' ) ;
throw new Error ( data ) ;
}
return ! isTextCompletion ? data . choices [ 0 ] [ "message" ] [ "content" ] : data . choices [ 0 ] [ "text" ] ;
}
}
function getStreamingReply ( getMessage , data ) {
if ( oai _settings . chat _completion _source == chat _completion _sources . CLAUDE ) {
getMessage += data ? . completion || "" ;
} else {
getMessage += data . choices [ 0 ] ? . delta ? . content || data . choices [ 0 ] ? . message ? . content || data . choices [ 0 ] ? . text || "" ;
}
return getMessage ;
}
function handleWindowError ( err ) {
const text = parseWindowError ( err ) ;
toastr . error ( text , 'Window.ai returned an error' ) ;
throw err ;
}
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 ( ) {
const body = JSON . stringify ( oai _settings . bias _presets [ oai _settings . bias _preset _selected ] ) ;
let result = { } ;
try {
const reply = await fetch ( ` /openai_bias?model= ${ oai _settings . openai _model } ` , {
method : 'POST' ,
headers : getRequestHeaders ( ) ,
body ,
} ) ;
result = await reply . json ( ) ;
}
catch ( err ) {
result = { } ;
console . error ( err ) ;
}
finally {
return result ;
}
}
class TokenHandler {
constructor ( countTokenFn ) {
this . countTokenFn = countTokenFn ;
this . counts = {
'start_chat' : 0 ,
'prompt' : 0 ,
'bias' : 0 ,
'nudge' : 0 ,
'jailbreak' : 0 ,
'impersonate' : 0 ,
'examples' : 0 ,
'conversation' : 0 ,
} ;
}
uncount ( value , type ) {
this . counts [ type ] -= value ;
}
count ( messages , full , type ) {
//console.log(messages);
const token _count = this . countTokenFn ( messages , full ) ;
this . counts [ type ] += token _count ;
return token _count ;
}
log ( ) {
const total = Object . values ( this . counts ) . reduce ( ( a , b ) => a + b ) ;
console . table ( { ... this . counts , 'total' : total } ) ;
}
}
function countTokens ( messages , full = false ) {
let chatId = 'undefined' ;
try {
if ( selected _group ) {
chatId = groups . find ( x => x . id == selected _group ) ? . chat _id ;
}
else if ( this _chid ) {
chatId = characters [ this _chid ] . chat ;
}
} catch {
console . log ( 'No character / group selected. Using default cache item' ) ;
}
if ( typeof tokenCache [ chatId ] !== 'object' ) {
tokenCache [ chatId ] = { } ;
}
if ( ! Array . isArray ( messages ) ) {
messages = [ messages ] ;
}
let token _count = - 1 ;
for ( const message of messages ) {
const hash = getStringHash ( message . content ) ;
const cachedCount = tokenCache [ chatId ] [ hash ] ;
if ( cachedCount ) {
token _count += cachedCount ;
}
else {
let model = getTokenizerModel ( ) ;
jQuery . ajax ( {
async : false ,
type : 'POST' , //
url : ` /tokenize_openai?model= ${ model } ` ,
data : JSON . stringify ( [ message ] ) ,
dataType : "json" ,
contentType : "application/json" ,
success : function ( data ) {
token _count += data . token _count ;
tokenCache [ chatId ] [ hash ] = data . token _count ;
}
} ) ;
}
}
if ( ! full ) token _count -= 2 ;
return token _count ;
}
export function getTokenizerModel ( ) {
// OpenAI models always provide their own tokenizer
if ( oai _settings . chat _completion _source == chat _completion _sources . OPENAI ) {
return oai _settings . openai _model ;
}
const turboTokenizer = 'gpt-3.5-turbo' ;
const gpt4Tokenizer = 'gpt-4' ;
const gpt2Tokenizer = 'gpt2' ;
const claudeTokenizer = 'claude' ;
// Assuming no one would use it for different models.. right?
if ( oai _settings . chat _completion _source == chat _completion _sources . SCALE ) {
return gpt4Tokenizer ;
}
// Select correct tokenizer for WindowAI proxies
if ( oai _settings . chat _completion _source == chat _completion _sources . WINDOWAI && oai _settings . windowai _model ) {
if ( oai _settings . windowai _model . includes ( 'gpt-4' ) ) {
return gpt4Tokenizer ;
}
else if ( oai _settings . windowai _model . includes ( 'gpt-3.5-turbo' ) ) {
return turboTokenizer ;
}
else if ( oai _settings . windowai _model . includes ( 'claude' ) ) {
return claudeTokenizer ;
}
else if ( oai _settings . windowai _model . includes ( 'GPT-NeoXT' ) ) {
return gpt2Tokenizer ;
}
}
// And for OpenRouter (if not a site model, then it's impossible to determine the tokenizer)
if ( oai _settings . chat _completion _source == chat _completion _sources . OPENROUTER && oai _settings . openrouter _model ) {
if ( oai _settings . openrouter _model . includes ( 'gpt-4' ) ) {
return gpt4Tokenizer ;
}
else if ( oai _settings . openrouter _model . includes ( 'gpt-3.5-turbo' ) ) {
return turboTokenizer ;
}
else if ( oai _settings . openrouter _model . includes ( 'claude' ) ) {
return claudeTokenizer ;
}
else if ( oai _settings . openrouter _model . includes ( 'GPT-NeoXT' ) ) {
return gpt2Tokenizer ;
}
}
if ( oai _settings . chat _completion _source == chat _completion _sources . CLAUDE ) {
return claudeTokenizer ;
}
// Default to Turbo 3.5
return turboTokenizer ;
}
function loadOpenAISettings ( data , settings ) {
openai _setting _names = data . openai _setting _names ;
openai _settings = data . openai _settings ;
openai _settings . forEach ( function ( item , i , arr ) {
openai _settings [ i ] = JSON . parse ( item ) ;
} ) ;
$ ( "#settings_perset_openai" ) . empty ( ) ;
let arr _holder = { } ;
openai _setting _names . forEach ( function ( item , i , arr ) {
arr _holder [ item ] = i ;
$ ( '#settings_perset_openai' ) . append ( ` <option value= ${ i } > ${ item } </option> ` ) ;
} ) ;
openai _setting _names = arr _holder ;
oai _settings . preset _settings _openai = settings . preset _settings _openai ;
$ ( ` #settings_perset_openai option[value= ${ openai _setting _names [ oai _settings . preset _settings _openai ] } ] ` ) . attr ( 'selected' , true ) ;
oai _settings . temp _openai = settings . temp _openai ? ? default _settings . temp _openai ;
oai _settings . freq _pen _openai = settings . freq _pen _openai ? ? default _settings . freq _pen _openai ;
oai _settings . pres _pen _openai = settings . pres _pen _openai ? ? default _settings . pres _pen _openai ;
oai _settings . top _p _openai = settings . top _p _openai ? ? default _settings . top _p _openai ;
oai _settings . top _k _openai = settings . top _k _openai ? ? default _settings . top _k _openai ;
oai _settings . stream _openai = settings . stream _openai ? ? default _settings . stream _openai ;
oai _settings . openai _max _context = settings . openai _max _context ? ? default _settings . openai _max _context ;
oai _settings . openai _max _tokens = settings . openai _max _tokens ? ? default _settings . openai _max _tokens ;
oai _settings . bias _preset _selected = settings . bias _preset _selected ? ? default _settings . bias _preset _selected ;
oai _settings . bias _presets = settings . bias _presets ? ? default _settings . bias _presets ;
oai _settings . legacy _streaming = settings . legacy _streaming ? ? default _settings . legacy _streaming ;
oai _settings . max _context _unlocked = settings . max _context _unlocked ? ? default _settings . max _context _unlocked ;
oai _settings . nsfw _avoidance _prompt = settings . nsfw _avoidance _prompt ? ? default _settings . nsfw _avoidance _prompt ;
oai _settings . send _if _empty = settings . send _if _empty ? ? default _settings . send _if _empty ;
oai _settings . wi _format = settings . wi _format ? ? default _settings . wi _format ;
oai _settings . claude _model = settings . claude _model ? ? default _settings . claude _model ;
oai _settings . windowai _model = settings . windowai _model ? ? default _settings . windowai _model ;
oai _settings . openrouter _model = settings . openrouter _model ? ? default _settings . openrouter _model ;
oai _settings . chat _completion _source = settings . chat _completion _source ? ? default _settings . chat _completion _source ;
oai _settings . api _url _scale = settings . api _url _scale ? ? default _settings . api _url _scale ;
2023-07-21 12:35:39 +02:00
oai _settings . show _external _models = settings . show _external _models ? ? default _settings . show _external _models ;
2023-07-28 20:33:29 +02:00
oai _settings . proxy _password = settings . proxy _password ? ? default _settings . proxy _password ;
2023-07-30 00:51:59 +02:00
oai _settings . assistant _prefill = settings . assistant _prefill ? ? default _settings . assistant _prefill ;
2023-07-20 19:32:15 +02:00
2023-06-01 18:55:20 +02:00
oai _settings . prompts = settings . prompts ? ? [ ]
2023-05-28 15:58:12 +02:00
oai _settings . prompt _lists = settings . prompt _lists ? ? [ ] ;
oai _settings . prompt _manager _settings = settings . prompt _manager _settings ? ? [ ] ;
2023-07-20 19:32:15 +02:00
if ( settings . nsfw _toggle !== undefined ) oai _settings . nsfw _toggle = ! ! settings . nsfw _toggle ;
if ( settings . keep _example _dialogue !== undefined ) oai _settings . keep _example _dialogue = ! ! settings . keep _example _dialogue ;
if ( settings . enhance _definitions !== undefined ) oai _settings . enhance _definitions = ! ! settings . enhance _definitions ;
if ( settings . wrap _in _quotes !== undefined ) oai _settings . wrap _in _quotes = ! ! settings . wrap _in _quotes ;
if ( settings . nsfw _first !== undefined ) oai _settings . nsfw _first = ! ! settings . nsfw _first ;
if ( settings . openai _model !== undefined ) oai _settings . openai _model = settings . openai _model ;
if ( settings . jailbreak _system !== undefined ) oai _settings . jailbreak _system = ! ! settings . jailbreak _system ;
$ ( '#stream_toggle' ) . prop ( 'checked' , oai _settings . stream _openai ) ;
$ ( '#api_url_scale' ) . val ( oai _settings . api _url _scale ) ;
2023-07-28 20:33:29 +02:00
$ ( '#openai_proxy_password' ) . val ( oai _settings . proxy _password ) ;
2023-07-30 00:51:59 +02:00
$ ( '#claude_assistant_prefill' ) . val ( oai _settings . assistant _prefill ) ;
2023-07-20 19:32:15 +02:00
$ ( '#model_openai_select' ) . val ( oai _settings . openai _model ) ;
$ ( ` #model_openai_select option[value=" ${ oai _settings . openai _model } " ` ) . attr ( 'selected' , true ) ;
$ ( '#model_claude_select' ) . val ( oai _settings . claude _model ) ;
$ ( ` #model_claude_select option[value=" ${ oai _settings . claude _model } " ` ) . attr ( 'selected' , true ) ;
$ ( '#model_windowai_select' ) . val ( oai _settings . windowai _model ) ;
$ ( ` #model_windowai_select option[value=" ${ oai _settings . windowai _model } " ` ) . attr ( 'selected' , true ) ;
$ ( '#openai_max_context' ) . val ( oai _settings . openai _max _context ) ;
$ ( '#openai_max_context_counter' ) . text ( ` ${ oai _settings . openai _max _context } ` ) ;
$ ( '#model_openrouter_select' ) . val ( oai _settings . openrouter _model ) ;
$ ( '#openai_max_tokens' ) . val ( oai _settings . openai _max _tokens ) ;
$ ( '#nsfw_toggle' ) . prop ( 'checked' , oai _settings . nsfw _toggle ) ;
$ ( '#keep_example_dialogue' ) . prop ( 'checked' , oai _settings . keep _example _dialogue ) ;
$ ( '#enhance_definitions' ) . prop ( 'checked' , oai _settings . enhance _definitions ) ;
$ ( '#wrap_in_quotes' ) . prop ( 'checked' , oai _settings . wrap _in _quotes ) ;
$ ( '#nsfw_first' ) . prop ( 'checked' , oai _settings . nsfw _first ) ;
$ ( '#jailbreak_system' ) . prop ( 'checked' , oai _settings . jailbreak _system ) ;
$ ( '#legacy_streaming' ) . prop ( 'checked' , oai _settings . legacy _streaming ) ;
2023-07-21 12:35:39 +02:00
$ ( '#openai_show_external_models' ) . prop ( 'checked' , oai _settings . show _external _models ) ;
$ ( '#openai_external_category' ) . toggle ( oai _settings . show _external _models ) ;
2023-07-20 19:32:15 +02:00
if ( settings . main _prompt !== undefined ) oai _settings . main _prompt = settings . main _prompt ;
if ( settings . nsfw _prompt !== undefined ) oai _settings . nsfw _prompt = settings . nsfw _prompt ;
if ( settings . jailbreak _prompt !== undefined ) oai _settings . jailbreak _prompt = settings . jailbreak _prompt ;
if ( settings . impersonation _prompt !== undefined ) oai _settings . impersonation _prompt = settings . impersonation _prompt ;
$ ( '#main_prompt_textarea' ) . val ( oai _settings . main _prompt ) ;
$ ( '#nsfw_prompt_textarea' ) . val ( oai _settings . nsfw _prompt ) ;
$ ( '#jailbreak_prompt_textarea' ) . val ( oai _settings . jailbreak _prompt ) ;
$ ( '#impersonation_prompt_textarea' ) . val ( oai _settings . impersonation _prompt ) ;
$ ( '#nsfw_avoidance_prompt_textarea' ) . val ( oai _settings . nsfw _avoidance _prompt ) ;
$ ( '#wi_format_textarea' ) . val ( oai _settings . wi _format ) ;
$ ( '#send_if_empty_textarea' ) . val ( oai _settings . send _if _empty ) ;
$ ( '#temp_openai' ) . val ( oai _settings . temp _openai ) ;
$ ( '#temp_counter_openai' ) . text ( Number ( oai _settings . temp _openai ) . toFixed ( 2 ) ) ;
$ ( '#freq_pen_openai' ) . val ( oai _settings . freq _pen _openai ) ;
$ ( '#freq_pen_counter_openai' ) . text ( Number ( oai _settings . freq _pen _openai ) . toFixed ( 2 ) ) ;
$ ( '#pres_pen_openai' ) . val ( oai _settings . pres _pen _openai ) ;
$ ( '#pres_pen_counter_openai' ) . text ( Number ( oai _settings . pres _pen _openai ) . toFixed ( 2 ) ) ;
$ ( '#top_p_openai' ) . val ( oai _settings . top _p _openai ) ;
$ ( '#top_p_counter_openai' ) . text ( Number ( oai _settings . top _p _openai ) . toFixed ( 2 ) ) ;
$ ( '#top_k_openai' ) . val ( oai _settings . top _k _openai ) ;
$ ( '#top_k_counter_openai' ) . text ( Number ( oai _settings . top _k _openai ) . toFixed ( 0 ) ) ;
if ( settings . reverse _proxy !== undefined ) oai _settings . reverse _proxy = settings . reverse _proxy ;
$ ( '#openai_reverse_proxy' ) . val ( oai _settings . reverse _proxy ) ;
2023-07-28 20:33:29 +02:00
$ ( ".reverse_proxy_warning" ) . toggle ( oai _settings . reverse _proxy !== '' ) ;
2023-07-20 19:32:15 +02:00
$ ( '#openai_logit_bias_preset' ) . empty ( ) ;
for ( const preset of Object . keys ( oai _settings . bias _presets ) ) {
const option = document . createElement ( 'option' ) ;
option . innerText = preset ;
option . value = preset ;
option . selected = preset === oai _settings . bias _preset _selected ;
$ ( '#openai_logit_bias_preset' ) . append ( option ) ;
}
$ ( '#openai_logit_bias_preset' ) . trigger ( 'change' ) ;
$ ( '#chat_completion_source' ) . val ( oai _settings . chat _completion _source ) . trigger ( 'change' ) ;
$ ( '#oai_max_context_unlocked' ) . prop ( 'checked' , oai _settings . max _context _unlocked ) ;
}
async function getStatusOpen ( ) {
if ( is _get _status _openai ) {
if ( oai _settings . chat _completion _source == chat _completion _sources . WINDOWAI ) {
let status ;
if ( 'ai' in window ) {
status = 'Valid' ;
}
else {
showWindowExtensionError ( ) ;
status = 'no_connection' ;
}
setOnlineStatus ( status ) ;
return resultCheckStatusOpen ( ) ;
}
if ( oai _settings . chat _completion _source == chat _completion _sources . SCALE || oai _settings . chat _completion _source == chat _completion _sources . CLAUDE ) {
let status = 'Unable to verify key; press "Test Message" to validate.' ;
setOnlineStatus ( status ) ;
return resultCheckStatusOpen ( ) ;
}
let data = {
reverse _proxy : oai _settings . reverse _proxy ,
2023-07-28 20:33:29 +02:00
proxy _password : oai _settings . proxy _password ,
2023-07-20 19:32:15 +02:00
use _openrouter : oai _settings . chat _completion _source == chat _completion _sources . OPENROUTER ,
} ;
return jQuery . ajax ( {
type : 'POST' , //
url : '/getstatus_openai' , //
data : JSON . stringify ( data ) ,
beforeSend : function ( ) {
if ( oai _settings . reverse _proxy && ! data . use _openrouter ) {
validateReverseProxy ( ) ;
}
} ,
cache : false ,
dataType : "json" ,
contentType : "application/json" ,
success : function ( data ) {
if ( ! ( 'error' in data ) )
setOnlineStatus ( 'Valid' ) ;
if ( 'data' in data && Array . isArray ( data . data ) ) {
saveModelList ( data . data ) ;
}
resultCheckStatusOpen ( ) ;
} ,
error : function ( jqXHR , exception ) {
setOnlineStatus ( 'no_connection' ) ;
console . log ( exception ) ;
console . log ( jqXHR ) ;
resultCheckStatusOpen ( ) ;
}
} ) ;
} else {
setOnlineStatus ( 'no_connection' ) ;
}
}
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 ( ) {
is _api _button _press _openai = false ;
checkOnlineStatus ( ) ;
$ ( "#api_loading_openai" ) . css ( "display" , 'none' ) ;
$ ( "#api_button_openai" ) . css ( "display" , 'inline-block' ) ;
}
function trySelectPresetByName ( name ) {
let preset _found = null ;
for ( const key in openai _setting _names ) {
if ( name . trim ( ) == key . trim ( ) ) {
preset _found = key ;
break ;
}
}
// Don't change if the current preset is the same
if ( preset _found && preset _found === oai _settings . preset _settings _openai ) {
return ;
}
if ( preset _found ) {
oai _settings . preset _settings _openai = preset _found ;
const value = openai _setting _names [ preset _found ]
$ ( ` #settings_perset_openai option[value=" ${ value } "] ` ) . attr ( 'selected' , true ) ;
$ ( '#settings_perset_openai' ) . val ( value ) . trigger ( 'change' ) ;
}
}
async function saveOpenAIPreset ( name , settings ) {
const presetBody = {
chat _completion _source : settings . chat _completion _source ,
openai _model : settings . openai _model ,
claude _model : settings . claude _model ,
windowai _model : settings . windowai _model ,
openrouter _model : settings . openrouter _model ,
temperature : settings . temp _openai ,
frequency _penalty : settings . freq _pen _openai ,
presence _penalty : settings . pres _pen _openai ,
top _p : settings . top _p _openai ,
top _k : settings . top _k _openai ,
openai _max _context : settings . openai _max _context ,
openai _max _tokens : settings . openai _max _tokens ,
nsfw _toggle : settings . nsfw _toggle ,
enhance _definitions : settings . enhance _definitions ,
wrap _in _quotes : settings . wrap _in _quotes ,
send _if _empty : settings . send _if _empty ,
nsfw _first : settings . nsfw _first ,
main _prompt : settings . main _prompt ,
nsfw _prompt : settings . nsfw _prompt ,
jailbreak _prompt : settings . jailbreak _prompt ,
jailbreak _system : settings . jailbreak _system ,
impersonation _prompt : settings . impersonation _prompt ,
bias _preset _selected : settings . bias _preset _selected ,
reverse _proxy : settings . reverse _proxy ,
2023-07-28 20:33:29 +02:00
proxy _password : settings . proxy _password ,
2023-07-20 19:32:15 +02:00
legacy _streaming : settings . legacy _streaming ,
max _context _unlocked : settings . max _context _unlocked ,
nsfw _avoidance _prompt : settings . nsfw _avoidance _prompt ,
wi _format : settings . wi _format ,
stream _openai : settings . stream _openai ,
api _url _scale : settings . api _url _scale ,
2023-07-21 12:35:39 +02:00
show _external _models : settings . show _external _models ,
2023-07-30 00:51:59 +02:00
assistant _prefill : settings . assistant _prefill ,
2023-07-20 19:32:15 +02:00
} ;
const savePresetSettings = await fetch ( ` /savepreset_openai?name= ${ name } ` , {
method : 'POST' ,
headers : getRequestHeaders ( ) ,
body : JSON . stringify ( presetBody ) ,
} ) ;
if ( savePresetSettings . ok ) {
const data = await savePresetSettings . json ( ) ;
if ( Object . keys ( openai _setting _names ) . includes ( data . name ) ) {
oai _settings . preset _settings _openai = data . name ;
const value = openai _setting _names [ data . name ] ;
Object . assign ( openai _settings [ value ] , presetBody ) ;
$ ( ` #settings_perset_openai option[value=" ${ value } "] ` ) . attr ( 'selected' , true ) ;
$ ( '#settings_perset_openai' ) . trigger ( 'change' ) ;
}
else {
openai _settings . push ( presetBody ) ;
openai _setting _names [ data . name ] = openai _settings . length - 1 ;
const option = document . createElement ( 'option' ) ;
option . selected = true ;
option . value = openai _settings . length - 1 ;
option . innerText = data . name ;
$ ( '#settings_perset_openai' ) . append ( option ) . trigger ( 'change' ) ;
}
} else {
toastr . error ( 'Failed to save preset' ) ;
}
}
function onLogitBiasPresetChange ( ) {
const value = $ ( '#openai_logit_bias_preset' ) . find ( ':selected' ) . val ( ) ;
const preset = oai _settings . bias _presets [ value ] ;
if ( ! Array . isArray ( preset ) ) {
console . error ( 'Preset not found' ) ;
return ;
}
oai _settings . bias _preset _selected = value ;
$ ( '.openai_logit_bias_list' ) . empty ( ) ;
for ( const entry of preset ) {
if ( entry ) {
createLogitBiasListItem ( entry ) ;
}
}
biasCache = undefined ;
saveSettingsDebounced ( ) ;
}
function createNewLogitBiasEntry ( ) {
const entry = { text : '' , value : 0 } ;
oai _settings . bias _presets [ oai _settings . bias _preset _selected ] . push ( entry ) ;
biasCache = undefined ;
createLogitBiasListItem ( entry ) ;
saveSettingsDebounced ( ) ;
}
function createLogitBiasListItem ( entry ) {
const id = oai _settings . bias _presets [ oai _settings . bias _preset _selected ] . indexOf ( entry ) ;
const template = $ ( '#openai_logit_bias_template .openai_logit_bias_form' ) . clone ( ) ;
template . data ( 'id' , id ) ;
template . find ( '.openai_logit_bias_text' ) . val ( entry . text ) . on ( 'input' , function ( ) {
oai _settings . bias _presets [ oai _settings . bias _preset _selected ] [ id ] . text = $ ( this ) . val ( ) ;
biasCache = undefined ;
saveSettingsDebounced ( ) ;
} ) ;
template . find ( '.openai_logit_bias_value' ) . val ( entry . value ) . on ( 'input' , function ( ) {
oai _settings . bias _presets [ oai _settings . bias _preset _selected ] [ id ] . value = Number ( $ ( this ) . val ( ) ) ;
biasCache = undefined ;
saveSettingsDebounced ( ) ;
} ) ;
template . find ( '.openai_logit_bias_remove' ) . on ( 'click' , function ( ) {
$ ( this ) . closest ( '.openai_logit_bias_form' ) . remove ( ) ;
oai _settings . bias _presets [ oai _settings . bias _preset _selected ] [ id ] = undefined ;
biasCache = undefined ;
saveSettingsDebounced ( ) ;
} ) ;
$ ( '.openai_logit_bias_list' ) . prepend ( template ) ;
}
async function createNewLogitBiasPreset ( ) {
const name = await callPopup ( 'Preset name:' , 'input' ) ;
if ( ! name ) {
return ;
}
if ( name in oai _settings . bias _presets ) {
toastr . error ( 'Preset name should be unique.' ) ;
return ;
}
oai _settings . bias _preset _selected = name ;
oai _settings . bias _presets [ name ] = [ ] ;
addLogitBiasPresetOption ( name ) ;
saveSettingsDebounced ( ) ;
}
function addLogitBiasPresetOption ( name ) {
const option = document . createElement ( 'option' ) ;
option . innerText = name ;
option . value = name ;
option . selected = true ;
$ ( '#openai_logit_bias_preset' ) . append ( option ) ;
$ ( '#openai_logit_bias_preset' ) . trigger ( 'change' ) ;
}
function onImportPresetClick ( ) {
$ ( '#openai_preset_import_file' ) . trigger ( 'click' ) ;
}
function onLogitBiasPresetImportClick ( ) {
$ ( '#openai_logit_bias_import_file' ) . trigger ( 'click' ) ;
}
async function onPresetImportFileChange ( e ) {
const file = e . target . files [ 0 ] ;
if ( ! file ) {
return ;
}
const name = file . name . replace ( /\.[^/.]+$/ , "" ) ;
const importedFile = await getFileText ( file ) ;
let presetBody ;
e . target . value = '' ;
try {
presetBody = JSON . parse ( importedFile ) ;
} catch ( err ) {
toastr . error ( 'Invalid file' ) ;
return ;
}
if ( name in openai _setting _names ) {
const confirm = await callPopup ( 'Preset name already exists. Overwrite?' , 'confirm' ) ;
if ( ! confirm ) {
return ;
}
}
const savePresetSettings = await fetch ( ` /savepreset_openai?name= ${ name } ` , {
method : 'POST' ,
headers : getRequestHeaders ( ) ,
body : importedFile ,
} ) ;
if ( ! savePresetSettings . ok ) {
toastr . error ( 'Failed to save preset' ) ;
return ;
}
const data = await savePresetSettings . json ( ) ;
if ( Object . keys ( openai _setting _names ) . includes ( data . name ) ) {
oai _settings . preset _settings _openai = data . name ;
const value = openai _setting _names [ data . name ] ;
Object . assign ( openai _settings [ value ] , presetBody ) ;
$ ( ` #settings_perset_openai option[value=" ${ value } "] ` ) . attr ( 'selected' , true ) ;
$ ( '#settings_perset_openai' ) . trigger ( 'change' ) ;
} else {
openai _settings . push ( presetBody ) ;
openai _setting _names [ data . name ] = openai _settings . length - 1 ;
const option = document . createElement ( 'option' ) ;
option . selected = true ;
option . value = openai _settings . length - 1 ;
option . innerText = data . name ;
$ ( '#settings_perset_openai' ) . append ( option ) . trigger ( 'change' ) ;
}
}
async function onExportPresetClick ( ) {
if ( ! oai _settings . preset _settings _openai ) {
toastr . error ( 'No preset selected' ) ;
return ;
}
const preset = openai _settings [ openai _setting _names [ oai _settings . preset _settings _openai ] ] ;
const presetJsonString = JSON . stringify ( preset , null , 4 ) ;
download ( presetJsonString , oai _settings . preset _settings _openai , 'application/json' ) ;
}
async function onLogitBiasPresetImportFileChange ( e ) {
const file = e . target . files [ 0 ] ;
if ( ! file || file . type !== "application/json" ) {
return ;
}
const name = file . name . replace ( /\.[^/.]+$/ , "" ) ;
const importedFile = await parseJsonFile ( file ) ;
e . target . value = '' ;
if ( name in oai _settings . bias _presets ) {
toastr . error ( 'Preset name should be unique.' ) ;
return ;
}
if ( ! Array . isArray ( importedFile ) ) {
toastr . error ( 'Invalid logit bias preset file.' ) ;
return ;
}
for ( const entry of importedFile ) {
if ( typeof entry == 'object' ) {
if ( entry . hasOwnProperty ( 'text' ) && entry . hasOwnProperty ( 'value' ) ) {
continue ;
}
}
callPopup ( 'Invalid logit bias preset file.' , 'text' ) ;
return ;
}
oai _settings . bias _presets [ name ] = importedFile ;
oai _settings . bias _preset _selected = name ;
addLogitBiasPresetOption ( name ) ;
saveSettingsDebounced ( ) ;
}
function onLogitBiasPresetExportClick ( ) {
if ( ! oai _settings . bias _preset _selected || Object . keys ( oai _settings . bias _presets ) . length === 0 ) {
return ;
}
const presetJsonString = JSON . stringify ( oai _settings . bias _presets [ oai _settings . bias _preset _selected ] , null , 4 ) ;
download ( presetJsonString , oai _settings . bias _preset _selected , 'application/json' ) ;
}
async function onDeletePresetClick ( ) {
const confirm = await callPopup ( 'Delete the preset? This action is irreversible and your current settings will be overwritten.' , 'confirm' ) ;
if ( ! confirm ) {
return ;
}
const nameToDelete = oai _settings . preset _settings _openai ;
const value = openai _setting _names [ oai _settings . preset _settings _openai ] ;
$ ( ` #settings_perset_openai option[value=" ${ value } "] ` ) . remove ( ) ;
delete openai _setting _names [ oai _settings . preset _settings _openai ] ;
oai _settings . preset _settings _openai = null ;
if ( Object . keys ( openai _setting _names ) . length ) {
oai _settings . preset _settings _openai = Object . keys ( openai _setting _names ) [ 0 ] ;
const newValue = openai _setting _names [ oai _settings . preset _settings _openai ] ;
$ ( ` #settings_perset_openai option[value=" ${ newValue } "] ` ) . attr ( 'selected' , true ) ;
$ ( '#settings_perset_openai' ) . trigger ( 'change' ) ;
}
const response = await fetch ( '/deletepreset_openai' , {
method : 'POST' ,
headers : getRequestHeaders ( ) ,
body : JSON . stringify ( { name : nameToDelete } ) ,
} ) ;
if ( ! response . ok ) {
console . warn ( 'Preset was not deleted from server' ) ;
}
saveSettingsDebounced ( ) ;
}
async function onLogitBiasPresetDeleteClick ( ) {
const value = await callPopup ( 'Delete the preset?' , 'confirm' ) ;
if ( ! value ) {
return ;
}
$ ( ` #openai_logit_bias_preset option[value=" ${ oai _settings . bias _preset _selected } "] ` ) . remove ( ) ;
delete oai _settings . bias _presets [ oai _settings . bias _preset _selected ] ;
oai _settings . bias _preset _selected = null ;
if ( Object . keys ( oai _settings . bias _presets ) . length ) {
oai _settings . bias _preset _selected = Object . keys ( oai _settings . bias _presets ) [ 0 ] ;
$ ( ` #openai_logit_bias_preset option[value=" ${ oai _settings . bias _preset _selected } "] ` ) . attr ( 'selected' , true ) ;
$ ( '#openai_logit_bias_preset' ) . trigger ( 'change' ) ;
}
biasCache = undefined ;
saveSettingsDebounced ( ) ;
}
// Load OpenAI preset settings
function onSettingsPresetChange ( ) {
oai _settings . preset _settings _openai = $ ( '#settings_perset_openai' ) . find ( ":selected" ) . text ( ) ;
const preset = openai _settings [ openai _setting _names [ oai _settings . preset _settings _openai ] ] ;
const updateInput = ( selector , value ) => $ ( selector ) . val ( value ) . trigger ( 'input' ) ;
const updateCheckbox = ( selector , value ) => $ ( selector ) . prop ( 'checked' , value ) . trigger ( 'input' ) ;
const settingsToUpdate = {
chat _completion _source : [ '#chat_completion_source' , 'chat_completion_source' , false ] ,
temperature : [ '#temp_openai' , 'temp_openai' , false ] ,
frequency _penalty : [ '#freq_pen_openai' , 'freq_pen_openai' , false ] ,
presence _penalty : [ '#pres_pen_openai' , 'pres_pen_openai' , false ] ,
top _p : [ '#top_p_openai' , 'top_p_openai' , false ] ,
top _k : [ '#top_k_openai' , 'top_k_openai' , false ] ,
max _context _unlocked : [ '#oai_max_context_unlocked' , 'max_context_unlocked' , true ] ,
openai _model : [ '#model_openai_select' , 'openai_model' , false ] ,
claude _model : [ '#model_claude_select' , 'claude_model' , false ] ,
windowai _model : [ '#model_windowai_select' , 'windowai_model' , false ] ,
openrouter _model : [ '#model_openrouter_select' , 'openrouter_model' , false ] ,
openai _max _context : [ '#openai_max_context' , 'openai_max_context' , false ] ,
openai _max _tokens : [ '#openai_max_tokens' , 'openai_max_tokens' , false ] ,
nsfw _toggle : [ '#nsfw_toggle' , 'nsfw_toggle' , true ] ,
enhance _definitions : [ '#enhance_definitions' , 'enhance_definitions' , true ] ,
wrap _in _quotes : [ '#wrap_in_quotes' , 'wrap_in_quotes' , true ] ,
send _if _empty : [ '#send_if_empty_textarea' , 'send_if_empty' , false ] ,
jailbreak _system : [ '#jailbreak_system' , 'jailbreak_system' , true ] ,
impersonation _prompt : [ '#impersonation_prompt_textarea' , 'impersonation_prompt' , false ] ,
bias _preset _selected : [ '#openai_logit_bias_preset' , 'bias_preset_selected' , false ] ,
reverse _proxy : [ '#openai_reverse_proxy' , 'reverse_proxy' , false ] ,
legacy _streaming : [ '#legacy_streaming' , 'legacy_streaming' , true ] ,
nsfw _avoidance _prompt : [ '#nsfw_avoidance_prompt_textarea' , 'nsfw_avoidance_prompt' , false ] ,
wi _format : [ '#wi_format_textarea' , 'wi_format' , false ] ,
stream _openai : [ '#stream_toggle' , 'stream_openai' , true ] ,
api _url _scale : [ '#api_url_scale' , 'api_url_scale' , false ] ,
2023-07-21 12:35:39 +02:00
show _external _models : [ '#openai_show_external_models' , 'show_external_models' , true ] ,
2023-07-28 20:33:29 +02:00
proxy _password : [ '#openai_proxy_password' , 'proxy_password' , false ] ,
2023-07-30 00:51:59 +02:00
assistant _prefill : [ '#claude_assistant_prefill' , 'assistant_prefill' , false ] ,
2023-07-20 19:32:15 +02:00
} ;
for ( const [ key , [ selector , setting , isCheckbox ] ] of Object . entries ( settingsToUpdate ) ) {
if ( preset [ key ] !== undefined ) {
if ( isCheckbox ) {
updateCheckbox ( selector , preset [ key ] ) ;
} else {
updateInput ( selector , preset [ key ] ) ;
}
oai _settings [ setting ] = preset [ key ] ;
}
}
$ ( ` #chat_completion_source ` ) . trigger ( 'change' ) ;
$ ( ` #openai_logit_bias_preset ` ) . trigger ( 'change' ) ;
saveSettingsDebounced ( ) ;
}
function getMaxContextOpenAI ( value ) {
if ( oai _settings . max _context _unlocked ) {
return unlocked _max ;
}
else if ( [ 'gpt-4' , 'gpt-4-0314' , 'gpt-4-0613' ] . includes ( value ) ) {
return max _8k ;
}
else if ( [ 'gpt-4-32k' , 'gpt-4-32k-0314' , 'gpt-4-32k-0613' ] . includes ( value ) ) {
return max _32k ;
}
else if ( [ 'gpt-3.5-turbo-16k' , 'gpt-3.5-turbo-16k-0613' ] . includes ( value ) ) {
return max _16k ;
}
else if ( value == 'code-davinci-002' ) {
return max _8k ;
}
else if ( [ 'text-curie-001' , 'text-babbage-001' , 'text-ada-001' ] . includes ( value ) ) {
return max _2k ;
}
else {
// default to gpt-3 (4095 tokens)
return max _4k ;
}
}
function getMaxContextWindowAI ( value ) {
if ( oai _settings . max _context _unlocked ) {
return unlocked _max ;
}
else if ( value . endsWith ( '100k' ) ) {
return claude _100k _max ;
}
else if ( value . includes ( 'claude' ) ) {
return claude _max ;
}
else if ( value . includes ( 'gpt-3.5-turbo-16k' ) ) {
return max _16k ;
}
else if ( value . includes ( 'gpt-3.5' ) ) {
return max _4k ;
}
else if ( value . includes ( 'gpt-4-32k' ) ) {
return max _32k ;
}
else if ( value . includes ( 'gpt-4' ) ) {
return max _8k ;
}
else if ( value . includes ( 'palm-2' ) ) {
return palm2 _max ;
}
else if ( value . includes ( 'GPT-NeoXT' ) ) {
return max _2k ;
}
else {
// default to gpt-3 (4095 tokens)
return max _4k ;
}
}
async function onModelChange ( ) {
let value = $ ( this ) . val ( ) ;
if ( $ ( this ) . is ( '#model_claude_select' ) ) {
console . log ( 'Claude model changed to' , value ) ;
oai _settings . claude _model = value ;
}
if ( $ ( this ) . is ( '#model_windowai_select' ) ) {
console . log ( 'WindowAI model changed to' , value ) ;
oai _settings . windowai _model = value ;
}
if ( $ ( this ) . is ( '#model_openai_select' ) ) {
console . log ( 'OpenAI model changed to' , value ) ;
oai _settings . openai _model = value ;
}
if ( $ ( this ) . is ( '#model_openrouter_select' ) ) {
if ( ! value ) {
console . debug ( 'Null OR model selected. Ignoring.' ) ;
return ;
}
console . log ( 'OpenRouter model changed to' , value ) ;
oai _settings . openrouter _model = value ;
}
if ( oai _settings . chat _completion _source == chat _completion _sources . SCALE ) {
if ( oai _settings . max _context _unlocked ) {
$ ( '#openai_max_context' ) . attr ( 'max' , unlocked _max ) ;
} else {
$ ( '#openai_max_context' ) . attr ( 'max' , scale _max ) ;
}
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' ) ;
}
if ( oai _settings . chat _completion _source == chat _completion _sources . OPENROUTER ) {
if ( oai _settings . max _context _unlocked ) {
$ ( '#openai_max_context' ) . attr ( 'max' , unlocked _max ) ;
} else {
const model = model _list . find ( m => m . id == oai _settings . openrouter _model ) ;
if ( model ? . context _length ) {
$ ( '#openai_max_context' ) . attr ( 'max' , model . context _length ) ;
} else {
$ ( '#openai_max_context' ) . attr ( 'max' , max _8k ) ;
}
}
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' ) ;
if ( value && ( value . includes ( 'claude' ) || value . includes ( 'palm-2' ) ) ) {
oai _settings . temp _openai = Math . min ( claude _max _temp , oai _settings . temp _openai ) ;
$ ( '#temp_openai' ) . attr ( 'max' , claude _max _temp ) . val ( oai _settings . temp _openai ) . trigger ( 'input' ) ;
}
else {
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' ) ;
}
2023-08-09 20:59:34 +02:00
calculateOpenRouterCost ( ) ;
2023-07-20 19:32:15 +02:00
}
if ( oai _settings . chat _completion _source == chat _completion _sources . CLAUDE ) {
if ( oai _settings . max _context _unlocked ) {
$ ( '#openai_max_context' ) . attr ( 'max' , unlocked _max ) ;
}
else if ( value . endsWith ( '100k' ) || value . startsWith ( 'claude-2' ) ) {
$ ( '#openai_max_context' ) . attr ( 'max' , claude _100k _max ) ;
}
else {
$ ( '#openai_max_context' ) . attr ( 'max' , claude _max ) ;
}
oai _settings . openai _max _context = Math . min ( oai _settings . openai _max _context , Number ( $ ( '#openai_max_context' ) . attr ( 'max' ) ) ) ;
$ ( '#openai_max_context' ) . val ( oai _settings . openai _max _context ) . trigger ( 'input' ) ;
$ ( '#openai_reverse_proxy' ) . attr ( 'placeholder' , 'https://api.anthropic.com/v1' ) ;
oai _settings . temp _openai = Math . min ( claude _max _temp , oai _settings . temp _openai ) ;
$ ( '#temp_openai' ) . attr ( 'max' , claude _max _temp ) . val ( oai _settings . temp _openai ) . trigger ( 'input' ) ;
}
if ( oai _settings . chat _completion _source == chat _completion _sources . WINDOWAI ) {
if ( value == '' && 'ai' in window ) {
value = ( await window . ai . getCurrentModel ( ) ) || '' ;
}
$ ( '#openai_max_context' ) . attr ( 'max' , getMaxContextWindowAI ( value ) ) ;
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' ) ;
if ( value . includes ( 'claude' ) || value . includes ( 'palm-2' ) ) {
oai _settings . temp _openai = Math . min ( claude _max _temp , oai _settings . temp _openai ) ;
$ ( '#temp_openai' ) . attr ( 'max' , claude _max _temp ) . val ( oai _settings . temp _openai ) . trigger ( 'input' ) ;
}
else {
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 . OPENAI ) {
$ ( '#openai_max_context' ) . attr ( 'max' , getMaxContextOpenAI ( value ) ) ;
oai _settings . openai _max _context = Math . min ( oai _settings . openai _max _context , Number ( $ ( '#openai_max_context' ) . attr ( 'max' ) ) ) ;
$ ( '#openai_max_context' ) . val ( oai _settings . openai _max _context ) . trigger ( 'input' ) ;
$ ( '#openai_reverse_proxy' ) . attr ( 'placeholder' , 'https://api.openai.com/v1' ) ;
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' ) ;
}
saveSettingsDebounced ( ) ;
}
async function onNewPresetClick ( ) {
const popupText = `
< h3 > Preset name : < / h 3 >
< h4 > Hint : Use a character / group name to bind preset to a specific chat . < / h 4 > ` ;
const name = await callPopup ( popupText , 'input' ) ;
if ( ! name ) {
return ;
}
await saveOpenAIPreset ( name , oai _settings ) ;
}
function onReverseProxyInput ( ) {
oai _settings . reverse _proxy = $ ( this ) . val ( ) ;
2023-07-28 20:33:29 +02:00
$ ( ".reverse_proxy_warning" ) . toggle ( oai _settings . reverse _proxy != '' ) ;
2023-07-20 19:32:15 +02:00
saveSettingsDebounced ( ) ;
}
async function onConnectButtonClick ( e ) {
e . stopPropagation ( ) ;
if ( oai _settings . chat _completion _source == chat _completion _sources . WINDOWAI ) {
is _get _status _openai = true ;
is _api _button _press _openai = true ;
return await getStatusOpen ( ) ;
}
if ( oai _settings . chat _completion _source == chat _completion _sources . OPENROUTER ) {
const api _key _openrouter = $ ( '#api_key_openrouter' ) . val ( ) . trim ( ) ;
if ( api _key _openrouter . length ) {
await writeSecret ( SECRET _KEYS . OPENROUTER , api _key _openrouter ) ;
}
if ( ! secret _state [ SECRET _KEYS . OPENROUTER ] ) {
console . log ( 'No secret key saved for OpenRouter' ) ;
return ;
}
}
if ( oai _settings . chat _completion _source == chat _completion _sources . SCALE ) {
const api _key _scale = $ ( '#api_key_scale' ) . val ( ) . trim ( ) ;
if ( api _key _scale . length ) {
await writeSecret ( SECRET _KEYS . SCALE , api _key _scale ) ;
}
if ( ! oai _settings . api _url _scale ) {
console . log ( 'No API URL saved for Scale' ) ;
return ;
}
if ( ! secret _state [ SECRET _KEYS . SCALE ] ) {
console . log ( 'No secret key saved for Scale' ) ;
return ;
}
}
if ( oai _settings . chat _completion _source == chat _completion _sources . CLAUDE ) {
const api _key _claude = $ ( '#api_key_claude' ) . val ( ) . trim ( ) ;
if ( api _key _claude . length ) {
await writeSecret ( SECRET _KEYS . CLAUDE , api _key _claude ) ;
}
2023-07-28 20:33:29 +02:00
if ( ! secret _state [ SECRET _KEYS . CLAUDE ] && ! oai _settings . reverse _proxy ) {
2023-07-20 19:32:15 +02:00
console . log ( 'No secret key saved for Claude' ) ;
return ;
}
}
if ( oai _settings . chat _completion _source == chat _completion _sources . OPENAI ) {
const api _key _openai = $ ( '#api_key_openai' ) . val ( ) . trim ( ) ;
if ( api _key _openai . length ) {
await writeSecret ( SECRET _KEYS . OPENAI , api _key _openai ) ;
}
2023-07-28 20:33:29 +02:00
if ( ! secret _state [ SECRET _KEYS . OPENAI ] && ! oai _settings . reverse _proxy ) {
2023-07-20 19:32:15 +02:00
console . log ( 'No secret key saved for OpenAI' ) ;
return ;
}
}
$ ( "#api_loading_openai" ) . css ( "display" , 'inline-block' ) ;
$ ( "#api_button_openai" ) . css ( "display" , 'none' ) ;
saveSettingsDebounced ( ) ;
is _get _status _openai = true ;
is _api _button _press _openai = true ;
await getStatusOpen ( ) ;
}
function toggleChatCompletionForms ( ) {
if ( oai _settings . chat _completion _source == chat _completion _sources . CLAUDE ) {
$ ( '#model_claude_select' ) . trigger ( 'change' ) ;
}
else if ( oai _settings . chat _completion _source == chat _completion _sources . OPENAI ) {
2023-07-21 12:35:39 +02:00
if ( oai _settings . show _external _models && ( ! Array . isArray ( model _list ) || model _list . length == 0 ) ) {
// Wait until the models list is loaded so that we could show a proper saved model
}
else {
$ ( '#model_openai_select' ) . trigger ( 'change' ) ;
}
2023-07-20 19:32:15 +02:00
}
else if ( oai _settings . chat _completion _source == chat _completion _sources . WINDOWAI ) {
$ ( '#model_windowai_select' ) . trigger ( 'change' ) ;
}
else if ( oai _settings . chat _completion _source == chat _completion _sources . SCALE ) {
$ ( '#model_scale_select' ) . trigger ( 'change' ) ;
}
else if ( oai _settings . chat _completion _source == chat _completion _sources . OPENROUTER ) {
$ ( '#model_openrouter_select' ) . trigger ( 'change' ) ;
}
$ ( '[data-source]' ) . each ( function ( ) {
const validSources = $ ( this ) . data ( 'source' ) . split ( ',' ) ;
$ ( this ) . toggle ( validSources . includes ( oai _settings . chat _completion _source ) ) ;
} ) ;
}
async function testApiConnection ( ) {
// Check if the previous request is still in progress
if ( is _send _press ) {
toastr . info ( 'Please wait for the previous request to complete.' ) ;
return ;
}
try {
const reply = await sendOpenAIRequest ( 'quiet' , [ { 'role' : 'user' , 'content' : 'Hi' } ] ) ;
console . log ( reply ) ;
toastr . success ( 'API connection successful!' ) ;
}
catch ( err ) {
toastr . error ( 'Could not get a reply from API. Check your connection settings / API key and try again.' ) ;
}
}
function reconnectOpenAi ( ) {
setOnlineStatus ( 'no_connection' ) ;
resultCheckStatusOpen ( ) ;
$ ( '#api_button_openai' ) . trigger ( 'click' ) ;
}
$ ( document ) . ready ( function ( ) {
$ ( '#test_api_button' ) . on ( 'click' , testApiConnection ) ;
$ ( document ) . on ( 'input' , '#temp_openai' , function ( ) {
oai _settings . temp _openai = $ ( this ) . val ( ) ;
$ ( '#temp_counter_openai' ) . text ( Number ( $ ( this ) . val ( ) ) . toFixed ( 2 ) ) ;
saveSettingsDebounced ( ) ;
} ) ;
$ ( document ) . on ( 'input' , '#freq_pen_openai' , function ( ) {
oai _settings . freq _pen _openai = $ ( this ) . val ( ) ;
$ ( '#freq_pen_counter_openai' ) . text ( Number ( $ ( this ) . val ( ) ) . toFixed ( 2 ) ) ;
saveSettingsDebounced ( ) ;
} ) ;
$ ( document ) . on ( 'input' , '#pres_pen_openai' , function ( ) {
oai _settings . pres _pen _openai = $ ( this ) . val ( ) ;
$ ( '#pres_pen_counter_openai' ) . text ( Number ( $ ( this ) . val ( ) ) . toFixed ( 2 ) ) ;
saveSettingsDebounced ( ) ;
} ) ;
$ ( document ) . on ( 'input' , '#top_p_openai' , function ( ) {
oai _settings . top _p _openai = $ ( this ) . val ( ) ;
$ ( '#top_p_counter_openai' ) . text ( Number ( $ ( this ) . val ( ) ) . toFixed ( 2 ) ) ;
saveSettingsDebounced ( ) ;
} ) ;
$ ( document ) . on ( 'input' , '#top_k_openai' , function ( ) {
oai _settings . top _k _openai = $ ( this ) . val ( ) ;
$ ( '#top_k_counter_openai' ) . text ( Number ( $ ( this ) . val ( ) ) . toFixed ( 0 ) ) ;
saveSettingsDebounced ( ) ;
} ) ;
$ ( document ) . on ( 'input' , '#openai_max_context' , function ( ) {
oai _settings . openai _max _context = parseInt ( $ ( this ) . val ( ) ) ;
$ ( '#openai_max_context_counter' ) . text ( ` ${ $ ( this ) . val ( ) } ` ) ;
2023-08-09 20:59:34 +02:00
calculateOpenRouterCost ( ) ;
2023-07-20 19:32:15 +02:00
saveSettingsDebounced ( ) ;
} ) ;
$ ( document ) . on ( 'input' , '#openai_max_tokens' , function ( ) {
oai _settings . openai _max _tokens = parseInt ( $ ( this ) . val ( ) ) ;
2023-08-09 20:59:34 +02:00
calculateOpenRouterCost ( ) ;
2023-07-20 19:32:15 +02:00
saveSettingsDebounced ( ) ;
} ) ;
$ ( '#stream_toggle' ) . on ( 'change' , function ( ) {
oai _settings . stream _openai = ! ! $ ( '#stream_toggle' ) . prop ( 'checked' ) ;
saveSettingsDebounced ( ) ;
} ) ;
$ ( '#nsfw_toggle' ) . on ( 'change' , function ( ) {
oai _settings . nsfw _toggle = ! ! $ ( '#nsfw_toggle' ) . prop ( 'checked' ) ;
saveSettingsDebounced ( ) ;
} ) ;
$ ( '#enhance_definitions' ) . on ( 'change' , function ( ) {
oai _settings . enhance _definitions = ! ! $ ( '#enhance_definitions' ) . prop ( 'checked' ) ;
saveSettingsDebounced ( ) ;
} ) ;
$ ( '#wrap_in_quotes' ) . on ( 'change' , function ( ) {
oai _settings . wrap _in _quotes = ! ! $ ( '#wrap_in_quotes' ) . prop ( 'checked' ) ;
saveSettingsDebounced ( ) ;
} ) ;
$ ( "#send_if_empty_textarea" ) . on ( 'input' , function ( ) {
oai _settings . send _if _empty = $ ( '#send_if_empty_textarea' ) . val ( ) ;
saveSettingsDebounced ( ) ;
} ) ;
$ ( '#nsfw_first' ) . on ( 'change' , function ( ) {
oai _settings . nsfw _first = ! ! $ ( '#nsfw_first' ) . prop ( 'checked' ) ;
saveSettingsDebounced ( ) ;
} ) ;
$ ( "#jailbreak_prompt_textarea" ) . on ( 'input' , function ( ) {
oai _settings . jailbreak _prompt = $ ( '#jailbreak_prompt_textarea' ) . val ( ) ;
saveSettingsDebounced ( ) ;
} ) ;
$ ( "#main_prompt_textarea" ) . on ( 'input' , function ( ) {
oai _settings . main _prompt = $ ( '#main_prompt_textarea' ) . val ( ) ;
saveSettingsDebounced ( ) ;
} ) ;
$ ( "#nsfw_prompt_textarea" ) . on ( 'input' , function ( ) {
oai _settings . nsfw _prompt = $ ( '#nsfw_prompt_textarea' ) . val ( ) ;
saveSettingsDebounced ( ) ;
} ) ;
$ ( "#impersonation_prompt_textarea" ) . on ( 'input' , function ( ) {
oai _settings . impersonation _prompt = $ ( '#impersonation_prompt_textarea' ) . val ( ) ;
saveSettingsDebounced ( ) ;
} ) ;
$ ( "#nsfw_avoidance_prompt_textarea" ) . on ( 'input' , function ( ) {
oai _settings . nsfw _avoidance _prompt = $ ( '#nsfw_avoidance_prompt_textarea' ) . val ( ) ;
saveSettingsDebounced ( ) ;
} ) ;
$ ( "#wi_format_textarea" ) . on ( 'input' , function ( ) {
oai _settings . wi _format = $ ( '#wi_format_textarea' ) . val ( ) ;
saveSettingsDebounced ( ) ;
} ) ;
$ ( "#jailbreak_system" ) . on ( 'change' , function ( ) {
oai _settings . jailbreak _system = ! ! $ ( this ) . prop ( "checked" ) ;
saveSettingsDebounced ( ) ;
} ) ;
// auto-select a preset based on character/group name
$ ( document ) . on ( "click" , ".character_select" , function ( ) {
const chid = $ ( this ) . attr ( 'chid' ) ;
const name = characters [ chid ] ? . name ;
if ( ! name ) {
return ;
}
trySelectPresetByName ( name ) ;
} ) ;
$ ( document ) . on ( "click" , ".group_select" , function ( ) {
const grid = $ ( this ) . data ( 'id' ) ;
const name = groups . find ( x => x . id === grid ) ? . name ;
if ( ! name ) {
return ;
}
trySelectPresetByName ( name ) ;
} ) ;
$ ( "#update_oai_preset" ) . on ( 'click' , async function ( ) {
const name = oai _settings . preset _settings _openai ;
await saveOpenAIPreset ( name , oai _settings ) ;
toastr . success ( 'Preset updated' ) ;
} ) ;
$ ( "#main_prompt_restore" ) . on ( 'click' , function ( ) {
oai _settings . main _prompt = default _main _prompt ;
$ ( '#main_prompt_textarea' ) . val ( oai _settings . main _prompt ) ;
saveSettingsDebounced ( ) ;
} ) ;
$ ( "#nsfw_prompt_restore" ) . on ( 'click' , function ( ) {
oai _settings . nsfw _prompt = default _nsfw _prompt ;
$ ( '#nsfw_prompt_textarea' ) . val ( oai _settings . nsfw _prompt ) ;
saveSettingsDebounced ( ) ;
} ) ;
$ ( "#nsfw_avoidance_prompt_restore" ) . on ( 'click' , function ( ) {
oai _settings . nsfw _avoidance _prompt = default _nsfw _avoidance _prompt ;
$ ( '#nsfw_avoidance_prompt_textarea' ) . val ( oai _settings . nsfw _avoidance _prompt ) ;
saveSettingsDebounced ( ) ;
} ) ;
$ ( "#jailbreak_prompt_restore" ) . on ( 'click' , function ( ) {
oai _settings . jailbreak _prompt = default _jailbreak _prompt ;
$ ( '#jailbreak_prompt_textarea' ) . val ( oai _settings . jailbreak _prompt ) ;
saveSettingsDebounced ( ) ;
} ) ;
$ ( "#impersonation_prompt_restore" ) . on ( 'click' , function ( ) {
oai _settings . impersonation _prompt = default _impersonation _prompt ;
$ ( '#impersonation_prompt_textarea' ) . val ( oai _settings . impersonation _prompt ) ;
saveSettingsDebounced ( ) ;
} ) ;
$ ( "#wi_format_restore" ) . on ( 'click' , function ( ) {
oai _settings . wi _format = default _wi _format ;
$ ( '#wi_format_textarea' ) . val ( oai _settings . wi _format ) ;
saveSettingsDebounced ( ) ;
} ) ;
$ ( '#legacy_streaming' ) . on ( 'input' , function ( ) {
oai _settings . legacy _streaming = ! ! $ ( this ) . prop ( 'checked' ) ;
saveSettingsDebounced ( ) ;
} ) ;
$ ( '#chat_completion_source' ) . on ( 'change' , function ( ) {
oai _settings . chat _completion _source = $ ( this ) . find ( ":selected" ) . val ( ) ;
toggleChatCompletionForms ( ) ;
saveSettingsDebounced ( ) ;
if ( main _api == 'openai' ) {
reconnectOpenAi ( ) ;
}
} ) ;
$ ( '#oai_max_context_unlocked' ) . on ( 'input' , function ( ) {
oai _settings . max _context _unlocked = ! ! $ ( this ) . prop ( 'checked' ) ;
$ ( "#chat_completion_source" ) . trigger ( 'change' ) ;
saveSettingsDebounced ( ) ;
} ) ;
$ ( '#api_url_scale' ) . on ( 'input' , function ( ) {
oai _settings . api _url _scale = $ ( this ) . val ( ) ;
saveSettingsDebounced ( ) ;
} ) ;
2023-07-21 12:35:39 +02:00
$ ( '#openai_show_external_models' ) . on ( 'input' , function ( ) {
oai _settings . show _external _models = ! ! $ ( this ) . prop ( 'checked' ) ;
$ ( '#openai_external_category' ) . toggle ( oai _settings . show _external _models ) ;
saveSettingsDebounced ( ) ;
} ) ;
2023-07-28 20:33:29 +02:00
$ ( '#openai_proxy_password' ) . on ( 'input' , function ( ) {
oai _settings . proxy _password = $ ( this ) . val ( ) ;
saveSettingsDebounced ( ) ;
} ) ;
2023-07-30 00:51:59 +02:00
$ ( '#claude_assistant_prefill' ) . on ( 'input' , function ( ) {
oai _settings . assistant _prefill = $ ( this ) . val ( ) ;
saveSettingsDebounced ( ) ;
} ) ;
2023-07-20 19:32:15 +02:00
$ ( "#api_button_openai" ) . on ( "click" , onConnectButtonClick ) ;
$ ( "#openai_reverse_proxy" ) . on ( "input" , onReverseProxyInput ) ;
$ ( "#model_openai_select" ) . on ( "change" , onModelChange ) ;
$ ( "#model_claude_select" ) . on ( "change" , onModelChange ) ;
$ ( "#model_windowai_select" ) . on ( "change" , onModelChange ) ;
$ ( "#model_scale_select" ) . on ( "change" , onModelChange ) ;
$ ( "#model_openrouter_select" ) . on ( "change" , onModelChange ) ;
$ ( "#settings_perset_openai" ) . on ( "change" , onSettingsPresetChange ) ;
$ ( "#new_oai_preset" ) . on ( "click" , onNewPresetClick ) ;
$ ( "#delete_oai_preset" ) . on ( "click" , onDeletePresetClick ) ;
$ ( "#openai_logit_bias_preset" ) . on ( "change" , onLogitBiasPresetChange ) ;
$ ( "#openai_logit_bias_new_preset" ) . on ( "click" , createNewLogitBiasPreset ) ;
$ ( "#openai_logit_bias_new_entry" ) . on ( "click" , createNewLogitBiasEntry ) ;
$ ( "#openai_logit_bias_import_file" ) . on ( "input" , onLogitBiasPresetImportFileChange ) ;
$ ( "#openai_preset_import_file" ) . on ( "input" , onPresetImportFileChange ) ;
$ ( "#export_oai_preset" ) . on ( "click" , onExportPresetClick ) ;
$ ( "#openai_logit_bias_import_preset" ) . on ( "click" , onLogitBiasPresetImportClick ) ;
$ ( "#openai_logit_bias_export_preset" ) . on ( "click" , onLogitBiasPresetExportClick ) ;
$ ( "#openai_logit_bias_delete_preset" ) . on ( "click" , onLogitBiasPresetDeleteClick ) ;
$ ( "#import_oai_preset" ) . on ( "click" , onImportPresetClick ) ;
} ) ;