Added import function for AICharacterCards.com cards

Added ability to import cards directly from aicharactercards.com via it's api like Chub and Janny.
Video of it in action: https://streamable.com/gbfdtw

Just pass the last two slash vars from the url (the author and card title) from a page. EX: aicharcards/the-game-master to:
https://aicharactercards.com/wp-json/pngapi/v1/image/

In this example: https://aicharactercards.com/wp-json/pngapi/v1/image/aicharcards/the-game-master
This commit is contained in:
Blueprint Coding 2024-04-24 18:04:17 -06:00
parent 47b6562605
commit 305afb3713
2 changed files with 48 additions and 0 deletions

View File

@ -10552,6 +10552,7 @@ jQuery(async function () {
<li>Chub Lorebook (Direct Link or ID)<br>Example: <tt>lorebooks/bartleby/example-lorebook</tt></li> <li>Chub Lorebook (Direct Link or ID)<br>Example: <tt>lorebooks/bartleby/example-lorebook</tt></li>
<li>JanitorAI Character (Direct Link or UUID)<br>Example: <tt>ddd1498a-a370-4136-b138-a8cd9461fdfe_character-aqua-the-useless-goddess</tt></li> <li>JanitorAI Character (Direct Link or UUID)<br>Example: <tt>ddd1498a-a370-4136-b138-a8cd9461fdfe_character-aqua-the-useless-goddess</tt></li>
<li>Pygmalion.chat Character (Direct Link or UUID)<br>Example: <tt>a7ca95a1-0c88-4e23-91b3-149db1e78ab9</tt></li> <li>Pygmalion.chat Character (Direct Link or UUID)<br>Example: <tt>a7ca95a1-0c88-4e23-91b3-149db1e78ab9</tt></li>
<li>AICharacterCard.com Character (Direct Link or ID)<br>Example: <tt>AICC/aicharcards/the-game-master</tt></li>
<li>More coming soon...</li> <li>More coming soon...</li>
<ul>`; <ul>`;
const input = await callPopup(html, 'input', '', { okButton: 'Import', rows: 4 }); const input = await callPopup(html, 'input', '', { okButton: 'Import', rows: 4 });

View File

@ -345,6 +345,40 @@ async function downloadJannyCharacter(uuid) {
throw new Error('Failed to download character'); throw new Error('Failed to download character');
} }
//Download Character Cards from AICharactersCards.com (AICC) API.
async function downloadAICCCharacter(id) {
const apiURL = `https://aicharactercards.com/wp-json/pngapi/v1/image/${id}`;
try {
const response = await fetch(apiURL);
if (!response.ok) {
throw new Error(`Failed to download character: ${response.statusText}`);
}
const contentType = response.headers.get('content-type') || 'image/png'; // Default to 'image/png' if header is missing
const buffer = await response.buffer();
const fileName = `${sanitize(id)}.png`; // Assuming PNG, but adjust based on actual content or headers
return {
buffer: buffer,
fileName: fileName,
fileType: contentType
};
} catch (error) {
console.error('Error downloading character:', error);
throw error;
}
}
function parseAICC(url) {
const pattern = /^https?:\/\/aicharactercards\.com\/character-cards\/([^\/]+)\/([^\/]+)\/?$|([^\/]+)\/([^\/]+)$/;
const match = url.match(pattern);
if (match) {
// Match group 1 & 2 for full URL, 3 & 4 for relative path
return match[1] && match[2] ? `${match[1]}/${match[2]}` : `${match[3]}/${match[4]}`;
}
return null;
}
/** /**
* @param {String} url * @param {String} url
* @returns {String | null } UUID of the character * @returns {String | null } UUID of the character
@ -373,6 +407,7 @@ router.post('/importURL', jsonParser, async (request, response) => {
const isJannnyContent = url.includes('janitorai'); const isJannnyContent = url.includes('janitorai');
const isPygmalionContent = url.includes('pygmalion.chat'); const isPygmalionContent = url.includes('pygmalion.chat');
const isAICharacterCardsContent = url.includes('aicharactercards.com');
if (isPygmalionContent) { if (isPygmalionContent) {
const uuid = getUuidFromUrl(url); const uuid = getUuidFromUrl(url);
@ -390,6 +425,13 @@ router.post('/importURL', jsonParser, async (request, response) => {
type = 'character'; type = 'character';
result = await downloadJannyCharacter(uuid); result = await downloadJannyCharacter(uuid);
} else if (isAICharacterCardsContent) {
const AICCParsed = parseAICC(url);
if (!AICCParsed) {
return response.sendStatus(404);
}
type = 'character';
result = await downloadAICCCharacter(AICCParsed);
} else { } else {
const chubParsed = parseChubUrl(url); const chubParsed = parseChubUrl(url);
type = chubParsed?.type; type = chubParsed?.type;
@ -428,6 +470,7 @@ router.post('/importUUID', jsonParser, async (request, response) => {
const isJannny = uuid.includes('_character'); const isJannny = uuid.includes('_character');
const isPygmalion = (!isJannny && uuid.length == 36); const isPygmalion = (!isJannny && uuid.length == 36);
const isAICC = uuid.startsWith('AICC/');
const uuidType = uuid.includes('lorebook') ? 'lorebook' : 'character'; const uuidType = uuid.includes('lorebook') ? 'lorebook' : 'character';
if (isPygmalion) { if (isPygmalion) {
@ -436,6 +479,10 @@ router.post('/importUUID', jsonParser, async (request, response) => {
} else if (isJannny) { } else if (isJannny) {
console.log('Downloading Janitor character:', uuid.split('_')[0]); console.log('Downloading Janitor character:', uuid.split('_')[0]);
result = await downloadJannyCharacter(uuid.split('_')[0]); result = await downloadJannyCharacter(uuid.split('_')[0]);
} else if (isAICC) {
const [, author, card] = uuid.split('/');
console.log('Downloading AICC character:', `${author}/${card}`);
result = await downloadAICCCharacter(`${author}/${card}`);
} else { } else {
if (uuidType === 'character') { if (uuidType === 'character') {
console.log('Downloading chub character:', uuid); console.log('Downloading chub character:', uuid);