From 94582265c1b91d582305030439e2f3c8de33fcfe Mon Sep 17 00:00:00 2001
From: Chenyme <118253778+chenyme@users.noreply.github.com>
Date: Mon, 2 Feb 2026 21:16:50 +0800
Subject: [PATCH] feat: optimize initialization services and configurations
---
.gitignore | 1 +
Dockerfile | 1 +
app/core/config.py | 82 +++++++++++++++---
config.defaults.toml | 37 +++++++++
docker-compose.yml | 13 ++-
README.en.md => docs/README.en.md | 11 +++
env.example | 19 -----
readme.md | 133 +++++++++++++++++-------------
scripts/init_storage.sh | 41 +--------
9 files changed, 208 insertions(+), 130 deletions(-)
create mode 100644 config.defaults.toml
rename README.en.md => docs/README.en.md (92%)
delete mode 100644 env.example
diff --git a/.gitignore b/.gitignore
index 874c029..c711d97 100644
--- a/.gitignore
+++ b/.gitignore
@@ -47,6 +47,7 @@ logs/
# Data
data/*.json
data/tmp/
+data/.locks/
# Testing
.pytest_cache/
diff --git a/Dockerfile b/Dockerfile
index da179a2..ba133ed 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -20,6 +20,7 @@ COPY pyproject.toml uv.lock /app/
RUN uv sync --frozen --no-dev --no-install-project --active
+COPY config.defaults.toml /app/config.defaults.toml
COPY app /app/app
COPY main.py /app/main.py
COPY scripts /app/scripts
diff --git a/app/core/config.py b/app/core/config.py
index d248c69..401d512 100644
--- a/app/core/config.py
+++ b/app/core/config.py
@@ -2,10 +2,46 @@
配置管理
- config.toml: 运行时配置
+- config.defaults.toml: 默认配置基线
"""
-from typing import Any
-from app.core.storage import get_storage
+from copy import deepcopy
+from pathlib import Path
+from typing import Any, Dict
+import tomllib
+
+from app.core.logger import logger
+
+DEFAULT_CONFIG_FILE = Path(__file__).parent.parent.parent / "config.defaults.toml"
+
+
+def _deep_merge(base: Dict[str, Any], override: Dict[str, Any]) -> Dict[str, Any]:
+ """深度合并字典: override 覆盖 base."""
+ if not isinstance(base, dict):
+ return deepcopy(override) if isinstance(override, dict) else deepcopy(base)
+
+ result = deepcopy(base)
+ if not isinstance(override, dict):
+ return result
+
+ for key, val in override.items():
+ if isinstance(val, dict) and isinstance(result.get(key), dict):
+ result[key] = _deep_merge(result[key], val)
+ else:
+ result[key] = val
+ return result
+
+
+def _load_defaults() -> Dict[str, Any]:
+ """加载默认配置文件"""
+ if not DEFAULT_CONFIG_FILE.exists():
+ return {}
+ try:
+ with DEFAULT_CONFIG_FILE.open("rb") as f:
+ return tomllib.load(f)
+ except Exception as e:
+ logger.warning(f"Failed to load defaults from {DEFAULT_CONFIG_FILE}: {e}")
+ return {}
class Config:
@@ -16,32 +52,53 @@ class Config:
def __init__(self):
self._config = {}
+ self._defaults = {}
+ self._defaults_loaded = False
+
+ def _ensure_defaults(self):
+ if self._defaults_loaded:
+ return
+ self._defaults = _load_defaults()
+ self._defaults_loaded = True
async def load(self):
"""显式加载配置"""
try:
from app.core.storage import get_storage, LocalStorage
- import asyncio
+ self._ensure_defaults()
+
storage = get_storage()
config_data = await storage.load_config()
+ from_remote = True
# 从本地 data/config.toml 初始化后端
if config_data is None:
local_storage = LocalStorage()
+ from_remote = False
try:
# 尝试读取本地配置
config_data = await local_storage.load_config()
- # 初始化后端
- await storage.save_config(config_data)
- logger.info(f"Initialized remote storage ({storage.__class__.__name__}) with local config.")
except Exception as e:
logger.info(f"Failed to auto-init config from local: {e}")
config_data = {}
-
- self._config = config_data or {}
+
+ config_data = config_data or {}
+ merged = _deep_merge(self._defaults, config_data)
+
+ # 自动回填缺失配置到存储
+ should_persist = (not from_remote) or (merged != config_data)
+ if should_persist:
+ async with storage.acquire_lock("config_save", timeout=10):
+ await storage.save_config(merged)
+ if not from_remote:
+ logger.info(
+ f"Initialized remote storage ({storage.__class__.__name__}) with config baseline."
+ )
+
+ self._config = merged
except Exception as e:
- print(f"Error loading config: {e}")
+ logger.error(f"Error loading config: {e}")
self._config = {}
def get(self, key: str, default: Any = None) -> Any:
@@ -66,8 +123,11 @@ class Config:
from app.core.storage import get_storage
storage = get_storage()
async with storage.acquire_lock("config_save", timeout=10):
- await storage.save_config(new_config)
- await self.load()
+ self._ensure_defaults()
+ base = _deep_merge(self._defaults, self._config or {})
+ merged = _deep_merge(base, new_config or {})
+ await storage.save_config(merged)
+ self._config = merged
# 全局配置实例
diff --git a/config.defaults.toml b/config.defaults.toml
new file mode 100644
index 0000000..58cb2cf
--- /dev/null
+++ b/config.defaults.toml
@@ -0,0 +1,37 @@
+[grok]
+temporary = true
+stream = true
+thinking = true
+dynamic_statsig = true
+filter_tags = ["xaiartifact","xai:tool_usage_card","grok:render"]
+timeout = 120
+base_proxy_url = ""
+asset_proxy_url = ""
+cf_clearance = ""
+max_retry = 3
+retry_status_codes = [401,429,403]
+
+[app]
+app_url = "http://127.0.0.1:8000"
+app_key = "grok2api"
+api_key = ""
+image_format = "url"
+video_format = "url"
+
+[token]
+auto_refresh = true
+refresh_interval_hours = 8
+fail_threshold = 5
+save_delay_ms = 500
+reload_interval_sec = 30
+
+[cache]
+enable_auto_clean = true
+limit_mb = 1024
+
+[performance]
+assets_max_concurrent = 25
+media_max_concurrent = 50
+usage_max_concurrent = 25
+assets_delete_batch_size = 10
+admin_assets_batch_size = 10
diff --git a/docker-compose.yml b/docker-compose.yml
index 1e5edbb..0e3dac6 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -1,13 +1,22 @@
services:
grok2api:
- build: .
container_name: grok2api
+ image: ghcr.io/chenyme/grok2api:latest
ports:
- "8000:8000"
environment:
TZ: Asia/Shanghai
- SERVER_HOST: 0.0.0.0
+ LOG_LEVEL: INFO
SERVER_PORT: 8000
+ SERVER_WORKERS: 1
+ SERVER_STORAGE_TYPE: local
+ # SERVER_STORAGE_URL:
+
+ # SERVER_STORAGE_TYPE: (local, redis, mysql, pgsql) default: local
+ # SERVER_STORAGE_URL: (local mode is empty) default: empty
+ # Redis: redis://localhost:6379/0 or redis://:password@localhost:6379/0
+ # MySQL: mysql+aiomysql://user:pass@localhost/db
+ # PgSQL: postgresql+asyncpg://user:pass@localhost/db
volumes:
- ./data:/app/data
- ./logs:/app/logs
diff --git a/README.en.md b/docs/README.en.md
similarity index 92%
rename from README.en.md
rename to docs/README.en.md
index 4ad70d6..865adee 100644
--- a/README.en.md
+++ b/docs/README.en.md
@@ -31,6 +31,17 @@ git clone https://github.com/chenyme/grok2api
docker compose up -d
```
+### Environment variables
+
+| Variable | Description | Default | Example |
+| :--- | :--- | :--- | :--- |
+| `LOG_LEVEL` | Log level | `INFO` | `DEBUG` |
+| `SERVER_HOST` | Bind address | `0.0.0.0` | `0.0.0.0` |
+| `SERVER_PORT` | Service port | `8000` | `8000` |
+| `SERVER_WORKERS` | Uvicorn worker count | `1` | `2` |
+| `SERVER_STORAGE_TYPE` | Storage type (`local`/`redis`/`mysql`/`pgsql`) | `local` | `pgsql` |
+| `SERVER_STORAGE_URL` | Storage URL (empty for local) | `""` | `postgresql+asyncpg://user:password@host:5432/db` |
+
### Usage limits
- Basic account: 80 requests / 20h
diff --git a/env.example b/env.example
deleted file mode 100644
index 29f7e7f..0000000
--- a/env.example
+++ /dev/null
@@ -1,19 +0,0 @@
-# ============================================
-# 启动配置
-# ============================================
-SERVER_HOST=0.0.0.0
-SERVER_PORT=8000
-SERVER_WORKERS=1
-LOG_LEVEL=INFO
-
-# ============================================
-# 存储配置
-# ============================================
-# 存储类型: local, redis, mysql, pgsql
-SERVER_STORAGE_TYPE=local
-
-# 存储连接地址 (local 模式下留空)
-# Redis: redis://localhost:6379/0 or redis://:password@localhost:6379/0
-# MySQL: mysql+aiomysql://user:pass@localhost/db
-# PgSQL: postgresql+asyncpg://user:pass@localhost/db
-SERVER_STORAGE_URL=
\ No newline at end of file
diff --git a/readme.md b/readme.md
index 701655c..45728dd 100644
--- a/readme.md
+++ b/readme.md
@@ -31,6 +31,19 @@ git clone https://github.com/chenyme/grok2api
docker compose up -d
```
+### 环境变量
+
+> 配置 `.env` 文件
+
+| 变量名 | 说明 | 默认值 | 示例 |
+| :---------------------- | :-------------------------------------------------- | :---------- | :-------------------------------------------------- |
+| `LOG_LEVEL` | 日志级别 | `INFO` | `DEBUG` |
+| `SERVER_HOST` | 服务监听地址 | `0.0.0.0` | `0.0.0.0` |
+| `SERVER_PORT` | 服务端口 | `8000` | `8000` |
+| `SERVER_WORKERS` | Uvicorn worker 数量 | `1` | `2` |
+| `SERVER_STORAGE_TYPE` | 存储类型(`local`/`redis`/`mysql`/`pgsql`) | `local` | `pgsql` |
+| `SERVER_STORAGE_URL` | 存储连接串(local 时可为空) | `""` | `postgresql+asyncpg://user:password@host:5432/db` |
+
### 可用次数
- Basic 账号:80 次 / 20h
@@ -38,24 +51,25 @@ docker compose up -d
### 可用模型
-| 模型名 | 计次 | 可用账号 | 对话功能 | 图像功能 | 视频功能 |
-| :--- | :---: | :--- | :---: | :---: | :---: |
-| `grok-3` | 1 | Basic/Super | 支持 | 支持 | - |
-| `grok-3-fast` | 1 | Basic/Super | 支持 | 支持 | - |
-| `grok-4` | 1 | Basic/Super | 支持 | 支持 | - |
-| `grok-4-mini` | 1 | Basic/Super | 支持 | 支持 | - |
-| `grok-4-fast` | 1 | Basic/Super | 支持 | 支持 | - |
-| `grok-4-heavy` | 4 | Super | 支持 | 支持 | - |
-| `grok-4.1` | 1 | Basic/Super | 支持 | 支持 | - |
-| `grok-4.1-thinking` | 4 | Basic/Super | 支持 | 支持 | - |
-| `grok-imagine-1.0` | 4 | Basic/Super | - | 支持 | - |
-| `grok-imagine-1.0-video` | - | Basic/Super | - | - | 支持 |
+| 模型名 | 计次 | 可用账号 | 对话功能 | 图像功能 | 视频功能 |
+| :------------------------- | :--: | :---------- | :------: | :------: | :------: |
+| `grok-3` | 1 | Basic/Super | 支持 | 支持 | - |
+| `grok-3-fast` | 1 | Basic/Super | 支持 | 支持 | - |
+| `grok-4` | 1 | Basic/Super | 支持 | 支持 | - |
+| `grok-4-mini` | 1 | Basic/Super | 支持 | 支持 | - |
+| `grok-4-fast` | 1 | Basic/Super | 支持 | 支持 | - |
+| `grok-4-heavy` | 4 | Super | 支持 | 支持 | - |
+| `grok-4.1` | 1 | Basic/Super | 支持 | 支持 | - |
+| `grok-4.1-thinking` | 4 | Basic/Super | 支持 | 支持 | - |
+| `grok-imagine-1.0` | 4 | Basic/Super | - | 支持 | - |
+| `grok-imagine-1.0-video` | - | Basic/Super | - | - | 支持 |
## 接口说明
### `POST /v1/chat/completions`
+
> 通用接口,支持对话聊天、图像生成、图像编辑、视频生成、视频超分
```bash
@@ -73,17 +87,17 @@ curl http://localhost:8000/v1/chat/completions \
-| 字段 | 类型 | 说明 | 可用参数 |
-| :--- | :--- | :--- | :--- |
-| `model` | string | 模型名称 | - |
-| `messages` | array | 消息列表 | `developer`, `system`, `user`, `assistant` |
-| `stream` | boolean | 是否开启流式输出 | `true`, `false` |
-| `thinking` | string | 思维链模式 | `enabled`, `disabled`, `null` |
-| `video_config` | object | **视频模型专用配置对象** | - |
-| └─ `aspect_ratio` | string | 视频宽高比 | `16:9`, `9:16`, `1:1`, `2:3`, `3:2` |
-| └─ `video_length` | integer | 视频时长 (秒) | `5` - `15` |
-| └─ `resolution` | string | 分辨率 | `SD`, `HD` |
-| └─ `preset` | string | 风格预设 | `fun`, `normal`, `spicy` |
+| 字段 | 类型 | 说明 | 可用参数 |
+| :------------------- | :------ | :----------------------------- | :------------------------------------------------- |
+| `model` | string | 模型名称 | - |
+| `messages` | array | 消息列表 | `developer`, `system`, `user`, `assistant` |
+| `stream` | boolean | 是否开启流式输出 | `true`, `false` |
+| `thinking` | string | 思维链模式 | `enabled`, `disabled`, `null` |
+| `video_config` | object | **视频模型专用配置对象** | - |
+| └─`aspect_ratio` | string | 视频宽高比 | `16:9`, `9:16`, `1:1`, `2:3`, `3:2` |
+| └─`video_length` | integer | 视频时长 (秒) | `5` - `15` |
+| └─`resolution` | string | 分辨率 | `SD`, `HD` |
+| └─`preset` | string | 风格预设 | `fun`, `normal`, `spicy` |
注:除上述外的其他参数将自动丢弃并忽略
@@ -92,6 +106,7 @@ curl http://localhost:8000/v1/chat/completions \
### `POST /v1/images/generations`
+
> 图像接口,支持图像生成、图像编辑
```bash
@@ -110,12 +125,12 @@ curl http://localhost:8000/v1/images/generations \
-| 字段 | 类型 | 说明 | 可用参数 |
-| :--- | :--- | :--- | :--- |
-| `model` | string | 图像模型名 | `grok-imagine-1.0` |
-| `prompt` | string | 图像描述提示词 | - |
-| `n` | integer | 生成数量 | `1` - `10` (流式模式仅限 `1` 或 `2`) |
-| `stream` | boolean | 是否开启流式输出 | `true`, `false` |
+| 字段 | 类型 | 说明 | 可用参数 |
+| :--------- | :------ | :--------------- | :------------------------------------------- |
+| `model` | string | 图像模型名 | `grok-imagine-1.0` |
+| `prompt` | string | 图像描述提示词 | - |
+| `n` | integer | 生成数量 | `1` - `10` (流式模式仅限 `1` 或 `2`) |
+| `stream` | boolean | 是否开启流式输出 | `true`, `false` |
注:除上述外的其他参数将自动丢弃并忽略
@@ -129,36 +144,36 @@ curl http://localhost:8000/v1/images/generations \
配置文件:`data/config.toml`
-| 模块 | 字段 | 配置名 | 说明 | 默认值 |
-| :--- | :--- | :--- | :--- | :--- |
-| **app** | `app_url` | 应用地址 | 当前 Grok2API 服务的外部访问 URL,用于文件链接访问。 | `http://127.0.0.1:8000` |
-| | `app_key` | 后台密码 | 登录 Grok2API 服务管理后台的密码,请妥善保管。 | `grok2api` |
-| | `api_key` | API 密钥 | 调用 Grok2API 服务所需的 Bearer Token,请妥善保管。 | `""` |
-| | `image_format` | 图片格式 | 生成的图片格式(url 或 base64)。 | `url` |
-| | `video_format` | 视频格式 | 生成的视频格式(仅支持 url)。 | `url` |
-| **grok** | `temporary` | 临时对话 | 是否启用临时对话模式。 | `true` |
-| | `stream` | 流式响应 | 是否默认启用流式输出。 | `true` |
-| | `thinking` | 思维链 | 是否启用模型思维链输出。 | `true` |
-| | `dynamic_statsig` | 动态指纹 | 是否启用动态生成 Statsig 值。 | `true` |
-| | `filter_tags` | 过滤标签 | 自动过滤 Grok 响应中的特殊标签。 | `["xaiartifact", "xai:tool_usage_card", "grok:render"]` |
-| | `timeout` | 超时时间 | 请求 Grok 服务的超时时间(秒)。 | `120` |
-| | `base_proxy_url` | 基础代理 URL | 代理请求到 Grok 官网的基础服务地址。 | `""` |
-| | `asset_proxy_url` | 资源代理 URL | 代理请求到 Grok 官网的静态资源(图片/视频)地址。 | `""` |
-| | `cf_clearance` | CF Clearance | Cloudflare 验证 Cookie,用于验证 Cloudflare 的验证。 | `""` |
-| | `max_retry` | 最大重试 | 请求 Grok 服务失败时的最大重试次数。 | `3` |
-| | `retry_status_codes` | 重试状态码 | 触发重试的 HTTP 状态码列表。 | `[401, 429, 403]` |
-| **token** | `auto_refresh` | 自动刷新 | 是否开启 Token 自动刷新机制。 | `true` |
-| | `refresh_interval_hours` | 刷新间隔 | Token 刷新的时间间隔(小时)。 | `8` |
-| | `fail_threshold` | 失败阈值 | 单个 Token 连续失败多少次后被标记为不可用。 | `5` |
-| | `save_delay_ms` | 保存延迟 | Token 变更合并写入的延迟(毫秒)。 | `500` |
-| | `reload_interval_sec` | 一致性刷新 | 多 worker 场景下 Token 状态刷新间隔(秒)。 | `30` |
-| **cache** | `enable_auto_clean` | 自动清理 | 是否启用缓存自动清理,开启后按上限自动回收。 | `true` |
-| | `limit_mb` | 清理阈值 | 缓存大小阈值(MB),超过阈值会触发清理。 | `1024` |
-| **performance** | `assets_max_concurrent` | 资产并发上限 | 资源上传/下载/列表的并发上限。推荐 25。 | `25` |
-| | `media_max_concurrent` | 媒体并发上限 | 视频/媒体生成请求的并发上限。推荐 50。 | `50` |
-| | `usage_max_concurrent` | 用量并发上限 | 用量查询请求的并发上限。推荐 25。 | `25` |
-| | `assets_delete_batch_size` | 资产清理批量 | 在线资产删除单批并发数量。推荐 10。 | `10` |
-| | `admin_assets_batch_size` | 管理端批量 | 管理端在线资产统计/清理批量并发数量。推荐 10。 | `10` |
+| 模块 | 字段 | 配置名 | 说明 | 默认值 |
+| :-------------------- | :--------------------------- | :----------- | :--------------------------------------------------- | :-------------------------------------------------------- |
+| **app** | `app_url` | 应用地址 | 当前 Grok2API 服务的外部访问 URL,用于文件链接访问。 | `http://127.0.0.1:8000` |
+| | `app_key` | 后台密码 | 登录 Grok2API 服务管理后台的密码,请妥善保管。 | `grok2api` |
+| | `api_key` | API 密钥 | 调用 Grok2API 服务所需的 Bearer Token,请妥善保管。 | `""` |
+| | `image_format` | 图片格式 | 生成的图片格式(url 或 base64)。 | `url` |
+| | `video_format` | 视频格式 | 生成的视频格式(仅支持 url)。 | `url` |
+| **grok** | `temporary` | 临时对话 | 是否启用临时对话模式。 | `true` |
+| | `stream` | 流式响应 | 是否默认启用流式输出。 | `true` |
+| | `thinking` | 思维链 | 是否启用模型思维链输出。 | `true` |
+| | `dynamic_statsig` | 动态指纹 | 是否启用动态生成 Statsig 值。 | `true` |
+| | `filter_tags` | 过滤标签 | 自动过滤 Grok 响应中的特殊标签。 | `["xaiartifact", "xai:tool_usage_card", "grok:render"]` |
+| | `timeout` | 超时时间 | 请求 Grok 服务的超时时间(秒)。 | `120` |
+| | `base_proxy_url` | 基础代理 URL | 代理请求到 Grok 官网的基础服务地址。 | `""` |
+| | `asset_proxy_url` | 资源代理 URL | 代理请求到 Grok 官网的静态资源(图片/视频)地址。 | `""` |
+| | `cf_clearance` | CF Clearance | Cloudflare 验证 Cookie,用于验证 Cloudflare 的验证。 | `""` |
+| | `max_retry` | 最大重试 | 请求 Grok 服务失败时的最大重试次数。 | `3` |
+| | `retry_status_codes` | 重试状态码 | 触发重试的 HTTP 状态码列表。 | `[401, 429, 403]` |
+| **token** | `auto_refresh` | 自动刷新 | 是否开启 Token 自动刷新机制。 | `true` |
+| | `refresh_interval_hours` | 刷新间隔 | Token 刷新的时间间隔(小时)。 | `8` |
+| | `fail_threshold` | 失败阈值 | 单个 Token 连续失败多少次后被标记为不可用。 | `5` |
+| | `save_delay_ms` | 保存延迟 | Token 变更合并写入的延迟(毫秒)。 | `500` |
+| | `reload_interval_sec` | 一致性刷新 | 多 worker 场景下 Token 状态刷新间隔(秒)。 | `30` |
+| **cache** | `enable_auto_clean` | 自动清理 | 是否启用缓存自动清理,开启后按上限自动回收。 | `true` |
+| | `limit_mb` | 清理阈值 | 缓存大小阈值(MB),超过阈值会触发清理。 | `1024` |
+| **performance** | `assets_max_concurrent` | 资产并发上限 | 资源上传/下载/列表的并发上限。推荐 25。 | `25` |
+| | `media_max_concurrent` | 媒体并发上限 | 视频/媒体生成请求的并发上限。推荐 50。 | `50` |
+| | `usage_max_concurrent` | 用量并发上限 | 用量查询请求的并发上限。推荐 25。 | `25` |
+| | `assets_delete_batch_size` | 资产清理批量 | 在线资产删除单批并发数量。推荐 10。 | `10` |
+| | `admin_assets_batch_size` | 管理端批量 | 管理端在线资产统计/清理批量并发数量。推荐 10。 | `10` |
diff --git a/scripts/init_storage.sh b/scripts/init_storage.sh
index e6c0e9b..0c61ac2 100755
--- a/scripts/init_storage.sh
+++ b/scripts/init_storage.sh
@@ -5,49 +5,12 @@ ROOT_DIR="$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)"
DATA_DIR="$ROOT_DIR/data"
LOG_DIR="$ROOT_DIR/logs"
TMP_DIR="$DATA_DIR/tmp"
+DEFAULT_CONFIG="$ROOT_DIR/config.defaults.toml"
mkdir -p "$DATA_DIR" "$LOG_DIR" "$TMP_DIR"
if [ ! -f "$DATA_DIR/config.toml" ]; then
- cat > "$DATA_DIR/config.toml" <<'TOML'
-[grok]
-temporary = true
-stream = true
-thinking = true
-dynamic_statsig = true
-filter_tags = ["xaiartifact","xai:tool_usage_card","grok:render"]
-timeout = 120
-base_proxy_url = ""
-asset_proxy_url = ""
-cf_clearance = ""
-max_retry = 3
-retry_status_codes = [401,429,403]
-
-[app]
-app_url = "http://127.0.0.1:8000"
-app_key = "grok2api"
-api_key = ""
-image_format = "url"
-video_format = "url"
-
-[token]
-auto_refresh = true
-refresh_interval_hours = 8
-fail_threshold = 5
-save_delay_ms = 500
-reload_interval_sec = 30
-
-[cache]
-enable_auto_clean = true
-limit_mb = 1024
-
-[performance]
-assets_max_concurrent = 25 # 推荐 25
-media_max_concurrent = 50 # 推荐 50
-usage_max_concurrent = 25 # 推荐 25
-assets_delete_batch_size = 10 # 推荐 10
-admin_assets_batch_size = 10 # 推荐 10
-TOML
+ cp "$DEFAULT_CONFIG" "$DATA_DIR/config.toml"
fi
if [ ! -f "$DATA_DIR/token.json" ]; then