Merge branch 'sd_inline_image_generation' of https://github.com/sumit0k/SillyTavern into sumit0k/sd_inline_image_generation

This commit is contained in:
SillyLossy
2023-05-16 21:18:59 +03:00
2 changed files with 76 additions and 22 deletions

View File

@ -446,7 +446,7 @@ function getTokenCount(str, padding = undefined) {
let tokenCount = 0;
jQuery.ajax({
async: false,
type: 'POST', //
type: 'POST', //
url: `/tokenize_llama`,
data: JSON.stringify({ text: str }),
dataType: "json",
@ -588,7 +588,7 @@ $.get("/csrf-token").then(async (data) => {
});
function checkOnlineStatus() {
///////// REMOVED LINES THAT DUPLICATE RA_CHeckOnlineStatus FEATURES
///////// REMOVED LINES THAT DUPLICATE RA_CHeckOnlineStatus FEATURES
if (online_status == "no_connection") {
$("#online_status_indicator2").css("background-color", "red"); //Kobold
@ -1036,7 +1036,7 @@ function appendImageToMessage(mes, messageElement) {
image.src = mes.extra?.image;
image.title = mes.extra?.title || mes.title;
image.classList.add("img_extra");
messageElement.find(".mes_text").prepend(image);
mes.extra?.inline_image?messageElement.find(".mes_text").append(image):messageElement.find(".mes_text").prepend(image);
}
}
@ -1094,7 +1094,7 @@ function addOneMessage(mes, { type = "normal", insertAfter = null, scroll = true
avatarImg = default_avatar;
}
}
//old processing:
//old processing:
//if messge is from sytem, use the name provided in the message JSONL to proceed,
//if not system message, use name2 (char's name) to proceed
//characterName = mes.is_system || mes.force_avatar ? mes.name : name2;
@ -1963,7 +1963,7 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject,
// where it left off by removing the trailing newline at the end
// that was added by chat2 generator. This causes problems with
// instruct mode that could not have a trailing newline. So we're
// removing a newline ONLY at the end of the string if it exists.
// removing a newline ONLY at the end of the string if it exists.
item = item.replace(/\n?$/, '');
//item = item.substr(0, item.length - 1);
}
@ -2192,8 +2192,8 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject,
}
else {
jQuery.ajax({
type: 'POST', //
url: generate_url, //
type: 'POST', //
url: generate_url, //
data: JSON.stringify(generate_data),
beforeSend: function () {

View File

@ -41,6 +41,7 @@ const triggerWords = {
[generationMode.CHARACTER]: ['you'],
[generationMode.USER]: ['me'],
[generationMode.SCENARIO]: ['scene'],
[generationMode.FREE]: ['raw_last'],
[generationMode.NOW]: ['last'],
[generationMode.FACE]: ['face'],
@ -58,7 +59,7 @@ const quietPrompts = {
[generationMode.USER]: "[Pause your roleplay and provide a detailed description of {{user}}'s appearance from the perspective of {{char}} in the form of a comma-delimited list of keywords and phrases. Ignore the rest of the story when crafting this description. Do not roleplay as {{char}}}} when writing this description, and do not attempt to continue the story.]",
[generationMode.SCENARIO]: "[Pause your roleplay and provide a detailed description for all of the following: a brief recap of recent events in the story, {{char}}'s appearance, and {{char}}'s surroundings. Do not roleplay while writing this description.]",
[generationMode.FREE]: "[Pause your roleplay and provide ONLY an echo this string back to me verbatim: {0}. Do not write anything after the string. Do not roleplay at all in your response.]",
[generationMode.FREE]: "[Pause your roleplay and provide ONLY the last chat message string back to me verbatim. Do not write anything after the string. Do not roleplay at all in your response. Do not continue the roleplay story.]",
}
const helpString = [
@ -69,8 +70,9 @@ const helpString = [
`<li>${m(j(triggerWords[generationMode.USER]))} user character full body selfie</li>`,
`<li>${m(j(triggerWords[generationMode.SCENARIO]))} visual recap of the whole chat scenario</li>`,
`<li>${m(j(triggerWords[generationMode.NOW]))} visual recap of the last chat message</li>`,
`<li>${m(j(triggerWords[generationMode.FREE]))} visual recap of the last chat message with no summary</li>`,
'</ul>',
`Anything else would trigger a "free mode" to make SD generate whatever you prompted.<Br>
`Anything else would trigger a "free mode" to make SD generate whatever you prompted.<Br>
example: '/sd apple tree' would generate a picture of an apple tree.`,
].join('<br>');
@ -340,7 +342,14 @@ function processReply(str) {
return str;
}
async function generatePicture(_, trigger) {
function getRawLastMessage(context) {
const lastMessage = context.chat.slice(-1)[0].mes,
characterDescription = context.characters[context.characterId].description,
situation = context.characters[context.characterId].scenario;
return `((${lastMessage})), (${situation}:0.7), (${characterDescription}:0.5)`
}
async function generatePicture(_, trigger, message, callback) {
if (!trigger || trigger.trim().length === 0) {
console.log('Trigger word empty, aborting');
return;
@ -361,7 +370,7 @@ async function generatePicture(_, trigger) {
const context = getContext();
try {
const prompt = processReply(await new Promise(
const prompt = trigger == 'raw_last' ? message || getRawLastMessage(context) : processReply(await new Promise(
async function promptPromise(resolve, reject) {
try {
await context.generate('quiet', { resolve, reject, quiet_prompt, force_name2: true, });
@ -377,9 +386,9 @@ async function generatePicture(_, trigger) {
console.log('Processed Stable Diffusion prompt:', prompt);
if (extension_settings.sd.horde) {
await generateHordeImage(prompt);
await generateHordeImage(prompt, callback);
} else {
await generateExtrasImage(prompt);
await generateExtrasImage(prompt, callback);
}
} catch (err) {
console.trace(err);
@ -391,7 +400,7 @@ async function generatePicture(_, trigger) {
}
}
async function generateExtrasImage(prompt) {
async function generateExtrasImage(prompt, callback) {
const url = new URL(getApiUrl());
url.pathname = '/api/image';
const result = await fetch(url, {
@ -414,13 +423,13 @@ async function generateExtrasImage(prompt) {
if (result.ok) {
const data = await result.json();
const base64Image = `data:image/jpeg;base64,${data.image}`;
sendMessage(prompt, base64Image);
callback ? callback(prompt, base64Image) : sendMessage(prompt, base64Image);
} else {
callPopup('Image generation has failed. Please try again.', 'text');
}
}
async function generateHordeImage(prompt) {
async function generateHordeImage(prompt, callback) {
const result = await fetch('/horde_generateimage', {
method: 'POST',
headers: getRequestHeaders(),
@ -441,7 +450,7 @@ async function generateHordeImage(prompt) {
if (result.ok) {
const data = await result.text();
const base64Image = `data:image/webp;base64,${data}`;
sendMessage(prompt, base64Image);
callback ? callback(prompt, base64Image) : sendMessage(prompt, base64Image);
} else {
callPopup('Image generation has failed. Please try again.', 'text');
}
@ -468,6 +477,10 @@ async function sendMessage(prompt, image) {
}
function addSDGenButtons() {
const messageButtonHtml = `
<div title="Generate Image" onclick="sdMessageButton(event)" class="sd_message_gen fa-solid fa-paintbrush"></div>
`;
const buttonHtml = `
<div id="sd_gen" class="fa-solid fa-paintbrush" title="Trigger Stable Diffusion" /></div>
`;
@ -484,19 +497,23 @@ function addSDGenButtons() {
<li class="list-group-item" id="sd_me" data-value="me">Me</li>
<li class="list-group-item" id="sd_world" data-value="world">The Whole Story</li>
<li class="list-group-item" id="sd_last" data-value="last">The Last Message</li>
<li class="list-group-item" id="sd_raw_last" data-value="raw_last">Raw Last Message</li>
</ul>
</div>`;
$('.mes_buttons').prepend(messageButtonHtml);
$('#send_but_sheld').prepend(buttonHtml);
$('#send_but_sheld').prepend(waitButtonHtml);
$(document.body).append(dropdownHtml)
$(document.body).append(dropdownHtml);
const messageButton = $('.sd_message_gen');
const button = $('#sd_gen');
const waitButton = $("#sd_gen_wait");
const dropdown = $('#sd_dropdown');
waitButton.hide();
dropdown.hide();
button.hide();
messageButton.hide();
let popper = Popper.createPopper(button.get(0), dropdown.get(0), {
placement: 'top-start',
@ -519,14 +536,46 @@ function addSDGenButtons() {
async function moduleWorker() {
const context = getContext();
context.onlineStatus === 'no_connection'
? $('#sd_gen').hide(200)
: $('#sd_gen').show(200)
if (context.onlineStatus === 'no_connection'){
$('#sd_gen').hide(200);
$('.sd_message_gen').hide(200);
}
else{
$('#sd_gen').show(200);
$('.sd_message_gen').show(200);
}
}
addSDGenButtons();
setInterval(moduleWorker, UPDATE_INTERVAL);
function sdMessageButton (e) {
const character = $(e.currentTarget).parents('div.mes_block').children('div.ch_name').children('span.name_text').text(),
message = $(e.currentTarget).parents('div.mes_block').children('div.mes_text').text();
console.log("doing /sd raw last");
generatePicture('sd', 'raw_last', `${character} said: ${message}`, appendImageToMessage);
function appendImageToMessage(prompt, image){
const sd_image = document.createElement("img"),
context = getContext(),
message_id = $(e.target).parents('div.mes').attr('mesid');
sd_image.src = image;
sd_image.title = prompt;
sd_image.classList.add("img_extra");
$(e.target).parents('div.mes_block').children('div.mes_text').append(sd_image);
context.chat[message_id].extra.inline_image = true;
context.chat[message_id].extra.image = image;
context.chat[message_id].extra.title = prompt;
context.saveChat();
}
};
window.sdMessageButton = sdMessageButton;
$("#sd_dropdown [id]").on("click", function () {
var id = $(this).attr("id");
if (id == "sd_you") {
@ -553,6 +602,11 @@ $("#sd_dropdown [id]").on("click", function () {
console.log("doing /sd last");
generatePicture('sd', 'last');
}
else if (id == "sd_raw_last") {
console.log("doing /sd raw last");
generatePicture('sd', 'raw_last');
}
});
jQuery(async () => {
@ -618,4 +672,4 @@ jQuery(async () => {
});
await loadSettings();
});
});