diff --git a/.github/readme-zh_cn.md b/.github/readme-zh_cn.md index 415fce22..9fafb2d8 100644 --- a/.github/readme-zh_cn.md +++ b/.github/readme-zh_cn.md @@ -170,7 +170,7 @@ SillyTavern 会将 API 密钥保存在目录中的 `secrets.json` 文件内。 如果要想通过点击 API 输入框旁边的按钮来查看密钥,请按照以下设置: -1. 打开 `config.conf` 文件,将里面的 `allowKeysExposure` 设置为 `true`。 +1. 打开 `config.yaml` 文件,将里面的 `allowKeysExposure` 设置为 `true`。 2. 然后重启 SillyTavern 服务。 ## 远程访问 @@ -207,7 +207,7 @@ SillyTavern 会将 API 密钥保存在目录中的 `secrets.json` 文件内。 然后,文件中设置的 IP 就可以访问 SillyTavern 了。 -*注意:"config.conf" 文件内也有一个 "whitelist" 设置,你可以用同样的方法设置它,但如果 "whitelist.txt" 文件存在,这个设置将被忽略。 +*注意:"config.yaml" 文件内也有一个 "whitelist" 设置,你可以用同样的方法设置它,但如果 "whitelist.txt" 文件存在,这个设置将被忽略。 ### 2.获取 SillyTavern 服务的 IP 地址 @@ -233,19 +233,19 @@ SillyTavern 会将 API 密钥保存在目录中的 `secrets.json` 文件内。 ### 向所有 IP 开放您的 SillyTavern 服务 -我们不建议这样做,但您可以打开 `config.conf` 并将里面的 `whitelist` 设置改为 `false`。 +我们不建议这样做,但您可以打开 `config.yaml` 并将里面的 `whitelist` 设置改为 `false`。 你必须删除(或重命名)SillyTavern 文件夹中的 `whitelist.txt` 文件(如果有的话)。 这通常是不安全的做法,所以我们要求在这样做时必须设置用户名和密码。 -用户名和密码在`config.conf`文件中设置。 +用户名和密码在`config.yaml`文件中设置。 重启 SillyTavern 服务后,只要知道用户名和密码,任何设备都可以访问。 ### 还是无法访问? -* 为 `config.conf` 文件中的端口创建一条入站/出站防火墙规则。切勿将此误认为是路由器上的端口转发,否则,有人可能会发现你的聊天隐私,那就大错特错了。 +* 为 `config.yaml` 文件中的端口创建一条入站/出站防火墙规则。切勿将此误认为是路由器上的端口转发,否则,有人可能会发现你的聊天隐私,那就大错特错了。 * 在 "设置" > "网络和 Internet" > "以太网" 中启用 "专用网络" 配置。这对 Windows 11 非常重要,否则即使添加了上述防火墙规则也无法连接。 ### 性能问题? diff --git a/.github/readme.md b/.github/readme.md index 3fa3826b..cbcc8e30 100644 --- a/.github/readme.md +++ b/.github/readme.md @@ -173,7 +173,7 @@ By default, they will not be exposed to a frontend after you enter them and relo In order to enable viewing your keys by clicking a button in the API block: -1. Set the value of `allowKeysExposure` to `true` in `config.conf` file. +1. Set the value of `allowKeysExposure` to `true` in `config.yaml` file. 2. Restart the SillyTavern server. ## Remote connections @@ -211,7 +211,7 @@ CIDR masks are also accepted (eg. 10.0.0.0/24). Now devices which have the IP specified in the file will be able to connect. -*Note: `config.conf` also has a `whitelist` array, which you can use in the same way, but this array will be ignored if `whitelist.txt` exists.* +*Note: `config.yaml` also has a `whitelist` array, which you can use in the same way, but this array will be ignored if `whitelist.txt` exists.* ### 2. Getting the IP for the ST host machine @@ -237,19 +237,19 @@ Use http:// NOT https:// ### Opening your ST to all IPs -We do not recommend doing this, but you can open `config.conf` and change `whitelist` to `false`. +We do not recommend doing this, but you can open `config.yaml` and change `whitelist` to `false`. You must remove (or rename) `whitelist.txt` in the SillyTavern base install folder if it exists. This is usually an insecure practice, so we require you to set a username and password when you do this. -The username and password are set in `config.conf`. +The username and password are set in `config.yaml`. After restarting your ST server, any device will be able to connect to it, regardless of their IP as long as they know the username and password. ### Still Unable To Connect? -* Create an inbound/outbound firewall rule for the port found in `config.conf`. Do NOT mistake this for port-forwarding on your router, otherwise, someone could find your chat logs and that's a big no-no. +* Create an inbound/outbound firewall rule for the port found in `config.yaml`. Do NOT mistake this for port-forwarding on your router, otherwise, someone could find your chat logs and that's a big no-no. * Enable the Private Network profile type in Settings > Network and Internet > Ethernet. This is VERY important for Windows 11, otherwise, you would be unable to connect even with the aforementioned firewall rules. ## Performance issues? diff --git a/.gitignore b/.gitignore index 507f9161..ae782859 100644 --- a/.gitignore +++ b/.gitignore @@ -20,6 +20,8 @@ public/stats.json /uploads/ *.jsonl /config.conf +/config.yaml +/config.conf.bak /docker/config .DS_Store public/settings.json diff --git a/Dockerfile b/Dockerfile index 3afd3b7a..ec0f2e94 100644 --- a/Dockerfile +++ b/Dockerfile @@ -31,7 +31,7 @@ RUN \ echo "*** Create symbolic links to config directory ***" && \ for R in $RESOURCES; do ln -s "../config/$R" "public/$R"; done || true && \ \ - ln -s "./config/config.conf" "config.conf" || true && \ + ln -s "./config/config.yaml" "config.yaml" || true && \ ln -s "../config/settings.json" "public/settings.json" || true && \ ln -s "../../config/bg_load.css" "public/css/bg_load.css" || true && \ mkdir "config" || true diff --git a/Remote-Link.cmd b/Remote-Link.cmd index f44f232f..2747abdd 100644 --- a/Remote-Link.cmd +++ b/Remote-Link.cmd @@ -4,7 +4,7 @@ echo WARNING: Cloudflare Tunnel! echo ======================================================================================================================== echo This script downloads and runs the latest cloudflared.exe from Cloudflare to set up an HTTPS tunnel to your SillyTavern! echo Using the randomly generated temporary tunnel URL, anyone can access your SillyTavern over the Internet while the tunnel -echo is active. Keep the URL safe and secure your SillyTavern installation by setting a username and password in config.conf! +echo is active. Keep the URL safe and secure your SillyTavern installation by setting a username and password in config.yaml! echo. echo See https://docs.sillytavern.app/usage/remoteconnections/ for more details about how to secure your SillyTavern install. echo. diff --git a/default/config.conf b/default/config.conf deleted file mode 100644 index a256fd23..00000000 --- a/default/config.conf +++ /dev/null @@ -1,57 +0,0 @@ -const port = 8000; -const whitelist = ['127.0.0.1']; //Example for add several IP in whitelist: ['127.0.0.1', '192.168.0.10'] -const whitelistMode = true; //Disabling enabling the ip whitelist mode. true/false -const basicAuthMode = false; //Toggle basic authentication for endpoints. -const basicAuthUser = {username: "user", password: "password"}; //Login credentials when basicAuthMode is true. -const disableThumbnails = false; //Disables the generation of thumbnails, opting to use the raw images instead -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. -const thumbnailsQuality = 95; // Quality of thumbnails. 0-100 -const disableChatBackup = false; // Disables the backup of chat logs to the /backups folder -const enableCorsProxy = false; // Enables the CORS proxy for the frontend - -// If true, Allows insecure settings for listen, whitelist, and authentication. -// Change this setting only on "trusted networks". Do not change this value unless you are aware of the issues that can arise from changing this setting and configuring a insecure setting. -const securityOverride = false; - -// Additional settings for extra modules / extensions -const extras = { - // Disables auto-download of models from the HuggingFace Hub. - // You will need to manually download the models and put them into the /cache folder. - disableAutoDownload: false, - // Text classification model for sentiment analysis. HuggingFace ID of a model in ONNX format. - classificationModel: 'Cohee/distilbert-base-uncased-go-emotions-onnx', - // Image captioning model. HuggingFace ID of a model in ONNX format. - captioningModel: 'Xenova/vit-gpt2-image-captioning', - // Feature extraction model. HuggingFace ID of a model in ONNX format. - embeddingModel: 'Xenova/all-mpnet-base-v2', - // GPT-2 text generation model. HuggingFace ID of a model in ONNX format. - promptExpansionModel: 'Cohee/fooocus_expansion-onnx', -}; - -// Request overrides for additional headers -// Format is an array of objects: -// { hosts: [ "" ], headers: {
: "" } } -const requestOverrides = []; - -module.exports = { - port, - whitelist, - whitelistMode, - basicAuthMode, - basicAuthUser, - autorun, - enableExtensions, - listen, - disableThumbnails, - allowKeysExposure, - securityOverride, - skipContentCheck, - requestOverrides, - thumbnailsQuality, - extras, - disableChatBackup, -}; diff --git a/default/config.yaml b/default/config.yaml new file mode 100644 index 00000000..c129b39a --- /dev/null +++ b/default/config.yaml @@ -0,0 +1,53 @@ +# -- NETWORK CONFIGURATION -- +# Listen for incoming connections +listen: true +# Server port +port: 8000 +# Toggle whitelist mode +whitelistMode: true +# Whitelist of allowed IP addresses +whitelist: + - 127.0.0.1 +# Toggle basic authentication for endpoints +basicAuthMode: false +# Basic authentication credentials +basicAuthUser: + username: user + password: password +# Enables CORS proxy middleware +enableCorsProxy: false +# Disable security checks - NOT RECOMMENDED +securityOverride: false +# -- ADVANCED CONFIGURATION -- +# Open the browser automatically +autorun: true +# Disable thumbnail generation +disableThumbnails: false +# Thumbnail quality (0-100) +thumbnailsQuality: 95 +# Allow secret keys exposure via API +allowKeysExposure: false +# Skip new default content checks +skipContentCheck: false +# Disable automatic chats backup +disableChatBackup: false +# API request overrides (for KoboldAI and Text Completion APIs) +## Format is an array of objects: +## - hosts: +## - example.com +## headers: +## Content-Type: application/json +requestOverrides: [] +# -- PLUGIN CONFIGURATION -- +# Enable UI extensions +enableExtensions: true +# Extension settings +extras: + # Disables automatic model download from HuggingFace + disableAutoDownload: false + # Extra models for plugins. Expects model IDs from HuggingFace model hub in ONNX format + classificationModel: Cohee/distilbert-base-uncased-go-emotions-onnx + captioningModel: Xenova/vit-gpt2-image-captioning + embeddingModel: Xenova/all-mpnet-base-v2 + promptExpansionModel: Cohee/fooocus_expansion-onnx + diff --git a/docker/docker-entrypoint.sh b/docker/docker-entrypoint.sh index f3dd2aae..69d8aa68 100644 --- a/docker/docker-entrypoint.sh +++ b/docker/docker-entrypoint.sh @@ -9,9 +9,9 @@ for R in $RESOURCES; do fi done -if [ ! -e "config/config.conf" ]; then - echo "Resource not found, copying from defaults: config.conf" - cp -r "default/config.conf" "config/config.conf" +if [ ! -e "config/config.yaml" ]; then + echo "Resource not found, copying from defaults: config.yaml" + cp -r "default/config.yaml" "config/config.yaml" fi if [ ! -e "config/settings.json" ]; then @@ -24,15 +24,15 @@ if [ ! -e "config/bg_load.css" ]; then cp -r "default/bg_load.css" "config/bg_load.css" fi -CONFIG_FILE="config.conf" +CONFIG_FILE="config.yaml" -if grep -q "listen = false" $CONFIG_FILE; then - echo -e "\033[1;31mThe listen parameter is set to false. If you can't connect to the server, edit the \"docker/config/config.conf\" file and restart the container.\033[0m" +if grep -q "listen: false" $CONFIG_FILE; then + echo -e "\033[1;31mThe listen parameter is set to false. If you can't connect to the server, edit the \"docker/config/config.yaml\" file and restart the container.\033[0m" sleep 5 fi -if grep -q "whitelistMode = true" $CONFIG_FILE; then - echo -e "\033[1;31mThe whitelistMode parameter is set to true. If you can't connect to the server, edit the \"docker/config/config.conf\" file and restart the container.\033[0m" +if grep -q "whitelistMode: true" $CONFIG_FILE; then + echo -e "\033[1;31mThe whitelistMode parameter is set to true. If you can't connect to the server, edit the \"docker/config/config.yaml\" file and restart the container.\033[0m" sleep 5 fi diff --git a/package-lock.json b/package-lock.json index 37ad9a26..3ca8ea04 100644 --- a/package-lock.json +++ b/package-lock.json @@ -43,6 +43,7 @@ "vectra": "^0.2.2", "write-file-atomic": "^5.0.1", "ws": "^8.13.0", + "yaml": "^2.3.4", "yargs": "^17.7.1", "yauzl": "^2.10.0" }, @@ -4388,6 +4389,14 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, + "node_modules/yaml": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.4.tgz", + "integrity": "sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==", + "engines": { + "node": ">= 14" + } + }, "node_modules/yargs": { "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", diff --git a/package.json b/package.json index 2b9f1030..2289b052 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ "vectra": "^0.2.2", "write-file-atomic": "^5.0.1", "ws": "^8.13.0", + "yaml": "^2.3.4", "yargs": "^17.7.1", "yauzl": "^2.10.0" }, diff --git a/post-install.js b/post-install.js index 489bf840..541ce35f 100644 --- a/post-install.js +++ b/post-install.js @@ -4,6 +4,102 @@ const fs = require('fs'); const path = require('path'); const crypto = require('crypto'); +const yaml = require('yaml'); +const _ = require('lodash'); + +/** + * Colorizes console output. + */ +const color = { + byNum: (mess, fgNum) => { + mess = mess || ''; + fgNum = fgNum === undefined ? 31 : fgNum; + return '\u001b[' + fgNum + 'm' + mess + '\u001b[39m'; + }, + black: (mess) => color.byNum(mess, 30), + red: (mess) => color.byNum(mess, 31), + green: (mess) => color.byNum(mess, 32), + yellow: (mess) => color.byNum(mess, 33), + blue: (mess) => color.byNum(mess, 34), + magenta: (mess) => color.byNum(mess, 35), + cyan: (mess) => color.byNum(mess, 36), + white: (mess) => color.byNum(mess, 37) +}; + +/** + * Gets all keys from an object recursively. + * @param {object} obj Object to get all keys from + * @param {string} prefix Prefix to prepend to all keys + * @returns {string[]} Array of all keys in the object + */ +function getAllKeys(obj, prefix = '') { + if (typeof obj !== 'object' || Array.isArray(obj)) { + return []; + } + + return _.flatMap(Object.keys(obj), key => { + const newPrefix = prefix ? `${prefix}.${key}` : key; + if (typeof obj[key] === 'object' && !Array.isArray(obj[key])) { + return getAllKeys(obj[key], newPrefix); + } else { + return [newPrefix]; + } + }); +} + +/** + * Converts the old config.conf file to the new config.yaml format. + */ +function convertConfig() { + if (fs.existsSync('./config.conf')) { + if (fs.existsSync('./config.yaml')) { + console.log(color.yellow('Both config.conf and config.yaml exist. Please delete config.conf manually.')); + return; + } + + try { + console.log(color.blue('Converting config.conf to config.yaml. Your old config.conf will be renamed to config.conf.bak')); + const config = require(path.join(process.cwd(), './config.conf')); + fs.renameSync('./config.conf', './config.conf.bak'); + fs.writeFileSync('./config.yaml', yaml.stringify(config)); + console.log(color.green('Conversion successful. Please check your config.yaml and fix it if necessary.')); + } catch (error) { + console.error(color.red('FATAL: Config conversion failed. Please check your config.conf file and try again.')); + return; + } + } +} + +/** + * Compares the current config.yaml with the default config.yaml and adds any missing values. + */ +function addMissingConfigValues() { + try { + const defaultConfig = yaml.parse(fs.readFileSync(path.join(process.cwd(), './default/config.yaml'), 'utf8')); + let config = yaml.parse(fs.readFileSync(path.join(process.cwd(), './config.yaml'), 'utf8')); + + // Get all keys from the original config + const originalKeys = getAllKeys(config); + + // Use lodash's defaultsDeep function to recursively apply default properties + config = _.defaultsDeep(config, defaultConfig); + + // Get all keys from the updated config + const updatedKeys = getAllKeys(config); + + // Find the keys that were added + const addedKeys = _.difference(updatedKeys, originalKeys); + + if (addedKeys.length === 0) { + return; + } + + console.log('Adding missing config values to config.yaml:', addedKeys); + fs.writeFileSync('./config.yaml', yaml.stringify(config)); + } catch (error) { + console.error(color.red('FATAL: Could not add missing config values to config.yaml'), error); + } +} /** * Creates the default config files if they don't exist yet. @@ -12,7 +108,7 @@ function createDefaultFiles() { const files = { settings: './public/settings.json', bg_load: './public/css/bg_load.css', - config: './config.conf', + config: './config.yaml', user: './public/css/user.css', }; @@ -21,10 +117,10 @@ function createDefaultFiles() { if (!fs.existsSync(file)) { const defaultFilePath = path.join('./default', path.parse(file).base); fs.copyFileSync(defaultFilePath, file); - console.log(`Created default file: ${file}`); + console.log(color.green(`Created default file: ${file}`)); } } catch (error) { - console.error(`FATAL: Could not write default file: ${file}`, error); + console.error(color.red(`FATAL: Could not write default file: ${file}`), error); } } } @@ -73,10 +169,14 @@ function copyWasmFiles() { } try { + // 0. Convert config.conf to config.yaml + convertConfig(); // 1. Create default config files createDefaultFiles(); // 2. Copy transformers WASM binaries from node_modules copyWasmFiles(); + // 3. Add missing config values + addMissingConfigValues(); } catch (error) { console.error(error); } diff --git a/public/scripts/secrets.js b/public/scripts/secrets.js index 0e23eb4d..395fce92 100644 --- a/public/scripts/secrets.js +++ b/public/scripts/secrets.js @@ -55,7 +55,7 @@ async function viewSecrets() { }); if (response.status == 403) { - callPopup('

Forbidden

To view your API keys here, set the value of allowKeysExposure to true in config.conf file and restart the SillyTavern server.

', 'text'); + callPopup('

Forbidden

To view your API keys here, set the value of allowKeysExposure to true in config.yaml file and restart the SillyTavern server.

', 'text'); return; } diff --git a/server.js b/server.js index 2106b914..40c9fec9 100644 --- a/server.js +++ b/server.js @@ -55,7 +55,7 @@ const characterCardParser = require('./src/character-card-parser.js'); const contentManager = require('./src/content-manager'); const statsHelpers = require('./statsHelpers.js'); const { readSecret, migrateSecrets, SECRET_KEYS } = require('./src/secrets'); -const { delay, getVersion, deepMerge } = require('./src/util'); +const { delay, getVersion, deepMerge, getConfigValue, color } = require('./src/util'); const { invalidateThumbnail, ensureThumbnailCache } = require('./src/thumbnails'); const { getTokenizerModel, getTiktokenTokenizer, loadTokenizers, TEXT_COMPLETION_MODELS, getSentencepiceTokenizer, sentencepieceTokenizers } = require('./src/tokenizers'); const { convertClaudePrompt } = require('./src/chat-completion'); @@ -109,12 +109,10 @@ app.use(responseTime()); // impoort from statsHelpers.js -const config = require(path.join(process.cwd(), './config.conf')); - -const server_port = process.env.SILLY_TAVERN_PORT || config.port; +const server_port = process.env.SILLY_TAVERN_PORT || getConfigValue('port'); const whitelistPath = path.join(process.cwd(), "./whitelist.txt"); -let whitelist = config.whitelist; +let whitelist = getConfigValue('whitelist', []); if (fs.existsSync(whitelistPath)) { try { @@ -123,10 +121,10 @@ if (fs.existsSync(whitelistPath)) { } catch (e) { } } -const whitelistMode = config.whitelistMode; -const autorun = config.autorun && cliArguments.autorun !== false && !cliArguments.ssl; -const enableExtensions = config.enableExtensions; -const listen = config.listen; +const whitelistMode = getConfigValue('whitelistMode', true); +const autorun = getConfigValue('autorun') && cliArguments.autorun !== false && !cliArguments.ssl; +const enableExtensions = getConfigValue('enableExtensions', true); +const listen = getConfigValue('listen', false); const API_OPENAI = "https://api.openai.com/v1"; const API_CLAUDE = "https://api.anthropic.com/v1"; @@ -138,22 +136,6 @@ let main_api = "kobold"; let characters = {}; let response_dw_bg; -let color = { - byNum: (mess, fgNum) => { - mess = mess || ''; - fgNum = fgNum === undefined ? 31 : fgNum; - return '\u001b[' + fgNum + 'm' + mess + '\u001b[39m'; - }, - black: (mess) => color.byNum(mess, 30), - red: (mess) => color.byNum(mess, 31), - green: (mess) => color.byNum(mess, 32), - yellow: (mess) => color.byNum(mess, 33), - blue: (mess) => color.byNum(mess, 34), - magenta: (mess) => color.byNum(mess, 35), - cyan: (mess) => color.byNum(mess, 36), - white: (mess) => color.byNum(mess, 37) -}; - function getMancerHeaders() { const apiKey = readSecret(SECRET_KEYS.MANCER); @@ -182,7 +164,8 @@ function getTabbyHeaders() { } function getOverrideHeaders(urlHost) { - const overrideHeaders = config.requestOverrides?.find((e) => e.hosts?.includes(urlHost))?.headers; + const requestOverrides = getConfigValue('requestOverrides', []); + const overrideHeaders = requestOverrides?.find((e) => e.hosts?.includes(urlHost))?.headers; if (overrideHeaders && urlHost) { return overrideHeaders; } else { @@ -277,7 +260,7 @@ const CORS = cors({ app.use(CORS); -if (listen && config.basicAuthMode) app.use(basicAuthMiddleware); +if (listen && getConfigValue('basicAuthMode', false)) app.use(basicAuthMiddleware); // IP Whitelist // let knownIPs = new Set(); @@ -316,13 +299,13 @@ app.use(function (req, res, next) { //clientIp = req.connection.remoteAddress.split(':').pop(); if (whitelistMode === true && !whitelist.some(x => ipMatching.matches(clientIp, ipMatching.getMatch(x)))) { - console.log(color.red('Forbidden: Connection attempt from ' + clientIp + '. If you are attempting to connect, please add your IP address in whitelist or disable whitelist mode in config.conf in root of SillyTavern folder.\n')); - return res.status(403).send('Forbidden: Connection attempt from ' + clientIp + '. If you are attempting to connect, please add your IP address in whitelist or disable whitelist mode in config.conf in root of SillyTavern folder.'); + console.log(color.red('Forbidden: Connection attempt from ' + clientIp + '. If you are attempting to connect, please add your IP address in whitelist or disable whitelist mode in config.yaml in root of SillyTavern folder.\n')); + return res.status(403).send('Forbidden: Connection attempt from ' + clientIp + '. If you are attempting to connect, please add your IP address in whitelist or disable whitelist mode in config.yaml in root of SillyTavern folder.'); } next(); }); -if (config.enableCorsProxy === true || cliArguments.corsProxy === true) { +if (getConfigValue('enableCorsProxy', false) === true || cliArguments.corsProxy === true) { console.log('Enabling CORS proxy'); app.use('/proxy/:url', async (req, res) => { @@ -3670,12 +3653,12 @@ const setupTasks = async function () { console.log(color.green('SillyTavern is listening on: ' + tavernUrl)); if (listen) { - console.log('\n0.0.0.0 means SillyTavern is listening on all network interfaces (Wi-Fi, LAN, localhost). If you want to limit it only to internal localhost (127.0.0.1), change the setting in config.conf to "listen=false". Check "access.log" file in the SillyTavern directory if you want to inspect incoming connections.\n'); + console.log('\n0.0.0.0 means SillyTavern is listening on all network interfaces (Wi-Fi, LAN, localhost). If you want to limit it only to internal localhost (127.0.0.1), change the setting in config.yaml to "listen: false". Check "access.log" file in the SillyTavern directory if you want to inspect incoming connections.\n'); } } -if (listen && !config.whitelistMode && !config.basicAuthMode) { - if (config.securityOverride) { +if (listen && !getConfigValue('whitelistMode', true) && !getConfigValue('basicAuthMode', false)) { + if (getConfigValue('securityOverride', false)) { console.warn(color.red("Security has been overridden. If it's not a trusted network, change the settings.")); } else { @@ -3722,7 +3705,7 @@ function generateTimestamp() { */ function backupChat(name, chat) { try { - const isBackupDisabled = config.disableChatBackup; + const isBackupDisabled = getConfigValue('disableChatBackup', false); if (isBackupDisabled) { return; diff --git a/src/content-manager.js b/src/content-manager.js index 15e4dd5d..9dfb70dc 100644 --- a/src/content-manager.js +++ b/src/content-manager.js @@ -2,14 +2,14 @@ const fs = require('fs'); const path = require('path'); const fetch = require('node-fetch').default; const sanitize = require('sanitize-filename'); -const config = require(path.join(process.cwd(), './config.conf')); +const { getConfigValue } = require('./util'); 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) { + if (getConfigValue('skipContentCheck', false)) { return; } diff --git a/src/secrets.js b/src/secrets.js index 5c577b1e..cc705627 100644 --- a/src/secrets.js +++ b/src/secrets.js @@ -173,7 +173,7 @@ function registerEndpoints(app, jsonParser) { const allowKeysExposure = getConfigValue('allowKeysExposure', false); if (!allowKeysExposure) { - console.error('secrets.json could not be viewed unless the value of allowKeysExposure in config.conf is set to true'); + console.error('secrets.json could not be viewed unless the value of allowKeysExposure in config.yaml is set to true'); return response.sendStatus(403); } @@ -195,7 +195,7 @@ function registerEndpoints(app, jsonParser) { const allowKeysExposure = getConfigValue('allowKeysExposure', false); if (!allowKeysExposure) { - console.error('Cannot fetch secrets unless allowKeysExposure in config.conf is set to true'); + console.error('Cannot fetch secrets unless allowKeysExposure in config.yaml is set to true'); return response.sendStatus(403); } diff --git a/src/transformers.mjs b/src/transformers.mjs index 03d4a25c..db3649fb 100644 --- a/src/transformers.mjs +++ b/src/transformers.mjs @@ -65,7 +65,7 @@ function getModelForTask(task) { const model = getConfigValue(tasks[task].configField, null); return model || defaultModel; } catch (error) { - console.warn('Failed to read config.conf, using default classification model.'); + console.warn('Failed to read config.yaml, using default classification model.'); return defaultModel; } } diff --git a/src/util.js b/src/util.js index 78a7f26f..0dc7473c 100644 --- a/src/util.js +++ b/src/util.js @@ -4,20 +4,46 @@ const commandExistsSync = require('command-exists').sync; const _ = require('lodash'); const yauzl = require('yauzl'); const mime = require('mime-types'); +const yaml = require('yaml'); const { default: simpleGit } = require('simple-git'); /** - * Returns the config object from the config.conf file. + * Returns the config object from the config.yaml file. * @returns {object} Config object */ function getConfig() { - try { - const config = require(path.join(process.cwd(), './config.conf')); - return config; - } catch (error) { - console.warn('Failed to read config.conf'); - return {}; + function getNewConfig() { + try { + const config = yaml.parse(fs.readFileSync(path.join(process.cwd(), './config.yaml'), 'utf8')); + return config; + } catch (error) { + console.warn('Failed to read config.yaml'); + return {}; + } } + + function getLegacyConfig() { + try { + console.log(color.yellow('WARNING: config.conf is deprecated. Please run "npm run postinstall" to convert to config.yaml')); + const config = require(path.join(process.cwd(), './config.conf')); + return config; + } catch (error) { + console.warn('Failed to read config.conf'); + return {}; + } + } + + if (fs.existsSync('./config.yaml')) { + return getNewConfig(); + } + + if (fs.existsSync('./config.conf')) { + return getLegacyConfig(); + } + + console.error(color.red('No config file found. Please create a config.yaml file. The default config file can be found in the /default folder.')); + console.error(color.red('The program will now exit.')); + process.exit(1); } /** @@ -217,6 +243,22 @@ function deepMerge(target, source) { return output; } +const color = { + byNum: (mess, fgNum) => { + mess = mess || ''; + fgNum = fgNum === undefined ? 31 : fgNum; + return '\u001b[' + fgNum + 'm' + mess + '\u001b[39m'; + }, + black: (mess) => color.byNum(mess, 30), + red: (mess) => color.byNum(mess, 31), + green: (mess) => color.byNum(mess, 32), + yellow: (mess) => color.byNum(mess, 33), + blue: (mess) => color.byNum(mess, 34), + magenta: (mess) => color.byNum(mess, 35), + cyan: (mess) => color.byNum(mess, 36), + white: (mess) => color.byNum(mess, 37) +}; + module.exports = { getConfig, getConfigValue, @@ -227,4 +269,5 @@ module.exports = { readAllChunks, delay, deepMerge, + color, };