Merge branch 'songquanpeng:main' into main
This commit is contained in:
commit
e0b12c5f87
13
README.md
13
README.md
@ -152,12 +152,11 @@ sudo service nginx restart
|
|||||||
### 多机部署
|
### 多机部署
|
||||||
1. 所有服务器 `SESSION_SECRET` 设置一样的值。
|
1. 所有服务器 `SESSION_SECRET` 设置一样的值。
|
||||||
2. 必须设置 `SQL_DSN`,使用 MySQL 数据库而非 SQLite,所有服务器连接同一个数据库。
|
2. 必须设置 `SQL_DSN`,使用 MySQL 数据库而非 SQLite,所有服务器连接同一个数据库。
|
||||||
3. 所有从服务器必须设置 `SYNC_FREQUENCY`,以定期从数据库同步配置。
|
3. 所有从服务器必须设置 `NODE_TYPE` 为 `slave`。
|
||||||
4. 从服务器可以选择设置 `FRONTEND_BASE_URL`,以重定向页面请求到主服务器。
|
4. 设置 `SYNC_FREQUENCY` 后服务器将定期从数据库同步配置。
|
||||||
5. 从服务器上**分别**装好 Redis,设置好 `REDIS_CONN_STRING`,这样可以做到在缓存未过期的情况下数据库零访问,可以减少延迟。
|
5. 从服务器可以选择设置 `FRONTEND_BASE_URL`,以重定向页面请求到主服务器。
|
||||||
6. 如果主服务器访问数据库延迟也比较高,则也需要启用 Redis,并设置 `SYNC_FREQUENCY`,以定期从数据库同步配置。
|
6. 从服务器上**分别**装好 Redis,设置好 `REDIS_CONN_STRING`,这样可以做到在缓存未过期的情况下数据库零访问,可以减少延迟。
|
||||||
|
7. 如果主服务器访问数据库延迟也比较高,则也需要启用 Redis,并设置 `SYNC_FREQUENCY`,以定期从数据库同步配置。
|
||||||
注意,设置 `SYNC_FREQUENCY` 后会导致从服务器的状态不会实时更新,而是定期同步。
|
|
||||||
|
|
||||||
环境变量的具体使用方法详见[此处](#环境变量)。
|
环境变量的具体使用方法详见[此处](#环境变量)。
|
||||||
|
|
||||||
@ -249,6 +248,8 @@ graph LR
|
|||||||
+ 例子:`FRONTEND_BASE_URL=https://openai.justsong.cn`
|
+ 例子:`FRONTEND_BASE_URL=https://openai.justsong.cn`
|
||||||
5. `SYNC_FREQUENCY`:设置之后将定期与数据库同步配置,单位为秒,未设置则不进行同步。
|
5. `SYNC_FREQUENCY`:设置之后将定期与数据库同步配置,单位为秒,未设置则不进行同步。
|
||||||
+ 例子:`SYNC_FREQUENCY=60`
|
+ 例子:`SYNC_FREQUENCY=60`
|
||||||
|
6. `NODE_TYPE`:设置之后将指定节点类型,可选值为 `master` 和 `slave`,未设置则默认为 `master`。
|
||||||
|
+ 例子:`NODE_TYPE=slave`
|
||||||
|
|
||||||
### 命令行参数
|
### 命令行参数
|
||||||
1. `--port <port_number>`: 指定服务器监听的端口号,默认为 `3000`。
|
1. `--port <port_number>`: 指定服务器监听的端口号,默认为 `3000`。
|
||||||
|
@ -68,7 +68,7 @@ var PreConsumedQuota = 500
|
|||||||
|
|
||||||
var RootUserEmail = ""
|
var RootUserEmail = ""
|
||||||
|
|
||||||
var IsMasterNode = os.Getenv("SYNC_FREQUENCY") == ""
|
var IsMasterNode = os.Getenv("NODE_TYPE") != "slave"
|
||||||
|
|
||||||
const (
|
const (
|
||||||
RoleGuestUser = 0
|
RoleGuestUser = 0
|
||||||
|
@ -17,9 +17,9 @@ func InitRedisClient() (err error) {
|
|||||||
SysLog("REDIS_CONN_STRING not set, Redis is not enabled")
|
SysLog("REDIS_CONN_STRING not set, Redis is not enabled")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if IsMasterNode {
|
if os.Getenv("SYNC_FREQUENCY") == "" {
|
||||||
SysLog("Redis is disabled on master node")
|
|
||||||
RedisEnabled = false
|
RedisEnabled = false
|
||||||
|
SysLog("SYNC_FREQUENCY not set, Redis is disabled")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
SysLog("Redis is enabled")
|
SysLog("Redis is enabled")
|
||||||
|
@ -16,8 +16,10 @@ services:
|
|||||||
- REDIS_CONN_STRING=redis://redis
|
- REDIS_CONN_STRING=redis://redis
|
||||||
- SESSION_SECRET=random_string # 修改为随机字符串
|
- SESSION_SECRET=random_string # 修改为随机字符串
|
||||||
- TZ=Asia/Shanghai
|
- TZ=Asia/Shanghai
|
||||||
# - SYNC_FREQUENCY=60 # 多机部署时从节点取消注释该行
|
# - NODE_TYPE=slave # 多机部署时从节点取消注释该行
|
||||||
|
# - SYNC_FREQUENCY=60 # 需要定期从数据库加载数据时取消注释该行
|
||||||
# - FRONTEND_BASE_URL=https://openai.justsong.cn # 多机部署时从节点取消注释该行
|
# - FRONTEND_BASE_URL=https://openai.justsong.cn # 多机部署时从节点取消注释该行
|
||||||
|
|
||||||
depends_on:
|
depends_on:
|
||||||
- redis
|
- redis
|
||||||
healthcheck:
|
healthcheck:
|
||||||
|
@ -36,15 +36,15 @@ const EditChannel = () => {
|
|||||||
let res = await API.get(`/api/channel/${channelId}`);
|
let res = await API.get(`/api/channel/${channelId}`);
|
||||||
const { success, message, data } = res.data;
|
const { success, message, data } = res.data;
|
||||||
if (success) {
|
if (success) {
|
||||||
if (data.models === "") {
|
if (data.models === '') {
|
||||||
data.models = []
|
data.models = [];
|
||||||
} else {
|
} else {
|
||||||
data.models = data.models.split(",")
|
data.models = data.models.split(',');
|
||||||
}
|
}
|
||||||
if (data.group === "") {
|
if (data.group === '') {
|
||||||
data.groups = []
|
data.groups = [];
|
||||||
} else {
|
} else {
|
||||||
data.groups = data.group.split(",")
|
data.groups = data.group.split(',');
|
||||||
}
|
}
|
||||||
setInputs(data);
|
setInputs(data);
|
||||||
} else {
|
} else {
|
||||||
@ -59,10 +59,10 @@ const EditChannel = () => {
|
|||||||
setModelOptions(res.data.data.map((model) => ({
|
setModelOptions(res.data.data.map((model) => ({
|
||||||
key: model.id,
|
key: model.id,
|
||||||
text: model.id,
|
text: model.id,
|
||||||
value: model.id,
|
value: model.id
|
||||||
})));
|
})));
|
||||||
setFullModels(res.data.data.map((model) => model.id));
|
setFullModels(res.data.data.map((model) => model.id));
|
||||||
setBasicModels(res.data.data.filter((model) => !model.id.startsWith("gpt-4")).map((model) => model.id));
|
setBasicModels(res.data.data.filter((model) => !model.id.startsWith('gpt-4')).map((model) => model.id));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
showError(error.message);
|
showError(error.message);
|
||||||
}
|
}
|
||||||
@ -74,7 +74,7 @@ const EditChannel = () => {
|
|||||||
setGroupOptions(res.data.data.map((group) => ({
|
setGroupOptions(res.data.data.map((group) => ({
|
||||||
key: group,
|
key: group,
|
||||||
text: group,
|
text: group,
|
||||||
value: group,
|
value: group
|
||||||
})));
|
})));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
showError(error.message);
|
showError(error.message);
|
||||||
@ -94,6 +94,10 @@ const EditChannel = () => {
|
|||||||
showInfo('请填写渠道名称和渠道密钥!');
|
showInfo('请填写渠道名称和渠道密钥!');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (inputs.models.length === 0) {
|
||||||
|
showInfo('请至少选择一个模型!');
|
||||||
|
return;
|
||||||
|
}
|
||||||
let localInputs = inputs;
|
let localInputs = inputs;
|
||||||
if (localInputs.base_url.endsWith('/')) {
|
if (localInputs.base_url.endsWith('/')) {
|
||||||
localInputs.base_url = localInputs.base_url.slice(0, localInputs.base_url.length - 1);
|
localInputs.base_url = localInputs.base_url.slice(0, localInputs.base_url.length - 1);
|
||||||
@ -102,8 +106,8 @@ const EditChannel = () => {
|
|||||||
localInputs.other = '2023-03-15-preview';
|
localInputs.other = '2023-03-15-preview';
|
||||||
}
|
}
|
||||||
let res;
|
let res;
|
||||||
localInputs.models = localInputs.models.join(",")
|
localInputs.models = localInputs.models.join(',');
|
||||||
localInputs.group = localInputs.groups.join(",")
|
localInputs.group = localInputs.groups.join(',');
|
||||||
if (isEdit) {
|
if (isEdit) {
|
||||||
res = await API.put(`/api/channel/`, { ...localInputs, id: parseInt(channelId) });
|
res = await API.put(`/api/channel/`, { ...localInputs, id: parseInt(channelId) });
|
||||||
} else {
|
} else {
|
||||||
@ -190,9 +194,9 @@ const EditChannel = () => {
|
|||||||
inputs.type !== 3 && inputs.type !== 8 && (
|
inputs.type !== 3 && inputs.type !== 8 && (
|
||||||
<Form.Field>
|
<Form.Field>
|
||||||
<Form.Input
|
<Form.Input
|
||||||
label='Base URL'
|
label='镜像'
|
||||||
name='base_url'
|
name='base_url'
|
||||||
placeholder={'请输入自定义 Base URL,格式为:https://domain.com,可不填,不填使用渠道默认值'}
|
placeholder={'请输入镜像站地址,格式为:https://domain.com,可不填,不填则使用渠道默认值'}
|
||||||
onChange={handleInputChange}
|
onChange={handleInputChange}
|
||||||
value={inputs.base_url}
|
value={inputs.base_url}
|
||||||
autoComplete='new-password'
|
autoComplete='new-password'
|
||||||
@ -257,21 +261,10 @@ const EditChannel = () => {
|
|||||||
<Button type={'button'} onClick={() => {
|
<Button type={'button'} onClick={() => {
|
||||||
handleInputChange(null, { name: 'models', value: fullModels });
|
handleInputChange(null, { name: 'models', value: fullModels });
|
||||||
}}>填入所有模型</Button>
|
}}>填入所有模型</Button>
|
||||||
|
<Button type={'button'} onClick={() => {
|
||||||
|
handleInputChange(null, { name: 'models', value: [] });
|
||||||
|
}}>清除所有模型</Button>
|
||||||
</div>
|
</div>
|
||||||
{
|
|
||||||
inputs.type === 1 && (
|
|
||||||
<Form.Field>
|
|
||||||
<Form.Input
|
|
||||||
label='代理'
|
|
||||||
name='base_url'
|
|
||||||
placeholder={'请输入 OpenAI API 代理地址,如果不需要请留空,格式为:https://api.openai.com'}
|
|
||||||
onChange={handleInputChange}
|
|
||||||
value={inputs.base_url}
|
|
||||||
autoComplete='new-password'
|
|
||||||
/>
|
|
||||||
</Form.Field>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
{
|
{
|
||||||
batch ? <Form.Field>
|
batch ? <Form.Field>
|
||||||
<Form.TextArea
|
<Form.TextArea
|
||||||
|
Loading…
Reference in New Issue
Block a user