mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-02-26 08:58:09 +01:00
Merge branch 'config-yaml' into staging
This commit is contained in:
commit
809a55b2fd
10
.github/readme-zh_cn.md
vendored
10
.github/readme-zh_cn.md
vendored
@ -170,7 +170,7 @@ SillyTavern 会将 API 密钥保存在目录中的 `secrets.json` 文件内。
|
|||||||
|
|
||||||
如果要想通过点击 API 输入框旁边的按钮来查看密钥,请按照以下设置:
|
如果要想通过点击 API 输入框旁边的按钮来查看密钥,请按照以下设置:
|
||||||
|
|
||||||
1. 打开 `config.conf` 文件,将里面的 `allowKeysExposure` 设置为 `true`。
|
1. 打开 `config.yaml` 文件,将里面的 `allowKeysExposure` 设置为 `true`。
|
||||||
2. 然后重启 SillyTavern 服务。
|
2. 然后重启 SillyTavern 服务。
|
||||||
|
|
||||||
## 远程访问
|
## 远程访问
|
||||||
@ -207,7 +207,7 @@ SillyTavern 会将 API 密钥保存在目录中的 `secrets.json` 文件内。
|
|||||||
|
|
||||||
然后,文件中设置的 IP 就可以访问 SillyTavern 了。
|
然后,文件中设置的 IP 就可以访问 SillyTavern 了。
|
||||||
|
|
||||||
*注意:"config.conf" 文件内也有一个 "whitelist" 设置,你可以用同样的方法设置它,但如果 "whitelist.txt" 文件存在,这个设置将被忽略。
|
*注意:"config.yaml" 文件内也有一个 "whitelist" 设置,你可以用同样的方法设置它,但如果 "whitelist.txt" 文件存在,这个设置将被忽略。
|
||||||
|
|
||||||
### 2.获取 SillyTavern 服务的 IP 地址
|
### 2.获取 SillyTavern 服务的 IP 地址
|
||||||
|
|
||||||
@ -233,19 +233,19 @@ SillyTavern 会将 API 密钥保存在目录中的 `secrets.json` 文件内。
|
|||||||
|
|
||||||
### 向所有 IP 开放您的 SillyTavern 服务
|
### 向所有 IP 开放您的 SillyTavern 服务
|
||||||
|
|
||||||
我们不建议这样做,但您可以打开 `config.conf` 并将里面的 `whitelist` 设置改为 `false`。
|
我们不建议这样做,但您可以打开 `config.yaml` 并将里面的 `whitelist` 设置改为 `false`。
|
||||||
|
|
||||||
你必须删除(或重命名)SillyTavern 文件夹中的 `whitelist.txt` 文件(如果有的话)。
|
你必须删除(或重命名)SillyTavern 文件夹中的 `whitelist.txt` 文件(如果有的话)。
|
||||||
|
|
||||||
这通常是不安全的做法,所以我们要求在这样做时必须设置用户名和密码。
|
这通常是不安全的做法,所以我们要求在这样做时必须设置用户名和密码。
|
||||||
|
|
||||||
用户名和密码在`config.conf`文件中设置。
|
用户名和密码在`config.yaml`文件中设置。
|
||||||
|
|
||||||
重启 SillyTavern 服务后,只要知道用户名和密码,任何设备都可以访问。
|
重启 SillyTavern 服务后,只要知道用户名和密码,任何设备都可以访问。
|
||||||
|
|
||||||
### 还是无法访问?
|
### 还是无法访问?
|
||||||
|
|
||||||
* 为 `config.conf` 文件中的端口创建一条入站/出站防火墙规则。切勿将此误认为是路由器上的端口转发,否则,有人可能会发现你的聊天隐私,那就大错特错了。
|
* 为 `config.yaml` 文件中的端口创建一条入站/出站防火墙规则。切勿将此误认为是路由器上的端口转发,否则,有人可能会发现你的聊天隐私,那就大错特错了。
|
||||||
* 在 "设置" > "网络和 Internet" > "以太网" 中启用 "专用网络" 配置。这对 Windows 11 非常重要,否则即使添加了上述防火墙规则也无法连接。
|
* 在 "设置" > "网络和 Internet" > "以太网" 中启用 "专用网络" 配置。这对 Windows 11 非常重要,否则即使添加了上述防火墙规则也无法连接。
|
||||||
|
|
||||||
### 性能问题?
|
### 性能问题?
|
||||||
|
10
.github/readme.md
vendored
10
.github/readme.md
vendored
@ -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:
|
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.
|
2. Restart the SillyTavern server.
|
||||||
|
|
||||||
## Remote connections
|
## 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.
|
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
|
### 2. Getting the IP for the ST host machine
|
||||||
|
|
||||||
@ -237,19 +237,19 @@ Use http:// NOT https://
|
|||||||
|
|
||||||
### Opening your ST to all IPs
|
### 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.
|
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.
|
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.
|
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?
|
### 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.
|
* 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?
|
## Performance issues?
|
||||||
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -20,6 +20,8 @@ public/stats.json
|
|||||||
/uploads/
|
/uploads/
|
||||||
*.jsonl
|
*.jsonl
|
||||||
/config.conf
|
/config.conf
|
||||||
|
/config.yaml
|
||||||
|
/config.conf.bak
|
||||||
/docker/config
|
/docker/config
|
||||||
.DS_Store
|
.DS_Store
|
||||||
public/settings.json
|
public/settings.json
|
||||||
|
@ -31,7 +31,8 @@ RUN \
|
|||||||
echo "*** Create symbolic links to config directory ***" && \
|
echo "*** Create symbolic links to config directory ***" && \
|
||||||
for R in $RESOURCES; do ln -s "../config/$R" "public/$R"; done || true && \
|
for R in $RESOURCES; do ln -s "../config/$R" "public/$R"; done || true && \
|
||||||
\
|
\
|
||||||
ln -s "./config/config.conf" "config.conf" || true && \
|
rm -f "config.yaml" "public/settings.json" "public/css/bg_load.css" || true && \
|
||||||
|
ln -s "./config/config.yaml" "config.yaml" || true && \
|
||||||
ln -s "../config/settings.json" "public/settings.json" || true && \
|
ln -s "../config/settings.json" "public/settings.json" || true && \
|
||||||
ln -s "../../config/bg_load.css" "public/css/bg_load.css" || true && \
|
ln -s "../../config/bg_load.css" "public/css/bg_load.css" || true && \
|
||||||
mkdir "config" || true
|
mkdir "config" || true
|
||||||
|
@ -4,7 +4,7 @@ echo WARNING: Cloudflare Tunnel!
|
|||||||
echo ========================================================================================================================
|
echo ========================================================================================================================
|
||||||
echo This script downloads and runs the latest cloudflared.exe from Cloudflare to set up an HTTPS tunnel to your SillyTavern!
|
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 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.
|
||||||
echo See https://docs.sillytavern.app/usage/remoteconnections/ for more details about how to secure your SillyTavern install.
|
echo See https://docs.sillytavern.app/usage/remoteconnections/ for more details about how to secure your SillyTavern install.
|
||||||
echo.
|
echo.
|
||||||
|
@ -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: [ "<url>" ], headers: { <header>: "<value>" } }
|
|
||||||
const requestOverrides = [];
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
port,
|
|
||||||
whitelist,
|
|
||||||
whitelistMode,
|
|
||||||
basicAuthMode,
|
|
||||||
basicAuthUser,
|
|
||||||
autorun,
|
|
||||||
enableExtensions,
|
|
||||||
listen,
|
|
||||||
disableThumbnails,
|
|
||||||
allowKeysExposure,
|
|
||||||
securityOverride,
|
|
||||||
skipContentCheck,
|
|
||||||
requestOverrides,
|
|
||||||
thumbnailsQuality,
|
|
||||||
extras,
|
|
||||||
disableChatBackup,
|
|
||||||
};
|
|
53
default/config.yaml
Normal file
53
default/config.yaml
Normal file
@ -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
|
||||||
|
|
@ -9,9 +9,9 @@ for R in $RESOURCES; do
|
|||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
if [ ! -e "config/config.conf" ]; then
|
if [ ! -e "config/config.yaml" ]; then
|
||||||
echo "Resource not found, copying from defaults: config.conf"
|
echo "Resource not found, copying from defaults: config.yaml"
|
||||||
cp -r "default/config.conf" "config/config.conf"
|
cp -r "default/config.yaml" "config/config.yaml"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ ! -e "config/settings.json" ]; then
|
if [ ! -e "config/settings.json" ]; then
|
||||||
@ -24,15 +24,18 @@ if [ ! -e "config/bg_load.css" ]; then
|
|||||||
cp -r "default/bg_load.css" "config/bg_load.css"
|
cp -r "default/bg_load.css" "config/bg_load.css"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
CONFIG_FILE="config.conf"
|
CONFIG_FILE="config.yaml"
|
||||||
|
|
||||||
if grep -q "listen = false" $CONFIG_FILE; then
|
echo "Starting with the following config:"
|
||||||
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"
|
cat $CONFIG_FILE
|
||||||
|
|
||||||
|
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
|
sleep 5
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if grep -q "whitelistMode = true" $CONFIG_FILE; then
|
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"
|
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
|
sleep 5
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
9
package-lock.json
generated
9
package-lock.json
generated
@ -43,6 +43,7 @@
|
|||||||
"vectra": "^0.2.2",
|
"vectra": "^0.2.2",
|
||||||
"write-file-atomic": "^5.0.1",
|
"write-file-atomic": "^5.0.1",
|
||||||
"ws": "^8.13.0",
|
"ws": "^8.13.0",
|
||||||
|
"yaml": "^2.3.4",
|
||||||
"yargs": "^17.7.1",
|
"yargs": "^17.7.1",
|
||||||
"yauzl": "^2.10.0"
|
"yauzl": "^2.10.0"
|
||||||
},
|
},
|
||||||
@ -4388,6 +4389,14 @@
|
|||||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
||||||
"dev": true
|
"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": {
|
"node_modules/yargs": {
|
||||||
"version": "17.7.2",
|
"version": "17.7.2",
|
||||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
|
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
|
||||||
|
@ -33,6 +33,7 @@
|
|||||||
"vectra": "^0.2.2",
|
"vectra": "^0.2.2",
|
||||||
"write-file-atomic": "^5.0.1",
|
"write-file-atomic": "^5.0.1",
|
||||||
"ws": "^8.13.0",
|
"ws": "^8.13.0",
|
||||||
|
"yaml": "^2.3.4",
|
||||||
"yargs": "^17.7.1",
|
"yargs": "^17.7.1",
|
||||||
"yauzl": "^2.10.0"
|
"yauzl": "^2.10.0"
|
||||||
},
|
},
|
||||||
|
106
post-install.js
106
post-install.js
@ -4,6 +4,102 @@
|
|||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const crypto = require('crypto');
|
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.
|
* Creates the default config files if they don't exist yet.
|
||||||
@ -12,7 +108,7 @@ function createDefaultFiles() {
|
|||||||
const files = {
|
const files = {
|
||||||
settings: './public/settings.json',
|
settings: './public/settings.json',
|
||||||
bg_load: './public/css/bg_load.css',
|
bg_load: './public/css/bg_load.css',
|
||||||
config: './config.conf',
|
config: './config.yaml',
|
||||||
user: './public/css/user.css',
|
user: './public/css/user.css',
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -21,10 +117,10 @@ function createDefaultFiles() {
|
|||||||
if (!fs.existsSync(file)) {
|
if (!fs.existsSync(file)) {
|
||||||
const defaultFilePath = path.join('./default', path.parse(file).base);
|
const defaultFilePath = path.join('./default', path.parse(file).base);
|
||||||
fs.copyFileSync(defaultFilePath, file);
|
fs.copyFileSync(defaultFilePath, file);
|
||||||
console.log(`Created default file: ${file}`);
|
console.log(color.green(`Created default file: ${file}`));
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} 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 {
|
try {
|
||||||
|
// 0. Convert config.conf to config.yaml
|
||||||
|
convertConfig();
|
||||||
// 1. Create default config files
|
// 1. Create default config files
|
||||||
createDefaultFiles();
|
createDefaultFiles();
|
||||||
// 2. Copy transformers WASM binaries from node_modules
|
// 2. Copy transformers WASM binaries from node_modules
|
||||||
copyWasmFiles();
|
copyWasmFiles();
|
||||||
|
// 3. Add missing config values
|
||||||
|
addMissingConfigValues();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
}
|
}
|
||||||
|
@ -846,6 +846,10 @@ async function checkForExtensionUpdates(force) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function autoUpdateExtensions() {
|
async function autoUpdateExtensions() {
|
||||||
|
if (!Object.values(manifests).some(x => x.auto_update)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
toastr.info('Auto-updating extensions. This may take several minutes.', 'Please wait...', { timeOut: 10000, extendedTimeOut: 20000 });
|
toastr.info('Auto-updating extensions. This may take several minutes.', 'Please wait...', { timeOut: 10000, extendedTimeOut: 20000 });
|
||||||
const promises = [];
|
const promises = [];
|
||||||
for (const [id, manifest] of Object.entries(manifests)) {
|
for (const [id, manifest] of Object.entries(manifests)) {
|
||||||
|
@ -55,7 +55,7 @@ async function viewSecrets() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (response.status == 403) {
|
if (response.status == 403) {
|
||||||
callPopup('<h3>Forbidden</h3><p>To view your API keys here, set the value of allowKeysExposure to true in config.conf file and restart the SillyTavern server.</p>', 'text');
|
callPopup('<h3>Forbidden</h3><p>To view your API keys here, set the value of allowKeysExposure to true in config.yaml file and restart the SillyTavern server.</p>', 'text');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
51
server.js
51
server.js
@ -55,7 +55,7 @@ const characterCardParser = require('./src/character-card-parser.js');
|
|||||||
const contentManager = require('./src/content-manager');
|
const contentManager = require('./src/content-manager');
|
||||||
const statsHelpers = require('./statsHelpers.js');
|
const statsHelpers = require('./statsHelpers.js');
|
||||||
const { readSecret, migrateSecrets, SECRET_KEYS } = require('./src/secrets');
|
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 { invalidateThumbnail, ensureThumbnailCache } = require('./src/thumbnails');
|
||||||
const { getTokenizerModel, getTiktokenTokenizer, loadTokenizers, TEXT_COMPLETION_MODELS, getSentencepiceTokenizer, sentencepieceTokenizers } = require('./src/tokenizers');
|
const { getTokenizerModel, getTiktokenTokenizer, loadTokenizers, TEXT_COMPLETION_MODELS, getSentencepiceTokenizer, sentencepieceTokenizers } = require('./src/tokenizers');
|
||||||
const { convertClaudePrompt } = require('./src/chat-completion');
|
const { convertClaudePrompt } = require('./src/chat-completion');
|
||||||
@ -109,12 +109,10 @@ app.use(responseTime());
|
|||||||
|
|
||||||
// impoort from statsHelpers.js
|
// impoort from statsHelpers.js
|
||||||
|
|
||||||
const config = require(path.join(process.cwd(), './config.conf'));
|
const server_port = process.env.SILLY_TAVERN_PORT || getConfigValue('port');
|
||||||
|
|
||||||
const server_port = process.env.SILLY_TAVERN_PORT || config.port;
|
|
||||||
|
|
||||||
const whitelistPath = path.join(process.cwd(), "./whitelist.txt");
|
const whitelistPath = path.join(process.cwd(), "./whitelist.txt");
|
||||||
let whitelist = config.whitelist;
|
let whitelist = getConfigValue('whitelist', []);
|
||||||
|
|
||||||
if (fs.existsSync(whitelistPath)) {
|
if (fs.existsSync(whitelistPath)) {
|
||||||
try {
|
try {
|
||||||
@ -123,10 +121,10 @@ if (fs.existsSync(whitelistPath)) {
|
|||||||
} catch (e) { }
|
} catch (e) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
const whitelistMode = config.whitelistMode;
|
const whitelistMode = getConfigValue('whitelistMode', true);
|
||||||
const autorun = config.autorun && cliArguments.autorun !== false && !cliArguments.ssl;
|
const autorun = getConfigValue('autorun') && cliArguments.autorun !== false && !cliArguments.ssl;
|
||||||
const enableExtensions = config.enableExtensions;
|
const enableExtensions = getConfigValue('enableExtensions', true);
|
||||||
const listen = config.listen;
|
const listen = getConfigValue('listen', false);
|
||||||
|
|
||||||
const API_OPENAI = "https://api.openai.com/v1";
|
const API_OPENAI = "https://api.openai.com/v1";
|
||||||
const API_CLAUDE = "https://api.anthropic.com/v1";
|
const API_CLAUDE = "https://api.anthropic.com/v1";
|
||||||
@ -138,22 +136,6 @@ let main_api = "kobold";
|
|||||||
let characters = {};
|
let characters = {};
|
||||||
let response_dw_bg;
|
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() {
|
function getMancerHeaders() {
|
||||||
const apiKey = readSecret(SECRET_KEYS.MANCER);
|
const apiKey = readSecret(SECRET_KEYS.MANCER);
|
||||||
|
|
||||||
@ -182,7 +164,8 @@ function getTabbyHeaders() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getOverrideHeaders(urlHost) {
|
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) {
|
if (overrideHeaders && urlHost) {
|
||||||
return overrideHeaders;
|
return overrideHeaders;
|
||||||
} else {
|
} else {
|
||||||
@ -277,7 +260,7 @@ const CORS = cors({
|
|||||||
|
|
||||||
app.use(CORS);
|
app.use(CORS);
|
||||||
|
|
||||||
if (listen && config.basicAuthMode) app.use(basicAuthMiddleware);
|
if (listen && getConfigValue('basicAuthMode', false)) app.use(basicAuthMiddleware);
|
||||||
|
|
||||||
// IP Whitelist //
|
// IP Whitelist //
|
||||||
let knownIPs = new Set();
|
let knownIPs = new Set();
|
||||||
@ -316,13 +299,13 @@ app.use(function (req, res, next) {
|
|||||||
|
|
||||||
//clientIp = req.connection.remoteAddress.split(':').pop();
|
//clientIp = req.connection.remoteAddress.split(':').pop();
|
||||||
if (whitelistMode === true && !whitelist.some(x => ipMatching.matches(clientIp, ipMatching.getMatch(x)))) {
|
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'));
|
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('<b>Forbidden</b>: Connection attempt from <b>' + clientIp + '</b>. 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.');
|
return res.status(403).send('<b>Forbidden</b>: Connection attempt from <b>' + clientIp + '</b>. 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();
|
next();
|
||||||
});
|
});
|
||||||
|
|
||||||
if (config.enableCorsProxy === true || cliArguments.corsProxy === true) {
|
if (getConfigValue('enableCorsProxy', false) === true || cliArguments.corsProxy === true) {
|
||||||
console.log('Enabling CORS proxy');
|
console.log('Enabling CORS proxy');
|
||||||
|
|
||||||
app.use('/proxy/:url', async (req, res) => {
|
app.use('/proxy/:url', async (req, res) => {
|
||||||
@ -3670,12 +3653,12 @@ const setupTasks = async function () {
|
|||||||
console.log(color.green('SillyTavern is listening on: ' + tavernUrl));
|
console.log(color.green('SillyTavern is listening on: ' + tavernUrl));
|
||||||
|
|
||||||
if (listen) {
|
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 (listen && !getConfigValue('whitelistMode', true) && !getConfigValue('basicAuthMode', false)) {
|
||||||
if (config.securityOverride) {
|
if (getConfigValue('securityOverride', false)) {
|
||||||
console.warn(color.red("Security has been overridden. If it's not a trusted network, change the settings."));
|
console.warn(color.red("Security has been overridden. If it's not a trusted network, change the settings."));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -3722,7 +3705,7 @@ function generateTimestamp() {
|
|||||||
*/
|
*/
|
||||||
function backupChat(name, chat) {
|
function backupChat(name, chat) {
|
||||||
try {
|
try {
|
||||||
const isBackupDisabled = config.disableChatBackup;
|
const isBackupDisabled = getConfigValue('disableChatBackup', false);
|
||||||
|
|
||||||
if (isBackupDisabled) {
|
if (isBackupDisabled) {
|
||||||
return;
|
return;
|
||||||
|
@ -2,14 +2,14 @@ const fs = require('fs');
|
|||||||
const path = require('path');
|
const path = require('path');
|
||||||
const fetch = require('node-fetch').default;
|
const fetch = require('node-fetch').default;
|
||||||
const sanitize = require('sanitize-filename');
|
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 contentDirectory = path.join(process.cwd(), 'default/content');
|
||||||
const contentLogPath = path.join(contentDirectory, 'content.log');
|
const contentLogPath = path.join(contentDirectory, 'content.log');
|
||||||
const contentIndexPath = path.join(contentDirectory, 'index.json');
|
const contentIndexPath = path.join(contentDirectory, 'index.json');
|
||||||
|
|
||||||
function checkForNewContent() {
|
function checkForNewContent() {
|
||||||
try {
|
try {
|
||||||
if (config.skipContentCheck) {
|
if (getConfigValue('skipContentCheck', false)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -173,7 +173,7 @@ function registerEndpoints(app, jsonParser) {
|
|||||||
const allowKeysExposure = getConfigValue('allowKeysExposure', false);
|
const allowKeysExposure = getConfigValue('allowKeysExposure', false);
|
||||||
|
|
||||||
if (!allowKeysExposure) {
|
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);
|
return response.sendStatus(403);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -195,7 +195,7 @@ function registerEndpoints(app, jsonParser) {
|
|||||||
const allowKeysExposure = getConfigValue('allowKeysExposure', false);
|
const allowKeysExposure = getConfigValue('allowKeysExposure', false);
|
||||||
|
|
||||||
if (!allowKeysExposure) {
|
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);
|
return response.sendStatus(403);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,7 +65,7 @@ function getModelForTask(task) {
|
|||||||
const model = getConfigValue(tasks[task].configField, null);
|
const model = getConfigValue(tasks[task].configField, null);
|
||||||
return model || defaultModel;
|
return model || defaultModel;
|
||||||
} catch (error) {
|
} 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;
|
return defaultModel;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
45
src/util.js
45
src/util.js
@ -4,14 +4,27 @@ const commandExistsSync = require('command-exists').sync;
|
|||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
const yauzl = require('yauzl');
|
const yauzl = require('yauzl');
|
||||||
const mime = require('mime-types');
|
const mime = require('mime-types');
|
||||||
|
const yaml = require('yaml');
|
||||||
const { default: simpleGit } = require('simple-git');
|
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
|
* @returns {object} Config object
|
||||||
*/
|
*/
|
||||||
function getConfig() {
|
function getConfig() {
|
||||||
|
function getNewConfig() {
|
||||||
try {
|
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'));
|
const config = require(path.join(process.cwd(), './config.conf'));
|
||||||
return config;
|
return config;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -20,6 +33,19 @@ function getConfig() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the value for the given key from the config object.
|
* Returns the value for the given key from the config object.
|
||||||
* @param {string} key - Key to get from the config object
|
* @param {string} key - Key to get from the config object
|
||||||
@ -217,6 +243,22 @@ function deepMerge(target, source) {
|
|||||||
return output;
|
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 = {
|
module.exports = {
|
||||||
getConfig,
|
getConfig,
|
||||||
getConfigValue,
|
getConfigValue,
|
||||||
@ -227,4 +269,5 @@ module.exports = {
|
|||||||
readAllChunks,
|
readAllChunks,
|
||||||
delay,
|
delay,
|
||||||
deepMerge,
|
deepMerge,
|
||||||
|
color,
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user