2023-07-20 19:32:15 +02:00
import {
2023-09-28 18:10:00 +02:00
api _server _textgenerationwebui ,
2023-07-20 19:32:15 +02:00
getRequestHeaders ,
getStoppingStrings ,
max _context ,
saveSettingsDebounced ,
2023-07-23 22:52:31 +02:00
setGenerationParamsFromPreset ,
2023-07-20 19:32:15 +02:00
} from "../script.js" ;
2023-09-28 18:10:00 +02:00
import { loadMancerModels } from "./mancer-settings.js" ;
2023-07-20 19:32:15 +02:00
2023-08-07 22:46:32 +02:00
import {
power _user ,
} from "./power-user.js" ;
2023-09-27 21:09:09 +02:00
import { getTextTokens , tokenizers } from "./tokenizers.js" ;
2023-09-28 18:10:00 +02:00
import { delay , onlyUnique } from "./utils.js" ;
2023-08-07 22:46:32 +02:00
2023-07-20 19:32:15 +02:00
export {
textgenerationwebui _settings ,
loadTextGenSettings ,
generateTextGenWithStreaming ,
2023-08-03 12:07:54 +02:00
formatTextGenURL ,
2023-07-20 19:32:15 +02:00
}
2023-09-28 18:10:00 +02:00
export const textgen _types = {
OOBA : 'ooba' ,
MANCER : 'mancer' ,
APHRODITE : 'aphrodite' ,
} ;
2023-07-23 01:09:03 +02:00
const textgenerationwebui _settings = {
2023-07-20 19:32:15 +02:00
temp : 0.7 ,
top _p : 0.5 ,
top _k : 40 ,
top _a : 0 ,
tfs : 1 ,
epsilon _cutoff : 0 ,
eta _cutoff : 0 ,
typical _p : 1 ,
rep _pen : 1.2 ,
2023-07-22 00:38:35 +02:00
rep _pen _range : 0 ,
2023-07-20 19:32:15 +02:00
no _repeat _ngram _size : 0 ,
penalty _alpha : 0 ,
num _beams : 1 ,
length _penalty : 1 ,
min _length : 0 ,
encoder _rep _pen : 1 ,
do _sample : true ,
early _stopping : false ,
seed : - 1 ,
preset : 'Default' ,
add _bos _token : true ,
stopping _strings : [ ] ,
truncation _length : 2048 ,
ban _eos _token : false ,
skip _special _tokens : true ,
streaming : false ,
streaming _url : 'ws://127.0.0.1:5005/api/v1/stream' ,
mirostat _mode : 0 ,
mirostat _tau : 5 ,
mirostat _eta : 0.1 ,
2023-08-14 12:06:20 +02:00
guidance _scale : 1 ,
negative _prompt : '' ,
2023-09-27 21:09:09 +02:00
grammar _string : '' ,
banned _tokens : '' ,
2023-09-28 18:10:00 +02:00
type : textgen _types . OOBA ,
2023-07-20 19:32:15 +02:00
} ;
2023-10-05 12:10:41 +02:00
export let textgenerationwebui _banned _in _macros = [ ] ;
2023-07-23 22:52:31 +02:00
export let textgenerationwebui _presets = [ ] ;
export let textgenerationwebui _preset _names = [ ] ;
2023-07-20 19:32:15 +02:00
const setting _names = [
"temp" ,
"rep_pen" ,
2023-07-22 00:38:35 +02:00
"rep_pen_range" ,
2023-07-20 19:32:15 +02:00
"no_repeat_ngram_size" ,
"top_k" ,
"top_p" ,
"top_a" ,
"tfs" ,
"epsilon_cutoff" ,
"eta_cutoff" ,
"typical_p" ,
"penalty_alpha" ,
"num_beams" ,
"length_penalty" ,
"min_length" ,
"encoder_rep_pen" ,
"do_sample" ,
"early_stopping" ,
"seed" ,
"add_bos_token" ,
"ban_eos_token" ,
"skip_special_tokens" ,
"streaming" ,
"streaming_url" ,
"mirostat_mode" ,
"mirostat_tau" ,
"mirostat_eta" ,
2023-08-14 12:06:20 +02:00
"guidance_scale" ,
"negative_prompt" ,
2023-09-27 21:09:09 +02:00
"grammar_string" ,
"banned_tokens" ,
2023-07-20 19:32:15 +02:00
] ;
function selectPreset ( name ) {
const preset = textgenerationwebui _presets [ textgenerationwebui _preset _names . indexOf ( name ) ] ;
if ( ! preset ) {
return ;
}
textgenerationwebui _settings . preset = name ;
for ( const name of setting _names ) {
const value = preset [ name ] ;
setSettingByName ( name , value , true ) ;
}
2023-07-23 22:52:31 +02:00
setGenerationParamsFromPreset ( preset ) ;
2023-07-20 19:32:15 +02:00
saveSettingsDebounced ( ) ;
}
2023-08-08 22:12:03 +02:00
function formatTextGenURL ( value , use _mancer ) {
2023-08-03 12:07:54 +02:00
try {
const url = new URL ( value ) ;
2023-08-07 22:46:32 +02:00
if ( ! power _user . relaxed _api _urls ) {
2023-08-08 22:12:03 +02:00
if ( use _mancer ) { // If Mancer is in use, only require the URL to *end* with `/api`.
if ( ! url . pathname . endsWith ( '/api' ) ) {
return null ;
}
} else {
url . pathname = '/api' ;
}
2023-08-03 12:07:54 +02:00
}
2023-08-07 22:46:32 +02:00
return url . toString ( ) ;
2023-08-07 23:10:05 +02:00
} catch { } // Just using URL as a validation check
2023-08-03 12:07:54 +02:00
return null ;
}
2023-07-20 19:32:15 +02:00
function convertPresets ( presets ) {
2023-10-05 12:10:41 +02:00
return Array . isArray ( presets ) ? presets . map ( ( p ) => JSON . parse ( p ) ) : [ ] ;
2023-07-20 19:32:15 +02:00
}
2023-09-27 21:09:09 +02:00
/ * *
* @ returns { string } String with comma - separated banned token IDs
* /
function getCustomTokenBans ( ) {
2023-10-05 12:10:41 +02:00
if ( ! textgenerationwebui _settings . banned _tokens && ! textgenerationwebui _banned _in _macros . length ) {
2023-09-27 21:09:09 +02:00
return '' ;
}
const result = [ ] ;
2023-10-05 12:10:41 +02:00
const sequences = textgenerationwebui _settings . banned _tokens
. split ( '\n' )
. concat ( textgenerationwebui _banned _in _macros )
. filter ( x => x . length > 0 )
. filter ( onlyUnique ) ;
//debug
if ( textgenerationwebui _banned _in _macros . length ) {
console . log ( "=== Found banned word sequences in the macros:" , textgenerationwebui _banned _in _macros , "Resulting array of banned sequences (will be used this generation turn):" , sequences ) ;
}
//clean old temporary bans found in macros before, for the next generation turn.
textgenerationwebui _banned _in _macros = [ ] ;
2023-09-27 21:09:09 +02:00
for ( const line of sequences ) {
// Raw token ids, JSON serialized
if ( line . startsWith ( '[' ) && line . endsWith ( ']' ) ) {
try {
const tokens = JSON . parse ( line ) ;
if ( Array . isArray ( tokens ) && tokens . every ( t => Number . isInteger ( t ) ) ) {
result . push ( ... tokens ) ;
} else {
throw new Error ( 'Not an array of integers' ) ;
}
} catch ( err ) {
console . log ( ` Failed to parse bad word token list: ${ line } ` , err ) ;
}
} else {
try {
const tokens = getTextTokens ( tokenizers . LLAMA , line ) ;
result . push ( ... tokens ) ;
} catch {
console . log ( ` Could not tokenize raw text: ${ line } ` ) ;
}
}
}
return result . filter ( onlyUnique ) . map ( x => String ( x ) ) . join ( ',' ) ;
}
2023-07-20 19:32:15 +02:00
function loadTextGenSettings ( data , settings ) {
textgenerationwebui _presets = convertPresets ( data . textgenerationwebui _presets ) ;
textgenerationwebui _preset _names = data . textgenerationwebui _preset _names ? ? [ ] ;
Object . assign ( textgenerationwebui _settings , settings . textgenerationwebui _settings ? ? { } ) ;
2023-09-28 18:10:00 +02:00
if ( settings . api _use _mancer _webui ) {
textgenerationwebui _settings . type = textgen _types . MANCER ;
}
2023-07-20 19:32:15 +02:00
for ( const name of textgenerationwebui _preset _names ) {
const option = document . createElement ( 'option' ) ;
option . value = name ;
option . innerText = name ;
$ ( '#settings_preset_textgenerationwebui' ) . append ( option ) ;
}
if ( textgenerationwebui _settings . preset ) {
$ ( '#settings_preset_textgenerationwebui' ) . val ( textgenerationwebui _settings . preset ) ;
}
for ( const i of setting _names ) {
const value = textgenerationwebui _settings [ i ] ;
setSettingByName ( i , value ) ;
}
2023-09-28 18:10:00 +02:00
$ ( '#textgen_type' ) . val ( textgenerationwebui _settings . type ) . trigger ( 'change' ) ;
}
export function isMancer ( ) {
return textgenerationwebui _settings . type === textgen _types . MANCER ;
}
export function isAphrodite ( ) {
return textgenerationwebui _settings . type === textgen _types . APHRODITE ;
}
2023-10-08 22:42:28 +02:00
export function isOoba ( ) {
return textgenerationwebui _settings . type === textgen _types . OOBA ;
}
2023-09-28 18:10:00 +02:00
export function getTextGenUrlSourceId ( ) {
switch ( textgenerationwebui _settings . type ) {
case textgen _types . MANCER :
return "#mancer_api_url_text" ;
case textgen _types . OOBA :
return "#textgenerationwebui_api_url_text" ;
case textgen _types . APHRODITE :
return "#aphrodite_api_url_text" ;
}
2023-07-20 19:32:15 +02:00
}
2023-09-28 18:10:00 +02:00
jQuery ( function ( ) {
$ ( '#textgen_type' ) . on ( 'change' , function ( ) {
const type = String ( $ ( this ) . val ( ) ) ;
textgenerationwebui _settings . type = type ;
$ ( '[data-tg-type]' ) . each ( function ( ) {
const tgType = $ ( this ) . attr ( 'data-tg-type' ) ;
if ( tgType == type ) {
$ ( this ) . show ( ) ;
} else {
$ ( this ) . hide ( ) ;
}
} ) ;
if ( isMancer ( ) ) {
loadMancerModels ( ) ;
}
saveSettingsDebounced ( ) ;
$ ( '#api_button_textgenerationwebui' ) . trigger ( 'click' ) ;
} ) ;
2023-09-27 21:09:09 +02:00
$ ( '#settings_preset_textgenerationwebui' ) . on ( 'change' , function ( ) {
2023-07-20 19:32:15 +02:00
const presetName = $ ( this ) . val ( ) ;
selectPreset ( presetName ) ;
} ) ;
for ( const i of setting _names ) {
$ ( ` # ${ i } _textgenerationwebui ` ) . attr ( "x-setting-id" , i ) ;
$ ( document ) . on ( "input" , ` # ${ i } _textgenerationwebui ` , function ( ) {
const isCheckbox = $ ( this ) . attr ( 'type' ) == 'checkbox' ;
2023-08-14 12:06:20 +02:00
const isText = $ ( this ) . attr ( 'type' ) == 'text' || $ ( this ) . is ( 'textarea' ) ;
2023-07-20 19:32:15 +02:00
const id = $ ( this ) . attr ( "x-setting-id" ) ;
if ( isCheckbox ) {
const value = $ ( this ) . prop ( 'checked' ) ;
textgenerationwebui _settings [ id ] = value ;
}
else if ( isText ) {
const value = $ ( this ) . val ( ) ;
textgenerationwebui _settings [ id ] = value ;
}
else {
2023-08-22 18:35:56 +02:00
const value = Number ( $ ( this ) . val ( ) ) ;
2023-07-20 19:32:15 +02:00
$ ( ` # ${ id } _counter_textgenerationwebui ` ) . text ( value . toFixed ( 2 ) ) ;
2023-08-22 18:35:56 +02:00
textgenerationwebui _settings [ id ] = value ;
2023-07-20 19:32:15 +02:00
}
saveSettingsDebounced ( ) ;
} ) ;
}
} )
function setSettingByName ( i , value , trigger ) {
if ( value === null || value === undefined ) {
return ;
}
const isCheckbox = $ ( ` # ${ i } _textgenerationwebui ` ) . attr ( 'type' ) == 'checkbox' ;
2023-08-14 12:06:20 +02:00
const isText = $ ( ` # ${ i } _textgenerationwebui ` ) . attr ( 'type' ) == 'text' || $ ( ` # ${ i } _textgenerationwebui ` ) . is ( 'textarea' ) ;
2023-07-20 19:32:15 +02:00
if ( isCheckbox ) {
const val = Boolean ( value ) ;
$ ( ` # ${ i } _textgenerationwebui ` ) . prop ( 'checked' , val ) ;
}
else if ( isText ) {
$ ( ` # ${ i } _textgenerationwebui ` ) . val ( value ) ;
}
else {
const val = parseFloat ( value ) ;
$ ( ` # ${ i } _textgenerationwebui ` ) . val ( val ) ;
$ ( ` # ${ i } _counter_textgenerationwebui ` ) . text ( val . toFixed ( 2 ) ) ;
}
if ( trigger ) {
$ ( ` # ${ i } _textgenerationwebui ` ) . trigger ( 'input' ) ;
}
}
async function generateTextGenWithStreaming ( generate _data , signal ) {
2023-09-28 18:10:00 +02:00
let streamingUrl = textgenerationwebui _settings . streaming _url ;
if ( isMancer ( ) ) {
streamingUrl = api _server _textgenerationwebui . replace ( "http" , "ws" ) + "/v1/stream" ;
}
2023-10-05 12:10:41 +02:00
if ( isAphrodite ( ) ) {
2023-09-28 18:10:00 +02:00
streamingUrl = api _server _textgenerationwebui ;
}
2023-10-08 22:42:28 +02:00
if ( isMancer ( ) || isOoba ( ) ) {
try {
const parsedUrl = new URL ( streamingUrl ) ;
if ( parsedUrl . protocol !== 'ws:' && parsedUrl . protocol !== 'wss:' ) {
throw new Error ( 'Invalid protocol' ) ;
}
} catch {
toastr . error ( 'Invalid URL for streaming. Make sure it starts with ws:// or wss://' ) ;
return async function * ( ) { throw new Error ( 'Invalid URL for streaming.' ) ; }
}
}
2023-07-20 19:32:15 +02:00
const response = await fetch ( '/generate_textgenerationwebui' , {
headers : {
... getRequestHeaders ( ) ,
2023-08-22 18:35:56 +02:00
'X-Response-Streaming' : String ( true ) ,
2023-09-28 18:10:00 +02:00
'X-Streaming-URL' : streamingUrl ,
2023-07-20 19:32:15 +02:00
} ,
body : JSON . stringify ( generate _data ) ,
method : 'POST' ,
signal : signal ,
} ) ;
return async function * streamData ( ) {
const decoder = new TextDecoder ( ) ;
const reader = response . body . getReader ( ) ;
let getMessage = '' ;
while ( true ) {
const { done , value } = await reader . read ( ) ;
let response = decoder . decode ( value ) ;
2023-09-28 18:10:00 +02:00
if ( isAphrodite ( ) ) {
const events = response . split ( '\n\n' ) ;
2023-07-20 19:32:15 +02:00
2023-09-28 18:10:00 +02:00
for ( const event of events ) {
if ( event . length == 0 ) {
continue ;
}
try {
const { results } = JSON . parse ( event ) ;
2023-10-05 12:10:41 +02:00
2023-09-28 18:10:00 +02:00
if ( Array . isArray ( results ) && results . length > 0 ) {
getMessage = results [ 0 ] . text ;
yield getMessage ;
// unhang UI thread
await delay ( 1 ) ;
}
} catch {
// Ignore
}
}
if ( done ) {
return ;
}
} else {
getMessage += response ;
2023-10-05 12:10:41 +02:00
2023-09-28 18:10:00 +02:00
if ( done ) {
return ;
}
2023-10-05 12:10:41 +02:00
2023-09-28 18:10:00 +02:00
yield getMessage ;
}
2023-07-20 19:32:15 +02:00
}
}
}
2023-08-23 16:44:38 +02:00
export function getTextGenGenerationData ( finalPrompt , this _amount _gen , isImpersonate , cfgValues ) {
2023-07-20 19:32:15 +02:00
return {
2023-08-23 16:44:38 +02:00
'prompt' : finalPrompt ,
2023-07-20 19:32:15 +02:00
'max_new_tokens' : this _amount _gen ,
'do_sample' : textgenerationwebui _settings . do _sample ,
'temperature' : textgenerationwebui _settings . temp ,
'top_p' : textgenerationwebui _settings . top _p ,
'typical_p' : textgenerationwebui _settings . typical _p ,
'repetition_penalty' : textgenerationwebui _settings . rep _pen ,
2023-07-22 00:38:35 +02:00
'repetition_penalty_range' : textgenerationwebui _settings . rep _pen _range ,
2023-07-20 19:32:15 +02:00
'encoder_repetition_penalty' : textgenerationwebui _settings . encoder _rep _pen ,
'top_k' : textgenerationwebui _settings . top _k ,
'min_length' : textgenerationwebui _settings . min _length ,
'no_repeat_ngram_size' : textgenerationwebui _settings . no _repeat _ngram _size ,
'num_beams' : textgenerationwebui _settings . num _beams ,
'penalty_alpha' : textgenerationwebui _settings . penalty _alpha ,
'length_penalty' : textgenerationwebui _settings . length _penalty ,
'early_stopping' : textgenerationwebui _settings . early _stopping ,
2023-08-22 18:35:56 +02:00
'guidance_scale' : cfgValues ? . guidanceScale ? . value ? ? textgenerationwebui _settings . guidance _scale ? ? 1 ,
'negative_prompt' : cfgValues ? . negativePrompt ? ? textgenerationwebui _settings . negative _prompt ? ? '' ,
2023-07-20 19:32:15 +02:00
'seed' : textgenerationwebui _settings . seed ,
'add_bos_token' : textgenerationwebui _settings . add _bos _token ,
2023-09-06 13:19:29 +02:00
'stopping_strings' : getStoppingStrings ( isImpersonate ) ,
2023-07-20 19:32:15 +02:00
'truncation_length' : max _context ,
'ban_eos_token' : textgenerationwebui _settings . ban _eos _token ,
'skip_special_tokens' : textgenerationwebui _settings . skip _special _tokens ,
'top_a' : textgenerationwebui _settings . top _a ,
'tfs' : textgenerationwebui _settings . tfs ,
'epsilon_cutoff' : textgenerationwebui _settings . epsilon _cutoff ,
'eta_cutoff' : textgenerationwebui _settings . eta _cutoff ,
'mirostat_mode' : textgenerationwebui _settings . mirostat _mode ,
'mirostat_tau' : textgenerationwebui _settings . mirostat _tau ,
'mirostat_eta' : textgenerationwebui _settings . mirostat _eta ,
2023-09-27 21:09:09 +02:00
'grammar_string' : textgenerationwebui _settings . grammar _string ,
'custom_token_bans' : getCustomTokenBans ( ) ,
2023-10-11 16:56:52 +02:00
'use_mancer' : isMancer ( ) ,
'use_aphrodite' : isAphrodite ( ) ,
2023-07-20 19:32:15 +02:00
} ;
}