Change Avatar Custom Code
This is a code to change the Avatar of the Character, just type /change-avatar
Version 4
With /roll-avatar
to re-generate the image with the same description.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 | // This is the code to change the Avatar of the Character
// `/change-avatar` and it will prompt the character to describe themselves, then use that as a prompt for the avatar.
// `/roll-avatar` to re-generate the image with the same description.
window.generateImage = async function (mode, description) {
if (mode == 'new') {
let prevDataUrl = oc.character.avatar.url;
let { dataUrl } = await oc.textToImage({
prompt: `${oc.character.imagePromptPrefix == '' ? '' : oc.character.imagePromptPrefix + ', '}${description}${oc.character.imagePromptSuffix == '' ? '' : ', ' + oc.character.imagePromptSuffix}`,
negativePrompt: ``,
});
oc.character.avatar.url = await resizeDataURLWidth(dataUrl, 300);
oc.thread.messages.pop()
oc.thread.messages.pop()
oc.thread.messages.pop()
oc.thread.messages.push({
author: "system",
name: "System",
content: `<p>New Avatar:</p><img src="${dataUrl}" style="max-width: 200px; width: 100%; max-height: 200px; aspect-ratio: 1 / 1; object-fit: contain;">
<p>Old Avatar:</p><img src="${prevDataUrl}" style="max-width: 200px; width: 100%; max-height: 200px; aspect-ratio: 1 / 1; object-fit: contain;">
<p><button onclick="oc.character.avatar.url = '${prevDataUrl}'">Revert to Old Avatar?</button><br><button onclick="oc.character.avatar.url = '${dataUrl}'">Back to Generated Avatar?</button></p>`,
hiddenFrom: ['ai'],
expectsReply: false,
avatar: { size: 0 },
})
} else {
let prevDataUrl = oc.character.avatar.url;
let { dataUrl } = await oc.textToImage({
prompt: `${oc.character.imagePromptPrefix == '' ? '' : oc.character.imagePromptPrefix + ', '}${description}${oc.character.imagePromptSuffix == '' ? '' : ', ' + oc.character.imagePromptSuffix}`,
negativePrompt: ``,
});
oc.character.avatar.url = await resizeDataURLWidth(dataUrl, 300);
oc.thread.messages.pop()
oc.thread.messages.push({
author: "system",
name: "System",
content: `<p>New Avatar:</p><img src="${dataUrl}" style="max-width: 200px; width: 100%; max-height: 200px; aspect-ratio: 1 / 1; object-fit: contain;">
<p>Old Avatar:</p><img src="${prevDataUrl}" style="max-width: 200px; width: 100%; max-height: 200px; aspect-ratio: 1 / 1; object-fit: contain;">
<p><button onclick="oc.character.avatar.url = '${prevDataUrl}'">Revert to Old Avatar?</button><br><button onclick="oc.character.avatar.url = '${dataUrl}'">Back to Generated Avatar?</button></p>`,
hiddenFrom: ['ai'],
expectsReply: false,
avatar: { size: 0 },
})
}
}
window.alreadyGenerating = false;
oc.thread.on("MessageAdded", async function () {
let lastMessage = oc.thread.messages.at(-1);
oc.character.customData.description = oc.character.customData.description
? oc.character.customData.description
: "";
// console.log(lastMessage);
if (lastMessage.author !== "ai") {
if (/^\/change-avatar/.test(lastMessage.content)) {
oc.thread.messages.pop()
oc.thread.messages.push({
author: "user",
content: `${oc.character.name}, describe your appearance and personality in detail. Reply with a comma-separated list of keywords and keyphrases which *visually* capture your apprearance only. Imagine you're giving a list of keywords to an artist who will use them to paint or draw a portrait of you. Describe the your appearance with keywords/keyphrases, including your race, sex/gender, class, age, etc. Respond with only the comma-separated keyphrases - nothing more, nothing less.
Start with "Here is my current appearance:"`,
})
}
if (/^\/roll-avatar/.test(lastMessage.content)) {
oc.thread.messages.pop()
oc.thread.messages.push({
author: "system",
name: "System",
content: `The AI is Changing their Avatar, please wait ... <br><progress style="width:80px"></progress>`,
hiddenFrom: ['ai'],
expectsReply: false,
avatar: { size: 0 },
})
generateImage('reroll', oc.character.customData.description);
}
};
if (alreadyGenerating) return;
alreadyGenerating = true;
if (lastMessage.author === "ai") {
if (/^Here is my current appearance\:/.test(lastMessage.content)) {
let description = lastMessage.content.replace("Here is my current appearance:", '');
console.log("DESCRIPTION: ", description)
oc.character.customData.description = description
oc.thread.messages.push({
author: "system",
name: "System",
content: `The AI is Changing their Avatar, please wait ... <br><progress style="width:80px"></progress>`,
hiddenFrom: ['ai'],
expectsReply: false,
avatar: { size: 0 },
})
console.log("PUSHED MESSAGE");
generateImage('new', description);
}
};
alreadyGenerating = false;
})
async function resizeDataURLWidth(dataURL, newWidth) {
const blob = await fetch(dataURL).then(res => res.blob());
const bitmap = await createImageBitmap(blob);
const canvas = Object.assign(document.createElement('canvas'), { width: newWidth, height: bitmap.height / bitmap.width * newWidth });
const ctx = canvas.getContext('2d');
ctx.drawImage(bitmap, 0, 0, canvas.width, canvas.height);
return canvas.toDataURL('image/jpeg');
}
|
Version 3
Uses the new imagePromptPrefix
and imagePromptSuffix
, also removed the negativePrompt
since we can add them on the imagePromptSuffix
!
Version 2
Allows the AI to reply and change their appearance based on what they replied.
Version 1
It will generate a new avatar based on the description on 'roleInstruction' which is the Description/Instruction on the Input Box on the Edit Character after the Name Input Box: