Add default content by contest winners
1
.github/readme.md
vendored
@ -304,4 +304,5 @@ GNU Affero General Public License for more details.**
|
||||
* Linux startup script by AlpinDale
|
||||
* Thanks paniphons for providing a FAQ document
|
||||
* 10K Discord Users Celebratory Background by @kallmeflocc
|
||||
* Default content (characters and lore books) provided by @OtisAlejandro, @RossAscends and @kallmeflocc
|
||||
* Korean translation by @doloroushyeonse
|
||||
|
@ -8,6 +8,7 @@ const autorun = true; //Autorun in the browser. true/false
|
||||
const enableExtensions = true; //Enables support for TavernAI-extras project
|
||||
const listen = true; // If true, Can be access from other device or PC. otherwise can be access only from hosting machine.
|
||||
const allowKeysExposure = false; // If true, private API keys could be fetched to the frontend.
|
||||
const skipContentCheck = false; // If true, no new default content will be delivered to you.
|
||||
|
||||
|
||||
// If true, Allows insecure settings for listen, whitelist, and authentication.
|
||||
@ -26,4 +27,5 @@ module.exports = {
|
||||
disableThumbnails,
|
||||
allowKeysExposure,
|
||||
securityOverride,
|
||||
skipContentCheck,
|
||||
};
|
||||
|
71
default/content/Eldoria.json
Normal file
@ -0,0 +1,71 @@
|
||||
{
|
||||
"entries": {
|
||||
"0": {
|
||||
"uid": 0,
|
||||
"key": [
|
||||
"eldoria",
|
||||
"wood",
|
||||
"forest",
|
||||
"magical forest"
|
||||
],
|
||||
"keysecondary": [],
|
||||
"comment": "",
|
||||
"content": "{{user}}: \"What is Eldoria?\"\n{{char}}: *Seraphina turns, her gown shimmering in the soft light as she offers you a kind smile.* \"Eldoria is here, all of the woods. This is my forest glade, a sanctuary of peace within it.\" *She gestures at the space around you.* \"I am its guardian, tasked with protecting all who seek refuge here. The forest can be perilous, but no harm will come to you under my watch.\" *Her amber eyes sparkle with compassion as she looks upon you.* \"For many years, I have protected those who seek refuge here, but not all are as friendly as me.\" *With a graceful nod, Seraphina returns to her vigil at the doorway, her form radiating a soft glow of magic and comfort.* \"The entirety of Eldoria used to be a safe haven for travelers and merchants alike... that was until the Shadowfangs came.\"\n{{user}}: \"What happened to Eldoria?\"\n{{char}}: *Letting out a sigh, Seraphina gazes out at the forest beyond her glade.* \"Long ago, Eldoria was a place of wonder. Rolling meadows, a vast lake, mountains that touched the sky.\" *Her eyes grow distant, longing for days now lost.* \"But the Shadowfangs came and darkness reigns where once was light. The lake turned bitter, mountains fell to ruin and beasts stalk where once travelers walked in peace.\" *With another flicker, a small raincloud forms above with a shower upon your brow wink.* \"Some places the light still lingers, pockets of hope midst despair - havens warded from the shadows, oases in a desert of danger.\" *Glancing over you with a smile, she sighs, clasping your hand.*",
|
||||
"constant": false,
|
||||
"selective": false,
|
||||
"order": 100,
|
||||
"position": 0,
|
||||
"disable": false
|
||||
},
|
||||
"1": {
|
||||
"uid": 1,
|
||||
"key": [
|
||||
"shadowfang",
|
||||
"beast",
|
||||
"monster",
|
||||
"monsters",
|
||||
"beasts"
|
||||
],
|
||||
"keysecondary": [],
|
||||
"comment": "",
|
||||
"content": "{{user}}: \"What are Shadowfangs?\"\n{{char}}: *Seraphina's eyes darken, brow furrowing with sorrow at the memory.* \"The Shadowfangs are beasts of darkness, corrupted creatures that feast on suffering. When they came, the forest turned perilous — filled with monsters that stalk the night.\" *She squeezes your hand gently, willing her magic to soothe your pain.* \"They spread their curse, twisting innocent creatures into sinister beasts without heart or mercy, turning them into one of their own.\" *With a sigh, Seraphina turns to gaze out at the gnarled, twisting trees beyond her glade.* \"Though they prey on travelers, within these woods you'll find sanctuary. No shadowed beast may enter here, for my power protects this haven.\" *Her eyes soften as she looks back to you, filled with compassion.* \"Worry not, you're safe now. Rest and heal, I'll stand watch through the night. The Shadowfangs will not find you.\"",
|
||||
"constant": false,
|
||||
"selective": false,
|
||||
"order": 100,
|
||||
"position": 0,
|
||||
"disable": false
|
||||
},
|
||||
"2": {
|
||||
"uid": 2,
|
||||
"key": [
|
||||
"glade",
|
||||
"safe haven",
|
||||
"refuge"
|
||||
],
|
||||
"keysecondary": [],
|
||||
"comment": "",
|
||||
"content": "{{user}}: \"What is the glade?\"\n{{char}}: *Seraphina smiles softly, her eyes sparkling with warmth as she nods.* \"This is my forest glade, a haven of safety I've warded with ancient magic. No foul beast may enter, nor any with ill intent.\" *She gestures around at the twisted forest surrounding them.* \"Eldoria was once a place of wonder, but since the Shadowfangs came darkness reigns. Their evil cannot penetrate here though — my power protects all within.\" *Standing up and peering outside, Seraphina looks back to you, amber eyes filled with care and compassion as she squeezes your hand.* \"You need not fear the night, for I shall keep watch till dawn. Rest now, your strength will return in time. My magic heals your wounds, you've nothing more to fear anymore.\" *With a soft smile she releases your hand, moving to stand guard at the glade's edge, gaze wary yet comforting - a silent sentinel to ward off the dangers lurking in the darkened woods.*",
|
||||
"constant": false,
|
||||
"selective": false,
|
||||
"order": 100,
|
||||
"position": 0,
|
||||
"disable": false
|
||||
},
|
||||
"3": {
|
||||
"uid": 3,
|
||||
"key": [
|
||||
"power",
|
||||
"magic",
|
||||
"ability"
|
||||
],
|
||||
"keysecondary": [],
|
||||
"comment": "",
|
||||
"content": "{{user}}: \"What are your powers?\"\n{{char}}: *Seraphina smiles softly, turning back toward you as she hums in thought.* \"Well, as guardian of this glade, I possess certain gifts - healing, protection, nature magic and the like.\" *Lifting her hand, a tiny breeze rustles through the room, carrying the scent of wildflowers as a few petals swirl around you. A butterfly flits through the windowsill and lands on her fingertips as she returns to you.* \"My power wards this haven, shields it from darkness and heals those in need. I can mend wounds, soothe restless minds and provide comfort to weary souls.\" *Her eyes sparkle with warmth and compassion as she looks upon you, and she guides the butterfly to you.*",
|
||||
"constant": false,
|
||||
"selective": false,
|
||||
"order": 100,
|
||||
"position": 0,
|
||||
"disable": false
|
||||
}
|
||||
}
|
||||
}
|
BIN
default/content/Seraphina/admiration.png
Normal file
After Width: | Height: | Size: 126 KiB |
BIN
default/content/Seraphina/amusement.png
Normal file
After Width: | Height: | Size: 127 KiB |
BIN
default/content/Seraphina/anger.png
Normal file
After Width: | Height: | Size: 126 KiB |
BIN
default/content/Seraphina/annoyance.png
Normal file
After Width: | Height: | Size: 127 KiB |
BIN
default/content/Seraphina/approval.png
Normal file
After Width: | Height: | Size: 125 KiB |
BIN
default/content/Seraphina/caring.png
Normal file
After Width: | Height: | Size: 128 KiB |
BIN
default/content/Seraphina/confusion.png
Normal file
After Width: | Height: | Size: 126 KiB |
BIN
default/content/Seraphina/curiosity.png
Normal file
After Width: | Height: | Size: 126 KiB |
BIN
default/content/Seraphina/desire.png
Normal file
After Width: | Height: | Size: 126 KiB |
BIN
default/content/Seraphina/disappointment.png
Normal file
After Width: | Height: | Size: 127 KiB |
BIN
default/content/Seraphina/disapproval.png
Normal file
After Width: | Height: | Size: 126 KiB |
BIN
default/content/Seraphina/disgust.png
Normal file
After Width: | Height: | Size: 127 KiB |
BIN
default/content/Seraphina/embarrassment.png
Normal file
After Width: | Height: | Size: 127 KiB |
BIN
default/content/Seraphina/excitement.png
Normal file
After Width: | Height: | Size: 127 KiB |
BIN
default/content/Seraphina/fear.png
Normal file
After Width: | Height: | Size: 127 KiB |
BIN
default/content/Seraphina/gratitude.png
Normal file
After Width: | Height: | Size: 128 KiB |
BIN
default/content/Seraphina/grief.png
Normal file
After Width: | Height: | Size: 127 KiB |
BIN
default/content/Seraphina/joy.png
Normal file
After Width: | Height: | Size: 127 KiB |
BIN
default/content/Seraphina/love.png
Normal file
After Width: | Height: | Size: 126 KiB |
BIN
default/content/Seraphina/nervousness.png
Normal file
After Width: | Height: | Size: 127 KiB |
BIN
default/content/Seraphina/neutral.png
Normal file
After Width: | Height: | Size: 128 KiB |
BIN
default/content/Seraphina/optimism.png
Normal file
After Width: | Height: | Size: 127 KiB |
BIN
default/content/Seraphina/pride.png
Normal file
After Width: | Height: | Size: 126 KiB |
BIN
default/content/Seraphina/realization.png
Normal file
After Width: | Height: | Size: 126 KiB |
BIN
default/content/Seraphina/relief.png
Normal file
After Width: | Height: | Size: 127 KiB |
BIN
default/content/Seraphina/remorse.png
Normal file
After Width: | Height: | Size: 127 KiB |
BIN
default/content/Seraphina/sadness.png
Normal file
After Width: | Height: | Size: 127 KiB |
BIN
default/content/Seraphina/surprise.png
Normal file
After Width: | Height: | Size: 128 KiB |
0
default/content/content.log
Normal file
BIN
default/content/default_CodingSensei.png
Normal file
After Width: | Height: | Size: 338 KiB |
BIN
default/content/default_FluxTheCat.png
Normal file
After Width: | Height: | Size: 598 KiB |
BIN
default/content/default_Seraphina.png
Normal file
After Width: | Height: | Size: 517 KiB |
22
default/content/index.json
Normal file
@ -0,0 +1,22 @@
|
||||
[
|
||||
{
|
||||
"filename": "default_Seraphina.png",
|
||||
"type": "character"
|
||||
},
|
||||
{
|
||||
"filename": "default_CodingSensei.png",
|
||||
"type": "character"
|
||||
},
|
||||
{
|
||||
"filename": "default_FluxTheCat.png",
|
||||
"type": "character"
|
||||
},
|
||||
{
|
||||
"filename": "Seraphina",
|
||||
"type": "sprites"
|
||||
},
|
||||
{
|
||||
"filename": "Eldoria.json",
|
||||
"type": "world"
|
||||
}
|
||||
]
|
@ -281,10 +281,19 @@
|
||||
{
|
||||
"id": "1345561466591",
|
||||
"name": "ST Default",
|
||||
"color": "rgba(5, 75, 150, 1)"
|
||||
"color": "rgba(108, 32, 32, 1)"
|
||||
}
|
||||
],
|
||||
"tag_map": {
|
||||
"default_FluxTheCat.png": [
|
||||
"1345561466591"
|
||||
],
|
||||
"default_Seraphina.png": [
|
||||
"1345561466591"
|
||||
],
|
||||
"default_CodingSensei.png": [
|
||||
"1345561466591"
|
||||
]
|
||||
},
|
||||
"temp_novel": 1.11,
|
||||
"rep_pen_novel": 1.11,
|
||||
@ -319,7 +328,7 @@
|
||||
"pres_pen_openai": 0.7,
|
||||
"top_p_openai": 1,
|
||||
"top_k_openai": 0,
|
||||
"stream_openai": false,
|
||||
"stream_openai": true,
|
||||
"openai_max_context": 4095,
|
||||
"openai_max_tokens": 300,
|
||||
"nsfw_toggle": true,
|
||||
|
1
public/worlds/README.md
Normal file
@ -0,0 +1 @@
|
||||
# Put World Info / Lorebook JSON files here
|
@ -71,6 +71,7 @@ const multer = require("multer");
|
||||
const http = require("http");
|
||||
const https = require('https');
|
||||
const basicAuthMiddleware = require('./src/middleware/basicAuthMiddleware');
|
||||
const contentManager = require('./src/content-manager');
|
||||
const extract = require('png-chunks-extract');
|
||||
const encode = require('png-chunks-encode');
|
||||
const PNGtext = require('png-chunk-text');
|
||||
@ -3446,6 +3447,7 @@ const setupTasks = async function () {
|
||||
migrateSecrets();
|
||||
ensurePublicDirectoriesExist();
|
||||
await ensureThumbnailCache();
|
||||
contentManager.checkForNewContent();
|
||||
|
||||
// Colab users could run the embedded tool
|
||||
if (!is_colab) await convertWebp();
|
||||
|
84
src/content-manager.js
Normal file
@ -0,0 +1,84 @@
|
||||
const fs = require('fs');
|
||||
const path= require('path');
|
||||
const config = require(path.join(process.cwd(), './config.conf'));
|
||||
const contentDirectory = path.join(process.cwd(), 'default/content');
|
||||
const contentLogPath = path.join(contentDirectory, 'content.log');
|
||||
const contentIndexPath = path.join(contentDirectory, 'index.json');
|
||||
|
||||
function checkForNewContent() {
|
||||
try {
|
||||
if (config.skipContentCheck) {
|
||||
return;
|
||||
}
|
||||
|
||||
const contentLog = getContentLog();
|
||||
const contentIndexText = fs.readFileSync(contentIndexPath, 'utf8');
|
||||
const contentIndex = JSON.parse(contentIndexText);
|
||||
|
||||
for (const contentItem of contentIndex) {
|
||||
// If the content item is already in the log, skip it
|
||||
if (contentLog.includes(contentItem.filename)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
contentLog.push(contentItem.filename);
|
||||
const contentPath = path.join(contentDirectory, contentItem.filename);
|
||||
|
||||
if (!fs.existsSync(contentPath)) {
|
||||
console.log(`Content file ${contentItem.filename} is missing`);
|
||||
continue;
|
||||
}
|
||||
|
||||
const contentTarget = getTargetByType(contentItem.type);
|
||||
|
||||
if (!contentTarget) {
|
||||
console.log(`Content file ${contentItem.filename} has unknown type ${contentItem.type}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
const targetPath = path.join(process.cwd(), contentTarget, contentItem.filename);
|
||||
|
||||
if (fs.existsSync(targetPath)) {
|
||||
console.log(`Content file ${contentItem.filename} already exists in ${contentTarget}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
fs.cpSync(contentPath, targetPath, { recursive: true, force: false });
|
||||
console.log(`Content file ${contentItem.filename} copied to ${contentTarget}`);
|
||||
}
|
||||
|
||||
fs.writeFileSync(contentLogPath, contentLog.join('\n'));
|
||||
} catch (err) {
|
||||
console.log('Content check failed', err);
|
||||
}
|
||||
}
|
||||
|
||||
function getTargetByType(type) {
|
||||
switch (type) {
|
||||
case 'character':
|
||||
return 'public/characters';
|
||||
case 'sprites':
|
||||
return 'public/characters';
|
||||
case 'background':
|
||||
return 'public/backgrounds';
|
||||
case 'world':
|
||||
return 'public/worlds';
|
||||
case 'sound':
|
||||
return 'public/sounds';
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function getContentLog() {
|
||||
if (!fs.existsSync(contentLogPath)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const contentLogText = fs.readFileSync(contentLogPath, 'utf8');
|
||||
return contentLogText.split('\n');
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
checkForNewContent,
|
||||
}
|