multiplayer error handling

This commit is contained in:
Concedo 2024-11-19 23:31:48 +08:00
parent 1b663e10c8
commit a439dcb38e
2 changed files with 254 additions and 13 deletions

View file

@ -12,7 +12,7 @@ Current version indicated by LITEVER below.
-->
<script>
const LITEVER = 187;
const LITEVER = 188;
const urlParams = new URLSearchParams(window.location.search);
var localflag = true;
const STORAGE_PREFIX = (localflag?"e_":"")+"kaihordewebui_";
@ -636,6 +636,16 @@ Current version indicated by LITEVER below.
color: #d3e7ff;
}
.color_orangeurl {
color: #f7a223;
}
.color_orangeurl:hover {
color: #ffe8d6;
}
.color_orangeurl:focus {
color: #ffedd3;
}
.color_orange {
color: #f7a223;
}
@ -4241,6 +4251,7 @@ Current version indicated by LITEVER below.
const poll_interval_base_text = 500;
const poll_interval_base_img = 3800;
const poll_interval_idle = 1000;
const poll_interval_multiplayer = 2500; //every 2.5s
const text_hordes = [
{
@ -4296,6 +4307,9 @@ Current version indicated by LITEVER below.
const koboldcpp_logprobs_endpoint = "/api/extra/last_logprobs";
const koboldcpp_truemaxctxlen_endpoint = "/api/extra/true_max_context_length";
const koboldcpp_preloadstory_endpoint = "/api/extra/preloadstory";
const koboldcpp_multiplayer_check_endpoint = "/api/extra/multiplayer/status";
const koboldcpp_multiplayer_fetch_endpoint = "/api/extra/multiplayer/getstory";
const koboldcpp_multiplayer_submit_endpoint = "/api/extra/multiplayer/setstory";
const koboldcpp_transcribe_endpoint = "/api/extra/transcribe";
const koboldcpp_tokenize_endpoint = "/api/extra/tokencount";
const koboldcpp_perf_endpoint = "/api/extra/perf";
@ -4432,6 +4446,12 @@ Current version indicated by LITEVER below.
var koboldcpp_version = ""; //detect if we are using koboldcpp
var koboldcpp_version_obj = {};
var koboldcpp_has_vision = false;
var koboldcpp_has_multiplayer = false;
var multiplayer_active = false;
var multiplayer_last_turn_major = 0;
var multiplayer_last_turn_minor = 0;
var schedule_multiplayer_minor_change = false;
var schedule_multiplayer_major_change = false;
var last_request_str = "No Requests Available"; //full context of last submitted request
var last_response_obj = null;
var lastcheckgenkey = ""; //for checking polled-streaming unique id when generating in kcpp
@ -4983,6 +5003,7 @@ Current version indicated by LITEVER below.
//can we find the model that's used? if yes load it, otherwise load the first one
if (mdls.length > 0)
{
selected_models = []; //force clear is needed, as it can get overwritten
for (var i = 0; i < mdls.length; ++i) {
let skipignored = false;
for(let k=0;k<ignoredmodels.length;++k)
@ -5033,6 +5054,7 @@ Current version indicated by LITEVER below.
setInterval(poll_pending_response, poll_interval_base_text);
setInterval(poll_image_db, poll_interval_base_img); //check images every Xs
setInterval(poll_idle_responses, poll_interval_idle); //a basic update loop for idle responses
setInterval(poll_multiplayer, poll_interval_multiplayer); //a basic update loop for idle responses
attempt_connect(false);
@ -5224,6 +5246,7 @@ Current version indicated by LITEVER below.
}
}
document.body.classList.add("connected");
document.getElementById("multiplayerstatus").innerText = "";
document.getElementById("connectstatus").innerHTML = "AI Horde";
document.getElementById("connectstatus").classList.add("color_offwhite");
render_gametext(false);
@ -5238,6 +5261,7 @@ Current version indicated by LITEVER below.
else {
msgbox("Failed to connect to AI Horde Service!\nPlease check your network connection.<br><br>You may still be able to connect to an alternative service, <a href='#' class='color_blueurl' onclick='hide_popups();display_endpoint_container()'>click here to view options</a>.","Error Encountered",true);
document.body.classList.remove("connected");
document.getElementById("multiplayerstatus").innerText = "";
document.getElementById("connectstatus").innerHTML = "Offline Mode";
document.getElementById("connectstatus").classList.remove("color_offwhite");
render_gametext(false);
@ -5899,6 +5923,10 @@ Current version indicated by LITEVER below.
{
return (custom_kobold_endpoint!="" && koboldcpp_version && koboldcpp_version!="" && compare_version_str(koboldcpp_version, "1.74") >= 0);
}
function is_using_kcpp_with_multiplayer()
{
return (custom_kobold_endpoint!="" && koboldcpp_version && koboldcpp_version!="" && compare_version_str(koboldcpp_version, "1.78") >= 0 && koboldcpp_has_multiplayer);
}
//0 is none, 1 is pseudostreaming, 2 is true poll-streaming, 3 is sse-streaming
@ -6560,6 +6588,7 @@ Current version indicated by LITEVER below.
restart_new_game(false);
gametext_arr.push(text);
render_gametext(true);
sync_multiplayer(true);
}, null, true)
} else {
msgbox("Could not load selected file. Is it valid?");
@ -6587,10 +6616,10 @@ Current version indicated by LITEVER below.
return is_kai;
}
function kai_json_load(storyobj, force_load_settngs)
function kai_json_load(storyobj, force_load_settings, ignore_multiplayer_sync)
{
//either show popup or just proceed to load
handle_advload_popup((localsettings.show_advanced_load && !force_load_settngs),()=>
handle_advload_popup((localsettings.show_advanced_load && !force_load_settings),()=>
{
let old_gametext_arr = gametext_arr;
let old_current_anote = current_anote;
@ -6845,7 +6874,7 @@ Current version indicated by LITEVER below.
migrate_old_images_in_gametext();
//prompt to import settings
if (localsettings.show_advanced_load && !force_load_settngs)
if (localsettings.show_advanced_load && !force_load_settings)
{
import_settings(
document.getElementById("advset_mainstory").checked,
@ -6860,6 +6889,10 @@ Current version indicated by LITEVER below.
import_settings(true, true, true, true, true, true);
}
render_gametext(true);
if(!ignore_multiplayer_sync) //we don't want an infinite loop
{
sync_multiplayer(true);
}
});
}
@ -7041,6 +7074,7 @@ Current version indicated by LITEVER below.
}
}
render_gametext(true);
sync_multiplayer(true);
}
if(localsettings.import_tavern_prompt)
@ -7082,6 +7116,7 @@ Current version indicated by LITEVER below.
localsettings.opmode = 3;
localsettings.gui_type_chat = 2;
render_gametext(true);
sync_multiplayer(true);
}
function nai_json_load(obj)
{
@ -7104,6 +7139,7 @@ Current version indicated by LITEVER below.
current_wi = load_nai_wi(obj.lorebook);
}
render_gametext(true);
sync_multiplayer(true);
}
function load_nai_wi(obj)
{
@ -7652,6 +7688,93 @@ Current version indicated by LITEVER below.
}
}
function leave_multiplayer()
{
multiplayer_active = false;
multiplayer_last_turn_major = 0;
multiplayer_last_turn_minor = 0;
schedule_multiplayer_minor_change = false;
schedule_multiplayer_major_change = false;
render_gametext(false);
}
function join_multiplayer()
{
if(is_using_kcpp_with_multiplayer())
{
inputBox(`You're about to enter a Multiplayer Session.<br><br><span class="color_red">Note that stories or messages sent by other users are <b>unfiltered</b>, and may contain <b>offensive or disturbing content</b>. You assume full responsibility and participate at your own discretion.</span><br><br>Enter a unique nickname to use for chat mode (only yourself), or leave it blank to share the same common chatname with other users.`,"Join Multiplayer - Override Chat Nickname?","","[No Override]", ()=>{
let userinput = getInputBoxValue().trim();
multiplayer_active = true;
multiplayer_last_turn_major = 0;
multiplayer_last_turn_minor = 0;
schedule_multiplayer_minor_change = false;
schedule_multiplayer_major_change = false;
render_gametext(false);
},true);
}else{
leave_multiplayer();
msgbox("Multiplayer is not available or not enabled on this backend","No Multiplayer Detected");
}
}
function sync_multiplayer(fullupdate)
{
if(!is_using_kcpp_with_multiplayer() || !multiplayer_active)
{
schedule_multiplayer_minor_change = false;
schedule_multiplayer_major_change = false;
return;
}
schedule_multiplayer_minor_change = true;
if(fullupdate)
{
schedule_multiplayer_major_change = true;
}
}
function submit_multiplayer(fullupdate)
{
if(!is_using_kcpp_with_multiplayer() || !multiplayer_active)
{
schedule_multiplayer_minor_change = false;
schedule_multiplayer_major_change = false;
return;
}
let subdata = generate_compressed_story(true,true,true);
fetch(apply_proxy_url(custom_kobold_endpoint + koboldcpp_multiplayer_submit_endpoint),
{
method: 'POST',
headers: get_kobold_header(),
body: JSON.stringify({
"fullupdate": fullupdate,
"data": subdata,
})
})
.then(response => response.json())
.then(vals => {
if(vals && vals.success)
{
let expected_major = (fullupdate?(1+multiplayer_last_turn_major):multiplayer_last_turn_major);
let expected_minor = (fullupdate?0:(multiplayer_last_turn_minor+1));
if(vals.turn_major==expected_major && vals.turn_minor==expected_minor)
{
//if nobody else updated, disregard our own updates
multiplayer_last_turn_major = expected_major;
multiplayer_last_turn_minor = expected_minor;
}
}else{
leave_multiplayer();
msgbox("Multiplayer Error: " + JSON.stringify(vals),"Disconnected from Multiplayer");
}
}).catch(error => {
leave_multiplayer();
msgbox("Multiplayer Error: " + error,"Disconnected from Multiplayer");
console.log("Failed to access multiplayer status: " + error);
});
}
function character_creator()
{
hide_popups();
@ -7704,6 +7827,7 @@ Current version indicated by LITEVER below.
localsettings.gui_type_chat = 2;
localsettings.chatopponent = chatopponent;
render_gametext();
sync_multiplayer(true);
}
tempAestheticInstructUISettings = null;
hide_popups();
@ -7825,6 +7949,7 @@ Current version indicated by LITEVER below.
}
render_gametext(true);
sync_multiplayer(true);
}
function togglescenarioautopick()
{
@ -7971,6 +8096,10 @@ Current version indicated by LITEVER below.
let entry = `<button type="button" name="`+i+`" class="scenarioitem `+bcolor+` btn btn-primary" onclick="return click_scenario(`+i+`)">`+curr.title+`</button>`;
scenarios += entry;
}
if(is_using_kcpp_with_multiplayer())
{
scenarios += `<button type="button" name="" class="scenarioitem purple btn btn-primary" onclick="hide_popups();join_multiplayer()">Join Multiplayer</button>`;
}
document.getElementById("scenariogrid").innerHTML = scenarios;
document.getElementById("scenariodesc").innerText = "No Scenario Selected";
@ -8806,7 +8935,7 @@ Current version indicated by LITEVER below.
function togglepalmmodel()
{
let mdlname = document.getElementById("custom_palm_model").value;
if(mdlname=="gemini-1.5-pro-latest" || mdlname=="gemini-1.5-pro-001" || mdlname=="gemini-1.5-pro-002" || mdlname=="gemini-1.5-flash-latest" || mdlname=="gemini-1.5-pro-exp-0801" || mdlname=="gemini-1.5-pro-exp-0827")
if(mdlname=="gemini-1.5-pro-latest" || mdlname=="gemini-1.5-pro-001" || mdlname=="gemini-1.5-pro-002" || mdlname=="gemini-1.5-flash-latest" || mdlname=="gemini-1.5-pro-exp-0801" || mdlname=="gemini-1.5-pro-exp-0827" || mdlname=="gemini-exp-1114")
{
document.getElementById("gemini_system_instruction").classList.remove("hidden");
if(localsettings.saved_palm_jailbreak=="")
@ -9260,6 +9389,7 @@ Current version indicated by LITEVER below.
document.body.classList.add("connected");
document.getElementById("connectstatus").classList.add("color_offwhite");
}
document.getElementById("multiplayerstatus").innerText = "";
document.getElementById("connectstatus").innerHTML = "KoboldAI Endpoint";
render_gametext();
@ -9316,9 +9446,11 @@ Current version indicated by LITEVER below.
koboldcpp_version_obj = data;
koboldcpp_version = data.version;
console.log("KoboldCpp Detected: " + koboldcpp_version);
document.getElementById("multiplayerstatus").innerText = "";
document.getElementById("connectstatus").innerHTML = (`<span style='cursor: pointer;' onclick='fetch_koboldcpp_perf()'>KoboldCpp ${koboldcpp_version}</a>`);
koboldcpp_has_vision = (data.vision?true:false);
koboldcpp_has_whisper = (data.transcribe?true:false);
koboldcpp_has_multiplayer = (data.multiplayer?true:false);
let has_password = (data.protected?true:false);
let has_txt2img = (data.txt2img?true:false);
let no_txt_model = (mdlname=="inactive");
@ -9363,6 +9495,12 @@ Current version indicated by LITEVER below.
close_welcome_panel(false);
kai_json_load(tmpstory, false);
}
}else{
if(koboldcpp_has_multiplayer)
{
//force refresh
render_gametext(false);
}
}
}).catch(error => {
console.log("Failed to get preloaded story: " + error);
@ -9471,6 +9609,7 @@ Current version indicated by LITEVER below.
custom_kobold_endpoint = "";
if(localflag)
{
document.getElementById("multiplayerstatus").innerText = "";
document.getElementById("connectstatus").innerHTML = "Offline Mode";
}
render_gametext();
@ -9549,6 +9688,7 @@ Current version indicated by LITEVER below.
document.body.classList.add("connected");
document.getElementById("connectstatus").classList.add("color_offwhite");
}
document.getElementById("multiplayerstatus").innerText = "";
document.getElementById("connectstatus").innerHTML = "OpenAI Endpoint";
render_gametext(true);
}
@ -9599,6 +9739,7 @@ Current version indicated by LITEVER below.
document.body.classList.add("connected");
document.getElementById("connectstatus").classList.add("color_offwhite");
}
document.getElementById("multiplayerstatus").innerText = "";
document.getElementById("connectstatus").innerHTML = "Claude Endpoint";
render_gametext();
@ -9631,6 +9772,7 @@ Current version indicated by LITEVER below.
document.body.classList.add("connected");
document.getElementById("connectstatus").classList.add("color_offwhite");
}
document.getElementById("multiplayerstatus").innerText = "";
document.getElementById("connectstatus").innerHTML = "Gemini Endpoint";
render_gametext();
}
@ -9662,6 +9804,7 @@ Current version indicated by LITEVER below.
document.body.classList.add("connected");
document.getElementById("connectstatus").classList.add("color_offwhite");
}
document.getElementById("multiplayerstatus").innerText = "";
document.getElementById("connectstatus").innerHTML = "Cohere Endpoint";
render_gametext();
}
@ -10067,6 +10210,7 @@ Current version indicated by LITEVER below.
desired_new_home_cluster = null;
}
document.getElementById("multiplayerstatus").innerText = "";
document.getElementById("connectstatus").innerHTML = "AI Horde";
render_gametext();
@ -10909,6 +11053,7 @@ Current version indicated by LITEVER below.
autosave();//need to always autosave, so that we can switch back to non persistent sessions
render_gametext(false);
sync_multiplayer(true);
}
function get_preset_instruct_tag_format(sel)
@ -11175,6 +11320,7 @@ Current version indicated by LITEVER below.
}
hide_popups();
restart_new_game(true, document.getElementById("keep_memory").checked);
sync_multiplayer(true);
hide_popups();
}
@ -11501,6 +11647,7 @@ Current version indicated by LITEVER below.
let ns = new AestheticInstructUISettings();
aestheticInstructUISettings = deepCopyAestheticSettings(ns);
refreshPreview(false);
leave_multiplayer();
restart_new_game();
display_settings();
confirm_settings();
@ -12981,6 +13128,7 @@ Current version indicated by LITEVER below.
}
render_gametext();
sync_multiplayer(false);
}
is_impersonate_user = false;
}
@ -15242,6 +15390,83 @@ Current version indicated by LITEVER below.
});
}
function poll_multiplayer()
{
if(!is_using_kcpp_with_multiplayer() || !multiplayer_active)
{
document.getElementById("multiplayerstatus").innerText = "";
schedule_multiplayer_minor_change = false;
schedule_multiplayer_major_change = false;
return;
}
document.getElementById("multiplayerstatus").innerHTML = `<a href="#" onclick="leave_multiplayer()" class="color_orangeurl" style="font-size:10px">[Exit Multiplayer]</a>`;
//send our changes if they exist
if(schedule_multiplayer_minor_change || schedule_multiplayer_major_change)
{
submit_multiplayer(schedule_multiplayer_major_change);
schedule_multiplayer_minor_change = false;
schedule_multiplayer_major_change = false;
}
else
{
//listen for others changes
fetch(apply_proxy_url(custom_kobold_endpoint + koboldcpp_multiplayer_check_endpoint),
{
method: 'GET',
headers: get_kobold_header(),
})
.then(response => response.json())
.then(vals => {
if(vals && vals.turn_major && multiplayer_active && (vals.turn_major != multiplayer_last_turn_major || vals.turn_minor != multiplayer_last_turn_minor))
{
let minor_change = (multiplayer_last_turn_major == vals.turn_major);
multiplayer_last_turn_major = vals.turn_major;
multiplayer_last_turn_minor = vals.turn_minor;
fetch(apply_proxy_url(custom_kobold_endpoint + koboldcpp_multiplayer_fetch_endpoint),
{
method: 'GET',
headers: get_kobold_header(),
})
.then(response => response.text())
.then(story => {
let tmpstory = decompress_story(story);
if(tmpstory && is_kai_json(tmpstory))
{
if(minor_change)
{
//minor change, load only gametext_arr. assume its v1
gametext_arr = [];
if (tmpstory.prompt != "") {
gametext_arr.push(tmpstory.prompt);
}
for (var i = 0; i < tmpstory.actions.length; ++i) {
gametext_arr.push(tmpstory.actions[i]);
}
render_gametext(false);
}
else
{
kai_json_load(tmpstory, true, true); //major change, load everything
}
}
}).catch(error => {
console.log("Failed to get multiplayer story: " + error);
});
}
else if(!vals || vals.error)
{
leave_multiplayer();
msgbox("Disconnected from multiplayer due to bad response.","Disconnected from Multiplayer");
}
}).catch(error => {
leave_multiplayer();
msgbox("Disconnected from multiplayer: " + error,"Disconnected from Multiplayer");
console.log("Failed to access multiplayer status: " + error);
});
}
}
//clock speed is 500ms per tick
function poll_pending_response()
{
@ -15341,6 +15566,7 @@ Current version indicated by LITEVER below.
synchro_pending_stream = "";
show_abort_button(false);
render_gametext();
sync_multiplayer(false);
}
}
else {
@ -15609,6 +15835,7 @@ Current version indicated by LITEVER below.
}
render_gametext();
sync_multiplayer(false);
console.log("Merged edit field. Parts:" + gametext_arr.length);
}
@ -15920,7 +16147,9 @@ Current version indicated by LITEVER below.
document.getElementById("gametext").innerHTML = `Welcome to <span class="color_cyan">KoboldAI Lite</span>!`+
`<br>You are using the models <span class="color_green">${selmodelstr}</span>${(selected_workers.length == 0 ? `` : ` (Pinned to ${selected_workers.length} worker IDs)`)}.`+
`${whorun}.<br><br><b><span class="color_orange">${nowmode} Selected</span></b> - Enter a prompt below to begin!`+
`${whorun}.`+
(multiplayer_active?`<br><br><span class="color_green">[ Multiplayer is <b>Active</b>! This session is shared with other server participants.]<br>[ You can leave via exit button in top right corner. ]</span>`:(is_using_kcpp_with_multiplayer()?`<br><br>[ <a href="#" tabindex="${mainmenu_is_untab?`-1`:`0`}" class="color_blueurl mainnav" onclick="join_multiplayer()"><span class="color_green">Multiplayer Available</span> - Click Here To Join</a> ]`:``))+
`<br><br><b><span class="color_orange">${nowmode} Selected</span></b> - Enter a prompt below to begin!`+
`<br>Or, <a href="#" tabindex="${mainmenu_is_untab?`-1`:`0`}" class="color_blueurl mainnav" onclick="document.getElementById('loadfileinput').click()">load a <b>JSON File</b> or a <b>Character Card</b> here.</a>`+
`<br>Or, <a href="#" tabindex="${mainmenu_is_untab?`-1`:`0`}" class="color_blueurl mainnav" onclick="display_scenarios()">select a <b>Quick Start Scenario</b> here.</a>`+
`<br>${(welcome!=""?`<br><em>${escapeHtml(welcome)}</em>`:``)}`;
@ -17478,6 +17707,7 @@ Current version indicated by LITEVER below.
}
retry_preserve_last = false;
render_gametext();
sync_multiplayer(false);
}
}, 2000);
@ -17502,6 +17732,7 @@ Current version indicated by LITEVER below.
redo_arr.push(popped);
}
render_gametext();
sync_multiplayer(false);
}
}
@ -17525,6 +17756,7 @@ Current version indicated by LITEVER below.
gametext_arr.push(redo_prev_text.pop());
}
render_gametext();
sync_multiplayer(false);
}
}, 2000);
@ -17542,12 +17774,14 @@ Current version indicated by LITEVER below.
let popped = redo_arr.pop();
gametext_arr.push(popped);
render_gametext();
sync_multiplayer(false);
}else if (redo_prev_text.length>0) {
last_reply_was_empty = false;
retry_prev_text.push(gametext_arr.pop());
retry_preserve_last = false;
gametext_arr.push(redo_prev_text.pop());
render_gametext();
sync_multiplayer(false);
}
}
}
@ -18394,6 +18628,7 @@ Current version indicated by LITEVER below.
</div>
<div id="connectstatusdiv">
<div id="connectstatus">Connecting</div>
<div id="multiplayerstatus"></div>
</div>
</div>
</div>
@ -18868,6 +19103,7 @@ Current version indicated by LITEVER below.
<option value="gemini-1.5-flash-latest">gemini-1.5-flash-latest</option>
<option value="gemini-1.5-pro-exp-0801">gemini-1.5-pro-exp-0801</option>
<option value="gemini-1.5-pro-exp-0827">gemini-1.5-pro-exp-0827</option>
<option value="gemini-exp-1114">gemini-exp-1114</option>
<option value="text-bison-001">text-bison-001</option>
</select>
<span class="color_green" style="font-weight: bold;">Please input Gemini or PaLM API Key.</span><br><br>
@ -19973,7 +20209,7 @@ Current version indicated by LITEVER below.
</div>
<div class="popupfooter">
<button type="button" class="btn btn-primary" onclick="confirm_memory();save_wi();commit_wi_changes();render_gametext();hide_popups()">OK</button>
<button type="button" class="btn btn-primary" onclick="confirm_memory();save_wi();commit_wi_changes();render_gametext();sync_multiplayer(true);hide_popups()">OK</button>
<button type="button" class="btn btn-primary" onclick="hide_popups();">Cancel</button>
</div>
</div>

View file

@ -2077,13 +2077,18 @@ Enter Prompt:<br>
fullupdate = incoming_story.get('fullupdate', False)
storybody = incoming_story.get('data', None) #should be a compressed string
if storybody:
multiplayer_story_data_compressed = str(storybody) #save latest story
if fullupdate:
multiplayer_turn_minor = 0
multiplayer_turn_major += 1
storybody = str(storybody)
if len(storybody) > (1024*1024*3): #limit story to 3mb
response_code = 400
response_body = (json.dumps({"success":False, "error":"Story is too long!"}).encode())
else:
multiplayer_turn_minor += 1
response_body = (json.dumps({"success":True,"turn_major":multiplayer_turn_major,"turn_minor":multiplayer_turn_minor}).encode())
multiplayer_story_data_compressed = str(storybody) #save latest story
if fullupdate:
multiplayer_turn_minor = 0
multiplayer_turn_major += 1
else:
multiplayer_turn_minor += 1
response_body = (json.dumps({"success":True,"turn_major":multiplayer_turn_major,"turn_minor":multiplayer_turn_minor}).encode())
else:
response_code = 400
response_body = (json.dumps({"success":False, "error":"No story submitted!"}).encode())