Merge branch 'upstream' into concedo_experimental

# Conflicts:
#	.github/workflows/build-and-test-snapdragon.yml
#	.github/workflows/build-android.yml
#	.github/workflows/build-cache.yml
#	.github/workflows/build-cann.yml
#	.github/workflows/build-cross.yml
#	.github/workflows/build-openvino.yml
#	.github/workflows/build-riscv.yml
#	.github/workflows/build-sanitize.yml
#	.github/workflows/build-self-hosted.yml
#	.github/workflows/build-sycl.yml
#	.github/workflows/build-vulkan.yml
#	.github/workflows/build.yml
#	.github/workflows/release.yml
#	.github/workflows/server-sanitize.yml
#	ci/run.sh
#	docs/backend/SYCL.md
#	docs/backend/snapdragon/README.md
#	ggml/CMakeLists.txt
#	ggml/src/ggml-cuda/ggml-cuda.cu
#	ggml/src/ggml-hexagon/ggml-hexagon.cpp
#	ggml/src/ggml-hexagon/htp/CMakeLists.txt
#	ggml/src/ggml-hexagon/htp/cpy-ops.c
#	ggml/src/ggml-hexagon/htp/get-rows-ops.c
#	ggml/src/ggml-hexagon/htp/hmx-flash-attn-ops.c
#	ggml/src/ggml-hexagon/htp/htp-ctx.h
#	ggml/src/ggml-hexagon/htp/htp-ops.h
#	ggml/src/ggml-hexagon/htp/hvx-utils.h
#	ggml/src/ggml-hexagon/htp/main.c
#	ggml/src/ggml-hexagon/htp/rope-ops.c
#	ggml/src/ggml-hexagon/htp/set-rows-ops.c
#	ggml/src/ggml-hexagon/htp/unary-ops.c
#	ggml/src/ggml-sycl/common.hpp
#	ggml/src/ggml-sycl/ggml-sycl.cpp
#	ggml/src/ggml-webgpu/ggml-webgpu-shader-lib.hpp
#	ggml/src/ggml-webgpu/ggml-webgpu.cpp
#	ggml/src/ggml-webgpu/wgsl-shaders/common_decls.tmpl
#	ggml/src/ggml-webgpu/wgsl-shaders/mul_mat_vec.wgsl
#	ggml/src/ggml-webgpu/wgsl-shaders/mul_mat_vec_acc.tmpl
#	scripts/sync-ggml.last
#	tests/gguf-model-data.cpp
#	tests/test-backend-ops.cpp
This commit is contained in:
Concedo
2026-05-27 00:26:08 +08:00
30 changed files with 1051 additions and 97 deletions
+200 -37
View File
@@ -6022,7 +6022,7 @@ Current version indicated by LITEVER below.
inputtxt = replaceAll(inputtxt,instructsysplaceholder_end.trim(),get_instruct_systag_end(false));
return inputtxt;
}
function replace_noninstruct_placeholders(inputtxt,escape=false,isgametext=true,persistent_countmap=null)
function replace_chat_name_placeholders(inputtxt, escape=false)
{
let firstopponent = localsettings.chatopponent;
if (firstopponent && firstopponent.includes("||$||")) {
@@ -6040,7 +6040,11 @@ Current version indicated by LITEVER below.
inputtxt = replaceAll(inputtxt,"{{user}}",(localsettings.chatname?localsettings.chatname:"User"),true);
inputtxt = replaceAll(inputtxt,"{{char}}",(localsettings.chatopponent?firstopponent:defaultchatopponent),true);
}
return inputtxt;
}
function replace_noninstruct_placeholders(inputtxt,escape=false,isgametext=true,persistent_countmap=null)
{
inputtxt = replace_chat_name_placeholders(inputtxt,escape);
inputtxt = replaceAll(inputtxt,"{{original}}","",true); //redundant in Lite; use sysprompt or assistant jailbreak instead
for(let i=0;i<localsettings.placeholder_tags_data.length;++i)
@@ -11771,6 +11775,7 @@ Current version indicated by LITEVER below.
* @type {{
* name: string;
* urlParam: string;
* matchers: string[];
* inputBox: {
* text: string;
* placeholder: string;
@@ -11784,6 +11789,7 @@ Current version indicated by LITEVER below.
{
name: "prompts.forthisfeel.club",
urlParam: "aether",
matchers: ["forthisfeel.club/"],
inputBox: {
text: "Enter prompts.forthisfeel.club prompt URL, or 4-digit prompt number",
placeholder: "https://prompts.forthisfeel.club/1234"
@@ -11852,6 +11858,7 @@ Current version indicated by LITEVER below.
{
name: "chub.ai / characterhub.org",
urlParam: "chub",
matchers: ["chub.ai/","characterhub.org/"],
inputBox: {
text: "Enter chub.ai or characterhub.org card URL",
placeholder: "https://chub.ai/characters/Anonymous/example-character"
@@ -11936,6 +11943,7 @@ Current version indicated by LITEVER below.
{
name: "pygmalion.chat",
urlParam: "pyg",
matchers: ["pygmalion.chat/"],
inputBox: {
text: "Enter pygmalion.chat character UUID",
placeholder: "d7950ca8-c241-4725-8de1-42866e389ebf",
@@ -12008,6 +12016,7 @@ Current version indicated by LITEVER below.
{
name: "aicharactercards.com",
urlParam: "aicc",
matchers: ["aicharactercards.com/"],
inputBox: {
text: "Enter aicharactercards.com card URL",
placeholder: "https://aicharactercards.com/character-cards/work-jobs/deffcolony/lara-lightland",
@@ -12096,6 +12105,7 @@ Current version indicated by LITEVER below.
{
name: "character-tavern.com",
urlParam: "aicc",
matchers: ["character-tavern.com/"],
inputBox: {
text: "Enter character-tavern.com card URL",
placeholder: "https://character-tavern.com/character/yousef/Shinku",
@@ -12180,6 +12190,138 @@ Current version indicated by LITEVER below.
});
}
},
//botbooru
{
name: "botbooru.com",
urlParam: "botbooru",
matchers: ["botbooru.com/"],
inputBox: {
text: "Enter botbooru.com card URL",
placeholder: "https://botbooru.com/download/png/32104",
},
extraction: (userInput) => {
if (userInput.match(/character\//i))
{
userInput = userInput.split("#")[0].split("?")[0];
userInput = userInput.endsWith('/') ? userInput.slice(0, -1) : userInput;
let tmp = userInput.split("character/")[1];
return `https://botbooru.com/download/png/${tmp}`;
}
else
{
userInput = userInput.split("#")[0].split("?")[0];
userInput = userInput.endsWith('/') ? userInput.slice(0, -1) : userInput;
return userInput;
}
},
fetch: (userInput) => {
temp_scenario = {
"title":"",
"desc": "",
"opmode":3,
"chatopponent": "",
"gui_type":1,
"prompt":"",
"memory": "",
"authorsnote": "",
"worldinfo": [],
};
finalurl = apply_proxy_url(userInput,true);
//try to obtain the full portrait image
return fetch(finalurl, {
method: 'GET',
redirect: 'follow',
referrerPolicy: 'no-referrer',
})
.then(rb => {
if(rb.ok)
{
return rb.blob();
}else{
throw new Error('Cannot fetch tavern image');
}
})
.then(blob => {
preview_temp_scenario();
readTavernPngFromBlob(blob,(obj)=>{
load_temp_scenario_from_tavernobj(obj);
});
const objectURL = URL.createObjectURL(blob);
const compressedImg = compressImage(objectURL, (compressedImageURI, aspectratio)=>{
temp_scenario.image = compressedImageURI;
temp_scenario.image_aspect = aspectratio;
preview_temp_scenario();
}, true, AVATAR_PX);
})
.catch(error => {
throw new Error("Selected scenario is invalid.");
console.error(error);
});
}
},
//raw png URL download
{
name: "Raw URL",
urlParam: "rawurl",
matchers: ["/"],
inputBox: {
text: "Enter the direct URL to the character card file",
placeholder: "https://example.com/file.png",
},
extraction: (userInput) => {
return userInput;
},
fetch: (userInput) => {
temp_scenario = {
"title":"",
"desc": "",
"opmode":3,
"chatopponent": "",
"gui_type":1,
"prompt":"",
"memory": "",
"authorsnote": "",
"worldinfo": [],
};
finalurl = apply_proxy_url(userInput,false);
//try to obtain the full portrait image
return fetch(finalurl, {
method: 'GET',
redirect: 'follow',
referrerPolicy: 'no-referrer',
})
.then(rb => {
if(rb.ok)
{
return rb.blob();
}else{
throw new Error('Cannot fetch tavern image');
}
})
.then(blob => {
preview_temp_scenario();
readTavernPngFromBlob(blob,(obj)=>{
load_temp_scenario_from_tavernobj(obj);
});
const objectURL = URL.createObjectURL(blob);
const compressedImg = compressImage(objectURL, (compressedImageURI, aspectratio)=>{
temp_scenario.image = compressedImageURI;
temp_scenario.image_aspect = aspectratio;
preview_temp_scenario();
}, true, AVATAR_PX);
})
.catch(error => {
throw new Error("Selected scenario is invalid.");
console.error(error);
});
}
},
// char-archive has shut down
// {
@@ -12308,7 +12450,7 @@ Current version indicated by LITEVER below.
else inputBox(
scenario_source.inputBox.text,
"Import from " + scenario_source.name,
"",
getInputBoxValue(),
scenario_source.inputBox.placeholder,
(value) => {
const input = getInputBoxValue().trim();
@@ -12317,6 +12459,57 @@ Current version indicated by LITEVER below.
);
}
function import_scenario_unified_dropdown()
{
let dropdown = document.getElementById("importscenariounifieddropdown");
if(dropdown)
{
let picked = dropdown.value;
if(picked!="-1")
{
import_scenario(scenario_sources[picked]);
}
}
}
function import_scenario_unified() //a single button entry point to import from any source
{
let combined_txt = "Please enter the full URL of the character card to import, or pick a specific website.";
let selbox = `Source: <select style="padding:4px; display: inline; width: 200px; padding: 6px 3px;" class="form-control" id="importscenariounifieddropdown" onchange="import_scenario_unified_dropdown()">`;
selbox += `<option value="-1">Automatic</option>`;
for(let i=0;i<scenario_sources.length;++i)
{
selbox += `<option value="${i}">${scenario_sources[i].name}</option>`;
}
selbox += "</select>";
combined_txt += "<br>" + selbox;
inputBox(combined_txt,"Import character card from URL","","Enter full URL to character card",
(value) => {
const input = getInputBoxValue().trim();
let found = -1;
for(let i=0;i<scenario_sources.length;++i)
{
for(let j=0;j<scenario_sources[i].matchers.length;++j)
{
let curr = scenario_sources[i].matchers[j].toLowerCase();
if(curr && input.toLowerCase().includes(curr))
{
found = i;
break;
}
}
if(found!=-1)
{
break;
}
}
if(found!=-1)
{
import_scenario(scenario_sources[found],input);
}
},true);
}
function display_scenarios()
{
mainmenu_untab(true);
@@ -12327,10 +12520,7 @@ Current version indicated by LITEVER below.
scenarios += `<button type="button" name="" class="scenarioitem purple btn btn-primary" onclick="hide_popups();document.getElementById('loadfileinput').click()">Load Character Card or JSON File</button>`;
scenarios += `<button type="button" name="" class="scenarioitem purple btn btn-primary" onclick="hide_popups();display_scenariolibrary();">Load or Save Custom Scenario</button>`;
scenarios += `<button type="button" name="" class="scenarioitem purple btn btn-primary" onclick="character_creator()">New Character Creator</button>`;
for(let i=0;i<scenario_sources.length;++i) {
scenarios += `<button type="button" name="" class="scenarioitem purple btn btn-primary" onclick="import_scenario(scenario_sources[${i}])">${scenario_sources[i].name}</button>`
}
scenarios += `<button type="button" name="" class="scenarioitem purple btn btn-primary" onclick="import_scenario_unified()">Import from Website URL</button>`
for(let i=0;i<scenario_db.length;++i)
{
@@ -21849,35 +22039,6 @@ Current version indicated by LITEVER below.
}
//to reduce the prompt being flagged for CP on horde and failing, we sanitize it while trying to have as little impact on normal usage.
//this does not affect the story context, only images sent
//we only match whole words, to avoid the scunthorpe problem
function sanitize_horde_image_prompt(inputtext) {
if (inputtext == null || inputtext == "") { return ""; }
//to avoid flagging from some image models, always swap these words
inputtext = inputtext.replace(/\b(girl)\b/gmi, "woman");
inputtext = inputtext.replace(/\b(boy)\b/gmi, "man");
inputtext = inputtext.replace(/\b(girls)\b/gmi, "women");
inputtext = inputtext.replace(/\b(boys)\b/gmi, "men");
//always remove these high risk words from prompt, as they add little value to image gen while increasing the risk the prompt gets flagged
inputtext = inputtext.replace(/\b(under.age|under.aged|underage|underaged|loli|pedo|pedophile|(\w+).year.old|(\w+).years.old|minor|prepubescent|minors|shota)\b/gmi, "");
//if nsfw is detected, do not remove it but apply additional precautions
let foundnsfw = inputtext.match(/\b(cock|ahegao|hentai|uncensored|lewd|cocks|deepthroat|deepthroating|dick|dicks|cumshot|lesbian|fuck|fucked|fucking|sperm|naked|nipples|tits|boobs|breasts|boob|breast|topless|ass|butt|fingering|masturbate|masturbating|bitch|blowjob|pussy|piss|asshole|dildo|dildos|vibrator|erection|foreskin|handjob|nude|penis|porn|vibrator|virgin|vagina|vulva|threesome|orgy|bdsm|hickey|condom|testicles|anal|bareback|bukkake|creampie|stripper|strap-on|missionary|clitoris|clit|clitty|cowgirl|fleshlight|sex|buttplug|milf|oral|sucking|bondage|orgasm|scissoring|railed|slut|sluts|slutty|cumming|cunt|faggot|sissy|anal|anus|cum|semen|scat|nsfw|xxx|explicit|erotic|horny|aroused|jizz|moan|rape|raped|raping|throbbing|humping)\b/gmi);
if (foundnsfw) {
//replace risky subject nouns with person
inputtext = inputtext.replace(/\b(youngster|infant|baby|toddler|child|teen|kid|kiddie|kiddo|teenager|student|preteen|pre.teen)\b/gmi, "person");
//remove risky adjectives and related words
inputtext = inputtext.replace(/\b(young|younger|youthful|youth|small|smaller|smallest|girly|boyish|lil|tiny|teenaged|lit[tl]le|school.aged|school|highschool|kindergarten|teens|children|kids)\b/gmi, "");
}
return inputtext;
}
function generate_new_image(sentence, base64img="", autoappend=true) //base64img is for img2img, autoappend automatically adds it to gametext arr
{
if(base64img!="")
@@ -21904,7 +22065,6 @@ Current version indicated by LITEVER below.
}
if (localsettings.generate_images_mode==1) { //horde
sentence = sanitize_horde_image_prompt(sentence);
usedscheduler = null; //horde does not use schedulers
switch(usedsampler) //these names are used for horde only
{
@@ -26534,6 +26694,9 @@ Current version indicated by LITEVER below.
let chatunits = []; //parse chat body into nice chat chunks
let myturnchat = false; //who is currently speaking?
//fix: because chat operates on actual names, we MUST replace chat name placeholders early on.
input = replace_chat_name_placeholders(input,false);
var othernamesregex = new RegExp("(?!" + localsettings.chatname + ").+?\: ", "gi");
if(!localsettings.chat_match_any_name && localsettings.chatopponent!="")