2023-04-30 12:16:48 +02:00
// Copyright (c) 2023 Julian Müller (ChaoticByte)
2023-05-18 15:34:34 +02:00
// Fetch configuration and initialize Eucalyptus Chat Frontend
fetch ( "/config" )
. then ( r => {
return r . json ( ) ;
} ) . then ( frontend _config => {
2023-04-30 12:16:48 +02:00
// Message Context
2023-05-18 15:34:34 +02:00
let conversation = [ frontend _config . profile . conversation _prefix ] ;
2023-04-30 12:16:48 +02:00
// Elements - Sidebar
2023-05-18 15:34:34 +02:00
const settingsLabelAssistantNameElement = document . getElementById ( "settings-label-assistant" ) ;
2023-04-30 12:16:48 +02:00
const settingsMaxTokensElement = document . getElementById ( "settings-max-tokens" ) ;
const settingsTemperatureElement = document . getElementById ( "settings-temperature" ) ;
const settingsTopPElement = document . getElementById ( "settings-top-p" ) ;
2023-05-18 11:54:57 +02:00
const settingsTopKElement = document . getElementById ( "settings-top-k" ) ;
const settingsRepeatPenaltyElement = document . getElementById ( "settings-repeat-penalty" ) ;
const settingsPresencePenaltyElement = document . getElementById ( "settings-presence-penalty" ) ;
const settingsFrequencyPenaltyElement = document . getElementById ( "settings-frequency-penalty" ) ;
2023-04-30 12:40:57 +02:00
const resetSettingsButtonElement = document . getElementById ( "reset-settings-btn" ) ;
2023-04-30 12:16:48 +02:00
const resetHistoryButtonElement = document . getElementById ( "reset-history-btn" ) ;
2023-05-18 15:34:34 +02:00
settingsLabelAssistantNameElement . innerText = frontend _config . profile . name ;
2023-04-30 12:16:48 +02:00
// Elements - Main
const messageHistoryContainer = document . getElementById ( "messages" ) ;
const textInputElement = document . getElementById ( "text-input" ) ;
const sendButtonElement = document . getElementById ( "send-btn" ) ;
// API requests
async function apiCompletion ( prompt , settings ) {
const bodyData = JSON . stringify ( {
"prompt" : prompt ,
2023-05-18 15:54:41 +02:00
"stop" : frontend _config . profile . stop _sequences ,
2023-04-30 12:16:48 +02:00
"max_tokens" : settings . max _tokens ,
"temperature" : settings . temperature ,
2023-05-18 11:54:57 +02:00
"top_p" : settings . top _p ,
"top_k" : settings . top _k ,
"repeat_penalty" : settings . repeat _penalty ,
"presence_penalty" : settings . presence _penalty ,
"frequency_penalty" : settings . frequency _penalty
2023-04-30 12:16:48 +02:00
} ) ;
const response = await fetch ( frontend _config . api _url + "/v1/completions" , {
method : "post" ,
cache : "no-cache" ,
body : bodyData ,
headers : {
"content-type" : "application/json"
}
} ) ;
const responseData = await response . json ( ) ;
return responseData [ "choices" ] [ 0 ] [ "text" ] ;
}
// User-defined settings
2023-04-30 12:40:57 +02:00
const defaultSettings = {
max _tokens : 100 ,
temperature : 0.8 ,
2023-05-18 11:54:57 +02:00
top _p : 0.95 ,
top _k : 40 ,
repeat _penalty : 1.1 ,
presence _penalty : 0.0 ,
frequency _penalty : 0.0
2023-04-30 12:40:57 +02:00
}
2023-04-30 12:16:48 +02:00
function getSettings ( ) {
return {
max _tokens : settingsMaxTokensElement . value ,
temperature : settingsTemperatureElement . value ,
2023-05-18 11:54:57 +02:00
top _p : settingsTopPElement . value ,
top _k : settingsTopKElement . value ,
repeat _penalty : settingsRepeatPenaltyElement . value ,
presence _penalty : settingsPresencePenaltyElement . value ,
frequency _penalty : settingsFrequencyPenaltyElement . value
2023-04-30 12:16:48 +02:00
}
}
2023-04-30 12:40:57 +02:00
function resetSettings ( ) {
settingsMaxTokensElement . value = defaultSettings . max _tokens ;
settingsTemperatureElement . value = defaultSettings . temperature ;
settingsTopPElement . value = defaultSettings . top _p ;
2023-05-18 11:54:57 +02:00
settingsTopKElement . value = defaultSettings . top _k ;
settingsRepeatPenaltyElement . value = defaultSettings . repeat _penalty ;
settingsPresencePenaltyElement . value = defaultSettings . presence _penalty ;
settingsFrequencyPenaltyElement . value = defaultSettings . frequency _penalty ;
2023-04-30 12:40:57 +02:00
}
2023-04-30 12:16:48 +02:00
// Chat
2023-05-18 15:34:34 +02:00
// Message Roles
const Roles = {
2023-04-30 12:16:48 +02:00
USER : {
name : "User" ,
class : "message-bg-user"
} ,
ASSISTANT : {
2023-05-18 15:34:34 +02:00
name : frontend _config . profile . name ,
2023-04-30 12:16:48 +02:00
class : "message-bg-assistant"
}
}
2023-05-18 15:34:34 +02:00
function addMessage ( message , role ) {
if ( role == Roles . USER ) {
conversation . push (
" " + frontend _config . profile . user _keyword + " "
+ message + " " + frontend _config . profile . assistant _keyword ) ;
2023-04-30 12:16:48 +02:00
}
else { conversation . push ( message ) ; }
// UI
2023-05-18 15:34:34 +02:00
let messageRoleElem = document . createElement ( "div" ) ;
messageRoleElem . classList . add ( "message-type" ) ;
messageRoleElem . innerText = role . name ;
2023-04-30 12:16:48 +02:00
let messageTextElem = document . createElement ( "div" ) ;
messageTextElem . classList . add ( "message-text" ) ;
messageTextElem . innerText = message ;
let messageElem = document . createElement ( "div" ) ;
messageElem . classList . add ( "message" ) ;
2023-05-18 15:34:34 +02:00
messageElem . classList . add ( role . class ) ;
messageElem . appendChild ( messageRoleElem ) ;
2023-04-30 12:16:48 +02:00
messageElem . appendChild ( messageTextElem ) ;
messageHistoryContainer . appendChild ( messageElem ) ;
2023-04-30 12:25:04 +02:00
messageHistoryContainer . scrollTo ( 0 , messageHistoryContainer . scrollHeight ) ;
2023-04-30 12:16:48 +02:00
}
2023-04-30 19:34:11 +02:00
function resizeInputElement ( ) {
// Calculate Line height
textInputElement . style . removeProperty ( "height" ) ;
let newHeight = textInputElement . scrollHeight ;
textInputElement . style . height = newHeight . toString ( ) + "px" ;
}
2023-04-30 12:16:48 +02:00
function disableInput ( ) {
2023-04-30 12:40:57 +02:00
settingsMaxTokensElement . disabled = true ;
settingsTemperatureElement . disabled = true ;
settingsTopPElement . disabled = true ;
2023-05-18 11:54:57 +02:00
settingsTopKElement . disabled = true ;
settingsRepeatPenaltyElement . disabled = true ;
settingsPresencePenaltyElement . disabled = true ;
settingsFrequencyPenaltyElement . disabled = true ;
2023-04-30 12:40:57 +02:00
resetSettingsButtonElement . disabled = true ;
resetHistoryButtonElement . disabled = true ;
2023-04-30 12:16:48 +02:00
sendButtonElement . disabled = true ;
textInputElement . disabled = true ;
}
function enableInput ( ) {
2023-04-30 12:40:57 +02:00
settingsMaxTokensElement . disabled = false ;
settingsTemperatureElement . disabled = false ;
settingsTopPElement . disabled = false ;
2023-05-18 11:54:57 +02:00
settingsTopKElement . disabled = false ;
settingsRepeatPenaltyElement . disabled = false ;
settingsPresencePenaltyElement . disabled = false ;
settingsFrequencyPenaltyElement . disabled = false ;
2023-04-30 12:40:57 +02:00
resetSettingsButtonElement . disabled = false ;
resetHistoryButtonElement . disabled = false ;
sendButtonElement . disabled = false ;
2023-04-30 12:16:48 +02:00
textInputElement . disabled = false ;
// focus text input
textInputElement . focus ( ) ;
}
async function chat ( ) {
2023-05-18 15:34:34 +02:00
disableInput ( ) ;
let input = textInputElement . value . trim ( ) ;
if ( input == "" ) {
enableInput ( ) ;
2023-04-30 12:16:48 +02:00
}
else {
2023-05-18 15:34:34 +02:00
textInputElement . value = "" ;
resizeInputElement ( ) ;
addMessage ( input , Roles . USER ) ;
let prompt = conversation . join ( "" ) ;
let settings = getSettings ( ) ;
apiCompletion ( prompt , settings ) . then ( r => {
addMessage ( r , Roles . ASSISTANT ) ;
2023-04-30 12:16:48 +02:00
enableInput ( ) ;
2023-05-18 15:34:34 +02:00
} ) ;
2023-04-30 12:16:48 +02:00
}
}
function resetHistory ( ) {
2023-05-18 15:34:34 +02:00
conversation = [ frontend _config . profile . conversation _prefix ] ;
2023-04-30 12:16:48 +02:00
messageHistoryContainer . innerText = "" ;
}
// Event Listeners
2023-04-30 19:34:11 +02:00
2023-04-30 12:40:57 +02:00
resetSettingsButtonElement . addEventListener ( "click" , resetSettings ) ;
2023-04-30 12:16:48 +02:00
resetHistoryButtonElement . addEventListener ( "click" , resetHistory ) ;
sendButtonElement . addEventListener ( "click" , chat ) ;
2023-04-30 19:34:11 +02:00
2023-04-30 12:16:48 +02:00
textInputElement . addEventListener ( "keypress" , e => {
// Send via Ctrl+Enter
if ( e . key == "Enter" && e . ctrlKey ) {
chat ( ) ;
}
} ) ;
2023-04-30 19:34:11 +02:00
textInputElement . addEventListener ( "input" , resizeInputElement ) ;
2023-05-18 10:32:31 +02:00
resizeInputElement ( ) ;
2023-04-30 12:16:48 +02:00
2023-05-18 15:34:34 +02:00
} ) ;