From bcd94069a74b6264b2cb7f4744c611b14beb1c48 Mon Sep 17 00:00:00 2001
From: Chenyme <118253778+chenyme@users.noreply.github.com>
Date: Sat, 7 Feb 2026 13:30:50 +0800
Subject: [PATCH] feat: migrate configuration structure to improve organization
and flexibility
---
app/api/v1/image.py | 10 +-
app/core/config.py | 87 ++++++++++-
app/services/grok/defaults.py | 76 ++++++----
.../grok/processors/chat_processors.py | 10 +-
.../grok/processors/image_processors.py | 4 +-
.../grok/processors/video_processors.py | 6 +-
app/services/grok/services/assets.py | 8 +-
app/services/grok/services/chat.py | 18 +--
app/services/grok/services/image.py | 12 +-
app/services/grok/services/media.py | 12 +-
app/services/grok/services/nsfw.py | 14 +-
app/services/grok/services/usage.py | 8 +-
app/services/grok/services/voice.py | 6 +-
app/services/grok/utils/headers.py | 2 +-
app/services/grok/utils/retry.py | 12 +-
app/services/grok/utils/statsig.py | 2 +-
app/static/config/config.html | 2 +-
app/static/config/config.js | 106 +++++++------
config.defaults.toml | 139 ++++++++++++++----
data/config.toml | 93 ++++++++----
docs/README.en.md | 54 ++++---
readme.md | 60 ++++----
22 files changed, 488 insertions(+), 253 deletions(-)
diff --git a/app/api/v1/image.py b/app/api/v1/image.py
index 9a382e2..fc588ff 100644
--- a/app/api/v1/image.py
+++ b/app/api/v1/image.py
@@ -93,7 +93,7 @@ def _validate_common_request(
# WS 流式仅支持 b64_json (base64 视为同义)
if (
request.stream
- and get_config("grok.image_ws")
+ and get_config("image.image_ws")
and request.response_format
and request.response_format not in {"b64_json", "base64"}
):
@@ -319,13 +319,13 @@ async def create_image(request: ImageGenerationRequest):
# 获取 token 和模型信息
token_mgr, token = await _get_token(request.model)
model_info = ModelService.get(request.model)
- use_ws = bool(get_config("grok.image_ws"))
+ use_ws = bool(get_config("image.image_ws"))
# 流式模式
if request.stream:
if use_ws:
aspect_ratio = resolve_aspect_ratio(request.size)
- enable_nsfw = bool(get_config("grok.image_ws_nsfw"))
+ enable_nsfw = bool(get_config("image.image_ws_nsfw"))
upstream = image_service.stream(
token=token,
prompt=request.prompt,
@@ -372,7 +372,7 @@ async def create_image(request: ImageGenerationRequest):
usage_override = None
if use_ws:
aspect_ratio = resolve_aspect_ratio(request.size)
- enable_nsfw = bool(get_config("grok.image_ws_nsfw"))
+ enable_nsfw = bool(get_config("image.image_ws_nsfw"))
all_images = []
seen = set()
expected_per_call = 6
@@ -643,7 +643,7 @@ async def edit_image(
] = parent_post_id
raw_payload = {
- "temporary": bool(get_config("grok.temporary")),
+ "temporary": bool(get_config("chat.temporary")),
"modelName": model_info.grok_model,
"message": edit_request.prompt,
"enableImageGeneration": True,
diff --git a/app/core/config.py b/app/core/config.py
index d9d3e8c..22c125b 100644
--- a/app/core/config.py
+++ b/app/core/config.py
@@ -32,6 +32,81 @@ def _deep_merge(base: Dict[str, Any], override: Dict[str, Any]) -> Dict[str, Any
return result
+def _migrate_deprecated_config(config: Dict[str, Any], valid_sections: set) -> tuple[Dict[str, Any], set]:
+ """
+ 迁移废弃的配置节到新配置结构
+
+ Returns:
+ (迁移后的配置, 废弃的配置节集合)
+ """
+ # 配置映射规则:旧配置 -> 新配置
+ MIGRATION_MAP = {
+ # grok.* -> 对应的新配置节
+ "grok.temporary": "chat.temporary",
+ "grok.disable_memory": "chat.disable_memory",
+ "grok.stream": "chat.stream",
+ "grok.thinking": "chat.thinking",
+ "grok.dynamic_statsig": "chat.dynamic_statsig",
+ "grok.filter_tags": "chat.filter_tags",
+
+ "grok.timeout": "network.timeout",
+ "grok.base_proxy_url": "network.base_proxy_url",
+ "grok.asset_proxy_url": "network.asset_proxy_url",
+
+ "grok.cf_clearance": "security.cf_clearance",
+ "grok.browser": "security.browser",
+ "grok.user_agent": "security.user_agent",
+
+ "grok.max_retry": "retry.max_retry",
+ "grok.retry_status_codes": "retry.retry_status_codes",
+ "grok.retry_backoff_base": "retry.retry_backoff_base",
+ "grok.retry_backoff_factor": "retry.retry_backoff_factor",
+ "grok.retry_backoff_max": "retry.retry_backoff_max",
+ "grok.retry_budget": "retry.retry_budget",
+
+ "grok.stream_idle_timeout": "timeout.stream_idle_timeout",
+ "grok.video_idle_timeout": "timeout.video_idle_timeout",
+
+ "grok.image_ws": "image.image_ws",
+ "grok.image_ws_nsfw": "image.image_ws_nsfw",
+ "grok.image_ws_blocked_seconds": "image.image_ws_blocked_seconds",
+ "grok.image_ws_final_min_bytes": "image.image_ws_final_min_bytes",
+ "grok.image_ws_medium_min_bytes": "image.image_ws_medium_min_bytes",
+ }
+
+ deprecated_sections = set(config.keys()) - valid_sections
+ if not deprecated_sections:
+ return config, set()
+
+ result = {k: deepcopy(v) for k, v in config.items() if k in valid_sections}
+ migrated_count = 0
+
+ # 处理废弃配置节中的配置项
+ for old_section in deprecated_sections:
+ if old_section not in config or not isinstance(config[old_section], dict):
+ continue
+
+ for old_key, old_value in config[old_section].items():
+ # 查找映射规则
+ old_path = f"{old_section}.{old_key}"
+ new_path = MIGRATION_MAP.get(old_path)
+
+ if new_path:
+ new_section, new_key = new_path.split(".", 1)
+ # 确保新配置节存在
+ if new_section not in result:
+ result[new_section] = {}
+ # 迁移配置项(保留用户的自定义值)
+ result[new_section][new_key] = old_value
+ migrated_count += 1
+ logger.debug(f"Migrated config: {old_path} -> {new_path} = {old_value}")
+
+ if migrated_count > 0:
+ logger.info(f"Migrated {migrated_count} config items from deprecated sections")
+
+ return result, deprecated_sections
+
+
def _load_defaults() -> Dict[str, Any]:
"""加载默认配置文件"""
if not DEFAULT_CONFIG_FILE.exists():
@@ -91,10 +166,18 @@ class Config:
config_data = {}
config_data = config_data or {}
+
+ # 检查是否有废弃的配置节
+ valid_sections = set(self._defaults.keys())
+ config_data, deprecated_sections = _migrate_deprecated_config(config_data, valid_sections)
+ if deprecated_sections:
+ logger.info(f"Cleaned deprecated config sections: {deprecated_sections}")
+
merged = _deep_merge(self._defaults, config_data)
# 自动回填缺失配置到存储
- should_persist = (not from_remote) or (merged != config_data)
+ # 或迁移了配置后需要更新
+ should_persist = (not from_remote) or (merged != config_data) or deprecated_sections
if should_persist:
async with storage.acquire_lock("config_save", timeout=10):
await storage.save_config(merged)
@@ -102,6 +185,8 @@ class Config:
logger.info(
f"Initialized remote storage ({storage.__class__.__name__}) with config baseline."
)
+ if deprecated_sections:
+ logger.info("Configuration automatically migrated and cleaned.")
self._config = merged
except Exception as e:
diff --git a/app/services/grok/defaults.py b/app/services/grok/defaults.py
index 78ade9a..e23f515 100644
--- a/app/services/grok/defaults.py
+++ b/app/services/grok/defaults.py
@@ -6,60 +6,84 @@ Grok 服务默认配置
# Grok 服务默认配置
GROK_DEFAULTS = {
- "grok": {
- # 网络配置
- "browser": "chrome136",
+ "app": {
+ "app_url": "",
+ "app_key": "grok2api",
+ "api_key": "",
+ "image_format": "url",
+ "video_format": "html",
+ },
+
+ "network": {
"timeout": 120,
- "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36",
"base_proxy_url": "",
"asset_proxy_url": "",
+ },
+
+ "security": {
"cf_clearance": "",
-
- # 对话配置
+ "browser": "chrome136",
+ "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36",
+ },
+
+ "chat": {
"temporary": True,
"disable_memory": True,
"stream": True,
"thinking": False,
+ "dynamic_statsig": True,
"filter_tags": ["grok:render", "xaiartifact", "xai:tool_usage_card"],
-
- # 重试配置
+ },
+
+ "retry": {
"max_retry": 3,
"retry_status_codes": [401, 429, 403],
"retry_backoff_base": 0.5,
"retry_backoff_factor": 2.0,
"retry_backoff_max": 30.0,
"retry_budget": 90.0,
-
- # 超时配置
+ },
+
+ "timeout": {
"stream_idle_timeout": 45.0,
"video_idle_timeout": 90.0,
-
- # 图片配置
+ },
+
+ "image": {
+ "image_ws": True,
+ "image_ws_nsfw": True,
"image_ws_blocked_seconds": 15,
"image_ws_final_min_bytes": 100000,
"image_ws_medium_min_bytes": 30000,
-
- # Statsig
- "dynamic_statsig": True,
},
- "app": {
- "app_url": "",
- "image_format": "url",
- "video_format": "html",
- },
-
- "performance": {
- "assets_max_concurrent": 25,
- "assets_delete_batch_size": 10,
- "media_max_concurrent": 50,
- "usage_max_concurrent": 25,
+ "token": {
+ "auto_refresh": True,
+ "refresh_interval_hours": 8,
+ "super_refresh_interval_hours": 2,
+ "fail_threshold": 5,
+ "save_delay_ms": 500,
+ "reload_interval_sec": 30,
},
"cache": {
"enable_auto_clean": True,
"limit_mb": 1024,
},
+
+ "performance": {
+ "assets_max_concurrent": 25,
+ "assets_delete_batch_size": 10,
+ "assets_batch_size": 10,
+ "assets_max_tokens": 1000,
+ "media_max_concurrent": 50,
+ "usage_max_concurrent": 25,
+ "usage_batch_size": 50,
+ "usage_max_tokens": 1000,
+ "nsfw_max_concurrent": 10,
+ "nsfw_batch_size": 50,
+ "nsfw_max_tokens": 1000,
+ },
}
diff --git a/app/services/grok/processors/chat_processors.py b/app/services/grok/processors/chat_processors.py
index a7bf5d4..d7002ca 100644
--- a/app/services/grok/processors/chat_processors.py
+++ b/app/services/grok/processors/chat_processors.py
@@ -32,13 +32,13 @@ class StreamProcessor(BaseProcessor):
self.fingerprint: str = ""
self.think_opened: bool = False
self.role_sent: bool = False
- self.filter_tags = get_config("grok.filter_tags")
+ self.filter_tags = get_config("chat.filter_tags")
self.image_format = get_config("app.image_format")
self._tag_buffer: str = ""
self._in_filter_tag: bool = False
if think is None:
- self.show_think = get_config("grok.thinking")
+ self.show_think = get_config("chat.thinking")
else:
self.show_think = think
@@ -114,7 +114,7 @@ class StreamProcessor(BaseProcessor):
async def process(self, response: AsyncIterable[bytes]) -> AsyncGenerator[str, None]:
"""处理流式响应"""
- idle_timeout = get_config("grok.stream_idle_timeout")
+ idle_timeout = get_config("timeout.stream_idle_timeout")
try:
async for line in _with_idle_timeout(response, idle_timeout, self.model):
@@ -223,7 +223,7 @@ class CollectProcessor(BaseProcessor):
def __init__(self, model: str, token: str = ""):
super().__init__(model, token)
self.image_format = get_config("app.image_format")
- self.filter_tags = get_config("grok.filter_tags")
+ self.filter_tags = get_config("chat.filter_tags")
def _filter_content(self, content: str) -> str:
"""过滤内容中的特殊标签"""
@@ -242,7 +242,7 @@ class CollectProcessor(BaseProcessor):
response_id = ""
fingerprint = ""
content = ""
- idle_timeout = get_config("grok.stream_idle_timeout")
+ idle_timeout = get_config("timeout.stream_idle_timeout")
try:
async for line in _with_idle_timeout(response, idle_timeout, self.model):
diff --git a/app/services/grok/processors/image_processors.py b/app/services/grok/processors/image_processors.py
index 8550108..42214c7 100644
--- a/app/services/grok/processors/image_processors.py
+++ b/app/services/grok/processors/image_processors.py
@@ -45,7 +45,7 @@ class ImageStreamProcessor(BaseProcessor):
async def process(self, response: AsyncIterable[bytes]) -> AsyncGenerator[str, None]:
"""处理流式响应"""
final_images = []
- idle_timeout = get_config("grok.stream_idle_timeout")
+ idle_timeout = get_config("timeout.stream_idle_timeout")
try:
async for line in _with_idle_timeout(response, idle_timeout, self.model):
@@ -160,7 +160,7 @@ class ImageCollectProcessor(BaseProcessor):
async def process(self, response: AsyncIterable[bytes]) -> List[str]:
"""处理并收集图片"""
images = []
- idle_timeout = get_config("grok.stream_idle_timeout")
+ idle_timeout = get_config("timeout.stream_idle_timeout")
try:
async for line in _with_idle_timeout(response, idle_timeout, self.model):
diff --git a/app/services/grok/processors/video_processors.py b/app/services/grok/processors/video_processors.py
index df8750c..ec39aae 100644
--- a/app/services/grok/processors/video_processors.py
+++ b/app/services/grok/processors/video_processors.py
@@ -32,7 +32,7 @@ class VideoStreamProcessor(BaseProcessor):
self.video_format = str(get_config("app.video_format")).lower()
if think is None:
- self.show_think = get_config("grok.thinking")
+ self.show_think = get_config("chat.thinking")
else:
self.show_think = think
@@ -68,7 +68,7 @@ class VideoStreamProcessor(BaseProcessor):
async def process(self, response: AsyncIterable[bytes]) -> AsyncGenerator[str, None]:
"""处理视频流式响应"""
- idle_timeout = get_config("grok.video_idle_timeout")
+ idle_timeout = get_config("timeout.video_idle_timeout")
try:
async for line in _with_idle_timeout(response, idle_timeout, self.model):
@@ -171,7 +171,7 @@ class VideoCollectProcessor(BaseProcessor):
"""处理并收集视频响应"""
response_id = ""
content = ""
- idle_timeout = get_config("grok.video_idle_timeout")
+ idle_timeout = get_config("timeout.video_idle_timeout")
try:
async for line in _with_idle_timeout(response, idle_timeout, self.model):
diff --git a/app/services/grok/services/assets.py b/app/services/grok/services/assets.py
index 91a5270..d576b81 100644
--- a/app/services/grok/services/assets.py
+++ b/app/services/grok/services/assets.py
@@ -111,10 +111,10 @@ class ServiceConfig:
@classmethod
def from_settings(cls, proxy: Optional[str] = None):
return cls(
- proxy=proxy or get_config("grok.asset_proxy_url") or get_config("grok.base_proxy_url"),
- timeout=get_config("grok.timeout"),
- browser=get_config("grok.browser"),
- user_agent=get_config("grok.user_agent"),
+ proxy=proxy or get_config("network.asset_proxy_url") or get_config("network.base_proxy_url"),
+ timeout=get_config("network.timeout"),
+ browser=get_config("security.browser"),
+ user_agent=get_config("security.user_agent"),
)
def get_proxies(self) -> Optional[dict]:
diff --git a/app/services/grok/services/chat.py b/app/services/grok/services/chat.py
index 8d2aab7..99ea4ce 100644
--- a/app/services/grok/services/chat.py
+++ b/app/services/grok/services/chat.py
@@ -102,7 +102,7 @@ class ChatRequestBuilder:
@staticmethod
def build_headers(token: str) -> Dict[str, str]:
"""构造请求头"""
- user_agent = get_config("grok.user_agent")
+ user_agent = get_config("security.user_agent")
headers = {
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate, br, zstd",
@@ -142,7 +142,7 @@ class ChatRequestBuilder:
merged_attachments.extend(image_attachments)
payload = {
- "temporary": get_config("grok.temporary"),
+ "temporary": get_config("chat.temporary"),
"modelName": model,
"message": message,
"fileAttachments": merged_attachments,
@@ -160,7 +160,7 @@ class ChatRequestBuilder:
"modelConfigOverride": {"modelMap": {}},
"requestModelDetails": {"modelId": model},
},
- "disableMemory": get_config("grok.disable_memory"),
+ "disableMemory": get_config("chat.disable_memory"),
"deviceEnvInfo": {
"darkModeEnabled": False,
"devicePixelRatio": 2,
@@ -181,27 +181,27 @@ class GrokChatService:
"""Grok API 调用服务"""
def __init__(self, proxy: str = None):
- self.proxy = proxy or get_config("grok.base_proxy_url")
+ self.proxy = proxy or get_config("network.base_proxy_url")
async def chat(self, token: str, message: str, model: str = "grok-3", mode: str = None,
stream: bool = None, file_attachments: List[str] = None,
image_attachments: List[str] = None, raw_payload: Dict[str, Any] = None):
"""发送聊天请求"""
if stream is None:
- stream = get_config("grok.stream")
+ stream = get_config("chat.stream")
headers = ChatRequestBuilder.build_headers(token)
payload = raw_payload if raw_payload is not None else ChatRequestBuilder.build_payload(
message, model, mode, file_attachments, image_attachments
)
proxies = {"http": self.proxy, "https": self.proxy} if self.proxy else None
- timeout = get_config("grok.timeout")
+ timeout = get_config("network.timeout")
logger.debug(f"Chat request: model={model}, mode={mode}, stream={stream}, attachments={len(file_attachments or [])}")
# 建立连接
async def establish_connection():
- browser = get_config("grok.browser")
+ browser = get_config("security.browser")
session = AsyncSession(impersonate=browser)
try:
response = await session.post(
@@ -303,7 +303,7 @@ class GrokChatService:
finally:
await upload_service.close()
- stream = request.stream if request.stream is not None else get_config("grok.stream")
+ stream = request.stream if request.stream is not None else get_config("chat.stream")
response = await self.chat(
token, message, grok_model, mode, stream,
@@ -340,7 +340,7 @@ class ChatService:
# 解析参数
think = {"enabled": True, "disabled": False}.get(thinking)
- is_stream = stream if stream is not None else get_config("grok.stream")
+ is_stream = stream if stream is not None else get_config("chat.stream")
# 构造请求
chat_request = ChatRequest(model=model, messages=messages, stream=is_stream, think=think)
diff --git a/app/services/grok/services/image.py b/app/services/grok/services/image.py
index 9e51207..b94feb6 100644
--- a/app/services/grok/services/image.py
+++ b/app/services/grok/services/image.py
@@ -32,7 +32,7 @@ class ImageService:
self._url_pattern = re.compile(r"/images/([a-f0-9-]+)\.(png|jpg|jpeg)")
def _resolve_proxy(self) -> tuple[aiohttp.BaseConnector, Optional[str]]:
- proxy_url = get_config("grok.base_proxy_url")
+ proxy_url = get_config("network.base_proxy_url")
if not proxy_url:
return aiohttp.TCPConnector(ssl=self._ssl_context), None
@@ -46,7 +46,7 @@ class ImageService:
def _get_ws_headers(self, token: str) -> Dict[str, str]:
cookie = build_sso_cookie(token, include_rw=True)
- user_agent = get_config("grok.user_agent")
+ user_agent = get_config("security.user_agent")
return {
"Cookie": cookie,
"Origin": "https://grok.com",
@@ -61,7 +61,7 @@ class ImageService:
return match.group(1) if match else None
def _is_final_image(self, url: str, blob_size: int) -> bool:
- return (url or "").lower().endswith((".jpg", ".jpeg")) and blob_size > get_config("grok.image_ws_final_min_bytes")
+ return (url or "").lower().endswith((".jpg", ".jpeg")) and blob_size > get_config("image.image_ws_final_min_bytes")
def _classify_image(self, url: str, blob: str) -> Optional[Dict[str, object]]:
if not url or not blob:
@@ -71,7 +71,7 @@ class ImageService:
blob_size = len(blob)
is_final = self._is_final_image(url, blob_size)
- stage = "final" if is_final else ("medium" if blob_size > get_config("grok.image_ws_medium_min_bytes") else "preview")
+ stage = "final" if is_final else ("medium" if blob_size > get_config("image.image_ws_medium_min_bytes") else "preview")
return {
"type": "image",
@@ -122,8 +122,8 @@ class ImageService:
) -> AsyncGenerator[Dict[str, object], None]:
request_id = str(uuid.uuid4())
headers = self._get_ws_headers(token)
- timeout = float(get_config("grok.timeout"))
- blocked_seconds = float(get_config("grok.image_ws_blocked_seconds"))
+ timeout = float(get_config("network.timeout"))
+ blocked_seconds = float(get_config("image.image_ws_blocked_seconds"))
try:
connector, proxy = self._resolve_proxy()
diff --git a/app/services/grok/services/media.py b/app/services/grok/services/media.py
index 39b0849..10c4ba4 100644
--- a/app/services/grok/services/media.py
+++ b/app/services/grok/services/media.py
@@ -43,14 +43,14 @@ class VideoService:
"""视频生成服务"""
def __init__(self, proxy: str = None):
- self.proxy = proxy or get_config("grok.base_proxy_url")
- self.timeout = get_config("grok.timeout")
+ self.proxy = proxy or get_config("network.base_proxy_url")
+ self.timeout = get_config("network.timeout")
def _build_headers(
self, token: str, referer: str = "https://grok.com/imagine"
) -> dict:
"""构建请求头"""
- user_agent = get_config("grok.user_agent")
+ user_agent = get_config("security.user_agent")
headers = {
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate, br, zstd",
@@ -103,7 +103,7 @@ class VideoService:
CREATE_POST_API,
headers=headers,
json=payload,
- impersonate=get_config("grok.browser"),
+ impersonate=get_config("security.browser"),
timeout=30,
proxies=self._build_proxies(),
)
@@ -172,7 +172,7 @@ class VideoService:
headers = self._build_headers(token)
payload = self._build_payload(prompt, post_id, aspect_ratio, video_length, resolution_name, preset)
- session = AsyncSession(impersonate=get_config("grok.browser"))
+ session = AsyncSession(impersonate=get_config("security.browser"))
response = await session.post(
CHAT_API,
headers=headers,
@@ -267,7 +267,7 @@ class VideoService:
)
think = {"enabled": True, "disabled": False}.get(thinking)
- is_stream = stream if stream is not None else get_config("grok.stream")
+ is_stream = stream if stream is not None else get_config("chat.stream")
# 提取内容
from app.services.grok.services.chat import MessageExtractor
diff --git a/app/services/grok/services/nsfw.py b/app/services/grok/services/nsfw.py
index 169ed4d..fa02b8f 100644
--- a/app/services/grok/services/nsfw.py
+++ b/app/services/grok/services/nsfw.py
@@ -37,8 +37,8 @@ class NSFWService:
"""NSFW 模式服务"""
def __init__(self, proxy: str = None):
- self.proxy = proxy or get_config("grok.base_proxy_url")
- self.timeout = float(get_config("grok.timeout"))
+ self.proxy = proxy or get_config("network.base_proxy_url")
+ self.timeout = float(get_config("network.timeout"))
def _build_proxies(self) -> Optional[dict]:
"""构建代理配置"""
@@ -60,7 +60,7 @@ class NSFWService:
def _build_headers(self, token: str) -> dict:
"""构造 gRPC-Web 请求头"""
cookie = build_sso_cookie(token, include_rw=True)
- user_agent = get_config("grok.user_agent")
+ user_agent = get_config("security.user_agent")
return {
"accept": "*/*",
"content-type": "application/grpc-web+proto",
@@ -75,7 +75,7 @@ class NSFWService:
def _build_birth_headers(self, token: str) -> dict:
"""构造设置出生日期请求头"""
cookie = build_sso_cookie(token, include_rw=True)
- user_agent = get_config("grok.user_agent")
+ user_agent = get_config("security.user_agent")
return {
"accept": "*/*",
"content-type": "application/json",
@@ -97,9 +97,7 @@ class NSFWService:
protobuf = b"\x0a\x02\x10\x01\x12" + bytes([len(inner)]) + inner
return encode_grpc_web_payload(protobuf)
- async def _set_birth_date(
- self, session: AsyncSession, token: str
- ) -> tuple[bool, int, Optional[str]]:
+ async def _set_birth_date(self, session: AsyncSession, token: str) -> tuple[bool, int, Optional[str]]:
"""设置出生日期"""
headers = self._build_birth_headers(token)
payload = {"birthDate": self._random_birth_date()}
@@ -125,7 +123,7 @@ class NSFWService:
logger.debug(f"NSFW payload: len={len(payload)} hex={payload.hex()}")
try:
- browser = get_config("grok.browser")
+ browser = get_config("security.browser")
async with AsyncSession(impersonate=browser) as session:
# 先设置出生日期
ok, birth_status, birth_err = await self._set_birth_date(session, token)
diff --git a/app/services/grok/services/usage.py b/app/services/grok/services/usage.py
index bf3d5cb..adb04b3 100644
--- a/app/services/grok/services/usage.py
+++ b/app/services/grok/services/usage.py
@@ -23,12 +23,12 @@ class UsageService:
"""用量查询服务"""
def __init__(self, proxy: str = None):
- self.proxy = proxy or get_config("grok.base_proxy_url")
- self.timeout = get_config("grok.timeout")
+ self.proxy = proxy or get_config("network.base_proxy_url")
+ self.timeout = get_config("network.timeout")
def _build_headers(self, token: str) -> dict:
"""构建请求头"""
- user_agent = get_config("grok.user_agent")
+ user_agent = get_config("security.user_agent")
headers = {
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate, br, zstd",
@@ -97,7 +97,7 @@ class UsageService:
try:
headers = self._build_headers(token)
payload = {"requestKind": "DEFAULT", "modelName": model_name}
- browser = get_config("grok.browser")
+ browser = get_config("security.browser")
async with AsyncSession() as session:
response = await session.post(
diff --git a/app/services/grok/services/voice.py b/app/services/grok/services/voice.py
index 6c231ae..ae003f0 100644
--- a/app/services/grok/services/voice.py
+++ b/app/services/grok/services/voice.py
@@ -18,7 +18,7 @@ class VoiceService:
"""Voice Mode Service (LiveKit)"""
def __init__(self, proxy: str = None):
- self.proxy = proxy or get_config("grok.base_proxy_url")
+ self.proxy = proxy or get_config("network.base_proxy_url")
async def get_token(
self,
@@ -42,8 +42,8 @@ class VoiceService:
proxies = {"http": self.proxy, "https": self.proxy} if self.proxy else None
try:
- browser = get_config("grok.browser")
- timeout = get_config("grok.timeout")
+ browser = get_config("security.browser")
+ timeout = get_config("network.timeout")
async with AsyncSession(impersonate=browser) as session:
response = await session.post(
LIVEKIT_TOKEN_API,
diff --git a/app/services/grok/utils/headers.py b/app/services/grok/utils/headers.py
index 146e704..7a5e1c2 100644
--- a/app/services/grok/utils/headers.py
+++ b/app/services/grok/utils/headers.py
@@ -17,7 +17,7 @@ def _normalize_token(token: str) -> str:
def build_sso_cookie(token: str, include_rw: bool = False) -> str:
token = _normalize_token(token)
- cf = get_config("grok.cf_clearance")
+ cf = get_config("security.cf_clearance")
cookie = f"sso={token}"
if include_rw:
cookie = f"{cookie}; sso-rw={token}"
diff --git a/app/services/grok/utils/retry.py b/app/services/grok/utils/retry.py
index 2cd52c5..7fa7eba 100644
--- a/app/services/grok/utils/retry.py
+++ b/app/services/grok/utils/retry.py
@@ -23,17 +23,17 @@ class RetryContext:
def __init__(self):
self.attempt = 0
- self.max_retry = int(get_config("grok.max_retry"))
- self.retry_codes = get_config("grok.retry_status_codes")
+ self.max_retry = int(get_config("retry.max_retry"))
+ self.retry_codes = get_config("retry.retry_status_codes")
self.last_error = None
self.last_status = None
self.total_delay = 0.0
- self.retry_budget = float(get_config("grok.retry_budget"))
+ self.retry_budget = float(get_config("retry.retry_budget"))
# 退避参数
- self.backoff_base = float(get_config("grok.retry_backoff_base"))
- self.backoff_factor = float(get_config("grok.retry_backoff_factor"))
- self.backoff_max = float(get_config("grok.retry_backoff_max"))
+ self.backoff_base = float(get_config("retry.retry_backoff_base"))
+ self.backoff_factor = float(get_config("retry.retry_backoff_factor"))
+ self.backoff_max = float(get_config("retry.retry_backoff_max"))
# decorrelated jitter 状态
self._last_delay = self.backoff_base
diff --git a/app/services/grok/utils/statsig.py b/app/services/grok/utils/statsig.py
index bf78741..c2cd15f 100644
--- a/app/services/grok/utils/statsig.py
+++ b/app/services/grok/utils/statsig.py
@@ -30,7 +30,7 @@ class StatsigService:
Returns:
Base64 编码的 ID
"""
- dynamic = get_config("grok.dynamic_statsig")
+ dynamic = get_config("chat.dynamic_statsig")
if not dynamic:
return "ZTpUeXBlRXJyb3I6IENhbm5vdCByZWFkIHByb3BlcnRpZXMgb2YgdW5kZWZpbmVkIChyZWFkaW5nICdjaGlsZE5vZGVzJyk="
diff --git a/app/static/config/config.html b/app/static/config/config.html
index 7fb207f..6fdff9e 100644
--- a/app/static/config/config.html
+++ b/app/static/config/config.html
@@ -50,7 +50,7 @@
-
+