mirror of https://github.com/Mai-with-u/MaiBot.git
feat: 增强 WebUI 配置,支持防爬虫和安全 Cookie 设置
parent
d3b71a7181
commit
3231995ebd
|
|
@ -75,7 +75,6 @@ max_embedding_workers = 12 # 嵌入/抽取并发线程数
|
|||
embedding_chunk_size = 16 # 每批嵌入的条数
|
||||
info_extraction_workers = 3 # 实体抽取同时执行线程数
|
||||
enable_ppr = true # 是否启用PPR,低配机器可关闭
|
||||
ppr_node_cap = 8000 # 图节点数超过该值时自动跳过PPR
|
||||
```
|
||||
|
||||
- `embedding_dimension`
|
||||
|
|
@ -101,8 +100,6 @@ ppr_node_cap = 8000 # 图节点数超过该值时自动跳过PPR
|
|||
- `true`:检索会结合向量+知识图,效果更好,但略慢;
|
||||
- `false`:只用向量检索,牺牲一定效果,性能更稳定。
|
||||
|
||||
- `ppr_node_cap`
|
||||
安全阈值:当图节点数超过阈值时自动跳过 PPR,以避免“大图”导致卡顿。
|
||||
|
||||
> 调参建议:
|
||||
> - 若导入/检索阶段机器明显“顶不住”(>=1MB的大文本,且分配配置<4C),优先调低:
|
||||
|
|
|
|||
|
|
@ -42,7 +42,10 @@ def lpmm_start_up(): # sourcery skip: extract-duplicate-method
|
|||
logger.info("创建LLM客户端")
|
||||
|
||||
# 初始化Embedding库
|
||||
embed_manager = EmbeddingManager()
|
||||
embed_manager = EmbeddingManager(
|
||||
max_workers=global_config.lpmm_knowledge.max_embedding_workers,
|
||||
chunk_size=global_config.lpmm_knowledge.embedding_chunk_size,
|
||||
)
|
||||
logger.info("正在从文件加载Embedding库")
|
||||
try:
|
||||
embed_manager.load_from_file()
|
||||
|
|
|
|||
|
|
@ -358,12 +358,9 @@ class KGManager:
|
|||
paragraph_search_result: ParagraphEmbedding的搜索结果(paragraph_hash, similarity)
|
||||
embed_manager: EmbeddingManager对象
|
||||
"""
|
||||
# 性能保护:关闭或超限时直接返回向量检索结果(仅基于节点规模与开关)
|
||||
if (
|
||||
not global_config.lpmm_knowledge.enable_ppr
|
||||
or len(self.graph.get_node_list()) > global_config.lpmm_knowledge.ppr_node_cap
|
||||
):
|
||||
logger.info("PPR 已禁用或超出阈值,使用纯向量检索结果")
|
||||
# 性能保护:关闭时直接返回向量检索结果
|
||||
if not global_config.lpmm_knowledge.enable_ppr:
|
||||
logger.info("PPR 已禁用,使用纯向量检索结果")
|
||||
return paragraph_search_result, None
|
||||
# 图中存在的节点总集
|
||||
existed_nodes = self.graph.get_node_list()
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ from src.config.official_configs import (
|
|||
MemoryConfig,
|
||||
DebugConfig,
|
||||
DreamConfig,
|
||||
WebUIConfig,
|
||||
)
|
||||
|
||||
from .api_ada_configs import (
|
||||
|
|
@ -347,6 +348,7 @@ class Config(ConfigBase):
|
|||
response_post_process: ResponsePostProcessConfig
|
||||
response_splitter: ResponseSplitterConfig
|
||||
telemetry: TelemetryConfig
|
||||
webui: WebUIConfig
|
||||
experimental: ExperimentalConfig
|
||||
maim_message: MaimMessageConfig
|
||||
lpmm_knowledge: LPMMKnowledgeConfig
|
||||
|
|
|
|||
|
|
@ -597,6 +597,38 @@ class TelemetryConfig(ConfigBase):
|
|||
"""是否启用遥测"""
|
||||
|
||||
|
||||
@dataclass
|
||||
class WebUIConfig(ConfigBase):
|
||||
"""WebUI配置类"""
|
||||
|
||||
enabled: bool = True
|
||||
"""是否启用WebUI"""
|
||||
|
||||
mode: Literal["development", "production"] = "production"
|
||||
"""运行模式:development(开发) 或 production(生产)"""
|
||||
|
||||
host: str = "0.0.0.0"
|
||||
"""WebUI服务器监听地址"""
|
||||
|
||||
port: int = 8001
|
||||
"""WebUI服务器端口"""
|
||||
|
||||
anti_crawler_mode: Literal["false", "strict", "loose", "basic"] = "basic"
|
||||
"""防爬虫模式:false(禁用) / strict(严格) / loose(宽松) / basic(基础-只记录不阻止)"""
|
||||
|
||||
allowed_ips: str = "127.0.0.1"
|
||||
"""IP白名单(逗号分隔,支持精确IP、CIDR格式和通配符)"""
|
||||
|
||||
trusted_proxies: str = ""
|
||||
"""信任的代理IP列表(逗号分隔),只有来自这些IP的X-Forwarded-For才被信任"""
|
||||
|
||||
trust_xff: bool = False
|
||||
"""是否启用X-Forwarded-For代理解析(默认false)"""
|
||||
|
||||
secure_cookie: bool = False
|
||||
"""是否启用安全Cookie(仅通过HTTPS传输,默认false)"""
|
||||
|
||||
|
||||
@dataclass
|
||||
class DebugConfig(ConfigBase):
|
||||
"""调试配置类"""
|
||||
|
|
@ -722,6 +754,18 @@ class LPMMKnowledgeConfig(ConfigBase):
|
|||
embedding_dimension: int = 1024
|
||||
"""嵌入向量维度,应该与模型的输出维度一致"""
|
||||
|
||||
max_embedding_workers: int = 3
|
||||
"""嵌入/抽取并发线程数"""
|
||||
|
||||
embedding_chunk_size: int = 4
|
||||
"""每批嵌入的条数"""
|
||||
|
||||
max_synonym_entities: int = 2000
|
||||
"""同义边参与的实体数上限,超限则跳过"""
|
||||
|
||||
enable_ppr: bool = True
|
||||
"""是否启用PPR,低配机器可关闭"""
|
||||
|
||||
|
||||
@dataclass
|
||||
class DreamConfig(ConfigBase):
|
||||
|
|
|
|||
|
|
@ -44,10 +44,9 @@ class MainSystem:
|
|||
|
||||
def _setup_webui_server(self):
|
||||
"""设置独立的 WebUI 服务器"""
|
||||
import os
|
||||
from src.config.config import global_config
|
||||
|
||||
webui_enabled = os.getenv("WEBUI_ENABLED", "false").lower() == "true"
|
||||
if not webui_enabled:
|
||||
if not global_config.webui.enabled:
|
||||
logger.info("WebUI 已禁用")
|
||||
return
|
||||
|
||||
|
|
|
|||
|
|
@ -124,10 +124,8 @@ SCANNER_SPECIFIC_HEADERS = {
|
|||
# strict: 严格模式(更严格的检测,更低的频率限制)
|
||||
# loose: 宽松模式(较宽松的检测,较高的频率限制)
|
||||
# basic: 基础模式(只记录恶意访问,不阻止,不限制请求数,不跟踪IP)
|
||||
ANTI_CRAWLER_MODE = os.getenv("WEBUI_ANTI_CRAWLER_MODE", "basic").lower()
|
||||
|
||||
|
||||
# IP白名单配置(从环境变量读取,逗号分隔)
|
||||
# IP白名单配置(从配置文件读取,逗号分隔)
|
||||
# 支持格式:
|
||||
# - 精确IP:127.0.0.1, 192.168.1.100
|
||||
# - CIDR格式:192.168.1.0/24, 172.17.0.0/16 (适用于Docker网络)
|
||||
|
|
@ -236,13 +234,23 @@ def _convert_wildcard_to_regex(wildcard_pattern: str) -> Optional[str]:
|
|||
return regex
|
||||
|
||||
|
||||
ALLOWED_IPS = _parse_allowed_ips(os.getenv("WEBUI_ALLOWED_IPS", ""))
|
||||
# 从配置读取防爬虫设置(延迟导入避免循环依赖)
|
||||
def _get_anti_crawler_config():
|
||||
"""获取防爬虫配置"""
|
||||
from src.config.config import global_config
|
||||
return {
|
||||
'mode': global_config.webui.anti_crawler_mode,
|
||||
'allowed_ips': _parse_allowed_ips(global_config.webui.allowed_ips),
|
||||
'trusted_proxies': _parse_allowed_ips(global_config.webui.trusted_proxies),
|
||||
'trust_xff': global_config.webui.trust_xff
|
||||
}
|
||||
|
||||
# 信任的代理IP配置(从环境变量读取,逗号分隔)
|
||||
# 只有在信任的代理IP下才使用X-Forwarded-For头
|
||||
# 默认关闭(空),不信任任何代理
|
||||
TRUSTED_PROXIES = _parse_allowed_ips(os.getenv("WEBUI_TRUSTED_PROXIES", ""))
|
||||
TRUST_XFF = os.getenv("WEBUI_TRUST_XFF", "false").lower() == "true"
|
||||
# 初始化配置(将在模块加载时执行)
|
||||
_config = _get_anti_crawler_config()
|
||||
ANTI_CRAWLER_MODE = _config['mode']
|
||||
ALLOWED_IPS = _config['allowed_ips']
|
||||
TRUSTED_PROXIES = _config['trusted_proxies']
|
||||
TRUST_XFF = _config['trust_xff']
|
||||
|
||||
|
||||
def _get_mode_config(mode: str) -> dict:
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@ WebUI 认证模块
|
|||
提供统一的认证依赖,支持 Cookie 和 Header 两种方式
|
||||
"""
|
||||
|
||||
import os
|
||||
from typing import Optional
|
||||
from fastapi import HTTPException, Cookie, Header, Response, Request
|
||||
from src.common.logger import get_logger
|
||||
from src.config.config import global_config
|
||||
from .token_manager import get_token_manager
|
||||
|
||||
logger = get_logger("webui.auth")
|
||||
|
|
@ -23,23 +23,18 @@ def _is_secure_environment() -> bool:
|
|||
Returns:
|
||||
bool: 如果应该使用 secure cookie 则返回 True
|
||||
"""
|
||||
# 检查环境变量
|
||||
secure_cookie_env = os.environ.get("WEBUI_SECURE_COOKIE", "")
|
||||
if secure_cookie_env.lower() in ("true", "1", "yes"):
|
||||
logger.info(f"WEBUI_SECURE_COOKIE 设置为 {secure_cookie_env},启用 secure cookie")
|
||||
# 从配置读取
|
||||
if global_config.webui.secure_cookie:
|
||||
logger.info("配置中启用了 secure_cookie")
|
||||
return True
|
||||
if secure_cookie_env.lower() in ("false", "0", "no"):
|
||||
logger.info(f"WEBUI_SECURE_COOKIE 设置为 {secure_cookie_env},禁用 secure cookie")
|
||||
return False
|
||||
|
||||
|
||||
# 检查是否是生产环境
|
||||
env = os.environ.get("WEBUI_MODE", "").lower()
|
||||
if env in ("production", "prod"):
|
||||
logger.info(f"WEBUI_MODE 设置为 {env},启用 secure cookie")
|
||||
if global_config.webui.mode == "production":
|
||||
logger.info("WebUI运行在生产模式,启用 secure cookie")
|
||||
return True
|
||||
|
||||
# 默认:开发环境不启用(因为通常是 HTTP)
|
||||
logger.debug(f"未设置特殊环境变量 (WEBUI_SECURE_COOKIE={secure_cookie_env}, WEBUI_MODE={env}),禁用 secure cookie")
|
||||
logger.debug("WebUI运行在开发模式,禁用 secure cookie")
|
||||
return False
|
||||
|
||||
|
||||
|
|
@ -111,7 +106,7 @@ def set_auth_cookie(response: Response, token: str, request: Optional[Request] =
|
|||
logger.warning("=" * 80)
|
||||
logger.warning("检测到 HTTP 连接但环境配置要求 HTTPS (secure cookie)")
|
||||
logger.warning("已自动禁用 secure 标志以允许登录,但建议修改配置:")
|
||||
logger.warning("1. 在 .env 文件中设置: WEBUI_SECURE_COOKIE=false")
|
||||
logger.warning("1. 在配置文件中设置: webui.secure_cookie = false")
|
||||
logger.warning("2. 如果使用反向代理,请确保正确配置 X-Forwarded-Proto 头")
|
||||
logger.warning("=" * 80)
|
||||
is_secure = False
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
"""独立的 WebUI 服务器 - 运行在 0.0.0.0:8001"""
|
||||
|
||||
import os
|
||||
import asyncio
|
||||
import mimetypes
|
||||
from pathlib import Path
|
||||
|
|
@ -130,9 +129,10 @@ class WebUIServer:
|
|||
"""配置防爬虫中间件"""
|
||||
try:
|
||||
from src.webui.anti_crawler import AntiCrawlerMiddleware
|
||||
from src.config.config import global_config
|
||||
|
||||
# 从环境变量读取防爬虫模式(false/strict/loose/basic)
|
||||
anti_crawler_mode = os.getenv("WEBUI_ANTI_CRAWLER_MODE", "basic").lower()
|
||||
# 从配置读取防爬虫模式
|
||||
anti_crawler_mode = global_config.webui.anti_crawler_mode
|
||||
|
||||
# 注意:中间件按注册顺序反向执行,所以先注册的中间件后执行
|
||||
# 我们需要在CORS之前注册,这样防爬虫检查会在CORS之前执行
|
||||
|
|
@ -186,7 +186,7 @@ class WebUIServer:
|
|||
error_msg = f"❌ WebUI 服务器启动失败: 端口 {self.port} 已被占用"
|
||||
logger.error(error_msg)
|
||||
logger.error(f"💡 请检查是否有其他程序正在使用端口 {self.port}")
|
||||
logger.error("💡 可以通过环境变量 WEBUI_PORT 修改 WebUI 端口")
|
||||
logger.error("💡 可以在配置文件中修改 webui.port 来更改 WebUI 端口")
|
||||
logger.error(f"💡 Windows 用户可以运行: netstat -ano | findstr :{self.port}")
|
||||
logger.error(f"💡 Linux/Mac 用户可以运行: lsof -i :{self.port}")
|
||||
raise OSError(f"端口 {self.port} 已被占用,无法启动 WebUI 服务器")
|
||||
|
|
@ -212,7 +212,7 @@ class WebUIServer:
|
|||
if "address already in use" in str(e).lower() or e.errno in (98, 10048): # 98: Linux, 10048: Windows
|
||||
logger.error(f"❌ WebUI 服务器启动失败: 端口 {self.port} 已被占用")
|
||||
logger.error(f"💡 请检查是否有其他程序正在使用端口 {self.port}")
|
||||
logger.error("💡 可以通过环境变量 WEBUI_PORT 修改 WebUI 端口")
|
||||
logger.error("💡 可以在配置文件中修改 webui.port 来更改 WebUI 端口")
|
||||
else:
|
||||
logger.error(f"❌ WebUI 服务器启动失败 (网络错误): {e}")
|
||||
raise
|
||||
|
|
@ -257,8 +257,9 @@ def get_webui_server() -> WebUIServer:
|
|||
"""获取全局 WebUI 服务器实例"""
|
||||
global _webui_server
|
||||
if _webui_server is None:
|
||||
# 从环境变量读取配置
|
||||
host = os.getenv("WEBUI_HOST", "0.0.0.0")
|
||||
port = int(os.getenv("WEBUI_PORT", "8001"))
|
||||
# 从配置读取
|
||||
from src.config.config import global_config
|
||||
host = global_config.webui.host
|
||||
port = global_config.webui.port
|
||||
_webui_server = WebUIServer(host=host, port=port)
|
||||
return _webui_server
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
[inner]
|
||||
version = "7.2.2"
|
||||
version = "7.2.3"
|
||||
|
||||
#----以下是给开发人员阅读的,如果你只是部署了麦麦,不需要阅读----
|
||||
# 如果你想要修改配置文件,请递增version的值
|
||||
|
|
@ -191,8 +191,6 @@ max_embedding_workers = 3 # 嵌入/抽取并发线程数
|
|||
embedding_chunk_size = 4 # 每批嵌入的条数
|
||||
max_synonym_entities = 2000 # 同义边参与的实体数上限,超限则跳过
|
||||
enable_ppr = true # 是否启用PPR,低配机器可关闭
|
||||
ppr_node_cap = 8000 # 图节点数超过该值时跳过PPR
|
||||
webui_graph_default_limit = 200 # WebUI /graph 默认返回的最大节点数,避免大图负载
|
||||
|
||||
[keyword_reaction]
|
||||
keyword_rules = [
|
||||
|
|
@ -260,6 +258,22 @@ api_server_allowed_api_keys = [] # 新版API Server允许的API Key列表,为
|
|||
[telemetry] #发送统计信息,主要是看全球有多少只麦麦
|
||||
enable = true
|
||||
|
||||
[webui] # WebUI 独立服务器配置
|
||||
enabled = true # 是否启用WebUI
|
||||
mode = "production" # 模式: development(开发) 或 production(生产)
|
||||
host = "0.0.0.0" # WebUI 服务器监听地址
|
||||
port = 8001 # WebUI 服务器端口
|
||||
|
||||
# 防爬虫配置
|
||||
anti_crawler_mode = "basic" # 防爬虫模式: false(禁用) / strict(严格) / loose(宽松) / basic(基础-只记录不阻止)
|
||||
allowed_ips = "127.0.0.1" # IP白名单(逗号分隔,支持精确IP、CIDR格式和通配符)
|
||||
# 示例: 127.0.0.1,192.168.1.0/24,172.17.0.0/16
|
||||
trusted_proxies = "" # 信任的代理IP列表(逗号分隔),只有来自这些IP的X-Forwarded-For才被信任
|
||||
# 示例: 127.0.0.1,192.168.1.1,172.17.0.1
|
||||
trust_xff = false # 是否启用X-Forwarded-For代理解析(默认false)
|
||||
# 启用后,仍要求直连IP在trusted_proxies中才会信任XFF头
|
||||
secure_cookie = false # 是否启用安全Cookie(仅通过HTTPS传输,默认false)
|
||||
|
||||
[experimental] #实验性功能
|
||||
# 为指定聊天添加额外的prompt配置
|
||||
# 格式: ["platform:id:type:prompt内容", ...]
|
||||
|
|
|
|||
Loading…
Reference in New Issue