Add support for importing character from JanitorAI (#1401)

* Add Janny support

* Add description

* Remove unofficial JanAI mirror
This commit is contained in:
dllt98 2023-11-27 08:29:19 +07:00 committed by GitHub
parent c742251c5a
commit 50ebd1cf66
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 70 additions and 13 deletions

View File

@ -9367,6 +9367,7 @@ jQuery(async function () {
<ul class="justifyLeft">
<li>Chub characters (direct link or id)<br>Example: <tt>Anonymous/example-character</tt></li>
<li>Chub lorebooks (direct link or id)<br>Example: <tt>lorebooks/bartleby/example-lorebook</tt></li>
<li>JanitorAI character (direct link or id)<br>Example: <tt>https://janitorai.com/characters/ddd1498a-a370-4136-b138-a8cd9461fdfe_character-aqua-the-useless-goddess</tt></li>
<li>More coming soon...</li>
<ul>`
const input = await callPopup(html, 'input');

View File

@ -176,6 +176,49 @@ function parseChubUrl(str) {
return null;
}
// Warning: Some characters might not exist in JannyAI.me
async function downloadJannyCharacter(uuid) {
// This endpoint is being guarded behind Bot Fight Mode of Cloudflare
// So hosted ST on Azure/AWS/GCP/Collab might get blocked by IP
// Should work normally on self-host PC/Android
const result = await fetch('https://api.janitorai.me/api/v1/download', {
method: 'POST',
headers: { 'Content-Type': 'application/json'},
body: JSON.stringify({
"characterId": uuid,
})
});
if (result.ok) {
const downloadResult = await result.json();
if (downloadResult.status === 'ok') {
const imageResult = await fetch(downloadResult.downloadUrl)
const buffer = await imageResult.buffer();
const fileName = `${sanitize(uuid)}.png`;
const fileType = result.headers.get('content-type');
return { buffer, fileName, fileType };
}
}
console.log('Janny returned error', result.statusText, await result.text());
throw new Error('Failed to download character');
}
/**
* @param {String} url
* @returns {String | null } UUID of the character
*/
function parseJannyUrl(url) {
// Extract UUID from URL
const uuidRegex = /[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}/;
const matches = url.match(uuidRegex);
// Check if UUID is found
const uuid = matches ? matches[0] : null;
return uuid
}
/**
* Registers endpoints for custom content management
* @param {import('express').Express} app Express app
@ -190,24 +233,37 @@ function registerEndpoints(app, jsonParser) {
try {
const url = request.body.url;
let result;
let type;
const chubParsed = parseChubUrl(url);
const isJannnyContent = url.includes('janitorai')
if (isJannnyContent) {
const uuid = parseJannyUrl(url);
if (!uuid) {
return response.sendStatus(404);
}
if (chubParsed?.type === 'character') {
console.log('Downloading chub character:', chubParsed.id);
result = await downloadChubCharacter(chubParsed.id);
}
else if (chubParsed?.type === 'lorebook') {
console.log('Downloading chub lorebook:', chubParsed.id);
result = await downloadChubLorebook(chubParsed.id);
}
else {
return response.sendStatus(404);
}
type = 'character';
result = await downloadJannyCharacter(uuid);
} else {
const chubParsed = parseChubUrl(url);
type = chubParsed?.type;
if (chubParsed?.type === 'character') {
console.log('Downloading chub character:', chubParsed.id);
result = await downloadChubCharacter(chubParsed.id);
}
else if (chubParsed?.type === 'lorebook') {
console.log('Downloading chub lorebook:', chubParsed.id);
result = await downloadChubLorebook(chubParsed.id);
}
else {
return response.sendStatus(404);
}
}
if (result.fileType) response.set('Content-Type', result.fileType)
response.set('Content-Disposition', `attachment; filename="${result.fileName}"`);
response.set('X-Custom-Content-Type', chubParsed?.type);
response.set('X-Custom-Content-Type', type);
return response.send(result.buffer);
} catch (error) {
console.log('Importing custom content failed', error);