2023-12-02 19:04:51 +01:00
import { callPopup , getRequestHeaders } from '../script.js' ;
2023-07-20 19:32:15 +02:00
export const SECRET _KEYS = {
HORDE : 'api_key_horde' ,
2023-08-02 09:31:17 +02:00
MANCER : 'api_key_mancer' ,
2023-09-28 18:10:00 +02:00
APHRODITE : 'api_key_aphrodite' ,
2023-11-17 06:32:49 +01:00
TABBY : 'api_key_tabby' ,
2023-07-20 19:32:15 +02:00
OPENAI : 'api_key_openai' ,
NOVEL : 'api_key_novel' ,
CLAUDE : 'api_key_claude' ,
OPENROUTER : 'api_key_openrouter' ,
SCALE : 'api_key_scale' ,
2023-08-19 17:20:42 +02:00
AI21 : 'api_key_ai21' ,
2023-08-20 12:55:37 +02:00
SCALE _COOKIE : 'scale_cookie' ,
2023-09-23 19:48:56 +02:00
PALM : 'api_key_palm' ,
2023-11-13 23:16:41 +01:00
SERPAPI : 'api_key_serpapi' ,
2023-12-02 20:11:06 +01:00
} ;
2023-07-20 19:32:15 +02:00
const INPUT _MAP = {
[ SECRET _KEYS . HORDE ] : '#horde_api_key' ,
2023-08-02 09:31:17 +02:00
[ SECRET _KEYS . MANCER ] : '#api_key_mancer' ,
2023-07-20 19:32:15 +02:00
[ SECRET _KEYS . OPENAI ] : '#api_key_openai' ,
[ SECRET _KEYS . NOVEL ] : '#api_key_novel' ,
[ SECRET _KEYS . CLAUDE ] : '#api_key_claude' ,
[ SECRET _KEYS . OPENROUTER ] : '#api_key_openrouter' ,
[ SECRET _KEYS . SCALE ] : '#api_key_scale' ,
2023-08-19 17:20:42 +02:00
[ SECRET _KEYS . AI21 ] : '#api_key_ai21' ,
2023-08-20 12:55:37 +02:00
[ SECRET _KEYS . SCALE _COOKIE ] : '#scale_cookie' ,
2023-09-23 19:48:56 +02:00
[ SECRET _KEYS . PALM ] : '#api_key_palm' ,
2023-09-28 18:10:00 +02:00
[ SECRET _KEYS . APHRODITE ] : '#api_key_aphrodite' ,
2023-12-02 21:06:57 +01:00
[ SECRET _KEYS . TABBY ] : '#api_key_tabby' ,
2023-12-02 20:11:06 +01:00
} ;
2023-07-20 19:32:15 +02:00
async function clearSecret ( ) {
const key = $ ( this ) . data ( 'key' ) ;
await writeSecret ( key , '' ) ;
secret _state [ key ] = false ;
updateSecretDisplay ( ) ;
$ ( INPUT _MAP [ key ] ) . val ( '' ) ;
$ ( '#main_api' ) . trigger ( 'change' ) ;
}
function updateSecretDisplay ( ) {
for ( const [ secret _key , input _selector ] of Object . entries ( INPUT _MAP ) ) {
const validSecret = ! ! secret _state [ secret _key ] ;
const placeholder = validSecret ? '✔️ Key saved' : '❌ Missing key' ;
$ ( input _selector ) . attr ( 'placeholder' , placeholder ) ;
}
}
async function viewSecrets ( ) {
2023-12-03 15:19:25 +01:00
const response = await fetch ( '/api/secrets/view' , {
2023-07-20 19:32:15 +02:00
method : 'POST' ,
headers : getRequestHeaders ( ) ,
} ) ;
if ( response . status == 403 ) {
2023-11-25 22:45:33 +01:00
callPopup ( '<h3>Forbidden</h3><p>To view your API keys here, set the value of allowKeysExposure to true in config.yaml file and restart the SillyTavern server.</p>' , 'text' ) ;
2023-07-20 19:32:15 +02:00
return ;
}
if ( ! response . ok ) {
return ;
}
$ ( '#dialogue_popup' ) . addClass ( 'wide_dialogue_popup' ) ;
const data = await response . json ( ) ;
const table = document . createElement ( 'table' ) ;
table . classList . add ( 'responsiveTable' ) ;
$ ( table ) . append ( '<thead><th>Key</th><th>Value</th></thead>' ) ;
for ( const [ key , value ] of Object . entries ( data ) ) {
$ ( table ) . append ( ` <tr><td> ${ DOMPurify . sanitize ( key ) } </td><td> ${ DOMPurify . sanitize ( value ) } </td></tr> ` ) ;
}
callPopup ( table . outerHTML , 'text' ) ;
}
export let secret _state = { } ;
export async function writeSecret ( key , value ) {
try {
2023-09-16 15:39:07 +02:00
const response = await fetch ( '/api/secrets/write' , {
2023-07-20 19:32:15 +02:00
method : 'POST' ,
headers : getRequestHeaders ( ) ,
body : JSON . stringify ( { key , value } ) ,
} ) ;
if ( response . ok ) {
const text = await response . text ( ) ;
if ( text == 'ok' ) {
secret _state [ key ] = true ;
updateSecretDisplay ( ) ;
}
}
} catch {
console . error ( 'Could not write secret value: ' , key ) ;
}
}
export async function readSecretState ( ) {
try {
2023-09-16 15:39:07 +02:00
const response = await fetch ( '/api/secrets/read' , {
2023-07-20 19:32:15 +02:00
method : 'POST' ,
headers : getRequestHeaders ( ) ,
} ) ;
if ( response . ok ) {
secret _state = await response . json ( ) ;
updateSecretDisplay ( ) ;
await checkOpenRouterAuth ( ) ;
}
} catch {
console . error ( 'Could not read secrets file' ) ;
}
}
2023-11-20 06:34:06 +01:00
export async function findSecret ( key ) {
try {
const response = await fetch ( '/api/secrets/find' , {
method : 'POST' ,
headers : getRequestHeaders ( ) ,
body : JSON . stringify ( { key } ) ,
} ) ;
if ( response . ok ) {
const data = await response . json ( ) ;
2023-12-02 20:11:06 +01:00
return data . value ;
2023-11-20 06:34:06 +01:00
}
} catch {
console . error ( 'Could not find secret value: ' , key ) ;
}
}
2023-07-20 19:32:15 +02:00
function authorizeOpenRouter ( ) {
const openRouterUrl = ` https://openrouter.ai/auth?callback_url= ${ encodeURIComponent ( location . origin ) } ` ;
location . href = openRouterUrl ;
}
async function checkOpenRouterAuth ( ) {
const params = new URLSearchParams ( location . search ) ;
if ( params . has ( 'code' ) ) {
const code = params . get ( 'code' ) ;
try {
2023-12-02 19:04:51 +01:00
const response = await fetch ( 'https://openrouter.ai/api/v1/auth/keys' , {
2023-07-20 19:32:15 +02:00
method : 'POST' ,
body : JSON . stringify ( { code } ) ,
} ) ;
if ( ! response . ok ) {
throw new Error ( 'OpenRouter exchange error' ) ;
}
const data = await response . json ( ) ;
if ( ! data || ! data . key ) {
throw new Error ( 'OpenRouter invalid response' ) ;
}
await writeSecret ( SECRET _KEYS . OPENROUTER , data . key ) ;
if ( secret _state [ SECRET _KEYS . OPENROUTER ] ) {
toastr . success ( 'OpenRouter token saved' ) ;
// Remove the code from the URL
const currentUrl = window . location . href ;
2023-12-02 19:04:51 +01:00
const urlWithoutSearchParams = currentUrl . split ( '?' ) [ 0 ] ;
window . history . pushState ( { } , '' , urlWithoutSearchParams ) ;
2023-07-20 19:32:15 +02:00
} else {
throw new Error ( 'OpenRouter token not saved' ) ;
}
} catch ( err ) {
toastr . error ( 'Could not verify OpenRouter token. Please try again.' ) ;
return ;
}
}
}
jQuery ( async ( ) => {
$ ( '#viewSecrets' ) . on ( 'click' , viewSecrets ) ;
$ ( document ) . on ( 'click' , '.clear-api-key' , clearSecret ) ;
$ ( document ) . on ( 'input' , Object . values ( INPUT _MAP ) . join ( ',' ) , function ( ) {
const id = $ ( this ) . attr ( 'id' ) ;
const value = $ ( this ) . val ( ) ;
const warningElement = $ ( ` [data-for=" ${ id } "] ` ) ;
warningElement . toggle ( value . length > 0 ) ;
} ) ;
$ ( '#openrouter_authorize' ) . on ( 'click' , authorizeOpenRouter ) ;
} ) ;