diff --git a/bot.py b/bot.py index 5e2042ff..c63a1286 100644 --- a/bot.py +++ b/bot.py @@ -41,6 +41,7 @@ logger = get_logger("main") # 定义重启退出码 RESTART_EXIT_CODE = 42 + def run_runner_process(): """ Runner 进程逻辑:作为守护进程运行,负责启动和监控 Worker 进程。 @@ -55,25 +56,25 @@ def run_runner_process(): while True: logger.info(f"正在启动 {script_file}...") - + # 启动子进程 (Worker) # 使用 sys.executable 确保使用相同的 Python 解释器 cmd = [python_executable, script_file] + sys.argv[1:] - + process = subprocess.Popen(cmd, env=env) - + try: # 等待子进程结束 return_code = process.wait() - + if return_code == RESTART_EXIT_CODE: logger.info("检测到重启请求 (退出码 42),正在重启...") - time.sleep(1) # 稍作等待 + time.sleep(1) # 稍作等待 continue else: logger.info(f"程序已退出 (退出码 {return_code})") sys.exit(return_code) - + except KeyboardInterrupt: # 向子进程发送终止信号 if process.poll() is None: @@ -87,6 +88,7 @@ def run_runner_process(): process.kill() sys.exit(0) + # 检查是否是 Worker 进程 # 如果没有设置 MAIBOT_WORKER_PROCESS 环境变量,说明是直接运行的脚本, # 此时应该作为 Runner 运行。 diff --git a/plugins/MaiBot_MCPBridgePlugin/config_converter.py b/plugins/MaiBot_MCPBridgePlugin/config_converter.py index 16f9e028..eb036991 100644 --- a/plugins/MaiBot_MCPBridgePlugin/config_converter.py +++ b/plugins/MaiBot_MCPBridgePlugin/config_converter.py @@ -19,6 +19,7 @@ from typing import Any, Dict, List, Optional, Tuple @dataclass class ConversionResult: """转换结果""" + success: bool servers: List[Dict[str, Any]] = field(default_factory=list) errors: List[str] = field(default_factory=list) @@ -53,7 +54,7 @@ class ConfigConverter: @classmethod def detect_format(cls, config: Dict[str, Any]) -> Optional[str]: """检测配置格式类型 - + Returns: "claude": Claude Desktop 格式 (mcpServers 对象) "kiro": Kiro MCP 格式 (mcpServers 对象,与 Claude 相同) @@ -82,7 +83,7 @@ class ConfigConverter: @classmethod def parse_json_safe(cls, json_str: str) -> Tuple[Optional[Any], Optional[str]]: """安全解析 JSON 字符串 - + Returns: (解析结果, 错误信息) """ @@ -102,11 +103,11 @@ class ConfigConverter: @classmethod def validate_server_config(cls, name: str, config: Dict[str, Any]) -> Tuple[bool, Optional[str], List[str]]: """验证单个服务器配置 - + Args: name: 服务器名称 config: 服务器配置字典 - + Returns: (是否有效, 错误信息, 警告列表) """ @@ -177,11 +178,11 @@ class ConfigConverter: @classmethod def convert_claude_server(cls, name: str, config: Dict[str, Any]) -> Dict[str, Any]: """将单个 Claude 格式服务器配置转换为 MaiBot 格式 - + Args: name: 服务器名称 config: Claude 格式的服务器配置 - + Returns: MaiBot 格式的服务器配置 """ @@ -231,10 +232,10 @@ class ConfigConverter: @classmethod def convert_maibot_server(cls, config: Dict[str, Any]) -> Tuple[str, Dict[str, Any]]: """将单个 MaiBot 格式服务器配置转换为 Claude 格式 - + Args: config: MaiBot 格式的服务器配置 - + Returns: (服务器名称, Claude 格式的服务器配置) """ @@ -271,17 +272,13 @@ class ConfigConverter: return name, result @classmethod - def from_claude_format( - cls, - config: Dict[str, Any], - existing_names: Optional[set] = None - ) -> ConversionResult: + def from_claude_format(cls, config: Dict[str, Any], existing_names: Optional[set] = None) -> ConversionResult: """从 Claude Desktop 格式转换为 MaiBot 格式 - + Args: config: Claude Desktop 配置 (包含 mcpServers 字段) existing_names: 已存在的服务器名称集合,用于跳过重复 - + Returns: ConversionResult """ @@ -336,10 +333,10 @@ class ConfigConverter: @classmethod def to_claude_format(cls, servers: List[Dict[str, Any]]) -> Dict[str, Any]: """将 MaiBot 格式转换为 Claude Desktop 格式 - + Args: servers: MaiBot 格式的服务器列表 - + Returns: Claude Desktop 格式的配置 """ @@ -355,19 +352,15 @@ class ConfigConverter: return {"mcpServers": mcp_servers} @classmethod - def import_from_string( - cls, - json_str: str, - existing_names: Optional[set] = None - ) -> ConversionResult: + def import_from_string(cls, json_str: str, existing_names: Optional[set] = None) -> ConversionResult: """从 JSON 字符串导入配置 - + 自动检测格式并转换为 MaiBot 格式 - + Args: json_str: JSON 字符串 existing_names: 已存在的服务器名称集合 - + Returns: ConversionResult """ @@ -422,19 +415,14 @@ class ConfigConverter: return result @classmethod - def export_to_string( - cls, - servers: List[Dict[str, Any]], - format_type: str = "claude", - pretty: bool = True - ) -> str: + def export_to_string(cls, servers: List[Dict[str, Any]], format_type: str = "claude", pretty: bool = True) -> str: """导出配置为 JSON 字符串 - + Args: servers: MaiBot 格式的服务器列表 format_type: 导出格式 ("claude", "kiro", "maibot") pretty: 是否格式化输出 - + Returns: JSON 字符串 """ diff --git a/plugins/MaiBot_MCPBridgePlugin/mcp_client.py b/plugins/MaiBot_MCPBridgePlugin/mcp_client.py index 0d4eebff..d2eed62b 100644 --- a/plugins/MaiBot_MCPBridgePlugin/mcp_client.py +++ b/plugins/MaiBot_MCPBridgePlugin/mcp_client.py @@ -34,28 +34,31 @@ from enum import Enum # 尝试导入 MaiBot 的 logger,如果失败则使用标准 logging try: from src.common.logger import get_logger + logger = get_logger("mcp_client") except ImportError: # Fallback: 使用标准 logging logger = logging.getLogger("mcp_client") if not logger.handlers: handler = logging.StreamHandler() - handler.setFormatter(logging.Formatter('[%(levelname)s] %(name)s: %(message)s')) + handler.setFormatter(logging.Formatter("[%(levelname)s] %(name)s: %(message)s")) logger.addHandler(handler) logger.setLevel(logging.INFO) class TransportType(Enum): """MCP 传输类型""" - STDIO = "stdio" # 本地进程通信 - SSE = "sse" # Server-Sent Events (旧版 HTTP) - HTTP = "http" # HTTP Streamable (新版,推荐) + + STDIO = "stdio" # 本地进程通信 + SSE = "sse" # Server-Sent Events (旧版 HTTP) + HTTP = "http" # HTTP Streamable (新版,推荐) STREAMABLE_HTTP = "streamable_http" # HTTP Streamable 的别名 @dataclass class MCPToolInfo: """MCP 工具信息""" + name: str description: str input_schema: Dict[str, Any] @@ -65,6 +68,7 @@ class MCPToolInfo: @dataclass class MCPResourceInfo: """MCP 资源信息""" + uri: str name: str description: str @@ -75,6 +79,7 @@ class MCPResourceInfo: @dataclass class MCPPromptInfo: """MCP 提示模板信息""" + name: str description: str arguments: List[Dict[str, Any]] # [{name, description, required}] @@ -84,6 +89,7 @@ class MCPPromptInfo: @dataclass class MCPServerConfig: """MCP 服务器配置""" + name: str enabled: bool = True transport: TransportType = TransportType.STDIO @@ -99,6 +105,7 @@ class MCPServerConfig: @dataclass class MCPCallResult: """MCP 工具调用结果""" + success: bool content: Any error: Optional[str] = None @@ -108,27 +115,28 @@ class MCPCallResult: class CircuitState(Enum): """断路器状态""" - CLOSED = "closed" # 正常状态,允许请求 - OPEN = "open" # 熔断状态,拒绝请求 + + CLOSED = "closed" # 正常状态,允许请求 + OPEN = "open" # 熔断状态,拒绝请求 HALF_OPEN = "half_open" # 半开状态,允许少量试探请求 @dataclass class CircuitBreaker: """v1.7.0: 断路器 - 防止对故障服务器持续请求 - + 状态转换: - CLOSED -> OPEN: 连续失败次数达到阈值 - OPEN -> HALF_OPEN: 熔断时间到期 - HALF_OPEN -> CLOSED: 试探请求成功 - HALF_OPEN -> OPEN: 试探请求失败 """ - + # 配置 - failure_threshold: int = 5 # 连续失败多少次后熔断 - recovery_timeout: float = 60.0 # 熔断后多久尝试恢复(秒) - half_open_max_calls: int = 1 # 半开状态最多允许几次试探调用 - + failure_threshold: int = 5 # 连续失败多少次后熔断 + recovery_timeout: float = 60.0 # 熔断后多久尝试恢复(秒) + half_open_max_calls: int = 1 # 半开状态最多允许几次试探调用 + # 状态 state: CircuitState = field(default=CircuitState.CLOSED) failure_count: int = 0 @@ -136,18 +144,18 @@ class CircuitBreaker: last_failure_time: float = 0.0 last_state_change: float = field(default_factory=time.time) half_open_calls: int = 0 - + def can_execute(self) -> Tuple[bool, Optional[str]]: """检查是否允许执行请求 - + Returns: (是否允许, 拒绝原因) """ current_time = time.time() - + if self.state == CircuitState.CLOSED: return True, None - + if self.state == CircuitState.OPEN: # 检查是否到了恢复时间 time_since_failure = current_time - self.last_failure_time @@ -158,20 +166,20 @@ class CircuitBreaker: else: remaining = self.recovery_timeout - time_since_failure return False, f"断路器熔断中,{remaining:.0f}秒后重试" - + if self.state == CircuitState.HALF_OPEN: # 半开状态,检查是否还有试探配额 if self.half_open_calls < self.half_open_max_calls: return True, None else: return False, "断路器半开状态,等待试探结果" - + return True, None - + def record_success(self) -> None: """记录成功调用""" self.success_count += 1 - + if self.state == CircuitState.HALF_OPEN: # 半开状态下成功,恢复到关闭状态 self._transition_to(CircuitState.CLOSED) @@ -179,12 +187,12 @@ class CircuitBreaker: elif self.state == CircuitState.CLOSED: # 正常状态下成功,重置失败计数 self.failure_count = 0 - + def record_failure(self) -> None: """记录失败调用""" self.failure_count += 1 self.last_failure_time = time.time() - + if self.state == CircuitState.HALF_OPEN: # 半开状态下失败,重新熔断 self._transition_to(CircuitState.OPEN) @@ -194,21 +202,21 @@ class CircuitBreaker: if self.failure_count >= self.failure_threshold: self._transition_to(CircuitState.OPEN) logger.warning(f"断路器熔断(连续失败 {self.failure_count} 次)") - + def _transition_to(self, new_state: CircuitState) -> None: """状态转换""" old_state = self.state self.state = new_state self.last_state_change = time.time() - + if new_state == CircuitState.CLOSED: self.failure_count = 0 self.half_open_calls = 0 elif new_state == CircuitState.HALF_OPEN: self.half_open_calls = 0 - + logger.debug(f"断路器状态: {old_state.value} -> {new_state.value}") - + def reset(self) -> None: """重置断路器""" self.state = CircuitState.CLOSED @@ -216,7 +224,7 @@ class CircuitBreaker: self.success_count = 0 self.half_open_calls = 0 self.last_state_change = time.time() - + def get_status(self) -> Dict[str, Any]: """获取断路器状态""" return { @@ -232,6 +240,7 @@ class CircuitBreaker: @dataclass class ToolCallStats: """工具调用统计""" + tool_key: str total_calls: int = 0 success_calls: int = 0 @@ -239,21 +248,21 @@ class ToolCallStats: total_duration_ms: float = 0.0 last_call_time: Optional[float] = None last_error: Optional[str] = None - + @property def success_rate(self) -> float: """成功率(0-100)""" if self.total_calls == 0: return 0.0 return (self.success_calls / self.total_calls) * 100 - + @property def avg_duration_ms(self) -> float: """平均耗时(毫秒)""" if self.success_calls == 0: return 0.0 return self.total_duration_ms / self.success_calls - + def record_call(self, success: bool, duration_ms: float, error: Optional[str] = None) -> None: """记录一次调用""" self.total_calls += 1 @@ -264,7 +273,7 @@ class ToolCallStats: else: self.failed_calls += 1 self.last_error = error - + def to_dict(self) -> Dict[str, Any]: """转换为字典""" return { @@ -282,6 +291,7 @@ class ToolCallStats: @dataclass class ServerStats: """服务器统计""" + server_name: str connect_count: int = 0 # 连接次数 disconnect_count: int = 0 # 断开次数 @@ -290,26 +300,26 @@ class ServerStats: last_disconnect_time: Optional[float] = None last_heartbeat_time: Optional[float] = None consecutive_failures: int = 0 # 连续失败次数 - + def record_connect(self) -> None: self.connect_count += 1 self.last_connect_time = time.time() self.consecutive_failures = 0 - + def record_disconnect(self) -> None: self.disconnect_count += 1 self.last_disconnect_time = time.time() - + def record_reconnect(self) -> None: self.reconnect_count += 1 self.consecutive_failures = 0 - + def record_failure(self) -> None: self.consecutive_failures += 1 - + def record_heartbeat(self) -> None: self.last_heartbeat_time = time.time() - + def to_dict(self) -> Dict[str, Any]: return { "server_name": self.server_name, @@ -325,7 +335,7 @@ class ServerStats: class MCPClientSession: """MCP 客户端会话,管理与单个 MCP 服务器的连接""" - + def __init__(self, config: MCPServerConfig, call_timeout: float = 60.0): self.config = config self.call_timeout = call_timeout @@ -338,63 +348,63 @@ class MCPClientSession: self._prompts: List[MCPPromptInfo] = [] # v1.2.0: Prompts 支持 self._connected = False self._lock = asyncio.Lock() - + # 功能支持标记(服务器可能不支持某些功能) self._supports_resources: bool = False self._supports_prompts: bool = False - + # 统计信息 self.stats = ServerStats(server_name=config.name) self._tool_stats: Dict[str, ToolCallStats] = {} - + # v1.7.0: 断路器 self._circuit_breaker = CircuitBreaker() - + @property def is_connected(self) -> bool: return self._connected - + @property def tools(self) -> List[MCPToolInfo]: return self._tools.copy() - + @property def resources(self) -> List[MCPResourceInfo]: """v1.2.0: 获取资源列表""" return self._resources.copy() - + @property def prompts(self) -> List[MCPPromptInfo]: """v1.2.0: 获取提示模板列表""" return self._prompts.copy() - + @property def supports_resources(self) -> bool: """v1.2.0: 服务器是否支持 Resources""" return self._supports_resources - + @property def supports_prompts(self) -> bool: """v1.2.0: 服务器是否支持 Prompts""" return self._supports_prompts - + @property def server_name(self) -> str: return self.config.name - + def get_tool_stats(self, tool_name: str) -> Optional[ToolCallStats]: """获取工具统计""" return self._tool_stats.get(tool_name) - + def get_circuit_breaker_status(self) -> Dict[str, Any]: """v1.7.0: 获取断路器状态""" return self._circuit_breaker.get_status() - + def reset_circuit_breaker(self) -> None: """v1.7.0: 重置断路器""" self._circuit_breaker.reset() logger.info(f"[{self.server_name}] 断路器已重置") - + def get_all_tool_stats(self) -> Dict[str, ToolCallStats]: """获取所有工具统计""" return self._tool_stats.copy() @@ -404,7 +414,7 @@ class MCPClientSession: async with self._lock: if self._connected: return True - + try: success = False if self.config.transport == TransportType.STDIO: @@ -416,7 +426,7 @@ class MCPClientSession: else: logger.error(f"[{self.server_name}] 不支持的传输类型: {self.config.transport}") return False - + if success: self.stats.record_connect() # v1.7.0: 连接成功时重置断路器 @@ -424,13 +434,13 @@ class MCPClientSession: else: self.stats.record_failure() return success - + except Exception as e: logger.error(f"[{self.server_name}] 连接失败: {e}") self._connected = False self.stats.record_failure() return False - + async def _connect_stdio(self) -> bool: """通过 stdio 连接 MCP 服务器""" try: @@ -440,31 +450,29 @@ class MCPClientSession: except ImportError: logger.error(f"[{self.server_name}] 未安装 mcp 库,请运行: pip install mcp") return False - + server_params = StdioServerParameters( - command=self.config.command, - args=self.config.args, - env=self.config.env if self.config.env else None + command=self.config.command, args=self.config.args, env=self.config.env if self.config.env else None ) - + self._stdio_context = stdio_client(server_params) self._read_stream, self._write_stream = await self._stdio_context.__aenter__() - + self._session_context = ClientSession(self._read_stream, self._write_stream) self._session = await self._session_context.__aenter__() - + await self._session.initialize() await self._fetch_tools() - + self._connected = True logger.info(f"[{self.server_name}] stdio 连接成功,发现 {len(self._tools)} 个工具") return True - + except Exception as e: logger.error(f"[{self.server_name}] stdio 连接失败: {e}") await self._cleanup() return False - + async def _connect_sse(self) -> bool: """通过 SSE 连接 MCP 服务器""" try: @@ -474,13 +482,13 @@ class MCPClientSession: except ImportError: logger.error(f"[{self.server_name}] 未安装 mcp 库,请运行: pip install mcp") return False - + if not self.config.url: logger.error(f"[{self.server_name}] SSE 传输需要配置 url") return False - + logger.debug(f"[{self.server_name}] 正在连接 SSE MCP 服务器: {self.config.url}") - + # v1.4.2: 支持 headers 鉴权 sse_kwargs = { "url": self.config.url, @@ -489,23 +497,24 @@ class MCPClientSession: } if self.config.headers: sse_kwargs["headers"] = self.config.headers - + self._sse_context = sse_client(**sse_kwargs) self._read_stream, self._write_stream = await self._sse_context.__aenter__() - + self._session_context = ClientSession(self._read_stream, self._write_stream) self._session = await self._session_context.__aenter__() - + await self._session.initialize() await self._fetch_tools() - + self._connected = True logger.info(f"[{self.server_name}] SSE 连接成功,发现 {len(self._tools)} 个工具") return True - + except Exception as e: logger.error(f"[{self.server_name}] SSE 连接失败: {e}") import traceback + logger.debug(f"[{self.server_name}] 详细错误: {traceback.format_exc()}") await self._cleanup() return False @@ -519,13 +528,13 @@ class MCPClientSession: except ImportError: logger.error(f"[{self.server_name}] 未安装 mcp 库,请运行: pip install mcp") return False - + if not self.config.url: logger.error(f"[{self.server_name}] HTTP 传输需要配置 url") return False - + logger.debug(f"[{self.server_name}] 正在连接 HTTP MCP 服务器: {self.config.url}") - + # v1.4.2: 支持 headers 鉴权 http_kwargs = { "url": self.config.url, @@ -534,23 +543,24 @@ class MCPClientSession: } if self.config.headers: http_kwargs["headers"] = self.config.headers - + self._http_context = streamablehttp_client(**http_kwargs) self._read_stream, self._write_stream, self._get_session_id = await self._http_context.__aenter__() - + self._session_context = ClientSession(self._read_stream, self._write_stream) self._session = await self._session_context.__aenter__() - + await self._session.initialize() await self._fetch_tools() - + self._connected = True logger.info(f"[{self.server_name}] HTTP 连接成功,发现 {len(self._tools)} 个工具") return True - + except Exception as e: logger.error(f"[{self.server_name}] HTTP 连接失败: {e}") import traceback + logger.debug(f"[{self.server_name}] 详细错误: {traceback.format_exc()}") await self._cleanup() return False @@ -559,59 +569,56 @@ class MCPClientSession: """获取 MCP 服务器的工具列表""" if not self._session: return - + try: result = await self._session.list_tools() self._tools = [] - + for tool in result.tools: tool_info = MCPToolInfo( name=tool.name, description=tool.description or f"MCP tool: {tool.name}", - input_schema=tool.inputSchema if hasattr(tool, 'inputSchema') else {}, - server_name=self.server_name + input_schema=tool.inputSchema if hasattr(tool, "inputSchema") else {}, + server_name=self.server_name, ) self._tools.append(tool_info) # 初始化工具统计 if tool.name not in self._tool_stats: self._tool_stats[tool.name] = ToolCallStats(tool_key=tool.name) logger.debug(f"[{self.server_name}] 发现工具: {tool.name}") - + except Exception as e: logger.error(f"[{self.server_name}] 获取工具列表失败: {e}") self._tools = [] async def fetch_resources(self) -> bool: """v1.2.0: 获取 MCP 服务器的资源列表 - + Returns: bool: 是否成功获取(服务器不支持时返回 False) """ if not self._session: return False - + try: - result = await asyncio.wait_for( - self._session.list_resources(), - timeout=self.call_timeout - ) + result = await asyncio.wait_for(self._session.list_resources(), timeout=self.call_timeout) self._resources = [] - + for resource in result.resources: resource_info = MCPResourceInfo( uri=str(resource.uri), name=resource.name or str(resource.uri), description=resource.description or "", - mime_type=resource.mimeType if hasattr(resource, 'mimeType') else None, - server_name=self.server_name + mime_type=resource.mimeType if hasattr(resource, "mimeType") else None, + server_name=self.server_name, ) self._resources.append(resource_info) logger.debug(f"[{self.server_name}] 发现资源: {resource_info.uri}") - + self._supports_resources = True logger.info(f"[{self.server_name}] 获取到 {len(self._resources)} 个资源") return True - + except Exception as e: # 服务器可能不支持 resources,这不是错误 error_str = str(e).lower() @@ -625,44 +632,43 @@ class MCPClientSession: async def fetch_prompts(self) -> bool: """v1.2.0: 获取 MCP 服务器的提示模板列表 - + Returns: bool: 是否成功获取(服务器不支持时返回 False) """ if not self._session: return False - + try: - result = await asyncio.wait_for( - self._session.list_prompts(), - timeout=self.call_timeout - ) + result = await asyncio.wait_for(self._session.list_prompts(), timeout=self.call_timeout) self._prompts = [] - + for prompt in result.prompts: # 解析参数 arguments = [] - if hasattr(prompt, 'arguments') and prompt.arguments: + if hasattr(prompt, "arguments") and prompt.arguments: for arg in prompt.arguments: - arguments.append({ - "name": arg.name, - "description": arg.description or "", - "required": arg.required if hasattr(arg, 'required') else False, - }) - + arguments.append( + { + "name": arg.name, + "description": arg.description or "", + "required": arg.required if hasattr(arg, "required") else False, + } + ) + prompt_info = MCPPromptInfo( name=prompt.name, description=prompt.description or f"MCP prompt: {prompt.name}", arguments=arguments, - server_name=self.server_name + server_name=self.server_name, ) self._prompts.append(prompt_info) logger.debug(f"[{self.server_name}] 发现提示模板: {prompt.name}") - + self._supports_prompts = True logger.info(f"[{self.server_name}] 获取到 {len(self._prompts)} 个提示模板") return True - + except Exception as e: # 服务器可能不支持 prompts,这不是错误 error_str = str(e).lower() @@ -676,45 +682,35 @@ class MCPClientSession: async def read_resource(self, uri: str) -> MCPCallResult: """v1.2.0: 读取指定资源的内容 - + Args: uri: 资源 URI - + Returns: MCPCallResult: 包含资源内容的结果 """ start_time = time.time() - + if not self._connected or not self._session: - return MCPCallResult( - success=False, - content=None, - error=f"服务器 {self.server_name} 未连接" - ) - + return MCPCallResult(success=False, content=None, error=f"服务器 {self.server_name} 未连接") + if not self._supports_resources: - return MCPCallResult( - success=False, - content=None, - error=f"服务器 {self.server_name} 不支持 Resources 功能" - ) - + return MCPCallResult(success=False, content=None, error=f"服务器 {self.server_name} 不支持 Resources 功能") + try: - result = await asyncio.wait_for( - self._session.read_resource(uri), - timeout=self.call_timeout - ) - + result = await asyncio.wait_for(self._session.read_resource(uri), timeout=self.call_timeout) + duration_ms = (time.time() - start_time) * 1000 - + # 处理返回内容 content_parts = [] for content in result.contents: - if hasattr(content, 'text'): + if hasattr(content, "text"): content_parts.append(content.text) - elif hasattr(content, 'blob'): + elif hasattr(content, "blob"): # 二进制数据,返回 base64 或提示 import base64 + blob_data = content.blob if len(blob_data) < 10000: # 小于 10KB 返回 base64 content_parts.append(f"[base64]{base64.b64encode(blob_data).decode()}") @@ -722,117 +718,85 @@ class MCPClientSession: content_parts.append(f"[二进制数据: {len(blob_data)} bytes]") else: content_parts.append(str(content)) - + return MCPCallResult( - success=True, - content="\n".join(content_parts) if content_parts else "", - duration_ms=duration_ms + success=True, content="\n".join(content_parts) if content_parts else "", duration_ms=duration_ms ) - + except asyncio.TimeoutError: duration_ms = (time.time() - start_time) * 1000 return MCPCallResult( - success=False, - content=None, - error=f"读取资源超时({self.call_timeout}秒)", - duration_ms=duration_ms + success=False, content=None, error=f"读取资源超时({self.call_timeout}秒)", duration_ms=duration_ms ) except Exception as e: duration_ms = (time.time() - start_time) * 1000 logger.error(f"[{self.server_name}] 读取资源 {uri} 失败: {e}") - return MCPCallResult( - success=False, - content=None, - error=str(e), - duration_ms=duration_ms - ) + return MCPCallResult(success=False, content=None, error=str(e), duration_ms=duration_ms) async def get_prompt(self, name: str, arguments: Optional[Dict[str, str]] = None) -> MCPCallResult: """v1.2.0: 获取提示模板的内容 - + Args: name: 提示模板名称 arguments: 模板参数 - + Returns: MCPCallResult: 包含提示内容的结果 """ start_time = time.time() - + if not self._connected or not self._session: - return MCPCallResult( - success=False, - content=None, - error=f"服务器 {self.server_name} 未连接" - ) - + return MCPCallResult(success=False, content=None, error=f"服务器 {self.server_name} 未连接") + if not self._supports_prompts: - return MCPCallResult( - success=False, - content=None, - error=f"服务器 {self.server_name} 不支持 Prompts 功能" - ) - + return MCPCallResult(success=False, content=None, error=f"服务器 {self.server_name} 不支持 Prompts 功能") + try: result = await asyncio.wait_for( - self._session.get_prompt(name, arguments=arguments or {}), - timeout=self.call_timeout + self._session.get_prompt(name, arguments=arguments or {}), timeout=self.call_timeout ) - + duration_ms = (time.time() - start_time) * 1000 - + # 处理返回的消息 messages = [] for msg in result.messages: - role = msg.role if hasattr(msg, 'role') else "unknown" + role = msg.role if hasattr(msg, "role") else "unknown" content_text = "" - if hasattr(msg, 'content'): - if hasattr(msg.content, 'text'): + if hasattr(msg, "content"): + if hasattr(msg.content, "text"): content_text = msg.content.text elif isinstance(msg.content, str): content_text = msg.content else: content_text = str(msg.content) messages.append(f"[{role}]: {content_text}") - + return MCPCallResult( - success=True, - content="\n\n".join(messages) if messages else "", - duration_ms=duration_ms + success=True, content="\n\n".join(messages) if messages else "", duration_ms=duration_ms ) - + except asyncio.TimeoutError: duration_ms = (time.time() - start_time) * 1000 return MCPCallResult( - success=False, - content=None, - error=f"获取提示模板超时({self.call_timeout}秒)", - duration_ms=duration_ms + success=False, content=None, error=f"获取提示模板超时({self.call_timeout}秒)", duration_ms=duration_ms ) except Exception as e: duration_ms = (time.time() - start_time) * 1000 logger.error(f"[{self.server_name}] 获取提示模板 {name} 失败: {e}") - return MCPCallResult( - success=False, - content=None, - error=str(e), - duration_ms=duration_ms - ) - + return MCPCallResult(success=False, content=None, error=str(e), duration_ms=duration_ms) + async def check_health(self) -> bool: """检查连接健康状态(心跳检测) - + 通过调用 list_tools 来验证连接是否正常 """ if not self._connected or not self._session: return False - + try: # 使用 list_tools 作为心跳检测 - await asyncio.wait_for( - self._session.list_tools(), - timeout=10.0 - ) + await asyncio.wait_for(self._session.list_tools(), timeout=10.0) self.stats.record_heartbeat() return True except Exception as e: @@ -841,25 +805,20 @@ class MCPClientSession: self._connected = False self.stats.record_disconnect() return False - + async def call_tool(self, tool_name: str, arguments: Dict[str, Any]) -> MCPCallResult: """调用 MCP 工具""" start_time = time.time() - + # v1.7.0: 断路器检查 can_execute, reject_reason = self._circuit_breaker.can_execute() if not can_execute: - return MCPCallResult( - success=False, - content=None, - error=f"⚡ {reject_reason}", - circuit_broken=True - ) - + return MCPCallResult(success=False, content=None, error=f"⚡ {reject_reason}", circuit_broken=True) + # 半开状态下增加试探计数 if self._circuit_breaker.state == CircuitState.HALF_OPEN: self._circuit_breaker.half_open_calls += 1 - + if not self._connected or not self._session: error_msg = f"服务器 {self.server_name} 未连接" # 记录失败 @@ -867,38 +826,37 @@ class MCPClientSession: self._tool_stats[tool_name].record_call(False, 0, error_msg) self._circuit_breaker.record_failure() return MCPCallResult(success=False, content=None, error=error_msg) - + try: result = await asyncio.wait_for( - self._session.call_tool(tool_name, arguments=arguments), - timeout=self.call_timeout + self._session.call_tool(tool_name, arguments=arguments), timeout=self.call_timeout ) - + duration_ms = (time.time() - start_time) * 1000 - + # 处理返回内容 content_parts = [] for content in result.content: - if hasattr(content, 'text'): + if hasattr(content, "text"): content_parts.append(content.text) - elif hasattr(content, 'data'): + elif hasattr(content, "data"): content_parts.append(f"[二进制数据: {len(content.data)} bytes]") else: content_parts.append(str(content)) - + # 记录成功 if tool_name in self._tool_stats: self._tool_stats[tool_name].record_call(True, duration_ms) - + # v1.7.0: 断路器记录成功 self._circuit_breaker.record_success() - + return MCPCallResult( success=True, content="\n".join(content_parts) if content_parts else "执行成功(无返回内容)", - duration_ms=duration_ms + duration_ms=duration_ms, ) - + except asyncio.TimeoutError: duration_ms = (time.time() - start_time) * 1000 error_msg = f"工具调用超时({self.call_timeout}秒)" @@ -907,7 +865,7 @@ class MCPClientSession: # v1.7.0: 断路器记录失败 self._circuit_breaker.record_failure() return MCPCallResult(success=False, content=None, error=error_msg, duration_ms=duration_ms) - + except Exception as e: duration_ms = (time.time() - start_time) * 1000 error_msg = str(e) @@ -928,7 +886,7 @@ class MCPClientSession: if self._connected: self.stats.record_disconnect() await self._cleanup() - + async def _cleanup(self) -> None: """清理资源""" self._connected = False @@ -937,31 +895,31 @@ class MCPClientSession: self._prompts = [] # v1.2.0 self._supports_resources = False # v1.2.0 self._supports_prompts = False # v1.2.0 - + try: - if hasattr(self, '_session_context') and self._session_context: + if hasattr(self, "_session_context") and self._session_context: await self._session_context.__aexit__(None, None, None) except Exception as e: logger.debug(f"[{self.server_name}] 关闭会话时出错: {e}") - + try: - if hasattr(self, '_stdio_context') and self._stdio_context: + if hasattr(self, "_stdio_context") and self._stdio_context: await self._stdio_context.__aexit__(None, None, None) except Exception as e: logger.debug(f"[{self.server_name}] 关闭 stdio 连接时出错: {e}") - + try: - if hasattr(self, '_http_context') and self._http_context: + if hasattr(self, "_http_context") and self._http_context: await self._http_context.__aexit__(None, None, None) except Exception as e: logger.debug(f"[{self.server_name}] 关闭 HTTP 连接时出错: {e}") - + try: - if hasattr(self, '_sse_context') and self._sse_context: + if hasattr(self, "_sse_context") and self._sse_context: await self._sse_context.__aexit__(None, None, None) except Exception as e: logger.debug(f"[{self.server_name}] 关闭 SSE 连接时出错: {e}") - + self._session = None self._session_context = None self._stdio_context = None @@ -969,27 +927,27 @@ class MCPClientSession: self._sse_context = None self._read_stream = None self._write_stream = None - + logger.debug(f"[{self.server_name}] 连接已关闭") class MCPClientManager: """MCP 客户端管理器,管理多个 MCP 服务器连接 - + 功能: - 管理多个 MCP 服务器连接 - 心跳检测和自动重连 - 调用统计 """ - + _instance: Optional["MCPClientManager"] = None - + def __new__(cls): if cls._instance is None: cls._instance = super().__new__(cls) cls._instance._initialized = False return cls._instance - + def __init__(self): if self._initialized: return @@ -1000,14 +958,14 @@ class MCPClientManager: self._all_prompts: Dict[str, Tuple[MCPPromptInfo, MCPClientSession]] = {} # v1.2.0 self._settings: Dict[str, Any] = {} self._lock = asyncio.Lock() - + # 心跳检测任务 self._heartbeat_task: Optional[asyncio.Task] = None self._heartbeat_running = False - + # 状态变化回调 self._on_status_change: Optional[callable] = None - + # 全局统计 self._global_stats = { "total_tool_calls": 0, @@ -1015,15 +973,15 @@ class MCPClientManager: "failed_calls": 0, "start_time": time.time(), } - + def configure(self, settings: Dict[str, Any]) -> None: """配置管理器""" self._settings = settings - + def set_status_change_callback(self, callback: callable) -> None: """设置状态变化回调函数""" self._on_status_change = callback - + def _notify_status_change(self) -> None: """通知状态变化""" if self._on_status_change: @@ -1031,27 +989,27 @@ class MCPClientManager: self._on_status_change() except Exception as e: logger.debug(f"状态变化回调出错: {e}") - + @property def all_tools(self) -> Dict[str, Tuple[MCPToolInfo, MCPClientSession]]: """获取所有已注册的工具""" return self._all_tools.copy() - + @property def all_resources(self) -> Dict[str, Tuple[MCPResourceInfo, MCPClientSession]]: """v1.2.0: 获取所有已注册的资源""" return self._all_resources.copy() - + @property def all_prompts(self) -> Dict[str, Tuple[MCPPromptInfo, MCPClientSession]]: """v1.2.0: 获取所有已注册的提示模板""" return self._all_prompts.copy() - + @property def connected_servers(self) -> List[str]: """获取已连接的服务器列表""" return [name for name, client in self._clients.items() if client.is_connected] - + @property def disconnected_servers(self) -> List[str]: """获取已断开的服务器列表""" @@ -1063,36 +1021,38 @@ class MCPClientManager: if config.name in self._clients: logger.warning(f"服务器 {config.name} 已存在") return False - + call_timeout = self._settings.get("call_timeout", 60.0) client = MCPClientSession(config, call_timeout) self._clients[config.name] = client - + if not config.enabled: logger.info(f"服务器 {config.name} 已添加但未启用") return True - + # 尝试连接 retry_attempts = self._settings.get("retry_attempts", 3) retry_interval = self._settings.get("retry_interval", 5.0) - + for attempt in range(1, retry_attempts + 1): if await client.connect(): self._register_tools(client) return True - + if attempt < retry_attempts: - logger.warning(f"服务器 {config.name} 连接失败,{retry_interval}秒后重试 ({attempt}/{retry_attempts})") + logger.warning( + f"服务器 {config.name} 连接失败,{retry_interval}秒后重试 ({attempt}/{retry_attempts})" + ) await asyncio.sleep(retry_interval) - + logger.error(f"服务器 {config.name} 连接失败,已达最大重试次数 ({retry_attempts})") # 连接失败,但保留在 _clients 中以便后续重连 return False - + def _register_tools(self, client: MCPClientSession) -> None: """注册客户端的工具""" tool_prefix = self._settings.get("tool_prefix", "mcp") - + for tool in client.tools: if tool.name.startswith(f"{tool_prefix}_{client.server_name}_"): tool_key = tool.name @@ -1100,12 +1060,12 @@ class MCPClientManager: tool_key = f"{tool_prefix}_{client.server_name}_{tool.name}" self._all_tools[tool_key] = (tool, client) logger.debug(f"注册 MCP 工具: {tool_key}") - + def _unregister_tools(self, server_name: str) -> List[str]: """注销服务器的工具,返回被注销的工具键列表""" tool_prefix = self._settings.get("tool_prefix", "mcp") prefix = f"{tool_prefix}_{server_name}_" - + keys_to_remove = [k for k in self._all_tools.keys() if k.startswith(prefix)] for key in keys_to_remove: del self._all_tools[key] @@ -1115,7 +1075,7 @@ class MCPClientManager: def _register_resources(self, client: MCPClientSession) -> None: """v1.2.0: 注册客户端的资源""" tool_prefix = self._settings.get("tool_prefix", "mcp") - + for resource in client.resources: # 资源键格式: mcp_{server}_{uri_safe_name} # 将 URI 转换为安全的键名 @@ -1123,12 +1083,12 @@ class MCPClientManager: resource_key = f"{tool_prefix}_{client.server_name}_res_{safe_uri}" self._all_resources[resource_key] = (resource, client) logger.debug(f"注册 MCP 资源: {resource_key}") - + def _unregister_resources(self, server_name: str) -> List[str]: """v1.2.0: 注销服务器的资源""" tool_prefix = self._settings.get("tool_prefix", "mcp") prefix = f"{tool_prefix}_{server_name}_res_" - + keys_to_remove = [k for k in self._all_resources.keys() if k.startswith(prefix)] for key in keys_to_remove: del self._all_resources[key] @@ -1138,56 +1098,56 @@ class MCPClientManager: def _register_prompts(self, client: MCPClientSession) -> None: """v1.2.0: 注册客户端的提示模板""" tool_prefix = self._settings.get("tool_prefix", "mcp") - + for prompt in client.prompts: prompt_key = f"{tool_prefix}_{client.server_name}_prompt_{prompt.name}" self._all_prompts[prompt_key] = (prompt, client) logger.debug(f"注册 MCP 提示模板: {prompt_key}") - + def _unregister_prompts(self, server_name: str) -> List[str]: """v1.2.0: 注销服务器的提示模板""" tool_prefix = self._settings.get("tool_prefix", "mcp") prefix = f"{tool_prefix}_{server_name}_prompt_" - + keys_to_remove = [k for k in self._all_prompts.keys() if k.startswith(prefix)] for key in keys_to_remove: del self._all_prompts[key] logger.debug(f"注销 MCP 提示模板: {key}") return keys_to_remove - + async def remove_server(self, server_name: str) -> bool: """移除 MCP 服务器""" async with self._lock: if server_name not in self._clients: return False - + client = self._clients[server_name] await client.disconnect() self._unregister_tools(server_name) self._unregister_resources(server_name) # v1.2.0 self._unregister_prompts(server_name) # v1.2.0 del self._clients[server_name] - + logger.info(f"服务器 {server_name} 已移除") return True - + async def reconnect_server(self, server_name: str) -> bool: """重新连接服务器""" if server_name not in self._clients: return False - + client = self._clients[server_name] - + async with self._lock: self._unregister_tools(server_name) self._unregister_resources(server_name) # v1.2.0 self._unregister_prompts(server_name) # v1.2.0 await client.disconnect() - + # 尝试重连 retry_attempts = self._settings.get("retry_attempts", 3) retry_interval = self._settings.get("retry_interval", 5.0) - + for attempt in range(1, retry_attempts + 1): if await client.connect(): async with self._lock: @@ -1202,46 +1162,42 @@ class MCPClientManager: client.stats.record_reconnect() logger.info(f"服务器 {server_name} 重连成功") return True - + if attempt < retry_attempts: logger.warning(f"服务器 {server_name} 重连失败,{retry_interval}秒后重试 ({attempt}/{retry_attempts})") await asyncio.sleep(retry_interval) - + logger.error(f"服务器 {server_name} 重连失败") return False async def call_tool(self, tool_key: str, arguments: Dict[str, Any]) -> MCPCallResult: """调用 MCP 工具""" if tool_key not in self._all_tools: - return MCPCallResult( - success=False, - content=None, - error=f"工具 {tool_key} 不存在" - ) - + return MCPCallResult(success=False, content=None, error=f"工具 {tool_key} 不存在") + tool_info, client = self._all_tools[tool_key] - + # 更新全局统计 self._global_stats["total_tool_calls"] += 1 - + result = await client.call_tool(tool_info.name, arguments) - + if result.success: self._global_stats["successful_calls"] += 1 else: self._global_stats["failed_calls"] += 1 - + return result async def fetch_resources_for_server(self, server_name: str) -> bool: """v1.2.0: 获取指定服务器的资源列表""" if server_name not in self._clients: return False - + client = self._clients[server_name] if not client.is_connected: return False - + success = await client.fetch_resources() if success: async with self._lock: @@ -1252,11 +1208,11 @@ class MCPClientManager: """v1.2.0: 获取指定服务器的提示模板列表""" if server_name not in self._clients: return False - + client = self._clients[server_name] if not client.is_connected: return False - + success = await client.fetch_prompts() if success: async with self._lock: @@ -1265,7 +1221,7 @@ class MCPClientManager: async def read_resource(self, uri: str, server_name: Optional[str] = None) -> MCPCallResult: """v1.2.0: 读取资源内容 - + Args: uri: 资源 URI server_name: 指定服务器名称(可选,不指定则自动查找) @@ -1273,36 +1229,29 @@ class MCPClientManager: # 如果指定了服务器 if server_name: if server_name not in self._clients: - return MCPCallResult( - success=False, - content=None, - error=f"服务器 {server_name} 不存在" - ) + return MCPCallResult(success=False, content=None, error=f"服务器 {server_name} 不存在") client = self._clients[server_name] return await client.read_resource(uri) - + # 自动查找拥有该资源的服务器 for resource_key, (resource_info, client) in self._all_resources.items(): if resource_info.uri == uri: return await client.read_resource(uri) - + # 尝试在所有支持 resources 的服务器上查找 for client in self._clients.values(): if client.is_connected and client.supports_resources: result = await client.read_resource(uri) if result.success: return result - - return MCPCallResult( - success=False, - content=None, - error=f"未找到资源: {uri}" - ) - async def get_prompt(self, name: str, arguments: Optional[Dict[str, str]] = None, - server_name: Optional[str] = None) -> MCPCallResult: + return MCPCallResult(success=False, content=None, error=f"未找到资源: {uri}") + + async def get_prompt( + self, name: str, arguments: Optional[Dict[str, str]] = None, server_name: Optional[str] = None + ) -> MCPCallResult: """v1.2.0: 获取提示模板内容 - + Args: name: 提示模板名称 arguments: 模板参数 @@ -1311,42 +1260,34 @@ class MCPClientManager: # 如果指定了服务器 if server_name: if server_name not in self._clients: - return MCPCallResult( - success=False, - content=None, - error=f"服务器 {server_name} 不存在" - ) + return MCPCallResult(success=False, content=None, error=f"服务器 {server_name} 不存在") client = self._clients[server_name] return await client.get_prompt(name, arguments) - + # 自动查找拥有该提示模板的服务器 for prompt_key, (prompt_info, client) in self._all_prompts.items(): if prompt_info.name == name: return await client.get_prompt(name, arguments) - - return MCPCallResult( - success=False, - content=None, - error=f"未找到提示模板: {name}" - ) - + + return MCPCallResult(success=False, content=None, error=f"未找到提示模板: {name}") + # ==================== 心跳检测 ==================== - + async def start_heartbeat(self) -> None: """启动心跳检测任务""" if self._heartbeat_running: logger.warning("心跳检测任务已在运行") return - + heartbeat_enabled = self._settings.get("heartbeat_enabled", True) if not heartbeat_enabled: logger.info("心跳检测已禁用") return - + self._heartbeat_running = True self._heartbeat_task = asyncio.create_task(self._heartbeat_loop()) logger.info("心跳检测任务已启动") - + async def stop_heartbeat(self) -> None: """停止心跳检测任务""" self._heartbeat_running = False @@ -1358,52 +1299,52 @@ class MCPClientManager: pass self._heartbeat_task = None logger.info("心跳检测任务已停止") - + async def _heartbeat_loop(self) -> None: """心跳检测循环(v1.5.2: 智能心跳间隔)""" base_interval = self._settings.get("heartbeat_interval", 60.0) auto_reconnect = self._settings.get("auto_reconnect", True) max_reconnect_attempts = self._settings.get("max_reconnect_attempts", 3) - + # v1.5.2: 智能心跳配置 adaptive_enabled = self._settings.get("heartbeat_adaptive", True) max_multiplier = self._settings.get("heartbeat_max_multiplier", 3.0) - + # 每个服务器独立的心跳间隔(根据稳定性动态调整) server_intervals: Dict[str, float] = {} min_interval = max(base_interval * 0.5, 30.0) # 最小间隔 max_interval = base_interval * max_multiplier # 最大间隔 - + mode_str = "智能" if adaptive_enabled else "固定" logger.info(f"心跳检测循环启动,{mode_str}模式,基准间隔: {base_interval}秒") - + while self._heartbeat_running: try: # 使用最小的服务器间隔作为循环间隔 current_interval = min(server_intervals.values()) if server_intervals else base_interval current_interval = max(current_interval, min_interval) - + await asyncio.sleep(current_interval) - + if not self._heartbeat_running: break - + current_time = time.time() - + # 检查所有已启用的服务器 for server_name, client in list(self._clients.items()): if not client.config.enabled: continue - + # 初始化服务器间隔 if server_name not in server_intervals: server_intervals[server_name] = base_interval - + # 检查是否到达该服务器的心跳时间 last_heartbeat = client.stats.last_heartbeat_time or 0 if current_time - last_heartbeat < server_intervals[server_name] * 0.9: continue # 还没到心跳时间 - + if client.is_connected: # 检查健康状态 healthy = await client.check_health() @@ -1435,71 +1376,73 @@ class MCPClientManager: # 达到最大重连次数,降低检测频率 server_intervals[server_name] = max_interval logger.debug(f"[{server_name}] 已达最大重连次数,降低检测频率") - + except asyncio.CancelledError: break except Exception as e: logger.error(f"心跳检测循环出错: {e}") await asyncio.sleep(5) - + async def _try_reconnect(self, server_name: str, max_attempts: int) -> bool: """尝试重连服务器""" client = self._clients.get(server_name) if not client: return False - + if client.stats.consecutive_failures >= max_attempts: logger.warning(f"[{server_name}] 连续失败次数已达上限 ({max_attempts}),暂停重连") return False - + logger.info(f"[{server_name}] 尝试重连 (失败次数: {client.stats.consecutive_failures}/{max_attempts})") - + success = await self.reconnect_server(server_name) if not success: client.stats.record_failure() - + self._notify_status_change() # 重连后更新状态 return success # ==================== 统计和状态 ==================== - + def get_tool_stats(self, tool_key: str) -> Optional[Dict[str, Any]]: """获取指定工具的统计信息""" if tool_key not in self._all_tools: return None - + tool_info, client = self._all_tools[tool_key] stats = client.get_tool_stats(tool_info.name) return stats.to_dict() if stats else None - + def get_all_stats(self) -> Dict[str, Any]: """获取所有统计信息""" server_stats = {} tool_stats = {} - + for server_name, client in self._clients.items(): server_stats[server_name] = client.stats.to_dict() for tool_name, stats in client.get_all_tool_stats().items(): full_key = f"{self._settings.get('tool_prefix', 'mcp')}_{server_name}_{tool_name}" tool_stats[full_key] = stats.to_dict() - + uptime = time.time() - self._global_stats["start_time"] - + return { "global": { **self._global_stats, "uptime_seconds": round(uptime, 2), - "calls_per_minute": round(self._global_stats["total_tool_calls"] / (uptime / 60), 2) if uptime > 0 else 0, + "calls_per_minute": round(self._global_stats["total_tool_calls"] / (uptime / 60), 2) + if uptime > 0 + else 0, }, "servers": server_stats, "tools": tool_stats, } - + async def shutdown(self) -> None: """关闭所有连接""" # 停止心跳检测 await self.stop_heartbeat() - + async with self._lock: for client in self._clients.values(): await client.disconnect() @@ -1508,7 +1451,7 @@ class MCPClientManager: self._all_resources.clear() # v1.2.0 self._all_prompts.clear() # v1.2.0 logger.info("MCP 客户端管理器已关闭") - + def get_status(self) -> Dict[str, Any]: """获取状态信息""" return { diff --git a/plugins/MaiBot_MCPBridgePlugin/plugin.py b/plugins/MaiBot_MCPBridgePlugin/plugin.py index aae3f4bd..4ad38d0f 100644 --- a/plugins/MaiBot_MCPBridgePlugin/plugin.py +++ b/plugins/MaiBot_MCPBridgePlugin/plugin.py @@ -84,7 +84,7 @@ from .mcp_client import ( TransportType, mcp_manager, ) -from .config_converter import ConfigConverter, ConversionResult +from .config_converter import ConfigConverter logger = get_logger("mcp_bridge_plugin") @@ -93,9 +93,11 @@ logger = get_logger("mcp_bridge_plugin") # v1.4.0: 调用链路追踪 # ============================================================================ + @dataclass class ToolCallRecord: """工具调用记录""" + call_id: str timestamp: float tool_name: str @@ -115,46 +117,46 @@ class ToolCallRecord: class ToolCallTracer: """工具调用追踪器""" - + def __init__(self, max_records: int = 100): self._records: deque[ToolCallRecord] = deque(maxlen=max_records) self._enabled: bool = True self._log_enabled: bool = False self._log_path: Optional[Path] = None - + def configure(self, enabled: bool, max_records: int, log_enabled: bool, log_path: Optional[Path] = None) -> None: """配置追踪器""" self._enabled = enabled self._records = deque(self._records, maxlen=max_records) self._log_enabled = log_enabled self._log_path = log_path - + def record(self, record: ToolCallRecord) -> None: """添加调用记录""" if not self._enabled: return - + self._records.append(record) - + if self._log_enabled and self._log_path: self._write_to_log(record) - + def get_recent(self, n: int = 10) -> List[ToolCallRecord]: """获取最近 N 条记录""" return list(self._records)[-n:] - + def get_by_tool(self, tool_name: str) -> List[ToolCallRecord]: """按工具名筛选记录""" return [r for r in self._records if r.tool_name == tool_name] - + def get_by_server(self, server_name: str) -> List[ToolCallRecord]: """按服务器名筛选记录""" return [r for r in self._records if r.server_name == server_name] - + def clear(self) -> None: """清空记录""" self._records.clear() - + def _write_to_log(self, record: ToolCallRecord) -> None: """写入 JSONL 日志文件""" try: @@ -164,7 +166,7 @@ class ToolCallTracer: f.write(json.dumps(asdict(record), ensure_ascii=False) + "\n") except Exception as e: logger.warning(f"写入追踪日志失败: {e}") - + @property def total_records(self) -> int: return len(self._records) @@ -178,9 +180,11 @@ tool_call_tracer = ToolCallTracer() # v1.4.0: 工具调用缓存 # ============================================================================ + @dataclass class CacheEntry: """缓存条目""" + tool_name: str args_hash: str result: str @@ -191,7 +195,7 @@ class CacheEntry: class ToolCallCache: """工具调用缓存(LRU)""" - + def __init__(self, max_entries: int = 200, ttl: int = 300): self._cache: OrderedDict[str, CacheEntry] = OrderedDict() self._max_entries = max_entries @@ -199,54 +203,54 @@ class ToolCallCache: self._enabled = False self._exclude_patterns: List[str] = [] self._stats = {"hits": 0, "misses": 0} - + def configure(self, enabled: bool, ttl: int, max_entries: int, exclude_tools: str) -> None: """配置缓存""" self._enabled = enabled self._ttl = ttl self._max_entries = max_entries self._exclude_patterns = [p.strip() for p in exclude_tools.strip().split("\n") if p.strip()] - + def get(self, tool_name: str, args: Dict) -> Optional[str]: """获取缓存""" if not self._enabled: return None - + if self._is_excluded(tool_name): return None - + key = self._generate_key(tool_name, args) - + if key not in self._cache: self._stats["misses"] += 1 return None - + entry = self._cache[key] - + # 检查是否过期 if time.time() > entry.expires_at: del self._cache[key] self._stats["misses"] += 1 return None - + # LRU: 移到末尾 self._cache.move_to_end(key) entry.hit_count += 1 self._stats["hits"] += 1 - + return entry.result - + def set(self, tool_name: str, args: Dict, result: str) -> None: """设置缓存""" if not self._enabled: return - + if self._is_excluded(tool_name): return - + key = self._generate_key(tool_name, args) now = time.time() - + entry = CacheEntry( tool_name=tool_name, args_hash=key, @@ -254,7 +258,7 @@ class ToolCallCache: created_at=now, expires_at=now + self._ttl, ) - + # 如果已存在,更新 if key in self._cache: self._cache[key] = entry @@ -263,25 +267,25 @@ class ToolCallCache: # 检查容量 self._evict_if_needed() self._cache[key] = entry - + def clear(self) -> None: """清空缓存""" self._cache.clear() self._stats = {"hits": 0, "misses": 0} - + def _generate_key(self, tool_name: str, args: Dict) -> str: """生成缓存键""" args_str = json.dumps(args, sort_keys=True, ensure_ascii=False) content = f"{tool_name}:{args_str}" return hashlib.md5(content.encode()).hexdigest() - + def _is_excluded(self, tool_name: str) -> bool: """检查是否在排除列表中""" for pattern in self._exclude_patterns: if fnmatch.fnmatch(tool_name, pattern): return True return False - + def _evict_if_needed(self) -> None: """必要时淘汰条目""" # 先清理过期的 @@ -289,11 +293,11 @@ class ToolCallCache: expired_keys = [k for k, v in self._cache.items() if now > v.expires_at] for k in expired_keys: del self._cache[k] - + # LRU 淘汰 while len(self._cache) >= self._max_entries: self._cache.popitem(last=False) - + def get_stats(self) -> Dict[str, Any]: """获取缓存统计""" total = self._stats["hits"] + self._stats["misses"] @@ -317,16 +321,17 @@ tool_call_cache = ToolCallCache() # v1.4.0: 工具权限控制 # ============================================================================ + class PermissionChecker: """工具权限检查器""" - + def __init__(self): self._enabled = False self._default_mode = "allow_all" # allow_all 或 deny_all self._rules: List[Dict] = [] self._quick_deny_groups: set = set() self._quick_allow_users: set = set() - + def configure( self, enabled: bool, @@ -338,61 +343,61 @@ class PermissionChecker: """配置权限检查器""" self._enabled = enabled self._default_mode = default_mode if default_mode in ("allow_all", "deny_all") else "allow_all" - + # 解析快捷配置 self._quick_deny_groups = {g.strip() for g in quick_deny_groups.strip().split("\n") if g.strip()} self._quick_allow_users = {u.strip() for u in quick_allow_users.strip().split("\n") if u.strip()} - + try: self._rules = json.loads(rules_json) if rules_json.strip() else [] except json.JSONDecodeError as e: logger.warning(f"权限规则 JSON 解析失败: {e}") self._rules = [] - + def check(self, tool_name: str, chat_id: str, user_id: str, is_group: bool) -> bool: """检查权限 - + Args: tool_name: 工具名称 chat_id: 聊天 ID(群号或私聊 ID) user_id: 用户 ID is_group: 是否为群聊 - + Returns: True 表示允许,False 表示拒绝 """ if not self._enabled: return True - + # 快捷配置优先级最高 # 1. 管理员白名单(始终允许) if user_id and user_id in self._quick_allow_users: return True - + # 2. 禁用群列表(始终拒绝) if is_group and chat_id and chat_id in self._quick_deny_groups: return False - + # 查找匹配的规则 for rule in self._rules: tool_pattern = rule.get("tool", "") if not self._match_tool(tool_pattern, tool_name): continue - + # 找到匹配的规则 mode = rule.get("mode", "") allowed = rule.get("allowed", []) denied = rule.get("denied", []) - + # 构建当前上下文的 ID 列表 context_ids = self._build_context_ids(chat_id, user_id, is_group) - + # 检查 denied 列表(优先级最高) if denied: for ctx_id in context_ids: if self._match_id_list(denied, ctx_id): return False - + # 检查 allowed 列表 if allowed: for ctx_id in context_ids: @@ -401,41 +406,41 @@ class PermissionChecker: # 如果是 whitelist 模式且不在 allowed 中,拒绝 if mode == "whitelist": return False - + # 规则匹配但没有明确允许/拒绝,继续检查下一条规则 - + # 没有匹配的规则,使用默认模式 return self._default_mode == "allow_all" - + def _match_tool(self, pattern: str, tool_name: str) -> bool: """工具名通配符匹配""" if not pattern: return False return fnmatch.fnmatch(tool_name, pattern) - + def _build_context_ids(self, chat_id: str, user_id: str, is_group: bool) -> List[str]: """构建上下文 ID 列表""" ids = [] - + # 用户级别(任何场景生效) if user_id: ids.append(f"qq:{user_id}:user") - + # 场景级别 if is_group and chat_id: ids.append(f"qq:{chat_id}:group") elif chat_id: ids.append(f"qq:{chat_id}:private") - + return ids - + def _match_id_list(self, id_list: List[str], context_id: str) -> bool: """检查 ID 是否在列表中""" for rule_id in id_list: if fnmatch.fnmatch(context_id, rule_id): return True return False - + def get_rules_for_tool(self, tool_name: str) -> List[Dict]: """获取特定工具的权限规则""" return [r for r in self._rules if self._match_tool(r.get("tool", ""), tool_name)] @@ -449,6 +454,7 @@ permission_checker = PermissionChecker() # 工具类型转换 # ============================================================================ + def convert_json_type_to_tool_param_type(json_type: str) -> ToolParamType: """将 JSON Schema 类型转换为 MaiBot 的 ToolParamType""" type_mapping = { @@ -462,34 +468,36 @@ def convert_json_type_to_tool_param_type(json_type: str) -> ToolParamType: return type_mapping.get(json_type, ToolParamType.STRING) -def parse_mcp_parameters(input_schema: Dict[str, Any]) -> List[Tuple[str, ToolParamType, str, bool, Optional[List[str]]]]: +def parse_mcp_parameters( + input_schema: Dict[str, Any], +) -> List[Tuple[str, ToolParamType, str, bool, Optional[List[str]]]]: """解析 MCP 工具的参数 schema,转换为 MaiBot 的参数格式""" parameters = [] - + if not input_schema: return parameters - + properties = input_schema.get("properties", {}) required = input_schema.get("required", []) - + for param_name, param_info in properties.items(): json_type = param_info.get("type", "string") param_type = convert_json_type_to_tool_param_type(json_type) description = param_info.get("description", f"参数 {param_name}") - + if json_type == "array": description = f"{description} (JSON 数组格式)" elif json_type == "object": description = f"{description} (JSON 对象格式)" - + is_required = param_name in required enum_values = param_info.get("enum") - + if enum_values is not None: enum_values = [str(v) for v in enum_values] - + parameters.append((param_name, param_type, description, is_required, enum_values)) - + return parameters @@ -497,28 +505,29 @@ def parse_mcp_parameters(input_schema: Dict[str, Any]) -> List[Tuple[str, ToolPa # MCP 工具代理 # ============================================================================ + class MCPToolProxy(BaseTool): """MCP 工具代理基类""" - + name: str = "" description: str = "" parameters: List[Tuple[str, ToolParamType, str, bool, Optional[List[str]]]] = [] available_for_llm: bool = True - + _mcp_tool_key: str = "" _mcp_original_name: str = "" _mcp_server_name: str = "" - + async def execute(self, function_args: Dict[str, Any]) -> Dict[str, Any]: """执行 MCP 工具调用""" global _plugin_instance - + call_id = str(uuid.uuid4())[:8] start_time = time.time() - + # 移除 MaiBot 内部标记 args = {k: v for k, v in function_args.items() if k != "llm_called"} - + # 解析 JSON 字符串参数 parsed_args = {} for key, value in args.items(): @@ -532,24 +541,21 @@ class MCPToolProxy(BaseTool): parsed_args[key] = value else: parsed_args[key] = value - + # 获取上下文信息 chat_id, user_id, is_group, user_query = self._get_context_info() - + # v1.4.0: 权限检查 if not permission_checker.check(self.name, chat_id, user_id, is_group): logger.warning(f"权限拒绝: 工具 {self.name}, chat={chat_id}, user={user_id}") - return { - "name": self.name, - "content": f"⛔ 权限不足:工具 {self.name} 在当前场景下不可用" - } - + return {"name": self.name, "content": f"⛔ 权限不足:工具 {self.name} 在当前场景下不可用"} + logger.debug(f"调用 MCP 工具: {self._mcp_tool_key}, 参数: {parsed_args}") - + # v1.4.0: 检查缓存 cache_hit = False cached_result = tool_call_cache.get(self.name, parsed_args) - + if cached_result is not None: cache_hit = True content = cached_result @@ -560,13 +566,13 @@ class MCPToolProxy(BaseTool): else: # 调用 MCP result = await mcp_manager.call_tool(self._mcp_tool_key, parsed_args) - + if result.success: content = result.content raw_result = content success = True error = "" - + # 存入缓存 tool_call_cache.set(self.name, parsed_args, content) else: @@ -575,7 +581,7 @@ class MCPToolProxy(BaseTool): success = False error = result.error logger.warning(f"MCP 工具 {self.name} 调用失败: {result.error}") - + # v1.3.0: 后处理 post_processed = False processed_result = content @@ -585,9 +591,9 @@ class MCPToolProxy(BaseTool): post_processed = True processed_result = processed_content content = processed_content - + duration_ms = (time.time() - start_time) * 1000 - + # v1.4.0: 记录调用追踪 record = ToolCallRecord( call_id=call_id, @@ -607,16 +613,16 @@ class MCPToolProxy(BaseTool): cache_hit=cache_hit, ) tool_call_tracer.record(record) - + return {"name": self.name, "content": content} - + def _get_context_info(self) -> Tuple[str, str, bool, str]: """获取上下文信息""" chat_id = "" user_id = "" is_group = False user_query = "" - + if self.chat_stream and hasattr(self.chat_stream, "context") and self.chat_stream.context: try: ctx = self.chat_stream.context @@ -626,53 +632,53 @@ class MCPToolProxy(BaseTool): user_id = str(ctx.user_id) if ctx.user_id else "" if hasattr(ctx, "is_group"): is_group = bool(ctx.is_group) - + last_message = ctx.get_last_message() if last_message and hasattr(last_message, "processed_plain_text"): user_query = last_message.processed_plain_text or "" except Exception as e: logger.debug(f"获取上下文信息失败: {e}") - + return chat_id, user_id, is_group, user_query async def _post_process_result(self, content: str) -> str: """v1.3.0: 对工具返回结果进行后处理(摘要提炼)""" global _plugin_instance - + if _plugin_instance is None: return content - + settings = _plugin_instance.config.get("settings", {}) - + if not settings.get("post_process_enabled", False): return content - + server_post_config = self._get_server_post_process_config() - + if server_post_config is not None: if not server_post_config.get("enabled", True): return content - + threshold = settings.get("post_process_threshold", 500) if server_post_config and "threshold" in server_post_config: threshold = server_post_config["threshold"] - + content_length = len(content) if content else 0 if content_length <= threshold: return content - + user_query = self._get_context_info()[3] if not user_query: return content - + max_tokens = settings.get("post_process_max_tokens", 500) if server_post_config and "max_tokens" in server_post_config: max_tokens = server_post_config["max_tokens"] - + prompt_template = settings.get("post_process_prompt", "") if server_post_config and "prompt" in server_post_config: prompt_template = server_post_config["prompt"] - + if not prompt_template: prompt_template = """用户问题:{query} @@ -680,13 +686,13 @@ class MCPToolProxy(BaseTool): {result} 请从上述内容中提取与用户问题最相关的关键信息,简洁准确地输出:""" - + try: prompt = prompt_template.format(query=user_query, result=content) except KeyError as e: logger.warning(f"后处理 prompt 模板格式错误: {e}") return content - + try: processed_content = await self._call_post_process_llm(prompt, max_tokens, settings, server_post_config) if processed_content: @@ -696,14 +702,14 @@ class MCPToolProxy(BaseTool): except Exception as e: logger.error(f"MCP 工具 {self.name} 后处理失败: {e}") return content - + def _get_server_post_process_config(self) -> Optional[Dict[str, Any]]: """获取当前服务器的后处理配置""" global _plugin_instance - + if _plugin_instance is None: return None - + servers_section = _plugin_instance.config.get("servers", {}) if isinstance(servers_section, dict): servers_list = servers_section.get("list", "[]") @@ -718,29 +724,25 @@ class MCPToolProxy(BaseTool): return None else: servers = servers_section if isinstance(servers_section, list) else [] - + for server_conf in servers: if server_conf.get("name") == self._mcp_server_name: return server_conf.get("post_process") - + return None - + async def _call_post_process_llm( - self, - prompt: str, - max_tokens: int, - settings: Dict[str, Any], - server_config: Optional[Dict[str, Any]] + self, prompt: str, max_tokens: int, settings: Dict[str, Any], server_config: Optional[Dict[str, Any]] ) -> Optional[str]: """调用 LLM 进行后处理""" from src.config.config import model_config from src.config.api_ada_configs import TaskConfig from src.llm_models.utils_model import LLMRequest - + model_name = settings.get("post_process_model", "") if server_config and "model" in server_config: model_name = server_config["model"] - + if model_name: task_config = TaskConfig( model_list=[model_name], @@ -750,59 +752,56 @@ class MCPToolProxy(BaseTool): ) else: task_config = model_config.model_task_config.utils - + llm_request = LLMRequest(model_set=task_config, request_type="mcp_post_process") - + response, (reasoning, model_used, _) = await llm_request.generate_response_async( prompt=prompt, max_tokens=max_tokens, temperature=0.3, ) - + return response.strip() if response else None - + def _format_error_message(self, error: str, duration_ms: float) -> str: """格式化友好的错误消息""" if not error: return "工具调用失败(未知错误)" - + error_lower = error.lower() - + if "未连接" in error or "not connected" in error_lower: return f"⚠️ MCP 服务器 [{self._mcp_server_name}] 未连接,请检查服务器状态或等待自动重连" - + if "超时" in error or "timeout" in error_lower: return f"⏱️ 工具调用超时(耗时 {duration_ms:.0f}ms),服务器响应过慢,请稍后重试" - + if "connection" in error_lower and ("closed" in error_lower or "reset" in error_lower): return f"🔌 与 MCP 服务器 [{self._mcp_server_name}] 的连接已断开,正在尝试重连..." - + if "invalid" in error_lower and "argument" in error_lower: return f"❌ 参数错误: {error}" - + return f"❌ 工具调用失败: {error}" - + async def direct_execute(self, **function_args) -> Dict[str, Any]: """直接执行(供其他插件调用)""" return await self.execute(function_args) def create_mcp_tool_class( - tool_key: str, - tool_info: MCPToolInfo, - tool_prefix: str, - disabled: bool = False + tool_key: str, tool_info: MCPToolInfo, tool_prefix: str, disabled: bool = False ) -> Type[MCPToolProxy]: """根据 MCP 工具信息动态创建 BaseTool 子类""" parameters = parse_mcp_parameters(tool_info.input_schema) - + class_name = f"MCPTool_{tool_info.server_name}_{tool_info.name}".replace("-", "_").replace(".", "_") tool_name = tool_key.replace("-", "_").replace(".", "_") - + description = tool_info.description if not description.endswith(f"[来自 MCP 服务器: {tool_info.server_name}]"): description = f"{description} [来自 MCP 服务器: {tool_info.server_name}]" - + tool_class = type( class_name, (MCPToolProxy,), @@ -814,31 +813,27 @@ def create_mcp_tool_class( "_mcp_tool_key": tool_key, "_mcp_original_name": tool_info.name, "_mcp_server_name": tool_info.server_name, - } + }, ) - + return tool_class class MCPToolRegistry: """MCP 工具注册表""" - + def __init__(self): self._tool_classes: Dict[str, Type[MCPToolProxy]] = {} self._tool_infos: Dict[str, ToolInfo] = {} - + def register_tool( - self, - tool_key: str, - tool_info: MCPToolInfo, - tool_prefix: str, - disabled: bool = False + self, tool_key: str, tool_info: MCPToolInfo, tool_prefix: str, disabled: bool = False ) -> Tuple[ToolInfo, Type[MCPToolProxy]]: """注册 MCP 工具""" tool_class = create_mcp_tool_class(tool_key, tool_info, tool_prefix, disabled) - + self._tool_classes[tool_key] = tool_class - + info = ToolInfo( name=tool_class.name, tool_description=tool_class.description, @@ -847,9 +842,9 @@ class MCPToolRegistry: component_type=ComponentType.TOOL, ) self._tool_infos[tool_key] = info - + return info, tool_class - + def unregister_tool(self, tool_key: str) -> bool: """注销工具""" if tool_key in self._tool_classes: @@ -857,11 +852,11 @@ class MCPToolRegistry: del self._tool_infos[tool_key] return True return False - + def get_all_components(self) -> List[Tuple[ComponentInfo, Type]]: """获取所有工具组件""" return [(self._tool_infos[key], self._tool_classes[key]) for key in self._tool_classes.keys()] - + def clear(self) -> None: """清空所有注册""" self._tool_classes.clear() @@ -879,9 +874,10 @@ _plugin_instance: Optional["MCPBridgePlugin"] = None # 内置工具 # ============================================================================ + class MCPReadResourceTool(BaseTool): """v1.2.0: MCP 资源读取工具""" - + name = "mcp_read_resource" description = "读取 MCP 服务器提供的资源内容(如文件、数据库记录等)。使用前请先用 mcp_status 查看可用资源。" parameters = [ @@ -889,28 +885,28 @@ class MCPReadResourceTool(BaseTool): ("server_name", ToolParamType.STRING, "指定服务器名称(可选,不指定则自动查找)", False, None), ] available_for_llm = True - + async def execute(self, function_args: Dict[str, Any]) -> Dict[str, Any]: uri = function_args.get("uri", "") server_name = function_args.get("server_name") - + if not uri: return {"name": self.name, "content": "❌ 请提供资源 URI"} - + result = await mcp_manager.read_resource(uri, server_name) - + if result.success: return {"name": self.name, "content": result.content} else: return {"name": self.name, "content": f"❌ 读取资源失败: {result.error}"} - + async def direct_execute(self, **function_args) -> Dict[str, Any]: return await self.execute(function_args) class MCPGetPromptTool(BaseTool): """v1.2.0: MCP 提示模板工具""" - + name = "mcp_get_prompt" description = "获取 MCP 服务器提供的提示模板内容。使用前请先用 mcp_status 查看可用模板。" parameters = [ @@ -919,78 +915,83 @@ class MCPGetPromptTool(BaseTool): ("server_name", ToolParamType.STRING, "指定服务器名称(可选)", False, None), ] available_for_llm = True - + async def execute(self, function_args: Dict[str, Any]) -> Dict[str, Any]: prompt_name = function_args.get("name", "") arguments_str = function_args.get("arguments", "") server_name = function_args.get("server_name") - + if not prompt_name: return {"name": self.name, "content": "❌ 请提供提示模板名称"} - + arguments = None if arguments_str: try: arguments = json.loads(arguments_str) except json.JSONDecodeError: return {"name": self.name, "content": "❌ 参数格式错误,请使用 JSON 对象格式"} - + result = await mcp_manager.get_prompt(prompt_name, arguments, server_name) - + if result.success: return {"name": self.name, "content": result.content} else: return {"name": self.name, "content": f"❌ 获取提示模板失败: {result.error}"} - + async def direct_execute(self, **function_args) -> Dict[str, Any]: return await self.execute(function_args) class MCPStatusTool(BaseTool): """MCP 状态查询工具""" - + name = "mcp_status" - description = "查询 MCP 桥接插件的状态,包括服务器连接状态、可用工具列表、资源列表、提示模板列表、调用统计、追踪记录等信息" + description = ( + "查询 MCP 桥接插件的状态,包括服务器连接状态、可用工具列表、资源列表、提示模板列表、调用统计、追踪记录等信息" + ) parameters = [ - ("query_type", ToolParamType.STRING, "查询类型", False, ["status", "tools", "resources", "prompts", "stats", "trace", "cache", "all"]), + ( + "query_type", + ToolParamType.STRING, + "查询类型", + False, + ["status", "tools", "resources", "prompts", "stats", "trace", "cache", "all"], + ), ("server_name", ToolParamType.STRING, "指定服务器名称(可选)", False, None), ] available_for_llm = True - + async def execute(self, function_args: Dict[str, Any]) -> Dict[str, Any]: query_type = function_args.get("query_type", "status") server_name = function_args.get("server_name") - + result_parts = [] - + if query_type in ("status", "all"): result_parts.append(self._format_status(server_name)) - + if query_type in ("tools", "all"): result_parts.append(self._format_tools(server_name)) - + if query_type in ("resources", "all"): result_parts.append(self._format_resources(server_name)) - + if query_type in ("prompts", "all"): result_parts.append(self._format_prompts(server_name)) - + if query_type in ("stats", "all"): result_parts.append(self._format_stats(server_name)) - + # v1.4.0: 追踪记录 if query_type in ("trace",): result_parts.append(self._format_trace()) - + # v1.4.0: 缓存状态 if query_type in ("cache",): result_parts.append(self._format_cache()) - - return { - "name": self.name, - "content": "\n\n".join(result_parts) if result_parts else "未知的查询类型" - } - + + return {"name": self.name, "content": "\n\n".join(result_parts) if result_parts else "未知的查询类型"} + def _format_status(self, server_name: Optional[str] = None) -> str: status = mcp_manager.get_status() lines = ["📊 MCP 桥接插件状态"] @@ -999,24 +1000,24 @@ class MCPStatusTool(BaseTool): lines.append(f" 已断开: {status['disconnected_servers']}") lines.append(f" 可用工具数: {status['total_tools']}") lines.append(f" 心跳检测: {'运行中' if status['heartbeat_running'] else '已停止'}") - + lines.append("\n🔌 服务器详情:") - for name, info in status['servers'].items(): + for name, info in status["servers"].items(): if server_name and name != server_name: continue - status_icon = "✅" if info['connected'] else "❌" - enabled_text = "" if info['enabled'] else " (已禁用)" + status_icon = "✅" if info["connected"] else "❌" + enabled_text = "" if info["enabled"] else " (已禁用)" lines.append(f" {status_icon} {name}{enabled_text}") lines.append(f" 传输: {info['transport']}, 工具数: {info['tools_count']}") - if info['consecutive_failures'] > 0: + if info["consecutive_failures"] > 0: lines.append(f" ⚠️ 连续失败: {info['consecutive_failures']} 次") - + return "\n".join(lines) - + def _format_tools(self, server_name: Optional[str] = None) -> str: tools = mcp_manager.all_tools lines = ["🔧 可用 MCP 工具"] - + by_server: Dict[str, List[str]] = {} for tool_key, (tool_info, _) in tools.items(): if server_name and tool_info.server_name != server_name: @@ -1024,35 +1025,35 @@ class MCPStatusTool(BaseTool): if tool_info.server_name not in by_server: by_server[tool_info.server_name] = [] by_server[tool_info.server_name].append(f" • {tool_key}: {tool_info.description[:50]}...") - + for srv_name, tool_list in by_server.items(): lines.append(f"\n📦 {srv_name} ({len(tool_list)} 个工具):") lines.extend(tool_list) - + if not by_server: lines.append(" (无可用工具)") - + return "\n".join(lines) - + def _format_stats(self, server_name: Optional[str] = None) -> str: stats = mcp_manager.get_all_stats() lines = ["📈 调用统计"] - - g = stats['global'] + + g = stats["global"] lines.append(f" 总调用次数: {g['total_tool_calls']}") lines.append(f" 成功: {g['successful_calls']}, 失败: {g['failed_calls']}") - if g['total_tool_calls'] > 0: - success_rate = (g['successful_calls'] / g['total_tool_calls']) * 100 + if g["total_tool_calls"] > 0: + success_rate = (g["successful_calls"] / g["total_tool_calls"]) * 100 lines.append(f" 成功率: {success_rate:.1f}%") lines.append(f" 运行时间: {g['uptime_seconds']:.0f} 秒") - + return "\n".join(lines) - + def _format_resources(self, server_name: Optional[str] = None) -> str: resources = mcp_manager.all_resources if not resources: return "📦 当前没有可用的 MCP 资源" - + lines = ["📦 可用 MCP 资源"] by_server: Dict[str, List[MCPResourceInfo]] = {} for key, (resource_info, _) in resources.items(): @@ -1061,19 +1062,19 @@ class MCPStatusTool(BaseTool): if resource_info.server_name not in by_server: by_server[resource_info.server_name] = [] by_server[resource_info.server_name].append(resource_info) - + for srv_name, resource_list in by_server.items(): lines.append(f"\n🔌 {srv_name} ({len(resource_list)} 个资源):") for res in resource_list: lines.append(f" • {res.name}: {res.uri}") - + return "\n".join(lines) - + def _format_prompts(self, server_name: Optional[str] = None) -> str: prompts = mcp_manager.all_prompts if not prompts: return "📝 当前没有可用的 MCP 提示模板" - + lines = ["📝 可用 MCP 提示模板"] by_server: Dict[str, List[MCPPromptInfo]] = {} for key, (prompt_info, _) in prompts.items(): @@ -1082,20 +1083,20 @@ class MCPStatusTool(BaseTool): if prompt_info.server_name not in by_server: by_server[prompt_info.server_name] = [] by_server[prompt_info.server_name].append(prompt_info) - + for srv_name, prompt_list in by_server.items(): lines.append(f"\n🔌 {srv_name} ({len(prompt_list)} 个模板):") for prompt in prompt_list: lines.append(f" • {prompt.name}") - + return "\n".join(lines) - + def _format_trace(self) -> str: """v1.4.0: 格式化追踪记录""" records = tool_call_tracer.get_recent(10) if not records: return "🔍 暂无调用追踪记录" - + lines = ["🔍 最近调用追踪记录"] for r in reversed(records): status = "✅" if r.success else "❌" @@ -1104,9 +1105,9 @@ class MCPStatusTool(BaseTool): lines.append(f" {status}{cache}{post} {r.tool_name} ({r.duration_ms:.0f}ms)") if r.error: lines.append(f" 错误: {r.error[:50]}") - + return "\n".join(lines) - + def _format_cache(self) -> str: """v1.4.0: 格式化缓存状态""" stats = tool_call_cache.get_stats() @@ -1117,7 +1118,7 @@ class MCPStatusTool(BaseTool): lines.append(f" 命中: {stats['hits']}, 未命中: {stats['misses']}") lines.append(f" 命中率: {stats['hit_rate']}") return "\n".join(lines) - + async def direct_execute(self, **function_args) -> Dict[str, Any]: return await self.execute(function_args) @@ -1126,6 +1127,7 @@ class MCPStatusTool(BaseTool): # 命令处理 # ============================================================================ + class MCPStatusCommand(BaseCommand): """MCP 状态查询命令 - 通过 /mcp 命令查看服务器状态""" @@ -1140,23 +1142,23 @@ class MCPStatusCommand(BaseCommand): if subcommand == "reconnect": return await self._handle_reconnect(arg) - + # v1.4.0: 追踪命令 if subcommand == "trace": return await self._handle_trace(arg) - + # v1.4.0: 缓存命令 if subcommand == "cache": return await self._handle_cache(arg) - + # v1.4.0: 权限命令 if subcommand == "perm": return await self._handle_perm(arg) - + # v1.6.0: 导出命令 if subcommand == "export": return await self._handle_export(arg) - + # v1.7.0: 工具搜索命令 if subcommand == "search": return await self._handle_search(arg) @@ -1169,7 +1171,7 @@ class MCPStatusCommand(BaseCommand): """查找相似的服务器名称""" name_lower = name.lower() all_servers = list(mcp_manager._clients.keys()) - + # 简单的相似度匹配:包含关系或前缀匹配 similar = [] for srv in all_servers: @@ -1178,7 +1180,7 @@ class MCPStatusCommand(BaseCommand): similar.append(srv) elif srv_lower.startswith(name_lower[:3]) if len(name_lower) >= 3 else False: similar.append(srv) - + return similar[:max_results] async def _handle_reconnect(self, server_name: Optional[str] = None) -> Tuple[bool, Optional[str], bool]: @@ -1212,7 +1214,7 @@ class MCPStatusCommand(BaseCommand): await self.send_text(f"{status} {srv}") return (True, None, True) - + async def _handle_trace(self, arg: Optional[str] = None) -> Tuple[bool, Optional[str], bool]: """v1.4.0: 处理追踪命令""" if arg and arg.isdigit(): @@ -1225,11 +1227,11 @@ class MCPStatusCommand(BaseCommand): else: # /mcp trace - 最近 10 条 records = tool_call_tracer.get_recent(10) - + if not records: await self.send_text("🔍 暂无调用追踪记录\n\n用法: /mcp trace [数量|工具名]") return (True, None, True) - + lines = [f"🔍 调用追踪记录 ({len(records)} 条)"] lines.append("-" * 30) for i, r in enumerate(reversed(records)): @@ -1243,17 +1245,17 @@ class MCPStatusCommand(BaseCommand): lines.append(f" 错误: {r.error[:50]}") if i < len(records) - 1: lines.append("") - + await self.send_text("\n".join(lines)) return (True, None, True) - + async def _handle_cache(self, arg: Optional[str] = None) -> Tuple[bool, Optional[str], bool]: """v1.4.0: 处理缓存命令""" if arg == "clear": tool_call_cache.clear() await self.send_text("✅ 缓存已清空") return (True, None, True) - + stats = tool_call_cache.get_stats() lines = ["🗄️ 缓存状态"] lines.append(f"├ 启用: {'是' if stats['enabled'] else '否'}") @@ -1262,22 +1264,22 @@ class MCPStatusCommand(BaseCommand): lines.append(f"├ 命中: {stats['hits']}") lines.append(f"├ 未命中: {stats['misses']}") lines.append(f"└ 命中率: {stats['hit_rate']}") - + await self.send_text("\n".join(lines)) return (True, None, True) - + async def _handle_perm(self, arg: Optional[str] = None) -> Tuple[bool, Optional[str], bool]: """v1.4.0: 处理权限命令""" global _plugin_instance - + if _plugin_instance is None: await self.send_text("❌ 插件未初始化") return (True, None, True) - + perm_config = _plugin_instance.config.get("permissions", {}) enabled = perm_config.get("perm_enabled", False) default_mode = perm_config.get("perm_default_mode", "allow_all") - + if arg: # 查看特定工具的权限 rules = permission_checker.get_rules_for_tool(arg) @@ -1306,50 +1308,52 @@ class MCPStatusCommand(BaseCommand): lines.append(f"├ 管理员白名单: {allow_count} 人") lines.append(f"└ 高级规则: {len(permission_checker._rules)} 条") await self.send_text("\n".join(lines)) - + return (True, None, True) - + async def _handle_export(self, format_type: Optional[str] = None) -> Tuple[bool, Optional[str], bool]: """v1.6.0: 处理导出命令""" global _plugin_instance - + if _plugin_instance is None: await self.send_text("❌ 插件未初始化") return (True, None, True) - + # 获取当前服务器列表 servers_section = _plugin_instance.config.get("servers", {}) servers_list_str = servers_section.get("list", "[]") if isinstance(servers_section, dict) else "[]" - + try: servers = json.loads(servers_list_str) if servers_list_str.strip() else [] except json.JSONDecodeError: await self.send_text("❌ 当前服务器配置格式错误,无法导出") return (True, None, True) - + if not servers: await self.send_text("📤 当前没有配置任何服务器") return (True, None, True) - + # 确定导出格式 format_type = (format_type or "claude").lower() if format_type not in ("claude", "kiro", "maibot"): format_type = "claude" - + # 导出 try: exported = ConfigConverter.export_to_string(servers, format_type, pretty=True) - - format_name = {"claude": "Claude Desktop", "kiro": "Kiro MCP", "maibot": "MaiBot"}.get(format_type, format_type) + + format_name = {"claude": "Claude Desktop", "kiro": "Kiro MCP", "maibot": "MaiBot"}.get( + format_type, format_type + ) lines = [f"📤 导出为 {format_name} 格式 ({len(servers)} 个服务器):"] lines.append("") lines.append(exported) - + await self.send_text("\n".join(lines)) except Exception as e: logger.error(f"导出配置失败: {e}") await self.send_text(f"❌ 导出失败: {str(e)}") - + return (True, None, True) async def _handle_search(self, query: Optional[str] = None) -> Tuple[bool, Optional[str], bool]: @@ -1406,11 +1410,11 @@ class MCPStatusCommand(BaseCommand): for srv_name, tool_list in by_server.items(): lines.append(f"\n📦 {srv_name} ({len(tool_list)} 个):") - + # 单服务器或结果少于 15 个时显示全部 show_all = single_server or len(matched) <= 15 display_limit = len(tool_list) if show_all else 5 - + for tool_key, tool_info in tool_list[:display_limit]: desc = tool_info.description[:40] + "..." if len(tool_info.description) > 40 else tool_info.description lines.append(f" • {tool_key}") @@ -1446,9 +1450,9 @@ class MCPStatusCommand(BaseCommand): cb = info.get("circuit_breaker", {}) cb_state = cb.get("state", "closed") if cb_state == "open": - lines.append(f" ⚡ 断路器熔断中") + lines.append(" ⚡ 断路器熔断中") elif cb_state == "half_open": - lines.append(f" ⚡ 断路器试探中") + lines.append(" ⚡ 断路器试探中") if info["consecutive_failures"] > 0: lines.append(f" ⚠️ 连续失败 {info['consecutive_failures']} 次") @@ -1464,7 +1468,7 @@ class MCPStatusCommand(BaseCommand): # 如果指定了服务器名,显示全部工具;否则折叠显示 show_all = server_name is not None - + for srv, tool_list in by_server.items(): lines.append(f" 📦 {srv} ({len(tool_list)})") if show_all: @@ -1527,13 +1531,13 @@ class MCPImportCommand(BaseCommand): async def execute(self) -> Tuple[bool, Optional[str], bool]: """执行导入命令""" global _plugin_instance - + if _plugin_instance is None: await self.send_text("❌ 插件未初始化") return (True, None, True) - + content = self.matched_groups.get("content", "") - + if not content or not content.strip(): # 显示使用帮助 help_text = """📥 MCP 配置导入 @@ -1551,31 +1555,31 @@ class MCPImportCommand(BaseCommand): /mcp import {"mcpServers":{"api":{"url":"https://example.com/mcp","transport":"sse"}}}""" await self.send_text(help_text) return (True, None, True) - + # 获取现有服务器名称 servers_section = _plugin_instance.config.get("servers", {}) servers_list_str = servers_section.get("list", "[]") if isinstance(servers_section, dict) else "[]" - + try: existing_servers = json.loads(servers_list_str) if servers_list_str.strip() else [] except json.JSONDecodeError: existing_servers = [] - + existing_names = {srv.get("name", "") for srv in existing_servers if isinstance(srv, dict)} - + # 执行导入 result = ConfigConverter.import_from_string(content.strip(), existing_names) - + # 构建响应 lines = [] - + if not result.success: lines.append("❌ 导入失败:") for err in result.errors: lines.append(f" • {err}") await self.send_text("\n".join(lines)) return (True, None, True) - + if not result.servers: lines.append("⚠️ 没有新服务器可导入") if result.skipped: @@ -1588,44 +1592,44 @@ class MCPImportCommand(BaseCommand): lines.append(f" • {w}") await self.send_text("\n".join(lines)) return (True, None, True) - + # 合并到现有列表 new_servers = existing_servers + result.servers new_list_str = json.dumps(new_servers, ensure_ascii=False, indent=2) - + # 更新配置 if "servers" not in _plugin_instance.config: _plugin_instance.config["servers"] = {} _plugin_instance.config["servers"]["list"] = new_list_str - + # 保存到配置文件 _plugin_instance._save_servers_list(new_list_str) - + # 构建成功响应 lines.append(f"✅ 成功导入 {len(result.servers)} 个服务器:") for srv in result.servers: transport = srv.get("transport", "stdio") lines.append(f" • {srv.get('name')} ({transport})") - + if result.skipped: lines.append(f"\n⏭️ 跳过 {len(result.skipped)} 个:") for s in result.skipped[:5]: lines.append(f" • {s}") if len(result.skipped) > 5: lines.append(f" ... 还有 {len(result.skipped) - 5} 个") - + if result.warnings: lines.append("\n⚠️ 警告:") for w in result.warnings[:3]: lines.append(f" • {w}") - + if result.errors: lines.append("\n❌ 部分失败:") for e in result.errors[:3]: lines.append(f" • {e}") - + lines.append("\n💡 发送 /mcp reconnect 使配置生效") - + await self.send_text("\n".join(lines)) return (True, None, True) @@ -1634,56 +1638,57 @@ class MCPImportCommand(BaseCommand): # 事件处理器 # ============================================================================ + class MCPStartupHandler(BaseEventHandler): """MCP 启动事件处理器""" - + event_type = EventType.ON_START handler_name = "mcp_startup_handler" handler_description = "MCP 桥接插件启动处理器" weight = 0 intercept_message = False - + async def execute(self, message: Optional[Any]) -> Tuple[bool, bool, Optional[str], None, None]: """处理启动事件""" global _plugin_instance - + if _plugin_instance is None: logger.warning("MCP 桥接插件实例未初始化") return (False, True, None, None, None) - + logger.info("MCP 桥接插件收到 ON_START 事件,开始连接 MCP 服务器...") await _plugin_instance._async_connect_servers() - + await mcp_manager.start_heartbeat() - + # v1.6.0: 启动配置文件监控(用于 WebUI 导入) await _plugin_instance._start_config_watcher() - + return (True, True, None, None, None) class MCPStopHandler(BaseEventHandler): """MCP 停止事件处理器""" - + event_type = EventType.ON_STOP handler_name = "mcp_stop_handler" handler_description = "MCP 桥接插件停止处理器" weight = 0 intercept_message = False - + async def execute(self, message: Optional[Any]) -> Tuple[bool, bool, Optional[str], None, None]: """处理停止事件""" global _plugin_instance - + logger.info("MCP 桥接插件收到 ON_STOP 事件,正在关闭...") - + # v1.6.0: 停止配置文件监控 if _plugin_instance: await _plugin_instance._stop_config_watcher() - + await mcp_manager.shutdown() mcp_tool_registry.clear() - + logger.info("MCP 桥接插件已关闭所有连接") return (True, True, None, None, None) @@ -1692,16 +1697,17 @@ class MCPStopHandler(BaseEventHandler): # 主插件类 # ============================================================================ + @register_plugin class MCPBridgePlugin(BasePlugin): """MCP 桥接插件 v1.4.0 - 将 MCP 服务器的工具桥接到 MaiBot""" - + plugin_name: str = "mcp_bridge_plugin" enable_plugin: bool = False # 默认禁用,用户需在 WebUI 手动启用 dependencies: List[str] = [] python_dependencies: List[str] = ["mcp"] config_file_name: str = "config.toml" - + config_section_descriptions = { "guide": "📖 快速入门", "plugin": "🔘 插件开关", @@ -1713,7 +1719,7 @@ class MCPBridgePlugin(BasePlugin): "tools": "🔧 工具管理", "permissions": "🔐 权限控制", } - + config_schema: dict = { # 新手引导区(只读) "guide": { @@ -2116,9 +2122,9 @@ class MCPBridgePlugin(BasePlugin): label="📜 高级权限规则(可选)", input_type="textarea", rows=10, - placeholder='''[ + placeholder="""[ {"tool": "mcp_*_delete_*", "denied": ["qq:123456:group"]} -]''', +]""", hint="格式: qq:ID:group/private/user,工具名支持通配符 *", order=10, ), @@ -2217,43 +2223,43 @@ class MCPBridgePlugin(BasePlugin): ), }, } - + @staticmethod def _fix_config_multiline_strings(config_path: Path) -> bool: """修复配置文件中的多行字符串格式问题 - + 处理两种情况: 1. 带转义 \\n 的单行字符串(json.dumps 生成) 2. 跨越多行但使用普通双引号的字符串(控制字符错误) - + Returns: bool: 是否进行了修复 """ if not config_path.exists(): return False - + try: content = config_path.read_text(encoding="utf-8") - + # 情况1: 修复带转义 \n 的单行字符串 # 匹配: key = "内容包含\n的字符串" pattern1 = r'^(\s*\w+\s*=\s*)"((?:[^"\\]|\\.)*\\n(?:[^"\\]|\\.)*)"(\s*)$' - + # 情况2: 修复跨越多行的普通双引号字符串 # 匹配: key = "第一行 # 第二行 # 第三行" pattern2_start = r'^(\s*\w+\s*=\s*)"([^"]*?)$' # 开始行 pattern2_end = r'^([^"]*)"(\s*)$' # 结束行 - + lines = content.split("\n") fixed_lines = [] modified = False - + i = 0 while i < len(lines): line = lines[i] - + # 情况1: 单行带转义换行符 match1 = re.match(pattern1, line) if match1: @@ -2261,24 +2267,26 @@ class MCPBridgePlugin(BasePlugin): value = match1.group(2) suffix = match1.group(3) # 将转义的换行符还原为实际换行符 - unescaped = value.replace("\\n", "\n").replace("\\t", "\t").replace('\\"', '"').replace("\\\\", "\\") + unescaped = ( + value.replace("\\n", "\n").replace("\\t", "\t").replace('\\"', '"').replace("\\\\", "\\") + ) fixed_line = f'{prefix}"""{unescaped}"""{suffix}' fixed_lines.append(fixed_line) modified = True i += 1 continue - + # 情况2: 跨越多行的字符串 match2_start = re.match(pattern2_start, line) if match2_start: prefix = match2_start.group(1) first_part = match2_start.group(2) - + # 收集后续行直到找到结束引号 multiline_parts = [first_part] j = i + 1 found_end = False - + while j < len(lines): next_line = lines[j] match2_end = re.match(pattern2_end, next_line) @@ -2291,7 +2299,7 @@ class MCPBridgePlugin(BasePlugin): else: multiline_parts.append(next_line) j += 1 - + if found_end and len(multiline_parts) > 1: # 合并为三引号字符串 full_value = "\n".join(multiline_parts) @@ -2300,35 +2308,35 @@ class MCPBridgePlugin(BasePlugin): modified = True i = j continue - + fixed_lines.append(line) i += 1 - + if modified: config_path.write_text("\n".join(fixed_lines), encoding="utf-8") logger.info("已自动修复配置文件中的多行字符串格式") return True - + return False except Exception as e: logger.warning(f"修复配置文件格式失败: {e}") return False - + def __init__(self, *args, **kwargs): global _plugin_instance - + # 在父类初始化前尝试修复配置文件格式 config_path = Path(__file__).parent / "config.toml" self._fix_config_multiline_strings(config_path) - + super().__init__(*args, **kwargs) self._initialized = False _plugin_instance = self - + # 配置 MCP 管理器 settings = self.config.get("settings", {}) mcp_manager.configure(settings) - + # v1.4.0: 配置追踪器 trace_log_path = Path(__file__).parent / "logs" / "trace.jsonl" tool_call_tracer.configure( @@ -2337,7 +2345,7 @@ class MCPBridgePlugin(BasePlugin): log_enabled=settings.get("trace_log_enabled", False), log_path=trace_log_path, ) - + # v1.4.0: 配置缓存 tool_call_cache.configure( enabled=settings.get("cache_enabled", False), @@ -2345,7 +2353,7 @@ class MCPBridgePlugin(BasePlugin): max_entries=settings.get("cache_max_entries", 200), exclude_tools=settings.get("cache_exclude_tools", ""), ) - + # v1.4.0: 配置权限检查器 perm_config = self.config.get("permissions", {}) permission_checker.configure( @@ -2355,13 +2363,13 @@ class MCPBridgePlugin(BasePlugin): quick_deny_groups=perm_config.get("quick_deny_groups", ""), quick_allow_users=perm_config.get("quick_allow_users", ""), ) - + # 注册状态变化回调 mcp_manager.set_status_change_callback(self._update_status_display) - + # v1.6.0: 处理 WebUI 导入导出 self._process_webui_import_export() - + # v1.5.1: 处理快速添加服务器 self._process_quick_add_server() @@ -2560,7 +2568,7 @@ class MCPBridgePlugin(BasePlugin): continue import_config_str = str(import_config).strip() - logger.info(f"检测到 WebUI 导入请求,开始处理...") + logger.info("检测到 WebUI 导入请求,开始处理...") # 执行导入 await self._execute_webui_import(import_config_str, doc, config_path) @@ -2650,23 +2658,23 @@ class MCPBridgePlugin(BasePlugin): """v1.5.1: 处理快速添加服务器表单,将新服务器合并到列表""" quick_add = self.config.get("quick_add", {}) server_name = quick_add.get("server_name", "").strip() - + if not server_name: return # 没有填写名称,跳过 - + server_type = quick_add.get("server_type", "streamable_http") server_url = quick_add.get("server_url", "").strip() server_command = quick_add.get("server_command", "").strip() server_args_str = quick_add.get("server_args", "").strip() server_headers_str = quick_add.get("server_headers", "").strip() - + # 构建新服务器配置 new_server = { "name": server_name, "enabled": True, "transport": server_type, } - + if server_type == "stdio": if not server_command: logger.warning(f"快速添加: stdio 类型需要填写命令,跳过 {server_name}") @@ -2679,7 +2687,7 @@ class MCPBridgePlugin(BasePlugin): logger.warning(f"快速添加: {server_type} 类型需要填写 URL,跳过 {server_name}") return new_server["url"] = server_url - + # 解析鉴权头 if server_headers_str: try: @@ -2688,39 +2696,39 @@ class MCPBridgePlugin(BasePlugin): new_server["headers"] = headers except json.JSONDecodeError: logger.warning("快速添加: 鉴权头 JSON 格式错误,已忽略") - + # 获取现有服务器列表 servers_section = self.config.get("servers", {}) servers_list_str = servers_section.get("list", "[]") if isinstance(servers_section, dict) else "[]" - + try: servers_list = json.loads(servers_list_str) if servers_list_str.strip() else [] except json.JSONDecodeError: servers_list = [] - + # 检查是否已存在同名服务器 for existing in servers_list: if existing.get("name") == server_name: logger.info(f"快速添加: 服务器 {server_name} 已存在,跳过") self._clear_quick_add_fields() return - + # 添加新服务器 servers_list.append(new_server) logger.info(f"快速添加: 已添加服务器 {server_name} ({server_type})") - + # 更新配置 new_list_str = json.dumps(servers_list, ensure_ascii=False, indent=2) if "servers" not in self.config: self.config["servers"] = {} self.config["servers"]["list"] = new_list_str - + # 清空快速添加字段 self._clear_quick_add_fields() - + # 保存到配置文件 self._save_servers_list(new_list_str) - + def _clear_quick_add_fields(self) -> None: """清空快速添加表单字段""" if "quick_add" not in self.config: @@ -2730,25 +2738,25 @@ class MCPBridgePlugin(BasePlugin): self.config["quick_add"]["server_command"] = "" self.config["quick_add"]["server_args"] = "" self.config["quick_add"]["server_headers"] = "" - + def _save_servers_list(self, servers_json: str) -> None: """保存服务器列表到配置文件""" import tomlkit from tomlkit.items import String, StringType, Trivia - + try: config_path = Path(__file__).parent / "config.toml" if config_path.exists(): with open(config_path, "r", encoding="utf-8") as f: doc = tomlkit.load(f) - + if "servers" not in doc: doc["servers"] = tomlkit.table() - + # 使用多行字符串 ml_string = String(StringType.MLB, servers_json, servers_json, Trivia()) doc["servers"]["list"] = ml_string - + # 清空快速添加字段 if "quick_add" in doc: doc["quick_add"]["server_name"] = "" @@ -2756,27 +2764,28 @@ class MCPBridgePlugin(BasePlugin): doc["quick_add"]["server_command"] = "" doc["quick_add"]["server_args"] = "" doc["quick_add"]["server_headers"] = "" - + with open(config_path, "w", encoding="utf-8") as f: tomlkit.dump(doc, f) - + logger.info("服务器列表已保存到配置文件") except Exception as e: logger.warning(f"保存服务器列表失败: {e}") - + def _get_disabled_tools(self) -> set: """v1.4.0: 获取禁用的工具列表""" tools_config = self.config.get("tools", {}) disabled_str = tools_config.get("disabled_tools", "") return {t.strip() for t in disabled_str.strip().split("\n") if t.strip()} - + async def _async_connect_servers(self) -> None: """异步连接所有配置的 MCP 服务器(v1.5.0: 并行连接优化)""" import asyncio + settings = self.config.get("settings", {}) - + servers_section = self.config.get("servers", []) - + if isinstance(servers_section, dict): servers_list = servers_section.get("list", []) if isinstance(servers_list, str): @@ -2787,45 +2796,45 @@ class MCPBridgePlugin(BasePlugin): servers_config = [] else: servers_config = servers_section - + if not servers_config: logger.warning("未配置任何 MCP 服务器") self._initialized = True return - + auto_connect = settings.get("auto_connect", True) if not auto_connect: logger.info("auto_connect 已禁用,跳过自动连接") self._initialized = True return - + tool_prefix = settings.get("tool_prefix", "mcp") disabled_tools = self._get_disabled_tools() enable_resources = settings.get("enable_resources", False) enable_prompts = settings.get("enable_prompts", False) - + # 解析所有服务器配置 enabled_configs: List[MCPServerConfig] = [] for idx, server_conf in enumerate(servers_config): server_name = server_conf.get("name", f"unknown_{idx}") - + if not server_conf.get("enabled", True): logger.info(f"服务器 {server_name} 已禁用,跳过") continue - + try: config = self._parse_server_config(server_conf) enabled_configs.append(config) except Exception as e: logger.error(f"解析服务器 {server_name} 配置失败: {e}") - + if not enabled_configs: logger.warning("没有已启用的 MCP 服务器") self._initialized = True return - + logger.info(f"准备并行连接 {len(enabled_configs)} 个 MCP 服务器") - + # v1.5.0: 并行连接所有服务器 async def connect_single_server(config: MCPServerConfig) -> Tuple[MCPServerConfig, bool]: """连接单个服务器""" @@ -2851,15 +2860,12 @@ class MCPBridgePlugin(BasePlugin): except Exception as e: logger.error(f"❌ 服务器 {config.name} 连接异常: {e}") return config, False - + # 并行执行所有连接 start_time = time.time() - results = await asyncio.gather( - *[connect_single_server(cfg) for cfg in enabled_configs], - return_exceptions=True - ) + results = await asyncio.gather(*[connect_single_server(cfg) for cfg in enabled_configs], return_exceptions=True) connect_duration = time.time() - start_time - + # 统计连接结果 success_count = 0 failed_count = 0 @@ -2873,43 +2879,42 @@ class MCPBridgePlugin(BasePlugin): success_count += 1 else: failed_count += 1 - + logger.info(f"并行连接完成: {success_count} 成功, {failed_count} 失败, 耗时 {connect_duration:.2f}s") - + # 注册所有工具 from src.plugin_system.core.component_registry import component_registry + registered_count = 0 - + for tool_key, (tool_info, _) in mcp_manager.all_tools.items(): tool_name = tool_key.replace("-", "_").replace(".", "_") is_disabled = tool_name in disabled_tools - - info, tool_class = mcp_tool_registry.register_tool( - tool_key, tool_info, tool_prefix, disabled=is_disabled - ) + + info, tool_class = mcp_tool_registry.register_tool(tool_key, tool_info, tool_prefix, disabled=is_disabled) info.plugin_name = self.plugin_name - + if component_registry.register_component(info, tool_class): registered_count += 1 status = "🚫" if is_disabled else "✅" logger.info(f"{status} 注册 MCP 工具: {tool_class.name}") else: logger.warning(f"❌ 注册 MCP 工具失败: {tool_class.name}") - + self._initialized = True logger.info(f"MCP 桥接插件初始化完成,已注册 {registered_count} 个工具") - + # 更新状态显示 self._update_status_display() self._update_tool_list_display() - + def _parse_servers_json(self, servers_list: str) -> List[Dict]: """解析服务器列表 JSON 字符串""" if not servers_list.strip(): return [] - + content = servers_list.strip() - + try: parsed = json.loads(content) if isinstance(parsed, list): @@ -2922,7 +2927,7 @@ class MCPBridgePlugin(BasePlugin): return [] except json.JSONDecodeError as e: logger.warning(f"JSON 解析失败: {e}") - + if content.startswith("{") and not content.startswith("["): try: fixed_content = f"[{content}]" @@ -2932,14 +2937,14 @@ class MCPBridgePlugin(BasePlugin): return parsed except json.JSONDecodeError: pass - + logger.error("❌ 服务器配置 JSON 格式错误") return [] - + def _parse_server_config(self, conf: Dict) -> MCPServerConfig: """解析服务器配置字典""" transport_str = conf.get("transport", "stdio").lower() - + transport_map = { "stdio": TransportType.STDIO, "sse": TransportType.SSE, @@ -2947,7 +2952,7 @@ class MCPBridgePlugin(BasePlugin): "streamable_http": TransportType.STREAMABLE_HTTP, } transport = transport_map.get(transport_str, TransportType.STDIO) - + return MCPServerConfig( name=conf.get("name", "unnamed"), enabled=conf.get("enabled", True), @@ -2958,68 +2963,69 @@ class MCPBridgePlugin(BasePlugin): url=conf.get("url", ""), headers=conf.get("headers", {}), # v1.4.2: 鉴权头支持 ) - + def _update_tool_list_display(self) -> None: """v1.4.0: 更新工具列表显示""" import tomlkit - + tools = mcp_manager.all_tools disabled_tools = self._get_disabled_tools() - + lines = [] by_server: Dict[str, List[str]] = {} - + for tool_key, (tool_info, _) in tools.items(): tool_name = tool_key.replace("-", "_").replace(".", "_") if tool_info.server_name not in by_server: by_server[tool_info.server_name] = [] - + is_disabled = tool_name in disabled_tools status = " ❌" if is_disabled else "" by_server[tool_info.server_name].append(f" • {tool_name}{status}") - + for srv_name, tool_list in by_server.items(): lines.append(f"📦 {srv_name} ({len(tool_list)}个工具):") lines.extend(tool_list) lines.append("") - + if not by_server: lines.append("(无已注册工具)") - + tool_list_text = "\n".join(lines) - + # 更新内存配置 if "tools" not in self.config: self.config["tools"] = {} self.config["tools"]["tool_list"] = tool_list_text - + # 写入配置文件 try: config_path = Path(__file__).parent / "config.toml" if config_path.exists(): with open(config_path, "r", encoding="utf-8") as f: doc = tomlkit.load(f) - + if "tools" not in doc: doc["tools"] = tomlkit.table() # 使用 tomlkit 多行字符串避免控制字符问题 from tomlkit.items import String, StringType, Trivia + ml_string = String(StringType.MLB, tool_list_text, tool_list_text, Trivia()) doc["tools"]["tool_list"] = ml_string - + with open(config_path, "w", encoding="utf-8") as f: tomlkit.dump(doc, f) except Exception as e: logger.warning(f"更新工具列表显示失败: {e}") - + def _update_status_display(self) -> None: """更新配置文件中的状态显示字段""" import tomlkit - + status = mcp_manager.get_status() settings = self.config.get("settings", {}) lines = [] - + lines.append(f"服务器: {status['connected_servers']}/{status['total_servers']} 已连接") lines.append(f"工具数: {status['total_tools']}") if settings.get("enable_resources", False): @@ -3028,13 +3034,13 @@ class MCPBridgePlugin(BasePlugin): lines.append(f"模板数: {status.get('total_prompts', 0)}") lines.append(f"心跳: {'运行中' if status['heartbeat_running'] else '已停止'}") lines.append("") - + tools = mcp_manager.all_tools - + for name, info in status.get("servers", {}).items(): icon = "✅" if info["connected"] else "❌" lines.append(f"{icon} {name} ({info['transport']})") - + # v1.7.0: 显示断路器状态 cb_status = info.get("circuit_breaker", {}) cb_state = cb_status.get("state", "closed") @@ -3042,53 +3048,54 @@ class MCPBridgePlugin(BasePlugin): lines.append(" ⚡ 断路器: 熔断中") elif cb_state == "half_open": lines.append(" ⚡ 断路器: 试探中") - + server_tools = [t.name for key, (t, _) in tools.items() if t.server_name == name] if server_tools: for tool_name in server_tools: lines.append(f" • {tool_name}") else: lines.append(" (无工具)") - + if not status.get("servers"): lines.append("(无服务器)") - + status_text = "\n".join(lines) - + if "status" not in self.config: self.config["status"] = {} self.config["status"]["connection_status"] = status_text - + try: config_path = Path(__file__).parent / "config.toml" if config_path.exists(): with open(config_path, "r", encoding="utf-8") as f: doc = tomlkit.load(f) - + if "status" not in doc: doc["status"] = tomlkit.table() # 使用 tomlkit 多行字符串避免控制字符问题 from tomlkit.items import String, StringType, Trivia + ml_string = String(StringType.MLB, status_text, status_text, Trivia()) doc["status"]["connection_status"] = ml_string - + with open(config_path, "w", encoding="utf-8") as f: tomlkit.dump(doc, f) except Exception as e: logger.warning(f"更新配置文件状态失败: {e}") - + def get_plugin_components(self) -> List[Tuple[ComponentInfo, Type]]: """返回插件的所有组件""" components: List[Tuple[ComponentInfo, Type]] = [] - + # 事件处理器 components.append((MCPStartupHandler.get_handler_info(), MCPStartupHandler)) components.append((MCPStopHandler.get_handler_info(), MCPStopHandler)) - + # 命令 components.append((MCPStatusCommand.get_command_info(), MCPStatusCommand)) components.append((MCPImportCommand.get_command_info(), MCPImportCommand)) - + # 内置工具 status_tool_info = ToolInfo( name=MCPStatusTool.name, @@ -3098,9 +3105,9 @@ class MCPBridgePlugin(BasePlugin): component_type=ComponentType.TOOL, ) components.append((status_tool_info, MCPStatusTool)) - + settings = self.config.get("settings", {}) - + if settings.get("enable_resources", False): read_resource_info = ToolInfo( name=MCPReadResourceTool.name, @@ -3110,7 +3117,7 @@ class MCPBridgePlugin(BasePlugin): component_type=ComponentType.TOOL, ) components.append((read_resource_info, MCPReadResourceTool)) - + if settings.get("enable_prompts", False): get_prompt_info = ToolInfo( name=MCPGetPromptTool.name, @@ -3120,9 +3127,9 @@ class MCPBridgePlugin(BasePlugin): component_type=ComponentType.TOOL, ) components.append((get_prompt_info, MCPGetPromptTool)) - + return components - + def get_status(self) -> Dict[str, Any]: """获取插件状态""" return { @@ -3132,7 +3139,7 @@ class MCPBridgePlugin(BasePlugin): "trace_records": tool_call_tracer.total_records, "cache_stats": tool_call_cache.get_stats(), } - + def get_stats(self) -> Dict[str, Any]: """获取详细统计信息""" return mcp_manager.get_all_stats() diff --git a/plugins/MaiBot_MCPBridgePlugin/test_mcp_client.py b/plugins/MaiBot_MCPBridgePlugin/test_mcp_client.py index d2264314..fc968ae3 100644 --- a/plugins/MaiBot_MCPBridgePlugin/test_mcp_client.py +++ b/plugins/MaiBot_MCPBridgePlugin/test_mcp_client.py @@ -23,22 +23,22 @@ from mcp_client import ( async def test_stats(): """测试统计类""" print("\n=== 测试统计类 ===") - + # 测试 ToolCallStats stats = ToolCallStats(tool_key="test_tool") stats.record_call(True, 100.0) stats.record_call(True, 200.0) stats.record_call(False, 50.0, "timeout") - + assert stats.total_calls == 3 assert stats.success_calls == 2 assert stats.failed_calls == 1 - assert stats.success_rate == (2/3) * 100 + assert stats.success_rate == (2 / 3) * 100 assert stats.avg_duration_ms == 150.0 assert stats.last_error == "timeout" - + print(f"✅ ToolCallStats: {stats.to_dict()}") - + # 测试 ServerStats server_stats = ServerStats(server_name="test_server") server_stats.record_connect() @@ -46,133 +46,138 @@ async def test_stats(): server_stats.record_disconnect() server_stats.record_failure() server_stats.record_failure() - + assert server_stats.connect_count == 1 assert server_stats.disconnect_count == 1 assert server_stats.consecutive_failures == 2 - + print(f"✅ ServerStats: {server_stats.to_dict()}") - + return True async def test_manager_basic(): """测试管理器基本功能""" print("\n=== 测试管理器基本功能 ===") - + # 创建新的管理器实例(绕过单例) manager = MCPClientManager.__new__(MCPClientManager) manager._initialized = False manager.__init__() - + # 配置 - manager.configure({ - "tool_prefix": "mcp", - "call_timeout": 30.0, - "retry_attempts": 1, - "retry_interval": 1.0, - "heartbeat_enabled": False, - }) - + manager.configure( + { + "tool_prefix": "mcp", + "call_timeout": 30.0, + "retry_attempts": 1, + "retry_interval": 1.0, + "heartbeat_enabled": False, + } + ) + # 测试状态 status = manager.get_status() assert status["total_servers"] == 0 assert status["connected_servers"] == 0 print(f"✅ 初始状态: {status}") - + # 测试添加禁用的服务器 config = MCPServerConfig( - name="disabled_server", - enabled=False, - transport=TransportType.HTTP, - url="https://example.com/mcp" + name="disabled_server", enabled=False, transport=TransportType.HTTP, url="https://example.com/mcp" ) result = await manager.add_server(config) assert result == True assert "disabled_server" in manager._clients assert manager._clients["disabled_server"].is_connected == False print("✅ 添加禁用服务器成功") - + # 测试重复添加 result = await manager.add_server(config) assert result == False print("✅ 重复添加被拒绝") - + # 测试移除 result = await manager.remove_server("disabled_server") assert result == True assert "disabled_server" not in manager._clients print("✅ 移除服务器成功") - + # 清理 await manager.shutdown() print("✅ 管理器关闭成功") - + return True async def test_http_connection(): """测试 HTTP 连接(使用真实的 MCP 服务器)""" print("\n=== 测试 HTTP 连接 ===") - + # 创建新的管理器实例 manager = MCPClientManager.__new__(MCPClientManager) manager._initialized = False manager.__init__() - - manager.configure({ - "tool_prefix": "mcp", - "call_timeout": 30.0, - "retry_attempts": 2, - "retry_interval": 2.0, - "heartbeat_enabled": False, - }) - + + manager.configure( + { + "tool_prefix": "mcp", + "call_timeout": 30.0, + "retry_attempts": 2, + "retry_interval": 2.0, + "heartbeat_enabled": False, + } + ) + # 使用 HowToCook MCP 服务器测试 config = MCPServerConfig( name="howtocook", enabled=True, transport=TransportType.HTTP, - url="https://mcp.api-inference.modelscope.net/c9b55951d4ed47/mcp" + url="https://mcp.api-inference.modelscope.net/c9b55951d4ed47/mcp", ) - + print(f"正在连接 {config.url} ...") result = await manager.add_server(config) - + if result: - print(f"✅ 连接成功!") - + print("✅ 连接成功!") + # 检查工具 tools = manager.all_tools print(f"✅ 发现 {len(tools)} 个工具:") for tool_key in tools: print(f" - {tool_key}") - + # 测试心跳 client = manager._clients["howtocook"] healthy = await client.check_health() print(f"✅ 心跳检测: {'健康' if healthy else '异常'}") - + # 测试工具调用 if "mcp_howtocook_whatToEat" in tools: print("\n正在调用 whatToEat 工具...") call_result = await manager.call_tool("mcp_howtocook_whatToEat", {}) if call_result.success: print(f"✅ 工具调用成功 (耗时: {call_result.duration_ms:.0f}ms)") - print(f" 结果: {call_result.content[:200]}..." if len(str(call_result.content)) > 200 else f" 结果: {call_result.content}") + print( + f" 结果: {call_result.content[:200]}..." + if len(str(call_result.content)) > 200 + else f" 结果: {call_result.content}" + ) else: print(f"❌ 工具调用失败: {call_result.error}") - + # 查看统计 stats = manager.get_all_stats() - print(f"\n📊 统计信息:") + print("\n📊 统计信息:") print(f" 全局调用: {stats['global']['total_tool_calls']}") print(f" 成功: {stats['global']['successful_calls']}") print(f" 失败: {stats['global']['failed_calls']}") - + else: - print(f"❌ 连接失败") - + print("❌ 连接失败") + # 清理 await manager.shutdown() return result @@ -181,55 +186,57 @@ async def test_http_connection(): async def test_heartbeat(): """测试心跳检测功能""" print("\n=== 测试心跳检测 ===") - + # 创建新的管理器实例 manager = MCPClientManager.__new__(MCPClientManager) manager._initialized = False manager.__init__() - - manager.configure({ - "tool_prefix": "mcp", - "call_timeout": 30.0, - "retry_attempts": 1, - "retry_interval": 1.0, - "heartbeat_enabled": True, - "heartbeat_interval": 5.0, # 5秒间隔用于测试 - "auto_reconnect": True, - "max_reconnect_attempts": 2, - }) - + + manager.configure( + { + "tool_prefix": "mcp", + "call_timeout": 30.0, + "retry_attempts": 1, + "retry_interval": 1.0, + "heartbeat_enabled": True, + "heartbeat_interval": 5.0, # 5秒间隔用于测试 + "auto_reconnect": True, + "max_reconnect_attempts": 2, + } + ) + # 添加一个测试服务器 config = MCPServerConfig( name="heartbeat_test", enabled=True, transport=TransportType.HTTP, - url="https://mcp.api-inference.modelscope.net/c9b55951d4ed47/mcp" + url="https://mcp.api-inference.modelscope.net/c9b55951d4ed47/mcp", ) - + print("正在连接服务器...") result = await manager.add_server(config) - + if result: print("✅ 服务器连接成功") - + # 启动心跳检测 await manager.start_heartbeat() print("✅ 心跳检测已启动") - + # 等待一个心跳周期 print("等待心跳检测...") await asyncio.sleep(2) - + # 检查状态 status = manager.get_status() print(f"✅ 心跳运行状态: {status['heartbeat_running']}") - + # 停止心跳 await manager.stop_heartbeat() print("✅ 心跳检测已停止") else: print("❌ 服务器连接失败,跳过心跳测试") - + await manager.shutdown() return True @@ -239,30 +246,31 @@ async def main(): print("=" * 50) print("MCP 客户端测试") print("=" * 50) - + try: # 基础测试 await test_stats() await test_manager_basic() - + # 网络测试 print("\n是否进行网络连接测试? (需要网络) [y/N]: ", end="") # 自动进行网络测试 await test_http_connection() - + # 心跳测试 await test_heartbeat() - + print("\n" + "=" * 50) print("✅ 所有测试通过!") print("=" * 50) - + except Exception as e: print(f"\n❌ 测试失败: {e}") import traceback + traceback.print_exc() return False - + return True diff --git a/scripts/replyer_action_stats.py b/scripts/replyer_action_stats.py index f155d98e..8d8904bf 100644 --- a/scripts/replyer_action_stats.py +++ b/scripts/replyer_action_stats.py @@ -35,13 +35,13 @@ def get_chat_name(chat_id: str) -> str: return f"{chat_stream.group_name}" elif chat_stream.user_nickname: return f"{chat_stream.user_nickname}的私聊" - + if get_chat_manager: chat_manager = get_chat_manager() stream_name = chat_manager.get_stream_name(chat_id) if stream_name: return stream_name - + return f"未知聊天 ({chat_id[:8]}...)" except Exception: return f"查询失败 ({chat_id[:8]}...)" @@ -51,11 +51,11 @@ def load_records(temp_dir: str = "data/temp") -> List[Dict[str, Any]]: """加载所有 replyer 动作记录""" records = [] temp_path = Path(temp_dir) - + if not temp_path.exists(): print(f"目录不存在: {temp_dir}") return records - + # 查找所有 replyer_action_*.json 文件 pattern = "replyer_action_*.json" for file_path in temp_path.glob(pattern): @@ -65,7 +65,7 @@ def load_records(temp_dir: str = "data/temp") -> List[Dict[str, Any]]: records.append(data) except Exception as e: print(f"读取文件失败 {file_path}: {e}") - + # 按时间戳排序 records.sort(key=lambda x: x.get("timestamp", "")) return records @@ -91,7 +91,7 @@ def calculate_time_distribution(records: List[Dict[str, Any]]) -> Dict[str, int] "30天内": 0, "更早": 0, } - + for record in records: try: ts = record.get("timestamp", "") @@ -99,7 +99,7 @@ def calculate_time_distribution(records: List[Dict[str, Any]]) -> Dict[str, int] continue dt = datetime.fromisoformat(ts) diff = (now - dt).days - + if diff == 0: distribution["今天"] += 1 elif diff == 1: @@ -114,7 +114,7 @@ def calculate_time_distribution(records: List[Dict[str, Any]]) -> Dict[str, int] distribution["更早"] += 1 except Exception: pass - + return distribution @@ -123,17 +123,17 @@ def print_statistics(records: List[Dict[str, Any]]): if not records: print("没有找到任何记录") return - + print("=" * 80) print("Replyer 动作选择记录统计") print("=" * 80) print() - + # 总记录数 total_count = len(records) print(f"📊 总记录数: {total_count}") print() - + # 时间范围 timestamps = [r.get("timestamp", "") for r in records if r.get("timestamp")] if timestamps: @@ -141,7 +141,7 @@ def print_statistics(records: List[Dict[str, Any]]): last_time = format_timestamp(max(timestamps)) print(f"📅 时间范围: {first_time} ~ {last_time}") print() - + # 按 think_level 统计 think_levels = [r.get("think_level", 0) for r in records] think_level_counter = Counter(think_levels) @@ -152,7 +152,7 @@ def print_statistics(records: List[Dict[str, Any]]): level_name = {0: "不需要思考", 1: "简单思考", 2: "深度思考"}.get(level, f"未知({level})") print(f" Level {level} ({level_name}): {count} 次 ({percentage:.1f}%)") print() - + # 按 chat_id 统计(总体) chat_counter = Counter([r.get("chat_id", "未知") for r in records]) print(f"💬 聊天分布 (共 {len(chat_counter)} 个聊天):") @@ -164,30 +164,30 @@ def print_statistics(records: List[Dict[str, Any]]): if len(chat_counter) > 10: print(f" ... 还有 {len(chat_counter) - 10} 个聊天") print() - + # 每个 chat_id 的详细统计 print("=" * 80) print("每个聊天的详细统计") print("=" * 80) print() - + # 按 chat_id 分组记录 records_by_chat = defaultdict(list) for record in records: chat_id = record.get("chat_id", "未知") records_by_chat[chat_id].append(record) - + # 按记录数排序 sorted_chats = sorted(records_by_chat.items(), key=lambda x: len(x[1]), reverse=True) - + for chat_id, chat_records in sorted_chats: chat_name = get_chat_name(chat_id) chat_count = len(chat_records) chat_percentage = (chat_count / total_count) * 100 - + print(f"📱 {chat_name} ({chat_id[:8]}...)") print(f" 总记录数: {chat_count} ({chat_percentage:.1f}%)") - + # 该聊天的 think_level 分布 chat_think_levels = [r.get("think_level", 0) for r in chat_records] chat_think_counter = Counter(chat_think_levels) @@ -197,14 +197,14 @@ def print_statistics(records: List[Dict[str, Any]]): level_percentage = (level_count / chat_count) * 100 level_name = {0: "不需要思考", 1: "简单思考", 2: "深度思考"}.get(level, f"未知({level})") print(f" Level {level} ({level_name}): {level_count} 次 ({level_percentage:.1f}%)") - + # 该聊天的时间范围 chat_timestamps = [r.get("timestamp", "") for r in chat_records if r.get("timestamp")] if chat_timestamps: first_time = format_timestamp(min(chat_timestamps)) last_time = format_timestamp(max(chat_timestamps)) print(f" 时间范围: {first_time} ~ {last_time}") - + # 该聊天的时间分布 chat_time_dist = calculate_time_distribution(chat_records) print(" 时间分布:") @@ -212,7 +212,7 @@ def print_statistics(records: List[Dict[str, Any]]): if count > 0: period_percentage = (count / chat_count) * 100 print(f" {period}: {count} 次 ({period_percentage:.1f}%)") - + # 显示该聊天最近的一条理由示例 if chat_records: latest_record = chat_records[-1] @@ -222,9 +222,9 @@ def print_statistics(records: List[Dict[str, Any]]): timestamp = format_timestamp(latest_record.get("timestamp", "")) think_level = latest_record.get("think_level", 0) print(f" 最新记录 [{timestamp}] (Level {think_level}): {reason}") - + print() - + # 时间分布 time_dist = calculate_time_distribution(records) print("⏰ 时间分布:") @@ -233,7 +233,7 @@ def print_statistics(records: List[Dict[str, Any]]): percentage = (count / total_count) * 100 print(f" {period}: {count} 次 ({percentage:.1f}%)") print() - + # 显示一些示例理由 print("📝 示例理由 (最近5条):") recent_records = records[-5:] @@ -243,29 +243,29 @@ def print_statistics(records: List[Dict[str, Any]]): timestamp = format_timestamp(record.get("timestamp", "")) chat_id = record.get("chat_id", "未知") chat_name = get_chat_name(chat_id) - + # 截断过长的理由 if len(reason) > 100: reason = reason[:100] + "..." - + print(f" {i}. [{timestamp}] {chat_name} (Level {think_level})") print(f" {reason}") print() - + # 按 think_level 分组显示理由示例 print("=" * 80) print("按思考深度分类的示例理由") print("=" * 80) print() - + for level in [0, 1, 2]: level_records = [r for r in records if r.get("think_level") == level] if not level_records: continue - + level_name = {0: "不需要思考", 1: "简单思考", 2: "深度思考"}.get(level, f"未知({level})") print(f"Level {level} ({level_name}) - 共 {len(level_records)} 条:") - + # 显示3个示例(选择最近的) examples = level_records[-3:] if len(level_records) >= 3 else level_records for i, record in enumerate(examples, 1): @@ -278,7 +278,7 @@ def print_statistics(records: List[Dict[str, Any]]): print(f" {i}. [{timestamp}] {chat_name}") print(f" {reason}") print() - + # 统计信息汇总 print("=" * 80) print("统计汇总") @@ -301,4 +301,3 @@ def main(): if __name__ == "__main__": main() - diff --git a/src/bw_learner/expression_learner.py b/src/bw_learner/expression_learner.py index 73522e4a..4b306fe2 100644 --- a/src/bw_learner/expression_learner.py +++ b/src/bw_learner/expression_learner.py @@ -3,7 +3,7 @@ import json import os import re import asyncio -from typing import List, Optional, Tuple, Any, Dict, Callable +from typing import List, Optional, Tuple, Any, Dict from src.common.logger import get_logger from src.common.database.database_model import Expression from src.llm_models.utils_model import LLMRequest @@ -13,7 +13,12 @@ from src.chat.utils.chat_message_builder import ( ) from src.chat.utils.prompt_builder import Prompt, global_prompt_manager from src.chat.message_receive.chat_stream import get_chat_manager -from src.bw_learner.learner_utils import filter_message_content, is_bot_message, build_context_paragraph, contains_bot_self_name +from src.bw_learner.learner_utils import ( + filter_message_content, + is_bot_message, + build_context_paragraph, + contains_bot_self_name, +) from src.bw_learner.jargon_miner import miner_manager from json_repair import repair_json @@ -77,8 +82,6 @@ def init_prompt() -> None: Prompt(learn_style_prompt, "learn_style_prompt") - - class ExpressionLearner: def __init__(self, chat_id: str) -> None: self.express_learn_model: LLMRequest = LLMRequest( @@ -95,20 +98,20 @@ class ExpressionLearner: self._learning_lock = asyncio.Lock() async def learn_and_store( - self, + self, messages: List[Any], - person_name_filter: Optional[Callable[[str], bool]] = None, ) -> List[Tuple[str, str, str]]: """ 学习并存储表达方式 - + Args: messages: 外部传入的消息列表(必需) - person_name_filter: 可选的过滤函数,用于检查内容是否包含人物名称 + num: 学习数量 + timestamp_start: 学习开始的时间戳,如果为None则使用self.last_learning_time """ if not messages: return None - + random_msg = messages # 学习用(开启行编号,便于溯源) @@ -134,37 +137,26 @@ class ExpressionLearner: jargon_entries: List[Tuple[str, str]] # (content, source_id) expressions, jargon_entries = self.parse_expression_response(response) expressions = self._filter_self_reference_styles(expressions) - - # 过滤掉包含人物名称的表达方式 - if person_name_filter: - filtered_expressions = [] - for situation, style, source_id in expressions: - # 检查 situation 和 style 是否包含人物名称 - if person_name_filter(situation) or person_name_filter(style): - logger.info(f"跳过包含人物名称的表达方式: situation={situation}, style={style}") - continue - filtered_expressions.append((situation, style, source_id)) - expressions = filtered_expressions - + # 检查表达方式数量,如果超过10个则放弃本次表达学习 if len(expressions) > 10: logger.info(f"表达方式提取数量超过10个(实际{len(expressions)}个),放弃本次表达学习") expressions = [] - + # 检查黑话数量,如果超过30个则放弃本次黑话学习 if len(jargon_entries) > 30: logger.info(f"黑话提取数量超过30个(实际{len(jargon_entries)}个),放弃本次黑话学习") jargon_entries = [] - + # 处理黑话条目,路由到 jargon_miner(即使没有表达方式也要处理黑话) if jargon_entries: - await self._process_jargon_entries(jargon_entries, random_msg, person_name_filter) - + await self._process_jargon_entries(jargon_entries, random_msg) + # 如果没有表达方式,直接返回 if not expressions: logger.info("过滤后没有可用的表达方式(style 与机器人名称重复)") return [] - + logger.info(f"学习的prompt: {prompt}") logger.info(f"学习的expressions: {expressions}") logger.info(f"学习的jargon_entries: {jargon_entries}") @@ -186,18 +178,17 @@ class ExpressionLearner: # 当前行的原始内容 current_msg = random_msg[line_index] - + # 过滤掉从bot自己发言中提取到的表达方式 if is_bot_message(current_msg): continue - + context = filter_message_content(current_msg.processed_plain_text or "") if not context: continue filtered_expressions.append((situation, style, context)) - - + learnt_expressions = filtered_expressions if learnt_expressions is None: @@ -281,37 +272,38 @@ class ExpressionLearner: # 如果解析失败,尝试修复中文引号问题 # 使用状态机方法,在 JSON 字符串值内部将中文引号替换为转义的英文引号 try: + def fix_chinese_quotes_in_json(text): """使用状态机修复 JSON 字符串值中的中文引号""" result = [] i = 0 in_string = False escape_next = False - + while i < len(text): char = text[i] - + if escape_next: # 当前字符是转义字符后的字符,直接添加 result.append(char) escape_next = False i += 1 continue - - if char == '\\': + + if char == "\\": # 转义字符 result.append(char) escape_next = True i += 1 continue - + if char == '"' and not escape_next: # 遇到英文引号,切换字符串状态 in_string = not in_string result.append(char) i += 1 continue - + if in_string: # 在字符串值内部,将中文引号替换为转义的英文引号 if char == '"': # 中文左引号 U+201C @@ -323,13 +315,13 @@ class ExpressionLearner: else: # 不在字符串内,直接添加 result.append(char) - + i += 1 - - return ''.join(result) - + + return "".join(result) + fixed_raw = fix_chinese_quotes_in_json(raw) - + # 再次尝试解析 if fixed_raw.startswith("[") and fixed_raw.endswith("]"): parsed = json.loads(fixed_raw) @@ -357,12 +349,12 @@ class ExpressionLearner: for item in parsed_list: if not isinstance(item, dict): continue - + # 检查是否是表达方式条目(有 situation 和 style) situation = str(item.get("situation", "")).strip() style = str(item.get("style", "")).strip() source_id = str(item.get("source_id", "")).strip() - + if situation and style and source_id: # 表达方式条目 expressions.append((situation, style, source_id)) @@ -511,75 +503,64 @@ class ExpressionLearner: logger.error(f"概括表达情境失败: {e}") return None - async def _process_jargon_entries( - self, - jargon_entries: List[Tuple[str, str]], - messages: List[Any], - person_name_filter: Optional[Callable[[str], bool]] = None - ) -> None: + async def _process_jargon_entries(self, jargon_entries: List[Tuple[str, str]], messages: List[Any]) -> None: """ 处理从 expression learner 提取的黑话条目,路由到 jargon_miner - + Args: jargon_entries: 黑话条目列表,每个元素是 (content, source_id) messages: 消息列表,用于构建上下文 - person_name_filter: 可选的过滤函数,用于检查内容是否包含人物名称 """ if not jargon_entries or not messages: return - + # 获取 jargon_miner 实例 jargon_miner = miner_manager.get_miner(self.chat_id) - + # 构建黑话条目格式,与 jargon_miner.run_once 中的格式一致 entries: List[Dict[str, List[str]]] = [] - + for content, source_id in jargon_entries: content = content.strip() if not content: continue - + # 检查是否包含机器人名称 if contains_bot_self_name(content): logger.info(f"跳过包含机器人昵称/别名的黑话: {content}") continue - - # 检查是否包含人物名称 - if person_name_filter and person_name_filter(content): - logger.info(f"跳过包含人物名称的黑话: {content}") - continue - + # 解析 source_id source_id_str = (source_id or "").strip() if not source_id_str.isdigit(): logger.warning(f"黑话条目 source_id 无效: content={content}, source_id={source_id_str}") continue - + # build_anonymous_messages 的编号从 1 开始 line_index = int(source_id_str) - 1 if line_index < 0 or line_index >= len(messages): logger.warning(f"黑话条目 source_id 超出范围: content={content}, source_id={source_id_str}") continue - + # 检查是否是机器人自己的消息 target_msg = messages[line_index] if is_bot_message(target_msg): logger.info(f"跳过引用机器人自身消息的黑话: content={content}, source_id={source_id_str}") continue - + # 构建上下文段落 context_paragraph = build_context_paragraph(messages, line_index) if not context_paragraph: logger.warning(f"黑话条目上下文为空: content={content}, source_id={source_id_str}") continue - + entries.append({"content": content, "raw_content": [context_paragraph]}) - + if not entries: return - + # 调用 jargon_miner 处理这些条目 - await jargon_miner.process_extracted_entries(entries, person_name_filter) + await jargon_miner.process_extracted_entries(entries) init_prompt() diff --git a/src/bw_learner/expression_reflector.py b/src/bw_learner/expression_reflector.py index dc651e55..c627b5b7 100644 --- a/src/bw_learner/expression_reflector.py +++ b/src/bw_learner/expression_reflector.py @@ -82,9 +82,7 @@ class ExpressionReflector: # 获取未检查的表达 try: logger.info("[Expression Reflection] 查询未检查且未拒绝的表达") - expressions = ( - Expression.select().where((~Expression.checked) & (~Expression.rejected)).limit(50) - ) + expressions = Expression.select().where((~Expression.checked) & (~Expression.rejected)).limit(50) expr_list = list(expressions) logger.info(f"[Expression Reflection] 找到 {len(expr_list)} 个候选表达") @@ -147,7 +145,7 @@ expression_reflector_manager = ExpressionReflectorManager() async def _check_tracker_exists(operator_config: str) -> bool: """检查指定 Operator 是否已有活跃的 Tracker""" - from src.express.reflect_tracker import reflect_tracker_manager + from src.bw_learner.reflect_tracker import reflect_tracker_manager chat_manager = get_chat_manager() chat_stream = None @@ -242,7 +240,7 @@ async def _send_to_operator(operator_config: str, text: str, expr: Expression): stream_id = chat_stream.stream_id # 注册 Tracker - from src.express.reflect_tracker import ReflectTracker, reflect_tracker_manager + from src.bw_learner.reflect_tracker import ReflectTracker, reflect_tracker_manager tracker = ReflectTracker(chat_stream=chat_stream, expression=expr, created_time=time.time()) reflect_tracker_manager.add_tracker(stream_id, tracker) diff --git a/src/bw_learner/expression_selector.py b/src/bw_learner/expression_selector.py index 931c5eb5..386d4fdf 100644 --- a/src/bw_learner/expression_selector.py +++ b/src/bw_learner/expression_selector.py @@ -128,9 +128,7 @@ class ExpressionSelector: # 查询所有相关chat_id的表达方式,排除 rejected=1 的,且只选择 count > 1 的 style_query = Expression.select().where( - (Expression.chat_id.in_(related_chat_ids)) - & (~Expression.rejected) - & (Expression.count > 1) + (Expression.chat_id.in_(related_chat_ids)) & (~Expression.rejected) & (Expression.count > 1) ) style_exprs = [ @@ -150,12 +148,15 @@ class ExpressionSelector: # 要求至少有10个 count > 1 的表达方式才进行选择 min_required = 10 if len(style_exprs) < min_required: - logger.info(f"聊天流 {chat_id} count > 1 的表达方式不足 {min_required} 个(实际 {len(style_exprs)} 个),不进行选择") + logger.info( + f"聊天流 {chat_id} count > 1 的表达方式不足 {min_required} 个(实际 {len(style_exprs)} 个),不进行选择" + ) return [], [] # 固定选择5个 select_count = 5 import random + selected_style = random.sample(style_exprs, select_count) # 更新last_active_time @@ -163,7 +164,9 @@ class ExpressionSelector: self.update_expressions_last_active_time(selected_style) selected_ids = [expr["id"] for expr in selected_style] - logger.debug(f"think_level=0: 从 {len(style_exprs)} 个 count>1 的表达方式中随机选择了 {len(selected_style)} 个") + logger.debug( + f"think_level=0: 从 {len(style_exprs)} 个 count>1 的表达方式中随机选择了 {len(selected_style)} 个" + ) return selected_style, selected_ids except Exception as e: @@ -186,9 +189,7 @@ class ExpressionSelector: related_chat_ids = self.get_related_chat_ids(chat_id) # 优化:一次性查询所有相关chat_id的表达方式,排除 rejected=1 的表达 - style_query = Expression.select().where( - (Expression.chat_id.in_(related_chat_ids)) & (~Expression.rejected) - ) + style_query = Expression.select().where((Expression.chat_id.in_(related_chat_ids)) & (~Expression.rejected)) style_exprs = [ { @@ -246,7 +247,9 @@ class ExpressionSelector: # 使用classic模式(随机选择+LLM选择) logger.debug(f"使用classic模式为聊天流 {chat_id} 选择表达方式,think_level={think_level}") - return await self._select_expressions_classic(chat_id, chat_info, max_num, target_message, reply_reason, think_level) + return await self._select_expressions_classic( + chat_id, chat_info, max_num, target_message, reply_reason, think_level + ) async def _select_expressions_classic( self, @@ -275,14 +278,12 @@ class ExpressionSelector: # think_level == 0: 只选择 count > 1 的项目,随机选10个,不进行LLM选择 if think_level == 0: return self._select_expressions_simple(chat_id, max_num) - + # think_level == 1: 先选高count,再从所有表达方式中随机抽样 # 1. 获取所有表达方式并分离 count > 1 和 count <= 1 的 related_chat_ids = self.get_related_chat_ids(chat_id) - style_query = Expression.select().where( - (Expression.chat_id.in_(related_chat_ids)) & (~Expression.rejected) - ) - + style_query = Expression.select().where((Expression.chat_id.in_(related_chat_ids)) & (~Expression.rejected)) + all_style_exprs = [ { "id": expr.id, @@ -299,29 +300,33 @@ class ExpressionSelector: # 分离 count > 1 和 count <= 1 的表达方式 high_count_exprs = [expr for expr in all_style_exprs if (expr.get("count", 1) or 1) > 1] - + # 根据 think_level 设置要求(仅支持 0/1,0 已在上方返回) min_high_count = 10 min_total_count = 10 select_high_count = 5 select_random_count = 5 - + # 检查数量要求 if len(high_count_exprs) < min_high_count: - logger.info(f"聊天流 {chat_id} count > 1 的表达方式不足 {min_high_count} 个(实际 {len(high_count_exprs)} 个),不进行选择") + logger.info( + f"聊天流 {chat_id} count > 1 的表达方式不足 {min_high_count} 个(实际 {len(high_count_exprs)} 个),不进行选择" + ) return [], [] - + if len(all_style_exprs) < min_total_count: - logger.info(f"聊天流 {chat_id} 总表达方式不足 {min_total_count} 个(实际 {len(all_style_exprs)} 个),不进行选择") + logger.info( + f"聊天流 {chat_id} 总表达方式不足 {min_total_count} 个(实际 {len(all_style_exprs)} 个),不进行选择" + ) return [], [] - + # 先选取高count的表达方式 selected_high = weighted_sample(high_count_exprs, min(len(high_count_exprs), select_high_count)) - + # 然后从所有表达方式中随机抽样(使用加权抽样) remaining_num = select_random_count selected_random = weighted_sample(all_style_exprs, min(len(all_style_exprs), remaining_num)) - + # 合并候选池(去重,避免重复) candidate_exprs = selected_high.copy() candidate_ids = {expr["id"] for expr in candidate_exprs} @@ -329,9 +334,10 @@ class ExpressionSelector: if expr["id"] not in candidate_ids: candidate_exprs.append(expr) candidate_ids.add(expr["id"]) - + # 打乱顺序,避免高count的都在前面 import random + random.shuffle(candidate_exprs) # 2. 构建所有表达方式的索引和情境列表 @@ -351,7 +357,7 @@ class ExpressionSelector: all_situations_str = "\n".join(all_situations) if target_message: - target_message_str = f",现在你想要对这条消息进行回复:\"{target_message}\"" + target_message_str = f',现在你想要对这条消息进行回复:"{target_message}"' target_message_extra_block = "4.考虑你要回复的目标消息" else: target_message_str = "" diff --git a/src/bw_learner/jargon_explainer.py b/src/bw_learner/jargon_explainer.py index ac62fa5f..207a080a 100644 --- a/src/bw_learner/jargon_explainer.py +++ b/src/bw_learner/jargon_explainer.py @@ -8,7 +8,12 @@ from src.llm_models.utils_model import LLMRequest from src.config.config import model_config, global_config from src.chat.utils.prompt_builder import Prompt, global_prompt_manager from src.bw_learner.jargon_miner import search_jargon -from src.bw_learner.learner_utils import is_bot_message, contains_bot_self_name, parse_chat_id_list, chat_id_list_contains +from src.bw_learner.learner_utils import ( + is_bot_message, + contains_bot_self_name, + parse_chat_id_list, + chat_id_list_contains, +) logger = get_logger("jargon") @@ -357,4 +362,4 @@ async def retrieve_concepts_with_jargon(concepts: List[str], chat_id: str) -> st if results: return "【概念检索结果】\n" + "\n".join(results) + "\n" - return "" \ No newline at end of file + return "" diff --git a/src/bw_learner/jargon_miner.py b/src/bw_learner/jargon_miner.py index 78c5f0dc..af2c6361 100644 --- a/src/bw_learner/jargon_miner.py +++ b/src/bw_learner/jargon_miner.py @@ -1,4 +1,3 @@ -import time import json import asyncio import random @@ -14,7 +13,6 @@ from src.config.config import model_config, global_config from src.chat.message_receive.chat_stream import get_chat_manager from src.chat.utils.chat_message_builder import ( build_readable_messages_with_id, - get_raw_msg_by_timestamp_with_chat_inclusive, ) from src.chat.utils.prompt_builder import Prompt, global_prompt_manager from src.bw_learner.learner_utils import ( @@ -33,23 +31,23 @@ logger = get_logger("jargon") def _is_single_char_jargon(content: str) -> bool: """ 判断是否是单字黑话(单个汉字、英文或数字) - + Args: content: 词条内容 - + Returns: bool: 如果是单字黑话返回True,否则返回False """ if not content or len(content) != 1: return False - + char = content[0] # 判断是否是单个汉字、单个英文字母或单个数字 return ( - '\u4e00' <= char <= '\u9fff' or # 汉字 - 'a' <= char <= 'z' or # 小写字母 - 'A' <= char <= 'Z' or # 大写字母 - '0' <= char <= '9' # 数字 + "\u4e00" <= char <= "\u9fff" # 汉字 + or "a" <= char <= "z" # 小写字母 + or "A" <= char <= "Z" # 大写字母 + or "0" <= char <= "9" # 数字 ) @@ -195,7 +193,7 @@ class JargonMiner: model_set=model_config.model_task_config.utils, request_type="jargon.extract", ) - + self.llm_inference = LLMRequest( model_set=model_config.model_task_config.utils, request_type="jargon.inference", @@ -207,7 +205,7 @@ class JargonMiner: self.stream_name = stream_name if stream_name else self.chat_id self.cache_limit = 50 self.cache: OrderedDict[str, None] = OrderedDict() - + # 黑话提取锁,防止并发执行 self._extraction_lock = asyncio.Lock() @@ -299,17 +297,19 @@ class JargonMiner: # 获取当前count和上一次的meaning current_count = jargon_obj.count or 0 previous_meaning = jargon_obj.meaning or "" - + # 当count为24, 60时,随机移除一半的raw_content项目 if current_count in [24, 60] and len(raw_content_list) > 1: # 计算要保留的数量(至少保留1个) keep_count = max(1, len(raw_content_list) // 2) raw_content_list = random.sample(raw_content_list, keep_count) - logger.info(f"jargon {content} count={current_count},随机移除后剩余 {len(raw_content_list)} 个raw_content项目") + logger.info( + f"jargon {content} count={current_count},随机移除后剩余 {len(raw_content_list)} 个raw_content项目" + ) # 步骤1: 基于raw_content和content推断 raw_content_text = "\n".join(raw_content_list) - + # 当count为24, 60, 100时,在prompt中放入上一次推断出的meaning作为参考 previous_meaning_section = "" previous_meaning_instruction = "" @@ -318,8 +318,10 @@ class JargonMiner: **上一次推断的含义(仅供参考)** {previous_meaning} """ - previous_meaning_instruction = "- 请参考上一次推断的含义,结合新的上下文信息,给出更准确或更新的推断结果" - + previous_meaning_instruction = ( + "- 请参考上一次推断的含义,结合新的上下文信息,给出更准确或更新的推断结果" + ) + prompt1 = await global_prompt_manager.format_prompt( "jargon_inference_with_context_prompt", content=content, @@ -485,7 +487,7 @@ class JargonMiner: ) -> None: """ 运行一次黑话提取 - + Args: messages: 外部传入的消息列表(必需) person_name_filter: 可选的过滤函数,用于检查内容是否包含人物名称 @@ -660,7 +662,9 @@ class JargonMiner: if obj.raw_content: try: existing_raw_content = ( - json.loads(obj.raw_content) if isinstance(obj.raw_content, str) else obj.raw_content + json.loads(obj.raw_content) + if isinstance(obj.raw_content, str) + else obj.raw_content ) if not isinstance(existing_raw_content, list): existing_raw_content = [existing_raw_content] if existing_raw_content else [] @@ -740,14 +744,14 @@ class JargonMiner: ) -> None: """ 处理已提取的黑话条目(从 expression_learner 路由过来的) - + Args: entries: 黑话条目列表,每个元素格式为 {"content": "...", "raw_content": [...]} person_name_filter: 可选的过滤函数,用于检查内容是否包含人物名称 """ if not entries: return - + try: # 去重并合并raw_content(按 content 聚合) merged_entries: OrderedDict[str, Dict[str, List[str]]] = OrderedDict() @@ -899,8 +903,6 @@ class JargonMinerManager: miner_manager = JargonMinerManager() - - def search_jargon( keyword: str, chat_id: Optional[str] = None, limit: int = 10, case_sensitive: bool = False, fuzzy: bool = True ) -> List[Dict[str, str]]: diff --git a/src/bw_learner/message_recorder.py b/src/bw_learner/message_recorder.py index 8c13013f..b31ab153 100644 --- a/src/bw_learner/message_recorder.py +++ b/src/bw_learner/message_recorder.py @@ -1,62 +1,39 @@ import time import asyncio -from typing import List, Any, Optional -from collections import OrderedDict -from dataclasses import dataclass +from typing import List, Any from src.common.logger import get_logger from src.config.config import global_config from src.chat.message_receive.chat_stream import get_chat_manager from src.chat.utils.chat_message_builder import get_raw_msg_by_timestamp_with_chat_inclusive from src.bw_learner.expression_learner import expression_learner_manager from src.bw_learner.jargon_miner import miner_manager -from src.person_info.person_info import Person logger = get_logger("bw_learner") -@dataclass -class PersonInfo: - """参与聊天的人物信息""" - user_id: str - user_platform: str - user_nickname: str - user_cardname: Optional[str] - person_name: str - last_seen_time: float # 最后发言时间 - - def get_unique_key(self) -> str: - """获取唯一标识(用于去重)""" - return f"{self.user_platform}:{self.user_id}" - - class MessageRecorder: """ 统一的消息记录器,负责管理时间窗口和消息提取,并将消息分发给 expression_learner 和 jargon_miner """ - + def __init__(self, chat_id: str) -> None: self.chat_id = chat_id self.chat_stream = get_chat_manager().get_stream(chat_id) self.chat_name = get_chat_manager().get_stream_name(chat_id) or chat_id - + # 维护每个chat的上次提取时间 self.last_extraction_time: float = time.time() - + # 提取锁,防止并发执行 self._extraction_lock = asyncio.Lock() - - # 维护参与该chat_id的人物列表(最多30个,使用OrderedDict保持插入顺序) - # key: f"{platform}:{user_id}", value: PersonInfo - self._person_list: OrderedDict[str, PersonInfo] = OrderedDict() - self._max_person_count = 30 - + # 获取 expression 和 jargon 的配置参数 self._init_parameters() - + # 获取 expression_learner 和 jargon_miner 实例 self.expression_learner = expression_learner_manager.get_expression_learner(chat_id) self.jargon_miner = miner_manager.get_miner(chat_id) - + def _init_parameters(self) -> None: """初始化提取参数""" # 获取 expression 配置 @@ -65,17 +42,17 @@ class MessageRecorder: ) self.min_messages_for_extraction = 30 self.min_extraction_interval = 60 - + logger.debug( f"MessageRecorder 初始化: chat_id={self.chat_id}, " f"min_messages={self.min_messages_for_extraction}, " f"min_interval={self.min_extraction_interval}" ) - + def should_trigger_extraction(self) -> bool: """ 检查是否应该触发消息提取 - + Returns: bool: 是否应该触发提取 """ @@ -83,19 +60,19 @@ class MessageRecorder: time_diff = time.time() - self.last_extraction_time if time_diff < self.min_extraction_interval: return False - + # 检查消息数量 recent_messages = get_raw_msg_by_timestamp_with_chat_inclusive( chat_id=self.chat_id, timestamp_start=self.last_extraction_time, timestamp_end=time.time(), ) - + if not recent_messages or len(recent_messages) < self.min_messages_for_extraction: return False - + return True - + async def extract_and_distribute(self) -> None: """ 提取消息并分发给 expression_learner 和 jargon_miner @@ -105,46 +82,40 @@ class MessageRecorder: # 在锁内检查,避免并发触发 if not self.should_trigger_extraction(): return - + # 检查 chat_stream 是否存在 if not self.chat_stream: return - + # 记录本次提取的时间窗口,避免重复提取 extraction_start_time = self.last_extraction_time extraction_end_time = time.time() - + # 立即更新提取时间,防止并发触发 self.last_extraction_time = extraction_end_time - + try: logger.info(f"在聊天流 {self.chat_name} 开始统一消息提取和分发") - + # 拉取提取窗口内的消息 messages = get_raw_msg_by_timestamp_with_chat_inclusive( chat_id=self.chat_id, timestamp_start=extraction_start_time, timestamp_end=extraction_end_time, ) - + if not messages: logger.debug(f"聊天流 {self.chat_name} 没有新消息,跳过提取") return - + # 按时间排序,确保顺序一致 messages = sorted(messages, key=lambda msg: msg.time or 0) - - # 更新参与聊天的人物列表 - self._update_person_list(messages) - - logger.info(f"聊天流 {self.chat_name} 的人物列表: {self._person_list}") - + logger.info( f"聊天流 {self.chat_name} 提取到 {len(messages)} 条消息," f"时间窗口: {extraction_start_time:.2f} - {extraction_end_time:.2f}" ) - - + # 分别触发 expression_learner 和 jargon_miner 的处理 # 传递提取的消息,避免它们重复获取 # 触发 expression 学习(如果启用) @@ -152,40 +123,35 @@ class MessageRecorder: asyncio.create_task( self._trigger_expression_learning(extraction_start_time, extraction_end_time, messages) ) - + # 触发 jargon 提取(如果启用),传递消息 # if self.enable_jargon_learning: - # asyncio.create_task( - # self._trigger_jargon_extraction(extraction_start_time, extraction_end_time, messages) - # ) - + # asyncio.create_task( + # self._trigger_jargon_extraction(extraction_start_time, extraction_end_time, messages) + # ) + except Exception as e: logger.error(f"为聊天流 {self.chat_name} 提取和分发消息失败: {e}") import traceback + traceback.print_exc() # 即使失败也保持时间戳更新,避免频繁重试 - + async def _trigger_expression_learning( - self, - timestamp_start: float, - timestamp_end: float, - messages: List[Any] + self, timestamp_start: float, timestamp_end: float, messages: List[Any] ) -> None: """ 触发 expression 学习,使用指定的消息列表 - + Args: timestamp_start: 开始时间戳 timestamp_end: 结束时间戳 messages: 消息列表 """ try: - # 传递消息和过滤函数给 ExpressionLearner - learnt_style = await self.expression_learner.learn_and_store( - messages=messages, - person_name_filter=self.contains_person_name - ) - + # 传递消息给 ExpressionLearner(必需参数) + learnt_style = await self.expression_learner.learn_and_store(messages=messages) + if learnt_style: logger.info(f"聊天流 {self.chat_name} 表达学习完成") else: @@ -193,148 +159,37 @@ class MessageRecorder: except Exception as e: logger.error(f"为聊天流 {self.chat_name} 触发表达学习失败: {e}") import traceback + traceback.print_exc() - + async def _trigger_jargon_extraction( - self, - timestamp_start: float, - timestamp_end: float, - messages: List[Any] + self, timestamp_start: float, timestamp_end: float, messages: List[Any] ) -> None: """ 触发 jargon 提取,使用指定的消息列表 - + Args: timestamp_start: 开始时间戳 timestamp_end: 结束时间戳 messages: 消息列表 """ try: - # 传递消息和过滤函数给 JargonMiner - await self.jargon_miner.run_once( - messages=messages, - person_name_filter=self.contains_person_name - ) - + # 传递消息给 JargonMiner,避免它重复获取 + await self.jargon_miner.run_once(messages=messages) + except Exception as e: logger.error(f"为聊天流 {self.chat_name} 触发黑话提取失败: {e}") import traceback + traceback.print_exc() - - def _update_person_list(self, messages: List[Any]) -> None: - """ - 从消息中提取人物信息并更新人物列表 - - Args: - messages: 消息列表 - """ - for msg in messages: - # 获取消息发送者信息 - # 消息对象可能是 DatabaseMessages,它有 user_info 属性 - if hasattr(msg, 'user_info'): - # DatabaseMessages 类型 - user_info = msg.user_info - user_id = getattr(user_info, 'user_id', None) or '' - user_platform = getattr(user_info, 'platform', None) or '' - user_nickname = getattr(user_info, 'user_nickname', None) or '' - user_cardname = getattr(user_info, 'user_cardname', None) - else: - # 直接属性访问 - user_id = getattr(msg, 'user_id', None) or '' - user_platform = getattr(msg, 'user_platform', None) or '' - user_nickname = getattr(msg, 'user_nickname', None) or '' - user_cardname = getattr(msg, 'user_cardname', None) - - msg_time = getattr(msg, 'time', time.time()) - - # 检查必要信息 - if not user_id or not user_platform: - continue - - # 获取 person_name - try: - person = Person(platform=user_platform, user_id=str(user_id)) - person_name = person.person_name or user_nickname or (user_cardname if user_cardname else "未知用户") - except Exception as e: - logger.info(f"获取person_name失败: {e}, 使用nickname") - person_name = user_nickname or (user_cardname if user_cardname else "未知用户") - - # 生成唯一key - unique_key = f"{user_platform}:{user_id}" - - # 如果已存在,更新最后发言时间 - if unique_key in self._person_list: - self._person_list[unique_key].last_seen_time = msg_time - # 移动到末尾(表示最近活跃) - self._person_list.move_to_end(unique_key) - else: - # 如果超过最大数量,移除最早的(最前面的) - if len(self._person_list) >= self._max_person_count: - oldest_key = next(iter(self._person_list)) - del self._person_list[oldest_key] - logger.info(f"人物列表已满,移除最早的人物: {oldest_key}") - - # 添加新人物 - person_info = PersonInfo( - user_id=str(user_id), - user_platform=user_platform, - user_nickname=user_nickname or "", - user_cardname=user_cardname, - person_name=person_name, - last_seen_time=msg_time - ) - self._person_list[unique_key] = person_info - logger.info(f"添加新人物到列表: {unique_key}, person_name={person_name}") - - def contains_person_name(self, content: str) -> bool: - """ - 检查内容是否包含任何参与聊天的人物的名称或昵称 - - Args: - content: 要检查的内容 - - Returns: - bool: 如果包含任何人物名称或昵称,返回True - """ - if not content or not self._person_list: - return False - - content_lower = content.strip().lower() - if not content_lower: - return False - - # 检查所有人物 - for person_info in self._person_list.values(): - # 检查 person_name - if person_info.person_name: - person_name_lower = person_info.person_name.strip().lower() - if person_name_lower and person_name_lower in content_lower: - logger.debug(f"内容包含person_name: {person_info.person_name} in {content}") - return True - - # 检查 user_nickname - if person_info.user_nickname: - nickname_lower = person_info.user_nickname.strip().lower() - if nickname_lower and nickname_lower in content_lower: - logger.debug(f"内容包含nickname: {person_info.user_nickname} in {content}") - return True - - # 检查 user_cardname(群昵称) - if person_info.user_cardname: - cardname_lower = person_info.user_cardname.strip().lower() - if cardname_lower and cardname_lower in content_lower: - logger.debug(f"内容包含cardname: {person_info.user_cardname} in {content}") - return True - - return False class MessageRecorderManager: """MessageRecorder 管理器""" - + def __init__(self) -> None: self._recorders: dict[str, MessageRecorder] = {} - + def get_recorder(self, chat_id: str) -> MessageRecorder: """获取或创建指定 chat_id 的 MessageRecorder""" if chat_id not in self._recorders: @@ -349,10 +204,9 @@ recorder_manager = MessageRecorderManager() async def extract_and_distribute_messages(chat_id: str) -> None: """ 统一的消息提取和分发入口函数 - + Args: chat_id: 聊天流ID """ recorder = recorder_manager.get_recorder(chat_id) await recorder.extract_and_distribute() - diff --git a/src/chat/brain_chat/brain_chat.py b/src/chat/brain_chat/brain_chat.py index ae05e5dd..4a22628e 100644 --- a/src/chat/brain_chat/brain_chat.py +++ b/src/chat/brain_chat/brain_chat.py @@ -176,19 +176,19 @@ class BrainChatting: # 如果有新消息,更新 last_read_time if len(recent_messages_list) >= 1: self.last_read_time = time.time() - + # 总是执行一次思考迭代(不管有没有新消息) # wait 动作会在其内部等待,不需要在这里处理 should_continue = await self._observe(recent_messages_list=recent_messages_list) - + if not should_continue: # 选择了 complete_talk,返回 False 表示需要等待新消息 return False - + # 继续下一次迭代(除非选择了 complete_talk) # 短暂等待后再继续,避免过于频繁的循环 await asyncio.sleep(0.1) - + return True async def _send_and_store_reply( @@ -328,9 +328,7 @@ class BrainChatting: ) # 检查是否有 complete_talk 动作(会停止后续迭代) - has_complete_talk = any( - action.action_type == "complete_talk" for action in action_to_use_info - ) + has_complete_talk = any(action.action_type == "complete_talk" for action in action_to_use_info) # 并行执行所有动作 action_tasks = [ @@ -430,12 +428,12 @@ class BrainChatting: await asyncio.sleep(3) self._loop_task = asyncio.create_task(self._main_chat_loop()) logger.error(f"{self.log_prefix} 结束了当前聊天循环") - + async def _wait_for_new_message(self): """等待新消息到达""" last_check_time = self.last_read_time check_interval = 1.0 # 每秒检查一次 - + while self.running: # 检查是否有新消息 recent_messages_list = message_api.get_messages_by_time_in_chat( @@ -448,13 +446,13 @@ class BrainChatting: filter_command=False, filter_intercept_message_level=1, ) - + # 如果有新消息,更新 last_read_time 并返回 if len(recent_messages_list) >= 1: self.last_read_time = time.time() logger.info(f"{self.log_prefix} 检测到新消息,恢复循环") return - + # 等待一段时间后再次检查 await asyncio.sleep(check_interval) @@ -660,9 +658,9 @@ class BrainChatting: except (ValueError, TypeError): logger.warning(f"{self.log_prefix} wait_seconds 参数格式错误,使用默认值 5 秒") wait_seconds = 5 - + logger.info(f"{self.log_prefix} 执行 wait 动作,等待 {wait_seconds} 秒") - + # 记录动作信息 await database_api.store_action_info( chat_stream=self.chat_stream, @@ -673,12 +671,12 @@ class BrainChatting: action_data={"reason": reason, "wait_seconds": wait_seconds}, action_name="wait", ) - + # 等待指定时间 await asyncio.sleep(wait_seconds) - + logger.info(f"{self.log_prefix} wait 动作完成,继续下一次思考") - + # 这些动作本身不产生文本回复 self._last_successful_reply = False return { @@ -693,9 +691,9 @@ class BrainChatting: logger.debug(f"{self.log_prefix} 检测到 listening 动作,已合并到 wait,自动转换") # 使用默认等待时间 wait_seconds = 3 - + logger.info(f"{self.log_prefix} 执行 listening(转换为 wait)动作,等待 {wait_seconds} 秒") - + # 记录动作信息 await database_api.store_action_info( chat_stream=self.chat_stream, @@ -706,12 +704,12 @@ class BrainChatting: action_data={"reason": reason, "wait_seconds": wait_seconds}, action_name="listening", ) - + # 等待指定时间 await asyncio.sleep(wait_seconds) - + logger.info(f"{self.log_prefix} listening 动作完成,继续下一次思考") - + # 这些动作本身不产生文本回复 self._last_successful_reply = False return { diff --git a/src/chat/brain_chat/brain_planner.py b/src/chat/brain_chat/brain_planner.py index 7da5dc29..14d28575 100644 --- a/src/chat/brain_chat/brain_planner.py +++ b/src/chat/brain_chat/brain_planner.py @@ -147,7 +147,7 @@ class BrainPlanner: ) # 用于动作规划 self.last_obs_time_mark = 0.0 - + # 计划日志记录 self.plan_log: List[Tuple[str, float, List[ActionPlannerInfo]]] = [] @@ -203,9 +203,11 @@ class BrainPlanner: # 内部保留动作(不依赖插件系统) # 注意:listening 已合并到 wait 中,如果遇到 listening 则转换为 wait internal_action_names = ["complete_talk", "reply", "wait_time", "wait", "listening"] - - logger.debug(f"{self.log_prefix}动作验证: action={action}, internal={internal_action_names}, available={available_action_names}") - + + logger.debug( + f"{self.log_prefix}动作验证: action={action}, internal={internal_action_names}, available={available_action_names}" + ) + # 将 listening 转换为 wait(向后兼容) if action == "listening": logger.debug(f"{self.log_prefix}检测到 listening 动作,已合并到 wait,自动转换") @@ -521,7 +523,7 @@ class BrainPlanner: if json_objects: logger.info(f"{self.log_prefix}从响应中提取到{len(json_objects)}个JSON对象") for i, json_obj in enumerate(json_objects): - logger.info(f"{self.log_prefix}解析第{i+1}个JSON对象: {json_obj}") + logger.info(f"{self.log_prefix}解析第{i + 1}个JSON对象: {json_obj}") filtered_actions_list = list(filtered_actions.items()) for json_obj in json_objects: parsed_actions = self._parse_single_action(json_obj, message_id_list, filtered_actions_list) @@ -553,7 +555,9 @@ class BrainPlanner: return extracted_reasoning, actions - def _create_complete_talk(self, reasoning: str, available_actions: Dict[str, ActionInfo]) -> List[ActionPlannerInfo]: + def _create_complete_talk( + self, reasoning: str, available_actions: Dict[str, ActionInfo] + ) -> List[ActionPlannerInfo]: """创建complete_talk""" return [ ActionPlannerInfo( @@ -564,7 +568,7 @@ class BrainPlanner: available_actions=available_actions, ) ] - + def add_plan_log(self, reasoning: str, actions: List[ActionPlannerInfo]): """添加计划日志""" self.plan_log.append((reasoning, time.time(), actions)) diff --git a/src/chat/emoji_system/emoji_manager.py b/src/chat/emoji_system/emoji_manager.py index f7d132a3..af12bb1a 100644 --- a/src/chat/emoji_system/emoji_manager.py +++ b/src/chat/emoji_system/emoji_manager.py @@ -271,7 +271,7 @@ def _to_emoji_objects(data: Any) -> Tuple[List["MaiEmoji"], int]: emoji.description = emoji_data.description # Deserialize emotion string from DB to list - emoji.emotion = emoji_data.emotion.replace(",",",").split(",") if emoji_data.emotion else [] + emoji.emotion = emoji_data.emotion.replace(",", ",").split(",") if emoji_data.emotion else [] emoji.usage_count = emoji_data.usage_count db_last_used_time = emoji_data.last_used_time @@ -732,7 +732,7 @@ class EmojiManager: emoji_record = Emoji.get_or_none(Emoji.emoji_hash == emoji_hash) if emoji_record and emoji_record.emotion: logger.info(f"[缓存命中] 从数据库获取表情包情感标签: {emoji_record.emotion[:50]}...") - return emoji_record.emotion.replace(",",",").split(",") + return emoji_record.emotion.replace(",", ",").split(",") except Exception as e: logger.error(f"从数据库查询表情包情感标签时出错: {e}") @@ -993,7 +993,7 @@ class EmojiManager: ) # 处理情感列表 - emotions = [e.strip() for e in emotions_text.replace(",",",").split(",") if e.strip()] + emotions = [e.strip() for e in emotions_text.replace(",", ",").split(",") if e.strip()] # 根据情感标签数量随机选择 - 超过5个选3个,超过2个选2个 if len(emotions) > 5: diff --git a/src/chat/heart_flow/heartFC_chat.py b/src/chat/heart_flow/heartFC_chat.py index f700ff47..5fbddb7c 100644 --- a/src/chat/heart_flow/heartFC_chat.py +++ b/src/chat/heart_flow/heartFC_chat.py @@ -619,13 +619,13 @@ class HeartFChatting: think_level = 0 # 使用 action_reasoning(planner 的整体思考理由)作为 reply_reason planner_reasoning = action_planner_info.action_reasoning or reason - + record_replyer_action_temp( chat_id=self.stream_id, reason=reason, think_level=think_level, ) - + await database_api.store_action_info( chat_stream=self.chat_stream, action_build_into_prompt=False, diff --git a/src/chat/message_receive/bot.py b/src/chat/message_receive/bot.py index 14c49d04..c45ec105 100644 --- a/src/chat/message_receive/bot.py +++ b/src/chat/message_receive/bot.py @@ -123,7 +123,11 @@ class ChatBot: logger.warning(f"命令执行失败: {command_class.__name__} - {response}") # 根据命令的拦截设置决定是否继续处理消息 - return True, response, not bool(intercept_message_level) # 找到命令,根据intercept_message决定是否继续 + return ( + True, + response, + not bool(intercept_message_level), + ) # 找到命令,根据intercept_message决定是否继续 except Exception as e: logger.error(f"执行命令时出错: {command_class.__name__} - {e}") diff --git a/src/chat/message_receive/message.py b/src/chat/message_receive/message.py index 727dd3b0..d093e07e 100644 --- a/src/chat/message_receive/message.py +++ b/src/chat/message_receive/message.py @@ -213,6 +213,68 @@ class MessageRecv(Message): } """ return "" + elif segment.type == "video_card": + # 处理视频卡片消息 + self.is_picid = False + self.is_emoji = False + self.is_voice = False + if isinstance(segment.data, dict): + file_name = segment.data.get("file", "未知视频") + file_size = segment.data.get("file_size", "") + url = segment.data.get("url", "") + text = f"[视频: {file_name}" + if file_size: + text += f", 大小: {file_size}字节" + text += "]" + if url: + text += f" 链接: {url}" + return text + return "[视频]" + elif segment.type == "music_card": + # 处理音乐卡片消息 + self.is_picid = False + self.is_emoji = False + self.is_voice = False + if isinstance(segment.data, dict): + title = segment.data.get("title", "未知歌曲") + singer = segment.data.get("singer", "") + tag = segment.data.get("tag", "") # 音乐来源,如"网易云音乐" + jump_url = segment.data.get("jump_url", "") + music_url = segment.data.get("music_url", "") + text = f"[音乐: {title}" + if singer: + text += f" - {singer}" + if tag: + text += f" ({tag})" + text += "]" + if jump_url: + text += f" 跳转链接: {jump_url}" + if music_url: + text += f" 音乐链接: {music_url}" + return text + return "[音乐]" + elif segment.type == "miniapp_card": + # 处理小程序分享卡片(如B站视频分享) + self.is_picid = False + self.is_emoji = False + self.is_voice = False + if isinstance(segment.data, dict): + title = segment.data.get("title", "") # 小程序名称 + desc = segment.data.get("desc", "") # 内容描述 + source_url = segment.data.get("source_url", "") # 原始链接 + url = segment.data.get("url", "") # 小程序链接 + text = "[小程序分享" + if title: + text += f" - {title}" + text += "]" + if desc: + text += f" {desc}" + if source_url: + text += f" 链接: {source_url}" + elif url: + text += f" 链接: {url}" + return text + return "[小程序分享]" else: return "" except Exception as e: diff --git a/src/chat/message_receive/uni_message_sender.py b/src/chat/message_receive/uni_message_sender.py index 3e33511f..a45ac515 100644 --- a/src/chat/message_receive/uni_message_sender.py +++ b/src/chat/message_receive/uni_message_sender.py @@ -42,22 +42,21 @@ def is_webui_virtual_group(group_id: str) -> bool: def parse_message_segments(segment) -> list: """解析消息段,转换为 WebUI 可用的格式 - + 参考 NapCat 适配器的消息解析逻辑 - + Args: segment: Seg 消息段对象 - + Returns: list: 消息段列表,每个元素为 {"type": "...", "data": ...} """ - from maim_message import Seg - + result = [] - + if segment is None: return result - + if segment.type == "seglist": # 处理消息段列表 if segment.data: @@ -112,15 +111,19 @@ def parse_message_segments(segment) -> list: forward_items = [] if segment.data: for item in segment.data: - forward_items.append({ - "content": parse_message_segments(item.get("message_segment", {})) if isinstance(item, dict) else [] - }) + forward_items.append( + { + "content": parse_message_segments(item.get("message_segment", {})) + if isinstance(item, dict) + else [] + } + ) result.append({"type": "forward", "data": forward_items}) else: # 未知类型,尝试作为文本处理 if segment.data: result.append({"type": "unknown", "original_type": segment.type, "data": str(segment.data)}) - + return result @@ -134,7 +137,7 @@ async def _send_message(message: MessageSending, show_log=True) -> bool: # 检查是否是 WebUI 平台的消息,或者是 WebUI 虚拟群的消息 chat_manager, webui_platform = get_webui_chat_broadcaster() is_webui_message = (platform == webui_platform) or is_webui_virtual_group(group_id) - + if is_webui_message and chat_manager is not None: # WebUI 聊天室消息(包括虚拟身份模式),通过 WebSocket 广播 import time @@ -142,7 +145,7 @@ async def _send_message(message: MessageSending, show_log=True) -> bool: # 解析消息段,获取富文本内容 message_segments = parse_message_segments(message.message_segment) - + # 判断消息类型 # 如果只有一个文本段,使用简单的 text 类型 # 否则使用 rich 类型,包含完整的消息段 diff --git a/src/chat/planner_actions/planner.py b/src/chat/planner_actions/planner.py index 2c58de7d..bc20c552 100644 --- a/src/chat/planner_actions/planner.py +++ b/src/chat/planner_actions/planner.py @@ -77,8 +77,7 @@ target_message_id为必填,表示触发消息的id ```""", "planner_prompt", ) - - + Prompt( """ {action_name} diff --git a/src/chat/replyer/group_generator.py b/src/chat/replyer/group_generator.py index 57f64dba..3c4c5440 100644 --- a/src/chat/replyer/group_generator.py +++ b/src/chat/replyer/group_generator.py @@ -250,7 +250,12 @@ class DefaultReplyer: # 使用从处理器传来的选中表达方式 # 使用模型预测选择表达方式 selected_expressions, selected_ids = await expression_selector.select_suitable_expressions( - self.chat_stream.stream_id, chat_history, max_num=8, target_message=target, reply_reason=reply_reason, think_level=think_level + self.chat_stream.stream_id, + chat_history, + max_num=8, + target_message=target, + reply_reason=reply_reason, + think_level=think_level, ) if selected_expressions: @@ -273,7 +278,6 @@ class DefaultReplyer: return f"{expression_habits_title}\n{expression_habits_block}", selected_ids - async def build_tool_info(self, chat_history: str, sender: str, target: str, enable_tool: bool = True) -> str: """构建工具信息块 @@ -788,7 +792,8 @@ class DefaultReplyer: # 并行执行八个构建任务(包括黑话解释) task_results = await asyncio.gather( self._time_and_run_task( - self.build_expression_habits(chat_talking_prompt_short, target, reply_reason, think_level=think_level), "expression_habits" + self.build_expression_habits(chat_talking_prompt_short, target, reply_reason, think_level=think_level), + "expression_habits", ), self._time_and_run_task( self.build_tool_info(chat_talking_prompt_short, sender, target, enable_tool=enable_tool), "tool_info" @@ -980,7 +985,6 @@ class DefaultReplyer: else: reply_target_block = "" - chat_target_1 = await global_prompt_manager.get_prompt_async("chat_target_group1") chat_target_2 = await global_prompt_manager.get_prompt_async("chat_target_group2") diff --git a/src/chat/replyer/private_generator.py b/src/chat/replyer/private_generator.py index 9ff340d9..a9b78c28 100644 --- a/src/chat/replyer/private_generator.py +++ b/src/chat/replyer/private_generator.py @@ -287,7 +287,6 @@ class PrivateReplyer: return f"{expression_habits_title}\n{expression_habits_block}", selected_ids - async def build_tool_info(self, chat_history: str, sender: str, target: str, enable_tool: bool = True) -> str: """构建工具信息块 @@ -907,16 +906,11 @@ class PrivateReplyer: else: reply_target_block = "" - chat_target_name = "对方" if self.chat_target_info: chat_target_name = self.chat_target_info.person_name or self.chat_target_info.user_nickname or "对方" - chat_target_1 = await global_prompt_manager.format_prompt( - "chat_target_private1", sender_name=chat_target_name - ) - chat_target_2 = await global_prompt_manager.format_prompt( - "chat_target_private2", sender_name=chat_target_name - ) + chat_target_1 = await global_prompt_manager.format_prompt("chat_target_private1", sender_name=chat_target_name) + chat_target_2 = await global_prompt_manager.format_prompt("chat_target_private2", sender_name=chat_target_name) template_name = "default_expressor_prompt" diff --git a/src/chat/replyer/prompt/replyer_private_prompt.py b/src/chat/replyer/prompt/replyer_private_prompt.py index c251d1a1..7dfd54e7 100644 --- a/src/chat/replyer/prompt/replyer_private_prompt.py +++ b/src/chat/replyer/prompt/replyer_private_prompt.py @@ -1,8 +1,9 @@ from src.chat.utils.prompt_builder import Prompt + def init_replyer_private_prompt(): Prompt( - """{knowledge_prompt}{tool_info_block}{extra_info_block} + """{knowledge_prompt}{tool_info_block}{extra_info_block} {expression_habits_block}{memory_retrieval}{jargon_explanation} 你正在和{sender_name}聊天,这是你们之前聊的内容: @@ -17,9 +18,9 @@ def init_replyer_private_prompt(): {reply_style} 请注意不要输出多余内容(包括前后缀,冒号和引号,括号,表情等),只输出回复内容。 {moderation_prompt}不要输出多余内容(包括前后缀,冒号和引号,括号,表情包,at或 @等 )。""", - "private_replyer_prompt", - ) - + "private_replyer_prompt", + ) + Prompt( """{knowledge_prompt}{tool_info_block}{extra_info_block} {expression_habits_block}{memory_retrieval}{jargon_explanation} @@ -37,4 +38,4 @@ def init_replyer_private_prompt(): {moderation_prompt}不要输出多余内容(包括冒号和引号,括号,表情包,at或 @等 )。 """, "private_replyer_self_prompt", - ) \ No newline at end of file + ) diff --git a/src/chat/replyer/prompt/replyer_prompt.py b/src/chat/replyer/prompt/replyer_prompt.py index 858015ac..3689cf8f 100644 --- a/src/chat/replyer/prompt/replyer_prompt.py +++ b/src/chat/replyer/prompt/replyer_prompt.py @@ -23,7 +23,7 @@ def init_replyer_prompt(): 现在,你说:""", "replyer_prompt_0", ) - + Prompt( """{knowledge_prompt}{tool_info_block}{extra_info_block} {expression_habits_block}{memory_retrieval}{jargon_explanation} @@ -44,4 +44,3 @@ def init_replyer_prompt(): 现在,你说:""", "replyer_prompt", ) - diff --git a/src/chat/utils/chat_message_builder.py b/src/chat/utils/chat_message_builder.py index 6a634fb4..156322ae 100644 --- a/src/chat/utils/chat_message_builder.py +++ b/src/chat/utils/chat_message_builder.py @@ -311,7 +311,10 @@ def get_raw_msg_before_timestamp_with_chat( filter_query = {"chat_id": chat_id, "time": {"$lt": timestamp}} sort_order = [("time", 1)] return find_messages( - message_filter=filter_query, sort=sort_order, limit=limit, filter_intercept_message_level=filter_intercept_message_level + message_filter=filter_query, + sort=sort_order, + limit=limit, + filter_intercept_message_level=filter_intercept_message_level, ) diff --git a/src/chat/utils/statistic.py b/src/chat/utils/statistic.py index 4a115e06..20c0843b 100644 --- a/src/chat/utils/statistic.py +++ b/src/chat/utils/statistic.py @@ -746,7 +746,7 @@ class StatisticOutputTask(AsyncTask): data_fmt = "{:<32} {:>10} {:>12} {:>12} {:>12} {:>9.2f}¥ {:>10.1f} {:>10.1f} {:>12} {:>12}" total_replies = stats.get(TOTAL_REPLY_CNT, 0) - + output = [ "按模型分类统计:", " 模型名称 调用次数 输入Token 输出Token Token总量 累计花费 平均耗时(秒) 标准差(秒) 每次回复平均调用次数 每次回复平均Token数", @@ -759,11 +759,11 @@ class StatisticOutputTask(AsyncTask): cost = stats[COST_BY_MODEL][model_name] avg_time_cost = stats[AVG_TIME_COST_BY_MODEL][model_name] std_time_cost = stats[STD_TIME_COST_BY_MODEL][model_name] - + # 计算每次回复平均值 avg_count_per_reply = count / total_replies if total_replies > 0 else 0.0 avg_tokens_per_reply = tokens / total_replies if total_replies > 0 else 0.0 - + # 格式化大数字 formatted_count = _format_large_number(count) formatted_in_tokens = _format_large_number(in_tokens) @@ -771,7 +771,7 @@ class StatisticOutputTask(AsyncTask): formatted_tokens = _format_large_number(tokens) formatted_avg_count = _format_large_number(avg_count_per_reply) if total_replies > 0 else "N/A" formatted_avg_tokens = _format_large_number(avg_tokens_per_reply) if total_replies > 0 else "N/A" - + output.append( data_fmt.format( name, @@ -800,7 +800,7 @@ class StatisticOutputTask(AsyncTask): data_fmt = "{:<32} {:>10} {:>12} {:>12} {:>12} {:>9.2f}¥ {:>10.1f} {:>10.1f} {:>12} {:>12}" total_replies = stats.get(TOTAL_REPLY_CNT, 0) - + output = [ "按模块分类统计:", " 模块名称 调用次数 输入Token 输出Token Token总量 累计花费 平均耗时(秒) 标准差(秒) 每次回复平均调用次数 每次回复平均Token数", @@ -813,11 +813,11 @@ class StatisticOutputTask(AsyncTask): cost = stats[COST_BY_MODULE][module_name] avg_time_cost = stats[AVG_TIME_COST_BY_MODULE][module_name] std_time_cost = stats[STD_TIME_COST_BY_MODULE][module_name] - + # 计算每次回复平均值 avg_count_per_reply = count / total_replies if total_replies > 0 else 0.0 avg_tokens_per_reply = tokens / total_replies if total_replies > 0 else 0.0 - + # 格式化大数字 formatted_count = _format_large_number(count) formatted_in_tokens = _format_large_number(in_tokens) @@ -825,7 +825,7 @@ class StatisticOutputTask(AsyncTask): formatted_tokens = _format_large_number(tokens) formatted_avg_count = _format_large_number(avg_count_per_reply) if total_replies > 0 else "N/A" formatted_avg_tokens = _format_large_number(avg_tokens_per_reply) if total_replies > 0 else "N/A" - + output.append( data_fmt.format( name, diff --git a/src/chat/utils/utils.py b/src/chat/utils/utils.py index 67089fe6..bb0c01f7 100644 --- a/src/chat/utils/utils.py +++ b/src/chat/utils/utils.py @@ -646,7 +646,7 @@ def get_chat_type_and_target_info(chat_id: str) -> Tuple[bool, Optional["TargetP def record_replyer_action_temp(chat_id: str, reason: str, think_level: int) -> None: """ 临时记录replyer动作被选择的信息(仅群聊) - + Args: chat_id: 聊天ID reason: 选择理由 @@ -656,7 +656,7 @@ def record_replyer_action_temp(chat_id: str, reason: str, think_level: int) -> N # 确保data/temp目录存在 temp_dir = "data/temp" os.makedirs(temp_dir, exist_ok=True) - + # 创建记录数据 record_data = { "chat_id": chat_id, @@ -664,16 +664,16 @@ def record_replyer_action_temp(chat_id: str, reason: str, think_level: int) -> N "think_level": think_level, "timestamp": datetime.now().isoformat(), } - + # 生成文件名(使用时间戳避免冲突) timestamp_str = datetime.now().strftime("%Y%m%d_%H%M%S_%f") filename = f"replyer_action_{timestamp_str}.json" filepath = os.path.join(temp_dir, filename) - + # 写入文件 with open(filepath, "w", encoding="utf-8") as f: json.dump(record_data, f, ensure_ascii=False, indent=2) - + logger.debug(f"已记录replyer动作选择: chat_id={chat_id}, think_level={think_level}") except Exception as e: logger.warning(f"记录replyer动作选择失败: {e}") diff --git a/src/chat/utils/utils_image.py b/src/chat/utils/utils_image.py index 56a3ae0f..1145cc83 100644 --- a/src/chat/utils/utils_image.py +++ b/src/chat/utils/utils_image.py @@ -130,12 +130,10 @@ class ImageManager: try: # 清理Images表中type为emoji的记录 deleted_images = Images.delete().where(Images.type == "emoji").execute() - + # 清理ImageDescriptions表中type为emoji的记录 - deleted_descriptions = ( - ImageDescriptions.delete().where(ImageDescriptions.type == "emoji").execute() - ) - + deleted_descriptions = ImageDescriptions.delete().where(ImageDescriptions.type == "emoji").execute() + total_deleted = deleted_images + deleted_descriptions if total_deleted > 0: logger.info( @@ -166,7 +164,7 @@ class ImageManager: async def _save_emoji_file_if_needed(self, image_base64: str, image_hash: str, image_format: str) -> None: """如果启用了steal_emoji且表情包未注册,保存文件到data/emoji目录 - + Args: image_base64: 图片的base64编码 image_hash: 图片的MD5哈希值 @@ -174,7 +172,7 @@ class ImageManager: """ if not global_config.emoji.steal_emoji: return - + try: from src.chat.emoji_system.emoji_manager import EMOJI_DIR from src.chat.emoji_system.emoji_manager import get_emoji_manager @@ -236,12 +234,16 @@ class ImageManager: # 优先使用情感标签,如果没有则使用详细描述 result_text = "" if cache_record.emotion_tags: - logger.info(f"[缓存命中] 使用EmojiDescriptionCache表中的情感标签: {cache_record.emotion_tags[:50]}...") + logger.info( + f"[缓存命中] 使用EmojiDescriptionCache表中的情感标签: {cache_record.emotion_tags[:50]}..." + ) result_text = f"[表情包:{cache_record.emotion_tags}]" elif cache_record.description: - logger.info(f"[缓存命中] 使用EmojiDescriptionCache表中的描述: {cache_record.description[:50]}...") + logger.info( + f"[缓存命中] 使用EmojiDescriptionCache表中的描述: {cache_record.description[:50]}..." + ) result_text = f"[表情包:{cache_record.description}]" - + # 即使缓存命中,如果启用了steal_emoji,也检查是否需要保存文件 if result_text: await self._save_emoji_file_if_needed(image_base64, image_hash, image_format) diff --git a/src/common/database/database_model.py b/src/common/database/database_model.py index 02a581cd..4d930f60 100644 --- a/src/common/database/database_model.py +++ b/src/common/database/database_model.py @@ -609,23 +609,23 @@ def _fix_table_constraints(table_name, model, constraints_to_fix): fields = list(model._meta.fields.keys()) # Peewee 默认使用 'id' 作为主键字段名 # 尝试获取主键字段名,如果获取失败则默认使用 'id' - primary_key_name = 'id' # 默认值 + primary_key_name = "id" # 默认值 try: - if hasattr(model._meta, 'primary_key') and model._meta.primary_key: - if hasattr(model._meta.primary_key, 'name'): + if hasattr(model._meta, "primary_key") and model._meta.primary_key: + if hasattr(model._meta.primary_key, "name"): primary_key_name = model._meta.primary_key.name elif isinstance(model._meta.primary_key, str): primary_key_name = model._meta.primary_key except Exception: pass # 如果获取失败,使用默认值 'id' - + # 如果字段列表包含主键,则排除它 if primary_key_name in fields: fields_without_pk = [f for f in fields if f != primary_key_name] logger.info(f"排除主键字段 '{primary_key_name}',让数据库自动生成新的主键") else: fields_without_pk = fields - + fields_str = ", ".join(fields_without_pk) # 检查是否有字段需要从 NULL 改为 NOT NULL diff --git a/src/common/toml_utils.py b/src/common/toml_utils.py index 0a88c458..6a7b8bb9 100644 --- a/src/common/toml_utils.py +++ b/src/common/toml_utils.py @@ -34,7 +34,7 @@ def _format_toml_value(obj: Any, threshold: int, depth: int = 0) -> Any: return obj # 决定是否多行:仅在顶层且长度超过阈值时 - should_multiline = (depth == 0 and len(obj) > threshold) + should_multiline = depth == 0 and len(obj) > threshold # 如果已经是 tomlkit Array,原地修改以保留注释 if isinstance(obj, Array): @@ -46,7 +46,7 @@ def _format_toml_value(obj: Any, threshold: int, depth: int = 0) -> Any: # 普通 list:转换为 tomlkit 数组 arr = tomlkit.array() arr.multiline(should_multiline) - + for item in obj: arr.append(_format_toml_value(item, threshold, depth + 1)) return arr @@ -112,7 +112,7 @@ def save_toml_with_format( formatted = _format_toml_value(data, multiline_threshold) if multiline_threshold >= 0 else data output = tomlkit.dumps(formatted) # 规范化:将 3+ 连续空行压缩为 1 个空行,防止空行累积 - output = re.sub(r'\n{3,}', '\n\n', output) + output = re.sub(r"\n{3,}", "\n\n", output) with open(file_path, "w", encoding="utf-8") as f: f.write(output) @@ -122,4 +122,4 @@ def format_toml_string(data: Any, multiline_threshold: int = 1) -> str: formatted = _format_toml_value(data, multiline_threshold) if multiline_threshold >= 0 else data output = tomlkit.dumps(formatted) # 规范化:将 3+ 连续空行压缩为 1 个空行,防止空行累积 - return re.sub(r'\n{3,}', '\n\n', output) \ No newline at end of file + return re.sub(r"\n{3,}", "\n\n", output) diff --git a/src/config/official_configs.py b/src/config/official_configs.py index 55528d51..bfd6ea5c 100644 --- a/src/config/official_configs.py +++ b/src/config/official_configs.py @@ -778,9 +778,9 @@ class DreamConfig(ConfigBase): """ if not self.dream_time_ranges: return True - + now_min = self._now_minutes() - + for time_range in self.dream_time_ranges: if not isinstance(time_range, str): continue @@ -790,7 +790,7 @@ class DreamConfig(ConfigBase): start_min, end_min = parsed if self._in_range(now_min, start_min, end_min): return True - + return False def __post_init__(self): @@ -800,4 +800,4 @@ class DreamConfig(ConfigBase): if self.max_iterations < 1: raise ValueError(f"max_iterations 必须至少为1,当前值: {self.max_iterations}") if self.first_delay_seconds < 0: - raise ValueError(f"first_delay_seconds 不能为负数,当前值: {self.first_delay_seconds}") \ No newline at end of file + raise ValueError(f"first_delay_seconds 不能为负数,当前值: {self.first_delay_seconds}") diff --git a/src/dream/dream_agent.py b/src/dream/dream_agent.py index c14f8061..b516a88e 100644 --- a/src/dream/dream_agent.py +++ b/src/dream/dream_agent.py @@ -1,14 +1,13 @@ import asyncio import random import time -import json from typing import Any, Dict, List, Optional, Tuple from peewee import fn from src.common.logger import get_logger from src.config.config import global_config, model_config -from src.common.database.database_model import ChatHistory, Jargon +from src.common.database.database_model import ChatHistory from src.chat.utils.prompt_builder import Prompt, global_prompt_manager from src.llm_models.payload_content.message import MessageBuilder, RoleType, Message from src.plugin_system.apis import llm_api @@ -82,7 +81,6 @@ def init_dream_prompts() -> None: ) - class DreamTool: """dream 模块内部使用的简易工具封装""" @@ -150,7 +148,13 @@ def init_dream_tools(chat_id: str) -> None: "search_chat_history", "根据关键词或参与人查询当前 chat_id 下的 ChatHistory 概览,便于快速定位相关记忆。", [ - ("keyword", ToolParamType.STRING, "关键词(可选,支持多个关键词,可用空格、逗号等分隔)。", False, None), + ( + "keyword", + ToolParamType.STRING, + "关键词(可选,支持多个关键词,可用空格、逗号等分隔)。", + False, + None, + ), ("participant", ToolParamType.STRING, "参与人昵称(可选)。", False, None), ], search_chat_history, @@ -201,8 +205,20 @@ def init_dream_tools(chat_id: str) -> None: [ ("theme", ToolParamType.STRING, "新的主题标题(必填)。", True, None), ("summary", ToolParamType.STRING, "新的概括内容(必填)。", True, None), - ("keywords", ToolParamType.STRING, "新的关键词 JSON 字符串,如 ['关键词1','关键词2'](必填)。", True, None), - ("key_point", ToolParamType.STRING, "新的关键信息 JSON 字符串,如 ['要点1','要点2'](必填)。", True, None), + ( + "keywords", + ToolParamType.STRING, + "新的关键词 JSON 字符串,如 ['关键词1','关键词2'](必填)。", + True, + None, + ), + ( + "key_point", + ToolParamType.STRING, + "新的关键信息 JSON 字符串,如 ['要点1','要点2'](必填)。", + True, + None, + ), ("start_time", ToolParamType.STRING, "起始时间戳(秒,Unix 时间,必填)。", True, None), ("end_time", ToolParamType.STRING, "结束时间戳(秒,Unix 时间,必填)。", True, None), ], @@ -215,7 +231,13 @@ def init_dream_tools(chat_id: str) -> None: "finish_maintenance", "结束本次 dream 维护任务。当你认为当前 chat_id 下的维护工作已经完成,没有更多需要整理、合并或修改的内容时,调用此工具来主动结束本次运行。", [ - ("reason", ToolParamType.STRING, "结束维护的原因说明(可选),例如 '已完成所有记录的整理' 或 '当前记录质量良好,无需进一步维护'。", False, None), + ( + "reason", + ToolParamType.STRING, + "结束维护的原因说明(可选),例如 '已完成所有记录的整理' 或 '当前记录质量良好,无需进一步维护'。", + False, + None, + ), ], finish_maintenance, ) @@ -246,7 +268,7 @@ async def run_dream_agent_once( """ if max_iterations is None: max_iterations = global_config.dream.max_iterations - + start_ts = time.time() logger.info(f"[dream] 开始对 chat_id={chat_id} 进行 dream 维护,最多迭代 {max_iterations} 轮") @@ -282,9 +304,7 @@ async def run_dream_agent_once( else "未知" ) end_time_str = ( - time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(record.end_time)) - if record.end_time - else "未知" + time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(record.end_time)) if record.end_time else "未知" ) detail_text = ( f"ID={record.id}\n" @@ -305,8 +325,7 @@ async def run_dream_agent_once( start_detail_builder = MessageBuilder() start_detail_builder.set_role(RoleType.User) start_detail_builder.add_text_content( - "【起始记忆详情】以下是本轮随机/指定的起始记忆的详细信息,供你在整理时优先参考:\n\n" - + detail_text + "【起始记忆详情】以下是本轮随机/指定的起始记忆的详细信息,供你在整理时优先参考:\n\n" + detail_text ) conversation_messages.append(start_detail_builder.build()) else: @@ -343,13 +362,17 @@ async def run_dream_agent_once( conversation_messages.append(round_info_builder.build()) # 调用 LLM 让其决定是否要使用工具 - success, response, reasoning_content, model_name, tool_calls = ( - await llm_api.generate_with_model_with_tools_by_message_factory( - message_factory, - model_config=model_config.model_task_config.tool_use, - tool_options=tool_defs, - request_type="dream.react", - ) + ( + success, + response, + reasoning_content, + model_name, + tool_calls, + ) = await llm_api.generate_with_model_with_tools_by_message_factory( + message_factory, + model_config=model_config.model_task_config.tool_use, + tool_options=tool_defs, + request_type="dream.react", ) if not success: @@ -522,7 +545,7 @@ async def start_dream_scheduler( if interval_seconds is None: interval_seconds = global_config.dream.interval_minutes * 60 - + logger.info( f"[dream] dream 调度器启动:首次延迟 {first_delay_seconds}s,之后每隔 {interval_seconds}s ({interval_seconds // 60} 分钟) 运行一次 dream agent" ) @@ -555,4 +578,3 @@ async def start_dream_scheduler( # 初始化提示词 init_dream_prompts() - diff --git a/src/dream/dream_generator.py b/src/dream/dream_generator.py index 174d1b69..945aebf9 100644 --- a/src/dream/dream_generator.py +++ b/src/dream/dream_generator.py @@ -86,7 +86,7 @@ async def generate_dream_summary( try: import json from src.chat.utils.prompt_builder import global_prompt_manager - + # 第一步:建立工具调用结果映射 (call_id -> result) tool_results_map: dict[str, str] = {} for msg in conversation_messages: @@ -98,11 +98,11 @@ async def generate_dream_summary( else: content = str(msg.content) tool_results_map[msg.tool_call_id] = content - + # 第二步:详细记录所有工具调用操作和结果到日志 tool_call_count = 0 logger.info(f"[dream][工具调用详情] 开始记录 chat_id={chat_id} 的所有工具调用操作:") - + for msg in conversation_messages: if msg.role == RoleType.Assistant and msg.tool_calls: tool_call_count += 1 @@ -110,34 +110,38 @@ async def generate_dream_summary( thought_content = "" if msg.content: if isinstance(msg.content, list) and msg.content: - thought_content = msg.content[0].text if hasattr(msg.content[0], "text") else str(msg.content[0]) + thought_content = ( + msg.content[0].text if hasattr(msg.content[0], "text") else str(msg.content[0]) + ) else: thought_content = str(msg.content) - + logger.info(f"[dream][工具调用详情] === 第 {tool_call_count} 组工具调用 ===") if thought_content: - logger.info(f"[dream][工具调用详情] 思考内容:{thought_content[:500]}{'...' if len(thought_content) > 500 else ''}") - + logger.info( + f"[dream][工具调用详情] 思考内容:{thought_content[:500]}{'...' if len(thought_content) > 500 else ''}" + ) + # 记录每个工具调用的详细信息 for idx, tool_call in enumerate(msg.tool_calls, 1): tool_name = tool_call.func_name tool_args = tool_call.args or {} tool_call_id = tool_call.call_id tool_result = tool_results_map.get(tool_call_id, "未找到执行结果") - + # 格式化参数 try: args_str = json.dumps(tool_args, ensure_ascii=False, indent=2) if tool_args else "无参数" except Exception: args_str = str(tool_args) - + logger.info(f"[dream][工具调用详情] --- 工具 {idx}: {tool_name} ---") logger.info(f"[dream][工具调用详情] 调用参数:\n{args_str}") logger.info(f"[dream][工具调用详情] 执行结果:\n{tool_result}") logger.info(f"[dream][工具调用详情] {'-' * 60}") - + logger.info(f"[dream][工具调用详情] 共记录了 {tool_call_count} 组工具调用操作") - + # 第三步:构建对话历史摘要(用于生成梦境) conversation_summary = [] for msg in conversation_messages: @@ -145,11 +149,11 @@ async def generate_dream_summary( content = "" if msg.content: content = msg.content[0].text if isinstance(msg.content, list) and msg.content else str(msg.content) - + if role == "user" and "轮次信息" in content: # 跳过轮次信息消息 continue - + if role == "assistant": # 只保留思考内容,简化工具调用信息 if content: @@ -162,13 +166,13 @@ async def generate_dream_summary( # 截取前300字符 content_preview = content[:300] + ("..." if len(content) > 300 else "") conversation_summary.append(f"[工具执行] {content_preview}") - + conversation_text = "\n".join(conversation_summary[-20:]) # 只保留最后20条消息 - + # 随机选择2个梦境风格 selected_styles = get_random_dream_styles(2) - dream_styles_text = "\n".join([f"{i+1}. {style}" for i, style in enumerate(selected_styles)]) - + dream_styles_text = "\n".join([f"{i + 1}. {style}" for i, style in enumerate(selected_styles)]) + # 使用 Prompt 管理器格式化梦境生成 prompt dream_prompt = await global_prompt_manager.format_prompt( "dream_summary_prompt", @@ -186,13 +190,14 @@ async def generate_dream_summary( max_tokens=512, temperature=0.8, ) - + if dream_content: logger.info(f"[dream][梦境总结] 对 chat_id={chat_id} 的整理过程梦境:\n{dream_content}") else: logger.warning("[dream][梦境总结] 未能生成梦境总结") - + except Exception as e: logger.error(f"[dream][梦境总结] 生成梦境总结失败: {e}", exc_info=True) -init_dream_summary_prompt() \ No newline at end of file + +init_dream_summary_prompt() diff --git a/src/dream/tools/__init__.py b/src/dream/tools/__init__.py index ef3b8be3..cd784b02 100644 --- a/src/dream/tools/__init__.py +++ b/src/dream/tools/__init__.py @@ -4,8 +4,3 @@ dream agent 工具实现模块。 每个工具的具体实现放在独立文件中,通过 make_xxx(chat_id) 工厂函数 生成绑定到特定 chat_id 的协程函数,由 dream_agent.init_dream_tools 统一注册。 """ - - - - - diff --git a/src/dream/tools/create_chat_history_tool.py b/src/dream/tools/create_chat_history_tool.py index dde4ffaf..551b7ec6 100644 --- a/src/dream/tools/create_chat_history_tool.py +++ b/src/dream/tools/create_chat_history_tool.py @@ -60,8 +60,3 @@ def make_create_chat_history(chat_id: str): return f"create_chat_history 执行失败: {e}" return create_chat_history - - - - - diff --git a/src/dream/tools/delete_chat_history_tool.py b/src/dream/tools/delete_chat_history_tool.py index e7b9755d..18c32f27 100644 --- a/src/dream/tools/delete_chat_history_tool.py +++ b/src/dream/tools/delete_chat_history_tool.py @@ -23,8 +23,3 @@ def make_delete_chat_history(chat_id: str): # chat_id 目前未直接使用, return f"delete_chat_history 执行失败: {e}" return delete_chat_history - - - - - diff --git a/src/dream/tools/delete_jargon_tool.py b/src/dream/tools/delete_jargon_tool.py index 0ff1c218..8edd3245 100644 --- a/src/dream/tools/delete_jargon_tool.py +++ b/src/dream/tools/delete_jargon_tool.py @@ -23,8 +23,3 @@ def make_delete_jargon(chat_id: str): # chat_id 目前未直接使用,预留 return f"delete_jargon 执行失败: {e}" return delete_jargon - - - - - diff --git a/src/dream/tools/finish_maintenance_tool.py b/src/dream/tools/finish_maintenance_tool.py index 66f8c99e..403b6c6e 100644 --- a/src/dream/tools/finish_maintenance_tool.py +++ b/src/dream/tools/finish_maintenance_tool.py @@ -14,8 +14,3 @@ def make_finish_maintenance(chat_id: str): # chat_id 目前未直接使用, return msg return finish_maintenance - - - - - diff --git a/src/dream/tools/get_chat_history_detail_tool.py b/src/dream/tools/get_chat_history_detail_tool.py index 4f9e16b7..92f1d4d9 100644 --- a/src/dream/tools/get_chat_history_detail_tool.py +++ b/src/dream/tools/get_chat_history_detail_tool.py @@ -1,5 +1,4 @@ import time -from typing import Optional from src.common.logger import get_logger from src.common.database.database_model import ChatHistory @@ -20,14 +19,10 @@ def make_get_chat_history_detail(chat_id: str): # chat_id 目前未直接使用 # 将时间戳转换为可读时间格式 start_time_str = ( - time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(record.start_time)) - if record.start_time - else "未知" + time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(record.start_time)) if record.start_time else "未知" ) end_time_str = ( - time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(record.end_time)) - if record.end_time - else "未知" + time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(record.end_time)) if record.end_time else "未知" ) result = ( @@ -40,17 +35,10 @@ def make_get_chat_history_detail(chat_id: str): # chat_id 目前未直接使用 f"概括={record.summary or '无'}\n" f"关键信息={record.key_point or '无'}" ) - logger.debug( - f"[dream][tool] get_chat_history_detail 成功,预览: {result[:200].replace(chr(10), ' ')}" - ) + logger.debug(f"[dream][tool] get_chat_history_detail 成功,预览: {result[:200].replace(chr(10), ' ')}") return result except Exception as e: logger.error(f"get_chat_history_detail 失败: {e}") return f"get_chat_history_detail 执行失败: {e}" return get_chat_history_detail - - - - - diff --git a/src/dream/tools/search_chat_history_tool.py b/src/dream/tools/search_chat_history_tool.py index 105f6676..5d216f00 100644 --- a/src/dream/tools/search_chat_history_tool.py +++ b/src/dream/tools/search_chat_history_tool.py @@ -78,9 +78,7 @@ def make_search_chat_history(chat_id: str): if record.keywords: try: keywords_data = ( - json.loads(record.keywords) - if isinstance(record.keywords, str) - else record.keywords + json.loads(record.keywords) if isinstance(record.keywords, str) else record.keywords ) if isinstance(keywords_data, list): record_keywords_list = [str(k).lower() for k in keywords_data] @@ -125,9 +123,7 @@ def make_search_chat_history(chat_id: str): keywords_str = "、".join(keywords_list) if len(keywords_list) > 2: required_count = len(keywords_list) - 1 - return ( - f"未找到包含至少{required_count}个关键词(共{len(keywords_list)}个)'{keywords_str}'的聊天记录" - ) + return f"未找到包含至少{required_count}个关键词(共{len(keywords_list)}个)'{keywords_str}'的聊天记录" else: return f"未找到包含所有关键词'{keywords_str}'的聊天记录" elif participant: @@ -142,9 +138,7 @@ def make_search_chat_history(chat_id: str): if record.keywords: try: keywords_data = ( - json.loads(record.keywords) - if isinstance(record.keywords, str) - else record.keywords + json.loads(record.keywords) if isinstance(record.keywords, str) else record.keywords ) if isinstance(keywords_data, list): for k in keywords_data: @@ -160,13 +154,13 @@ def make_search_chat_history(chat_id: str): keywords_str = "、".join(sorted(all_keywords_set)) response_text = ( f"包含“{search_label}”的结果过多,请尝试更多关键词精确查找\n\n" - f"有关\"{search_label}\"的关键词:\n" + f'有关"{search_label}"的关键词:\n' f"{keywords_str}" ) else: response_text = ( f"包含“{search_label}”的结果过多,请尝试更多关键词精确查找\n\n" - f"有关\"{search_label}\"的关键词信息为空" + f'有关"{search_label}"的关键词信息为空' ) logger.info( @@ -192,9 +186,7 @@ def make_search_chat_history(chat_id: str): if record.keywords: try: keywords_data = ( - json.loads(record.keywords) - if isinstance(record.keywords, str) - else record.keywords + json.loads(record.keywords) if isinstance(record.keywords, str) else record.keywords ) if isinstance(keywords_data, list) and keywords_data: keywords_str = "、".join([str(k) for k in keywords_data]) @@ -220,8 +212,3 @@ def make_search_chat_history(chat_id: str): return f"search_chat_history 执行失败: {e}" return search_chat_history - - - - - diff --git a/src/dream/tools/search_jargon_tool.py b/src/dream/tools/search_jargon_tool.py index 0429a6a7..139536ac 100644 --- a/src/dream/tools/search_jargon_tool.py +++ b/src/dream/tools/search_jargon_tool.py @@ -16,9 +16,7 @@ def make_search_jargon(chat_id: str): if not keyword or not keyword.strip(): return "未指定查询关键词(参数 keyword 为必填,且不能为空)" - logger.info( - f"[dream][tool] 调用 search_jargon(keyword={keyword}) (作用域 chat_id={chat_id})" - ) + logger.info(f"[dream][tool] 调用 search_jargon(keyword={keyword}) (作用域 chat_id={chat_id})") # 基础条件:只查 is_jargon=True 的记录 query = Jargon.select().where(Jargon.is_jargon) @@ -102,5 +100,3 @@ def make_search_jargon(chat_id: str): return f"search_jargon 执行失败: {e}" return search_jargon - - diff --git a/src/dream/tools/update_chat_history_tool.py b/src/dream/tools/update_chat_history_tool.py index 8c0caf63..a65e78a7 100644 --- a/src/dream/tools/update_chat_history_tool.py +++ b/src/dream/tools/update_chat_history_tool.py @@ -49,8 +49,3 @@ def make_update_chat_history(chat_id: str): # chat_id 目前未直接使用, return f"update_chat_history 执行失败: {e}" return update_chat_history - - - - - diff --git a/src/dream/tools/update_jargon_tool.py b/src/dream/tools/update_jargon_tool.py index b50504ae..1d559cf6 100644 --- a/src/dream/tools/update_jargon_tool.py +++ b/src/dream/tools/update_jargon_tool.py @@ -49,8 +49,3 @@ def make_update_jargon(chat_id: str): # chat_id 目前未直接使用,预留 return f"update_jargon 执行失败: {e}" return update_jargon - - - - - diff --git a/src/hippo_memorizer/chat_history_summarizer.py b/src/hippo_memorizer/chat_history_summarizer.py index 456a0f2e..241a2af8 100644 --- a/src/hippo_memorizer/chat_history_summarizer.py +++ b/src/hippo_memorizer/chat_history_summarizer.py @@ -316,7 +316,9 @@ class ChatHistorySummarizer: before_count = len(self.current_batch.messages) self.current_batch.messages.extend(new_messages) self.current_batch.end_time = current_time - logger.info(f"{self.log_prefix} 更新聊天检查批次: {before_count} -> {len(self.current_batch.messages)} 条消息") + logger.info( + f"{self.log_prefix} 更新聊天检查批次: {before_count} -> {len(self.current_batch.messages)} 条消息" + ) # 更新批次后持久化 self._persist_topic_cache() else: @@ -362,9 +364,7 @@ class ChatHistorySummarizer: else: time_str = f"{time_since_last_check / 3600:.1f}小时" - logger.debug( - f"{self.log_prefix} 批次状态检查 | 消息数: {message_count} | 距上次检查: {time_str}" - ) + logger.debug(f"{self.log_prefix} 批次状态检查 | 消息数: {message_count} | 距上次检查: {time_str}") # 检查“话题检查”触发条件 should_check = False @@ -414,7 +414,7 @@ class ChatHistorySummarizer: # 说明 bot 没有参与这段对话,不应该记录 bot_user_id = str(global_config.bot.qq_account) has_bot_message = False - + for msg in messages: if msg.user_info.user_id == bot_user_id: has_bot_message = True @@ -427,7 +427,9 @@ class ChatHistorySummarizer: return # 2. 构造编号后的消息字符串和参与者信息 - numbered_lines, index_to_msg_str, index_to_msg_text, index_to_participants = self._build_numbered_messages_for_llm(messages) + numbered_lines, index_to_msg_str, index_to_msg_text, index_to_participants = ( + self._build_numbered_messages_for_llm(messages) + ) # 3. 调用 LLM 识别话题,并得到 topic -> indices(失败时最多重试 3 次) existing_topics = list(self.topic_cache.keys()) @@ -456,9 +458,7 @@ class ChatHistorySummarizer: ) if not success or not topic_to_indices: - logger.error( - f"{self.log_prefix} 话题识别连续 {max_retries} 次失败或始终无有效话题,本次检查放弃" - ) + logger.error(f"{self.log_prefix} 话题识别连续 {max_retries} 次失败或始终无有效话题,本次检查放弃") # 即使识别失败,也认为是一次“检查”,但不更新 no_update_checks(保持原状) return @@ -610,9 +610,7 @@ class ChatHistorySummarizer: if not numbered_lines: return False, {} - history_topics_block = ( - "\n".join(f"- {t}" for t in existing_topics) if existing_topics else "(当前无历史话题)" - ) + history_topics_block = "\n".join(f"- {t}" for t in existing_topics) if existing_topics else "(当前无历史话题)" messages_block = "\n".join(numbered_lines) prompt = await global_prompt_manager.format_prompt( @@ -635,17 +633,17 @@ class ChatHistorySummarizer: json_str = None json_pattern = r"```json\s*(.*?)\s*```" matches = re.findall(json_pattern, response, re.DOTALL) - + if matches: # 找到JSON代码块,使用第一个匹配 json_str = matches[0].strip() else: # 如果没有找到代码块,尝试查找JSON数组的开始和结束位置 # 查找第一个 [ 和最后一个 ] - start_idx = response.find('[') - end_idx = response.rfind(']') + start_idx = response.find("[") + end_idx = response.rfind("]") if start_idx != -1 and end_idx != -1 and end_idx > start_idx: - json_str = response[start_idx:end_idx + 1].strip() + json_str = response[start_idx : end_idx + 1].strip() else: # 如果还是找不到,尝试直接使用整个响应(移除可能的markdown标记) json_str = response.strip() @@ -942,4 +940,3 @@ class ChatHistorySummarizer: init_prompt() - diff --git a/src/llm_models/model_client/gemini_client.py b/src/llm_models/model_client/gemini_client.py index b52474e4..33afacaa 100644 --- a/src/llm_models/model_client/gemini_client.py +++ b/src/llm_models/model_client/gemini_client.py @@ -98,7 +98,10 @@ def _convert_messages( content: List[Part] = [] for item in message.content: if isinstance(item, tuple): - image_format = "jpeg" if item[0].lower() == "jpg" else item[0].lower() + image_format = item[0].lower() + # 规范 JPEG MIME 类型后缀,统一使用 image/jpeg + if image_format in ("jpg", "jpeg"): + image_format = "jpeg" content.append(Part.from_bytes(data=base64.b64decode(item[1]), mime_type=f"image/{image_format}")) elif isinstance(item, str): content.append(Part.from_text(text=item)) diff --git a/src/llm_models/model_client/openai_client.py b/src/llm_models/model_client/openai_client.py index 5793d4f9..5372d95b 100644 --- a/src/llm_models/model_client/openai_client.py +++ b/src/llm_models/model_client/openai_client.py @@ -61,10 +61,16 @@ def _convert_messages(messages: list[Message]) -> list[ChatCompletionMessagePara content = [] for item in message.content: if isinstance(item, tuple): + image_format = item[0].lower() + # 规范 JPEG MIME 类型后缀,统一使用 image/jpeg + if image_format in ("jpg", "jpeg"): + mime_suffix = "jpeg" + else: + mime_suffix = image_format content.append( { "type": "image_url", - "image_url": {"url": f"data:image/{item[0].lower()};base64,{item[1]}"}, + "image_url": {"url": f"data:image/{mime_suffix};base64,{item[1]}"}, } ) elif isinstance(item, str): diff --git a/src/llm_models/utils_model.py b/src/llm_models/utils_model.py index 7fb4cfd0..df22c9cd 100644 --- a/src/llm_models/utils_model.py +++ b/src/llm_models/utils_model.py @@ -49,7 +49,7 @@ class LLMRequest: def _check_slow_request(self, time_cost: float, model_name: str) -> None: """检查请求是否过慢并输出警告日志 - + Args: time_cost: 请求耗时(秒) model_name: 使用的模型名称 @@ -323,7 +323,7 @@ class LLMRequest: effective_temperature = (model_info.extra_params or {}).get("temperature") if effective_temperature is None: effective_temperature = self.model_for_task.temperature - + # max_tokens 优先级:参数传入 > 模型级别配置 > extra_params > 任务配置 effective_max_tokens = max_tokens if effective_max_tokens is None: @@ -332,7 +332,7 @@ class LLMRequest: effective_max_tokens = (model_info.extra_params or {}).get("max_tokens") if effective_max_tokens is None: effective_max_tokens = self.model_for_task.max_tokens - + return await client.get_response( model_info=model_info, message_list=(compressed_messages or message_list), @@ -366,7 +366,9 @@ class LLMRequest: logger.error(f"模型 '{model_info.name}' 在多次出现空回复后仍然失败。{original_error_info}") raise ModelAttemptFailed(f"模型 '{model_info.name}' 重试耗尽", original_exception=e) from e - logger.warning(f"模型 '{model_info.name}' 返回空回复(可重试){original_error_info}。剩余重试次数: {retry_remain}") + logger.warning( + f"模型 '{model_info.name}' 返回空回复(可重试){original_error_info}。剩余重试次数: {retry_remain}" + ) await asyncio.sleep(api_provider.retry_interval) except NetworkConnectionError as e: @@ -394,7 +396,9 @@ class LLMRequest: if e.status_code == 429 or e.status_code >= 500: retry_remain -= 1 if retry_remain <= 0: - logger.error(f"模型 '{model_info.name}' 在遇到 {e.status_code} 错误并用尽重试次数后仍然失败。{original_error_info}") + logger.error( + f"模型 '{model_info.name}' 在遇到 {e.status_code} 错误并用尽重试次数后仍然失败。{original_error_info}" + ) raise ModelAttemptFailed(f"模型 '{model_info.name}' 重试耗尽", original_exception=e) from e logger.warning( @@ -540,7 +544,5 @@ class LLMRequest: if e.__cause__: original_error_type = type(e.__cause__).__name__ original_error_msg = str(e.__cause__) - return ( - f"\n 底层异常类型: {original_error_type}\n 底层异常信息: {original_error_msg}" - ) + return f"\n 底层异常类型: {original_error_type}\n 底层异常信息: {original_error_msg}" return "" diff --git a/src/main.py b/src/main.py index d5426f5c..b6141ad4 100644 --- a/src/main.py +++ b/src/main.py @@ -113,7 +113,6 @@ class MainSystem: get_emoji_manager().initialize() logger.info("表情包管理器初始化成功") - # 初始化聊天管理器 await get_chat_manager()._initialize() asyncio.create_task(get_chat_manager()._auto_save_task()) diff --git a/src/memory_system/memory_retrieval.py b/src/memory_system/memory_retrieval.py index 248e3062..9aafb9ef 100644 --- a/src/memory_system/memory_retrieval.py +++ b/src/memory_system/memory_retrieval.py @@ -136,8 +136,6 @@ def init_memory_retrieval_prompt(): ) - - def _log_conversation_messages( conversation_messages: List[Message], head_prompt: Optional[str] = None, @@ -172,7 +170,9 @@ def _log_conversation_messages( # 构建单条消息的日志信息 # msg_info = f"\n========================================\n[消息 {idx}] 角色: {role_name} 内容类型: {content_type}\n-----------------------------" - msg_info = f"\n========================================\n[消息 {idx}] 角色: {role_name}\n-----------------------------" + msg_info = ( + f"\n========================================\n[消息 {idx}] 角色: {role_name}\n-----------------------------" + ) # if full_content: # msg_info += f"\n{full_content}" @@ -185,8 +185,7 @@ def _log_conversation_messages( msg_info += f"\n - {tool_call.func_name}: {json.dumps(tool_call.args, ensure_ascii=False)}" # if msg.tool_call_id: - # msg_info += f"\n 工具调用ID: {msg.tool_call_id}" - + # msg_info += f"\n 工具调用ID: {msg.tool_call_id}" log_lines.append(msg_info) @@ -330,7 +329,7 @@ async def _react_agent_solve_question( remaining_iterations=remaining_iterations, max_iterations=max_iterations, ) - + # 后续迭代都复用第一次构建的head_prompt head_prompt = first_head_prompt @@ -365,7 +364,7 @@ async def _react_agent_solve_question( ) # logger.info( - # f"ReAct Agent 第 {iteration + 1} 次迭代 模型: {model_name} ,调用工具数量: {len(tool_calls) if tool_calls else 0} ,调用工具响应: {response}" + # f"ReAct Agent 第 {iteration + 1} 次迭代 模型: {model_name} ,调用工具数量: {len(tool_calls) if tool_calls else 0} ,调用工具响应: {response}" # ) if not success: @@ -409,20 +408,20 @@ async def _react_agent_solve_question( """从文本中解析finish_search函数调用,返回(found_answer, answer)元组,如果未找到则返回(None, None)""" if not text: return None, None - + # 查找finish_search函数调用位置(不区分大小写) func_pattern = "finish_search" text_lower = text.lower() func_pos = text_lower.find(func_pattern) if func_pos == -1: return None, None - + # 查找函数调用的开始和结束位置 # 从func_pos开始向后查找左括号 start_pos = text.find("(", func_pos) if start_pos == -1: return None, None - + # 查找匹配的右括号(考虑嵌套) paren_count = 0 end_pos = start_pos @@ -437,10 +436,10 @@ async def _react_agent_solve_question( else: # 没有找到匹配的右括号 return None, None - + # 提取函数参数部分 params_text = text[start_pos + 1 : end_pos] - + # 解析found_answer参数(布尔值,可能是true/false/True/False) found_answer = None found_answer_patterns = [ @@ -454,49 +453,60 @@ async def _react_agent_solve_question( if match: found_answer = "true" in match.group(0).lower() break - + # 解析answer参数(字符串,使用extract_quoted_content) answer = extract_quoted_content(text, "finish_search", "answer") - + return found_answer, answer - + parsed_found_answer, parsed_answer = parse_finish_search_from_text(response) - + if parsed_found_answer is not None: # 检测到finish_search函数调用格式 if parsed_found_answer: # 找到了答案 if parsed_answer: - step["actions"].append({"action_type": "finish_search", "action_params": {"found_answer": True, "answer": parsed_answer}}) + step["actions"].append( + { + "action_type": "finish_search", + "action_params": {"found_answer": True, "answer": parsed_answer}, + } + ) step["observations"] = ["检测到finish_search文本格式调用,找到答案"] thinking_steps.append(step) - logger.info(f"ReAct Agent 第 {iteration + 1} 次迭代 通过finish_search文本格式找到关于问题{question}的答案: {parsed_answer}") - + logger.info( + f"ReAct Agent 第 {iteration + 1} 次迭代 通过finish_search文本格式找到关于问题{question}的答案: {parsed_answer}" + ) + _log_conversation_messages( conversation_messages, head_prompt=first_head_prompt, final_status=f"找到答案:{parsed_answer}", ) - + return True, parsed_answer, thinking_steps, False else: # found_answer为True但没有提供answer,视为错误,继续迭代 - logger.warning(f"ReAct Agent 第 {iteration + 1} 次迭代 finish_search文本格式found_answer为True但未提供answer") + logger.warning( + f"ReAct Agent 第 {iteration + 1} 次迭代 finish_search文本格式found_answer为True但未提供answer" + ) else: # 未找到答案,直接退出查询 - step["actions"].append({"action_type": "finish_search", "action_params": {"found_answer": False}}) + step["actions"].append( + {"action_type": "finish_search", "action_params": {"found_answer": False}} + ) step["observations"] = ["检测到finish_search文本格式调用,未找到答案"] thinking_steps.append(step) logger.info(f"ReAct Agent 第 {iteration + 1} 次迭代 通过finish_search文本格式判断未找到答案") - + _log_conversation_messages( conversation_messages, head_prompt=first_head_prompt, final_status="未找到答案:通过finish_search文本格式判断未找到答案", ) - + return False, "", thinking_steps, False - + # 如果没有检测到finish_search格式,记录思考过程,继续下一轮迭代 step["observations"] = [f"思考完成,但未调用工具。响应: {response}"] logger.info(f"ReAct Agent 第 {iteration + 1} 次迭代 思考完成但未调用工具: {response}") @@ -514,44 +524,53 @@ async def _react_agent_solve_question( for tool_call in tool_calls: tool_name = tool_call.func_name tool_args = tool_call.args or {} - + if tool_name == "finish_search": finish_search_found = tool_args.get("found_answer", False) finish_search_answer = tool_args.get("answer", "") - + if finish_search_found: # 找到了答案 if finish_search_answer: - step["actions"].append({"action_type": "finish_search", "action_params": {"found_answer": True, "answer": finish_search_answer}}) + step["actions"].append( + { + "action_type": "finish_search", + "action_params": {"found_answer": True, "answer": finish_search_answer}, + } + ) step["observations"] = ["检测到finish_search工具调用,找到答案"] thinking_steps.append(step) - logger.info(f"ReAct Agent 第 {iteration + 1} 次迭代 通过finish_search工具找到关于问题{question}的答案: {finish_search_answer}") - + logger.info( + f"ReAct Agent 第 {iteration + 1} 次迭代 通过finish_search工具找到关于问题{question}的答案: {finish_search_answer}" + ) + _log_conversation_messages( conversation_messages, head_prompt=first_head_prompt, final_status=f"找到答案:{finish_search_answer}", ) - + return True, finish_search_answer, thinking_steps, False else: # found_answer为True但没有提供answer,视为错误 - logger.warning(f"ReAct Agent 第 {iteration + 1} 次迭代 finish_search工具found_answer为True但未提供answer") + logger.warning( + f"ReAct Agent 第 {iteration + 1} 次迭代 finish_search工具found_answer为True但未提供answer" + ) else: # 未找到答案,直接退出查询 step["actions"].append({"action_type": "finish_search", "action_params": {"found_answer": False}}) step["observations"] = ["检测到finish_search工具调用,未找到答案"] thinking_steps.append(step) logger.info(f"ReAct Agent 第 {iteration + 1} 次迭代 通过finish_search工具判断未找到答案") - + _log_conversation_messages( conversation_messages, head_prompt=first_head_prompt, final_status="未找到答案:通过finish_search工具判断未找到答案", ) - + return False, "", thinking_steps, False - + # 如果没有finish_search工具调用,继续处理其他工具 tool_tasks = [] for i, tool_call in enumerate(tool_calls): @@ -627,7 +646,7 @@ async def _react_agent_solve_question( observation_text += f"\n\n{jargon_info}" collected_info += f"\n{jargon_info}\n" logger.info(f"工具输出触发黑话解析: {new_concepts}") - + tool_builder = MessageBuilder() tool_builder.set_role(RoleType.Tool) tool_builder.add_text_content(observation_text) @@ -645,7 +664,7 @@ async def _react_agent_solve_question( elif iteration + 1 >= max_iterations: should_do_final_evaluation = True logger.info(f"ReAct Agent达到最大迭代次数(已迭代{iteration + 1}次),进入最终评估") - + if should_do_final_evaluation: # 获取必要变量用于最终评估 tool_registry = get_tool_registry() @@ -653,7 +672,7 @@ async def _react_agent_solve_question( time_now = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) current_iteration = iteration + 1 remaining_iterations = 0 - + # 提取函数调用中参数的值,支持单引号和双引号 def extract_quoted_content(text, func_name, param_name): """从文本中提取函数调用中参数的值,支持单引号和双引号 @@ -724,7 +743,13 @@ async def _react_agent_solve_question( max_iterations=max_iterations, ) - eval_success, eval_response, eval_reasoning_content, eval_model_name, eval_tool_calls = await llm_api.generate_with_model_with_tools( + ( + eval_success, + eval_response, + eval_reasoning_content, + eval_model_name, + eval_tool_calls, + ) = await llm_api.generate_with_model_with_tools( evaluation_prompt, model_config=model_config.model_task_config.tool_use, tool_options=[], # 最终评估阶段不提供工具 @@ -739,7 +764,7 @@ async def _react_agent_solve_question( final_status="未找到答案:最终评估阶段LLM调用失败", ) return False, "最终评估阶段LLM调用失败", thinking_steps, is_timeout - + if global_config.debug.show_memory_prompt: logger.info(f"ReAct Agent 最终评估Prompt: {evaluation_prompt}") logger.info(f"ReAct Agent 最终评估响应: {eval_response}") @@ -759,17 +784,17 @@ async def _react_agent_solve_question( "iteration": current_iteration, "thought": f"[最终评估] {eval_response}", "actions": [{"action_type": "found_answer", "action_params": {"answer": found_answer_content}}], - "observations": ["最终评估阶段检测到found_answer"] + "observations": ["最终评估阶段检测到found_answer"], } thinking_steps.append(eval_step) logger.info(f"ReAct Agent 最终评估阶段找到关于问题{question}的答案: {found_answer_content}") - + _log_conversation_messages( conversation_messages, head_prompt=first_head_prompt, final_status=f"找到答案:{found_answer_content}", ) - + return True, found_answer_content, thinking_steps, False # 如果评估为not_enough_info,返回空字符串(不返回任何信息) @@ -778,35 +803,37 @@ async def _react_agent_solve_question( "iteration": current_iteration, "thought": f"[最终评估] {eval_response}", "actions": [{"action_type": "not_enough_info", "action_params": {"reason": not_enough_info_reason}}], - "observations": ["最终评估阶段检测到not_enough_info"] + "observations": ["最终评估阶段检测到not_enough_info"], } thinking_steps.append(eval_step) logger.info(f"ReAct Agent 最终评估阶段判断信息不足: {not_enough_info_reason}") - + _log_conversation_messages( conversation_messages, head_prompt=first_head_prompt, final_status=f"未找到答案:{not_enough_info_reason}", ) - + return False, "", thinking_steps, is_timeout # 如果没有明确判断,视为not_enough_info,返回空字符串(不返回任何信息) eval_step = { "iteration": current_iteration, "thought": f"[最终评估] {eval_response}", - "actions": [{"action_type": "not_enough_info", "action_params": {"reason": "已到达最大迭代次数,无法找到答案"}}], - "observations": ["已到达最大迭代次数,无法找到答案"] + "actions": [ + {"action_type": "not_enough_info", "action_params": {"reason": "已到达最大迭代次数,无法找到答案"}} + ], + "observations": ["已到达最大迭代次数,无法找到答案"], } thinking_steps.append(eval_step) logger.info("ReAct Agent 已到达最大迭代次数,无法找到答案") - + _log_conversation_messages( conversation_messages, head_prompt=first_head_prompt, final_status="未找到答案:已到达最大迭代次数,无法找到答案", ) - + return False, "", thinking_steps, is_timeout # 如果正常迭代过程中提前找到答案返回,不会到达这里 @@ -817,7 +844,7 @@ async def _react_agent_solve_question( head_prompt=first_head_prompt, final_status="未找到答案:正常迭代结束", ) - + return False, "", thinking_steps, is_timeout @@ -1129,7 +1156,9 @@ async def build_memory_retrieval_prompt( else: max_iterations = base_max_iterations timeout_seconds = global_config.memory.agent_timeout_seconds - logger.debug(f"问题数量: {len(questions)},think_level={think_level},设置最大迭代次数: {max_iterations}(基础值: {base_max_iterations}),超时时间: {timeout_seconds}秒") + logger.debug( + f"问题数量: {len(questions)},think_level={think_level},设置最大迭代次数: {max_iterations}(基础值: {base_max_iterations}),超时时间: {timeout_seconds}秒" + ) # 并行处理所有问题,将概念检索结果作为初始信息传递 question_tasks = [ @@ -1157,10 +1186,10 @@ async def build_memory_retrieval_prompt( # 获取最近10分钟内已找到答案的缓存记录 cached_answers = _get_recent_found_answers(chat_id, time_window_seconds=600.0) - + # 合并当前查询结果和缓存答案(去重:如果当前查询的问题在缓存中已存在,优先使用当前结果) all_results = [] - + # 先添加当前查询的结果 current_questions = set() for result in question_results: @@ -1170,7 +1199,7 @@ async def build_memory_retrieval_prompt( if question_end != -1: current_questions.add(result[4:question_end]) all_results.append(result) - + # 添加缓存答案(排除当前查询中已存在的问题) for cached_answer in cached_answers: if cached_answer.startswith("问题:"): @@ -1198,4 +1227,3 @@ async def build_memory_retrieval_prompt( except Exception as e: logger.error(f"记忆检索时发生异常: {str(e)}") return "" - diff --git a/src/memory_system/memory_utils.py b/src/memory_system/memory_utils.py index 7aa33a52..9886142c 100644 --- a/src/memory_system/memory_utils.py +++ b/src/memory_system/memory_utils.py @@ -17,7 +17,6 @@ from src.common.logger import get_logger logger = get_logger("memory_utils") - def parse_questions_json(response: str) -> Tuple[List[str], List[str]]: """解析问题JSON,返回概念列表和问题列表 @@ -68,6 +67,7 @@ def parse_questions_json(response: str) -> Tuple[List[str], List[str]]: logger.error(f"解析问题JSON失败: {e}, 响应内容: {response[:200]}...") return [], [] + def parse_datetime_to_timestamp(value: str) -> float: """ 接受多种常见格式并转换为时间戳(秒) diff --git a/src/memory_system/retrieval_tools/found_answer.py b/src/memory_system/retrieval_tools/found_answer.py index 148424b9..bbed96b3 100644 --- a/src/memory_system/retrieval_tools/found_answer.py +++ b/src/memory_system/retrieval_tools/found_answer.py @@ -47,4 +47,3 @@ def register_tool(): ], execute_func=finish_search, ) - diff --git a/src/memory_system/retrieval_tools/query_chat_history.py b/src/memory_system/retrieval_tools/query_chat_history.py index 5cf9a8ed..351d0606 100644 --- a/src/memory_system/retrieval_tools/query_chat_history.py +++ b/src/memory_system/retrieval_tools/query_chat_history.py @@ -16,9 +16,7 @@ from .tool_registry import register_memory_retrieval_tool logger = get_logger("memory_retrieval_tools") -async def search_chat_history( - chat_id: str, keyword: Optional[str] = None, participant: Optional[str] = None -) -> str: +async def search_chat_history(chat_id: str, keyword: Optional[str] = None, participant: Optional[str] = None) -> str: """根据关键词或参与人查询记忆,返回匹配的记忆id、记忆标题theme和关键词keywords Args: @@ -117,7 +115,7 @@ async def search_chat_history( ) if kw_matched: matched_count += 1 - + # 计算需要匹配的关键词数量 total_keywords = len(keywords_lower) if total_keywords > 2: @@ -126,7 +124,7 @@ async def search_chat_history( else: # 关键词数量<=2,必须全部匹配 required_matches = total_keywords - + keyword_matched = matched_count >= required_matches # 两者都匹配(如果同时有participant和keyword,需要两者都匹配;如果只有一个条件,只需要该条件匹配) @@ -144,7 +142,9 @@ async def search_chat_history( keywords_list = parse_keywords_string(keyword) if len(keywords_list) > 2: required_count = len(keywords_list) - 1 - return f"未找到包含至少{required_count}个关键词(共{len(keywords_list)}个)'{keywords_str}'的聊天记录" + return ( + f"未找到包含至少{required_count}个关键词(共{len(keywords_list)}个)'{keywords_str}'的聊天记录" + ) else: return f"未找到包含所有关键词'{keywords_str}'的聊天记录" elif participant: @@ -160,9 +160,7 @@ async def search_chat_history( if record.keywords: try: keywords_data = ( - json.loads(record.keywords) - if isinstance(record.keywords, str) - else record.keywords + json.loads(record.keywords) if isinstance(record.keywords, str) else record.keywords ) if isinstance(keywords_data, list): for k in keywords_data: @@ -179,13 +177,12 @@ async def search_chat_history( keywords_str = "、".join(sorted(all_keywords_set)) return ( f"包含“{search_label}”的结果过多,请尝试更多关键词精确查找\n\n" - f"有关\"{search_label}\"的关键词:\n" + f'有关"{search_label}"的关键词:\n' f"{keywords_str}" ) else: return ( - f"包含“{search_label}”的结果过多,请尝试更多关键词精确查找\n\n" - f"有关\"{search_label}\"的关键词信息为空" + f'包含“{search_label}”的结果过多,请尝试更多关键词精确查找\n\n有关"{search_label}"的关键词信息为空' ) # 构建结果文本,返回id、theme和keywords(最多20条) diff --git a/src/plugin_system/__init__.py b/src/plugin_system/__init__.py index a3561f0e..7e92a60d 100644 --- a/src/plugin_system/__init__.py +++ b/src/plugin_system/__init__.py @@ -11,6 +11,9 @@ from .base import ( BaseCommand, BaseTool, ConfigField, + ConfigSection, + ConfigLayout, + ConfigTab, ComponentType, ActionActivationType, ChatMode, @@ -116,6 +119,9 @@ __all__ = [ # 装饰器 "register_plugin", "ConfigField", + "ConfigSection", + "ConfigLayout", + "ConfigTab", # 工具函数 "ManifestValidator", "get_logger", diff --git a/src/plugin_system/base/__init__.py b/src/plugin_system/base/__init__.py index a8c320bf..9f930b5a 100644 --- a/src/plugin_system/base/__init__.py +++ b/src/plugin_system/base/__init__.py @@ -29,7 +29,7 @@ from .component_types import ( ForwardNode, ReplySetModel, ) -from .config_types import ConfigField +from .config_types import ConfigField, ConfigSection, ConfigLayout, ConfigTab __all__ = [ "BasePlugin", @@ -46,6 +46,9 @@ __all__ = [ "PluginInfo", "PythonDependency", "ConfigField", + "ConfigSection", + "ConfigLayout", + "ConfigTab", "EventHandlerInfo", "EventType", "BaseEventHandler", diff --git a/src/plugin_system/base/config_types.py b/src/plugin_system/base/config_types.py index c8537ace..18a98614 100644 --- a/src/plugin_system/base/config_types.py +++ b/src/plugin_system/base/config_types.py @@ -70,6 +70,12 @@ class ConfigField: depends_on: Optional[str] = None # 依赖的字段路径,如 "section.field" depends_value: Any = None # 依赖字段需要的值(当依赖字段等于此值时显示) + # === 列表类型专用 === + item_type: Optional[str] = None # 数组元素类型: "string", "number", "object" + item_fields: Optional[Dict[str, Any]] = None # 当 item_type="object" 时,定义对象的字段结构 + min_items: Optional[int] = None # 数组最小元素数量 + max_items: Optional[int] = None # 数组最大元素数量 + def get_ui_type(self) -> str: """ 获取 UI 控件类型 @@ -132,6 +138,10 @@ class ConfigField: "group": self.group, "depends_on": self.depends_on, "depends_value": self.depends_value, + "item_type": self.item_type, + "item_fields": self.item_fields, + "min_items": self.min_items, + "max_items": self.max_items, } diff --git a/src/webui/anti_crawler.py b/src/webui/anti_crawler.py new file mode 100644 index 00000000..997d854b --- /dev/null +++ b/src/webui/anti_crawler.py @@ -0,0 +1,784 @@ +""" +WebUI 防爬虫模块 +提供爬虫检测和阻止功能,保护 WebUI 不被搜索引擎和恶意爬虫访问 +""" + +import os +import time +import ipaddress +import re +from collections import deque +from typing import Optional +from starlette.middleware.base import BaseHTTPMiddleware +from starlette.requests import Request +from starlette.responses import PlainTextResponse + +from src.common.logger import get_logger + +logger = get_logger("webui.anti_crawler") + +# 常见爬虫 User-Agent 列表(使用更精确的关键词,避免误报) +CRAWLER_USER_AGENTS = { + # 搜索引擎爬虫(精确匹配) + "googlebot", + "bingbot", + "baiduspider", + "yandexbot", + "slurp", # Yahoo + "duckduckbot", + "sogou", + "exabot", + "facebot", + "ia_archiver", # Internet Archive + # 通用爬虫(移除过于宽泛的关键词) + "crawler", + "spider", + "scraper", + "wget", # 保留wget,因为通常用于自动化脚本 + "scrapy", # 保留scrapy,因为这是爬虫框架 + # 安全扫描工具(这些是明确的扫描工具) + "masscan", + "nmap", + "nikto", + "sqlmap", + # 注意:移除了以下过于宽泛的关键词以避免误报: + # - "bot" (会误匹配GitHub-Robot等) + # - "curl" (正常工具) + # - "python-requests" (正常库) + # - "httpx" (正常库) + # - "aiohttp" (正常库) +} + +# 资产测绘工具 User-Agent 标识 +ASSET_SCANNER_USER_AGENTS = { + # 知名资产测绘平台 + "shodan", + "censys", + "zoomeye", + "fofa", + "quake", + "hunter", + "binaryedge", + "onyphe", + "securitytrails", + "virustotal", + "passivetotal", + # 安全扫描工具 + "acunetix", + "appscan", + "burpsuite", + "nessus", + "openvas", + "qualys", + "rapid7", + "tenable", + "veracode", + "zap", + "awvs", # Acunetix Web Vulnerability Scanner + "netsparker", + "skipfish", + "w3af", + "arachni", + # 其他扫描工具 + "masscan", + "zmap", + "nmap", + "whatweb", + "wpscan", + "joomscan", + "dnsenum", + "subfinder", + "amass", + "sublist3r", + "theharvester", +} + +# 资产测绘工具常用的HTTP头标识 +ASSET_SCANNER_HEADERS = { + # 常见的扫描工具自定义头 + "x-scan": {"shodan", "censys", "zoomeye", "fofa"}, + "x-scanner": {"nmap", "masscan", "zmap"}, + "x-probe": {"masscan", "zmap"}, + # 其他可疑头(移除反向代理标准头) + "x-originating-ip": set(), + "x-remote-ip": set(), + "x-remote-addr": set(), + # 注意:移除了以下反向代理标准头以避免误报: + # - "x-forwarded-proto" (反向代理标准头) + # - "x-real-ip" (反向代理标准头,已在_get_client_ip中使用) +} + +# 仅检查特定HTTP头中的可疑模式(收紧匹配范围) +# 只检查这些特定头,不检查所有头 +SCANNER_SPECIFIC_HEADERS = { + "x-scan", + "x-scanner", + "x-probe", + "x-originating-ip", + "x-remote-ip", + "x-remote-addr", +} + +# 防爬虫模式配置 +# false: 禁用 +# strict: 严格模式(更严格的检测,更低的频率限制) +# loose: 宽松模式(较宽松的检测,较高的频率限制) +# basic: 基础模式(只记录恶意访问,不阻止,不限制请求数,不跟踪IP) +ANTI_CRAWLER_MODE = os.getenv("WEBUI_ANTI_CRAWLER_MODE", "basic").lower() + + +# IP白名单配置(从环境变量读取,逗号分隔) +# 支持格式: +# - 精确IP:127.0.0.1, 192.168.1.100 +# - CIDR格式:192.168.1.0/24, 172.17.0.0/16 (适用于Docker网络) +# - 通配符:192.168.*.*, 10.*.*.*, *.*.*.* (匹配所有) +# - IPv6:::1, 2001:db8::/32 +def _parse_allowed_ips(ip_string: str) -> list: + """ + 解析IP白名单字符串,支持精确IP、CIDR格式和通配符 + + Args: + ip_string: 逗号分隔的IP字符串 + + Returns: + IP白名单列表,每个元素可能是: + - ipaddress.IPv4Network/IPv6Network对象(CIDR格式) + - ipaddress.IPv4Address/IPv6Address对象(精确IP) + - str(通配符模式,已转换为正则表达式) + """ + allowed = [] + if not ip_string: + return allowed + + for ip_entry in ip_string.split(","): + ip_entry = ip_entry.strip() # 去除空格 + if not ip_entry: + continue + + # 检查通配符格式(包含*) + if "*" in ip_entry: + # 处理通配符 + pattern = _convert_wildcard_to_regex(ip_entry) + if pattern: + allowed.append(pattern) + else: + logger.warning(f"无效的通配符IP格式,已忽略: {ip_entry}") + continue + + try: + # 尝试解析为CIDR格式(包含/) + if "/" in ip_entry: + allowed.append(ipaddress.ip_network(ip_entry, strict=False)) + else: + # 精确IP地址 + allowed.append(ipaddress.ip_address(ip_entry)) + except (ValueError, AttributeError) as e: + logger.warning(f"无效的IP白名单条目,已忽略: {ip_entry} ({e})") + + return allowed + + +def _convert_wildcard_to_regex(wildcard_pattern: str) -> Optional[str]: + """ + 将通配符IP模式转换为正则表达式 + + 支持的格式: + - 192.168.*.* 或 192.168.* + - 10.*.*.* 或 10.* + - *.*.*.* 或 * + + Args: + wildcard_pattern: 通配符模式字符串 + + Returns: + 正则表达式字符串,如果格式无效则返回None + """ + # 去除空格 + pattern = wildcard_pattern.strip() + + # 处理单个*(匹配所有) + if pattern == "*": + return r".*" + + # 处理IPv4通配符格式 + # 支持:192.168.*.*, 192.168.*, 10.*.*.*, 10.* 等 + parts = pattern.split(".") + + if len(parts) > 4: + return None # IPv4最多4段 + + # 构建正则表达式 + regex_parts = [] + for part in parts: + part = part.strip() + if part == "*": + regex_parts.append(r"\d+") # 匹配任意数字 + elif part.isdigit(): + # 验证数字范围(0-255) + num = int(part) + if 0 <= num <= 255: + regex_parts.append(re.escape(part)) + else: + return None # 无效的数字 + else: + return None # 无效的格式 + + # 如果部分少于4段,补充.* + while len(regex_parts) < 4: + regex_parts.append(r"\d+") + + # 组合成正则表达式 + regex = r"^" + r"\.".join(regex_parts) + r"$" + return regex + + +ALLOWED_IPS = _parse_allowed_ips(os.getenv("WEBUI_ALLOWED_IPS", "")) + +# 信任的代理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" + + +def _get_mode_config(mode: str) -> dict: + """ + 根据模式获取配置参数 + + Args: + mode: 防爬虫模式 (false/strict/loose/basic) + + Returns: + 配置字典,包含所有相关参数 + """ + mode = mode.lower() + + if mode == "false": + return { + "enabled": False, + "rate_limit_window": 60, + "rate_limit_max_requests": 1000, # 禁用时设置很高的值 + "max_tracked_ips": 0, + "check_user_agent": False, + "check_asset_scanner": False, + "check_rate_limit": False, + "block_on_detect": False, # 不阻止 + } + elif mode == "strict": + return { + "enabled": True, + "rate_limit_window": 60, + "rate_limit_max_requests": 15, # 严格模式:更低的请求数 + "max_tracked_ips": 20000, + "check_user_agent": True, + "check_asset_scanner": True, + "check_rate_limit": True, + "block_on_detect": True, # 阻止恶意访问 + } + elif mode == "loose": + return { + "enabled": True, + "rate_limit_window": 60, + "rate_limit_max_requests": 60, # 宽松模式:更高的请求数 + "max_tracked_ips": 5000, + "check_user_agent": True, + "check_asset_scanner": True, + "check_rate_limit": True, + "block_on_detect": True, # 阻止恶意访问 + } + else: # basic (默认模式) + return { + "enabled": True, + "rate_limit_window": 60, + "rate_limit_max_requests": 1000, # 不限制请求数 + "max_tracked_ips": 0, # 不跟踪IP + "check_user_agent": True, # 检测但不阻止 + "check_asset_scanner": True, # 检测但不阻止 + "check_rate_limit": False, # 不限制请求频率 + "block_on_detect": False, # 只记录,不阻止 + } + + +class AntiCrawlerMiddleware(BaseHTTPMiddleware): + """防爬虫中间件""" + + def __init__(self, app, mode: str = "standard"): + """ + 初始化防爬虫中间件 + + Args: + app: FastAPI 应用实例 + mode: 防爬虫模式 (false/strict/loose/standard) + """ + super().__init__(app) + self.mode = mode.lower() + # 根据模式获取配置 + config = _get_mode_config(self.mode) + self.enabled = config["enabled"] + self.rate_limit_window = config["rate_limit_window"] + self.rate_limit_max_requests = config["rate_limit_max_requests"] + self.max_tracked_ips = config["max_tracked_ips"] + self.check_user_agent = config["check_user_agent"] + self.check_asset_scanner = config["check_asset_scanner"] + self.check_rate_limit = config["check_rate_limit"] + self.block_on_detect = config["block_on_detect"] # 是否阻止检测到的恶意访问 + + # 用于存储每个IP的请求时间戳(使用deque提高性能) + self.request_times: dict[str, deque] = {} + # 上次清理时间 + self.last_cleanup = time.time() + # 将关键词列表转换为集合以提高查找性能 + self.crawler_keywords_set = set(CRAWLER_USER_AGENTS) + self.scanner_keywords_set = set(ASSET_SCANNER_USER_AGENTS) + + def _is_crawler_user_agent(self, user_agent: Optional[str]) -> bool: + """ + 检测是否为爬虫 User-Agent + + Args: + user_agent: User-Agent 字符串 + + Returns: + 如果是爬虫则返回 True + """ + if not user_agent: + # 没有 User-Agent 的请求记录日志但不直接阻止 + # 改为只记录,让频率限制来处理 + logger.debug("请求缺少User-Agent") + return False # 不再直接阻止无User-Agent的请求 + + user_agent_lower = user_agent.lower() + + # 使用集合查找提高性能(检查是否包含爬虫关键词) + for crawler_keyword in self.crawler_keywords_set: + if crawler_keyword in user_agent_lower: + return True + + return False + + def _is_asset_scanner_header(self, request: Request) -> bool: + """ + 检测是否为资产测绘工具的HTTP头(只检查特定头,收紧匹配) + + Args: + request: 请求对象 + + Returns: + 如果检测到资产测绘工具头则返回 True + """ + # 只检查特定的扫描工具头,不检查所有头 + for header_name, header_value in request.headers.items(): + header_name_lower = header_name.lower() + header_value_lower = header_value.lower() if header_value else "" + + # 检查已知的扫描工具头 + if header_name_lower in ASSET_SCANNER_HEADERS: + # 如果该头有特定的工具集合,检查值是否匹配 + expected_tools = ASSET_SCANNER_HEADERS[header_name_lower] + if expected_tools: + for tool in expected_tools: + if tool in header_value_lower: + return True + else: + # 如果没有特定工具集合,只要存在该头就视为可疑 + if header_value_lower: + return True + + # 只检查特定头中的可疑模式(收紧匹配) + if header_name_lower in SCANNER_SPECIFIC_HEADERS: + # 检查头值中是否包含已知扫描工具名称 + for tool in self.scanner_keywords_set: + if tool in header_value_lower: + return True + + return False + + def _detect_asset_scanner(self, request: Request) -> tuple[bool, Optional[str]]: + """ + 检测资产测绘工具 + + Args: + request: 请求对象 + + Returns: + (是否检测到, 检测到的工具名称) + """ + user_agent = request.headers.get("User-Agent") + + # 检查 User-Agent(使用集合查找提高性能) + if user_agent: + user_agent_lower = user_agent.lower() + for scanner_keyword in self.scanner_keywords_set: + if scanner_keyword in user_agent_lower: + return True, scanner_keyword + + # 检查HTTP头 + if self._is_asset_scanner_header(request): + # 尝试从User-Agent或头中提取工具名称 + detected_tool = None + if user_agent: + user_agent_lower = user_agent.lower() + for tool in self.scanner_keywords_set: + if tool in user_agent_lower: + detected_tool = tool + break + + # 检查HTTP头中的工具标识(只检查特定头) + if not detected_tool: + for header_name, header_value in request.headers.items(): + header_name_lower = header_name.lower() + if header_name_lower in SCANNER_SPECIFIC_HEADERS: + header_value_lower = (header_value or "").lower() + for tool in self.scanner_keywords_set: + if tool in header_value_lower: + detected_tool = tool + break + if detected_tool: + break + + return True, detected_tool or "unknown_scanner" + + return False, None + + def _check_rate_limit(self, client_ip: str) -> bool: + """ + 检查请求频率限制 + + Args: + client_ip: 客户端IP地址 + + Returns: + 如果超过限制则返回 True(需要阻止) + """ + # 检查IP白名单 + if self._is_ip_allowed(client_ip): + return False + + current_time = time.time() + + # 定期清理过期的请求记录(每5分钟清理一次) + if current_time - self.last_cleanup > 300: + self._cleanup_old_requests(current_time) + self.last_cleanup = current_time + + # 限制跟踪的IP数量,防止内存泄漏 + if self.max_tracked_ips > 0 and len(self.request_times) > self.max_tracked_ips: + # 清理最旧的记录(删除最久未访问的IP) + self._cleanup_oldest_ips() + + # 获取或创建该IP的请求时间deque(不使用maxlen,避免限流变松) + if client_ip not in self.request_times: + self.request_times[client_ip] = deque() + + request_times = self.request_times[client_ip] + + # 移除时间窗口外的请求记录(从左侧弹出过期记录) + while request_times and current_time - request_times[0] >= self.rate_limit_window: + request_times.popleft() + + # 检查是否超过限制 + if len(request_times) >= self.rate_limit_max_requests: + return True + + # 记录当前请求时间 + request_times.append(current_time) + return False + + def _cleanup_old_requests(self, current_time: float): + """清理过期的请求记录(只清理当前需要检查的IP,不全量遍历)""" + # 这个方法现在主要用于定期清理,实际清理在_check_rate_limit中按需进行 + # 清理最久未访问的IP记录 + if len(self.request_times) > self.max_tracked_ips * 0.8: + self._cleanup_oldest_ips() + + def _cleanup_oldest_ips(self): + """清理最久未访问的IP记录(全量遍历找真正的oldest)""" + if not self.request_times: + return + + # 先收集空deque的IP(优先删除) + empty_ips = [] + # 找到最久未访问的IP(最旧时间戳) + oldest_ip = None + oldest_time = float("inf") + + # 全量遍历找真正的oldest(超限时性能可接受) + for ip, times in self.request_times.items(): + if not times: + # 空deque,记录待删除 + empty_ips.append(ip) + else: + # 找到最旧的时间戳 + if times[0] < oldest_time: + oldest_time = times[0] + oldest_ip = ip + + # 先删除空deque的IP + for ip in empty_ips: + del self.request_times[ip] + + # 如果没有空deque可删除,且仍需要清理,删除最旧的一个IP + if not empty_ips and oldest_ip: + del self.request_times[oldest_ip] + + def _is_trusted_proxy(self, ip: str) -> bool: + """ + 检查IP是否在信任的代理列表中 + + Args: + ip: IP地址字符串 + + Returns: + 如果是信任的代理则返回 True + """ + if not TRUSTED_PROXIES or ip == "unknown": + return False + + # 检查代理列表中的每个条目 + for trusted_entry in TRUSTED_PROXIES: + # 通配符模式(字符串,正则表达式) + if isinstance(trusted_entry, str): + try: + if re.match(trusted_entry, ip): + return True + except re.error: + continue + # CIDR格式(网络对象) + elif isinstance(trusted_entry, (ipaddress.IPv4Network, ipaddress.IPv6Network)): + try: + client_ip_obj = ipaddress.ip_address(ip) + if client_ip_obj in trusted_entry: + return True + except (ValueError, AttributeError): + continue + # 精确IP(地址对象) + elif isinstance(trusted_entry, (ipaddress.IPv4Address, ipaddress.IPv6Address)): + try: + client_ip_obj = ipaddress.ip_address(ip) + if client_ip_obj == trusted_entry: + return True + except (ValueError, AttributeError): + continue + + return False + + def _get_client_ip(self, request: Request) -> str: + """ + 获取客户端真实IP地址(带基本验证和代理信任检查) + + Args: + request: 请求对象 + + Returns: + 客户端IP地址 + """ + # 获取直接连接的客户端IP(用于验证代理) + direct_client_ip = None + if request.client: + direct_client_ip = request.client.host + + # 检查是否信任X-Forwarded-For头 + # TRUST_XFF 只表示"启用代理解析能力",但仍要求直连 IP 在 TRUSTED_PROXIES 中 + use_xff = False + if TRUST_XFF and TRUSTED_PROXIES and direct_client_ip: + # 只有在启用 TRUST_XFF 且直连 IP 在信任列表中时,才信任 XFF + use_xff = self._is_trusted_proxy(direct_client_ip) + + # 如果信任代理,优先从 X-Forwarded-For 获取 + if use_xff: + forwarded_for = request.headers.get("X-Forwarded-For") + if forwarded_for: + # X-Forwarded-For 可能包含多个IP,取第一个 + ip = forwarded_for.split(",")[0].strip() + # 基本验证IP格式 + if self._validate_ip(ip): + return ip + + # 从 X-Real-IP 获取(如果信任代理) + if use_xff: + real_ip = request.headers.get("X-Real-IP") + if real_ip: + ip = real_ip.strip() + if self._validate_ip(ip): + return ip + + # 使用直接连接的客户端IP + if direct_client_ip and self._validate_ip(direct_client_ip): + return direct_client_ip + + return "unknown" + + def _validate_ip(self, ip: str) -> bool: + """ + 验证IP地址格式 + + Args: + ip: IP地址字符串 + + Returns: + 如果格式有效则返回 True + """ + try: + ipaddress.ip_address(ip) + return True + except (ValueError, AttributeError): + return False + + def _is_ip_allowed(self, ip: str) -> bool: + """ + 检查IP是否在白名单中(支持精确IP、CIDR格式和通配符) + + Args: + ip: 客户端IP地址 + + Returns: + 如果IP在白名单中则返回 True + """ + if not ALLOWED_IPS or ip == "unknown": + return False + + # 检查白名单中的每个条目 + for allowed_entry in ALLOWED_IPS: + # 通配符模式(字符串,正则表达式) + if isinstance(allowed_entry, str): + try: + if re.match(allowed_entry, ip): + return True + except re.error: + # 正则表达式错误,跳过 + continue + # CIDR格式(网络对象) + elif isinstance(allowed_entry, (ipaddress.IPv4Network, ipaddress.IPv6Network)): + try: + client_ip_obj = ipaddress.ip_address(ip) + if client_ip_obj in allowed_entry: + return True + except (ValueError, AttributeError): + # IP格式无效,跳过 + continue + # 精确IP(地址对象) + elif isinstance(allowed_entry, (ipaddress.IPv4Address, ipaddress.IPv6Address)): + try: + client_ip_obj = ipaddress.ip_address(ip) + if client_ip_obj == allowed_entry: + return True + except (ValueError, AttributeError): + # IP格式无效,跳过 + continue + + return False + + async def dispatch(self, request: Request, call_next): + """ + 处理请求 + + Args: + request: 请求对象 + call_next: 下一个中间件或路由处理函数 + + Returns: + 响应对象 + """ + # 如果未启用,直接通过 + if not self.enabled: + return await call_next(request) + + # 允许访问 robots.txt(由专门的路由处理) + if request.url.path == "/robots.txt": + return await call_next(request) + + # 允许访问静态资源(CSS、JS、图片等) + # 注意:.json 已移除,避免 API 路径绕过防护 + # 静态资源只在特定前缀下放行(/static/、/assets/、/dist/) + static_extensions = { + ".css", + ".js", + ".png", + ".jpg", + ".jpeg", + ".gif", + ".svg", + ".ico", + ".woff", + ".woff2", + ".ttf", + ".eot", + } + static_prefixes = {"/static/", "/assets/", "/dist/"} + + # 检查是否是静态资源路径(特定前缀下的静态文件) + path = request.url.path + is_static_path = any(path.startswith(prefix) for prefix in static_prefixes) and any( + path.endswith(ext) for ext in static_extensions + ) + + # 也允许根路径下的静态文件(如 /favicon.ico) + is_root_static = path.count("/") == 1 and any(path.endswith(ext) for ext in static_extensions) + + if is_static_path or is_root_static: + return await call_next(request) + + # 获取客户端IP(只获取一次,避免重复调用) + client_ip = self._get_client_ip(request) + + # 检查IP白名单(优先检查,白名单IP直接通过) + if self._is_ip_allowed(client_ip): + return await call_next(request) + + # 获取 User-Agent + user_agent = request.headers.get("User-Agent") + + # 检测资产测绘工具(优先检测,因为更危险) + if self.check_asset_scanner: + is_scanner, scanner_name = self._detect_asset_scanner(request) + if is_scanner: + logger.warning( + f"🚫 检测到资产测绘工具请求 - IP: {client_ip}, 工具: {scanner_name}, " + f"User-Agent: {user_agent}, Path: {request.url.path}" + ) + # 根据配置决定是否阻止 + if self.block_on_detect: + return PlainTextResponse( + "Access Denied: Asset scanning tools are not allowed", + status_code=403, + ) + + # 检测爬虫 User-Agent + if self.check_user_agent and self._is_crawler_user_agent(user_agent): + logger.warning(f"🚫 检测到爬虫请求 - IP: {client_ip}, User-Agent: {user_agent}, Path: {request.url.path}") + # 根据配置决定是否阻止 + if self.block_on_detect: + return PlainTextResponse( + "Access Denied: Crawlers are not allowed", + status_code=403, + ) + + # 检查请求频率限制 + if self.check_rate_limit and self._check_rate_limit(client_ip): + logger.warning(f"🚫 请求频率过高 - IP: {client_ip}, User-Agent: {user_agent}, Path: {request.url.path}") + return PlainTextResponse( + "Too Many Requests: Rate limit exceeded", + status_code=429, + ) + + # 正常请求,继续处理 + return await call_next(request) + + +def create_robots_txt_response() -> PlainTextResponse: + """ + 创建 robots.txt 响应 + + Returns: + robots.txt 响应对象 + """ + robots_content = """User-agent: * +Disallow: / + +# 禁止所有爬虫访问 +""" + return PlainTextResponse( + content=robots_content, + media_type="text/plain", + headers={"Cache-Control": "public, max-age=86400"}, # 缓存24小时 + ) diff --git a/src/webui/auth.py b/src/webui/auth.py index 8d52a5e3..86621714 100644 --- a/src/webui/auth.py +++ b/src/webui/auth.py @@ -3,6 +3,7 @@ WebUI 认证模块 提供统一的认证依赖,支持 Cookie 和 Header 两种方式 """ +import os from typing import Optional from fastapi import HTTPException, Cookie, Header, Response, Request from src.common.logger import get_logger @@ -15,6 +16,28 @@ COOKIE_NAME = "maibot_session" COOKIE_MAX_AGE = 7 * 24 * 60 * 60 # 7天 +def _is_secure_environment() -> bool: + """ + 检测是否应该启用安全 Cookie(HTTPS) + + Returns: + bool: 如果应该使用 secure cookie 则返回 True + """ + # 检查环境变量 + if os.environ.get("WEBUI_SECURE_COOKIE", "").lower() in ("true", "1", "yes"): + return True + if os.environ.get("WEBUI_SECURE_COOKIE", "").lower() in ("false", "0", "no"): + return False + + # 检查是否是生产环境 + env = os.environ.get("WEBUI_MODE", "").lower() + if env in ("production", "prod"): + return True + + # 默认:开发环境不启用(因为通常是 HTTP) + return False + + def get_current_token( request: Request, maibot_session: Optional[str] = Cookie(None), @@ -22,69 +45,76 @@ def get_current_token( ) -> str: """ 获取当前请求的 token,优先从 Cookie 获取,其次从 Header 获取 - + Args: request: FastAPI Request 对象 maibot_session: Cookie 中的 token authorization: Authorization Header (Bearer token) - + Returns: 验证通过的 token - + Raises: HTTPException: 认证失败时抛出 401 错误 """ token = None - + # 优先从 Cookie 获取 if maibot_session: token = maibot_session # 其次从 Header 获取(兼容旧版本) elif authorization and authorization.startswith("Bearer "): token = authorization.replace("Bearer ", "") - + if not token: raise HTTPException(status_code=401, detail="未提供有效的认证信息") - + # 验证 token token_manager = get_token_manager() if not token_manager.verify_token(token): raise HTTPException(status_code=401, detail="Token 无效或已过期") - + return token def set_auth_cookie(response: Response, token: str) -> None: """ 设置认证 Cookie - + Args: response: FastAPI Response 对象 token: 要设置的 token """ + # 根据环境决定安全设置 + is_secure = _is_secure_environment() + response.set_cookie( key=COOKIE_NAME, value=token, max_age=COOKIE_MAX_AGE, - httponly=True, # 防止 JS 读取 - samesite="lax", # 允许同站导航时发送 Cookie(兼容开发环境代理) - secure=False, # 本地开发不强制 HTTPS,生产环境建议设为 True + httponly=True, # 防止 JS 读取,阻止 XSS 窃取 + samesite="strict" if is_secure else "lax", # 生产环境使用 strict 防止 CSRF + secure=is_secure, # 生产环境强制 HTTPS path="/", # 确保 Cookie 在所有路径下可用 ) - logger.debug(f"已设置认证 Cookie: {token[:8]}...") + logger.debug(f"已设置认证 Cookie: {token[:8]}... (secure={is_secure})") def clear_auth_cookie(response: Response) -> None: """ 清除认证 Cookie - + Args: response: FastAPI Response 对象 """ + # 保持与 set_auth_cookie 相同的安全设置 + is_secure = _is_secure_environment() + response.delete_cookie( key=COOKIE_NAME, httponly=True, - samesite="lax", + samesite="strict" if is_secure else "lax", + secure=is_secure, path="/", ) logger.debug("已清除认证 Cookie") @@ -96,32 +126,32 @@ def verify_auth_token_from_cookie_or_header( ) -> bool: """ 验证认证 Token,支持从 Cookie 或 Header 获取 - + Args: maibot_session: Cookie 中的 token authorization: Authorization header (Bearer token) - + Returns: 验证成功返回 True - + Raises: HTTPException: 认证失败时抛出 401 错误 """ token = None - + # 优先从 Cookie 获取 if maibot_session: token = maibot_session # 其次从 Header 获取(兼容旧版本) elif authorization and authorization.startswith("Bearer "): token = authorization.replace("Bearer ", "") - + if not token: raise HTTPException(status_code=401, detail="未提供有效的认证信息") - + # 验证 token token_manager = get_token_manager() if not token_manager.verify_token(token): raise HTTPException(status_code=401, detail="Token 无效或已过期") - + return True diff --git a/src/webui/chat_routes.py b/src/webui/chat_routes.py index 14d8d9d2..6535b9e9 100644 --- a/src/webui/chat_routes.py +++ b/src/webui/chat_routes.py @@ -8,18 +8,30 @@ import time import uuid from typing import Dict, Any, Optional, List -from fastapi import APIRouter, WebSocket, WebSocketDisconnect, Query +from fastapi import APIRouter, WebSocket, WebSocketDisconnect, Query, Depends, Cookie, Header from pydantic import BaseModel from src.common.logger import get_logger from src.common.database.database_model import Messages, PersonInfo from src.config.config import global_config from src.chat.message_receive.bot import chat_bot +from src.webui.auth import verify_auth_token_from_cookie_or_header +from src.webui.token_manager import get_token_manager +from src.webui.ws_auth import verify_ws_token logger = get_logger("webui.chat") router = APIRouter(prefix="/api/chat", tags=["LocalChat"]) + +def require_auth( + maibot_session: Optional[str] = Cookie(None), + authorization: Optional[str] = Header(None), +) -> bool: + """认证依赖:验证用户是否已登录""" + return verify_auth_token_from_cookie_or_header(maibot_session, authorization) + + # WebUI 聊天的虚拟群组 ID WEBUI_CHAT_GROUP_ID = "webui_local_chat" WEBUI_CHAT_PLATFORM = "webui" @@ -63,14 +75,14 @@ class ChatHistoryManager: def _message_to_dict(self, msg: Messages, group_id: Optional[str] = None) -> Dict[str, Any]: """将数据库消息转换为前端格式 - + Args: msg: 数据库消息对象 group_id: 群 ID,用于判断是否是虚拟群 """ # 判断是否是机器人消息 user_id = msg.user_id or "" - + # 对于虚拟群,通过比较机器人 QQ 账号来判断 # 对于普通 WebUI 群,检查 user_id 是否以 webui_ 开头 if group_id and group_id.startswith(VIRTUAL_GROUP_ID_PREFIX): @@ -256,6 +268,7 @@ async def get_chat_history( limit: int = Query(default=50, ge=1, le=200), user_id: Optional[str] = Query(default=None), # 保留参数兼容性,但不用于过滤 group_id: Optional[str] = Query(default=None), # 可选:指定群 ID 获取历史 + _auth: bool = Depends(require_auth), ): """获取聊天历史记录 @@ -272,7 +285,7 @@ async def get_chat_history( @router.get("/platforms") -async def get_available_platforms(): +async def get_available_platforms(_auth: bool = Depends(require_auth)): """获取可用平台列表 从 PersonInfo 表中获取所有已知的平台 @@ -303,6 +316,7 @@ async def get_persons_by_platform( platform: str = Query(..., description="平台名称"), search: Optional[str] = Query(default=None, description="搜索关键词"), limit: int = Query(default=50, ge=1, le=200), + _auth: bool = Depends(require_auth), ): """获取指定平台的用户列表 @@ -350,7 +364,7 @@ async def get_persons_by_platform( @router.delete("/history") -async def clear_chat_history(group_id: Optional[str] = Query(default=None)): +async def clear_chat_history(group_id: Optional[str] = Query(default=None), _auth: bool = Depends(require_auth)): """清空聊天历史记录 Args: @@ -372,6 +386,7 @@ async def websocket_chat( person_id: Optional[str] = Query(default=None), group_name: Optional[str] = Query(default=None), group_id: Optional[str] = Query(default=None), # 前端传递的稳定 group_id + token: Optional[str] = Query(default=None), # 认证 token ): """WebSocket 聊天端点 @@ -382,9 +397,45 @@ async def websocket_chat( person_id: 虚拟身份模式的用户 person_id(可选) group_name: 虚拟身份模式的群名(可选) group_id: 虚拟身份模式的群 ID(可选,由前端生成并持久化) + token: 认证 token(可选,也可从 Cookie 获取) 虚拟身份模式可通过 URL 参数直接配置,或通过消息中的 set_virtual_identity 配置 + + 支持三种认证方式(按优先级): + 1. query 参数 token(推荐,通过 /api/webui/ws-token 获取临时 token) + 2. Cookie 中的 maibot_session + 3. 直接使用 session token(兼容) + + 示例:ws://host/api/chat/ws?token=xxx """ + is_authenticated = False + + # 方式 1: 尝试验证临时 WebSocket token(推荐方式) + if token and verify_ws_token(token): + is_authenticated = True + logger.debug("聊天 WebSocket 使用临时 token 认证成功") + + # 方式 2: 尝试从 Cookie 获取 session token + if not is_authenticated: + cookie_token = websocket.cookies.get("maibot_session") + if cookie_token: + token_manager = get_token_manager() + if token_manager.verify_token(cookie_token): + is_authenticated = True + logger.debug("聊天 WebSocket 使用 Cookie 认证成功") + + # 方式 3: 尝试直接验证 query 参数作为 session token(兼容旧方式) + if not is_authenticated and token: + token_manager = get_token_manager() + if token_manager.verify_token(token): + is_authenticated = True + logger.debug("聊天 WebSocket 使用 session token 认证成功") + + if not is_authenticated: + logger.warning("聊天 WebSocket 连接被拒绝:认证失败") + await websocket.close(code=4001, reason="认证失败,请重新登录") + return + # 生成会话 ID(每次连接都是新的) session_id = str(uuid.uuid4()) @@ -414,7 +465,9 @@ async def websocket_chat( group_id=virtual_group_id, group_name=group_name or "WebUI虚拟群聊", ) - logger.info(f"虚拟身份模式已通过 URL 参数激活: {current_virtual_config.user_nickname} @ {current_virtual_config.platform}, group_id={virtual_group_id}") + logger.info( + f"虚拟身份模式已通过 URL 参数激活: {current_virtual_config.user_nickname} @ {current_virtual_config.platform}, group_id={virtual_group_id}" + ) except Exception as e: logger.warning(f"通过 URL 参数配置虚拟身份失败: {e}") @@ -710,7 +763,7 @@ async def websocket_chat( @router.get("/info") -async def get_chat_info(): +async def get_chat_info(_auth: bool = Depends(require_auth)): """获取聊天室信息""" return { "bot_name": global_config.bot.nickname, diff --git a/src/webui/config_routes.py b/src/webui/config_routes.py index 25127fe5..6a028927 100644 --- a/src/webui/config_routes.py +++ b/src/webui/config_routes.py @@ -4,10 +4,11 @@ import os import tomlkit -from fastapi import APIRouter, HTTPException, Body -from typing import Any, Annotated +from fastapi import APIRouter, HTTPException, Body, Depends, Cookie, Header +from typing import Any, Annotated, Optional from src.common.logger import get_logger +from src.webui.auth import verify_auth_token_from_cookie_or_header from src.common.toml_utils import save_toml_with_format, _update_toml_doc from src.config.config import Config, APIAdapterConfig, CONFIG_DIR, PROJECT_ROOT from src.config.official_configs import ( @@ -49,11 +50,19 @@ PathBody = Annotated[dict[str, str], Body()] router = APIRouter(prefix="/config", tags=["config"]) +def require_auth( + maibot_session: Optional[str] = Cookie(None), + authorization: Optional[str] = Header(None), +) -> bool: + """认证依赖:验证用户是否已登录""" + return verify_auth_token_from_cookie_or_header(maibot_session, authorization) + + # ===== 架构获取接口 ===== @router.get("/schema/bot") -async def get_bot_config_schema(): +async def get_bot_config_schema(_auth: bool = Depends(require_auth)): """获取麦麦主程序配置架构""" try: # Config 类包含所有子配置 @@ -65,7 +74,7 @@ async def get_bot_config_schema(): @router.get("/schema/model") -async def get_model_config_schema(): +async def get_model_config_schema(_auth: bool = Depends(require_auth)): """获取模型配置架构(包含提供商和模型任务配置)""" try: schema = ConfigSchemaGenerator.generate_config_schema(APIAdapterConfig) @@ -79,7 +88,7 @@ async def get_model_config_schema(): @router.get("/schema/section/{section_name}") -async def get_config_section_schema(section_name: str): +async def get_config_section_schema(section_name: str, _auth: bool = Depends(require_auth)): """ 获取指定配置节的架构 @@ -149,7 +158,7 @@ async def get_config_section_schema(section_name: str): @router.get("/bot") -async def get_bot_config(): +async def get_bot_config(_auth: bool = Depends(require_auth)): """获取麦麦主程序配置""" try: config_path = os.path.join(CONFIG_DIR, "bot_config.toml") @@ -168,7 +177,7 @@ async def get_bot_config(): @router.get("/model") -async def get_model_config(): +async def get_model_config(_auth: bool = Depends(require_auth)): """获取模型配置(包含提供商和模型任务配置)""" try: config_path = os.path.join(CONFIG_DIR, "model_config.toml") @@ -190,7 +199,7 @@ async def get_model_config(): @router.post("/bot") -async def update_bot_config(config_data: ConfigBody): +async def update_bot_config(config_data: ConfigBody, _auth: bool = Depends(require_auth)): """更新麦麦主程序配置""" try: # 验证配置数据 @@ -213,7 +222,7 @@ async def update_bot_config(config_data: ConfigBody): @router.post("/model") -async def update_model_config(config_data: ConfigBody): +async def update_model_config(config_data: ConfigBody, _auth: bool = Depends(require_auth)): """更新模型配置""" try: # 验证配置数据 @@ -239,7 +248,7 @@ async def update_model_config(config_data: ConfigBody): @router.post("/bot/section/{section_name}") -async def update_bot_config_section(section_name: str, section_data: SectionBody): +async def update_bot_config_section(section_name: str, section_data: SectionBody, _auth: bool = Depends(require_auth)): """更新麦麦主程序配置的指定节(保留注释和格式)""" try: # 读取现有配置 @@ -288,7 +297,7 @@ async def update_bot_config_section(section_name: str, section_data: SectionBody @router.get("/bot/raw") -async def get_bot_config_raw(): +async def get_bot_config_raw(_auth: bool = Depends(require_auth)): """获取麦麦主程序配置的原始 TOML 内容""" try: config_path = os.path.join(CONFIG_DIR, "bot_config.toml") @@ -307,7 +316,7 @@ async def get_bot_config_raw(): @router.post("/bot/raw") -async def update_bot_config_raw(raw_content: RawContentBody): +async def update_bot_config_raw(raw_content: RawContentBody, _auth: bool = Depends(require_auth)): """更新麦麦主程序配置(直接保存原始 TOML 内容,会先验证格式)""" try: # 验证 TOML 格式 @@ -337,7 +346,9 @@ async def update_bot_config_raw(raw_content: RawContentBody): @router.post("/model/section/{section_name}") -async def update_model_config_section(section_name: str, section_data: SectionBody): +async def update_model_config_section( + section_name: str, section_data: SectionBody, _auth: bool = Depends(require_auth) +): """更新模型配置的指定节(保留注释和格式)""" try: # 读取现有配置 @@ -368,6 +379,17 @@ async def update_model_config_section(section_name: str, section_data: SectionBo try: APIAdapterConfig.from_dict(config_data) except Exception as e: + logger.error(f"配置数据验证失败,详细错误: {str(e)}") + # 特殊处理:如果是更新 api_providers,检查是否有模型引用了已删除的provider + if section_name == "api_providers" and "api_provider" in str(e): + provider_names = {p.get("name") for p in section_data if isinstance(p, dict)} + models = config_data.get("models", []) + orphaned_models = [ + m.get("name") for m in models if isinstance(m, dict) and m.get("api_provider") not in provider_names + ] + if orphaned_models: + error_msg = f"以下模型引用了已删除的提供商: {', '.join(orphaned_models)}。请先在模型管理页面删除这些模型,或重新分配它们的提供商。" + raise HTTPException(status_code=400, detail=error_msg) from e raise HTTPException(status_code=400, detail=f"配置数据验证失败: {str(e)}") from e # 保存配置(格式化数组为多行,保留注释) @@ -418,7 +440,7 @@ def _to_relative_path(path: str) -> str: @router.get("/adapter-config/path") -async def get_adapter_config_path(): +async def get_adapter_config_path(_auth: bool = Depends(require_auth)): """获取保存的适配器配置文件路径""" try: # 从 data/webui.json 读取路径偏好 @@ -457,7 +479,7 @@ async def get_adapter_config_path(): @router.post("/adapter-config/path") -async def save_adapter_config_path(data: PathBody): +async def save_adapter_config_path(data: PathBody, _auth: bool = Depends(require_auth)): """保存适配器配置文件路径偏好""" try: path = data.get("path") @@ -500,7 +522,7 @@ async def save_adapter_config_path(data: PathBody): @router.get("/adapter-config") -async def get_adapter_config(path: str): +async def get_adapter_config(path: str, _auth: bool = Depends(require_auth)): """从指定路径读取适配器配置文件""" try: if not path: @@ -532,7 +554,7 @@ async def get_adapter_config(path: str): @router.post("/adapter-config") -async def save_adapter_config(data: PathBody): +async def save_adapter_config(data: PathBody, _auth: bool = Depends(require_auth)): """保存适配器配置到指定路径""" try: path = data.get("path") diff --git a/src/webui/emoji_routes.py b/src/webui/emoji_routes.py index 0784a26a..90b2d60b 100644 --- a/src/webui/emoji_routes.py +++ b/src/webui/emoji_routes.py @@ -1,4 +1,4 @@ -""" 表情包管理 API 路由""" +"""表情包管理 API 路由""" from fastapi import APIRouter, HTTPException, Header, Query, UploadFile, File, Form, Cookie from fastapi.responses import FileResponse, JSONResponse @@ -48,7 +48,7 @@ def _get_thumbnail_lock(file_hash: str) -> threading.Lock: def _background_generate_thumbnail(source_path: str, file_hash: str) -> None: """ 后台生成缩略图(在线程池中执行) - + 生成完成后自动从 generating 集合中移除 """ try: @@ -74,14 +74,14 @@ def _get_thumbnail_cache_path(file_hash: str) -> Path: def _generate_thumbnail(source_path: str, file_hash: str) -> Path: """ 生成缩略图并保存到缓存目录 - + Args: source_path: 原图路径 file_hash: 文件哈希值,用作缓存文件名 - + Returns: 缩略图路径 - + Features: - GIF: 提取第一帧作为缩略图 - 所有格式统一转为 WebP @@ -89,63 +89,63 @@ def _generate_thumbnail(source_path: str, file_hash: str) -> Path: """ _ensure_thumbnail_cache_dir() cache_path = _get_thumbnail_cache_path(file_hash) - + # 使用锁防止并发生成同一缩略图 lock = _get_thumbnail_lock(file_hash) with lock: # 双重检查,可能在等待锁时已被其他线程生成 if cache_path.exists(): return cache_path - + try: with Image.open(source_path) as img: # GIF 处理:提取第一帧 - if hasattr(img, 'n_frames') and img.n_frames > 1: + if hasattr(img, "n_frames") and img.n_frames > 1: img.seek(0) # 确保在第一帧 - + # 转换为 RGB/RGBA(WebP 支持透明度) - if img.mode in ('P', 'PA'): + if img.mode in ("P", "PA"): # 调色板模式转换为 RGBA 以保留透明度 - img = img.convert('RGBA') - elif img.mode == 'LA': - img = img.convert('RGBA') - elif img.mode not in ('RGB', 'RGBA'): - img = img.convert('RGB') - + img = img.convert("RGBA") + elif img.mode == "LA": + img = img.convert("RGBA") + elif img.mode not in ("RGB", "RGBA"): + img = img.convert("RGB") + # 创建缩略图(保持宽高比) img.thumbnail(THUMBNAIL_SIZE, Image.Resampling.LANCZOS) - + # 保存为 WebP 格式 - img.save(cache_path, 'WEBP', quality=THUMBNAIL_QUALITY, method=6) - + img.save(cache_path, "WEBP", quality=THUMBNAIL_QUALITY, method=6) + logger.debug(f"生成缩略图: {file_hash} -> {cache_path}") - + except Exception as e: logger.warning(f"生成缩略图失败 {file_hash}: {e},将返回原图") # 生成失败时不创建缓存文件,下次会重试 raise - + return cache_path def cleanup_orphaned_thumbnails() -> tuple[int, int]: """ 清理孤立的缩略图缓存(原图已不存在的缩略图) - + Returns: (清理数量, 保留数量) """ if not THUMBNAIL_CACHE_DIR.exists(): return 0, 0 - + # 获取所有表情包的哈希值 valid_hashes = set() for emoji in Emoji.select(Emoji.emoji_hash): valid_hashes.add(emoji.emoji_hash) - + cleaned = 0 kept = 0 - + for cache_file in THUMBNAIL_CACHE_DIR.glob("*.webp"): file_hash = cache_file.stem if file_hash not in valid_hashes: @@ -157,12 +157,13 @@ def cleanup_orphaned_thumbnails() -> tuple[int, int]: logger.warning(f"清理缩略图失败 {cache_file.name}: {e}") else: kept += 1 - + if cleaned > 0: logger.info(f"清理孤立缩略图: 删除 {cleaned} 个,保留 {kept} 个") - + return cleaned, kept + # 模块级别的类型别名(解决 B008 ruff 错误) EmojiFile = Annotated[UploadFile, File(description="表情包图片文件")] EmojiFiles = Annotated[List[UploadFile], File(description="多个表情包图片文件")] @@ -365,7 +366,9 @@ async def get_emoji_list( @router.get("/{emoji_id}", response_model=EmojiDetailResponse) -async def get_emoji_detail(emoji_id: int, maibot_session: Optional[str] = Cookie(None), authorization: Optional[str] = Header(None)): +async def get_emoji_detail( + emoji_id: int, maibot_session: Optional[str] = Cookie(None), authorization: Optional[str] = Header(None) +): """ 获取表情包详细信息 @@ -394,7 +397,12 @@ async def get_emoji_detail(emoji_id: int, maibot_session: Optional[str] = Cookie @router.patch("/{emoji_id}", response_model=EmojiUpdateResponse) -async def update_emoji(emoji_id: int, request: EmojiUpdateRequest, maibot_session: Optional[str] = Cookie(None), authorization: Optional[str] = Header(None)): +async def update_emoji( + emoji_id: int, + request: EmojiUpdateRequest, + maibot_session: Optional[str] = Cookie(None), + authorization: Optional[str] = Header(None), +): """ 增量更新表情包(只更新提供的字段) @@ -446,7 +454,9 @@ async def update_emoji(emoji_id: int, request: EmojiUpdateRequest, maibot_sessio @router.delete("/{emoji_id}", response_model=EmojiDeleteResponse) -async def delete_emoji(emoji_id: int, maibot_session: Optional[str] = Cookie(None), authorization: Optional[str] = Header(None)): +async def delete_emoji( + emoji_id: int, maibot_session: Optional[str] = Cookie(None), authorization: Optional[str] = Header(None) +): """ 删除表情包 @@ -538,7 +548,9 @@ async def get_emoji_stats(maibot_session: Optional[str] = Cookie(None), authoriz @router.post("/{emoji_id}/register", response_model=EmojiUpdateResponse) -async def register_emoji(emoji_id: int, maibot_session: Optional[str] = Cookie(None), authorization: Optional[str] = Header(None)): +async def register_emoji( + emoji_id: int, maibot_session: Optional[str] = Cookie(None), authorization: Optional[str] = Header(None) +): """ 注册表情包(快捷操作) @@ -578,7 +590,9 @@ async def register_emoji(emoji_id: int, maibot_session: Optional[str] = Cookie(N @router.post("/{emoji_id}/ban", response_model=EmojiUpdateResponse) -async def ban_emoji(emoji_id: int, maibot_session: Optional[str] = Cookie(None), authorization: Optional[str] = Header(None)): +async def ban_emoji( + emoji_id: int, maibot_session: Optional[str] = Cookie(None), authorization: Optional[str] = Header(None) +): """ 禁用表情包(快捷操作) @@ -633,7 +647,7 @@ async def get_emoji_thumbnail( Returns: 表情包缩略图(WebP 格式)或原图 - + Features: - 懒加载:首次请求时生成缩略图 - 缓存:后续请求直接返回缓存 @@ -643,7 +657,7 @@ async def get_emoji_thumbnail( try: token_manager = get_token_manager() is_valid = False - + # 1. 优先使用 Cookie if maibot_session and token_manager.verify_token(maibot_session): is_valid = True @@ -655,7 +669,7 @@ async def get_emoji_thumbnail( auth_token = authorization.replace("Bearer ", "") if token_manager.verify_token(auth_token): is_valid = True - + if not is_valid: raise HTTPException(status_code=401, detail="Token 无效或已过期") @@ -680,35 +694,27 @@ async def get_emoji_thumbnail( } media_type = mime_types.get(emoji.format.lower(), "application/octet-stream") return FileResponse( - path=emoji.full_path, - media_type=media_type, - filename=f"{emoji.emoji_hash}.{emoji.format}" + path=emoji.full_path, media_type=media_type, filename=f"{emoji.emoji_hash}.{emoji.format}" ) # 尝试获取或生成缩略图 cache_path = _get_thumbnail_cache_path(emoji.emoji_hash) - + # 检查缓存是否存在 if cache_path.exists(): # 缓存命中,直接返回 return FileResponse( - path=str(cache_path), - media_type="image/webp", - filename=f"{emoji.emoji_hash}_thumb.webp" + path=str(cache_path), media_type="image/webp", filename=f"{emoji.emoji_hash}_thumb.webp" ) - + # 缓存未命中,触发后台生成并返回 202 with _generating_lock: if emoji.emoji_hash not in _generating_thumbnails: # 标记为正在生成 _generating_thumbnails.add(emoji.emoji_hash) # 提交到线程池后台生成 - _thumbnail_executor.submit( - _background_generate_thumbnail, - emoji.full_path, - emoji.emoji_hash - ) - + _thumbnail_executor.submit(_background_generate_thumbnail, emoji.full_path, emoji.emoji_hash) + # 返回 202 Accepted,告诉前端缩略图正在生成中 return JSONResponse( status_code=202, @@ -719,7 +725,7 @@ async def get_emoji_thumbnail( }, headers={ "Retry-After": "1", # 建议 1 秒后重试 - } + }, ) except HTTPException: @@ -730,7 +736,11 @@ async def get_emoji_thumbnail( @router.post("/batch/delete", response_model=BatchDeleteResponse) -async def batch_delete_emojis(request: BatchDeleteRequest, maibot_session: Optional[str] = Cookie(None), authorization: Optional[str] = Header(None)): +async def batch_delete_emojis( + request: BatchDeleteRequest, + maibot_session: Optional[str] = Cookie(None), + authorization: Optional[str] = Header(None), +): """ 批量删除表情包 @@ -1079,7 +1089,7 @@ async def batch_upload_emoji( class ThumbnailCacheStatsResponse(BaseModel): """缩略图缓存统计响应""" - + success: bool cache_dir: str total_count: int @@ -1090,7 +1100,7 @@ class ThumbnailCacheStatsResponse(BaseModel): class ThumbnailCleanupResponse(BaseModel): """缩略图清理响应""" - + success: bool message: str cleaned_count: int @@ -1099,7 +1109,7 @@ class ThumbnailCleanupResponse(BaseModel): class ThumbnailPreheatResponse(BaseModel): """缩略图预热响应""" - + success: bool message: str generated_count: int @@ -1114,27 +1124,27 @@ async def get_thumbnail_cache_stats( ): """ 获取缩略图缓存统计信息 - + Returns: 缓存目录、缓存数量、总大小、覆盖率等统计信息 """ try: verify_auth_token(maibot_session, authorization) - + _ensure_thumbnail_cache_dir() - + # 统计缓存文件 cache_files = list(THUMBNAIL_CACHE_DIR.glob("*.webp")) total_count = len(cache_files) total_size = sum(f.stat().st_size for f in cache_files) total_size_mb = round(total_size / (1024 * 1024), 2) - + # 统计表情包总数 emoji_count = Emoji.select().count() - + # 计算覆盖率 coverage_percent = round((total_count / emoji_count * 100) if emoji_count > 0 else 0, 1) - + return ThumbnailCacheStatsResponse( success=True, cache_dir=str(THUMBNAIL_CACHE_DIR.absolute()), @@ -1143,7 +1153,7 @@ async def get_thumbnail_cache_stats( emoji_count=emoji_count, coverage_percent=coverage_percent, ) - + except HTTPException: raise except Exception as e: @@ -1158,22 +1168,22 @@ async def cleanup_thumbnail_cache( ): """ 清理孤立的缩略图缓存(原图已删除的表情包对应的缩略图) - + Returns: 清理结果 """ try: verify_auth_token(maibot_session, authorization) - + cleaned, kept = cleanup_orphaned_thumbnails() - + return ThumbnailCleanupResponse( success=True, message=f"清理完成:删除 {cleaned} 个孤立缓存,保留 {kept} 个有效缓存", cleaned_count=cleaned, kept_count=kept, ) - + except HTTPException: raise except Exception as e: @@ -1189,20 +1199,20 @@ async def preheat_thumbnail_cache( ): """ 预热缩略图缓存(提前生成未缓存的缩略图) - + 优先处理使用次数高的表情包 - + Args: limit: 最多预热数量 (1-1000) - + Returns: 预热结果 """ try: verify_auth_token(maibot_session, authorization) - + _ensure_thumbnail_cache_dir() - + # 获取使用次数最高的表情包(未缓存的优先) emojis = ( Emoji.select() @@ -1210,41 +1220,36 @@ async def preheat_thumbnail_cache( .order_by(Emoji.usage_count.desc()) .limit(limit * 2) # 多查一些,因为有些可能已缓存 ) - + generated = 0 skipped = 0 failed = 0 - + for emoji in emojis: if generated >= limit: break - + cache_path = _get_thumbnail_cache_path(emoji.emoji_hash) - + # 已缓存,跳过 if cache_path.exists(): skipped += 1 continue - + # 原文件不存在,跳过 if not os.path.exists(emoji.full_path): failed += 1 continue - + try: # 使用线程池异步生成缩略图,避免阻塞事件循环 loop = asyncio.get_event_loop() - await loop.run_in_executor( - _thumbnail_executor, - _generate_thumbnail, - emoji.full_path, - emoji.emoji_hash - ) + await loop.run_in_executor(_thumbnail_executor, _generate_thumbnail, emoji.full_path, emoji.emoji_hash) generated += 1 except Exception as e: logger.warning(f"预热缩略图失败 {emoji.emoji_hash}: {e}") failed += 1 - + return ThumbnailPreheatResponse( success=True, message=f"预热完成:生成 {generated} 个,跳过 {skipped} 个已缓存,失败 {failed} 个", @@ -1252,7 +1257,7 @@ async def preheat_thumbnail_cache( skipped_count=skipped, failed_count=failed, ) - + except HTTPException: raise except Exception as e: @@ -1267,13 +1272,13 @@ async def clear_all_thumbnail_cache( ): """ 清空所有缩略图缓存(下次访问时会重新生成) - + Returns: 清理结果 """ try: verify_auth_token(maibot_session, authorization) - + if not THUMBNAIL_CACHE_DIR.exists(): return ThumbnailCleanupResponse( success=True, @@ -1281,7 +1286,7 @@ async def clear_all_thumbnail_cache( cleaned_count=0, kept_count=0, ) - + cleaned = 0 for cache_file in THUMBNAIL_CACHE_DIR.glob("*.webp"): try: @@ -1289,16 +1294,16 @@ async def clear_all_thumbnail_cache( cleaned += 1 except Exception as e: logger.warning(f"删除缓存文件失败 {cache_file.name}: {e}") - + logger.info(f"已清空缩略图缓存: 删除 {cleaned} 个文件") - + return ThumbnailCleanupResponse( success=True, message=f"已清空所有缩略图缓存:删除 {cleaned} 个文件", cleaned_count=cleaned, kept_count=0, ) - + except HTTPException: raise except Exception as e: diff --git a/src/webui/expression_routes.py b/src/webui/expression_routes.py index 1fa0ce7d..b6ec76b3 100644 --- a/src/webui/expression_routes.py +++ b/src/webui/expression_routes.py @@ -256,7 +256,9 @@ async def get_expression_list( @router.get("/{expression_id}", response_model=ExpressionDetailResponse) -async def get_expression_detail(expression_id: int, maibot_session: Optional[str] = Cookie(None), authorization: Optional[str] = Header(None)): +async def get_expression_detail( + expression_id: int, maibot_session: Optional[str] = Cookie(None), authorization: Optional[str] = Header(None) +): """ 获取表达方式详细信息 @@ -285,7 +287,11 @@ async def get_expression_detail(expression_id: int, maibot_session: Optional[str @router.post("/", response_model=ExpressionCreateResponse) -async def create_expression(request: ExpressionCreateRequest, maibot_session: Optional[str] = Cookie(None), authorization: Optional[str] = Header(None)): +async def create_expression( + request: ExpressionCreateRequest, + maibot_session: Optional[str] = Cookie(None), + authorization: Optional[str] = Header(None), +): """ 创建新的表达方式 @@ -326,7 +332,10 @@ async def create_expression(request: ExpressionCreateRequest, maibot_session: Op @router.patch("/{expression_id}", response_model=ExpressionUpdateResponse) async def update_expression( - expression_id: int, request: ExpressionUpdateRequest, maibot_session: Optional[str] = Cookie(None), authorization: Optional[str] = Header(None) + expression_id: int, + request: ExpressionUpdateRequest, + maibot_session: Optional[str] = Cookie(None), + authorization: Optional[str] = Header(None), ): """ 增量更新表达方式(只更新提供的字段) @@ -376,7 +385,9 @@ async def update_expression( @router.delete("/{expression_id}", response_model=ExpressionDeleteResponse) -async def delete_expression(expression_id: int, maibot_session: Optional[str] = Cookie(None), authorization: Optional[str] = Header(None)): +async def delete_expression( + expression_id: int, maibot_session: Optional[str] = Cookie(None), authorization: Optional[str] = Header(None) +): """ 删除表达方式 @@ -419,7 +430,11 @@ class BatchDeleteRequest(BaseModel): @router.post("/batch/delete", response_model=ExpressionDeleteResponse) -async def batch_delete_expressions(request: BatchDeleteRequest, maibot_session: Optional[str] = Cookie(None), authorization: Optional[str] = Header(None)): +async def batch_delete_expressions( + request: BatchDeleteRequest, + maibot_session: Optional[str] = Cookie(None), + authorization: Optional[str] = Header(None), +): """ 批量删除表达方式 @@ -460,7 +475,9 @@ async def batch_delete_expressions(request: BatchDeleteRequest, maibot_session: @router.get("/stats/summary") -async def get_expression_stats(maibot_session: Optional[str] = Cookie(None), authorization: Optional[str] = Header(None)): +async def get_expression_stats( + maibot_session: Optional[str] = Cookie(None), authorization: Optional[str] = Header(None) +): """ 获取表达方式统计数据 diff --git a/src/webui/jargon_routes.py b/src/webui/jargon_routes.py index 318912e8..8d372688 100644 --- a/src/webui/jargon_routes.py +++ b/src/webui/jargon_routes.py @@ -24,7 +24,7 @@ def parse_chat_id_to_stream_ids(chat_id_str: str) -> List[str]: """ if not chat_id_str: return [] - + try: # 尝试解析为 JSON parsed = json.loads(chat_id_str) @@ -49,10 +49,10 @@ def get_display_name_for_chat_id(chat_id_str: str) -> str: 尝试解析 JSON 并查询 ChatStreams 表获取群聊名称 """ stream_ids = parse_chat_id_to_stream_ids(chat_id_str) - + if not stream_ids: return chat_id_str - + # 查询所有 stream_id 对应的名称 names = [] for stream_id in stream_ids: @@ -62,7 +62,7 @@ def get_display_name_for_chat_id(chat_id_str: str) -> str: else: # 如果没找到,显示截断的 stream_id names.append(stream_id[:8] + "..." if len(stream_id) > 8 else stream_id) - + return ", ".join(names) if names else chat_id_str @@ -187,7 +187,7 @@ def jargon_to_dict(jargon: Jargon) -> dict: chat_name = get_display_name_for_chat_id(jargon.chat_id) if jargon.chat_id else None stream_ids = parse_chat_id_to_stream_ids(jargon.chat_id) if jargon.chat_id else [] stream_id = stream_ids[0] if stream_ids else None - + return { "id": jargon.id, "content": jargon.content, @@ -277,17 +277,13 @@ async def get_chat_list(): """获取所有有黑话记录的聊天列表""" try: # 获取所有不同的 chat_id - chat_ids = ( - Jargon.select(Jargon.chat_id) - .distinct() - .where(Jargon.chat_id.is_null(False)) - ) + chat_ids = Jargon.select(Jargon.chat_id).distinct().where(Jargon.chat_id.is_null(False)) chat_id_list = [j.chat_id for j in chat_ids if j.chat_id] # 用于按 stream_id 去重 seen_stream_ids: set[str] = set() - + for chat_id in chat_id_list: stream_ids = parse_chat_id_to_stream_ids(chat_id) if stream_ids: @@ -346,12 +342,7 @@ async def get_jargon_stats(): complete_count = Jargon.select().where(Jargon.is_complete).count() # 关联的聊天数量 - chat_count = ( - Jargon.select(Jargon.chat_id) - .distinct() - .where(Jargon.chat_id.is_null(False)) - .count() - ) + chat_count = Jargon.select(Jargon.chat_id).distinct().where(Jargon.chat_id.is_null(False)).count() # 按聊天统计 TOP 5 top_chats = ( @@ -403,9 +394,7 @@ async def create_jargon(request: JargonCreateRequest): """创建黑话""" try: # 检查是否已存在相同内容的黑话 - existing = Jargon.get_or_none( - (Jargon.content == request.content) & (Jargon.chat_id == request.chat_id) - ) + existing = Jargon.get_or_none((Jargon.content == request.content) & (Jargon.chat_id == request.chat_id)) if existing: raise HTTPException(status_code=400, detail="该聊天中已存在相同内容的黑话") @@ -527,11 +516,7 @@ async def batch_set_jargon_status( if not ids: raise HTTPException(status_code=400, detail="ID列表不能为空") - updated_count = ( - Jargon.update(is_jargon=is_jargon) - .where(Jargon.id.in_(ids)) - .execute() - ) + updated_count = Jargon.update(is_jargon=is_jargon).where(Jargon.id.in_(ids)).execute() logger.info(f"批量更新黑话状态成功: 更新了 {updated_count} 条记录,is_jargon={is_jargon}") diff --git a/src/webui/knowledge_routes.py b/src/webui/knowledge_routes.py index af4594b6..87b2e7b5 100644 --- a/src/webui/knowledge_routes.py +++ b/src/webui/knowledge_routes.py @@ -1,15 +1,24 @@ """知识库图谱可视化 API 路由""" from typing import List, Optional -from fastapi import APIRouter, Query +from fastapi import APIRouter, Query, Depends, Cookie, Header from pydantic import BaseModel import logging +from src.webui.auth import verify_auth_token_from_cookie_or_header logger = logging.getLogger(__name__) router = APIRouter(prefix="/api/webui/knowledge", tags=["knowledge"]) +def require_auth( + maibot_session: Optional[str] = Cookie(None), + authorization: Optional[str] = Header(None), +) -> bool: + """认证依赖:验证用户是否已登录""" + return verify_auth_token_from_cookie_or_header(maibot_session, authorization) + + class KnowledgeNode(BaseModel): """知识节点""" @@ -113,6 +122,7 @@ def _convert_graph_to_json(kg_manager) -> KnowledgeGraph: async def get_knowledge_graph( limit: int = Query(100, ge=1, le=10000, description="返回的最大节点数"), node_type: str = Query("all", description="节点类型过滤: all, entity, paragraph"), + _auth: bool = Depends(require_auth), ): """获取知识图谱(限制节点数量) @@ -199,7 +209,7 @@ async def get_knowledge_graph( @router.get("/stats", response_model=KnowledgeStats) -async def get_knowledge_stats(): +async def get_knowledge_stats(_auth: bool = Depends(require_auth)): """获取知识库统计信息 Returns: @@ -248,7 +258,7 @@ async def get_knowledge_stats(): @router.get("/search", response_model=List[KnowledgeNode]) -async def search_knowledge_node(query: str = Query(..., min_length=1)): +async def search_knowledge_node(query: str = Query(..., min_length=1), _auth: bool = Depends(require_auth)): """搜索知识节点 Args: diff --git a/src/webui/logs_ws.py b/src/webui/logs_ws.py index e0e0a9a1..5ae92189 100644 --- a/src/webui/logs_ws.py +++ b/src/webui/logs_ws.py @@ -1,10 +1,12 @@ """WebSocket 日志推送模块""" -from fastapi import APIRouter, WebSocket, WebSocketDisconnect -from typing import Set +from fastapi import APIRouter, WebSocket, WebSocketDisconnect, Query +from typing import Set, Optional import json from pathlib import Path from src.common.logger import get_logger +from src.webui.token_manager import get_token_manager +from src.webui.ws_auth import verify_ws_token logger = get_logger("webui.logs_ws") router = APIRouter() @@ -73,14 +75,48 @@ def load_recent_logs(limit: int = 100) -> list[dict]: @router.websocket("/ws/logs") -async def websocket_logs(websocket: WebSocket): +async def websocket_logs(websocket: WebSocket, token: Optional[str] = Query(None)): """WebSocket 日志推送端点 客户端连接后会持续接收服务器端的日志消息 + 支持三种认证方式(按优先级): + 1. query 参数 token(推荐,通过 /api/webui/ws-token 获取临时 token) + 2. Cookie 中的 maibot_session + 3. 直接使用 session token(兼容) + + 示例:ws://host/ws/logs?token=xxx """ + is_authenticated = False + + # 方式 1: 尝试验证临时 WebSocket token(推荐方式) + if token and verify_ws_token(token): + is_authenticated = True + logger.debug("WebSocket 使用临时 token 认证成功") + + # 方式 2: 尝试从 Cookie 获取 session token + if not is_authenticated: + cookie_token = websocket.cookies.get("maibot_session") + if cookie_token: + token_manager = get_token_manager() + if token_manager.verify_token(cookie_token): + is_authenticated = True + logger.debug("WebSocket 使用 Cookie 认证成功") + + # 方式 3: 尝试直接验证 query 参数作为 session token(兼容旧方式) + if not is_authenticated and token: + token_manager = get_token_manager() + if token_manager.verify_token(token): + is_authenticated = True + logger.debug("WebSocket 使用 session token 认证成功") + + if not is_authenticated: + logger.warning("WebSocket 连接被拒绝:认证失败") + await websocket.close(code=4001, reason="认证失败,请重新登录") + return + await websocket.accept() active_connections.add(websocket) - logger.info(f"📡 WebSocket 客户端已连接,当前连接数: {len(active_connections)}") + logger.info(f"📡 WebSocket 客户端已连接(已认证),当前连接数: {len(active_connections)}") # 连接建立后,立即发送历史日志 try: diff --git a/src/webui/model_routes.py b/src/webui/model_routes.py index 7d8310ee..a84241b9 100644 --- a/src/webui/model_routes.py +++ b/src/webui/model_routes.py @@ -6,18 +6,27 @@ import os import httpx -from fastapi import APIRouter, HTTPException, Query +from fastapi import APIRouter, HTTPException, Query, Depends, Cookie, Header from typing import Optional import tomlkit from src.common.logger import get_logger from src.config.config import CONFIG_DIR +from src.webui.auth import verify_auth_token_from_cookie_or_header logger = get_logger("webui") router = APIRouter(prefix="/models", tags=["models"]) +def require_auth( + maibot_session: Optional[str] = Cookie(None), + authorization: Optional[str] = Header(None), +) -> bool: + """认证依赖:验证用户是否已登录""" + return verify_auth_token_from_cookie_or_header(maibot_session, authorization) + + # 模型获取器配置 MODEL_FETCHER_CONFIG = { # OpenAI 兼容格式的提供商 @@ -184,6 +193,7 @@ async def get_provider_models( provider_name: str = Query(..., description="提供商名称"), parser: str = Query("openai", description="响应解析器类型 (openai | gemini)"), endpoint: str = Query("/models", description="获取模型列表的端点"), + _auth: bool = Depends(require_auth), ): """ 获取指定提供商的可用模型列表 @@ -228,6 +238,7 @@ async def get_models_by_url( parser: str = Query("openai", description="响应解析器类型 (openai | gemini)"), endpoint: str = Query("/models", description="获取模型列表的端点"), client_type: str = Query("openai", description="客户端类型 (openai | gemini)"), + _auth: bool = Depends(require_auth), ): """ 通过 URL 直接获取模型列表(用于自定义提供商) @@ -251,6 +262,7 @@ async def get_models_by_url( async def test_provider_connection( base_url: str = Query(..., description="提供商的基础 URL"), api_key: Optional[str] = Query(None, description="API Key(可选,用于验证 Key 有效性)"), + _auth: bool = Depends(require_auth), ): """ 测试提供商连接状态 @@ -337,6 +349,7 @@ async def test_provider_connection( @router.post("/test-connection-by-name") async def test_provider_connection_by_name( provider_name: str = Query(..., description="提供商名称"), + _auth: bool = Depends(require_auth), ): """ 通过提供商名称测试连接(从配置文件读取信息) diff --git a/src/webui/person_routes.py b/src/webui/person_routes.py index 5c039371..9881d44e 100644 --- a/src/webui/person_routes.py +++ b/src/webui/person_routes.py @@ -200,7 +200,9 @@ async def get_person_list( @router.get("/{person_id}", response_model=PersonDetailResponse) -async def get_person_detail(person_id: str, maibot_session: Optional[str] = Cookie(None), authorization: Optional[str] = Header(None)): +async def get_person_detail( + person_id: str, maibot_session: Optional[str] = Cookie(None), authorization: Optional[str] = Header(None) +): """ 获取人物详细信息 @@ -229,7 +231,12 @@ async def get_person_detail(person_id: str, maibot_session: Optional[str] = Cook @router.patch("/{person_id}", response_model=PersonUpdateResponse) -async def update_person(person_id: str, request: PersonUpdateRequest, maibot_session: Optional[str] = Cookie(None), authorization: Optional[str] = Header(None)): +async def update_person( + person_id: str, + request: PersonUpdateRequest, + maibot_session: Optional[str] = Cookie(None), + authorization: Optional[str] = Header(None), +): """ 增量更新人物信息(只更新提供的字段) @@ -278,7 +285,9 @@ async def update_person(person_id: str, request: PersonUpdateRequest, maibot_ses @router.delete("/{person_id}", response_model=PersonDeleteResponse) -async def delete_person(person_id: str, maibot_session: Optional[str] = Cookie(None), authorization: Optional[str] = Header(None)): +async def delete_person( + person_id: str, maibot_session: Optional[str] = Cookie(None), authorization: Optional[str] = Header(None) +): """ 删除人物信息 @@ -348,7 +357,11 @@ async def get_person_stats(maibot_session: Optional[str] = Cookie(None), authori @router.post("/batch/delete", response_model=BatchDeleteResponse) -async def batch_delete_persons(request: BatchDeleteRequest, maibot_session: Optional[str] = Cookie(None), authorization: Optional[str] = Header(None)): +async def batch_delete_persons( + request: BatchDeleteRequest, + maibot_session: Optional[str] = Cookie(None), + authorization: Optional[str] = Header(None), +): """ 批量删除人物信息 diff --git a/src/webui/plugin_progress_ws.py b/src/webui/plugin_progress_ws.py index 7e0fb647..8d0a18c6 100644 --- a/src/webui/plugin_progress_ws.py +++ b/src/webui/plugin_progress_ws.py @@ -1,10 +1,12 @@ """WebSocket 插件加载进度推送模块""" -from fastapi import APIRouter, WebSocket, WebSocketDisconnect -from typing import Set, Dict, Any +from fastapi import APIRouter, WebSocket, WebSocketDisconnect, Query +from typing import Set, Dict, Any, Optional import json import asyncio from src.common.logger import get_logger +from src.webui.token_manager import get_token_manager +from src.webui.ws_auth import verify_ws_token logger = get_logger("webui.plugin_progress") @@ -89,14 +91,48 @@ async def update_progress( @router.websocket("/ws/plugin-progress") -async def websocket_plugin_progress(websocket: WebSocket): +async def websocket_plugin_progress(websocket: WebSocket, token: Optional[str] = Query(None)): """WebSocket 插件加载进度推送端点 客户端连接后会立即收到当前进度状态 + 支持三种认证方式(按优先级): + 1. query 参数 token(推荐,通过 /api/webui/ws-token 获取临时 token) + 2. Cookie 中的 maibot_session + 3. 直接使用 session token(兼容) + + 示例:ws://host/ws/plugin-progress?token=xxx """ + is_authenticated = False + + # 方式 1: 尝试验证临时 WebSocket token(推荐方式) + if token and verify_ws_token(token): + is_authenticated = True + logger.debug("插件进度 WebSocket 使用临时 token 认证成功") + + # 方式 2: 尝试从 Cookie 获取 session token + if not is_authenticated: + cookie_token = websocket.cookies.get("maibot_session") + if cookie_token: + token_manager = get_token_manager() + if token_manager.verify_token(cookie_token): + is_authenticated = True + logger.debug("插件进度 WebSocket 使用 Cookie 认证成功") + + # 方式 3: 尝试直接验证 query 参数作为 session token(兼容旧方式) + if not is_authenticated and token: + token_manager = get_token_manager() + if token_manager.verify_token(token): + is_authenticated = True + logger.debug("插件进度 WebSocket 使用 session token 认证成功") + + if not is_authenticated: + logger.warning("插件进度 WebSocket 连接被拒绝:认证失败") + await websocket.close(code=4001, reason="认证失败,请重新登录") + return + await websocket.accept() active_connections.add(websocket) - logger.info(f"📡 插件进度 WebSocket 客户端已连接,当前连接数: {len(active_connections)}") + logger.info(f"📡 插件进度 WebSocket 客户端已连接(已认证),当前连接数: {len(active_connections)}") try: # 发送当前进度状态 diff --git a/src/webui/plugin_routes.py b/src/webui/plugin_routes.py index a99d36f5..1d11a20c 100644 --- a/src/webui/plugin_routes.py +++ b/src/webui/plugin_routes.py @@ -34,6 +34,85 @@ def get_token_from_cookie_or_header( return None +def validate_safe_path(user_path: str, base_path: Path) -> Path: + """ + 验证用户提供的路径是否安全,防止路径遍历攻击 + + Args: + user_path: 用户输入的路径(相对路径) + base_path: 允许的基础目录 + + Returns: + 安全的绝对路径 + + Raises: + HTTPException: 如果检测到路径遍历攻击 + """ + # 规范化基础路径 + base_resolved = base_path.resolve() + + # 检查用户路径是否包含可疑字符 + # 禁止: .., 绝对路径开头, 空字节等 + if any(pattern in user_path for pattern in ["..", "\x00"]): + logger.warning(f"检测到可疑路径: {user_path}") + raise HTTPException(status_code=400, detail="路径包含非法字符") + + # 检查是否为绝对路径(Windows 和 Unix) + if user_path.startswith("/") or user_path.startswith("\\") or (len(user_path) > 1 and user_path[1] == ":"): + logger.warning(f"检测到绝对路径: {user_path}") + raise HTTPException(status_code=400, detail="不允许使用绝对路径") + + # 构建目标路径并解析 + target_path = (base_path / user_path).resolve() + + # 验证解析后的路径仍在基础目录内 + try: + target_path.relative_to(base_resolved) + except ValueError as e: + logger.warning(f"路径遍历攻击检测: {user_path} -> {target_path}") + raise HTTPException(status_code=400, detail="路径超出允许范围") from e + + return target_path + + +def validate_plugin_id(plugin_id: str) -> str: + """ + 验证插件 ID 格式是否安全 + + Args: + plugin_id: 插件 ID (支持 author.name 格式,允许中文) + + Returns: + 验证通过的插件 ID + + Raises: + HTTPException: 如果插件 ID 格式不安全 + """ + # 禁止空字符串 + if not plugin_id or not plugin_id.strip(): + logger.warning("非法插件 ID: 空字符串") + raise HTTPException(status_code=400, detail="插件 ID 不能为空") + + # 禁止危险字符: 路径分隔符、空字节、控制字符等 + dangerous_patterns = ["/", "\\", "\x00", "..", "\n", "\r", "\t"] + for pattern in dangerous_patterns: + if pattern in plugin_id: + logger.warning(f"非法插件 ID 格式: {plugin_id} (包含危险字符)") + raise HTTPException(status_code=400, detail="插件 ID 包含非法字符") + + # 禁止以点开头或结尾(防止隐藏文件和路径问题) + if plugin_id.startswith(".") or plugin_id.endswith("."): + logger.warning(f"非法插件 ID: {plugin_id}") + raise HTTPException(status_code=400, detail="插件 ID 不能以点开头或结尾") + + # 禁止特殊名称 + if plugin_id in (".", ".."): + logger.warning(f"非法插件 ID: {plugin_id}") + raise HTTPException(status_code=400, detail="插件 ID 不能为特殊目录名") + + return plugin_id + + def parse_version(version_str: str) -> tuple[int, int, int]: """ 解析版本号字符串 @@ -125,6 +204,7 @@ def coerce_types(schema_part: Dict[str, Any], config_part: Dict[str, Any]) -> No """ 根据 schema 将配置中的类型纠正(目前只纠正 list-from-str)。 """ + def _is_list_type(tp: Any) -> bool: origin = get_origin(tp) return tp is list or origin is list @@ -313,7 +393,9 @@ async def check_git_status() -> GitStatusResponse: @router.get("/mirrors", response_model=AvailableMirrorsResponse) -async def get_available_mirrors(maibot_session: Optional[str] = Cookie(None), authorization: Optional[str] = Header(None)) -> AvailableMirrorsResponse: +async def get_available_mirrors( + maibot_session: Optional[str] = Cookie(None), authorization: Optional[str] = Header(None) +) -> AvailableMirrorsResponse: """ 获取所有可用的镜像源配置 """ @@ -343,7 +425,9 @@ async def get_available_mirrors(maibot_session: Optional[str] = Cookie(None), au @router.post("/mirrors", response_model=MirrorConfigResponse) -async def add_mirror(request: AddMirrorRequest, maibot_session: Optional[str] = Cookie(None), authorization: Optional[str] = Header(None)) -> MirrorConfigResponse: +async def add_mirror( + request: AddMirrorRequest, maibot_session: Optional[str] = Cookie(None), authorization: Optional[str] = Header(None) +) -> MirrorConfigResponse: """ 添加新的镜像源 """ @@ -383,7 +467,10 @@ async def add_mirror(request: AddMirrorRequest, maibot_session: Optional[str] = @router.put("/mirrors/{mirror_id}", response_model=MirrorConfigResponse) async def update_mirror( - mirror_id: str, request: UpdateMirrorRequest, maibot_session: Optional[str] = Cookie(None), authorization: Optional[str] = Header(None) + mirror_id: str, + request: UpdateMirrorRequest, + maibot_session: Optional[str] = Cookie(None), + authorization: Optional[str] = Header(None), ) -> MirrorConfigResponse: """ 更新镜像源配置 @@ -426,7 +513,9 @@ async def update_mirror( @router.delete("/mirrors/{mirror_id}") -async def delete_mirror(mirror_id: str, maibot_session: Optional[str] = Cookie(None), authorization: Optional[str] = Header(None)) -> Dict[str, Any]: +async def delete_mirror( + mirror_id: str, maibot_session: Optional[str] = Cookie(None), authorization: Optional[str] = Header(None) +) -> Dict[str, Any]: """ 删除镜像源 """ @@ -449,26 +538,24 @@ async def delete_mirror(mirror_id: str, maibot_session: Optional[str] = Cookie(N @router.post("/fetch-raw", response_model=FetchRawFileResponse) async def fetch_raw_file( - request: FetchRawFileRequest, maibot_session: Optional[str] = Cookie(None), authorization: Optional[str] = Header(None) + request: FetchRawFileRequest, + maibot_session: Optional[str] = Cookie(None), + authorization: Optional[str] = Header(None), ) -> FetchRawFileResponse: """ 获取 GitHub 仓库的 Raw 文件内容 支持多镜像源自动切换和错误重试 - 注意:此接口可公开访问,用于获取插件仓库等公开资源 + 需要认证才能访问,防止被滥用作为 SSRF 跳板 """ - # Token 验证(可选,用于日志记录) + # Token 验证(强制) token = get_token_from_cookie_or_header(maibot_session, authorization) token_manager = get_token_manager() - is_authenticated = token and token_manager.verify_token(token) + if not token or not token_manager.verify_token(token): + raise HTTPException(status_code=401, detail="未授权:无效的访问令牌") - # 对于公开仓库的访问,不强制要求认证 - # 只在日志中记录是否认证 - logger.info( - f"收到获取 Raw 文件请求 (认证: {is_authenticated}): " - f"{request.owner}/{request.repo}/{request.branch}/{request.file_path}" - ) + logger.info(f"收到获取 Raw 文件请求: {request.owner}/{request.repo}/{request.branch}/{request.file_path}") # 发送开始加载进度 await update_progress( @@ -534,7 +621,9 @@ async def fetch_raw_file( @router.post("/clone", response_model=CloneRepositoryResponse) async def clone_repository( - request: CloneRepositoryRequest, maibot_session: Optional[str] = Cookie(None), authorization: Optional[str] = Header(None) + request: CloneRepositoryRequest, + maibot_session: Optional[str] = Cookie(None), + authorization: Optional[str] = Header(None), ) -> CloneRepositoryResponse: """ 克隆 GitHub 仓库到本地 @@ -550,10 +639,10 @@ async def clone_repository( logger.info(f"收到克隆仓库请求: {request.owner}/{request.repo} -> {request.target_path}") try: - # TODO: 验证 target_path 的安全性,防止路径遍历攻击 - # TODO: 确定实际的插件目录基路径 - base_plugin_path = Path("./plugins") # 临时路径 - target_path = base_plugin_path / request.target_path + # 验证 target_path 的安全性,防止路径遍历攻击 + base_plugin_path = Path("./plugins").resolve() + base_plugin_path.mkdir(exist_ok=True) + target_path = validate_safe_path(request.target_path, base_plugin_path) service = get_git_mirror_service() result = await service.clone_repository( @@ -574,7 +663,11 @@ async def clone_repository( @router.post("/install") -async def install_plugin(request: InstallPluginRequest, maibot_session: Optional[str] = Cookie(None), authorization: Optional[str] = Header(None)) -> Dict[str, Any]: +async def install_plugin( + request: InstallPluginRequest, + maibot_session: Optional[str] = Cookie(None), + authorization: Optional[str] = Header(None), +) -> Dict[str, Any]: """ 安装插件 @@ -589,13 +682,16 @@ async def install_plugin(request: InstallPluginRequest, maibot_session: Optional logger.info(f"收到安装插件请求: {request.plugin_id}") try: + # 验证插件 ID 格式安全性 + plugin_id = validate_plugin_id(request.plugin_id) + # 推送进度:开始安装 await update_progress( stage="loading", progress=5, - message=f"开始安装插件: {request.plugin_id}", + message=f"开始安装插件: {plugin_id}", operation="install", - plugin_id=request.plugin_id, + plugin_id=plugin_id, ) # 1. 解析仓库 URL @@ -616,27 +712,28 @@ async def install_plugin(request: InstallPluginRequest, maibot_session: Optional progress=10, message=f"解析仓库信息: {owner}/{repo}", operation="install", - plugin_id=request.plugin_id, + plugin_id=plugin_id, ) # 2. 确定插件安装路径 - plugins_dir = Path("plugins") + plugins_dir = Path("plugins").resolve() plugins_dir.mkdir(exist_ok=True) # 将插件 ID 中的点替换为下划线作为文件夹名称(避免文件系统问题) # 例如: SengokuCola.Mute-Plugin -> SengokuCola_Mute-Plugin - folder_name = request.plugin_id.replace(".", "_") - target_path = plugins_dir / folder_name + folder_name = plugin_id.replace(".", "_") + # 使用安全路径验证,防止路径遍历 + target_path = validate_safe_path(folder_name, plugins_dir) # 检查插件是否已安装(需要检查两种格式:新格式下划线和旧格式点) - old_format_path = plugins_dir / request.plugin_id + old_format_path = plugins_dir / plugin_id if target_path.exists() or old_format_path.exists(): await update_progress( stage="error", progress=0, message="插件已存在", operation="install", - plugin_id=request.plugin_id, + plugin_id=plugin_id, error="插件已安装,请先卸载", ) raise HTTPException(status_code=400, detail="插件已安装") @@ -646,7 +743,7 @@ async def install_plugin(request: InstallPluginRequest, maibot_session: Optional progress=15, message=f"准备克隆到: {target_path}", operation="install", - plugin_id=request.plugin_id, + plugin_id=plugin_id, ) # 3. 克隆仓库(这里会自动推送 20%-80% 的进度) @@ -675,14 +772,14 @@ async def install_plugin(request: InstallPluginRequest, maibot_session: Optional progress=0, message="克隆仓库失败", operation="install", - plugin_id=request.plugin_id, + plugin_id=plugin_id, error=error_msg, ) raise HTTPException(status_code=500, detail=error_msg) # 4. 验证插件完整性 await update_progress( - stage="loading", progress=85, message="验证插件文件...", operation="install", plugin_id=request.plugin_id + stage="loading", progress=85, message="验证插件文件...", operation="install", plugin_id=plugin_id ) manifest_path = target_path / "_manifest.json" @@ -697,14 +794,14 @@ async def install_plugin(request: InstallPluginRequest, maibot_session: Optional progress=0, message="插件缺少 _manifest.json", operation="install", - plugin_id=request.plugin_id, + plugin_id=plugin_id, error="无效的插件格式", ) raise HTTPException(status_code=400, detail="无效的插件:缺少 _manifest.json") # 5. 读取并验证 manifest await update_progress( - stage="loading", progress=90, message="读取插件配置...", operation="install", plugin_id=request.plugin_id + stage="loading", progress=90, message="读取插件配置...", operation="install", plugin_id=plugin_id ) try: @@ -721,7 +818,7 @@ async def install_plugin(request: InstallPluginRequest, maibot_session: Optional # 将插件 ID 写入 manifest(用于后续准确识别) # 这样即使文件夹名称改变,也能通过 manifest 准确识别插件 - manifest["id"] = request.plugin_id + manifest["id"] = plugin_id with open(manifest_path, "w", encoding="utf-8") as f: json_module.dump(manifest, f, ensure_ascii=False, indent=2) @@ -736,7 +833,7 @@ async def install_plugin(request: InstallPluginRequest, maibot_session: Optional progress=0, message="_manifest.json 无效", operation="install", - plugin_id=request.plugin_id, + plugin_id=plugin_id, error=str(e), ) raise HTTPException(status_code=400, detail=f"无效的 _manifest.json: {e}") from e @@ -747,13 +844,13 @@ async def install_plugin(request: InstallPluginRequest, maibot_session: Optional progress=100, message=f"成功安装插件: {manifest['name']} v{manifest['version']}", operation="install", - plugin_id=request.plugin_id, + plugin_id=plugin_id, ) return { "success": True, "message": "插件安装成功", - "plugin_id": request.plugin_id, + "plugin_id": plugin_id, "plugin_name": manifest["name"], "version": manifest["version"], "path": str(target_path), @@ -769,7 +866,7 @@ async def install_plugin(request: InstallPluginRequest, maibot_session: Optional progress=0, message="安装失败", operation="install", - plugin_id=request.plugin_id, + plugin_id=plugin_id, error=str(e), ) @@ -778,7 +875,9 @@ async def install_plugin(request: InstallPluginRequest, maibot_session: Optional @router.post("/uninstall") async def uninstall_plugin( - request: UninstallPluginRequest, maibot_session: Optional[str] = Cookie(None), authorization: Optional[str] = Header(None) + request: UninstallPluginRequest, + maibot_session: Optional[str] = Cookie(None), + authorization: Optional[str] = Header(None), ) -> Dict[str, Any]: """ 卸载插件 @@ -794,22 +893,26 @@ async def uninstall_plugin( logger.info(f"收到卸载插件请求: {request.plugin_id}") try: + # 验证插件 ID 格式安全性 + plugin_id = validate_plugin_id(request.plugin_id) + # 推送进度:开始卸载 await update_progress( stage="loading", progress=10, - message=f"开始卸载插件: {request.plugin_id}", + message=f"开始卸载插件: {plugin_id}", operation="uninstall", - plugin_id=request.plugin_id, + plugin_id=plugin_id, ) # 1. 检查插件是否存在(支持新旧两种格式) - plugins_dir = Path("plugins") + plugins_dir = Path("plugins").resolve() # 新格式:下划线 - folder_name = request.plugin_id.replace(".", "_") - plugin_path = plugins_dir / folder_name + folder_name = plugin_id.replace(".", "_") + # 使用安全路径验证 + plugin_path = validate_safe_path(folder_name, plugins_dir) # 旧格式:点 - old_format_path = plugins_dir / request.plugin_id + old_format_path = validate_safe_path(plugin_id, plugins_dir) # 优先使用新格式,如果不存在则尝试旧格式 if not plugin_path.exists(): @@ -821,7 +924,7 @@ async def uninstall_plugin( progress=0, message="插件不存在", operation="uninstall", - plugin_id=request.plugin_id, + plugin_id=plugin_id, error="插件未安装或已被删除", ) raise HTTPException(status_code=404, detail="插件未安装") @@ -831,12 +934,12 @@ async def uninstall_plugin( progress=30, message=f"正在删除插件文件: {plugin_path}", operation="uninstall", - plugin_id=request.plugin_id, + plugin_id=plugin_id, ) # 2. 读取插件信息(用于日志) manifest_path = plugin_path / "_manifest.json" - plugin_name = request.plugin_id + plugin_name = plugin_id if manifest_path.exists(): try: @@ -844,7 +947,7 @@ async def uninstall_plugin( with open(manifest_path, "r", encoding="utf-8") as f: manifest = json_module.load(f) - plugin_name = manifest.get("name", request.plugin_id) + plugin_name = manifest.get("name", plugin_id) except Exception: pass # 如果读取失败,使用插件 ID 作为名称 @@ -853,7 +956,7 @@ async def uninstall_plugin( progress=50, message=f"正在删除 {plugin_name}...", operation="uninstall", - plugin_id=request.plugin_id, + plugin_id=plugin_id, ) # 3. 删除插件目录 @@ -869,7 +972,7 @@ async def uninstall_plugin( shutil.rmtree(plugin_path, onerror=remove_readonly) - logger.info(f"成功卸载插件: {request.plugin_id} ({plugin_name})") + logger.info(f"成功卸载插件: {plugin_id} ({plugin_name})") # 4. 推送成功状态 await update_progress( @@ -877,10 +980,10 @@ async def uninstall_plugin( progress=100, message=f"成功卸载插件: {plugin_name}", operation="uninstall", - plugin_id=request.plugin_id, + plugin_id=plugin_id, ) - return {"success": True, "message": "插件卸载成功", "plugin_id": request.plugin_id, "plugin_name": plugin_name} + return {"success": True, "message": "插件卸载成功", "plugin_id": plugin_id, "plugin_name": plugin_name} except HTTPException: raise @@ -892,7 +995,7 @@ async def uninstall_plugin( progress=0, message="卸载失败", operation="uninstall", - plugin_id=request.plugin_id, + plugin_id=plugin_id, error="权限不足,无法删除插件文件", ) @@ -905,7 +1008,7 @@ async def uninstall_plugin( progress=0, message="卸载失败", operation="uninstall", - plugin_id=request.plugin_id, + plugin_id=plugin_id, error=str(e), ) @@ -913,7 +1016,11 @@ async def uninstall_plugin( @router.post("/update") -async def update_plugin(request: UpdatePluginRequest, maibot_session: Optional[str] = Cookie(None), authorization: Optional[str] = Header(None)) -> Dict[str, Any]: +async def update_plugin( + request: UpdatePluginRequest, + maibot_session: Optional[str] = Cookie(None), + authorization: Optional[str] = Header(None), +) -> Dict[str, Any]: """ 更新插件 @@ -928,22 +1035,26 @@ async def update_plugin(request: UpdatePluginRequest, maibot_session: Optional[s logger.info(f"收到更新插件请求: {request.plugin_id}") try: + # 验证插件 ID 格式安全性 + plugin_id = validate_plugin_id(request.plugin_id) + # 推送进度:开始更新 await update_progress( stage="loading", progress=5, - message=f"开始更新插件: {request.plugin_id}", + message=f"开始更新插件: {plugin_id}", operation="update", - plugin_id=request.plugin_id, + plugin_id=plugin_id, ) # 1. 检查插件是否已安装(支持新旧两种格式) - plugins_dir = Path("plugins") + plugins_dir = Path("plugins").resolve() # 新格式:下划线 - folder_name = request.plugin_id.replace(".", "_") - plugin_path = plugins_dir / folder_name + folder_name = plugin_id.replace(".", "_") + # 使用安全路径验证 + plugin_path = validate_safe_path(folder_name, plugins_dir) # 旧格式:点 - old_format_path = plugins_dir / request.plugin_id + old_format_path = validate_safe_path(plugin_id, plugins_dir) # 优先使用新格式,如果不存在则尝试旧格式 if not plugin_path.exists(): @@ -955,7 +1066,7 @@ async def update_plugin(request: UpdatePluginRequest, maibot_session: Optional[s progress=0, message="插件不存在", operation="update", - plugin_id=request.plugin_id, + plugin_id=plugin_id, error="插件未安装,请先安装", ) raise HTTPException(status_code=404, detail="插件未安装") @@ -979,12 +1090,12 @@ async def update_plugin(request: UpdatePluginRequest, maibot_session: Optional[s progress=10, message=f"当前版本: {old_version},准备更新...", operation="update", - plugin_id=request.plugin_id, + plugin_id=plugin_id, ) # 3. 删除旧版本 await update_progress( - stage="loading", progress=20, message="正在删除旧版本...", operation="update", plugin_id=request.plugin_id + stage="loading", progress=20, message="正在删除旧版本...", operation="update", plugin_id=plugin_id ) import shutil @@ -999,7 +1110,7 @@ async def update_plugin(request: UpdatePluginRequest, maibot_session: Optional[s shutil.rmtree(plugin_path, onerror=remove_readonly) - logger.info(f"已删除旧版本: {request.plugin_id} v{old_version}") + logger.info(f"已删除旧版本: {plugin_id} v{old_version}") # 4. 解析仓库 URL await update_progress( @@ -1007,7 +1118,7 @@ async def update_plugin(request: UpdatePluginRequest, maibot_session: Optional[s progress=30, message="正在准备下载新版本...", operation="update", - plugin_id=request.plugin_id, + plugin_id=plugin_id, ) repo_url = request.repository_url.rstrip("/") @@ -1045,14 +1156,14 @@ async def update_plugin(request: UpdatePluginRequest, maibot_session: Optional[s progress=0, message="下载新版本失败", operation="update", - plugin_id=request.plugin_id, + plugin_id=plugin_id, error=error_msg, ) raise HTTPException(status_code=500, detail=error_msg) # 6. 验证新版本 await update_progress( - stage="loading", progress=90, message="验证新版本...", operation="update", plugin_id=request.plugin_id + stage="loading", progress=90, message="验证新版本...", operation="update", plugin_id=plugin_id ) new_manifest_path = plugin_path / "_manifest.json" @@ -1072,7 +1183,7 @@ async def update_plugin(request: UpdatePluginRequest, maibot_session: Optional[s progress=0, message="新版本缺少 _manifest.json", operation="update", - plugin_id=request.plugin_id, + plugin_id=plugin_id, error="无效的插件格式", ) raise HTTPException(status_code=400, detail="无效的插件:缺少 _manifest.json") @@ -1083,9 +1194,9 @@ async def update_plugin(request: UpdatePluginRequest, maibot_session: Optional[s new_manifest = json_module.load(f) new_version = new_manifest.get("version", "unknown") - new_name = new_manifest.get("name", request.plugin_id) + new_name = new_manifest.get("name", plugin_id) - logger.info(f"成功更新插件: {request.plugin_id} {old_version} → {new_version}") + logger.info(f"成功更新插件: {plugin_id} {old_version} → {new_version}") # 8. 推送成功状态 await update_progress( @@ -1093,13 +1204,13 @@ async def update_plugin(request: UpdatePluginRequest, maibot_session: Optional[s progress=100, message=f"成功更新 {new_name}: {old_version} → {new_version}", operation="update", - plugin_id=request.plugin_id, + plugin_id=plugin_id, ) return { "success": True, "message": "插件更新成功", - "plugin_id": request.plugin_id, + "plugin_id": plugin_id, "plugin_name": new_name, "old_version": old_version, "new_version": new_version, @@ -1114,7 +1225,7 @@ async def update_plugin(request: UpdatePluginRequest, maibot_session: Optional[s progress=0, message="_manifest.json 无效", operation="update", - plugin_id=request.plugin_id, + plugin_id=plugin_id, error=str(e), ) raise HTTPException(status_code=400, detail=f"无效的 _manifest.json: {e}") from e @@ -1125,14 +1236,16 @@ async def update_plugin(request: UpdatePluginRequest, maibot_session: Optional[s logger.error(f"更新插件失败: {e}", exc_info=True) await update_progress( - stage="error", progress=0, message="更新失败", operation="update", plugin_id=request.plugin_id, error=str(e) + stage="error", progress=0, message="更新失败", operation="update", plugin_id=plugin_id, error=str(e) ) raise HTTPException(status_code=500, detail=f"服务器错误: {str(e)}") from e @router.get("/installed") -async def get_installed_plugins(maibot_session: Optional[str] = Cookie(None), authorization: Optional[str] = Header(None)) -> Dict[str, Any]: +async def get_installed_plugins( + maibot_session: Optional[str] = Cookie(None), authorization: Optional[str] = Header(None) +) -> Dict[str, Any]: """ 获取已安装的插件列表 @@ -1272,7 +1385,9 @@ class UpdatePluginConfigRequest(BaseModel): @router.get("/config/{plugin_id}/schema") -async def get_plugin_config_schema(plugin_id: str, maibot_session: Optional[str] = Cookie(None), authorization: Optional[str] = Header(None)) -> Dict[str, Any]: +async def get_plugin_config_schema( + plugin_id: str, maibot_session: Optional[str] = Cookie(None), authorization: Optional[str] = Header(None) +) -> Dict[str, Any]: """ 获取插件配置 Schema @@ -1373,12 +1488,34 @@ async def get_plugin_config_schema(plugin_id: str, maibot_session: Optional[str] # 推断字段类型 field_type = type(field_value).__name__ ui_type = "text" + item_type = None + item_fields = None + if isinstance(field_value, bool): ui_type = "switch" elif isinstance(field_value, (int, float)): ui_type = "number" elif isinstance(field_value, list): ui_type = "list" + # 推断数组元素类型 + if field_value: + first_item = field_value[0] + if isinstance(first_item, dict): + item_type = "object" + # 从第一个元素推断字段结构 + item_fields = {} + for k, v in first_item.items(): + item_fields[k] = { + "type": "number" if isinstance(v, (int, float)) else "string", + "label": k, + "default": "" if isinstance(v, str) else 0, + } + elif isinstance(first_item, (int, float)): + item_type = "number" + else: + item_type = "string" + else: + item_type = "string" elif isinstance(field_value, dict): ui_type = "json" @@ -1393,6 +1530,26 @@ async def get_plugin_config_schema(plugin_id: str, maibot_session: Optional[str] "hidden": False, "disabled": False, "order": 0, + "item_type": item_type, + "item_fields": item_fields, + "min_items": None, + "max_items": None, + # 补充缺失的字段 + "placeholder": None, + "hint": None, + "icon": None, + "example": None, + "choices": None, + "min": None, + "max": None, + "step": None, + "pattern": None, + "max_length": None, + "input_type": None, + "rows": 3, + "group": None, + "depends_on": None, + "depends_value": None, } return {"success": True, "schema": schema} @@ -1405,7 +1562,9 @@ async def get_plugin_config_schema(plugin_id: str, maibot_session: Optional[str] @router.get("/config/{plugin_id}") -async def get_plugin_config(plugin_id: str, maibot_session: Optional[str] = Cookie(None), authorization: Optional[str] = Header(None)) -> Dict[str, Any]: +async def get_plugin_config( + plugin_id: str, maibot_session: Optional[str] = Cookie(None), authorization: Optional[str] = Header(None) +) -> Dict[str, Any]: """ 获取插件当前配置值 @@ -1461,7 +1620,10 @@ async def get_plugin_config(plugin_id: str, maibot_session: Optional[str] = Cook @router.put("/config/{plugin_id}") async def update_plugin_config( - plugin_id: str, request: UpdatePluginConfigRequest, maibot_session: Optional[str] = Cookie(None), authorization: Optional[str] = Header(None) + plugin_id: str, + request: UpdatePluginConfigRequest, + maibot_session: Optional[str] = Cookie(None), + authorization: Optional[str] = Header(None), ) -> Dict[str, Any]: """ 更新插件配置 @@ -1532,7 +1694,9 @@ async def update_plugin_config( @router.post("/config/{plugin_id}/reset") -async def reset_plugin_config(plugin_id: str, maibot_session: Optional[str] = Cookie(None), authorization: Optional[str] = Header(None)) -> Dict[str, Any]: +async def reset_plugin_config( + plugin_id: str, maibot_session: Optional[str] = Cookie(None), authorization: Optional[str] = Header(None) +) -> Dict[str, Any]: """ 重置插件配置为默认值 @@ -1592,7 +1756,9 @@ async def reset_plugin_config(plugin_id: str, maibot_session: Optional[str] = Co @router.post("/config/{plugin_id}/toggle") -async def toggle_plugin(plugin_id: str, maibot_session: Optional[str] = Cookie(None), authorization: Optional[str] = Header(None)) -> Dict[str, Any]: +async def toggle_plugin( + plugin_id: str, maibot_session: Optional[str] = Cookie(None), authorization: Optional[str] = Header(None) +) -> Dict[str, Any]: """ 切换插件启用状态 diff --git a/src/webui/rate_limiter.py b/src/webui/rate_limiter.py new file mode 100644 index 00000000..23cfc0f0 --- /dev/null +++ b/src/webui/rate_limiter.py @@ -0,0 +1,245 @@ +""" +WebUI 请求频率限制模块 +防止暴力破解和 API 滥用 +""" + +import time +from collections import defaultdict +from typing import Dict, Tuple, Optional +from fastapi import Request, HTTPException +from src.common.logger import get_logger + +logger = get_logger("webui.rate_limiter") + + +class RateLimiter: + """ + 简单的内存请求频率限制器 + + 使用滑动窗口算法实现 + """ + + def __init__(self): + # 存储格式: {key: [(timestamp, count), ...]} + self._requests: Dict[str, list] = defaultdict(list) + # 被封禁的 IP: {ip: unblock_timestamp} + self._blocked: Dict[str, float] = {} + + def _get_client_ip(self, request: Request) -> str: + """获取客户端 IP 地址""" + # 检查代理头 + forwarded = request.headers.get("X-Forwarded-For") + if forwarded: + # 取第一个 IP(最原始的客户端) + return forwarded.split(",")[0].strip() + + real_ip = request.headers.get("X-Real-IP") + if real_ip: + return real_ip + + # 直接连接的客户端 + if request.client: + return request.client.host + + return "unknown" + + def _cleanup_old_requests(self, key: str, window_seconds: int): + """清理过期的请求记录""" + now = time.time() + cutoff = now - window_seconds + self._requests[key] = [(ts, count) for ts, count in self._requests[key] if ts > cutoff] + + def _cleanup_expired_blocks(self): + """清理过期的封禁""" + now = time.time() + expired = [ip for ip, unblock_time in self._blocked.items() if now > unblock_time] + for ip in expired: + del self._blocked[ip] + logger.info(f"🔓 IP {ip} 封禁已解除") + + def is_blocked(self, request: Request) -> Tuple[bool, Optional[int]]: + """ + 检查 IP 是否被封禁 + + Returns: + (是否被封禁, 剩余封禁秒数) + """ + self._cleanup_expired_blocks() + ip = self._get_client_ip(request) + + if ip in self._blocked: + remaining = int(self._blocked[ip] - time.time()) + return True, max(0, remaining) + + return False, None + + def check_rate_limit( + self, request: Request, max_requests: int, window_seconds: int, key_suffix: str = "" + ) -> Tuple[bool, int]: + """ + 检查请求是否超过频率限制 + + Args: + request: FastAPI Request 对象 + max_requests: 窗口期内允许的最大请求数 + window_seconds: 窗口时间(秒) + key_suffix: 键后缀,用于区分不同的限制规则 + + Returns: + (是否允许, 剩余请求数) + """ + ip = self._get_client_ip(request) + key = f"{ip}:{key_suffix}" if key_suffix else ip + + # 清理过期记录 + self._cleanup_old_requests(key, window_seconds) + + # 计算当前窗口内的请求数 + current_count = sum(count for _, count in self._requests[key]) + + if current_count >= max_requests: + return False, 0 + + # 记录新请求 + now = time.time() + self._requests[key].append((now, 1)) + + remaining = max_requests - current_count - 1 + return True, remaining + + def block_ip(self, request: Request, duration_seconds: int): + """ + 封禁 IP + + Args: + request: FastAPI Request 对象 + duration_seconds: 封禁时长(秒) + """ + ip = self._get_client_ip(request) + self._blocked[ip] = time.time() + duration_seconds + logger.warning(f"🔒 IP {ip} 已被封禁 {duration_seconds} 秒") + + def record_failed_attempt( + self, request: Request, max_failures: int = 5, window_seconds: int = 300, block_duration: int = 600 + ) -> Tuple[bool, int]: + """ + 记录失败尝试(如登录失败) + + 如果在窗口期内失败次数过多,自动封禁 IP + + Args: + request: FastAPI Request 对象 + max_failures: 允许的最大失败次数 + window_seconds: 统计窗口(秒) + block_duration: 封禁时长(秒) + + Returns: + (是否被封禁, 剩余尝试次数) + """ + ip = self._get_client_ip(request) + key = f"{ip}:auth_failures" + + # 清理过期记录 + self._cleanup_old_requests(key, window_seconds) + + # 计算当前失败次数 + current_failures = sum(count for _, count in self._requests[key]) + + # 记录本次失败 + now = time.time() + self._requests[key].append((now, 1)) + current_failures += 1 + + remaining = max_failures - current_failures + + # 检查是否需要封禁 + if current_failures >= max_failures: + self.block_ip(request, block_duration) + logger.warning(f"⚠️ IP {ip} 认证失败次数过多 ({current_failures}/{max_failures}),已封禁") + return True, 0 + + if current_failures >= max_failures - 2: + logger.warning(f"⚠️ IP {ip} 认证失败 {current_failures}/{max_failures} 次") + + return False, max(0, remaining) + + def reset_failures(self, request: Request): + """ + 重置失败计数(认证成功后调用) + """ + ip = self._get_client_ip(request) + key = f"{ip}:auth_failures" + if key in self._requests: + del self._requests[key] + + +# 全局单例 +_rate_limiter: Optional[RateLimiter] = None + + +def get_rate_limiter() -> RateLimiter: + """获取 RateLimiter 单例""" + global _rate_limiter + if _rate_limiter is None: + _rate_limiter = RateLimiter() + return _rate_limiter + + +async def check_auth_rate_limit(request: Request): + """ + 认证接口的频率限制依赖 + + 规则: + - 每个 IP 每分钟最多 10 次认证请求 + - 连续失败 5 次后封禁 10 分钟 + """ + limiter = get_rate_limiter() + + # 检查是否被封禁 + blocked, remaining_block = limiter.is_blocked(request) + if blocked: + raise HTTPException( + status_code=429, + detail=f"请求过于频繁,请在 {remaining_block} 秒后重试", + headers={"Retry-After": str(remaining_block)}, + ) + + # 检查频率限制 + allowed, remaining = limiter.check_rate_limit( + request, + max_requests=10, # 每分钟 10 次 + window_seconds=60, + key_suffix="auth", + ) + + if not allowed: + raise HTTPException(status_code=429, detail="认证请求过于频繁,请稍后重试", headers={"Retry-After": "60"}) + + +async def check_api_rate_limit(request: Request): + """ + 普通 API 的频率限制依赖 + + 规则:每个 IP 每分钟最多 100 次请求 + """ + limiter = get_rate_limiter() + + # 检查是否被封禁 + blocked, remaining_block = limiter.is_blocked(request) + if blocked: + raise HTTPException( + status_code=429, + detail=f"请求过于频繁,请在 {remaining_block} 秒后重试", + headers={"Retry-After": str(remaining_block)}, + ) + + # 检查频率限制 + allowed, _ = limiter.check_rate_limit( + request, + max_requests=100, # 每分钟 100 次 + window_seconds=60, + key_suffix="api", + ) + + if not allowed: + raise HTTPException(status_code=429, detail="请求过于频繁,请稍后重试", headers={"Retry-After": "60"}) diff --git a/src/webui/routers/system.py b/src/webui/routers/system.py index d6932896..b1d3729a 100644 --- a/src/webui/routers/system.py +++ b/src/webui/routers/system.py @@ -7,10 +7,12 @@ import os import time from datetime import datetime -from fastapi import APIRouter, HTTPException +from typing import Optional +from fastapi import APIRouter, HTTPException, Depends, Cookie, Header from pydantic import BaseModel from src.config.config import MMC_VERSION from src.common.logger import get_logger +from src.webui.auth import verify_auth_token_from_cookie_or_header router = APIRouter(prefix="/system", tags=["system"]) logger = get_logger("webui_system") @@ -19,6 +21,14 @@ logger = get_logger("webui_system") _start_time = time.time() +def require_auth( + maibot_session: Optional[str] = Cookie(None), + authorization: Optional[str] = Header(None), +) -> bool: + """认证依赖:验证用户是否已登录""" + return verify_auth_token_from_cookie_or_header(maibot_session, authorization) + + class RestartResponse(BaseModel): """重启响应""" @@ -36,7 +46,7 @@ class StatusResponse(BaseModel): @router.post("/restart", response_model=RestartResponse) -async def restart_maibot(): +async def restart_maibot(_auth: bool = Depends(require_auth)): """ 重启麦麦主程序 @@ -67,7 +77,7 @@ async def restart_maibot(): @router.get("/status", response_model=StatusResponse) -async def get_maibot_status(): +async def get_maibot_status(_auth: bool = Depends(require_auth)): """ 获取麦麦运行状态 @@ -90,7 +100,7 @@ async def get_maibot_status(): @router.post("/reload-config") -async def reload_config(): +async def reload_config(_auth: bool = Depends(require_auth)): """ 热重载配置(不重启进程) diff --git a/src/webui/routes.py b/src/webui/routes.py index 96942f1d..bb92d6cc 100644 --- a/src/webui/routes.py +++ b/src/webui/routes.py @@ -1,11 +1,12 @@ """WebUI API 路由""" -from fastapi import APIRouter, HTTPException, Header, Response, Request, Cookie +from fastapi import APIRouter, HTTPException, Header, Response, Request, Cookie, Depends from pydantic import BaseModel, Field from typing import Optional from src.common.logger import get_logger from .token_manager import get_token_manager from .auth import set_auth_cookie, clear_auth_cookie +from .rate_limiter import get_rate_limiter, check_auth_rate_limit from .config_routes import router as config_router from .statistics_routes import router as statistics_router from .person_routes import router as person_router @@ -16,6 +17,7 @@ from .plugin_routes import router as plugin_router from .plugin_progress_ws import get_progress_router from .routers.system import router as system_router from .model_routes import router as model_router +from .ws_auth import router as ws_auth_router logger = get_logger("webui.api") @@ -42,6 +44,8 @@ router.include_router(get_progress_router()) router.include_router(system_router) # 注册模型列表获取路由 router.include_router(model_router) +# 注册 WebSocket 认证路由 +router.include_router(ws_auth_router) class TokenVerifyRequest(BaseModel): @@ -107,12 +111,18 @@ async def health_check(): @router.post("/auth/verify", response_model=TokenVerifyResponse) -async def verify_token(request: TokenVerifyRequest, response: Response): +async def verify_token( + request_body: TokenVerifyRequest, + request: Request, + response: Response, + _rate_limit: None = Depends(check_auth_rate_limit), +): """ 验证访问令牌,验证成功后设置 HttpOnly Cookie Args: - request: 包含 token 的验证请求 + request_body: 包含 token 的验证请求 + request: FastAPI Request 对象(用于获取客户端 IP) response: FastAPI Response 对象 Returns: @@ -120,16 +130,37 @@ async def verify_token(request: TokenVerifyRequest, response: Response): """ try: token_manager = get_token_manager() - is_valid = token_manager.verify_token(request.token) + rate_limiter = get_rate_limiter() + + is_valid = token_manager.verify_token(request_body.token) if is_valid: + # 认证成功,重置失败计数 + rate_limiter.reset_failures(request) # 设置 HttpOnly Cookie - set_auth_cookie(response, request.token) + set_auth_cookie(response, request_body.token) # 同时返回首次配置状态,避免额外请求 is_first_setup = token_manager.is_first_setup() return TokenVerifyResponse(valid=True, message="Token 验证成功", is_first_setup=is_first_setup) else: - return TokenVerifyResponse(valid=False, message="Token 无效或已过期") + # 记录失败尝试 + blocked, remaining = rate_limiter.record_failed_attempt( + request, + max_failures=5, # 5 次失败 + window_seconds=300, # 5 分钟窗口 + block_duration=600, # 封禁 10 分钟 + ) + + if blocked: + raise HTTPException(status_code=429, detail="认证失败次数过多,您的 IP 已被临时封禁 10 分钟") + + message = "Token 无效或已过期" + if remaining <= 2: + message += f"(剩余 {remaining} 次尝试机会)" + + return TokenVerifyResponse(valid=False, message=message) + except HTTPException: + raise except Exception as e: logger.error(f"Token 验证失败: {e}") raise HTTPException(status_code=500, detail="Token 验证失败") from e @@ -139,10 +170,10 @@ async def verify_token(request: TokenVerifyRequest, response: Response): async def logout(response: Response): """ 登出并清除认证 Cookie - + Args: response: FastAPI Response 对象 - + Returns: 登出结果 """ @@ -158,23 +189,23 @@ async def check_auth_status( ): """ 检查当前认证状态(用于前端判断是否已登录) - + Returns: 认证状态 """ try: token = None - + # 优先从 Cookie 获取 if maibot_session: token = maibot_session # 其次从 Header 获取 elif authorization and authorization.startswith("Bearer "): token = authorization.replace("Bearer ", "") - + if not token: return {"authenticated": False} - + token_manager = get_token_manager() if token_manager.verify_token(token): return {"authenticated": True} @@ -211,7 +242,7 @@ async def update_token( current_token = maibot_session elif authorization and authorization.startswith("Bearer "): current_token = authorization.replace("Bearer ", "") - + if not current_token: raise HTTPException(status_code=401, detail="未提供有效的认证信息") @@ -222,7 +253,7 @@ async def update_token( # 更新 token success, message = token_manager.update_token(request.new_token) - + # 如果更新成功,清除 Cookie,要求用户重新登录 if success: clear_auth_cookie(response) @@ -263,7 +294,7 @@ async def regenerate_token( if not current_token: raise HTTPException(status_code=401, detail="未提供有效的认证信息") - + token_manager = get_token_manager() if not token_manager.verify_token(current_token): @@ -271,7 +302,7 @@ async def regenerate_token( # 重新生成 token new_token = token_manager.regenerate_token() - + # 清除 Cookie,要求用户重新登录 clear_auth_cookie(response) @@ -306,7 +337,7 @@ async def get_setup_status( current_token = maibot_session elif authorization and authorization.startswith("Bearer "): current_token = authorization.replace("Bearer ", "") - + if not current_token: raise HTTPException(status_code=401, detail="未提供有效的认证信息") @@ -349,7 +380,7 @@ async def complete_setup( current_token = maibot_session elif authorization and authorization.startswith("Bearer "): current_token = authorization.replace("Bearer ", "") - + if not current_token: raise HTTPException(status_code=401, detail="未提供有效的认证信息") @@ -392,7 +423,7 @@ async def reset_setup( current_token = maibot_session elif authorization and authorization.startswith("Bearer "): current_token = authorization.replace("Bearer ", "") - + if not current_token: raise HTTPException(status_code=401, detail="未提供有效的认证信息") diff --git a/src/webui/statistics_routes.py b/src/webui/statistics_routes.py index b0a3664c..e5628538 100644 --- a/src/webui/statistics_routes.py +++ b/src/webui/statistics_routes.py @@ -1,19 +1,28 @@ """统计数据 API 路由""" -from fastapi import APIRouter, HTTPException +from fastapi import APIRouter, HTTPException, Depends, Cookie, Header from pydantic import BaseModel, Field -from typing import Dict, Any, List +from typing import Dict, Any, List, Optional from datetime import datetime, timedelta from peewee import fn from src.common.logger import get_logger from src.common.database.database_model import LLMUsage, OnlineTime, Messages +from src.webui.auth import verify_auth_token_from_cookie_or_header logger = get_logger("webui.statistics") router = APIRouter(prefix="/statistics", tags=["statistics"]) +def require_auth( + maibot_session: Optional[str] = Cookie(None), + authorization: Optional[str] = Header(None), +) -> bool: + """认证依赖:验证用户是否已登录""" + return verify_auth_token_from_cookie_or_header(maibot_session, authorization) + + class StatisticsSummary(BaseModel): """统计数据摘要""" @@ -58,7 +67,7 @@ class DashboardData(BaseModel): @router.get("/dashboard", response_model=DashboardData) -async def get_dashboard_data(hours: int = 24): +async def get_dashboard_data(hours: int = 24, _auth: bool = Depends(require_auth)): """ 获取仪表盘统计数据 @@ -275,7 +284,7 @@ async def _get_recent_activity(limit: int = 10) -> List[Dict[str, Any]]: @router.get("/summary") -async def get_summary(hours: int = 24): +async def get_summary(hours: int = 24, _auth: bool = Depends(require_auth)): """ 获取统计摘要 @@ -293,7 +302,7 @@ async def get_summary(hours: int = 24): @router.get("/models") -async def get_model_stats(hours: int = 24): +async def get_model_stats(hours: int = 24, _auth: bool = Depends(require_auth)): """ 获取模型统计 diff --git a/src/webui/token_manager.py b/src/webui/token_manager.py index 17e3f068..bd1e5fbb 100644 --- a/src/webui/token_manager.py +++ b/src/webui/token_manager.py @@ -166,22 +166,22 @@ class TokenManager: str: 新生成的 token """ logger.info("正在重新生成 WebUI Token...") - + # 生成新的 64 位十六进制字符串 new_token = secrets.token_hex(32) - + # 加载现有配置,保留 first_setup_completed 状态 config = self._load_config() old_token = config.get("access_token", "")[:8] if config.get("access_token") else "无" first_setup_completed = config.get("first_setup_completed", True) # 默认为 True,表示已完成配置 - + config["access_token"] = new_token config["updated_at"] = self._get_current_timestamp() config["first_setup_completed"] = first_setup_completed # 保留原来的状态 - + self._save_config(config) logger.info(f"WebUI Token 已重新生成: {old_token}... -> {new_token[:8]}...") - + return new_token def _validate_token_format(self, token: str) -> bool: diff --git a/src/webui/webui_server.py b/src/webui/webui_server.py index 21e79565..267787c4 100644 --- a/src/webui/webui_server.py +++ b/src/webui/webui_server.py @@ -22,6 +22,9 @@ class WebUIServer: self.app = FastAPI(title="MaiBot WebUI") self._server = None + # 配置防爬虫中间件(需要在CORS之前注册) + self._setup_anti_crawler() + # 配置 CORS(支持开发环境跨域请求) self._setup_cors() @@ -32,6 +35,9 @@ class WebUIServer: self._register_api_routes() self._setup_static_files() + # 注册robots.txt路由 + self._setup_robots_txt() + def _setup_cors(self): """配置 CORS 中间件""" # 开发环境需要允许前端开发服务器的跨域请求 @@ -40,12 +46,21 @@ class WebUIServer: allow_origins=[ "http://localhost:5173", # Vite 开发服务器 "http://127.0.0.1:5173", + "http://localhost:7999", # 前端开发服务器备用端口 + "http://127.0.0.1:7999", "http://localhost:8001", # 生产环境 "http://127.0.0.1:8001", ], allow_credentials=True, # 允许携带 Cookie - allow_methods=["*"], - allow_headers=["*"], + allow_methods=["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"], # 明确指定允许的方法 + allow_headers=[ + "Content-Type", + "Authorization", + "Accept", + "Origin", + "X-Requested-With", + ], # 明确指定允许的头 + expose_headers=["Content-Length", "Content-Type"], # 允许前端读取的响应头 ) logger.debug("✅ CORS 中间件已配置") @@ -89,20 +104,60 @@ class WebUIServer: """服务单页应用 - 只处理非 API 请求""" # 如果是根路径,直接返回 index.html if not full_path or full_path == "/": - return FileResponse(static_path / "index.html", media_type="text/html") + response = FileResponse(static_path / "index.html", media_type="text/html") + response.headers["X-Robots-Tag"] = "noindex, nofollow, noarchive" + return response # 检查是否是静态文件 file_path = static_path / full_path if file_path.is_file() and file_path.exists(): # 自动检测 MIME 类型 media_type = mimetypes.guess_type(str(file_path))[0] - return FileResponse(file_path, media_type=media_type) + response = FileResponse(file_path, media_type=media_type) + # HTML 文件添加防索引头 + if str(file_path).endswith(".html"): + response.headers["X-Robots-Tag"] = "noindex, nofollow, noarchive" + return response # 其他路径返回 index.html(SPA 路由) - return FileResponse(static_path / "index.html", media_type="text/html") + response = FileResponse(static_path / "index.html", media_type="text/html") + response.headers["X-Robots-Tag"] = "noindex, nofollow, noarchive" + return response logger.info(f"✅ WebUI 静态文件服务已配置: {static_path}") + def _setup_anti_crawler(self): + """配置防爬虫中间件""" + try: + from src.webui.anti_crawler import AntiCrawlerMiddleware + + # 从环境变量读取防爬虫模式(false/strict/loose/basic) + anti_crawler_mode = os.getenv("WEBUI_ANTI_CRAWLER_MODE", "basic").lower() + + # 注意:中间件按注册顺序反向执行,所以先注册的中间件后执行 + # 我们需要在CORS之前注册,这样防爬虫检查会在CORS之前执行 + self.app.add_middleware(AntiCrawlerMiddleware, mode=anti_crawler_mode) + + mode_descriptions = {"false": "已禁用", "strict": "严格模式", "loose": "宽松模式", "basic": "基础模式"} + mode_desc = mode_descriptions.get(anti_crawler_mode, "基础模式") + logger.info(f"🛡️ 防爬虫中间件已配置: {mode_desc}") + except Exception as e: + logger.error(f"❌ 配置防爬虫中间件失败: {e}", exc_info=True) + + def _setup_robots_txt(self): + """设置robots.txt路由""" + try: + from src.webui.anti_crawler import create_robots_txt_response + + @self.app.get("/robots.txt", include_in_schema=False) + async def robots_txt(): + """返回robots.txt,禁止所有爬虫""" + return create_robots_txt_response() + + logger.debug("✅ robots.txt 路由已注册") + except Exception as e: + logger.error(f"❌ 注册robots.txt路由失败: {e}", exc_info=True) + def _register_api_routes(self): """注册所有 WebUI API 路由""" try: @@ -110,8 +165,10 @@ class WebUIServer: from src.webui.routes import router as webui_router from src.webui.logs_ws import router as logs_router from src.webui.knowledge_routes import router as knowledge_router + # 导入本地聊天室路由 from src.webui.chat_routes import router as chat_router + # 注册路由 self.app.include_router(webui_router) self.app.include_router(logs_router) @@ -166,6 +223,7 @@ class WebUIServer: def _check_port_available(self) -> bool: """检查端口是否可用""" import socket + try: with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.settimeout(1) diff --git a/src/webui/ws_auth.py b/src/webui/ws_auth.py new file mode 100644 index 00000000..e6bb00e7 --- /dev/null +++ b/src/webui/ws_auth.py @@ -0,0 +1,114 @@ +"""WebSocket 认证模块 + +提供所有 WebSocket 端点统一使用的临时 token 认证机制。 +临时 token 有效期 60 秒,且只能使用一次,用于解决 WebSocket 握手时 Cookie 不可用的问题。 +""" + +from fastapi import APIRouter, Cookie, Header +from typing import Optional +import secrets +import time +from src.common.logger import get_logger +from src.webui.token_manager import get_token_manager + +logger = get_logger("webui.ws_auth") +router = APIRouter() + +# WebSocket 临时 token 存储 {token: (expire_time, session_token)} +# 临时 token 有效期 60 秒,仅用于 WebSocket 握手 +_ws_temp_tokens: dict[str, tuple[float, str]] = {} +_WS_TOKEN_EXPIRE_SECONDS = 60 + + +def _cleanup_expired_ws_tokens(): + """清理过期的临时 token""" + now = time.time() + expired = [t for t, (exp, _) in _ws_temp_tokens.items() if now > exp] + for t in expired: + del _ws_temp_tokens[t] + + +def generate_ws_token(session_token: str) -> str: + """生成 WebSocket 临时 token + + Args: + session_token: 原始的 session token + + Returns: + 临时 token 字符串 + """ + _cleanup_expired_ws_tokens() + temp_token = secrets.token_urlsafe(32) + _ws_temp_tokens[temp_token] = (time.time() + _WS_TOKEN_EXPIRE_SECONDS, session_token) + logger.debug(f"生成 WS 临时 token: {temp_token[:8]}... 有效期 {_WS_TOKEN_EXPIRE_SECONDS}s") + return temp_token + + +def verify_ws_token(temp_token: str) -> bool: + """验证并消费 WebSocket 临时 token(一次性使用) + + Args: + temp_token: 临时 token + + Returns: + 验证是否通过 + """ + _cleanup_expired_ws_tokens() + if temp_token not in _ws_temp_tokens: + logger.warning(f"WS token 不存在: {temp_token[:8]}...") + return False + expire_time, session_token = _ws_temp_tokens[temp_token] + if time.time() > expire_time: + del _ws_temp_tokens[temp_token] + logger.warning(f"WS token 已过期: {temp_token[:8]}...") + return False + # 验证原始 session token 仍然有效 + token_manager = get_token_manager() + if not token_manager.verify_token(session_token): + del _ws_temp_tokens[temp_token] + logger.warning(f"WS token 关联的 session 已失效: {temp_token[:8]}...") + return False + # 消费 token(一次性使用) + del _ws_temp_tokens[temp_token] + logger.debug(f"WS token 验证成功: {temp_token[:8]}...") + return True + + +@router.get("/ws-token") +async def get_ws_token( + maibot_session: Optional[str] = Cookie(None), + authorization: Optional[str] = Header(None), +): + """ + 获取 WebSocket 连接用的临时 token + + 此端点验证当前会话的 Cookie 或 Authorization header, + 然后返回一个临时 token 用于 WebSocket 握手认证。 + 临时 token 有效期 60 秒,且只能使用一次。 + + 注意:在未认证时返回 200 状态码但 success=False,避免前端因 401 刷新页面。 + """ + # 获取当前 session token + session_token = None + if maibot_session: + session_token = maibot_session + elif authorization and authorization.startswith("Bearer "): + session_token = authorization.replace("Bearer ", "") + + if not session_token: + # 返回 200 但 success=False,避免前端因 401 刷新页面 + # 这在登录页面是正常情况,不应该触发错误处理 + logger.debug("ws-token 请求:未提供认证信息(可能在登录页面)") + return {"success": False, "message": "未提供认证信息,请先登录", "token": None, "expires_in": 0} + + # 验证 session token + token_manager = get_token_manager() + if not token_manager.verify_token(session_token): + # 同样返回 200 但 success=False,避免前端刷新 + logger.debug("ws-token 请求:认证已过期") + return {"success": False, "message": "认证已过期,请重新登录", "token": None, "expires_in": 0} + + # 生成临时 WebSocket token + ws_token = generate_ws_token(session_token) + + return {"success": True, "token": ws_token, "expires_in": _WS_TOKEN_EXPIRE_SECONDS} diff --git a/template/template.env b/template/template.env index b6dd0e5c..1d46dcf5 100644 --- a/template/template.env +++ b/template/template.env @@ -6,4 +6,13 @@ PORT=8000 WEBUI_ENABLED=true WEBUI_MODE=production # 模式: development(开发) 或 production(生产) WEBUI_HOST=0.0.0.0 # WebUI 服务器监听地址 -WEBUI_PORT=8001 # WebUI 服务器端口 \ No newline at end of file +WEBUI_PORT=8001 # WebUI 服务器端口 + +# 防爬虫配置 +WEBUI_ANTI_CRAWLER_MODE=basic # 防爬虫模式: false(禁用) / strict(严格) / loose(宽松) / basic(基础-只记录不阻止) +WEBUI_ALLOWED_IPS=127.0.0.1 # IP白名单(逗号分隔,支持精确IP、CIDR格式和通配符) + # 示例: 127.0.0.1,192.168.1.0/24,172.17.0.0/16 +WEBUI_TRUSTED_PROXIES= # 信任的代理IP列表(逗号分隔),只有来自这些IP的X-Forwarded-For才被信任 + # 示例: 127.0.0.1,192.168.1.1,172.17.0.1 +WEBUI_TRUST_XFF=false # 是否启用X-Forwarded-For代理解析(默认false) + # 启用后,仍要求直连IP在TRUSTED_PROXIES中才会信任XFF头 \ No newline at end of file diff --git a/webui/dist/assets/dnd-B_gmzEl7.js b/webui/dist/assets/dnd-B_gmzEl7.js new file mode 100644 index 00000000..3d96b92e --- /dev/null +++ b/webui/dist/assets/dnd-B_gmzEl7.js @@ -0,0 +1,5 @@ +import{r as c,R as P,b as Oe}from"./router-Bz250laD.js";function Sn(){for(var e=arguments.length,t=new Array(e),n=0;nr=>{t.forEach(o=>o(r))},t)}const tt=typeof window<"u"&&typeof window.document<"u"&&typeof window.document.createElement<"u";function me(e){const t=Object.prototype.toString.call(e);return t==="[object Window]"||t==="[object global]"}function bt(e){return"nodeType"in e}function B(e){var t,n;return e?me(e)?e:bt(e)&&(t=(n=e.ownerDocument)==null?void 0:n.defaultView)!=null?t:window:window}function wt(e){const{Document:t}=B(e);return e instanceof t}function Be(e){return me(e)?!1:e instanceof B(e).HTMLElement}function Wt(e){return e instanceof B(e).SVGElement}function ye(e){return e?me(e)?e.document:bt(e)?wt(e)?e:Be(e)||Wt(e)?e.ownerDocument:document:document:document}const Q=tt?c.useLayoutEffect:c.useEffect;function mt(e){const t=c.useRef(e);return Q(()=>{t.current=e}),c.useCallback(function(){for(var n=arguments.length,r=new Array(n),o=0;o{e.current=setInterval(r,o)},[]),n=c.useCallback(()=>{e.current!==null&&(clearInterval(e.current),e.current=null)},[]);return[t,n]}function ke(e,t){t===void 0&&(t=[e]);const n=c.useRef(e);return Q(()=>{n.current!==e&&(n.current=e)},t),n}function Fe(e,t){const n=c.useRef();return c.useMemo(()=>{const r=e(n.current);return n.current=r,r},[...t])}function Je(e){const t=mt(e),n=c.useRef(null),r=c.useCallback(o=>{o!==n.current&&t?.(o,n.current),n.current=o},[]);return[n,r]}function ft(e){const t=c.useRef();return c.useEffect(()=>{t.current=e},[e]),t.current}let ct={};function $e(e,t){return c.useMemo(()=>{if(t)return t;const n=ct[e]==null?0:ct[e]+1;return ct[e]=n,e+"-"+n},[e,t])}function Ht(e){return function(t){for(var n=arguments.length,r=new Array(n>1?n-1:0),o=1;o{const a=Object.entries(s);for(const[l,u]of a){const f=i[l];f!=null&&(i[l]=f+e*u)}return i},{...t})}}const we=Ht(1),ze=Ht(-1);function In(e){return"clientX"in e&&"clientY"in e}function yt(e){if(!e)return!1;const{KeyboardEvent:t}=B(e.target);return t&&e instanceof t}function Mn(e){if(!e)return!1;const{TouchEvent:t}=B(e.target);return t&&e instanceof t}function ht(e){if(Mn(e)){if(e.touches&&e.touches.length){const{clientX:t,clientY:n}=e.touches[0];return{x:t,y:n}}else if(e.changedTouches&&e.changedTouches.length){const{clientX:t,clientY:n}=e.changedTouches[0];return{x:t,y:n}}}return In(e)?{x:e.clientX,y:e.clientY}:null}const _e=Object.freeze({Translate:{toString(e){if(!e)return;const{x:t,y:n}=e;return"translate3d("+(t?Math.round(t):0)+"px, "+(n?Math.round(n):0)+"px, 0)"}},Scale:{toString(e){if(!e)return;const{scaleX:t,scaleY:n}=e;return"scaleX("+t+") scaleY("+n+")"}},Transform:{toString(e){if(e)return[_e.Translate.toString(e),_e.Scale.toString(e)].join(" ")}},Transition:{toString(e){let{property:t,duration:n,easing:r}=e;return t+" "+n+"ms "+r}}}),Tt="a,frame,iframe,input:not([type=hidden]):not(:disabled),select:not(:disabled),textarea:not(:disabled),button:not(:disabled),*[tabindex]";function An(e){return e.matches(Tt)?e:e.querySelector(Tt)}const On={display:"none"};function Tn(e){let{id:t,value:n}=e;return P.createElement("div",{id:t,style:On},n)}function Nn(e){let{id:t,announcement:n,ariaLiveType:r="assertive"}=e;const o={position:"fixed",top:0,left:0,width:1,height:1,margin:-1,border:0,padding:0,overflow:"hidden",clip:"rect(0 0 0 0)",clipPath:"inset(100%)",whiteSpace:"nowrap"};return P.createElement("div",{id:t,style:o,role:"status","aria-live":r,"aria-atomic":!0},n)}function Ln(){const[e,t]=c.useState("");return{announce:c.useCallback(r=>{r!=null&&t(r)},[]),announcement:e}}const Kt=c.createContext(null);function kn(e){const t=c.useContext(Kt);c.useEffect(()=>{if(!t)throw new Error("useDndMonitor must be used within a children of ");return t(e)},[e,t])}function zn(){const[e]=c.useState(()=>new Set),t=c.useCallback(r=>(e.add(r),()=>e.delete(r)),[e]);return[c.useCallback(r=>{let{type:o,event:i}=r;e.forEach(s=>{var a;return(a=s[o])==null?void 0:a.call(s,i)})},[e]),t]}const Pn={draggable:` + To pick up a draggable item, press the space bar. + While dragging, use the arrow keys to move the item. + Press space again to drop the item in its new position, or press escape to cancel. + `},Bn={onDragStart(e){let{active:t}=e;return"Picked up draggable item "+t.id+"."},onDragOver(e){let{active:t,over:n}=e;return n?"Draggable item "+t.id+" was moved over droppable area "+n.id+".":"Draggable item "+t.id+" is no longer over a droppable area."},onDragEnd(e){let{active:t,over:n}=e;return n?"Draggable item "+t.id+" was dropped over droppable area "+n.id:"Draggable item "+t.id+" was dropped."},onDragCancel(e){let{active:t}=e;return"Dragging was cancelled. Draggable item "+t.id+" was dropped."}};function Fn(e){let{announcements:t=Bn,container:n,hiddenTextDescribedById:r,screenReaderInstructions:o=Pn}=e;const{announce:i,announcement:s}=Ln(),a=$e("DndLiveRegion"),[l,u]=c.useState(!1);if(c.useEffect(()=>{u(!0)},[]),kn(c.useMemo(()=>({onDragStart(d){let{active:g}=d;i(t.onDragStart({active:g}))},onDragMove(d){let{active:g,over:h}=d;t.onDragMove&&i(t.onDragMove({active:g,over:h}))},onDragOver(d){let{active:g,over:h}=d;i(t.onDragOver({active:g,over:h}))},onDragEnd(d){let{active:g,over:h}=d;i(t.onDragEnd({active:g,over:h}))},onDragCancel(d){let{active:g,over:h}=d;i(t.onDragCancel({active:g,over:h}))}}),[i,t])),!l)return null;const f=P.createElement(P.Fragment,null,P.createElement(Tn,{id:r,value:o.draggable}),P.createElement(Nn,{id:a,announcement:s}));return n?Oe.createPortal(f,n):f}var O;(function(e){e.DragStart="dragStart",e.DragMove="dragMove",e.DragEnd="dragEnd",e.DragCancel="dragCancel",e.DragOver="dragOver",e.RegisterDroppable="registerDroppable",e.SetDroppableDisabled="setDroppableDisabled",e.UnregisterDroppable="unregisterDroppable"})(O||(O={}));function Qe(){}function ao(e,t){return c.useMemo(()=>({sensor:e,options:t??{}}),[e,t])}function co(){for(var e=arguments.length,t=new Array(e),n=0;n[...t].filter(r=>r!=null),[...t])}const V=Object.freeze({x:0,y:0});function Vt(e,t){return Math.sqrt(Math.pow(e.x-t.x,2)+Math.pow(e.y-t.y,2))}function qt(e,t){let{data:{value:n}}=e,{data:{value:r}}=t;return n-r}function $n(e,t){let{data:{value:n}}=e,{data:{value:r}}=t;return r-n}function Nt(e){let{left:t,top:n,height:r,width:o}=e;return[{x:t,y:n},{x:t+o,y:n},{x:t,y:n+r},{x:t+o,y:n+r}]}function Gt(e,t){if(!e||e.length===0)return null;const[n]=e;return n[t]}function Lt(e,t,n){return t===void 0&&(t=e.left),n===void 0&&(n=e.top),{x:t+e.width*.5,y:n+e.height*.5}}const lo=e=>{let{collisionRect:t,droppableRects:n,droppableContainers:r}=e;const o=Lt(t,t.left,t.top),i=[];for(const s of r){const{id:a}=s,l=n.get(a);if(l){const u=Vt(Lt(l),o);i.push({id:a,data:{droppableContainer:s,value:u}})}}return i.sort(qt)},Xn=e=>{let{collisionRect:t,droppableRects:n,droppableContainers:r}=e;const o=Nt(t),i=[];for(const s of r){const{id:a}=s,l=n.get(a);if(l){const u=Nt(l),f=o.reduce((g,h,C)=>g+Vt(u[C],h),0),d=Number((f/4).toFixed(4));i.push({id:a,data:{droppableContainer:s,value:d}})}}return i.sort(qt)};function Yn(e,t){const n=Math.max(t.top,e.top),r=Math.max(t.left,e.left),o=Math.min(t.left+t.width,e.left+e.width),i=Math.min(t.top+t.height,e.top+e.height),s=o-r,a=i-n;if(r{let{collisionRect:t,droppableRects:n,droppableContainers:r}=e;const o=[];for(const i of r){const{id:s}=i,a=n.get(s);if(a){const l=Yn(a,t);l>0&&o.push({id:s,data:{droppableContainer:i,value:l}})}}return o.sort($n)};function Un(e,t,n){return{...e,scaleX:t&&n?t.width/n.width:1,scaleY:t&&n?t.height/n.height:1}}function Jt(e,t){return e&&t?{x:e.left-t.left,y:e.top-t.top}:V}function Wn(e){return function(n){for(var r=arguments.length,o=new Array(r>1?r-1:0),i=1;i({...s,top:s.top+e*a.y,bottom:s.bottom+e*a.y,left:s.left+e*a.x,right:s.right+e*a.x}),{...n})}}const Hn=Wn(1);function Kn(e){if(e.startsWith("matrix3d(")){const t=e.slice(9,-1).split(/, /);return{x:+t[12],y:+t[13],scaleX:+t[0],scaleY:+t[5]}}else if(e.startsWith("matrix(")){const t=e.slice(7,-1).split(/, /);return{x:+t[4],y:+t[5],scaleX:+t[0],scaleY:+t[3]}}return null}function Vn(e,t,n){const r=Kn(t);if(!r)return e;const{scaleX:o,scaleY:i,x:s,y:a}=r,l=e.left-s-(1-o)*parseFloat(n),u=e.top-a-(1-i)*parseFloat(n.slice(n.indexOf(" ")+1)),f=o?e.width/o:e.width,d=i?e.height/i:e.height;return{width:f,height:d,top:u,right:l+f,bottom:u+d,left:l}}const qn={ignoreTransform:!1};function xe(e,t){t===void 0&&(t=qn);let n=e.getBoundingClientRect();if(t.ignoreTransform){const{transform:u,transformOrigin:f}=B(e).getComputedStyle(e);u&&(n=Vn(n,u,f))}const{top:r,left:o,width:i,height:s,bottom:a,right:l}=n;return{top:r,left:o,width:i,height:s,bottom:a,right:l}}function kt(e){return xe(e,{ignoreTransform:!0})}function Gn(e){const t=e.innerWidth,n=e.innerHeight;return{top:0,left:0,right:t,bottom:n,width:t,height:n}}function Jn(e,t){return t===void 0&&(t=B(e).getComputedStyle(e)),t.position==="fixed"}function _n(e,t){t===void 0&&(t=B(e).getComputedStyle(e));const n=/(auto|scroll|overlay)/;return["overflow","overflowX","overflowY"].some(o=>{const i=t[o];return typeof i=="string"?n.test(i):!1})}function nt(e,t){const n=[];function r(o){if(t!=null&&n.length>=t||!o)return n;if(wt(o)&&o.scrollingElement!=null&&!n.includes(o.scrollingElement))return n.push(o.scrollingElement),n;if(!Be(o)||Wt(o)||n.includes(o))return n;const i=B(e).getComputedStyle(o);return o!==e&&_n(o,i)&&n.push(o),Jn(o,i)?n:r(o.parentNode)}return e?r(e):n}function _t(e){const[t]=nt(e,1);return t??null}function lt(e){return!tt||!e?null:me(e)?e:bt(e)?wt(e)||e===ye(e).scrollingElement?window:Be(e)?e:null:null}function Qt(e){return me(e)?e.scrollX:e.scrollLeft}function Zt(e){return me(e)?e.scrollY:e.scrollTop}function gt(e){return{x:Qt(e),y:Zt(e)}}var N;(function(e){e[e.Forward=1]="Forward",e[e.Backward=-1]="Backward"})(N||(N={}));function en(e){return!tt||!e?!1:e===document.scrollingElement}function tn(e){const t={x:0,y:0},n=en(e)?{height:window.innerHeight,width:window.innerWidth}:{height:e.clientHeight,width:e.clientWidth},r={x:e.scrollWidth-n.width,y:e.scrollHeight-n.height},o=e.scrollTop<=t.y,i=e.scrollLeft<=t.x,s=e.scrollTop>=r.y,a=e.scrollLeft>=r.x;return{isTop:o,isLeft:i,isBottom:s,isRight:a,maxScroll:r,minScroll:t}}const Qn={x:.2,y:.2};function Zn(e,t,n,r,o){let{top:i,left:s,right:a,bottom:l}=n;r===void 0&&(r=10),o===void 0&&(o=Qn);const{isTop:u,isBottom:f,isLeft:d,isRight:g}=tn(e),h={x:0,y:0},C={x:0,y:0},v={height:t.height*o.y,width:t.width*o.x};return!u&&i<=t.top+v.height?(h.y=N.Backward,C.y=r*Math.abs((t.top+v.height-i)/v.height)):!f&&l>=t.bottom-v.height&&(h.y=N.Forward,C.y=r*Math.abs((t.bottom-v.height-l)/v.height)),!g&&a>=t.right-v.width?(h.x=N.Forward,C.x=r*Math.abs((t.right-v.width-a)/v.width)):!d&&s<=t.left+v.width&&(h.x=N.Backward,C.x=r*Math.abs((t.left+v.width-s)/v.width)),{direction:h,speed:C}}function er(e){if(e===document.scrollingElement){const{innerWidth:i,innerHeight:s}=window;return{top:0,left:0,right:i,bottom:s,width:i,height:s}}const{top:t,left:n,right:r,bottom:o}=e.getBoundingClientRect();return{top:t,left:n,right:r,bottom:o,width:e.clientWidth,height:e.clientHeight}}function nn(e){return e.reduce((t,n)=>we(t,gt(n)),V)}function tr(e){return e.reduce((t,n)=>t+Qt(n),0)}function nr(e){return e.reduce((t,n)=>t+Zt(n),0)}function rr(e,t){if(t===void 0&&(t=xe),!e)return;const{top:n,left:r,bottom:o,right:i}=t(e);_t(e)&&(o<=0||i<=0||n>=window.innerHeight||r>=window.innerWidth)&&e.scrollIntoView({block:"center",inline:"center"})}const or=[["x",["left","right"],tr],["y",["top","bottom"],nr]];class xt{constructor(t,n){this.rect=void 0,this.width=void 0,this.height=void 0,this.top=void 0,this.bottom=void 0,this.right=void 0,this.left=void 0;const r=nt(n),o=nn(r);this.rect={...t},this.width=t.width,this.height=t.height;for(const[i,s,a]of or)for(const l of s)Object.defineProperty(this,l,{get:()=>{const u=a(r),f=o[i]-u;return this.rect[l]+f},enumerable:!0});Object.defineProperty(this,"rect",{enumerable:!1})}}class Te{constructor(t){this.target=void 0,this.listeners=[],this.removeAll=()=>{this.listeners.forEach(n=>{var r;return(r=this.target)==null?void 0:r.removeEventListener(...n)})},this.target=t}add(t,n,r){var o;(o=this.target)==null||o.addEventListener(t,n,r),this.listeners.push([t,n,r])}}function ir(e){const{EventTarget:t}=B(e);return e instanceof t?e:ye(e)}function ut(e,t){const n=Math.abs(e.x),r=Math.abs(e.y);return typeof t=="number"?Math.sqrt(n**2+r**2)>t:"x"in t&&"y"in t?n>t.x&&r>t.y:"x"in t?n>t.x:"y"in t?r>t.y:!1}var W;(function(e){e.Click="click",e.DragStart="dragstart",e.Keydown="keydown",e.ContextMenu="contextmenu",e.Resize="resize",e.SelectionChange="selectionchange",e.VisibilityChange="visibilitychange"})(W||(W={}));function zt(e){e.preventDefault()}function sr(e){e.stopPropagation()}var w;(function(e){e.Space="Space",e.Down="ArrowDown",e.Right="ArrowRight",e.Left="ArrowLeft",e.Up="ArrowUp",e.Esc="Escape",e.Enter="Enter",e.Tab="Tab"})(w||(w={}));const rn={start:[w.Space,w.Enter],cancel:[w.Esc],end:[w.Space,w.Enter,w.Tab]},ar=(e,t)=>{let{currentCoordinates:n}=t;switch(e.code){case w.Right:return{...n,x:n.x+25};case w.Left:return{...n,x:n.x-25};case w.Down:return{...n,y:n.y+25};case w.Up:return{...n,y:n.y-25}}};class on{constructor(t){this.props=void 0,this.autoScrollEnabled=!1,this.referenceCoordinates=void 0,this.listeners=void 0,this.windowListeners=void 0,this.props=t;const{event:{target:n}}=t;this.props=t,this.listeners=new Te(ye(n)),this.windowListeners=new Te(B(n)),this.handleKeyDown=this.handleKeyDown.bind(this),this.handleCancel=this.handleCancel.bind(this),this.attach()}attach(){this.handleStart(),this.windowListeners.add(W.Resize,this.handleCancel),this.windowListeners.add(W.VisibilityChange,this.handleCancel),setTimeout(()=>this.listeners.add(W.Keydown,this.handleKeyDown))}handleStart(){const{activeNode:t,onStart:n}=this.props,r=t.node.current;r&&rr(r),n(V)}handleKeyDown(t){if(yt(t)){const{active:n,context:r,options:o}=this.props,{keyboardCodes:i=rn,coordinateGetter:s=ar,scrollBehavior:a="smooth"}=o,{code:l}=t;if(i.end.includes(l)){this.handleEnd(t);return}if(i.cancel.includes(l)){this.handleCancel(t);return}const{collisionRect:u}=r.current,f=u?{x:u.left,y:u.top}:V;this.referenceCoordinates||(this.referenceCoordinates=f);const d=s(t,{active:n,context:r.current,currentCoordinates:f});if(d){const g=ze(d,f),h={x:0,y:0},{scrollableAncestors:C}=r.current;for(const v of C){const p=t.code,{isTop:m,isRight:y,isLeft:b,isBottom:R,maxScroll:S,minScroll:E}=tn(v),x=er(v),D={x:Math.min(p===w.Right?x.right-x.width/2:x.right,Math.max(p===w.Right?x.left:x.left+x.width/2,d.x)),y:Math.min(p===w.Down?x.bottom-x.height/2:x.bottom,Math.max(p===w.Down?x.top:x.top+x.height/2,d.y))},A=p===w.Right&&!y||p===w.Left&&!b,T=p===w.Down&&!R||p===w.Up&&!m;if(A&&D.x!==d.x){const M=v.scrollLeft+g.x,H=p===w.Right&&M<=S.x||p===w.Left&&M>=E.x;if(H&&!g.y){v.scrollTo({left:M,behavior:a});return}H?h.x=v.scrollLeft-M:h.x=p===w.Right?v.scrollLeft-S.x:v.scrollLeft-E.x,h.x&&v.scrollBy({left:-h.x,behavior:a});break}else if(T&&D.y!==d.y){const M=v.scrollTop+g.y,H=p===w.Down&&M<=S.y||p===w.Up&&M>=E.y;if(H&&!g.x){v.scrollTo({top:M,behavior:a});return}H?h.y=v.scrollTop-M:h.y=p===w.Down?v.scrollTop-S.y:v.scrollTop-E.y,h.y&&v.scrollBy({top:-h.y,behavior:a});break}}this.handleMove(t,we(ze(d,this.referenceCoordinates),h))}}}handleMove(t,n){const{onMove:r}=this.props;t.preventDefault(),r(n)}handleEnd(t){const{onEnd:n}=this.props;t.preventDefault(),this.detach(),n()}handleCancel(t){const{onCancel:n}=this.props;t.preventDefault(),this.detach(),n()}detach(){this.listeners.removeAll(),this.windowListeners.removeAll()}}on.activators=[{eventName:"onKeyDown",handler:(e,t,n)=>{let{keyboardCodes:r=rn,onActivation:o}=t,{active:i}=n;const{code:s}=e.nativeEvent;if(r.start.includes(s)){const a=i.activatorNode.current;return a&&e.target!==a?!1:(e.preventDefault(),o?.({event:e.nativeEvent}),!0)}return!1}}];function Pt(e){return!!(e&&"distance"in e)}function Bt(e){return!!(e&&"delay"in e)}class Dt{constructor(t,n,r){var o;r===void 0&&(r=ir(t.event.target)),this.props=void 0,this.events=void 0,this.autoScrollEnabled=!0,this.document=void 0,this.activated=!1,this.initialCoordinates=void 0,this.timeoutId=null,this.listeners=void 0,this.documentListeners=void 0,this.windowListeners=void 0,this.props=t,this.events=n;const{event:i}=t,{target:s}=i;this.props=t,this.events=n,this.document=ye(s),this.documentListeners=new Te(this.document),this.listeners=new Te(r),this.windowListeners=new Te(B(s)),this.initialCoordinates=(o=ht(i))!=null?o:V,this.handleStart=this.handleStart.bind(this),this.handleMove=this.handleMove.bind(this),this.handleEnd=this.handleEnd.bind(this),this.handleCancel=this.handleCancel.bind(this),this.handleKeydown=this.handleKeydown.bind(this),this.removeTextSelection=this.removeTextSelection.bind(this),this.attach()}attach(){const{events:t,props:{options:{activationConstraint:n,bypassActivationConstraint:r}}}=this;if(this.listeners.add(t.move.name,this.handleMove,{passive:!1}),this.listeners.add(t.end.name,this.handleEnd),t.cancel&&this.listeners.add(t.cancel.name,this.handleCancel),this.windowListeners.add(W.Resize,this.handleCancel),this.windowListeners.add(W.DragStart,zt),this.windowListeners.add(W.VisibilityChange,this.handleCancel),this.windowListeners.add(W.ContextMenu,zt),this.documentListeners.add(W.Keydown,this.handleKeydown),n){if(r!=null&&r({event:this.props.event,activeNode:this.props.activeNode,options:this.props.options}))return this.handleStart();if(Bt(n)){this.timeoutId=setTimeout(this.handleStart,n.delay),this.handlePending(n);return}if(Pt(n)){this.handlePending(n);return}}this.handleStart()}detach(){this.listeners.removeAll(),this.windowListeners.removeAll(),setTimeout(this.documentListeners.removeAll,50),this.timeoutId!==null&&(clearTimeout(this.timeoutId),this.timeoutId=null)}handlePending(t,n){const{active:r,onPending:o}=this.props;o(r,t,this.initialCoordinates,n)}handleStart(){const{initialCoordinates:t}=this,{onStart:n}=this.props;t&&(this.activated=!0,this.documentListeners.add(W.Click,sr,{capture:!0}),this.removeTextSelection(),this.documentListeners.add(W.SelectionChange,this.removeTextSelection),n(t))}handleMove(t){var n;const{activated:r,initialCoordinates:o,props:i}=this,{onMove:s,options:{activationConstraint:a}}=i;if(!o)return;const l=(n=ht(t))!=null?n:V,u=ze(o,l);if(!r&&a){if(Pt(a)){if(a.tolerance!=null&&ut(u,a.tolerance))return this.handleCancel();if(ut(u,a.distance))return this.handleStart()}if(Bt(a)&&ut(u,a.tolerance))return this.handleCancel();this.handlePending(a,u);return}t.cancelable&&t.preventDefault(),s(l)}handleEnd(){const{onAbort:t,onEnd:n}=this.props;this.detach(),this.activated||t(this.props.active),n()}handleCancel(){const{onAbort:t,onCancel:n}=this.props;this.detach(),this.activated||t(this.props.active),n()}handleKeydown(t){t.code===w.Esc&&this.handleCancel()}removeTextSelection(){var t;(t=this.document.getSelection())==null||t.removeAllRanges()}}const cr={cancel:{name:"pointercancel"},move:{name:"pointermove"},end:{name:"pointerup"}};class sn extends Dt{constructor(t){const{event:n}=t,r=ye(n.target);super(t,cr,r)}}sn.activators=[{eventName:"onPointerDown",handler:(e,t)=>{let{nativeEvent:n}=e,{onActivation:r}=t;return!n.isPrimary||n.button!==0?!1:(r?.({event:n}),!0)}}];const lr={move:{name:"mousemove"},end:{name:"mouseup"}};var vt;(function(e){e[e.RightClick=2]="RightClick"})(vt||(vt={}));class ur extends Dt{constructor(t){super(t,lr,ye(t.event.target))}}ur.activators=[{eventName:"onMouseDown",handler:(e,t)=>{let{nativeEvent:n}=e,{onActivation:r}=t;return n.button===vt.RightClick?!1:(r?.({event:n}),!0)}}];const dt={cancel:{name:"touchcancel"},move:{name:"touchmove"},end:{name:"touchend"}};class dr extends Dt{constructor(t){super(t,dt)}static setup(){return window.addEventListener(dt.move.name,t,{capture:!1,passive:!1}),function(){window.removeEventListener(dt.move.name,t)};function t(){}}}dr.activators=[{eventName:"onTouchStart",handler:(e,t)=>{let{nativeEvent:n}=e,{onActivation:r}=t;const{touches:o}=n;return o.length>1?!1:(r?.({event:n}),!0)}}];var Ne;(function(e){e[e.Pointer=0]="Pointer",e[e.DraggableRect=1]="DraggableRect"})(Ne||(Ne={}));var Ze;(function(e){e[e.TreeOrder=0]="TreeOrder",e[e.ReversedTreeOrder=1]="ReversedTreeOrder"})(Ze||(Ze={}));function fr(e){let{acceleration:t,activator:n=Ne.Pointer,canScroll:r,draggingRect:o,enabled:i,interval:s=5,order:a=Ze.TreeOrder,pointerCoordinates:l,scrollableAncestors:u,scrollableAncestorRects:f,delta:d,threshold:g}=e;const h=gr({delta:d,disabled:!i}),[C,v]=En(),p=c.useRef({x:0,y:0}),m=c.useRef({x:0,y:0}),y=c.useMemo(()=>{switch(n){case Ne.Pointer:return l?{top:l.y,bottom:l.y,left:l.x,right:l.x}:null;case Ne.DraggableRect:return o}},[n,o,l]),b=c.useRef(null),R=c.useCallback(()=>{const E=b.current;if(!E)return;const x=p.current.x*m.current.x,D=p.current.y*m.current.y;E.scrollBy(x,D)},[]),S=c.useMemo(()=>a===Ze.TreeOrder?[...u].reverse():u,[a,u]);c.useEffect(()=>{if(!i||!u.length||!y){v();return}for(const E of S){if(r?.(E)===!1)continue;const x=u.indexOf(E),D=f[x];if(!D)continue;const{direction:A,speed:T}=Zn(E,D,y,t,g);for(const M of["x","y"])h[M][A[M]]||(T[M]=0,A[M]=0);if(T.x>0||T.y>0){v(),b.current=E,C(R,s),p.current=T,m.current=A;return}}p.current={x:0,y:0},m.current={x:0,y:0},v()},[t,R,r,v,i,s,JSON.stringify(y),JSON.stringify(h),C,u,S,f,JSON.stringify(g)])}const hr={x:{[N.Backward]:!1,[N.Forward]:!1},y:{[N.Backward]:!1,[N.Forward]:!1}};function gr(e){let{delta:t,disabled:n}=e;const r=ft(t);return Fe(o=>{if(n||!r||!o)return hr;const i={x:Math.sign(t.x-r.x),y:Math.sign(t.y-r.y)};return{x:{[N.Backward]:o.x[N.Backward]||i.x===-1,[N.Forward]:o.x[N.Forward]||i.x===1},y:{[N.Backward]:o.y[N.Backward]||i.y===-1,[N.Forward]:o.y[N.Forward]||i.y===1}}},[n,t,r])}function vr(e,t){const n=t!=null?e.get(t):void 0,r=n?n.node.current:null;return Fe(o=>{var i;return t==null?null:(i=r??o)!=null?i:null},[r,t])}function pr(e,t){return c.useMemo(()=>e.reduce((n,r)=>{const{sensor:o}=r,i=o.activators.map(s=>({eventName:s.eventName,handler:t(s.handler,r)}));return[...n,...i]},[]),[e,t])}var Pe;(function(e){e[e.Always=0]="Always",e[e.BeforeDragging=1]="BeforeDragging",e[e.WhileDragging=2]="WhileDragging"})(Pe||(Pe={}));var pt;(function(e){e.Optimized="optimized"})(pt||(pt={}));const Ft=new Map;function br(e,t){let{dragging:n,dependencies:r,config:o}=t;const[i,s]=c.useState(null),{frequency:a,measure:l,strategy:u}=o,f=c.useRef(e),d=p(),g=ke(d),h=c.useCallback(function(m){m===void 0&&(m=[]),!g.current&&s(y=>y===null?m:y.concat(m.filter(b=>!y.includes(b))))},[g]),C=c.useRef(null),v=Fe(m=>{if(d&&!n)return Ft;if(!m||m===Ft||f.current!==e||i!=null){const y=new Map;for(let b of e){if(!b)continue;if(i&&i.length>0&&!i.includes(b.id)&&b.rect.current){y.set(b.id,b.rect.current);continue}const R=b.node.current,S=R?new xt(l(R),R):null;b.rect.current=S,S&&y.set(b.id,S)}return y}return m},[e,i,n,d,l]);return c.useEffect(()=>{f.current=e},[e]),c.useEffect(()=>{d||h()},[n,d]),c.useEffect(()=>{i&&i.length>0&&s(null)},[JSON.stringify(i)]),c.useEffect(()=>{d||typeof a!="number"||C.current!==null||(C.current=setTimeout(()=>{h(),C.current=null},a))},[a,d,h,...r]),{droppableRects:v,measureDroppableContainers:h,measuringScheduled:i!=null};function p(){switch(u){case Pe.Always:return!1;case Pe.BeforeDragging:return n;default:return!n}}}function an(e,t){return Fe(n=>e?n||(typeof t=="function"?t(e):e):null,[t,e])}function wr(e,t){return an(e,t)}function mr(e){let{callback:t,disabled:n}=e;const r=mt(t),o=c.useMemo(()=>{if(n||typeof window>"u"||typeof window.MutationObserver>"u")return;const{MutationObserver:i}=window;return new i(r)},[r,n]);return c.useEffect(()=>()=>o?.disconnect(),[o]),o}function rt(e){let{callback:t,disabled:n}=e;const r=mt(t),o=c.useMemo(()=>{if(n||typeof window>"u"||typeof window.ResizeObserver>"u")return;const{ResizeObserver:i}=window;return new i(r)},[n]);return c.useEffect(()=>()=>o?.disconnect(),[o]),o}function yr(e){return new xt(xe(e),e)}function $t(e,t,n){t===void 0&&(t=yr);const[r,o]=c.useState(null);function i(){o(l=>{if(!e)return null;if(e.isConnected===!1){var u;return(u=l??n)!=null?u:null}const f=t(e);return JSON.stringify(l)===JSON.stringify(f)?l:f})}const s=mr({callback(l){if(e)for(const u of l){const{type:f,target:d}=u;if(f==="childList"&&d instanceof HTMLElement&&d.contains(e)){i();break}}}}),a=rt({callback:i});return Q(()=>{i(),e?(a?.observe(e),s?.observe(document.body,{childList:!0,subtree:!0})):(a?.disconnect(),s?.disconnect())},[e]),r}function xr(e){const t=an(e);return Jt(e,t)}const Xt=[];function Dr(e){const t=c.useRef(e),n=Fe(r=>e?r&&r!==Xt&&e&&t.current&&e.parentNode===t.current.parentNode?r:nt(e):Xt,[e]);return c.useEffect(()=>{t.current=e},[e]),n}function Cr(e){const[t,n]=c.useState(null),r=c.useRef(e),o=c.useCallback(i=>{const s=lt(i.target);s&&n(a=>a?(a.set(s,gt(s)),new Map(a)):null)},[]);return c.useEffect(()=>{const i=r.current;if(e!==i){s(i);const a=e.map(l=>{const u=lt(l);return u?(u.addEventListener("scroll",o,{passive:!0}),[u,gt(u)]):null}).filter(l=>l!=null);n(a.length?new Map(a):null),r.current=e}return()=>{s(e),s(i)};function s(a){a.forEach(l=>{const u=lt(l);u?.removeEventListener("scroll",o)})}},[o,e]),c.useMemo(()=>e.length?t?Array.from(t.values()).reduce((i,s)=>we(i,s),V):nn(e):V,[e,t])}function Yt(e,t){t===void 0&&(t=[]);const n=c.useRef(null);return c.useEffect(()=>{n.current=null},t),c.useEffect(()=>{const r=e!==V;r&&!n.current&&(n.current=e),!r&&n.current&&(n.current=null)},[e]),n.current?ze(e,n.current):V}function Rr(e){c.useEffect(()=>{if(!tt)return;const t=e.map(n=>{let{sensor:r}=n;return r.setup==null?void 0:r.setup()});return()=>{for(const n of t)n?.()}},e.map(t=>{let{sensor:n}=t;return n}))}function Sr(e,t){return c.useMemo(()=>e.reduce((n,r)=>{let{eventName:o,handler:i}=r;return n[o]=s=>{i(s,t)},n},{}),[e,t])}function cn(e){return c.useMemo(()=>e?Gn(e):null,[e])}const jt=[];function Er(e,t){t===void 0&&(t=xe);const[n]=e,r=cn(n?B(n):null),[o,i]=c.useState(jt);function s(){i(()=>e.length?e.map(l=>en(l)?r:new xt(t(l),l)):jt)}const a=rt({callback:s});return Q(()=>{a?.disconnect(),s(),e.forEach(l=>a?.observe(l))},[e]),o}function Ir(e){if(!e)return null;if(e.children.length>1)return e;const t=e.children[0];return Be(t)?t:e}function Mr(e){let{measure:t}=e;const[n,r]=c.useState(null),o=c.useCallback(u=>{for(const{target:f}of u)if(Be(f)){r(d=>{const g=t(f);return d?{...d,width:g.width,height:g.height}:g});break}},[t]),i=rt({callback:o}),s=c.useCallback(u=>{const f=Ir(u);i?.disconnect(),f&&i?.observe(f),r(f?t(f):null)},[t,i]),[a,l]=Je(s);return c.useMemo(()=>({nodeRef:a,rect:n,setRef:l}),[n,a,l])}const Ar=[{sensor:sn,options:{}},{sensor:on,options:{}}],Or={current:{}},Ge={draggable:{measure:kt},droppable:{measure:kt,strategy:Pe.WhileDragging,frequency:pt.Optimized},dragOverlay:{measure:xe}};class Le extends Map{get(t){var n;return t!=null&&(n=super.get(t))!=null?n:void 0}toArray(){return Array.from(this.values())}getEnabled(){return this.toArray().filter(t=>{let{disabled:n}=t;return!n})}getNodeFor(t){var n,r;return(n=(r=this.get(t))==null?void 0:r.node.current)!=null?n:void 0}}const Tr={activatorEvent:null,active:null,activeNode:null,activeNodeRect:null,collisions:null,containerNodeRect:null,draggableNodes:new Map,droppableRects:new Map,droppableContainers:new Le,over:null,dragOverlay:{nodeRef:{current:null},rect:null,setRef:Qe},scrollableAncestors:[],scrollableAncestorRects:[],measuringConfiguration:Ge,measureDroppableContainers:Qe,windowRect:null,measuringScheduled:!1},Nr={activatorEvent:null,activators:[],active:null,activeNodeRect:null,ariaDescribedById:{draggable:""},dispatch:Qe,draggableNodes:new Map,over:null,measureDroppableContainers:Qe},ot=c.createContext(Nr),ln=c.createContext(Tr);function Lr(){return{draggable:{active:null,initialCoordinates:{x:0,y:0},nodes:new Map,translate:{x:0,y:0}},droppable:{containers:new Le}}}function kr(e,t){switch(t.type){case O.DragStart:return{...e,draggable:{...e.draggable,initialCoordinates:t.initialCoordinates,active:t.active}};case O.DragMove:return e.draggable.active==null?e:{...e,draggable:{...e.draggable,translate:{x:t.coordinates.x-e.draggable.initialCoordinates.x,y:t.coordinates.y-e.draggable.initialCoordinates.y}}};case O.DragEnd:case O.DragCancel:return{...e,draggable:{...e.draggable,active:null,initialCoordinates:{x:0,y:0},translate:{x:0,y:0}}};case O.RegisterDroppable:{const{element:n}=t,{id:r}=n,o=new Le(e.droppable.containers);return o.set(r,n),{...e,droppable:{...e.droppable,containers:o}}}case O.SetDroppableDisabled:{const{id:n,key:r,disabled:o}=t,i=e.droppable.containers.get(n);if(!i||r!==i.key)return e;const s=new Le(e.droppable.containers);return s.set(n,{...i,disabled:o}),{...e,droppable:{...e.droppable,containers:s}}}case O.UnregisterDroppable:{const{id:n,key:r}=t,o=e.droppable.containers.get(n);if(!o||r!==o.key)return e;const i=new Le(e.droppable.containers);return i.delete(n),{...e,droppable:{...e.droppable,containers:i}}}default:return e}}function zr(e){let{disabled:t}=e;const{active:n,activatorEvent:r,draggableNodes:o}=c.useContext(ot),i=ft(r),s=ft(n?.id);return c.useEffect(()=>{if(!t&&!r&&i&&s!=null){if(!yt(i)||document.activeElement===i.target)return;const a=o.get(s);if(!a)return;const{activatorNode:l,node:u}=a;if(!l.current&&!u.current)return;requestAnimationFrame(()=>{for(const f of[l.current,u.current]){if(!f)continue;const d=An(f);if(d){d.focus();break}}})}},[r,t,o,s,i]),null}function Pr(e,t){let{transform:n,...r}=t;return e!=null&&e.length?e.reduce((o,i)=>i({transform:o,...r}),n):n}function Br(e){return c.useMemo(()=>({draggable:{...Ge.draggable,...e?.draggable},droppable:{...Ge.droppable,...e?.droppable},dragOverlay:{...Ge.dragOverlay,...e?.dragOverlay}}),[e?.draggable,e?.droppable,e?.dragOverlay])}function Fr(e){let{activeNode:t,measure:n,initialRect:r,config:o=!0}=e;const i=c.useRef(!1),{x:s,y:a}=typeof o=="boolean"?{x:o,y:o}:o;Q(()=>{if(!s&&!a||!t){i.current=!1;return}if(i.current||!r)return;const u=t?.node.current;if(!u||u.isConnected===!1)return;const f=n(u),d=Jt(f,r);if(s||(d.x=0),a||(d.y=0),i.current=!0,Math.abs(d.x)>0||Math.abs(d.y)>0){const g=_t(u);g&&g.scrollBy({top:d.y,left:d.x})}},[t,s,a,r,n])}const un=c.createContext({...V,scaleX:1,scaleY:1});var ue;(function(e){e[e.Uninitialized=0]="Uninitialized",e[e.Initializing=1]="Initializing",e[e.Initialized=2]="Initialized"})(ue||(ue={}));const uo=c.memo(function(t){var n,r,o,i;let{id:s,accessibility:a,autoScroll:l=!0,children:u,sensors:f=Ar,collisionDetection:d=jn,measuring:g,modifiers:h,...C}=t;const v=c.useReducer(kr,void 0,Lr),[p,m]=v,[y,b]=zn(),[R,S]=c.useState(ue.Uninitialized),E=R===ue.Initialized,{draggable:{active:x,nodes:D,translate:A},droppable:{containers:T}}=p,M=x!=null?D.get(x):null,H=c.useRef({initial:null,translated:null}),K=c.useMemo(()=>{var k;return x!=null?{id:x,data:(k=M?.data)!=null?k:Or,rect:H}:null},[x,M]),q=c.useRef(null),[De,Xe]=c.useState(null),[F,Ye]=c.useState(null),Z=ke(C,Object.values(C)),Ce=$e("DndDescribedBy",s),je=c.useMemo(()=>T.getEnabled(),[T]),z=Br(g),{droppableRects:ee,measureDroppableContainers:de,measuringScheduled:Re}=br(je,{dragging:E,dependencies:[A.x,A.y],config:z.droppable}),j=vr(D,x),Ue=c.useMemo(()=>F?ht(F):null,[F]),oe=Rn(),te=wr(j,z.draggable.measure);Fr({activeNode:x!=null?D.get(x):null,config:oe.layoutShiftCompensation,initialRect:te,measure:z.draggable.measure});const I=$t(j,z.draggable.measure,te),Se=$t(j?j.parentElement:null),G=c.useRef({activatorEvent:null,active:null,activeNode:j,collisionRect:null,collisions:null,droppableRects:ee,draggableNodes:D,draggingNode:null,draggingNodeRect:null,droppableContainers:T,over:null,scrollableAncestors:[],scrollAdjustedTranslate:null}),fe=T.getNodeFor((n=G.current.over)==null?void 0:n.id),ne=Mr({measure:z.dragOverlay.measure}),he=(r=ne.nodeRef.current)!=null?r:j,ge=E?(o=ne.rect)!=null?o:I:null,Ct=!!(ne.nodeRef.current&&ne.rect),Rt=xr(Ct?null:I),it=cn(he?B(he):null),ie=Dr(E?fe??j:null),We=Er(ie),He=Pr(h,{transform:{x:A.x-Rt.x,y:A.y-Rt.y,scaleX:1,scaleY:1},activatorEvent:F,active:K,activeNodeRect:I,containerNodeRect:Se,draggingNodeRect:ge,over:G.current.over,overlayNodeRect:ne.rect,scrollableAncestors:ie,scrollableAncestorRects:We,windowRect:it}),St=Ue?we(Ue,A):null,Et=Cr(ie),bn=Yt(Et),wn=Yt(Et,[I]),ve=we(He,bn),pe=ge?Hn(ge,He):null,Ee=K&&pe?d({active:K,collisionRect:pe,droppableRects:ee,droppableContainers:je,pointerCoordinates:St}):null,It=Gt(Ee,"id"),[se,Mt]=c.useState(null),mn=Ct?He:we(He,wn),yn=Un(mn,(i=se?.rect)!=null?i:null,I),st=c.useRef(null),At=c.useCallback((k,$)=>{let{sensor:X,options:ae}=$;if(q.current==null)return;const U=D.get(q.current);if(!U)return;const Y=k.nativeEvent,J=new X({active:q.current,activeNode:U,event:Y,options:ae,context:G,onAbort(L){if(!D.get(L))return;const{onDragAbort:_}=Z.current,re={id:L};_?.(re),y({type:"onDragAbort",event:re})},onPending(L,ce,_,re){if(!D.get(L))return;const{onDragPending:Me}=Z.current,le={id:L,constraint:ce,initialCoordinates:_,offset:re};Me?.(le),y({type:"onDragPending",event:le})},onStart(L){const ce=q.current;if(ce==null)return;const _=D.get(ce);if(!_)return;const{onDragStart:re}=Z.current,Ie={activatorEvent:Y,active:{id:ce,data:_.data,rect:H}};Oe.unstable_batchedUpdates(()=>{re?.(Ie),S(ue.Initializing),m({type:O.DragStart,initialCoordinates:L,active:ce}),y({type:"onDragStart",event:Ie}),Xe(st.current),Ye(Y)})},onMove(L){m({type:O.DragMove,coordinates:L})},onEnd:be(O.DragEnd),onCancel:be(O.DragCancel)});st.current=J;function be(L){return async function(){const{active:_,collisions:re,over:Ie,scrollAdjustedTranslate:Me}=G.current;let le=null;if(_&&Me){const{cancelDrop:Ae}=Z.current;le={activatorEvent:Y,active:_,collisions:re,delta:Me,over:Ie},L===O.DragEnd&&typeof Ae=="function"&&await Promise.resolve(Ae(le))&&(L=O.DragCancel)}q.current=null,Oe.unstable_batchedUpdates(()=>{m({type:L}),S(ue.Uninitialized),Mt(null),Xe(null),Ye(null),st.current=null;const Ae=L===O.DragEnd?"onDragEnd":"onDragCancel";if(le){const at=Z.current[Ae];at?.(le),y({type:Ae,event:le})}})}}},[D]),xn=c.useCallback((k,$)=>(X,ae)=>{const U=X.nativeEvent,Y=D.get(ae);if(q.current!==null||!Y||U.dndKit||U.defaultPrevented)return;const J={active:Y};k(X,$.options,J)===!0&&(U.dndKit={capturedBy:$.sensor},q.current=ae,At(X,$))},[D,At]),Ot=pr(f,xn);Rr(f),Q(()=>{I&&R===ue.Initializing&&S(ue.Initialized)},[I,R]),c.useEffect(()=>{const{onDragMove:k}=Z.current,{active:$,activatorEvent:X,collisions:ae,over:U}=G.current;if(!$||!X)return;const Y={active:$,activatorEvent:X,collisions:ae,delta:{x:ve.x,y:ve.y},over:U};Oe.unstable_batchedUpdates(()=>{k?.(Y),y({type:"onDragMove",event:Y})})},[ve.x,ve.y]),c.useEffect(()=>{const{active:k,activatorEvent:$,collisions:X,droppableContainers:ae,scrollAdjustedTranslate:U}=G.current;if(!k||q.current==null||!$||!U)return;const{onDragOver:Y}=Z.current,J=ae.get(It),be=J&&J.rect.current?{id:J.id,rect:J.rect.current,data:J.data,disabled:J.disabled}:null,L={active:k,activatorEvent:$,collisions:X,delta:{x:U.x,y:U.y},over:be};Oe.unstable_batchedUpdates(()=>{Mt(be),Y?.(L),y({type:"onDragOver",event:L})})},[It]),Q(()=>{G.current={activatorEvent:F,active:K,activeNode:j,collisionRect:pe,collisions:Ee,droppableRects:ee,draggableNodes:D,draggingNode:he,draggingNodeRect:ge,droppableContainers:T,over:se,scrollableAncestors:ie,scrollAdjustedTranslate:ve},H.current={initial:ge,translated:pe}},[K,j,Ee,pe,D,he,ge,ee,T,se,ie,ve]),fr({...oe,delta:A,draggingRect:pe,pointerCoordinates:St,scrollableAncestors:ie,scrollableAncestorRects:We});const Dn=c.useMemo(()=>({active:K,activeNode:j,activeNodeRect:I,activatorEvent:F,collisions:Ee,containerNodeRect:Se,dragOverlay:ne,draggableNodes:D,droppableContainers:T,droppableRects:ee,over:se,measureDroppableContainers:de,scrollableAncestors:ie,scrollableAncestorRects:We,measuringConfiguration:z,measuringScheduled:Re,windowRect:it}),[K,j,I,F,Ee,Se,ne,D,T,ee,se,de,ie,We,z,Re,it]),Cn=c.useMemo(()=>({activatorEvent:F,activators:Ot,active:K,activeNodeRect:I,ariaDescribedById:{draggable:Ce},dispatch:m,draggableNodes:D,over:se,measureDroppableContainers:de}),[F,Ot,K,I,m,Ce,D,se,de]);return P.createElement(Kt.Provider,{value:b},P.createElement(ot.Provider,{value:Cn},P.createElement(ln.Provider,{value:Dn},P.createElement(un.Provider,{value:yn},u)),P.createElement(zr,{disabled:a?.restoreFocus===!1})),P.createElement(Fn,{...a,hiddenTextDescribedById:Ce}));function Rn(){const k=De?.autoScrollEnabled===!1,$=typeof l=="object"?l.enabled===!1:l===!1,X=E&&!k&&!$;return typeof l=="object"?{...l,enabled:X}:{enabled:X}}}),$r=c.createContext(null),Ut="button",Xr="Draggable";function Yr(e){let{id:t,data:n,disabled:r=!1,attributes:o}=e;const i=$e(Xr),{activators:s,activatorEvent:a,active:l,activeNodeRect:u,ariaDescribedById:f,draggableNodes:d,over:g}=c.useContext(ot),{role:h=Ut,roleDescription:C="draggable",tabIndex:v=0}=o??{},p=l?.id===t,m=c.useContext(p?un:$r),[y,b]=Je(),[R,S]=Je(),E=Sr(s,t),x=ke(n);Q(()=>(d.set(t,{id:t,key:i,node:y,activatorNode:R,data:x}),()=>{const A=d.get(t);A&&A.key===i&&d.delete(t)}),[d,t]);const D=c.useMemo(()=>({role:h,tabIndex:v,"aria-disabled":r,"aria-pressed":p&&h===Ut?!0:void 0,"aria-roledescription":C,"aria-describedby":f.draggable}),[r,h,v,p,C,f.draggable]);return{active:l,activatorEvent:a,activeNodeRect:u,attributes:D,isDragging:p,listeners:r?void 0:E,node:y,over:g,setNodeRef:b,setActivatorNodeRef:S,transform:m}}function jr(){return c.useContext(ln)}const Ur="Droppable",Wr={timeout:25};function Hr(e){let{data:t,disabled:n=!1,id:r,resizeObserverConfig:o}=e;const i=$e(Ur),{active:s,dispatch:a,over:l,measureDroppableContainers:u}=c.useContext(ot),f=c.useRef({disabled:n}),d=c.useRef(!1),g=c.useRef(null),h=c.useRef(null),{disabled:C,updateMeasurementsFor:v,timeout:p}={...Wr,...o},m=ke(v??r),y=c.useCallback(()=>{if(!d.current){d.current=!0;return}h.current!=null&&clearTimeout(h.current),h.current=setTimeout(()=>{u(Array.isArray(m.current)?m.current:[m.current]),h.current=null},p)},[p]),b=rt({callback:y,disabled:C||!s}),R=c.useCallback((D,A)=>{b&&(A&&(b.unobserve(A),d.current=!1),D&&b.observe(D))},[b]),[S,E]=Je(R),x=ke(t);return c.useEffect(()=>{!b||!S.current||(b.disconnect(),d.current=!1,b.observe(S.current))},[S,b]),c.useEffect(()=>(a({type:O.RegisterDroppable,element:{id:r,key:i,disabled:n,node:S,rect:g,data:x}}),()=>a({type:O.UnregisterDroppable,key:i,id:r})),[r]),c.useEffect(()=>{n!==f.current.disabled&&(a({type:O.SetDroppableDisabled,id:r,key:i,disabled:n}),f.current.disabled=n)},[r,i,n,a]),{active:s,rect:g,isOver:l?.id===r,node:S,over:l,setNodeRef:E}}function dn(e,t,n){const r=e.slice();return r.splice(n<0?r.length+n:n,0,r.splice(t,1)[0]),r}function Kr(e,t){return e.reduce((n,r,o)=>{const i=t.get(r);return i&&(n[o]=i),n},Array(e.length))}function Ke(e){return e!==null&&e>=0}function Vr(e,t){if(e===t)return!0;if(e.length!==t.length)return!1;for(let n=0;n{var t;let{rects:n,activeNodeRect:r,activeIndex:o,overIndex:i,index:s}=e;const a=(t=n[o])!=null?t:r;if(!a)return null;const l=Gr(n,s,o);if(s===o){const u=n[i];return u?{x:oo&&s<=i?{x:-a.width-l,y:0,...Ve}:s=i?{x:a.width+l,y:0,...Ve}:{x:0,y:0,...Ve}};function Gr(e,t,n){const r=e[t],o=e[t-1],i=e[t+1];return!r||!o&&!i?0:n{let{rects:t,activeIndex:n,overIndex:r,index:o}=e;const i=dn(t,r,n),s=t[o],a=i[o];return!a||!s?null:{x:a.left-s.left,y:a.top-s.top,scaleX:a.width/s.width,scaleY:a.height/s.height}},qe={scaleX:1,scaleY:1},ho=e=>{var t;let{activeIndex:n,activeNodeRect:r,index:o,rects:i,overIndex:s}=e;const a=(t=i[n])!=null?t:r;if(!a)return null;if(o===n){const u=i[s];return u?{x:0,y:nn&&o<=s?{x:0,y:-a.height-l,...qe}:o=s?{x:0,y:a.height+l,...qe}:{x:0,y:0,...qe}};function Jr(e,t,n){const r=e[t],o=e[t-1],i=e[t+1];return r?nr.map(E=>typeof E=="object"&&"id"in E?E.id:E),[r]),C=s!=null,v=s?h.indexOf(s.id):-1,p=u?h.indexOf(u.id):-1,m=c.useRef(h),y=!Vr(h,m.current),b=p!==-1&&v===-1||y,R=qr(i);Q(()=>{y&&C&&f(h)},[y,h,C,f]),c.useEffect(()=>{m.current=h},[h]);const S=c.useMemo(()=>({activeIndex:v,containerId:d,disabled:R,disableTransforms:b,items:h,overIndex:p,useDragOverlay:g,sortedRects:Kr(h,l),strategy:o}),[v,d,R.draggable,R.droppable,b,h,p,l,g,o]);return P.createElement(gn.Provider,{value:S},t)}const _r=e=>{let{id:t,items:n,activeIndex:r,overIndex:o}=e;return dn(n,r,o).indexOf(t)},Qr=e=>{let{containerId:t,isSorting:n,wasDragging:r,index:o,items:i,newIndex:s,previousItems:a,previousContainerId:l,transition:u}=e;return!u||!r||a!==i&&o===s?!1:n?!0:s!==o&&t===l},Zr={duration:200,easing:"ease"},vn="transform",eo=_e.Transition.toString({property:vn,duration:0,easing:"linear"}),to={roleDescription:"sortable"};function no(e){let{disabled:t,index:n,node:r,rect:o}=e;const[i,s]=c.useState(null),a=c.useRef(n);return Q(()=>{if(!t&&n!==a.current&&r.current){const l=o.current;if(l){const u=xe(r.current,{ignoreTransform:!0}),f={x:l.left-u.left,y:l.top-u.top,scaleX:l.width/u.width,scaleY:l.height/u.height};(f.x||f.y)&&s(f)}}n!==a.current&&(a.current=n)},[t,n,r,o]),c.useEffect(()=>{i&&s(null)},[i]),i}function vo(e){let{animateLayoutChanges:t=Qr,attributes:n,disabled:r,data:o,getNewIndex:i=_r,id:s,strategy:a,resizeObserverConfig:l,transition:u=Zr}=e;const{items:f,containerId:d,activeIndex:g,disabled:h,disableTransforms:C,sortedRects:v,overIndex:p,useDragOverlay:m,strategy:y}=c.useContext(gn),b=ro(r,h),R=f.indexOf(s),S=c.useMemo(()=>({sortable:{containerId:d,index:R,items:f},...o}),[d,o,R,f]),E=c.useMemo(()=>f.slice(f.indexOf(s)),[f,s]),{rect:x,node:D,isOver:A,setNodeRef:T}=Hr({id:s,data:S,disabled:b.droppable,resizeObserverConfig:{updateMeasurementsFor:E,...l}}),{active:M,activatorEvent:H,activeNodeRect:K,attributes:q,setNodeRef:De,listeners:Xe,isDragging:F,over:Ye,setActivatorNodeRef:Z,transform:Ce}=Yr({id:s,data:S,attributes:{...to,...n},disabled:b.draggable}),je=Sn(T,De),z=!!M,ee=z&&!C&&Ke(g)&&Ke(p),de=!m&&F,Re=de&&ee?Ce:null,Ue=ee?Re??(a??y)({rects:v,activeNodeRect:K,activeIndex:g,overIndex:p,index:R}):null,oe=Ke(g)&&Ke(p)?i({id:s,items:f,activeIndex:g,overIndex:p}):R,te=M?.id,I=c.useRef({activeId:te,items:f,newIndex:oe,containerId:d}),Se=f!==I.current.items,G=t({active:M,containerId:d,isDragging:F,isSorting:z,id:s,index:R,items:f,newIndex:I.current.newIndex,previousItems:I.current.items,previousContainerId:I.current.containerId,transition:u,wasDragging:I.current.activeId!=null}),fe=no({disabled:!G,index:R,node:D,rect:x});return c.useEffect(()=>{z&&I.current.newIndex!==oe&&(I.current.newIndex=oe),d!==I.current.containerId&&(I.current.containerId=d),f!==I.current.items&&(I.current.items=f)},[z,oe,d,f]),c.useEffect(()=>{if(te===I.current.activeId)return;if(te!=null&&I.current.activeId==null){I.current.activeId=te;return}const he=setTimeout(()=>{I.current.activeId=te},50);return()=>clearTimeout(he)},[te]),{active:M,activeIndex:g,attributes:q,data:S,rect:x,index:R,newIndex:oe,items:f,isOver:A,isSorting:z,isDragging:F,listeners:Xe,node:D,overIndex:p,over:Ye,setNodeRef:je,setActivatorNodeRef:Z,setDroppableNodeRef:T,setDraggableNodeRef:De,transform:fe??Ue,transition:ne()};function ne(){if(fe||Se&&I.current.newIndex===R)return eo;if(!(de&&!yt(H)||!u)&&(z||G))return _e.Transition.toString({...u,property:vn})}}function ro(e,t){var n,r;return typeof e=="boolean"?{draggable:e,droppable:!1}:{draggable:(n=e?.draggable)!=null?n:t.draggable,droppable:(r=e?.droppable)!=null?r:t.droppable}}function et(e){if(!e)return!1;const t=e.data.current;return!!(t&&"sortable"in t&&typeof t.sortable=="object"&&"containerId"in t.sortable&&"items"in t.sortable&&"index"in t.sortable)}const oo=[w.Down,w.Right,w.Up,w.Left],po=(e,t)=>{let{context:{active:n,collisionRect:r,droppableRects:o,droppableContainers:i,over:s,scrollableAncestors:a}}=t;if(oo.includes(e.code)){if(e.preventDefault(),!n||!r)return;const l=[];i.getEnabled().forEach(d=>{if(!d||d!=null&&d.disabled)return;const g=o.get(d.id);if(g)switch(e.code){case w.Down:r.topg.top&&l.push(d);break;case w.Left:r.left>g.left&&l.push(d);break;case w.Right:r.left1&&(f=u[1].id),f!=null){const d=i.get(n.id),g=i.get(f),h=g?o.get(g.id):null,C=g?.node.current;if(C&&h&&d&&g){const p=nt(C).some((E,x)=>a[x]!==E),m=pn(d,g),y=io(d,g),b=p||!m?{x:0,y:0}:{x:y?r.width-h.width:0,y:y?r.height-h.height:0},R={x:h.left,y:h.top};return b.x&&b.y?R:ze(R,b)}}}};function pn(e,t){return!et(e)||!et(t)?!1:e.data.current.sortable.containerId===t.data.current.sortable.containerId}function io(e,t){return!et(e)||!et(t)||!pn(e,t)?!1:e.data.current.sortable.indexr=>{t.forEach(o=>o(r))},t)}const et=typeof window<"u"&&typeof window.document<"u"&&typeof window.document.createElement<"u";function me(e){const t=Object.prototype.toString.call(e);return t==="[object Window]"||t==="[object global]"}function pt(e){return"nodeType"in e}function B(e){var t,n;return e?me(e)?e:pt(e)&&(t=(n=e.ownerDocument)==null?void 0:n.defaultView)!=null?t:window:window}function bt(e){const{Document:t}=B(e);return e instanceof t}function Be(e){return me(e)?!1:e instanceof B(e).HTMLElement}function Ut(e){return e instanceof B(e).SVGElement}function ye(e){return e?me(e)?e.document:pt(e)?bt(e)?e:Be(e)||Ut(e)?e.ownerDocument:document:document:document}const Q=et?c.useLayoutEffect:c.useEffect;function wt(e){const t=c.useRef(e);return Q(()=>{t.current=e}),c.useCallback(function(){for(var n=arguments.length,r=new Array(n),o=0;o{e.current=setInterval(r,o)},[]),n=c.useCallback(()=>{e.current!==null&&(clearInterval(e.current),e.current=null)},[]);return[t,n]}function ke(e,t){t===void 0&&(t=[e]);const n=c.useRef(e);return Q(()=>{n.current!==e&&(n.current=e)},t),n}function Fe(e,t){const n=c.useRef();return c.useMemo(()=>{const r=e(n.current);return n.current=r,r},[...t])}function Ge(e){const t=wt(e),n=c.useRef(null),r=c.useCallback(o=>{o!==n.current&&t?.(o,n.current),n.current=o},[]);return[n,r]}function dt(e){const t=c.useRef();return c.useEffect(()=>{t.current=e},[e]),t.current}let at={};function $e(e,t){return c.useMemo(()=>{if(t)return t;const n=at[e]==null?0:at[e]+1;return at[e]=n,e+"-"+n},[e,t])}function Wt(e){return function(t){for(var n=arguments.length,r=new Array(n>1?n-1:0),o=1;o{const a=Object.entries(s);for(const[l,u]of a){const f=i[l];f!=null&&(i[l]=f+e*u)}return i},{...t})}}const we=Wt(1),ze=Wt(-1);function En(e){return"clientX"in e&&"clientY"in e}function mt(e){if(!e)return!1;const{KeyboardEvent:t}=B(e.target);return t&&e instanceof t}function Mn(e){if(!e)return!1;const{TouchEvent:t}=B(e.target);return t&&e instanceof t}function ft(e){if(Mn(e)){if(e.touches&&e.touches.length){const{clientX:t,clientY:n}=e.touches[0];return{x:t,y:n}}else if(e.changedTouches&&e.changedTouches.length){const{clientX:t,clientY:n}=e.changedTouches[0];return{x:t,y:n}}}return En(e)?{x:e.clientX,y:e.clientY}:null}const Je=Object.freeze({Translate:{toString(e){if(!e)return;const{x:t,y:n}=e;return"translate3d("+(t?Math.round(t):0)+"px, "+(n?Math.round(n):0)+"px, 0)"}},Scale:{toString(e){if(!e)return;const{scaleX:t,scaleY:n}=e;return"scaleX("+t+") scaleY("+n+")"}},Transform:{toString(e){if(e)return[Je.Translate.toString(e),Je.Scale.toString(e)].join(" ")}},Transition:{toString(e){let{property:t,duration:n,easing:r}=e;return t+" "+n+"ms "+r}}}),Ot="a,frame,iframe,input:not([type=hidden]):not(:disabled),select:not(:disabled),textarea:not(:disabled),button:not(:disabled),*[tabindex]";function In(e){return e.matches(Ot)?e:e.querySelector(Ot)}const An={display:"none"};function On(e){let{id:t,value:n}=e;return P.createElement("div",{id:t,style:An},n)}function Tn(e){let{id:t,announcement:n,ariaLiveType:r="assertive"}=e;const o={position:"fixed",top:0,left:0,width:1,height:1,margin:-1,border:0,padding:0,overflow:"hidden",clip:"rect(0 0 0 0)",clipPath:"inset(100%)",whiteSpace:"nowrap"};return P.createElement("div",{id:t,style:o,role:"status","aria-live":r,"aria-atomic":!0},n)}function Nn(){const[e,t]=c.useState("");return{announce:c.useCallback(r=>{r!=null&&t(r)},[]),announcement:e}}const Ht=c.createContext(null);function Ln(e){const t=c.useContext(Ht);c.useEffect(()=>{if(!t)throw new Error("useDndMonitor must be used within a children of ");return t(e)},[e,t])}function kn(){const[e]=c.useState(()=>new Set),t=c.useCallback(r=>(e.add(r),()=>e.delete(r)),[e]);return[c.useCallback(r=>{let{type:o,event:i}=r;e.forEach(s=>{var a;return(a=s[o])==null?void 0:a.call(s,i)})},[e]),t]}const zn={draggable:` - To pick up a draggable item, press the space bar. - While dragging, use the arrow keys to move the item. - Press space again to drop the item in its new position, or press escape to cancel. - `},Pn={onDragStart(e){let{active:t}=e;return"Picked up draggable item "+t.id+"."},onDragOver(e){let{active:t,over:n}=e;return n?"Draggable item "+t.id+" was moved over droppable area "+n.id+".":"Draggable item "+t.id+" is no longer over a droppable area."},onDragEnd(e){let{active:t,over:n}=e;return n?"Draggable item "+t.id+" was dropped over droppable area "+n.id:"Draggable item "+t.id+" was dropped."},onDragCancel(e){let{active:t}=e;return"Dragging was cancelled. Draggable item "+t.id+" was dropped."}};function Bn(e){let{announcements:t=Pn,container:n,hiddenTextDescribedById:r,screenReaderInstructions:o=zn}=e;const{announce:i,announcement:s}=Nn(),a=$e("DndLiveRegion"),[l,u]=c.useState(!1);if(c.useEffect(()=>{u(!0)},[]),Ln(c.useMemo(()=>({onDragStart(d){let{active:g}=d;i(t.onDragStart({active:g}))},onDragMove(d){let{active:g,over:h}=d;t.onDragMove&&i(t.onDragMove({active:g,over:h}))},onDragOver(d){let{active:g,over:h}=d;i(t.onDragOver({active:g,over:h}))},onDragEnd(d){let{active:g,over:h}=d;i(t.onDragEnd({active:g,over:h}))},onDragCancel(d){let{active:g,over:h}=d;i(t.onDragCancel({active:g,over:h}))}}),[i,t])),!l)return null;const f=P.createElement(P.Fragment,null,P.createElement(On,{id:r,value:o.draggable}),P.createElement(Tn,{id:a,announcement:s}));return n?Oe.createPortal(f,n):f}var O;(function(e){e.DragStart="dragStart",e.DragMove="dragMove",e.DragEnd="dragEnd",e.DragCancel="dragCancel",e.DragOver="dragOver",e.RegisterDroppable="registerDroppable",e.SetDroppableDisabled="setDroppableDisabled",e.UnregisterDroppable="unregisterDroppable"})(O||(O={}));function _e(){}function io(e,t){return c.useMemo(()=>({sensor:e,options:t??{}}),[e,t])}function so(){for(var e=arguments.length,t=new Array(e),n=0;n[...t].filter(r=>r!=null),[...t])}const V=Object.freeze({x:0,y:0});function Kt(e,t){return Math.sqrt(Math.pow(e.x-t.x,2)+Math.pow(e.y-t.y,2))}function Vt(e,t){let{data:{value:n}}=e,{data:{value:r}}=t;return n-r}function Fn(e,t){let{data:{value:n}}=e,{data:{value:r}}=t;return r-n}function Tt(e){let{left:t,top:n,height:r,width:o}=e;return[{x:t,y:n},{x:t+o,y:n},{x:t,y:n+r},{x:t+o,y:n+r}]}function qt(e,t){if(!e||e.length===0)return null;const[n]=e;return n[t]}function Nt(e,t,n){return t===void 0&&(t=e.left),n===void 0&&(n=e.top),{x:t+e.width*.5,y:n+e.height*.5}}const ao=e=>{let{collisionRect:t,droppableRects:n,droppableContainers:r}=e;const o=Nt(t,t.left,t.top),i=[];for(const s of r){const{id:a}=s,l=n.get(a);if(l){const u=Kt(Nt(l),o);i.push({id:a,data:{droppableContainer:s,value:u}})}}return i.sort(Vt)},$n=e=>{let{collisionRect:t,droppableRects:n,droppableContainers:r}=e;const o=Tt(t),i=[];for(const s of r){const{id:a}=s,l=n.get(a);if(l){const u=Tt(l),f=o.reduce((g,h,C)=>g+Kt(u[C],h),0),d=Number((f/4).toFixed(4));i.push({id:a,data:{droppableContainer:s,value:d}})}}return i.sort(Vt)};function Xn(e,t){const n=Math.max(t.top,e.top),r=Math.max(t.left,e.left),o=Math.min(t.left+t.width,e.left+e.width),i=Math.min(t.top+t.height,e.top+e.height),s=o-r,a=i-n;if(r{let{collisionRect:t,droppableRects:n,droppableContainers:r}=e;const o=[];for(const i of r){const{id:s}=i,a=n.get(s);if(a){const l=Xn(a,t);l>0&&o.push({id:s,data:{droppableContainer:i,value:l}})}}return o.sort(Fn)};function jn(e,t,n){return{...e,scaleX:t&&n?t.width/n.width:1,scaleY:t&&n?t.height/n.height:1}}function Gt(e,t){return e&&t?{x:e.left-t.left,y:e.top-t.top}:V}function Un(e){return function(n){for(var r=arguments.length,o=new Array(r>1?r-1:0),i=1;i({...s,top:s.top+e*a.y,bottom:s.bottom+e*a.y,left:s.left+e*a.x,right:s.right+e*a.x}),{...n})}}const Wn=Un(1);function Hn(e){if(e.startsWith("matrix3d(")){const t=e.slice(9,-1).split(/, /);return{x:+t[12],y:+t[13],scaleX:+t[0],scaleY:+t[5]}}else if(e.startsWith("matrix(")){const t=e.slice(7,-1).split(/, /);return{x:+t[4],y:+t[5],scaleX:+t[0],scaleY:+t[3]}}return null}function Kn(e,t,n){const r=Hn(t);if(!r)return e;const{scaleX:o,scaleY:i,x:s,y:a}=r,l=e.left-s-(1-o)*parseFloat(n),u=e.top-a-(1-i)*parseFloat(n.slice(n.indexOf(" ")+1)),f=o?e.width/o:e.width,d=i?e.height/i:e.height;return{width:f,height:d,top:u,right:l+f,bottom:u+d,left:l}}const Vn={ignoreTransform:!1};function xe(e,t){t===void 0&&(t=Vn);let n=e.getBoundingClientRect();if(t.ignoreTransform){const{transform:u,transformOrigin:f}=B(e).getComputedStyle(e);u&&(n=Kn(n,u,f))}const{top:r,left:o,width:i,height:s,bottom:a,right:l}=n;return{top:r,left:o,width:i,height:s,bottom:a,right:l}}function Lt(e){return xe(e,{ignoreTransform:!0})}function qn(e){const t=e.innerWidth,n=e.innerHeight;return{top:0,left:0,right:t,bottom:n,width:t,height:n}}function Gn(e,t){return t===void 0&&(t=B(e).getComputedStyle(e)),t.position==="fixed"}function Jn(e,t){t===void 0&&(t=B(e).getComputedStyle(e));const n=/(auto|scroll|overlay)/;return["overflow","overflowX","overflowY"].some(o=>{const i=t[o];return typeof i=="string"?n.test(i):!1})}function tt(e,t){const n=[];function r(o){if(t!=null&&n.length>=t||!o)return n;if(bt(o)&&o.scrollingElement!=null&&!n.includes(o.scrollingElement))return n.push(o.scrollingElement),n;if(!Be(o)||Ut(o)||n.includes(o))return n;const i=B(e).getComputedStyle(o);return o!==e&&Jn(o,i)&&n.push(o),Gn(o,i)?n:r(o.parentNode)}return e?r(e):n}function Jt(e){const[t]=tt(e,1);return t??null}function ct(e){return!et||!e?null:me(e)?e:pt(e)?bt(e)||e===ye(e).scrollingElement?window:Be(e)?e:null:null}function _t(e){return me(e)?e.scrollX:e.scrollLeft}function Qt(e){return me(e)?e.scrollY:e.scrollTop}function ht(e){return{x:_t(e),y:Qt(e)}}var N;(function(e){e[e.Forward=1]="Forward",e[e.Backward=-1]="Backward"})(N||(N={}));function Zt(e){return!et||!e?!1:e===document.scrollingElement}function en(e){const t={x:0,y:0},n=Zt(e)?{height:window.innerHeight,width:window.innerWidth}:{height:e.clientHeight,width:e.clientWidth},r={x:e.scrollWidth-n.width,y:e.scrollHeight-n.height},o=e.scrollTop<=t.y,i=e.scrollLeft<=t.x,s=e.scrollTop>=r.y,a=e.scrollLeft>=r.x;return{isTop:o,isLeft:i,isBottom:s,isRight:a,maxScroll:r,minScroll:t}}const _n={x:.2,y:.2};function Qn(e,t,n,r,o){let{top:i,left:s,right:a,bottom:l}=n;r===void 0&&(r=10),o===void 0&&(o=_n);const{isTop:u,isBottom:f,isLeft:d,isRight:g}=en(e),h={x:0,y:0},C={x:0,y:0},v={height:t.height*o.y,width:t.width*o.x};return!u&&i<=t.top+v.height?(h.y=N.Backward,C.y=r*Math.abs((t.top+v.height-i)/v.height)):!f&&l>=t.bottom-v.height&&(h.y=N.Forward,C.y=r*Math.abs((t.bottom-v.height-l)/v.height)),!g&&a>=t.right-v.width?(h.x=N.Forward,C.x=r*Math.abs((t.right-v.width-a)/v.width)):!d&&s<=t.left+v.width&&(h.x=N.Backward,C.x=r*Math.abs((t.left+v.width-s)/v.width)),{direction:h,speed:C}}function Zn(e){if(e===document.scrollingElement){const{innerWidth:i,innerHeight:s}=window;return{top:0,left:0,right:i,bottom:s,width:i,height:s}}const{top:t,left:n,right:r,bottom:o}=e.getBoundingClientRect();return{top:t,left:n,right:r,bottom:o,width:e.clientWidth,height:e.clientHeight}}function tn(e){return e.reduce((t,n)=>we(t,ht(n)),V)}function er(e){return e.reduce((t,n)=>t+_t(n),0)}function tr(e){return e.reduce((t,n)=>t+Qt(n),0)}function nr(e,t){if(t===void 0&&(t=xe),!e)return;const{top:n,left:r,bottom:o,right:i}=t(e);Jt(e)&&(o<=0||i<=0||n>=window.innerHeight||r>=window.innerWidth)&&e.scrollIntoView({block:"center",inline:"center"})}const rr=[["x",["left","right"],er],["y",["top","bottom"],tr]];class yt{constructor(t,n){this.rect=void 0,this.width=void 0,this.height=void 0,this.top=void 0,this.bottom=void 0,this.right=void 0,this.left=void 0;const r=tt(n),o=tn(r);this.rect={...t},this.width=t.width,this.height=t.height;for(const[i,s,a]of rr)for(const l of s)Object.defineProperty(this,l,{get:()=>{const u=a(r),f=o[i]-u;return this.rect[l]+f},enumerable:!0});Object.defineProperty(this,"rect",{enumerable:!1})}}class Te{constructor(t){this.target=void 0,this.listeners=[],this.removeAll=()=>{this.listeners.forEach(n=>{var r;return(r=this.target)==null?void 0:r.removeEventListener(...n)})},this.target=t}add(t,n,r){var o;(o=this.target)==null||o.addEventListener(t,n,r),this.listeners.push([t,n,r])}}function or(e){const{EventTarget:t}=B(e);return e instanceof t?e:ye(e)}function lt(e,t){const n=Math.abs(e.x),r=Math.abs(e.y);return typeof t=="number"?Math.sqrt(n**2+r**2)>t:"x"in t&&"y"in t?n>t.x&&r>t.y:"x"in t?n>t.x:"y"in t?r>t.y:!1}var W;(function(e){e.Click="click",e.DragStart="dragstart",e.Keydown="keydown",e.ContextMenu="contextmenu",e.Resize="resize",e.SelectionChange="selectionchange",e.VisibilityChange="visibilitychange"})(W||(W={}));function kt(e){e.preventDefault()}function ir(e){e.stopPropagation()}var w;(function(e){e.Space="Space",e.Down="ArrowDown",e.Right="ArrowRight",e.Left="ArrowLeft",e.Up="ArrowUp",e.Esc="Escape",e.Enter="Enter",e.Tab="Tab"})(w||(w={}));const nn={start:[w.Space,w.Enter],cancel:[w.Esc],end:[w.Space,w.Enter,w.Tab]},sr=(e,t)=>{let{currentCoordinates:n}=t;switch(e.code){case w.Right:return{...n,x:n.x+25};case w.Left:return{...n,x:n.x-25};case w.Down:return{...n,y:n.y+25};case w.Up:return{...n,y:n.y-25}}};class rn{constructor(t){this.props=void 0,this.autoScrollEnabled=!1,this.referenceCoordinates=void 0,this.listeners=void 0,this.windowListeners=void 0,this.props=t;const{event:{target:n}}=t;this.props=t,this.listeners=new Te(ye(n)),this.windowListeners=new Te(B(n)),this.handleKeyDown=this.handleKeyDown.bind(this),this.handleCancel=this.handleCancel.bind(this),this.attach()}attach(){this.handleStart(),this.windowListeners.add(W.Resize,this.handleCancel),this.windowListeners.add(W.VisibilityChange,this.handleCancel),setTimeout(()=>this.listeners.add(W.Keydown,this.handleKeyDown))}handleStart(){const{activeNode:t,onStart:n}=this.props,r=t.node.current;r&&nr(r),n(V)}handleKeyDown(t){if(mt(t)){const{active:n,context:r,options:o}=this.props,{keyboardCodes:i=nn,coordinateGetter:s=sr,scrollBehavior:a="smooth"}=o,{code:l}=t;if(i.end.includes(l)){this.handleEnd(t);return}if(i.cancel.includes(l)){this.handleCancel(t);return}const{collisionRect:u}=r.current,f=u?{x:u.left,y:u.top}:V;this.referenceCoordinates||(this.referenceCoordinates=f);const d=s(t,{active:n,context:r.current,currentCoordinates:f});if(d){const g=ze(d,f),h={x:0,y:0},{scrollableAncestors:C}=r.current;for(const v of C){const p=t.code,{isTop:m,isRight:y,isLeft:b,isBottom:R,maxScroll:S,minScroll:E}=en(v),x=Zn(v),D={x:Math.min(p===w.Right?x.right-x.width/2:x.right,Math.max(p===w.Right?x.left:x.left+x.width/2,d.x)),y:Math.min(p===w.Down?x.bottom-x.height/2:x.bottom,Math.max(p===w.Down?x.top:x.top+x.height/2,d.y))},A=p===w.Right&&!y||p===w.Left&&!b,T=p===w.Down&&!R||p===w.Up&&!m;if(A&&D.x!==d.x){const I=v.scrollLeft+g.x,H=p===w.Right&&I<=S.x||p===w.Left&&I>=E.x;if(H&&!g.y){v.scrollTo({left:I,behavior:a});return}H?h.x=v.scrollLeft-I:h.x=p===w.Right?v.scrollLeft-S.x:v.scrollLeft-E.x,h.x&&v.scrollBy({left:-h.x,behavior:a});break}else if(T&&D.y!==d.y){const I=v.scrollTop+g.y,H=p===w.Down&&I<=S.y||p===w.Up&&I>=E.y;if(H&&!g.x){v.scrollTo({top:I,behavior:a});return}H?h.y=v.scrollTop-I:h.y=p===w.Down?v.scrollTop-S.y:v.scrollTop-E.y,h.y&&v.scrollBy({top:-h.y,behavior:a});break}}this.handleMove(t,we(ze(d,this.referenceCoordinates),h))}}}handleMove(t,n){const{onMove:r}=this.props;t.preventDefault(),r(n)}handleEnd(t){const{onEnd:n}=this.props;t.preventDefault(),this.detach(),n()}handleCancel(t){const{onCancel:n}=this.props;t.preventDefault(),this.detach(),n()}detach(){this.listeners.removeAll(),this.windowListeners.removeAll()}}rn.activators=[{eventName:"onKeyDown",handler:(e,t,n)=>{let{keyboardCodes:r=nn,onActivation:o}=t,{active:i}=n;const{code:s}=e.nativeEvent;if(r.start.includes(s)){const a=i.activatorNode.current;return a&&e.target!==a?!1:(e.preventDefault(),o?.({event:e.nativeEvent}),!0)}return!1}}];function zt(e){return!!(e&&"distance"in e)}function Pt(e){return!!(e&&"delay"in e)}class xt{constructor(t,n,r){var o;r===void 0&&(r=or(t.event.target)),this.props=void 0,this.events=void 0,this.autoScrollEnabled=!0,this.document=void 0,this.activated=!1,this.initialCoordinates=void 0,this.timeoutId=null,this.listeners=void 0,this.documentListeners=void 0,this.windowListeners=void 0,this.props=t,this.events=n;const{event:i}=t,{target:s}=i;this.props=t,this.events=n,this.document=ye(s),this.documentListeners=new Te(this.document),this.listeners=new Te(r),this.windowListeners=new Te(B(s)),this.initialCoordinates=(o=ft(i))!=null?o:V,this.handleStart=this.handleStart.bind(this),this.handleMove=this.handleMove.bind(this),this.handleEnd=this.handleEnd.bind(this),this.handleCancel=this.handleCancel.bind(this),this.handleKeydown=this.handleKeydown.bind(this),this.removeTextSelection=this.removeTextSelection.bind(this),this.attach()}attach(){const{events:t,props:{options:{activationConstraint:n,bypassActivationConstraint:r}}}=this;if(this.listeners.add(t.move.name,this.handleMove,{passive:!1}),this.listeners.add(t.end.name,this.handleEnd),t.cancel&&this.listeners.add(t.cancel.name,this.handleCancel),this.windowListeners.add(W.Resize,this.handleCancel),this.windowListeners.add(W.DragStart,kt),this.windowListeners.add(W.VisibilityChange,this.handleCancel),this.windowListeners.add(W.ContextMenu,kt),this.documentListeners.add(W.Keydown,this.handleKeydown),n){if(r!=null&&r({event:this.props.event,activeNode:this.props.activeNode,options:this.props.options}))return this.handleStart();if(Pt(n)){this.timeoutId=setTimeout(this.handleStart,n.delay),this.handlePending(n);return}if(zt(n)){this.handlePending(n);return}}this.handleStart()}detach(){this.listeners.removeAll(),this.windowListeners.removeAll(),setTimeout(this.documentListeners.removeAll,50),this.timeoutId!==null&&(clearTimeout(this.timeoutId),this.timeoutId=null)}handlePending(t,n){const{active:r,onPending:o}=this.props;o(r,t,this.initialCoordinates,n)}handleStart(){const{initialCoordinates:t}=this,{onStart:n}=this.props;t&&(this.activated=!0,this.documentListeners.add(W.Click,ir,{capture:!0}),this.removeTextSelection(),this.documentListeners.add(W.SelectionChange,this.removeTextSelection),n(t))}handleMove(t){var n;const{activated:r,initialCoordinates:o,props:i}=this,{onMove:s,options:{activationConstraint:a}}=i;if(!o)return;const l=(n=ft(t))!=null?n:V,u=ze(o,l);if(!r&&a){if(zt(a)){if(a.tolerance!=null&<(u,a.tolerance))return this.handleCancel();if(lt(u,a.distance))return this.handleStart()}if(Pt(a)&<(u,a.tolerance))return this.handleCancel();this.handlePending(a,u);return}t.cancelable&&t.preventDefault(),s(l)}handleEnd(){const{onAbort:t,onEnd:n}=this.props;this.detach(),this.activated||t(this.props.active),n()}handleCancel(){const{onAbort:t,onCancel:n}=this.props;this.detach(),this.activated||t(this.props.active),n()}handleKeydown(t){t.code===w.Esc&&this.handleCancel()}removeTextSelection(){var t;(t=this.document.getSelection())==null||t.removeAllRanges()}}const ar={cancel:{name:"pointercancel"},move:{name:"pointermove"},end:{name:"pointerup"}};class on extends xt{constructor(t){const{event:n}=t,r=ye(n.target);super(t,ar,r)}}on.activators=[{eventName:"onPointerDown",handler:(e,t)=>{let{nativeEvent:n}=e,{onActivation:r}=t;return!n.isPrimary||n.button!==0?!1:(r?.({event:n}),!0)}}];const cr={move:{name:"mousemove"},end:{name:"mouseup"}};var gt;(function(e){e[e.RightClick=2]="RightClick"})(gt||(gt={}));class lr extends xt{constructor(t){super(t,cr,ye(t.event.target))}}lr.activators=[{eventName:"onMouseDown",handler:(e,t)=>{let{nativeEvent:n}=e,{onActivation:r}=t;return n.button===gt.RightClick?!1:(r?.({event:n}),!0)}}];const ut={cancel:{name:"touchcancel"},move:{name:"touchmove"},end:{name:"touchend"}};class ur extends xt{constructor(t){super(t,ut)}static setup(){return window.addEventListener(ut.move.name,t,{capture:!1,passive:!1}),function(){window.removeEventListener(ut.move.name,t)};function t(){}}}ur.activators=[{eventName:"onTouchStart",handler:(e,t)=>{let{nativeEvent:n}=e,{onActivation:r}=t;const{touches:o}=n;return o.length>1?!1:(r?.({event:n}),!0)}}];var Ne;(function(e){e[e.Pointer=0]="Pointer",e[e.DraggableRect=1]="DraggableRect"})(Ne||(Ne={}));var Qe;(function(e){e[e.TreeOrder=0]="TreeOrder",e[e.ReversedTreeOrder=1]="ReversedTreeOrder"})(Qe||(Qe={}));function dr(e){let{acceleration:t,activator:n=Ne.Pointer,canScroll:r,draggingRect:o,enabled:i,interval:s=5,order:a=Qe.TreeOrder,pointerCoordinates:l,scrollableAncestors:u,scrollableAncestorRects:f,delta:d,threshold:g}=e;const h=hr({delta:d,disabled:!i}),[C,v]=Sn(),p=c.useRef({x:0,y:0}),m=c.useRef({x:0,y:0}),y=c.useMemo(()=>{switch(n){case Ne.Pointer:return l?{top:l.y,bottom:l.y,left:l.x,right:l.x}:null;case Ne.DraggableRect:return o}},[n,o,l]),b=c.useRef(null),R=c.useCallback(()=>{const E=b.current;if(!E)return;const x=p.current.x*m.current.x,D=p.current.y*m.current.y;E.scrollBy(x,D)},[]),S=c.useMemo(()=>a===Qe.TreeOrder?[...u].reverse():u,[a,u]);c.useEffect(()=>{if(!i||!u.length||!y){v();return}for(const E of S){if(r?.(E)===!1)continue;const x=u.indexOf(E),D=f[x];if(!D)continue;const{direction:A,speed:T}=Qn(E,D,y,t,g);for(const I of["x","y"])h[I][A[I]]||(T[I]=0,A[I]=0);if(T.x>0||T.y>0){v(),b.current=E,C(R,s),p.current=T,m.current=A;return}}p.current={x:0,y:0},m.current={x:0,y:0},v()},[t,R,r,v,i,s,JSON.stringify(y),JSON.stringify(h),C,u,S,f,JSON.stringify(g)])}const fr={x:{[N.Backward]:!1,[N.Forward]:!1},y:{[N.Backward]:!1,[N.Forward]:!1}};function hr(e){let{delta:t,disabled:n}=e;const r=dt(t);return Fe(o=>{if(n||!r||!o)return fr;const i={x:Math.sign(t.x-r.x),y:Math.sign(t.y-r.y)};return{x:{[N.Backward]:o.x[N.Backward]||i.x===-1,[N.Forward]:o.x[N.Forward]||i.x===1},y:{[N.Backward]:o.y[N.Backward]||i.y===-1,[N.Forward]:o.y[N.Forward]||i.y===1}}},[n,t,r])}function gr(e,t){const n=t!=null?e.get(t):void 0,r=n?n.node.current:null;return Fe(o=>{var i;return t==null?null:(i=r??o)!=null?i:null},[r,t])}function vr(e,t){return c.useMemo(()=>e.reduce((n,r)=>{const{sensor:o}=r,i=o.activators.map(s=>({eventName:s.eventName,handler:t(s.handler,r)}));return[...n,...i]},[]),[e,t])}var Pe;(function(e){e[e.Always=0]="Always",e[e.BeforeDragging=1]="BeforeDragging",e[e.WhileDragging=2]="WhileDragging"})(Pe||(Pe={}));var vt;(function(e){e.Optimized="optimized"})(vt||(vt={}));const Bt=new Map;function pr(e,t){let{dragging:n,dependencies:r,config:o}=t;const[i,s]=c.useState(null),{frequency:a,measure:l,strategy:u}=o,f=c.useRef(e),d=p(),g=ke(d),h=c.useCallback(function(m){m===void 0&&(m=[]),!g.current&&s(y=>y===null?m:y.concat(m.filter(b=>!y.includes(b))))},[g]),C=c.useRef(null),v=Fe(m=>{if(d&&!n)return Bt;if(!m||m===Bt||f.current!==e||i!=null){const y=new Map;for(let b of e){if(!b)continue;if(i&&i.length>0&&!i.includes(b.id)&&b.rect.current){y.set(b.id,b.rect.current);continue}const R=b.node.current,S=R?new yt(l(R),R):null;b.rect.current=S,S&&y.set(b.id,S)}return y}return m},[e,i,n,d,l]);return c.useEffect(()=>{f.current=e},[e]),c.useEffect(()=>{d||h()},[n,d]),c.useEffect(()=>{i&&i.length>0&&s(null)},[JSON.stringify(i)]),c.useEffect(()=>{d||typeof a!="number"||C.current!==null||(C.current=setTimeout(()=>{h(),C.current=null},a))},[a,d,h,...r]),{droppableRects:v,measureDroppableContainers:h,measuringScheduled:i!=null};function p(){switch(u){case Pe.Always:return!1;case Pe.BeforeDragging:return n;default:return!n}}}function sn(e,t){return Fe(n=>e?n||(typeof t=="function"?t(e):e):null,[t,e])}function br(e,t){return sn(e,t)}function wr(e){let{callback:t,disabled:n}=e;const r=wt(t),o=c.useMemo(()=>{if(n||typeof window>"u"||typeof window.MutationObserver>"u")return;const{MutationObserver:i}=window;return new i(r)},[r,n]);return c.useEffect(()=>()=>o?.disconnect(),[o]),o}function nt(e){let{callback:t,disabled:n}=e;const r=wt(t),o=c.useMemo(()=>{if(n||typeof window>"u"||typeof window.ResizeObserver>"u")return;const{ResizeObserver:i}=window;return new i(r)},[n]);return c.useEffect(()=>()=>o?.disconnect(),[o]),o}function mr(e){return new yt(xe(e),e)}function Ft(e,t,n){t===void 0&&(t=mr);const[r,o]=c.useState(null);function i(){o(l=>{if(!e)return null;if(e.isConnected===!1){var u;return(u=l??n)!=null?u:null}const f=t(e);return JSON.stringify(l)===JSON.stringify(f)?l:f})}const s=wr({callback(l){if(e)for(const u of l){const{type:f,target:d}=u;if(f==="childList"&&d instanceof HTMLElement&&d.contains(e)){i();break}}}}),a=nt({callback:i});return Q(()=>{i(),e?(a?.observe(e),s?.observe(document.body,{childList:!0,subtree:!0})):(a?.disconnect(),s?.disconnect())},[e]),r}function yr(e){const t=sn(e);return Gt(e,t)}const $t=[];function xr(e){const t=c.useRef(e),n=Fe(r=>e?r&&r!==$t&&e&&t.current&&e.parentNode===t.current.parentNode?r:tt(e):$t,[e]);return c.useEffect(()=>{t.current=e},[e]),n}function Dr(e){const[t,n]=c.useState(null),r=c.useRef(e),o=c.useCallback(i=>{const s=ct(i.target);s&&n(a=>a?(a.set(s,ht(s)),new Map(a)):null)},[]);return c.useEffect(()=>{const i=r.current;if(e!==i){s(i);const a=e.map(l=>{const u=ct(l);return u?(u.addEventListener("scroll",o,{passive:!0}),[u,ht(u)]):null}).filter(l=>l!=null);n(a.length?new Map(a):null),r.current=e}return()=>{s(e),s(i)};function s(a){a.forEach(l=>{const u=ct(l);u?.removeEventListener("scroll",o)})}},[o,e]),c.useMemo(()=>e.length?t?Array.from(t.values()).reduce((i,s)=>we(i,s),V):tn(e):V,[e,t])}function Xt(e,t){t===void 0&&(t=[]);const n=c.useRef(null);return c.useEffect(()=>{n.current=null},t),c.useEffect(()=>{const r=e!==V;r&&!n.current&&(n.current=e),!r&&n.current&&(n.current=null)},[e]),n.current?ze(e,n.current):V}function Cr(e){c.useEffect(()=>{if(!et)return;const t=e.map(n=>{let{sensor:r}=n;return r.setup==null?void 0:r.setup()});return()=>{for(const n of t)n?.()}},e.map(t=>{let{sensor:n}=t;return n}))}function Rr(e,t){return c.useMemo(()=>e.reduce((n,r)=>{let{eventName:o,handler:i}=r;return n[o]=s=>{i(s,t)},n},{}),[e,t])}function an(e){return c.useMemo(()=>e?qn(e):null,[e])}const Yt=[];function Sr(e,t){t===void 0&&(t=xe);const[n]=e,r=an(n?B(n):null),[o,i]=c.useState(Yt);function s(){i(()=>e.length?e.map(l=>Zt(l)?r:new yt(t(l),l)):Yt)}const a=nt({callback:s});return Q(()=>{a?.disconnect(),s(),e.forEach(l=>a?.observe(l))},[e]),o}function Er(e){if(!e)return null;if(e.children.length>1)return e;const t=e.children[0];return Be(t)?t:e}function Mr(e){let{measure:t}=e;const[n,r]=c.useState(null),o=c.useCallback(u=>{for(const{target:f}of u)if(Be(f)){r(d=>{const g=t(f);return d?{...d,width:g.width,height:g.height}:g});break}},[t]),i=nt({callback:o}),s=c.useCallback(u=>{const f=Er(u);i?.disconnect(),f&&i?.observe(f),r(f?t(f):null)},[t,i]),[a,l]=Ge(s);return c.useMemo(()=>({nodeRef:a,rect:n,setRef:l}),[n,a,l])}const Ir=[{sensor:on,options:{}},{sensor:rn,options:{}}],Ar={current:{}},qe={draggable:{measure:Lt},droppable:{measure:Lt,strategy:Pe.WhileDragging,frequency:vt.Optimized},dragOverlay:{measure:xe}};class Le extends Map{get(t){var n;return t!=null&&(n=super.get(t))!=null?n:void 0}toArray(){return Array.from(this.values())}getEnabled(){return this.toArray().filter(t=>{let{disabled:n}=t;return!n})}getNodeFor(t){var n,r;return(n=(r=this.get(t))==null?void 0:r.node.current)!=null?n:void 0}}const Or={activatorEvent:null,active:null,activeNode:null,activeNodeRect:null,collisions:null,containerNodeRect:null,draggableNodes:new Map,droppableRects:new Map,droppableContainers:new Le,over:null,dragOverlay:{nodeRef:{current:null},rect:null,setRef:_e},scrollableAncestors:[],scrollableAncestorRects:[],measuringConfiguration:qe,measureDroppableContainers:_e,windowRect:null,measuringScheduled:!1},Tr={activatorEvent:null,activators:[],active:null,activeNodeRect:null,ariaDescribedById:{draggable:""},dispatch:_e,draggableNodes:new Map,over:null,measureDroppableContainers:_e},rt=c.createContext(Tr),cn=c.createContext(Or);function Nr(){return{draggable:{active:null,initialCoordinates:{x:0,y:0},nodes:new Map,translate:{x:0,y:0}},droppable:{containers:new Le}}}function Lr(e,t){switch(t.type){case O.DragStart:return{...e,draggable:{...e.draggable,initialCoordinates:t.initialCoordinates,active:t.active}};case O.DragMove:return e.draggable.active==null?e:{...e,draggable:{...e.draggable,translate:{x:t.coordinates.x-e.draggable.initialCoordinates.x,y:t.coordinates.y-e.draggable.initialCoordinates.y}}};case O.DragEnd:case O.DragCancel:return{...e,draggable:{...e.draggable,active:null,initialCoordinates:{x:0,y:0},translate:{x:0,y:0}}};case O.RegisterDroppable:{const{element:n}=t,{id:r}=n,o=new Le(e.droppable.containers);return o.set(r,n),{...e,droppable:{...e.droppable,containers:o}}}case O.SetDroppableDisabled:{const{id:n,key:r,disabled:o}=t,i=e.droppable.containers.get(n);if(!i||r!==i.key)return e;const s=new Le(e.droppable.containers);return s.set(n,{...i,disabled:o}),{...e,droppable:{...e.droppable,containers:s}}}case O.UnregisterDroppable:{const{id:n,key:r}=t,o=e.droppable.containers.get(n);if(!o||r!==o.key)return e;const i=new Le(e.droppable.containers);return i.delete(n),{...e,droppable:{...e.droppable,containers:i}}}default:return e}}function kr(e){let{disabled:t}=e;const{active:n,activatorEvent:r,draggableNodes:o}=c.useContext(rt),i=dt(r),s=dt(n?.id);return c.useEffect(()=>{if(!t&&!r&&i&&s!=null){if(!mt(i)||document.activeElement===i.target)return;const a=o.get(s);if(!a)return;const{activatorNode:l,node:u}=a;if(!l.current&&!u.current)return;requestAnimationFrame(()=>{for(const f of[l.current,u.current]){if(!f)continue;const d=In(f);if(d){d.focus();break}}})}},[r,t,o,s,i]),null}function zr(e,t){let{transform:n,...r}=t;return e!=null&&e.length?e.reduce((o,i)=>i({transform:o,...r}),n):n}function Pr(e){return c.useMemo(()=>({draggable:{...qe.draggable,...e?.draggable},droppable:{...qe.droppable,...e?.droppable},dragOverlay:{...qe.dragOverlay,...e?.dragOverlay}}),[e?.draggable,e?.droppable,e?.dragOverlay])}function Br(e){let{activeNode:t,measure:n,initialRect:r,config:o=!0}=e;const i=c.useRef(!1),{x:s,y:a}=typeof o=="boolean"?{x:o,y:o}:o;Q(()=>{if(!s&&!a||!t){i.current=!1;return}if(i.current||!r)return;const u=t?.node.current;if(!u||u.isConnected===!1)return;const f=n(u),d=Gt(f,r);if(s||(d.x=0),a||(d.y=0),i.current=!0,Math.abs(d.x)>0||Math.abs(d.y)>0){const g=Jt(u);g&&g.scrollBy({top:d.y,left:d.x})}},[t,s,a,r,n])}const ln=c.createContext({...V,scaleX:1,scaleY:1});var ue;(function(e){e[e.Uninitialized=0]="Uninitialized",e[e.Initializing=1]="Initializing",e[e.Initialized=2]="Initialized"})(ue||(ue={}));const co=c.memo(function(t){var n,r,o,i;let{id:s,accessibility:a,autoScroll:l=!0,children:u,sensors:f=Ir,collisionDetection:d=Yn,measuring:g,modifiers:h,...C}=t;const v=c.useReducer(Lr,void 0,Nr),[p,m]=v,[y,b]=kn(),[R,S]=c.useState(ue.Uninitialized),E=R===ue.Initialized,{draggable:{active:x,nodes:D,translate:A},droppable:{containers:T}}=p,I=x!=null?D.get(x):null,H=c.useRef({initial:null,translated:null}),K=c.useMemo(()=>{var k;return x!=null?{id:x,data:(k=I?.data)!=null?k:Ar,rect:H}:null},[x,I]),q=c.useRef(null),[De,Xe]=c.useState(null),[F,Ye]=c.useState(null),Z=ke(C,Object.values(C)),Ce=$e("DndDescribedBy",s),je=c.useMemo(()=>T.getEnabled(),[T]),z=Pr(g),{droppableRects:ee,measureDroppableContainers:de,measuringScheduled:Re}=pr(je,{dragging:E,dependencies:[A.x,A.y],config:z.droppable}),j=gr(D,x),Ue=c.useMemo(()=>F?ft(F):null,[F]),oe=Cn(),te=br(j,z.draggable.measure);Br({activeNode:x!=null?D.get(x):null,config:oe.layoutShiftCompensation,initialRect:te,measure:z.draggable.measure});const M=Ft(j,z.draggable.measure,te),Se=Ft(j?j.parentElement:null),G=c.useRef({activatorEvent:null,active:null,activeNode:j,collisionRect:null,collisions:null,droppableRects:ee,draggableNodes:D,draggingNode:null,draggingNodeRect:null,droppableContainers:T,over:null,scrollableAncestors:[],scrollAdjustedTranslate:null}),fe=T.getNodeFor((n=G.current.over)==null?void 0:n.id),ne=Mr({measure:z.dragOverlay.measure}),he=(r=ne.nodeRef.current)!=null?r:j,ge=E?(o=ne.rect)!=null?o:M:null,Dt=!!(ne.nodeRef.current&&ne.rect),Ct=yr(Dt?null:M),ot=an(he?B(he):null),ie=xr(E?fe??j:null),We=Sr(ie),He=zr(h,{transform:{x:A.x-Ct.x,y:A.y-Ct.y,scaleX:1,scaleY:1},activatorEvent:F,active:K,activeNodeRect:M,containerNodeRect:Se,draggingNodeRect:ge,over:G.current.over,overlayNodeRect:ne.rect,scrollableAncestors:ie,scrollableAncestorRects:We,windowRect:ot}),Rt=Ue?we(Ue,A):null,St=Dr(ie),pn=Xt(St),bn=Xt(St,[M]),ve=we(He,pn),pe=ge?Wn(ge,He):null,Ee=K&&pe?d({active:K,collisionRect:pe,droppableRects:ee,droppableContainers:je,pointerCoordinates:Rt}):null,Et=qt(Ee,"id"),[se,Mt]=c.useState(null),wn=Dt?He:we(He,bn),mn=jn(wn,(i=se?.rect)!=null?i:null,M),it=c.useRef(null),It=c.useCallback((k,$)=>{let{sensor:X,options:ae}=$;if(q.current==null)return;const U=D.get(q.current);if(!U)return;const Y=k.nativeEvent,J=new X({active:q.current,activeNode:U,event:Y,options:ae,context:G,onAbort(L){if(!D.get(L))return;const{onDragAbort:_}=Z.current,re={id:L};_?.(re),y({type:"onDragAbort",event:re})},onPending(L,ce,_,re){if(!D.get(L))return;const{onDragPending:Ie}=Z.current,le={id:L,constraint:ce,initialCoordinates:_,offset:re};Ie?.(le),y({type:"onDragPending",event:le})},onStart(L){const ce=q.current;if(ce==null)return;const _=D.get(ce);if(!_)return;const{onDragStart:re}=Z.current,Me={activatorEvent:Y,active:{id:ce,data:_.data,rect:H}};Oe.unstable_batchedUpdates(()=>{re?.(Me),S(ue.Initializing),m({type:O.DragStart,initialCoordinates:L,active:ce}),y({type:"onDragStart",event:Me}),Xe(it.current),Ye(Y)})},onMove(L){m({type:O.DragMove,coordinates:L})},onEnd:be(O.DragEnd),onCancel:be(O.DragCancel)});it.current=J;function be(L){return async function(){const{active:_,collisions:re,over:Me,scrollAdjustedTranslate:Ie}=G.current;let le=null;if(_&&Ie){const{cancelDrop:Ae}=Z.current;le={activatorEvent:Y,active:_,collisions:re,delta:Ie,over:Me},L===O.DragEnd&&typeof Ae=="function"&&await Promise.resolve(Ae(le))&&(L=O.DragCancel)}q.current=null,Oe.unstable_batchedUpdates(()=>{m({type:L}),S(ue.Uninitialized),Mt(null),Xe(null),Ye(null),it.current=null;const Ae=L===O.DragEnd?"onDragEnd":"onDragCancel";if(le){const st=Z.current[Ae];st?.(le),y({type:Ae,event:le})}})}}},[D]),yn=c.useCallback((k,$)=>(X,ae)=>{const U=X.nativeEvent,Y=D.get(ae);if(q.current!==null||!Y||U.dndKit||U.defaultPrevented)return;const J={active:Y};k(X,$.options,J)===!0&&(U.dndKit={capturedBy:$.sensor},q.current=ae,It(X,$))},[D,It]),At=vr(f,yn);Cr(f),Q(()=>{M&&R===ue.Initializing&&S(ue.Initialized)},[M,R]),c.useEffect(()=>{const{onDragMove:k}=Z.current,{active:$,activatorEvent:X,collisions:ae,over:U}=G.current;if(!$||!X)return;const Y={active:$,activatorEvent:X,collisions:ae,delta:{x:ve.x,y:ve.y},over:U};Oe.unstable_batchedUpdates(()=>{k?.(Y),y({type:"onDragMove",event:Y})})},[ve.x,ve.y]),c.useEffect(()=>{const{active:k,activatorEvent:$,collisions:X,droppableContainers:ae,scrollAdjustedTranslate:U}=G.current;if(!k||q.current==null||!$||!U)return;const{onDragOver:Y}=Z.current,J=ae.get(Et),be=J&&J.rect.current?{id:J.id,rect:J.rect.current,data:J.data,disabled:J.disabled}:null,L={active:k,activatorEvent:$,collisions:X,delta:{x:U.x,y:U.y},over:be};Oe.unstable_batchedUpdates(()=>{Mt(be),Y?.(L),y({type:"onDragOver",event:L})})},[Et]),Q(()=>{G.current={activatorEvent:F,active:K,activeNode:j,collisionRect:pe,collisions:Ee,droppableRects:ee,draggableNodes:D,draggingNode:he,draggingNodeRect:ge,droppableContainers:T,over:se,scrollableAncestors:ie,scrollAdjustedTranslate:ve},H.current={initial:ge,translated:pe}},[K,j,Ee,pe,D,he,ge,ee,T,se,ie,ve]),dr({...oe,delta:A,draggingRect:pe,pointerCoordinates:Rt,scrollableAncestors:ie,scrollableAncestorRects:We});const xn=c.useMemo(()=>({active:K,activeNode:j,activeNodeRect:M,activatorEvent:F,collisions:Ee,containerNodeRect:Se,dragOverlay:ne,draggableNodes:D,droppableContainers:T,droppableRects:ee,over:se,measureDroppableContainers:de,scrollableAncestors:ie,scrollableAncestorRects:We,measuringConfiguration:z,measuringScheduled:Re,windowRect:ot}),[K,j,M,F,Ee,Se,ne,D,T,ee,se,de,ie,We,z,Re,ot]),Dn=c.useMemo(()=>({activatorEvent:F,activators:At,active:K,activeNodeRect:M,ariaDescribedById:{draggable:Ce},dispatch:m,draggableNodes:D,over:se,measureDroppableContainers:de}),[F,At,K,M,m,Ce,D,se,de]);return P.createElement(Ht.Provider,{value:b},P.createElement(rt.Provider,{value:Dn},P.createElement(cn.Provider,{value:xn},P.createElement(ln.Provider,{value:mn},u)),P.createElement(kr,{disabled:a?.restoreFocus===!1})),P.createElement(Bn,{...a,hiddenTextDescribedById:Ce}));function Cn(){const k=De?.autoScrollEnabled===!1,$=typeof l=="object"?l.enabled===!1:l===!1,X=E&&!k&&!$;return typeof l=="object"?{...l,enabled:X}:{enabled:X}}}),Fr=c.createContext(null),jt="button",$r="Draggable";function Xr(e){let{id:t,data:n,disabled:r=!1,attributes:o}=e;const i=$e($r),{activators:s,activatorEvent:a,active:l,activeNodeRect:u,ariaDescribedById:f,draggableNodes:d,over:g}=c.useContext(rt),{role:h=jt,roleDescription:C="draggable",tabIndex:v=0}=o??{},p=l?.id===t,m=c.useContext(p?ln:Fr),[y,b]=Ge(),[R,S]=Ge(),E=Rr(s,t),x=ke(n);Q(()=>(d.set(t,{id:t,key:i,node:y,activatorNode:R,data:x}),()=>{const A=d.get(t);A&&A.key===i&&d.delete(t)}),[d,t]);const D=c.useMemo(()=>({role:h,tabIndex:v,"aria-disabled":r,"aria-pressed":p&&h===jt?!0:void 0,"aria-roledescription":C,"aria-describedby":f.draggable}),[r,h,v,p,C,f.draggable]);return{active:l,activatorEvent:a,activeNodeRect:u,attributes:D,isDragging:p,listeners:r?void 0:E,node:y,over:g,setNodeRef:b,setActivatorNodeRef:S,transform:m}}function Yr(){return c.useContext(cn)}const jr="Droppable",Ur={timeout:25};function Wr(e){let{data:t,disabled:n=!1,id:r,resizeObserverConfig:o}=e;const i=$e(jr),{active:s,dispatch:a,over:l,measureDroppableContainers:u}=c.useContext(rt),f=c.useRef({disabled:n}),d=c.useRef(!1),g=c.useRef(null),h=c.useRef(null),{disabled:C,updateMeasurementsFor:v,timeout:p}={...Ur,...o},m=ke(v??r),y=c.useCallback(()=>{if(!d.current){d.current=!0;return}h.current!=null&&clearTimeout(h.current),h.current=setTimeout(()=>{u(Array.isArray(m.current)?m.current:[m.current]),h.current=null},p)},[p]),b=nt({callback:y,disabled:C||!s}),R=c.useCallback((D,A)=>{b&&(A&&(b.unobserve(A),d.current=!1),D&&b.observe(D))},[b]),[S,E]=Ge(R),x=ke(t);return c.useEffect(()=>{!b||!S.current||(b.disconnect(),d.current=!1,b.observe(S.current))},[S,b]),c.useEffect(()=>(a({type:O.RegisterDroppable,element:{id:r,key:i,disabled:n,node:S,rect:g,data:x}}),()=>a({type:O.UnregisterDroppable,key:i,id:r})),[r]),c.useEffect(()=>{n!==f.current.disabled&&(a({type:O.SetDroppableDisabled,id:r,key:i,disabled:n}),f.current.disabled=n)},[r,i,n,a]),{active:s,rect:g,isOver:l?.id===r,node:S,over:l,setNodeRef:E}}function un(e,t,n){const r=e.slice();return r.splice(n<0?r.length+n:n,0,r.splice(t,1)[0]),r}function Hr(e,t){return e.reduce((n,r,o)=>{const i=t.get(r);return i&&(n[o]=i),n},Array(e.length))}function Ke(e){return e!==null&&e>=0}function Kr(e,t){if(e===t)return!0;if(e.length!==t.length)return!1;for(let n=0;n{var t;let{rects:n,activeNodeRect:r,activeIndex:o,overIndex:i,index:s}=e;const a=(t=n[o])!=null?t:r;if(!a)return null;const l=qr(n,s,o);if(s===o){const u=n[i];return u?{x:oo&&s<=i?{x:-a.width-l,y:0,...Ve}:s=i?{x:a.width+l,y:0,...Ve}:{x:0,y:0,...Ve}};function qr(e,t,n){const r=e[t],o=e[t-1],i=e[t+1];return!r||!o&&!i?0:n{let{rects:t,activeIndex:n,overIndex:r,index:o}=e;const i=un(t,r,n),s=t[o],a=i[o];return!a||!s?null:{x:a.left-s.left,y:a.top-s.top,scaleX:a.width/s.width,scaleY:a.height/s.height}},fn="Sortable",hn=P.createContext({activeIndex:-1,containerId:fn,disableTransforms:!1,items:[],overIndex:-1,useDragOverlay:!1,sortedRects:[],strategy:dn,disabled:{draggable:!1,droppable:!1}});function uo(e){let{children:t,id:n,items:r,strategy:o=dn,disabled:i=!1}=e;const{active:s,dragOverlay:a,droppableRects:l,over:u,measureDroppableContainers:f}=Yr(),d=$e(fn,n),g=a.rect!==null,h=c.useMemo(()=>r.map(E=>typeof E=="object"&&"id"in E?E.id:E),[r]),C=s!=null,v=s?h.indexOf(s.id):-1,p=u?h.indexOf(u.id):-1,m=c.useRef(h),y=!Kr(h,m.current),b=p!==-1&&v===-1||y,R=Vr(i);Q(()=>{y&&C&&f(h)},[y,h,C,f]),c.useEffect(()=>{m.current=h},[h]);const S=c.useMemo(()=>({activeIndex:v,containerId:d,disabled:R,disableTransforms:b,items:h,overIndex:p,useDragOverlay:g,sortedRects:Hr(h,l),strategy:o}),[v,d,R.draggable,R.droppable,b,h,p,l,g,o]);return P.createElement(hn.Provider,{value:S},t)}const Gr=e=>{let{id:t,items:n,activeIndex:r,overIndex:o}=e;return un(n,r,o).indexOf(t)},Jr=e=>{let{containerId:t,isSorting:n,wasDragging:r,index:o,items:i,newIndex:s,previousItems:a,previousContainerId:l,transition:u}=e;return!u||!r||a!==i&&o===s?!1:n?!0:s!==o&&t===l},_r={duration:200,easing:"ease"},gn="transform",Qr=Je.Transition.toString({property:gn,duration:0,easing:"linear"}),Zr={roleDescription:"sortable"};function eo(e){let{disabled:t,index:n,node:r,rect:o}=e;const[i,s]=c.useState(null),a=c.useRef(n);return Q(()=>{if(!t&&n!==a.current&&r.current){const l=o.current;if(l){const u=xe(r.current,{ignoreTransform:!0}),f={x:l.left-u.left,y:l.top-u.top,scaleX:l.width/u.width,scaleY:l.height/u.height};(f.x||f.y)&&s(f)}}n!==a.current&&(a.current=n)},[t,n,r,o]),c.useEffect(()=>{i&&s(null)},[i]),i}function fo(e){let{animateLayoutChanges:t=Jr,attributes:n,disabled:r,data:o,getNewIndex:i=Gr,id:s,strategy:a,resizeObserverConfig:l,transition:u=_r}=e;const{items:f,containerId:d,activeIndex:g,disabled:h,disableTransforms:C,sortedRects:v,overIndex:p,useDragOverlay:m,strategy:y}=c.useContext(hn),b=to(r,h),R=f.indexOf(s),S=c.useMemo(()=>({sortable:{containerId:d,index:R,items:f},...o}),[d,o,R,f]),E=c.useMemo(()=>f.slice(f.indexOf(s)),[f,s]),{rect:x,node:D,isOver:A,setNodeRef:T}=Wr({id:s,data:S,disabled:b.droppable,resizeObserverConfig:{updateMeasurementsFor:E,...l}}),{active:I,activatorEvent:H,activeNodeRect:K,attributes:q,setNodeRef:De,listeners:Xe,isDragging:F,over:Ye,setActivatorNodeRef:Z,transform:Ce}=Xr({id:s,data:S,attributes:{...Zr,...n},disabled:b.draggable}),je=Rn(T,De),z=!!I,ee=z&&!C&&Ke(g)&&Ke(p),de=!m&&F,Re=de&&ee?Ce:null,Ue=ee?Re??(a??y)({rects:v,activeNodeRect:K,activeIndex:g,overIndex:p,index:R}):null,oe=Ke(g)&&Ke(p)?i({id:s,items:f,activeIndex:g,overIndex:p}):R,te=I?.id,M=c.useRef({activeId:te,items:f,newIndex:oe,containerId:d}),Se=f!==M.current.items,G=t({active:I,containerId:d,isDragging:F,isSorting:z,id:s,index:R,items:f,newIndex:M.current.newIndex,previousItems:M.current.items,previousContainerId:M.current.containerId,transition:u,wasDragging:M.current.activeId!=null}),fe=eo({disabled:!G,index:R,node:D,rect:x});return c.useEffect(()=>{z&&M.current.newIndex!==oe&&(M.current.newIndex=oe),d!==M.current.containerId&&(M.current.containerId=d),f!==M.current.items&&(M.current.items=f)},[z,oe,d,f]),c.useEffect(()=>{if(te===M.current.activeId)return;if(te!=null&&M.current.activeId==null){M.current.activeId=te;return}const he=setTimeout(()=>{M.current.activeId=te},50);return()=>clearTimeout(he)},[te]),{active:I,activeIndex:g,attributes:q,data:S,rect:x,index:R,newIndex:oe,items:f,isOver:A,isSorting:z,isDragging:F,listeners:Xe,node:D,overIndex:p,over:Ye,setNodeRef:je,setActivatorNodeRef:Z,setDroppableNodeRef:T,setDraggableNodeRef:De,transform:fe??Ue,transition:ne()};function ne(){if(fe||Se&&M.current.newIndex===R)return Qr;if(!(de&&!mt(H)||!u)&&(z||G))return Je.Transition.toString({...u,property:gn})}}function to(e,t){var n,r;return typeof e=="boolean"?{draggable:e,droppable:!1}:{draggable:(n=e?.draggable)!=null?n:t.draggable,droppable:(r=e?.droppable)!=null?r:t.droppable}}function Ze(e){if(!e)return!1;const t=e.data.current;return!!(t&&"sortable"in t&&typeof t.sortable=="object"&&"containerId"in t.sortable&&"items"in t.sortable&&"index"in t.sortable)}const no=[w.Down,w.Right,w.Up,w.Left],ho=(e,t)=>{let{context:{active:n,collisionRect:r,droppableRects:o,droppableContainers:i,over:s,scrollableAncestors:a}}=t;if(no.includes(e.code)){if(e.preventDefault(),!n||!r)return;const l=[];i.getEnabled().forEach(d=>{if(!d||d!=null&&d.disabled)return;const g=o.get(d.id);if(g)switch(e.code){case w.Down:r.topg.top&&l.push(d);break;case w.Left:r.left>g.left&&l.push(d);break;case w.Right:r.left1&&(f=u[1].id),f!=null){const d=i.get(n.id),g=i.get(f),h=g?o.get(g.id):null,C=g?.node.current;if(C&&h&&d&&g){const p=tt(C).some((E,x)=>a[x]!==E),m=vn(d,g),y=ro(d,g),b=p||!m?{x:0,y:0}:{x:y?r.width-h.width:0,y:y?r.height-h.height:0},R={x:h.left,y:h.top};return b.x&&b.y?R:ze(R,b)}}}};function vn(e,t){return!Ze(e)||!Ze(t)?!1:e.data.current.sortable.containerId===t.data.current.sortable.containerId}function ro(e,t){return!Ze(e)||!Ze(t)||!vn(e,t)?!1:e.data.current.sortable.indext.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase(),M=t=>t.replace(/^([A-Z])|[\s-_]+(\w)/g,(a,c,o)=>o?o.toUpperCase():c.toLowerCase()),d=t=>{const a=M(t);return a.charAt(0).toUpperCase()+a.slice(1)},r=(...t)=>t.filter((a,c,o)=>!!a&&a.trim()!==""&&o.indexOf(a)===c).join(" ").trim(),x=t=>{for(const a in t)if(a.startsWith("aria-")||a==="role"||a==="title")return!0};var m={xmlns:"http://www.w3.org/2000/svg",width:24,height:24,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"};const v=s.forwardRef(({color:t="currentColor",size:a=24,strokeWidth:c=2,absoluteStrokeWidth:o,className:y="",children:n,iconNode:k,...h},i)=>s.createElement("svg",{ref:i,...m,width:a,height:a,stroke:t,strokeWidth:o?Number(c)*24/Number(a):c,className:r("lucide",y),...!n&&!x(h)&&{"aria-hidden":"true"},...h},[...k.map(([p,l])=>s.createElement(p,l)),...Array.isArray(n)?n:[n]]));const e=(t,a)=>{const c=s.forwardRef(({className:o,...y},n)=>s.createElement(v,{ref:n,iconNode:a,className:r(`lucide-${_(d(t))}`,`lucide-${t}`,o),...y}));return c.displayName=d(t),c};const g=[["path",{d:"M22 12h-2.48a2 2 0 0 0-1.93 1.46l-2.35 8.36a.25.25 0 0 1-.48 0L9.24 2.18a.25.25 0 0 0-.48 0l-2.35 8.36A2 2 0 0 1 4.49 12H2",key:"169zse"}]],p2=e("activity",g);const u=[["path",{d:"m12 19-7-7 7-7",key:"1l729n"}],["path",{d:"M19 12H5",key:"x3x0zl"}]],l2=e("arrow-left",u);const f=[["path",{d:"M5 12h14",key:"1ays0h"}],["path",{d:"m12 5 7 7-7 7",key:"xquz4c"}]],_2=e("arrow-right",f);const $=[["path",{d:"M4.929 4.929 19.07 19.071",key:"196cmz"}],["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}]],M2=e("ban",$);const N=[["path",{d:"M12 7v14",key:"1akyts"}],["path",{d:"M3 18a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h5a4 4 0 0 1 4 4 4 4 0 0 1 4-4h5a1 1 0 0 1 1 1v13a1 1 0 0 1-1 1h-6a3 3 0 0 0-3 3 3 3 0 0 0-3-3z",key:"ruj8y"}]],x2=e("book-open",N);const w=[["path",{d:"M12 8V4H8",key:"hb8ula"}],["rect",{width:"16",height:"12",x:"4",y:"8",rx:"2",key:"enze0r"}],["path",{d:"M2 14h2",key:"vft8re"}],["path",{d:"M20 14h2",key:"4cs60a"}],["path",{d:"M15 13v2",key:"1xurst"}],["path",{d:"M9 13v2",key:"rq6x2g"}]],m2=e("bot",w);const z=[["path",{d:"M2.97 12.92A2 2 0 0 0 2 14.63v3.24a2 2 0 0 0 .97 1.71l3 1.8a2 2 0 0 0 2.06 0L12 19v-5.5l-5-3-4.03 2.42Z",key:"lc1i9w"}],["path",{d:"m7 16.5-4.74-2.85",key:"1o9zyk"}],["path",{d:"m7 16.5 5-3",key:"va8pkn"}],["path",{d:"M7 16.5v5.17",key:"jnp8gn"}],["path",{d:"M12 13.5V19l3.97 2.38a2 2 0 0 0 2.06 0l3-1.8a2 2 0 0 0 .97-1.71v-3.24a2 2 0 0 0-.97-1.71L17 10.5l-5 3Z",key:"8zsnat"}],["path",{d:"m17 16.5-5-3",key:"8arw3v"}],["path",{d:"m17 16.5 4.74-2.85",key:"8rfmw"}],["path",{d:"M17 16.5v5.17",key:"k6z78m"}],["path",{d:"M7.97 4.42A2 2 0 0 0 7 6.13v4.37l5 3 5-3V6.13a2 2 0 0 0-.97-1.71l-3-1.8a2 2 0 0 0-2.06 0l-3 1.8Z",key:"1xygjf"}],["path",{d:"M12 8 7.26 5.15",key:"1vbdud"}],["path",{d:"m12 8 4.74-2.85",key:"3rx089"}],["path",{d:"M12 13.5V8",key:"1io7kd"}]],v2=e("boxes",z);const b=[["path",{d:"M12 20v-9",key:"1qisl0"}],["path",{d:"M14 7a4 4 0 0 1 4 4v3a6 6 0 0 1-12 0v-3a4 4 0 0 1 4-4z",key:"uouzyp"}],["path",{d:"M14.12 3.88 16 2",key:"qol33r"}],["path",{d:"M21 21a4 4 0 0 0-3.81-4",key:"1b0z45"}],["path",{d:"M21 5a4 4 0 0 1-3.55 3.97",key:"5cxbf6"}],["path",{d:"M22 13h-4",key:"1jl80f"}],["path",{d:"M3 21a4 4 0 0 1 3.81-4",key:"1fjd4g"}],["path",{d:"M3 5a4 4 0 0 0 3.55 3.97",key:"1d7oge"}],["path",{d:"M6 13H2",key:"82j7cp"}],["path",{d:"m8 2 1.88 1.88",key:"fmnt4t"}],["path",{d:"M9 7.13V6a3 3 0 1 1 6 0v1.13",key:"1vgav8"}]],g2=e("bug",b);const q=[["path",{d:"M8 2v4",key:"1cmpym"}],["path",{d:"M16 2v4",key:"4m81vk"}],["rect",{width:"18",height:"18",x:"3",y:"4",rx:"2",key:"1hopcy"}],["path",{d:"M3 10h18",key:"8toen8"}]],u2=e("calendar",q);const C=[["path",{d:"M3 3v16a2 2 0 0 0 2 2h16",key:"c24i48"}],["path",{d:"M18 17V9",key:"2bz60n"}],["path",{d:"M13 17V5",key:"1frdt8"}],["path",{d:"M8 17v-3",key:"17ska0"}]],f2=e("chart-column",C);const j=[["path",{d:"M20 6 9 17l-5-5",key:"1gmf2c"}]],$2=e("check",j);const V=[["path",{d:"m6 9 6 6 6-6",key:"qrunsl"}]],N2=e("chevron-down",V);const A=[["path",{d:"m15 18-6-6 6-6",key:"1wnfg3"}]],w2=e("chevron-left",A);const L=[["path",{d:"m9 18 6-6-6-6",key:"mthhwq"}]],z2=e("chevron-right",L);const H=[["path",{d:"m18 15-6-6-6 6",key:"153udz"}]],b2=e("chevron-up",H);const S=[["path",{d:"m11 17-5-5 5-5",key:"13zhaf"}],["path",{d:"m18 17-5-5 5-5",key:"h8a8et"}]],q2=e("chevrons-left",S);const P=[["path",{d:"m6 17 5-5-5-5",key:"xnjwq"}],["path",{d:"m13 17 5-5-5-5",key:"17xmmf"}]],C2=e("chevrons-right",P);const U=[["path",{d:"m7 15 5 5 5-5",key:"1hf1tw"}],["path",{d:"m7 9 5-5 5 5",key:"sgt6xg"}]],j2=e("chevrons-up-down",U);const R=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["line",{x1:"12",x2:"12",y1:"8",y2:"12",key:"1pkeuh"}],["line",{x1:"12",x2:"12.01",y1:"16",y2:"16",key:"4dfq90"}]],V2=e("circle-alert",R);const T=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"m9 12 2 2 4-4",key:"dzmm74"}]],A2=e("circle-check",T);const Z=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3",key:"1u773s"}],["path",{d:"M12 17h.01",key:"p32p05"}]],L2=e("circle-question-mark",Z);const B=[["path",{d:"M18 20a6 6 0 0 0-12 0",key:"1qehca"}],["circle",{cx:"12",cy:"10",r:"4",key:"1h16sb"}],["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}]],H2=e("circle-user-round",B);const D=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["circle",{cx:"12",cy:"10",r:"3",key:"ilqhr7"}],["path",{d:"M7 20.662V19a2 2 0 0 1 2-2h6a2 2 0 0 1 2 2v1.662",key:"154egf"}]],S2=e("circle-user",D);const E=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"m15 9-6 6",key:"1uzhvr"}],["path",{d:"m9 9 6 6",key:"z0biqf"}]],P2=e("circle-x",E);const F=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}]],U2=e("circle",F);const O=[["rect",{width:"8",height:"4",x:"8",y:"2",rx:"1",ry:"1",key:"tgr4d6"}],["path",{d:"M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2",key:"116196"}],["path",{d:"M12 11h4",key:"1jrz19"}],["path",{d:"M12 16h4",key:"n85exb"}],["path",{d:"M8 11h.01",key:"1dfujw"}],["path",{d:"M8 16h.01",key:"18s6g9"}]],R2=e("clipboard-list",O);const G=[["path",{d:"M12 6v6l4 2",key:"mmk7yg"}],["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}]],T2=e("clock",G);const I=[["path",{d:"m18 16 4-4-4-4",key:"1inbqp"}],["path",{d:"m6 8-4 4 4 4",key:"15zrgr"}],["path",{d:"m14.5 4-5 16",key:"e7oirm"}]],Z2=e("code-xml",I);const W=[["path",{d:"M22 7.7c0-.6-.4-1.2-.8-1.5l-6.3-3.9a1.72 1.72 0 0 0-1.7 0l-10.3 6c-.5.2-.9.8-.9 1.4v6.6c0 .5.4 1.2.8 1.5l6.3 3.9a1.72 1.72 0 0 0 1.7 0l10.3-6c.5-.3.9-1 .9-1.5Z",key:"1t2lqe"}],["path",{d:"M10 21.9V14L2.1 9.1",key:"o7czzq"}],["path",{d:"m10 14 11.9-6.9",key:"zm5e20"}],["path",{d:"M14 19.8v-8.1",key:"159ecu"}],["path",{d:"M18 17.5V9.4",key:"11uown"}]],B2=e("container",W);const K=[["rect",{width:"14",height:"14",x:"8",y:"8",rx:"2",ry:"2",key:"17jyea"}],["path",{d:"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2",key:"zix9uf"}]],D2=e("copy",K);const Q=[["ellipse",{cx:"12",cy:"5",rx:"9",ry:"3",key:"msslwz"}],["path",{d:"M3 5V19A9 3 0 0 0 21 19V5",key:"1wlel7"}],["path",{d:"M3 12A9 3 0 0 0 21 12",key:"mv7ke4"}]],E2=e("database",Q);const X=[["line",{x1:"12",x2:"12",y1:"2",y2:"22",key:"7eqyqh"}],["path",{d:"M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6",key:"1b0p4s"}]],F2=e("dollar-sign",X);const J=[["path",{d:"M12 15V3",key:"m9g1x1"}],["path",{d:"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4",key:"ih7n3h"}],["path",{d:"m7 10 5 5 5-5",key:"brsn70"}]],O2=e("download",J);const Y=[["path",{d:"M15 3h6v6",key:"1q9fwt"}],["path",{d:"M10 14 21 3",key:"gplh6r"}],["path",{d:"M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6",key:"a6xqqp"}]],G2=e("external-link",Y);const e1=[["path",{d:"M10.733 5.076a10.744 10.744 0 0 1 11.205 6.575 1 1 0 0 1 0 .696 10.747 10.747 0 0 1-1.444 2.49",key:"ct8e1f"}],["path",{d:"M14.084 14.158a3 3 0 0 1-4.242-4.242",key:"151rxh"}],["path",{d:"M17.479 17.499a10.75 10.75 0 0 1-15.417-5.151 1 1 0 0 1 0-.696 10.75 10.75 0 0 1 4.446-5.143",key:"13bj9a"}],["path",{d:"m2 2 20 20",key:"1ooewy"}]],I2=e("eye-off",e1);const a1=[["path",{d:"M2.062 12.348a1 1 0 0 1 0-.696 10.75 10.75 0 0 1 19.876 0 1 1 0 0 1 0 .696 10.75 10.75 0 0 1-19.876 0",key:"1nclc0"}],["circle",{cx:"12",cy:"12",r:"3",key:"1v7zrd"}]],W2=e("eye",a1);const t1=[["path",{d:"M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z",key:"1oefj6"}],["path",{d:"M12 17h.01",key:"p32p05"}],["path",{d:"M9.1 9a3 3 0 0 1 5.82 1c0 2-3 3-3 3",key:"mhlwft"}]],K2=e("file-question-mark",t1);const c1=[["path",{d:"M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z",key:"1oefj6"}],["path",{d:"M14 2v5a1 1 0 0 0 1 1h5",key:"wfsgrz"}],["circle",{cx:"11.5",cy:"14.5",r:"2.5",key:"1bq0ko"}],["path",{d:"M13.3 16.3 15 18",key:"2quom7"}]],Q2=e("file-search",c1);const o1=[["path",{d:"M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z",key:"1oefj6"}],["path",{d:"M14 2v5a1 1 0 0 0 1 1h5",key:"wfsgrz"}],["path",{d:"M10 9H8",key:"b1mrlr"}],["path",{d:"M16 13H8",key:"t4e002"}],["path",{d:"M16 17H8",key:"z1uh3a"}]],X2=e("file-text",o1);const n1=[["path",{d:"m6 14 1.5-2.9A2 2 0 0 1 9.24 10H20a2 2 0 0 1 1.94 2.5l-1.54 6a2 2 0 0 1-1.95 1.5H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h3.9a2 2 0 0 1 1.69.9l.81 1.2a2 2 0 0 0 1.67.9H18a2 2 0 0 1 2 2v2",key:"usdka0"}]],J2=e("folder-open",n1);const s1=[["path",{d:"M10 20a1 1 0 0 0 .553.895l2 1A1 1 0 0 0 14 21v-7a2 2 0 0 1 .517-1.341L21.74 4.67A1 1 0 0 0 21 3H3a1 1 0 0 0-.742 1.67l7.225 7.989A2 2 0 0 1 10 14z",key:"sc7q7i"}]],Y2=e("funnel",s1);const y1=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20",key:"13o1zl"}],["path",{d:"M2 12h20",key:"9i4pu4"}]],e0=e("globe",y1);const h1=[["path",{d:"M21.42 10.922a1 1 0 0 0-.019-1.838L12.83 5.18a2 2 0 0 0-1.66 0L2.6 9.08a1 1 0 0 0 0 1.832l8.57 3.908a2 2 0 0 0 1.66 0z",key:"j76jl0"}],["path",{d:"M22 10v6",key:"1lu8f3"}],["path",{d:"M6 12.5V16a6 3 0 0 0 12 0v-3.5",key:"1r8lef"}]],a0=e("graduation-cap",h1);const d1=[["circle",{cx:"9",cy:"12",r:"1",key:"1vctgf"}],["circle",{cx:"9",cy:"5",r:"1",key:"hp0tcf"}],["circle",{cx:"9",cy:"19",r:"1",key:"fkjjf6"}],["circle",{cx:"15",cy:"12",r:"1",key:"1tmaij"}],["circle",{cx:"15",cy:"5",r:"1",key:"19l28e"}],["circle",{cx:"15",cy:"19",r:"1",key:"f4zoj3"}]],t0=e("grip-vertical",d1);const r1=[["line",{x1:"22",x2:"2",y1:"12",y2:"12",key:"1y58io"}],["path",{d:"M5.45 5.11 2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z",key:"oot6mr"}],["line",{x1:"6",x2:"6.01",y1:"16",y2:"16",key:"sgf278"}],["line",{x1:"10",x2:"10.01",y1:"16",y2:"16",key:"1l4acy"}]],c0=e("hard-drive",r1);const k1=[["line",{x1:"4",x2:"20",y1:"9",y2:"9",key:"4lhtct"}],["line",{x1:"4",x2:"20",y1:"15",y2:"15",key:"vyu0kd"}],["line",{x1:"10",x2:"8",y1:"3",y2:"21",key:"1ggp8o"}],["line",{x1:"16",x2:"14",y1:"3",y2:"21",key:"weycgp"}]],o0=e("hash",k1);const i1=[["path",{d:"M15 21v-8a1 1 0 0 0-1-1h-4a1 1 0 0 0-1 1v8",key:"5wwlr5"}],["path",{d:"M3 10a2 2 0 0 1 .709-1.528l7-6a2 2 0 0 1 2.582 0l7 6A2 2 0 0 1 21 10v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z",key:"r6nss1"}]],n0=e("house",i1);const p1=[["rect",{width:"18",height:"18",x:"3",y:"3",rx:"2",ry:"2",key:"1m3agn"}],["circle",{cx:"9",cy:"9",r:"2",key:"af1f0g"}],["path",{d:"m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21",key:"1xmnt7"}]],s0=e("image",p1);const l1=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"M12 16v-4",key:"1dtifu"}],["path",{d:"M12 8h.01",key:"e9boi3"}]],y0=e("info",l1);const _1=[["path",{d:"m15.5 7.5 2.3 2.3a1 1 0 0 0 1.4 0l2.1-2.1a1 1 0 0 0 0-1.4L19 4",key:"g0fldk"}],["path",{d:"m21 2-9.6 9.6",key:"1j0ho8"}],["circle",{cx:"7.5",cy:"15.5",r:"5.5",key:"yqb3hr"}]],h0=e("key",_1);const M1=[["rect",{width:"7",height:"7",x:"3",y:"3",rx:"1",key:"1g98yp"}],["rect",{width:"7",height:"7",x:"14",y:"3",rx:"1",key:"6d4xhi"}],["rect",{width:"7",height:"7",x:"14",y:"14",rx:"1",key:"nxv5o0"}],["rect",{width:"7",height:"7",x:"3",y:"14",rx:"1",key:"1bb6yr"}]],d0=e("layout-grid",M1);const x1=[["path",{d:"M21 12a9 9 0 1 1-6.219-8.56",key:"13zald"}]],r0=e("loader-circle",x1);const m1=[["rect",{width:"18",height:"11",x:"3",y:"11",rx:"2",ry:"2",key:"1w4ew1"}],["path",{d:"M7 11V7a5 5 0 0 1 10 0v4",key:"fwvmzm"}]],k0=e("lock",m1);const v1=[["path",{d:"m16 17 5-5-5-5",key:"1bji2h"}],["path",{d:"M21 12H9",key:"dn1m92"}],["path",{d:"M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4",key:"1uf3rs"}]],i0=e("log-out",v1);const g1=[["path",{d:"M4 5h16",key:"1tepv9"}],["path",{d:"M4 12h16",key:"1lakjw"}],["path",{d:"M4 19h16",key:"1djgab"}]],p0=e("menu",g1);const u1=[["path",{d:"M2.992 16.342a2 2 0 0 1 .094 1.167l-1.065 3.29a1 1 0 0 0 1.236 1.168l3.413-.998a2 2 0 0 1 1.099.092 10 10 0 1 0-4.777-4.719",key:"1sd12s"}]],l0=e("message-circle",u1);const f1=[["path",{d:"M22 17a2 2 0 0 1-2 2H6.828a2 2 0 0 0-1.414.586l-2.202 2.202A.71.71 0 0 1 2 21.286V5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2z",key:"18887p"}]],_0=e("message-square",f1);const $1=[["path",{d:"M20.985 12.486a9 9 0 1 1-9.473-9.472c.405-.022.617.46.402.803a6 6 0 0 0 8.268 8.268c.344-.215.825-.004.803.401",key:"kfwtm"}]],M0=e("moon",$1);const N1=[["rect",{x:"16",y:"16",width:"6",height:"6",rx:"1",key:"4q2zg0"}],["rect",{x:"2",y:"16",width:"6",height:"6",rx:"1",key:"8cvhb9"}],["rect",{x:"9",y:"2",width:"6",height:"6",rx:"1",key:"1egb70"}],["path",{d:"M5 16v-3a1 1 0 0 1 1-1h12a1 1 0 0 1 1 1v3",key:"1jsf9p"}],["path",{d:"M12 12V8",key:"2874zd"}]],x0=e("network",N1);const w1=[["path",{d:"M11 21.73a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73z",key:"1a0edw"}],["path",{d:"M12 22V12",key:"d0xqtd"}],["polyline",{points:"3.29 7 12 12 20.71 7",key:"ousv84"}],["path",{d:"m7.5 4.27 9 5.15",key:"1c824w"}]],m0=e("package",w1);const z1=[["path",{d:"M12 22a1 1 0 0 1 0-20 10 9 0 0 1 10 9 5 5 0 0 1-5 5h-2.25a1.75 1.75 0 0 0-1.4 2.8l.3.4a1.75 1.75 0 0 1-1.4 2.8z",key:"e79jfc"}],["circle",{cx:"13.5",cy:"6.5",r:".5",fill:"currentColor",key:"1okk4w"}],["circle",{cx:"17.5",cy:"10.5",r:".5",fill:"currentColor",key:"f64h9f"}],["circle",{cx:"6.5",cy:"12.5",r:".5",fill:"currentColor",key:"qy21gx"}],["circle",{cx:"8.5",cy:"7.5",r:".5",fill:"currentColor",key:"fotxhn"}]],v0=e("palette",z1);const b1=[["rect",{width:"18",height:"18",x:"3",y:"3",rx:"2",key:"afitv7"}],["path",{d:"M3 9h18",key:"1pudct"}],["path",{d:"M9 21V9",key:"1oto5p"}]],g0=e("panels-top-left",b1);const q1=[["rect",{x:"14",y:"3",width:"5",height:"18",rx:"1",key:"kaeet6"}],["rect",{x:"5",y:"3",width:"5",height:"18",rx:"1",key:"1wsw3u"}]],u0=e("pause",q1);const C1=[["path",{d:"M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z",key:"1a8usu"}]],f0=e("pen",C1);const j1=[["path",{d:"M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z",key:"1a8usu"}],["path",{d:"m15 5 4 4",key:"1mk7zo"}]],$0=e("pencil",j1);const V1=[["path",{d:"M5 5a2 2 0 0 1 3.008-1.728l11.997 6.998a2 2 0 0 1 .003 3.458l-12 7A2 2 0 0 1 5 19z",key:"10ikf1"}]],N0=e("play",V1);const A1=[["path",{d:"M5 12h14",key:"1ays0h"}],["path",{d:"M12 5v14",key:"s699le"}]],w0=e("plus",A1);const L1=[["path",{d:"M12 2v10",key:"mnfbl"}],["path",{d:"M18.4 6.6a9 9 0 1 1-12.77.04",key:"obofu9"}]],z0=e("power",L1);const H1=[["path",{d:"M15.39 4.39a1 1 0 0 0 1.68-.474 2.5 2.5 0 1 1 3.014 3.015 1 1 0 0 0-.474 1.68l1.683 1.682a2.414 2.414 0 0 1 0 3.414L19.61 15.39a1 1 0 0 1-1.68-.474 2.5 2.5 0 1 0-3.014 3.015 1 1 0 0 1 .474 1.68l-1.683 1.682a2.414 2.414 0 0 1-3.414 0L8.61 19.61a1 1 0 0 0-1.68.474 2.5 2.5 0 1 1-3.014-3.015 1 1 0 0 0 .474-1.68l-1.683-1.682a2.414 2.414 0 0 1 0-3.414L4.39 8.61a1 1 0 0 1 1.68.474 2.5 2.5 0 1 0 3.014-3.015 1 1 0 0 1-.474-1.68l1.683-1.682a2.414 2.414 0 0 1 3.414 0z",key:"w46dr5"}]],b0=e("puzzle",H1);const S1=[["path",{d:"M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8",key:"v9h5vc"}],["path",{d:"M21 3v5h-5",key:"1q7to0"}],["path",{d:"M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16",key:"3uifl3"}],["path",{d:"M8 16H3v5",key:"1cv678"}]],q0=e("refresh-cw",S1);const P1=[["path",{d:"M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8",key:"1357e3"}],["path",{d:"M3 3v5h5",key:"1xhq8a"}]],C0=e("rotate-ccw",P1);const U1=[["path",{d:"M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8",key:"1p45f6"}],["path",{d:"M21 3v5h-5",key:"1q7to0"}]],j0=e("rotate-cw",U1);const R1=[["path",{d:"M15.2 3a2 2 0 0 1 1.4.6l3.8 3.8a2 2 0 0 1 .6 1.4V19a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2z",key:"1c8476"}],["path",{d:"M17 21v-7a1 1 0 0 0-1-1H8a1 1 0 0 0-1 1v7",key:"1ydtos"}],["path",{d:"M7 3v4a1 1 0 0 0 1 1h7",key:"t51u73"}]],V0=e("save",R1);const T1=[["path",{d:"m21 21-4.34-4.34",key:"14j7rj"}],["circle",{cx:"11",cy:"11",r:"8",key:"4ej97u"}]],A0=e("search",T1);const Z1=[["path",{d:"M14.536 21.686a.5.5 0 0 0 .937-.024l6.5-19a.496.496 0 0 0-.635-.635l-19 6.5a.5.5 0 0 0-.024.937l7.93 3.18a2 2 0 0 1 1.112 1.11z",key:"1ffxy3"}],["path",{d:"m21.854 2.147-10.94 10.939",key:"12cjpa"}]],L0=e("send",Z1);const B1=[["rect",{width:"20",height:"8",x:"2",y:"2",rx:"2",ry:"2",key:"ngkwjq"}],["rect",{width:"20",height:"8",x:"2",y:"14",rx:"2",ry:"2",key:"iecqi9"}],["line",{x1:"6",x2:"6.01",y1:"6",y2:"6",key:"16zg32"}],["line",{x1:"6",x2:"6.01",y1:"18",y2:"18",key:"nzw8ys"}]],H0=e("server",B1);const D1=[["path",{d:"M14 17H5",key:"gfn3mx"}],["path",{d:"M19 7h-9",key:"6i9tg"}],["circle",{cx:"17",cy:"17",r:"3",key:"18b49y"}],["circle",{cx:"7",cy:"7",r:"3",key:"dfmy0x"}]],S0=e("settings-2",D1);const E1=[["path",{d:"M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915",key:"1i5ecw"}],["circle",{cx:"12",cy:"12",r:"3",key:"1v7zrd"}]],P0=e("settings",E1);const F1=[["path",{d:"M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z",key:"oel41y"}]],U0=e("shield",F1);const O1=[["path",{d:"M21 4v16",key:"7j8fe9"}],["path",{d:"M6.029 4.285A2 2 0 0 0 3 6v12a2 2 0 0 0 3.029 1.715l9.997-5.998a2 2 0 0 0 .003-3.432z",key:"zs4d6"}]],R0=e("skip-forward",O1);const G1=[["path",{d:"M10 8h4",key:"1sr2af"}],["path",{d:"M12 21v-9",key:"17s77i"}],["path",{d:"M12 8V3",key:"13r4qs"}],["path",{d:"M17 16h4",key:"h1uq16"}],["path",{d:"M19 12V3",key:"o1uvq1"}],["path",{d:"M19 21v-5",key:"qua636"}],["path",{d:"M3 14h4",key:"bcjad9"}],["path",{d:"M5 10V3",key:"cb8scm"}],["path",{d:"M5 21v-7",key:"1w1uti"}]],T0=e("sliders-vertical",G1);const I1=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"M8 14s1.5 2 4 2 4-2 4-2",key:"1y1vjs"}],["line",{x1:"9",x2:"9.01",y1:"9",y2:"9",key:"yxxnd0"}],["line",{x1:"15",x2:"15.01",y1:"9",y2:"9",key:"1p4y9e"}]],Z0=e("smile",I1);const W1=[["path",{d:"M11.017 2.814a1 1 0 0 1 1.966 0l1.051 5.558a2 2 0 0 0 1.594 1.594l5.558 1.051a1 1 0 0 1 0 1.966l-5.558 1.051a2 2 0 0 0-1.594 1.594l-1.051 5.558a1 1 0 0 1-1.966 0l-1.051-5.558a2 2 0 0 0-1.594-1.594l-5.558-1.051a1 1 0 0 1 0-1.966l5.558-1.051a2 2 0 0 0 1.594-1.594z",key:"1s2grr"}],["path",{d:"M20 2v4",key:"1rf3ol"}],["path",{d:"M22 4h-4",key:"gwowj6"}],["circle",{cx:"4",cy:"20",r:"2",key:"6kqj1y"}]],B0=e("sparkles",W1);const K1=[["path",{d:"M12 3H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7",key:"1m0v6g"}],["path",{d:"M18.375 2.625a1 1 0 0 1 3 3l-9.013 9.014a2 2 0 0 1-.853.505l-2.873.84a.5.5 0 0 1-.62-.62l.84-2.873a2 2 0 0 1 .506-.852z",key:"ohrbg2"}]],D0=e("square-pen",K1);const Q1=[["path",{d:"M11.525 2.295a.53.53 0 0 1 .95 0l2.31 4.679a2.123 2.123 0 0 0 1.595 1.16l5.166.756a.53.53 0 0 1 .294.904l-3.736 3.638a2.123 2.123 0 0 0-.611 1.878l.882 5.14a.53.53 0 0 1-.771.56l-4.618-2.428a2.122 2.122 0 0 0-1.973 0L6.396 21.01a.53.53 0 0 1-.77-.56l.881-5.139a2.122 2.122 0 0 0-.611-1.879L2.16 9.795a.53.53 0 0 1 .294-.906l5.165-.755a2.122 2.122 0 0 0 1.597-1.16z",key:"r04s7s"}]],E0=e("star",Q1);const X1=[["circle",{cx:"12",cy:"12",r:"4",key:"4exip2"}],["path",{d:"M12 2v2",key:"tus03m"}],["path",{d:"M12 20v2",key:"1lh1kg"}],["path",{d:"m4.93 4.93 1.41 1.41",key:"149t6j"}],["path",{d:"m17.66 17.66 1.41 1.41",key:"ptbguv"}],["path",{d:"M2 12h2",key:"1t8f8n"}],["path",{d:"M20 12h2",key:"1q8mjw"}],["path",{d:"m6.34 17.66-1.41 1.41",key:"1m8zz5"}],["path",{d:"m19.07 4.93-1.41 1.41",key:"1shlcs"}]],F0=e("sun",X1);const J1=[["path",{d:"M12 19h8",key:"baeox8"}],["path",{d:"m4 17 6-6-6-6",key:"1yngyt"}]],O0=e("terminal",J1);const Y1=[["path",{d:"M17 14V2",key:"8ymqnk"}],["path",{d:"M9 18.12 10 14H4.17a2 2 0 0 1-1.92-2.56l2.33-8A2 2 0 0 1 6.5 2H20a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2h-2.76a2 2 0 0 0-1.79 1.11L12 22a3.13 3.13 0 0 1-3-3.88Z",key:"m61m77"}]],G0=e("thumbs-down",Y1);const e2=[["path",{d:"M7 10v12",key:"1qc93n"}],["path",{d:"M15 5.88 14 10h5.83a2 2 0 0 1 1.92 2.56l-2.33 8A2 2 0 0 1 17.5 22H4a2 2 0 0 1-2-2v-8a2 2 0 0 1 2-2h2.76a2 2 0 0 0 1.79-1.11L12 2a3.13 3.13 0 0 1 3 3.88Z",key:"emmmcr"}]],I0=e("thumbs-up",e2);const a2=[["path",{d:"M10 11v6",key:"nco0om"}],["path",{d:"M14 11v6",key:"outv1u"}],["path",{d:"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6",key:"miytrc"}],["path",{d:"M3 6h18",key:"d0wm0j"}],["path",{d:"M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2",key:"e791ji"}]],W0=e("trash-2",a2);const t2=[["path",{d:"M16 7h6v6",key:"box55l"}],["path",{d:"m22 7-8.5 8.5-5-5L2 17",key:"1t1m79"}]],K0=e("trending-up",t2);const c2=[["path",{d:"m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3",key:"wmoenq"}],["path",{d:"M12 9v4",key:"juzpu7"}],["path",{d:"M12 17h.01",key:"p32p05"}]],Q0=e("triangle-alert",c2);const o2=[["path",{d:"M12 4v16",key:"1654pz"}],["path",{d:"M4 7V5a1 1 0 0 1 1-1h14a1 1 0 0 1 1 1v2",key:"e0r10z"}],["path",{d:"M9 20h6",key:"s66wpe"}]],X0=e("type",o2);const n2=[["path",{d:"M12 3v12",key:"1x0j5s"}],["path",{d:"m17 8-5-5-5 5",key:"7q97r8"}],["path",{d:"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4",key:"ih7n3h"}]],J0=e("upload",n2);const s2=[["path",{d:"M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2",key:"975kel"}],["circle",{cx:"12",cy:"7",r:"4",key:"17ys0d"}]],Y0=e("user",s2);const y2=[["path",{d:"M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2",key:"1yyitq"}],["path",{d:"M16 3.128a4 4 0 0 1 0 7.744",key:"16gr8j"}],["path",{d:"M22 21v-2a4 4 0 0 0-3-3.87",key:"kshegd"}],["circle",{cx:"9",cy:"7",r:"4",key:"nufk8"}]],ee=e("users",y2);const h2=[["path",{d:"M12 20h.01",key:"zekei9"}],["path",{d:"M8.5 16.429a5 5 0 0 1 7 0",key:"1bycff"}],["path",{d:"M5 12.859a10 10 0 0 1 5.17-2.69",key:"1dl1wf"}],["path",{d:"M19 12.859a10 10 0 0 0-2.007-1.523",key:"4k23kn"}],["path",{d:"M2 8.82a15 15 0 0 1 4.177-2.643",key:"1grhjp"}],["path",{d:"M22 8.82a15 15 0 0 0-11.288-3.764",key:"z3jwby"}],["path",{d:"m2 2 20 20",key:"1ooewy"}]],ae=e("wifi-off",h2);const d2=[["path",{d:"M12 20h.01",key:"zekei9"}],["path",{d:"M2 8.82a15 15 0 0 1 20 0",key:"dnpr2z"}],["path",{d:"M5 12.859a10 10 0 0 1 14 0",key:"1x1e6c"}],["path",{d:"M8.5 16.429a5 5 0 0 1 7 0",key:"1bycff"}]],te=e("wifi",d2);const r2=[["path",{d:"M18 6 6 18",key:"1bl5f8"}],["path",{d:"m6 6 12 12",key:"d8bk6v"}]],ce=e("x",r2);const k2=[["path",{d:"M4 14a1 1 0 0 1-.78-1.63l9.9-10.2a.5.5 0 0 1 .86.46l-1.92 6.02A1 1 0 0 0 13 10h7a1 1 0 0 1 .78 1.63l-9.9 10.2a.5.5 0 0 1-.86-.46l1.92-6.02A1 1 0 0 0 11 14z",key:"1xq2db"}]],oe=e("zap",k2);export{g0 as $,p2 as A,m2 as B,V2 as C,F2 as D,I2 as E,X2 as F,A0 as G,c0 as H,y0 as I,n0 as J,h0 as K,r0 as L,_0 as M,l2 as N,w0 as O,z0 as P,N2 as Q,q0 as R,P0 as S,K0 as T,J0 as U,b2 as V,Q2 as W,ce as X,t0 as Y,oe as Z,V0 as _,C0 as a,Z2 as a0,$0 as a1,q2 as a2,w2 as a3,z2 as a4,C2 as a5,j2 as a6,a0 as a7,B2 as a8,m0 as a9,K2 as aA,H0 as aB,v2 as aC,S2 as aD,f2 as aE,T0 as aF,p0 as aG,x2 as aH,i0 as aI,g2 as aJ,J2 as aa,s0 as ab,Y2 as ac,D0 as ad,M2 as ae,o0 as af,l0 as ag,e0 as ah,ee as ai,x0 as aj,u0 as ak,N0 as al,u2 as am,X0 as an,E0 as ao,I0 as ap,G0 as aq,j0 as ar,S0 as as,d0 as at,H2 as au,te as av,ae as aw,f0 as ax,L0 as ay,U2 as az,A2 as b,b0 as c,R2 as d,E2 as e,T2 as f,v0 as g,U0 as h,Q0 as i,$2 as j,D2 as k,W2 as l,P2 as m,W0 as n,O2 as o,F0 as p,M0 as q,k0 as r,L2 as s,O0 as t,G2 as u,B0 as v,Y0 as w,Z0 as x,R0 as y,_2 as z}; diff --git a/webui/dist/assets/icons-CwAZotQh.js b/webui/dist/assets/icons-CwAZotQh.js deleted file mode 100644 index f0275a38..00000000 --- a/webui/dist/assets/icons-CwAZotQh.js +++ /dev/null @@ -1 +0,0 @@ -import{r as s}from"./router-Bz250laD.js";const _=t=>t.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase(),M=t=>t.replace(/^([A-Z])|[\s-_]+(\w)/g,(a,c,o)=>o?o.toUpperCase():c.toLowerCase()),d=t=>{const a=M(t);return a.charAt(0).toUpperCase()+a.slice(1)},r=(...t)=>t.filter((a,c,o)=>!!a&&a.trim()!==""&&o.indexOf(a)===c).join(" ").trim(),x=t=>{for(const a in t)if(a.startsWith("aria-")||a==="role"||a==="title")return!0};var m={xmlns:"http://www.w3.org/2000/svg",width:24,height:24,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"};const v=s.forwardRef(({color:t="currentColor",size:a=24,strokeWidth:c=2,absoluteStrokeWidth:o,className:y="",children:n,iconNode:k,...h},i)=>s.createElement("svg",{ref:i,...m,width:a,height:a,stroke:t,strokeWidth:o?Number(c)*24/Number(a):c,className:r("lucide",y),...!n&&!x(h)&&{"aria-hidden":"true"},...h},[...k.map(([p,l])=>s.createElement(p,l)),...Array.isArray(n)?n:[n]]));const e=(t,a)=>{const c=s.forwardRef(({className:o,...y},n)=>s.createElement(v,{ref:n,iconNode:a,className:r(`lucide-${_(d(t))}`,`lucide-${t}`,o),...y}));return c.displayName=d(t),c};const g=[["path",{d:"M22 12h-2.48a2 2 0 0 0-1.93 1.46l-2.35 8.36a.25.25 0 0 1-.48 0L9.24 2.18a.25.25 0 0 0-.48 0l-2.35 8.36A2 2 0 0 1 4.49 12H2",key:"169zse"}]],i2=e("activity",g);const u=[["path",{d:"m12 19-7-7 7-7",key:"1l729n"}],["path",{d:"M19 12H5",key:"x3x0zl"}]],p2=e("arrow-left",u);const f=[["path",{d:"M5 12h14",key:"1ays0h"}],["path",{d:"m12 5 7 7-7 7",key:"xquz4c"}]],l2=e("arrow-right",f);const $=[["path",{d:"M4.929 4.929 19.07 19.071",key:"196cmz"}],["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}]],_2=e("ban",$);const N=[["path",{d:"M12 7v14",key:"1akyts"}],["path",{d:"M3 18a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h5a4 4 0 0 1 4 4 4 4 0 0 1 4-4h5a1 1 0 0 1 1 1v13a1 1 0 0 1-1 1h-6a3 3 0 0 0-3 3 3 3 0 0 0-3-3z",key:"ruj8y"}]],M2=e("book-open",N);const w=[["path",{d:"M12 8V4H8",key:"hb8ula"}],["rect",{width:"16",height:"12",x:"4",y:"8",rx:"2",key:"enze0r"}],["path",{d:"M2 14h2",key:"vft8re"}],["path",{d:"M20 14h2",key:"4cs60a"}],["path",{d:"M15 13v2",key:"1xurst"}],["path",{d:"M9 13v2",key:"rq6x2g"}]],x2=e("bot",w);const z=[["path",{d:"M2.97 12.92A2 2 0 0 0 2 14.63v3.24a2 2 0 0 0 .97 1.71l3 1.8a2 2 0 0 0 2.06 0L12 19v-5.5l-5-3-4.03 2.42Z",key:"lc1i9w"}],["path",{d:"m7 16.5-4.74-2.85",key:"1o9zyk"}],["path",{d:"m7 16.5 5-3",key:"va8pkn"}],["path",{d:"M7 16.5v5.17",key:"jnp8gn"}],["path",{d:"M12 13.5V19l3.97 2.38a2 2 0 0 0 2.06 0l3-1.8a2 2 0 0 0 .97-1.71v-3.24a2 2 0 0 0-.97-1.71L17 10.5l-5 3Z",key:"8zsnat"}],["path",{d:"m17 16.5-5-3",key:"8arw3v"}],["path",{d:"m17 16.5 4.74-2.85",key:"8rfmw"}],["path",{d:"M17 16.5v5.17",key:"k6z78m"}],["path",{d:"M7.97 4.42A2 2 0 0 0 7 6.13v4.37l5 3 5-3V6.13a2 2 0 0 0-.97-1.71l-3-1.8a2 2 0 0 0-2.06 0l-3 1.8Z",key:"1xygjf"}],["path",{d:"M12 8 7.26 5.15",key:"1vbdud"}],["path",{d:"m12 8 4.74-2.85",key:"3rx089"}],["path",{d:"M12 13.5V8",key:"1io7kd"}]],m2=e("boxes",z);const b=[["path",{d:"M12 20v-9",key:"1qisl0"}],["path",{d:"M14 7a4 4 0 0 1 4 4v3a6 6 0 0 1-12 0v-3a4 4 0 0 1 4-4z",key:"uouzyp"}],["path",{d:"M14.12 3.88 16 2",key:"qol33r"}],["path",{d:"M21 21a4 4 0 0 0-3.81-4",key:"1b0z45"}],["path",{d:"M21 5a4 4 0 0 1-3.55 3.97",key:"5cxbf6"}],["path",{d:"M22 13h-4",key:"1jl80f"}],["path",{d:"M3 21a4 4 0 0 1 3.81-4",key:"1fjd4g"}],["path",{d:"M3 5a4 4 0 0 0 3.55 3.97",key:"1d7oge"}],["path",{d:"M6 13H2",key:"82j7cp"}],["path",{d:"m8 2 1.88 1.88",key:"fmnt4t"}],["path",{d:"M9 7.13V6a3 3 0 1 1 6 0v1.13",key:"1vgav8"}]],v2=e("bug",b);const q=[["path",{d:"M8 2v4",key:"1cmpym"}],["path",{d:"M16 2v4",key:"4m81vk"}],["rect",{width:"18",height:"18",x:"3",y:"4",rx:"2",key:"1hopcy"}],["path",{d:"M3 10h18",key:"8toen8"}]],g2=e("calendar",q);const j=[["path",{d:"M3 3v16a2 2 0 0 0 2 2h16",key:"c24i48"}],["path",{d:"M18 17V9",key:"2bz60n"}],["path",{d:"M13 17V5",key:"1frdt8"}],["path",{d:"M8 17v-3",key:"17ska0"}]],u2=e("chart-column",j);const C=[["path",{d:"M20 6 9 17l-5-5",key:"1gmf2c"}]],f2=e("check",C);const V=[["path",{d:"m6 9 6 6 6-6",key:"qrunsl"}]],$2=e("chevron-down",V);const A=[["path",{d:"m15 18-6-6 6-6",key:"1wnfg3"}]],N2=e("chevron-left",A);const H=[["path",{d:"m9 18 6-6-6-6",key:"mthhwq"}]],w2=e("chevron-right",H);const L=[["path",{d:"m18 15-6-6-6 6",key:"153udz"}]],z2=e("chevron-up",L);const S=[["path",{d:"m11 17-5-5 5-5",key:"13zhaf"}],["path",{d:"m18 17-5-5 5-5",key:"h8a8et"}]],b2=e("chevrons-left",S);const P=[["path",{d:"m6 17 5-5-5-5",key:"xnjwq"}],["path",{d:"m13 17 5-5-5-5",key:"17xmmf"}]],q2=e("chevrons-right",P);const U=[["path",{d:"m7 15 5 5 5-5",key:"1hf1tw"}],["path",{d:"m7 9 5-5 5 5",key:"sgt6xg"}]],j2=e("chevrons-up-down",U);const T=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["line",{x1:"12",x2:"12",y1:"8",y2:"12",key:"1pkeuh"}],["line",{x1:"12",x2:"12.01",y1:"16",y2:"16",key:"4dfq90"}]],C2=e("circle-alert",T);const Z=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"m9 12 2 2 4-4",key:"dzmm74"}]],V2=e("circle-check",Z);const B=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3",key:"1u773s"}],["path",{d:"M12 17h.01",key:"p32p05"}]],A2=e("circle-question-mark",B);const D=[["path",{d:"M18 20a6 6 0 0 0-12 0",key:"1qehca"}],["circle",{cx:"12",cy:"10",r:"4",key:"1h16sb"}],["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}]],H2=e("circle-user-round",D);const E=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["circle",{cx:"12",cy:"10",r:"3",key:"ilqhr7"}],["path",{d:"M7 20.662V19a2 2 0 0 1 2-2h6a2 2 0 0 1 2 2v1.662",key:"154egf"}]],L2=e("circle-user",E);const R=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"m15 9-6 6",key:"1uzhvr"}],["path",{d:"m9 9 6 6",key:"z0biqf"}]],S2=e("circle-x",R);const F=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}]],P2=e("circle",F);const O=[["rect",{width:"8",height:"4",x:"8",y:"2",rx:"1",ry:"1",key:"tgr4d6"}],["path",{d:"M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2",key:"116196"}],["path",{d:"M12 11h4",key:"1jrz19"}],["path",{d:"M12 16h4",key:"n85exb"}],["path",{d:"M8 11h.01",key:"1dfujw"}],["path",{d:"M8 16h.01",key:"18s6g9"}]],U2=e("clipboard-list",O);const G=[["path",{d:"M12 6v6l4 2",key:"mmk7yg"}],["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}]],T2=e("clock",G);const I=[["path",{d:"m18 16 4-4-4-4",key:"1inbqp"}],["path",{d:"m6 8-4 4 4 4",key:"15zrgr"}],["path",{d:"m14.5 4-5 16",key:"e7oirm"}]],Z2=e("code-xml",I);const W=[["path",{d:"M22 7.7c0-.6-.4-1.2-.8-1.5l-6.3-3.9a1.72 1.72 0 0 0-1.7 0l-10.3 6c-.5.2-.9.8-.9 1.4v6.6c0 .5.4 1.2.8 1.5l6.3 3.9a1.72 1.72 0 0 0 1.7 0l10.3-6c.5-.3.9-1 .9-1.5Z",key:"1t2lqe"}],["path",{d:"M10 21.9V14L2.1 9.1",key:"o7czzq"}],["path",{d:"m10 14 11.9-6.9",key:"zm5e20"}],["path",{d:"M14 19.8v-8.1",key:"159ecu"}],["path",{d:"M18 17.5V9.4",key:"11uown"}]],B2=e("container",W);const K=[["rect",{width:"14",height:"14",x:"8",y:"8",rx:"2",ry:"2",key:"17jyea"}],["path",{d:"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2",key:"zix9uf"}]],D2=e("copy",K);const Q=[["ellipse",{cx:"12",cy:"5",rx:"9",ry:"3",key:"msslwz"}],["path",{d:"M3 5V19A9 3 0 0 0 21 19V5",key:"1wlel7"}],["path",{d:"M3 12A9 3 0 0 0 21 12",key:"mv7ke4"}]],E2=e("database",Q);const X=[["line",{x1:"12",x2:"12",y1:"2",y2:"22",key:"7eqyqh"}],["path",{d:"M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6",key:"1b0p4s"}]],R2=e("dollar-sign",X);const J=[["path",{d:"M12 15V3",key:"m9g1x1"}],["path",{d:"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4",key:"ih7n3h"}],["path",{d:"m7 10 5 5 5-5",key:"brsn70"}]],F2=e("download",J);const Y=[["path",{d:"M15 3h6v6",key:"1q9fwt"}],["path",{d:"M10 14 21 3",key:"gplh6r"}],["path",{d:"M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6",key:"a6xqqp"}]],O2=e("external-link",Y);const e1=[["path",{d:"M10.733 5.076a10.744 10.744 0 0 1 11.205 6.575 1 1 0 0 1 0 .696 10.747 10.747 0 0 1-1.444 2.49",key:"ct8e1f"}],["path",{d:"M14.084 14.158a3 3 0 0 1-4.242-4.242",key:"151rxh"}],["path",{d:"M17.479 17.499a10.75 10.75 0 0 1-15.417-5.151 1 1 0 0 1 0-.696 10.75 10.75 0 0 1 4.446-5.143",key:"13bj9a"}],["path",{d:"m2 2 20 20",key:"1ooewy"}]],G2=e("eye-off",e1);const a1=[["path",{d:"M2.062 12.348a1 1 0 0 1 0-.696 10.75 10.75 0 0 1 19.876 0 1 1 0 0 1 0 .696 10.75 10.75 0 0 1-19.876 0",key:"1nclc0"}],["circle",{cx:"12",cy:"12",r:"3",key:"1v7zrd"}]],I2=e("eye",a1);const t1=[["path",{d:"M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z",key:"1oefj6"}],["path",{d:"M12 17h.01",key:"p32p05"}],["path",{d:"M9.1 9a3 3 0 0 1 5.82 1c0 2-3 3-3 3",key:"mhlwft"}]],W2=e("file-question-mark",t1);const c1=[["path",{d:"M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z",key:"1oefj6"}],["path",{d:"M14 2v5a1 1 0 0 0 1 1h5",key:"wfsgrz"}],["circle",{cx:"11.5",cy:"14.5",r:"2.5",key:"1bq0ko"}],["path",{d:"M13.3 16.3 15 18",key:"2quom7"}]],K2=e("file-search",c1);const o1=[["path",{d:"M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z",key:"1oefj6"}],["path",{d:"M14 2v5a1 1 0 0 0 1 1h5",key:"wfsgrz"}],["path",{d:"M10 9H8",key:"b1mrlr"}],["path",{d:"M16 13H8",key:"t4e002"}],["path",{d:"M16 17H8",key:"z1uh3a"}]],Q2=e("file-text",o1);const n1=[["path",{d:"m6 14 1.5-2.9A2 2 0 0 1 9.24 10H20a2 2 0 0 1 1.94 2.5l-1.54 6a2 2 0 0 1-1.95 1.5H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h3.9a2 2 0 0 1 1.69.9l.81 1.2a2 2 0 0 0 1.67.9H18a2 2 0 0 1 2 2v2",key:"usdka0"}]],X2=e("folder-open",n1);const s1=[["path",{d:"M10 20a1 1 0 0 0 .553.895l2 1A1 1 0 0 0 14 21v-7a2 2 0 0 1 .517-1.341L21.74 4.67A1 1 0 0 0 21 3H3a1 1 0 0 0-.742 1.67l7.225 7.989A2 2 0 0 1 10 14z",key:"sc7q7i"}]],J2=e("funnel",s1);const y1=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20",key:"13o1zl"}],["path",{d:"M2 12h20",key:"9i4pu4"}]],Y2=e("globe",y1);const h1=[["path",{d:"M21.42 10.922a1 1 0 0 0-.019-1.838L12.83 5.18a2 2 0 0 0-1.66 0L2.6 9.08a1 1 0 0 0 0 1.832l8.57 3.908a2 2 0 0 0 1.66 0z",key:"j76jl0"}],["path",{d:"M22 10v6",key:"1lu8f3"}],["path",{d:"M6 12.5V16a6 3 0 0 0 12 0v-3.5",key:"1r8lef"}]],e0=e("graduation-cap",h1);const d1=[["circle",{cx:"9",cy:"12",r:"1",key:"1vctgf"}],["circle",{cx:"9",cy:"5",r:"1",key:"hp0tcf"}],["circle",{cx:"9",cy:"19",r:"1",key:"fkjjf6"}],["circle",{cx:"15",cy:"12",r:"1",key:"1tmaij"}],["circle",{cx:"15",cy:"5",r:"1",key:"19l28e"}],["circle",{cx:"15",cy:"19",r:"1",key:"f4zoj3"}]],a0=e("grip-vertical",d1);const r1=[["line",{x1:"22",x2:"2",y1:"12",y2:"12",key:"1y58io"}],["path",{d:"M5.45 5.11 2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z",key:"oot6mr"}],["line",{x1:"6",x2:"6.01",y1:"16",y2:"16",key:"sgf278"}],["line",{x1:"10",x2:"10.01",y1:"16",y2:"16",key:"1l4acy"}]],t0=e("hard-drive",r1);const k1=[["line",{x1:"4",x2:"20",y1:"9",y2:"9",key:"4lhtct"}],["line",{x1:"4",x2:"20",y1:"15",y2:"15",key:"vyu0kd"}],["line",{x1:"10",x2:"8",y1:"3",y2:"21",key:"1ggp8o"}],["line",{x1:"16",x2:"14",y1:"3",y2:"21",key:"weycgp"}]],c0=e("hash",k1);const i1=[["path",{d:"M15 21v-8a1 1 0 0 0-1-1h-4a1 1 0 0 0-1 1v8",key:"5wwlr5"}],["path",{d:"M3 10a2 2 0 0 1 .709-1.528l7-6a2 2 0 0 1 2.582 0l7 6A2 2 0 0 1 21 10v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z",key:"r6nss1"}]],o0=e("house",i1);const p1=[["rect",{width:"18",height:"18",x:"3",y:"3",rx:"2",ry:"2",key:"1m3agn"}],["circle",{cx:"9",cy:"9",r:"2",key:"af1f0g"}],["path",{d:"m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21",key:"1xmnt7"}]],n0=e("image",p1);const l1=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"M12 16v-4",key:"1dtifu"}],["path",{d:"M12 8h.01",key:"e9boi3"}]],s0=e("info",l1);const _1=[["path",{d:"m15.5 7.5 2.3 2.3a1 1 0 0 0 1.4 0l2.1-2.1a1 1 0 0 0 0-1.4L19 4",key:"g0fldk"}],["path",{d:"m21 2-9.6 9.6",key:"1j0ho8"}],["circle",{cx:"7.5",cy:"15.5",r:"5.5",key:"yqb3hr"}]],y0=e("key",_1);const M1=[["rect",{width:"7",height:"7",x:"3",y:"3",rx:"1",key:"1g98yp"}],["rect",{width:"7",height:"7",x:"14",y:"3",rx:"1",key:"6d4xhi"}],["rect",{width:"7",height:"7",x:"14",y:"14",rx:"1",key:"nxv5o0"}],["rect",{width:"7",height:"7",x:"3",y:"14",rx:"1",key:"1bb6yr"}]],h0=e("layout-grid",M1);const x1=[["path",{d:"M21 12a9 9 0 1 1-6.219-8.56",key:"13zald"}]],d0=e("loader-circle",x1);const m1=[["rect",{width:"18",height:"11",x:"3",y:"11",rx:"2",ry:"2",key:"1w4ew1"}],["path",{d:"M7 11V7a5 5 0 0 1 10 0v4",key:"fwvmzm"}]],r0=e("lock",m1);const v1=[["path",{d:"m16 17 5-5-5-5",key:"1bji2h"}],["path",{d:"M21 12H9",key:"dn1m92"}],["path",{d:"M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4",key:"1uf3rs"}]],k0=e("log-out",v1);const g1=[["path",{d:"M4 5h16",key:"1tepv9"}],["path",{d:"M4 12h16",key:"1lakjw"}],["path",{d:"M4 19h16",key:"1djgab"}]],i0=e("menu",g1);const u1=[["path",{d:"M2.992 16.342a2 2 0 0 1 .094 1.167l-1.065 3.29a1 1 0 0 0 1.236 1.168l3.413-.998a2 2 0 0 1 1.099.092 10 10 0 1 0-4.777-4.719",key:"1sd12s"}]],p0=e("message-circle",u1);const f1=[["path",{d:"M22 17a2 2 0 0 1-2 2H6.828a2 2 0 0 0-1.414.586l-2.202 2.202A.71.71 0 0 1 2 21.286V5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2z",key:"18887p"}]],l0=e("message-square",f1);const $1=[["path",{d:"M20.985 12.486a9 9 0 1 1-9.473-9.472c.405-.022.617.46.402.803a6 6 0 0 0 8.268 8.268c.344-.215.825-.004.803.401",key:"kfwtm"}]],_0=e("moon",$1);const N1=[["rect",{x:"16",y:"16",width:"6",height:"6",rx:"1",key:"4q2zg0"}],["rect",{x:"2",y:"16",width:"6",height:"6",rx:"1",key:"8cvhb9"}],["rect",{x:"9",y:"2",width:"6",height:"6",rx:"1",key:"1egb70"}],["path",{d:"M5 16v-3a1 1 0 0 1 1-1h12a1 1 0 0 1 1 1v3",key:"1jsf9p"}],["path",{d:"M12 12V8",key:"2874zd"}]],M0=e("network",N1);const w1=[["path",{d:"M11 21.73a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73z",key:"1a0edw"}],["path",{d:"M12 22V12",key:"d0xqtd"}],["polyline",{points:"3.29 7 12 12 20.71 7",key:"ousv84"}],["path",{d:"m7.5 4.27 9 5.15",key:"1c824w"}]],x0=e("package",w1);const z1=[["path",{d:"M12 22a1 1 0 0 1 0-20 10 9 0 0 1 10 9 5 5 0 0 1-5 5h-2.25a1.75 1.75 0 0 0-1.4 2.8l.3.4a1.75 1.75 0 0 1-1.4 2.8z",key:"e79jfc"}],["circle",{cx:"13.5",cy:"6.5",r:".5",fill:"currentColor",key:"1okk4w"}],["circle",{cx:"17.5",cy:"10.5",r:".5",fill:"currentColor",key:"f64h9f"}],["circle",{cx:"6.5",cy:"12.5",r:".5",fill:"currentColor",key:"qy21gx"}],["circle",{cx:"8.5",cy:"7.5",r:".5",fill:"currentColor",key:"fotxhn"}]],m0=e("palette",z1);const b1=[["rect",{width:"18",height:"18",x:"3",y:"3",rx:"2",key:"afitv7"}],["path",{d:"M3 9h18",key:"1pudct"}],["path",{d:"M9 21V9",key:"1oto5p"}]],v0=e("panels-top-left",b1);const q1=[["rect",{x:"14",y:"3",width:"5",height:"18",rx:"1",key:"kaeet6"}],["rect",{x:"5",y:"3",width:"5",height:"18",rx:"1",key:"1wsw3u"}]],g0=e("pause",q1);const j1=[["path",{d:"M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z",key:"1a8usu"}]],u0=e("pen",j1);const C1=[["path",{d:"M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z",key:"1a8usu"}],["path",{d:"m15 5 4 4",key:"1mk7zo"}]],f0=e("pencil",C1);const V1=[["path",{d:"M5 5a2 2 0 0 1 3.008-1.728l11.997 6.998a2 2 0 0 1 .003 3.458l-12 7A2 2 0 0 1 5 19z",key:"10ikf1"}]],$0=e("play",V1);const A1=[["path",{d:"M5 12h14",key:"1ays0h"}],["path",{d:"M12 5v14",key:"s699le"}]],N0=e("plus",A1);const H1=[["path",{d:"M12 2v10",key:"mnfbl"}],["path",{d:"M18.4 6.6a9 9 0 1 1-12.77.04",key:"obofu9"}]],w0=e("power",H1);const L1=[["path",{d:"M15.39 4.39a1 1 0 0 0 1.68-.474 2.5 2.5 0 1 1 3.014 3.015 1 1 0 0 0-.474 1.68l1.683 1.682a2.414 2.414 0 0 1 0 3.414L19.61 15.39a1 1 0 0 1-1.68-.474 2.5 2.5 0 1 0-3.014 3.015 1 1 0 0 1 .474 1.68l-1.683 1.682a2.414 2.414 0 0 1-3.414 0L8.61 19.61a1 1 0 0 0-1.68.474 2.5 2.5 0 1 1-3.014-3.015 1 1 0 0 0 .474-1.68l-1.683-1.682a2.414 2.414 0 0 1 0-3.414L4.39 8.61a1 1 0 0 1 1.68.474 2.5 2.5 0 1 0 3.014-3.015 1 1 0 0 1-.474-1.68l1.683-1.682a2.414 2.414 0 0 1 3.414 0z",key:"w46dr5"}]],z0=e("puzzle",L1);const S1=[["path",{d:"M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8",key:"v9h5vc"}],["path",{d:"M21 3v5h-5",key:"1q7to0"}],["path",{d:"M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16",key:"3uifl3"}],["path",{d:"M8 16H3v5",key:"1cv678"}]],b0=e("refresh-cw",S1);const P1=[["path",{d:"M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8",key:"1357e3"}],["path",{d:"M3 3v5h5",key:"1xhq8a"}]],q0=e("rotate-ccw",P1);const U1=[["path",{d:"M15.2 3a2 2 0 0 1 1.4.6l3.8 3.8a2 2 0 0 1 .6 1.4V19a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2z",key:"1c8476"}],["path",{d:"M17 21v-7a1 1 0 0 0-1-1H8a1 1 0 0 0-1 1v7",key:"1ydtos"}],["path",{d:"M7 3v4a1 1 0 0 0 1 1h7",key:"t51u73"}]],j0=e("save",U1);const T1=[["path",{d:"m21 21-4.34-4.34",key:"14j7rj"}],["circle",{cx:"11",cy:"11",r:"8",key:"4ej97u"}]],C0=e("search",T1);const Z1=[["path",{d:"M14.536 21.686a.5.5 0 0 0 .937-.024l6.5-19a.496.496 0 0 0-.635-.635l-19 6.5a.5.5 0 0 0-.024.937l7.93 3.18a2 2 0 0 1 1.112 1.11z",key:"1ffxy3"}],["path",{d:"m21.854 2.147-10.94 10.939",key:"12cjpa"}]],V0=e("send",Z1);const B1=[["rect",{width:"20",height:"8",x:"2",y:"2",rx:"2",ry:"2",key:"ngkwjq"}],["rect",{width:"20",height:"8",x:"2",y:"14",rx:"2",ry:"2",key:"iecqi9"}],["line",{x1:"6",x2:"6.01",y1:"6",y2:"6",key:"16zg32"}],["line",{x1:"6",x2:"6.01",y1:"18",y2:"18",key:"nzw8ys"}]],A0=e("server",B1);const D1=[["path",{d:"M14 17H5",key:"gfn3mx"}],["path",{d:"M19 7h-9",key:"6i9tg"}],["circle",{cx:"17",cy:"17",r:"3",key:"18b49y"}],["circle",{cx:"7",cy:"7",r:"3",key:"dfmy0x"}]],H0=e("settings-2",D1);const E1=[["path",{d:"M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915",key:"1i5ecw"}],["circle",{cx:"12",cy:"12",r:"3",key:"1v7zrd"}]],L0=e("settings",E1);const R1=[["path",{d:"M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z",key:"oel41y"}]],S0=e("shield",R1);const F1=[["path",{d:"M21 4v16",key:"7j8fe9"}],["path",{d:"M6.029 4.285A2 2 0 0 0 3 6v12a2 2 0 0 0 3.029 1.715l9.997-5.998a2 2 0 0 0 .003-3.432z",key:"zs4d6"}]],P0=e("skip-forward",F1);const O1=[["path",{d:"M10 8h4",key:"1sr2af"}],["path",{d:"M12 21v-9",key:"17s77i"}],["path",{d:"M12 8V3",key:"13r4qs"}],["path",{d:"M17 16h4",key:"h1uq16"}],["path",{d:"M19 12V3",key:"o1uvq1"}],["path",{d:"M19 21v-5",key:"qua636"}],["path",{d:"M3 14h4",key:"bcjad9"}],["path",{d:"M5 10V3",key:"cb8scm"}],["path",{d:"M5 21v-7",key:"1w1uti"}]],U0=e("sliders-vertical",O1);const G1=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"M8 14s1.5 2 4 2 4-2 4-2",key:"1y1vjs"}],["line",{x1:"9",x2:"9.01",y1:"9",y2:"9",key:"yxxnd0"}],["line",{x1:"15",x2:"15.01",y1:"9",y2:"9",key:"1p4y9e"}]],T0=e("smile",G1);const I1=[["path",{d:"M11.017 2.814a1 1 0 0 1 1.966 0l1.051 5.558a2 2 0 0 0 1.594 1.594l5.558 1.051a1 1 0 0 1 0 1.966l-5.558 1.051a2 2 0 0 0-1.594 1.594l-1.051 5.558a1 1 0 0 1-1.966 0l-1.051-5.558a2 2 0 0 0-1.594-1.594l-5.558-1.051a1 1 0 0 1 0-1.966l5.558-1.051a2 2 0 0 0 1.594-1.594z",key:"1s2grr"}],["path",{d:"M20 2v4",key:"1rf3ol"}],["path",{d:"M22 4h-4",key:"gwowj6"}],["circle",{cx:"4",cy:"20",r:"2",key:"6kqj1y"}]],Z0=e("sparkles",I1);const W1=[["path",{d:"M12 3H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7",key:"1m0v6g"}],["path",{d:"M18.375 2.625a1 1 0 0 1 3 3l-9.013 9.014a2 2 0 0 1-.853.505l-2.873.84a.5.5 0 0 1-.62-.62l.84-2.873a2 2 0 0 1 .506-.852z",key:"ohrbg2"}]],B0=e("square-pen",W1);const K1=[["path",{d:"M11.525 2.295a.53.53 0 0 1 .95 0l2.31 4.679a2.123 2.123 0 0 0 1.595 1.16l5.166.756a.53.53 0 0 1 .294.904l-3.736 3.638a2.123 2.123 0 0 0-.611 1.878l.882 5.14a.53.53 0 0 1-.771.56l-4.618-2.428a2.122 2.122 0 0 0-1.973 0L6.396 21.01a.53.53 0 0 1-.77-.56l.881-5.139a2.122 2.122 0 0 0-.611-1.879L2.16 9.795a.53.53 0 0 1 .294-.906l5.165-.755a2.122 2.122 0 0 0 1.597-1.16z",key:"r04s7s"}]],D0=e("star",K1);const Q1=[["circle",{cx:"12",cy:"12",r:"4",key:"4exip2"}],["path",{d:"M12 2v2",key:"tus03m"}],["path",{d:"M12 20v2",key:"1lh1kg"}],["path",{d:"m4.93 4.93 1.41 1.41",key:"149t6j"}],["path",{d:"m17.66 17.66 1.41 1.41",key:"ptbguv"}],["path",{d:"M2 12h2",key:"1t8f8n"}],["path",{d:"M20 12h2",key:"1q8mjw"}],["path",{d:"m6.34 17.66-1.41 1.41",key:"1m8zz5"}],["path",{d:"m19.07 4.93-1.41 1.41",key:"1shlcs"}]],E0=e("sun",Q1);const X1=[["path",{d:"M12 19h8",key:"baeox8"}],["path",{d:"m4 17 6-6-6-6",key:"1yngyt"}]],R0=e("terminal",X1);const J1=[["path",{d:"M17 14V2",key:"8ymqnk"}],["path",{d:"M9 18.12 10 14H4.17a2 2 0 0 1-1.92-2.56l2.33-8A2 2 0 0 1 6.5 2H20a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2h-2.76a2 2 0 0 0-1.79 1.11L12 22a3.13 3.13 0 0 1-3-3.88Z",key:"m61m77"}]],F0=e("thumbs-down",J1);const Y1=[["path",{d:"M7 10v12",key:"1qc93n"}],["path",{d:"M15 5.88 14 10h5.83a2 2 0 0 1 1.92 2.56l-2.33 8A2 2 0 0 1 17.5 22H4a2 2 0 0 1-2-2v-8a2 2 0 0 1 2-2h2.76a2 2 0 0 0 1.79-1.11L12 2a3.13 3.13 0 0 1 3 3.88Z",key:"emmmcr"}]],O0=e("thumbs-up",Y1);const e2=[["path",{d:"M10 11v6",key:"nco0om"}],["path",{d:"M14 11v6",key:"outv1u"}],["path",{d:"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6",key:"miytrc"}],["path",{d:"M3 6h18",key:"d0wm0j"}],["path",{d:"M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2",key:"e791ji"}]],G0=e("trash-2",e2);const a2=[["path",{d:"M16 7h6v6",key:"box55l"}],["path",{d:"m22 7-8.5 8.5-5-5L2 17",key:"1t1m79"}]],I0=e("trending-up",a2);const t2=[["path",{d:"m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3",key:"wmoenq"}],["path",{d:"M12 9v4",key:"juzpu7"}],["path",{d:"M12 17h.01",key:"p32p05"}]],W0=e("triangle-alert",t2);const c2=[["path",{d:"M12 4v16",key:"1654pz"}],["path",{d:"M4 7V5a1 1 0 0 1 1-1h14a1 1 0 0 1 1 1v2",key:"e0r10z"}],["path",{d:"M9 20h6",key:"s66wpe"}]],K0=e("type",c2);const o2=[["path",{d:"M12 3v12",key:"1x0j5s"}],["path",{d:"m17 8-5-5-5 5",key:"7q97r8"}],["path",{d:"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4",key:"ih7n3h"}]],Q0=e("upload",o2);const n2=[["path",{d:"M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2",key:"975kel"}],["circle",{cx:"12",cy:"7",r:"4",key:"17ys0d"}]],X0=e("user",n2);const s2=[["path",{d:"M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2",key:"1yyitq"}],["path",{d:"M16 3.128a4 4 0 0 1 0 7.744",key:"16gr8j"}],["path",{d:"M22 21v-2a4 4 0 0 0-3-3.87",key:"kshegd"}],["circle",{cx:"9",cy:"7",r:"4",key:"nufk8"}]],J0=e("users",s2);const y2=[["path",{d:"M12 20h.01",key:"zekei9"}],["path",{d:"M8.5 16.429a5 5 0 0 1 7 0",key:"1bycff"}],["path",{d:"M5 12.859a10 10 0 0 1 5.17-2.69",key:"1dl1wf"}],["path",{d:"M19 12.859a10 10 0 0 0-2.007-1.523",key:"4k23kn"}],["path",{d:"M2 8.82a15 15 0 0 1 4.177-2.643",key:"1grhjp"}],["path",{d:"M22 8.82a15 15 0 0 0-11.288-3.764",key:"z3jwby"}],["path",{d:"m2 2 20 20",key:"1ooewy"}]],Y0=e("wifi-off",y2);const h2=[["path",{d:"M12 20h.01",key:"zekei9"}],["path",{d:"M2 8.82a15 15 0 0 1 20 0",key:"dnpr2z"}],["path",{d:"M5 12.859a10 10 0 0 1 14 0",key:"1x1e6c"}],["path",{d:"M8.5 16.429a5 5 0 0 1 7 0",key:"1bycff"}]],ee=e("wifi",h2);const d2=[["path",{d:"M18 6 6 18",key:"1bl5f8"}],["path",{d:"m6 6 12 12",key:"d8bk6v"}]],ae=e("x",d2);const r2=[["path",{d:"M4 14a1 1 0 0 1-.78-1.63l9.9-10.2a.5.5 0 0 1 .86.46l-1.92 6.02A1 1 0 0 0 13 10h7a1 1 0 0 1 .78 1.63l-9.9 10.2a.5.5 0 0 1-.86-.46l1.92-6.02A1 1 0 0 0 11 14z",key:"1xq2db"}]],te=e("zap",r2);export{Z2 as $,i2 as A,x2 as B,V2 as C,R2 as D,G2 as E,Q2 as F,C0 as G,t0 as H,s0 as I,o0 as J,y0 as K,r0 as L,l0 as M,p2 as N,N0 as O,w0 as P,$2 as Q,b0 as R,L0 as S,I0 as T,Q0 as U,z2 as V,K2 as W,ae as X,j0 as Y,te as Z,v0 as _,C2 as a,f0 as a0,b2 as a1,N2 as a2,w2 as a3,q2 as a4,j2 as a5,a0 as a6,e0 as a7,B2 as a8,x0 as a9,A0 as aA,m2 as aB,L2 as aC,u2 as aD,U0 as aE,i0 as aF,M2 as aG,k0 as aH,v2 as aI,X2 as aa,n0 as ab,J2 as ac,B0 as ad,_2 as ae,c0 as af,p0 as ag,Y2 as ah,J0 as ai,M0 as aj,g2 as ak,g0 as al,$0 as am,K0 as an,D0 as ao,O0 as ap,F0 as aq,H0 as ar,h0 as as,H2 as at,ee as au,Y0 as av,u0 as aw,V0 as ax,P2 as ay,W2 as az,q0 as b,z0 as c,U2 as d,E2 as e,T2 as f,m0 as g,S0 as h,W0 as i,f2 as j,D2 as k,I2 as l,S2 as m,G0 as n,F2 as o,E0 as p,_0 as q,A2 as r,R0 as s,O2 as t,d0 as u,Z0 as v,X0 as w,T0 as x,P0 as y,l2 as z}; diff --git a/webui/dist/assets/index-CJYRKPEp.css b/webui/dist/assets/index-CJYRKPEp.css new file mode 100644 index 00000000..709e48ab --- /dev/null +++ b/webui/dist/assets/index-CJYRKPEp.css @@ -0,0 +1 @@ +@charset "UTF-8";*,:before,:after{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}:before,:after{--tw-content: ""}html,:host{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}:root{--background: 0 0% 100%;--foreground: 222.2 84% 4.9%;--card: 0 0% 100%;--card-foreground: 222.2 84% 4.9%;--popover: 0 0% 100%;--popover-foreground: 222.2 84% 4.9%;--primary: 221.2 83.2% 53.3%;--primary-foreground: 210 40% 98%;--primary-gradient: none;--secondary: 210 40% 96.1%;--secondary-foreground: 222.2 47.4% 11.2%;--muted: 210 40% 96.1%;--muted-foreground: 215.4 16.3% 46.9%;--accent: 210 40% 96.1%;--accent-foreground: 222.2 47.4% 11.2%;--destructive: 0 84.2% 60.2%;--destructive-foreground: 210 40% 98%;--border: 214.3 31.8% 91.4%;--input: 214.3 31.8% 91.4%;--ring: 221.2 83.2% 53.3%;--radius: .5rem;--chart-1: 221.2 83.2% 53.3%;--chart-2: 160 60% 45%;--chart-3: 30 80% 55%;--chart-4: 280 65% 60%;--chart-5: 340 75% 55%}.dark{--background: 222.2 84% 4.9%;--foreground: 210 40% 98%;--card: 222.2 84% 4.9%;--card-foreground: 210 40% 98%;--popover: 222.2 84% 4.9%;--popover-foreground: 210 40% 98%;--primary: 217.2 91.2% 59.8%;--primary-foreground: 222.2 47.4% 11.2%;--primary-gradient: none;--secondary: 217.2 32.6% 17.5%;--secondary-foreground: 210 40% 98%;--muted: 217.2 32.6% 17.5%;--muted-foreground: 215 20.2% 65.1%;--accent: 217.2 32.6% 17.5%;--accent-foreground: 210 40% 98%;--destructive: 0 62.8% 30.6%;--destructive-foreground: 210 40% 98%;--border: 217.2 32.6% 17.5%;--input: 217.2 32.6% 17.5%;--ring: 224.3 76.3% 48%;--chart-1: 217.2 91.2% 59.8%;--chart-2: 160 60% 50%;--chart-3: 30 80% 60%;--chart-4: 280 65% 65%;--chart-5: 340 75% 60%}*{border-color:hsl(var(--border))}body{background-color:hsl(var(--background));color:hsl(var(--foreground))}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{-webkit-appearance:none;margin:0}input[type=number]{-moz-appearance:textfield;-webkit-appearance:textfield;appearance:textfield}.\!container{width:100%!important}.container{width:100%}@media(min-width:640px){.\!container{max-width:640px!important}.container{max-width:640px}}@media(min-width:768px){.\!container{max-width:768px!important}.container{max-width:768px}}@media(min-width:1024px){.\!container{max-width:1024px!important}.container{max-width:1024px}}@media(min-width:1280px){.\!container{max-width:1280px!important}.container{max-width:1280px}}@media(min-width:1536px){.\!container{max-width:1536px!important}.container{max-width:1536px}}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.pointer-events-none{pointer-events:none}.pointer-events-auto{pointer-events:auto}.visible{visibility:visible}.invisible{visibility:hidden}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{inset:0}.inset-16{inset:4rem}.inset-8{inset:2rem}.inset-x-0{left:0;right:0}.inset-y-0{top:0;bottom:0}.bottom-0{bottom:0}.bottom-1\/4{bottom:25%}.bottom-4{bottom:1rem}.left-0{left:0}.left-1{left:.25rem}.left-1\/2{left:50%}.left-1\/4{left:25%}.left-2{left:.5rem}.left-2\.5{left:.625rem}.left-3{left:.75rem}.left-\[50\%\]{left:50%}.right-0{right:0}.right-1{right:.25rem}.right-1\.5{right:.375rem}.right-1\/3{right:33.333333%}.right-1\/4{right:25%}.right-2{right:.5rem}.right-4{right:1rem}.top-0{top:0}.top-1{top:.25rem}.top-1\.5{top:.375rem}.top-1\/2{top:50%}.top-1\/4{top:25%}.top-2{top:.5rem}.top-2\.5{top:.625rem}.top-3{top:.75rem}.top-3\/4{top:75%}.top-4{top:1rem}.top-\[50\%\]{top:50%}.z-10{z-index:10}.z-40{z-index:40}.z-50{z-index:50}.z-\[100\]{z-index:100}.order-1{order:1}.order-2{order:2}.col-span-2{grid-column:span 2 / span 2}.-mx-1{margin-left:-.25rem;margin-right:-.25rem}.-mx-4{margin-left:-1rem;margin-right:-1rem}.mx-1{margin-left:.25rem;margin-right:.25rem}.mx-2{margin-left:.5rem;margin-right:.5rem}.mx-4{margin-left:1rem;margin-right:1rem}.mx-auto{margin-left:auto;margin-right:auto}.my-0\.5{margin-top:.125rem;margin-bottom:.125rem}.my-1{margin-top:.25rem;margin-bottom:.25rem}.my-2{margin-top:.5rem;margin-bottom:.5rem}.my-3{margin-top:.75rem;margin-bottom:.75rem}.my-4{margin-top:1rem;margin-bottom:1rem}.-mt-1{margin-top:-.25rem}.-mt-2{margin-top:-.5rem}.mb-1{margin-bottom:.25rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.mb-6{margin-bottom:1.5rem}.mb-8{margin-bottom:2rem}.ml-0\.5{margin-left:.125rem}.ml-1{margin-left:.25rem}.ml-10{margin-left:2.5rem}.ml-2{margin-left:.5rem}.ml-3{margin-left:.75rem}.ml-4{margin-left:1rem}.ml-6{margin-left:1.5rem}.ml-auto{margin-left:auto}.mr-1{margin-right:.25rem}.mr-1\.5{margin-right:.375rem}.mr-2{margin-right:.5rem}.mt-0{margin-top:0}.mt-0\.5{margin-top:.125rem}.mt-1{margin-top:.25rem}.mt-1\.5{margin-top:.375rem}.mt-12{margin-top:3rem}.mt-2{margin-top:.5rem}.mt-3{margin-top:.75rem}.mt-4{margin-top:1rem}.mt-5{margin-top:1.25rem}.mt-6{margin-top:1.5rem}.line-clamp-1{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:1}.line-clamp-2{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2}.block{display:block}.inline{display:inline}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.hidden{display:none}.aspect-auto{aspect-ratio:auto}.aspect-square{aspect-ratio:1 / 1}.aspect-video{aspect-ratio:16 / 9}.size-4{width:1rem;height:1rem}.size-\[--cell-size\]{width:var(--cell-size);height:var(--cell-size)}.h-0\.5{height:.125rem}.h-1\.5{height:.375rem}.h-10{height:2.5rem}.h-12{height:3rem}.h-16{height:4rem}.h-2{height:.5rem}.h-2\.5{height:.625rem}.h-20{height:5rem}.h-3{height:.75rem}.h-3\.5{height:.875rem}.h-32{height:8rem}.h-4{height:1rem}.h-40{height:10rem}.h-48{height:12rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-60{height:15rem}.h-64{height:16rem}.h-7{height:1.75rem}.h-8{height:2rem}.h-9{height:2.25rem}.h-\[--cell-size\]{height:var(--cell-size)}.h-\[1\.25rem\]{height:1.25rem}.h-\[140px\]{height:140px}.h-\[1px\]{height:1px}.h-\[200px\]{height:200px}.h-\[250px\]{height:250px}.h-\[280px\]{height:280px}.h-\[300px\]{height:300px}.h-\[350px\]{height:350px}.h-\[400px\]{height:400px}.h-\[600px\]{height:600px}.h-\[calc\(100vh-12rem\)\]{height:calc(100vh - 12rem)}.h-\[calc\(100vh-200px\)\]{height:calc(100vh - 200px)}.h-\[calc\(100vh-240px\)\]{height:calc(100vh - 240px)}.h-\[calc\(100vh-260px\)\]{height:calc(100vh - 260px)}.h-\[calc\(100vh-4rem\)\]{height:calc(100vh - 4rem)}.h-\[var\(--radix-select-trigger-height\)\]{height:var(--radix-select-trigger-height)}.h-auto{height:auto}.h-full{height:100%}.h-px{height:1px}.h-screen{height:100vh}.max-h-32{max-height:8rem}.max-h-64{max-height:16rem}.max-h-\[--radix-context-menu-content-available-height\]{max-height:var(--radix-context-menu-content-available-height)}.max-h-\[--radix-select-content-available-height\]{max-height:var(--radix-select-content-available-height)}.max-h-\[200px\]{max-height:200px}.max-h-\[300px\]{max-height:300px}.max-h-\[60vh\]{max-height:60vh}.max-h-\[80vh\]{max-height:80vh}.max-h-\[85vh\]{max-height:85vh}.max-h-\[90vh\]{max-height:90vh}.max-h-\[calc\(90vh-120px\)\]{max-height:calc(90vh - 120px)}.max-h-\[calc\(90vh-8rem\)\]{max-height:calc(90vh - 8rem)}.max-h-full{max-height:100%}.max-h-none{max-height:none}.max-h-screen{max-height:100vh}.min-h-0{min-height:0px}.min-h-10{min-height:2.5rem}.min-h-\[100px\]{min-height:100px}.min-h-\[140px\]{min-height:140px}.min-h-\[300px\]{min-height:300px}.min-h-\[400px\]{min-height:400px}.min-h-\[60px\]{min-height:60px}.min-h-screen{min-height:100vh}.w-0{width:0px}.w-1{width:.25rem}.w-1\.5{width:.375rem}.w-10{width:2.5rem}.w-12{width:3rem}.w-16{width:4rem}.w-2{width:.5rem}.w-2\.5{width:.625rem}.w-20{width:5rem}.w-24{width:6rem}.w-28{width:7rem}.w-3{width:.75rem}.w-3\.5{width:.875rem}.w-32{width:8rem}.w-4{width:1rem}.w-5{width:1.25rem}.w-6{width:1.5rem}.w-64{width:16rem}.w-7{width:1.75rem}.w-72{width:18rem}.w-8{width:2rem}.w-80{width:20rem}.w-9{width:2.25rem}.w-\[--cell-size\]{width:var(--cell-size)}.w-\[100px\]{width:100px}.w-\[120px\]{width:120px}.w-\[130px\]{width:130px}.w-\[1px\]{width:1px}.w-\[600px\]{width:600px}.w-\[65px\]{width:65px}.w-\[95vw\]{width:95vw}.w-auto{width:auto}.w-fit{width:-moz-fit-content;width:fit-content}.w-full{width:100%}.w-px{width:1px}.min-w-0{min-width:0px}.min-w-\[--cell-size\]{min-width:var(--cell-size)}.min-w-\[100px\]{min-width:100px}.min-w-\[120px\]{min-width:120px}.min-w-\[80px\]{min-width:80px}.min-w-\[8rem\]{min-width:8rem}.min-w-\[var\(--radix-select-trigger-width\)\]{min-width:var(--radix-select-trigger-width)}.min-w-full{min-width:100%}.max-w-2xl{max-width:42rem}.max-w-32{max-width:8rem}.max-w-3xl{max-width:48rem}.max-w-4xl{max-width:56rem}.max-w-\[100px\]{max-width:100px}.max-w-\[150px\]{max-width:150px}.max-w-\[200px\]{max-width:200px}.max-w-\[60px\]{max-width:60px}.max-w-\[75\%\]{max-width:75%}.max-w-\[90\%\]{max-width:90%}.max-w-\[95vw\]{max-width:95vw}.max-w-full{max-width:100%}.max-w-lg{max-width:32rem}.max-w-md{max-width:28rem}.max-w-none{max-width:none}.max-w-xs{max-width:20rem}.flex-1{flex:1 1 0%}.flex-shrink-0,.shrink-0{flex-shrink:0}.grow{flex-grow:1}.caption-bottom{caption-side:bottom}.border-collapse{border-collapse:collapse}.origin-\[--radix-context-menu-content-transform-origin\]{transform-origin:var(--radix-context-menu-content-transform-origin)}.origin-\[--radix-popover-content-transform-origin\]{transform-origin:var(--radix-popover-content-transform-origin)}.origin-\[--radix-select-content-transform-origin\]{transform-origin:var(--radix-select-content-transform-origin)}.origin-\[--radix-tooltip-content-transform-origin\]{transform-origin:var(--radix-tooltip-content-transform-origin)}.-translate-x-1\/2{--tw-translate-x: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-x-full{--tw-translate-x: -100%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-y-1\/2{--tw-translate-y: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-0{--tw-translate-x: 0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-\[-50\%\]{--tw-translate-x: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-y-\[-50\%\]{--tw-translate-y: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.rotate-180{--tw-rotate: 180deg;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.animate-\[ping_3s_ease-in-out_infinite\]{animation:ping 3s ease-in-out infinite}.animate-\[ping_3s_ease-in-out_infinite_0\.5s\]{animation:ping 3s ease-in-out infinite .5s}.animate-\[ping_3s_ease-in-out_infinite_1s\]{animation:ping 3s ease-in-out infinite 1s}@keyframes bounce{0%,to{transform:translateY(-25%);animation-timing-function:cubic-bezier(.8,0,1,1)}50%{transform:none;animation-timing-function:cubic-bezier(0,0,.2,1)}}.animate-bounce{animation:bounce 1s infinite}@keyframes ping{75%,to{transform:scale(2);opacity:0}}.animate-ping{animation:ping 1s cubic-bezier(0,0,.2,1) infinite}@keyframes pulse{50%{opacity:.5}}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}@keyframes spin{to{transform:rotate(360deg)}}.animate-spin{animation:spin 1s linear infinite}.cursor-default{cursor:default}.cursor-grab{cursor:grab}.cursor-move{cursor:move}.cursor-not-allowed{cursor:not-allowed}.cursor-pointer{cursor:pointer}.touch-none{touch-action:none}.select-none{-webkit-user-select:none;-moz-user-select:none;user-select:none}.select-all{-webkit-user-select:all;-moz-user-select:all;user-select:all}.resize-y{resize:vertical}.resize{resize:both}.list-inside{list-style-position:inside}.list-decimal{list-style-type:decimal}.list-disc{list-style-type:disc}.list-none{list-style-type:none}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.grid-cols-\[1fr_1fr_90px_32px\]{grid-template-columns:1fr 1fr 90px 32px}.grid-rows-\[auto_1fr_auto\]{grid-template-rows:auto 1fr auto}.flex-row{flex-direction:row}.flex-row-reverse{flex-direction:row-reverse}.flex-col{flex-direction:column}.flex-col-reverse{flex-direction:column-reverse}.flex-wrap{flex-wrap:wrap}.place-content-center{place-content:center}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.items-center{align-items:center}.items-baseline{align-items:baseline}.items-stretch{align-items:stretch}.justify-start{justify-content:flex-start}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-0{gap:0px}.gap-0\.5{gap:.125rem}.gap-1{gap:.25rem}.gap-1\.5{gap:.375rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.gap-6{gap:1.5rem}.space-x-2>:not([hidden])~:not([hidden]){--tw-space-x-reverse: 0;margin-right:calc(.5rem * var(--tw-space-x-reverse));margin-left:calc(.5rem * calc(1 - var(--tw-space-x-reverse)))}.space-y-0>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(0px * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(0px * var(--tw-space-y-reverse))}.space-y-0\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.125rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.125rem * var(--tw-space-y-reverse))}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.25rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.25rem * var(--tw-space-y-reverse))}.space-y-1\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.375rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.375rem * var(--tw-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem * var(--tw-space-y-reverse))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.75rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem * var(--tw-space-y-reverse))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem * var(--tw-space-y-reverse))}.space-y-6>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.5rem * var(--tw-space-y-reverse))}.space-y-8>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(2rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(2rem * var(--tw-space-y-reverse))}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-visible{overflow:visible}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.overflow-x-hidden{overflow-x:hidden}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.text-ellipsis{text-overflow:ellipsis}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-line{white-space:pre-line}.whitespace-pre-wrap{white-space:pre-wrap}.break-words{overflow-wrap:break-word}.break-all{word-break:break-all}.rounded{border-radius:.25rem}.rounded-2xl{border-radius:1rem}.rounded-\[2px\]{border-radius:2px}.rounded-\[inherit\]{border-radius:inherit}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:var(--radius)}.rounded-md{border-radius:calc(var(--radius) - 2px)}.rounded-none{border-radius:0}.rounded-sm{border-radius:calc(var(--radius) - 4px)}.rounded-xl{border-radius:.75rem}.rounded-l-md{border-top-left-radius:calc(var(--radius) - 2px);border-bottom-left-radius:calc(var(--radius) - 2px)}.rounded-r-full{border-top-right-radius:9999px;border-bottom-right-radius:9999px}.rounded-r-md{border-top-right-radius:calc(var(--radius) - 2px);border-bottom-right-radius:calc(var(--radius) - 2px)}.rounded-tl-sm{border-top-left-radius:calc(var(--radius) - 4px)}.rounded-tr-sm{border-top-right-radius:calc(var(--radius) - 4px)}.border{border-width:1px}.border-0{border-width:0px}.border-2{border-width:2px}.border-4{border-width:4px}.border-\[1\.5px\]{border-width:1.5px}.border-b{border-bottom-width:1px}.border-l{border-left-width:1px}.border-l-2{border-left-width:2px}.border-l-4{border-left-width:4px}.border-r{border-right-width:1px}.border-t{border-top-width:1px}.border-dashed{border-style:dashed}.border-\[--color-border\]{border-color:var(--color-border)}.border-amber-200{--tw-border-opacity: 1;border-color:rgb(253 230 138 / var(--tw-border-opacity, 1))}.border-amber-500\/50{border-color:#f59e0b80}.border-blue-200{--tw-border-opacity: 1;border-color:rgb(191 219 254 / var(--tw-border-opacity, 1))}.border-blue-500{--tw-border-opacity: 1;border-color:rgb(59 130 246 / var(--tw-border-opacity, 1))}.border-blue-700{--tw-border-opacity: 1;border-color:rgb(29 78 216 / var(--tw-border-opacity, 1))}.border-border{border-color:hsl(var(--border))}.border-border\/50{border-color:hsl(var(--border) / .5)}.border-current{border-color:currentColor}.border-gray-800{--tw-border-opacity: 1;border-color:rgb(31 41 55 / var(--tw-border-opacity, 1))}.border-green-200{--tw-border-opacity: 1;border-color:rgb(187 247 208 / var(--tw-border-opacity, 1))}.border-green-300{--tw-border-opacity: 1;border-color:rgb(134 239 172 / var(--tw-border-opacity, 1))}.border-green-500{--tw-border-opacity: 1;border-color:rgb(34 197 94 / var(--tw-border-opacity, 1))}.border-green-600{--tw-border-opacity: 1;border-color:rgb(22 163 74 / var(--tw-border-opacity, 1))}.border-green-700{--tw-border-opacity: 1;border-color:rgb(21 128 61 / var(--tw-border-opacity, 1))}.border-input{border-color:hsl(var(--input))}.border-muted{border-color:hsl(var(--muted))}.border-muted-foreground\/30{border-color:hsl(var(--muted-foreground) / .3)}.border-muted-foreground\/50{border-color:hsl(var(--muted-foreground) / .5)}.border-orange-200{--tw-border-opacity: 1;border-color:rgb(254 215 170 / var(--tw-border-opacity, 1))}.border-orange-600{--tw-border-opacity: 1;border-color:rgb(234 88 12 / var(--tw-border-opacity, 1))}.border-primary{border-color:hsl(var(--primary))}.border-primary\/10{border-color:hsl(var(--primary) / .1)}.border-primary\/20{border-color:hsl(var(--primary) / .2)}.border-primary\/30{border-color:hsl(var(--primary) / .3)}.border-primary\/50{border-color:hsl(var(--primary) / .5)}.border-purple-500{--tw-border-opacity: 1;border-color:rgb(168 85 247 / var(--tw-border-opacity, 1))}.border-red-200{--tw-border-opacity: 1;border-color:rgb(254 202 202 / var(--tw-border-opacity, 1))}.border-red-300{--tw-border-opacity: 1;border-color:rgb(252 165 165 / var(--tw-border-opacity, 1))}.border-red-500{--tw-border-opacity: 1;border-color:rgb(239 68 68 / var(--tw-border-opacity, 1))}.border-red-500\/50{border-color:#ef444480}.border-transparent{border-color:transparent}.border-yellow-200{--tw-border-opacity: 1;border-color:rgb(254 240 138 / var(--tw-border-opacity, 1))}.border-yellow-500\/50{border-color:#eab30880}.border-l-transparent{border-left-color:transparent}.border-t-transparent{border-top-color:transparent}.bg-\[--color-bg\]{background-color:var(--color-bg)}.bg-accent{background-color:hsl(var(--accent))}.bg-amber-50{--tw-bg-opacity: 1;background-color:rgb(255 251 235 / var(--tw-bg-opacity, 1))}.bg-amber-500\/10{background-color:#f59e0b1a}.bg-background{background-color:hsl(var(--background))}.bg-background\/50{background-color:hsl(var(--background) / .5)}.bg-background\/80{background-color:hsl(var(--background) / .8)}.bg-background\/95{background-color:hsl(var(--background) / .95)}.bg-black{--tw-bg-opacity: 1;background-color:rgb(0 0 0 / var(--tw-bg-opacity, 1))}.bg-black\/50{background-color:#00000080}.bg-black\/80{background-color:#000c}.bg-blue-100{--tw-bg-opacity: 1;background-color:rgb(219 234 254 / var(--tw-bg-opacity, 1))}.bg-blue-50{--tw-bg-opacity: 1;background-color:rgb(239 246 255 / var(--tw-bg-opacity, 1))}.bg-blue-500{--tw-bg-opacity: 1;background-color:rgb(59 130 246 / var(--tw-bg-opacity, 1))}.bg-blue-600{--tw-bg-opacity: 1;background-color:rgb(37 99 235 / var(--tw-bg-opacity, 1))}.bg-blue-900\/20{background-color:#1e3a8a33}.bg-border{background-color:hsl(var(--border))}.bg-card{background-color:hsl(var(--card))}.bg-card\/80{background-color:hsl(var(--card) / .8)}.bg-gray-100{--tw-bg-opacity: 1;background-color:rgb(243 244 246 / var(--tw-bg-opacity, 1))}.bg-gray-400{--tw-bg-opacity: 1;background-color:rgb(156 163 175 / var(--tw-bg-opacity, 1))}.bg-gray-800\/20{background-color:#1f293733}.bg-gray-800\/30{background-color:#1f29374d}.bg-green-100{--tw-bg-opacity: 1;background-color:rgb(220 252 231 / var(--tw-bg-opacity, 1))}.bg-green-50{--tw-bg-opacity: 1;background-color:rgb(240 253 244 / var(--tw-bg-opacity, 1))}.bg-green-500{--tw-bg-opacity: 1;background-color:rgb(34 197 94 / var(--tw-bg-opacity, 1))}.bg-green-600{--tw-bg-opacity: 1;background-color:rgb(22 163 74 / var(--tw-bg-opacity, 1))}.bg-muted{background-color:hsl(var(--muted))}.bg-muted-foreground\/50{background-color:hsl(var(--muted-foreground) / .5)}.bg-muted\/20{background-color:hsl(var(--muted) / .2)}.bg-muted\/30{background-color:hsl(var(--muted) / .3)}.bg-muted\/50{background-color:hsl(var(--muted) / .5)}.bg-muted\/60{background-color:hsl(var(--muted) / .6)}.bg-orange-50{--tw-bg-opacity: 1;background-color:rgb(255 247 237 / var(--tw-bg-opacity, 1))}.bg-orange-500{--tw-bg-opacity: 1;background-color:rgb(249 115 22 / var(--tw-bg-opacity, 1))}.bg-orange-600{--tw-bg-opacity: 1;background-color:rgb(234 88 12 / var(--tw-bg-opacity, 1))}.bg-pink-500{--tw-bg-opacity: 1;background-color:rgb(236 72 153 / var(--tw-bg-opacity, 1))}.bg-popover{background-color:hsl(var(--popover))}.bg-primary{background-color:hsl(var(--primary))}.bg-primary-foreground\/20{background-color:hsl(var(--primary-foreground) / .2)}.bg-primary\/10{background-color:hsl(var(--primary) / .1)}.bg-primary\/15{background-color:hsl(var(--primary) / .15)}.bg-primary\/20{background-color:hsl(var(--primary) / .2)}.bg-primary\/5{background-color:hsl(var(--primary) / .05)}.bg-primary\/60{background-color:hsl(var(--primary) / .6)}.bg-purple-100{--tw-bg-opacity: 1;background-color:rgb(243 232 255 / var(--tw-bg-opacity, 1))}.bg-purple-500{--tw-bg-opacity: 1;background-color:rgb(168 85 247 / var(--tw-bg-opacity, 1))}.bg-red-100{--tw-bg-opacity: 1;background-color:rgb(254 226 226 / var(--tw-bg-opacity, 1))}.bg-red-50{--tw-bg-opacity: 1;background-color:rgb(254 242 242 / var(--tw-bg-opacity, 1))}.bg-red-500{--tw-bg-opacity: 1;background-color:rgb(239 68 68 / var(--tw-bg-opacity, 1))}.bg-red-500\/10{background-color:#ef44441a}.bg-red-600{--tw-bg-opacity: 1;background-color:rgb(220 38 38 / var(--tw-bg-opacity, 1))}.bg-red-900\/20{background-color:#7f1d1d33}.bg-red-900\/30{background-color:#7f1d1d4d}.bg-secondary{background-color:hsl(var(--secondary))}.bg-secondary\/5{background-color:hsl(var(--secondary) / .05)}.bg-slate-200{--tw-bg-opacity: 1;background-color:rgb(226 232 240 / var(--tw-bg-opacity, 1))}.bg-slate-300{--tw-bg-opacity: 1;background-color:rgb(203 213 225 / var(--tw-bg-opacity, 1))}.bg-slate-400{--tw-bg-opacity: 1;background-color:rgb(148 163 184 / var(--tw-bg-opacity, 1))}.bg-slate-700{--tw-bg-opacity: 1;background-color:rgb(51 65 85 / var(--tw-bg-opacity, 1))}.bg-slate-800{--tw-bg-opacity: 1;background-color:rgb(30 41 59 / var(--tw-bg-opacity, 1))}.bg-slate-900{--tw-bg-opacity: 1;background-color:rgb(15 23 42 / var(--tw-bg-opacity, 1))}.bg-transparent{background-color:transparent}.bg-white{--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity, 1))}.bg-yellow-200{--tw-bg-opacity: 1;background-color:rgb(254 240 138 / var(--tw-bg-opacity, 1))}.bg-yellow-50{--tw-bg-opacity: 1;background-color:rgb(254 252 232 / var(--tw-bg-opacity, 1))}.bg-yellow-500\/5{background-color:#eab3080d}.bg-yellow-900\/20{background-color:#713f1233}.bg-gradient-to-br{background-image:linear-gradient(to bottom right,var(--tw-gradient-stops))}.bg-gradient-to-r{background-image:linear-gradient(to right,var(--tw-gradient-stops))}.from-blue-500{--tw-gradient-from: #3b82f6 var(--tw-gradient-from-position);--tw-gradient-to: rgb(59 130 246 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.from-green-500{--tw-gradient-from: #22c55e var(--tw-gradient-from-position);--tw-gradient-to: rgb(34 197 94 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.from-indigo-500{--tw-gradient-from: #6366f1 var(--tw-gradient-from-position);--tw-gradient-to: rgb(99 102 241 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.from-orange-500{--tw-gradient-from: #f97316 var(--tw-gradient-from-position);--tw-gradient-to: rgb(249 115 22 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.from-primary\/5{--tw-gradient-from: hsl(var(--primary) / .05) var(--tw-gradient-from-position);--tw-gradient-to: hsl(var(--primary) / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.from-purple-500{--tw-gradient-from: #a855f7 var(--tw-gradient-from-position);--tw-gradient-to: rgb(168 85 247 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.from-red-500{--tw-gradient-from: #ef4444 var(--tw-gradient-from-position);--tw-gradient-to: rgb(239 68 68 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.from-slate-200{--tw-gradient-from: #e2e8f0 var(--tw-gradient-from-position);--tw-gradient-to: rgb(226 232 240 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.from-slate-300{--tw-gradient-from: #cbd5e1 var(--tw-gradient-from-position);--tw-gradient-to: rgb(203 213 225 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.from-slate-400{--tw-gradient-from: #94a3b8 var(--tw-gradient-from-position);--tw-gradient-to: rgb(148 163 184 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.via-background{--tw-gradient-to: hsl(var(--background) / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), hsl(var(--background)) var(--tw-gradient-via-position), var(--tw-gradient-to)}.to-blue-600{--tw-gradient-to: #2563eb var(--tw-gradient-to-position)}.to-cyan-500{--tw-gradient-to: #06b6d4 var(--tw-gradient-to-position)}.to-emerald-500{--tw-gradient-to: #10b981 var(--tw-gradient-to-position)}.to-green-600{--tw-gradient-to: #16a34a var(--tw-gradient-to-position)}.to-orange-500{--tw-gradient-to: #f97316 var(--tw-gradient-to-position)}.to-pink-500{--tw-gradient-to: #ec4899 var(--tw-gradient-to-position)}.to-primary\/10{--tw-gradient-to: hsl(var(--primary) / .1) var(--tw-gradient-to-position)}.to-purple-500{--tw-gradient-to: #a855f7 var(--tw-gradient-to-position)}.to-secondary\/5{--tw-gradient-to: hsl(var(--secondary) / .05) var(--tw-gradient-to-position)}.to-slate-700{--tw-gradient-to: #334155 var(--tw-gradient-to-position)}.to-slate-800{--tw-gradient-to: #1e293b var(--tw-gradient-to-position)}.to-slate-900{--tw-gradient-to: #0f172a var(--tw-gradient-to-position)}.fill-current{fill:currentColor}.fill-yellow-400{fill:#facc15}.object-contain{-o-object-fit:contain;object-fit:contain}.object-cover{-o-object-fit:cover;object-fit:cover}.p-0{padding:0}.p-0\.5{padding:.125rem}.p-1{padding:.25rem}.p-1\.5{padding:.375rem}.p-2{padding:.5rem}.p-2\.5{padding:.625rem}.p-3{padding:.75rem}.p-4{padding:1rem}.p-6{padding:1.5rem}.p-\[1px\]{padding:1px}.px-1{padding-left:.25rem;padding-right:.25rem}.px-1\.5{padding-left:.375rem;padding-right:.375rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-2\.5{padding-left:.625rem;padding-right:.625rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.px-8{padding-left:2rem;padding-right:2rem}.px-\[--cell-size\]{padding-left:var(--cell-size);padding-right:var(--cell-size)}.py-0{padding-top:0;padding-bottom:0}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.py-12{padding-top:3rem;padding-bottom:3rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-2\.5{padding-top:.625rem;padding-bottom:.625rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-4{padding-top:1rem;padding-bottom:1rem}.py-6{padding-top:1.5rem;padding-bottom:1.5rem}.py-8{padding-top:2rem;padding-bottom:2rem}.pb-0{padding-bottom:0}.pb-2{padding-bottom:.5rem}.pb-3{padding-bottom:.75rem}.pb-4{padding-bottom:1rem}.pl-10{padding-left:2.5rem}.pl-11{padding-left:2.75rem}.pl-2{padding-left:.5rem}.pl-4{padding-left:1rem}.pl-6{padding-left:1.5rem}.pl-8{padding-left:2rem}.pl-9{padding-left:2.25rem}.pr-1{padding-right:.25rem}.pr-10{padding-right:2.5rem}.pr-16{padding-right:4rem}.pr-2{padding-right:.5rem}.pr-4{padding-right:1rem}.pr-6{padding-right:1.5rem}.pr-8{padding-right:2rem}.pt-0{padding-top:0}.pt-1{padding-top:.25rem}.pt-2{padding-top:.5rem}.pt-3{padding-top:.75rem}.pt-4{padding-top:1rem}.pt-6{padding-top:1.5rem}.pt-8{padding-top:2rem}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.align-middle{vertical-align:middle}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-2xl{font-size:1.5rem;line-height:2rem}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-\[0\.8rem\]{font-size:.8rem}.text-\[10px\]{font-size:10px}.text-\[150px\]{font-size:150px}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-black{font-weight:900}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-normal{font-weight:400}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.italic{font-style:italic}.tabular-nums{--tw-numeric-spacing: tabular-nums;font-variant-numeric:var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) var(--tw-numeric-spacing) var(--tw-numeric-fraction)}.leading-none{line-height:1}.leading-relaxed{line-height:1.625}.tracking-tight{letter-spacing:-.025em}.tracking-wider{letter-spacing:.05em}.tracking-widest{letter-spacing:.1em}.text-accent-foreground{color:hsl(var(--accent-foreground))}.text-amber-600{--tw-text-opacity: 1;color:rgb(217 119 6 / var(--tw-text-opacity, 1))}.text-amber-700{--tw-text-opacity: 1;color:rgb(180 83 9 / var(--tw-text-opacity, 1))}.text-amber-900{--tw-text-opacity: 1;color:rgb(120 53 15 / var(--tw-text-opacity, 1))}.text-blue-500{--tw-text-opacity: 1;color:rgb(59 130 246 / var(--tw-text-opacity, 1))}.text-blue-600{--tw-text-opacity: 1;color:rgb(37 99 235 / var(--tw-text-opacity, 1))}.text-blue-700{--tw-text-opacity: 1;color:rgb(29 78 216 / var(--tw-text-opacity, 1))}.text-blue-800{--tw-text-opacity: 1;color:rgb(30 64 175 / var(--tw-text-opacity, 1))}.text-blue-900{--tw-text-opacity: 1;color:rgb(30 58 138 / var(--tw-text-opacity, 1))}.text-card-foreground{color:hsl(var(--card-foreground))}.text-current{color:currentColor}.text-cyan-400{--tw-text-opacity: 1;color:rgb(34 211 238 / var(--tw-text-opacity, 1))}.text-foreground{color:hsl(var(--foreground))}.text-foreground\/50{color:hsl(var(--foreground) / .5)}.text-gray-300{--tw-text-opacity: 1;color:rgb(209 213 219 / var(--tw-text-opacity, 1))}.text-gray-500{--tw-text-opacity: 1;color:rgb(107 114 128 / var(--tw-text-opacity, 1))}.text-gray-600{--tw-text-opacity: 1;color:rgb(75 85 99 / var(--tw-text-opacity, 1))}.text-gray-700{--tw-text-opacity: 1;color:rgb(55 65 81 / var(--tw-text-opacity, 1))}.text-gray-900{--tw-text-opacity: 1;color:rgb(17 24 39 / var(--tw-text-opacity, 1))}.text-green-500{--tw-text-opacity: 1;color:rgb(34 197 94 / var(--tw-text-opacity, 1))}.text-green-600{--tw-text-opacity: 1;color:rgb(22 163 74 / var(--tw-text-opacity, 1))}.text-green-700{--tw-text-opacity: 1;color:rgb(21 128 61 / var(--tw-text-opacity, 1))}.text-muted-foreground{color:hsl(var(--muted-foreground))}.text-muted-foreground\/50{color:hsl(var(--muted-foreground) / .5)}.text-muted-foreground\/60{color:hsl(var(--muted-foreground) / .6)}.text-orange-600{--tw-text-opacity: 1;color:rgb(234 88 12 / var(--tw-text-opacity, 1))}.text-orange-800{--tw-text-opacity: 1;color:rgb(154 52 18 / var(--tw-text-opacity, 1))}.text-orange-900{--tw-text-opacity: 1;color:rgb(124 45 18 / var(--tw-text-opacity, 1))}.text-popover-foreground{color:hsl(var(--popover-foreground))}.text-primary{color:hsl(var(--primary))}.text-primary-foreground{color:hsl(var(--primary-foreground))}.text-primary-foreground\/70{color:hsl(var(--primary-foreground) / .7)}.text-primary\/10{color:hsl(var(--primary) / .1)}.text-primary\/30{color:hsl(var(--primary) / .3)}.text-primary\/60{color:hsl(var(--primary) / .6)}.text-purple-500{--tw-text-opacity: 1;color:rgb(168 85 247 / var(--tw-text-opacity, 1))}.text-purple-600{--tw-text-opacity: 1;color:rgb(147 51 234 / var(--tw-text-opacity, 1))}.text-purple-700{--tw-text-opacity: 1;color:rgb(126 34 206 / var(--tw-text-opacity, 1))}.text-red-500{--tw-text-opacity: 1;color:rgb(239 68 68 / var(--tw-text-opacity, 1))}.text-red-600{--tw-text-opacity: 1;color:rgb(220 38 38 / var(--tw-text-opacity, 1))}.text-red-700{--tw-text-opacity: 1;color:rgb(185 28 28 / var(--tw-text-opacity, 1))}.text-secondary-foreground{color:hsl(var(--secondary-foreground))}.text-white{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.text-yellow-400{--tw-text-opacity: 1;color:rgb(250 204 21 / var(--tw-text-opacity, 1))}.text-yellow-500{--tw-text-opacity: 1;color:rgb(234 179 8 / var(--tw-text-opacity, 1))}.text-yellow-600{--tw-text-opacity: 1;color:rgb(202 138 4 / var(--tw-text-opacity, 1))}.text-yellow-800{--tw-text-opacity: 1;color:rgb(133 77 14 / var(--tw-text-opacity, 1))}.text-yellow-900{--tw-text-opacity: 1;color:rgb(113 63 18 / var(--tw-text-opacity, 1))}.underline{text-decoration-line:underline}.underline-offset-4{text-underline-offset:4px}.opacity-0{opacity:0}.opacity-100{opacity:1}.opacity-30{opacity:.3}.opacity-50{opacity:.5}.opacity-70{opacity:.7}.opacity-90{opacity:.9}.shadow{--tw-shadow: 0 1px 3px 0 rgb(0 0 0 / .1), 0 1px 2px -1px rgb(0 0 0 / .1);--tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-2xl{--tw-shadow: 0 25px 50px -12px rgb(0 0 0 / .25);--tw-shadow-colored: 0 25px 50px -12px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-lg{--tw-shadow: 0 10px 15px -3px rgb(0 0 0 / .1), 0 4px 6px -4px rgb(0 0 0 / .1);--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-md{--tw-shadow: 0 4px 6px -1px rgb(0 0 0 / .1), 0 2px 4px -2px rgb(0 0 0 / .1);--tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-none{--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-sm{--tw-shadow: 0 1px 2px 0 rgb(0 0 0 / .05);--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-xl{--tw-shadow: 0 20px 25px -5px rgb(0 0 0 / .1), 0 8px 10px -6px rgb(0 0 0 / .1);--tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.outline-none{outline:2px solid transparent;outline-offset:2px}.outline{outline-style:solid}.ring-0{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(0px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.ring-2{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.ring-primary{--tw-ring-color: hsl(var(--primary))}.ring-offset-background{--tw-ring-offset-color: hsl(var(--background))}.blur-3xl{--tw-blur: blur(64px);filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.backdrop-blur{--tw-backdrop-blur: blur(8px);-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.backdrop-blur-md{--tw-backdrop-blur: blur(12px);-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.backdrop-blur-sm{--tw-backdrop-blur: blur(4px);-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.backdrop-blur-xl{--tw-backdrop-blur: blur(24px);-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.backdrop-filter{-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-all{transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-opacity{transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-shadow{transition-property:box-shadow;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-transform{transition-property:transform;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.delay-150{transition-delay:.15s}.delay-300{transition-delay:.3s}.duration-200{transition-duration:.2s}.duration-300{transition-duration:.3s}.ease-in-out{transition-timing-function:cubic-bezier(.4,0,.2,1)}.text-primary-gradient{color:hsl(var(--primary))}.has-gradient .text-primary-gradient{background:var(--primary-gradient);-webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:transparent;color:transparent}.\[--cell-size\:2rem\]{--cell-size: 2rem}.no-animations *,.no-animations *:before,.no-animations *:after{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important}.no-animations *:hover{transition-duration:.01ms!important}::view-transition-old(root),::view-transition-new(root){animation:none;mix-blend-mode:normal}::view-transition-old(root){z-index:1}::view-transition-new(root){z-index:999}.__floater{z-index:99999!important;pointer-events:auto!important}.react-joyride__overlay,.react-joyride__spotlight{z-index:99998!important}.react-joyride__tooltip{pointer-events:auto!important}#tour-portal-container *{pointer-events:auto}.file\:border-0::file-selector-button{border-width:0px}.file\:bg-transparent::file-selector-button{background-color:transparent}.file\:text-sm::file-selector-button{font-size:.875rem;line-height:1.25rem}.file\:font-medium::file-selector-button{font-weight:500}.file\:text-foreground::file-selector-button{color:hsl(var(--foreground))}.placeholder\:text-muted-foreground::-moz-placeholder{color:hsl(var(--muted-foreground))}.placeholder\:text-muted-foreground::placeholder{color:hsl(var(--muted-foreground))}.hover\:border-muted-foreground\/50:hover{border-color:hsl(var(--muted-foreground) / .5)}.hover\:border-primary\/50:hover{border-color:hsl(var(--primary) / .5)}.hover\:bg-accent:hover{background-color:hsl(var(--accent))}.hover\:bg-accent\/50:hover{background-color:hsl(var(--accent) / .5)}.hover\:bg-blue-700:hover{--tw-bg-opacity: 1;background-color:rgb(29 78 216 / var(--tw-bg-opacity, 1))}.hover\:bg-gray-100:hover{--tw-bg-opacity: 1;background-color:rgb(243 244 246 / var(--tw-bg-opacity, 1))}.hover\:bg-green-700:hover{--tw-bg-opacity: 1;background-color:rgb(21 128 61 / var(--tw-bg-opacity, 1))}.hover\:bg-muted:hover{background-color:hsl(var(--muted))}.hover\:bg-muted-foreground\/20:hover{background-color:hsl(var(--muted-foreground) / .2)}.hover\:bg-muted\/50:hover{background-color:hsl(var(--muted) / .5)}.hover\:bg-orange-700:hover{--tw-bg-opacity: 1;background-color:rgb(194 65 12 / var(--tw-bg-opacity, 1))}.hover\:bg-primary\/10:hover{background-color:hsl(var(--primary) / .1)}.hover\:bg-primary\/80:hover{background-color:hsl(var(--primary) / .8)}.hover\:bg-primary\/90:hover{background-color:hsl(var(--primary) / .9)}.hover\:bg-red-700:hover{--tw-bg-opacity: 1;background-color:rgb(185 28 28 / var(--tw-bg-opacity, 1))}.hover\:bg-secondary:hover{background-color:hsl(var(--secondary))}.hover\:bg-secondary\/80:hover{background-color:hsl(var(--secondary) / .8)}.hover\:bg-secondary\/90:hover{background-color:hsl(var(--secondary) / .9)}.hover\:bg-transparent:hover{background-color:transparent}.hover\:bg-white\/5:hover{background-color:#ffffff0d}.hover\:text-accent-foreground:hover{color:hsl(var(--accent-foreground))}.hover\:text-foreground:hover{color:hsl(var(--foreground))}.hover\:text-green-700:hover{--tw-text-opacity: 1;color:rgb(21 128 61 / var(--tw-text-opacity, 1))}.hover\:text-orange-700:hover{--tw-text-opacity: 1;color:rgb(194 65 12 / var(--tw-text-opacity, 1))}.hover\:text-primary\/80:hover{color:hsl(var(--primary) / .8)}.hover\:text-red-700:hover{--tw-text-opacity: 1;color:rgb(185 28 28 / var(--tw-text-opacity, 1))}.hover\:text-yellow-300:hover{--tw-text-opacity: 1;color:rgb(253 224 71 / var(--tw-text-opacity, 1))}.hover\:underline:hover{text-decoration-line:underline}.hover\:opacity-100:hover{opacity:1}.hover\:shadow-lg:hover{--tw-shadow: 0 10px 15px -3px rgb(0 0 0 / .1), 0 4px 6px -4px rgb(0 0 0 / .1);--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.hover\:ring-2:hover{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.hover\:ring-primary:hover{--tw-ring-color: hsl(var(--primary))}.focus\:bg-accent:focus{background-color:hsl(var(--accent))}.focus\:bg-gray-100:focus{--tw-bg-opacity: 1;background-color:rgb(243 244 246 / var(--tw-bg-opacity, 1))}.focus\:text-accent-foreground:focus{color:hsl(var(--accent-foreground))}.focus\:opacity-100:focus{opacity:1}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.focus\:ring-1:focus{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus\:ring-2:focus{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus\:ring-ring:focus{--tw-ring-color: hsl(var(--ring))}.focus\:ring-offset-2:focus{--tw-ring-offset-width: 2px}.focus-visible\:outline-none:focus-visible{outline:2px solid transparent;outline-offset:2px}.focus-visible\:ring-0:focus-visible{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(0px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus-visible\:ring-1:focus-visible{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus-visible\:ring-2:focus-visible{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus-visible\:ring-red-500:focus-visible{--tw-ring-opacity: 1;--tw-ring-color: rgb(239 68 68 / var(--tw-ring-opacity, 1))}.focus-visible\:ring-ring:focus-visible{--tw-ring-color: hsl(var(--ring))}.focus-visible\:ring-offset-2:focus-visible{--tw-ring-offset-width: 2px}.focus-visible\:ring-offset-background:focus-visible{--tw-ring-offset-color: hsl(var(--background))}.active\:cursor-grabbing:active{cursor:grabbing}.active\:border-primary\/70:active{border-color:hsl(var(--primary) / .7)}.disabled\:pointer-events-none:disabled{pointer-events:none}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-50:disabled{opacity:.5}.group[open] .group-open\:rotate-180{--tw-rotate: 180deg;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group:hover .group-hover\:opacity-100{opacity:1}.group.destructive .group-\[\.destructive\]\:border-muted\/40{border-color:hsl(var(--muted) / .4)}.group.destructive .group-\[\.destructive\]\:text-red-300{--tw-text-opacity: 1;color:rgb(252 165 165 / var(--tw-text-opacity, 1))}.group.destructive .group-\[\.destructive\]\:hover\:text-red-50:hover{--tw-text-opacity: 1;color:rgb(254 242 242 / var(--tw-text-opacity, 1))}.group.destructive .group-\[\.destructive\]\:focus\:ring-red-400:focus{--tw-ring-opacity: 1;--tw-ring-color: rgb(248 113 113 / var(--tw-ring-opacity, 1))}.group.destructive .group-\[\.destructive\]\:focus\:ring-offset-red-600:focus{--tw-ring-offset-color: #dc2626}.peer:disabled~.peer-disabled\:cursor-not-allowed{cursor:not-allowed}.peer:disabled~.peer-disabled\:opacity-70{opacity:.7}.aria-disabled\:opacity-50[aria-disabled=true]{opacity:.5}.aria-selected\:text-muted-foreground[aria-selected=true]{color:hsl(var(--muted-foreground))}.data-\[disabled\=true\]\:pointer-events-none[data-disabled=true],.data-\[disabled\]\:pointer-events-none[data-disabled]{pointer-events:none}.data-\[side\=bottom\]\:translate-y-1[data-side=bottom]{--tw-translate-y: .25rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.data-\[side\=left\]\:-translate-x-1[data-side=left]{--tw-translate-x: -.25rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.data-\[side\=right\]\:translate-x-1[data-side=right]{--tw-translate-x: .25rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.data-\[side\=top\]\:-translate-y-1[data-side=top]{--tw-translate-y: -.25rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.data-\[state\=checked\]\:translate-x-4[data-state=checked]{--tw-translate-x: 1rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.data-\[state\=unchecked\]\:translate-x-0[data-state=unchecked],.data-\[swipe\=cancel\]\:translate-x-0[data-swipe=cancel]{--tw-translate-x: 0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.data-\[swipe\=end\]\:translate-x-\[var\(--radix-toast-swipe-end-x\)\][data-swipe=end]{--tw-translate-x: var(--radix-toast-swipe-end-x);transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.data-\[swipe\=move\]\:translate-x-\[var\(--radix-toast-swipe-move-x\)\][data-swipe=move]{--tw-translate-x: var(--radix-toast-swipe-move-x);transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes fade-out{0%{opacity:1}to{opacity:0}}.data-\[state\=closed\]\:animate-fade-out[data-state=closed]{animation:fade-out .15s ease-in}.data-\[state\=closed\]\:animate-slide-out-to-right[data-state=closed]{animation:slide-out-to-right .2s ease-in}@keyframes fade-in{0%{opacity:0}to{opacity:1}}.data-\[state\=open\]\:animate-fade-in[data-state=open]{animation:fade-in .2s ease-out}@keyframes slide-in-from-right{0%{transform:translate(100%)}to{transform:translate(0)}}.data-\[state\=open\]\:animate-slide-in-from-right[data-state=open]{animation:slide-in-from-right .3s ease-out}@keyframes slide-out-to-right{0%{transform:translate(0)}to{transform:translate(100%)}}.data-\[swipe\=end\]\:animate-slide-out-to-right[data-swipe=end]{animation:slide-out-to-right .2s ease-in}.data-\[range-end\=true\]\:rounded-md[data-range-end=true]{border-radius:calc(var(--radius) - 2px)}.data-\[range-middle\=true\]\:rounded-none[data-range-middle=true]{border-radius:0}.data-\[range-start\=true\]\:rounded-md[data-range-start=true]{border-radius:calc(var(--radius) - 2px)}.data-\[selected\=true\]\:rounded-none[data-selected=true]{border-radius:0}.data-\[range-end\=true\]\:bg-primary[data-range-end=true]{background-color:hsl(var(--primary))}.data-\[range-middle\=true\]\:bg-accent[data-range-middle=true]{background-color:hsl(var(--accent))}.data-\[range-start\=true\]\:bg-primary[data-range-start=true],.data-\[selected-single\=true\]\:bg-primary[data-selected-single=true]{background-color:hsl(var(--primary))}.data-\[selected\=true\]\:bg-accent[data-selected=true]{background-color:hsl(var(--accent))}.data-\[state\=active\]\:bg-background[data-state=active]{background-color:hsl(var(--background))}.data-\[state\=checked\]\:bg-primary[data-state=checked]{background-color:hsl(var(--primary))}.data-\[state\=open\]\:bg-accent[data-state=open]{background-color:hsl(var(--accent))}.data-\[state\=selected\]\:bg-muted[data-state=selected]{background-color:hsl(var(--muted))}.data-\[state\=unchecked\]\:bg-input[data-state=unchecked]{background-color:hsl(var(--input))}.data-\[placeholder\]\:text-muted-foreground[data-placeholder]{color:hsl(var(--muted-foreground))}.data-\[range-end\=true\]\:text-primary-foreground[data-range-end=true]{color:hsl(var(--primary-foreground))}.data-\[range-middle\=true\]\:text-accent-foreground[data-range-middle=true]{color:hsl(var(--accent-foreground))}.data-\[range-start\=true\]\:text-primary-foreground[data-range-start=true],.data-\[selected-single\=true\]\:text-primary-foreground[data-selected-single=true]{color:hsl(var(--primary-foreground))}.data-\[selected\=true\]\:text-accent-foreground[data-selected=true]{color:hsl(var(--accent-foreground))}.data-\[state\=active\]\:text-foreground[data-state=active]{color:hsl(var(--foreground))}.data-\[state\=checked\]\:text-primary-foreground[data-state=checked]{color:hsl(var(--primary-foreground))}.data-\[state\=open\]\:text-accent-foreground[data-state=open]{color:hsl(var(--accent-foreground))}.data-\[state\=open\]\:text-muted-foreground[data-state=open]{color:hsl(var(--muted-foreground))}.data-\[disabled\=true\]\:opacity-50[data-disabled=true],.data-\[disabled\]\:opacity-50[data-disabled]{opacity:.5}.data-\[state\=active\]\:shadow[data-state=active]{--tw-shadow: 0 1px 3px 0 rgb(0 0 0 / .1), 0 1px 2px -1px rgb(0 0 0 / .1);--tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.data-\[state\=active\]\:shadow-sm[data-state=active]{--tw-shadow: 0 1px 2px 0 rgb(0 0 0 / .05);--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.data-\[swipe\=move\]\:transition-none[data-swipe=move]{transition-property:none}.data-\[state\=active\]\:duration-300[data-state=active]{transition-duration:.3s}.group\/day[data-focused=true] .group-data-\[focused\=true\]\/day\:relative{position:relative}.group\/day[data-focused=true] .group-data-\[focused\=true\]\/day\:z-10{z-index:10}.group\/day[data-focused=true] .group-data-\[focused\=true\]\/day\:border-ring{border-color:hsl(var(--ring))}.group\/day[data-focused=true] .group-data-\[focused\=true\]\/day\:ring-\[3px\]{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.group\/day[data-focused=true] .group-data-\[focused\=true\]\/day\:ring-ring\/50{--tw-ring-color: hsl(var(--ring) / .5)}@supports (backdrop-filter: var(--tw)){.supports-\[backdrop-filter\]\:bg-background\/60{background-color:hsl(var(--background) / .6)}}.dark\:border-amber-800:is(.dark *){--tw-border-opacity: 1;border-color:rgb(146 64 14 / var(--tw-border-opacity, 1))}.dark\:border-blue-800:is(.dark *){--tw-border-opacity: 1;border-color:rgb(30 64 175 / var(--tw-border-opacity, 1))}.dark\:border-blue-900:is(.dark *){--tw-border-opacity: 1;border-color:rgb(30 58 138 / var(--tw-border-opacity, 1))}.dark\:border-gray-900:is(.dark *){--tw-border-opacity: 1;border-color:rgb(17 24 39 / var(--tw-border-opacity, 1))}.dark\:border-green-800:is(.dark *){--tw-border-opacity: 1;border-color:rgb(22 101 52 / var(--tw-border-opacity, 1))}.dark\:border-green-900:is(.dark *){--tw-border-opacity: 1;border-color:rgb(20 83 45 / var(--tw-border-opacity, 1))}.dark\:border-orange-900:is(.dark *){--tw-border-opacity: 1;border-color:rgb(124 45 18 / var(--tw-border-opacity, 1))}.dark\:border-red-900:is(.dark *){--tw-border-opacity: 1;border-color:rgb(127 29 29 / var(--tw-border-opacity, 1))}.dark\:border-yellow-900:is(.dark *){--tw-border-opacity: 1;border-color:rgb(113 63 18 / var(--tw-border-opacity, 1))}.dark\:bg-amber-950\/30:is(.dark *){background-color:#451a034d}.dark\:bg-blue-500\/20:is(.dark *){background-color:#3b82f633}.dark\:bg-blue-900:is(.dark *){--tw-bg-opacity: 1;background-color:rgb(30 58 138 / var(--tw-bg-opacity, 1))}.dark\:bg-blue-900\/30:is(.dark *){background-color:#1e3a8a4d}.dark\:bg-blue-950:is(.dark *){--tw-bg-opacity: 1;background-color:rgb(23 37 84 / var(--tw-bg-opacity, 1))}.dark\:bg-blue-950\/20:is(.dark *){background-color:#17255433}.dark\:bg-blue-950\/30:is(.dark *){background-color:#1725544d}.dark\:bg-gray-800:is(.dark *){--tw-bg-opacity: 1;background-color:rgb(31 41 55 / var(--tw-bg-opacity, 1))}.dark\:bg-gray-800\/30:is(.dark *){background-color:#1f29374d}.dark\:bg-gray-800\/50:is(.dark *){background-color:#1f293780}.dark\:bg-gray-900:is(.dark *){--tw-bg-opacity: 1;background-color:rgb(17 24 39 / var(--tw-bg-opacity, 1))}.dark\:bg-gray-950:is(.dark *){--tw-bg-opacity: 1;background-color:rgb(3 7 18 / var(--tw-bg-opacity, 1))}.dark\:bg-green-900\/30:is(.dark *){background-color:#14532d4d}.dark\:bg-green-950:is(.dark *){--tw-bg-opacity: 1;background-color:rgb(5 46 22 / var(--tw-bg-opacity, 1))}.dark\:bg-green-950\/20:is(.dark *){background-color:#052e1633}.dark\:bg-orange-950\/20:is(.dark *){background-color:#43140733}.dark\:bg-purple-900\/30:is(.dark *){background-color:#581c874d}.dark\:bg-red-500\/20:is(.dark *){background-color:#ef444433}.dark\:bg-red-600\/30:is(.dark *){background-color:#dc26264d}.dark\:bg-red-900\/30:is(.dark *){background-color:#7f1d1d4d}.dark\:bg-red-950\/20:is(.dark *){background-color:#450a0a33}.dark\:bg-red-950\/50:is(.dark *){background-color:#450a0a80}.dark\:bg-yellow-500\/20:is(.dark *){background-color:#eab30833}.dark\:bg-yellow-900:is(.dark *){--tw-bg-opacity: 1;background-color:rgb(113 63 18 / var(--tw-bg-opacity, 1))}.dark\:bg-yellow-950\/30:is(.dark *){background-color:#4220064d}.dark\:text-amber-100:is(.dark *){--tw-text-opacity: 1;color:rgb(254 243 199 / var(--tw-text-opacity, 1))}.dark\:text-amber-400:is(.dark *){--tw-text-opacity: 1;color:rgb(251 191 36 / var(--tw-text-opacity, 1))}.dark\:text-blue-100:is(.dark *){--tw-text-opacity: 1;color:rgb(219 234 254 / var(--tw-text-opacity, 1))}.dark\:text-blue-200:is(.dark *){--tw-text-opacity: 1;color:rgb(191 219 254 / var(--tw-text-opacity, 1))}.dark\:text-blue-300:is(.dark *){--tw-text-opacity: 1;color:rgb(147 197 253 / var(--tw-text-opacity, 1))}.dark\:text-blue-400:is(.dark *){--tw-text-opacity: 1;color:rgb(96 165 250 / var(--tw-text-opacity, 1))}.dark\:text-cyan-500:is(.dark *){--tw-text-opacity: 1;color:rgb(6 182 212 / var(--tw-text-opacity, 1))}.dark\:text-gray-100:is(.dark *){--tw-text-opacity: 1;color:rgb(243 244 246 / var(--tw-text-opacity, 1))}.dark\:text-gray-400:is(.dark *){--tw-text-opacity: 1;color:rgb(156 163 175 / var(--tw-text-opacity, 1))}.dark\:text-gray-600:is(.dark *){--tw-text-opacity: 1;color:rgb(75 85 99 / var(--tw-text-opacity, 1))}.dark\:text-green-300:is(.dark *){--tw-text-opacity: 1;color:rgb(134 239 172 / var(--tw-text-opacity, 1))}.dark\:text-green-400:is(.dark *){--tw-text-opacity: 1;color:rgb(74 222 128 / var(--tw-text-opacity, 1))}.dark\:text-orange-100:is(.dark *){--tw-text-opacity: 1;color:rgb(255 237 213 / var(--tw-text-opacity, 1))}.dark\:text-orange-200:is(.dark *){--tw-text-opacity: 1;color:rgb(254 215 170 / var(--tw-text-opacity, 1))}.dark\:text-purple-400:is(.dark *){--tw-text-opacity: 1;color:rgb(192 132 252 / var(--tw-text-opacity, 1))}.dark\:text-red-300:is(.dark *){--tw-text-opacity: 1;color:rgb(252 165 165 / var(--tw-text-opacity, 1))}.dark\:text-red-400:is(.dark *){--tw-text-opacity: 1;color:rgb(248 113 113 / var(--tw-text-opacity, 1))}.dark\:text-red-500:is(.dark *){--tw-text-opacity: 1;color:rgb(239 68 68 / var(--tw-text-opacity, 1))}.dark\:text-yellow-200:is(.dark *){--tw-text-opacity: 1;color:rgb(254 240 138 / var(--tw-text-opacity, 1))}.dark\:text-yellow-300:is(.dark *){--tw-text-opacity: 1;color:rgb(253 224 71 / var(--tw-text-opacity, 1))}.dark\:text-yellow-400:is(.dark *){--tw-text-opacity: 1;color:rgb(250 204 21 / var(--tw-text-opacity, 1))}.dark\:text-yellow-500:is(.dark *){--tw-text-opacity: 1;color:rgb(234 179 8 / var(--tw-text-opacity, 1))}.dark\:hover\:bg-gray-800:hover:is(.dark *){--tw-bg-opacity: 1;background-color:rgb(31 41 55 / var(--tw-bg-opacity, 1))}.dark\:focus\:bg-gray-800:focus:is(.dark *){--tw-bg-opacity: 1;background-color:rgb(31 41 55 / var(--tw-bg-opacity, 1))}@media(min-width:640px){.sm\:right-2{right:.5rem}.sm\:right-3{right:.75rem}.sm\:top-2{top:.5rem}.sm\:top-3{top:.75rem}.sm\:order-1{order:1}.sm\:order-2{order:2}.sm\:col-span-2{grid-column:span 2 / span 2}.sm\:mx-0{margin-left:0;margin-right:0}.sm\:mb-3{margin-bottom:.75rem}.sm\:mb-4{margin-bottom:1rem}.sm\:mb-6{margin-bottom:1.5rem}.sm\:ml-0{margin-left:0}.sm\:ml-1{margin-left:.25rem}.sm\:mr-1{margin-right:.25rem}.sm\:mt-0{margin-top:0}.sm\:mt-2{margin-top:.5rem}.sm\:mt-3{margin-top:.75rem}.sm\:mt-6{margin-top:1.5rem}.sm\:block{display:block}.sm\:inline{display:inline}.sm\:flex{display:flex}.sm\:grid{display:grid}.sm\:hidden{display:none}.sm\:h-10{height:2.5rem}.sm\:h-12{height:3rem}.sm\:h-2{height:.5rem}.sm\:h-2\.5{height:.625rem}.sm\:h-24{height:6rem}.sm\:h-4{height:1rem}.sm\:h-5{height:1.25rem}.sm\:h-8{height:2rem}.sm\:h-9{height:2.25rem}.sm\:h-\[300px\]{height:300px}.sm\:h-\[400px\]{height:400px}.sm\:h-\[500px\]{height:500px}.sm\:h-\[calc\(100vh-280px\)\]{height:calc(100vh - 280px)}.sm\:w-10{width:2.5rem}.sm\:w-2{width:.5rem}.sm\:w-2\.5{width:.625rem}.sm\:w-24{width:6rem}.sm\:w-28{width:7rem}.sm\:w-4{width:1rem}.sm\:w-5{width:1.25rem}.sm\:w-8{width:2rem}.sm\:w-80{width:20rem}.sm\:w-96{width:24rem}.sm\:w-\[200px\]{width:200px}.sm\:w-\[500px\]{width:500px}.sm\:w-auto{width:auto}.sm\:w-full{width:100%}.sm\:min-w-\[120px\]{min-width:120px}.sm\:max-w-2xl{max-width:42rem}.sm\:max-w-\[420px\]{max-width:420px}.sm\:max-w-\[500px\]{max-width:500px}.sm\:max-w-\[70\%\]{max-width:70%}.sm\:max-w-\[900px\]{max-width:900px}.sm\:max-w-md{max-width:28rem}.sm\:max-w-sm{max-width:24rem}.sm\:flex-1{flex:1 1 0%}.sm\:flex-none{flex:none}.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.sm\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.sm\:grid-cols-5{grid-template-columns:repeat(5,minmax(0,1fr))}.sm\:grid-cols-6{grid-template-columns:repeat(6,minmax(0,1fr))}.sm\:flex-row{flex-direction:row}.sm\:items-start{align-items:flex-start}.sm\:items-center{align-items:center}.sm\:justify-end{justify-content:flex-end}.sm\:justify-between{justify-content:space-between}.sm\:gap-0{gap:0px}.sm\:gap-1{gap:.25rem}.sm\:gap-2{gap:.5rem}.sm\:gap-3{gap:.75rem}.sm\:gap-4{gap:1rem}.sm\:gap-6{gap:1.5rem}.sm\:space-x-2>:not([hidden])~:not([hidden]){--tw-space-x-reverse: 0;margin-right:calc(.5rem * var(--tw-space-x-reverse));margin-left:calc(.5rem * calc(1 - var(--tw-space-x-reverse)))}.sm\:space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.75rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem * var(--tw-space-y-reverse))}.sm\:space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem * var(--tw-space-y-reverse))}.sm\:space-y-5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1.25rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.25rem * var(--tw-space-y-reverse))}.sm\:space-y-6>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.5rem * var(--tw-space-y-reverse))}.sm\:space-y-8>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(2rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(2rem * var(--tw-space-y-reverse))}.sm\:rounded-lg{border-radius:var(--radius)}.sm\:p-3{padding:.75rem}.sm\:p-4{padding:1rem}.sm\:p-6{padding:1.5rem}.sm\:px-0{padding-left:0;padding-right:0}.sm\:px-3{padding-left:.75rem;padding-right:.75rem}.sm\:px-4{padding-left:1rem;padding-right:1rem}.sm\:py-2{padding-top:.5rem;padding-bottom:.5rem}.sm\:pb-3{padding-bottom:.75rem}.sm\:text-left{text-align:left}.sm\:text-right{text-align:right}.sm\:text-2xl{font-size:1.5rem;line-height:2rem}.sm\:text-3xl{font-size:1.875rem;line-height:2.25rem}.sm\:text-\[200px\]{font-size:200px}.sm\:text-base{font-size:1rem;line-height:1.5rem}.sm\:text-lg{font-size:1.125rem;line-height:1.75rem}.sm\:text-sm{font-size:.875rem;line-height:1.25rem}.sm\:text-xl{font-size:1.25rem;line-height:1.75rem}.sm\:text-xs{font-size:.75rem;line-height:1rem}}@media(min-width:768px){.md\:top-4{top:1rem}.md\:mb-4{margin-bottom:1rem}.md\:mb-6{margin-bottom:1.5rem}.md\:mb-8{margin-bottom:2rem}.md\:mt-8{margin-top:2rem}.md\:block{display:block}.md\:inline{display:inline}.md\:flex{display:flex}.md\:hidden{display:none}.md\:h-16{height:4rem}.md\:h-4{height:1rem}.md\:h-5{height:1.25rem}.md\:h-8{height:2rem}.md\:h-96{height:24rem}.md\:h-\[500px\]{height:500px}.md\:min-h-\[400px\]{min-height:400px}.md\:w-16{width:4rem}.md\:w-4{width:1rem}.md\:w-5{width:1.25rem}.md\:w-8{width:2rem}.md\:w-96{width:24rem}.md\:max-w-none{max-width:none}.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.md\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.md\:grid-cols-6{grid-template-columns:repeat(6,minmax(0,1fr))}.md\:flex-row{flex-direction:row}.md\:gap-2{gap:.5rem}.md\:gap-3{gap:.75rem}.md\:gap-4{gap:1rem}.md\:gap-6{gap:1.5rem}.md\:space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem * var(--tw-space-y-reverse))}.md\:space-y-6>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.5rem * var(--tw-space-y-reverse))}.md\:whitespace-normal{white-space:normal}.md\:p-12{padding:3rem}.md\:p-4{padding:1rem}.md\:p-6{padding:1.5rem}.md\:p-8{padding:2rem}.md\:text-2xl{font-size:1.5rem;line-height:2rem}.md\:text-3xl{font-size:1.875rem;line-height:2.25rem}.md\:text-base{font-size:1rem;line-height:1.5rem}.md\:text-lg{font-size:1.125rem;line-height:1.75rem}.md\:text-sm{font-size:.875rem;line-height:1.25rem}.md\:text-xs{font-size:.75rem;line-height:1rem}}@media(min-width:1024px){.lg\:invisible{visibility:hidden}.lg\:relative{position:relative}.lg\:z-0{z-index:0}.lg\:col-span-1{grid-column:span 1 / span 1}.lg\:mx-auto{margin-left:auto;margin-right:auto}.lg\:mb-1{margin-bottom:.25rem}.lg\:block{display:block}.lg\:inline{display:inline}.lg\:flex{display:flex}.lg\:hidden{display:none}.lg\:w-12{width:3rem}.lg\:w-16{width:4rem}.lg\:w-64{width:16rem}.lg\:w-8{width:2rem}.lg\:w-\[130px\]{width:130px}.lg\:w-\[160px\]{width:160px}.lg\:w-\[75px\]{width:75px}.lg\:w-auto{width:auto}.lg\:w-full{width:100%}.lg\:max-w-0{max-width:0px}.lg\:flex-1{flex:1 1 0%}.lg\:flex-none{flex:none}.lg\:translate-x-0{--tw-translate-x: 0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.lg\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.lg\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.lg\:grid-cols-6{grid-template-columns:repeat(6,minmax(0,1fr))}.lg\:grid-cols-7{grid-template-columns:repeat(7,minmax(0,1fr))}.lg\:grid-cols-8{grid-template-columns:repeat(8,minmax(0,1fr))}.lg\:grid-cols-9{grid-template-columns:repeat(9,minmax(0,1fr))}.lg\:justify-center{justify-content:center}.lg\:gap-0{gap:0px}.lg\:space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.75rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem * var(--tw-space-y-reverse))}.lg\:overflow-hidden{overflow:hidden}.lg\:p-2{padding:.5rem}.lg\:p-4{padding:1rem}.lg\:px-0{padding-left:0;padding-right:0}.lg\:px-4{padding-left:1rem;padding-right:1rem}.lg\:pb-4{padding-bottom:1rem}.lg\:text-2xl{font-size:1.5rem;line-height:2rem}.lg\:opacity-0{opacity:0}}@media(min-width:1280px){.xl\:grid-cols-10{grid-template-columns:repeat(10,minmax(0,1fr))}.xl\:grid-cols-5{grid-template-columns:repeat(5,minmax(0,1fr))}.xl\:grid-cols-8{grid-template-columns:repeat(8,minmax(0,1fr))}}.\[\&\+div\]\:text-xs+div{font-size:.75rem;line-height:1rem}.\[\&\:\:-webkit-scrollbar-thumb\:hover\]\:bg-border\/80::-webkit-scrollbar-thumb:hover{background-color:hsl(var(--border) / .8)}.\[\&\:\:-webkit-scrollbar-thumb\]\:rounded-full::-webkit-scrollbar-thumb{border-radius:9999px}.\[\&\:\:-webkit-scrollbar-thumb\]\:bg-border::-webkit-scrollbar-thumb{background-color:hsl(var(--border))}.\[\&\:\:-webkit-scrollbar-track\]\:bg-transparent::-webkit-scrollbar-track{background-color:transparent}.\[\&\:\:-webkit-scrollbar\]\:w-2\.5::-webkit-scrollbar{width:.625rem}.\[\&\:first-child\[data-selected\=true\]_button\]\:rounded-l-md:first-child[data-selected=true] button{border-top-left-radius:calc(var(--radius) - 2px);border-bottom-left-radius:calc(var(--radius) - 2px)}.\[\&\:has\(\[role\=checkbox\]\)\]\:pr-0:has([role=checkbox]){padding-right:0}.\[\&\:last-child\[data-selected\=true\]_button\]\:rounded-r-md:last-child[data-selected=true] button{border-top-right-radius:calc(var(--radius) - 2px);border-bottom-right-radius:calc(var(--radius) - 2px)}.\[\&\>\[role\=checkbox\]\]\:translate-y-\[2px\]>[role=checkbox]{--tw-translate-y: 2px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.\[\&\>div\]\:bg-green-500>div{--tw-bg-opacity: 1;background-color:rgb(34 197 94 / var(--tw-bg-opacity, 1))}.\[\&\>span\]\:line-clamp-1>span{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:1}.\[\&\>span\]\:text-xs>span{font-size:.75rem;line-height:1rem}.\[\&\>span\]\:opacity-70>span{opacity:.7}.\[\&\>svg\+div\]\:translate-y-\[-3px\]>svg+div{--tw-translate-y: -3px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.\[\&\>svg\]\:absolute>svg{position:absolute}.\[\&\>svg\]\:left-4>svg{left:1rem}.\[\&\>svg\]\:top-4>svg{top:1rem}.\[\&\>svg\]\:size-3\.5>svg{width:.875rem;height:.875rem}.\[\&\>svg\]\:h-2\.5>svg{height:.625rem}.\[\&\>svg\]\:h-3>svg{height:.75rem}.\[\&\>svg\]\:w-2\.5>svg{width:.625rem}.\[\&\>svg\]\:w-3>svg{width:.75rem}.\[\&\>svg\]\:text-foreground>svg{color:hsl(var(--foreground))}.\[\&\>svg\]\:text-muted-foreground>svg{color:hsl(var(--muted-foreground))}.\[\&\>svg\~\*\]\:pl-7>svg~*{padding-left:1.75rem}.\[\&\>tr\]\:last\:border-b-0:last-child>tr{border-bottom-width:0px}.\[\&_\.recharts-cartesian-axis-tick_text\]\:fill-muted-foreground .recharts-cartesian-axis-tick text{fill:hsl(var(--muted-foreground))}.\[\&_\.recharts-cartesian-grid_line\[stroke\=\'\#ccc\'\]\]\:stroke-border\/50 .recharts-cartesian-grid line[stroke="#ccc"]{stroke:hsl(var(--border) / .5)}.\[\&_\.recharts-curve\.recharts-tooltip-cursor\]\:stroke-border .recharts-curve.recharts-tooltip-cursor{stroke:hsl(var(--border))}.\[\&_\.recharts-dot\[stroke\=\'\#fff\'\]\]\:stroke-transparent .recharts-dot[stroke="#fff"]{stroke:transparent}.\[\&_\.recharts-layer\]\:outline-none .recharts-layer{outline:2px solid transparent;outline-offset:2px}.\[\&_\.recharts-polar-grid_\[stroke\=\'\#ccc\'\]\]\:stroke-border .recharts-polar-grid [stroke="#ccc"]{stroke:hsl(var(--border))}.\[\&_\.recharts-radial-bar-background-sector\]\:fill-muted .recharts-radial-bar-background-sector,.\[\&_\.recharts-rectangle\.recharts-tooltip-cursor\]\:fill-muted .recharts-rectangle.recharts-tooltip-cursor{fill:hsl(var(--muted))}.\[\&_\.recharts-reference-line_\[stroke\=\'\#ccc\'\]\]\:stroke-border .recharts-reference-line [stroke="#ccc"]{stroke:hsl(var(--border))}.\[\&_\.recharts-sector\[stroke\=\'\#fff\'\]\]\:stroke-transparent .recharts-sector[stroke="#fff"]{stroke:transparent}.\[\&_\.recharts-sector\]\:outline-none .recharts-sector,.\[\&_\.recharts-surface\]\:outline-none .recharts-surface{outline:2px solid transparent;outline-offset:2px}.\[\&_\[cmdk-group-heading\]\]\:px-2 [cmdk-group-heading]{padding-left:.5rem;padding-right:.5rem}.\[\&_\[cmdk-group-heading\]\]\:py-1\.5 [cmdk-group-heading]{padding-top:.375rem;padding-bottom:.375rem}.\[\&_\[cmdk-group-heading\]\]\:text-xs [cmdk-group-heading]{font-size:.75rem;line-height:1rem}.\[\&_\[cmdk-group-heading\]\]\:font-medium [cmdk-group-heading]{font-weight:500}.\[\&_\[cmdk-group-heading\]\]\:text-muted-foreground [cmdk-group-heading]{color:hsl(var(--muted-foreground))}.\[\&_\[cmdk-group\]\:not\(\[hidden\]\)_\~\[cmdk-group\]\]\:pt-0 [cmdk-group]:not([hidden])~[cmdk-group]{padding-top:0}.\[\&_\[cmdk-group\]\]\:px-2 [cmdk-group]{padding-left:.5rem;padding-right:.5rem}.\[\&_\[cmdk-input-wrapper\]_svg\]\:h-5 [cmdk-input-wrapper] svg{height:1.25rem}.\[\&_\[cmdk-input-wrapper\]_svg\]\:w-5 [cmdk-input-wrapper] svg{width:1.25rem}.\[\&_\[cmdk-input\]\]\:h-12 [cmdk-input]{height:3rem}.\[\&_\[cmdk-item\]\]\:px-2 [cmdk-item]{padding-left:.5rem;padding-right:.5rem}.\[\&_\[cmdk-item\]\]\:py-3 [cmdk-item]{padding-top:.75rem;padding-bottom:.75rem}.\[\&_\[cmdk-item\]_svg\]\:h-5 [cmdk-item] svg{height:1.25rem}.\[\&_\[cmdk-item\]_svg\]\:w-5 [cmdk-item] svg{width:1.25rem}.\[\&_p\]\:leading-relaxed p{line-height:1.625}.\[\&_svg\]\:pointer-events-none svg{pointer-events:none}.\[\&_svg\]\:invisible svg{visibility:hidden}.\[\&_svg\]\:size-4 svg{width:1rem;height:1rem}.\[\&_svg\]\:shrink-0 svg{flex-shrink:0}.\[\&_tr\:last-child\]\:border-0 tr:last-child{border-width:0px}.\[\&_tr\]\:border-b tr{border-bottom-width:1px}[data-slot=card-content] .\[\[data-slot\=card-content\]_\&\]\:bg-transparent,[data-slot=popover-content] .\[\[data-slot\=popover-content\]_\&\]\:bg-transparent{background-color:transparent}.uppy-Root{box-sizing:border-box;color:#333;font-family:-apple-system,system-ui,BlinkMacSystemFont,Segoe UI,Segoe UI Symbol,Segoe UI Emoji,Apple Color Emoji,Roboto,Helvetica,Arial,sans-serif;line-height:1;position:relative;text-align:left;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.uppy-Root[dir=rtl],[dir=rtl] .uppy-Root{text-align:right}.uppy-Root *,.uppy-Root :after,.uppy-Root :before{box-sizing:inherit}.uppy-Root [hidden]{display:none}.uppy-u-reset{all:initial;-webkit-appearance:none;-moz-appearance:none;appearance:none;box-sizing:border-box;font-family:-apple-system,system-ui,BlinkMacSystemFont,Segoe UI,Segoe UI Symbol,Segoe UI Emoji,Apple Color Emoji,Roboto,Helvetica,Arial,sans-serif;line-height:1}[dir=rtl] .uppy-u-reset{text-align:right}.uppy-truncate-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.uppy-c-textInput{background-color:#fff;border:1px solid #ddd;border-radius:4px;font-family:inherit;font-size:14px;line-height:1.5;padding:6px 8px}.uppy-size--md .uppy-c-textInput{padding:8px 10px}.uppy-c-textInput:focus{border-color:#1269cf99;box-shadow:0 0 0 3px #1269cf26;outline:none}[data-uppy-theme=dark] .uppy-c-textInput{background-color:#333;border-color:#333;color:#eaeaea}[data-uppy-theme=dark] .uppy-c-textInput:focus{border-color:#525252;box-shadow:none}.uppy-c-icon{display:inline-block;max-height:100%;max-width:100%;overflow:hidden;fill:currentColor}.uppy-c-btn{align-items:center;color:inherit;display:inline-flex;font-family:inherit;font-size:inherit;font-weight:500;justify-content:center;line-height:1;transition-duration:.3s;transition-property:background-color,color;-webkit-user-select:none;-moz-user-select:none;user-select:none;white-space:nowrap}.uppy-c-btn,[dir=rtl] .uppy-c-btn{text-align:center}.uppy-c-btn:not(:disabled):not(.disabled){cursor:pointer}.uppy-c-btn::-moz-focus-inner{border:0}.uppy-c-btn-primary{background-color:#1269cf;border-radius:4px;color:#fff;font-size:14px;padding:10px 18px}.uppy-c-btn-primary:not(:disabled):hover{background-color:#0e51a0}.uppy-c-btn-primary:focus{box-shadow:0 0 0 3px #1269cf66;outline:none}.uppy-size--md .uppy-c-btn-primary{padding:13px 22px}[data-uppy-theme=dark] .uppy-c-btn-primary{color:#eaeaea}[data-uppy-theme=dark] .uppy-c-btn-primary:focus{outline:none}[data-uppy-theme=dark] .uppy-c-btn-primary::-moz-focus-inner{border:0}[data-uppy-theme=dark] .uppy-c-btn-primary:focus{box-shadow:0 0 0 2px #aae1ffd9}.uppy-c-btn-primary.uppy-c-btn--disabled{background-color:#8eb2db}.uppy-c-btn-link{background-color:initial;border-radius:4px;color:#525252;font-size:14px;line-height:1;padding:10px 15px}.uppy-c-btn-link:hover{color:#333}.uppy-c-btn-link:focus{box-shadow:0 0 0 3px #1269cf40;outline:none}.uppy-size--md .uppy-c-btn-link{padding:13px 18px}[data-uppy-theme=dark] .uppy-c-btn-link{color:#eaeaea}[data-uppy-theme=dark] .uppy-c-btn-link:focus{outline:none}[data-uppy-theme=dark] .uppy-c-btn-link::-moz-focus-inner{border:0}[data-uppy-theme=dark] .uppy-c-btn-link:focus{box-shadow:0 0 0 2px #aae1ffd9}[data-uppy-theme=dark] .uppy-c-btn-link:hover{color:#939393}.uppy-ProviderBrowser-viewType--grid ul.uppy-ProviderBrowser-list,.uppy-ProviderBrowser-viewType--unsplash ul.uppy-ProviderBrowser-list{align-items:flex-start;display:flex;flex-direction:row;flex-wrap:wrap;justify-content:space-between;padding:6px}.uppy-ProviderBrowser-viewType--grid ul.uppy-ProviderBrowser-list:after,.uppy-ProviderBrowser-viewType--unsplash ul.uppy-ProviderBrowser-list:after{content:"";flex:auto}.uppy-ProviderBrowser-viewType--grid li.uppy-ProviderBrowserItem,.uppy-ProviderBrowser-viewType--unsplash li.uppy-ProviderBrowserItem{margin:0;position:relative;width:50%}.uppy-size--md .uppy-ProviderBrowser-viewType--grid li.uppy-ProviderBrowserItem,.uppy-size--md .uppy-ProviderBrowser-viewType--unsplash li.uppy-ProviderBrowserItem{width:33.3333%}.uppy-size--lg .uppy-ProviderBrowser-viewType--grid li.uppy-ProviderBrowserItem,.uppy-size--lg .uppy-ProviderBrowser-viewType--unsplash li.uppy-ProviderBrowserItem{width:25%}.uppy-ProviderBrowser-viewType--grid li.uppy-ProviderBrowserItem:before,.uppy-ProviderBrowser-viewType--unsplash li.uppy-ProviderBrowserItem:before{content:"";display:block;padding-top:100%}.uppy-ProviderBrowser-viewType--grid li.uppy-ProviderBrowserItem--selected img,.uppy-ProviderBrowser-viewType--grid li.uppy-ProviderBrowserItem--selected svg,.uppy-ProviderBrowser-viewType--unsplash li.uppy-ProviderBrowserItem--selected img,.uppy-ProviderBrowser-viewType--unsplash li.uppy-ProviderBrowserItem--selected svg{opacity:.85}.uppy-ProviderBrowser-viewType--grid li.uppy-ProviderBrowserItem--disabled,.uppy-ProviderBrowser-viewType--unsplash li.uppy-ProviderBrowserItem--disabled{opacity:.5}.uppy-ProviderBrowser-viewType--grid li.uppy-ProviderBrowserItem--noPreview .uppy-ProviderBrowserItem-inner,.uppy-ProviderBrowser-viewType--unsplash li.uppy-ProviderBrowserItem--noPreview .uppy-ProviderBrowserItem-inner{background-color:#93939333}[data-uppy-theme=dark] .uppy-ProviderBrowser-viewType--grid li.uppy-ProviderBrowserItem--noPreview .uppy-ProviderBrowserItem-inner,[data-uppy-theme=dark] .uppy-ProviderBrowser-viewType--unsplash li.uppy-ProviderBrowserItem--noPreview .uppy-ProviderBrowserItem-inner{background-color:#eaeaea33}.uppy-ProviderBrowser-viewType--grid li.uppy-ProviderBrowserItem--noPreview svg,.uppy-ProviderBrowser-viewType--unsplash li.uppy-ProviderBrowserItem--noPreview svg{height:30%;width:30%;fill:#000000b3}[data-uppy-theme=dark] .uppy-ProviderBrowser-viewType--grid li.uppy-ProviderBrowserItem--noPreview svg,[data-uppy-theme=dark] .uppy-ProviderBrowser-viewType--unsplash li.uppy-ProviderBrowserItem--noPreview svg{fill:#fffc}.uppy-ProviderBrowser-viewType--grid .uppy-ProviderBrowserItem-inner,.uppy-ProviderBrowser-viewType--unsplash .uppy-ProviderBrowserItem-inner{border-radius:4px;height:calc(100% - 14px);inset:7px;overflow:hidden;position:absolute;text-align:center;width:calc(100% - 14px)}@media(hover:none){.uppy-ProviderBrowser-viewType--grid .uppy-ProviderBrowserItem-inner .uppy-ProviderBrowserItem-author,.uppy-ProviderBrowser-viewType--unsplash .uppy-ProviderBrowserItem-inner .uppy-ProviderBrowserItem-author{display:block}}[data-uppy-theme=dark] .uppy-ProviderBrowser-viewType--grid .uppy-ProviderBrowserItem-inner,[data-uppy-theme=dark] .uppy-ProviderBrowser-viewType--unsplash .uppy-ProviderBrowserItem-inner{box-shadow:0 0 0 3px #aae1ffb3}.uppy-ProviderBrowser-viewType--grid .uppy-ProviderBrowserItem-inner img,.uppy-ProviderBrowser-viewType--unsplash .uppy-ProviderBrowserItem-inner img{border-radius:4px;height:100%;-o-object-fit:cover;object-fit:cover;width:100%}.uppy-ProviderBrowser-viewType--grid .uppy-ProviderBrowserItem-author,.uppy-ProviderBrowser-viewType--unsplash .uppy-ProviderBrowserItem-author{background:#0000004d;bottom:0;color:#fff;display:none;font-size:12px;font-weight:500;left:0;margin:0;padding:5px;position:absolute;text-decoration:none;width:100%}.uppy-ProviderBrowser-viewType--grid .uppy-ProviderBrowserItem-author:hover,.uppy-ProviderBrowser-viewType--unsplash .uppy-ProviderBrowserItem-author:hover{background:#0006;text-decoration:underline}.uppy-ProviderBrowser-viewType--grid .uppy-ProviderBrowserItem-checkbox,.uppy-ProviderBrowser-viewType--unsplash .uppy-ProviderBrowserItem-checkbox{background-color:#1269cf;border-radius:50%;height:26px;opacity:0;position:absolute;right:16px;top:16px;width:26px;z-index:1002}.uppy-ProviderBrowser-viewType--grid .uppy-ProviderBrowserItem-checkbox:after,.uppy-ProviderBrowser-viewType--unsplash .uppy-ProviderBrowserItem-checkbox:after{height:7px;inset-inline-start:7px;top:8px;width:12px}.uppy-ProviderBrowser-viewType--grid .uppy-ProviderBrowserItem--is-checked .uppy-ProviderBrowserItem-checkbox,.uppy-ProviderBrowser-viewType--unsplash .uppy-ProviderBrowserItem--is-checked .uppy-ProviderBrowserItem-checkbox{opacity:1}.uppy-ProviderBrowser-viewType--grid .uppy-ProviderBrowserItem-checkbox--grid:focus+label .uppy-ProviderBrowserItem-author,.uppy-ProviderBrowser-viewType--grid .uppy-ProviderBrowserItem-checkbox--grid:hover+label .uppy-ProviderBrowserItem-author,.uppy-ProviderBrowser-viewType--unsplash .uppy-ProviderBrowserItem-checkbox--grid:focus+label .uppy-ProviderBrowserItem-author,.uppy-ProviderBrowser-viewType--unsplash .uppy-ProviderBrowserItem-checkbox--grid:hover+label .uppy-ProviderBrowserItem-author{display:block}.uppy-ProviderBrowser-viewType--grid .uppy-ProviderBrowserItem-checkbox--grid:focus+label,.uppy-ProviderBrowser-viewType--unsplash .uppy-ProviderBrowserItem-checkbox--grid:focus+label{box-shadow:0 0 0 3px #1269cf80}.uppy-ProviderBrowser-viewType--grid .uppy-ProviderBrowserItem-checkbox--grid:focus+label:focus,.uppy-ProviderBrowser-viewType--unsplash .uppy-ProviderBrowserItem-checkbox--grid:focus+label:focus{outline:none}.uppy-ProviderBrowser-viewType--grid .uppy-ProviderBrowserItem-checkbox--grid:focus+label::-moz-focus-inner,.uppy-ProviderBrowser-viewType--unsplash .uppy-ProviderBrowserItem-checkbox--grid:focus+label::-moz-focus-inner{border:0}.uppy-ProviderBrowser-viewType--list{background-color:#fff}[data-uppy-theme=dark] .uppy-ProviderBrowser-viewType--list{background-color:#1f1f1f}.uppy-ProviderBrowser-viewType--list li.uppy-ProviderBrowserItem{align-items:center;display:flex;margin:0;padding:7px 15px}[data-uppy-theme=dark] .uppy-ProviderBrowser-viewType--list li.uppy-ProviderBrowserItem{color:#eaeaea}.uppy-ProviderBrowser-viewType--list li.uppy-ProviderBrowserItem--disabled{opacity:.6}.uppy-ProviderBrowser-viewType--list .uppy-ProviderBrowserItem-checkbox{background-color:#fff;border:1px solid #cfcfcf;border-radius:3px;height:17px;margin-inline-end:15px;width:17px}.uppy-ProviderBrowser-viewType--list .uppy-ProviderBrowserItem-checkbox:focus{border:1px solid #1269cf;box-shadow:0 0 0 3px #1269cf40;outline:none}.uppy-ProviderBrowser-viewType--list .uppy-ProviderBrowserItem-checkbox:after{height:5px;inset-inline-start:3px;opacity:0;top:4px;width:9px}[data-uppy-theme=dark] .uppy-ProviderBrowser-viewType--list .uppy-ProviderBrowserItem-checkbox:focus{border-color:#02baf2b3;box-shadow:0 0 0 3px #02baf233}.uppy-ProviderBrowser-viewType--list .uppy-ProviderBrowserItem--is-checked .uppy-ProviderBrowserItem-checkbox,.uppy-ProviderBrowser-viewType--list .uppy-ProviderBrowserItem--is-partial .uppy-ProviderBrowserItem-checkbox{background-color:#1269cf;border-color:#1269cf}.uppy-ProviderBrowser-viewType--list .uppy-ProviderBrowserItem--is-checked .uppy-ProviderBrowserItem-checkbox:after,.uppy-ProviderBrowser-viewType--list .uppy-ProviderBrowserItem--is-partial .uppy-ProviderBrowserItem-checkbox:after{opacity:1}.uppy-ProviderBrowser-viewType--list .uppy-ProviderBrowserItem-inner{align-items:center;color:inherit;display:flex;font-family:-apple-system,system-ui,BlinkMacSystemFont,Segoe UI,Segoe UI Symbol,Segoe UI Emoji,Apple Color Emoji,Roboto,Helvetica,Arial,sans-serif;overflow:hidden;padding:2px;text-overflow:ellipsis;white-space:nowrap}.uppy-ProviderBrowser-viewType--list .uppy-ProviderBrowserItem-inner:focus{outline:none;text-decoration:underline}.uppy-ProviderBrowser-viewType--list .uppy-ProviderBrowserItem-inner img,.uppy-ProviderBrowser-viewType--list .uppy-ProviderBrowserItem-inner svg{margin-inline-end:8px}.uppy-ProviderBrowser-viewType--list .uppy-ProviderBrowserItem-inner span{line-height:1.2;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.uppy-ProviderBrowser-viewType--list .uppy-ProviderBrowserItem--disabled .uppy-ProviderBrowserItem-inner{cursor:default}.uppy-ProviderBrowser-viewType--list .uppy-ProviderBrowserItem-iconWrap{margin-inline-end:7px;width:20px}.uppy-ProviderBrowserItem-checkbox{cursor:pointer;flex-shrink:0;position:relative}.uppy-ProviderBrowserItem-checkbox:disabled,.uppy-ProviderBrowserItem-checkbox:disabled:after{cursor:default}[data-uppy-theme=dark] .uppy-ProviderBrowserItem-checkbox{background-color:#1f1f1f;border-color:#939393}[data-uppy-theme=dark] .uppy-ProviderBrowserItem--is-checked .uppy-ProviderBrowserItem-checkbox{background-color:#333}.uppy-ProviderBrowserItem--is-checked .uppy-ProviderBrowserItem-checkbox:after{border-bottom:2px solid #eaeaea;border-left:2px solid #eaeaea;content:"";cursor:pointer;position:absolute;transform:rotate(-45deg)}.uppy-ProviderBrowserItem--is-partial .uppy-ProviderBrowserItem-checkbox:after{background-color:#eaeaea!important;content:""!important;height:2px!important;left:20%!important;position:absolute!important;right:20%!important;top:50%!important;transform:translateY(-50%)!important}.uppy-SearchProvider{align-items:center;display:flex;flex:1;flex-direction:column;height:100%;justify-content:center;width:100%}[data-uppy-theme=dark] .uppy-SearchProvider{background-color:#1f1f1f}.uppy-SearchProvider-input{margin-bottom:15px;max-width:650px;width:90%}.uppy-size--md .uppy-SearchProvider-input{margin-bottom:20px}.uppy-SearchProvider-input::-webkit-search-cancel-button{display:none}.uppy-SearchProvider-searchButton{padding:13px 25px}.uppy-size--md .uppy-SearchProvider-searchButton{padding:13px 30px}.uppy-DashboardContent-panelBody{align-items:center;display:flex;flex:1;justify-content:center}[data-uppy-theme=dark] .uppy-DashboardContent-panelBody{background-color:#1f1f1f}.uppy-Provider-auth,.uppy-Provider-empty,.uppy-Provider-error,.uppy-Provider-loading{align-items:center;color:#939393;display:flex;flex:1;flex-flow:column wrap;justify-content:center}.uppy-Provider-empty{color:#939393}.uppy-Provider-authIcon svg{height:75px;width:100px}.uppy-Provider-authTitle{color:#757575;font-size:17px;font-weight:400;line-height:1.4;margin-bottom:30px;max-width:500px;padding:0 15px;text-align:center}.uppy-size--md .uppy-Provider-authTitle{font-size:20px}[data-uppy-theme=dark] .uppy-Provider-authTitle{color:#cfcfcf}.uppy-Provider-btn-google{align-items:center;background:#4285f4;display:flex;padding:8px 12px!important}.uppy-Provider-btn-google:hover{background-color:#1266f1}.uppy-Provider-btn-google:focus{box-shadow:0 0 0 3px #4285f466;outline:none}.uppy-Provider-btn-google svg{margin-right:8px}.uppy-Provider-breadcrumbs{color:#525252;flex:1;font-size:12px;margin-bottom:10px;text-align:start}.uppy-size--md .uppy-Provider-breadcrumbs{margin-bottom:0}[data-uppy-theme=dark] .uppy-Provider-breadcrumbs{color:#eaeaea}.uppy-Provider-breadcrumbsIcon{color:#525252;display:inline-block;line-height:1;margin-inline-end:4px;vertical-align:middle}.uppy-Provider-breadcrumbsIcon svg{height:13px;width:13px;fill:#525252}.uppy-Provider-breadcrumbs button{border-radius:3px;display:inline-block;line-height:inherit;padding:4px}.uppy-Provider-breadcrumbs button:focus{outline:none}.uppy-Provider-breadcrumbs button::-moz-focus-inner{border:0}.uppy-Provider-breadcrumbs button:hover{color:#0e51a0}.uppy-Provider-breadcrumbs button:focus{background-color:#dfe6f1}[data-uppy-theme=dark] .uppy-Provider-breadcrumbs button:focus{background-color:#333}.uppy-Provider-breadcrumbs button:not(:last-of-type){text-decoration:underline}.uppy-Provider-breadcrumbs button:last-of-type{color:#333;cursor:normal;font-weight:500;pointer-events:none}.uppy-Provider-breadcrumbs button:hover{cursor:pointer}[data-uppy-theme=dark] .uppy-Provider-breadcrumbs button{color:#eaeaea}.uppy-ProviderBrowser{display:flex;flex:1;flex-direction:column;font-size:14px;font-weight:400;height:100%}.uppy-ProviderBrowser-user{color:#333;font-weight:500;margin:0 8px 0 0}[data-uppy-theme=dark] .uppy-ProviderBrowser-user{color:#eaeaea}.uppy-ProviderBrowser-user:after{color:#939393;content:"·";font-weight:400;inset-inline-start:4px;position:relative}.uppy-ProviderBrowser-header{border-bottom:1px solid #eaeaea;position:relative;z-index:1001}[data-uppy-theme=dark] .uppy-ProviderBrowser-header{border-bottom:1px solid #333}.uppy-ProviderBrowser-headerBar{background-color:#fafafa;color:#757575;font-size:12px;line-height:1.4;padding:7px 15px;z-index:1001}.uppy-size--md .uppy-ProviderBrowser-headerBar{align-items:center;display:flex}[data-uppy-theme=dark] .uppy-ProviderBrowser-headerBar{background-color:#1f1f1f}.uppy-ProviderBrowser-headerBar--simple{display:block;justify-content:center;text-align:center}.uppy-ProviderBrowser-headerBar--simple .uppy-Provider-breadcrumbsWrap{display:inline-block;flex:none;vertical-align:middle}.uppy-ProviderBrowser-searchFilter{align-items:center;display:flex;height:30px;margin-bottom:15px;margin-top:15px;padding-left:8px;padding-right:8px;position:relative;width:100%}.uppy-ProviderBrowser-searchFilterInput{background-color:#eaeaea;border:0;border-radius:4px;color:#333;font-family:-apple-system,system-ui,BlinkMacSystemFont,Segoe UI,Segoe UI Symbol,Segoe UI Emoji,Apple Color Emoji,Roboto,Helvetica,Arial,sans-serif;font-size:13px;height:30px;line-height:1.4;outline:0;padding-inline-end:30px;padding-inline-start:30px;width:100%;z-index:1001}.uppy-ProviderBrowser-searchFilterInput::-webkit-search-cancel-button{display:none}[data-uppy-theme=dark] .uppy-ProviderBrowser-searchFilterInput{background-color:#1f1f1f;color:#eaeaea}.uppy-ProviderBrowser-searchFilterInput:focus{background-color:#cfcfcf;border:0}[data-uppy-theme=dark] .uppy-ProviderBrowser-searchFilterInput:focus{background-color:#333}.uppy-ProviderBrowser-searchFilterIcon{color:#757575;height:12px;inset-inline-start:16px;position:absolute;width:12px;z-index:1002}.uppy-ProviderBrowser-searchFilterInput::-moz-placeholder{color:#939393;opacity:1}.uppy-ProviderBrowser-searchFilterInput::placeholder{color:#939393;opacity:1}.uppy-ProviderBrowser-searchFilterReset{border-radius:3px;color:#939393;cursor:pointer;height:22px;inset-inline-end:16px;padding:6px;position:absolute;width:22px;z-index:1002}.uppy-ProviderBrowser-searchFilterReset:focus{outline:none}.uppy-ProviderBrowser-searchFilterReset::-moz-focus-inner{border:0}.uppy-ProviderBrowser-searchFilterReset:focus{box-shadow:0 0 0 3px #1269cf80}.uppy-ProviderBrowser-searchFilterReset:hover{color:#757575}.uppy-ProviderBrowser-searchFilterReset svg{vertical-align:text-top}.uppy-ProviderBrowser-userLogout{border-radius:3px;color:#1269cf;cursor:pointer;line-height:inherit;padding:4px}.uppy-ProviderBrowser-userLogout:focus{outline:none}.uppy-ProviderBrowser-userLogout::-moz-focus-inner{border:0}.uppy-ProviderBrowser-userLogout:hover{color:#0e51a0}.uppy-ProviderBrowser-userLogout:focus{background-color:#dfe6f1}[data-uppy-theme=dark] .uppy-ProviderBrowser-userLogout:focus{background-color:#333}.uppy-ProviderBrowser-userLogout:hover{text-decoration:underline}[data-uppy-theme=dark] .uppy-ProviderBrowser-userLogout{color:#eaeaea}.uppy-ProviderBrowser-body{flex:1;position:relative}.uppy-ProviderBrowser-list{background-color:#fff;border-spacing:0;display:block;flex:1;height:100%;inset:0;list-style:none;margin:0;overflow-x:hidden;overflow-y:auto;padding:0;position:absolute;width:100%;-webkit-overflow-scrolling:touch}[data-uppy-theme=dark] .uppy-ProviderBrowser-list{background-color:#1f1f1f}.uppy-ProviderBrowser-list:focus{outline:none}.uppy-ProviderBrowserItem-inner{cursor:pointer;font-size:13px;font-weight:500}.uppy-ProviderBrowser-footer{align-items:center;background-color:#fff;border-top:1px solid #eaeaea;display:flex;justify-content:space-between;padding:15px}.uppy-ProviderBrowser-footer button{margin-inline-end:8px}[data-uppy-theme=dark] .uppy-ProviderBrowser-footer{background-color:#1f1f1f;border-top:1px solid #333}.uppy-ProviderBrowser-footer-buttons{flex-shrink:0}.uppy-ProviderBrowser-footer-error{color:#e32437;line-height:18px}@media(max-width:426px){.uppy-ProviderBrowser-footer{align-items:stretch;flex-direction:column-reverse}.uppy-ProviderBrowser-footer-error{padding-bottom:10px}}.picker-dialog-bg{z-index:20000!important}.picker-dialog{z-index:20001!important}.uppy-Dashboard-Item-previewInnerWrap{align-items:center;border-radius:3px;box-shadow:0 0 2px #0006;display:flex;flex-direction:column;height:100%;justify-content:center;overflow:hidden;position:relative;width:100%}.uppy-size--md .uppy-Dashboard-Item-previewInnerWrap{box-shadow:0 1px 2px #00000026}.uppy-Dashboard--singleFile .uppy-Dashboard-Item-previewInnerWrap{box-shadow:none}.uppy-Dashboard-Item-previewInnerWrap:after{background-color:#000000a6;content:"";display:none;inset:0;position:absolute;z-index:1001}.uppy-Dashboard-Item-previewLink{inset:0;position:absolute;z-index:1002}.uppy-Dashboard-Item-previewLink:focus{box-shadow:inset 0 0 0 3px #579df0}[data-uppy-theme=dark] .uppy-Dashboard-Item-previewLink:focus{box-shadow:inset 0 0 0 3px #016c8d}.uppy-Dashboard-Item-preview img.uppy-Dashboard-Item-previewImg{border-radius:3px;height:100%;-o-object-fit:cover;object-fit:cover;transform:translateZ(0);width:100%}.uppy-Dashboard--singleFile .uppy-Dashboard-Item-preview img.uppy-Dashboard-Item-previewImg{height:auto;max-height:100%;max-width:100%;-o-object-fit:contain;object-fit:contain;padding:10px;width:auto}.uppy-Dashboard-Item-progress{color:#fff;left:50%;position:absolute;text-align:center;top:50%;transform:translate(-50%,-50%);transition:all .35 ease;width:120px;z-index:1002}.uppy-Dashboard-Item-progressIndicator{color:#fff;display:inline-block;height:38px;opacity:.9;width:38px}.uppy-size--md .uppy-Dashboard-Item-progressIndicator{height:55px;width:55px}button.uppy-Dashboard-Item-progressIndicator{cursor:pointer}button.uppy-Dashboard-Item-progressIndicator:focus{outline:none}button.uppy-Dashboard-Item-progressIndicator::-moz-focus-inner{border:0}button.uppy-Dashboard-Item-progressIndicator:focus .uppy-Dashboard-Item-progressIcon--bg,button.uppy-Dashboard-Item-progressIndicator:focus .uppy-Dashboard-Item-progressIcon--retry{fill:#579df0}.uppy-Dashboard-Item-progressIcon--circle{height:100%;width:100%}.uppy-Dashboard-Item-progressIcon--bg{stroke:#fff6}.uppy-Dashboard-Item-progressIcon--progress{transition:stroke-dashoffset .5s ease-out;stroke:#fff}.uppy-Dashboard-Item-progressIcon--play{transition:all .2s;fill:#fff;stroke:#fff}.uppy-Dashboard-Item-progressIcon--cancel{transition:all .2s;fill:#fff}.uppy-Dashboard-Item-progressIcon--pause{transition:all .2s;fill:#fff;stroke:#fff}.uppy-Dashboard-Item-progressIcon--check{transition:all .2s;fill:#fff}.uppy-Dashboard-Item-progressIcon--retry{fill:#fff}.uppy-Dashboard-Item.is-complete .uppy-Dashboard-Item-progress{inset-inline-end:-8px;inset-inline-start:auto;top:-9px;transform:none;width:auto}.uppy-Dashboard-Item.is-error .uppy-Dashboard-Item-progressIndicator{height:18px;width:18px}.uppy-size--md .uppy-Dashboard-Item.is-error .uppy-Dashboard-Item-progressIndicator{height:28px;width:28px}.uppy-Dashboard-Item.is-complete .uppy-Dashboard-Item-progressIndicator{height:18px;opacity:1;width:18px}.uppy-size--md .uppy-Dashboard-Item.is-complete .uppy-Dashboard-Item-progressIndicator{height:22px;width:22px}.uppy-Dashboard-Item.is-processing .uppy-Dashboard-Item-progress{opacity:0}.uppy-Dashboard-Item-fileInfo{padding-inline-end:5px}.uppy-Dashboard--singleFile .uppy-Dashboard-Item-fileInfo{padding-inline-end:10px}.uppy-size--md.uppy-Dashboard--singleFile .uppy-Dashboard-Item-fileInfo{padding-inline-end:15px}.uppy-Dashboard-Item-name{font-size:12px;font-weight:500;line-height:1.3;margin-bottom:5px;word-wrap:anywhere;word-break:break-all}[data-uppy-theme=dark] .uppy-Dashboard-Item-name{color:#eaeaea}.uppy-size--md.uppy-Dashboard--singleFile .uppy-Dashboard-Item-name{font-size:14px;line-height:1.4}.uppy-Dashboard-Item-fileName{align-items:baseline;display:flex}.uppy-Dashboard-Item-fileName button{margin-left:5px}.uppy-Dashboard-Item-author{color:#757575;display:inline-block;font-size:11px;font-weight:400;line-height:1;margin-bottom:5px;vertical-align:bottom}.uppy-Dashboard-Item-author a{color:#757575}.uppy-Dashboard-Item-status{color:#757575;font-size:11px;font-weight:400;line-height:1}[data-uppy-theme=dark] .uppy-Dashboard-Item-status{color:#bbb}.uppy-Dashboard-Item-statusSize{display:inline-block;margin-bottom:5px;text-transform:uppercase;vertical-align:bottom}.uppy-Dashboard-Item-reSelect{color:#1269cf;font-family:inherit;font-size:inherit;font-weight:600}.uppy-Dashboard-Item-errorMessage{background-color:#fdeff1;color:#a51523;font-size:11px;font-weight:500;line-height:1.3;padding:5px 6px}.uppy-Dashboard-Item-errorMessageBtn{color:#a51523;cursor:pointer;font-size:11px;font-weight:500;text-decoration:underline}.uppy-Dashboard-Item-preview .uppy-Dashboard-Item-errorMessage{display:none}.uppy-size--md .uppy-Dashboard-Item-preview .uppy-Dashboard-Item-errorMessage{border-bottom-left-radius:3px;border-bottom-right-radius:3px;border-top:1px solid #f7c2c8;bottom:0;display:block;left:0;line-height:1.4;padding:6px 8px;position:absolute;right:0}.uppy-Dashboard-Item-fileInfo .uppy-Dashboard-Item-errorMessage{border:1px solid #f7c2c8;border-radius:3px;display:inline-block;position:static}.uppy-size--md .uppy-Dashboard-Item-fileInfo .uppy-Dashboard-Item-errorMessage{display:none}.uppy-Dashboard-Item-action{color:#939393;cursor:pointer}.uppy-Dashboard-Item-action:focus{outline:none}.uppy-Dashboard-Item-action::-moz-focus-inner{border:0}.uppy-Dashboard-Item-action:focus{box-shadow:0 0 0 3px #1269cf80}.uppy-Dashboard-Item-action:hover{color:#1f1f1f;opacity:1}[data-uppy-theme=dark] .uppy-Dashboard-Item-action{color:#cfcfcf}[data-uppy-theme=dark] .uppy-Dashboard-Item-action:focus{outline:none}[data-uppy-theme=dark] .uppy-Dashboard-Item-action::-moz-focus-inner{border:0}[data-uppy-theme=dark] .uppy-Dashboard-Item-action:focus{box-shadow:0 0 0 2px #aae1ffd9}[data-uppy-theme=dark] .uppy-Dashboard-Item-action:hover{color:#eaeaea}.uppy-Dashboard-Item-action--remove{color:#1f1f1f;opacity:.95}.uppy-Dashboard-Item-action--remove:hover{color:#000;opacity:1}.uppy-size--md .uppy-Dashboard-Item-action--remove{height:18px;inset-inline-end:-8px;padding:0;position:absolute;top:-8px;width:18px;z-index:1002}.uppy-size--md .uppy-Dashboard-Item-action--remove:focus{border-radius:50%}.uppy-Dashboard--singleFile.uppy-size--height-md .uppy-Dashboard-Item-action--remove{inset-inline-end:8px;position:absolute;top:8px}[data-uppy-theme=dark] .uppy-Dashboard-Item-action--remove{color:#525252}[data-uppy-theme=dark] .uppy-Dashboard-Item-action--remove:hover{color:#333}.uppy-Dashboard:not(.uppy-size--md):not(.uppy-Dashboard--singleFile.uppy-size--height-md) .uppy-Dashboard-Item-actionWrapper{align-items:center;display:flex}.uppy-Dashboard:not(.uppy-size--md):not(.uppy-Dashboard--singleFile.uppy-size--height-md) .uppy-Dashboard-Item-action{height:22px;margin-left:3px;padding:3px;width:22px}.uppy-Dashboard:not(.uppy-size--md):not(.uppy-Dashboard--singleFile.uppy-size--height-md) .uppy-Dashboard-Item-action:focus{border-radius:3px}.uppy-size--md .uppy-Dashboard-Item-action--copyLink,.uppy-size--md .uppy-Dashboard-Item-action--edit{height:16px;padding:0;width:16px}.uppy-size--md .uppy-Dashboard-Item-action--copyLink:focus,.uppy-size--md .uppy-Dashboard-Item-action--edit:focus{border-radius:3px}.uppy-Dashboard-Item{align-items:center;border-bottom:1px solid #eaeaea;display:flex;padding:10px}.uppy-Dashboard:not(.uppy-Dashboard--singleFile) .uppy-Dashboard-Item{padding-inline-end:0}[data-uppy-theme=dark] .uppy-Dashboard-Item{border-bottom:1px solid #333}.uppy-size--md .uppy-Dashboard-Item{border-bottom:0;display:block;float:inline-start;height:215px;margin:5px 15px;padding:0;position:relative;width:calc(33.333% - 30px)}.uppy-size--lg .uppy-Dashboard-Item{height:190px;margin:5px 15px;padding:0;width:calc(25% - 30px)}.uppy-size--xl .uppy-Dashboard-Item{height:210px;padding:0;width:calc(20% - 30px)}.uppy-Dashboard--singleFile .uppy-Dashboard-Item{border-bottom:0;display:flex;flex-direction:column;height:100%;max-width:400px;padding:15px;position:relative;width:100%}.uppy-Dashboard-Item.is-ghost .uppy-Dashboard-Item-previewInnerWrap{opacity:.2}.uppy-Dashboard-Item.is-ghost .uppy-Dashboard-Item-name{opacity:.7}.uppy-Dashboard-Item.is-ghost .uppy-Dashboard-Item-preview:before{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='35' height='39' viewBox='0 0 35 39'%3E%3Cpath fill='%2523000' d='M1.708 38.66c1.709 0 3.417-3.417 6.834-3.417s5.125 3.417 8.61 3.417c3.348 0 5.056-3.417 8.473-3.417 4.305 0 5.125 3.417 6.833 3.417.889 0 1.709-.889 1.709-1.709v-19.68C34.167-5.757 0-5.757 0 17.271v19.68c0 .82.888 1.709 1.708 1.709m8.542-17.084a3.383 3.383 0 0 1-3.417-3.416 3.383 3.383 0 0 1 3.417-3.417 3.383 3.383 0 0 1 3.417 3.417 3.383 3.383 0 0 1-3.417 3.416m13.667 0A3.383 3.383 0 0 1 20.5 18.16a3.383 3.383 0 0 1 3.417-3.417 3.383 3.383 0 0 1 3.416 3.417 3.383 3.383 0 0 1-3.416 3.416'/%3E%3C/svg%3E");background-position:50% 10px;background-repeat:no-repeat;background-size:25px;content:"";inset:0;opacity:.5;position:absolute;z-index:1005}.uppy-size--md .uppy-Dashboard-Item.is-ghost .uppy-Dashboard-Item-preview:before{background-position:50% 50%;background-size:40px}.uppy-Dashboard--singleFile .uppy-Dashboard-Item.is-ghost .uppy-Dashboard-Item-preview:before{background-position:50% 50%;background-size:30%}.uppy-Dashboard-Item-preview{flex-grow:0;flex-shrink:0;height:50px;position:relative;width:50px}.uppy-size--md .uppy-Dashboard-Item-preview{height:140px;width:100%}.uppy-size--lg .uppy-Dashboard-Item-preview{height:120px}.uppy-size--xl .uppy-Dashboard-Item-preview{height:140px}.uppy-Dashboard--singleFile .uppy-Dashboard-Item-preview{flex-grow:1;max-height:75%;width:100%}.uppy-Dashboard--singleFile.uppy-size--md .uppy-Dashboard-Item-preview{max-height:100%}.uppy-Dashboard-Item-fileInfoAndButtons{align-items:center;display:flex;flex-grow:1;justify-content:space-between;padding-inline-end:8px;padding-inline-start:12px}.uppy-Dashboard--singleFile .uppy-Dashboard-Item-fileInfoAndButtons,.uppy-size--md .uppy-Dashboard-Item-fileInfoAndButtons{align-items:flex-start;padding:9px 0 0}.uppy-Dashboard--singleFile .uppy-Dashboard-Item-fileInfoAndButtons{flex-grow:0;width:100%}.uppy-Dashboard-Item-fileInfo{flex-grow:1;flex-shrink:1}.uppy-Dashboard-Item-actionWrapper{flex-grow:0;flex-shrink:0}.uppy-Dashboard-Item.is-error .uppy-Dashboard-Item-previewInnerWrap:after,.uppy-Dashboard-Item.is-inprogress .uppy-Dashboard-Item-previewInnerWrap:after{display:block}.uppy-Dashboard-Item-errorDetails{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#939393;border:none;border-radius:50%;color:#fff;cursor:help;flex-shrink:0;font-size:10px;font-weight:600;height:13px;inset-inline-start:2px;line-height:12px;position:relative;text-align:center;top:0;width:13px}.uppy-Dashboard-Item-errorDetails:after{line-height:1.3;word-wrap:break-word}.uppy-Dashboard-FileCard{background-color:#fff;border-radius:5px;box-shadow:0 0 10px 4px #0000001a;display:flex;flex-direction:column;height:100%;inset:0;position:absolute;width:100%;z-index:1005}.uppy-Dashboard-FileCard .uppy-DashboardContent-bar{border-top-left-radius:5px;border-top-right-radius:5px}.uppy-Dashboard-FileCard .uppy-Dashboard-FileCard-actions{border-bottom-left-radius:5px;border-bottom-right-radius:5px}.uppy-Dashboard-FileCard-inner{display:flex;flex-direction:column;flex-grow:1;flex-shrink:1;height:100%;min-height:0}.uppy-Dashboard-FileCard-preview{align-items:center;border-bottom:1px solid #eaeaea;display:flex;flex-grow:0;flex-shrink:1;height:60%;justify-content:center;min-height:0;position:relative}[data-uppy-theme=dark] .uppy-Dashboard-FileCard-preview{background-color:#333;border-bottom:0}.uppy-Dashboard-FileCard-preview img.uppy-Dashboard-Item-previewImg{border-radius:3px;box-shadow:0 3px 20px #00000026;flex:0 0 auto;max-height:90%;max-width:90%;-o-object-fit:cover;object-fit:cover}.uppy-Dashboard-FileCard-edit{background-color:#00000080;border-radius:50px;color:#fff;font-size:13px;inset-inline-end:10px;padding:7px 15px;position:absolute;top:10px}.uppy-Dashboard-FileCard-edit:focus{outline:none}.uppy-Dashboard-FileCard-edit::-moz-focus-inner{border:0}.uppy-Dashboard-FileCard-edit:focus{box-shadow:0 0 0 3px #1269cf80}.uppy-Dashboard-FileCard-edit:hover{background-color:#000c}.uppy-Dashboard-FileCard-info{flex-grow:0;flex-shrink:0;height:40%;overflow-y:auto;padding:30px 20px 20px;-webkit-overflow-scrolling:touch}[data-uppy-theme=dark] .uppy-Dashboard-FileCard-info{background-color:#1f1f1f}.uppy-Dashboard-FileCard-fieldset{border:0;font-size:0;margin:auto auto 12px;max-width:640px;padding:0}.uppy-Dashboard-FileCard-label{color:#525252;display:inline-block;font-size:12px;vertical-align:middle;width:22%}.uppy-size--md .uppy-Dashboard-FileCard-label{font-size:14px}[data-uppy-theme=dark] .uppy-Dashboard-FileCard-label{color:#eaeaea}.uppy-Dashboard-FileCard-input{display:inline-block;vertical-align:middle;width:78%}.uppy-Dashboard-FileCard-actions{align-items:center;background-color:#fafafa;border-top:1px solid #eaeaea;display:flex;flex-grow:0;flex-shrink:0;height:55px;padding:0 15px}.uppy-size--md .uppy-Dashboard-FileCard-actions{height:65px}[data-uppy-theme=dark] .uppy-Dashboard-FileCard-actions{background-color:#1f1f1f;border-top:1px solid #333}.uppy-Dashboard-FileCard-actionsBtn{margin-inline-end:10px}.uppy-Informer{bottom:60px;left:0;position:absolute;right:0;text-align:center;z-index:1005}.uppy-Informer span>div{margin-bottom:6px}.uppy-Informer-animated{opacity:0;transform:translateY(350%);transition:all .3s ease-in;z-index:-1000}.uppy-Informer p{background-color:#757575;border-radius:18px;color:#fff;display:inline-block;font-size:12px;font-weight:400;line-height:1.4;margin:0;max-width:90%;padding:6px 15px}.uppy-size--md .uppy-Informer p{font-size:14px;line-height:1.3;max-width:500px;padding:10px 20px}[data-uppy-theme=dark] .uppy-Informer p{background-color:#333}.uppy-Informer p span{background-color:#fff;border-radius:50%;color:#525252;display:inline-block;font-size:10px;height:13px;inset-inline-start:3px;line-height:12px;margin-inline-start:-1px;position:relative;top:-1px;vertical-align:middle;width:13px}.uppy-Informer p span:hover{cursor:help}.uppy-Informer p span:after{line-height:1.3;word-wrap:break-word}.uppy-Root [aria-label][role~=tooltip]{position:relative}.uppy-Root [aria-label][role~=tooltip]:after,.uppy-Root [aria-label][role~=tooltip]:before{backface-visibility:hidden;box-sizing:border-box;opacity:0;pointer-events:none;position:absolute;transform:translateZ(0);transform-origin:top;transition:all var(--microtip-transition-duration,.18s) var(--microtip-transition-easing,ease-in-out) var(--microtip-transition-delay,0s);will-change:transform;z-index:10}.uppy-Root [aria-label][role~=tooltip]:before{background-size:100% auto!important;content:""}.uppy-Root [aria-label][role~=tooltip]:after{background:#111111e6;border-radius:4px;box-sizing:initial;color:#fff;content:attr(aria-label);font-size:var(--microtip-font-size,13px);font-weight:var(--microtip-font-weight,normal);padding:.5em 1em;text-transform:var(--microtip-text-transform,none);white-space:nowrap}.uppy-Root [aria-label][role~=tooltip]:focus:after,.uppy-Root [aria-label][role~=tooltip]:focus:before,.uppy-Root [aria-label][role~=tooltip]:hover:after,.uppy-Root [aria-label][role~=tooltip]:hover:before{opacity:1;pointer-events:auto}.uppy-Root [role~=tooltip][data-microtip-position|=top]:before{background:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='36' height='12'%3E%3Cpath fill='rgba(17, 17, 17, 0.9)' d='M2.658 0h32.004c-6 0-11.627 12.002-16.002 12.002S8.594 0 2.658 0'/%3E%3C/svg%3E") no-repeat;bottom:100%;height:6px;left:50%;margin-bottom:5px;transform:translate3d(-50%,0,0);width:18px}.uppy-Root [role~=tooltip][data-microtip-position|=top]:after{bottom:100%;left:50%;margin-bottom:11px;transform:translate3d(-50%,0,0)}.uppy-Root [role~=tooltip][data-microtip-position=top]:hover:after,.uppy-Root [role~=tooltip][data-microtip-position|=top]:hover:before{transform:translate3d(-50%,-5px,0)}.uppy-Root [role~=tooltip][data-microtip-position=top-left]:after{bottom:100%;transform:translate3d(calc(-100% + 16px),0,0)}.uppy-Root [role~=tooltip][data-microtip-position=top-left]:hover:after{transform:translate3d(calc(-100% + 16px),-5px,0)}.uppy-Root [role~=tooltip][data-microtip-position=top-right]:after{bottom:100%;transform:translate3d(-16px,0,0)}.uppy-Root [role~=tooltip][data-microtip-position=top-right]:hover:after{transform:translate3d(-16px,-5px,0)}.uppy-Root [role~=tooltip][data-microtip-position|=bottom]:before{background:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='36' height='12'%3E%3Cpath fill='rgba(17, 17, 17, 0.9)' d='M33.342 12H1.338c6 0 11.627-12.002 16.002-12.002S27.406 12 33.342 12'/%3E%3C/svg%3E") no-repeat;bottom:auto;height:6px;left:50%;margin-bottom:0;margin-top:5px;top:100%;transform:translate3d(-50%,-10px,0);width:18px}.uppy-Root [role~=tooltip][data-microtip-position|=bottom]:after{left:50%;margin-top:11px;top:100%;transform:translate3d(-50%,-10px,0)}.uppy-Root [role~=tooltip][data-microtip-position=bottom]:hover:after,.uppy-Root [role~=tooltip][data-microtip-position|=bottom]:hover:before{transform:translate3d(-50%,0,0)}.uppy-Root [role~=tooltip][data-microtip-position=bottom-left]:after{top:100%;transform:translate3d(calc(-100% + 16px),-10px,0)}.uppy-Root [role~=tooltip][data-microtip-position=bottom-left]:hover:after{transform:translate3d(calc(-100% + 16px),0,0)}.uppy-Root [role~=tooltip][data-microtip-position=bottom-right]:after{top:100%;transform:translate3d(-16px,-10px,0)}.uppy-Root [role~=tooltip][data-microtip-position=bottom-right]:hover:after{transform:translate3d(-16px,0,0)}.uppy-Root [role~=tooltip][data-microtip-position=left]:after,.uppy-Root [role~=tooltip][data-microtip-position=left]:before{inset:50% 100% auto auto;transform:translate3d(10px,-50%,0)}.uppy-Root [role~=tooltip][data-microtip-position=left]:before{background:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='36'%3E%3Cpath fill='rgba(17, 17, 17, 0.9)' d='M0 33.342V1.338c0 6 12.002 11.627 12.002 16.002S0 27.406 0 33.342'/%3E%3C/svg%3E") no-repeat;height:18px;margin-bottom:0;margin-right:5px;width:6px}.uppy-Root [role~=tooltip][data-microtip-position=left]:after{margin-right:11px}.uppy-Root [role~=tooltip][data-microtip-position=left]:hover:after,.uppy-Root [role~=tooltip][data-microtip-position=left]:hover:before{transform:translate3d(0,-50%,0)}.uppy-Root [role~=tooltip][data-microtip-position=right]:after,.uppy-Root [role~=tooltip][data-microtip-position=right]:before{bottom:auto;left:100%;top:50%;transform:translate3d(-10px,-50%,0)}.uppy-Root [role~=tooltip][data-microtip-position=right]:before{background:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='36'%3E%3Cpath fill='rgba(17, 17, 17, 0.9)' d='M12 2.658v32.004c0-6-12.002-11.627-12.002-16.002S12 8.594 12 2.658'/%3E%3C/svg%3E") no-repeat;height:18px;margin-bottom:0;margin-left:5px;width:6px}.uppy-Root [role~=tooltip][data-microtip-position=right]:after{margin-left:11px}.uppy-Root [role~=tooltip][data-microtip-position=right]:hover:after,.uppy-Root [role~=tooltip][data-microtip-position=right]:hover:before{transform:translate3d(0,-50%,0)}.uppy-Root [role~=tooltip][data-microtip-size=small]:after{white-space:normal;width:80px}.uppy-Root [role~=tooltip][data-microtip-size=medium]:after{white-space:normal;width:150px}.uppy-Root [role~=tooltip][data-microtip-size=large]:after{white-space:normal;width:260px}.uppy-StatusBar{background-color:#fff;color:#fff;display:flex;font-size:12px;font-weight:400;height:46px;line-height:40px;position:relative;transition:height .2s;z-index:1001}[data-uppy-theme=dark] .uppy-StatusBar{background-color:#1f1f1f}.uppy-StatusBar:before{background-color:#eaeaea;content:"";height:2px;inset:0;position:absolute;width:100%}[data-uppy-theme=dark] .uppy-StatusBar:before{background-color:#757575}.uppy-StatusBar[aria-hidden=true]{height:0;overflow-y:hidden}.uppy-StatusBar.is-complete .uppy-StatusBar-progress{background-color:#1bb240}.uppy-StatusBar.is-error .uppy-StatusBar-progress{background-color:#e32437}.uppy-StatusBar.is-complete .uppy-StatusBar-statusIndicator{color:#1bb240}.uppy-StatusBar.is-error .uppy-StatusBar-statusIndicator{color:#e32437}.uppy-StatusBar:not([aria-hidden=true]).is-waiting{background-color:#fff;border-top:1px solid #eaeaea;height:65px}[data-uppy-theme=dark] .uppy-StatusBar:not([aria-hidden=true]).is-waiting{background-color:#1f1f1f;border-top:1px solid #333}.uppy-StatusBar-progress{background-color:#1269cf;height:2px;position:absolute;transition:background-color,width .3s ease-out;z-index:1001}.uppy-StatusBar-progress.is-indeterminate{animation:uppy-StatusBar-ProgressStripes 1s linear infinite;background-image:linear-gradient(45deg,#0000004d 25%,#0000 0 50%,#0000004d 0 75%,#0000 0,#0000);background-size:64px 64px}@keyframes uppy-StatusBar-ProgressStripes{0%{background-position:0 0}to{background-position:64px 0}}.uppy-StatusBar.is-postprocessing .uppy-StatusBar-progress,.uppy-StatusBar.is-preprocessing .uppy-StatusBar-progress{background-color:#f6a623}.uppy-StatusBar.is-waiting .uppy-StatusBar-progress{display:none}.uppy-StatusBar-content{align-items:center;color:#333;display:flex;height:100%;padding-inline-start:10px;position:relative;text-overflow:ellipsis;white-space:nowrap;z-index:1002}.uppy-size--md .uppy-StatusBar-content{padding-inline-start:15px}[data-uppy-theme=dark] .uppy-StatusBar-content{color:#eaeaea}.uppy-StatusBar-status{display:flex;flex-direction:column;font-weight:400;justify-content:center;line-height:1.4;padding-inline-end:.3em}.uppy-StatusBar-statusPrimary{display:flex;font-weight:500;line-height:1}.uppy-StatusBar-statusPrimary button.uppy-StatusBar-details{margin-left:5px}[data-uppy-theme=dark] .uppy-StatusBar-statusPrimary{color:#eaeaea}.uppy-StatusBar-statusSecondary{color:#757575;display:inline-block;font-size:11px;line-height:1.2;margin-top:1px;white-space:nowrap}[data-uppy-theme=dark] .uppy-StatusBar-statusSecondary{color:#bbb}.uppy-StatusBar-statusSecondaryHint{display:inline-block;line-height:1;margin-inline-end:5px;vertical-align:middle}.uppy-size--md .uppy-StatusBar-statusSecondaryHint{margin-inline-end:8px}.uppy-StatusBar-statusIndicator{color:#525252;margin-inline-end:7px;position:relative;top:1px}.uppy-StatusBar-statusIndicator svg{vertical-align:text-bottom}.uppy-StatusBar-actions{align-items:center;bottom:0;display:flex;inset-inline-end:10px;position:absolute;top:0;z-index:1004}.uppy-StatusBar.is-waiting .uppy-StatusBar-actions{background-color:#fafafa;height:100%;padding:0 15px;position:static;width:100%}[data-uppy-theme=dark] .uppy-StatusBar.is-waiting .uppy-StatusBar-actions{background-color:#1f1f1f}.uppy-StatusBar:not([aria-hidden=true]).is-waiting.has-ghosts{flex-direction:column;height:90px}.uppy-size--md .uppy-StatusBar:not([aria-hidden=true]).is-waiting.has-ghosts{flex-direction:row;height:65px}.uppy-StatusBar:not([aria-hidden=true]).is-waiting.has-ghosts .uppy-StatusBar-actions{flex-direction:column;justify-content:center}.uppy-size--md .uppy-StatusBar:not([aria-hidden=true]).is-waiting.has-ghosts .uppy-StatusBar-actions{flex-direction:row;justify-content:normal}.uppy-StatusBar-actionCircleBtn{cursor:pointer;line-height:1;margin:3px;opacity:.9}.uppy-StatusBar-actionCircleBtn:focus{outline:none}.uppy-StatusBar-actionCircleBtn::-moz-focus-inner{border:0}.uppy-StatusBar-actionCircleBtn:focus{box-shadow:0 0 0 3px #1269cf80}[data-uppy-theme=dark] .uppy-StatusBar-actionCircleBtn:focus{outline:none}[data-uppy-theme=dark] .uppy-StatusBar-actionCircleBtn::-moz-focus-inner{border:0}[data-uppy-theme=dark] .uppy-StatusBar-actionCircleBtn:focus{box-shadow:0 0 0 2px #aae1ffd9}.uppy-StatusBar-actionCircleBtn:hover{opacity:1}.uppy-StatusBar-actionCircleBtn:focus{border-radius:50%}.uppy-StatusBar-actionCircleBtn svg{vertical-align:bottom}.uppy-StatusBar-actionBtn{color:#1269cf;display:inline-block;font-size:10px;line-height:inherit;vertical-align:middle}.uppy-size--md .uppy-StatusBar-actionBtn{font-size:11px}.uppy-StatusBar-actionBtn--disabled{opacity:.4}[data-uppy-theme=dark] .uppy-StatusBar-actionBtn--disabled{opacity:.7}.uppy-StatusBar-actionBtn--retry{background-color:#ff4b23;border-radius:8px;color:#fff;height:16px;line-height:1;margin-inline-end:6px;padding:1px 6px 3px 18px;position:relative}.uppy-StatusBar-actionBtn--retry:focus{outline:none}.uppy-StatusBar-actionBtn--retry::-moz-focus-inner{border:0}.uppy-StatusBar-actionBtn--retry:focus{box-shadow:0 0 0 3px #1269cf80}[data-uppy-theme=dark] .uppy-StatusBar-actionBtn--retry:focus{outline:none}[data-uppy-theme=dark] .uppy-StatusBar-actionBtn--retry::-moz-focus-inner{border:0}[data-uppy-theme=dark] .uppy-StatusBar-actionBtn--retry:focus{box-shadow:0 0 0 2px #aae1ffd9}.uppy-StatusBar-actionBtn--retry:hover{background-color:#f92d00}.uppy-StatusBar-actionBtn--retry svg{inset-inline-start:6px;position:absolute;top:3px}.uppy-StatusBar.is-waiting .uppy-StatusBar-actionBtn--upload{background-color:#1bb240;color:#fff;font-size:14px;line-height:1;padding:15px 10px;width:100%}.uppy-StatusBar.is-waiting .uppy-StatusBar-actionBtn--upload:hover{background-color:#189c38}[data-uppy-theme=dark] .uppy-StatusBar.is-waiting .uppy-StatusBar-actionBtn--upload{background-color:#1c8b37}[data-uppy-theme=dark] .uppy-StatusBar.is-waiting .uppy-StatusBar-actionBtn--upload:hover{background-color:#18762f}.uppy-size--md .uppy-StatusBar.is-waiting .uppy-StatusBar-actionBtn--upload{padding:13px 22px;width:auto}.uppy-StatusBar.is-waiting .uppy-StatusBar-actionBtn--upload.uppy-StatusBar-actionBtn--disabled:hover{background-color:#1bb240;cursor:not-allowed}[data-uppy-theme=dark] .uppy-StatusBar.is-waiting .uppy-StatusBar-actionBtn--upload.uppy-StatusBar-actionBtn--disabled:hover{background-color:#1c8b37}.uppy-StatusBar:not(.is-waiting) .uppy-StatusBar-actionBtn--upload{background-color:initial;color:#1269cf}.uppy-StatusBar-actionBtn--uploadNewlyAdded{border-radius:3px;padding-inline-end:3px;padding-bottom:1px;padding-inline-start:3px}.uppy-StatusBar-actionBtn--uploadNewlyAdded:focus{outline:none}.uppy-StatusBar-actionBtn--uploadNewlyAdded::-moz-focus-inner{border:0}.uppy-StatusBar-actionBtn--uploadNewlyAdded:focus{box-shadow:0 0 0 3px #1269cf80}[data-uppy-theme=dark] .uppy-StatusBar-actionBtn--uploadNewlyAdded:focus{outline:none}[data-uppy-theme=dark] .uppy-StatusBar-actionBtn--uploadNewlyAdded::-moz-focus-inner{border:0}[data-uppy-theme=dark] .uppy-StatusBar-actionBtn--uploadNewlyAdded:focus{box-shadow:0 0 0 2px #aae1ffd9}.uppy-StatusBar.is-postprocessing .uppy-StatusBar-actionBtn--uploadNewlyAdded,.uppy-StatusBar.is-preprocessing .uppy-StatusBar-actionBtn--uploadNewlyAdded{display:none}.uppy-StatusBar-actionBtn--done{border-radius:3px;line-height:1;padding:7px 8px}.uppy-StatusBar-actionBtn--done:focus{outline:none}.uppy-StatusBar-actionBtn--done::-moz-focus-inner{border:0}.uppy-StatusBar-actionBtn--done:hover{color:#0e51a0}.uppy-StatusBar-actionBtn--done:focus{background-color:#dfe6f1}[data-uppy-theme=dark] .uppy-StatusBar-actionBtn--done:focus{background-color:#333}[data-uppy-theme=dark] .uppy-StatusBar-actionBtn--done{color:#02baf2}.uppy-size--md .uppy-StatusBar-actionBtn--done{font-size:14px}.uppy-StatusBar-serviceMsg{color:#000;font-size:11px;line-height:1.1;padding-left:10px}.uppy-size--md .uppy-StatusBar-serviceMsg{font-size:14px;padding-left:15px}[data-uppy-theme=dark] .uppy-StatusBar-serviceMsg{color:#eaeaea}.uppy-StatusBar-serviceMsg-ghostsIcon{left:6px;opacity:.5;position:relative;top:2px;vertical-align:text-bottom;width:10px}.uppy-size--md .uppy-StatusBar-serviceMsg-ghostsIcon{left:10px;top:1px;width:15px}.uppy-StatusBar-details{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#939393;border-radius:50%;color:#fff;cursor:help;display:inline-block;font-size:10px;font-weight:600;height:13px;inset-inline-start:2px;line-height:12px;position:relative;text-align:center;top:0;vertical-align:middle;width:13px}.uppy-StatusBar-details:after{line-height:1.3;word-wrap:break-word}.uppy-StatusBar-spinner{animation-duration:1s;animation-iteration-count:infinite;animation-name:uppy-StatusBar-spinnerAnimation;animation-timing-function:linear;fill:#1269cf;margin-inline-end:10px}.uppy-StatusBar.is-postprocessing .uppy-StatusBar-spinner,.uppy-StatusBar.is-preprocessing .uppy-StatusBar-spinner{fill:#f6a623}@keyframes uppy-StatusBar-spinnerAnimation{0%{transform:rotate(0)}to{transform:rotate(1turn)}}.uppy-transition-slideDownUp-enter{opacity:.01;transform:translate3d(0,-105%,0);transition:transform .25s ease-in-out,opacity .25s ease-in-out}.uppy-transition-slideDownUp-enter.uppy-transition-slideDownUp-enter-active{opacity:1;transform:translateZ(0)}.uppy-transition-slideDownUp-leave{opacity:1;transform:translateZ(0);transition:transform .25s ease-in-out,opacity .25s ease-in-out}.uppy-transition-slideDownUp-leave.uppy-transition-slideDownUp-leave-active{opacity:.01;transform:translate3d(0,-105%,0)}@keyframes uppy-Dashboard-fadeIn{0%{opacity:0}to{opacity:1}}@keyframes uppy-Dashboard-fadeOut{0%{opacity:1}to{opacity:0}}@keyframes uppy-Dashboard-slideDownAndFadeIn{0%{opacity:0;transform:translate3d(-50%,-70%,0)}to{opacity:1;transform:translate3d(-50%,-50%,0)}}@keyframes uppy-Dashboard-slideDownAndFadeIn--small{0%{opacity:0;transform:translate3d(0,-20%,0)}to{opacity:1;transform:translateZ(0)}}@keyframes uppy-Dashboard-slideUpFadeOut{0%{opacity:1;transform:translate3d(-50%,-50%,0)}to{opacity:0;transform:translate3d(-50%,-70%,0)}}@keyframes uppy-Dashboard-slideUpFadeOut--small{0%{opacity:1;transform:translateZ(0)}to{opacity:0;transform:translate3d(0,-20%,0)}}.uppy-Dashboard--modal{z-index:1001}.uppy-Dashboard--modal[aria-hidden=true]{display:none}.uppy-Dashboard--modal.uppy-Dashboard--animateOpenClose>.uppy-Dashboard-inner{animation:uppy-Dashboard-slideDownAndFadeIn--small .3s cubic-bezier(0,0,.2,1)}@media only screen and (min-width:820px){.uppy-Dashboard--modal.uppy-Dashboard--animateOpenClose>.uppy-Dashboard-inner{animation:uppy-Dashboard-slideDownAndFadeIn .3s cubic-bezier(0,0,.2,1)}}.uppy-Dashboard--modal.uppy-Dashboard--animateOpenClose>.uppy-Dashboard-overlay{animation:uppy-Dashboard-fadeIn .3s cubic-bezier(0,0,.2,1)}.uppy-Dashboard--modal.uppy-Dashboard--animateOpenClose.uppy-Dashboard--isClosing>.uppy-Dashboard-inner{animation:uppy-Dashboard-slideUpFadeOut--small .3s cubic-bezier(0,0,.2,1)}@media only screen and (min-width:820px){.uppy-Dashboard--modal.uppy-Dashboard--animateOpenClose.uppy-Dashboard--isClosing>.uppy-Dashboard-inner{animation:uppy-Dashboard-slideUpFadeOut .3s cubic-bezier(0,0,.2,1)}}.uppy-Dashboard--modal.uppy-Dashboard--animateOpenClose.uppy-Dashboard--isClosing>.uppy-Dashboard-overlay{animation:uppy-Dashboard-fadeOut .3s cubic-bezier(0,0,.2,1)}.uppy-Dashboard-isFixed{height:100vh;overflow:hidden}.uppy-Dashboard--modal .uppy-Dashboard-overlay{background-color:#00000080;inset:0;position:fixed;z-index:1001}.uppy-Dashboard-inner{background-color:#f4f4f4;border:1px solid #eaeaea;border-radius:5px;max-height:100%;max-width:100%;outline:none;position:relative}.uppy-size--md .uppy-Dashboard-inner{min-height:auto}@media only screen and (min-width:820px){.uppy-Dashboard-inner{height:500px;width:650px}}.uppy-Dashboard--modal .uppy-Dashboard-inner{z-index:1002}[data-uppy-theme=dark] .uppy-Dashboard-inner{background-color:#1f1f1f}.uppy-Dashboard--isDisabled .uppy-Dashboard-inner{cursor:not-allowed}.uppy-Dashboard-innerWrap{border-radius:5px;display:flex;flex-direction:column;height:100%;opacity:0;overflow:hidden;position:relative}.uppy-Dashboard--isInnerWrapVisible .uppy-Dashboard-innerWrap{opacity:1}.uppy-Dashboard--isDisabled .uppy-Dashboard-innerWrap{cursor:not-allowed;filter:grayscale(100%);opacity:.6;-webkit-user-select:none;-moz-user-select:none;user-select:none}.uppy-Dashboard--isDisabled .uppy-ProviderIconBg{fill:#9f9f9f}.uppy-Dashboard--isDisabled [aria-disabled],.uppy-Dashboard--isDisabled [disabled]{cursor:not-allowed;pointer-events:none}.uppy-Dashboard--modal .uppy-Dashboard-inner{border:none;inset:35px 15px 15px;position:fixed}@media only screen and (min-width:820px){.uppy-Dashboard--modal .uppy-Dashboard-inner{box-shadow:0 5px 15px 4px #00000026;left:50%;right:auto;top:50%;transform:translate(-50%,-50%)}}.uppy-Dashboard-close{color:#ffffffe6;cursor:pointer;display:block;font-size:27px;inset-inline-end:-2px;position:absolute;top:-33px;z-index:1005}.uppy-Dashboard-close:focus{outline:none}.uppy-Dashboard-close::-moz-focus-inner{border:0}.uppy-Dashboard-close:focus{color:#6eabf2}@media only screen and (min-width:820px){.uppy-Dashboard-close{font-size:35px;inset-inline-end:-35px;top:-10px}}.uppy-Dashboard-serviceMsg{background-color:#fffbf7;border-bottom:1px solid #edd4b9;border-top:1px solid #edd4b9;font-size:12px;font-weight:500;line-height:1.3;padding:12px 0;position:relative;top:-1px;z-index:1004}.uppy-size--md .uppy-Dashboard-serviceMsg{font-size:14px;line-height:1.4}[data-uppy-theme=dark] .uppy-Dashboard-serviceMsg{background-color:#1f1f1f;border-bottom:1px solid #333;border-top:1px solid #333;color:#eaeaea}.uppy-Dashboard-serviceMsg-title{display:block;line-height:1;margin-bottom:4px;padding-left:42px}.uppy-Dashboard-serviceMsg-text{padding:0 15px}.uppy-Dashboard-serviceMsg-actionBtn{color:#1269cf;font-size:inherit;font-weight:inherit;vertical-align:initial}[data-uppy-theme=dark] .uppy-Dashboard-serviceMsg-actionBtn{color:#02baf2e6}.uppy-Dashboard-serviceMsg-icon{left:15px;position:absolute;top:10px}.uppy-Dashboard-AddFiles{align-items:center;display:flex;flex-direction:column;height:100%;justify-content:center;position:relative;text-align:center}[data-uppy-drag-drop-supported=true] .uppy-Dashboard-AddFiles{border:1px dashed #dfdfdf;border-radius:3px;height:calc(100% - 14px);margin:7px}.uppy-Dashboard-AddFilesPanel .uppy-Dashboard-AddFiles{border:none;height:calc(100% - 54px)}.uppy-Dashboard--modal .uppy-Dashboard-AddFiles{border-color:#cfcfcf}[data-uppy-theme=dark] .uppy-Dashboard-AddFiles{border-color:#757575}.uppy-Dashboard-AddFiles-info{display:none;margin-top:auto;padding-bottom:15px;padding-top:15px}.uppy-size--height-md .uppy-Dashboard-AddFiles-info{display:block}.uppy-size--md .uppy-Dashboard-AddFiles-info{bottom:25px;left:0;padding-bottom:0;padding-top:30px;position:absolute;right:0}[data-uppy-num-acquirers="0"] .uppy-Dashboard-AddFiles-info{margin-top:0}.uppy-Dashboard-browse{color:#1269cf;cursor:pointer}.uppy-Dashboard-browse:focus{outline:none}.uppy-Dashboard-browse::-moz-focus-inner{border:0}.uppy-Dashboard-browse:focus,.uppy-Dashboard-browse:hover{border-bottom:1px solid #1269cf}[data-uppy-theme=dark] .uppy-Dashboard-browse{color:#02baf2e6}[data-uppy-theme=dark] .uppy-Dashboard-browse:focus,[data-uppy-theme=dark] .uppy-Dashboard-browse:hover{border-bottom:1px solid #02baf2}.uppy-Dashboard-browseBtn{display:block;font-size:14px;font-weight:500;margin-bottom:5px;margin-top:8px;width:100%}.uppy-size--md .uppy-Dashboard-browseBtn{font-size:15px;margin:15px auto;padding:13px 44px;width:auto}.uppy-Dashboard-AddFiles-list{display:flex;flex:1;flex-direction:column;margin-top:2px;overflow-y:auto;padding:2px 0;width:100%;-webkit-overflow-scrolling:touch}.uppy-size--md .uppy-Dashboard-AddFiles-list{flex:none;flex-direction:row;flex-wrap:wrap;justify-content:center;margin-top:15px;max-width:600px;overflow-y:visible;padding-top:0}.uppy-DashboardTab{border-bottom:1px solid #eaeaea;text-align:center;width:100%}[data-uppy-theme=dark] .uppy-DashboardTab{border-bottom:1px solid #333}.uppy-size--md .uppy-DashboardTab{border-bottom:none;display:inline-block;margin-bottom:10px;width:auto}.uppy-DashboardTab-btn{align-items:center;-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:initial;color:#525252;cursor:pointer;flex-direction:row;height:100%;justify-content:left;padding:12px 15px;width:100%}.uppy-DashboardTab-btn:focus{outline:none}.uppy-size--md .uppy-DashboardTab-btn{border-radius:5px;flex-direction:column;margin-inline-end:1px;padding:10px 3px;width:86px}[data-uppy-theme=dark] .uppy-DashboardTab-btn{color:#eaeaea}.uppy-DashboardTab-btn::-moz-focus-inner{border:0}.uppy-DashboardTab-btn:hover{background-color:#e9ecef}[data-uppy-theme=dark] .uppy-DashboardTab-btn:hover{background-color:#333}.uppy-DashboardTab-btn:active,.uppy-DashboardTab-btn:focus{background-color:#dfe6f1}[data-uppy-theme=dark] .uppy-DashboardTab-btn:active,[data-uppy-theme=dark] .uppy-DashboardTab-btn:focus{background-color:#525252}.uppy-DashboardTab-btn svg{display:inline-block;max-height:100%;max-width:100%;overflow:hidden;transition:transform .15s ease-in-out;vertical-align:text-top}.uppy-DashboardTab-inner{align-items:center;background-color:#fff;border-radius:8px;box-shadow:0 1px 1px #0000001a,0 1px 2px #0000001a,0 2px 3px #00000005;display:flex;height:32px;justify-content:center;margin-inline-end:10px;width:32px}.uppy-size--md .uppy-DashboardTab-inner{margin-inline-end:0}[data-uppy-theme=dark] .uppy-DashboardTab-inner{background-color:#323232;box-shadow:0 1px 1px #0003,0 1px 2px #0003,0 2px 3px #00000014}.uppy-DashboardTab-name{font-size:14px;font-weight:400}.uppy-size--md .uppy-DashboardTab-name{font-size:12px;line-height:15px;margin-bottom:0;margin-top:8px}.uppy-DashboardTab-iconMyDevice{color:#1269cf}[data-uppy-theme=dark] .uppy-DashboardTab-iconMyDevice{color:#02baf2}.uppy-DashboardTab-iconBox{color:#0061d5}[data-uppy-theme=dark] .uppy-DashboardTab-iconBox{color:#eaeaea}.uppy-DashboardTab-iconDropbox{color:#0061fe}[data-uppy-theme=dark] .uppy-DashboardTab-iconDropbox{color:#eaeaea}.uppy-DashboardTab-iconUnsplash{color:#111}[data-uppy-theme=dark] .uppy-DashboardTab-iconUnsplash{color:#eaeaea}.uppy-DashboardTab-iconWebdav{color:#111}[data-uppy-theme=dark] .uppy-DashboardTab-iconWebdav{color:#eaeaea}.uppy-DashboardTab-iconScreenRec{color:#2c3e50}[data-uppy-theme=dark] .uppy-DashboardTab-iconScreenRec{color:#eaeaea}.uppy-DashboardTab-iconAudio{color:#8030a3}[data-uppy-theme=dark] .uppy-DashboardTab-iconAudio{color:#bf6ee3}.uppy-Dashboard-input{height:.1px;opacity:0;overflow:hidden;position:absolute;width:.1px;z-index:-1}.uppy-DashboardContent-bar{align-items:center;background-color:#fafafa;border-bottom:1px solid #eaeaea;display:flex;flex-shrink:0;height:40px;justify-content:space-between;padding:0 10px;position:relative;width:100%;z-index:1004}.uppy-size--md .uppy-DashboardContent-bar{height:50px;padding:0 15px}[data-uppy-theme=dark] .uppy-DashboardContent-bar{background-color:#1f1f1f;border-bottom:1px solid #333}.uppy-DashboardContent-title{font-size:12px;font-weight:500;left:0;line-height:40px;margin:auto;max-width:170px;overflow-x:hidden;position:absolute;right:0;text-align:center;text-overflow:ellipsis;top:0;white-space:nowrap;width:100%}.uppy-size--md .uppy-DashboardContent-title{font-size:14px;line-height:50px;max-width:300px}[data-uppy-theme=dark] .uppy-DashboardContent-title{color:#eaeaea}.uppy-DashboardContent-back,.uppy-DashboardContent-save{-webkit-appearance:none;background:none;border:0;border-radius:3px;color:inherit;color:#1269cf;cursor:pointer;font-family:inherit;font-size:inherit;font-size:12px;font-weight:400;line-height:1;margin:0;margin-inline-start:-6px;padding:7px 6px}.uppy-DashboardContent-back:focus,.uppy-DashboardContent-save:focus{outline:none}.uppy-DashboardContent-back::-moz-focus-inner,.uppy-DashboardContent-save::-moz-focus-inner{border:0}.uppy-DashboardContent-back:hover,.uppy-DashboardContent-save:hover{color:#0e51a0}.uppy-DashboardContent-back:focus,.uppy-DashboardContent-save:focus{background-color:#dfe6f1}[data-uppy-theme=dark] .uppy-DashboardContent-back:focus,[data-uppy-theme=dark] .uppy-DashboardContent-save:focus{background-color:#333}.uppy-size--md .uppy-DashboardContent-back,.uppy-size--md .uppy-DashboardContent-save{font-size:14px}[data-uppy-theme=dark] .uppy-DashboardContent-back,[data-uppy-theme=dark] .uppy-DashboardContent-save{color:#02baf2}.uppy-DashboardContent-addMore{-webkit-appearance:none;background:none;border:0;border-radius:3px;color:inherit;color:#1269cf;cursor:pointer;font-family:inherit;font-size:inherit;font-weight:500;height:29px;line-height:1;margin:0;margin-inline-end:-5px;padding:7px 8px;width:29px}.uppy-DashboardContent-addMore:focus{outline:none}.uppy-DashboardContent-addMore::-moz-focus-inner{border:0}.uppy-DashboardContent-addMore:hover{color:#0e51a0}.uppy-DashboardContent-addMore:focus{background-color:#dfe6f1}[data-uppy-theme=dark] .uppy-DashboardContent-addMore:focus{background-color:#333}.uppy-size--md .uppy-DashboardContent-addMore{font-size:14px;height:auto;margin-inline-end:-8px;width:auto}[data-uppy-theme=dark] .uppy-DashboardContent-addMore{color:#02baf2}.uppy-DashboardContent-addMore svg{margin-inline-end:4px;vertical-align:initial}.uppy-size--md .uppy-DashboardContent-addMore svg{height:11px;width:11px}.uppy-DashboardContent-addMoreCaption{display:none}.uppy-size--md .uppy-DashboardContent-addMoreCaption{display:inline}.uppy-DashboardContent-panel{background-color:#f5f5f5;flex:1}.uppy-Dashboard-AddFilesPanel,.uppy-DashboardContent-panel{border-radius:5px;display:flex;flex-direction:column;inset:0;overflow:hidden;position:absolute;z-index:1005}.uppy-Dashboard-AddFilesPanel{background:#fafafa;background:linear-gradient(0deg,#fafafa 35%,#fafafad9);box-shadow:0 0 10px 5px #00000026}[data-uppy-theme=dark] .uppy-Dashboard-AddFilesPanel{background-color:#333;background-image:linear-gradient(0deg,#1f1f1f 35%,#1f1f1fd9)}.uppy-Dashboard--isAddFilesPanelVisible .uppy-Dashboard-files{filter:blur(2px)}.uppy-Dashboard-progress{bottom:0;height:12%;left:0;position:absolute;width:100%}.uppy-Dashboard-progressBarContainer.is-active{height:100%;left:0;position:absolute;top:0;width:100%;z-index:1004}.uppy-Dashboard-filesContainer{flex:1;margin:0;overflow-y:hidden;position:relative}.uppy-Dashboard-filesContainer:after{clear:both;content:"";display:table}.uppy-Dashboard-files{flex:1;margin:0;overflow-y:auto;padding:0 0 10px;-webkit-overflow-scrolling:touch}.uppy-size--md .uppy-Dashboard-files{padding-top:10px}.uppy-Dashboard--singleFile .uppy-Dashboard-filesInner{align-items:center;display:flex;height:100%;justify-content:center}.uppy-Dashboard-dropFilesHereHint{align-items:center;background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='48' height='48'%3E%3Cpath fill='%231269CF' d='M24 1v1C11.85 2 2 11.85 2 24s9.85 22 22 22 22-9.85 22-22S36.15 2 24 2zm0 0V0c13.254 0 24 10.746 24 24S37.254 48 24 48 0 37.254 0 24 10.746 0 24 0zm7.707 19.293a.999.999 0 1 1-1.414 1.414L25 16.414V34a1 1 0 1 1-2 0V16.414l-5.293 5.293a.999.999 0 1 1-1.414-1.414l7-7a1 1 0 0 1 1.414 0z'/%3E%3C/svg%3E");background-position:50% 50%;background-repeat:no-repeat;border:1px dashed #1269cf;border-radius:3px;color:#757575;display:flex;font-size:16px;justify-content:center;inset:7px;padding-top:90px;position:absolute;text-align:center;visibility:hidden;z-index:2000}[data-uppy-theme=dark] .uppy-Dashboard-dropFilesHereHint{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='48' height='48'%3E%3Cpath fill='%2302BAF2' d='M24 1v1C11.85 2 2 11.85 2 24s9.85 22 22 22 22-9.85 22-22S36.15 2 24 2zm0 0V0c13.254 0 24 10.746 24 24S37.254 48 24 48 0 37.254 0 24 10.746 0 24 0zm7.707 19.293a.999.999 0 1 1-1.414 1.414L25 16.414V34a1 1 0 1 1-2 0V16.414l-5.293 5.293a.999.999 0 1 1-1.414-1.414l7-7a1 1 0 0 1 1.414 0z'/%3E%3C/svg%3E");border-color:#02baf2;color:#bbb}.uppy-Dashboard.uppy-Dashboard--isDraggingOver .uppy-Dashboard-dropFilesHereHint{pointer-events:none;visibility:visible}.uppy-Dashboard.uppy-Dashboard--isDraggingOver .uppy-Dashboard-files,.uppy-Dashboard.uppy-Dashboard--isDraggingOver .uppy-Dashboard-progressindicators,.uppy-Dashboard.uppy-Dashboard--isDraggingOver .uppy-Dashboard-serviceMsg,.uppy-Dashboard.uppy-Dashboard--isDraggingOver .uppy-DashboardContent-bar{opacity:.15}.uppy-Dashboard.uppy-Dashboard--isDraggingOver .uppy-Dashboard-AddFiles{opacity:.03}.uppy-Dashboard-AddFiles-title{color:#000;font-size:17px;font-weight:500;line-height:1.35;margin-bottom:5px;margin-top:15px;padding:0 15px;text-align:inline-start;width:100%}.uppy-size--md .uppy-Dashboard-AddFiles-title{font-size:21px;font-weight:400;margin-top:5px;max-width:480px;padding:0 35px;text-align:center}[data-uppy-num-acquirers="0"] .uppy-Dashboard-AddFiles-title{text-align:center}[data-uppy-theme=dark] .uppy-Dashboard-AddFiles-title{color:#eaeaea}.uppy-Dashboard-AddFiles-title button{font-weight:500}.uppy-size--md .uppy-Dashboard-AddFiles-title button{font-weight:400}.uppy-Dashboard-note{color:#757575;font-size:14px;line-height:1.25;margin:auto;max-width:350px;padding:0 15px;text-align:center}.uppy-size--md .uppy-Dashboard-note{line-height:1.35;max-width:600px}[data-uppy-theme=dark] .uppy-Dashboard-note{color:#cfcfcf}a.uppy-Dashboard-poweredBy{color:#939393;display:inline-block;font-size:11px;margin-top:8px;text-align:center;text-decoration:none}.uppy-Dashboard-poweredByIcon{margin-left:1px;margin-right:1px;opacity:.9;position:relative;top:1px;vertical-align:text-top;fill:none;stroke:#939393}.uppy-Dashboard-Item-previewIcon{height:25px;left:50%;position:absolute;top:50%;transform:translate(-50%,-50%);width:25px;z-index:100}.uppy-size--md .uppy-Dashboard-Item-previewIcon{height:38px;width:38px}.uppy-Dashboard-Item-previewIcon svg{height:100%;width:100%}.uppy-Dashboard--singleFile .uppy-Dashboard-Item-previewIcon{height:100%;max-height:60%;max-width:60%;width:100%}.uppy-Dashboard-Item-previewIconWrap{height:76px;max-height:75%;position:relative}.uppy-Dashboard--singleFile .uppy-Dashboard-Item-previewIconWrap{height:100%;width:100%}.uppy-Dashboard-Item-previewIconBg{filter:drop-shadow(rgba(0,0,0,.1) 0 1px 1px);height:100%;width:100%}.uppy-Dashboard-upload{height:50px;position:relative;width:50px}.uppy-size--md .uppy-Dashboard-upload{height:60px;width:60px}.uppy-Dashboard-upload .uppy-c-icon{position:relative;top:1px;width:50%}.uppy-Dashboard-uploadCount{background-color:#1bb240;border-radius:50%;color:#fff;font-size:8px;height:16px;inset-inline-end:-12px;line-height:16px;position:absolute;top:-12px;width:16px}.uppy-size--md .uppy-Dashboard-uploadCount{font-size:9px;height:18px;line-height:18px;width:18px}.uppy-Dashboard-inner{border:none!important;background:transparent!important}.uppy-Dashboard-innerWrap{border-radius:.5rem;overflow:hidden}.uppy-Dashboard-AddFiles{border:2px dashed hsl(var(--border))!important;border-radius:.5rem!important;background:hsl(var(--muted) / .3)!important;transition:all .2s ease}.uppy-Dashboard-AddFiles:hover{border-color:hsl(var(--primary))!important;background:hsl(var(--muted) / .5)!important}.uppy-Dashboard-AddFiles-title{color:hsl(var(--foreground))!important;font-weight:500!important}.uppy-Dashboard-AddFiles-info{color:hsl(var(--muted-foreground))!important}.uppy-Dashboard-browse{color:hsl(var(--primary))!important;font-weight:500!important}.uppy-Dashboard-browse:hover{text-decoration:underline!important}.uppy-Dashboard-files{background:transparent!important}.uppy-Dashboard-Item{border-bottom-color:hsl(var(--border))!important}.uppy-Dashboard-Item-name{color:hsl(var(--foreground))!important}.uppy-Dashboard-Item-status{color:hsl(var(--muted-foreground))!important}.uppy-StatusBar{background:hsl(var(--muted))!important;border-top:1px solid hsl(var(--border))!important}.uppy-StatusBar-progress{background:hsl(var(--primary))!important}.uppy-StatusBar-content{color:hsl(var(--foreground))!important}.uppy-StatusBar-actionBtn--upload{background:hsl(var(--primary))!important;color:hsl(var(--primary-foreground))!important;border-radius:.375rem!important;font-weight:500!important;padding:.5rem 1rem!important}.uppy-StatusBar-actionBtn--upload:hover{background:hsl(var(--primary) / .9)!important}.uppy-Dashboard-note{color:hsl(var(--muted-foreground))!important;font-size:.75rem!important}[data-uppy-theme=dark] .uppy-Dashboard-AddFiles,.dark .uppy-Dashboard-AddFiles{background:hsl(var(--muted) / .2)!important}[data-uppy-theme=dark] .uppy-Dashboard-AddFiles-title,.dark .uppy-Dashboard-AddFiles-title{color:hsl(var(--foreground))!important}[data-uppy-theme=dark] .uppy-StatusBar,.dark .uppy-StatusBar{background:hsl(var(--muted) / .5)!important}.uppy-Dashboard{font-family:inherit!important}.uppy-Dashboard-Item-preview{border-radius:.375rem!important;overflow:hidden}.uppy-Dashboard-Item-action--remove{color:hsl(var(--destructive))!important}.uppy-Dashboard-Item-action--remove:hover{opacity:.8}.uppy-Dashboard-Item.is-complete .uppy-Dashboard-Item-progress{color:hsl(var(--success, 142 76% 36%))!important}.uppy-Dashboard-Item.is-error .uppy-Dashboard-Item-progress{color:hsl(var(--destructive))!important}.uppy-Dashboard-files::-webkit-scrollbar{width:6px}.uppy-Dashboard-files::-webkit-scrollbar-track{background:transparent}.uppy-Dashboard-files::-webkit-scrollbar-thumb{background:hsl(var(--muted-foreground) / .3);border-radius:3px}.uppy-Dashboard-files::-webkit-scrollbar-thumb:hover{background:hsl(var(--muted-foreground) / .5)}@font-face{font-display:block;font-family:KaTeX_AMS;font-style:normal;font-weight:400;src:url(/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2) format("woff2"),url(/assets/KaTeX_AMS-Regular-DMm9YOAa.woff) format("woff"),url(/assets/KaTeX_AMS-Regular-DRggAlZN.ttf) format("truetype")}@font-face{font-display:block;font-family:KaTeX_Caligraphic;font-style:normal;font-weight:700;src:url(/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2) format("woff2"),url(/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff) format("woff"),url(/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf) format("truetype")}@font-face{font-display:block;font-family:KaTeX_Caligraphic;font-style:normal;font-weight:400;src:url(/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2) format("woff2"),url(/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff) format("woff"),url(/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf) format("truetype")}@font-face{font-display:block;font-family:KaTeX_Fraktur;font-style:normal;font-weight:700;src:url(/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2) format("woff2"),url(/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff) format("woff"),url(/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf) format("truetype")}@font-face{font-display:block;font-family:KaTeX_Fraktur;font-style:normal;font-weight:400;src:url(/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2) format("woff2"),url(/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff) format("woff"),url(/assets/KaTeX_Fraktur-Regular-CB_wures.ttf) format("truetype")}@font-face{font-display:block;font-family:KaTeX_Main;font-style:normal;font-weight:700;src:url(/assets/KaTeX_Main-Bold-Cx986IdX.woff2) format("woff2"),url(/assets/KaTeX_Main-Bold-Jm3AIy58.woff) format("woff"),url(/assets/KaTeX_Main-Bold-waoOVXN0.ttf) format("truetype")}@font-face{font-display:block;font-family:KaTeX_Main;font-style:italic;font-weight:700;src:url(/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2) format("woff2"),url(/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff) format("woff"),url(/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf) format("truetype")}@font-face{font-display:block;font-family:KaTeX_Main;font-style:italic;font-weight:400;src:url(/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2) format("woff2"),url(/assets/KaTeX_Main-Italic-BMLOBm91.woff) format("woff"),url(/assets/KaTeX_Main-Italic-3WenGoN9.ttf) format("truetype")}@font-face{font-display:block;font-family:KaTeX_Main;font-style:normal;font-weight:400;src:url(/assets/KaTeX_Main-Regular-B22Nviop.woff2) format("woff2"),url(/assets/KaTeX_Main-Regular-Dr94JaBh.woff) format("woff"),url(/assets/KaTeX_Main-Regular-ypZvNtVU.ttf) format("truetype")}@font-face{font-display:block;font-family:KaTeX_Math;font-style:italic;font-weight:700;src:url(/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2) format("woff2"),url(/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff) format("woff"),url(/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf) format("truetype")}@font-face{font-display:block;font-family:KaTeX_Math;font-style:italic;font-weight:400;src:url(/assets/KaTeX_Math-Italic-t53AETM-.woff2) format("woff2"),url(/assets/KaTeX_Math-Italic-DA0__PXp.woff) format("woff"),url(/assets/KaTeX_Math-Italic-flOr_0UB.ttf) format("truetype")}@font-face{font-display:block;font-family:KaTeX_SansSerif;font-style:normal;font-weight:700;src:url(/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2) format("woff2"),url(/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff) format("woff"),url(/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf) format("truetype")}@font-face{font-display:block;font-family:KaTeX_SansSerif;font-style:italic;font-weight:400;src:url(/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2) format("woff2"),url(/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff) format("woff"),url(/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf) format("truetype")}@font-face{font-display:block;font-family:KaTeX_SansSerif;font-style:normal;font-weight:400;src:url(/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2) format("woff2"),url(/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff) format("woff"),url(/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf) format("truetype")}@font-face{font-display:block;font-family:KaTeX_Script;font-style:normal;font-weight:400;src:url(/assets/KaTeX_Script-Regular-D3wIWfF6.woff2) format("woff2"),url(/assets/KaTeX_Script-Regular-D5yQViql.woff) format("woff"),url(/assets/KaTeX_Script-Regular-C5JkGWo-.ttf) format("truetype")}@font-face{font-display:block;font-family:KaTeX_Size1;font-style:normal;font-weight:400;src:url(/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2) format("woff2"),url(/assets/KaTeX_Size1-Regular-C195tn64.woff) format("woff"),url(/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf) format("truetype")}@font-face{font-display:block;font-family:KaTeX_Size2;font-style:normal;font-weight:400;src:url(/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2) format("woff2"),url(/assets/KaTeX_Size2-Regular-oD1tc_U0.woff) format("woff"),url(/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf) format("truetype")}@font-face{font-display:block;font-family:KaTeX_Size3;font-style:normal;font-weight:400;src:url(data:font/woff2;base64,d09GMgABAAAAAA4oAA4AAAAAHbQAAA3TAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAABmAAgRQIDgmcDBEICo1oijYBNgIkA14LMgAEIAWJAAeBHAyBHBvbGiMRdnO0IkRRkiYDgr9KsJ1NUAf2kILNxgUmgqIgq1P89vcbIcmsQbRps3vCcXdYOKSWEPEKgZgQkprQQsxIXUgq0DqpGKmIvrgkeVGtEQD9DzAO29fM9jYhxZEsL2FeURH2JN4MIcTdO049NCVdxQ/w9NrSYFEBKTDKpLKfNkCGDc1RwjZLQcm3vqJ2UW9Xfa3tgAHz6ivp6vgC2yD4/6352ndnN0X0TL7seypkjZlMsjmZnf0Mm5Q+JykRWQBKCVCVPbARPXWyQtb5VgLB6Biq7/Uixcj2WGqdI8tGSgkuRG+t910GKP2D7AQH0DB9FMDW/obJZ8giFI3Wg8Cvevz0M+5m0rTh7XDBlvo9Y4vm13EXmfttwI4mBo1EG15fxJhUiCLbiiyCf/ZA6MFAhg3pGIZGdGIVjtPn6UcMk9A/UUr9PhoNsCENw1APAq0gpH73e+M+0ueyHbabc3vkbcdtzcf/fiy+NxQEjf9ud/ELBHAXJ0nk4z+MXH2Ev/kWyV4k7SkvpPc9Qr38F6RPWnM9cN6DJ0AdD1BhtgABtmoRoFCvPsBAumNm6soZG2Gk5GyVTo2sJncSyp0jQTYoR6WDvTwaaEcHsxHfvuWhHA3a6bN7twRKtcGok6NsCi7jYRrM2jExsUFMxMQYuJbMhuWNOumEJy9hi29Dmg5zMp/A5+hhPG19j1vBrq8JTLr8ki5VLPmG/PynJHVul440bxg5xuymHUFPBshC+nA9I1FmwbRBTNHAcik3Oae0cxKoI3MOriM42UrPe51nsaGxJ+WfXubAsP84aabUlQSJ1IiE0iPETLUU4CATgfXSCSpuRFRmCGbO+wSpAnzaeaCYW1VNEysRtuXCEL1kUFUbbtMv3Tilt/1c11jt3Q5bbMa84cpWipp8Elw3MZhOHsOlwwVUQM3lAR35JiFQbaYCRnMF2lxAWoOg2gyoIV4PouX8HytNIfLhqpJtXB4vjiViUI8IJ7bkC4ikkQvKksnOTKICwnqWSZ9YS5f0WCxmpgjbIq7EJcM4aI2nmhLNY2JIUgOjXZFWBHb+x5oh6cwb0Tv1ackHdKi0I9OO2wE9aogIOn540CCCziyhN+IaejtgAONKznHlHyutPrHGwCx9S6B8kfS4Mfi4Eyv7OU730bT1SCBjt834cXsf43zVjPUqqJjgrjeGnBxSG4aYAKFuVbeCfkDIjAqMb6yLNIbCuvXhMH2/+k2vkNpkORhR59N1CkzoOENvneIosjYmuTxlhUzaGEJQ/iWqx4dmwpmKjrwTiTGTCVozNAYqk/zXOndWxuWSmJkQpJw3pK5KX6QrLt5LATMqpmPAQhkhK6PUjzHUn7E0gHE0kPE0iKkolgkUx9SZmVAdDgpffdyJKg3k7VmzYGCwVXGz/tXmkOIp+vcWs+EMuhhvN0h9uhfzWJziBQmCREGSIFmQIkgVpAnSBRmC//6hkLZwaVhwxlrJSOdqlFtOYxlau9F2QN5Y98xmIAsiM1HVp2VFX+DHHGg6Ecjh3vmqtidX3qHI2qycTk/iwxSt5UzTmEP92ZBnEWTk4Mx8Mpl78ZDokxg/KWb+Q0QkvdKVmq3TMW+RXEgrsziSAfNXFMhDc60N5N9jQzjfO0kBKpUZl0ZmwJ41j/B9Hz6wmRaJB84niNmQrzp9eSlQCDDzazGDdVi3P36VZQ+Jy4f9UBNp+3zTjqI4abaFAm+GShVaXlsGdF3FYzZcDI6cori4kMxUECl9IjJZpzkvitAoxKue+90pDMvcKRxLl53TmOKCmV/xRolNKSqqUxc6LStOETmFOiLZZptlZepcKiAzteG8PEdpnQpbOMNcMsR4RR2Bs0cKFEvSmIjAFcnarqwUL4lDhHmnVkwu1IwshbiCcgvOheZuYyOteufZZwlcTlLgnZ3o/WcYdzZHW/WGaqaVfmTZ1aWCceJjkbZqsfbkOtcFlUZM/jy+hXHDbaUobWqqXaeWobbLO99yG5N3U4wxco0rQGGcOLASFMXeJoham8M+/x6O2WywK2l4HGbq1CoUyC/IZikQhdq3SiuNrvAEj0AVu9x2x3lp/xWzahaxidezFVtdcb5uEnzyl0ZmYiuKI0exvCd4Xc9CV1KB0db00z92wDPde0kukbvZIWN6jUWFTmPIC/Y4UPCm8UfDTFZpZNon1qLFTkBhxzB+FjQRA2Q/YRJT8pQigslMaUpFyAG8TMlXigiqmAZX4xgijKjRlGpLE0GdplRfCaJo0JQaSxNBk6ZmMzcya0FmrcisDdn0Q3HI2sWSppYigmlM1XT/kLQZSNpMJG0WkjYbSZuDpM1F0uYhFc1HxU4m1QJjDK6iL0S5uSj5rgXc3RejEigtcRBtqYPQsiTskmO5vosV+q4VGIKbOkDg0jtRrq+Em1YloaTFar3EGr1EUC8R0kus1Uus00usL97ABr2BjXoDm/QGNhuWtMVBKOwg/i78lT7hBsAvDmwHc/ao3vmUbBmhjeYySZNWvGkfZAgISDSaDo1SVpzGDsAEkF8B+gEapViUoZgUWXcRIGFZNm6gWbAKk0bp0k1MHG9fLYtV4iS2SmLEQFARzRcnf9PUS0LVn05/J9MiRRBU3v2IrvW974v4N00L7ZMk0wXP1409CHo/an8zTRHD3eSJ6m8D4YMkZNl3M79sqeuAsr/m3f+8/yl7A50aiAEJgeBeMWzu7ui9UfUBCe2TIqZIoOd/3/udRBOQidQZUERzb2/VwZN1H/Sju82ew2H2Wfr6qvfVf3hqwDvAIpkQVFy4B9Pe9e4/XvPeceu7h3dvO56iJPf0+A6cqA2ip18ER+iFgggiuOkvj24bby0N9j2UHIkgqIt+sVgfodC4YghLSMjSZbH0VR/6dMDrYJeKHilKTemt6v6kvzvn3/RrdWtr0GoN/xL+Sex/cPYLUpepx9cz/D46UPU5KXgAQa+NDps1v6J3xP1i2HtaDB0M9aX2deA7SYff//+gUCovMmIK/qfsFcOk+4Y5ZN97XlG6zebqtMbKgeRFi51vnxTQYBUik2rS/Cn6PC8ADR8FGxsRPB82dzfND90gIcshOcYUkfjherBz53odpm6TP8txlwOZ71xmfHHOvq053qFF/MRlS3jP0ELudrf2OeN8DHvp6ZceLe8qKYvWz/7yp0u4dKPfli3CYq0O13Ih71mylJ80tOi10On8wi+F4+LWgDPeJ30msSQt9/vkmHq9/Lvo2b461mP801v3W4xTcs6CbvF9UDdrSt+A8OUbpSh55qAUFXWznBBfdeJ8a4d7ugT5tvxUza3h9m4H7ptTqiG4z0g5dc0X29OcGlhpGFMpQo9ytTS+NViZpNdvU4kWx+LKxNY10kQ1yqGXrhe4/1nvP7E+nd5A92TtaRplbHSqoIdOqtRWti+fkB5/n1+/VvCmz12pG1kpQWsfi1ftlBobm0bpngs16CHkbIwdLnParxtTV3QYRlfJ0KFskH7pdN/YDn+yRuSd7sNH3aO0DYPggk6uWuXrfOc+fa3VTxFVvKaNxHsiHmsXyCLIE5yuOeN3/Jdf8HBL/5M6shjyhxHx9BjB1O0+4NLOnjLLSxwO7ukN4jMbOIcD879KLSi6Pk61Oqm2377n8079PXEEQ7cy7OKEC9nbpet118fxweTafpt69x/Bt8UqGzNQt7aelpc44dn5cqhwf71+qKp/Zf/+a0zcizOUWpl/iBcSXip0pplkatCchoH5c5aUM8I7/dWxAej8WicPL1URFZ9BDJelUwEwTkGqUhgSlydVes95YdXvhh9Gfz/aeFWvgVb4tuLbcv4+wLdutVZv/cUonwBD/6eDlE0aSiKK/uoH3+J1wDE/jMVqY2ysGufN84oIXB0sPzy8ollX/LegY74DgJXJR57sn+VGza0x3DnuIgABFM15LmajjjsNlYj+JEZGbuRYcAMOWxFkPN2w6Wd46xo4gVWQR/X4lyI/R6K/YK0110GzudPRW7Y+UOBGTfNNzHeYT0fiH0taunBpq9HEW8OKSaBGj21L0MqenEmNRWBAWDWAk4CpNoEZJ2tTaPFgbQYj8HxtFilErs3BTRwT8uO1NXQaWfIotchmPkAF5mMBAliEmZiOGVgCG9LgRzpscMAOOwowlT3JhusdazXGSC/hxR3UlmWVwWHpOIKheqONvjyhSiTHIkVUco5bnji8m//zL7PKaT1Vl5I6UE609f+gkr6MZKVyKc7zJRmCahLsdlyA5fdQkRSan9LgnnLEyGSkaKJCJog0wAgvepWBt80+1yKln1bMVtCljfNWDueKLsWwaEbBSfSPTEmVRsUcYYMnEjcjeyCZzBXK9E9BYBXLKjOSpUDR+nEV3TFSUdQaz+ot98QxgXwx0GQ+EEUAKB2qZPkQQ0GqFD8UPFMqyaCHM24BZmSGic9EYMagKizOw9Hz50DMrDLrqqLkTAhplMictiCAx5S3BIUQdeJeLnBy2CNtMfz6cV4u8XKoFZQesbf9YZiIERiHjaNodDW6LgcirX/mPnJIkBGDUpTBhSa0EIr38D5hCIszhCM8URGBqImoWjpvpt1ebu/v3Gl3qJfMnNM+9V+kiRFyROTPHQWOcs1dNW94/ukKMPZBvDi55i5CttdeJz84DLngLqjcdwEZ87bFFR8CIG35OAkDVN6VRDZ7aq67NteYqZ2lpT8oYB2CytoBd6VuAx4WgiAsnuj3WohG+LugzXiQRDeM3XYXlULv4dp5VFYC) format("woff2"),url(/assets/KaTeX_Size3-Regular-CTq5MqoE.woff) format("woff"),url(/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf) format("truetype")}@font-face{font-display:block;font-family:KaTeX_Size4;font-style:normal;font-weight:400;src:url(/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2) format("woff2"),url(/assets/KaTeX_Size4-Regular-BF-4gkZK.woff) format("woff"),url(/assets/KaTeX_Size4-Regular-DWFBv043.ttf) format("truetype")}@font-face{font-display:block;font-family:KaTeX_Typewriter;font-style:normal;font-weight:400;src:url(/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2) format("woff2"),url(/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff) format("woff"),url(/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf) format("truetype")}.katex{font: 1.21em KaTeX_Main,Times New Roman,serif;line-height:1.2;text-indent:0;text-rendering:auto}.katex *{-ms-high-contrast-adjust:none!important;border-color:currentColor}.katex .katex-version:after{content:"0.16.27"}.katex .katex-mathml{clip:rect(1px,1px,1px,1px);border:0;height:1px;overflow:hidden;padding:0;position:absolute;width:1px}.katex .katex-html>.newline{display:block}.katex .base{position:relative;white-space:nowrap;width:-moz-min-content;width:min-content}.katex .base,.katex .strut{display:inline-block}.katex .textbf{font-weight:700}.katex .textit{font-style:italic}.katex .textrm{font-family:KaTeX_Main}.katex .textsf{font-family:KaTeX_SansSerif}.katex .texttt{font-family:KaTeX_Typewriter}.katex .mathnormal{font-family:KaTeX_Math;font-style:italic}.katex .mathit{font-family:KaTeX_Main;font-style:italic}.katex .mathrm{font-style:normal}.katex .mathbf{font-family:KaTeX_Main;font-weight:700}.katex .boldsymbol{font-family:KaTeX_Math;font-style:italic;font-weight:700}.katex .amsrm,.katex .mathbb,.katex .textbb{font-family:KaTeX_AMS}.katex .mathcal{font-family:KaTeX_Caligraphic}.katex .mathfrak,.katex .textfrak{font-family:KaTeX_Fraktur}.katex .mathboldfrak,.katex .textboldfrak{font-family:KaTeX_Fraktur;font-weight:700}.katex .mathtt{font-family:KaTeX_Typewriter}.katex .mathscr,.katex .textscr{font-family:KaTeX_Script}.katex .mathsf,.katex .textsf{font-family:KaTeX_SansSerif}.katex .mathboldsf,.katex .textboldsf{font-family:KaTeX_SansSerif;font-weight:700}.katex .mathitsf,.katex .mathsfit,.katex .textitsf{font-family:KaTeX_SansSerif;font-style:italic}.katex .mainrm{font-family:KaTeX_Main;font-style:normal}.katex .vlist-t{border-collapse:collapse;display:inline-table;table-layout:fixed}.katex .vlist-r{display:table-row}.katex .vlist{display:table-cell;position:relative;vertical-align:bottom}.katex .vlist>span{display:block;height:0;position:relative}.katex .vlist>span>span{display:inline-block}.katex .vlist>span>.pstrut{overflow:hidden;width:0}.katex .vlist-t2{margin-right:-2px}.katex .vlist-s{display:table-cell;font-size:1px;min-width:2px;vertical-align:bottom;width:2px}.katex .vbox{align-items:baseline;display:inline-flex;flex-direction:column}.katex .hbox{width:100%}.katex .hbox,.katex .thinbox{display:inline-flex;flex-direction:row}.katex .thinbox{max-width:0;width:0}.katex .msupsub{text-align:left}.katex .mfrac>span>span{text-align:center}.katex .mfrac .frac-line{border-bottom-style:solid;display:inline-block;width:100%}.katex .hdashline,.katex .hline,.katex .mfrac .frac-line,.katex .overline .overline-line,.katex .rule,.katex .underline .underline-line{min-height:1px}.katex .mspace{display:inline-block}.katex .clap,.katex .llap,.katex .rlap{position:relative;width:0}.katex .clap>.inner,.katex .llap>.inner,.katex .rlap>.inner{position:absolute}.katex .clap>.fix,.katex .llap>.fix,.katex .rlap>.fix{display:inline-block}.katex .llap>.inner{right:0}.katex .clap>.inner,.katex .rlap>.inner{left:0}.katex .clap>.inner>span{margin-left:-50%;margin-right:50%}.katex .rule{border:0 solid;display:inline-block;position:relative}.katex .hline,.katex .overline .overline-line,.katex .underline .underline-line{border-bottom-style:solid;display:inline-block;width:100%}.katex .hdashline{border-bottom-style:dashed;display:inline-block;width:100%}.katex .sqrt>.root{margin-left:.2777777778em;margin-right:-.5555555556em}.katex .fontsize-ensurer.reset-size1.size1,.katex .sizing.reset-size1.size1{font-size:1em}.katex .fontsize-ensurer.reset-size1.size2,.katex .sizing.reset-size1.size2{font-size:1.2em}.katex .fontsize-ensurer.reset-size1.size3,.katex .sizing.reset-size1.size3{font-size:1.4em}.katex .fontsize-ensurer.reset-size1.size4,.katex .sizing.reset-size1.size4{font-size:1.6em}.katex .fontsize-ensurer.reset-size1.size5,.katex .sizing.reset-size1.size5{font-size:1.8em}.katex .fontsize-ensurer.reset-size1.size6,.katex .sizing.reset-size1.size6{font-size:2em}.katex .fontsize-ensurer.reset-size1.size7,.katex .sizing.reset-size1.size7{font-size:2.4em}.katex .fontsize-ensurer.reset-size1.size8,.katex .sizing.reset-size1.size8{font-size:2.88em}.katex .fontsize-ensurer.reset-size1.size9,.katex .sizing.reset-size1.size9{font-size:3.456em}.katex .fontsize-ensurer.reset-size1.size10,.katex .sizing.reset-size1.size10{font-size:4.148em}.katex .fontsize-ensurer.reset-size1.size11,.katex .sizing.reset-size1.size11{font-size:4.976em}.katex .fontsize-ensurer.reset-size2.size1,.katex .sizing.reset-size2.size1{font-size:.8333333333em}.katex .fontsize-ensurer.reset-size2.size2,.katex .sizing.reset-size2.size2{font-size:1em}.katex .fontsize-ensurer.reset-size2.size3,.katex .sizing.reset-size2.size3{font-size:1.1666666667em}.katex .fontsize-ensurer.reset-size2.size4,.katex .sizing.reset-size2.size4{font-size:1.3333333333em}.katex .fontsize-ensurer.reset-size2.size5,.katex .sizing.reset-size2.size5{font-size:1.5em}.katex .fontsize-ensurer.reset-size2.size6,.katex .sizing.reset-size2.size6{font-size:1.6666666667em}.katex .fontsize-ensurer.reset-size2.size7,.katex .sizing.reset-size2.size7{font-size:2em}.katex .fontsize-ensurer.reset-size2.size8,.katex .sizing.reset-size2.size8{font-size:2.4em}.katex .fontsize-ensurer.reset-size2.size9,.katex .sizing.reset-size2.size9{font-size:2.88em}.katex .fontsize-ensurer.reset-size2.size10,.katex .sizing.reset-size2.size10{font-size:3.4566666667em}.katex .fontsize-ensurer.reset-size2.size11,.katex .sizing.reset-size2.size11{font-size:4.1466666667em}.katex .fontsize-ensurer.reset-size3.size1,.katex .sizing.reset-size3.size1{font-size:.7142857143em}.katex .fontsize-ensurer.reset-size3.size2,.katex .sizing.reset-size3.size2{font-size:.8571428571em}.katex .fontsize-ensurer.reset-size3.size3,.katex .sizing.reset-size3.size3{font-size:1em}.katex .fontsize-ensurer.reset-size3.size4,.katex .sizing.reset-size3.size4{font-size:1.1428571429em}.katex .fontsize-ensurer.reset-size3.size5,.katex .sizing.reset-size3.size5{font-size:1.2857142857em}.katex .fontsize-ensurer.reset-size3.size6,.katex .sizing.reset-size3.size6{font-size:1.4285714286em}.katex .fontsize-ensurer.reset-size3.size7,.katex .sizing.reset-size3.size7{font-size:1.7142857143em}.katex .fontsize-ensurer.reset-size3.size8,.katex .sizing.reset-size3.size8{font-size:2.0571428571em}.katex .fontsize-ensurer.reset-size3.size9,.katex .sizing.reset-size3.size9{font-size:2.4685714286em}.katex .fontsize-ensurer.reset-size3.size10,.katex .sizing.reset-size3.size10{font-size:2.9628571429em}.katex .fontsize-ensurer.reset-size3.size11,.katex .sizing.reset-size3.size11{font-size:3.5542857143em}.katex .fontsize-ensurer.reset-size4.size1,.katex .sizing.reset-size4.size1{font-size:.625em}.katex .fontsize-ensurer.reset-size4.size2,.katex .sizing.reset-size4.size2{font-size:.75em}.katex .fontsize-ensurer.reset-size4.size3,.katex .sizing.reset-size4.size3{font-size:.875em}.katex .fontsize-ensurer.reset-size4.size4,.katex .sizing.reset-size4.size4{font-size:1em}.katex .fontsize-ensurer.reset-size4.size5,.katex .sizing.reset-size4.size5{font-size:1.125em}.katex .fontsize-ensurer.reset-size4.size6,.katex .sizing.reset-size4.size6{font-size:1.25em}.katex .fontsize-ensurer.reset-size4.size7,.katex .sizing.reset-size4.size7{font-size:1.5em}.katex .fontsize-ensurer.reset-size4.size8,.katex .sizing.reset-size4.size8{font-size:1.8em}.katex .fontsize-ensurer.reset-size4.size9,.katex .sizing.reset-size4.size9{font-size:2.16em}.katex .fontsize-ensurer.reset-size4.size10,.katex .sizing.reset-size4.size10{font-size:2.5925em}.katex .fontsize-ensurer.reset-size4.size11,.katex .sizing.reset-size4.size11{font-size:3.11em}.katex .fontsize-ensurer.reset-size5.size1,.katex .sizing.reset-size5.size1{font-size:.5555555556em}.katex .fontsize-ensurer.reset-size5.size2,.katex .sizing.reset-size5.size2{font-size:.6666666667em}.katex .fontsize-ensurer.reset-size5.size3,.katex .sizing.reset-size5.size3{font-size:.7777777778em}.katex .fontsize-ensurer.reset-size5.size4,.katex .sizing.reset-size5.size4{font-size:.8888888889em}.katex .fontsize-ensurer.reset-size5.size5,.katex .sizing.reset-size5.size5{font-size:1em}.katex .fontsize-ensurer.reset-size5.size6,.katex .sizing.reset-size5.size6{font-size:1.1111111111em}.katex .fontsize-ensurer.reset-size5.size7,.katex .sizing.reset-size5.size7{font-size:1.3333333333em}.katex .fontsize-ensurer.reset-size5.size8,.katex .sizing.reset-size5.size8{font-size:1.6em}.katex .fontsize-ensurer.reset-size5.size9,.katex .sizing.reset-size5.size9{font-size:1.92em}.katex .fontsize-ensurer.reset-size5.size10,.katex .sizing.reset-size5.size10{font-size:2.3044444444em}.katex .fontsize-ensurer.reset-size5.size11,.katex .sizing.reset-size5.size11{font-size:2.7644444444em}.katex .fontsize-ensurer.reset-size6.size1,.katex .sizing.reset-size6.size1{font-size:.5em}.katex .fontsize-ensurer.reset-size6.size2,.katex .sizing.reset-size6.size2{font-size:.6em}.katex .fontsize-ensurer.reset-size6.size3,.katex .sizing.reset-size6.size3{font-size:.7em}.katex .fontsize-ensurer.reset-size6.size4,.katex .sizing.reset-size6.size4{font-size:.8em}.katex .fontsize-ensurer.reset-size6.size5,.katex .sizing.reset-size6.size5{font-size:.9em}.katex .fontsize-ensurer.reset-size6.size6,.katex .sizing.reset-size6.size6{font-size:1em}.katex .fontsize-ensurer.reset-size6.size7,.katex .sizing.reset-size6.size7{font-size:1.2em}.katex .fontsize-ensurer.reset-size6.size8,.katex .sizing.reset-size6.size8{font-size:1.44em}.katex .fontsize-ensurer.reset-size6.size9,.katex .sizing.reset-size6.size9{font-size:1.728em}.katex .fontsize-ensurer.reset-size6.size10,.katex .sizing.reset-size6.size10{font-size:2.074em}.katex .fontsize-ensurer.reset-size6.size11,.katex .sizing.reset-size6.size11{font-size:2.488em}.katex .fontsize-ensurer.reset-size7.size1,.katex .sizing.reset-size7.size1{font-size:.4166666667em}.katex .fontsize-ensurer.reset-size7.size2,.katex .sizing.reset-size7.size2{font-size:.5em}.katex .fontsize-ensurer.reset-size7.size3,.katex .sizing.reset-size7.size3{font-size:.5833333333em}.katex .fontsize-ensurer.reset-size7.size4,.katex .sizing.reset-size7.size4{font-size:.6666666667em}.katex .fontsize-ensurer.reset-size7.size5,.katex .sizing.reset-size7.size5{font-size:.75em}.katex .fontsize-ensurer.reset-size7.size6,.katex .sizing.reset-size7.size6{font-size:.8333333333em}.katex .fontsize-ensurer.reset-size7.size7,.katex .sizing.reset-size7.size7{font-size:1em}.katex .fontsize-ensurer.reset-size7.size8,.katex .sizing.reset-size7.size8{font-size:1.2em}.katex .fontsize-ensurer.reset-size7.size9,.katex .sizing.reset-size7.size9{font-size:1.44em}.katex .fontsize-ensurer.reset-size7.size10,.katex .sizing.reset-size7.size10{font-size:1.7283333333em}.katex .fontsize-ensurer.reset-size7.size11,.katex .sizing.reset-size7.size11{font-size:2.0733333333em}.katex .fontsize-ensurer.reset-size8.size1,.katex .sizing.reset-size8.size1{font-size:.3472222222em}.katex .fontsize-ensurer.reset-size8.size2,.katex .sizing.reset-size8.size2{font-size:.4166666667em}.katex .fontsize-ensurer.reset-size8.size3,.katex .sizing.reset-size8.size3{font-size:.4861111111em}.katex .fontsize-ensurer.reset-size8.size4,.katex .sizing.reset-size8.size4{font-size:.5555555556em}.katex .fontsize-ensurer.reset-size8.size5,.katex .sizing.reset-size8.size5{font-size:.625em}.katex .fontsize-ensurer.reset-size8.size6,.katex .sizing.reset-size8.size6{font-size:.6944444444em}.katex .fontsize-ensurer.reset-size8.size7,.katex .sizing.reset-size8.size7{font-size:.8333333333em}.katex .fontsize-ensurer.reset-size8.size8,.katex .sizing.reset-size8.size8{font-size:1em}.katex .fontsize-ensurer.reset-size8.size9,.katex .sizing.reset-size8.size9{font-size:1.2em}.katex .fontsize-ensurer.reset-size8.size10,.katex .sizing.reset-size8.size10{font-size:1.4402777778em}.katex .fontsize-ensurer.reset-size8.size11,.katex .sizing.reset-size8.size11{font-size:1.7277777778em}.katex .fontsize-ensurer.reset-size9.size1,.katex .sizing.reset-size9.size1{font-size:.2893518519em}.katex .fontsize-ensurer.reset-size9.size2,.katex .sizing.reset-size9.size2{font-size:.3472222222em}.katex .fontsize-ensurer.reset-size9.size3,.katex .sizing.reset-size9.size3{font-size:.4050925926em}.katex .fontsize-ensurer.reset-size9.size4,.katex .sizing.reset-size9.size4{font-size:.462962963em}.katex .fontsize-ensurer.reset-size9.size5,.katex .sizing.reset-size9.size5{font-size:.5208333333em}.katex .fontsize-ensurer.reset-size9.size6,.katex .sizing.reset-size9.size6{font-size:.5787037037em}.katex .fontsize-ensurer.reset-size9.size7,.katex .sizing.reset-size9.size7{font-size:.6944444444em}.katex .fontsize-ensurer.reset-size9.size8,.katex .sizing.reset-size9.size8{font-size:.8333333333em}.katex .fontsize-ensurer.reset-size9.size9,.katex .sizing.reset-size9.size9{font-size:1em}.katex .fontsize-ensurer.reset-size9.size10,.katex .sizing.reset-size9.size10{font-size:1.2002314815em}.katex .fontsize-ensurer.reset-size9.size11,.katex .sizing.reset-size9.size11{font-size:1.4398148148em}.katex .fontsize-ensurer.reset-size10.size1,.katex .sizing.reset-size10.size1{font-size:.2410800386em}.katex .fontsize-ensurer.reset-size10.size2,.katex .sizing.reset-size10.size2{font-size:.2892960463em}.katex .fontsize-ensurer.reset-size10.size3,.katex .sizing.reset-size10.size3{font-size:.337512054em}.katex .fontsize-ensurer.reset-size10.size4,.katex .sizing.reset-size10.size4{font-size:.3857280617em}.katex .fontsize-ensurer.reset-size10.size5,.katex .sizing.reset-size10.size5{font-size:.4339440694em}.katex .fontsize-ensurer.reset-size10.size6,.katex .sizing.reset-size10.size6{font-size:.4821600771em}.katex .fontsize-ensurer.reset-size10.size7,.katex .sizing.reset-size10.size7{font-size:.5785920926em}.katex .fontsize-ensurer.reset-size10.size8,.katex .sizing.reset-size10.size8{font-size:.6943105111em}.katex .fontsize-ensurer.reset-size10.size9,.katex .sizing.reset-size10.size9{font-size:.8331726133em}.katex .fontsize-ensurer.reset-size10.size10,.katex .sizing.reset-size10.size10{font-size:1em}.katex .fontsize-ensurer.reset-size10.size11,.katex .sizing.reset-size10.size11{font-size:1.1996142719em}.katex .fontsize-ensurer.reset-size11.size1,.katex .sizing.reset-size11.size1{font-size:.2009646302em}.katex .fontsize-ensurer.reset-size11.size2,.katex .sizing.reset-size11.size2{font-size:.2411575563em}.katex .fontsize-ensurer.reset-size11.size3,.katex .sizing.reset-size11.size3{font-size:.2813504823em}.katex .fontsize-ensurer.reset-size11.size4,.katex .sizing.reset-size11.size4{font-size:.3215434084em}.katex .fontsize-ensurer.reset-size11.size5,.katex .sizing.reset-size11.size5{font-size:.3617363344em}.katex .fontsize-ensurer.reset-size11.size6,.katex .sizing.reset-size11.size6{font-size:.4019292605em}.katex .fontsize-ensurer.reset-size11.size7,.katex .sizing.reset-size11.size7{font-size:.4823151125em}.katex .fontsize-ensurer.reset-size11.size8,.katex .sizing.reset-size11.size8{font-size:.578778135em}.katex .fontsize-ensurer.reset-size11.size9,.katex .sizing.reset-size11.size9{font-size:.6945337621em}.katex .fontsize-ensurer.reset-size11.size10,.katex .sizing.reset-size11.size10{font-size:.8336012862em}.katex .fontsize-ensurer.reset-size11.size11,.katex .sizing.reset-size11.size11{font-size:1em}.katex .delimsizing.size1{font-family:KaTeX_Size1}.katex .delimsizing.size2{font-family:KaTeX_Size2}.katex .delimsizing.size3{font-family:KaTeX_Size3}.katex .delimsizing.size4{font-family:KaTeX_Size4}.katex .delimsizing.mult .delim-size1>span{font-family:KaTeX_Size1}.katex .delimsizing.mult .delim-size4>span{font-family:KaTeX_Size4}.katex .nulldelimiter{display:inline-block;width:.12em}.katex .delimcenter,.katex .op-symbol{position:relative}.katex .op-symbol.small-op{font-family:KaTeX_Size1}.katex .op-symbol.large-op{font-family:KaTeX_Size2}.katex .accent>.vlist-t,.katex .op-limits>.vlist-t{text-align:center}.katex .accent .accent-body{position:relative}.katex .accent .accent-body:not(.accent-full){width:0}.katex .overlay{display:block}.katex .mtable .vertical-separator{display:inline-block;min-width:1px}.katex .mtable .arraycolsep{display:inline-block}.katex .mtable .col-align-c>.vlist-t{text-align:center}.katex .mtable .col-align-l>.vlist-t{text-align:left}.katex .mtable .col-align-r>.vlist-t{text-align:right}.katex .svg-align{text-align:left}.katex svg{fill:currentColor;stroke:currentColor;fill-rule:nonzero;fill-opacity:1;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;display:block;height:inherit;position:absolute;width:100%}.katex svg path{stroke:none}.katex img{border-style:none;max-height:none;max-width:none;min-height:0;min-width:0}.katex .stretchy{display:block;overflow:hidden;position:relative;width:100%}.katex .stretchy:after,.katex .stretchy:before{content:""}.katex .hide-tail{overflow:hidden;position:relative;width:100%}.katex .halfarrow-left{left:0;overflow:hidden;position:absolute;width:50.2%}.katex .halfarrow-right{overflow:hidden;position:absolute;right:0;width:50.2%}.katex .brace-left{left:0;overflow:hidden;position:absolute;width:25.1%}.katex .brace-center{left:25%;overflow:hidden;position:absolute;width:50%}.katex .brace-right{overflow:hidden;position:absolute;right:0;width:25.1%}.katex .x-arrow-pad{padding:0 .5em}.katex .cd-arrow-pad{padding:0 .55556em 0 .27778em}.katex .mover,.katex .munder,.katex .x-arrow{text-align:center}.katex .boxpad{padding:0 .3em}.katex .fbox,.katex .fcolorbox{border:.04em solid;box-sizing:border-box}.katex .cancel-pad{padding:0 .2em}.katex .cancel-lap{margin-left:-.2em;margin-right:-.2em}.katex .sout{border-bottom-style:solid;border-bottom-width:.08em}.katex .angl{border-right:.049em solid;border-top:.049em solid;box-sizing:border-box;margin-right:.03889em}.katex .anglpad{padding:0 .03889em}.katex .eqn-num:before{content:"(" counter(katexEqnNo) ")";counter-increment:katexEqnNo}.katex .mml-eqn-num:before{content:"(" counter(mmlEqnNo) ")";counter-increment:mmlEqnNo}.katex .mtr-glue{width:50%}.katex .cd-vert-arrow{display:inline-block;position:relative}.katex .cd-label-left{display:inline-block;position:absolute;right:calc(50% + .3em);text-align:left}.katex .cd-label-right{display:inline-block;left:calc(50% + .3em);position:absolute;text-align:right}.katex-display{display:block;margin:1em 0;text-align:center}.katex-display>.katex{display:block;text-align:center;white-space:nowrap}.katex-display>.katex>.katex-html{display:block;position:relative}.katex-display>.katex>.katex-html>.tag{position:absolute;right:0}.katex-display.leqno>.katex>.katex-html>.tag{left:0;right:auto}.katex-display.fleqn>.katex{padding-left:2em;text-align:left}body{counter-reset:katexEqnNo mmlEqnNo}.react-flow{direction:ltr}.react-flow__container{position:absolute;width:100%;height:100%;top:0;left:0}.react-flow__pane{z-index:1;cursor:grab}.react-flow__pane.selection{cursor:pointer}.react-flow__pane.dragging{cursor:grabbing}.react-flow__viewport{transform-origin:0 0;z-index:2;pointer-events:none}.react-flow__renderer{z-index:4}.react-flow__selection{z-index:6}.react-flow__nodesselection-rect:focus,.react-flow__nodesselection-rect:focus-visible{outline:none}.react-flow .react-flow__edges{pointer-events:none;overflow:visible}.react-flow__edge-path,.react-flow__connection-path{stroke:#b1b1b7;stroke-width:1;fill:none}.react-flow__edge{pointer-events:visibleStroke;cursor:pointer}.react-flow__edge.animated path{stroke-dasharray:5;animation:dashdraw .5s linear infinite}.react-flow__edge.animated path.react-flow__edge-interaction{stroke-dasharray:none;animation:none}.react-flow__edge.inactive{pointer-events:none}.react-flow__edge.selected,.react-flow__edge:focus,.react-flow__edge:focus-visible{outline:none}.react-flow__edge.selected .react-flow__edge-path,.react-flow__edge:focus .react-flow__edge-path,.react-flow__edge:focus-visible .react-flow__edge-path{stroke:#555}.react-flow__edge-textwrapper{pointer-events:all}.react-flow__edge-textbg{fill:#fff}.react-flow__edge .react-flow__edge-text{pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.react-flow__connection{pointer-events:none}.react-flow__connection .animated{stroke-dasharray:5;animation:dashdraw .5s linear infinite}.react-flow__connectionline{z-index:1001}.react-flow__nodes{pointer-events:none;transform-origin:0 0}.react-flow__node{position:absolute;-webkit-user-select:none;-moz-user-select:none;user-select:none;pointer-events:all;transform-origin:0 0;box-sizing:border-box;cursor:grab}.react-flow__node.dragging{cursor:grabbing}.react-flow__nodesselection{z-index:3;transform-origin:left top;pointer-events:none}.react-flow__nodesselection-rect{position:absolute;pointer-events:all;cursor:grab}.react-flow__handle{position:absolute;pointer-events:none;min-width:5px;min-height:5px;width:6px;height:6px;background:#1a192b;border:1px solid white;border-radius:100%}.react-flow__handle.connectionindicator{pointer-events:all;cursor:crosshair}.react-flow__handle-bottom{top:auto;left:50%;bottom:-4px;transform:translate(-50%)}.react-flow__handle-top{left:50%;top:-4px;transform:translate(-50%)}.react-flow__handle-left{top:50%;left:-4px;transform:translateY(-50%)}.react-flow__handle-right{right:-4px;top:50%;transform:translateY(-50%)}.react-flow__edgeupdater{cursor:move;pointer-events:all}.react-flow__panel{position:absolute;z-index:5;margin:15px}.react-flow__panel.top{top:0}.react-flow__panel.bottom{bottom:0}.react-flow__panel.left{left:0}.react-flow__panel.right{right:0}.react-flow__panel.center{left:50%;transform:translate(-50%)}.react-flow__attribution{font-size:10px;background:#ffffff80;padding:2px 3px;margin:0}.react-flow__attribution a{text-decoration:none;color:#999}@keyframes dashdraw{0%{stroke-dashoffset:10}}.react-flow__edgelabel-renderer{position:absolute;width:100%;height:100%;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.react-flow__edge.updating .react-flow__edge-path{stroke:#777}.react-flow__edge-text{font-size:10px}.react-flow__node.selectable:focus,.react-flow__node.selectable:focus-visible{outline:none}.react-flow__node-default,.react-flow__node-input,.react-flow__node-output,.react-flow__node-group{padding:10px;border-radius:3px;width:150px;font-size:12px;color:#222;text-align:center;border-width:1px;border-style:solid;border-color:#1a192b;background-color:#fff}.react-flow__node-default.selectable:hover,.react-flow__node-input.selectable:hover,.react-flow__node-output.selectable:hover,.react-flow__node-group.selectable:hover{box-shadow:0 1px 4px 1px #00000014}.react-flow__node-default.selectable.selected,.react-flow__node-default.selectable:focus,.react-flow__node-default.selectable:focus-visible,.react-flow__node-input.selectable.selected,.react-flow__node-input.selectable:focus,.react-flow__node-input.selectable:focus-visible,.react-flow__node-output.selectable.selected,.react-flow__node-output.selectable:focus,.react-flow__node-output.selectable:focus-visible,.react-flow__node-group.selectable.selected,.react-flow__node-group.selectable:focus,.react-flow__node-group.selectable:focus-visible{box-shadow:0 0 0 .5px #1a192b}.react-flow__node-group{background-color:#f0f0f040}.react-flow__nodesselection-rect,.react-flow__selection{background:#0059dc14;border:1px dotted rgba(0,89,220,.8)}.react-flow__nodesselection-rect:focus,.react-flow__nodesselection-rect:focus-visible,.react-flow__selection:focus,.react-flow__selection:focus-visible{outline:none}.react-flow__controls{box-shadow:0 0 2px 1px #00000014}.react-flow__controls-button{border:none;background:#fefefe;border-bottom:1px solid #eee;box-sizing:content-box;display:flex;justify-content:center;align-items:center;width:16px;height:16px;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;user-select:none;padding:5px}.react-flow__controls-button:hover{background:#f4f4f4}.react-flow__controls-button svg{width:100%;max-width:12px;max-height:12px}.react-flow__controls-button:disabled{pointer-events:none}.react-flow__controls-button:disabled svg{fill-opacity:.4}.react-flow__minimap{background-color:#fff}.react-flow__minimap svg{display:block}.react-flow__resize-control{position:absolute}.react-flow__resize-control.left,.react-flow__resize-control.right{cursor:ew-resize}.react-flow__resize-control.top,.react-flow__resize-control.bottom{cursor:ns-resize}.react-flow__resize-control.top.left,.react-flow__resize-control.bottom.right{cursor:nwse-resize}.react-flow__resize-control.bottom.left,.react-flow__resize-control.top.right{cursor:nesw-resize}.react-flow__resize-control.handle{width:4px;height:4px;border:1px solid #fff;border-radius:1px;background-color:#3367d9;transform:translate(-50%,-50%)}.react-flow__resize-control.handle.left{left:0;top:50%}.react-flow__resize-control.handle.right{left:100%;top:50%}.react-flow__resize-control.handle.top{left:50%;top:0}.react-flow__resize-control.handle.bottom{left:50%;top:100%}.react-flow__resize-control.handle.top.left,.react-flow__resize-control.handle.bottom.left{left:0}.react-flow__resize-control.handle.top.right,.react-flow__resize-control.handle.bottom.right{left:100%}.react-flow__resize-control.line{border-color:#3367d9;border-width:0;border-style:solid}.react-flow__resize-control.line.left,.react-flow__resize-control.line.right{width:1px;transform:translate(-50%);top:0;height:100%}.react-flow__resize-control.line.left{left:0;border-left-width:1px}.react-flow__resize-control.line.right{left:100%;border-right-width:1px}.react-flow__resize-control.line.top,.react-flow__resize-control.line.bottom{height:1px;transform:translateY(-50%);left:0;width:100%}.react-flow__resize-control.line.top{top:0;border-top-width:1px}.react-flow__resize-control.line.bottom{border-bottom-width:1px;top:100%} diff --git a/webui/dist/assets/index-CWjV9Ftw.css b/webui/dist/assets/index-CWjV9Ftw.css deleted file mode 100644 index 37552871..00000000 --- a/webui/dist/assets/index-CWjV9Ftw.css +++ /dev/null @@ -1 +0,0 @@ -@charset "UTF-8";*,:before,:after{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}:before,:after{--tw-content: ""}html,:host{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}:root{--background: 0 0% 100%;--foreground: 222.2 84% 4.9%;--card: 0 0% 100%;--card-foreground: 222.2 84% 4.9%;--popover: 0 0% 100%;--popover-foreground: 222.2 84% 4.9%;--primary: 221.2 83.2% 53.3%;--primary-foreground: 210 40% 98%;--primary-gradient: none;--secondary: 210 40% 96.1%;--secondary-foreground: 222.2 47.4% 11.2%;--muted: 210 40% 96.1%;--muted-foreground: 215.4 16.3% 46.9%;--accent: 210 40% 96.1%;--accent-foreground: 222.2 47.4% 11.2%;--destructive: 0 84.2% 60.2%;--destructive-foreground: 210 40% 98%;--border: 214.3 31.8% 91.4%;--input: 214.3 31.8% 91.4%;--ring: 221.2 83.2% 53.3%;--radius: .5rem;--chart-1: 221.2 83.2% 53.3%;--chart-2: 160 60% 45%;--chart-3: 30 80% 55%;--chart-4: 280 65% 60%;--chart-5: 340 75% 55%}.dark{--background: 222.2 84% 4.9%;--foreground: 210 40% 98%;--card: 222.2 84% 4.9%;--card-foreground: 210 40% 98%;--popover: 222.2 84% 4.9%;--popover-foreground: 210 40% 98%;--primary: 217.2 91.2% 59.8%;--primary-foreground: 222.2 47.4% 11.2%;--primary-gradient: none;--secondary: 217.2 32.6% 17.5%;--secondary-foreground: 210 40% 98%;--muted: 217.2 32.6% 17.5%;--muted-foreground: 215 20.2% 65.1%;--accent: 217.2 32.6% 17.5%;--accent-foreground: 210 40% 98%;--destructive: 0 62.8% 30.6%;--destructive-foreground: 210 40% 98%;--border: 217.2 32.6% 17.5%;--input: 217.2 32.6% 17.5%;--ring: 224.3 76.3% 48%;--chart-1: 217.2 91.2% 59.8%;--chart-2: 160 60% 50%;--chart-3: 30 80% 60%;--chart-4: 280 65% 65%;--chart-5: 340 75% 60%}*{border-color:hsl(var(--border))}body{background-color:hsl(var(--background));color:hsl(var(--foreground))}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{-webkit-appearance:none;margin:0}input[type=number]{-moz-appearance:textfield;-webkit-appearance:textfield;appearance:textfield}.\!container{width:100%!important}.container{width:100%}@media(min-width:640px){.\!container{max-width:640px!important}.container{max-width:640px}}@media(min-width:768px){.\!container{max-width:768px!important}.container{max-width:768px}}@media(min-width:1024px){.\!container{max-width:1024px!important}.container{max-width:1024px}}@media(min-width:1280px){.\!container{max-width:1280px!important}.container{max-width:1280px}}@media(min-width:1536px){.\!container{max-width:1536px!important}.container{max-width:1536px}}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.pointer-events-none{pointer-events:none}.pointer-events-auto{pointer-events:auto}.invisible{visibility:hidden}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{inset:0}.inset-x-0{left:0;right:0}.inset-y-0{top:0;bottom:0}.bottom-0{bottom:0}.bottom-1\/4{bottom:25%}.bottom-4{bottom:1rem}.left-0{left:0}.left-1{left:.25rem}.left-1\/2{left:50%}.left-1\/4{left:25%}.left-2{left:.5rem}.left-2\.5{left:.625rem}.left-3{left:.75rem}.left-\[50\%\]{left:50%}.right-0{right:0}.right-1{right:.25rem}.right-1\.5{right:.375rem}.right-1\/4{right:25%}.right-2{right:.5rem}.right-4{right:1rem}.top-0{top:0}.top-1{top:.25rem}.top-1\.5{top:.375rem}.top-1\/2{top:50%}.top-1\/4{top:25%}.top-2{top:.5rem}.top-2\.5{top:.625rem}.top-3{top:.75rem}.top-4{top:1rem}.top-\[50\%\]{top:50%}.z-10{z-index:10}.z-40{z-index:40}.z-50{z-index:50}.z-\[100\]{z-index:100}.order-1{order:1}.order-2{order:2}.col-span-2{grid-column:span 2 / span 2}.-mx-1{margin-left:-.25rem;margin-right:-.25rem}.-mx-4{margin-left:-1rem;margin-right:-1rem}.mx-1{margin-left:.25rem;margin-right:.25rem}.mx-2{margin-left:.5rem;margin-right:.5rem}.mx-4{margin-left:1rem;margin-right:1rem}.mx-auto{margin-left:auto;margin-right:auto}.my-0\.5{margin-top:.125rem;margin-bottom:.125rem}.my-1{margin-top:.25rem;margin-bottom:.25rem}.my-2{margin-top:.5rem;margin-bottom:.5rem}.my-3{margin-top:.75rem;margin-bottom:.75rem}.my-4{margin-top:1rem;margin-bottom:1rem}.-mt-2{margin-top:-.5rem}.mb-1{margin-bottom:.25rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.mb-6{margin-bottom:1.5rem}.mb-8{margin-bottom:2rem}.ml-0\.5{margin-left:.125rem}.ml-1{margin-left:.25rem}.ml-10{margin-left:2.5rem}.ml-2{margin-left:.5rem}.ml-3{margin-left:.75rem}.ml-4{margin-left:1rem}.ml-6{margin-left:1.5rem}.ml-auto{margin-left:auto}.mr-1{margin-right:.25rem}.mr-2{margin-right:.5rem}.mt-0{margin-top:0}.mt-0\.5{margin-top:.125rem}.mt-1{margin-top:.25rem}.mt-1\.5{margin-top:.375rem}.mt-12{margin-top:3rem}.mt-2{margin-top:.5rem}.mt-3{margin-top:.75rem}.mt-4{margin-top:1rem}.mt-5{margin-top:1.25rem}.mt-6{margin-top:1.5rem}.line-clamp-1{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:1}.line-clamp-2{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2}.block{display:block}.inline{display:inline}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.hidden{display:none}.aspect-auto{aspect-ratio:auto}.aspect-square{aspect-ratio:1 / 1}.aspect-video{aspect-ratio:16 / 9}.size-4{width:1rem;height:1rem}.size-\[--cell-size\]{width:var(--cell-size);height:var(--cell-size)}.h-0\.5{height:.125rem}.h-1\.5{height:.375rem}.h-10{height:2.5rem}.h-12{height:3rem}.h-16{height:4rem}.h-2{height:.5rem}.h-2\.5{height:.625rem}.h-20{height:5rem}.h-3{height:.75rem}.h-3\.5{height:.875rem}.h-32{height:8rem}.h-4{height:1rem}.h-40{height:10rem}.h-48{height:12rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-60{height:15rem}.h-64{height:16rem}.h-7{height:1.75rem}.h-8{height:2rem}.h-9{height:2.25rem}.h-\[--cell-size\]{height:var(--cell-size)}.h-\[1\.25rem\]{height:1.25rem}.h-\[140px\]{height:140px}.h-\[1px\]{height:1px}.h-\[200px\]{height:200px}.h-\[250px\]{height:250px}.h-\[280px\]{height:280px}.h-\[300px\]{height:300px}.h-\[350px\]{height:350px}.h-\[400px\]{height:400px}.h-\[calc\(100vh-12rem\)\]{height:calc(100vh - 12rem)}.h-\[calc\(100vh-200px\)\]{height:calc(100vh - 200px)}.h-\[calc\(100vh-240px\)\]{height:calc(100vh - 240px)}.h-\[calc\(100vh-260px\)\]{height:calc(100vh - 260px)}.h-\[calc\(100vh-4rem\)\]{height:calc(100vh - 4rem)}.h-\[var\(--radix-select-trigger-height\)\]{height:var(--radix-select-trigger-height)}.h-auto{height:auto}.h-full{height:100%}.h-px{height:1px}.h-screen{height:100vh}.max-h-32{max-height:8rem}.max-h-64{max-height:16rem}.max-h-\[--radix-context-menu-content-available-height\]{max-height:var(--radix-context-menu-content-available-height)}.max-h-\[--radix-select-content-available-height\]{max-height:var(--radix-select-content-available-height)}.max-h-\[200px\]{max-height:200px}.max-h-\[300px\]{max-height:300px}.max-h-\[60vh\]{max-height:60vh}.max-h-\[80vh\]{max-height:80vh}.max-h-\[85vh\]{max-height:85vh}.max-h-\[90vh\]{max-height:90vh}.max-h-\[calc\(90vh-120px\)\]{max-height:calc(90vh - 120px)}.max-h-\[calc\(90vh-8rem\)\]{max-height:calc(90vh - 8rem)}.max-h-full{max-height:100%}.max-h-none{max-height:none}.max-h-screen{max-height:100vh}.min-h-0{min-height:0px}.min-h-10{min-height:2.5rem}.min-h-\[100px\]{min-height:100px}.min-h-\[140px\]{min-height:140px}.min-h-\[300px\]{min-height:300px}.min-h-\[400px\]{min-height:400px}.min-h-\[60px\]{min-height:60px}.min-h-screen{min-height:100vh}.w-0{width:0px}.w-1{width:.25rem}.w-1\.5{width:.375rem}.w-10{width:2.5rem}.w-12{width:3rem}.w-16{width:4rem}.w-2{width:.5rem}.w-2\.5{width:.625rem}.w-20{width:5rem}.w-24{width:6rem}.w-28{width:7rem}.w-3{width:.75rem}.w-3\.5{width:.875rem}.w-32{width:8rem}.w-4{width:1rem}.w-5{width:1.25rem}.w-6{width:1.5rem}.w-64{width:16rem}.w-7{width:1.75rem}.w-72{width:18rem}.w-8{width:2rem}.w-80{width:20rem}.w-9{width:2.25rem}.w-\[--cell-size\]{width:var(--cell-size)}.w-\[100px\]{width:100px}.w-\[120px\]{width:120px}.w-\[130px\]{width:130px}.w-\[1px\]{width:1px}.w-\[65px\]{width:65px}.w-\[95vw\]{width:95vw}.w-auto{width:auto}.w-fit{width:-moz-fit-content;width:fit-content}.w-full{width:100%}.w-px{width:1px}.min-w-0{min-width:0px}.min-w-\[--cell-size\]{min-width:var(--cell-size)}.min-w-\[100px\]{min-width:100px}.min-w-\[120px\]{min-width:120px}.min-w-\[80px\]{min-width:80px}.min-w-\[8rem\]{min-width:8rem}.min-w-\[var\(--radix-select-trigger-width\)\]{min-width:var(--radix-select-trigger-width)}.min-w-full{min-width:100%}.max-w-2xl{max-width:42rem}.max-w-32{max-width:8rem}.max-w-3xl{max-width:48rem}.max-w-4xl{max-width:56rem}.max-w-\[100px\]{max-width:100px}.max-w-\[150px\]{max-width:150px}.max-w-\[200px\]{max-width:200px}.max-w-\[60px\]{max-width:60px}.max-w-\[75\%\]{max-width:75%}.max-w-\[90\%\]{max-width:90%}.max-w-\[95vw\]{max-width:95vw}.max-w-full{max-width:100%}.max-w-lg{max-width:32rem}.max-w-md{max-width:28rem}.max-w-none{max-width:none}.max-w-xs{max-width:20rem}.flex-1{flex:1 1 0%}.flex-shrink-0,.shrink-0{flex-shrink:0}.grow{flex-grow:1}.caption-bottom{caption-side:bottom}.border-collapse{border-collapse:collapse}.origin-\[--radix-context-menu-content-transform-origin\]{transform-origin:var(--radix-context-menu-content-transform-origin)}.origin-\[--radix-popover-content-transform-origin\]{transform-origin:var(--radix-popover-content-transform-origin)}.origin-\[--radix-select-content-transform-origin\]{transform-origin:var(--radix-select-content-transform-origin)}.origin-\[--radix-tooltip-content-transform-origin\]{transform-origin:var(--radix-tooltip-content-transform-origin)}.-translate-x-full{--tw-translate-x: -100%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-y-1\/2{--tw-translate-y: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-0{--tw-translate-x: 0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-\[-50\%\]{--tw-translate-x: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-y-\[-50\%\]{--tw-translate-y: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.rotate-180{--tw-rotate: 180deg;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes bounce{0%,to{transform:translateY(-25%);animation-timing-function:cubic-bezier(.8,0,1,1)}50%{transform:none;animation-timing-function:cubic-bezier(0,0,.2,1)}}.animate-bounce{animation:bounce 1s infinite}@keyframes pulse{50%{opacity:.5}}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}@keyframes spin{to{transform:rotate(360deg)}}.animate-spin{animation:spin 1s linear infinite}.cursor-default{cursor:default}.cursor-grab{cursor:grab}.cursor-move{cursor:move}.cursor-not-allowed{cursor:not-allowed}.cursor-pointer{cursor:pointer}.touch-none{touch-action:none}.select-none{-webkit-user-select:none;-moz-user-select:none;user-select:none}.select-all{-webkit-user-select:all;-moz-user-select:all;user-select:all}.resize-y{resize:vertical}.resize{resize:both}.list-inside{list-style-position:inside}.list-decimal{list-style-type:decimal}.list-disc{list-style-type:disc}.list-none{list-style-type:none}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.grid-cols-\[1fr_1fr_90px_32px\]{grid-template-columns:1fr 1fr 90px 32px}.grid-rows-\[auto_1fr_auto\]{grid-template-rows:auto 1fr auto}.flex-row{flex-direction:row}.flex-row-reverse{flex-direction:row-reverse}.flex-col{flex-direction:column}.flex-col-reverse{flex-direction:column-reverse}.flex-wrap{flex-wrap:wrap}.place-content-center{place-content:center}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.items-center{align-items:center}.items-baseline{align-items:baseline}.items-stretch{align-items:stretch}.justify-start{justify-content:flex-start}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-0{gap:0px}.gap-0\.5{gap:.125rem}.gap-1{gap:.25rem}.gap-1\.5{gap:.375rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.gap-6{gap:1.5rem}.space-x-2>:not([hidden])~:not([hidden]){--tw-space-x-reverse: 0;margin-right:calc(.5rem * var(--tw-space-x-reverse));margin-left:calc(.5rem * calc(1 - var(--tw-space-x-reverse)))}.space-y-0>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(0px * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(0px * var(--tw-space-y-reverse))}.space-y-0\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.125rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.125rem * var(--tw-space-y-reverse))}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.25rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.25rem * var(--tw-space-y-reverse))}.space-y-1\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.375rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.375rem * var(--tw-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem * var(--tw-space-y-reverse))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.75rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem * var(--tw-space-y-reverse))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem * var(--tw-space-y-reverse))}.space-y-6>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.5rem * var(--tw-space-y-reverse))}.space-y-8>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(2rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(2rem * var(--tw-space-y-reverse))}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-visible{overflow:visible}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.overflow-x-hidden{overflow-x:hidden}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.text-ellipsis{text-overflow:ellipsis}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-line{white-space:pre-line}.whitespace-pre-wrap{white-space:pre-wrap}.break-words{overflow-wrap:break-word}.break-all{word-break:break-all}.rounded{border-radius:.25rem}.rounded-2xl{border-radius:1rem}.rounded-\[2px\]{border-radius:2px}.rounded-\[inherit\]{border-radius:inherit}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:var(--radius)}.rounded-md{border-radius:calc(var(--radius) - 2px)}.rounded-none{border-radius:0}.rounded-sm{border-radius:calc(var(--radius) - 4px)}.rounded-xl{border-radius:.75rem}.rounded-l-md{border-top-left-radius:calc(var(--radius) - 2px);border-bottom-left-radius:calc(var(--radius) - 2px)}.rounded-r-full{border-top-right-radius:9999px;border-bottom-right-radius:9999px}.rounded-r-md{border-top-right-radius:calc(var(--radius) - 2px);border-bottom-right-radius:calc(var(--radius) - 2px)}.rounded-tl-sm{border-top-left-radius:calc(var(--radius) - 4px)}.rounded-tr-sm{border-top-right-radius:calc(var(--radius) - 4px)}.border{border-width:1px}.border-0{border-width:0px}.border-2{border-width:2px}.border-4{border-width:4px}.border-\[1\.5px\]{border-width:1.5px}.border-b{border-bottom-width:1px}.border-l{border-left-width:1px}.border-l-2{border-left-width:2px}.border-l-4{border-left-width:4px}.border-r{border-right-width:1px}.border-t{border-top-width:1px}.border-dashed{border-style:dashed}.border-\[--color-border\]{border-color:var(--color-border)}.border-amber-200{--tw-border-opacity: 1;border-color:rgb(253 230 138 / var(--tw-border-opacity, 1))}.border-amber-500\/50{border-color:#f59e0b80}.border-blue-200{--tw-border-opacity: 1;border-color:rgb(191 219 254 / var(--tw-border-opacity, 1))}.border-blue-500{--tw-border-opacity: 1;border-color:rgb(59 130 246 / var(--tw-border-opacity, 1))}.border-blue-700{--tw-border-opacity: 1;border-color:rgb(29 78 216 / var(--tw-border-opacity, 1))}.border-border{border-color:hsl(var(--border))}.border-border\/50{border-color:hsl(var(--border) / .5)}.border-current{border-color:currentColor}.border-gray-800{--tw-border-opacity: 1;border-color:rgb(31 41 55 / var(--tw-border-opacity, 1))}.border-green-200{--tw-border-opacity: 1;border-color:rgb(187 247 208 / var(--tw-border-opacity, 1))}.border-green-300{--tw-border-opacity: 1;border-color:rgb(134 239 172 / var(--tw-border-opacity, 1))}.border-green-500{--tw-border-opacity: 1;border-color:rgb(34 197 94 / var(--tw-border-opacity, 1))}.border-green-600{--tw-border-opacity: 1;border-color:rgb(22 163 74 / var(--tw-border-opacity, 1))}.border-green-700{--tw-border-opacity: 1;border-color:rgb(21 128 61 / var(--tw-border-opacity, 1))}.border-input{border-color:hsl(var(--input))}.border-muted{border-color:hsl(var(--muted))}.border-muted-foreground\/30{border-color:hsl(var(--muted-foreground) / .3)}.border-muted-foreground\/50{border-color:hsl(var(--muted-foreground) / .5)}.border-orange-200{--tw-border-opacity: 1;border-color:rgb(254 215 170 / var(--tw-border-opacity, 1))}.border-orange-600{--tw-border-opacity: 1;border-color:rgb(234 88 12 / var(--tw-border-opacity, 1))}.border-primary{border-color:hsl(var(--primary))}.border-primary\/20{border-color:hsl(var(--primary) / .2)}.border-primary\/30{border-color:hsl(var(--primary) / .3)}.border-primary\/50{border-color:hsl(var(--primary) / .5)}.border-purple-500{--tw-border-opacity: 1;border-color:rgb(168 85 247 / var(--tw-border-opacity, 1))}.border-red-300{--tw-border-opacity: 1;border-color:rgb(252 165 165 / var(--tw-border-opacity, 1))}.border-red-500{--tw-border-opacity: 1;border-color:rgb(239 68 68 / var(--tw-border-opacity, 1))}.border-red-500\/50{border-color:#ef444480}.border-transparent{border-color:transparent}.border-yellow-200{--tw-border-opacity: 1;border-color:rgb(254 240 138 / var(--tw-border-opacity, 1))}.border-yellow-500\/50{border-color:#eab30880}.border-l-transparent{border-left-color:transparent}.border-t-transparent{border-top-color:transparent}.bg-\[--color-bg\]{background-color:var(--color-bg)}.bg-accent{background-color:hsl(var(--accent))}.bg-amber-50{--tw-bg-opacity: 1;background-color:rgb(255 251 235 / var(--tw-bg-opacity, 1))}.bg-amber-500\/10{background-color:#f59e0b1a}.bg-background{background-color:hsl(var(--background))}.bg-background\/50{background-color:hsl(var(--background) / .5)}.bg-background\/80{background-color:hsl(var(--background) / .8)}.bg-background\/95{background-color:hsl(var(--background) / .95)}.bg-black{--tw-bg-opacity: 1;background-color:rgb(0 0 0 / var(--tw-bg-opacity, 1))}.bg-black\/50{background-color:#00000080}.bg-black\/80{background-color:#000c}.bg-blue-100{--tw-bg-opacity: 1;background-color:rgb(219 234 254 / var(--tw-bg-opacity, 1))}.bg-blue-50{--tw-bg-opacity: 1;background-color:rgb(239 246 255 / var(--tw-bg-opacity, 1))}.bg-blue-500{--tw-bg-opacity: 1;background-color:rgb(59 130 246 / var(--tw-bg-opacity, 1))}.bg-blue-600{--tw-bg-opacity: 1;background-color:rgb(37 99 235 / var(--tw-bg-opacity, 1))}.bg-blue-900\/20{background-color:#1e3a8a33}.bg-border{background-color:hsl(var(--border))}.bg-card{background-color:hsl(var(--card))}.bg-card\/80{background-color:hsl(var(--card) / .8)}.bg-gray-100{--tw-bg-opacity: 1;background-color:rgb(243 244 246 / var(--tw-bg-opacity, 1))}.bg-gray-400{--tw-bg-opacity: 1;background-color:rgb(156 163 175 / var(--tw-bg-opacity, 1))}.bg-gray-800\/20{background-color:#1f293733}.bg-gray-800\/30{background-color:#1f29374d}.bg-green-100{--tw-bg-opacity: 1;background-color:rgb(220 252 231 / var(--tw-bg-opacity, 1))}.bg-green-50{--tw-bg-opacity: 1;background-color:rgb(240 253 244 / var(--tw-bg-opacity, 1))}.bg-green-500{--tw-bg-opacity: 1;background-color:rgb(34 197 94 / var(--tw-bg-opacity, 1))}.bg-green-600{--tw-bg-opacity: 1;background-color:rgb(22 163 74 / var(--tw-bg-opacity, 1))}.bg-muted{background-color:hsl(var(--muted))}.bg-muted-foreground\/50{background-color:hsl(var(--muted-foreground) / .5)}.bg-muted\/20{background-color:hsl(var(--muted) / .2)}.bg-muted\/30{background-color:hsl(var(--muted) / .3)}.bg-muted\/50{background-color:hsl(var(--muted) / .5)}.bg-muted\/60{background-color:hsl(var(--muted) / .6)}.bg-orange-50{--tw-bg-opacity: 1;background-color:rgb(255 247 237 / var(--tw-bg-opacity, 1))}.bg-orange-500{--tw-bg-opacity: 1;background-color:rgb(249 115 22 / var(--tw-bg-opacity, 1))}.bg-orange-600{--tw-bg-opacity: 1;background-color:rgb(234 88 12 / var(--tw-bg-opacity, 1))}.bg-pink-500{--tw-bg-opacity: 1;background-color:rgb(236 72 153 / var(--tw-bg-opacity, 1))}.bg-popover{background-color:hsl(var(--popover))}.bg-primary{background-color:hsl(var(--primary))}.bg-primary-foreground\/20{background-color:hsl(var(--primary-foreground) / .2)}.bg-primary\/10{background-color:hsl(var(--primary) / .1)}.bg-primary\/20{background-color:hsl(var(--primary) / .2)}.bg-primary\/5{background-color:hsl(var(--primary) / .05)}.bg-primary\/60{background-color:hsl(var(--primary) / .6)}.bg-purple-100{--tw-bg-opacity: 1;background-color:rgb(243 232 255 / var(--tw-bg-opacity, 1))}.bg-purple-500{--tw-bg-opacity: 1;background-color:rgb(168 85 247 / var(--tw-bg-opacity, 1))}.bg-red-100{--tw-bg-opacity: 1;background-color:rgb(254 226 226 / var(--tw-bg-opacity, 1))}.bg-red-50{--tw-bg-opacity: 1;background-color:rgb(254 242 242 / var(--tw-bg-opacity, 1))}.bg-red-500{--tw-bg-opacity: 1;background-color:rgb(239 68 68 / var(--tw-bg-opacity, 1))}.bg-red-500\/10{background-color:#ef44441a}.bg-red-600{--tw-bg-opacity: 1;background-color:rgb(220 38 38 / var(--tw-bg-opacity, 1))}.bg-red-900\/20{background-color:#7f1d1d33}.bg-red-900\/30{background-color:#7f1d1d4d}.bg-secondary{background-color:hsl(var(--secondary))}.bg-secondary\/5{background-color:hsl(var(--secondary) / .05)}.bg-slate-200{--tw-bg-opacity: 1;background-color:rgb(226 232 240 / var(--tw-bg-opacity, 1))}.bg-slate-300{--tw-bg-opacity: 1;background-color:rgb(203 213 225 / var(--tw-bg-opacity, 1))}.bg-slate-400{--tw-bg-opacity: 1;background-color:rgb(148 163 184 / var(--tw-bg-opacity, 1))}.bg-slate-700{--tw-bg-opacity: 1;background-color:rgb(51 65 85 / var(--tw-bg-opacity, 1))}.bg-slate-800{--tw-bg-opacity: 1;background-color:rgb(30 41 59 / var(--tw-bg-opacity, 1))}.bg-slate-900{--tw-bg-opacity: 1;background-color:rgb(15 23 42 / var(--tw-bg-opacity, 1))}.bg-transparent{background-color:transparent}.bg-white{--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity, 1))}.bg-yellow-200{--tw-bg-opacity: 1;background-color:rgb(254 240 138 / var(--tw-bg-opacity, 1))}.bg-yellow-50{--tw-bg-opacity: 1;background-color:rgb(254 252 232 / var(--tw-bg-opacity, 1))}.bg-yellow-500\/5{background-color:#eab3080d}.bg-yellow-900\/20{background-color:#713f1233}.bg-gradient-to-br{background-image:linear-gradient(to bottom right,var(--tw-gradient-stops))}.bg-gradient-to-r{background-image:linear-gradient(to right,var(--tw-gradient-stops))}.from-blue-500{--tw-gradient-from: #3b82f6 var(--tw-gradient-from-position);--tw-gradient-to: rgb(59 130 246 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.from-green-500{--tw-gradient-from: #22c55e var(--tw-gradient-from-position);--tw-gradient-to: rgb(34 197 94 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.from-indigo-500{--tw-gradient-from: #6366f1 var(--tw-gradient-from-position);--tw-gradient-to: rgb(99 102 241 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.from-orange-500{--tw-gradient-from: #f97316 var(--tw-gradient-from-position);--tw-gradient-to: rgb(249 115 22 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.from-primary\/5{--tw-gradient-from: hsl(var(--primary) / .05) var(--tw-gradient-from-position);--tw-gradient-to: hsl(var(--primary) / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.from-purple-500{--tw-gradient-from: #a855f7 var(--tw-gradient-from-position);--tw-gradient-to: rgb(168 85 247 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.from-red-500{--tw-gradient-from: #ef4444 var(--tw-gradient-from-position);--tw-gradient-to: rgb(239 68 68 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.from-slate-200{--tw-gradient-from: #e2e8f0 var(--tw-gradient-from-position);--tw-gradient-to: rgb(226 232 240 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.from-slate-300{--tw-gradient-from: #cbd5e1 var(--tw-gradient-from-position);--tw-gradient-to: rgb(203 213 225 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.from-slate-400{--tw-gradient-from: #94a3b8 var(--tw-gradient-from-position);--tw-gradient-to: rgb(148 163 184 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.via-background{--tw-gradient-to: hsl(var(--background) / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), hsl(var(--background)) var(--tw-gradient-via-position), var(--tw-gradient-to)}.to-blue-600{--tw-gradient-to: #2563eb var(--tw-gradient-to-position)}.to-cyan-500{--tw-gradient-to: #06b6d4 var(--tw-gradient-to-position)}.to-emerald-500{--tw-gradient-to: #10b981 var(--tw-gradient-to-position)}.to-green-600{--tw-gradient-to: #16a34a var(--tw-gradient-to-position)}.to-orange-500{--tw-gradient-to: #f97316 var(--tw-gradient-to-position)}.to-pink-500{--tw-gradient-to: #ec4899 var(--tw-gradient-to-position)}.to-primary\/10{--tw-gradient-to: hsl(var(--primary) / .1) var(--tw-gradient-to-position)}.to-purple-500{--tw-gradient-to: #a855f7 var(--tw-gradient-to-position)}.to-secondary\/5{--tw-gradient-to: hsl(var(--secondary) / .05) var(--tw-gradient-to-position)}.to-slate-700{--tw-gradient-to: #334155 var(--tw-gradient-to-position)}.to-slate-800{--tw-gradient-to: #1e293b var(--tw-gradient-to-position)}.to-slate-900{--tw-gradient-to: #0f172a var(--tw-gradient-to-position)}.fill-current{fill:currentColor}.fill-yellow-400{fill:#facc15}.object-contain{-o-object-fit:contain;object-fit:contain}.object-cover{-o-object-fit:cover;object-fit:cover}.p-0{padding:0}.p-0\.5{padding:.125rem}.p-1{padding:.25rem}.p-1\.5{padding:.375rem}.p-2{padding:.5rem}.p-2\.5{padding:.625rem}.p-3{padding:.75rem}.p-4{padding:1rem}.p-6{padding:1.5rem}.p-8{padding:2rem}.p-\[1px\]{padding:1px}.px-1{padding-left:.25rem;padding-right:.25rem}.px-1\.5{padding-left:.375rem;padding-right:.375rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-2\.5{padding-left:.625rem;padding-right:.625rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-8{padding-left:2rem;padding-right:2rem}.px-\[--cell-size\]{padding-left:var(--cell-size);padding-right:var(--cell-size)}.py-0{padding-top:0;padding-bottom:0}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.py-12{padding-top:3rem;padding-bottom:3rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-2\.5{padding-top:.625rem;padding-bottom:.625rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-4{padding-top:1rem;padding-bottom:1rem}.py-6{padding-top:1.5rem;padding-bottom:1.5rem}.py-8{padding-top:2rem;padding-bottom:2rem}.pb-0{padding-bottom:0}.pb-2{padding-bottom:.5rem}.pb-3{padding-bottom:.75rem}.pl-10{padding-left:2.5rem}.pl-11{padding-left:2.75rem}.pl-2{padding-left:.5rem}.pl-4{padding-left:1rem}.pl-6{padding-left:1.5rem}.pl-8{padding-left:2rem}.pl-9{padding-left:2.25rem}.pr-1{padding-right:.25rem}.pr-10{padding-right:2.5rem}.pr-16{padding-right:4rem}.pr-2{padding-right:.5rem}.pr-4{padding-right:1rem}.pr-6{padding-right:1.5rem}.pr-8{padding-right:2rem}.pt-0{padding-top:0}.pt-1{padding-top:.25rem}.pt-2{padding-top:.5rem}.pt-3{padding-top:.75rem}.pt-4{padding-top:1rem}.pt-6{padding-top:1.5rem}.pt-8{padding-top:2rem}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.align-middle{vertical-align:middle}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-2xl{font-size:1.5rem;line-height:2rem}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-\[0\.8rem\]{font-size:.8rem}.text-\[10px\]{font-size:10px}.text-\[150px\]{font-size:150px}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-black{font-weight:900}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-normal{font-weight:400}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.italic{font-style:italic}.tabular-nums{--tw-numeric-spacing: tabular-nums;font-variant-numeric:var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) var(--tw-numeric-spacing) var(--tw-numeric-fraction)}.leading-none{line-height:1}.leading-relaxed{line-height:1.625}.tracking-tight{letter-spacing:-.025em}.tracking-wider{letter-spacing:.05em}.tracking-widest{letter-spacing:.1em}.text-accent-foreground{color:hsl(var(--accent-foreground))}.text-amber-600{--tw-text-opacity: 1;color:rgb(217 119 6 / var(--tw-text-opacity, 1))}.text-amber-700{--tw-text-opacity: 1;color:rgb(180 83 9 / var(--tw-text-opacity, 1))}.text-amber-900{--tw-text-opacity: 1;color:rgb(120 53 15 / var(--tw-text-opacity, 1))}.text-blue-500{--tw-text-opacity: 1;color:rgb(59 130 246 / var(--tw-text-opacity, 1))}.text-blue-600{--tw-text-opacity: 1;color:rgb(37 99 235 / var(--tw-text-opacity, 1))}.text-blue-700{--tw-text-opacity: 1;color:rgb(29 78 216 / var(--tw-text-opacity, 1))}.text-blue-800{--tw-text-opacity: 1;color:rgb(30 64 175 / var(--tw-text-opacity, 1))}.text-blue-900{--tw-text-opacity: 1;color:rgb(30 58 138 / var(--tw-text-opacity, 1))}.text-card-foreground{color:hsl(var(--card-foreground))}.text-current{color:currentColor}.text-cyan-400{--tw-text-opacity: 1;color:rgb(34 211 238 / var(--tw-text-opacity, 1))}.text-foreground{color:hsl(var(--foreground))}.text-foreground\/50{color:hsl(var(--foreground) / .5)}.text-gray-300{--tw-text-opacity: 1;color:rgb(209 213 219 / var(--tw-text-opacity, 1))}.text-gray-500{--tw-text-opacity: 1;color:rgb(107 114 128 / var(--tw-text-opacity, 1))}.text-gray-600{--tw-text-opacity: 1;color:rgb(75 85 99 / var(--tw-text-opacity, 1))}.text-gray-700{--tw-text-opacity: 1;color:rgb(55 65 81 / var(--tw-text-opacity, 1))}.text-gray-900{--tw-text-opacity: 1;color:rgb(17 24 39 / var(--tw-text-opacity, 1))}.text-green-500{--tw-text-opacity: 1;color:rgb(34 197 94 / var(--tw-text-opacity, 1))}.text-green-600{--tw-text-opacity: 1;color:rgb(22 163 74 / var(--tw-text-opacity, 1))}.text-green-700{--tw-text-opacity: 1;color:rgb(21 128 61 / var(--tw-text-opacity, 1))}.text-muted-foreground{color:hsl(var(--muted-foreground))}.text-muted-foreground\/50{color:hsl(var(--muted-foreground) / .5)}.text-muted-foreground\/60{color:hsl(var(--muted-foreground) / .6)}.text-orange-600{--tw-text-opacity: 1;color:rgb(234 88 12 / var(--tw-text-opacity, 1))}.text-orange-800{--tw-text-opacity: 1;color:rgb(154 52 18 / var(--tw-text-opacity, 1))}.text-orange-900{--tw-text-opacity: 1;color:rgb(124 45 18 / var(--tw-text-opacity, 1))}.text-popover-foreground{color:hsl(var(--popover-foreground))}.text-primary{color:hsl(var(--primary))}.text-primary-foreground{color:hsl(var(--primary-foreground))}.text-primary-foreground\/70{color:hsl(var(--primary-foreground) / .7)}.text-primary\/10{color:hsl(var(--primary) / .1)}.text-primary\/30{color:hsl(var(--primary) / .3)}.text-primary\/60{color:hsl(var(--primary) / .6)}.text-purple-500{--tw-text-opacity: 1;color:rgb(168 85 247 / var(--tw-text-opacity, 1))}.text-purple-600{--tw-text-opacity: 1;color:rgb(147 51 234 / var(--tw-text-opacity, 1))}.text-purple-700{--tw-text-opacity: 1;color:rgb(126 34 206 / var(--tw-text-opacity, 1))}.text-red-500{--tw-text-opacity: 1;color:rgb(239 68 68 / var(--tw-text-opacity, 1))}.text-red-600{--tw-text-opacity: 1;color:rgb(220 38 38 / var(--tw-text-opacity, 1))}.text-red-700{--tw-text-opacity: 1;color:rgb(185 28 28 / var(--tw-text-opacity, 1))}.text-secondary-foreground{color:hsl(var(--secondary-foreground))}.text-white{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.text-yellow-400{--tw-text-opacity: 1;color:rgb(250 204 21 / var(--tw-text-opacity, 1))}.text-yellow-500{--tw-text-opacity: 1;color:rgb(234 179 8 / var(--tw-text-opacity, 1))}.text-yellow-600{--tw-text-opacity: 1;color:rgb(202 138 4 / var(--tw-text-opacity, 1))}.text-yellow-800{--tw-text-opacity: 1;color:rgb(133 77 14 / var(--tw-text-opacity, 1))}.text-yellow-900{--tw-text-opacity: 1;color:rgb(113 63 18 / var(--tw-text-opacity, 1))}.underline{text-decoration-line:underline}.underline-offset-4{text-underline-offset:4px}.opacity-0{opacity:0}.opacity-100{opacity:1}.opacity-50{opacity:.5}.opacity-70{opacity:.7}.opacity-90{opacity:.9}.shadow{--tw-shadow: 0 1px 3px 0 rgb(0 0 0 / .1), 0 1px 2px -1px rgb(0 0 0 / .1);--tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-2xl{--tw-shadow: 0 25px 50px -12px rgb(0 0 0 / .25);--tw-shadow-colored: 0 25px 50px -12px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-lg{--tw-shadow: 0 10px 15px -3px rgb(0 0 0 / .1), 0 4px 6px -4px rgb(0 0 0 / .1);--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-md{--tw-shadow: 0 4px 6px -1px rgb(0 0 0 / .1), 0 2px 4px -2px rgb(0 0 0 / .1);--tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-none{--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-sm{--tw-shadow: 0 1px 2px 0 rgb(0 0 0 / .05);--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-xl{--tw-shadow: 0 20px 25px -5px rgb(0 0 0 / .1), 0 8px 10px -6px rgb(0 0 0 / .1);--tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.outline-none{outline:2px solid transparent;outline-offset:2px}.outline{outline-style:solid}.ring-0{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(0px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.ring-2{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.ring-primary{--tw-ring-color: hsl(var(--primary))}.ring-offset-background{--tw-ring-offset-color: hsl(var(--background))}.blur-3xl{--tw-blur: blur(64px);filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.backdrop-blur{--tw-backdrop-blur: blur(8px);-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.backdrop-blur-md{--tw-backdrop-blur: blur(12px);-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.backdrop-blur-sm{--tw-backdrop-blur: blur(4px);-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.backdrop-blur-xl{--tw-backdrop-blur: blur(24px);-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.backdrop-filter{-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-all{transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-opacity{transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-shadow{transition-property:box-shadow;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-transform{transition-property:transform;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.duration-200{transition-duration:.2s}.duration-300{transition-duration:.3s}.ease-in-out{transition-timing-function:cubic-bezier(.4,0,.2,1)}.text-primary-gradient{color:hsl(var(--primary))}.has-gradient .text-primary-gradient{background:var(--primary-gradient);-webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:transparent;color:transparent}.\[--cell-size\:2rem\]{--cell-size: 2rem}.no-animations *,.no-animations *:before,.no-animations *:after{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important}.no-animations *:hover{transition-duration:.01ms!important}::view-transition-old(root),::view-transition-new(root){animation:none;mix-blend-mode:normal}::view-transition-old(root){z-index:1}::view-transition-new(root){z-index:999}.__floater{z-index:99999!important;pointer-events:auto!important}.react-joyride__overlay,.react-joyride__spotlight{z-index:99998!important}.react-joyride__tooltip{pointer-events:auto!important}#tour-portal-container *{pointer-events:auto}.file\:border-0::file-selector-button{border-width:0px}.file\:bg-transparent::file-selector-button{background-color:transparent}.file\:text-sm::file-selector-button{font-size:.875rem;line-height:1.25rem}.file\:font-medium::file-selector-button{font-weight:500}.file\:text-foreground::file-selector-button{color:hsl(var(--foreground))}.placeholder\:text-muted-foreground::-moz-placeholder{color:hsl(var(--muted-foreground))}.placeholder\:text-muted-foreground::placeholder{color:hsl(var(--muted-foreground))}.hover\:border-muted-foreground\/50:hover{border-color:hsl(var(--muted-foreground) / .5)}.hover\:border-primary\/50:hover{border-color:hsl(var(--primary) / .5)}.hover\:bg-accent:hover{background-color:hsl(var(--accent))}.hover\:bg-accent\/50:hover{background-color:hsl(var(--accent) / .5)}.hover\:bg-blue-700:hover{--tw-bg-opacity: 1;background-color:rgb(29 78 216 / var(--tw-bg-opacity, 1))}.hover\:bg-gray-100:hover{--tw-bg-opacity: 1;background-color:rgb(243 244 246 / var(--tw-bg-opacity, 1))}.hover\:bg-green-700:hover{--tw-bg-opacity: 1;background-color:rgb(21 128 61 / var(--tw-bg-opacity, 1))}.hover\:bg-muted:hover{background-color:hsl(var(--muted))}.hover\:bg-muted-foreground\/20:hover{background-color:hsl(var(--muted-foreground) / .2)}.hover\:bg-muted\/50:hover{background-color:hsl(var(--muted) / .5)}.hover\:bg-orange-700:hover{--tw-bg-opacity: 1;background-color:rgb(194 65 12 / var(--tw-bg-opacity, 1))}.hover\:bg-primary\/10:hover{background-color:hsl(var(--primary) / .1)}.hover\:bg-primary\/80:hover{background-color:hsl(var(--primary) / .8)}.hover\:bg-primary\/90:hover{background-color:hsl(var(--primary) / .9)}.hover\:bg-red-700:hover{--tw-bg-opacity: 1;background-color:rgb(185 28 28 / var(--tw-bg-opacity, 1))}.hover\:bg-secondary:hover{background-color:hsl(var(--secondary))}.hover\:bg-secondary\/80:hover{background-color:hsl(var(--secondary) / .8)}.hover\:bg-secondary\/90:hover{background-color:hsl(var(--secondary) / .9)}.hover\:bg-transparent:hover{background-color:transparent}.hover\:bg-white\/5:hover{background-color:#ffffff0d}.hover\:text-accent-foreground:hover{color:hsl(var(--accent-foreground))}.hover\:text-foreground:hover{color:hsl(var(--foreground))}.hover\:text-green-700:hover{--tw-text-opacity: 1;color:rgb(21 128 61 / var(--tw-text-opacity, 1))}.hover\:text-orange-700:hover{--tw-text-opacity: 1;color:rgb(194 65 12 / var(--tw-text-opacity, 1))}.hover\:text-primary\/80:hover{color:hsl(var(--primary) / .8)}.hover\:text-red-700:hover{--tw-text-opacity: 1;color:rgb(185 28 28 / var(--tw-text-opacity, 1))}.hover\:text-yellow-300:hover{--tw-text-opacity: 1;color:rgb(253 224 71 / var(--tw-text-opacity, 1))}.hover\:underline:hover{text-decoration-line:underline}.hover\:opacity-100:hover{opacity:1}.hover\:shadow-lg:hover{--tw-shadow: 0 10px 15px -3px rgb(0 0 0 / .1), 0 4px 6px -4px rgb(0 0 0 / .1);--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.hover\:ring-2:hover{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.hover\:ring-primary:hover{--tw-ring-color: hsl(var(--primary))}.focus\:bg-accent:focus{background-color:hsl(var(--accent))}.focus\:bg-gray-100:focus{--tw-bg-opacity: 1;background-color:rgb(243 244 246 / var(--tw-bg-opacity, 1))}.focus\:text-accent-foreground:focus{color:hsl(var(--accent-foreground))}.focus\:opacity-100:focus{opacity:1}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.focus\:ring-1:focus{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus\:ring-2:focus{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus\:ring-ring:focus{--tw-ring-color: hsl(var(--ring))}.focus\:ring-offset-2:focus{--tw-ring-offset-width: 2px}.focus-visible\:outline-none:focus-visible{outline:2px solid transparent;outline-offset:2px}.focus-visible\:ring-0:focus-visible{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(0px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus-visible\:ring-1:focus-visible{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus-visible\:ring-2:focus-visible{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus-visible\:ring-red-500:focus-visible{--tw-ring-opacity: 1;--tw-ring-color: rgb(239 68 68 / var(--tw-ring-opacity, 1))}.focus-visible\:ring-ring:focus-visible{--tw-ring-color: hsl(var(--ring))}.focus-visible\:ring-offset-2:focus-visible{--tw-ring-offset-width: 2px}.focus-visible\:ring-offset-background:focus-visible{--tw-ring-offset-color: hsl(var(--background))}.active\:cursor-grabbing:active{cursor:grabbing}.active\:border-primary\/70:active{border-color:hsl(var(--primary) / .7)}.disabled\:pointer-events-none:disabled{pointer-events:none}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-50:disabled{opacity:.5}.group[open] .group-open\:rotate-180{--tw-rotate: 180deg;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group:hover .group-hover\:opacity-100{opacity:1}.group.destructive .group-\[\.destructive\]\:border-muted\/40{border-color:hsl(var(--muted) / .4)}.group.destructive .group-\[\.destructive\]\:text-red-300{--tw-text-opacity: 1;color:rgb(252 165 165 / var(--tw-text-opacity, 1))}.group.destructive .group-\[\.destructive\]\:hover\:text-red-50:hover{--tw-text-opacity: 1;color:rgb(254 242 242 / var(--tw-text-opacity, 1))}.group.destructive .group-\[\.destructive\]\:focus\:ring-red-400:focus{--tw-ring-opacity: 1;--tw-ring-color: rgb(248 113 113 / var(--tw-ring-opacity, 1))}.group.destructive .group-\[\.destructive\]\:focus\:ring-offset-red-600:focus{--tw-ring-offset-color: #dc2626}.peer:disabled~.peer-disabled\:cursor-not-allowed{cursor:not-allowed}.peer:disabled~.peer-disabled\:opacity-70{opacity:.7}.aria-disabled\:opacity-50[aria-disabled=true]{opacity:.5}.aria-selected\:text-muted-foreground[aria-selected=true]{color:hsl(var(--muted-foreground))}.data-\[disabled\=true\]\:pointer-events-none[data-disabled=true],.data-\[disabled\]\:pointer-events-none[data-disabled]{pointer-events:none}.data-\[side\=bottom\]\:translate-y-1[data-side=bottom]{--tw-translate-y: .25rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.data-\[side\=left\]\:-translate-x-1[data-side=left]{--tw-translate-x: -.25rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.data-\[side\=right\]\:translate-x-1[data-side=right]{--tw-translate-x: .25rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.data-\[side\=top\]\:-translate-y-1[data-side=top]{--tw-translate-y: -.25rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.data-\[state\=checked\]\:translate-x-4[data-state=checked]{--tw-translate-x: 1rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.data-\[state\=unchecked\]\:translate-x-0[data-state=unchecked],.data-\[swipe\=cancel\]\:translate-x-0[data-swipe=cancel]{--tw-translate-x: 0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.data-\[swipe\=end\]\:translate-x-\[var\(--radix-toast-swipe-end-x\)\][data-swipe=end]{--tw-translate-x: var(--radix-toast-swipe-end-x);transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.data-\[swipe\=move\]\:translate-x-\[var\(--radix-toast-swipe-move-x\)\][data-swipe=move]{--tw-translate-x: var(--radix-toast-swipe-move-x);transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes fade-out{0%{opacity:1}to{opacity:0}}.data-\[state\=closed\]\:animate-fade-out[data-state=closed]{animation:fade-out .15s ease-in}.data-\[state\=closed\]\:animate-slide-out-to-right[data-state=closed]{animation:slide-out-to-right .2s ease-in}@keyframes fade-in{0%{opacity:0}to{opacity:1}}.data-\[state\=open\]\:animate-fade-in[data-state=open]{animation:fade-in .2s ease-out}@keyframes slide-in-from-right{0%{transform:translate(100%)}to{transform:translate(0)}}.data-\[state\=open\]\:animate-slide-in-from-right[data-state=open]{animation:slide-in-from-right .3s ease-out}@keyframes slide-out-to-right{0%{transform:translate(0)}to{transform:translate(100%)}}.data-\[swipe\=end\]\:animate-slide-out-to-right[data-swipe=end]{animation:slide-out-to-right .2s ease-in}.data-\[range-end\=true\]\:rounded-md[data-range-end=true]{border-radius:calc(var(--radius) - 2px)}.data-\[range-middle\=true\]\:rounded-none[data-range-middle=true]{border-radius:0}.data-\[range-start\=true\]\:rounded-md[data-range-start=true]{border-radius:calc(var(--radius) - 2px)}.data-\[selected\=true\]\:rounded-none[data-selected=true]{border-radius:0}.data-\[range-end\=true\]\:bg-primary[data-range-end=true]{background-color:hsl(var(--primary))}.data-\[range-middle\=true\]\:bg-accent[data-range-middle=true]{background-color:hsl(var(--accent))}.data-\[range-start\=true\]\:bg-primary[data-range-start=true],.data-\[selected-single\=true\]\:bg-primary[data-selected-single=true]{background-color:hsl(var(--primary))}.data-\[selected\=true\]\:bg-accent[data-selected=true]{background-color:hsl(var(--accent))}.data-\[state\=active\]\:bg-background[data-state=active]{background-color:hsl(var(--background))}.data-\[state\=checked\]\:bg-primary[data-state=checked]{background-color:hsl(var(--primary))}.data-\[state\=open\]\:bg-accent[data-state=open]{background-color:hsl(var(--accent))}.data-\[state\=selected\]\:bg-muted[data-state=selected]{background-color:hsl(var(--muted))}.data-\[state\=unchecked\]\:bg-input[data-state=unchecked]{background-color:hsl(var(--input))}.data-\[placeholder\]\:text-muted-foreground[data-placeholder]{color:hsl(var(--muted-foreground))}.data-\[range-end\=true\]\:text-primary-foreground[data-range-end=true]{color:hsl(var(--primary-foreground))}.data-\[range-middle\=true\]\:text-accent-foreground[data-range-middle=true]{color:hsl(var(--accent-foreground))}.data-\[range-start\=true\]\:text-primary-foreground[data-range-start=true],.data-\[selected-single\=true\]\:text-primary-foreground[data-selected-single=true]{color:hsl(var(--primary-foreground))}.data-\[selected\=true\]\:text-accent-foreground[data-selected=true]{color:hsl(var(--accent-foreground))}.data-\[state\=active\]\:text-foreground[data-state=active]{color:hsl(var(--foreground))}.data-\[state\=checked\]\:text-primary-foreground[data-state=checked]{color:hsl(var(--primary-foreground))}.data-\[state\=open\]\:text-accent-foreground[data-state=open]{color:hsl(var(--accent-foreground))}.data-\[state\=open\]\:text-muted-foreground[data-state=open]{color:hsl(var(--muted-foreground))}.data-\[disabled\=true\]\:opacity-50[data-disabled=true],.data-\[disabled\]\:opacity-50[data-disabled]{opacity:.5}.data-\[state\=active\]\:shadow[data-state=active]{--tw-shadow: 0 1px 3px 0 rgb(0 0 0 / .1), 0 1px 2px -1px rgb(0 0 0 / .1);--tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.data-\[state\=active\]\:shadow-sm[data-state=active]{--tw-shadow: 0 1px 2px 0 rgb(0 0 0 / .05);--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.data-\[swipe\=move\]\:transition-none[data-swipe=move]{transition-property:none}.data-\[state\=active\]\:duration-300[data-state=active]{transition-duration:.3s}.group\/day[data-focused=true] .group-data-\[focused\=true\]\/day\:relative{position:relative}.group\/day[data-focused=true] .group-data-\[focused\=true\]\/day\:z-10{z-index:10}.group\/day[data-focused=true] .group-data-\[focused\=true\]\/day\:border-ring{border-color:hsl(var(--ring))}.group\/day[data-focused=true] .group-data-\[focused\=true\]\/day\:ring-\[3px\]{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.group\/day[data-focused=true] .group-data-\[focused\=true\]\/day\:ring-ring\/50{--tw-ring-color: hsl(var(--ring) / .5)}@supports (backdrop-filter: var(--tw)){.supports-\[backdrop-filter\]\:bg-background\/60{background-color:hsl(var(--background) / .6)}}.dark\:border-amber-800:is(.dark *){--tw-border-opacity: 1;border-color:rgb(146 64 14 / var(--tw-border-opacity, 1))}.dark\:border-blue-800:is(.dark *){--tw-border-opacity: 1;border-color:rgb(30 64 175 / var(--tw-border-opacity, 1))}.dark\:border-gray-900:is(.dark *){--tw-border-opacity: 1;border-color:rgb(17 24 39 / var(--tw-border-opacity, 1))}.dark\:border-green-800:is(.dark *){--tw-border-opacity: 1;border-color:rgb(22 101 52 / var(--tw-border-opacity, 1))}.dark\:border-orange-900:is(.dark *){--tw-border-opacity: 1;border-color:rgb(124 45 18 / var(--tw-border-opacity, 1))}.dark\:border-yellow-900:is(.dark *){--tw-border-opacity: 1;border-color:rgb(113 63 18 / var(--tw-border-opacity, 1))}.dark\:bg-amber-950\/30:is(.dark *){background-color:#451a034d}.dark\:bg-blue-500\/20:is(.dark *){background-color:#3b82f633}.dark\:bg-blue-900:is(.dark *){--tw-bg-opacity: 1;background-color:rgb(30 58 138 / var(--tw-bg-opacity, 1))}.dark\:bg-blue-900\/30:is(.dark *){background-color:#1e3a8a4d}.dark\:bg-blue-950:is(.dark *){--tw-bg-opacity: 1;background-color:rgb(23 37 84 / var(--tw-bg-opacity, 1))}.dark\:bg-blue-950\/20:is(.dark *){background-color:#17255433}.dark\:bg-blue-950\/30:is(.dark *){background-color:#1725544d}.dark\:bg-gray-800:is(.dark *){--tw-bg-opacity: 1;background-color:rgb(31 41 55 / var(--tw-bg-opacity, 1))}.dark\:bg-gray-800\/30:is(.dark *){background-color:#1f29374d}.dark\:bg-gray-800\/50:is(.dark *){background-color:#1f293780}.dark\:bg-gray-900:is(.dark *){--tw-bg-opacity: 1;background-color:rgb(17 24 39 / var(--tw-bg-opacity, 1))}.dark\:bg-gray-950:is(.dark *){--tw-bg-opacity: 1;background-color:rgb(3 7 18 / var(--tw-bg-opacity, 1))}.dark\:bg-green-900\/30:is(.dark *){background-color:#14532d4d}.dark\:bg-green-950:is(.dark *){--tw-bg-opacity: 1;background-color:rgb(5 46 22 / var(--tw-bg-opacity, 1))}.dark\:bg-green-950\/20:is(.dark *){background-color:#052e1633}.dark\:bg-orange-950\/20:is(.dark *){background-color:#43140733}.dark\:bg-purple-900\/30:is(.dark *){background-color:#581c874d}.dark\:bg-red-500\/20:is(.dark *){background-color:#ef444433}.dark\:bg-red-600\/30:is(.dark *){background-color:#dc26264d}.dark\:bg-red-900\/30:is(.dark *){background-color:#7f1d1d4d}.dark\:bg-red-950\/50:is(.dark *){background-color:#450a0a80}.dark\:bg-yellow-500\/20:is(.dark *){background-color:#eab30833}.dark\:bg-yellow-900:is(.dark *){--tw-bg-opacity: 1;background-color:rgb(113 63 18 / var(--tw-bg-opacity, 1))}.dark\:bg-yellow-950\/30:is(.dark *){background-color:#4220064d}.dark\:text-amber-100:is(.dark *){--tw-text-opacity: 1;color:rgb(254 243 199 / var(--tw-text-opacity, 1))}.dark\:text-amber-400:is(.dark *){--tw-text-opacity: 1;color:rgb(251 191 36 / var(--tw-text-opacity, 1))}.dark\:text-blue-100:is(.dark *){--tw-text-opacity: 1;color:rgb(219 234 254 / var(--tw-text-opacity, 1))}.dark\:text-blue-200:is(.dark *){--tw-text-opacity: 1;color:rgb(191 219 254 / var(--tw-text-opacity, 1))}.dark\:text-blue-300:is(.dark *){--tw-text-opacity: 1;color:rgb(147 197 253 / var(--tw-text-opacity, 1))}.dark\:text-blue-400:is(.dark *){--tw-text-opacity: 1;color:rgb(96 165 250 / var(--tw-text-opacity, 1))}.dark\:text-cyan-500:is(.dark *){--tw-text-opacity: 1;color:rgb(6 182 212 / var(--tw-text-opacity, 1))}.dark\:text-gray-100:is(.dark *){--tw-text-opacity: 1;color:rgb(243 244 246 / var(--tw-text-opacity, 1))}.dark\:text-gray-400:is(.dark *){--tw-text-opacity: 1;color:rgb(156 163 175 / var(--tw-text-opacity, 1))}.dark\:text-gray-600:is(.dark *){--tw-text-opacity: 1;color:rgb(75 85 99 / var(--tw-text-opacity, 1))}.dark\:text-green-400:is(.dark *){--tw-text-opacity: 1;color:rgb(74 222 128 / var(--tw-text-opacity, 1))}.dark\:text-orange-100:is(.dark *){--tw-text-opacity: 1;color:rgb(255 237 213 / var(--tw-text-opacity, 1))}.dark\:text-orange-200:is(.dark *){--tw-text-opacity: 1;color:rgb(254 215 170 / var(--tw-text-opacity, 1))}.dark\:text-purple-400:is(.dark *){--tw-text-opacity: 1;color:rgb(192 132 252 / var(--tw-text-opacity, 1))}.dark\:text-red-400:is(.dark *){--tw-text-opacity: 1;color:rgb(248 113 113 / var(--tw-text-opacity, 1))}.dark\:text-red-500:is(.dark *){--tw-text-opacity: 1;color:rgb(239 68 68 / var(--tw-text-opacity, 1))}.dark\:text-yellow-200:is(.dark *){--tw-text-opacity: 1;color:rgb(254 240 138 / var(--tw-text-opacity, 1))}.dark\:text-yellow-300:is(.dark *){--tw-text-opacity: 1;color:rgb(253 224 71 / var(--tw-text-opacity, 1))}.dark\:text-yellow-400:is(.dark *){--tw-text-opacity: 1;color:rgb(250 204 21 / var(--tw-text-opacity, 1))}.dark\:text-yellow-500:is(.dark *){--tw-text-opacity: 1;color:rgb(234 179 8 / var(--tw-text-opacity, 1))}.dark\:hover\:bg-gray-800:hover:is(.dark *){--tw-bg-opacity: 1;background-color:rgb(31 41 55 / var(--tw-bg-opacity, 1))}.dark\:focus\:bg-gray-800:focus:is(.dark *){--tw-bg-opacity: 1;background-color:rgb(31 41 55 / var(--tw-bg-opacity, 1))}@media(min-width:640px){.sm\:right-2{right:.5rem}.sm\:right-3{right:.75rem}.sm\:top-2{top:.5rem}.sm\:top-3{top:.75rem}.sm\:order-1{order:1}.sm\:order-2{order:2}.sm\:col-span-2{grid-column:span 2 / span 2}.sm\:mx-0{margin-left:0;margin-right:0}.sm\:mb-3{margin-bottom:.75rem}.sm\:mb-4{margin-bottom:1rem}.sm\:mb-6{margin-bottom:1.5rem}.sm\:ml-0{margin-left:0}.sm\:ml-1{margin-left:.25rem}.sm\:mr-1{margin-right:.25rem}.sm\:mr-2{margin-right:.5rem}.sm\:mt-0{margin-top:0}.sm\:mt-2{margin-top:.5rem}.sm\:mt-3{margin-top:.75rem}.sm\:mt-6{margin-top:1.5rem}.sm\:block{display:block}.sm\:inline{display:inline}.sm\:flex{display:flex}.sm\:grid{display:grid}.sm\:hidden{display:none}.sm\:h-10{height:2.5rem}.sm\:h-12{height:3rem}.sm\:h-2{height:.5rem}.sm\:h-24{height:6rem}.sm\:h-3{height:.75rem}.sm\:h-4{height:1rem}.sm\:h-5{height:1.25rem}.sm\:h-8{height:2rem}.sm\:h-9{height:2.25rem}.sm\:h-\[300px\]{height:300px}.sm\:h-\[400px\]{height:400px}.sm\:h-\[500px\]{height:500px}.sm\:h-\[calc\(100vh-280px\)\]{height:calc(100vh - 280px)}.sm\:w-10{width:2.5rem}.sm\:w-2{width:.5rem}.sm\:w-24{width:6rem}.sm\:w-28{width:7rem}.sm\:w-3{width:.75rem}.sm\:w-4{width:1rem}.sm\:w-5{width:1.25rem}.sm\:w-8{width:2rem}.sm\:w-80{width:20rem}.sm\:w-96{width:24rem}.sm\:w-\[140px\]{width:140px}.sm\:w-\[160px\]{width:160px}.sm\:w-\[200px\]{width:200px}.sm\:w-\[500px\]{width:500px}.sm\:w-auto{width:auto}.sm\:w-full{width:100%}.sm\:min-w-\[120px\]{min-width:120px}.sm\:max-w-2xl{max-width:42rem}.sm\:max-w-\[420px\]{max-width:420px}.sm\:max-w-\[500px\]{max-width:500px}.sm\:max-w-\[70\%\]{max-width:70%}.sm\:max-w-\[900px\]{max-width:900px}.sm\:max-w-md{max-width:28rem}.sm\:max-w-sm{max-width:24rem}.sm\:flex-1{flex:1 1 0%}.sm\:flex-none{flex:none}.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.sm\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.sm\:grid-cols-5{grid-template-columns:repeat(5,minmax(0,1fr))}.sm\:grid-cols-6{grid-template-columns:repeat(6,minmax(0,1fr))}.sm\:flex-row{flex-direction:row}.sm\:flex-wrap{flex-wrap:wrap}.sm\:items-start{align-items:flex-start}.sm\:items-center{align-items:center}.sm\:justify-end{justify-content:flex-end}.sm\:justify-between{justify-content:space-between}.sm\:gap-0{gap:0px}.sm\:gap-1{gap:.25rem}.sm\:gap-2{gap:.5rem}.sm\:gap-3{gap:.75rem}.sm\:gap-4{gap:1rem}.sm\:gap-6{gap:1.5rem}.sm\:space-x-2>:not([hidden])~:not([hidden]){--tw-space-x-reverse: 0;margin-right:calc(.5rem * var(--tw-space-x-reverse));margin-left:calc(.5rem * calc(1 - var(--tw-space-x-reverse)))}.sm\:space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.75rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem * var(--tw-space-y-reverse))}.sm\:space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem * var(--tw-space-y-reverse))}.sm\:space-y-5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1.25rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.25rem * var(--tw-space-y-reverse))}.sm\:space-y-6>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.5rem * var(--tw-space-y-reverse))}.sm\:space-y-8>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(2rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(2rem * var(--tw-space-y-reverse))}.sm\:rounded-lg{border-radius:var(--radius)}.sm\:p-3{padding:.75rem}.sm\:p-4{padding:1rem}.sm\:p-6{padding:1.5rem}.sm\:px-0{padding-left:0;padding-right:0}.sm\:px-3{padding-left:.75rem;padding-right:.75rem}.sm\:px-4{padding-left:1rem;padding-right:1rem}.sm\:py-2{padding-top:.5rem;padding-bottom:.5rem}.sm\:pb-4{padding-bottom:1rem}.sm\:text-left{text-align:left}.sm\:text-2xl{font-size:1.5rem;line-height:2rem}.sm\:text-3xl{font-size:1.875rem;line-height:2.25rem}.sm\:text-\[200px\]{font-size:200px}.sm\:text-base{font-size:1rem;line-height:1.5rem}.sm\:text-lg{font-size:1.125rem;line-height:1.75rem}.sm\:text-sm{font-size:.875rem;line-height:1.25rem}.sm\:text-xl{font-size:1.25rem;line-height:1.75rem}.sm\:text-xs{font-size:.75rem;line-height:1rem}}@media(min-width:768px){.md\:top-4{top:1rem}.md\:mb-4{margin-bottom:1rem}.md\:mb-6{margin-bottom:1.5rem}.md\:mb-8{margin-bottom:2rem}.md\:mt-8{margin-top:2rem}.md\:block{display:block}.md\:flex{display:flex}.md\:hidden{display:none}.md\:h-16{height:4rem}.md\:h-4{height:1rem}.md\:h-5{height:1.25rem}.md\:h-8{height:2rem}.md\:h-96{height:24rem}.md\:h-\[500px\]{height:500px}.md\:min-h-\[400px\]{min-height:400px}.md\:w-16{width:4rem}.md\:w-4{width:1rem}.md\:w-5{width:1.25rem}.md\:w-8{width:2rem}.md\:w-96{width:24rem}.md\:max-w-none{max-width:none}.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.md\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.md\:grid-cols-6{grid-template-columns:repeat(6,minmax(0,1fr))}.md\:flex-row{flex-direction:row}.md\:gap-2{gap:.5rem}.md\:gap-3{gap:.75rem}.md\:gap-4{gap:1rem}.md\:gap-6{gap:1.5rem}.md\:space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem * var(--tw-space-y-reverse))}.md\:space-y-6>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.5rem * var(--tw-space-y-reverse))}.md\:whitespace-normal{white-space:normal}.md\:p-12{padding:3rem}.md\:p-4{padding:1rem}.md\:p-6{padding:1.5rem}.md\:p-8{padding:2rem}.md\:text-2xl{font-size:1.5rem;line-height:2rem}.md\:text-3xl{font-size:1.875rem;line-height:2.25rem}.md\:text-base{font-size:1rem;line-height:1.5rem}.md\:text-lg{font-size:1.125rem;line-height:1.75rem}.md\:text-sm{font-size:.875rem;line-height:1.25rem}.md\:text-xs{font-size:.75rem;line-height:1rem}}@media(min-width:1024px){.lg\:invisible{visibility:hidden}.lg\:relative{position:relative}.lg\:z-0{z-index:0}.lg\:col-span-1{grid-column:span 1 / span 1}.lg\:mx-auto{margin-left:auto;margin-right:auto}.lg\:mb-1{margin-bottom:.25rem}.lg\:block{display:block}.lg\:flex{display:flex}.lg\:hidden{display:none}.lg\:w-12{width:3rem}.lg\:w-16{width:4rem}.lg\:w-64{width:16rem}.lg\:w-8{width:2rem}.lg\:w-\[130px\]{width:130px}.lg\:w-\[160px\]{width:160px}.lg\:w-\[180px\]{width:180px}.lg\:w-\[200px\]{width:200px}.lg\:w-\[240px\]{width:240px}.lg\:w-\[75px\]{width:75px}.lg\:w-auto{width:auto}.lg\:w-full{width:100%}.lg\:max-w-0{max-width:0px}.lg\:flex-1{flex:1 1 0%}.lg\:flex-none{flex:none}.lg\:translate-x-0{--tw-translate-x: 0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.lg\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.lg\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.lg\:grid-cols-6{grid-template-columns:repeat(6,minmax(0,1fr))}.lg\:grid-cols-7{grid-template-columns:repeat(7,minmax(0,1fr))}.lg\:grid-cols-8{grid-template-columns:repeat(8,minmax(0,1fr))}.lg\:grid-cols-9{grid-template-columns:repeat(9,minmax(0,1fr))}.lg\:justify-center{justify-content:center}.lg\:gap-0{gap:0px}.lg\:space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.75rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem * var(--tw-space-y-reverse))}.lg\:overflow-hidden{overflow:hidden}.lg\:p-2{padding:.5rem}.lg\:p-6{padding:1.5rem}.lg\:px-0{padding-left:0;padding-right:0}.lg\:px-6{padding-left:1.5rem;padding-right:1.5rem}.lg\:pb-6{padding-bottom:1.5rem}.lg\:text-3xl{font-size:1.875rem;line-height:2.25rem}.lg\:opacity-0{opacity:0}}@media(min-width:1280px){.xl\:grid-cols-10{grid-template-columns:repeat(10,minmax(0,1fr))}.xl\:grid-cols-5{grid-template-columns:repeat(5,minmax(0,1fr))}.xl\:grid-cols-8{grid-template-columns:repeat(8,minmax(0,1fr))}}.\[\&\+div\]\:text-xs+div{font-size:.75rem;line-height:1rem}.\[\&\:\:-webkit-scrollbar-thumb\:hover\]\:bg-border\/80::-webkit-scrollbar-thumb:hover{background-color:hsl(var(--border) / .8)}.\[\&\:\:-webkit-scrollbar-thumb\]\:rounded-full::-webkit-scrollbar-thumb{border-radius:9999px}.\[\&\:\:-webkit-scrollbar-thumb\]\:bg-border::-webkit-scrollbar-thumb{background-color:hsl(var(--border))}.\[\&\:\:-webkit-scrollbar-track\]\:bg-transparent::-webkit-scrollbar-track{background-color:transparent}.\[\&\:\:-webkit-scrollbar\]\:w-2\.5::-webkit-scrollbar{width:.625rem}.\[\&\:first-child\[data-selected\=true\]_button\]\:rounded-l-md:first-child[data-selected=true] button{border-top-left-radius:calc(var(--radius) - 2px);border-bottom-left-radius:calc(var(--radius) - 2px)}.\[\&\:has\(\[role\=checkbox\]\)\]\:pr-0:has([role=checkbox]){padding-right:0}.\[\&\:last-child\[data-selected\=true\]_button\]\:rounded-r-md:last-child[data-selected=true] button{border-top-right-radius:calc(var(--radius) - 2px);border-bottom-right-radius:calc(var(--radius) - 2px)}.\[\&\>\[role\=checkbox\]\]\:translate-y-\[2px\]>[role=checkbox]{--tw-translate-y: 2px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.\[\&\>span\]\:line-clamp-1>span{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:1}.\[\&\>span\]\:text-xs>span{font-size:.75rem;line-height:1rem}.\[\&\>span\]\:opacity-70>span{opacity:.7}.\[\&\>svg\+div\]\:translate-y-\[-3px\]>svg+div{--tw-translate-y: -3px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.\[\&\>svg\]\:absolute>svg{position:absolute}.\[\&\>svg\]\:left-4>svg{left:1rem}.\[\&\>svg\]\:top-4>svg{top:1rem}.\[\&\>svg\]\:size-3\.5>svg{width:.875rem;height:.875rem}.\[\&\>svg\]\:h-2\.5>svg{height:.625rem}.\[\&\>svg\]\:h-3>svg{height:.75rem}.\[\&\>svg\]\:w-2\.5>svg{width:.625rem}.\[\&\>svg\]\:w-3>svg{width:.75rem}.\[\&\>svg\]\:text-foreground>svg{color:hsl(var(--foreground))}.\[\&\>svg\]\:text-muted-foreground>svg{color:hsl(var(--muted-foreground))}.\[\&\>svg\~\*\]\:pl-7>svg~*{padding-left:1.75rem}.\[\&\>tr\]\:last\:border-b-0:last-child>tr{border-bottom-width:0px}.\[\&_\.recharts-cartesian-axis-tick_text\]\:fill-muted-foreground .recharts-cartesian-axis-tick text{fill:hsl(var(--muted-foreground))}.\[\&_\.recharts-cartesian-grid_line\[stroke\=\'\#ccc\'\]\]\:stroke-border\/50 .recharts-cartesian-grid line[stroke="#ccc"]{stroke:hsl(var(--border) / .5)}.\[\&_\.recharts-curve\.recharts-tooltip-cursor\]\:stroke-border .recharts-curve.recharts-tooltip-cursor{stroke:hsl(var(--border))}.\[\&_\.recharts-dot\[stroke\=\'\#fff\'\]\]\:stroke-transparent .recharts-dot[stroke="#fff"]{stroke:transparent}.\[\&_\.recharts-layer\]\:outline-none .recharts-layer{outline:2px solid transparent;outline-offset:2px}.\[\&_\.recharts-polar-grid_\[stroke\=\'\#ccc\'\]\]\:stroke-border .recharts-polar-grid [stroke="#ccc"]{stroke:hsl(var(--border))}.\[\&_\.recharts-radial-bar-background-sector\]\:fill-muted .recharts-radial-bar-background-sector,.\[\&_\.recharts-rectangle\.recharts-tooltip-cursor\]\:fill-muted .recharts-rectangle.recharts-tooltip-cursor{fill:hsl(var(--muted))}.\[\&_\.recharts-reference-line_\[stroke\=\'\#ccc\'\]\]\:stroke-border .recharts-reference-line [stroke="#ccc"]{stroke:hsl(var(--border))}.\[\&_\.recharts-sector\[stroke\=\'\#fff\'\]\]\:stroke-transparent .recharts-sector[stroke="#fff"]{stroke:transparent}.\[\&_\.recharts-sector\]\:outline-none .recharts-sector,.\[\&_\.recharts-surface\]\:outline-none .recharts-surface{outline:2px solid transparent;outline-offset:2px}.\[\&_\[cmdk-group-heading\]\]\:px-2 [cmdk-group-heading]{padding-left:.5rem;padding-right:.5rem}.\[\&_\[cmdk-group-heading\]\]\:py-1\.5 [cmdk-group-heading]{padding-top:.375rem;padding-bottom:.375rem}.\[\&_\[cmdk-group-heading\]\]\:text-xs [cmdk-group-heading]{font-size:.75rem;line-height:1rem}.\[\&_\[cmdk-group-heading\]\]\:font-medium [cmdk-group-heading]{font-weight:500}.\[\&_\[cmdk-group-heading\]\]\:text-muted-foreground [cmdk-group-heading]{color:hsl(var(--muted-foreground))}.\[\&_\[cmdk-group\]\:not\(\[hidden\]\)_\~\[cmdk-group\]\]\:pt-0 [cmdk-group]:not([hidden])~[cmdk-group]{padding-top:0}.\[\&_\[cmdk-group\]\]\:px-2 [cmdk-group]{padding-left:.5rem;padding-right:.5rem}.\[\&_\[cmdk-input-wrapper\]_svg\]\:h-5 [cmdk-input-wrapper] svg{height:1.25rem}.\[\&_\[cmdk-input-wrapper\]_svg\]\:w-5 [cmdk-input-wrapper] svg{width:1.25rem}.\[\&_\[cmdk-input\]\]\:h-12 [cmdk-input]{height:3rem}.\[\&_\[cmdk-item\]\]\:px-2 [cmdk-item]{padding-left:.5rem;padding-right:.5rem}.\[\&_\[cmdk-item\]\]\:py-3 [cmdk-item]{padding-top:.75rem;padding-bottom:.75rem}.\[\&_\[cmdk-item\]_svg\]\:h-5 [cmdk-item] svg{height:1.25rem}.\[\&_\[cmdk-item\]_svg\]\:w-5 [cmdk-item] svg{width:1.25rem}.\[\&_p\]\:leading-relaxed p{line-height:1.625}.\[\&_svg\]\:pointer-events-none svg{pointer-events:none}.\[\&_svg\]\:invisible svg{visibility:hidden}.\[\&_svg\]\:size-4 svg{width:1rem;height:1rem}.\[\&_svg\]\:shrink-0 svg{flex-shrink:0}.\[\&_tr\:last-child\]\:border-0 tr:last-child{border-width:0px}.\[\&_tr\]\:border-b tr{border-bottom-width:1px}[data-slot=card-content] .\[\[data-slot\=card-content\]_\&\]\:bg-transparent,[data-slot=popover-content] .\[\[data-slot\=popover-content\]_\&\]\:bg-transparent{background-color:transparent}.uppy-Root{box-sizing:border-box;color:#333;font-family:-apple-system,system-ui,BlinkMacSystemFont,Segoe UI,Segoe UI Symbol,Segoe UI Emoji,Apple Color Emoji,Roboto,Helvetica,Arial,sans-serif;line-height:1;position:relative;text-align:left;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.uppy-Root[dir=rtl],[dir=rtl] .uppy-Root{text-align:right}.uppy-Root *,.uppy-Root :after,.uppy-Root :before{box-sizing:inherit}.uppy-Root [hidden]{display:none}.uppy-u-reset{all:initial;-webkit-appearance:none;-moz-appearance:none;appearance:none;box-sizing:border-box;font-family:-apple-system,system-ui,BlinkMacSystemFont,Segoe UI,Segoe UI Symbol,Segoe UI Emoji,Apple Color Emoji,Roboto,Helvetica,Arial,sans-serif;line-height:1}[dir=rtl] .uppy-u-reset{text-align:right}.uppy-truncate-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.uppy-c-textInput{background-color:#fff;border:1px solid #ddd;border-radius:4px;font-family:inherit;font-size:14px;line-height:1.5;padding:6px 8px}.uppy-size--md .uppy-c-textInput{padding:8px 10px}.uppy-c-textInput:focus{border-color:#1269cf99;box-shadow:0 0 0 3px #1269cf26;outline:none}[data-uppy-theme=dark] .uppy-c-textInput{background-color:#333;border-color:#333;color:#eaeaea}[data-uppy-theme=dark] .uppy-c-textInput:focus{border-color:#525252;box-shadow:none}.uppy-c-icon{display:inline-block;max-height:100%;max-width:100%;overflow:hidden;fill:currentColor}.uppy-c-btn{align-items:center;color:inherit;display:inline-flex;font-family:inherit;font-size:inherit;font-weight:500;justify-content:center;line-height:1;transition-duration:.3s;transition-property:background-color,color;-webkit-user-select:none;-moz-user-select:none;user-select:none;white-space:nowrap}.uppy-c-btn,[dir=rtl] .uppy-c-btn{text-align:center}.uppy-c-btn:not(:disabled):not(.disabled){cursor:pointer}.uppy-c-btn::-moz-focus-inner{border:0}.uppy-c-btn-primary{background-color:#1269cf;border-radius:4px;color:#fff;font-size:14px;padding:10px 18px}.uppy-c-btn-primary:not(:disabled):hover{background-color:#0e51a0}.uppy-c-btn-primary:focus{box-shadow:0 0 0 3px #1269cf66;outline:none}.uppy-size--md .uppy-c-btn-primary{padding:13px 22px}[data-uppy-theme=dark] .uppy-c-btn-primary{color:#eaeaea}[data-uppy-theme=dark] .uppy-c-btn-primary:focus{outline:none}[data-uppy-theme=dark] .uppy-c-btn-primary::-moz-focus-inner{border:0}[data-uppy-theme=dark] .uppy-c-btn-primary:focus{box-shadow:0 0 0 2px #aae1ffd9}.uppy-c-btn-primary.uppy-c-btn--disabled{background-color:#8eb2db}.uppy-c-btn-link{background-color:initial;border-radius:4px;color:#525252;font-size:14px;line-height:1;padding:10px 15px}.uppy-c-btn-link:hover{color:#333}.uppy-c-btn-link:focus{box-shadow:0 0 0 3px #1269cf40;outline:none}.uppy-size--md .uppy-c-btn-link{padding:13px 18px}[data-uppy-theme=dark] .uppy-c-btn-link{color:#eaeaea}[data-uppy-theme=dark] .uppy-c-btn-link:focus{outline:none}[data-uppy-theme=dark] .uppy-c-btn-link::-moz-focus-inner{border:0}[data-uppy-theme=dark] .uppy-c-btn-link:focus{box-shadow:0 0 0 2px #aae1ffd9}[data-uppy-theme=dark] .uppy-c-btn-link:hover{color:#939393}.uppy-ProviderBrowser-viewType--grid ul.uppy-ProviderBrowser-list,.uppy-ProviderBrowser-viewType--unsplash ul.uppy-ProviderBrowser-list{align-items:flex-start;display:flex;flex-direction:row;flex-wrap:wrap;justify-content:space-between;padding:6px}.uppy-ProviderBrowser-viewType--grid ul.uppy-ProviderBrowser-list:after,.uppy-ProviderBrowser-viewType--unsplash ul.uppy-ProviderBrowser-list:after{content:"";flex:auto}.uppy-ProviderBrowser-viewType--grid li.uppy-ProviderBrowserItem,.uppy-ProviderBrowser-viewType--unsplash li.uppy-ProviderBrowserItem{margin:0;position:relative;width:50%}.uppy-size--md .uppy-ProviderBrowser-viewType--grid li.uppy-ProviderBrowserItem,.uppy-size--md .uppy-ProviderBrowser-viewType--unsplash li.uppy-ProviderBrowserItem{width:33.3333%}.uppy-size--lg .uppy-ProviderBrowser-viewType--grid li.uppy-ProviderBrowserItem,.uppy-size--lg .uppy-ProviderBrowser-viewType--unsplash li.uppy-ProviderBrowserItem{width:25%}.uppy-ProviderBrowser-viewType--grid li.uppy-ProviderBrowserItem:before,.uppy-ProviderBrowser-viewType--unsplash li.uppy-ProviderBrowserItem:before{content:"";display:block;padding-top:100%}.uppy-ProviderBrowser-viewType--grid li.uppy-ProviderBrowserItem--selected img,.uppy-ProviderBrowser-viewType--grid li.uppy-ProviderBrowserItem--selected svg,.uppy-ProviderBrowser-viewType--unsplash li.uppy-ProviderBrowserItem--selected img,.uppy-ProviderBrowser-viewType--unsplash li.uppy-ProviderBrowserItem--selected svg{opacity:.85}.uppy-ProviderBrowser-viewType--grid li.uppy-ProviderBrowserItem--disabled,.uppy-ProviderBrowser-viewType--unsplash li.uppy-ProviderBrowserItem--disabled{opacity:.5}.uppy-ProviderBrowser-viewType--grid li.uppy-ProviderBrowserItem--noPreview .uppy-ProviderBrowserItem-inner,.uppy-ProviderBrowser-viewType--unsplash li.uppy-ProviderBrowserItem--noPreview .uppy-ProviderBrowserItem-inner{background-color:#93939333}[data-uppy-theme=dark] .uppy-ProviderBrowser-viewType--grid li.uppy-ProviderBrowserItem--noPreview .uppy-ProviderBrowserItem-inner,[data-uppy-theme=dark] .uppy-ProviderBrowser-viewType--unsplash li.uppy-ProviderBrowserItem--noPreview .uppy-ProviderBrowserItem-inner{background-color:#eaeaea33}.uppy-ProviderBrowser-viewType--grid li.uppy-ProviderBrowserItem--noPreview svg,.uppy-ProviderBrowser-viewType--unsplash li.uppy-ProviderBrowserItem--noPreview svg{height:30%;width:30%;fill:#000000b3}[data-uppy-theme=dark] .uppy-ProviderBrowser-viewType--grid li.uppy-ProviderBrowserItem--noPreview svg,[data-uppy-theme=dark] .uppy-ProviderBrowser-viewType--unsplash li.uppy-ProviderBrowserItem--noPreview svg{fill:#fffc}.uppy-ProviderBrowser-viewType--grid .uppy-ProviderBrowserItem-inner,.uppy-ProviderBrowser-viewType--unsplash .uppy-ProviderBrowserItem-inner{border-radius:4px;height:calc(100% - 14px);inset:7px;overflow:hidden;position:absolute;text-align:center;width:calc(100% - 14px)}@media(hover:none){.uppy-ProviderBrowser-viewType--grid .uppy-ProviderBrowserItem-inner .uppy-ProviderBrowserItem-author,.uppy-ProviderBrowser-viewType--unsplash .uppy-ProviderBrowserItem-inner .uppy-ProviderBrowserItem-author{display:block}}[data-uppy-theme=dark] .uppy-ProviderBrowser-viewType--grid .uppy-ProviderBrowserItem-inner,[data-uppy-theme=dark] .uppy-ProviderBrowser-viewType--unsplash .uppy-ProviderBrowserItem-inner{box-shadow:0 0 0 3px #aae1ffb3}.uppy-ProviderBrowser-viewType--grid .uppy-ProviderBrowserItem-inner img,.uppy-ProviderBrowser-viewType--unsplash .uppy-ProviderBrowserItem-inner img{border-radius:4px;height:100%;-o-object-fit:cover;object-fit:cover;width:100%}.uppy-ProviderBrowser-viewType--grid .uppy-ProviderBrowserItem-author,.uppy-ProviderBrowser-viewType--unsplash .uppy-ProviderBrowserItem-author{background:#0000004d;bottom:0;color:#fff;display:none;font-size:12px;font-weight:500;left:0;margin:0;padding:5px;position:absolute;text-decoration:none;width:100%}.uppy-ProviderBrowser-viewType--grid .uppy-ProviderBrowserItem-author:hover,.uppy-ProviderBrowser-viewType--unsplash .uppy-ProviderBrowserItem-author:hover{background:#0006;text-decoration:underline}.uppy-ProviderBrowser-viewType--grid .uppy-ProviderBrowserItem-checkbox,.uppy-ProviderBrowser-viewType--unsplash .uppy-ProviderBrowserItem-checkbox{background-color:#1269cf;border-radius:50%;height:26px;opacity:0;position:absolute;right:16px;top:16px;width:26px;z-index:1002}.uppy-ProviderBrowser-viewType--grid .uppy-ProviderBrowserItem-checkbox:after,.uppy-ProviderBrowser-viewType--unsplash .uppy-ProviderBrowserItem-checkbox:after{height:7px;inset-inline-start:7px;top:8px;width:12px}.uppy-ProviderBrowser-viewType--grid .uppy-ProviderBrowserItem--is-checked .uppy-ProviderBrowserItem-checkbox,.uppy-ProviderBrowser-viewType--unsplash .uppy-ProviderBrowserItem--is-checked .uppy-ProviderBrowserItem-checkbox{opacity:1}.uppy-ProviderBrowser-viewType--grid .uppy-ProviderBrowserItem-checkbox--grid:focus+label .uppy-ProviderBrowserItem-author,.uppy-ProviderBrowser-viewType--grid .uppy-ProviderBrowserItem-checkbox--grid:hover+label .uppy-ProviderBrowserItem-author,.uppy-ProviderBrowser-viewType--unsplash .uppy-ProviderBrowserItem-checkbox--grid:focus+label .uppy-ProviderBrowserItem-author,.uppy-ProviderBrowser-viewType--unsplash .uppy-ProviderBrowserItem-checkbox--grid:hover+label .uppy-ProviderBrowserItem-author{display:block}.uppy-ProviderBrowser-viewType--grid .uppy-ProviderBrowserItem-checkbox--grid:focus+label,.uppy-ProviderBrowser-viewType--unsplash .uppy-ProviderBrowserItem-checkbox--grid:focus+label{box-shadow:0 0 0 3px #1269cf80}.uppy-ProviderBrowser-viewType--grid .uppy-ProviderBrowserItem-checkbox--grid:focus+label:focus,.uppy-ProviderBrowser-viewType--unsplash .uppy-ProviderBrowserItem-checkbox--grid:focus+label:focus{outline:none}.uppy-ProviderBrowser-viewType--grid .uppy-ProviderBrowserItem-checkbox--grid:focus+label::-moz-focus-inner,.uppy-ProviderBrowser-viewType--unsplash .uppy-ProviderBrowserItem-checkbox--grid:focus+label::-moz-focus-inner{border:0}.uppy-ProviderBrowser-viewType--list{background-color:#fff}[data-uppy-theme=dark] .uppy-ProviderBrowser-viewType--list{background-color:#1f1f1f}.uppy-ProviderBrowser-viewType--list li.uppy-ProviderBrowserItem{align-items:center;display:flex;margin:0;padding:7px 15px}[data-uppy-theme=dark] .uppy-ProviderBrowser-viewType--list li.uppy-ProviderBrowserItem{color:#eaeaea}.uppy-ProviderBrowser-viewType--list li.uppy-ProviderBrowserItem--disabled{opacity:.6}.uppy-ProviderBrowser-viewType--list .uppy-ProviderBrowserItem-checkbox{background-color:#fff;border:1px solid #cfcfcf;border-radius:3px;height:17px;margin-inline-end:15px;width:17px}.uppy-ProviderBrowser-viewType--list .uppy-ProviderBrowserItem-checkbox:focus{border:1px solid #1269cf;box-shadow:0 0 0 3px #1269cf40;outline:none}.uppy-ProviderBrowser-viewType--list .uppy-ProviderBrowserItem-checkbox:after{height:5px;inset-inline-start:3px;opacity:0;top:4px;width:9px}[data-uppy-theme=dark] .uppy-ProviderBrowser-viewType--list .uppy-ProviderBrowserItem-checkbox:focus{border-color:#02baf2b3;box-shadow:0 0 0 3px #02baf233}.uppy-ProviderBrowser-viewType--list .uppy-ProviderBrowserItem--is-checked .uppy-ProviderBrowserItem-checkbox,.uppy-ProviderBrowser-viewType--list .uppy-ProviderBrowserItem--is-partial .uppy-ProviderBrowserItem-checkbox{background-color:#1269cf;border-color:#1269cf}.uppy-ProviderBrowser-viewType--list .uppy-ProviderBrowserItem--is-checked .uppy-ProviderBrowserItem-checkbox:after,.uppy-ProviderBrowser-viewType--list .uppy-ProviderBrowserItem--is-partial .uppy-ProviderBrowserItem-checkbox:after{opacity:1}.uppy-ProviderBrowser-viewType--list .uppy-ProviderBrowserItem-inner{align-items:center;color:inherit;display:flex;font-family:-apple-system,system-ui,BlinkMacSystemFont,Segoe UI,Segoe UI Symbol,Segoe UI Emoji,Apple Color Emoji,Roboto,Helvetica,Arial,sans-serif;overflow:hidden;padding:2px;text-overflow:ellipsis;white-space:nowrap}.uppy-ProviderBrowser-viewType--list .uppy-ProviderBrowserItem-inner:focus{outline:none;text-decoration:underline}.uppy-ProviderBrowser-viewType--list .uppy-ProviderBrowserItem-inner img,.uppy-ProviderBrowser-viewType--list .uppy-ProviderBrowserItem-inner svg{margin-inline-end:8px}.uppy-ProviderBrowser-viewType--list .uppy-ProviderBrowserItem-inner span{line-height:1.2;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.uppy-ProviderBrowser-viewType--list .uppy-ProviderBrowserItem--disabled .uppy-ProviderBrowserItem-inner{cursor:default}.uppy-ProviderBrowser-viewType--list .uppy-ProviderBrowserItem-iconWrap{margin-inline-end:7px;width:20px}.uppy-ProviderBrowserItem-checkbox{cursor:pointer;flex-shrink:0;position:relative}.uppy-ProviderBrowserItem-checkbox:disabled,.uppy-ProviderBrowserItem-checkbox:disabled:after{cursor:default}[data-uppy-theme=dark] .uppy-ProviderBrowserItem-checkbox{background-color:#1f1f1f;border-color:#939393}[data-uppy-theme=dark] .uppy-ProviderBrowserItem--is-checked .uppy-ProviderBrowserItem-checkbox{background-color:#333}.uppy-ProviderBrowserItem--is-checked .uppy-ProviderBrowserItem-checkbox:after{border-bottom:2px solid #eaeaea;border-left:2px solid #eaeaea;content:"";cursor:pointer;position:absolute;transform:rotate(-45deg)}.uppy-ProviderBrowserItem--is-partial .uppy-ProviderBrowserItem-checkbox:after{background-color:#eaeaea!important;content:""!important;height:2px!important;left:20%!important;position:absolute!important;right:20%!important;top:50%!important;transform:translateY(-50%)!important}.uppy-SearchProvider{align-items:center;display:flex;flex:1;flex-direction:column;height:100%;justify-content:center;width:100%}[data-uppy-theme=dark] .uppy-SearchProvider{background-color:#1f1f1f}.uppy-SearchProvider-input{margin-bottom:15px;max-width:650px;width:90%}.uppy-size--md .uppy-SearchProvider-input{margin-bottom:20px}.uppy-SearchProvider-input::-webkit-search-cancel-button{display:none}.uppy-SearchProvider-searchButton{padding:13px 25px}.uppy-size--md .uppy-SearchProvider-searchButton{padding:13px 30px}.uppy-DashboardContent-panelBody{align-items:center;display:flex;flex:1;justify-content:center}[data-uppy-theme=dark] .uppy-DashboardContent-panelBody{background-color:#1f1f1f}.uppy-Provider-auth,.uppy-Provider-empty,.uppy-Provider-error,.uppy-Provider-loading{align-items:center;color:#939393;display:flex;flex:1;flex-flow:column wrap;justify-content:center}.uppy-Provider-empty{color:#939393}.uppy-Provider-authIcon svg{height:75px;width:100px}.uppy-Provider-authTitle{color:#757575;font-size:17px;font-weight:400;line-height:1.4;margin-bottom:30px;max-width:500px;padding:0 15px;text-align:center}.uppy-size--md .uppy-Provider-authTitle{font-size:20px}[data-uppy-theme=dark] .uppy-Provider-authTitle{color:#cfcfcf}.uppy-Provider-btn-google{align-items:center;background:#4285f4;display:flex;padding:8px 12px!important}.uppy-Provider-btn-google:hover{background-color:#1266f1}.uppy-Provider-btn-google:focus{box-shadow:0 0 0 3px #4285f466;outline:none}.uppy-Provider-btn-google svg{margin-right:8px}.uppy-Provider-breadcrumbs{color:#525252;flex:1;font-size:12px;margin-bottom:10px;text-align:start}.uppy-size--md .uppy-Provider-breadcrumbs{margin-bottom:0}[data-uppy-theme=dark] .uppy-Provider-breadcrumbs{color:#eaeaea}.uppy-Provider-breadcrumbsIcon{color:#525252;display:inline-block;line-height:1;margin-inline-end:4px;vertical-align:middle}.uppy-Provider-breadcrumbsIcon svg{height:13px;width:13px;fill:#525252}.uppy-Provider-breadcrumbs button{border-radius:3px;display:inline-block;line-height:inherit;padding:4px}.uppy-Provider-breadcrumbs button:focus{outline:none}.uppy-Provider-breadcrumbs button::-moz-focus-inner{border:0}.uppy-Provider-breadcrumbs button:hover{color:#0e51a0}.uppy-Provider-breadcrumbs button:focus{background-color:#dfe6f1}[data-uppy-theme=dark] .uppy-Provider-breadcrumbs button:focus{background-color:#333}.uppy-Provider-breadcrumbs button:not(:last-of-type){text-decoration:underline}.uppy-Provider-breadcrumbs button:last-of-type{color:#333;cursor:normal;font-weight:500;pointer-events:none}.uppy-Provider-breadcrumbs button:hover{cursor:pointer}[data-uppy-theme=dark] .uppy-Provider-breadcrumbs button{color:#eaeaea}.uppy-ProviderBrowser{display:flex;flex:1;flex-direction:column;font-size:14px;font-weight:400;height:100%}.uppy-ProviderBrowser-user{color:#333;font-weight:500;margin:0 8px 0 0}[data-uppy-theme=dark] .uppy-ProviderBrowser-user{color:#eaeaea}.uppy-ProviderBrowser-user:after{color:#939393;content:"·";font-weight:400;inset-inline-start:4px;position:relative}.uppy-ProviderBrowser-header{border-bottom:1px solid #eaeaea;position:relative;z-index:1001}[data-uppy-theme=dark] .uppy-ProviderBrowser-header{border-bottom:1px solid #333}.uppy-ProviderBrowser-headerBar{background-color:#fafafa;color:#757575;font-size:12px;line-height:1.4;padding:7px 15px;z-index:1001}.uppy-size--md .uppy-ProviderBrowser-headerBar{align-items:center;display:flex}[data-uppy-theme=dark] .uppy-ProviderBrowser-headerBar{background-color:#1f1f1f}.uppy-ProviderBrowser-headerBar--simple{display:block;justify-content:center;text-align:center}.uppy-ProviderBrowser-headerBar--simple .uppy-Provider-breadcrumbsWrap{display:inline-block;flex:none;vertical-align:middle}.uppy-ProviderBrowser-searchFilter{align-items:center;display:flex;height:30px;margin-bottom:15px;margin-top:15px;padding-left:8px;padding-right:8px;position:relative;width:100%}.uppy-ProviderBrowser-searchFilterInput{background-color:#eaeaea;border:0;border-radius:4px;color:#333;font-family:-apple-system,system-ui,BlinkMacSystemFont,Segoe UI,Segoe UI Symbol,Segoe UI Emoji,Apple Color Emoji,Roboto,Helvetica,Arial,sans-serif;font-size:13px;height:30px;line-height:1.4;outline:0;padding-inline-end:30px;padding-inline-start:30px;width:100%;z-index:1001}.uppy-ProviderBrowser-searchFilterInput::-webkit-search-cancel-button{display:none}[data-uppy-theme=dark] .uppy-ProviderBrowser-searchFilterInput{background-color:#1f1f1f;color:#eaeaea}.uppy-ProviderBrowser-searchFilterInput:focus{background-color:#cfcfcf;border:0}[data-uppy-theme=dark] .uppy-ProviderBrowser-searchFilterInput:focus{background-color:#333}.uppy-ProviderBrowser-searchFilterIcon{color:#757575;height:12px;inset-inline-start:16px;position:absolute;width:12px;z-index:1002}.uppy-ProviderBrowser-searchFilterInput::-moz-placeholder{color:#939393;opacity:1}.uppy-ProviderBrowser-searchFilterInput::placeholder{color:#939393;opacity:1}.uppy-ProviderBrowser-searchFilterReset{border-radius:3px;color:#939393;cursor:pointer;height:22px;inset-inline-end:16px;padding:6px;position:absolute;width:22px;z-index:1002}.uppy-ProviderBrowser-searchFilterReset:focus{outline:none}.uppy-ProviderBrowser-searchFilterReset::-moz-focus-inner{border:0}.uppy-ProviderBrowser-searchFilterReset:focus{box-shadow:0 0 0 3px #1269cf80}.uppy-ProviderBrowser-searchFilterReset:hover{color:#757575}.uppy-ProviderBrowser-searchFilterReset svg{vertical-align:text-top}.uppy-ProviderBrowser-userLogout{border-radius:3px;color:#1269cf;cursor:pointer;line-height:inherit;padding:4px}.uppy-ProviderBrowser-userLogout:focus{outline:none}.uppy-ProviderBrowser-userLogout::-moz-focus-inner{border:0}.uppy-ProviderBrowser-userLogout:hover{color:#0e51a0}.uppy-ProviderBrowser-userLogout:focus{background-color:#dfe6f1}[data-uppy-theme=dark] .uppy-ProviderBrowser-userLogout:focus{background-color:#333}.uppy-ProviderBrowser-userLogout:hover{text-decoration:underline}[data-uppy-theme=dark] .uppy-ProviderBrowser-userLogout{color:#eaeaea}.uppy-ProviderBrowser-body{flex:1;position:relative}.uppy-ProviderBrowser-list{background-color:#fff;border-spacing:0;display:block;flex:1;height:100%;inset:0;list-style:none;margin:0;overflow-x:hidden;overflow-y:auto;padding:0;position:absolute;width:100%;-webkit-overflow-scrolling:touch}[data-uppy-theme=dark] .uppy-ProviderBrowser-list{background-color:#1f1f1f}.uppy-ProviderBrowser-list:focus{outline:none}.uppy-ProviderBrowserItem-inner{cursor:pointer;font-size:13px;font-weight:500}.uppy-ProviderBrowser-footer{align-items:center;background-color:#fff;border-top:1px solid #eaeaea;display:flex;justify-content:space-between;padding:15px}.uppy-ProviderBrowser-footer button{margin-inline-end:8px}[data-uppy-theme=dark] .uppy-ProviderBrowser-footer{background-color:#1f1f1f;border-top:1px solid #333}.uppy-ProviderBrowser-footer-buttons{flex-shrink:0}.uppy-ProviderBrowser-footer-error{color:#e32437;line-height:18px}@media(max-width:426px){.uppy-ProviderBrowser-footer{align-items:stretch;flex-direction:column-reverse}.uppy-ProviderBrowser-footer-error{padding-bottom:10px}}.picker-dialog-bg{z-index:20000!important}.picker-dialog{z-index:20001!important}.uppy-Dashboard-Item-previewInnerWrap{align-items:center;border-radius:3px;box-shadow:0 0 2px #0006;display:flex;flex-direction:column;height:100%;justify-content:center;overflow:hidden;position:relative;width:100%}.uppy-size--md .uppy-Dashboard-Item-previewInnerWrap{box-shadow:0 1px 2px #00000026}.uppy-Dashboard--singleFile .uppy-Dashboard-Item-previewInnerWrap{box-shadow:none}.uppy-Dashboard-Item-previewInnerWrap:after{background-color:#000000a6;content:"";display:none;inset:0;position:absolute;z-index:1001}.uppy-Dashboard-Item-previewLink{inset:0;position:absolute;z-index:1002}.uppy-Dashboard-Item-previewLink:focus{box-shadow:inset 0 0 0 3px #579df0}[data-uppy-theme=dark] .uppy-Dashboard-Item-previewLink:focus{box-shadow:inset 0 0 0 3px #016c8d}.uppy-Dashboard-Item-preview img.uppy-Dashboard-Item-previewImg{border-radius:3px;height:100%;-o-object-fit:cover;object-fit:cover;transform:translateZ(0);width:100%}.uppy-Dashboard--singleFile .uppy-Dashboard-Item-preview img.uppy-Dashboard-Item-previewImg{height:auto;max-height:100%;max-width:100%;-o-object-fit:contain;object-fit:contain;padding:10px;width:auto}.uppy-Dashboard-Item-progress{color:#fff;left:50%;position:absolute;text-align:center;top:50%;transform:translate(-50%,-50%);transition:all .35 ease;width:120px;z-index:1002}.uppy-Dashboard-Item-progressIndicator{color:#fff;display:inline-block;height:38px;opacity:.9;width:38px}.uppy-size--md .uppy-Dashboard-Item-progressIndicator{height:55px;width:55px}button.uppy-Dashboard-Item-progressIndicator{cursor:pointer}button.uppy-Dashboard-Item-progressIndicator:focus{outline:none}button.uppy-Dashboard-Item-progressIndicator::-moz-focus-inner{border:0}button.uppy-Dashboard-Item-progressIndicator:focus .uppy-Dashboard-Item-progressIcon--bg,button.uppy-Dashboard-Item-progressIndicator:focus .uppy-Dashboard-Item-progressIcon--retry{fill:#579df0}.uppy-Dashboard-Item-progressIcon--circle{height:100%;width:100%}.uppy-Dashboard-Item-progressIcon--bg{stroke:#fff6}.uppy-Dashboard-Item-progressIcon--progress{transition:stroke-dashoffset .5s ease-out;stroke:#fff}.uppy-Dashboard-Item-progressIcon--play{transition:all .2s;fill:#fff;stroke:#fff}.uppy-Dashboard-Item-progressIcon--cancel{transition:all .2s;fill:#fff}.uppy-Dashboard-Item-progressIcon--pause{transition:all .2s;fill:#fff;stroke:#fff}.uppy-Dashboard-Item-progressIcon--check{transition:all .2s;fill:#fff}.uppy-Dashboard-Item-progressIcon--retry{fill:#fff}.uppy-Dashboard-Item.is-complete .uppy-Dashboard-Item-progress{inset-inline-end:-8px;inset-inline-start:auto;top:-9px;transform:none;width:auto}.uppy-Dashboard-Item.is-error .uppy-Dashboard-Item-progressIndicator{height:18px;width:18px}.uppy-size--md .uppy-Dashboard-Item.is-error .uppy-Dashboard-Item-progressIndicator{height:28px;width:28px}.uppy-Dashboard-Item.is-complete .uppy-Dashboard-Item-progressIndicator{height:18px;opacity:1;width:18px}.uppy-size--md .uppy-Dashboard-Item.is-complete .uppy-Dashboard-Item-progressIndicator{height:22px;width:22px}.uppy-Dashboard-Item.is-processing .uppy-Dashboard-Item-progress{opacity:0}.uppy-Dashboard-Item-fileInfo{padding-inline-end:5px}.uppy-Dashboard--singleFile .uppy-Dashboard-Item-fileInfo{padding-inline-end:10px}.uppy-size--md.uppy-Dashboard--singleFile .uppy-Dashboard-Item-fileInfo{padding-inline-end:15px}.uppy-Dashboard-Item-name{font-size:12px;font-weight:500;line-height:1.3;margin-bottom:5px;word-wrap:anywhere;word-break:break-all}[data-uppy-theme=dark] .uppy-Dashboard-Item-name{color:#eaeaea}.uppy-size--md.uppy-Dashboard--singleFile .uppy-Dashboard-Item-name{font-size:14px;line-height:1.4}.uppy-Dashboard-Item-fileName{align-items:baseline;display:flex}.uppy-Dashboard-Item-fileName button{margin-left:5px}.uppy-Dashboard-Item-author{color:#757575;display:inline-block;font-size:11px;font-weight:400;line-height:1;margin-bottom:5px;vertical-align:bottom}.uppy-Dashboard-Item-author a{color:#757575}.uppy-Dashboard-Item-status{color:#757575;font-size:11px;font-weight:400;line-height:1}[data-uppy-theme=dark] .uppy-Dashboard-Item-status{color:#bbb}.uppy-Dashboard-Item-statusSize{display:inline-block;margin-bottom:5px;text-transform:uppercase;vertical-align:bottom}.uppy-Dashboard-Item-reSelect{color:#1269cf;font-family:inherit;font-size:inherit;font-weight:600}.uppy-Dashboard-Item-errorMessage{background-color:#fdeff1;color:#a51523;font-size:11px;font-weight:500;line-height:1.3;padding:5px 6px}.uppy-Dashboard-Item-errorMessageBtn{color:#a51523;cursor:pointer;font-size:11px;font-weight:500;text-decoration:underline}.uppy-Dashboard-Item-preview .uppy-Dashboard-Item-errorMessage{display:none}.uppy-size--md .uppy-Dashboard-Item-preview .uppy-Dashboard-Item-errorMessage{border-bottom-left-radius:3px;border-bottom-right-radius:3px;border-top:1px solid #f7c2c8;bottom:0;display:block;left:0;line-height:1.4;padding:6px 8px;position:absolute;right:0}.uppy-Dashboard-Item-fileInfo .uppy-Dashboard-Item-errorMessage{border:1px solid #f7c2c8;border-radius:3px;display:inline-block;position:static}.uppy-size--md .uppy-Dashboard-Item-fileInfo .uppy-Dashboard-Item-errorMessage{display:none}.uppy-Dashboard-Item-action{color:#939393;cursor:pointer}.uppy-Dashboard-Item-action:focus{outline:none}.uppy-Dashboard-Item-action::-moz-focus-inner{border:0}.uppy-Dashboard-Item-action:focus{box-shadow:0 0 0 3px #1269cf80}.uppy-Dashboard-Item-action:hover{color:#1f1f1f;opacity:1}[data-uppy-theme=dark] .uppy-Dashboard-Item-action{color:#cfcfcf}[data-uppy-theme=dark] .uppy-Dashboard-Item-action:focus{outline:none}[data-uppy-theme=dark] .uppy-Dashboard-Item-action::-moz-focus-inner{border:0}[data-uppy-theme=dark] .uppy-Dashboard-Item-action:focus{box-shadow:0 0 0 2px #aae1ffd9}[data-uppy-theme=dark] .uppy-Dashboard-Item-action:hover{color:#eaeaea}.uppy-Dashboard-Item-action--remove{color:#1f1f1f;opacity:.95}.uppy-Dashboard-Item-action--remove:hover{color:#000;opacity:1}.uppy-size--md .uppy-Dashboard-Item-action--remove{height:18px;inset-inline-end:-8px;padding:0;position:absolute;top:-8px;width:18px;z-index:1002}.uppy-size--md .uppy-Dashboard-Item-action--remove:focus{border-radius:50%}.uppy-Dashboard--singleFile.uppy-size--height-md .uppy-Dashboard-Item-action--remove{inset-inline-end:8px;position:absolute;top:8px}[data-uppy-theme=dark] .uppy-Dashboard-Item-action--remove{color:#525252}[data-uppy-theme=dark] .uppy-Dashboard-Item-action--remove:hover{color:#333}.uppy-Dashboard:not(.uppy-size--md):not(.uppy-Dashboard--singleFile.uppy-size--height-md) .uppy-Dashboard-Item-actionWrapper{align-items:center;display:flex}.uppy-Dashboard:not(.uppy-size--md):not(.uppy-Dashboard--singleFile.uppy-size--height-md) .uppy-Dashboard-Item-action{height:22px;margin-left:3px;padding:3px;width:22px}.uppy-Dashboard:not(.uppy-size--md):not(.uppy-Dashboard--singleFile.uppy-size--height-md) .uppy-Dashboard-Item-action:focus{border-radius:3px}.uppy-size--md .uppy-Dashboard-Item-action--copyLink,.uppy-size--md .uppy-Dashboard-Item-action--edit{height:16px;padding:0;width:16px}.uppy-size--md .uppy-Dashboard-Item-action--copyLink:focus,.uppy-size--md .uppy-Dashboard-Item-action--edit:focus{border-radius:3px}.uppy-Dashboard-Item{align-items:center;border-bottom:1px solid #eaeaea;display:flex;padding:10px}.uppy-Dashboard:not(.uppy-Dashboard--singleFile) .uppy-Dashboard-Item{padding-inline-end:0}[data-uppy-theme=dark] .uppy-Dashboard-Item{border-bottom:1px solid #333}.uppy-size--md .uppy-Dashboard-Item{border-bottom:0;display:block;float:inline-start;height:215px;margin:5px 15px;padding:0;position:relative;width:calc(33.333% - 30px)}.uppy-size--lg .uppy-Dashboard-Item{height:190px;margin:5px 15px;padding:0;width:calc(25% - 30px)}.uppy-size--xl .uppy-Dashboard-Item{height:210px;padding:0;width:calc(20% - 30px)}.uppy-Dashboard--singleFile .uppy-Dashboard-Item{border-bottom:0;display:flex;flex-direction:column;height:100%;max-width:400px;padding:15px;position:relative;width:100%}.uppy-Dashboard-Item.is-ghost .uppy-Dashboard-Item-previewInnerWrap{opacity:.2}.uppy-Dashboard-Item.is-ghost .uppy-Dashboard-Item-name{opacity:.7}.uppy-Dashboard-Item.is-ghost .uppy-Dashboard-Item-preview:before{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='35' height='39' viewBox='0 0 35 39'%3E%3Cpath fill='%2523000' d='M1.708 38.66c1.709 0 3.417-3.417 6.834-3.417s5.125 3.417 8.61 3.417c3.348 0 5.056-3.417 8.473-3.417 4.305 0 5.125 3.417 6.833 3.417.889 0 1.709-.889 1.709-1.709v-19.68C34.167-5.757 0-5.757 0 17.271v19.68c0 .82.888 1.709 1.708 1.709m8.542-17.084a3.383 3.383 0 0 1-3.417-3.416 3.383 3.383 0 0 1 3.417-3.417 3.383 3.383 0 0 1 3.417 3.417 3.383 3.383 0 0 1-3.417 3.416m13.667 0A3.383 3.383 0 0 1 20.5 18.16a3.383 3.383 0 0 1 3.417-3.417 3.383 3.383 0 0 1 3.416 3.417 3.383 3.383 0 0 1-3.416 3.416'/%3E%3C/svg%3E");background-position:50% 10px;background-repeat:no-repeat;background-size:25px;content:"";inset:0;opacity:.5;position:absolute;z-index:1005}.uppy-size--md .uppy-Dashboard-Item.is-ghost .uppy-Dashboard-Item-preview:before{background-position:50% 50%;background-size:40px}.uppy-Dashboard--singleFile .uppy-Dashboard-Item.is-ghost .uppy-Dashboard-Item-preview:before{background-position:50% 50%;background-size:30%}.uppy-Dashboard-Item-preview{flex-grow:0;flex-shrink:0;height:50px;position:relative;width:50px}.uppy-size--md .uppy-Dashboard-Item-preview{height:140px;width:100%}.uppy-size--lg .uppy-Dashboard-Item-preview{height:120px}.uppy-size--xl .uppy-Dashboard-Item-preview{height:140px}.uppy-Dashboard--singleFile .uppy-Dashboard-Item-preview{flex-grow:1;max-height:75%;width:100%}.uppy-Dashboard--singleFile.uppy-size--md .uppy-Dashboard-Item-preview{max-height:100%}.uppy-Dashboard-Item-fileInfoAndButtons{align-items:center;display:flex;flex-grow:1;justify-content:space-between;padding-inline-end:8px;padding-inline-start:12px}.uppy-Dashboard--singleFile .uppy-Dashboard-Item-fileInfoAndButtons,.uppy-size--md .uppy-Dashboard-Item-fileInfoAndButtons{align-items:flex-start;padding:9px 0 0}.uppy-Dashboard--singleFile .uppy-Dashboard-Item-fileInfoAndButtons{flex-grow:0;width:100%}.uppy-Dashboard-Item-fileInfo{flex-grow:1;flex-shrink:1}.uppy-Dashboard-Item-actionWrapper{flex-grow:0;flex-shrink:0}.uppy-Dashboard-Item.is-error .uppy-Dashboard-Item-previewInnerWrap:after,.uppy-Dashboard-Item.is-inprogress .uppy-Dashboard-Item-previewInnerWrap:after{display:block}.uppy-Dashboard-Item-errorDetails{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#939393;border:none;border-radius:50%;color:#fff;cursor:help;flex-shrink:0;font-size:10px;font-weight:600;height:13px;inset-inline-start:2px;line-height:12px;position:relative;text-align:center;top:0;width:13px}.uppy-Dashboard-Item-errorDetails:after{line-height:1.3;word-wrap:break-word}.uppy-Dashboard-FileCard{background-color:#fff;border-radius:5px;box-shadow:0 0 10px 4px #0000001a;display:flex;flex-direction:column;height:100%;inset:0;position:absolute;width:100%;z-index:1005}.uppy-Dashboard-FileCard .uppy-DashboardContent-bar{border-top-left-radius:5px;border-top-right-radius:5px}.uppy-Dashboard-FileCard .uppy-Dashboard-FileCard-actions{border-bottom-left-radius:5px;border-bottom-right-radius:5px}.uppy-Dashboard-FileCard-inner{display:flex;flex-direction:column;flex-grow:1;flex-shrink:1;height:100%;min-height:0}.uppy-Dashboard-FileCard-preview{align-items:center;border-bottom:1px solid #eaeaea;display:flex;flex-grow:0;flex-shrink:1;height:60%;justify-content:center;min-height:0;position:relative}[data-uppy-theme=dark] .uppy-Dashboard-FileCard-preview{background-color:#333;border-bottom:0}.uppy-Dashboard-FileCard-preview img.uppy-Dashboard-Item-previewImg{border-radius:3px;box-shadow:0 3px 20px #00000026;flex:0 0 auto;max-height:90%;max-width:90%;-o-object-fit:cover;object-fit:cover}.uppy-Dashboard-FileCard-edit{background-color:#00000080;border-radius:50px;color:#fff;font-size:13px;inset-inline-end:10px;padding:7px 15px;position:absolute;top:10px}.uppy-Dashboard-FileCard-edit:focus{outline:none}.uppy-Dashboard-FileCard-edit::-moz-focus-inner{border:0}.uppy-Dashboard-FileCard-edit:focus{box-shadow:0 0 0 3px #1269cf80}.uppy-Dashboard-FileCard-edit:hover{background-color:#000c}.uppy-Dashboard-FileCard-info{flex-grow:0;flex-shrink:0;height:40%;overflow-y:auto;padding:30px 20px 20px;-webkit-overflow-scrolling:touch}[data-uppy-theme=dark] .uppy-Dashboard-FileCard-info{background-color:#1f1f1f}.uppy-Dashboard-FileCard-fieldset{border:0;font-size:0;margin:auto auto 12px;max-width:640px;padding:0}.uppy-Dashboard-FileCard-label{color:#525252;display:inline-block;font-size:12px;vertical-align:middle;width:22%}.uppy-size--md .uppy-Dashboard-FileCard-label{font-size:14px}[data-uppy-theme=dark] .uppy-Dashboard-FileCard-label{color:#eaeaea}.uppy-Dashboard-FileCard-input{display:inline-block;vertical-align:middle;width:78%}.uppy-Dashboard-FileCard-actions{align-items:center;background-color:#fafafa;border-top:1px solid #eaeaea;display:flex;flex-grow:0;flex-shrink:0;height:55px;padding:0 15px}.uppy-size--md .uppy-Dashboard-FileCard-actions{height:65px}[data-uppy-theme=dark] .uppy-Dashboard-FileCard-actions{background-color:#1f1f1f;border-top:1px solid #333}.uppy-Dashboard-FileCard-actionsBtn{margin-inline-end:10px}.uppy-Informer{bottom:60px;left:0;position:absolute;right:0;text-align:center;z-index:1005}.uppy-Informer span>div{margin-bottom:6px}.uppy-Informer-animated{opacity:0;transform:translateY(350%);transition:all .3s ease-in;z-index:-1000}.uppy-Informer p{background-color:#757575;border-radius:18px;color:#fff;display:inline-block;font-size:12px;font-weight:400;line-height:1.4;margin:0;max-width:90%;padding:6px 15px}.uppy-size--md .uppy-Informer p{font-size:14px;line-height:1.3;max-width:500px;padding:10px 20px}[data-uppy-theme=dark] .uppy-Informer p{background-color:#333}.uppy-Informer p span{background-color:#fff;border-radius:50%;color:#525252;display:inline-block;font-size:10px;height:13px;inset-inline-start:3px;line-height:12px;margin-inline-start:-1px;position:relative;top:-1px;vertical-align:middle;width:13px}.uppy-Informer p span:hover{cursor:help}.uppy-Informer p span:after{line-height:1.3;word-wrap:break-word}.uppy-Root [aria-label][role~=tooltip]{position:relative}.uppy-Root [aria-label][role~=tooltip]:after,.uppy-Root [aria-label][role~=tooltip]:before{backface-visibility:hidden;box-sizing:border-box;opacity:0;pointer-events:none;position:absolute;transform:translateZ(0);transform-origin:top;transition:all var(--microtip-transition-duration,.18s) var(--microtip-transition-easing,ease-in-out) var(--microtip-transition-delay,0s);will-change:transform;z-index:10}.uppy-Root [aria-label][role~=tooltip]:before{background-size:100% auto!important;content:""}.uppy-Root [aria-label][role~=tooltip]:after{background:#111111e6;border-radius:4px;box-sizing:initial;color:#fff;content:attr(aria-label);font-size:var(--microtip-font-size,13px);font-weight:var(--microtip-font-weight,normal);padding:.5em 1em;text-transform:var(--microtip-text-transform,none);white-space:nowrap}.uppy-Root [aria-label][role~=tooltip]:focus:after,.uppy-Root [aria-label][role~=tooltip]:focus:before,.uppy-Root [aria-label][role~=tooltip]:hover:after,.uppy-Root [aria-label][role~=tooltip]:hover:before{opacity:1;pointer-events:auto}.uppy-Root [role~=tooltip][data-microtip-position|=top]:before{background:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='36' height='12'%3E%3Cpath fill='rgba(17, 17, 17, 0.9)' d='M2.658 0h32.004c-6 0-11.627 12.002-16.002 12.002S8.594 0 2.658 0'/%3E%3C/svg%3E") no-repeat;bottom:100%;height:6px;left:50%;margin-bottom:5px;transform:translate3d(-50%,0,0);width:18px}.uppy-Root [role~=tooltip][data-microtip-position|=top]:after{bottom:100%;left:50%;margin-bottom:11px;transform:translate3d(-50%,0,0)}.uppy-Root [role~=tooltip][data-microtip-position=top]:hover:after,.uppy-Root [role~=tooltip][data-microtip-position|=top]:hover:before{transform:translate3d(-50%,-5px,0)}.uppy-Root [role~=tooltip][data-microtip-position=top-left]:after{bottom:100%;transform:translate3d(calc(-100% + 16px),0,0)}.uppy-Root [role~=tooltip][data-microtip-position=top-left]:hover:after{transform:translate3d(calc(-100% + 16px),-5px,0)}.uppy-Root [role~=tooltip][data-microtip-position=top-right]:after{bottom:100%;transform:translate3d(-16px,0,0)}.uppy-Root [role~=tooltip][data-microtip-position=top-right]:hover:after{transform:translate3d(-16px,-5px,0)}.uppy-Root [role~=tooltip][data-microtip-position|=bottom]:before{background:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='36' height='12'%3E%3Cpath fill='rgba(17, 17, 17, 0.9)' d='M33.342 12H1.338c6 0 11.627-12.002 16.002-12.002S27.406 12 33.342 12'/%3E%3C/svg%3E") no-repeat;bottom:auto;height:6px;left:50%;margin-bottom:0;margin-top:5px;top:100%;transform:translate3d(-50%,-10px,0);width:18px}.uppy-Root [role~=tooltip][data-microtip-position|=bottom]:after{left:50%;margin-top:11px;top:100%;transform:translate3d(-50%,-10px,0)}.uppy-Root [role~=tooltip][data-microtip-position=bottom]:hover:after,.uppy-Root [role~=tooltip][data-microtip-position|=bottom]:hover:before{transform:translate3d(-50%,0,0)}.uppy-Root [role~=tooltip][data-microtip-position=bottom-left]:after{top:100%;transform:translate3d(calc(-100% + 16px),-10px,0)}.uppy-Root [role~=tooltip][data-microtip-position=bottom-left]:hover:after{transform:translate3d(calc(-100% + 16px),0,0)}.uppy-Root [role~=tooltip][data-microtip-position=bottom-right]:after{top:100%;transform:translate3d(-16px,-10px,0)}.uppy-Root [role~=tooltip][data-microtip-position=bottom-right]:hover:after{transform:translate3d(-16px,0,0)}.uppy-Root [role~=tooltip][data-microtip-position=left]:after,.uppy-Root [role~=tooltip][data-microtip-position=left]:before{inset:50% 100% auto auto;transform:translate3d(10px,-50%,0)}.uppy-Root [role~=tooltip][data-microtip-position=left]:before{background:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='36'%3E%3Cpath fill='rgba(17, 17, 17, 0.9)' d='M0 33.342V1.338c0 6 12.002 11.627 12.002 16.002S0 27.406 0 33.342'/%3E%3C/svg%3E") no-repeat;height:18px;margin-bottom:0;margin-right:5px;width:6px}.uppy-Root [role~=tooltip][data-microtip-position=left]:after{margin-right:11px}.uppy-Root [role~=tooltip][data-microtip-position=left]:hover:after,.uppy-Root [role~=tooltip][data-microtip-position=left]:hover:before{transform:translate3d(0,-50%,0)}.uppy-Root [role~=tooltip][data-microtip-position=right]:after,.uppy-Root [role~=tooltip][data-microtip-position=right]:before{bottom:auto;left:100%;top:50%;transform:translate3d(-10px,-50%,0)}.uppy-Root [role~=tooltip][data-microtip-position=right]:before{background:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='36'%3E%3Cpath fill='rgba(17, 17, 17, 0.9)' d='M12 2.658v32.004c0-6-12.002-11.627-12.002-16.002S12 8.594 12 2.658'/%3E%3C/svg%3E") no-repeat;height:18px;margin-bottom:0;margin-left:5px;width:6px}.uppy-Root [role~=tooltip][data-microtip-position=right]:after{margin-left:11px}.uppy-Root [role~=tooltip][data-microtip-position=right]:hover:after,.uppy-Root [role~=tooltip][data-microtip-position=right]:hover:before{transform:translate3d(0,-50%,0)}.uppy-Root [role~=tooltip][data-microtip-size=small]:after{white-space:normal;width:80px}.uppy-Root [role~=tooltip][data-microtip-size=medium]:after{white-space:normal;width:150px}.uppy-Root [role~=tooltip][data-microtip-size=large]:after{white-space:normal;width:260px}.uppy-StatusBar{background-color:#fff;color:#fff;display:flex;font-size:12px;font-weight:400;height:46px;line-height:40px;position:relative;transition:height .2s;z-index:1001}[data-uppy-theme=dark] .uppy-StatusBar{background-color:#1f1f1f}.uppy-StatusBar:before{background-color:#eaeaea;content:"";height:2px;inset:0;position:absolute;width:100%}[data-uppy-theme=dark] .uppy-StatusBar:before{background-color:#757575}.uppy-StatusBar[aria-hidden=true]{height:0;overflow-y:hidden}.uppy-StatusBar.is-complete .uppy-StatusBar-progress{background-color:#1bb240}.uppy-StatusBar.is-error .uppy-StatusBar-progress{background-color:#e32437}.uppy-StatusBar.is-complete .uppy-StatusBar-statusIndicator{color:#1bb240}.uppy-StatusBar.is-error .uppy-StatusBar-statusIndicator{color:#e32437}.uppy-StatusBar:not([aria-hidden=true]).is-waiting{background-color:#fff;border-top:1px solid #eaeaea;height:65px}[data-uppy-theme=dark] .uppy-StatusBar:not([aria-hidden=true]).is-waiting{background-color:#1f1f1f;border-top:1px solid #333}.uppy-StatusBar-progress{background-color:#1269cf;height:2px;position:absolute;transition:background-color,width .3s ease-out;z-index:1001}.uppy-StatusBar-progress.is-indeterminate{animation:uppy-StatusBar-ProgressStripes 1s linear infinite;background-image:linear-gradient(45deg,#0000004d 25%,#0000 0 50%,#0000004d 0 75%,#0000 0,#0000);background-size:64px 64px}@keyframes uppy-StatusBar-ProgressStripes{0%{background-position:0 0}to{background-position:64px 0}}.uppy-StatusBar.is-postprocessing .uppy-StatusBar-progress,.uppy-StatusBar.is-preprocessing .uppy-StatusBar-progress{background-color:#f6a623}.uppy-StatusBar.is-waiting .uppy-StatusBar-progress{display:none}.uppy-StatusBar-content{align-items:center;color:#333;display:flex;height:100%;padding-inline-start:10px;position:relative;text-overflow:ellipsis;white-space:nowrap;z-index:1002}.uppy-size--md .uppy-StatusBar-content{padding-inline-start:15px}[data-uppy-theme=dark] .uppy-StatusBar-content{color:#eaeaea}.uppy-StatusBar-status{display:flex;flex-direction:column;font-weight:400;justify-content:center;line-height:1.4;padding-inline-end:.3em}.uppy-StatusBar-statusPrimary{display:flex;font-weight:500;line-height:1}.uppy-StatusBar-statusPrimary button.uppy-StatusBar-details{margin-left:5px}[data-uppy-theme=dark] .uppy-StatusBar-statusPrimary{color:#eaeaea}.uppy-StatusBar-statusSecondary{color:#757575;display:inline-block;font-size:11px;line-height:1.2;margin-top:1px;white-space:nowrap}[data-uppy-theme=dark] .uppy-StatusBar-statusSecondary{color:#bbb}.uppy-StatusBar-statusSecondaryHint{display:inline-block;line-height:1;margin-inline-end:5px;vertical-align:middle}.uppy-size--md .uppy-StatusBar-statusSecondaryHint{margin-inline-end:8px}.uppy-StatusBar-statusIndicator{color:#525252;margin-inline-end:7px;position:relative;top:1px}.uppy-StatusBar-statusIndicator svg{vertical-align:text-bottom}.uppy-StatusBar-actions{align-items:center;bottom:0;display:flex;inset-inline-end:10px;position:absolute;top:0;z-index:1004}.uppy-StatusBar.is-waiting .uppy-StatusBar-actions{background-color:#fafafa;height:100%;padding:0 15px;position:static;width:100%}[data-uppy-theme=dark] .uppy-StatusBar.is-waiting .uppy-StatusBar-actions{background-color:#1f1f1f}.uppy-StatusBar:not([aria-hidden=true]).is-waiting.has-ghosts{flex-direction:column;height:90px}.uppy-size--md .uppy-StatusBar:not([aria-hidden=true]).is-waiting.has-ghosts{flex-direction:row;height:65px}.uppy-StatusBar:not([aria-hidden=true]).is-waiting.has-ghosts .uppy-StatusBar-actions{flex-direction:column;justify-content:center}.uppy-size--md .uppy-StatusBar:not([aria-hidden=true]).is-waiting.has-ghosts .uppy-StatusBar-actions{flex-direction:row;justify-content:normal}.uppy-StatusBar-actionCircleBtn{cursor:pointer;line-height:1;margin:3px;opacity:.9}.uppy-StatusBar-actionCircleBtn:focus{outline:none}.uppy-StatusBar-actionCircleBtn::-moz-focus-inner{border:0}.uppy-StatusBar-actionCircleBtn:focus{box-shadow:0 0 0 3px #1269cf80}[data-uppy-theme=dark] .uppy-StatusBar-actionCircleBtn:focus{outline:none}[data-uppy-theme=dark] .uppy-StatusBar-actionCircleBtn::-moz-focus-inner{border:0}[data-uppy-theme=dark] .uppy-StatusBar-actionCircleBtn:focus{box-shadow:0 0 0 2px #aae1ffd9}.uppy-StatusBar-actionCircleBtn:hover{opacity:1}.uppy-StatusBar-actionCircleBtn:focus{border-radius:50%}.uppy-StatusBar-actionCircleBtn svg{vertical-align:bottom}.uppy-StatusBar-actionBtn{color:#1269cf;display:inline-block;font-size:10px;line-height:inherit;vertical-align:middle}.uppy-size--md .uppy-StatusBar-actionBtn{font-size:11px}.uppy-StatusBar-actionBtn--disabled{opacity:.4}[data-uppy-theme=dark] .uppy-StatusBar-actionBtn--disabled{opacity:.7}.uppy-StatusBar-actionBtn--retry{background-color:#ff4b23;border-radius:8px;color:#fff;height:16px;line-height:1;margin-inline-end:6px;padding:1px 6px 3px 18px;position:relative}.uppy-StatusBar-actionBtn--retry:focus{outline:none}.uppy-StatusBar-actionBtn--retry::-moz-focus-inner{border:0}.uppy-StatusBar-actionBtn--retry:focus{box-shadow:0 0 0 3px #1269cf80}[data-uppy-theme=dark] .uppy-StatusBar-actionBtn--retry:focus{outline:none}[data-uppy-theme=dark] .uppy-StatusBar-actionBtn--retry::-moz-focus-inner{border:0}[data-uppy-theme=dark] .uppy-StatusBar-actionBtn--retry:focus{box-shadow:0 0 0 2px #aae1ffd9}.uppy-StatusBar-actionBtn--retry:hover{background-color:#f92d00}.uppy-StatusBar-actionBtn--retry svg{inset-inline-start:6px;position:absolute;top:3px}.uppy-StatusBar.is-waiting .uppy-StatusBar-actionBtn--upload{background-color:#1bb240;color:#fff;font-size:14px;line-height:1;padding:15px 10px;width:100%}.uppy-StatusBar.is-waiting .uppy-StatusBar-actionBtn--upload:hover{background-color:#189c38}[data-uppy-theme=dark] .uppy-StatusBar.is-waiting .uppy-StatusBar-actionBtn--upload{background-color:#1c8b37}[data-uppy-theme=dark] .uppy-StatusBar.is-waiting .uppy-StatusBar-actionBtn--upload:hover{background-color:#18762f}.uppy-size--md .uppy-StatusBar.is-waiting .uppy-StatusBar-actionBtn--upload{padding:13px 22px;width:auto}.uppy-StatusBar.is-waiting .uppy-StatusBar-actionBtn--upload.uppy-StatusBar-actionBtn--disabled:hover{background-color:#1bb240;cursor:not-allowed}[data-uppy-theme=dark] .uppy-StatusBar.is-waiting .uppy-StatusBar-actionBtn--upload.uppy-StatusBar-actionBtn--disabled:hover{background-color:#1c8b37}.uppy-StatusBar:not(.is-waiting) .uppy-StatusBar-actionBtn--upload{background-color:initial;color:#1269cf}.uppy-StatusBar-actionBtn--uploadNewlyAdded{border-radius:3px;padding-inline-end:3px;padding-bottom:1px;padding-inline-start:3px}.uppy-StatusBar-actionBtn--uploadNewlyAdded:focus{outline:none}.uppy-StatusBar-actionBtn--uploadNewlyAdded::-moz-focus-inner{border:0}.uppy-StatusBar-actionBtn--uploadNewlyAdded:focus{box-shadow:0 0 0 3px #1269cf80}[data-uppy-theme=dark] .uppy-StatusBar-actionBtn--uploadNewlyAdded:focus{outline:none}[data-uppy-theme=dark] .uppy-StatusBar-actionBtn--uploadNewlyAdded::-moz-focus-inner{border:0}[data-uppy-theme=dark] .uppy-StatusBar-actionBtn--uploadNewlyAdded:focus{box-shadow:0 0 0 2px #aae1ffd9}.uppy-StatusBar.is-postprocessing .uppy-StatusBar-actionBtn--uploadNewlyAdded,.uppy-StatusBar.is-preprocessing .uppy-StatusBar-actionBtn--uploadNewlyAdded{display:none}.uppy-StatusBar-actionBtn--done{border-radius:3px;line-height:1;padding:7px 8px}.uppy-StatusBar-actionBtn--done:focus{outline:none}.uppy-StatusBar-actionBtn--done::-moz-focus-inner{border:0}.uppy-StatusBar-actionBtn--done:hover{color:#0e51a0}.uppy-StatusBar-actionBtn--done:focus{background-color:#dfe6f1}[data-uppy-theme=dark] .uppy-StatusBar-actionBtn--done:focus{background-color:#333}[data-uppy-theme=dark] .uppy-StatusBar-actionBtn--done{color:#02baf2}.uppy-size--md .uppy-StatusBar-actionBtn--done{font-size:14px}.uppy-StatusBar-serviceMsg{color:#000;font-size:11px;line-height:1.1;padding-left:10px}.uppy-size--md .uppy-StatusBar-serviceMsg{font-size:14px;padding-left:15px}[data-uppy-theme=dark] .uppy-StatusBar-serviceMsg{color:#eaeaea}.uppy-StatusBar-serviceMsg-ghostsIcon{left:6px;opacity:.5;position:relative;top:2px;vertical-align:text-bottom;width:10px}.uppy-size--md .uppy-StatusBar-serviceMsg-ghostsIcon{left:10px;top:1px;width:15px}.uppy-StatusBar-details{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#939393;border-radius:50%;color:#fff;cursor:help;display:inline-block;font-size:10px;font-weight:600;height:13px;inset-inline-start:2px;line-height:12px;position:relative;text-align:center;top:0;vertical-align:middle;width:13px}.uppy-StatusBar-details:after{line-height:1.3;word-wrap:break-word}.uppy-StatusBar-spinner{animation-duration:1s;animation-iteration-count:infinite;animation-name:uppy-StatusBar-spinnerAnimation;animation-timing-function:linear;fill:#1269cf;margin-inline-end:10px}.uppy-StatusBar.is-postprocessing .uppy-StatusBar-spinner,.uppy-StatusBar.is-preprocessing .uppy-StatusBar-spinner{fill:#f6a623}@keyframes uppy-StatusBar-spinnerAnimation{0%{transform:rotate(0)}to{transform:rotate(1turn)}}.uppy-transition-slideDownUp-enter{opacity:.01;transform:translate3d(0,-105%,0);transition:transform .25s ease-in-out,opacity .25s ease-in-out}.uppy-transition-slideDownUp-enter.uppy-transition-slideDownUp-enter-active{opacity:1;transform:translateZ(0)}.uppy-transition-slideDownUp-leave{opacity:1;transform:translateZ(0);transition:transform .25s ease-in-out,opacity .25s ease-in-out}.uppy-transition-slideDownUp-leave.uppy-transition-slideDownUp-leave-active{opacity:.01;transform:translate3d(0,-105%,0)}@keyframes uppy-Dashboard-fadeIn{0%{opacity:0}to{opacity:1}}@keyframes uppy-Dashboard-fadeOut{0%{opacity:1}to{opacity:0}}@keyframes uppy-Dashboard-slideDownAndFadeIn{0%{opacity:0;transform:translate3d(-50%,-70%,0)}to{opacity:1;transform:translate3d(-50%,-50%,0)}}@keyframes uppy-Dashboard-slideDownAndFadeIn--small{0%{opacity:0;transform:translate3d(0,-20%,0)}to{opacity:1;transform:translateZ(0)}}@keyframes uppy-Dashboard-slideUpFadeOut{0%{opacity:1;transform:translate3d(-50%,-50%,0)}to{opacity:0;transform:translate3d(-50%,-70%,0)}}@keyframes uppy-Dashboard-slideUpFadeOut--small{0%{opacity:1;transform:translateZ(0)}to{opacity:0;transform:translate3d(0,-20%,0)}}.uppy-Dashboard--modal{z-index:1001}.uppy-Dashboard--modal[aria-hidden=true]{display:none}.uppy-Dashboard--modal.uppy-Dashboard--animateOpenClose>.uppy-Dashboard-inner{animation:uppy-Dashboard-slideDownAndFadeIn--small .3s cubic-bezier(0,0,.2,1)}@media only screen and (min-width:820px){.uppy-Dashboard--modal.uppy-Dashboard--animateOpenClose>.uppy-Dashboard-inner{animation:uppy-Dashboard-slideDownAndFadeIn .3s cubic-bezier(0,0,.2,1)}}.uppy-Dashboard--modal.uppy-Dashboard--animateOpenClose>.uppy-Dashboard-overlay{animation:uppy-Dashboard-fadeIn .3s cubic-bezier(0,0,.2,1)}.uppy-Dashboard--modal.uppy-Dashboard--animateOpenClose.uppy-Dashboard--isClosing>.uppy-Dashboard-inner{animation:uppy-Dashboard-slideUpFadeOut--small .3s cubic-bezier(0,0,.2,1)}@media only screen and (min-width:820px){.uppy-Dashboard--modal.uppy-Dashboard--animateOpenClose.uppy-Dashboard--isClosing>.uppy-Dashboard-inner{animation:uppy-Dashboard-slideUpFadeOut .3s cubic-bezier(0,0,.2,1)}}.uppy-Dashboard--modal.uppy-Dashboard--animateOpenClose.uppy-Dashboard--isClosing>.uppy-Dashboard-overlay{animation:uppy-Dashboard-fadeOut .3s cubic-bezier(0,0,.2,1)}.uppy-Dashboard-isFixed{height:100vh;overflow:hidden}.uppy-Dashboard--modal .uppy-Dashboard-overlay{background-color:#00000080;inset:0;position:fixed;z-index:1001}.uppy-Dashboard-inner{background-color:#f4f4f4;border:1px solid #eaeaea;border-radius:5px;max-height:100%;max-width:100%;outline:none;position:relative}.uppy-size--md .uppy-Dashboard-inner{min-height:auto}@media only screen and (min-width:820px){.uppy-Dashboard-inner{height:500px;width:650px}}.uppy-Dashboard--modal .uppy-Dashboard-inner{z-index:1002}[data-uppy-theme=dark] .uppy-Dashboard-inner{background-color:#1f1f1f}.uppy-Dashboard--isDisabled .uppy-Dashboard-inner{cursor:not-allowed}.uppy-Dashboard-innerWrap{border-radius:5px;display:flex;flex-direction:column;height:100%;opacity:0;overflow:hidden;position:relative}.uppy-Dashboard--isInnerWrapVisible .uppy-Dashboard-innerWrap{opacity:1}.uppy-Dashboard--isDisabled .uppy-Dashboard-innerWrap{cursor:not-allowed;filter:grayscale(100%);opacity:.6;-webkit-user-select:none;-moz-user-select:none;user-select:none}.uppy-Dashboard--isDisabled .uppy-ProviderIconBg{fill:#9f9f9f}.uppy-Dashboard--isDisabled [aria-disabled],.uppy-Dashboard--isDisabled [disabled]{cursor:not-allowed;pointer-events:none}.uppy-Dashboard--modal .uppy-Dashboard-inner{border:none;inset:35px 15px 15px;position:fixed}@media only screen and (min-width:820px){.uppy-Dashboard--modal .uppy-Dashboard-inner{box-shadow:0 5px 15px 4px #00000026;left:50%;right:auto;top:50%;transform:translate(-50%,-50%)}}.uppy-Dashboard-close{color:#ffffffe6;cursor:pointer;display:block;font-size:27px;inset-inline-end:-2px;position:absolute;top:-33px;z-index:1005}.uppy-Dashboard-close:focus{outline:none}.uppy-Dashboard-close::-moz-focus-inner{border:0}.uppy-Dashboard-close:focus{color:#6eabf2}@media only screen and (min-width:820px){.uppy-Dashboard-close{font-size:35px;inset-inline-end:-35px;top:-10px}}.uppy-Dashboard-serviceMsg{background-color:#fffbf7;border-bottom:1px solid #edd4b9;border-top:1px solid #edd4b9;font-size:12px;font-weight:500;line-height:1.3;padding:12px 0;position:relative;top:-1px;z-index:1004}.uppy-size--md .uppy-Dashboard-serviceMsg{font-size:14px;line-height:1.4}[data-uppy-theme=dark] .uppy-Dashboard-serviceMsg{background-color:#1f1f1f;border-bottom:1px solid #333;border-top:1px solid #333;color:#eaeaea}.uppy-Dashboard-serviceMsg-title{display:block;line-height:1;margin-bottom:4px;padding-left:42px}.uppy-Dashboard-serviceMsg-text{padding:0 15px}.uppy-Dashboard-serviceMsg-actionBtn{color:#1269cf;font-size:inherit;font-weight:inherit;vertical-align:initial}[data-uppy-theme=dark] .uppy-Dashboard-serviceMsg-actionBtn{color:#02baf2e6}.uppy-Dashboard-serviceMsg-icon{left:15px;position:absolute;top:10px}.uppy-Dashboard-AddFiles{align-items:center;display:flex;flex-direction:column;height:100%;justify-content:center;position:relative;text-align:center}[data-uppy-drag-drop-supported=true] .uppy-Dashboard-AddFiles{border:1px dashed #dfdfdf;border-radius:3px;height:calc(100% - 14px);margin:7px}.uppy-Dashboard-AddFilesPanel .uppy-Dashboard-AddFiles{border:none;height:calc(100% - 54px)}.uppy-Dashboard--modal .uppy-Dashboard-AddFiles{border-color:#cfcfcf}[data-uppy-theme=dark] .uppy-Dashboard-AddFiles{border-color:#757575}.uppy-Dashboard-AddFiles-info{display:none;margin-top:auto;padding-bottom:15px;padding-top:15px}.uppy-size--height-md .uppy-Dashboard-AddFiles-info{display:block}.uppy-size--md .uppy-Dashboard-AddFiles-info{bottom:25px;left:0;padding-bottom:0;padding-top:30px;position:absolute;right:0}[data-uppy-num-acquirers="0"] .uppy-Dashboard-AddFiles-info{margin-top:0}.uppy-Dashboard-browse{color:#1269cf;cursor:pointer}.uppy-Dashboard-browse:focus{outline:none}.uppy-Dashboard-browse::-moz-focus-inner{border:0}.uppy-Dashboard-browse:focus,.uppy-Dashboard-browse:hover{border-bottom:1px solid #1269cf}[data-uppy-theme=dark] .uppy-Dashboard-browse{color:#02baf2e6}[data-uppy-theme=dark] .uppy-Dashboard-browse:focus,[data-uppy-theme=dark] .uppy-Dashboard-browse:hover{border-bottom:1px solid #02baf2}.uppy-Dashboard-browseBtn{display:block;font-size:14px;font-weight:500;margin-bottom:5px;margin-top:8px;width:100%}.uppy-size--md .uppy-Dashboard-browseBtn{font-size:15px;margin:15px auto;padding:13px 44px;width:auto}.uppy-Dashboard-AddFiles-list{display:flex;flex:1;flex-direction:column;margin-top:2px;overflow-y:auto;padding:2px 0;width:100%;-webkit-overflow-scrolling:touch}.uppy-size--md .uppy-Dashboard-AddFiles-list{flex:none;flex-direction:row;flex-wrap:wrap;justify-content:center;margin-top:15px;max-width:600px;overflow-y:visible;padding-top:0}.uppy-DashboardTab{border-bottom:1px solid #eaeaea;text-align:center;width:100%}[data-uppy-theme=dark] .uppy-DashboardTab{border-bottom:1px solid #333}.uppy-size--md .uppy-DashboardTab{border-bottom:none;display:inline-block;margin-bottom:10px;width:auto}.uppy-DashboardTab-btn{align-items:center;-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:initial;color:#525252;cursor:pointer;flex-direction:row;height:100%;justify-content:left;padding:12px 15px;width:100%}.uppy-DashboardTab-btn:focus{outline:none}.uppy-size--md .uppy-DashboardTab-btn{border-radius:5px;flex-direction:column;margin-inline-end:1px;padding:10px 3px;width:86px}[data-uppy-theme=dark] .uppy-DashboardTab-btn{color:#eaeaea}.uppy-DashboardTab-btn::-moz-focus-inner{border:0}.uppy-DashboardTab-btn:hover{background-color:#e9ecef}[data-uppy-theme=dark] .uppy-DashboardTab-btn:hover{background-color:#333}.uppy-DashboardTab-btn:active,.uppy-DashboardTab-btn:focus{background-color:#dfe6f1}[data-uppy-theme=dark] .uppy-DashboardTab-btn:active,[data-uppy-theme=dark] .uppy-DashboardTab-btn:focus{background-color:#525252}.uppy-DashboardTab-btn svg{display:inline-block;max-height:100%;max-width:100%;overflow:hidden;transition:transform .15s ease-in-out;vertical-align:text-top}.uppy-DashboardTab-inner{align-items:center;background-color:#fff;border-radius:8px;box-shadow:0 1px 1px #0000001a,0 1px 2px #0000001a,0 2px 3px #00000005;display:flex;height:32px;justify-content:center;margin-inline-end:10px;width:32px}.uppy-size--md .uppy-DashboardTab-inner{margin-inline-end:0}[data-uppy-theme=dark] .uppy-DashboardTab-inner{background-color:#323232;box-shadow:0 1px 1px #0003,0 1px 2px #0003,0 2px 3px #00000014}.uppy-DashboardTab-name{font-size:14px;font-weight:400}.uppy-size--md .uppy-DashboardTab-name{font-size:12px;line-height:15px;margin-bottom:0;margin-top:8px}.uppy-DashboardTab-iconMyDevice{color:#1269cf}[data-uppy-theme=dark] .uppy-DashboardTab-iconMyDevice{color:#02baf2}.uppy-DashboardTab-iconBox{color:#0061d5}[data-uppy-theme=dark] .uppy-DashboardTab-iconBox{color:#eaeaea}.uppy-DashboardTab-iconDropbox{color:#0061fe}[data-uppy-theme=dark] .uppy-DashboardTab-iconDropbox{color:#eaeaea}.uppy-DashboardTab-iconUnsplash{color:#111}[data-uppy-theme=dark] .uppy-DashboardTab-iconUnsplash{color:#eaeaea}.uppy-DashboardTab-iconWebdav{color:#111}[data-uppy-theme=dark] .uppy-DashboardTab-iconWebdav{color:#eaeaea}.uppy-DashboardTab-iconScreenRec{color:#2c3e50}[data-uppy-theme=dark] .uppy-DashboardTab-iconScreenRec{color:#eaeaea}.uppy-DashboardTab-iconAudio{color:#8030a3}[data-uppy-theme=dark] .uppy-DashboardTab-iconAudio{color:#bf6ee3}.uppy-Dashboard-input{height:.1px;opacity:0;overflow:hidden;position:absolute;width:.1px;z-index:-1}.uppy-DashboardContent-bar{align-items:center;background-color:#fafafa;border-bottom:1px solid #eaeaea;display:flex;flex-shrink:0;height:40px;justify-content:space-between;padding:0 10px;position:relative;width:100%;z-index:1004}.uppy-size--md .uppy-DashboardContent-bar{height:50px;padding:0 15px}[data-uppy-theme=dark] .uppy-DashboardContent-bar{background-color:#1f1f1f;border-bottom:1px solid #333}.uppy-DashboardContent-title{font-size:12px;font-weight:500;left:0;line-height:40px;margin:auto;max-width:170px;overflow-x:hidden;position:absolute;right:0;text-align:center;text-overflow:ellipsis;top:0;white-space:nowrap;width:100%}.uppy-size--md .uppy-DashboardContent-title{font-size:14px;line-height:50px;max-width:300px}[data-uppy-theme=dark] .uppy-DashboardContent-title{color:#eaeaea}.uppy-DashboardContent-back,.uppy-DashboardContent-save{-webkit-appearance:none;background:none;border:0;border-radius:3px;color:inherit;color:#1269cf;cursor:pointer;font-family:inherit;font-size:inherit;font-size:12px;font-weight:400;line-height:1;margin:0;margin-inline-start:-6px;padding:7px 6px}.uppy-DashboardContent-back:focus,.uppy-DashboardContent-save:focus{outline:none}.uppy-DashboardContent-back::-moz-focus-inner,.uppy-DashboardContent-save::-moz-focus-inner{border:0}.uppy-DashboardContent-back:hover,.uppy-DashboardContent-save:hover{color:#0e51a0}.uppy-DashboardContent-back:focus,.uppy-DashboardContent-save:focus{background-color:#dfe6f1}[data-uppy-theme=dark] .uppy-DashboardContent-back:focus,[data-uppy-theme=dark] .uppy-DashboardContent-save:focus{background-color:#333}.uppy-size--md .uppy-DashboardContent-back,.uppy-size--md .uppy-DashboardContent-save{font-size:14px}[data-uppy-theme=dark] .uppy-DashboardContent-back,[data-uppy-theme=dark] .uppy-DashboardContent-save{color:#02baf2}.uppy-DashboardContent-addMore{-webkit-appearance:none;background:none;border:0;border-radius:3px;color:inherit;color:#1269cf;cursor:pointer;font-family:inherit;font-size:inherit;font-weight:500;height:29px;line-height:1;margin:0;margin-inline-end:-5px;padding:7px 8px;width:29px}.uppy-DashboardContent-addMore:focus{outline:none}.uppy-DashboardContent-addMore::-moz-focus-inner{border:0}.uppy-DashboardContent-addMore:hover{color:#0e51a0}.uppy-DashboardContent-addMore:focus{background-color:#dfe6f1}[data-uppy-theme=dark] .uppy-DashboardContent-addMore:focus{background-color:#333}.uppy-size--md .uppy-DashboardContent-addMore{font-size:14px;height:auto;margin-inline-end:-8px;width:auto}[data-uppy-theme=dark] .uppy-DashboardContent-addMore{color:#02baf2}.uppy-DashboardContent-addMore svg{margin-inline-end:4px;vertical-align:initial}.uppy-size--md .uppy-DashboardContent-addMore svg{height:11px;width:11px}.uppy-DashboardContent-addMoreCaption{display:none}.uppy-size--md .uppy-DashboardContent-addMoreCaption{display:inline}.uppy-DashboardContent-panel{background-color:#f5f5f5;flex:1}.uppy-Dashboard-AddFilesPanel,.uppy-DashboardContent-panel{border-radius:5px;display:flex;flex-direction:column;inset:0;overflow:hidden;position:absolute;z-index:1005}.uppy-Dashboard-AddFilesPanel{background:#fafafa;background:linear-gradient(0deg,#fafafa 35%,#fafafad9);box-shadow:0 0 10px 5px #00000026}[data-uppy-theme=dark] .uppy-Dashboard-AddFilesPanel{background-color:#333;background-image:linear-gradient(0deg,#1f1f1f 35%,#1f1f1fd9)}.uppy-Dashboard--isAddFilesPanelVisible .uppy-Dashboard-files{filter:blur(2px)}.uppy-Dashboard-progress{bottom:0;height:12%;left:0;position:absolute;width:100%}.uppy-Dashboard-progressBarContainer.is-active{height:100%;left:0;position:absolute;top:0;width:100%;z-index:1004}.uppy-Dashboard-filesContainer{flex:1;margin:0;overflow-y:hidden;position:relative}.uppy-Dashboard-filesContainer:after{clear:both;content:"";display:table}.uppy-Dashboard-files{flex:1;margin:0;overflow-y:auto;padding:0 0 10px;-webkit-overflow-scrolling:touch}.uppy-size--md .uppy-Dashboard-files{padding-top:10px}.uppy-Dashboard--singleFile .uppy-Dashboard-filesInner{align-items:center;display:flex;height:100%;justify-content:center}.uppy-Dashboard-dropFilesHereHint{align-items:center;background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='48' height='48'%3E%3Cpath fill='%231269CF' d='M24 1v1C11.85 2 2 11.85 2 24s9.85 22 22 22 22-9.85 22-22S36.15 2 24 2zm0 0V0c13.254 0 24 10.746 24 24S37.254 48 24 48 0 37.254 0 24 10.746 0 24 0zm7.707 19.293a.999.999 0 1 1-1.414 1.414L25 16.414V34a1 1 0 1 1-2 0V16.414l-5.293 5.293a.999.999 0 1 1-1.414-1.414l7-7a1 1 0 0 1 1.414 0z'/%3E%3C/svg%3E");background-position:50% 50%;background-repeat:no-repeat;border:1px dashed #1269cf;border-radius:3px;color:#757575;display:flex;font-size:16px;justify-content:center;inset:7px;padding-top:90px;position:absolute;text-align:center;visibility:hidden;z-index:2000}[data-uppy-theme=dark] .uppy-Dashboard-dropFilesHereHint{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='48' height='48'%3E%3Cpath fill='%2302BAF2' d='M24 1v1C11.85 2 2 11.85 2 24s9.85 22 22 22 22-9.85 22-22S36.15 2 24 2zm0 0V0c13.254 0 24 10.746 24 24S37.254 48 24 48 0 37.254 0 24 10.746 0 24 0zm7.707 19.293a.999.999 0 1 1-1.414 1.414L25 16.414V34a1 1 0 1 1-2 0V16.414l-5.293 5.293a.999.999 0 1 1-1.414-1.414l7-7a1 1 0 0 1 1.414 0z'/%3E%3C/svg%3E");border-color:#02baf2;color:#bbb}.uppy-Dashboard.uppy-Dashboard--isDraggingOver .uppy-Dashboard-dropFilesHereHint{pointer-events:none;visibility:visible}.uppy-Dashboard.uppy-Dashboard--isDraggingOver .uppy-Dashboard-files,.uppy-Dashboard.uppy-Dashboard--isDraggingOver .uppy-Dashboard-progressindicators,.uppy-Dashboard.uppy-Dashboard--isDraggingOver .uppy-Dashboard-serviceMsg,.uppy-Dashboard.uppy-Dashboard--isDraggingOver .uppy-DashboardContent-bar{opacity:.15}.uppy-Dashboard.uppy-Dashboard--isDraggingOver .uppy-Dashboard-AddFiles{opacity:.03}.uppy-Dashboard-AddFiles-title{color:#000;font-size:17px;font-weight:500;line-height:1.35;margin-bottom:5px;margin-top:15px;padding:0 15px;text-align:inline-start;width:100%}.uppy-size--md .uppy-Dashboard-AddFiles-title{font-size:21px;font-weight:400;margin-top:5px;max-width:480px;padding:0 35px;text-align:center}[data-uppy-num-acquirers="0"] .uppy-Dashboard-AddFiles-title{text-align:center}[data-uppy-theme=dark] .uppy-Dashboard-AddFiles-title{color:#eaeaea}.uppy-Dashboard-AddFiles-title button{font-weight:500}.uppy-size--md .uppy-Dashboard-AddFiles-title button{font-weight:400}.uppy-Dashboard-note{color:#757575;font-size:14px;line-height:1.25;margin:auto;max-width:350px;padding:0 15px;text-align:center}.uppy-size--md .uppy-Dashboard-note{line-height:1.35;max-width:600px}[data-uppy-theme=dark] .uppy-Dashboard-note{color:#cfcfcf}a.uppy-Dashboard-poweredBy{color:#939393;display:inline-block;font-size:11px;margin-top:8px;text-align:center;text-decoration:none}.uppy-Dashboard-poweredByIcon{margin-left:1px;margin-right:1px;opacity:.9;position:relative;top:1px;vertical-align:text-top;fill:none;stroke:#939393}.uppy-Dashboard-Item-previewIcon{height:25px;left:50%;position:absolute;top:50%;transform:translate(-50%,-50%);width:25px;z-index:100}.uppy-size--md .uppy-Dashboard-Item-previewIcon{height:38px;width:38px}.uppy-Dashboard-Item-previewIcon svg{height:100%;width:100%}.uppy-Dashboard--singleFile .uppy-Dashboard-Item-previewIcon{height:100%;max-height:60%;max-width:60%;width:100%}.uppy-Dashboard-Item-previewIconWrap{height:76px;max-height:75%;position:relative}.uppy-Dashboard--singleFile .uppy-Dashboard-Item-previewIconWrap{height:100%;width:100%}.uppy-Dashboard-Item-previewIconBg{filter:drop-shadow(rgba(0,0,0,.1) 0 1px 1px);height:100%;width:100%}.uppy-Dashboard-upload{height:50px;position:relative;width:50px}.uppy-size--md .uppy-Dashboard-upload{height:60px;width:60px}.uppy-Dashboard-upload .uppy-c-icon{position:relative;top:1px;width:50%}.uppy-Dashboard-uploadCount{background-color:#1bb240;border-radius:50%;color:#fff;font-size:8px;height:16px;inset-inline-end:-12px;line-height:16px;position:absolute;top:-12px;width:16px}.uppy-size--md .uppy-Dashboard-uploadCount{font-size:9px;height:18px;line-height:18px;width:18px}.uppy-Dashboard-inner{border:none!important;background:transparent!important}.uppy-Dashboard-innerWrap{border-radius:.5rem;overflow:hidden}.uppy-Dashboard-AddFiles{border:2px dashed hsl(var(--border))!important;border-radius:.5rem!important;background:hsl(var(--muted) / .3)!important;transition:all .2s ease}.uppy-Dashboard-AddFiles:hover{border-color:hsl(var(--primary))!important;background:hsl(var(--muted) / .5)!important}.uppy-Dashboard-AddFiles-title{color:hsl(var(--foreground))!important;font-weight:500!important}.uppy-Dashboard-AddFiles-info{color:hsl(var(--muted-foreground))!important}.uppy-Dashboard-browse{color:hsl(var(--primary))!important;font-weight:500!important}.uppy-Dashboard-browse:hover{text-decoration:underline!important}.uppy-Dashboard-files{background:transparent!important}.uppy-Dashboard-Item{border-bottom-color:hsl(var(--border))!important}.uppy-Dashboard-Item-name{color:hsl(var(--foreground))!important}.uppy-Dashboard-Item-status{color:hsl(var(--muted-foreground))!important}.uppy-StatusBar{background:hsl(var(--muted))!important;border-top:1px solid hsl(var(--border))!important}.uppy-StatusBar-progress{background:hsl(var(--primary))!important}.uppy-StatusBar-content{color:hsl(var(--foreground))!important}.uppy-StatusBar-actionBtn--upload{background:hsl(var(--primary))!important;color:hsl(var(--primary-foreground))!important;border-radius:.375rem!important;font-weight:500!important;padding:.5rem 1rem!important}.uppy-StatusBar-actionBtn--upload:hover{background:hsl(var(--primary) / .9)!important}.uppy-Dashboard-note{color:hsl(var(--muted-foreground))!important;font-size:.75rem!important}[data-uppy-theme=dark] .uppy-Dashboard-AddFiles,.dark .uppy-Dashboard-AddFiles{background:hsl(var(--muted) / .2)!important}[data-uppy-theme=dark] .uppy-Dashboard-AddFiles-title,.dark .uppy-Dashboard-AddFiles-title{color:hsl(var(--foreground))!important}[data-uppy-theme=dark] .uppy-StatusBar,.dark .uppy-StatusBar{background:hsl(var(--muted) / .5)!important}.uppy-Dashboard{font-family:inherit!important}.uppy-Dashboard-Item-preview{border-radius:.375rem!important;overflow:hidden}.uppy-Dashboard-Item-action--remove{color:hsl(var(--destructive))!important}.uppy-Dashboard-Item-action--remove:hover{opacity:.8}.uppy-Dashboard-Item.is-complete .uppy-Dashboard-Item-progress{color:hsl(var(--success, 142 76% 36%))!important}.uppy-Dashboard-Item.is-error .uppy-Dashboard-Item-progress{color:hsl(var(--destructive))!important}.uppy-Dashboard-files::-webkit-scrollbar{width:6px}.uppy-Dashboard-files::-webkit-scrollbar-track{background:transparent}.uppy-Dashboard-files::-webkit-scrollbar-thumb{background:hsl(var(--muted-foreground) / .3);border-radius:3px}.uppy-Dashboard-files::-webkit-scrollbar-thumb:hover{background:hsl(var(--muted-foreground) / .5)}@font-face{font-display:block;font-family:KaTeX_AMS;font-style:normal;font-weight:400;src:url(/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2) format("woff2"),url(/assets/KaTeX_AMS-Regular-DMm9YOAa.woff) format("woff"),url(/assets/KaTeX_AMS-Regular-DRggAlZN.ttf) format("truetype")}@font-face{font-display:block;font-family:KaTeX_Caligraphic;font-style:normal;font-weight:700;src:url(/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2) format("woff2"),url(/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff) format("woff"),url(/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf) format("truetype")}@font-face{font-display:block;font-family:KaTeX_Caligraphic;font-style:normal;font-weight:400;src:url(/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2) format("woff2"),url(/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff) format("woff"),url(/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf) format("truetype")}@font-face{font-display:block;font-family:KaTeX_Fraktur;font-style:normal;font-weight:700;src:url(/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2) format("woff2"),url(/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff) format("woff"),url(/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf) format("truetype")}@font-face{font-display:block;font-family:KaTeX_Fraktur;font-style:normal;font-weight:400;src:url(/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2) format("woff2"),url(/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff) format("woff"),url(/assets/KaTeX_Fraktur-Regular-CB_wures.ttf) format("truetype")}@font-face{font-display:block;font-family:KaTeX_Main;font-style:normal;font-weight:700;src:url(/assets/KaTeX_Main-Bold-Cx986IdX.woff2) format("woff2"),url(/assets/KaTeX_Main-Bold-Jm3AIy58.woff) format("woff"),url(/assets/KaTeX_Main-Bold-waoOVXN0.ttf) format("truetype")}@font-face{font-display:block;font-family:KaTeX_Main;font-style:italic;font-weight:700;src:url(/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2) format("woff2"),url(/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff) format("woff"),url(/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf) format("truetype")}@font-face{font-display:block;font-family:KaTeX_Main;font-style:italic;font-weight:400;src:url(/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2) format("woff2"),url(/assets/KaTeX_Main-Italic-BMLOBm91.woff) format("woff"),url(/assets/KaTeX_Main-Italic-3WenGoN9.ttf) format("truetype")}@font-face{font-display:block;font-family:KaTeX_Main;font-style:normal;font-weight:400;src:url(/assets/KaTeX_Main-Regular-B22Nviop.woff2) format("woff2"),url(/assets/KaTeX_Main-Regular-Dr94JaBh.woff) format("woff"),url(/assets/KaTeX_Main-Regular-ypZvNtVU.ttf) format("truetype")}@font-face{font-display:block;font-family:KaTeX_Math;font-style:italic;font-weight:700;src:url(/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2) format("woff2"),url(/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff) format("woff"),url(/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf) format("truetype")}@font-face{font-display:block;font-family:KaTeX_Math;font-style:italic;font-weight:400;src:url(/assets/KaTeX_Math-Italic-t53AETM-.woff2) format("woff2"),url(/assets/KaTeX_Math-Italic-DA0__PXp.woff) format("woff"),url(/assets/KaTeX_Math-Italic-flOr_0UB.ttf) format("truetype")}@font-face{font-display:block;font-family:KaTeX_SansSerif;font-style:normal;font-weight:700;src:url(/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2) format("woff2"),url(/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff) format("woff"),url(/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf) format("truetype")}@font-face{font-display:block;font-family:KaTeX_SansSerif;font-style:italic;font-weight:400;src:url(/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2) format("woff2"),url(/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff) format("woff"),url(/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf) format("truetype")}@font-face{font-display:block;font-family:KaTeX_SansSerif;font-style:normal;font-weight:400;src:url(/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2) format("woff2"),url(/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff) format("woff"),url(/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf) format("truetype")}@font-face{font-display:block;font-family:KaTeX_Script;font-style:normal;font-weight:400;src:url(/assets/KaTeX_Script-Regular-D3wIWfF6.woff2) format("woff2"),url(/assets/KaTeX_Script-Regular-D5yQViql.woff) format("woff"),url(/assets/KaTeX_Script-Regular-C5JkGWo-.ttf) format("truetype")}@font-face{font-display:block;font-family:KaTeX_Size1;font-style:normal;font-weight:400;src:url(/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2) format("woff2"),url(/assets/KaTeX_Size1-Regular-C195tn64.woff) format("woff"),url(/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf) format("truetype")}@font-face{font-display:block;font-family:KaTeX_Size2;font-style:normal;font-weight:400;src:url(/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2) format("woff2"),url(/assets/KaTeX_Size2-Regular-oD1tc_U0.woff) format("woff"),url(/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf) format("truetype")}@font-face{font-display:block;font-family:KaTeX_Size3;font-style:normal;font-weight:400;src:url(data:font/woff2;base64,d09GMgABAAAAAA4oAA4AAAAAHbQAAA3TAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAABmAAgRQIDgmcDBEICo1oijYBNgIkA14LMgAEIAWJAAeBHAyBHBvbGiMRdnO0IkRRkiYDgr9KsJ1NUAf2kILNxgUmgqIgq1P89vcbIcmsQbRps3vCcXdYOKSWEPEKgZgQkprQQsxIXUgq0DqpGKmIvrgkeVGtEQD9DzAO29fM9jYhxZEsL2FeURH2JN4MIcTdO049NCVdxQ/w9NrSYFEBKTDKpLKfNkCGDc1RwjZLQcm3vqJ2UW9Xfa3tgAHz6ivp6vgC2yD4/6352ndnN0X0TL7seypkjZlMsjmZnf0Mm5Q+JykRWQBKCVCVPbARPXWyQtb5VgLB6Biq7/Uixcj2WGqdI8tGSgkuRG+t910GKP2D7AQH0DB9FMDW/obJZ8giFI3Wg8Cvevz0M+5m0rTh7XDBlvo9Y4vm13EXmfttwI4mBo1EG15fxJhUiCLbiiyCf/ZA6MFAhg3pGIZGdGIVjtPn6UcMk9A/UUr9PhoNsCENw1APAq0gpH73e+M+0ueyHbabc3vkbcdtzcf/fiy+NxQEjf9ud/ELBHAXJ0nk4z+MXH2Ev/kWyV4k7SkvpPc9Qr38F6RPWnM9cN6DJ0AdD1BhtgABtmoRoFCvPsBAumNm6soZG2Gk5GyVTo2sJncSyp0jQTYoR6WDvTwaaEcHsxHfvuWhHA3a6bN7twRKtcGok6NsCi7jYRrM2jExsUFMxMQYuJbMhuWNOumEJy9hi29Dmg5zMp/A5+hhPG19j1vBrq8JTLr8ki5VLPmG/PynJHVul440bxg5xuymHUFPBshC+nA9I1FmwbRBTNHAcik3Oae0cxKoI3MOriM42UrPe51nsaGxJ+WfXubAsP84aabUlQSJ1IiE0iPETLUU4CATgfXSCSpuRFRmCGbO+wSpAnzaeaCYW1VNEysRtuXCEL1kUFUbbtMv3Tilt/1c11jt3Q5bbMa84cpWipp8Elw3MZhOHsOlwwVUQM3lAR35JiFQbaYCRnMF2lxAWoOg2gyoIV4PouX8HytNIfLhqpJtXB4vjiViUI8IJ7bkC4ikkQvKksnOTKICwnqWSZ9YS5f0WCxmpgjbIq7EJcM4aI2nmhLNY2JIUgOjXZFWBHb+x5oh6cwb0Tv1ackHdKi0I9OO2wE9aogIOn540CCCziyhN+IaejtgAONKznHlHyutPrHGwCx9S6B8kfS4Mfi4Eyv7OU730bT1SCBjt834cXsf43zVjPUqqJjgrjeGnBxSG4aYAKFuVbeCfkDIjAqMb6yLNIbCuvXhMH2/+k2vkNpkORhR59N1CkzoOENvneIosjYmuTxlhUzaGEJQ/iWqx4dmwpmKjrwTiTGTCVozNAYqk/zXOndWxuWSmJkQpJw3pK5KX6QrLt5LATMqpmPAQhkhK6PUjzHUn7E0gHE0kPE0iKkolgkUx9SZmVAdDgpffdyJKg3k7VmzYGCwVXGz/tXmkOIp+vcWs+EMuhhvN0h9uhfzWJziBQmCREGSIFmQIkgVpAnSBRmC//6hkLZwaVhwxlrJSOdqlFtOYxlau9F2QN5Y98xmIAsiM1HVp2VFX+DHHGg6Ecjh3vmqtidX3qHI2qycTk/iwxSt5UzTmEP92ZBnEWTk4Mx8Mpl78ZDokxg/KWb+Q0QkvdKVmq3TMW+RXEgrsziSAfNXFMhDc60N5N9jQzjfO0kBKpUZl0ZmwJ41j/B9Hz6wmRaJB84niNmQrzp9eSlQCDDzazGDdVi3P36VZQ+Jy4f9UBNp+3zTjqI4abaFAm+GShVaXlsGdF3FYzZcDI6cori4kMxUECl9IjJZpzkvitAoxKue+90pDMvcKRxLl53TmOKCmV/xRolNKSqqUxc6LStOETmFOiLZZptlZepcKiAzteG8PEdpnQpbOMNcMsR4RR2Bs0cKFEvSmIjAFcnarqwUL4lDhHmnVkwu1IwshbiCcgvOheZuYyOteufZZwlcTlLgnZ3o/WcYdzZHW/WGaqaVfmTZ1aWCceJjkbZqsfbkOtcFlUZM/jy+hXHDbaUobWqqXaeWobbLO99yG5N3U4wxco0rQGGcOLASFMXeJoham8M+/x6O2WywK2l4HGbq1CoUyC/IZikQhdq3SiuNrvAEj0AVu9x2x3lp/xWzahaxidezFVtdcb5uEnzyl0ZmYiuKI0exvCd4Xc9CV1KB0db00z92wDPde0kukbvZIWN6jUWFTmPIC/Y4UPCm8UfDTFZpZNon1qLFTkBhxzB+FjQRA2Q/YRJT8pQigslMaUpFyAG8TMlXigiqmAZX4xgijKjRlGpLE0GdplRfCaJo0JQaSxNBk6ZmMzcya0FmrcisDdn0Q3HI2sWSppYigmlM1XT/kLQZSNpMJG0WkjYbSZuDpM1F0uYhFc1HxU4m1QJjDK6iL0S5uSj5rgXc3RejEigtcRBtqYPQsiTskmO5vosV+q4VGIKbOkDg0jtRrq+Em1YloaTFar3EGr1EUC8R0kus1Uus00usL97ABr2BjXoDm/QGNhuWtMVBKOwg/i78lT7hBsAvDmwHc/ao3vmUbBmhjeYySZNWvGkfZAgISDSaDo1SVpzGDsAEkF8B+gEapViUoZgUWXcRIGFZNm6gWbAKk0bp0k1MHG9fLYtV4iS2SmLEQFARzRcnf9PUS0LVn05/J9MiRRBU3v2IrvW974v4N00L7ZMk0wXP1409CHo/an8zTRHD3eSJ6m8D4YMkZNl3M79sqeuAsr/m3f+8/yl7A50aiAEJgeBeMWzu7ui9UfUBCe2TIqZIoOd/3/udRBOQidQZUERzb2/VwZN1H/Sju82ew2H2Wfr6qvfVf3hqwDvAIpkQVFy4B9Pe9e4/XvPeceu7h3dvO56iJPf0+A6cqA2ip18ER+iFgggiuOkvj24bby0N9j2UHIkgqIt+sVgfodC4YghLSMjSZbH0VR/6dMDrYJeKHilKTemt6v6kvzvn3/RrdWtr0GoN/xL+Sex/cPYLUpepx9cz/D46UPU5KXgAQa+NDps1v6J3xP1i2HtaDB0M9aX2deA7SYff//+gUCovMmIK/qfsFcOk+4Y5ZN97XlG6zebqtMbKgeRFi51vnxTQYBUik2rS/Cn6PC8ADR8FGxsRPB82dzfND90gIcshOcYUkfjherBz53odpm6TP8txlwOZ71xmfHHOvq053qFF/MRlS3jP0ELudrf2OeN8DHvp6ZceLe8qKYvWz/7yp0u4dKPfli3CYq0O13Ih71mylJ80tOi10On8wi+F4+LWgDPeJ30msSQt9/vkmHq9/Lvo2b461mP801v3W4xTcs6CbvF9UDdrSt+A8OUbpSh55qAUFXWznBBfdeJ8a4d7ugT5tvxUza3h9m4H7ptTqiG4z0g5dc0X29OcGlhpGFMpQo9ytTS+NViZpNdvU4kWx+LKxNY10kQ1yqGXrhe4/1nvP7E+nd5A92TtaRplbHSqoIdOqtRWti+fkB5/n1+/VvCmz12pG1kpQWsfi1ftlBobm0bpngs16CHkbIwdLnParxtTV3QYRlfJ0KFskH7pdN/YDn+yRuSd7sNH3aO0DYPggk6uWuXrfOc+fa3VTxFVvKaNxHsiHmsXyCLIE5yuOeN3/Jdf8HBL/5M6shjyhxHx9BjB1O0+4NLOnjLLSxwO7ukN4jMbOIcD879KLSi6Pk61Oqm2377n8079PXEEQ7cy7OKEC9nbpet118fxweTafpt69x/Bt8UqGzNQt7aelpc44dn5cqhwf71+qKp/Zf/+a0zcizOUWpl/iBcSXip0pplkatCchoH5c5aUM8I7/dWxAej8WicPL1URFZ9BDJelUwEwTkGqUhgSlydVes95YdXvhh9Gfz/aeFWvgVb4tuLbcv4+wLdutVZv/cUonwBD/6eDlE0aSiKK/uoH3+J1wDE/jMVqY2ysGufN84oIXB0sPzy8ollX/LegY74DgJXJR57sn+VGza0x3DnuIgABFM15LmajjjsNlYj+JEZGbuRYcAMOWxFkPN2w6Wd46xo4gVWQR/X4lyI/R6K/YK0110GzudPRW7Y+UOBGTfNNzHeYT0fiH0taunBpq9HEW8OKSaBGj21L0MqenEmNRWBAWDWAk4CpNoEZJ2tTaPFgbQYj8HxtFilErs3BTRwT8uO1NXQaWfIotchmPkAF5mMBAliEmZiOGVgCG9LgRzpscMAOOwowlT3JhusdazXGSC/hxR3UlmWVwWHpOIKheqONvjyhSiTHIkVUco5bnji8m//zL7PKaT1Vl5I6UE609f+gkr6MZKVyKc7zJRmCahLsdlyA5fdQkRSan9LgnnLEyGSkaKJCJog0wAgvepWBt80+1yKln1bMVtCljfNWDueKLsWwaEbBSfSPTEmVRsUcYYMnEjcjeyCZzBXK9E9BYBXLKjOSpUDR+nEV3TFSUdQaz+ot98QxgXwx0GQ+EEUAKB2qZPkQQ0GqFD8UPFMqyaCHM24BZmSGic9EYMagKizOw9Hz50DMrDLrqqLkTAhplMictiCAx5S3BIUQdeJeLnBy2CNtMfz6cV4u8XKoFZQesbf9YZiIERiHjaNodDW6LgcirX/mPnJIkBGDUpTBhSa0EIr38D5hCIszhCM8URGBqImoWjpvpt1ebu/v3Gl3qJfMnNM+9V+kiRFyROTPHQWOcs1dNW94/ukKMPZBvDi55i5CttdeJz84DLngLqjcdwEZ87bFFR8CIG35OAkDVN6VRDZ7aq67NteYqZ2lpT8oYB2CytoBd6VuAx4WgiAsnuj3WohG+LugzXiQRDeM3XYXlULv4dp5VFYC) format("woff2"),url(/assets/KaTeX_Size3-Regular-CTq5MqoE.woff) format("woff"),url(/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf) format("truetype")}@font-face{font-display:block;font-family:KaTeX_Size4;font-style:normal;font-weight:400;src:url(/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2) format("woff2"),url(/assets/KaTeX_Size4-Regular-BF-4gkZK.woff) format("woff"),url(/assets/KaTeX_Size4-Regular-DWFBv043.ttf) format("truetype")}@font-face{font-display:block;font-family:KaTeX_Typewriter;font-style:normal;font-weight:400;src:url(/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2) format("woff2"),url(/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff) format("woff"),url(/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf) format("truetype")}.katex{font: 1.21em KaTeX_Main,Times New Roman,serif;line-height:1.2;text-indent:0;text-rendering:auto}.katex *{-ms-high-contrast-adjust:none!important;border-color:currentColor}.katex .katex-version:after{content:"0.16.27"}.katex .katex-mathml{clip:rect(1px,1px,1px,1px);border:0;height:1px;overflow:hidden;padding:0;position:absolute;width:1px}.katex .katex-html>.newline{display:block}.katex .base{position:relative;white-space:nowrap;width:-moz-min-content;width:min-content}.katex .base,.katex .strut{display:inline-block}.katex .textbf{font-weight:700}.katex .textit{font-style:italic}.katex .textrm{font-family:KaTeX_Main}.katex .textsf{font-family:KaTeX_SansSerif}.katex .texttt{font-family:KaTeX_Typewriter}.katex .mathnormal{font-family:KaTeX_Math;font-style:italic}.katex .mathit{font-family:KaTeX_Main;font-style:italic}.katex .mathrm{font-style:normal}.katex .mathbf{font-family:KaTeX_Main;font-weight:700}.katex .boldsymbol{font-family:KaTeX_Math;font-style:italic;font-weight:700}.katex .amsrm,.katex .mathbb,.katex .textbb{font-family:KaTeX_AMS}.katex .mathcal{font-family:KaTeX_Caligraphic}.katex .mathfrak,.katex .textfrak{font-family:KaTeX_Fraktur}.katex .mathboldfrak,.katex .textboldfrak{font-family:KaTeX_Fraktur;font-weight:700}.katex .mathtt{font-family:KaTeX_Typewriter}.katex .mathscr,.katex .textscr{font-family:KaTeX_Script}.katex .mathsf,.katex .textsf{font-family:KaTeX_SansSerif}.katex .mathboldsf,.katex .textboldsf{font-family:KaTeX_SansSerif;font-weight:700}.katex .mathitsf,.katex .mathsfit,.katex .textitsf{font-family:KaTeX_SansSerif;font-style:italic}.katex .mainrm{font-family:KaTeX_Main;font-style:normal}.katex .vlist-t{border-collapse:collapse;display:inline-table;table-layout:fixed}.katex .vlist-r{display:table-row}.katex .vlist{display:table-cell;position:relative;vertical-align:bottom}.katex .vlist>span{display:block;height:0;position:relative}.katex .vlist>span>span{display:inline-block}.katex .vlist>span>.pstrut{overflow:hidden;width:0}.katex .vlist-t2{margin-right:-2px}.katex .vlist-s{display:table-cell;font-size:1px;min-width:2px;vertical-align:bottom;width:2px}.katex .vbox{align-items:baseline;display:inline-flex;flex-direction:column}.katex .hbox{width:100%}.katex .hbox,.katex .thinbox{display:inline-flex;flex-direction:row}.katex .thinbox{max-width:0;width:0}.katex .msupsub{text-align:left}.katex .mfrac>span>span{text-align:center}.katex .mfrac .frac-line{border-bottom-style:solid;display:inline-block;width:100%}.katex .hdashline,.katex .hline,.katex .mfrac .frac-line,.katex .overline .overline-line,.katex .rule,.katex .underline .underline-line{min-height:1px}.katex .mspace{display:inline-block}.katex .clap,.katex .llap,.katex .rlap{position:relative;width:0}.katex .clap>.inner,.katex .llap>.inner,.katex .rlap>.inner{position:absolute}.katex .clap>.fix,.katex .llap>.fix,.katex .rlap>.fix{display:inline-block}.katex .llap>.inner{right:0}.katex .clap>.inner,.katex .rlap>.inner{left:0}.katex .clap>.inner>span{margin-left:-50%;margin-right:50%}.katex .rule{border:0 solid;display:inline-block;position:relative}.katex .hline,.katex .overline .overline-line,.katex .underline .underline-line{border-bottom-style:solid;display:inline-block;width:100%}.katex .hdashline{border-bottom-style:dashed;display:inline-block;width:100%}.katex .sqrt>.root{margin-left:.2777777778em;margin-right:-.5555555556em}.katex .fontsize-ensurer.reset-size1.size1,.katex .sizing.reset-size1.size1{font-size:1em}.katex .fontsize-ensurer.reset-size1.size2,.katex .sizing.reset-size1.size2{font-size:1.2em}.katex .fontsize-ensurer.reset-size1.size3,.katex .sizing.reset-size1.size3{font-size:1.4em}.katex .fontsize-ensurer.reset-size1.size4,.katex .sizing.reset-size1.size4{font-size:1.6em}.katex .fontsize-ensurer.reset-size1.size5,.katex .sizing.reset-size1.size5{font-size:1.8em}.katex .fontsize-ensurer.reset-size1.size6,.katex .sizing.reset-size1.size6{font-size:2em}.katex .fontsize-ensurer.reset-size1.size7,.katex .sizing.reset-size1.size7{font-size:2.4em}.katex .fontsize-ensurer.reset-size1.size8,.katex .sizing.reset-size1.size8{font-size:2.88em}.katex .fontsize-ensurer.reset-size1.size9,.katex .sizing.reset-size1.size9{font-size:3.456em}.katex .fontsize-ensurer.reset-size1.size10,.katex .sizing.reset-size1.size10{font-size:4.148em}.katex .fontsize-ensurer.reset-size1.size11,.katex .sizing.reset-size1.size11{font-size:4.976em}.katex .fontsize-ensurer.reset-size2.size1,.katex .sizing.reset-size2.size1{font-size:.8333333333em}.katex .fontsize-ensurer.reset-size2.size2,.katex .sizing.reset-size2.size2{font-size:1em}.katex .fontsize-ensurer.reset-size2.size3,.katex .sizing.reset-size2.size3{font-size:1.1666666667em}.katex .fontsize-ensurer.reset-size2.size4,.katex .sizing.reset-size2.size4{font-size:1.3333333333em}.katex .fontsize-ensurer.reset-size2.size5,.katex .sizing.reset-size2.size5{font-size:1.5em}.katex .fontsize-ensurer.reset-size2.size6,.katex .sizing.reset-size2.size6{font-size:1.6666666667em}.katex .fontsize-ensurer.reset-size2.size7,.katex .sizing.reset-size2.size7{font-size:2em}.katex .fontsize-ensurer.reset-size2.size8,.katex .sizing.reset-size2.size8{font-size:2.4em}.katex .fontsize-ensurer.reset-size2.size9,.katex .sizing.reset-size2.size9{font-size:2.88em}.katex .fontsize-ensurer.reset-size2.size10,.katex .sizing.reset-size2.size10{font-size:3.4566666667em}.katex .fontsize-ensurer.reset-size2.size11,.katex .sizing.reset-size2.size11{font-size:4.1466666667em}.katex .fontsize-ensurer.reset-size3.size1,.katex .sizing.reset-size3.size1{font-size:.7142857143em}.katex .fontsize-ensurer.reset-size3.size2,.katex .sizing.reset-size3.size2{font-size:.8571428571em}.katex .fontsize-ensurer.reset-size3.size3,.katex .sizing.reset-size3.size3{font-size:1em}.katex .fontsize-ensurer.reset-size3.size4,.katex .sizing.reset-size3.size4{font-size:1.1428571429em}.katex .fontsize-ensurer.reset-size3.size5,.katex .sizing.reset-size3.size5{font-size:1.2857142857em}.katex .fontsize-ensurer.reset-size3.size6,.katex .sizing.reset-size3.size6{font-size:1.4285714286em}.katex .fontsize-ensurer.reset-size3.size7,.katex .sizing.reset-size3.size7{font-size:1.7142857143em}.katex .fontsize-ensurer.reset-size3.size8,.katex .sizing.reset-size3.size8{font-size:2.0571428571em}.katex .fontsize-ensurer.reset-size3.size9,.katex .sizing.reset-size3.size9{font-size:2.4685714286em}.katex .fontsize-ensurer.reset-size3.size10,.katex .sizing.reset-size3.size10{font-size:2.9628571429em}.katex .fontsize-ensurer.reset-size3.size11,.katex .sizing.reset-size3.size11{font-size:3.5542857143em}.katex .fontsize-ensurer.reset-size4.size1,.katex .sizing.reset-size4.size1{font-size:.625em}.katex .fontsize-ensurer.reset-size4.size2,.katex .sizing.reset-size4.size2{font-size:.75em}.katex .fontsize-ensurer.reset-size4.size3,.katex .sizing.reset-size4.size3{font-size:.875em}.katex .fontsize-ensurer.reset-size4.size4,.katex .sizing.reset-size4.size4{font-size:1em}.katex .fontsize-ensurer.reset-size4.size5,.katex .sizing.reset-size4.size5{font-size:1.125em}.katex .fontsize-ensurer.reset-size4.size6,.katex .sizing.reset-size4.size6{font-size:1.25em}.katex .fontsize-ensurer.reset-size4.size7,.katex .sizing.reset-size4.size7{font-size:1.5em}.katex .fontsize-ensurer.reset-size4.size8,.katex .sizing.reset-size4.size8{font-size:1.8em}.katex .fontsize-ensurer.reset-size4.size9,.katex .sizing.reset-size4.size9{font-size:2.16em}.katex .fontsize-ensurer.reset-size4.size10,.katex .sizing.reset-size4.size10{font-size:2.5925em}.katex .fontsize-ensurer.reset-size4.size11,.katex .sizing.reset-size4.size11{font-size:3.11em}.katex .fontsize-ensurer.reset-size5.size1,.katex .sizing.reset-size5.size1{font-size:.5555555556em}.katex .fontsize-ensurer.reset-size5.size2,.katex .sizing.reset-size5.size2{font-size:.6666666667em}.katex .fontsize-ensurer.reset-size5.size3,.katex .sizing.reset-size5.size3{font-size:.7777777778em}.katex .fontsize-ensurer.reset-size5.size4,.katex .sizing.reset-size5.size4{font-size:.8888888889em}.katex .fontsize-ensurer.reset-size5.size5,.katex .sizing.reset-size5.size5{font-size:1em}.katex .fontsize-ensurer.reset-size5.size6,.katex .sizing.reset-size5.size6{font-size:1.1111111111em}.katex .fontsize-ensurer.reset-size5.size7,.katex .sizing.reset-size5.size7{font-size:1.3333333333em}.katex .fontsize-ensurer.reset-size5.size8,.katex .sizing.reset-size5.size8{font-size:1.6em}.katex .fontsize-ensurer.reset-size5.size9,.katex .sizing.reset-size5.size9{font-size:1.92em}.katex .fontsize-ensurer.reset-size5.size10,.katex .sizing.reset-size5.size10{font-size:2.3044444444em}.katex .fontsize-ensurer.reset-size5.size11,.katex .sizing.reset-size5.size11{font-size:2.7644444444em}.katex .fontsize-ensurer.reset-size6.size1,.katex .sizing.reset-size6.size1{font-size:.5em}.katex .fontsize-ensurer.reset-size6.size2,.katex .sizing.reset-size6.size2{font-size:.6em}.katex .fontsize-ensurer.reset-size6.size3,.katex .sizing.reset-size6.size3{font-size:.7em}.katex .fontsize-ensurer.reset-size6.size4,.katex .sizing.reset-size6.size4{font-size:.8em}.katex .fontsize-ensurer.reset-size6.size5,.katex .sizing.reset-size6.size5{font-size:.9em}.katex .fontsize-ensurer.reset-size6.size6,.katex .sizing.reset-size6.size6{font-size:1em}.katex .fontsize-ensurer.reset-size6.size7,.katex .sizing.reset-size6.size7{font-size:1.2em}.katex .fontsize-ensurer.reset-size6.size8,.katex .sizing.reset-size6.size8{font-size:1.44em}.katex .fontsize-ensurer.reset-size6.size9,.katex .sizing.reset-size6.size9{font-size:1.728em}.katex .fontsize-ensurer.reset-size6.size10,.katex .sizing.reset-size6.size10{font-size:2.074em}.katex .fontsize-ensurer.reset-size6.size11,.katex .sizing.reset-size6.size11{font-size:2.488em}.katex .fontsize-ensurer.reset-size7.size1,.katex .sizing.reset-size7.size1{font-size:.4166666667em}.katex .fontsize-ensurer.reset-size7.size2,.katex .sizing.reset-size7.size2{font-size:.5em}.katex .fontsize-ensurer.reset-size7.size3,.katex .sizing.reset-size7.size3{font-size:.5833333333em}.katex .fontsize-ensurer.reset-size7.size4,.katex .sizing.reset-size7.size4{font-size:.6666666667em}.katex .fontsize-ensurer.reset-size7.size5,.katex .sizing.reset-size7.size5{font-size:.75em}.katex .fontsize-ensurer.reset-size7.size6,.katex .sizing.reset-size7.size6{font-size:.8333333333em}.katex .fontsize-ensurer.reset-size7.size7,.katex .sizing.reset-size7.size7{font-size:1em}.katex .fontsize-ensurer.reset-size7.size8,.katex .sizing.reset-size7.size8{font-size:1.2em}.katex .fontsize-ensurer.reset-size7.size9,.katex .sizing.reset-size7.size9{font-size:1.44em}.katex .fontsize-ensurer.reset-size7.size10,.katex .sizing.reset-size7.size10{font-size:1.7283333333em}.katex .fontsize-ensurer.reset-size7.size11,.katex .sizing.reset-size7.size11{font-size:2.0733333333em}.katex .fontsize-ensurer.reset-size8.size1,.katex .sizing.reset-size8.size1{font-size:.3472222222em}.katex .fontsize-ensurer.reset-size8.size2,.katex .sizing.reset-size8.size2{font-size:.4166666667em}.katex .fontsize-ensurer.reset-size8.size3,.katex .sizing.reset-size8.size3{font-size:.4861111111em}.katex .fontsize-ensurer.reset-size8.size4,.katex .sizing.reset-size8.size4{font-size:.5555555556em}.katex .fontsize-ensurer.reset-size8.size5,.katex .sizing.reset-size8.size5{font-size:.625em}.katex .fontsize-ensurer.reset-size8.size6,.katex .sizing.reset-size8.size6{font-size:.6944444444em}.katex .fontsize-ensurer.reset-size8.size7,.katex .sizing.reset-size8.size7{font-size:.8333333333em}.katex .fontsize-ensurer.reset-size8.size8,.katex .sizing.reset-size8.size8{font-size:1em}.katex .fontsize-ensurer.reset-size8.size9,.katex .sizing.reset-size8.size9{font-size:1.2em}.katex .fontsize-ensurer.reset-size8.size10,.katex .sizing.reset-size8.size10{font-size:1.4402777778em}.katex .fontsize-ensurer.reset-size8.size11,.katex .sizing.reset-size8.size11{font-size:1.7277777778em}.katex .fontsize-ensurer.reset-size9.size1,.katex .sizing.reset-size9.size1{font-size:.2893518519em}.katex .fontsize-ensurer.reset-size9.size2,.katex .sizing.reset-size9.size2{font-size:.3472222222em}.katex .fontsize-ensurer.reset-size9.size3,.katex .sizing.reset-size9.size3{font-size:.4050925926em}.katex .fontsize-ensurer.reset-size9.size4,.katex .sizing.reset-size9.size4{font-size:.462962963em}.katex .fontsize-ensurer.reset-size9.size5,.katex .sizing.reset-size9.size5{font-size:.5208333333em}.katex .fontsize-ensurer.reset-size9.size6,.katex .sizing.reset-size9.size6{font-size:.5787037037em}.katex .fontsize-ensurer.reset-size9.size7,.katex .sizing.reset-size9.size7{font-size:.6944444444em}.katex .fontsize-ensurer.reset-size9.size8,.katex .sizing.reset-size9.size8{font-size:.8333333333em}.katex .fontsize-ensurer.reset-size9.size9,.katex .sizing.reset-size9.size9{font-size:1em}.katex .fontsize-ensurer.reset-size9.size10,.katex .sizing.reset-size9.size10{font-size:1.2002314815em}.katex .fontsize-ensurer.reset-size9.size11,.katex .sizing.reset-size9.size11{font-size:1.4398148148em}.katex .fontsize-ensurer.reset-size10.size1,.katex .sizing.reset-size10.size1{font-size:.2410800386em}.katex .fontsize-ensurer.reset-size10.size2,.katex .sizing.reset-size10.size2{font-size:.2892960463em}.katex .fontsize-ensurer.reset-size10.size3,.katex .sizing.reset-size10.size3{font-size:.337512054em}.katex .fontsize-ensurer.reset-size10.size4,.katex .sizing.reset-size10.size4{font-size:.3857280617em}.katex .fontsize-ensurer.reset-size10.size5,.katex .sizing.reset-size10.size5{font-size:.4339440694em}.katex .fontsize-ensurer.reset-size10.size6,.katex .sizing.reset-size10.size6{font-size:.4821600771em}.katex .fontsize-ensurer.reset-size10.size7,.katex .sizing.reset-size10.size7{font-size:.5785920926em}.katex .fontsize-ensurer.reset-size10.size8,.katex .sizing.reset-size10.size8{font-size:.6943105111em}.katex .fontsize-ensurer.reset-size10.size9,.katex .sizing.reset-size10.size9{font-size:.8331726133em}.katex .fontsize-ensurer.reset-size10.size10,.katex .sizing.reset-size10.size10{font-size:1em}.katex .fontsize-ensurer.reset-size10.size11,.katex .sizing.reset-size10.size11{font-size:1.1996142719em}.katex .fontsize-ensurer.reset-size11.size1,.katex .sizing.reset-size11.size1{font-size:.2009646302em}.katex .fontsize-ensurer.reset-size11.size2,.katex .sizing.reset-size11.size2{font-size:.2411575563em}.katex .fontsize-ensurer.reset-size11.size3,.katex .sizing.reset-size11.size3{font-size:.2813504823em}.katex .fontsize-ensurer.reset-size11.size4,.katex .sizing.reset-size11.size4{font-size:.3215434084em}.katex .fontsize-ensurer.reset-size11.size5,.katex .sizing.reset-size11.size5{font-size:.3617363344em}.katex .fontsize-ensurer.reset-size11.size6,.katex .sizing.reset-size11.size6{font-size:.4019292605em}.katex .fontsize-ensurer.reset-size11.size7,.katex .sizing.reset-size11.size7{font-size:.4823151125em}.katex .fontsize-ensurer.reset-size11.size8,.katex .sizing.reset-size11.size8{font-size:.578778135em}.katex .fontsize-ensurer.reset-size11.size9,.katex .sizing.reset-size11.size9{font-size:.6945337621em}.katex .fontsize-ensurer.reset-size11.size10,.katex .sizing.reset-size11.size10{font-size:.8336012862em}.katex .fontsize-ensurer.reset-size11.size11,.katex .sizing.reset-size11.size11{font-size:1em}.katex .delimsizing.size1{font-family:KaTeX_Size1}.katex .delimsizing.size2{font-family:KaTeX_Size2}.katex .delimsizing.size3{font-family:KaTeX_Size3}.katex .delimsizing.size4{font-family:KaTeX_Size4}.katex .delimsizing.mult .delim-size1>span{font-family:KaTeX_Size1}.katex .delimsizing.mult .delim-size4>span{font-family:KaTeX_Size4}.katex .nulldelimiter{display:inline-block;width:.12em}.katex .delimcenter,.katex .op-symbol{position:relative}.katex .op-symbol.small-op{font-family:KaTeX_Size1}.katex .op-symbol.large-op{font-family:KaTeX_Size2}.katex .accent>.vlist-t,.katex .op-limits>.vlist-t{text-align:center}.katex .accent .accent-body{position:relative}.katex .accent .accent-body:not(.accent-full){width:0}.katex .overlay{display:block}.katex .mtable .vertical-separator{display:inline-block;min-width:1px}.katex .mtable .arraycolsep{display:inline-block}.katex .mtable .col-align-c>.vlist-t{text-align:center}.katex .mtable .col-align-l>.vlist-t{text-align:left}.katex .mtable .col-align-r>.vlist-t{text-align:right}.katex .svg-align{text-align:left}.katex svg{fill:currentColor;stroke:currentColor;fill-rule:nonzero;fill-opacity:1;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;display:block;height:inherit;position:absolute;width:100%}.katex svg path{stroke:none}.katex img{border-style:none;max-height:none;max-width:none;min-height:0;min-width:0}.katex .stretchy{display:block;overflow:hidden;position:relative;width:100%}.katex .stretchy:after,.katex .stretchy:before{content:""}.katex .hide-tail{overflow:hidden;position:relative;width:100%}.katex .halfarrow-left{left:0;overflow:hidden;position:absolute;width:50.2%}.katex .halfarrow-right{overflow:hidden;position:absolute;right:0;width:50.2%}.katex .brace-left{left:0;overflow:hidden;position:absolute;width:25.1%}.katex .brace-center{left:25%;overflow:hidden;position:absolute;width:50%}.katex .brace-right{overflow:hidden;position:absolute;right:0;width:25.1%}.katex .x-arrow-pad{padding:0 .5em}.katex .cd-arrow-pad{padding:0 .55556em 0 .27778em}.katex .mover,.katex .munder,.katex .x-arrow{text-align:center}.katex .boxpad{padding:0 .3em}.katex .fbox,.katex .fcolorbox{border:.04em solid;box-sizing:border-box}.katex .cancel-pad{padding:0 .2em}.katex .cancel-lap{margin-left:-.2em;margin-right:-.2em}.katex .sout{border-bottom-style:solid;border-bottom-width:.08em}.katex .angl{border-right:.049em solid;border-top:.049em solid;box-sizing:border-box;margin-right:.03889em}.katex .anglpad{padding:0 .03889em}.katex .eqn-num:before{content:"(" counter(katexEqnNo) ")";counter-increment:katexEqnNo}.katex .mml-eqn-num:before{content:"(" counter(mmlEqnNo) ")";counter-increment:mmlEqnNo}.katex .mtr-glue{width:50%}.katex .cd-vert-arrow{display:inline-block;position:relative}.katex .cd-label-left{display:inline-block;position:absolute;right:calc(50% + .3em);text-align:left}.katex .cd-label-right{display:inline-block;left:calc(50% + .3em);position:absolute;text-align:right}.katex-display{display:block;margin:1em 0;text-align:center}.katex-display>.katex{display:block;text-align:center;white-space:nowrap}.katex-display>.katex>.katex-html{display:block;position:relative}.katex-display>.katex>.katex-html>.tag{position:absolute;right:0}.katex-display.leqno>.katex>.katex-html>.tag{left:0;right:auto}.katex-display.fleqn>.katex{padding-left:2em;text-align:left}body{counter-reset:katexEqnNo mmlEqnNo}.react-flow{direction:ltr}.react-flow__container{position:absolute;width:100%;height:100%;top:0;left:0}.react-flow__pane{z-index:1;cursor:grab}.react-flow__pane.selection{cursor:pointer}.react-flow__pane.dragging{cursor:grabbing}.react-flow__viewport{transform-origin:0 0;z-index:2;pointer-events:none}.react-flow__renderer{z-index:4}.react-flow__selection{z-index:6}.react-flow__nodesselection-rect:focus,.react-flow__nodesselection-rect:focus-visible{outline:none}.react-flow .react-flow__edges{pointer-events:none;overflow:visible}.react-flow__edge-path,.react-flow__connection-path{stroke:#b1b1b7;stroke-width:1;fill:none}.react-flow__edge{pointer-events:visibleStroke;cursor:pointer}.react-flow__edge.animated path{stroke-dasharray:5;animation:dashdraw .5s linear infinite}.react-flow__edge.animated path.react-flow__edge-interaction{stroke-dasharray:none;animation:none}.react-flow__edge.inactive{pointer-events:none}.react-flow__edge.selected,.react-flow__edge:focus,.react-flow__edge:focus-visible{outline:none}.react-flow__edge.selected .react-flow__edge-path,.react-flow__edge:focus .react-flow__edge-path,.react-flow__edge:focus-visible .react-flow__edge-path{stroke:#555}.react-flow__edge-textwrapper{pointer-events:all}.react-flow__edge-textbg{fill:#fff}.react-flow__edge .react-flow__edge-text{pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.react-flow__connection{pointer-events:none}.react-flow__connection .animated{stroke-dasharray:5;animation:dashdraw .5s linear infinite}.react-flow__connectionline{z-index:1001}.react-flow__nodes{pointer-events:none;transform-origin:0 0}.react-flow__node{position:absolute;-webkit-user-select:none;-moz-user-select:none;user-select:none;pointer-events:all;transform-origin:0 0;box-sizing:border-box;cursor:grab}.react-flow__node.dragging{cursor:grabbing}.react-flow__nodesselection{z-index:3;transform-origin:left top;pointer-events:none}.react-flow__nodesselection-rect{position:absolute;pointer-events:all;cursor:grab}.react-flow__handle{position:absolute;pointer-events:none;min-width:5px;min-height:5px;width:6px;height:6px;background:#1a192b;border:1px solid white;border-radius:100%}.react-flow__handle.connectionindicator{pointer-events:all;cursor:crosshair}.react-flow__handle-bottom{top:auto;left:50%;bottom:-4px;transform:translate(-50%)}.react-flow__handle-top{left:50%;top:-4px;transform:translate(-50%)}.react-flow__handle-left{top:50%;left:-4px;transform:translateY(-50%)}.react-flow__handle-right{right:-4px;top:50%;transform:translateY(-50%)}.react-flow__edgeupdater{cursor:move;pointer-events:all}.react-flow__panel{position:absolute;z-index:5;margin:15px}.react-flow__panel.top{top:0}.react-flow__panel.bottom{bottom:0}.react-flow__panel.left{left:0}.react-flow__panel.right{right:0}.react-flow__panel.center{left:50%;transform:translate(-50%)}.react-flow__attribution{font-size:10px;background:#ffffff80;padding:2px 3px;margin:0}.react-flow__attribution a{text-decoration:none;color:#999}@keyframes dashdraw{0%{stroke-dashoffset:10}}.react-flow__edgelabel-renderer{position:absolute;width:100%;height:100%;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.react-flow__edge.updating .react-flow__edge-path{stroke:#777}.react-flow__edge-text{font-size:10px}.react-flow__node.selectable:focus,.react-flow__node.selectable:focus-visible{outline:none}.react-flow__node-default,.react-flow__node-input,.react-flow__node-output,.react-flow__node-group{padding:10px;border-radius:3px;width:150px;font-size:12px;color:#222;text-align:center;border-width:1px;border-style:solid;border-color:#1a192b;background-color:#fff}.react-flow__node-default.selectable:hover,.react-flow__node-input.selectable:hover,.react-flow__node-output.selectable:hover,.react-flow__node-group.selectable:hover{box-shadow:0 1px 4px 1px #00000014}.react-flow__node-default.selectable.selected,.react-flow__node-default.selectable:focus,.react-flow__node-default.selectable:focus-visible,.react-flow__node-input.selectable.selected,.react-flow__node-input.selectable:focus,.react-flow__node-input.selectable:focus-visible,.react-flow__node-output.selectable.selected,.react-flow__node-output.selectable:focus,.react-flow__node-output.selectable:focus-visible,.react-flow__node-group.selectable.selected,.react-flow__node-group.selectable:focus,.react-flow__node-group.selectable:focus-visible{box-shadow:0 0 0 .5px #1a192b}.react-flow__node-group{background-color:#f0f0f040}.react-flow__nodesselection-rect,.react-flow__selection{background:#0059dc14;border:1px dotted rgba(0,89,220,.8)}.react-flow__nodesselection-rect:focus,.react-flow__nodesselection-rect:focus-visible,.react-flow__selection:focus,.react-flow__selection:focus-visible{outline:none}.react-flow__controls{box-shadow:0 0 2px 1px #00000014}.react-flow__controls-button{border:none;background:#fefefe;border-bottom:1px solid #eee;box-sizing:content-box;display:flex;justify-content:center;align-items:center;width:16px;height:16px;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;user-select:none;padding:5px}.react-flow__controls-button:hover{background:#f4f4f4}.react-flow__controls-button svg{width:100%;max-width:12px;max-height:12px}.react-flow__controls-button:disabled{pointer-events:none}.react-flow__controls-button:disabled svg{fill-opacity:.4}.react-flow__minimap{background-color:#fff}.react-flow__minimap svg{display:block}.react-flow__resize-control{position:absolute}.react-flow__resize-control.left,.react-flow__resize-control.right{cursor:ew-resize}.react-flow__resize-control.top,.react-flow__resize-control.bottom{cursor:ns-resize}.react-flow__resize-control.top.left,.react-flow__resize-control.bottom.right{cursor:nwse-resize}.react-flow__resize-control.bottom.left,.react-flow__resize-control.top.right{cursor:nesw-resize}.react-flow__resize-control.handle{width:4px;height:4px;border:1px solid #fff;border-radius:1px;background-color:#3367d9;transform:translate(-50%,-50%)}.react-flow__resize-control.handle.left{left:0;top:50%}.react-flow__resize-control.handle.right{left:100%;top:50%}.react-flow__resize-control.handle.top{left:50%;top:0}.react-flow__resize-control.handle.bottom{left:50%;top:100%}.react-flow__resize-control.handle.top.left,.react-flow__resize-control.handle.bottom.left{left:0}.react-flow__resize-control.handle.top.right,.react-flow__resize-control.handle.bottom.right{left:100%}.react-flow__resize-control.line{border-color:#3367d9;border-width:0;border-style:solid}.react-flow__resize-control.line.left,.react-flow__resize-control.line.right{width:1px;transform:translate(-50%);top:0;height:100%}.react-flow__resize-control.line.left{left:0;border-left-width:1px}.react-flow__resize-control.line.right{left:100%;border-right-width:1px}.react-flow__resize-control.line.top,.react-flow__resize-control.line.bottom{height:1px;transform:translateY(-50%);left:0;width:100%}.react-flow__resize-control.line.top{top:0;border-top-width:1px}.react-flow__resize-control.line.bottom{border-bottom-width:1px;top:100%} diff --git a/webui/dist/assets/index-CgxOYrz-.js b/webui/dist/assets/index-CgxOYrz-.js deleted file mode 100644 index 1f13752a..00000000 --- a/webui/dist/assets/index-CgxOYrz-.js +++ /dev/null @@ -1,54 +0,0 @@ -import{r as u,j as e,L as Kn,e as va,R as bt,b as Ub,f as Bb,g as Hb,h as qb,k as tt,l as Gb,m as $b,O as _p,n as Fb}from"./router-Bz250laD.js";import{a as Vb,b as Qb,g as Ib}from"./react-vendor-BmxF9s7Q.js";import{N as Yb,c as Kb,O as tr,P as Ac,g as ju}from"./utils-BXc2jIuz.js";import{L as Sp,T as Cp,C as kp,R as Xb,a as Tp,V as Jb,b as Zb,S as Ep,c as Pb,d as zp,I as Wb,e as Ap,f as eN,g as Mp,h as sN,i as tN,j as aN,O as Dp,P as lN,k as Op,l as Rp,D as Lp,A as Up,m as Bp,n as nN,o as rN,p as Hp,q as iN,r as qp,s as cN,t as oN,u as dN,v as uN,w as mN,x as Gp,y as $p,F as Fp,z as Vp,B as xN,E as hN}from"./radix-extra-DDK-u9dm.js";import{R as fN,T as pN,L as gN,g as jN,C as Mc,X as Dc,Y as Pr,h as vN,B as vu,j as Oc,P as bN,k as NN,l as yN}from"./charts-DbiuC1q1.js";import{S as wN,G as Qp,O as Ip,o as _N,C as Yp,p as SN,T as Kp,D as Xp,R as CN,q as kN,H as Jp,I as TN,J as Zp,K as Pp,L as EN,M as Wp,V as zN,N as eg,Q as sg,U as AN,X as MN,Y as tg,Z as DN,_ as ON,$ as ag,a0 as RN,e as LN,f as UN,c as lg,P as Xc,d as Fu,b as Du,h as BN,l as HN,m as qN,a1 as GN,a2 as ng,a3 as $N,a4 as FN,a5 as VN,a6 as rg,a7 as ig,a8 as cg,a9 as og,aa as dg,ab as ug,ac as QN}from"./radix-core-9dEfQl-6.js";import{R as zt,P as hi,C as aa,a as At,Z as an,b as $c,F as Sa,c as IN,S as ar,d as YN,M as Rl,A as KN,D as XN,e as Fc,f as Pn,T as JN,X as rl,g as ZN,h as PN,I as Ra,i as Ca,j as Qt,k as Vc,E as ci,l as Rt,m as mg,H as WN,n as We,o as Oa,U as oi,p as xg,q as hg,L as Jf,K as fg,r as pg,s as ey,t as Hc,u as it,v as sy,B as ti,w as Qc,x as Vu,y as ty,z as ay,G as Mt,J as Jc,N as er,O as dt,Q as Ll,V as di,W as Qu,Y as fi,_ as ly,$ as ny,a0 as ln,a1 as lr,a2 as il,a3 as Ba,a4 as nr,a5 as Iu,a6 as ry,a7 as iy,a8 as cy,a9 as Ol,aa as oy,ab as gg,ac as Ou,ad as nn,ae as dy,af as sr,ag as uy,ah as Ru,ai as Lu,aj as jg,ak as Zf,al as my,am as xy,an as hy,ao as nl,ap as bu,aq as Pf,ar as fy,as as vg,at as Nu,au as py,av as gy,aw as jy,ax as vy,ay as by,az as bg,aA as Ng,aB as yg,aC as wg,aD as Ny,aE as Wf,aF as yy,aG as wy,aH as _y,aI as Sy}from"./icons-CwAZotQh.js";import{S as Cy,p as ky,j as Ty,a as Ey,E as ep,R as zy,o as Ay}from"./codemirror-BEE0n9kQ.js";import{_ as Kt,c as My,g as _g,D as Dy,z as Rc}from"./misc-CKjrIrIJ.js";import{u as Oy,a as sp,D as Ry,c as Ly,S as Uy,h as By,b as Hy,s as qy,K as Gy,P as $y,d as Fy,C as Vy}from"./dnd-CHfCzWUK.js";import{D as Qy,U as Iy}from"./uppy-BMZiFQyG.js";import{M as Yy,r as Ky,a as Xy,b as Jy}from"./markdown-kUhwkcQP.js";import{c as Zy,H as Ic,P as Yc,u as Py,d as Wy,R as e0,B as s0,e as t0,C as a0,M as l0,f as n0}from"./reactflow-DLoXAt4c.js";(function(){const r=document.createElement("link").relList;if(r&&r.supports&&r.supports("modulepreload"))return;for(const m of document.querySelectorAll('link[rel="modulepreload"]'))d(m);new MutationObserver(m=>{for(const x of m)if(x.type==="childList")for(const f of x.addedNodes)f.tagName==="LINK"&&f.rel==="modulepreload"&&d(f)}).observe(document,{childList:!0,subtree:!0});function i(m){const x={};return m.integrity&&(x.integrity=m.integrity),m.referrerPolicy&&(x.referrerPolicy=m.referrerPolicy),m.crossOrigin==="use-credentials"?x.credentials="include":m.crossOrigin==="anonymous"?x.credentials="omit":x.credentials="same-origin",x}function d(m){if(m.ep)return;m.ep=!0;const x=i(m);fetch(m.href,x)}})();var yu={exports:{}},Wr={},wu={exports:{}},_u={};var tp;function r0(){return tp||(tp=1,(function(n){function r(D,J){var q=D.length;D.push(J);e:for(;0>>1,R=D[se];if(0>>1;sem(_e,q))Cem(ze,_e)?(D[se]=ze,D[Ce]=q,se=Ce):(D[se]=_e,D[me]=q,se=me);else if(Cem(ze,q))D[se]=ze,D[Ce]=q,se=Ce;else break e}}return J}function m(D,J){var q=D.sortIndex-J.sortIndex;return q!==0?q:D.id-J.id}if(n.unstable_now=void 0,typeof performance=="object"&&typeof performance.now=="function"){var x=performance;n.unstable_now=function(){return x.now()}}else{var f=Date,p=f.now();n.unstable_now=function(){return f.now()-p}}var g=[],b=[],j=1,y=null,N=3,k=!1,w=!1,U=!1,O=!1,B=typeof setTimeout=="function"?setTimeout:null,Y=typeof clearTimeout=="function"?clearTimeout:null,L=typeof setImmediate<"u"?setImmediate:null;function z(D){for(var J=i(b);J!==null;){if(J.callback===null)d(b);else if(J.startTime<=D)d(b),J.sortIndex=J.expirationTime,r(g,J);else break;J=i(b)}}function K(D){if(U=!1,z(D),!w)if(i(g)!==null)w=!0,I||(I=!0,pe());else{var J=i(b);J!==null&&be(K,J.startTime-D)}}var I=!1,T=-1,A=5,te=-1;function fe(){return O?!0:!(n.unstable_now()-teD&&fe());){var se=y.callback;if(typeof se=="function"){y.callback=null,N=y.priorityLevel;var R=se(y.expirationTime<=D);if(D=n.unstable_now(),typeof R=="function"){y.callback=R,z(D),J=!0;break s}y===i(g)&&d(g),z(D)}else d(g);y=i(g)}if(y!==null)J=!0;else{var ue=i(b);ue!==null&&be(K,ue.startTime-D),J=!1}}break e}finally{y=null,N=q,k=!1}J=void 0}}finally{J?pe():I=!1}}}var pe;if(typeof L=="function")pe=function(){L(je)};else if(typeof MessageChannel<"u"){var he=new MessageChannel,ve=he.port2;he.port1.onmessage=je,pe=function(){ve.postMessage(null)}}else pe=function(){B(je,0)};function be(D,J){T=B(function(){D(n.unstable_now())},J)}n.unstable_IdlePriority=5,n.unstable_ImmediatePriority=1,n.unstable_LowPriority=4,n.unstable_NormalPriority=3,n.unstable_Profiling=null,n.unstable_UserBlockingPriority=2,n.unstable_cancelCallback=function(D){D.callback=null},n.unstable_forceFrameRate=function(D){0>D||125se?(D.sortIndex=q,r(b,D),i(g)===null&&D===i(b)&&(U?(Y(T),T=-1):U=!0,be(K,q-se))):(D.sortIndex=R,r(g,D),w||k||(w=!0,I||(I=!0,pe()))),D},n.unstable_shouldYield=fe,n.unstable_wrapCallback=function(D){var J=N;return function(){var q=N;N=J;try{return D.apply(this,arguments)}finally{N=q}}}})(_u)),_u}var ap;function i0(){return ap||(ap=1,wu.exports=r0()),wu.exports}var lp;function c0(){if(lp)return Wr;lp=1;var n=i0(),r=Vb(),i=Qb();function d(s){var t="https://react.dev/errors/"+s;if(1R||(s.current=se[R],se[R]=null,R--)}function _e(s,t){R++,se[R]=s.current,s.current=t}var Ce=ue(null),ze=ue(null),ge=ue(null),ae=ue(null);function re(s,t){switch(_e(ge,t),_e(ze,s),_e(Ce,null),t.nodeType){case 9:case 11:s=(s=t.documentElement)&&(s=s.namespaceURI)?vf(s):0;break;default:if(s=t.tagName,t=t.namespaceURI)t=vf(t),s=bf(t,s);else switch(s){case"svg":s=1;break;case"math":s=2;break;default:s=0}}me(Ce),_e(Ce,s)}function F(){me(Ce),me(ze),me(ge)}function P(s){s.memoizedState!==null&&_e(ae,s);var t=Ce.current,a=bf(t,s.type);t!==a&&(_e(ze,s),_e(Ce,a))}function Te(s){ze.current===s&&(me(Ce),me(ze)),ae.current===s&&(me(ae),Kr._currentValue=q)}var Le,E;function xe(s){if(Le===void 0)try{throw Error()}catch(a){var t=a.stack.trim().match(/\n( *(at )?)/);Le=t&&t[1]||"",E=-1)":-1c||M[l]!==W[c]){var ce=` -`+M[l].replace(" at new "," at ");return s.displayName&&ce.includes("")&&(ce=ce.replace("",s.displayName)),ce}while(1<=l&&0<=c);break}}}finally{Ye=!1,Error.prepareStackTrace=a}return(a=s?s.displayName||s.name:"")?xe(a):""}function Q(s,t){switch(s.tag){case 26:case 27:case 5:return xe(s.type);case 16:return xe("Lazy");case 13:return s.child!==t&&t!==null?xe("Suspense Fallback"):xe("Suspense");case 19:return xe("SuspenseList");case 0:case 15:return ke(s.type,!1);case 11:return ke(s.type.render,!1);case 1:return ke(s.type,!0);case 31:return xe("Activity");default:return""}}function Ne(s){try{var t="",a=null;do t+=Q(s,a),a=s,s=s.return;while(s);return t}catch(l){return` -Error generating stack: `+l.message+` -`+l.stack}}var qe=Object.prototype.hasOwnProperty,Fs=n.unstable_scheduleCallback,ks=n.unstable_cancelCallback,xt=n.unstable_shouldYield,js=n.unstable_requestPaint,Vs=n.unstable_now,X=n.unstable_getCurrentPriorityLevel,He=n.unstable_ImmediatePriority,De=n.unstable_UserBlockingPriority,Ke=n.unstable_NormalPriority,Ns=n.unstable_LowPriority,Je=n.unstable_IdlePriority,Ks=n.log,ye=n.unstable_setDisableYieldValue,_s=null,Ae=null;function vs(s){if(typeof Ks=="function"&&ye(s),Ae&&typeof Ae.setStrictMode=="function")try{Ae.setStrictMode(_s,s)}catch{}}var bs=Math.clz32?Math.clz32:Ss,Nt=Math.log,Xs=Math.LN2;function Ss(s){return s>>>=0,s===0?32:31-(Nt(s)/Xs|0)|0}var Es=256,Js=262144,Ha=4194304;function Lt(s){var t=s&42;if(t!==0)return t;switch(s&-s){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:return 64;case 128:return 128;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:return s&261888;case 262144:case 524288:case 1048576:case 2097152:return s&3932160;case 4194304:case 8388608:case 16777216:case 33554432:return s&62914560;case 67108864:return 67108864;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 0;default:return s}}function ol(s,t,a){var l=s.pendingLanes;if(l===0)return 0;var c=0,o=s.suspendedLanes,h=s.pingedLanes;s=s.warmLanes;var v=l&134217727;return v!==0?(l=v&~o,l!==0?c=Lt(l):(h&=v,h!==0?c=Lt(h):a||(a=v&~s,a!==0&&(c=Lt(a))))):(v=l&~o,v!==0?c=Lt(v):h!==0?c=Lt(h):a||(a=l&~s,a!==0&&(c=Lt(a)))),c===0?0:t!==0&&t!==c&&(t&o)===0&&(o=c&-c,a=t&-t,o>=a||o===32&&(a&4194048)!==0)?t:c}function ba(s,t){return(s.pendingLanes&~(s.suspendedLanes&~s.pingedLanes)&t)===0}function _(s,t){switch(s){case 1:case 2:case 4:case 8:case 64:return t+250;case 16:case 32:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return t+5e3;case 4194304:case 8388608:case 16777216:case 33554432:return-1;case 67108864:case 134217728:case 268435456:case 536870912:case 1073741824:return-1;default:return-1}}function G(){var s=Ha;return Ha<<=1,(Ha&62914560)===0&&(Ha=4194304),s}function we(s){for(var t=[],a=0;31>a;a++)t.push(s);return t}function Ms(s,t){s.pendingLanes|=t,t!==268435456&&(s.suspendedLanes=0,s.pingedLanes=0,s.warmLanes=0)}function Dt(s,t,a,l,c,o){var h=s.pendingLanes;s.pendingLanes=a,s.suspendedLanes=0,s.pingedLanes=0,s.warmLanes=0,s.expiredLanes&=a,s.entangledLanes&=a,s.errorRecoveryDisabledLanes&=a,s.shellSuspendCounter=0;var v=s.entanglements,M=s.expirationTimes,W=s.hiddenUpdates;for(a=h&~a;0"u")return null;try{return s.activeElement||s.body}catch{return s.body}}var Aj=/[\n"\\]/g;function ra(s){return s.replace(Aj,function(t){return"\\"+t.charCodeAt(0).toString(16)+" "})}function mo(s,t,a,l,c,o,h,v){s.name="",h!=null&&typeof h!="function"&&typeof h!="symbol"&&typeof h!="boolean"?s.type=h:s.removeAttribute("type"),t!=null?h==="number"?(t===0&&s.value===""||s.value!=t)&&(s.value=""+na(t)):s.value!==""+na(t)&&(s.value=""+na(t)):h!=="submit"&&h!=="reset"||s.removeAttribute("value"),t!=null?xo(s,h,na(t)):a!=null?xo(s,h,na(a)):l!=null&&s.removeAttribute("value"),c==null&&o!=null&&(s.defaultChecked=!!o),c!=null&&(s.checked=c&&typeof c!="function"&&typeof c!="symbol"),v!=null&&typeof v!="function"&&typeof v!="symbol"&&typeof v!="boolean"?s.name=""+na(v):s.removeAttribute("name")}function mm(s,t,a,l,c,o,h,v){if(o!=null&&typeof o!="function"&&typeof o!="symbol"&&typeof o!="boolean"&&(s.type=o),t!=null||a!=null){if(!(o!=="submit"&&o!=="reset"||t!=null)){uo(s);return}a=a!=null?""+na(a):"",t=t!=null?""+na(t):a,v||t===s.value||(s.value=t),s.defaultValue=t}l=l??c,l=typeof l!="function"&&typeof l!="symbol"&&!!l,s.checked=v?s.checked:!!l,s.defaultChecked=!!l,h!=null&&typeof h!="function"&&typeof h!="symbol"&&typeof h!="boolean"&&(s.name=h),uo(s)}function xo(s,t,a){t==="number"&&Ni(s.ownerDocument)===s||s.defaultValue===""+a||(s.defaultValue=""+a)}function fn(s,t,a,l){if(s=s.options,t){t={};for(var c=0;c"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),jo=!1;if($a)try{var mr={};Object.defineProperty(mr,"passive",{get:function(){jo=!0}}),window.addEventListener("test",mr,mr),window.removeEventListener("test",mr,mr)}catch{jo=!1}var ul=null,vo=null,wi=null;function vm(){if(wi)return wi;var s,t=vo,a=t.length,l,c="value"in ul?ul.value:ul.textContent,o=c.length;for(s=0;s=fr),Sm=" ",Cm=!1;function km(s,t){switch(s){case"keyup":return nv.indexOf(t.keyCode)!==-1;case"keydown":return t.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function Tm(s){return s=s.detail,typeof s=="object"&&"data"in s?s.data:null}var vn=!1;function iv(s,t){switch(s){case"compositionend":return Tm(t);case"keypress":return t.which!==32?null:(Cm=!0,Sm);case"textInput":return s=t.data,s===Sm&&Cm?null:s;default:return null}}function cv(s,t){if(vn)return s==="compositionend"||!_o&&km(s,t)?(s=vm(),wi=vo=ul=null,vn=!1,s):null;switch(s){case"paste":return null;case"keypress":if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1=t)return{node:a,offset:t-s};s=l}e:{for(;a;){if(a.nextSibling){a=a.nextSibling;break e}a=a.parentNode}a=void 0}a=Lm(a)}}function Bm(s,t){return s&&t?s===t?!0:s&&s.nodeType===3?!1:t&&t.nodeType===3?Bm(s,t.parentNode):"contains"in s?s.contains(t):s.compareDocumentPosition?!!(s.compareDocumentPosition(t)&16):!1:!1}function Hm(s){s=s!=null&&s.ownerDocument!=null&&s.ownerDocument.defaultView!=null?s.ownerDocument.defaultView:window;for(var t=Ni(s.document);t instanceof s.HTMLIFrameElement;){try{var a=typeof t.contentWindow.location.href=="string"}catch{a=!1}if(a)s=t.contentWindow;else break;t=Ni(s.document)}return t}function ko(s){var t=s&&s.nodeName&&s.nodeName.toLowerCase();return t&&(t==="input"&&(s.type==="text"||s.type==="search"||s.type==="tel"||s.type==="url"||s.type==="password")||t==="textarea"||s.contentEditable==="true")}var pv=$a&&"documentMode"in document&&11>=document.documentMode,bn=null,To=null,vr=null,Eo=!1;function qm(s,t,a){var l=a.window===a?a.document:a.nodeType===9?a:a.ownerDocument;Eo||bn==null||bn!==Ni(l)||(l=bn,"selectionStart"in l&&ko(l)?l={start:l.selectionStart,end:l.selectionEnd}:(l=(l.ownerDocument&&l.ownerDocument.defaultView||window).getSelection(),l={anchorNode:l.anchorNode,anchorOffset:l.anchorOffset,focusNode:l.focusNode,focusOffset:l.focusOffset}),vr&&jr(vr,l)||(vr=l,l=pc(To,"onSelect"),0>=h,c-=h,Ta=1<<32-bs(t)+c|a<es?(ps=Me,Me=null):ps=Me.sibling;var ws=ee(V,Me,Z[es],oe);if(ws===null){Me===null&&(Me=ps);break}s&&Me&&ws.alternate===null&&t(V,Me),H=o(ws,H,es),ys===null?Ge=ws:ys.sibling=ws,ys=ws,Me=ps}if(es===Z.length)return a(V,Me),gs&&Va(V,es),Ge;if(Me===null){for(;eses?(ps=Me,Me=null):ps=Me.sibling;var Dl=ee(V,Me,ws.value,oe);if(Dl===null){Me===null&&(Me=ps);break}s&&Me&&Dl.alternate===null&&t(V,Me),H=o(Dl,H,es),ys===null?Ge=Dl:ys.sibling=Dl,ys=Dl,Me=ps}if(ws.done)return a(V,Me),gs&&Va(V,es),Ge;if(Me===null){for(;!ws.done;es++,ws=Z.next())ws=de(V,ws.value,oe),ws!==null&&(H=o(ws,H,es),ys===null?Ge=ws:ys.sibling=ws,ys=ws);return gs&&Va(V,es),Ge}for(Me=l(Me);!ws.done;es++,ws=Z.next())ws=ne(Me,V,es,ws.value,oe),ws!==null&&(s&&ws.alternate!==null&&Me.delete(ws.key===null?es:ws.key),H=o(ws,H,es),ys===null?Ge=ws:ys.sibling=ws,ys=ws);return s&&Me.forEach(function(Lb){return t(V,Lb)}),gs&&Va(V,es),Ge}function Rs(V,H,Z,oe){if(typeof Z=="object"&&Z!==null&&Z.type===U&&Z.key===null&&(Z=Z.props.children),typeof Z=="object"&&Z!==null){switch(Z.$$typeof){case k:e:{for(var Ge=Z.key;H!==null;){if(H.key===Ge){if(Ge=Z.type,Ge===U){if(H.tag===7){a(V,H.sibling),oe=c(H,Z.props.children),oe.return=V,V=oe;break e}}else if(H.elementType===Ge||typeof Ge=="object"&&Ge!==null&&Ge.$$typeof===A&&Xl(Ge)===H.type){a(V,H.sibling),oe=c(H,Z.props),Sr(oe,Z),oe.return=V,V=oe;break e}a(V,H);break}else t(V,H);H=H.sibling}Z.type===U?(oe=Vl(Z.props.children,V.mode,oe,Z.key),oe.return=V,V=oe):(oe=Di(Z.type,Z.key,Z.props,null,V.mode,oe),Sr(oe,Z),oe.return=V,V=oe)}return h(V);case w:e:{for(Ge=Z.key;H!==null;){if(H.key===Ge)if(H.tag===4&&H.stateNode.containerInfo===Z.containerInfo&&H.stateNode.implementation===Z.implementation){a(V,H.sibling),oe=c(H,Z.children||[]),oe.return=V,V=oe;break e}else{a(V,H);break}else t(V,H);H=H.sibling}oe=Lo(Z,V.mode,oe),oe.return=V,V=oe}return h(V);case A:return Z=Xl(Z),Rs(V,H,Z,oe)}if(be(Z))return Ee(V,H,Z,oe);if(pe(Z)){if(Ge=pe(Z),typeof Ge!="function")throw Error(d(150));return Z=Ge.call(Z),Ie(V,H,Z,oe)}if(typeof Z.then=="function")return Rs(V,H,qi(Z),oe);if(Z.$$typeof===L)return Rs(V,H,Li(V,Z),oe);Gi(V,Z)}return typeof Z=="string"&&Z!==""||typeof Z=="number"||typeof Z=="bigint"?(Z=""+Z,H!==null&&H.tag===6?(a(V,H.sibling),oe=c(H,Z),oe.return=V,V=oe):(a(V,H),oe=Ro(Z,V.mode,oe),oe.return=V,V=oe),h(V)):a(V,H)}return function(V,H,Z,oe){try{_r=0;var Ge=Rs(V,H,Z,oe);return An=null,Ge}catch(Me){if(Me===zn||Me===Bi)throw Me;var ys=Jt(29,Me,null,V.mode);return ys.lanes=oe,ys.return=V,ys}finally{}}}var Zl=ox(!0),dx=ox(!1),pl=!1;function Ko(s){s.updateQueue={baseState:s.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,lanes:0,hiddenCallbacks:null},callbacks:null}}function Xo(s,t){s=s.updateQueue,t.updateQueue===s&&(t.updateQueue={baseState:s.baseState,firstBaseUpdate:s.firstBaseUpdate,lastBaseUpdate:s.lastBaseUpdate,shared:s.shared,callbacks:null})}function gl(s){return{lane:s,tag:0,payload:null,callback:null,next:null}}function jl(s,t,a){var l=s.updateQueue;if(l===null)return null;if(l=l.shared,(Cs&2)!==0){var c=l.pending;return c===null?t.next=t:(t.next=c.next,c.next=t),l.pending=t,t=Mi(s),Ym(s,null,a),t}return Ai(s,l,t,a),Mi(s)}function Cr(s,t,a){if(t=t.updateQueue,t!==null&&(t=t.shared,(a&4194048)!==0)){var l=t.lanes;l&=s.pendingLanes,a|=l,t.lanes=a,cr(s,a)}}function Jo(s,t){var a=s.updateQueue,l=s.alternate;if(l!==null&&(l=l.updateQueue,a===l)){var c=null,o=null;if(a=a.firstBaseUpdate,a!==null){do{var h={lane:a.lane,tag:a.tag,payload:a.payload,callback:null,next:null};o===null?c=o=h:o=o.next=h,a=a.next}while(a!==null);o===null?c=o=t:o=o.next=t}else c=o=t;a={baseState:l.baseState,firstBaseUpdate:c,lastBaseUpdate:o,shared:l.shared,callbacks:l.callbacks},s.updateQueue=a;return}s=a.lastBaseUpdate,s===null?a.firstBaseUpdate=t:s.next=t,a.lastBaseUpdate=t}var Zo=!1;function kr(){if(Zo){var s=En;if(s!==null)throw s}}function Tr(s,t,a,l){Zo=!1;var c=s.updateQueue;pl=!1;var o=c.firstBaseUpdate,h=c.lastBaseUpdate,v=c.shared.pending;if(v!==null){c.shared.pending=null;var M=v,W=M.next;M.next=null,h===null?o=W:h.next=W,h=M;var ce=s.alternate;ce!==null&&(ce=ce.updateQueue,v=ce.lastBaseUpdate,v!==h&&(v===null?ce.firstBaseUpdate=W:v.next=W,ce.lastBaseUpdate=M))}if(o!==null){var de=c.baseState;h=0,ce=W=M=null,v=o;do{var ee=v.lane&-536870913,ne=ee!==v.lane;if(ne?(fs&ee)===ee:(l&ee)===ee){ee!==0&&ee===Tn&&(Zo=!0),ce!==null&&(ce=ce.next={lane:0,tag:v.tag,payload:v.payload,callback:null,next:null});e:{var Ee=s,Ie=v;ee=t;var Rs=a;switch(Ie.tag){case 1:if(Ee=Ie.payload,typeof Ee=="function"){de=Ee.call(Rs,de,ee);break e}de=Ee;break e;case 3:Ee.flags=Ee.flags&-65537|128;case 0:if(Ee=Ie.payload,ee=typeof Ee=="function"?Ee.call(Rs,de,ee):Ee,ee==null)break e;de=y({},de,ee);break e;case 2:pl=!0}}ee=v.callback,ee!==null&&(s.flags|=64,ne&&(s.flags|=8192),ne=c.callbacks,ne===null?c.callbacks=[ee]:ne.push(ee))}else ne={lane:ee,tag:v.tag,payload:v.payload,callback:v.callback,next:null},ce===null?(W=ce=ne,M=de):ce=ce.next=ne,h|=ee;if(v=v.next,v===null){if(v=c.shared.pending,v===null)break;ne=v,v=ne.next,ne.next=null,c.lastBaseUpdate=ne,c.shared.pending=null}}while(!0);ce===null&&(M=de),c.baseState=M,c.firstBaseUpdate=W,c.lastBaseUpdate=ce,o===null&&(c.shared.lanes=0),wl|=h,s.lanes=h,s.memoizedState=de}}function ux(s,t){if(typeof s!="function")throw Error(d(191,s));s.call(t)}function mx(s,t){var a=s.callbacks;if(a!==null)for(s.callbacks=null,s=0;so?o:8;var h=D.T,v={};D.T=v,pd(s,!1,t,a);try{var M=c(),W=D.S;if(W!==null&&W(v,M),M!==null&&typeof M=="object"&&typeof M.then=="function"){var ce=Sv(M,l);Ar(s,t,ce,sa(s))}else Ar(s,t,l,sa(s))}catch(de){Ar(s,t,{then:function(){},status:"rejected",reason:de},sa())}finally{J.p=o,h!==null&&v.types!==null&&(h.types=v.types),D.T=h}}function Av(){}function hd(s,t,a,l){if(s.tag!==5)throw Error(d(476));var c=Vx(s).queue;Fx(s,c,t,q,a===null?Av:function(){return Qx(s),a(l)})}function Vx(s){var t=s.memoizedState;if(t!==null)return t;t={memoizedState:q,baseState:q,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:Ka,lastRenderedState:q},next:null};var a={};return t.next={memoizedState:a,baseState:a,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:Ka,lastRenderedState:a},next:null},s.memoizedState=t,s=s.alternate,s!==null&&(s.memoizedState=t),t}function Qx(s){var t=Vx(s);t.next===null&&(t=s.alternate.memoizedState),Ar(s,t.next.queue,{},sa())}function fd(){return Ct(Kr)}function Ix(){return ot().memoizedState}function Yx(){return ot().memoizedState}function Mv(s){for(var t=s.return;t!==null;){switch(t.tag){case 24:case 3:var a=sa();s=gl(a);var l=jl(t,s,a);l!==null&&(Ft(l,t,a),Cr(l,t,a)),t={cache:Vo()},s.payload=t;return}t=t.return}}function Dv(s,t,a){var l=sa();a={lane:l,revertLane:0,gesture:null,action:a,hasEagerState:!1,eagerState:null,next:null},Zi(s)?Xx(t,a):(a=Do(s,t,a,l),a!==null&&(Ft(a,s,l),Jx(a,t,l)))}function Kx(s,t,a){var l=sa();Ar(s,t,a,l)}function Ar(s,t,a,l){var c={lane:l,revertLane:0,gesture:null,action:a,hasEagerState:!1,eagerState:null,next:null};if(Zi(s))Xx(t,c);else{var o=s.alternate;if(s.lanes===0&&(o===null||o.lanes===0)&&(o=t.lastRenderedReducer,o!==null))try{var h=t.lastRenderedState,v=o(h,a);if(c.hasEagerState=!0,c.eagerState=v,Xt(v,h))return Ai(s,t,c,0),Hs===null&&zi(),!1}catch{}finally{}if(a=Do(s,t,c,l),a!==null)return Ft(a,s,l),Jx(a,t,l),!0}return!1}function pd(s,t,a,l){if(l={lane:2,revertLane:Kd(),gesture:null,action:l,hasEagerState:!1,eagerState:null,next:null},Zi(s)){if(t)throw Error(d(479))}else t=Do(s,a,l,2),t!==null&&Ft(t,s,2)}function Zi(s){var t=s.alternate;return s===Pe||t!==null&&t===Pe}function Xx(s,t){Dn=Vi=!0;var a=s.pending;a===null?t.next=t:(t.next=a.next,a.next=t),s.pending=t}function Jx(s,t,a){if((a&4194048)!==0){var l=t.lanes;l&=s.pendingLanes,a|=l,t.lanes=a,cr(s,a)}}var Mr={readContext:Ct,use:Yi,useCallback:at,useContext:at,useEffect:at,useImperativeHandle:at,useLayoutEffect:at,useInsertionEffect:at,useMemo:at,useReducer:at,useRef:at,useState:at,useDebugValue:at,useDeferredValue:at,useTransition:at,useSyncExternalStore:at,useId:at,useHostTransitionStatus:at,useFormState:at,useActionState:at,useOptimistic:at,useMemoCache:at,useCacheRefresh:at};Mr.useEffectEvent=at;var Zx={readContext:Ct,use:Yi,useCallback:function(s,t){return Ot().memoizedState=[s,t===void 0?null:t],s},useContext:Ct,useEffect:Ox,useImperativeHandle:function(s,t,a){a=a!=null?a.concat([s]):null,Xi(4194308,4,Bx.bind(null,t,s),a)},useLayoutEffect:function(s,t){return Xi(4194308,4,s,t)},useInsertionEffect:function(s,t){Xi(4,2,s,t)},useMemo:function(s,t){var a=Ot();t=t===void 0?null:t;var l=s();if(Pl){vs(!0);try{s()}finally{vs(!1)}}return a.memoizedState=[l,t],l},useReducer:function(s,t,a){var l=Ot();if(a!==void 0){var c=a(t);if(Pl){vs(!0);try{a(t)}finally{vs(!1)}}}else c=t;return l.memoizedState=l.baseState=c,s={pending:null,lanes:0,dispatch:null,lastRenderedReducer:s,lastRenderedState:c},l.queue=s,s=s.dispatch=Dv.bind(null,Pe,s),[l.memoizedState,s]},useRef:function(s){var t=Ot();return s={current:s},t.memoizedState=s},useState:function(s){s=od(s);var t=s.queue,a=Kx.bind(null,Pe,t);return t.dispatch=a,[s.memoizedState,a]},useDebugValue:md,useDeferredValue:function(s,t){var a=Ot();return xd(a,s,t)},useTransition:function(){var s=od(!1);return s=Fx.bind(null,Pe,s.queue,!0,!1),Ot().memoizedState=s,[!1,s]},useSyncExternalStore:function(s,t,a){var l=Pe,c=Ot();if(gs){if(a===void 0)throw Error(d(407));a=a()}else{if(a=t(),Hs===null)throw Error(d(349));(fs&127)!==0||jx(l,t,a)}c.memoizedState=a;var o={value:a,getSnapshot:t};return c.queue=o,Ox(bx.bind(null,l,o,s),[s]),l.flags|=2048,Rn(9,{destroy:void 0},vx.bind(null,l,o,a,t),null),a},useId:function(){var s=Ot(),t=Hs.identifierPrefix;if(gs){var a=Ea,l=Ta;a=(l&~(1<<32-bs(l)-1)).toString(32)+a,t="_"+t+"R_"+a,a=Qi++,0<\/script>",o=o.removeChild(o.firstChild);break;case"select":o=typeof l.is=="string"?h.createElement("select",{is:l.is}):h.createElement("select"),l.multiple?o.multiple=!0:l.size&&(o.size=l.size);break;default:o=typeof l.is=="string"?h.createElement(c,{is:l.is}):h.createElement(c)}}o[_t]=t,o[Ut]=l;e:for(h=t.child;h!==null;){if(h.tag===5||h.tag===6)o.appendChild(h.stateNode);else if(h.tag!==4&&h.tag!==27&&h.child!==null){h.child.return=h,h=h.child;continue}if(h===t)break e;for(;h.sibling===null;){if(h.return===null||h.return===t)break e;h=h.return}h.sibling.return=h.return,h=h.sibling}t.stateNode=o;e:switch(Tt(o,c,l),c){case"button":case"input":case"select":case"textarea":l=!!l.autoFocus;break e;case"img":l=!0;break e;default:l=!1}l&&Ja(t)}}return Ys(t),zd(t,t.type,s===null?null:s.memoizedProps,t.pendingProps,a),null;case 6:if(s&&t.stateNode!=null)s.memoizedProps!==l&&Ja(t);else{if(typeof l!="string"&&t.stateNode===null)throw Error(d(166));if(s=ge.current,Cn(t)){if(s=t.stateNode,a=t.memoizedProps,l=null,c=St,c!==null)switch(c.tag){case 27:case 5:l=c.memoizedProps}s[_t]=t,s=!!(s.nodeValue===a||l!==null&&l.suppressHydrationWarning===!0||gf(s.nodeValue,a)),s||hl(t,!0)}else s=gc(s).createTextNode(l),s[_t]=t,t.stateNode=s}return Ys(t),null;case 31:if(a=t.memoizedState,s===null||s.memoizedState!==null){if(l=Cn(t),a!==null){if(s===null){if(!l)throw Error(d(318));if(s=t.memoizedState,s=s!==null?s.dehydrated:null,!s)throw Error(d(557));s[_t]=t}else Ql(),(t.flags&128)===0&&(t.memoizedState=null),t.flags|=4;Ys(t),s=!1}else a=qo(),s!==null&&s.memoizedState!==null&&(s.memoizedState.hydrationErrors=a),s=!0;if(!s)return t.flags&256?(Pt(t),t):(Pt(t),null);if((t.flags&128)!==0)throw Error(d(558))}return Ys(t),null;case 13:if(l=t.memoizedState,s===null||s.memoizedState!==null&&s.memoizedState.dehydrated!==null){if(c=Cn(t),l!==null&&l.dehydrated!==null){if(s===null){if(!c)throw Error(d(318));if(c=t.memoizedState,c=c!==null?c.dehydrated:null,!c)throw Error(d(317));c[_t]=t}else Ql(),(t.flags&128)===0&&(t.memoizedState=null),t.flags|=4;Ys(t),c=!1}else c=qo(),s!==null&&s.memoizedState!==null&&(s.memoizedState.hydrationErrors=c),c=!0;if(!c)return t.flags&256?(Pt(t),t):(Pt(t),null)}return Pt(t),(t.flags&128)!==0?(t.lanes=a,t):(a=l!==null,s=s!==null&&s.memoizedState!==null,a&&(l=t.child,c=null,l.alternate!==null&&l.alternate.memoizedState!==null&&l.alternate.memoizedState.cachePool!==null&&(c=l.alternate.memoizedState.cachePool.pool),o=null,l.memoizedState!==null&&l.memoizedState.cachePool!==null&&(o=l.memoizedState.cachePool.pool),o!==c&&(l.flags|=2048)),a!==s&&a&&(t.child.flags|=8192),tc(t,t.updateQueue),Ys(t),null);case 4:return F(),s===null&&Pd(t.stateNode.containerInfo),Ys(t),null;case 10:return Ia(t.type),Ys(t),null;case 19:if(me(ct),l=t.memoizedState,l===null)return Ys(t),null;if(c=(t.flags&128)!==0,o=l.rendering,o===null)if(c)Or(l,!1);else{if(lt!==0||s!==null&&(s.flags&128)!==0)for(s=t.child;s!==null;){if(o=Fi(s),o!==null){for(t.flags|=128,Or(l,!1),s=o.updateQueue,t.updateQueue=s,tc(t,s),t.subtreeFlags=0,s=a,a=t.child;a!==null;)Km(a,s),a=a.sibling;return _e(ct,ct.current&1|2),gs&&Va(t,l.treeForkCount),t.child}s=s.sibling}l.tail!==null&&Vs()>ic&&(t.flags|=128,c=!0,Or(l,!1),t.lanes=4194304)}else{if(!c)if(s=Fi(o),s!==null){if(t.flags|=128,c=!0,s=s.updateQueue,t.updateQueue=s,tc(t,s),Or(l,!0),l.tail===null&&l.tailMode==="hidden"&&!o.alternate&&!gs)return Ys(t),null}else 2*Vs()-l.renderingStartTime>ic&&a!==536870912&&(t.flags|=128,c=!0,Or(l,!1),t.lanes=4194304);l.isBackwards?(o.sibling=t.child,t.child=o):(s=l.last,s!==null?s.sibling=o:t.child=o,l.last=o)}return l.tail!==null?(s=l.tail,l.rendering=s,l.tail=s.sibling,l.renderingStartTime=Vs(),s.sibling=null,a=ct.current,_e(ct,c?a&1|2:a&1),gs&&Va(t,l.treeForkCount),s):(Ys(t),null);case 22:case 23:return Pt(t),Wo(),l=t.memoizedState!==null,s!==null?s.memoizedState!==null!==l&&(t.flags|=8192):l&&(t.flags|=8192),l?(a&536870912)!==0&&(t.flags&128)===0&&(Ys(t),t.subtreeFlags&6&&(t.flags|=8192)):Ys(t),a=t.updateQueue,a!==null&&tc(t,a.retryQueue),a=null,s!==null&&s.memoizedState!==null&&s.memoizedState.cachePool!==null&&(a=s.memoizedState.cachePool.pool),l=null,t.memoizedState!==null&&t.memoizedState.cachePool!==null&&(l=t.memoizedState.cachePool.pool),l!==a&&(t.flags|=2048),s!==null&&me(Kl),null;case 24:return a=null,s!==null&&(a=s.memoizedState.cache),t.memoizedState.cache!==a&&(t.flags|=2048),Ia(ht),Ys(t),null;case 25:return null;case 30:return null}throw Error(d(156,t.tag))}function Bv(s,t){switch(Bo(t),t.tag){case 1:return s=t.flags,s&65536?(t.flags=s&-65537|128,t):null;case 3:return Ia(ht),F(),s=t.flags,(s&65536)!==0&&(s&128)===0?(t.flags=s&-65537|128,t):null;case 26:case 27:case 5:return Te(t),null;case 31:if(t.memoizedState!==null){if(Pt(t),t.alternate===null)throw Error(d(340));Ql()}return s=t.flags,s&65536?(t.flags=s&-65537|128,t):null;case 13:if(Pt(t),s=t.memoizedState,s!==null&&s.dehydrated!==null){if(t.alternate===null)throw Error(d(340));Ql()}return s=t.flags,s&65536?(t.flags=s&-65537|128,t):null;case 19:return me(ct),null;case 4:return F(),null;case 10:return Ia(t.type),null;case 22:case 23:return Pt(t),Wo(),s!==null&&me(Kl),s=t.flags,s&65536?(t.flags=s&-65537|128,t):null;case 24:return Ia(ht),null;case 25:return null;default:return null}}function Nh(s,t){switch(Bo(t),t.tag){case 3:Ia(ht),F();break;case 26:case 27:case 5:Te(t);break;case 4:F();break;case 31:t.memoizedState!==null&&Pt(t);break;case 13:Pt(t);break;case 19:me(ct);break;case 10:Ia(t.type);break;case 22:case 23:Pt(t),Wo(),s!==null&&me(Kl);break;case 24:Ia(ht)}}function Rr(s,t){try{var a=t.updateQueue,l=a!==null?a.lastEffect:null;if(l!==null){var c=l.next;a=c;do{if((a.tag&s)===s){l=void 0;var o=a.create,h=a.inst;l=o(),h.destroy=l}a=a.next}while(a!==c)}}catch(v){As(t,t.return,v)}}function Nl(s,t,a){try{var l=t.updateQueue,c=l!==null?l.lastEffect:null;if(c!==null){var o=c.next;l=o;do{if((l.tag&s)===s){var h=l.inst,v=h.destroy;if(v!==void 0){h.destroy=void 0,c=t;var M=a,W=v;try{W()}catch(ce){As(c,M,ce)}}}l=l.next}while(l!==o)}}catch(ce){As(t,t.return,ce)}}function yh(s){var t=s.updateQueue;if(t!==null){var a=s.stateNode;try{mx(t,a)}catch(l){As(s,s.return,l)}}}function wh(s,t,a){a.props=Wl(s.type,s.memoizedProps),a.state=s.memoizedState;try{a.componentWillUnmount()}catch(l){As(s,t,l)}}function Lr(s,t){try{var a=s.ref;if(a!==null){switch(s.tag){case 26:case 27:case 5:var l=s.stateNode;break;case 30:l=s.stateNode;break;default:l=s.stateNode}typeof a=="function"?s.refCleanup=a(l):a.current=l}}catch(c){As(s,t,c)}}function za(s,t){var a=s.ref,l=s.refCleanup;if(a!==null)if(typeof l=="function")try{l()}catch(c){As(s,t,c)}finally{s.refCleanup=null,s=s.alternate,s!=null&&(s.refCleanup=null)}else if(typeof a=="function")try{a(null)}catch(c){As(s,t,c)}else a.current=null}function _h(s){var t=s.type,a=s.memoizedProps,l=s.stateNode;try{e:switch(t){case"button":case"input":case"select":case"textarea":a.autoFocus&&l.focus();break e;case"img":a.src?l.src=a.src:a.srcSet&&(l.srcset=a.srcSet)}}catch(c){As(s,s.return,c)}}function Ad(s,t,a){try{var l=s.stateNode;rb(l,s.type,a,t),l[Ut]=t}catch(c){As(s,s.return,c)}}function Sh(s){return s.tag===5||s.tag===3||s.tag===26||s.tag===27&&Tl(s.type)||s.tag===4}function Md(s){e:for(;;){for(;s.sibling===null;){if(s.return===null||Sh(s.return))return null;s=s.return}for(s.sibling.return=s.return,s=s.sibling;s.tag!==5&&s.tag!==6&&s.tag!==18;){if(s.tag===27&&Tl(s.type)||s.flags&2||s.child===null||s.tag===4)continue e;s.child.return=s,s=s.child}if(!(s.flags&2))return s.stateNode}}function Dd(s,t,a){var l=s.tag;if(l===5||l===6)s=s.stateNode,t?(a.nodeType===9?a.body:a.nodeName==="HTML"?a.ownerDocument.body:a).insertBefore(s,t):(t=a.nodeType===9?a.body:a.nodeName==="HTML"?a.ownerDocument.body:a,t.appendChild(s),a=a._reactRootContainer,a!=null||t.onclick!==null||(t.onclick=Ga));else if(l!==4&&(l===27&&Tl(s.type)&&(a=s.stateNode,t=null),s=s.child,s!==null))for(Dd(s,t,a),s=s.sibling;s!==null;)Dd(s,t,a),s=s.sibling}function ac(s,t,a){var l=s.tag;if(l===5||l===6)s=s.stateNode,t?a.insertBefore(s,t):a.appendChild(s);else if(l!==4&&(l===27&&Tl(s.type)&&(a=s.stateNode),s=s.child,s!==null))for(ac(s,t,a),s=s.sibling;s!==null;)ac(s,t,a),s=s.sibling}function Ch(s){var t=s.stateNode,a=s.memoizedProps;try{for(var l=s.type,c=t.attributes;c.length;)t.removeAttributeNode(c[0]);Tt(t,l,a),t[_t]=s,t[Ut]=a}catch(o){As(s,s.return,o)}}var Za=!1,gt=!1,Od=!1,kh=typeof WeakSet=="function"?WeakSet:Set,wt=null;function Hv(s,t){if(s=s.containerInfo,su=_c,s=Hm(s),ko(s)){if("selectionStart"in s)var a={start:s.selectionStart,end:s.selectionEnd};else e:{a=(a=s.ownerDocument)&&a.defaultView||window;var l=a.getSelection&&a.getSelection();if(l&&l.rangeCount!==0){a=l.anchorNode;var c=l.anchorOffset,o=l.focusNode;l=l.focusOffset;try{a.nodeType,o.nodeType}catch{a=null;break e}var h=0,v=-1,M=-1,W=0,ce=0,de=s,ee=null;s:for(;;){for(var ne;de!==a||c!==0&&de.nodeType!==3||(v=h+c),de!==o||l!==0&&de.nodeType!==3||(M=h+l),de.nodeType===3&&(h+=de.nodeValue.length),(ne=de.firstChild)!==null;)ee=de,de=ne;for(;;){if(de===s)break s;if(ee===a&&++W===c&&(v=h),ee===o&&++ce===l&&(M=h),(ne=de.nextSibling)!==null)break;de=ee,ee=de.parentNode}de=ne}a=v===-1||M===-1?null:{start:v,end:M}}else a=null}a=a||{start:0,end:0}}else a=null;for(tu={focusedElem:s,selectionRange:a},_c=!1,wt=t;wt!==null;)if(t=wt,s=t.child,(t.subtreeFlags&1028)!==0&&s!==null)s.return=t,wt=s;else for(;wt!==null;){switch(t=wt,o=t.alternate,s=t.flags,t.tag){case 0:if((s&4)!==0&&(s=t.updateQueue,s=s!==null?s.events:null,s!==null))for(a=0;a title"))),Tt(o,l,a),o[_t]=s,yt(o),l=o;break e;case"link":var h=Of("link","href",c).get(l+(a.href||""));if(h){for(var v=0;vRs&&(h=Rs,Rs=Ie,Ie=h);var V=Um(v,Ie),H=Um(v,Rs);if(V&&H&&(ne.rangeCount!==1||ne.anchorNode!==V.node||ne.anchorOffset!==V.offset||ne.focusNode!==H.node||ne.focusOffset!==H.offset)){var Z=de.createRange();Z.setStart(V.node,V.offset),ne.removeAllRanges(),Ie>Rs?(ne.addRange(Z),ne.extend(H.node,H.offset)):(Z.setEnd(H.node,H.offset),ne.addRange(Z))}}}}for(de=[],ne=v;ne=ne.parentNode;)ne.nodeType===1&&de.push({element:ne,left:ne.scrollLeft,top:ne.scrollTop});for(typeof v.focus=="function"&&v.focus(),v=0;va?32:a,D.T=null,a=Gd,Gd=null;var o=Sl,h=tl;if(vt=0,qn=Sl=null,tl=0,(Cs&6)!==0)throw Error(d(331));var v=Cs;if(Cs|=4,Bh(o.current),Rh(o,o.current,h,a),Cs=v,$r(0,!1),Ae&&typeof Ae.onPostCommitFiberRoot=="function")try{Ae.onPostCommitFiberRoot(_s,o)}catch{}return!0}finally{J.p=c,D.T=l,tf(s,t)}}function lf(s,t,a){t=ca(a,t),t=bd(s.stateNode,t,2),s=jl(s,t,2),s!==null&&(Ms(s,2),Aa(s))}function As(s,t,a){if(s.tag===3)lf(s,s,a);else for(;t!==null;){if(t.tag===3){lf(t,s,a);break}else if(t.tag===1){var l=t.stateNode;if(typeof t.type.getDerivedStateFromError=="function"||typeof l.componentDidCatch=="function"&&(_l===null||!_l.has(l))){s=ca(a,s),a=nh(2),l=jl(t,a,2),l!==null&&(rh(a,l,t,s),Ms(l,2),Aa(l));break}}t=t.return}}function Qd(s,t,a){var l=s.pingCache;if(l===null){l=s.pingCache=new $v;var c=new Set;l.set(t,c)}else c=l.get(t),c===void 0&&(c=new Set,l.set(t,c));c.has(a)||(Ud=!0,c.add(a),s=Yv.bind(null,s,t,a),t.then(s,s))}function Yv(s,t,a){var l=s.pingCache;l!==null&&l.delete(t),s.pingedLanes|=s.suspendedLanes&a,s.warmLanes&=~a,Hs===s&&(fs&a)===a&&(lt===4||lt===3&&(fs&62914560)===fs&&300>Vs()-rc?(Cs&2)===0&&Gn(s,0):Bd|=a,Hn===fs&&(Hn=0)),Aa(s)}function nf(s,t){t===0&&(t=G()),s=Fl(s,t),s!==null&&(Ms(s,t),Aa(s))}function Kv(s){var t=s.memoizedState,a=0;t!==null&&(a=t.retryLane),nf(s,a)}function Xv(s,t){var a=0;switch(s.tag){case 31:case 13:var l=s.stateNode,c=s.memoizedState;c!==null&&(a=c.retryLane);break;case 19:l=s.stateNode;break;case 22:l=s.stateNode._retryCache;break;default:throw Error(d(314))}l!==null&&l.delete(t),nf(s,a)}function Jv(s,t){return Fs(s,t)}var xc=null,Fn=null,Id=!1,hc=!1,Yd=!1,kl=0;function Aa(s){s!==Fn&&s.next===null&&(Fn===null?xc=Fn=s:Fn=Fn.next=s),hc=!0,Id||(Id=!0,Pv())}function $r(s,t){if(!Yd&&hc){Yd=!0;do for(var a=!1,l=xc;l!==null;){if(s!==0){var c=l.pendingLanes;if(c===0)var o=0;else{var h=l.suspendedLanes,v=l.pingedLanes;o=(1<<31-bs(42|s)+1)-1,o&=c&~(h&~v),o=o&201326741?o&201326741|1:o?o|2:0}o!==0&&(a=!0,df(l,o))}else o=fs,o=ol(l,l===Hs?o:0,l.cancelPendingCommit!==null||l.timeoutHandle!==-1),(o&3)===0||ba(l,o)||(a=!0,df(l,o));l=l.next}while(a);Yd=!1}}function Zv(){rf()}function rf(){hc=Id=!1;var s=0;kl!==0&&cb()&&(s=kl);for(var t=Vs(),a=null,l=xc;l!==null;){var c=l.next,o=cf(l,t);o===0?(l.next=null,a===null?xc=c:a.next=c,c===null&&(Fn=a)):(a=l,(s!==0||(o&3)!==0)&&(hc=!0)),l=c}vt!==0&&vt!==5||$r(s),kl!==0&&(kl=0)}function cf(s,t){for(var a=s.suspendedLanes,l=s.pingedLanes,c=s.expirationTimes,o=s.pendingLanes&-62914561;0v)break;var ce=M.transferSize,de=M.initiatorType;ce&&jf(de)&&(M=M.responseEnd,h+=ce*(M"u"?null:document;function zf(s,t,a){var l=Vn;if(l&&typeof t=="string"&&t){var c=ra(t);c='link[rel="'+s+'"][href="'+c+'"]',typeof a=="string"&&(c+='[crossorigin="'+a+'"]'),Ef.has(c)||(Ef.add(c),s={rel:s,crossOrigin:a,href:t},l.querySelector(c)===null&&(t=l.createElement("link"),Tt(t,"link",s),yt(t),l.head.appendChild(t)))}}function gb(s){al.D(s),zf("dns-prefetch",s,null)}function jb(s,t){al.C(s,t),zf("preconnect",s,t)}function vb(s,t,a){al.L(s,t,a);var l=Vn;if(l&&s&&t){var c='link[rel="preload"][as="'+ra(t)+'"]';t==="image"&&a&&a.imageSrcSet?(c+='[imagesrcset="'+ra(a.imageSrcSet)+'"]',typeof a.imageSizes=="string"&&(c+='[imagesizes="'+ra(a.imageSizes)+'"]')):c+='[href="'+ra(s)+'"]';var o=c;switch(t){case"style":o=Qn(s);break;case"script":o=In(s)}ha.has(o)||(s=y({rel:"preload",href:t==="image"&&a&&a.imageSrcSet?void 0:s,as:t},a),ha.set(o,s),l.querySelector(c)!==null||t==="style"&&l.querySelector(Ir(o))||t==="script"&&l.querySelector(Yr(o))||(t=l.createElement("link"),Tt(t,"link",s),yt(t),l.head.appendChild(t)))}}function bb(s,t){al.m(s,t);var a=Vn;if(a&&s){var l=t&&typeof t.as=="string"?t.as:"script",c='link[rel="modulepreload"][as="'+ra(l)+'"][href="'+ra(s)+'"]',o=c;switch(l){case"audioworklet":case"paintworklet":case"serviceworker":case"sharedworker":case"worker":case"script":o=In(s)}if(!ha.has(o)&&(s=y({rel:"modulepreload",href:s},t),ha.set(o,s),a.querySelector(c)===null)){switch(l){case"audioworklet":case"paintworklet":case"serviceworker":case"sharedworker":case"worker":case"script":if(a.querySelector(Yr(o)))return}l=a.createElement("link"),Tt(l,"link",s),yt(l),a.head.appendChild(l)}}}function Nb(s,t,a){al.S(s,t,a);var l=Vn;if(l&&s){var c=xn(l).hoistableStyles,o=Qn(s);t=t||"default";var h=c.get(o);if(!h){var v={loading:0,preload:null};if(h=l.querySelector(Ir(o)))v.loading=5;else{s=y({rel:"stylesheet",href:s,"data-precedence":t},a),(a=ha.get(o))&&ou(s,a);var M=h=l.createElement("link");yt(M),Tt(M,"link",s),M._p=new Promise(function(W,ce){M.onload=W,M.onerror=ce}),M.addEventListener("load",function(){v.loading|=1}),M.addEventListener("error",function(){v.loading|=2}),v.loading|=4,vc(h,t,l)}h={type:"stylesheet",instance:h,count:1,state:v},c.set(o,h)}}}function yb(s,t){al.X(s,t);var a=Vn;if(a&&s){var l=xn(a).hoistableScripts,c=In(s),o=l.get(c);o||(o=a.querySelector(Yr(c)),o||(s=y({src:s,async:!0},t),(t=ha.get(c))&&du(s,t),o=a.createElement("script"),yt(o),Tt(o,"link",s),a.head.appendChild(o)),o={type:"script",instance:o,count:1,state:null},l.set(c,o))}}function wb(s,t){al.M(s,t);var a=Vn;if(a&&s){var l=xn(a).hoistableScripts,c=In(s),o=l.get(c);o||(o=a.querySelector(Yr(c)),o||(s=y({src:s,async:!0,type:"module"},t),(t=ha.get(c))&&du(s,t),o=a.createElement("script"),yt(o),Tt(o,"link",s),a.head.appendChild(o)),o={type:"script",instance:o,count:1,state:null},l.set(c,o))}}function Af(s,t,a,l){var c=(c=ge.current)?jc(c):null;if(!c)throw Error(d(446));switch(s){case"meta":case"title":return null;case"style":return typeof a.precedence=="string"&&typeof a.href=="string"?(t=Qn(a.href),a=xn(c).hoistableStyles,l=a.get(t),l||(l={type:"style",instance:null,count:0,state:null},a.set(t,l)),l):{type:"void",instance:null,count:0,state:null};case"link":if(a.rel==="stylesheet"&&typeof a.href=="string"&&typeof a.precedence=="string"){s=Qn(a.href);var o=xn(c).hoistableStyles,h=o.get(s);if(h||(c=c.ownerDocument||c,h={type:"stylesheet",instance:null,count:0,state:{loading:0,preload:null}},o.set(s,h),(o=c.querySelector(Ir(s)))&&!o._p&&(h.instance=o,h.state.loading=5),ha.has(s)||(a={rel:"preload",as:"style",href:a.href,crossOrigin:a.crossOrigin,integrity:a.integrity,media:a.media,hrefLang:a.hrefLang,referrerPolicy:a.referrerPolicy},ha.set(s,a),o||_b(c,s,a,h.state))),t&&l===null)throw Error(d(528,""));return h}if(t&&l!==null)throw Error(d(529,""));return null;case"script":return t=a.async,a=a.src,typeof a=="string"&&t&&typeof t!="function"&&typeof t!="symbol"?(t=In(a),a=xn(c).hoistableScripts,l=a.get(t),l||(l={type:"script",instance:null,count:0,state:null},a.set(t,l)),l):{type:"void",instance:null,count:0,state:null};default:throw Error(d(444,s))}}function Qn(s){return'href="'+ra(s)+'"'}function Ir(s){return'link[rel="stylesheet"]['+s+"]"}function Mf(s){return y({},s,{"data-precedence":s.precedence,precedence:null})}function _b(s,t,a,l){s.querySelector('link[rel="preload"][as="style"]['+t+"]")?l.loading=1:(t=s.createElement("link"),l.preload=t,t.addEventListener("load",function(){return l.loading|=1}),t.addEventListener("error",function(){return l.loading|=2}),Tt(t,"link",a),yt(t),s.head.appendChild(t))}function In(s){return'[src="'+ra(s)+'"]'}function Yr(s){return"script[async]"+s}function Df(s,t,a){if(t.count++,t.instance===null)switch(t.type){case"style":var l=s.querySelector('style[data-href~="'+ra(a.href)+'"]');if(l)return t.instance=l,yt(l),l;var c=y({},a,{"data-href":a.href,"data-precedence":a.precedence,href:null,precedence:null});return l=(s.ownerDocument||s).createElement("style"),yt(l),Tt(l,"style",c),vc(l,a.precedence,s),t.instance=l;case"stylesheet":c=Qn(a.href);var o=s.querySelector(Ir(c));if(o)return t.state.loading|=4,t.instance=o,yt(o),o;l=Mf(a),(c=ha.get(c))&&ou(l,c),o=(s.ownerDocument||s).createElement("link"),yt(o);var h=o;return h._p=new Promise(function(v,M){h.onload=v,h.onerror=M}),Tt(o,"link",l),t.state.loading|=4,vc(o,a.precedence,s),t.instance=o;case"script":return o=In(a.src),(c=s.querySelector(Yr(o)))?(t.instance=c,yt(c),c):(l=a,(c=ha.get(o))&&(l=y({},a),du(l,c)),s=s.ownerDocument||s,c=s.createElement("script"),yt(c),Tt(c,"link",l),s.head.appendChild(c),t.instance=c);case"void":return null;default:throw Error(d(443,t.type))}else t.type==="stylesheet"&&(t.state.loading&4)===0&&(l=t.instance,t.state.loading|=4,vc(l,a.precedence,s));return t.instance}function vc(s,t,a){for(var l=a.querySelectorAll('link[rel="stylesheet"][data-precedence],style[data-precedence]'),c=l.length?l[l.length-1]:null,o=c,h=0;h title"):null)}function Sb(s,t,a){if(a===1||t.itemProp!=null)return!1;switch(s){case"meta":case"title":return!0;case"style":if(typeof t.precedence!="string"||typeof t.href!="string"||t.href==="")break;return!0;case"link":if(typeof t.rel!="string"||typeof t.href!="string"||t.href===""||t.onLoad||t.onError)break;switch(t.rel){case"stylesheet":return s=t.disabled,typeof t.precedence=="string"&&s==null;default:return!0}case"script":if(t.async&&typeof t.async!="function"&&typeof t.async!="symbol"&&!t.onLoad&&!t.onError&&t.src&&typeof t.src=="string")return!0}return!1}function Lf(s){return!(s.type==="stylesheet"&&(s.state.loading&3)===0)}function Cb(s,t,a,l){if(a.type==="stylesheet"&&(typeof l.media!="string"||matchMedia(l.media).matches!==!1)&&(a.state.loading&4)===0){if(a.instance===null){var c=Qn(l.href),o=t.querySelector(Ir(c));if(o){t=o._p,t!==null&&typeof t=="object"&&typeof t.then=="function"&&(s.count++,s=Nc.bind(s),t.then(s,s)),a.state.loading|=4,a.instance=o,yt(o);return}o=t.ownerDocument||t,l=Mf(l),(c=ha.get(c))&&ou(l,c),o=o.createElement("link"),yt(o);var h=o;h._p=new Promise(function(v,M){h.onload=v,h.onerror=M}),Tt(o,"link",l),a.instance=o}s.stylesheets===null&&(s.stylesheets=new Map),s.stylesheets.set(a,t),(t=a.state.preload)&&(a.state.loading&3)===0&&(s.count++,a=Nc.bind(s),t.addEventListener("load",a),t.addEventListener("error",a))}}var uu=0;function kb(s,t){return s.stylesheets&&s.count===0&&wc(s,s.stylesheets),0uu?50:800)+t);return s.unsuspend=a,function(){s.unsuspend=null,clearTimeout(l),clearTimeout(c)}}:null}function Nc(){if(this.count--,this.count===0&&(this.imgCount===0||!this.waitingForImages)){if(this.stylesheets)wc(this,this.stylesheets);else if(this.unsuspend){var s=this.unsuspend;this.unsuspend=null,s()}}}var yc=null;function wc(s,t){s.stylesheets=null,s.unsuspend!==null&&(s.count++,yc=new Map,t.forEach(Tb,s),yc=null,Nc.call(s))}function Tb(s,t){if(!(t.state.loading&4)){var a=yc.get(s);if(a)var l=a.get(null);else{a=new Map,yc.set(s,a);for(var c=s.querySelectorAll("link[data-precedence],style[data-precedence]"),o=0;o"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(n)}catch(r){console.error(r)}}return n(),yu.exports=c0(),yu.exports}var d0=o0();function $(...n){return Yb(Kb(n))}const Fe=u.forwardRef(({className:n,...r},i)=>e.jsx("div",{ref:i,className:$("rounded-xl border bg-card text-card-foreground shadow",n),...r}));Fe.displayName="Card";const ts=u.forwardRef(({className:n,...r},i)=>e.jsx("div",{ref:i,className:$("flex flex-col space-y-1.5 p-6",n),...r}));ts.displayName="CardHeader";const as=u.forwardRef(({className:n,...r},i)=>e.jsx("div",{ref:i,className:$("font-semibold leading-none tracking-tight",n),...r}));as.displayName="CardTitle";const et=u.forwardRef(({className:n,...r},i)=>e.jsx("div",{ref:i,className:$("text-sm text-muted-foreground",n),...r}));et.displayName="CardDescription";const xs=u.forwardRef(({className:n,...r},i)=>e.jsx("div",{ref:i,className:$("p-6 pt-0",n),...r}));xs.displayName="CardContent";const Sg=u.forwardRef(({className:n,...r},i)=>e.jsx("div",{ref:i,className:$("flex items-center p-6 pt-0",n),...r}));Sg.displayName="CardFooter";const ga=Xb,la=u.forwardRef(({className:n,...r},i)=>e.jsx(Sp,{ref:i,className:$("inline-flex h-9 items-center justify-center rounded-lg bg-muted p-1 text-muted-foreground",n),...r}));la.displayName=Sp.displayName;const ss=u.forwardRef(({className:n,...r},i)=>e.jsx(Cp,{ref:i,className:$("inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1 text-sm font-medium ring-offset-background transition-all duration-300 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow",n),...r}));ss.displayName=Cp.displayName;const Ts=u.forwardRef(({className:n,...r},i)=>e.jsx(kp,{ref:i,className:$("mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 data-[state=active]:animate-in data-[state=active]:fade-in data-[state=active]:duration-300",n),...r}));Ts.displayName=kp.displayName;const Ze=u.forwardRef(({className:n,children:r,viewportRef:i,...d},m)=>e.jsxs(Tp,{ref:m,className:$("relative overflow-hidden",n),...d,children:[e.jsx(Jb,{ref:i,className:"h-full w-full rounded-[inherit]",children:r}),e.jsx(Uu,{}),e.jsx(Uu,{orientation:"horizontal"}),e.jsx(Zb,{})]}));Ze.displayName=Tp.displayName;const Uu=u.forwardRef(({className:n,orientation:r="vertical",...i},d)=>e.jsx(Ep,{ref:d,orientation:r,className:$("flex touch-none select-none transition-colors",r==="vertical"&&"h-full w-2.5 border-l border-l-transparent p-[1px]",r==="horizontal"&&"h-2.5 flex-col border-t border-t-transparent p-[1px]",n),...i,children:e.jsx(Pb,{className:"relative flex-1 rounded-full bg-border"})}));Uu.displayName=Ep.displayName;function Cg({className:n,...r}){return e.jsx("div",{className:$("animate-pulse rounded-md bg-primary/10",n),...r})}const rr=u.forwardRef(({className:n,value:r,...i},d)=>e.jsx(zp,{ref:d,className:$("relative h-2 w-full overflow-hidden rounded-full bg-primary/20",n),...i,children:e.jsx(Wb,{className:"h-full w-full flex-1 bg-primary transition-all",style:{transform:`translateX(-${100-(r||0)}%)`}})}));rr.displayName=zp.displayName;const u0={light:"",dark:".dark"},kg=u.createContext(null);function Tg(){const n=u.useContext(kg);if(!n)throw new Error("useChart must be used within a ");return n}const Xn=u.forwardRef(({id:n,className:r,children:i,config:d,...m},x)=>{const f=u.useId(),p=`chart-${n||f.replace(/:/g,"")}`;return e.jsx(kg.Provider,{value:{config:d},children:e.jsxs("div",{"data-chart":p,ref:x,className:$("flex aspect-video justify-center text-xs [&_.recharts-cartesian-axis-tick_text]:fill-muted-foreground [&_.recharts-cartesian-grid_line[stroke='#ccc']]:stroke-border/50 [&_.recharts-curve.recharts-tooltip-cursor]:stroke-border [&_.recharts-dot[stroke='#fff']]:stroke-transparent [&_.recharts-layer]:outline-none [&_.recharts-polar-grid_[stroke='#ccc']]:stroke-border [&_.recharts-radial-bar-background-sector]:fill-muted [&_.recharts-rectangle.recharts-tooltip-cursor]:fill-muted [&_.recharts-reference-line_[stroke='#ccc']]:stroke-border [&_.recharts-sector[stroke='#fff']]:stroke-transparent [&_.recharts-sector]:outline-none [&_.recharts-surface]:outline-none",r),...m,children:[e.jsx(m0,{id:p,config:d}),e.jsx(fN,{children:i})]})})});Xn.displayName="Chart";const m0=({id:n,config:r})=>{const i=Object.entries(r).filter(([,d])=>d.theme||d.color);return i.length?e.jsx("style",{dangerouslySetInnerHTML:{__html:Object.entries(u0).map(([d,m])=>` -${m} [data-chart=${n}] { -${i.map(([x,f])=>{const p=f.theme?.[d]||f.color;return p?` --color-${x}: ${p};`:null}).join(` -`)} -} -`).join(` -`)}}):null},ei=pN,Jn=u.forwardRef(({active:n,payload:r,className:i,indicator:d="dot",hideLabel:m=!1,hideIndicator:x=!1,label:f,labelFormatter:p,labelClassName:g,formatter:b,color:j,nameKey:y,labelKey:N},k)=>{const{config:w}=Tg(),U=u.useMemo(()=>{if(m||!r?.length)return null;const[B]=r,Y=`${N||B?.dataKey||B?.name||"value"}`,L=Bu(w,B,Y),z=!N&&typeof f=="string"?w[f]?.label||f:L?.label;return p?e.jsx("div",{className:$("font-medium",g),children:p(z,r)}):z?e.jsx("div",{className:$("font-medium",g),children:z}):null},[f,p,r,m,g,w,N]);if(!n||!r?.length)return null;const O=r.length===1&&d!=="dot";return e.jsxs("div",{ref:k,className:$("grid min-w-[8rem] items-start gap-1.5 rounded-lg border border-border/50 bg-background px-2.5 py-1.5 text-xs shadow-xl",i),children:[O?null:U,e.jsx("div",{className:"grid gap-1.5",children:r.filter(B=>B.type!=="none").map((B,Y)=>{const L=`${y||B.name||B.dataKey||"value"}`,z=Bu(w,B,L),K=j||B.payload.fill||B.color;return e.jsx("div",{className:$("flex w-full flex-wrap items-stretch gap-2 [&>svg]:h-2.5 [&>svg]:w-2.5 [&>svg]:text-muted-foreground",d==="dot"&&"items-center"),children:b&&B?.value!==void 0&&B.name?b(B.value,B.name,B,Y,B.payload):e.jsxs(e.Fragment,{children:[z?.icon?e.jsx(z.icon,{}):!x&&e.jsx("div",{className:$("shrink-0 rounded-[2px] border-[--color-border] bg-[--color-bg]",{"h-2.5 w-2.5":d==="dot","w-1":d==="line","w-0 border-[1.5px] border-dashed bg-transparent":d==="dashed","my-0.5":O&&d==="dashed"}),style:{"--color-bg":K,"--color-border":K}}),e.jsxs("div",{className:$("flex flex-1 justify-between leading-none",O?"items-end":"items-center"),children:[e.jsxs("div",{className:"grid gap-1.5",children:[O?U:null,e.jsx("span",{className:"text-muted-foreground",children:z?.label||B.name})]}),B.value&&e.jsx("span",{className:"font-mono font-medium tabular-nums text-foreground",children:B.value.toLocaleString()})]})]})},B.dataKey)})})]})});Jn.displayName="ChartTooltip";const x0=gN,Eg=u.forwardRef(({className:n,hideIcon:r=!1,payload:i,verticalAlign:d="bottom",nameKey:m},x)=>{const{config:f}=Tg();return i?.length?e.jsx("div",{ref:x,className:$("flex items-center justify-center gap-4",d==="top"?"pb-3":"pt-3",n),children:i.filter(p=>p.type!=="none").map(p=>{const g=`${m||p.dataKey||"value"}`,b=Bu(f,p,g);return e.jsxs("div",{className:$("flex items-center gap-1.5 [&>svg]:h-3 [&>svg]:w-3 [&>svg]:text-muted-foreground"),children:[b?.icon&&!r?e.jsx(b.icon,{}):e.jsx("div",{className:"h-2 w-2 shrink-0 rounded-[2px]",style:{backgroundColor:p.color}}),b?.label]},p.value)})}):null});Eg.displayName="ChartLegend";function Bu(n,r,i){if(typeof r!="object"||r===null)return;const d="payload"in r&&typeof r.payload=="object"&&r.payload!==null?r.payload:void 0;let m=i;return i in r&&typeof r[i]=="string"?m=r[i]:d&&i in d&&typeof d[i]=="string"&&(m=d[i]),m in n?n[m]:n[i]}const ui=tr("inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",{variants:{variant:{default:"bg-primary text-primary-foreground shadow hover:bg-primary/90",destructive:"bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",outline:"border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",secondary:"bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",ghost:"hover:bg-accent hover:text-accent-foreground",link:"text-primary underline-offset-4 hover:underline"},size:{default:"h-9 px-4 py-2",sm:"h-8 rounded-md px-3 text-xs",lg:"h-10 rounded-md px-8",icon:"h-9 w-9"}},defaultVariants:{variant:"default",size:"default"}}),S=u.forwardRef(({className:n,variant:r,size:i,asChild:d=!1,...m},x)=>{const f=d?wN:"button";return e.jsx(f,{className:$(ui({variant:r,size:i,className:n})),ref:x,...m})});S.displayName="Button";const h0=tr("inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",{variants:{variant:{default:"border-transparent bg-primary text-primary-foreground shadow hover:bg-primary/80",secondary:"border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",destructive:"border-transparent bg-destructive text-destructive-foreground shadow hover:bg-destructive/80",outline:"text-foreground"}},defaultVariants:{variant:"default"}});function Qe({className:n,variant:r,...i}){return e.jsx("div",{className:$(h0({variant:r}),n),...i})}const f0=5,p0=5e3;let Su=0;function g0(){return Su=(Su+1)%Number.MAX_SAFE_INTEGER,Su.toString()}const Cu=new Map,rp=n=>{if(Cu.has(n))return;const r=setTimeout(()=>{Cu.delete(n),ii({type:"REMOVE_TOAST",toastId:n})},p0);Cu.set(n,r)},j0=(n,r)=>{switch(r.type){case"ADD_TOAST":return{...n,toasts:[r.toast,...n.toasts].slice(0,f0)};case"UPDATE_TOAST":return{...n,toasts:n.toasts.map(i=>i.id===r.toast.id?{...i,...r.toast}:i)};case"DISMISS_TOAST":{const{toastId:i}=r;return i?rp(i):n.toasts.forEach(d=>{rp(d.id)}),{...n,toasts:n.toasts.map(d=>d.id===i||i===void 0?{...d,open:!1}:d)}}case"REMOVE_TOAST":return r.toastId===void 0?{...n,toasts:[]}:{...n,toasts:n.toasts.filter(i=>i.id!==r.toastId)}}},qc=[];let Gc={toasts:[]};function ii(n){Gc=j0(Gc,n),qc.forEach(r=>{r(Gc)})}function v0({...n}){const r=g0(),i=m=>ii({type:"UPDATE_TOAST",toast:{...m,id:r}}),d=()=>ii({type:"DISMISS_TOAST",toastId:r});return ii({type:"ADD_TOAST",toast:{...n,id:r,open:!0,onOpenChange:m=>{m||d()}}}),{id:r,dismiss:d,update:i}}function $s(){const[n,r]=u.useState(Gc);return u.useEffect(()=>(qc.push(r),()=>{const i=qc.indexOf(r);i>-1&&qc.splice(i,1)}),[n]),{...n,toast:v0,dismiss:i=>ii({type:"DISMISS_TOAST",toastId:i})}}const b0=n=>{const r=[];for(let i=0;i{try{k(!0);const R=await Ac.get("https://v1.hitokoto.cn/?c=a&c=b&c=c&c=d&c=h&c=i&c=k");y({hitokoto:R.data.hitokoto,from:R.data.from||R.data.from_who||"未知"})}catch(R){console.error("获取一言失败:",R),y({hitokoto:"人生就像一盒巧克力,你永远不知道下一颗是什么味道。",from:"阿甘正传"})}finally{k(!1)}},[]),z=u.useCallback(async()=>{try{const R=localStorage.getItem("access-token"),ue=await Ac.get("/api/webui/system/status",{headers:{Authorization:`Bearer ${R}`}});U(ue.data)}catch(R){console.error("获取机器人状态失败:",R),U(null)}},[]),K=async()=>{if(!O)try{B(!0);const R=localStorage.getItem("access-token");await Ac.post("/api/webui/system/restart",{},{headers:{Authorization:`Bearer ${R}`}}),Y({title:"重启中",description:"麦麦正在重启,请稍候..."}),setTimeout(()=>{z(),B(!1)},3e3)}catch(R){console.error("重启失败:",R),Y({title:"重启失败",description:"无法重启麦麦,请检查控制台",variant:"destructive"}),B(!1)}},I=u.useCallback(async()=>{try{const R=localStorage.getItem("access-token"),ue=await Ac.get(`/api/webui/statistics/dashboard?hours=${f}`,{headers:{Authorization:`Bearer ${R}`}});r(ue.data),d(!1),x(100)}catch(R){console.error("Failed to fetch dashboard data:",R),d(!1),x(100)}},[f]);if(u.useEffect(()=>{if(!i)return;x(0);const R=setTimeout(()=>x(15),200),ue=setTimeout(()=>x(30),800),me=setTimeout(()=>x(45),2e3),_e=setTimeout(()=>x(60),4e3),Ce=setTimeout(()=>x(75),6500),ze=setTimeout(()=>x(85),9e3),ge=setTimeout(()=>x(92),11e3);return()=>{clearTimeout(R),clearTimeout(ue),clearTimeout(me),clearTimeout(_e),clearTimeout(Ce),clearTimeout(ze),clearTimeout(ge)}},[i]),u.useEffect(()=>{I(),L(),z()},[I,L,z]),u.useEffect(()=>{if(!g)return;const R=setInterval(()=>{I(),z()},3e4);return()=>clearInterval(R)},[g,I,z]),i||!n)return e.jsx("div",{className:"flex items-center justify-center h-[calc(100vh-200px)]",children:e.jsxs("div",{className:"text-center space-y-6 w-full max-w-md px-4",children:[e.jsx(zt,{className:"h-12 w-12 animate-spin mx-auto text-primary"}),e.jsxs("div",{className:"space-y-2",children:[e.jsx("p",{className:"text-lg font-medium",children:"加载统计数据中..."}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"正在获取麦麦运行数据"})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(rr,{value:m,className:"h-2"}),e.jsxs("p",{className:"text-xs text-muted-foreground",children:[m,"%"]})]})]})});const{summary:T,model_stats:A=[],hourly_data:te=[],daily_data:fe=[],recent_activity:je=[]}=n,pe=T??{total_requests:0,total_cost:0,total_tokens:0,online_time:0,total_messages:0,total_replies:0,avg_response_time:0,cost_per_hour:0,tokens_per_hour:0},he=R=>{const ue=Math.floor(R/3600),me=Math.floor(R%3600/60);return`${ue}小时${me}分钟`},ve=R=>{const ue=R.toLocaleString("zh-CN");return R>=1e9?{display:`${(R/1e9).toFixed(2)}B`,exact:ue,needsExact:!0}:R>=1e6?{display:`${(R/1e6).toFixed(2)}M`,exact:ue,needsExact:!0}:R>=1e4?{display:`${(R/1e3).toFixed(1)}K`,exact:ue,needsExact:!0}:R>=1e3?{display:`${(R/1e3).toFixed(2)}K`,exact:ue,needsExact:!0}:{display:ue,exact:ue,needsExact:!1}},be=R=>{const ue=`¥${R.toLocaleString("zh-CN",{minimumFractionDigits:2,maximumFractionDigits:2})}`;return R>=1e6?{display:`¥${(R/1e6).toFixed(2)}M`,exact:ue,needsExact:!0}:R>=1e4?{display:`¥${(R/1e3).toFixed(1)}K`,exact:ue,needsExact:!0}:R>=1e3?{display:`¥${(R/1e3).toFixed(2)}K`,exact:ue,needsExact:!0}:{display:ue,exact:ue,needsExact:!1}},D=R=>new Date(R).toLocaleString("zh-CN",{month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit"}),J=b0(A.length),q=A.map((R,ue)=>({name:R.model_name,value:R.request_count,fill:J[ue]})),se={requests:{label:"请求数",color:"hsl(var(--chart-1))"},cost:{label:"花费(¥)",color:"hsl(var(--chart-2))"},tokens:{label:"Tokens",color:"hsl(var(--chart-3))"}};return e.jsx(Ze,{className:"h-full",children:e.jsxs("div",{className:"space-y-4 sm:space-y-6 p-4 sm:p-6",children:[e.jsxs("div",{className:"flex flex-col sm:flex-row sm:items-center justify-between gap-4",children:[e.jsxs("div",{children:[e.jsx("h1",{className:"text-2xl sm:text-3xl font-bold",children:"实时监控面板"}),e.jsx("p",{className:"text-sm text-muted-foreground mt-1",children:"麦麦运行状态和统计数据一览"})]}),e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsx(ga,{value:f.toString(),onValueChange:R=>p(Number(R)),children:e.jsxs(la,{className:"grid grid-cols-3 w-full sm:w-auto",children:[e.jsx(ss,{value:"24",children:"24小时"}),e.jsx(ss,{value:"168",children:"7天"}),e.jsx(ss,{value:"720",children:"30天"})]})}),e.jsxs(S,{variant:g?"default":"outline",size:"sm",onClick:()=>b(!g),className:"gap-2",children:[e.jsx(zt,{className:`h-4 w-4 ${g?"animate-spin":""}`}),e.jsx("span",{className:"hidden sm:inline",children:"自动刷新"})]}),e.jsx(S,{variant:"outline",size:"sm",onClick:I,children:e.jsx(zt,{className:"h-4 w-4"})})]})]}),e.jsxs("div",{className:"flex items-center gap-3 px-4 py-2 rounded-lg border border-dashed border-muted-foreground/30 bg-muted/20",children:[N?e.jsx(Cg,{className:"h-5 flex-1"}):j?e.jsxs("p",{className:"flex-1 text-sm text-muted-foreground italic truncate",children:['"',j.hitokoto,'" —— ',j.from]}):null,e.jsx(S,{variant:"ghost",size:"icon",className:"h-7 w-7 shrink-0",onClick:L,disabled:N,children:e.jsx(zt,{className:`h-3.5 w-3.5 ${N?"animate-spin":""}`})})]}),e.jsxs("div",{className:"grid gap-4 grid-cols-1 lg:grid-cols-3",children:[e.jsxs(Fe,{className:"lg:col-span-1",children:[e.jsx(ts,{className:"pb-3",children:e.jsxs(as,{className:"text-sm font-medium flex items-center gap-2",children:[e.jsx(hi,{className:"h-4 w-4"}),"麦麦状态"]})}),e.jsx(xs,{children:e.jsxs("div",{className:"flex items-center gap-4",children:[e.jsx("div",{className:"flex items-center gap-2",children:w?.running?e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"h-3 w-3 rounded-full bg-green-500 animate-pulse"}),e.jsxs(Qe,{variant:"outline",className:"text-green-600 border-green-300 bg-green-50",children:[e.jsx(aa,{className:"h-3 w-3 mr-1"}),"运行中"]})]}):e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"h-3 w-3 rounded-full bg-red-500"}),e.jsxs(Qe,{variant:"outline",className:"text-red-600 border-red-300 bg-red-50",children:[e.jsx(At,{className:"h-3 w-3 mr-1"}),"已停止"]})]})}),w&&e.jsxs("div",{className:"text-xs text-muted-foreground",children:[e.jsxs("span",{children:["v",w.version]}),e.jsx("span",{className:"mx-2",children:"|"}),e.jsxs("span",{children:["运行 ",he(w.uptime)]})]})]})})]}),e.jsxs(Fe,{children:[e.jsx(ts,{className:"pb-3",children:e.jsxs(as,{className:"text-sm font-medium flex items-center gap-2",children:[e.jsx(an,{className:"h-4 w-4"}),"快速操作"]})}),e.jsx(xs,{children:e.jsxs("div",{className:"flex flex-wrap gap-2",children:[e.jsxs(S,{variant:"outline",size:"sm",onClick:K,disabled:O,className:"gap-2",children:[e.jsx($c,{className:`h-4 w-4 ${O?"animate-spin":""}`}),O?"重启中...":"重启麦麦"]}),e.jsx(S,{variant:"outline",size:"sm",asChild:!0,className:"gap-2",children:e.jsxs(Kn,{to:"/logs",children:[e.jsx(Sa,{className:"h-4 w-4"}),"查看日志"]})}),e.jsx(S,{variant:"outline",size:"sm",asChild:!0,className:"gap-2",children:e.jsxs(Kn,{to:"/plugins",children:[e.jsx(IN,{className:"h-4 w-4"}),"插件管理"]})}),e.jsx(S,{variant:"outline",size:"sm",asChild:!0,className:"gap-2",children:e.jsxs(Kn,{to:"/settings",children:[e.jsx(ar,{className:"h-4 w-4"}),"系统设置"]})})]})})]}),e.jsxs(Fe,{children:[e.jsxs(ts,{className:"pb-3",children:[e.jsxs(as,{className:"text-sm font-medium flex items-center gap-2",children:[e.jsx(YN,{className:"h-4 w-4"}),"反馈问卷"]}),e.jsx(et,{className:"text-xs",children:"帮助我们改进产品体验"})]}),e.jsx(xs,{children:e.jsxs("div",{className:"flex flex-wrap gap-2",children:[e.jsx(S,{variant:"outline",size:"sm",asChild:!0,className:"gap-2",children:e.jsxs(Kn,{to:"/survey/webui-feedback",children:[e.jsx(Sa,{className:"h-4 w-4"}),"WebUI 反馈"]})}),e.jsx(S,{variant:"outline",size:"sm",asChild:!0,className:"gap-2",children:e.jsxs(Kn,{to:"/survey/maibot-feedback",children:[e.jsx(Rl,{className:"h-4 w-4"}),"麦麦反馈"]})})]})})]})]}),e.jsxs("div",{className:"grid gap-4 grid-cols-1 xs:grid-cols-2 lg:grid-cols-4",children:[e.jsxs(Fe,{children:[e.jsxs(ts,{className:"flex flex-row items-center justify-between space-y-0 pb-2",children:[e.jsx(as,{className:"text-sm font-medium",children:"总请求数"}),e.jsx(KN,{className:"h-4 w-4 text-muted-foreground"})]}),e.jsxs(xs,{children:[e.jsxs("div",{className:"text-2xl font-bold",children:[ve(pe.total_requests).display,ve(pe.total_requests).needsExact&&e.jsxs("span",{className:"text-xs font-normal text-muted-foreground ml-1",children:["(",ve(pe.total_requests).exact,")"]})]}),e.jsxs("p",{className:"text-xs text-muted-foreground mt-1",children:["最近",f<48?f+"小时":Math.floor(f/24)+"天"]})]})]}),e.jsxs(Fe,{children:[e.jsxs(ts,{className:"flex flex-row items-center justify-between space-y-0 pb-2",children:[e.jsx(as,{className:"text-sm font-medium",children:"总花费"}),e.jsx(XN,{className:"h-4 w-4 text-muted-foreground"})]}),e.jsxs(xs,{children:[e.jsxs("div",{className:"text-2xl font-bold",children:[be(pe.total_cost).display,be(pe.total_cost).needsExact&&e.jsxs("span",{className:"text-xs font-normal text-muted-foreground ml-1",children:["(",be(pe.total_cost).exact,")"]})]}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:pe.cost_per_hour>0?`¥${pe.cost_per_hour.toFixed(2)}/小时`:"暂无数据"})]})]}),e.jsxs(Fe,{children:[e.jsxs(ts,{className:"flex flex-row items-center justify-between space-y-0 pb-2",children:[e.jsx(as,{className:"text-sm font-medium",children:"Token消耗"}),e.jsx(Fc,{className:"h-4 w-4 text-muted-foreground"})]}),e.jsxs(xs,{children:[e.jsxs("div",{className:"text-2xl font-bold",children:[ve(pe.total_tokens).display,ve(pe.total_tokens).needsExact&&e.jsxs("span",{className:"text-xs font-normal text-muted-foreground ml-1",children:["(",ve(pe.total_tokens).exact,")"]})]}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:pe.tokens_per_hour>0?`${ve(pe.tokens_per_hour).display}/小时`:"暂无数据"})]})]}),e.jsxs(Fe,{children:[e.jsxs(ts,{className:"flex flex-row items-center justify-between space-y-0 pb-2",children:[e.jsx(as,{className:"text-sm font-medium",children:"平均响应"}),e.jsx(an,{className:"h-4 w-4 text-muted-foreground"})]}),e.jsxs(xs,{children:[e.jsxs("div",{className:"text-2xl font-bold",children:[pe.avg_response_time.toFixed(2),"s"]}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:"API平均耗时"})]})]})]}),e.jsxs("div",{className:"grid gap-4 grid-cols-1 sm:grid-cols-3",children:[e.jsxs(Fe,{children:[e.jsxs(ts,{className:"flex flex-row items-center justify-between space-y-0 pb-2",children:[e.jsx(as,{className:"text-sm font-medium",children:"在线时长"}),e.jsx(Pn,{className:"h-4 w-4 text-muted-foreground"})]}),e.jsx(xs,{children:e.jsxs("div",{className:"text-xl font-bold",children:[he(pe.online_time),e.jsxs("span",{className:"text-xs font-normal text-muted-foreground ml-1",children:["(",pe.online_time.toLocaleString(),"秒)"]})]})})]}),e.jsxs(Fe,{children:[e.jsxs(ts,{className:"flex flex-row items-center justify-between space-y-0 pb-2",children:[e.jsx(as,{className:"text-sm font-medium",children:"消息处理"}),e.jsx(Rl,{className:"h-4 w-4 text-muted-foreground"})]}),e.jsxs(xs,{children:[e.jsxs("div",{className:"text-xl font-bold",children:[ve(pe.total_messages).display,ve(pe.total_messages).needsExact&&e.jsxs("span",{className:"text-xs font-normal text-muted-foreground ml-1",children:["(",ve(pe.total_messages).exact,")"]})]}),e.jsxs("p",{className:"text-xs text-muted-foreground mt-1",children:["回复 ",ve(pe.total_replies).display,ve(pe.total_replies).needsExact&&e.jsxs("span",{children:["(",ve(pe.total_replies).exact,")"]})," 条"]})]})]}),e.jsxs(Fe,{children:[e.jsxs(ts,{className:"flex flex-row items-center justify-between space-y-0 pb-2",children:[e.jsx(as,{className:"text-sm font-medium",children:"成本效率"}),e.jsx(JN,{className:"h-4 w-4 text-muted-foreground"})]}),e.jsxs(xs,{children:[e.jsx("div",{className:"text-xl font-bold",children:pe.total_messages>0?`¥${(pe.total_cost/pe.total_messages*100).toFixed(2)}`:"¥0.00"}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:"每100条消息"})]})]})]}),e.jsxs(ga,{defaultValue:"trends",className:"space-y-4",children:[e.jsxs(la,{className:"grid w-full grid-cols-2 sm:grid-cols-4",children:[e.jsx(ss,{value:"trends",children:"趋势"}),e.jsx(ss,{value:"models",children:"模型"}),e.jsx(ss,{value:"activity",children:"活动"}),e.jsx(ss,{value:"daily",children:"日统计"})]}),e.jsxs(Ts,{value:"trends",className:"space-y-4",children:[e.jsxs(Fe,{children:[e.jsxs(ts,{children:[e.jsx(as,{children:"请求趋势"}),e.jsxs(et,{children:["最近",f,"小时的请求量变化"]})]}),e.jsx(xs,{children:e.jsx(Xn,{config:se,className:"h-[300px] sm:h-[400px] w-full aspect-auto",children:e.jsxs(jN,{data:te,children:[e.jsx(Mc,{strokeDasharray:"3 3",stroke:"hsl(var(--muted-foreground) / 0.2)"}),e.jsx(Dc,{dataKey:"timestamp",tickFormatter:R=>D(R),angle:-45,textAnchor:"end",height:60,stroke:"hsl(var(--muted-foreground))",tick:{fill:"hsl(var(--muted-foreground))"}}),e.jsx(Pr,{stroke:"hsl(var(--muted-foreground))",tick:{fill:"hsl(var(--muted-foreground))"}}),e.jsx(ei,{content:e.jsx(Jn,{labelFormatter:R=>D(R)})}),e.jsx(vN,{type:"monotone",dataKey:"requests",stroke:"var(--color-requests)",strokeWidth:2})]})})})]}),e.jsxs("div",{className:"grid gap-4 grid-cols-1 lg:grid-cols-2",children:[e.jsxs(Fe,{children:[e.jsxs(ts,{children:[e.jsx(as,{children:"花费趋势"}),e.jsx(et,{children:"API调用成本变化"})]}),e.jsx(xs,{children:e.jsx(Xn,{config:se,className:"h-[250px] sm:h-[300px] w-full aspect-auto",children:e.jsxs(vu,{data:te,children:[e.jsx(Mc,{strokeDasharray:"3 3",stroke:"hsl(var(--muted-foreground) / 0.2)"}),e.jsx(Dc,{dataKey:"timestamp",tickFormatter:R=>D(R),angle:-45,textAnchor:"end",height:60,stroke:"hsl(var(--muted-foreground))",tick:{fill:"hsl(var(--muted-foreground))"}}),e.jsx(Pr,{stroke:"hsl(var(--muted-foreground))",tick:{fill:"hsl(var(--muted-foreground))"}}),e.jsx(ei,{content:e.jsx(Jn,{labelFormatter:R=>D(R)})}),e.jsx(Oc,{dataKey:"cost",fill:"var(--color-cost)"})]})})})]}),e.jsxs(Fe,{children:[e.jsxs(ts,{children:[e.jsx(as,{children:"Token消耗"}),e.jsx(et,{children:"Token使用量变化"})]}),e.jsx(xs,{children:e.jsx(Xn,{config:se,className:"h-[250px] sm:h-[300px] w-full aspect-auto",children:e.jsxs(vu,{data:te,children:[e.jsx(Mc,{strokeDasharray:"3 3",stroke:"hsl(var(--muted-foreground) / 0.2)"}),e.jsx(Dc,{dataKey:"timestamp",tickFormatter:R=>D(R),angle:-45,textAnchor:"end",height:60,stroke:"hsl(var(--muted-foreground))",tick:{fill:"hsl(var(--muted-foreground))"}}),e.jsx(Pr,{stroke:"hsl(var(--muted-foreground))",tick:{fill:"hsl(var(--muted-foreground))"}}),e.jsx(ei,{content:e.jsx(Jn,{labelFormatter:R=>D(R)})}),e.jsx(Oc,{dataKey:"tokens",fill:"var(--color-tokens)"})]})})})]})]})]}),e.jsx(Ts,{value:"models",className:"space-y-4",children:e.jsxs("div",{className:"grid gap-4 grid-cols-1 lg:grid-cols-2",children:[e.jsxs(Fe,{children:[e.jsxs(ts,{children:[e.jsx(as,{children:"模型请求分布"}),e.jsxs(et,{children:["各模型使用占比 (共 ",A.length," 个模型)"]})]}),e.jsx(xs,{children:e.jsx(Xn,{config:Object.fromEntries(A.map((R,ue)=>[R.model_name,{label:R.model_name,color:J[ue]}])),className:"h-[300px] sm:h-[400px] w-full aspect-auto",children:e.jsxs(bN,{children:[e.jsx(ei,{content:e.jsx(Jn,{})}),e.jsx(NN,{data:q,cx:"50%",cy:"50%",labelLine:!1,label:({name:R,percent:ue})=>ue&&ue<.05?"":`${R} ${ue?(ue*100).toFixed(0):0}%`,outerRadius:100,dataKey:"value",children:q.map((R,ue)=>e.jsx(yN,{fill:R.fill},`cell-${ue}`))})]})})})]}),e.jsxs(Fe,{children:[e.jsxs(ts,{children:[e.jsx(as,{children:"模型详细统计"}),e.jsx(et,{children:"请求数、花费和性能"})]}),e.jsx(xs,{children:e.jsx(Ze,{className:"h-[300px] sm:h-[400px]",children:e.jsx("div",{className:"space-y-3",children:A.map((R,ue)=>e.jsxs("div",{className:"p-4 rounded-lg border bg-card hover:bg-accent/50 transition-colors",children:[e.jsxs("div",{className:"flex items-center justify-between mb-2",children:[e.jsx("h4",{className:"font-semibold text-sm truncate flex-1 min-w-0",children:R.model_name}),e.jsx("div",{className:"w-3 h-3 rounded-full ml-2 flex-shrink-0",style:{backgroundColor:`hsl(var(--chart-${ue%5+1}))`}})]}),e.jsxs("div",{className:"grid grid-cols-2 gap-2 text-xs",children:[e.jsxs("div",{children:[e.jsx("span",{className:"text-muted-foreground",children:"请求数:"}),e.jsx("span",{className:"ml-1 font-medium",children:R.request_count.toLocaleString()})]}),e.jsxs("div",{children:[e.jsx("span",{className:"text-muted-foreground",children:"花费:"}),e.jsxs("span",{className:"ml-1 font-medium",children:["¥",R.total_cost.toFixed(2)]})]}),e.jsxs("div",{children:[e.jsx("span",{className:"text-muted-foreground",children:"Tokens:"}),e.jsxs("span",{className:"ml-1 font-medium",children:[(R.total_tokens/1e3).toFixed(1),"K"]})]}),e.jsxs("div",{children:[e.jsx("span",{className:"text-muted-foreground",children:"平均耗时:"}),e.jsxs("span",{className:"ml-1 font-medium",children:[R.avg_response_time.toFixed(2),"s"]})]})]})]},ue))})})})]})]})}),e.jsx(Ts,{value:"activity",children:e.jsxs(Fe,{children:[e.jsxs(ts,{children:[e.jsx(as,{children:"最近活动"}),e.jsx(et,{children:"最新的API调用记录"})]}),e.jsx(xs,{children:e.jsx(Ze,{className:"h-[400px] sm:h-[500px]",children:e.jsx("div",{className:"space-y-2",children:je.map((R,ue)=>e.jsxs("div",{className:"p-3 sm:p-4 rounded-lg border bg-card hover:bg-accent/50 transition-colors",children:[e.jsxs("div",{className:"flex flex-col sm:flex-row sm:items-center justify-between gap-2 mb-2",children:[e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsx("div",{className:"font-medium text-sm truncate",children:R.model}),e.jsx("div",{className:"text-xs text-muted-foreground",children:R.request_type})]}),e.jsx("div",{className:"text-xs text-muted-foreground flex-shrink-0",children:D(R.timestamp)})]}),e.jsxs("div",{className:"grid grid-cols-2 sm:grid-cols-4 gap-2 text-xs",children:[e.jsxs("div",{children:[e.jsx("span",{className:"text-muted-foreground",children:"Tokens:"}),e.jsx("span",{className:"ml-1",children:R.tokens})]}),e.jsxs("div",{children:[e.jsx("span",{className:"text-muted-foreground",children:"花费:"}),e.jsxs("span",{className:"ml-1",children:["¥",R.cost.toFixed(4)]})]}),e.jsxs("div",{children:[e.jsx("span",{className:"text-muted-foreground",children:"耗时:"}),e.jsxs("span",{className:"ml-1",children:[R.time_cost.toFixed(2),"s"]})]}),e.jsxs("div",{children:[e.jsx("span",{className:"text-muted-foreground",children:"状态:"}),e.jsx("span",{className:`ml-1 ${R.status==="success"?"text-green-600":"text-red-600"}`,children:R.status})]})]})]},ue))})})})]})}),e.jsx(Ts,{value:"daily",children:e.jsxs(Fe,{children:[e.jsxs(ts,{children:[e.jsx(as,{children:"每日统计"}),e.jsx(et,{children:"最近7天的数据汇总"})]}),e.jsx(xs,{children:e.jsx(Xn,{config:{requests:{label:"请求数",color:"hsl(var(--chart-1))"},cost:{label:"花费(¥)",color:"hsl(var(--chart-2))"}},className:"h-[400px] sm:h-[500px] w-full aspect-auto",children:e.jsxs(vu,{data:fe,children:[e.jsx(Mc,{strokeDasharray:"3 3",stroke:"hsl(var(--muted-foreground) / 0.2)"}),e.jsx(Dc,{dataKey:"timestamp",tickFormatter:R=>{const ue=new Date(R);return`${ue.getMonth()+1}/${ue.getDate()}`},stroke:"hsl(var(--muted-foreground))",tick:{fill:"hsl(var(--muted-foreground))"}}),e.jsx(Pr,{yAxisId:"left",stroke:"hsl(var(--muted-foreground))",tick:{fill:"hsl(var(--muted-foreground))"}}),e.jsx(Pr,{yAxisId:"right",orientation:"right",stroke:"hsl(var(--muted-foreground))",tick:{fill:"hsl(var(--muted-foreground))"}}),e.jsx(ei,{content:e.jsx(Jn,{labelFormatter:R=>new Date(R).toLocaleDateString("zh-CN")})}),e.jsx(x0,{content:e.jsx(Eg,{})}),e.jsx(Oc,{yAxisId:"left",dataKey:"requests",fill:"var(--color-requests)"}),e.jsx(Oc,{yAxisId:"right",dataKey:"cost",fill:"var(--color-cost)"})]})})})]})})]})]})})}const y0={theme:"system",setTheme:()=>null},zg=u.createContext(y0),Yu=()=>{const n=u.useContext(zg);if(n===void 0)throw new Error("useTheme must be used within a ThemeProvider");return n},w0=(n,r,i)=>{const d=document.documentElement.classList.contains("no-animations");if(!document.startViewTransition||d){r(n);return}const m=i.clientX,x=i.clientY,f=Math.hypot(Math.max(m,innerWidth-m),Math.max(x,innerHeight-x));document.startViewTransition(()=>{r(n)}).ready.then(()=>{document.documentElement.animate({clipPath:[`circle(0px at ${m}px ${x}px)`,`circle(${f}px at ${m}px ${x}px)`]},{duration:500,easing:"ease-in-out",pseudoElement:"::view-transition-new(root)"})})},Ag=u.createContext(void 0),Mg=()=>{const n=u.useContext(Ag);if(n===void 0)throw new Error("useAnimation must be used within an AnimationProvider");return n},$e=u.forwardRef(({className:n,...r},i)=>e.jsx(Ap,{className:$("peer inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input",n),...r,ref:i,children:e.jsx(eN,{className:$("pointer-events-none block h-4 w-4 rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-4 data-[state=unchecked]:translate-x-0")})}));$e.displayName=Ap.displayName;const _0=tr("text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"),C=u.forwardRef(({className:n,...r},i)=>e.jsx(Qp,{ref:i,className:$(_0(),n),...r}));C.displayName=Qp.displayName;const ie=u.forwardRef(({className:n,type:r,...i},d)=>e.jsx("input",{type:r,className:$("flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-base shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",n),ref:d,...i}));ie.displayName="Input";const S0=[{id:"minLength",label:"长度至少 10 位",description:"Token 长度必须大于等于 10 个字符",validate:n=>n.length>=10},{id:"hasUppercase",label:"包含大写字母",description:"至少包含一个大写字母 (A-Z)",validate:n=>/[A-Z]/.test(n)},{id:"hasLowercase",label:"包含小写字母",description:"至少包含一个小写字母 (a-z)",validate:n=>/[a-z]/.test(n)},{id:"hasSpecialChar",label:"包含特殊符号",description:"至少包含一个特殊符号 (!@#$%^&*()_+-=[]{}|;:,.<>?/)",validate:n=>/[!@#$%^&*()_+\-=[\]{}|;:,.<>?/]/.test(n)}];function C0(n){const r=S0.map(d=>({id:d.id,label:d.label,description:d.description,passed:d.validate(n)}));return{isValid:r.every(d=>d.passed),rules:r}}const Zc="0.12.0 Beta",Ku="MaiBot Dashboard",k0=`${Ku} v${Zc}`,T0=(n="v")=>`${n}${Zc}`,Vt={THEME:"maibot-ui-theme",ACCENT_COLOR:"accent-color",ENABLE_ANIMATIONS:"maibot-animations",ENABLE_WAVES_BACKGROUND:"maibot-waves-background",LOG_CACHE_SIZE:"maibot-log-cache-size",LOG_AUTO_SCROLL:"maibot-log-auto-scroll",LOG_FONT_SIZE:"maibot-log-font-size",LOG_LINE_SPACING:"maibot-log-line-spacing",DATA_SYNC_INTERVAL:"maibot-data-sync-interval",WS_RECONNECT_INTERVAL:"maibot-ws-reconnect-interval",WS_MAX_RECONNECT_ATTEMPTS:"maibot-ws-max-reconnect-attempts",COMPLETED_TOURS:"maibot-completed-tours"},Da={theme:"system",accentColor:"blue",enableAnimations:!0,enableWavesBackground:!0,logCacheSize:1e3,logAutoScroll:!0,logFontSize:"xs",logLineSpacing:4,dataSyncInterval:30,wsReconnectInterval:3e3,wsMaxReconnectAttempts:10};function nt(n){const r=Dg(n),i=localStorage.getItem(r);if(i===null)return Da[n];const d=Da[n];if(typeof d=="boolean")return i==="true";if(typeof d=="number"){const m=parseFloat(i);return isNaN(m)?d:m}return i}function Zn(n,r){const i=Dg(n);localStorage.setItem(i,String(r)),window.dispatchEvent(new CustomEvent("maibot-settings-change",{detail:{key:n,value:r}}))}function E0(){return{theme:nt("theme"),accentColor:nt("accentColor"),enableAnimations:nt("enableAnimations"),enableWavesBackground:nt("enableWavesBackground"),logCacheSize:nt("logCacheSize"),logAutoScroll:nt("logAutoScroll"),logFontSize:nt("logFontSize"),logLineSpacing:nt("logLineSpacing"),dataSyncInterval:nt("dataSyncInterval"),wsReconnectInterval:nt("wsReconnectInterval"),wsMaxReconnectAttempts:nt("wsMaxReconnectAttempts")}}function z0(){const n=E0(),r=localStorage.getItem(Vt.COMPLETED_TOURS),i=r?JSON.parse(r):[];return{...n,completedTours:i}}function A0(n){const r=[],i=[];for(const[d,m]of Object.entries(n)){if(d==="completedTours"){Array.isArray(m)?(localStorage.setItem(Vt.COMPLETED_TOURS,JSON.stringify(m)),r.push("completedTours")):i.push("completedTours");continue}if(d in Da){const x=d,f=Da[x];if(typeof m==typeof f){if(x==="theme"&&!["light","dark","system"].includes(m)){i.push(d);continue}if(x==="logFontSize"&&!["xs","sm","base"].includes(m)){i.push(d);continue}Zn(x,m),r.push(d)}else i.push(d)}else i.push(d)}return{success:r.length>0,imported:r,skipped:i}}function M0(){for(const n of Object.keys(Da))Zn(n,Da[n]);localStorage.removeItem(Vt.COMPLETED_TOURS),window.dispatchEvent(new CustomEvent("maibot-settings-reset"))}function D0(){const n=[],r=[],i=[];for(let d=0;dd.size-i.size),{used:n,items:localStorage.length,details:r}}function O0(n){if(n===0)return"0 B";const r=1024,i=["B","KB","MB"],d=Math.floor(Math.log(n)/Math.log(r));return parseFloat((n/Math.pow(r,d)).toFixed(2))+" "+i[d]}function Dg(n){return{theme:Vt.THEME,accentColor:Vt.ACCENT_COLOR,enableAnimations:Vt.ENABLE_ANIMATIONS,enableWavesBackground:Vt.ENABLE_WAVES_BACKGROUND,logCacheSize:Vt.LOG_CACHE_SIZE,logAutoScroll:Vt.LOG_AUTO_SCROLL,logFontSize:Vt.LOG_FONT_SIZE,logLineSpacing:Vt.LOG_LINE_SPACING,dataSyncInterval:Vt.DATA_SYNC_INTERVAL,wsReconnectInterval:Vt.WS_RECONNECT_INTERVAL,wsMaxReconnectAttempts:Vt.WS_MAX_RECONNECT_ATTEMPTS}[n]}const pa=u.forwardRef(({className:n,...r},i)=>e.jsxs(Mp,{ref:i,className:$("relative flex w-full touch-none select-none items-center",n),...r,children:[e.jsx(sN,{className:"relative h-1.5 w-full grow overflow-hidden rounded-full bg-primary/20",children:e.jsx(tN,{className:"absolute h-full bg-primary"})}),e.jsx(aN,{className:"block h-4 w-4 rounded-full border border-primary/50 bg-background shadow transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50"})]}));pa.displayName=Mp.displayName;class R0{ws=null;reconnectTimeout=null;reconnectAttempts=0;heartbeatInterval=null;logCallbacks=new Set;connectionCallbacks=new Set;isConnected=!1;logCache=[];getMaxCacheSize(){return nt("logCacheSize")}getMaxReconnectAttempts(){return nt("wsMaxReconnectAttempts")}getReconnectInterval(){return nt("wsReconnectInterval")}getWebSocketUrl(){{const r=window.location.protocol==="https:"?"wss:":"ws:",i=window.location.host;return`${r}//${i}/ws/logs`}}connect(){if(this.ws?.readyState===WebSocket.OPEN||this.ws?.readyState===WebSocket.CONNECTING)return;const r=this.getWebSocketUrl();try{this.ws=new WebSocket(r),this.ws.onopen=()=>{this.isConnected=!0,this.reconnectAttempts=0,this.notifyConnection(!0),this.startHeartbeat()},this.ws.onmessage=i=>{try{if(i.data==="pong")return;const d=JSON.parse(i.data);this.notifyLog(d)}catch(d){console.error("解析日志消息失败:",d)}},this.ws.onerror=i=>{console.error("❌ WebSocket 错误:",i),this.isConnected=!1,this.notifyConnection(!1)},this.ws.onclose=()=>{this.isConnected=!1,this.notifyConnection(!1),this.stopHeartbeat(),this.attemptReconnect()}}catch(i){console.error("创建 WebSocket 连接失败:",i),this.attemptReconnect()}}attemptReconnect(){const r=this.getMaxReconnectAttempts();if(this.reconnectAttempts>=r)return;this.reconnectAttempts+=1;const i=this.getReconnectInterval(),d=Math.min(i*this.reconnectAttempts,3e4);this.reconnectTimeout=window.setTimeout(()=>{this.connect()},d)}startHeartbeat(){this.heartbeatInterval=window.setInterval(()=>{this.ws?.readyState===WebSocket.OPEN&&this.ws.send("ping")},3e4)}stopHeartbeat(){this.heartbeatInterval!==null&&(clearInterval(this.heartbeatInterval),this.heartbeatInterval=null)}disconnect(){this.reconnectTimeout!==null&&(clearTimeout(this.reconnectTimeout),this.reconnectTimeout=null),this.stopHeartbeat(),this.ws&&(this.ws.close(),this.ws=null),this.isConnected=!1,this.reconnectAttempts=0}onLog(r){return this.logCallbacks.add(r),()=>this.logCallbacks.delete(r)}onConnectionChange(r){return this.connectionCallbacks.add(r),r(this.isConnected),()=>this.connectionCallbacks.delete(r)}notifyLog(r){if(!this.logCache.some(d=>d.id===r.id)){this.logCache.push(r);const d=this.getMaxCacheSize();this.logCache.length>d&&(this.logCache=this.logCache.slice(-d)),this.logCallbacks.forEach(m=>{try{m(r)}catch(x){console.error("日志回调执行失败:",x)}})}}notifyConnection(r){this.connectionCallbacks.forEach(i=>{try{i(r)}catch(d){console.error("连接状态回调执行失败:",d)}})}getAllLogs(){return[...this.logCache]}clearLogs(){this.logCache=[]}getConnectionStatus(){return this.isConnected}}const tn=new R0;typeof window<"u"&&tn.connect();const qs=CN,Xu=kN,L0=_N,Og=u.forwardRef(({className:n,...r},i)=>e.jsx(Ip,{ref:i,className:$("fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",n),...r}));Og.displayName=Ip.displayName;const Ls=u.forwardRef(({className:n,children:r,preventOutsideClose:i=!1,...d},m)=>e.jsxs(L0,{children:[e.jsx(Og,{}),e.jsxs(Yp,{ref:m,className:$("fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",n),onPointerDownOutside:i?x=>x.preventDefault():void 0,onInteractOutside:i?x=>x.preventDefault():void 0,...d,children:[r,e.jsxs(SN,{className:"absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground",children:[e.jsx(rl,{className:"h-4 w-4"}),e.jsx("span",{className:"sr-only",children:"Close"})]})]})]}));Ls.displayName=Yp.displayName;const Us=({className:n,...r})=>e.jsx("div",{className:$("flex flex-col space-y-1.5 text-center sm:text-left",n),...r});Us.displayName="DialogHeader";const st=({className:n,...r})=>e.jsx("div",{className:$("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",n),...r});st.displayName="DialogFooter";const Bs=u.forwardRef(({className:n,...r},i)=>e.jsx(Kp,{ref:i,className:$("text-lg font-semibold leading-none tracking-tight",n),...r}));Bs.displayName=Kp.displayName;const Ps=u.forwardRef(({className:n,...r},i)=>e.jsx(Xp,{ref:i,className:$("text-sm text-muted-foreground",n),...r}));Ps.displayName=Xp.displayName;const hs=nN,rt=rN,U0=lN,Rg=u.forwardRef(({className:n,...r},i)=>e.jsx(Dp,{className:$("fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",n),...r,ref:i}));Rg.displayName=Dp.displayName;const ls=u.forwardRef(({className:n,...r},i)=>e.jsxs(U0,{children:[e.jsx(Rg,{}),e.jsx(Op,{ref:i,className:$("fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",n),...r})]}));ls.displayName=Op.displayName;const ns=({className:n,...r})=>e.jsx("div",{className:$("flex flex-col space-y-2 text-center sm:text-left",n),...r});ns.displayName="AlertDialogHeader";const rs=({className:n,...r})=>e.jsx("div",{className:$("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",n),...r});rs.displayName="AlertDialogFooter";const is=u.forwardRef(({className:n,...r},i)=>e.jsx(Rp,{ref:i,className:$("text-lg font-semibold",n),...r}));is.displayName=Rp.displayName;const cs=u.forwardRef(({className:n,...r},i)=>e.jsx(Lp,{ref:i,className:$("text-sm text-muted-foreground",n),...r}));cs.displayName=Lp.displayName;const os=u.forwardRef(({className:n,...r},i)=>e.jsx(Up,{ref:i,className:$(ui(),n),...r}));os.displayName=Up.displayName;const ds=u.forwardRef(({className:n,...r},i)=>e.jsx(Bp,{ref:i,className:$(ui({variant:"outline"}),"mt-2 sm:mt-0",n),...r}));ds.displayName=Bp.displayName;function B0(){return e.jsxs("div",{className:"space-y-4 sm:space-y-6 p-4 sm:p-6",children:[e.jsx("div",{className:"flex flex-col sm:flex-row sm:items-center justify-between gap-4",children:e.jsxs("div",{children:[e.jsx("h1",{className:"text-2xl sm:text-3xl font-bold",children:"系统设置"}),e.jsx("p",{className:"text-muted-foreground mt-1 sm:mt-2 text-sm sm:text-base",children:"管理您的应用偏好设置"})]})}),e.jsxs(ga,{defaultValue:"appearance",className:"w-full",children:[e.jsxs(la,{className:"grid w-full grid-cols-2 sm:grid-cols-4 gap-0.5 sm:gap-1 h-auto p-1",children:[e.jsxs(ss,{value:"appearance",className:"gap-1 sm:gap-2 text-xs sm:text-sm px-2 sm:px-3 py-2",children:[e.jsx(ZN,{className:"h-3.5 w-3.5 sm:h-4 sm:w-4",strokeWidth:2,fill:"none"}),e.jsx("span",{children:"外观"})]}),e.jsxs(ss,{value:"security",className:"gap-1 sm:gap-2 text-xs sm:text-sm px-2 sm:px-3 py-2",children:[e.jsx(PN,{className:"h-3.5 w-3.5 sm:h-4 sm:w-4",strokeWidth:2,fill:"none"}),e.jsx("span",{children:"安全"})]}),e.jsxs(ss,{value:"other",className:"gap-1 sm:gap-2 text-xs sm:text-sm px-2 sm:px-3 py-2",children:[e.jsx(ar,{className:"h-3.5 w-3.5 sm:h-4 sm:w-4",strokeWidth:2,fill:"none"}),e.jsx("span",{children:"其他"})]}),e.jsxs(ss,{value:"about",className:"gap-1 sm:gap-2 text-xs sm:text-sm px-2 sm:px-3 py-2",children:[e.jsx(Ra,{className:"h-3.5 w-3.5 sm:h-4 sm:w-4",strokeWidth:2,fill:"none"}),e.jsx("span",{children:"关于"})]})]}),e.jsxs(Ze,{className:"h-[calc(100vh-240px)] sm:h-[calc(100vh-280px)] mt-4 sm:mt-6",children:[e.jsx(Ts,{value:"appearance",className:"mt-0",children:e.jsx(H0,{})}),e.jsx(Ts,{value:"security",className:"mt-0",children:e.jsx(q0,{})}),e.jsx(Ts,{value:"other",className:"mt-0",children:e.jsx(G0,{})}),e.jsx(Ts,{value:"about",className:"mt-0",children:e.jsx($0,{})})]})]})]})}function cp(n){const r=document.documentElement,d={blue:{hsl:"221.2 83.2% 53.3%",darkHsl:"217.2 91.2% 59.8%",gradient:null},purple:{hsl:"271 91% 65%",darkHsl:"270 95% 75%",gradient:null},green:{hsl:"142 71% 45%",darkHsl:"142 76% 36%",gradient:null},orange:{hsl:"25 95% 53%",darkHsl:"20 90% 48%",gradient:null},pink:{hsl:"330 81% 60%",darkHsl:"330 85% 70%",gradient:null},red:{hsl:"0 84% 60%",darkHsl:"0 90% 70%",gradient:null},"gradient-sunset":{hsl:"15 95% 60%",darkHsl:"15 95% 65%",gradient:"linear-gradient(135deg, hsl(25 95% 53%) 0%, hsl(330 81% 60%) 100%)"},"gradient-ocean":{hsl:"200 90% 55%",darkHsl:"200 90% 60%",gradient:"linear-gradient(135deg, hsl(221.2 83.2% 53.3%) 0%, hsl(189 94% 43%) 100%)"},"gradient-forest":{hsl:"150 70% 45%",darkHsl:"150 75% 40%",gradient:"linear-gradient(135deg, hsl(142 71% 45%) 0%, hsl(158 64% 52%) 100%)"},"gradient-aurora":{hsl:"310 85% 65%",darkHsl:"310 90% 70%",gradient:"linear-gradient(135deg, hsl(271 91% 65%) 0%, hsl(330 81% 60%) 100%)"},"gradient-fire":{hsl:"15 95% 55%",darkHsl:"15 95% 60%",gradient:"linear-gradient(135deg, hsl(0 84% 60%) 0%, hsl(25 95% 53%) 100%)"},"gradient-twilight":{hsl:"250 90% 60%",darkHsl:"250 95% 65%",gradient:"linear-gradient(135deg, hsl(239 84% 67%) 0%, hsl(271 91% 65%) 100%)"}}[n];if(d)r.style.setProperty("--primary",d.hsl),d.gradient?(r.style.setProperty("--primary-gradient",d.gradient),r.classList.add("has-gradient")):(r.style.removeProperty("--primary-gradient"),r.classList.remove("has-gradient"));else if(n.startsWith("#")){const m=x=>{x=x.replace("#","");const f=parseInt(x.substring(0,2),16)/255,p=parseInt(x.substring(2,4),16)/255,g=parseInt(x.substring(4,6),16)/255,b=Math.max(f,p,g),j=Math.min(f,p,g);let y=0,N=0;const k=(b+j)/2;if(b!==j){const w=b-j;switch(N=k>.5?w/(2-b-j):w/(b+j),b){case f:y=((p-g)/w+(plocalStorage.getItem("accent-color")||"blue");u.useEffect(()=>{const b=localStorage.getItem("accent-color")||"blue";cp(b)},[]);const g=b=>{p(b),localStorage.setItem("accent-color",b),cp(b)};return e.jsxs("div",{className:"space-y-6 sm:space-y-8",children:[e.jsxs("div",{children:[e.jsx("h3",{className:"text-base sm:text-lg font-semibold mb-3 sm:mb-4",children:"主题模式"}),e.jsxs("div",{className:"grid grid-cols-1 sm:grid-cols-3 gap-3 sm:gap-4",children:[e.jsx(ku,{value:"light",current:n,onChange:r,label:"浅色",description:"始终使用浅色主题"}),e.jsx(ku,{value:"dark",current:n,onChange:r,label:"深色",description:"始终使用深色主题"}),e.jsx(ku,{value:"system",current:n,onChange:r,label:"跟随系统",description:"根据系统设置自动切换"})]})]}),e.jsxs("div",{children:[e.jsx("h3",{className:"text-base sm:text-lg font-semibold mb-3 sm:mb-4",children:"主题色"}),e.jsxs("div",{className:"space-y-3 sm:space-y-4",children:[e.jsxs("div",{children:[e.jsx("h4",{className:"text-xs sm:text-sm font-medium mb-2 sm:mb-3",children:"单色"}),e.jsxs("div",{className:"grid grid-cols-3 sm:grid-cols-6 gap-2 sm:gap-3",children:[e.jsx(fa,{value:"blue",current:f,onChange:g,label:"蓝色",colorClass:"bg-blue-500"}),e.jsx(fa,{value:"purple",current:f,onChange:g,label:"紫色",colorClass:"bg-purple-500"}),e.jsx(fa,{value:"green",current:f,onChange:g,label:"绿色",colorClass:"bg-green-500"}),e.jsx(fa,{value:"orange",current:f,onChange:g,label:"橙色",colorClass:"bg-orange-500"}),e.jsx(fa,{value:"pink",current:f,onChange:g,label:"粉色",colorClass:"bg-pink-500"}),e.jsx(fa,{value:"red",current:f,onChange:g,label:"红色",colorClass:"bg-red-500"})]})]}),e.jsxs("div",{children:[e.jsx("h4",{className:"text-xs sm:text-sm font-medium mb-2 sm:mb-3",children:"渐变色"}),e.jsxs("div",{className:"grid grid-cols-3 sm:grid-cols-6 gap-2 sm:gap-3",children:[e.jsx(fa,{value:"gradient-sunset",current:f,onChange:g,label:"日落",colorClass:"bg-gradient-to-r from-orange-500 to-pink-500"}),e.jsx(fa,{value:"gradient-ocean",current:f,onChange:g,label:"海洋",colorClass:"bg-gradient-to-r from-blue-500 to-cyan-500"}),e.jsx(fa,{value:"gradient-forest",current:f,onChange:g,label:"森林",colorClass:"bg-gradient-to-r from-green-500 to-emerald-500"}),e.jsx(fa,{value:"gradient-aurora",current:f,onChange:g,label:"极光",colorClass:"bg-gradient-to-r from-purple-500 to-pink-500"}),e.jsx(fa,{value:"gradient-fire",current:f,onChange:g,label:"烈焰",colorClass:"bg-gradient-to-r from-red-500 to-orange-500"}),e.jsx(fa,{value:"gradient-twilight",current:f,onChange:g,label:"暮光",colorClass:"bg-gradient-to-r from-indigo-500 to-purple-500"})]})]}),e.jsxs("div",{children:[e.jsx("h4",{className:"text-xs sm:text-sm font-medium mb-2 sm:mb-3",children:"自定义颜色"}),e.jsxs("div",{className:"flex flex-col sm:flex-row gap-3 sm:gap-4",children:[e.jsx("div",{className:"flex-1",children:e.jsx("input",{type:"color",value:f.startsWith("#")?f:"#3b82f6",onChange:b=>g(b.target.value),className:"h-10 sm:h-12 w-full rounded-lg border-2 border-border cursor-pointer",title:"选择自定义颜色"})}),e.jsx("div",{className:"flex-1",children:e.jsx(ie,{type:"text",value:f,onChange:b=>g(b.target.value),placeholder:"#3b82f6",className:"font-mono text-sm"})})]}),e.jsx("p",{className:"text-[10px] sm:text-xs text-muted-foreground mt-2",children:"点击色块选择颜色,或手动输入 HEX 颜色代码"})]})]})]}),e.jsxs("div",{children:[e.jsx("h3",{className:"text-base sm:text-lg font-semibold mb-3 sm:mb-4",children:"动画效果"}),e.jsxs("div",{className:"space-y-2 sm:space-y-3",children:[e.jsx("div",{className:"rounded-lg border bg-card p-3 sm:p-4",children:e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"space-y-0.5 flex-1",children:[e.jsx(C,{htmlFor:"animations",className:"text-base font-medium cursor-pointer",children:"启用动画效果"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"关闭后将禁用所有过渡动画和特效,提升性能"})]}),e.jsx($e,{id:"animations",checked:i,onCheckedChange:d})]})}),e.jsx("div",{className:"rounded-lg border bg-card p-4",children:e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"space-y-0.5 flex-1",children:[e.jsx(C,{htmlFor:"waves-background",className:"text-base font-medium cursor-pointer",children:"登录页波浪背景"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"关闭后登录页将使用纯色背景,适合低性能设备"})]}),e.jsx($e,{id:"waves-background",checked:m,onCheckedChange:x})]})})]})]})]})}function q0(){const n=va(),[r,i]=u.useState(""),[d,m]=u.useState(""),[x,f]=u.useState(!1),[p,g]=u.useState(!1),[b,j]=u.useState(!1),[y,N]=u.useState(!1),[k,w]=u.useState(!1),[U,O]=u.useState(!1),[B,Y]=u.useState(""),[L,z]=u.useState(!1),{toast:K}=$s(),I=u.useMemo(()=>C0(d),[d]),T=async he=>{if(!r){K({title:"无法复制",description:"Token 存储在安全 Cookie 中,请重新生成以获取新 Token",variant:"destructive"});return}try{await navigator.clipboard.writeText(he),w(!0),K({title:"复制成功",description:"Token 已复制到剪贴板"}),setTimeout(()=>w(!1),2e3)}catch{K({title:"复制失败",description:"请手动复制 Token",variant:"destructive"})}},A=async()=>{if(!d.trim()){K({title:"输入错误",description:"请输入新的 Token",variant:"destructive"});return}if(!I.isValid){const he=I.rules.filter(ve=>!ve.passed).map(ve=>ve.label).join(", ");K({title:"格式错误",description:`Token 不符合要求: ${he}`,variant:"destructive"});return}j(!0);try{const he=await fetch("/api/webui/auth/update",{method:"POST",headers:{"Content-Type":"application/json"},credentials:"include",body:JSON.stringify({new_token:d.trim()})}),ve=await he.json();he.ok&&ve.success?(m(""),i(d.trim()),K({title:"更新成功",description:"Access Token 已更新,即将跳转到登录页"}),setTimeout(()=>{n({to:"/auth"})},1500)):K({title:"更新失败",description:ve.message||"无法更新 Token",variant:"destructive"})}catch(he){console.error("更新 Token 错误:",he),K({title:"更新失败",description:"连接服务器失败",variant:"destructive"})}finally{j(!1)}},te=async()=>{N(!0);try{const he=await fetch("/api/webui/auth/regenerate",{method:"POST",headers:{"Content-Type":"application/json"},credentials:"include"}),ve=await he.json();he.ok&&ve.success?(i(ve.token),Y(ve.token),O(!0),z(!1),K({title:"生成成功",description:"新的 Access Token 已生成,请及时保存"})):K({title:"生成失败",description:ve.message||"无法生成新 Token",variant:"destructive"})}catch(he){console.error("生成 Token 错误:",he),K({title:"生成失败",description:"连接服务器失败",variant:"destructive"})}finally{N(!1)}},fe=async()=>{try{await navigator.clipboard.writeText(B),z(!0),K({title:"复制成功",description:"Token 已复制到剪贴板"})}catch{K({title:"复制失败",description:"请手动复制 Token",variant:"destructive"})}},je=()=>{O(!1),setTimeout(()=>{Y(""),z(!1)},300),setTimeout(()=>{n({to:"/auth"})},500)},pe=he=>{he||je()};return e.jsxs("div",{className:"space-y-4 sm:space-y-6",children:[e.jsx(qs,{open:U,onOpenChange:pe,children:e.jsxs(Ls,{className:"sm:max-w-md",children:[e.jsxs(Us,{children:[e.jsxs(Bs,{className:"flex items-center gap-2",children:[e.jsx(Ca,{className:"h-5 w-5 text-yellow-500"}),"新的 Access Token"]}),e.jsx(Ps,{children:"这是您的新 Token,请立即保存。关闭此窗口后将跳转到登录页面。"})]}),e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"rounded-lg border-2 border-primary/20 bg-primary/5 p-4",children:[e.jsx(C,{className:"text-xs text-muted-foreground mb-2 block",children:"您的新 Token (64位安全令牌)"}),e.jsx("div",{className:"font-mono text-sm break-all select-all bg-background p-3 rounded border",children:B})]}),e.jsx("div",{className:"rounded-lg border border-yellow-200 dark:border-yellow-900 bg-yellow-50 dark:bg-yellow-950/30 p-3",children:e.jsxs("div",{className:"flex gap-2",children:[e.jsx(Ca,{className:"h-4 w-4 text-yellow-600 dark:text-yellow-500 flex-shrink-0 mt-0.5"}),e.jsxs("div",{className:"text-sm text-yellow-800 dark:text-yellow-300 space-y-1",children:[e.jsx("p",{className:"font-semibold",children:"重要提示"}),e.jsxs("ul",{className:"list-disc list-inside space-y-0.5 text-xs",children:[e.jsx("li",{children:"此 Token 仅显示一次,关闭后无法再查看"}),e.jsx("li",{children:"请立即复制并保存到安全的位置"}),e.jsx("li",{children:"关闭窗口后将自动跳转到登录页面"}),e.jsx("li",{children:"请使用新 Token 重新登录系统"})]})]})]})})]}),e.jsxs(st,{className:"gap-2 sm:gap-0",children:[e.jsx(S,{variant:"outline",onClick:fe,className:"gap-2",children:L?e.jsxs(e.Fragment,{children:[e.jsx(Qt,{className:"h-4 w-4 text-green-500"}),"已复制"]}):e.jsxs(e.Fragment,{children:[e.jsx(Vc,{className:"h-4 w-4"}),"复制 Token"]})}),e.jsx(S,{onClick:je,children:"我已保存,关闭"})]})]})}),e.jsxs("div",{className:"rounded-lg border bg-card p-4 sm:p-6",children:[e.jsx("h3",{className:"text-base sm:text-lg font-semibold mb-3 sm:mb-4",children:"当前 Access Token"}),e.jsx("div",{className:"space-y-3 sm:space-y-4",children:e.jsxs("div",{className:"space-y-2",children:[e.jsx(C,{htmlFor:"current-token",className:"text-sm",children:"您的访问令牌"}),e.jsxs("div",{className:"flex flex-col sm:flex-row gap-2",children:[e.jsxs("div",{className:"relative flex-1",children:[e.jsx(ie,{id:"current-token",type:x?"text":"password",value:r||"••••••••••••••••••••••••••••••••",readOnly:!0,className:"pr-10 font-mono text-sm",placeholder:"Token 存储在安全 Cookie 中"}),e.jsx("button",{onClick:()=>{r?f(!x):K({title:"无法查看",description:'Token 存储在安全 Cookie 中,如需新 Token 请点击"重新生成"'})},className:"absolute right-2 top-1/2 -translate-y-1/2 p-1.5 hover:bg-accent rounded",title:x?"隐藏":"显示",children:x?e.jsx(ci,{className:"h-4 w-4 text-muted-foreground"}):e.jsx(Rt,{className:"h-4 w-4 text-muted-foreground"})})]}),e.jsxs("div",{className:"flex gap-2 w-full sm:w-auto",children:[e.jsx(S,{variant:"outline",size:"icon",onClick:()=>T(r),title:"复制到剪贴板",className:"flex-shrink-0",disabled:!r,children:k?e.jsx(Qt,{className:"h-4 w-4 text-green-500"}):e.jsx(Vc,{className:"h-4 w-4"})}),e.jsxs(hs,{children:[e.jsx(rt,{asChild:!0,children:e.jsxs(S,{variant:"outline",disabled:y,className:"gap-2 flex-1 sm:flex-none",children:[e.jsx(zt,{className:$("h-4 w-4",y&&"animate-spin")}),e.jsx("span",{className:"hidden sm:inline",children:"重新生成"}),e.jsx("span",{className:"sm:hidden",children:"生成"})]})}),e.jsxs(ls,{children:[e.jsxs(ns,{children:[e.jsx(is,{children:"确认重新生成 Token"}),e.jsx(cs,{children:"这将生成一个新的 64 位安全令牌,并使当前 Token 立即失效。 您需要使用新 Token 重新登录系统。此操作不可撤销,确定要继续吗?"})]}),e.jsxs(rs,{children:[e.jsx(ds,{children:"取消"}),e.jsx(os,{onClick:te,children:"确认生成"})]})]})]})]})]}),e.jsx("p",{className:"text-[10px] sm:text-xs text-muted-foreground",children:"请妥善保管您的 Access Token,不要泄露给他人"})]})})]}),e.jsxs("div",{className:"rounded-lg border bg-card p-4 sm:p-6",children:[e.jsx("h3",{className:"text-base sm:text-lg font-semibold mb-3 sm:mb-4",children:"自定义 Access Token"}),e.jsxs("div",{className:"space-y-3 sm:space-y-4",children:[e.jsxs("div",{className:"space-y-2",children:[e.jsx(C,{htmlFor:"new-token",className:"text-sm",children:"新的访问令牌"}),e.jsxs("div",{className:"relative",children:[e.jsx(ie,{id:"new-token",type:p?"text":"password",value:d,onChange:he=>m(he.target.value),className:"pr-10 font-mono text-sm",placeholder:"输入自定义 Token"}),e.jsx("button",{onClick:()=>g(!p),className:"absolute right-2 top-1/2 -translate-y-1/2 p-1.5 hover:bg-accent rounded",title:p?"隐藏":"显示",children:p?e.jsx(ci,{className:"h-4 w-4 text-muted-foreground"}):e.jsx(Rt,{className:"h-4 w-4 text-muted-foreground"})})]}),d&&e.jsxs("div",{className:"mt-3 space-y-2 p-3 rounded-lg bg-muted/50",children:[e.jsx("p",{className:"text-sm font-medium text-foreground",children:"Token 安全要求:"}),e.jsx("div",{className:"space-y-1.5",children:I.rules.map(he=>e.jsxs("div",{className:"flex items-center gap-2 text-sm",children:[he.passed?e.jsx(aa,{className:"h-4 w-4 text-green-500 flex-shrink-0"}):e.jsx(mg,{className:"h-4 w-4 text-muted-foreground flex-shrink-0"}),e.jsx("span",{className:$(he.passed?"text-green-600 dark:text-green-400":"text-muted-foreground"),children:he.label})]},he.id))}),I.isValid&&e.jsx("div",{className:"mt-2 pt-2 border-t border-border",children:e.jsxs("div",{className:"flex items-center gap-2 text-sm text-green-600 dark:text-green-400",children:[e.jsx(Qt,{className:"h-4 w-4"}),e.jsx("span",{className:"font-medium",children:"Token 格式正确,可以使用"})]})})]})]}),e.jsx(S,{onClick:A,disabled:b||!I.isValid||!d,className:"w-full sm:w-auto",children:b?"更新中...":"更新自定义 Token"})]})]}),e.jsxs("div",{className:"rounded-lg border border-yellow-200 dark:border-yellow-900 bg-yellow-50 dark:bg-yellow-950/30 p-3 sm:p-4",children:[e.jsx("h4",{className:"text-sm sm:text-base font-semibold text-yellow-900 dark:text-yellow-200 mb-2",children:"安全提示"}),e.jsxs("ul",{className:"text-xs sm:text-sm text-yellow-800 dark:text-yellow-300 space-y-1 list-disc list-inside",children:[e.jsx("li",{children:"重新生成 Token 会创建系统随机生成的 64 位安全令牌"}),e.jsx("li",{children:"自定义 Token 必须满足所有安全要求才能使用"}),e.jsx("li",{children:"更新 Token 后,旧的 Token 将立即失效"}),e.jsx("li",{children:"请在安全的环境下查看和复制 Token"}),e.jsx("li",{children:"如果怀疑 Token 泄露,请立即重新生成或更新"}),e.jsx("li",{children:"建议使用系统生成的 Token 以获得最高安全性"})]})]})]})}function G0(){const n=va(),{toast:r}=$s(),[i,d]=u.useState(!1),[m,x]=u.useState(!1),[f,p]=u.useState(()=>nt("logCacheSize")),[g,b]=u.useState(()=>nt("wsReconnectInterval")),[j,y]=u.useState(()=>nt("wsMaxReconnectAttempts")),[N,k]=u.useState(()=>nt("dataSyncInterval")),[w,U]=u.useState(()=>ip()),[O,B]=u.useState(!1),[Y,L]=u.useState(!1),z=u.useRef(null);if(m)throw new Error("这是一个手动触发的测试错误,用于验证错误边界组件是否正常工作。");const K=()=>{U(ip())},I=D=>{const J=D[0];p(J),Zn("logCacheSize",J)},T=D=>{const J=D[0];b(J),Zn("wsReconnectInterval",J)},A=D=>{const J=D[0];y(J),Zn("wsMaxReconnectAttempts",J)},te=D=>{const J=D[0];k(J),Zn("dataSyncInterval",J)},fe=()=>{tn.clearLogs(),r({title:"日志已清除",description:"日志缓存已清空"})},je=()=>{const D=D0();K(),r({title:"缓存已清除",description:`已清除 ${D.clearedKeys.length} 项缓存数据`})},pe=()=>{B(!0);try{const D=z0(),J=JSON.stringify(D,null,2),q=new Blob([J],{type:"application/json"}),se=URL.createObjectURL(q),R=document.createElement("a");R.href=se,R.download=`maibot-webui-settings-${new Date().toISOString().slice(0,10)}.json`,document.body.appendChild(R),R.click(),document.body.removeChild(R),URL.revokeObjectURL(se),r({title:"导出成功",description:"设置已导出为 JSON 文件"})}catch(D){console.error("导出设置失败:",D),r({title:"导出失败",description:"无法导出设置",variant:"destructive"})}finally{B(!1)}},he=D=>{const J=D.target.files?.[0];if(!J)return;L(!0);const q=new FileReader;q.onload=se=>{try{const R=se.target?.result,ue=JSON.parse(R),me=A0(ue);me.success?(p(nt("logCacheSize")),b(nt("wsReconnectInterval")),y(nt("wsMaxReconnectAttempts")),k(nt("dataSyncInterval")),K(),r({title:"导入成功",description:`成功导入 ${me.imported.length} 项设置${me.skipped.length>0?`,跳过 ${me.skipped.length} 项`:""}`}),(me.imported.includes("theme")||me.imported.includes("accentColor"))&&r({title:"提示",description:"部分设置需要刷新页面才能完全生效"})):r({title:"导入失败",description:"没有有效的设置项可导入",variant:"destructive"})}catch(R){console.error("导入设置失败:",R),r({title:"导入失败",description:"文件格式无效",variant:"destructive"})}finally{L(!1),z.current&&(z.current.value="")}},q.readAsText(J)},ve=()=>{M0(),p(Da.logCacheSize),b(Da.wsReconnectInterval),y(Da.wsMaxReconnectAttempts),k(Da.dataSyncInterval),K(),r({title:"已重置",description:"所有设置已恢复为默认值,刷新页面以应用更改"})},be=async()=>{d(!0);try{const D=localStorage.getItem("access-token"),J=await fetch("/api/webui/setup/reset",{method:"POST",headers:{Authorization:`Bearer ${D}`}}),q=await J.json();J.ok&&q.success?(r({title:"重置成功",description:"即将进入初次配置向导"}),setTimeout(()=>{n({to:"/setup"})},1e3)):r({title:"重置失败",description:q.message||"无法重置配置状态",variant:"destructive"})}catch(D){console.error("重置配置状态错误:",D),r({title:"重置失败",description:"连接服务器失败",variant:"destructive"})}finally{d(!1)}};return e.jsxs("div",{className:"space-y-4 sm:space-y-6",children:[e.jsxs("div",{className:"rounded-lg border bg-card p-4 sm:p-6",children:[e.jsxs("h3",{className:"text-base sm:text-lg font-semibold mb-3 sm:mb-4 flex items-center gap-2",children:[e.jsx(Fc,{className:"h-5 w-5"}),"性能与存储"]}),e.jsxs("div",{className:"space-y-4 sm:space-y-5",children:[e.jsxs("div",{className:"rounded-lg bg-muted/50 p-3 sm:p-4",children:[e.jsxs("div",{className:"flex items-center justify-between mb-2",children:[e.jsxs("span",{className:"text-sm font-medium flex items-center gap-2",children:[e.jsx(WN,{className:"h-4 w-4"}),"本地存储使用"]}),e.jsx(S,{variant:"ghost",size:"sm",onClick:K,className:"h-7 px-2",children:e.jsx(zt,{className:"h-3 w-3"})})]}),e.jsx("div",{className:"text-2xl font-bold text-primary",children:O0(w.used)}),e.jsxs("p",{className:"text-xs text-muted-foreground mt-1",children:[w.items," 个存储项"]})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(C,{className:"text-sm font-medium",children:"日志缓存大小"}),e.jsxs("span",{className:"text-sm text-muted-foreground",children:[f," 条"]})]}),e.jsx(pa,{value:[f],onValueChange:I,min:100,max:5e3,step:100,className:"w-full"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"控制日志查看器最多缓存的日志条数,较大的值会占用更多内存"})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(C,{className:"text-sm font-medium",children:"首页数据刷新间隔"}),e.jsxs("span",{className:"text-sm text-muted-foreground",children:[N," 秒"]})]}),e.jsx(pa,{value:[N],onValueChange:te,min:10,max:120,step:5,className:"w-full"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"控制首页统计数据的自动刷新间隔"})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(C,{className:"text-sm font-medium",children:"WebSocket 重连间隔"}),e.jsxs("span",{className:"text-sm text-muted-foreground",children:[g/1e3," 秒"]})]}),e.jsx(pa,{value:[g],onValueChange:T,min:1e3,max:1e4,step:500,className:"w-full"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"日志 WebSocket 连接断开后的重连基础间隔"})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(C,{className:"text-sm font-medium",children:"WebSocket 最大重连次数"}),e.jsxs("span",{className:"text-sm text-muted-foreground",children:[j," 次"]})]}),e.jsx(pa,{value:[j],onValueChange:A,min:3,max:30,step:1,className:"w-full"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"连接失败后的最大重连尝试次数"})]}),e.jsxs("div",{className:"flex flex-wrap gap-2 pt-2",children:[e.jsxs(S,{variant:"outline",size:"sm",onClick:fe,className:"gap-2",children:[e.jsx(We,{className:"h-4 w-4"}),"清除日志缓存"]}),e.jsxs(hs,{children:[e.jsx(rt,{asChild:!0,children:e.jsxs(S,{variant:"outline",size:"sm",className:"gap-2",children:[e.jsx(We,{className:"h-4 w-4"}),"清除本地缓存"]})}),e.jsxs(ls,{children:[e.jsxs(ns,{children:[e.jsx(is,{children:"确认清除本地缓存"}),e.jsx(cs,{children:"这将清除所有本地缓存的设置和数据(不包括登录凭证)。 您可能需要重新配置部分偏好设置。确定要继续吗?"})]}),e.jsxs(rs,{children:[e.jsx(ds,{children:"取消"}),e.jsx(os,{onClick:je,children:"确认清除"})]})]})]})]})]})]}),e.jsxs("div",{className:"rounded-lg border bg-card p-4 sm:p-6",children:[e.jsxs("h3",{className:"text-base sm:text-lg font-semibold mb-3 sm:mb-4 flex items-center gap-2",children:[e.jsx(Oa,{className:"h-5 w-5"}),"导入/导出设置"]}),e.jsxs("div",{className:"space-y-4",children:[e.jsx("p",{className:"text-xs sm:text-sm text-muted-foreground",children:"导出当前的界面设置以便备份,或从之前导出的文件中恢复设置。"}),e.jsxs("div",{className:"flex flex-wrap gap-2",children:[e.jsxs(S,{variant:"outline",onClick:pe,disabled:O,className:"gap-2",children:[e.jsx(Oa,{className:"h-4 w-4"}),O?"导出中...":"导出设置"]}),e.jsx("input",{ref:z,type:"file",accept:".json",onChange:he,className:"hidden"}),e.jsxs(S,{variant:"outline",onClick:()=>z.current?.click(),disabled:Y,className:"gap-2",children:[e.jsx(oi,{className:"h-4 w-4"}),Y?"导入中...":"导入设置"]})]}),e.jsx("div",{className:"pt-2 border-t",children:e.jsxs(hs,{children:[e.jsx(rt,{asChild:!0,children:e.jsxs(S,{variant:"outline",size:"sm",className:"gap-2 text-destructive hover:text-destructive",children:[e.jsx($c,{className:"h-4 w-4"}),"重置所有设置为默认值"]})}),e.jsxs(ls,{children:[e.jsxs(ns,{children:[e.jsx(is,{children:"确认重置所有设置"}),e.jsx(cs,{children:"这将把所有界面设置恢复为默认值,包括主题、颜色、动画等偏好设置。 此操作不会影响您的登录状态。确定要继续吗?"})]}),e.jsxs(rs,{children:[e.jsx(ds,{children:"取消"}),e.jsx(os,{onClick:ve,children:"确认重置"})]})]})]})})]})]}),e.jsxs("div",{className:"rounded-lg border bg-card p-4 sm:p-6",children:[e.jsx("h3",{className:"text-base sm:text-lg font-semibold mb-3 sm:mb-4",children:"配置向导"}),e.jsxs("div",{className:"space-y-3 sm:space-y-4",children:[e.jsx("div",{className:"space-y-2",children:e.jsx("p",{className:"text-xs sm:text-sm text-muted-foreground",children:"重新进行初次配置向导,可以帮助您重新设置系统的基础配置。"})}),e.jsxs(hs,{children:[e.jsx(rt,{asChild:!0,children:e.jsxs(S,{variant:"outline",disabled:i,className:"gap-2",children:[e.jsx($c,{className:$("h-4 w-4",i&&"animate-spin")}),"重新进行初次配置"]})}),e.jsxs(ls,{children:[e.jsxs(ns,{children:[e.jsx(is,{children:"确认重新配置"}),e.jsx(cs,{children:"这将带您重新进入初次配置向导。您可以重新设置系统的基础配置项。确定要继续吗?"})]}),e.jsxs(rs,{children:[e.jsx(ds,{children:"取消"}),e.jsx(os,{onClick:be,children:"确认重置"})]})]})]})]})]}),e.jsxs("div",{className:"rounded-lg border border-dashed border-yellow-500/50 bg-yellow-500/5 p-4 sm:p-6",children:[e.jsxs("h3",{className:"text-base sm:text-lg font-semibold mb-3 sm:mb-4 flex items-center gap-2",children:[e.jsx(Ca,{className:"h-5 w-5 text-yellow-500"}),"开发者工具"]}),e.jsxs("div",{className:"space-y-3 sm:space-y-4",children:[e.jsx("div",{className:"space-y-2",children:e.jsx("p",{className:"text-xs sm:text-sm text-muted-foreground",children:"以下功能仅供开发调试使用,可能会导致页面崩溃或异常。"})}),e.jsxs(hs,{children:[e.jsx(rt,{asChild:!0,children:e.jsxs(S,{variant:"destructive",className:"gap-2",children:[e.jsx(Ca,{className:"h-4 w-4"}),"触发测试错误"]})}),e.jsxs(ls,{children:[e.jsxs(ns,{children:[e.jsx(is,{children:"确认触发错误"}),e.jsx(cs,{children:"这将手动触发一个 React 错误,用于测试错误边界组件的显示效果。 页面将显示错误界面,您可以通过刷新页面或点击返回首页来恢复。"})]}),e.jsxs(rs,{children:[e.jsx(ds,{children:"取消"}),e.jsx(os,{onClick:()=>x(!0),className:"bg-destructive text-destructive-foreground hover:bg-destructive/90",children:"确认触发"})]})]})]})]})]})]})}function $0(){return e.jsxs("div",{className:"space-y-4 sm:space-y-6",children:[e.jsx("div",{className:"rounded-lg border-2 border-primary/30 bg-gradient-to-r from-primary/5 to-primary/10 p-4 sm:p-6",children:e.jsxs("div",{className:"flex items-start gap-3 sm:gap-4",children:[e.jsx("div",{className:"flex-shrink-0 rounded-lg bg-primary/10 p-2 sm:p-3",children:e.jsx("svg",{className:"h-6 w-6 sm:h-8 sm:w-8 text-primary",fill:"currentColor",viewBox:"0 0 24 24","aria-hidden":"true",children:e.jsx("path",{fillRule:"evenodd",d:"M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z",clipRule:"evenodd"})})}),e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsx("h3",{className:"text-lg sm:text-xl font-bold text-foreground mb-2",children:"开源项目"}),e.jsx("p",{className:"text-sm sm:text-base text-muted-foreground mb-3",children:"本项目在 GitHub 开源,欢迎 Star ⭐ 支持!"}),e.jsxs("a",{href:"https://github.com/Mai-with-u/MaiBot-Dashboard",target:"_blank",rel:"noopener noreferrer",className:$("inline-flex items-center gap-2 px-4 py-2 rounded-lg","bg-primary text-primary-foreground font-medium text-sm","hover:bg-primary/90 transition-colors","focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"),children:[e.jsx("svg",{className:"h-4 w-4",fill:"currentColor",viewBox:"0 0 24 24","aria-hidden":"true",children:e.jsx("path",{fillRule:"evenodd",d:"M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z",clipRule:"evenodd"})}),"前往 GitHub",e.jsx("svg",{className:"h-4 w-4",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",children:e.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"})})]})]})]})}),e.jsxs("div",{className:"rounded-lg border bg-card p-4 sm:p-6",children:[e.jsxs("h3",{className:"text-base sm:text-lg font-semibold mb-3 sm:mb-4",children:["关于 ",Ku]}),e.jsxs("div",{className:"space-y-2 text-xs sm:text-sm text-muted-foreground",children:[e.jsxs("p",{children:["版本: ",Zc]}),e.jsx("p",{children:"麦麦(MaiBot)的现代化 Web 管理界面"})]})]}),e.jsxs("div",{className:"rounded-lg border bg-card p-4 sm:p-6",children:[e.jsx("h3",{className:"text-base sm:text-lg font-semibold mb-3 sm:mb-4",children:"作者"}),e.jsxs("div",{className:"space-y-3",children:[e.jsxs("div",{className:"space-y-1",children:[e.jsx("p",{className:"text-sm font-medium",children:"MaiBot 核心"}),e.jsx("p",{className:"text-xs sm:text-sm text-muted-foreground",children:"Mai-with-u"})]}),e.jsxs("div",{className:"space-y-1",children:[e.jsx("p",{className:"text-sm font-medium",children:"WebUI"}),e.jsxs("p",{className:"text-xs sm:text-sm text-muted-foreground",children:["Mai-with-u ",e.jsx("a",{href:"https://github.com/DrSmoothl",target:"_blank",rel:"noopener noreferrer",className:"text-primary underline",children:"@MotricSeven"})]})]})]})]}),e.jsxs("div",{className:"rounded-lg border bg-card p-4 sm:p-6",children:[e.jsx("h3",{className:"text-base sm:text-lg font-semibold mb-3 sm:mb-4",children:"技术栈"}),e.jsxs("div",{className:"grid grid-cols-1 sm:grid-cols-2 gap-3 text-xs sm:text-sm text-muted-foreground",children:[e.jsxs("div",{className:"space-y-1.5",children:[e.jsx("p",{className:"font-medium text-foreground",children:"前端框架"}),e.jsxs("ul",{className:"space-y-0.5 list-disc list-inside",children:[e.jsx("li",{children:"React 19.2.0"}),e.jsx("li",{children:"TypeScript 5.7.2"}),e.jsx("li",{children:"Vite 6.0.7"}),e.jsx("li",{children:"TanStack Router 1.94.2"})]})]}),e.jsxs("div",{className:"space-y-1.5",children:[e.jsx("p",{className:"font-medium text-foreground",children:"UI 组件"}),e.jsxs("ul",{className:"space-y-0.5 list-disc list-inside",children:[e.jsx("li",{children:"shadcn/ui"}),e.jsx("li",{children:"Radix UI"}),e.jsx("li",{children:"Tailwind CSS 3.4.17"}),e.jsx("li",{children:"Lucide Icons"})]})]}),e.jsxs("div",{className:"space-y-1.5",children:[e.jsx("p",{className:"font-medium text-foreground",children:"后端"}),e.jsxs("ul",{className:"space-y-0.5 list-disc list-inside",children:[e.jsx("li",{children:"Python 3.12+"}),e.jsx("li",{children:"FastAPI"}),e.jsx("li",{children:"Uvicorn"}),e.jsx("li",{children:"WebSocket"})]})]}),e.jsxs("div",{className:"space-y-1.5",children:[e.jsx("p",{className:"font-medium text-foreground",children:"构建工具"}),e.jsxs("ul",{className:"space-y-0.5 list-disc list-inside",children:[e.jsx("li",{children:"Bun / npm"}),e.jsx("li",{children:"ESLint 9.17.0"}),e.jsx("li",{children:"PostCSS"})]})]})]})]}),e.jsxs("div",{className:"rounded-lg border bg-card p-4 sm:p-6",children:[e.jsx("h3",{className:"text-base sm:text-lg font-semibold mb-3 sm:mb-4",children:"开源库感谢"}),e.jsx("p",{className:"text-xs sm:text-sm text-muted-foreground mb-3",children:"本项目使用了以下优秀的开源库,感谢他们的贡献:"}),e.jsx(Ze,{className:"h-[300px] sm:h-[400px]",children:e.jsxs("div",{className:"space-y-4 pr-4",children:[e.jsxs("div",{className:"space-y-2",children:[e.jsx("p",{className:"text-sm font-medium text-foreground",children:"UI 框架与组件"}),e.jsxs("div",{className:"grid gap-2 text-xs sm:text-sm",children:[e.jsx(Ws,{name:"React",description:"用户界面构建库",license:"MIT"}),e.jsx(Ws,{name:"shadcn/ui",description:"优雅的 React 组件库",license:"MIT"}),e.jsx(Ws,{name:"Radix UI",description:"无样式的可访问组件库",license:"MIT"}),e.jsx(Ws,{name:"Tailwind CSS",description:"实用优先的 CSS 框架",license:"MIT"}),e.jsx(Ws,{name:"Lucide React",description:"精美的图标库",license:"ISC"})]})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx("p",{className:"text-sm font-medium text-foreground",children:"路由与状态管理"}),e.jsxs("div",{className:"grid gap-2 text-xs sm:text-sm",children:[e.jsx(Ws,{name:"TanStack Router",description:"类型安全的路由库",license:"MIT"}),e.jsx(Ws,{name:"Zustand",description:"轻量级状态管理",license:"MIT"})]})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx("p",{className:"text-sm font-medium text-foreground",children:"表单处理"}),e.jsxs("div",{className:"grid gap-2 text-xs sm:text-sm",children:[e.jsx(Ws,{name:"React Hook Form",description:"高性能表单库",license:"MIT"}),e.jsx(Ws,{name:"Zod",description:"TypeScript 优先的 schema 验证",license:"MIT"})]})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx("p",{className:"text-sm font-medium text-foreground",children:"工具库"}),e.jsxs("div",{className:"grid gap-2 text-xs sm:text-sm",children:[e.jsx(Ws,{name:"clsx",description:"条件 className 构建工具",license:"MIT"}),e.jsx(Ws,{name:"tailwind-merge",description:"Tailwind 类名合并工具",license:"MIT"}),e.jsx(Ws,{name:"class-variance-authority",description:"组件变体管理",license:"Apache-2.0"}),e.jsx(Ws,{name:"date-fns",description:"现代化日期处理库",license:"MIT"})]})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx("p",{className:"text-sm font-medium text-foreground",children:"动画效果"}),e.jsxs("div",{className:"grid gap-2 text-xs sm:text-sm",children:[e.jsx(Ws,{name:"Framer Motion",description:"React 动画库",license:"MIT"}),e.jsx(Ws,{name:"vaul",description:"抽屉组件动画",license:"MIT"})]})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx("p",{className:"text-sm font-medium text-foreground",children:"后端框架"}),e.jsxs("div",{className:"grid gap-2 text-xs sm:text-sm",children:[e.jsx(Ws,{name:"FastAPI",description:"现代化 Python Web 框架",license:"MIT"}),e.jsx(Ws,{name:"Uvicorn",description:"ASGI 服务器",license:"BSD-3-Clause"}),e.jsx(Ws,{name:"Pydantic",description:"数据验证库",license:"MIT"}),e.jsx(Ws,{name:"python-multipart",description:"文件上传支持",license:"Apache-2.0"})]})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx("p",{className:"text-sm font-medium text-foreground",children:"开发工具"}),e.jsxs("div",{className:"grid gap-2 text-xs sm:text-sm",children:[e.jsx(Ws,{name:"TypeScript",description:"JavaScript 的超集",license:"Apache-2.0"}),e.jsx(Ws,{name:"Vite",description:"下一代前端构建工具",license:"MIT"}),e.jsx(Ws,{name:"ESLint",description:"JavaScript 代码检查工具",license:"MIT"}),e.jsx(Ws,{name:"PostCSS",description:"CSS 转换工具",license:"MIT"})]})]})]})})]}),e.jsxs("div",{className:"rounded-lg border bg-card p-4 sm:p-6",children:[e.jsx("h3",{className:"text-base sm:text-lg font-semibold mb-3 sm:mb-4",children:"开源许可"}),e.jsxs("div",{className:"space-y-3",children:[e.jsx("div",{className:"rounded-lg bg-primary/5 border border-primary/20 p-3 sm:p-4",children:e.jsxs("div",{className:"flex items-start gap-2 sm:gap-3",children:[e.jsx("div",{className:"flex-shrink-0 mt-0.5",children:e.jsx("div",{className:"rounded-md bg-primary/10 px-2 py-1",children:e.jsx("span",{className:"text-xs sm:text-sm font-bold text-primary",children:"GPLv3"})})}),e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsx("p",{className:"text-sm sm:text-base font-semibold text-foreground mb-1",children:"MaiBot WebUI"}),e.jsx("p",{className:"text-xs sm:text-sm text-muted-foreground",children:"本项目采用 GNU General Public License v3.0 开源许可证。 您可以自由地使用、修改和分发本软件,但必须保持相同的开源许可。"})]})]})}),e.jsx("p",{className:"text-xs sm:text-sm text-muted-foreground",children:"本项目依赖的所有开源库均遵循各自的开源许可证(MIT、Apache-2.0、BSD 等)。 感谢所有开源贡献者的无私奉献。"})]})]})]})}function Ws({name:n,description:r,license:i}){return e.jsxs("div",{className:"flex items-start justify-between gap-2 rounded-lg border bg-muted/30 p-2.5 sm:p-3",children:[e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsx("p",{className:"font-medium text-foreground truncate",children:n}),e.jsx("p",{className:"text-muted-foreground text-xs mt-0.5",children:r})]}),e.jsx("span",{className:"inline-flex items-center rounded-full bg-primary/10 px-2 py-0.5 text-[10px] font-medium text-primary flex-shrink-0",children:i})]})}function ku({value:n,current:r,onChange:i,label:d,description:m}){const x=r===n;return e.jsxs("button",{onClick:()=>i(n),className:$("relative rounded-lg border-2 p-3 sm:p-4 text-left transition-all","hover:border-primary/50 hover:bg-accent/50",x?"border-primary bg-accent":"border-border"),children:[x&&e.jsx("div",{className:"absolute top-2 right-2 sm:top-3 sm:right-3 h-2 w-2 rounded-full bg-primary"}),e.jsxs("div",{className:"space-y-1",children:[e.jsx("div",{className:"text-sm sm:text-base font-medium",children:d}),e.jsx("div",{className:"text-[10px] sm:text-xs text-muted-foreground",children:m})]}),e.jsxs("div",{className:"mt-2 sm:mt-3 flex gap-1",children:[n==="light"&&e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"h-2 w-2 rounded-full bg-slate-200"}),e.jsx("div",{className:"h-2 w-2 rounded-full bg-slate-300"}),e.jsx("div",{className:"h-2 w-2 rounded-full bg-slate-400"})]}),n==="dark"&&e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"h-2 w-2 rounded-full bg-slate-700"}),e.jsx("div",{className:"h-2 w-2 rounded-full bg-slate-800"}),e.jsx("div",{className:"h-2 w-2 rounded-full bg-slate-900"})]}),n==="system"&&e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"h-2 w-2 rounded-full bg-gradient-to-r from-slate-200 to-slate-700"}),e.jsx("div",{className:"h-2 w-2 rounded-full bg-gradient-to-r from-slate-300 to-slate-800"}),e.jsx("div",{className:"h-2 w-2 rounded-full bg-gradient-to-r from-slate-400 to-slate-900"})]})]})]})}function fa({value:n,current:r,onChange:i,label:d,colorClass:m}){const x=r===n;return e.jsxs("button",{onClick:()=>i(n),className:$("relative rounded-lg border-2 p-2 sm:p-3 text-left transition-all","hover:border-primary/50 hover:bg-accent/50",x?"border-primary bg-accent":"border-border"),children:[x&&e.jsx("div",{className:"absolute top-1.5 right-1.5 sm:top-2 sm:right-2 h-1.5 w-1.5 sm:h-2 sm:w-2 rounded-full bg-primary"}),e.jsxs("div",{className:"flex flex-col items-center gap-1.5 sm:gap-2",children:[e.jsx("div",{className:$("h-8 w-8 sm:h-10 sm:w-10 rounded-full",m)}),e.jsx("div",{className:"text-[10px] sm:text-xs font-medium text-center",children:d})]})]})}class F0{grad3;p;perm;constructor(r=0){this.grad3=[[1,1,0],[-1,1,0],[1,-1,0],[-1,-1,0],[1,0,1],[-1,0,1],[1,0,-1],[-1,0,-1],[0,1,1],[0,-1,1],[0,1,-1],[0,-1,-1]],this.p=[];for(let i=0;i<256;i++)this.p[i]=Math.floor(Math.random()*256);this.perm=[];for(let i=0;i<512;i++)this.perm[i]=this.p[i&255]}dot(r,i,d){return r[0]*i+r[1]*d}mix(r,i,d){return(1-d)*r+d*i}fade(r){return r*r*r*(r*(r*6-15)+10)}perlin2(r,i){const d=Math.floor(r)&255,m=Math.floor(i)&255;r-=Math.floor(r),i-=Math.floor(i);const x=this.fade(r),f=this.fade(i),p=this.perm[d]+m,g=this.perm[p],b=this.perm[p+1],j=this.perm[d+1]+m,y=this.perm[j],N=this.perm[j+1];return this.mix(this.mix(this.dot(this.grad3[g%12],r,i),this.dot(this.grad3[y%12],r-1,i),x),this.mix(this.dot(this.grad3[b%12],r,i-1),this.dot(this.grad3[N%12],r-1,i-1),x),f)}}function op(){const n=u.useRef(null),r=u.useRef(null),i=u.useRef(void 0),d=u.useRef({mouse:{x:-10,y:0,lx:0,ly:0,sx:0,sy:0,v:0,vs:0,a:0,set:!1},lines:[],paths:[],noise:new F0(Math.random()),bounding:null});return u.useEffect(()=>{const m=r.current,x=n.current;if(!m||!x)return;const f=d.current,p=()=>{const U=m.getBoundingClientRect();f.bounding=U,x.style.width=`${U.width}px`,x.style.height=`${U.height}px`},g=()=>{if(!f.bounding)return;const{width:U,height:O}=f.bounding;f.lines=[],f.paths.forEach(te=>te.remove()),f.paths=[];const B=10,Y=32,L=U+200,z=O+30,K=Math.ceil(L/B),I=Math.ceil(z/Y),T=(U-B*K)/2,A=(O-Y*I)/2;for(let te=0;te<=K;te++){const fe=[];for(let pe=0;pe<=I;pe++){const he={x:T+B*te,y:A+Y*pe,wave:{x:0,y:0},cursor:{x:0,y:0,vx:0,vy:0}};fe.push(he)}const je=document.createElementNS("http://www.w3.org/2000/svg","path");x.appendChild(je),f.paths.push(je),f.lines.push(fe)}},b=U=>{const{lines:O,mouse:B,noise:Y}=f;O.forEach(L=>{L.forEach(z=>{const K=Y.perlin2((z.x+U*.0125)*.002,(z.y+U*.005)*.0015)*12;z.wave.x=Math.cos(K)*32,z.wave.y=Math.sin(K)*16;const I=z.x-B.sx,T=z.y-B.sy,A=Math.hypot(I,T),te=Math.max(175,B.vs);if(A{const B={x:U.x+U.wave.x+(O?U.cursor.x:0),y:U.y+U.wave.y+(O?U.cursor.y:0)};return B.x=Math.round(B.x*10)/10,B.y=Math.round(B.y*10)/10,B},y=()=>{const{lines:U,paths:O}=f;U.forEach((B,Y)=>{let L=j(B[0],!1),z=`M ${L.x} ${L.y}`;B.forEach((K,I)=>{const T=I===B.length-1;L=j(K,!T),z+=`L ${L.x} ${L.y}`}),O[Y].setAttribute("d",z)})},N=U=>{const{mouse:O}=f;O.sx+=(O.x-O.sx)*.1,O.sy+=(O.y-O.sy)*.1;const B=O.x-O.lx,Y=O.y-O.ly,L=Math.hypot(B,Y);O.v=L,O.vs+=(L-O.vs)*.1,O.vs=Math.min(100,O.vs),O.lx=O.x,O.ly=O.y,O.a=Math.atan2(Y,B),m&&(m.style.setProperty("--x",`${O.sx}px`),m.style.setProperty("--y",`${O.sy}px`)),b(U),y(),i.current=requestAnimationFrame(N)},k=U=>{if(!f.bounding)return;const{mouse:O}=f;O.x=U.pageX-f.bounding.left,O.y=U.pageY-f.bounding.top+window.scrollY,O.set||(O.sx=O.x,O.sy=O.y,O.lx=O.x,O.ly=O.y,O.set=!0)},w=()=>{p(),g()};return p(),g(),window.addEventListener("resize",w),window.addEventListener("mousemove",k),i.current=requestAnimationFrame(N),()=>{window.removeEventListener("resize",w),window.removeEventListener("mousemove",k),i.current&&cancelAnimationFrame(i.current)}},[]),e.jsxs("div",{ref:r,className:"waves-background",style:{position:"absolute",top:0,left:0,width:"100%",height:"100%",overflow:"hidden",pointerEvents:"none"},children:[e.jsx("div",{className:"waves-cursor",style:{position:"absolute",top:0,left:0,width:"0.5rem",height:"0.5rem",background:"hsl(var(--primary) / 0.3)",borderRadius:"50%",transform:"translate3d(calc(var(--x, -0.5rem) - 50%), calc(var(--y, 50%) - 50%), 0)",willChange:"transform",pointerEvents:"none"}}),e.jsx("svg",{ref:n,style:{display:"block",width:"100%",height:"100%"},children:e.jsx("style",{children:` - path { - fill: none; - stroke: hsl(var(--primary) / 0.20); - stroke-width: 1px; - } - `})})]})}async function Se(n,r){const i={...r,credentials:"include",headers:{"Content-Type":"application/json",...r?.headers}},d=await fetch(n,i);if(d.status===401)throw window.location.href="/auth",new Error("认证失败,请重新登录");return d}function Gs(){return{"Content-Type":"application/json"}}async function V0(){try{await fetch("/api/webui/auth/logout",{method:"POST",credentials:"include"})}catch(n){console.error("登出请求失败:",n)}window.location.href="/auth"}async function Ju(){try{return(await(await fetch("/api/webui/auth/check",{method:"GET",credentials:"include"})).json()).authenticated===!0}catch{return!1}}function Q0(){const[n,r]=u.useState(""),[i,d]=u.useState(!1),[m,x]=u.useState(""),[f,p]=u.useState(!0),g=va(),{enableWavesBackground:b,setEnableWavesBackground:j}=Mg(),{theme:y,setTheme:N}=Yu();u.useEffect(()=>{(async()=>{try{await Ju()&&g({to:"/"})}catch{}finally{p(!1)}})()},[g]);const w=y==="system"?window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light":y,U=()=>{N(w==="dark"?"light":"dark")},O=async B=>{if(B.preventDefault(),x(""),!n.trim()){x("请输入 Access Token");return}d(!0);try{const Y=await fetch("/api/webui/auth/verify",{method:"POST",headers:{"Content-Type":"application/json"},credentials:"include",body:JSON.stringify({token:n.trim()})}),L=await Y.json();Y.ok&&L.valid?L.is_first_setup?g({to:"/setup"}):g({to:"/"}):x(L.message||"Token 验证失败,请检查后重试")}catch(Y){console.error("Token 验证错误:",Y),x("连接服务器失败,请检查网络连接")}finally{d(!1)}};return f?e.jsxs("div",{className:"relative flex min-h-screen items-center justify-center overflow-hidden bg-background p-4",children:[b&&e.jsx(op,{}),e.jsx("div",{className:"text-muted-foreground",children:"正在检查登录状态..."})]}):e.jsxs("div",{className:"relative flex min-h-screen items-center justify-center overflow-hidden bg-background p-4",children:[b&&e.jsx(op,{}),e.jsxs(Fe,{className:"relative z-10 w-full max-w-md shadow-2xl backdrop-blur-xl bg-card/80 border-border/50",children:[e.jsx("button",{onClick:U,className:"absolute right-4 top-4 rounded-lg p-2 hover:bg-accent transition-colors z-10 text-foreground",title:w==="dark"?"切换到浅色模式":"切换到深色模式",children:w==="dark"?e.jsx(xg,{className:"h-5 w-5",strokeWidth:2.5,fill:"none"}):e.jsx(hg,{className:"h-5 w-5",strokeWidth:2.5,fill:"none"})}),e.jsxs(ts,{className:"space-y-4 text-center",children:[e.jsx("div",{className:"mx-auto flex h-16 w-16 items-center justify-center rounded-2xl bg-primary/10",children:e.jsx(Jf,{className:"h-8 w-8 text-primary",strokeWidth:2,fill:"none"})}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(as,{className:"text-2xl font-bold",children:"欢迎使用 MaiBot"}),e.jsx(et,{className:"text-base",children:"请输入您的 Access Token 以继续访问系统"})]})]}),e.jsx(xs,{children:e.jsxs("form",{onSubmit:O,className:"space-y-4",children:[e.jsxs("div",{className:"space-y-2",children:[e.jsx(C,{htmlFor:"token",className:"text-sm font-medium",children:"Access Token"}),e.jsxs("div",{className:"relative",children:[e.jsx(fg,{className:"absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground",strokeWidth:2,fill:"none"}),e.jsx(ie,{id:"token",type:"password",placeholder:"请输入您的 Access Token",value:n,onChange:B=>r(B.target.value),className:$("pl-10",m&&"border-red-500 focus-visible:ring-red-500"),disabled:i,autoFocus:!0,autoComplete:"off"})]})]}),m&&e.jsxs("div",{className:"flex items-center gap-2 rounded-md bg-red-50 p-3 text-sm text-red-600 dark:bg-red-950/50 dark:text-red-400",children:[e.jsx(At,{className:"h-4 w-4 flex-shrink-0",strokeWidth:2,fill:"none"}),e.jsx("span",{children:m})]}),e.jsx(S,{type:"submit",className:"w-full",disabled:i,children:i?e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"mr-2 h-4 w-4 animate-spin rounded-full border-2 border-current border-t-transparent"}),"验证中..."]}):"验证并进入"}),e.jsxs(qs,{children:[e.jsx(Xu,{asChild:!0,children:e.jsxs("button",{className:"w-full text-center text-sm text-primary hover:text-primary/80 transition-colors underline-offset-4 hover:underline flex items-center justify-center gap-1",children:[e.jsx(pg,{className:"h-4 w-4",strokeWidth:2,fill:"none"}),"我没有 Token,我该去哪里获得 Token?"]})}),e.jsxs(Ls,{className:"sm:max-w-md",children:[e.jsxs(Us,{children:[e.jsxs(Bs,{className:"flex items-center gap-2",children:[e.jsx(Jf,{className:"h-5 w-5 text-primary",strokeWidth:2,fill:"none"}),"如何获取 Access Token"]}),e.jsx(Ps,{children:"Access Token 是访问 MaiBot WebUI 的唯一凭证,请按以下方式获取"})]}),e.jsxs("div",{className:"space-y-4",children:[e.jsx("div",{className:"rounded-lg border bg-muted/50 p-4 space-y-2",children:e.jsxs("div",{className:"flex items-start gap-3",children:[e.jsx(ey,{className:"h-5 w-5 text-primary flex-shrink-0 mt-0.5",strokeWidth:2,fill:"none"}),e.jsxs("div",{className:"flex-1 space-y-2",children:[e.jsx("h4",{className:"font-semibold text-sm",children:"方式一:查看启动日志"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"在 MaiBot 启动时,控制台会显示 WebUI Access Token。"}),e.jsxs("div",{className:"rounded bg-background p-2 font-mono text-xs",children:[e.jsx("p",{className:"text-muted-foreground",children:"🔑 WebUI Access Token: abc123..."}),e.jsx("p",{className:"text-muted-foreground",children:"💡 请使用此 Token 登录 WebUI"})]})]})]})}),e.jsx("div",{className:"rounded-lg border bg-muted/50 p-4 space-y-2",children:e.jsxs("div",{className:"flex items-start gap-3",children:[e.jsx(Sa,{className:"h-5 w-5 text-primary flex-shrink-0 mt-0.5",strokeWidth:2,fill:"none"}),e.jsxs("div",{className:"flex-1 space-y-2",children:[e.jsx("h4",{className:"font-semibold text-sm",children:"方式二:查看配置文件"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"Token 保存在项目根目录的配置文件中:"}),e.jsx("div",{className:"rounded bg-background p-2 font-mono text-xs break-all",children:e.jsx("code",{className:"text-primary",children:"data/webui.json"})}),e.jsxs("p",{className:"text-xs text-muted-foreground",children:["打开此文件,复制 ",e.jsx("code",{className:"px-1 py-0.5 bg-background rounded",children:"access_token"})," 字段的值"]})]})]})}),e.jsx("div",{className:"rounded-lg border border-yellow-200 dark:border-yellow-900 bg-yellow-50 dark:bg-yellow-950/30 p-3",children:e.jsxs("div",{className:"flex gap-2",children:[e.jsx(At,{className:"h-4 w-4 text-yellow-600 dark:text-yellow-500 flex-shrink-0 mt-0.5",strokeWidth:2,fill:"none"}),e.jsxs("div",{className:"text-sm text-yellow-800 dark:text-yellow-300 space-y-1",children:[e.jsx("p",{className:"font-semibold",children:"安全提示"}),e.jsxs("ul",{className:"list-disc list-inside space-y-0.5 text-xs",children:[e.jsx("li",{children:"请妥善保管您的 Token,不要泄露给他人"}),e.jsx("li",{children:"如需重置 Token,请在登录后前往系统设置"})]})]})]})})]})]})]}),e.jsxs(hs,{children:[e.jsx(rt,{asChild:!0,children:e.jsxs("button",{className:"w-full text-center text-sm text-muted-foreground hover:text-foreground transition-colors underline-offset-4 hover:underline flex items-center justify-center gap-1",children:[e.jsx(an,{className:"h-4 w-4",strokeWidth:2,fill:"none"}),"我觉得这个界面很卡怎么办?"]})}),e.jsxs(ls,{children:[e.jsxs(ns,{children:[e.jsxs(is,{className:"flex items-center gap-2",children:[e.jsx(an,{className:"h-5 w-5 text-primary",strokeWidth:2,fill:"none"}),"关闭背景动画"]}),e.jsx(cs,{children:"背景动画可能会在低性能设备上造成卡顿。关闭动画可以显著提升界面流畅度。"})]}),e.jsx("div",{className:"rounded-lg border bg-muted/50 p-4 space-y-2",children:e.jsx("p",{className:"text-sm text-muted-foreground",children:"关闭动画后,背景将变为纯色,但不影响任何功能的使用。您可以随时在系统设置中重新开启动画。"})}),e.jsxs(rs,{children:[e.jsx(ds,{children:"取消"}),e.jsx(os,{onClick:()=>j(!1),children:"关闭动画"})]})]})]})]})})]}),e.jsx("div",{className:"absolute bottom-4 left-0 right-0 text-center text-xs text-muted-foreground",children:e.jsx("p",{children:k0})})]})}const Qs=u.forwardRef(({className:n,...r},i)=>e.jsx("textarea",{className:$("flex min-h-[60px] w-full rounded-md border border-input bg-transparent px-3 py-2 text-base shadow-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",n),ref:i,...r}));Qs.displayName="Textarea";const Pc=u.forwardRef(({className:n,orientation:r="horizontal",decorative:i=!0,...d},m)=>e.jsx(Hp,{ref:m,decorative:i,orientation:r,className:$("shrink-0 bg-border",r==="horizontal"?"h-[1px] w-full":"h-full w-[1px]",n),...d}));Pc.displayName=Hp.displayName;function I0({config:n,onChange:r}){const i=m=>{m.trim()&&!n.alias_names.includes(m.trim())&&r({...n,alias_names:[...n.alias_names,m.trim()]})},d=m=>{r({...n,alias_names:n.alias_names.filter((x,f)=>f!==m)})};return e.jsxs("div",{className:"space-y-6",children:[e.jsxs("div",{className:"space-y-3",children:[e.jsx(C,{htmlFor:"qq_account",children:"QQ账号 *"}),e.jsx(ie,{id:"qq_account",type:"number",placeholder:"请输入机器人的QQ账号",value:n.qq_account||"",onChange:m=>r({...n,qq_account:Number(m.target.value)})}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"机器人登录使用的QQ账号"})]}),e.jsxs("div",{className:"space-y-3",children:[e.jsx(C,{htmlFor:"nickname",children:"昵称 *"}),e.jsx(ie,{id:"nickname",placeholder:"请输入机器人的昵称",value:n.nickname,onChange:m=>r({...n,nickname:m.target.value})}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"机器人的主要称呼名称"})]}),e.jsxs("div",{className:"space-y-3",children:[e.jsx(C,{children:"别名"}),e.jsx("div",{className:"flex flex-wrap gap-2 mb-2",children:n.alias_names.map((m,x)=>e.jsxs(Qe,{variant:"secondary",className:"gap-1",children:[m,e.jsx("button",{type:"button",onClick:()=>d(x),className:"ml-1 hover:text-destructive",children:e.jsx(rl,{className:"h-3 w-3"})})]},x))}),e.jsxs("div",{className:"flex gap-2",children:[e.jsx(ie,{id:"alias_input",placeholder:"输入别名后按回车添加",onKeyPress:m=>{m.key==="Enter"&&(i(m.target.value),m.target.value="")}}),e.jsx(S,{type:"button",variant:"outline",onClick:()=>{const m=document.getElementById("alias_input");m&&(i(m.value),m.value="")},children:"添加"})]}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"机器人的其他称呼,可以添加多个"})]})]})}function Y0({config:n,onChange:r}){return e.jsxs("div",{className:"space-y-6",children:[e.jsxs("div",{className:"space-y-3",children:[e.jsx(C,{htmlFor:"personality",children:"人格特征 *"}),e.jsx(Qs,{id:"personality",placeholder:"描述机器人的人格特质和身份特征(建议120字以内)",value:n.personality,onChange:i=>r({...n,personality:i.target.value}),rows:3}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"例如:是一个女大学生,现在在读大二,会刷贴吧"})]}),e.jsxs("div",{className:"space-y-3",children:[e.jsx(C,{htmlFor:"reply_style",children:"表达风格 *"}),e.jsx(Qs,{id:"reply_style",placeholder:"描述机器人说话的表达风格、表达习惯",value:n.reply_style,onChange:i=>r({...n,reply_style:i.target.value}),rows:3}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"例如:回复平淡一些,简短一些,说中文,参考贴吧、知乎和微博的回复风格"})]}),e.jsxs("div",{className:"space-y-3",children:[e.jsx(C,{htmlFor:"interest",children:"兴趣 *"}),e.jsx(Qs,{id:"interest",placeholder:"描述机器人感兴趣的话题",value:n.interest,onChange:i=>r({...n,interest:i.target.value}),rows:2}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"会影响机器人对什么话题进行回复"})]}),e.jsx(Pc,{}),e.jsxs("div",{className:"space-y-3",children:[e.jsx(C,{htmlFor:"plan_style",children:"群聊说话规则 *"}),e.jsx(Qs,{id:"plan_style",placeholder:"机器人在群聊中的行为风格和规则",value:n.plan_style,onChange:i=>r({...n,plan_style:i.target.value}),rows:4}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"定义机器人在群聊中如何行动,例如回复频率、条件等"})]}),e.jsxs("div",{className:"space-y-3",children:[e.jsx(C,{htmlFor:"private_plan_style",children:"私聊说话规则 *"}),e.jsx(Qs,{id:"private_plan_style",placeholder:"机器人在私聊中的行为风格和规则",value:n.private_plan_style,onChange:i=>r({...n,private_plan_style:i.target.value}),rows:3}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"定义机器人在私聊中的行为方式"})]})]})}function K0({config:n,onChange:r}){return e.jsxs("div",{className:"space-y-6",children:[e.jsxs("div",{className:"space-y-3",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(C,{htmlFor:"emoji_chance",children:"表情包激活概率"}),e.jsxs("span",{className:"text-sm text-muted-foreground",children:[(n.emoji_chance*100).toFixed(0),"%"]})]}),e.jsx(ie,{id:"emoji_chance",type:"range",min:"0",max:"1",step:"0.1",value:n.emoji_chance,onChange:i=>r({...n,emoji_chance:Number(i.target.value)})}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"机器人发送表情包的概率"})]}),e.jsxs("div",{className:"space-y-3",children:[e.jsx(C,{htmlFor:"max_reg_num",children:"最大表情包数量"}),e.jsx(ie,{id:"max_reg_num",type:"number",min:"1",max:"200",value:n.max_reg_num,onChange:i=>r({...n,max_reg_num:Number(i.target.value)})}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"机器人最多保存的表情包数量"})]}),e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"space-y-1",children:[e.jsx(C,{htmlFor:"do_replace",children:"达到最大数量时替换"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"开启后会删除旧表情包,关闭则不再收集新表情包"})]}),e.jsx($e,{id:"do_replace",checked:n.do_replace,onCheckedChange:i=>r({...n,do_replace:i})})]}),e.jsxs("div",{className:"space-y-3",children:[e.jsx(C,{htmlFor:"check_interval",children:"检查间隔(分钟)"}),e.jsx(ie,{id:"check_interval",type:"number",min:"1",max:"120",value:n.check_interval,onChange:i=>r({...n,check_interval:Number(i.target.value)})}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"检查表情包注册、破损、删除的时间间隔"})]}),e.jsx(Pc,{}),e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"space-y-1",children:[e.jsx(C,{htmlFor:"steal_emoji",children:"偷取表情包"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"允许机器人将一些表情包据为己有"})]}),e.jsx($e,{id:"steal_emoji",checked:n.steal_emoji,onCheckedChange:i=>r({...n,steal_emoji:i})})]}),e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"space-y-1",children:[e.jsx(C,{htmlFor:"content_filtration",children:"启用表情包过滤"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"只保存符合要求的表情包"})]}),e.jsx($e,{id:"content_filtration",checked:n.content_filtration,onCheckedChange:i=>r({...n,content_filtration:i})})]}),n.content_filtration&&e.jsxs("div",{className:"space-y-3",children:[e.jsx(C,{htmlFor:"filtration_prompt",children:"过滤要求"}),e.jsx(ie,{id:"filtration_prompt",placeholder:"例如:符合公序良俗",value:n.filtration_prompt,onChange:i=>r({...n,filtration_prompt:i.target.value})}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"描述表情包应该符合的要求"})]})]})}function X0({config:n,onChange:r}){return e.jsxs("div",{className:"space-y-6",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"space-y-1",children:[e.jsx(C,{htmlFor:"enable_tool",children:"启用工具系统"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"允许机器人使用各种工具增强功能"})]}),e.jsx($e,{id:"enable_tool",checked:n.enable_tool,onCheckedChange:i=>r({...n,enable_tool:i})})]}),e.jsx(Pc,{}),e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"space-y-1",children:[e.jsx(C,{htmlFor:"all_global",children:"启用全局黑话模式"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"允许机器人学习和使用群组黑话"})]}),e.jsx($e,{id:"all_global",checked:n.all_global,onCheckedChange:i=>r({...n,all_global:i})})]})]})}function J0({config:n,onChange:r}){const[i,d]=u.useState(!1);return e.jsxs("div",{className:"space-y-6",children:[e.jsx("div",{className:"rounded-lg bg-blue-50 dark:bg-blue-950/30 border border-blue-200 dark:border-blue-800 p-4",children:e.jsxs("div",{className:"flex items-start gap-3",children:[e.jsx("div",{className:"mt-0.5",children:e.jsx("svg",{className:"h-5 w-5 text-blue-600 dark:text-blue-400",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",children:e.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"})})}),e.jsxs("div",{className:"flex-1 text-sm",children:[e.jsx("p",{className:"font-medium text-blue-900 dark:text-blue-100 mb-1",children:"关于硅基流动 (SiliconFlow)"}),e.jsx("p",{className:"text-blue-700 dark:text-blue-300 mb-2",children:"硅基流动提供了完整的模型覆盖,包括 DeepSeek V3、Qwen、视觉模型、语音识别和嵌入模型。 只需一个 API Key 即可使用麦麦的所有功能!"}),e.jsxs("a",{href:"https://cloud.siliconflow.cn",target:"_blank",rel:"noopener noreferrer",className:"inline-flex items-center gap-1 text-blue-600 dark:text-blue-400 hover:underline font-medium",children:["前往硅基流动获取 API Key",e.jsx(Hc,{className:"h-3 w-3"})]})]})]})}),e.jsxs("div",{className:"space-y-3",children:[e.jsx(C,{htmlFor:"siliconflow_api_key",children:"SiliconFlow API Key *"}),e.jsxs("div",{className:"relative",children:[e.jsx(ie,{id:"siliconflow_api_key",type:i?"text":"password",placeholder:"sk-...",value:n.api_key,onChange:m=>r({api_key:m.target.value}),className:"font-mono pr-10"}),e.jsx(S,{type:"button",variant:"ghost",size:"sm",className:"absolute right-0 top-0 h-full px-3 hover:bg-transparent",onClick:()=>d(!i),children:i?e.jsx(ci,{className:"h-4 w-4 text-muted-foreground"}):e.jsx(Rt,{className:"h-4 w-4 text-muted-foreground"})})]}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"请输入您的硅基流动 API 密钥。获取后,麦麦将自动配置所有必需的模型。"})]}),e.jsxs("div",{className:"rounded-lg bg-muted/50 p-4 text-sm space-y-2",children:[e.jsx("p",{className:"font-medium",children:"将自动配置以下模型:"}),e.jsxs("ul",{className:"list-disc list-inside space-y-1 text-muted-foreground ml-2",children:[e.jsx("li",{children:"DeepSeek V3 - 主要对话和工具模型"}),e.jsx("li",{children:"Qwen3 30B - 高频小任务和工具调用"}),e.jsx("li",{children:"Qwen3 VL 30B - 图像识别"}),e.jsx("li",{children:"SenseVoice - 语音识别"}),e.jsx("li",{children:"BGE-M3 - 文本嵌入"}),e.jsx("li",{children:"知识库相关模型 (LPMM)"})]})]}),e.jsx("div",{className:"rounded-lg border border-amber-200 dark:border-amber-800 bg-amber-50 dark:bg-amber-950/30 p-4",children:e.jsxs("p",{className:"text-sm text-amber-900 dark:text-amber-100",children:[e.jsx("span",{className:"font-medium",children:"💡 提示:"}),'完成向导后,您可以在"系统设置 → 模型配置"中添加更多 API 提供商和模型。']})})]})}async function Z0(){const n=await Se("/api/webui/config/bot",{method:"GET",headers:Gs()});if(!n.ok)throw new Error("读取Bot配置失败");const i=(await n.json()).config.bot||{};return{qq_account:i.qq_account||0,nickname:i.nickname||"",alias_names:i.alias_names||[]}}async function P0(){const n=await Se("/api/webui/config/bot",{method:"GET",headers:Gs()});if(!n.ok)throw new Error("读取人格配置失败");const i=(await n.json()).config.personality||{};return{personality:i.personality||"",reply_style:i.reply_style||"",interest:i.interest||"",plan_style:i.plan_style||"",private_plan_style:i.private_plan_style||""}}async function W0(){const n=await Se("/api/webui/config/bot",{method:"GET",headers:Gs()});if(!n.ok)throw new Error("读取表情包配置失败");const i=(await n.json()).config.emoji||{};return{emoji_chance:i.emoji_chance??.4,max_reg_num:i.max_reg_num??40,do_replace:i.do_replace??!0,check_interval:i.check_interval??10,steal_emoji:i.steal_emoji??!0,content_filtration:i.content_filtration??!1,filtration_prompt:i.filtration_prompt||""}}async function ew(){const n=await Se("/api/webui/config/bot",{method:"GET",headers:Gs()});if(!n.ok)throw new Error("读取其他配置失败");const i=(await n.json()).config,d=i.tool||{},m=i.expression||{};return{enable_tool:d.enable_tool??!0,all_global:m.all_global_jargon??!0}}async function sw(){const n=await Se("/api/webui/config/model",{method:"GET",headers:Gs()});if(!n.ok)throw new Error("读取模型配置失败");return{api_key:((await n.json()).config.api_providers||[]).find(x=>x.name==="SiliconFlow")?.api_key||""}}async function tw(n){const r=await Se("/api/webui/config/bot/section/bot",{method:"POST",headers:Gs(),body:JSON.stringify(n)});if(!r.ok){const i=await r.json();throw new Error(i.detail||"保存Bot基础配置失败")}return await r.json()}async function aw(n){const r=await Se("/api/webui/config/bot/section/personality",{method:"POST",headers:Gs(),body:JSON.stringify(n)});if(!r.ok){const i=await r.json();throw new Error(i.detail||"保存人格配置失败")}return await r.json()}async function lw(n){const r=await Se("/api/webui/config/bot/section/emoji",{method:"POST",headers:Gs(),body:JSON.stringify(n)});if(!r.ok){const i=await r.json();throw new Error(i.detail||"保存表情包配置失败")}return await r.json()}async function nw(n){const r=[];r.push(Se("/api/webui/config/bot/section/tool",{method:"POST",headers:Gs(),body:JSON.stringify({enable_tool:n.enable_tool})})),r.push(Se("/api/webui/config/bot/section/expression",{method:"POST",headers:Gs(),body:JSON.stringify({all_global_jargon:n.all_global})}));const i=await Promise.all(r);for(const d of i)if(!d.ok){const m=await d.json();throw new Error(m.detail||"保存其他配置失败")}return{success:!0}}async function rw(n){const r=await Se("/api/webui/config/model",{method:"GET",headers:Gs()});if(!r.ok)throw new Error("读取模型配置失败");const d=(await r.json()).config,m=d.api_providers||[],x=m.findIndex(g=>g.name==="SiliconFlow");x>=0?m[x]={...m[x],api_key:n.api_key}:m.push({name:"SiliconFlow",base_url:"https://api.siliconflow.cn/v1",api_key:n.api_key,client_type:"openai",max_retry:3,timeout:120,retry_interval:5});const f={...d,api_providers:m},p=await Se("/api/webui/config/model",{method:"POST",headers:Gs(),body:JSON.stringify(f)});if(!p.ok){const g=await p.json();throw new Error(g.detail||"保存模型配置失败")}return await p.json()}async function dp(){const n=localStorage.getItem("access-token"),r=await Se("/api/webui/setup/complete",{method:"POST",headers:{Authorization:`Bearer ${n}`}});if(!r.ok){const i=await r.json();throw new Error(i.message||"标记配置完成失败")}return await r.json()}async function Wc(){const n=await Se("/api/webui/system/restart",{method:"POST",headers:Gs()});if(!n.ok){const r=await n.json();throw new Error(r.detail||"重启失败")}return await n.json()}async function Lg(){const n=await Se("/api/webui/system/status",{method:"GET",headers:Gs()});if(!n.ok){const r=await n.json();throw new Error(r.detail||"获取状态失败")}return await n.json()}function iw(){const n=va(),{toast:r}=$s(),[i,d]=u.useState(0),[m,x]=u.useState(!1),[f,p]=u.useState(!1),[g,b]=u.useState(!0),[j,y]=u.useState({qq_account:0,nickname:"",alias_names:[]}),[N,k]=u.useState({personality:"是一个女大学生,现在在读大二,会刷贴吧。",reply_style:"请回复的平淡一些,简短一些,说中文,不要刻意突出自身学科背景。可以参考贴吧,知乎和微博的回复风格。",interest:"对技术相关话题,游戏和动漫相关话题感兴趣,也对日常话题感兴趣,不喜欢太过沉重严肃的话题",plan_style:`1.思考**所有**的可用的action中的**每个动作**是否符合当下条件,如果动作使用条件符合聊天内容就使用 -2.如果相同的内容已经被执行,请不要重复执行 -3.请控制你的发言频率,不要太过频繁的发言 -4.如果有人对你感到厌烦,请减少回复 -5.如果有人对你进行攻击,或者情绪激动,请你以合适的方法应对`,private_plan_style:`1.思考**所有**的可用的action中的**每个动作**是否符合当下条件,如果动作使用条件符合聊天内容就使用 -2.如果相同的内容已经被执行,请不要重复执行 -3.某句话如果已经被回复过,不要重复回复`}),[w,U]=u.useState({emoji_chance:.4,max_reg_num:40,do_replace:!0,check_interval:10,steal_emoji:!0,content_filtration:!1,filtration_prompt:"符合公序良俗"}),[O,B]=u.useState({enable_tool:!0,all_global:!0}),[Y,L]=u.useState({api_key:""}),[z,K]=u.useState(!1),[I,T]=u.useState(""),A=[{id:"bot-basic",title:"Bot基础",description:"配置机器人的基本信息",icon:ti},{id:"personality",title:"人格配置",description:"定义机器人的性格和说话风格",icon:Qc},{id:"emoji",title:"表情包",description:"配置表情包相关设置",icon:Vu},{id:"other",title:"其他设置",description:"工具、情绪系统等配置",icon:ar},{id:"siliconflow",title:"API配置",description:"配置硅基流动API密钥",icon:fg}],te=(i+1)/A.length*100;u.useEffect(()=>{(async()=>{try{b(!0);const[J,q,se,R,ue]=await Promise.all([Z0(),P0(),W0(),ew(),sw()]);y(J),k(q),U(se),B(R),L(ue)}catch(J){r({title:"加载配置失败",description:J instanceof Error?J.message:"无法加载现有配置,将使用默认值",variant:"destructive"})}finally{b(!1)}})()},[r]);const fe=async()=>{p(!0);try{switch(i){case 0:await tw(j);break;case 1:await aw(N);break;case 2:await lw(w);break;case 3:await nw(O);break;case 4:await rw(Y);break}return r({title:"保存成功",description:`${A[i].title}配置已保存`}),!0}catch(D){return r({title:"保存失败",description:D instanceof Error?D.message:"未知错误",variant:"destructive"}),!1}finally{p(!1)}},je=async()=>{await fe()&&i{i>0&&d(i-1)},he=async()=>{x(!0),K(!0);try{if(T("正在保存API配置..."),!await fe()){x(!1),K(!1);return}T("正在完成初始化..."),await dp(),T("正在重启麦麦..."),await Wc(),r({title:"配置完成",description:"麦麦正在重启以应用新配置..."}),T("等待麦麦重启完成...");const J=60;let q=0,se=!1;for(;qsetTimeout(R,1e3));try{(await Lg()).running&&(se=!0,T("重启成功!正在跳转..."))}catch{q++}}if(!se)throw new Error("重启超时,请手动检查麦麦状态");setTimeout(()=>{n({to:"/"})},1e3)}catch(D){K(!1),r({title:"配置失败",description:D instanceof Error?D.message:"未知错误",variant:"destructive"})}finally{x(!1)}},ve=async()=>{try{await dp(),n({to:"/"})}catch(D){r({title:"跳过失败",description:D instanceof Error?D.message:"未知错误",variant:"destructive"})}},be=()=>{switch(i){case 0:return e.jsx(I0,{config:j,onChange:y});case 1:return e.jsx(Y0,{config:N,onChange:k});case 2:return e.jsx(K0,{config:w,onChange:U});case 3:return e.jsx(X0,{config:O,onChange:B});case 4:return e.jsx(J0,{config:Y,onChange:L});default:return null}};return e.jsxs("div",{className:"relative flex min-h-screen flex-col items-center justify-center overflow-hidden bg-gradient-to-br from-primary/5 via-background to-secondary/5 p-4 md:p-6",children:[z&&e.jsx("div",{className:"fixed inset-0 z-50 flex items-center justify-center bg-background/80 backdrop-blur-sm",children:e.jsxs("div",{className:"mx-auto flex max-w-md flex-col items-center space-y-6 rounded-lg border bg-card p-8 text-center shadow-lg",children:[e.jsx("div",{className:"flex h-20 w-20 items-center justify-center rounded-full bg-primary/10",children:e.jsx(it,{className:"h-10 w-10 animate-spin text-primary"})}),e.jsxs("div",{className:"space-y-2",children:[e.jsx("h2",{className:"text-2xl font-bold",children:"正在重启麦麦"}),e.jsx("p",{className:"text-muted-foreground",children:I})]}),e.jsx("div",{className:"w-full",children:e.jsx("div",{className:"h-2 w-full overflow-hidden rounded-full bg-secondary",children:e.jsx("div",{className:"h-full w-full animate-pulse bg-primary",style:{animation:"pulse 1.5s cubic-bezier(0.4, 0, 0.6, 1) infinite"}})})}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"请稍候,这可能需要一分钟..."})]})}),e.jsxs("div",{className:"absolute inset-0 overflow-hidden pointer-events-none",children:[e.jsx("div",{className:"absolute left-1/4 top-1/4 h-64 w-64 md:h-96 md:w-96 rounded-full bg-primary/5 blur-3xl"}),e.jsx("div",{className:"absolute right-1/4 bottom-1/4 h-64 w-64 md:h-96 md:w-96 rounded-full bg-secondary/5 blur-3xl"})]}),g?e.jsxs("div",{className:"relative z-10 text-center",children:[e.jsx("div",{className:"mx-auto mb-4 flex h-16 w-16 items-center justify-center",children:e.jsx("div",{className:"h-12 w-12 animate-spin rounded-full border-4 border-primary border-t-transparent"})}),e.jsx("p",{className:"text-lg font-medium",children:"加载配置中..."}),e.jsx("p",{className:"text-sm text-muted-foreground mt-2",children:"正在读取现有配置"})]}):e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"relative z-10 w-full max-w-4xl",children:[e.jsxs("div",{className:"mb-6 md:mb-8 text-center",children:[e.jsx("div",{className:"mx-auto mb-4 flex h-12 w-12 md:h-16 md:w-16 items-center justify-center rounded-2xl bg-primary/10",children:e.jsx(sy,{className:"h-6 w-6 md:h-8 md:w-8 text-primary",strokeWidth:2,fill:"none"})}),e.jsx("h1",{className:"mb-2 text-2xl md:text-3xl font-bold",children:"首次配置向导"}),e.jsxs("p",{className:"text-sm md:text-base text-muted-foreground",children:["让我们一起完成 ",Ku," 的初始配置"]})]}),e.jsxs("div",{className:"mb-6 md:mb-8",children:[e.jsxs("div",{className:"mb-2 flex items-center justify-between text-xs md:text-sm",children:[e.jsxs("span",{className:"text-muted-foreground",children:["步骤 ",i+1," / ",A.length]}),e.jsxs("span",{className:"font-medium text-primary",children:[Math.round(te),"%"]})]}),e.jsx(rr,{value:te,className:"h-2"})]}),e.jsx("div",{className:"mb-6 md:mb-8 flex justify-between",children:A.map((D,J)=>{const q=D.icon;return e.jsxs("div",{className:$("flex flex-1 flex-col items-center gap-1 md:gap-2",Jn({to:"/"}),className:"gap-2 w-full sm:w-auto",children:[e.jsx(Jc,{className:"h-4 w-4"}),"返回首页"]}),e.jsxs(S,{size:"lg",variant:"outline",onClick:()=>window.history.back(),className:"gap-2 w-full sm:w-auto",children:[e.jsx(er,{className:"h-4 w-4"}),"返回上一页"]})]}),e.jsx("div",{className:"mt-12 pt-8 border-t border-border",children:e.jsx("p",{className:"text-sm text-muted-foreground",children:"如果您认为这是一个错误,请联系系统管理员"})})]})})}const cw=bt.memo(function({config:r,onChange:i}){const d=()=>{i({...r,platforms:[...r.platforms,""]})},m=b=>{i({...r,platforms:r.platforms.filter((j,y)=>y!==b)})},x=(b,j)=>{const y=[...r.platforms];y[b]=j,i({...r,platforms:y})},f=()=>{i({...r,alias_names:[...r.alias_names,""]})},p=b=>{i({...r,alias_names:r.alias_names.filter((j,y)=>y!==b)})},g=(b,j)=>{const y=[...r.alias_names];y[b]=j,i({...r,alias_names:y})};return e.jsx("div",{className:"rounded-lg border bg-card p-4 sm:p-6 space-y-6",children:e.jsxs("div",{children:[e.jsx("h3",{className:"text-lg font-semibold mb-4",children:"基本信息"}),e.jsxs("div",{className:"grid gap-4",children:[e.jsxs("div",{className:"grid gap-2",children:[e.jsx(C,{htmlFor:"platform",children:"平台"}),e.jsx(ie,{id:"platform",value:r.platform,onChange:b=>i({...r,platform:b.target.value}),placeholder:"qq"})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(C,{htmlFor:"qq_account",children:"QQ账号"}),e.jsx(ie,{id:"qq_account",value:r.qq_account,onChange:b=>i({...r,qq_account:b.target.value}),placeholder:"123456789"})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(C,{htmlFor:"nickname",children:"昵称"}),e.jsx(ie,{id:"nickname",value:r.nickname,onChange:b=>i({...r,nickname:b.target.value}),placeholder:"麦麦"})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(C,{children:"其他平台账号"}),e.jsxs(S,{onClick:d,size:"sm",variant:"outline",children:[e.jsx(dt,{className:"h-4 w-4 mr-1"}),"添加"]})]}),e.jsxs("div",{className:"space-y-2",children:[r.platforms.map((b,j)=>e.jsxs("div",{className:"flex gap-2",children:[e.jsx(ie,{value:b,onChange:y=>x(j,y.target.value),placeholder:"wx:114514"}),e.jsxs(hs,{children:[e.jsx(rt,{asChild:!0,children:e.jsx(S,{size:"icon",variant:"outline",children:e.jsx(We,{className:"h-4 w-4"})})}),e.jsxs(ls,{children:[e.jsxs(ns,{children:[e.jsx(is,{children:"确认删除"}),e.jsxs(cs,{children:['确定要删除平台账号 "',b||"(空)",'" 吗?此操作无法撤销。']})]}),e.jsxs(rs,{children:[e.jsx(ds,{children:"取消"}),e.jsx(os,{onClick:()=>m(j),children:"删除"})]})]})]})]},j)),r.platforms.length===0&&e.jsx("p",{className:"text-sm text-muted-foreground",children:"暂无其他平台账号"})]})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(C,{children:"别名"}),e.jsxs(S,{onClick:f,size:"sm",variant:"outline",children:[e.jsx(dt,{className:"h-4 w-4 mr-1"}),"添加"]})]}),e.jsxs("div",{className:"space-y-2",children:[r.alias_names.map((b,j)=>e.jsxs("div",{className:"flex gap-2",children:[e.jsx(ie,{value:b,onChange:y=>g(j,y.target.value),placeholder:"小麦"}),e.jsxs(hs,{children:[e.jsx(rt,{asChild:!0,children:e.jsx(S,{size:"icon",variant:"outline",children:e.jsx(We,{className:"h-4 w-4"})})}),e.jsxs(ls,{children:[e.jsxs(ns,{children:[e.jsx(is,{children:"确认删除"}),e.jsxs(cs,{children:['确定要删除别名 "',b||"(空)",'" 吗?此操作无法撤销。']})]}),e.jsxs(rs,{children:[e.jsx(ds,{children:"取消"}),e.jsx(os,{onClick:()=>p(j),children:"删除"})]})]})]})]},j)),r.alias_names.length===0&&e.jsx("p",{className:"text-sm text-muted-foreground",children:"暂无别名"})]})]})]})]})})}),ow=bt.memo(function({config:r,onChange:i}){const d=()=>{i({...r,states:[...r.states,""]})},m=f=>{i({...r,states:r.states.filter((p,g)=>g!==f)})},x=(f,p)=>{const g=[...r.states];g[f]=p,i({...r,states:g})};return e.jsx("div",{className:"rounded-lg border bg-card p-4 sm:p-6 space-y-6",children:e.jsxs("div",{children:[e.jsx("h3",{className:"text-lg font-semibold mb-4",children:"人格设置"}),e.jsxs("div",{className:"grid gap-4",children:[e.jsxs("div",{className:"grid gap-2",children:[e.jsx(C,{htmlFor:"personality",children:"人格特质"}),e.jsx(Qs,{id:"personality",value:r.personality,onChange:f=>i({...r,personality:f.target.value}),placeholder:"描述人格特质和身份特征(建议120字以内)",rows:3}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"建议120字以内,描述人格特质和身份特征"})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(C,{htmlFor:"reply_style",children:"表达风格"}),e.jsx(Qs,{id:"reply_style",value:r.reply_style,onChange:f=>i({...r,reply_style:f.target.value}),placeholder:"描述说话的表达风格和习惯",rows:3})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(C,{htmlFor:"interest",children:"兴趣"}),e.jsx(Qs,{id:"interest",value:r.interest,onChange:f=>i({...r,interest:f.target.value}),placeholder:"会影响麦麦对什么话题进行回复",rows:2})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(C,{htmlFor:"plan_style",children:"说话规则与行为风格"}),e.jsx(Qs,{id:"plan_style",value:r.plan_style,onChange:f=>i({...r,plan_style:f.target.value}),placeholder:"麦麦的说话规则和行为风格",rows:5})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(C,{htmlFor:"visual_style",children:"识图规则"}),e.jsx(Qs,{id:"visual_style",value:r.visual_style,onChange:f=>i({...r,visual_style:f.target.value}),placeholder:"识图时的处理规则",rows:3})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(C,{htmlFor:"private_plan_style",children:"私聊规则"}),e.jsx(Qs,{id:"private_plan_style",value:r.private_plan_style,onChange:f=>i({...r,private_plan_style:f.target.value}),placeholder:"私聊的说话规则和行为风格",rows:4})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(C,{children:"状态列表(人格多样性)"}),e.jsxs(S,{onClick:d,size:"sm",variant:"outline",children:[e.jsx(dt,{className:"h-4 w-4 mr-1"}),"添加状态"]})]}),e.jsx("div",{className:"space-y-2",children:r.states.map((f,p)=>e.jsxs("div",{className:"flex gap-2",children:[e.jsx(Qs,{value:f,onChange:g=>x(p,g.target.value),placeholder:"描述一个人格状态",rows:2}),e.jsxs(hs,{children:[e.jsx(rt,{asChild:!0,children:e.jsx(S,{size:"icon",variant:"outline",children:e.jsx(We,{className:"h-4 w-4"})})}),e.jsxs(ls,{children:[e.jsxs(ns,{children:[e.jsx(is,{children:"确认删除"}),e.jsx(cs,{children:"确定要删除这个人格状态吗?此操作无法撤销。"})]}),e.jsxs(rs,{children:[e.jsx(ds,{children:"取消"}),e.jsx(os,{onClick:()=>m(p),children:"删除"})]})]})]})]},p))})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(C,{htmlFor:"state_probability",children:"状态替换概率"}),e.jsx(ie,{id:"state_probability",type:"number",step:"0.1",min:"0",max:"1",value:r.state_probability,onChange:f=>i({...r,state_probability:parseFloat(f.target.value)})}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"每次构建人格时替换 personality 的概率(0.0-1.0)"})]})]})]})})}),Ue=DN,Be=ON,Oe=u.forwardRef(({className:n,children:r,...i},d)=>e.jsxs(Jp,{ref:d,className:$("flex h-9 w-full items-center justify-between whitespace-nowrap rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm ring-offset-background data-[placeholder]:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",n),...i,children:[r,e.jsx(TN,{asChild:!0,children:e.jsx(Ll,{className:"h-4 w-4 opacity-50"})})]}));Oe.displayName=Jp.displayName;const Bg=u.forwardRef(({className:n,...r},i)=>e.jsx(Zp,{ref:i,className:$("flex cursor-default items-center justify-center py-1",n),...r,children:e.jsx(di,{className:"h-4 w-4"})}));Bg.displayName=Zp.displayName;const Hg=u.forwardRef(({className:n,...r},i)=>e.jsx(Pp,{ref:i,className:$("flex cursor-default items-center justify-center py-1",n),...r,children:e.jsx(Ll,{className:"h-4 w-4"})}));Hg.displayName=Pp.displayName;const Re=u.forwardRef(({className:n,children:r,position:i="popper",...d},m)=>e.jsx(EN,{children:e.jsxs(Wp,{ref:m,className:$("relative z-[100] max-h-[--radix-select-content-available-height] min-w-[8rem] overflow-hidden rounded-md border border-border bg-white dark:bg-gray-900 text-gray-900 dark:text-gray-100 shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-select-content-transform-origin]",i==="popper"&&"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",n),position:i,...d,children:[e.jsx(Bg,{}),e.jsx(zN,{className:$("p-1",i==="popper"&&"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]"),children:r}),e.jsx(Hg,{})]})}));Re.displayName=Wp.displayName;const dw=u.forwardRef(({className:n,...r},i)=>e.jsx(eg,{ref:i,className:$("px-2 py-1.5 text-sm font-semibold",n),...r}));dw.displayName=eg.displayName;const le=u.forwardRef(({className:n,children:r,...i},d)=>e.jsxs(sg,{ref:d,className:$("relative flex w-full cursor-default select-none items-center rounded-sm py-2 pl-2 pr-8 text-sm outline-none bg-white dark:bg-gray-900 hover:bg-gray-100 dark:hover:bg-gray-800 focus:bg-gray-100 dark:focus:bg-gray-800 data-[disabled]:pointer-events-none data-[disabled]:opacity-50",n),...i,children:[e.jsx("span",{className:"absolute right-2 flex h-3.5 w-3.5 items-center justify-center",children:e.jsx(AN,{children:e.jsx(Qt,{className:"h-4 w-4"})})}),e.jsx(MN,{children:r})]}));le.displayName=sg.displayName;const uw=u.forwardRef(({className:n,...r},i)=>e.jsx(tg,{ref:i,className:$("-mx-1 my-1 h-px bg-muted",n),...r}));uw.displayName=tg.displayName;const La=cN,Ua=oN,ka=u.forwardRef(({className:n,align:r="center",sideOffset:i=4,...d},m)=>e.jsx(iN,{children:e.jsx(qp,{ref:m,align:r,sideOffset:i,className:$("z-50 w-72 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-popover-content-transform-origin]",n),...d})}));ka.displayName=qp.displayName;const mw=bt.memo(function({value:r,onChange:i}){const[d,m]=u.useState("00"),[x,f]=u.useState("00"),[p,g]=u.useState("23"),[b,j]=u.useState("59");u.useEffect(()=>{const N=r.split("-");if(N.length===2){const[k,w]=N,[U,O]=k.split(":"),[B,Y]=w.split(":");U&&m(U.padStart(2,"0")),O&&f(O.padStart(2,"0")),B&&g(B.padStart(2,"0")),Y&&j(Y.padStart(2,"0"))}},[r]);const y=(N,k,w,U)=>{const O=`${N}:${k}-${w}:${U}`;i(O)};return e.jsxs(La,{children:[e.jsx(Ua,{asChild:!0,children:e.jsxs(S,{variant:"outline",className:"w-full justify-start font-mono text-sm",children:[e.jsx(Pn,{className:"h-4 w-4 mr-2"}),r||"选择时间段"]})}),e.jsx(ka,{className:"w-72 sm:w-80",children:e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{children:[e.jsx("h4",{className:"font-medium text-sm mb-3",children:"开始时间"}),e.jsxs("div",{className:"grid grid-cols-2 gap-2 sm:gap-3",children:[e.jsxs("div",{children:[e.jsx(C,{className:"text-xs",children:"小时"}),e.jsxs(Ue,{value:d,onValueChange:N=>{m(N),y(N,x,p,b)},children:[e.jsx(Oe,{children:e.jsx(Be,{})}),e.jsx(Re,{children:Array.from({length:24},(N,k)=>k).map(N=>e.jsx(le,{value:N.toString().padStart(2,"0"),children:N.toString().padStart(2,"0")},N))})]})]}),e.jsxs("div",{children:[e.jsx(C,{className:"text-xs",children:"分钟"}),e.jsxs(Ue,{value:x,onValueChange:N=>{f(N),y(d,N,p,b)},children:[e.jsx(Oe,{children:e.jsx(Be,{})}),e.jsx(Re,{children:Array.from({length:60},(N,k)=>k).map(N=>e.jsx(le,{value:N.toString().padStart(2,"0"),children:N.toString().padStart(2,"0")},N))})]})]})]})]}),e.jsxs("div",{children:[e.jsx("h4",{className:"font-medium text-sm mb-3",children:"结束时间"}),e.jsxs("div",{className:"grid grid-cols-2 gap-2 sm:gap-3",children:[e.jsxs("div",{children:[e.jsx(C,{className:"text-xs",children:"小时"}),e.jsxs(Ue,{value:p,onValueChange:N=>{g(N),y(d,x,N,b)},children:[e.jsx(Oe,{children:e.jsx(Be,{})}),e.jsx(Re,{children:Array.from({length:24},(N,k)=>k).map(N=>e.jsx(le,{value:N.toString().padStart(2,"0"),children:N.toString().padStart(2,"0")},N))})]})]}),e.jsxs("div",{children:[e.jsx(C,{className:"text-xs",children:"分钟"}),e.jsxs(Ue,{value:b,onValueChange:N=>{j(N),y(d,x,p,N)},children:[e.jsx(Oe,{children:e.jsx(Be,{})}),e.jsx(Re,{children:Array.from({length:60},(N,k)=>k).map(N=>e.jsx(le,{value:N.toString().padStart(2,"0"),children:N.toString().padStart(2,"0")},N))})]})]})]})]})]})})]})}),xw=bt.memo(function({rule:r}){const i=`{ target = "${r.target}", time = "${r.time}", value = ${r.value.toFixed(1)} }`;return e.jsxs(La,{children:[e.jsx(Ua,{asChild:!0,children:e.jsxs(S,{variant:"outline",size:"sm",children:[e.jsx(Rt,{className:"h-4 w-4 mr-1"}),"预览"]})}),e.jsx(ka,{className:"w-80 sm:w-96",children:e.jsxs("div",{className:"space-y-2",children:[e.jsx("h4",{className:"font-medium text-sm",children:"配置预览"}),e.jsx("div",{className:"rounded-md bg-muted p-3 font-mono text-xs break-all",children:i}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"这是保存到 bot_config.toml 文件中的格式"})]})})]})}),hw=bt.memo(function({config:r,onChange:i}){const d=()=>{i({...r,talk_value_rules:[...r.talk_value_rules,{target:"",time:"00:00-23:59",value:1}]})},m=f=>{i({...r,talk_value_rules:r.talk_value_rules.filter((p,g)=>g!==f)})},x=(f,p,g)=>{const b=[...r.talk_value_rules];b[f]={...b[f],[p]:g},i({...r,talk_value_rules:b})};return e.jsxs("div",{className:"rounded-lg border bg-card p-4 sm:p-6 space-y-6",children:[e.jsxs("div",{children:[e.jsx("h3",{className:"text-lg font-semibold mb-4",children:"聊天设置"}),e.jsxs("div",{className:"grid gap-4",children:[e.jsxs("div",{className:"grid gap-2",children:[e.jsx(C,{htmlFor:"talk_value",children:"聊天频率(基础值)"}),e.jsx(ie,{id:"talk_value",type:"number",step:"0.1",min:"0",max:"1",value:r.talk_value,onChange:f=>i({...r,talk_value:parseFloat(f.target.value)})}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"越小越沉默,范围 0-1"})]}),e.jsxs("div",{className:"flex items-center space-x-2",children:[e.jsx($e,{id:"mentioned_bot_reply",checked:r.mentioned_bot_reply,onCheckedChange:f=>i({...r,mentioned_bot_reply:f})}),e.jsx(C,{htmlFor:"mentioned_bot_reply",className:"cursor-pointer",children:"启用提及必回复"})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(C,{htmlFor:"max_context_size",children:"上下文长度"}),e.jsx(ie,{id:"max_context_size",type:"number",min:"1",value:r.max_context_size,onChange:f=>i({...r,max_context_size:parseInt(f.target.value)})})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(C,{htmlFor:"planner_smooth",children:"规划器平滑"}),e.jsx(ie,{id:"planner_smooth",type:"number",step:"1",min:"0",value:r.planner_smooth,onChange:f=>i({...r,planner_smooth:parseFloat(f.target.value)})}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"增大数值会减小 planner 负荷,推荐 1-5,0 为关闭"})]}),e.jsxs("div",{className:"flex items-center space-x-2",children:[e.jsx($e,{id:"enable_talk_value_rules",checked:r.enable_talk_value_rules,onCheckedChange:f=>i({...r,enable_talk_value_rules:f})}),e.jsx(C,{htmlFor:"enable_talk_value_rules",className:"cursor-pointer",children:"启用动态发言频率规则"})]}),e.jsxs("div",{className:"flex items-center space-x-2",children:[e.jsx($e,{id:"include_planner_reasoning",checked:r.include_planner_reasoning,onCheckedChange:f=>i({...r,include_planner_reasoning:f})}),e.jsx(C,{htmlFor:"include_planner_reasoning",className:"cursor-pointer",children:"将 planner 推理加入 replyer"})]})]})]}),r.enable_talk_value_rules&&e.jsxs("div",{className:"border-t pt-6",children:[e.jsxs("div",{className:"flex items-center justify-between mb-4",children:[e.jsxs("div",{children:[e.jsx("h4",{className:"text-base font-semibold",children:"动态发言频率规则"}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:"按时段或聊天流ID调整发言频率,优先匹配具体聊天,再匹配全局规则"})]}),e.jsxs(S,{onClick:d,size:"sm",children:[e.jsx(dt,{className:"h-4 w-4 mr-1"}),"添加规则"]})]}),r.talk_value_rules&&r.talk_value_rules.length>0?e.jsx("div",{className:"space-y-4",children:r.talk_value_rules.map((f,p)=>e.jsxs("div",{className:"rounded-lg border p-4 bg-muted/50 space-y-4",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("span",{className:"text-sm font-medium text-muted-foreground",children:["规则 #",p+1]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(xw,{rule:f}),e.jsxs(hs,{children:[e.jsx(rt,{asChild:!0,children:e.jsx(S,{variant:"ghost",size:"sm",children:e.jsx(We,{className:"h-4 w-4 text-destructive"})})}),e.jsxs(ls,{children:[e.jsxs(ns,{children:[e.jsx(is,{children:"确认删除"}),e.jsxs(cs,{children:["确定要删除规则 #",p+1," 吗?此操作无法撤销。"]})]}),e.jsxs(rs,{children:[e.jsx(ds,{children:"取消"}),e.jsx(os,{onClick:()=>m(p),children:"删除"})]})]})]})]})]}),e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"grid gap-2",children:[e.jsx(C,{className:"text-xs font-medium",children:"配置类型"}),e.jsxs(Ue,{value:f.target===""?"global":"specific",onValueChange:g=>{g==="global"?x(p,"target",""):x(p,"target","qq::group")},children:[e.jsx(Oe,{children:e.jsx(Be,{})}),e.jsxs(Re,{children:[e.jsx(le,{value:"global",children:"全局配置"}),e.jsx(le,{value:"specific",children:"详细配置"})]})]})]}),f.target!==""&&(()=>{const g=f.target.split(":"),b=g[0]||"qq",j=g[1]||"",y=g[2]||"group";return e.jsxs("div",{className:"grid gap-4 p-3 sm:p-4 rounded-lg bg-muted/50",children:[e.jsxs("div",{className:"grid grid-cols-1 sm:grid-cols-3 gap-3",children:[e.jsxs("div",{className:"grid gap-2",children:[e.jsx(C,{className:"text-xs font-medium",children:"平台"}),e.jsxs(Ue,{value:b,onValueChange:N=>{x(p,"target",`${N}:${j}:${y}`)},children:[e.jsx(Oe,{children:e.jsx(Be,{})}),e.jsxs(Re,{children:[e.jsx(le,{value:"qq",children:"QQ"}),e.jsx(le,{value:"wx",children:"微信"})]})]})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(C,{className:"text-xs font-medium",children:"群 ID"}),e.jsx(ie,{value:j,onChange:N=>{x(p,"target",`${b}:${N.target.value}:${y}`)},placeholder:"输入群 ID",className:"font-mono text-sm"})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(C,{className:"text-xs font-medium",children:"类型"}),e.jsxs(Ue,{value:y,onValueChange:N=>{x(p,"target",`${b}:${j}:${N}`)},children:[e.jsx(Oe,{children:e.jsx(Be,{})}),e.jsxs(Re,{children:[e.jsx(le,{value:"group",children:"群组(group)"}),e.jsx(le,{value:"private",children:"私聊(private)"})]})]})]})]}),e.jsxs("p",{className:"text-xs text-muted-foreground",children:["当前聊天流 ID:",f.target||"(未设置)"]})]})})(),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(C,{className:"text-xs font-medium",children:"时间段 (Time)"}),e.jsx(mw,{value:f.time,onChange:g=>x(p,"time",g)}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"支持跨夜区间,例如 23:00-02:00"})]}),e.jsxs("div",{className:"grid gap-3",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(C,{htmlFor:`rule-value-${p}`,className:"text-xs font-medium",children:"发言频率值 (Value)"}),e.jsx(ie,{id:`rule-value-${p}`,type:"number",step:"0.01",min:"0.01",max:"1",value:f.value,onChange:g=>{const b=parseFloat(g.target.value);isNaN(b)||x(p,"value",Math.max(.01,Math.min(1,b)))},className:"w-20 h-8 text-xs"})]}),e.jsx(pa,{value:[f.value],onValueChange:g=>x(p,"value",g[0]),min:.01,max:1,step:.01,className:"w-full"}),e.jsxs("div",{className:"flex justify-between text-xs text-muted-foreground",children:[e.jsx("span",{children:"0.01 (极少发言)"}),e.jsx("span",{children:"0.5"}),e.jsx("span",{children:"1.0 (正常)"})]})]})]})]},p))}):e.jsx("div",{className:"text-center py-8 text-muted-foreground",children:e.jsx("p",{className:"text-sm",children:'暂无规则,点击"添加规则"按钮创建'})}),e.jsxs("div",{className:"mt-4 p-4 bg-blue-50 dark:bg-blue-950/20 border border-blue-200 dark:border-blue-800 rounded-lg",children:[e.jsx("h5",{className:"text-sm font-semibold text-blue-900 dark:text-blue-100 mb-2",children:"📝 规则说明"}),e.jsxs("ul",{className:"text-xs text-blue-800 dark:text-blue-200 space-y-1",children:[e.jsxs("li",{children:["• ",e.jsx("strong",{children:"Target 为空"}),":全局规则,对所有聊天生效"]}),e.jsxs("li",{children:["• ",e.jsx("strong",{children:"Target 指定"}),":仅对特定聊天流生效(格式:platform:id:type)"]}),e.jsxs("li",{children:["• ",e.jsx("strong",{children:"优先级"}),":先匹配具体聊天流规则,再匹配全局规则"]}),e.jsxs("li",{children:["• ",e.jsx("strong",{children:"时间支持跨夜"}),":例如 23:00-02:00 表示晚上11点到次日凌晨2点"]}),e.jsxs("li",{children:["• ",e.jsx("strong",{children:"数值范围"}),":建议 0-1,0 表示完全沉默,1 表示正常发言"]})]})]})]})]})}),fw=bt.memo(function({config:r,onChange:i}){return e.jsxs("div",{className:"rounded-lg border bg-card p-4 sm:p-6 space-y-4",children:[e.jsx("h3",{className:"text-lg font-semibold",children:"语音设置"}),e.jsxs("div",{className:"flex items-center space-x-2",children:[e.jsx($e,{checked:r.enable_asr,onCheckedChange:d=>i({...r,enable_asr:d})}),e.jsx(C,{className:"cursor-pointer",children:"启用语音识别"})]}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"启用后麦麦可以识别语音消息,需要配置语音识别模型"})]})}),pw=bt.memo(function({config:r,onChange:i}){return e.jsxs("div",{className:"rounded-lg border bg-card p-4 sm:p-6 space-y-4",children:[e.jsx("h3",{className:"text-lg font-semibold",children:"LPMM 知识库设置"}),e.jsxs("div",{className:"grid gap-4",children:[e.jsxs("div",{className:"flex items-center space-x-2",children:[e.jsx($e,{checked:r.enable,onCheckedChange:d=>i({...r,enable:d})}),e.jsx(C,{className:"cursor-pointer",children:"启用 LPMM 知识库"})]}),r.enable&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"grid gap-2",children:[e.jsx(C,{children:"LPMM 模式"}),e.jsxs(Ue,{value:r.lpmm_mode,onValueChange:d=>i({...r,lpmm_mode:d}),children:[e.jsx(Oe,{children:e.jsx(Be,{placeholder:"选择 LPMM 模式"})}),e.jsxs(Re,{children:[e.jsx(le,{value:"classic",children:"经典模式"}),e.jsx(le,{value:"agent",children:"Agent 模式"})]})]})]}),e.jsxs("div",{className:"grid grid-cols-1 sm:grid-cols-2 gap-4",children:[e.jsxs("div",{className:"grid gap-2",children:[e.jsx(C,{children:"同义词搜索 TopK"}),e.jsx(ie,{type:"number",min:"1",value:r.rag_synonym_search_top_k,onChange:d=>i({...r,rag_synonym_search_top_k:parseInt(d.target.value)})})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(C,{children:"同义词阈值"}),e.jsx(ie,{type:"number",step:"0.1",min:"0",max:"1",value:r.rag_synonym_threshold,onChange:d=>i({...r,rag_synonym_threshold:parseFloat(d.target.value)})})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(C,{children:"实体提取线程数"}),e.jsx(ie,{type:"number",min:"1",value:r.info_extraction_workers,onChange:d=>i({...r,info_extraction_workers:parseInt(d.target.value)})})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(C,{children:"嵌入向量维度"}),e.jsx(ie,{type:"number",min:"1",value:r.embedding_dimension,onChange:d=>i({...r,embedding_dimension:parseInt(d.target.value)})})]})]})]})]})]})}),gw=bt.memo(function({config:r,onChange:i}){const[d,m]=u.useState(""),[x,f]=u.useState("WARNING"),p=()=>{d&&!r.suppress_libraries.includes(d)&&(i({...r,suppress_libraries:[...r.suppress_libraries,d]}),m(""))},g=w=>{i({...r,suppress_libraries:r.suppress_libraries.filter(U=>U!==w)})},b=()=>{d&&!r.library_log_levels[d]&&(i({...r,library_log_levels:{...r.library_log_levels,[d]:x}}),m(""),f("WARNING"))},j=w=>{const U={...r.library_log_levels};delete U[w],i({...r,library_log_levels:U})},y=["DEBUG","INFO","WARNING","ERROR","CRITICAL"],N=["FULL","compact","lite"],k=["none","title","full"];return e.jsxs("div",{className:"rounded-lg border bg-card p-4 sm:p-6 space-y-6",children:[e.jsxs("div",{children:[e.jsx("h3",{className:"text-lg font-semibold mb-4",children:"日志配置"}),e.jsxs("div",{className:"grid grid-cols-1 sm:grid-cols-2 gap-4",children:[e.jsxs("div",{className:"grid gap-2",children:[e.jsx(C,{children:"日期格式"}),e.jsx(ie,{value:r.date_style,onChange:w=>i({...r,date_style:w.target.value}),placeholder:"例如: m-d H:i:s"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"m=月, d=日, H=时, i=分, s=秒"})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(C,{children:"日志级别样式"}),e.jsxs(Ue,{value:r.log_level_style,onValueChange:w=>i({...r,log_level_style:w}),children:[e.jsx(Oe,{children:e.jsx(Be,{})}),e.jsx(Re,{children:N.map(w=>e.jsx(le,{value:w,children:w},w))})]})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(C,{children:"日志文本颜色"}),e.jsxs(Ue,{value:r.color_text,onValueChange:w=>i({...r,color_text:w}),children:[e.jsx(Oe,{children:e.jsx(Be,{})}),e.jsx(Re,{children:k.map(w=>e.jsx(le,{value:w,children:w},w))})]})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(C,{children:"全局日志级别"}),e.jsxs(Ue,{value:r.log_level,onValueChange:w=>i({...r,log_level:w}),children:[e.jsx(Oe,{children:e.jsx(Be,{})}),e.jsx(Re,{children:y.map(w=>e.jsx(le,{value:w,children:w},w))})]})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(C,{children:"控制台日志级别"}),e.jsxs(Ue,{value:r.console_log_level,onValueChange:w=>i({...r,console_log_level:w}),children:[e.jsx(Oe,{children:e.jsx(Be,{})}),e.jsx(Re,{children:y.map(w=>e.jsx(le,{value:w,children:w},w))})]})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(C,{children:"文件日志级别"}),e.jsxs(Ue,{value:r.file_log_level,onValueChange:w=>i({...r,file_log_level:w}),children:[e.jsx(Oe,{children:e.jsx(Be,{})}),e.jsx(Re,{children:y.map(w=>e.jsx(le,{value:w,children:w},w))})]})]})]})]}),e.jsxs("div",{children:[e.jsx(C,{className:"mb-2 block",children:"完全屏蔽的库"}),e.jsxs("div",{className:"flex gap-2 mb-2",children:[e.jsx(ie,{value:d,onChange:w=>m(w.target.value),placeholder:"输入库名",className:"flex-1",onKeyDown:w=>{w.key==="Enter"&&(w.preventDefault(),p())}}),e.jsx(S,{onClick:p,size:"sm",className:"flex-shrink-0",children:e.jsx(dt,{className:"h-4 w-4",strokeWidth:2,fill:"none"})})]}),e.jsx("div",{className:"flex flex-wrap gap-2",children:r.suppress_libraries.map(w=>e.jsxs("div",{className:"flex items-center gap-1 bg-secondary px-3 py-1 rounded-md",children:[e.jsx("span",{className:"text-sm",children:w}),e.jsx(S,{variant:"ghost",size:"sm",className:"h-5 w-5 p-0",onClick:()=>g(w),children:e.jsx(We,{className:"h-3 w-3",strokeWidth:2,fill:"none"})})]},w))})]}),e.jsxs("div",{children:[e.jsx(C,{className:"mb-2 block",children:"特定库的日志级别"}),e.jsxs("div",{className:"flex gap-2 mb-2",children:[e.jsx(ie,{value:d,onChange:w=>m(w.target.value),placeholder:"输入库名",className:"flex-1"}),e.jsxs(Ue,{value:x,onValueChange:f,children:[e.jsx(Oe,{className:"w-32",children:e.jsx(Be,{})}),e.jsx(Re,{children:y.map(w=>e.jsx(le,{value:w,children:w},w))})]}),e.jsx(S,{onClick:b,size:"sm",children:e.jsx(dt,{className:"h-4 w-4",strokeWidth:2,fill:"none"})})]}),e.jsx("div",{className:"space-y-2",children:Object.entries(r.library_log_levels).map(([w,U])=>e.jsxs("div",{className:"flex items-center justify-between bg-secondary px-3 py-2 rounded-md",children:[e.jsx("span",{className:"text-sm font-medium",children:w}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:"text-sm text-muted-foreground",children:U}),e.jsx(S,{variant:"ghost",size:"sm",className:"h-6 w-6 p-0",onClick:()=>j(w),children:e.jsx(We,{className:"h-3 w-3",strokeWidth:2,fill:"none"})})]})]},w))})]})]})}),jw=bt.memo(function({config:r,onChange:i}){return e.jsxs("div",{className:"rounded-lg border bg-card p-4 sm:p-6 space-y-4",children:[e.jsx("h3",{className:"text-lg font-semibold",children:"调试配置"}),e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"space-y-0.5",children:[e.jsx(C,{children:"显示 Prompt"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"是否在日志中显示提示词"})]}),e.jsx($e,{checked:r.show_prompt,onCheckedChange:d=>i({...r,show_prompt:d})})]}),e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"space-y-0.5",children:[e.jsx(C,{children:"显示回复器 Prompt"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"是否显示回复器的提示词"})]}),e.jsx($e,{checked:r.show_replyer_prompt,onCheckedChange:d=>i({...r,show_replyer_prompt:d})})]}),e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"space-y-0.5",children:[e.jsx(C,{children:"显示回复器推理"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"是否显示回复器的推理过程"})]}),e.jsx($e,{checked:r.show_replyer_reasoning,onCheckedChange:d=>i({...r,show_replyer_reasoning:d})})]}),e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"space-y-0.5",children:[e.jsx(C,{children:"显示 Jargon Prompt"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"是否显示术语相关的提示词"})]}),e.jsx($e,{checked:r.show_jargon_prompt,onCheckedChange:d=>i({...r,show_jargon_prompt:d})})]}),e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"space-y-0.5",children:[e.jsx(C,{children:"显示记忆检索 Prompt"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"是否显示记忆检索相关的提示词"})]}),e.jsx($e,{checked:r.show_memory_prompt,onCheckedChange:d=>i({...r,show_memory_prompt:d})})]}),e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"space-y-0.5",children:[e.jsx(C,{children:"显示 Planner Prompt"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"是否显示 Planner 的提示词和原始返回结果"})]}),e.jsx($e,{checked:r.show_planner_prompt,onCheckedChange:d=>i({...r,show_planner_prompt:d})})]}),e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"space-y-0.5",children:[e.jsx(C,{children:"显示 LPMM 相关文段"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"是否显示 LPMM 知识库找到的相关文段日志"})]}),e.jsx($e,{checked:r.show_lpmm_paragraph,onCheckedChange:d=>i({...r,show_lpmm_paragraph:d})})]})]})]})}),vw=bt.memo(function({config:r,onChange:i}){const[d,m]=u.useState(""),x=()=>{d&&!r.auth_token.includes(d)&&(i({...r,auth_token:[...r.auth_token,d]}),m(""))},f=p=>{i({...r,auth_token:r.auth_token.filter((g,b)=>b!==p)})};return e.jsxs("div",{className:"rounded-lg border bg-card p-4 sm:p-6 space-y-6",children:[e.jsxs("div",{children:[e.jsx("h3",{className:"text-lg font-semibold mb-4",children:"MaimMessage 服务配置"}),e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"space-y-0.5",children:[e.jsx(C,{children:"启用自定义服务器"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"是否使用自定义的 MaimMessage 服务器"})]}),e.jsx($e,{checked:r.use_custom,onCheckedChange:p=>i({...r,use_custom:p})})]}),r.use_custom&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"grid grid-cols-1 sm:grid-cols-2 gap-4",children:[e.jsxs("div",{className:"grid gap-2",children:[e.jsx(C,{children:"主机地址"}),e.jsx(ie,{value:r.host,onChange:p=>i({...r,host:p.target.value}),placeholder:"127.0.0.1"})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(C,{children:"端口号"}),e.jsx(ie,{type:"number",value:r.port,onChange:p=>i({...r,port:parseInt(p.target.value)}),placeholder:"8090"})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(C,{children:"连接模式"}),e.jsxs(Ue,{value:r.mode,onValueChange:p=>i({...r,mode:p}),children:[e.jsx(Oe,{children:e.jsx(Be,{})}),e.jsxs(Re,{children:[e.jsx(le,{value:"ws",children:"WebSocket (ws)"}),e.jsx(le,{value:"tcp",children:"TCP"})]})]})]}),e.jsxs("div",{className:"flex items-center space-x-2",children:[e.jsx($e,{checked:r.use_wss,onCheckedChange:p=>i({...r,use_wss:p}),disabled:r.mode!=="ws"}),e.jsx(C,{children:"使用 WSS 安全连接"})]})]}),r.use_wss&&r.mode==="ws"&&e.jsxs("div",{className:"grid gap-4",children:[e.jsxs("div",{className:"grid gap-2",children:[e.jsx(C,{children:"SSL 证书文件路径"}),e.jsx(ie,{value:r.cert_file,onChange:p=>i({...r,cert_file:p.target.value}),placeholder:"cert.pem"})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(C,{children:"SSL 密钥文件路径"}),e.jsx(ie,{value:r.key_file,onChange:p=>i({...r,key_file:p.target.value}),placeholder:"key.pem"})]})]})]})]})]}),e.jsxs("div",{children:[e.jsx(C,{className:"mb-2 block",children:"认证令牌"}),e.jsx("p",{className:"text-sm text-muted-foreground mb-2",children:"用于 API 验证,为空则不启用验证"}),e.jsxs("div",{className:"flex gap-2 mb-2",children:[e.jsx(ie,{value:d,onChange:p=>m(p.target.value),placeholder:"输入认证令牌",onKeyDown:p=>{p.key==="Enter"&&(p.preventDefault(),x())}}),e.jsx(S,{onClick:x,size:"sm",children:e.jsx(dt,{className:"h-4 w-4",strokeWidth:2,fill:"none"})})]}),e.jsx("div",{className:"space-y-2",children:r.auth_token.map((p,g)=>e.jsxs("div",{className:"flex items-center justify-between bg-secondary px-3 py-2 rounded-md",children:[e.jsx("span",{className:"text-sm font-mono",children:p}),e.jsx(S,{variant:"ghost",size:"sm",className:"h-6 w-6 p-0",onClick:()=>f(g),children:e.jsx(We,{className:"h-3 w-3",strokeWidth:2,fill:"none"})})]},g))})]})]})}),bw=bt.memo(function({config:r,onChange:i}){return e.jsxs("div",{className:"rounded-lg border bg-card p-4 sm:p-6 space-y-4",children:[e.jsx("h3",{className:"text-lg font-semibold",children:"统计信息"}),e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"space-y-0.5",children:[e.jsx(C,{children:"启用统计信息发送"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"发送匿名统计信息,帮助我们了解全球有多少只麦麦在运行"})]}),e.jsx($e,{checked:r.enable,onCheckedChange:d=>i({...r,enable:d})})]})]})}),Nw=bt.memo(function({emojiConfig:r,memoryConfig:i,toolConfig:d,onEmojiChange:m,onMemoryChange:x,onToolChange:f}){return e.jsxs("div",{className:"space-y-6",children:[e.jsx("div",{className:"rounded-lg border bg-card p-4 sm:p-6 space-y-4",children:e.jsxs("div",{children:[e.jsx("h3",{className:"text-lg font-semibold mb-4",children:"工具设置"}),e.jsxs("div",{className:"flex items-center space-x-2",children:[e.jsx($e,{id:"enable_tool",checked:d.enable_tool,onCheckedChange:p=>f({...d,enable_tool:p})}),e.jsx(C,{htmlFor:"enable_tool",className:"cursor-pointer",children:"启用工具系统"})]}),e.jsx("p",{className:"text-xs text-muted-foreground mt-2",children:"允许麦麦使用各种工具来增强功能"})]})}),e.jsx("div",{className:"rounded-lg border bg-card p-4 sm:p-6 space-y-4",children:e.jsxs("div",{children:[e.jsx("h3",{className:"text-lg font-semibold mb-4",children:"记忆设置"}),e.jsxs("div",{className:"grid gap-4",children:[e.jsxs("div",{className:"grid gap-2",children:[e.jsx(C,{htmlFor:"max_agent_iterations",children:"记忆思考深度"}),e.jsx(ie,{id:"max_agent_iterations",type:"number",min:"1",value:i.max_agent_iterations,onChange:p=>x({...i,max_agent_iterations:parseInt(p.target.value)})}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"最低为 1(不深入思考)"})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(C,{htmlFor:"agent_timeout_seconds",children:"最长回忆时间(秒)"}),e.jsx(ie,{id:"agent_timeout_seconds",type:"number",min:"1",step:"0.1",value:i.agent_timeout_seconds??120,onChange:p=>x({...i,agent_timeout_seconds:parseFloat(p.target.value)})}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"记忆检索的超时时间,避免过长的等待"})]}),e.jsxs("div",{className:"flex items-center space-x-2",children:[e.jsx($e,{id:"enable_jargon_detection",checked:i.enable_jargon_detection??!0,onCheckedChange:p=>x({...i,enable_jargon_detection:p})}),e.jsx(C,{htmlFor:"enable_jargon_detection",className:"cursor-pointer",children:"启用黑话识别"})]}),e.jsx("p",{className:"text-xs text-muted-foreground -mt-2",children:"记忆检索过程中是否启用黑话识别"}),e.jsxs("div",{className:"flex items-center space-x-2",children:[e.jsx($e,{id:"global_memory",checked:i.global_memory??!1,onCheckedChange:p=>x({...i,global_memory:p})}),e.jsx(C,{htmlFor:"global_memory",className:"cursor-pointer",children:"全局记忆查询"})]}),e.jsx("p",{className:"text-xs text-muted-foreground -mt-2",children:"允许记忆检索在所有聊天记录中进行全局查询(忽略当前聊天流)"})]})]})}),e.jsx("div",{className:"rounded-lg border bg-card p-4 sm:p-6 space-y-4",children:e.jsxs("div",{children:[e.jsx("h3",{className:"text-lg font-semibold mb-4",children:"表情包设置"}),e.jsxs("div",{className:"grid gap-4",children:[e.jsxs("div",{className:"grid gap-2",children:[e.jsx(C,{htmlFor:"emoji_chance",children:"表情包激活概率"}),e.jsx(ie,{id:"emoji_chance",type:"number",step:"0.1",min:"0",max:"1",value:r.emoji_chance,onChange:p=>m({...r,emoji_chance:parseFloat(p.target.value)})}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"范围 0-1,越大越容易发送表情包"})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(C,{htmlFor:"max_reg_num",children:"最大注册数量"}),e.jsx(ie,{id:"max_reg_num",type:"number",min:"1",value:r.max_reg_num,onChange:p=>m({...r,max_reg_num:parseInt(p.target.value)})}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"麦麦最多可以注册的表情包数量"})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(C,{htmlFor:"check_interval",children:"检查间隔(分钟)"}),e.jsx(ie,{id:"check_interval",type:"number",min:"1",value:r.check_interval,onChange:p=>m({...r,check_interval:parseInt(p.target.value)})}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"检查表情包(注册、破损、删除)的时间间隔"})]}),e.jsxs("div",{className:"flex items-center space-x-2",children:[e.jsx($e,{id:"do_replace",checked:r.do_replace,onCheckedChange:p=>m({...r,do_replace:p})}),e.jsx(C,{htmlFor:"do_replace",className:"cursor-pointer",children:"达到最大数量时替换表情包"})]}),e.jsxs("div",{className:"flex items-center space-x-2",children:[e.jsx($e,{id:"steal_emoji",checked:r.steal_emoji,onCheckedChange:p=>m({...r,steal_emoji:p})}),e.jsx(C,{htmlFor:"steal_emoji",className:"cursor-pointer",children:"偷取表情包"})]}),e.jsx("p",{className:"text-xs text-muted-foreground -mt-2",children:"允许麦麦将看到的表情包据为己有"}),e.jsxs("div",{className:"flex items-center space-x-2",children:[e.jsx($e,{id:"content_filtration",checked:r.content_filtration,onCheckedChange:p=>m({...r,content_filtration:p})}),e.jsx(C,{htmlFor:"content_filtration",className:"cursor-pointer",children:"启用表情包过滤"})]}),r.content_filtration&&e.jsxs("div",{className:"grid gap-2 pl-6 border-l-2 border-primary/20",children:[e.jsx(C,{htmlFor:"filtration_prompt",children:"过滤要求"}),e.jsx(ie,{id:"filtration_prompt",value:r.filtration_prompt,onChange:p=>m({...r,filtration_prompt:p.target.value}),placeholder:"符合公序良俗"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"只有符合此要求的表情包才会被保存"})]})]})]})})]})}),yw=bt.memo(function({member:r,groupIndex:i,memberIndex:d,availableChatIds:m,onUpdate:x,onRemove:f}){const p=m.includes(r)||r==="*",[g,b]=u.useState(!p);return e.jsxs("div",{className:"flex gap-2",children:[e.jsx("div",{className:"flex-1 flex gap-2",children:g?e.jsxs(e.Fragment,{children:[e.jsx(ie,{value:r,onChange:j=>x(i,d,j.target.value),placeholder:'输入 "*" 或 "qq:123456:group"',className:"flex-1"}),m.length>0&&e.jsx(S,{size:"sm",variant:"outline",onClick:()=>b(!1),title:"切换到下拉选择",children:"下拉"})]}):e.jsxs(e.Fragment,{children:[e.jsxs(Ue,{value:r,onValueChange:j=>x(i,d,j),children:[e.jsx(Oe,{className:"flex-1",children:e.jsx(Be,{placeholder:"选择聊天流"})}),e.jsxs(Re,{children:[e.jsx(le,{value:"*",children:"* (全局共享)"}),m.map((j,y)=>e.jsx(le,{value:j,children:j},y))]})]}),e.jsx(S,{size:"sm",variant:"outline",onClick:()=>b(!0),title:"切换到手动输入",children:"输入"})]})}),e.jsxs(hs,{children:[e.jsx(rt,{asChild:!0,children:e.jsx(S,{size:"icon",variant:"outline",children:e.jsx(We,{className:"h-4 w-4"})})}),e.jsxs(ls,{children:[e.jsxs(ns,{children:[e.jsx(is,{children:"确认删除"}),e.jsxs(cs,{children:['确定要删除组成员 "',r||"(空)",'" 吗?此操作无法撤销。']})]}),e.jsxs(rs,{children:[e.jsx(ds,{children:"取消"}),e.jsx(os,{onClick:()=>f(i,d),children:"删除"})]})]})]})]})}),ww=bt.memo(function({config:r,onChange:i}){const d=()=>{i({...r,learning_list:[...r.learning_list,["","enable","enable","1.0"]]})},m=N=>{i({...r,learning_list:r.learning_list.filter((k,w)=>w!==N)})},x=(N,k,w)=>{const U=[...r.learning_list];U[N][k]=w,i({...r,learning_list:U})},f=({rule:N})=>{const k=`["${N[0]}", "${N[1]}", "${N[2]}", "${N[3]}"]`;return e.jsxs(La,{children:[e.jsx(Ua,{asChild:!0,children:e.jsxs(S,{variant:"outline",size:"sm",children:[e.jsx(Rt,{className:"h-4 w-4 mr-1"}),"预览"]})}),e.jsx(ka,{className:"w-80 sm:w-96",children:e.jsxs("div",{className:"space-y-2",children:[e.jsx("h4",{className:"font-medium text-sm",children:"配置预览"}),e.jsx("div",{className:"rounded-md bg-muted p-3 font-mono text-xs break-all",children:k}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"这是保存到 bot_config.toml 文件中的格式"})]})})]})},p=()=>{i({...r,expression_groups:[...r.expression_groups,[]]})},g=N=>{i({...r,expression_groups:r.expression_groups.filter((k,w)=>w!==N)})},b=N=>{const k=[...r.expression_groups];k[N]=[...k[N],""],i({...r,expression_groups:k})},j=(N,k)=>{const w=[...r.expression_groups];w[N]=w[N].filter((U,O)=>O!==k),i({...r,expression_groups:w})},y=(N,k,w)=>{const U=[...r.expression_groups];U[N][k]=w,i({...r,expression_groups:U})};return e.jsxs("div",{className:"space-y-6",children:[e.jsx("div",{className:"rounded-lg border bg-card p-4 sm:p-6 space-y-6",children:e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center justify-between mb-4",children:[e.jsxs("div",{children:[e.jsx("h3",{className:"text-lg font-semibold",children:"表达学习配置"}),e.jsx("p",{className:"text-sm text-muted-foreground mt-1",children:"配置麦麦如何学习和使用表达方式"})]}),e.jsxs(S,{onClick:d,size:"sm",variant:"outline",children:[e.jsx(dt,{className:"h-4 w-4 mr-1"}),"添加规则"]})]}),e.jsxs("div",{className:"space-y-4",children:[r.learning_list.map((N,k)=>{const w=r.learning_list.some((z,K)=>K!==k&&z[0]===""),U=N[0]==="",O=N[0].split(":"),B=O[0]||"qq",Y=O[1]||"",L=O[2]||"group";return e.jsxs("div",{className:"rounded-lg border p-4 space-y-4",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("span",{className:"text-sm font-medium",children:["规则 ",k+1," ",U&&"(全局配置)"]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(f,{rule:N}),e.jsxs(hs,{children:[e.jsx(rt,{asChild:!0,children:e.jsx(S,{size:"sm",variant:"ghost",children:e.jsx(We,{className:"h-4 w-4"})})}),e.jsxs(ls,{children:[e.jsxs(ns,{children:[e.jsx(is,{children:"确认删除"}),e.jsxs(cs,{children:["确定要删除学习规则 ",k+1," 吗?此操作无法撤销。"]})]}),e.jsxs(rs,{children:[e.jsx(ds,{children:"取消"}),e.jsx(os,{onClick:()=>m(k),children:"删除"})]})]})]})]})]}),e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"grid gap-2",children:[e.jsx(C,{className:"text-xs font-medium",children:"配置类型"}),e.jsxs(Ue,{value:U?"global":"specific",onValueChange:z=>{z==="global"?x(k,0,""):x(k,0,"qq::group")},disabled:w&&!U,children:[e.jsx(Oe,{children:e.jsx(Be,{})}),e.jsxs(Re,{children:[e.jsx(le,{value:"global",children:"全局配置"}),e.jsx(le,{value:"specific",disabled:w&&!U,children:"详细配置"})]})]}),w&&!U&&e.jsx("p",{className:"text-xs text-amber-600",children:"已存在全局配置,无法创建新的全局配置"})]}),!U&&e.jsxs("div",{className:"grid gap-4 p-3 sm:p-4 rounded-lg bg-muted/50",children:[e.jsxs("div",{className:"grid grid-cols-1 sm:grid-cols-3 gap-3",children:[e.jsxs("div",{className:"grid gap-2",children:[e.jsx(C,{className:"text-xs font-medium",children:"平台"}),e.jsxs(Ue,{value:B,onValueChange:z=>{x(k,0,`${z}:${Y}:${L}`)},children:[e.jsx(Oe,{children:e.jsx(Be,{})}),e.jsxs(Re,{children:[e.jsx(le,{value:"qq",children:"QQ"}),e.jsx(le,{value:"wx",children:"微信"})]})]})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(C,{className:"text-xs font-medium",children:"群 ID"}),e.jsx(ie,{value:Y,onChange:z=>{x(k,0,`${B}:${z.target.value}:${L}`)},placeholder:"输入群 ID",className:"font-mono text-sm"})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(C,{className:"text-xs font-medium",children:"类型"}),e.jsxs(Ue,{value:L,onValueChange:z=>{x(k,0,`${B}:${Y}:${z}`)},children:[e.jsx(Oe,{children:e.jsx(Be,{})}),e.jsxs(Re,{children:[e.jsx(le,{value:"group",children:"群组(group)"}),e.jsx(le,{value:"private",children:"私聊(private)"})]})]})]})]}),e.jsxs("p",{className:"text-xs text-muted-foreground",children:["当前聊天流 ID:",N[0]||"(未设置)"]})]}),e.jsx("div",{className:"grid gap-2",children:e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{children:[e.jsx(C,{className:"text-xs font-medium",children:"使用学到的表达"}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:"允许麦麦使用从聊天中学到的表达方式"})]}),e.jsx($e,{checked:N[1]==="enable",onCheckedChange:z=>x(k,1,z?"enable":"disable")})]})}),e.jsx("div",{className:"grid gap-2",children:e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{children:[e.jsx(C,{className:"text-xs font-medium",children:"学习表达"}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:"允许麦麦从聊天中学习新的表达方式"})]}),e.jsx($e,{checked:N[2]==="enable",onCheckedChange:z=>x(k,2,z?"enable":"disable")})]})}),e.jsxs("div",{className:"grid gap-3",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(C,{className:"text-xs font-medium",children:"学习强度"}),e.jsx(ie,{type:"number",step:"0.1",min:"0",max:"5",value:N[3],onChange:z=>{const K=parseFloat(z.target.value);isNaN(K)||x(k,3,Math.max(0,Math.min(5,K)).toFixed(1))},className:"w-20 h-8 text-xs"})]}),e.jsx(pa,{value:[parseFloat(N[3])||1],onValueChange:z=>x(k,3,z[0].toFixed(1)),min:0,max:5,step:.1,className:"w-full"}),e.jsxs("div",{className:"flex justify-between text-xs text-muted-foreground",children:[e.jsx("span",{children:"0 (不学习)"}),e.jsx("span",{children:"2.5"}),e.jsx("span",{children:"5.0 (快速学习)"})]}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"影响学习频率,最短学习间隔 = 300/学习强度(秒)"})]})]})]},k)}),r.learning_list.length===0&&e.jsx("div",{className:"text-center py-8 text-muted-foreground",children:'暂无学习规则,点击"添加规则"开始配置'})]})]})}),e.jsx("div",{className:"rounded-lg border bg-card p-4 sm:p-6 space-y-6",children:e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center justify-between mb-4",children:[e.jsxs("div",{children:[e.jsx("h3",{className:"text-lg font-semibold",children:"表达反思配置"}),e.jsx("p",{className:"text-sm text-muted-foreground mt-1",children:"配置麦麦主动向管理员询问表达方式是否合适的功能"})]}),e.jsx($e,{checked:r.reflect,onCheckedChange:N=>i({...r,reflect:N})})]}),r.reflect&&e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"rounded-lg border p-4 space-y-4",children:[e.jsx("div",{className:"flex items-center justify-between",children:e.jsx("span",{className:"text-sm font-medium",children:"反思操作员"})}),e.jsx("div",{className:"space-y-4",children:(()=>{const k=(r.reflect_operator_id||"").split(":"),w=k[0]||"qq",U=k[1]||"",O=k[2]||"private";return e.jsxs("div",{className:"grid gap-4 p-3 sm:p-4 rounded-lg bg-muted/50",children:[e.jsxs("div",{className:"grid grid-cols-1 sm:grid-cols-3 gap-3",children:[e.jsxs("div",{className:"grid gap-2",children:[e.jsx(C,{className:"text-xs font-medium",children:"平台"}),e.jsxs(Ue,{value:w,onValueChange:B=>{i({...r,reflect_operator_id:`${B}:${U}:${O}`})},children:[e.jsx(Oe,{children:e.jsx(Be,{})}),e.jsxs(Re,{children:[e.jsx(le,{value:"qq",children:"QQ"}),e.jsx(le,{value:"wx",children:"微信"})]})]})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(C,{className:"text-xs font-medium",children:"用户/群 ID"}),e.jsx(ie,{value:U,onChange:B=>{i({...r,reflect_operator_id:`${w}:${B.target.value}:${O}`})},placeholder:"输入 ID",className:"font-mono text-sm"})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(C,{className:"text-xs font-medium",children:"类型"}),e.jsxs(Ue,{value:O,onValueChange:B=>{i({...r,reflect_operator_id:`${w}:${U}:${B}`})},children:[e.jsx(Oe,{children:e.jsx(Be,{})}),e.jsxs(Re,{children:[e.jsx(le,{value:"private",children:"私聊(private)"}),e.jsx(le,{value:"group",children:"群组(group)"})]})]})]})]}),e.jsxs("p",{className:"text-xs text-muted-foreground",children:["当前操作员 ID:",r.reflect_operator_id||"(未设置)"]}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"麦麦会向此操作员询问表达方式是否合适"})]})})()})]}),e.jsxs("div",{className:"rounded-lg border p-4 space-y-4",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{children:[e.jsx("span",{className:"text-sm font-medium",children:"允许反思的聊天流"}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:"只有在此列表中的聊天流才会提出问题并跟踪。如果列表为空,则所有聊天流都可以进行表达反思"})]}),e.jsxs(S,{onClick:()=>{i({...r,allow_reflect:[...r.allow_reflect||[],"qq::group"]})},size:"sm",variant:"outline",children:[e.jsx(dt,{className:"h-4 w-4 mr-1"}),"添加聊天流"]})]}),e.jsxs("div",{className:"space-y-2",children:[(r.allow_reflect||[]).map((N,k)=>{const w=N.split(":"),U=w[0]||"qq",O=w[1]||"",B=w[2]||"group";return e.jsxs("div",{className:"flex items-center gap-2 p-3 rounded-lg bg-muted/50",children:[e.jsxs(Ue,{value:U,onValueChange:Y=>{const L=[...r.allow_reflect];L[k]=`${Y}:${O}:${B}`,i({...r,allow_reflect:L})},children:[e.jsx(Oe,{className:"w-24",children:e.jsx(Be,{})}),e.jsxs(Re,{children:[e.jsx(le,{value:"qq",children:"QQ"}),e.jsx(le,{value:"wx",children:"微信"})]})]}),e.jsx(ie,{value:O,onChange:Y=>{const L=[...r.allow_reflect];L[k]=`${U}:${Y.target.value}:${B}`,i({...r,allow_reflect:L})},placeholder:"ID",className:"flex-1 font-mono text-sm"}),e.jsxs(Ue,{value:B,onValueChange:Y=>{const L=[...r.allow_reflect];L[k]=`${U}:${O}:${Y}`,i({...r,allow_reflect:L})},children:[e.jsx(Oe,{className:"w-32",children:e.jsx(Be,{})}),e.jsxs(Re,{children:[e.jsx(le,{value:"group",children:"群组"}),e.jsx(le,{value:"private",children:"私聊"})]})]}),e.jsx(S,{onClick:()=>{i({...r,allow_reflect:r.allow_reflect.filter((Y,L)=>L!==k)})},size:"sm",variant:"ghost",children:e.jsx(We,{className:"h-4 w-4"})})]},k)}),(!r.allow_reflect||r.allow_reflect.length===0)&&e.jsx("div",{className:"text-center py-4 text-muted-foreground text-sm",children:"列表为空,所有聊天流都可以进行表达反思"})]})]})]})]})}),e.jsx("div",{className:"rounded-lg border bg-card p-4 sm:p-6 space-y-6",children:e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center justify-between mb-4",children:[e.jsxs("div",{children:[e.jsx("h3",{className:"text-lg font-semibold",children:"表达共享组配置"}),e.jsx("p",{className:"text-sm text-muted-foreground mt-1",children:"配置不同聊天流之间如何共享学到的表达方式"})]}),e.jsxs(S,{onClick:p,size:"sm",variant:"outline",children:[e.jsx(dt,{className:"h-4 w-4 mr-1"}),"添加共享组"]})]}),e.jsxs("div",{className:"space-y-4",children:[r.expression_groups.map((N,k)=>{const w=r.learning_list.map(U=>U[0]).filter(U=>U!=="");return e.jsxs("div",{className:"rounded-lg border p-4 space-y-3",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("span",{className:"text-sm font-medium",children:["共享组 ",k+1,N.length===1&&N[0]==="*"&&"(全局共享)"]}),e.jsxs("div",{className:"flex gap-2",children:[e.jsx(S,{onClick:()=>b(k),size:"sm",variant:"outline",children:e.jsx(dt,{className:"h-4 w-4"})}),e.jsxs(hs,{children:[e.jsx(rt,{asChild:!0,children:e.jsx(S,{size:"sm",variant:"ghost",children:e.jsx(We,{className:"h-4 w-4"})})}),e.jsxs(ls,{children:[e.jsxs(ns,{children:[e.jsx(is,{children:"确认删除"}),e.jsxs(cs,{children:["确定要删除共享组 ",k+1," 吗?此操作无法撤销。"]})]}),e.jsxs(rs,{children:[e.jsx(ds,{children:"取消"}),e.jsx(os,{onClick:()=>g(k),children:"删除"})]})]})]})]})]}),e.jsx("div",{className:"space-y-2",children:N.map((U,O)=>e.jsx(yw,{member:U,groupIndex:k,memberIndex:O,availableChatIds:w,onUpdate:y,onRemove:j},`${k}-${O}`))}),e.jsx("p",{className:"text-xs text-muted-foreground",children:'提示:可以从下拉框选择已配置的聊天流,或手动输入。输入 "*" 启用全局共享'})]},k)}),r.expression_groups.length===0&&e.jsx("div",{className:"text-center py-8 text-muted-foreground",children:'暂无共享组,点击"添加共享组"开始配置'})]})]})}),e.jsx("div",{className:"rounded-lg border bg-card p-4 sm:p-6 space-y-4",children:e.jsxs("div",{children:[e.jsx("h3",{className:"text-lg font-semibold mb-4",children:"黑话设置"}),e.jsxs("div",{className:"flex items-center space-x-2",children:[e.jsx($e,{id:"all_global_jargon",checked:r.all_global_jargon??!1,onCheckedChange:N=>i({...r,all_global_jargon:N})}),e.jsx(C,{htmlFor:"all_global_jargon",className:"cursor-pointer",children:"全局黑话模式"})]}),e.jsx("p",{className:"text-xs text-muted-foreground mt-2",children:"开启后,新增的黑话将默认设为全局(所有聊天流共享)。关闭后,已记录的全局黑话不会改变,需要手动删除。"})]})})]})});function _w({regex:n,reaction:r,onRegexChange:i,onReactionChange:d}){const[m,x]=u.useState(!1),[f,p]=u.useState(""),[g,b]=u.useState(null),[j,y]=u.useState(""),[N,k]=u.useState({}),[w,U]=u.useState(""),O=u.useRef(null),[B,Y]=u.useState("build"),L=T=>T.replace(/\(\?P<([^>]+)>/g,"(?<$1>"),z=(T,A=0)=>{const te=O.current;if(!te)return;const fe=te.selectionStart||0,je=te.selectionEnd||0,pe=n.substring(0,fe)+T+n.substring(je);i(pe),setTimeout(()=>{const he=fe+T.length+A;te.setSelectionRange(he,he),te.focus()},0)};u.useEffect(()=>{if(!n||!f){b(null),k({}),U(r),y("");return}try{const T=L(n),A=new RegExp(T,"g"),te=f.match(A);b(te),y("");const je=new RegExp(T).exec(f);if(je&&je.groups){k(je.groups);let pe=r;Object.entries(je.groups).forEach(([he,ve])=>{pe=pe.replace(new RegExp(`\\[${he}\\]`,"g"),ve||"")}),U(pe)}else k({}),U(r)}catch(T){y(T.message),b(null),k({}),U(r)}},[n,f,r]);const K=()=>{if(!f||!g||g.length===0)return e.jsx("span",{className:"text-muted-foreground",children:f||"请输入测试文本"});try{const T=L(n),A=new RegExp(T,"g");let te=0;const fe=[];let je;for(;(je=A.exec(f))!==null;)je.index>te&&fe.push(e.jsx("span",{children:f.substring(te,je.index)},`text-${te}`)),fe.push(e.jsx("span",{className:"bg-yellow-200 dark:bg-yellow-900 font-semibold",children:je[0]},`match-${je.index}`)),te=je.index+je[0].length;return te)",desc:"Python风格命名捕获组",moveCursor:-1},{label:"非捕获组",pattern:"(?:)",desc:"分组但不保存匹配结果",moveCursor:-1}]},{category:"字符类",items:[{label:"字符集",pattern:"[]",desc:"匹配括号内的任意字符",moveCursor:-1},{label:"排除字符",pattern:"[^]",desc:"匹配不在括号内的字符",moveCursor:-1},{label:"范围",pattern:"[a-z]",desc:"匹配a到z的字符"},{label:"中文字符",pattern:"[\\u4e00-\\u9fa5]",desc:"匹配中文汉字"}]},{category:"常用模板",items:[{label:"捕获词语",pattern:"(?P\\S+)",desc:"捕获一个词语"},{label:"捕获句子",pattern:"(?P.+)",desc:"捕获整个句子"},{label:"捕获数字",pattern:"(?P\\d+)",desc:"捕获一个或多个数字"},{label:"可选词语",pattern:"(?:词语1|词语2)",desc:"匹配多个可选项之一"}]}];return e.jsxs(qs,{open:m,onOpenChange:x,children:[e.jsx(Xu,{asChild:!0,children:e.jsxs(S,{variant:"outline",size:"sm",children:[e.jsx(Qu,{className:"h-4 w-4 mr-1"}),"正则编辑器"]})}),e.jsxs(Ls,{className:"max-w-[95vw] sm:max-w-[900px] max-h-[90vh]",children:[e.jsxs(Us,{children:[e.jsx(Bs,{children:"正则表达式编辑器"}),e.jsx(Ps,{className:"text-sm",children:"使用可视化工具构建正则表达式,并实时测试效果"})]}),e.jsx(Ze,{className:"max-h-[calc(90vh-120px)]",children:e.jsxs(ga,{value:B,onValueChange:T=>Y(T),className:"w-full",children:[e.jsxs(la,{className:"grid w-full grid-cols-2",children:[e.jsx(ss,{value:"build",children:"🔧 构建器"}),e.jsx(ss,{value:"test",children:"🧪 测试器"})]}),e.jsxs(Ts,{value:"build",className:"space-y-4 mt-4",children:[e.jsxs("div",{className:"space-y-2",children:[e.jsx(C,{className:"text-sm font-medium",children:"正则表达式"}),e.jsx(ie,{ref:O,value:n,onChange:T=>i(T.target.value),className:"font-mono text-sm",placeholder:"点击下方按钮构建正则表达式..."})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(C,{className:"text-sm font-medium",children:"Reaction 内容"}),e.jsx(Qs,{value:r,onChange:T=>d(T.target.value),placeholder:"使用 [捕获组名] 引用捕获的内容...",rows:3,className:"text-sm"})]}),e.jsxs("div",{className:"space-y-4 border-t pt-4",children:[I.map(T=>e.jsxs("div",{className:"space-y-2",children:[e.jsx("h5",{className:"text-xs font-semibold text-primary",children:T.category}),e.jsx("div",{className:"grid grid-cols-1 sm:grid-cols-2 gap-2",children:T.items.map(A=>e.jsx(S,{variant:"outline",size:"sm",className:"justify-start h-auto py-2 px-3",onClick:()=>z(A.pattern,A.moveCursor||0),children:e.jsxs("div",{className:"flex flex-col items-start w-full",children:[e.jsxs("div",{className:"flex items-center gap-2 w-full",children:[e.jsx("span",{className:"text-xs font-medium",children:A.label}),e.jsx("code",{className:"ml-auto text-xs bg-muted px-1.5 py-0.5 rounded font-mono",children:A.pattern})]}),e.jsx("span",{className:"text-xs text-muted-foreground mt-0.5",children:A.desc})]})},A.label))})]},T.category)),e.jsxs("div",{className:"space-y-2 border-t pt-4",children:[e.jsx("h5",{className:"text-xs font-semibold text-primary",children:"完整示例模板"}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(S,{variant:"outline",size:"sm",className:"w-full justify-start h-auto py-2 px-3",onClick:()=>i("^(?P\\S{1,20})是这样的$"),children:e.jsxs("div",{className:"flex flex-col items-start w-full",children:[e.jsxs("code",{className:"text-xs font-mono bg-muted px-2 py-1 rounded w-full overflow-x-auto",children:["^(?P\\S","{1,20}",")是这样的$"]}),e.jsx("span",{className:"text-xs text-muted-foreground mt-1",children:"匹配「某事物是这样的」并捕获事物名称"})]})}),e.jsx(S,{variant:"outline",size:"sm",className:"w-full justify-start h-auto py-2 px-3",onClick:()=>i("(?:[^,。.\\s]+,\\s*)?我(?:也)?[没沒]要求你\\s*(?P.+?)[.。,,]?$"),children:e.jsxs("div",{className:"flex flex-col items-start w-full",children:[e.jsx("code",{className:"text-xs font-mono bg-muted px-2 py-1 rounded w-full overflow-x-auto",children:"(?:[^,。.\\s]+,\\s*)?我(?:也)?[没沒]要求你\\s*(?P.+?)[.。,,]?$"}),e.jsx("span",{className:"text-xs text-muted-foreground mt-1",children:"匹配「我没要求你做某事」并捕获具体行为"})]})}),e.jsx(S,{variant:"outline",size:"sm",className:"w-full justify-start h-auto py-2 px-3",onClick:()=>i("(?P.+?)(?:是|为什么|怎么)"),children:e.jsxs("div",{className:"flex flex-col items-start w-full",children:[e.jsx("code",{className:"text-xs font-mono bg-muted px-2 py-1 rounded w-full overflow-x-auto",children:"(?P.+?)(?:是|为什么|怎么)"}),e.jsx("span",{className:"text-xs text-muted-foreground mt-1",children:"捕获问题主题词"})]})})]})]})]}),e.jsxs("div",{className:"rounded-md bg-blue-50 dark:bg-blue-950/30 border border-blue-200 dark:border-blue-800 p-3 space-y-1",children:[e.jsx("p",{className:"text-xs font-medium text-blue-900 dark:text-blue-100",children:"💡 使用提示"}),e.jsxs("ul",{className:"text-xs text-blue-700 dark:text-blue-300 space-y-1 list-disc list-inside",children:[e.jsx("li",{children:"点击输入框设置光标位置,然后点击按钮插入模式"}),e.jsxs("li",{children:["命名捕获组格式:",e.jsx("code",{className:"bg-blue-100 dark:bg-blue-900 px-1 rounded",children:"(?P<名称>模式)"})]}),e.jsxs("li",{children:["在 reaction 中使用 ",e.jsx("code",{className:"bg-blue-100 dark:bg-blue-900 px-1 rounded",children:"[名称]"})," 引用捕获的内容"]}),e.jsx("li",{children:"切换到测试器标签页验证正则表达式效果"})]})]})]}),e.jsxs(Ts,{value:"test",className:"space-y-4 mt-4",children:[e.jsxs("div",{className:"space-y-2",children:[e.jsx(C,{className:"text-sm font-medium",children:"当前正则表达式"}),e.jsx("div",{className:"rounded-md bg-muted p-3 font-mono text-xs break-all",children:n||"(未设置)"})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(C,{htmlFor:"test-text",className:"text-sm font-medium",children:"测试文本"}),e.jsx(Qs,{id:"test-text",value:f,onChange:T=>p(T.target.value),placeholder:`在此输入要测试的文本... -例如:打游戏是这样的`,className:"min-h-[100px] text-sm"})]}),j&&e.jsxs("div",{className:"rounded-md bg-destructive/10 border border-destructive/20 p-3",children:[e.jsx("p",{className:"text-sm text-destructive font-medium",children:"正则表达式错误"}),e.jsx("p",{className:"text-xs text-destructive/80 mt-1",children:j})]}),!j&&f&&e.jsxs("div",{className:"space-y-3",children:[e.jsx("div",{className:"flex items-center gap-2",children:g&&g.length>0?e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"h-2 w-2 rounded-full bg-green-500"}),e.jsxs("span",{className:"text-sm font-medium text-green-600 dark:text-green-400",children:["匹配成功 (",g.length," 处)"]})]}):e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"h-2 w-2 rounded-full bg-gray-400"}),e.jsx("span",{className:"text-sm font-medium text-muted-foreground",children:"无匹配"})]})}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(C,{className:"text-sm font-medium",children:"匹配高亮"}),e.jsx(Ze,{className:"h-40 rounded-md bg-muted p-3",children:e.jsx("div",{className:"text-sm break-words",children:K()})})]}),Object.keys(N).length>0&&e.jsxs("div",{className:"space-y-2",children:[e.jsx(C,{className:"text-sm font-medium",children:"命名捕获组"}),e.jsx(Ze,{className:"h-32 rounded-md border p-3",children:e.jsx("div",{className:"space-y-2",children:Object.entries(N).map(([T,A])=>e.jsxs("div",{className:"flex items-start gap-2 text-sm",children:[e.jsxs("span",{className:"font-mono font-semibold text-primary min-w-[80px]",children:["[",T,"]"]}),e.jsx("span",{className:"text-muted-foreground",children:"="}),e.jsx("span",{className:"font-mono bg-muted px-2 py-0.5 rounded",children:A})]},T))})})]}),Object.keys(N).length>0&&r&&e.jsxs("div",{className:"space-y-2",children:[e.jsx(C,{className:"text-sm font-medium",children:"Reaction 替换预览"}),e.jsx(Ze,{className:"h-48 rounded-md bg-blue-50 dark:bg-blue-950/30 border border-blue-200 dark:border-blue-800 p-3",children:e.jsx("div",{className:"text-sm break-words",children:w})}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"reaction 中的 [name] 已被替换为对应的捕获组值"})]})]}),e.jsxs("div",{className:"rounded-md bg-blue-50 dark:bg-blue-950/30 border border-blue-200 dark:border-blue-800 p-3 space-y-1",children:[e.jsx("p",{className:"text-xs font-medium text-blue-900 dark:text-blue-100",children:"💡 测试说明"}),e.jsxs("ul",{className:"text-xs text-blue-700 dark:text-blue-300 space-y-1 list-disc list-inside",children:[e.jsx("li",{children:"匹配的文本会以黄色背景高亮显示"}),e.jsx("li",{children:"命名捕获组的值会显示在下方列表中"}),e.jsx("li",{children:"Reaction 替换预览显示最终生成的反应内容"}),e.jsx("li",{children:"如需修改正则,切换回构建器标签页"})]})]})]})]})})]})]})}const Sw=bt.memo(function({keywordReactionConfig:r,responsePostProcessConfig:i,chineseTypoConfig:d,responseSplitterConfig:m,onKeywordReactionChange:x,onResponsePostProcessChange:f,onChineseTypoChange:p,onResponseSplitterChange:g}){const b=()=>{x({...r,regex_rules:[...r.regex_rules,{regex:[""],reaction:""}]})},j=z=>{x({...r,regex_rules:r.regex_rules.filter((K,I)=>I!==z)})},y=(z,K,I)=>{const T=[...r.regex_rules];K==="regex"&&typeof I=="string"?T[z]={...T[z],regex:[I]}:K==="reaction"&&typeof I=="string"&&(T[z]={...T[z],reaction:I}),x({...r,regex_rules:T})},N=()=>{x({...r,keyword_rules:[...r.keyword_rules,{keywords:[],reaction:""}]})},k=z=>{x({...r,keyword_rules:r.keyword_rules.filter((K,I)=>I!==z)})},w=(z,K,I)=>{const T=[...r.keyword_rules];typeof I=="string"&&(T[z]={...T[z],reaction:I}),x({...r,keyword_rules:T})},U=z=>{const K=[...r.keyword_rules];K[z]={...K[z],keywords:[...K[z].keywords||[],""]},x({...r,keyword_rules:K})},O=(z,K)=>{const I=[...r.keyword_rules];I[z]={...I[z],keywords:(I[z].keywords||[]).filter((T,A)=>A!==K)},x({...r,keyword_rules:I})},B=(z,K,I)=>{const T=[...r.keyword_rules],A=[...T[z].keywords||[]];A[K]=I,T[z]={...T[z],keywords:A},x({...r,keyword_rules:T})},Y=({rule:z})=>{const K=`{ regex = [${(z.regex||[]).map(I=>`"${I}"`).join(", ")}], reaction = "${z.reaction}" }`;return e.jsxs(La,{children:[e.jsx(Ua,{asChild:!0,children:e.jsxs(S,{variant:"outline",size:"sm",children:[e.jsx(Rt,{className:"h-4 w-4 mr-1"}),"预览"]})}),e.jsx(ka,{className:"w-[95vw] sm:w-[500px]",children:e.jsxs("div",{className:"space-y-2",children:[e.jsx("h4",{className:"font-medium text-sm",children:"配置预览"}),e.jsx(Ze,{className:"h-60 rounded-md bg-muted p-3",children:e.jsx("pre",{className:"font-mono text-xs break-all",children:K})}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"这是保存到 bot_config.toml 文件中的格式"})]})})]})},L=({rule:z})=>{const K=`[[keyword_reaction.keyword_rules]] -keywords = [${(z.keywords||[]).map(I=>`"${I}"`).join(", ")}] -reaction = "${z.reaction}"`;return e.jsxs(La,{children:[e.jsx(Ua,{asChild:!0,children:e.jsxs(S,{variant:"outline",size:"sm",children:[e.jsx(Rt,{className:"h-4 w-4 mr-1"}),"预览"]})}),e.jsx(ka,{className:"w-[95vw] sm:w-[500px]",children:e.jsxs("div",{className:"space-y-2",children:[e.jsx("h4",{className:"font-medium text-sm",children:"配置预览"}),e.jsx(Ze,{className:"h-60 rounded-md bg-muted p-3",children:e.jsx("pre",{className:"font-mono text-xs whitespace-pre-wrap break-all",children:K})}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"这是保存到 bot_config.toml 文件中的格式"})]})})]})};return e.jsxs("div",{className:"space-y-6",children:[e.jsxs("div",{className:"rounded-lg border bg-card p-4 sm:p-6 space-y-6",children:[e.jsxs("div",{children:[e.jsx("h3",{className:"text-lg font-semibold mb-2",children:"关键词反应配置"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"配置触发特定反应的关键词和正则表达式规则"})]}),e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{children:[e.jsx("h4",{className:"text-base font-semibold",children:"正则表达式规则"}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:"使用正则表达式匹配消息内容"})]}),e.jsxs(S,{onClick:b,size:"sm",variant:"outline",children:[e.jsx(dt,{className:"h-4 w-4 mr-1"}),"添加正则规则"]})]}),e.jsxs("div",{className:"space-y-3",children:[r.regex_rules.map((z,K)=>e.jsxs("div",{className:"rounded-lg border p-4 space-y-3",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("span",{className:"text-sm font-medium",children:["正则规则 ",K+1]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(_w,{regex:z.regex&&z.regex[0]||"",reaction:z.reaction,onRegexChange:I=>y(K,"regex",I),onReactionChange:I=>y(K,"reaction",I)}),e.jsx(Y,{rule:z}),e.jsxs(hs,{children:[e.jsx(rt,{asChild:!0,children:e.jsx(S,{size:"sm",variant:"ghost",children:e.jsx(We,{className:"h-4 w-4"})})}),e.jsxs(ls,{children:[e.jsxs(ns,{children:[e.jsx(is,{children:"确认删除"}),e.jsxs(cs,{children:["确定要删除正则规则 ",K+1," 吗?此操作无法撤销。"]})]}),e.jsxs(rs,{children:[e.jsx(ds,{children:"取消"}),e.jsx(os,{onClick:()=>j(K),children:"删除"})]})]})]})]})]}),e.jsxs("div",{className:"space-y-3",children:[e.jsxs("div",{className:"grid gap-2",children:[e.jsx(C,{className:"text-xs font-medium",children:"正则表达式(Python 语法)"}),e.jsx(ie,{value:z.regex&&z.regex[0]||"",onChange:I=>y(K,"regex",I.target.value),placeholder:"例如:^(?P\\\\S{1,20})是这样的$ (点击正则编辑器按钮可视化构建)",className:"font-mono text-sm"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:'支持命名捕获组 (?Ppattern),可在 reaction 中使用 [name] 引用。点击"正则编辑器"可视化构建和测试!'})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(C,{className:"text-xs font-medium",children:"反应内容"}),e.jsx(Qs,{value:z.reaction,onChange:I=>y(K,"reaction",I.target.value),placeholder:`触发后麦麦的反应... -可以使用 [捕获组名] 来引用正则表达式中的内容`,rows:3,className:"text-sm"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"使用 [捕获组名] 引用正则表达式中的命名捕获组,例如 [n] 会被替换为捕获的内容"})]})]})]},K)),r.regex_rules.length===0&&e.jsx("div",{className:"text-center py-8 text-muted-foreground",children:'暂无正则规则,点击"添加正则规则"开始配置'})]})]}),e.jsxs("div",{className:"space-y-4 border-t pt-6",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{children:[e.jsx("h4",{className:"text-base font-semibold",children:"关键词规则"}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:"使用关键词列表匹配消息内容"})]}),e.jsxs(S,{onClick:N,size:"sm",variant:"outline",children:[e.jsx(dt,{className:"h-4 w-4 mr-1"}),"添加关键词规则"]})]}),e.jsxs("div",{className:"space-y-3",children:[r.keyword_rules.map((z,K)=>e.jsxs("div",{className:"rounded-lg border p-4 space-y-3",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("span",{className:"text-sm font-medium",children:["关键词规则 ",K+1]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(L,{rule:z}),e.jsxs(hs,{children:[e.jsx(rt,{asChild:!0,children:e.jsx(S,{size:"sm",variant:"ghost",children:e.jsx(We,{className:"h-4 w-4"})})}),e.jsxs(ls,{children:[e.jsxs(ns,{children:[e.jsx(is,{children:"确认删除"}),e.jsxs(cs,{children:["确定要删除关键词规则 ",K+1," 吗?此操作无法撤销。"]})]}),e.jsxs(rs,{children:[e.jsx(ds,{children:"取消"}),e.jsx(os,{onClick:()=>k(K),children:"删除"})]})]})]})]})]}),e.jsxs("div",{className:"space-y-3",children:[e.jsxs("div",{className:"grid gap-2",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(C,{className:"text-xs font-medium",children:"关键词列表"}),e.jsxs(S,{onClick:()=>U(K),size:"sm",variant:"ghost",children:[e.jsx(dt,{className:"h-3 w-3 mr-1"}),"添加关键词"]})]}),e.jsxs("div",{className:"space-y-2",children:[(z.keywords||[]).map((I,T)=>e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(ie,{value:I,onChange:A=>B(K,T,A.target.value),placeholder:"关键词",className:"flex-1"}),e.jsx(S,{onClick:()=>O(K,T),size:"sm",variant:"ghost",children:e.jsx(We,{className:"h-4 w-4"})})]},T)),(!z.keywords||z.keywords.length===0)&&e.jsx("p",{className:"text-xs text-muted-foreground text-center py-2",children:'暂无关键词,点击"添加关键词"开始配置'})]})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(C,{className:"text-xs font-medium",children:"反应内容"}),e.jsx(Qs,{value:z.reaction,onChange:I=>w(K,"reaction",I.target.value),placeholder:"触发后麦麦的反应...",rows:3,className:"text-sm"})]})]})]},K)),r.keyword_rules.length===0&&e.jsx("div",{className:"text-center py-8 text-muted-foreground",children:'暂无关键词规则,点击"添加关键词规则"开始配置'})]})]})]}),e.jsxs("div",{className:"rounded-lg border bg-card p-4 sm:p-6 space-y-6",children:[e.jsxs("div",{children:[e.jsx("h3",{className:"text-lg font-semibold mb-4",children:"回复后处理配置"}),e.jsxs("div",{className:"flex items-center space-x-2",children:[e.jsx($e,{id:"enable_response_post_process",checked:i.enable_response_post_process,onCheckedChange:z=>f({...i,enable_response_post_process:z})}),e.jsx(C,{htmlFor:"enable_response_post_process",className:"cursor-pointer",children:"启用回复后处理"})]}),e.jsx("p",{className:"text-xs text-muted-foreground mt-2",children:"包括错别字生成器和回复分割器"})]}),i.enable_response_post_process&&e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"border-t pt-6 space-y-4",children:e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center space-x-2 mb-4",children:[e.jsx($e,{id:"enable_chinese_typo",checked:d.enable,onCheckedChange:z=>p({...d,enable:z})}),e.jsx(C,{htmlFor:"enable_chinese_typo",className:"cursor-pointer font-semibold",children:"中文错别字生成器"})]}),e.jsx("p",{className:"text-xs text-muted-foreground mb-4",children:"为回复添加随机错别字,让麦麦的回复更自然"}),d.enable&&e.jsxs("div",{className:"grid gap-4 pl-6 border-l-2 border-primary/20",children:[e.jsxs("div",{className:"grid gap-2",children:[e.jsx(C,{htmlFor:"error_rate",className:"text-xs font-medium",children:"单字替换概率"}),e.jsx(ie,{id:"error_rate",type:"number",step:"0.001",min:"0",max:"1",value:d.error_rate,onChange:z=>p({...d,error_rate:parseFloat(z.target.value)})})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(C,{htmlFor:"min_freq",className:"text-xs font-medium",children:"最小字频阈值"}),e.jsx(ie,{id:"min_freq",type:"number",min:"0",value:d.min_freq,onChange:z=>p({...d,min_freq:parseInt(z.target.value)})})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(C,{htmlFor:"tone_error_rate",className:"text-xs font-medium",children:"声调错误概率"}),e.jsx(ie,{id:"tone_error_rate",type:"number",step:"0.01",min:"0",max:"1",value:d.tone_error_rate,onChange:z=>p({...d,tone_error_rate:parseFloat(z.target.value)})})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(C,{htmlFor:"word_replace_rate",className:"text-xs font-medium",children:"整词替换概率"}),e.jsx(ie,{id:"word_replace_rate",type:"number",step:"0.001",min:"0",max:"1",value:d.word_replace_rate,onChange:z=>p({...d,word_replace_rate:parseFloat(z.target.value)})})]})]})]})}),e.jsx("div",{className:"border-t pt-6 space-y-4",children:e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center space-x-2 mb-4",children:[e.jsx($e,{id:"enable_response_splitter",checked:m.enable,onCheckedChange:z=>g({...m,enable:z})}),e.jsx(C,{htmlFor:"enable_response_splitter",className:"cursor-pointer font-semibold",children:"回复分割器"})]}),e.jsx("p",{className:"text-xs text-muted-foreground mb-4",children:"控制回复的长度和句子数量"}),m.enable&&e.jsxs("div",{className:"grid gap-4 pl-6 border-l-2 border-primary/20",children:[e.jsxs("div",{className:"grid gap-2",children:[e.jsx(C,{htmlFor:"max_length",className:"text-xs font-medium",children:"最大长度"}),e.jsx(ie,{id:"max_length",type:"number",min:"1",value:m.max_length,onChange:z=>g({...m,max_length:parseInt(z.target.value)})}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"回复允许的最大字符数"})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(C,{htmlFor:"max_sentence_num",className:"text-xs font-medium",children:"最大句子数"}),e.jsx(ie,{id:"max_sentence_num",type:"number",min:"1",value:m.max_sentence_num,onChange:z=>g({...m,max_sentence_num:parseInt(z.target.value)})}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"回复允许的最大句子数量"})]}),e.jsxs("div",{className:"flex items-center space-x-2",children:[e.jsx($e,{id:"enable_kaomoji_protection",checked:m.enable_kaomoji_protection,onCheckedChange:z=>g({...m,enable_kaomoji_protection:z})}),e.jsx(C,{htmlFor:"enable_kaomoji_protection",className:"cursor-pointer",children:"启用颜文字保护"})]}),e.jsxs("div",{className:"flex items-center space-x-2",children:[e.jsx($e,{id:"enable_overflow_return_all",checked:m.enable_overflow_return_all,onCheckedChange:z=>g({...m,enable_overflow_return_all:z})}),e.jsx(C,{htmlFor:"enable_overflow_return_all",className:"cursor-pointer",children:"超出时一次性返回全部"})]}),e.jsx("p",{className:"text-xs text-muted-foreground -mt-2",children:"当句子数量超出限制时,合并后一次性返回所有内容"})]})]})})]})]})]})}),Ul="/api/webui/config";async function up(){const r=await(await Se(`${Ul}/bot`)).json();if(!r.success)throw new Error("获取配置数据失败");return r.config}async function Wn(){const r=await(await Se(`${Ul}/model`)).json();if(!r.success)throw new Error("获取模型配置数据失败");return r.config}async function mp(n){const i=await(await Se(`${Ul}/bot`,{method:"POST",body:JSON.stringify(n)})).json();if(!i.success)throw new Error(i.message||"保存配置失败")}async function Cw(){const r=await(await Se(`${Ul}/bot/raw`)).json();if(!r.success)throw new Error("获取配置源代码失败");return r.content}async function kw(n){const i=await(await Se(`${Ul}/bot/raw`,{method:"POST",body:JSON.stringify({raw_content:n})})).json();if(!i.success)throw new Error(i.message||"保存配置失败")}async function Kc(n){const i=await(await Se(`${Ul}/model`,{method:"POST",body:JSON.stringify(n)})).json();if(!i.success)throw new Error(i.message||"保存配置失败")}async function Tw(n,r){const d=await(await Se(`${Ul}/bot/section/${n}`,{method:"POST",body:JSON.stringify(r)})).json();if(!d.success)throw new Error(d.message||`保存配置节 ${n} 失败`)}async function Hu(n,r){const d=await(await Se(`${Ul}/model/section/${n}`,{method:"POST",body:JSON.stringify(r)})).json();if(!d.success)throw new Error(d.message||`保存配置节 ${n} 失败`)}async function Ew(n,r="openai",i="/models"){const d=new URLSearchParams({provider_name:n,parser:r,endpoint:i}),m=await Se(`/api/webui/models/list?${d}`);if(!m.ok){const f=await m.json().catch(()=>({}));throw new Error(f.detail||`获取模型列表失败 (${m.status})`)}const x=await m.json();if(!x.success)throw new Error("获取模型列表失败");return x.models}async function zw(n){const r=new URLSearchParams({provider_name:n}),i=await Se(`/api/webui/models/test-connection-by-name?${r}`,{method:"POST"});if(!i.ok){const d=await i.json().catch(()=>({}));throw new Error(d.detail||`测试连接失败 (${i.status})`)}return await i.json()}const Aw=tr("relative w-full rounded-lg border px-4 py-3 text-sm [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground [&>svg~*]:pl-7",{variants:{variant:{default:"bg-background text-foreground",destructive:"border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive"}},defaultVariants:{variant:"default"}}),It=u.forwardRef(({className:n,variant:r,...i},d)=>e.jsx("div",{ref:d,role:"alert",className:$(Aw({variant:r}),n),...i}));It.displayName="Alert";const Mw=u.forwardRef(({className:n,...r},i)=>e.jsx("h5",{ref:i,className:$("mb-1 font-medium leading-none tracking-tight",n),...r}));Mw.displayName="AlertTitle";const Yt=u.forwardRef(({className:n,...r},i)=>e.jsx("div",{ref:i,className:$("text-sm [&_p]:leading-relaxed",n),...r}));Yt.displayName="AlertDescription";function Zu({onRestartComplete:n,onRestartFailed:r}){const[i,d]=u.useState(0),[m,x]=u.useState("restarting"),[f,p]=u.useState(0),[g,b]=u.useState(0);u.useEffect(()=>{const N=setInterval(()=>{d(U=>U>=90?U:U+1)},200),k=setInterval(()=>{p(U=>U+1)},1e3),w=setTimeout(()=>{x("checking"),j()},3e3);return()=>{clearInterval(N),clearInterval(k),clearTimeout(w)}},[]);const j=()=>{const k=async()=>{try{if(b(U=>U+1),(await fetch("/api/webui/system/status",{method:"GET",headers:{"Content-Type":"application/json"},signal:AbortSignal.timeout(3e3)})).ok)d(100),x("success"),setTimeout(()=>{n?.()},1500);else throw new Error("Status check failed")}catch{g<60?setTimeout(k,2e3):(x("failed"),r?.())}};k()},y=N=>{const k=Math.floor(N/60),w=N%60;return`${k}:${w.toString().padStart(2,"0")}`};return e.jsx("div",{className:"fixed inset-0 bg-background/95 backdrop-blur-sm z-50 flex items-center justify-center",children:e.jsxs("div",{className:"max-w-md w-full mx-4 space-y-8",children:[e.jsxs("div",{className:"flex flex-col items-center space-y-4",children:[m==="restarting"&&e.jsxs(e.Fragment,{children:[e.jsx(it,{className:"h-16 w-16 text-primary animate-spin"}),e.jsx("h2",{className:"text-2xl font-bold",children:"正在重启麦麦"}),e.jsx("p",{className:"text-muted-foreground text-center",children:"请稍候,麦麦正在重启中..."})]}),m==="checking"&&e.jsxs(e.Fragment,{children:[e.jsx(it,{className:"h-16 w-16 text-primary animate-spin"}),e.jsx("h2",{className:"text-2xl font-bold",children:"检查服务状态"}),e.jsxs("p",{className:"text-muted-foreground text-center",children:["等待服务恢复... (尝试 ",g,"/60)"]})]}),m==="success"&&e.jsxs(e.Fragment,{children:[e.jsx(aa,{className:"h-16 w-16 text-green-500"}),e.jsx("h2",{className:"text-2xl font-bold",children:"重启成功"}),e.jsx("p",{className:"text-muted-foreground text-center",children:"正在跳转到登录页面..."})]}),m==="failed"&&e.jsxs(e.Fragment,{children:[e.jsx(At,{className:"h-16 w-16 text-destructive"}),e.jsx("h2",{className:"text-2xl font-bold",children:"重启超时"}),e.jsx("p",{className:"text-muted-foreground text-center",children:"服务未能在预期时间内恢复,请手动检查或刷新页面"})]})]}),m!=="failed"&&e.jsxs("div",{className:"space-y-2",children:[e.jsx(rr,{value:i,className:"h-2"}),e.jsxs("div",{className:"flex justify-between text-sm text-muted-foreground",children:[e.jsxs("span",{children:[i,"%"]}),e.jsxs("span",{children:["已用时: ",y(f)]})]})]}),e.jsx("div",{className:"bg-muted/50 rounded-lg p-4 space-y-2",children:e.jsxs("p",{className:"text-sm text-muted-foreground",children:[m==="restarting"&&"🔄 配置已保存,正在重启主程序...",m==="checking"&&"⏳ 正在等待服务恢复,请勿关闭页面...",m==="success"&&"✅ 配置已生效,服务运行正常",m==="failed"&&"⚠️ 如果长时间无响应,请尝试手动重启"]})}),m==="failed"&&e.jsxs("div",{className:"flex gap-2",children:[e.jsx("button",{onClick:()=>window.location.reload(),className:"flex-1 px-4 py-2 bg-primary text-primary-foreground rounded-md hover:bg-primary/90",children:"刷新页面"}),e.jsx("button",{onClick:()=>{x("checking"),b(0),j()},className:"flex-1 px-4 py-2 bg-secondary text-secondary-foreground rounded-md hover:bg-secondary/90",children:"重试检测"})]})]})})}const Dw={name:"toml",startState:function(){return{inString:!1,stringType:"",lhs:!0,inArray:0}},token:function(n,r){let i;if(!r.inString&&(i=n.match(/^('''|"""|'|")/))&&(r.stringType=i[0],r.inString=!0),n.sol()&&!r.inString&&r.inArray===0&&(r.lhs=!0),r.inString){for(;r.inString;)if(n.match(r.stringType))r.inString=!1;else if(n.peek()==="\\")n.next(),n.next();else{if(n.eol())break;n.match(/^.[^\\\"\']*/)}return r.lhs?"property":"string"}else{if(r.inArray&&n.peek()==="]")return n.next(),r.inArray--,"bracket";if(r.lhs&&n.peek()==="["&&n.skipTo("]"))return n.next(),n.peek()==="]"&&n.next(),"atom";if(n.peek()==="#")return n.skipToEnd(),"comment";if(n.eatSpace())return null;if(r.lhs&&n.eatWhile(function(d){return d!="="&&d!=" "}))return"property";if(r.lhs&&n.peek()==="=")return n.next(),r.lhs=!1,null;if(!r.lhs&&n.match(/^\d\d\d\d[\d\-\:\.T]*Z/))return"atom";if(!r.lhs&&(n.match("true")||n.match("false")))return"atom";if(!r.lhs&&n.peek()==="[")return r.inArray++,n.next(),"bracket";if(!r.lhs&&n.match(/^\-?\d+(?:\.\d+)?/))return"number";n.eatSpace()||n.next()}return null},languageData:{commentTokens:{line:"#"}}},Ow={python:[ky()],json:[Ty(),Ey()],toml:[Cy.define(Dw)],text:[]};function Rw({value:n,onChange:r,language:i="text",readOnly:d=!1,height:m="400px",minHeight:x,maxHeight:f,placeholder:p,theme:g="dark",className:b=""}){const[j,y]=u.useState(!1);if(u.useEffect(()=>{y(!0)},[]),!j)return e.jsx("div",{className:`rounded-md border bg-muted animate-pulse ${b}`,style:{height:m,minHeight:x,maxHeight:f}});const N=[...Ow[i]||[],ep.lineWrapping];return d&&N.push(ep.editable.of(!1)),e.jsx("div",{className:`rounded-md overflow-hidden border ${b}`,children:e.jsx(zy,{value:n,height:m,minHeight:x,maxHeight:f,theme:g==="dark"?Ay:void 0,extensions:N,onChange:r,placeholder:p,basicSetup:{lineNumbers:!0,highlightActiveLineGutter:!0,highlightSpecialChars:!0,history:!0,foldGutter:!0,drawSelection:!0,dropCursor:!0,allowMultipleSelections:!0,indentOnInput:!0,syntaxHighlighting:!0,bracketMatching:!0,closeBrackets:!0,autocompletion:!0,rectangularSelection:!0,crosshairCursor:!0,highlightActiveLine:!0,highlightSelectionMatches:!0,closeBracketsKeymap:!0,defaultKeymap:!0,searchKeymap:!0,historyKeymap:!0,foldKeymap:!0,completionKeymap:!0,lintKeymap:!0}})})}function Lw(n,r,i,d={}){const{debounceMs:m=2e3,onSaveSuccess:x,onSaveError:f}=d,p=u.useRef(null),g=u.useCallback(async(N,k)=>{try{r(!0),await Tw(N,k),i(!1),x?.()}catch(w){console.error(`自动保存 ${N} 失败:`,w),i(!0),f?.(w instanceof Error?w:new Error(String(w)))}finally{r(!1)}},[r,i,x,f]),b=u.useCallback((N,k)=>{n||(i(!0),p.current&&clearTimeout(p.current),p.current=setTimeout(()=>{g(N,k)},m))},[n,i,g,m]),j=u.useCallback(async(N,k)=>{p.current&&(clearTimeout(p.current),p.current=null),await g(N,k)},[g]),y=u.useCallback(()=>{p.current&&(clearTimeout(p.current),p.current=null)},[]);return u.useEffect(()=>()=>{p.current&&clearTimeout(p.current)},[]),{triggerAutoSave:b,saveNow:j,cancelPendingAutoSave:y}}function Et(n,r,i,d){u.useEffect(()=>{n&&!i&&d(r,n)},[n])}const Uw=500;function Bw(){const[n,r]=u.useState(!0),[i,d]=u.useState(!1),[m,x]=u.useState(!1),[f,p]=u.useState(!1),[g,b]=u.useState(!1),[j,y]=u.useState(!1),[N,k]=u.useState("visual"),[w,U]=u.useState(""),[O,B]=u.useState(!1),{toast:Y}=$s(),[L,z]=u.useState(null),[K,I]=u.useState(null),[T,A]=u.useState(null),[te,fe]=u.useState(null),[je,pe]=u.useState(null),[he,ve]=u.useState(null),[be,D]=u.useState(null),[J,q]=u.useState(null),[se,R]=u.useState(null),[ue,me]=u.useState(null),[_e,Ce]=u.useState(null),[ze,ge]=u.useState(null),[ae,re]=u.useState(null),[F,P]=u.useState(null),[Te,Le]=u.useState(null),[E,xe]=u.useState(null),[Ye,ke]=u.useState(null),Q=u.useRef(!0),Ne=u.useRef({}),qe=u.useCallback(ye=>{Ne.current=ye,z(ye.bot),I(ye.personality);const _s=ye.chat;_s.talk_value_rules||(_s.talk_value_rules=[]),A(_s),fe(ye.expression),pe(ye.emoji),ve(ye.memory),D(ye.tool),q(ye.voice),R(ye.lpmm_knowledge),me(ye.keyword_reaction),Ce(ye.response_post_process),ge(ye.chinese_typo),re(ye.response_splitter),P(ye.log),Le(ye.debug),xe(ye.maim_message),ke(ye.telemetry)},[]),Fs=u.useCallback(()=>({...Ne.current,bot:L,personality:K,chat:T,expression:te,emoji:je,memory:he,tool:be,voice:J,lpmm_knowledge:se,keyword_reaction:ue,response_post_process:_e,chinese_typo:ze,response_splitter:ae,log:F,debug:Te,maim_message:E,telemetry:Ye}),[L,K,T,te,je,he,be,J,se,ue,_e,ze,ae,F,Te,E,Ye]),ks=u.useCallback(async()=>{try{const ye=await Cw();U(ye),B(!1)}catch(ye){Y({variant:"destructive",title:"加载失败",description:ye instanceof Error?ye.message:"加载源代码失败"})}},[Y]),xt=u.useCallback(async()=>{try{r(!0);const ye=await up();qe(ye),p(!1),Q.current=!1,await ks()}catch(ye){console.error("加载配置失败:",ye),Y({title:"加载失败",description:"无法加载配置文件",variant:"destructive"})}finally{r(!1)}},[Y,ks,qe]);u.useEffect(()=>{xt()},[xt]);const{triggerAutoSave:js,cancelPendingAutoSave:Vs}=Lw(Q.current,x,p);Et(L,"bot",Q.current,js),Et(K,"personality",Q.current,js),Et(T,"chat",Q.current,js),Et(te,"expression",Q.current,js),Et(je,"emoji",Q.current,js),Et(he,"memory",Q.current,js),Et(be,"tool",Q.current,js),Et(J,"voice",Q.current,js),Et(se,"lpmm_knowledge",Q.current,js),Et(ue,"keyword_reaction",Q.current,js),Et(_e,"response_post_process",Q.current,js),Et(ze,"chinese_typo",Q.current,js),Et(ae,"response_splitter",Q.current,js),Et(F,"log",Q.current,js),Et(Te,"debug",Q.current,js),Et(E,"maim_message",Q.current,js),Et(Ye,"telemetry",Q.current,js);const X=async()=>{try{d(!0),await kw(w),p(!1),B(!1),Y({title:"保存成功",description:"配置已保存"}),await xt()}catch(ye){B(!0),Y({variant:"destructive",title:"保存失败",description:ye instanceof Error?ye.message:"保存配置失败"})}finally{d(!1)}},He=async ye=>{if(f){Y({variant:"destructive",title:"切换失败",description:"请先保存当前更改"});return}if(k(ye),ye==="source")await ks();else try{const _s=await up();qe(_s),p(!1)}catch(_s){console.error("加载配置失败:",_s),Y({title:"加载失败",description:"无法加载配置文件",variant:"destructive"})}},De=async()=>{try{d(!0),Vs(),await mp(Fs()),p(!1),Y({title:"保存成功",description:"麦麦主程序配置已保存"})}catch(ye){console.error("保存配置失败:",ye),Y({title:"保存失败",description:ye.message,variant:"destructive"})}finally{d(!1)}},Ke=async()=>{try{b(!0),Wc().catch(()=>{}),y(!0)}catch(ye){console.error("重启失败:",ye),y(!1),Y({title:"重启失败",description:"无法发送重启请求,请手动重启",variant:"destructive"}),b(!1)}},Ns=async()=>{try{d(!0),Vs(),await mp(Fs()),p(!1),Y({title:"保存成功",description:"配置已保存,即将重启麦麦..."}),await new Promise(ye=>setTimeout(ye,Uw)),await Ke()}catch(ye){console.error("保存失败:",ye),Y({title:"保存失败",description:ye.message,variant:"destructive"})}finally{d(!1)}},Je=()=>{localStorage.removeItem("access-token"),window.location.href="/auth"},Ks=()=>{y(!1),b(!1),Y({title:"重启失败",description:"服务器未能在预期时间内恢复,请手动检查",variant:"destructive"})};return n?e.jsx(Ze,{className:"h-full",children:e.jsx("div",{className:"space-y-4 sm:space-y-6 p-4 sm:p-6",children:e.jsx("div",{className:"flex items-center justify-center h-64",children:e.jsx("p",{className:"text-muted-foreground",children:"加载中..."})})})}):e.jsx(Ze,{className:"h-full",children:e.jsxs("div",{className:"space-y-4 sm:space-y-6 p-4 sm:p-6",children:[e.jsxs("div",{className:"flex flex-col gap-3 sm:gap-4",children:[e.jsxs("div",{className:"flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsx("h1",{className:"text-xl sm:text-2xl md:text-3xl font-bold",children:"麦麦主程序配置"}),e.jsx("p",{className:"text-muted-foreground mt-1 text-xs sm:text-sm",children:"管理麦麦的核心功能和行为设置"})]}),e.jsxs("div",{className:"flex gap-2 flex-shrink-0",children:[e.jsxs(S,{onClick:N==="visual"?De:X,disabled:i||m||!f||g,size:"sm",variant:"outline",className:"w-20 sm:w-24",children:[e.jsx(fi,{className:"h-4 w-4 flex-shrink-0",strokeWidth:2,fill:"none"}),e.jsx("span",{className:"ml-1 truncate text-xs sm:text-sm",children:i?"保存中":m?"自动":f?"保存":"已保存"})]}),e.jsxs(hs,{children:[e.jsx(rt,{asChild:!0,children:e.jsxs(S,{disabled:i||m||g,size:"sm",className:"w-20 sm:w-28",children:[e.jsx(hi,{className:"h-4 w-4 flex-shrink-0"}),e.jsx("span",{className:"ml-1 truncate text-xs sm:text-sm",children:g?"重启中":f?"保存重启":"重启"})]})}),e.jsxs(ls,{children:[e.jsxs(ns,{children:[e.jsx(is,{children:"确认重启麦麦?"}),e.jsx(cs,{asChild:!0,children:e.jsx("div",{children:e.jsx("p",{children:f?"当前有未保存的配置更改。点击确认将先保存配置,然后重启麦麦使新配置生效。重启过程中麦麦将暂时离线。":"即将重启麦麦主程序。重启过程中麦麦将暂时离线,配置将在重启后生效。"})})})]}),e.jsxs(rs,{children:[e.jsx(ds,{children:"取消"}),e.jsx(os,{onClick:f?Ns:Ke,children:f?"保存并重启":"确认重启"})]})]})]})]})]}),e.jsx("div",{className:"flex",children:e.jsx(ga,{value:N,onValueChange:ye=>He(ye),className:"w-full",children:e.jsxs(la,{className:"h-8 sm:h-9 w-full grid grid-cols-2",children:[e.jsxs(ss,{value:"visual",className:"text-xs sm:text-sm",children:[e.jsx(ly,{className:"h-3 w-3 sm:h-4 sm:w-4 mr-1"}),"可视化编辑"]}),e.jsxs(ss,{value:"source",className:"text-xs sm:text-sm",children:[e.jsx(ny,{className:"h-3 w-3 sm:h-4 sm:w-4 mr-1"}),"源代码编辑"]})]})})})]}),e.jsxs(It,{children:[e.jsx(Ra,{className:"h-4 w-4"}),e.jsxs(Yt,{children:["配置更新后需要",e.jsx("strong",{children:"重启麦麦"}),'才能生效。你可以点击右上角的"保存并重启"按钮一键完成保存和重启。']})]}),N==="source"&&e.jsxs("div",{className:"space-y-4",children:[e.jsxs(It,{children:[e.jsx(Ra,{className:"h-4 w-4"}),e.jsxs(Yt,{children:[e.jsx("strong",{children:"源代码模式(高级功能):"}),"直接编辑 TOML 配置文件。此功能仅适用于熟悉 TOML 语法的高级用户。保存时会在后端验证格式,只有格式完全正确才能保存。",O&&e.jsx("span",{className:"text-destructive font-semibold ml-2",children:"⚠️ 上次保存失败,请检查 TOML 格式"})]})]}),e.jsx(Rw,{value:w,onChange:ye=>{U(ye),p(!0),O&&B(!1)},language:"toml",theme:"dark",height:"calc(100vh - 280px)",minHeight:"500px",placeholder:"TOML 配置内容"})]}),N==="visual"&&e.jsx(e.Fragment,{children:e.jsxs(ga,{defaultValue:"bot",className:"w-full",children:[e.jsxs(la,{className:"flex flex-wrap h-auto gap-1 p-1 sm:grid sm:grid-cols-5 lg:grid-cols-9",children:[e.jsx(ss,{value:"bot",className:"text-xs px-2 py-1.5 sm:px-3 sm:py-2 data-[state=active]:shadow-sm",children:"基本信息"}),e.jsx(ss,{value:"personality",className:"text-xs px-2 py-1.5 sm:px-3 sm:py-2 data-[state=active]:shadow-sm",children:"人格"}),e.jsx(ss,{value:"chat",className:"text-xs px-2 py-1.5 sm:px-3 sm:py-2 data-[state=active]:shadow-sm",children:"聊天"}),e.jsx(ss,{value:"expression",className:"text-xs px-2 py-1.5 sm:px-3 sm:py-2 data-[state=active]:shadow-sm",children:"表达"}),e.jsx(ss,{value:"features",className:"text-xs px-2 py-1.5 sm:px-3 sm:py-2 data-[state=active]:shadow-sm",children:"功能"}),e.jsx(ss,{value:"processing",className:"text-xs px-2 py-1.5 sm:px-3 sm:py-2 data-[state=active]:shadow-sm",children:"处理"}),e.jsx(ss,{value:"voice",className:"text-xs px-2 py-1.5 sm:px-3 sm:py-2 data-[state=active]:shadow-sm",children:"语音"}),e.jsx(ss,{value:"lpmm",className:"text-xs px-2 py-1.5 sm:px-3 sm:py-2 data-[state=active]:shadow-sm",children:"知识库"}),e.jsx(ss,{value:"other",className:"text-xs px-2 py-1.5 sm:px-3 sm:py-2 data-[state=active]:shadow-sm",children:"其他"})]}),e.jsx(Ts,{value:"bot",className:"space-y-4",children:L&&e.jsx(cw,{config:L,onChange:z})}),e.jsx(Ts,{value:"personality",className:"space-y-4",children:K&&e.jsx(ow,{config:K,onChange:I})}),e.jsx(Ts,{value:"chat",className:"space-y-4",children:T&&e.jsx(hw,{config:T,onChange:A})}),e.jsx(Ts,{value:"expression",className:"space-y-4",children:te&&e.jsx(ww,{config:te,onChange:fe})}),e.jsx(Ts,{value:"features",className:"space-y-4",children:je&&he&&be&&e.jsx(Nw,{emojiConfig:je,memoryConfig:he,toolConfig:be,onEmojiChange:pe,onMemoryChange:ve,onToolChange:D})}),e.jsx(Ts,{value:"processing",className:"space-y-4",children:ue&&_e&&ze&&ae&&e.jsx(Sw,{keywordReactionConfig:ue,responsePostProcessConfig:_e,chineseTypoConfig:ze,responseSplitterConfig:ae,onKeywordReactionChange:me,onResponsePostProcessChange:Ce,onChineseTypoChange:ge,onResponseSplitterChange:re})}),e.jsx(Ts,{value:"voice",className:"space-y-4",children:J&&e.jsx(fw,{config:J,onChange:q})}),e.jsx(Ts,{value:"lpmm",className:"space-y-4",children:se&&e.jsx(pw,{config:se,onChange:R})}),e.jsxs(Ts,{value:"other",className:"space-y-4",children:[F&&e.jsx(gw,{config:F,onChange:P}),Te&&e.jsx(jw,{config:Te,onChange:Le}),E&&e.jsx(vw,{config:E,onChange:xe}),Ye&&e.jsx(bw,{config:Ye,onChange:ke})]})]})}),j&&e.jsx(Zu,{onRestartComplete:Je,onRestartFailed:Ks})]})})}const rn=u.forwardRef(({className:n,...r},i)=>e.jsx("div",{className:"relative w-full overflow-auto",children:e.jsx("table",{ref:i,className:$("w-full caption-bottom text-sm",n),...r})}));rn.displayName="Table";const cn=u.forwardRef(({className:n,...r},i)=>e.jsx("thead",{ref:i,className:$("[&_tr]:border-b",n),...r}));cn.displayName="TableHeader";const on=u.forwardRef(({className:n,...r},i)=>e.jsx("tbody",{ref:i,className:$("[&_tr:last-child]:border-0",n),...r}));on.displayName="TableBody";const Hw=u.forwardRef(({className:n,...r},i)=>e.jsx("tfoot",{ref:i,className:$("border-t bg-muted/50 font-medium [&>tr]:last:border-b-0",n),...r}));Hw.displayName="TableFooter";const ut=u.forwardRef(({className:n,...r},i)=>e.jsx("tr",{ref:i,className:$("border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted",n),...r}));ut.displayName="TableRow";const Xe=u.forwardRef(({className:n,...r},i)=>e.jsx("th",{ref:i,className:$("h-12 px-4 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",n),...r}));Xe.displayName="TableHead";const Ve=u.forwardRef(({className:n,...r},i)=>e.jsx("td",{ref:i,className:$("px-4 py-3 align-middle [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",n),...r}));Ve.displayName="TableCell";const qw=u.forwardRef(({className:n,...r},i)=>e.jsx("caption",{ref:i,className:$("mt-4 text-sm text-muted-foreground",n),...r}));qw.displayName="TableCaption";const eo=u.forwardRef(({className:n,...r},i)=>e.jsx(Kt,{ref:i,className:$("flex h-full w-full flex-col overflow-hidden rounded-md bg-popover text-popover-foreground",n),...r}));eo.displayName=Kt.displayName;const so=u.forwardRef(({className:n,...r},i)=>e.jsxs("div",{className:"flex items-center border-b px-3","cmdk-input-wrapper":"",children:[e.jsx(Mt,{className:"mr-2 h-4 w-4 shrink-0 opacity-50"}),e.jsx(Kt.Input,{ref:i,className:$("flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50",n),...r})]}));so.displayName=Kt.Input.displayName;const to=u.forwardRef(({className:n,...r},i)=>e.jsx(Kt.List,{ref:i,className:$("max-h-[300px] overflow-y-auto overflow-x-hidden",n),...r}));to.displayName=Kt.List.displayName;const ao=u.forwardRef((n,r)=>e.jsx(Kt.Empty,{ref:r,className:"py-6 text-center text-sm",...n}));ao.displayName=Kt.Empty.displayName;const mi=u.forwardRef(({className:n,...r},i)=>e.jsx(Kt.Group,{ref:i,className:$("overflow-hidden p-1 text-foreground [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground",n),...r}));mi.displayName=Kt.Group.displayName;const Gw=u.forwardRef(({className:n,...r},i)=>e.jsx(Kt.Separator,{ref:i,className:$("-mx-1 h-px bg-border",n),...r}));Gw.displayName=Kt.Separator.displayName;const xi=u.forwardRef(({className:n,...r},i)=>e.jsx(Kt.Item,{ref:i,className:$("relative flex cursor-default gap-2 select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[disabled=true]:pointer-events-none data-[selected=true]:bg-accent data-[selected=true]:text-accent-foreground data-[disabled=true]:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",n),...r}));xi.displayName=Kt.Item.displayName;const mt=u.forwardRef(({className:n,...r},i)=>e.jsx(ag,{ref:i,className:$("grid place-content-center peer h-4 w-4 shrink-0 rounded-sm border border-primary shadow focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground",n),...r,children:e.jsx(RN,{className:$("grid place-content-center text-current"),children:e.jsx(Qt,{className:"h-4 w-4"})})}));mt.displayName=ag.displayName;const qg=u.createContext(null),Gg="maibot-completed-tours";function $w(){try{const n=localStorage.getItem(Gg);return n?new Set(JSON.parse(n)):new Set}catch{return new Set}}function xp(n){localStorage.setItem(Gg,JSON.stringify([...n]))}function Fw({children:n}){const[r,i]=u.useState({activeTourId:null,stepIndex:0,isRunning:!1}),d=u.useRef(new Map),[,m]=u.useState(0),[x,f]=u.useState($w),p=u.useCallback((L,z)=>{d.current.set(L,z),m(K=>K+1)},[]),g=u.useCallback(L=>{d.current.delete(L),i(z=>z.activeTourId===L?{...z,activeTourId:null,isRunning:!1,stepIndex:0}:z)},[]),b=u.useCallback((L,z=0)=>{d.current.has(L)&&i({activeTourId:L,stepIndex:z,isRunning:!0})},[]),j=u.useCallback(()=>{i(L=>({...L,isRunning:!1}))},[]),y=u.useCallback(L=>{i(z=>({...z,stepIndex:L}))},[]),N=u.useCallback(()=>{i(L=>({...L,stepIndex:L.stepIndex+1}))},[]),k=u.useCallback(()=>{i(L=>({...L,stepIndex:Math.max(0,L.stepIndex-1)}))},[]),w=u.useCallback(()=>r.activeTourId?d.current.get(r.activeTourId)||[]:[],[r.activeTourId]),U=u.useCallback(L=>{f(z=>{const K=new Set(z);return K.add(L),xp(K),K})},[]),O=u.useCallback(L=>{const{action:z,index:K,status:I,type:T}=L,A=["finished","skipped"];if(z==="close"){i(te=>({...te,isRunning:!1,stepIndex:0}));return}A.includes(I)?i(te=>(I==="finished"&&te.activeTourId&&setTimeout(()=>U(te.activeTourId),0),{...te,isRunning:!1,stepIndex:0})):T==="step:after"&&(z==="next"?i(te=>({...te,stepIndex:K+1})):z==="prev"&&i(te=>({...te,stepIndex:K-1})))},[U]),B=u.useCallback(L=>x.has(L),[x]),Y=u.useCallback(L=>{f(z=>{const K=new Set(z);return K.delete(L),xp(K),K})},[]);return e.jsx(qg.Provider,{value:{state:r,tours:d.current,registerTour:p,unregisterTour:g,startTour:b,stopTour:j,goToStep:y,nextStep:N,prevStep:k,getCurrentSteps:w,handleJoyrideCallback:O,isTourCompleted:B,markTourCompleted:U,resetTourCompleted:Y},children:n})}function Pu(){const n=u.useContext(qg);if(!n)throw new Error("useTour must be used within a TourProvider");return n}const Vw={options:{zIndex:1e4,primaryColor:"hsl(var(--primary))",textColor:"hsl(var(--foreground))",backgroundColor:"hsl(var(--background))",arrowColor:"hsl(var(--background))",overlayColor:"rgba(0, 0, 0, 0.5)"},tooltip:{borderRadius:"var(--radius)",padding:"1rem"},tooltipContainer:{textAlign:"left"},tooltipTitle:{fontSize:"1rem",fontWeight:600,marginBottom:"0.5rem"},tooltipContent:{fontSize:"0.875rem",padding:"0.5rem 0"},buttonNext:{backgroundColor:"hsl(var(--primary))",color:"hsl(var(--primary-foreground))",borderRadius:"calc(var(--radius) - 2px)",fontSize:"0.875rem",padding:"0.5rem 1rem"},buttonBack:{color:"hsl(var(--muted-foreground))",fontSize:"0.875rem",marginRight:"0.5rem"},buttonSkip:{color:"hsl(var(--muted-foreground))",fontSize:"0.875rem"},buttonClose:{color:"hsl(var(--muted-foreground))"},spotlight:{borderRadius:"var(--radius)"}},Qw={back:"上一步",close:"关闭",last:"完成",next:"下一步",nextLabelWithProgress:"下一步 ({step}/{steps})",open:"打开对话框",skip:"跳过"};function Iw(){const{state:n,getCurrentSteps:r,handleJoyrideCallback:i}=Pu(),d=r(),[m,x]=u.useState(!1),f=u.useRef(n.stepIndex),p=u.useRef(null);u.useEffect(()=>{f.current!==n.stepIndex&&(x(!1),f.current=n.stepIndex)},[n.stepIndex]),u.useEffect(()=>{if(!n.isRunning||d.length===0){x(!1);return}const j=d[n.stepIndex];if(!j){x(!1);return}const y=j.target;if(y==="body"){x(!0);return}x(!1);const N=setTimeout(()=>{const k=()=>{const B=document.querySelector(y);if(B){const Y=B.getBoundingClientRect();if(Y.width>0&&Y.height>0)return!0}return!1};if(k()){setTimeout(()=>x(!0),100);return}const w=setInterval(()=>{k()&&(clearInterval(w),setTimeout(()=>x(!0),100))},100),U=setTimeout(()=>{clearInterval(w),x(!0)},5e3),O=()=>{clearInterval(w),clearTimeout(U)};p.current=O},150);return()=>{clearTimeout(N),p.current&&(p.current(),p.current=null)}},[n.isRunning,n.stepIndex,d]);const g=u.useRef(null);if(u.useEffect(()=>{let j=document.getElementById("tour-portal-container");return j||(j=document.createElement("div"),j.id="tour-portal-container",j.style.cssText="position: fixed; top: 0; left: 0; z-index: 99999; pointer-events: none;",document.body.appendChild(j)),g.current=j,()=>{}},[]),!n.isRunning||d.length===0||!m)return null;const b=e.jsx(My,{steps:d,stepIndex:n.stepIndex,run:n.isRunning,continuous:!0,showSkipButton:!0,showProgress:!0,disableOverlayClose:!0,disableScrolling:!1,disableScrollParentFix:!1,callback:i,styles:Vw,locale:Qw,scrollOffset:80,scrollToFirstStep:!0,floaterProps:{styles:{floater:{zIndex:99999}},disableAnimation:!0}},`tour-step-${n.stepIndex}`);return g.current?Ub.createPortal(b,g.current):b}const Ma="model-assignment-tour",$g=[{target:"body",content:"本引导旨在帮助你配置模型提供商和对应的模型,并为麦麦的各个组件分配合适的模型。",placement:"center",disableBeacon:!0,disableOverlayClose:!0,hideCloseButton:!1,spotlightClicks:!1},{target:'[data-tour="sidebar-model-provider"]',content:'第一步,你需要配置模型提供商。模型提供商决定了你要使用谁家的模型,无论是单一厂商(如 DeepSeek),还是模型平台(如 Siliconflow),都可以在这里进行配置。点击"下一步"进入配置页面。',placement:"right",disableBeacon:!0,disableOverlayClose:!0,hideCloseButton:!1,spotlightClicks:!1},{target:'[data-tour="add-provider-button"]',content:'点击"添加提供商"按钮,开始配置你的模型提供商。',placement:"bottom",disableBeacon:!0,disableOverlayClose:!0,hideCloseButton:!1,spotlightClicks:!0,hideFooter:!0},{target:'[data-tour="provider-dialog"]',content:"在这里,你可以选择你想要配置的模型提供商,填写相关信息后保存即可。",placement:"left",disableBeacon:!0,disableOverlayClose:!0,hideCloseButton:!1,spotlightClicks:!1},{target:'[data-tour="provider-name-input"]',content:"这里的名称是你为这个模型提供商起的一个名字,方便你在后续使用时识别它。",placement:"bottom",disableBeacon:!0,disableOverlayClose:!0,hideCloseButton:!1,spotlightClicks:!1},{target:'[data-tour="provider-apikey-input"]',content:"这里需要填写你从模型提供商那里获取的 API 密钥,用于验证和调用模型服务。对于不同的提供商,获取 API 密钥的方式可能有所不同,请参考对应提供商的文档。",placement:"bottom",disableBeacon:!0,disableOverlayClose:!0,hideCloseButton:!1,spotlightClicks:!1},{target:'[data-tour="provider-url-input"]',content:"这里需要填写模型提供商的 API 访问地址,确保填写正确以便系统能够连接到模型服务。对于不同的提供商,API 地址可能有所不同,请参考对应提供商的文档。",placement:"bottom",disableBeacon:!0,disableOverlayClose:!0,hideCloseButton:!1,spotlightClicks:!1},{target:'[data-tour="provider-template-select"]',content:"当然,如果你不知道如何填写这些信息,很多模型提供商在这里都提供了预设的模板供你选择,选择对应的模板后,相关信息会自动填充。",placement:"bottom",disableBeacon:!0,disableOverlayClose:!0,hideCloseButton:!1,spotlightClicks:!1},{target:'[data-tour="provider-save-button"]',content:"填写完所有信息后,点击保存按钮,模型提供商就配置完成了。",placement:"top",disableBeacon:!0,disableOverlayClose:!0,hideCloseButton:!1,spotlightClicks:!1},{target:'[data-tour="provider-cancel-button"]',content:"因为这次咱们什么都没有填写,所以点击取消按钮退出吧。",placement:"top",disableBeacon:!0,disableOverlayClose:!0,hideCloseButton:!1,spotlightClicks:!0,hideFooter:!0},{target:'[data-tour="sidebar-model-management"]',content:'配置好模型提供商后,接下来我们需要为麦麦添加模型并分配功能。点击"下一步"进入模型管理页面。',placement:"right",disableBeacon:!0,disableOverlayClose:!0,hideCloseButton:!1,spotlightClicks:!1},{target:'[data-tour="add-model-button"]',content:'在为麦麦的组件分配模型之前,首先需要添加你想要分配的模型,点击"添加模型"按钮开始添加。',placement:"bottom",disableBeacon:!0,disableOverlayClose:!0,hideCloseButton:!1,spotlightClicks:!0,hideFooter:!0},{target:'[data-tour="model-dialog"]',content:"在这里,你可以选择你之前配置好的模型提供商,然后选择对应的模型来添加。",placement:"left",disableBeacon:!0,disableOverlayClose:!0,hideCloseButton:!1,spotlightClicks:!1},{target:'[data-tour="model-name-input"]',content:"这里的模型名称是你为这个模型起的一个名字,方便你在后续使用时识别它。",placement:"bottom",disableBeacon:!0,disableOverlayClose:!0,hideCloseButton:!1,spotlightClicks:!1},{target:'[data-tour="model-provider-select"]',content:"在这里选择你之前配置好的模型提供商,这样系统才能知道你要添加哪个提供商的模型。",placement:"bottom",disableBeacon:!0,disableOverlayClose:!0,hideCloseButton:!1,spotlightClicks:!1},{target:'[data-tour="model-identifier-input"]',content:"这里需要填写你想要添加的模型的标识符,不同的模型提供商可能有不同的标识符格式,请参考对应提供商的文档。",placement:"bottom",disableBeacon:!0,disableOverlayClose:!0,hideCloseButton:!1,spotlightClicks:!1},{target:'[data-tour="model-save-button"]',content:"填写完所有信息后,点击保存按钮,模型就添加完成了。",placement:"top",disableBeacon:!0,disableOverlayClose:!0,hideCloseButton:!1,spotlightClicks:!1},{target:'[data-tour="model-cancel-button"]',content:"当然,因为这次咱们什么都没有填写,所以直接点击取消按钮退出吧,等你准备好了再来添加模型。",placement:"top",disableBeacon:!0,disableOverlayClose:!0,hideCloseButton:!1,spotlightClicks:!0,hideFooter:!0},{target:'[data-tour="tasks-tab-trigger"]',content:'最后一步,添加好模型后,切换到"为模型分配功能"标签页,为麦麦的各个组件分配合适的模型。',placement:"bottom",disableBeacon:!0,disableOverlayClose:!0,hideCloseButton:!1,spotlightClicks:!0,hideFooter:!0},{target:'[data-tour="task-model-select"]',content:"在这里,你可以为每个组件选择一个或多个合适的模型,选择完成后配置会自动保存。恭喜你完成了模型配置的学习!",placement:"bottom",disableBeacon:!0,disableOverlayClose:!0,hideCloseButton:!1,spotlightClicks:!1}],Fg={0:"/config/model",1:"/config/model",2:"/config/modelProvider",3:"/config/modelProvider",4:"/config/modelProvider",5:"/config/modelProvider",6:"/config/modelProvider",7:"/config/modelProvider",8:"/config/modelProvider",9:"/config/modelProvider",10:"/config/modelProvider",11:"/config/model",12:"/config/model",13:"/config/model",14:"/config/model",15:"/config/model",16:"/config/model",17:"/config/model",18:"/config/model",19:"/config/model"},ai=[{id:"siliconflow",name:"SiliconFlow",base_url:"https://api.siliconflow.cn/v1",client_type:"openai",display_name:"硅基流动 (SiliconFlow)",modelFetcher:{endpoint:"/models",parser:"openai"}},{id:"deepseek",name:"DeepSeek",base_url:"https://api.deepseek.com",client_type:"openai",display_name:"DeepSeek",modelFetcher:{endpoint:"/models",parser:"openai"}},{id:"rinkoai",name:"RinkoAI",base_url:"https://rinkoai.com/v1",client_type:"openai",display_name:"RinkoAI",modelFetcher:{endpoint:"/models",parser:"openai"}},{id:"zhipu",name:"ZhipuAI",base_url:"https://open.bigmodel.cn/api/paas/v4",client_type:"openai",display_name:"智谱 AI (ZhipuAI / GLM)",modelFetcher:{endpoint:"/models",parser:"openai"}},{id:"moonshot",name:"Moonshot",base_url:"https://api.moonshot.cn/v1",client_type:"openai",display_name:"月之暗面 (Moonshot / Kimi)",modelFetcher:{endpoint:"/models",parser:"openai"}},{id:"doubao",name:"Doubao",base_url:"https://ark.cn-beijing.volces.com/api/v3",client_type:"openai",display_name:"字节豆包 (Doubao)",modelFetcher:{endpoint:"/models",parser:"openai"}},{id:"alibaba",name:"Alibaba",base_url:"https://dashscope.aliyuncs.com/compatible-mode/v1",client_type:"openai",display_name:"阿里云百炼 (Alibaba Qwen)",modelFetcher:{endpoint:"/models",parser:"openai"}},{id:"baichuan",name:"Baichuan",base_url:"https://api.baichuan-ai.com/v1",client_type:"openai",display_name:"百川智能 (Baichuan)",modelFetcher:{endpoint:"/models",parser:"openai"}},{id:"minimax",name:"MiniMax",base_url:"https://api.minimax.chat/v1",client_type:"openai",display_name:"MiniMax (海螺 AI)",modelFetcher:{endpoint:"/models",parser:"openai"}},{id:"stepfun",name:"StepFun",base_url:"https://api.stepfun.com/v1",client_type:"openai",display_name:"阶跃星辰 (StepFun)",modelFetcher:{endpoint:"/models",parser:"openai"}},{id:"lingyi",name:"Lingyi",base_url:"https://api.lingyiwanwu.com/v1",client_type:"openai",display_name:"零一万物 (Lingyi / Yi)",modelFetcher:{endpoint:"/models",parser:"openai"}},{id:"openai",name:"OpenAI",base_url:"https://api.openai.com/v1",client_type:"openai",display_name:"OpenAI",modelFetcher:{endpoint:"/models",parser:"openai"}},{id:"xai",name:"xAI",base_url:"https://api.x.ai/v1",client_type:"openai",display_name:"xAI (Grok)",modelFetcher:{endpoint:"/models",parser:"openai"}},{id:"anthropic",name:"Anthropic",base_url:"https://api.anthropic.com/v1",client_type:"openai",display_name:"Anthropic (Claude)"},{id:"gemini",name:"Gemini",base_url:"https://generativelanguage.googleapis.com/v1beta",client_type:"gemini",display_name:"Google Gemini",modelFetcher:{endpoint:"/models",parser:"gemini"}},{id:"cohere",name:"Cohere",base_url:"https://api.cohere.ai/v1",client_type:"openai",display_name:"Cohere"},{id:"groq",name:"Groq",base_url:"https://api.groq.com/openai/v1",client_type:"openai",display_name:"Groq",modelFetcher:{endpoint:"/models",parser:"openai"}},{id:"together",name:"Together AI",base_url:"https://api.together.xyz/v1",client_type:"openai",display_name:"Together AI",modelFetcher:{endpoint:"/models",parser:"openai"}},{id:"fireworks",name:"Fireworks",base_url:"https://api.fireworks.ai/inference/v1",client_type:"openai",display_name:"Fireworks AI",modelFetcher:{endpoint:"/models",parser:"openai"}},{id:"mistral",name:"Mistral",base_url:"https://api.mistral.ai/v1",client_type:"openai",display_name:"Mistral AI",modelFetcher:{endpoint:"/models",parser:"openai"}},{id:"perplexity",name:"Perplexity",base_url:"https://api.perplexity.ai",client_type:"openai",display_name:"Perplexity AI"},{id:"custom",name:"",base_url:"",client_type:"openai",display_name:"自定义"}];function hp(n){return n?n.replace(/\/+$/,"").toLowerCase():""}function Yw(n){if(!n)return null;const r=hp(n);return ai.find(i=>i.id!=="custom"&&hp(i.base_url)===r)||null}function Kw(){const[n,r]=u.useState([]),[i,d]=u.useState(!0),[m,x]=u.useState(!1),[f,p]=u.useState(!1),[g,b]=u.useState(!1),[j,y]=u.useState(!1),[N,k]=u.useState(!1),[w,U]=u.useState(!1),[O,B]=u.useState(null),[Y,L]=u.useState(null),[z,K]=u.useState("custom"),[I,T]=u.useState(!1),[A,te]=u.useState(!1),[fe,je]=u.useState(null),[pe,he]=u.useState(!1),[ve,be]=u.useState(""),[D,J]=u.useState(new Set),[q,se]=u.useState(!1),[R,ue]=u.useState(1),[me,_e]=u.useState(20),[Ce,ze]=u.useState(""),[ge,ae]=u.useState({}),[re,F]=u.useState(new Set),[P,Te]=u.useState(new Map),{toast:Le}=$s(),E=va(),{state:xe,goToStep:Ye,registerTour:ke}=Pu(),Q=u.useRef(null),Ne=u.useRef(!0);u.useEffect(()=>{ke(Ma,$g)},[ke]),u.useEffect(()=>{if(xe.activeTourId===Ma&&xe.isRunning){const _=Fg[xe.stepIndex];_&&!window.location.pathname.endsWith(_.replace("/config/",""))&&E({to:_})}},[xe.stepIndex,xe.activeTourId,xe.isRunning,E]);const qe=u.useRef(xe.stepIndex);u.useEffect(()=>{if(xe.activeTourId===Ma&&xe.isRunning){const _=qe.current,G=xe.stepIndex;_>=3&&_<=9&&G<3&&U(!1),_>=10&&G>=3&&G<=9&&(ae({}),K("custom"),B({name:"",base_url:"",api_key:"",client_type:"openai",max_retry:2,timeout:30,retry_interval:10}),L(null),he(!1),U(!0)),qe.current=G}},[xe.stepIndex,xe.activeTourId,xe.isRunning]),u.useEffect(()=>{if(xe.activeTourId!==Ma||!xe.isRunning)return;const _=G=>{const we=G.target,Ms=xe.stepIndex;Ms===2&&we.closest('[data-tour="add-provider-button"]')?setTimeout(()=>Ye(3),300):Ms===9&&we.closest('[data-tour="provider-cancel-button"]')&&setTimeout(()=>Ye(10),300)};return document.addEventListener("click",_,!0),()=>document.removeEventListener("click",_,!0)},[xe,Ye]),u.useEffect(()=>{Fs()},[]);const Fs=async()=>{try{d(!0);const _=await Wn();r(_.api_providers||[]),b(!1),Ne.current=!1}catch(_){console.error("加载配置失败:",_)}finally{d(!1)}},ks=async()=>{try{y(!0),Wc().catch(()=>{}),k(!0)}catch(_){console.error("重启失败:",_),k(!1),Le({title:"重启失败",description:"无法发送重启请求,请手动重启",variant:"destructive"}),y(!1)}},xt=async()=>{try{x(!0),Q.current&&clearTimeout(Q.current);const _=await Wn();_.api_providers=n,await Kc(_),b(!1),Le({title:"保存成功",description:"正在重启麦麦..."}),await ks()}catch(_){console.error("保存配置失败:",_),Le({title:"保存失败",description:_.message,variant:"destructive"}),x(!1)}},js=()=>{localStorage.removeItem("access-token"),window.location.href="/auth"},Vs=()=>{k(!1),y(!1),Le({title:"重启超时",description:"服务未能在预期时间内恢复,请手动检查或刷新页面",variant:"destructive"})},X=u.useCallback(async _=>{if(!Ne.current)try{p(!0),await Hu("api_providers",_),b(!1)}catch(G){console.error("自动保存失败:",G),b(!0)}finally{p(!1)}},[]);u.useEffect(()=>{if(!Ne.current)return b(!0),Q.current&&clearTimeout(Q.current),Q.current=setTimeout(()=>{X(n)},2e3),()=>{Q.current&&clearTimeout(Q.current)}},[n,X]);const He=async()=>{try{x(!0),Q.current&&clearTimeout(Q.current);const _=await Wn();_.api_providers=n,await Kc(_),b(!1),Le({title:"保存成功",description:"模型提供商配置已保存"})}catch(_){console.error("保存配置失败:",_),Le({title:"保存失败",description:_.message,variant:"destructive"})}finally{x(!1)}},De=(_,G)=>{if(ae({}),_){const we=ai.find(Ms=>Ms.base_url===_.base_url&&Ms.client_type===_.client_type);K(we?.id||"custom"),B(_)}else K("custom"),B({name:"",base_url:"",api_key:"",client_type:"openai",max_retry:2,timeout:30,retry_interval:10});L(G),he(!1),U(!0)},Ke=_=>{K(_),T(!1);const G=ai.find(we=>we.id===_);G&&G.id!=="custom"?B(we=>({...we,name:G.name,base_url:G.base_url,client_type:G.client_type})):G?.id==="custom"&&B(we=>({...we,name:"",base_url:"",client_type:"openai"}))},Ns=u.useMemo(()=>z!=="custom",[z]),Je=async()=>{if(O?.api_key)try{await navigator.clipboard.writeText(O.api_key),Le({title:"复制成功",description:"API Key 已复制到剪贴板"})}catch{Le({title:"复制失败",description:"无法访问剪贴板",variant:"destructive"})}},Ks=()=>{if(!O)return;const _={};if(O.name?.trim()||(_.name="请输入提供商名称"),O.base_url?.trim()||(_.base_url="请输入基础 URL"),O.api_key?.trim()||(_.api_key="请输入 API Key"),Object.keys(_).length>0){ae(_);return}ae({});const G={...O,max_retry:O.max_retry??2,timeout:O.timeout??30,retry_interval:O.retry_interval??10};if(Y!==null){const we=[...n];we[Y]=G,r(we)}else r([...n,G]);U(!1),B(null),L(null)},ye=_=>{if(!_&&O){const G={...O,max_retry:O.max_retry??2,timeout:O.timeout??30,retry_interval:O.retry_interval??10};B(G)}U(_)},_s=_=>{je(_),te(!0)},Ae=()=>{if(fe!==null){const _=n.filter((G,we)=>we!==fe);r(_),Le({title:"删除成功",description:"提供商已从列表中移除"})}te(!1),je(null)},vs=_=>{const G=new Set(D);G.has(_)?G.delete(_):G.add(_),J(G)},bs=()=>{if(D.size===Ss.length)J(new Set);else{const _=Ss.map((G,we)=>n.findIndex(Ms=>Ms===Ss[we]));J(new Set(_))}},Nt=()=>{if(D.size===0){Le({title:"提示",description:"请先选择要删除的提供商",variant:"default"});return}se(!0)},Xs=()=>{const _=n.filter((G,we)=>!D.has(we));r(_),J(new Set),se(!1),Le({title:"批量删除成功",description:`已删除 ${D.size} 个提供商`})},Ss=n.filter(_=>{if(!ve)return!0;const G=ve.toLowerCase();return _.name.toLowerCase().includes(G)||_.base_url.toLowerCase().includes(G)||_.client_type.toLowerCase().includes(G)}),Es=Math.ceil(Ss.length/me),Js=Ss.slice((R-1)*me,R*me),Ha=()=>{const _=parseInt(Ce);_>=1&&_<=Es&&(ue(_),ze(""))},Lt=async _=>{F(G=>new Set(G).add(_));try{const G=await zw(_);Te(we=>new Map(we).set(_,G)),G.network_ok?G.api_key_valid===!0?Le({title:"连接正常",description:`${_} 网络连接正常,API Key 有效 (${G.latency_ms}ms)`}):G.api_key_valid===!1?Le({title:"连接正常但 Key 无效",description:`${_} 网络连接正常,但 API Key 无效或已过期`,variant:"destructive"}):Le({title:"网络连接正常",description:`${_} 可以访问 (${G.latency_ms}ms)`}):Le({title:"连接失败",description:G.error||"无法连接到提供商",variant:"destructive"})}catch(G){Le({title:"测试失败",description:G.message,variant:"destructive"})}finally{F(G=>{const we=new Set(G);return we.delete(_),we})}},ol=async()=>{for(const _ of n)await Lt(_.name)},ba=_=>{const G=re.has(_),we=P.get(_);return G?e.jsxs(Qe,{variant:"secondary",className:"gap-1",children:[e.jsx(it,{className:"h-3 w-3 animate-spin"}),"测试中"]}):we?we.network_ok?we.api_key_valid===!0?e.jsxs(Qe,{className:"gap-1 bg-green-600 hover:bg-green-700",children:[e.jsx(aa,{className:"h-3 w-3"}),"正常"]}):we.api_key_valid===!1?e.jsxs(Qe,{variant:"destructive",className:"gap-1",children:[e.jsx(At,{className:"h-3 w-3"}),"Key无效"]}):e.jsxs(Qe,{className:"gap-1 bg-blue-600 hover:bg-blue-700",children:[e.jsx(aa,{className:"h-3 w-3"}),"可访问"]}):e.jsxs(Qe,{variant:"destructive",className:"gap-1",children:[e.jsx(mg,{className:"h-3 w-3"}),"离线"]}):null};return i?e.jsx("div",{className:"space-y-4 sm:space-y-6 p-4 sm:p-6",children:e.jsx("div",{className:"flex items-center justify-center h-64",children:e.jsx("p",{className:"text-muted-foreground",children:"加载中..."})})}):e.jsxs("div",{className:"space-y-4 sm:space-y-6 p-4 sm:p-6",children:[e.jsxs("div",{className:"flex flex-col sm:flex-row sm:items-center justify-between gap-4",children:[e.jsxs("div",{children:[e.jsx("h1",{className:"text-2xl sm:text-3xl font-bold",children:"AI模型厂商配置"}),e.jsx("p",{className:"text-muted-foreground mt-1 sm:mt-2 text-sm sm:text-base",children:"管理 AI 模型厂商的 API 配置"})]}),e.jsxs("div",{className:"flex flex-col sm:flex-row gap-2",children:[D.size>0&&e.jsxs(S,{onClick:Nt,size:"sm",variant:"destructive",className:"w-full sm:w-auto",children:[e.jsx(We,{className:"mr-2 h-4 w-4",strokeWidth:2,fill:"none"}),"批量删除 (",D.size,")"]}),e.jsxs(S,{onClick:ol,size:"sm",variant:"outline",className:"w-full sm:w-auto",disabled:n.length===0||re.size>0,children:[e.jsx(an,{className:"mr-2 h-4 w-4"}),re.size>0?`测试中 (${re.size})`:"测试全部"]}),e.jsxs(S,{onClick:()=>De(null,null),size:"sm",className:"w-full sm:w-auto","data-tour":"add-provider-button",children:[e.jsx(dt,{className:"mr-2 h-4 w-4",strokeWidth:2,fill:"none"}),"添加提供商"]}),e.jsxs(S,{onClick:He,disabled:m||f||!g||j,size:"sm",variant:"outline",className:"w-full sm:w-auto sm:min-w-[120px]",children:[e.jsx(fi,{className:"mr-2 h-4 w-4",strokeWidth:2,fill:"none"}),m?"保存中...":f?"自动保存中...":g?"保存配置":"已保存"]}),e.jsxs(hs,{children:[e.jsx(rt,{asChild:!0,children:e.jsxs(S,{disabled:m||f||j,size:"sm",className:"w-full sm:w-auto sm:min-w-[120px]",children:[e.jsx(hi,{className:"mr-2 h-4 w-4"}),j?"重启中...":g?"保存并重启":"重启麦麦"]})}),e.jsxs(ls,{children:[e.jsxs(ns,{children:[e.jsx(is,{children:"确认重启麦麦?"}),e.jsx(cs,{asChild:!0,children:e.jsx("div",{children:e.jsx("p",{children:g?"当前有未保存的配置更改。点击确认将先保存配置,然后重启麦麦使新配置生效。重启过程中麦麦将暂时离线。":"即将重启麦麦主程序。重启过程中麦麦将暂时离线,配置将在重启后生效。"})})})]}),e.jsxs(rs,{children:[e.jsx(ds,{children:"取消"}),e.jsx(os,{onClick:g?xt:ks,children:g?"保存并重启":"确认重启"})]})]})]})]})]}),e.jsxs(It,{children:[e.jsx(Ra,{className:"h-4 w-4"}),e.jsxs(Yt,{children:["配置更新后需要",e.jsx("strong",{children:"重启麦麦"}),'才能生效。你可以点击右上角的"保存并重启"按钮一键完成保存和重启。']})]}),e.jsxs(Ze,{className:"h-[calc(100vh-260px)]",children:[e.jsxs("div",{className:"flex flex-col sm:flex-row items-start sm:items-center gap-2 mb-4",children:[e.jsxs("div",{className:"relative w-full sm:flex-1 sm:max-w-sm",children:[e.jsx(Mt,{className:"absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground"}),e.jsx(ie,{placeholder:"搜索提供商名称、URL 或类型...",value:ve,onChange:_=>be(_.target.value),className:"pl-9"})]}),ve&&e.jsxs("p",{className:"text-sm text-muted-foreground whitespace-nowrap",children:["找到 ",Ss.length," 个结果"]})]}),e.jsx("div",{className:"md:hidden space-y-3",children:Ss.length===0?e.jsx("div",{className:"text-center text-muted-foreground py-8 rounded-lg border bg-card",children:ve?"未找到匹配的提供商":'暂无提供商配置,点击"添加提供商"开始配置'}):Js.map((_,G)=>{const we=n.findIndex(Ms=>Ms===_);return e.jsxs("div",{className:"rounded-lg border bg-card p-4 space-y-3",children:[e.jsxs("div",{className:"flex items-start justify-between gap-2",children:[e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsxs("div",{className:"flex items-center gap-2 flex-wrap",children:[e.jsx("h3",{className:"font-semibold text-base truncate",children:_.name}),ba(_.name)]}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1 break-all",children:_.base_url})]}),e.jsxs("div",{className:"flex gap-1 flex-shrink-0",children:[e.jsx(S,{variant:"outline",size:"sm",onClick:()=>Lt(_.name),disabled:re.has(_.name),title:"测试连接",children:re.has(_.name)?e.jsx(it,{className:"h-4 w-4 animate-spin"}):e.jsx(an,{className:"h-4 w-4"})}),e.jsx(S,{variant:"default",size:"sm",onClick:()=>De(_,we),children:e.jsx(ln,{className:"h-4 w-4",strokeWidth:2,fill:"none"})}),e.jsx(S,{size:"sm",onClick:()=>_s(we),className:"bg-red-600 hover:bg-red-700 text-white",children:e.jsx(We,{className:"h-4 w-4",strokeWidth:2,fill:"none"})})]})]}),e.jsxs("div",{className:"grid grid-cols-2 gap-2 text-sm",children:[e.jsxs("div",{children:[e.jsx("span",{className:"text-muted-foreground text-xs",children:"客户端类型"}),e.jsx("p",{className:"font-medium",children:_.client_type})]}),e.jsxs("div",{children:[e.jsx("span",{className:"text-muted-foreground text-xs",children:"最大重试"}),e.jsx("p",{className:"font-medium",children:_.max_retry})]}),e.jsxs("div",{children:[e.jsx("span",{className:"text-muted-foreground text-xs",children:"超时(秒)"}),e.jsx("p",{className:"font-medium",children:_.timeout})]}),e.jsxs("div",{children:[e.jsx("span",{className:"text-muted-foreground text-xs",children:"重试间隔(秒)"}),e.jsx("p",{className:"font-medium",children:_.retry_interval})]})]})]},G)})}),e.jsx("div",{className:"hidden md:block rounded-lg border bg-card overflow-hidden",children:e.jsx("div",{className:"overflow-x-auto",children:e.jsxs(rn,{children:[e.jsx(cn,{children:e.jsxs(ut,{children:[e.jsx(Xe,{className:"w-12",children:e.jsx(mt,{checked:D.size===Ss.length&&Ss.length>0,onCheckedChange:bs})}),e.jsx(Xe,{children:"状态"}),e.jsx(Xe,{children:"名称"}),e.jsx(Xe,{children:"基础URL"}),e.jsx(Xe,{children:"客户端类型"}),e.jsx(Xe,{className:"text-right",children:"最大重试"}),e.jsx(Xe,{className:"text-right",children:"超时(秒)"}),e.jsx(Xe,{className:"text-right",children:"重试间隔(秒)"}),e.jsx(Xe,{className:"text-right",children:"操作"})]})}),e.jsx(on,{children:Js.length===0?e.jsx(ut,{children:e.jsx(Ve,{colSpan:9,className:"text-center text-muted-foreground py-8",children:ve?"未找到匹配的提供商":'暂无提供商配置,点击"添加提供商"开始配置'})}):Js.map((_,G)=>{const we=n.findIndex(Ms=>Ms===_);return e.jsxs(ut,{children:[e.jsx(Ve,{children:e.jsx(mt,{checked:D.has(we),onCheckedChange:()=>vs(we)})}),e.jsx(Ve,{children:ba(_.name)||e.jsx(Qe,{variant:"outline",className:"text-muted-foreground",children:"未测试"})}),e.jsx(Ve,{className:"font-medium",children:_.name}),e.jsx(Ve,{className:"max-w-xs truncate",title:_.base_url,children:_.base_url}),e.jsx(Ve,{children:_.client_type}),e.jsx(Ve,{className:"text-right",children:_.max_retry}),e.jsx(Ve,{className:"text-right",children:_.timeout}),e.jsx(Ve,{className:"text-right",children:_.retry_interval}),e.jsx(Ve,{className:"text-right",children:e.jsxs("div",{className:"flex justify-end gap-2",children:[e.jsx(S,{variant:"outline",size:"sm",onClick:()=>Lt(_.name),disabled:re.has(_.name),title:"测试连接",children:re.has(_.name)?e.jsx(it,{className:"h-4 w-4 animate-spin"}):e.jsx(an,{className:"h-4 w-4"})}),e.jsxs(S,{variant:"default",size:"sm",onClick:()=>De(_,we),children:[e.jsx(ln,{className:"h-4 w-4 mr-1",strokeWidth:2,fill:"none"}),"编辑"]}),e.jsxs(S,{size:"sm",onClick:()=>_s(we),className:"bg-red-600 hover:bg-red-700 text-white",children:[e.jsx(We,{className:"h-4 w-4 mr-1",strokeWidth:2,fill:"none"}),"删除"]})]})})]},G)})})]})})}),Ss.length>0&&e.jsxs("div",{className:"flex flex-col sm:flex-row items-center justify-between gap-4 mt-4",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(C,{htmlFor:"page-size-provider",className:"text-sm whitespace-nowrap",children:"每页显示"}),e.jsxs(Ue,{value:me.toString(),onValueChange:_=>{_e(parseInt(_)),ue(1),J(new Set)},children:[e.jsx(Oe,{id:"page-size-provider",className:"w-20",children:e.jsx(Be,{})}),e.jsxs(Re,{children:[e.jsx(le,{value:"10",children:"10"}),e.jsx(le,{value:"20",children:"20"}),e.jsx(le,{value:"50",children:"50"}),e.jsx(le,{value:"100",children:"100"})]})]}),e.jsxs("span",{className:"text-sm text-muted-foreground",children:["显示 ",(R-1)*me+1," 到"," ",Math.min(R*me,Ss.length)," 条,共 ",Ss.length," 条"]})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(S,{variant:"outline",size:"sm",onClick:()=>ue(1),disabled:R===1,className:"hidden sm:flex",children:e.jsx(lr,{className:"h-4 w-4"})}),e.jsxs(S,{variant:"outline",size:"sm",onClick:()=>ue(_=>Math.max(1,_-1)),disabled:R===1,children:[e.jsx(il,{className:"h-4 w-4 sm:mr-1"}),e.jsx("span",{className:"hidden sm:inline",children:"上一页"})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(ie,{type:"number",value:Ce,onChange:_=>ze(_.target.value),onKeyDown:_=>_.key==="Enter"&&Ha(),placeholder:R.toString(),className:"w-16 h-8 text-center",min:1,max:Es}),e.jsx(S,{variant:"outline",size:"sm",onClick:Ha,disabled:!Ce,className:"h-8",children:"跳转"})]}),e.jsxs(S,{variant:"outline",size:"sm",onClick:()=>ue(_=>_+1),disabled:R>=Es,children:[e.jsx("span",{className:"hidden sm:inline",children:"下一页"}),e.jsx(Ba,{className:"h-4 w-4 sm:ml-1"})]}),e.jsx(S,{variant:"outline",size:"sm",onClick:()=>ue(Es),disabled:R>=Es,className:"hidden sm:flex",children:e.jsx(nr,{className:"h-4 w-4"})})]})]})]}),e.jsx(qs,{open:w,onOpenChange:ye,children:e.jsxs(Ls,{className:"max-w-[95vw] sm:max-w-2xl max-h-[90vh] overflow-y-auto","data-tour":"provider-dialog",preventOutsideClose:xe.isRunning,children:[e.jsxs(Us,{children:[e.jsx(Bs,{children:Y!==null?"编辑提供商":"添加提供商"}),e.jsx(Ps,{children:"配置 API 提供商的连接信息和参数"})]}),e.jsxs("form",{onSubmit:_=>{_.preventDefault(),Ks()},autoComplete:"off",children:[e.jsxs("div",{className:"grid gap-4 py-4",children:[e.jsxs("div",{className:"grid gap-2","data-tour":"provider-template-select",children:[e.jsx(C,{htmlFor:"template",children:"提供商模板"}),e.jsxs(La,{open:I,onOpenChange:T,children:[e.jsx(Ua,{asChild:!0,children:e.jsxs(S,{variant:"outline",role:"combobox","aria-expanded":I,className:"w-full justify-between",children:[z?ai.find(_=>_.id===z)?.display_name:"选择提供商模板...",e.jsx(Iu,{className:"ml-2 h-4 w-4 shrink-0 opacity-50"})]})}),e.jsx(ka,{className:"p-0",align:"start",style:{width:"var(--radix-popover-trigger-width)"},children:e.jsxs(eo,{children:[e.jsx(so,{placeholder:"搜索提供商模板..."}),e.jsx(Ze,{className:"h-[300px]",children:e.jsxs(to,{className:"max-h-none overflow-visible",children:[e.jsx(ao,{children:"未找到匹配的模板"}),e.jsx(mi,{children:ai.map(_=>e.jsxs(xi,{value:_.display_name,onSelect:()=>Ke(_.id),children:[e.jsx(Qt,{className:`mr-2 h-4 w-4 ${z===_.id?"opacity-100":"opacity-0"}`}),_.display_name]},_.id))})]})})]})})]}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"选择预设模板可自动填充 URL 和客户端类型,支持搜索"})]}),e.jsxs("div",{className:"grid gap-2","data-tour":"provider-name-input",children:[e.jsx(C,{htmlFor:"name",className:ge.name?"text-destructive":"",children:"名称 *"}),e.jsx(ie,{id:"name",value:O?.name||"",onChange:_=>{B(G=>G?{...G,name:_.target.value}:null),ge.name&&ae(G=>({...G,name:void 0}))},placeholder:"例如: DeepSeek, SiliconFlow",className:ge.name?"border-destructive focus-visible:ring-destructive":""}),ge.name&&e.jsx("p",{className:"text-xs text-destructive",children:ge.name})]}),e.jsxs("div",{className:"grid gap-2","data-tour":"provider-url-input",children:[e.jsx(C,{htmlFor:"base_url",className:ge.base_url?"text-destructive":"",children:"基础 URL *"}),e.jsx(ie,{id:"base_url",value:O?.base_url||"",onChange:_=>{B(G=>G?{...G,base_url:_.target.value}:null),ge.base_url&&ae(G=>({...G,base_url:void 0}))},placeholder:"https://api.example.com/v1",disabled:Ns,className:`${Ns?"bg-muted cursor-not-allowed":""} ${ge.base_url?"border-destructive focus-visible:ring-destructive":""}`}),ge.base_url&&e.jsx("p",{className:"text-xs text-destructive",children:ge.base_url}),Ns&&!ge.base_url&&e.jsx("p",{className:"text-xs text-muted-foreground",children:'使用模板时 URL 不可编辑,切换到"自定义"以手动配置'})]}),e.jsxs("div",{className:"grid gap-2","data-tour":"provider-apikey-input",children:[e.jsx(C,{htmlFor:"api_key",className:ge.api_key?"text-destructive":"",children:"API Key *"}),e.jsxs("div",{className:"flex gap-2",children:[e.jsx(ie,{id:"api_key",type:pe?"text":"password",value:O?.api_key||"",onChange:_=>{B(G=>G?{...G,api_key:_.target.value}:null),ge.api_key&&ae(G=>({...G,api_key:void 0}))},placeholder:"sk-...",className:`flex-1 ${ge.api_key?"border-destructive focus-visible:ring-destructive":""}`}),e.jsx(S,{type:"button",variant:"outline",size:"icon",onClick:()=>he(!pe),title:pe?"隐藏密钥":"显示密钥",children:pe?e.jsx(ci,{className:"h-4 w-4"}):e.jsx(Rt,{className:"h-4 w-4"})}),e.jsx(S,{type:"button",variant:"outline",size:"icon",onClick:Je,title:"复制密钥",children:e.jsx(Vc,{className:"h-4 w-4"})})]}),ge.api_key&&e.jsx("p",{className:"text-xs text-destructive",children:ge.api_key})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(C,{htmlFor:"client_type",children:"客户端类型"}),e.jsxs(Ue,{value:O?.client_type||"openai",onValueChange:_=>B(G=>G?{...G,client_type:_}:null),disabled:Ns,children:[e.jsx(Oe,{id:"client_type",className:Ns?"bg-muted cursor-not-allowed":"",children:e.jsx(Be,{placeholder:"选择客户端类型"})}),e.jsxs(Re,{children:[e.jsx(le,{value:"openai",children:"OpenAI"}),e.jsx(le,{value:"gemini",children:"Gemini"})]})]}),Ns&&e.jsx("p",{className:"text-xs text-muted-foreground",children:'使用模板时客户端类型不可编辑,切换到"自定义"以手动配置'})]}),e.jsxs("div",{className:"grid grid-cols-1 sm:grid-cols-3 gap-4",children:[e.jsxs("div",{className:"grid gap-2",children:[e.jsx(C,{htmlFor:"max_retry",children:"最大重试"}),e.jsx(ie,{id:"max_retry",type:"number",min:"0",value:O?.max_retry??"",onChange:_=>{const G=_.target.value===""?null:parseInt(_.target.value);B(we=>we?{...we,max_retry:G}:null)},placeholder:"默认: 2"})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(C,{htmlFor:"timeout",children:"超时(秒)"}),e.jsx(ie,{id:"timeout",type:"number",min:"1",value:O?.timeout??"",onChange:_=>{const G=_.target.value===""?null:parseInt(_.target.value);B(we=>we?{...we,timeout:G}:null)},placeholder:"默认: 30"})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(C,{htmlFor:"retry_interval",children:"重试间隔(秒)"}),e.jsx(ie,{id:"retry_interval",type:"number",min:"1",value:O?.retry_interval??"",onChange:_=>{const G=_.target.value===""?null:parseInt(_.target.value);B(we=>we?{...we,retry_interval:G}:null)},placeholder:"默认: 10"})]})]})]}),e.jsxs(st,{children:[e.jsx(S,{type:"button",variant:"outline",onClick:()=>U(!1),"data-tour":"provider-cancel-button",children:"取消"}),e.jsx(S,{type:"submit","data-tour":"provider-save-button",children:"保存"})]})]})]})}),e.jsx(hs,{open:A,onOpenChange:te,children:e.jsxs(ls,{children:[e.jsxs(ns,{children:[e.jsx(is,{children:"确认删除"}),e.jsxs(cs,{children:['确定要删除提供商 "',fe!==null?n[fe]?.name:"",'" 吗? 此操作无法撤销。']})]}),e.jsxs(rs,{children:[e.jsx(ds,{children:"取消"}),e.jsx(os,{onClick:Ae,children:"删除"})]})]})}),e.jsx(hs,{open:q,onOpenChange:se,children:e.jsxs(ls,{children:[e.jsxs(ns,{children:[e.jsx(is,{children:"确认批量删除"}),e.jsxs(cs,{children:["确定要删除选中的 ",D.size," 个提供商吗? 此操作无法撤销。"]})]}),e.jsxs(rs,{children:[e.jsx(ds,{children:"取消"}),e.jsx(os,{onClick:Xs,className:"bg-destructive text-destructive-foreground hover:bg-destructive/90",children:"批量删除"})]})]})}),N&&e.jsx(Zu,{onRestartComplete:js,onRestartFailed:Vs})]})}function Vg(){return typeof crypto<"u"&&typeof crypto.randomUUID=="function"?crypto.randomUUID():`${Date.now().toString(36)}-${Math.random().toString(36).substring(2,11)}`}function Qg(n){return typeof n=="boolean"?"boolean":typeof n=="number"?"number":"string"}function Xw(n,r){switch(r){case"boolean":return n==="true";case"number":{const i=parseFloat(n);return isNaN(i)?0:i}default:return n}}function Tu(n){return Object.entries(n).map(([r,i])=>({id:Vg(),key:r,value:i,type:Qg(i)}))}function Eu(n){const r={};for(const i of n)i.key.trim()&&(r[i.key.trim()]=i.value);return r}function zu(n){if(!n.trim())return{valid:!0,parsed:{}};try{const r=JSON.parse(n);if(typeof r!="object"||r===null||Array.isArray(r))return{valid:!1,error:"必须是一个 JSON 对象 {}"};for(const[i,d]of Object.entries(r))if(d!==null&&!["string","number","boolean"].includes(typeof d))return{valid:!1,error:`键 "${i}" 的值类型不支持(仅支持 string/number/boolean)`};return{valid:!0,parsed:r}}catch{return{valid:!1,error:"JSON 格式错误"}}}function Jw(n){switch(n){case"boolean":return"布尔";case"number":return"数字";default:return"字符串"}}function Zw(n){switch(n){case"boolean":return"bg-purple-100 text-purple-700 dark:bg-purple-900/30 dark:text-purple-400";case"number":return"bg-blue-100 text-blue-700 dark:bg-blue-900/30 dark:text-blue-400";default:return"bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-400"}}function Pw({value:n,onChange:r,className:i,placeholder:d="添加额外参数..."}){const[m,x]=u.useState("list"),[f,p]=u.useState(()=>Tu(n||{})),[g,b]=u.useState(()=>Object.keys(n||{}).length>0?JSON.stringify(n,null,2):""),[j,y]=u.useState(null);u.useEffect(()=>{const Y=Tu(n||{});p(Y),b(Object.keys(n||{}).length>0?JSON.stringify(n,null,2):"")},[n]);const N=u.useMemo(()=>{const Y=zu(g);return Y.valid&&Y.parsed?{success:!0,data:Y.parsed}:{success:!1,data:{}}},[g]),k=u.useCallback(Y=>{const L=Y;if(L==="json"&&m==="list"){const z=Eu(f);b(Object.keys(z).length>0?JSON.stringify(z,null,2):""),y(null)}else if(L==="list"&&m==="json"){const z=zu(g);z.valid&&z.parsed&&(p(Tu(z.parsed)),y(null))}x(L)},[m,f,g]),w=u.useCallback(()=>{const Y={id:Vg(),key:"",value:"",type:"string"},L=[...f,Y];p(L)},[f]),U=u.useCallback(Y=>{const L=f.filter(z=>z.id!==Y);p(L),r(Eu(L))},[f,r]),O=u.useCallback((Y,L,z)=>{const K=f.map(I=>{if(I.id!==Y)return I;if(L==="type"){const T=z;let A;return T==="boolean"?A=I.value==="true"||I.value===!0:T==="number"?A=typeof I.value=="number"?I.value:parseFloat(String(I.value))||0:A=String(I.value),{...I,type:T,value:A}}else return L==="value"?{...I,value:Xw(z,I.type)}:{...I,[L]:z}});p(K),r(Eu(K))},[f,r]),B=u.useCallback(Y=>{b(Y);const L=zu(Y);L.valid&&L.parsed?(y(null),r(L.parsed)):y(L.error||"JSON 格式错误")},[r]);return e.jsxs("div",{className:$("space-y-3",i),children:[e.jsx(C,{className:"text-sm font-medium",children:"额外参数"}),e.jsxs(ga,{value:m,onValueChange:k,className:"w-full",children:[e.jsxs(la,{className:"h-8 p-0.5 bg-muted/60",children:[e.jsx(ss,{value:"list",className:"h-7 px-3 text-xs data-[state=active]:bg-background data-[state=active]:shadow-sm",children:"键值对"}),e.jsx(ss,{value:"json",className:"h-7 px-3 text-xs data-[state=active]:bg-background data-[state=active]:shadow-sm",children:"JSON"})]}),e.jsxs(Ts,{value:"list",className:"mt-3 space-y-2",children:[f.length===0?e.jsx("div",{className:"text-sm text-muted-foreground text-center py-4 border border-dashed rounded-md",children:d}):e.jsxs("div",{className:"space-y-2",children:[e.jsxs("div",{className:"grid grid-cols-[1fr_1fr_90px_32px] gap-2 text-xs text-muted-foreground px-1",children:[e.jsx("span",{children:"键名"}),e.jsx("span",{children:"值"}),e.jsx("span",{children:"类型"}),e.jsx("span",{})]}),f.map(Y=>e.jsxs("div",{className:"grid grid-cols-[1fr_1fr_90px_32px] gap-2 items-center",children:[e.jsx(ie,{value:Y.key,onChange:L=>O(Y.id,"key",L.target.value),placeholder:"key",className:"h-8 text-sm"}),Y.type==="boolean"?e.jsxs("div",{className:"flex items-center h-8 px-3 border rounded-md bg-background",children:[e.jsx($e,{checked:Y.value===!0,onCheckedChange:L=>O(Y.id,"value",String(L))}),e.jsx("span",{className:"ml-2 text-sm text-muted-foreground",children:Y.value?"true":"false"})]}):e.jsx(ie,{type:Y.type==="number"?"number":"text",value:Y.value,onChange:L=>O(Y.id,"value",L.target.value),placeholder:"value",className:"h-8 text-sm",step:Y.type==="number"?"any":void 0}),e.jsxs(Ue,{value:Y.type,onValueChange:L=>O(Y.id,"type",L),children:[e.jsx(Oe,{className:"h-8 text-xs",children:e.jsx(Be,{})}),e.jsxs(Re,{children:[e.jsx(le,{value:"string",children:"字符串"}),e.jsx(le,{value:"number",children:"数字"}),e.jsx(le,{value:"boolean",children:"布尔"})]})]}),e.jsx(S,{type:"button",variant:"ghost",size:"icon",className:"h-8 w-8 text-muted-foreground hover:text-destructive",onClick:()=>U(Y.id),children:e.jsx(We,{className:"h-4 w-4"})})]},Y.id))]}),e.jsxs(S,{type:"button",variant:"outline",size:"sm",className:"w-full h-8",onClick:w,children:[e.jsx(dt,{className:"h-4 w-4 mr-1"}),"添加参数"]})]}),e.jsx(Ts,{value:"json",className:"mt-3",children:e.jsxs("div",{className:"grid grid-cols-1 md:grid-cols-2 gap-3",children:[e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx("span",{className:"text-xs text-muted-foreground",children:"编辑"}),j?e.jsxs("div",{className:"flex items-center gap-1 text-xs text-destructive",children:[e.jsx(At,{className:"h-3 w-3"}),e.jsx("span",{className:"truncate max-w-[150px]",children:j})]}):g.trim()&&e.jsxs("div",{className:"flex items-center gap-1 text-xs text-green-600 dark:text-green-400",children:[e.jsx(Qt,{className:"h-3 w-3"}),e.jsx("span",{children:"有效"})]})]}),e.jsx(Qs,{value:g,onChange:Y=>B(Y.target.value),placeholder:`{ - "key": "value" -}`,className:$("font-mono text-sm min-h-[140px] h-[140px] resize-y flex-1",j&&"border-destructive focus-visible:ring-destructive")}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"支持 string、number、boolean 类型"})]}),e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsx("span",{className:"text-xs text-muted-foreground",children:"预览"}),e.jsx("div",{className:"min-h-[140px] h-[140px] flex-1 rounded-md border bg-muted/30 p-3 overflow-auto",children:N.success&&Object.keys(N.data).length>0?e.jsx("div",{className:"space-y-2",children:Object.entries(N.data).map(([Y,L])=>{const z=Qg(L);return e.jsxs("div",{className:"flex items-center gap-2 text-sm",children:[e.jsx("code",{className:"px-1.5 py-0.5 bg-background rounded text-xs font-medium",children:Y}),e.jsx("span",{className:"text-muted-foreground",children:"="}),e.jsx("span",{className:$("font-mono",z==="boolean"&&(L?"text-green-600 dark:text-green-400":"text-red-600 dark:text-red-400"),z==="number"&&"text-blue-600 dark:text-blue-400",z==="string"&&"text-amber-600 dark:text-amber-400"),children:z==="string"?`"${L}"`:String(L)}),e.jsx(Qe,{variant:"secondary",className:$("h-5 text-[10px] px-1.5",Zw(z)),children:Jw(z)})]},Y)})}):N.success?e.jsx("div",{className:"flex items-center justify-center h-full text-sm text-muted-foreground",children:"暂无参数"}):e.jsx("div",{className:"flex items-center justify-center h-full text-sm text-destructive",children:"JSON 格式错误"})}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"实时预览解析结果"})]})]})})]})]})}function Ww({value:n,label:r,onRemove:i}){const{attributes:d,listeners:m,setNodeRef:x,transform:f,transition:p,isDragging:g}=Fy({id:n}),b={transform:Vy.Transform.toString(f),transition:p,opacity:g?.5:1},j=N=>{N.preventDefault(),N.stopPropagation(),i(n)},y=N=>{N.stopPropagation()};return e.jsx("div",{ref:x,style:b,className:$("inline-flex items-center gap-1",g&&"shadow-lg"),children:e.jsxs(Qe,{variant:"secondary",className:"cursor-move hover:bg-secondary/80 flex items-center gap-1",children:[e.jsx("div",{...d,...m,className:"cursor-grab active:cursor-grabbing flex items-center",children:e.jsx(ry,{className:"h-3 w-3 text-muted-foreground"})}),e.jsx("span",{children:r}),e.jsx("button",{type:"button",className:"ml-1 rounded-sm hover:bg-destructive/20 focus:outline-none focus:ring-1 focus:ring-destructive",onClick:j,onPointerDown:y,onMouseDown:N=>N.stopPropagation(),children:e.jsx(rl,{className:"h-3 w-3 cursor-pointer hover:text-destructive",strokeWidth:2,fill:"none"})})]})})}function e1({options:n,selected:r,onChange:i,placeholder:d="选择选项...",emptyText:m="未找到选项",className:x}){const[f,p]=u.useState(!1),g=Oy(sp($y,{activationConstraint:{distance:8}}),sp(Gy,{coordinateGetter:qy})),b=N=>{r.includes(N)?i(r.filter(k=>k!==N)):i([...r,N])},j=N=>{i(r.filter(k=>k!==N))},y=N=>{const{active:k,over:w}=N;if(w&&k.id!==w.id){const U=r.indexOf(k.id),O=r.indexOf(w.id);i(Hy(r,U,O))}};return e.jsxs(La,{open:f,onOpenChange:p,children:[e.jsx(Ua,{asChild:!0,children:e.jsxs(S,{variant:"outline",role:"combobox","aria-expanded":f,className:$("w-full justify-between min-h-10 h-auto",x),children:[e.jsx(Ry,{sensors:g,collisionDetection:Ly,onDragEnd:y,children:e.jsx(Uy,{items:r,strategy:By,children:e.jsx("div",{className:"flex gap-1 flex-wrap flex-1",children:r.length===0?e.jsx("span",{className:"text-muted-foreground",children:d}):r.map(N=>{const k=n.find(w=>w.value===N);return e.jsx(Ww,{value:N,label:k?.label||N,onRemove:j},N)})})})}),e.jsx(Iu,{className:"ml-2 h-4 w-4 shrink-0 opacity-50",strokeWidth:2,fill:"none"})]})}),e.jsx(ka,{className:"w-full p-0",align:"start",children:e.jsxs(eo,{children:[e.jsx(so,{placeholder:"搜索...",className:"h-9"}),e.jsxs(to,{children:[e.jsx(ao,{children:m}),e.jsx(mi,{children:n.map(N=>{const k=r.includes(N.value);return e.jsxs(xi,{value:N.value,onSelect:()=>b(N.value),children:[e.jsx("div",{className:$("mr-2 flex h-4 w-4 items-center justify-center rounded-sm border border-primary",k?"bg-primary text-primary-foreground":"opacity-50 [&_svg]:invisible"),children:e.jsx(Qt,{className:"h-3 w-3",strokeWidth:2,fill:"none"})}),e.jsx("span",{children:N.label})]},N.value)})})]})]})})]})}const _a=bt.memo(function({title:r,description:i,taskConfig:d,modelNames:m,onChange:x,hideTemperature:f=!1,hideMaxTokens:p=!1,dataTour:g}){const b=j=>{x("model_list",j)};return e.jsxs("div",{className:"rounded-lg border bg-card p-4 sm:p-6 space-y-4",children:[e.jsxs("div",{children:[e.jsx("h4",{className:"font-semibold text-base sm:text-lg",children:r}),e.jsx("p",{className:"text-xs sm:text-sm text-muted-foreground mt-1",children:i})]}),e.jsxs("div",{className:"grid gap-4",children:[e.jsxs("div",{className:"grid gap-2","data-tour":g,children:[e.jsx(C,{children:"模型列表"}),e.jsx(e1,{options:m.map(j=>({label:j,value:j})),selected:d.model_list||[],onChange:b,placeholder:"选择模型...",emptyText:"暂无可用模型"})]}),e.jsxs("div",{className:"grid grid-cols-1 sm:grid-cols-2 gap-4",children:[!f&&e.jsxs("div",{className:"grid gap-3",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(C,{children:"温度"}),e.jsx(ie,{type:"number",step:"0.1",min:"0",max:"1",value:d.temperature??.3,onChange:j=>{const y=parseFloat(j.target.value);!isNaN(y)&&y>=0&&y<=1&&x("temperature",y)},className:"w-20 h-8 text-sm"})]}),e.jsx(pa,{value:[d.temperature??.3],onValueChange:j=>x("temperature",j[0]),min:0,max:1,step:.1,className:"w-full"})]}),!p&&e.jsxs("div",{className:"grid gap-2",children:[e.jsx(C,{children:"最大 Token"}),e.jsx(ie,{type:"number",step:"1",min:"1",value:d.max_tokens??1024,onChange:j=>x("max_tokens",parseInt(j.target.value))})]})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(C,{children:"慢请求阈值 (秒)"}),e.jsx("span",{className:"text-xs text-muted-foreground",children:"超时警告"})]}),e.jsx(ie,{type:"number",step:"1",min:"1",value:d.slow_threshold??15,onChange:j=>{const y=parseInt(j.target.value);!isNaN(y)&&y>=1&&x("slow_threshold",y)},placeholder:"15"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"模型响应时间超过此阈值将输出警告日志"})]})]})]})}),s1=bt.memo(function({paginatedModels:r,allModels:i,onEdit:d,onDelete:m,isModelUsed:x,searchQuery:f}){return r.length===0?e.jsx("div",{className:"md:hidden text-center text-muted-foreground py-8 rounded-lg border bg-card",children:f?"未找到匹配的模型":"暂无模型配置"}):e.jsx("div",{className:"md:hidden space-y-3",children:r.map((p,g)=>{const b=i.findIndex(y=>y===p),j=x(p.name);return e.jsxs("div",{className:"rounded-lg border bg-card p-4 space-y-3",children:[e.jsxs("div",{className:"flex items-start justify-between gap-2",children:[e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsxs("div",{className:"flex items-center gap-2 mb-1",children:[e.jsx("h3",{className:"font-semibold text-base",children:p.name}),e.jsx(Qe,{variant:j?"default":"secondary",className:j?"bg-green-600 hover:bg-green-700":"",children:j?"已使用":"未使用"})]}),e.jsx("p",{className:"text-xs text-muted-foreground break-all",title:p.model_identifier,children:p.model_identifier})]}),e.jsxs("div",{className:"flex gap-1 flex-shrink-0",children:[e.jsxs(S,{variant:"default",size:"sm",onClick:()=>d(p,b),children:[e.jsx(ln,{className:"h-4 w-4 mr-1",strokeWidth:2,fill:"none"}),"编辑"]}),e.jsxs(S,{size:"sm",onClick:()=>m(b),className:"bg-red-600 hover:bg-red-700 text-white",children:[e.jsx(We,{className:"h-4 w-4 mr-1",strokeWidth:2,fill:"none"}),"删除"]})]})]}),e.jsxs("div",{className:"grid grid-cols-2 gap-2 text-sm",children:[e.jsxs("div",{children:[e.jsx("span",{className:"text-muted-foreground text-xs",children:"提供商"}),e.jsx("p",{className:"font-medium",children:p.api_provider})]}),e.jsxs("div",{children:[e.jsx("span",{className:"text-muted-foreground text-xs",children:"模型温度"}),e.jsx("p",{className:"font-medium",children:p.temperature!=null?p.temperature:e.jsx("span",{className:"text-muted-foreground",children:"默认"})})]}),e.jsxs("div",{children:[e.jsx("span",{className:"text-muted-foreground text-xs",children:"输入价格"}),e.jsxs("p",{className:"font-medium",children:["¥",p.price_in,"/M"]})]}),e.jsxs("div",{children:[e.jsx("span",{className:"text-muted-foreground text-xs",children:"输出价格"}),e.jsxs("p",{className:"font-medium",children:["¥",p.price_out,"/M"]})]})]})]},g)})})}),t1=bt.memo(function({paginatedModels:r,allModels:i,filteredModels:d,selectedModels:m,onEdit:x,onDelete:f,onToggleSelection:p,onToggleSelectAll:g,isModelUsed:b,searchQuery:j}){return e.jsx("div",{className:"hidden md:block rounded-lg border bg-card overflow-hidden",children:e.jsx("div",{className:"overflow-x-auto",children:e.jsxs(rn,{children:[e.jsx(cn,{children:e.jsxs(ut,{children:[e.jsx(Xe,{className:"w-12",children:e.jsx(mt,{checked:m.size===d.length&&d.length>0,onCheckedChange:g})}),e.jsx(Xe,{className:"w-24",children:"使用状态"}),e.jsx(Xe,{children:"模型名称"}),e.jsx(Xe,{children:"模型标识符"}),e.jsx(Xe,{children:"提供商"}),e.jsx(Xe,{className:"text-center",children:"温度"}),e.jsx(Xe,{className:"text-right",children:"输入价格"}),e.jsx(Xe,{className:"text-right",children:"输出价格"}),e.jsx(Xe,{className:"text-right",children:"操作"})]})}),e.jsx(on,{children:r.length===0?e.jsx(ut,{children:e.jsx(Ve,{colSpan:9,className:"text-center text-muted-foreground py-8",children:j?"未找到匹配的模型":"暂无模型配置"})}):r.map((y,N)=>{const k=i.findIndex(U=>U===y),w=b(y.name);return e.jsxs(ut,{children:[e.jsx(Ve,{children:e.jsx(mt,{checked:m.has(k),onCheckedChange:()=>p(k)})}),e.jsx(Ve,{children:e.jsx(Qe,{variant:w?"default":"secondary",className:w?"bg-green-600 hover:bg-green-700":"",children:w?"已使用":"未使用"})}),e.jsx(Ve,{className:"font-medium",children:y.name}),e.jsx(Ve,{className:"max-w-xs truncate",title:y.model_identifier,children:y.model_identifier}),e.jsx(Ve,{children:y.api_provider}),e.jsx(Ve,{className:"text-center",children:y.temperature!=null?y.temperature:e.jsx("span",{className:"text-muted-foreground",children:"-"})}),e.jsxs(Ve,{className:"text-right",children:["¥",y.price_in,"/M"]}),e.jsxs(Ve,{className:"text-right",children:["¥",y.price_out,"/M"]}),e.jsx(Ve,{className:"text-right",children:e.jsxs("div",{className:"flex justify-end gap-2",children:[e.jsxs(S,{variant:"default",size:"sm",onClick:()=>x(y,k),children:[e.jsx(ln,{className:"h-4 w-4 mr-1",strokeWidth:2,fill:"none"}),"编辑"]}),e.jsxs(S,{size:"sm",onClick:()=>f(k),className:"bg-red-600 hover:bg-red-700 text-white",children:[e.jsx(We,{className:"h-4 w-4 mr-1",strokeWidth:2,fill:"none"}),"删除"]})]})})]},N)})})]})})})}),a1=300*1e3,fp=new Map,l1=[10,20,50,100],n1=bt.memo(function({page:r,pageSize:i,totalItems:d,jumpToPage:m,onPageChange:x,onPageSizeChange:f,onJumpToPageChange:p,onJumpToPage:g,onSelectionClear:b}){const j=Math.ceil(d/i),y=k=>{f(parseInt(k)),x(1),b?.()},N=k=>{k.key==="Enter"&&g()};return d===0?null:e.jsxs("div",{className:"flex flex-col sm:flex-row items-center justify-between gap-4 mt-4",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(C,{htmlFor:"page-size-model",className:"text-sm whitespace-nowrap",children:"每页显示"}),e.jsxs(Ue,{value:i.toString(),onValueChange:y,children:[e.jsx(Oe,{id:"page-size-model",className:"w-20",children:e.jsx(Be,{})}),e.jsx(Re,{children:l1.map(k=>e.jsx(le,{value:k.toString(),children:k},k))})]}),e.jsxs("span",{className:"text-sm text-muted-foreground",children:["显示 ",(r-1)*i+1," 到"," ",Math.min(r*i,d)," 条,共 ",d," 条"]})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(S,{variant:"outline",size:"sm",onClick:()=>x(1),disabled:r===1,className:"hidden sm:flex",children:e.jsx(lr,{className:"h-4 w-4"})}),e.jsxs(S,{variant:"outline",size:"sm",onClick:()=>x(Math.max(1,r-1)),disabled:r===1,children:[e.jsx(il,{className:"h-4 w-4 sm:mr-1"}),e.jsx("span",{className:"hidden sm:inline",children:"上一页"})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(ie,{type:"number",value:m,onChange:k=>p(k.target.value),onKeyDown:N,placeholder:r.toString(),className:"w-16 h-8 text-center",min:1,max:j}),e.jsx(S,{variant:"outline",size:"sm",onClick:g,disabled:!m,className:"h-8",children:"跳转"})]}),e.jsxs(S,{variant:"outline",size:"sm",onClick:()=>x(r+1),disabled:r>=j,children:[e.jsx("span",{className:"hidden sm:inline",children:"下一页"}),e.jsx(Ba,{className:"h-4 w-4 sm:ml-1"})]}),e.jsx(S,{variant:"outline",size:"sm",onClick:()=>x(j),disabled:r>=j,className:"hidden sm:flex",children:e.jsx(nr,{className:"h-4 w-4"})})]})]})});function r1(n){const{models:r,taskConfig:i,debounceMs:d=2e3,onSavingChange:m,onUnsavedChange:x}=n,f=u.useRef(null),p=u.useRef(null),g=u.useRef(!0),b=u.useCallback(()=>{f.current&&(clearTimeout(f.current),f.current=null),p.current&&(clearTimeout(p.current),p.current=null)},[]),j=u.useCallback(k=>{const w={model_identifier:k.model_identifier,name:k.name,api_provider:k.api_provider,price_in:k.price_in??0,price_out:k.price_out??0,force_stream_mode:k.force_stream_mode??!1,extra_params:k.extra_params??{}};return k.temperature!=null&&(w.temperature=k.temperature),k.max_tokens!=null&&(w.max_tokens=k.max_tokens),w},[]),y=u.useCallback(async k=>{try{m?.(!0);const w=k.map(j);await Hu("models",w),x?.(!1)}catch(w){console.error("自动保存模型列表失败:",w),x?.(!0)}finally{m?.(!1)}},[m,x,j]),N=u.useCallback(async k=>{try{m?.(!0),await Hu("model_task_config",k),x?.(!1)}catch(w){console.error("自动保存任务配置失败:",w),x?.(!0)}finally{m?.(!1)}},[m,x]);return u.useEffect(()=>{if(!g.current)return x?.(!0),f.current&&clearTimeout(f.current),f.current=setTimeout(()=>{y(r)},d),()=>{f.current&&clearTimeout(f.current)}},[r,y,d,x]),u.useEffect(()=>{if(!(g.current||!i))return x?.(!0),p.current&&clearTimeout(p.current),p.current=setTimeout(()=>{N(i)},d),()=>{p.current&&clearTimeout(p.current)}},[i,N,d,x]),u.useEffect(()=>()=>{b()},[b]),{clearTimers:b,initialLoadRef:g}}function i1(n={}){const{onCloseEditDialog:r}=n,i=va(),{registerTour:d,startTour:m,state:x,goToStep:f}=Pu(),p=u.useRef(x.stepIndex);return u.useEffect(()=>{d(Ma,$g)},[d]),u.useEffect(()=>{if(x.activeTourId===Ma&&x.isRunning){const b=Fg[x.stepIndex];b&&!window.location.pathname.endsWith(b.replace("/config/",""))&&i({to:b})}},[x.stepIndex,x.activeTourId,x.isRunning,i]),u.useEffect(()=>{if(x.activeTourId===Ma&&x.isRunning){const b=p.current,j=x.stepIndex;b>=12&&b<=17&&j<12&&r?.(),p.current=j}},[x.stepIndex,x.activeTourId,x.isRunning,r]),u.useEffect(()=>{if(x.activeTourId!==Ma||!x.isRunning)return;const b=j=>{const y=j.target,N=x.stepIndex;N===2&&y.closest('[data-tour="add-provider-button"]')?setTimeout(()=>f(3),300):N===9&&y.closest('[data-tour="provider-cancel-button"]')?setTimeout(()=>f(10),300):N===11&&y.closest('[data-tour="add-model-button"]')?setTimeout(()=>f(12),300):N===17&&y.closest('[data-tour="model-cancel-button"]')?setTimeout(()=>f(18),300):N===18&&y.closest('[data-tour="tasks-tab-trigger"]')&&setTimeout(()=>f(19),300)};return document.addEventListener("click",b,!0),()=>document.removeEventListener("click",b,!0)},[x,f]),{startTour:u.useCallback(()=>{m(Ma)},[m]),isRunning:x.isRunning&&x.activeTourId===Ma,stepIndex:x.stepIndex}}function c1(n){const{getProviderConfig:r}=n,[i,d]=u.useState([]),[m,x]=u.useState(!1),[f,p]=u.useState(null),[g,b]=u.useState(null),j=u.useCallback(()=>{d([]),p(null),b(null)},[]),y=u.useCallback(async(N,k=!1)=>{const w=r(N);if(!w?.base_url){d([]),b(null),p('提供商配置不完整,请先在"模型提供商配置"中配置');return}if(!w.api_key){d([]),b(null),p('该提供商未配置 API Key,请先在"模型提供商配置"中填写');return}const U=Yw(w.base_url);if(b(U),!U?.modelFetcher){d([]),p(null);return}const O=`${N}:${w.base_url}`,B=fp.get(O);if(!k&&B&&Date.now()-B.timestampT(!1)}),{clearTimers:Ye,initialLoadRef:ke}=r1({models:n,taskConfig:g,onSavingChange:U,onUnsavedChange:B}),Q=u.useCallback(async()=>{try{y(!0);const _=await Wn(),G=_.models||[];r(G),p(G.map(Ms=>Ms.name));const we=_.api_providers||[];d(we.map(Ms=>Ms.name)),x(we),b(_.model_task_config||null),B(!1),ke.current=!1}catch(_){console.error("加载配置失败:",_)}finally{y(!1)}},[ke]);u.useEffect(()=>{Q()},[Q]);const Ne=u.useCallback(_=>m.find(G=>G.name===_),[m]),{availableModels:qe,fetchingModels:Fs,modelFetchError:ks,matchedTemplate:xt,fetchModelsForProvider:js,clearModels:Vs}=c1({getProviderConfig:Ne});u.useEffect(()=>{I&&A?.api_provider&&js(A.api_provider)},[I,A?.api_provider,js]);const X=async()=>{try{L(!0),Wc().catch(()=>{}),K(!0)}catch(_){console.error("重启失败:",_),K(!1),Le({title:"重启失败",description:"无法发送重启请求,请手动重启",variant:"destructive"}),L(!1)}},He=_=>{const G={model_identifier:_.model_identifier,name:_.name,api_provider:_.api_provider,price_in:_.price_in??0,price_out:_.price_out??0,force_stream_mode:_.force_stream_mode??!1,extra_params:_.extra_params??{}};return _.temperature!=null&&(G.temperature=_.temperature),_.max_tokens!=null&&(G.max_tokens=_.max_tokens),G},De=async()=>{try{k(!0),Ye();const _=await Wn();_.models=n.map(He),_.model_task_config=g,await Kc(_),B(!1),Le({title:"保存成功",description:"正在重启麦麦..."}),await X()}catch(_){console.error("保存配置失败:",_),Le({title:"保存失败",description:_.message,variant:"destructive"}),k(!1)}},Ke=()=>{localStorage.removeItem("access-token"),window.location.href="/auth"},Ns=()=>{K(!1),L(!1),Le({title:"重启超时",description:"服务未能在预期时间内恢复,请手动检查或刷新页面",variant:"destructive"})},Je=async()=>{try{k(!0),Ye();const _=await Wn();_.models=n.map(He),_.model_task_config=g,await Kc(_),B(!1),Le({title:"保存成功",description:"模型配置已保存"}),await Q()}catch(_){console.error("保存配置失败:",_),Le({title:"保存失败",description:_.message,variant:"destructive"})}finally{k(!1)}},Ks=(_,G)=>{Te({}),te(_||{model_identifier:"",name:"",api_provider:i[0]||"",price_in:0,price_out:0,temperature:null,max_tokens:null,force_stream_mode:!1,extra_params:{}}),je(G),T(!0)},ye=()=>{if(!A)return;const _={};if(A.name?.trim()||(_.name="请输入模型名称"),A.api_provider?.trim()||(_.api_provider="请选择 API 提供商"),A.model_identifier?.trim()||(_.model_identifier="请输入模型标识符"),Object.keys(_).length>0){Te(_);return}Te({});const G={model_identifier:A.model_identifier,name:A.name,api_provider:A.api_provider,price_in:A.price_in??0,price_out:A.price_out??0,force_stream_mode:A.force_stream_mode??!1,extra_params:A.extra_params??{}};A.temperature!=null&&(G.temperature=A.temperature),A.max_tokens!=null&&(G.max_tokens=A.max_tokens);let we,Ms=null;if(fe!==null?(Ms=n[fe].name,we=[...n],we[fe]=G):we=[...n,G],r(we),p(we.map(Dt=>Dt.name)),Ms&&Ms!==G.name&&g){const Dt=ji=>ji.map(cr=>cr===Ms?G.name:cr);b({...g,utils:{...g.utils,model_list:Dt(g.utils?.model_list||[])},utils_small:{...g.utils_small,model_list:Dt(g.utils_small?.model_list||[])},tool_use:{...g.tool_use,model_list:Dt(g.tool_use?.model_list||[])},replyer:{...g.replyer,model_list:Dt(g.replyer?.model_list||[])},planner:{...g.planner,model_list:Dt(g.planner?.model_list||[])},vlm:{...g.vlm,model_list:Dt(g.vlm?.model_list||[])},voice:{...g.voice,model_list:Dt(g.voice?.model_list||[])},embedding:{...g.embedding,model_list:Dt(g.embedding?.model_list||[])},lpmm_entity_extract:{...g.lpmm_entity_extract,model_list:Dt(g.lpmm_entity_extract?.model_list||[])},lpmm_rdf_build:{...g.lpmm_rdf_build,model_list:Dt(g.lpmm_rdf_build?.model_list||[])},lpmm_qa:{...g.lpmm_qa,model_list:Dt(g.lpmm_qa?.model_list||[])}})}T(!1),te(null),je(null)},_s=_=>{if(!_&&A){const G={...A,price_in:A.price_in??0,price_out:A.price_out??0};te(G)}T(_)},Ae=_=>{be(_),he(!0)},vs=()=>{if(ve!==null){const _=n.filter((G,we)=>we!==ve);r(_),p(_.map(G=>G.name)),Le({title:"删除成功",description:"模型已从列表中移除"})}he(!1),be(null)},bs=_=>{const G=new Set(q);G.has(_)?G.delete(_):G.add(_),se(G)},Nt=()=>{if(q.size===Js.length)se(new Set);else{const _=Js.map((G,we)=>n.findIndex(Ms=>Ms===Js[we]));se(new Set(_))}},Xs=()=>{if(q.size===0){Le({title:"提示",description:"请先选择要删除的模型",variant:"default"});return}ue(!0)},Ss=()=>{const _=n.filter((G,we)=>!q.has(we));r(_),p(_.map(G=>G.name)),se(new Set),ue(!1),Le({title:"批量删除成功",description:`已删除 ${q.size} 个模型`})},Es=(_,G,we)=>{g&&b({...g,[_]:{...g[_],[G]:we}})},Js=n.filter(_=>{if(!D)return!0;const G=D.toLowerCase();return _.name.toLowerCase().includes(G)||_.model_identifier.toLowerCase().includes(G)||_.api_provider.toLowerCase().includes(G)}),Ha=Math.ceil(Js.length/Ce),Lt=Js.slice((me-1)*Ce,me*Ce),ol=()=>{const _=parseInt(ge);_>=1&&_<=Ha&&(_e(_),ae(""))},ba=_=>g?[g.utils?.model_list||[],g.utils_small?.model_list||[],g.tool_use?.model_list||[],g.replyer?.model_list||[],g.planner?.model_list||[],g.vlm?.model_list||[],g.voice?.model_list||[],g.embedding?.model_list||[],g.lpmm_entity_extract?.model_list||[],g.lpmm_rdf_build?.model_list||[],g.lpmm_qa?.model_list||[]].some(we=>we.includes(_)):!1;return j?e.jsx(Ze,{className:"h-full",children:e.jsx("div",{className:"space-y-4 sm:space-y-6 p-4 sm:p-6",children:e.jsx("div",{className:"flex items-center justify-center h-64",children:e.jsx("p",{className:"text-muted-foreground",children:"加载中..."})})})}):e.jsx(Ze,{className:"h-full",children:e.jsxs("div",{className:"space-y-4 sm:space-y-6 p-4 sm:p-6",children:[e.jsxs("div",{className:"flex flex-col sm:flex-row sm:items-center justify-between gap-4",children:[e.jsxs("div",{children:[e.jsx("h1",{className:"text-2xl sm:text-3xl font-bold",children:"模型管理与分配"}),e.jsx("p",{className:"text-muted-foreground mt-1 sm:mt-2 text-sm sm:text-base",children:"添加模型并为模型分配功能"})]}),e.jsxs("div",{className:"flex gap-2 w-full sm:w-auto",children:[e.jsxs(S,{onClick:Je,disabled:N||w||!O||Y,size:"sm",variant:"outline",className:"flex-1 sm:flex-none sm:min-w-[120px]",children:[e.jsx(fi,{className:"mr-2 h-4 w-4",strokeWidth:2,fill:"none"}),N?"保存中...":w?"自动保存中...":O?"保存配置":"已保存"]}),e.jsxs(hs,{children:[e.jsx(rt,{asChild:!0,children:e.jsxs(S,{disabled:N||w||Y,size:"sm",className:"flex-1 sm:flex-none sm:min-w-[120px]",children:[e.jsx(hi,{className:"mr-2 h-4 w-4"}),Y?"重启中...":O?"保存并重启":"重启麦麦"]})}),e.jsxs(ls,{children:[e.jsxs(ns,{children:[e.jsx(is,{children:"确认重启麦麦?"}),e.jsx(cs,{asChild:!0,children:e.jsx("div",{children:e.jsx("p",{children:O?"当前有未保存的配置更改。点击确认将先保存配置,然后重启麦麦使新配置生效。重启过程中麦麦将暂时离线。":"即将重启麦麦主程序。重启过程中麦麦将暂时离线,配置将在重启后生效。"})})})]}),e.jsxs(rs,{children:[e.jsx(ds,{children:"取消"}),e.jsx(os,{onClick:O?De:X,children:O?"保存并重启":"确认重启"})]})]})]})]})]}),e.jsxs(It,{children:[e.jsx(Ra,{className:"h-4 w-4"}),e.jsxs(Yt,{children:["配置更新后需要",e.jsx("strong",{children:"重启麦麦"}),'才能生效。你可以点击右上角的"保存并重启"按钮一键完成保存和重启。']})]}),e.jsxs(It,{className:"hidden lg:flex border-primary/30 bg-primary/5 cursor-pointer hover:bg-primary/10 transition-colors",onClick:E,children:[e.jsx(iy,{className:"h-4 w-4 text-primary"}),e.jsxs(Yt,{className:"flex items-center justify-between",children:[e.jsxs("span",{children:[e.jsx("strong",{className:"text-primary",children:"新手引导:"}),"不知道如何配置模型?点击这里开始学习如何为麦麦的组件分配模型。"]}),e.jsx(S,{variant:"outline",size:"sm",className:"ml-4 shrink-0",children:"开始引导"})]})]}),e.jsxs(ga,{defaultValue:"models",className:"w-full",children:[e.jsxs(la,{className:"grid w-full max-w-full sm:max-w-md grid-cols-2",children:[e.jsx(ss,{value:"models",children:"添加模型"}),e.jsx(ss,{value:"tasks","data-tour":"tasks-tab-trigger",children:"为模型分配功能"})]}),e.jsxs(Ts,{value:"models",className:"space-y-4 mt-0",children:[e.jsxs("div",{className:"flex flex-col sm:flex-row justify-between items-start sm:items-center gap-2",children:[e.jsx("p",{className:"text-sm text-muted-foreground",children:"配置可用的模型列表"}),e.jsxs("div",{className:"flex gap-2 w-full sm:w-auto",children:[q.size>0&&e.jsxs(S,{onClick:Xs,size:"sm",variant:"destructive",className:"w-full sm:w-auto",children:[e.jsx(We,{className:"mr-2 h-4 w-4",strokeWidth:2,fill:"none"}),"批量删除 (",q.size,")"]}),e.jsxs(S,{onClick:()=>Ks(null,null),size:"sm",variant:"outline",className:"w-full sm:w-auto","data-tour":"add-model-button",children:[e.jsx(dt,{className:"mr-2 h-4 w-4",strokeWidth:2,fill:"none"}),"添加模型"]})]})]}),e.jsxs("div",{className:"flex flex-col sm:flex-row items-start sm:items-center gap-2",children:[e.jsxs("div",{className:"relative w-full sm:flex-1 sm:max-w-sm",children:[e.jsx(Mt,{className:"absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground"}),e.jsx(ie,{placeholder:"搜索模型名称、标识符或提供商...",value:D,onChange:_=>J(_.target.value),className:"pl-9"})]}),D&&e.jsxs("p",{className:"text-sm text-muted-foreground whitespace-nowrap",children:["找到 ",Js.length," 个结果"]})]}),e.jsx(s1,{paginatedModels:Lt,allModels:n,onEdit:Ks,onDelete:Ae,isModelUsed:ba,searchQuery:D}),e.jsx(t1,{paginatedModels:Lt,allModels:n,filteredModels:Js,selectedModels:q,onEdit:Ks,onDelete:Ae,onToggleSelection:bs,onToggleSelectAll:Nt,isModelUsed:ba,searchQuery:D}),e.jsx(n1,{page:me,pageSize:Ce,totalItems:Js.length,jumpToPage:ge,onPageChange:_e,onPageSizeChange:ze,onJumpToPageChange:ae,onJumpToPage:ol,onSelectionClear:()=>se(new Set)})]}),e.jsxs(Ts,{value:"tasks",className:"space-y-6 mt-0",children:[e.jsx("p",{className:"text-sm text-muted-foreground",children:"为不同的任务配置使用的模型和参数"}),g&&e.jsxs("div",{className:"grid gap-4 sm:gap-6",children:[e.jsx(_a,{title:"组件模型 (utils)",description:"用于表情包、取名、关系、情绪变化等组件",taskConfig:g.utils,modelNames:f,onChange:(_,G)=>Es("utils",_,G),dataTour:"task-model-select"}),e.jsx(_a,{title:"组件小模型 (utils_small)",description:"消耗量较大的组件,建议使用速度较快的小模型",taskConfig:g.utils_small,modelNames:f,onChange:(_,G)=>Es("utils_small",_,G)}),e.jsx(_a,{title:"工具调用模型 (tool_use)",description:"需要使用支持工具调用的模型",taskConfig:g.tool_use,modelNames:f,onChange:(_,G)=>Es("tool_use",_,G)}),e.jsx(_a,{title:"首要回复模型 (replyer)",description:"用于表达器和表达方式学习",taskConfig:g.replyer,modelNames:f,onChange:(_,G)=>Es("replyer",_,G)}),e.jsx(_a,{title:"决策模型 (planner)",description:"负责决定麦麦该什么时候回复",taskConfig:g.planner,modelNames:f,onChange:(_,G)=>Es("planner",_,G)}),e.jsx(_a,{title:"图像识别模型 (vlm)",description:"视觉语言模型",taskConfig:g.vlm,modelNames:f,onChange:(_,G)=>Es("vlm",_,G),hideTemperature:!0}),e.jsx(_a,{title:"语音识别模型 (voice)",description:"语音转文字",taskConfig:g.voice,modelNames:f,onChange:(_,G)=>Es("voice",_,G),hideTemperature:!0,hideMaxTokens:!0}),e.jsx(_a,{title:"嵌入模型 (embedding)",description:"用于向量化",taskConfig:g.embedding,modelNames:f,onChange:(_,G)=>Es("embedding",_,G),hideTemperature:!0,hideMaxTokens:!0}),e.jsxs("div",{className:"space-y-4",children:[e.jsx("h3",{className:"text-lg font-semibold",children:"LPMM 知识库模型"}),e.jsx(_a,{title:"实体提取模型 (lpmm_entity_extract)",description:"从文本中提取实体",taskConfig:g.lpmm_entity_extract,modelNames:f,onChange:(_,G)=>Es("lpmm_entity_extract",_,G)}),e.jsx(_a,{title:"RDF 构建模型 (lpmm_rdf_build)",description:"构建知识图谱",taskConfig:g.lpmm_rdf_build,modelNames:f,onChange:(_,G)=>Es("lpmm_rdf_build",_,G)}),e.jsx(_a,{title:"问答模型 (lpmm_qa)",description:"知识库问答",taskConfig:g.lpmm_qa,modelNames:f,onChange:(_,G)=>Es("lpmm_qa",_,G)})]})]})]})]}),e.jsx(qs,{open:I,onOpenChange:_s,children:e.jsxs(Ls,{className:"max-w-[95vw] sm:max-w-2xl max-h-[90vh] overflow-y-auto","data-tour":"model-dialog",preventOutsideClose:xe,children:[e.jsxs(Us,{children:[e.jsx(Bs,{children:fe!==null?"编辑模型":"添加模型"}),e.jsx(Ps,{children:"配置模型的基本信息和参数"})]}),e.jsxs("div",{className:"grid gap-4 py-4",children:[e.jsxs("div",{className:"grid gap-2","data-tour":"model-name-input",children:[e.jsx(C,{htmlFor:"model_name",className:P.name?"text-destructive":"",children:"模型名称 *"}),e.jsx(ie,{id:"model_name",value:A?.name||"",onChange:_=>{te(G=>G?{...G,name:_.target.value}:null),P.name&&Te(G=>({...G,name:void 0}))},placeholder:"例如: qwen3-30b",className:P.name?"border-destructive focus-visible:ring-destructive":""}),P.name?e.jsx("p",{className:"text-xs text-destructive",children:P.name}):e.jsx("p",{className:"text-xs text-muted-foreground",children:"用于在任务配置中引用此模型"})]}),e.jsxs("div",{className:"grid gap-2","data-tour":"model-provider-select",children:[e.jsx(C,{htmlFor:"api_provider",className:P.api_provider?"text-destructive":"",children:"API 提供商 *"}),e.jsxs(Ue,{value:A?.api_provider||"",onValueChange:_=>{te(G=>G?{...G,api_provider:_}:null),Vs(),P.api_provider&&Te(G=>({...G,api_provider:void 0}))},children:[e.jsx(Oe,{id:"api_provider",className:P.api_provider?"border-destructive focus-visible:ring-destructive":"",children:e.jsx(Be,{placeholder:"选择提供商"})}),e.jsx(Re,{children:i.map(_=>e.jsx(le,{value:_,children:_},_))})]}),P.api_provider&&e.jsx("p",{className:"text-xs text-destructive",children:P.api_provider})]}),e.jsxs("div",{className:"grid gap-2","data-tour":"model-identifier-input",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(C,{htmlFor:"model_identifier",className:P.model_identifier?"text-destructive":"",children:"模型标识符 *"}),xt?.modelFetcher&&e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(Qe,{variant:"secondary",className:"text-xs",children:xt.display_name}),e.jsx(S,{variant:"ghost",size:"sm",className:"h-6 px-2",onClick:()=>A?.api_provider&&js(A.api_provider,!0),disabled:Fs,children:Fs?e.jsx(it,{className:"h-3 w-3 animate-spin"}):e.jsx(zt,{className:"h-3 w-3"})})]})]}),xt?.modelFetcher?e.jsxs(La,{open:re,onOpenChange:F,children:[e.jsx(Ua,{asChild:!0,children:e.jsxs(S,{variant:"outline",role:"combobox","aria-expanded":re,className:"w-full justify-between font-normal",disabled:Fs||!!ks,children:[Fs?e.jsxs("span",{className:"flex items-center gap-2 text-muted-foreground",children:[e.jsx(it,{className:"h-4 w-4 animate-spin"}),"正在获取模型列表..."]}):ks?e.jsx("span",{className:"text-muted-foreground text-sm",children:"点击下方输入框手动填写"}):A?.model_identifier?e.jsx("span",{className:"truncate",children:A.model_identifier}):e.jsx("span",{className:"text-muted-foreground",children:"搜索或选择模型..."}),e.jsx(Iu,{className:"ml-2 h-4 w-4 shrink-0 opacity-50"})]})}),e.jsx(ka,{className:"p-0",align:"start",style:{width:"var(--radix-popover-trigger-width)"},children:e.jsxs(eo,{children:[e.jsx(so,{placeholder:"搜索模型..."}),e.jsx(Ze,{className:"h-[300px]",children:e.jsxs(to,{className:"max-h-none overflow-visible",children:[e.jsx(ao,{children:ks?e.jsxs("div",{className:"py-4 px-2 text-center space-y-2",children:[e.jsx("p",{className:"text-sm text-destructive",children:ks}),!ks.includes("API Key")&&e.jsx(S,{variant:"link",size:"sm",onClick:()=>A?.api_provider&&js(A.api_provider,!0),children:"重试"})]}):"未找到匹配的模型"}),e.jsx(mi,{heading:"可用模型",children:qe.map(_=>e.jsxs(xi,{value:_.id,onSelect:()=>{te(G=>G?{...G,model_identifier:_.id}:null),F(!1)},children:[e.jsx(Qt,{className:`mr-2 h-4 w-4 ${A?.model_identifier===_.id?"opacity-100":"opacity-0"}`}),e.jsxs("div",{className:"flex flex-col",children:[e.jsx("span",{children:_.id}),_.name!==_.id&&e.jsx("span",{className:"text-xs text-muted-foreground",children:_.name})]})]},_.id))}),e.jsx(mi,{heading:"手动输入",children:e.jsxs(xi,{value:"__manual_input__",onSelect:()=>{F(!1)},children:[e.jsx(ln,{className:"mr-2 h-4 w-4"}),"手动输入模型标识符..."]})})]})})]})})]}):e.jsx(ie,{id:"model_identifier",value:A?.model_identifier||"",onChange:_=>{te(G=>G?{...G,model_identifier:_.target.value}:null),P.model_identifier&&Te(G=>({...G,model_identifier:void 0}))},placeholder:"Qwen/Qwen3-30B-A3B-Instruct-2507",className:P.model_identifier?"border-destructive focus-visible:ring-destructive":""}),P.model_identifier&&e.jsx("p",{className:"text-xs text-destructive",children:P.model_identifier}),ks&&xt?.modelFetcher&&!P.model_identifier&&e.jsxs(It,{variant:"destructive",className:"mt-2 py-2",children:[e.jsx(Ra,{className:"h-4 w-4"}),e.jsx(Yt,{className:"text-xs",children:ks})]}),xt?.modelFetcher&&e.jsx(ie,{value:A?.model_identifier||"",onChange:_=>{te(G=>G?{...G,model_identifier:_.target.value}:null),P.model_identifier&&Te(G=>({...G,model_identifier:void 0}))},placeholder:"或手动输入模型标识符",className:`mt-2 ${P.model_identifier?"border-destructive focus-visible:ring-destructive":""}`}),!P.model_identifier&&e.jsx("p",{className:"text-xs text-muted-foreground",children:ks?'请手动输入模型标识符,或前往"模型提供商配置"检查 API Key':xt?.modelFetcher?`已识别为 ${xt.display_name},支持自动获取模型列表`:"API 提供商提供的模型 ID"})]}),e.jsxs("div",{className:"grid grid-cols-1 sm:grid-cols-2 gap-4",children:[e.jsxs("div",{className:"grid gap-2",children:[e.jsx(C,{htmlFor:"price_in",children:"输入价格 (¥/M token)"}),e.jsx(ie,{id:"price_in",type:"number",step:"0.1",min:"0",value:A?.price_in??"",onChange:_=>{const G=_.target.value===""?null:parseFloat(_.target.value);te(we=>we?{...we,price_in:G}:null)},placeholder:"默认: 0"})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(C,{htmlFor:"price_out",children:"输出价格 (¥/M token)"}),e.jsx(ie,{id:"price_out",type:"number",step:"0.1",min:"0",value:A?.price_out??"",onChange:_=>{const G=_.target.value===""?null:parseFloat(_.target.value);te(we=>we?{...we,price_out:G}:null)},placeholder:"默认: 0"})]})]}),e.jsxs("div",{className:"rounded-lg border p-4 space-y-3",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"space-y-0.5",children:[e.jsx(C,{htmlFor:"enable_model_temperature",className:"cursor-pointer",children:"自定义模型温度"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"启用后将覆盖「为模型分配功能」中的任务温度配置"})]}),e.jsx($e,{id:"enable_model_temperature",checked:A?.temperature!=null,onCheckedChange:_=>{te(_?G=>G?{...G,temperature:.5}:null:G=>G?{...G,temperature:null}:null)}})]}),A?.temperature!=null&&e.jsxs("div",{className:"space-y-2 pt-2 border-t",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(C,{className:"text-sm",children:"温度值"}),e.jsx("span",{className:"text-sm font-medium tabular-nums",children:A.temperature.toFixed(1)})]}),e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("span",{className:"text-xs text-muted-foreground",children:"0"}),e.jsx(pa,{value:[A.temperature],onValueChange:_=>te(G=>G?{...G,temperature:_[0]}:null),min:0,max:1,step:.1,className:"flex-1"}),e.jsx("span",{className:"text-xs text-muted-foreground",children:"1"})]}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"较低的温度(0.1-0.3)产生更确定的输出,较高的温度(0.7-1.0)产生更多样化的输出"})]})]}),e.jsxs("div",{className:"rounded-lg border p-4 space-y-3",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"space-y-0.5",children:[e.jsx(C,{htmlFor:"enable_model_max_tokens",className:"cursor-pointer",children:"自定义最大 Token"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"启用后将覆盖「为模型分配功能」中的任务最大 Token 配置"})]}),e.jsx($e,{id:"enable_model_max_tokens",checked:A?.max_tokens!=null,onCheckedChange:_=>{te(_?G=>G?{...G,max_tokens:2048}:null:G=>G?{...G,max_tokens:null}:null)}})]}),A?.max_tokens!=null&&e.jsxs("div",{className:"space-y-2 pt-2 border-t",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(C,{className:"text-sm",children:"最大 Token 数"}),e.jsx(ie,{type:"number",min:"1",max:"128000",value:A.max_tokens,onChange:_=>{const G=parseInt(_.target.value);!isNaN(G)&&G>=1&&te(we=>we?{...we,max_tokens:G}:null)},className:"w-28 h-8 text-sm"})]}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"限制模型单次输出的最大 token 数量,不同模型支持的上限不同"})]})]}),e.jsxs("div",{className:"flex items-center space-x-2",children:[e.jsx($e,{id:"force_stream_mode",checked:A?.force_stream_mode||!1,onCheckedChange:_=>te(G=>G?{...G,force_stream_mode:_}:null)}),e.jsx(C,{htmlFor:"force_stream_mode",className:"cursor-pointer",children:"强制流式输出模式"})]}),e.jsx(Pw,{value:A?.extra_params||{},onChange:_=>te(G=>G?{...G,extra_params:_}:null),placeholder:"添加额外参数(如 enable_thinking、top_p 等)..."})]}),e.jsxs(st,{children:[e.jsx(S,{variant:"outline",onClick:()=>T(!1),"data-tour":"model-cancel-button",children:"取消"}),e.jsx(S,{onClick:ye,"data-tour":"model-save-button",children:"保存"})]})]})}),e.jsx(hs,{open:pe,onOpenChange:he,children:e.jsxs(ls,{children:[e.jsxs(ns,{children:[e.jsx(is,{children:"确认删除"}),e.jsxs(cs,{children:['确定要删除模型 "',ve!==null?n[ve]?.name:"",'" 吗? 此操作无法撤销。']})]}),e.jsxs(rs,{children:[e.jsx(ds,{children:"取消"}),e.jsx(os,{onClick:vs,children:"删除"})]})]})}),e.jsx(hs,{open:R,onOpenChange:ue,children:e.jsxs(ls,{children:[e.jsxs(ns,{children:[e.jsx(is,{children:"确认批量删除"}),e.jsxs(cs,{children:["确定要删除选中的 ",q.size," 个模型吗? 此操作无法撤销。"]})]}),e.jsxs(rs,{children:[e.jsx(ds,{children:"取消"}),e.jsx(os,{onClick:Ss,className:"bg-destructive text-destructive-foreground hover:bg-destructive/90",children:"批量删除"})]})]})}),z&&e.jsx(Zu,{onRestartComplete:Ke,onRestartFailed:Ns})]})})}const lo="/api/webui/config";async function d1(){const r=await(await Se(`${lo}/adapter-config/path`)).json();return!r.success||!r.path?null:{path:r.path,lastModified:r.lastModified}}async function pp(n){const i=await(await Se(`${lo}/adapter-config/path`,{method:"POST",headers:Gs(),body:JSON.stringify({path:n})})).json();if(!i.success)throw new Error(i.message||"保存路径失败")}async function gp(n){const i=await(await Se(`${lo}/adapter-config?path=${encodeURIComponent(n)}`)).json();if(!i.success)throw new Error("读取配置文件失败");return i.content}async function jp(n,r){const d=await(await Se(`${lo}/adapter-config`,{method:"POST",headers:Gs(),body:JSON.stringify({path:n,content:r})})).json();if(!d.success)throw new Error(d.message||"保存配置失败")}const ta={inner:{version:"0.1.2"},nickname:{nickname:""},napcat_server:{host:"localhost",port:8095,token:"",heartbeat_interval:30},maibot_server:{host:"localhost",port:8e3},chat:{group_list_type:"whitelist",group_list:[],private_list_type:"whitelist",private_list:[],ban_user_id:[],ban_qq_bot:!1,enable_poke:!0},voice:{use_tts:!1},debug:{level:"INFO"}},Au={oneclick:{name:"一键包",description:"使用一键包部署的适配器配置",path:"../MaiBot-Napcat-Adapter/config.toml",icon:Ol},docker:{name:"Docker",description:"Docker Compose 部署的适配器配置",path:"/MaiMBot/adapters-config/config.toml",icon:cy}};function u1(){const[n,r]=u.useState("upload"),[i,d]=u.useState(null),[m,x]=u.useState(""),[f,p]=u.useState(""),[g,b]=u.useState("oneclick"),[j,y]=u.useState(""),[N,k]=u.useState(!1),[w,U]=u.useState(!1),[O,B]=u.useState(!1),[Y,L]=u.useState(!1),[z,K]=u.useState(null),I=u.useRef(null),{toast:T}=$s(),A=u.useRef(null),te=ae=>{if(!ae.trim())return{valid:!1,error:"路径不能为空"};if(!ae.toLowerCase().endsWith(".toml"))return{valid:!1,error:"文件必须是 .toml 格式"};const re=/^([a-zA-Z]:\\|\\\\[^\\]+\\[^\\]+\\).+\.toml$/i,F=/^(\/|~\/).+\.toml$/i,P=/^(\.{1,2}[\\/]|[^:\\/]).+\.toml$/i,Te=re.test(ae),Le=F.test(ae),E=P.test(ae);return!Te&&!Le&&!E?{valid:!1,error:"路径格式错误"}:/[<>"|?*\x00-\x1F]/.test(ae)?{valid:!1,error:"路径包含非法字符"}:{valid:!0,error:""}},fe=ae=>{if(p(ae),ae.trim()){const re=te(ae);y(re.error)}else y("")},je=u.useCallback(async ae=>{const re=Au[ae];U(!0);try{const F=await gp(re.path),P=me(F);d(P),b(ae),p(re.path),await pp(re.path),T({title:"加载成功",description:`已从${re.name}预设加载配置`})}catch(F){console.error("加载预设配置失败:",F),T({title:"加载失败",description:F instanceof Error?F.message:"无法读取预设配置文件",variant:"destructive"})}finally{U(!1)}},[T]),pe=u.useCallback(async ae=>{const re=te(ae);if(!re.valid){y(re.error),T({title:"路径无效",description:re.error,variant:"destructive"});return}y(""),U(!0);try{const F=await gp(ae),P=me(F);d(P),p(ae),await pp(ae),T({title:"加载成功",description:"已从配置文件加载"})}catch(F){console.error("加载配置失败:",F),T({title:"加载失败",description:F instanceof Error?F.message:"无法读取配置文件",variant:"destructive"})}finally{U(!1)}},[T]);u.useEffect(()=>{(async()=>{try{const re=await d1();if(re&&re.path){p(re.path);const F=Object.entries(Au).find(([,P])=>P.path===re.path);F?(r("preset"),b(F[0]),await je(F[0])):(r("path"),await pe(re.path))}}catch(re){console.error("加载保存的路径失败:",re)}})()},[pe,je]);const he=u.useCallback(ae=>{n!=="path"&&n!=="preset"||!f||(A.current&&clearTimeout(A.current),A.current=setTimeout(async()=>{k(!0);try{const re=_e(ae);await jp(f,re),T({title:"自动保存成功",description:"配置已保存到文件"})}catch(re){console.error("自动保存失败:",re),T({title:"自动保存失败",description:re instanceof Error?re.message:"保存配置失败",variant:"destructive"})}finally{k(!1)}},1e3))},[n,f,T]),ve=async()=>{if(!i||!f)return;const ae=te(f);if(!ae.valid){T({title:"保存失败",description:ae.error,variant:"destructive"});return}k(!0);try{const re=_e(i);await jp(f,re),T({title:"保存成功",description:"配置已保存到文件"})}catch(re){console.error("保存失败:",re),T({title:"保存失败",description:re instanceof Error?re.message:"保存配置失败",variant:"destructive"})}finally{k(!1)}},be=async()=>{f&&await pe(f)},D=ae=>{if(ae!==n){if(i){K(ae),B(!0);return}J(ae)}},J=ae=>{d(null),x(""),y(""),r(ae),ae==="preset"&&je("oneclick"),T({title:"已切换模式",description:{upload:"现在可以上传配置文件",path:"现在可以指定配置文件路径",preset:"现在可以使用预设配置"}[ae]})},q=()=>{z&&(J(z),K(null)),B(!1)},se=()=>{if(i){L(!0);return}R()},R=()=>{p(""),d(null),y(""),T({title:"已清空",description:"路径和配置已清空"})},ue=()=>{R(),L(!1)},me=ae=>{const re=JSON.parse(JSON.stringify(ta)),F=ae.split(` -`);let P="";for(const Te of F){const Le=Te.trim();if(!Le||Le.startsWith("#"))continue;const E=Le.match(/^\[(\w+)\]/);if(E){P=E[1];continue}const xe=Le.match(/^(\w+)\s*=\s*(.+)$/);if(xe&&P){const[,Ye,ke]=xe;let Q=ke.trim();const Ne=Q.match(/^("[^"]*")/);if(Ne)Q=Ne[1];else{const Fs=Q.indexOf("#");Fs!==-1&&(Q=Q.substring(0,Fs).trim())}let qe;if(Q==="true")qe=!0;else if(Q==="false")qe=!1;else if(Q.startsWith("[")&&Q.endsWith("]")){const Fs=Q.slice(1,-1).trim();if(Fs){const ks=Fs.split(",").map(js=>{const Vs=js.trim();return isNaN(Number(Vs))?Vs.replace(/"/g,""):Number(Vs)}),xt=typeof ks[0];qe=ks.every(js=>typeof js===xt)?ks:ks.filter(js=>typeof js=="number")}else qe=[]}else Q.startsWith('"')&&Q.endsWith('"')?qe=Q.slice(1,-1):isNaN(Number(Q))?qe=Q.replace(/"/g,""):qe=Number(Q);if(P in re){const Fs=re[P];Fs[Ye]=qe}}}return re},_e=ae=>{const re=[],F=(P,Te)=>P===""||P===null||P===void 0?Te:P;return re.push("[inner]"),re.push(`version = "${F(ae.inner.version,ta.inner.version)}" # 版本号`),re.push("# 请勿修改版本号,除非你知道自己在做什么"),re.push(""),re.push("[nickname] # 现在没用"),re.push(`nickname = "${F(ae.nickname.nickname,ta.nickname.nickname)}"`),re.push(""),re.push("[napcat_server] # Napcat连接的ws服务设置"),re.push(`host = "${F(ae.napcat_server.host,ta.napcat_server.host)}" # Napcat设定的主机地址`),re.push(`port = ${F(ae.napcat_server.port||0,ta.napcat_server.port)} # Napcat设定的端口`),re.push(`token = "${F(ae.napcat_server.token,ta.napcat_server.token)}" # Napcat设定的访问令牌,若无则留空`),re.push(`heartbeat_interval = ${F(ae.napcat_server.heartbeat_interval||0,ta.napcat_server.heartbeat_interval)} # 与Napcat设置的心跳相同(按秒计)`),re.push(""),re.push("[maibot_server] # 连接麦麦的ws服务设置"),re.push(`host = "${F(ae.maibot_server.host,ta.maibot_server.host)}" # 麦麦在.env文件中设置的主机地址,即HOST字段`),re.push(`port = ${F(ae.maibot_server.port||0,ta.maibot_server.port)} # 麦麦在.env文件中设置的端口,即PORT字段`),re.push(""),re.push("[chat] # 黑白名单功能"),re.push(`group_list_type = "${F(ae.chat.group_list_type,ta.chat.group_list_type)}" # 群组名单类型,可选为:whitelist, blacklist`),re.push(`group_list = [${ae.chat.group_list.join(", ")}] # 群组名单`),re.push("# 当group_list_type为whitelist时,只有群组名单中的群组可以聊天"),re.push("# 当group_list_type为blacklist时,群组名单中的任何群组无法聊天"),re.push(`private_list_type = "${F(ae.chat.private_list_type,ta.chat.private_list_type)}" # 私聊名单类型,可选为:whitelist, blacklist`),re.push(`private_list = [${ae.chat.private_list.join(", ")}] # 私聊名单`),re.push("# 当private_list_type为whitelist时,只有私聊名单中的用户可以聊天"),re.push("# 当private_list_type为blacklist时,私聊名单中的任何用户无法聊天"),re.push(`ban_user_id = [${ae.chat.ban_user_id.join(", ")}] # 全局禁止名单(全局禁止名单中的用户无法进行任何聊天)`),re.push(`ban_qq_bot = ${ae.chat.ban_qq_bot} # 是否屏蔽QQ官方机器人`),re.push(`enable_poke = ${ae.chat.enable_poke} # 是否启用戳一戳功能`),re.push(""),re.push("[voice] # 发送语音设置"),re.push(`use_tts = ${ae.voice.use_tts} # 是否使用tts语音(请确保你配置了tts并有对应的adapter)`),re.push(""),re.push("[debug]"),re.push(`level = "${F(ae.debug.level,ta.debug.level)}" # 日志等级(DEBUG, INFO, WARNING, ERROR, CRITICAL)`),re.join(` -`)},Ce=ae=>{const re=ae.target.files?.[0];if(!re)return;const F=new FileReader;F.onload=P=>{try{const Te=P.target?.result,Le=me(Te);d(Le),x(re.name),T({title:"上传成功",description:`已加载配置文件:${re.name}`})}catch(Te){console.error("解析配置文件失败:",Te),T({title:"解析失败",description:"配置文件格式错误,请检查文件内容",variant:"destructive"})}},F.readAsText(re)},ze=()=>{if(!i)return;const ae=_e(i),re=new Blob([ae],{type:"text/plain;charset=utf-8"}),F=URL.createObjectURL(re),P=document.createElement("a");P.href=F,P.download=m||"config.toml",document.body.appendChild(P),P.click(),document.body.removeChild(P),URL.revokeObjectURL(F),T({title:"下载成功",description:"配置文件已下载,请手动覆盖并重启适配器"})},ge=()=>{d(JSON.parse(JSON.stringify(ta))),x("config.toml"),T({title:"已加载默认配置",description:"可以开始编辑配置"})};return e.jsx(Ze,{className:"h-full",children:e.jsxs("div",{className:"space-y-4 sm:space-y-6 p-4 sm:p-6",children:[e.jsx("div",{className:"flex flex-col sm:flex-row sm:items-center justify-between gap-4",children:e.jsxs("div",{children:[e.jsx("h1",{className:"text-2xl sm:text-3xl font-bold",children:"麦麦适配器配置"}),e.jsx("p",{className:"text-muted-foreground mt-1 sm:mt-2 text-sm sm:text-base",children:"管理麦麦的 QQ 适配器的配置文件"})]})}),e.jsxs("div",{className:"flex items-start gap-2 p-3 rounded-lg border border-amber-500/50 bg-amber-500/10 text-amber-700 dark:text-amber-400",children:[e.jsx(At,{className:"h-4 w-4 mt-0.5 flex-shrink-0"}),e.jsx("p",{className:"text-sm",children:"适配器配置保存之后使用 WebUI 的重启功能适配器并不会重启,需要手动重启适配器。"})]}),e.jsxs(Fe,{children:[e.jsxs(ts,{children:[e.jsx(as,{children:"工作模式"}),e.jsx(et,{children:"选择配置文件的管理方式"})]}),e.jsxs(xs,{className:"space-y-4",children:[e.jsxs("div",{className:"grid grid-cols-1 md:grid-cols-3 gap-3 md:gap-4",children:[e.jsx("div",{className:`border-2 rounded-lg p-3 md:p-4 cursor-pointer transition-all ${n==="preset"?"border-primary bg-primary/5":"border-muted hover:border-primary/50 active:border-primary/70"}`,onClick:()=>D("preset"),children:e.jsxs("div",{className:"flex items-start gap-2 md:gap-3",children:[e.jsx(Ol,{className:"h-4 w-4 md:h-5 md:w-5 mt-0.5 flex-shrink-0"}),e.jsxs("div",{className:"min-w-0",children:[e.jsx("h3",{className:"font-semibold text-sm md:text-base",children:"预设模式"}),e.jsx("p",{className:"text-xs md:text-sm text-muted-foreground mt-1 line-clamp-2",children:"使用预设的部署配置"})]})]})}),e.jsx("div",{className:`border-2 rounded-lg p-3 md:p-4 cursor-pointer transition-all ${n==="upload"?"border-primary bg-primary/5":"border-muted hover:border-primary/50 active:border-primary/70"}`,onClick:()=>D("upload"),children:e.jsxs("div",{className:"flex items-start gap-2 md:gap-3",children:[e.jsx(oi,{className:"h-4 w-4 md:h-5 md:w-5 mt-0.5 flex-shrink-0"}),e.jsxs("div",{className:"min-w-0",children:[e.jsx("h3",{className:"font-semibold text-sm md:text-base",children:"上传文件模式"}),e.jsx("p",{className:"text-xs md:text-sm text-muted-foreground mt-1 line-clamp-2",children:"上传配置文件,编辑后下载并手动覆盖"})]})]})}),e.jsx("div",{className:`border-2 rounded-lg p-3 md:p-4 cursor-pointer transition-all ${n==="path"?"border-primary bg-primary/5":"border-muted hover:border-primary/50 active:border-primary/70"}`,onClick:()=>D("path"),children:e.jsxs("div",{className:"flex items-start gap-2 md:gap-3",children:[e.jsx(oy,{className:"h-4 w-4 md:h-5 md:w-5 mt-0.5 flex-shrink-0"}),e.jsxs("div",{className:"min-w-0",children:[e.jsx("h3",{className:"font-semibold text-sm md:text-base",children:"指定路径模式"}),e.jsx("p",{className:"text-xs md:text-sm text-muted-foreground mt-1 line-clamp-2",children:"指定配置文件路径,自动加载和保存"})]})]})})]}),n==="preset"&&e.jsxs("div",{className:"space-y-3 pt-2 border-t",children:[e.jsx(C,{className:"text-sm md:text-base",children:"选择部署方式"}),e.jsx("div",{className:"grid grid-cols-1 sm:grid-cols-2 gap-3",children:Object.entries(Au).map(([ae,re])=>{const F=re.icon,P=g===ae;return e.jsx("div",{className:`border-2 rounded-lg p-3 cursor-pointer transition-all ${P?"border-primary bg-primary/5":"border-muted hover:border-primary/50"}`,onClick:()=>{b(ae),je(ae)},children:e.jsxs("div",{className:"flex items-start gap-3",children:[e.jsx(F,{className:"h-5 w-5 mt-0.5 flex-shrink-0"}),e.jsxs("div",{className:"min-w-0 flex-1",children:[e.jsx("h4",{className:"font-semibold text-sm",children:re.name}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:re.description}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1 font-mono break-all",children:re.path})]})]})},ae)})})]}),n==="path"&&e.jsxs("div",{className:"space-y-3 pt-2 border-t",children:[e.jsxs("div",{className:"space-y-2",children:[e.jsx(C,{htmlFor:"config-path",className:"text-sm md:text-base",children:"配置文件路径"}),e.jsxs("div",{className:"flex flex-col sm:flex-row gap-2",children:[e.jsxs("div",{className:"flex-1 space-y-1",children:[e.jsx(ie,{id:"config-path",value:f,onChange:ae=>fe(ae.target.value),placeholder:"例: C:\\Adapter\\config.toml",className:`text-sm ${j?"border-destructive":""}`}),j&&e.jsx("p",{className:"text-xs text-destructive",children:j})]}),e.jsx(S,{onClick:()=>pe(f),disabled:w||!f||!!j,className:"w-full sm:w-auto",children:w?e.jsxs(e.Fragment,{children:[e.jsx(zt,{className:"h-4 w-4 animate-spin mr-2"}),e.jsx("span",{className:"sm:hidden",children:"加载中..."})]}):e.jsxs(e.Fragment,{children:[e.jsx("span",{className:"sm:hidden",children:"加载配置"}),e.jsx("span",{className:"hidden sm:inline",children:"加载"})]})})]})]}),e.jsxs("details",{className:"rounded-lg bg-muted/50 p-3 group",children:[e.jsxs("summary",{className:"text-xs font-medium cursor-pointer select-none list-none flex items-center justify-between",children:[e.jsx("span",{children:"路径格式说明"}),e.jsx("svg",{className:"h-4 w-4 transition-transform group-open:rotate-180",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",children:e.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M19 9l-7 7-7-7"})})]}),e.jsxs("div",{className:"mt-2 space-y-2 text-xs text-muted-foreground",children:[e.jsxs("div",{className:"space-y-1",children:[e.jsx("div",{className:"flex items-center gap-2",children:e.jsx("span",{className:"font-mono bg-background px-1.5 py-0.5 rounded text-[10px] md:text-xs whitespace-nowrap",children:"Windows"})}),e.jsxs("div",{className:"pl-2 space-y-0.5 text-[10px] md:text-xs break-all",children:[e.jsx("div",{children:"C:\\Adapter\\config.toml"}),e.jsx("div",{className:"hidden sm:block",children:"D:\\MaiBot\\adapter\\config.toml"}),e.jsx("div",{className:"hidden sm:block",children:"\\\\server\\share\\config.toml"})]})]}),e.jsxs("div",{className:"space-y-1",children:[e.jsx("div",{className:"flex items-center gap-2",children:e.jsx("span",{className:"font-mono bg-background px-1.5 py-0.5 rounded text-[10px] md:text-xs whitespace-nowrap",children:"Linux"})}),e.jsxs("div",{className:"pl-2 space-y-0.5 text-[10px] md:text-xs break-all",children:[e.jsx("div",{children:"/opt/adapter/config.toml"}),e.jsx("div",{className:"hidden sm:block",children:"/home/user/adapter/config.toml"}),e.jsx("div",{className:"hidden sm:block",children:"~/adapter/config.toml"})]})]}),e.jsx("p",{className:"pt-1 border-t text-[10px] md:text-xs",children:"💡 配置会自动保存到指定文件,修改后 1 秒自动保存"})]})]})]})]})]}),e.jsxs(It,{children:[e.jsx(Ra,{className:"h-4 w-4"}),e.jsx(Yt,{children:n==="preset"?e.jsxs(e.Fragment,{children:[e.jsx("strong",{children:"预设模式:"}),"选择预设的部署方式,配置会自动加载,修改后 1 秒自动保存",N&&" (正在保存...)"]}):n==="upload"?e.jsxs(e.Fragment,{children:[e.jsx("strong",{children:"上传文件模式:"}),"上传配置文件 → 在线编辑 → 下载文件 → 手动覆盖并重启适配器"]}):e.jsxs(e.Fragment,{children:[e.jsx("strong",{children:"指定路径模式:"}),"指定配置文件路径后,配置会自动加载,修改后 1 秒自动保存",N&&" (正在保存...)"]})})]}),n==="upload"&&!i&&e.jsxs("div",{className:"flex flex-col sm:flex-row gap-2 w-full",children:[e.jsx("input",{ref:I,type:"file",accept:".toml",className:"hidden",onChange:Ce}),e.jsxs(S,{onClick:()=>I.current?.click(),size:"sm",variant:"outline",className:"w-full sm:w-auto",children:[e.jsx(oi,{className:"mr-2 h-4 w-4"}),"上传配置"]}),e.jsxs(S,{onClick:ge,size:"sm",className:"w-full sm:w-auto",children:[e.jsx(Sa,{className:"mr-2 h-4 w-4"}),"使用默认配置"]})]}),n==="upload"&&i&&e.jsx("div",{className:"flex gap-2",children:e.jsxs(S,{onClick:ze,size:"sm",className:"w-full sm:w-auto",children:[e.jsx(Oa,{className:"mr-2 h-4 w-4"}),"下载配置"]})}),(n==="preset"||n==="path")&&i&&e.jsxs("div",{className:"flex flex-col sm:flex-row gap-2",children:[e.jsxs(S,{onClick:ve,size:"sm",disabled:N||!!j,className:"w-full sm:w-auto",children:[e.jsx(fi,{className:"mr-2 h-4 w-4"}),N?"保存中...":"立即保存"]}),e.jsxs(S,{onClick:be,size:"sm",variant:"outline",disabled:w,className:"w-full sm:w-auto",children:[e.jsx(zt,{className:`mr-2 h-4 w-4 ${w?"animate-spin":""}`}),"刷新"]}),n==="path"&&e.jsxs(S,{onClick:se,size:"sm",variant:"destructive",className:"w-full sm:w-auto",children:[e.jsx(We,{className:"mr-2 h-4 w-4"}),"清空路径"]})]}),i?e.jsxs(ga,{defaultValue:"napcat",className:"w-full",children:[e.jsx("div",{className:"overflow-x-auto -mx-4 px-4 sm:mx-0 sm:px-0",children:e.jsxs(la,{className:"inline-flex w-auto min-w-full sm:grid sm:w-full sm:grid-cols-5",children:[e.jsxs(ss,{value:"napcat",className:"flex-shrink-0 text-xs sm:text-sm whitespace-nowrap",children:[e.jsx("span",{className:"hidden sm:inline",children:"Napcat 连接"}),e.jsx("span",{className:"sm:hidden",children:"Napcat"})]}),e.jsxs(ss,{value:"maibot",className:"flex-shrink-0 text-xs sm:text-sm whitespace-nowrap",children:[e.jsx("span",{className:"hidden sm:inline",children:"麦麦连接"}),e.jsx("span",{className:"sm:hidden",children:"麦麦"})]}),e.jsxs(ss,{value:"chat",className:"flex-shrink-0 text-xs sm:text-sm whitespace-nowrap",children:[e.jsx("span",{className:"hidden sm:inline",children:"聊天控制"}),e.jsx("span",{className:"sm:hidden",children:"聊天"})]}),e.jsxs(ss,{value:"voice",className:"flex-shrink-0 text-xs sm:text-sm whitespace-nowrap",children:[e.jsx("span",{className:"hidden sm:inline",children:"语音设置"}),e.jsx("span",{className:"sm:hidden",children:"语音"})]}),e.jsx(ss,{value:"debug",className:"flex-shrink-0 text-xs sm:text-sm whitespace-nowrap",children:"调试"})]})}),e.jsx(Ts,{value:"napcat",className:"space-y-4",children:e.jsx(m1,{config:i,onChange:ae=>{d(ae),he(ae)}})}),e.jsx(Ts,{value:"maibot",className:"space-y-4",children:e.jsx(x1,{config:i,onChange:ae=>{d(ae),he(ae)}})}),e.jsx(Ts,{value:"chat",className:"space-y-4",children:e.jsx(h1,{config:i,onChange:ae=>{d(ae),he(ae)}})}),e.jsx(Ts,{value:"voice",className:"space-y-4",children:e.jsx(f1,{config:i,onChange:ae=>{d(ae),he(ae)}})}),e.jsx(Ts,{value:"debug",className:"space-y-4",children:e.jsx(p1,{config:i,onChange:ae=>{d(ae),he(ae)}})})]}):e.jsx("div",{className:"rounded-lg border bg-card p-6 md:p-12",children:e.jsxs("div",{className:"text-center space-y-3 md:space-y-4",children:[e.jsx(Sa,{className:"h-12 w-12 md:h-16 md:w-16 mx-auto text-muted-foreground"}),e.jsxs("div",{children:[e.jsx("h3",{className:"text-base md:text-lg font-semibold",children:"尚未加载配置"}),e.jsx("p",{className:"text-xs md:text-sm text-muted-foreground mt-2 px-4",children:n==="preset"?"请选择预设的部署方式":n==="upload"?"请上传现有配置文件,或使用默认配置开始编辑":"请指定配置文件路径并点击加载按钮"})]})]})}),e.jsx(hs,{open:O,onOpenChange:B,children:e.jsxs(ls,{children:[e.jsxs(ns,{children:[e.jsx(is,{children:"确认切换模式"}),e.jsxs(cs,{children:["切换模式将清空当前配置,确定要继续吗?",e.jsx("br",{}),e.jsx("span",{className:"text-destructive font-medium",children:"请确保已保存重要配置"})]})]}),e.jsxs(rs,{children:[e.jsx(ds,{onClick:()=>{B(!1),K(null)},children:"取消"}),e.jsx(os,{onClick:q,children:"确认切换"})]})]})}),e.jsx(hs,{open:Y,onOpenChange:L,children:e.jsxs(ls,{children:[e.jsxs(ns,{children:[e.jsx(is,{children:"确认清空路径"}),e.jsxs(cs,{children:["清空路径将清除当前配置,确定要继续吗?",e.jsx("br",{}),e.jsx("span",{className:"text-muted-foreground text-sm",children:"此操作不会删除配置文件,只是清除界面中的配置"})]})]}),e.jsxs(rs,{children:[e.jsx(ds,{onClick:()=>L(!1),children:"取消"}),e.jsx(os,{onClick:ue,className:"bg-destructive hover:bg-destructive/90",children:"确认清空"})]})]})})]})})}function m1({config:n,onChange:r}){return e.jsx("div",{className:"rounded-lg border bg-card p-4 md:p-6 space-y-4 md:space-y-6",children:e.jsxs("div",{children:[e.jsx("h3",{className:"text-base md:text-lg font-semibold mb-3 md:mb-4",children:"Napcat WebSocket 服务设置"}),e.jsxs("div",{className:"grid gap-3 md:gap-4",children:[e.jsxs("div",{className:"grid gap-2",children:[e.jsx(C,{htmlFor:"napcat-host",className:"text-sm md:text-base",children:"主机地址"}),e.jsx(ie,{id:"napcat-host",value:n.napcat_server.host,onChange:i=>r({...n,napcat_server:{...n.napcat_server,host:i.target.value}}),placeholder:"localhost",className:"text-sm md:text-base"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"Napcat 设定的主机地址"})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(C,{htmlFor:"napcat-port",className:"text-sm md:text-base",children:"端口"}),e.jsx(ie,{id:"napcat-port",type:"number",value:n.napcat_server.port||"",onChange:i=>r({...n,napcat_server:{...n.napcat_server,port:i.target.value?parseInt(i.target.value):0}}),placeholder:"8095",className:"text-sm md:text-base"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"Napcat 设定的端口(留空使用默认值 8095)"})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(C,{htmlFor:"napcat-token",className:"text-sm md:text-base",children:"访问令牌(Token)"}),e.jsx(ie,{id:"napcat-token",type:"password",value:n.napcat_server.token,onChange:i=>r({...n,napcat_server:{...n.napcat_server,token:i.target.value}}),placeholder:"留空表示无需令牌",className:"text-sm md:text-base"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"Napcat 设定的访问令牌,若无则留空"})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(C,{htmlFor:"napcat-heartbeat",className:"text-sm md:text-base",children:"心跳间隔(秒)"}),e.jsx(ie,{id:"napcat-heartbeat",type:"number",value:n.napcat_server.heartbeat_interval||"",onChange:i=>r({...n,napcat_server:{...n.napcat_server,heartbeat_interval:i.target.value?parseInt(i.target.value):0}}),placeholder:"30",className:"text-sm md:text-base"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"与 Napcat 设置的心跳间隔保持一致(留空使用默认值 30)"})]})]})]})})}function x1({config:n,onChange:r}){return e.jsx("div",{className:"rounded-lg border bg-card p-4 md:p-6 space-y-4 md:space-y-6",children:e.jsxs("div",{children:[e.jsx("h3",{className:"text-base md:text-lg font-semibold mb-3 md:mb-4",children:"麦麦 WebSocket 服务设置"}),e.jsxs("div",{className:"grid gap-3 md:gap-4",children:[e.jsxs("div",{className:"grid gap-2",children:[e.jsx(C,{htmlFor:"maibot-host",className:"text-sm md:text-base",children:"主机地址"}),e.jsx(ie,{id:"maibot-host",value:n.maibot_server.host,onChange:i=>r({...n,maibot_server:{...n.maibot_server,host:i.target.value}}),placeholder:"localhost",className:"text-sm md:text-base"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"麦麦在 .env 文件中设置的 HOST 字段"})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(C,{htmlFor:"maibot-port",className:"text-sm md:text-base",children:"端口"}),e.jsx(ie,{id:"maibot-port",type:"number",value:n.maibot_server.port||"",onChange:i=>r({...n,maibot_server:{...n.maibot_server,port:i.target.value?parseInt(i.target.value):0}}),placeholder:"8000",className:"text-sm md:text-base"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"麦麦在 .env 文件中设置的 PORT 字段(留空使用默认值 8000)"})]})]})]})})}function h1({config:n,onChange:r}){const i=x=>{const f={...n};x==="group"?f.chat.group_list=[...f.chat.group_list,0]:x==="private"?f.chat.private_list=[...f.chat.private_list,0]:f.chat.ban_user_id=[...f.chat.ban_user_id,0],r(f)},d=(x,f)=>{const p={...n};x==="group"?p.chat.group_list=p.chat.group_list.filter((g,b)=>b!==f):x==="private"?p.chat.private_list=p.chat.private_list.filter((g,b)=>b!==f):p.chat.ban_user_id=p.chat.ban_user_id.filter((g,b)=>b!==f),r(p)},m=(x,f,p)=>{const g={...n};x==="group"?g.chat.group_list[f]=p:x==="private"?g.chat.private_list[f]=p:g.chat.ban_user_id[f]=p,r(g)};return e.jsx("div",{className:"rounded-lg border bg-card p-4 md:p-6 space-y-4 md:space-y-6",children:e.jsxs("div",{children:[e.jsx("h3",{className:"text-base md:text-lg font-semibold mb-3 md:mb-4",children:"聊天黑白名单功能"}),e.jsxs("div",{className:"grid gap-4 md:gap-6",children:[e.jsxs("div",{className:"space-y-3 md:space-y-4",children:[e.jsxs("div",{className:"grid gap-2",children:[e.jsx(C,{className:"text-sm md:text-base",children:"群组名单类型"}),e.jsxs(Ue,{value:n.chat.group_list_type,onValueChange:x=>r({...n,chat:{...n.chat,group_list_type:x}}),children:[e.jsx(Oe,{children:e.jsx(Be,{})}),e.jsxs(Re,{children:[e.jsx(le,{value:"whitelist",children:"白名单(仅名单内可聊天)"}),e.jsx(le,{value:"blacklist",children:"黑名单(名单内禁止聊天)"})]})]})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsxs("div",{className:"flex flex-col sm:flex-row sm:items-center sm:justify-between gap-2 sm:gap-0",children:[e.jsx(C,{className:"text-sm md:text-base",children:"群组列表"}),e.jsxs(S,{onClick:()=>i("group"),size:"sm",variant:"outline",className:"w-full sm:w-auto",children:[e.jsx(Sa,{className:"mr-1 h-4 w-4"}),"添加群号"]})]}),n.chat.group_list.map((x,f)=>e.jsxs("div",{className:"flex gap-2",children:[e.jsx(ie,{type:"number",value:x,onChange:p=>m("group",f,parseInt(p.target.value)||0),placeholder:"输入群号",className:"text-sm md:text-base"}),e.jsxs(hs,{children:[e.jsx(rt,{asChild:!0,children:e.jsx(S,{size:"icon",variant:"outline",children:e.jsx(We,{className:"h-4 w-4"})})}),e.jsxs(ls,{children:[e.jsxs(ns,{children:[e.jsx(is,{children:"确认删除"}),e.jsxs(cs,{children:["确定要删除群号 ",x," 吗?此操作无法撤销。"]})]}),e.jsxs(rs,{children:[e.jsx(ds,{children:"取消"}),e.jsx(os,{onClick:()=>d("group",f),children:"删除"})]})]})]})]},f)),n.chat.group_list.length===0&&e.jsx("p",{className:"text-sm text-muted-foreground",children:"暂无群组"})]})]}),e.jsxs("div",{className:"space-y-3 md:space-y-4",children:[e.jsxs("div",{className:"grid gap-2",children:[e.jsx(C,{className:"text-sm md:text-base",children:"私聊名单类型"}),e.jsxs(Ue,{value:n.chat.private_list_type,onValueChange:x=>r({...n,chat:{...n.chat,private_list_type:x}}),children:[e.jsx(Oe,{children:e.jsx(Be,{})}),e.jsxs(Re,{children:[e.jsx(le,{value:"whitelist",children:"白名单(仅名单内可聊天)"}),e.jsx(le,{value:"blacklist",children:"黑名单(名单内禁止聊天)"})]})]})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsxs("div",{className:"flex flex-col sm:flex-row sm:items-center sm:justify-between gap-2 sm:gap-0",children:[e.jsx(C,{className:"text-sm md:text-base",children:"私聊列表"}),e.jsxs(S,{onClick:()=>i("private"),size:"sm",variant:"outline",className:"w-full sm:w-auto",children:[e.jsx(Sa,{className:"mr-1 h-4 w-4"}),"添加用户"]})]}),n.chat.private_list.map((x,f)=>e.jsxs("div",{className:"flex gap-2",children:[e.jsx(ie,{type:"number",value:x,onChange:p=>m("private",f,parseInt(p.target.value)||0),placeholder:"输入QQ号",className:"text-sm md:text-base"}),e.jsxs(hs,{children:[e.jsx(rt,{asChild:!0,children:e.jsx(S,{size:"icon",variant:"outline",children:e.jsx(We,{className:"h-4 w-4"})})}),e.jsxs(ls,{children:[e.jsxs(ns,{children:[e.jsx(is,{children:"确认删除"}),e.jsxs(cs,{children:["确定要删除用户 ",x," 吗?此操作无法撤销。"]})]}),e.jsxs(rs,{children:[e.jsx(ds,{children:"取消"}),e.jsx(os,{onClick:()=>d("private",f),children:"删除"})]})]})]})]},f)),n.chat.private_list.length===0&&e.jsx("p",{className:"text-sm text-muted-foreground",children:"暂无用户"})]})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsxs("div",{className:"flex flex-col sm:flex-row sm:items-center sm:justify-between gap-2 sm:gap-0",children:[e.jsxs("div",{children:[e.jsx(C,{className:"text-sm md:text-base",children:"全局禁止名单"}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:"名单中的用户无法进行任何聊天"})]}),e.jsxs(S,{onClick:()=>i("ban"),size:"sm",variant:"outline",className:"w-full sm:w-auto",children:[e.jsx(Sa,{className:"mr-1 h-4 w-4"}),"添加用户"]})]}),n.chat.ban_user_id.map((x,f)=>e.jsxs("div",{className:"flex gap-2",children:[e.jsx(ie,{type:"number",value:x,onChange:p=>m("ban",f,parseInt(p.target.value)||0),placeholder:"输入QQ号",className:"text-sm md:text-base"}),e.jsxs(hs,{children:[e.jsx(rt,{asChild:!0,children:e.jsx(S,{size:"icon",variant:"outline",children:e.jsx(We,{className:"h-4 w-4"})})}),e.jsxs(ls,{children:[e.jsxs(ns,{children:[e.jsx(is,{children:"确认删除"}),e.jsxs(cs,{children:["确定要从全局禁止名单中删除用户 ",x," 吗?此操作无法撤销。"]})]}),e.jsxs(rs,{children:[e.jsx(ds,{children:"取消"}),e.jsx(os,{onClick:()=>d("ban",f),children:"删除"})]})]})]})]},f)),n.chat.ban_user_id.length===0&&e.jsx("p",{className:"text-sm text-muted-foreground",children:"暂无禁止用户"})]}),e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{children:[e.jsx(C,{className:"text-sm md:text-base",children:"屏蔽QQ官方机器人"}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:"是否屏蔽来自QQ官方机器人的消息"})]}),e.jsx($e,{checked:n.chat.ban_qq_bot,onCheckedChange:x=>r({...n,chat:{...n.chat,ban_qq_bot:x}})})]}),e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{children:[e.jsx(C,{className:"text-sm md:text-base",children:"启用戳一戳功能"}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:"是否响应戳一戳消息"})]}),e.jsx($e,{checked:n.chat.enable_poke,onCheckedChange:x=>r({...n,chat:{...n.chat,enable_poke:x}})})]})]})]})})}function f1({config:n,onChange:r}){return e.jsx("div",{className:"rounded-lg border bg-card p-4 md:p-6 space-y-4 md:space-y-6",children:e.jsxs("div",{children:[e.jsx("h3",{className:"text-base md:text-lg font-semibold mb-3 md:mb-4",children:"发送语音设置"}),e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{children:[e.jsx(C,{className:"text-sm md:text-base",children:"使用 TTS 语音"}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:"请确保已配置 TTS 并有对应的适配器"})]}),e.jsx($e,{checked:n.voice.use_tts,onCheckedChange:i=>r({...n,voice:{use_tts:i}})})]})]})})}function p1({config:n,onChange:r}){return e.jsx("div",{className:"rounded-lg border bg-card p-4 md:p-6 space-y-4 md:space-y-6",children:e.jsxs("div",{children:[e.jsx("h3",{className:"text-base md:text-lg font-semibold mb-3 md:mb-4",children:"调试设置"}),e.jsx("div",{className:"grid gap-3 md:gap-4",children:e.jsxs("div",{className:"grid gap-2",children:[e.jsx(C,{className:"text-sm md:text-base",children:"日志等级"}),e.jsxs(Ue,{value:n.debug.level,onValueChange:i=>r({...n,debug:{level:i}}),children:[e.jsx(Oe,{children:e.jsx(Be,{})}),e.jsxs(Re,{children:[e.jsx(le,{value:"DEBUG",children:"DEBUG(调试)"}),e.jsx(le,{value:"INFO",children:"INFO(信息)"}),e.jsx(le,{value:"WARNING",children:"WARNING(警告)"}),e.jsx(le,{value:"ERROR",children:"ERROR(错误)"}),e.jsx(le,{value:"CRITICAL",children:"CRITICAL(严重)"})]})]}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"设置适配器的日志输出等级"})]})})]})})}const g1=["defaultChecked","defaultValue","suppressContentEditableWarning","suppressHydrationWarning","dangerouslySetInnerHTML","accessKey","className","contentEditable","contextMenu","dir","draggable","hidden","id","lang","placeholder","slot","spellCheck","style","tabIndex","title","translate","radioGroup","role","about","datatype","inlist","prefix","property","resource","typeof","vocab","autoCapitalize","autoCorrect","autoSave","color","itemProp","itemScope","itemType","itemID","itemRef","results","security","unselectable","inputMode","is","onCopy","onCopyCapture","onCut","onCutCapture","onPaste","onPasteCapture","onCompositionEnd","onCompositionEndCapture","onCompositionStart","onCompositionStartCapture","onCompositionUpdate","onCompositionUpdateCapture","onFocus","onFocusCapture","onBlur","onBlurCapture","onChange","onChangeCapture","onBeforeInput","onBeforeInputCapture","onInput","onInputCapture","onReset","onResetCapture","onSubmit","onSubmitCapture","onInvalid","onInvalidCapture","onLoad","onLoadCapture","onError","onErrorCapture","onKeyDown","onKeyDownCapture","onKeyPress","onKeyPressCapture","onKeyUp","onKeyUpCapture","onAbort","onAbortCapture","onCanPlay","onCanPlayCapture","onCanPlayThrough","onCanPlayThroughCapture","onDurationChange","onDurationChangeCapture","onEmptied","onEmptiedCapture","onEncrypted","onEncryptedCapture","onEnded","onEndedCapture","onLoadedData","onLoadedDataCapture","onLoadedMetadata","onLoadedMetadataCapture","onLoadStart","onLoadStartCapture","onPause","onPauseCapture","onPlay","onPlayCapture","onPlaying","onPlayingCapture","onProgress","onProgressCapture","onRateChange","onRateChangeCapture","onSeeked","onSeekedCapture","onSeeking","onSeekingCapture","onStalled","onStalledCapture","onSuspend","onSuspendCapture","onTimeUpdate","onTimeUpdateCapture","onVolumeChange","onVolumeChangeCapture","onWaiting","onWaitingCapture","onAuxClick","onAuxClickCapture","onClick","onClickCapture","onContextMenu","onContextMenuCapture","onDoubleClick","onDoubleClickCapture","onDrag","onDragCapture","onDragEnd","onDragEndCapture","onDragEnter","onDragEnterCapture","onDragExit","onDragExitCapture","onDragLeave","onDragLeaveCapture","onDragOver","onDragOverCapture","onDragStart","onDragStartCapture","onDrop","onDropCapture","onMouseDown","onMouseDownCapture","onMouseEnter","onMouseLeave","onMouseMove","onMouseMoveCapture","onMouseOut","onMouseOutCapture","onMouseOver","onMouseOverCapture","onMouseUp","onMouseUpCapture","onSelect","onSelectCapture","onTouchCancel","onTouchCancelCapture","onTouchEnd","onTouchEndCapture","onTouchMove","onTouchMoveCapture","onTouchStart","onTouchStartCapture","onPointerDown","onPointerDownCapture","onPointerMove","onPointerMoveCapture","onPointerUp","onPointerUpCapture","onPointerCancel","onPointerCancelCapture","onPointerEnter","onPointerEnterCapture","onPointerLeave","onPointerLeaveCapture","onPointerOver","onPointerOverCapture","onPointerOut","onPointerOutCapture","onGotPointerCapture","onGotPointerCaptureCapture","onLostPointerCapture","onLostPointerCaptureCapture","onScroll","onScrollCapture","onWheel","onWheelCapture","onAnimationStart","onAnimationStartCapture","onAnimationEnd","onAnimationEndCapture","onAnimationIteration","onAnimationIterationCapture","onTransitionEnd","onTransitionEndCapture"],j1=/^(aria-|data-)/,Ig=n=>Object.fromEntries(Object.entries(n).filter(([r])=>j1.test(r)||g1.includes(r)));function v1(n,r){const i=Ig(n);return Object.keys(n).some(d=>!Object.hasOwn(i,d)&&n[d]!==r[d])}class b1 extends u.Component{container;plugin;componentDidMount(){this.installPlugin()}componentDidUpdate(r){if(r.uppy!==this.props.uppy)this.uninstallPlugin(r),this.installPlugin();else if(v1(this.props,r)){const{uppy:i,...d}={...this.props,target:this.container};this.plugin.setOptions(d)}}componentWillUnmount(){this.uninstallPlugin()}installPlugin(){const{uppy:r,...i}={id:"Dashboard",...this.props,inline:!0,target:this.container};r.use(Qy,i),this.plugin=r.getPlugin(i.id)}uninstallPlugin(r=this.props){const{uppy:i}=r;i.removePlugin(this.plugin)}render(){return u.createElement("div",{className:"uppy-Container",ref:r=>{this.container=r},...Ig(this.props)})}}function N1({src:n,alt:r="表情包",className:i,maxRetries:d=5,retryInterval:m=1500}){const[x,f]=u.useState("loading"),[p,g]=u.useState(0),[b,j]=u.useState(null),y=u.useCallback(async()=>{try{const N=await fetch(n,{credentials:"include"});if(N.status===202){f("generating"),p{g(U=>U+1)},m):f("error");return}if(!N.ok){f("error");return}const k=await N.blob(),w=URL.createObjectURL(k);j(w),f("loaded")}catch(N){console.error("加载缩略图失败:",N),f("error")}},[n,p,d,m]);return u.useEffect(()=>{f("loading"),g(0),j(null)},[n]),u.useEffect(()=>{y()},[y]),u.useEffect(()=>()=>{b&&URL.revokeObjectURL(b)},[b]),x==="loading"||x==="generating"?e.jsx(Cg,{className:$("w-full h-full",i)}):x==="error"||!b?e.jsx("div",{className:$("w-full h-full flex items-center justify-center bg-muted",i),children:e.jsx(gg,{className:"h-8 w-8 text-muted-foreground"})}):e.jsx("img",{src:b,alt:r,className:$("w-full h-full object-contain",i)})}function Yg({content:n,className:r=""}){return e.jsx("div",{className:`prose prose-sm dark:prose-invert max-w-none ${r}`,children:e.jsx(Yy,{remarkPlugins:[Xy,Jy],rehypePlugins:[Ky],components:{code({inline:i,className:d,children:m,...x}){return i?e.jsx("code",{className:"bg-muted px-1.5 py-0.5 rounded text-sm font-mono",...x,children:m}):e.jsx("code",{className:`${d} block bg-muted p-4 rounded-lg overflow-x-auto`,...x,children:m})},table({children:i,...d}){return e.jsx("div",{className:"overflow-x-auto",children:e.jsx("table",{className:"border-collapse border border-border",...d,children:i})})},th({children:i,...d}){return e.jsx("th",{className:"border border-border bg-muted px-4 py-2 text-left font-semibold",...d,children:i})},td({children:i,...d}){return e.jsx("td",{className:"border border-border px-4 py-2",...d,children:i})},a({children:i,...d}){return e.jsx("a",{className:"text-primary hover:underline",target:"_blank",rel:"noopener noreferrer",...d,children:i})},blockquote({children:i,...d}){return e.jsx("blockquote",{className:"border-l-4 border-primary pl-4 italic text-muted-foreground",...d,children:i})},h1({children:i,...d}){return e.jsx("h1",{className:"text-3xl font-bold mt-6 mb-4",...d,children:i})},h2({children:i,...d}){return e.jsx("h2",{className:"text-2xl font-bold mt-5 mb-3",...d,children:i})},h3({children:i,...d}){return e.jsx("h3",{className:"text-xl font-bold mt-4 mb-2",...d,children:i})},h4({children:i,...d}){return e.jsx("h4",{className:"text-lg font-semibold mt-3 mb-2",...d,children:i})},ul({children:i,...d}){return e.jsx("ul",{className:"list-disc list-inside space-y-1 my-2",...d,children:i})},ol({children:i,...d}){return e.jsx("ol",{className:"list-decimal list-inside space-y-1 my-2",...d,children:i})},p({children:i,...d}){return e.jsx("p",{className:"my-2 leading-relaxed",...d,children:i})},hr({...i}){return e.jsx("hr",{className:"my-4 border-border",...i})}},children:n})})}function y1({children:n,className:r}){return e.jsx(Yg,{content:n,className:r})}const ja="/api/webui/emoji";async function w1(n){const r=new URLSearchParams;n.page&&r.append("page",n.page.toString()),n.page_size&&r.append("page_size",n.page_size.toString()),n.search&&r.append("search",n.search),n.is_registered!==void 0&&r.append("is_registered",n.is_registered.toString()),n.is_banned!==void 0&&r.append("is_banned",n.is_banned.toString()),n.format&&r.append("format",n.format),n.sort_by&&r.append("sort_by",n.sort_by),n.sort_order&&r.append("sort_order",n.sort_order);const i=await Se(`${ja}/list?${r}`,{});if(!i.ok)throw new Error(`获取表情包列表失败: ${i.statusText}`);return i.json()}async function _1(n){const r=await Se(`${ja}/${n}`,{});if(!r.ok)throw new Error(`获取表情包详情失败: ${r.statusText}`);return r.json()}async function S1(n,r){const i=await Se(`${ja}/${n}`,{method:"PATCH",body:JSON.stringify(r)});if(!i.ok)throw new Error(`更新表情包失败: ${i.statusText}`);return i.json()}async function C1(n){const r=await Se(`${ja}/${n}`,{method:"DELETE"});if(!r.ok)throw new Error(`删除表情包失败: ${r.statusText}`);return r.json()}async function k1(){const n=await Se(`${ja}/stats/summary`,{});if(!n.ok)throw new Error(`获取统计数据失败: ${n.statusText}`);return n.json()}async function T1(n){const r=await Se(`${ja}/${n}/register`,{method:"POST"});if(!r.ok)throw new Error(`注册表情包失败: ${r.statusText}`);return r.json()}async function E1(n){const r=await Se(`${ja}/${n}/ban`,{method:"POST"});if(!r.ok)throw new Error(`封禁表情包失败: ${r.statusText}`);return r.json()}function z1(n,r=!1){return r?`${ja}/${n}/thumbnail?original=true`:`${ja}/${n}/thumbnail`}function A1(n){return`${ja}/${n}/thumbnail?original=true`}async function M1(n){const r=await Se(`${ja}/batch/delete`,{method:"POST",body:JSON.stringify({emoji_ids:n})});if(!r.ok){const i=await r.json();throw new Error(i.detail||"批量删除失败")}return r.json()}function D1(){return`${ja}/upload`}function O1(){const[n,r]=u.useState([]),[i,d]=u.useState(null),[m,x]=u.useState(!1),[f,p]=u.useState(1),[g,b]=u.useState(0),[j,y]=u.useState(20),[N,k]=u.useState("all"),[w,U]=u.useState("all"),[O,B]=u.useState("all"),[Y,L]=u.useState("usage_count"),[z,K]=u.useState("desc"),[I,T]=u.useState(null),[A,te]=u.useState(!1),[fe,je]=u.useState(!1),[pe,he]=u.useState(!1),[ve,be]=u.useState(new Set),[D,J]=u.useState(!1),[q,se]=u.useState(""),[R,ue]=u.useState("medium"),[me,_e]=u.useState(!1),{toast:Ce}=$s(),ze=u.useCallback(async()=>{try{x(!0);const Q=await w1({page:f,page_size:j,is_registered:N==="all"?void 0:N==="registered",is_banned:w==="all"?void 0:w==="banned",format:O==="all"?void 0:O,sort_by:Y,sort_order:z});r(Q.data),b(Q.total)}catch(Q){const Ne=Q instanceof Error?Q.message:"加载表情包列表失败";Ce({title:"错误",description:Ne,variant:"destructive"})}finally{x(!1)}},[f,j,N,w,O,Y,z,Ce]),ge=async()=>{try{const Q=await k1();d(Q.data)}catch(Q){console.error("加载统计数据失败:",Q)}};u.useEffect(()=>{ze()},[ze]),u.useEffect(()=>{ge()},[]);const ae=async Q=>{try{const Ne=await _1(Q.id);T(Ne.data),te(!0)}catch(Ne){const qe=Ne instanceof Error?Ne.message:"加载详情失败";Ce({title:"错误",description:qe,variant:"destructive"})}},re=Q=>{T(Q),je(!0)},F=Q=>{T(Q),he(!0)},P=async()=>{if(I)try{await C1(I.id),Ce({title:"成功",description:"表情包已删除"}),he(!1),T(null),ze(),ge()}catch(Q){const Ne=Q instanceof Error?Q.message:"删除失败";Ce({title:"错误",description:Ne,variant:"destructive"})}},Te=async Q=>{try{await T1(Q.id),Ce({title:"成功",description:"表情包已注册"}),ze(),ge()}catch(Ne){const qe=Ne instanceof Error?Ne.message:"注册失败";Ce({title:"错误",description:qe,variant:"destructive"})}},Le=async Q=>{try{await E1(Q.id),Ce({title:"成功",description:"表情包已封禁"}),ze(),ge()}catch(Ne){const qe=Ne instanceof Error?Ne.message:"封禁失败";Ce({title:"错误",description:qe,variant:"destructive"})}},E=Q=>{const Ne=new Set(ve);Ne.has(Q)?Ne.delete(Q):Ne.add(Q),be(Ne)},xe=async()=>{try{const Q=await M1(Array.from(ve));Ce({title:"批量删除完成",description:Q.message}),be(new Set),J(!1),ze(),ge()}catch(Q){Ce({title:"批量删除失败",description:Q instanceof Error?Q.message:"批量删除失败",variant:"destructive"})}},Ye=()=>{const Q=parseInt(q),Ne=Math.ceil(g/j);Q>=1&&Q<=Ne?(p(Q),se("")):Ce({title:"无效的页码",description:`请输入1-${Ne}之间的页码`,variant:"destructive"})},ke=i?.formats?Object.keys(i.formats):[];return e.jsxs("div",{className:"h-[calc(100vh-4rem)] flex flex-col p-4 sm:p-6",children:[e.jsxs("div",{className:"mb-4 sm:mb-6 flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4",children:[e.jsxs("div",{children:[e.jsx("h1",{className:"text-2xl sm:text-3xl font-bold",children:"表情包管理"}),e.jsx("p",{className:"text-sm text-muted-foreground mt-1",children:"管理麦麦的表情包资源"})]}),e.jsxs(S,{onClick:()=>_e(!0),className:"gap-2",children:[e.jsx(oi,{className:"h-4 w-4"}),"上传表情包"]})]}),e.jsx(Ze,{className:"flex-1",children:e.jsxs("div",{className:"space-y-4 sm:space-y-6 pr-4",children:[i&&e.jsxs("div",{className:"grid gap-4 grid-cols-2 lg:grid-cols-4",children:[e.jsx(Fe,{children:e.jsxs(ts,{className:"pb-2",children:[e.jsx(et,{children:"总数"}),e.jsx(as,{className:"text-2xl",children:i.total})]})}),e.jsx(Fe,{children:e.jsxs(ts,{className:"pb-2",children:[e.jsx(et,{children:"已注册"}),e.jsx(as,{className:"text-2xl text-green-600",children:i.registered})]})}),e.jsx(Fe,{children:e.jsxs(ts,{className:"pb-2",children:[e.jsx(et,{children:"已封禁"}),e.jsx(as,{className:"text-2xl text-red-600",children:i.banned})]})}),e.jsx(Fe,{children:e.jsxs(ts,{className:"pb-2",children:[e.jsx(et,{children:"未注册"}),e.jsx(as,{className:"text-2xl text-gray-600",children:i.unregistered})]})})]}),e.jsxs(Fe,{children:[e.jsx(ts,{children:e.jsxs(as,{className:"flex items-center gap-2",children:[e.jsx(Ou,{className:"h-5 w-5"}),"筛选和排序"]})}),e.jsxs(xs,{className:"space-y-4",children:[e.jsxs("div",{className:"grid gap-4 sm:grid-cols-2 lg:grid-cols-4",children:[e.jsxs("div",{className:"space-y-2",children:[e.jsx(C,{children:"排序方式"}),e.jsxs(Ue,{value:`${Y}-${z}`,onValueChange:Q=>{const[Ne,qe]=Q.split("-");L(Ne),K(qe),p(1)},children:[e.jsx(Oe,{children:e.jsx(Be,{})}),e.jsxs(Re,{children:[e.jsx(le,{value:"usage_count-desc",children:"使用次数 (多→少)"}),e.jsx(le,{value:"usage_count-asc",children:"使用次数 (少→多)"}),e.jsx(le,{value:"register_time-desc",children:"注册时间 (新→旧)"}),e.jsx(le,{value:"register_time-asc",children:"注册时间 (旧→新)"}),e.jsx(le,{value:"record_time-desc",children:"记录时间 (新→旧)"}),e.jsx(le,{value:"record_time-asc",children:"记录时间 (旧→新)"}),e.jsx(le,{value:"last_used_time-desc",children:"最后使用 (新→旧)"}),e.jsx(le,{value:"last_used_time-asc",children:"最后使用 (旧→新)"})]})]})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(C,{children:"注册状态"}),e.jsxs(Ue,{value:N,onValueChange:Q=>{k(Q),p(1)},children:[e.jsx(Oe,{children:e.jsx(Be,{})}),e.jsxs(Re,{children:[e.jsx(le,{value:"all",children:"全部"}),e.jsx(le,{value:"registered",children:"已注册"}),e.jsx(le,{value:"unregistered",children:"未注册"})]})]})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(C,{children:"封禁状态"}),e.jsxs(Ue,{value:w,onValueChange:Q=>{U(Q),p(1)},children:[e.jsx(Oe,{children:e.jsx(Be,{})}),e.jsxs(Re,{children:[e.jsx(le,{value:"all",children:"全部"}),e.jsx(le,{value:"banned",children:"已封禁"}),e.jsx(le,{value:"unbanned",children:"未封禁"})]})]})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(C,{children:"格式"}),e.jsxs(Ue,{value:O,onValueChange:Q=>{B(Q),p(1)},children:[e.jsx(Oe,{children:e.jsx(Be,{})}),e.jsxs(Re,{children:[e.jsx(le,{value:"all",children:"全部"}),ke.map(Q=>e.jsxs(le,{value:Q,children:[Q.toUpperCase()," (",i?.formats[Q],")"]},Q))]})]})]})]}),e.jsxs("div",{className:"flex flex-col sm:flex-row items-start sm:items-center justify-between gap-3 pt-4 border-t",children:[e.jsxs("div",{className:"flex items-center gap-4",children:[ve.size>0&&e.jsxs("span",{className:"text-sm text-muted-foreground",children:["已选择 ",ve.size," 个表情包"]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(C,{className:"text-sm whitespace-nowrap",children:"卡片大小"}),e.jsxs(Ue,{value:R,onValueChange:Q=>ue(Q),children:[e.jsx(Oe,{className:"w-24",children:e.jsx(Be,{})}),e.jsxs(Re,{children:[e.jsx(le,{value:"small",children:"小"}),e.jsx(le,{value:"medium",children:"中"}),e.jsx(le,{value:"large",children:"大"})]})]})]})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(C,{htmlFor:"emoji-page-size",className:"text-sm whitespace-nowrap",children:"每页显示"}),e.jsxs(Ue,{value:j.toString(),onValueChange:Q=>{y(parseInt(Q)),p(1),be(new Set)},children:[e.jsx(Oe,{id:"emoji-page-size",className:"w-20",children:e.jsx(Be,{})}),e.jsxs(Re,{children:[e.jsx(le,{value:"20",children:"20"}),e.jsx(le,{value:"40",children:"40"}),e.jsx(le,{value:"60",children:"60"}),e.jsx(le,{value:"100",children:"100"})]})]}),ve.size>0&&e.jsxs(e.Fragment,{children:[e.jsx(S,{variant:"outline",size:"sm",onClick:()=>be(new Set),children:"取消选择"}),e.jsxs(S,{variant:"destructive",size:"sm",onClick:()=>J(!0),children:[e.jsx(We,{className:"h-4 w-4 mr-1"}),"批量删除"]})]})]})]}),e.jsx("div",{className:"flex justify-end pt-4 border-t",children:e.jsxs(S,{variant:"outline",size:"sm",onClick:ze,disabled:m,children:[e.jsx(zt,{className:`h-4 w-4 mr-2 ${m?"animate-spin":""}`}),"刷新"]})})]})]}),e.jsxs(Fe,{children:[e.jsxs(ts,{children:[e.jsx(as,{children:"表情包列表"}),e.jsxs(et,{children:["共 ",g," 个表情包,当前第 ",f," 页"]})]}),e.jsxs(xs,{children:[n.length===0?e.jsx("div",{className:"text-center py-12 text-muted-foreground",children:"暂无数据"}):e.jsx("div",{className:`grid gap-3 ${R==="small"?"grid-cols-3 sm:grid-cols-4 md:grid-cols-6 lg:grid-cols-8 xl:grid-cols-10":R==="medium"?"grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-6 xl:grid-cols-8":"grid-cols-2 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5"}`,children:n.map(Q=>e.jsxs("div",{className:`group relative rounded-lg border bg-card overflow-hidden hover:ring-2 hover:ring-primary transition-all cursor-pointer ${ve.has(Q.id)?"ring-2 ring-primary bg-primary/5":""}`,onClick:()=>E(Q.id),children:[e.jsx("div",{className:`absolute top-1 left-1 z-10 transition-opacity ${ve.has(Q.id)?"opacity-100":"opacity-0 group-hover:opacity-100"}`,children:e.jsx("div",{className:`w-5 h-5 rounded-full border-2 flex items-center justify-center ${ve.has(Q.id)?"bg-primary border-primary text-primary-foreground":"bg-background/80 border-muted-foreground/50"}`,children:ve.has(Q.id)&&e.jsx(aa,{className:"h-3 w-3"})})}),e.jsxs("div",{className:"absolute top-1 right-1 z-10 flex flex-col gap-0.5",children:[Q.is_registered&&e.jsx(Qe,{variant:"default",className:"bg-green-600 text-[10px] px-1 py-0",children:"已注册"}),Q.is_banned&&e.jsx(Qe,{variant:"destructive",className:"text-[10px] px-1 py-0",children:"已封禁"})]}),e.jsx("div",{className:`aspect-square bg-muted flex items-center justify-center overflow-hidden ${R==="small"?"p-1":R==="medium"?"p-2":"p-3"}`,children:e.jsx(N1,{src:z1(Q.id),alt:"表情包"})}),e.jsxs("div",{className:`border-t bg-card ${R==="small"?"p-1":"p-2"}`,children:[e.jsxs("div",{className:"flex items-center justify-between gap-1 text-xs text-muted-foreground mb-1",children:[e.jsx(Qe,{variant:"outline",className:"text-[10px] px-1 py-0",children:Q.format.toUpperCase()}),e.jsxs("span",{className:"font-mono",children:[Q.usage_count,"次"]})]}),e.jsxs("div",{className:`flex gap-1 justify-center opacity-0 group-hover:opacity-100 transition-opacity ${R==="small"?"flex-wrap":""}`,children:[e.jsx(S,{variant:"ghost",size:"icon",className:"h-6 w-6",onClick:Ne=>{Ne.stopPropagation(),re(Q)},title:"编辑",children:e.jsx(nn,{className:"h-3 w-3"})}),e.jsx(S,{variant:"ghost",size:"icon",className:"h-6 w-6",onClick:Ne=>{Ne.stopPropagation(),ae(Q)},title:"详情",children:e.jsx(Ra,{className:"h-3 w-3"})}),!Q.is_registered&&e.jsx(S,{variant:"ghost",size:"icon",className:"h-6 w-6 text-green-600 hover:text-green-700",onClick:Ne=>{Ne.stopPropagation(),Te(Q)},title:"注册",children:e.jsx(aa,{className:"h-3 w-3"})}),!Q.is_banned&&e.jsx(S,{variant:"ghost",size:"icon",className:"h-6 w-6 text-orange-600 hover:text-orange-700",onClick:Ne=>{Ne.stopPropagation(),Le(Q)},title:"封禁",children:e.jsx(dy,{className:"h-3 w-3"})}),e.jsx(S,{variant:"ghost",size:"icon",className:"h-6 w-6 text-red-600 hover:text-red-700",onClick:Ne=>{Ne.stopPropagation(),F(Q)},title:"删除",children:e.jsx(We,{className:"h-3 w-3"})})]})]})]},Q.id))}),g>0&&e.jsxs("div",{className:"flex flex-col sm:flex-row items-center justify-between gap-4 mt-4",children:[e.jsxs("div",{className:"text-sm text-muted-foreground",children:["显示 ",(f-1)*j+1," 到"," ",Math.min(f*j,g)," 条,共 ",g," 条"]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(S,{variant:"outline",size:"sm",onClick:()=>p(1),disabled:f===1,className:"hidden sm:flex",children:e.jsx(lr,{className:"h-4 w-4"})}),e.jsxs(S,{variant:"outline",size:"sm",onClick:()=>p(Q=>Math.max(1,Q-1)),disabled:f===1,children:[e.jsx(il,{className:"h-4 w-4 sm:mr-1"}),e.jsx("span",{className:"hidden sm:inline",children:"上一页"})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(ie,{type:"number",value:q,onChange:Q=>se(Q.target.value),onKeyDown:Q=>Q.key==="Enter"&&Ye(),placeholder:f.toString(),className:"w-16 h-8 text-center",min:1,max:Math.ceil(g/j)}),e.jsx(S,{variant:"outline",size:"sm",onClick:Ye,disabled:!q,className:"h-8",children:"跳转"})]}),e.jsxs(S,{variant:"outline",size:"sm",onClick:()=>p(Q=>Q+1),disabled:f>=Math.ceil(g/j),children:[e.jsx("span",{className:"hidden sm:inline",children:"下一页"}),e.jsx(Ba,{className:"h-4 w-4 sm:ml-1"})]}),e.jsx(S,{variant:"outline",size:"sm",onClick:()=>p(Math.ceil(g/j)),disabled:f>=Math.ceil(g/j),className:"hidden sm:flex",children:e.jsx(nr,{className:"h-4 w-4"})})]})]})]})]}),e.jsx(R1,{emoji:I,open:A,onOpenChange:te}),e.jsx(L1,{emoji:I,open:fe,onOpenChange:je,onSuccess:()=>{ze(),ge()}}),e.jsx(U1,{open:me,onOpenChange:_e,onSuccess:()=>{ze(),ge()}})]})}),e.jsx(hs,{open:D,onOpenChange:J,children:e.jsxs(ls,{children:[e.jsxs(ns,{children:[e.jsx(is,{children:"确认批量删除"}),e.jsxs(cs,{children:["你确定要删除选中的 ",ve.size," 个表情包吗?此操作不可撤销。"]})]}),e.jsxs(rs,{children:[e.jsx(ds,{children:"取消"}),e.jsx(os,{onClick:xe,children:"确认删除"})]})]})}),e.jsx(qs,{open:pe,onOpenChange:he,children:e.jsxs(Ls,{children:[e.jsxs(Us,{children:[e.jsx(Bs,{children:"确认删除"}),e.jsx(Ps,{children:"确定要删除这个表情包吗?此操作无法撤销。"})]}),e.jsxs(st,{children:[e.jsx(S,{variant:"outline",onClick:()=>he(!1),children:"取消"}),e.jsx(S,{variant:"destructive",onClick:P,children:"删除"})]})]})})]})}function R1({emoji:n,open:r,onOpenChange:i}){if(!n)return null;const d=m=>m?new Date(m*1e3).toLocaleString("zh-CN"):"-";return e.jsx(qs,{open:r,onOpenChange:i,children:e.jsxs(Ls,{className:"max-w-2xl max-h-[90vh]",children:[e.jsx(Us,{children:e.jsx(Bs,{children:"表情包详情"})}),e.jsx(Ze,{className:"max-h-[calc(90vh-8rem)] pr-4",children:e.jsxs("div",{className:"space-y-4",children:[e.jsx("div",{className:"flex justify-center",children:e.jsx("div",{className:"w-32 h-32 bg-muted rounded-lg flex items-center justify-center overflow-hidden",children:e.jsx("img",{src:A1(n.id),alt:n.description||"表情包",className:"w-full h-full object-cover",onError:m=>{const x=m.target;x.style.display="none";const f=x.parentElement;f&&(f.innerHTML='')}})})}),e.jsxs("div",{className:"grid gap-4 sm:grid-cols-2",children:[e.jsxs("div",{children:[e.jsx(C,{className:"text-muted-foreground",children:"ID"}),e.jsx("div",{className:"mt-1 font-mono",children:n.id})]}),e.jsxs("div",{children:[e.jsx(C,{className:"text-muted-foreground",children:"格式"}),e.jsx("div",{className:"mt-1",children:e.jsx(Qe,{variant:"outline",children:n.format.toUpperCase()})})]})]}),e.jsxs("div",{children:[e.jsx(C,{className:"text-muted-foreground",children:"文件路径"}),e.jsx("div",{className:"mt-1 font-mono text-sm break-all bg-muted p-2 rounded",children:n.full_path})]}),e.jsxs("div",{children:[e.jsx(C,{className:"text-muted-foreground",children:"哈希值"}),e.jsx("div",{className:"mt-1 font-mono text-sm break-all bg-muted p-2 rounded",children:n.emoji_hash})]}),e.jsxs("div",{children:[e.jsx(C,{className:"text-muted-foreground",children:"描述"}),n.description?e.jsx("div",{className:"mt-1 rounded-lg border bg-muted/50 p-3",children:e.jsx(y1,{className:"prose-sm",children:n.description})}):e.jsx("div",{className:"mt-1 text-sm text-muted-foreground",children:"-"})]}),e.jsxs("div",{children:[e.jsx(C,{className:"text-muted-foreground",children:"情绪"}),e.jsx("div",{className:"mt-1",children:n.emotion?e.jsx("span",{className:"text-sm",children:n.emotion}):e.jsx("span",{className:"text-sm text-muted-foreground",children:"-"})})]}),e.jsxs("div",{className:"grid gap-4 sm:grid-cols-2",children:[e.jsxs("div",{children:[e.jsx(C,{className:"text-muted-foreground",children:"状态"}),e.jsxs("div",{className:"mt-2 flex gap-2",children:[n.is_registered&&e.jsx(Qe,{variant:"default",className:"bg-green-600",children:"已注册"}),n.is_banned&&e.jsx(Qe,{variant:"destructive",children:"已封禁"}),!n.is_registered&&!n.is_banned&&e.jsx(Qe,{variant:"outline",children:"未注册"})]})]}),e.jsxs("div",{children:[e.jsx(C,{className:"text-muted-foreground",children:"使用次数"}),e.jsx("div",{className:"mt-1 font-mono text-lg",children:n.usage_count})]})]}),e.jsxs("div",{className:"grid gap-4 sm:grid-cols-2",children:[e.jsxs("div",{children:[e.jsx(C,{className:"text-muted-foreground",children:"记录时间"}),e.jsx("div",{className:"mt-1 text-sm",children:d(n.record_time)})]}),e.jsxs("div",{children:[e.jsx(C,{className:"text-muted-foreground",children:"注册时间"}),e.jsx("div",{className:"mt-1 text-sm",children:d(n.register_time)})]})]}),e.jsxs("div",{children:[e.jsx(C,{className:"text-muted-foreground",children:"最后使用"}),e.jsx("div",{className:"mt-1 text-sm",children:d(n.last_used_time)})]})]})})]})})}function L1({emoji:n,open:r,onOpenChange:i,onSuccess:d}){const[m,x]=u.useState(""),[f,p]=u.useState(!1),[g,b]=u.useState(!1),[j,y]=u.useState(!1),{toast:N}=$s();u.useEffect(()=>{n&&(x(n.emotion||""),p(n.is_registered),b(n.is_banned))},[n]);const k=async()=>{if(n)try{y(!0);const w=m.split(/[,,]/).map(U=>U.trim()).filter(Boolean).join(",");await S1(n.id,{emotion:w||void 0,is_registered:f,is_banned:g}),N({title:"成功",description:"表情包信息已更新"}),i(!1),d()}catch(w){const U=w instanceof Error?w.message:"保存失败";N({title:"错误",description:U,variant:"destructive"})}finally{y(!1)}};return n?e.jsx(qs,{open:r,onOpenChange:i,children:e.jsxs(Ls,{className:"max-w-2xl",children:[e.jsxs(Us,{children:[e.jsx(Bs,{children:"编辑表情包"}),e.jsx(Ps,{children:"修改表情包的情绪和状态信息"})]}),e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{children:[e.jsx(C,{children:"情绪"}),e.jsx(Qs,{value:m,onChange:w=>x(w.target.value),placeholder:"输入情绪描述...",rows:2,className:"mt-1"}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:"输入情绪相关的文本描述"})]}),e.jsxs("div",{className:"grid gap-4 sm:grid-cols-2",children:[e.jsxs("div",{className:"flex items-center space-x-2",children:[e.jsx(mt,{id:"is_registered",checked:f,onCheckedChange:w=>{w===!0?(p(!0),b(!1)):p(!1)}}),e.jsx(C,{htmlFor:"is_registered",className:"cursor-pointer",children:"已注册"})]}),e.jsxs("div",{className:"flex items-center space-x-2",children:[e.jsx(mt,{id:"is_banned",checked:g,onCheckedChange:w=>{w===!0?(b(!0),p(!1)):b(!1)}}),e.jsx(C,{htmlFor:"is_banned",className:"cursor-pointer",children:"已封禁"})]})]})]}),e.jsxs(st,{children:[e.jsx(S,{variant:"outline",onClick:()=>i(!1),children:"取消"}),e.jsx(S,{onClick:k,disabled:j,children:j?"保存中...":"保存"})]})]})}):null}function U1({open:n,onOpenChange:r,onSuccess:i}){const[d,m]=u.useState("select"),[x,f]=u.useState([]),[p,g]=u.useState(null),[b,j]=u.useState(!1),{toast:y}=$s(),N=u.useMemo(()=>new Iy({id:"emoji-uploader",autoProceed:!1,restrictions:{maxFileSize:10485760,allowedFileTypes:["image/jpeg","image/png","image/gif","image/webp"],maxNumberOfFiles:20},locale:{pluralize:()=>0,strings:{addMoreFiles:"添加更多文件",addingMoreFiles:"正在添加更多文件",allowedFileTypes:"允许的文件类型:%{types}",cancel:"取消",closeModal:"关闭",complete:"完成",connectedToInternet:"已连接到互联网",copyLink:"复制链接",copyLinkToClipboardFallback:"复制下方链接",copyLinkToClipboardSuccess:"链接已复制到剪贴板",dashboardTitle:"选择文件",dashboardWindowTitle:"文件选择窗口(按 ESC 关闭)",done:"完成",dropHereOr:"拖放文件到这里或 %{browse}",dropHint:"将文件拖放到此处",dropPasteFiles:"将文件拖放到这里或 %{browseFiles}",dropPasteFolders:"将文件拖放到这里或 %{browseFolders}",dropPasteBoth:"将文件拖放到这里,%{browseFiles} 或 %{browseFolders}",dropPasteImportFiles:"将文件拖放到这里,%{browseFiles} 或从以下位置导入:",dropPasteImportFolders:"将文件拖放到这里,%{browseFolders} 或从以下位置导入:",dropPasteImportBoth:"将文件拖放到这里,%{browseFiles},%{browseFolders} 或从以下位置导入:",editFile:"编辑文件",editing:"正在编辑 %{file}",emptyFolderAdded:"未从空文件夹添加文件",exceedsSize:"%{file} 超过了最大允许大小 %{size}",failedToUpload:"上传 %{file} 失败",fileSource:"文件来源:%{name}",filesUploadedOfTotal:{0:"已上传 %{complete} / %{smart_count} 个文件",1:"已上传 %{complete} / %{smart_count} 个文件"},filter:"筛选",finishEditingFile:"完成编辑文件",folderAdded:{0:"已从 %{folder} 添加 %{smart_count} 个文件",1:"已从 %{folder} 添加 %{smart_count} 个文件"},generatingThumbnails:"正在生成缩略图...",import:"导入",importFiles:"从以下位置导入文件:",importFrom:"从 %{name} 导入",loading:"加载中...",logOut:"登出",myDevice:"我的设备",noFilesFound:"这里没有文件或文件夹",noInternetConnection:"无网络连接",openFolderNamed:"打开文件夹 %{name}",pause:"暂停",pauseUpload:"暂停上传",paused:"已暂停",poweredBy:"技术支持:%{uppy}",processingXFiles:{0:"正在处理 %{smart_count} 个文件",1:"正在处理 %{smart_count} 个文件"},recording:"录制中",removeFile:"移除文件",resetFilter:"重置筛选",resume:"继续",resumeUpload:"继续上传",retry:"重试",retryUpload:"重试上传",save:"保存",saveChanges:"保存更改",selectFileNamed:"选择文件 %{name}",selectX:{0:"选择 %{smart_count}",1:"选择 %{smart_count}"},smile:"笑一个!",startRecording:"开始录制视频",stopRecording:"停止录制视频",takePicture:"拍照",timedOut:"上传已停滞 %{seconds} 秒,正在中止。",upload:"下一步",uploadComplete:"上传完成",uploadFailed:"上传失败",uploadPaused:"上传已暂停",uploadXFiles:{0:"下一步(%{smart_count} 个文件)",1:"下一步(%{smart_count} 个文件)"},uploadXNewFiles:{0:"下一步(+%{smart_count} 个文件)",1:"下一步(+%{smart_count} 个文件)"},uploading:"正在上传",uploadingXFiles:{0:"正在上传 %{smart_count} 个文件",1:"正在上传 %{smart_count} 个文件"},xFilesSelected:{0:"已选择 %{smart_count} 个文件",1:"已选择 %{smart_count} 个文件"},xMoreFilesAdded:{0:"又添加了 %{smart_count} 个文件",1:"又添加了 %{smart_count} 个文件"},xTimeLeft:"剩余 %{time}",youCanOnlyUploadFileTypes:"您只能上传:%{types}",youCanOnlyUploadX:{0:"您只能上传 %{smart_count} 个文件",1:"您只能上传 %{smart_count} 个文件"},youHaveToAtLeastSelectX:{0:"您至少需要选择 %{smart_count} 个文件",1:"您至少需要选择 %{smart_count} 个文件"},browseFiles:"浏览文件",browseFolders:"浏览文件夹",cancelUpload:"取消上传",addMore:"添加更多",back:"返回",editFileWithFilename:"编辑文件 %{file}"}}}),[]);u.useEffect(()=>{const I=()=>{const T=N.getFiles();if(T.length===0)return;const A=T.map(te=>({id:te.id,name:te.name,previewUrl:te.preview||URL.createObjectURL(te.data),emotion:"",description:"",isRegistered:!0,file:te.data}));f(A),T.length===1?(g(A[0].id),m("edit-single")):m("edit-multiple")};return N.on("upload",I),()=>{N.off("upload",I)}},[N]),u.useEffect(()=>{n||(N.cancelAll(),m("select"),f([]),g(null),j(!1))},[n,N]);const k=u.useCallback((I,T)=>{f(A=>A.map(te=>te.id===I?{...te,...T}:te))},[]),w=u.useCallback(I=>I.emotion.trim().length>0,[]),U=u.useMemo(()=>x.length>0&&x.every(w),[x,w]),O=u.useMemo(()=>x.find(I=>I.id===p)||null,[x,p]),B=u.useCallback(()=>{(d==="edit-single"||d==="edit-multiple")&&(m("select"),f([]),g(null))},[d]),Y=u.useCallback(async()=>{if(!U){y({title:"请填写必填项",description:"每个表情包的情感标签都是必填的",variant:"destructive"});return}j(!0);const I=localStorage.getItem("access-token")||"";let T=0,A=0;try{for(const te of x){const fe=new FormData;fe.append("file",te.file),fe.append("emotion",te.emotion),fe.append("description",te.description),fe.append("is_registered",te.isRegistered.toString());try{(await fetch(D1(),{method:"POST",headers:{Authorization:`Bearer ${I}`},body:fe})).ok?T++:A++}catch{A++}}A===0?(y({title:"上传成功",description:`成功上传 ${T} 个表情包`}),r(!1),i()):(y({title:"部分上传失败",description:`成功 ${T} 个,失败 ${A} 个`,variant:"destructive"}),i())}finally{j(!1)}},[U,x,y,r,i]),L=()=>e.jsx("div",{className:"space-y-4",children:e.jsx("div",{className:"border rounded-lg overflow-hidden w-full",children:e.jsx(b1,{uppy:N,proudlyDisplayPoweredByUppy:!1,hideProgressDetails:!0,height:350,width:"100%",theme:"auto",note:"支持 JPG、PNG、GIF、WebP 格式,最多 20 个文件"})})}),z=()=>{const I=x[0];return I?e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"flex items-center gap-4",children:[e.jsxs(S,{variant:"ghost",size:"sm",onClick:B,children:[e.jsx(er,{className:"h-4 w-4 mr-1"}),"返回"]}),e.jsx("span",{className:"text-sm text-muted-foreground",children:"编辑表情包信息"})]}),e.jsxs("div",{className:"flex gap-6",children:[e.jsxs("div",{className:"flex-shrink-0",children:[e.jsx("div",{className:"w-32 h-32 rounded-lg border overflow-hidden bg-muted flex items-center justify-center",children:e.jsx("img",{src:I.previewUrl,alt:I.name,className:"max-w-full max-h-full object-contain"})}),e.jsx("p",{className:"text-xs text-muted-foreground mt-2 text-center truncate max-w-32",children:I.name})]}),e.jsxs("div",{className:"flex-1 space-y-4",children:[e.jsxs("div",{className:"space-y-2",children:[e.jsxs(C,{htmlFor:"single-emotion",children:["情感标签 ",e.jsx("span",{className:"text-destructive",children:"*"})]}),e.jsx(ie,{id:"single-emotion",value:I.emotion,onChange:T=>k(I.id,{emotion:T.target.value}),placeholder:"多个标签用逗号分隔,如:开心,高兴",className:I.emotion.trim()?"":"border-destructive"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"用于情感匹配,多个标签用逗号分隔"})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(C,{htmlFor:"single-description",children:"描述"}),e.jsx(ie,{id:"single-description",value:I.description,onChange:T=>k(I.id,{description:T.target.value}),placeholder:"输入表情包描述..."})]}),e.jsxs("div",{className:"flex items-center space-x-2",children:[e.jsx(mt,{id:"single-is-registered",checked:I.isRegistered,onCheckedChange:T=>k(I.id,{isRegistered:T===!0})}),e.jsx(C,{htmlFor:"single-is-registered",className:"cursor-pointer",children:"上传后立即注册(可被麦麦使用)"})]})]})]}),e.jsx(st,{children:e.jsx(S,{onClick:Y,disabled:!U||b,children:b?"上传中...":"上传"})})]}):null},K=()=>{const I=x.filter(w).length,T=x.length;return e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"flex items-center gap-4",children:[e.jsxs(S,{variant:"ghost",size:"sm",onClick:B,children:[e.jsx(er,{className:"h-4 w-4 mr-1"}),"返回"]}),e.jsxs("span",{className:"text-sm text-muted-foreground",children:["编辑表情包信息(",I,"/",T," 已完成)"]})]}),e.jsx(Qe,{variant:U?"default":"secondary",children:U?e.jsxs(e.Fragment,{children:[e.jsx(Qt,{className:"h-3 w-3 mr-1"}),"全部完成"]}):e.jsxs(e.Fragment,{children:[e.jsx(rl,{className:"h-3 w-3 mr-1"}),"未完成"]})})]}),e.jsxs("div",{className:"grid grid-cols-2 gap-4",children:[e.jsx(Ze,{className:"h-[350px] pr-2",children:e.jsx("div",{className:"space-y-2",children:x.map(A=>{const te=w(A),fe=p===A.id;return e.jsxs("div",{onClick:()=>g(A.id),className:` - flex items-center gap-3 p-3 rounded-lg border-2 cursor-pointer transition-all - ${fe?"ring-2 ring-primary":""} - ${te?"border-green-500 bg-green-50 dark:bg-green-950/20":"border-border hover:border-muted-foreground/50"} - `,children:[e.jsx("div",{className:"w-12 h-12 rounded border overflow-hidden bg-muted flex-shrink-0 flex items-center justify-center",children:e.jsx("img",{src:A.previewUrl,alt:A.name,className:"max-w-full max-h-full object-contain"})}),e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsx("p",{className:"text-sm font-medium truncate",children:A.name}),e.jsx("p",{className:"text-xs text-muted-foreground truncate",children:A.emotion||"未填写情感标签"})]}),te?e.jsx(aa,{className:"h-5 w-5 text-green-500 flex-shrink-0"}):e.jsx("div",{className:"h-5 w-5 rounded-full border-2 border-muted-foreground/30 flex-shrink-0"})]},A.id)})})}),e.jsx("div",{className:"border rounded-lg p-4",children:O?e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("div",{className:"w-16 h-16 rounded border overflow-hidden bg-muted flex items-center justify-center",children:e.jsx("img",{src:O.previewUrl,alt:O.name,className:"max-w-full max-h-full object-contain"})}),e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsx("p",{className:"font-medium truncate",children:O.name}),w(O)&&e.jsxs(Qe,{variant:"outline",className:"text-green-600 border-green-600",children:[e.jsx(Qt,{className:"h-3 w-3 mr-1"}),"已完成"]})]})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsxs(C,{htmlFor:"multi-emotion",children:["情感标签 ",e.jsx("span",{className:"text-destructive",children:"*"})]}),e.jsx(ie,{id:"multi-emotion",value:O.emotion,onChange:A=>k(O.id,{emotion:A.target.value}),placeholder:"多个标签用逗号分隔,如:开心,高兴",className:O.emotion.trim()?"":"border-destructive"})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(C,{htmlFor:"multi-description",children:"描述"}),e.jsx(ie,{id:"multi-description",value:O.description,onChange:A=>k(O.id,{description:A.target.value}),placeholder:"输入表情包描述..."})]}),e.jsxs("div",{className:"flex items-center space-x-2",children:[e.jsx(mt,{id:"multi-is-registered",checked:O.isRegistered,onCheckedChange:A=>k(O.id,{isRegistered:A===!0})}),e.jsx(C,{htmlFor:"multi-is-registered",className:"cursor-pointer text-sm",children:"上传后立即注册"})]})]}):e.jsx("div",{className:"h-full flex items-center justify-center text-muted-foreground",children:e.jsxs("div",{className:"text-center",children:[e.jsx(gg,{className:"h-12 w-12 mx-auto mb-2 opacity-50"}),e.jsx("p",{children:"点击左侧卡片编辑"})]})})})]}),e.jsx(st,{children:e.jsx(S,{onClick:Y,disabled:!U||b,children:b?"上传中...":`上传全部 (${T})`})})]})};return e.jsx(qs,{open:n,onOpenChange:r,children:e.jsxs(Ls,{className:"max-w-3xl max-h-[90vh] overflow-hidden",children:[e.jsxs(Us,{children:[e.jsxs(Bs,{className:"flex items-center gap-2",children:[e.jsx(oi,{className:"h-5 w-5"}),d==="select"&&"上传表情包 - 选择文件",d==="edit-single"&&"上传表情包 - 填写信息",d==="edit-multiple"&&"上传表情包 - 批量编辑"]}),e.jsxs(Ps,{children:[d==="select"&&"支持 JPG、PNG、GIF、WebP 格式,单个文件最大 10MB,可同时上传多个文件",d==="edit-single"&&"请填写表情包的情感标签(必填)和描述",d==="edit-multiple"&&"点击左侧卡片编辑每个表情包的信息,情感标签为必填项"]})]}),e.jsxs("div",{className:"overflow-y-auto pr-1",children:[d==="select"&&L(),d==="edit-single"&&z(),d==="edit-multiple"&&K()]})]})})}const Bl="/api/webui/expression";async function B1(){const n=await Se(`${Bl}/chats`,{});if(!n.ok){const r=await n.json();throw new Error(r.detail||"获取聊天列表失败")}return n.json()}async function H1(n){const r=new URLSearchParams;n.page&&r.append("page",n.page.toString()),n.page_size&&r.append("page_size",n.page_size.toString()),n.search&&r.append("search",n.search),n.chat_id&&r.append("chat_id",n.chat_id);const i=await Se(`${Bl}/list?${r}`,{});if(!i.ok){const d=await i.json();throw new Error(d.detail||"获取表达方式列表失败")}return i.json()}async function q1(n){const r=await Se(`${Bl}/${n}`,{});if(!r.ok){const i=await r.json();throw new Error(i.detail||"获取表达方式详情失败")}return r.json()}async function G1(n){const r=await Se(`${Bl}/`,{method:"POST",body:JSON.stringify(n)});if(!r.ok){const i=await r.json();throw new Error(i.detail||"创建表达方式失败")}return r.json()}async function $1(n,r){const i=await Se(`${Bl}/${n}`,{method:"PATCH",body:JSON.stringify(r)});if(!i.ok){const d=await i.json();throw new Error(d.detail||"更新表达方式失败")}return i.json()}async function F1(n){const r=await Se(`${Bl}/${n}`,{method:"DELETE"});if(!r.ok){const i=await r.json();throw new Error(i.detail||"删除表达方式失败")}return r.json()}async function V1(n){const r=await Se(`${Bl}/batch/delete`,{method:"POST",body:JSON.stringify({ids:n})});if(!r.ok){const i=await r.json();throw new Error(i.detail||"批量删除表达方式失败")}return r.json()}async function Q1(){const n=await Se(`${Bl}/stats/summary`,{});if(!n.ok){const r=await n.json();throw new Error(r.detail||"获取统计数据失败")}return n.json()}function I1(){const[n,r]=u.useState([]),[i,d]=u.useState(!0),[m,x]=u.useState(0),[f,p]=u.useState(1),[g,b]=u.useState(20),[j,y]=u.useState(""),[N,k]=u.useState(null),[w,U]=u.useState(!1),[O,B]=u.useState(!1),[Y,L]=u.useState(!1),[z,K]=u.useState(null),[I,T]=u.useState(new Set),[A,te]=u.useState(!1),[fe,je]=u.useState(""),[pe,he]=u.useState({total:0,recent_7days:0,chat_count:0,top_chats:{}}),[ve,be]=u.useState([]),[D,J]=u.useState(new Map),{toast:q}=$s(),se=async()=>{try{d(!0);const P=await H1({page:f,page_size:g,search:j||void 0});r(P.data),x(P.total)}catch(P){q({title:"加载失败",description:P instanceof Error?P.message:"无法加载表达方式",variant:"destructive"})}finally{d(!1)}},R=async()=>{try{const P=await Q1();P?.data&&he(P.data)}catch(P){console.error("加载统计数据失败:",P)}},ue=async()=>{try{const P=await B1();if(P?.data){be(P.data);const Te=new Map;P.data.forEach(Le=>{Te.set(Le.chat_id,Le.chat_name)}),J(Te)}}catch(P){console.error("加载聊天列表失败:",P)}},me=P=>D.get(P)||P;u.useEffect(()=>{se(),R(),ue()},[f,g,j]);const _e=async P=>{try{const Te=await q1(P.id);k(Te.data),U(!0)}catch(Te){q({title:"加载详情失败",description:Te instanceof Error?Te.message:"无法加载表达方式详情",variant:"destructive"})}},Ce=P=>{k(P),B(!0)},ze=async P=>{try{await F1(P.id),q({title:"删除成功",description:`已删除表达方式: ${P.situation}`}),K(null),se(),R()}catch(Te){q({title:"删除失败",description:Te instanceof Error?Te.message:"无法删除表达方式",variant:"destructive"})}},ge=P=>{const Te=new Set(I);Te.has(P)?Te.delete(P):Te.add(P),T(Te)},ae=()=>{I.size===n.length&&n.length>0?T(new Set):T(new Set(n.map(P=>P.id)))},re=async()=>{try{await V1(Array.from(I)),q({title:"批量删除成功",description:`已删除 ${I.size} 个表达方式`}),T(new Set),te(!1),se(),R()}catch(P){q({title:"批量删除失败",description:P instanceof Error?P.message:"无法批量删除表达方式",variant:"destructive"})}},F=()=>{const P=parseInt(fe),Te=Math.ceil(m/g);P>=1&&P<=Te?(p(P),je("")):q({title:"无效的页码",description:`请输入1-${Te}之间的页码`,variant:"destructive"})};return e.jsxs("div",{className:"h-[calc(100vh-4rem)] flex flex-col p-4 sm:p-6",children:[e.jsx("div",{className:"mb-4 sm:mb-6",children:e.jsxs("div",{className:"flex flex-col sm:flex-row sm:items-center justify-between gap-4",children:[e.jsxs("div",{children:[e.jsxs("h1",{className:"text-2xl sm:text-3xl font-bold flex items-center gap-2",children:[e.jsx(Rl,{className:"h-8 w-8",strokeWidth:2}),"表达方式管理"]}),e.jsx("p",{className:"text-muted-foreground mt-1 text-sm sm:text-base",children:"管理麦麦的表达方式和话术模板"})]}),e.jsxs(S,{onClick:()=>L(!0),className:"gap-2",children:[e.jsx(dt,{className:"h-4 w-4"}),"新增表达方式"]})]})}),e.jsx(Ze,{className:"flex-1",children:e.jsxs("div",{className:"space-y-4 sm:space-y-6 pr-4",children:[e.jsxs("div",{className:"grid grid-cols-1 sm:grid-cols-3 gap-4",children:[e.jsxs("div",{className:"rounded-lg border bg-card p-4",children:[e.jsx("div",{className:"text-sm text-muted-foreground",children:"总数量"}),e.jsx("div",{className:"text-2xl font-bold mt-1",children:pe.total})]}),e.jsxs("div",{className:"rounded-lg border bg-card p-4",children:[e.jsx("div",{className:"text-sm text-muted-foreground",children:"近7天新增"}),e.jsx("div",{className:"text-2xl font-bold mt-1 text-green-600",children:pe.recent_7days})]}),e.jsxs("div",{className:"rounded-lg border bg-card p-4",children:[e.jsx("div",{className:"text-sm text-muted-foreground",children:"关联聊天数"}),e.jsx("div",{className:"text-2xl font-bold mt-1 text-blue-600",children:pe.chat_count})]})]}),e.jsxs("div",{className:"rounded-lg border bg-card p-4",children:[e.jsx(C,{htmlFor:"search",children:"搜索"}),e.jsx("div",{className:"flex flex-col sm:flex-row gap-2 mt-1.5",children:e.jsxs("div",{className:"flex-1 relative",children:[e.jsx(Mt,{className:"absolute left-2.5 top-2.5 h-4 w-4 text-muted-foreground"}),e.jsx(ie,{id:"search",placeholder:"搜索情境、风格或上下文...",value:j,onChange:P=>y(P.target.value),className:"pl-9"})]})}),e.jsxs("div",{className:"flex flex-col sm:flex-row items-start sm:items-center justify-between gap-3 mt-4 pt-4 border-t",children:[e.jsx("div",{className:"flex items-center gap-2 text-sm text-muted-foreground",children:I.size>0&&e.jsxs("span",{children:["已选择 ",I.size," 个表达方式"]})}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(C,{htmlFor:"page-size",className:"text-sm whitespace-nowrap",children:"每页显示"}),e.jsxs(Ue,{value:g.toString(),onValueChange:P=>{b(parseInt(P)),p(1),T(new Set)},children:[e.jsx(Oe,{id:"page-size",className:"w-20",children:e.jsx(Be,{})}),e.jsxs(Re,{children:[e.jsx(le,{value:"10",children:"10"}),e.jsx(le,{value:"20",children:"20"}),e.jsx(le,{value:"50",children:"50"}),e.jsx(le,{value:"100",children:"100"})]})]}),I.size>0&&e.jsxs(e.Fragment,{children:[e.jsx(S,{variant:"outline",size:"sm",onClick:()=>T(new Set),children:"取消选择"}),e.jsxs(S,{variant:"destructive",size:"sm",onClick:()=>te(!0),children:[e.jsx(We,{className:"h-4 w-4 mr-1"}),"批量删除"]})]})]})]})]}),e.jsxs("div",{className:"rounded-lg border bg-card",children:[e.jsx("div",{className:"hidden md:block",children:e.jsxs(rn,{children:[e.jsx(cn,{children:e.jsxs(ut,{children:[e.jsx(Xe,{className:"w-12",children:e.jsx(mt,{checked:I.size===n.length&&n.length>0,onCheckedChange:ae})}),e.jsx(Xe,{children:"情境"}),e.jsx(Xe,{children:"风格"}),e.jsx(Xe,{children:"聊天"}),e.jsx(Xe,{className:"text-right",children:"操作"})]})}),e.jsx(on,{children:i?e.jsx(ut,{children:e.jsx(Ve,{colSpan:5,className:"text-center py-8 text-muted-foreground",children:"加载中..."})}):n.length===0?e.jsx(ut,{children:e.jsx(Ve,{colSpan:5,className:"text-center py-8 text-muted-foreground",children:"暂无数据"})}):n.map(P=>e.jsxs(ut,{children:[e.jsx(Ve,{children:e.jsx(mt,{checked:I.has(P.id),onCheckedChange:()=>ge(P.id)})}),e.jsx(Ve,{className:"font-medium max-w-xs truncate",children:P.situation}),e.jsx(Ve,{className:"max-w-xs truncate",children:P.style}),e.jsx(Ve,{className:"max-w-[200px] truncate",title:me(P.chat_id),style:{wordBreak:"keep-all"},children:e.jsx("span",{className:"whitespace-nowrap overflow-hidden text-ellipsis block",children:me(P.chat_id)})}),e.jsx(Ve,{className:"text-right",children:e.jsxs("div",{className:"flex justify-end gap-2",children:[e.jsxs(S,{variant:"default",size:"sm",onClick:()=>Ce(P),children:[e.jsx(nn,{className:"h-4 w-4 mr-1"}),"编辑"]}),e.jsx(S,{variant:"outline",size:"icon",className:"h-8 w-8",onClick:()=>_e(P),title:"查看详情",children:e.jsx(Rt,{className:"h-4 w-4"})}),e.jsxs(S,{size:"sm",onClick:()=>K(P),className:"bg-red-600 hover:bg-red-700 text-white",children:[e.jsx(We,{className:"h-4 w-4 mr-1"}),"删除"]})]})})]},P.id))})]})}),e.jsx("div",{className:"md:hidden space-y-3 p-4",children:i?e.jsx("div",{className:"text-center py-8 text-muted-foreground",children:"加载中..."}):n.length===0?e.jsx("div",{className:"text-center py-8 text-muted-foreground",children:"暂无数据"}):n.map(P=>e.jsxs("div",{className:"rounded-lg border bg-card p-4 space-y-3 overflow-hidden",children:[e.jsxs("div",{className:"flex items-start gap-3",children:[e.jsx(mt,{checked:I.has(P.id),onCheckedChange:()=>ge(P.id),className:"mt-1"}),e.jsxs("div",{className:"min-w-0 flex-1 overflow-hidden space-y-2",children:[e.jsxs("div",{children:[e.jsx("div",{className:"text-xs text-muted-foreground mb-1",children:"情境"}),e.jsx("h3",{className:"font-semibold text-sm line-clamp-2 w-full break-all",title:P.situation,children:P.situation})]}),e.jsxs("div",{children:[e.jsx("div",{className:"text-xs text-muted-foreground mb-1",children:"风格"}),e.jsx("p",{className:"text-sm line-clamp-2 w-full break-all",title:P.style,children:P.style})]})]})]}),e.jsxs("div",{className:"text-sm",children:[e.jsx("div",{className:"text-xs text-muted-foreground mb-1",children:"聊天"}),e.jsx("p",{className:"text-sm truncate",title:me(P.chat_id),style:{wordBreak:"keep-all"},children:me(P.chat_id)})]}),e.jsxs("div",{className:"flex flex-wrap gap-1 pt-2 border-t overflow-hidden",children:[e.jsxs(S,{variant:"outline",size:"sm",onClick:()=>Ce(P),className:"text-xs px-2 py-1 h-auto flex-shrink-0",children:[e.jsx(nn,{className:"h-3 w-3 mr-1"}),"编辑"]}),e.jsx(S,{variant:"outline",size:"sm",onClick:()=>_e(P),className:"text-xs px-2 py-1 h-auto flex-shrink-0",children:e.jsx(Rt,{className:"h-3 w-3"})}),e.jsxs(S,{variant:"outline",size:"sm",onClick:()=>K(P),className:"text-xs px-2 py-1 h-auto flex-shrink-0 text-destructive hover:text-destructive",children:[e.jsx(We,{className:"h-3 w-3 mr-1"}),"删除"]})]})]},P.id))}),m>0&&e.jsxs("div",{className:"flex flex-col sm:flex-row items-center justify-between gap-4 px-4 py-3 border-t",children:[e.jsxs("div",{className:"text-sm text-muted-foreground",children:["共 ",m," 条记录,第 ",f," / ",Math.ceil(m/g)," 页"]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(S,{variant:"outline",size:"sm",onClick:()=>p(1),disabled:f===1,className:"hidden sm:flex",children:e.jsx(lr,{className:"h-4 w-4"})}),e.jsxs(S,{variant:"outline",size:"sm",onClick:()=>p(f-1),disabled:f===1,children:[e.jsx(il,{className:"h-4 w-4 sm:mr-1"}),e.jsx("span",{className:"hidden sm:inline",children:"上一页"})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(ie,{type:"number",value:fe,onChange:P=>je(P.target.value),onKeyDown:P=>P.key==="Enter"&&F(),placeholder:f.toString(),className:"w-16 h-8 text-center",min:1,max:Math.ceil(m/g)}),e.jsx(S,{variant:"outline",size:"sm",onClick:F,disabled:!fe,className:"h-8",children:"跳转"})]}),e.jsxs(S,{variant:"outline",size:"sm",onClick:()=>p(f+1),disabled:f>=Math.ceil(m/g),children:[e.jsx("span",{className:"hidden sm:inline",children:"下一页"}),e.jsx(Ba,{className:"h-4 w-4 sm:ml-1"})]}),e.jsx(S,{variant:"outline",size:"sm",onClick:()=>p(Math.ceil(m/g)),disabled:f>=Math.ceil(m/g),className:"hidden sm:flex",children:e.jsx(nr,{className:"h-4 w-4"})})]})]})]})]})}),e.jsx(Y1,{expression:N,open:w,onOpenChange:U,chatNameMap:D}),e.jsx(K1,{open:Y,onOpenChange:L,chatList:ve,onSuccess:()=>{se(),R(),L(!1)}}),e.jsx(X1,{expression:N,open:O,onOpenChange:B,chatList:ve,onSuccess:()=>{se(),R(),B(!1)}}),e.jsx(hs,{open:!!z,onOpenChange:()=>K(null),children:e.jsxs(ls,{children:[e.jsxs(ns,{children:[e.jsx(is,{children:"确认删除"}),e.jsxs(cs,{children:['确定要删除表达方式 "',z?.situation,'" 吗? 此操作不可撤销。']})]}),e.jsxs(rs,{children:[e.jsx(ds,{children:"取消"}),e.jsx(os,{onClick:()=>z&&ze(z),className:"bg-destructive text-destructive-foreground hover:bg-destructive/90",children:"删除"})]})]})}),e.jsx(J1,{open:A,onOpenChange:te,onConfirm:re,count:I.size})]})}function Y1({expression:n,open:r,onOpenChange:i,chatNameMap:d}){if(!n)return null;const m=f=>f?new Date(f*1e3).toLocaleString("zh-CN"):"-",x=f=>d.get(f)||f;return e.jsx(qs,{open:r,onOpenChange:i,children:e.jsxs(Ls,{className:"max-w-2xl max-h-[80vh] overflow-y-auto",children:[e.jsxs(Us,{children:[e.jsx(Bs,{children:"表达方式详情"}),e.jsx(Ps,{children:"查看表达方式的完整信息"})]}),e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"grid grid-cols-2 gap-4",children:[e.jsx(si,{label:"情境",value:n.situation}),e.jsx(si,{label:"风格",value:n.style}),e.jsx(si,{label:"聊天",value:x(n.chat_id)}),e.jsx(si,{icon:sr,label:"记录ID",value:n.id.toString(),mono:!0})]}),e.jsx("div",{className:"grid grid-cols-2 gap-4",children:e.jsx(si,{icon:Pn,label:"创建时间",value:m(n.create_date)})})]}),e.jsx(st,{children:e.jsx(S,{onClick:()=>i(!1),children:"关闭"})})]})})}function si({icon:n,label:r,value:i,mono:d=!1}){return e.jsxs("div",{className:"space-y-1",children:[e.jsxs(C,{className:"text-xs text-muted-foreground flex items-center gap-1",children:[n&&e.jsx(n,{className:"h-3 w-3"}),r]}),e.jsx("div",{className:$("text-sm",d&&"font-mono",!i&&"text-muted-foreground"),children:i||"-"})]})}function K1({open:n,onOpenChange:r,chatList:i,onSuccess:d}){const[m,x]=u.useState({situation:"",style:"",chat_id:""}),[f,p]=u.useState(!1),{toast:g}=$s(),b=async()=>{if(!m.situation||!m.style||!m.chat_id){g({title:"验证失败",description:"请填写必填字段:情境、风格和聊天",variant:"destructive"});return}try{p(!0),await G1(m),g({title:"创建成功",description:"表达方式已创建"}),x({situation:"",style:"",chat_id:""}),d()}catch(j){g({title:"创建失败",description:j instanceof Error?j.message:"无法创建表达方式",variant:"destructive"})}finally{p(!1)}};return e.jsx(qs,{open:n,onOpenChange:r,children:e.jsxs(Ls,{className:"max-w-2xl max-h-[80vh] overflow-y-auto",children:[e.jsxs(Us,{children:[e.jsx(Bs,{children:"新增表达方式"}),e.jsx(Ps,{children:"创建新的表达方式记录"})]}),e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"grid grid-cols-2 gap-4",children:[e.jsxs("div",{className:"space-y-2",children:[e.jsxs(C,{htmlFor:"situation",children:["情境 ",e.jsx("span",{className:"text-destructive",children:"*"})]}),e.jsx(ie,{id:"situation",value:m.situation,onChange:j=>x({...m,situation:j.target.value}),placeholder:"描述使用场景"})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsxs(C,{htmlFor:"style",children:["风格 ",e.jsx("span",{className:"text-destructive",children:"*"})]}),e.jsx(ie,{id:"style",value:m.style,onChange:j=>x({...m,style:j.target.value}),placeholder:"描述表达风格"})]})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsxs(C,{htmlFor:"chat_id",children:["聊天 ",e.jsx("span",{className:"text-destructive",children:"*"})]}),e.jsxs(Ue,{value:m.chat_id,onValueChange:j=>x({...m,chat_id:j}),children:[e.jsx(Oe,{children:e.jsx(Be,{placeholder:"选择关联的聊天"})}),e.jsx(Re,{children:i.map(j=>e.jsx(le,{value:j.chat_id,children:e.jsxs("span",{className:"truncate",style:{wordBreak:"keep-all"},children:[j.chat_name,j.is_group&&e.jsx("span",{className:"text-muted-foreground ml-1",children:"(群聊)"})]})},j.chat_id))})]})]})]}),e.jsxs(st,{children:[e.jsx(S,{variant:"outline",onClick:()=>r(!1),children:"取消"}),e.jsx(S,{onClick:b,disabled:f,children:f?"创建中...":"创建"})]})]})})}function X1({expression:n,open:r,onOpenChange:i,chatList:d,onSuccess:m}){const[x,f]=u.useState({}),[p,g]=u.useState(!1),{toast:b}=$s();u.useEffect(()=>{n&&f({situation:n.situation,style:n.style,chat_id:n.chat_id})},[n]);const j=async()=>{if(n)try{g(!0),await $1(n.id,x),b({title:"保存成功",description:"表达方式已更新"}),m()}catch(y){b({title:"保存失败",description:y instanceof Error?y.message:"无法更新表达方式",variant:"destructive"})}finally{g(!1)}};return n?e.jsx(qs,{open:r,onOpenChange:i,children:e.jsxs(Ls,{className:"max-w-2xl max-h-[80vh] overflow-y-auto",children:[e.jsxs(Us,{children:[e.jsx(Bs,{children:"编辑表达方式"}),e.jsx(Ps,{children:"修改表达方式的信息"})]}),e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"grid grid-cols-2 gap-4",children:[e.jsxs("div",{className:"space-y-2",children:[e.jsx(C,{htmlFor:"edit_situation",children:"情境"}),e.jsx(ie,{id:"edit_situation",value:x.situation||"",onChange:y=>f({...x,situation:y.target.value}),placeholder:"描述使用场景"})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(C,{htmlFor:"edit_style",children:"风格"}),e.jsx(ie,{id:"edit_style",value:x.style||"",onChange:y=>f({...x,style:y.target.value}),placeholder:"描述表达风格"})]})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(C,{htmlFor:"edit_chat_id",children:"聊天"}),e.jsxs(Ue,{value:x.chat_id||"",onValueChange:y=>f({...x,chat_id:y}),children:[e.jsx(Oe,{children:e.jsx(Be,{placeholder:"选择关联的聊天"})}),e.jsx(Re,{children:d.map(y=>e.jsx(le,{value:y.chat_id,children:e.jsxs("span",{className:"truncate",style:{wordBreak:"keep-all"},children:[y.chat_name,y.is_group&&e.jsx("span",{className:"text-muted-foreground ml-1",children:"(群聊)"})]})},y.chat_id))})]})]})]}),e.jsxs(st,{children:[e.jsx(S,{variant:"outline",onClick:()=>i(!1),children:"取消"}),e.jsx(S,{onClick:j,disabled:p,children:p?"保存中...":"保存"})]})]})}):null}function J1({open:n,onOpenChange:r,onConfirm:i,count:d}){return e.jsx(hs,{open:n,onOpenChange:r,children:e.jsxs(ls,{children:[e.jsxs(ns,{children:[e.jsx(is,{children:"确认批量删除"}),e.jsxs(cs,{children:["您即将删除 ",d," 个表达方式,此操作无法撤销。确定要继续吗?"]})]}),e.jsxs(rs,{children:[e.jsx(ds,{children:"取消"}),e.jsx(os,{onClick:i,className:"bg-destructive text-destructive-foreground hover:bg-destructive/90",children:"确认删除"})]})]})})}const cl="/api/webui/jargon";async function Z1(){const n=await Se(`${cl}/chats`,{});if(!n.ok){const r=await n.json();throw new Error(r.detail||"获取聊天列表失败")}return n.json()}async function P1(n){const r=new URLSearchParams;n.page&&r.append("page",n.page.toString()),n.page_size&&r.append("page_size",n.page_size.toString()),n.search&&r.append("search",n.search),n.chat_id&&r.append("chat_id",n.chat_id),n.is_jargon!==void 0&&n.is_jargon!==null&&r.append("is_jargon",n.is_jargon.toString()),n.is_global!==void 0&&r.append("is_global",n.is_global.toString());const i=await Se(`${cl}/list?${r}`,{});if(!i.ok){const d=await i.json();throw new Error(d.detail||"获取黑话列表失败")}return i.json()}async function W1(n){const r=await Se(`${cl}/${n}`,{});if(!r.ok){const i=await r.json();throw new Error(i.detail||"获取黑话详情失败")}return r.json()}async function e2(n){const r=await Se(`${cl}/`,{method:"POST",body:JSON.stringify(n)});if(!r.ok){const i=await r.json();throw new Error(i.detail||"创建黑话失败")}return r.json()}async function s2(n,r){const i=await Se(`${cl}/${n}`,{method:"PATCH",body:JSON.stringify(r)});if(!i.ok){const d=await i.json();throw new Error(d.detail||"更新黑话失败")}return i.json()}async function t2(n){const r=await Se(`${cl}/${n}`,{method:"DELETE"});if(!r.ok){const i=await r.json();throw new Error(i.detail||"删除黑话失败")}return r.json()}async function a2(n){const r=await Se(`${cl}/batch/delete`,{method:"POST",body:JSON.stringify({ids:n})});if(!r.ok){const i=await r.json();throw new Error(i.detail||"批量删除黑话失败")}return r.json()}async function l2(){const n=await Se(`${cl}/stats/summary`,{});if(!n.ok){const r=await n.json();throw new Error(r.detail||"获取黑话统计失败")}return n.json()}async function n2(n,r){const i=new URLSearchParams;n.forEach(m=>i.append("ids",m.toString())),i.append("is_jargon",r.toString());const d=await Se(`${cl}/batch/set-jargon?${i}`,{method:"POST"});if(!d.ok){const m=await d.json();throw new Error(m.detail||"批量设置黑话状态失败")}return d.json()}function r2(){const[n,r]=u.useState([]),[i,d]=u.useState(!0),[m,x]=u.useState(0),[f,p]=u.useState(1),[g,b]=u.useState(20),[j,y]=u.useState(""),[N,k]=u.useState("all"),[w,U]=u.useState("all"),[O,B]=u.useState(null),[Y,L]=u.useState(!1),[z,K]=u.useState(!1),[I,T]=u.useState(!1),[A,te]=u.useState(null),[fe,je]=u.useState(new Set),[pe,he]=u.useState(!1),[ve,be]=u.useState(""),[D,J]=u.useState({total:0,confirmed_jargon:0,confirmed_not_jargon:0,pending:0,global_count:0,complete_count:0,chat_count:0,top_chats:{}}),[q,se]=u.useState([]),{toast:R}=$s(),ue=async()=>{try{d(!0);const E=await P1({page:f,page_size:g,search:j||void 0,chat_id:N==="all"?void 0:N,is_jargon:w==="all"?void 0:w==="true"?!0:w==="false"?!1:void 0});r(E.data),x(E.total)}catch(E){R({title:"加载失败",description:E instanceof Error?E.message:"无法加载黑话列表",variant:"destructive"})}finally{d(!1)}},me=async()=>{try{const E=await l2();E?.data&&J(E.data)}catch(E){console.error("加载统计数据失败:",E)}},_e=async()=>{try{const E=await Z1();E?.data&&se(E.data)}catch(E){console.error("加载聊天列表失败:",E)}};u.useEffect(()=>{ue(),me(),_e()},[f,g,j,N,w]);const Ce=async E=>{try{const xe=await W1(E.id);B(xe.data),L(!0)}catch(xe){R({title:"加载详情失败",description:xe instanceof Error?xe.message:"无法加载黑话详情",variant:"destructive"})}},ze=E=>{B(E),K(!0)},ge=async E=>{try{await t2(E.id),R({title:"删除成功",description:`已删除黑话: ${E.content}`}),te(null),ue(),me()}catch(xe){R({title:"删除失败",description:xe instanceof Error?xe.message:"无法删除黑话",variant:"destructive"})}},ae=E=>{const xe=new Set(fe);xe.has(E)?xe.delete(E):xe.add(E),je(xe)},re=()=>{fe.size===n.length&&n.length>0?je(new Set):je(new Set(n.map(E=>E.id)))},F=async()=>{try{await a2(Array.from(fe)),R({title:"批量删除成功",description:`已删除 ${fe.size} 个黑话`}),je(new Set),he(!1),ue(),me()}catch(E){R({title:"批量删除失败",description:E instanceof Error?E.message:"无法批量删除黑话",variant:"destructive"})}},P=async E=>{try{await n2(Array.from(fe),E),R({title:"操作成功",description:`已将 ${fe.size} 个词条设为${E?"黑话":"非黑话"}`}),je(new Set),ue(),me()}catch(xe){R({title:"操作失败",description:xe instanceof Error?xe.message:"批量设置失败",variant:"destructive"})}},Te=()=>{const E=parseInt(ve),xe=Math.ceil(m/g);E>=1&&E<=xe?(p(E),be("")):R({title:"无效的页码",description:`请输入1-${xe}之间的页码`,variant:"destructive"})},Le=E=>E===!0?e.jsxs(Qe,{variant:"default",className:"bg-green-600 hover:bg-green-700",children:[e.jsx(Qt,{className:"h-3 w-3 mr-1"}),"是黑话"]}):E===!1?e.jsxs(Qe,{variant:"secondary",children:[e.jsx(rl,{className:"h-3 w-3 mr-1"}),"非黑话"]}):e.jsxs(Qe,{variant:"outline",children:[e.jsx(pg,{className:"h-3 w-3 mr-1"}),"未判定"]});return e.jsxs("div",{className:"h-[calc(100vh-4rem)] flex flex-col p-4 sm:p-6",children:[e.jsx("div",{className:"mb-4 sm:mb-6",children:e.jsxs("div",{className:"flex flex-col sm:flex-row sm:items-center justify-between gap-4",children:[e.jsxs("div",{children:[e.jsxs("h1",{className:"text-2xl sm:text-3xl font-bold flex items-center gap-2",children:[e.jsx(uy,{className:"h-8 w-8",strokeWidth:2}),"黑话管理"]}),e.jsx("p",{className:"text-muted-foreground mt-1 text-sm sm:text-base",children:"管理麦麦学习到的黑话和俚语"})]}),e.jsxs(S,{onClick:()=>T(!0),className:"gap-2",children:[e.jsx(dt,{className:"h-4 w-4"}),"新增黑话"]})]})}),e.jsx(Ze,{className:"flex-1",children:e.jsxs("div",{className:"space-y-4 sm:space-y-6 pr-4",children:[e.jsxs("div",{className:"grid grid-cols-2 sm:grid-cols-4 lg:grid-cols-7 gap-3",children:[e.jsxs("div",{className:"rounded-lg border bg-card p-3 sm:p-4",children:[e.jsx("div",{className:"text-xs sm:text-sm text-muted-foreground",children:"总数量"}),e.jsx("div",{className:"text-xl sm:text-2xl font-bold mt-1",children:D.total})]}),e.jsxs("div",{className:"rounded-lg border bg-card p-3 sm:p-4",children:[e.jsx("div",{className:"text-xs sm:text-sm text-muted-foreground",children:"已确认黑话"}),e.jsx("div",{className:"text-xl sm:text-2xl font-bold mt-1 text-green-600",children:D.confirmed_jargon})]}),e.jsxs("div",{className:"rounded-lg border bg-card p-3 sm:p-4",children:[e.jsx("div",{className:"text-xs sm:text-sm text-muted-foreground",children:"确认非黑话"}),e.jsx("div",{className:"text-xl sm:text-2xl font-bold mt-1 text-gray-500",children:D.confirmed_not_jargon})]}),e.jsxs("div",{className:"rounded-lg border bg-card p-3 sm:p-4",children:[e.jsx("div",{className:"text-xs sm:text-sm text-muted-foreground",children:"待判定"}),e.jsx("div",{className:"text-xl sm:text-2xl font-bold mt-1 text-yellow-600",children:D.pending})]}),e.jsxs("div",{className:"rounded-lg border bg-card p-3 sm:p-4",children:[e.jsx("div",{className:"text-xs sm:text-sm text-muted-foreground",children:"全局黑话"}),e.jsx("div",{className:"text-xl sm:text-2xl font-bold mt-1 text-blue-600",children:D.global_count})]}),e.jsxs("div",{className:"rounded-lg border bg-card p-3 sm:p-4",children:[e.jsx("div",{className:"text-xs sm:text-sm text-muted-foreground",children:"推断完成"}),e.jsx("div",{className:"text-xl sm:text-2xl font-bold mt-1 text-purple-600",children:D.complete_count})]}),e.jsxs("div",{className:"rounded-lg border bg-card p-3 sm:p-4",children:[e.jsx("div",{className:"text-xs sm:text-sm text-muted-foreground",children:"关联聊天数"}),e.jsx("div",{className:"text-xl sm:text-2xl font-bold mt-1",children:D.chat_count})]})]}),e.jsxs("div",{className:"rounded-lg border bg-card p-4",children:[e.jsxs("div",{className:"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4",children:[e.jsxs("div",{className:"space-y-1.5",children:[e.jsx(C,{htmlFor:"search",children:"搜索"}),e.jsxs("div",{className:"relative",children:[e.jsx(Mt,{className:"absolute left-2.5 top-2.5 h-4 w-4 text-muted-foreground"}),e.jsx(ie,{id:"search",placeholder:"搜索内容、含义...",value:j,onChange:E=>y(E.target.value),className:"pl-9"})]})]}),e.jsxs("div",{className:"space-y-1.5",children:[e.jsx(C,{children:"聊天筛选"}),e.jsxs(Ue,{value:N,onValueChange:k,children:[e.jsx(Oe,{children:e.jsx(Be,{placeholder:"全部聊天"})}),e.jsxs(Re,{children:[e.jsx(le,{value:"all",children:"全部聊天"}),q.map(E=>e.jsx(le,{value:E.chat_id,children:E.chat_name},E.chat_id))]})]})]}),e.jsxs("div",{className:"space-y-1.5",children:[e.jsx(C,{children:"状态筛选"}),e.jsxs(Ue,{value:w,onValueChange:U,children:[e.jsx(Oe,{children:e.jsx(Be,{placeholder:"全部状态"})}),e.jsxs(Re,{children:[e.jsx(le,{value:"all",children:"全部状态"}),e.jsx(le,{value:"true",children:"是黑话"}),e.jsx(le,{value:"false",children:"非黑话"})]})]})]}),e.jsxs("div",{className:"space-y-1.5",children:[e.jsx(C,{htmlFor:"page-size",children:"每页显示"}),e.jsxs(Ue,{value:g.toString(),onValueChange:E=>{b(parseInt(E)),p(1),je(new Set)},children:[e.jsx(Oe,{id:"page-size",children:e.jsx(Be,{})}),e.jsxs(Re,{children:[e.jsx(le,{value:"10",children:"10"}),e.jsx(le,{value:"20",children:"20"}),e.jsx(le,{value:"50",children:"50"}),e.jsx(le,{value:"100",children:"100"})]})]})]})]}),fe.size>0&&e.jsxs("div",{className:"flex flex-wrap items-center gap-2 mt-4 pt-4 border-t",children:[e.jsxs("span",{className:"text-sm text-muted-foreground",children:["已选择 ",fe.size," 个"]}),e.jsxs(S,{variant:"outline",size:"sm",onClick:()=>P(!0),children:[e.jsx(Qt,{className:"h-4 w-4 mr-1"}),"标记为黑话"]}),e.jsxs(S,{variant:"outline",size:"sm",onClick:()=>P(!1),children:[e.jsx(rl,{className:"h-4 w-4 mr-1"}),"标记为非黑话"]}),e.jsx(S,{variant:"outline",size:"sm",onClick:()=>je(new Set),children:"取消选择"}),e.jsxs(S,{variant:"destructive",size:"sm",onClick:()=>he(!0),children:[e.jsx(We,{className:"h-4 w-4 mr-1"}),"批量删除"]})]})]}),e.jsxs("div",{className:"rounded-lg border bg-card",children:[e.jsx("div",{className:"hidden md:block",children:e.jsxs(rn,{children:[e.jsx(cn,{children:e.jsxs(ut,{children:[e.jsx(Xe,{className:"w-12",children:e.jsx(mt,{checked:fe.size===n.length&&n.length>0,onCheckedChange:re})}),e.jsx(Xe,{children:"内容"}),e.jsx(Xe,{children:"含义"}),e.jsx(Xe,{children:"聊天"}),e.jsx(Xe,{children:"状态"}),e.jsx(Xe,{className:"text-center",children:"次数"}),e.jsx(Xe,{className:"text-right",children:"操作"})]})}),e.jsx(on,{children:i?e.jsx(ut,{children:e.jsx(Ve,{colSpan:7,className:"text-center py-8 text-muted-foreground",children:"加载中..."})}):n.length===0?e.jsx(ut,{children:e.jsx(Ve,{colSpan:7,className:"text-center py-8 text-muted-foreground",children:"暂无数据"})}):n.map(E=>e.jsxs(ut,{children:[e.jsx(Ve,{children:e.jsx(mt,{checked:fe.has(E.id),onCheckedChange:()=>ae(E.id)})}),e.jsx(Ve,{className:"font-medium max-w-[200px]",children:e.jsxs("div",{className:"flex items-center gap-2",children:[E.is_global&&e.jsx("span",{title:"全局黑话",children:e.jsx(Ru,{className:"h-4 w-4 text-blue-500 flex-shrink-0"})}),e.jsx("span",{className:"truncate",title:E.content,children:E.content})]})}),e.jsx(Ve,{className:"max-w-[200px] truncate",title:E.meaning||"",children:E.meaning||e.jsx("span",{className:"text-muted-foreground",children:"-"})}),e.jsx(Ve,{className:"max-w-[150px] truncate",title:E.chat_name||E.chat_id,children:E.chat_name||E.chat_id}),e.jsx(Ve,{children:Le(E.is_jargon)}),e.jsx(Ve,{className:"text-center",children:E.count}),e.jsx(Ve,{className:"text-right",children:e.jsxs("div",{className:"flex justify-end gap-2",children:[e.jsxs(S,{variant:"default",size:"sm",onClick:()=>ze(E),children:[e.jsx(nn,{className:"h-4 w-4 mr-1"}),"编辑"]}),e.jsx(S,{variant:"outline",size:"icon",className:"h-8 w-8",onClick:()=>Ce(E),title:"查看详情",children:e.jsx(Rt,{className:"h-4 w-4"})}),e.jsxs(S,{size:"sm",onClick:()=>te(E),className:"bg-red-600 hover:bg-red-700 text-white",children:[e.jsx(We,{className:"h-4 w-4 mr-1"}),"删除"]})]})})]},E.id))})]})}),e.jsx("div",{className:"md:hidden space-y-3 p-4",children:i?e.jsx("div",{className:"text-center py-8 text-muted-foreground",children:"加载中..."}):n.length===0?e.jsx("div",{className:"text-center py-8 text-muted-foreground",children:"暂无数据"}):n.map(E=>e.jsxs("div",{className:"rounded-lg border bg-card p-4 space-y-3",children:[e.jsxs("div",{className:"flex items-start gap-3",children:[e.jsx(mt,{checked:fe.has(E.id),onCheckedChange:()=>ae(E.id),className:"mt-1"}),e.jsxs("div",{className:"min-w-0 flex-1 space-y-2",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[E.is_global&&e.jsx(Ru,{className:"h-4 w-4 text-blue-500 flex-shrink-0"}),e.jsx("h3",{className:"font-semibold text-sm break-all",children:E.content})]}),E.meaning&&e.jsx("p",{className:"text-sm text-muted-foreground break-all",children:E.meaning}),e.jsxs("div",{className:"flex flex-wrap items-center gap-2 text-xs",children:[Le(E.is_jargon),e.jsxs("span",{className:"text-muted-foreground",children:["次数: ",E.count]})]}),e.jsxs("div",{className:"text-xs text-muted-foreground truncate",children:["聊天: ",E.chat_name||E.chat_id]})]})]}),e.jsxs("div",{className:"flex flex-wrap gap-1 pt-2 border-t",children:[e.jsxs(S,{variant:"outline",size:"sm",onClick:()=>ze(E),className:"text-xs px-2 py-1 h-auto",children:[e.jsx(nn,{className:"h-3 w-3 mr-1"}),"编辑"]}),e.jsx(S,{variant:"outline",size:"sm",onClick:()=>Ce(E),className:"text-xs px-2 py-1 h-auto",children:e.jsx(Rt,{className:"h-3 w-3"})}),e.jsxs(S,{variant:"outline",size:"sm",onClick:()=>te(E),className:"text-xs px-2 py-1 h-auto text-destructive hover:text-destructive",children:[e.jsx(We,{className:"h-3 w-3 mr-1"}),"删除"]})]})]},E.id))}),m>0&&e.jsxs("div",{className:"flex flex-col sm:flex-row items-center justify-between gap-4 px-4 py-3 border-t",children:[e.jsxs("div",{className:"text-sm text-muted-foreground",children:["共 ",m," 条记录,第 ",f," / ",Math.ceil(m/g)," 页"]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(S,{variant:"outline",size:"sm",onClick:()=>p(1),disabled:f===1,className:"hidden sm:flex",children:e.jsx(lr,{className:"h-4 w-4"})}),e.jsxs(S,{variant:"outline",size:"sm",onClick:()=>p(f-1),disabled:f===1,children:[e.jsx(il,{className:"h-4 w-4 sm:mr-1"}),e.jsx("span",{className:"hidden sm:inline",children:"上一页"})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(ie,{type:"number",value:ve,onChange:E=>be(E.target.value),onKeyDown:E=>E.key==="Enter"&&Te(),placeholder:f.toString(),className:"w-16 h-8 text-center",min:1,max:Math.ceil(m/g)}),e.jsx(S,{variant:"outline",size:"sm",onClick:Te,disabled:!ve,className:"h-8",children:"跳转"})]}),e.jsxs(S,{variant:"outline",size:"sm",onClick:()=>p(f+1),disabled:f>=Math.ceil(m/g),children:[e.jsx("span",{className:"hidden sm:inline",children:"下一页"}),e.jsx(Ba,{className:"h-4 w-4 sm:ml-1"})]}),e.jsx(S,{variant:"outline",size:"sm",onClick:()=>p(Math.ceil(m/g)),disabled:f>=Math.ceil(m/g),className:"hidden sm:flex",children:e.jsx(nr,{className:"h-4 w-4"})})]})]})]})]})}),e.jsx(i2,{jargon:O,open:Y,onOpenChange:L}),e.jsx(c2,{open:I,onOpenChange:T,chatList:q,onSuccess:()=>{ue(),me(),T(!1)}}),e.jsx(o2,{jargon:O,open:z,onOpenChange:K,chatList:q,onSuccess:()=>{ue(),me(),K(!1)}}),e.jsx(hs,{open:!!A,onOpenChange:()=>te(null),children:e.jsxs(ls,{children:[e.jsxs(ns,{children:[e.jsx(is,{children:"确认删除"}),e.jsxs(cs,{children:['确定要删除黑话 "',A?.content,'" 吗?此操作不可撤销。']})]}),e.jsxs(rs,{children:[e.jsx(ds,{children:"取消"}),e.jsx(os,{onClick:()=>A&&ge(A),className:"bg-destructive text-destructive-foreground hover:bg-destructive/90",children:"删除"})]})]})}),e.jsx(hs,{open:pe,onOpenChange:he,children:e.jsxs(ls,{children:[e.jsxs(ns,{children:[e.jsx(is,{children:"确认批量删除"}),e.jsxs(cs,{children:["您即将删除 ",fe.size," 个黑话,此操作无法撤销。确定要继续吗?"]})]}),e.jsxs(rs,{children:[e.jsx(ds,{children:"取消"}),e.jsx(os,{onClick:F,className:"bg-destructive text-destructive-foreground hover:bg-destructive/90",children:"确认删除"})]})]})})]})}function i2({jargon:n,open:r,onOpenChange:i}){return n?e.jsx(qs,{open:r,onOpenChange:i,children:e.jsxs(Ls,{className:"max-w-2xl max-h-[80vh] grid grid-rows-[auto_1fr_auto] overflow-hidden",children:[e.jsxs(Us,{children:[e.jsx(Bs,{children:"黑话详情"}),e.jsx(Ps,{children:"查看黑话的完整信息"})]}),e.jsx(Ze,{className:"h-full pr-4",children:e.jsxs("div",{className:"space-y-4 pb-2",children:[e.jsxs("div",{className:"grid grid-cols-2 gap-4",children:[e.jsx(Mu,{icon:sr,label:"记录ID",value:n.id.toString(),mono:!0}),e.jsx(Mu,{label:"使用次数",value:n.count.toString()})]}),e.jsxs("div",{className:"space-y-1",children:[e.jsx(C,{className:"text-xs text-muted-foreground",children:"内容"}),e.jsx("div",{className:"text-sm p-2 bg-muted rounded break-all whitespace-pre-wrap",children:n.content})]}),n.raw_content&&e.jsxs("div",{className:"space-y-1",children:[e.jsx(C,{className:"text-xs text-muted-foreground",children:"原始内容"}),e.jsx("div",{className:"text-sm p-2 bg-muted rounded break-all",children:(()=>{try{const d=JSON.parse(n.raw_content);return Array.isArray(d)?d.map((m,x)=>e.jsxs("div",{children:[x>0&&e.jsx("hr",{className:"my-3 border-border"}),e.jsx("div",{className:"whitespace-pre-wrap",children:m})]},x)):e.jsx("div",{className:"whitespace-pre-wrap",children:n.raw_content})}catch{return e.jsx("div",{className:"whitespace-pre-wrap",children:n.raw_content})}})()})]}),e.jsxs("div",{className:"space-y-1",children:[e.jsx(C,{className:"text-xs text-muted-foreground",children:"含义"}),e.jsx("div",{className:"text-sm p-2 bg-muted rounded break-all",children:n.meaning?e.jsx(Yg,{content:n.meaning}):"-"})]}),e.jsxs("div",{className:"grid grid-cols-2 gap-4",children:[e.jsx(Mu,{label:"聊天",value:n.chat_name||n.chat_id}),e.jsxs("div",{className:"space-y-1",children:[e.jsx(C,{className:"text-xs text-muted-foreground",children:"状态"}),e.jsxs("div",{className:"flex items-center gap-2",children:[n.is_jargon===!0&&e.jsx(Qe,{variant:"default",className:"bg-green-600",children:"是黑话"}),n.is_jargon===!1&&e.jsx(Qe,{variant:"secondary",children:"非黑话"}),n.is_jargon===null&&e.jsx(Qe,{variant:"outline",children:"未判定"}),n.is_global&&e.jsx(Qe,{variant:"outline",className:"border-blue-500 text-blue-500",children:"全局"}),n.is_complete&&e.jsx(Qe,{variant:"outline",className:"border-purple-500 text-purple-500",children:"推断完成"})]})]})]}),n.inference_with_context&&e.jsxs("div",{className:"space-y-1",children:[e.jsx(C,{className:"text-xs text-muted-foreground",children:"上下文推断结果"}),e.jsx("div",{className:"p-2 bg-muted rounded break-all whitespace-pre-wrap font-mono text-xs max-h-[200px] overflow-y-auto",children:n.inference_with_context})]}),n.inference_content_only&&e.jsxs("div",{className:"space-y-1",children:[e.jsx(C,{className:"text-xs text-muted-foreground",children:"纯词条推断结果"}),e.jsx("div",{className:"p-2 bg-muted rounded break-all whitespace-pre-wrap font-mono text-xs max-h-[200px] overflow-y-auto",children:n.inference_content_only})]})]})}),e.jsx(st,{className:"flex-shrink-0",children:e.jsx(S,{onClick:()=>i(!1),children:"关闭"})})]})}):null}function Mu({icon:n,label:r,value:i,mono:d=!1}){return e.jsxs("div",{className:"space-y-1",children:[e.jsxs(C,{className:"text-xs text-muted-foreground flex items-center gap-1",children:[n&&e.jsx(n,{className:"h-3 w-3"}),r]}),e.jsx("div",{className:$("text-sm",d&&"font-mono",!i&&"text-muted-foreground"),children:i||"-"})]})}function c2({open:n,onOpenChange:r,chatList:i,onSuccess:d}){const[m,x]=u.useState({content:"",meaning:"",chat_id:"",is_global:!1}),[f,p]=u.useState(!1),{toast:g}=$s(),b=async()=>{if(!m.content||!m.chat_id){g({title:"验证失败",description:"请填写必填字段:内容和聊天",variant:"destructive"});return}try{p(!0),await e2(m),g({title:"创建成功",description:"黑话已创建"}),x({content:"",meaning:"",chat_id:"",is_global:!1}),d()}catch(j){g({title:"创建失败",description:j instanceof Error?j.message:"无法创建黑话",variant:"destructive"})}finally{p(!1)}};return e.jsx(qs,{open:n,onOpenChange:r,children:e.jsxs(Ls,{className:"max-w-2xl max-h-[80vh] overflow-y-auto",children:[e.jsxs(Us,{children:[e.jsx(Bs,{children:"新增黑话"}),e.jsx(Ps,{children:"创建新的黑话记录"})]}),e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"space-y-2",children:[e.jsxs(C,{htmlFor:"content",children:["内容 ",e.jsx("span",{className:"text-destructive",children:"*"})]}),e.jsx(ie,{id:"content",value:m.content,onChange:j=>x({...m,content:j.target.value}),placeholder:"输入黑话内容"})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(C,{htmlFor:"meaning",children:"含义"}),e.jsx(Qs,{id:"meaning",value:m.meaning||"",onChange:j=>x({...m,meaning:j.target.value}),placeholder:"输入黑话含义(可选)",rows:3})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsxs(C,{htmlFor:"chat_id",children:["聊天 ",e.jsx("span",{className:"text-destructive",children:"*"})]}),e.jsxs(Ue,{value:m.chat_id,onValueChange:j=>x({...m,chat_id:j}),children:[e.jsx(Oe,{children:e.jsx(Be,{placeholder:"选择关联的聊天"})}),e.jsx(Re,{children:i.map(j=>e.jsx(le,{value:j.chat_id,children:j.chat_name},j.chat_id))})]})]}),e.jsxs("div",{className:"flex items-center space-x-2",children:[e.jsx($e,{id:"is_global",checked:m.is_global,onCheckedChange:j=>x({...m,is_global:j})}),e.jsx(C,{htmlFor:"is_global",children:"设为全局黑话"})]})]}),e.jsxs(st,{children:[e.jsx(S,{variant:"outline",onClick:()=>r(!1),children:"取消"}),e.jsx(S,{onClick:b,disabled:f,children:f?"创建中...":"创建"})]})]})})}function o2({jargon:n,open:r,onOpenChange:i,chatList:d,onSuccess:m}){const[x,f]=u.useState({}),[p,g]=u.useState(!1),{toast:b}=$s();u.useEffect(()=>{n&&f({content:n.content,meaning:n.meaning||"",chat_id:n.stream_id||n.chat_id,is_global:n.is_global,is_jargon:n.is_jargon})},[n]);const j=async()=>{if(n)try{g(!0),await s2(n.id,x),b({title:"保存成功",description:"黑话已更新"}),m()}catch(y){b({title:"保存失败",description:y instanceof Error?y.message:"无法更新黑话",variant:"destructive"})}finally{g(!1)}};return n?e.jsx(qs,{open:r,onOpenChange:i,children:e.jsxs(Ls,{className:"max-w-2xl max-h-[80vh] overflow-y-auto",children:[e.jsxs(Us,{children:[e.jsx(Bs,{children:"编辑黑话"}),e.jsx(Ps,{children:"修改黑话的信息"})]}),e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"space-y-2",children:[e.jsx(C,{htmlFor:"edit_content",children:"内容"}),e.jsx(ie,{id:"edit_content",value:x.content||"",onChange:y=>f({...x,content:y.target.value}),placeholder:"输入黑话内容"})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(C,{htmlFor:"edit_meaning",children:"含义"}),e.jsx(Qs,{id:"edit_meaning",value:x.meaning||"",onChange:y=>f({...x,meaning:y.target.value}),placeholder:"输入黑话含义",rows:3})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(C,{htmlFor:"edit_chat_id",children:"聊天"}),e.jsxs(Ue,{value:x.chat_id||"",onValueChange:y=>f({...x,chat_id:y}),children:[e.jsx(Oe,{children:e.jsx(Be,{placeholder:"选择关联的聊天"})}),e.jsx(Re,{children:d.map(y=>e.jsx(le,{value:y.chat_id,children:y.chat_name},y.chat_id))})]})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(C,{children:"黑话状态"}),e.jsxs(Ue,{value:x.is_jargon===null?"null":x.is_jargon?.toString()||"null",onValueChange:y=>f({...x,is_jargon:y==="null"?null:y==="true"}),children:[e.jsx(Oe,{children:e.jsx(Be,{})}),e.jsxs(Re,{children:[e.jsx(le,{value:"null",children:"未判定"}),e.jsx(le,{value:"true",children:"是黑话"}),e.jsx(le,{value:"false",children:"非黑话"})]})]})]}),e.jsxs("div",{className:"flex items-center space-x-2",children:[e.jsx($e,{id:"edit_is_global",checked:x.is_global,onCheckedChange:y=>f({...x,is_global:y})}),e.jsx(C,{htmlFor:"edit_is_global",children:"全局黑话"})]})]}),e.jsxs(st,{children:[e.jsx(S,{variant:"outline",onClick:()=>i(!1),children:"取消"}),e.jsx(S,{onClick:j,disabled:p,children:p?"保存中...":"保存"})]})]})}):null}const ir="/api/webui/person";async function d2(n){const r=new URLSearchParams;n.page&&r.append("page",n.page.toString()),n.page_size&&r.append("page_size",n.page_size.toString()),n.search&&r.append("search",n.search),n.is_known!==void 0&&r.append("is_known",n.is_known.toString()),n.platform&&r.append("platform",n.platform);const i=await Se(`${ir}/list?${r}`,{headers:Gs()});if(!i.ok){const d=await i.json();throw new Error(d.detail||"获取人物列表失败")}return i.json()}async function u2(n){const r=await Se(`${ir}/${n}`,{headers:Gs()});if(!r.ok){const i=await r.json();throw new Error(i.detail||"获取人物详情失败")}return r.json()}async function m2(n,r){const i=await Se(`${ir}/${n}`,{method:"PATCH",headers:Gs(),body:JSON.stringify(r)});if(!i.ok){const d=await i.json();throw new Error(d.detail||"更新人物信息失败")}return i.json()}async function x2(n){const r=await Se(`${ir}/${n}`,{method:"DELETE",headers:Gs()});if(!r.ok){const i=await r.json();throw new Error(i.detail||"删除人物信息失败")}return r.json()}async function h2(){const n=await Se(`${ir}/stats/summary`,{headers:Gs()});if(!n.ok){const r=await n.json();throw new Error(r.detail||"获取统计数据失败")}return n.json()}async function f2(n){const r=await Se(`${ir}/batch/delete`,{method:"POST",headers:Gs(),body:JSON.stringify({person_ids:n})});if(!r.ok){const i=await r.json();throw new Error(i.detail||"批量删除失败")}return r.json()}function p2(){const[n,r]=u.useState([]),[i,d]=u.useState(!0),[m,x]=u.useState(0),[f,p]=u.useState(1),[g,b]=u.useState(20),[j,y]=u.useState(""),[N,k]=u.useState(void 0),[w,U]=u.useState(void 0),[O,B]=u.useState(null),[Y,L]=u.useState(!1),[z,K]=u.useState(!1),[I,T]=u.useState(null),[A,te]=u.useState({total:0,known:0,unknown:0,platforms:{}}),[fe,je]=u.useState(new Set),[pe,he]=u.useState(!1),[ve,be]=u.useState(""),{toast:D}=$s(),J=async()=>{try{d(!0);const F=await d2({page:f,page_size:g,search:j||void 0,is_known:N,platform:w});r(F.data),x(F.total)}catch(F){D({title:"加载失败",description:F instanceof Error?F.message:"无法加载人物信息",variant:"destructive"})}finally{d(!1)}},q=async()=>{try{const F=await h2();F?.data&&te(F.data)}catch(F){console.error("加载统计数据失败:",F)}};u.useEffect(()=>{J(),q()},[f,g,j,N,w]);const se=async F=>{try{const P=await u2(F.person_id);B(P.data),L(!0)}catch(P){D({title:"加载详情失败",description:P instanceof Error?P.message:"无法加载人物详情",variant:"destructive"})}},R=F=>{B(F),K(!0)},ue=async F=>{try{await x2(F.person_id),D({title:"删除成功",description:`已删除人物信息: ${F.person_name||F.nickname||F.user_id}`}),T(null),J(),q()}catch(P){D({title:"删除失败",description:P instanceof Error?P.message:"无法删除人物信息",variant:"destructive"})}},me=u.useMemo(()=>Object.keys(A.platforms),[A.platforms]),_e=F=>{const P=new Set(fe);P.has(F)?P.delete(F):P.add(F),je(P)},Ce=()=>{fe.size===n.length&&n.length>0?je(new Set):je(new Set(n.map(F=>F.person_id)))},ze=()=>{if(fe.size===0){D({title:"未选择任何人物",description:"请先选择要删除的人物",variant:"destructive"});return}he(!0)},ge=async()=>{try{const F=await f2(Array.from(fe));D({title:"批量删除完成",description:F.message}),je(new Set),he(!1),J(),q()}catch(F){D({title:"批量删除失败",description:F instanceof Error?F.message:"批量删除失败",variant:"destructive"})}},ae=()=>{const F=parseInt(ve),P=Math.ceil(m/g);F>=1&&F<=P?(p(F),be("")):D({title:"无效的页码",description:`请输入1-${P}之间的页码`,variant:"destructive"})},re=F=>F?new Date(F*1e3).toLocaleString("zh-CN"):"-";return e.jsxs("div",{className:"h-[calc(100vh-4rem)] flex flex-col p-4 sm:p-6",children:[e.jsx("div",{className:"mb-4 sm:mb-6",children:e.jsx("div",{className:"flex flex-col sm:flex-row sm:items-center justify-between gap-4",children:e.jsxs("div",{children:[e.jsxs("h1",{className:"text-2xl sm:text-3xl font-bold flex items-center gap-2",children:[e.jsx(Lu,{className:"h-8 w-8",strokeWidth:2}),"人物信息管理"]}),e.jsx("p",{className:"text-muted-foreground mt-1 text-sm sm:text-base",children:"管理麦麦认识的所有人物信息"})]})})}),e.jsx(Ze,{className:"flex-1",children:e.jsxs("div",{className:"space-y-4 sm:space-y-6 pr-4",children:[e.jsxs("div",{className:"grid grid-cols-1 sm:grid-cols-3 gap-4",children:[e.jsxs("div",{className:"rounded-lg border bg-card p-4",children:[e.jsx("div",{className:"text-sm text-muted-foreground",children:"总人数"}),e.jsx("div",{className:"text-2xl font-bold mt-1",children:A.total})]}),e.jsxs("div",{className:"rounded-lg border bg-card p-4",children:[e.jsx("div",{className:"text-sm text-muted-foreground",children:"已认识"}),e.jsx("div",{className:"text-2xl font-bold mt-1 text-green-600",children:A.known})]}),e.jsxs("div",{className:"rounded-lg border bg-card p-4",children:[e.jsx("div",{className:"text-sm text-muted-foreground",children:"未认识"}),e.jsx("div",{className:"text-2xl font-bold mt-1 text-muted-foreground",children:A.unknown})]})]}),e.jsxs("div",{className:"rounded-lg border bg-card p-4",children:[e.jsxs("div",{className:"grid grid-cols-1 sm:grid-cols-4 gap-4",children:[e.jsxs("div",{className:"sm:col-span-2",children:[e.jsx(C,{htmlFor:"search",children:"搜索"}),e.jsxs("div",{className:"relative mt-1.5",children:[e.jsx(Mt,{className:"absolute left-2.5 top-2.5 h-4 w-4 text-muted-foreground"}),e.jsx(ie,{id:"search",placeholder:"搜索名称、昵称或用户ID...",value:j,onChange:F=>y(F.target.value),className:"pl-9"})]})]}),e.jsxs("div",{children:[e.jsx(C,{htmlFor:"filter-known",children:"认识状态"}),e.jsxs(Ue,{value:N===void 0?"all":N.toString(),onValueChange:F=>{k(F==="all"?void 0:F==="true"),p(1)},children:[e.jsx(Oe,{id:"filter-known",className:"mt-1.5",children:e.jsx(Be,{})}),e.jsxs(Re,{children:[e.jsx(le,{value:"all",children:"全部"}),e.jsx(le,{value:"true",children:"已认识"}),e.jsx(le,{value:"false",children:"未认识"})]})]})]}),e.jsxs("div",{children:[e.jsx(C,{htmlFor:"filter-platform",children:"平台"}),e.jsxs(Ue,{value:w||"all",onValueChange:F=>{U(F==="all"?void 0:F),p(1)},children:[e.jsx(Oe,{id:"filter-platform",className:"mt-1.5",children:e.jsx(Be,{})}),e.jsxs(Re,{children:[e.jsx(le,{value:"all",children:"全部平台"}),me.map(F=>e.jsxs(le,{value:F,children:[F," (",A.platforms[F],")"]},F))]})]})]})]}),e.jsxs("div",{className:"flex flex-col sm:flex-row items-start sm:items-center justify-between gap-3 mt-4 pt-4 border-t",children:[e.jsx("div",{className:"flex items-center gap-2 text-sm text-muted-foreground",children:fe.size>0&&e.jsxs("span",{children:["已选择 ",fe.size," 个人物"]})}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(C,{htmlFor:"page-size",className:"text-sm whitespace-nowrap",children:"每页显示"}),e.jsxs(Ue,{value:g.toString(),onValueChange:F=>{b(parseInt(F)),p(1),je(new Set)},children:[e.jsx(Oe,{id:"page-size",className:"w-20",children:e.jsx(Be,{})}),e.jsxs(Re,{children:[e.jsx(le,{value:"10",children:"10"}),e.jsx(le,{value:"20",children:"20"}),e.jsx(le,{value:"50",children:"50"}),e.jsx(le,{value:"100",children:"100"})]})]}),fe.size>0&&e.jsxs(e.Fragment,{children:[e.jsx(S,{variant:"outline",size:"sm",onClick:()=>je(new Set),children:"取消选择"}),e.jsxs(S,{variant:"destructive",size:"sm",onClick:ze,children:[e.jsx(We,{className:"h-4 w-4 mr-1"}),"批量删除"]})]})]})]})]}),e.jsxs("div",{className:"rounded-lg border bg-card",children:[e.jsx("div",{className:"hidden md:block",children:e.jsxs(rn,{children:[e.jsx(cn,{children:e.jsxs(ut,{children:[e.jsx(Xe,{className:"w-12",children:e.jsx(mt,{checked:n.length>0&&fe.size===n.length,onCheckedChange:Ce,"aria-label":"全选"})}),e.jsx(Xe,{children:"状态"}),e.jsx(Xe,{children:"名称"}),e.jsx(Xe,{children:"昵称"}),e.jsx(Xe,{children:"平台"}),e.jsx(Xe,{children:"用户ID"}),e.jsx(Xe,{children:"最后更新"}),e.jsx(Xe,{className:"text-right",children:"操作"})]})}),e.jsx(on,{children:i?e.jsx(ut,{children:e.jsx(Ve,{colSpan:8,className:"text-center py-8 text-muted-foreground",children:"加载中..."})}):n.length===0?e.jsx(ut,{children:e.jsx(Ve,{colSpan:8,className:"text-center py-8 text-muted-foreground",children:"暂无数据"})}):n.map(F=>e.jsxs(ut,{children:[e.jsx(Ve,{children:e.jsx(mt,{checked:fe.has(F.person_id),onCheckedChange:()=>_e(F.person_id),"aria-label":`选择 ${F.person_name||F.nickname||F.user_id}`})}),e.jsx(Ve,{children:e.jsx("div",{className:$("inline-flex items-center gap-1 px-2 py-1 rounded-full text-xs font-medium",F.is_known?"bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-400":"bg-gray-100 text-gray-700 dark:bg-gray-800 dark:text-gray-400"),children:F.is_known?"已认识":"未认识"})}),e.jsx(Ve,{className:"font-medium",children:F.person_name||e.jsx("span",{className:"text-muted-foreground",children:"-"})}),e.jsx(Ve,{children:F.nickname||"-"}),e.jsx(Ve,{children:F.platform}),e.jsx(Ve,{className:"font-mono text-sm",children:F.user_id}),e.jsx(Ve,{className:"text-sm text-muted-foreground",children:re(F.last_know)}),e.jsx(Ve,{className:"text-right",children:e.jsxs("div",{className:"flex justify-end gap-2",children:[e.jsxs(S,{variant:"default",size:"sm",onClick:()=>se(F),children:[e.jsx(Rt,{className:"h-4 w-4 mr-1"}),"详情"]}),e.jsxs(S,{variant:"default",size:"sm",onClick:()=>R(F),children:[e.jsx(nn,{className:"h-4 w-4 mr-1"}),"编辑"]}),e.jsxs(S,{size:"sm",onClick:()=>T(F),className:"bg-red-600 hover:bg-red-700 text-white",children:[e.jsx(We,{className:"h-4 w-4 mr-1"}),"删除"]})]})})]},F.id))})]})}),e.jsx("div",{className:"md:hidden space-y-3 p-4",children:i?e.jsx("div",{className:"text-center py-8 text-muted-foreground",children:"加载中..."}):n.length===0?e.jsx("div",{className:"text-center py-8 text-muted-foreground",children:"暂无数据"}):n.map(F=>e.jsxs("div",{className:"rounded-lg border bg-card p-4 space-y-3 overflow-hidden",children:[e.jsxs("div",{className:"flex items-start gap-3",children:[e.jsx(mt,{checked:fe.has(F.person_id),onCheckedChange:()=>_e(F.person_id),className:"mt-1"}),e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsx("div",{className:$("inline-flex items-center gap-1 px-2 py-1 rounded-full text-xs font-medium mb-2",F.is_known?"bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-400":"bg-gray-100 text-gray-700 dark:bg-gray-800 dark:text-gray-400"),children:F.is_known?"已认识":"未认识"}),e.jsx("h3",{className:"font-semibold text-sm line-clamp-1 w-full break-all",children:F.person_name||e.jsx("span",{className:"text-muted-foreground",children:"未命名"})}),F.nickname&&e.jsxs("p",{className:"text-xs text-muted-foreground mt-1 line-clamp-1 w-full break-all",children:["昵称: ",F.nickname]})]})]}),e.jsxs("div",{className:"grid grid-cols-2 gap-2 text-sm",children:[e.jsxs("div",{children:[e.jsx("div",{className:"text-xs text-muted-foreground mb-1",children:"平台"}),e.jsx("p",{className:"font-medium text-xs",children:F.platform})]}),e.jsxs("div",{children:[e.jsx("div",{className:"text-xs text-muted-foreground mb-1",children:"用户ID"}),e.jsx("p",{className:"font-mono text-xs truncate",title:F.user_id,children:F.user_id})]}),e.jsxs("div",{className:"col-span-2",children:[e.jsx("div",{className:"text-xs text-muted-foreground mb-1",children:"最后更新"}),e.jsx("p",{className:"text-xs",children:re(F.last_know)})]})]}),e.jsxs("div",{className:"flex flex-wrap gap-1 pt-2 border-t overflow-hidden",children:[e.jsxs(S,{variant:"outline",size:"sm",onClick:()=>se(F),className:"text-xs px-2 py-1 h-auto flex-shrink-0",children:[e.jsx(Rt,{className:"h-3 w-3 mr-1"}),"查看"]}),e.jsxs(S,{variant:"outline",size:"sm",onClick:()=>R(F),className:"text-xs px-2 py-1 h-auto flex-shrink-0",children:[e.jsx(nn,{className:"h-3 w-3 mr-1"}),"编辑"]}),e.jsxs(S,{variant:"outline",size:"sm",onClick:()=>T(F),className:"text-xs px-2 py-1 h-auto flex-shrink-0 text-destructive hover:text-destructive",children:[e.jsx(We,{className:"h-3 w-3 mr-1"}),"删除"]})]})]},F.id))}),m>0&&e.jsxs("div",{className:"flex flex-col sm:flex-row items-center justify-between gap-4 px-4 py-3 border-t",children:[e.jsxs("div",{className:"text-sm text-muted-foreground",children:["共 ",m," 条记录,第 ",f," / ",Math.ceil(m/g)," 页"]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(S,{variant:"outline",size:"sm",onClick:()=>p(1),disabled:f===1,className:"hidden sm:flex",children:e.jsx(lr,{className:"h-4 w-4"})}),e.jsxs(S,{variant:"outline",size:"sm",onClick:()=>p(f-1),disabled:f===1,children:[e.jsx(il,{className:"h-4 w-4 sm:mr-1"}),e.jsx("span",{className:"hidden sm:inline",children:"上一页"})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(ie,{type:"number",value:ve,onChange:F=>be(F.target.value),onKeyDown:F=>F.key==="Enter"&&ae(),placeholder:f.toString(),className:"w-16 h-8 text-center",min:1,max:Math.ceil(m/g)}),e.jsx(S,{variant:"outline",size:"sm",onClick:ae,disabled:!ve,className:"h-8",children:"跳转"})]}),e.jsxs(S,{variant:"outline",size:"sm",onClick:()=>p(f+1),disabled:f>=Math.ceil(m/g),children:[e.jsx("span",{className:"hidden sm:inline",children:"下一页"}),e.jsx(Ba,{className:"h-4 w-4 sm:ml-1"})]}),e.jsx(S,{variant:"outline",size:"sm",onClick:()=>p(Math.ceil(m/g)),disabled:f>=Math.ceil(m/g),className:"hidden sm:flex",children:e.jsx(nr,{className:"h-4 w-4"})})]})]})]})]})}),e.jsx(g2,{person:O,open:Y,onOpenChange:L}),e.jsx(j2,{person:O,open:z,onOpenChange:K,onSuccess:()=>{J(),q(),K(!1)}}),e.jsx(hs,{open:!!I,onOpenChange:()=>T(null),children:e.jsxs(ls,{children:[e.jsxs(ns,{children:[e.jsx(is,{children:"确认删除"}),e.jsxs(cs,{children:['确定要删除人物信息 "',I?.person_name||I?.nickname||I?.user_id,'" 吗? 此操作不可撤销。']})]}),e.jsxs(rs,{children:[e.jsx(ds,{children:"取消"}),e.jsx(os,{onClick:()=>I&&ue(I),className:"bg-destructive text-destructive-foreground hover:bg-destructive/90",children:"删除"})]})]})}),e.jsx(hs,{open:pe,onOpenChange:he,children:e.jsxs(ls,{children:[e.jsxs(ns,{children:[e.jsx(is,{children:"确认批量删除"}),e.jsxs(cs,{children:["确定要删除选中的 ",fe.size," 个人物信息吗? 此操作不可撤销。"]})]}),e.jsxs(rs,{children:[e.jsx(ds,{children:"取消"}),e.jsx(os,{onClick:ge,className:"bg-destructive text-destructive-foreground hover:bg-destructive/90",children:"批量删除"})]})]})})]})}function g2({person:n,open:r,onOpenChange:i}){if(!n)return null;const d=m=>m?new Date(m*1e3).toLocaleString("zh-CN"):"-";return e.jsx(qs,{open:r,onOpenChange:i,children:e.jsxs(Ls,{className:"max-w-2xl max-h-[80vh] overflow-y-auto",children:[e.jsxs(Us,{children:[e.jsx(Bs,{children:"人物详情"}),e.jsxs(Ps,{children:["查看 ",n.person_name||n.nickname||n.user_id," 的完整信息"]})]}),e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"grid grid-cols-2 gap-4",children:[e.jsx(ll,{icon:Qc,label:"人物名称",value:n.person_name}),e.jsx(ll,{icon:Rl,label:"昵称",value:n.nickname}),e.jsx(ll,{icon:sr,label:"用户ID",value:n.user_id,mono:!0}),e.jsx(ll,{icon:sr,label:"人物ID",value:n.person_id,mono:!0}),e.jsx(ll,{label:"平台",value:n.platform}),e.jsx(ll,{label:"状态",value:n.is_known?"已认识":"未认识"})]}),n.name_reason&&e.jsxs("div",{className:"rounded-lg border bg-muted/50 p-3",children:[e.jsx(C,{className:"text-xs text-muted-foreground",children:"名称设定原因"}),e.jsx("p",{className:"mt-1 text-sm",children:n.name_reason})]}),n.memory_points&&e.jsxs("div",{className:"rounded-lg border bg-muted/50 p-3",children:[e.jsx(C,{className:"text-xs text-muted-foreground",children:"个人印象"}),e.jsx("p",{className:"mt-1 text-sm whitespace-pre-wrap",children:n.memory_points})]}),n.group_nick_name&&n.group_nick_name.length>0&&e.jsxs("div",{className:"rounded-lg border bg-muted/50 p-3",children:[e.jsx(C,{className:"text-xs text-muted-foreground",children:"群昵称"}),e.jsx("div",{className:"mt-2 space-y-1",children:n.group_nick_name.map((m,x)=>e.jsxs("div",{className:"text-sm flex items-center gap-2",children:[e.jsx("span",{className:"font-mono text-xs text-muted-foreground",children:m.group_id}),e.jsx("span",{children:"→"}),e.jsx("span",{children:m.group_nick_name})]},x))})]}),e.jsxs("div",{className:"grid grid-cols-3 gap-4",children:[e.jsx(ll,{icon:Pn,label:"认识时间",value:d(n.know_times)}),e.jsx(ll,{icon:Pn,label:"首次记录",value:d(n.know_since)}),e.jsx(ll,{icon:Pn,label:"最后更新",value:d(n.last_know)})]})]}),e.jsx(st,{children:e.jsx(S,{onClick:()=>i(!1),children:"关闭"})})]})})}function ll({icon:n,label:r,value:i,mono:d=!1}){return e.jsxs("div",{className:"space-y-1",children:[e.jsxs(C,{className:"text-xs text-muted-foreground flex items-center gap-1",children:[n&&e.jsx(n,{className:"h-3 w-3"}),r]}),e.jsx("div",{className:$("text-sm",d&&"font-mono",!i&&"text-muted-foreground"),children:i||"-"})]})}function j2({person:n,open:r,onOpenChange:i,onSuccess:d}){const[m,x]=u.useState({}),[f,p]=u.useState(!1),{toast:g}=$s();u.useEffect(()=>{n&&x({person_name:n.person_name||"",name_reason:n.name_reason||"",nickname:n.nickname||"",memory_points:n.memory_points||"",is_known:n.is_known})},[n]);const b=async()=>{if(n)try{p(!0),await m2(n.person_id,m),g({title:"保存成功",description:"人物信息已更新"}),d()}catch(j){g({title:"保存失败",description:j instanceof Error?j.message:"无法更新人物信息",variant:"destructive"})}finally{p(!1)}};return n?e.jsx(qs,{open:r,onOpenChange:i,children:e.jsxs(Ls,{className:"max-w-2xl max-h-[80vh] overflow-y-auto",children:[e.jsxs(Us,{children:[e.jsx(Bs,{children:"编辑人物信息"}),e.jsxs(Ps,{children:["修改 ",n.person_name||n.nickname||n.user_id," 的信息"]})]}),e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"grid grid-cols-2 gap-4",children:[e.jsxs("div",{className:"space-y-2",children:[e.jsx(C,{htmlFor:"person_name",children:"人物名称"}),e.jsx(ie,{id:"person_name",value:m.person_name||"",onChange:j=>x({...m,person_name:j.target.value}),placeholder:"为这个人设置一个名称"})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(C,{htmlFor:"nickname",children:"昵称"}),e.jsx(ie,{id:"nickname",value:m.nickname||"",onChange:j=>x({...m,nickname:j.target.value}),placeholder:"昵称"})]})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(C,{htmlFor:"name_reason",children:"名称设定原因"}),e.jsx(Qs,{id:"name_reason",value:m.name_reason||"",onChange:j=>x({...m,name_reason:j.target.value}),placeholder:"为什么这样称呼这个人?",rows:2})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(C,{htmlFor:"memory_points",children:"个人印象"}),e.jsx(Qs,{id:"memory_points",value:m.memory_points||"",onChange:j=>x({...m,memory_points:j.target.value}),placeholder:"对这个人的印象和记忆点...",rows:4})]}),e.jsxs("div",{className:"flex items-center justify-between rounded-lg border p-3",children:[e.jsxs("div",{children:[e.jsx(C,{htmlFor:"is_known",className:"text-base font-medium",children:"已认识"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"标记是否已经认识这个人"})]}),e.jsx($e,{id:"is_known",checked:m.is_known,onCheckedChange:j=>x({...m,is_known:j})})]})]}),e.jsxs(st,{children:[e.jsx(S,{variant:"outline",onClick:()=>i(!1),children:"取消"}),e.jsx(S,{onClick:b,disabled:f,children:f?"保存中...":"保存"})]})]})}):null}var v2=Zy();const vp=Ib(v2),Wu="/api/webui";async function b2(n=100,r="all"){const i=`${Wu}/knowledge/graph?limit=${n}&node_type=${r}`,d=await fetch(i);if(!d.ok)throw new Error(`获取知识图谱失败: ${d.status}`);return d.json()}async function N2(){const n=await fetch(`${Wu}/knowledge/stats`);if(!n.ok)throw new Error("获取知识图谱统计信息失败");return n.json()}async function y2(n){const r=await fetch(`${Wu}/knowledge/search?query=${encodeURIComponent(n)}`);if(!r.ok)throw new Error("搜索知识节点失败");return r.json()}const Kg=u.memo(({data:n})=>e.jsxs("div",{className:"px-4 py-2 shadow-md rounded-lg bg-gradient-to-br from-blue-500 to-blue-600 border-2 border-blue-700 min-w-[120px]",children:[e.jsx(Ic,{type:"target",position:Yc.Top}),e.jsx("div",{className:"font-semibold text-white text-sm truncate max-w-[200px]",title:n.content,children:n.label}),e.jsx(Ic,{type:"source",position:Yc.Bottom})]}));Kg.displayName="EntityNode";const Xg=u.memo(({data:n})=>e.jsxs("div",{className:"px-3 py-2 shadow-md rounded-md bg-gradient-to-br from-green-500 to-green-600 border-2 border-green-700 min-w-[100px]",children:[e.jsx(Ic,{type:"target",position:Yc.Top}),e.jsx("div",{className:"font-medium text-white text-xs truncate max-w-[150px]",title:n.content,children:n.label}),e.jsx(Ic,{type:"source",position:Yc.Bottom})]}));Xg.displayName="ParagraphNode";const w2={entity:Kg,paragraph:Xg};function _2(n,r){const i=new vp.graphlib.Graph;i.setDefaultEdgeLabel(()=>({})),i.setGraph({rankdir:"TB",ranksep:100,nodesep:80});const d=[],m=[];return n.forEach(x=>{i.setNode(x.id,{width:150,height:50})}),r.forEach(x=>{i.setEdge(x.source,x.target)}),vp.layout(i),n.forEach(x=>{const f=i.node(x.id);d.push({id:x.id,type:x.type,position:{x:f.x-75,y:f.y-25},data:{label:x.content.slice(0,20)+(x.content.length>20?"...":""),content:x.content}})}),r.forEach((x,f)=>{const p={id:`edge-${f}`,source:x.source,target:x.target,animated:n.length<=200&&x.weight>5,style:{strokeWidth:Math.min(x.weight/2,5),opacity:.6}};x.weight>10&&n.length<100&&(p.label=`${x.weight.toFixed(0)}`),m.push(p)}),{nodes:d,edges:m}}function S2(){const n=va(),[r,i]=u.useState(!1),[d,m]=u.useState(null),[x,f]=u.useState(""),[p,g]=u.useState("all"),[b,j]=u.useState(50),[y,N]=u.useState("50"),[k,w]=u.useState(!1),[U,O]=u.useState(!0),[B,Y]=u.useState(!1),[L,z]=u.useState(!1),[K,I,T]=Py([]),[A,te,fe]=Wy([]),[je,pe]=u.useState(0),[he,ve]=u.useState(null),[be,D]=u.useState(null),{toast:J}=$s(),q=u.useCallback(ge=>ge.type==="entity"?"#6366f1":ge.type==="paragraph"?"#10b981":"#6b7280",[]),se=u.useCallback(async(ge=!1)=>{try{if(!ge&&b>200){z(!0);return}i(!0);const[ae,re]=await Promise.all([b2(b,p),N2()]);if(m(re),ae.nodes.length===0){J({title:"提示",description:"知识库为空,请先导入知识数据"}),I([]),te([]);return}const{nodes:F,edges:P}=_2(ae.nodes,ae.edges);I(F),te(P),pe(F.length),re&&re.total_nodes>b&&J({title:"提示",description:`知识图谱包含 ${re.total_nodes} 个节点,当前显示 ${F.length} 个`}),J({title:"加载成功",description:`已加载 ${F.length} 个节点,${P.length} 条边`})}catch(ae){console.error("加载知识图谱失败:",ae),J({title:"加载失败",description:ae instanceof Error?ae.message:"未知错误",variant:"destructive"})}finally{i(!1)}},[b,p,J]),R=u.useCallback(async()=>{if(!x.trim()){J({title:"提示",description:"请输入搜索关键词"});return}try{const ge=await y2(x);if(ge.length===0){J({title:"未找到",description:"没有找到匹配的节点"});return}const ae=new Set(ge.map(re=>re.id));I(re=>re.map(F=>({...F,style:{...F.style,opacity:ae.has(F.id)?1:.3,filter:ae.has(F.id)?"brightness(1.2)":"brightness(0.8)"}}))),J({title:"搜索完成",description:`找到 ${ge.length} 个匹配节点`})}catch(ge){console.error("搜索失败:",ge),J({title:"搜索失败",description:ge instanceof Error?ge.message:"未知错误",variant:"destructive"})}},[x,J]),ue=u.useCallback(()=>{I(ge=>ge.map(ae=>({...ae,style:{...ae.style,opacity:1,filter:"brightness(1)"}})))},[]),me=u.useCallback(()=>{O(!1),Y(!0),se()},[se]),_e=u.useCallback(()=>{z(!1),setTimeout(()=>{se(!0)},0)},[se]),Ce=u.useCallback((ge,ae)=>{K.find(F=>F.id===ae.id)&&ve({id:ae.id,type:ae.type,content:ae.data.content})},[K]);u.useEffect(()=>{U||B&&se()},[b,p,U,B]);const ze=u.useCallback((ge,ae)=>{const re=K.find(Te=>Te.id===ae.source),F=K.find(Te=>Te.id===ae.target),P=A.find(Te=>Te.id===ae.id);re&&F&&P&&D({source:{id:re.id,type:re.type,content:re.data.content},target:{id:F.id,type:F.type,content:F.data.content},edge:{source:ae.source,target:ae.target,weight:parseFloat(ae.label||"0")}})},[K,A]);return e.jsxs("div",{className:"h-full flex flex-col",children:[e.jsxs("div",{className:"flex-shrink-0 p-4 border-b bg-background",children:[e.jsxs("div",{className:"flex flex-col sm:flex-row justify-between items-start sm:items-center gap-4",children:[e.jsxs("div",{children:[e.jsx("h1",{className:"text-2xl sm:text-3xl font-bold",children:"麦麦知识库图谱"}),e.jsx("p",{className:"text-muted-foreground mt-1",children:"可视化知识实体与关系网络"})]}),d&&e.jsxs("div",{className:"flex gap-2 flex-wrap",children:[e.jsxs(Qe,{variant:"outline",className:"gap-1",children:[e.jsx(Fc,{className:"h-3 w-3"}),"节点: ",d.total_nodes]}),e.jsxs(Qe,{variant:"outline",className:"gap-1",children:[e.jsx(jg,{className:"h-3 w-3"}),"边: ",d.total_edges]}),e.jsxs(Qe,{variant:"outline",className:"gap-1",children:[e.jsx(Ra,{className:"h-3 w-3"}),"实体: ",d.entity_nodes]}),e.jsxs(Qe,{variant:"outline",className:"gap-1",children:[e.jsx(Sa,{className:"h-3 w-3"}),"段落: ",d.paragraph_nodes]})]})]}),e.jsxs("div",{className:"flex flex-col sm:flex-row gap-2 mt-4",children:[e.jsxs("div",{className:"flex-1 flex gap-2",children:[e.jsx(ie,{placeholder:"搜索节点内容...",value:x,onChange:ge=>f(ge.target.value),onKeyDown:ge=>ge.key==="Enter"&&R(),className:"flex-1"}),e.jsx(S,{onClick:R,size:"sm",children:e.jsx(Mt,{className:"h-4 w-4"})}),e.jsx(S,{onClick:ue,variant:"outline",size:"sm",children:"重置"})]}),e.jsxs("div",{className:"flex gap-2",children:[e.jsxs(Ue,{value:p,onValueChange:ge=>g(ge),children:[e.jsx(Oe,{className:"w-[120px]",children:e.jsx(Be,{})}),e.jsxs(Re,{children:[e.jsx(le,{value:"all",children:"全部节点"}),e.jsx(le,{value:"entity",children:"仅实体"}),e.jsx(le,{value:"paragraph",children:"仅段落"})]})]}),e.jsxs(Ue,{value:b===1e4?"all":k?"custom":b.toString(),onValueChange:ge=>{ge==="custom"?(w(!0),N(b.toString())):ge==="all"?(w(!1),j(1e4)):(w(!1),j(Number(ge)))},children:[e.jsx(Oe,{className:"w-[120px]",children:e.jsx(Be,{})}),e.jsxs(Re,{children:[e.jsx(le,{value:"50",children:"50 节点"}),e.jsx(le,{value:"100",children:"100 节点"}),e.jsx(le,{value:"200",children:"200 节点"}),e.jsx(le,{value:"500",children:"500 节点"}),e.jsx(le,{value:"1000",children:"1000 节点"}),e.jsx(le,{value:"all",children:"全部 (最多10000)"}),e.jsx(le,{value:"custom",children:"自定义..."})]})]}),k&&e.jsx(ie,{type:"number",min:"50",value:y,onChange:ge=>N(ge.target.value),onBlur:()=>{const ge=parseInt(y);!isNaN(ge)&&ge>=50?j(ge):(N("50"),j(50))},onKeyDown:ge=>{if(ge.key==="Enter"){const ae=parseInt(y);!isNaN(ae)&&ae>=50?j(ae):(N("50"),j(50))}},placeholder:"最少50个",className:"w-[120px]"}),e.jsx(S,{onClick:()=>se(),variant:"outline",size:"sm",disabled:r,children:e.jsx(zt,{className:$("h-4 w-4",r&&"animate-spin")})})]})]})]}),e.jsx("div",{className:"flex-1 relative",children:r?e.jsx("div",{className:"absolute inset-0 flex items-center justify-center",children:e.jsxs("div",{className:"text-center",children:[e.jsx(zt,{className:"h-8 w-8 animate-spin mx-auto mb-2 text-muted-foreground"}),e.jsx("p",{className:"text-muted-foreground",children:"加载知识图谱中..."})]})}):K.length===0?e.jsx("div",{className:"absolute inset-0 flex items-center justify-center",children:e.jsxs("div",{className:"text-center",children:[e.jsx(Fc,{className:"h-12 w-12 mx-auto mb-4 text-muted-foreground"}),e.jsx("h3",{className:"text-lg font-semibold mb-2",children:"知识库为空"}),e.jsx("p",{className:"text-muted-foreground",children:"请先导入知识数据"})]})}):e.jsxs(e0,{nodes:K,edges:A,onNodesChange:T,onEdgesChange:fe,onNodeClick:Ce,onEdgeClick:ze,nodeTypes:w2,fitView:!0,minZoom:.05,maxZoom:1.5,defaultViewport:{x:0,y:0,zoom:.5},elevateNodesOnSelect:je<=500,nodesDraggable:je<=1e3,attributionPosition:"bottom-left",children:[e.jsx(s0,{variant:t0.Dots,gap:12,size:1}),e.jsx(a0,{}),je<=500&&e.jsx(l0,{nodeColor:q,nodeBorderRadius:8,pannable:!0,zoomable:!0}),e.jsxs(n0,{position:"top-right",className:"bg-background/95 backdrop-blur-sm rounded-lg border p-3 shadow-lg",children:[e.jsx("div",{className:"text-sm font-semibold mb-2",children:"图例"}),e.jsxs("div",{className:"space-y-2 text-xs",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("div",{className:"w-4 h-4 rounded bg-gradient-to-br from-blue-500 to-blue-600 border-2 border-blue-700"}),e.jsx("span",{children:"实体节点"})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("div",{className:"w-4 h-4 rounded bg-gradient-to-br from-green-500 to-green-600 border-2 border-green-700"}),e.jsx("span",{children:"段落节点"})]}),je>200&&e.jsxs("div",{className:"mt-2 pt-2 border-t text-yellow-600 dark:text-yellow-500",children:[e.jsx("div",{className:"font-semibold",children:"性能模式"}),e.jsx("div",{children:"已禁用动画"}),je>500&&e.jsx("div",{children:"已禁用缩略图"})]})]})]})]})}),e.jsx(qs,{open:!!he,onOpenChange:ge=>!ge&&ve(null),children:e.jsxs(Ls,{className:"max-w-2xl max-h-[80vh] overflow-y-auto",children:[e.jsx(Us,{children:e.jsx(Bs,{children:"节点详情"})}),he&&e.jsxs("div",{className:"space-y-4",children:[e.jsx("div",{className:"grid grid-cols-2 gap-4",children:e.jsxs("div",{children:[e.jsx("label",{className:"text-sm font-medium text-muted-foreground",children:"类型"}),e.jsx("div",{className:"mt-1",children:e.jsx(Qe,{variant:he.type==="entity"?"default":"secondary",children:he.type==="entity"?"🏷️ 实体":"📄 段落"})})]})}),e.jsxs("div",{children:[e.jsx("label",{className:"text-sm font-medium text-muted-foreground",children:"ID"}),e.jsx("code",{className:"mt-1 block p-2 bg-muted rounded text-xs break-all",children:he.id})]}),e.jsxs("div",{children:[e.jsx("label",{className:"text-sm font-medium text-muted-foreground",children:"内容"}),e.jsx(Ze,{className:"mt-1 h-40 p-3 bg-muted rounded",children:e.jsx("p",{className:"text-sm whitespace-pre-wrap",children:he.content})})]})]})]})}),e.jsx(qs,{open:!!be,onOpenChange:ge=>!ge&&D(null),children:e.jsxs(Ls,{className:"max-w-2xl max-h-[80vh] overflow-hidden flex flex-col",children:[e.jsx(Us,{children:e.jsx(Bs,{children:"边详情"})}),be&&e.jsx(Ze,{className:"flex-1 pr-4",children:e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"flex items-center gap-4",children:[e.jsxs("div",{className:"flex-1 min-w-0 p-3 bg-blue-50 dark:bg-blue-950 rounded border-2 border-blue-200 dark:border-blue-800",children:[e.jsx("div",{className:"text-xs text-muted-foreground mb-1",children:"源节点"}),e.jsx("div",{className:"font-medium text-sm mb-2 truncate",children:be.source.content}),e.jsxs("code",{className:"text-xs text-muted-foreground truncate block",children:[be.source.id.slice(0,40),"..."]})]}),e.jsx("div",{className:"text-2xl text-muted-foreground flex-shrink-0",children:"→"}),e.jsxs("div",{className:"flex-1 min-w-0 p-3 bg-green-50 dark:bg-green-950 rounded border-2 border-green-200 dark:border-green-800",children:[e.jsx("div",{className:"text-xs text-muted-foreground mb-1",children:"目标节点"}),e.jsx("div",{className:"font-medium text-sm mb-2 truncate",children:be.target.content}),e.jsxs("code",{className:"text-xs text-muted-foreground truncate block",children:[be.target.id.slice(0,40),"..."]})]})]}),e.jsxs("div",{children:[e.jsx("label",{className:"text-sm font-medium text-muted-foreground",children:"权重"}),e.jsx("div",{className:"mt-1",children:e.jsx(Qe,{variant:"outline",className:"text-base font-mono",children:be.edge.weight.toFixed(4)})})]})]})})]})}),e.jsx(hs,{open:U,onOpenChange:O,children:e.jsxs(ls,{children:[e.jsxs(ns,{children:[e.jsx(is,{children:"加载知识图谱"}),e.jsxs(cs,{children:["知识图谱的动态展示会消耗较多系统资源。",e.jsx("br",{}),"确定要加载知识图谱吗?"]})]}),e.jsxs(rs,{children:[e.jsx(ds,{onClick:()=>n({to:"/"}),children:"取消 (返回首页)"}),e.jsx(os,{onClick:me,children:"确认加载"})]})]})}),e.jsx(hs,{open:L,onOpenChange:z,children:e.jsxs(ls,{children:[e.jsxs(ns,{children:[e.jsx(is,{children:"⚠️ 节点数量较多"}),e.jsx(cs,{asChild:!0,children:e.jsxs("div",{children:[e.jsxs("p",{children:["您正在尝试加载 ",e.jsx("strong",{className:"text-orange-600",children:b>=1e4?"全部 (最多10000个)":b})," 个节点。"]}),e.jsx("p",{className:"mt-4",children:"节点数量过多可能导致:"}),e.jsxs("ul",{className:"list-disc list-inside mt-2 space-y-1",children:[e.jsx("li",{children:"页面加载时间较长"}),e.jsx("li",{children:"浏览器卡顿或崩溃"}),e.jsx("li",{children:"系统资源占用过高"})]}),e.jsx("p",{className:"mt-4",children:"建议先选择较少的节点数量 (50-200 个)。"})]})})]}),e.jsxs(rs,{children:[e.jsx(ds,{onClick:()=>{z(!1),b>200&&(j(50),w(!1))},children:"取消"}),e.jsx(os,{onClick:_e,className:"bg-orange-600 hover:bg-orange-700",children:"我了解风险,继续加载"})]})]})})]})}function bp({className:n,classNames:r,showOutsideDays:i=!0,captionLayout:d="label",buttonVariant:m="ghost",formatters:x,components:f,...p}){const g=_g();return e.jsx(Dy,{showOutsideDays:i,className:$("bg-background group/calendar p-3 [--cell-size:2rem] [[data-slot=card-content]_&]:bg-transparent [[data-slot=popover-content]_&]:bg-transparent",String.raw`rtl:**:[.rdp-button\_next>svg]:rotate-180`,String.raw`rtl:**:[.rdp-button\_previous>svg]:rotate-180`,n),captionLayout:d,formatters:{formatMonthDropdown:b=>b.toLocaleString("default",{month:"short"}),...x},classNames:{root:$("w-fit",g.root),months:$("relative flex flex-col gap-4 md:flex-row",g.months),month:$("flex w-full flex-col gap-4",g.month),nav:$("absolute inset-x-0 top-0 flex w-full items-center justify-between gap-1",g.nav),button_previous:$(ui({variant:m}),"h-[--cell-size] w-[--cell-size] select-none p-0 aria-disabled:opacity-50",g.button_previous),button_next:$(ui({variant:m}),"h-[--cell-size] w-[--cell-size] select-none p-0 aria-disabled:opacity-50",g.button_next),month_caption:$("flex h-[--cell-size] w-full items-center justify-center px-[--cell-size]",g.month_caption),dropdowns:$("flex h-[--cell-size] w-full items-center justify-center gap-1.5 text-sm font-medium",g.dropdowns),dropdown_root:$("has-focus:border-ring border-input shadow-xs has-focus:ring-ring/50 has-focus:ring-[3px] relative rounded-md border",g.dropdown_root),dropdown:$("bg-popover absolute inset-0 opacity-0",g.dropdown),caption_label:$("select-none font-medium",d==="label"?"text-sm":"[&>svg]:text-muted-foreground flex h-8 items-center gap-1 rounded-md pl-2 pr-1 text-sm [&>svg]:size-3.5",g.caption_label),table:"w-full border-collapse",weekdays:$("flex",g.weekdays),weekday:$("text-muted-foreground flex-1 select-none rounded-md text-[0.8rem] font-normal",g.weekday),week:$("mt-2 flex w-full",g.week),week_number_header:$("w-[--cell-size] select-none",g.week_number_header),week_number:$("text-muted-foreground select-none text-[0.8rem]",g.week_number),day:$("group/day relative aspect-square h-full w-full select-none p-0 text-center [&:first-child[data-selected=true]_button]:rounded-l-md [&:last-child[data-selected=true]_button]:rounded-r-md",g.day),range_start:$("bg-accent rounded-l-md",g.range_start),range_middle:$("rounded-none",g.range_middle),range_end:$("bg-accent rounded-r-md",g.range_end),today:$("bg-accent text-accent-foreground rounded-md data-[selected=true]:rounded-none",g.today),outside:$("text-muted-foreground aria-selected:text-muted-foreground",g.outside),disabled:$("text-muted-foreground opacity-50",g.disabled),hidden:$("invisible",g.hidden),...r},components:{Root:({className:b,rootRef:j,...y})=>e.jsx("div",{"data-slot":"calendar",ref:j,className:$(b),...y}),Chevron:({className:b,orientation:j,...y})=>j==="left"?e.jsx(il,{className:$("size-4",b),...y}):j==="right"?e.jsx(Ba,{className:$("size-4",b),...y}):e.jsx(Ll,{className:$("size-4",b),...y}),DayButton:C2,WeekNumber:({children:b,...j})=>e.jsx("td",{...j,children:e.jsx("div",{className:"flex size-[--cell-size] items-center justify-center text-center",children:b})}),...f},...p})}function C2({className:n,day:r,modifiers:i,...d}){const m=_g(),x=u.useRef(null);return u.useEffect(()=>{i.focused&&x.current?.focus()},[i.focused]),e.jsx(S,{ref:x,variant:"ghost",size:"icon","data-day":r.date.toLocaleDateString(),"data-selected-single":i.selected&&!i.range_start&&!i.range_end&&!i.range_middle,"data-range-start":i.range_start,"data-range-end":i.range_end,"data-range-middle":i.range_middle,className:$("data-[selected-single=true]:bg-primary data-[selected-single=true]:text-primary-foreground data-[range-middle=true]:bg-accent data-[range-middle=true]:text-accent-foreground data-[range-start=true]:bg-primary data-[range-start=true]:text-primary-foreground data-[range-end=true]:bg-primary data-[range-end=true]:text-primary-foreground group-data-[focused=true]/day:border-ring group-data-[focused=true]/day:ring-ring/50 flex aspect-square h-auto w-full min-w-[--cell-size] flex-col gap-1 font-normal leading-none data-[range-end=true]:rounded-md data-[range-middle=true]:rounded-none data-[range-start=true]:rounded-md group-data-[focused=true]/day:relative group-data-[focused=true]/day:z-10 group-data-[focused=true]/day:ring-[3px] [&>span]:text-xs [&>span]:opacity-70",m.day,n),...d})}const Lc={xs:{label:"小",rowHeight:28,class:"text-[10px] sm:text-xs"},sm:{label:"中",rowHeight:36,class:"text-xs sm:text-sm"},base:{label:"大",rowHeight:44,class:"text-sm sm:text-base"}};function k2(){const[n,r]=u.useState([]),[i,d]=u.useState(""),[m,x]=u.useState("all"),[f,p]=u.useState("all"),[g,b]=u.useState(void 0),[j,y]=u.useState(void 0),[N,k]=u.useState(!0),[w,U]=u.useState(!1),[O,B]=u.useState("xs"),[Y,L]=u.useState(4),z=u.useRef(null);u.useEffect(()=>{const q=tn.getAllLogs();r(q);const se=tn.onLog(()=>{r(tn.getAllLogs())}),R=tn.onConnectionChange(ue=>{U(ue)});return()=>{se(),R()}},[]);const K=u.useMemo(()=>{const q=new Set(n.map(se=>se.module).filter(se=>se&&se.trim()!==""));return Array.from(q).sort()},[n]),I=q=>{switch(q){case"DEBUG":return"text-muted-foreground";case"INFO":return"text-blue-500 dark:text-blue-400";case"WARNING":return"text-yellow-600 dark:text-yellow-500";case"ERROR":return"text-red-600 dark:text-red-500";case"CRITICAL":return"text-red-700 dark:text-red-400 font-bold";default:return"text-foreground"}},T=q=>{switch(q){case"DEBUG":return"bg-gray-800/30 dark:bg-gray-800/50";case"INFO":return"bg-blue-900/20 dark:bg-blue-500/20";case"WARNING":return"bg-yellow-900/20 dark:bg-yellow-500/20";case"ERROR":return"bg-red-900/20 dark:bg-red-500/20";case"CRITICAL":return"bg-red-900/30 dark:bg-red-600/30";default:return"bg-gray-800/20 dark:bg-gray-800/30"}},A=()=>{window.location.reload()},te=()=>{tn.clearLogs(),r([])},fe=()=>{const q=he.map(me=>`${me.timestamp} [${me.level.padEnd(8)}] [${me.module}] ${me.message}`).join(` -`),se=new Blob([q],{type:"text/plain;charset=utf-8"}),R=URL.createObjectURL(se),ue=document.createElement("a");ue.href=R,ue.download=`logs-${ju(new Date,"yyyy-MM-dd-HHmmss")}.txt`,ue.click(),URL.revokeObjectURL(R)},je=()=>{k(!N)},pe=()=>{b(void 0),y(void 0)},he=u.useMemo(()=>n.filter(q=>{const se=i===""||q.message.toLowerCase().includes(i.toLowerCase())||q.module.toLowerCase().includes(i.toLowerCase()),R=m==="all"||q.level===m,ue=f==="all"||q.module===f;let me=!0;if(g||j){const _e=new Date(q.timestamp);if(g){const Ce=new Date(g);Ce.setHours(0,0,0,0),me=me&&_e>=Ce}if(j){const Ce=new Date(j);Ce.setHours(23,59,59,999),me=me&&_e<=Ce}}return se&&R&&ue&&me}),[n,i,m,f,g,j]),ve=Lc[O].rowHeight+Y,be=Bb({count:he.length,getScrollElement:()=>z.current,estimateSize:()=>ve,overscan:50}),D=u.useRef(!1),J=u.useRef(he.length);return u.useEffect(()=>{const q=z.current;if(!q)return;const se=()=>{if(D.current)return;const{scrollTop:R,scrollHeight:ue,clientHeight:me}=q,_e=ue-R-me;_e>100&&N?k(!1):_e<50&&!N&&k(!0)};return q.addEventListener("scroll",se,{passive:!0}),()=>q.removeEventListener("scroll",se)},[N]),u.useEffect(()=>{const q=he.length>J.current;J.current=he.length,N&&he.length>0&&q&&(D.current=!0,be.scrollToIndex(he.length-1,{align:"end",behavior:"auto"}),requestAnimationFrame(()=>{requestAnimationFrame(()=>{D.current=!1})}))},[he.length,N,be]),e.jsxs("div",{className:"h-full flex flex-col overflow-hidden",children:[e.jsxs("div",{className:"flex-shrink-0 space-y-4 p-3 sm:p-4 lg:p-6",children:[e.jsxs("div",{className:"flex flex-col sm:flex-row sm:items-center justify-between gap-3",children:[e.jsxs("div",{children:[e.jsx("h1",{className:"text-xl sm:text-2xl lg:text-3xl font-bold",children:"日志查看器"}),e.jsx("p",{className:"text-xs sm:text-sm text-muted-foreground mt-1",children:"实时查看和分析麦麦运行日志"})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("div",{className:$("h-2.5 w-2.5 sm:h-3 sm:w-3 rounded-full",w?"bg-green-500 animate-pulse":"bg-red-500")}),e.jsx("span",{className:"text-xs sm:text-sm text-muted-foreground",children:w?"已连接":"未连接"})]})]}),e.jsx(Fe,{className:"p-3 sm:p-4",children:e.jsxs("div",{className:"flex flex-col gap-3 sm:gap-4",children:[e.jsxs("div",{className:"flex flex-col gap-3 sm:flex-row sm:gap-4",children:[e.jsxs("div",{className:"flex-1 relative",children:[e.jsx(Mt,{className:"absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground"}),e.jsx(ie,{placeholder:"搜索日志...",value:i,onChange:q=>d(q.target.value),className:"pl-9 h-9 text-sm"})]}),e.jsxs(Ue,{value:m,onValueChange:x,children:[e.jsxs(Oe,{className:"w-full sm:w-[140px] lg:w-[180px] h-9 text-sm",children:[e.jsx(Ou,{className:"h-4 w-4 mr-2"}),e.jsx(Be,{placeholder:"级别"})]}),e.jsxs(Re,{children:[e.jsx(le,{value:"all",children:"全部级别"}),e.jsx(le,{value:"DEBUG",children:"DEBUG"}),e.jsx(le,{value:"INFO",children:"INFO"}),e.jsx(le,{value:"WARNING",children:"WARNING"}),e.jsx(le,{value:"ERROR",children:"ERROR"}),e.jsx(le,{value:"CRITICAL",children:"CRITICAL"})]})]}),e.jsxs(Ue,{value:f,onValueChange:p,children:[e.jsxs(Oe,{className:"w-full sm:w-[160px] lg:w-[200px] h-9 text-sm",children:[e.jsx(Ou,{className:"h-4 w-4 mr-2"}),e.jsx(Be,{placeholder:"模块"})]}),e.jsxs(Re,{children:[e.jsx(le,{value:"all",children:"全部模块"}),K.map(q=>e.jsx(le,{value:q,children:q},q))]})]})]}),e.jsxs("div",{className:"flex flex-col gap-2 sm:flex-row sm:gap-4",children:[e.jsxs(La,{children:[e.jsx(Ua,{asChild:!0,children:e.jsxs(S,{variant:"outline",size:"sm",className:$("w-full sm:w-[200px] lg:w-[240px] justify-start text-left font-normal h-9",!g&&"text-muted-foreground"),children:[e.jsx(Zf,{className:"mr-2 h-4 w-4"}),e.jsx("span",{className:"text-xs sm:text-sm",children:g?ju(g,"PPP",{locale:Rc}):"开始日期"})]})}),e.jsx(ka,{className:"w-auto p-0",align:"start",children:e.jsx(bp,{mode:"single",selected:g,onSelect:b,initialFocus:!0,locale:Rc})})]}),e.jsxs(La,{children:[e.jsx(Ua,{asChild:!0,children:e.jsxs(S,{variant:"outline",size:"sm",className:$("w-full sm:w-[200px] lg:w-[240px] justify-start text-left font-normal h-9",!j&&"text-muted-foreground"),children:[e.jsx(Zf,{className:"mr-2 h-4 w-4"}),e.jsx("span",{className:"text-xs sm:text-sm",children:j?ju(j,"PPP",{locale:Rc}):"结束日期"})]})}),e.jsx(ka,{className:"w-auto p-0",align:"start",children:e.jsx(bp,{mode:"single",selected:j,onSelect:y,initialFocus:!0,locale:Rc})})]}),(g||j)&&e.jsxs(S,{variant:"outline",size:"sm",onClick:pe,className:"w-full sm:w-auto h-9",children:[e.jsx(rl,{className:"h-4 w-4 sm:mr-2"}),e.jsx("span",{className:"hidden sm:inline text-sm",children:"清除时间筛选"}),e.jsx("span",{className:"sm:hidden text-sm",children:"清除"})]})]}),e.jsxs("div",{className:"flex flex-col gap-2 sm:flex-row sm:flex-wrap sm:items-center",children:[e.jsxs("div",{className:"flex gap-2 flex-wrap",children:[e.jsxs(S,{variant:N?"default":"outline",size:"sm",onClick:je,className:"flex-1 sm:flex-none h-9",children:[N?e.jsx(my,{className:"h-4 w-4"}):e.jsx(xy,{className:"h-4 w-4"}),e.jsx("span",{className:"ml-2 text-sm",children:N?"自动滚动":"已暂停"})]}),e.jsxs(S,{variant:"outline",size:"sm",onClick:A,className:"flex-1 sm:flex-none h-9",children:[e.jsx(zt,{className:"h-4 w-4"}),e.jsx("span",{className:"ml-2 text-sm",children:"刷新"})]}),e.jsxs(S,{variant:"outline",size:"sm",onClick:te,className:"flex-1 sm:flex-none h-9",children:[e.jsx(We,{className:"h-4 w-4"}),e.jsx("span",{className:"ml-2 text-sm",children:"清空"})]}),e.jsxs(S,{variant:"outline",size:"sm",onClick:fe,className:"flex-1 sm:flex-none h-9",children:[e.jsx(Oa,{className:"h-4 w-4"}),e.jsx("span",{className:"ml-2 text-sm",children:"导出"})]})]}),e.jsx("div",{className:"flex-1 hidden sm:block"}),e.jsxs("div",{className:"text-xs sm:text-sm text-muted-foreground flex items-center justify-center sm:justify-end",children:[e.jsxs("span",{className:"font-mono",children:[he.length," / ",n.length]}),e.jsx("span",{className:"ml-1",children:"条日志"})]})]}),e.jsxs("div",{className:"flex flex-col gap-3 sm:flex-row sm:items-center sm:gap-6 pt-2 border-t border-border/50",children:[e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsxs("div",{className:"flex items-center gap-2 text-sm text-muted-foreground",children:[e.jsx(hy,{className:"h-4 w-4"}),e.jsx("span",{children:"字号"})]}),e.jsx("div",{className:"flex gap-1",children:Object.keys(Lc).map(q=>e.jsx(S,{variant:O===q?"default":"outline",size:"sm",onClick:()=>B(q),className:"h-7 px-3 text-xs",children:Lc[q].label},q))})]}),e.jsxs("div",{className:"flex items-center gap-3 flex-1 max-w-xs",children:[e.jsx("span",{className:"text-sm text-muted-foreground whitespace-nowrap",children:"行距"}),e.jsx(pa,{value:[Y],onValueChange:([q])=>L(q),min:0,max:12,step:2,className:"flex-1"}),e.jsxs("span",{className:"text-xs text-muted-foreground w-8",children:[Y,"px"]})]})]})]})})]}),e.jsx("div",{className:"flex-1 min-h-0 px-3 sm:px-4 lg:px-6 pb-3 sm:pb-4 lg:pb-6",children:e.jsx(Fe,{className:"bg-black dark:bg-gray-950 border-gray-800 dark:border-gray-900 h-full overflow-hidden",children:e.jsx("div",{ref:z,className:$("h-full overflow-auto","[&::-webkit-scrollbar]:w-2.5","[&::-webkit-scrollbar-track]:bg-transparent","[&::-webkit-scrollbar-thumb]:bg-border [&::-webkit-scrollbar-thumb]:rounded-full","[&::-webkit-scrollbar-thumb:hover]:bg-border/80"),children:e.jsx("div",{className:$("p-2 sm:p-3 font-mono relative",Lc[O].class),style:{height:`${be.getTotalSize()}px`},children:he.length===0?e.jsx("div",{className:"text-gray-500 dark:text-gray-600 text-center py-8 text-sm",children:"暂无日志数据"}):be.getVirtualItems().map(q=>{const se=he[q.index];return e.jsxs("div",{"data-index":q.index,ref:be.measureElement,className:$("absolute top-0 left-0 w-full px-2 sm:px-3 rounded hover:bg-white/5 transition-colors group",T(se.level)),style:{transform:`translateY(${q.start}px)`,paddingTop:`${Y/2}px`,paddingBottom:`${Y/2}px`},children:[e.jsxs("div",{className:"flex flex-col gap-0.5 sm:hidden",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:"text-gray-500 dark:text-gray-600",children:se.timestamp}),e.jsxs("span",{className:$("font-semibold",I(se.level)),children:["[",se.level,"]"]})]}),e.jsx("div",{className:"text-cyan-400 dark:text-cyan-500 truncate",children:se.module}),e.jsx("div",{className:"text-gray-300 dark:text-gray-400 whitespace-pre-wrap break-words",children:se.message})]}),e.jsxs("div",{className:"hidden sm:flex gap-2 items-start",children:[e.jsx("span",{className:"text-gray-500 dark:text-gray-600 flex-shrink-0 w-[130px] lg:w-[160px]",children:se.timestamp}),e.jsxs("span",{className:$("flex-shrink-0 w-[65px] lg:w-[75px] font-semibold",I(se.level)),children:["[",se.level,"]"]}),e.jsx("span",{className:"text-cyan-400 dark:text-cyan-500 flex-shrink-0 w-[100px] lg:w-[130px] truncate",children:se.module}),e.jsx("span",{className:"text-gray-300 dark:text-gray-400 flex-1 whitespace-pre-wrap break-words",children:se.message})]})]},q.key)})})})})})]})}const T2="Mai-with-u",E2="plugin-repo",z2="main",A2="plugin_details.json";async function M2(){try{const n=await Se("/api/webui/plugins/fetch-raw",{method:"POST",body:JSON.stringify({owner:T2,repo:E2,branch:z2,file_path:A2})});if(!n.ok)throw new Error(`HTTP error! status: ${n.status}`);const r=await n.json();if(!r.success||!r.data)throw new Error(r.error||"获取插件列表失败");return JSON.parse(r.data).filter(m=>!m?.id||!m?.manifest?(console.warn("跳过无效插件数据:",m),!1):!m.manifest.name||!m.manifest.version?(console.warn("跳过缺少必需字段的插件:",m.id),!1):!0).map(m=>({id:m.id,manifest:{manifest_version:m.manifest.manifest_version||1,name:m.manifest.name,version:m.manifest.version,description:m.manifest.description||"",author:m.manifest.author||{name:"Unknown"},license:m.manifest.license||"Unknown",host_application:m.manifest.host_application||{min_version:"0.0.0"},homepage_url:m.manifest.homepage_url,repository_url:m.manifest.repository_url,keywords:m.manifest.keywords||[],categories:m.manifest.categories||[],default_locale:m.manifest.default_locale||"zh-CN",locales_path:m.manifest.locales_path},downloads:0,rating:0,review_count:0,installed:!1,published_at:new Date().toISOString(),updated_at:new Date().toISOString()}))}catch(n){throw console.error("Failed to fetch plugin list:",n),n}}async function D2(){try{const n=await Se("/api/webui/plugins/git-status");if(!n.ok)throw new Error(`HTTP error! status: ${n.status}`);return await n.json()}catch(n){return console.error("Failed to check Git status:",n),{installed:!1,error:"无法检测 Git 安装状态"}}}async function O2(){try{const n=await Se("/api/webui/plugins/version");if(!n.ok)throw new Error(`HTTP error! status: ${n.status}`);return await n.json()}catch(n){return console.error("Failed to get Maimai version:",n),{version:"0.0.0",version_major:0,version_minor:0,version_patch:0}}}function R2(n,r,i){const d=n.split(".").map(p=>parseInt(p)||0),m=d[0]||0,x=d[1]||0,f=d[2]||0;if(i.version_majorparseInt(y)||0),g=p[0]||0,b=p[1]||0,j=p[2]||0;if(i.version_major>g||i.version_major===g&&i.version_minor>b||i.version_major===g&&i.version_minor===b&&i.version_patch>j)return!1}return!0}function L2(n,r){const i=window.location.protocol==="https:"?"wss:":"ws:",d=window.location.host,m=new WebSocket(`${i}//${d}/api/webui/ws/plugin-progress`);return m.onopen=()=>{console.log("Plugin progress WebSocket connected");const x=setInterval(()=>{m.readyState===WebSocket.OPEN?m.send("ping"):clearInterval(x)},3e4)},m.onmessage=x=>{try{if(x.data==="pong")return;const f=JSON.parse(x.data);n(f)}catch(f){console.error("Failed to parse progress data:",f)}},m.onerror=x=>{console.error("Plugin progress WebSocket error:",x),r?.(x)},m.onclose=()=>{console.log("Plugin progress WebSocket disconnected")},m}async function li(){try{const n=await Se("/api/webui/plugins/installed",{headers:Gs()});if(!n.ok)throw new Error(`HTTP error! status: ${n.status}`);const r=await n.json();if(!r.success)throw new Error(r.message||"获取已安装插件列表失败");return r.plugins||[]}catch(n){return console.error("Failed to get installed plugins:",n),[]}}function Uc(n,r){return r.some(i=>i.id===n)}function Bc(n,r){const i=r.find(d=>d.id===n);if(i)return i.manifest?.version||i.version}async function U2(n,r,i="main"){const d=await Se("/api/webui/plugins/install",{method:"POST",body:JSON.stringify({plugin_id:n,repository_url:r,branch:i})});if(!d.ok){const m=await d.json();throw new Error(m.detail||"安装失败")}return await d.json()}async function B2(n){const r=await Se("/api/webui/plugins/uninstall",{method:"POST",body:JSON.stringify({plugin_id:n})});if(!r.ok){const i=await r.json();throw new Error(i.detail||"卸载失败")}return await r.json()}async function H2(n,r,i="main"){const d=await Se("/api/webui/plugins/update",{method:"POST",body:JSON.stringify({plugin_id:n,repository_url:r,branch:i})});if(!d.ok){const m=await d.json();throw new Error(m.detail||"更新失败")}return await d.json()}async function q2(n){const r=await Se(`/api/webui/plugins/config/${n}/schema`,{headers:Gs()});if(!r.ok){const d=await r.json();throw new Error(d.detail||"获取配置 Schema 失败")}const i=await r.json();if(!i.success)throw new Error(i.message||"获取配置 Schema 失败");return i.schema}async function G2(n){const r=await Se(`/api/webui/plugins/config/${n}`,{headers:Gs()});if(!r.ok){const d=await r.json();throw new Error(d.detail||"获取配置失败")}const i=await r.json();if(!i.success)throw new Error(i.message||"获取配置失败");return i.config}async function $2(n,r){const i=await Se(`/api/webui/plugins/config/${n}`,{method:"PUT",body:JSON.stringify({config:r})});if(!i.ok){const d=await i.json();throw new Error(d.detail||"保存配置失败")}return await i.json()}async function F2(n){const r=await Se(`/api/webui/plugins/config/${n}/reset`,{method:"POST",headers:Gs()});if(!r.ok){const i=await r.json();throw new Error(i.detail||"重置配置失败")}return await r.json()}async function V2(n){const r=await Se(`/api/webui/plugins/config/${n}/toggle`,{method:"POST",headers:Gs()});if(!r.ok){const i=await r.json();throw new Error(i.detail||"切换状态失败")}return await r.json()}const pi="https://maibot-plugin-stats.maibot-webui.workers.dev";async function Jg(n){try{const r=await fetch(`${pi}/stats/${n}`);return r.ok?await r.json():(console.error("Failed to fetch plugin stats:",r.statusText),null)}catch(r){return console.error("Error fetching plugin stats:",r),null}}async function Q2(n,r){try{const i=r||em(),d=await fetch(`${pi}/stats/like`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({plugin_id:n,user_id:i})}),m=await d.json();return d.status===429?{success:!1,error:"操作过于频繁,请稍后再试"}:d.ok?{success:!0,...m}:{success:!1,error:m.error||"点赞失败"}}catch(i){return console.error("Error liking plugin:",i),{success:!1,error:"网络错误"}}}async function I2(n,r){try{const i=r||em(),d=await fetch(`${pi}/stats/dislike`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({plugin_id:n,user_id:i})}),m=await d.json();return d.status===429?{success:!1,error:"操作过于频繁,请稍后再试"}:d.ok?{success:!0,...m}:{success:!1,error:m.error||"点踩失败"}}catch(i){return console.error("Error disliking plugin:",i),{success:!1,error:"网络错误"}}}async function Y2(n,r,i,d){if(r<1||r>5)return{success:!1,error:"评分必须在 1-5 之间"};try{const m=d||em(),x=await fetch(`${pi}/stats/rate`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({plugin_id:n,rating:r,comment:i,user_id:m})}),f=await x.json();return x.status===429?{success:!1,error:"每天最多评分 3 次"}:x.ok?{success:!0,...f}:{success:!1,error:f.error||"评分失败"}}catch(m){return console.error("Error rating plugin:",m),{success:!1,error:"网络错误"}}}async function K2(n){try{const r=await fetch(`${pi}/stats/download`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({plugin_id:n})}),i=await r.json();return r.status===429?(console.warn("Download recording rate limited"),{success:!0}):r.ok?{success:!0,...i}:(console.error("Failed to record download:",i.error),{success:!1,error:i.error})}catch(r){return console.error("Error recording download:",r),{success:!1,error:"网络错误"}}}function X2(){const n=navigator,r=[navigator.userAgent,navigator.language,navigator.languages?.join(",")||"",navigator.platform,navigator.hardwareConcurrency||0,screen.width,screen.height,screen.colorDepth,screen.pixelDepth,new Date().getTimezoneOffset(),Intl.DateTimeFormat().resolvedOptions().timeZone,navigator.maxTouchPoints||0,n.deviceMemory||0].join("|");let i=0;for(let d=0;d{x(!0);const B=await Jg(n);B&&d(B),x(!1)};u.useEffect(()=>{k()},[n]);const w=async()=>{const B=await Q2(n);B.success?(N({title:"已点赞",description:"感谢你的支持!"}),k()):N({title:"点赞失败",description:B.error||"未知错误",variant:"destructive"})},U=async()=>{const B=await I2(n);B.success?(N({title:"已反馈",description:"感谢你的反馈!"}),k()):N({title:"操作失败",description:B.error||"未知错误",variant:"destructive"})},O=async()=>{if(f===0){N({title:"请选择评分",description:"至少选择 1 颗星",variant:"destructive"});return}const B=await Y2(n,f,g||void 0);B.success?(N({title:"评分成功",description:"感谢你的评价!"}),y(!1),p(0),b(""),k()):N({title:"评分失败",description:B.error||"未知错误",variant:"destructive"})};return m?e.jsxs("div",{className:"flex items-center gap-4 text-sm text-muted-foreground",children:[e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx(Oa,{className:"h-4 w-4"}),e.jsx("span",{children:"-"})]}),e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx(nl,{className:"h-4 w-4"}),e.jsx("span",{children:"-"})]})]}):i?r?e.jsxs("div",{className:"flex items-center gap-4 text-sm text-muted-foreground",children:[e.jsxs("div",{className:"flex items-center gap-1",title:`下载量: ${i.downloads.toLocaleString()}`,children:[e.jsx(Oa,{className:"h-4 w-4"}),e.jsx("span",{children:i.downloads.toLocaleString()})]}),e.jsxs("div",{className:"flex items-center gap-1",title:`评分: ${i.rating.toFixed(1)} (${i.rating_count} 条评价)`,children:[e.jsx(nl,{className:"h-4 w-4 fill-yellow-400 text-yellow-400"}),e.jsx("span",{children:i.rating.toFixed(1)})]}),e.jsxs("div",{className:"flex items-center gap-1",title:`点赞数: ${i.likes}`,children:[e.jsx(bu,{className:"h-4 w-4"}),e.jsx("span",{children:i.likes})]})]}):e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"grid grid-cols-2 sm:grid-cols-4 gap-4",children:[e.jsxs("div",{className:"flex flex-col items-center p-3 rounded-lg border bg-card",children:[e.jsx(Oa,{className:"h-5 w-5 text-muted-foreground mb-1"}),e.jsx("span",{className:"text-2xl font-bold",children:i.downloads.toLocaleString()}),e.jsx("span",{className:"text-xs text-muted-foreground",children:"下载量"})]}),e.jsxs("div",{className:"flex flex-col items-center p-3 rounded-lg border bg-card",children:[e.jsx(nl,{className:"h-5 w-5 text-yellow-400 mb-1 fill-yellow-400"}),e.jsx("span",{className:"text-2xl font-bold",children:i.rating.toFixed(1)}),e.jsxs("span",{className:"text-xs text-muted-foreground",children:[i.rating_count," 条评价"]})]}),e.jsxs("div",{className:"flex flex-col items-center p-3 rounded-lg border bg-card",children:[e.jsx(bu,{className:"h-5 w-5 text-green-500 mb-1"}),e.jsx("span",{className:"text-2xl font-bold",children:i.likes}),e.jsx("span",{className:"text-xs text-muted-foreground",children:"点赞"})]}),e.jsxs("div",{className:"flex flex-col items-center p-3 rounded-lg border bg-card",children:[e.jsx(Pf,{className:"h-5 w-5 text-red-500 mb-1"}),e.jsx("span",{className:"text-2xl font-bold",children:i.dislikes}),e.jsx("span",{className:"text-xs text-muted-foreground",children:"点踩"})]})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsxs(S,{variant:"outline",size:"sm",onClick:w,children:[e.jsx(bu,{className:"h-4 w-4 mr-1"}),"点赞"]}),e.jsxs(S,{variant:"outline",size:"sm",onClick:U,children:[e.jsx(Pf,{className:"h-4 w-4 mr-1"}),"点踩"]}),e.jsxs(qs,{open:j,onOpenChange:y,children:[e.jsx(Xu,{asChild:!0,children:e.jsxs(S,{variant:"default",size:"sm",children:[e.jsx(nl,{className:"h-4 w-4 mr-1"}),"评分"]})}),e.jsxs(Ls,{children:[e.jsxs(Us,{children:[e.jsx(Bs,{children:"为插件评分"}),e.jsx(Ps,{children:"分享你的使用体验,帮助其他用户"})]}),e.jsxs("div",{className:"space-y-4 py-4",children:[e.jsxs("div",{className:"flex flex-col items-center gap-2",children:[e.jsx("div",{className:"flex gap-2",children:[1,2,3,4,5].map(B=>e.jsx("button",{onClick:()=>p(B),className:"focus:outline-none",children:e.jsx(nl,{className:`h-8 w-8 transition-colors ${B<=f?"fill-yellow-400 text-yellow-400":"text-muted-foreground hover:text-yellow-300"}`})},B))}),e.jsxs("span",{className:"text-sm text-muted-foreground",children:[f===0&&"点击星星进行评分",f===1&&"很差",f===2&&"一般",f===3&&"还行",f===4&&"不错",f===5&&"非常好"]})]}),e.jsxs("div",{children:[e.jsx("label",{className:"text-sm font-medium mb-2 block",children:"评论(可选)"}),e.jsx(Qs,{value:g,onChange:B=>b(B.target.value),placeholder:"分享你的使用体验...",rows:4,maxLength:500}),e.jsxs("div",{className:"text-xs text-muted-foreground mt-1 text-right",children:[g.length," / 500"]})]})]}),e.jsxs(st,{children:[e.jsx(S,{variant:"outline",onClick:()=>y(!1),children:"取消"}),e.jsx(S,{onClick:O,disabled:f===0,children:"提交评分"})]})]})]})]}),i.recent_ratings&&i.recent_ratings.length>0&&e.jsxs("div",{className:"space-y-2",children:[e.jsx("h4",{className:"text-sm font-semibold",children:"最近评价"}),e.jsx("div",{className:"space-y-3",children:i.recent_ratings.map((B,Y)=>e.jsxs("div",{className:"p-3 rounded-lg border bg-muted/50",children:[e.jsxs("div",{className:"flex items-center justify-between mb-2",children:[e.jsx("div",{className:"flex gap-1",children:[1,2,3,4,5].map(L=>e.jsx(nl,{className:`h-3 w-3 ${L<=B.rating?"fill-yellow-400 text-yellow-400":"text-muted-foreground"}`},L))}),e.jsx("span",{className:"text-xs text-muted-foreground",children:new Date(B.created_at).toLocaleDateString()})]}),B.comment&&e.jsx("p",{className:"text-sm text-muted-foreground",children:B.comment})]},Y))})]})]}):null}const Np={"Group Management":"群组管理","Entertainment & Interaction":"娱乐互动","Utility Tools":"实用工具","Content Generation":"内容生成",Multimedia:"多媒体","External Integration":"外部集成","Data Analysis & Insights":"数据分析与洞察",Other:"其他"};function Z2(){const n=va(),[r,i]=u.useState(null),[d,m]=u.useState(""),[x,f]=u.useState("all"),[p,g]=u.useState("all"),[b,j]=u.useState(!0),[y,N]=u.useState([]),[k,w]=u.useState(!0),[U,O]=u.useState(null),[B,Y]=u.useState(null),[L,z]=u.useState(null),[K,I]=u.useState(null),[,T]=u.useState([]),[A,te]=u.useState({}),[fe,je]=u.useState(!1),[pe,he]=u.useState(null),[ve,be]=u.useState("main"),[D,J]=u.useState(""),[q,se]=u.useState("preset"),[R,ue]=u.useState(!1),{toast:me}=$s(),_e=async E=>{const xe=E.map(async Q=>{try{const Ne=await Jg(Q.id);return{id:Q.id,stats:Ne}}catch(Ne){return console.warn(`Failed to load stats for ${Q.id}:`,Ne),{id:Q.id,stats:null}}}),Ye=await Promise.all(xe),ke={};Ye.forEach(({id:Q,stats:Ne})=>{Ne&&(ke[Q]=Ne)}),te(ke)};u.useEffect(()=>{let E=null,xe=!1;return(async()=>{if(E=L2(ke=>{xe||(z(ke),ke.stage==="success"?setTimeout(()=>{xe||z(null)},2e3):ke.stage==="error"&&(w(!1),O(ke.error||"加载失败")))},ke=>{console.error("WebSocket error:",ke),xe||me({title:"WebSocket 连接失败",description:"无法实时显示加载进度",variant:"destructive"})}),await new Promise(ke=>{if(!E){ke();return}const Q=()=>{E&&E.readyState===WebSocket.OPEN?(console.log("WebSocket connected, starting to load plugins"),ke()):E&&E.readyState===WebSocket.CLOSED?(console.warn("WebSocket closed before loading plugins"),ke()):setTimeout(Q,100)};Q()}),!xe){const ke=await D2();Y(ke),ke.installed||me({title:"Git 未安装",description:ke.error||"请先安装 Git 才能使用插件安装功能",variant:"destructive"})}if(!xe){const ke=await O2();I(ke)}if(!xe)try{w(!0),O(null);const ke=await M2();if(!xe){const Q=await li();T(Q);const Ne=ke.map(qe=>{const Fs=Uc(qe.id,Q),ks=Bc(qe.id,Q);return{...qe,installed:Fs,installed_version:ks}});for(const qe of Q)!Ne.some(ks=>ks.id===qe.id)&&qe.manifest&&Ne.push({id:qe.id,manifest:{manifest_version:qe.manifest.manifest_version||1,name:qe.manifest.name,version:qe.manifest.version,description:qe.manifest.description||"",author:qe.manifest.author,license:qe.manifest.license||"Unknown",host_application:qe.manifest.host_application,homepage_url:qe.manifest.homepage_url,repository_url:qe.manifest.repository_url,keywords:qe.manifest.keywords||[],categories:qe.manifest.categories||[],default_locale:qe.manifest.default_locale||"zh-CN",locales_path:qe.manifest.locales_path},downloads:0,rating:0,review_count:0,installed:!0,installed_version:qe.manifest.version,published_at:new Date().toISOString(),updated_at:new Date().toISOString()});N(Ne),_e(Ne)}}catch(ke){if(!xe){const Q=ke instanceof Error?ke.message:"加载插件列表失败";O(Q),me({title:"加载失败",description:Q,variant:"destructive"})}}finally{xe||w(!1)}})(),()=>{xe=!0,E&&E.close()}},[me]);const Ce=E=>{if(!E.installed&&K&&!ze(E))return e.jsxs(Qe,{variant:"destructive",className:"gap-1",children:[e.jsx(At,{className:"h-3 w-3"}),"不兼容"]});if(E.installed){const xe=E.installed_version?.trim(),Ye=E.manifest.version?.trim();if(xe!==Ye){const ke=xe?.split(".").map(Number)||[0,0,0],Q=Ye?.split(".").map(Number)||[0,0,0];for(let Ne=0;Ne<3;Ne++){if((Q[Ne]||0)>(ke[Ne]||0))return e.jsxs(Qe,{variant:"outline",className:"gap-1 text-orange-600 border-orange-600",children:[e.jsx(At,{className:"h-3 w-3"}),"可更新"]});if((Q[Ne]||0)<(ke[Ne]||0))break}}return e.jsxs(Qe,{variant:"default",className:"gap-1",children:[e.jsx(aa,{className:"h-3 w-3"}),"已安装"]})}return null},ze=E=>!K||!E.manifest?.host_application?!0:R2(E.manifest.host_application.min_version,E.manifest.host_application.max_version,K),ge=E=>{if(!E.installed||!E.installed_version||!E.manifest?.version)return!1;const xe=E.installed_version.trim(),Ye=E.manifest.version.trim();if(xe===Ye)return!1;const ke=xe.split(".").map(Number),Q=Ye.split(".").map(Number);for(let Ne=0;Ne<3;Ne++){if((Q[Ne]||0)>(ke[Ne]||0))return!0;if((Q[Ne]||0)<(ke[Ne]||0))return!1}return!1},ae=y.filter(E=>{if(!E.manifest)return console.warn("[过滤] 跳过无 manifest 的插件:",E.id),!1;const xe=d===""||E.manifest.name?.toLowerCase().includes(d.toLowerCase())||E.manifest.description?.toLowerCase().includes(d.toLowerCase())||E.manifest.keywords&&E.manifest.keywords.some(Ne=>Ne.toLowerCase().includes(d.toLowerCase())),Ye=x==="all"||E.manifest.categories&&E.manifest.categories.includes(x);let ke=!0;p==="installed"?ke=E.installed===!0:p==="updates"&&(ke=E.installed===!0&&ge(E));const Q=!b||!K||ze(E);return xe&&Ye&&ke&&Q}),re=()=>{i(null)},F=E=>{if(!B?.installed){me({title:"无法安装",description:"Git 未安装",variant:"destructive"});return}if(K&&!ze(E)){me({title:"无法安装",description:"插件与当前麦麦版本不兼容",variant:"destructive"});return}he(E),be("main"),J(""),se("preset"),ue(!1),je(!0)},P=async()=>{if(!pe)return;const E=q==="custom"?D:ve;if(!E||E.trim()===""){me({title:"分支名称不能为空",variant:"destructive"});return}try{je(!1),await U2(pe.id,pe.manifest.repository_url||"",E),K2(pe.id).catch(Ye=>{console.warn("Failed to record download:",Ye)}),me({title:"安装成功",description:`${pe.manifest.name} 已成功安装`});const xe=await li();T(xe),N(Ye=>Ye.map(ke=>{if(ke.id===pe.id){const Q=Uc(ke.id,xe),Ne=Bc(ke.id,xe);return{...ke,installed:Q,installed_version:Ne}}return ke}))}catch(xe){me({title:"安装失败",description:xe instanceof Error?xe.message:"未知错误",variant:"destructive"})}finally{he(null)}},Te=async E=>{try{await B2(E.id),me({title:"卸载成功",description:`${E.manifest.name} 已成功卸载`});const xe=await li();T(xe),N(Ye=>Ye.map(ke=>{if(ke.id===E.id){const Q=Uc(ke.id,xe),Ne=Bc(ke.id,xe);return{...ke,installed:Q,installed_version:Ne}}return ke}))}catch(xe){me({title:"卸载失败",description:xe instanceof Error?xe.message:"未知错误",variant:"destructive"})}},Le=async E=>{if(!B?.installed){me({title:"无法更新",description:"Git 未安装",variant:"destructive"});return}try{const xe=await H2(E.id,E.manifest.repository_url||"","main");me({title:"更新成功",description:`${E.manifest.name} 已从 ${xe.old_version} 更新到 ${xe.new_version}`});const Ye=await li();T(Ye),N(ke=>ke.map(Q=>{if(Q.id===E.id){const Ne=Uc(Q.id,Ye),qe=Bc(Q.id,Ye);return{...Q,installed:Ne,installed_version:qe}}return Q}))}catch(xe){me({title:"更新失败",description:xe instanceof Error?xe.message:"未知错误",variant:"destructive"})}};return e.jsx(Ze,{className:"h-full",children:e.jsxs("div",{className:"space-y-6 p-4 sm:p-6",children:[e.jsxs("div",{className:"flex flex-col sm:flex-row sm:items-start sm:justify-between gap-4",children:[e.jsxs("div",{children:[e.jsx("h1",{className:"text-2xl sm:text-3xl font-bold",children:"插件市场"}),e.jsx("p",{className:"text-muted-foreground mt-2",children:"浏览和管理麦麦的插件"})]}),e.jsxs(S,{onClick:()=>n({to:"/plugin-mirrors"}),children:[e.jsx(fy,{className:"h-4 w-4 mr-2"}),"配置镜像源"]})]}),B&&!B.installed&&e.jsxs(Fe,{className:"border-orange-600 bg-orange-50 dark:bg-orange-950/20",children:[e.jsx(ts,{children:e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx(Ca,{className:"h-5 w-5 text-orange-600"}),e.jsxs("div",{children:[e.jsx(as,{className:"text-lg text-orange-900 dark:text-orange-100",children:"Git 未安装"}),e.jsx(et,{className:"text-orange-800 dark:text-orange-200",children:B.error||"请先安装 Git 才能使用插件安装功能"})]})]})}),e.jsx(xs,{children:e.jsxs("p",{className:"text-sm text-orange-800 dark:text-orange-200",children:["您可以从 ",e.jsx("a",{href:"https://git-scm.com/downloads",target:"_blank",rel:"noopener noreferrer",className:"underline font-medium",children:"git-scm.com"})," 下载并安装 Git。 安装完成后,请重启麦麦应用。"]})})]}),e.jsx(Fe,{className:"p-4",children:e.jsxs("div",{className:"flex flex-col gap-4",children:[e.jsxs("div",{className:"flex flex-col sm:flex-row gap-4",children:[e.jsxs("div",{className:"flex-1 relative",children:[e.jsx(Mt,{className:"absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground"}),e.jsx(ie,{placeholder:"搜索插件...",value:d,onChange:E=>m(E.target.value),className:"pl-9"})]}),e.jsxs(Ue,{value:x,onValueChange:f,children:[e.jsx(Oe,{className:"w-full sm:w-[200px]",children:e.jsx(Be,{placeholder:"选择分类"})}),e.jsxs(Re,{children:[e.jsx(le,{value:"all",children:"全部分类"}),e.jsx(le,{value:"Group Management",children:"群组管理"}),e.jsx(le,{value:"Entertainment & Interaction",children:"娱乐互动"}),e.jsx(le,{value:"Utility Tools",children:"实用工具"}),e.jsx(le,{value:"Content Generation",children:"内容生成"}),e.jsx(le,{value:"Multimedia",children:"多媒体"}),e.jsx(le,{value:"External Integration",children:"外部集成"}),e.jsx(le,{value:"Data Analysis & Insights",children:"数据分析与洞察"}),e.jsx(le,{value:"Other",children:"其他"})]})]})]}),e.jsxs("div",{className:"flex items-center space-x-2",children:[e.jsx(mt,{id:"compatible-only",checked:b,onCheckedChange:E=>j(E===!0)}),e.jsx("label",{htmlFor:"compatible-only",className:"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70 cursor-pointer",children:"只显示兼容当前版本的插件"})]})]})}),e.jsx(ga,{value:p,onValueChange:g,className:"w-full",children:e.jsxs(la,{className:"grid w-full grid-cols-3",children:[e.jsxs(ss,{value:"all",children:["全部插件 (",y.filter(E=>{if(!E.manifest)return!1;const xe=d===""||E.manifest.name?.toLowerCase().includes(d.toLowerCase())||E.manifest.description?.toLowerCase().includes(d.toLowerCase())||E.manifest.keywords&&E.manifest.keywords.some(Q=>Q.toLowerCase().includes(d.toLowerCase())),Ye=x==="all"||E.manifest.categories&&E.manifest.categories.includes(x),ke=!b||!K||ze(E);return xe&&Ye&&ke}).length,")"]}),e.jsxs(ss,{value:"installed",children:["已安装 (",y.filter(E=>{if(!E.manifest)return!1;const xe=d===""||E.manifest.name?.toLowerCase().includes(d.toLowerCase())||E.manifest.description?.toLowerCase().includes(d.toLowerCase())||E.manifest.keywords&&E.manifest.keywords.some(Q=>Q.toLowerCase().includes(d.toLowerCase())),Ye=x==="all"||E.manifest.categories&&E.manifest.categories.includes(x),ke=!b||!K||ze(E);return E.installed&&xe&&Ye&&ke}).length,")"]}),e.jsxs(ss,{value:"updates",children:["可更新 (",y.filter(E=>{if(!E.manifest)return!1;const xe=d===""||E.manifest.name?.toLowerCase().includes(d.toLowerCase())||E.manifest.description?.toLowerCase().includes(d.toLowerCase())||E.manifest.keywords&&E.manifest.keywords.some(Q=>Q.toLowerCase().includes(d.toLowerCase())),Ye=x==="all"||E.manifest.categories&&E.manifest.categories.includes(x),ke=!b||!K||ze(E);return E.installed&&ge(E)&&xe&&Ye&&ke}).length,")"]})]})}),L&&L.stage==="loading"&&e.jsx(Fe,{className:"p-4",children:e.jsxs("div",{className:"space-y-3",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(it,{className:"h-4 w-4 animate-spin"}),e.jsxs("span",{className:"text-sm font-medium",children:[L.operation==="fetch"&&"加载插件列表",L.operation==="install"&&`安装插件${L.plugin_id?`: ${L.plugin_id}`:""}`,L.operation==="uninstall"&&`卸载插件${L.plugin_id?`: ${L.plugin_id}`:""}`,L.operation==="update"&&`更新插件${L.plugin_id?`: ${L.plugin_id}`:""}`]})]}),e.jsxs("span",{className:"text-sm font-medium",children:[L.progress,"%"]})]}),e.jsx(rr,{value:L.progress,className:"h-2"}),e.jsx("div",{className:"text-xs text-muted-foreground",children:L.message}),L.operation==="fetch"&&L.total_plugins>0&&e.jsxs("div",{className:"text-xs text-muted-foreground text-center",children:["已加载 ",L.loaded_plugins," / ",L.total_plugins," 个插件"]})]})}),L&&L.stage==="error"&&L.error&&e.jsx(Fe,{className:"border-destructive bg-destructive/10",children:e.jsx(ts,{children:e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx(Ca,{className:"h-5 w-5 text-destructive"}),e.jsxs("div",{children:[e.jsx(as,{className:"text-lg text-destructive",children:"加载失败"}),e.jsx(et,{className:"text-destructive/80",children:L.error})]})]})})}),k?e.jsxs("div",{className:"flex items-center justify-center py-12",children:[e.jsx(it,{className:"h-8 w-8 animate-spin text-muted-foreground"}),e.jsx("span",{className:"ml-3 text-muted-foreground",children:"加载插件列表中..."})]}):U?e.jsx(Fe,{className:"p-6",children:e.jsxs("div",{className:"flex flex-col items-center justify-center py-8 text-center",children:[e.jsx(Ca,{className:"h-12 w-12 text-destructive mb-4"}),e.jsx("h3",{className:"text-lg font-semibold mb-2",children:"加载失败"}),e.jsx("p",{className:"text-sm text-muted-foreground mb-4",children:U}),e.jsx(S,{onClick:()=>window.location.reload(),children:"重新加载"})]})}):ae.length===0?e.jsx(Fe,{className:"p-6",children:e.jsxs("div",{className:"flex flex-col items-center justify-center py-8 text-center",children:[e.jsx(Mt,{className:"h-12 w-12 text-muted-foreground mb-4"}),e.jsx("h3",{className:"text-lg font-semibold mb-2",children:"未找到插件"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:d||x!=="all"?"尝试调整搜索条件或筛选器":"暂无可用插件"})]})}):e.jsx("div",{className:"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6",children:ae.map(E=>e.jsxs(Fe,{className:"flex flex-col hover:shadow-lg transition-shadow h-full",children:[e.jsxs(ts,{children:[e.jsxs("div",{className:"flex items-start justify-between gap-2",children:[e.jsx(as,{className:"text-xl",children:E.manifest?.name||E.id}),e.jsxs("div",{className:"flex flex-col gap-1",children:[E.manifest?.categories&&E.manifest.categories[0]&&e.jsx(Qe,{variant:"secondary",className:"text-xs whitespace-nowrap",children:Np[E.manifest.categories[0]]||E.manifest.categories[0]}),Ce(E)]})]}),e.jsx(et,{className:"line-clamp-2",children:E.manifest?.description||"无描述"})]}),e.jsx(xs,{className:"flex-1",children:e.jsxs("div",{className:"space-y-3",children:[e.jsxs("div",{className:"flex items-center gap-4 text-sm text-muted-foreground",children:[e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx(Oa,{className:"h-4 w-4"}),e.jsx("span",{children:(A[E.id]?.downloads??E.downloads??0).toLocaleString()})]}),e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx(nl,{className:"h-4 w-4 fill-yellow-400 text-yellow-400"}),e.jsx("span",{children:(A[E.id]?.rating??E.rating??0).toFixed(1)})]})]}),e.jsxs("div",{className:"flex flex-wrap gap-2",children:[E.manifest?.keywords&&E.manifest.keywords.slice(0,3).map(xe=>e.jsx(Qe,{variant:"outline",className:"text-xs",children:xe},xe)),E.manifest?.keywords&&E.manifest.keywords.length>3&&e.jsxs(Qe,{variant:"outline",className:"text-xs",children:["+",E.manifest.keywords.length-3]})]}),e.jsxs("div",{className:"text-xs text-muted-foreground pt-2 border-t space-y-1",children:[e.jsxs("div",{children:["v",E.manifest?.version||"unknown"," · ",E.manifest?.author?.name||"Unknown"]}),E.manifest?.host_application&&e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx("span",{children:"支持:"}),e.jsxs("span",{className:"font-medium",children:[E.manifest.host_application.min_version,E.manifest.host_application.max_version?` - ${E.manifest.host_application.max_version}`:" - 最新版本"]})]})]})]})}),e.jsx(Sg,{className:"pt-4",children:e.jsxs("div",{className:"flex items-center justify-end gap-2 w-full",children:[e.jsx(S,{variant:"outline",size:"sm",onClick:()=>i(E),children:"查看详情"}),E.installed?ge(E)?e.jsxs(S,{size:"sm",disabled:!B?.installed,title:B?.installed?void 0:"Git 未安装",onClick:()=>Le(E),children:[e.jsx(zt,{className:"h-4 w-4 mr-1"}),"更新"]}):e.jsxs(S,{variant:"destructive",size:"sm",disabled:!B?.installed,title:B?.installed?void 0:"Git 未安装",onClick:()=>Te(E),children:[e.jsx(We,{className:"h-4 w-4 mr-1"}),"卸载"]}):e.jsxs(S,{size:"sm",disabled:!B?.installed||L?.operation==="install"||K!==null&&!ze(E),title:B?.installed?K!==null&&!ze(E)?`不兼容当前版本 (需要 ${E.manifest?.host_application?.min_version||"未知"}${E.manifest?.host_application?.max_version?` - ${E.manifest.host_application.max_version}`:"+"},当前 ${K?.version})`:void 0:"Git 未安装",onClick:()=>F(E),children:[e.jsx(Oa,{className:"h-4 w-4 mr-1"}),L?.operation==="install"&&L?.plugin_id===E.id?"安装中...":"安装"]})]})})]},E.id))}),e.jsx(qs,{open:r!==null,onOpenChange:re,children:r&&r.manifest&&e.jsx(Ls,{className:"max-w-2xl max-h-[80vh] p-0 flex flex-col",children:e.jsx(Ze,{className:"flex-1 overflow-auto",children:e.jsxs("div",{className:"p-6",children:[e.jsx(Us,{children:e.jsxs("div",{className:"flex items-start justify-between gap-4",children:[e.jsxs("div",{className:"space-y-2 flex-1",children:[e.jsx(Bs,{className:"text-2xl",children:r.manifest.name}),e.jsxs(Ps,{children:["作者: ",r.manifest.author?.name||"Unknown",r.manifest.author?.url&&e.jsx("a",{href:r.manifest.author.url,target:"_blank",rel:"noopener noreferrer",className:"ml-2 text-primary hover:underline",children:e.jsx(Hc,{className:"h-3 w-3 inline"})})]})]}),e.jsxs("div",{className:"flex flex-col gap-2",children:[r.manifest.categories&&r.manifest.categories[0]&&e.jsx(Qe,{variant:"secondary",children:Np[r.manifest.categories[0]]||r.manifest.categories[0]}),Ce(r)]})]})}),e.jsxs("div",{className:"space-y-6",children:[e.jsx(J2,{pluginId:r.id}),e.jsxs("div",{className:"grid grid-cols-2 sm:grid-cols-3 gap-4",children:[e.jsxs("div",{children:[e.jsx("p",{className:"text-sm font-medium",children:"版本"}),e.jsxs("p",{className:"text-sm text-muted-foreground",children:["v",r.manifest?.version||"unknown"]}),r.installed&&r.installed_version&&e.jsxs("p",{className:"text-xs text-muted-foreground",children:["已安装: v",r.installed_version]})]}),e.jsxs("div",{children:[e.jsx("p",{className:"text-sm font-medium",children:"下载量"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:(A[r.id]?.downloads??r.downloads??0).toLocaleString()})]}),e.jsxs("div",{children:[e.jsx("p",{className:"text-sm font-medium",children:"评分"}),e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx(nl,{className:"h-4 w-4 fill-yellow-400 text-yellow-400"}),e.jsxs("span",{className:"text-sm text-muted-foreground",children:[(A[r.id]?.rating??r.rating??0).toFixed(1)," (",A[r.id]?.rating_count??r.review_count??0,")"]})]})]}),e.jsxs("div",{children:[e.jsx("p",{className:"text-sm font-medium",children:"许可证"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:r.manifest.license||"Unknown"})]}),e.jsxs("div",{className:"col-span-2",children:[e.jsx("p",{className:"text-sm font-medium",children:"支持版本"}),e.jsxs("p",{className:"text-sm text-muted-foreground",children:[r.manifest.host_application?.min_version||"未知",r.manifest.host_application?.max_version?` - ${r.manifest.host_application.max_version}`:" - 最新版本"]})]})]}),e.jsxs("div",{children:[e.jsx("p",{className:"text-sm font-medium mb-2",children:"关键词"}),e.jsx("div",{className:"flex flex-wrap gap-2",children:r.manifest.keywords&&r.manifest.keywords.map(E=>e.jsx(Qe,{variant:"outline",children:E},E))})]}),r.detailed_description&&e.jsxs("div",{children:[e.jsx("p",{className:"text-sm font-medium mb-2",children:"详细说明"}),e.jsx("p",{className:"text-sm text-muted-foreground whitespace-pre-line",children:r.detailed_description})]}),!r.detailed_description&&e.jsxs("div",{children:[e.jsx("p",{className:"text-sm font-medium mb-2",children:"说明"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:r.manifest.description||"无描述"})]}),e.jsxs("div",{className:"space-y-2",children:[r.manifest.homepage_url&&e.jsxs("div",{className:"text-sm",children:[e.jsx("span",{className:"font-medium",children:"主页: "}),e.jsx("a",{href:r.manifest.homepage_url,target:"_blank",rel:"noopener noreferrer",className:"text-primary hover:underline",children:r.manifest.homepage_url})]}),r.manifest.repository_url&&e.jsxs("div",{className:"text-sm",children:[e.jsx("span",{className:"font-medium",children:"仓库: "}),e.jsx("a",{href:r.manifest.repository_url,target:"_blank",rel:"noopener noreferrer",className:"text-primary hover:underline",children:r.manifest.repository_url})]})]})]}),e.jsxs(st,{children:[r.manifest.homepage_url&&e.jsxs(S,{onClick:()=>window.open(r.manifest.homepage_url,"_blank"),children:[e.jsx(Hc,{className:"h-4 w-4 mr-2"}),"访问主页"]}),r.manifest.repository_url&&e.jsxs(S,{variant:"outline",onClick:()=>window.open(r.manifest.repository_url,"_blank"),children:[e.jsx(Hc,{className:"h-4 w-4 mr-2"}),"查看仓库"]})]})]})})})}),e.jsx(qs,{open:fe,onOpenChange:je,children:e.jsxs(Ls,{children:[e.jsxs(Us,{children:[e.jsx(Bs,{children:"安装插件"}),e.jsxs(Ps,{children:["安装 ",pe?.manifest.name]})]}),e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{children:[e.jsxs("p",{className:"text-sm text-muted-foreground",children:["版本: ",pe?.manifest.version]}),e.jsxs("p",{className:"text-sm text-muted-foreground",children:["作者: ",typeof pe?.manifest.author=="string"?pe.manifest.author:pe?.manifest.author?.name]})]}),e.jsxs("div",{className:"flex items-center space-x-2",children:[e.jsx(mt,{id:"advanced-options",checked:R,onCheckedChange:E=>ue(E)}),e.jsx("label",{htmlFor:"advanced-options",className:"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70",children:"高级选项"})]}),R&&e.jsx("div",{className:"space-y-4 p-4 border rounded-lg",children:e.jsxs("div",{className:"space-y-2",children:[e.jsx("label",{className:"text-sm font-medium",children:"分支选择"}),e.jsxs(ga,{value:q,onValueChange:E=>se(E),children:[e.jsxs(la,{className:"grid w-full grid-cols-2",children:[e.jsx(ss,{value:"preset",className:"text-xs",children:"预设分支"}),e.jsx(ss,{value:"custom",className:"text-xs",children:"自定义分支"})]}),q==="preset"&&e.jsx("div",{className:"mt-3",children:e.jsxs(Ue,{value:ve,onValueChange:be,children:[e.jsx(Oe,{children:e.jsx(Be,{placeholder:"选择分支"})}),e.jsxs(Re,{children:[e.jsx(le,{value:"main",children:"main (默认)"}),e.jsx(le,{value:"master",children:"master"}),e.jsx(le,{value:"dev",children:"dev (开发版)"}),e.jsx(le,{value:"develop",children:"develop"}),e.jsx(le,{value:"beta",children:"beta (测试版)"}),e.jsx(le,{value:"stable",children:"stable (稳定版)"})]})]})}),q==="custom"&&e.jsxs("div",{className:"space-y-2 mt-3",children:[e.jsx("input",{type:"text",className:"flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",placeholder:"输入分支名称,例如: feature/new-feature",value:D,onChange:E=>J(E.target.value)}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"输入 Git 分支名称、标签或提交哈希"})]})]})]})}),!R&&e.jsx("p",{className:"text-sm text-muted-foreground",children:"将从默认分支 (main) 安装插件"})]}),e.jsxs(st,{children:[e.jsx(S,{variant:"outline",onClick:()=>je(!1),children:"取消"}),e.jsxs(S,{onClick:P,children:[e.jsx(Oa,{className:"h-4 w-4 mr-2"}),"安装"]})]})]})})]})})}function P2(){return e.jsxs("div",{className:"h-[calc(100vh-4rem)] flex flex-col p-4 sm:p-6",children:[e.jsx("div",{className:"mb-4 sm:mb-6",children:e.jsx("div",{className:"flex flex-col sm:flex-row sm:items-center justify-between gap-4",children:e.jsxs("div",{children:[e.jsxs("h1",{className:"text-2xl sm:text-3xl font-bold flex items-center gap-2",children:[e.jsx(vg,{className:"h-8 w-8",strokeWidth:2}),"模型分配预设市场"]}),e.jsx("p",{className:"text-muted-foreground mt-1 text-sm sm:text-base",children:"浏览和下载社区共享的模型分配预设配置"})]})})}),e.jsx(Ze,{className:"flex-1",children:e.jsx("div",{className:"flex items-center justify-center h-[calc(100vh-12rem)]",children:e.jsxs(Fe,{className:"max-w-2xl w-full border-dashed",children:[e.jsxs(ts,{className:"text-center",children:[e.jsx("div",{className:"flex justify-center mb-4",children:e.jsx(Ol,{className:"h-16 w-16 text-muted-foreground"})}),e.jsx(as,{className:"text-2xl",children:"功能开发中"}),e.jsx(et,{className:"text-base",children:"模型分配预设市场功能正在开发中,敬请期待!"})]}),e.jsx(xs,{children:e.jsxs("div",{className:"space-y-3 text-sm text-muted-foreground",children:[e.jsx("p",{className:"font-medium text-foreground",children:"📦 即将推出的功能:"}),e.jsxs("ul",{className:"space-y-2 ml-6",children:[e.jsxs("li",{className:"flex items-start",children:[e.jsx("span",{className:"mr-2",children:"•"}),e.jsx("span",{children:"浏览社区共享的模型分配预设配置"})]}),e.jsxs("li",{className:"flex items-start",children:[e.jsx("span",{className:"mr-2",children:"•"}),e.jsx("span",{children:"一键下载和应用预设配置"})]}),e.jsxs("li",{className:"flex items-start",children:[e.jsx("span",{className:"mr-2",children:"•"}),e.jsx("span",{children:"分享自己的模型分配方案"})]}),e.jsxs("li",{className:"flex items-start",children:[e.jsx("span",{className:"mr-2",children:"•"}),e.jsx("span",{children:"预设配置评分和评论系统"})]}),e.jsxs("li",{className:"flex items-start",children:[e.jsx("span",{className:"mr-2",children:"•"}),e.jsx("span",{children:"根据使用场景智能推荐配置"})]})]})]})})]})})})]})}const qu=dN,Gu=uN,$u=mN;function W2({field:n,value:r,onChange:i}){const[d,m]=u.useState(!1);switch(n.ui_type){case"switch":return e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"space-y-0.5",children:[e.jsx(C,{children:n.label}),n.hint&&e.jsx("p",{className:"text-xs text-muted-foreground",children:n.hint})]}),e.jsx($e,{checked:!!r,onCheckedChange:i,disabled:n.disabled})]});case"number":return e.jsxs("div",{className:"space-y-2",children:[e.jsx(C,{children:n.label}),e.jsx(ie,{type:"number",value:r??n.default,onChange:x=>i(parseFloat(x.target.value)||0),min:n.min,max:n.max,step:n.step??1,placeholder:n.placeholder,disabled:n.disabled}),n.hint&&e.jsx("p",{className:"text-xs text-muted-foreground",children:n.hint})]});case"slider":return e.jsxs("div",{className:"space-y-2",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(C,{children:n.label}),e.jsx("span",{className:"text-sm text-muted-foreground",children:r??n.default})]}),e.jsx(pa,{value:[r??n.default],onValueChange:x=>i(x[0]),min:n.min??0,max:n.max??100,step:n.step??1,disabled:n.disabled}),n.hint&&e.jsx("p",{className:"text-xs text-muted-foreground",children:n.hint})]});case"select":return e.jsxs("div",{className:"space-y-2",children:[e.jsx(C,{children:n.label}),e.jsxs(Ue,{value:String(r??n.default),onValueChange:i,disabled:n.disabled,children:[e.jsx(Oe,{children:e.jsx(Be,{placeholder:n.placeholder??"请选择"})}),e.jsx(Re,{children:n.choices?.map(x=>e.jsx(le,{value:String(x),children:String(x)},String(x)))})]}),n.hint&&e.jsx("p",{className:"text-xs text-muted-foreground",children:n.hint})]});case"textarea":return e.jsxs("div",{className:"space-y-2",children:[e.jsx(C,{children:n.label}),e.jsx(Qs,{value:r??n.default,onChange:x=>i(x.target.value),placeholder:n.placeholder,rows:n.rows??3,disabled:n.disabled}),n.hint&&e.jsx("p",{className:"text-xs text-muted-foreground",children:n.hint})]});case"password":return e.jsxs("div",{className:"space-y-2",children:[e.jsx(C,{children:n.label}),e.jsxs("div",{className:"relative",children:[e.jsx(ie,{type:d?"text":"password",value:r??"",onChange:x=>i(x.target.value),placeholder:n.placeholder,disabled:n.disabled,className:"pr-10"}),e.jsx(S,{type:"button",variant:"ghost",size:"icon",className:"absolute right-0 top-0 h-full px-3",onClick:()=>m(!d),children:d?e.jsx(ci,{className:"h-4 w-4"}):e.jsx(Rt,{className:"h-4 w-4"})})]}),n.hint&&e.jsx("p",{className:"text-xs text-muted-foreground",children:n.hint})]});case"text":default:return e.jsxs("div",{className:"space-y-2",children:[e.jsx(C,{children:n.label}),e.jsx(ie,{type:"text",value:r??n.default??"",onChange:x=>i(x.target.value),placeholder:n.placeholder,maxLength:n.max_length,disabled:n.disabled}),n.hint&&e.jsx("p",{className:"text-xs text-muted-foreground",children:n.hint})]})}}function yp({section:n,config:r,onChange:i}){const[d,m]=u.useState(!n.collapsed),x=Object.entries(n.fields).filter(([,f])=>!f.hidden).sort(([,f],[,p])=>f.order-p.order);return e.jsx(qu,{open:d,onOpenChange:m,children:e.jsxs(Fe,{children:[e.jsx(Gu,{asChild:!0,children:e.jsxs(ts,{className:"cursor-pointer hover:bg-muted/50 transition-colors",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[d?e.jsx(Ll,{className:"h-4 w-4 text-muted-foreground"}):e.jsx(Ba,{className:"h-4 w-4 text-muted-foreground"}),e.jsx(as,{className:"text-lg",children:n.title})]}),e.jsxs(Qe,{variant:"secondary",className:"text-xs",children:[x.length," 项"]})]}),n.description&&e.jsx(et,{className:"ml-6",children:n.description})]})}),e.jsx($u,{children:e.jsx(xs,{className:"space-y-4 pt-0",children:x.map(([f,p])=>e.jsx(W2,{field:p,value:r[n.name]?.[f],onChange:g=>i(n.name,f,g),sectionName:n.name},f))})})]})})}function e_({plugin:n,onBack:r}){const{toast:i}=$s(),[d,m]=u.useState(null),[x,f]=u.useState({}),[p,g]=u.useState({}),[b,j]=u.useState(!0),[y,N]=u.useState(!1),[k,w]=u.useState(!1),[U,O]=u.useState(!1),B=u.useCallback(async()=>{j(!0);try{const[A,te]=await Promise.all([q2(n.id),G2(n.id)]);m(A),f(te),g(JSON.parse(JSON.stringify(te)))}catch(A){i({title:"加载配置失败",description:A instanceof Error?A.message:"未知错误",variant:"destructive"})}finally{j(!1)}},[n.id,i]);u.useEffect(()=>{B()},[B]),u.useEffect(()=>{w(JSON.stringify(x)!==JSON.stringify(p))},[x,p]);const Y=(A,te,fe)=>{f(je=>({...je,[A]:{...je[A]||{},[te]:fe}}))},L=async()=>{N(!0);try{await $2(n.id,x),g(JSON.parse(JSON.stringify(x))),i({title:"配置已保存",description:"更改将在插件重新加载后生效"})}catch(A){i({title:"保存失败",description:A instanceof Error?A.message:"未知错误",variant:"destructive"})}finally{N(!1)}},z=async()=>{try{await F2(n.id),i({title:"配置已重置",description:"下次加载插件时将使用默认配置"}),O(!1),B()}catch(A){i({title:"重置失败",description:A instanceof Error?A.message:"未知错误",variant:"destructive"})}},K=async()=>{try{const A=await V2(n.id);i({title:A.message,description:A.note}),B()}catch(A){i({title:"切换状态失败",description:A instanceof Error?A.message:"未知错误",variant:"destructive"})}};if(b)return e.jsx("div",{className:"flex items-center justify-center h-64",children:e.jsx(it,{className:"h-8 w-8 animate-spin text-muted-foreground"})});if(!d)return e.jsxs("div",{className:"flex flex-col items-center justify-center h-64 space-y-4",children:[e.jsx(At,{className:"h-12 w-12 text-muted-foreground"}),e.jsx("p",{className:"text-muted-foreground",children:"无法加载配置"}),e.jsxs(S,{onClick:r,variant:"outline",children:[e.jsx(er,{className:"h-4 w-4 mr-2"}),"返回"]})]});const I=Object.values(d.sections).sort((A,te)=>A.order-te.order),T=x.plugin?.enabled!==!1;return e.jsxs("div",{className:"space-y-4 sm:space-y-6",children:[e.jsxs("div",{className:"flex flex-col sm:flex-row sm:items-start sm:justify-between gap-4",children:[e.jsxs("div",{className:"flex items-start gap-3",children:[e.jsx(S,{variant:"ghost",size:"icon",onClick:r,children:e.jsx(er,{className:"h-5 w-5"})}),e.jsxs("div",{children:[e.jsx("h1",{className:"text-2xl sm:text-3xl font-bold",children:d.plugin_info.name||n.manifest.name}),e.jsxs("div",{className:"flex items-center gap-2 mt-1",children:[e.jsx(Qe,{variant:T?"default":"secondary",children:T?"已启用":"已禁用"}),e.jsxs("span",{className:"text-sm text-muted-foreground",children:["v",d.plugin_info.version||n.manifest.version]})]})]})]}),e.jsxs("div",{className:"flex gap-2 ml-10 sm:ml-0",children:[e.jsxs(S,{variant:"outline",size:"sm",onClick:K,children:[e.jsx(hi,{className:"h-4 w-4 mr-2"}),T?"禁用":"启用"]}),e.jsxs(S,{variant:"outline",size:"sm",onClick:()=>O(!0),children:[e.jsx($c,{className:"h-4 w-4 mr-2"}),"重置"]}),e.jsxs(S,{size:"sm",onClick:L,disabled:!k||y,children:[y?e.jsx(it,{className:"h-4 w-4 mr-2 animate-spin"}):e.jsx(fi,{className:"h-4 w-4 mr-2"}),"保存"]})]})]}),k&&e.jsx(Fe,{className:"border-orange-200 bg-orange-50 dark:bg-orange-950/20 dark:border-orange-900",children:e.jsx(xs,{className:"py-3",children:e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(Ra,{className:"h-4 w-4 text-orange-600"}),e.jsx("p",{className:"text-sm text-orange-800 dark:text-orange-200",children:"有未保存的更改"})]})})}),d.layout.type==="tabs"&&d.layout.tabs.length>0?e.jsxs(ga,{defaultValue:d.layout.tabs[0]?.id,children:[e.jsx(la,{children:d.layout.tabs.map(A=>e.jsxs(ss,{value:A.id,children:[A.title,A.badge&&e.jsx(Qe,{variant:"secondary",className:"ml-2 text-xs",children:A.badge})]},A.id))}),d.layout.tabs.map(A=>e.jsx(Ts,{value:A.id,className:"space-y-4 mt-4",children:A.sections.map(te=>{const fe=d.sections[te];return fe?e.jsx(yp,{section:fe,config:x,onChange:Y},te):null})},A.id))]}):e.jsx("div",{className:"space-y-4",children:I.map(A=>e.jsx(yp,{section:A,config:x,onChange:Y},A.name))}),e.jsx(qs,{open:U,onOpenChange:O,children:e.jsxs(Ls,{children:[e.jsxs(Us,{children:[e.jsx(Bs,{children:"确认重置配置"}),e.jsx(Ps,{children:"这将删除当前配置文件,下次加载插件时将使用默认配置。此操作不可撤销。"})]}),e.jsxs(st,{children:[e.jsx(S,{variant:"outline",onClick:()=>O(!1),children:"取消"}),e.jsx(S,{variant:"destructive",onClick:z,children:"确认重置"})]})]})})]})}function s_(){const{toast:n}=$s(),[r,i]=u.useState([]),[d,m]=u.useState(!0),[x,f]=u.useState(""),[p,g]=u.useState(null),b=async()=>{m(!0);try{const k=await li();i(k)}catch(k){n({title:"加载插件列表失败",description:k instanceof Error?k.message:"未知错误",variant:"destructive"})}finally{m(!1)}};u.useEffect(()=>{b()},[]);const j=r.filter(k=>{const w=x.toLowerCase();return k.id.toLowerCase().includes(w)||k.manifest.name.toLowerCase().includes(w)||k.manifest.description?.toLowerCase().includes(w)}),y=r.length,N=0;return p?e.jsx(Ze,{className:"h-full",children:e.jsx("div",{className:"p-4 sm:p-6",children:e.jsx(e_,{plugin:p,onBack:()=>g(null)})})}):e.jsx(Ze,{className:"h-full",children:e.jsxs("div",{className:"space-y-4 sm:space-y-6 p-4 sm:p-6",children:[e.jsxs("div",{className:"flex flex-col sm:flex-row sm:items-start sm:justify-between gap-4",children:[e.jsxs("div",{children:[e.jsx("h1",{className:"text-2xl sm:text-3xl font-bold",children:"插件配置"}),e.jsx("p",{className:"text-muted-foreground mt-1 sm:mt-2 text-sm sm:text-base",children:"管理和配置已安装的插件"})]}),e.jsxs(S,{variant:"outline",size:"sm",onClick:b,children:[e.jsx(zt,{className:`h-4 w-4 mr-2 ${d?"animate-spin":""}`}),"刷新"]})]}),e.jsxs("div",{className:"grid gap-4 grid-cols-1 xs:grid-cols-2 lg:grid-cols-3",children:[e.jsxs(Fe,{children:[e.jsxs(ts,{className:"flex flex-row items-center justify-between space-y-0 pb-2",children:[e.jsx(as,{className:"text-sm font-medium",children:"已安装插件"}),e.jsx(Ol,{className:"h-4 w-4 text-muted-foreground"})]}),e.jsxs(xs,{children:[e.jsx("div",{className:"text-2xl font-bold",children:r.length}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:d?"正在加载...":"个插件"})]})]}),e.jsxs(Fe,{children:[e.jsxs(ts,{className:"flex flex-row items-center justify-between space-y-0 pb-2",children:[e.jsx(as,{className:"text-sm font-medium",children:"已启用"}),e.jsx(aa,{className:"h-4 w-4 text-green-600"})]}),e.jsxs(xs,{children:[e.jsx("div",{className:"text-2xl font-bold",children:y}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:"运行中的插件"})]})]}),e.jsxs(Fe,{children:[e.jsxs(ts,{className:"flex flex-row items-center justify-between space-y-0 pb-2",children:[e.jsx(as,{className:"text-sm font-medium",children:"已禁用"}),e.jsx(At,{className:"h-4 w-4 text-orange-600"})]}),e.jsxs(xs,{children:[e.jsx("div",{className:"text-2xl font-bold",children:N}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:"未激活的插件"})]})]})]}),e.jsxs("div",{className:"relative",children:[e.jsx(Mt,{className:"absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground"}),e.jsx(ie,{placeholder:"搜索插件...",value:x,onChange:k=>f(k.target.value),className:"pl-9"})]}),e.jsxs(Fe,{children:[e.jsxs(ts,{children:[e.jsx(as,{children:"已安装的插件"}),e.jsx(et,{children:"点击插件查看和编辑配置"})]}),e.jsx(xs,{children:d?e.jsx("div",{className:"flex items-center justify-center py-12",children:e.jsx(it,{className:"h-8 w-8 animate-spin text-muted-foreground"})}):j.length===0?e.jsxs("div",{className:"flex flex-col items-center justify-center py-12 space-y-4",children:[e.jsx(Ol,{className:"h-16 w-16 text-muted-foreground/50"}),e.jsxs("div",{className:"text-center space-y-2",children:[e.jsx("p",{className:"text-lg font-medium text-muted-foreground",children:x?"没有找到匹配的插件":"暂无已安装的插件"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:x?"尝试其他搜索关键词":"前往插件市场安装插件"})]})]}):e.jsx("div",{className:"space-y-2",children:j.map(k=>e.jsxs("div",{className:"flex items-center justify-between p-4 rounded-lg border hover:bg-muted/50 cursor-pointer transition-colors",onClick:()=>g(k),children:[e.jsxs("div",{className:"flex items-center gap-3 min-w-0",children:[e.jsx("div",{className:"h-10 w-10 rounded-lg bg-primary/10 flex items-center justify-center flex-shrink-0",children:e.jsx(Ol,{className:"h-5 w-5 text-primary"})}),e.jsxs("div",{className:"min-w-0",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("h3",{className:"font-medium truncate",children:k.manifest.name}),e.jsxs(Qe,{variant:"secondary",className:"text-xs flex-shrink-0",children:["v",k.manifest.version]})]}),e.jsx("p",{className:"text-sm text-muted-foreground truncate",children:k.manifest.description||"暂无描述"})]})]}),e.jsxs("div",{className:"flex items-center gap-2 flex-shrink-0",children:[e.jsx(S,{variant:"ghost",size:"sm",children:e.jsx(ar,{className:"h-4 w-4"})}),e.jsx(Ba,{className:"h-4 w-4 text-muted-foreground"})]})]},k.id))})})]})]})})}function t_(){const n=va(),{toast:r}=$s(),[i,d]=u.useState([]),[m,x]=u.useState(!0),[f,p]=u.useState(null),[g,b]=u.useState(null),[j,y]=u.useState(!1),[N,k]=u.useState(!1),[w,U]=u.useState({id:"",name:"",raw_prefix:"",clone_prefix:"",enabled:!0,priority:1}),O=u.useCallback(async()=>{try{x(!0),p(null);const T=localStorage.getItem("access-token"),A=await fetch("/api/webui/plugins/mirrors",{headers:{Authorization:`Bearer ${T}`}});if(!A.ok)throw new Error("获取镜像源列表失败");const te=await A.json();d(te.mirrors||[])}catch(T){const A=T instanceof Error?T.message:"加载镜像源失败";p(A),r({title:"加载失败",description:A,variant:"destructive"})}finally{x(!1)}},[r]);u.useEffect(()=>{O()},[O]);const B=async()=>{try{const T=localStorage.getItem("access-token"),A=await fetch("/api/webui/plugins/mirrors",{method:"POST",headers:{Authorization:`Bearer ${T}`,"Content-Type":"application/json"},body:JSON.stringify(w)});if(!A.ok){const te=await A.json();throw new Error(te.detail||"添加镜像源失败")}r({title:"添加成功",description:"镜像源已添加"}),y(!1),U({id:"",name:"",raw_prefix:"",clone_prefix:"",enabled:!0,priority:1}),O()}catch(T){r({title:"添加失败",description:T instanceof Error?T.message:"未知错误",variant:"destructive"})}},Y=async()=>{if(g)try{const T=localStorage.getItem("access-token");if(!(await fetch(`/api/webui/plugins/mirrors/${g.id}`,{method:"PUT",headers:{Authorization:`Bearer ${T}`,"Content-Type":"application/json"},body:JSON.stringify({name:w.name,raw_prefix:w.raw_prefix,clone_prefix:w.clone_prefix,enabled:w.enabled,priority:w.priority})})).ok)throw new Error("更新镜像源失败");r({title:"更新成功",description:"镜像源已更新"}),k(!1),b(null),O()}catch(T){r({title:"更新失败",description:T instanceof Error?T.message:"未知错误",variant:"destructive"})}},L=async T=>{if(confirm("确定要删除这个镜像源吗?"))try{const A=localStorage.getItem("access-token");if(!(await fetch(`/api/webui/plugins/mirrors/${T}`,{method:"DELETE",headers:{Authorization:`Bearer ${A}`}})).ok)throw new Error("删除镜像源失败");r({title:"删除成功",description:"镜像源已删除"}),O()}catch(A){r({title:"删除失败",description:A instanceof Error?A.message:"未知错误",variant:"destructive"})}},z=async T=>{try{const A=localStorage.getItem("access-token");if(!(await fetch(`/api/webui/plugins/mirrors/${T.id}`,{method:"PUT",headers:{Authorization:`Bearer ${A}`,"Content-Type":"application/json"},body:JSON.stringify({enabled:!T.enabled})})).ok)throw new Error("更新状态失败");O()}catch(A){r({title:"更新失败",description:A instanceof Error?A.message:"未知错误",variant:"destructive"})}},K=T=>{b(T),U({id:T.id,name:T.name,raw_prefix:T.raw_prefix,clone_prefix:T.clone_prefix,enabled:T.enabled,priority:T.priority}),k(!0)},I=async(T,A)=>{const te=A==="up"?T.priority-1:T.priority+1;if(!(te<1))try{const fe=localStorage.getItem("access-token");if(!(await fetch(`/api/webui/plugins/mirrors/${T.id}`,{method:"PUT",headers:{Authorization:`Bearer ${fe}`,"Content-Type":"application/json"},body:JSON.stringify({priority:te})})).ok)throw new Error("更新优先级失败");O()}catch(fe){r({title:"更新失败",description:fe instanceof Error?fe.message:"未知错误",variant:"destructive"})}};return e.jsx(Ze,{className:"h-full",children:e.jsxs("div",{className:"space-y-6 p-4 sm:p-6",children:[e.jsxs("div",{className:"flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4",children:[e.jsxs("div",{className:"flex items-center gap-4",children:[e.jsx(S,{variant:"ghost",size:"icon",onClick:()=>n({to:"/plugins"}),children:e.jsx(er,{className:"h-5 w-5"})}),e.jsxs("div",{children:[e.jsx("h1",{className:"text-2xl sm:text-3xl font-bold",children:"镜像源配置"}),e.jsx("p",{className:"text-sm text-muted-foreground mt-1",children:"管理 Git 克隆和文件下载的镜像源"})]})]}),e.jsxs(S,{onClick:()=>y(!0),children:[e.jsx(dt,{className:"h-4 w-4 mr-2"}),"添加镜像源"]})]}),m?e.jsx(Fe,{className:"p-6",children:e.jsx("div",{className:"flex items-center justify-center py-8",children:e.jsx(it,{className:"h-8 w-8 animate-spin text-primary"})})}):f?e.jsx(Fe,{className:"p-6",children:e.jsxs("div",{className:"flex flex-col items-center justify-center py-8 text-center",children:[e.jsx(Ca,{className:"h-12 w-12 text-destructive mb-4"}),e.jsx("h3",{className:"text-lg font-semibold mb-2",children:"加载失败"}),e.jsx("p",{className:"text-sm text-muted-foreground mb-4",children:f}),e.jsx(S,{onClick:O,children:"重新加载"})]})}):e.jsxs(Fe,{children:[e.jsx("div",{className:"hidden md:block",children:e.jsxs(rn,{children:[e.jsx(cn,{children:e.jsxs(ut,{children:[e.jsx(Xe,{children:"状态"}),e.jsx(Xe,{children:"名称"}),e.jsx(Xe,{children:"ID"}),e.jsx(Xe,{children:"优先级"}),e.jsx(Xe,{className:"text-right",children:"操作"})]})}),e.jsx(on,{children:i.map(T=>e.jsxs(ut,{children:[e.jsx(Ve,{children:e.jsx($e,{checked:T.enabled,onCheckedChange:()=>z(T)})}),e.jsx(Ve,{children:e.jsxs("div",{children:[e.jsx("div",{className:"font-medium",children:T.name}),e.jsxs("div",{className:"text-xs text-muted-foreground mt-1",children:["Raw: ",T.raw_prefix]})]})}),e.jsx(Ve,{children:e.jsx(Qe,{variant:"outline",children:T.id})}),e.jsx(Ve,{children:e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:"font-mono",children:T.priority}),e.jsxs("div",{className:"flex flex-col gap-1",children:[e.jsx(S,{variant:"ghost",size:"icon",className:"h-5 w-5",onClick:()=>I(T,"up"),disabled:T.priority===1,children:e.jsx(di,{className:"h-3 w-3"})}),e.jsx(S,{variant:"ghost",size:"icon",className:"h-5 w-5",onClick:()=>I(T,"down"),children:e.jsx(Ll,{className:"h-3 w-3"})})]})]})}),e.jsx(Ve,{className:"text-right",children:e.jsxs("div",{className:"flex items-center justify-end gap-2",children:[e.jsx(S,{variant:"ghost",size:"icon",onClick:()=>K(T),children:e.jsx(ln,{className:"h-4 w-4"})}),e.jsx(S,{variant:"ghost",size:"icon",onClick:()=>L(T.id),children:e.jsx(We,{className:"h-4 w-4 text-destructive"})})]})})]},T.id))})]})}),e.jsx("div",{className:"md:hidden p-4 space-y-4",children:i.map(T=>e.jsx(Fe,{className:"p-4",children:e.jsxs("div",{className:"space-y-3",children:[e.jsxs("div",{className:"flex items-start justify-between",children:[e.jsxs("div",{className:"flex-1",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("h3",{className:"font-semibold",children:T.name}),T.enabled&&e.jsx(Qe,{variant:"default",className:"text-xs",children:"启用"})]}),e.jsx(Qe,{variant:"outline",className:"mt-1 text-xs",children:T.id})]}),e.jsx($e,{checked:T.enabled,onCheckedChange:()=>z(T)})]}),e.jsxs("div",{className:"text-sm space-y-1",children:[e.jsxs("div",{className:"text-muted-foreground",children:[e.jsx("span",{className:"font-medium",children:"Raw: "}),e.jsx("span",{className:"break-all",children:T.raw_prefix})]}),e.jsxs("div",{className:"text-muted-foreground",children:[e.jsx("span",{className:"font-medium",children:"优先级: "}),e.jsx("span",{className:"font-mono",children:T.priority})]})]}),e.jsxs("div",{className:"flex items-center gap-2 pt-2 border-t",children:[e.jsxs(S,{variant:"outline",size:"sm",className:"flex-1",onClick:()=>K(T),children:[e.jsx(ln,{className:"h-4 w-4 mr-1"}),"编辑"]}),e.jsx(S,{variant:"outline",size:"sm",onClick:()=>I(T,"up"),disabled:T.priority===1,children:e.jsx(di,{className:"h-4 w-4"})}),e.jsx(S,{variant:"outline",size:"sm",onClick:()=>I(T,"down"),children:e.jsx(Ll,{className:"h-4 w-4"})}),e.jsx(S,{variant:"destructive",size:"sm",onClick:()=>L(T.id),children:e.jsx(We,{className:"h-4 w-4"})})]})]})},T.id))})]}),e.jsx(qs,{open:j,onOpenChange:y,children:e.jsxs(Ls,{className:"max-w-lg",children:[e.jsxs(Us,{children:[e.jsx(Bs,{children:"添加镜像源"}),e.jsx(Ps,{children:"添加新的 Git 镜像源配置"})]}),e.jsxs("div",{className:"space-y-4 py-4",children:[e.jsxs("div",{className:"space-y-2",children:[e.jsx(C,{htmlFor:"add-id",children:"镜像源 ID *"}),e.jsx(ie,{id:"add-id",placeholder:"例如: my-mirror",value:w.id,onChange:T=>U({...w,id:T.target.value})})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(C,{htmlFor:"add-name",children:"名称 *"}),e.jsx(ie,{id:"add-name",placeholder:"例如: 我的镜像源",value:w.name,onChange:T=>U({...w,name:T.target.value})})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(C,{htmlFor:"add-raw",children:"Raw 文件前缀 *"}),e.jsx(ie,{id:"add-raw",placeholder:"https://example.com/raw",value:w.raw_prefix,onChange:T=>U({...w,raw_prefix:T.target.value})})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(C,{htmlFor:"add-clone",children:"克隆前缀 *"}),e.jsx(ie,{id:"add-clone",placeholder:"https://example.com/clone",value:w.clone_prefix,onChange:T=>U({...w,clone_prefix:T.target.value})})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(C,{htmlFor:"add-priority",children:"优先级"}),e.jsx(ie,{id:"add-priority",type:"number",min:"1",value:w.priority,onChange:T=>U({...w,priority:parseInt(T.target.value)||1})}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"数字越小优先级越高"})]}),e.jsxs("div",{className:"flex items-center space-x-2",children:[e.jsx($e,{id:"add-enabled",checked:w.enabled,onCheckedChange:T=>U({...w,enabled:T})}),e.jsx(C,{htmlFor:"add-enabled",children:"启用此镜像源"})]})]}),e.jsxs(st,{children:[e.jsx(S,{variant:"outline",onClick:()=>y(!1),children:"取消"}),e.jsx(S,{onClick:B,children:"添加"})]})]})}),e.jsx(qs,{open:N,onOpenChange:k,children:e.jsxs(Ls,{className:"max-w-lg",children:[e.jsxs(Us,{children:[e.jsx(Bs,{children:"编辑镜像源"}),e.jsx(Ps,{children:"修改镜像源配置"})]}),e.jsxs("div",{className:"space-y-4 py-4",children:[e.jsxs("div",{className:"space-y-2",children:[e.jsx(C,{children:"镜像源 ID"}),e.jsx(ie,{value:w.id,disabled:!0})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(C,{htmlFor:"edit-name",children:"名称 *"}),e.jsx(ie,{id:"edit-name",value:w.name,onChange:T=>U({...w,name:T.target.value})})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(C,{htmlFor:"edit-raw",children:"Raw 文件前缀 *"}),e.jsx(ie,{id:"edit-raw",value:w.raw_prefix,onChange:T=>U({...w,raw_prefix:T.target.value})})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(C,{htmlFor:"edit-clone",children:"克隆前缀 *"}),e.jsx(ie,{id:"edit-clone",value:w.clone_prefix,onChange:T=>U({...w,clone_prefix:T.target.value})})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(C,{htmlFor:"edit-priority",children:"优先级"}),e.jsx(ie,{id:"edit-priority",type:"number",min:"1",value:w.priority,onChange:T=>U({...w,priority:parseInt(T.target.value)||1})}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"数字越小优先级越高"})]}),e.jsxs("div",{className:"flex items-center space-x-2",children:[e.jsx($e,{id:"edit-enabled",checked:w.enabled,onCheckedChange:T=>U({...w,enabled:T})}),e.jsx(C,{htmlFor:"edit-enabled",children:"启用此镜像源"})]})]}),e.jsxs(st,{children:[e.jsx(S,{variant:"outline",onClick:()=>k(!1),children:"取消"}),e.jsx(S,{onClick:Y,children:"保存"})]})]})})]})})}const ni=u.forwardRef(({className:n,...r},i)=>e.jsx(Gp,{ref:i,className:$("relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full",n),...r}));ni.displayName=Gp.displayName;const a_=u.forwardRef(({className:n,...r},i)=>e.jsx($p,{ref:i,className:$("aspect-square h-full w-full",n),...r}));a_.displayName=$p.displayName;const ri=u.forwardRef(({className:n,...r},i)=>e.jsx(Fp,{ref:i,className:$("flex h-full w-full items-center justify-center rounded-full bg-muted",n),...r}));ri.displayName=Fp.displayName;function l_(){return"webui_"+Math.random().toString(36).substr(2,9)+"_"+Date.now().toString(36)}function n_(){const n="maibot_webui_user_id";let r=localStorage.getItem(n);return r||(r=l_(),localStorage.setItem(n,r)),r}function r_(){return localStorage.getItem("maibot_webui_user_name")||"WebUI用户"}function i_(n){localStorage.setItem("maibot_webui_user_name",n)}const Zg="maibot_webui_virtual_tabs";function c_(){try{const n=localStorage.getItem(Zg);if(n)return JSON.parse(n)}catch(n){console.error("[Chat] 加载虚拟标签页失败:",n)}return[]}function wp(n){try{localStorage.setItem(Zg,JSON.stringify(n))}catch(r){console.error("[Chat] 保存虚拟标签页失败:",r)}}function o_({segment:n}){switch(n.type){case"text":return e.jsx("span",{className:"whitespace-pre-wrap",children:String(n.data)});case"image":case"emoji":return e.jsx("img",{src:String(n.data),alt:n.type==="emoji"?"表情包":"图片",className:$("rounded-lg max-w-full",n.type==="emoji"?"max-h-32":"max-h-64"),loading:"lazy",onError:r=>{const i=r.target;i.style.display="none",i.parentElement?.insertAdjacentHTML("beforeend",`[${n.type==="emoji"?"表情包":"图片"}加载失败]`)}});case"voice":return e.jsx("div",{className:"flex items-center gap-2",children:e.jsx("audio",{controls:!0,src:String(n.data),className:"max-w-[200px] h-8",children:"您的浏览器不支持音频播放"})});case"video":return e.jsx("video",{controls:!0,src:String(n.data),className:"rounded-lg max-w-full max-h-64",children:"您的浏览器不支持视频播放"});case"face":return e.jsxs("span",{className:"text-muted-foreground",children:["[表情:",String(n.data),"]"]});case"music":return e.jsx("span",{className:"text-muted-foreground",children:"[音乐分享]"});case"file":return e.jsxs("span",{className:"text-muted-foreground",children:["[文件: ",String(n.data),"]"]});case"reply":return e.jsx("span",{className:"text-muted-foreground text-xs",children:"[回复消息]"});case"forward":return e.jsx("span",{className:"text-muted-foreground",children:"[转发消息]"});case"unknown":default:return e.jsxs("span",{className:"text-muted-foreground",children:["[",n.original_type||"未知消息","]"]})}}function d_({message:n,isBot:r}){return n.message_type==="rich"&&n.segments&&n.segments.length>0?e.jsx("div",{className:"flex flex-col gap-2",children:n.segments.map((i,d)=>e.jsx(o_,{segment:i},d))}):e.jsx("span",{className:"whitespace-pre-wrap",children:n.content})}function u_(){const n={id:"webui-default",type:"webui",label:"WebUI",messages:[],isConnected:!1,isTyping:!1,sessionInfo:{}},r=()=>{const He=c_().map(De=>{const Ke=De.virtualConfig;return!Ke.groupId&&Ke.platform&&Ke.userId&&(Ke.groupId=`webui_virtual_group_${Ke.platform}_${Ke.userId}`),{id:De.id,type:"virtual",label:De.label,virtualConfig:Ke,messages:[],isConnected:!1,isTyping:!1,sessionInfo:{}}});return[n,...He]},[i,d]=u.useState(r),[m,x]=u.useState("webui-default"),f=i.find(X=>X.id===m)||i[0],[p,g]=u.useState(""),[b,j]=u.useState(!1),[y,N]=u.useState(!0),[k,w]=u.useState(r_()),[U,O]=u.useState(!1),[B,Y]=u.useState(""),[L,z]=u.useState(!1),[K,I]=u.useState([]),[T,A]=u.useState([]),[te,fe]=u.useState(!1),[je,pe]=u.useState(!1),[he,ve]=u.useState(""),[be,D]=u.useState({platform:"",personId:"",userId:"",userName:"",groupName:"",groupId:""}),J=u.useRef(n_()),q=u.useRef(new Map),se=u.useRef(null),R=u.useRef(new Map),ue=u.useRef(0),me=u.useRef(new Map),{toast:_e}=$s(),Ce=X=>(ue.current+=1,`${X}-${Date.now()}-${ue.current}-${Math.random().toString(36).substr(2,9)}`),ze=u.useCallback((X,He)=>{d(De=>De.map(Ke=>Ke.id===X?{...Ke,...He}:Ke))},[]),ge=u.useCallback((X,He)=>{d(De=>De.map(Ke=>Ke.id===X?{...Ke,messages:[...Ke.messages,He]}:Ke))},[]),ae=u.useCallback(()=>{se.current?.scrollIntoView({behavior:"smooth"})},[]);u.useEffect(()=>{ae()},[f?.messages,ae]);const re=u.useCallback(async()=>{fe(!0);try{const X=await Se("/api/chat/platforms");if(console.log("[Chat] 平台列表响应:",X.status,X.headers.get("content-type")),X.ok){const He=X.headers.get("content-type");if(He&&He.includes("application/json")){const De=await X.json();console.log("[Chat] 平台列表数据:",De),I(De.platforms||[])}else{const De=await X.text();console.error("[Chat] 获取平台列表失败: 非 JSON 响应:",De.substring(0,200)),_e({title:"连接失败",description:"无法连接到后端服务,请确保 MaiBot 已启动",variant:"destructive"})}}else console.error("[Chat] 获取平台列表失败: HTTP",X.status),_e({title:"获取平台失败",description:`服务器返回错误: ${X.status}`,variant:"destructive"})}catch(X){console.error("[Chat] 获取平台列表失败:",X),_e({title:"网络错误",description:"无法连接到后端服务",variant:"destructive"})}finally{fe(!1)}},[_e]),F=u.useCallback(async(X,He)=>{pe(!0);try{const De=new URLSearchParams;X&&De.append("platform",X),He&&De.append("search",He),De.append("limit","50");const Ke=await Se(`/api/chat/persons?${De.toString()}`);if(Ke.ok){const Ns=Ke.headers.get("content-type");if(Ns&&Ns.includes("application/json")){const Je=await Ke.json();A(Je.persons||[])}else console.error("[Chat] 获取用户列表失败: 后端返回非 JSON 响应")}}catch(De){console.error("[Chat] 获取用户列表失败:",De)}finally{pe(!1)}},[]);u.useEffect(()=>{be.platform&&F(be.platform,he)},[be.platform,he,F]);const P=u.useCallback(async(X,He)=>{N(!0);try{const De=new URLSearchParams;De.append("user_id",J.current),De.append("limit","50"),He&&De.append("group_id",He);const Ke=`/api/chat/history?${De.toString()}`;console.log("[Chat] 正在加载历史消息:",Ke);const Ns=await Se(Ke);if(Ns.ok){const Je=await Ns.text();try{const Ks=JSON.parse(Je);if(Ks.messages&&Ks.messages.length>0){const ye=Ks.messages.map(Ae=>({id:Ae.id,type:Ae.type,content:Ae.content,timestamp:Ae.timestamp,sender:{name:Ae.sender_name||(Ae.is_bot?"麦麦":"WebUI用户"),user_id:Ae.user_id,is_bot:Ae.is_bot}}));ze(X,{messages:ye});const _s=me.current.get(X)||new Set;ye.forEach(Ae=>{if(Ae.type==="bot"){const vs=`bot-${Ae.content}-${Math.floor(Ae.timestamp*1e3)}`;_s.add(vs)}}),me.current.set(X,_s)}}catch(Ks){console.error("[Chat] JSON 解析失败:",Ks)}}}catch(De){console.error("[Chat] 加载历史消息失败:",De)}finally{N(!1)}},[ze]),Te=u.useCallback((X,He,De)=>{const Ke=q.current.get(X);if(Ke?.readyState===WebSocket.OPEN||Ke?.readyState===WebSocket.CONNECTING){console.log(`[Tab ${X}] WebSocket 已存在,跳过连接`);return}j(!0);const Ns=window.location.protocol==="https:"?"wss:":"ws:",Je=new URLSearchParams;He==="virtual"&&De?(Je.append("user_id",De.userId),Je.append("user_name",De.userName),Je.append("platform",De.platform),Je.append("person_id",De.personId),Je.append("group_name",De.groupName||"WebUI虚拟群聊"),De.groupId&&Je.append("group_id",De.groupId)):(Je.append("user_id",J.current),Je.append("user_name",k));const Ks=`${Ns}//${window.location.host}/api/chat/ws?${Je.toString()}`;console.log(`[Tab ${X}] 正在连接 WebSocket:`,Ks);try{const ye=new WebSocket(Ks);q.current.set(X,ye),ye.onopen=()=>{ze(X,{isConnected:!0}),j(!1),console.log(`[Tab ${X}] WebSocket 已连接`)},ye.onmessage=_s=>{try{const Ae=JSON.parse(_s.data);switch(Ae.type){case"session_info":ze(X,{sessionInfo:{session_id:Ae.session_id,user_id:Ae.user_id,user_name:Ae.user_name,bot_name:Ae.bot_name}});break;case"system":ge(X,{id:Ce("sys"),type:"system",content:Ae.content||"",timestamp:Ae.timestamp||Date.now()/1e3});break;case"user_message":{const vs=Ae.sender?.user_id,bs=He==="virtual"&&De?De.userId:J.current;console.log(`[Tab ${X}] 收到 user_message, sender: ${vs}, current: ${bs}`);const Nt=vs?vs.replace(/^webui_user_/,""):"",Xs=bs?bs.replace(/^webui_user_/,""):"";if(Nt&&Xs&&Nt===Xs){console.log(`[Tab ${X}] 跳过自己的消息(user_id 匹配)`);break}const Ss=me.current.get(X)||new Set,Es=`user-${Ae.content}-${Math.floor((Ae.timestamp||0)*1e3)}`;if(Ss.has(Es)){console.log(`[Tab ${X}] 跳过自己的消息(内容去重)`);break}if(Ss.add(Es),me.current.set(X,Ss),Ss.size>100){const Js=Ss.values().next().value;Js&&Ss.delete(Js)}ge(X,{id:Ae.message_id||Ce("user"),type:"user",content:Ae.content||"",timestamp:Ae.timestamp||Date.now()/1e3,sender:Ae.sender});break}case"bot_message":{ze(X,{isTyping:!1});const vs=me.current.get(X)||new Set,bs=`bot-${Ae.content}-${Math.floor((Ae.timestamp||0)*1e3)}`;if(vs.has(bs))break;if(vs.add(bs),me.current.set(X,vs),vs.size>100){const Nt=vs.values().next().value;Nt&&vs.delete(Nt)}d(Nt=>Nt.map(Xs=>{if(Xs.id!==X)return Xs;const Ss=Xs.messages.filter(Js=>Js.type!=="thinking"),Es={id:Ce("bot"),type:"bot",content:Ae.content||"",message_type:Ae.message_type==="rich"?"rich":"text",segments:Ae.segments,timestamp:Ae.timestamp||Date.now()/1e3,sender:Ae.sender};return{...Xs,messages:[...Ss,Es]}}));break}case"typing":ze(X,{isTyping:Ae.is_typing||!1});break;case"error":d(vs=>vs.map(bs=>{if(bs.id!==X)return bs;const Nt=bs.messages.filter(Xs=>Xs.type!=="thinking");return{...bs,messages:[...Nt,{id:Ce("error"),type:"error",content:Ae.content||"发生错误",timestamp:Ae.timestamp||Date.now()/1e3}]}})),_e({title:"错误",description:Ae.content,variant:"destructive"});break;case"pong":break;case"history":{const vs=Ae.messages||[];if(vs.length>0){const bs=me.current.get(X)||new Set,Nt=vs.map(Xs=>{const Ss=Xs.is_bot||!1,Es=Xs.id||Ce(Ss?"bot":"user"),Js=`${Ss?"bot":"user"}-${Xs.content}-${Math.floor(Xs.timestamp*1e3)}`;return bs.add(Js),{id:Es,type:Ss?"bot":"user",content:Xs.content,timestamp:Xs.timestamp,sender:{name:Xs.sender_name||(Ss?"麦麦":"用户"),user_id:Xs.sender_id,is_bot:Ss}}});me.current.set(X,bs),ze(X,{messages:Nt}),console.log(`[Tab ${X}] 已加载 ${Nt.length} 条历史消息`)}break}default:console.log("未知消息类型:",Ae.type)}}catch(Ae){console.error("解析消息失败:",Ae)}},ye.onclose=()=>{ze(X,{isConnected:!1}),j(!1),q.current.delete(X),console.log(`[Tab ${X}] WebSocket 已断开`);const _s=R.current.get(X);_s&&clearTimeout(_s);const Ae=window.setTimeout(()=>{if(!Le.current){const vs=i.find(bs=>bs.id===X);vs&&Te(X,vs.type,vs.virtualConfig)}},5e3);R.current.set(X,Ae)},ye.onerror=_s=>{console.error(`[Tab ${X}] WebSocket 错误:`,_s),j(!1)}}catch(ye){console.error(`[Tab ${X}] 创建 WebSocket 失败:`,ye),j(!1)}},[k,ze,ge,_e,i]),Le=u.useRef(!1);u.useEffect(()=>{Le.current=!1;const X=q.current,He=R.current,De=me.current;P("webui-default");const Ke=setTimeout(()=>{Le.current||(Te("webui-default","webui"),i.forEach(Je=>{Je.type==="virtual"&&Je.virtualConfig&&(De.set(Je.id,new Set),setTimeout(()=>{Le.current||Te(Je.id,"virtual",Je.virtualConfig)},200))}))},100),Ns=setInterval(()=>{X.forEach(Je=>{Je.readyState===WebSocket.OPEN&&Je.send(JSON.stringify({type:"ping"}))})},3e4);return()=>{Le.current=!0,clearTimeout(Ke),clearInterval(Ns),He.forEach(Je=>{clearTimeout(Je)}),He.clear(),X.forEach(Je=>{Je.close()}),X.clear()}},[]);const E=u.useCallback(()=>{const X=q.current.get(m);if(!p.trim()||!X||X.readyState!==WebSocket.OPEN)return;const He=f?.type==="virtual"&&f.virtualConfig?.userName||k,De=p.trim(),Ke=Date.now()/1e3;X.send(JSON.stringify({type:"message",content:De,user_name:He}));const Ns=me.current.get(m)||new Set,Je=`user-${De}-${Math.floor(Ke*1e3)}`;if(Ns.add(Je),me.current.set(m,Ns),Ns.size>100){const _s=Ns.values().next().value;_s&&Ns.delete(_s)}const Ks={id:Ce("user"),type:"user",content:De,timestamp:Ke,sender:{name:He,is_bot:!1}};ge(m,Ks);const ye={id:Ce("thinking"),type:"thinking",content:"",timestamp:Ke+.001,sender:{name:f?.sessionInfo.bot_name||"麦麦",is_bot:!0}};ge(m,ye),g("")},[p,k,m,f,ge]),xe=X=>{X.key==="Enter"&&!X.shiftKey&&(X.preventDefault(),E())},Ye=()=>{Y(k),O(!0)},ke=()=>{const X=B.trim()||"WebUI用户";w(X),i_(X),O(!1);const He=q.current.get(m);He?.readyState===WebSocket.OPEN&&He.send(JSON.stringify({type:"update_nickname",user_name:X}))},Q=()=>{Y(""),O(!1)},Ne=X=>new Date(X*1e3).toLocaleTimeString("zh-CN",{hour:"2-digit",minute:"2-digit"}),qe=()=>{const X=q.current.get(m);X&&(X.close(),q.current.delete(m)),Te(m,f?.type||"webui",f?.virtualConfig)},Fs=()=>{D({platform:"",personId:"",userId:"",userName:"",groupName:"",groupId:""}),ve(""),re(),z(!0)},ks=()=>{if(!be.platform||!be.personId){_e({title:"配置不完整",description:"请选择平台和用户",variant:"destructive"});return}const X=`webui_virtual_group_${be.platform}_${be.userId}`,He=`virtual-${be.platform}-${be.userId}-${Date.now()}`,De=be.userName||be.userId,Ke={id:He,type:"virtual",label:De,virtualConfig:{...be,groupId:X},messages:[],isConnected:!1,isTyping:!1,sessionInfo:{}};d(Ns=>{const Je=[...Ns,Ke],Ks=Je.filter(ye=>ye.type==="virtual"&&ye.virtualConfig).map(ye=>({id:ye.id,label:ye.label,virtualConfig:ye.virtualConfig,createdAt:Date.now()}));return wp(Ks),Je}),x(He),z(!1),me.current.set(He,new Set),setTimeout(()=>{Te(He,"virtual",be)},100),_e({title:"虚拟身份标签页",description:`已创建 ${De} 的对话`})},xt=(X,He)=>{if(He?.stopPropagation(),X==="webui-default")return;const De=q.current.get(X);De&&(De.close(),q.current.delete(X));const Ke=R.current.get(X);Ke&&(clearTimeout(Ke),R.current.delete(X)),me.current.delete(X),d(Ns=>{const Je=Ns.filter(ye=>ye.id!==X),Ks=Je.filter(ye=>ye.type==="virtual"&&ye.virtualConfig).map(ye=>({id:ye.id,label:ye.label,virtualConfig:ye.virtualConfig,createdAt:Date.now()}));return wp(Ks),Je}),m===X&&x("webui-default")},js=X=>{x(X)},Vs=X=>{D(He=>({...He,personId:X.person_id,userId:X.user_id,userName:X.nickname||X.person_name}))};return e.jsxs("div",{className:"h-full flex flex-col",children:[e.jsx(qs,{open:L,onOpenChange:z,children:e.jsxs(Ls,{className:"sm:max-w-[500px] max-h-[85vh] overflow-hidden flex flex-col",children:[e.jsxs(Us,{children:[e.jsxs(Bs,{className:"flex items-center gap-2",children:[e.jsx(Nu,{className:"h-5 w-5"}),"新建虚拟身份对话"]}),e.jsx(Ps,{children:"选择一个麦麦已认识的用户,以该用户的身份与麦麦对话。麦麦将使用她对该用户的记忆和认知来回应。"})]}),e.jsxs("div",{className:"space-y-4 flex-1 overflow-hidden flex flex-col",children:[e.jsxs("div",{className:"space-y-2",children:[e.jsxs(C,{className:"flex items-center gap-2",children:[e.jsx(Ru,{className:"h-4 w-4"}),"选择平台"]}),e.jsxs(Ue,{value:be.platform,onValueChange:X=>{D(He=>({...He,platform:X,personId:"",userId:"",userName:""})),A([])},children:[e.jsx(Oe,{disabled:te,children:e.jsx(Be,{placeholder:te?"加载中...":"选择平台"})}),e.jsx(Re,{children:K.map(X=>e.jsxs(le,{value:X.platform,children:[X.platform," (",X.count," 人)"]},X.platform))})]})]}),be.platform&&e.jsxs("div",{className:"space-y-2 flex-1 overflow-hidden flex flex-col",children:[e.jsxs(C,{className:"flex items-center gap-2",children:[e.jsx(Lu,{className:"h-4 w-4"}),"选择用户"]}),e.jsxs("div",{className:"relative",children:[e.jsx(Mt,{className:"absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground"}),e.jsx(ie,{placeholder:"搜索用户名...",value:he,onChange:X=>ve(X.target.value),className:"pl-9"})]}),e.jsx(Ze,{className:"h-[250px] border rounded-md",children:e.jsx("div",{className:"p-2",children:je?e.jsx("div",{className:"flex items-center justify-center py-8",children:e.jsx(it,{className:"h-6 w-6 animate-spin text-muted-foreground"})}):T.length===0?e.jsxs("div",{className:"flex flex-col items-center justify-center py-8 text-muted-foreground",children:[e.jsx(Lu,{className:"h-8 w-8 mb-2 opacity-50"}),e.jsx("p",{className:"text-sm",children:"没有找到用户"})]}):e.jsx("div",{className:"space-y-1",children:T.map(X=>e.jsxs("button",{onClick:()=>Vs(X),className:$("w-full flex items-center gap-3 p-2 rounded-md text-left transition-colors",be.personId===X.person_id?"bg-primary text-primary-foreground":"hover:bg-muted"),children:[e.jsx(ni,{className:"h-8 w-8 shrink-0",children:e.jsx(ri,{className:$("text-xs",be.personId===X.person_id?"bg-primary-foreground/20":"bg-muted"),children:(X.nickname||X.person_name||"?").charAt(0)})}),e.jsxs("div",{className:"min-w-0 flex-1",children:[e.jsx("div",{className:"font-medium truncate",children:X.nickname||X.person_name}),e.jsxs("div",{className:$("text-xs truncate",be.personId===X.person_id?"text-primary-foreground/70":"text-muted-foreground"),children:["ID: ",X.user_id,X.is_known&&" · 已认识"]})]})]},X.person_id))})})})]}),be.personId&&e.jsxs("div",{className:"space-y-2",children:[e.jsx(C,{children:"虚拟群名(可选)"}),e.jsx(ie,{placeholder:"WebUI虚拟群聊",value:be.groupName,onChange:X=>D(He=>({...He,groupName:X.target.value}))}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"麦麦会认为这是一个名为此名称的群聊"})]})]}),e.jsxs(st,{className:"gap-2 sm:gap-0",children:[e.jsx(S,{variant:"outline",onClick:()=>z(!1),children:"取消"}),e.jsx(S,{onClick:ks,disabled:!be.platform||!be.personId,children:"创建对话"})]})]})}),e.jsx("div",{className:"shrink-0 border-b bg-muted/30",children:e.jsx("div",{className:"max-w-4xl mx-auto px-2 sm:px-4",children:e.jsxs("div",{className:"flex items-center gap-1 overflow-x-auto py-1.5 scrollbar-thin",children:[i.map(X=>e.jsxs("div",{className:$("flex items-center gap-1.5 px-3 py-1.5 rounded-md text-sm whitespace-nowrap transition-colors cursor-pointer","hover:bg-muted",m===X.id?"bg-background shadow-sm border":"text-muted-foreground"),onClick:()=>js(X.id),children:[X.type==="webui"?e.jsx(Rl,{className:"h-3.5 w-3.5"}):e.jsx(Nu,{className:"h-3.5 w-3.5"}),e.jsx("span",{className:"max-w-[100px] truncate",children:X.label}),e.jsx("span",{className:$("w-1.5 h-1.5 rounded-full",X.isConnected?"bg-green-500":"bg-muted-foreground/50")}),X.id!=="webui-default"&&e.jsx("span",{onClick:He=>xt(X.id,He),className:"ml-0.5 p-0.5 rounded hover:bg-muted-foreground/20 cursor-pointer",role:"button",tabIndex:0,onKeyDown:He=>{(He.key==="Enter"||He.key===" ")&&(He.preventDefault(),xt(X.id,He))},children:e.jsx(rl,{className:"h-3 w-3"})})]},X.id)),e.jsx("button",{onClick:Fs,className:"flex items-center gap-1 px-2 py-1.5 rounded-md text-sm text-muted-foreground hover:bg-muted hover:text-foreground transition-colors",title:"新建虚拟身份对话",children:e.jsx(dt,{className:"h-3.5 w-3.5"})})]})})}),e.jsx("div",{className:"shrink-0 border-b bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60",children:e.jsxs("div",{className:"p-3 sm:p-4 max-w-4xl mx-auto",children:[e.jsxs("div",{className:"flex items-center justify-between gap-2",children:[e.jsxs("div",{className:"flex items-center gap-2 sm:gap-3 min-w-0",children:[e.jsx(ni,{className:"h-8 w-8 sm:h-10 sm:w-10 shrink-0",children:e.jsx(ri,{className:"bg-primary/10 text-primary",children:e.jsx(ti,{className:"h-4 w-4 sm:h-5 sm:w-5"})})}),e.jsxs("div",{className:"min-w-0",children:[e.jsx("h1",{className:"text-base sm:text-lg font-semibold truncate",children:f?.sessionInfo.bot_name||"麦麦"}),e.jsx("div",{className:"flex items-center gap-1.5 text-xs text-muted-foreground",children:f?.isConnected?e.jsxs(e.Fragment,{children:[e.jsx(py,{className:"h-3 w-3 text-green-500"}),e.jsx("span",{className:"text-green-600 dark:text-green-400",children:"已连接"})]}):b?e.jsxs(e.Fragment,{children:[e.jsx(it,{className:"h-3 w-3 animate-spin"}),e.jsx("span",{children:"连接中..."})]}):e.jsxs(e.Fragment,{children:[e.jsx(gy,{className:"h-3 w-3 text-red-500"}),e.jsx("span",{className:"text-red-600 dark:text-red-400",children:"未连接"})]})})]})]}),e.jsxs("div",{className:"flex items-center gap-1 shrink-0",children:[y&&e.jsx(it,{className:"h-4 w-4 animate-spin text-muted-foreground"}),e.jsx(S,{variant:"ghost",size:"icon",className:"h-8 w-8",onClick:qe,disabled:b,title:"重新连接",children:e.jsx(zt,{className:$("h-4 w-4",b&&"animate-spin")})})]})]}),e.jsx("div",{className:"hidden sm:flex items-center gap-2 mt-2 text-sm text-muted-foreground",children:f?.type==="virtual"&&f.virtualConfig?e.jsxs(e.Fragment,{children:[e.jsx(Nu,{className:"h-3 w-3 text-primary"}),e.jsx("span",{children:"虚拟身份:"}),e.jsx("span",{className:"font-medium text-primary",children:f.virtualConfig.userName}),e.jsxs("span",{className:"text-xs",children:["(",f.virtualConfig.platform,")"]}),f.virtualConfig.groupName&&e.jsxs(e.Fragment,{children:[e.jsx("span",{className:"mx-1",children:"·"}),e.jsxs("span",{className:"text-xs",children:["群:",f.virtualConfig.groupName]})]})]}):e.jsxs(e.Fragment,{children:[e.jsx(Qc,{className:"h-3 w-3"}),e.jsx("span",{children:"当前身份:"}),U?e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(ie,{value:B,onChange:X=>Y(X.target.value),onKeyDown:X=>{X.key==="Enter"&&ke(),X.key==="Escape"&&Q()},className:"h-7 w-32",placeholder:"输入昵称",autoFocus:!0}),e.jsx(S,{size:"sm",variant:"ghost",className:"h-7 px-2",onClick:ke,children:"保存"}),e.jsx(S,{size:"sm",variant:"ghost",className:"h-7 px-2",onClick:Q,children:"取消"})]}):e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx("span",{className:"font-medium text-foreground",children:k}),e.jsx(S,{size:"sm",variant:"ghost",className:"h-6 w-6 p-0",onClick:Ye,title:"修改昵称",children:e.jsx(jy,{className:"h-3 w-3"})})]})]})})]})}),e.jsx("div",{className:"flex-1 overflow-hidden",children:e.jsx(Ze,{className:"h-full",children:e.jsxs("div",{className:"p-3 sm:p-4 max-w-4xl mx-auto space-y-3 sm:space-y-4",children:[f?.messages.length===0&&!y&&e.jsxs("div",{className:"flex flex-col items-center justify-center py-12 text-muted-foreground",children:[e.jsx(ti,{className:"h-12 w-12 mb-4 opacity-50"}),e.jsxs("p",{className:"text-sm",children:["开始与 ",f?.sessionInfo.bot_name||"麦麦"," 对话吧!"]})]}),f?.messages.map(X=>e.jsxs("div",{className:$("flex gap-2 sm:gap-3",X.type==="user"&&"flex-row-reverse",X.type==="system"&&"justify-center",X.type==="error"&&"justify-center"),children:[X.type==="system"&&e.jsx("div",{className:"text-xs text-muted-foreground bg-muted/50 px-3 py-1 rounded-full max-w-[90%]",children:X.content}),X.type==="error"&&e.jsx("div",{className:"text-xs text-red-600 dark:text-red-400 bg-red-100 dark:bg-red-900/30 px-3 py-1 rounded-full max-w-[90%]",children:X.content}),X.type==="thinking"&&e.jsxs(e.Fragment,{children:[e.jsx(ni,{className:"h-7 w-7 sm:h-8 sm:w-8 shrink-0",children:e.jsx(ri,{className:"bg-primary/10 text-primary",children:e.jsx(ti,{className:"h-3.5 w-3.5 sm:h-4 sm:w-4"})})}),e.jsxs("div",{className:"flex flex-col gap-1 max-w-[75%] sm:max-w-[70%]",children:[e.jsx("div",{className:"flex items-center gap-2 text-[10px] sm:text-xs text-muted-foreground",children:e.jsx("span",{className:"hidden sm:inline",children:X.sender?.name||f?.sessionInfo.bot_name})}),e.jsx("div",{className:"bg-muted rounded-2xl rounded-tl-sm px-4 py-3",children:e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsxs("div",{className:"flex gap-1",children:[e.jsx("span",{className:"w-2 h-2 bg-primary/60 rounded-full animate-bounce",style:{animationDelay:"0ms"}}),e.jsx("span",{className:"w-2 h-2 bg-primary/60 rounded-full animate-bounce",style:{animationDelay:"150ms"}}),e.jsx("span",{className:"w-2 h-2 bg-primary/60 rounded-full animate-bounce",style:{animationDelay:"300ms"}})]}),e.jsx("span",{className:"text-xs text-muted-foreground ml-1",children:"思考中..."})]})})]})]}),(X.type==="user"||X.type==="bot")&&e.jsxs(e.Fragment,{children:[e.jsx(ni,{className:"h-7 w-7 sm:h-8 sm:w-8 shrink-0",children:e.jsx(ri,{className:$("text-xs",X.type==="bot"?"bg-primary/10 text-primary":"bg-secondary text-secondary-foreground"),children:X.type==="bot"?e.jsx(ti,{className:"h-3.5 w-3.5 sm:h-4 sm:w-4"}):e.jsx(Qc,{className:"h-3.5 w-3.5 sm:h-4 sm:w-4"})})}),e.jsxs("div",{className:$("flex flex-col gap-1 max-w-[75%] sm:max-w-[70%]",X.type==="user"&&"items-end"),children:[e.jsxs("div",{className:"flex items-center gap-2 text-[10px] sm:text-xs text-muted-foreground",children:[e.jsx("span",{className:"hidden sm:inline",children:X.sender?.name||(X.type==="bot"?f?.sessionInfo.bot_name:k)}),e.jsx("span",{children:Ne(X.timestamp)})]}),e.jsx("div",{className:$("rounded-2xl px-3 py-2 text-sm break-words",X.type==="bot"?"bg-muted rounded-tl-sm":"bg-primary text-primary-foreground rounded-tr-sm"),children:e.jsx(d_,{message:X,isBot:X.type==="bot"})})]})]})]},X.id)),e.jsx("div",{ref:se})]})})}),e.jsx("div",{className:"shrink-0 border-t bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60",children:e.jsx("div",{className:"p-3 sm:p-4 max-w-4xl mx-auto",children:e.jsxs("div",{className:"flex gap-2",children:[e.jsx(ie,{value:p,onChange:X=>g(X.target.value),onKeyDown:xe,placeholder:f?.isConnected?"输入消息...":"等待连接...",disabled:!f?.isConnected,className:"flex-1 h-10 sm:h-10"}),e.jsx(S,{onClick:E,disabled:!f?.isConnected||!p.trim(),size:"icon",className:"h-10 w-10 shrink-0",children:e.jsx(vy,{className:"h-4 w-4"})})]})})})]})}var sm="Radio",[m_,Pg]=lg(sm),[x_,h_]=m_(sm),Wg=u.forwardRef((n,r)=>{const{__scopeRadio:i,name:d,checked:m=!1,required:x,disabled:f,value:p="on",onCheck:g,form:b,...j}=n,[y,N]=u.useState(null),k=Fu(r,O=>N(O)),w=u.useRef(!1),U=y?b||!!y.closest("form"):!0;return e.jsxs(x_,{scope:i,checked:m,disabled:f,children:[e.jsx(Xc.button,{type:"button",role:"radio","aria-checked":m,"data-state":aj(m),"data-disabled":f?"":void 0,disabled:f,value:p,...j,ref:k,onClick:Du(n.onClick,O=>{m||g?.(),U&&(w.current=O.isPropagationStopped(),w.current||O.stopPropagation())})}),U&&e.jsx(tj,{control:y,bubbles:!w.current,name:d,value:p,checked:m,required:x,disabled:f,form:b,style:{transform:"translateX(-100%)"}})]})});Wg.displayName=sm;var ej="RadioIndicator",sj=u.forwardRef((n,r)=>{const{__scopeRadio:i,forceMount:d,...m}=n,x=h_(ej,i);return e.jsx(BN,{present:d||x.checked,children:e.jsx(Xc.span,{"data-state":aj(x.checked),"data-disabled":x.disabled?"":void 0,...m,ref:r})})});sj.displayName=ej;var f_="RadioBubbleInput",tj=u.forwardRef(({__scopeRadio:n,control:r,checked:i,bubbles:d=!0,...m},x)=>{const f=u.useRef(null),p=Fu(f,x),g=HN(i),b=qN(r);return u.useEffect(()=>{const j=f.current;if(!j)return;const y=window.HTMLInputElement.prototype,k=Object.getOwnPropertyDescriptor(y,"checked").set;if(g!==i&&k){const w=new Event("click",{bubbles:d});k.call(j,i),j.dispatchEvent(w)}},[g,i,d]),e.jsx(Xc.input,{type:"radio","aria-hidden":!0,defaultChecked:i,...m,tabIndex:-1,ref:p,style:{...m.style,...b,position:"absolute",pointerEvents:"none",opacity:0,margin:0}})});tj.displayName=f_;function aj(n){return n?"checked":"unchecked"}var p_=["ArrowUp","ArrowDown","ArrowLeft","ArrowRight"],no="RadioGroup",[g_]=lg(no,[Vp,Pg]),lj=Vp(),nj=Pg(),[j_,v_]=g_(no),rj=u.forwardRef((n,r)=>{const{__scopeRadioGroup:i,name:d,defaultValue:m,value:x,required:f=!1,disabled:p=!1,orientation:g,dir:b,loop:j=!0,onValueChange:y,...N}=n,k=lj(i),w=LN(b),[U,O]=UN({prop:x,defaultProp:m??null,onChange:y,caller:no});return e.jsx(j_,{scope:i,name:d,required:f,disabled:p,value:U,onValueChange:O,children:e.jsx(xN,{asChild:!0,...k,orientation:g,dir:w,loop:j,children:e.jsx(Xc.div,{role:"radiogroup","aria-required":f,"aria-orientation":g,"data-disabled":p?"":void 0,dir:w,...N,ref:r})})})});rj.displayName=no;var ij="RadioGroupItem",cj=u.forwardRef((n,r)=>{const{__scopeRadioGroup:i,disabled:d,...m}=n,x=v_(ij,i),f=x.disabled||d,p=lj(i),g=nj(i),b=u.useRef(null),j=Fu(r,b),y=x.value===m.value,N=u.useRef(!1);return u.useEffect(()=>{const k=U=>{p_.includes(U.key)&&(N.current=!0)},w=()=>N.current=!1;return document.addEventListener("keydown",k),document.addEventListener("keyup",w),()=>{document.removeEventListener("keydown",k),document.removeEventListener("keyup",w)}},[]),e.jsx(hN,{asChild:!0,...p,focusable:!f,active:y,children:e.jsx(Wg,{disabled:f,required:x.required,checked:y,...g,...m,name:x.name,ref:j,onCheck:()=>x.onValueChange(m.value),onKeyDown:Du(k=>{k.key==="Enter"&&k.preventDefault()}),onFocus:Du(m.onFocus,()=>{N.current&&b.current?.click()})})})});cj.displayName=ij;var b_="RadioGroupIndicator",oj=u.forwardRef((n,r)=>{const{__scopeRadioGroup:i,...d}=n,m=nj(i);return e.jsx(sj,{...m,...d,ref:r})});oj.displayName=b_;var dj=rj,uj=cj,N_=oj;const mj=u.forwardRef(({className:n,...r},i)=>e.jsx(dj,{className:$("grid gap-2",n),...r,ref:i}));mj.displayName=dj.displayName;const xj=u.forwardRef(({className:n,...r},i)=>e.jsx(uj,{ref:i,className:$("aspect-square h-4 w-4 rounded-full border border-primary text-primary shadow focus:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50",n),...r,children:e.jsx(N_,{className:"flex items-center justify-center",children:e.jsx(by,{className:"h-2.5 w-2.5 fill-current text-current"})})}));xj.displayName=uj.displayName;function y_({question:n,value:r,onChange:i,error:d,disabled:m=!1}){const[x,f]=u.useState(null),p=m||n.readOnly,g=()=>{switch(n.type){case"single":return e.jsx(mj,{value:r||"",onValueChange:i,disabled:p,className:"space-y-2",children:n.options?.map(b=>e.jsxs("div",{className:"flex items-center space-x-2",children:[e.jsx(xj,{value:b.value,id:`${n.id}-${b.id}`}),e.jsx(C,{htmlFor:`${n.id}-${b.id}`,className:"cursor-pointer font-normal",children:b.label})]},b.id))});case"multiple":{const b=r||[];return e.jsxs("div",{className:"space-y-2",children:[n.options?.map(j=>e.jsxs("div",{className:"flex items-center space-x-2",children:[e.jsx(mt,{id:`${n.id}-${j.id}`,checked:b.includes(j.value),disabled:p||n.maxSelections!==void 0&&b.length>=n.maxSelections&&!b.includes(j.value),onCheckedChange:y=>{i(y?[...b,j.value]:b.filter(N=>N!==j.value))}}),e.jsx(C,{htmlFor:`${n.id}-${j.id}`,className:"cursor-pointer font-normal",children:j.label})]},j.id)),n.maxSelections&&e.jsxs("p",{className:"text-xs text-muted-foreground",children:["最多选择 ",n.maxSelections," 项"]})]})}case"text":return e.jsx(ie,{value:r||"",onChange:b=>i(b.target.value),placeholder:n.placeholder||"请输入...",disabled:p,readOnly:n.readOnly,maxLength:n.maxLength,className:$(n.readOnly&&"bg-muted cursor-not-allowed")});case"textarea":return e.jsxs("div",{className:"space-y-1",children:[e.jsx(Qs,{value:r||"",onChange:b=>i(b.target.value),placeholder:n.placeholder||"请输入...",disabled:p,readOnly:n.readOnly,maxLength:n.maxLength,rows:4,className:$(n.readOnly&&"bg-muted cursor-not-allowed")}),n.maxLength&&e.jsxs("p",{className:"text-xs text-muted-foreground text-right",children:[(r||"").length," / ",n.maxLength]})]});case"rating":{const b=r||0,j=x!==null?x:b;return e.jsxs("div",{className:"flex items-center gap-1",children:[[1,2,3,4,5].map(y=>e.jsx("button",{type:"button",disabled:p,className:$("p-1 transition-colors focus:outline-none focus:ring-2 focus:ring-ring rounded",p&&"cursor-not-allowed opacity-50"),onMouseEnter:()=>!p&&f(y),onMouseLeave:()=>f(null),onClick:()=>!p&&i(y),children:e.jsx(nl,{className:$("h-6 w-6 transition-colors",y<=j?"fill-yellow-400 text-yellow-400":"text-muted-foreground")})},y)),b>0&&e.jsxs("span",{className:"ml-2 text-sm text-muted-foreground",children:[b," / 5"]})]})}case"scale":{const b=n.min??1,j=n.max??10,y=n.step??1,N=r??b;return e.jsxs("div",{className:"space-y-4",children:[e.jsx(pa,{value:[N],onValueChange:([k])=>i(k),min:b,max:j,step:y,disabled:p}),e.jsxs("div",{className:"flex justify-between text-xs text-muted-foreground",children:[e.jsx("span",{children:n.minLabel||b}),e.jsx("span",{className:"font-medium text-foreground",children:N}),e.jsx("span",{children:n.maxLabel||j})]})]})}case"dropdown":return e.jsxs(Ue,{value:r||"",onValueChange:i,disabled:p,children:[e.jsx(Oe,{children:e.jsx(Be,{placeholder:n.placeholder||"请选择..."})}),e.jsx(Re,{children:n.options?.map(b=>e.jsx(le,{value:b.value,children:b.label},b.id))})]});default:return e.jsx("div",{className:"text-muted-foreground",children:"不支持的问题类型"})}};return e.jsxs("div",{className:"space-y-3",children:[e.jsxs("div",{className:"space-y-1",children:[e.jsxs(C,{className:"text-base font-medium",children:[n.title,n.required&&e.jsx("span",{className:"text-destructive ml-1",children:"*"})]}),n.description&&e.jsx("p",{className:"text-sm text-muted-foreground",children:n.description})]}),g(),d&&e.jsx("p",{className:"text-sm text-destructive",children:d})]})}const hj="https://maibot-plugin-stats.maibot-webui.workers.dev";function fj(){const n="maibot_user_id";let r=localStorage.getItem(n);if(!r){const i=Math.random().toString(36).substring(2,10),d=Date.now().toString(36),m=Math.random().toString(36).substring(2,10);r=`fp_${i}_${d}_${m}`,localStorage.setItem(n,r)}return r}async function w_(n,r,i,d){try{const m=d?.userId||fj(),x={surveyId:n,surveyVersion:r,userId:m,answers:i,submittedAt:new Date().toISOString(),allowMultiple:d?.allowMultiple,metadata:{userAgent:navigator.userAgent,language:navigator.language}},f=await fetch(`${hj}/survey/submit`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(x)}),p=await f.json();return f.status===429?{success:!1,error:"提交过于频繁,请稍后再试"}:f.status===409?{success:!1,error:p.error||"你已经提交过这份问卷了"}:f.ok?{success:!0,submissionId:p.submissionId,message:p.message}:{success:!1,error:p.error||"提交失败"}}catch(m){return console.error("Error submitting survey:",m),{success:!1,error:"网络错误"}}}async function __(n,r){try{const i=r||fj(),d=new URLSearchParams({user_id:i,survey_id:n}),m=await fetch(`${hj}/survey/check?${d}`);return m.ok?{success:!0,hasSubmitted:(await m.json()).hasSubmitted}:{success:!1,error:(await m.json()).error||"检查失败"}}catch(i){return console.error("Error checking submission:",i),{success:!1,error:"网络错误"}}}function pj({config:n,initialAnswers:r,onSubmitSuccess:i,onSubmitError:d,showProgress:m=!0,paginateQuestions:x=!1,className:f}){const p=u.useCallback(()=>!r||r.length===0?{}:r.reduce((q,se)=>(q[se.questionId]=se.value,q),{}),[r]),[g,b]=u.useState(()=>p()),[j,y]=u.useState({}),[N,k]=u.useState(0),[w,U]=u.useState(!1),[O,B]=u.useState(!1),[Y,L]=u.useState(null),[z,K]=u.useState(null),[I,T]=u.useState(!1),[A,te]=u.useState(!0);u.useEffect(()=>{r&&r.length>0&&b(q=>({...q,...p()}))},[r,p]),u.useEffect(()=>{(async()=>{if(!n.settings?.allowMultiple){const se=await __(n.id);se.success&&se.hasSubmitted&&T(!0)}te(!1)})()},[n.id,n.settings?.allowMultiple]);const fe=u.useCallback(()=>{const q=new Date;return!(n.settings?.startTime&&new Date(n.settings.startTime)>q||n.settings?.endTime&&new Date(n.settings.endTime){const se=g[q.id];return se==null?!1:Array.isArray(se)?se.length>0:typeof se=="string"?se.trim()!=="":!0}).length,pe=je/n.questions.length*100,he=u.useCallback((q,se)=>{b(R=>({...R,[q]:se})),y(R=>{const ue={...R};return delete ue[q],ue})},[]),ve=u.useCallback(()=>{const q={};for(const se of n.questions){if(se.required){const R=g[se.id];if(R==null){q[se.id]="此题为必填项";continue}if(Array.isArray(R)&&R.length===0){q[se.id]="请至少选择一项";continue}if(typeof R=="string"&&R.trim()===""){q[se.id]="此题为必填项";continue}}se.minLength&&typeof g[se.id]=="string"&&g[se.id].length{if(!ve()){if(x){const q=n.questions.findIndex(se=>j[se.id]);q>=0&&k(q)}return}U(!0),L(null);try{const q=n.questions.filter(R=>g[R.id]!==void 0).map(R=>({questionId:R.id,value:g[R.id]})),se=await w_(n.id,n.version,q,{allowMultiple:n.settings?.allowMultiple});if(se.success&&se.submissionId)B(!0),K(se.submissionId),i?.(se.submissionId);else{const R=se.error||"提交失败";L(R),d?.(R)}}catch(q){const se=q instanceof Error?q.message:"提交失败";L(se),d?.(se)}finally{U(!1)}},[ve,x,n,g,j,i,d]),D=u.useCallback(q=>{q>=0&&qe.jsxs("div",{className:$("p-4 rounded-lg border bg-card",j[q.id]?"border-destructive bg-destructive/5":"border-border"),children:[x&&e.jsxs("div",{className:"text-xs text-muted-foreground mb-2",children:["问题 ",N+1," / ",n.questions.length]}),!x&&e.jsxs("div",{className:"text-xs text-muted-foreground mb-2",children:[se+1,"."]}),e.jsx(y_,{question:q,value:g[q.id],onChange:R=>he(q.id,R),error:j[q.id],disabled:w})]},q.id)),Y&&e.jsxs(It,{variant:"destructive",children:[e.jsx(At,{className:"h-4 w-4"}),e.jsx(Yt,{children:Y})]}),e.jsx("div",{className:"flex justify-between items-center py-4",children:x?e.jsxs(e.Fragment,{children:[e.jsxs(S,{variant:"outline",onClick:()=>D(N-1),disabled:N===0||w,children:[e.jsx(il,{className:"h-4 w-4 mr-1"}),"上一题"]}),N===n.questions.length-1?e.jsxs(S,{onClick:be,disabled:w,children:[w&&e.jsx(it,{className:"h-4 w-4 mr-2 animate-spin"}),"提交问卷"]}):e.jsxs(S,{onClick:()=>D(N+1),disabled:w,children:["下一题",e.jsx(Ba,{className:"h-4 w-4 ml-1"})]})]}):e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"text-sm text-muted-foreground",children:Object.keys(j).length>0&&e.jsxs("span",{className:"text-destructive",children:["还有 ",Object.keys(j).length," 个必填项未完成"]})}),e.jsxs(S,{onClick:be,disabled:w,size:"lg",children:[w&&e.jsx(it,{className:"h-4 w-4 mr-2 animate-spin"}),"提交问卷"]})]})})]})})]})}const S_={id:"webui-feedback-v1",version:"1.0.0",title:"麦麦 WebUI 使用反馈问卷",description:"感谢您使用麦麦 WebUI!您的反馈将帮助我们不断改进产品体验。",questions:[{id:"webui_version",type:"text",title:"你正在使用的 WebUI 版本",description:"此项由系统自动填写",required:!0,readOnly:!0,placeholder:"自动检测中..."},{id:"ui_design_satisfaction",type:"single",title:"你觉得当前的 WebUI 界面设计如何?",required:!0,options:[{id:"very_satisfied",label:"非常满意",value:"very_satisfied"},{id:"satisfied",label:"满意",value:"satisfied"},{id:"neutral",label:"一般",value:"neutral"},{id:"dissatisfied",label:"不满意",value:"dissatisfied"},{id:"very_dissatisfied",label:"非常不满意",value:"very_dissatisfied"}]},{id:"problems_encountered",type:"multiple",title:"你在使用 WebUI 时遇到过哪些问题?",description:"可多选",required:!0,options:[{id:"lag",label:"界面卡顿",value:"lag"},{id:"incomplete",label:"功能不完整",value:"incomplete"},{id:"complex",label:"操作复杂",value:"complex"},{id:"bugs",label:"存在 Bug",value:"bugs"},{id:"none",label:"没有遇到问题",value:"none"},{id:"other",label:"其他",value:"other"}]},{id:"problems_other",type:"text",title:'如选择"其他",请说明遇到的问题',required:!1,placeholder:"请描述你遇到的其他问题...",maxLength:500},{id:"useful_features",type:"textarea",title:"你觉得哪些功能是最有用的?",required:!0,placeholder:"请分享你认为最有价值的功能...",maxLength:1e3},{id:"feature_requests",type:"textarea",title:"你希望在未来的版本中增加哪些功能?",required:!0,placeholder:"请告诉我们你期望的新功能...",maxLength:1e3},{id:"overall_satisfaction",type:"single",title:"你对麦麦 WebUI 的整体满意度如何?",required:!0,options:[{id:"very_satisfied",label:"非常满意",value:"very_satisfied"},{id:"satisfied",label:"满意",value:"satisfied"},{id:"neutral",label:"一般",value:"neutral"},{id:"dissatisfied",label:"不满意",value:"dissatisfied"},{id:"very_dissatisfied",label:"非常不满意",value:"very_dissatisfied"}]},{id:"would_recommend",type:"single",title:"你愿意推荐麦麦 WebUI 给其他人使用吗?",required:!0,options:[{id:"yes",label:"是",value:"yes"},{id:"no",label:"否",value:"no"}]},{id:"other_suggestions",type:"textarea",title:"其他建议或意见",description:"此项为选填",required:!1,placeholder:"如果你有任何其他想法或建议,请在此分享...",maxLength:2e3}],settings:{allowMultiple:!1,thankYouMessage:"感谢你的反馈!你的意见对我们非常重要,我们会认真考虑每一条建议。"}},C_={id:"maibot-feedback-v1",version:"1.0.0",title:"麦麦使用体验反馈问卷",description:"感谢您使用麦麦!您的反馈将帮助我们打造更好的 AI 伙伴。",questions:[{id:"maibot_version",type:"text",title:"你正在使用的麦麦版本",description:"此项由系统自动填写",required:!0,readOnly:!0,placeholder:"自动检测中..."},{id:"improvement_areas",type:"textarea",title:"你认为麦麦还有哪些部分可以改进?",required:!0,placeholder:"请分享你认为可以改进的方面...",maxLength:1e3},{id:"problems_encountered",type:"multiple",title:"你在使用麦麦时遇到过哪些问题?",description:"可多选",required:!0,options:[{id:"incomplete",label:"功能不完整",value:"incomplete"},{id:"slow_response",label:"响应速度慢",value:"slow_response"},{id:"complex",label:"操作复杂",value:"complex"},{id:"unstable",label:"运行不稳定",value:"unstable"},{id:"config_difficult",label:"配置困难",value:"config_difficult"},{id:"none",label:"没有遇到问题",value:"none"},{id:"other",label:"其他",value:"other"}]},{id:"problems_other",type:"text",title:'如选择"其他",请说明遇到的问题',required:!1,placeholder:"请描述你遇到的其他问题...",maxLength:500},{id:"helpful_features",type:"textarea",title:"你觉得麦麦的哪些功能对你最有帮助?",required:!0,placeholder:"请分享对你最有帮助的功能...",maxLength:1e3},{id:"feature_requests",type:"textarea",title:"你希望在未来的版本中增加哪些功能?",required:!0,placeholder:"请告诉我们你期望的新功能...",maxLength:1e3},{id:"overall_satisfaction",type:"single",title:"你对麦麦的整体满意度如何?",required:!0,options:[{id:"very_satisfied",label:"非常满意",value:"very_satisfied"},{id:"satisfied",label:"满意",value:"satisfied"},{id:"neutral",label:"一般",value:"neutral"},{id:"dissatisfied",label:"不满意",value:"dissatisfied"},{id:"very_dissatisfied",label:"非常不满意",value:"very_dissatisfied"}]},{id:"would_recommend",type:"single",title:"你愿意推荐麦麦给其他人使用吗?",required:!0,options:[{id:"yes",label:"是",value:"yes"},{id:"no",label:"否",value:"no"}]},{id:"other_suggestions",type:"textarea",title:"其他建议或意见",description:"此项为选填",required:!1,placeholder:"如果你有任何其他想法或建议,请在此分享...",maxLength:2e3}],settings:{allowMultiple:!1,thankYouMessage:"感谢你的反馈!你的意见对麦麦的成长非常重要,我们会认真考虑每一条建议。"}};function k_(){const[n,r]=u.useState(null),[i,d]=u.useState(!0);u.useEffect(()=>{const p=JSON.parse(JSON.stringify(S_));r(p),d(!1)},[]);const m=u.useMemo(()=>[{questionId:"webui_version",value:`v${Zc}`}],[]),x=u.useCallback(p=>{console.log("WebUI Survey submitted:",p)},[]),f=u.useCallback(p=>{console.error("WebUI Survey submission error:",p)},[]);return i?e.jsx("div",{className:"flex items-center justify-center min-h-[400px]",children:e.jsx(it,{className:"h-8 w-8 animate-spin text-muted-foreground"})}):n?e.jsxs("div",{className:"h-[calc(100vh-4rem)] flex flex-col p-4 sm:p-6",children:[e.jsxs("div",{className:"mb-4 sm:mb-6 shrink-0",children:[e.jsxs("h1",{className:"text-2xl sm:text-3xl font-bold flex items-center gap-2",children:[e.jsx(bg,{className:"h-8 w-8",strokeWidth:2}),"WebUI 使用反馈问卷"]}),e.jsx("p",{className:"text-muted-foreground mt-1 text-sm sm:text-base",children:"感谢您的反馈,帮助我们持续改进产品体验"})]}),e.jsx("div",{className:"flex-1 min-h-0",children:e.jsx(pj,{config:n,initialAnswers:m,showProgress:!0,paginateQuestions:!1,onSubmitSuccess:x,onSubmitError:f})})]}):e.jsxs("div",{className:"flex flex-col items-center justify-center min-h-[400px] gap-4",children:[e.jsxs(It,{variant:"destructive",className:"max-w-md",children:[e.jsx(At,{className:"h-4 w-4"}),e.jsx(Yt,{children:"无法加载问卷配置"})]}),e.jsx(S,{variant:"outline",onClick:()=>window.location.reload(),children:"重试"})]})}function T_(){const[n,r]=u.useState(null),[i,d]=u.useState(!0),[m,x]=u.useState("未知版本");u.useEffect(()=>{(async()=>{try{const y=await Lg();x(y.version||"未知版本")}catch(y){console.error("Failed to get MaiBot version:",y),x("获取失败")}const j=JSON.parse(JSON.stringify(C_));r(j),d(!1)})()},[]);const f=u.useMemo(()=>[{questionId:"maibot_version",value:m}],[m]),p=u.useCallback(b=>{console.log("MaiBot Survey submitted:",b)},[]),g=u.useCallback(b=>{console.error("MaiBot Survey submission error:",b)},[]);return i?e.jsx("div",{className:"flex items-center justify-center min-h-[400px]",children:e.jsx(it,{className:"h-8 w-8 animate-spin text-muted-foreground"})}):n?e.jsxs("div",{className:"h-[calc(100vh-4rem)] flex flex-col p-4 sm:p-6",children:[e.jsxs("div",{className:"mb-4 sm:mb-6 shrink-0",children:[e.jsxs("h1",{className:"text-2xl sm:text-3xl font-bold flex items-center gap-2",children:[e.jsx(bg,{className:"h-8 w-8",strokeWidth:2}),"麦麦使用体验反馈问卷"]}),e.jsx("p",{className:"text-muted-foreground mt-1 text-sm sm:text-base",children:"感谢您的反馈,帮助我们打造更好的 AI 伙伴"})]}),e.jsx("div",{className:"flex-1 min-h-0",children:e.jsx(pj,{config:n,initialAnswers:f,showProgress:!0,paginateQuestions:!1,onSubmitSuccess:p,onSubmitError:g})})]}):e.jsxs("div",{className:"flex flex-col items-center justify-center min-h-[400px] gap-4",children:[e.jsxs(It,{variant:"destructive",className:"max-w-md",children:[e.jsx(At,{className:"h-4 w-4"}),e.jsx(Yt,{children:"无法加载问卷配置"})]}),e.jsx(S,{variant:"outline",onClick:()=>window.location.reload(),children:"重试"})]})}function E_(){const n=va(),[r,i]=u.useState(!0);return u.useEffect(()=>{let d=!1;return(async()=>{try{const x=await Ju();!d&&!x&&n({to:"/auth"})}catch{d||n({to:"/auth"})}finally{d||i(!1)}})(),()=>{d=!0}},[n]),{checking:r}}async function z_(){return await Ju()}const A_=tr("pointer-events-none inline-flex select-none items-center gap-1 rounded border bg-muted px-1.5 font-mono font-medium opacity-100",{variants:{size:{sm:"h-5 text-[10px]",default:"h-6 text-xs",lg:"h-7 text-sm"}},defaultVariants:{size:"default"}}),gj=u.forwardRef(({className:n,size:r,abbrTitle:i,children:d,...m},x)=>e.jsx("kbd",{className:$(A_({size:r,className:n})),ref:x,...m,children:i?e.jsx("abbr",{title:i,children:d}):d}));gj.displayName="Kbd";const M_=[{icon:Jc,title:"首页",description:"查看仪表板概览",path:"/",category:"概览"},{icon:Sa,title:"麦麦主程序配置",description:"配置麦麦的核心设置",path:"/config/bot",category:"配置"},{icon:Ng,title:"麦麦模型提供商配置",description:"配置模型提供商",path:"/config/modelProvider",category:"配置"},{icon:yg,title:"麦麦模型配置",description:"配置模型参数",path:"/config/model",category:"配置"},{icon:Vu,title:"表情包管理",description:"管理麦麦的表情包",path:"/resource/emoji",category:"资源"},{icon:Rl,title:"表达方式管理",description:"管理麦麦的表达方式",path:"/resource/expression",category:"资源"},{icon:wg,title:"人物信息管理",description:"管理人物信息",path:"/resource/person",category:"资源"},{icon:sr,title:"黑话管理",description:"管理麦麦学习到的黑话和俚语",path:"/resource/jargon",category:"资源"},{icon:Ny,title:"统计信息",description:"查看使用统计",path:"/statistics",category:"监控"},{icon:Ol,title:"插件市场",description:"浏览和安装插件",path:"/plugins",category:"扩展"},{icon:Qu,title:"日志查看器",description:"查看系统日志",path:"/logs",category:"监控"},{icon:ar,title:"系统设置",description:"配置系统参数",path:"/settings",category:"系统"}];function D_({open:n,onOpenChange:r}){const[i,d]=u.useState(""),[m,x]=u.useState(0),f=va(),p=M_.filter(j=>j.title.toLowerCase().includes(i.toLowerCase())||j.description.toLowerCase().includes(i.toLowerCase())||j.category.toLowerCase().includes(i.toLowerCase()));u.useEffect(()=>{n&&(d(""),x(0))},[n]);const g=u.useCallback(j=>{f({to:j}),r(!1)},[f,r]),b=u.useCallback(j=>{j.key==="ArrowDown"?(j.preventDefault(),x(y=>(y+1)%p.length)):j.key==="ArrowUp"?(j.preventDefault(),x(y=>(y-1+p.length)%p.length)):j.key==="Enter"&&p[m]&&(j.preventDefault(),g(p[m].path))},[p,m,g]);return e.jsx(qs,{open:n,onOpenChange:r,children:e.jsxs(Ls,{className:"max-w-2xl p-0 gap-0",children:[e.jsxs(Us,{className:"px-4 pt-4 pb-0",children:[e.jsx(Bs,{className:"sr-only",children:"搜索"}),e.jsxs("div",{className:"relative",children:[e.jsx(Mt,{className:"absolute left-3 top-1/2 h-5 w-5 -translate-y-1/2 text-muted-foreground"}),e.jsx(ie,{value:i,onChange:j=>{d(j.target.value),x(0)},onKeyDown:b,placeholder:"搜索页面...",className:"h-12 pl-11 text-base border-0 focus-visible:ring-0 shadow-none",autoFocus:!0})]})]}),e.jsx("div",{className:"border-t",children:e.jsx(Ze,{className:"h-[400px]",children:p.length>0?e.jsx("div",{className:"p-2",children:p.map((j,y)=>{const N=j.icon;return e.jsxs("button",{onClick:()=>g(j.path),onMouseEnter:()=>x(y),className:$("w-full flex items-center gap-3 px-3 py-2.5 rounded-md text-left transition-colors",y===m?"bg-accent text-accent-foreground":"hover:bg-accent/50"),children:[e.jsx(N,{className:"h-5 w-5 flex-shrink-0"}),e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsx("div",{className:"font-medium text-sm",children:j.title}),e.jsx("div",{className:"text-xs text-muted-foreground truncate",children:j.description})]}),e.jsx("div",{className:"text-xs text-muted-foreground px-2 py-1 bg-muted rounded",children:j.category})]},j.path)})}):e.jsxs("div",{className:"flex flex-col items-center justify-center py-12 text-center",children:[e.jsx(Mt,{className:"h-12 w-12 text-muted-foreground/50 mb-4"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:i?"未找到匹配的页面":"输入关键词开始搜索"})]})})}),e.jsx("div",{className:"border-t px-4 py-3 flex items-center justify-between text-xs text-muted-foreground",children:e.jsxs("div",{className:"flex items-center gap-4",children:[e.jsxs("span",{className:"flex items-center gap-1",children:[e.jsx("kbd",{className:"px-1.5 py-0.5 bg-muted rounded border",children:"↑"}),e.jsx("kbd",{className:"px-1.5 py-0.5 bg-muted rounded border",children:"↓"}),"导航"]}),e.jsxs("span",{className:"flex items-center gap-1",children:[e.jsx("kbd",{className:"px-1.5 py-0.5 bg-muted rounded border",children:"Enter"}),"选择"]}),e.jsxs("span",{className:"flex items-center gap-1",children:[e.jsx("kbd",{className:"px-1.5 py-0.5 bg-muted rounded border",children:"Esc"}),"关闭"]})]})})]})})}const O_=$N,R_=FN,L_=VN,jj=u.forwardRef(({className:n,sideOffset:r=4,...i},d)=>e.jsx(GN,{children:e.jsx(ng,{ref:d,sideOffset:r,className:$("z-50 overflow-hidden rounded-md bg-primary px-3 py-1.5 text-xs text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-tooltip-content-transform-origin]",n),...i})}));jj.displayName=ng.displayName;function U_({children:n}){const{checking:r}=E_(),[i,d]=u.useState(!0),[m,x]=u.useState(!1),[f,p]=u.useState(!1),{theme:g,setTheme:b}=Yu(),j=Hb();if(u.useEffect(()=>{const U=O=>{(O.metaKey||O.ctrlKey)&&O.key==="k"&&(O.preventDefault(),p(!0))};return window.addEventListener("keydown",U),()=>window.removeEventListener("keydown",U)},[]),r)return e.jsx("div",{className:"flex h-screen items-center justify-center bg-background",children:e.jsx("div",{className:"text-muted-foreground",children:"正在验证登录状态..."})});const y=[{title:"概览",items:[{icon:Jc,label:"首页",path:"/"}]},{title:"麦麦配置编辑",items:[{icon:Sa,label:"麦麦主程序配置",path:"/config/bot"},{icon:Ng,label:"AI模型厂商配置",path:"/config/modelProvider",tourId:"sidebar-model-provider"},{icon:yg,label:"模型管理与分配",path:"/config/model",tourId:"sidebar-model-management"},{icon:Wf,label:"麦麦适配器配置",path:"/config/adapter"}]},{title:"麦麦资源管理",items:[{icon:Vu,label:"表情包管理",path:"/resource/emoji"},{icon:Rl,label:"表达方式管理",path:"/resource/expression"},{icon:sr,label:"黑话管理",path:"/resource/jargon"},{icon:wg,label:"人物信息管理",path:"/resource/person"},{icon:jg,label:"知识库图谱可视化",path:"/resource/knowledge-graph"}]},{title:"扩展与监控",items:[{icon:Ol,label:"插件市场",path:"/plugins"},{icon:vg,label:"模型分配预设市场",path:"/model-presets"},{icon:Wf,label:"插件配置",path:"/plugin-config"},{icon:Qu,label:"日志查看器",path:"/logs"},{icon:Rl,label:"本地聊天室",path:"/chat"}]},{title:"系统",items:[{icon:ar,label:"系统设置",path:"/settings"}]}],k=g==="system"?window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light":g,w=async()=>{await V0()};return e.jsx(O_,{delayDuration:300,children:e.jsxs("div",{className:"flex h-screen overflow-hidden",children:[e.jsxs("aside",{className:$("fixed inset-y-0 left-0 z-50 flex flex-col border-r bg-card transition-all duration-300 lg:relative lg:z-0","w-64 lg:w-auto",i?"lg:w-64":"lg:w-16",m?"translate-x-0":"-translate-x-full lg:translate-x-0"),children:[e.jsx("div",{className:"flex h-16 items-center border-b px-4",children:e.jsxs("div",{className:$("relative flex items-center justify-center flex-1 transition-all overflow-hidden","lg:flex-1",!i&&"lg:flex-none lg:w-8"),children:[e.jsxs("div",{className:$("flex items-baseline gap-2",!i&&"lg:hidden"),children:[e.jsx("span",{className:"font-bold text-xl text-primary-gradient whitespace-nowrap",children:"MaiBot WebUI"}),e.jsx("span",{className:"text-xs text-primary/60 whitespace-nowrap",children:T0()})]}),!i&&e.jsx("span",{className:"hidden lg:block font-bold text-primary-gradient text-2xl",children:"M"})]})}),e.jsx(Ze,{className:$("flex-1 overflow-x-hidden",!i&&"lg:w-16"),children:e.jsx("nav",{className:$("p-4",!i&&"lg:p-2 lg:w-16"),children:e.jsx("ul",{className:$("space-y-6",!i&&"lg:space-y-3 lg:w-full"),children:y.map((U,O)=>e.jsxs("li",{children:[e.jsx("div",{className:$("px-3 h-[1.25rem]","mb-2",!i&&"lg:mb-1 lg:invisible"),children:e.jsx("h3",{className:"text-xs font-semibold uppercase tracking-wider text-muted-foreground/60 whitespace-nowrap",children:U.title})}),!i&&O>0&&e.jsx("div",{className:"hidden lg:block mb-2 border-t border-border"}),e.jsx("ul",{className:"space-y-1",children:U.items.map(B=>{const Y=j({to:B.path}),L=B.icon,z=e.jsxs(e.Fragment,{children:[Y&&e.jsx("div",{className:"absolute left-0 top-1/2 h-8 w-1 -translate-y-1/2 rounded-r-full bg-primary transition-opacity duration-300"}),e.jsxs("div",{className:$("flex items-center transition-all duration-300",i?"gap-3":"gap-3 lg:gap-0"),children:[e.jsx(L,{className:$("h-5 w-5 flex-shrink-0",Y&&"text-primary"),strokeWidth:2,fill:"none"}),e.jsx("span",{className:$("text-sm font-medium whitespace-nowrap transition-all duration-300",Y&&"font-semibold",i?"opacity-100 max-w-[200px]":"opacity-100 max-w-[200px] lg:opacity-0 lg:max-w-0 lg:overflow-hidden"),children:B.label})]})]});return e.jsx("li",{className:"relative",children:e.jsxs(R_,{children:[e.jsx(L_,{asChild:!0,children:e.jsx(Kn,{to:B.path,"data-tour":B.tourId,className:$("relative flex items-center rounded-lg py-2 transition-all duration-300","hover:bg-accent hover:text-accent-foreground",Y?"bg-accent text-foreground":"text-muted-foreground hover:text-foreground",i?"px-3":"px-3 lg:px-0 lg:justify-center lg:w-12 lg:mx-auto"),onClick:()=>x(!1),children:z})}),!i&&e.jsx(jj,{side:"right",className:"hidden lg:block",children:e.jsx("p",{children:B.label})})]})},B.path)})})]},U.title))})})})]}),m&&e.jsx("div",{className:"fixed inset-0 z-40 bg-black/50 lg:hidden",onClick:()=>x(!1)}),e.jsxs("div",{className:"flex flex-1 flex-col overflow-hidden",children:[e.jsxs("header",{className:"flex h-16 items-center justify-between border-b bg-card/80 backdrop-blur-md px-4 sticky top-0 z-10",children:[e.jsxs("div",{className:"flex items-center gap-4",children:[e.jsx("button",{onClick:()=>x(!m),className:"rounded-lg p-2 hover:bg-accent lg:hidden",children:e.jsx(yy,{className:"h-5 w-5"})}),e.jsx("button",{onClick:()=>d(!i),className:"hidden rounded-lg p-2 hover:bg-accent lg:block",title:i?"收起侧边栏":"展开侧边栏",children:e.jsx(il,{className:$("h-5 w-5 transition-transform",!i&&"rotate-180")})})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsxs("button",{onClick:()=>p(!0),className:"relative hidden md:flex items-center w-64 h-9 pl-9 pr-16 bg-background/50 border rounded-md hover:bg-accent/50 transition-colors text-left",children:[e.jsx(Mt,{className:"absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground"}),e.jsx("span",{className:"text-sm text-muted-foreground",children:"搜索..."}),e.jsxs(gj,{size:"sm",className:"absolute right-2 top-1/2 -translate-y-1/2",children:[e.jsx("span",{className:"text-xs",children:"⌘"}),"K"]})]}),e.jsx(D_,{open:f,onOpenChange:p}),e.jsxs(S,{variant:"ghost",size:"sm",onClick:()=>window.open("https://docs.mai-mai.org","_blank"),className:"gap-2",title:"查看麦麦文档",children:[e.jsx(wy,{className:"h-4 w-4"}),e.jsx("span",{className:"hidden sm:inline",children:"麦麦文档"})]}),e.jsx("button",{onClick:U=>{w0(k==="dark"?"light":"dark",b,U)},className:"rounded-lg p-2 hover:bg-accent",title:k==="dark"?"切换到浅色模式":"切换到深色模式",children:k==="dark"?e.jsx(xg,{className:"h-5 w-5"}):e.jsx(hg,{className:"h-5 w-5"})}),e.jsx("div",{className:"h-6 w-px bg-border"}),e.jsxs(S,{variant:"ghost",size:"sm",onClick:w,className:"gap-2",title:"登出系统",children:[e.jsx(_y,{className:"h-4 w-4"}),e.jsx("span",{className:"hidden sm:inline",children:"登出"})]})]})]}),e.jsx("main",{className:"flex-1 overflow-hidden bg-background",children:n})]})]})})}function B_(n){const r=n.split(` -`).slice(1),i=[];for(const d of r){const m=d.trim();if(!m.startsWith("at "))continue;const x=m.match(/at\s+(?:(.+?)\s+\()?(.+?):(\d+):(\d+)\)?$/);x?i.push({functionName:x[1]||"",fileName:x[2],lineNumber:x[3],columnNumber:x[4],raw:m}):i.push({functionName:"",fileName:"",lineNumber:"",columnNumber:"",raw:m})}return i}function H_({error:n,errorInfo:r}){const[i,d]=u.useState(!0),[m,x]=u.useState(!1),[f,p]=u.useState(!1),g=n.stack?B_(n.stack):[],b=async()=>{const j=` -Error: ${n.name} -Message: ${n.message} - -Stack Trace: -${n.stack||"No stack trace available"} - -Component Stack: -${r?.componentStack||"No component stack available"} - -URL: ${window.location.href} -User Agent: ${navigator.userAgent} -Time: ${new Date().toISOString()} - `.trim();try{await navigator.clipboard.writeText(j),p(!0),setTimeout(()=>p(!1),2e3)}catch(y){console.error("Failed to copy:",y)}};return e.jsxs("div",{className:"space-y-4",children:[e.jsxs(It,{variant:"destructive",className:"border-red-500/50 bg-red-500/10",children:[e.jsx(Ca,{className:"h-4 w-4"}),e.jsxs(Yt,{className:"font-mono text-sm",children:[e.jsxs("span",{className:"font-semibold",children:[n.name,":"]})," ",n.message]})]}),g.length>0&&e.jsxs(qu,{open:i,onOpenChange:d,children:[e.jsx(Gu,{asChild:!0,children:e.jsxs(S,{variant:"ghost",className:"w-full justify-between p-3 h-auto",children:[e.jsxs("span",{className:"font-semibold text-sm flex items-center gap-2",children:[e.jsx(Sy,{className:"h-4 w-4"}),"Stack Trace (",g.length," frames)"]}),i?e.jsx(di,{className:"h-4 w-4"}):e.jsx(Ll,{className:"h-4 w-4"})]})}),e.jsx($u,{children:e.jsx(Ze,{className:"h-[280px] rounded-md border bg-muted/30",children:e.jsx("div",{className:"p-3 space-y-1",children:g.map((j,y)=>e.jsx("div",{className:"font-mono text-xs p-2 rounded hover:bg-muted/50 transition-colors",children:e.jsxs("div",{className:"flex items-start gap-2",children:[e.jsxs("span",{className:"text-muted-foreground w-6 text-right flex-shrink-0",children:[y+1,"."]}),e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsx("span",{className:"text-primary font-medium",children:j.functionName}),j.fileName&&e.jsxs("div",{className:"text-muted-foreground mt-0.5 break-all",children:[j.fileName,j.lineNumber&&e.jsxs("span",{className:"text-yellow-600 dark:text-yellow-400",children:[":",j.lineNumber,":",j.columnNumber]})]})]})]})},y))})})})]}),r?.componentStack&&e.jsxs(qu,{open:m,onOpenChange:x,children:[e.jsx(Gu,{asChild:!0,children:e.jsxs(S,{variant:"ghost",className:"w-full justify-between p-3 h-auto",children:[e.jsxs("span",{className:"font-semibold text-sm flex items-center gap-2",children:[e.jsx(Ca,{className:"h-4 w-4"}),"Component Stack"]}),m?e.jsx(di,{className:"h-4 w-4"}):e.jsx(Ll,{className:"h-4 w-4"})]})}),e.jsx($u,{children:e.jsx(Ze,{className:"h-[200px] rounded-md border bg-muted/30",children:e.jsx("pre",{className:"p-3 font-mono text-xs whitespace-pre-wrap text-muted-foreground",children:r.componentStack})})})]}),e.jsx(S,{variant:"outline",size:"sm",onClick:b,className:"w-full",children:f?e.jsxs(e.Fragment,{children:[e.jsx(Qt,{className:"mr-2 h-4 w-4 text-green-500"}),"已复制到剪贴板"]}):e.jsxs(e.Fragment,{children:[e.jsx(Vc,{className:"mr-2 h-4 w-4"}),"复制错误信息"]})})]})}function vj({error:n,errorInfo:r}){const i=()=>{window.location.href="/"},d=()=>{window.location.reload()};return e.jsx("div",{className:"min-h-screen flex items-center justify-center bg-background p-4",children:e.jsxs(Fe,{className:"w-full max-w-2xl shadow-lg",children:[e.jsxs(ts,{className:"text-center pb-2",children:[e.jsx("div",{className:"mx-auto flex h-16 w-16 items-center justify-center rounded-full bg-red-100 dark:bg-red-900/30 mb-4",children:e.jsx(Ca,{className:"h-8 w-8 text-red-600 dark:text-red-400"})}),e.jsx(as,{className:"text-2xl font-bold",children:"页面出现了问题"}),e.jsx(et,{className:"text-base mt-2",children:"应用程序遇到了意外错误。您可以尝试刷新页面或返回首页。"})]}),e.jsxs(xs,{className:"space-y-4",children:[e.jsx(H_,{error:n,errorInfo:r}),e.jsxs("div",{className:"flex flex-col sm:flex-row gap-2 pt-2",children:[e.jsxs(S,{onClick:d,className:"flex-1",children:[e.jsx(zt,{className:"mr-2 h-4 w-4"}),"刷新页面"]}),e.jsxs(S,{onClick:i,variant:"outline",className:"flex-1",children:[e.jsx(Jc,{className:"mr-2 h-4 w-4"}),"返回首页"]})]}),e.jsx("p",{className:"text-xs text-center text-muted-foreground pt-2",children:"如果问题持续存在,请将错误信息复制并反馈给开发者"})]})]})})}class q_ extends u.Component{constructor(r){super(r),this.state={hasError:!1,error:null,errorInfo:null}}static getDerivedStateFromError(r){return{hasError:!0,error:r}}componentDidCatch(r,i){console.error("ErrorBoundary caught an error:",r,i),this.setState({errorInfo:i})}handleReset=()=>{this.setState({hasError:!1,error:null,errorInfo:null})};render(){return this.state.hasError&&this.state.error?this.props.fallback?this.props.fallback:e.jsx(vj,{error:this.state.error,errorInfo:this.state.errorInfo}):this.props.children}}function bj({error:n}){return e.jsx(vj,{error:n,errorInfo:null})}const gi=qb({component:()=>e.jsxs(e.Fragment,{children:[e.jsx(_p,{}),!1]}),beforeLoad:()=>{if(window.location.pathname==="/"&&!z_())throw $b({to:"/auth"})}}),G_=tt({getParentRoute:()=>gi,path:"/auth",component:Q0}),$_=tt({getParentRoute:()=>gi,path:"/setup",component:iw}),jt=tt({getParentRoute:()=>gi,id:"protected",component:()=>e.jsx(U_,{children:e.jsx(_p,{})}),errorComponent:({error:n})=>e.jsx(bj,{error:n})}),F_=tt({getParentRoute:()=>jt,path:"/",component:N0}),V_=tt({getParentRoute:()=>jt,path:"/config/bot",component:Bw}),Q_=tt({getParentRoute:()=>jt,path:"/config/modelProvider",component:Kw}),I_=tt({getParentRoute:()=>jt,path:"/config/model",component:o1}),Y_=tt({getParentRoute:()=>jt,path:"/config/adapter",component:u1}),K_=tt({getParentRoute:()=>jt,path:"/resource/emoji",component:O1}),X_=tt({getParentRoute:()=>jt,path:"/resource/expression",component:I1}),J_=tt({getParentRoute:()=>jt,path:"/resource/person",component:p2}),Z_=tt({getParentRoute:()=>jt,path:"/resource/jargon",component:r2}),P_=tt({getParentRoute:()=>jt,path:"/resource/knowledge-graph",component:S2}),W_=tt({getParentRoute:()=>jt,path:"/logs",component:k2}),eS=tt({getParentRoute:()=>jt,path:"/chat",component:u_}),sS=tt({getParentRoute:()=>jt,path:"/plugins",component:Z2}),tS=tt({getParentRoute:()=>jt,path:"/model-presets",component:P2}),aS=tt({getParentRoute:()=>jt,path:"/plugin-config",component:s_}),lS=tt({getParentRoute:()=>jt,path:"/plugin-mirrors",component:t_}),nS=tt({getParentRoute:()=>jt,path:"/settings",component:B0}),rS=tt({getParentRoute:()=>jt,path:"/survey/webui-feedback",component:k_}),iS=tt({getParentRoute:()=>jt,path:"/survey/maibot-feedback",component:T_}),cS=tt({getParentRoute:()=>gi,path:"*",component:Ug}),oS=gi.addChildren([G_,$_,jt.addChildren([F_,V_,Q_,I_,Y_,K_,X_,Z_,J_,P_,sS,tS,aS,lS,W_,eS,nS,rS,iS]),cS]),dS=Gb({routeTree:oS,defaultNotFoundComponent:Ug,defaultErrorComponent:({error:n})=>e.jsx(bj,{error:n})});function uS({children:n,defaultTheme:r="system",storageKey:i="ui-theme",...d}){const[m,x]=u.useState(()=>localStorage.getItem(i)||r);u.useEffect(()=>{const p=window.document.documentElement;if(p.classList.remove("light","dark"),m==="system"){const g=window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light";p.classList.add(g);return}p.classList.add(m)},[m]),u.useEffect(()=>{const p=localStorage.getItem("accent-color");if(p){const g=document.documentElement,j={blue:{hsl:"221.2 83.2% 53.3%",darkHsl:"217.2 91.2% 59.8%",gradient:null},purple:{hsl:"271 91% 65%",darkHsl:"270 95% 75%",gradient:null},green:{hsl:"142 71% 45%",darkHsl:"142 76% 36%",gradient:null},orange:{hsl:"25 95% 53%",darkHsl:"20 90% 48%",gradient:null},pink:{hsl:"330 81% 60%",darkHsl:"330 85% 70%",gradient:null},red:{hsl:"0 84% 60%",darkHsl:"0 90% 70%",gradient:null},"gradient-sunset":{hsl:"15 95% 60%",darkHsl:"15 95% 65%",gradient:"linear-gradient(135deg, hsl(25 95% 53%) 0%, hsl(330 81% 60%) 100%)"},"gradient-ocean":{hsl:"200 90% 55%",darkHsl:"200 90% 60%",gradient:"linear-gradient(135deg, hsl(221.2 83.2% 53.3%) 0%, hsl(189 94% 43%) 100%)"},"gradient-forest":{hsl:"150 70% 45%",darkHsl:"150 75% 40%",gradient:"linear-gradient(135deg, hsl(142 71% 45%) 0%, hsl(158 64% 52%) 100%)"},"gradient-aurora":{hsl:"310 85% 65%",darkHsl:"310 90% 70%",gradient:"linear-gradient(135deg, hsl(271 91% 65%) 0%, hsl(330 81% 60%) 100%)"},"gradient-fire":{hsl:"15 95% 55%",darkHsl:"15 95% 60%",gradient:"linear-gradient(135deg, hsl(0 84% 60%) 0%, hsl(25 95% 53%) 100%)"},"gradient-twilight":{hsl:"250 90% 60%",darkHsl:"250 95% 65%",gradient:"linear-gradient(135deg, hsl(239 84% 67%) 0%, hsl(271 91% 65%) 100%)"}}[p];j&&(g.style.setProperty("--primary",j.hsl),j.gradient?(g.style.setProperty("--primary-gradient",j.gradient),g.classList.add("has-gradient")):(g.style.removeProperty("--primary-gradient"),g.classList.remove("has-gradient")))}},[]);const f={theme:m,setTheme:p=>{localStorage.setItem(i,p),x(p)}};return e.jsx(zg.Provider,{...d,value:f,children:n})}function mS({children:n,defaultEnabled:r=!0,defaultWavesEnabled:i=!0,storageKey:d="enable-animations",wavesStorageKey:m="enable-waves-background"}){const[x,f]=u.useState(()=>{const j=localStorage.getItem(d);return j!==null?j==="true":r}),[p,g]=u.useState(()=>{const j=localStorage.getItem(m);return j!==null?j==="true":i});u.useEffect(()=>{const j=document.documentElement;x?j.classList.remove("no-animations"):j.classList.add("no-animations"),localStorage.setItem(d,String(x))},[x,d]),u.useEffect(()=>{localStorage.setItem(m,String(p))},[p,m]);const b={enableAnimations:x,setEnableAnimations:f,enableWavesBackground:p,setEnableWavesBackground:g};return e.jsx(Ag.Provider,{value:b,children:n})}const xS=QN,Nj=u.forwardRef(({className:n,...r},i)=>e.jsx(rg,{ref:i,className:$("fixed bottom-0 right-0 z-[100] flex max-h-screen w-full flex-col-reverse p-4 sm:max-w-[420px] gap-2",n),...r}));Nj.displayName=rg.displayName;const hS=tr("group pointer-events-auto relative flex w-full items-center justify-between space-x-2 overflow-hidden rounded-md border p-4 pr-6 shadow-lg transition-all data-[swipe=cancel]:translate-x-0 data-[swipe=end]:translate-x-[var(--radix-toast-swipe-end-x)] data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)] data-[swipe=move]:transition-none data-[state=open]:animate-slide-in-from-right data-[state=open]:animate-fade-in data-[state=closed]:animate-slide-out-to-right data-[state=closed]:animate-fade-out data-[swipe=end]:animate-slide-out-to-right",{variants:{variant:{default:"border bg-primary/5 text-foreground backdrop-blur-sm",destructive:"destructive group border-destructive bg-destructive/10 text-destructive-foreground backdrop-blur-sm"}},defaultVariants:{variant:"default"}}),yj=u.forwardRef(({className:n,variant:r,...i},d)=>e.jsx(ig,{ref:d,className:$(hS({variant:r}),n),...i}));yj.displayName=ig.displayName;const fS=u.forwardRef(({className:n,...r},i)=>e.jsx(cg,{ref:i,className:$("inline-flex h-8 shrink-0 items-center justify-center rounded-md border bg-transparent px-3 text-sm font-medium transition-colors hover:bg-secondary focus:outline-none focus:ring-1 focus:ring-ring disabled:pointer-events-none disabled:opacity-50 group-[.destructive]:border-muted/40 group-[.destructive]:hover:border-destructive/30 group-[.destructive]:hover:bg-destructive group-[.destructive]:hover:text-destructive-foreground group-[.destructive]:focus:ring-destructive",n),...r}));fS.displayName=cg.displayName;const wj=u.forwardRef(({className:n,...r},i)=>e.jsx(og,{ref:i,className:$("absolute right-1 top-1 rounded-md p-1 text-foreground/50 opacity-0 transition-opacity hover:text-foreground focus:opacity-100 focus:outline-none focus:ring-1 group-hover:opacity-100 group-[.destructive]:text-red-300 group-[.destructive]:hover:text-red-50 group-[.destructive]:focus:ring-red-400 group-[.destructive]:focus:ring-offset-red-600",n),"toast-close":"",...r,children:e.jsx(rl,{className:"h-4 w-4"})}));wj.displayName=og.displayName;const _j=u.forwardRef(({className:n,...r},i)=>e.jsx(dg,{ref:i,className:$("text-sm font-semibold [&+div]:text-xs",n),...r}));_j.displayName=dg.displayName;const Sj=u.forwardRef(({className:n,...r},i)=>e.jsx(ug,{ref:i,className:$("text-sm opacity-90",n),...r}));Sj.displayName=ug.displayName;function pS(){const{toasts:n}=$s();return e.jsxs(xS,{children:[n.map(function({id:r,title:i,description:d,action:m,...x}){return e.jsxs(yj,{...x,children:[e.jsxs("div",{className:"grid gap-1",children:[i&&e.jsx(_j,{children:i}),d&&e.jsx(Sj,{children:d})]}),m,e.jsx(wj,{})]},r)}),e.jsx(Nj,{})]})}d0.createRoot(document.getElementById("root")).render(e.jsx(u.StrictMode,{children:e.jsx(q_,{children:e.jsx(uS,{defaultTheme:"system",children:e.jsx(mS,{children:e.jsxs(Fw,{children:[e.jsx(Fb,{router:dS}),e.jsx(Iw,{}),e.jsx(pS,{})]})})})})})); diff --git a/webui/dist/assets/index-D-S1XZ00.js b/webui/dist/assets/index-D-S1XZ00.js new file mode 100644 index 00000000..7d7591c1 --- /dev/null +++ b/webui/dist/assets/index-D-S1XZ00.js @@ -0,0 +1,86 @@ +import{r as m,j as e,L as ci,e as ka,R as Ct,b as jN,f as vN,g as bN,h as NN,k as lt,l as yN,m as wN,O as Vp,n as _N}from"./router-Bz250laD.js";import{a as SN,b as CN,g as kN}from"./react-vendor-BmxF9s7Q.js";import{N as TN,c as EN,O as gi,P as zN,g as Du}from"./utils-BXc2jIuz.js";import{L as Fp,T as Ip,C as Qp,R as MN,a as Yp,V as AN,b as ON,S as Kp,c as DN,d as Xp,I as RN,e as Pp,f as LN,g as Jp,h as UN,i as BN,j as HN,O as Zp,P as $N,k as Wp,l as eg,D as sg,A as tg,m as ag,n as qN,o as GN,p as lg,q as VN,r as ng,s as FN,t as IN,u as QN,v as YN,w as KN,x as ig,y as rg,F as cg,z as og,B as XN,E as PN}from"./radix-extra-DDK-u9dm.js";import{R as JN,T as ZN,L as WN,g as ey,C as Xc,X as Pc,Y as ur,h as sy,B as Ru,j as Jc,P as ty,k as ay,l as ly}from"./charts-DbiuC1q1.js";import{S as ny,G as dg,O as ug,o as iy,C as mg,p as ry,T as xg,D as hg,R as cy,q as oy,H as fg,I as dy,J as pg,K as gg,L as uy,M as jg,V as my,N as vg,Q as bg,U as xy,X as hy,Y as Ng,Z as fy,_ as py,$ as yg,a0 as gy,e as jy,f as vy,c as wg,P as fo,d as nm,b as Zu,h as by,l as Ny,m as yy,a1 as wy,a2 as _g,a3 as _y,a4 as Sy,a5 as Cy,a6 as Sg,a7 as Cg,a8 as kg,a9 as Tg,aa as Eg,ab as zg,ac as ky}from"./radix-core-9dEfQl-6.js";import{R as At,a as yr,C as Ot,b as aa,L as tt,P as Mr,Z as hn,F as Aa,c as Ty,S as ji,d as Ey,M as Fl,A as zy,D as My,e as ro,f as xi,T as Ay,X as fl,g as Oy,h as Dy,I as Ra,i as Oa,j as ea,k as co,E as wr,l as Gt,m as Mg,H as Ry,n as es,o as Da,U as _r,p as Ag,q as Og,r as xp,K as Dg,s as Rg,t as Ly,u as ao,v as Uy,B as fr,w as oo,x as im,y as By,z as Hy,G as $t,J as po,N as hi,O as ut,Q as Fa,V as fi,W as rm,Y as Lg,_ as Ar,$ as $y,a0 as qy,a1 as fn,a2 as vi,a3 as pl,a4 as Ya,a5 as bi,a6 as cm,a7 as Gy,a8 as Vy,a9 as Vl,aa as Fy,ab as Ug,ac as lo,ad as pn,ae as Iy,af as pi,ag as Qy,ah as Wu,ai as em,aj as Bg,ak as Yy,al as Ky,am as hp,an as Xy,ao as xl,ap as Lu,aq as fp,ar as Hg,as as Py,at as $g,au as Uu,av as Jy,aw as Zy,ax as Wy,ay as e0,az as s0,aA as qg,aB as Gg,aC as Vg,aD as Fg,aE as t0,aF as pp,aG as a0,aH as l0,aI as n0,aJ as i0}from"./icons-B6qV_tuI.js";import{S as r0,p as c0,j as o0,a as d0,E as gp,R as u0,o as m0}from"./codemirror-BEE0n9kQ.js";import{u as Ig,a as uo,s as Qg,K as Yg,P as Kg,b as Xg,D as Pg,c as Jg,S as Zg,v as x0,d as Wg,C as ej,h as h0}from"./dnd-B_gmzEl7.js";import{_ as la,c as f0,g as sj,D as p0,z as Zc}from"./misc-CKjrIrIJ.js";import{D as g0,U as j0}from"./uppy-BMZiFQyG.js";import{M as v0,r as b0,a as N0,b as y0}from"./markdown-kUhwkcQP.js";import{c as w0,H as mo,P as xo,u as _0,d as S0,R as C0,B as k0,e as T0,C as E0,M as z0,f as M0}from"./reactflow-DLoXAt4c.js";(function(){const i=document.createElement("link").relList;if(i&&i.supports&&i.supports("modulepreload"))return;for(const u of document.querySelectorAll('link[rel="modulepreload"]'))o(u);new MutationObserver(u=>{for(const x of u)if(x.type==="childList")for(const h of x.addedNodes)h.tagName==="LINK"&&h.rel==="modulepreload"&&o(h)}).observe(document,{childList:!0,subtree:!0});function r(u){const x={};return u.integrity&&(x.integrity=u.integrity),u.referrerPolicy&&(x.referrerPolicy=u.referrerPolicy),u.crossOrigin==="use-credentials"?x.credentials="include":u.crossOrigin==="anonymous"?x.credentials="omit":x.credentials="same-origin",x}function o(u){if(u.ep)return;u.ep=!0;const x=r(u);fetch(u.href,x)}})();var Bu={exports:{}},mr={},Hu={exports:{}},$u={};var jp;function A0(){return jp||(jp=1,(function(l){function i(U,P){var X=U.length;U.push(P);e:for(;0>>1,B=U[L];if(0>>1;L<_e;){var Ne=2*(L+1)-1,Ce=U[Ne],ve=Ne+1,ze=U[ve];if(0>u(Ce,X))veu(ze,Ce)?(U[L]=ze,U[ve]=X,L=ve):(U[L]=Ce,U[Ne]=X,L=Ne);else if(veu(ze,X))U[L]=ze,U[ve]=X,L=ve;else break e}}return P}function u(U,P){var X=U.sortIndex-P.sortIndex;return X!==0?X:U.id-P.id}if(l.unstable_now=void 0,typeof performance=="object"&&typeof performance.now=="function"){var x=performance;l.unstable_now=function(){return x.now()}}else{var h=Date,f=h.now();l.unstable_now=function(){return h.now()-f}}var g=[],j=[],v=1,y=null,b=3,S=!1,w=!1,O=!1,A=!1,D=typeof setTimeout=="function"?setTimeout:null,V=typeof clearTimeout=="function"?clearTimeout:null,z=typeof setImmediate<"u"?setImmediate:null;function _(U){for(var P=r(j);P!==null;){if(P.callback===null)o(j);else if(P.startTime<=U)o(j),P.sortIndex=P.expirationTime,i(g,P);else break;P=r(j)}}function T(U){if(O=!1,_(U),!w)if(r(g)!==null)w=!0,$||($=!0,Se());else{var P=r(j);P!==null&&be(T,P.startTime-U)}}var $=!1,E=-1,se=5,te=-1;function ne(){return A?!0:!(l.unstable_now()-teU&&ne());){var L=y.callback;if(typeof L=="function"){y.callback=null,b=y.priorityLevel;var B=L(y.expirationTime<=U);if(U=l.unstable_now(),typeof B=="function"){y.callback=B,_(U),P=!0;break s}y===r(g)&&o(g),_(U)}else o(g);y=r(g)}if(y!==null)P=!0;else{var _e=r(j);_e!==null&&be(T,_e.startTime-U),P=!1}}break e}finally{y=null,b=X,S=!1}P=void 0}}finally{P?Se():$=!1}}}var Se;if(typeof z=="function")Se=function(){z(ue)};else if(typeof MessageChannel<"u"){var oe=new MessageChannel,je=oe.port2;oe.port1.onmessage=ue,Se=function(){je.postMessage(null)}}else Se=function(){D(ue,0)};function be(U,P){E=D(function(){U(l.unstable_now())},P)}l.unstable_IdlePriority=5,l.unstable_ImmediatePriority=1,l.unstable_LowPriority=4,l.unstable_NormalPriority=3,l.unstable_Profiling=null,l.unstable_UserBlockingPriority=2,l.unstable_cancelCallback=function(U){U.callback=null},l.unstable_forceFrameRate=function(U){0>U||125L?(U.sortIndex=X,i(j,U),r(g)===null&&U===r(j)&&(O?(V(E),E=-1):O=!0,be(T,X-L))):(U.sortIndex=B,i(g,U),w||S||(w=!0,$||($=!0,Se()))),U},l.unstable_shouldYield=ne,l.unstable_wrapCallback=function(U){var P=b;return function(){var X=b;b=P;try{return U.apply(this,arguments)}finally{b=X}}}})($u)),$u}var vp;function O0(){return vp||(vp=1,Hu.exports=A0()),Hu.exports}var bp;function D0(){if(bp)return mr;bp=1;var l=O0(),i=SN(),r=CN();function o(s){var t="https://react.dev/errors/"+s;if(1B||(s.current=L[B],L[B]=null,B--)}function Ce(s,t){B++,L[B]=s.current,s.current=t}var ve=_e(null),ze=_e(null),Q=_e(null),xe=_e(null);function Te(s,t){switch(Ce(Q,t),Ce(ze,s),Ce(ve,null),t.nodeType){case 9:case 11:s=(s=t.documentElement)&&(s=s.namespaceURI)?Lf(s):0;break;default:if(s=t.tagName,t=t.namespaceURI)t=Lf(t),s=Uf(t,s);else switch(s){case"svg":s=1;break;case"math":s=2;break;default:s=0}}Ne(ve),Ce(ve,s)}function J(){Ne(ve),Ne(ze),Ne(Q)}function le(s){s.memoizedState!==null&&Ce(xe,s);var t=ve.current,a=Uf(t,s.type);t!==a&&(Ce(ze,s),Ce(ve,a))}function qe(s){ze.current===s&&(Ne(ve),Ne(ze)),xe.current===s&&(Ne(xe),rr._currentValue=X)}var We,fe;function ls(s){if(We===void 0)try{throw Error()}catch(a){var t=a.stack.trim().match(/\n( *(at )?)/);We=t&&t[1]||"",fe=-1)":-1c||M[n]!==K[c]){var ce=` +`+M[n].replace(" at new "," at ");return s.displayName&&ce.includes("")&&(ce=ce.replace("",s.displayName)),ce}while(1<=n&&0<=c);break}}}finally{G=!1,Error.prepareStackTrace=a}return(a=s?s.displayName||s.name:"")?ls(a):""}function re(s,t){switch(s.tag){case 26:case 27:case 5:return ls(s.type);case 16:return ls("Lazy");case 13:return s.child!==t&&t!==null?ls("Suspense Fallback"):ls("Suspense");case 19:return ls("SuspenseList");case 0:case 15:return Me(s.type,!1);case 11:return Me(s.type.render,!1);case 1:return Me(s.type,!0);case 31:return ls("Activity");default:return""}}function pe(s){try{var t="",a=null;do t+=re(s,a),a=s,s=s.return;while(s);return t}catch(n){return` +Error generating stack: `+n.message+` +`+n.stack}}var Ee=Object.prototype.hasOwnProperty,Ie=l.unstable_scheduleCallback,$e=l.unstable_cancelCallback,Vt=l.unstable_shouldYield,_t=l.unstable_requestPaint,nt=l.unstable_now,F=l.unstable_getCurrentPriorityLevel,He=l.unstable_ImmediatePriority,De=l.unstable_UserBlockingPriority,ye=l.unstable_NormalPriority,ps=l.unstable_LowPriority,ss=l.unstable_IdlePriority,Es=l.log,Ms=l.unstable_setDisableYieldValue,Ls=null,ts=null;function Pe(s){if(typeof Es=="function"&&Ms(s),ts&&typeof ts.setStrictMode=="function")try{ts.setStrictMode(Ls,s)}catch{}}var Xe=Math.clz32?Math.clz32:Xs,Os=Math.log,kt=Math.LN2;function Xs(s){return s>>>=0,s===0?32:31-(Os(s)/kt|0)|0}var Ss=256,xt=262144,W=4194304;function de(s){var t=s&42;if(t!==0)return t;switch(s&-s){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:return 64;case 128:return 128;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:return s&261888;case 262144:case 524288:case 1048576:case 2097152:return s&3932160;case 4194304:case 8388608:case 16777216:case 33554432:return s&62914560;case 67108864:return 67108864;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 0;default:return s}}function ys(s,t,a){var n=s.pendingLanes;if(n===0)return 0;var c=0,d=s.suspendedLanes,p=s.pingedLanes;s=s.warmLanes;var N=n&134217727;return N!==0?(n=N&~d,n!==0?c=de(n):(p&=N,p!==0?c=de(p):a||(a=N&~s,a!==0&&(c=de(a))))):(N=n&~d,N!==0?c=de(N):p!==0?c=de(p):a||(a=n&~s,a!==0&&(c=de(a)))),c===0?0:t!==0&&t!==c&&(t&d)===0&&(d=c&-c,a=t&-t,d>=a||d===32&&(a&4194048)!==0)?t:c}function Tt(s,t){return(s.pendingLanes&~(s.suspendedLanes&~s.pingedLanes)&t)===0}function Et(s,t){switch(s){case 1:case 2:case 4:case 8:case 64:return t+250;case 16:case 32:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return t+5e3;case 4194304:case 8388608:case 16777216:case 33554432:return-1;case 67108864:case 134217728:case 268435456:case 536870912:case 1073741824:return-1;default:return-1}}function I(){var s=W;return W<<=1,(W&62914560)===0&&(W=4194304),s}function ge(s){for(var t=[],a=0;31>a;a++)t.push(s);return t}function ke(s,t){s.pendingLanes|=t,t!==268435456&&(s.suspendedLanes=0,s.pingedLanes=0,s.warmLanes=0)}function Us(s,t,a,n,c,d){var p=s.pendingLanes;s.pendingLanes=a,s.suspendedLanes=0,s.pingedLanes=0,s.warmLanes=0,s.expiredLanes&=a,s.entangledLanes&=a,s.errorRecoveryDisabledLanes&=a,s.shellSuspendCounter=0;var N=s.entanglements,M=s.expirationTimes,K=s.hiddenUpdates;for(a=p&~a;0"u")return null;try{return s.activeElement||s.body}catch{return s.body}}var mv=/[\n"\\]/g;function fa(s){return s.replace(mv,function(t){return"\\"+t.charCodeAt(0).toString(16)+" "})}function To(s,t,a,n,c,d,p,N){s.name="",p!=null&&typeof p!="function"&&typeof p!="symbol"&&typeof p!="boolean"?s.type=p:s.removeAttribute("type"),t!=null?p==="number"?(t===0&&s.value===""||s.value!=t)&&(s.value=""+ha(t)):s.value!==""+ha(t)&&(s.value=""+ha(t)):p!=="submit"&&p!=="reset"||s.removeAttribute("value"),t!=null?Eo(s,p,ha(t)):a!=null?Eo(s,p,ha(a)):n!=null&&s.removeAttribute("value"),c==null&&d!=null&&(s.defaultChecked=!!d),c!=null&&(s.checked=c&&typeof c!="function"&&typeof c!="symbol"),N!=null&&typeof N!="function"&&typeof N!="symbol"&&typeof N!="boolean"?s.name=""+ha(N):s.removeAttribute("name")}function Em(s,t,a,n,c,d,p,N){if(d!=null&&typeof d!="function"&&typeof d!="symbol"&&typeof d!="boolean"&&(s.type=d),t!=null||a!=null){if(!(d!=="submit"&&d!=="reset"||t!=null)){ko(s);return}a=a!=null?""+ha(a):"",t=t!=null?""+ha(t):a,N||t===s.value||(s.value=t),s.defaultValue=t}n=n??c,n=typeof n!="function"&&typeof n!="symbol"&&!!n,s.checked=N?s.checked:!!n,s.defaultChecked=!!n,p!=null&&typeof p!="function"&&typeof p!="symbol"&&typeof p!="boolean"&&(s.name=p),ko(s)}function Eo(s,t,a){t==="number"&&Hr(s.ownerDocument)===s||s.defaultValue===""+a||(s.defaultValue=""+a)}function Tn(s,t,a,n){if(s=s.options,t){t={};for(var c=0;c"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),Do=!1;if(Pa)try{var Si={};Object.defineProperty(Si,"passive",{get:function(){Do=!0}}),window.addEventListener("test",Si,Si),window.removeEventListener("test",Si,Si)}catch{Do=!1}var vl=null,Ro=null,qr=null;function Lm(){if(qr)return qr;var s,t=Ro,a=t.length,n,c="value"in vl?vl.value:vl.textContent,d=c.length;for(s=0;s=Ti),Gm=" ",Vm=!1;function Fm(s,t){switch(s){case"keyup":return $v.indexOf(t.keyCode)!==-1;case"keydown":return t.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function Im(s){return s=s.detail,typeof s=="object"&&"data"in s?s.data:null}var An=!1;function Gv(s,t){switch(s){case"compositionend":return Im(t);case"keypress":return t.which!==32?null:(Vm=!0,Gm);case"textInput":return s=t.data,s===Gm&&Vm?null:s;default:return null}}function Vv(s,t){if(An)return s==="compositionend"||!$o&&Fm(s,t)?(s=Lm(),qr=Ro=vl=null,An=!1,s):null;switch(s){case"paste":return null;case"keypress":if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1=t)return{node:a,offset:t-s};s=n}e:{for(;a;){if(a.nextSibling){a=a.nextSibling;break e}a=a.parentNode}a=void 0}a=Wm(a)}}function sx(s,t){return s&&t?s===t?!0:s&&s.nodeType===3?!1:t&&t.nodeType===3?sx(s,t.parentNode):"contains"in s?s.contains(t):s.compareDocumentPosition?!!(s.compareDocumentPosition(t)&16):!1:!1}function tx(s){s=s!=null&&s.ownerDocument!=null&&s.ownerDocument.defaultView!=null?s.ownerDocument.defaultView:window;for(var t=Hr(s.document);t instanceof s.HTMLIFrameElement;){try{var a=typeof t.contentWindow.location.href=="string"}catch{a=!1}if(a)s=t.contentWindow;else break;t=Hr(s.document)}return t}function Vo(s){var t=s&&s.nodeName&&s.nodeName.toLowerCase();return t&&(t==="input"&&(s.type==="text"||s.type==="search"||s.type==="tel"||s.type==="url"||s.type==="password")||t==="textarea"||s.contentEditable==="true")}var Jv=Pa&&"documentMode"in document&&11>=document.documentMode,On=null,Fo=null,Ai=null,Io=!1;function ax(s,t,a){var n=a.window===a?a.document:a.nodeType===9?a:a.ownerDocument;Io||On==null||On!==Hr(n)||(n=On,"selectionStart"in n&&Vo(n)?n={start:n.selectionStart,end:n.selectionEnd}:(n=(n.ownerDocument&&n.ownerDocument.defaultView||window).getSelection(),n={anchorNode:n.anchorNode,anchorOffset:n.anchorOffset,focusNode:n.focusNode,focusOffset:n.focusOffset}),Ai&&Mi(Ai,n)||(Ai=n,n=Dc(Fo,"onSelect"),0>=p,c-=p,Ba=1<<32-Xe(t)+c|a<ns?(_s=Oe,Oe=null):_s=Oe.sibling;var Ts=Z(q,Oe,Y[ns],me);if(Ts===null){Oe===null&&(Oe=_s);break}s&&Oe&&Ts.alternate===null&&t(q,Oe),R=d(Ts,R,ns),ks===null?Ge=Ts:ks.sibling=Ts,ks=Ts,Oe=_s}if(ns===Y.length)return a(q,Oe),Cs&&Za(q,ns),Ge;if(Oe===null){for(;nsns?(_s=Oe,Oe=null):_s=Oe.sibling;var ql=Z(q,Oe,Ts.value,me);if(ql===null){Oe===null&&(Oe=_s);break}s&&Oe&&ql.alternate===null&&t(q,Oe),R=d(ql,R,ns),ks===null?Ge=ql:ks.sibling=ql,ks=ql,Oe=_s}if(Ts.done)return a(q,Oe),Cs&&Za(q,ns),Ge;if(Oe===null){for(;!Ts.done;ns++,Ts=Y.next())Ts=he(q,Ts.value,me),Ts!==null&&(R=d(Ts,R,ns),ks===null?Ge=Ts:ks.sibling=Ts,ks=Ts);return Cs&&Za(q,ns),Ge}for(Oe=n(Oe);!Ts.done;ns++,Ts=Y.next())Ts=ae(Oe,q,ns,Ts.value,me),Ts!==null&&(s&&Ts.alternate!==null&&Oe.delete(Ts.key===null?ns:Ts.key),R=d(Ts,R,ns),ks===null?Ge=Ts:ks.sibling=Ts,ks=Ts);return s&&Oe.forEach(function(gN){return t(q,gN)}),Cs&&Za(q,ns),Ge}function $s(q,R,Y,me){if(typeof Y=="object"&&Y!==null&&Y.type===O&&Y.key===null&&(Y=Y.props.children),typeof Y=="object"&&Y!==null){switch(Y.$$typeof){case S:e:{for(var Ge=Y.key;R!==null;){if(R.key===Ge){if(Ge=Y.type,Ge===O){if(R.tag===7){a(q,R.sibling),me=c(R,Y.props.children),me.return=q,q=me;break e}}else if(R.elementType===Ge||typeof Ge=="object"&&Ge!==null&&Ge.$$typeof===se&&nn(Ge)===R.type){a(q,R.sibling),me=c(R,Y.props),Bi(me,Y),me.return=q,q=me;break e}a(q,R);break}else t(q,R);R=R.sibling}Y.type===O?(me=en(Y.props.children,q.mode,me,Y.key),me.return=q,q=me):(me=Jr(Y.type,Y.key,Y.props,null,q.mode,me),Bi(me,Y),me.return=q,q=me)}return p(q);case w:e:{for(Ge=Y.key;R!==null;){if(R.key===Ge)if(R.tag===4&&R.stateNode.containerInfo===Y.containerInfo&&R.stateNode.implementation===Y.implementation){a(q,R.sibling),me=c(R,Y.children||[]),me.return=q,q=me;break e}else{a(q,R);break}else t(q,R);R=R.sibling}me=Zo(Y,q.mode,me),me.return=q,q=me}return p(q);case se:return Y=nn(Y),$s(q,R,Y,me)}if(be(Y))return Ae(q,R,Y,me);if(Se(Y)){if(Ge=Se(Y),typeof Ge!="function")throw Error(o(150));return Y=Ge.call(Y),Ke(q,R,Y,me)}if(typeof Y.then=="function")return $s(q,R,lc(Y),me);if(Y.$$typeof===z)return $s(q,R,ec(q,Y),me);nc(q,Y)}return typeof Y=="string"&&Y!==""||typeof Y=="number"||typeof Y=="bigint"?(Y=""+Y,R!==null&&R.tag===6?(a(q,R.sibling),me=c(R,Y),me.return=q,q=me):(a(q,R),me=Jo(Y,q.mode,me),me.return=q,q=me),p(q)):a(q,R)}return function(q,R,Y,me){try{Ui=0;var Ge=$s(q,R,Y,me);return Fn=null,Ge}catch(Oe){if(Oe===Vn||Oe===tc)throw Oe;var ks=ia(29,Oe,null,q.mode);return ks.lanes=me,ks.return=q,ks}finally{}}}var cn=Cx(!0),kx=Cx(!1),_l=!1;function dd(s){s.updateQueue={baseState:s.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,lanes:0,hiddenCallbacks:null},callbacks:null}}function ud(s,t){s=s.updateQueue,t.updateQueue===s&&(t.updateQueue={baseState:s.baseState,firstBaseUpdate:s.firstBaseUpdate,lastBaseUpdate:s.lastBaseUpdate,shared:s.shared,callbacks:null})}function Sl(s){return{lane:s,tag:0,payload:null,callback:null,next:null}}function Cl(s,t,a){var n=s.updateQueue;if(n===null)return null;if(n=n.shared,(zs&2)!==0){var c=n.pending;return c===null?t.next=t:(t.next=c.next,c.next=t),n.pending=t,t=Pr(s),dx(s,null,a),t}return Xr(s,n,t,a),Pr(s)}function Hi(s,t,a){if(t=t.updateQueue,t!==null&&(t=t.shared,(a&4194048)!==0)){var n=t.lanes;n&=s.pendingLanes,a|=n,t.lanes=a,Ft(s,a)}}function md(s,t){var a=s.updateQueue,n=s.alternate;if(n!==null&&(n=n.updateQueue,a===n)){var c=null,d=null;if(a=a.firstBaseUpdate,a!==null){do{var p={lane:a.lane,tag:a.tag,payload:a.payload,callback:null,next:null};d===null?c=d=p:d=d.next=p,a=a.next}while(a!==null);d===null?c=d=t:d=d.next=t}else c=d=t;a={baseState:n.baseState,firstBaseUpdate:c,lastBaseUpdate:d,shared:n.shared,callbacks:n.callbacks},s.updateQueue=a;return}s=a.lastBaseUpdate,s===null?a.firstBaseUpdate=t:s.next=t,a.lastBaseUpdate=t}var xd=!1;function $i(){if(xd){var s=Gn;if(s!==null)throw s}}function qi(s,t,a,n){xd=!1;var c=s.updateQueue;_l=!1;var d=c.firstBaseUpdate,p=c.lastBaseUpdate,N=c.shared.pending;if(N!==null){c.shared.pending=null;var M=N,K=M.next;M.next=null,p===null?d=K:p.next=K,p=M;var ce=s.alternate;ce!==null&&(ce=ce.updateQueue,N=ce.lastBaseUpdate,N!==p&&(N===null?ce.firstBaseUpdate=K:N.next=K,ce.lastBaseUpdate=M))}if(d!==null){var he=c.baseState;p=0,ce=K=M=null,N=d;do{var Z=N.lane&-536870913,ae=Z!==N.lane;if(ae?(ws&Z)===Z:(n&Z)===Z){Z!==0&&Z===qn&&(xd=!0),ce!==null&&(ce=ce.next={lane:0,tag:N.tag,payload:N.payload,callback:null,next:null});e:{var Ae=s,Ke=N;Z=t;var $s=a;switch(Ke.tag){case 1:if(Ae=Ke.payload,typeof Ae=="function"){he=Ae.call($s,he,Z);break e}he=Ae;break e;case 3:Ae.flags=Ae.flags&-65537|128;case 0:if(Ae=Ke.payload,Z=typeof Ae=="function"?Ae.call($s,he,Z):Ae,Z==null)break e;he=y({},he,Z);break e;case 2:_l=!0}}Z=N.callback,Z!==null&&(s.flags|=64,ae&&(s.flags|=8192),ae=c.callbacks,ae===null?c.callbacks=[Z]:ae.push(Z))}else ae={lane:Z,tag:N.tag,payload:N.payload,callback:N.callback,next:null},ce===null?(K=ce=ae,M=he):ce=ce.next=ae,p|=Z;if(N=N.next,N===null){if(N=c.shared.pending,N===null)break;ae=N,N=ae.next,ae.next=null,c.lastBaseUpdate=ae,c.shared.pending=null}}while(!0);ce===null&&(M=he),c.baseState=M,c.firstBaseUpdate=K,c.lastBaseUpdate=ce,d===null&&(c.shared.lanes=0),Ml|=p,s.lanes=p,s.memoizedState=he}}function Tx(s,t){if(typeof s!="function")throw Error(o(191,s));s.call(t)}function Ex(s,t){var a=s.callbacks;if(a!==null)for(s.callbacks=null,s=0;sd?d:8;var p=U.T,N={};U.T=N,Ad(s,!1,t,a);try{var M=c(),K=U.S;if(K!==null&&K(N,M),M!==null&&typeof M=="object"&&typeof M.then=="function"){var ce=ib(M,n);Fi(s,t,ce,ua(s))}else Fi(s,t,n,ua(s))}catch(he){Fi(s,t,{then:function(){},status:"rejected",reason:he},ua())}finally{P.p=d,p!==null&&N.types!==null&&(p.types=N.types),U.T=p}}function mb(){}function zd(s,t,a,n){if(s.tag!==5)throw Error(o(476));var c=rh(s).queue;ih(s,c,t,X,a===null?mb:function(){return ch(s),a(n)})}function rh(s){var t=s.memoizedState;if(t!==null)return t;t={memoizedState:X,baseState:X,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:tl,lastRenderedState:X},next:null};var a={};return t.next={memoizedState:a,baseState:a,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:tl,lastRenderedState:a},next:null},s.memoizedState=t,s=s.alternate,s!==null&&(s.memoizedState=t),t}function ch(s){var t=rh(s);t.next===null&&(t=s.alternate.memoizedState),Fi(s,t.next.queue,{},ua())}function Md(){return Lt(rr)}function oh(){return pt().memoizedState}function dh(){return pt().memoizedState}function xb(s){for(var t=s.return;t!==null;){switch(t.tag){case 24:case 3:var a=ua();s=Sl(a);var n=Cl(t,s,a);n!==null&&(Zt(n,t,a),Hi(n,t,a)),t={cache:id()},s.payload=t;return}t=t.return}}function hb(s,t,a){var n=ua();a={lane:n,revertLane:0,gesture:null,action:a,hasEagerState:!1,eagerState:null,next:null},fc(s)?mh(t,a):(a=Xo(s,t,a,n),a!==null&&(Zt(a,s,n),xh(a,t,n)))}function uh(s,t,a){var n=ua();Fi(s,t,a,n)}function Fi(s,t,a,n){var c={lane:n,revertLane:0,gesture:null,action:a,hasEagerState:!1,eagerState:null,next:null};if(fc(s))mh(t,c);else{var d=s.alternate;if(s.lanes===0&&(d===null||d.lanes===0)&&(d=t.lastRenderedReducer,d!==null))try{var p=t.lastRenderedState,N=d(p,a);if(c.hasEagerState=!0,c.eagerState=N,na(N,p))return Xr(s,t,c,0),Fs===null&&Kr(),!1}catch{}finally{}if(a=Xo(s,t,c,n),a!==null)return Zt(a,s,n),xh(a,t,n),!0}return!1}function Ad(s,t,a,n){if(n={lane:2,revertLane:du(),gesture:null,action:n,hasEagerState:!1,eagerState:null,next:null},fc(s)){if(t)throw Error(o(479))}else t=Xo(s,a,n,2),t!==null&&Zt(t,s,2)}function fc(s){var t=s.alternate;return s===as||t!==null&&t===as}function mh(s,t){Qn=cc=!0;var a=s.pending;a===null?t.next=t:(t.next=a.next,a.next=t),s.pending=t}function xh(s,t,a){if((a&4194048)!==0){var n=t.lanes;n&=s.pendingLanes,a|=n,t.lanes=a,Ft(s,a)}}var Ii={readContext:Lt,use:uc,useCallback:rt,useContext:rt,useEffect:rt,useImperativeHandle:rt,useLayoutEffect:rt,useInsertionEffect:rt,useMemo:rt,useReducer:rt,useRef:rt,useState:rt,useDebugValue:rt,useDeferredValue:rt,useTransition:rt,useSyncExternalStore:rt,useId:rt,useHostTransitionStatus:rt,useFormState:rt,useActionState:rt,useOptimistic:rt,useMemoCache:rt,useCacheRefresh:rt};Ii.useEffectEvent=rt;var hh={readContext:Lt,use:uc,useCallback:function(s,t){return qt().memoizedState=[s,t===void 0?null:t],s},useContext:Lt,useEffect:Jx,useImperativeHandle:function(s,t,a){a=a!=null?a.concat([s]):null,xc(4194308,4,sh.bind(null,t,s),a)},useLayoutEffect:function(s,t){return xc(4194308,4,s,t)},useInsertionEffect:function(s,t){xc(4,2,s,t)},useMemo:function(s,t){var a=qt();t=t===void 0?null:t;var n=s();if(on){Pe(!0);try{s()}finally{Pe(!1)}}return a.memoizedState=[n,t],n},useReducer:function(s,t,a){var n=qt();if(a!==void 0){var c=a(t);if(on){Pe(!0);try{a(t)}finally{Pe(!1)}}}else c=t;return n.memoizedState=n.baseState=c,s={pending:null,lanes:0,dispatch:null,lastRenderedReducer:s,lastRenderedState:c},n.queue=s,s=s.dispatch=hb.bind(null,as,s),[n.memoizedState,s]},useRef:function(s){var t=qt();return s={current:s},t.memoizedState=s},useState:function(s){s=Sd(s);var t=s.queue,a=uh.bind(null,as,t);return t.dispatch=a,[s.memoizedState,a]},useDebugValue:Td,useDeferredValue:function(s,t){var a=qt();return Ed(a,s,t)},useTransition:function(){var s=Sd(!1);return s=ih.bind(null,as,s.queue,!0,!1),qt().memoizedState=s,[!1,s]},useSyncExternalStore:function(s,t,a){var n=as,c=qt();if(Cs){if(a===void 0)throw Error(o(407));a=a()}else{if(a=t(),Fs===null)throw Error(o(349));(ws&127)!==0||Rx(n,t,a)}c.memoizedState=a;var d={value:a,getSnapshot:t};return c.queue=d,Jx(Ux.bind(null,n,d,s),[s]),n.flags|=2048,Kn(9,{destroy:void 0},Lx.bind(null,n,d,a,t),null),a},useId:function(){var s=qt(),t=Fs.identifierPrefix;if(Cs){var a=Ha,n=Ba;a=(n&~(1<<32-Xe(n)-1)).toString(32)+a,t="_"+t+"R_"+a,a=oc++,0<\/script>",d=d.removeChild(d.firstChild);break;case"select":d=typeof n.is=="string"?p.createElement("select",{is:n.is}):p.createElement("select"),n.multiple?d.multiple=!0:n.size&&(d.size=n.size);break;default:d=typeof n.is=="string"?p.createElement(c,{is:n.is}):p.createElement(c)}}d[Dt]=t,d[Qt]=n;e:for(p=t.child;p!==null;){if(p.tag===5||p.tag===6)d.appendChild(p.stateNode);else if(p.tag!==4&&p.tag!==27&&p.child!==null){p.child.return=p,p=p.child;continue}if(p===t)break e;for(;p.sibling===null;){if(p.return===null||p.return===t)break e;p=p.return}p.sibling.return=p.return,p=p.sibling}t.stateNode=d;e:switch(Bt(d,c,n),c){case"button":case"input":case"select":case"textarea":n=!!n.autoFocus;break e;case"img":n=!0;break e;default:n=!1}n&&ll(t)}}return Js(t),Qd(t,t.type,s===null?null:s.memoizedProps,t.pendingProps,a),null;case 6:if(s&&t.stateNode!=null)s.memoizedProps!==n&&ll(t);else{if(typeof n!="string"&&t.stateNode===null)throw Error(o(166));if(s=Q.current,Hn(t)){if(s=t.stateNode,a=t.memoizedProps,n=null,c=Rt,c!==null)switch(c.tag){case 27:case 5:n=c.memoizedProps}s[Dt]=t,s=!!(s.nodeValue===a||n!==null&&n.suppressHydrationWarning===!0||Df(s.nodeValue,a)),s||yl(t,!0)}else s=Rc(s).createTextNode(n),s[Dt]=t,t.stateNode=s}return Js(t),null;case 31:if(a=t.memoizedState,s===null||s.memoizedState!==null){if(n=Hn(t),a!==null){if(s===null){if(!n)throw Error(o(318));if(s=t.memoizedState,s=s!==null?s.dehydrated:null,!s)throw Error(o(557));s[Dt]=t}else sn(),(t.flags&128)===0&&(t.memoizedState=null),t.flags|=4;Js(t),s=!1}else a=td(),s!==null&&s.memoizedState!==null&&(s.memoizedState.hydrationErrors=a),s=!0;if(!s)return t.flags&256?(ca(t),t):(ca(t),null);if((t.flags&128)!==0)throw Error(o(558))}return Js(t),null;case 13:if(n=t.memoizedState,s===null||s.memoizedState!==null&&s.memoizedState.dehydrated!==null){if(c=Hn(t),n!==null&&n.dehydrated!==null){if(s===null){if(!c)throw Error(o(318));if(c=t.memoizedState,c=c!==null?c.dehydrated:null,!c)throw Error(o(317));c[Dt]=t}else sn(),(t.flags&128)===0&&(t.memoizedState=null),t.flags|=4;Js(t),c=!1}else c=td(),s!==null&&s.memoizedState!==null&&(s.memoizedState.hydrationErrors=c),c=!0;if(!c)return t.flags&256?(ca(t),t):(ca(t),null)}return ca(t),(t.flags&128)!==0?(t.lanes=a,t):(a=n!==null,s=s!==null&&s.memoizedState!==null,a&&(n=t.child,c=null,n.alternate!==null&&n.alternate.memoizedState!==null&&n.alternate.memoizedState.cachePool!==null&&(c=n.alternate.memoizedState.cachePool.pool),d=null,n.memoizedState!==null&&n.memoizedState.cachePool!==null&&(d=n.memoizedState.cachePool.pool),d!==c&&(n.flags|=2048)),a!==s&&a&&(t.child.flags|=8192),bc(t,t.updateQueue),Js(t),null);case 4:return J(),s===null&&hu(t.stateNode.containerInfo),Js(t),null;case 10:return el(t.type),Js(t),null;case 19:if(Ne(ft),n=t.memoizedState,n===null)return Js(t),null;if(c=(t.flags&128)!==0,d=n.rendering,d===null)if(c)Yi(n,!1);else{if(ct!==0||s!==null&&(s.flags&128)!==0)for(s=t.child;s!==null;){if(d=rc(s),d!==null){for(t.flags|=128,Yi(n,!1),s=d.updateQueue,t.updateQueue=s,bc(t,s),t.subtreeFlags=0,s=a,a=t.child;a!==null;)ux(a,s),a=a.sibling;return Ce(ft,ft.current&1|2),Cs&&Za(t,n.treeForkCount),t.child}s=s.sibling}n.tail!==null&&nt()>Sc&&(t.flags|=128,c=!0,Yi(n,!1),t.lanes=4194304)}else{if(!c)if(s=rc(d),s!==null){if(t.flags|=128,c=!0,s=s.updateQueue,t.updateQueue=s,bc(t,s),Yi(n,!0),n.tail===null&&n.tailMode==="hidden"&&!d.alternate&&!Cs)return Js(t),null}else 2*nt()-n.renderingStartTime>Sc&&a!==536870912&&(t.flags|=128,c=!0,Yi(n,!1),t.lanes=4194304);n.isBackwards?(d.sibling=t.child,t.child=d):(s=n.last,s!==null?s.sibling=d:t.child=d,n.last=d)}return n.tail!==null?(s=n.tail,n.rendering=s,n.tail=s.sibling,n.renderingStartTime=nt(),s.sibling=null,a=ft.current,Ce(ft,c?a&1|2:a&1),Cs&&Za(t,n.treeForkCount),s):(Js(t),null);case 22:case 23:return ca(t),fd(),n=t.memoizedState!==null,s!==null?s.memoizedState!==null!==n&&(t.flags|=8192):n&&(t.flags|=8192),n?(a&536870912)!==0&&(t.flags&128)===0&&(Js(t),t.subtreeFlags&6&&(t.flags|=8192)):Js(t),a=t.updateQueue,a!==null&&bc(t,a.retryQueue),a=null,s!==null&&s.memoizedState!==null&&s.memoizedState.cachePool!==null&&(a=s.memoizedState.cachePool.pool),n=null,t.memoizedState!==null&&t.memoizedState.cachePool!==null&&(n=t.memoizedState.cachePool.pool),n!==a&&(t.flags|=2048),s!==null&&Ne(ln),null;case 24:return a=null,s!==null&&(a=s.memoizedState.cache),t.memoizedState.cache!==a&&(t.flags|=2048),el(vt),Js(t),null;case 25:return null;case 30:return null}throw Error(o(156,t.tag))}function vb(s,t){switch(ed(t),t.tag){case 1:return s=t.flags,s&65536?(t.flags=s&-65537|128,t):null;case 3:return el(vt),J(),s=t.flags,(s&65536)!==0&&(s&128)===0?(t.flags=s&-65537|128,t):null;case 26:case 27:case 5:return qe(t),null;case 31:if(t.memoizedState!==null){if(ca(t),t.alternate===null)throw Error(o(340));sn()}return s=t.flags,s&65536?(t.flags=s&-65537|128,t):null;case 13:if(ca(t),s=t.memoizedState,s!==null&&s.dehydrated!==null){if(t.alternate===null)throw Error(o(340));sn()}return s=t.flags,s&65536?(t.flags=s&-65537|128,t):null;case 19:return Ne(ft),null;case 4:return J(),null;case 10:return el(t.type),null;case 22:case 23:return ca(t),fd(),s!==null&&Ne(ln),s=t.flags,s&65536?(t.flags=s&-65537|128,t):null;case 24:return el(vt),null;case 25:return null;default:return null}}function Bh(s,t){switch(ed(t),t.tag){case 3:el(vt),J();break;case 26:case 27:case 5:qe(t);break;case 4:J();break;case 31:t.memoizedState!==null&&ca(t);break;case 13:ca(t);break;case 19:Ne(ft);break;case 10:el(t.type);break;case 22:case 23:ca(t),fd(),s!==null&&Ne(ln);break;case 24:el(vt)}}function Ki(s,t){try{var a=t.updateQueue,n=a!==null?a.lastEffect:null;if(n!==null){var c=n.next;a=c;do{if((a.tag&s)===s){n=void 0;var d=a.create,p=a.inst;n=d(),p.destroy=n}a=a.next}while(a!==c)}}catch(N){Rs(t,t.return,N)}}function El(s,t,a){try{var n=t.updateQueue,c=n!==null?n.lastEffect:null;if(c!==null){var d=c.next;n=d;do{if((n.tag&s)===s){var p=n.inst,N=p.destroy;if(N!==void 0){p.destroy=void 0,c=t;var M=a,K=N;try{K()}catch(ce){Rs(c,M,ce)}}}n=n.next}while(n!==d)}}catch(ce){Rs(t,t.return,ce)}}function Hh(s){var t=s.updateQueue;if(t!==null){var a=s.stateNode;try{Ex(t,a)}catch(n){Rs(s,s.return,n)}}}function $h(s,t,a){a.props=dn(s.type,s.memoizedProps),a.state=s.memoizedState;try{a.componentWillUnmount()}catch(n){Rs(s,t,n)}}function Xi(s,t){try{var a=s.ref;if(a!==null){switch(s.tag){case 26:case 27:case 5:var n=s.stateNode;break;case 30:n=s.stateNode;break;default:n=s.stateNode}typeof a=="function"?s.refCleanup=a(n):a.current=n}}catch(c){Rs(s,t,c)}}function $a(s,t){var a=s.ref,n=s.refCleanup;if(a!==null)if(typeof n=="function")try{n()}catch(c){Rs(s,t,c)}finally{s.refCleanup=null,s=s.alternate,s!=null&&(s.refCleanup=null)}else if(typeof a=="function")try{a(null)}catch(c){Rs(s,t,c)}else a.current=null}function qh(s){var t=s.type,a=s.memoizedProps,n=s.stateNode;try{e:switch(t){case"button":case"input":case"select":case"textarea":a.autoFocus&&n.focus();break e;case"img":a.src?n.src=a.src:a.srcSet&&(n.srcset=a.srcSet)}}catch(c){Rs(s,s.return,c)}}function Yd(s,t,a){try{var n=s.stateNode;qb(n,s.type,a,t),n[Qt]=t}catch(c){Rs(s,s.return,c)}}function Gh(s){return s.tag===5||s.tag===3||s.tag===26||s.tag===27&&Ll(s.type)||s.tag===4}function Kd(s){e:for(;;){for(;s.sibling===null;){if(s.return===null||Gh(s.return))return null;s=s.return}for(s.sibling.return=s.return,s=s.sibling;s.tag!==5&&s.tag!==6&&s.tag!==18;){if(s.tag===27&&Ll(s.type)||s.flags&2||s.child===null||s.tag===4)continue e;s.child.return=s,s=s.child}if(!(s.flags&2))return s.stateNode}}function Xd(s,t,a){var n=s.tag;if(n===5||n===6)s=s.stateNode,t?(a.nodeType===9?a.body:a.nodeName==="HTML"?a.ownerDocument.body:a).insertBefore(s,t):(t=a.nodeType===9?a.body:a.nodeName==="HTML"?a.ownerDocument.body:a,t.appendChild(s),a=a._reactRootContainer,a!=null||t.onclick!==null||(t.onclick=Xa));else if(n!==4&&(n===27&&Ll(s.type)&&(a=s.stateNode,t=null),s=s.child,s!==null))for(Xd(s,t,a),s=s.sibling;s!==null;)Xd(s,t,a),s=s.sibling}function Nc(s,t,a){var n=s.tag;if(n===5||n===6)s=s.stateNode,t?a.insertBefore(s,t):a.appendChild(s);else if(n!==4&&(n===27&&Ll(s.type)&&(a=s.stateNode),s=s.child,s!==null))for(Nc(s,t,a),s=s.sibling;s!==null;)Nc(s,t,a),s=s.sibling}function Vh(s){var t=s.stateNode,a=s.memoizedProps;try{for(var n=s.type,c=t.attributes;c.length;)t.removeAttributeNode(c[0]);Bt(t,n,a),t[Dt]=s,t[Qt]=a}catch(d){Rs(s,s.return,d)}}var nl=!1,yt=!1,Pd=!1,Fh=typeof WeakSet=="function"?WeakSet:Set,Mt=null;function bb(s,t){if(s=s.containerInfo,gu=Gc,s=tx(s),Vo(s)){if("selectionStart"in s)var a={start:s.selectionStart,end:s.selectionEnd};else e:{a=(a=s.ownerDocument)&&a.defaultView||window;var n=a.getSelection&&a.getSelection();if(n&&n.rangeCount!==0){a=n.anchorNode;var c=n.anchorOffset,d=n.focusNode;n=n.focusOffset;try{a.nodeType,d.nodeType}catch{a=null;break e}var p=0,N=-1,M=-1,K=0,ce=0,he=s,Z=null;s:for(;;){for(var ae;he!==a||c!==0&&he.nodeType!==3||(N=p+c),he!==d||n!==0&&he.nodeType!==3||(M=p+n),he.nodeType===3&&(p+=he.nodeValue.length),(ae=he.firstChild)!==null;)Z=he,he=ae;for(;;){if(he===s)break s;if(Z===a&&++K===c&&(N=p),Z===d&&++ce===n&&(M=p),(ae=he.nextSibling)!==null)break;he=Z,Z=he.parentNode}he=ae}a=N===-1||M===-1?null:{start:N,end:M}}else a=null}a=a||{start:0,end:0}}else a=null;for(ju={focusedElem:s,selectionRange:a},Gc=!1,Mt=t;Mt!==null;)if(t=Mt,s=t.child,(t.subtreeFlags&1028)!==0&&s!==null)s.return=t,Mt=s;else for(;Mt!==null;){switch(t=Mt,d=t.alternate,s=t.flags,t.tag){case 0:if((s&4)!==0&&(s=t.updateQueue,s=s!==null?s.events:null,s!==null))for(a=0;a title"))),Bt(d,n,a),d[Dt]=s,zt(d),n=d;break e;case"link":var p=Jf("link","href",c).get(n+(a.href||""));if(p){for(var N=0;N$s&&(p=$s,$s=Ke,Ke=p);var q=ex(N,Ke),R=ex(N,$s);if(q&&R&&(ae.rangeCount!==1||ae.anchorNode!==q.node||ae.anchorOffset!==q.offset||ae.focusNode!==R.node||ae.focusOffset!==R.offset)){var Y=he.createRange();Y.setStart(q.node,q.offset),ae.removeAllRanges(),Ke>$s?(ae.addRange(Y),ae.extend(R.node,R.offset)):(Y.setEnd(R.node,R.offset),ae.addRange(Y))}}}}for(he=[],ae=N;ae=ae.parentNode;)ae.nodeType===1&&he.push({element:ae,left:ae.scrollLeft,top:ae.scrollTop});for(typeof N.focus=="function"&&N.focus(),N=0;Na?32:a,U.T=null,a=au,au=null;var d=Ol,p=dl;if(St=0,Wn=Ol=null,dl=0,(zs&6)!==0)throw Error(o(331));var N=zs;if(zs|=4,sf(d.current),Zh(d,d.current,p,a),zs=N,sr(0,!1),ts&&typeof ts.onPostCommitFiberRoot=="function")try{ts.onPostCommitFiberRoot(Ls,d)}catch{}return!0}finally{P.p=c,U.T=n,bf(s,t)}}function yf(s,t,a){t=ga(a,t),t=Ld(s.stateNode,t,2),s=Cl(s,t,2),s!==null&&(ke(s,2),qa(s))}function Rs(s,t,a){if(s.tag===3)yf(s,s,a);else for(;t!==null;){if(t.tag===3){yf(t,s,a);break}else if(t.tag===1){var n=t.stateNode;if(typeof t.type.getDerivedStateFromError=="function"||typeof n.componentDidCatch=="function"&&(Al===null||!Al.has(n))){s=ga(a,s),a=yh(2),n=Cl(t,a,2),n!==null&&(wh(a,n,t,s),ke(n,2),qa(n));break}}t=t.return}}function ru(s,t,a){var n=s.pingCache;if(n===null){n=s.pingCache=new wb;var c=new Set;n.set(t,c)}else c=n.get(t),c===void 0&&(c=new Set,n.set(t,c));c.has(a)||(Wd=!0,c.add(a),s=Tb.bind(null,s,t,a),t.then(s,s))}function Tb(s,t,a){var n=s.pingCache;n!==null&&n.delete(t),s.pingedLanes|=s.suspendedLanes&a,s.warmLanes&=~a,Fs===s&&(ws&a)===a&&(ct===4||ct===3&&(ws&62914560)===ws&&300>nt()-_c?(zs&2)===0&&ei(s,0):eu|=a,Zn===ws&&(Zn=0)),qa(s)}function wf(s,t){t===0&&(t=I()),s=Wl(s,t),s!==null&&(ke(s,t),qa(s))}function Eb(s){var t=s.memoizedState,a=0;t!==null&&(a=t.retryLane),wf(s,a)}function zb(s,t){var a=0;switch(s.tag){case 31:case 13:var n=s.stateNode,c=s.memoizedState;c!==null&&(a=c.retryLane);break;case 19:n=s.stateNode;break;case 22:n=s.stateNode._retryCache;break;default:throw Error(o(314))}n!==null&&n.delete(t),wf(s,a)}function Mb(s,t){return Ie(s,t)}var Mc=null,ti=null,cu=!1,Ac=!1,ou=!1,Rl=0;function qa(s){s!==ti&&s.next===null&&(ti===null?Mc=ti=s:ti=ti.next=s),Ac=!0,cu||(cu=!0,Ob())}function sr(s,t){if(!ou&&Ac){ou=!0;do for(var a=!1,n=Mc;n!==null;){if(s!==0){var c=n.pendingLanes;if(c===0)var d=0;else{var p=n.suspendedLanes,N=n.pingedLanes;d=(1<<31-Xe(42|s)+1)-1,d&=c&~(p&~N),d=d&201326741?d&201326741|1:d?d|2:0}d!==0&&(a=!0,kf(n,d))}else d=ws,d=ys(n,n===Fs?d:0,n.cancelPendingCommit!==null||n.timeoutHandle!==-1),(d&3)===0||Tt(n,d)||(a=!0,kf(n,d));n=n.next}while(a);ou=!1}}function Ab(){_f()}function _f(){Ac=cu=!1;var s=0;Rl!==0&&Vb()&&(s=Rl);for(var t=nt(),a=null,n=Mc;n!==null;){var c=n.next,d=Sf(n,t);d===0?(n.next=null,a===null?Mc=c:a.next=c,c===null&&(ti=a)):(a=n,(s!==0||(d&3)!==0)&&(Ac=!0)),n=c}St!==0&&St!==5||sr(s),Rl!==0&&(Rl=0)}function Sf(s,t){for(var a=s.suspendedLanes,n=s.pingedLanes,c=s.expirationTimes,d=s.pendingLanes&-62914561;0N)break;var ce=M.transferSize,he=M.initiatorType;ce&&Rf(he)&&(M=M.responseEnd,p+=ce*(M"u"?null:document;function Yf(s,t,a){var n=ai;if(n&&typeof t=="string"&&t){var c=fa(t);c='link[rel="'+s+'"][href="'+c+'"]',typeof a=="string"&&(c+='[crossorigin="'+a+'"]'),Qf.has(c)||(Qf.add(c),s={rel:s,crossOrigin:a,href:t},n.querySelector(c)===null&&(t=n.createElement("link"),Bt(t,"link",s),zt(t),n.head.appendChild(t)))}}function Zb(s){ul.D(s),Yf("dns-prefetch",s,null)}function Wb(s,t){ul.C(s,t),Yf("preconnect",s,t)}function eN(s,t,a){ul.L(s,t,a);var n=ai;if(n&&s&&t){var c='link[rel="preload"][as="'+fa(t)+'"]';t==="image"&&a&&a.imageSrcSet?(c+='[imagesrcset="'+fa(a.imageSrcSet)+'"]',typeof a.imageSizes=="string"&&(c+='[imagesizes="'+fa(a.imageSizes)+'"]')):c+='[href="'+fa(s)+'"]';var d=c;switch(t){case"style":d=li(s);break;case"script":d=ni(s)}wa.has(d)||(s=y({rel:"preload",href:t==="image"&&a&&a.imageSrcSet?void 0:s,as:t},a),wa.set(d,s),n.querySelector(c)!==null||t==="style"&&n.querySelector(nr(d))||t==="script"&&n.querySelector(ir(d))||(t=n.createElement("link"),Bt(t,"link",s),zt(t),n.head.appendChild(t)))}}function sN(s,t){ul.m(s,t);var a=ai;if(a&&s){var n=t&&typeof t.as=="string"?t.as:"script",c='link[rel="modulepreload"][as="'+fa(n)+'"][href="'+fa(s)+'"]',d=c;switch(n){case"audioworklet":case"paintworklet":case"serviceworker":case"sharedworker":case"worker":case"script":d=ni(s)}if(!wa.has(d)&&(s=y({rel:"modulepreload",href:s},t),wa.set(d,s),a.querySelector(c)===null)){switch(n){case"audioworklet":case"paintworklet":case"serviceworker":case"sharedworker":case"worker":case"script":if(a.querySelector(ir(d)))return}n=a.createElement("link"),Bt(n,"link",s),zt(n),a.head.appendChild(n)}}}function tN(s,t,a){ul.S(s,t,a);var n=ai;if(n&&s){var c=Cn(n).hoistableStyles,d=li(s);t=t||"default";var p=c.get(d);if(!p){var N={loading:0,preload:null};if(p=n.querySelector(nr(d)))N.loading=5;else{s=y({rel:"stylesheet",href:s,"data-precedence":t},a),(a=wa.get(d))&&Su(s,a);var M=p=n.createElement("link");zt(M),Bt(M,"link",s),M._p=new Promise(function(K,ce){M.onload=K,M.onerror=ce}),M.addEventListener("load",function(){N.loading|=1}),M.addEventListener("error",function(){N.loading|=2}),N.loading|=4,Uc(p,t,n)}p={type:"stylesheet",instance:p,count:1,state:N},c.set(d,p)}}}function aN(s,t){ul.X(s,t);var a=ai;if(a&&s){var n=Cn(a).hoistableScripts,c=ni(s),d=n.get(c);d||(d=a.querySelector(ir(c)),d||(s=y({src:s,async:!0},t),(t=wa.get(c))&&Cu(s,t),d=a.createElement("script"),zt(d),Bt(d,"link",s),a.head.appendChild(d)),d={type:"script",instance:d,count:1,state:null},n.set(c,d))}}function lN(s,t){ul.M(s,t);var a=ai;if(a&&s){var n=Cn(a).hoistableScripts,c=ni(s),d=n.get(c);d||(d=a.querySelector(ir(c)),d||(s=y({src:s,async:!0,type:"module"},t),(t=wa.get(c))&&Cu(s,t),d=a.createElement("script"),zt(d),Bt(d,"link",s),a.head.appendChild(d)),d={type:"script",instance:d,count:1,state:null},n.set(c,d))}}function Kf(s,t,a,n){var c=(c=Q.current)?Lc(c):null;if(!c)throw Error(o(446));switch(s){case"meta":case"title":return null;case"style":return typeof a.precedence=="string"&&typeof a.href=="string"?(t=li(a.href),a=Cn(c).hoistableStyles,n=a.get(t),n||(n={type:"style",instance:null,count:0,state:null},a.set(t,n)),n):{type:"void",instance:null,count:0,state:null};case"link":if(a.rel==="stylesheet"&&typeof a.href=="string"&&typeof a.precedence=="string"){s=li(a.href);var d=Cn(c).hoistableStyles,p=d.get(s);if(p||(c=c.ownerDocument||c,p={type:"stylesheet",instance:null,count:0,state:{loading:0,preload:null}},d.set(s,p),(d=c.querySelector(nr(s)))&&!d._p&&(p.instance=d,p.state.loading=5),wa.has(s)||(a={rel:"preload",as:"style",href:a.href,crossOrigin:a.crossOrigin,integrity:a.integrity,media:a.media,hrefLang:a.hrefLang,referrerPolicy:a.referrerPolicy},wa.set(s,a),d||nN(c,s,a,p.state))),t&&n===null)throw Error(o(528,""));return p}if(t&&n!==null)throw Error(o(529,""));return null;case"script":return t=a.async,a=a.src,typeof a=="string"&&t&&typeof t!="function"&&typeof t!="symbol"?(t=ni(a),a=Cn(c).hoistableScripts,n=a.get(t),n||(n={type:"script",instance:null,count:0,state:null},a.set(t,n)),n):{type:"void",instance:null,count:0,state:null};default:throw Error(o(444,s))}}function li(s){return'href="'+fa(s)+'"'}function nr(s){return'link[rel="stylesheet"]['+s+"]"}function Xf(s){return y({},s,{"data-precedence":s.precedence,precedence:null})}function nN(s,t,a,n){s.querySelector('link[rel="preload"][as="style"]['+t+"]")?n.loading=1:(t=s.createElement("link"),n.preload=t,t.addEventListener("load",function(){return n.loading|=1}),t.addEventListener("error",function(){return n.loading|=2}),Bt(t,"link",a),zt(t),s.head.appendChild(t))}function ni(s){return'[src="'+fa(s)+'"]'}function ir(s){return"script[async]"+s}function Pf(s,t,a){if(t.count++,t.instance===null)switch(t.type){case"style":var n=s.querySelector('style[data-href~="'+fa(a.href)+'"]');if(n)return t.instance=n,zt(n),n;var c=y({},a,{"data-href":a.href,"data-precedence":a.precedence,href:null,precedence:null});return n=(s.ownerDocument||s).createElement("style"),zt(n),Bt(n,"style",c),Uc(n,a.precedence,s),t.instance=n;case"stylesheet":c=li(a.href);var d=s.querySelector(nr(c));if(d)return t.state.loading|=4,t.instance=d,zt(d),d;n=Xf(a),(c=wa.get(c))&&Su(n,c),d=(s.ownerDocument||s).createElement("link"),zt(d);var p=d;return p._p=new Promise(function(N,M){p.onload=N,p.onerror=M}),Bt(d,"link",n),t.state.loading|=4,Uc(d,a.precedence,s),t.instance=d;case"script":return d=ni(a.src),(c=s.querySelector(ir(d)))?(t.instance=c,zt(c),c):(n=a,(c=wa.get(d))&&(n=y({},a),Cu(n,c)),s=s.ownerDocument||s,c=s.createElement("script"),zt(c),Bt(c,"link",n),s.head.appendChild(c),t.instance=c);case"void":return null;default:throw Error(o(443,t.type))}else t.type==="stylesheet"&&(t.state.loading&4)===0&&(n=t.instance,t.state.loading|=4,Uc(n,a.precedence,s));return t.instance}function Uc(s,t,a){for(var n=a.querySelectorAll('link[rel="stylesheet"][data-precedence],style[data-precedence]'),c=n.length?n[n.length-1]:null,d=c,p=0;p title"):null)}function iN(s,t,a){if(a===1||t.itemProp!=null)return!1;switch(s){case"meta":case"title":return!0;case"style":if(typeof t.precedence!="string"||typeof t.href!="string"||t.href==="")break;return!0;case"link":if(typeof t.rel!="string"||typeof t.href!="string"||t.href===""||t.onLoad||t.onError)break;switch(t.rel){case"stylesheet":return s=t.disabled,typeof t.precedence=="string"&&s==null;default:return!0}case"script":if(t.async&&typeof t.async!="function"&&typeof t.async!="symbol"&&!t.onLoad&&!t.onError&&t.src&&typeof t.src=="string")return!0}return!1}function Wf(s){return!(s.type==="stylesheet"&&(s.state.loading&3)===0)}function rN(s,t,a,n){if(a.type==="stylesheet"&&(typeof n.media!="string"||matchMedia(n.media).matches!==!1)&&(a.state.loading&4)===0){if(a.instance===null){var c=li(n.href),d=t.querySelector(nr(c));if(d){t=d._p,t!==null&&typeof t=="object"&&typeof t.then=="function"&&(s.count++,s=Hc.bind(s),t.then(s,s)),a.state.loading|=4,a.instance=d,zt(d);return}d=t.ownerDocument||t,n=Xf(n),(c=wa.get(c))&&Su(n,c),d=d.createElement("link"),zt(d);var p=d;p._p=new Promise(function(N,M){p.onload=N,p.onerror=M}),Bt(d,"link",n),a.instance=d}s.stylesheets===null&&(s.stylesheets=new Map),s.stylesheets.set(a,t),(t=a.state.preload)&&(a.state.loading&3)===0&&(s.count++,a=Hc.bind(s),t.addEventListener("load",a),t.addEventListener("error",a))}}var ku=0;function cN(s,t){return s.stylesheets&&s.count===0&&qc(s,s.stylesheets),0ku?50:800)+t);return s.unsuspend=a,function(){s.unsuspend=null,clearTimeout(n),clearTimeout(c)}}:null}function Hc(){if(this.count--,this.count===0&&(this.imgCount===0||!this.waitingForImages)){if(this.stylesheets)qc(this,this.stylesheets);else if(this.unsuspend){var s=this.unsuspend;this.unsuspend=null,s()}}}var $c=null;function qc(s,t){s.stylesheets=null,s.unsuspend!==null&&(s.count++,$c=new Map,t.forEach(oN,s),$c=null,Hc.call(s))}function oN(s,t){if(!(t.state.loading&4)){var a=$c.get(s);if(a)var n=a.get(null);else{a=new Map,$c.set(s,a);for(var c=s.querySelectorAll("link[data-precedence],style[data-precedence]"),d=0;d"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(l)}catch(i){console.error(i)}}return l(),Bu.exports=D0(),Bu.exports}var L0=R0();function H(...l){return TN(EN(l))}const Ve=m.forwardRef(({className:l,...i},r)=>e.jsx("div",{ref:r,className:H("rounded-xl border bg-card text-card-foreground shadow",l),...i}));Ve.displayName="Card";const rs=m.forwardRef(({className:l,...i},r)=>e.jsx("div",{ref:r,className:H("flex flex-col space-y-1.5 p-6",l),...i}));rs.displayName="CardHeader";const cs=m.forwardRef(({className:l,...i},r)=>e.jsx("div",{ref:r,className:H("font-semibold leading-none tracking-tight",l),...i}));cs.displayName="CardTitle";const st=m.forwardRef(({className:l,...i},r)=>e.jsx("div",{ref:r,className:H("text-sm text-muted-foreground",l),...i}));st.displayName="CardDescription";const gs=m.forwardRef(({className:l,...i},r)=>e.jsx("div",{ref:r,className:H("p-6 pt-0",l),...i}));gs.displayName="CardContent";const tj=m.forwardRef(({className:l,...i},r)=>e.jsx("div",{ref:r,className:H("flex items-center p-6 pt-0",l),...i}));tj.displayName="CardFooter";const Sa=MN,xa=m.forwardRef(({className:l,...i},r)=>e.jsx(Fp,{ref:r,className:H("inline-flex h-9 items-center justify-center rounded-lg bg-muted p-1 text-muted-foreground",l),...i}));xa.displayName=Fp.displayName;const is=m.forwardRef(({className:l,...i},r)=>e.jsx(Ip,{ref:r,className:H("inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1 text-sm font-medium ring-offset-background transition-all duration-300 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow",l),...i}));is.displayName=Ip.displayName;const As=m.forwardRef(({className:l,...i},r)=>e.jsx(Qp,{ref:r,className:H("mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 data-[state=active]:animate-in data-[state=active]:fade-in data-[state=active]:duration-300",l),...i}));As.displayName=Qp.displayName;const Ze=m.forwardRef(({className:l,children:i,viewportRef:r,...o},u)=>e.jsxs(Yp,{ref:u,className:H("relative overflow-hidden",l),...o,children:[e.jsx(AN,{ref:r,className:"h-full w-full rounded-[inherit]",children:i}),e.jsx(sm,{}),e.jsx(sm,{orientation:"horizontal"}),e.jsx(ON,{})]}));Ze.displayName=Yp.displayName;const sm=m.forwardRef(({className:l,orientation:i="vertical",...r},o)=>e.jsx(Kp,{ref:o,orientation:i,className:H("flex touch-none select-none transition-colors",i==="vertical"&&"h-full w-2.5 border-l border-l-transparent p-[1px]",i==="horizontal"&&"h-2.5 flex-col border-t border-t-transparent p-[1px]",l),...r,children:e.jsx(DN,{className:"relative flex-1 rounded-full bg-border"})}));sm.displayName=Kp.displayName;function aj({className:l,...i}){return e.jsx("div",{className:H("animate-pulse rounded-md bg-primary/10",l),...i})}const gn=m.forwardRef(({className:l,value:i,...r},o)=>e.jsx(Xp,{ref:o,className:H("relative h-2 w-full overflow-hidden rounded-full bg-primary/20",l),...r,children:e.jsx(RN,{className:"h-full w-full flex-1 bg-primary transition-all",style:{transform:`translateX(-${100-(i||0)}%)`}})}));gn.displayName=Xp.displayName;async function we(l,i){const o=i?.body instanceof FormData?{...i?.headers}:{"Content-Type":"application/json",...i?.headers},u={...i,credentials:"include",headers:o},x=await fetch(l,u);if(x.status===401)throw window.location.href="/auth",new Error("认证失败,请重新登录");return x}function Is(){return{"Content-Type":"application/json"}}async function U0(){try{await fetch("/api/webui/auth/logout",{method:"POST",credentials:"include"})}catch(l){console.error("登出请求失败:",l)}window.location.href="/auth"}async function om(){try{return(await(await fetch("/api/webui/auth/check",{method:"GET",credentials:"include"})).json()).authenticated===!0}catch{return!1}}const B0={light:"",dark:".dark"},lj=m.createContext(null);function nj(){const l=m.useContext(lj);if(!l)throw new Error("useChart must be used within a ");return l}const oi=m.forwardRef(({id:l,className:i,children:r,config:o,...u},x)=>{const h=m.useId(),f=`chart-${l||h.replace(/:/g,"")}`;return e.jsx(lj.Provider,{value:{config:o},children:e.jsxs("div",{"data-chart":f,ref:x,className:H("flex aspect-video justify-center text-xs [&_.recharts-cartesian-axis-tick_text]:fill-muted-foreground [&_.recharts-cartesian-grid_line[stroke='#ccc']]:stroke-border/50 [&_.recharts-curve.recharts-tooltip-cursor]:stroke-border [&_.recharts-dot[stroke='#fff']]:stroke-transparent [&_.recharts-layer]:outline-none [&_.recharts-polar-grid_[stroke='#ccc']]:stroke-border [&_.recharts-radial-bar-background-sector]:fill-muted [&_.recharts-rectangle.recharts-tooltip-cursor]:fill-muted [&_.recharts-reference-line_[stroke='#ccc']]:stroke-border [&_.recharts-sector[stroke='#fff']]:stroke-transparent [&_.recharts-sector]:outline-none [&_.recharts-surface]:outline-none",i),...u,children:[e.jsx(H0,{id:f,config:o}),e.jsx(JN,{children:r})]})})});oi.displayName="Chart";const H0=({id:l,config:i})=>{const r=Object.entries(i).filter(([,o])=>o.theme||o.color);return r.length?e.jsx("style",{dangerouslySetInnerHTML:{__html:Object.entries(B0).map(([o,u])=>` +${u} [data-chart=${l}] { +${r.map(([x,h])=>{const f=h.theme?.[o]||h.color;return f?` --color-${x}: ${f};`:null}).join(` +`)} +} +`).join(` +`)}}):null},xr=ZN,di=m.forwardRef(({active:l,payload:i,className:r,indicator:o="dot",hideLabel:u=!1,hideIndicator:x=!1,label:h,labelFormatter:f,labelClassName:g,formatter:j,color:v,nameKey:y,labelKey:b},S)=>{const{config:w}=nj(),O=m.useMemo(()=>{if(u||!i?.length)return null;const[D]=i,V=`${b||D?.dataKey||D?.name||"value"}`,z=tm(w,D,V),_=!b&&typeof h=="string"?w[h]?.label||h:z?.label;return f?e.jsx("div",{className:H("font-medium",g),children:f(_,i)}):_?e.jsx("div",{className:H("font-medium",g),children:_}):null},[h,f,i,u,g,w,b]);if(!l||!i?.length)return null;const A=i.length===1&&o!=="dot";return e.jsxs("div",{ref:S,className:H("grid min-w-[8rem] items-start gap-1.5 rounded-lg border border-border/50 bg-background px-2.5 py-1.5 text-xs shadow-xl",r),children:[A?null:O,e.jsx("div",{className:"grid gap-1.5",children:i.filter(D=>D.type!=="none").map((D,V)=>{const z=`${y||D.name||D.dataKey||"value"}`,_=tm(w,D,z),T=v||D.payload.fill||D.color;return e.jsx("div",{className:H("flex w-full flex-wrap items-stretch gap-2 [&>svg]:h-2.5 [&>svg]:w-2.5 [&>svg]:text-muted-foreground",o==="dot"&&"items-center"),children:j&&D?.value!==void 0&&D.name?j(D.value,D.name,D,V,D.payload):e.jsxs(e.Fragment,{children:[_?.icon?e.jsx(_.icon,{}):!x&&e.jsx("div",{className:H("shrink-0 rounded-[2px] border-[--color-border] bg-[--color-bg]",{"h-2.5 w-2.5":o==="dot","w-1":o==="line","w-0 border-[1.5px] border-dashed bg-transparent":o==="dashed","my-0.5":A&&o==="dashed"}),style:{"--color-bg":T,"--color-border":T}}),e.jsxs("div",{className:H("flex flex-1 justify-between leading-none",A?"items-end":"items-center"),children:[e.jsxs("div",{className:"grid gap-1.5",children:[A?O:null,e.jsx("span",{className:"text-muted-foreground",children:_?.label||D.name})]}),D.value&&e.jsx("span",{className:"font-mono font-medium tabular-nums text-foreground",children:D.value.toLocaleString()})]})]})},D.dataKey)})})]})});di.displayName="ChartTooltip";const $0=WN,ij=m.forwardRef(({className:l,hideIcon:i=!1,payload:r,verticalAlign:o="bottom",nameKey:u},x)=>{const{config:h}=nj();return r?.length?e.jsx("div",{ref:x,className:H("flex items-center justify-center gap-4",o==="top"?"pb-3":"pt-3",l),children:r.filter(f=>f.type!=="none").map(f=>{const g=`${u||f.dataKey||"value"}`,j=tm(h,f,g);return e.jsxs("div",{className:H("flex items-center gap-1.5 [&>svg]:h-3 [&>svg]:w-3 [&>svg]:text-muted-foreground"),children:[j?.icon&&!i?e.jsx(j.icon,{}):e.jsx("div",{className:"h-2 w-2 shrink-0 rounded-[2px]",style:{backgroundColor:f.color}}),j?.label]},f.value)})}):null});ij.displayName="ChartLegend";function tm(l,i,r){if(typeof i!="object"||i===null)return;const o="payload"in i&&typeof i.payload=="object"&&i.payload!==null?i.payload:void 0;let u=r;return r in i&&typeof i[r]=="string"?u=i[r]:o&&r in o&&typeof o[r]=="string"&&(u=o[r]),u in l?l[u]:l[r]}const Sr=gi("inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",{variants:{variant:{default:"bg-primary text-primary-foreground shadow hover:bg-primary/90",destructive:"bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",outline:"border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",secondary:"bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",ghost:"hover:bg-accent hover:text-accent-foreground",link:"text-primary underline-offset-4 hover:underline"},size:{default:"h-9 px-4 py-2",sm:"h-8 rounded-md px-3 text-xs",lg:"h-10 rounded-md px-8",icon:"h-9 w-9"}},defaultVariants:{variant:"default",size:"default"}}),C=m.forwardRef(({className:l,variant:i,size:r,asChild:o=!1,...u},x)=>{const h=o?ny:"button";return e.jsx(h,{className:H(Sr({variant:i,size:r,className:l})),ref:x,...u})});C.displayName="Button";const q0=gi("inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",{variants:{variant:{default:"border-transparent bg-primary text-primary-foreground shadow hover:bg-primary/80",secondary:"border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",destructive:"border-transparent bg-destructive text-destructive-foreground shadow hover:bg-destructive/80",outline:"text-foreground"}},defaultVariants:{variant:"default"}});function Ye({className:l,variant:i,...r}){return e.jsx("div",{className:H(q0({variant:i}),l),...r})}async function G0(){const l=await we("/api/webui/system/restart",{method:"POST",headers:Is()});if(!l.ok){const i=await l.json();throw new Error(i.detail||"重启失败")}return await l.json()}async function V0(){const l=await we("/api/webui/system/status",{method:"GET",headers:Is()});if(!l.ok){const i=await l.json();throw new Error(i.detail||"获取状态失败")}return await l.json()}const ri={INITIAL_DELAY:3e3,CHECK_INTERVAL:2e3,CHECK_TIMEOUT:3e3,MAX_ATTEMPTS:60,PROGRESS_INTERVAL:200,SUCCESS_REDIRECT_DELAY:1500},rj=m.createContext(null);function jn({children:l,onRestartComplete:i,onRestartFailed:r,healthCheckUrl:o="/api/webui/system/status",maxAttempts:u=ri.MAX_ATTEMPTS}){const[x,h]=m.useState({status:"idle",progress:0,elapsedTime:0,checkAttempts:0,maxAttempts:u}),[f,g]=m.useState({}),j=m.useCallback(()=>{f.progress&&clearInterval(f.progress),f.elapsed&&clearInterval(f.elapsed),f.check&&clearTimeout(f.check),g({})},[f]),v=m.useCallback(()=>{j(),h({status:"idle",progress:0,elapsedTime:0,checkAttempts:0,maxAttempts:u})},[j,u]),y=m.useCallback(async()=>{try{const A=new AbortController,D=setTimeout(()=>A.abort(),ri.CHECK_TIMEOUT),V=await fetch(o,{method:"GET",headers:{"Content-Type":"application/json"},credentials:"include",signal:A.signal});return clearTimeout(D),V.ok}catch{return!1}},[o]),b=m.useCallback(()=>{let A=0;const D=async()=>{if(A++,h(z=>({...z,status:"checking",checkAttempts:A})),await y())j(),h(z=>({...z,status:"success",progress:100})),setTimeout(()=>{i?.(),window.location.href="/auth"},ri.SUCCESS_REDIRECT_DELAY);else if(A>=u){j();const z=`健康检查超时 (${A}/${u})`;h(_=>({..._,status:"failed",error:z})),r?.(z)}else{const z=setTimeout(D,ri.CHECK_INTERVAL);g(_=>({..._,check:z}))}};D()},[y,j,u,i,r]),S=m.useCallback(()=>{h(A=>({...A,status:"checking",checkAttempts:0,error:void 0})),b()},[b]),w=m.useCallback(async A=>{const{delay:D=0,skipApiCall:V=!1}=A??{};if(x.status!=="idle"&&x.status!=="failed")return;if(j(),h({status:"requesting",progress:0,elapsedTime:0,checkAttempts:0,maxAttempts:u}),D>0&&await new Promise(T=>setTimeout(T,D)),V)h(T=>({...T,status:"restarting"}));else try{h(T=>({...T,status:"restarting"})),await Promise.race([G0(),new Promise(T=>setTimeout(T,5e3))])}catch{}const z=setInterval(()=>{h(T=>({...T,progress:T.progress>=90?T.progress:T.progress+1}))},ri.PROGRESS_INTERVAL),_=setInterval(()=>{h(T=>({...T,elapsedTime:T.elapsedTime+1}))},1e3);g({progress:z,elapsed:_}),setTimeout(()=>{b()},ri.INITIAL_DELAY)},[x.status,j,u,b]),O={state:x,isRestarting:x.status!=="idle",triggerRestart:w,resetState:v,retryHealthCheck:S};return e.jsx(rj.Provider,{value:O,children:l})}function Il(){const l=m.useContext(rj);if(!l)throw new Error("useRestart must be used within a RestartProvider");return l}const F0=(l,i,r,o,u)=>({idle:{icon:null,title:"",description:"",tip:""},requesting:{icon:e.jsx(tt,{className:"h-16 w-16 text-primary animate-spin"}),title:o??"准备重启",description:u??"正在发送重启请求...",tip:"🔄 正在准备重启麦麦..."},restarting:{icon:e.jsx(tt,{className:"h-16 w-16 text-primary animate-spin"}),title:o??"正在重启麦麦",description:u??"请稍候,麦麦正在重启中...",tip:"🔄 配置已保存,正在重启主程序..."},checking:{icon:e.jsx(tt,{className:"h-16 w-16 text-primary animate-spin"}),title:"检查服务状态",description:`等待服务恢复... (${i}/${r})`,tip:"⏳ 正在等待服务恢复,请勿关闭页面..."},success:{icon:e.jsx(aa,{className:"h-16 w-16 text-green-500"}),title:"重启成功",description:"正在跳转到登录页面...",tip:"✅ 配置已生效,服务运行正常"},failed:{icon:e.jsx(Ot,{className:"h-16 w-16 text-destructive"}),title:"重启超时",description:"服务未能在预期时间内恢复",tip:"⚠️ 如果长时间无响应,请尝试手动重启"}})[l];function vn({visible:l,onComplete:i,onFailed:r,title:o,description:u,showAnimation:x=!0,className:h}){let f=null;try{f=Il()}catch{}return(f?f.isRestarting:l)?f?e.jsx(cj,{state:f.state,onRetry:f.retryHealthCheck,onComplete:i,onFailed:r,title:o,description:u,showAnimation:x,className:h}):e.jsx(I0,{onComplete:i,onFailed:r,title:o,description:u,showAnimation:x,className:h}):null}function cj({state:l,onRetry:i,onComplete:r,onFailed:o,title:u,description:x,showAnimation:h,className:f}){const{status:g,progress:j,elapsedTime:v,checkAttempts:y,maxAttempts:b}=l;m.useEffect(()=>{g==="success"&&r?r():g==="failed"&&o&&o()},[g,r,o]);const S=F0(g,y,b,u,x),w=O=>{const A=Math.floor(O/60),D=O%60;return`${A}:${D.toString().padStart(2,"0")}`};return e.jsxs("div",{className:H("fixed inset-0 bg-background/95 backdrop-blur-sm z-50 flex items-center justify-center",f),children:[h&&e.jsx(Q0,{}),e.jsxs("div",{className:"max-w-md w-full mx-4 space-y-8 relative z-10",children:[e.jsxs("div",{className:"flex flex-col items-center space-y-4",children:[e.jsxs("div",{className:"relative",children:[S.icon,(g==="restarting"||g==="checking")&&e.jsx("div",{className:"absolute inset-0 rounded-full bg-primary/20 animate-ping"})]}),e.jsx("h2",{className:"text-2xl font-bold",children:S.title}),e.jsx("p",{className:"text-muted-foreground text-center",children:S.description})]}),g!=="failed"&&g!=="idle"&&e.jsxs("div",{className:"space-y-2",children:[e.jsx(gn,{value:j,className:"h-2"}),e.jsxs("div",{className:"flex justify-between text-sm text-muted-foreground",children:[e.jsxs("span",{children:[j,"%"]}),e.jsxs("span",{children:["已用时: ",w(v)]})]})]}),e.jsx("div",{className:"bg-muted/50 rounded-lg p-4",children:e.jsx("p",{className:"text-sm text-muted-foreground",children:S.tip})}),g==="failed"&&e.jsxs("div",{className:"flex gap-2",children:[e.jsxs(C,{onClick:()=>window.location.reload(),variant:"default",className:"flex-1",children:[e.jsx(At,{className:"mr-2 h-4 w-4"}),"刷新页面"]}),e.jsxs(C,{onClick:i,variant:"secondary",className:"flex-1",children:[e.jsx(yr,{className:"mr-2 h-4 w-4"}),"重试检测"]})]})]})]})}function I0({onComplete:l,onFailed:i,title:r,description:o,showAnimation:u,className:x}){const[h,f]=m.useState({status:"restarting",progress:0,elapsedTime:0,checkAttempts:0,maxAttempts:60}),g=m.useCallback(()=>{let j=0;const v=60,y=async()=>{j++,f(b=>({...b,status:"checking",checkAttempts:j}));try{if((await fetch("/api/webui/system/status",{method:"GET",signal:AbortSignal.timeout(3e3)})).ok){f(S=>({...S,status:"success",progress:100})),setTimeout(()=>{l?.(),window.location.href="/auth"},1500);return}}catch{}j>=v?(f(b=>({...b,status:"failed"})),i?.()):setTimeout(y,2e3)};y()},[l,i]);return m.useEffect(()=>{const j=setInterval(()=>{f(b=>({...b,progress:b.progress>=90?b.progress:b.progress+1}))},200),v=setInterval(()=>{f(b=>({...b,elapsedTime:b.elapsedTime+1}))},1e3),y=setTimeout(()=>{g()},3e3);return()=>{clearInterval(j),clearInterval(v),clearTimeout(y)}},[g]),e.jsx(cj,{state:h,onRetry:g,onComplete:l,onFailed:i,title:r,description:o,showAnimation:u,className:x})}function Q0(){return e.jsxs("div",{className:"absolute inset-0 overflow-hidden pointer-events-none",children:[e.jsxs("div",{className:"absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-[600px] h-[600px]",children:[e.jsx("div",{className:"absolute inset-0 rounded-full border border-primary/10 animate-[ping_3s_ease-in-out_infinite]"}),e.jsx("div",{className:"absolute inset-8 rounded-full border border-primary/10 animate-[ping_3s_ease-in-out_infinite_0.5s]"}),e.jsx("div",{className:"absolute inset-16 rounded-full border border-primary/10 animate-[ping_3s_ease-in-out_infinite_1s]"})]}),e.jsx("div",{className:"absolute top-1/4 left-1/4 w-2 h-2 bg-primary/20 rounded-full animate-bounce"}),e.jsx("div",{className:"absolute top-3/4 right-1/4 w-3 h-3 bg-primary/15 rounded-full animate-bounce delay-150"}),e.jsx("div",{className:"absolute top-1/2 right-1/3 w-2 h-2 bg-primary/20 rounded-full animate-bounce delay-300"})]})}function Y0(){return e.jsx(jn,{children:e.jsx(X0,{})})}const K0=l=>{const i=[];for(let r=0;r{try{S(!0);const L=await zN.get("https://v1.hitokoto.cn/?c=a&c=b&c=c&c=d&c=h&c=i&c=k");y({hitokoto:L.data.hitokoto,from:L.data.from||L.data.from_who||"未知"})}catch(L){console.error("获取一言失败:",L),y({hitokoto:"人生就像一盒巧克力,你永远不知道下一颗是什么味道。",from:"阿甘正传"})}finally{S(!1)}},[]),z=m.useCallback(async()=>{try{const L=await we("/api/webui/system/status");if(L.ok){const B=await L.json();O(B)}else O(null)}catch(L){console.error("获取机器人状态失败:",L),O(null)}},[]),_=async()=>{await A()},T=m.useCallback(async()=>{try{const L=await we(`/api/webui/statistics/dashboard?hours=${h}`);if(L.ok){const B=await L.json();i(B)}o(!1),x(100)}catch(L){console.error("Failed to fetch dashboard data:",L),o(!1),x(100)}},[h]);if(m.useEffect(()=>{if(!r)return;x(0);const L=setTimeout(()=>x(15),200),B=setTimeout(()=>x(30),800),_e=setTimeout(()=>x(45),2e3),Ne=setTimeout(()=>x(60),4e3),Ce=setTimeout(()=>x(75),6500),ve=setTimeout(()=>x(85),9e3),ze=setTimeout(()=>x(92),11e3);return()=>{clearTimeout(L),clearTimeout(B),clearTimeout(_e),clearTimeout(Ne),clearTimeout(Ce),clearTimeout(ve),clearTimeout(ze)}},[r]),m.useEffect(()=>{T(),V(),z()},[T,V,z]),m.useEffect(()=>{if(!g)return;const L=setInterval(()=>{T(),z()},3e4);return()=>clearInterval(L)},[g,T,z]),r||!l)return e.jsx("div",{className:"flex items-center justify-center h-[calc(100vh-200px)]",children:e.jsxs("div",{className:"text-center space-y-6 w-full max-w-md px-4",children:[e.jsx(At,{className:"h-12 w-12 animate-spin mx-auto text-primary"}),e.jsxs("div",{className:"space-y-2",children:[e.jsx("p",{className:"text-lg font-medium",children:"加载统计数据中..."}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"正在获取麦麦运行数据"})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(gn,{value:u,className:"h-2"}),e.jsxs("p",{className:"text-xs text-muted-foreground",children:[u,"%"]})]})]})});const{summary:$,model_stats:E=[],hourly_data:se=[],daily_data:te=[],recent_activity:ne=[]}=l,ue=$??{total_requests:0,total_cost:0,total_tokens:0,online_time:0,total_messages:0,total_replies:0,avg_response_time:0,cost_per_hour:0,tokens_per_hour:0},Se=L=>{const B=Math.floor(L/3600),_e=Math.floor(L%3600/60);return`${B}小时${_e}分钟`},oe=L=>{const B=L.toLocaleString("zh-CN");return L>=1e9?{display:`${(L/1e9).toFixed(2)}B`,exact:B,needsExact:!0}:L>=1e6?{display:`${(L/1e6).toFixed(2)}M`,exact:B,needsExact:!0}:L>=1e4?{display:`${(L/1e3).toFixed(1)}K`,exact:B,needsExact:!0}:L>=1e3?{display:`${(L/1e3).toFixed(2)}K`,exact:B,needsExact:!0}:{display:B,exact:B,needsExact:!1}},je=L=>{const B=`¥${L.toLocaleString("zh-CN",{minimumFractionDigits:2,maximumFractionDigits:2})}`;return L>=1e6?{display:`¥${(L/1e6).toFixed(2)}M`,exact:B,needsExact:!0}:L>=1e4?{display:`¥${(L/1e3).toFixed(1)}K`,exact:B,needsExact:!0}:L>=1e3?{display:`¥${(L/1e3).toFixed(2)}K`,exact:B,needsExact:!0}:{display:B,exact:B,needsExact:!1}},be=L=>new Date(L).toLocaleString("zh-CN",{month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit"}),U=K0(E.length),P=E.map((L,B)=>({name:L.model_name,value:L.request_count,fill:U[B]})),X={requests:{label:"请求数",color:"hsl(var(--chart-1))"},cost:{label:"花费(¥)",color:"hsl(var(--chart-2))"},tokens:{label:"Tokens",color:"hsl(var(--chart-3))"}};return e.jsx(Ze,{className:"h-full",children:e.jsxs("div",{className:"space-y-4 sm:space-y-6 p-4 sm:p-6",children:[e.jsxs("div",{className:"flex flex-col sm:flex-row sm:items-center justify-between gap-4",children:[e.jsxs("div",{children:[e.jsx("h1",{className:"text-2xl sm:text-3xl font-bold",children:"实时监控面板"}),e.jsx("p",{className:"text-sm text-muted-foreground mt-1",children:"麦麦运行状态和统计数据一览"})]}),e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsx(Sa,{value:h.toString(),onValueChange:L=>f(Number(L)),children:e.jsxs(xa,{className:"grid grid-cols-3 w-full sm:w-auto",children:[e.jsx(is,{value:"24",children:"24小时"}),e.jsx(is,{value:"168",children:"7天"}),e.jsx(is,{value:"720",children:"30天"})]})}),e.jsxs(C,{variant:g?"default":"outline",size:"sm",onClick:()=>j(!g),className:"gap-2",children:[e.jsx(At,{className:`h-4 w-4 ${g?"animate-spin":""}`}),e.jsx("span",{className:"hidden sm:inline",children:"自动刷新"})]}),e.jsx(C,{variant:"outline",size:"sm",onClick:T,children:e.jsx(At,{className:"h-4 w-4"})})]})]}),e.jsxs("div",{className:"flex items-center gap-3 px-4 py-2 rounded-lg border border-dashed border-muted-foreground/30 bg-muted/20",children:[b?e.jsx(aj,{className:"h-5 flex-1"}):v?e.jsxs("p",{className:"flex-1 text-sm text-muted-foreground italic truncate",children:['"',v.hitokoto,'" —— ',v.from]}):null,e.jsx(C,{variant:"ghost",size:"icon",className:"h-7 w-7 shrink-0",onClick:V,disabled:b,children:e.jsx(At,{className:`h-3.5 w-3.5 ${b?"animate-spin":""}`})})]}),e.jsxs("div",{className:"grid gap-4 grid-cols-1 lg:grid-cols-3",children:[e.jsxs(Ve,{className:"lg:col-span-1",children:[e.jsx(rs,{className:"pb-3",children:e.jsxs(cs,{className:"text-sm font-medium flex items-center gap-2",children:[e.jsx(Mr,{className:"h-4 w-4"}),"麦麦状态"]})}),e.jsx(gs,{children:e.jsxs("div",{className:"flex items-center gap-4",children:[e.jsx("div",{className:"flex items-center gap-2",children:w?.running?e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"h-3 w-3 rounded-full bg-green-500 animate-pulse"}),e.jsxs(Ye,{variant:"outline",className:"text-green-600 border-green-300 bg-green-50",children:[e.jsx(aa,{className:"h-3 w-3 mr-1"}),"运行中"]})]}):e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"h-3 w-3 rounded-full bg-red-500"}),e.jsxs(Ye,{variant:"outline",className:"text-red-600 border-red-300 bg-red-50",children:[e.jsx(Ot,{className:"h-3 w-3 mr-1"}),"已停止"]})]})}),w&&e.jsxs("div",{className:"text-xs text-muted-foreground",children:[e.jsxs("span",{children:["v",w.version]}),e.jsx("span",{className:"mx-2",children:"|"}),e.jsxs("span",{children:["运行 ",Se(w.uptime)]})]})]})})]}),e.jsxs(Ve,{children:[e.jsx(rs,{className:"pb-3",children:e.jsxs(cs,{className:"text-sm font-medium flex items-center gap-2",children:[e.jsx(hn,{className:"h-4 w-4"}),"快速操作"]})}),e.jsx(gs,{children:e.jsxs("div",{className:"flex flex-wrap gap-2",children:[e.jsxs(C,{variant:"outline",size:"sm",onClick:_,disabled:D,className:"gap-2",children:[e.jsx(yr,{className:`h-4 w-4 ${D?"animate-spin":""}`}),D?"重启中...":"重启麦麦"]}),e.jsx(C,{variant:"outline",size:"sm",asChild:!0,className:"gap-2",children:e.jsxs(ci,{to:"/logs",children:[e.jsx(Aa,{className:"h-4 w-4"}),"查看日志"]})}),e.jsx(C,{variant:"outline",size:"sm",asChild:!0,className:"gap-2",children:e.jsxs(ci,{to:"/plugins",children:[e.jsx(Ty,{className:"h-4 w-4"}),"插件管理"]})}),e.jsx(C,{variant:"outline",size:"sm",asChild:!0,className:"gap-2",children:e.jsxs(ci,{to:"/settings",children:[e.jsx(ji,{className:"h-4 w-4"}),"系统设置"]})})]})})]}),e.jsxs(Ve,{children:[e.jsxs(rs,{className:"pb-3",children:[e.jsxs(cs,{className:"text-sm font-medium flex items-center gap-2",children:[e.jsx(Ey,{className:"h-4 w-4"}),"反馈问卷"]}),e.jsx(st,{className:"text-xs",children:"帮助我们改进产品体验"})]}),e.jsx(gs,{children:e.jsxs("div",{className:"flex flex-wrap gap-2",children:[e.jsx(C,{variant:"outline",size:"sm",asChild:!0,className:"gap-2",children:e.jsxs(ci,{to:"/survey/webui-feedback",children:[e.jsx(Aa,{className:"h-4 w-4"}),"WebUI 反馈"]})}),e.jsx(C,{variant:"outline",size:"sm",asChild:!0,className:"gap-2",children:e.jsxs(ci,{to:"/survey/maibot-feedback",children:[e.jsx(Fl,{className:"h-4 w-4"}),"麦麦反馈"]})})]})})]})]}),e.jsxs("div",{className:"grid gap-4 grid-cols-1 xs:grid-cols-2 lg:grid-cols-4",children:[e.jsxs(Ve,{children:[e.jsxs(rs,{className:"flex flex-row items-center justify-between space-y-0 pb-2",children:[e.jsx(cs,{className:"text-sm font-medium",children:"总请求数"}),e.jsx(zy,{className:"h-4 w-4 text-muted-foreground"})]}),e.jsxs(gs,{children:[e.jsxs("div",{className:"text-2xl font-bold",children:[oe(ue.total_requests).display,oe(ue.total_requests).needsExact&&e.jsxs("span",{className:"text-xs font-normal text-muted-foreground ml-1",children:["(",oe(ue.total_requests).exact,")"]})]}),e.jsxs("p",{className:"text-xs text-muted-foreground mt-1",children:["最近",h<48?h+"小时":Math.floor(h/24)+"天"]})]})]}),e.jsxs(Ve,{children:[e.jsxs(rs,{className:"flex flex-row items-center justify-between space-y-0 pb-2",children:[e.jsx(cs,{className:"text-sm font-medium",children:"总花费"}),e.jsx(My,{className:"h-4 w-4 text-muted-foreground"})]}),e.jsxs(gs,{children:[e.jsxs("div",{className:"text-2xl font-bold",children:[je(ue.total_cost).display,je(ue.total_cost).needsExact&&e.jsxs("span",{className:"text-xs font-normal text-muted-foreground ml-1",children:["(",je(ue.total_cost).exact,")"]})]}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:ue.cost_per_hour>0?`¥${ue.cost_per_hour.toFixed(2)}/小时`:"暂无数据"})]})]}),e.jsxs(Ve,{children:[e.jsxs(rs,{className:"flex flex-row items-center justify-between space-y-0 pb-2",children:[e.jsx(cs,{className:"text-sm font-medium",children:"Token消耗"}),e.jsx(ro,{className:"h-4 w-4 text-muted-foreground"})]}),e.jsxs(gs,{children:[e.jsxs("div",{className:"text-2xl font-bold",children:[oe(ue.total_tokens).display,oe(ue.total_tokens).needsExact&&e.jsxs("span",{className:"text-xs font-normal text-muted-foreground ml-1",children:["(",oe(ue.total_tokens).exact,")"]})]}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:ue.tokens_per_hour>0?`${oe(ue.tokens_per_hour).display}/小时`:"暂无数据"})]})]}),e.jsxs(Ve,{children:[e.jsxs(rs,{className:"flex flex-row items-center justify-between space-y-0 pb-2",children:[e.jsx(cs,{className:"text-sm font-medium",children:"平均响应"}),e.jsx(hn,{className:"h-4 w-4 text-muted-foreground"})]}),e.jsxs(gs,{children:[e.jsxs("div",{className:"text-2xl font-bold",children:[ue.avg_response_time.toFixed(2),"s"]}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:"API平均耗时"})]})]})]}),e.jsxs("div",{className:"grid gap-4 grid-cols-1 sm:grid-cols-3",children:[e.jsxs(Ve,{children:[e.jsxs(rs,{className:"flex flex-row items-center justify-between space-y-0 pb-2",children:[e.jsx(cs,{className:"text-sm font-medium",children:"在线时长"}),e.jsx(xi,{className:"h-4 w-4 text-muted-foreground"})]}),e.jsx(gs,{children:e.jsxs("div",{className:"text-xl font-bold",children:[Se(ue.online_time),e.jsxs("span",{className:"text-xs font-normal text-muted-foreground ml-1",children:["(",ue.online_time.toLocaleString(),"秒)"]})]})})]}),e.jsxs(Ve,{children:[e.jsxs(rs,{className:"flex flex-row items-center justify-between space-y-0 pb-2",children:[e.jsx(cs,{className:"text-sm font-medium",children:"消息处理"}),e.jsx(Fl,{className:"h-4 w-4 text-muted-foreground"})]}),e.jsxs(gs,{children:[e.jsxs("div",{className:"text-xl font-bold",children:[oe(ue.total_messages).display,oe(ue.total_messages).needsExact&&e.jsxs("span",{className:"text-xs font-normal text-muted-foreground ml-1",children:["(",oe(ue.total_messages).exact,")"]})]}),e.jsxs("p",{className:"text-xs text-muted-foreground mt-1",children:["回复 ",oe(ue.total_replies).display,oe(ue.total_replies).needsExact&&e.jsxs("span",{children:["(",oe(ue.total_replies).exact,")"]})," 条"]})]})]}),e.jsxs(Ve,{children:[e.jsxs(rs,{className:"flex flex-row items-center justify-between space-y-0 pb-2",children:[e.jsx(cs,{className:"text-sm font-medium",children:"成本效率"}),e.jsx(Ay,{className:"h-4 w-4 text-muted-foreground"})]}),e.jsxs(gs,{children:[e.jsx("div",{className:"text-xl font-bold",children:ue.total_messages>0?`¥${(ue.total_cost/ue.total_messages*100).toFixed(2)}`:"¥0.00"}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:"每100条消息"})]})]})]}),e.jsxs(Sa,{defaultValue:"trends",className:"space-y-4",children:[e.jsxs(xa,{className:"grid w-full grid-cols-2 sm:grid-cols-4",children:[e.jsx(is,{value:"trends",children:"趋势"}),e.jsx(is,{value:"models",children:"模型"}),e.jsx(is,{value:"activity",children:"活动"}),e.jsx(is,{value:"daily",children:"日统计"})]}),e.jsxs(As,{value:"trends",className:"space-y-4",children:[e.jsxs(Ve,{children:[e.jsxs(rs,{children:[e.jsx(cs,{children:"请求趋势"}),e.jsxs(st,{children:["最近",h,"小时的请求量变化"]})]}),e.jsx(gs,{children:e.jsx(oi,{config:X,className:"h-[300px] sm:h-[400px] w-full aspect-auto",children:e.jsxs(ey,{data:se,children:[e.jsx(Xc,{strokeDasharray:"3 3",stroke:"hsl(var(--muted-foreground) / 0.2)"}),e.jsx(Pc,{dataKey:"timestamp",tickFormatter:L=>be(L),angle:-45,textAnchor:"end",height:60,stroke:"hsl(var(--muted-foreground))",tick:{fill:"hsl(var(--muted-foreground))"}}),e.jsx(ur,{stroke:"hsl(var(--muted-foreground))",tick:{fill:"hsl(var(--muted-foreground))"}}),e.jsx(xr,{content:e.jsx(di,{labelFormatter:L=>be(L)})}),e.jsx(sy,{type:"monotone",dataKey:"requests",stroke:"var(--color-requests)",strokeWidth:2})]})})})]}),e.jsxs("div",{className:"grid gap-4 grid-cols-1 lg:grid-cols-2",children:[e.jsxs(Ve,{children:[e.jsxs(rs,{children:[e.jsx(cs,{children:"花费趋势"}),e.jsx(st,{children:"API调用成本变化"})]}),e.jsx(gs,{children:e.jsx(oi,{config:X,className:"h-[250px] sm:h-[300px] w-full aspect-auto",children:e.jsxs(Ru,{data:se,children:[e.jsx(Xc,{strokeDasharray:"3 3",stroke:"hsl(var(--muted-foreground) / 0.2)"}),e.jsx(Pc,{dataKey:"timestamp",tickFormatter:L=>be(L),angle:-45,textAnchor:"end",height:60,stroke:"hsl(var(--muted-foreground))",tick:{fill:"hsl(var(--muted-foreground))"}}),e.jsx(ur,{stroke:"hsl(var(--muted-foreground))",tick:{fill:"hsl(var(--muted-foreground))"}}),e.jsx(xr,{content:e.jsx(di,{labelFormatter:L=>be(L)})}),e.jsx(Jc,{dataKey:"cost",fill:"var(--color-cost)"})]})})})]}),e.jsxs(Ve,{children:[e.jsxs(rs,{children:[e.jsx(cs,{children:"Token消耗"}),e.jsx(st,{children:"Token使用量变化"})]}),e.jsx(gs,{children:e.jsx(oi,{config:X,className:"h-[250px] sm:h-[300px] w-full aspect-auto",children:e.jsxs(Ru,{data:se,children:[e.jsx(Xc,{strokeDasharray:"3 3",stroke:"hsl(var(--muted-foreground) / 0.2)"}),e.jsx(Pc,{dataKey:"timestamp",tickFormatter:L=>be(L),angle:-45,textAnchor:"end",height:60,stroke:"hsl(var(--muted-foreground))",tick:{fill:"hsl(var(--muted-foreground))"}}),e.jsx(ur,{stroke:"hsl(var(--muted-foreground))",tick:{fill:"hsl(var(--muted-foreground))"}}),e.jsx(xr,{content:e.jsx(di,{labelFormatter:L=>be(L)})}),e.jsx(Jc,{dataKey:"tokens",fill:"var(--color-tokens)"})]})})})]})]})]}),e.jsx(As,{value:"models",className:"space-y-4",children:e.jsxs("div",{className:"grid gap-4 grid-cols-1 lg:grid-cols-2",children:[e.jsxs(Ve,{children:[e.jsxs(rs,{children:[e.jsx(cs,{children:"模型请求分布"}),e.jsxs(st,{children:["各模型使用占比 (共 ",E.length," 个模型)"]})]}),e.jsx(gs,{children:e.jsx(oi,{config:Object.fromEntries(E.map((L,B)=>[L.model_name,{label:L.model_name,color:U[B]}])),className:"h-[300px] sm:h-[400px] w-full aspect-auto",children:e.jsxs(ty,{children:[e.jsx(xr,{content:e.jsx(di,{})}),e.jsx(ay,{data:P,cx:"50%",cy:"50%",labelLine:!1,label:({name:L,percent:B})=>B&&B<.05?"":`${L} ${B?(B*100).toFixed(0):0}%`,outerRadius:100,dataKey:"value",children:P.map((L,B)=>e.jsx(ly,{fill:L.fill},`cell-${B}`))})]})})})]}),e.jsxs(Ve,{children:[e.jsxs(rs,{children:[e.jsx(cs,{children:"模型详细统计"}),e.jsx(st,{children:"请求数、花费和性能"})]}),e.jsx(gs,{children:e.jsx(Ze,{className:"h-[300px] sm:h-[400px]",children:e.jsx("div",{className:"space-y-3",children:E.map((L,B)=>e.jsxs("div",{className:"p-4 rounded-lg border bg-card hover:bg-accent/50 transition-colors",children:[e.jsxs("div",{className:"flex items-center justify-between mb-2",children:[e.jsx("h4",{className:"font-semibold text-sm truncate flex-1 min-w-0",children:L.model_name}),e.jsx("div",{className:"w-3 h-3 rounded-full ml-2 flex-shrink-0",style:{backgroundColor:`hsl(var(--chart-${B%5+1}))`}})]}),e.jsxs("div",{className:"grid grid-cols-2 gap-2 text-xs",children:[e.jsxs("div",{children:[e.jsx("span",{className:"text-muted-foreground",children:"请求数:"}),e.jsx("span",{className:"ml-1 font-medium",children:L.request_count.toLocaleString()})]}),e.jsxs("div",{children:[e.jsx("span",{className:"text-muted-foreground",children:"花费:"}),e.jsxs("span",{className:"ml-1 font-medium",children:["¥",L.total_cost.toFixed(2)]})]}),e.jsxs("div",{children:[e.jsx("span",{className:"text-muted-foreground",children:"Tokens:"}),e.jsxs("span",{className:"ml-1 font-medium",children:[(L.total_tokens/1e3).toFixed(1),"K"]})]}),e.jsxs("div",{children:[e.jsx("span",{className:"text-muted-foreground",children:"平均耗时:"}),e.jsxs("span",{className:"ml-1 font-medium",children:[L.avg_response_time.toFixed(2),"s"]})]})]})]},B))})})})]})]})}),e.jsx(As,{value:"activity",children:e.jsxs(Ve,{children:[e.jsxs(rs,{children:[e.jsx(cs,{children:"最近活动"}),e.jsx(st,{children:"最新的API调用记录"})]}),e.jsx(gs,{children:e.jsx(Ze,{className:"h-[400px] sm:h-[500px]",children:e.jsx("div",{className:"space-y-2",children:ne.map((L,B)=>e.jsxs("div",{className:"p-3 sm:p-4 rounded-lg border bg-card hover:bg-accent/50 transition-colors",children:[e.jsxs("div",{className:"flex flex-col sm:flex-row sm:items-center justify-between gap-2 mb-2",children:[e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsx("div",{className:"font-medium text-sm truncate",children:L.model}),e.jsx("div",{className:"text-xs text-muted-foreground",children:L.request_type})]}),e.jsx("div",{className:"text-xs text-muted-foreground flex-shrink-0",children:be(L.timestamp)})]}),e.jsxs("div",{className:"grid grid-cols-2 sm:grid-cols-4 gap-2 text-xs",children:[e.jsxs("div",{children:[e.jsx("span",{className:"text-muted-foreground",children:"Tokens:"}),e.jsx("span",{className:"ml-1",children:L.tokens})]}),e.jsxs("div",{children:[e.jsx("span",{className:"text-muted-foreground",children:"花费:"}),e.jsxs("span",{className:"ml-1",children:["¥",L.cost.toFixed(4)]})]}),e.jsxs("div",{children:[e.jsx("span",{className:"text-muted-foreground",children:"耗时:"}),e.jsxs("span",{className:"ml-1",children:[L.time_cost.toFixed(2),"s"]})]}),e.jsxs("div",{children:[e.jsx("span",{className:"text-muted-foreground",children:"状态:"}),e.jsx("span",{className:`ml-1 ${L.status==="success"?"text-green-600":"text-red-600"}`,children:L.status})]})]})]},B))})})})]})}),e.jsx(As,{value:"daily",children:e.jsxs(Ve,{children:[e.jsxs(rs,{children:[e.jsx(cs,{children:"每日统计"}),e.jsx(st,{children:"最近7天的数据汇总"})]}),e.jsx(gs,{children:e.jsx(oi,{config:{requests:{label:"请求数",color:"hsl(var(--chart-1))"},cost:{label:"花费(¥)",color:"hsl(var(--chart-2))"}},className:"h-[400px] sm:h-[500px] w-full aspect-auto",children:e.jsxs(Ru,{data:te,children:[e.jsx(Xc,{strokeDasharray:"3 3",stroke:"hsl(var(--muted-foreground) / 0.2)"}),e.jsx(Pc,{dataKey:"timestamp",tickFormatter:L=>{const B=new Date(L);return`${B.getMonth()+1}/${B.getDate()}`},stroke:"hsl(var(--muted-foreground))",tick:{fill:"hsl(var(--muted-foreground))"}}),e.jsx(ur,{yAxisId:"left",stroke:"hsl(var(--muted-foreground))",tick:{fill:"hsl(var(--muted-foreground))"}}),e.jsx(ur,{yAxisId:"right",orientation:"right",stroke:"hsl(var(--muted-foreground))",tick:{fill:"hsl(var(--muted-foreground))"}}),e.jsx(xr,{content:e.jsx(di,{labelFormatter:L=>new Date(L).toLocaleDateString("zh-CN")})}),e.jsx($0,{content:e.jsx(ij,{})}),e.jsx(Jc,{yAxisId:"left",dataKey:"requests",fill:"var(--color-requests)"}),e.jsx(Jc,{yAxisId:"right",dataKey:"cost",fill:"var(--color-cost)"})]})})})]})})]}),e.jsx(vn,{})]})})}const P0={theme:"system",setTheme:()=>null},oj=m.createContext(P0),dm=()=>{const l=m.useContext(oj);if(l===void 0)throw new Error("useTheme must be used within a ThemeProvider");return l},J0=(l,i,r)=>{const o=document.documentElement.classList.contains("no-animations");if(!document.startViewTransition||o){i(l);return}const u=r.clientX,x=r.clientY,h=Math.hypot(Math.max(u,innerWidth-u),Math.max(x,innerHeight-x));document.startViewTransition(()=>{i(l)}).ready.then(()=>{document.documentElement.animate({clipPath:[`circle(0px at ${u}px ${x}px)`,`circle(${h}px at ${u}px ${x}px)`]},{duration:500,easing:"ease-in-out",pseudoElement:"::view-transition-new(root)"})})},dj=m.createContext(void 0),uj=()=>{const l=m.useContext(dj);if(l===void 0)throw new Error("useAnimation must be used within an AnimationProvider");return l},Fe=m.forwardRef(({className:l,...i},r)=>e.jsx(Pp,{className:H("peer inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input",l),...i,ref:r,children:e.jsx(LN,{className:H("pointer-events-none block h-4 w-4 rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-4 data-[state=unchecked]:translate-x-0")})}));Fe.displayName=Pp.displayName;const Z0=gi("text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"),k=m.forwardRef(({className:l,...i},r)=>e.jsx(dg,{ref:r,className:H(Z0(),l),...i}));k.displayName=dg.displayName;const ie=m.forwardRef(({className:l,type:i,...r},o)=>e.jsx("input",{type:i,className:H("flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-base shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",l),ref:o,...r}));ie.displayName="Input";const W0=5,ew=5e3;let qu=0;function sw(){return qu=(qu+1)%Number.MAX_SAFE_INTEGER,qu.toString()}const Gu=new Map,yp=l=>{if(Gu.has(l))return;const i=setTimeout(()=>{Gu.delete(l),br({type:"REMOVE_TOAST",toastId:l})},ew);Gu.set(l,i)},tw=(l,i)=>{switch(i.type){case"ADD_TOAST":return{...l,toasts:[i.toast,...l.toasts].slice(0,W0)};case"UPDATE_TOAST":return{...l,toasts:l.toasts.map(r=>r.id===i.toast.id?{...r,...i.toast}:r)};case"DISMISS_TOAST":{const{toastId:r}=i;return r?yp(r):l.toasts.forEach(o=>{yp(o.id)}),{...l,toasts:l.toasts.map(o=>o.id===r||r===void 0?{...o,open:!1}:o)}}case"REMOVE_TOAST":return i.toastId===void 0?{...l,toasts:[]}:{...l,toasts:l.toasts.filter(r=>r.id!==i.toastId)}}},no=[];let io={toasts:[]};function br(l){io=tw(io,l),no.forEach(i=>{i(io)})}function aw({...l}){const i=sw(),r=u=>br({type:"UPDATE_TOAST",toast:{...u,id:i}}),o=()=>br({type:"DISMISS_TOAST",toastId:i});return br({type:"ADD_TOAST",toast:{...l,id:i,open:!0,onOpenChange:u=>{u||o()}}}),{id:i,dismiss:o,update:r}}function Ks(){const[l,i]=m.useState(io);return m.useEffect(()=>(no.push(i),()=>{const r=no.indexOf(i);r>-1&&no.splice(r,1)}),[l]),{...l,toast:aw,dismiss:r=>br({type:"DISMISS_TOAST",toastId:r})}}const lw=[{id:"minLength",label:"长度至少 10 位",description:"Token 长度必须大于等于 10 个字符",validate:l=>l.length>=10},{id:"hasUppercase",label:"包含大写字母",description:"至少包含一个大写字母 (A-Z)",validate:l=>/[A-Z]/.test(l)},{id:"hasLowercase",label:"包含小写字母",description:"至少包含一个小写字母 (a-z)",validate:l=>/[a-z]/.test(l)},{id:"hasSpecialChar",label:"包含特殊符号",description:"至少包含一个特殊符号 (!@#$%^&*()_+-=[]{}|;:,.<>?/)",validate:l=>/[!@#$%^&*()_+\-=[\]{}|;:,.<>?/]/.test(l)}];function nw(l){const i=lw.map(o=>({id:o.id,label:o.label,description:o.description,passed:o.validate(l)}));return{isValid:i.every(o=>o.passed),rules:i}}const go="0.12.0 Beta",um="MaiBot Dashboard",iw=`${um} v${go}`,rw=(l="v")=>`${l}${go}`,Wt={THEME:"maibot-ui-theme",ACCENT_COLOR:"accent-color",ENABLE_ANIMATIONS:"maibot-animations",ENABLE_WAVES_BACKGROUND:"maibot-waves-background",LOG_CACHE_SIZE:"maibot-log-cache-size",LOG_AUTO_SCROLL:"maibot-log-auto-scroll",LOG_FONT_SIZE:"maibot-log-font-size",LOG_LINE_SPACING:"maibot-log-line-spacing",DATA_SYNC_INTERVAL:"maibot-data-sync-interval",WS_RECONNECT_INTERVAL:"maibot-ws-reconnect-interval",WS_MAX_RECONNECT_ATTEMPTS:"maibot-ws-max-reconnect-attempts",COMPLETED_TOURS:"maibot-completed-tours"},Va={theme:"system",accentColor:"blue",enableAnimations:!0,enableWavesBackground:!0,logCacheSize:1e3,logAutoScroll:!0,logFontSize:"xs",logLineSpacing:4,dataSyncInterval:30,wsReconnectInterval:3e3,wsMaxReconnectAttempts:10};function dt(l){const i=mj(l),r=localStorage.getItem(i);if(r===null)return Va[l];const o=Va[l];if(typeof o=="boolean")return r==="true";if(typeof o=="number"){const u=parseFloat(r);return isNaN(u)?o:u}return r}function ui(l,i){const r=mj(l);localStorage.setItem(r,String(i)),window.dispatchEvent(new CustomEvent("maibot-settings-change",{detail:{key:l,value:i}}))}function cw(){return{theme:dt("theme"),accentColor:dt("accentColor"),enableAnimations:dt("enableAnimations"),enableWavesBackground:dt("enableWavesBackground"),logCacheSize:dt("logCacheSize"),logAutoScroll:dt("logAutoScroll"),logFontSize:dt("logFontSize"),logLineSpacing:dt("logLineSpacing"),dataSyncInterval:dt("dataSyncInterval"),wsReconnectInterval:dt("wsReconnectInterval"),wsMaxReconnectAttempts:dt("wsMaxReconnectAttempts")}}function ow(){const l=cw(),i=localStorage.getItem(Wt.COMPLETED_TOURS),r=i?JSON.parse(i):[];return{...l,completedTours:r}}function dw(l){const i=[],r=[];for(const[o,u]of Object.entries(l)){if(o==="completedTours"){Array.isArray(u)?(localStorage.setItem(Wt.COMPLETED_TOURS,JSON.stringify(u)),i.push("completedTours")):r.push("completedTours");continue}if(o in Va){const x=o,h=Va[x];if(typeof u==typeof h){if(x==="theme"&&!["light","dark","system"].includes(u)){r.push(o);continue}if(x==="logFontSize"&&!["xs","sm","base"].includes(u)){r.push(o);continue}ui(x,u),i.push(o)}else r.push(o)}else r.push(o)}return{success:i.length>0,imported:i,skipped:r}}function uw(){for(const l of Object.keys(Va))ui(l,Va[l]);localStorage.removeItem(Wt.COMPLETED_TOURS),window.dispatchEvent(new CustomEvent("maibot-settings-reset"))}function mw(){const l=[],i=[],r=[];for(let o=0;oo.size-r.size),{used:l,items:localStorage.length,details:i}}function xw(l){if(l===0)return"0 B";const i=1024,r=["B","KB","MB"],o=Math.floor(Math.log(l)/Math.log(i));return parseFloat((l/Math.pow(i,o)).toFixed(2))+" "+r[o]}function mj(l){return{theme:Wt.THEME,accentColor:Wt.ACCENT_COLOR,enableAnimations:Wt.ENABLE_ANIMATIONS,enableWavesBackground:Wt.ENABLE_WAVES_BACKGROUND,logCacheSize:Wt.LOG_CACHE_SIZE,logAutoScroll:Wt.LOG_AUTO_SCROLL,logFontSize:Wt.LOG_FONT_SIZE,logLineSpacing:Wt.LOG_LINE_SPACING,dataSyncInterval:Wt.DATA_SYNC_INTERVAL,wsReconnectInterval:Wt.WS_RECONNECT_INTERVAL,wsMaxReconnectAttempts:Wt.WS_MAX_RECONNECT_ATTEMPTS}[l]}const ma=m.forwardRef(({className:l,...i},r)=>e.jsxs(Jp,{ref:r,className:H("relative flex w-full touch-none select-none items-center",l),...i,children:[e.jsx(UN,{className:"relative h-1.5 w-full grow overflow-hidden rounded-full bg-primary/20",children:e.jsx(BN,{className:"absolute h-full bg-primary"})}),e.jsx(HN,{className:"block h-4 w-4 rounded-full border border-primary/50 bg-background shadow transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50"})]}));ma.displayName=Jp.displayName;class hw{ws=null;reconnectTimeout=null;reconnectAttempts=0;heartbeatInterval=null;logCallbacks=new Set;connectionCallbacks=new Set;isConnected=!1;logCache=[];getMaxCacheSize(){return dt("logCacheSize")}getMaxReconnectAttempts(){return dt("wsMaxReconnectAttempts")}getReconnectInterval(){return dt("wsReconnectInterval")}getWebSocketUrl(i){let r;{const o=window.location.protocol==="https:"?"wss:":"ws:",u=window.location.host;r=`${o}//${u}/ws/logs`}return i?`${r}?token=${encodeURIComponent(i)}`:r}async getWsToken(){try{const i=await we("/api/webui/ws-token",{method:"GET",credentials:"include"});if(!i.ok)return console.error("获取 WebSocket token 失败:",i.status),null;const r=await i.json();return r.success&&r.token?r.token:null}catch(i){return console.error("获取 WebSocket token 失败:",i),null}}async connect(){if(this.ws?.readyState===WebSocket.OPEN||this.ws?.readyState===WebSocket.CONNECTING)return;const i=await this.getWsToken(),r=this.getWebSocketUrl(i||void 0);try{this.ws=new WebSocket(r),this.ws.onopen=()=>{this.isConnected=!0,this.reconnectAttempts=0,this.notifyConnection(!0),this.startHeartbeat()},this.ws.onmessage=o=>{try{if(o.data==="pong")return;const u=JSON.parse(o.data);this.notifyLog(u)}catch(u){console.error("解析日志消息失败:",u)}},this.ws.onerror=o=>{console.error("❌ WebSocket 错误:",o),this.isConnected=!1,this.notifyConnection(!1)},this.ws.onclose=()=>{this.isConnected=!1,this.notifyConnection(!1),this.stopHeartbeat(),this.attemptReconnect()}}catch(o){console.error("创建 WebSocket 连接失败:",o),this.attemptReconnect()}}attemptReconnect(){const i=this.getMaxReconnectAttempts();if(this.reconnectAttempts>=i)return;this.reconnectAttempts+=1;const r=this.getReconnectInterval(),o=Math.min(r*this.reconnectAttempts,3e4);this.reconnectTimeout=window.setTimeout(()=>{this.connect()},o)}startHeartbeat(){this.heartbeatInterval=window.setInterval(()=>{this.ws?.readyState===WebSocket.OPEN&&this.ws.send("ping")},3e4)}stopHeartbeat(){this.heartbeatInterval!==null&&(clearInterval(this.heartbeatInterval),this.heartbeatInterval=null)}disconnect(){this.reconnectTimeout!==null&&(clearTimeout(this.reconnectTimeout),this.reconnectTimeout=null),this.stopHeartbeat(),this.ws&&(this.ws.close(),this.ws=null),this.isConnected=!1,this.reconnectAttempts=0}onLog(i){return this.logCallbacks.add(i),()=>this.logCallbacks.delete(i)}onConnectionChange(i){return this.connectionCallbacks.add(i),i(this.isConnected),()=>this.connectionCallbacks.delete(i)}notifyLog(i){if(!this.logCache.some(o=>o.id===i.id)){this.logCache.push(i);const o=this.getMaxCacheSize();this.logCache.length>o&&(this.logCache=this.logCache.slice(-o)),this.logCallbacks.forEach(u=>{try{u(i)}catch(x){console.error("日志回调执行失败:",x)}})}}notifyConnection(i){this.connectionCallbacks.forEach(r=>{try{r(i)}catch(o){console.error("连接状态回调执行失败:",o)}})}getAllLogs(){return[...this.logCache]}clearLogs(){this.logCache=[]}getConnectionStatus(){return this.isConnected}}const xn=new hw;typeof window<"u"&&setTimeout(()=>{xn.connect()},100);const Qs=cy,mm=oy,fw=iy,xj=m.forwardRef(({className:l,...i},r)=>e.jsx(ug,{ref:r,className:H("fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",l),...i}));xj.displayName=ug.displayName;const qs=m.forwardRef(({className:l,children:i,preventOutsideClose:r=!1,...o},u)=>e.jsxs(fw,{children:[e.jsx(xj,{}),e.jsxs(mg,{ref:u,className:H("fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",l),onPointerDownOutside:r?x=>x.preventDefault():void 0,onInteractOutside:r?x=>x.preventDefault():void 0,...o,children:[i,e.jsxs(ry,{className:"absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground",children:[e.jsx(fl,{className:"h-4 w-4"}),e.jsx("span",{className:"sr-only",children:"Close"})]})]})]}));qs.displayName=mg.displayName;const Gs=({className:l,...i})=>e.jsx("div",{className:H("flex flex-col space-y-1.5 text-center sm:text-left",l),...i});Gs.displayName="DialogHeader";const at=({className:l,...i})=>e.jsx("div",{className:H("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",l),...i});at.displayName="DialogFooter";const Vs=m.forwardRef(({className:l,...i},r)=>e.jsx(xg,{ref:r,className:H("text-lg font-semibold leading-none tracking-tight",l),...i}));Vs.displayName=xg.displayName;const Ws=m.forwardRef(({className:l,...i},r)=>e.jsx(hg,{ref:r,className:H("text-sm text-muted-foreground",l),...i}));Ws.displayName=hg.displayName;const js=qN,mt=GN,pw=$N,hj=m.forwardRef(({className:l,...i},r)=>e.jsx(Zp,{className:H("fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",l),...i,ref:r}));hj.displayName=Zp.displayName;const os=m.forwardRef(({className:l,...i},r)=>e.jsxs(pw,{children:[e.jsx(hj,{}),e.jsx(Wp,{ref:r,className:H("fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",l),...i})]}));os.displayName=Wp.displayName;const ds=({className:l,...i})=>e.jsx("div",{className:H("flex flex-col space-y-2 text-center sm:text-left",l),...i});ds.displayName="AlertDialogHeader";const us=({className:l,...i})=>e.jsx("div",{className:H("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",l),...i});us.displayName="AlertDialogFooter";const ms=m.forwardRef(({className:l,...i},r)=>e.jsx(eg,{ref:r,className:H("text-lg font-semibold",l),...i}));ms.displayName=eg.displayName;const xs=m.forwardRef(({className:l,...i},r)=>e.jsx(sg,{ref:r,className:H("text-sm text-muted-foreground",l),...i}));xs.displayName=sg.displayName;const hs=m.forwardRef(({className:l,...i},r)=>e.jsx(tg,{ref:r,className:H(Sr(),l),...i}));hs.displayName=tg.displayName;const fs=m.forwardRef(({className:l,...i},r)=>e.jsx(ag,{ref:r,className:H(Sr({variant:"outline"}),"mt-2 sm:mt-0",l),...i}));fs.displayName=ag.displayName;function gw(){return e.jsxs("div",{className:"space-y-4 sm:space-y-6 p-4 sm:p-6",children:[e.jsx("div",{className:"flex flex-col sm:flex-row sm:items-center justify-between gap-4",children:e.jsxs("div",{children:[e.jsx("h1",{className:"text-2xl sm:text-3xl font-bold",children:"系统设置"}),e.jsx("p",{className:"text-muted-foreground mt-1 sm:mt-2 text-sm sm:text-base",children:"管理您的应用偏好设置"})]})}),e.jsxs(Sa,{defaultValue:"appearance",className:"w-full",children:[e.jsxs(xa,{className:"grid w-full grid-cols-2 sm:grid-cols-4 gap-0.5 sm:gap-1 h-auto p-1",children:[e.jsxs(is,{value:"appearance",className:"gap-1 sm:gap-2 text-xs sm:text-sm px-2 sm:px-3 py-2",children:[e.jsx(Oy,{className:"h-3.5 w-3.5 sm:h-4 sm:w-4",strokeWidth:2,fill:"none"}),e.jsx("span",{children:"外观"})]}),e.jsxs(is,{value:"security",className:"gap-1 sm:gap-2 text-xs sm:text-sm px-2 sm:px-3 py-2",children:[e.jsx(Dy,{className:"h-3.5 w-3.5 sm:h-4 sm:w-4",strokeWidth:2,fill:"none"}),e.jsx("span",{children:"安全"})]}),e.jsxs(is,{value:"other",className:"gap-1 sm:gap-2 text-xs sm:text-sm px-2 sm:px-3 py-2",children:[e.jsx(ji,{className:"h-3.5 w-3.5 sm:h-4 sm:w-4",strokeWidth:2,fill:"none"}),e.jsx("span",{children:"其他"})]}),e.jsxs(is,{value:"about",className:"gap-1 sm:gap-2 text-xs sm:text-sm px-2 sm:px-3 py-2",children:[e.jsx(Ra,{className:"h-3.5 w-3.5 sm:h-4 sm:w-4",strokeWidth:2,fill:"none"}),e.jsx("span",{children:"关于"})]})]}),e.jsxs(Ze,{className:"h-[calc(100vh-240px)] sm:h-[calc(100vh-280px)] mt-4 sm:mt-6",children:[e.jsx(As,{value:"appearance",className:"mt-0",children:e.jsx(jw,{})}),e.jsx(As,{value:"security",className:"mt-0",children:e.jsx(vw,{})}),e.jsx(As,{value:"other",className:"mt-0",children:e.jsx(bw,{})}),e.jsx(As,{value:"about",className:"mt-0",children:e.jsx(Nw,{})})]})]})]})}function _p(l){const i=document.documentElement,o={blue:{hsl:"221.2 83.2% 53.3%",darkHsl:"217.2 91.2% 59.8%",gradient:null},purple:{hsl:"271 91% 65%",darkHsl:"270 95% 75%",gradient:null},green:{hsl:"142 71% 45%",darkHsl:"142 76% 36%",gradient:null},orange:{hsl:"25 95% 53%",darkHsl:"20 90% 48%",gradient:null},pink:{hsl:"330 81% 60%",darkHsl:"330 85% 70%",gradient:null},red:{hsl:"0 84% 60%",darkHsl:"0 90% 70%",gradient:null},"gradient-sunset":{hsl:"15 95% 60%",darkHsl:"15 95% 65%",gradient:"linear-gradient(135deg, hsl(25 95% 53%) 0%, hsl(330 81% 60%) 100%)"},"gradient-ocean":{hsl:"200 90% 55%",darkHsl:"200 90% 60%",gradient:"linear-gradient(135deg, hsl(221.2 83.2% 53.3%) 0%, hsl(189 94% 43%) 100%)"},"gradient-forest":{hsl:"150 70% 45%",darkHsl:"150 75% 40%",gradient:"linear-gradient(135deg, hsl(142 71% 45%) 0%, hsl(158 64% 52%) 100%)"},"gradient-aurora":{hsl:"310 85% 65%",darkHsl:"310 90% 70%",gradient:"linear-gradient(135deg, hsl(271 91% 65%) 0%, hsl(330 81% 60%) 100%)"},"gradient-fire":{hsl:"15 95% 55%",darkHsl:"15 95% 60%",gradient:"linear-gradient(135deg, hsl(0 84% 60%) 0%, hsl(25 95% 53%) 100%)"},"gradient-twilight":{hsl:"250 90% 60%",darkHsl:"250 95% 65%",gradient:"linear-gradient(135deg, hsl(239 84% 67%) 0%, hsl(271 91% 65%) 100%)"}}[l];if(o)i.style.setProperty("--primary",o.hsl),o.gradient?(i.style.setProperty("--primary-gradient",o.gradient),i.classList.add("has-gradient")):(i.style.removeProperty("--primary-gradient"),i.classList.remove("has-gradient"));else if(l.startsWith("#")){const u=x=>{x=x.replace("#","");const h=parseInt(x.substring(0,2),16)/255,f=parseInt(x.substring(2,4),16)/255,g=parseInt(x.substring(4,6),16)/255,j=Math.max(h,f,g),v=Math.min(h,f,g);let y=0,b=0;const S=(j+v)/2;if(j!==v){const w=j-v;switch(b=S>.5?w/(2-j-v):w/(j+v),j){case h:y=((f-g)/w+(flocalStorage.getItem("accent-color")||"blue");m.useEffect(()=>{const j=localStorage.getItem("accent-color")||"blue";_p(j)},[]);const g=j=>{f(j),localStorage.setItem("accent-color",j),_p(j)};return e.jsxs("div",{className:"space-y-6 sm:space-y-8",children:[e.jsxs("div",{children:[e.jsx("h3",{className:"text-base sm:text-lg font-semibold mb-3 sm:mb-4",children:"主题模式"}),e.jsxs("div",{className:"grid grid-cols-1 sm:grid-cols-3 gap-3 sm:gap-4",children:[e.jsx(Vu,{value:"light",current:l,onChange:i,label:"浅色",description:"始终使用浅色主题"}),e.jsx(Vu,{value:"dark",current:l,onChange:i,label:"深色",description:"始终使用深色主题"}),e.jsx(Vu,{value:"system",current:l,onChange:i,label:"跟随系统",description:"根据系统设置自动切换"})]})]}),e.jsxs("div",{children:[e.jsx("h3",{className:"text-base sm:text-lg font-semibold mb-3 sm:mb-4",children:"主题色"}),e.jsxs("div",{className:"space-y-3 sm:space-y-4",children:[e.jsxs("div",{children:[e.jsx("h4",{className:"text-xs sm:text-sm font-medium mb-2 sm:mb-3",children:"单色"}),e.jsxs("div",{className:"grid grid-cols-3 sm:grid-cols-6 gap-2 sm:gap-3",children:[e.jsx(_a,{value:"blue",current:h,onChange:g,label:"蓝色",colorClass:"bg-blue-500"}),e.jsx(_a,{value:"purple",current:h,onChange:g,label:"紫色",colorClass:"bg-purple-500"}),e.jsx(_a,{value:"green",current:h,onChange:g,label:"绿色",colorClass:"bg-green-500"}),e.jsx(_a,{value:"orange",current:h,onChange:g,label:"橙色",colorClass:"bg-orange-500"}),e.jsx(_a,{value:"pink",current:h,onChange:g,label:"粉色",colorClass:"bg-pink-500"}),e.jsx(_a,{value:"red",current:h,onChange:g,label:"红色",colorClass:"bg-red-500"})]})]}),e.jsxs("div",{children:[e.jsx("h4",{className:"text-xs sm:text-sm font-medium mb-2 sm:mb-3",children:"渐变色"}),e.jsxs("div",{className:"grid grid-cols-3 sm:grid-cols-6 gap-2 sm:gap-3",children:[e.jsx(_a,{value:"gradient-sunset",current:h,onChange:g,label:"日落",colorClass:"bg-gradient-to-r from-orange-500 to-pink-500"}),e.jsx(_a,{value:"gradient-ocean",current:h,onChange:g,label:"海洋",colorClass:"bg-gradient-to-r from-blue-500 to-cyan-500"}),e.jsx(_a,{value:"gradient-forest",current:h,onChange:g,label:"森林",colorClass:"bg-gradient-to-r from-green-500 to-emerald-500"}),e.jsx(_a,{value:"gradient-aurora",current:h,onChange:g,label:"极光",colorClass:"bg-gradient-to-r from-purple-500 to-pink-500"}),e.jsx(_a,{value:"gradient-fire",current:h,onChange:g,label:"烈焰",colorClass:"bg-gradient-to-r from-red-500 to-orange-500"}),e.jsx(_a,{value:"gradient-twilight",current:h,onChange:g,label:"暮光",colorClass:"bg-gradient-to-r from-indigo-500 to-purple-500"})]})]}),e.jsxs("div",{children:[e.jsx("h4",{className:"text-xs sm:text-sm font-medium mb-2 sm:mb-3",children:"自定义颜色"}),e.jsxs("div",{className:"flex flex-col sm:flex-row gap-3 sm:gap-4",children:[e.jsx("div",{className:"flex-1",children:e.jsx("input",{type:"color",value:h.startsWith("#")?h:"#3b82f6",onChange:j=>g(j.target.value),className:"h-10 sm:h-12 w-full rounded-lg border-2 border-border cursor-pointer",title:"选择自定义颜色"})}),e.jsx("div",{className:"flex-1",children:e.jsx(ie,{type:"text",value:h,onChange:j=>g(j.target.value),placeholder:"#3b82f6",className:"font-mono text-sm"})})]}),e.jsx("p",{className:"text-[10px] sm:text-xs text-muted-foreground mt-2",children:"点击色块选择颜色,或手动输入 HEX 颜色代码"})]})]})]}),e.jsxs("div",{children:[e.jsx("h3",{className:"text-base sm:text-lg font-semibold mb-3 sm:mb-4",children:"动画效果"}),e.jsxs("div",{className:"space-y-2 sm:space-y-3",children:[e.jsx("div",{className:"rounded-lg border bg-card p-3 sm:p-4",children:e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"space-y-0.5 flex-1",children:[e.jsx(k,{htmlFor:"animations",className:"text-base font-medium cursor-pointer",children:"启用动画效果"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"关闭后将禁用所有过渡动画和特效,提升性能"})]}),e.jsx(Fe,{id:"animations",checked:r,onCheckedChange:o})]})}),e.jsx("div",{className:"rounded-lg border bg-card p-4",children:e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"space-y-0.5 flex-1",children:[e.jsx(k,{htmlFor:"waves-background",className:"text-base font-medium cursor-pointer",children:"登录页波浪背景"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"关闭后登录页将使用纯色背景,适合低性能设备"})]}),e.jsx(Fe,{id:"waves-background",checked:u,onCheckedChange:x})]})})]})]})]})}function vw(){const l=ka(),[i,r]=m.useState(""),[o,u]=m.useState(""),[x,h]=m.useState(!1),[f,g]=m.useState(!1),[j,v]=m.useState(!1),[y,b]=m.useState(!1),[S,w]=m.useState(!1),[O,A]=m.useState(!1),[D,V]=m.useState(""),[z,_]=m.useState(!1),{toast:T}=Ks(),$=m.useMemo(()=>nw(o),[o]),E=async oe=>{if(!i){T({title:"无法复制",description:"Token 存储在安全 Cookie 中,请重新生成以获取新 Token",variant:"destructive"});return}try{await navigator.clipboard.writeText(oe),w(!0),T({title:"复制成功",description:"Token 已复制到剪贴板"}),setTimeout(()=>w(!1),2e3)}catch{T({title:"复制失败",description:"请手动复制 Token",variant:"destructive"})}},se=async()=>{if(!o.trim()){T({title:"输入错误",description:"请输入新的 Token",variant:"destructive"});return}if(!$.isValid){const oe=$.rules.filter(je=>!je.passed).map(je=>je.label).join(", ");T({title:"格式错误",description:`Token 不符合要求: ${oe}`,variant:"destructive"});return}v(!0);try{const oe=await fetch("/api/webui/auth/update",{method:"POST",headers:{"Content-Type":"application/json"},credentials:"include",body:JSON.stringify({new_token:o.trim()})}),je=await oe.json();oe.ok&&je.success?(u(""),r(o.trim()),T({title:"更新成功",description:"Access Token 已更新,即将跳转到登录页"}),setTimeout(()=>{l({to:"/auth"})},1500)):T({title:"更新失败",description:je.message||"无法更新 Token",variant:"destructive"})}catch(oe){console.error("更新 Token 错误:",oe),T({title:"更新失败",description:"连接服务器失败",variant:"destructive"})}finally{v(!1)}},te=async()=>{b(!0);try{const oe=await fetch("/api/webui/auth/regenerate",{method:"POST",headers:{"Content-Type":"application/json"},credentials:"include"}),je=await oe.json();oe.ok&&je.success?(r(je.token),V(je.token),A(!0),_(!1),T({title:"生成成功",description:"新的 Access Token 已生成,请及时保存"})):T({title:"生成失败",description:je.message||"无法生成新 Token",variant:"destructive"})}catch(oe){console.error("生成 Token 错误:",oe),T({title:"生成失败",description:"连接服务器失败",variant:"destructive"})}finally{b(!1)}},ne=async()=>{try{await navigator.clipboard.writeText(D),_(!0),T({title:"复制成功",description:"Token 已复制到剪贴板"})}catch{T({title:"复制失败",description:"请手动复制 Token",variant:"destructive"})}},ue=()=>{A(!1),setTimeout(()=>{V(""),_(!1)},300),setTimeout(()=>{l({to:"/auth"})},500)},Se=oe=>{oe||ue()};return e.jsxs("div",{className:"space-y-4 sm:space-y-6",children:[e.jsx(Qs,{open:O,onOpenChange:Se,children:e.jsxs(qs,{className:"sm:max-w-md",children:[e.jsxs(Gs,{children:[e.jsxs(Vs,{className:"flex items-center gap-2",children:[e.jsx(Oa,{className:"h-5 w-5 text-yellow-500"}),"新的 Access Token"]}),e.jsx(Ws,{children:"这是您的新 Token,请立即保存。关闭此窗口后将跳转到登录页面。"})]}),e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"rounded-lg border-2 border-primary/20 bg-primary/5 p-4",children:[e.jsx(k,{className:"text-xs text-muted-foreground mb-2 block",children:"您的新 Token (64位安全令牌)"}),e.jsx("div",{className:"font-mono text-sm break-all select-all bg-background p-3 rounded border",children:D})]}),e.jsx("div",{className:"rounded-lg border border-yellow-200 dark:border-yellow-900 bg-yellow-50 dark:bg-yellow-950/30 p-3",children:e.jsxs("div",{className:"flex gap-2",children:[e.jsx(Oa,{className:"h-4 w-4 text-yellow-600 dark:text-yellow-500 flex-shrink-0 mt-0.5"}),e.jsxs("div",{className:"text-sm text-yellow-800 dark:text-yellow-300 space-y-1",children:[e.jsx("p",{className:"font-semibold",children:"重要提示"}),e.jsxs("ul",{className:"list-disc list-inside space-y-0.5 text-xs",children:[e.jsx("li",{children:"此 Token 仅显示一次,关闭后无法再查看"}),e.jsx("li",{children:"请立即复制并保存到安全的位置"}),e.jsx("li",{children:"关闭窗口后将自动跳转到登录页面"}),e.jsx("li",{children:"请使用新 Token 重新登录系统"})]})]})]})})]}),e.jsxs(at,{className:"gap-2 sm:gap-0",children:[e.jsx(C,{variant:"outline",onClick:ne,className:"gap-2",children:z?e.jsxs(e.Fragment,{children:[e.jsx(ea,{className:"h-4 w-4 text-green-500"}),"已复制"]}):e.jsxs(e.Fragment,{children:[e.jsx(co,{className:"h-4 w-4"}),"复制 Token"]})}),e.jsx(C,{onClick:ue,children:"我已保存,关闭"})]})]})}),e.jsxs("div",{className:"rounded-lg border bg-card p-4 sm:p-6",children:[e.jsx("h3",{className:"text-base sm:text-lg font-semibold mb-3 sm:mb-4",children:"当前 Access Token"}),e.jsx("div",{className:"space-y-3 sm:space-y-4",children:e.jsxs("div",{className:"space-y-2",children:[e.jsx(k,{htmlFor:"current-token",className:"text-sm",children:"您的访问令牌"}),e.jsxs("div",{className:"flex flex-col sm:flex-row gap-2",children:[e.jsxs("div",{className:"relative flex-1",children:[e.jsx(ie,{id:"current-token",type:x?"text":"password",value:i||"••••••••••••••••••••••••••••••••",readOnly:!0,className:"pr-10 font-mono text-sm",placeholder:"Token 存储在安全 Cookie 中"}),e.jsx("button",{onClick:()=>{i?h(!x):T({title:"无法查看",description:'Token 存储在安全 Cookie 中,如需新 Token 请点击"重新生成"'})},className:"absolute right-2 top-1/2 -translate-y-1/2 p-1.5 hover:bg-accent rounded",title:x?"隐藏":"显示",children:x?e.jsx(wr,{className:"h-4 w-4 text-muted-foreground"}):e.jsx(Gt,{className:"h-4 w-4 text-muted-foreground"})})]}),e.jsxs("div",{className:"flex gap-2 w-full sm:w-auto",children:[e.jsx(C,{variant:"outline",size:"icon",onClick:()=>E(i),title:"复制到剪贴板",className:"flex-shrink-0",disabled:!i,children:S?e.jsx(ea,{className:"h-4 w-4 text-green-500"}):e.jsx(co,{className:"h-4 w-4"})}),e.jsxs(js,{children:[e.jsx(mt,{asChild:!0,children:e.jsxs(C,{variant:"outline",disabled:y,className:"gap-2 flex-1 sm:flex-none",children:[e.jsx(At,{className:H("h-4 w-4",y&&"animate-spin")}),e.jsx("span",{className:"hidden sm:inline",children:"重新生成"}),e.jsx("span",{className:"sm:hidden",children:"生成"})]})}),e.jsxs(os,{children:[e.jsxs(ds,{children:[e.jsx(ms,{children:"确认重新生成 Token"}),e.jsx(xs,{children:"这将生成一个新的 64 位安全令牌,并使当前 Token 立即失效。 您需要使用新 Token 重新登录系统。此操作不可撤销,确定要继续吗?"})]}),e.jsxs(us,{children:[e.jsx(fs,{children:"取消"}),e.jsx(hs,{onClick:te,children:"确认生成"})]})]})]})]})]}),e.jsx("p",{className:"text-[10px] sm:text-xs text-muted-foreground",children:"请妥善保管您的 Access Token,不要泄露给他人"})]})})]}),e.jsxs("div",{className:"rounded-lg border bg-card p-4 sm:p-6",children:[e.jsx("h3",{className:"text-base sm:text-lg font-semibold mb-3 sm:mb-4",children:"自定义 Access Token"}),e.jsxs("div",{className:"space-y-3 sm:space-y-4",children:[e.jsxs("div",{className:"space-y-2",children:[e.jsx(k,{htmlFor:"new-token",className:"text-sm",children:"新的访问令牌"}),e.jsxs("div",{className:"relative",children:[e.jsx(ie,{id:"new-token",type:f?"text":"password",value:o,onChange:oe=>u(oe.target.value),className:"pr-10 font-mono text-sm",placeholder:"输入自定义 Token"}),e.jsx("button",{onClick:()=>g(!f),className:"absolute right-2 top-1/2 -translate-y-1/2 p-1.5 hover:bg-accent rounded",title:f?"隐藏":"显示",children:f?e.jsx(wr,{className:"h-4 w-4 text-muted-foreground"}):e.jsx(Gt,{className:"h-4 w-4 text-muted-foreground"})})]}),o&&e.jsxs("div",{className:"mt-3 space-y-2 p-3 rounded-lg bg-muted/50",children:[e.jsx("p",{className:"text-sm font-medium text-foreground",children:"Token 安全要求:"}),e.jsx("div",{className:"space-y-1.5",children:$.rules.map(oe=>e.jsxs("div",{className:"flex items-center gap-2 text-sm",children:[oe.passed?e.jsx(aa,{className:"h-4 w-4 text-green-500 flex-shrink-0"}):e.jsx(Mg,{className:"h-4 w-4 text-muted-foreground flex-shrink-0"}),e.jsx("span",{className:H(oe.passed?"text-green-600 dark:text-green-400":"text-muted-foreground"),children:oe.label})]},oe.id))}),$.isValid&&e.jsx("div",{className:"mt-2 pt-2 border-t border-border",children:e.jsxs("div",{className:"flex items-center gap-2 text-sm text-green-600 dark:text-green-400",children:[e.jsx(ea,{className:"h-4 w-4"}),e.jsx("span",{className:"font-medium",children:"Token 格式正确,可以使用"})]})})]})]}),e.jsx(C,{onClick:se,disabled:j||!$.isValid||!o,className:"w-full sm:w-auto",children:j?"更新中...":"更新自定义 Token"})]})]}),e.jsxs("div",{className:"rounded-lg border border-yellow-200 dark:border-yellow-900 bg-yellow-50 dark:bg-yellow-950/30 p-3 sm:p-4",children:[e.jsx("h4",{className:"text-sm sm:text-base font-semibold text-yellow-900 dark:text-yellow-200 mb-2",children:"安全提示"}),e.jsxs("ul",{className:"text-xs sm:text-sm text-yellow-800 dark:text-yellow-300 space-y-1 list-disc list-inside",children:[e.jsx("li",{children:"重新生成 Token 会创建系统随机生成的 64 位安全令牌"}),e.jsx("li",{children:"自定义 Token 必须满足所有安全要求才能使用"}),e.jsx("li",{children:"更新 Token 后,旧的 Token 将立即失效"}),e.jsx("li",{children:"请在安全的环境下查看和复制 Token"}),e.jsx("li",{children:"如果怀疑 Token 泄露,请立即重新生成或更新"}),e.jsx("li",{children:"建议使用系统生成的 Token 以获得最高安全性"})]})]})]})}function bw(){const l=ka(),{toast:i}=Ks(),[r,o]=m.useState(!1),[u,x]=m.useState(!1),[h,f]=m.useState(()=>dt("logCacheSize")),[g,j]=m.useState(()=>dt("wsReconnectInterval")),[v,y]=m.useState(()=>dt("wsMaxReconnectAttempts")),[b,S]=m.useState(()=>dt("dataSyncInterval")),[w,O]=m.useState(()=>wp()),[A,D]=m.useState(!1),[V,z]=m.useState(!1),_=m.useRef(null);if(u)throw new Error("这是一个手动触发的测试错误,用于验证错误边界组件是否正常工作。");const T=()=>{O(wp())},$=U=>{const P=U[0];f(P),ui("logCacheSize",P)},E=U=>{const P=U[0];j(P),ui("wsReconnectInterval",P)},se=U=>{const P=U[0];y(P),ui("wsMaxReconnectAttempts",P)},te=U=>{const P=U[0];S(P),ui("dataSyncInterval",P)},ne=()=>{xn.clearLogs(),i({title:"日志已清除",description:"日志缓存已清空"})},ue=()=>{const U=mw();T(),i({title:"缓存已清除",description:`已清除 ${U.clearedKeys.length} 项缓存数据`})},Se=()=>{D(!0);try{const U=ow(),P=JSON.stringify(U,null,2),X=new Blob([P],{type:"application/json"}),L=URL.createObjectURL(X),B=document.createElement("a");B.href=L,B.download=`maibot-webui-settings-${new Date().toISOString().slice(0,10)}.json`,document.body.appendChild(B),B.click(),document.body.removeChild(B),URL.revokeObjectURL(L),i({title:"导出成功",description:"设置已导出为 JSON 文件"})}catch(U){console.error("导出设置失败:",U),i({title:"导出失败",description:"无法导出设置",variant:"destructive"})}finally{D(!1)}},oe=U=>{const P=U.target.files?.[0];if(!P)return;z(!0);const X=new FileReader;X.onload=L=>{try{const B=L.target?.result,_e=JSON.parse(B),Ne=dw(_e);Ne.success?(f(dt("logCacheSize")),j(dt("wsReconnectInterval")),y(dt("wsMaxReconnectAttempts")),S(dt("dataSyncInterval")),T(),i({title:"导入成功",description:`成功导入 ${Ne.imported.length} 项设置${Ne.skipped.length>0?`,跳过 ${Ne.skipped.length} 项`:""}`}),(Ne.imported.includes("theme")||Ne.imported.includes("accentColor"))&&i({title:"提示",description:"部分设置需要刷新页面才能完全生效"})):i({title:"导入失败",description:"没有有效的设置项可导入",variant:"destructive"})}catch(B){console.error("导入设置失败:",B),i({title:"导入失败",description:"文件格式无效",variant:"destructive"})}finally{z(!1),_.current&&(_.current.value="")}},X.readAsText(P)},je=()=>{uw(),f(Va.logCacheSize),j(Va.wsReconnectInterval),y(Va.wsMaxReconnectAttempts),S(Va.dataSyncInterval),T(),i({title:"已重置",description:"所有设置已恢复为默认值,刷新页面以应用更改"})},be=async()=>{o(!0);try{const U=await we("/api/webui/setup/reset",{method:"POST"}),P=await U.json();U.ok&&P.success?(i({title:"重置成功",description:"即将进入初次配置向导"}),setTimeout(()=>{l({to:"/setup"})},1e3)):i({title:"重置失败",description:P.message||"无法重置配置状态",variant:"destructive"})}catch(U){console.error("重置配置状态错误:",U),i({title:"重置失败",description:"连接服务器失败",variant:"destructive"})}finally{o(!1)}};return e.jsxs("div",{className:"space-y-4 sm:space-y-6",children:[e.jsxs("div",{className:"rounded-lg border bg-card p-4 sm:p-6",children:[e.jsxs("h3",{className:"text-base sm:text-lg font-semibold mb-3 sm:mb-4 flex items-center gap-2",children:[e.jsx(ro,{className:"h-5 w-5"}),"性能与存储"]}),e.jsxs("div",{className:"space-y-4 sm:space-y-5",children:[e.jsxs("div",{className:"rounded-lg bg-muted/50 p-3 sm:p-4",children:[e.jsxs("div",{className:"flex items-center justify-between mb-2",children:[e.jsxs("span",{className:"text-sm font-medium flex items-center gap-2",children:[e.jsx(Ry,{className:"h-4 w-4"}),"本地存储使用"]}),e.jsx(C,{variant:"ghost",size:"sm",onClick:T,className:"h-7 px-2",children:e.jsx(At,{className:"h-3 w-3"})})]}),e.jsx("div",{className:"text-2xl font-bold text-primary",children:xw(w.used)}),e.jsxs("p",{className:"text-xs text-muted-foreground mt-1",children:[w.items," 个存储项"]})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(k,{className:"text-sm font-medium",children:"日志缓存大小"}),e.jsxs("span",{className:"text-sm text-muted-foreground",children:[h," 条"]})]}),e.jsx(ma,{value:[h],onValueChange:$,min:100,max:5e3,step:100,className:"w-full"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"控制日志查看器最多缓存的日志条数,较大的值会占用更多内存"})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(k,{className:"text-sm font-medium",children:"首页数据刷新间隔"}),e.jsxs("span",{className:"text-sm text-muted-foreground",children:[b," 秒"]})]}),e.jsx(ma,{value:[b],onValueChange:te,min:10,max:120,step:5,className:"w-full"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"控制首页统计数据的自动刷新间隔"})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(k,{className:"text-sm font-medium",children:"WebSocket 重连间隔"}),e.jsxs("span",{className:"text-sm text-muted-foreground",children:[g/1e3," 秒"]})]}),e.jsx(ma,{value:[g],onValueChange:E,min:1e3,max:1e4,step:500,className:"w-full"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"日志 WebSocket 连接断开后的重连基础间隔"})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(k,{className:"text-sm font-medium",children:"WebSocket 最大重连次数"}),e.jsxs("span",{className:"text-sm text-muted-foreground",children:[v," 次"]})]}),e.jsx(ma,{value:[v],onValueChange:se,min:3,max:30,step:1,className:"w-full"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"连接失败后的最大重连尝试次数"})]}),e.jsxs("div",{className:"flex flex-wrap gap-2 pt-2",children:[e.jsxs(C,{variant:"outline",size:"sm",onClick:ne,className:"gap-2",children:[e.jsx(es,{className:"h-4 w-4"}),"清除日志缓存"]}),e.jsxs(js,{children:[e.jsx(mt,{asChild:!0,children:e.jsxs(C,{variant:"outline",size:"sm",className:"gap-2",children:[e.jsx(es,{className:"h-4 w-4"}),"清除本地缓存"]})}),e.jsxs(os,{children:[e.jsxs(ds,{children:[e.jsx(ms,{children:"确认清除本地缓存"}),e.jsx(xs,{children:"这将清除所有本地缓存的设置和数据(不包括登录凭证)。 您可能需要重新配置部分偏好设置。确定要继续吗?"})]}),e.jsxs(us,{children:[e.jsx(fs,{children:"取消"}),e.jsx(hs,{onClick:ue,children:"确认清除"})]})]})]})]})]})]}),e.jsxs("div",{className:"rounded-lg border bg-card p-4 sm:p-6",children:[e.jsxs("h3",{className:"text-base sm:text-lg font-semibold mb-3 sm:mb-4 flex items-center gap-2",children:[e.jsx(Da,{className:"h-5 w-5"}),"导入/导出设置"]}),e.jsxs("div",{className:"space-y-4",children:[e.jsx("p",{className:"text-xs sm:text-sm text-muted-foreground",children:"导出当前的界面设置以便备份,或从之前导出的文件中恢复设置。"}),e.jsxs("div",{className:"flex flex-wrap gap-2",children:[e.jsxs(C,{variant:"outline",onClick:Se,disabled:A,className:"gap-2",children:[e.jsx(Da,{className:"h-4 w-4"}),A?"导出中...":"导出设置"]}),e.jsx("input",{ref:_,type:"file",accept:".json",onChange:oe,className:"hidden"}),e.jsxs(C,{variant:"outline",onClick:()=>_.current?.click(),disabled:V,className:"gap-2",children:[e.jsx(_r,{className:"h-4 w-4"}),V?"导入中...":"导入设置"]})]}),e.jsx("div",{className:"pt-2 border-t",children:e.jsxs(js,{children:[e.jsx(mt,{asChild:!0,children:e.jsxs(C,{variant:"outline",size:"sm",className:"gap-2 text-destructive hover:text-destructive",children:[e.jsx(yr,{className:"h-4 w-4"}),"重置所有设置为默认值"]})}),e.jsxs(os,{children:[e.jsxs(ds,{children:[e.jsx(ms,{children:"确认重置所有设置"}),e.jsx(xs,{children:"这将把所有界面设置恢复为默认值,包括主题、颜色、动画等偏好设置。 此操作不会影响您的登录状态。确定要继续吗?"})]}),e.jsxs(us,{children:[e.jsx(fs,{children:"取消"}),e.jsx(hs,{onClick:je,children:"确认重置"})]})]})]})})]})]}),e.jsxs("div",{className:"rounded-lg border bg-card p-4 sm:p-6",children:[e.jsx("h3",{className:"text-base sm:text-lg font-semibold mb-3 sm:mb-4",children:"配置向导"}),e.jsxs("div",{className:"space-y-3 sm:space-y-4",children:[e.jsx("div",{className:"space-y-2",children:e.jsx("p",{className:"text-xs sm:text-sm text-muted-foreground",children:"重新进行初次配置向导,可以帮助您重新设置系统的基础配置。"})}),e.jsxs(js,{children:[e.jsx(mt,{asChild:!0,children:e.jsxs(C,{variant:"outline",disabled:r,className:"gap-2",children:[e.jsx(yr,{className:H("h-4 w-4",r&&"animate-spin")}),"重新进行初次配置"]})}),e.jsxs(os,{children:[e.jsxs(ds,{children:[e.jsx(ms,{children:"确认重新配置"}),e.jsx(xs,{children:"这将带您重新进入初次配置向导。您可以重新设置系统的基础配置项。确定要继续吗?"})]}),e.jsxs(us,{children:[e.jsx(fs,{children:"取消"}),e.jsx(hs,{onClick:be,children:"确认重置"})]})]})]})]})]}),e.jsxs("div",{className:"rounded-lg border border-dashed border-yellow-500/50 bg-yellow-500/5 p-4 sm:p-6",children:[e.jsxs("h3",{className:"text-base sm:text-lg font-semibold mb-3 sm:mb-4 flex items-center gap-2",children:[e.jsx(Oa,{className:"h-5 w-5 text-yellow-500"}),"开发者工具"]}),e.jsxs("div",{className:"space-y-3 sm:space-y-4",children:[e.jsx("div",{className:"space-y-2",children:e.jsx("p",{className:"text-xs sm:text-sm text-muted-foreground",children:"以下功能仅供开发调试使用,可能会导致页面崩溃或异常。"})}),e.jsxs(js,{children:[e.jsx(mt,{asChild:!0,children:e.jsxs(C,{variant:"destructive",className:"gap-2",children:[e.jsx(Oa,{className:"h-4 w-4"}),"触发测试错误"]})}),e.jsxs(os,{children:[e.jsxs(ds,{children:[e.jsx(ms,{children:"确认触发错误"}),e.jsx(xs,{children:"这将手动触发一个 React 错误,用于测试错误边界组件的显示效果。 页面将显示错误界面,您可以通过刷新页面或点击返回首页来恢复。"})]}),e.jsxs(us,{children:[e.jsx(fs,{children:"取消"}),e.jsx(hs,{onClick:()=>x(!0),className:"bg-destructive text-destructive-foreground hover:bg-destructive/90",children:"确认触发"})]})]})]})]})]})]})}function Nw(){return e.jsxs("div",{className:"space-y-4 sm:space-y-6",children:[e.jsx("div",{className:"rounded-lg border-2 border-primary/30 bg-gradient-to-r from-primary/5 to-primary/10 p-4 sm:p-6",children:e.jsxs("div",{className:"flex items-start gap-3 sm:gap-4",children:[e.jsx("div",{className:"flex-shrink-0 rounded-lg bg-primary/10 p-2 sm:p-3",children:e.jsx("svg",{className:"h-6 w-6 sm:h-8 sm:w-8 text-primary",fill:"currentColor",viewBox:"0 0 24 24","aria-hidden":"true",children:e.jsx("path",{fillRule:"evenodd",d:"M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z",clipRule:"evenodd"})})}),e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsx("h3",{className:"text-lg sm:text-xl font-bold text-foreground mb-2",children:"开源项目"}),e.jsx("p",{className:"text-sm sm:text-base text-muted-foreground mb-3",children:"本项目在 GitHub 开源,欢迎 Star ⭐ 支持!"}),e.jsxs("a",{href:"https://github.com/Mai-with-u/MaiBot-Dashboard",target:"_blank",rel:"noopener noreferrer",className:H("inline-flex items-center gap-2 px-4 py-2 rounded-lg","bg-primary text-primary-foreground font-medium text-sm","hover:bg-primary/90 transition-colors","focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"),children:[e.jsx("svg",{className:"h-4 w-4",fill:"currentColor",viewBox:"0 0 24 24","aria-hidden":"true",children:e.jsx("path",{fillRule:"evenodd",d:"M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z",clipRule:"evenodd"})}),"前往 GitHub",e.jsx("svg",{className:"h-4 w-4",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",children:e.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"})})]})]})]})}),e.jsxs("div",{className:"rounded-lg border bg-card p-4 sm:p-6",children:[e.jsxs("h3",{className:"text-base sm:text-lg font-semibold mb-3 sm:mb-4",children:["关于 ",um]}),e.jsxs("div",{className:"space-y-2 text-xs sm:text-sm text-muted-foreground",children:[e.jsxs("p",{children:["版本: ",go]}),e.jsx("p",{children:"麦麦(MaiBot)的现代化 Web 管理界面"})]})]}),e.jsxs("div",{className:"rounded-lg border bg-card p-4 sm:p-6",children:[e.jsx("h3",{className:"text-base sm:text-lg font-semibold mb-3 sm:mb-4",children:"作者"}),e.jsxs("div",{className:"space-y-3",children:[e.jsxs("div",{className:"space-y-1",children:[e.jsx("p",{className:"text-sm font-medium",children:"MaiBot 核心"}),e.jsx("p",{className:"text-xs sm:text-sm text-muted-foreground",children:"Mai-with-u"})]}),e.jsxs("div",{className:"space-y-1",children:[e.jsx("p",{className:"text-sm font-medium",children:"WebUI"}),e.jsxs("p",{className:"text-xs sm:text-sm text-muted-foreground",children:["Mai-with-u ",e.jsx("a",{href:"https://github.com/DrSmoothl",target:"_blank",rel:"noopener noreferrer",className:"text-primary underline",children:"@MotricSeven"})]})]})]})]}),e.jsxs("div",{className:"rounded-lg border bg-card p-4 sm:p-6",children:[e.jsx("h3",{className:"text-base sm:text-lg font-semibold mb-3 sm:mb-4",children:"技术栈"}),e.jsxs("div",{className:"grid grid-cols-1 sm:grid-cols-2 gap-3 text-xs sm:text-sm text-muted-foreground",children:[e.jsxs("div",{className:"space-y-1.5",children:[e.jsx("p",{className:"font-medium text-foreground",children:"前端框架"}),e.jsxs("ul",{className:"space-y-0.5 list-disc list-inside",children:[e.jsx("li",{children:"React 19.2.0"}),e.jsx("li",{children:"TypeScript 5.7.2"}),e.jsx("li",{children:"Vite 6.0.7"}),e.jsx("li",{children:"TanStack Router 1.94.2"})]})]}),e.jsxs("div",{className:"space-y-1.5",children:[e.jsx("p",{className:"font-medium text-foreground",children:"UI 组件"}),e.jsxs("ul",{className:"space-y-0.5 list-disc list-inside",children:[e.jsx("li",{children:"shadcn/ui"}),e.jsx("li",{children:"Radix UI"}),e.jsx("li",{children:"Tailwind CSS 3.4.17"}),e.jsx("li",{children:"Lucide Icons"})]})]}),e.jsxs("div",{className:"space-y-1.5",children:[e.jsx("p",{className:"font-medium text-foreground",children:"后端"}),e.jsxs("ul",{className:"space-y-0.5 list-disc list-inside",children:[e.jsx("li",{children:"Python 3.12+"}),e.jsx("li",{children:"FastAPI"}),e.jsx("li",{children:"Uvicorn"}),e.jsx("li",{children:"WebSocket"})]})]}),e.jsxs("div",{className:"space-y-1.5",children:[e.jsx("p",{className:"font-medium text-foreground",children:"构建工具"}),e.jsxs("ul",{className:"space-y-0.5 list-disc list-inside",children:[e.jsx("li",{children:"Bun / npm"}),e.jsx("li",{children:"ESLint 9.17.0"}),e.jsx("li",{children:"PostCSS"})]})]})]})]}),e.jsxs("div",{className:"rounded-lg border bg-card p-4 sm:p-6",children:[e.jsx("h3",{className:"text-base sm:text-lg font-semibold mb-3 sm:mb-4",children:"开源库感谢"}),e.jsx("p",{className:"text-xs sm:text-sm text-muted-foreground mb-3",children:"本项目使用了以下优秀的开源库,感谢他们的贡献:"}),e.jsx(Ze,{className:"h-[300px] sm:h-[400px]",children:e.jsxs("div",{className:"space-y-4 pr-4",children:[e.jsxs("div",{className:"space-y-2",children:[e.jsx("p",{className:"text-sm font-medium text-foreground",children:"UI 框架与组件"}),e.jsxs("div",{className:"grid gap-2 text-xs sm:text-sm",children:[e.jsx(et,{name:"React",description:"用户界面构建库",license:"MIT"}),e.jsx(et,{name:"shadcn/ui",description:"优雅的 React 组件库",license:"MIT"}),e.jsx(et,{name:"Radix UI",description:"无样式的可访问组件库",license:"MIT"}),e.jsx(et,{name:"Tailwind CSS",description:"实用优先的 CSS 框架",license:"MIT"}),e.jsx(et,{name:"Lucide React",description:"精美的图标库",license:"ISC"})]})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx("p",{className:"text-sm font-medium text-foreground",children:"路由与状态管理"}),e.jsxs("div",{className:"grid gap-2 text-xs sm:text-sm",children:[e.jsx(et,{name:"TanStack Router",description:"类型安全的路由库",license:"MIT"}),e.jsx(et,{name:"Zustand",description:"轻量级状态管理",license:"MIT"})]})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx("p",{className:"text-sm font-medium text-foreground",children:"表单处理"}),e.jsxs("div",{className:"grid gap-2 text-xs sm:text-sm",children:[e.jsx(et,{name:"React Hook Form",description:"高性能表单库",license:"MIT"}),e.jsx(et,{name:"Zod",description:"TypeScript 优先的 schema 验证",license:"MIT"})]})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx("p",{className:"text-sm font-medium text-foreground",children:"工具库"}),e.jsxs("div",{className:"grid gap-2 text-xs sm:text-sm",children:[e.jsx(et,{name:"clsx",description:"条件 className 构建工具",license:"MIT"}),e.jsx(et,{name:"tailwind-merge",description:"Tailwind 类名合并工具",license:"MIT"}),e.jsx(et,{name:"class-variance-authority",description:"组件变体管理",license:"Apache-2.0"}),e.jsx(et,{name:"date-fns",description:"现代化日期处理库",license:"MIT"})]})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx("p",{className:"text-sm font-medium text-foreground",children:"动画效果"}),e.jsxs("div",{className:"grid gap-2 text-xs sm:text-sm",children:[e.jsx(et,{name:"Framer Motion",description:"React 动画库",license:"MIT"}),e.jsx(et,{name:"vaul",description:"抽屉组件动画",license:"MIT"})]})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx("p",{className:"text-sm font-medium text-foreground",children:"后端框架"}),e.jsxs("div",{className:"grid gap-2 text-xs sm:text-sm",children:[e.jsx(et,{name:"FastAPI",description:"现代化 Python Web 框架",license:"MIT"}),e.jsx(et,{name:"Uvicorn",description:"ASGI 服务器",license:"BSD-3-Clause"}),e.jsx(et,{name:"Pydantic",description:"数据验证库",license:"MIT"}),e.jsx(et,{name:"python-multipart",description:"文件上传支持",license:"Apache-2.0"})]})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx("p",{className:"text-sm font-medium text-foreground",children:"开发工具"}),e.jsxs("div",{className:"grid gap-2 text-xs sm:text-sm",children:[e.jsx(et,{name:"TypeScript",description:"JavaScript 的超集",license:"Apache-2.0"}),e.jsx(et,{name:"Vite",description:"下一代前端构建工具",license:"MIT"}),e.jsx(et,{name:"ESLint",description:"JavaScript 代码检查工具",license:"MIT"}),e.jsx(et,{name:"PostCSS",description:"CSS 转换工具",license:"MIT"})]})]})]})})]}),e.jsxs("div",{className:"rounded-lg border bg-card p-4 sm:p-6",children:[e.jsx("h3",{className:"text-base sm:text-lg font-semibold mb-3 sm:mb-4",children:"开源许可"}),e.jsxs("div",{className:"space-y-3",children:[e.jsx("div",{className:"rounded-lg bg-primary/5 border border-primary/20 p-3 sm:p-4",children:e.jsxs("div",{className:"flex items-start gap-2 sm:gap-3",children:[e.jsx("div",{className:"flex-shrink-0 mt-0.5",children:e.jsx("div",{className:"rounded-md bg-primary/10 px-2 py-1",children:e.jsx("span",{className:"text-xs sm:text-sm font-bold text-primary",children:"GPLv3"})})}),e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsx("p",{className:"text-sm sm:text-base font-semibold text-foreground mb-1",children:"MaiBot WebUI"}),e.jsx("p",{className:"text-xs sm:text-sm text-muted-foreground",children:"本项目采用 GNU General Public License v3.0 开源许可证。 您可以自由地使用、修改和分发本软件,但必须保持相同的开源许可。"})]})]})}),e.jsx("p",{className:"text-xs sm:text-sm text-muted-foreground",children:"本项目依赖的所有开源库均遵循各自的开源许可证(MIT、Apache-2.0、BSD 等)。 感谢所有开源贡献者的无私奉献。"})]})]})]})}function et({name:l,description:i,license:r}){return e.jsxs("div",{className:"flex items-start justify-between gap-2 rounded-lg border bg-muted/30 p-2.5 sm:p-3",children:[e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsx("p",{className:"font-medium text-foreground truncate",children:l}),e.jsx("p",{className:"text-muted-foreground text-xs mt-0.5",children:i})]}),e.jsx("span",{className:"inline-flex items-center rounded-full bg-primary/10 px-2 py-0.5 text-[10px] font-medium text-primary flex-shrink-0",children:r})]})}function Vu({value:l,current:i,onChange:r,label:o,description:u}){const x=i===l;return e.jsxs("button",{onClick:()=>r(l),className:H("relative rounded-lg border-2 p-3 sm:p-4 text-left transition-all","hover:border-primary/50 hover:bg-accent/50",x?"border-primary bg-accent":"border-border"),children:[x&&e.jsx("div",{className:"absolute top-2 right-2 sm:top-3 sm:right-3 h-2 w-2 rounded-full bg-primary"}),e.jsxs("div",{className:"space-y-1",children:[e.jsx("div",{className:"text-sm sm:text-base font-medium",children:o}),e.jsx("div",{className:"text-[10px] sm:text-xs text-muted-foreground",children:u})]}),e.jsxs("div",{className:"mt-2 sm:mt-3 flex gap-1",children:[l==="light"&&e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"h-2 w-2 rounded-full bg-slate-200"}),e.jsx("div",{className:"h-2 w-2 rounded-full bg-slate-300"}),e.jsx("div",{className:"h-2 w-2 rounded-full bg-slate-400"})]}),l==="dark"&&e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"h-2 w-2 rounded-full bg-slate-700"}),e.jsx("div",{className:"h-2 w-2 rounded-full bg-slate-800"}),e.jsx("div",{className:"h-2 w-2 rounded-full bg-slate-900"})]}),l==="system"&&e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"h-2 w-2 rounded-full bg-gradient-to-r from-slate-200 to-slate-700"}),e.jsx("div",{className:"h-2 w-2 rounded-full bg-gradient-to-r from-slate-300 to-slate-800"}),e.jsx("div",{className:"h-2 w-2 rounded-full bg-gradient-to-r from-slate-400 to-slate-900"})]})]})]})}function _a({value:l,current:i,onChange:r,label:o,colorClass:u}){const x=i===l;return e.jsxs("button",{onClick:()=>r(l),className:H("relative rounded-lg border-2 p-2 sm:p-3 text-left transition-all","hover:border-primary/50 hover:bg-accent/50",x?"border-primary bg-accent":"border-border"),children:[x&&e.jsx("div",{className:"absolute top-1.5 right-1.5 sm:top-2 sm:right-2 h-1.5 w-1.5 sm:h-2 sm:w-2 rounded-full bg-primary"}),e.jsxs("div",{className:"flex flex-col items-center gap-1.5 sm:gap-2",children:[e.jsx("div",{className:H("h-8 w-8 sm:h-10 sm:w-10 rounded-full",u)}),e.jsx("div",{className:"text-[10px] sm:text-xs font-medium text-center",children:o})]})]})}class yw{grad3;p;perm;constructor(i=0){this.grad3=[[1,1,0],[-1,1,0],[1,-1,0],[-1,-1,0],[1,0,1],[-1,0,1],[1,0,-1],[-1,0,-1],[0,1,1],[0,-1,1],[0,1,-1],[0,-1,-1]],this.p=[];for(let r=0;r<256;r++)this.p[r]=Math.floor(Math.random()*256);this.perm=[];for(let r=0;r<512;r++)this.perm[r]=this.p[r&255]}dot(i,r,o){return i[0]*r+i[1]*o}mix(i,r,o){return(1-o)*i+o*r}fade(i){return i*i*i*(i*(i*6-15)+10)}perlin2(i,r){const o=Math.floor(i)&255,u=Math.floor(r)&255;i-=Math.floor(i),r-=Math.floor(r);const x=this.fade(i),h=this.fade(r),f=this.perm[o]+u,g=this.perm[f],j=this.perm[f+1],v=this.perm[o+1]+u,y=this.perm[v],b=this.perm[v+1];return this.mix(this.mix(this.dot(this.grad3[g%12],i,r),this.dot(this.grad3[y%12],i-1,r),x),this.mix(this.dot(this.grad3[j%12],i,r-1),this.dot(this.grad3[b%12],i-1,r-1),x),h)}}function Sp(){const l=m.useRef(null),i=m.useRef(null),r=m.useRef(void 0),o=m.useRef({mouse:{x:-10,y:0,lx:0,ly:0,sx:0,sy:0,v:0,vs:0,a:0,set:!1},lines:[],paths:[],noise:new yw(Math.random()),bounding:null});return m.useEffect(()=>{const u=i.current,x=l.current;if(!u||!x)return;const h=o.current,f=()=>{const O=u.getBoundingClientRect();h.bounding=O,x.style.width=`${O.width}px`,x.style.height=`${O.height}px`},g=()=>{if(!h.bounding)return;const{width:O,height:A}=h.bounding;h.lines=[],h.paths.forEach(te=>te.remove()),h.paths=[];const D=10,V=32,z=O+200,_=A+30,T=Math.ceil(z/D),$=Math.ceil(_/V),E=(O-D*T)/2,se=(A-V*$)/2;for(let te=0;te<=T;te++){const ne=[];for(let Se=0;Se<=$;Se++){const oe={x:E+D*te,y:se+V*Se,wave:{x:0,y:0},cursor:{x:0,y:0,vx:0,vy:0}};ne.push(oe)}const ue=document.createElementNS("http://www.w3.org/2000/svg","path");x.appendChild(ue),h.paths.push(ue),h.lines.push(ne)}},j=O=>{const{lines:A,mouse:D,noise:V}=h;A.forEach(z=>{z.forEach(_=>{const T=V.perlin2((_.x+O*.0125)*.002,(_.y+O*.005)*.0015)*12;_.wave.x=Math.cos(T)*32,_.wave.y=Math.sin(T)*16;const $=_.x-D.sx,E=_.y-D.sy,se=Math.hypot($,E),te=Math.max(175,D.vs);if(se{const D={x:O.x+O.wave.x+(A?O.cursor.x:0),y:O.y+O.wave.y+(A?O.cursor.y:0)};return D.x=Math.round(D.x*10)/10,D.y=Math.round(D.y*10)/10,D},y=()=>{const{lines:O,paths:A}=h;O.forEach((D,V)=>{let z=v(D[0],!1),_=`M ${z.x} ${z.y}`;D.forEach((T,$)=>{const E=$===D.length-1;z=v(T,!E),_+=`L ${z.x} ${z.y}`}),A[V].setAttribute("d",_)})},b=O=>{const{mouse:A}=h;A.sx+=(A.x-A.sx)*.1,A.sy+=(A.y-A.sy)*.1;const D=A.x-A.lx,V=A.y-A.ly,z=Math.hypot(D,V);A.v=z,A.vs+=(z-A.vs)*.1,A.vs=Math.min(100,A.vs),A.lx=A.x,A.ly=A.y,A.a=Math.atan2(V,D),u&&(u.style.setProperty("--x",`${A.sx}px`),u.style.setProperty("--y",`${A.sy}px`)),j(O),y(),r.current=requestAnimationFrame(b)},S=O=>{if(!h.bounding)return;const{mouse:A}=h;A.x=O.pageX-h.bounding.left,A.y=O.pageY-h.bounding.top+window.scrollY,A.set||(A.sx=A.x,A.sy=A.y,A.lx=A.x,A.ly=A.y,A.set=!0)},w=()=>{f(),g()};return f(),g(),window.addEventListener("resize",w),window.addEventListener("mousemove",S),r.current=requestAnimationFrame(b),()=>{window.removeEventListener("resize",w),window.removeEventListener("mousemove",S),r.current&&cancelAnimationFrame(r.current)}},[]),e.jsxs("div",{ref:i,className:"waves-background",style:{position:"absolute",top:0,left:0,width:"100%",height:"100%",overflow:"hidden",pointerEvents:"none"},children:[e.jsx("div",{className:"waves-cursor",style:{position:"absolute",top:0,left:0,width:"0.5rem",height:"0.5rem",background:"hsl(var(--primary) / 0.3)",borderRadius:"50%",transform:"translate3d(calc(var(--x, -0.5rem) - 50%), calc(var(--y, 50%) - 50%), 0)",willChange:"transform",pointerEvents:"none"}}),e.jsx("svg",{ref:l,style:{display:"block",width:"100%",height:"100%"},children:e.jsx("style",{children:` + path { + fill: none; + stroke: hsl(var(--primary) / 0.20); + stroke-width: 1px; + } + `})})]})}function ww(){const[l,i]=m.useState(""),[r,o]=m.useState(!1),[u,x]=m.useState(""),[h,f]=m.useState(!0),g=ka(),{enableWavesBackground:j,setEnableWavesBackground:v}=uj(),{theme:y,setTheme:b}=dm();m.useEffect(()=>{(async()=>{try{await om()&&g({to:"/"})}catch{}finally{f(!1)}})()},[g]);const w=y==="system"?window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light":y,O=()=>{b(w==="dark"?"light":"dark")},A=async D=>{if(D.preventDefault(),x(""),!l.trim()){x("请输入 Access Token");return}o(!0);try{const V=await fetch("/api/webui/auth/verify",{method:"POST",headers:{"Content-Type":"application/json"},credentials:"include",body:JSON.stringify({token:l.trim()})}),z=await V.json();V.ok&&z.valid?z.is_first_setup?g({to:"/setup"}):g({to:"/"}):x(z.message||"Token 验证失败,请检查后重试")}catch(V){console.error("Token 验证错误:",V),x("连接服务器失败,请检查网络连接")}finally{o(!1)}};return h?e.jsxs("div",{className:"relative flex min-h-screen items-center justify-center overflow-hidden bg-background p-4",children:[j&&e.jsx(Sp,{}),e.jsx("div",{className:"text-muted-foreground",children:"正在检查登录状态..."})]}):e.jsxs("div",{className:"relative flex min-h-screen items-center justify-center overflow-hidden bg-background p-4",children:[j&&e.jsx(Sp,{}),e.jsxs(Ve,{className:"relative z-10 w-full max-w-md shadow-2xl backdrop-blur-xl bg-card/80 border-border/50",children:[e.jsx("button",{onClick:O,className:"absolute right-4 top-4 rounded-lg p-2 hover:bg-accent transition-colors z-10 text-foreground",title:w==="dark"?"切换到浅色模式":"切换到深色模式",children:w==="dark"?e.jsx(Ag,{className:"h-5 w-5",strokeWidth:2.5,fill:"none"}):e.jsx(Og,{className:"h-5 w-5",strokeWidth:2.5,fill:"none"})}),e.jsxs(rs,{className:"space-y-4 text-center",children:[e.jsx("div",{className:"mx-auto flex h-16 w-16 items-center justify-center rounded-2xl bg-primary/10",children:e.jsx(xp,{className:"h-8 w-8 text-primary",strokeWidth:2,fill:"none"})}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(cs,{className:"text-2xl font-bold",children:"欢迎使用 MaiBot"}),e.jsx(st,{className:"text-base",children:"请输入您的 Access Token 以继续访问系统"})]})]}),e.jsx(gs,{children:e.jsxs("form",{onSubmit:A,className:"space-y-4",children:[e.jsxs("div",{className:"space-y-2",children:[e.jsx(k,{htmlFor:"token",className:"text-sm font-medium",children:"Access Token"}),e.jsxs("div",{className:"relative",children:[e.jsx(Dg,{className:"absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground",strokeWidth:2,fill:"none"}),e.jsx(ie,{id:"token",type:"password",placeholder:"请输入您的 Access Token",value:l,onChange:D=>i(D.target.value),className:H("pl-10",u&&"border-red-500 focus-visible:ring-red-500"),disabled:r,autoFocus:!0,autoComplete:"off"})]})]}),u&&e.jsxs("div",{className:"flex items-center gap-2 rounded-md bg-red-50 p-3 text-sm text-red-600 dark:bg-red-950/50 dark:text-red-400",children:[e.jsx(Ot,{className:"h-4 w-4 flex-shrink-0",strokeWidth:2,fill:"none"}),e.jsx("span",{children:u})]}),e.jsx(C,{type:"submit",className:"w-full",disabled:r,children:r?e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"mr-2 h-4 w-4 animate-spin rounded-full border-2 border-current border-t-transparent"}),"验证中..."]}):"验证并进入"}),e.jsxs(Qs,{children:[e.jsx(mm,{asChild:!0,children:e.jsxs("button",{className:"w-full text-center text-sm text-primary hover:text-primary/80 transition-colors underline-offset-4 hover:underline flex items-center justify-center gap-1",children:[e.jsx(Rg,{className:"h-4 w-4",strokeWidth:2,fill:"none"}),"我没有 Token,我该去哪里获得 Token?"]})}),e.jsxs(qs,{className:"sm:max-w-md",children:[e.jsxs(Gs,{children:[e.jsxs(Vs,{className:"flex items-center gap-2",children:[e.jsx(xp,{className:"h-5 w-5 text-primary",strokeWidth:2,fill:"none"}),"如何获取 Access Token"]}),e.jsx(Ws,{children:"Access Token 是访问 MaiBot WebUI 的唯一凭证,请按以下方式获取"})]}),e.jsxs("div",{className:"space-y-4",children:[e.jsx("div",{className:"rounded-lg border bg-muted/50 p-4 space-y-2",children:e.jsxs("div",{className:"flex items-start gap-3",children:[e.jsx(Ly,{className:"h-5 w-5 text-primary flex-shrink-0 mt-0.5",strokeWidth:2,fill:"none"}),e.jsxs("div",{className:"flex-1 space-y-2",children:[e.jsx("h4",{className:"font-semibold text-sm",children:"方式一:查看启动日志"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"在 MaiBot 启动时,控制台会显示 WebUI Access Token。"}),e.jsxs("div",{className:"rounded bg-background p-2 font-mono text-xs",children:[e.jsx("p",{className:"text-muted-foreground",children:"🔑 WebUI Access Token: abc123..."}),e.jsx("p",{className:"text-muted-foreground",children:"💡 请使用此 Token 登录 WebUI"})]})]})]})}),e.jsx("div",{className:"rounded-lg border bg-muted/50 p-4 space-y-2",children:e.jsxs("div",{className:"flex items-start gap-3",children:[e.jsx(Aa,{className:"h-5 w-5 text-primary flex-shrink-0 mt-0.5",strokeWidth:2,fill:"none"}),e.jsxs("div",{className:"flex-1 space-y-2",children:[e.jsx("h4",{className:"font-semibold text-sm",children:"方式二:查看配置文件"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"Token 保存在项目根目录的配置文件中:"}),e.jsx("div",{className:"rounded bg-background p-2 font-mono text-xs break-all",children:e.jsx("code",{className:"text-primary",children:"data/webui.json"})}),e.jsxs("p",{className:"text-xs text-muted-foreground",children:["打开此文件,复制 ",e.jsx("code",{className:"px-1 py-0.5 bg-background rounded",children:"access_token"})," 字段的值"]})]})]})}),e.jsx("div",{className:"rounded-lg border border-yellow-200 dark:border-yellow-900 bg-yellow-50 dark:bg-yellow-950/30 p-3",children:e.jsxs("div",{className:"flex gap-2",children:[e.jsx(Ot,{className:"h-4 w-4 text-yellow-600 dark:text-yellow-500 flex-shrink-0 mt-0.5",strokeWidth:2,fill:"none"}),e.jsxs("div",{className:"text-sm text-yellow-800 dark:text-yellow-300 space-y-1",children:[e.jsx("p",{className:"font-semibold",children:"安全提示"}),e.jsxs("ul",{className:"list-disc list-inside space-y-0.5 text-xs",children:[e.jsx("li",{children:"请妥善保管您的 Token,不要泄露给他人"}),e.jsx("li",{children:"如需重置 Token,请在登录后前往系统设置"})]})]})]})})]})]})]}),e.jsxs(js,{children:[e.jsx(mt,{asChild:!0,children:e.jsxs("button",{className:"w-full text-center text-sm text-muted-foreground hover:text-foreground transition-colors underline-offset-4 hover:underline flex items-center justify-center gap-1",children:[e.jsx(hn,{className:"h-4 w-4",strokeWidth:2,fill:"none"}),"我觉得这个界面很卡怎么办?"]})}),e.jsxs(os,{children:[e.jsxs(ds,{children:[e.jsxs(ms,{className:"flex items-center gap-2",children:[e.jsx(hn,{className:"h-5 w-5 text-primary",strokeWidth:2,fill:"none"}),"关闭背景动画"]}),e.jsx(xs,{children:"背景动画可能会在低性能设备上造成卡顿。关闭动画可以显著提升界面流畅度。"})]}),e.jsx("div",{className:"rounded-lg border bg-muted/50 p-4 space-y-2",children:e.jsx("p",{className:"text-sm text-muted-foreground",children:"关闭动画后,背景将变为纯色,但不影响任何功能的使用。您可以随时在系统设置中重新开启动画。"})}),e.jsxs(us,{children:[e.jsx(fs,{children:"取消"}),e.jsx(hs,{onClick:()=>v(!1),children:"关闭动画"})]})]})]})]})})]}),e.jsx("div",{className:"absolute bottom-4 left-0 right-0 text-center text-xs text-muted-foreground",children:e.jsx("p",{children:iw})})]})}const Ys=m.forwardRef(({className:l,...i},r)=>e.jsx("textarea",{className:H("flex min-h-[60px] w-full rounded-md border border-input bg-transparent px-3 py-2 text-base shadow-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",l),ref:r,...i}));Ys.displayName="Textarea";const jo=m.forwardRef(({className:l,orientation:i="horizontal",decorative:r=!0,...o},u)=>e.jsx(lg,{ref:u,decorative:r,orientation:i,className:H("shrink-0 bg-border",i==="horizontal"?"h-[1px] w-full":"h-full w-[1px]",l),...o}));jo.displayName=lg.displayName;function _w({config:l,onChange:i}){const r=u=>{u.trim()&&!l.alias_names.includes(u.trim())&&i({...l,alias_names:[...l.alias_names,u.trim()]})},o=u=>{i({...l,alias_names:l.alias_names.filter((x,h)=>h!==u)})};return e.jsxs("div",{className:"space-y-6",children:[e.jsxs("div",{className:"space-y-3",children:[e.jsx(k,{htmlFor:"qq_account",children:"QQ账号 *"}),e.jsx(ie,{id:"qq_account",type:"number",placeholder:"请输入机器人的QQ账号",value:l.qq_account||"",onChange:u=>i({...l,qq_account:Number(u.target.value)})}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"机器人登录使用的QQ账号"})]}),e.jsxs("div",{className:"space-y-3",children:[e.jsx(k,{htmlFor:"nickname",children:"昵称 *"}),e.jsx(ie,{id:"nickname",placeholder:"请输入机器人的昵称",value:l.nickname,onChange:u=>i({...l,nickname:u.target.value})}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"机器人的主要称呼名称"})]}),e.jsxs("div",{className:"space-y-3",children:[e.jsx(k,{children:"别名"}),e.jsx("div",{className:"flex flex-wrap gap-2 mb-2",children:l.alias_names.map((u,x)=>e.jsxs(Ye,{variant:"secondary",className:"gap-1",children:[u,e.jsx("button",{type:"button",onClick:()=>o(x),className:"ml-1 hover:text-destructive",children:e.jsx(fl,{className:"h-3 w-3"})})]},x))}),e.jsxs("div",{className:"flex gap-2",children:[e.jsx(ie,{id:"alias_input",placeholder:"输入别名后按回车添加",onKeyPress:u=>{u.key==="Enter"&&(r(u.target.value),u.target.value="")}}),e.jsx(C,{type:"button",variant:"outline",onClick:()=>{const u=document.getElementById("alias_input");u&&(r(u.value),u.value="")},children:"添加"})]}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"机器人的其他称呼,可以添加多个"})]})]})}function Sw({config:l,onChange:i}){return e.jsxs("div",{className:"space-y-6",children:[e.jsxs("div",{className:"space-y-3",children:[e.jsx(k,{htmlFor:"personality",children:"人格特征 *"}),e.jsx(Ys,{id:"personality",placeholder:"描述机器人的人格特质和身份特征(建议120字以内)",value:l.personality,onChange:r=>i({...l,personality:r.target.value}),rows:3}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"例如:是一个女大学生,现在在读大二,会刷贴吧"})]}),e.jsxs("div",{className:"space-y-3",children:[e.jsx(k,{htmlFor:"reply_style",children:"表达风格 *"}),e.jsx(Ys,{id:"reply_style",placeholder:"描述机器人说话的表达风格、表达习惯",value:l.reply_style,onChange:r=>i({...l,reply_style:r.target.value}),rows:3}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"例如:回复平淡一些,简短一些,说中文,参考贴吧、知乎和微博的回复风格"})]}),e.jsxs("div",{className:"space-y-3",children:[e.jsx(k,{htmlFor:"interest",children:"兴趣 *"}),e.jsx(Ys,{id:"interest",placeholder:"描述机器人感兴趣的话题",value:l.interest,onChange:r=>i({...l,interest:r.target.value}),rows:2}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"会影响机器人对什么话题进行回复"})]}),e.jsx(jo,{}),e.jsxs("div",{className:"space-y-3",children:[e.jsx(k,{htmlFor:"plan_style",children:"群聊说话规则 *"}),e.jsx(Ys,{id:"plan_style",placeholder:"机器人在群聊中的行为风格和规则",value:l.plan_style,onChange:r=>i({...l,plan_style:r.target.value}),rows:4}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"定义机器人在群聊中如何行动,例如回复频率、条件等"})]}),e.jsxs("div",{className:"space-y-3",children:[e.jsx(k,{htmlFor:"private_plan_style",children:"私聊说话规则 *"}),e.jsx(Ys,{id:"private_plan_style",placeholder:"机器人在私聊中的行为风格和规则",value:l.private_plan_style,onChange:r=>i({...l,private_plan_style:r.target.value}),rows:3}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"定义机器人在私聊中的行为方式"})]})]})}function Cw({config:l,onChange:i}){return e.jsxs("div",{className:"space-y-6",children:[e.jsxs("div",{className:"space-y-3",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(k,{htmlFor:"emoji_chance",children:"表情包激活概率"}),e.jsxs("span",{className:"text-sm text-muted-foreground",children:[(l.emoji_chance*100).toFixed(0),"%"]})]}),e.jsx(ie,{id:"emoji_chance",type:"range",min:"0",max:"1",step:"0.1",value:l.emoji_chance,onChange:r=>i({...l,emoji_chance:Number(r.target.value)})}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"机器人发送表情包的概率"})]}),e.jsxs("div",{className:"space-y-3",children:[e.jsx(k,{htmlFor:"max_reg_num",children:"最大表情包数量"}),e.jsx(ie,{id:"max_reg_num",type:"number",min:"1",max:"200",value:l.max_reg_num,onChange:r=>i({...l,max_reg_num:Number(r.target.value)})}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"机器人最多保存的表情包数量"})]}),e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"space-y-1",children:[e.jsx(k,{htmlFor:"do_replace",children:"达到最大数量时替换"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"开启后会删除旧表情包,关闭则不再收集新表情包"})]}),e.jsx(Fe,{id:"do_replace",checked:l.do_replace,onCheckedChange:r=>i({...l,do_replace:r})})]}),e.jsxs("div",{className:"space-y-3",children:[e.jsx(k,{htmlFor:"check_interval",children:"检查间隔(分钟)"}),e.jsx(ie,{id:"check_interval",type:"number",min:"1",max:"120",value:l.check_interval,onChange:r=>i({...l,check_interval:Number(r.target.value)})}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"检查表情包注册、破损、删除的时间间隔"})]}),e.jsx(jo,{}),e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"space-y-1",children:[e.jsx(k,{htmlFor:"steal_emoji",children:"偷取表情包"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"允许机器人将一些表情包据为己有"})]}),e.jsx(Fe,{id:"steal_emoji",checked:l.steal_emoji,onCheckedChange:r=>i({...l,steal_emoji:r})})]}),e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"space-y-1",children:[e.jsx(k,{htmlFor:"content_filtration",children:"启用表情包过滤"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"只保存符合要求的表情包"})]}),e.jsx(Fe,{id:"content_filtration",checked:l.content_filtration,onCheckedChange:r=>i({...l,content_filtration:r})})]}),l.content_filtration&&e.jsxs("div",{className:"space-y-3",children:[e.jsx(k,{htmlFor:"filtration_prompt",children:"过滤要求"}),e.jsx(ie,{id:"filtration_prompt",placeholder:"例如:符合公序良俗",value:l.filtration_prompt,onChange:r=>i({...l,filtration_prompt:r.target.value})}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"描述表情包应该符合的要求"})]})]})}function kw({config:l,onChange:i}){return e.jsxs("div",{className:"space-y-6",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"space-y-1",children:[e.jsx(k,{htmlFor:"enable_tool",children:"启用工具系统"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"允许机器人使用各种工具增强功能"})]}),e.jsx(Fe,{id:"enable_tool",checked:l.enable_tool,onCheckedChange:r=>i({...l,enable_tool:r})})]}),e.jsx(jo,{}),e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"space-y-1",children:[e.jsx(k,{htmlFor:"all_global",children:"启用全局黑话模式"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"允许机器人学习和使用群组黑话"})]}),e.jsx(Fe,{id:"all_global",checked:l.all_global,onCheckedChange:r=>i({...l,all_global:r})})]})]})}function Tw({config:l,onChange:i}){const[r,o]=m.useState(!1);return e.jsxs("div",{className:"space-y-6",children:[e.jsx("div",{className:"rounded-lg bg-blue-50 dark:bg-blue-950/30 border border-blue-200 dark:border-blue-800 p-4",children:e.jsxs("div",{className:"flex items-start gap-3",children:[e.jsx("div",{className:"mt-0.5",children:e.jsx("svg",{className:"h-5 w-5 text-blue-600 dark:text-blue-400",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",children:e.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"})})}),e.jsxs("div",{className:"flex-1 text-sm",children:[e.jsx("p",{className:"font-medium text-blue-900 dark:text-blue-100 mb-1",children:"关于硅基流动 (SiliconFlow)"}),e.jsx("p",{className:"text-blue-700 dark:text-blue-300 mb-2",children:"硅基流动提供了完整的模型覆盖,包括 DeepSeek V3、Qwen、视觉模型、语音识别和嵌入模型。 只需一个 API Key 即可使用麦麦的所有功能!"}),e.jsxs("a",{href:"https://cloud.siliconflow.cn",target:"_blank",rel:"noopener noreferrer",className:"inline-flex items-center gap-1 text-blue-600 dark:text-blue-400 hover:underline font-medium",children:["前往硅基流动获取 API Key",e.jsx(ao,{className:"h-3 w-3"})]})]})]})}),e.jsxs("div",{className:"space-y-3",children:[e.jsx(k,{htmlFor:"siliconflow_api_key",children:"SiliconFlow API Key *"}),e.jsxs("div",{className:"relative",children:[e.jsx(ie,{id:"siliconflow_api_key",type:r?"text":"password",placeholder:"sk-...",value:l.api_key,onChange:u=>i({api_key:u.target.value}),className:"font-mono pr-10"}),e.jsx(C,{type:"button",variant:"ghost",size:"sm",className:"absolute right-0 top-0 h-full px-3 hover:bg-transparent",onClick:()=>o(!r),children:r?e.jsx(wr,{className:"h-4 w-4 text-muted-foreground"}):e.jsx(Gt,{className:"h-4 w-4 text-muted-foreground"})})]}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"请输入您的硅基流动 API 密钥。获取后,麦麦将自动配置所有必需的模型。"})]}),e.jsxs("div",{className:"rounded-lg bg-muted/50 p-4 text-sm space-y-2",children:[e.jsx("p",{className:"font-medium",children:"将自动配置以下模型:"}),e.jsxs("ul",{className:"list-disc list-inside space-y-1 text-muted-foreground ml-2",children:[e.jsx("li",{children:"DeepSeek V3 - 主要对话和工具模型"}),e.jsx("li",{children:"Qwen3 30B - 高频小任务和工具调用"}),e.jsx("li",{children:"Qwen3 VL 30B - 图像识别"}),e.jsx("li",{children:"SenseVoice - 语音识别"}),e.jsx("li",{children:"BGE-M3 - 文本嵌入"}),e.jsx("li",{children:"知识库相关模型 (LPMM)"})]})]}),e.jsx("div",{className:"rounded-lg border border-amber-200 dark:border-amber-800 bg-amber-50 dark:bg-amber-950/30 p-4",children:e.jsxs("p",{className:"text-sm text-amber-900 dark:text-amber-100",children:[e.jsx("span",{className:"font-medium",children:"💡 提示:"}),'完成向导后,您可以在"系统设置 → 模型配置"中添加更多 API 提供商和模型。']})})]})}async function Ew(){const l=await we("/api/webui/config/bot",{method:"GET",headers:Is()});if(!l.ok)throw new Error("读取Bot配置失败");const r=(await l.json()).config.bot||{};return{qq_account:r.qq_account||0,nickname:r.nickname||"",alias_names:r.alias_names||[]}}async function zw(){const l=await we("/api/webui/config/bot",{method:"GET",headers:Is()});if(!l.ok)throw new Error("读取人格配置失败");const r=(await l.json()).config.personality||{};return{personality:r.personality||"",reply_style:r.reply_style||"",interest:r.interest||"",plan_style:r.plan_style||"",private_plan_style:r.private_plan_style||""}}async function Mw(){const l=await we("/api/webui/config/bot",{method:"GET",headers:Is()});if(!l.ok)throw new Error("读取表情包配置失败");const r=(await l.json()).config.emoji||{};return{emoji_chance:r.emoji_chance??.4,max_reg_num:r.max_reg_num??40,do_replace:r.do_replace??!0,check_interval:r.check_interval??10,steal_emoji:r.steal_emoji??!0,content_filtration:r.content_filtration??!1,filtration_prompt:r.filtration_prompt||""}}async function Aw(){const l=await we("/api/webui/config/bot",{method:"GET",headers:Is()});if(!l.ok)throw new Error("读取其他配置失败");const r=(await l.json()).config,o=r.tool||{},u=r.expression||{};return{enable_tool:o.enable_tool??!0,all_global:u.all_global_jargon??!0}}async function Ow(){const l=await we("/api/webui/config/model",{method:"GET",headers:Is()});if(!l.ok)throw new Error("读取模型配置失败");return{api_key:((await l.json()).config.api_providers||[]).find(x=>x.name==="SiliconFlow")?.api_key||""}}async function Dw(l){const i=await we("/api/webui/config/bot/section/bot",{method:"POST",headers:Is(),body:JSON.stringify(l)});if(!i.ok){const r=await i.json();throw new Error(r.detail||"保存Bot基础配置失败")}return await i.json()}async function Rw(l){const i=await we("/api/webui/config/bot/section/personality",{method:"POST",headers:Is(),body:JSON.stringify(l)});if(!i.ok){const r=await i.json();throw new Error(r.detail||"保存人格配置失败")}return await i.json()}async function Lw(l){const i=await we("/api/webui/config/bot/section/emoji",{method:"POST",headers:Is(),body:JSON.stringify(l)});if(!i.ok){const r=await i.json();throw new Error(r.detail||"保存表情包配置失败")}return await i.json()}async function Uw(l){const i=[];i.push(we("/api/webui/config/bot/section/tool",{method:"POST",headers:Is(),body:JSON.stringify({enable_tool:l.enable_tool})})),i.push(we("/api/webui/config/bot/section/expression",{method:"POST",headers:Is(),body:JSON.stringify({all_global_jargon:l.all_global})}));const r=await Promise.all(i);for(const o of r)if(!o.ok){const u=await o.json();throw new Error(u.detail||"保存其他配置失败")}return{success:!0}}async function Bw(l){const i=await we("/api/webui/config/model",{method:"GET",headers:Is()});if(!i.ok)throw new Error("读取模型配置失败");const o=(await i.json()).config,u=o.api_providers||[],x=u.findIndex(g=>g.name==="SiliconFlow");x>=0?u[x]={...u[x],api_key:l.api_key}:u.push({name:"SiliconFlow",base_url:"https://api.siliconflow.cn/v1",api_key:l.api_key,client_type:"openai",max_retry:3,timeout:120,retry_interval:5});const h={...o,api_providers:u},f=await we("/api/webui/config/model",{method:"POST",headers:Is(),body:JSON.stringify(h)});if(!f.ok){const g=await f.json();throw new Error(g.detail||"保存模型配置失败")}return await f.json()}async function Cp(){const l=await we("/api/webui/setup/complete",{method:"POST"});if(!l.ok){const i=await l.json();throw new Error(i.message||"标记配置完成失败")}return await l.json()}function Hw(){return e.jsx(jn,{children:e.jsx($w,{})})}function $w(){const l=ka(),{toast:i}=Ks(),{triggerRestart:r}=Il(),[o,u]=m.useState(0),[x,h]=m.useState(!1),[f,g]=m.useState(!1),[j,v]=m.useState(!0),[y,b]=m.useState({qq_account:0,nickname:"",alias_names:[]}),[S,w]=m.useState({personality:"是一个女大学生,现在在读大二,会刷贴吧。",reply_style:"请回复的平淡一些,简短一些,说中文,不要刻意突出自身学科背景。可以参考贴吧,知乎和微博的回复风格。",interest:"对技术相关话题,游戏和动漫相关话题感兴趣,也对日常话题感兴趣,不喜欢太过沉重严肃的话题",plan_style:`1.思考**所有**的可用的action中的**每个动作**是否符合当下条件,如果动作使用条件符合聊天内容就使用 +2.如果相同的内容已经被执行,请不要重复执行 +3.请控制你的发言频率,不要太过频繁的发言 +4.如果有人对你感到厌烦,请减少回复 +5.如果有人对你进行攻击,或者情绪激动,请你以合适的方法应对`,private_plan_style:`1.思考**所有**的可用的action中的**每个动作**是否符合当下条件,如果动作使用条件符合聊天内容就使用 +2.如果相同的内容已经被执行,请不要重复执行 +3.某句话如果已经被回复过,不要重复回复`}),[O,A]=m.useState({emoji_chance:.4,max_reg_num:40,do_replace:!0,check_interval:10,steal_emoji:!0,content_filtration:!1,filtration_prompt:"符合公序良俗"}),[D,V]=m.useState({enable_tool:!0,all_global:!0}),[z,_]=m.useState({api_key:""}),T=[{id:"bot-basic",title:"Bot基础",description:"配置机器人的基本信息",icon:fr},{id:"personality",title:"人格配置",description:"定义机器人的性格和说话风格",icon:oo},{id:"emoji",title:"表情包",description:"配置表情包相关设置",icon:im},{id:"other",title:"其他设置",description:"工具、情绪系统等配置",icon:ji},{id:"siliconflow",title:"API配置",description:"配置硅基流动API密钥",icon:Dg}],$=(o+1)/T.length*100;m.useEffect(()=>{(async()=>{try{v(!0);const[je,be,U,P,X]=await Promise.all([Ew(),zw(),Mw(),Aw(),Ow()]);b(je),w(be),A(U),V(P),_(X)}catch(je){i({title:"加载配置失败",description:je instanceof Error?je.message:"无法加载现有配置,将使用默认值",variant:"destructive"})}finally{v(!1)}})()},[i]);const E=async()=>{g(!0);try{switch(o){case 0:await Dw(y);break;case 1:await Rw(S);break;case 2:await Lw(O);break;case 3:await Uw(D);break;case 4:await Bw(z);break}return i({title:"保存成功",description:`${T[o].title}配置已保存`}),!0}catch(oe){return i({title:"保存失败",description:oe instanceof Error?oe.message:"未知错误",variant:"destructive"}),!1}finally{g(!1)}},se=async()=>{await E()&&o{o>0&&u(o-1)},ne=async()=>{h(!0);try{if(!await E()){h(!1);return}await Cp(),i({title:"配置完成",description:"麦麦正在重启以应用新配置..."}),await r()}catch(oe){i({title:"配置失败",description:oe instanceof Error?oe.message:"未知错误",variant:"destructive"})}finally{h(!1)}},ue=async()=>{try{await Cp(),l({to:"/"})}catch(oe){i({title:"跳过失败",description:oe instanceof Error?oe.message:"未知错误",variant:"destructive"})}},Se=()=>{switch(o){case 0:return e.jsx(_w,{config:y,onChange:b});case 1:return e.jsx(Sw,{config:S,onChange:w});case 2:return e.jsx(Cw,{config:O,onChange:A});case 3:return e.jsx(kw,{config:D,onChange:V});case 4:return e.jsx(Tw,{config:z,onChange:_});default:return null}};return e.jsxs("div",{className:"relative flex min-h-screen flex-col items-center justify-center overflow-hidden bg-gradient-to-br from-primary/5 via-background to-secondary/5 p-4 md:p-6",children:[e.jsx(vn,{}),e.jsxs("div",{className:"absolute inset-0 overflow-hidden pointer-events-none",children:[e.jsx("div",{className:"absolute left-1/4 top-1/4 h-64 w-64 md:h-96 md:w-96 rounded-full bg-primary/5 blur-3xl"}),e.jsx("div",{className:"absolute right-1/4 bottom-1/4 h-64 w-64 md:h-96 md:w-96 rounded-full bg-secondary/5 blur-3xl"})]}),j?e.jsxs("div",{className:"relative z-10 text-center",children:[e.jsx("div",{className:"mx-auto mb-4 flex h-16 w-16 items-center justify-center",children:e.jsx("div",{className:"h-12 w-12 animate-spin rounded-full border-4 border-primary border-t-transparent"})}),e.jsx("p",{className:"text-lg font-medium",children:"加载配置中..."}),e.jsx("p",{className:"text-sm text-muted-foreground mt-2",children:"正在读取现有配置"})]}):e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"relative z-10 w-full max-w-4xl",children:[e.jsxs("div",{className:"mb-6 md:mb-8 text-center",children:[e.jsx("div",{className:"mx-auto mb-4 flex h-12 w-12 md:h-16 md:w-16 items-center justify-center rounded-2xl bg-primary/10",children:e.jsx(Uy,{className:"h-6 w-6 md:h-8 md:w-8 text-primary",strokeWidth:2,fill:"none"})}),e.jsx("h1",{className:"mb-2 text-2xl md:text-3xl font-bold",children:"首次配置向导"}),e.jsxs("p",{className:"text-sm md:text-base text-muted-foreground",children:["让我们一起完成 ",um," 的初始配置"]})]}),e.jsxs("div",{className:"mb-6 md:mb-8",children:[e.jsxs("div",{className:"mb-2 flex items-center justify-between text-xs md:text-sm",children:[e.jsxs("span",{className:"text-muted-foreground",children:["步骤 ",o+1," / ",T.length]}),e.jsxs("span",{className:"font-medium text-primary",children:[Math.round($),"%"]})]}),e.jsx(gn,{value:$,className:"h-2"})]}),e.jsx("div",{className:"mb-6 md:mb-8 flex justify-between",children:T.map((oe,je)=>{const be=oe.icon;return e.jsxs("div",{className:H("flex flex-1 flex-col items-center gap-1 md:gap-2",jel({to:"/"}),className:"gap-2 w-full sm:w-auto",children:[e.jsx(po,{className:"h-4 w-4"}),"返回首页"]}),e.jsxs(C,{size:"lg",variant:"outline",onClick:()=>window.history.back(),className:"gap-2 w-full sm:w-auto",children:[e.jsx(hi,{className:"h-4 w-4"}),"返回上一页"]})]}),e.jsx("div",{className:"mt-12 pt-8 border-t border-border",children:e.jsx("p",{className:"text-sm text-muted-foreground",children:"如果您认为这是一个错误,请联系系统管理员"})})]})})}const qw=Ct.memo(function({config:i,onChange:r}){const o=()=>{r({...i,platforms:[...i.platforms,""]})},u=j=>{r({...i,platforms:i.platforms.filter((v,y)=>y!==j)})},x=(j,v)=>{const y=[...i.platforms];y[j]=v,r({...i,platforms:y})},h=()=>{r({...i,alias_names:[...i.alias_names,""]})},f=j=>{r({...i,alias_names:i.alias_names.filter((v,y)=>y!==j)})},g=(j,v)=>{const y=[...i.alias_names];y[j]=v,r({...i,alias_names:y})};return e.jsx("div",{className:"rounded-lg border bg-card p-4 sm:p-6 space-y-6",children:e.jsxs("div",{children:[e.jsx("h3",{className:"text-lg font-semibold mb-4",children:"基本信息"}),e.jsxs("div",{className:"grid gap-4",children:[e.jsxs("div",{className:"grid gap-2",children:[e.jsx(k,{htmlFor:"platform",children:"平台"}),e.jsx(ie,{id:"platform",value:i.platform,onChange:j=>r({...i,platform:j.target.value}),placeholder:"qq"})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(k,{htmlFor:"qq_account",children:"QQ账号"}),e.jsx(ie,{id:"qq_account",value:i.qq_account,onChange:j=>r({...i,qq_account:j.target.value}),placeholder:"123456789"})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(k,{htmlFor:"nickname",children:"昵称"}),e.jsx(ie,{id:"nickname",value:i.nickname,onChange:j=>r({...i,nickname:j.target.value}),placeholder:"麦麦"})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(k,{children:"其他平台账号"}),e.jsxs(C,{onClick:o,size:"sm",variant:"outline",children:[e.jsx(ut,{className:"h-4 w-4 mr-1"}),"添加"]})]}),e.jsxs("div",{className:"space-y-2",children:[i.platforms.map((j,v)=>e.jsxs("div",{className:"flex gap-2",children:[e.jsx(ie,{value:j,onChange:y=>x(v,y.target.value),placeholder:"wx:114514"}),e.jsxs(js,{children:[e.jsx(mt,{asChild:!0,children:e.jsx(C,{size:"icon",variant:"outline",children:e.jsx(es,{className:"h-4 w-4"})})}),e.jsxs(os,{children:[e.jsxs(ds,{children:[e.jsx(ms,{children:"确认删除"}),e.jsxs(xs,{children:['确定要删除平台账号 "',j||"(空)",'" 吗?此操作无法撤销。']})]}),e.jsxs(us,{children:[e.jsx(fs,{children:"取消"}),e.jsx(hs,{onClick:()=>u(v),children:"删除"})]})]})]})]},v)),i.platforms.length===0&&e.jsx("p",{className:"text-sm text-muted-foreground",children:"暂无其他平台账号"})]})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(k,{children:"别名"}),e.jsxs(C,{onClick:h,size:"sm",variant:"outline",children:[e.jsx(ut,{className:"h-4 w-4 mr-1"}),"添加"]})]}),e.jsxs("div",{className:"space-y-2",children:[i.alias_names.map((j,v)=>e.jsxs("div",{className:"flex gap-2",children:[e.jsx(ie,{value:j,onChange:y=>g(v,y.target.value),placeholder:"小麦"}),e.jsxs(js,{children:[e.jsx(mt,{asChild:!0,children:e.jsx(C,{size:"icon",variant:"outline",children:e.jsx(es,{className:"h-4 w-4"})})}),e.jsxs(os,{children:[e.jsxs(ds,{children:[e.jsx(ms,{children:"确认删除"}),e.jsxs(xs,{children:['确定要删除别名 "',j||"(空)",'" 吗?此操作无法撤销。']})]}),e.jsxs(us,{children:[e.jsx(fs,{children:"取消"}),e.jsx(hs,{onClick:()=>f(v),children:"删除"})]})]})]})]},v)),i.alias_names.length===0&&e.jsx("p",{className:"text-sm text-muted-foreground",children:"暂无别名"})]})]})]})]})})}),Gw=Ct.memo(function({config:i,onChange:r}){const o=()=>{r({...i,states:[...i.states,""]})},u=h=>{r({...i,states:i.states.filter((f,g)=>g!==h)})},x=(h,f)=>{const g=[...i.states];g[h]=f,r({...i,states:g})};return e.jsx("div",{className:"rounded-lg border bg-card p-4 sm:p-6 space-y-6",children:e.jsxs("div",{children:[e.jsx("h3",{className:"text-lg font-semibold mb-4",children:"人格设置"}),e.jsxs("div",{className:"grid gap-4",children:[e.jsxs("div",{className:"grid gap-2",children:[e.jsx(k,{htmlFor:"personality",children:"人格特质"}),e.jsx(Ys,{id:"personality",value:i.personality,onChange:h=>r({...i,personality:h.target.value}),placeholder:"描述人格特质和身份特征(建议120字以内)",rows:3}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"建议120字以内,描述人格特质和身份特征"})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(k,{htmlFor:"reply_style",children:"表达风格"}),e.jsx(Ys,{id:"reply_style",value:i.reply_style,onChange:h=>r({...i,reply_style:h.target.value}),placeholder:"描述说话的表达风格和习惯",rows:3})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(k,{htmlFor:"interest",children:"兴趣"}),e.jsx(Ys,{id:"interest",value:i.interest,onChange:h=>r({...i,interest:h.target.value}),placeholder:"会影响麦麦对什么话题进行回复",rows:2})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(k,{htmlFor:"plan_style",children:"说话规则与行为风格"}),e.jsx(Ys,{id:"plan_style",value:i.plan_style,onChange:h=>r({...i,plan_style:h.target.value}),placeholder:"麦麦的说话规则和行为风格",rows:5})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(k,{htmlFor:"visual_style",children:"识图规则"}),e.jsx(Ys,{id:"visual_style",value:i.visual_style,onChange:h=>r({...i,visual_style:h.target.value}),placeholder:"识图时的处理规则",rows:3})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(k,{htmlFor:"private_plan_style",children:"私聊规则"}),e.jsx(Ys,{id:"private_plan_style",value:i.private_plan_style,onChange:h=>r({...i,private_plan_style:h.target.value}),placeholder:"私聊的说话规则和行为风格",rows:4})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(k,{children:"状态列表(人格多样性)"}),e.jsxs(C,{onClick:o,size:"sm",variant:"outline",children:[e.jsx(ut,{className:"h-4 w-4 mr-1"}),"添加状态"]})]}),e.jsx("div",{className:"space-y-2",children:i.states.map((h,f)=>e.jsxs("div",{className:"flex gap-2",children:[e.jsx(Ys,{value:h,onChange:g=>x(f,g.target.value),placeholder:"描述一个人格状态",rows:2}),e.jsxs(js,{children:[e.jsx(mt,{asChild:!0,children:e.jsx(C,{size:"icon",variant:"outline",children:e.jsx(es,{className:"h-4 w-4"})})}),e.jsxs(os,{children:[e.jsxs(ds,{children:[e.jsx(ms,{children:"确认删除"}),e.jsx(xs,{children:"确定要删除这个人格状态吗?此操作无法撤销。"})]}),e.jsxs(us,{children:[e.jsx(fs,{children:"取消"}),e.jsx(hs,{onClick:()=>u(f),children:"删除"})]})]})]})]},f))})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(k,{htmlFor:"state_probability",children:"状态替换概率"}),e.jsx(ie,{id:"state_probability",type:"number",step:"0.1",min:"0",max:"1",value:i.state_probability,onChange:h=>r({...i,state_probability:parseFloat(h.target.value)})}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"每次构建人格时替换 personality 的概率(0.0-1.0)"})]})]})]})})}),Ue=fy,Be=py,Re=m.forwardRef(({className:l,children:i,...r},o)=>e.jsxs(fg,{ref:o,className:H("flex h-9 w-full items-center justify-between whitespace-nowrap rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm ring-offset-background data-[placeholder]:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",l),...r,children:[i,e.jsx(dy,{asChild:!0,children:e.jsx(Fa,{className:"h-4 w-4 opacity-50"})})]}));Re.displayName=fg.displayName;const pj=m.forwardRef(({className:l,...i},r)=>e.jsx(pg,{ref:r,className:H("flex cursor-default items-center justify-center py-1",l),...i,children:e.jsx(fi,{className:"h-4 w-4"})}));pj.displayName=pg.displayName;const gj=m.forwardRef(({className:l,...i},r)=>e.jsx(gg,{ref:r,className:H("flex cursor-default items-center justify-center py-1",l),...i,children:e.jsx(Fa,{className:"h-4 w-4"})}));gj.displayName=gg.displayName;const Le=m.forwardRef(({className:l,children:i,position:r="popper",...o},u)=>e.jsx(uy,{children:e.jsxs(jg,{ref:u,className:H("relative z-[100] max-h-[--radix-select-content-available-height] min-w-[8rem] overflow-hidden rounded-md border border-border bg-white dark:bg-gray-900 text-gray-900 dark:text-gray-100 shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-select-content-transform-origin]",r==="popper"&&"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",l),position:r,...o,children:[e.jsx(pj,{}),e.jsx(my,{className:H("p-1",r==="popper"&&"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]"),children:i}),e.jsx(gj,{})]})}));Le.displayName=jg.displayName;const Vw=m.forwardRef(({className:l,...i},r)=>e.jsx(vg,{ref:r,className:H("px-2 py-1.5 text-sm font-semibold",l),...i}));Vw.displayName=vg.displayName;const ee=m.forwardRef(({className:l,children:i,...r},o)=>e.jsxs(bg,{ref:o,className:H("relative flex w-full cursor-default select-none items-center rounded-sm py-2 pl-2 pr-8 text-sm outline-none bg-white dark:bg-gray-900 hover:bg-gray-100 dark:hover:bg-gray-800 focus:bg-gray-100 dark:focus:bg-gray-800 data-[disabled]:pointer-events-none data-[disabled]:opacity-50",l),...r,children:[e.jsx("span",{className:"absolute right-2 flex h-3.5 w-3.5 items-center justify-center",children:e.jsx(xy,{children:e.jsx(ea,{className:"h-4 w-4"})})}),e.jsx(hy,{children:i})]}));ee.displayName=bg.displayName;const Fw=m.forwardRef(({className:l,...i},r)=>e.jsx(Ng,{ref:r,className:H("-mx-1 my-1 h-px bg-muted",l),...i}));Fw.displayName=Ng.displayName;const Ia=FN,Qa=IN,La=m.forwardRef(({className:l,align:i="center",sideOffset:r=4,...o},u)=>e.jsx(VN,{children:e.jsx(ng,{ref:u,align:i,sideOffset:r,className:H("z-50 w-72 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-popover-content-transform-origin]",l),...o})}));La.displayName=ng.displayName;const Iw=Ct.memo(function({value:i,onChange:r}){const[o,u]=m.useState("00"),[x,h]=m.useState("00"),[f,g]=m.useState("23"),[j,v]=m.useState("59");m.useEffect(()=>{const b=i.split("-");if(b.length===2){const[S,w]=b,[O,A]=S.split(":"),[D,V]=w.split(":");O&&u(O.padStart(2,"0")),A&&h(A.padStart(2,"0")),D&&g(D.padStart(2,"0")),V&&v(V.padStart(2,"0"))}},[i]);const y=(b,S,w,O)=>{const A=`${b}:${S}-${w}:${O}`;r(A)};return e.jsxs(Ia,{children:[e.jsx(Qa,{asChild:!0,children:e.jsxs(C,{variant:"outline",className:"w-full justify-start font-mono text-sm",children:[e.jsx(xi,{className:"h-4 w-4 mr-2"}),i||"选择时间段"]})}),e.jsx(La,{className:"w-72 sm:w-80",children:e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{children:[e.jsx("h4",{className:"font-medium text-sm mb-3",children:"开始时间"}),e.jsxs("div",{className:"grid grid-cols-2 gap-2 sm:gap-3",children:[e.jsxs("div",{children:[e.jsx(k,{className:"text-xs",children:"小时"}),e.jsxs(Ue,{value:o,onValueChange:b=>{u(b),y(b,x,f,j)},children:[e.jsx(Re,{children:e.jsx(Be,{})}),e.jsx(Le,{children:Array.from({length:24},(b,S)=>S).map(b=>e.jsx(ee,{value:b.toString().padStart(2,"0"),children:b.toString().padStart(2,"0")},b))})]})]}),e.jsxs("div",{children:[e.jsx(k,{className:"text-xs",children:"分钟"}),e.jsxs(Ue,{value:x,onValueChange:b=>{h(b),y(o,b,f,j)},children:[e.jsx(Re,{children:e.jsx(Be,{})}),e.jsx(Le,{children:Array.from({length:60},(b,S)=>S).map(b=>e.jsx(ee,{value:b.toString().padStart(2,"0"),children:b.toString().padStart(2,"0")},b))})]})]})]})]}),e.jsxs("div",{children:[e.jsx("h4",{className:"font-medium text-sm mb-3",children:"结束时间"}),e.jsxs("div",{className:"grid grid-cols-2 gap-2 sm:gap-3",children:[e.jsxs("div",{children:[e.jsx(k,{className:"text-xs",children:"小时"}),e.jsxs(Ue,{value:f,onValueChange:b=>{g(b),y(o,x,b,j)},children:[e.jsx(Re,{children:e.jsx(Be,{})}),e.jsx(Le,{children:Array.from({length:24},(b,S)=>S).map(b=>e.jsx(ee,{value:b.toString().padStart(2,"0"),children:b.toString().padStart(2,"0")},b))})]})]}),e.jsxs("div",{children:[e.jsx(k,{className:"text-xs",children:"分钟"}),e.jsxs(Ue,{value:j,onValueChange:b=>{v(b),y(o,x,f,b)},children:[e.jsx(Re,{children:e.jsx(Be,{})}),e.jsx(Le,{children:Array.from({length:60},(b,S)=>S).map(b=>e.jsx(ee,{value:b.toString().padStart(2,"0"),children:b.toString().padStart(2,"0")},b))})]})]})]})]})]})})]})}),Qw=Ct.memo(function({rule:i}){const r=`{ target = "${i.target}", time = "${i.time}", value = ${i.value.toFixed(1)} }`;return e.jsxs(Ia,{children:[e.jsx(Qa,{asChild:!0,children:e.jsxs(C,{variant:"outline",size:"sm",children:[e.jsx(Gt,{className:"h-4 w-4 mr-1"}),"预览"]})}),e.jsx(La,{className:"w-80 sm:w-96",children:e.jsxs("div",{className:"space-y-2",children:[e.jsx("h4",{className:"font-medium text-sm",children:"配置预览"}),e.jsx("div",{className:"rounded-md bg-muted p-3 font-mono text-xs break-all",children:r}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"这是保存到 bot_config.toml 文件中的格式"})]})})]})}),Yw=Ct.memo(function({config:i,onChange:r}){const o=()=>{r({...i,talk_value_rules:[...i.talk_value_rules,{target:"",time:"00:00-23:59",value:1}]})},u=h=>{r({...i,talk_value_rules:i.talk_value_rules.filter((f,g)=>g!==h)})},x=(h,f,g)=>{const j=[...i.talk_value_rules];j[h]={...j[h],[f]:g},r({...i,talk_value_rules:j})};return e.jsxs("div",{className:"rounded-lg border bg-card p-4 sm:p-6 space-y-6",children:[e.jsxs("div",{children:[e.jsx("h3",{className:"text-lg font-semibold mb-4",children:"聊天设置"}),e.jsxs("div",{className:"grid gap-4",children:[e.jsxs("div",{className:"grid gap-2",children:[e.jsx(k,{htmlFor:"talk_value",children:"聊天频率(基础值)"}),e.jsx(ie,{id:"talk_value",type:"number",step:"0.1",min:"0",max:"1",value:i.talk_value,onChange:h=>r({...i,talk_value:parseFloat(h.target.value)})}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"越小越沉默,范围 0-1"})]}),e.jsxs("div",{className:"flex items-center space-x-2",children:[e.jsx(Fe,{id:"mentioned_bot_reply",checked:i.mentioned_bot_reply,onCheckedChange:h=>r({...i,mentioned_bot_reply:h})}),e.jsx(k,{htmlFor:"mentioned_bot_reply",className:"cursor-pointer",children:"启用提及必回复"})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(k,{htmlFor:"max_context_size",children:"上下文长度"}),e.jsx(ie,{id:"max_context_size",type:"number",min:"1",value:i.max_context_size,onChange:h=>r({...i,max_context_size:parseInt(h.target.value)})})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(k,{htmlFor:"planner_smooth",children:"规划器平滑"}),e.jsx(ie,{id:"planner_smooth",type:"number",step:"1",min:"0",value:i.planner_smooth,onChange:h=>r({...i,planner_smooth:parseFloat(h.target.value)})}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"增大数值会减小 planner 负荷,推荐 1-5,0 为关闭"})]}),e.jsxs("div",{className:"flex items-center space-x-2",children:[e.jsx(Fe,{id:"enable_talk_value_rules",checked:i.enable_talk_value_rules,onCheckedChange:h=>r({...i,enable_talk_value_rules:h})}),e.jsx(k,{htmlFor:"enable_talk_value_rules",className:"cursor-pointer",children:"启用动态发言频率规则"})]}),e.jsxs("div",{className:"flex items-center space-x-2",children:[e.jsx(Fe,{id:"include_planner_reasoning",checked:i.include_planner_reasoning,onCheckedChange:h=>r({...i,include_planner_reasoning:h})}),e.jsx(k,{htmlFor:"include_planner_reasoning",className:"cursor-pointer",children:"将 planner 推理加入 replyer"})]})]})]}),i.enable_talk_value_rules&&e.jsxs("div",{className:"border-t pt-6",children:[e.jsxs("div",{className:"flex items-center justify-between mb-4",children:[e.jsxs("div",{children:[e.jsx("h4",{className:"text-base font-semibold",children:"动态发言频率规则"}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:"按时段或聊天流ID调整发言频率,优先匹配具体聊天,再匹配全局规则"})]}),e.jsxs(C,{onClick:o,size:"sm",children:[e.jsx(ut,{className:"h-4 w-4 mr-1"}),"添加规则"]})]}),i.talk_value_rules&&i.talk_value_rules.length>0?e.jsx("div",{className:"space-y-4",children:i.talk_value_rules.map((h,f)=>e.jsxs("div",{className:"rounded-lg border p-4 bg-muted/50 space-y-4",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("span",{className:"text-sm font-medium text-muted-foreground",children:["规则 #",f+1]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(Qw,{rule:h}),e.jsxs(js,{children:[e.jsx(mt,{asChild:!0,children:e.jsx(C,{variant:"ghost",size:"sm",children:e.jsx(es,{className:"h-4 w-4 text-destructive"})})}),e.jsxs(os,{children:[e.jsxs(ds,{children:[e.jsx(ms,{children:"确认删除"}),e.jsxs(xs,{children:["确定要删除规则 #",f+1," 吗?此操作无法撤销。"]})]}),e.jsxs(us,{children:[e.jsx(fs,{children:"取消"}),e.jsx(hs,{onClick:()=>u(f),children:"删除"})]})]})]})]})]}),e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"grid gap-2",children:[e.jsx(k,{className:"text-xs font-medium",children:"配置类型"}),e.jsxs(Ue,{value:h.target===""?"global":"specific",onValueChange:g=>{g==="global"?x(f,"target",""):x(f,"target","qq::group")},children:[e.jsx(Re,{children:e.jsx(Be,{})}),e.jsxs(Le,{children:[e.jsx(ee,{value:"global",children:"全局配置"}),e.jsx(ee,{value:"specific",children:"详细配置"})]})]})]}),h.target!==""&&(()=>{const g=h.target.split(":"),j=g[0]||"qq",v=g[1]||"",y=g[2]||"group";return e.jsxs("div",{className:"grid gap-4 p-3 sm:p-4 rounded-lg bg-muted/50",children:[e.jsxs("div",{className:"grid grid-cols-1 sm:grid-cols-3 gap-3",children:[e.jsxs("div",{className:"grid gap-2",children:[e.jsx(k,{className:"text-xs font-medium",children:"平台"}),e.jsxs(Ue,{value:j,onValueChange:b=>{x(f,"target",`${b}:${v}:${y}`)},children:[e.jsx(Re,{children:e.jsx(Be,{})}),e.jsxs(Le,{children:[e.jsx(ee,{value:"qq",children:"QQ"}),e.jsx(ee,{value:"wx",children:"微信"})]})]})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(k,{className:"text-xs font-medium",children:"群 ID"}),e.jsx(ie,{value:v,onChange:b=>{x(f,"target",`${j}:${b.target.value}:${y}`)},placeholder:"输入群 ID",className:"font-mono text-sm"})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(k,{className:"text-xs font-medium",children:"类型"}),e.jsxs(Ue,{value:y,onValueChange:b=>{x(f,"target",`${j}:${v}:${b}`)},children:[e.jsx(Re,{children:e.jsx(Be,{})}),e.jsxs(Le,{children:[e.jsx(ee,{value:"group",children:"群组(group)"}),e.jsx(ee,{value:"private",children:"私聊(private)"})]})]})]})]}),e.jsxs("p",{className:"text-xs text-muted-foreground",children:["当前聊天流 ID:",h.target||"(未设置)"]})]})})(),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(k,{className:"text-xs font-medium",children:"时间段 (Time)"}),e.jsx(Iw,{value:h.time,onChange:g=>x(f,"time",g)}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"支持跨夜区间,例如 23:00-02:00"})]}),e.jsxs("div",{className:"grid gap-3",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(k,{htmlFor:`rule-value-${f}`,className:"text-xs font-medium",children:"发言频率值 (Value)"}),e.jsx(ie,{id:`rule-value-${f}`,type:"number",step:"0.01",min:"0.01",max:"1",value:h.value,onChange:g=>{const j=parseFloat(g.target.value);isNaN(j)||x(f,"value",Math.max(.01,Math.min(1,j)))},className:"w-20 h-8 text-xs"})]}),e.jsx(ma,{value:[h.value],onValueChange:g=>x(f,"value",g[0]),min:.01,max:1,step:.01,className:"w-full"}),e.jsxs("div",{className:"flex justify-between text-xs text-muted-foreground",children:[e.jsx("span",{children:"0.01 (极少发言)"}),e.jsx("span",{children:"0.5"}),e.jsx("span",{children:"1.0 (正常)"})]})]})]})]},f))}):e.jsx("div",{className:"text-center py-8 text-muted-foreground",children:e.jsx("p",{className:"text-sm",children:'暂无规则,点击"添加规则"按钮创建'})}),e.jsxs("div",{className:"mt-4 p-4 bg-blue-50 dark:bg-blue-950/20 border border-blue-200 dark:border-blue-800 rounded-lg",children:[e.jsx("h5",{className:"text-sm font-semibold text-blue-900 dark:text-blue-100 mb-2",children:"📝 规则说明"}),e.jsxs("ul",{className:"text-xs text-blue-800 dark:text-blue-200 space-y-1",children:[e.jsxs("li",{children:["• ",e.jsx("strong",{children:"Target 为空"}),":全局规则,对所有聊天生效"]}),e.jsxs("li",{children:["• ",e.jsx("strong",{children:"Target 指定"}),":仅对特定聊天流生效(格式:platform:id:type)"]}),e.jsxs("li",{children:["• ",e.jsx("strong",{children:"优先级"}),":先匹配具体聊天流规则,再匹配全局规则"]}),e.jsxs("li",{children:["• ",e.jsx("strong",{children:"时间支持跨夜"}),":例如 23:00-02:00 表示晚上11点到次日凌晨2点"]}),e.jsxs("li",{children:["• ",e.jsx("strong",{children:"数值范围"}),":建议 0-1,0 表示完全沉默,1 表示正常发言"]})]})]})]})]})}),Kw=Ct.memo(function({config:i,onChange:r}){return e.jsxs("div",{className:"rounded-lg border bg-card p-4 sm:p-6 space-y-4",children:[e.jsx("h3",{className:"text-lg font-semibold",children:"语音设置"}),e.jsxs("div",{className:"flex items-center space-x-2",children:[e.jsx(Fe,{checked:i.enable_asr,onCheckedChange:o=>r({...i,enable_asr:o})}),e.jsx(k,{className:"cursor-pointer",children:"启用语音识别"})]}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"启用后麦麦可以识别语音消息,需要配置语音识别模型"})]})}),Xw=Ct.memo(function({config:i,onChange:r}){return e.jsxs("div",{className:"rounded-lg border bg-card p-4 sm:p-6 space-y-4",children:[e.jsx("h3",{className:"text-lg font-semibold",children:"LPMM 知识库设置"}),e.jsxs("div",{className:"grid gap-4",children:[e.jsxs("div",{className:"flex items-center space-x-2",children:[e.jsx(Fe,{checked:i.enable,onCheckedChange:o=>r({...i,enable:o})}),e.jsx(k,{className:"cursor-pointer",children:"启用 LPMM 知识库"})]}),i.enable&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"grid gap-2",children:[e.jsx(k,{children:"LPMM 模式"}),e.jsxs(Ue,{value:i.lpmm_mode,onValueChange:o=>r({...i,lpmm_mode:o}),children:[e.jsx(Re,{children:e.jsx(Be,{placeholder:"选择 LPMM 模式"})}),e.jsxs(Le,{children:[e.jsx(ee,{value:"classic",children:"经典模式"}),e.jsx(ee,{value:"agent",children:"Agent 模式"})]})]})]}),e.jsxs("div",{className:"grid grid-cols-1 sm:grid-cols-2 gap-4",children:[e.jsxs("div",{className:"grid gap-2",children:[e.jsx(k,{children:"同义词搜索 TopK"}),e.jsx(ie,{type:"number",min:"1",value:i.rag_synonym_search_top_k,onChange:o=>r({...i,rag_synonym_search_top_k:parseInt(o.target.value)})})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(k,{children:"同义词阈值"}),e.jsx(ie,{type:"number",step:"0.1",min:"0",max:"1",value:i.rag_synonym_threshold,onChange:o=>r({...i,rag_synonym_threshold:parseFloat(o.target.value)})})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(k,{children:"实体提取线程数"}),e.jsx(ie,{type:"number",min:"1",value:i.info_extraction_workers,onChange:o=>r({...i,info_extraction_workers:parseInt(o.target.value)})})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(k,{children:"嵌入向量维度"}),e.jsx(ie,{type:"number",min:"1",value:i.embedding_dimension,onChange:o=>r({...i,embedding_dimension:parseInt(o.target.value)})})]})]})]})]})]})}),Pw=Ct.memo(function({config:i,onChange:r}){const[o,u]=m.useState(""),[x,h]=m.useState("WARNING"),f=()=>{o&&!i.suppress_libraries.includes(o)&&(r({...i,suppress_libraries:[...i.suppress_libraries,o]}),u(""))},g=w=>{r({...i,suppress_libraries:i.suppress_libraries.filter(O=>O!==w)})},j=()=>{o&&!i.library_log_levels[o]&&(r({...i,library_log_levels:{...i.library_log_levels,[o]:x}}),u(""),h("WARNING"))},v=w=>{const O={...i.library_log_levels};delete O[w],r({...i,library_log_levels:O})},y=["DEBUG","INFO","WARNING","ERROR","CRITICAL"],b=["FULL","compact","lite"],S=["none","title","full"];return e.jsxs("div",{className:"rounded-lg border bg-card p-4 sm:p-6 space-y-6",children:[e.jsxs("div",{children:[e.jsx("h3",{className:"text-lg font-semibold mb-4",children:"日志配置"}),e.jsxs("div",{className:"grid grid-cols-1 sm:grid-cols-2 gap-4",children:[e.jsxs("div",{className:"grid gap-2",children:[e.jsx(k,{children:"日期格式"}),e.jsx(ie,{value:i.date_style,onChange:w=>r({...i,date_style:w.target.value}),placeholder:"例如: m-d H:i:s"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"m=月, d=日, H=时, i=分, s=秒"})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(k,{children:"日志级别样式"}),e.jsxs(Ue,{value:i.log_level_style,onValueChange:w=>r({...i,log_level_style:w}),children:[e.jsx(Re,{children:e.jsx(Be,{})}),e.jsx(Le,{children:b.map(w=>e.jsx(ee,{value:w,children:w},w))})]})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(k,{children:"日志文本颜色"}),e.jsxs(Ue,{value:i.color_text,onValueChange:w=>r({...i,color_text:w}),children:[e.jsx(Re,{children:e.jsx(Be,{})}),e.jsx(Le,{children:S.map(w=>e.jsx(ee,{value:w,children:w},w))})]})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(k,{children:"全局日志级别"}),e.jsxs(Ue,{value:i.log_level,onValueChange:w=>r({...i,log_level:w}),children:[e.jsx(Re,{children:e.jsx(Be,{})}),e.jsx(Le,{children:y.map(w=>e.jsx(ee,{value:w,children:w},w))})]})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(k,{children:"控制台日志级别"}),e.jsxs(Ue,{value:i.console_log_level,onValueChange:w=>r({...i,console_log_level:w}),children:[e.jsx(Re,{children:e.jsx(Be,{})}),e.jsx(Le,{children:y.map(w=>e.jsx(ee,{value:w,children:w},w))})]})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(k,{children:"文件日志级别"}),e.jsxs(Ue,{value:i.file_log_level,onValueChange:w=>r({...i,file_log_level:w}),children:[e.jsx(Re,{children:e.jsx(Be,{})}),e.jsx(Le,{children:y.map(w=>e.jsx(ee,{value:w,children:w},w))})]})]})]})]}),e.jsxs("div",{children:[e.jsx(k,{className:"mb-2 block",children:"完全屏蔽的库"}),e.jsxs("div",{className:"flex gap-2 mb-2",children:[e.jsx(ie,{value:o,onChange:w=>u(w.target.value),placeholder:"输入库名",className:"flex-1",onKeyDown:w=>{w.key==="Enter"&&(w.preventDefault(),f())}}),e.jsx(C,{onClick:f,size:"sm",className:"flex-shrink-0",children:e.jsx(ut,{className:"h-4 w-4",strokeWidth:2,fill:"none"})})]}),e.jsx("div",{className:"flex flex-wrap gap-2",children:i.suppress_libraries.map(w=>e.jsxs("div",{className:"flex items-center gap-1 bg-secondary px-3 py-1 rounded-md",children:[e.jsx("span",{className:"text-sm",children:w}),e.jsx(C,{variant:"ghost",size:"sm",className:"h-5 w-5 p-0",onClick:()=>g(w),children:e.jsx(es,{className:"h-3 w-3",strokeWidth:2,fill:"none"})})]},w))})]}),e.jsxs("div",{children:[e.jsx(k,{className:"mb-2 block",children:"特定库的日志级别"}),e.jsxs("div",{className:"flex gap-2 mb-2",children:[e.jsx(ie,{value:o,onChange:w=>u(w.target.value),placeholder:"输入库名",className:"flex-1"}),e.jsxs(Ue,{value:x,onValueChange:h,children:[e.jsx(Re,{className:"w-32",children:e.jsx(Be,{})}),e.jsx(Le,{children:y.map(w=>e.jsx(ee,{value:w,children:w},w))})]}),e.jsx(C,{onClick:j,size:"sm",children:e.jsx(ut,{className:"h-4 w-4",strokeWidth:2,fill:"none"})})]}),e.jsx("div",{className:"space-y-2",children:Object.entries(i.library_log_levels).map(([w,O])=>e.jsxs("div",{className:"flex items-center justify-between bg-secondary px-3 py-2 rounded-md",children:[e.jsx("span",{className:"text-sm font-medium",children:w}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:"text-sm text-muted-foreground",children:O}),e.jsx(C,{variant:"ghost",size:"sm",className:"h-6 w-6 p-0",onClick:()=>v(w),children:e.jsx(es,{className:"h-3 w-3",strokeWidth:2,fill:"none"})})]})]},w))})]})]})}),Jw=Ct.memo(function({config:i,onChange:r}){return e.jsxs("div",{className:"rounded-lg border bg-card p-4 sm:p-6 space-y-4",children:[e.jsx("h3",{className:"text-lg font-semibold",children:"调试配置"}),e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"space-y-0.5",children:[e.jsx(k,{children:"显示 Prompt"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"是否在日志中显示提示词"})]}),e.jsx(Fe,{checked:i.show_prompt,onCheckedChange:o=>r({...i,show_prompt:o})})]}),e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"space-y-0.5",children:[e.jsx(k,{children:"显示回复器 Prompt"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"是否显示回复器的提示词"})]}),e.jsx(Fe,{checked:i.show_replyer_prompt,onCheckedChange:o=>r({...i,show_replyer_prompt:o})})]}),e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"space-y-0.5",children:[e.jsx(k,{children:"显示回复器推理"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"是否显示回复器的推理过程"})]}),e.jsx(Fe,{checked:i.show_replyer_reasoning,onCheckedChange:o=>r({...i,show_replyer_reasoning:o})})]}),e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"space-y-0.5",children:[e.jsx(k,{children:"显示 Jargon Prompt"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"是否显示术语相关的提示词"})]}),e.jsx(Fe,{checked:i.show_jargon_prompt,onCheckedChange:o=>r({...i,show_jargon_prompt:o})})]}),e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"space-y-0.5",children:[e.jsx(k,{children:"显示记忆检索 Prompt"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"是否显示记忆检索相关的提示词"})]}),e.jsx(Fe,{checked:i.show_memory_prompt,onCheckedChange:o=>r({...i,show_memory_prompt:o})})]}),e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"space-y-0.5",children:[e.jsx(k,{children:"显示 Planner Prompt"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"是否显示 Planner 的提示词和原始返回结果"})]}),e.jsx(Fe,{checked:i.show_planner_prompt,onCheckedChange:o=>r({...i,show_planner_prompt:o})})]}),e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"space-y-0.5",children:[e.jsx(k,{children:"显示 LPMM 相关文段"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"是否显示 LPMM 知识库找到的相关文段日志"})]}),e.jsx(Fe,{checked:i.show_lpmm_paragraph,onCheckedChange:o=>r({...i,show_lpmm_paragraph:o})})]})]})]})}),Zw=Ct.memo(function({config:i,onChange:r}){const[o,u]=m.useState(""),x=()=>{o&&!i.auth_token.includes(o)&&(r({...i,auth_token:[...i.auth_token,o]}),u(""))},h=f=>{r({...i,auth_token:i.auth_token.filter((g,j)=>j!==f)})};return e.jsxs("div",{className:"rounded-lg border bg-card p-4 sm:p-6 space-y-6",children:[e.jsxs("div",{children:[e.jsx("h3",{className:"text-lg font-semibold mb-4",children:"MaimMessage 服务配置"}),e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"space-y-0.5",children:[e.jsx(k,{children:"启用自定义服务器"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"是否使用自定义的 MaimMessage 服务器"})]}),e.jsx(Fe,{checked:i.use_custom,onCheckedChange:f=>r({...i,use_custom:f})})]}),i.use_custom&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"grid grid-cols-1 sm:grid-cols-2 gap-4",children:[e.jsxs("div",{className:"grid gap-2",children:[e.jsx(k,{children:"主机地址"}),e.jsx(ie,{value:i.host,onChange:f=>r({...i,host:f.target.value}),placeholder:"127.0.0.1"})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(k,{children:"端口号"}),e.jsx(ie,{type:"number",value:i.port,onChange:f=>r({...i,port:parseInt(f.target.value)}),placeholder:"8090"})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(k,{children:"连接模式"}),e.jsxs(Ue,{value:i.mode,onValueChange:f=>r({...i,mode:f}),children:[e.jsx(Re,{children:e.jsx(Be,{})}),e.jsxs(Le,{children:[e.jsx(ee,{value:"ws",children:"WebSocket (ws)"}),e.jsx(ee,{value:"tcp",children:"TCP"})]})]})]}),e.jsxs("div",{className:"flex items-center space-x-2",children:[e.jsx(Fe,{checked:i.use_wss,onCheckedChange:f=>r({...i,use_wss:f}),disabled:i.mode!=="ws"}),e.jsx(k,{children:"使用 WSS 安全连接"})]})]}),i.use_wss&&i.mode==="ws"&&e.jsxs("div",{className:"grid gap-4",children:[e.jsxs("div",{className:"grid gap-2",children:[e.jsx(k,{children:"SSL 证书文件路径"}),e.jsx(ie,{value:i.cert_file,onChange:f=>r({...i,cert_file:f.target.value}),placeholder:"cert.pem"})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(k,{children:"SSL 密钥文件路径"}),e.jsx(ie,{value:i.key_file,onChange:f=>r({...i,key_file:f.target.value}),placeholder:"key.pem"})]})]})]})]})]}),e.jsxs("div",{children:[e.jsx(k,{className:"mb-2 block",children:"认证令牌"}),e.jsx("p",{className:"text-sm text-muted-foreground mb-2",children:"用于 API 验证,为空则不启用验证"}),e.jsxs("div",{className:"flex gap-2 mb-2",children:[e.jsx(ie,{value:o,onChange:f=>u(f.target.value),placeholder:"输入认证令牌",onKeyDown:f=>{f.key==="Enter"&&(f.preventDefault(),x())}}),e.jsx(C,{onClick:x,size:"sm",children:e.jsx(ut,{className:"h-4 w-4",strokeWidth:2,fill:"none"})})]}),e.jsx("div",{className:"space-y-2",children:i.auth_token.map((f,g)=>e.jsxs("div",{className:"flex items-center justify-between bg-secondary px-3 py-2 rounded-md",children:[e.jsx("span",{className:"text-sm font-mono",children:f}),e.jsx(C,{variant:"ghost",size:"sm",className:"h-6 w-6 p-0",onClick:()=>h(g),children:e.jsx(es,{className:"h-3 w-3",strokeWidth:2,fill:"none"})})]},g))})]})]})}),Ww=Ct.memo(function({config:i,onChange:r}){return e.jsxs("div",{className:"rounded-lg border bg-card p-4 sm:p-6 space-y-4",children:[e.jsx("h3",{className:"text-lg font-semibold",children:"统计信息"}),e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"space-y-0.5",children:[e.jsx(k,{children:"启用统计信息发送"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"发送匿名统计信息,帮助我们了解全球有多少只麦麦在运行"})]}),e.jsx(Fe,{checked:i.enable,onCheckedChange:o=>r({...i,enable:o})})]})]})}),e1=Ct.memo(function({emojiConfig:i,memoryConfig:r,toolConfig:o,onEmojiChange:u,onMemoryChange:x,onToolChange:h}){return e.jsxs("div",{className:"space-y-6",children:[e.jsx("div",{className:"rounded-lg border bg-card p-4 sm:p-6 space-y-4",children:e.jsxs("div",{children:[e.jsx("h3",{className:"text-lg font-semibold mb-4",children:"工具设置"}),e.jsxs("div",{className:"flex items-center space-x-2",children:[e.jsx(Fe,{id:"enable_tool",checked:o.enable_tool,onCheckedChange:f=>h({...o,enable_tool:f})}),e.jsx(k,{htmlFor:"enable_tool",className:"cursor-pointer",children:"启用工具系统"})]}),e.jsx("p",{className:"text-xs text-muted-foreground mt-2",children:"允许麦麦使用各种工具来增强功能"})]})}),e.jsx("div",{className:"rounded-lg border bg-card p-4 sm:p-6 space-y-4",children:e.jsxs("div",{children:[e.jsx("h3",{className:"text-lg font-semibold mb-4",children:"记忆设置"}),e.jsxs("div",{className:"grid gap-4",children:[e.jsxs("div",{className:"grid gap-2",children:[e.jsx(k,{htmlFor:"max_agent_iterations",children:"记忆思考深度"}),e.jsx(ie,{id:"max_agent_iterations",type:"number",min:"1",value:r.max_agent_iterations,onChange:f=>x({...r,max_agent_iterations:parseInt(f.target.value)})}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"最低为 1(不深入思考)"})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(k,{htmlFor:"agent_timeout_seconds",children:"最长回忆时间(秒)"}),e.jsx(ie,{id:"agent_timeout_seconds",type:"number",min:"1",step:"0.1",value:r.agent_timeout_seconds??120,onChange:f=>x({...r,agent_timeout_seconds:parseFloat(f.target.value)})}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"记忆检索的超时时间,避免过长的等待"})]}),e.jsxs("div",{className:"flex items-center space-x-2",children:[e.jsx(Fe,{id:"enable_jargon_detection",checked:r.enable_jargon_detection??!0,onCheckedChange:f=>x({...r,enable_jargon_detection:f})}),e.jsx(k,{htmlFor:"enable_jargon_detection",className:"cursor-pointer",children:"启用黑话识别"})]}),e.jsx("p",{className:"text-xs text-muted-foreground -mt-2",children:"记忆检索过程中是否启用黑话识别"}),e.jsxs("div",{className:"flex items-center space-x-2",children:[e.jsx(Fe,{id:"global_memory",checked:r.global_memory??!1,onCheckedChange:f=>x({...r,global_memory:f})}),e.jsx(k,{htmlFor:"global_memory",className:"cursor-pointer",children:"全局记忆查询"})]}),e.jsx("p",{className:"text-xs text-muted-foreground -mt-2",children:"允许记忆检索在所有聊天记录中进行全局查询(忽略当前聊天流)"})]})]})}),e.jsx("div",{className:"rounded-lg border bg-card p-4 sm:p-6 space-y-4",children:e.jsxs("div",{children:[e.jsx("h3",{className:"text-lg font-semibold mb-4",children:"表情包设置"}),e.jsxs("div",{className:"grid gap-4",children:[e.jsxs("div",{className:"grid gap-2",children:[e.jsx(k,{htmlFor:"emoji_chance",children:"表情包激活概率"}),e.jsx(ie,{id:"emoji_chance",type:"number",step:"0.1",min:"0",max:"1",value:i.emoji_chance,onChange:f=>u({...i,emoji_chance:parseFloat(f.target.value)})}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"范围 0-1,越大越容易发送表情包"})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(k,{htmlFor:"max_reg_num",children:"最大注册数量"}),e.jsx(ie,{id:"max_reg_num",type:"number",min:"1",value:i.max_reg_num,onChange:f=>u({...i,max_reg_num:parseInt(f.target.value)})}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"麦麦最多可以注册的表情包数量"})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(k,{htmlFor:"check_interval",children:"检查间隔(分钟)"}),e.jsx(ie,{id:"check_interval",type:"number",min:"1",value:i.check_interval,onChange:f=>u({...i,check_interval:parseInt(f.target.value)})}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"检查表情包(注册、破损、删除)的时间间隔"})]}),e.jsxs("div",{className:"flex items-center space-x-2",children:[e.jsx(Fe,{id:"do_replace",checked:i.do_replace,onCheckedChange:f=>u({...i,do_replace:f})}),e.jsx(k,{htmlFor:"do_replace",className:"cursor-pointer",children:"达到最大数量时替换表情包"})]}),e.jsxs("div",{className:"flex items-center space-x-2",children:[e.jsx(Fe,{id:"steal_emoji",checked:i.steal_emoji,onCheckedChange:f=>u({...i,steal_emoji:f})}),e.jsx(k,{htmlFor:"steal_emoji",className:"cursor-pointer",children:"偷取表情包"})]}),e.jsx("p",{className:"text-xs text-muted-foreground -mt-2",children:"允许麦麦将看到的表情包据为己有"}),e.jsxs("div",{className:"flex items-center space-x-2",children:[e.jsx(Fe,{id:"content_filtration",checked:i.content_filtration,onCheckedChange:f=>u({...i,content_filtration:f})}),e.jsx(k,{htmlFor:"content_filtration",className:"cursor-pointer",children:"启用表情包过滤"})]}),i.content_filtration&&e.jsxs("div",{className:"grid gap-2 pl-6 border-l-2 border-primary/20",children:[e.jsx(k,{htmlFor:"filtration_prompt",children:"过滤要求"}),e.jsx(ie,{id:"filtration_prompt",value:i.filtration_prompt,onChange:f=>u({...i,filtration_prompt:f.target.value}),placeholder:"符合公序良俗"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"只有符合此要求的表情包才会被保存"})]})]})]})})]})}),s1=Ct.memo(function({member:i,groupIndex:r,memberIndex:o,availableChatIds:u,onUpdate:x,onRemove:h}){const f=u.includes(i)||i==="*",[g,j]=m.useState(!f);return e.jsxs("div",{className:"flex gap-2",children:[e.jsx("div",{className:"flex-1 flex gap-2",children:g?e.jsxs(e.Fragment,{children:[e.jsx(ie,{value:i,onChange:v=>x(r,o,v.target.value),placeholder:'输入 "*" 或 "qq:123456:group"',className:"flex-1"}),u.length>0&&e.jsx(C,{size:"sm",variant:"outline",onClick:()=>j(!1),title:"切换到下拉选择",children:"下拉"})]}):e.jsxs(e.Fragment,{children:[e.jsxs(Ue,{value:i,onValueChange:v=>x(r,o,v),children:[e.jsx(Re,{className:"flex-1",children:e.jsx(Be,{placeholder:"选择聊天流"})}),e.jsxs(Le,{children:[e.jsx(ee,{value:"*",children:"* (全局共享)"}),u.map((v,y)=>e.jsx(ee,{value:v,children:v},y))]})]}),e.jsx(C,{size:"sm",variant:"outline",onClick:()=>j(!0),title:"切换到手动输入",children:"输入"})]})}),e.jsxs(js,{children:[e.jsx(mt,{asChild:!0,children:e.jsx(C,{size:"icon",variant:"outline",children:e.jsx(es,{className:"h-4 w-4"})})}),e.jsxs(os,{children:[e.jsxs(ds,{children:[e.jsx(ms,{children:"确认删除"}),e.jsxs(xs,{children:['确定要删除组成员 "',i||"(空)",'" 吗?此操作无法撤销。']})]}),e.jsxs(us,{children:[e.jsx(fs,{children:"取消"}),e.jsx(hs,{onClick:()=>h(r,o),children:"删除"})]})]})]})]})}),t1=Ct.memo(function({config:i,onChange:r}){const o=()=>{r({...i,learning_list:[...i.learning_list,["","enable","enable","1.0"]]})},u=b=>{r({...i,learning_list:i.learning_list.filter((S,w)=>w!==b)})},x=(b,S,w)=>{const O=[...i.learning_list];O[b][S]=w,r({...i,learning_list:O})},h=({rule:b})=>{const S=`["${b[0]}", "${b[1]}", "${b[2]}", "${b[3]}"]`;return e.jsxs(Ia,{children:[e.jsx(Qa,{asChild:!0,children:e.jsxs(C,{variant:"outline",size:"sm",children:[e.jsx(Gt,{className:"h-4 w-4 mr-1"}),"预览"]})}),e.jsx(La,{className:"w-80 sm:w-96",children:e.jsxs("div",{className:"space-y-2",children:[e.jsx("h4",{className:"font-medium text-sm",children:"配置预览"}),e.jsx("div",{className:"rounded-md bg-muted p-3 font-mono text-xs break-all",children:S}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"这是保存到 bot_config.toml 文件中的格式"})]})})]})},f=()=>{r({...i,expression_groups:[...i.expression_groups,[]]})},g=b=>{r({...i,expression_groups:i.expression_groups.filter((S,w)=>w!==b)})},j=b=>{const S=[...i.expression_groups];S[b]=[...S[b],""],r({...i,expression_groups:S})},v=(b,S)=>{const w=[...i.expression_groups];w[b]=w[b].filter((O,A)=>A!==S),r({...i,expression_groups:w})},y=(b,S,w)=>{const O=[...i.expression_groups];O[b][S]=w,r({...i,expression_groups:O})};return e.jsxs("div",{className:"space-y-6",children:[e.jsx("div",{className:"rounded-lg border bg-card p-4 sm:p-6 space-y-6",children:e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center justify-between mb-4",children:[e.jsxs("div",{children:[e.jsx("h3",{className:"text-lg font-semibold",children:"表达学习配置"}),e.jsx("p",{className:"text-sm text-muted-foreground mt-1",children:"配置麦麦如何学习和使用表达方式"})]}),e.jsxs(C,{onClick:o,size:"sm",variant:"outline",children:[e.jsx(ut,{className:"h-4 w-4 mr-1"}),"添加规则"]})]}),e.jsxs("div",{className:"space-y-4",children:[i.learning_list.map((b,S)=>{const w=i.learning_list.some((_,T)=>T!==S&&_[0]===""),O=b[0]==="",A=b[0].split(":"),D=A[0]||"qq",V=A[1]||"",z=A[2]||"group";return e.jsxs("div",{className:"rounded-lg border p-4 space-y-4",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("span",{className:"text-sm font-medium",children:["规则 ",S+1," ",O&&"(全局配置)"]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(h,{rule:b}),e.jsxs(js,{children:[e.jsx(mt,{asChild:!0,children:e.jsx(C,{size:"sm",variant:"ghost",children:e.jsx(es,{className:"h-4 w-4"})})}),e.jsxs(os,{children:[e.jsxs(ds,{children:[e.jsx(ms,{children:"确认删除"}),e.jsxs(xs,{children:["确定要删除学习规则 ",S+1," 吗?此操作无法撤销。"]})]}),e.jsxs(us,{children:[e.jsx(fs,{children:"取消"}),e.jsx(hs,{onClick:()=>u(S),children:"删除"})]})]})]})]})]}),e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"grid gap-2",children:[e.jsx(k,{className:"text-xs font-medium",children:"配置类型"}),e.jsxs(Ue,{value:O?"global":"specific",onValueChange:_=>{_==="global"?x(S,0,""):x(S,0,"qq::group")},disabled:w&&!O,children:[e.jsx(Re,{children:e.jsx(Be,{})}),e.jsxs(Le,{children:[e.jsx(ee,{value:"global",children:"全局配置"}),e.jsx(ee,{value:"specific",disabled:w&&!O,children:"详细配置"})]})]}),w&&!O&&e.jsx("p",{className:"text-xs text-amber-600",children:"已存在全局配置,无法创建新的全局配置"})]}),!O&&e.jsxs("div",{className:"grid gap-4 p-3 sm:p-4 rounded-lg bg-muted/50",children:[e.jsxs("div",{className:"grid grid-cols-1 sm:grid-cols-3 gap-3",children:[e.jsxs("div",{className:"grid gap-2",children:[e.jsx(k,{className:"text-xs font-medium",children:"平台"}),e.jsxs(Ue,{value:D,onValueChange:_=>{x(S,0,`${_}:${V}:${z}`)},children:[e.jsx(Re,{children:e.jsx(Be,{})}),e.jsxs(Le,{children:[e.jsx(ee,{value:"qq",children:"QQ"}),e.jsx(ee,{value:"wx",children:"微信"})]})]})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(k,{className:"text-xs font-medium",children:"群 ID"}),e.jsx(ie,{value:V,onChange:_=>{x(S,0,`${D}:${_.target.value}:${z}`)},placeholder:"输入群 ID",className:"font-mono text-sm"})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(k,{className:"text-xs font-medium",children:"类型"}),e.jsxs(Ue,{value:z,onValueChange:_=>{x(S,0,`${D}:${V}:${_}`)},children:[e.jsx(Re,{children:e.jsx(Be,{})}),e.jsxs(Le,{children:[e.jsx(ee,{value:"group",children:"群组(group)"}),e.jsx(ee,{value:"private",children:"私聊(private)"})]})]})]})]}),e.jsxs("p",{className:"text-xs text-muted-foreground",children:["当前聊天流 ID:",b[0]||"(未设置)"]})]}),e.jsx("div",{className:"grid gap-2",children:e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{children:[e.jsx(k,{className:"text-xs font-medium",children:"使用学到的表达"}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:"允许麦麦使用从聊天中学到的表达方式"})]}),e.jsx(Fe,{checked:b[1]==="enable",onCheckedChange:_=>x(S,1,_?"enable":"disable")})]})}),e.jsx("div",{className:"grid gap-2",children:e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{children:[e.jsx(k,{className:"text-xs font-medium",children:"学习表达"}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:"允许麦麦从聊天中学习新的表达方式"})]}),e.jsx(Fe,{checked:b[2]==="enable",onCheckedChange:_=>x(S,2,_?"enable":"disable")})]})}),e.jsxs("div",{className:"grid gap-3",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(k,{className:"text-xs font-medium",children:"学习强度"}),e.jsx(ie,{type:"number",step:"0.1",min:"0",max:"5",value:b[3],onChange:_=>{const T=parseFloat(_.target.value);isNaN(T)||x(S,3,Math.max(0,Math.min(5,T)).toFixed(1))},className:"w-20 h-8 text-xs"})]}),e.jsx(ma,{value:[parseFloat(b[3])||1],onValueChange:_=>x(S,3,_[0].toFixed(1)),min:0,max:5,step:.1,className:"w-full"}),e.jsxs("div",{className:"flex justify-between text-xs text-muted-foreground",children:[e.jsx("span",{children:"0 (不学习)"}),e.jsx("span",{children:"2.5"}),e.jsx("span",{children:"5.0 (快速学习)"})]}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"影响学习频率,最短学习间隔 = 300/学习强度(秒)"})]})]})]},S)}),i.learning_list.length===0&&e.jsx("div",{className:"text-center py-8 text-muted-foreground",children:'暂无学习规则,点击"添加规则"开始配置'})]})]})}),e.jsx("div",{className:"rounded-lg border bg-card p-4 sm:p-6 space-y-6",children:e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center justify-between mb-4",children:[e.jsxs("div",{children:[e.jsx("h3",{className:"text-lg font-semibold",children:"表达反思配置"}),e.jsx("p",{className:"text-sm text-muted-foreground mt-1",children:"配置麦麦主动向管理员询问表达方式是否合适的功能"})]}),e.jsx(Fe,{checked:i.reflect,onCheckedChange:b=>r({...i,reflect:b})})]}),i.reflect&&e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"rounded-lg border p-4 space-y-4",children:[e.jsx("div",{className:"flex items-center justify-between",children:e.jsx("span",{className:"text-sm font-medium",children:"反思操作员"})}),e.jsx("div",{className:"space-y-4",children:(()=>{const S=(i.reflect_operator_id||"").split(":"),w=S[0]||"qq",O=S[1]||"",A=S[2]||"private";return e.jsxs("div",{className:"grid gap-4 p-3 sm:p-4 rounded-lg bg-muted/50",children:[e.jsxs("div",{className:"grid grid-cols-1 sm:grid-cols-3 gap-3",children:[e.jsxs("div",{className:"grid gap-2",children:[e.jsx(k,{className:"text-xs font-medium",children:"平台"}),e.jsxs(Ue,{value:w,onValueChange:D=>{r({...i,reflect_operator_id:`${D}:${O}:${A}`})},children:[e.jsx(Re,{children:e.jsx(Be,{})}),e.jsxs(Le,{children:[e.jsx(ee,{value:"qq",children:"QQ"}),e.jsx(ee,{value:"wx",children:"微信"})]})]})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(k,{className:"text-xs font-medium",children:"用户/群 ID"}),e.jsx(ie,{value:O,onChange:D=>{r({...i,reflect_operator_id:`${w}:${D.target.value}:${A}`})},placeholder:"输入 ID",className:"font-mono text-sm"})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(k,{className:"text-xs font-medium",children:"类型"}),e.jsxs(Ue,{value:A,onValueChange:D=>{r({...i,reflect_operator_id:`${w}:${O}:${D}`})},children:[e.jsx(Re,{children:e.jsx(Be,{})}),e.jsxs(Le,{children:[e.jsx(ee,{value:"private",children:"私聊(private)"}),e.jsx(ee,{value:"group",children:"群组(group)"})]})]})]})]}),e.jsxs("p",{className:"text-xs text-muted-foreground",children:["当前操作员 ID:",i.reflect_operator_id||"(未设置)"]}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"麦麦会向此操作员询问表达方式是否合适"})]})})()})]}),e.jsxs("div",{className:"rounded-lg border p-4 space-y-4",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{children:[e.jsx("span",{className:"text-sm font-medium",children:"允许反思的聊天流"}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:"只有在此列表中的聊天流才会提出问题并跟踪。如果列表为空,则所有聊天流都可以进行表达反思"})]}),e.jsxs(C,{onClick:()=>{r({...i,allow_reflect:[...i.allow_reflect||[],"qq::group"]})},size:"sm",variant:"outline",children:[e.jsx(ut,{className:"h-4 w-4 mr-1"}),"添加聊天流"]})]}),e.jsxs("div",{className:"space-y-2",children:[(i.allow_reflect||[]).map((b,S)=>{const w=b.split(":"),O=w[0]||"qq",A=w[1]||"",D=w[2]||"group";return e.jsxs("div",{className:"flex items-center gap-2 p-3 rounded-lg bg-muted/50",children:[e.jsxs(Ue,{value:O,onValueChange:V=>{const z=[...i.allow_reflect];z[S]=`${V}:${A}:${D}`,r({...i,allow_reflect:z})},children:[e.jsx(Re,{className:"w-24",children:e.jsx(Be,{})}),e.jsxs(Le,{children:[e.jsx(ee,{value:"qq",children:"QQ"}),e.jsx(ee,{value:"wx",children:"微信"})]})]}),e.jsx(ie,{value:A,onChange:V=>{const z=[...i.allow_reflect];z[S]=`${O}:${V.target.value}:${D}`,r({...i,allow_reflect:z})},placeholder:"ID",className:"flex-1 font-mono text-sm"}),e.jsxs(Ue,{value:D,onValueChange:V=>{const z=[...i.allow_reflect];z[S]=`${O}:${A}:${V}`,r({...i,allow_reflect:z})},children:[e.jsx(Re,{className:"w-32",children:e.jsx(Be,{})}),e.jsxs(Le,{children:[e.jsx(ee,{value:"group",children:"群组"}),e.jsx(ee,{value:"private",children:"私聊"})]})]}),e.jsx(C,{onClick:()=>{r({...i,allow_reflect:i.allow_reflect.filter((V,z)=>z!==S)})},size:"sm",variant:"ghost",children:e.jsx(es,{className:"h-4 w-4"})})]},S)}),(!i.allow_reflect||i.allow_reflect.length===0)&&e.jsx("div",{className:"text-center py-4 text-muted-foreground text-sm",children:"列表为空,所有聊天流都可以进行表达反思"})]})]})]})]})}),e.jsx("div",{className:"rounded-lg border bg-card p-4 sm:p-6 space-y-6",children:e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center justify-between mb-4",children:[e.jsxs("div",{children:[e.jsx("h3",{className:"text-lg font-semibold",children:"表达共享组配置"}),e.jsx("p",{className:"text-sm text-muted-foreground mt-1",children:"配置不同聊天流之间如何共享学到的表达方式"})]}),e.jsxs(C,{onClick:f,size:"sm",variant:"outline",children:[e.jsx(ut,{className:"h-4 w-4 mr-1"}),"添加共享组"]})]}),e.jsxs("div",{className:"space-y-4",children:[i.expression_groups.map((b,S)=>{const w=i.learning_list.map(O=>O[0]).filter(O=>O!=="");return e.jsxs("div",{className:"rounded-lg border p-4 space-y-3",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("span",{className:"text-sm font-medium",children:["共享组 ",S+1,b.length===1&&b[0]==="*"&&"(全局共享)"]}),e.jsxs("div",{className:"flex gap-2",children:[e.jsx(C,{onClick:()=>j(S),size:"sm",variant:"outline",children:e.jsx(ut,{className:"h-4 w-4"})}),e.jsxs(js,{children:[e.jsx(mt,{asChild:!0,children:e.jsx(C,{size:"sm",variant:"ghost",children:e.jsx(es,{className:"h-4 w-4"})})}),e.jsxs(os,{children:[e.jsxs(ds,{children:[e.jsx(ms,{children:"确认删除"}),e.jsxs(xs,{children:["确定要删除共享组 ",S+1," 吗?此操作无法撤销。"]})]}),e.jsxs(us,{children:[e.jsx(fs,{children:"取消"}),e.jsx(hs,{onClick:()=>g(S),children:"删除"})]})]})]})]})]}),e.jsx("div",{className:"space-y-2",children:b.map((O,A)=>e.jsx(s1,{member:O,groupIndex:S,memberIndex:A,availableChatIds:w,onUpdate:y,onRemove:v},`${S}-${A}`))}),e.jsx("p",{className:"text-xs text-muted-foreground",children:'提示:可以从下拉框选择已配置的聊天流,或手动输入。输入 "*" 启用全局共享'})]},S)}),i.expression_groups.length===0&&e.jsx("div",{className:"text-center py-8 text-muted-foreground",children:'暂无共享组,点击"添加共享组"开始配置'})]})]})}),e.jsx("div",{className:"rounded-lg border bg-card p-4 sm:p-6 space-y-4",children:e.jsxs("div",{children:[e.jsx("h3",{className:"text-lg font-semibold mb-4",children:"黑话设置"}),e.jsxs("div",{className:"flex items-center space-x-2",children:[e.jsx(Fe,{id:"all_global_jargon",checked:i.all_global_jargon??!1,onCheckedChange:b=>r({...i,all_global_jargon:b})}),e.jsx(k,{htmlFor:"all_global_jargon",className:"cursor-pointer",children:"全局黑话模式"})]}),e.jsx("p",{className:"text-xs text-muted-foreground mt-2",children:"开启后,新增的黑话将默认设为全局(所有聊天流共享)。关闭后,已记录的全局黑话不会改变,需要手动删除。"})]})})]})});function a1({regex:l,reaction:i,onRegexChange:r,onReactionChange:o}){const[u,x]=m.useState(!1),[h,f]=m.useState(""),[g,j]=m.useState(null),[v,y]=m.useState(""),[b,S]=m.useState({}),[w,O]=m.useState(""),A=m.useRef(null),[D,V]=m.useState("build"),z=E=>E.replace(/\(\?P<([^>]+)>/g,"(?<$1>"),_=(E,se=0)=>{const te=A.current;if(!te)return;const ne=te.selectionStart||0,ue=te.selectionEnd||0,Se=l.substring(0,ne)+E+l.substring(ue);r(Se),setTimeout(()=>{const oe=ne+E.length+se;te.setSelectionRange(oe,oe),te.focus()},0)};m.useEffect(()=>{if(!l||!h){j(null),S({}),O(i),y("");return}try{const E=z(l),se=new RegExp(E,"g"),te=h.match(se);j(te),y("");const ue=new RegExp(E).exec(h);if(ue&&ue.groups){S(ue.groups);let Se=i;Object.entries(ue.groups).forEach(([oe,je])=>{Se=Se.replace(new RegExp(`\\[${oe}\\]`,"g"),je||"")}),O(Se)}else S({}),O(i)}catch(E){y(E.message),j(null),S({}),O(i)}},[l,h,i]);const T=()=>{if(!h||!g||g.length===0)return e.jsx("span",{className:"text-muted-foreground",children:h||"请输入测试文本"});try{const E=z(l),se=new RegExp(E,"g");let te=0;const ne=[];let ue;for(;(ue=se.exec(h))!==null;)ue.index>te&&ne.push(e.jsx("span",{children:h.substring(te,ue.index)},`text-${te}`)),ne.push(e.jsx("span",{className:"bg-yellow-200 dark:bg-yellow-900 font-semibold",children:ue[0]},`match-${ue.index}`)),te=ue.index+ue[0].length;return te)",desc:"Python风格命名捕获组",moveCursor:-1},{label:"非捕获组",pattern:"(?:)",desc:"分组但不保存匹配结果",moveCursor:-1}]},{category:"字符类",items:[{label:"字符集",pattern:"[]",desc:"匹配括号内的任意字符",moveCursor:-1},{label:"排除字符",pattern:"[^]",desc:"匹配不在括号内的字符",moveCursor:-1},{label:"范围",pattern:"[a-z]",desc:"匹配a到z的字符"},{label:"中文字符",pattern:"[\\u4e00-\\u9fa5]",desc:"匹配中文汉字"}]},{category:"常用模板",items:[{label:"捕获词语",pattern:"(?P\\S+)",desc:"捕获一个词语"},{label:"捕获句子",pattern:"(?P.+)",desc:"捕获整个句子"},{label:"捕获数字",pattern:"(?P\\d+)",desc:"捕获一个或多个数字"},{label:"可选词语",pattern:"(?:词语1|词语2)",desc:"匹配多个可选项之一"}]}];return e.jsxs(Qs,{open:u,onOpenChange:x,children:[e.jsx(mm,{asChild:!0,children:e.jsxs(C,{variant:"outline",size:"sm",children:[e.jsx(rm,{className:"h-4 w-4 mr-1"}),"正则编辑器"]})}),e.jsxs(qs,{className:"max-w-[95vw] sm:max-w-[900px] max-h-[90vh]",children:[e.jsxs(Gs,{children:[e.jsx(Vs,{children:"正则表达式编辑器"}),e.jsx(Ws,{className:"text-sm",children:"使用可视化工具构建正则表达式,并实时测试效果"})]}),e.jsx(Ze,{className:"max-h-[calc(90vh-120px)]",children:e.jsxs(Sa,{value:D,onValueChange:E=>V(E),className:"w-full",children:[e.jsxs(xa,{className:"grid w-full grid-cols-2",children:[e.jsx(is,{value:"build",children:"🔧 构建器"}),e.jsx(is,{value:"test",children:"🧪 测试器"})]}),e.jsxs(As,{value:"build",className:"space-y-4 mt-4",children:[e.jsxs("div",{className:"space-y-2",children:[e.jsx(k,{className:"text-sm font-medium",children:"正则表达式"}),e.jsx(ie,{ref:A,value:l,onChange:E=>r(E.target.value),className:"font-mono text-sm",placeholder:"点击下方按钮构建正则表达式..."})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(k,{className:"text-sm font-medium",children:"Reaction 内容"}),e.jsx(Ys,{value:i,onChange:E=>o(E.target.value),placeholder:"使用 [捕获组名] 引用捕获的内容...",rows:3,className:"text-sm"})]}),e.jsxs("div",{className:"space-y-4 border-t pt-4",children:[$.map(E=>e.jsxs("div",{className:"space-y-2",children:[e.jsx("h5",{className:"text-xs font-semibold text-primary",children:E.category}),e.jsx("div",{className:"grid grid-cols-1 sm:grid-cols-2 gap-2",children:E.items.map(se=>e.jsx(C,{variant:"outline",size:"sm",className:"justify-start h-auto py-2 px-3",onClick:()=>_(se.pattern,se.moveCursor||0),children:e.jsxs("div",{className:"flex flex-col items-start w-full",children:[e.jsxs("div",{className:"flex items-center gap-2 w-full",children:[e.jsx("span",{className:"text-xs font-medium",children:se.label}),e.jsx("code",{className:"ml-auto text-xs bg-muted px-1.5 py-0.5 rounded font-mono",children:se.pattern})]}),e.jsx("span",{className:"text-xs text-muted-foreground mt-0.5",children:se.desc})]})},se.label))})]},E.category)),e.jsxs("div",{className:"space-y-2 border-t pt-4",children:[e.jsx("h5",{className:"text-xs font-semibold text-primary",children:"完整示例模板"}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(C,{variant:"outline",size:"sm",className:"w-full justify-start h-auto py-2 px-3",onClick:()=>r("^(?P\\S{1,20})是这样的$"),children:e.jsxs("div",{className:"flex flex-col items-start w-full",children:[e.jsxs("code",{className:"text-xs font-mono bg-muted px-2 py-1 rounded w-full overflow-x-auto",children:["^(?P\\S","{1,20}",")是这样的$"]}),e.jsx("span",{className:"text-xs text-muted-foreground mt-1",children:"匹配「某事物是这样的」并捕获事物名称"})]})}),e.jsx(C,{variant:"outline",size:"sm",className:"w-full justify-start h-auto py-2 px-3",onClick:()=>r("(?:[^,。.\\s]+,\\s*)?我(?:也)?[没沒]要求你\\s*(?P.+?)[.。,,]?$"),children:e.jsxs("div",{className:"flex flex-col items-start w-full",children:[e.jsx("code",{className:"text-xs font-mono bg-muted px-2 py-1 rounded w-full overflow-x-auto",children:"(?:[^,。.\\s]+,\\s*)?我(?:也)?[没沒]要求你\\s*(?P.+?)[.。,,]?$"}),e.jsx("span",{className:"text-xs text-muted-foreground mt-1",children:"匹配「我没要求你做某事」并捕获具体行为"})]})}),e.jsx(C,{variant:"outline",size:"sm",className:"w-full justify-start h-auto py-2 px-3",onClick:()=>r("(?P.+?)(?:是|为什么|怎么)"),children:e.jsxs("div",{className:"flex flex-col items-start w-full",children:[e.jsx("code",{className:"text-xs font-mono bg-muted px-2 py-1 rounded w-full overflow-x-auto",children:"(?P.+?)(?:是|为什么|怎么)"}),e.jsx("span",{className:"text-xs text-muted-foreground mt-1",children:"捕获问题主题词"})]})})]})]})]}),e.jsxs("div",{className:"rounded-md bg-blue-50 dark:bg-blue-950/30 border border-blue-200 dark:border-blue-800 p-3 space-y-1",children:[e.jsx("p",{className:"text-xs font-medium text-blue-900 dark:text-blue-100",children:"💡 使用提示"}),e.jsxs("ul",{className:"text-xs text-blue-700 dark:text-blue-300 space-y-1 list-disc list-inside",children:[e.jsx("li",{children:"点击输入框设置光标位置,然后点击按钮插入模式"}),e.jsxs("li",{children:["命名捕获组格式:",e.jsx("code",{className:"bg-blue-100 dark:bg-blue-900 px-1 rounded",children:"(?P<名称>模式)"})]}),e.jsxs("li",{children:["在 reaction 中使用 ",e.jsx("code",{className:"bg-blue-100 dark:bg-blue-900 px-1 rounded",children:"[名称]"})," 引用捕获的内容"]}),e.jsx("li",{children:"切换到测试器标签页验证正则表达式效果"})]})]})]}),e.jsxs(As,{value:"test",className:"space-y-4 mt-4",children:[e.jsxs("div",{className:"space-y-2",children:[e.jsx(k,{className:"text-sm font-medium",children:"当前正则表达式"}),e.jsx("div",{className:"rounded-md bg-muted p-3 font-mono text-xs break-all",children:l||"(未设置)"})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(k,{htmlFor:"test-text",className:"text-sm font-medium",children:"测试文本"}),e.jsx(Ys,{id:"test-text",value:h,onChange:E=>f(E.target.value),placeholder:`在此输入要测试的文本... +例如:打游戏是这样的`,className:"min-h-[100px] text-sm"})]}),v&&e.jsxs("div",{className:"rounded-md bg-destructive/10 border border-destructive/20 p-3",children:[e.jsx("p",{className:"text-sm text-destructive font-medium",children:"正则表达式错误"}),e.jsx("p",{className:"text-xs text-destructive/80 mt-1",children:v})]}),!v&&h&&e.jsxs("div",{className:"space-y-3",children:[e.jsx("div",{className:"flex items-center gap-2",children:g&&g.length>0?e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"h-2 w-2 rounded-full bg-green-500"}),e.jsxs("span",{className:"text-sm font-medium text-green-600 dark:text-green-400",children:["匹配成功 (",g.length," 处)"]})]}):e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"h-2 w-2 rounded-full bg-gray-400"}),e.jsx("span",{className:"text-sm font-medium text-muted-foreground",children:"无匹配"})]})}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(k,{className:"text-sm font-medium",children:"匹配高亮"}),e.jsx(Ze,{className:"h-40 rounded-md bg-muted p-3",children:e.jsx("div",{className:"text-sm break-words",children:T()})})]}),Object.keys(b).length>0&&e.jsxs("div",{className:"space-y-2",children:[e.jsx(k,{className:"text-sm font-medium",children:"命名捕获组"}),e.jsx(Ze,{className:"h-32 rounded-md border p-3",children:e.jsx("div",{className:"space-y-2",children:Object.entries(b).map(([E,se])=>e.jsxs("div",{className:"flex items-start gap-2 text-sm",children:[e.jsxs("span",{className:"font-mono font-semibold text-primary min-w-[80px]",children:["[",E,"]"]}),e.jsx("span",{className:"text-muted-foreground",children:"="}),e.jsx("span",{className:"font-mono bg-muted px-2 py-0.5 rounded",children:se})]},E))})})]}),Object.keys(b).length>0&&i&&e.jsxs("div",{className:"space-y-2",children:[e.jsx(k,{className:"text-sm font-medium",children:"Reaction 替换预览"}),e.jsx(Ze,{className:"h-48 rounded-md bg-blue-50 dark:bg-blue-950/30 border border-blue-200 dark:border-blue-800 p-3",children:e.jsx("div",{className:"text-sm break-words",children:w})}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"reaction 中的 [name] 已被替换为对应的捕获组值"})]})]}),e.jsxs("div",{className:"rounded-md bg-blue-50 dark:bg-blue-950/30 border border-blue-200 dark:border-blue-800 p-3 space-y-1",children:[e.jsx("p",{className:"text-xs font-medium text-blue-900 dark:text-blue-100",children:"💡 测试说明"}),e.jsxs("ul",{className:"text-xs text-blue-700 dark:text-blue-300 space-y-1 list-disc list-inside",children:[e.jsx("li",{children:"匹配的文本会以黄色背景高亮显示"}),e.jsx("li",{children:"命名捕获组的值会显示在下方列表中"}),e.jsx("li",{children:"Reaction 替换预览显示最终生成的反应内容"}),e.jsx("li",{children:"如需修改正则,切换回构建器标签页"})]})]})]})]})})]})]})}const l1=Ct.memo(function({keywordReactionConfig:i,responsePostProcessConfig:r,chineseTypoConfig:o,responseSplitterConfig:u,onKeywordReactionChange:x,onResponsePostProcessChange:h,onChineseTypoChange:f,onResponseSplitterChange:g}){const j=()=>{x({...i,regex_rules:[...i.regex_rules,{regex:[""],reaction:""}]})},v=_=>{x({...i,regex_rules:i.regex_rules.filter((T,$)=>$!==_)})},y=(_,T,$)=>{const E=[...i.regex_rules];T==="regex"&&typeof $=="string"?E[_]={...E[_],regex:[$]}:T==="reaction"&&typeof $=="string"&&(E[_]={...E[_],reaction:$}),x({...i,regex_rules:E})},b=()=>{x({...i,keyword_rules:[...i.keyword_rules,{keywords:[],reaction:""}]})},S=_=>{x({...i,keyword_rules:i.keyword_rules.filter((T,$)=>$!==_)})},w=(_,T,$)=>{const E=[...i.keyword_rules];typeof $=="string"&&(E[_]={...E[_],reaction:$}),x({...i,keyword_rules:E})},O=_=>{const T=[...i.keyword_rules];T[_]={...T[_],keywords:[...T[_].keywords||[],""]},x({...i,keyword_rules:T})},A=(_,T)=>{const $=[...i.keyword_rules];$[_]={...$[_],keywords:($[_].keywords||[]).filter((E,se)=>se!==T)},x({...i,keyword_rules:$})},D=(_,T,$)=>{const E=[...i.keyword_rules],se=[...E[_].keywords||[]];se[T]=$,E[_]={...E[_],keywords:se},x({...i,keyword_rules:E})},V=({rule:_})=>{const T=`{ regex = [${(_.regex||[]).map($=>`"${$}"`).join(", ")}], reaction = "${_.reaction}" }`;return e.jsxs(Ia,{children:[e.jsx(Qa,{asChild:!0,children:e.jsxs(C,{variant:"outline",size:"sm",children:[e.jsx(Gt,{className:"h-4 w-4 mr-1"}),"预览"]})}),e.jsx(La,{className:"w-[95vw] sm:w-[500px]",children:e.jsxs("div",{className:"space-y-2",children:[e.jsx("h4",{className:"font-medium text-sm",children:"配置预览"}),e.jsx(Ze,{className:"h-60 rounded-md bg-muted p-3",children:e.jsx("pre",{className:"font-mono text-xs break-all",children:T})}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"这是保存到 bot_config.toml 文件中的格式"})]})})]})},z=({rule:_})=>{const T=`[[keyword_reaction.keyword_rules]] +keywords = [${(_.keywords||[]).map($=>`"${$}"`).join(", ")}] +reaction = "${_.reaction}"`;return e.jsxs(Ia,{children:[e.jsx(Qa,{asChild:!0,children:e.jsxs(C,{variant:"outline",size:"sm",children:[e.jsx(Gt,{className:"h-4 w-4 mr-1"}),"预览"]})}),e.jsx(La,{className:"w-[95vw] sm:w-[500px]",children:e.jsxs("div",{className:"space-y-2",children:[e.jsx("h4",{className:"font-medium text-sm",children:"配置预览"}),e.jsx(Ze,{className:"h-60 rounded-md bg-muted p-3",children:e.jsx("pre",{className:"font-mono text-xs whitespace-pre-wrap break-all",children:T})}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"这是保存到 bot_config.toml 文件中的格式"})]})})]})};return e.jsxs("div",{className:"space-y-6",children:[e.jsxs("div",{className:"rounded-lg border bg-card p-4 sm:p-6 space-y-6",children:[e.jsxs("div",{children:[e.jsx("h3",{className:"text-lg font-semibold mb-2",children:"关键词反应配置"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"配置触发特定反应的关键词和正则表达式规则"})]}),e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{children:[e.jsx("h4",{className:"text-base font-semibold",children:"正则表达式规则"}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:"使用正则表达式匹配消息内容"})]}),e.jsxs(C,{onClick:j,size:"sm",variant:"outline",children:[e.jsx(ut,{className:"h-4 w-4 mr-1"}),"添加正则规则"]})]}),e.jsxs("div",{className:"space-y-3",children:[i.regex_rules.map((_,T)=>e.jsxs("div",{className:"rounded-lg border p-4 space-y-3",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("span",{className:"text-sm font-medium",children:["正则规则 ",T+1]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(a1,{regex:_.regex&&_.regex[0]||"",reaction:_.reaction,onRegexChange:$=>y(T,"regex",$),onReactionChange:$=>y(T,"reaction",$)}),e.jsx(V,{rule:_}),e.jsxs(js,{children:[e.jsx(mt,{asChild:!0,children:e.jsx(C,{size:"sm",variant:"ghost",children:e.jsx(es,{className:"h-4 w-4"})})}),e.jsxs(os,{children:[e.jsxs(ds,{children:[e.jsx(ms,{children:"确认删除"}),e.jsxs(xs,{children:["确定要删除正则规则 ",T+1," 吗?此操作无法撤销。"]})]}),e.jsxs(us,{children:[e.jsx(fs,{children:"取消"}),e.jsx(hs,{onClick:()=>v(T),children:"删除"})]})]})]})]})]}),e.jsxs("div",{className:"space-y-3",children:[e.jsxs("div",{className:"grid gap-2",children:[e.jsx(k,{className:"text-xs font-medium",children:"正则表达式(Python 语法)"}),e.jsx(ie,{value:_.regex&&_.regex[0]||"",onChange:$=>y(T,"regex",$.target.value),placeholder:"例如:^(?P\\\\S{1,20})是这样的$ (点击正则编辑器按钮可视化构建)",className:"font-mono text-sm"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:'支持命名捕获组 (?Ppattern),可在 reaction 中使用 [name] 引用。点击"正则编辑器"可视化构建和测试!'})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(k,{className:"text-xs font-medium",children:"反应内容"}),e.jsx(Ys,{value:_.reaction,onChange:$=>y(T,"reaction",$.target.value),placeholder:`触发后麦麦的反应... +可以使用 [捕获组名] 来引用正则表达式中的内容`,rows:3,className:"text-sm"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"使用 [捕获组名] 引用正则表达式中的命名捕获组,例如 [n] 会被替换为捕获的内容"})]})]})]},T)),i.regex_rules.length===0&&e.jsx("div",{className:"text-center py-8 text-muted-foreground",children:'暂无正则规则,点击"添加正则规则"开始配置'})]})]}),e.jsxs("div",{className:"space-y-4 border-t pt-6",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{children:[e.jsx("h4",{className:"text-base font-semibold",children:"关键词规则"}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:"使用关键词列表匹配消息内容"})]}),e.jsxs(C,{onClick:b,size:"sm",variant:"outline",children:[e.jsx(ut,{className:"h-4 w-4 mr-1"}),"添加关键词规则"]})]}),e.jsxs("div",{className:"space-y-3",children:[i.keyword_rules.map((_,T)=>e.jsxs("div",{className:"rounded-lg border p-4 space-y-3",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("span",{className:"text-sm font-medium",children:["关键词规则 ",T+1]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(z,{rule:_}),e.jsxs(js,{children:[e.jsx(mt,{asChild:!0,children:e.jsx(C,{size:"sm",variant:"ghost",children:e.jsx(es,{className:"h-4 w-4"})})}),e.jsxs(os,{children:[e.jsxs(ds,{children:[e.jsx(ms,{children:"确认删除"}),e.jsxs(xs,{children:["确定要删除关键词规则 ",T+1," 吗?此操作无法撤销。"]})]}),e.jsxs(us,{children:[e.jsx(fs,{children:"取消"}),e.jsx(hs,{onClick:()=>S(T),children:"删除"})]})]})]})]})]}),e.jsxs("div",{className:"space-y-3",children:[e.jsxs("div",{className:"grid gap-2",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(k,{className:"text-xs font-medium",children:"关键词列表"}),e.jsxs(C,{onClick:()=>O(T),size:"sm",variant:"ghost",children:[e.jsx(ut,{className:"h-3 w-3 mr-1"}),"添加关键词"]})]}),e.jsxs("div",{className:"space-y-2",children:[(_.keywords||[]).map(($,E)=>e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(ie,{value:$,onChange:se=>D(T,E,se.target.value),placeholder:"关键词",className:"flex-1"}),e.jsx(C,{onClick:()=>A(T,E),size:"sm",variant:"ghost",children:e.jsx(es,{className:"h-4 w-4"})})]},E)),(!_.keywords||_.keywords.length===0)&&e.jsx("p",{className:"text-xs text-muted-foreground text-center py-2",children:'暂无关键词,点击"添加关键词"开始配置'})]})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(k,{className:"text-xs font-medium",children:"反应内容"}),e.jsx(Ys,{value:_.reaction,onChange:$=>w(T,"reaction",$.target.value),placeholder:"触发后麦麦的反应...",rows:3,className:"text-sm"})]})]})]},T)),i.keyword_rules.length===0&&e.jsx("div",{className:"text-center py-8 text-muted-foreground",children:'暂无关键词规则,点击"添加关键词规则"开始配置'})]})]})]}),e.jsxs("div",{className:"rounded-lg border bg-card p-4 sm:p-6 space-y-6",children:[e.jsxs("div",{children:[e.jsx("h3",{className:"text-lg font-semibold mb-4",children:"回复后处理配置"}),e.jsxs("div",{className:"flex items-center space-x-2",children:[e.jsx(Fe,{id:"enable_response_post_process",checked:r.enable_response_post_process,onCheckedChange:_=>h({...r,enable_response_post_process:_})}),e.jsx(k,{htmlFor:"enable_response_post_process",className:"cursor-pointer",children:"启用回复后处理"})]}),e.jsx("p",{className:"text-xs text-muted-foreground mt-2",children:"包括错别字生成器和回复分割器"})]}),r.enable_response_post_process&&e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"border-t pt-6 space-y-4",children:e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center space-x-2 mb-4",children:[e.jsx(Fe,{id:"enable_chinese_typo",checked:o.enable,onCheckedChange:_=>f({...o,enable:_})}),e.jsx(k,{htmlFor:"enable_chinese_typo",className:"cursor-pointer font-semibold",children:"中文错别字生成器"})]}),e.jsx("p",{className:"text-xs text-muted-foreground mb-4",children:"为回复添加随机错别字,让麦麦的回复更自然"}),o.enable&&e.jsxs("div",{className:"grid gap-4 pl-6 border-l-2 border-primary/20",children:[e.jsxs("div",{className:"grid gap-2",children:[e.jsx(k,{htmlFor:"error_rate",className:"text-xs font-medium",children:"单字替换概率"}),e.jsx(ie,{id:"error_rate",type:"number",step:"0.001",min:"0",max:"1",value:o.error_rate,onChange:_=>f({...o,error_rate:parseFloat(_.target.value)})})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(k,{htmlFor:"min_freq",className:"text-xs font-medium",children:"最小字频阈值"}),e.jsx(ie,{id:"min_freq",type:"number",min:"0",value:o.min_freq,onChange:_=>f({...o,min_freq:parseInt(_.target.value)})})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(k,{htmlFor:"tone_error_rate",className:"text-xs font-medium",children:"声调错误概率"}),e.jsx(ie,{id:"tone_error_rate",type:"number",step:"0.01",min:"0",max:"1",value:o.tone_error_rate,onChange:_=>f({...o,tone_error_rate:parseFloat(_.target.value)})})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(k,{htmlFor:"word_replace_rate",className:"text-xs font-medium",children:"整词替换概率"}),e.jsx(ie,{id:"word_replace_rate",type:"number",step:"0.001",min:"0",max:"1",value:o.word_replace_rate,onChange:_=>f({...o,word_replace_rate:parseFloat(_.target.value)})})]})]})]})}),e.jsx("div",{className:"border-t pt-6 space-y-4",children:e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center space-x-2 mb-4",children:[e.jsx(Fe,{id:"enable_response_splitter",checked:u.enable,onCheckedChange:_=>g({...u,enable:_})}),e.jsx(k,{htmlFor:"enable_response_splitter",className:"cursor-pointer font-semibold",children:"回复分割器"})]}),e.jsx("p",{className:"text-xs text-muted-foreground mb-4",children:"控制回复的长度和句子数量"}),u.enable&&e.jsxs("div",{className:"grid gap-4 pl-6 border-l-2 border-primary/20",children:[e.jsxs("div",{className:"grid gap-2",children:[e.jsx(k,{htmlFor:"max_length",className:"text-xs font-medium",children:"最大长度"}),e.jsx(ie,{id:"max_length",type:"number",min:"1",value:u.max_length,onChange:_=>g({...u,max_length:parseInt(_.target.value)})}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"回复允许的最大字符数"})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(k,{htmlFor:"max_sentence_num",className:"text-xs font-medium",children:"最大句子数"}),e.jsx(ie,{id:"max_sentence_num",type:"number",min:"1",value:u.max_sentence_num,onChange:_=>g({...u,max_sentence_num:parseInt(_.target.value)})}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"回复允许的最大句子数量"})]}),e.jsxs("div",{className:"flex items-center space-x-2",children:[e.jsx(Fe,{id:"enable_kaomoji_protection",checked:u.enable_kaomoji_protection,onCheckedChange:_=>g({...u,enable_kaomoji_protection:_})}),e.jsx(k,{htmlFor:"enable_kaomoji_protection",className:"cursor-pointer",children:"启用颜文字保护"})]}),e.jsxs("div",{className:"flex items-center space-x-2",children:[e.jsx(Fe,{id:"enable_overflow_return_all",checked:u.enable_overflow_return_all,onCheckedChange:_=>g({...u,enable_overflow_return_all:_})}),e.jsx(k,{htmlFor:"enable_overflow_return_all",className:"cursor-pointer",children:"超出时一次性返回全部"})]}),e.jsx("p",{className:"text-xs text-muted-foreground -mt-2",children:"当句子数量超出限制时,合并后一次性返回所有内容"})]})]})})]})]})]})}),Ql="/api/webui/config";async function kp(){const i=await(await we(`${Ql}/bot`)).json();if(!i.success)throw new Error("获取配置数据失败");return i.config}async function Gl(){const i=await(await we(`${Ql}/model`)).json();if(!i.success)throw new Error("获取模型配置数据失败");return i.config}async function Tp(l){const r=await(await we(`${Ql}/bot`,{method:"POST",body:JSON.stringify(l)})).json();if(!r.success)throw new Error(r.message||"保存配置失败")}async function n1(){const i=await(await we(`${Ql}/bot/raw`)).json();if(!i.success)throw new Error("获取配置源代码失败");return i.content}async function i1(l){const r=await(await we(`${Ql}/bot/raw`,{method:"POST",body:JSON.stringify({raw_content:l})})).json();if(!r.success)throw new Error(r.message||"保存配置失败")}async function Nr(l){const r=await(await we(`${Ql}/model`,{method:"POST",body:JSON.stringify(l)})).json();if(!r.success)throw new Error(r.message||"保存配置失败")}async function r1(l,i){const o=await(await we(`${Ql}/bot/section/${l}`,{method:"POST",body:JSON.stringify(i)})).json();if(!o.success)throw new Error(o.message||`保存配置节 ${l} 失败`)}async function am(l,i){const o=await(await we(`${Ql}/model/section/${l}`,{method:"POST",body:JSON.stringify(i)})).json();if(!o.success)throw new Error(o.message||`保存配置节 ${l} 失败`)}async function c1(l,i="openai",r="/models"){const o=new URLSearchParams({provider_name:l,parser:i,endpoint:r}),u=await we(`/api/webui/models/list?${o}`);if(!u.ok){const h=await u.json().catch(()=>({}));throw new Error(h.detail||`获取模型列表失败 (${u.status})`)}const x=await u.json();if(!x.success)throw new Error("获取模型列表失败");return x.models}async function o1(l){const i=new URLSearchParams({provider_name:l}),r=await we(`/api/webui/models/test-connection-by-name?${i}`,{method:"POST"});if(!r.ok){const o=await r.json().catch(()=>({}));throw new Error(o.detail||`测试连接失败 (${r.status})`)}return await r.json()}const d1=gi("relative w-full rounded-lg border px-4 py-3 text-sm [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground [&>svg~*]:pl-7",{variants:{variant:{default:"bg-background text-foreground",destructive:"border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive"}},defaultVariants:{variant:"default"}}),sa=m.forwardRef(({className:l,variant:i,...r},o)=>e.jsx("div",{ref:o,role:"alert",className:H(d1({variant:i}),l),...r}));sa.displayName="Alert";const u1=m.forwardRef(({className:l,...i},r)=>e.jsx("h5",{ref:r,className:H("mb-1 font-medium leading-none tracking-tight",l),...i}));u1.displayName="AlertTitle";const ta=m.forwardRef(({className:l,...i},r)=>e.jsx("div",{ref:r,className:H("text-sm [&_p]:leading-relaxed",l),...i}));ta.displayName="AlertDescription";const m1={name:"toml",startState:function(){return{inString:!1,stringType:"",lhs:!0,inArray:0}},token:function(l,i){let r;if(!i.inString&&(r=l.match(/^('''|"""|'|")/))&&(i.stringType=r[0],i.inString=!0),l.sol()&&!i.inString&&i.inArray===0&&(i.lhs=!0),i.inString){for(;i.inString;)if(l.match(i.stringType))i.inString=!1;else if(l.peek()==="\\")l.next(),l.next();else{if(l.eol())break;l.match(/^.[^\\\"\']*/)}return i.lhs?"property":"string"}else{if(i.inArray&&l.peek()==="]")return l.next(),i.inArray--,"bracket";if(i.lhs&&l.peek()==="["&&l.skipTo("]"))return l.next(),l.peek()==="]"&&l.next(),"atom";if(l.peek()==="#")return l.skipToEnd(),"comment";if(l.eatSpace())return null;if(i.lhs&&l.eatWhile(function(o){return o!="="&&o!=" "}))return"property";if(i.lhs&&l.peek()==="=")return l.next(),i.lhs=!1,null;if(!i.lhs&&l.match(/^\d\d\d\d[\d\-\:\.T]*Z/))return"atom";if(!i.lhs&&(l.match("true")||l.match("false")))return"atom";if(!i.lhs&&l.peek()==="[")return i.inArray++,l.next(),"bracket";if(!i.lhs&&l.match(/^\-?\d+(?:\.\d+)?/))return"number";l.eatSpace()||l.next()}return null},languageData:{commentTokens:{line:"#"}}},x1={python:[c0()],json:[o0(),d0()],toml:[r0.define(m1)],text:[]};function h1({value:l,onChange:i,language:r="text",readOnly:o=!1,height:u="400px",minHeight:x,maxHeight:h,placeholder:f,theme:g="dark",className:j=""}){const[v,y]=m.useState(!1);if(m.useEffect(()=>{y(!0)},[]),!v)return e.jsx("div",{className:`rounded-md border bg-muted animate-pulse ${j}`,style:{height:u,minHeight:x,maxHeight:h}});const b=[...x1[r]||[],gp.lineWrapping];return o&&b.push(gp.editable.of(!1)),e.jsx("div",{className:`rounded-md overflow-hidden border ${j}`,children:e.jsx(u0,{value:l,height:u,minHeight:x,maxHeight:h,theme:g==="dark"?m0:void 0,extensions:b,onChange:i,placeholder:f,basicSetup:{lineNumbers:!0,highlightActiveLineGutter:!0,highlightSpecialChars:!0,history:!0,foldGutter:!0,drawSelection:!0,dropCursor:!0,allowMultipleSelections:!0,indentOnInput:!0,syntaxHighlighting:!0,bracketMatching:!0,closeBrackets:!0,autocompletion:!0,rectangularSelection:!0,crosshairCursor:!0,highlightActiveLine:!0,highlightSelectionMatches:!0,closeBracketsKeymap:!0,defaultKeymap:!0,searchKeymap:!0,historyKeymap:!0,foldKeymap:!0,completionKeymap:!0,lintKeymap:!0}})})}function f1({id:l,index:i,itemType:r,itemFields:o,value:u,onChange:x,onRemove:h,disabled:f,canRemove:g,placeholder:j}){const{attributes:v,listeners:y,setNodeRef:b,transform:S,transition:w,isDragging:O}=Wg({id:l,disabled:f}),A={transform:ej.Transform.toString(S),transition:w};return e.jsxs("div",{ref:b,style:A,className:H("flex items-start gap-2 group",O&&"opacity-50 z-50"),children:[e.jsx("button",{type:"button",className:H("flex-shrink-0 p-2 cursor-grab active:cursor-grabbing","text-muted-foreground hover:text-foreground transition-colors","opacity-0 group-hover:opacity-100 focus:opacity-100",f&&"cursor-not-allowed opacity-30"),...v,...y,children:e.jsx(Lg,{className:"h-4 w-4"})}),e.jsx("div",{className:"flex-1 min-w-0",children:r==="object"&&o?e.jsx(p1,{value:u,onChange:x,fields:o,disabled:f}):r==="number"?e.jsx(ie,{type:"number",value:u??"",onChange:D=>x(parseFloat(D.target.value)||0),placeholder:j??`第 ${i+1} 项`,disabled:f,className:"font-mono"}):e.jsx(ie,{type:"text",value:u??"",onChange:D=>x(D.target.value),placeholder:j??`第 ${i+1} 项`,disabled:f})}),e.jsx(C,{type:"button",variant:"ghost",size:"icon",onClick:h,disabled:f||!g,className:H("flex-shrink-0 text-muted-foreground hover:text-destructive","opacity-0 group-hover:opacity-100 focus:opacity-100 transition-opacity"),children:e.jsx(es,{className:"h-4 w-4"})})]})}function p1({value:l,onChange:i,fields:r,disabled:o}){const u=m.useCallback((h,f)=>{i({...l,[h]:f})},[l,i]),x=(h,f)=>{const g=l?.[h];if(f.type==="boolean"||f.type==="switch")return e.jsxs("div",{className:"flex items-center justify-between py-1",children:[e.jsx(k,{className:"text-xs text-muted-foreground",children:f.label??h}),e.jsx(Fe,{checked:!!(g??f.default),onCheckedChange:j=>u(h,j),disabled:o})]});if(f.type==="slider"||f.type==="number"&&f.min!=null&&f.max!=null){const j=g??f.default??f.min??0;return e.jsxs("div",{className:"space-y-1",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(k,{className:"text-xs text-muted-foreground",children:f.label??h}),e.jsx("span",{className:"text-xs text-muted-foreground",children:j})]}),e.jsx(ma,{value:[j],onValueChange:v=>u(h,v[0]),min:f.min??0,max:f.max??100,step:f.step??1,disabled:o,className:"py-1"})]})}return f.type==="select"&&f.choices?e.jsxs("div",{className:"space-y-1",children:[e.jsx(k,{className:"text-xs text-muted-foreground",children:f.label??h}),e.jsxs(Ue,{value:String(g??f.default??""),onValueChange:j=>u(h,j),disabled:o,children:[e.jsx(Re,{className:"h-8 text-sm",children:e.jsx(Be,{placeholder:f.placeholder??"请选择"})}),e.jsx(Le,{children:f.choices.map(j=>e.jsx(ee,{value:String(j),children:String(j)},String(j)))})]})]}):f.type==="number"?e.jsxs("div",{className:"space-y-1",children:[e.jsx(k,{className:"text-xs text-muted-foreground",children:f.label??h}),e.jsx(ie,{type:"number",value:g??f.default??"",onChange:j=>u(h,parseFloat(j.target.value)||0),placeholder:f.placeholder,disabled:o,className:"h-8 text-sm"})]}):e.jsxs("div",{className:"space-y-1",children:[e.jsx(k,{className:"text-xs text-muted-foreground",children:f.label??h}),e.jsx(ie,{type:"text",value:g??f.default??"",onChange:j=>u(h,j.target.value),placeholder:f.placeholder,disabled:o,className:"h-8 text-sm"})]})};return e.jsx(Ve,{className:"p-3 space-y-2 bg-muted/30",children:Object.entries(r).map(([h,f])=>e.jsx("div",{children:x(h,f)},h))})}function g1({value:l,onChange:i,itemType:r="string",itemFields:o,minItems:u,maxItems:x,disabled:h,placeholder:f}){const g=m.useMemo(()=>Array.isArray(l)?l:typeof l=="string"&&l.trim()?l.split(",").map(z=>z.trim()):[],[l]),[j]=m.useState(()=>new Map),v=m.useCallback(z=>(j.has(z)||j.set(z,`item-${Date.now()}-${z}-${Math.random().toString(36).slice(2)}`),j.get(z)),[j]),y=m.useMemo(()=>{const z=[];for(let _=0;_{const{active:_,over:T}=z;if(T&&_.id!==T.id){const $=y.indexOf(_.id),E=y.indexOf(T.id),se=Xg(g,$,E);i(se)}},[g,y,i]),w=m.useCallback(()=>{if(x!=null&&g.length>=x)return;let z;r==="object"&&o?z=Object.fromEntries(Object.entries(o).map(([_,T])=>[_,T.default??""])):r==="number"?z=0:z="",i([...g,z])},[g,x,r,o,i]),O=m.useCallback((z,_)=>{const T=[...g];T[z]=_,i(T)},[g,i]),A=m.useCallback(z=>{if(u!=null&&g.length<=u)return;const _=g.filter((T,$)=>$!==z);j.delete(z),i(_)},[g,u,j,i]),D=x==null||g.lengthu;return e.jsxs("div",{className:"space-y-2",children:[g.length===0?e.jsxs("div",{className:"flex items-center gap-2 text-sm text-muted-foreground py-4 justify-center border border-dashed rounded-md",children:[e.jsx(Ot,{className:"h-4 w-4"}),e.jsx("span",{children:"暂无数据,点击下方按钮添加"})]}):e.jsx(Pg,{sensors:b,collisionDetection:Jg,onDragEnd:S,children:e.jsx(Zg,{items:y,strategy:x0,children:e.jsx("div",{className:"space-y-2",children:g.map((z,_)=>e.jsx(f1,{id:y[_],index:_,itemType:r,itemFields:o,value:z,onChange:T=>O(_,T),onRemove:()=>A(_),disabled:h,canRemove:V,placeholder:f},y[_]))})})}),e.jsxs(C,{type:"button",variant:"outline",size:"sm",onClick:w,disabled:h||!D,className:"w-full",children:[e.jsx(ut,{className:"h-4 w-4 mr-1"}),"添加项目",x!==void 0&&e.jsxs("span",{className:"ml-2 text-xs text-muted-foreground",children:["(",g.length,"/",x,")"]})]}),(u!=null||x!=null)&&(u!==null||x!==null)&&e.jsx("p",{className:"text-xs text-muted-foreground text-center",children:u!=null&&x!=null?`允许 ${u} - ${x} 项`:u!=null?`至少 ${u} 项`:`最多 ${x} 项`})]})}function j1(l,i,r,o={}){const{debounceMs:u=2e3,onSaveSuccess:x,onSaveError:h}=o,f=m.useRef(null),g=m.useCallback(async(b,S)=>{try{i(!0),await r1(b,S),r(!1),x?.()}catch(w){console.error(`自动保存 ${b} 失败:`,w),r(!0),h?.(w instanceof Error?w:new Error(String(w)))}finally{i(!1)}},[i,r,x,h]),j=m.useCallback((b,S)=>{l||(r(!0),f.current&&clearTimeout(f.current),f.current=setTimeout(()=>{g(b,S)},u))},[l,r,g,u]),v=m.useCallback(async(b,S)=>{f.current&&(clearTimeout(f.current),f.current=null),await g(b,S)},[g]),y=m.useCallback(()=>{f.current&&(clearTimeout(f.current),f.current=null)},[]);return m.useEffect(()=>()=>{f.current&&clearTimeout(f.current)},[]),{triggerAutoSave:j,saveNow:v,cancelPendingAutoSave:y}}function Ht(l,i,r,o){m.useEffect(()=>{l&&!r&&o(i,l)},[l])}const v1=500;function b1(){return e.jsx(jn,{children:e.jsx(N1,{})})}function N1(){const[l,i]=m.useState(!0),[r,o]=m.useState(!1),[u,x]=m.useState(!1),[h,f]=m.useState(!1),[g,j]=m.useState("visual"),[v,y]=m.useState(""),[b,S]=m.useState(!1),{toast:w}=Ks(),{triggerRestart:O,isRestarting:A}=Il(),[D,V]=m.useState(null),[z,_]=m.useState(null),[T,$]=m.useState(null),[E,se]=m.useState(null),[te,ne]=m.useState(null),[ue,Se]=m.useState(null),[oe,je]=m.useState(null),[be,U]=m.useState(null),[P,X]=m.useState(null),[L,B]=m.useState(null),[_e,Ne]=m.useState(null),[Ce,ve]=m.useState(null),[ze,Q]=m.useState(null),[xe,Te]=m.useState(null),[J,le]=m.useState(null),[qe,We]=m.useState(null),[fe,ls]=m.useState(null),G=m.useRef(!0),Me=m.useRef({}),re=m.useCallback(ye=>{Me.current=ye,V(ye.bot),_(ye.personality);const ps=ye.chat;ps.talk_value_rules||(ps.talk_value_rules=[]),$(ps),se(ye.expression),ne(ye.emoji),Se(ye.memory),je(ye.tool),U(ye.voice),X(ye.lpmm_knowledge),B(ye.keyword_reaction),Ne(ye.response_post_process),ve(ye.chinese_typo),Q(ye.response_splitter),Te(ye.log),le(ye.debug),We(ye.maim_message),ls(ye.telemetry)},[]),pe=m.useCallback(()=>({...Me.current,bot:D,personality:z,chat:T,expression:E,emoji:te,memory:ue,tool:oe,voice:be,lpmm_knowledge:P,keyword_reaction:L,response_post_process:_e,chinese_typo:Ce,response_splitter:ze,log:xe,debug:J,maim_message:qe,telemetry:fe}),[D,z,T,E,te,ue,oe,be,P,L,_e,Ce,ze,xe,J,qe,fe]),Ee=m.useCallback(async()=>{try{const ps=(await n1()).replace(/"([^"]*)"/g,(ss,Es)=>`"${Es.replace(/\\n/g,` +`).replace(/\\t/g," ").replace(/\\r/g,"\r").replace(/\\"/g,'"').replace(/\\\\/g,"\\")}"`);y(ps),S(!1)}catch(ye){w({variant:"destructive",title:"加载失败",description:ye instanceof Error?ye.message:"加载源代码失败"})}},[w]),Ie=m.useCallback(async()=>{try{i(!0);const ye=await kp();re(ye),f(!1),G.current=!1,await Ee()}catch(ye){console.error("加载配置失败:",ye),w({title:"加载失败",description:"无法加载配置文件",variant:"destructive"})}finally{i(!1)}},[w,Ee,re]);m.useEffect(()=>{Ie()},[Ie]);const{triggerAutoSave:$e,cancelPendingAutoSave:Vt}=j1(G.current,x,f);Ht(D,"bot",G.current,$e),Ht(z,"personality",G.current,$e),Ht(T,"chat",G.current,$e),Ht(E,"expression",G.current,$e),Ht(te,"emoji",G.current,$e),Ht(ue,"memory",G.current,$e),Ht(oe,"tool",G.current,$e),Ht(be,"voice",G.current,$e),Ht(P,"lpmm_knowledge",G.current,$e),Ht(L,"keyword_reaction",G.current,$e),Ht(_e,"response_post_process",G.current,$e),Ht(Ce,"chinese_typo",G.current,$e),Ht(ze,"response_splitter",G.current,$e),Ht(xe,"log",G.current,$e),Ht(J,"debug",G.current,$e),Ht(qe,"maim_message",G.current,$e),Ht(fe,"telemetry",G.current,$e);const _t=async()=>{try{o(!0);const ye=v.replace(/"([^"]*)"/g,(ps,ss)=>`"${ss.replace(/\\/g,"\\\\").replace(/"/g,'\\"').replace(/\n/g,"\\n").replace(/\t/g,"\\t").replace(/\r/g,"\\r")}"`);await i1(ye),f(!1),S(!1),w({title:"保存成功",description:"配置已保存"}),await Ie()}catch(ye){S(!0),w({variant:"destructive",title:"保存失败",description:ye instanceof Error?ye.message:"保存配置失败"})}finally{o(!1)}},nt=async ye=>{if(h){w({variant:"destructive",title:"切换失败",description:"请先保存当前更改"});return}if(j(ye),ye==="source")await Ee();else try{const ps=await kp();re(ps),f(!1)}catch(ps){console.error("加载配置失败:",ps),w({title:"加载失败",description:"无法加载配置文件",variant:"destructive"})}},F=async()=>{try{o(!0),Vt(),await Tp(pe()),f(!1),w({title:"保存成功",description:"麦麦主程序配置已保存"})}catch(ye){console.error("保存配置失败:",ye),w({title:"保存失败",description:ye.message,variant:"destructive"})}finally{o(!1)}},He=async()=>{await O()},De=async()=>{try{o(!0),Vt(),await Tp(pe()),f(!1),w({title:"保存成功",description:"配置已保存,即将重启麦麦..."}),await new Promise(ye=>setTimeout(ye,v1)),await He()}catch(ye){console.error("保存失败:",ye),w({title:"保存失败",description:ye.message,variant:"destructive"})}finally{o(!1)}};return l?e.jsx(Ze,{className:"h-full",children:e.jsx("div",{className:"space-y-4 sm:space-y-6 p-4 sm:p-6",children:e.jsx("div",{className:"flex items-center justify-center h-64",children:e.jsx("p",{className:"text-muted-foreground",children:"加载中..."})})})}):e.jsx(Ze,{className:"h-full",children:e.jsxs("div",{className:"space-y-4 sm:space-y-6 p-4 sm:p-6",children:[e.jsxs("div",{className:"flex flex-col gap-3 sm:gap-4",children:[e.jsxs("div",{className:"flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsx("h1",{className:"text-xl sm:text-2xl md:text-3xl font-bold",children:"麦麦主程序配置"}),e.jsx("p",{className:"text-muted-foreground mt-1 text-xs sm:text-sm",children:"管理麦麦的核心功能和行为设置"})]}),e.jsxs("div",{className:"flex gap-2 flex-shrink-0",children:[e.jsxs(C,{onClick:g==="visual"?F:_t,disabled:r||u||!h||A,size:"sm",variant:"outline",className:"w-20 sm:w-24",children:[e.jsx(Ar,{className:"h-4 w-4 flex-shrink-0",strokeWidth:2,fill:"none"}),e.jsx("span",{className:"ml-1 truncate text-xs sm:text-sm",children:r?"保存中":u?"自动":h?"保存":"已保存"})]}),e.jsxs(js,{children:[e.jsx(mt,{asChild:!0,children:e.jsxs(C,{disabled:r||u||A,size:"sm",className:"w-20 sm:w-28",children:[e.jsx(Mr,{className:"h-4 w-4 flex-shrink-0"}),e.jsx("span",{className:"ml-1 truncate text-xs sm:text-sm",children:A?"重启中":h?"保存重启":"重启"})]})}),e.jsxs(os,{children:[e.jsxs(ds,{children:[e.jsx(ms,{children:"确认重启麦麦?"}),e.jsx(xs,{asChild:!0,children:e.jsx("div",{children:e.jsx("p",{children:h?"当前有未保存的配置更改。点击确认将先保存配置,然后重启麦麦使新配置生效。重启过程中麦麦将暂时离线。":"即将重启麦麦主程序。重启过程中麦麦将暂时离线,配置将在重启后生效。"})})})]}),e.jsxs(us,{children:[e.jsx(fs,{children:"取消"}),e.jsx(hs,{onClick:h?De:He,children:h?"保存并重启":"确认重启"})]})]})]})]})]}),e.jsx("div",{className:"flex",children:e.jsx(Sa,{value:g,onValueChange:ye=>nt(ye),className:"w-full",children:e.jsxs(xa,{className:"h-8 sm:h-9 w-full grid grid-cols-2",children:[e.jsxs(is,{value:"visual",className:"text-xs sm:text-sm",children:[e.jsx($y,{className:"h-3 w-3 sm:h-4 sm:w-4 mr-1"}),"可视化编辑"]}),e.jsxs(is,{value:"source",className:"text-xs sm:text-sm",children:[e.jsx(qy,{className:"h-3 w-3 sm:h-4 sm:w-4 mr-1"}),"源代码编辑"]})]})})})]}),e.jsxs(sa,{children:[e.jsx(Ra,{className:"h-4 w-4"}),e.jsxs(ta,{children:["配置更新后需要",e.jsx("strong",{children:"重启麦麦"}),'才能生效。你可以点击右上角的"保存并重启"按钮一键完成保存和重启。']})]}),g==="source"&&e.jsxs("div",{className:"space-y-4",children:[e.jsxs(sa,{children:[e.jsx(Ra,{className:"h-4 w-4"}),e.jsxs(ta,{children:[e.jsx("strong",{children:"源代码模式(高级功能):"}),"直接编辑 TOML 配置文件。此功能仅适用于熟悉 TOML 语法的高级用户。保存时会在后端验证格式,只有格式完全正确才能保存。",b&&e.jsx("span",{className:"text-destructive font-semibold ml-2",children:"⚠️ 上次保存失败,请检查 TOML 格式"})]})]}),e.jsx(h1,{value:v,onChange:ye=>{y(ye),f(!0),b&&S(!1)},language:"toml",theme:"dark",height:"calc(100vh - 280px)",minHeight:"500px",placeholder:"TOML 配置内容"})]}),g==="visual"&&e.jsx(e.Fragment,{children:e.jsxs(Sa,{defaultValue:"bot",className:"w-full",children:[e.jsxs(xa,{className:"flex flex-wrap h-auto gap-1 p-1 sm:grid sm:grid-cols-5 lg:grid-cols-9",children:[e.jsx(is,{value:"bot",className:"text-xs px-2 py-1.5 sm:px-3 sm:py-2 data-[state=active]:shadow-sm",children:"基本信息"}),e.jsx(is,{value:"personality",className:"text-xs px-2 py-1.5 sm:px-3 sm:py-2 data-[state=active]:shadow-sm",children:"人格"}),e.jsx(is,{value:"chat",className:"text-xs px-2 py-1.5 sm:px-3 sm:py-2 data-[state=active]:shadow-sm",children:"聊天"}),e.jsx(is,{value:"expression",className:"text-xs px-2 py-1.5 sm:px-3 sm:py-2 data-[state=active]:shadow-sm",children:"表达"}),e.jsx(is,{value:"features",className:"text-xs px-2 py-1.5 sm:px-3 sm:py-2 data-[state=active]:shadow-sm",children:"功能"}),e.jsx(is,{value:"processing",className:"text-xs px-2 py-1.5 sm:px-3 sm:py-2 data-[state=active]:shadow-sm",children:"处理"}),e.jsx(is,{value:"voice",className:"text-xs px-2 py-1.5 sm:px-3 sm:py-2 data-[state=active]:shadow-sm",children:"语音"}),e.jsx(is,{value:"lpmm",className:"text-xs px-2 py-1.5 sm:px-3 sm:py-2 data-[state=active]:shadow-sm",children:"知识库"}),e.jsx(is,{value:"other",className:"text-xs px-2 py-1.5 sm:px-3 sm:py-2 data-[state=active]:shadow-sm",children:"其他"})]}),e.jsx(As,{value:"bot",className:"space-y-4",children:D&&e.jsx(qw,{config:D,onChange:V})}),e.jsx(As,{value:"personality",className:"space-y-4",children:z&&e.jsx(Gw,{config:z,onChange:_})}),e.jsx(As,{value:"chat",className:"space-y-4",children:T&&e.jsx(Yw,{config:T,onChange:$})}),e.jsx(As,{value:"expression",className:"space-y-4",children:E&&e.jsx(t1,{config:E,onChange:se})}),e.jsx(As,{value:"features",className:"space-y-4",children:te&&ue&&oe&&e.jsx(e1,{emojiConfig:te,memoryConfig:ue,toolConfig:oe,onEmojiChange:ne,onMemoryChange:Se,onToolChange:je})}),e.jsx(As,{value:"processing",className:"space-y-4",children:L&&_e&&Ce&&ze&&e.jsx(l1,{keywordReactionConfig:L,responsePostProcessConfig:_e,chineseTypoConfig:Ce,responseSplitterConfig:ze,onKeywordReactionChange:B,onResponsePostProcessChange:Ne,onChineseTypoChange:ve,onResponseSplitterChange:Q})}),e.jsx(As,{value:"voice",className:"space-y-4",children:be&&e.jsx(Kw,{config:be,onChange:U})}),e.jsx(As,{value:"lpmm",className:"space-y-4",children:P&&e.jsx(Xw,{config:P,onChange:X})}),e.jsxs(As,{value:"other",className:"space-y-4",children:[xe&&e.jsx(Pw,{config:xe,onChange:Te}),J&&e.jsx(Jw,{config:J,onChange:le}),qe&&e.jsx(Zw,{config:qe,onChange:We}),fe&&e.jsx(Ww,{config:fe,onChange:ls})]})]})}),e.jsx(vn,{})]})})}const bn=m.forwardRef(({className:l,...i},r)=>e.jsx("div",{className:"relative w-full overflow-auto",children:e.jsx("table",{ref:r,className:H("w-full caption-bottom text-sm",l),...i})}));bn.displayName="Table";const Nn=m.forwardRef(({className:l,...i},r)=>e.jsx("thead",{ref:r,className:H("[&_tr]:border-b",l),...i}));Nn.displayName="TableHeader";const yn=m.forwardRef(({className:l,...i},r)=>e.jsx("tbody",{ref:r,className:H("[&_tr:last-child]:border-0",l),...i}));yn.displayName="TableBody";const y1=m.forwardRef(({className:l,...i},r)=>e.jsx("tfoot",{ref:r,className:H("border-t bg-muted/50 font-medium [&>tr]:last:border-b-0",l),...i}));y1.displayName="TableFooter";const gt=m.forwardRef(({className:l,...i},r)=>e.jsx("tr",{ref:r,className:H("border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted",l),...i}));gt.displayName="TableRow";const Je=m.forwardRef(({className:l,...i},r)=>e.jsx("th",{ref:r,className:H("h-12 px-4 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",l),...i}));Je.displayName="TableHead";const Qe=m.forwardRef(({className:l,...i},r)=>e.jsx("td",{ref:r,className:H("px-4 py-3 align-middle [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",l),...i}));Qe.displayName="TableCell";const w1=m.forwardRef(({className:l,...i},r)=>e.jsx("caption",{ref:r,className:H("mt-4 text-sm text-muted-foreground",l),...i}));w1.displayName="TableCaption";const vo=m.forwardRef(({className:l,...i},r)=>e.jsx(la,{ref:r,className:H("flex h-full w-full flex-col overflow-hidden rounded-md bg-popover text-popover-foreground",l),...i}));vo.displayName=la.displayName;const bo=m.forwardRef(({className:l,...i},r)=>e.jsxs("div",{className:"flex items-center border-b px-3","cmdk-input-wrapper":"",children:[e.jsx($t,{className:"mr-2 h-4 w-4 shrink-0 opacity-50"}),e.jsx(la.Input,{ref:r,className:H("flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50",l),...i})]}));bo.displayName=la.Input.displayName;const No=m.forwardRef(({className:l,...i},r)=>e.jsx(la.List,{ref:r,className:H("max-h-[300px] overflow-y-auto overflow-x-hidden",l),...i}));No.displayName=la.List.displayName;const yo=m.forwardRef((l,i)=>e.jsx(la.Empty,{ref:i,className:"py-6 text-center text-sm",...l}));yo.displayName=la.Empty.displayName;const Cr=m.forwardRef(({className:l,...i},r)=>e.jsx(la.Group,{ref:r,className:H("overflow-hidden p-1 text-foreground [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground",l),...i}));Cr.displayName=la.Group.displayName;const _1=m.forwardRef(({className:l,...i},r)=>e.jsx(la.Separator,{ref:r,className:H("-mx-1 h-px bg-border",l),...i}));_1.displayName=la.Separator.displayName;const kr=m.forwardRef(({className:l,...i},r)=>e.jsx(la.Item,{ref:r,className:H("relative flex cursor-default gap-2 select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[disabled=true]:pointer-events-none data-[selected=true]:bg-accent data-[selected=true]:text-accent-foreground data-[disabled=true]:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",l),...i}));kr.displayName=la.Item.displayName;const jt=m.forwardRef(({className:l,...i},r)=>e.jsx(yg,{ref:r,className:H("grid place-content-center peer h-4 w-4 shrink-0 rounded-sm border border-primary shadow focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground",l),...i,children:e.jsx(gy,{className:H("grid place-content-center text-current"),children:e.jsx(ea,{className:"h-4 w-4"})})}));jt.displayName=yg.displayName;const jj=m.createContext(null),vj="maibot-completed-tours";function S1(){try{const l=localStorage.getItem(vj);return l?new Set(JSON.parse(l)):new Set}catch{return new Set}}function Ep(l){localStorage.setItem(vj,JSON.stringify([...l]))}function C1({children:l}){const[i,r]=m.useState({activeTourId:null,stepIndex:0,isRunning:!1}),o=m.useRef(new Map),[,u]=m.useState(0),[x,h]=m.useState(S1),f=m.useCallback((z,_)=>{o.current.set(z,_),u(T=>T+1)},[]),g=m.useCallback(z=>{o.current.delete(z),r(_=>_.activeTourId===z?{..._,activeTourId:null,isRunning:!1,stepIndex:0}:_)},[]),j=m.useCallback((z,_=0)=>{o.current.has(z)&&r({activeTourId:z,stepIndex:_,isRunning:!0})},[]),v=m.useCallback(()=>{r(z=>({...z,isRunning:!1}))},[]),y=m.useCallback(z=>{r(_=>({..._,stepIndex:z}))},[]),b=m.useCallback(()=>{r(z=>({...z,stepIndex:z.stepIndex+1}))},[]),S=m.useCallback(()=>{r(z=>({...z,stepIndex:Math.max(0,z.stepIndex-1)}))},[]),w=m.useCallback(()=>i.activeTourId?o.current.get(i.activeTourId)||[]:[],[i.activeTourId]),O=m.useCallback(z=>{h(_=>{const T=new Set(_);return T.add(z),Ep(T),T})},[]),A=m.useCallback(z=>{const{action:_,index:T,status:$,type:E}=z,se=["finished","skipped"];if(_==="close"){r(te=>({...te,isRunning:!1,stepIndex:0}));return}se.includes($)?r(te=>($==="finished"&&te.activeTourId&&setTimeout(()=>O(te.activeTourId),0),{...te,isRunning:!1,stepIndex:0})):E==="step:after"&&(_==="next"?r(te=>({...te,stepIndex:T+1})):_==="prev"&&r(te=>({...te,stepIndex:T-1})))},[O]),D=m.useCallback(z=>x.has(z),[x]),V=m.useCallback(z=>{h(_=>{const T=new Set(_);return T.delete(z),Ep(T),T})},[]);return e.jsx(jj.Provider,{value:{state:i,tours:o.current,registerTour:f,unregisterTour:g,startTour:j,stopTour:v,goToStep:y,nextStep:b,prevStep:S,getCurrentSteps:w,handleJoyrideCallback:A,isTourCompleted:D,markTourCompleted:O,resetTourCompleted:V},children:l})}function xm(){const l=m.useContext(jj);if(!l)throw new Error("useTour must be used within a TourProvider");return l}const k1={options:{zIndex:1e4,primaryColor:"hsl(var(--primary))",textColor:"hsl(var(--foreground))",backgroundColor:"hsl(var(--background))",arrowColor:"hsl(var(--background))",overlayColor:"rgba(0, 0, 0, 0.5)"},tooltip:{borderRadius:"var(--radius)",padding:"1rem"},tooltipContainer:{textAlign:"left"},tooltipTitle:{fontSize:"1rem",fontWeight:600,marginBottom:"0.5rem"},tooltipContent:{fontSize:"0.875rem",padding:"0.5rem 0"},buttonNext:{backgroundColor:"hsl(var(--primary))",color:"hsl(var(--primary-foreground))",borderRadius:"calc(var(--radius) - 2px)",fontSize:"0.875rem",padding:"0.5rem 1rem"},buttonBack:{color:"hsl(var(--muted-foreground))",fontSize:"0.875rem",marginRight:"0.5rem"},buttonSkip:{color:"hsl(var(--muted-foreground))",fontSize:"0.875rem"},buttonClose:{color:"hsl(var(--muted-foreground))"},spotlight:{borderRadius:"var(--radius)"}},T1={back:"上一步",close:"关闭",last:"完成",next:"下一步",nextLabelWithProgress:"下一步 ({step}/{steps})",open:"打开对话框",skip:"跳过"};function E1(){const{state:l,getCurrentSteps:i,handleJoyrideCallback:r}=xm(),o=i(),[u,x]=m.useState(!1),h=m.useRef(l.stepIndex),f=m.useRef(null);m.useEffect(()=>{h.current!==l.stepIndex&&(x(!1),h.current=l.stepIndex)},[l.stepIndex]),m.useEffect(()=>{if(!l.isRunning||o.length===0){x(!1);return}const v=o[l.stepIndex];if(!v){x(!1);return}const y=v.target;if(y==="body"){x(!0);return}x(!1);const b=setTimeout(()=>{const S=()=>{const D=document.querySelector(y);if(D){const V=D.getBoundingClientRect();if(V.width>0&&V.height>0)return!0}return!1};if(S()){setTimeout(()=>x(!0),100);return}const w=setInterval(()=>{S()&&(clearInterval(w),setTimeout(()=>x(!0),100))},100),O=setTimeout(()=>{clearInterval(w),x(!0)},5e3),A=()=>{clearInterval(w),clearTimeout(O)};f.current=A},150);return()=>{clearTimeout(b),f.current&&(f.current(),f.current=null)}},[l.isRunning,l.stepIndex,o]);const g=m.useRef(null);if(m.useEffect(()=>{let v=document.getElementById("tour-portal-container");return v||(v=document.createElement("div"),v.id="tour-portal-container",v.style.cssText="position: fixed; top: 0; left: 0; z-index: 99999; pointer-events: none;",document.body.appendChild(v)),g.current=v,()=>{}},[]),!l.isRunning||o.length===0||!u)return null;const j=e.jsx(f0,{steps:o,stepIndex:l.stepIndex,run:l.isRunning,continuous:!0,showSkipButton:!0,showProgress:!0,disableOverlayClose:!0,disableScrolling:!1,disableScrollParentFix:!1,callback:r,styles:k1,locale:T1,scrollOffset:80,scrollToFirstStep:!0,floaterProps:{styles:{floater:{zIndex:99999}},disableAnimation:!0}},`tour-step-${l.stepIndex}`);return g.current?jN.createPortal(j,g.current):j}const Ga="model-assignment-tour",bj=[{target:"body",content:"本引导旨在帮助你配置模型提供商和对应的模型,并为麦麦的各个组件分配合适的模型。",placement:"center",disableBeacon:!0,disableOverlayClose:!0,hideCloseButton:!1,spotlightClicks:!1},{target:'[data-tour="sidebar-model-provider"]',content:'第一步,你需要配置模型提供商。模型提供商决定了你要使用谁家的模型,无论是单一厂商(如 DeepSeek),还是模型平台(如 Siliconflow),都可以在这里进行配置。点击"下一步"进入配置页面。',placement:"right",disableBeacon:!0,disableOverlayClose:!0,hideCloseButton:!1,spotlightClicks:!1},{target:'[data-tour="add-provider-button"]',content:'点击"添加提供商"按钮,开始配置你的模型提供商。',placement:"bottom",disableBeacon:!0,disableOverlayClose:!0,hideCloseButton:!1,spotlightClicks:!0,hideFooter:!0},{target:'[data-tour="provider-dialog"]',content:"在这里,你可以选择你想要配置的模型提供商,填写相关信息后保存即可。",placement:"left",disableBeacon:!0,disableOverlayClose:!0,hideCloseButton:!1,spotlightClicks:!1},{target:'[data-tour="provider-name-input"]',content:"这里的名称是你为这个模型提供商起的一个名字,方便你在后续使用时识别它。",placement:"bottom",disableBeacon:!0,disableOverlayClose:!0,hideCloseButton:!1,spotlightClicks:!1},{target:'[data-tour="provider-apikey-input"]',content:"这里需要填写你从模型提供商那里获取的 API 密钥,用于验证和调用模型服务。对于不同的提供商,获取 API 密钥的方式可能有所不同,请参考对应提供商的文档。",placement:"bottom",disableBeacon:!0,disableOverlayClose:!0,hideCloseButton:!1,spotlightClicks:!1},{target:'[data-tour="provider-url-input"]',content:"这里需要填写模型提供商的 API 访问地址,确保填写正确以便系统能够连接到模型服务。对于不同的提供商,API 地址可能有所不同,请参考对应提供商的文档。",placement:"bottom",disableBeacon:!0,disableOverlayClose:!0,hideCloseButton:!1,spotlightClicks:!1},{target:'[data-tour="provider-template-select"]',content:"当然,如果你不知道如何填写这些信息,很多模型提供商在这里都提供了预设的模板供你选择,选择对应的模板后,相关信息会自动填充。",placement:"bottom",disableBeacon:!0,disableOverlayClose:!0,hideCloseButton:!1,spotlightClicks:!1},{target:'[data-tour="provider-save-button"]',content:"填写完所有信息后,点击保存按钮,模型提供商就配置完成了。",placement:"top",disableBeacon:!0,disableOverlayClose:!0,hideCloseButton:!1,spotlightClicks:!1},{target:'[data-tour="provider-cancel-button"]',content:"因为这次咱们什么都没有填写,所以点击取消按钮退出吧。",placement:"top",disableBeacon:!0,disableOverlayClose:!0,hideCloseButton:!1,spotlightClicks:!0,hideFooter:!0},{target:'[data-tour="sidebar-model-management"]',content:'配置好模型提供商后,接下来我们需要为麦麦添加模型并分配功能。点击"下一步"进入模型管理页面。',placement:"right",disableBeacon:!0,disableOverlayClose:!0,hideCloseButton:!1,spotlightClicks:!1},{target:'[data-tour="add-model-button"]',content:'在为麦麦的组件分配模型之前,首先需要添加你想要分配的模型,点击"添加模型"按钮开始添加。',placement:"bottom",disableBeacon:!0,disableOverlayClose:!0,hideCloseButton:!1,spotlightClicks:!0,hideFooter:!0},{target:'[data-tour="model-dialog"]',content:"在这里,你可以选择你之前配置好的模型提供商,然后选择对应的模型来添加。",placement:"left",disableBeacon:!0,disableOverlayClose:!0,hideCloseButton:!1,spotlightClicks:!1},{target:'[data-tour="model-name-input"]',content:"这里的模型名称是你为这个模型起的一个名字,方便你在后续使用时识别它。",placement:"bottom",disableBeacon:!0,disableOverlayClose:!0,hideCloseButton:!1,spotlightClicks:!1},{target:'[data-tour="model-provider-select"]',content:"在这里选择你之前配置好的模型提供商,这样系统才能知道你要添加哪个提供商的模型。",placement:"bottom",disableBeacon:!0,disableOverlayClose:!0,hideCloseButton:!1,spotlightClicks:!1},{target:'[data-tour="model-identifier-input"]',content:"这里需要填写你想要添加的模型的标识符,不同的模型提供商可能有不同的标识符格式,请参考对应提供商的文档。",placement:"bottom",disableBeacon:!0,disableOverlayClose:!0,hideCloseButton:!1,spotlightClicks:!1},{target:'[data-tour="model-save-button"]',content:"填写完所有信息后,点击保存按钮,模型就添加完成了。",placement:"top",disableBeacon:!0,disableOverlayClose:!0,hideCloseButton:!1,spotlightClicks:!1},{target:'[data-tour="model-cancel-button"]',content:"当然,因为这次咱们什么都没有填写,所以直接点击取消按钮退出吧,等你准备好了再来添加模型。",placement:"top",disableBeacon:!0,disableOverlayClose:!0,hideCloseButton:!1,spotlightClicks:!0,hideFooter:!0},{target:'[data-tour="tasks-tab-trigger"]',content:'最后一步,添加好模型后,切换到"为模型分配功能"标签页,为麦麦的各个组件分配合适的模型。',placement:"bottom",disableBeacon:!0,disableOverlayClose:!0,hideCloseButton:!1,spotlightClicks:!0,hideFooter:!0},{target:'[data-tour="task-model-select"]',content:"在这里,你可以为每个组件选择一个或多个合适的模型,选择完成后配置会自动保存。恭喜你完成了模型配置的学习!",placement:"bottom",disableBeacon:!0,disableOverlayClose:!0,hideCloseButton:!1,spotlightClicks:!1}],Nj={0:"/config/model",1:"/config/model",2:"/config/modelProvider",3:"/config/modelProvider",4:"/config/modelProvider",5:"/config/modelProvider",6:"/config/modelProvider",7:"/config/modelProvider",8:"/config/modelProvider",9:"/config/modelProvider",10:"/config/modelProvider",11:"/config/model",12:"/config/model",13:"/config/model",14:"/config/model",15:"/config/model",16:"/config/model",17:"/config/model",18:"/config/model",19:"/config/model"},pr=[{id:"siliconflow",name:"SiliconFlow",base_url:"https://api.siliconflow.cn/v1",client_type:"openai",display_name:"硅基流动 (SiliconFlow)",modelFetcher:{endpoint:"/models",parser:"openai"}},{id:"deepseek",name:"DeepSeek",base_url:"https://api.deepseek.com",client_type:"openai",display_name:"DeepSeek",modelFetcher:{endpoint:"/models",parser:"openai"}},{id:"rinkoai",name:"RinkoAI",base_url:"https://rinkoai.com/v1",client_type:"openai",display_name:"RinkoAI",modelFetcher:{endpoint:"/models",parser:"openai"}},{id:"zhipu",name:"ZhipuAI",base_url:"https://open.bigmodel.cn/api/paas/v4",client_type:"openai",display_name:"智谱 AI (ZhipuAI / GLM)",modelFetcher:{endpoint:"/models",parser:"openai"}},{id:"moonshot",name:"Moonshot",base_url:"https://api.moonshot.cn/v1",client_type:"openai",display_name:"月之暗面 (Moonshot / Kimi)",modelFetcher:{endpoint:"/models",parser:"openai"}},{id:"doubao",name:"Doubao",base_url:"https://ark.cn-beijing.volces.com/api/v3",client_type:"openai",display_name:"字节豆包 (Doubao)",modelFetcher:{endpoint:"/models",parser:"openai"}},{id:"alibaba",name:"Alibaba",base_url:"https://dashscope.aliyuncs.com/compatible-mode/v1",client_type:"openai",display_name:"阿里云百炼 (Alibaba Qwen)",modelFetcher:{endpoint:"/models",parser:"openai"}},{id:"baichuan",name:"Baichuan",base_url:"https://api.baichuan-ai.com/v1",client_type:"openai",display_name:"百川智能 (Baichuan)",modelFetcher:{endpoint:"/models",parser:"openai"}},{id:"minimax",name:"MiniMax",base_url:"https://api.minimax.chat/v1",client_type:"openai",display_name:"MiniMax (海螺 AI)",modelFetcher:{endpoint:"/models",parser:"openai"}},{id:"stepfun",name:"StepFun",base_url:"https://api.stepfun.com/v1",client_type:"openai",display_name:"阶跃星辰 (StepFun)",modelFetcher:{endpoint:"/models",parser:"openai"}},{id:"lingyi",name:"Lingyi",base_url:"https://api.lingyiwanwu.com/v1",client_type:"openai",display_name:"零一万物 (Lingyi / Yi)",modelFetcher:{endpoint:"/models",parser:"openai"}},{id:"openai",name:"OpenAI",base_url:"https://api.openai.com/v1",client_type:"openai",display_name:"OpenAI",modelFetcher:{endpoint:"/models",parser:"openai"}},{id:"xai",name:"xAI",base_url:"https://api.x.ai/v1",client_type:"openai",display_name:"xAI (Grok)",modelFetcher:{endpoint:"/models",parser:"openai"}},{id:"anthropic",name:"Anthropic",base_url:"https://api.anthropic.com/v1",client_type:"openai",display_name:"Anthropic (Claude)"},{id:"gemini",name:"Gemini",base_url:"https://generativelanguage.googleapis.com/v1beta",client_type:"gemini",display_name:"Google Gemini",modelFetcher:{endpoint:"/models",parser:"gemini"}},{id:"cohere",name:"Cohere",base_url:"https://api.cohere.ai/v1",client_type:"openai",display_name:"Cohere"},{id:"groq",name:"Groq",base_url:"https://api.groq.com/openai/v1",client_type:"openai",display_name:"Groq",modelFetcher:{endpoint:"/models",parser:"openai"}},{id:"together",name:"Together AI",base_url:"https://api.together.xyz/v1",client_type:"openai",display_name:"Together AI",modelFetcher:{endpoint:"/models",parser:"openai"}},{id:"fireworks",name:"Fireworks",base_url:"https://api.fireworks.ai/inference/v1",client_type:"openai",display_name:"Fireworks AI",modelFetcher:{endpoint:"/models",parser:"openai"}},{id:"mistral",name:"Mistral",base_url:"https://api.mistral.ai/v1",client_type:"openai",display_name:"Mistral AI",modelFetcher:{endpoint:"/models",parser:"openai"}},{id:"perplexity",name:"Perplexity",base_url:"https://api.perplexity.ai",client_type:"openai",display_name:"Perplexity AI"},{id:"custom",name:"",base_url:"",client_type:"openai",display_name:"自定义"}];function zp(l){return l?l.replace(/\/+$/,"").toLowerCase():""}function z1(l){if(!l)return null;const i=zp(l);return pr.find(r=>r.id!=="custom"&&zp(r.base_url)===i)||null}const Wc=l=>({...l,max_retry:l.max_retry??2,timeout:l.timeout??30,retry_interval:l.retry_interval??10}),M1=l=>{const i={};return l?(l.name?.trim()||(i.name="请输入提供商名称"),l.base_url?.trim()||(i.base_url="请输入基础 URL"),l.api_key?.trim()||(i.api_key="请输入 API Key"),{isValid:Object.keys(i).length===0,errors:i}):{isValid:!1,errors:{name:"提供商数据为空"}}};function A1(){return e.jsx(jn,{children:e.jsx(O1,{})})}function O1(){const[l,i]=m.useState([]),[r,o]=m.useState(!0),[u,x]=m.useState(!1),[h,f]=m.useState(!1),[g,j]=m.useState(!1),[v,y]=m.useState(!1),[b,S]=m.useState(null),[w,O]=m.useState(null),[A,D]=m.useState("custom"),[V,z]=m.useState(!1),[_,T]=m.useState(!1),[$,E]=m.useState(null),[se,te]=m.useState(!1),[ne,ue]=m.useState(""),[Se,oe]=m.useState(new Set),[je,be]=m.useState(!1),[U,P]=m.useState(1),[X,L]=m.useState(20),[B,_e]=m.useState(""),[Ne,Ce]=m.useState({isOpen:!1,providersToDelete:[],affectedModels:[],pendingProviders:[],context:"auto",oldProviders:[]}),[ve,ze]=m.useState({}),[Q,xe]=m.useState(new Set),[Te,J]=m.useState(new Map),{toast:le}=Ks(),qe=ka(),{state:We,goToStep:fe,registerTour:ls}=xm(),{triggerRestart:G,isRestarting:Me}=Il(),re=m.useRef(null),pe=m.useRef(!0);m.useEffect(()=>{ls(Ga,bj)},[ls]),m.useEffect(()=>{if(We.activeTourId===Ga&&We.isRunning){const I=Nj[We.stepIndex];I&&!window.location.pathname.endsWith(I.replace("/config/",""))&&qe({to:I})}},[We.stepIndex,We.activeTourId,We.isRunning,qe]);const Ee=m.useRef(We.stepIndex);m.useEffect(()=>{if(We.activeTourId===Ga&&We.isRunning){const I=Ee.current,ge=We.stepIndex;I>=3&&I<=9&&ge<3&&y(!1),I>=10&&ge>=3&&ge<=9&&(ze({}),D("custom"),S({name:"",base_url:"",api_key:"",client_type:"openai",max_retry:2,timeout:30,retry_interval:10}),O(null),te(!1),y(!0)),Ee.current=ge}},[We.stepIndex,We.activeTourId,We.isRunning]),m.useEffect(()=>{if(We.activeTourId!==Ga||!We.isRunning)return;const I=ge=>{const ke=ge.target,Us=We.stepIndex;Us===2&&ke.closest('[data-tour="add-provider-button"]')?setTimeout(()=>fe(3),300):Us===9&&ke.closest('[data-tour="provider-cancel-button"]')&&setTimeout(()=>fe(10),300)};return document.addEventListener("click",I,!0),()=>document.removeEventListener("click",I,!0)},[We,fe]),m.useEffect(()=>{Ie()},[]);const Ie=async()=>{try{o(!0);const I=await Gl();i(I.api_providers||[]),j(!1),pe.current=!1}catch(I){console.error("加载配置失败:",I)}finally{o(!1)}},$e=async()=>{await G()},Vt=async()=>{try{x(!0),re.current&&clearTimeout(re.current);const I=l.map(it=>({...it,max_retry:it.max_retry??2,timeout:it.timeout??30,retry_interval:it.retry_interval??10})),{shouldProceed:ge}=await _t(I,"restart");if(!ge){x(!1);return}const ke=await Gl(),Us=new Set(I.map(it=>it.name)),Ft=(ke.models||[]).filter(it=>Us.has(it.api_provider));ke.api_providers=I,ke.models=Ft,await Nr(ke),j(!1),le({title:"保存成功",description:"正在重启麦麦..."}),await $e()}catch(I){console.error("保存配置失败:",I),le({title:"保存失败",description:I.message,variant:"destructive"}),x(!1)}},_t=m.useCallback(async(I,ge="auto")=>{try{const ke=await Gl(),Us=new Set(l.map(ht=>ht.name)),Ua=new Set(I.map(ht=>ht.name)),Ft=Array.from(Us).filter(ht=>!Ua.has(ht));if(Ft.length===0)return{shouldProceed:!0,providers:I};const It=(ke.models||[]).filter(ht=>Ft.includes(ht.api_provider));return It.length===0?{shouldProceed:!0,providers:I}:(Ce({isOpen:!0,providersToDelete:Ft,affectedModels:It,pendingProviders:I,context:ge,oldProviders:[...l]}),{shouldProceed:!1,providers:I})}catch(ke){return console.error("检查删除影响失败:",ke),{shouldProceed:!0,providers:I}}},[l]),nt=async()=>{try{(Ne.context==="auto"?f:x)(!0),Ce(ht=>({...ht,isOpen:!1}));const ge=await Gl(),ke=Ne.pendingProviders.map(Wc),Us=new Set(ke.map(ht=>ht.name)),Ft=(ge.models||[]).filter(ht=>Us.has(ht.api_provider)),it=new Set(Ne.affectedModels.map(ht=>ht.name)),It=ge.model_task_config;It&&Object.keys(It).forEach(ht=>{const Kl=It[ht];Kl&&Array.isArray(Kl.model_list)&&(Kl.model_list=Kl.model_list.filter(Lr=>!it.has(Lr)))}),ge.api_providers=ke,ge.models=Ft,ge.model_task_config=It,await Nr(ge),i(Ne.pendingProviders),j(!1),le({title:"删除成功",description:`已删除 ${Ne.providersToDelete.length} 个提供商和 ${Ne.affectedModels.length} 个关联模型`}),Ce({isOpen:!1,providersToDelete:[],affectedModels:[],pendingProviders:[],context:"auto",oldProviders:[]}),oe(new Set),Ne.context==="restart"&&await $e()}catch(I){console.error("删除失败:",I),le({title:"删除失败",description:I.message,variant:"destructive"})}finally{Ne.context==="auto"?f(!1):x(!1)}},F=()=>{Ne.oldProviders.length>0&&i(Ne.oldProviders),Ce({isOpen:!1,providersToDelete:[],affectedModels:[],pendingProviders:[],context:"auto",oldProviders:[]}),j(!1)},He=m.useCallback(async I=>{if(pe.current)return;const{shouldProceed:ge}=await _t(I,"auto");if(!ge){j(!0);return}try{f(!0);const ke=I.map(Wc);await am("api_providers",ke),j(!1)}catch(ke){console.error("自动保存失败:",ke),le({title:"自动保存失败",description:ke.message,variant:"destructive"}),j(!0)}finally{f(!1)}},[l,_t]);m.useEffect(()=>{if(!pe.current)return j(!0),re.current&&clearTimeout(re.current),re.current=setTimeout(()=>{He(l)},2e3),()=>{re.current&&clearTimeout(re.current)}},[l,He]);const De=async()=>{try{x(!0),re.current&&clearTimeout(re.current);const I=l.map(Wc),{shouldProceed:ge}=await _t(I,"manual");if(!ge){x(!1);return}const ke=await Gl(),Us=new Set(I.map(it=>it.name)),Ua=ke.models||[],Ft=Ua.filter(it=>{const It=Us.has(it.api_provider);return It||console.warn(`模型 "${it.name}" 引用了已删除的提供商 "${it.api_provider}",将被移除`),It});if(Ua.length!==Ft.length){const it=Ua.length-Ft.length;le({title:"注意",description:`已自动移除 ${it} 个引用已删除提供商的模型`,variant:"default"})}console.log("发送的 providers 数据:",I),ke.api_providers=I,ke.models=Ft,console.log("完整配置数据:",ke),await Nr(ke),j(!1),le({title:"保存成功",description:"模型提供商配置已保存"})}catch(I){console.error("保存配置失败:",I),le({title:"保存失败",description:I.message,variant:"destructive"})}finally{x(!1)}},ye=(I,ge)=>{if(ze({}),I){const ke=pr.find(Us=>Us.base_url===I.base_url&&Us.client_type===I.client_type);D(ke?.id||"custom"),S(I)}else D("custom"),S({name:"",base_url:"",api_key:"",client_type:"openai",max_retry:2,timeout:30,retry_interval:10});O(ge),te(!1),y(!0)},ps=m.useCallback(I=>{D(I),z(!1);const ge=pr.find(ke=>ke.id===I);ge&&ge.id!=="custom"?S(ke=>({...ke,name:ge.name,base_url:ge.base_url,client_type:ge.client_type})):ge?.id==="custom"&&S(ke=>({...ke,name:"",base_url:"",client_type:"openai"}))},[]),ss=m.useMemo(()=>A!=="custom",[A]),Es=m.useCallback(async()=>{if(b?.api_key)try{await navigator.clipboard.writeText(b.api_key),le({title:"复制成功",description:"API Key 已复制到剪贴板"})}catch{le({title:"复制失败",description:"无法访问剪贴板",variant:"destructive"})}},[b?.api_key,le]),Ms=()=>{if(!b)return;const{isValid:I,errors:ge}=M1(b);if(!I){ze(ge);return}ze({});const ke=Wc(b);if(w!==null){const Us=[...l];Us[w]=ke,i(Us)}else i([...l,ke]);y(!1),S(null),O(null)},Ls=I=>{if(!I&&b){const ge={...b,max_retry:b.max_retry??2,timeout:b.timeout??30,retry_interval:b.retry_interval??10};S(ge)}y(I)},ts=I=>{E(I),T(!0)},Pe=async()=>{if($!==null){const I=l.filter((ke,Us)=>Us!==$),{shouldProceed:ge}=await _t(I,"manual");ge&&(i(I),le({title:"删除成功",description:"提供商已从列表中移除"}))}T(!1),E(null)},Xe=I=>{const ge=new Set(Se);ge.has(I)?ge.delete(I):ge.add(I),oe(ge)},Os=()=>{if(Se.size===Ss.length)oe(new Set);else{const I=Ss.map((ge,ke)=>l.findIndex(Us=>Us===Ss[ke]));oe(new Set(I))}},kt=()=>{if(Se.size===0){le({title:"提示",description:"请先选择要删除的提供商",variant:"default"});return}be(!0)},Xs=async()=>{const I=l.filter((ke,Us)=>!Se.has(Us)),{shouldProceed:ge}=await _t(I,"manual");ge&&(i(I),oe(new Set),le({title:"批量删除成功",description:`已删除 ${Se.size} 个提供商`})),be(!1)},Ss=m.useMemo(()=>{if(!ne)return l;const I=ne.toLowerCase();return l.filter(ge=>ge.name.toLowerCase().includes(I)||ge.base_url.toLowerCase().includes(I)||ge.client_type.toLowerCase().includes(I))},[l,ne]),{totalPages:xt,paginatedProviders:W}=m.useMemo(()=>{const I=Math.ceil(Ss.length/X),ge=Ss.slice((U-1)*X,U*X);return{totalPages:I,paginatedProviders:ge}},[Ss,U,X]),de=m.useCallback(()=>{const I=parseInt(B);I>=1&&I<=xt&&(P(I),_e(""))},[B,xt]),ys=async I=>{xe(ge=>new Set(ge).add(I));try{const ge=await o1(I);J(ke=>new Map(ke).set(I,ge)),ge.network_ok?ge.api_key_valid===!0?le({title:"连接正常",description:`${I} 网络连接正常,API Key 有效 (${ge.latency_ms}ms)`}):ge.api_key_valid===!1?le({title:"连接正常但 Key 无效",description:`${I} 网络连接正常,但 API Key 无效或已过期`,variant:"destructive"}):le({title:"网络连接正常",description:`${I} 可以访问 (${ge.latency_ms}ms)`}):le({title:"连接失败",description:ge.error||"无法连接到提供商",variant:"destructive"})}catch(ge){le({title:"测试失败",description:ge.message,variant:"destructive"})}finally{xe(ge=>{const ke=new Set(ge);return ke.delete(I),ke})}},Tt=async()=>{for(const I of l)await ys(I.name)},Et=I=>{const ge=Q.has(I),ke=Te.get(I);return ge?e.jsxs(Ye,{variant:"secondary",className:"gap-1",children:[e.jsx(tt,{className:"h-3 w-3 animate-spin"}),"测试中"]}):ke?ke.network_ok?ke.api_key_valid===!0?e.jsxs(Ye,{className:"gap-1 bg-green-600 hover:bg-green-700",children:[e.jsx(aa,{className:"h-3 w-3"}),"正常"]}):ke.api_key_valid===!1?e.jsxs(Ye,{variant:"destructive",className:"gap-1",children:[e.jsx(Ot,{className:"h-3 w-3"}),"Key无效"]}):e.jsxs(Ye,{className:"gap-1 bg-blue-600 hover:bg-blue-700",children:[e.jsx(aa,{className:"h-3 w-3"}),"可访问"]}):e.jsxs(Ye,{variant:"destructive",className:"gap-1",children:[e.jsx(Mg,{className:"h-3 w-3"}),"离线"]}):null};return r?e.jsx("div",{className:"space-y-4 sm:space-y-6 p-4 sm:p-6",children:e.jsx("div",{className:"flex items-center justify-center h-64",children:e.jsx("p",{className:"text-muted-foreground",children:"加载中..."})})}):e.jsxs("div",{className:"space-y-4 sm:space-y-6 p-4 sm:p-6",children:[e.jsxs("div",{className:"flex flex-col sm:flex-row sm:items-center justify-between gap-4",children:[e.jsxs("div",{children:[e.jsx("h1",{className:"text-2xl sm:text-3xl font-bold",children:"AI模型厂商配置"}),e.jsx("p",{className:"text-muted-foreground mt-1 sm:mt-2 text-sm sm:text-base",children:"管理 AI 模型厂商的 API 配置"})]}),e.jsxs("div",{className:"flex flex-col sm:flex-row gap-2",children:[Se.size>0&&e.jsxs(C,{onClick:kt,size:"sm",variant:"destructive",className:"w-full sm:w-auto",children:[e.jsx(es,{className:"mr-2 h-4 w-4",strokeWidth:2,fill:"none"}),"批量删除 (",Se.size,")"]}),e.jsxs(C,{onClick:Tt,size:"sm",variant:"outline",className:"w-full sm:w-auto",disabled:l.length===0||Q.size>0,children:[e.jsx(hn,{className:"mr-2 h-4 w-4"}),Q.size>0?`测试中 (${Q.size})`:"测试全部"]}),e.jsxs(C,{onClick:()=>ye(null,null),size:"sm",className:"w-full sm:w-auto","data-tour":"add-provider-button",children:[e.jsx(ut,{className:"mr-2 h-4 w-4",strokeWidth:2,fill:"none"}),"添加提供商"]}),e.jsxs(C,{onClick:De,disabled:u||h||!g||Me,size:"sm",variant:"outline",className:"w-full sm:w-auto sm:min-w-[120px]",children:[e.jsx(Ar,{className:"mr-2 h-4 w-4",strokeWidth:2,fill:"none"}),u?"保存中...":h?"自动保存中...":g?"保存配置":"已保存"]}),e.jsxs(js,{children:[e.jsx(mt,{asChild:!0,children:e.jsxs(C,{disabled:u||h||Me,size:"sm",className:"w-full sm:w-auto sm:min-w-[120px]",children:[e.jsx(Mr,{className:"mr-2 h-4 w-4"}),Me?"重启中...":g?"保存并重启":"重启麦麦"]})}),e.jsxs(os,{children:[e.jsxs(ds,{children:[e.jsx(ms,{children:"确认重启麦麦?"}),e.jsx(xs,{asChild:!0,children:e.jsx("div",{children:e.jsx("p",{children:g?"当前有未保存的配置更改。点击确认将先保存配置,然后重启麦麦使新配置生效。重启过程中麦麦将暂时离线。":"即将重启麦麦主程序。重启过程中麦麦将暂时离线,配置将在重启后生效。"})})})]}),e.jsxs(us,{children:[e.jsx(fs,{children:"取消"}),e.jsx(hs,{onClick:g?Vt:$e,children:g?"保存并重启":"确认重启"})]})]})]})]})]}),e.jsxs(sa,{children:[e.jsx(Ra,{className:"h-4 w-4"}),e.jsxs(ta,{children:["配置更新后需要",e.jsx("strong",{children:"重启麦麦"}),'才能生效。你可以点击右上角的"保存并重启"按钮一键完成保存和重启。']})]}),e.jsxs(Ze,{className:"h-[calc(100vh-260px)]",children:[e.jsxs("div",{className:"flex flex-col sm:flex-row items-start sm:items-center gap-2 mb-4",children:[e.jsxs("div",{className:"relative w-full sm:flex-1 sm:max-w-sm",children:[e.jsx($t,{className:"absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground"}),e.jsx(ie,{placeholder:"搜索提供商名称、URL 或类型...",value:ne,onChange:I=>ue(I.target.value),className:"pl-9"})]}),ne&&e.jsxs("p",{className:"text-sm text-muted-foreground whitespace-nowrap",children:["找到 ",Ss.length," 个结果"]})]}),e.jsx("div",{className:"md:hidden space-y-3",children:Ss.length===0?e.jsx("div",{className:"text-center text-muted-foreground py-8 rounded-lg border bg-card",children:ne?"未找到匹配的提供商":'暂无提供商配置,点击"添加提供商"开始配置'}):W.map((I,ge)=>{const ke=l.findIndex(Us=>Us===I);return e.jsxs("div",{className:"rounded-lg border bg-card p-4 space-y-3",children:[e.jsxs("div",{className:"flex items-start justify-between gap-2",children:[e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsxs("div",{className:"flex items-center gap-2 flex-wrap",children:[e.jsx("h3",{className:"font-semibold text-base truncate",children:I.name}),Et(I.name)]}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1 break-all",children:I.base_url})]}),e.jsxs("div",{className:"flex gap-1 flex-shrink-0",children:[e.jsx(C,{variant:"outline",size:"sm",onClick:()=>ys(I.name),disabled:Q.has(I.name),title:"测试连接",children:Q.has(I.name)?e.jsx(tt,{className:"h-4 w-4 animate-spin"}):e.jsx(hn,{className:"h-4 w-4"})}),e.jsx(C,{variant:"default",size:"sm",onClick:()=>ye(I,ke),children:e.jsx(fn,{className:"h-4 w-4",strokeWidth:2,fill:"none"})}),e.jsx(C,{size:"sm",onClick:()=>ts(ke),className:"bg-red-600 hover:bg-red-700 text-white",children:e.jsx(es,{className:"h-4 w-4",strokeWidth:2,fill:"none"})})]})]}),e.jsxs("div",{className:"grid grid-cols-2 gap-2 text-sm",children:[e.jsxs("div",{children:[e.jsx("span",{className:"text-muted-foreground text-xs",children:"客户端类型"}),e.jsx("p",{className:"font-medium",children:I.client_type})]}),e.jsxs("div",{children:[e.jsx("span",{className:"text-muted-foreground text-xs",children:"最大重试"}),e.jsx("p",{className:"font-medium",children:I.max_retry})]}),e.jsxs("div",{children:[e.jsx("span",{className:"text-muted-foreground text-xs",children:"超时(秒)"}),e.jsx("p",{className:"font-medium",children:I.timeout})]}),e.jsxs("div",{children:[e.jsx("span",{className:"text-muted-foreground text-xs",children:"重试间隔(秒)"}),e.jsx("p",{className:"font-medium",children:I.retry_interval})]})]})]},ge)})}),e.jsx("div",{className:"hidden md:block rounded-lg border bg-card overflow-hidden",children:e.jsx("div",{className:"overflow-x-auto",children:e.jsxs(bn,{children:[e.jsx(Nn,{children:e.jsxs(gt,{children:[e.jsx(Je,{className:"w-12",children:e.jsx(jt,{checked:Se.size===Ss.length&&Ss.length>0,onCheckedChange:Os})}),e.jsx(Je,{children:"状态"}),e.jsx(Je,{children:"名称"}),e.jsx(Je,{children:"基础URL"}),e.jsx(Je,{children:"客户端类型"}),e.jsx(Je,{className:"text-right",children:"最大重试"}),e.jsx(Je,{className:"text-right",children:"超时(秒)"}),e.jsx(Je,{className:"text-right",children:"重试间隔(秒)"}),e.jsx(Je,{className:"text-right",children:"操作"})]})}),e.jsx(yn,{children:W.length===0?e.jsx(gt,{children:e.jsx(Qe,{colSpan:9,className:"text-center text-muted-foreground py-8",children:ne?"未找到匹配的提供商":'暂无提供商配置,点击"添加提供商"开始配置'})}):W.map((I,ge)=>{const ke=l.findIndex(Us=>Us===I);return e.jsxs(gt,{children:[e.jsx(Qe,{children:e.jsx(jt,{checked:Se.has(ke),onCheckedChange:()=>Xe(ke)})}),e.jsx(Qe,{children:Et(I.name)||e.jsx(Ye,{variant:"outline",className:"text-muted-foreground",children:"未测试"})}),e.jsx(Qe,{className:"font-medium",children:I.name}),e.jsx(Qe,{className:"max-w-xs truncate",title:I.base_url,children:I.base_url}),e.jsx(Qe,{children:I.client_type}),e.jsx(Qe,{className:"text-right",children:I.max_retry}),e.jsx(Qe,{className:"text-right",children:I.timeout}),e.jsx(Qe,{className:"text-right",children:I.retry_interval}),e.jsx(Qe,{className:"text-right",children:e.jsxs("div",{className:"flex justify-end gap-2",children:[e.jsx(C,{variant:"outline",size:"sm",onClick:()=>ys(I.name),disabled:Q.has(I.name),title:"测试连接",children:Q.has(I.name)?e.jsx(tt,{className:"h-4 w-4 animate-spin"}):e.jsx(hn,{className:"h-4 w-4"})}),e.jsxs(C,{variant:"default",size:"sm",onClick:()=>ye(I,ke),children:[e.jsx(fn,{className:"h-4 w-4 mr-1",strokeWidth:2,fill:"none"}),"编辑"]}),e.jsxs(C,{size:"sm",onClick:()=>ts(ke),className:"bg-red-600 hover:bg-red-700 text-white",children:[e.jsx(es,{className:"h-4 w-4 mr-1",strokeWidth:2,fill:"none"}),"删除"]})]})})]},ge)})})]})})}),Ss.length>0&&e.jsxs("div",{className:"flex flex-col sm:flex-row items-center justify-between gap-4 mt-4",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(k,{htmlFor:"page-size-provider",className:"text-sm whitespace-nowrap",children:"每页显示"}),e.jsxs(Ue,{value:X.toString(),onValueChange:I=>{L(parseInt(I)),P(1),oe(new Set)},children:[e.jsx(Re,{id:"page-size-provider",className:"w-20",children:e.jsx(Be,{})}),e.jsxs(Le,{children:[e.jsx(ee,{value:"10",children:"10"}),e.jsx(ee,{value:"20",children:"20"}),e.jsx(ee,{value:"50",children:"50"}),e.jsx(ee,{value:"100",children:"100"})]})]}),e.jsxs("span",{className:"text-sm text-muted-foreground",children:["显示 ",(U-1)*X+1," 到"," ",Math.min(U*X,Ss.length)," 条,共 ",Ss.length," 条"]})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(C,{variant:"outline",size:"sm",onClick:()=>P(1),disabled:U===1,className:"hidden sm:flex",children:e.jsx(vi,{className:"h-4 w-4"})}),e.jsxs(C,{variant:"outline",size:"sm",onClick:()=>P(I=>Math.max(1,I-1)),disabled:U===1,children:[e.jsx(pl,{className:"h-4 w-4 sm:mr-1"}),e.jsx("span",{className:"hidden sm:inline",children:"上一页"})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(ie,{type:"number",value:B,onChange:I=>_e(I.target.value),onKeyDown:I=>I.key==="Enter"&&de(),placeholder:U.toString(),className:"w-16 h-8 text-center",min:1,max:xt}),e.jsx(C,{variant:"outline",size:"sm",onClick:de,disabled:!B,className:"h-8",children:"跳转"})]}),e.jsxs(C,{variant:"outline",size:"sm",onClick:()=>P(I=>I+1),disabled:U>=xt,children:[e.jsx("span",{className:"hidden sm:inline",children:"下一页"}),e.jsx(Ya,{className:"h-4 w-4 sm:ml-1"})]}),e.jsx(C,{variant:"outline",size:"sm",onClick:()=>P(xt),disabled:U>=xt,className:"hidden sm:flex",children:e.jsx(bi,{className:"h-4 w-4"})})]})]})]}),e.jsx(Qs,{open:v,onOpenChange:Ls,children:e.jsxs(qs,{className:"max-w-[95vw] sm:max-w-2xl max-h-[90vh] overflow-y-auto","data-tour":"provider-dialog",preventOutsideClose:We.isRunning,children:[e.jsxs(Gs,{children:[e.jsx(Vs,{children:w!==null?"编辑提供商":"添加提供商"}),e.jsx(Ws,{children:"配置 API 提供商的连接信息和参数"})]}),e.jsxs("form",{onSubmit:I=>{I.preventDefault(),Ms()},autoComplete:"off",children:[e.jsxs("div",{className:"grid gap-4 py-4",children:[e.jsxs("div",{className:"grid gap-2","data-tour":"provider-template-select",children:[e.jsx(k,{htmlFor:"template",children:"提供商模板"}),e.jsxs(Ia,{open:V,onOpenChange:z,children:[e.jsx(Qa,{asChild:!0,children:e.jsxs(C,{variant:"outline",role:"combobox","aria-expanded":V,className:"w-full justify-between",children:[A?pr.find(I=>I.id===A)?.display_name:"选择提供商模板...",e.jsx(cm,{className:"ml-2 h-4 w-4 shrink-0 opacity-50"})]})}),e.jsx(La,{className:"p-0",align:"start",style:{width:"var(--radix-popover-trigger-width)"},children:e.jsxs(vo,{children:[e.jsx(bo,{placeholder:"搜索提供商模板..."}),e.jsx(Ze,{className:"h-[300px]",children:e.jsxs(No,{className:"max-h-none overflow-visible",children:[e.jsx(yo,{children:"未找到匹配的模板"}),e.jsx(Cr,{children:pr.map(I=>e.jsxs(kr,{value:I.display_name,onSelect:()=>ps(I.id),children:[e.jsx(ea,{className:`mr-2 h-4 w-4 ${A===I.id?"opacity-100":"opacity-0"}`}),I.display_name]},I.id))})]})})]})})]}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"选择预设模板可自动填充 URL 和客户端类型,支持搜索"})]}),e.jsxs("div",{className:"grid gap-2","data-tour":"provider-name-input",children:[e.jsx(k,{htmlFor:"name",className:ve.name?"text-destructive":"",children:"名称 *"}),e.jsx(ie,{id:"name",value:b?.name||"",onChange:I=>{S(ge=>ge?{...ge,name:I.target.value}:null),ve.name&&ze(ge=>({...ge,name:void 0}))},placeholder:"例如: DeepSeek, SiliconFlow",className:ve.name?"border-destructive focus-visible:ring-destructive":""}),ve.name&&e.jsx("p",{className:"text-xs text-destructive",children:ve.name})]}),e.jsxs("div",{className:"grid gap-2","data-tour":"provider-url-input",children:[e.jsx(k,{htmlFor:"base_url",className:ve.base_url?"text-destructive":"",children:"基础 URL *"}),e.jsx(ie,{id:"base_url",value:b?.base_url||"",onChange:I=>{S(ge=>ge?{...ge,base_url:I.target.value}:null),ve.base_url&&ze(ge=>({...ge,base_url:void 0}))},placeholder:"https://api.example.com/v1",disabled:ss,className:`${ss?"bg-muted cursor-not-allowed":""} ${ve.base_url?"border-destructive focus-visible:ring-destructive":""}`}),ve.base_url&&e.jsx("p",{className:"text-xs text-destructive",children:ve.base_url}),ss&&!ve.base_url&&e.jsx("p",{className:"text-xs text-muted-foreground",children:'使用模板时 URL 不可编辑,切换到"自定义"以手动配置'})]}),e.jsxs("div",{className:"grid gap-2","data-tour":"provider-apikey-input",children:[e.jsx(k,{htmlFor:"api_key",className:ve.api_key?"text-destructive":"",children:"API Key *"}),e.jsxs("div",{className:"flex gap-2",children:[e.jsx(ie,{id:"api_key",type:se?"text":"password",value:b?.api_key||"",onChange:I=>{S(ge=>ge?{...ge,api_key:I.target.value}:null),ve.api_key&&ze(ge=>({...ge,api_key:void 0}))},placeholder:"sk-...",className:`flex-1 ${ve.api_key?"border-destructive focus-visible:ring-destructive":""}`}),e.jsx(C,{type:"button",variant:"outline",size:"icon",onClick:()=>te(!se),title:se?"隐藏密钥":"显示密钥",children:se?e.jsx(wr,{className:"h-4 w-4"}):e.jsx(Gt,{className:"h-4 w-4"})}),e.jsx(C,{type:"button",variant:"outline",size:"icon",onClick:Es,title:"复制密钥",children:e.jsx(co,{className:"h-4 w-4"})})]}),ve.api_key&&e.jsx("p",{className:"text-xs text-destructive",children:ve.api_key})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(k,{htmlFor:"client_type",children:"客户端类型"}),e.jsxs(Ue,{value:b?.client_type||"openai",onValueChange:I=>S(ge=>ge?{...ge,client_type:I}:null),disabled:ss,children:[e.jsx(Re,{id:"client_type",className:ss?"bg-muted cursor-not-allowed":"",children:e.jsx(Be,{placeholder:"选择客户端类型"})}),e.jsxs(Le,{children:[e.jsx(ee,{value:"openai",children:"OpenAI"}),e.jsx(ee,{value:"gemini",children:"Gemini"})]})]}),ss&&e.jsx("p",{className:"text-xs text-muted-foreground",children:'使用模板时客户端类型不可编辑,切换到"自定义"以手动配置'})]}),e.jsxs("div",{className:"grid grid-cols-1 sm:grid-cols-3 gap-4",children:[e.jsxs("div",{className:"grid gap-2",children:[e.jsx(k,{htmlFor:"max_retry",children:"最大重试"}),e.jsx(ie,{id:"max_retry",type:"number",min:"0",value:b?.max_retry??"",onChange:I=>{const ge=I.target.value===""?null:parseInt(I.target.value);S(ke=>ke?{...ke,max_retry:ge}:null)},placeholder:"默认: 2"})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(k,{htmlFor:"timeout",children:"超时(秒)"}),e.jsx(ie,{id:"timeout",type:"number",min:"1",value:b?.timeout??"",onChange:I=>{const ge=I.target.value===""?null:parseInt(I.target.value);S(ke=>ke?{...ke,timeout:ge}:null)},placeholder:"默认: 30"})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(k,{htmlFor:"retry_interval",children:"重试间隔(秒)"}),e.jsx(ie,{id:"retry_interval",type:"number",min:"1",value:b?.retry_interval??"",onChange:I=>{const ge=I.target.value===""?null:parseInt(I.target.value);S(ke=>ke?{...ke,retry_interval:ge}:null)},placeholder:"默认: 10"})]})]})]}),e.jsxs(at,{children:[e.jsx(C,{type:"button",variant:"outline",onClick:()=>y(!1),"data-tour":"provider-cancel-button",children:"取消"}),e.jsx(C,{type:"submit","data-tour":"provider-save-button",children:"保存"})]})]})]})}),e.jsx(js,{open:_,onOpenChange:T,children:e.jsxs(os,{children:[e.jsxs(ds,{children:[e.jsx(ms,{children:"确认删除"}),e.jsxs(xs,{children:['确定要删除提供商 "',$!==null?l[$]?.name:"",'" 吗? 此操作无法撤销。']})]}),e.jsxs(us,{children:[e.jsx(fs,{children:"取消"}),e.jsx(hs,{onClick:Pe,children:"删除"})]})]})}),e.jsx(js,{open:je,onOpenChange:be,children:e.jsxs(os,{children:[e.jsxs(ds,{children:[e.jsx(ms,{children:"确认批量删除"}),e.jsxs(xs,{children:["确定要删除选中的 ",Se.size," 个提供商吗? 此操作无法撤销。"]})]}),e.jsxs(us,{children:[e.jsx(fs,{children:"取消"}),e.jsx(hs,{onClick:Xs,className:"bg-destructive text-destructive-foreground hover:bg-destructive/90",children:"批量删除"})]})]})}),e.jsx(js,{open:Ne.isOpen,onOpenChange:I=>Ce(ge=>({...ge,isOpen:I})),children:e.jsxs(os,{className:"max-w-2xl",children:[e.jsxs(ds,{children:[e.jsx(ms,{children:"确认删除提供商"}),e.jsx(xs,{asChild:!0,children:e.jsxs("div",{className:"space-y-3",children:[e.jsxs("p",{children:["您即将删除以下提供商:",e.jsx("strong",{className:"text-foreground ml-1",children:Ne.providersToDelete.join(", ")})]}),e.jsxs("p",{className:"text-yellow-600 dark:text-yellow-500 font-medium",children:["⚠️ 此操作将同时删除 ",Ne.affectedModels.length," 个关联的模型:"]}),e.jsx(Ze,{className:"h-32 w-full rounded border p-3",children:e.jsx("div",{className:"space-y-1",children:Ne.affectedModels.map((I,ge)=>e.jsxs("div",{className:"text-sm",children:[e.jsx("span",{className:"font-mono text-muted-foreground",children:"•"}),e.jsx("span",{className:"ml-2 font-medium",children:I.name}),e.jsxs("span",{className:"ml-2 text-xs text-muted-foreground",children:["(",I.model_identifier,")"]})]},ge))})}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"这些模型将从模型列表和所有任务分配中移除。此操作无法撤销。"})]})})]}),e.jsxs(us,{children:[e.jsx(fs,{onClick:F,children:"取消"}),e.jsx(hs,{onClick:nt,className:"bg-destructive text-destructive-foreground hover:bg-destructive/90",children:"确认删除"})]})]})}),e.jsx(vn,{})]})}function yj(){return typeof crypto<"u"&&typeof crypto.randomUUID=="function"?crypto.randomUUID():`${Date.now().toString(36)}-${Math.random().toString(36).substring(2,11)}`}function wj(l){return typeof l=="boolean"?"boolean":typeof l=="number"?"number":"string"}function D1(l,i){switch(i){case"boolean":return l==="true";case"number":{const r=parseFloat(l);return isNaN(r)?0:r}default:return l}}function Fu(l){return Object.entries(l).map(([i,r])=>({id:yj(),key:i,value:r,type:wj(r)}))}function Iu(l){const i={};for(const r of l)r.key.trim()&&(i[r.key.trim()]=r.value);return i}function Qu(l){if(!l.trim())return{valid:!0,parsed:{}};try{const i=JSON.parse(l);if(typeof i!="object"||i===null||Array.isArray(i))return{valid:!1,error:"必须是一个 JSON 对象 {}"};for(const[r,o]of Object.entries(i))if(o!==null&&!["string","number","boolean"].includes(typeof o))return{valid:!1,error:`键 "${r}" 的值类型不支持(仅支持 string/number/boolean)`};return{valid:!0,parsed:i}}catch{return{valid:!1,error:"JSON 格式错误"}}}function R1(l){switch(l){case"boolean":return"布尔";case"number":return"数字";default:return"字符串"}}function L1(l){switch(l){case"boolean":return"bg-purple-100 text-purple-700 dark:bg-purple-900/30 dark:text-purple-400";case"number":return"bg-blue-100 text-blue-700 dark:bg-blue-900/30 dark:text-blue-400";default:return"bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-400"}}function U1({value:l,onChange:i,className:r,placeholder:o="添加额外参数..."}){const[u,x]=m.useState("list"),[h,f]=m.useState(()=>Fu(l||{})),[g,j]=m.useState(()=>Object.keys(l||{}).length>0?JSON.stringify(l,null,2):""),[v,y]=m.useState(null);m.useEffect(()=>{const V=Fu(l||{});f(V),j(Object.keys(l||{}).length>0?JSON.stringify(l,null,2):"")},[l]);const b=m.useMemo(()=>{const V=Qu(g);return V.valid&&V.parsed?{success:!0,data:V.parsed}:{success:!1,data:{}}},[g]),S=m.useCallback(V=>{const z=V;if(z==="json"&&u==="list"){const _=Iu(h);j(Object.keys(_).length>0?JSON.stringify(_,null,2):""),y(null)}else if(z==="list"&&u==="json"){const _=Qu(g);_.valid&&_.parsed&&(f(Fu(_.parsed)),y(null))}x(z)},[u,h,g]),w=m.useCallback(()=>{const V={id:yj(),key:"",value:"",type:"string"},z=[...h,V];f(z)},[h]),O=m.useCallback(V=>{const z=h.filter(_=>_.id!==V);f(z),i(Iu(z))},[h,i]),A=m.useCallback((V,z,_)=>{const T=h.map($=>{if($.id!==V)return $;if(z==="type"){const E=_;let se;return E==="boolean"?se=$.value==="true"||$.value===!0:E==="number"?se=typeof $.value=="number"?$.value:parseFloat(String($.value))||0:se=String($.value),{...$,type:E,value:se}}else return z==="value"?{...$,value:D1(_,$.type)}:{...$,[z]:_}});f(T),i(Iu(T))},[h,i]),D=m.useCallback(V=>{j(V);const z=Qu(V);z.valid&&z.parsed?(y(null),i(z.parsed)):y(z.error||"JSON 格式错误")},[i]);return e.jsxs("div",{className:H("space-y-3",r),children:[e.jsx(k,{className:"text-sm font-medium",children:"额外参数"}),e.jsxs(Sa,{value:u,onValueChange:S,className:"w-full",children:[e.jsxs(xa,{className:"h-8 p-0.5 bg-muted/60",children:[e.jsx(is,{value:"list",className:"h-7 px-3 text-xs data-[state=active]:bg-background data-[state=active]:shadow-sm",children:"键值对"}),e.jsx(is,{value:"json",className:"h-7 px-3 text-xs data-[state=active]:bg-background data-[state=active]:shadow-sm",children:"JSON"})]}),e.jsxs(As,{value:"list",className:"mt-3 space-y-2",children:[h.length===0?e.jsx("div",{className:"text-sm text-muted-foreground text-center py-4 border border-dashed rounded-md",children:o}):e.jsxs("div",{className:"space-y-2",children:[e.jsxs("div",{className:"grid grid-cols-[1fr_1fr_90px_32px] gap-2 text-xs text-muted-foreground px-1",children:[e.jsx("span",{children:"键名"}),e.jsx("span",{children:"值"}),e.jsx("span",{children:"类型"}),e.jsx("span",{})]}),h.map(V=>e.jsxs("div",{className:"grid grid-cols-[1fr_1fr_90px_32px] gap-2 items-center",children:[e.jsx(ie,{value:V.key,onChange:z=>A(V.id,"key",z.target.value),placeholder:"key",className:"h-8 text-sm"}),V.type==="boolean"?e.jsxs("div",{className:"flex items-center h-8 px-3 border rounded-md bg-background",children:[e.jsx(Fe,{checked:V.value===!0,onCheckedChange:z=>A(V.id,"value",String(z))}),e.jsx("span",{className:"ml-2 text-sm text-muted-foreground",children:V.value?"true":"false"})]}):e.jsx(ie,{type:V.type==="number"?"number":"text",value:V.value,onChange:z=>A(V.id,"value",z.target.value),placeholder:"value",className:"h-8 text-sm",step:V.type==="number"?"any":void 0}),e.jsxs(Ue,{value:V.type,onValueChange:z=>A(V.id,"type",z),children:[e.jsx(Re,{className:"h-8 text-xs",children:e.jsx(Be,{})}),e.jsxs(Le,{children:[e.jsx(ee,{value:"string",children:"字符串"}),e.jsx(ee,{value:"number",children:"数字"}),e.jsx(ee,{value:"boolean",children:"布尔"})]})]}),e.jsx(C,{type:"button",variant:"ghost",size:"icon",className:"h-8 w-8 text-muted-foreground hover:text-destructive",onClick:()=>O(V.id),children:e.jsx(es,{className:"h-4 w-4"})})]},V.id))]}),e.jsxs(C,{type:"button",variant:"outline",size:"sm",className:"w-full h-8",onClick:w,children:[e.jsx(ut,{className:"h-4 w-4 mr-1"}),"添加参数"]})]}),e.jsx(As,{value:"json",className:"mt-3",children:e.jsxs("div",{className:"grid grid-cols-1 md:grid-cols-2 gap-3",children:[e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx("span",{className:"text-xs text-muted-foreground",children:"编辑"}),v?e.jsxs("div",{className:"flex items-center gap-1 text-xs text-destructive",children:[e.jsx(Ot,{className:"h-3 w-3"}),e.jsx("span",{className:"truncate max-w-[150px]",children:v})]}):g.trim()&&e.jsxs("div",{className:"flex items-center gap-1 text-xs text-green-600 dark:text-green-400",children:[e.jsx(ea,{className:"h-3 w-3"}),e.jsx("span",{children:"有效"})]})]}),e.jsx(Ys,{value:g,onChange:V=>D(V.target.value),placeholder:`{ + "key": "value" +}`,className:H("font-mono text-sm min-h-[140px] h-[140px] resize-y flex-1",v&&"border-destructive focus-visible:ring-destructive")}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"支持 string、number、boolean 类型"})]}),e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsx("span",{className:"text-xs text-muted-foreground",children:"预览"}),e.jsx("div",{className:"min-h-[140px] h-[140px] flex-1 rounded-md border bg-muted/30 p-3 overflow-auto",children:b.success&&Object.keys(b.data).length>0?e.jsx("div",{className:"space-y-2",children:Object.entries(b.data).map(([V,z])=>{const _=wj(z);return e.jsxs("div",{className:"flex items-center gap-2 text-sm",children:[e.jsx("code",{className:"px-1.5 py-0.5 bg-background rounded text-xs font-medium",children:V}),e.jsx("span",{className:"text-muted-foreground",children:"="}),e.jsx("span",{className:H("font-mono",_==="boolean"&&(z?"text-green-600 dark:text-green-400":"text-red-600 dark:text-red-400"),_==="number"&&"text-blue-600 dark:text-blue-400",_==="string"&&"text-amber-600 dark:text-amber-400"),children:_==="string"?`"${z}"`:String(z)}),e.jsx(Ye,{variant:"secondary",className:H("h-5 text-[10px] px-1.5",L1(_)),children:R1(_)})]},V)})}):b.success?e.jsx("div",{className:"flex items-center justify-center h-full text-sm text-muted-foreground",children:"暂无参数"}):e.jsx("div",{className:"flex items-center justify-center h-full text-sm text-destructive",children:"JSON 格式错误"})}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"实时预览解析结果"})]})]})})]})]})}function B1({value:l,label:i,onRemove:r}){const{attributes:o,listeners:u,setNodeRef:x,transform:h,transition:f,isDragging:g}=Wg({id:l}),j={transform:ej.Transform.toString(h),transition:f,opacity:g?.5:1},v=b=>{b.preventDefault(),b.stopPropagation(),r(l)},y=b=>{b.stopPropagation()};return e.jsx("div",{ref:x,style:j,className:H("inline-flex items-center gap-1",g&&"shadow-lg"),children:e.jsxs(Ye,{variant:"secondary",className:"cursor-move hover:bg-secondary/80 flex items-center gap-1",children:[e.jsx("div",{...o,...u,className:"cursor-grab active:cursor-grabbing flex items-center",children:e.jsx(Lg,{className:"h-3 w-3 text-muted-foreground"})}),e.jsx("span",{children:i}),e.jsx("button",{type:"button",className:"ml-1 rounded-sm hover:bg-destructive/20 focus:outline-none focus:ring-1 focus:ring-destructive",onClick:v,onPointerDown:y,onMouseDown:b=>b.stopPropagation(),children:e.jsx(fl,{className:"h-3 w-3 cursor-pointer hover:text-destructive",strokeWidth:2,fill:"none"})})]})})}function H1({options:l,selected:i,onChange:r,placeholder:o="选择选项...",emptyText:u="未找到选项",className:x}){const[h,f]=m.useState(!1),g=Ig(uo(Kg,{activationConstraint:{distance:8}}),uo(Yg,{coordinateGetter:Qg})),j=b=>{i.includes(b)?r(i.filter(S=>S!==b)):r([...i,b])},v=b=>{r(i.filter(S=>S!==b))},y=b=>{const{active:S,over:w}=b;if(w&&S.id!==w.id){const O=i.indexOf(S.id),A=i.indexOf(w.id);r(Xg(i,O,A))}};return e.jsxs(Ia,{open:h,onOpenChange:f,children:[e.jsx(Qa,{asChild:!0,children:e.jsxs(C,{variant:"outline",role:"combobox","aria-expanded":h,className:H("w-full justify-between min-h-10 h-auto",x),children:[e.jsx(Pg,{sensors:g,collisionDetection:Jg,onDragEnd:y,children:e.jsx(Zg,{items:i,strategy:h0,children:e.jsx("div",{className:"flex gap-1 flex-wrap flex-1",children:i.length===0?e.jsx("span",{className:"text-muted-foreground",children:o}):i.map(b=>{const S=l.find(w=>w.value===b);return e.jsx(B1,{value:b,label:S?.label||b,onRemove:v},b)})})})}),e.jsx(cm,{className:"ml-2 h-4 w-4 shrink-0 opacity-50",strokeWidth:2,fill:"none"})]})}),e.jsx(La,{className:"w-full p-0",align:"start",children:e.jsxs(vo,{children:[e.jsx(bo,{placeholder:"搜索...",className:"h-9"}),e.jsxs(No,{children:[e.jsx(yo,{children:u}),e.jsx(Cr,{children:l.map(b=>{const S=i.includes(b.value);return e.jsxs(kr,{value:b.value,onSelect:()=>j(b.value),children:[e.jsx("div",{className:H("mr-2 flex h-4 w-4 items-center justify-center rounded-sm border border-primary",S?"bg-primary text-primary-foreground":"opacity-50 [&_svg]:invisible"),children:e.jsx(ea,{className:"h-3 w-3",strokeWidth:2,fill:"none"})}),e.jsx("span",{children:b.label})]},b.value)})})]})]})})]})}const Ma=Ct.memo(function({title:i,description:r,taskConfig:o,modelNames:u,onChange:x,hideTemperature:h=!1,hideMaxTokens:f=!1,dataTour:g}){const j=v=>{x("model_list",v)};return e.jsxs("div",{className:"rounded-lg border bg-card p-4 sm:p-6 space-y-4",children:[e.jsxs("div",{children:[e.jsx("h4",{className:"font-semibold text-base sm:text-lg",children:i}),e.jsx("p",{className:"text-xs sm:text-sm text-muted-foreground mt-1",children:r})]}),e.jsxs("div",{className:"grid gap-4",children:[e.jsxs("div",{className:"grid gap-2","data-tour":g,children:[e.jsx(k,{children:"模型列表"}),e.jsx(H1,{options:u.map(v=>({label:v,value:v})),selected:o.model_list||[],onChange:j,placeholder:"选择模型...",emptyText:"暂无可用模型"})]}),e.jsxs("div",{className:"grid grid-cols-1 sm:grid-cols-2 gap-4",children:[!h&&e.jsxs("div",{className:"grid gap-3",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(k,{children:"温度"}),e.jsx(ie,{type:"number",step:"0.1",min:"0",max:"1",value:o.temperature??.3,onChange:v=>{const y=parseFloat(v.target.value);!isNaN(y)&&y>=0&&y<=1&&x("temperature",y)},className:"w-20 h-8 text-sm"})]}),e.jsx(ma,{value:[o.temperature??.3],onValueChange:v=>x("temperature",v[0]),min:0,max:1,step:.1,className:"w-full"})]}),!f&&e.jsxs("div",{className:"grid gap-2",children:[e.jsx(k,{children:"最大 Token"}),e.jsx(ie,{type:"number",step:"1",min:"1",value:o.max_tokens??1024,onChange:v=>x("max_tokens",parseInt(v.target.value))})]})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(k,{children:"慢请求阈值 (秒)"}),e.jsx("span",{className:"text-xs text-muted-foreground",children:"超时警告"})]}),e.jsx(ie,{type:"number",step:"1",min:"1",value:o.slow_threshold??15,onChange:v=>{const y=parseInt(v.target.value);!isNaN(y)&&y>=1&&x("slow_threshold",y)},placeholder:"15"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"模型响应时间超过此阈值将输出警告日志"})]})]})]})}),$1=Ct.memo(function({paginatedModels:i,allModels:r,onEdit:o,onDelete:u,isModelUsed:x,searchQuery:h}){return i.length===0?e.jsx("div",{className:"md:hidden text-center text-muted-foreground py-8 rounded-lg border bg-card",children:h?"未找到匹配的模型":"暂无模型配置"}):e.jsx("div",{className:"md:hidden space-y-3",children:i.map((f,g)=>{const j=r.findIndex(y=>y===f),v=x(f.name);return e.jsxs("div",{className:"rounded-lg border bg-card p-4 space-y-3",children:[e.jsxs("div",{className:"flex items-start justify-between gap-2",children:[e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsxs("div",{className:"flex items-center gap-2 mb-1",children:[e.jsx("h3",{className:"font-semibold text-base",children:f.name}),e.jsx(Ye,{variant:v?"default":"secondary",className:v?"bg-green-600 hover:bg-green-700":"",children:v?"已使用":"未使用"})]}),e.jsx("p",{className:"text-xs text-muted-foreground break-all",title:f.model_identifier,children:f.model_identifier})]}),e.jsxs("div",{className:"flex gap-1 flex-shrink-0",children:[e.jsxs(C,{variant:"default",size:"sm",onClick:()=>o(f,j),children:[e.jsx(fn,{className:"h-4 w-4 mr-1",strokeWidth:2,fill:"none"}),"编辑"]}),e.jsxs(C,{size:"sm",onClick:()=>u(j),className:"bg-red-600 hover:bg-red-700 text-white",children:[e.jsx(es,{className:"h-4 w-4 mr-1",strokeWidth:2,fill:"none"}),"删除"]})]})]}),e.jsxs("div",{className:"grid grid-cols-2 gap-2 text-sm",children:[e.jsxs("div",{children:[e.jsx("span",{className:"text-muted-foreground text-xs",children:"提供商"}),e.jsx("p",{className:"font-medium",children:f.api_provider})]}),e.jsxs("div",{children:[e.jsx("span",{className:"text-muted-foreground text-xs",children:"模型温度"}),e.jsx("p",{className:"font-medium",children:f.temperature!=null?f.temperature:e.jsx("span",{className:"text-muted-foreground",children:"默认"})})]}),e.jsxs("div",{children:[e.jsx("span",{className:"text-muted-foreground text-xs",children:"输入价格"}),e.jsxs("p",{className:"font-medium",children:["¥",f.price_in,"/M"]})]}),e.jsxs("div",{children:[e.jsx("span",{className:"text-muted-foreground text-xs",children:"输出价格"}),e.jsxs("p",{className:"font-medium",children:["¥",f.price_out,"/M"]})]})]})]},g)})})}),q1=Ct.memo(function({paginatedModels:i,allModels:r,filteredModels:o,selectedModels:u,onEdit:x,onDelete:h,onToggleSelection:f,onToggleSelectAll:g,isModelUsed:j,searchQuery:v}){return e.jsx("div",{className:"hidden md:block rounded-lg border bg-card overflow-hidden",children:e.jsx("div",{className:"overflow-x-auto",children:e.jsxs(bn,{children:[e.jsx(Nn,{children:e.jsxs(gt,{children:[e.jsx(Je,{className:"w-12",children:e.jsx(jt,{checked:u.size===o.length&&o.length>0,onCheckedChange:g})}),e.jsx(Je,{className:"w-24",children:"使用状态"}),e.jsx(Je,{children:"模型名称"}),e.jsx(Je,{children:"模型标识符"}),e.jsx(Je,{children:"提供商"}),e.jsx(Je,{className:"text-center",children:"温度"}),e.jsx(Je,{className:"text-right",children:"输入价格"}),e.jsx(Je,{className:"text-right",children:"输出价格"}),e.jsx(Je,{className:"text-right",children:"操作"})]})}),e.jsx(yn,{children:i.length===0?e.jsx(gt,{children:e.jsx(Qe,{colSpan:9,className:"text-center text-muted-foreground py-8",children:v?"未找到匹配的模型":"暂无模型配置"})}):i.map((y,b)=>{const S=r.findIndex(O=>O===y),w=j(y.name);return e.jsxs(gt,{children:[e.jsx(Qe,{children:e.jsx(jt,{checked:u.has(S),onCheckedChange:()=>f(S)})}),e.jsx(Qe,{children:e.jsx(Ye,{variant:w?"default":"secondary",className:w?"bg-green-600 hover:bg-green-700":"",children:w?"已使用":"未使用"})}),e.jsx(Qe,{className:"font-medium",children:y.name}),e.jsx(Qe,{className:"max-w-xs truncate",title:y.model_identifier,children:y.model_identifier}),e.jsx(Qe,{children:y.api_provider}),e.jsx(Qe,{className:"text-center",children:y.temperature!=null?y.temperature:e.jsx("span",{className:"text-muted-foreground",children:"-"})}),e.jsxs(Qe,{className:"text-right",children:["¥",y.price_in,"/M"]}),e.jsxs(Qe,{className:"text-right",children:["¥",y.price_out,"/M"]}),e.jsx(Qe,{className:"text-right",children:e.jsxs("div",{className:"flex justify-end gap-2",children:[e.jsxs(C,{variant:"default",size:"sm",onClick:()=>x(y,S),children:[e.jsx(fn,{className:"h-4 w-4 mr-1",strokeWidth:2,fill:"none"}),"编辑"]}),e.jsxs(C,{size:"sm",onClick:()=>h(S),className:"bg-red-600 hover:bg-red-700 text-white",children:[e.jsx(es,{className:"h-4 w-4 mr-1",strokeWidth:2,fill:"none"}),"删除"]})]})})]},b)})})]})})})}),G1=300*1e3,Mp=new Map,V1=[10,20,50,100],F1=Ct.memo(function({page:i,pageSize:r,totalItems:o,jumpToPage:u,onPageChange:x,onPageSizeChange:h,onJumpToPageChange:f,onJumpToPage:g,onSelectionClear:j}){const v=Math.ceil(o/r),y=S=>{h(parseInt(S)),x(1),j?.()},b=S=>{S.key==="Enter"&&g()};return o===0?null:e.jsxs("div",{className:"flex flex-col sm:flex-row items-center justify-between gap-4 mt-4",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(k,{htmlFor:"page-size-model",className:"text-sm whitespace-nowrap",children:"每页显示"}),e.jsxs(Ue,{value:r.toString(),onValueChange:y,children:[e.jsx(Re,{id:"page-size-model",className:"w-20",children:e.jsx(Be,{})}),e.jsx(Le,{children:V1.map(S=>e.jsx(ee,{value:S.toString(),children:S},S))})]}),e.jsxs("span",{className:"text-sm text-muted-foreground",children:["显示 ",(i-1)*r+1," 到"," ",Math.min(i*r,o)," 条,共 ",o," 条"]})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(C,{variant:"outline",size:"sm",onClick:()=>x(1),disabled:i===1,className:"hidden sm:flex",children:e.jsx(vi,{className:"h-4 w-4"})}),e.jsxs(C,{variant:"outline",size:"sm",onClick:()=>x(Math.max(1,i-1)),disabled:i===1,children:[e.jsx(pl,{className:"h-4 w-4 sm:mr-1"}),e.jsx("span",{className:"hidden sm:inline",children:"上一页"})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(ie,{type:"number",value:u,onChange:S=>f(S.target.value),onKeyDown:b,placeholder:i.toString(),className:"w-16 h-8 text-center",min:1,max:v}),e.jsx(C,{variant:"outline",size:"sm",onClick:g,disabled:!u,className:"h-8",children:"跳转"})]}),e.jsxs(C,{variant:"outline",size:"sm",onClick:()=>x(i+1),disabled:i>=v,children:[e.jsx("span",{className:"hidden sm:inline",children:"下一页"}),e.jsx(Ya,{className:"h-4 w-4 sm:ml-1"})]}),e.jsx(C,{variant:"outline",size:"sm",onClick:()=>x(v),disabled:i>=v,className:"hidden sm:flex",children:e.jsx(bi,{className:"h-4 w-4"})})]})]})});function I1(l){const{models:i,taskConfig:r,debounceMs:o=2e3,onSavingChange:u,onUnsavedChange:x}=l,h=m.useRef(null),f=m.useRef(null),g=m.useRef(!0),j=m.useCallback(()=>{h.current&&(clearTimeout(h.current),h.current=null),f.current&&(clearTimeout(f.current),f.current=null)},[]),v=m.useCallback(S=>{const w={model_identifier:S.model_identifier,name:S.name,api_provider:S.api_provider,price_in:S.price_in??0,price_out:S.price_out??0,force_stream_mode:S.force_stream_mode??!1,extra_params:S.extra_params??{}};return S.temperature!=null&&(w.temperature=S.temperature),S.max_tokens!=null&&(w.max_tokens=S.max_tokens),w},[]),y=m.useCallback(async S=>{try{u?.(!0);const w=S.map(v);await am("models",w),x?.(!1)}catch(w){console.error("自动保存模型列表失败:",w),x?.(!0)}finally{u?.(!1)}},[u,x,v]),b=m.useCallback(async S=>{try{u?.(!0),await am("model_task_config",S),x?.(!1)}catch(w){console.error("自动保存任务配置失败:",w),x?.(!0)}finally{u?.(!1)}},[u,x]);return m.useEffect(()=>{if(!g.current)return x?.(!0),h.current&&clearTimeout(h.current),h.current=setTimeout(()=>{y(i)},o),()=>{h.current&&clearTimeout(h.current)}},[i,y,o,x]),m.useEffect(()=>{if(!(g.current||!r))return x?.(!0),f.current&&clearTimeout(f.current),f.current=setTimeout(()=>{b(r)},o),()=>{f.current&&clearTimeout(f.current)}},[r,b,o,x]),m.useEffect(()=>()=>{j()},[j]),{clearTimers:j,initialLoadRef:g}}function Q1(l={}){const{onCloseEditDialog:i}=l,r=ka(),{registerTour:o,startTour:u,state:x,goToStep:h}=xm(),f=m.useRef(x.stepIndex);return m.useEffect(()=>{o(Ga,bj)},[o]),m.useEffect(()=>{if(x.activeTourId===Ga&&x.isRunning){const j=Nj[x.stepIndex];j&&!window.location.pathname.endsWith(j.replace("/config/",""))&&r({to:j})}},[x.stepIndex,x.activeTourId,x.isRunning,r]),m.useEffect(()=>{if(x.activeTourId===Ga&&x.isRunning){const j=f.current,v=x.stepIndex;j>=12&&j<=17&&v<12&&i?.(),f.current=v}},[x.stepIndex,x.activeTourId,x.isRunning,i]),m.useEffect(()=>{if(x.activeTourId!==Ga||!x.isRunning)return;const j=v=>{const y=v.target,b=x.stepIndex;b===2&&y.closest('[data-tour="add-provider-button"]')?setTimeout(()=>h(3),300):b===9&&y.closest('[data-tour="provider-cancel-button"]')?setTimeout(()=>h(10),300):b===11&&y.closest('[data-tour="add-model-button"]')?setTimeout(()=>h(12),300):b===17&&y.closest('[data-tour="model-cancel-button"]')?setTimeout(()=>h(18),300):b===18&&y.closest('[data-tour="tasks-tab-trigger"]')&&setTimeout(()=>h(19),300)};return document.addEventListener("click",j,!0),()=>document.removeEventListener("click",j,!0)},[x,h]),{startTour:m.useCallback(()=>{u(Ga)},[u]),isRunning:x.isRunning&&x.activeTourId===Ga,stepIndex:x.stepIndex}}function Y1(l){const{getProviderConfig:i}=l,[r,o]=m.useState([]),[u,x]=m.useState(!1),[h,f]=m.useState(null),[g,j]=m.useState(null),v=m.useCallback(()=>{o([]),f(null),j(null)},[]),y=m.useCallback(async(b,S=!1)=>{const w=i(b);if(!w?.base_url){o([]),j(null),f('提供商配置不完整,请先在"模型提供商配置"中配置');return}if(!w.api_key){o([]),j(null),f('该提供商未配置 API Key,请先在"模型提供商配置"中填写');return}const O=z1(w.base_url);if(j(O),!O?.modelFetcher){o([]),f(null);return}const A=`${b}:${w.base_url}`,D=Mp.get(A);if(!S&&D&&Date.now()-D.timestampz(!1)}),{clearTimers:fe,initialLoadRef:ls}=I1({models:l,taskConfig:g,onSavingChange:O,onUnsavedChange:D}),G=m.useCallback(async()=>{try{y(!0);const W=await Gl(),de=W.models||[];i(de),f(de.map(Tt=>Tt.name));const ys=W.api_providers||[];o(ys.map(Tt=>Tt.name)),x(ys),j(W.model_task_config||null),D(!1),ls.current=!1}catch(W){console.error("加载配置失败:",W)}finally{y(!1)}},[ls]);m.useEffect(()=>{G()},[G]);const Me=m.useCallback(W=>u.find(de=>de.name===W),[u]),{availableModels:re,fetchingModels:pe,modelFetchError:Ee,matchedTemplate:Ie,fetchModelsForProvider:$e,clearModels:Vt}=Y1({getProviderConfig:Me});m.useEffect(()=>{V&&_?.api_provider&&$e(_.api_provider)},[V,_?.api_provider,$e]);const _t=async()=>{await J()},nt=W=>{const de={model_identifier:W.model_identifier,name:W.name,api_provider:W.api_provider,price_in:W.price_in??0,price_out:W.price_out??0,force_stream_mode:W.force_stream_mode??!1,extra_params:W.extra_params??{}};return W.temperature!=null&&(de.temperature=W.temperature),W.max_tokens!=null&&(de.max_tokens=W.max_tokens),de},F=async()=>{try{S(!0),fe();const W=await Gl();W.models=l.map(nt),W.model_task_config=g,await Nr(W),D(!1),Te({title:"保存成功",description:"正在重启麦麦..."}),await _t()}catch(W){console.error("保存配置失败:",W),Te({title:"保存失败",description:W.message,variant:"destructive"}),S(!1)}},He=async()=>{try{S(!0),fe();const W=await Gl();W.models=l.map(nt),W.model_task_config=g,await Nr(W),D(!1),Te({title:"保存成功",description:"模型配置已保存"}),await G()}catch(W){console.error("保存配置失败:",W),Te({title:"保存失败",description:W.message,variant:"destructive"})}finally{S(!1)}},De=(W,de)=>{xe({}),T(W||{model_identifier:"",name:"",api_provider:r[0]||"",price_in:0,price_out:0,temperature:null,max_tokens:null,force_stream_mode:!1,extra_params:{}}),E(de),z(!0)},ye=()=>{if(!_)return;const W={};if(_.name?.trim()||(W.name="请输入模型名称"),_.api_provider?.trim()||(W.api_provider="请选择 API 提供商"),_.model_identifier?.trim()||(W.model_identifier="请输入模型标识符"),Object.keys(W).length>0){xe(W);return}xe({});const de={model_identifier:_.model_identifier,name:_.name,api_provider:_.api_provider,price_in:_.price_in??0,price_out:_.price_out??0,force_stream_mode:_.force_stream_mode??!1,extra_params:_.extra_params??{}};_.temperature!=null&&(de.temperature=_.temperature),_.max_tokens!=null&&(de.max_tokens=_.max_tokens);let ys,Tt=null;if($!==null?(Tt=l[$].name,ys=[...l],ys[$]=de):ys=[...l,de],i(ys),f(ys.map(Et=>Et.name)),Tt&&Tt!==de.name&&g){const Et=I=>I.map(ge=>ge===Tt?de.name:ge);j({...g,utils:{...g.utils,model_list:Et(g.utils?.model_list||[])},utils_small:{...g.utils_small,model_list:Et(g.utils_small?.model_list||[])},tool_use:{...g.tool_use,model_list:Et(g.tool_use?.model_list||[])},replyer:{...g.replyer,model_list:Et(g.replyer?.model_list||[])},planner:{...g.planner,model_list:Et(g.planner?.model_list||[])},vlm:{...g.vlm,model_list:Et(g.vlm?.model_list||[])},voice:{...g.voice,model_list:Et(g.voice?.model_list||[])},embedding:{...g.embedding,model_list:Et(g.embedding?.model_list||[])},lpmm_entity_extract:{...g.lpmm_entity_extract,model_list:Et(g.lpmm_entity_extract?.model_list||[])},lpmm_rdf_build:{...g.lpmm_rdf_build,model_list:Et(g.lpmm_rdf_build?.model_list||[])},lpmm_qa:{...g.lpmm_qa,model_list:Et(g.lpmm_qa?.model_list||[])}})}z(!1),T(null),E(null)},ps=W=>{if(!W&&_){const de={..._,price_in:_.price_in??0,price_out:_.price_out??0};T(de)}z(W)},ss=W=>{ue(W),te(!0)},Es=()=>{if(ne!==null){const W=l.filter((de,ys)=>ys!==ne);i(W),f(W.map(de=>de.name)),Te({title:"删除成功",description:"模型已从列表中移除"})}te(!1),ue(null)},Ms=W=>{const de=new Set(je);de.has(W)?de.delete(W):de.add(W),be(de)},Ls=()=>{if(je.size===Os.length)be(new Set);else{const W=Os.map((de,ys)=>l.findIndex(Tt=>Tt===Os[ys]));be(new Set(W))}},ts=()=>{if(je.size===0){Te({title:"提示",description:"请先选择要删除的模型",variant:"default"});return}P(!0)},Pe=()=>{const W=l.filter((de,ys)=>!je.has(ys));i(W),f(W.map(de=>de.name)),be(new Set),P(!1),Te({title:"批量删除成功",description:`已删除 ${je.size} 个模型`})},Xe=(W,de,ys)=>{g&&j({...g,[W]:{...g[W],[de]:ys}})},Os=l.filter(W=>{if(!Se)return!0;const de=Se.toLowerCase();return W.name.toLowerCase().includes(de)||W.model_identifier.toLowerCase().includes(de)||W.api_provider.toLowerCase().includes(de)}),kt=Math.ceil(Os.length/B),Xs=Os.slice((X-1)*B,X*B),Ss=()=>{const W=parseInt(Ne);W>=1&&W<=kt&&(L(W),Ce(""))},xt=W=>g?[g.utils?.model_list||[],g.utils_small?.model_list||[],g.tool_use?.model_list||[],g.replyer?.model_list||[],g.planner?.model_list||[],g.vlm?.model_list||[],g.voice?.model_list||[],g.embedding?.model_list||[],g.lpmm_entity_extract?.model_list||[],g.lpmm_rdf_build?.model_list||[],g.lpmm_qa?.model_list||[]].some(ys=>ys.includes(W)):!1;return v?e.jsx(Ze,{className:"h-full",children:e.jsx("div",{className:"space-y-4 sm:space-y-6 p-4 sm:p-6",children:e.jsx("div",{className:"flex items-center justify-center h-64",children:e.jsx("p",{className:"text-muted-foreground",children:"加载中..."})})})}):e.jsx(Ze,{className:"h-full",children:e.jsxs("div",{className:"space-y-4 sm:space-y-6 p-4 sm:p-6",children:[e.jsxs("div",{className:"flex flex-col sm:flex-row sm:items-center justify-between gap-4",children:[e.jsxs("div",{children:[e.jsx("h1",{className:"text-2xl sm:text-3xl font-bold",children:"模型管理与分配"}),e.jsx("p",{className:"text-muted-foreground mt-1 sm:mt-2 text-sm sm:text-base",children:"添加模型并为模型分配功能"})]}),e.jsxs("div",{className:"flex gap-2 w-full sm:w-auto",children:[e.jsxs(C,{onClick:He,disabled:b||w||!A||le,size:"sm",variant:"outline",className:"flex-1 sm:flex-none sm:min-w-[120px]",children:[e.jsx(Ar,{className:"mr-2 h-4 w-4",strokeWidth:2,fill:"none"}),b?"保存中...":w?"自动保存中...":A?"保存配置":"已保存"]}),e.jsxs(js,{children:[e.jsx(mt,{asChild:!0,children:e.jsxs(C,{disabled:b||w||le,size:"sm",className:"flex-1 sm:flex-none sm:min-w-[120px]",children:[e.jsx(Mr,{className:"mr-2 h-4 w-4"}),le?"重启中...":A?"保存并重启":"重启麦麦"]})}),e.jsxs(os,{children:[e.jsxs(ds,{children:[e.jsx(ms,{children:"确认重启麦麦?"}),e.jsx(xs,{asChild:!0,children:e.jsx("div",{children:e.jsx("p",{children:A?"当前有未保存的配置更改。点击确认将先保存配置,然后重启麦麦使新配置生效。重启过程中麦麦将暂时离线。":"即将重启麦麦主程序。重启过程中麦麦将暂时离线,配置将在重启后生效。"})})})]}),e.jsxs(us,{children:[e.jsx(fs,{children:"取消"}),e.jsx(hs,{onClick:A?F:_t,children:A?"保存并重启":"确认重启"})]})]})]})]})]}),e.jsxs(sa,{children:[e.jsx(Ra,{className:"h-4 w-4"}),e.jsxs(ta,{children:["配置更新后需要",e.jsx("strong",{children:"重启麦麦"}),'才能生效。你可以点击右上角的"保存并重启"按钮一键完成保存和重启。']})]}),e.jsxs(sa,{className:"hidden lg:flex border-primary/30 bg-primary/5 cursor-pointer hover:bg-primary/10 transition-colors",onClick:qe,children:[e.jsx(Gy,{className:"h-4 w-4 text-primary"}),e.jsxs(ta,{className:"flex items-center justify-between",children:[e.jsxs("span",{children:[e.jsx("strong",{className:"text-primary",children:"新手引导:"}),"不知道如何配置模型?点击这里开始学习如何为麦麦的组件分配模型。"]}),e.jsx(C,{variant:"outline",size:"sm",className:"ml-4 shrink-0",children:"开始引导"})]})]}),e.jsxs(Sa,{defaultValue:"models",className:"w-full",children:[e.jsxs(xa,{className:"grid w-full max-w-full sm:max-w-md grid-cols-2",children:[e.jsx(is,{value:"models",children:"添加模型"}),e.jsx(is,{value:"tasks","data-tour":"tasks-tab-trigger",children:"为模型分配功能"})]}),e.jsxs(As,{value:"models",className:"space-y-4 mt-0",children:[e.jsxs("div",{className:"flex flex-col sm:flex-row justify-between items-start sm:items-center gap-2",children:[e.jsx("p",{className:"text-sm text-muted-foreground",children:"配置可用的模型列表"}),e.jsxs("div",{className:"flex gap-2 w-full sm:w-auto",children:[je.size>0&&e.jsxs(C,{onClick:ts,size:"sm",variant:"destructive",className:"w-full sm:w-auto",children:[e.jsx(es,{className:"mr-2 h-4 w-4",strokeWidth:2,fill:"none"}),"批量删除 (",je.size,")"]}),e.jsxs(C,{onClick:()=>De(null,null),size:"sm",variant:"outline",className:"w-full sm:w-auto","data-tour":"add-model-button",children:[e.jsx(ut,{className:"mr-2 h-4 w-4",strokeWidth:2,fill:"none"}),"添加模型"]})]})]}),e.jsxs("div",{className:"flex flex-col sm:flex-row items-start sm:items-center gap-2",children:[e.jsxs("div",{className:"relative w-full sm:flex-1 sm:max-w-sm",children:[e.jsx($t,{className:"absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground"}),e.jsx(ie,{placeholder:"搜索模型名称、标识符或提供商...",value:Se,onChange:W=>oe(W.target.value),className:"pl-9"})]}),Se&&e.jsxs("p",{className:"text-sm text-muted-foreground whitespace-nowrap",children:["找到 ",Os.length," 个结果"]})]}),e.jsx($1,{paginatedModels:Xs,allModels:l,onEdit:De,onDelete:ss,isModelUsed:xt,searchQuery:Se}),e.jsx(q1,{paginatedModels:Xs,allModels:l,filteredModels:Os,selectedModels:je,onEdit:De,onDelete:ss,onToggleSelection:Ms,onToggleSelectAll:Ls,isModelUsed:xt,searchQuery:Se}),e.jsx(F1,{page:X,pageSize:B,totalItems:Os.length,jumpToPage:Ne,onPageChange:L,onPageSizeChange:_e,onJumpToPageChange:Ce,onJumpToPage:Ss,onSelectionClear:()=>be(new Set)})]}),e.jsxs(As,{value:"tasks",className:"space-y-6 mt-0",children:[e.jsx("p",{className:"text-sm text-muted-foreground",children:"为不同的任务配置使用的模型和参数"}),g&&e.jsxs("div",{className:"grid gap-4 sm:gap-6",children:[e.jsx(Ma,{title:"组件模型 (utils)",description:"用于表情包、取名、关系、情绪变化等组件",taskConfig:g.utils,modelNames:h,onChange:(W,de)=>Xe("utils",W,de),dataTour:"task-model-select"}),e.jsx(Ma,{title:"组件小模型 (utils_small)",description:"消耗量较大的组件,建议使用速度较快的小模型",taskConfig:g.utils_small,modelNames:h,onChange:(W,de)=>Xe("utils_small",W,de)}),e.jsx(Ma,{title:"工具调用模型 (tool_use)",description:"需要使用支持工具调用的模型",taskConfig:g.tool_use,modelNames:h,onChange:(W,de)=>Xe("tool_use",W,de)}),e.jsx(Ma,{title:"首要回复模型 (replyer)",description:"用于表达器和表达方式学习",taskConfig:g.replyer,modelNames:h,onChange:(W,de)=>Xe("replyer",W,de)}),e.jsx(Ma,{title:"决策模型 (planner)",description:"负责决定麦麦该什么时候回复",taskConfig:g.planner,modelNames:h,onChange:(W,de)=>Xe("planner",W,de)}),e.jsx(Ma,{title:"图像识别模型 (vlm)",description:"视觉语言模型",taskConfig:g.vlm,modelNames:h,onChange:(W,de)=>Xe("vlm",W,de),hideTemperature:!0}),e.jsx(Ma,{title:"语音识别模型 (voice)",description:"语音转文字",taskConfig:g.voice,modelNames:h,onChange:(W,de)=>Xe("voice",W,de),hideTemperature:!0,hideMaxTokens:!0}),e.jsx(Ma,{title:"嵌入模型 (embedding)",description:"用于向量化",taskConfig:g.embedding,modelNames:h,onChange:(W,de)=>Xe("embedding",W,de),hideTemperature:!0,hideMaxTokens:!0}),e.jsxs("div",{className:"space-y-4",children:[e.jsx("h3",{className:"text-lg font-semibold",children:"LPMM 知识库模型"}),e.jsx(Ma,{title:"实体提取模型 (lpmm_entity_extract)",description:"从文本中提取实体",taskConfig:g.lpmm_entity_extract,modelNames:h,onChange:(W,de)=>Xe("lpmm_entity_extract",W,de)}),e.jsx(Ma,{title:"RDF 构建模型 (lpmm_rdf_build)",description:"构建知识图谱",taskConfig:g.lpmm_rdf_build,modelNames:h,onChange:(W,de)=>Xe("lpmm_rdf_build",W,de)}),e.jsx(Ma,{title:"问答模型 (lpmm_qa)",description:"知识库问答",taskConfig:g.lpmm_qa,modelNames:h,onChange:(W,de)=>Xe("lpmm_qa",W,de)})]})]})]})]}),e.jsx(Qs,{open:V,onOpenChange:ps,children:e.jsxs(qs,{className:"max-w-[95vw] sm:max-w-2xl max-h-[90vh] overflow-y-auto","data-tour":"model-dialog",preventOutsideClose:We,children:[e.jsxs(Gs,{children:[e.jsx(Vs,{children:$!==null?"编辑模型":"添加模型"}),e.jsx(Ws,{children:"配置模型的基本信息和参数"})]}),e.jsxs("div",{className:"grid gap-4 py-4",children:[e.jsxs("div",{className:"grid gap-2","data-tour":"model-name-input",children:[e.jsx(k,{htmlFor:"model_name",className:Q.name?"text-destructive":"",children:"模型名称 *"}),e.jsx(ie,{id:"model_name",value:_?.name||"",onChange:W=>{T(de=>de?{...de,name:W.target.value}:null),Q.name&&xe(de=>({...de,name:void 0}))},placeholder:"例如: qwen3-30b",className:Q.name?"border-destructive focus-visible:ring-destructive":""}),Q.name?e.jsx("p",{className:"text-xs text-destructive",children:Q.name}):e.jsx("p",{className:"text-xs text-muted-foreground",children:"用于在任务配置中引用此模型"})]}),e.jsxs("div",{className:"grid gap-2","data-tour":"model-provider-select",children:[e.jsx(k,{htmlFor:"api_provider",className:Q.api_provider?"text-destructive":"",children:"API 提供商 *"}),e.jsxs(Ue,{value:_?.api_provider||"",onValueChange:W=>{T(de=>de?{...de,api_provider:W}:null),Vt(),Q.api_provider&&xe(de=>({...de,api_provider:void 0}))},children:[e.jsx(Re,{id:"api_provider",className:Q.api_provider?"border-destructive focus-visible:ring-destructive":"",children:e.jsx(Be,{placeholder:"选择提供商"})}),e.jsx(Le,{children:r.map(W=>e.jsx(ee,{value:W,children:W},W))})]}),Q.api_provider&&e.jsx("p",{className:"text-xs text-destructive",children:Q.api_provider})]}),e.jsxs("div",{className:"grid gap-2","data-tour":"model-identifier-input",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(k,{htmlFor:"model_identifier",className:Q.model_identifier?"text-destructive":"",children:"模型标识符 *"}),Ie?.modelFetcher&&e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(Ye,{variant:"secondary",className:"text-xs",children:Ie.display_name}),e.jsx(C,{variant:"ghost",size:"sm",className:"h-6 px-2",onClick:()=>_?.api_provider&&$e(_.api_provider,!0),disabled:pe,children:pe?e.jsx(tt,{className:"h-3 w-3 animate-spin"}):e.jsx(At,{className:"h-3 w-3"})})]})]}),Ie?.modelFetcher?e.jsxs(Ia,{open:ve,onOpenChange:ze,children:[e.jsx(Qa,{asChild:!0,children:e.jsxs(C,{variant:"outline",role:"combobox","aria-expanded":ve,className:"w-full justify-between font-normal",disabled:pe||!!Ee,children:[pe?e.jsxs("span",{className:"flex items-center gap-2 text-muted-foreground",children:[e.jsx(tt,{className:"h-4 w-4 animate-spin"}),"正在获取模型列表..."]}):Ee?e.jsx("span",{className:"text-muted-foreground text-sm",children:"点击下方输入框手动填写"}):_?.model_identifier?e.jsx("span",{className:"truncate",children:_.model_identifier}):e.jsx("span",{className:"text-muted-foreground",children:"搜索或选择模型..."}),e.jsx(cm,{className:"ml-2 h-4 w-4 shrink-0 opacity-50"})]})}),e.jsx(La,{className:"p-0",align:"start",style:{width:"var(--radix-popover-trigger-width)"},children:e.jsxs(vo,{children:[e.jsx(bo,{placeholder:"搜索模型..."}),e.jsx(Ze,{className:"h-[300px]",children:e.jsxs(No,{className:"max-h-none overflow-visible",children:[e.jsx(yo,{children:Ee?e.jsxs("div",{className:"py-4 px-2 text-center space-y-2",children:[e.jsx("p",{className:"text-sm text-destructive",children:Ee}),!Ee.includes("API Key")&&e.jsx(C,{variant:"link",size:"sm",onClick:()=>_?.api_provider&&$e(_.api_provider,!0),children:"重试"})]}):"未找到匹配的模型"}),e.jsx(Cr,{heading:"可用模型",children:re.map(W=>e.jsxs(kr,{value:W.id,onSelect:()=>{T(de=>de?{...de,model_identifier:W.id}:null),ze(!1)},children:[e.jsx(ea,{className:`mr-2 h-4 w-4 ${_?.model_identifier===W.id?"opacity-100":"opacity-0"}`}),e.jsxs("div",{className:"flex flex-col",children:[e.jsx("span",{children:W.id}),W.name!==W.id&&e.jsx("span",{className:"text-xs text-muted-foreground",children:W.name})]})]},W.id))}),e.jsx(Cr,{heading:"手动输入",children:e.jsxs(kr,{value:"__manual_input__",onSelect:()=>{ze(!1)},children:[e.jsx(fn,{className:"mr-2 h-4 w-4"}),"手动输入模型标识符..."]})})]})})]})})]}):e.jsx(ie,{id:"model_identifier",value:_?.model_identifier||"",onChange:W=>{T(de=>de?{...de,model_identifier:W.target.value}:null),Q.model_identifier&&xe(de=>({...de,model_identifier:void 0}))},placeholder:"Qwen/Qwen3-30B-A3B-Instruct-2507",className:Q.model_identifier?"border-destructive focus-visible:ring-destructive":""}),Q.model_identifier&&e.jsx("p",{className:"text-xs text-destructive",children:Q.model_identifier}),Ee&&Ie?.modelFetcher&&!Q.model_identifier&&e.jsxs(sa,{variant:"destructive",className:"mt-2 py-2",children:[e.jsx(Ra,{className:"h-4 w-4"}),e.jsx(ta,{className:"text-xs",children:Ee})]}),Ie?.modelFetcher&&e.jsx(ie,{value:_?.model_identifier||"",onChange:W=>{T(de=>de?{...de,model_identifier:W.target.value}:null),Q.model_identifier&&xe(de=>({...de,model_identifier:void 0}))},placeholder:"或手动输入模型标识符",className:`mt-2 ${Q.model_identifier?"border-destructive focus-visible:ring-destructive":""}`}),!Q.model_identifier&&e.jsx("p",{className:"text-xs text-muted-foreground",children:Ee?'请手动输入模型标识符,或前往"模型提供商配置"检查 API Key':Ie?.modelFetcher?`已识别为 ${Ie.display_name},支持自动获取模型列表`:"API 提供商提供的模型 ID"})]}),e.jsxs("div",{className:"grid grid-cols-1 sm:grid-cols-2 gap-4",children:[e.jsxs("div",{className:"grid gap-2",children:[e.jsx(k,{htmlFor:"price_in",children:"输入价格 (¥/M token)"}),e.jsx(ie,{id:"price_in",type:"number",step:"0.1",min:"0",value:_?.price_in??"",onChange:W=>{const de=W.target.value===""?null:parseFloat(W.target.value);T(ys=>ys?{...ys,price_in:de}:null)},placeholder:"默认: 0"})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(k,{htmlFor:"price_out",children:"输出价格 (¥/M token)"}),e.jsx(ie,{id:"price_out",type:"number",step:"0.1",min:"0",value:_?.price_out??"",onChange:W=>{const de=W.target.value===""?null:parseFloat(W.target.value);T(ys=>ys?{...ys,price_out:de}:null)},placeholder:"默认: 0"})]})]}),e.jsxs("div",{className:"rounded-lg border p-4 space-y-3",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"space-y-0.5",children:[e.jsx(k,{htmlFor:"enable_model_temperature",className:"cursor-pointer",children:"自定义模型温度"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"启用后将覆盖「为模型分配功能」中的任务温度配置"})]}),e.jsx(Fe,{id:"enable_model_temperature",checked:_?.temperature!=null,onCheckedChange:W=>{T(W?de=>de?{...de,temperature:.5}:null:de=>de?{...de,temperature:null}:null)}})]}),_?.temperature!=null&&e.jsxs("div",{className:"space-y-2 pt-2 border-t",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(k,{className:"text-sm",children:"温度值"}),e.jsx("span",{className:"text-sm font-medium tabular-nums",children:_.temperature.toFixed(1)})]}),e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("span",{className:"text-xs text-muted-foreground",children:"0"}),e.jsx(ma,{value:[_.temperature],onValueChange:W=>T(de=>de?{...de,temperature:W[0]}:null),min:0,max:1,step:.1,className:"flex-1"}),e.jsx("span",{className:"text-xs text-muted-foreground",children:"1"})]}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"较低的温度(0.1-0.3)产生更确定的输出,较高的温度(0.7-1.0)产生更多样化的输出"})]})]}),e.jsxs("div",{className:"rounded-lg border p-4 space-y-3",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"space-y-0.5",children:[e.jsx(k,{htmlFor:"enable_model_max_tokens",className:"cursor-pointer",children:"自定义最大 Token"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"启用后将覆盖「为模型分配功能」中的任务最大 Token 配置"})]}),e.jsx(Fe,{id:"enable_model_max_tokens",checked:_?.max_tokens!=null,onCheckedChange:W=>{T(W?de=>de?{...de,max_tokens:2048}:null:de=>de?{...de,max_tokens:null}:null)}})]}),_?.max_tokens!=null&&e.jsxs("div",{className:"space-y-2 pt-2 border-t",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(k,{className:"text-sm",children:"最大 Token 数"}),e.jsx(ie,{type:"number",min:"1",max:"128000",value:_.max_tokens,onChange:W=>{const de=parseInt(W.target.value);!isNaN(de)&&de>=1&&T(ys=>ys?{...ys,max_tokens:de}:null)},className:"w-28 h-8 text-sm"})]}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"限制模型单次输出的最大 token 数量,不同模型支持的上限不同"})]})]}),e.jsxs("div",{className:"flex items-center space-x-2",children:[e.jsx(Fe,{id:"force_stream_mode",checked:_?.force_stream_mode||!1,onCheckedChange:W=>T(de=>de?{...de,force_stream_mode:W}:null)}),e.jsx(k,{htmlFor:"force_stream_mode",className:"cursor-pointer",children:"强制流式输出模式"})]}),e.jsx(U1,{value:_?.extra_params||{},onChange:W=>T(de=>de?{...de,extra_params:W}:null),placeholder:"添加额外参数(如 enable_thinking、top_p 等)..."})]}),e.jsxs(at,{children:[e.jsx(C,{variant:"outline",onClick:()=>z(!1),"data-tour":"model-cancel-button",children:"取消"}),e.jsx(C,{onClick:ye,"data-tour":"model-save-button",children:"保存"})]})]})}),e.jsx(js,{open:se,onOpenChange:te,children:e.jsxs(os,{children:[e.jsxs(ds,{children:[e.jsx(ms,{children:"确认删除"}),e.jsxs(xs,{children:['确定要删除模型 "',ne!==null?l[ne]?.name:"",'" 吗? 此操作无法撤销。']})]}),e.jsxs(us,{children:[e.jsx(fs,{children:"取消"}),e.jsx(hs,{onClick:Es,children:"删除"})]})]})}),e.jsx(js,{open:U,onOpenChange:P,children:e.jsxs(os,{children:[e.jsxs(ds,{children:[e.jsx(ms,{children:"确认批量删除"}),e.jsxs(xs,{children:["确定要删除选中的 ",je.size," 个模型吗? 此操作无法撤销。"]})]}),e.jsxs(us,{children:[e.jsx(fs,{children:"取消"}),e.jsx(hs,{onClick:Pe,className:"bg-destructive text-destructive-foreground hover:bg-destructive/90",children:"批量删除"})]})]})}),e.jsx(vn,{})]})})}const Tr=QN,Er=YN,zr=KN,wo="/api/webui/config";async function P1(){const i=await(await we(`${wo}/adapter-config/path`)).json();return!i.success||!i.path?null:{path:i.path,lastModified:i.lastModified}}async function Ap(l){const r=await(await we(`${wo}/adapter-config/path`,{method:"POST",headers:Is(),body:JSON.stringify({path:l})})).json();if(!r.success)throw new Error(r.message||"保存路径失败")}async function Op(l){const r=await(await we(`${wo}/adapter-config?path=${encodeURIComponent(l)}`)).json();if(!r.success)throw new Error("读取配置文件失败");return r.content}async function Dp(l,i){const o=await(await we(`${wo}/adapter-config`,{method:"POST",headers:Is(),body:JSON.stringify({path:l,content:i})})).json();if(!o.success)throw new Error(o.message||"保存配置失败")}const ot={inner:{version:"0.1.2"},nickname:{nickname:""},napcat_server:{host:"localhost",port:8095,token:"",heartbeat_interval:30},maibot_server:{host:"localhost",port:8e3},chat:{group_list_type:"whitelist",group_list:[],private_list_type:"whitelist",private_list:[],ban_user_id:[],ban_qq_bot:!1,enable_poke:!0},voice:{use_tts:!1},debug:{level:"INFO"}},Yu={oneclick:{name:"一键包",description:"使用一键包部署的适配器配置",path:"../MaiBot-Napcat-Adapter/config.toml",icon:Vl},docker:{name:"Docker",description:"Docker Compose 部署的适配器配置",path:"/MaiMBot/adapters-config/config.toml",icon:Vy}};function J1(l,i){let r=l.slice(0,i).split(/\r\n|\n|\r/g);return[r.length,r.pop().length+1]}function Z1(l,i,r){let o=l.split(/\r\n|\n|\r/g),u="",x=(Math.log10(i+1)|0)+1;for(let h=i-1;h<=i+1;h++){let f=o[h-1];f&&(u+=h.toString().padEnd(x," "),u+=": ",u+=f,u+=` +`,h===i&&(u+=" ".repeat(x+r+2),u+=`^ +`))}return u}class Ns extends Error{line;column;codeblock;constructor(i,r){const[o,u]=J1(r.toml,r.ptr),x=Z1(r.toml,o,u);super(`Invalid TOML document: ${i} + +${x}`,r),this.line=o,this.column=u,this.codeblock=x}}function W1(l,i){let r=0;for(;l[i-++r]==="\\";);return--r&&r%2}function ho(l,i=0,r=l.length){let o=l.indexOf(` +`,i);return l[o-1]==="\r"&&o--,o<=r?o:-1}function hm(l,i){for(let r=i;r-1&&r!=="'"&&W1(l,i));return i>-1&&(i+=o.length,o.length>1&&(l[i]===r&&i++,l[i]===r&&i++)),i}let e2=/^(\d{4}-\d{2}-\d{2})?[T ]?(?:(\d{2}):\d{2}:\d{2}(?:\.\d+)?)?(Z|[-+]\d{2}:\d{2})?$/i;class mi extends Date{#s=!1;#t=!1;#e=null;constructor(i){let r=!0,o=!0,u="Z";if(typeof i=="string"){let x=i.match(e2);x?(x[1]||(r=!1,i=`0000-01-01T${i}`),o=!!x[2],o&&i[10]===" "&&(i=i.replace(" ","T")),x[2]&&+x[2]>23?i="":(u=x[3]||null,i=i.toUpperCase(),!u&&o&&(i+="Z"))):i=""}super(i),isNaN(this.getTime())||(this.#s=r,this.#t=o,this.#e=u)}isDateTime(){return this.#s&&this.#t}isLocal(){return!this.#s||!this.#t||!this.#e}isDate(){return this.#s&&!this.#t}isTime(){return this.#t&&!this.#s}isValid(){return this.#s||this.#t}toISOString(){let i=super.toISOString();if(this.isDate())return i.slice(0,10);if(this.isTime())return i.slice(11,23);if(this.#e===null)return i.slice(0,-1);if(this.#e==="Z")return i;let r=+this.#e.slice(1,3)*60+ +this.#e.slice(4,6);return r=this.#e[0]==="-"?r:-r,new Date(this.getTime()-r*6e4).toISOString().slice(0,-1)+this.#e}static wrapAsOffsetDateTime(i,r="Z"){let o=new mi(i);return o.#e=r,o}static wrapAsLocalDateTime(i){let r=new mi(i);return r.#e=null,r}static wrapAsLocalDate(i){let r=new mi(i);return r.#t=!1,r.#e=null,r}static wrapAsLocalTime(i){let r=new mi(i);return r.#s=!1,r.#e=null,r}}let s2=/^((0x[0-9a-fA-F](_?[0-9a-fA-F])*)|(([+-]|0[ob])?\d(_?\d)*))$/,t2=/^[+-]?\d(_?\d)*(\.\d(_?\d)*)?([eE][+-]?\d(_?\d)*)?$/,a2=/^[+-]?0[0-9_]/,l2=/^[0-9a-f]{4,8}$/i,Lp={b:"\b",t:" ",n:` +`,f:"\f",r:"\r",'"':'"',"\\":"\\"};function Sj(l,i=0,r=l.length){let o=l[i]==="'",u=l[i++]===l[i]&&l[i]===l[i+1];u&&(r-=2,l[i+=2]==="\r"&&i++,l[i]===` +`&&i++);let x=0,h,f="",g=i;for(;i-1&&(hm(l,x),u=u.slice(0,x));let h=u.trimEnd();if(!o){let f=u.indexOf(` +`,h.length);if(f>-1)throw new Ns("newlines are not allowed in inline tables",{toml:l,ptr:i+f})}return[h,x]}function fm(l,i,r,o,u){if(o===0)throw new Ns("document contains excessively nested structures. aborting.",{toml:l,ptr:i});let x=l[i];if(x==="["||x==="{"){let[g,j]=x==="["?o2(l,i,o,u):c2(l,i,o,u),v=r?Rp(l,j,",",r):j;if(j-v&&r==="}"){let y=ho(l,j,v);if(y>-1)throw new Ns("newlines are not allowed in inline tables",{toml:l,ptr:y})}return[g,v]}let h;if(x==='"'||x==="'"){h=_j(l,i);let g=Sj(l,i,h);if(r){if(h=hl(l,h,r!=="]"),l[h]&&l[h]!==","&&l[h]!==r&&l[h]!==` +`&&l[h]!=="\r")throw new Ns("unexpected character encountered",{toml:l,ptr:h});h+=+(l[h]===",")}return[g,h]}h=Rp(l,i,",",r);let f=i2(l,i,h-+(l[h-1]===","),r==="]");if(!f[0])throw new Ns("incomplete key-value declaration: no value specified",{toml:l,ptr:i});return r&&f[1]>-1&&(h=hl(l,i+f[1]),h+=+(l[h]===",")),[n2(f[0],l,i,u),h]}let r2=/^[a-zA-Z0-9-_]+[ \t]*$/;function lm(l,i,r="="){let o=i-1,u=[],x=l.indexOf(r,i);if(x<0)throw new Ns("incomplete key-value: cannot find end of key",{toml:l,ptr:i});do{let h=l[i=++o];if(h!==" "&&h!==" ")if(h==='"'||h==="'"){if(h===l[i+1]&&h===l[i+2])throw new Ns("multiline strings are not allowed in keys",{toml:l,ptr:i});let f=_j(l,i);if(f<0)throw new Ns("unfinished string encountered",{toml:l,ptr:i});o=l.indexOf(".",f);let g=l.slice(f,o<0||o>x?x:o),j=ho(g);if(j>-1)throw new Ns("newlines are not allowed in keys",{toml:l,ptr:i+o+j});if(g.trimStart())throw new Ns("found extra tokens after the string part",{toml:l,ptr:f});if(xx?x:o);if(!r2.test(f))throw new Ns("only letter, numbers, dashes and underscores are allowed in keys",{toml:l,ptr:i});u.push(f.trimEnd())}}while(o+1&&ou===""||u===null||u===void 0?x:u,r={inner:{version:i(l.inner.version,ot.inner.version)},nickname:{nickname:i(l.nickname.nickname,ot.nickname.nickname)},napcat_server:{host:i(l.napcat_server.host,ot.napcat_server.host),port:i(l.napcat_server.port||0,ot.napcat_server.port),token:i(l.napcat_server.token,ot.napcat_server.token),heartbeat_interval:i(l.napcat_server.heartbeat_interval||0,ot.napcat_server.heartbeat_interval)},maibot_server:{host:i(l.maibot_server.host,ot.maibot_server.host),port:i(l.maibot_server.port||0,ot.maibot_server.port)},chat:{group_list_type:i(l.chat.group_list_type,ot.chat.group_list_type),group_list:l.chat.group_list||[],private_list_type:i(l.chat.private_list_type,ot.chat.private_list_type),private_list:l.chat.private_list||[],ban_user_id:l.chat.ban_user_id||[],ban_qq_bot:l.chat.ban_qq_bot??ot.chat.ban_qq_bot,enable_poke:l.chat.enable_poke??ot.chat.enable_poke},voice:{use_tts:l.voice.use_tts??ot.voice.use_tts},debug:{level:i(l.debug.level,ot.debug.level)}};let o=f2(r);return o=p2(o),o}catch(i){throw console.error("TOML 生成失败:",i),new Error(`无法生成 TOML 文件: ${i instanceof Error?i.message:"未知错误"}`)}}function p2(l){const i=l.split(` +`),r=[];for(let o=0;o"|?*\x00-\x1F]/.test(l)?{valid:!1,error:"路径包含非法字符"}:{valid:!0,error:""}}function g2(){const[l,i]=m.useState("upload"),[r,o]=m.useState(null),[u,x]=m.useState(""),[h,f]=m.useState(""),[g,j]=m.useState("oneclick"),[v,y]=m.useState(""),[b,S]=m.useState(!1),[w,O]=m.useState(!1),[A,D]=m.useState(!1),[V,z]=m.useState(!1),[_,T]=m.useState(null),[$,E]=m.useState(!1),se=m.useRef(null),{toast:te}=Ks(),ne=m.useRef(null),ue=Q=>{if(f(Q),Q.trim()){const xe=Pu(Q);y(xe.error)}else y("")},Se=m.useCallback(async Q=>{const xe=Yu[Q];O(!0);try{const Te=await Op(xe.path),J=Ku(Te);o(J),j(Q),f(xe.path),await Ap(xe.path),te({title:"加载成功",description:`已从${xe.name}预设加载配置`})}catch(Te){console.error("加载预设配置失败:",Te),te({title:"加载失败",description:Te instanceof Error?Te.message:"无法读取预设配置文件",variant:"destructive"})}finally{O(!1)}},[te]),oe=m.useCallback(async Q=>{const xe=Pu(Q);if(!xe.valid){y(xe.error),te({title:"路径无效",description:xe.error,variant:"destructive"});return}y(""),O(!0);try{const Te=await Op(Q),J=Ku(Te);o(J),f(Q),await Ap(Q),te({title:"加载成功",description:"已从配置文件加载"})}catch(Te){console.error("加载配置失败:",Te),te({title:"加载失败",description:Te instanceof Error?Te.message:"无法读取配置文件",variant:"destructive"})}finally{O(!1)}},[te]);m.useEffect(()=>{(async()=>{try{const xe=await P1();if(xe&&xe.path){f(xe.path);const Te=Object.entries(Yu).find(([,J])=>J.path===xe.path);Te?(i("preset"),j(Te[0]),await Se(Te[0])):(i("path"),await oe(xe.path))}}catch(xe){console.error("加载保存的路径失败:",xe)}})()},[oe,Se]);const je=m.useCallback(Q=>{l!=="path"&&l!=="preset"||!h||(ne.current&&clearTimeout(ne.current),ne.current=setTimeout(async()=>{S(!0);try{const xe=Xu(Q);await Dp(h,xe),te({title:"自动保存成功",description:"配置已保存到文件"})}catch(xe){console.error("自动保存失败:",xe),te({title:"自动保存失败",description:xe instanceof Error?xe.message:"保存配置失败",variant:"destructive"})}finally{S(!1)}},1e3))},[l,h,te]),be=async()=>{if(!r||!h)return;const Q=Pu(h);if(!Q.valid){te({title:"保存失败",description:Q.error,variant:"destructive"});return}S(!0);try{const xe=Xu(r);await Dp(h,xe),te({title:"保存成功",description:"配置已保存到文件"})}catch(xe){console.error("保存失败:",xe),te({title:"保存失败",description:xe instanceof Error?xe.message:"保存配置失败",variant:"destructive"})}finally{S(!1)}},U=async()=>{h&&await oe(h)},P=Q=>{if(Q!==l){if(r){T(Q),D(!0);return}X(Q)}},X=Q=>{o(null),x(""),y(""),i(Q),Q==="preset"&&Se("oneclick"),te({title:"已切换模式",description:{upload:"现在可以上传配置文件",path:"现在可以指定配置文件路径",preset:"现在可以使用预设配置"}[Q]})},L=()=>{_&&(X(_),T(null)),D(!1)},B=()=>{if(r){z(!0);return}_e()},_e=()=>{f(""),o(null),y(""),te({title:"已清空",description:"路径和配置已清空"})},Ne=()=>{_e(),z(!1)},Ce=Q=>{const xe=Q.target.files?.[0];if(!xe)return;const Te=new FileReader;Te.onload=J=>{try{const le=J.target?.result,qe=Ku(le);o(qe),x(xe.name),te({title:"上传成功",description:`已加载配置文件:${xe.name}`})}catch(le){console.error("解析配置文件失败:",le),te({title:"解析失败",description:"配置文件格式错误,请检查文件内容",variant:"destructive"})}},Te.readAsText(xe)},ve=()=>{if(!r)return;const Q=Xu(r),xe=new Blob([Q],{type:"text/plain;charset=utf-8"}),Te=URL.createObjectURL(xe),J=document.createElement("a");J.href=Te,J.download=u||"config.toml",document.body.appendChild(J),J.click(),document.body.removeChild(J),URL.revokeObjectURL(Te),te({title:"下载成功",description:"配置文件已下载,请手动覆盖并重启适配器"})},ze=()=>{o(JSON.parse(JSON.stringify(ot))),x("config.toml"),te({title:"已加载默认配置",description:"可以开始编辑配置"})};return e.jsx(Ze,{className:"h-full",children:e.jsxs("div",{className:"space-y-4 sm:space-y-6 p-4 sm:p-6",children:[e.jsx("div",{className:"flex flex-col sm:flex-row sm:items-center justify-between gap-4",children:e.jsxs("div",{children:[e.jsx("h1",{className:"text-2xl sm:text-3xl font-bold",children:"麦麦适配器配置"}),e.jsx("p",{className:"text-muted-foreground mt-1 sm:mt-2 text-sm sm:text-base",children:"管理麦麦的 QQ 适配器的配置文件"})]})}),e.jsxs("div",{className:"flex items-start gap-2 p-3 rounded-lg border border-amber-500/50 bg-amber-500/10 text-amber-700 dark:text-amber-400",children:[e.jsx(Ot,{className:"h-4 w-4 mt-0.5 flex-shrink-0"}),e.jsx("p",{className:"text-sm",children:"适配器配置保存之后使用 WebUI 的重启功能适配器并不会重启,需要手动重启适配器。"})]}),e.jsx(Tr,{open:$,onOpenChange:E,children:e.jsxs(Ve,{children:[e.jsx(rs,{children:e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{children:[e.jsx(cs,{children:"工作模式"}),e.jsx(st,{children:"选择配置文件的管理方式"})]}),e.jsx(Er,{asChild:!0,children:e.jsxs(C,{variant:"ghost",size:"sm",className:"w-9 p-0",children:[e.jsx(Fa,{className:`h-4 w-4 transition-transform duration-200 ${$?"transform rotate-180":""}`}),e.jsx("span",{className:"sr-only",children:"切换"})]})})]})}),e.jsx(zr,{children:e.jsxs(gs,{className:"space-y-4",children:[e.jsxs("div",{className:"grid grid-cols-1 md:grid-cols-3 gap-3 md:gap-4",children:[e.jsx("div",{className:`border-2 rounded-lg p-3 md:p-4 cursor-pointer transition-all ${l==="preset"?"border-primary bg-primary/5":"border-muted hover:border-primary/50 active:border-primary/70"}`,onClick:()=>P("preset"),children:e.jsxs("div",{className:"flex items-start gap-2 md:gap-3",children:[e.jsx(Vl,{className:"h-4 w-4 md:h-5 md:w-5 mt-0.5 flex-shrink-0"}),e.jsxs("div",{className:"min-w-0",children:[e.jsx("h3",{className:"font-semibold text-sm md:text-base",children:"预设模式"}),e.jsx("p",{className:"text-xs md:text-sm text-muted-foreground mt-1 line-clamp-2",children:"使用预设的部署配置"})]})]})}),e.jsx("div",{className:`border-2 rounded-lg p-3 md:p-4 cursor-pointer transition-all ${l==="upload"?"border-primary bg-primary/5":"border-muted hover:border-primary/50 active:border-primary/70"}`,onClick:()=>P("upload"),children:e.jsxs("div",{className:"flex items-start gap-2 md:gap-3",children:[e.jsx(_r,{className:"h-4 w-4 md:h-5 md:w-5 mt-0.5 flex-shrink-0"}),e.jsxs("div",{className:"min-w-0",children:[e.jsx("h3",{className:"font-semibold text-sm md:text-base",children:"上传文件模式"}),e.jsx("p",{className:"text-xs md:text-sm text-muted-foreground mt-1 line-clamp-2",children:"上传配置文件,编辑后下载并手动覆盖"})]})]})}),e.jsx("div",{className:`border-2 rounded-lg p-3 md:p-4 cursor-pointer transition-all ${l==="path"?"border-primary bg-primary/5":"border-muted hover:border-primary/50 active:border-primary/70"}`,onClick:()=>P("path"),children:e.jsxs("div",{className:"flex items-start gap-2 md:gap-3",children:[e.jsx(Fy,{className:"h-4 w-4 md:h-5 md:w-5 mt-0.5 flex-shrink-0"}),e.jsxs("div",{className:"min-w-0",children:[e.jsx("h3",{className:"font-semibold text-sm md:text-base",children:"指定路径模式"}),e.jsx("p",{className:"text-xs md:text-sm text-muted-foreground mt-1 line-clamp-2",children:"指定配置文件路径,自动加载和保存"})]})]})})]}),l==="preset"&&e.jsxs("div",{className:"space-y-3 pt-2 border-t",children:[e.jsx(k,{className:"text-sm md:text-base",children:"选择部署方式"}),e.jsx("div",{className:"grid grid-cols-1 sm:grid-cols-2 gap-3",children:Object.entries(Yu).map(([Q,xe])=>{const Te=xe.icon,J=g===Q;return e.jsx("div",{className:`border-2 rounded-lg p-3 cursor-pointer transition-all ${J?"border-primary bg-primary/5":"border-muted hover:border-primary/50"}`,onClick:()=>{j(Q),Se(Q)},children:e.jsxs("div",{className:"flex items-start gap-3",children:[e.jsx(Te,{className:"h-5 w-5 mt-0.5 flex-shrink-0"}),e.jsxs("div",{className:"min-w-0 flex-1",children:[e.jsx("h4",{className:"font-semibold text-sm",children:xe.name}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:xe.description}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1 font-mono break-all",children:xe.path})]})]})},Q)})})]}),l==="path"&&e.jsxs("div",{className:"space-y-3 pt-2 border-t",children:[e.jsxs("div",{className:"space-y-2",children:[e.jsx(k,{htmlFor:"config-path",className:"text-sm md:text-base",children:"配置文件路径"}),e.jsxs("div",{className:"flex flex-col sm:flex-row gap-2",children:[e.jsxs("div",{className:"flex-1 space-y-1",children:[e.jsx(ie,{id:"config-path",value:h,onChange:Q=>ue(Q.target.value),placeholder:"例: C:\\Adapter\\config.toml",className:`text-sm ${v?"border-destructive":""}`}),v&&e.jsx("p",{className:"text-xs text-destructive",children:v})]}),e.jsx(C,{onClick:()=>oe(h),disabled:w||!h||!!v,className:"w-full sm:w-auto",children:w?e.jsxs(e.Fragment,{children:[e.jsx(At,{className:"h-4 w-4 animate-spin mr-2"}),e.jsx("span",{className:"sm:hidden",children:"加载中..."})]}):e.jsxs(e.Fragment,{children:[e.jsx("span",{className:"sm:hidden",children:"加载配置"}),e.jsx("span",{className:"hidden sm:inline",children:"加载"})]})})]})]}),e.jsxs("details",{className:"rounded-lg bg-muted/50 p-3 group",children:[e.jsxs("summary",{className:"text-xs font-medium cursor-pointer select-none list-none flex items-center justify-between",children:[e.jsx("span",{children:"路径格式说明"}),e.jsx("svg",{className:"h-4 w-4 transition-transform group-open:rotate-180",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",children:e.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M19 9l-7 7-7-7"})})]}),e.jsxs("div",{className:"mt-2 space-y-2 text-xs text-muted-foreground",children:[e.jsxs("div",{className:"space-y-1",children:[e.jsx("div",{className:"flex items-center gap-2",children:e.jsx("span",{className:"font-mono bg-background px-1.5 py-0.5 rounded text-[10px] md:text-xs whitespace-nowrap",children:"Windows"})}),e.jsxs("div",{className:"pl-2 space-y-0.5 text-[10px] md:text-xs break-all",children:[e.jsx("div",{children:"C:\\Adapter\\config.toml"}),e.jsx("div",{className:"hidden sm:block",children:"D:\\MaiBot\\adapter\\config.toml"}),e.jsx("div",{className:"hidden sm:block",children:"\\\\server\\share\\config.toml"})]})]}),e.jsxs("div",{className:"space-y-1",children:[e.jsx("div",{className:"flex items-center gap-2",children:e.jsx("span",{className:"font-mono bg-background px-1.5 py-0.5 rounded text-[10px] md:text-xs whitespace-nowrap",children:"Linux"})}),e.jsxs("div",{className:"pl-2 space-y-0.5 text-[10px] md:text-xs break-all",children:[e.jsx("div",{children:"/opt/adapter/config.toml"}),e.jsx("div",{className:"hidden sm:block",children:"/home/user/adapter/config.toml"}),e.jsx("div",{className:"hidden sm:block",children:"~/adapter/config.toml"})]})]}),e.jsx("p",{className:"pt-1 border-t text-[10px] md:text-xs",children:"💡 配置会自动保存到指定文件,修改后 1 秒自动保存"})]})]})]})]})})]})}),e.jsxs(sa,{children:[e.jsx(Ra,{className:"h-4 w-4"}),e.jsx(ta,{children:l==="preset"?e.jsxs(e.Fragment,{children:[e.jsx("strong",{children:"预设模式:"}),"选择预设的部署方式,配置会自动加载,修改后 1 秒自动保存",b&&" (正在保存...)"]}):l==="upload"?e.jsxs(e.Fragment,{children:[e.jsx("strong",{children:"上传文件模式:"}),"上传配置文件 → 在线编辑 → 下载文件 → 手动覆盖并重启适配器"]}):e.jsxs(e.Fragment,{children:[e.jsx("strong",{children:"指定路径模式:"}),"指定配置文件路径后,配置会自动加载,修改后 1 秒自动保存",b&&" (正在保存...)"]})})]}),l==="upload"&&!r&&e.jsxs("div",{className:"flex flex-col sm:flex-row gap-2 w-full",children:[e.jsx("input",{ref:se,type:"file",accept:".toml",className:"hidden",onChange:Ce}),e.jsxs(C,{onClick:()=>se.current?.click(),size:"sm",variant:"outline",className:"w-full sm:w-auto",children:[e.jsx(_r,{className:"mr-2 h-4 w-4"}),"上传配置"]}),e.jsxs(C,{onClick:ze,size:"sm",className:"w-full sm:w-auto",children:[e.jsx(Aa,{className:"mr-2 h-4 w-4"}),"使用默认配置"]})]}),l==="upload"&&r&&e.jsx("div",{className:"flex gap-2",children:e.jsxs(C,{onClick:ve,size:"sm",className:"w-full sm:w-auto",children:[e.jsx(Da,{className:"mr-2 h-4 w-4"}),"下载配置"]})}),(l==="preset"||l==="path")&&r&&e.jsxs("div",{className:"flex flex-col sm:flex-row gap-2",children:[e.jsxs(C,{onClick:be,size:"sm",disabled:b||!!v,className:"w-full sm:w-auto",children:[e.jsx(Ar,{className:"mr-2 h-4 w-4"}),b?"保存中...":"立即保存"]}),e.jsxs(C,{onClick:U,size:"sm",variant:"outline",disabled:w,className:"w-full sm:w-auto",children:[e.jsx(At,{className:`mr-2 h-4 w-4 ${w?"animate-spin":""}`}),"刷新"]}),l==="path"&&e.jsxs(C,{onClick:B,size:"sm",variant:"destructive",className:"w-full sm:w-auto",children:[e.jsx(es,{className:"mr-2 h-4 w-4"}),"清空路径"]})]}),r?e.jsxs(Sa,{defaultValue:"napcat",className:"w-full",children:[e.jsx("div",{className:"overflow-x-auto -mx-4 px-4 sm:mx-0 sm:px-0",children:e.jsxs(xa,{className:"inline-flex w-auto min-w-full sm:grid sm:w-full sm:grid-cols-5",children:[e.jsxs(is,{value:"napcat",className:"flex-shrink-0 text-xs sm:text-sm whitespace-nowrap",children:[e.jsx("span",{className:"hidden sm:inline",children:"Napcat 连接"}),e.jsx("span",{className:"sm:hidden",children:"Napcat"})]}),e.jsxs(is,{value:"maibot",className:"flex-shrink-0 text-xs sm:text-sm whitespace-nowrap",children:[e.jsx("span",{className:"hidden sm:inline",children:"麦麦连接"}),e.jsx("span",{className:"sm:hidden",children:"麦麦"})]}),e.jsxs(is,{value:"chat",className:"flex-shrink-0 text-xs sm:text-sm whitespace-nowrap",children:[e.jsx("span",{className:"hidden sm:inline",children:"聊天控制"}),e.jsx("span",{className:"sm:hidden",children:"聊天"})]}),e.jsxs(is,{value:"voice",className:"flex-shrink-0 text-xs sm:text-sm whitespace-nowrap",children:[e.jsx("span",{className:"hidden sm:inline",children:"语音设置"}),e.jsx("span",{className:"sm:hidden",children:"语音"})]}),e.jsx(is,{value:"debug",className:"flex-shrink-0 text-xs sm:text-sm whitespace-nowrap",children:"调试"})]})}),e.jsx(As,{value:"napcat",className:"space-y-4",children:e.jsx(j2,{config:r,onChange:Q=>{o(Q),je(Q)}})}),e.jsx(As,{value:"maibot",className:"space-y-4",children:e.jsx(v2,{config:r,onChange:Q=>{o(Q),je(Q)}})}),e.jsx(As,{value:"chat",className:"space-y-4",children:e.jsx(b2,{config:r,onChange:Q=>{o(Q),je(Q)}})}),e.jsx(As,{value:"voice",className:"space-y-4",children:e.jsx(N2,{config:r,onChange:Q=>{o(Q),je(Q)}})}),e.jsx(As,{value:"debug",className:"space-y-4",children:e.jsx(y2,{config:r,onChange:Q=>{o(Q),je(Q)}})})]}):e.jsx("div",{className:"rounded-lg border bg-card p-6 md:p-12",children:e.jsxs("div",{className:"text-center space-y-3 md:space-y-4",children:[e.jsx(Aa,{className:"h-12 w-12 md:h-16 md:w-16 mx-auto text-muted-foreground"}),e.jsxs("div",{children:[e.jsx("h3",{className:"text-base md:text-lg font-semibold",children:"尚未加载配置"}),e.jsx("p",{className:"text-xs md:text-sm text-muted-foreground mt-2 px-4",children:l==="preset"?"请选择预设的部署方式":l==="upload"?"请上传现有配置文件,或使用默认配置开始编辑":"请指定配置文件路径并点击加载按钮"})]})]})}),e.jsx(js,{open:A,onOpenChange:D,children:e.jsxs(os,{children:[e.jsxs(ds,{children:[e.jsx(ms,{children:"确认切换模式"}),e.jsxs(xs,{children:["切换模式将清空当前配置,确定要继续吗?",e.jsx("br",{}),e.jsx("span",{className:"text-destructive font-medium",children:"请确保已保存重要配置"})]})]}),e.jsxs(us,{children:[e.jsx(fs,{onClick:()=>{D(!1),T(null)},children:"取消"}),e.jsx(hs,{onClick:L,children:"确认切换"})]})]})}),e.jsx(js,{open:V,onOpenChange:z,children:e.jsxs(os,{children:[e.jsxs(ds,{children:[e.jsx(ms,{children:"确认清空路径"}),e.jsxs(xs,{children:["清空路径将清除当前配置,确定要继续吗?",e.jsx("br",{}),e.jsx("span",{className:"text-muted-foreground text-sm",children:"此操作不会删除配置文件,只是清除界面中的配置"})]})]}),e.jsxs(us,{children:[e.jsx(fs,{onClick:()=>z(!1),children:"取消"}),e.jsx(hs,{onClick:Ne,className:"bg-destructive hover:bg-destructive/90",children:"确认清空"})]})]})})]})})}function j2({config:l,onChange:i}){return e.jsx("div",{className:"rounded-lg border bg-card p-4 md:p-6 space-y-4 md:space-y-6",children:e.jsxs("div",{children:[e.jsx("h3",{className:"text-base md:text-lg font-semibold mb-3 md:mb-4",children:"Napcat WebSocket 服务设置"}),e.jsxs("div",{className:"grid gap-3 md:gap-4",children:[e.jsxs("div",{className:"grid gap-2",children:[e.jsx(k,{htmlFor:"napcat-host",className:"text-sm md:text-base",children:"主机地址"}),e.jsx(ie,{id:"napcat-host",value:l.napcat_server.host,onChange:r=>i({...l,napcat_server:{...l.napcat_server,host:r.target.value}}),placeholder:"localhost",className:"text-sm md:text-base"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"Napcat 设定的主机地址"})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(k,{htmlFor:"napcat-port",className:"text-sm md:text-base",children:"端口"}),e.jsx(ie,{id:"napcat-port",type:"number",value:l.napcat_server.port||"",onChange:r=>i({...l,napcat_server:{...l.napcat_server,port:r.target.value?parseInt(r.target.value):0}}),placeholder:"8095",className:"text-sm md:text-base"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"Napcat 设定的端口(留空使用默认值 8095)"})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(k,{htmlFor:"napcat-token",className:"text-sm md:text-base",children:"访问令牌(Token)"}),e.jsx(ie,{id:"napcat-token",type:"password",value:l.napcat_server.token,onChange:r=>i({...l,napcat_server:{...l.napcat_server,token:r.target.value}}),placeholder:"留空表示无需令牌",className:"text-sm md:text-base"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"Napcat 设定的访问令牌,若无则留空"})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(k,{htmlFor:"napcat-heartbeat",className:"text-sm md:text-base",children:"心跳间隔(秒)"}),e.jsx(ie,{id:"napcat-heartbeat",type:"number",value:l.napcat_server.heartbeat_interval||"",onChange:r=>i({...l,napcat_server:{...l.napcat_server,heartbeat_interval:r.target.value?parseInt(r.target.value):0}}),placeholder:"30",className:"text-sm md:text-base"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"与 Napcat 设置的心跳间隔保持一致(留空使用默认值 30)"})]})]})]})})}function v2({config:l,onChange:i}){return e.jsx("div",{className:"rounded-lg border bg-card p-4 md:p-6 space-y-4 md:space-y-6",children:e.jsxs("div",{children:[e.jsx("h3",{className:"text-base md:text-lg font-semibold mb-3 md:mb-4",children:"麦麦 WebSocket 服务设置"}),e.jsxs("div",{className:"grid gap-3 md:gap-4",children:[e.jsxs("div",{className:"grid gap-2",children:[e.jsx(k,{htmlFor:"maibot-host",className:"text-sm md:text-base",children:"主机地址"}),e.jsx(ie,{id:"maibot-host",value:l.maibot_server.host,onChange:r=>i({...l,maibot_server:{...l.maibot_server,host:r.target.value}}),placeholder:"localhost",className:"text-sm md:text-base"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"麦麦在 .env 文件中设置的 HOST 字段"})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(k,{htmlFor:"maibot-port",className:"text-sm md:text-base",children:"端口"}),e.jsx(ie,{id:"maibot-port",type:"number",value:l.maibot_server.port||"",onChange:r=>i({...l,maibot_server:{...l.maibot_server,port:r.target.value?parseInt(r.target.value):0}}),placeholder:"8000",className:"text-sm md:text-base"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"麦麦在 .env 文件中设置的 PORT 字段(留空使用默认值 8000)"})]})]})]})})}function b2({config:l,onChange:i}){const r=x=>{const h={...l};x==="group"?h.chat.group_list=[...h.chat.group_list,0]:x==="private"?h.chat.private_list=[...h.chat.private_list,0]:h.chat.ban_user_id=[...h.chat.ban_user_id,0],i(h)},o=(x,h)=>{const f={...l};x==="group"?f.chat.group_list=f.chat.group_list.filter((g,j)=>j!==h):x==="private"?f.chat.private_list=f.chat.private_list.filter((g,j)=>j!==h):f.chat.ban_user_id=f.chat.ban_user_id.filter((g,j)=>j!==h),i(f)},u=(x,h,f)=>{const g={...l};x==="group"?g.chat.group_list[h]=f:x==="private"?g.chat.private_list[h]=f:g.chat.ban_user_id[h]=f,i(g)};return e.jsx("div",{className:"rounded-lg border bg-card p-4 md:p-6 space-y-4 md:space-y-6",children:e.jsxs("div",{children:[e.jsx("h3",{className:"text-base md:text-lg font-semibold mb-3 md:mb-4",children:"聊天黑白名单功能"}),e.jsxs("div",{className:"grid gap-4 md:gap-6",children:[e.jsxs("div",{className:"space-y-3 md:space-y-4",children:[e.jsxs("div",{className:"grid gap-2",children:[e.jsx(k,{className:"text-sm md:text-base",children:"群组名单类型"}),e.jsxs(Ue,{value:l.chat.group_list_type,onValueChange:x=>i({...l,chat:{...l.chat,group_list_type:x}}),children:[e.jsx(Re,{children:e.jsx(Be,{})}),e.jsxs(Le,{children:[e.jsx(ee,{value:"whitelist",children:"白名单(仅名单内可聊天)"}),e.jsx(ee,{value:"blacklist",children:"黑名单(名单内禁止聊天)"})]})]})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsxs("div",{className:"flex flex-col sm:flex-row sm:items-center sm:justify-between gap-2 sm:gap-0",children:[e.jsx(k,{className:"text-sm md:text-base",children:"群组列表"}),e.jsxs(C,{onClick:()=>r("group"),size:"sm",variant:"outline",className:"w-full sm:w-auto",children:[e.jsx(Aa,{className:"mr-1 h-4 w-4"}),"添加群号"]})]}),l.chat.group_list.map((x,h)=>e.jsxs("div",{className:"flex gap-2",children:[e.jsx(ie,{type:"number",value:x,onChange:f=>u("group",h,parseInt(f.target.value)||0),placeholder:"输入群号",className:"text-sm md:text-base"}),e.jsxs(js,{children:[e.jsx(mt,{asChild:!0,children:e.jsx(C,{size:"icon",variant:"outline",children:e.jsx(es,{className:"h-4 w-4"})})}),e.jsxs(os,{children:[e.jsxs(ds,{children:[e.jsx(ms,{children:"确认删除"}),e.jsxs(xs,{children:["确定要删除群号 ",x," 吗?此操作无法撤销。"]})]}),e.jsxs(us,{children:[e.jsx(fs,{children:"取消"}),e.jsx(hs,{onClick:()=>o("group",h),children:"删除"})]})]})]})]},h)),l.chat.group_list.length===0&&e.jsx("p",{className:"text-sm text-muted-foreground",children:"暂无群组"})]})]}),e.jsxs("div",{className:"space-y-3 md:space-y-4",children:[e.jsxs("div",{className:"grid gap-2",children:[e.jsx(k,{className:"text-sm md:text-base",children:"私聊名单类型"}),e.jsxs(Ue,{value:l.chat.private_list_type,onValueChange:x=>i({...l,chat:{...l.chat,private_list_type:x}}),children:[e.jsx(Re,{children:e.jsx(Be,{})}),e.jsxs(Le,{children:[e.jsx(ee,{value:"whitelist",children:"白名单(仅名单内可聊天)"}),e.jsx(ee,{value:"blacklist",children:"黑名单(名单内禁止聊天)"})]})]})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsxs("div",{className:"flex flex-col sm:flex-row sm:items-center sm:justify-between gap-2 sm:gap-0",children:[e.jsx(k,{className:"text-sm md:text-base",children:"私聊列表"}),e.jsxs(C,{onClick:()=>r("private"),size:"sm",variant:"outline",className:"w-full sm:w-auto",children:[e.jsx(Aa,{className:"mr-1 h-4 w-4"}),"添加用户"]})]}),l.chat.private_list.map((x,h)=>e.jsxs("div",{className:"flex gap-2",children:[e.jsx(ie,{type:"number",value:x,onChange:f=>u("private",h,parseInt(f.target.value)||0),placeholder:"输入QQ号",className:"text-sm md:text-base"}),e.jsxs(js,{children:[e.jsx(mt,{asChild:!0,children:e.jsx(C,{size:"icon",variant:"outline",children:e.jsx(es,{className:"h-4 w-4"})})}),e.jsxs(os,{children:[e.jsxs(ds,{children:[e.jsx(ms,{children:"确认删除"}),e.jsxs(xs,{children:["确定要删除用户 ",x," 吗?此操作无法撤销。"]})]}),e.jsxs(us,{children:[e.jsx(fs,{children:"取消"}),e.jsx(hs,{onClick:()=>o("private",h),children:"删除"})]})]})]})]},h)),l.chat.private_list.length===0&&e.jsx("p",{className:"text-sm text-muted-foreground",children:"暂无用户"})]})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsxs("div",{className:"flex flex-col sm:flex-row sm:items-center sm:justify-between gap-2 sm:gap-0",children:[e.jsxs("div",{children:[e.jsx(k,{className:"text-sm md:text-base",children:"全局禁止名单"}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:"名单中的用户无法进行任何聊天"})]}),e.jsxs(C,{onClick:()=>r("ban"),size:"sm",variant:"outline",className:"w-full sm:w-auto",children:[e.jsx(Aa,{className:"mr-1 h-4 w-4"}),"添加用户"]})]}),l.chat.ban_user_id.map((x,h)=>e.jsxs("div",{className:"flex gap-2",children:[e.jsx(ie,{type:"number",value:x,onChange:f=>u("ban",h,parseInt(f.target.value)||0),placeholder:"输入QQ号",className:"text-sm md:text-base"}),e.jsxs(js,{children:[e.jsx(mt,{asChild:!0,children:e.jsx(C,{size:"icon",variant:"outline",children:e.jsx(es,{className:"h-4 w-4"})})}),e.jsxs(os,{children:[e.jsxs(ds,{children:[e.jsx(ms,{children:"确认删除"}),e.jsxs(xs,{children:["确定要从全局禁止名单中删除用户 ",x," 吗?此操作无法撤销。"]})]}),e.jsxs(us,{children:[e.jsx(fs,{children:"取消"}),e.jsx(hs,{onClick:()=>o("ban",h),children:"删除"})]})]})]})]},h)),l.chat.ban_user_id.length===0&&e.jsx("p",{className:"text-sm text-muted-foreground",children:"暂无禁止用户"})]}),e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{children:[e.jsx(k,{className:"text-sm md:text-base",children:"屏蔽QQ官方机器人"}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:"是否屏蔽来自QQ官方机器人的消息"})]}),e.jsx(Fe,{checked:l.chat.ban_qq_bot,onCheckedChange:x=>i({...l,chat:{...l.chat,ban_qq_bot:x}})})]}),e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{children:[e.jsx(k,{className:"text-sm md:text-base",children:"启用戳一戳功能"}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:"是否响应戳一戳消息"})]}),e.jsx(Fe,{checked:l.chat.enable_poke,onCheckedChange:x=>i({...l,chat:{...l.chat,enable_poke:x}})})]})]})]})})}function N2({config:l,onChange:i}){return e.jsx("div",{className:"rounded-lg border bg-card p-4 md:p-6 space-y-4 md:space-y-6",children:e.jsxs("div",{children:[e.jsx("h3",{className:"text-base md:text-lg font-semibold mb-3 md:mb-4",children:"发送语音设置"}),e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{children:[e.jsx(k,{className:"text-sm md:text-base",children:"使用 TTS 语音"}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:"请确保已配置 TTS 并有对应的适配器"})]}),e.jsx(Fe,{checked:l.voice.use_tts,onCheckedChange:r=>i({...l,voice:{use_tts:r}})})]})]})})}function y2({config:l,onChange:i}){return e.jsx("div",{className:"rounded-lg border bg-card p-4 md:p-6 space-y-4 md:space-y-6",children:e.jsxs("div",{children:[e.jsx("h3",{className:"text-base md:text-lg font-semibold mb-3 md:mb-4",children:"调试设置"}),e.jsx("div",{className:"grid gap-3 md:gap-4",children:e.jsxs("div",{className:"grid gap-2",children:[e.jsx(k,{className:"text-sm md:text-base",children:"日志等级"}),e.jsxs(Ue,{value:l.debug.level,onValueChange:r=>i({...l,debug:{level:r}}),children:[e.jsx(Re,{children:e.jsx(Be,{})}),e.jsxs(Le,{children:[e.jsx(ee,{value:"DEBUG",children:"DEBUG(调试)"}),e.jsx(ee,{value:"INFO",children:"INFO(信息)"}),e.jsx(ee,{value:"WARNING",children:"WARNING(警告)"}),e.jsx(ee,{value:"ERROR",children:"ERROR(错误)"}),e.jsx(ee,{value:"CRITICAL",children:"CRITICAL(严重)"})]})]}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"设置适配器的日志输出等级"})]})})]})})}const w2=["defaultChecked","defaultValue","suppressContentEditableWarning","suppressHydrationWarning","dangerouslySetInnerHTML","accessKey","className","contentEditable","contextMenu","dir","draggable","hidden","id","lang","placeholder","slot","spellCheck","style","tabIndex","title","translate","radioGroup","role","about","datatype","inlist","prefix","property","resource","typeof","vocab","autoCapitalize","autoCorrect","autoSave","color","itemProp","itemScope","itemType","itemID","itemRef","results","security","unselectable","inputMode","is","onCopy","onCopyCapture","onCut","onCutCapture","onPaste","onPasteCapture","onCompositionEnd","onCompositionEndCapture","onCompositionStart","onCompositionStartCapture","onCompositionUpdate","onCompositionUpdateCapture","onFocus","onFocusCapture","onBlur","onBlurCapture","onChange","onChangeCapture","onBeforeInput","onBeforeInputCapture","onInput","onInputCapture","onReset","onResetCapture","onSubmit","onSubmitCapture","onInvalid","onInvalidCapture","onLoad","onLoadCapture","onError","onErrorCapture","onKeyDown","onKeyDownCapture","onKeyPress","onKeyPressCapture","onKeyUp","onKeyUpCapture","onAbort","onAbortCapture","onCanPlay","onCanPlayCapture","onCanPlayThrough","onCanPlayThroughCapture","onDurationChange","onDurationChangeCapture","onEmptied","onEmptiedCapture","onEncrypted","onEncryptedCapture","onEnded","onEndedCapture","onLoadedData","onLoadedDataCapture","onLoadedMetadata","onLoadedMetadataCapture","onLoadStart","onLoadStartCapture","onPause","onPauseCapture","onPlay","onPlayCapture","onPlaying","onPlayingCapture","onProgress","onProgressCapture","onRateChange","onRateChangeCapture","onSeeked","onSeekedCapture","onSeeking","onSeekingCapture","onStalled","onStalledCapture","onSuspend","onSuspendCapture","onTimeUpdate","onTimeUpdateCapture","onVolumeChange","onVolumeChangeCapture","onWaiting","onWaitingCapture","onAuxClick","onAuxClickCapture","onClick","onClickCapture","onContextMenu","onContextMenuCapture","onDoubleClick","onDoubleClickCapture","onDrag","onDragCapture","onDragEnd","onDragEndCapture","onDragEnter","onDragEnterCapture","onDragExit","onDragExitCapture","onDragLeave","onDragLeaveCapture","onDragOver","onDragOverCapture","onDragStart","onDragStartCapture","onDrop","onDropCapture","onMouseDown","onMouseDownCapture","onMouseEnter","onMouseLeave","onMouseMove","onMouseMoveCapture","onMouseOut","onMouseOutCapture","onMouseOver","onMouseOverCapture","onMouseUp","onMouseUpCapture","onSelect","onSelectCapture","onTouchCancel","onTouchCancelCapture","onTouchEnd","onTouchEndCapture","onTouchMove","onTouchMoveCapture","onTouchStart","onTouchStartCapture","onPointerDown","onPointerDownCapture","onPointerMove","onPointerMoveCapture","onPointerUp","onPointerUpCapture","onPointerCancel","onPointerCancelCapture","onPointerEnter","onPointerEnterCapture","onPointerLeave","onPointerLeaveCapture","onPointerOver","onPointerOverCapture","onPointerOut","onPointerOutCapture","onGotPointerCapture","onGotPointerCaptureCapture","onLostPointerCapture","onLostPointerCaptureCapture","onScroll","onScrollCapture","onWheel","onWheelCapture","onAnimationStart","onAnimationStartCapture","onAnimationEnd","onAnimationEndCapture","onAnimationIteration","onAnimationIterationCapture","onTransitionEnd","onTransitionEndCapture"],_2=/^(aria-|data-)/,kj=l=>Object.fromEntries(Object.entries(l).filter(([i])=>_2.test(i)||w2.includes(i)));function S2(l,i){const r=kj(l);return Object.keys(l).some(o=>!Object.hasOwn(r,o)&&l[o]!==i[o])}class C2 extends m.Component{container;plugin;componentDidMount(){this.installPlugin()}componentDidUpdate(i){if(i.uppy!==this.props.uppy)this.uninstallPlugin(i),this.installPlugin();else if(S2(this.props,i)){const{uppy:r,...o}={...this.props,target:this.container};this.plugin.setOptions(o)}}componentWillUnmount(){this.uninstallPlugin()}installPlugin(){const{uppy:i,...r}={id:"Dashboard",...this.props,inline:!0,target:this.container};i.use(g0,r),this.plugin=i.getPlugin(r.id)}uninstallPlugin(i=this.props){const{uppy:r}=i;r.removePlugin(this.plugin)}render(){return m.createElement("div",{className:"uppy-Container",ref:i=>{this.container=i},...kj(this.props)})}}function k2({src:l,alt:i="表情包",className:r,maxRetries:o=5,retryInterval:u=1500}){const[x,h]=m.useState("loading"),[f,g]=m.useState(0),[j,v]=m.useState(null),y=m.useCallback(async()=>{try{const b=await fetch(l,{credentials:"include"});if(b.status===202){h("generating"),f{g(O=>O+1)},u):h("error");return}if(!b.ok){h("error");return}const S=await b.blob(),w=URL.createObjectURL(S);v(w),h("loaded")}catch(b){console.error("加载缩略图失败:",b),h("error")}},[l,f,o,u]);return m.useEffect(()=>{h("loading"),g(0),v(null)},[l]),m.useEffect(()=>{y()},[y]),m.useEffect(()=>()=>{j&&URL.revokeObjectURL(j)},[j]),x==="loading"||x==="generating"?e.jsx(aj,{className:H("w-full h-full",r)}):x==="error"||!j?e.jsx("div",{className:H("w-full h-full flex items-center justify-center bg-muted",r),children:e.jsx(Ug,{className:"h-8 w-8 text-muted-foreground"})}):e.jsx("img",{src:j,alt:i,className:H("w-full h-full object-contain",r)})}function Tj({content:l,className:i=""}){return e.jsx("div",{className:`prose prose-sm dark:prose-invert max-w-none ${i}`,children:e.jsx(v0,{remarkPlugins:[N0,y0],rehypePlugins:[b0],components:{code({inline:r,className:o,children:u,...x}){return r?e.jsx("code",{className:"bg-muted px-1.5 py-0.5 rounded text-sm font-mono",...x,children:u}):e.jsx("code",{className:`${o} block bg-muted p-4 rounded-lg overflow-x-auto`,...x,children:u})},table({children:r,...o}){return e.jsx("div",{className:"overflow-x-auto",children:e.jsx("table",{className:"border-collapse border border-border",...o,children:r})})},th({children:r,...o}){return e.jsx("th",{className:"border border-border bg-muted px-4 py-2 text-left font-semibold",...o,children:r})},td({children:r,...o}){return e.jsx("td",{className:"border border-border px-4 py-2",...o,children:r})},a({children:r,...o}){return e.jsx("a",{className:"text-primary hover:underline",target:"_blank",rel:"noopener noreferrer",...o,children:r})},blockquote({children:r,...o}){return e.jsx("blockquote",{className:"border-l-4 border-primary pl-4 italic text-muted-foreground",...o,children:r})},h1({children:r,...o}){return e.jsx("h1",{className:"text-3xl font-bold mt-6 mb-4",...o,children:r})},h2({children:r,...o}){return e.jsx("h2",{className:"text-2xl font-bold mt-5 mb-3",...o,children:r})},h3({children:r,...o}){return e.jsx("h3",{className:"text-xl font-bold mt-4 mb-2",...o,children:r})},h4({children:r,...o}){return e.jsx("h4",{className:"text-lg font-semibold mt-3 mb-2",...o,children:r})},ul({children:r,...o}){return e.jsx("ul",{className:"list-disc list-inside space-y-1 my-2",...o,children:r})},ol({children:r,...o}){return e.jsx("ol",{className:"list-decimal list-inside space-y-1 my-2",...o,children:r})},p({children:r,...o}){return e.jsx("p",{className:"my-2 leading-relaxed",...o,children:r})},hr({...r}){return e.jsx("hr",{className:"my-4 border-border",...r})}},children:l})})}function T2({children:l,className:i}){return e.jsx(Tj,{content:l,className:i})}const Ca="/api/webui/emoji";async function E2(l){const i=new URLSearchParams;l.page&&i.append("page",l.page.toString()),l.page_size&&i.append("page_size",l.page_size.toString()),l.search&&i.append("search",l.search),l.is_registered!==void 0&&i.append("is_registered",l.is_registered.toString()),l.is_banned!==void 0&&i.append("is_banned",l.is_banned.toString()),l.format&&i.append("format",l.format),l.sort_by&&i.append("sort_by",l.sort_by),l.sort_order&&i.append("sort_order",l.sort_order);const r=await we(`${Ca}/list?${i}`,{});if(!r.ok)throw new Error(`获取表情包列表失败: ${r.statusText}`);return r.json()}async function z2(l){const i=await we(`${Ca}/${l}`,{});if(!i.ok)throw new Error(`获取表情包详情失败: ${i.statusText}`);return i.json()}async function M2(l,i){const r=await we(`${Ca}/${l}`,{method:"PATCH",body:JSON.stringify(i)});if(!r.ok)throw new Error(`更新表情包失败: ${r.statusText}`);return r.json()}async function A2(l){const i=await we(`${Ca}/${l}`,{method:"DELETE"});if(!i.ok)throw new Error(`删除表情包失败: ${i.statusText}`);return i.json()}async function O2(){const l=await we(`${Ca}/stats/summary`,{});if(!l.ok)throw new Error(`获取统计数据失败: ${l.statusText}`);return l.json()}async function D2(l){const i=await we(`${Ca}/${l}/register`,{method:"POST"});if(!i.ok)throw new Error(`注册表情包失败: ${i.statusText}`);return i.json()}async function R2(l){const i=await we(`${Ca}/${l}/ban`,{method:"POST"});if(!i.ok)throw new Error(`封禁表情包失败: ${i.statusText}`);return i.json()}function L2(l,i=!1){return i?`${Ca}/${l}/thumbnail?original=true`:`${Ca}/${l}/thumbnail`}function U2(l){return`${Ca}/${l}/thumbnail?original=true`}async function B2(l){const i=await we(`${Ca}/batch/delete`,{method:"POST",body:JSON.stringify({emoji_ids:l})});if(!i.ok){const r=await i.json();throw new Error(r.detail||"批量删除失败")}return i.json()}function H2(){return`${Ca}/upload`}function $2(){const[l,i]=m.useState([]),[r,o]=m.useState(null),[u,x]=m.useState(!1),[h,f]=m.useState(1),[g,j]=m.useState(0),[v,y]=m.useState(20),[b,S]=m.useState("all"),[w,O]=m.useState("all"),[A,D]=m.useState("all"),[V,z]=m.useState("usage_count"),[_,T]=m.useState("desc"),[$,E]=m.useState(null),[se,te]=m.useState(!1),[ne,ue]=m.useState(!1),[Se,oe]=m.useState(!1),[je,be]=m.useState(new Set),[U,P]=m.useState(!1),[X,L]=m.useState(""),[B,_e]=m.useState("medium"),[Ne,Ce]=m.useState(!1),{toast:ve}=Ks(),ze=m.useCallback(async()=>{try{x(!0);const re=await E2({page:h,page_size:v,is_registered:b==="all"?void 0:b==="registered",is_banned:w==="all"?void 0:w==="banned",format:A==="all"?void 0:A,sort_by:V,sort_order:_});i(re.data),j(re.total)}catch(re){const pe=re instanceof Error?re.message:"加载表情包列表失败";ve({title:"错误",description:pe,variant:"destructive"})}finally{x(!1)}},[h,v,b,w,A,V,_,ve]),Q=async()=>{try{const re=await O2();o(re.data)}catch(re){console.error("加载统计数据失败:",re)}};m.useEffect(()=>{ze()},[ze]),m.useEffect(()=>{Q()},[]);const xe=async re=>{try{const pe=await z2(re.id);E(pe.data),te(!0)}catch(pe){const Ee=pe instanceof Error?pe.message:"加载详情失败";ve({title:"错误",description:Ee,variant:"destructive"})}},Te=re=>{E(re),ue(!0)},J=re=>{E(re),oe(!0)},le=async()=>{if($)try{await A2($.id),ve({title:"成功",description:"表情包已删除"}),oe(!1),E(null),ze(),Q()}catch(re){const pe=re instanceof Error?re.message:"删除失败";ve({title:"错误",description:pe,variant:"destructive"})}},qe=async re=>{try{await D2(re.id),ve({title:"成功",description:"表情包已注册"}),ze(),Q()}catch(pe){const Ee=pe instanceof Error?pe.message:"注册失败";ve({title:"错误",description:Ee,variant:"destructive"})}},We=async re=>{try{await R2(re.id),ve({title:"成功",description:"表情包已封禁"}),ze(),Q()}catch(pe){const Ee=pe instanceof Error?pe.message:"封禁失败";ve({title:"错误",description:Ee,variant:"destructive"})}},fe=re=>{const pe=new Set(je);pe.has(re)?pe.delete(re):pe.add(re),be(pe)},ls=async()=>{try{const re=await B2(Array.from(je));ve({title:"批量删除完成",description:re.message}),be(new Set),P(!1),ze(),Q()}catch(re){ve({title:"批量删除失败",description:re instanceof Error?re.message:"批量删除失败",variant:"destructive"})}},G=()=>{const re=parseInt(X),pe=Math.ceil(g/v);re>=1&&re<=pe?(f(re),L("")):ve({title:"无效的页码",description:`请输入1-${pe}之间的页码`,variant:"destructive"})},Me=r?.formats?Object.keys(r.formats):[];return e.jsxs("div",{className:"h-[calc(100vh-4rem)] flex flex-col p-4 sm:p-6",children:[e.jsxs("div",{className:"mb-4 sm:mb-6 flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4",children:[e.jsxs("div",{children:[e.jsx("h1",{className:"text-2xl sm:text-3xl font-bold",children:"表情包管理"}),e.jsx("p",{className:"text-sm text-muted-foreground mt-1",children:"管理麦麦的表情包资源"})]}),e.jsxs(C,{onClick:()=>Ce(!0),className:"gap-2",children:[e.jsx(_r,{className:"h-4 w-4"}),"上传表情包"]})]}),e.jsx(Ze,{className:"flex-1",children:e.jsxs("div",{className:"space-y-4 sm:space-y-6 pr-4",children:[r&&e.jsxs("div",{className:"grid gap-4 grid-cols-2 lg:grid-cols-4",children:[e.jsx(Ve,{children:e.jsxs(rs,{className:"pb-2",children:[e.jsx(st,{children:"总数"}),e.jsx(cs,{className:"text-2xl",children:r.total})]})}),e.jsx(Ve,{children:e.jsxs(rs,{className:"pb-2",children:[e.jsx(st,{children:"已注册"}),e.jsx(cs,{className:"text-2xl text-green-600",children:r.registered})]})}),e.jsx(Ve,{children:e.jsxs(rs,{className:"pb-2",children:[e.jsx(st,{children:"已封禁"}),e.jsx(cs,{className:"text-2xl text-red-600",children:r.banned})]})}),e.jsx(Ve,{children:e.jsxs(rs,{className:"pb-2",children:[e.jsx(st,{children:"未注册"}),e.jsx(cs,{className:"text-2xl text-gray-600",children:r.unregistered})]})})]}),e.jsxs(Ve,{children:[e.jsx(rs,{children:e.jsxs(cs,{className:"flex items-center gap-2",children:[e.jsx(lo,{className:"h-5 w-5"}),"筛选和排序"]})}),e.jsxs(gs,{className:"space-y-4",children:[e.jsxs("div",{className:"grid gap-4 sm:grid-cols-2 lg:grid-cols-4",children:[e.jsxs("div",{className:"space-y-2",children:[e.jsx(k,{children:"排序方式"}),e.jsxs(Ue,{value:`${V}-${_}`,onValueChange:re=>{const[pe,Ee]=re.split("-");z(pe),T(Ee),f(1)},children:[e.jsx(Re,{children:e.jsx(Be,{})}),e.jsxs(Le,{children:[e.jsx(ee,{value:"usage_count-desc",children:"使用次数 (多→少)"}),e.jsx(ee,{value:"usage_count-asc",children:"使用次数 (少→多)"}),e.jsx(ee,{value:"register_time-desc",children:"注册时间 (新→旧)"}),e.jsx(ee,{value:"register_time-asc",children:"注册时间 (旧→新)"}),e.jsx(ee,{value:"record_time-desc",children:"记录时间 (新→旧)"}),e.jsx(ee,{value:"record_time-asc",children:"记录时间 (旧→新)"}),e.jsx(ee,{value:"last_used_time-desc",children:"最后使用 (新→旧)"}),e.jsx(ee,{value:"last_used_time-asc",children:"最后使用 (旧→新)"})]})]})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(k,{children:"注册状态"}),e.jsxs(Ue,{value:b,onValueChange:re=>{S(re),f(1)},children:[e.jsx(Re,{children:e.jsx(Be,{})}),e.jsxs(Le,{children:[e.jsx(ee,{value:"all",children:"全部"}),e.jsx(ee,{value:"registered",children:"已注册"}),e.jsx(ee,{value:"unregistered",children:"未注册"})]})]})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(k,{children:"封禁状态"}),e.jsxs(Ue,{value:w,onValueChange:re=>{O(re),f(1)},children:[e.jsx(Re,{children:e.jsx(Be,{})}),e.jsxs(Le,{children:[e.jsx(ee,{value:"all",children:"全部"}),e.jsx(ee,{value:"banned",children:"已封禁"}),e.jsx(ee,{value:"unbanned",children:"未封禁"})]})]})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(k,{children:"格式"}),e.jsxs(Ue,{value:A,onValueChange:re=>{D(re),f(1)},children:[e.jsx(Re,{children:e.jsx(Be,{})}),e.jsxs(Le,{children:[e.jsx(ee,{value:"all",children:"全部"}),Me.map(re=>e.jsxs(ee,{value:re,children:[re.toUpperCase()," (",r?.formats[re],")"]},re))]})]})]})]}),e.jsxs("div",{className:"flex flex-col sm:flex-row items-start sm:items-center justify-between gap-3 pt-4 border-t",children:[e.jsxs("div",{className:"flex items-center gap-4",children:[je.size>0&&e.jsxs("span",{className:"text-sm text-muted-foreground",children:["已选择 ",je.size," 个表情包"]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(k,{className:"text-sm whitespace-nowrap",children:"卡片大小"}),e.jsxs(Ue,{value:B,onValueChange:re=>_e(re),children:[e.jsx(Re,{className:"w-24",children:e.jsx(Be,{})}),e.jsxs(Le,{children:[e.jsx(ee,{value:"small",children:"小"}),e.jsx(ee,{value:"medium",children:"中"}),e.jsx(ee,{value:"large",children:"大"})]})]})]})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(k,{htmlFor:"emoji-page-size",className:"text-sm whitespace-nowrap",children:"每页显示"}),e.jsxs(Ue,{value:v.toString(),onValueChange:re=>{y(parseInt(re)),f(1),be(new Set)},children:[e.jsx(Re,{id:"emoji-page-size",className:"w-20",children:e.jsx(Be,{})}),e.jsxs(Le,{children:[e.jsx(ee,{value:"20",children:"20"}),e.jsx(ee,{value:"40",children:"40"}),e.jsx(ee,{value:"60",children:"60"}),e.jsx(ee,{value:"100",children:"100"})]})]}),je.size>0&&e.jsxs(e.Fragment,{children:[e.jsx(C,{variant:"outline",size:"sm",onClick:()=>be(new Set),children:"取消选择"}),e.jsxs(C,{variant:"destructive",size:"sm",onClick:()=>P(!0),children:[e.jsx(es,{className:"h-4 w-4 mr-1"}),"批量删除"]})]})]})]}),e.jsx("div",{className:"flex justify-end pt-4 border-t",children:e.jsxs(C,{variant:"outline",size:"sm",onClick:ze,disabled:u,children:[e.jsx(At,{className:`h-4 w-4 mr-2 ${u?"animate-spin":""}`}),"刷新"]})})]})]}),e.jsxs(Ve,{children:[e.jsxs(rs,{children:[e.jsx(cs,{children:"表情包列表"}),e.jsxs(st,{children:["共 ",g," 个表情包,当前第 ",h," 页"]})]}),e.jsxs(gs,{children:[l.length===0?e.jsx("div",{className:"text-center py-12 text-muted-foreground",children:"暂无数据"}):e.jsx("div",{className:`grid gap-3 ${B==="small"?"grid-cols-3 sm:grid-cols-4 md:grid-cols-6 lg:grid-cols-8 xl:grid-cols-10":B==="medium"?"grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-6 xl:grid-cols-8":"grid-cols-2 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5"}`,children:l.map(re=>e.jsxs("div",{className:`group relative rounded-lg border bg-card overflow-hidden hover:ring-2 hover:ring-primary transition-all cursor-pointer ${je.has(re.id)?"ring-2 ring-primary bg-primary/5":""}`,onClick:()=>fe(re.id),children:[e.jsx("div",{className:`absolute top-1 left-1 z-10 transition-opacity ${je.has(re.id)?"opacity-100":"opacity-0 group-hover:opacity-100"}`,children:e.jsx("div",{className:`w-5 h-5 rounded-full border-2 flex items-center justify-center ${je.has(re.id)?"bg-primary border-primary text-primary-foreground":"bg-background/80 border-muted-foreground/50"}`,children:je.has(re.id)&&e.jsx(aa,{className:"h-3 w-3"})})}),e.jsxs("div",{className:"absolute top-1 right-1 z-10 flex flex-col gap-0.5",children:[re.is_registered&&e.jsx(Ye,{variant:"default",className:"bg-green-600 text-[10px] px-1 py-0",children:"已注册"}),re.is_banned&&e.jsx(Ye,{variant:"destructive",className:"text-[10px] px-1 py-0",children:"已封禁"})]}),e.jsx("div",{className:`aspect-square bg-muted flex items-center justify-center overflow-hidden ${B==="small"?"p-1":B==="medium"?"p-2":"p-3"}`,children:e.jsx(k2,{src:L2(re.id),alt:"表情包"})}),e.jsxs("div",{className:`border-t bg-card ${B==="small"?"p-1":"p-2"}`,children:[e.jsxs("div",{className:"flex items-center justify-between gap-1 text-xs text-muted-foreground mb-1",children:[e.jsx(Ye,{variant:"outline",className:"text-[10px] px-1 py-0",children:re.format.toUpperCase()}),e.jsxs("span",{className:"font-mono",children:[re.usage_count,"次"]})]}),e.jsxs("div",{className:`flex gap-1 justify-center opacity-0 group-hover:opacity-100 transition-opacity ${B==="small"?"flex-wrap":""}`,children:[e.jsx(C,{variant:"ghost",size:"icon",className:"h-6 w-6",onClick:pe=>{pe.stopPropagation(),Te(re)},title:"编辑",children:e.jsx(pn,{className:"h-3 w-3"})}),e.jsx(C,{variant:"ghost",size:"icon",className:"h-6 w-6",onClick:pe=>{pe.stopPropagation(),xe(re)},title:"详情",children:e.jsx(Ra,{className:"h-3 w-3"})}),!re.is_registered&&e.jsx(C,{variant:"ghost",size:"icon",className:"h-6 w-6 text-green-600 hover:text-green-700",onClick:pe=>{pe.stopPropagation(),qe(re)},title:"注册",children:e.jsx(aa,{className:"h-3 w-3"})}),!re.is_banned&&e.jsx(C,{variant:"ghost",size:"icon",className:"h-6 w-6 text-orange-600 hover:text-orange-700",onClick:pe=>{pe.stopPropagation(),We(re)},title:"封禁",children:e.jsx(Iy,{className:"h-3 w-3"})}),e.jsx(C,{variant:"ghost",size:"icon",className:"h-6 w-6 text-red-600 hover:text-red-700",onClick:pe=>{pe.stopPropagation(),J(re)},title:"删除",children:e.jsx(es,{className:"h-3 w-3"})})]})]})]},re.id))}),g>0&&e.jsxs("div",{className:"flex flex-col sm:flex-row items-center justify-between gap-4 mt-4",children:[e.jsxs("div",{className:"text-sm text-muted-foreground",children:["显示 ",(h-1)*v+1," 到"," ",Math.min(h*v,g)," 条,共 ",g," 条"]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(C,{variant:"outline",size:"sm",onClick:()=>f(1),disabled:h===1,className:"hidden sm:flex",children:e.jsx(vi,{className:"h-4 w-4"})}),e.jsxs(C,{variant:"outline",size:"sm",onClick:()=>f(re=>Math.max(1,re-1)),disabled:h===1,children:[e.jsx(pl,{className:"h-4 w-4 sm:mr-1"}),e.jsx("span",{className:"hidden sm:inline",children:"上一页"})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(ie,{type:"number",value:X,onChange:re=>L(re.target.value),onKeyDown:re=>re.key==="Enter"&&G(),placeholder:h.toString(),className:"w-16 h-8 text-center",min:1,max:Math.ceil(g/v)}),e.jsx(C,{variant:"outline",size:"sm",onClick:G,disabled:!X,className:"h-8",children:"跳转"})]}),e.jsxs(C,{variant:"outline",size:"sm",onClick:()=>f(re=>re+1),disabled:h>=Math.ceil(g/v),children:[e.jsx("span",{className:"hidden sm:inline",children:"下一页"}),e.jsx(Ya,{className:"h-4 w-4 sm:ml-1"})]}),e.jsx(C,{variant:"outline",size:"sm",onClick:()=>f(Math.ceil(g/v)),disabled:h>=Math.ceil(g/v),className:"hidden sm:flex",children:e.jsx(bi,{className:"h-4 w-4"})})]})]})]})]}),e.jsx(q2,{emoji:$,open:se,onOpenChange:te}),e.jsx(G2,{emoji:$,open:ne,onOpenChange:ue,onSuccess:()=>{ze(),Q()}}),e.jsx(V2,{open:Ne,onOpenChange:Ce,onSuccess:()=>{ze(),Q()}})]})}),e.jsx(js,{open:U,onOpenChange:P,children:e.jsxs(os,{children:[e.jsxs(ds,{children:[e.jsx(ms,{children:"确认批量删除"}),e.jsxs(xs,{children:["你确定要删除选中的 ",je.size," 个表情包吗?此操作不可撤销。"]})]}),e.jsxs(us,{children:[e.jsx(fs,{children:"取消"}),e.jsx(hs,{onClick:ls,children:"确认删除"})]})]})}),e.jsx(Qs,{open:Se,onOpenChange:oe,children:e.jsxs(qs,{children:[e.jsxs(Gs,{children:[e.jsx(Vs,{children:"确认删除"}),e.jsx(Ws,{children:"确定要删除这个表情包吗?此操作无法撤销。"})]}),e.jsxs(at,{children:[e.jsx(C,{variant:"outline",onClick:()=>oe(!1),children:"取消"}),e.jsx(C,{variant:"destructive",onClick:le,children:"删除"})]})]})})]})}function q2({emoji:l,open:i,onOpenChange:r}){if(!l)return null;const o=u=>u?new Date(u*1e3).toLocaleString("zh-CN"):"-";return e.jsx(Qs,{open:i,onOpenChange:r,children:e.jsxs(qs,{className:"max-w-2xl max-h-[90vh]",children:[e.jsx(Gs,{children:e.jsx(Vs,{children:"表情包详情"})}),e.jsx(Ze,{className:"max-h-[calc(90vh-8rem)] pr-4",children:e.jsxs("div",{className:"space-y-4",children:[e.jsx("div",{className:"flex justify-center",children:e.jsx("div",{className:"w-32 h-32 bg-muted rounded-lg flex items-center justify-center overflow-hidden",children:e.jsx("img",{src:U2(l.id),alt:l.description||"表情包",className:"w-full h-full object-cover",onError:u=>{const x=u.target;x.style.display="none";const h=x.parentElement;h&&(h.innerHTML='')}})})}),e.jsxs("div",{className:"grid gap-4 sm:grid-cols-2",children:[e.jsxs("div",{children:[e.jsx(k,{className:"text-muted-foreground",children:"ID"}),e.jsx("div",{className:"mt-1 font-mono",children:l.id})]}),e.jsxs("div",{children:[e.jsx(k,{className:"text-muted-foreground",children:"格式"}),e.jsx("div",{className:"mt-1",children:e.jsx(Ye,{variant:"outline",children:l.format.toUpperCase()})})]})]}),e.jsxs("div",{children:[e.jsx(k,{className:"text-muted-foreground",children:"文件路径"}),e.jsx("div",{className:"mt-1 font-mono text-sm break-all bg-muted p-2 rounded",children:l.full_path})]}),e.jsxs("div",{children:[e.jsx(k,{className:"text-muted-foreground",children:"哈希值"}),e.jsx("div",{className:"mt-1 font-mono text-sm break-all bg-muted p-2 rounded",children:l.emoji_hash})]}),e.jsxs("div",{children:[e.jsx(k,{className:"text-muted-foreground",children:"描述"}),l.description?e.jsx("div",{className:"mt-1 rounded-lg border bg-muted/50 p-3",children:e.jsx(T2,{className:"prose-sm",children:l.description})}):e.jsx("div",{className:"mt-1 text-sm text-muted-foreground",children:"-"})]}),e.jsxs("div",{children:[e.jsx(k,{className:"text-muted-foreground",children:"情绪"}),e.jsx("div",{className:"mt-1",children:l.emotion?e.jsx("span",{className:"text-sm",children:l.emotion}):e.jsx("span",{className:"text-sm text-muted-foreground",children:"-"})})]}),e.jsxs("div",{className:"grid gap-4 sm:grid-cols-2",children:[e.jsxs("div",{children:[e.jsx(k,{className:"text-muted-foreground",children:"状态"}),e.jsxs("div",{className:"mt-2 flex gap-2",children:[l.is_registered&&e.jsx(Ye,{variant:"default",className:"bg-green-600",children:"已注册"}),l.is_banned&&e.jsx(Ye,{variant:"destructive",children:"已封禁"}),!l.is_registered&&!l.is_banned&&e.jsx(Ye,{variant:"outline",children:"未注册"})]})]}),e.jsxs("div",{children:[e.jsx(k,{className:"text-muted-foreground",children:"使用次数"}),e.jsx("div",{className:"mt-1 font-mono text-lg",children:l.usage_count})]})]}),e.jsxs("div",{className:"grid gap-4 sm:grid-cols-2",children:[e.jsxs("div",{children:[e.jsx(k,{className:"text-muted-foreground",children:"记录时间"}),e.jsx("div",{className:"mt-1 text-sm",children:o(l.record_time)})]}),e.jsxs("div",{children:[e.jsx(k,{className:"text-muted-foreground",children:"注册时间"}),e.jsx("div",{className:"mt-1 text-sm",children:o(l.register_time)})]})]}),e.jsxs("div",{children:[e.jsx(k,{className:"text-muted-foreground",children:"最后使用"}),e.jsx("div",{className:"mt-1 text-sm",children:o(l.last_used_time)})]})]})})]})})}function G2({emoji:l,open:i,onOpenChange:r,onSuccess:o}){const[u,x]=m.useState(""),[h,f]=m.useState(!1),[g,j]=m.useState(!1),[v,y]=m.useState(!1),{toast:b}=Ks();m.useEffect(()=>{l&&(x(l.emotion||""),f(l.is_registered),j(l.is_banned))},[l]);const S=async()=>{if(l)try{y(!0);const w=u.split(/[,,]/).map(O=>O.trim()).filter(Boolean).join(",");await M2(l.id,{emotion:w||void 0,is_registered:h,is_banned:g}),b({title:"成功",description:"表情包信息已更新"}),r(!1),o()}catch(w){const O=w instanceof Error?w.message:"保存失败";b({title:"错误",description:O,variant:"destructive"})}finally{y(!1)}};return l?e.jsx(Qs,{open:i,onOpenChange:r,children:e.jsxs(qs,{className:"max-w-2xl",children:[e.jsxs(Gs,{children:[e.jsx(Vs,{children:"编辑表情包"}),e.jsx(Ws,{children:"修改表情包的情绪和状态信息"})]}),e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{children:[e.jsx(k,{children:"情绪"}),e.jsx(Ys,{value:u,onChange:w=>x(w.target.value),placeholder:"输入情绪描述...",rows:2,className:"mt-1"}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:"输入情绪相关的文本描述"})]}),e.jsxs("div",{className:"grid gap-4 sm:grid-cols-2",children:[e.jsxs("div",{className:"flex items-center space-x-2",children:[e.jsx(jt,{id:"is_registered",checked:h,onCheckedChange:w=>{w===!0?(f(!0),j(!1)):f(!1)}}),e.jsx(k,{htmlFor:"is_registered",className:"cursor-pointer",children:"已注册"})]}),e.jsxs("div",{className:"flex items-center space-x-2",children:[e.jsx(jt,{id:"is_banned",checked:g,onCheckedChange:w=>{w===!0?(j(!0),f(!1)):j(!1)}}),e.jsx(k,{htmlFor:"is_banned",className:"cursor-pointer",children:"已封禁"})]})]})]}),e.jsxs(at,{children:[e.jsx(C,{variant:"outline",onClick:()=>r(!1),children:"取消"}),e.jsx(C,{onClick:S,disabled:v,children:v?"保存中...":"保存"})]})]})}):null}function V2({open:l,onOpenChange:i,onSuccess:r}){const[o,u]=m.useState("select"),[x,h]=m.useState([]),[f,g]=m.useState(null),[j,v]=m.useState(!1),{toast:y}=Ks(),b=m.useMemo(()=>new j0({id:"emoji-uploader",autoProceed:!1,restrictions:{maxFileSize:10485760,allowedFileTypes:["image/jpeg","image/png","image/gif","image/webp"],maxNumberOfFiles:20},locale:{pluralize:()=>0,strings:{addMoreFiles:"添加更多文件",addingMoreFiles:"正在添加更多文件",allowedFileTypes:"允许的文件类型:%{types}",cancel:"取消",closeModal:"关闭",complete:"完成",connectedToInternet:"已连接到互联网",copyLink:"复制链接",copyLinkToClipboardFallback:"复制下方链接",copyLinkToClipboardSuccess:"链接已复制到剪贴板",dashboardTitle:"选择文件",dashboardWindowTitle:"文件选择窗口(按 ESC 关闭)",done:"完成",dropHereOr:"拖放文件到这里或 %{browse}",dropHint:"将文件拖放到此处",dropPasteFiles:"将文件拖放到这里或 %{browseFiles}",dropPasteFolders:"将文件拖放到这里或 %{browseFolders}",dropPasteBoth:"将文件拖放到这里,%{browseFiles} 或 %{browseFolders}",dropPasteImportFiles:"将文件拖放到这里,%{browseFiles} 或从以下位置导入:",dropPasteImportFolders:"将文件拖放到这里,%{browseFolders} 或从以下位置导入:",dropPasteImportBoth:"将文件拖放到这里,%{browseFiles},%{browseFolders} 或从以下位置导入:",editFile:"编辑文件",editing:"正在编辑 %{file}",emptyFolderAdded:"未从空文件夹添加文件",exceedsSize:"%{file} 超过了最大允许大小 %{size}",failedToUpload:"上传 %{file} 失败",fileSource:"文件来源:%{name}",filesUploadedOfTotal:{0:"已上传 %{complete} / %{smart_count} 个文件",1:"已上传 %{complete} / %{smart_count} 个文件"},filter:"筛选",finishEditingFile:"完成编辑文件",folderAdded:{0:"已从 %{folder} 添加 %{smart_count} 个文件",1:"已从 %{folder} 添加 %{smart_count} 个文件"},generatingThumbnails:"正在生成缩略图...",import:"导入",importFiles:"从以下位置导入文件:",importFrom:"从 %{name} 导入",loading:"加载中...",logOut:"登出",myDevice:"我的设备",noFilesFound:"这里没有文件或文件夹",noInternetConnection:"无网络连接",openFolderNamed:"打开文件夹 %{name}",pause:"暂停",pauseUpload:"暂停上传",paused:"已暂停",poweredBy:"技术支持:%{uppy}",processingXFiles:{0:"正在处理 %{smart_count} 个文件",1:"正在处理 %{smart_count} 个文件"},recording:"录制中",removeFile:"移除文件",resetFilter:"重置筛选",resume:"继续",resumeUpload:"继续上传",retry:"重试",retryUpload:"重试上传",save:"保存",saveChanges:"保存更改",selectFileNamed:"选择文件 %{name}",selectX:{0:"选择 %{smart_count}",1:"选择 %{smart_count}"},smile:"笑一个!",startRecording:"开始录制视频",stopRecording:"停止录制视频",takePicture:"拍照",timedOut:"上传已停滞 %{seconds} 秒,正在中止。",upload:"下一步",uploadComplete:"上传完成",uploadFailed:"上传失败",uploadPaused:"上传已暂停",uploadXFiles:{0:"下一步(%{smart_count} 个文件)",1:"下一步(%{smart_count} 个文件)"},uploadXNewFiles:{0:"下一步(+%{smart_count} 个文件)",1:"下一步(+%{smart_count} 个文件)"},uploading:"正在上传",uploadingXFiles:{0:"正在上传 %{smart_count} 个文件",1:"正在上传 %{smart_count} 个文件"},xFilesSelected:{0:"已选择 %{smart_count} 个文件",1:"已选择 %{smart_count} 个文件"},xMoreFilesAdded:{0:"又添加了 %{smart_count} 个文件",1:"又添加了 %{smart_count} 个文件"},xTimeLeft:"剩余 %{time}",youCanOnlyUploadFileTypes:"您只能上传:%{types}",youCanOnlyUploadX:{0:"您只能上传 %{smart_count} 个文件",1:"您只能上传 %{smart_count} 个文件"},youHaveToAtLeastSelectX:{0:"您至少需要选择 %{smart_count} 个文件",1:"您至少需要选择 %{smart_count} 个文件"},browseFiles:"浏览文件",browseFolders:"浏览文件夹",cancelUpload:"取消上传",addMore:"添加更多",back:"返回",editFileWithFilename:"编辑文件 %{file}"}}}),[]);m.useEffect(()=>{const $=()=>{const E=b.getFiles();if(E.length===0)return;const se=E.map(te=>({id:te.id,name:te.name,previewUrl:te.preview||URL.createObjectURL(te.data),emotion:"",description:"",isRegistered:!0,file:te.data}));h(se),E.length===1?(g(se[0].id),u("edit-single")):u("edit-multiple")};return b.on("upload",$),()=>{b.off("upload",$)}},[b]),m.useEffect(()=>{l||(b.cancelAll(),u("select"),h([]),g(null),v(!1))},[l,b]);const S=m.useCallback(($,E)=>{h(se=>se.map(te=>te.id===$?{...te,...E}:te))},[]),w=m.useCallback($=>$.emotion.trim().length>0,[]),O=m.useMemo(()=>x.length>0&&x.every(w),[x,w]),A=m.useMemo(()=>x.find($=>$.id===f)||null,[x,f]),D=m.useCallback(()=>{(o==="edit-single"||o==="edit-multiple")&&(u("select"),h([]),g(null))},[o]),V=m.useCallback(async()=>{if(!O){y({title:"请填写必填项",description:"每个表情包的情感标签都是必填的",variant:"destructive"});return}v(!0);let $=0,E=0;try{for(const se of x){const te=new FormData;te.append("file",se.file),te.append("emotion",se.emotion),te.append("description",se.description),te.append("is_registered",se.isRegistered.toString());try{(await we(H2(),{method:"POST",body:te})).ok?$++:E++}catch{E++}}E===0?(y({title:"上传成功",description:`成功上传 ${$} 个表情包`}),i(!1),r()):(y({title:"部分上传失败",description:`成功 ${$} 个,失败 ${E} 个`,variant:"destructive"}),r())}finally{v(!1)}},[O,x,y,i,r]),z=()=>e.jsx("div",{className:"space-y-4",children:e.jsx("div",{className:"border rounded-lg overflow-hidden w-full",children:e.jsx(C2,{uppy:b,proudlyDisplayPoweredByUppy:!1,hideProgressDetails:!0,height:350,width:"100%",theme:"auto",note:"支持 JPG、PNG、GIF、WebP 格式,最多 20 个文件"})})}),_=()=>{const $=x[0];return $?e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"flex items-center gap-4",children:[e.jsxs(C,{variant:"ghost",size:"sm",onClick:D,children:[e.jsx(hi,{className:"h-4 w-4 mr-1"}),"返回"]}),e.jsx("span",{className:"text-sm text-muted-foreground",children:"编辑表情包信息"})]}),e.jsxs("div",{className:"flex gap-6",children:[e.jsxs("div",{className:"flex-shrink-0",children:[e.jsx("div",{className:"w-32 h-32 rounded-lg border overflow-hidden bg-muted flex items-center justify-center",children:e.jsx("img",{src:$.previewUrl,alt:$.name,className:"max-w-full max-h-full object-contain"})}),e.jsx("p",{className:"text-xs text-muted-foreground mt-2 text-center truncate max-w-32",children:$.name})]}),e.jsxs("div",{className:"flex-1 space-y-4",children:[e.jsxs("div",{className:"space-y-2",children:[e.jsxs(k,{htmlFor:"single-emotion",children:["情感标签 ",e.jsx("span",{className:"text-destructive",children:"*"})]}),e.jsx(ie,{id:"single-emotion",value:$.emotion,onChange:E=>S($.id,{emotion:E.target.value}),placeholder:"多个标签用逗号分隔,如:开心,高兴",className:$.emotion.trim()?"":"border-destructive"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"用于情感匹配,多个标签用逗号分隔"})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(k,{htmlFor:"single-description",children:"描述"}),e.jsx(ie,{id:"single-description",value:$.description,onChange:E=>S($.id,{description:E.target.value}),placeholder:"输入表情包描述..."})]}),e.jsxs("div",{className:"flex items-center space-x-2",children:[e.jsx(jt,{id:"single-is-registered",checked:$.isRegistered,onCheckedChange:E=>S($.id,{isRegistered:E===!0})}),e.jsx(k,{htmlFor:"single-is-registered",className:"cursor-pointer",children:"上传后立即注册(可被麦麦使用)"})]})]})]}),e.jsx(at,{children:e.jsx(C,{onClick:V,disabled:!O||j,children:j?"上传中...":"上传"})})]}):null},T=()=>{const $=x.filter(w).length,E=x.length;return e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"flex items-center gap-4",children:[e.jsxs(C,{variant:"ghost",size:"sm",onClick:D,children:[e.jsx(hi,{className:"h-4 w-4 mr-1"}),"返回"]}),e.jsxs("span",{className:"text-sm text-muted-foreground",children:["编辑表情包信息(",$,"/",E," 已完成)"]})]}),e.jsx(Ye,{variant:O?"default":"secondary",children:O?e.jsxs(e.Fragment,{children:[e.jsx(ea,{className:"h-3 w-3 mr-1"}),"全部完成"]}):e.jsxs(e.Fragment,{children:[e.jsx(fl,{className:"h-3 w-3 mr-1"}),"未完成"]})})]}),e.jsxs("div",{className:"grid grid-cols-2 gap-4",children:[e.jsx(Ze,{className:"h-[350px] pr-2",children:e.jsx("div",{className:"space-y-2",children:x.map(se=>{const te=w(se),ne=f===se.id;return e.jsxs("div",{onClick:()=>g(se.id),className:` + flex items-center gap-3 p-3 rounded-lg border-2 cursor-pointer transition-all + ${ne?"ring-2 ring-primary":""} + ${te?"border-green-500 bg-green-50 dark:bg-green-950/20":"border-border hover:border-muted-foreground/50"} + `,children:[e.jsx("div",{className:"w-12 h-12 rounded border overflow-hidden bg-muted flex-shrink-0 flex items-center justify-center",children:e.jsx("img",{src:se.previewUrl,alt:se.name,className:"max-w-full max-h-full object-contain"})}),e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsx("p",{className:"text-sm font-medium truncate",children:se.name}),e.jsx("p",{className:"text-xs text-muted-foreground truncate",children:se.emotion||"未填写情感标签"})]}),te?e.jsx(aa,{className:"h-5 w-5 text-green-500 flex-shrink-0"}):e.jsx("div",{className:"h-5 w-5 rounded-full border-2 border-muted-foreground/30 flex-shrink-0"})]},se.id)})})}),e.jsx("div",{className:"border rounded-lg p-4",children:A?e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("div",{className:"w-16 h-16 rounded border overflow-hidden bg-muted flex items-center justify-center",children:e.jsx("img",{src:A.previewUrl,alt:A.name,className:"max-w-full max-h-full object-contain"})}),e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsx("p",{className:"font-medium truncate",children:A.name}),w(A)&&e.jsxs(Ye,{variant:"outline",className:"text-green-600 border-green-600",children:[e.jsx(ea,{className:"h-3 w-3 mr-1"}),"已完成"]})]})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsxs(k,{htmlFor:"multi-emotion",children:["情感标签 ",e.jsx("span",{className:"text-destructive",children:"*"})]}),e.jsx(ie,{id:"multi-emotion",value:A.emotion,onChange:se=>S(A.id,{emotion:se.target.value}),placeholder:"多个标签用逗号分隔,如:开心,高兴",className:A.emotion.trim()?"":"border-destructive"})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(k,{htmlFor:"multi-description",children:"描述"}),e.jsx(ie,{id:"multi-description",value:A.description,onChange:se=>S(A.id,{description:se.target.value}),placeholder:"输入表情包描述..."})]}),e.jsxs("div",{className:"flex items-center space-x-2",children:[e.jsx(jt,{id:"multi-is-registered",checked:A.isRegistered,onCheckedChange:se=>S(A.id,{isRegistered:se===!0})}),e.jsx(k,{htmlFor:"multi-is-registered",className:"cursor-pointer text-sm",children:"上传后立即注册"})]})]}):e.jsx("div",{className:"h-full flex items-center justify-center text-muted-foreground",children:e.jsxs("div",{className:"text-center",children:[e.jsx(Ug,{className:"h-12 w-12 mx-auto mb-2 opacity-50"}),e.jsx("p",{children:"点击左侧卡片编辑"})]})})})]}),e.jsx(at,{children:e.jsx(C,{onClick:V,disabled:!O||j,children:j?"上传中...":`上传全部 (${E})`})})]})};return e.jsx(Qs,{open:l,onOpenChange:i,children:e.jsxs(qs,{className:"max-w-3xl max-h-[90vh] overflow-hidden",children:[e.jsxs(Gs,{children:[e.jsxs(Vs,{className:"flex items-center gap-2",children:[e.jsx(_r,{className:"h-5 w-5"}),o==="select"&&"上传表情包 - 选择文件",o==="edit-single"&&"上传表情包 - 填写信息",o==="edit-multiple"&&"上传表情包 - 批量编辑"]}),e.jsxs(Ws,{children:[o==="select"&&"支持 JPG、PNG、GIF、WebP 格式,单个文件最大 10MB,可同时上传多个文件",o==="edit-single"&&"请填写表情包的情感标签(必填)和描述",o==="edit-multiple"&&"点击左侧卡片编辑每个表情包的信息,情感标签为必填项"]})]}),e.jsxs("div",{className:"overflow-y-auto pr-1",children:[o==="select"&&z(),o==="edit-single"&&_(),o==="edit-multiple"&&T()]})]})})}const Yl="/api/webui/expression";async function F2(){const l=await we(`${Yl}/chats`,{});if(!l.ok){const i=await l.json();throw new Error(i.detail||"获取聊天列表失败")}return l.json()}async function I2(l){const i=new URLSearchParams;l.page&&i.append("page",l.page.toString()),l.page_size&&i.append("page_size",l.page_size.toString()),l.search&&i.append("search",l.search),l.chat_id&&i.append("chat_id",l.chat_id);const r=await we(`${Yl}/list?${i}`,{});if(!r.ok){const o=await r.json();throw new Error(o.detail||"获取表达方式列表失败")}return r.json()}async function Q2(l){const i=await we(`${Yl}/${l}`,{});if(!i.ok){const r=await i.json();throw new Error(r.detail||"获取表达方式详情失败")}return i.json()}async function Y2(l){const i=await we(`${Yl}/`,{method:"POST",body:JSON.stringify(l)});if(!i.ok){const r=await i.json();throw new Error(r.detail||"创建表达方式失败")}return i.json()}async function K2(l,i){const r=await we(`${Yl}/${l}`,{method:"PATCH",body:JSON.stringify(i)});if(!r.ok){const o=await r.json();throw new Error(o.detail||"更新表达方式失败")}return r.json()}async function X2(l){const i=await we(`${Yl}/${l}`,{method:"DELETE"});if(!i.ok){const r=await i.json();throw new Error(r.detail||"删除表达方式失败")}return i.json()}async function P2(l){const i=await we(`${Yl}/batch/delete`,{method:"POST",body:JSON.stringify({ids:l})});if(!i.ok){const r=await i.json();throw new Error(r.detail||"批量删除表达方式失败")}return i.json()}async function J2(){const l=await we(`${Yl}/stats/summary`,{});if(!l.ok){const i=await l.json();throw new Error(i.detail||"获取统计数据失败")}return l.json()}function Z2(){const[l,i]=m.useState([]),[r,o]=m.useState(!0),[u,x]=m.useState(0),[h,f]=m.useState(1),[g,j]=m.useState(20),[v,y]=m.useState(""),[b,S]=m.useState(null),[w,O]=m.useState(!1),[A,D]=m.useState(!1),[V,z]=m.useState(!1),[_,T]=m.useState(null),[$,E]=m.useState(new Set),[se,te]=m.useState(!1),[ne,ue]=m.useState(""),[Se,oe]=m.useState({total:0,recent_7days:0,chat_count:0,top_chats:{}}),[je,be]=m.useState([]),[U,P]=m.useState(new Map),{toast:X}=Ks(),L=async()=>{try{o(!0);const le=await I2({page:h,page_size:g,search:v||void 0});i(le.data),x(le.total)}catch(le){X({title:"加载失败",description:le instanceof Error?le.message:"无法加载表达方式",variant:"destructive"})}finally{o(!1)}},B=async()=>{try{const le=await J2();le?.data&&oe(le.data)}catch(le){console.error("加载统计数据失败:",le)}},_e=async()=>{try{const le=await F2();if(le?.data){be(le.data);const qe=new Map;le.data.forEach(We=>{qe.set(We.chat_id,We.chat_name)}),P(qe)}}catch(le){console.error("加载聊天列表失败:",le)}},Ne=le=>U.get(le)||le;m.useEffect(()=>{L(),B(),_e()},[h,g,v]);const Ce=async le=>{try{const qe=await Q2(le.id);S(qe.data),O(!0)}catch(qe){X({title:"加载详情失败",description:qe instanceof Error?qe.message:"无法加载表达方式详情",variant:"destructive"})}},ve=le=>{S(le),D(!0)},ze=async le=>{try{await X2(le.id),X({title:"删除成功",description:`已删除表达方式: ${le.situation}`}),T(null),L(),B()}catch(qe){X({title:"删除失败",description:qe instanceof Error?qe.message:"无法删除表达方式",variant:"destructive"})}},Q=le=>{const qe=new Set($);qe.has(le)?qe.delete(le):qe.add(le),E(qe)},xe=()=>{$.size===l.length&&l.length>0?E(new Set):E(new Set(l.map(le=>le.id)))},Te=async()=>{try{await P2(Array.from($)),X({title:"批量删除成功",description:`已删除 ${$.size} 个表达方式`}),E(new Set),te(!1),L(),B()}catch(le){X({title:"批量删除失败",description:le instanceof Error?le.message:"无法批量删除表达方式",variant:"destructive"})}},J=()=>{const le=parseInt(ne),qe=Math.ceil(u/g);le>=1&&le<=qe?(f(le),ue("")):X({title:"无效的页码",description:`请输入1-${qe}之间的页码`,variant:"destructive"})};return e.jsxs("div",{className:"h-[calc(100vh-4rem)] flex flex-col p-4 sm:p-6",children:[e.jsx("div",{className:"mb-4 sm:mb-6",children:e.jsxs("div",{className:"flex flex-col sm:flex-row sm:items-center justify-between gap-4",children:[e.jsxs("div",{children:[e.jsxs("h1",{className:"text-2xl sm:text-3xl font-bold flex items-center gap-2",children:[e.jsx(Fl,{className:"h-8 w-8",strokeWidth:2}),"表达方式管理"]}),e.jsx("p",{className:"text-muted-foreground mt-1 text-sm sm:text-base",children:"管理麦麦的表达方式和话术模板"})]}),e.jsxs(C,{onClick:()=>z(!0),className:"gap-2",children:[e.jsx(ut,{className:"h-4 w-4"}),"新增表达方式"]})]})}),e.jsx(Ze,{className:"flex-1",children:e.jsxs("div",{className:"space-y-4 sm:space-y-6 pr-4",children:[e.jsxs("div",{className:"grid grid-cols-1 sm:grid-cols-3 gap-4",children:[e.jsxs("div",{className:"rounded-lg border bg-card p-4",children:[e.jsx("div",{className:"text-sm text-muted-foreground",children:"总数量"}),e.jsx("div",{className:"text-2xl font-bold mt-1",children:Se.total})]}),e.jsxs("div",{className:"rounded-lg border bg-card p-4",children:[e.jsx("div",{className:"text-sm text-muted-foreground",children:"近7天新增"}),e.jsx("div",{className:"text-2xl font-bold mt-1 text-green-600",children:Se.recent_7days})]}),e.jsxs("div",{className:"rounded-lg border bg-card p-4",children:[e.jsx("div",{className:"text-sm text-muted-foreground",children:"关联聊天数"}),e.jsx("div",{className:"text-2xl font-bold mt-1 text-blue-600",children:Se.chat_count})]})]}),e.jsxs("div",{className:"rounded-lg border bg-card p-4",children:[e.jsx(k,{htmlFor:"search",children:"搜索"}),e.jsx("div",{className:"flex flex-col sm:flex-row gap-2 mt-1.5",children:e.jsxs("div",{className:"flex-1 relative",children:[e.jsx($t,{className:"absolute left-2.5 top-2.5 h-4 w-4 text-muted-foreground"}),e.jsx(ie,{id:"search",placeholder:"搜索情境、风格或上下文...",value:v,onChange:le=>y(le.target.value),className:"pl-9"})]})}),e.jsxs("div",{className:"flex flex-col sm:flex-row items-start sm:items-center justify-between gap-3 mt-4 pt-4 border-t",children:[e.jsx("div",{className:"flex items-center gap-2 text-sm text-muted-foreground",children:$.size>0&&e.jsxs("span",{children:["已选择 ",$.size," 个表达方式"]})}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(k,{htmlFor:"page-size",className:"text-sm whitespace-nowrap",children:"每页显示"}),e.jsxs(Ue,{value:g.toString(),onValueChange:le=>{j(parseInt(le)),f(1),E(new Set)},children:[e.jsx(Re,{id:"page-size",className:"w-20",children:e.jsx(Be,{})}),e.jsxs(Le,{children:[e.jsx(ee,{value:"10",children:"10"}),e.jsx(ee,{value:"20",children:"20"}),e.jsx(ee,{value:"50",children:"50"}),e.jsx(ee,{value:"100",children:"100"})]})]}),$.size>0&&e.jsxs(e.Fragment,{children:[e.jsx(C,{variant:"outline",size:"sm",onClick:()=>E(new Set),children:"取消选择"}),e.jsxs(C,{variant:"destructive",size:"sm",onClick:()=>te(!0),children:[e.jsx(es,{className:"h-4 w-4 mr-1"}),"批量删除"]})]})]})]})]}),e.jsxs("div",{className:"rounded-lg border bg-card",children:[e.jsx("div",{className:"hidden md:block",children:e.jsxs(bn,{children:[e.jsx(Nn,{children:e.jsxs(gt,{children:[e.jsx(Je,{className:"w-12",children:e.jsx(jt,{checked:$.size===l.length&&l.length>0,onCheckedChange:xe})}),e.jsx(Je,{children:"情境"}),e.jsx(Je,{children:"风格"}),e.jsx(Je,{children:"聊天"}),e.jsx(Je,{className:"text-right",children:"操作"})]})}),e.jsx(yn,{children:r?e.jsx(gt,{children:e.jsx(Qe,{colSpan:5,className:"text-center py-8 text-muted-foreground",children:"加载中..."})}):l.length===0?e.jsx(gt,{children:e.jsx(Qe,{colSpan:5,className:"text-center py-8 text-muted-foreground",children:"暂无数据"})}):l.map(le=>e.jsxs(gt,{children:[e.jsx(Qe,{children:e.jsx(jt,{checked:$.has(le.id),onCheckedChange:()=>Q(le.id)})}),e.jsx(Qe,{className:"font-medium max-w-xs truncate",children:le.situation}),e.jsx(Qe,{className:"max-w-xs truncate",children:le.style}),e.jsx(Qe,{className:"max-w-[200px] truncate",title:Ne(le.chat_id),style:{wordBreak:"keep-all"},children:e.jsx("span",{className:"whitespace-nowrap overflow-hidden text-ellipsis block",children:Ne(le.chat_id)})}),e.jsx(Qe,{className:"text-right",children:e.jsxs("div",{className:"flex justify-end gap-2",children:[e.jsxs(C,{variant:"default",size:"sm",onClick:()=>ve(le),children:[e.jsx(pn,{className:"h-4 w-4 mr-1"}),"编辑"]}),e.jsx(C,{variant:"outline",size:"icon",className:"h-8 w-8",onClick:()=>Ce(le),title:"查看详情",children:e.jsx(Gt,{className:"h-4 w-4"})}),e.jsxs(C,{size:"sm",onClick:()=>T(le),className:"bg-red-600 hover:bg-red-700 text-white",children:[e.jsx(es,{className:"h-4 w-4 mr-1"}),"删除"]})]})})]},le.id))})]})}),e.jsx("div",{className:"md:hidden space-y-3 p-4",children:r?e.jsx("div",{className:"text-center py-8 text-muted-foreground",children:"加载中..."}):l.length===0?e.jsx("div",{className:"text-center py-8 text-muted-foreground",children:"暂无数据"}):l.map(le=>e.jsxs("div",{className:"rounded-lg border bg-card p-4 space-y-3 overflow-hidden",children:[e.jsxs("div",{className:"flex items-start gap-3",children:[e.jsx(jt,{checked:$.has(le.id),onCheckedChange:()=>Q(le.id),className:"mt-1"}),e.jsxs("div",{className:"min-w-0 flex-1 overflow-hidden space-y-2",children:[e.jsxs("div",{children:[e.jsx("div",{className:"text-xs text-muted-foreground mb-1",children:"情境"}),e.jsx("h3",{className:"font-semibold text-sm line-clamp-2 w-full break-all",title:le.situation,children:le.situation})]}),e.jsxs("div",{children:[e.jsx("div",{className:"text-xs text-muted-foreground mb-1",children:"风格"}),e.jsx("p",{className:"text-sm line-clamp-2 w-full break-all",title:le.style,children:le.style})]})]})]}),e.jsxs("div",{className:"text-sm",children:[e.jsx("div",{className:"text-xs text-muted-foreground mb-1",children:"聊天"}),e.jsx("p",{className:"text-sm truncate",title:Ne(le.chat_id),style:{wordBreak:"keep-all"},children:Ne(le.chat_id)})]}),e.jsxs("div",{className:"flex flex-wrap gap-1 pt-2 border-t overflow-hidden",children:[e.jsxs(C,{variant:"outline",size:"sm",onClick:()=>ve(le),className:"text-xs px-2 py-1 h-auto flex-shrink-0",children:[e.jsx(pn,{className:"h-3 w-3 mr-1"}),"编辑"]}),e.jsx(C,{variant:"outline",size:"sm",onClick:()=>Ce(le),className:"text-xs px-2 py-1 h-auto flex-shrink-0",children:e.jsx(Gt,{className:"h-3 w-3"})}),e.jsxs(C,{variant:"outline",size:"sm",onClick:()=>T(le),className:"text-xs px-2 py-1 h-auto flex-shrink-0 text-destructive hover:text-destructive",children:[e.jsx(es,{className:"h-3 w-3 mr-1"}),"删除"]})]})]},le.id))}),u>0&&e.jsxs("div",{className:"flex flex-col sm:flex-row items-center justify-between gap-4 px-4 py-3 border-t",children:[e.jsxs("div",{className:"text-sm text-muted-foreground",children:["共 ",u," 条记录,第 ",h," / ",Math.ceil(u/g)," 页"]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(C,{variant:"outline",size:"sm",onClick:()=>f(1),disabled:h===1,className:"hidden sm:flex",children:e.jsx(vi,{className:"h-4 w-4"})}),e.jsxs(C,{variant:"outline",size:"sm",onClick:()=>f(h-1),disabled:h===1,children:[e.jsx(pl,{className:"h-4 w-4 sm:mr-1"}),e.jsx("span",{className:"hidden sm:inline",children:"上一页"})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(ie,{type:"number",value:ne,onChange:le=>ue(le.target.value),onKeyDown:le=>le.key==="Enter"&&J(),placeholder:h.toString(),className:"w-16 h-8 text-center",min:1,max:Math.ceil(u/g)}),e.jsx(C,{variant:"outline",size:"sm",onClick:J,disabled:!ne,className:"h-8",children:"跳转"})]}),e.jsxs(C,{variant:"outline",size:"sm",onClick:()=>f(h+1),disabled:h>=Math.ceil(u/g),children:[e.jsx("span",{className:"hidden sm:inline",children:"下一页"}),e.jsx(Ya,{className:"h-4 w-4 sm:ml-1"})]}),e.jsx(C,{variant:"outline",size:"sm",onClick:()=>f(Math.ceil(u/g)),disabled:h>=Math.ceil(u/g),className:"hidden sm:flex",children:e.jsx(bi,{className:"h-4 w-4"})})]})]})]})]})}),e.jsx(W2,{expression:b,open:w,onOpenChange:O,chatNameMap:U}),e.jsx(e_,{open:V,onOpenChange:z,chatList:je,onSuccess:()=>{L(),B(),z(!1)}}),e.jsx(s_,{expression:b,open:A,onOpenChange:D,chatList:je,onSuccess:()=>{L(),B(),D(!1)}}),e.jsx(js,{open:!!_,onOpenChange:()=>T(null),children:e.jsxs(os,{children:[e.jsxs(ds,{children:[e.jsx(ms,{children:"确认删除"}),e.jsxs(xs,{children:['确定要删除表达方式 "',_?.situation,'" 吗? 此操作不可撤销。']})]}),e.jsxs(us,{children:[e.jsx(fs,{children:"取消"}),e.jsx(hs,{onClick:()=>_&&ze(_),className:"bg-destructive text-destructive-foreground hover:bg-destructive/90",children:"删除"})]})]})}),e.jsx(t_,{open:se,onOpenChange:te,onConfirm:Te,count:$.size})]})}function W2({expression:l,open:i,onOpenChange:r,chatNameMap:o}){if(!l)return null;const u=h=>h?new Date(h*1e3).toLocaleString("zh-CN"):"-",x=h=>o.get(h)||h;return e.jsx(Qs,{open:i,onOpenChange:r,children:e.jsxs(qs,{className:"max-w-2xl max-h-[80vh] overflow-y-auto",children:[e.jsxs(Gs,{children:[e.jsx(Vs,{children:"表达方式详情"}),e.jsx(Ws,{children:"查看表达方式的完整信息"})]}),e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"grid grid-cols-2 gap-4",children:[e.jsx(hr,{label:"情境",value:l.situation}),e.jsx(hr,{label:"风格",value:l.style}),e.jsx(hr,{label:"聊天",value:x(l.chat_id)}),e.jsx(hr,{icon:pi,label:"记录ID",value:l.id.toString(),mono:!0})]}),e.jsx("div",{className:"grid grid-cols-2 gap-4",children:e.jsx(hr,{icon:xi,label:"创建时间",value:u(l.create_date)})})]}),e.jsx(at,{children:e.jsx(C,{onClick:()=>r(!1),children:"关闭"})})]})})}function hr({icon:l,label:i,value:r,mono:o=!1}){return e.jsxs("div",{className:"space-y-1",children:[e.jsxs(k,{className:"text-xs text-muted-foreground flex items-center gap-1",children:[l&&e.jsx(l,{className:"h-3 w-3"}),i]}),e.jsx("div",{className:H("text-sm",o&&"font-mono",!r&&"text-muted-foreground"),children:r||"-"})]})}function e_({open:l,onOpenChange:i,chatList:r,onSuccess:o}){const[u,x]=m.useState({situation:"",style:"",chat_id:""}),[h,f]=m.useState(!1),{toast:g}=Ks(),j=async()=>{if(!u.situation||!u.style||!u.chat_id){g({title:"验证失败",description:"请填写必填字段:情境、风格和聊天",variant:"destructive"});return}try{f(!0),await Y2(u),g({title:"创建成功",description:"表达方式已创建"}),x({situation:"",style:"",chat_id:""}),o()}catch(v){g({title:"创建失败",description:v instanceof Error?v.message:"无法创建表达方式",variant:"destructive"})}finally{f(!1)}};return e.jsx(Qs,{open:l,onOpenChange:i,children:e.jsxs(qs,{className:"max-w-2xl max-h-[80vh] overflow-y-auto",children:[e.jsxs(Gs,{children:[e.jsx(Vs,{children:"新增表达方式"}),e.jsx(Ws,{children:"创建新的表达方式记录"})]}),e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"grid grid-cols-2 gap-4",children:[e.jsxs("div",{className:"space-y-2",children:[e.jsxs(k,{htmlFor:"situation",children:["情境 ",e.jsx("span",{className:"text-destructive",children:"*"})]}),e.jsx(ie,{id:"situation",value:u.situation,onChange:v=>x({...u,situation:v.target.value}),placeholder:"描述使用场景"})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsxs(k,{htmlFor:"style",children:["风格 ",e.jsx("span",{className:"text-destructive",children:"*"})]}),e.jsx(ie,{id:"style",value:u.style,onChange:v=>x({...u,style:v.target.value}),placeholder:"描述表达风格"})]})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsxs(k,{htmlFor:"chat_id",children:["聊天 ",e.jsx("span",{className:"text-destructive",children:"*"})]}),e.jsxs(Ue,{value:u.chat_id,onValueChange:v=>x({...u,chat_id:v}),children:[e.jsx(Re,{children:e.jsx(Be,{placeholder:"选择关联的聊天"})}),e.jsx(Le,{children:r.map(v=>e.jsx(ee,{value:v.chat_id,children:e.jsxs("span",{className:"truncate",style:{wordBreak:"keep-all"},children:[v.chat_name,v.is_group&&e.jsx("span",{className:"text-muted-foreground ml-1",children:"(群聊)"})]})},v.chat_id))})]})]})]}),e.jsxs(at,{children:[e.jsx(C,{variant:"outline",onClick:()=>i(!1),children:"取消"}),e.jsx(C,{onClick:j,disabled:h,children:h?"创建中...":"创建"})]})]})})}function s_({expression:l,open:i,onOpenChange:r,chatList:o,onSuccess:u}){const[x,h]=m.useState({}),[f,g]=m.useState(!1),{toast:j}=Ks();m.useEffect(()=>{l&&h({situation:l.situation,style:l.style,chat_id:l.chat_id})},[l]);const v=async()=>{if(l)try{g(!0),await K2(l.id,x),j({title:"保存成功",description:"表达方式已更新"}),u()}catch(y){j({title:"保存失败",description:y instanceof Error?y.message:"无法更新表达方式",variant:"destructive"})}finally{g(!1)}};return l?e.jsx(Qs,{open:i,onOpenChange:r,children:e.jsxs(qs,{className:"max-w-2xl max-h-[80vh] overflow-y-auto",children:[e.jsxs(Gs,{children:[e.jsx(Vs,{children:"编辑表达方式"}),e.jsx(Ws,{children:"修改表达方式的信息"})]}),e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"grid grid-cols-2 gap-4",children:[e.jsxs("div",{className:"space-y-2",children:[e.jsx(k,{htmlFor:"edit_situation",children:"情境"}),e.jsx(ie,{id:"edit_situation",value:x.situation||"",onChange:y=>h({...x,situation:y.target.value}),placeholder:"描述使用场景"})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(k,{htmlFor:"edit_style",children:"风格"}),e.jsx(ie,{id:"edit_style",value:x.style||"",onChange:y=>h({...x,style:y.target.value}),placeholder:"描述表达风格"})]})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(k,{htmlFor:"edit_chat_id",children:"聊天"}),e.jsxs(Ue,{value:x.chat_id||"",onValueChange:y=>h({...x,chat_id:y}),children:[e.jsx(Re,{children:e.jsx(Be,{placeholder:"选择关联的聊天"})}),e.jsx(Le,{children:o.map(y=>e.jsx(ee,{value:y.chat_id,children:e.jsxs("span",{className:"truncate",style:{wordBreak:"keep-all"},children:[y.chat_name,y.is_group&&e.jsx("span",{className:"text-muted-foreground ml-1",children:"(群聊)"})]})},y.chat_id))})]})]})]}),e.jsxs(at,{children:[e.jsx(C,{variant:"outline",onClick:()=>r(!1),children:"取消"}),e.jsx(C,{onClick:v,disabled:f,children:f?"保存中...":"保存"})]})]})}):null}function t_({open:l,onOpenChange:i,onConfirm:r,count:o}){return e.jsx(js,{open:l,onOpenChange:i,children:e.jsxs(os,{children:[e.jsxs(ds,{children:[e.jsx(ms,{children:"确认批量删除"}),e.jsxs(xs,{children:["您即将删除 ",o," 个表达方式,此操作无法撤销。确定要继续吗?"]})]}),e.jsxs(us,{children:[e.jsx(fs,{children:"取消"}),e.jsx(hs,{onClick:r,className:"bg-destructive text-destructive-foreground hover:bg-destructive/90",children:"确认删除"})]})]})})}const gl="/api/webui/jargon";async function a_(){const l=await we(`${gl}/chats`,{});if(!l.ok){const i=await l.json();throw new Error(i.detail||"获取聊天列表失败")}return l.json()}async function l_(l){const i=new URLSearchParams;l.page&&i.append("page",l.page.toString()),l.page_size&&i.append("page_size",l.page_size.toString()),l.search&&i.append("search",l.search),l.chat_id&&i.append("chat_id",l.chat_id),l.is_jargon!==void 0&&l.is_jargon!==null&&i.append("is_jargon",l.is_jargon.toString()),l.is_global!==void 0&&i.append("is_global",l.is_global.toString());const r=await we(`${gl}/list?${i}`,{});if(!r.ok){const o=await r.json();throw new Error(o.detail||"获取黑话列表失败")}return r.json()}async function n_(l){const i=await we(`${gl}/${l}`,{});if(!i.ok){const r=await i.json();throw new Error(r.detail||"获取黑话详情失败")}return i.json()}async function i_(l){const i=await we(`${gl}/`,{method:"POST",body:JSON.stringify(l)});if(!i.ok){const r=await i.json();throw new Error(r.detail||"创建黑话失败")}return i.json()}async function r_(l,i){const r=await we(`${gl}/${l}`,{method:"PATCH",body:JSON.stringify(i)});if(!r.ok){const o=await r.json();throw new Error(o.detail||"更新黑话失败")}return r.json()}async function c_(l){const i=await we(`${gl}/${l}`,{method:"DELETE"});if(!i.ok){const r=await i.json();throw new Error(r.detail||"删除黑话失败")}return i.json()}async function o_(l){const i=await we(`${gl}/batch/delete`,{method:"POST",body:JSON.stringify({ids:l})});if(!i.ok){const r=await i.json();throw new Error(r.detail||"批量删除黑话失败")}return i.json()}async function d_(){const l=await we(`${gl}/stats/summary`,{});if(!l.ok){const i=await l.json();throw new Error(i.detail||"获取黑话统计失败")}return l.json()}async function u_(l,i){const r=new URLSearchParams;l.forEach(u=>r.append("ids",u.toString())),r.append("is_jargon",i.toString());const o=await we(`${gl}/batch/set-jargon?${r}`,{method:"POST"});if(!o.ok){const u=await o.json();throw new Error(u.detail||"批量设置黑话状态失败")}return o.json()}function m_(){const[l,i]=m.useState([]),[r,o]=m.useState(!0),[u,x]=m.useState(0),[h,f]=m.useState(1),[g,j]=m.useState(20),[v,y]=m.useState(""),[b,S]=m.useState("all"),[w,O]=m.useState("all"),[A,D]=m.useState(null),[V,z]=m.useState(!1),[_,T]=m.useState(!1),[$,E]=m.useState(!1),[se,te]=m.useState(null),[ne,ue]=m.useState(new Set),[Se,oe]=m.useState(!1),[je,be]=m.useState(""),[U,P]=m.useState({total:0,confirmed_jargon:0,confirmed_not_jargon:0,pending:0,global_count:0,complete_count:0,chat_count:0,top_chats:{}}),[X,L]=m.useState([]),{toast:B}=Ks(),_e=async()=>{try{o(!0);const fe=await l_({page:h,page_size:g,search:v||void 0,chat_id:b==="all"?void 0:b,is_jargon:w==="all"?void 0:w==="true"?!0:w==="false"?!1:void 0});i(fe.data),x(fe.total)}catch(fe){B({title:"加载失败",description:fe instanceof Error?fe.message:"无法加载黑话列表",variant:"destructive"})}finally{o(!1)}},Ne=async()=>{try{const fe=await d_();fe?.data&&P(fe.data)}catch(fe){console.error("加载统计数据失败:",fe)}},Ce=async()=>{try{const fe=await a_();fe?.data&&L(fe.data)}catch(fe){console.error("加载聊天列表失败:",fe)}};m.useEffect(()=>{_e(),Ne(),Ce()},[h,g,v,b,w]);const ve=async fe=>{try{const ls=await n_(fe.id);D(ls.data),z(!0)}catch(ls){B({title:"加载详情失败",description:ls instanceof Error?ls.message:"无法加载黑话详情",variant:"destructive"})}},ze=fe=>{D(fe),T(!0)},Q=async fe=>{try{await c_(fe.id),B({title:"删除成功",description:`已删除黑话: ${fe.content}`}),te(null),_e(),Ne()}catch(ls){B({title:"删除失败",description:ls instanceof Error?ls.message:"无法删除黑话",variant:"destructive"})}},xe=fe=>{const ls=new Set(ne);ls.has(fe)?ls.delete(fe):ls.add(fe),ue(ls)},Te=()=>{ne.size===l.length&&l.length>0?ue(new Set):ue(new Set(l.map(fe=>fe.id)))},J=async()=>{try{await o_(Array.from(ne)),B({title:"批量删除成功",description:`已删除 ${ne.size} 个黑话`}),ue(new Set),oe(!1),_e(),Ne()}catch(fe){B({title:"批量删除失败",description:fe instanceof Error?fe.message:"无法批量删除黑话",variant:"destructive"})}},le=async fe=>{try{await u_(Array.from(ne),fe),B({title:"操作成功",description:`已将 ${ne.size} 个词条设为${fe?"黑话":"非黑话"}`}),ue(new Set),_e(),Ne()}catch(ls){B({title:"操作失败",description:ls instanceof Error?ls.message:"批量设置失败",variant:"destructive"})}},qe=()=>{const fe=parseInt(je),ls=Math.ceil(u/g);fe>=1&&fe<=ls?(f(fe),be("")):B({title:"无效的页码",description:`请输入1-${ls}之间的页码`,variant:"destructive"})},We=fe=>fe===!0?e.jsxs(Ye,{variant:"default",className:"bg-green-600 hover:bg-green-700",children:[e.jsx(ea,{className:"h-3 w-3 mr-1"}),"是黑话"]}):fe===!1?e.jsxs(Ye,{variant:"secondary",children:[e.jsx(fl,{className:"h-3 w-3 mr-1"}),"非黑话"]}):e.jsxs(Ye,{variant:"outline",children:[e.jsx(Rg,{className:"h-3 w-3 mr-1"}),"未判定"]});return e.jsxs("div",{className:"h-[calc(100vh-4rem)] flex flex-col p-4 sm:p-6",children:[e.jsx("div",{className:"mb-4 sm:mb-6",children:e.jsxs("div",{className:"flex flex-col sm:flex-row sm:items-center justify-between gap-4",children:[e.jsxs("div",{children:[e.jsxs("h1",{className:"text-2xl sm:text-3xl font-bold flex items-center gap-2",children:[e.jsx(Qy,{className:"h-8 w-8",strokeWidth:2}),"黑话管理"]}),e.jsx("p",{className:"text-muted-foreground mt-1 text-sm sm:text-base",children:"管理麦麦学习到的黑话和俚语"})]}),e.jsxs(C,{onClick:()=>E(!0),className:"gap-2",children:[e.jsx(ut,{className:"h-4 w-4"}),"新增黑话"]})]})}),e.jsx(Ze,{className:"flex-1",children:e.jsxs("div",{className:"space-y-4 sm:space-y-6 pr-4",children:[e.jsxs("div",{className:"grid grid-cols-2 sm:grid-cols-4 lg:grid-cols-7 gap-3",children:[e.jsxs("div",{className:"rounded-lg border bg-card p-3 sm:p-4",children:[e.jsx("div",{className:"text-xs sm:text-sm text-muted-foreground",children:"总数量"}),e.jsx("div",{className:"text-xl sm:text-2xl font-bold mt-1",children:U.total})]}),e.jsxs("div",{className:"rounded-lg border bg-card p-3 sm:p-4",children:[e.jsx("div",{className:"text-xs sm:text-sm text-muted-foreground",children:"已确认黑话"}),e.jsx("div",{className:"text-xl sm:text-2xl font-bold mt-1 text-green-600",children:U.confirmed_jargon})]}),e.jsxs("div",{className:"rounded-lg border bg-card p-3 sm:p-4",children:[e.jsx("div",{className:"text-xs sm:text-sm text-muted-foreground",children:"确认非黑话"}),e.jsx("div",{className:"text-xl sm:text-2xl font-bold mt-1 text-gray-500",children:U.confirmed_not_jargon})]}),e.jsxs("div",{className:"rounded-lg border bg-card p-3 sm:p-4",children:[e.jsx("div",{className:"text-xs sm:text-sm text-muted-foreground",children:"待判定"}),e.jsx("div",{className:"text-xl sm:text-2xl font-bold mt-1 text-yellow-600",children:U.pending})]}),e.jsxs("div",{className:"rounded-lg border bg-card p-3 sm:p-4",children:[e.jsx("div",{className:"text-xs sm:text-sm text-muted-foreground",children:"全局黑话"}),e.jsx("div",{className:"text-xl sm:text-2xl font-bold mt-1 text-blue-600",children:U.global_count})]}),e.jsxs("div",{className:"rounded-lg border bg-card p-3 sm:p-4",children:[e.jsx("div",{className:"text-xs sm:text-sm text-muted-foreground",children:"推断完成"}),e.jsx("div",{className:"text-xl sm:text-2xl font-bold mt-1 text-purple-600",children:U.complete_count})]}),e.jsxs("div",{className:"rounded-lg border bg-card p-3 sm:p-4",children:[e.jsx("div",{className:"text-xs sm:text-sm text-muted-foreground",children:"关联聊天数"}),e.jsx("div",{className:"text-xl sm:text-2xl font-bold mt-1",children:U.chat_count})]})]}),e.jsxs("div",{className:"rounded-lg border bg-card p-4",children:[e.jsxs("div",{className:"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4",children:[e.jsxs("div",{className:"space-y-1.5",children:[e.jsx(k,{htmlFor:"search",children:"搜索"}),e.jsxs("div",{className:"relative",children:[e.jsx($t,{className:"absolute left-2.5 top-2.5 h-4 w-4 text-muted-foreground"}),e.jsx(ie,{id:"search",placeholder:"搜索内容、含义...",value:v,onChange:fe=>y(fe.target.value),className:"pl-9"})]})]}),e.jsxs("div",{className:"space-y-1.5",children:[e.jsx(k,{children:"聊天筛选"}),e.jsxs(Ue,{value:b,onValueChange:S,children:[e.jsx(Re,{children:e.jsx(Be,{placeholder:"全部聊天"})}),e.jsxs(Le,{children:[e.jsx(ee,{value:"all",children:"全部聊天"}),X.map(fe=>e.jsx(ee,{value:fe.chat_id,children:fe.chat_name},fe.chat_id))]})]})]}),e.jsxs("div",{className:"space-y-1.5",children:[e.jsx(k,{children:"状态筛选"}),e.jsxs(Ue,{value:w,onValueChange:O,children:[e.jsx(Re,{children:e.jsx(Be,{placeholder:"全部状态"})}),e.jsxs(Le,{children:[e.jsx(ee,{value:"all",children:"全部状态"}),e.jsx(ee,{value:"true",children:"是黑话"}),e.jsx(ee,{value:"false",children:"非黑话"})]})]})]}),e.jsxs("div",{className:"space-y-1.5",children:[e.jsx(k,{htmlFor:"page-size",children:"每页显示"}),e.jsxs(Ue,{value:g.toString(),onValueChange:fe=>{j(parseInt(fe)),f(1),ue(new Set)},children:[e.jsx(Re,{id:"page-size",children:e.jsx(Be,{})}),e.jsxs(Le,{children:[e.jsx(ee,{value:"10",children:"10"}),e.jsx(ee,{value:"20",children:"20"}),e.jsx(ee,{value:"50",children:"50"}),e.jsx(ee,{value:"100",children:"100"})]})]})]})]}),ne.size>0&&e.jsxs("div",{className:"flex flex-wrap items-center gap-2 mt-4 pt-4 border-t",children:[e.jsxs("span",{className:"text-sm text-muted-foreground",children:["已选择 ",ne.size," 个"]}),e.jsxs(C,{variant:"outline",size:"sm",onClick:()=>le(!0),children:[e.jsx(ea,{className:"h-4 w-4 mr-1"}),"标记为黑话"]}),e.jsxs(C,{variant:"outline",size:"sm",onClick:()=>le(!1),children:[e.jsx(fl,{className:"h-4 w-4 mr-1"}),"标记为非黑话"]}),e.jsx(C,{variant:"outline",size:"sm",onClick:()=>ue(new Set),children:"取消选择"}),e.jsxs(C,{variant:"destructive",size:"sm",onClick:()=>oe(!0),children:[e.jsx(es,{className:"h-4 w-4 mr-1"}),"批量删除"]})]})]}),e.jsxs("div",{className:"rounded-lg border bg-card",children:[e.jsx("div",{className:"hidden md:block",children:e.jsxs(bn,{children:[e.jsx(Nn,{children:e.jsxs(gt,{children:[e.jsx(Je,{className:"w-12",children:e.jsx(jt,{checked:ne.size===l.length&&l.length>0,onCheckedChange:Te})}),e.jsx(Je,{children:"内容"}),e.jsx(Je,{children:"含义"}),e.jsx(Je,{children:"聊天"}),e.jsx(Je,{children:"状态"}),e.jsx(Je,{className:"text-center",children:"次数"}),e.jsx(Je,{className:"text-right",children:"操作"})]})}),e.jsx(yn,{children:r?e.jsx(gt,{children:e.jsx(Qe,{colSpan:7,className:"text-center py-8 text-muted-foreground",children:"加载中..."})}):l.length===0?e.jsx(gt,{children:e.jsx(Qe,{colSpan:7,className:"text-center py-8 text-muted-foreground",children:"暂无数据"})}):l.map(fe=>e.jsxs(gt,{children:[e.jsx(Qe,{children:e.jsx(jt,{checked:ne.has(fe.id),onCheckedChange:()=>xe(fe.id)})}),e.jsx(Qe,{className:"font-medium max-w-[200px]",children:e.jsxs("div",{className:"flex items-center gap-2",children:[fe.is_global&&e.jsx("span",{title:"全局黑话",children:e.jsx(Wu,{className:"h-4 w-4 text-blue-500 flex-shrink-0"})}),e.jsx("span",{className:"truncate",title:fe.content,children:fe.content})]})}),e.jsx(Qe,{className:"max-w-[200px] truncate",title:fe.meaning||"",children:fe.meaning||e.jsx("span",{className:"text-muted-foreground",children:"-"})}),e.jsx(Qe,{className:"max-w-[150px] truncate",title:fe.chat_name||fe.chat_id,children:fe.chat_name||fe.chat_id}),e.jsx(Qe,{children:We(fe.is_jargon)}),e.jsx(Qe,{className:"text-center",children:fe.count}),e.jsx(Qe,{className:"text-right",children:e.jsxs("div",{className:"flex justify-end gap-2",children:[e.jsxs(C,{variant:"default",size:"sm",onClick:()=>ze(fe),children:[e.jsx(pn,{className:"h-4 w-4 mr-1"}),"编辑"]}),e.jsx(C,{variant:"outline",size:"icon",className:"h-8 w-8",onClick:()=>ve(fe),title:"查看详情",children:e.jsx(Gt,{className:"h-4 w-4"})}),e.jsxs(C,{size:"sm",onClick:()=>te(fe),className:"bg-red-600 hover:bg-red-700 text-white",children:[e.jsx(es,{className:"h-4 w-4 mr-1"}),"删除"]})]})})]},fe.id))})]})}),e.jsx("div",{className:"md:hidden space-y-3 p-4",children:r?e.jsx("div",{className:"text-center py-8 text-muted-foreground",children:"加载中..."}):l.length===0?e.jsx("div",{className:"text-center py-8 text-muted-foreground",children:"暂无数据"}):l.map(fe=>e.jsxs("div",{className:"rounded-lg border bg-card p-4 space-y-3",children:[e.jsxs("div",{className:"flex items-start gap-3",children:[e.jsx(jt,{checked:ne.has(fe.id),onCheckedChange:()=>xe(fe.id),className:"mt-1"}),e.jsxs("div",{className:"min-w-0 flex-1 space-y-2",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[fe.is_global&&e.jsx(Wu,{className:"h-4 w-4 text-blue-500 flex-shrink-0"}),e.jsx("h3",{className:"font-semibold text-sm break-all",children:fe.content})]}),fe.meaning&&e.jsx("p",{className:"text-sm text-muted-foreground break-all",children:fe.meaning}),e.jsxs("div",{className:"flex flex-wrap items-center gap-2 text-xs",children:[We(fe.is_jargon),e.jsxs("span",{className:"text-muted-foreground",children:["次数: ",fe.count]})]}),e.jsxs("div",{className:"text-xs text-muted-foreground truncate",children:["聊天: ",fe.chat_name||fe.chat_id]})]})]}),e.jsxs("div",{className:"flex flex-wrap gap-1 pt-2 border-t",children:[e.jsxs(C,{variant:"outline",size:"sm",onClick:()=>ze(fe),className:"text-xs px-2 py-1 h-auto",children:[e.jsx(pn,{className:"h-3 w-3 mr-1"}),"编辑"]}),e.jsx(C,{variant:"outline",size:"sm",onClick:()=>ve(fe),className:"text-xs px-2 py-1 h-auto",children:e.jsx(Gt,{className:"h-3 w-3"})}),e.jsxs(C,{variant:"outline",size:"sm",onClick:()=>te(fe),className:"text-xs px-2 py-1 h-auto text-destructive hover:text-destructive",children:[e.jsx(es,{className:"h-3 w-3 mr-1"}),"删除"]})]})]},fe.id))}),u>0&&e.jsxs("div",{className:"flex flex-col sm:flex-row items-center justify-between gap-4 px-4 py-3 border-t",children:[e.jsxs("div",{className:"text-sm text-muted-foreground",children:["共 ",u," 条记录,第 ",h," / ",Math.ceil(u/g)," 页"]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(C,{variant:"outline",size:"sm",onClick:()=>f(1),disabled:h===1,className:"hidden sm:flex",children:e.jsx(vi,{className:"h-4 w-4"})}),e.jsxs(C,{variant:"outline",size:"sm",onClick:()=>f(h-1),disabled:h===1,children:[e.jsx(pl,{className:"h-4 w-4 sm:mr-1"}),e.jsx("span",{className:"hidden sm:inline",children:"上一页"})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(ie,{type:"number",value:je,onChange:fe=>be(fe.target.value),onKeyDown:fe=>fe.key==="Enter"&&qe(),placeholder:h.toString(),className:"w-16 h-8 text-center",min:1,max:Math.ceil(u/g)}),e.jsx(C,{variant:"outline",size:"sm",onClick:qe,disabled:!je,className:"h-8",children:"跳转"})]}),e.jsxs(C,{variant:"outline",size:"sm",onClick:()=>f(h+1),disabled:h>=Math.ceil(u/g),children:[e.jsx("span",{className:"hidden sm:inline",children:"下一页"}),e.jsx(Ya,{className:"h-4 w-4 sm:ml-1"})]}),e.jsx(C,{variant:"outline",size:"sm",onClick:()=>f(Math.ceil(u/g)),disabled:h>=Math.ceil(u/g),className:"hidden sm:flex",children:e.jsx(bi,{className:"h-4 w-4"})})]})]})]})]})}),e.jsx(x_,{jargon:A,open:V,onOpenChange:z}),e.jsx(h_,{open:$,onOpenChange:E,chatList:X,onSuccess:()=>{_e(),Ne(),E(!1)}}),e.jsx(f_,{jargon:A,open:_,onOpenChange:T,chatList:X,onSuccess:()=>{_e(),Ne(),T(!1)}}),e.jsx(js,{open:!!se,onOpenChange:()=>te(null),children:e.jsxs(os,{children:[e.jsxs(ds,{children:[e.jsx(ms,{children:"确认删除"}),e.jsxs(xs,{children:['确定要删除黑话 "',se?.content,'" 吗?此操作不可撤销。']})]}),e.jsxs(us,{children:[e.jsx(fs,{children:"取消"}),e.jsx(hs,{onClick:()=>se&&Q(se),className:"bg-destructive text-destructive-foreground hover:bg-destructive/90",children:"删除"})]})]})}),e.jsx(js,{open:Se,onOpenChange:oe,children:e.jsxs(os,{children:[e.jsxs(ds,{children:[e.jsx(ms,{children:"确认批量删除"}),e.jsxs(xs,{children:["您即将删除 ",ne.size," 个黑话,此操作无法撤销。确定要继续吗?"]})]}),e.jsxs(us,{children:[e.jsx(fs,{children:"取消"}),e.jsx(hs,{onClick:J,className:"bg-destructive text-destructive-foreground hover:bg-destructive/90",children:"确认删除"})]})]})})]})}function x_({jargon:l,open:i,onOpenChange:r}){return l?e.jsx(Qs,{open:i,onOpenChange:r,children:e.jsxs(qs,{className:"max-w-2xl max-h-[80vh] grid grid-rows-[auto_1fr_auto] overflow-hidden",children:[e.jsxs(Gs,{children:[e.jsx(Vs,{children:"黑话详情"}),e.jsx(Ws,{children:"查看黑话的完整信息"})]}),e.jsx(Ze,{className:"h-full pr-4",children:e.jsxs("div",{className:"space-y-4 pb-2",children:[e.jsxs("div",{className:"grid grid-cols-2 gap-4",children:[e.jsx(Ju,{icon:pi,label:"记录ID",value:l.id.toString(),mono:!0}),e.jsx(Ju,{label:"使用次数",value:l.count.toString()})]}),e.jsxs("div",{className:"space-y-1",children:[e.jsx(k,{className:"text-xs text-muted-foreground",children:"内容"}),e.jsx("div",{className:"text-sm p-2 bg-muted rounded break-all whitespace-pre-wrap",children:l.content})]}),l.raw_content&&e.jsxs("div",{className:"space-y-1",children:[e.jsx(k,{className:"text-xs text-muted-foreground",children:"原始内容"}),e.jsx("div",{className:"text-sm p-2 bg-muted rounded break-all",children:(()=>{try{const o=JSON.parse(l.raw_content);return Array.isArray(o)?o.map((u,x)=>e.jsxs("div",{children:[x>0&&e.jsx("hr",{className:"my-3 border-border"}),e.jsx("div",{className:"whitespace-pre-wrap",children:u})]},x)):e.jsx("div",{className:"whitespace-pre-wrap",children:l.raw_content})}catch{return e.jsx("div",{className:"whitespace-pre-wrap",children:l.raw_content})}})()})]}),e.jsxs("div",{className:"space-y-1",children:[e.jsx(k,{className:"text-xs text-muted-foreground",children:"含义"}),e.jsx("div",{className:"text-sm p-2 bg-muted rounded break-all",children:l.meaning?e.jsx(Tj,{content:l.meaning}):"-"})]}),e.jsxs("div",{className:"grid grid-cols-2 gap-4",children:[e.jsx(Ju,{label:"聊天",value:l.chat_name||l.chat_id}),e.jsxs("div",{className:"space-y-1",children:[e.jsx(k,{className:"text-xs text-muted-foreground",children:"状态"}),e.jsxs("div",{className:"flex items-center gap-2",children:[l.is_jargon===!0&&e.jsx(Ye,{variant:"default",className:"bg-green-600",children:"是黑话"}),l.is_jargon===!1&&e.jsx(Ye,{variant:"secondary",children:"非黑话"}),l.is_jargon===null&&e.jsx(Ye,{variant:"outline",children:"未判定"}),l.is_global&&e.jsx(Ye,{variant:"outline",className:"border-blue-500 text-blue-500",children:"全局"}),l.is_complete&&e.jsx(Ye,{variant:"outline",className:"border-purple-500 text-purple-500",children:"推断完成"})]})]})]}),l.inference_with_context&&e.jsxs("div",{className:"space-y-1",children:[e.jsx(k,{className:"text-xs text-muted-foreground",children:"上下文推断结果"}),e.jsx("div",{className:"p-2 bg-muted rounded break-all whitespace-pre-wrap font-mono text-xs max-h-[200px] overflow-y-auto",children:l.inference_with_context})]}),l.inference_content_only&&e.jsxs("div",{className:"space-y-1",children:[e.jsx(k,{className:"text-xs text-muted-foreground",children:"纯词条推断结果"}),e.jsx("div",{className:"p-2 bg-muted rounded break-all whitespace-pre-wrap font-mono text-xs max-h-[200px] overflow-y-auto",children:l.inference_content_only})]})]})}),e.jsx(at,{className:"flex-shrink-0",children:e.jsx(C,{onClick:()=>r(!1),children:"关闭"})})]})}):null}function Ju({icon:l,label:i,value:r,mono:o=!1}){return e.jsxs("div",{className:"space-y-1",children:[e.jsxs(k,{className:"text-xs text-muted-foreground flex items-center gap-1",children:[l&&e.jsx(l,{className:"h-3 w-3"}),i]}),e.jsx("div",{className:H("text-sm",o&&"font-mono",!r&&"text-muted-foreground"),children:r||"-"})]})}function h_({open:l,onOpenChange:i,chatList:r,onSuccess:o}){const[u,x]=m.useState({content:"",meaning:"",chat_id:"",is_global:!1}),[h,f]=m.useState(!1),{toast:g}=Ks(),j=async()=>{if(!u.content||!u.chat_id){g({title:"验证失败",description:"请填写必填字段:内容和聊天",variant:"destructive"});return}try{f(!0),await i_(u),g({title:"创建成功",description:"黑话已创建"}),x({content:"",meaning:"",chat_id:"",is_global:!1}),o()}catch(v){g({title:"创建失败",description:v instanceof Error?v.message:"无法创建黑话",variant:"destructive"})}finally{f(!1)}};return e.jsx(Qs,{open:l,onOpenChange:i,children:e.jsxs(qs,{className:"max-w-2xl max-h-[80vh] overflow-y-auto",children:[e.jsxs(Gs,{children:[e.jsx(Vs,{children:"新增黑话"}),e.jsx(Ws,{children:"创建新的黑话记录"})]}),e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"space-y-2",children:[e.jsxs(k,{htmlFor:"content",children:["内容 ",e.jsx("span",{className:"text-destructive",children:"*"})]}),e.jsx(ie,{id:"content",value:u.content,onChange:v=>x({...u,content:v.target.value}),placeholder:"输入黑话内容"})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(k,{htmlFor:"meaning",children:"含义"}),e.jsx(Ys,{id:"meaning",value:u.meaning||"",onChange:v=>x({...u,meaning:v.target.value}),placeholder:"输入黑话含义(可选)",rows:3})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsxs(k,{htmlFor:"chat_id",children:["聊天 ",e.jsx("span",{className:"text-destructive",children:"*"})]}),e.jsxs(Ue,{value:u.chat_id,onValueChange:v=>x({...u,chat_id:v}),children:[e.jsx(Re,{children:e.jsx(Be,{placeholder:"选择关联的聊天"})}),e.jsx(Le,{children:r.map(v=>e.jsx(ee,{value:v.chat_id,children:v.chat_name},v.chat_id))})]})]}),e.jsxs("div",{className:"flex items-center space-x-2",children:[e.jsx(Fe,{id:"is_global",checked:u.is_global,onCheckedChange:v=>x({...u,is_global:v})}),e.jsx(k,{htmlFor:"is_global",children:"设为全局黑话"})]})]}),e.jsxs(at,{children:[e.jsx(C,{variant:"outline",onClick:()=>i(!1),children:"取消"}),e.jsx(C,{onClick:j,disabled:h,children:h?"创建中...":"创建"})]})]})})}function f_({jargon:l,open:i,onOpenChange:r,chatList:o,onSuccess:u}){const[x,h]=m.useState({}),[f,g]=m.useState(!1),{toast:j}=Ks();m.useEffect(()=>{l&&h({content:l.content,meaning:l.meaning||"",chat_id:l.stream_id||l.chat_id,is_global:l.is_global,is_jargon:l.is_jargon})},[l]);const v=async()=>{if(l)try{g(!0),await r_(l.id,x),j({title:"保存成功",description:"黑话已更新"}),u()}catch(y){j({title:"保存失败",description:y instanceof Error?y.message:"无法更新黑话",variant:"destructive"})}finally{g(!1)}};return l?e.jsx(Qs,{open:i,onOpenChange:r,children:e.jsxs(qs,{className:"max-w-2xl max-h-[80vh] overflow-y-auto",children:[e.jsxs(Gs,{children:[e.jsx(Vs,{children:"编辑黑话"}),e.jsx(Ws,{children:"修改黑话的信息"})]}),e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"space-y-2",children:[e.jsx(k,{htmlFor:"edit_content",children:"内容"}),e.jsx(ie,{id:"edit_content",value:x.content||"",onChange:y=>h({...x,content:y.target.value}),placeholder:"输入黑话内容"})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(k,{htmlFor:"edit_meaning",children:"含义"}),e.jsx(Ys,{id:"edit_meaning",value:x.meaning||"",onChange:y=>h({...x,meaning:y.target.value}),placeholder:"输入黑话含义",rows:3})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(k,{htmlFor:"edit_chat_id",children:"聊天"}),e.jsxs(Ue,{value:x.chat_id||"",onValueChange:y=>h({...x,chat_id:y}),children:[e.jsx(Re,{children:e.jsx(Be,{placeholder:"选择关联的聊天"})}),e.jsx(Le,{children:o.map(y=>e.jsx(ee,{value:y.chat_id,children:y.chat_name},y.chat_id))})]})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(k,{children:"黑话状态"}),e.jsxs(Ue,{value:x.is_jargon===null?"null":x.is_jargon?.toString()||"null",onValueChange:y=>h({...x,is_jargon:y==="null"?null:y==="true"}),children:[e.jsx(Re,{children:e.jsx(Be,{})}),e.jsxs(Le,{children:[e.jsx(ee,{value:"null",children:"未判定"}),e.jsx(ee,{value:"true",children:"是黑话"}),e.jsx(ee,{value:"false",children:"非黑话"})]})]})]}),e.jsxs("div",{className:"flex items-center space-x-2",children:[e.jsx(Fe,{id:"edit_is_global",checked:x.is_global,onCheckedChange:y=>h({...x,is_global:y})}),e.jsx(k,{htmlFor:"edit_is_global",children:"全局黑话"})]})]}),e.jsxs(at,{children:[e.jsx(C,{variant:"outline",onClick:()=>r(!1),children:"取消"}),e.jsx(C,{onClick:v,disabled:f,children:f?"保存中...":"保存"})]})]})}):null}const Ni="/api/webui/person";async function p_(l){const i=new URLSearchParams;l.page&&i.append("page",l.page.toString()),l.page_size&&i.append("page_size",l.page_size.toString()),l.search&&i.append("search",l.search),l.is_known!==void 0&&i.append("is_known",l.is_known.toString()),l.platform&&i.append("platform",l.platform);const r=await we(`${Ni}/list?${i}`,{headers:Is()});if(!r.ok){const o=await r.json();throw new Error(o.detail||"获取人物列表失败")}return r.json()}async function g_(l){const i=await we(`${Ni}/${l}`,{headers:Is()});if(!i.ok){const r=await i.json();throw new Error(r.detail||"获取人物详情失败")}return i.json()}async function j_(l,i){const r=await we(`${Ni}/${l}`,{method:"PATCH",headers:Is(),body:JSON.stringify(i)});if(!r.ok){const o=await r.json();throw new Error(o.detail||"更新人物信息失败")}return r.json()}async function v_(l){const i=await we(`${Ni}/${l}`,{method:"DELETE",headers:Is()});if(!i.ok){const r=await i.json();throw new Error(r.detail||"删除人物信息失败")}return i.json()}async function b_(){const l=await we(`${Ni}/stats/summary`,{headers:Is()});if(!l.ok){const i=await l.json();throw new Error(i.detail||"获取统计数据失败")}return l.json()}async function N_(l){const i=await we(`${Ni}/batch/delete`,{method:"POST",headers:Is(),body:JSON.stringify({person_ids:l})});if(!i.ok){const r=await i.json();throw new Error(r.detail||"批量删除失败")}return i.json()}function y_(){const[l,i]=m.useState([]),[r,o]=m.useState(!0),[u,x]=m.useState(0),[h,f]=m.useState(1),[g,j]=m.useState(20),[v,y]=m.useState(""),[b,S]=m.useState(void 0),[w,O]=m.useState(void 0),[A,D]=m.useState(null),[V,z]=m.useState(!1),[_,T]=m.useState(!1),[$,E]=m.useState(null),[se,te]=m.useState({total:0,known:0,unknown:0,platforms:{}}),[ne,ue]=m.useState(new Set),[Se,oe]=m.useState(!1),[je,be]=m.useState(""),{toast:U}=Ks(),P=async()=>{try{o(!0);const J=await p_({page:h,page_size:g,search:v||void 0,is_known:b,platform:w});i(J.data),x(J.total)}catch(J){U({title:"加载失败",description:J instanceof Error?J.message:"无法加载人物信息",variant:"destructive"})}finally{o(!1)}},X=async()=>{try{const J=await b_();J?.data&&te(J.data)}catch(J){console.error("加载统计数据失败:",J)}};m.useEffect(()=>{P(),X()},[h,g,v,b,w]);const L=async J=>{try{const le=await g_(J.person_id);D(le.data),z(!0)}catch(le){U({title:"加载详情失败",description:le instanceof Error?le.message:"无法加载人物详情",variant:"destructive"})}},B=J=>{D(J),T(!0)},_e=async J=>{try{await v_(J.person_id),U({title:"删除成功",description:`已删除人物信息: ${J.person_name||J.nickname||J.user_id}`}),E(null),P(),X()}catch(le){U({title:"删除失败",description:le instanceof Error?le.message:"无法删除人物信息",variant:"destructive"})}},Ne=m.useMemo(()=>Object.keys(se.platforms),[se.platforms]),Ce=J=>{const le=new Set(ne);le.has(J)?le.delete(J):le.add(J),ue(le)},ve=()=>{ne.size===l.length&&l.length>0?ue(new Set):ue(new Set(l.map(J=>J.person_id)))},ze=()=>{if(ne.size===0){U({title:"未选择任何人物",description:"请先选择要删除的人物",variant:"destructive"});return}oe(!0)},Q=async()=>{try{const J=await N_(Array.from(ne));U({title:"批量删除完成",description:J.message}),ue(new Set),oe(!1),P(),X()}catch(J){U({title:"批量删除失败",description:J instanceof Error?J.message:"批量删除失败",variant:"destructive"})}},xe=()=>{const J=parseInt(je),le=Math.ceil(u/g);J>=1&&J<=le?(f(J),be("")):U({title:"无效的页码",description:`请输入1-${le}之间的页码`,variant:"destructive"})},Te=J=>J?new Date(J*1e3).toLocaleString("zh-CN"):"-";return e.jsxs("div",{className:"h-[calc(100vh-4rem)] flex flex-col p-4 sm:p-6",children:[e.jsx("div",{className:"mb-4 sm:mb-6",children:e.jsx("div",{className:"flex flex-col sm:flex-row sm:items-center justify-between gap-4",children:e.jsxs("div",{children:[e.jsxs("h1",{className:"text-2xl sm:text-3xl font-bold flex items-center gap-2",children:[e.jsx(em,{className:"h-8 w-8",strokeWidth:2}),"人物信息管理"]}),e.jsx("p",{className:"text-muted-foreground mt-1 text-sm sm:text-base",children:"管理麦麦认识的所有人物信息"})]})})}),e.jsx(Ze,{className:"flex-1",children:e.jsxs("div",{className:"space-y-4 sm:space-y-6 pr-4",children:[e.jsxs("div",{className:"grid grid-cols-1 sm:grid-cols-3 gap-4",children:[e.jsxs("div",{className:"rounded-lg border bg-card p-4",children:[e.jsx("div",{className:"text-sm text-muted-foreground",children:"总人数"}),e.jsx("div",{className:"text-2xl font-bold mt-1",children:se.total})]}),e.jsxs("div",{className:"rounded-lg border bg-card p-4",children:[e.jsx("div",{className:"text-sm text-muted-foreground",children:"已认识"}),e.jsx("div",{className:"text-2xl font-bold mt-1 text-green-600",children:se.known})]}),e.jsxs("div",{className:"rounded-lg border bg-card p-4",children:[e.jsx("div",{className:"text-sm text-muted-foreground",children:"未认识"}),e.jsx("div",{className:"text-2xl font-bold mt-1 text-muted-foreground",children:se.unknown})]})]}),e.jsxs("div",{className:"rounded-lg border bg-card p-4",children:[e.jsxs("div",{className:"grid grid-cols-1 sm:grid-cols-4 gap-4",children:[e.jsxs("div",{className:"sm:col-span-2",children:[e.jsx(k,{htmlFor:"search",children:"搜索"}),e.jsxs("div",{className:"relative mt-1.5",children:[e.jsx($t,{className:"absolute left-2.5 top-2.5 h-4 w-4 text-muted-foreground"}),e.jsx(ie,{id:"search",placeholder:"搜索名称、昵称或用户ID...",value:v,onChange:J=>y(J.target.value),className:"pl-9"})]})]}),e.jsxs("div",{children:[e.jsx(k,{htmlFor:"filter-known",children:"认识状态"}),e.jsxs(Ue,{value:b===void 0?"all":b.toString(),onValueChange:J=>{S(J==="all"?void 0:J==="true"),f(1)},children:[e.jsx(Re,{id:"filter-known",className:"mt-1.5",children:e.jsx(Be,{})}),e.jsxs(Le,{children:[e.jsx(ee,{value:"all",children:"全部"}),e.jsx(ee,{value:"true",children:"已认识"}),e.jsx(ee,{value:"false",children:"未认识"})]})]})]}),e.jsxs("div",{children:[e.jsx(k,{htmlFor:"filter-platform",children:"平台"}),e.jsxs(Ue,{value:w||"all",onValueChange:J=>{O(J==="all"?void 0:J),f(1)},children:[e.jsx(Re,{id:"filter-platform",className:"mt-1.5",children:e.jsx(Be,{})}),e.jsxs(Le,{children:[e.jsx(ee,{value:"all",children:"全部平台"}),Ne.map(J=>e.jsxs(ee,{value:J,children:[J," (",se.platforms[J],")"]},J))]})]})]})]}),e.jsxs("div",{className:"flex flex-col sm:flex-row items-start sm:items-center justify-between gap-3 mt-4 pt-4 border-t",children:[e.jsx("div",{className:"flex items-center gap-2 text-sm text-muted-foreground",children:ne.size>0&&e.jsxs("span",{children:["已选择 ",ne.size," 个人物"]})}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(k,{htmlFor:"page-size",className:"text-sm whitespace-nowrap",children:"每页显示"}),e.jsxs(Ue,{value:g.toString(),onValueChange:J=>{j(parseInt(J)),f(1),ue(new Set)},children:[e.jsx(Re,{id:"page-size",className:"w-20",children:e.jsx(Be,{})}),e.jsxs(Le,{children:[e.jsx(ee,{value:"10",children:"10"}),e.jsx(ee,{value:"20",children:"20"}),e.jsx(ee,{value:"50",children:"50"}),e.jsx(ee,{value:"100",children:"100"})]})]}),ne.size>0&&e.jsxs(e.Fragment,{children:[e.jsx(C,{variant:"outline",size:"sm",onClick:()=>ue(new Set),children:"取消选择"}),e.jsxs(C,{variant:"destructive",size:"sm",onClick:ze,children:[e.jsx(es,{className:"h-4 w-4 mr-1"}),"批量删除"]})]})]})]})]}),e.jsxs("div",{className:"rounded-lg border bg-card",children:[e.jsx("div",{className:"hidden md:block",children:e.jsxs(bn,{children:[e.jsx(Nn,{children:e.jsxs(gt,{children:[e.jsx(Je,{className:"w-12",children:e.jsx(jt,{checked:l.length>0&&ne.size===l.length,onCheckedChange:ve,"aria-label":"全选"})}),e.jsx(Je,{children:"状态"}),e.jsx(Je,{children:"名称"}),e.jsx(Je,{children:"昵称"}),e.jsx(Je,{children:"平台"}),e.jsx(Je,{children:"用户ID"}),e.jsx(Je,{children:"最后更新"}),e.jsx(Je,{className:"text-right",children:"操作"})]})}),e.jsx(yn,{children:r?e.jsx(gt,{children:e.jsx(Qe,{colSpan:8,className:"text-center py-8 text-muted-foreground",children:"加载中..."})}):l.length===0?e.jsx(gt,{children:e.jsx(Qe,{colSpan:8,className:"text-center py-8 text-muted-foreground",children:"暂无数据"})}):l.map(J=>e.jsxs(gt,{children:[e.jsx(Qe,{children:e.jsx(jt,{checked:ne.has(J.person_id),onCheckedChange:()=>Ce(J.person_id),"aria-label":`选择 ${J.person_name||J.nickname||J.user_id}`})}),e.jsx(Qe,{children:e.jsx("div",{className:H("inline-flex items-center gap-1 px-2 py-1 rounded-full text-xs font-medium",J.is_known?"bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-400":"bg-gray-100 text-gray-700 dark:bg-gray-800 dark:text-gray-400"),children:J.is_known?"已认识":"未认识"})}),e.jsx(Qe,{className:"font-medium",children:J.person_name||e.jsx("span",{className:"text-muted-foreground",children:"-"})}),e.jsx(Qe,{children:J.nickname||"-"}),e.jsx(Qe,{children:J.platform}),e.jsx(Qe,{className:"font-mono text-sm",children:J.user_id}),e.jsx(Qe,{className:"text-sm text-muted-foreground",children:Te(J.last_know)}),e.jsx(Qe,{className:"text-right",children:e.jsxs("div",{className:"flex justify-end gap-2",children:[e.jsxs(C,{variant:"default",size:"sm",onClick:()=>L(J),children:[e.jsx(Gt,{className:"h-4 w-4 mr-1"}),"详情"]}),e.jsxs(C,{variant:"default",size:"sm",onClick:()=>B(J),children:[e.jsx(pn,{className:"h-4 w-4 mr-1"}),"编辑"]}),e.jsxs(C,{size:"sm",onClick:()=>E(J),className:"bg-red-600 hover:bg-red-700 text-white",children:[e.jsx(es,{className:"h-4 w-4 mr-1"}),"删除"]})]})})]},J.id))})]})}),e.jsx("div",{className:"md:hidden space-y-3 p-4",children:r?e.jsx("div",{className:"text-center py-8 text-muted-foreground",children:"加载中..."}):l.length===0?e.jsx("div",{className:"text-center py-8 text-muted-foreground",children:"暂无数据"}):l.map(J=>e.jsxs("div",{className:"rounded-lg border bg-card p-4 space-y-3 overflow-hidden",children:[e.jsxs("div",{className:"flex items-start gap-3",children:[e.jsx(jt,{checked:ne.has(J.person_id),onCheckedChange:()=>Ce(J.person_id),className:"mt-1"}),e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsx("div",{className:H("inline-flex items-center gap-1 px-2 py-1 rounded-full text-xs font-medium mb-2",J.is_known?"bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-400":"bg-gray-100 text-gray-700 dark:bg-gray-800 dark:text-gray-400"),children:J.is_known?"已认识":"未认识"}),e.jsx("h3",{className:"font-semibold text-sm line-clamp-1 w-full break-all",children:J.person_name||e.jsx("span",{className:"text-muted-foreground",children:"未命名"})}),J.nickname&&e.jsxs("p",{className:"text-xs text-muted-foreground mt-1 line-clamp-1 w-full break-all",children:["昵称: ",J.nickname]})]})]}),e.jsxs("div",{className:"grid grid-cols-2 gap-2 text-sm",children:[e.jsxs("div",{children:[e.jsx("div",{className:"text-xs text-muted-foreground mb-1",children:"平台"}),e.jsx("p",{className:"font-medium text-xs",children:J.platform})]}),e.jsxs("div",{children:[e.jsx("div",{className:"text-xs text-muted-foreground mb-1",children:"用户ID"}),e.jsx("p",{className:"font-mono text-xs truncate",title:J.user_id,children:J.user_id})]}),e.jsxs("div",{className:"col-span-2",children:[e.jsx("div",{className:"text-xs text-muted-foreground mb-1",children:"最后更新"}),e.jsx("p",{className:"text-xs",children:Te(J.last_know)})]})]}),e.jsxs("div",{className:"flex flex-wrap gap-1 pt-2 border-t overflow-hidden",children:[e.jsxs(C,{variant:"outline",size:"sm",onClick:()=>L(J),className:"text-xs px-2 py-1 h-auto flex-shrink-0",children:[e.jsx(Gt,{className:"h-3 w-3 mr-1"}),"查看"]}),e.jsxs(C,{variant:"outline",size:"sm",onClick:()=>B(J),className:"text-xs px-2 py-1 h-auto flex-shrink-0",children:[e.jsx(pn,{className:"h-3 w-3 mr-1"}),"编辑"]}),e.jsxs(C,{variant:"outline",size:"sm",onClick:()=>E(J),className:"text-xs px-2 py-1 h-auto flex-shrink-0 text-destructive hover:text-destructive",children:[e.jsx(es,{className:"h-3 w-3 mr-1"}),"删除"]})]})]},J.id))}),u>0&&e.jsxs("div",{className:"flex flex-col sm:flex-row items-center justify-between gap-4 px-4 py-3 border-t",children:[e.jsxs("div",{className:"text-sm text-muted-foreground",children:["共 ",u," 条记录,第 ",h," / ",Math.ceil(u/g)," 页"]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(C,{variant:"outline",size:"sm",onClick:()=>f(1),disabled:h===1,className:"hidden sm:flex",children:e.jsx(vi,{className:"h-4 w-4"})}),e.jsxs(C,{variant:"outline",size:"sm",onClick:()=>f(h-1),disabled:h===1,children:[e.jsx(pl,{className:"h-4 w-4 sm:mr-1"}),e.jsx("span",{className:"hidden sm:inline",children:"上一页"})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(ie,{type:"number",value:je,onChange:J=>be(J.target.value),onKeyDown:J=>J.key==="Enter"&&xe(),placeholder:h.toString(),className:"w-16 h-8 text-center",min:1,max:Math.ceil(u/g)}),e.jsx(C,{variant:"outline",size:"sm",onClick:xe,disabled:!je,className:"h-8",children:"跳转"})]}),e.jsxs(C,{variant:"outline",size:"sm",onClick:()=>f(h+1),disabled:h>=Math.ceil(u/g),children:[e.jsx("span",{className:"hidden sm:inline",children:"下一页"}),e.jsx(Ya,{className:"h-4 w-4 sm:ml-1"})]}),e.jsx(C,{variant:"outline",size:"sm",onClick:()=>f(Math.ceil(u/g)),disabled:h>=Math.ceil(u/g),className:"hidden sm:flex",children:e.jsx(bi,{className:"h-4 w-4"})})]})]})]})]})}),e.jsx(w_,{person:A,open:V,onOpenChange:z}),e.jsx(__,{person:A,open:_,onOpenChange:T,onSuccess:()=>{P(),X(),T(!1)}}),e.jsx(js,{open:!!$,onOpenChange:()=>E(null),children:e.jsxs(os,{children:[e.jsxs(ds,{children:[e.jsx(ms,{children:"确认删除"}),e.jsxs(xs,{children:['确定要删除人物信息 "',$?.person_name||$?.nickname||$?.user_id,'" 吗? 此操作不可撤销。']})]}),e.jsxs(us,{children:[e.jsx(fs,{children:"取消"}),e.jsx(hs,{onClick:()=>$&&_e($),className:"bg-destructive text-destructive-foreground hover:bg-destructive/90",children:"删除"})]})]})}),e.jsx(js,{open:Se,onOpenChange:oe,children:e.jsxs(os,{children:[e.jsxs(ds,{children:[e.jsx(ms,{children:"确认批量删除"}),e.jsxs(xs,{children:["确定要删除选中的 ",ne.size," 个人物信息吗? 此操作不可撤销。"]})]}),e.jsxs(us,{children:[e.jsx(fs,{children:"取消"}),e.jsx(hs,{onClick:Q,className:"bg-destructive text-destructive-foreground hover:bg-destructive/90",children:"批量删除"})]})]})})]})}function w_({person:l,open:i,onOpenChange:r}){if(!l)return null;const o=u=>u?new Date(u*1e3).toLocaleString("zh-CN"):"-";return e.jsx(Qs,{open:i,onOpenChange:r,children:e.jsxs(qs,{className:"max-w-2xl max-h-[80vh] overflow-y-auto",children:[e.jsxs(Gs,{children:[e.jsx(Vs,{children:"人物详情"}),e.jsxs(Ws,{children:["查看 ",l.person_name||l.nickname||l.user_id," 的完整信息"]})]}),e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"grid grid-cols-2 gap-4",children:[e.jsx(ml,{icon:oo,label:"人物名称",value:l.person_name}),e.jsx(ml,{icon:Fl,label:"昵称",value:l.nickname}),e.jsx(ml,{icon:pi,label:"用户ID",value:l.user_id,mono:!0}),e.jsx(ml,{icon:pi,label:"人物ID",value:l.person_id,mono:!0}),e.jsx(ml,{label:"平台",value:l.platform}),e.jsx(ml,{label:"状态",value:l.is_known?"已认识":"未认识"})]}),l.name_reason&&e.jsxs("div",{className:"rounded-lg border bg-muted/50 p-3",children:[e.jsx(k,{className:"text-xs text-muted-foreground",children:"名称设定原因"}),e.jsx("p",{className:"mt-1 text-sm",children:l.name_reason})]}),l.memory_points&&e.jsxs("div",{className:"rounded-lg border bg-muted/50 p-3",children:[e.jsx(k,{className:"text-xs text-muted-foreground",children:"个人印象"}),e.jsx("p",{className:"mt-1 text-sm whitespace-pre-wrap",children:l.memory_points})]}),l.group_nick_name&&l.group_nick_name.length>0&&e.jsxs("div",{className:"rounded-lg border bg-muted/50 p-3",children:[e.jsx(k,{className:"text-xs text-muted-foreground",children:"群昵称"}),e.jsx("div",{className:"mt-2 space-y-1",children:l.group_nick_name.map((u,x)=>e.jsxs("div",{className:"text-sm flex items-center gap-2",children:[e.jsx("span",{className:"font-mono text-xs text-muted-foreground",children:u.group_id}),e.jsx("span",{children:"→"}),e.jsx("span",{children:u.group_nick_name})]},x))})]}),e.jsxs("div",{className:"grid grid-cols-3 gap-4",children:[e.jsx(ml,{icon:xi,label:"认识时间",value:o(l.know_times)}),e.jsx(ml,{icon:xi,label:"首次记录",value:o(l.know_since)}),e.jsx(ml,{icon:xi,label:"最后更新",value:o(l.last_know)})]})]}),e.jsx(at,{children:e.jsx(C,{onClick:()=>r(!1),children:"关闭"})})]})})}function ml({icon:l,label:i,value:r,mono:o=!1}){return e.jsxs("div",{className:"space-y-1",children:[e.jsxs(k,{className:"text-xs text-muted-foreground flex items-center gap-1",children:[l&&e.jsx(l,{className:"h-3 w-3"}),i]}),e.jsx("div",{className:H("text-sm",o&&"font-mono",!r&&"text-muted-foreground"),children:r||"-"})]})}function __({person:l,open:i,onOpenChange:r,onSuccess:o}){const[u,x]=m.useState({}),[h,f]=m.useState(!1),{toast:g}=Ks();m.useEffect(()=>{l&&x({person_name:l.person_name||"",name_reason:l.name_reason||"",nickname:l.nickname||"",memory_points:l.memory_points||"",is_known:l.is_known})},[l]);const j=async()=>{if(l)try{f(!0),await j_(l.person_id,u),g({title:"保存成功",description:"人物信息已更新"}),o()}catch(v){g({title:"保存失败",description:v instanceof Error?v.message:"无法更新人物信息",variant:"destructive"})}finally{f(!1)}};return l?e.jsx(Qs,{open:i,onOpenChange:r,children:e.jsxs(qs,{className:"max-w-2xl max-h-[80vh] overflow-y-auto",children:[e.jsxs(Gs,{children:[e.jsx(Vs,{children:"编辑人物信息"}),e.jsxs(Ws,{children:["修改 ",l.person_name||l.nickname||l.user_id," 的信息"]})]}),e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"grid grid-cols-2 gap-4",children:[e.jsxs("div",{className:"space-y-2",children:[e.jsx(k,{htmlFor:"person_name",children:"人物名称"}),e.jsx(ie,{id:"person_name",value:u.person_name||"",onChange:v=>x({...u,person_name:v.target.value}),placeholder:"为这个人设置一个名称"})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(k,{htmlFor:"nickname",children:"昵称"}),e.jsx(ie,{id:"nickname",value:u.nickname||"",onChange:v=>x({...u,nickname:v.target.value}),placeholder:"昵称"})]})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(k,{htmlFor:"name_reason",children:"名称设定原因"}),e.jsx(Ys,{id:"name_reason",value:u.name_reason||"",onChange:v=>x({...u,name_reason:v.target.value}),placeholder:"为什么这样称呼这个人?",rows:2})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(k,{htmlFor:"memory_points",children:"个人印象"}),e.jsx(Ys,{id:"memory_points",value:u.memory_points||"",onChange:v=>x({...u,memory_points:v.target.value}),placeholder:"对这个人的印象和记忆点...",rows:4})]}),e.jsxs("div",{className:"flex items-center justify-between rounded-lg border p-3",children:[e.jsxs("div",{children:[e.jsx(k,{htmlFor:"is_known",className:"text-base font-medium",children:"已认识"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"标记是否已经认识这个人"})]}),e.jsx(Fe,{id:"is_known",checked:u.is_known,onCheckedChange:v=>x({...u,is_known:v})})]})]}),e.jsxs(at,{children:[e.jsx(C,{variant:"outline",onClick:()=>r(!1),children:"取消"}),e.jsx(C,{onClick:j,disabled:h,children:h?"保存中...":"保存"})]})]})}):null}var S_=w0();const Bp=kN(S_),vm="/api/webui";async function C_(l=100,i="all"){const r=`${vm}/knowledge/graph?limit=${l}&node_type=${i}`,o=await fetch(r);if(!o.ok)throw new Error(`获取知识图谱失败: ${o.status}`);return o.json()}async function k_(){const l=await fetch(`${vm}/knowledge/stats`);if(!l.ok)throw new Error("获取知识图谱统计信息失败");return l.json()}async function T_(l){const i=await fetch(`${vm}/knowledge/search?query=${encodeURIComponent(l)}`);if(!i.ok)throw new Error("搜索知识节点失败");return i.json()}const Ej=m.memo(({data:l})=>e.jsxs("div",{className:"px-4 py-2 shadow-md rounded-lg bg-gradient-to-br from-blue-500 to-blue-600 border-2 border-blue-700 min-w-[120px]",children:[e.jsx(mo,{type:"target",position:xo.Top}),e.jsx("div",{className:"font-semibold text-white text-sm truncate max-w-[200px]",title:l.content,children:l.label}),e.jsx(mo,{type:"source",position:xo.Bottom})]}));Ej.displayName="EntityNode";const zj=m.memo(({data:l})=>e.jsxs("div",{className:"px-3 py-2 shadow-md rounded-md bg-gradient-to-br from-green-500 to-green-600 border-2 border-green-700 min-w-[100px]",children:[e.jsx(mo,{type:"target",position:xo.Top}),e.jsx("div",{className:"font-medium text-white text-xs truncate max-w-[150px]",title:l.content,children:l.label}),e.jsx(mo,{type:"source",position:xo.Bottom})]}));zj.displayName="ParagraphNode";const E_={entity:Ej,paragraph:zj};function z_(l,i){const r=new Bp.graphlib.Graph;r.setDefaultEdgeLabel(()=>({})),r.setGraph({rankdir:"TB",ranksep:100,nodesep:80});const o=[],u=[];return l.forEach(x=>{r.setNode(x.id,{width:150,height:50})}),i.forEach(x=>{r.setEdge(x.source,x.target)}),Bp.layout(r),l.forEach(x=>{const h=r.node(x.id);o.push({id:x.id,type:x.type,position:{x:h.x-75,y:h.y-25},data:{label:x.content.slice(0,20)+(x.content.length>20?"...":""),content:x.content}})}),i.forEach((x,h)=>{const f={id:`edge-${h}`,source:x.source,target:x.target,animated:l.length<=200&&x.weight>5,style:{strokeWidth:Math.min(x.weight/2,5),opacity:.6}};x.weight>10&&l.length<100&&(f.label=`${x.weight.toFixed(0)}`),u.push(f)}),{nodes:o,edges:u}}function M_(){const l=ka(),[i,r]=m.useState(!1),[o,u]=m.useState(null),[x,h]=m.useState(""),[f,g]=m.useState("all"),[j,v]=m.useState(50),[y,b]=m.useState("50"),[S,w]=m.useState(!1),[O,A]=m.useState(!0),[D,V]=m.useState(!1),[z,_]=m.useState(!1),[T,$,E]=_0([]),[se,te,ne]=S0([]),[ue,Se]=m.useState(0),[oe,je]=m.useState(null),[be,U]=m.useState(null),{toast:P}=Ks(),X=m.useCallback(Q=>Q.type==="entity"?"#6366f1":Q.type==="paragraph"?"#10b981":"#6b7280",[]),L=m.useCallback(async(Q=!1)=>{try{if(!Q&&j>200){_(!0);return}r(!0);const[xe,Te]=await Promise.all([C_(j,f),k_()]);if(u(Te),xe.nodes.length===0){P({title:"提示",description:"知识库为空,请先导入知识数据"}),$([]),te([]);return}const{nodes:J,edges:le}=z_(xe.nodes,xe.edges);$(J),te(le),Se(J.length),Te&&Te.total_nodes>j&&P({title:"提示",description:`知识图谱包含 ${Te.total_nodes} 个节点,当前显示 ${J.length} 个`}),P({title:"加载成功",description:`已加载 ${J.length} 个节点,${le.length} 条边`})}catch(xe){console.error("加载知识图谱失败:",xe),P({title:"加载失败",description:xe instanceof Error?xe.message:"未知错误",variant:"destructive"})}finally{r(!1)}},[j,f,P]),B=m.useCallback(async()=>{if(!x.trim()){P({title:"提示",description:"请输入搜索关键词"});return}try{const Q=await T_(x);if(Q.length===0){P({title:"未找到",description:"没有找到匹配的节点"});return}const xe=new Set(Q.map(Te=>Te.id));$(Te=>Te.map(J=>({...J,style:{...J.style,opacity:xe.has(J.id)?1:.3,filter:xe.has(J.id)?"brightness(1.2)":"brightness(0.8)"}}))),P({title:"搜索完成",description:`找到 ${Q.length} 个匹配节点`})}catch(Q){console.error("搜索失败:",Q),P({title:"搜索失败",description:Q instanceof Error?Q.message:"未知错误",variant:"destructive"})}},[x,P]),_e=m.useCallback(()=>{$(Q=>Q.map(xe=>({...xe,style:{...xe.style,opacity:1,filter:"brightness(1)"}})))},[]),Ne=m.useCallback(()=>{A(!1),V(!0),L()},[L]),Ce=m.useCallback(()=>{_(!1),setTimeout(()=>{L(!0)},0)},[L]),ve=m.useCallback((Q,xe)=>{T.find(J=>J.id===xe.id)&&je({id:xe.id,type:xe.type,content:xe.data.content})},[T]);m.useEffect(()=>{O||D&&L()},[j,f,O,D]);const ze=m.useCallback((Q,xe)=>{const Te=T.find(qe=>qe.id===xe.source),J=T.find(qe=>qe.id===xe.target),le=se.find(qe=>qe.id===xe.id);Te&&J&&le&&U({source:{id:Te.id,type:Te.type,content:Te.data.content},target:{id:J.id,type:J.type,content:J.data.content},edge:{source:xe.source,target:xe.target,weight:parseFloat(xe.label||"0")}})},[T,se]);return e.jsxs("div",{className:"h-full flex flex-col",children:[e.jsxs("div",{className:"flex-shrink-0 p-4 border-b bg-background",children:[e.jsxs("div",{className:"flex flex-col sm:flex-row justify-between items-start sm:items-center gap-4",children:[e.jsxs("div",{children:[e.jsx("h1",{className:"text-2xl sm:text-3xl font-bold",children:"麦麦知识库图谱"}),e.jsx("p",{className:"text-muted-foreground mt-1",children:"可视化知识实体与关系网络"})]}),o&&e.jsxs("div",{className:"flex gap-2 flex-wrap",children:[e.jsxs(Ye,{variant:"outline",className:"gap-1",children:[e.jsx(ro,{className:"h-3 w-3"}),"节点: ",o.total_nodes]}),e.jsxs(Ye,{variant:"outline",className:"gap-1",children:[e.jsx(Bg,{className:"h-3 w-3"}),"边: ",o.total_edges]}),e.jsxs(Ye,{variant:"outline",className:"gap-1",children:[e.jsx(Ra,{className:"h-3 w-3"}),"实体: ",o.entity_nodes]}),e.jsxs(Ye,{variant:"outline",className:"gap-1",children:[e.jsx(Aa,{className:"h-3 w-3"}),"段落: ",o.paragraph_nodes]})]})]}),e.jsxs("div",{className:"flex flex-col sm:flex-row gap-2 mt-4",children:[e.jsxs("div",{className:"flex-1 flex gap-2",children:[e.jsx(ie,{placeholder:"搜索节点内容...",value:x,onChange:Q=>h(Q.target.value),onKeyDown:Q=>Q.key==="Enter"&&B(),className:"flex-1"}),e.jsx(C,{onClick:B,size:"sm",children:e.jsx($t,{className:"h-4 w-4"})}),e.jsx(C,{onClick:_e,variant:"outline",size:"sm",children:"重置"})]}),e.jsxs("div",{className:"flex gap-2",children:[e.jsxs(Ue,{value:f,onValueChange:Q=>g(Q),children:[e.jsx(Re,{className:"w-[120px]",children:e.jsx(Be,{})}),e.jsxs(Le,{children:[e.jsx(ee,{value:"all",children:"全部节点"}),e.jsx(ee,{value:"entity",children:"仅实体"}),e.jsx(ee,{value:"paragraph",children:"仅段落"})]})]}),e.jsxs(Ue,{value:j===1e4?"all":S?"custom":j.toString(),onValueChange:Q=>{Q==="custom"?(w(!0),b(j.toString())):Q==="all"?(w(!1),v(1e4)):(w(!1),v(Number(Q)))},children:[e.jsx(Re,{className:"w-[120px]",children:e.jsx(Be,{})}),e.jsxs(Le,{children:[e.jsx(ee,{value:"50",children:"50 节点"}),e.jsx(ee,{value:"100",children:"100 节点"}),e.jsx(ee,{value:"200",children:"200 节点"}),e.jsx(ee,{value:"500",children:"500 节点"}),e.jsx(ee,{value:"1000",children:"1000 节点"}),e.jsx(ee,{value:"all",children:"全部 (最多10000)"}),e.jsx(ee,{value:"custom",children:"自定义..."})]})]}),S&&e.jsx(ie,{type:"number",min:"50",value:y,onChange:Q=>b(Q.target.value),onBlur:()=>{const Q=parseInt(y);!isNaN(Q)&&Q>=50?v(Q):(b("50"),v(50))},onKeyDown:Q=>{if(Q.key==="Enter"){const xe=parseInt(y);!isNaN(xe)&&xe>=50?v(xe):(b("50"),v(50))}},placeholder:"最少50个",className:"w-[120px]"}),e.jsx(C,{onClick:()=>L(),variant:"outline",size:"sm",disabled:i,children:e.jsx(At,{className:H("h-4 w-4",i&&"animate-spin")})})]})]})]}),e.jsx("div",{className:"flex-1 relative",children:i?e.jsx("div",{className:"absolute inset-0 flex items-center justify-center",children:e.jsxs("div",{className:"text-center",children:[e.jsx(At,{className:"h-8 w-8 animate-spin mx-auto mb-2 text-muted-foreground"}),e.jsx("p",{className:"text-muted-foreground",children:"加载知识图谱中..."})]})}):T.length===0?e.jsx("div",{className:"absolute inset-0 flex items-center justify-center",children:e.jsxs("div",{className:"text-center",children:[e.jsx(ro,{className:"h-12 w-12 mx-auto mb-4 text-muted-foreground"}),e.jsx("h3",{className:"text-lg font-semibold mb-2",children:"知识库为空"}),e.jsx("p",{className:"text-muted-foreground",children:"请先导入知识数据"})]})}):e.jsxs(C0,{nodes:T,edges:se,onNodesChange:E,onEdgesChange:ne,onNodeClick:ve,onEdgeClick:ze,nodeTypes:E_,fitView:!0,minZoom:.05,maxZoom:1.5,defaultViewport:{x:0,y:0,zoom:.5},elevateNodesOnSelect:ue<=500,nodesDraggable:ue<=1e3,attributionPosition:"bottom-left",children:[e.jsx(k0,{variant:T0.Dots,gap:12,size:1}),e.jsx(E0,{}),ue<=500&&e.jsx(z0,{nodeColor:X,nodeBorderRadius:8,pannable:!0,zoomable:!0}),e.jsxs(M0,{position:"top-right",className:"bg-background/95 backdrop-blur-sm rounded-lg border p-3 shadow-lg",children:[e.jsx("div",{className:"text-sm font-semibold mb-2",children:"图例"}),e.jsxs("div",{className:"space-y-2 text-xs",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("div",{className:"w-4 h-4 rounded bg-gradient-to-br from-blue-500 to-blue-600 border-2 border-blue-700"}),e.jsx("span",{children:"实体节点"})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("div",{className:"w-4 h-4 rounded bg-gradient-to-br from-green-500 to-green-600 border-2 border-green-700"}),e.jsx("span",{children:"段落节点"})]}),ue>200&&e.jsxs("div",{className:"mt-2 pt-2 border-t text-yellow-600 dark:text-yellow-500",children:[e.jsx("div",{className:"font-semibold",children:"性能模式"}),e.jsx("div",{children:"已禁用动画"}),ue>500&&e.jsx("div",{children:"已禁用缩略图"})]})]})]})]})}),e.jsx(Qs,{open:!!oe,onOpenChange:Q=>!Q&&je(null),children:e.jsxs(qs,{className:"max-w-2xl max-h-[80vh] overflow-y-auto",children:[e.jsx(Gs,{children:e.jsx(Vs,{children:"节点详情"})}),oe&&e.jsxs("div",{className:"space-y-4",children:[e.jsx("div",{className:"grid grid-cols-2 gap-4",children:e.jsxs("div",{children:[e.jsx("label",{className:"text-sm font-medium text-muted-foreground",children:"类型"}),e.jsx("div",{className:"mt-1",children:e.jsx(Ye,{variant:oe.type==="entity"?"default":"secondary",children:oe.type==="entity"?"🏷️ 实体":"📄 段落"})})]})}),e.jsxs("div",{children:[e.jsx("label",{className:"text-sm font-medium text-muted-foreground",children:"ID"}),e.jsx("code",{className:"mt-1 block p-2 bg-muted rounded text-xs break-all",children:oe.id})]}),e.jsxs("div",{children:[e.jsx("label",{className:"text-sm font-medium text-muted-foreground",children:"内容"}),e.jsx(Ze,{className:"mt-1 h-40 p-3 bg-muted rounded",children:e.jsx("p",{className:"text-sm whitespace-pre-wrap",children:oe.content})})]})]})]})}),e.jsx(Qs,{open:!!be,onOpenChange:Q=>!Q&&U(null),children:e.jsxs(qs,{className:"max-w-2xl max-h-[80vh] overflow-hidden flex flex-col",children:[e.jsx(Gs,{children:e.jsx(Vs,{children:"边详情"})}),be&&e.jsx(Ze,{className:"flex-1 pr-4",children:e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"flex items-center gap-4",children:[e.jsxs("div",{className:"flex-1 min-w-0 p-3 bg-blue-50 dark:bg-blue-950 rounded border-2 border-blue-200 dark:border-blue-800",children:[e.jsx("div",{className:"text-xs text-muted-foreground mb-1",children:"源节点"}),e.jsx("div",{className:"font-medium text-sm mb-2 truncate",children:be.source.content}),e.jsxs("code",{className:"text-xs text-muted-foreground truncate block",children:[be.source.id.slice(0,40),"..."]})]}),e.jsx("div",{className:"text-2xl text-muted-foreground flex-shrink-0",children:"→"}),e.jsxs("div",{className:"flex-1 min-w-0 p-3 bg-green-50 dark:bg-green-950 rounded border-2 border-green-200 dark:border-green-800",children:[e.jsx("div",{className:"text-xs text-muted-foreground mb-1",children:"目标节点"}),e.jsx("div",{className:"font-medium text-sm mb-2 truncate",children:be.target.content}),e.jsxs("code",{className:"text-xs text-muted-foreground truncate block",children:[be.target.id.slice(0,40),"..."]})]})]}),e.jsxs("div",{children:[e.jsx("label",{className:"text-sm font-medium text-muted-foreground",children:"权重"}),e.jsx("div",{className:"mt-1",children:e.jsx(Ye,{variant:"outline",className:"text-base font-mono",children:be.edge.weight.toFixed(4)})})]})]})})]})}),e.jsx(js,{open:O,onOpenChange:A,children:e.jsxs(os,{children:[e.jsxs(ds,{children:[e.jsx(ms,{children:"加载知识图谱"}),e.jsxs(xs,{children:["知识图谱的动态展示会消耗较多系统资源。",e.jsx("br",{}),"确定要加载知识图谱吗?"]})]}),e.jsxs(us,{children:[e.jsx(fs,{onClick:()=>l({to:"/"}),children:"取消 (返回首页)"}),e.jsx(hs,{onClick:Ne,children:"确认加载"})]})]})}),e.jsx(js,{open:z,onOpenChange:_,children:e.jsxs(os,{children:[e.jsxs(ds,{children:[e.jsx(ms,{children:"⚠️ 节点数量较多"}),e.jsx(xs,{asChild:!0,children:e.jsxs("div",{children:[e.jsxs("p",{children:["您正在尝试加载 ",e.jsx("strong",{className:"text-orange-600",children:j>=1e4?"全部 (最多10000个)":j})," 个节点。"]}),e.jsx("p",{className:"mt-4",children:"节点数量过多可能导致:"}),e.jsxs("ul",{className:"list-disc list-inside mt-2 space-y-1",children:[e.jsx("li",{children:"页面加载时间较长"}),e.jsx("li",{children:"浏览器卡顿或崩溃"}),e.jsx("li",{children:"系统资源占用过高"})]}),e.jsx("p",{className:"mt-4",children:"建议先选择较少的节点数量 (50-200 个)。"})]})})]}),e.jsxs(us,{children:[e.jsx(fs,{onClick:()=>{_(!1),j>200&&(v(50),w(!1))},children:"取消"}),e.jsx(hs,{onClick:Ce,className:"bg-orange-600 hover:bg-orange-700",children:"我了解风险,继续加载"})]})]})})]})}function Hp({className:l,classNames:i,showOutsideDays:r=!0,captionLayout:o="label",buttonVariant:u="ghost",formatters:x,components:h,...f}){const g=sj();return e.jsx(p0,{showOutsideDays:r,className:H("bg-background group/calendar p-3 [--cell-size:2rem] [[data-slot=card-content]_&]:bg-transparent [[data-slot=popover-content]_&]:bg-transparent",String.raw`rtl:**:[.rdp-button\_next>svg]:rotate-180`,String.raw`rtl:**:[.rdp-button\_previous>svg]:rotate-180`,l),captionLayout:o,formatters:{formatMonthDropdown:j=>j.toLocaleString("default",{month:"short"}),...x},classNames:{root:H("w-fit",g.root),months:H("relative flex flex-col gap-4 md:flex-row",g.months),month:H("flex w-full flex-col gap-4",g.month),nav:H("absolute inset-x-0 top-0 flex w-full items-center justify-between gap-1",g.nav),button_previous:H(Sr({variant:u}),"h-[--cell-size] w-[--cell-size] select-none p-0 aria-disabled:opacity-50",g.button_previous),button_next:H(Sr({variant:u}),"h-[--cell-size] w-[--cell-size] select-none p-0 aria-disabled:opacity-50",g.button_next),month_caption:H("flex h-[--cell-size] w-full items-center justify-center px-[--cell-size]",g.month_caption),dropdowns:H("flex h-[--cell-size] w-full items-center justify-center gap-1.5 text-sm font-medium",g.dropdowns),dropdown_root:H("has-focus:border-ring border-input shadow-xs has-focus:ring-ring/50 has-focus:ring-[3px] relative rounded-md border",g.dropdown_root),dropdown:H("bg-popover absolute inset-0 opacity-0",g.dropdown),caption_label:H("select-none font-medium",o==="label"?"text-sm":"[&>svg]:text-muted-foreground flex h-8 items-center gap-1 rounded-md pl-2 pr-1 text-sm [&>svg]:size-3.5",g.caption_label),table:"w-full border-collapse",weekdays:H("flex",g.weekdays),weekday:H("text-muted-foreground flex-1 select-none rounded-md text-[0.8rem] font-normal",g.weekday),week:H("mt-2 flex w-full",g.week),week_number_header:H("w-[--cell-size] select-none",g.week_number_header),week_number:H("text-muted-foreground select-none text-[0.8rem]",g.week_number),day:H("group/day relative aspect-square h-full w-full select-none p-0 text-center [&:first-child[data-selected=true]_button]:rounded-l-md [&:last-child[data-selected=true]_button]:rounded-r-md",g.day),range_start:H("bg-accent rounded-l-md",g.range_start),range_middle:H("rounded-none",g.range_middle),range_end:H("bg-accent rounded-r-md",g.range_end),today:H("bg-accent text-accent-foreground rounded-md data-[selected=true]:rounded-none",g.today),outside:H("text-muted-foreground aria-selected:text-muted-foreground",g.outside),disabled:H("text-muted-foreground opacity-50",g.disabled),hidden:H("invisible",g.hidden),...i},components:{Root:({className:j,rootRef:v,...y})=>e.jsx("div",{"data-slot":"calendar",ref:v,className:H(j),...y}),Chevron:({className:j,orientation:v,...y})=>v==="left"?e.jsx(pl,{className:H("size-4",j),...y}):v==="right"?e.jsx(Ya,{className:H("size-4",j),...y}):e.jsx(Fa,{className:H("size-4",j),...y}),DayButton:A_,WeekNumber:({children:j,...v})=>e.jsx("td",{...v,children:e.jsx("div",{className:"flex size-[--cell-size] items-center justify-center text-center",children:j})}),...h},...f})}function A_({className:l,day:i,modifiers:r,...o}){const u=sj(),x=m.useRef(null);return m.useEffect(()=>{r.focused&&x.current?.focus()},[r.focused]),e.jsx(C,{ref:x,variant:"ghost",size:"icon","data-day":i.date.toLocaleDateString(),"data-selected-single":r.selected&&!r.range_start&&!r.range_end&&!r.range_middle,"data-range-start":r.range_start,"data-range-end":r.range_end,"data-range-middle":r.range_middle,className:H("data-[selected-single=true]:bg-primary data-[selected-single=true]:text-primary-foreground data-[range-middle=true]:bg-accent data-[range-middle=true]:text-accent-foreground data-[range-start=true]:bg-primary data-[range-start=true]:text-primary-foreground data-[range-end=true]:bg-primary data-[range-end=true]:text-primary-foreground group-data-[focused=true]/day:border-ring group-data-[focused=true]/day:ring-ring/50 flex aspect-square h-auto w-full min-w-[--cell-size] flex-col gap-1 font-normal leading-none data-[range-end=true]:rounded-md data-[range-middle=true]:rounded-none data-[range-start=true]:rounded-md group-data-[focused=true]/day:relative group-data-[focused=true]/day:z-10 group-data-[focused=true]/day:ring-[3px] [&>span]:text-xs [&>span]:opacity-70",u.day,l),...o})}const eo={xs:{label:"小",rowHeight:28,class:"text-[10px] sm:text-xs"},sm:{label:"中",rowHeight:36,class:"text-xs sm:text-sm"},base:{label:"大",rowHeight:44,class:"text-sm sm:text-base"}};function O_(){const[l,i]=m.useState([]),[r,o]=m.useState(""),[u,x]=m.useState("all"),[h,f]=m.useState("all"),[g,j]=m.useState(void 0),[v,y]=m.useState(void 0),[b,S]=m.useState(!0),[w,O]=m.useState(!1),[A,D]=m.useState("xs"),[V,z]=m.useState(4),[_,T]=m.useState(!1),$=m.useRef(null);m.useEffect(()=>{const B=xn.getAllLogs();i(B);const _e=xn.onLog(()=>{i(xn.getAllLogs())}),Ne=xn.onConnectionChange(Ce=>{O(Ce)});return()=>{_e(),Ne()}},[]);const E=m.useMemo(()=>{const B=new Set(l.map(_e=>_e.module).filter(_e=>_e&&_e.trim()!==""));return Array.from(B).sort()},[l]),se=B=>{switch(B){case"DEBUG":return"text-muted-foreground";case"INFO":return"text-blue-500 dark:text-blue-400";case"WARNING":return"text-yellow-600 dark:text-yellow-500";case"ERROR":return"text-red-600 dark:text-red-500";case"CRITICAL":return"text-red-700 dark:text-red-400 font-bold";default:return"text-foreground"}},te=B=>{switch(B){case"DEBUG":return"bg-gray-800/30 dark:bg-gray-800/50";case"INFO":return"bg-blue-900/20 dark:bg-blue-500/20";case"WARNING":return"bg-yellow-900/20 dark:bg-yellow-500/20";case"ERROR":return"bg-red-900/20 dark:bg-red-500/20";case"CRITICAL":return"bg-red-900/30 dark:bg-red-600/30";default:return"bg-gray-800/20 dark:bg-gray-800/30"}},ne=()=>{window.location.reload()},ue=()=>{xn.clearLogs(),i([])},Se=()=>{const B=be.map(ve=>`${ve.timestamp} [${ve.level.padEnd(8)}] [${ve.module}] ${ve.message}`).join(` +`),_e=new Blob([B],{type:"text/plain;charset=utf-8"}),Ne=URL.createObjectURL(_e),Ce=document.createElement("a");Ce.href=Ne,Ce.download=`logs-${Du(new Date,"yyyy-MM-dd-HHmmss")}.txt`,Ce.click(),URL.revokeObjectURL(Ne)},oe=()=>{S(!b)},je=()=>{j(void 0),y(void 0)},be=m.useMemo(()=>l.filter(B=>{const _e=r===""||B.message.toLowerCase().includes(r.toLowerCase())||B.module.toLowerCase().includes(r.toLowerCase()),Ne=u==="all"||B.level===u,Ce=h==="all"||B.module===h;let ve=!0;if(g||v){const ze=new Date(B.timestamp);if(g){const Q=new Date(g);Q.setHours(0,0,0,0),ve=ve&&ze>=Q}if(v){const Q=new Date(v);Q.setHours(23,59,59,999),ve=ve&&ze<=Q}}return _e&&Ne&&Ce&&ve}),[l,r,u,h,g,v]),U=eo[A].rowHeight+V,P=vN({count:be.length,getScrollElement:()=>$.current,estimateSize:()=>U,overscan:50}),X=m.useRef(!1),L=m.useRef(be.length);return m.useEffect(()=>{const B=$.current;if(!B)return;const _e=()=>{if(X.current)return;const{scrollTop:Ne,scrollHeight:Ce,clientHeight:ve}=B,ze=Ce-Ne-ve;ze>100&&b?S(!1):ze<50&&!b&&S(!0)};return B.addEventListener("scroll",_e,{passive:!0}),()=>B.removeEventListener("scroll",_e)},[b]),m.useEffect(()=>{const B=be.length>L.current;L.current=be.length,b&&be.length>0&&B&&(X.current=!0,P.scrollToIndex(be.length-1,{align:"end",behavior:"auto"}),requestAnimationFrame(()=>{requestAnimationFrame(()=>{X.current=!1})}))},[be.length,b,P]),e.jsxs("div",{className:"h-full flex flex-col overflow-hidden",children:[e.jsxs("div",{className:"flex-shrink-0 space-y-2 sm:space-y-3 p-2 sm:p-3 lg:p-4",children:[e.jsxs("div",{className:"flex items-center justify-between gap-3",children:[e.jsxs("div",{children:[e.jsx("h1",{className:"text-lg sm:text-xl lg:text-2xl font-bold",children:"日志查看器"}),e.jsx("p",{className:"text-xs text-muted-foreground mt-0.5 hidden sm:block",children:"实时查看和分析麦麦运行日志"})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("div",{className:H("h-2 w-2 sm:h-2.5 sm:w-2.5 rounded-full",w?"bg-green-500 animate-pulse":"bg-red-500")}),e.jsx("span",{className:"text-xs text-muted-foreground",children:w?"已连接":"未连接"})]})]}),e.jsx(Ve,{className:"p-2 sm:p-3",children:e.jsx(Tr,{open:_,onOpenChange:T,children:e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsxs("div",{className:"flex gap-2",children:[e.jsxs("div",{className:"flex-1 relative min-w-0",children:[e.jsx($t,{className:"absolute left-2 top-1/2 -translate-y-1/2 h-3.5 w-3.5 text-muted-foreground"}),e.jsx(ie,{placeholder:"搜索日志...",value:r,onChange:B=>o(B.target.value),className:"pl-8 h-8 text-xs sm:text-sm"})]}),e.jsxs("div",{className:"flex gap-1 flex-shrink-0",children:[e.jsxs(C,{variant:b?"default":"outline",size:"sm",onClick:oe,className:"h-8 px-2",title:b?"自动滚动":"已暂停",children:[b?e.jsx(Yy,{className:"h-3.5 w-3.5"}):e.jsx(Ky,{className:"h-3.5 w-3.5"}),e.jsx("span",{className:"ml-1 text-xs hidden sm:inline",children:b?"滚动":"暂停"})]}),e.jsxs(C,{variant:"outline",size:"sm",onClick:ue,className:"h-8 px-2",title:"清空日志",children:[e.jsx(es,{className:"h-3.5 w-3.5"}),e.jsx("span",{className:"ml-1 text-xs hidden md:inline",children:"清空"})]}),e.jsxs(C,{variant:"outline",size:"sm",onClick:Se,className:"h-8 px-2 hidden sm:flex",title:"导出日志",children:[e.jsx(Da,{className:"h-3.5 w-3.5"}),e.jsx("span",{className:"ml-1 text-xs hidden lg:inline",children:"导出"})]}),e.jsx(Er,{asChild:!0,children:e.jsxs(C,{variant:"outline",size:"sm",className:"h-8 px-2",title:_?"收起筛选":"展开筛选",children:[e.jsx(lo,{className:"h-3.5 w-3.5"}),_?e.jsx(fi,{className:"h-3.5 w-3.5 ml-1"}):e.jsx(Fa,{className:"h-3.5 w-3.5 ml-1"})]})})]})]}),e.jsxs("div",{className:"text-xs text-muted-foreground text-center sm:text-right -mt-1",children:[e.jsxs("span",{className:"font-mono",children:[be.length," / ",l.length]}),e.jsx("span",{className:"ml-1",children:"条日志"})]}),e.jsxs(zr,{className:"space-y-2",children:[e.jsxs("div",{className:"flex flex-col gap-2 sm:flex-row sm:gap-2",children:[e.jsxs(Ue,{value:u,onValueChange:x,children:[e.jsxs(Re,{className:"w-full sm:flex-1 h-8 text-xs",children:[e.jsx(lo,{className:"h-3.5 w-3.5 mr-1.5"}),e.jsx(Be,{placeholder:"级别"})]}),e.jsxs(Le,{children:[e.jsx(ee,{value:"all",children:"全部级别"}),e.jsx(ee,{value:"DEBUG",children:"DEBUG"}),e.jsx(ee,{value:"INFO",children:"INFO"}),e.jsx(ee,{value:"WARNING",children:"WARNING"}),e.jsx(ee,{value:"ERROR",children:"ERROR"}),e.jsx(ee,{value:"CRITICAL",children:"CRITICAL"})]})]}),e.jsxs(Ue,{value:h,onValueChange:f,children:[e.jsxs(Re,{className:"w-full sm:flex-1 h-8 text-xs",children:[e.jsx(lo,{className:"h-3.5 w-3.5 mr-1.5"}),e.jsx(Be,{placeholder:"模块"})]}),e.jsxs(Le,{children:[e.jsx(ee,{value:"all",children:"全部模块"}),E.map(B=>e.jsx(ee,{value:B,children:B},B))]})]})]}),e.jsxs("div",{className:"flex flex-col gap-2 sm:flex-row sm:gap-2",children:[e.jsxs(Ia,{children:[e.jsx(Qa,{asChild:!0,children:e.jsxs(C,{variant:"outline",size:"sm",className:H("w-full sm:flex-1 justify-start text-left font-normal h-8",!g&&"text-muted-foreground"),children:[e.jsx(hp,{className:"mr-1.5 h-3.5 w-3.5"}),e.jsx("span",{className:"text-xs",children:g?Du(g,"PP",{locale:Zc}):"开始日期"})]})}),e.jsx(La,{className:"w-auto p-0",align:"start",children:e.jsx(Hp,{mode:"single",selected:g,onSelect:j,initialFocus:!0,locale:Zc})})]}),e.jsxs(Ia,{children:[e.jsx(Qa,{asChild:!0,children:e.jsxs(C,{variant:"outline",size:"sm",className:H("w-full sm:flex-1 justify-start text-left font-normal h-8",!v&&"text-muted-foreground"),children:[e.jsx(hp,{className:"mr-1.5 h-3.5 w-3.5"}),e.jsx("span",{className:"text-xs",children:v?Du(v,"PP",{locale:Zc}):"结束日期"})]})}),e.jsx(La,{className:"w-auto p-0",align:"start",children:e.jsx(Hp,{mode:"single",selected:v,onSelect:y,initialFocus:!0,locale:Zc})})]}),(g||v)&&e.jsxs(C,{variant:"outline",size:"sm",onClick:je,className:"w-full sm:w-auto h-8",children:[e.jsx(fl,{className:"h-3.5 w-3.5 sm:mr-1"}),e.jsx("span",{className:"text-xs",children:"清除"})]})]}),e.jsxs("div",{className:"flex flex-col gap-2 sm:flex-row sm:items-center sm:gap-3 pt-2 border-t border-border/50",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsxs("div",{className:"flex items-center gap-1.5 text-xs text-muted-foreground",children:[e.jsx(Xy,{className:"h-3.5 w-3.5"}),e.jsx("span",{children:"字号"})]}),e.jsx("div",{className:"flex gap-1",children:Object.keys(eo).map(B=>e.jsx(C,{variant:A===B?"default":"outline",size:"sm",onClick:()=>D(B),className:"h-6 px-2 text-xs",children:eo[B].label},B))})]}),e.jsxs("div",{className:"flex items-center gap-2 flex-1 max-w-[200px]",children:[e.jsx("span",{className:"text-xs text-muted-foreground whitespace-nowrap",children:"行距"}),e.jsx(ma,{value:[V],onValueChange:([B])=>z(B),min:0,max:12,step:2,className:"flex-1"}),e.jsxs("span",{className:"text-xs text-muted-foreground w-7",children:[V,"px"]})]}),e.jsxs("div",{className:"flex gap-2 sm:hidden",children:[e.jsxs(C,{variant:"outline",size:"sm",onClick:ne,className:"flex-1 h-8",children:[e.jsx(At,{className:"h-3.5 w-3.5 mr-1"}),e.jsx("span",{className:"text-xs",children:"刷新"})]}),e.jsxs(C,{variant:"outline",size:"sm",onClick:Se,className:"flex-1 h-8",children:[e.jsx(Da,{className:"h-3.5 w-3.5 mr-1"}),e.jsx("span",{className:"text-xs",children:"导出"})]})]})]})]})]})})})]}),e.jsx("div",{className:"flex-1 min-h-0 px-2 sm:px-3 lg:px-4 pb-2 sm:pb-3 lg:pb-4",children:e.jsx(Ve,{className:"bg-black dark:bg-gray-950 border-gray-800 dark:border-gray-900 h-full overflow-hidden",children:e.jsx("div",{ref:$,className:H("h-full overflow-auto","[&::-webkit-scrollbar]:w-2.5","[&::-webkit-scrollbar-track]:bg-transparent","[&::-webkit-scrollbar-thumb]:bg-border [&::-webkit-scrollbar-thumb]:rounded-full","[&::-webkit-scrollbar-thumb:hover]:bg-border/80"),children:e.jsx("div",{className:H("p-2 sm:p-3 font-mono relative",eo[A].class),style:{height:`${P.getTotalSize()}px`},children:be.length===0?e.jsx("div",{className:"text-gray-500 dark:text-gray-600 text-center py-8 text-xs sm:text-sm",children:"暂无日志数据"}):P.getVirtualItems().map(B=>{const _e=be[B.index];return e.jsxs("div",{"data-index":B.index,ref:P.measureElement,className:H("absolute top-0 left-0 w-full px-2 sm:px-3 rounded hover:bg-white/5 transition-colors",te(_e.level)),style:{transform:`translateY(${B.start}px)`,paddingTop:`${V/2}px`,paddingBottom:`${V/2}px`},children:[e.jsxs("div",{className:"flex flex-col gap-0.5 sm:hidden",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:"text-gray-500 dark:text-gray-600 text-[10px]",children:_e.timestamp}),e.jsxs("span",{className:H("font-semibold text-[10px]",se(_e.level)),children:["[",_e.level,"]"]})]}),e.jsx("div",{className:"text-cyan-400 dark:text-cyan-500 truncate text-[10px]",children:_e.module}),e.jsx("div",{className:"text-gray-300 dark:text-gray-400 whitespace-pre-wrap break-words text-[10px]",children:_e.message})]}),e.jsxs("div",{className:"hidden sm:flex gap-2 items-start",children:[e.jsx("span",{className:"text-gray-500 dark:text-gray-600 flex-shrink-0 w-[130px] lg:w-[160px]",children:_e.timestamp}),e.jsxs("span",{className:H("flex-shrink-0 w-[65px] lg:w-[75px] font-semibold",se(_e.level)),children:["[",_e.level,"]"]}),e.jsx("span",{className:"text-cyan-400 dark:text-cyan-500 flex-shrink-0 w-[100px] lg:w-[130px] truncate",children:_e.module}),e.jsx("span",{className:"text-gray-300 dark:text-gray-400 flex-1 whitespace-pre-wrap break-words",children:_e.message})]})]},B.key)})})})})})]})}const D_="Mai-with-u",R_="plugin-repo",L_="main",U_="plugin_details.json";async function B_(){try{const l=await we("/api/webui/plugins/fetch-raw",{method:"POST",body:JSON.stringify({owner:D_,repo:R_,branch:L_,file_path:U_})});if(!l.ok)throw new Error(`HTTP error! status: ${l.status}`);const i=await l.json();if(!i.success||!i.data)throw new Error(i.error||"获取插件列表失败");return JSON.parse(i.data).filter(u=>!u?.id||!u?.manifest?(console.warn("跳过无效插件数据:",u),!1):!u.manifest.name||!u.manifest.version?(console.warn("跳过缺少必需字段的插件:",u.id),!1):!0).map(u=>({id:u.id,manifest:{manifest_version:u.manifest.manifest_version||1,name:u.manifest.name,version:u.manifest.version,description:u.manifest.description||"",author:u.manifest.author||{name:"Unknown"},license:u.manifest.license||"Unknown",host_application:u.manifest.host_application||{min_version:"0.0.0"},homepage_url:u.manifest.homepage_url,repository_url:u.manifest.repository_url,keywords:u.manifest.keywords||[],categories:u.manifest.categories||[],default_locale:u.manifest.default_locale||"zh-CN",locales_path:u.manifest.locales_path},downloads:0,rating:0,review_count:0,installed:!1,published_at:new Date().toISOString(),updated_at:new Date().toISOString()}))}catch(l){throw console.error("Failed to fetch plugin list:",l),l}}async function H_(){try{const l=await we("/api/webui/plugins/git-status");if(!l.ok)throw new Error(`HTTP error! status: ${l.status}`);return await l.json()}catch(l){return console.error("Failed to check Git status:",l),{installed:!1,error:"无法检测 Git 安装状态"}}}async function $_(){try{const l=await we("/api/webui/plugins/version");if(!l.ok)throw new Error(`HTTP error! status: ${l.status}`);return await l.json()}catch(l){return console.error("Failed to get Maimai version:",l),{version:"0.0.0",version_major:0,version_minor:0,version_patch:0}}}function q_(l,i,r){const o=l.split(".").map(f=>parseInt(f)||0),u=o[0]||0,x=o[1]||0,h=o[2]||0;if(r.version_majorparseInt(y)||0),g=f[0]||0,j=f[1]||0,v=f[2]||0;if(r.version_major>g||r.version_major===g&&r.version_minor>j||r.version_major===g&&r.version_minor===j&&r.version_patch>v)return!1}return!0}async function G_(){try{const l=await we("/api/webui/ws-token");if(!l.ok)return console.error("获取 WebSocket token 失败:",l.status),null;const i=await l.json();return i.success&&i.token?i.token:null}catch(l){return console.error("获取 WebSocket token 失败:",l),null}}async function V_(l,i){const r=await G_(),o=window.location.protocol==="https:"?"wss:":"ws:",u=window.location.host;let x=`${o}//${u}/api/webui/ws/plugin-progress`;r&&(x+=`?token=${encodeURIComponent(r)}`);try{const h=new WebSocket(x);return h.onopen=()=>{console.log("Plugin progress WebSocket connected");const f=setInterval(()=>{h.readyState===WebSocket.OPEN?h.send("ping"):clearInterval(f)},3e4)},h.onmessage=f=>{try{if(f.data==="pong")return;const g=JSON.parse(f.data);l(g)}catch(g){console.error("Failed to parse progress data:",g)}},h.onerror=f=>{console.error("Plugin progress WebSocket error:",f),i?.(f)},h.onclose=()=>{console.log("Plugin progress WebSocket disconnected")},h}catch(h){return console.error("创建 WebSocket 连接失败:",h),null}}async function gr(){try{const l=await we("/api/webui/plugins/installed",{headers:Is()});if(!l.ok)throw new Error(`HTTP error! status: ${l.status}`);const i=await l.json();if(!i.success)throw new Error(i.message||"获取已安装插件列表失败");return i.plugins||[]}catch(l){return console.error("Failed to get installed plugins:",l),[]}}function so(l,i){return i.some(r=>r.id===l)}function to(l,i){const r=i.find(o=>o.id===l);if(r)return r.manifest?.version||r.version}async function F_(l,i,r="main"){const o=await we("/api/webui/plugins/install",{method:"POST",body:JSON.stringify({plugin_id:l,repository_url:i,branch:r})});if(!o.ok){const u=await o.json();throw new Error(u.detail||"安装失败")}return await o.json()}async function I_(l){const i=await we("/api/webui/plugins/uninstall",{method:"POST",body:JSON.stringify({plugin_id:l})});if(!i.ok){const r=await i.json();throw new Error(r.detail||"卸载失败")}return await i.json()}async function Q_(l,i,r="main"){const o=await we("/api/webui/plugins/update",{method:"POST",body:JSON.stringify({plugin_id:l,repository_url:i,branch:r})});if(!o.ok){const u=await o.json();throw new Error(u.detail||"更新失败")}return await o.json()}async function Y_(l){const i=await we(`/api/webui/plugins/config/${l}/schema`,{headers:Is()});if(!i.ok){const o=await i.json();throw new Error(o.detail||"获取配置 Schema 失败")}const r=await i.json();if(!r.success)throw new Error(r.message||"获取配置 Schema 失败");return r.schema}async function K_(l){const i=await we(`/api/webui/plugins/config/${l}`,{headers:Is()});if(!i.ok){const o=await i.json();throw new Error(o.detail||"获取配置失败")}const r=await i.json();if(!r.success)throw new Error(r.message||"获取配置失败");return r.config}async function X_(l,i){const r=await we(`/api/webui/plugins/config/${l}`,{method:"PUT",body:JSON.stringify({config:i})});if(!r.ok){const o=await r.json();throw new Error(o.detail||"保存配置失败")}return await r.json()}async function P_(l){const i=await we(`/api/webui/plugins/config/${l}/reset`,{method:"POST",headers:Is()});if(!i.ok){const r=await i.json();throw new Error(r.detail||"重置配置失败")}return await i.json()}async function J_(l){const i=await we(`/api/webui/plugins/config/${l}/toggle`,{method:"POST",headers:Is()});if(!i.ok){const r=await i.json();throw new Error(r.detail||"切换状态失败")}return await i.json()}const Dr="https://maibot-plugin-stats.maibot-webui.workers.dev";async function Mj(l){try{const i=await fetch(`${Dr}/stats/${l}`);return i.ok?await i.json():(console.error("Failed to fetch plugin stats:",i.statusText),null)}catch(i){return console.error("Error fetching plugin stats:",i),null}}async function Z_(l,i){try{const r=i||bm(),o=await fetch(`${Dr}/stats/like`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({plugin_id:l,user_id:r})}),u=await o.json();return o.status===429?{success:!1,error:"操作过于频繁,请稍后再试"}:o.ok?{success:!0,...u}:{success:!1,error:u.error||"点赞失败"}}catch(r){return console.error("Error liking plugin:",r),{success:!1,error:"网络错误"}}}async function W_(l,i){try{const r=i||bm(),o=await fetch(`${Dr}/stats/dislike`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({plugin_id:l,user_id:r})}),u=await o.json();return o.status===429?{success:!1,error:"操作过于频繁,请稍后再试"}:o.ok?{success:!0,...u}:{success:!1,error:u.error||"点踩失败"}}catch(r){return console.error("Error disliking plugin:",r),{success:!1,error:"网络错误"}}}async function eS(l,i,r,o){if(i<1||i>5)return{success:!1,error:"评分必须在 1-5 之间"};try{const u=o||bm(),x=await fetch(`${Dr}/stats/rate`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({plugin_id:l,rating:i,comment:r,user_id:u})}),h=await x.json();return x.status===429?{success:!1,error:"每天最多评分 3 次"}:x.ok?{success:!0,...h}:{success:!1,error:h.error||"评分失败"}}catch(u){return console.error("Error rating plugin:",u),{success:!1,error:"网络错误"}}}async function sS(l){try{const i=await fetch(`${Dr}/stats/download`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({plugin_id:l})}),r=await i.json();return i.status===429?(console.warn("Download recording rate limited"),{success:!0}):i.ok?{success:!0,...r}:(console.error("Failed to record download:",r.error),{success:!1,error:r.error})}catch(i){return console.error("Error recording download:",i),{success:!1,error:"网络错误"}}}function tS(){const l=navigator,i=[navigator.userAgent,navigator.language,navigator.languages?.join(",")||"",navigator.platform,navigator.hardwareConcurrency||0,screen.width,screen.height,screen.colorDepth,screen.pixelDepth,new Date().getTimezoneOffset(),Intl.DateTimeFormat().resolvedOptions().timeZone,navigator.maxTouchPoints||0,l.deviceMemory||0].join("|");let r=0;for(let o=0;o{x(!0);const D=await Mj(l);D&&o(D),x(!1)};m.useEffect(()=>{S()},[l]);const w=async()=>{const D=await Z_(l);D.success?(b({title:"已点赞",description:"感谢你的支持!"}),S()):b({title:"点赞失败",description:D.error||"未知错误",variant:"destructive"})},O=async()=>{const D=await W_(l);D.success?(b({title:"已反馈",description:"感谢你的反馈!"}),S()):b({title:"操作失败",description:D.error||"未知错误",variant:"destructive"})},A=async()=>{if(h===0){b({title:"请选择评分",description:"至少选择 1 颗星",variant:"destructive"});return}const D=await eS(l,h,g||void 0);D.success?(b({title:"评分成功",description:"感谢你的评价!"}),y(!1),f(0),j(""),S()):b({title:"评分失败",description:D.error||"未知错误",variant:"destructive"})};return u?e.jsxs("div",{className:"flex items-center gap-4 text-sm text-muted-foreground",children:[e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx(Da,{className:"h-4 w-4"}),e.jsx("span",{children:"-"})]}),e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx(xl,{className:"h-4 w-4"}),e.jsx("span",{children:"-"})]})]}):r?i?e.jsxs("div",{className:"flex items-center gap-4 text-sm text-muted-foreground",children:[e.jsxs("div",{className:"flex items-center gap-1",title:`下载量: ${r.downloads.toLocaleString()}`,children:[e.jsx(Da,{className:"h-4 w-4"}),e.jsx("span",{children:r.downloads.toLocaleString()})]}),e.jsxs("div",{className:"flex items-center gap-1",title:`评分: ${r.rating.toFixed(1)} (${r.rating_count} 条评价)`,children:[e.jsx(xl,{className:"h-4 w-4 fill-yellow-400 text-yellow-400"}),e.jsx("span",{children:r.rating.toFixed(1)})]}),e.jsxs("div",{className:"flex items-center gap-1",title:`点赞数: ${r.likes}`,children:[e.jsx(Lu,{className:"h-4 w-4"}),e.jsx("span",{children:r.likes})]})]}):e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"grid grid-cols-2 sm:grid-cols-4 gap-4",children:[e.jsxs("div",{className:"flex flex-col items-center p-3 rounded-lg border bg-card",children:[e.jsx(Da,{className:"h-5 w-5 text-muted-foreground mb-1"}),e.jsx("span",{className:"text-2xl font-bold",children:r.downloads.toLocaleString()}),e.jsx("span",{className:"text-xs text-muted-foreground",children:"下载量"})]}),e.jsxs("div",{className:"flex flex-col items-center p-3 rounded-lg border bg-card",children:[e.jsx(xl,{className:"h-5 w-5 text-yellow-400 mb-1 fill-yellow-400"}),e.jsx("span",{className:"text-2xl font-bold",children:r.rating.toFixed(1)}),e.jsxs("span",{className:"text-xs text-muted-foreground",children:[r.rating_count," 条评价"]})]}),e.jsxs("div",{className:"flex flex-col items-center p-3 rounded-lg border bg-card",children:[e.jsx(Lu,{className:"h-5 w-5 text-green-500 mb-1"}),e.jsx("span",{className:"text-2xl font-bold",children:r.likes}),e.jsx("span",{className:"text-xs text-muted-foreground",children:"点赞"})]}),e.jsxs("div",{className:"flex flex-col items-center p-3 rounded-lg border bg-card",children:[e.jsx(fp,{className:"h-5 w-5 text-red-500 mb-1"}),e.jsx("span",{className:"text-2xl font-bold",children:r.dislikes}),e.jsx("span",{className:"text-xs text-muted-foreground",children:"点踩"})]})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsxs(C,{variant:"outline",size:"sm",onClick:w,children:[e.jsx(Lu,{className:"h-4 w-4 mr-1"}),"点赞"]}),e.jsxs(C,{variant:"outline",size:"sm",onClick:O,children:[e.jsx(fp,{className:"h-4 w-4 mr-1"}),"点踩"]}),e.jsxs(Qs,{open:v,onOpenChange:y,children:[e.jsx(mm,{asChild:!0,children:e.jsxs(C,{variant:"default",size:"sm",children:[e.jsx(xl,{className:"h-4 w-4 mr-1"}),"评分"]})}),e.jsxs(qs,{children:[e.jsxs(Gs,{children:[e.jsx(Vs,{children:"为插件评分"}),e.jsx(Ws,{children:"分享你的使用体验,帮助其他用户"})]}),e.jsxs("div",{className:"space-y-4 py-4",children:[e.jsxs("div",{className:"flex flex-col items-center gap-2",children:[e.jsx("div",{className:"flex gap-2",children:[1,2,3,4,5].map(D=>e.jsx("button",{onClick:()=>f(D),className:"focus:outline-none",children:e.jsx(xl,{className:`h-8 w-8 transition-colors ${D<=h?"fill-yellow-400 text-yellow-400":"text-muted-foreground hover:text-yellow-300"}`})},D))}),e.jsxs("span",{className:"text-sm text-muted-foreground",children:[h===0&&"点击星星进行评分",h===1&&"很差",h===2&&"一般",h===3&&"还行",h===4&&"不错",h===5&&"非常好"]})]}),e.jsxs("div",{children:[e.jsx("label",{className:"text-sm font-medium mb-2 block",children:"评论(可选)"}),e.jsx(Ys,{value:g,onChange:D=>j(D.target.value),placeholder:"分享你的使用体验...",rows:4,maxLength:500}),e.jsxs("div",{className:"text-xs text-muted-foreground mt-1 text-right",children:[g.length," / 500"]})]})]}),e.jsxs(at,{children:[e.jsx(C,{variant:"outline",onClick:()=>y(!1),children:"取消"}),e.jsx(C,{onClick:A,disabled:h===0,children:"提交评分"})]})]})]})]}),r.recent_ratings&&r.recent_ratings.length>0&&e.jsxs("div",{className:"space-y-2",children:[e.jsx("h4",{className:"text-sm font-semibold",children:"最近评价"}),e.jsx("div",{className:"space-y-3",children:r.recent_ratings.map((D,V)=>e.jsxs("div",{className:"p-3 rounded-lg border bg-muted/50",children:[e.jsxs("div",{className:"flex items-center justify-between mb-2",children:[e.jsx("div",{className:"flex gap-1",children:[1,2,3,4,5].map(z=>e.jsx(xl,{className:`h-3 w-3 ${z<=D.rating?"fill-yellow-400 text-yellow-400":"text-muted-foreground"}`},z))}),e.jsx("span",{className:"text-xs text-muted-foreground",children:new Date(D.created_at).toLocaleDateString()})]}),D.comment&&e.jsx("p",{className:"text-sm text-muted-foreground",children:D.comment})]},V))})]})]}):null}const $p={"Group Management":"群组管理","Entertainment & Interaction":"娱乐互动","Utility Tools":"实用工具","Content Generation":"内容生成",Multimedia:"多媒体","External Integration":"外部集成","Data Analysis & Insights":"数据分析与洞察",Other:"其他"};function lS(){return e.jsx(jn,{children:e.jsx(nS,{})})}function nS(){const l=ka(),{triggerRestart:i,isRestarting:r}=Il(),[o,u]=m.useState(null),[x,h]=m.useState(""),[f,g]=m.useState("all"),[j,v]=m.useState("all"),[y,b]=m.useState(!0),[S,w]=m.useState([]),[O,A]=m.useState(!0),[D,V]=m.useState(null),[z,_]=m.useState(null),[T,$]=m.useState(null),[E,se]=m.useState(null),[,te]=m.useState([]),[ne,ue]=m.useState({}),[Se,oe]=m.useState(!1),[je,be]=m.useState(null),[U,P]=m.useState("main"),[X,L]=m.useState(""),[B,_e]=m.useState("preset"),[Ne,Ce]=m.useState(!1),{toast:ve}=Ks(),ze=async G=>{const Me=G.map(async Ee=>{try{const Ie=await Mj(Ee.id);return{id:Ee.id,stats:Ie}}catch(Ie){return console.warn(`Failed to load stats for ${Ee.id}:`,Ie),{id:Ee.id,stats:null}}}),re=await Promise.all(Me),pe={};re.forEach(({id:Ee,stats:Ie})=>{Ie&&(pe[Ee]=Ie)}),ue(pe)};m.useEffect(()=>{let G=null,Me=!1;return(async()=>{if(G=await V_(pe=>{Me||($(pe),pe.stage==="success"?setTimeout(()=>{Me||$(null)},2e3):pe.stage==="error"&&(A(!1),V(pe.error||"加载失败")))},pe=>{console.error("WebSocket error:",pe),Me||ve({title:"WebSocket 连接失败",description:"无法实时显示加载进度",variant:"destructive"})}),await new Promise(pe=>{if(!G){pe();return}const Ee=()=>{G&&G.readyState===WebSocket.OPEN?(console.log("WebSocket connected, starting to load plugins"),pe()):G&&G.readyState===WebSocket.CLOSED?(console.warn("WebSocket closed before loading plugins"),pe()):setTimeout(Ee,100)};Ee()}),!Me){const pe=await H_();_(pe),pe.installed||ve({title:"Git 未安装",description:pe.error||"请先安装 Git 才能使用插件安装功能",variant:"destructive"})}if(!Me){const pe=await $_();se(pe)}if(!Me)try{A(!0),V(null);const pe=await B_();if(!Me){const Ee=await gr();te(Ee);const Ie=pe.map($e=>{const Vt=so($e.id,Ee),_t=to($e.id,Ee);return{...$e,installed:Vt,installed_version:_t}});for(const $e of Ee)!Ie.some(_t=>_t.id===$e.id)&&$e.manifest&&Ie.push({id:$e.id,manifest:{manifest_version:$e.manifest.manifest_version||1,name:$e.manifest.name,version:$e.manifest.version,description:$e.manifest.description||"",author:$e.manifest.author,license:$e.manifest.license||"Unknown",host_application:$e.manifest.host_application,homepage_url:$e.manifest.homepage_url,repository_url:$e.manifest.repository_url,keywords:$e.manifest.keywords||[],categories:$e.manifest.categories||[],default_locale:$e.manifest.default_locale||"zh-CN",locales_path:$e.manifest.locales_path},downloads:0,rating:0,review_count:0,installed:!0,installed_version:$e.manifest.version,published_at:new Date().toISOString(),updated_at:new Date().toISOString()});w(Ie),ze(Ie)}}catch(pe){if(!Me){const Ee=pe instanceof Error?pe.message:"加载插件列表失败";V(Ee),ve({title:"加载失败",description:Ee,variant:"destructive"})}}finally{Me||A(!1)}})(),()=>{Me=!0,G&&G.close()}},[ve]);const Q=G=>{if(!G.installed&&E&&!xe(G))return e.jsxs(Ye,{variant:"destructive",className:"gap-1",children:[e.jsx(Ot,{className:"h-3 w-3"}),"不兼容"]});if(G.installed){const Me=G.installed_version?.trim(),re=G.manifest.version?.trim();if(Me!==re){const pe=Me?.split(".").map(Number)||[0,0,0],Ee=re?.split(".").map(Number)||[0,0,0];for(let Ie=0;Ie<3;Ie++){if((Ee[Ie]||0)>(pe[Ie]||0))return e.jsxs(Ye,{variant:"outline",className:"gap-1 text-orange-600 border-orange-600",children:[e.jsx(Ot,{className:"h-3 w-3"}),"可更新"]});if((Ee[Ie]||0)<(pe[Ie]||0))break}}return e.jsxs(Ye,{variant:"default",className:"gap-1",children:[e.jsx(aa,{className:"h-3 w-3"}),"已安装"]})}return null},xe=G=>!E||!G.manifest?.host_application?!0:q_(G.manifest.host_application.min_version,G.manifest.host_application.max_version,E),Te=G=>{if(!G.installed||!G.installed_version||!G.manifest?.version)return!1;const Me=G.installed_version.trim(),re=G.manifest.version.trim();if(Me===re)return!1;const pe=Me.split(".").map(Number),Ee=re.split(".").map(Number);for(let Ie=0;Ie<3;Ie++){if((Ee[Ie]||0)>(pe[Ie]||0))return!0;if((Ee[Ie]||0)<(pe[Ie]||0))return!1}return!1},J=S.filter(G=>{if(!G.manifest)return console.warn("[过滤] 跳过无 manifest 的插件:",G.id),!1;const Me=x===""||G.manifest.name?.toLowerCase().includes(x.toLowerCase())||G.manifest.description?.toLowerCase().includes(x.toLowerCase())||G.manifest.keywords&&G.manifest.keywords.some(Ie=>Ie.toLowerCase().includes(x.toLowerCase())),re=f==="all"||G.manifest.categories&&G.manifest.categories.includes(f);let pe=!0;j==="installed"?pe=G.installed===!0:j==="updates"&&(pe=G.installed===!0&&Te(G));const Ee=!y||!E||xe(G);return Me&&re&&pe&&Ee}),le=()=>{u(null)},qe=G=>{if(!z?.installed){ve({title:"无法安装",description:"Git 未安装",variant:"destructive"});return}if(E&&!xe(G)){ve({title:"无法安装",description:"插件与当前麦麦版本不兼容",variant:"destructive"});return}be(G),P("main"),L(""),_e("preset"),Ce(!1),oe(!0)},We=async()=>{if(!je)return;const G=B==="custom"?X:U;if(!G||G.trim()===""){ve({title:"分支名称不能为空",variant:"destructive"});return}try{oe(!1),await F_(je.id,je.manifest.repository_url||"",G),sS(je.id).catch(re=>{console.warn("Failed to record download:",re)}),ve({title:"安装成功",description:`${je.manifest.name} 已成功安装`});const Me=await gr();te(Me),w(re=>re.map(pe=>{if(pe.id===je.id){const Ee=so(pe.id,Me),Ie=to(pe.id,Me);return{...pe,installed:Ee,installed_version:Ie}}return pe}))}catch(Me){ve({title:"安装失败",description:Me instanceof Error?Me.message:"未知错误",variant:"destructive"})}finally{be(null)}},fe=async G=>{try{await I_(G.id),ve({title:"卸载成功",description:`${G.manifest.name} 已成功卸载`});const Me=await gr();te(Me),w(re=>re.map(pe=>{if(pe.id===G.id){const Ee=so(pe.id,Me),Ie=to(pe.id,Me);return{...pe,installed:Ee,installed_version:Ie}}return pe}))}catch(Me){ve({title:"卸载失败",description:Me instanceof Error?Me.message:"未知错误",variant:"destructive"})}},ls=async G=>{if(!z?.installed){ve({title:"无法更新",description:"Git 未安装",variant:"destructive"});return}try{const Me=await Q_(G.id,G.manifest.repository_url||"","main");ve({title:"更新成功",description:`${G.manifest.name} 已从 ${Me.old_version} 更新到 ${Me.new_version}`});const re=await gr();te(re),w(pe=>pe.map(Ee=>{if(Ee.id===G.id){const Ie=so(Ee.id,re),$e=to(Ee.id,re);return{...Ee,installed:Ie,installed_version:$e}}return Ee}))}catch(Me){ve({title:"更新失败",description:Me instanceof Error?Me.message:"未知错误",variant:"destructive"})}};return e.jsx(Ze,{className:"h-full",children:e.jsxs("div",{className:"space-y-6 p-4 sm:p-6",children:[e.jsxs("div",{className:"flex flex-col sm:flex-row sm:items-start sm:justify-between gap-4",children:[e.jsxs("div",{children:[e.jsx("h1",{className:"text-2xl sm:text-3xl font-bold",children:"插件市场"}),e.jsx("p",{className:"text-muted-foreground mt-2",children:"浏览和管理麦麦的插件"})]}),e.jsxs("div",{className:"flex gap-2",children:[e.jsxs(C,{variant:"outline",onClick:()=>i(),disabled:r,children:[e.jsx(Hg,{className:`h-4 w-4 mr-2 ${r?"animate-spin":""}`}),"重启麦麦"]}),e.jsxs(C,{onClick:()=>l({to:"/plugin-mirrors"}),children:[e.jsx(Py,{className:"h-4 w-4 mr-2"}),"配置镜像源"]})]})]}),e.jsx(Ve,{className:"border-blue-200 bg-blue-50 dark:bg-blue-950/20 dark:border-blue-900",children:e.jsx(gs,{className:"py-3",children:e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(Ra,{className:"h-4 w-4 text-blue-600 flex-shrink-0"}),e.jsxs("p",{className:"text-sm text-blue-800 dark:text-blue-200",children:["安装、卸载或更新插件后,需要",e.jsx("span",{className:"font-semibold",children:"重启麦麦"}),"才能使更改生效"]})]})})}),z&&!z.installed&&e.jsxs(Ve,{className:"border-orange-600 bg-orange-50 dark:bg-orange-950/20",children:[e.jsx(rs,{children:e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx(Oa,{className:"h-5 w-5 text-orange-600"}),e.jsxs("div",{children:[e.jsx(cs,{className:"text-lg text-orange-900 dark:text-orange-100",children:"Git 未安装"}),e.jsx(st,{className:"text-orange-800 dark:text-orange-200",children:z.error||"请先安装 Git 才能使用插件安装功能"})]})]})}),e.jsx(gs,{children:e.jsxs("p",{className:"text-sm text-orange-800 dark:text-orange-200",children:["您可以从 ",e.jsx("a",{href:"https://git-scm.com/downloads",target:"_blank",rel:"noopener noreferrer",className:"underline font-medium",children:"git-scm.com"})," 下载并安装 Git。 安装完成后,请重启麦麦应用。"]})})]}),e.jsx(Ve,{className:"p-4",children:e.jsxs("div",{className:"flex flex-col gap-4",children:[e.jsxs("div",{className:"flex flex-col sm:flex-row gap-4",children:[e.jsxs("div",{className:"flex-1 relative",children:[e.jsx($t,{className:"absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground"}),e.jsx(ie,{placeholder:"搜索插件...",value:x,onChange:G=>h(G.target.value),className:"pl-9"})]}),e.jsxs(Ue,{value:f,onValueChange:g,children:[e.jsx(Re,{className:"w-full sm:w-[200px]",children:e.jsx(Be,{placeholder:"选择分类"})}),e.jsxs(Le,{children:[e.jsx(ee,{value:"all",children:"全部分类"}),e.jsx(ee,{value:"Group Management",children:"群组管理"}),e.jsx(ee,{value:"Entertainment & Interaction",children:"娱乐互动"}),e.jsx(ee,{value:"Utility Tools",children:"实用工具"}),e.jsx(ee,{value:"Content Generation",children:"内容生成"}),e.jsx(ee,{value:"Multimedia",children:"多媒体"}),e.jsx(ee,{value:"External Integration",children:"外部集成"}),e.jsx(ee,{value:"Data Analysis & Insights",children:"数据分析与洞察"}),e.jsx(ee,{value:"Other",children:"其他"})]})]})]}),e.jsxs("div",{className:"flex items-center space-x-2",children:[e.jsx(jt,{id:"compatible-only",checked:y,onCheckedChange:G=>b(G===!0)}),e.jsx("label",{htmlFor:"compatible-only",className:"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70 cursor-pointer",children:"只显示兼容当前版本的插件"})]})]})}),e.jsx(Sa,{value:j,onValueChange:v,className:"w-full",children:e.jsxs(xa,{className:"grid w-full grid-cols-3",children:[e.jsxs(is,{value:"all",children:["全部插件 (",S.filter(G=>{if(!G.manifest)return!1;const Me=x===""||G.manifest.name?.toLowerCase().includes(x.toLowerCase())||G.manifest.description?.toLowerCase().includes(x.toLowerCase())||G.manifest.keywords&&G.manifest.keywords.some(Ee=>Ee.toLowerCase().includes(x.toLowerCase())),re=f==="all"||G.manifest.categories&&G.manifest.categories.includes(f),pe=!y||!E||xe(G);return Me&&re&&pe}).length,")"]}),e.jsxs(is,{value:"installed",children:["已安装 (",S.filter(G=>{if(!G.manifest)return!1;const Me=x===""||G.manifest.name?.toLowerCase().includes(x.toLowerCase())||G.manifest.description?.toLowerCase().includes(x.toLowerCase())||G.manifest.keywords&&G.manifest.keywords.some(Ee=>Ee.toLowerCase().includes(x.toLowerCase())),re=f==="all"||G.manifest.categories&&G.manifest.categories.includes(f),pe=!y||!E||xe(G);return G.installed&&Me&&re&&pe}).length,")"]}),e.jsxs(is,{value:"updates",children:["可更新 (",S.filter(G=>{if(!G.manifest)return!1;const Me=x===""||G.manifest.name?.toLowerCase().includes(x.toLowerCase())||G.manifest.description?.toLowerCase().includes(x.toLowerCase())||G.manifest.keywords&&G.manifest.keywords.some(Ee=>Ee.toLowerCase().includes(x.toLowerCase())),re=f==="all"||G.manifest.categories&&G.manifest.categories.includes(f),pe=!y||!E||xe(G);return G.installed&&Te(G)&&Me&&re&&pe}).length,")"]})]})}),T&&T.stage==="loading"&&T.operation==="fetch"&&e.jsx(Ve,{className:"p-4",children:e.jsxs("div",{className:"space-y-3",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(tt,{className:"h-4 w-4 animate-spin"}),e.jsx("span",{className:"text-sm font-medium",children:"加载插件列表"})]}),e.jsxs("span",{className:"text-sm font-medium",children:[T.progress,"%"]})]}),e.jsx(gn,{value:T.progress,className:"h-2"}),e.jsx("div",{className:"text-xs text-muted-foreground",children:T.message}),T.total_plugins>0&&e.jsxs("div",{className:"text-xs text-muted-foreground text-center",children:["已加载 ",T.loaded_plugins," / ",T.total_plugins," 个插件"]})]})}),T&&T.stage==="error"&&T.error&&e.jsx(Ve,{className:"border-destructive bg-destructive/10",children:e.jsx(rs,{children:e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx(Oa,{className:"h-5 w-5 text-destructive"}),e.jsxs("div",{children:[e.jsx(cs,{className:"text-lg text-destructive",children:"加载失败"}),e.jsx(st,{className:"text-destructive/80",children:T.error})]})]})})}),O?e.jsxs("div",{className:"flex items-center justify-center py-12",children:[e.jsx(tt,{className:"h-8 w-8 animate-spin text-muted-foreground"}),e.jsx("span",{className:"ml-3 text-muted-foreground",children:"加载插件列表中..."})]}):D?e.jsx(Ve,{className:"p-6",children:e.jsxs("div",{className:"flex flex-col items-center justify-center py-8 text-center",children:[e.jsx(Oa,{className:"h-12 w-12 text-destructive mb-4"}),e.jsx("h3",{className:"text-lg font-semibold mb-2",children:"加载失败"}),e.jsx("p",{className:"text-sm text-muted-foreground mb-4",children:D}),e.jsx(C,{onClick:()=>window.location.reload(),children:"重新加载"})]})}):J.length===0?e.jsx(Ve,{className:"p-6",children:e.jsxs("div",{className:"flex flex-col items-center justify-center py-8 text-center",children:[e.jsx($t,{className:"h-12 w-12 text-muted-foreground mb-4"}),e.jsx("h3",{className:"text-lg font-semibold mb-2",children:"未找到插件"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:x||f!=="all"?"尝试调整搜索条件或筛选器":"暂无可用插件"})]})}):e.jsx("div",{className:"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6",children:J.map(G=>e.jsxs(Ve,{className:"flex flex-col hover:shadow-lg transition-shadow h-full",children:[e.jsxs(rs,{children:[e.jsxs("div",{className:"flex items-start justify-between gap-2",children:[e.jsx(cs,{className:"text-xl",children:G.manifest?.name||G.id}),e.jsxs("div",{className:"flex flex-col gap-1",children:[G.manifest?.categories&&G.manifest.categories[0]&&e.jsx(Ye,{variant:"secondary",className:"text-xs whitespace-nowrap",children:$p[G.manifest.categories[0]]||G.manifest.categories[0]}),Q(G)]})]}),e.jsx(st,{className:"line-clamp-2",children:G.manifest?.description||"无描述"})]}),e.jsx(gs,{className:"flex-1",children:e.jsxs("div",{className:"space-y-3",children:[e.jsxs("div",{className:"flex items-center gap-4 text-sm text-muted-foreground",children:[e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx(Da,{className:"h-4 w-4"}),e.jsx("span",{children:(ne[G.id]?.downloads??G.downloads??0).toLocaleString()})]}),e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx(xl,{className:"h-4 w-4 fill-yellow-400 text-yellow-400"}),e.jsx("span",{children:(ne[G.id]?.rating??G.rating??0).toFixed(1)})]})]}),e.jsxs("div",{className:"flex flex-wrap gap-2",children:[G.manifest?.keywords&&G.manifest.keywords.slice(0,3).map(Me=>e.jsx(Ye,{variant:"outline",className:"text-xs",children:Me},Me)),G.manifest?.keywords&&G.manifest.keywords.length>3&&e.jsxs(Ye,{variant:"outline",className:"text-xs",children:["+",G.manifest.keywords.length-3]})]}),e.jsxs("div",{className:"text-xs text-muted-foreground pt-2 border-t space-y-1",children:[e.jsxs("div",{children:["v",G.manifest?.version||"unknown"," · ",G.manifest?.author?.name||"Unknown"]}),G.manifest?.host_application&&e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx("span",{children:"支持:"}),e.jsxs("span",{className:"font-medium",children:[G.manifest.host_application.min_version,G.manifest.host_application.max_version?` - ${G.manifest.host_application.max_version}`:" - 最新版本"]})]})]})]})}),e.jsx(tj,{className:"pt-4",children:e.jsxs("div",{className:"flex items-center justify-end gap-2 w-full",children:[e.jsx(C,{variant:"outline",size:"sm",onClick:()=>u(G),children:"查看详情"}),G.installed?Te(G)?e.jsxs(C,{size:"sm",disabled:!z?.installed,title:z?.installed?void 0:"Git 未安装",onClick:()=>ls(G),children:[e.jsx(At,{className:"h-4 w-4 mr-1"}),"更新"]}):e.jsxs(C,{variant:"destructive",size:"sm",disabled:!z?.installed,title:z?.installed?void 0:"Git 未安装",onClick:()=>fe(G),children:[e.jsx(es,{className:"h-4 w-4 mr-1"}),"卸载"]}):e.jsxs(C,{size:"sm",disabled:!z?.installed||T?.operation==="install"||E!==null&&!xe(G),title:z?.installed?E!==null&&!xe(G)?`不兼容当前版本 (需要 ${G.manifest?.host_application?.min_version||"未知"}${G.manifest?.host_application?.max_version?` - ${G.manifest.host_application.max_version}`:"+"},当前 ${E?.version})`:void 0:"Git 未安装",onClick:()=>qe(G),children:[e.jsx(Da,{className:"h-4 w-4 mr-1"}),T?.operation==="install"&&T?.plugin_id===G.id?"安装中...":"安装"]})]})}),T&&(T.stage==="loading"||T.stage==="success"||T.stage==="error")&&T.operation!=="fetch"&&T.plugin_id===G.id&&e.jsx("div",{className:"px-6 pb-4 -mt-2",children:e.jsxs("div",{className:`space-y-2 p-3 rounded-lg border ${T.stage==="success"?"bg-green-50 dark:bg-green-950/20 border-green-200 dark:border-green-900":T.stage==="error"?"bg-red-50 dark:bg-red-950/20 border-red-200 dark:border-red-900":"bg-muted/50"}`,children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[T.stage==="loading"?e.jsx(tt,{className:"h-3 w-3 animate-spin"}):T.stage==="success"?e.jsx(aa,{className:"h-3 w-3 text-green-600"}):e.jsx(Ot,{className:"h-3 w-3 text-red-600"}),e.jsx("span",{className:`text-xs font-medium ${T.stage==="success"?"text-green-700 dark:text-green-300":T.stage==="error"?"text-red-700 dark:text-red-300":""}`,children:T.stage==="loading"?e.jsxs(e.Fragment,{children:[T.operation==="install"&&"正在安装",T.operation==="uninstall"&&"正在卸载",T.operation==="update"&&"正在更新"]}):T.stage==="success"?e.jsxs(e.Fragment,{children:[T.operation==="install"&&"安装完成",T.operation==="uninstall"&&"卸载完成",T.operation==="update"&&"更新完成"]}):e.jsxs(e.Fragment,{children:[T.operation==="install"&&"安装失败",T.operation==="uninstall"&&"卸载失败",T.operation==="update"&&"更新失败"]})})]}),T.stage!=="error"&&e.jsxs("span",{className:`text-xs font-medium ${T.stage==="success"?"text-green-700 dark:text-green-300":""}`,children:[T.progress,"%"]})]}),T.stage!=="error"&&e.jsx(gn,{value:T.progress,className:`h-1.5 ${T.stage==="success"?"[&>div]:bg-green-500":""}`}),e.jsx("div",{className:`text-xs ${T.stage==="success"?"text-green-600 dark:text-green-400 truncate":T.stage==="error"?"text-red-600 dark:text-red-400":"text-muted-foreground truncate"}`,children:T.stage==="error"?T.error||T.message||"操作失败":T.message})]})})]},G.id))}),e.jsx(Qs,{open:o!==null,onOpenChange:le,children:o&&o.manifest&&e.jsx(qs,{className:"max-w-2xl max-h-[80vh] p-0 flex flex-col",children:e.jsx(Ze,{className:"flex-1 overflow-auto",children:e.jsxs("div",{className:"p-6",children:[e.jsx(Gs,{children:e.jsxs("div",{className:"flex items-start justify-between gap-4",children:[e.jsxs("div",{className:"space-y-2 flex-1",children:[e.jsx(Vs,{className:"text-2xl",children:o.manifest.name}),e.jsxs(Ws,{children:["作者: ",o.manifest.author?.name||"Unknown",o.manifest.author?.url&&e.jsx("a",{href:o.manifest.author.url,target:"_blank",rel:"noopener noreferrer",className:"ml-2 text-primary hover:underline",children:e.jsx(ao,{className:"h-3 w-3 inline"})})]})]}),e.jsxs("div",{className:"flex flex-col gap-2",children:[o.manifest.categories&&o.manifest.categories[0]&&e.jsx(Ye,{variant:"secondary",children:$p[o.manifest.categories[0]]||o.manifest.categories[0]}),Q(o)]})]})}),e.jsxs("div",{className:"space-y-6",children:[e.jsx(aS,{pluginId:o.id}),e.jsxs("div",{className:"grid grid-cols-2 sm:grid-cols-3 gap-4",children:[e.jsxs("div",{children:[e.jsx("p",{className:"text-sm font-medium",children:"版本"}),e.jsxs("p",{className:"text-sm text-muted-foreground",children:["v",o.manifest?.version||"unknown"]}),o.installed&&o.installed_version&&e.jsxs("p",{className:"text-xs text-muted-foreground",children:["已安装: v",o.installed_version]})]}),e.jsxs("div",{children:[e.jsx("p",{className:"text-sm font-medium",children:"下载量"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:(ne[o.id]?.downloads??o.downloads??0).toLocaleString()})]}),e.jsxs("div",{children:[e.jsx("p",{className:"text-sm font-medium",children:"评分"}),e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx(xl,{className:"h-4 w-4 fill-yellow-400 text-yellow-400"}),e.jsxs("span",{className:"text-sm text-muted-foreground",children:[(ne[o.id]?.rating??o.rating??0).toFixed(1)," (",ne[o.id]?.rating_count??o.review_count??0,")"]})]})]}),e.jsxs("div",{children:[e.jsx("p",{className:"text-sm font-medium",children:"许可证"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:o.manifest.license||"Unknown"})]}),e.jsxs("div",{className:"col-span-2",children:[e.jsx("p",{className:"text-sm font-medium",children:"支持版本"}),e.jsxs("p",{className:"text-sm text-muted-foreground",children:[o.manifest.host_application?.min_version||"未知",o.manifest.host_application?.max_version?` - ${o.manifest.host_application.max_version}`:" - 最新版本"]})]})]}),e.jsxs("div",{children:[e.jsx("p",{className:"text-sm font-medium mb-2",children:"关键词"}),e.jsx("div",{className:"flex flex-wrap gap-2",children:o.manifest.keywords&&o.manifest.keywords.map(G=>e.jsx(Ye,{variant:"outline",children:G},G))})]}),o.detailed_description&&e.jsxs("div",{children:[e.jsx("p",{className:"text-sm font-medium mb-2",children:"详细说明"}),e.jsx("p",{className:"text-sm text-muted-foreground whitespace-pre-line",children:o.detailed_description})]}),!o.detailed_description&&e.jsxs("div",{children:[e.jsx("p",{className:"text-sm font-medium mb-2",children:"说明"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:o.manifest.description||"无描述"})]}),e.jsxs("div",{className:"space-y-2",children:[o.manifest.homepage_url&&e.jsxs("div",{className:"text-sm",children:[e.jsx("span",{className:"font-medium",children:"主页: "}),e.jsx("a",{href:o.manifest.homepage_url,target:"_blank",rel:"noopener noreferrer",className:"text-primary hover:underline",children:o.manifest.homepage_url})]}),o.manifest.repository_url&&e.jsxs("div",{className:"text-sm",children:[e.jsx("span",{className:"font-medium",children:"仓库: "}),e.jsx("a",{href:o.manifest.repository_url,target:"_blank",rel:"noopener noreferrer",className:"text-primary hover:underline",children:o.manifest.repository_url})]})]})]}),e.jsxs(at,{children:[o.manifest.homepage_url&&e.jsxs(C,{onClick:()=>window.open(o.manifest.homepage_url,"_blank"),children:[e.jsx(ao,{className:"h-4 w-4 mr-2"}),"访问主页"]}),o.manifest.repository_url&&e.jsxs(C,{variant:"outline",onClick:()=>window.open(o.manifest.repository_url,"_blank"),children:[e.jsx(ao,{className:"h-4 w-4 mr-2"}),"查看仓库"]})]})]})})})}),e.jsx(Qs,{open:Se,onOpenChange:oe,children:e.jsxs(qs,{children:[e.jsxs(Gs,{children:[e.jsx(Vs,{children:"安装插件"}),e.jsxs(Ws,{children:["安装 ",je?.manifest.name]})]}),e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{children:[e.jsxs("p",{className:"text-sm text-muted-foreground",children:["版本: ",je?.manifest.version]}),e.jsxs("p",{className:"text-sm text-muted-foreground",children:["作者: ",typeof je?.manifest.author=="string"?je.manifest.author:je?.manifest.author?.name]})]}),e.jsxs("div",{className:"flex items-center space-x-2",children:[e.jsx(jt,{id:"advanced-options",checked:Ne,onCheckedChange:G=>Ce(G)}),e.jsx("label",{htmlFor:"advanced-options",className:"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70",children:"高级选项"})]}),Ne&&e.jsx("div",{className:"space-y-4 p-4 border rounded-lg",children:e.jsxs("div",{className:"space-y-2",children:[e.jsx("label",{className:"text-sm font-medium",children:"分支选择"}),e.jsxs(Sa,{value:B,onValueChange:G=>_e(G),children:[e.jsxs(xa,{className:"grid w-full grid-cols-2",children:[e.jsx(is,{value:"preset",className:"text-xs",children:"预设分支"}),e.jsx(is,{value:"custom",className:"text-xs",children:"自定义分支"})]}),B==="preset"&&e.jsx("div",{className:"mt-3",children:e.jsxs(Ue,{value:U,onValueChange:P,children:[e.jsx(Re,{children:e.jsx(Be,{placeholder:"选择分支"})}),e.jsxs(Le,{children:[e.jsx(ee,{value:"main",children:"main (默认)"}),e.jsx(ee,{value:"master",children:"master"}),e.jsx(ee,{value:"dev",children:"dev (开发版)"}),e.jsx(ee,{value:"develop",children:"develop"}),e.jsx(ee,{value:"beta",children:"beta (测试版)"}),e.jsx(ee,{value:"stable",children:"stable (稳定版)"})]})]})}),B==="custom"&&e.jsxs("div",{className:"space-y-2 mt-3",children:[e.jsx("input",{type:"text",className:"flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",placeholder:"输入分支名称,例如: feature/new-feature",value:X,onChange:G=>L(G.target.value)}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"输入 Git 分支名称、标签或提交哈希"})]})]})]})}),!Ne&&e.jsx("p",{className:"text-sm text-muted-foreground",children:"将从默认分支 (main) 安装插件"})]}),e.jsxs(at,{children:[e.jsx(C,{variant:"outline",onClick:()=>oe(!1),children:"取消"}),e.jsxs(C,{onClick:We,children:[e.jsx(Da,{className:"h-4 w-4 mr-2"}),"安装"]})]})]})}),e.jsx(vn,{})]})})}function iS(){return e.jsxs("div",{className:"h-[calc(100vh-4rem)] flex flex-col p-4 sm:p-6",children:[e.jsx("div",{className:"mb-4 sm:mb-6",children:e.jsx("div",{className:"flex flex-col sm:flex-row sm:items-center justify-between gap-4",children:e.jsxs("div",{children:[e.jsxs("h1",{className:"text-2xl sm:text-3xl font-bold flex items-center gap-2",children:[e.jsx($g,{className:"h-8 w-8",strokeWidth:2}),"模型分配预设市场"]}),e.jsx("p",{className:"text-muted-foreground mt-1 text-sm sm:text-base",children:"浏览和下载社区共享的模型分配预设配置"})]})})}),e.jsx(Ze,{className:"flex-1",children:e.jsx("div",{className:"flex items-center justify-center h-[calc(100vh-12rem)]",children:e.jsxs(Ve,{className:"max-w-2xl w-full border-dashed",children:[e.jsxs(rs,{className:"text-center",children:[e.jsx("div",{className:"flex justify-center mb-4",children:e.jsx(Vl,{className:"h-16 w-16 text-muted-foreground"})}),e.jsx(cs,{className:"text-2xl",children:"功能开发中"}),e.jsx(st,{className:"text-base",children:"模型分配预设市场功能正在开发中,敬请期待!"})]}),e.jsx(gs,{children:e.jsxs("div",{className:"space-y-3 text-sm text-muted-foreground",children:[e.jsx("p",{className:"font-medium text-foreground",children:"📦 即将推出的功能:"}),e.jsxs("ul",{className:"space-y-2 ml-6",children:[e.jsxs("li",{className:"flex items-start",children:[e.jsx("span",{className:"mr-2",children:"•"}),e.jsx("span",{children:"浏览社区共享的模型分配预设配置"})]}),e.jsxs("li",{className:"flex items-start",children:[e.jsx("span",{className:"mr-2",children:"•"}),e.jsx("span",{children:"一键下载和应用预设配置"})]}),e.jsxs("li",{className:"flex items-start",children:[e.jsx("span",{className:"mr-2",children:"•"}),e.jsx("span",{children:"分享自己的模型分配方案"})]}),e.jsxs("li",{className:"flex items-start",children:[e.jsx("span",{className:"mr-2",children:"•"}),e.jsx("span",{children:"预设配置评分和评论系统"})]}),e.jsxs("li",{className:"flex items-start",children:[e.jsx("span",{className:"mr-2",children:"•"}),e.jsx("span",{children:"根据使用场景智能推荐配置"})]})]})]})})]})})})]})}function rS({field:l,value:i,onChange:r}){const[o,u]=m.useState(!1);switch(l.ui_type){case"switch":return e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"space-y-0.5",children:[e.jsx(k,{children:l.label}),l.hint&&e.jsx("p",{className:"text-xs text-muted-foreground",children:l.hint})]}),e.jsx(Fe,{checked:!!i,onCheckedChange:r,disabled:l.disabled})]});case"number":return e.jsxs("div",{className:"space-y-2",children:[e.jsx(k,{children:l.label}),e.jsx(ie,{type:"number",value:i??l.default,onChange:x=>r(parseFloat(x.target.value)||0),min:l.min,max:l.max,step:l.step??1,placeholder:l.placeholder,disabled:l.disabled}),l.hint&&e.jsx("p",{className:"text-xs text-muted-foreground",children:l.hint})]});case"slider":return e.jsxs("div",{className:"space-y-2",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(k,{children:l.label}),e.jsx("span",{className:"text-sm text-muted-foreground",children:i??l.default})]}),e.jsx(ma,{value:[i??l.default],onValueChange:x=>r(x[0]),min:l.min??0,max:l.max??100,step:l.step??1,disabled:l.disabled}),l.hint&&e.jsx("p",{className:"text-xs text-muted-foreground",children:l.hint})]});case"select":return e.jsxs("div",{className:"space-y-2",children:[e.jsx(k,{children:l.label}),e.jsxs(Ue,{value:String(i??l.default),onValueChange:r,disabled:l.disabled,children:[e.jsx(Re,{children:e.jsx(Be,{placeholder:l.placeholder??"请选择"})}),e.jsx(Le,{children:l.choices?.map(x=>e.jsx(ee,{value:String(x),children:String(x)},String(x)))})]}),l.hint&&e.jsx("p",{className:"text-xs text-muted-foreground",children:l.hint})]});case"textarea":return e.jsxs("div",{className:"space-y-2",children:[e.jsx(k,{children:l.label}),e.jsx(Ys,{value:i??l.default,onChange:x=>r(x.target.value),placeholder:l.placeholder,rows:l.rows??3,disabled:l.disabled}),l.hint&&e.jsx("p",{className:"text-xs text-muted-foreground",children:l.hint})]});case"password":return e.jsxs("div",{className:"space-y-2",children:[e.jsx(k,{children:l.label}),e.jsxs("div",{className:"relative",children:[e.jsx(ie,{type:o?"text":"password",value:i??"",onChange:x=>r(x.target.value),placeholder:l.placeholder,disabled:l.disabled,className:"pr-10"}),e.jsx(C,{type:"button",variant:"ghost",size:"icon",className:"absolute right-0 top-0 h-full px-3",onClick:()=>u(!o),children:o?e.jsx(wr,{className:"h-4 w-4"}):e.jsx(Gt,{className:"h-4 w-4"})})]}),l.hint&&e.jsx("p",{className:"text-xs text-muted-foreground",children:l.hint})]});case"list":return e.jsxs("div",{className:"space-y-2",children:[e.jsx(k,{children:l.label}),e.jsx(g1,{value:Array.isArray(i)?i:[],onChange:x=>r(x),itemType:l.item_type??"string",itemFields:l.item_fields,minItems:l.min_items,maxItems:l.max_items,disabled:l.disabled,placeholder:l.placeholder}),l.hint&&e.jsx("p",{className:"text-xs text-muted-foreground",children:l.hint})]});case"text":default:return e.jsxs("div",{className:"space-y-2",children:[e.jsx(k,{children:l.label}),e.jsx(ie,{type:"text",value:i??l.default??"",onChange:x=>r(x.target.value),placeholder:l.placeholder,maxLength:l.max_length,disabled:l.disabled}),l.hint&&e.jsx("p",{className:"text-xs text-muted-foreground",children:l.hint})]})}}function qp({section:l,config:i,onChange:r}){const[o,u]=m.useState(!l.collapsed),x=Object.entries(l.fields).filter(([,h])=>!h.hidden).sort(([,h],[,f])=>h.order-f.order);return e.jsx(Tr,{open:o,onOpenChange:u,children:e.jsxs(Ve,{children:[e.jsx(Er,{asChild:!0,children:e.jsxs(rs,{className:"cursor-pointer hover:bg-muted/50 transition-colors",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[o?e.jsx(Fa,{className:"h-4 w-4 text-muted-foreground"}):e.jsx(Ya,{className:"h-4 w-4 text-muted-foreground"}),e.jsx(cs,{className:"text-lg",children:l.title})]}),e.jsxs(Ye,{variant:"secondary",className:"text-xs",children:[x.length," 项"]})]}),l.description&&e.jsx(st,{className:"ml-6",children:l.description})]})}),e.jsx(zr,{children:e.jsx(gs,{className:"space-y-4 pt-0",children:x.map(([h,f])=>e.jsx(rS,{field:f,value:i[l.name]?.[h],onChange:g=>r(l.name,h,g),sectionName:l.name},h))})})]})})}function cS({plugin:l,onBack:i}){const{toast:r}=Ks(),{triggerRestart:o,isRestarting:u}=Il(),[x,h]=m.useState(null),[f,g]=m.useState({}),[j,v]=m.useState({}),[y,b]=m.useState(!0),[S,w]=m.useState(!1),[O,A]=m.useState(!1),[D,V]=m.useState(!1),z=m.useCallback(async()=>{b(!0);try{const[ne,ue]=await Promise.all([Y_(l.id),K_(l.id)]);h(ne),g(ue),v(JSON.parse(JSON.stringify(ue)))}catch(ne){r({title:"加载配置失败",description:ne instanceof Error?ne.message:"未知错误",variant:"destructive"})}finally{b(!1)}},[l.id,r]);m.useEffect(()=>{z()},[z]),m.useEffect(()=>{A(JSON.stringify(f)!==JSON.stringify(j))},[f,j]);const _=(ne,ue,Se)=>{g(oe=>({...oe,[ne]:{...oe[ne]||{},[ue]:Se}}))},T=async()=>{w(!0);try{await X_(l.id,f),v(JSON.parse(JSON.stringify(f))),r({title:"配置已保存",description:"更改将在插件重新加载后生效"})}catch(ne){r({title:"保存失败",description:ne instanceof Error?ne.message:"未知错误",variant:"destructive"})}finally{w(!1)}},$=async()=>{try{await P_(l.id),r({title:"配置已重置",description:"下次加载插件时将使用默认配置"}),V(!1),z()}catch(ne){r({title:"重置失败",description:ne instanceof Error?ne.message:"未知错误",variant:"destructive"})}},E=async()=>{try{const ne=await J_(l.id);r({title:ne.message,description:ne.note}),z()}catch(ne){r({title:"切换状态失败",description:ne instanceof Error?ne.message:"未知错误",variant:"destructive"})}};if(y)return e.jsx("div",{className:"flex items-center justify-center h-64",children:e.jsx(tt,{className:"h-8 w-8 animate-spin text-muted-foreground"})});if(!x)return e.jsxs("div",{className:"flex flex-col items-center justify-center h-64 space-y-4",children:[e.jsx(Ot,{className:"h-12 w-12 text-muted-foreground"}),e.jsx("p",{className:"text-muted-foreground",children:"无法加载配置"}),e.jsxs(C,{onClick:i,variant:"outline",children:[e.jsx(hi,{className:"h-4 w-4 mr-2"}),"返回"]})]});const se=Object.values(x.sections).sort((ne,ue)=>ne.order-ue.order),te=f.plugin?.enabled!==!1;return e.jsxs("div",{className:"space-y-4 sm:space-y-6",children:[e.jsxs("div",{className:"flex flex-col sm:flex-row sm:items-start sm:justify-between gap-4",children:[e.jsxs("div",{className:"flex items-start gap-3",children:[e.jsx(C,{variant:"ghost",size:"icon",onClick:i,children:e.jsx(hi,{className:"h-5 w-5"})}),e.jsxs("div",{children:[e.jsx("h1",{className:"text-2xl sm:text-3xl font-bold",children:x.plugin_info.name||l.manifest.name}),e.jsxs("div",{className:"flex items-center gap-2 mt-1",children:[e.jsx(Ye,{variant:te?"default":"secondary",children:te?"已启用":"已禁用"}),e.jsxs("span",{className:"text-sm text-muted-foreground",children:["v",x.plugin_info.version||l.manifest.version]})]})]})]}),e.jsxs("div",{className:"flex gap-2 ml-10 sm:ml-0",children:[e.jsxs(C,{variant:"outline",size:"sm",onClick:()=>o(),disabled:u,children:[e.jsx(Hg,{className:`h-4 w-4 mr-2 ${u?"animate-spin":""}`}),"重启麦麦"]}),e.jsxs(C,{variant:"outline",size:"sm",onClick:E,children:[e.jsx(Mr,{className:"h-4 w-4 mr-2"}),te?"禁用":"启用"]}),e.jsxs(C,{variant:"outline",size:"sm",onClick:()=>V(!0),children:[e.jsx(yr,{className:"h-4 w-4 mr-2"}),"重置"]}),e.jsxs(C,{size:"sm",onClick:T,disabled:!O||S,children:[S?e.jsx(tt,{className:"h-4 w-4 mr-2 animate-spin"}):e.jsx(Ar,{className:"h-4 w-4 mr-2"}),"保存"]})]})]}),O&&e.jsx(Ve,{className:"border-orange-200 bg-orange-50 dark:bg-orange-950/20 dark:border-orange-900",children:e.jsx(gs,{className:"py-3",children:e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(Ra,{className:"h-4 w-4 text-orange-600"}),e.jsx("p",{className:"text-sm text-orange-800 dark:text-orange-200",children:"有未保存的更改"})]})})}),x.layout.type==="tabs"&&x.layout.tabs.length>0?e.jsxs(Sa,{defaultValue:x.layout.tabs[0]?.id,children:[e.jsx(xa,{children:x.layout.tabs.map(ne=>e.jsxs(is,{value:ne.id,children:[ne.title,ne.badge&&e.jsx(Ye,{variant:"secondary",className:"ml-2 text-xs",children:ne.badge})]},ne.id))}),x.layout.tabs.map(ne=>e.jsx(As,{value:ne.id,className:"space-y-4 mt-4",children:ne.sections.map(ue=>{const Se=x.sections[ue];return Se?e.jsx(qp,{section:Se,config:f,onChange:_},ue):null})},ne.id))]}):e.jsx("div",{className:"space-y-4",children:se.map(ne=>e.jsx(qp,{section:ne,config:f,onChange:_},ne.name))}),e.jsx(Qs,{open:D,onOpenChange:V,children:e.jsxs(qs,{children:[e.jsxs(Gs,{children:[e.jsx(Vs,{children:"确认重置配置"}),e.jsx(Ws,{children:"这将删除当前配置文件,下次加载插件时将使用默认配置。此操作不可撤销。"})]}),e.jsxs(at,{children:[e.jsx(C,{variant:"outline",onClick:()=>V(!1),children:"取消"}),e.jsx(C,{variant:"destructive",onClick:$,children:"确认重置"})]})]})})]})}function oS(){return e.jsx(jn,{children:e.jsx(dS,{})})}function dS(){const{toast:l}=Ks(),[i,r]=m.useState([]),[o,u]=m.useState(!0),[x,h]=m.useState(""),[f,g]=m.useState(null),j=async()=>{u(!0);try{const S=await gr();r(S)}catch(S){l({title:"加载插件列表失败",description:S instanceof Error?S.message:"未知错误",variant:"destructive"})}finally{u(!1)}};m.useEffect(()=>{j()},[]);const v=i.filter(S=>{const w=x.toLowerCase();return S.id.toLowerCase().includes(w)||S.manifest.name.toLowerCase().includes(w)||S.manifest.description?.toLowerCase().includes(w)}),y=i.length,b=0;return f?e.jsxs(e.Fragment,{children:[e.jsx(Ze,{className:"h-full",children:e.jsx("div",{className:"p-4 sm:p-6",children:e.jsx(cS,{plugin:f,onBack:()=>g(null)})})}),e.jsx(vn,{})]}):e.jsx(Ze,{className:"h-full",children:e.jsxs("div",{className:"space-y-4 sm:space-y-6 p-4 sm:p-6",children:[e.jsxs("div",{className:"flex flex-col sm:flex-row sm:items-start sm:justify-between gap-4",children:[e.jsxs("div",{children:[e.jsx("h1",{className:"text-2xl sm:text-3xl font-bold",children:"插件配置"}),e.jsx("p",{className:"text-muted-foreground mt-1 sm:mt-2 text-sm sm:text-base",children:"管理和配置已安装的插件"})]}),e.jsxs(C,{variant:"outline",size:"sm",onClick:j,children:[e.jsx(At,{className:`h-4 w-4 mr-2 ${o?"animate-spin":""}`}),"刷新"]})]}),e.jsxs("div",{className:"grid gap-4 grid-cols-1 xs:grid-cols-2 lg:grid-cols-3",children:[e.jsxs(Ve,{children:[e.jsxs(rs,{className:"flex flex-row items-center justify-between space-y-0 pb-2",children:[e.jsx(cs,{className:"text-sm font-medium",children:"已安装插件"}),e.jsx(Vl,{className:"h-4 w-4 text-muted-foreground"})]}),e.jsxs(gs,{children:[e.jsx("div",{className:"text-2xl font-bold",children:i.length}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:o?"正在加载...":"个插件"})]})]}),e.jsxs(Ve,{children:[e.jsxs(rs,{className:"flex flex-row items-center justify-between space-y-0 pb-2",children:[e.jsx(cs,{className:"text-sm font-medium",children:"已启用"}),e.jsx(aa,{className:"h-4 w-4 text-green-600"})]}),e.jsxs(gs,{children:[e.jsx("div",{className:"text-2xl font-bold",children:y}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:"运行中的插件"})]})]}),e.jsxs(Ve,{children:[e.jsxs(rs,{className:"flex flex-row items-center justify-between space-y-0 pb-2",children:[e.jsx(cs,{className:"text-sm font-medium",children:"已禁用"}),e.jsx(Ot,{className:"h-4 w-4 text-orange-600"})]}),e.jsxs(gs,{children:[e.jsx("div",{className:"text-2xl font-bold",children:b}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:"未激活的插件"})]})]})]}),e.jsxs("div",{className:"relative",children:[e.jsx($t,{className:"absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground"}),e.jsx(ie,{placeholder:"搜索插件...",value:x,onChange:S=>h(S.target.value),className:"pl-9"})]}),e.jsxs(Ve,{children:[e.jsxs(rs,{children:[e.jsx(cs,{children:"已安装的插件"}),e.jsx(st,{children:"点击插件查看和编辑配置"})]}),e.jsx(gs,{children:o?e.jsx("div",{className:"flex items-center justify-center py-12",children:e.jsx(tt,{className:"h-8 w-8 animate-spin text-muted-foreground"})}):v.length===0?e.jsxs("div",{className:"flex flex-col items-center justify-center py-12 space-y-4",children:[e.jsx(Vl,{className:"h-16 w-16 text-muted-foreground/50"}),e.jsxs("div",{className:"text-center space-y-2",children:[e.jsx("p",{className:"text-lg font-medium text-muted-foreground",children:x?"没有找到匹配的插件":"暂无已安装的插件"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:x?"尝试其他搜索关键词":"前往插件市场安装插件"})]})]}):e.jsx("div",{className:"space-y-2",children:v.map(S=>e.jsxs("div",{className:"flex items-center justify-between p-4 rounded-lg border hover:bg-muted/50 cursor-pointer transition-colors",onClick:()=>g(S),children:[e.jsxs("div",{className:"flex items-center gap-3 min-w-0",children:[e.jsx("div",{className:"h-10 w-10 rounded-lg bg-primary/10 flex items-center justify-center flex-shrink-0",children:e.jsx(Vl,{className:"h-5 w-5 text-primary"})}),e.jsxs("div",{className:"min-w-0",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("h3",{className:"font-medium truncate",children:S.manifest.name}),e.jsxs(Ye,{variant:"secondary",className:"text-xs flex-shrink-0",children:["v",S.manifest.version]})]}),e.jsx("p",{className:"text-sm text-muted-foreground truncate",children:S.manifest.description||"暂无描述"})]})]}),e.jsxs("div",{className:"flex items-center gap-2 flex-shrink-0",children:[e.jsx(C,{variant:"ghost",size:"sm",children:e.jsx(ji,{className:"h-4 w-4"})}),e.jsx(Ya,{className:"h-4 w-4 text-muted-foreground"})]})]},S.id))})})]})]})})}function uS(){const l=ka(),{toast:i}=Ks(),[r,o]=m.useState([]),[u,x]=m.useState(!0),[h,f]=m.useState(null),[g,j]=m.useState(null),[v,y]=m.useState(!1),[b,S]=m.useState(!1),[w,O]=m.useState({id:"",name:"",raw_prefix:"",clone_prefix:"",enabled:!0,priority:1}),A=m.useCallback(async()=>{try{x(!0),f(null);const E=await we("/api/webui/plugins/mirrors");if(!E.ok)throw new Error("获取镜像源列表失败");const se=await E.json();o(se.mirrors||[])}catch(E){const se=E instanceof Error?E.message:"加载镜像源失败";f(se),i({title:"加载失败",description:se,variant:"destructive"})}finally{x(!1)}},[i]);m.useEffect(()=>{A()},[A]);const D=async()=>{try{const E=await we("/api/webui/plugins/mirrors",{method:"POST",body:JSON.stringify(w)});if(!E.ok){const se=await E.json();throw new Error(se.detail||"添加镜像源失败")}i({title:"添加成功",description:"镜像源已添加"}),y(!1),O({id:"",name:"",raw_prefix:"",clone_prefix:"",enabled:!0,priority:1}),A()}catch(E){i({title:"添加失败",description:E instanceof Error?E.message:"未知错误",variant:"destructive"})}},V=async()=>{if(g)try{if(!(await we(`/api/webui/plugins/mirrors/${g.id}`,{method:"PUT",body:JSON.stringify({name:w.name,raw_prefix:w.raw_prefix,clone_prefix:w.clone_prefix,enabled:w.enabled,priority:w.priority})})).ok)throw new Error("更新镜像源失败");i({title:"更新成功",description:"镜像源已更新"}),S(!1),j(null),A()}catch(E){i({title:"更新失败",description:E instanceof Error?E.message:"未知错误",variant:"destructive"})}},z=async E=>{if(confirm("确定要删除这个镜像源吗?"))try{if(!(await we(`/api/webui/plugins/mirrors/${E}`,{method:"DELETE"})).ok)throw new Error("删除镜像源失败");i({title:"删除成功",description:"镜像源已删除"}),A()}catch(se){i({title:"删除失败",description:se instanceof Error?se.message:"未知错误",variant:"destructive"})}},_=async E=>{try{if(!(await we(`/api/webui/plugins/mirrors/${E.id}`,{method:"PUT",body:JSON.stringify({enabled:!E.enabled})})).ok)throw new Error("更新状态失败");A()}catch(se){i({title:"更新失败",description:se instanceof Error?se.message:"未知错误",variant:"destructive"})}},T=E=>{j(E),O({id:E.id,name:E.name,raw_prefix:E.raw_prefix,clone_prefix:E.clone_prefix,enabled:E.enabled,priority:E.priority}),S(!0)},$=async(E,se)=>{const te=se==="up"?E.priority-1:E.priority+1;if(!(te<1))try{if(!(await we(`/api/webui/plugins/mirrors/${E.id}`,{method:"PUT",body:JSON.stringify({priority:te})})).ok)throw new Error("更新优先级失败");A()}catch(ne){i({title:"更新失败",description:ne instanceof Error?ne.message:"未知错误",variant:"destructive"})}};return e.jsx(Ze,{className:"h-full",children:e.jsxs("div",{className:"space-y-6 p-4 sm:p-6",children:[e.jsxs("div",{className:"flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4",children:[e.jsxs("div",{className:"flex items-center gap-4",children:[e.jsx(C,{variant:"ghost",size:"icon",onClick:()=>l({to:"/plugins"}),children:e.jsx(hi,{className:"h-5 w-5"})}),e.jsxs("div",{children:[e.jsx("h1",{className:"text-2xl sm:text-3xl font-bold",children:"镜像源配置"}),e.jsx("p",{className:"text-sm text-muted-foreground mt-1",children:"管理 Git 克隆和文件下载的镜像源"})]})]}),e.jsxs(C,{onClick:()=>y(!0),children:[e.jsx(ut,{className:"h-4 w-4 mr-2"}),"添加镜像源"]})]}),u?e.jsx(Ve,{className:"p-6",children:e.jsx("div",{className:"flex items-center justify-center py-8",children:e.jsx(tt,{className:"h-8 w-8 animate-spin text-primary"})})}):h?e.jsx(Ve,{className:"p-6",children:e.jsxs("div",{className:"flex flex-col items-center justify-center py-8 text-center",children:[e.jsx(Oa,{className:"h-12 w-12 text-destructive mb-4"}),e.jsx("h3",{className:"text-lg font-semibold mb-2",children:"加载失败"}),e.jsx("p",{className:"text-sm text-muted-foreground mb-4",children:h}),e.jsx(C,{onClick:A,children:"重新加载"})]})}):e.jsxs(Ve,{children:[e.jsx("div",{className:"hidden md:block",children:e.jsxs(bn,{children:[e.jsx(Nn,{children:e.jsxs(gt,{children:[e.jsx(Je,{children:"状态"}),e.jsx(Je,{children:"名称"}),e.jsx(Je,{children:"ID"}),e.jsx(Je,{children:"优先级"}),e.jsx(Je,{className:"text-right",children:"操作"})]})}),e.jsx(yn,{children:r.map(E=>e.jsxs(gt,{children:[e.jsx(Qe,{children:e.jsx(Fe,{checked:E.enabled,onCheckedChange:()=>_(E)})}),e.jsx(Qe,{children:e.jsxs("div",{children:[e.jsx("div",{className:"font-medium",children:E.name}),e.jsxs("div",{className:"text-xs text-muted-foreground mt-1",children:["Raw: ",E.raw_prefix]})]})}),e.jsx(Qe,{children:e.jsx(Ye,{variant:"outline",children:E.id})}),e.jsx(Qe,{children:e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:"font-mono",children:E.priority}),e.jsxs("div",{className:"flex flex-col gap-1",children:[e.jsx(C,{variant:"ghost",size:"icon",className:"h-5 w-5",onClick:()=>$(E,"up"),disabled:E.priority===1,children:e.jsx(fi,{className:"h-3 w-3"})}),e.jsx(C,{variant:"ghost",size:"icon",className:"h-5 w-5",onClick:()=>$(E,"down"),children:e.jsx(Fa,{className:"h-3 w-3"})})]})]})}),e.jsx(Qe,{className:"text-right",children:e.jsxs("div",{className:"flex items-center justify-end gap-2",children:[e.jsx(C,{variant:"ghost",size:"icon",onClick:()=>T(E),children:e.jsx(fn,{className:"h-4 w-4"})}),e.jsx(C,{variant:"ghost",size:"icon",onClick:()=>z(E.id),children:e.jsx(es,{className:"h-4 w-4 text-destructive"})})]})})]},E.id))})]})}),e.jsx("div",{className:"md:hidden p-4 space-y-4",children:r.map(E=>e.jsx(Ve,{className:"p-4",children:e.jsxs("div",{className:"space-y-3",children:[e.jsxs("div",{className:"flex items-start justify-between",children:[e.jsxs("div",{className:"flex-1",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("h3",{className:"font-semibold",children:E.name}),E.enabled&&e.jsx(Ye,{variant:"default",className:"text-xs",children:"启用"})]}),e.jsx(Ye,{variant:"outline",className:"mt-1 text-xs",children:E.id})]}),e.jsx(Fe,{checked:E.enabled,onCheckedChange:()=>_(E)})]}),e.jsxs("div",{className:"text-sm space-y-1",children:[e.jsxs("div",{className:"text-muted-foreground",children:[e.jsx("span",{className:"font-medium",children:"Raw: "}),e.jsx("span",{className:"break-all",children:E.raw_prefix})]}),e.jsxs("div",{className:"text-muted-foreground",children:[e.jsx("span",{className:"font-medium",children:"优先级: "}),e.jsx("span",{className:"font-mono",children:E.priority})]})]}),e.jsxs("div",{className:"flex items-center gap-2 pt-2 border-t",children:[e.jsxs(C,{variant:"outline",size:"sm",className:"flex-1",onClick:()=>T(E),children:[e.jsx(fn,{className:"h-4 w-4 mr-1"}),"编辑"]}),e.jsx(C,{variant:"outline",size:"sm",onClick:()=>$(E,"up"),disabled:E.priority===1,children:e.jsx(fi,{className:"h-4 w-4"})}),e.jsx(C,{variant:"outline",size:"sm",onClick:()=>$(E,"down"),children:e.jsx(Fa,{className:"h-4 w-4"})}),e.jsx(C,{variant:"destructive",size:"sm",onClick:()=>z(E.id),children:e.jsx(es,{className:"h-4 w-4"})})]})]})},E.id))})]}),e.jsx(Qs,{open:v,onOpenChange:y,children:e.jsxs(qs,{className:"max-w-lg",children:[e.jsxs(Gs,{children:[e.jsx(Vs,{children:"添加镜像源"}),e.jsx(Ws,{children:"添加新的 Git 镜像源配置"})]}),e.jsxs("div",{className:"space-y-4 py-4",children:[e.jsxs("div",{className:"space-y-2",children:[e.jsx(k,{htmlFor:"add-id",children:"镜像源 ID *"}),e.jsx(ie,{id:"add-id",placeholder:"例如: my-mirror",value:w.id,onChange:E=>O({...w,id:E.target.value})})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(k,{htmlFor:"add-name",children:"名称 *"}),e.jsx(ie,{id:"add-name",placeholder:"例如: 我的镜像源",value:w.name,onChange:E=>O({...w,name:E.target.value})})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(k,{htmlFor:"add-raw",children:"Raw 文件前缀 *"}),e.jsx(ie,{id:"add-raw",placeholder:"https://example.com/raw",value:w.raw_prefix,onChange:E=>O({...w,raw_prefix:E.target.value})})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(k,{htmlFor:"add-clone",children:"克隆前缀 *"}),e.jsx(ie,{id:"add-clone",placeholder:"https://example.com/clone",value:w.clone_prefix,onChange:E=>O({...w,clone_prefix:E.target.value})})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(k,{htmlFor:"add-priority",children:"优先级"}),e.jsx(ie,{id:"add-priority",type:"number",min:"1",value:w.priority,onChange:E=>O({...w,priority:parseInt(E.target.value)||1})}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"数字越小优先级越高"})]}),e.jsxs("div",{className:"flex items-center space-x-2",children:[e.jsx(Fe,{id:"add-enabled",checked:w.enabled,onCheckedChange:E=>O({...w,enabled:E})}),e.jsx(k,{htmlFor:"add-enabled",children:"启用此镜像源"})]})]}),e.jsxs(at,{children:[e.jsx(C,{variant:"outline",onClick:()=>y(!1),children:"取消"}),e.jsx(C,{onClick:D,children:"添加"})]})]})}),e.jsx(Qs,{open:b,onOpenChange:S,children:e.jsxs(qs,{className:"max-w-lg",children:[e.jsxs(Gs,{children:[e.jsx(Vs,{children:"编辑镜像源"}),e.jsx(Ws,{children:"修改镜像源配置"})]}),e.jsxs("div",{className:"space-y-4 py-4",children:[e.jsxs("div",{className:"space-y-2",children:[e.jsx(k,{children:"镜像源 ID"}),e.jsx(ie,{value:w.id,disabled:!0})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(k,{htmlFor:"edit-name",children:"名称 *"}),e.jsx(ie,{id:"edit-name",value:w.name,onChange:E=>O({...w,name:E.target.value})})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(k,{htmlFor:"edit-raw",children:"Raw 文件前缀 *"}),e.jsx(ie,{id:"edit-raw",value:w.raw_prefix,onChange:E=>O({...w,raw_prefix:E.target.value})})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(k,{htmlFor:"edit-clone",children:"克隆前缀 *"}),e.jsx(ie,{id:"edit-clone",value:w.clone_prefix,onChange:E=>O({...w,clone_prefix:E.target.value})})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(k,{htmlFor:"edit-priority",children:"优先级"}),e.jsx(ie,{id:"edit-priority",type:"number",min:"1",value:w.priority,onChange:E=>O({...w,priority:parseInt(E.target.value)||1})}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"数字越小优先级越高"})]}),e.jsxs("div",{className:"flex items-center space-x-2",children:[e.jsx(Fe,{id:"edit-enabled",checked:w.enabled,onCheckedChange:E=>O({...w,enabled:E})}),e.jsx(k,{htmlFor:"edit-enabled",children:"启用此镜像源"})]})]}),e.jsxs(at,{children:[e.jsx(C,{variant:"outline",onClick:()=>S(!1),children:"取消"}),e.jsx(C,{onClick:V,children:"保存"})]})]})})]})})}const jr=m.forwardRef(({className:l,...i},r)=>e.jsx(ig,{ref:r,className:H("relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full",l),...i}));jr.displayName=ig.displayName;const mS=m.forwardRef(({className:l,...i},r)=>e.jsx(rg,{ref:r,className:H("aspect-square h-full w-full",l),...i}));mS.displayName=rg.displayName;const vr=m.forwardRef(({className:l,...i},r)=>e.jsx(cg,{ref:r,className:H("flex h-full w-full items-center justify-center rounded-full bg-muted",l),...i}));vr.displayName=cg.displayName;function xS(){return"webui_"+Math.random().toString(36).substr(2,9)+"_"+Date.now().toString(36)}function hS(){const l="maibot_webui_user_id";let i=localStorage.getItem(l);return i||(i=xS(),localStorage.setItem(l,i)),i}function fS(){return localStorage.getItem("maibot_webui_user_name")||"WebUI用户"}function pS(l){localStorage.setItem("maibot_webui_user_name",l)}const Aj="maibot_webui_virtual_tabs";function gS(){try{const l=localStorage.getItem(Aj);if(l)return JSON.parse(l)}catch(l){console.error("[Chat] 加载虚拟标签页失败:",l)}return[]}function Gp(l){try{localStorage.setItem(Aj,JSON.stringify(l))}catch(i){console.error("[Chat] 保存虚拟标签页失败:",i)}}function jS({segment:l}){switch(l.type){case"text":return e.jsx("span",{className:"whitespace-pre-wrap",children:String(l.data)});case"image":case"emoji":return e.jsx("img",{src:String(l.data),alt:l.type==="emoji"?"表情包":"图片",className:H("rounded-lg max-w-full",l.type==="emoji"?"max-h-32":"max-h-64"),loading:"lazy",onError:i=>{const r=i.target;r.style.display="none",r.parentElement?.insertAdjacentHTML("beforeend",`[${l.type==="emoji"?"表情包":"图片"}加载失败]`)}});case"voice":return e.jsx("div",{className:"flex items-center gap-2",children:e.jsx("audio",{controls:!0,src:String(l.data),className:"max-w-[200px] h-8",children:"您的浏览器不支持音频播放"})});case"video":return e.jsx("video",{controls:!0,src:String(l.data),className:"rounded-lg max-w-full max-h-64",children:"您的浏览器不支持视频播放"});case"face":return e.jsxs("span",{className:"text-muted-foreground",children:["[表情:",String(l.data),"]"]});case"music":return e.jsx("span",{className:"text-muted-foreground",children:"[音乐分享]"});case"file":return e.jsxs("span",{className:"text-muted-foreground",children:["[文件: ",String(l.data),"]"]});case"reply":return e.jsx("span",{className:"text-muted-foreground text-xs",children:"[回复消息]"});case"forward":return e.jsx("span",{className:"text-muted-foreground",children:"[转发消息]"});case"unknown":default:return e.jsxs("span",{className:"text-muted-foreground",children:["[",l.original_type||"未知消息","]"]})}}function vS({message:l,isBot:i}){return l.message_type==="rich"&&l.segments&&l.segments.length>0?e.jsx("div",{className:"flex flex-col gap-2",children:l.segments.map((r,o)=>e.jsx(jS,{segment:r},o))}):e.jsx("span",{className:"whitespace-pre-wrap",children:l.content})}function bS(){const l={id:"webui-default",type:"webui",label:"WebUI",messages:[],isConnected:!1,isTyping:!1,sessionInfo:{}},i=()=>{const He=gS().map(De=>{const ye=De.virtualConfig;return!ye.groupId&&ye.platform&&ye.userId&&(ye.groupId=`webui_virtual_group_${ye.platform}_${ye.userId}`),{id:De.id,type:"virtual",label:De.label,virtualConfig:ye,messages:[],isConnected:!1,isTyping:!1,sessionInfo:{}}});return[l,...He]},[r,o]=m.useState(i),[u,x]=m.useState("webui-default"),h=r.find(F=>F.id===u)||r[0],[f,g]=m.useState(""),[j,v]=m.useState(!1),[y,b]=m.useState(!0),[S,w]=m.useState(fS()),[O,A]=m.useState(!1),[D,V]=m.useState(""),[z,_]=m.useState(!1),[T,$]=m.useState([]),[E,se]=m.useState([]),[te,ne]=m.useState(!1),[ue,Se]=m.useState(!1),[oe,je]=m.useState(""),[be,U]=m.useState({platform:"",personId:"",userId:"",userName:"",groupName:"",groupId:""}),P=m.useRef(hS()),X=m.useRef(new Map),L=m.useRef(null),B=m.useRef(new Map),_e=m.useRef(0),Ne=m.useRef(new Map),{toast:Ce}=Ks(),ve=F=>(_e.current+=1,`${F}-${Date.now()}-${_e.current}-${Math.random().toString(36).substr(2,9)}`),ze=m.useCallback((F,He)=>{o(De=>De.map(ye=>ye.id===F?{...ye,...He}:ye))},[]),Q=m.useCallback((F,He)=>{o(De=>De.map(ye=>ye.id===F?{...ye,messages:[...ye.messages,He]}:ye))},[]),xe=m.useCallback(()=>{L.current?.scrollIntoView({behavior:"smooth"})},[]);m.useEffect(()=>{xe()},[h?.messages,xe]);const Te=m.useCallback(async()=>{ne(!0);try{const F=await we("/api/chat/platforms");if(console.log("[Chat] 平台列表响应:",F.status,F.headers.get("content-type")),F.ok){const He=F.headers.get("content-type");if(He&&He.includes("application/json")){const De=await F.json();console.log("[Chat] 平台列表数据:",De),$(De.platforms||[])}else{const De=await F.text();console.error("[Chat] 获取平台列表失败: 非 JSON 响应:",De.substring(0,200)),Ce({title:"连接失败",description:"无法连接到后端服务,请确保 MaiBot 已启动",variant:"destructive"})}}else console.error("[Chat] 获取平台列表失败: HTTP",F.status),Ce({title:"获取平台失败",description:`服务器返回错误: ${F.status}`,variant:"destructive"})}catch(F){console.error("[Chat] 获取平台列表失败:",F),Ce({title:"网络错误",description:"无法连接到后端服务",variant:"destructive"})}finally{ne(!1)}},[Ce]),J=m.useCallback(async(F,He)=>{Se(!0);try{const De=new URLSearchParams;F&&De.append("platform",F),He&&De.append("search",He),De.append("limit","50");const ye=await we(`/api/chat/persons?${De.toString()}`);if(ye.ok){const ps=ye.headers.get("content-type");if(ps&&ps.includes("application/json")){const ss=await ye.json();se(ss.persons||[])}else console.error("[Chat] 获取用户列表失败: 后端返回非 JSON 响应")}}catch(De){console.error("[Chat] 获取用户列表失败:",De)}finally{Se(!1)}},[]);m.useEffect(()=>{be.platform&&J(be.platform,oe)},[be.platform,oe,J]);const le=m.useCallback(async(F,He)=>{b(!0);try{const De=new URLSearchParams;De.append("user_id",P.current),De.append("limit","50"),He&&De.append("group_id",He);const ye=`/api/chat/history?${De.toString()}`;console.log("[Chat] 正在加载历史消息:",ye);const ps=await we(ye);if(ps.ok){const ss=await ps.text();try{const Es=JSON.parse(ss);if(Es.messages&&Es.messages.length>0){const Ms=Es.messages.map(ts=>({id:ts.id,type:ts.type,content:ts.content,timestamp:ts.timestamp,sender:{name:ts.sender_name||(ts.is_bot?"麦麦":"WebUI用户"),user_id:ts.user_id,is_bot:ts.is_bot}}));ze(F,{messages:Ms});const Ls=Ne.current.get(F)||new Set;Ms.forEach(ts=>{if(ts.type==="bot"){const Pe=`bot-${ts.content}-${Math.floor(ts.timestamp*1e3)}`;Ls.add(Pe)}}),Ne.current.set(F,Ls)}}catch(Es){console.error("[Chat] JSON 解析失败:",Es)}}}catch(De){console.error("[Chat] 加载历史消息失败:",De)}finally{b(!1)}},[ze]),qe=m.useCallback(async(F,He,De)=>{const ye=X.current.get(F);if(ye?.readyState===WebSocket.OPEN||ye?.readyState===WebSocket.CONNECTING){console.log(`[Tab ${F}] WebSocket 已存在,跳过连接`);return}v(!0);let ps=null;try{const Ls=await we("/api/webui/ws-token");if(Ls.ok){const ts=await Ls.json();ts.success&&ts.token&&(ps=ts.token)}}catch(Ls){console.error(`[Tab ${F}] 获取 WebSocket token 失败:`,Ls)}const ss=window.location.protocol==="https:"?"wss:":"ws:",Es=new URLSearchParams;ps&&Es.append("token",ps),He==="virtual"&&De?(Es.append("user_id",De.userId),Es.append("user_name",De.userName),Es.append("platform",De.platform),Es.append("person_id",De.personId),Es.append("group_name",De.groupName||"WebUI虚拟群聊"),De.groupId&&Es.append("group_id",De.groupId)):(Es.append("user_id",P.current),Es.append("user_name",S));const Ms=`${ss}//${window.location.host}/api/chat/ws?${Es.toString()}`;console.log(`[Tab ${F}] 正在连接 WebSocket:`,Ms);try{const Ls=new WebSocket(Ms);X.current.set(F,Ls),Ls.onopen=()=>{ze(F,{isConnected:!0}),v(!1),console.log(`[Tab ${F}] WebSocket 已连接`)},Ls.onmessage=ts=>{try{const Pe=JSON.parse(ts.data);switch(Pe.type){case"session_info":ze(F,{sessionInfo:{session_id:Pe.session_id,user_id:Pe.user_id,user_name:Pe.user_name,bot_name:Pe.bot_name}});break;case"system":Q(F,{id:ve("sys"),type:"system",content:Pe.content||"",timestamp:Pe.timestamp||Date.now()/1e3});break;case"user_message":{const Xe=Pe.sender?.user_id,Os=He==="virtual"&&De?De.userId:P.current;console.log(`[Tab ${F}] 收到 user_message, sender: ${Xe}, current: ${Os}`);const kt=Xe?Xe.replace(/^webui_user_/,""):"",Xs=Os?Os.replace(/^webui_user_/,""):"";if(kt&&Xs&&kt===Xs){console.log(`[Tab ${F}] 跳过自己的消息(user_id 匹配)`);break}const Ss=Ne.current.get(F)||new Set,xt=`user-${Pe.content}-${Math.floor((Pe.timestamp||0)*1e3)}`;if(Ss.has(xt)){console.log(`[Tab ${F}] 跳过自己的消息(内容去重)`);break}if(Ss.add(xt),Ne.current.set(F,Ss),Ss.size>100){const W=Ss.values().next().value;W&&Ss.delete(W)}Q(F,{id:Pe.message_id||ve("user"),type:"user",content:Pe.content||"",timestamp:Pe.timestamp||Date.now()/1e3,sender:Pe.sender});break}case"bot_message":{ze(F,{isTyping:!1});const Xe=Ne.current.get(F)||new Set,Os=`bot-${Pe.content}-${Math.floor((Pe.timestamp||0)*1e3)}`;if(Xe.has(Os))break;if(Xe.add(Os),Ne.current.set(F,Xe),Xe.size>100){const kt=Xe.values().next().value;kt&&Xe.delete(kt)}o(kt=>kt.map(Xs=>{if(Xs.id!==F)return Xs;const Ss=Xs.messages.filter(W=>W.type!=="thinking"),xt={id:ve("bot"),type:"bot",content:Pe.content||"",message_type:Pe.message_type==="rich"?"rich":"text",segments:Pe.segments,timestamp:Pe.timestamp||Date.now()/1e3,sender:Pe.sender};return{...Xs,messages:[...Ss,xt]}}));break}case"typing":ze(F,{isTyping:Pe.is_typing||!1});break;case"error":o(Xe=>Xe.map(Os=>{if(Os.id!==F)return Os;const kt=Os.messages.filter(Xs=>Xs.type!=="thinking");return{...Os,messages:[...kt,{id:ve("error"),type:"error",content:Pe.content||"发生错误",timestamp:Pe.timestamp||Date.now()/1e3}]}})),Ce({title:"错误",description:Pe.content,variant:"destructive"});break;case"pong":break;case"history":{const Xe=Pe.messages||[];if(Xe.length>0){const Os=Ne.current.get(F)||new Set,kt=Xe.map(Xs=>{const Ss=Xs.is_bot||!1,xt=Xs.id||ve(Ss?"bot":"user"),W=`${Ss?"bot":"user"}-${Xs.content}-${Math.floor(Xs.timestamp*1e3)}`;return Os.add(W),{id:xt,type:Ss?"bot":"user",content:Xs.content,timestamp:Xs.timestamp,sender:{name:Xs.sender_name||(Ss?"麦麦":"用户"),user_id:Xs.sender_id,is_bot:Ss}}});Ne.current.set(F,Os),ze(F,{messages:kt}),console.log(`[Tab ${F}] 已加载 ${kt.length} 条历史消息`)}break}default:console.log("未知消息类型:",Pe.type)}}catch(Pe){console.error("解析消息失败:",Pe)}},Ls.onclose=()=>{ze(F,{isConnected:!1}),v(!1),X.current.delete(F),console.log(`[Tab ${F}] WebSocket 已断开`);const ts=B.current.get(F);ts&&clearTimeout(ts);const Pe=window.setTimeout(()=>{if(!We.current){const Xe=r.find(Os=>Os.id===F);Xe&&qe(F,Xe.type,Xe.virtualConfig)}},5e3);B.current.set(F,Pe)},Ls.onerror=ts=>{console.error(`[Tab ${F}] WebSocket 错误:`,ts),v(!1)}}catch(Ls){console.error(`[Tab ${F}] 创建 WebSocket 失败:`,Ls),v(!1)}},[S,ze,Q,Ce,r]),We=m.useRef(!1);m.useEffect(()=>{We.current=!1;const F=X.current,He=B.current,De=Ne.current;le("webui-default");const ye=setTimeout(()=>{We.current||(qe("webui-default","webui"),r.forEach(ss=>{ss.type==="virtual"&&ss.virtualConfig&&(De.set(ss.id,new Set),setTimeout(()=>{We.current||qe(ss.id,"virtual",ss.virtualConfig)},200))}))},100),ps=setInterval(()=>{F.forEach(ss=>{ss.readyState===WebSocket.OPEN&&ss.send(JSON.stringify({type:"ping"}))})},3e4);return()=>{We.current=!0,clearTimeout(ye),clearInterval(ps),He.forEach(ss=>{clearTimeout(ss)}),He.clear(),F.forEach(ss=>{ss.close()}),F.clear()}},[]);const fe=m.useCallback(()=>{const F=X.current.get(u);if(!f.trim()||!F||F.readyState!==WebSocket.OPEN)return;const He=h?.type==="virtual"&&h.virtualConfig?.userName||S,De=f.trim(),ye=Date.now()/1e3;F.send(JSON.stringify({type:"message",content:De,user_name:He}));const ps=Ne.current.get(u)||new Set,ss=`user-${De}-${Math.floor(ye*1e3)}`;if(ps.add(ss),Ne.current.set(u,ps),ps.size>100){const Ls=ps.values().next().value;Ls&&ps.delete(Ls)}const Es={id:ve("user"),type:"user",content:De,timestamp:ye,sender:{name:He,is_bot:!1}};Q(u,Es);const Ms={id:ve("thinking"),type:"thinking",content:"",timestamp:ye+.001,sender:{name:h?.sessionInfo.bot_name||"麦麦",is_bot:!0}};Q(u,Ms),g("")},[f,S,u,h,Q]),ls=F=>{F.key==="Enter"&&!F.shiftKey&&(F.preventDefault(),fe())},G=()=>{V(S),A(!0)},Me=()=>{const F=D.trim()||"WebUI用户";w(F),pS(F),A(!1);const He=X.current.get(u);He?.readyState===WebSocket.OPEN&&He.send(JSON.stringify({type:"update_nickname",user_name:F}))},re=()=>{V(""),A(!1)},pe=F=>new Date(F*1e3).toLocaleTimeString("zh-CN",{hour:"2-digit",minute:"2-digit"}),Ee=()=>{const F=X.current.get(u);F&&(F.close(),X.current.delete(u)),qe(u,h?.type||"webui",h?.virtualConfig)},Ie=()=>{U({platform:"",personId:"",userId:"",userName:"",groupName:"",groupId:""}),je(""),Te(),_(!0)},$e=()=>{if(!be.platform||!be.personId){Ce({title:"配置不完整",description:"请选择平台和用户",variant:"destructive"});return}const F=`webui_virtual_group_${be.platform}_${be.userId}`,He=`virtual-${be.platform}-${be.userId}-${Date.now()}`,De=be.userName||be.userId,ye={id:He,type:"virtual",label:De,virtualConfig:{...be,groupId:F},messages:[],isConnected:!1,isTyping:!1,sessionInfo:{}};o(ps=>{const ss=[...ps,ye],Es=ss.filter(Ms=>Ms.type==="virtual"&&Ms.virtualConfig).map(Ms=>({id:Ms.id,label:Ms.label,virtualConfig:Ms.virtualConfig,createdAt:Date.now()}));return Gp(Es),ss}),x(He),_(!1),Ne.current.set(He,new Set),setTimeout(()=>{qe(He,"virtual",be)},100),Ce({title:"虚拟身份标签页",description:`已创建 ${De} 的对话`})},Vt=(F,He)=>{if(He?.stopPropagation(),F==="webui-default")return;const De=X.current.get(F);De&&(De.close(),X.current.delete(F));const ye=B.current.get(F);ye&&(clearTimeout(ye),B.current.delete(F)),Ne.current.delete(F),o(ps=>{const ss=ps.filter(Ms=>Ms.id!==F),Es=ss.filter(Ms=>Ms.type==="virtual"&&Ms.virtualConfig).map(Ms=>({id:Ms.id,label:Ms.label,virtualConfig:Ms.virtualConfig,createdAt:Date.now()}));return Gp(Es),ss}),u===F&&x("webui-default")},_t=F=>{x(F)},nt=F=>{U(He=>({...He,personId:F.person_id,userId:F.user_id,userName:F.nickname||F.person_name}))};return e.jsxs("div",{className:"h-full flex flex-col",children:[e.jsx(Qs,{open:z,onOpenChange:_,children:e.jsxs(qs,{className:"sm:max-w-[500px] max-h-[85vh] overflow-hidden flex flex-col",children:[e.jsxs(Gs,{children:[e.jsxs(Vs,{className:"flex items-center gap-2",children:[e.jsx(Uu,{className:"h-5 w-5"}),"新建虚拟身份对话"]}),e.jsx(Ws,{children:"选择一个麦麦已认识的用户,以该用户的身份与麦麦对话。麦麦将使用她对该用户的记忆和认知来回应。"})]}),e.jsxs("div",{className:"space-y-4 flex-1 overflow-hidden flex flex-col",children:[e.jsxs("div",{className:"space-y-2",children:[e.jsxs(k,{className:"flex items-center gap-2",children:[e.jsx(Wu,{className:"h-4 w-4"}),"选择平台"]}),e.jsxs(Ue,{value:be.platform,onValueChange:F=>{U(He=>({...He,platform:F,personId:"",userId:"",userName:""})),se([])},children:[e.jsx(Re,{disabled:te,children:e.jsx(Be,{placeholder:te?"加载中...":"选择平台"})}),e.jsx(Le,{children:T.map(F=>e.jsxs(ee,{value:F.platform,children:[F.platform," (",F.count," 人)"]},F.platform))})]})]}),be.platform&&e.jsxs("div",{className:"space-y-2 flex-1 overflow-hidden flex flex-col",children:[e.jsxs(k,{className:"flex items-center gap-2",children:[e.jsx(em,{className:"h-4 w-4"}),"选择用户"]}),e.jsxs("div",{className:"relative",children:[e.jsx($t,{className:"absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground"}),e.jsx(ie,{placeholder:"搜索用户名...",value:oe,onChange:F=>je(F.target.value),className:"pl-9"})]}),e.jsx(Ze,{className:"h-[250px] border rounded-md",children:e.jsx("div",{className:"p-2",children:ue?e.jsx("div",{className:"flex items-center justify-center py-8",children:e.jsx(tt,{className:"h-6 w-6 animate-spin text-muted-foreground"})}):E.length===0?e.jsxs("div",{className:"flex flex-col items-center justify-center py-8 text-muted-foreground",children:[e.jsx(em,{className:"h-8 w-8 mb-2 opacity-50"}),e.jsx("p",{className:"text-sm",children:"没有找到用户"})]}):e.jsx("div",{className:"space-y-1",children:E.map(F=>e.jsxs("button",{onClick:()=>nt(F),className:H("w-full flex items-center gap-3 p-2 rounded-md text-left transition-colors",be.personId===F.person_id?"bg-primary text-primary-foreground":"hover:bg-muted"),children:[e.jsx(jr,{className:"h-8 w-8 shrink-0",children:e.jsx(vr,{className:H("text-xs",be.personId===F.person_id?"bg-primary-foreground/20":"bg-muted"),children:(F.nickname||F.person_name||"?").charAt(0)})}),e.jsxs("div",{className:"min-w-0 flex-1",children:[e.jsx("div",{className:"font-medium truncate",children:F.nickname||F.person_name}),e.jsxs("div",{className:H("text-xs truncate",be.personId===F.person_id?"text-primary-foreground/70":"text-muted-foreground"),children:["ID: ",F.user_id,F.is_known&&" · 已认识"]})]})]},F.person_id))})})})]}),be.personId&&e.jsxs("div",{className:"space-y-2",children:[e.jsx(k,{children:"虚拟群名(可选)"}),e.jsx(ie,{placeholder:"WebUI虚拟群聊",value:be.groupName,onChange:F=>U(He=>({...He,groupName:F.target.value}))}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"麦麦会认为这是一个名为此名称的群聊"})]})]}),e.jsxs(at,{className:"gap-2 sm:gap-0",children:[e.jsx(C,{variant:"outline",onClick:()=>_(!1),children:"取消"}),e.jsx(C,{onClick:$e,disabled:!be.platform||!be.personId,children:"创建对话"})]})]})}),e.jsx("div",{className:"shrink-0 border-b bg-muted/30",children:e.jsx("div",{className:"max-w-4xl mx-auto px-2 sm:px-4",children:e.jsxs("div",{className:"flex items-center gap-1 overflow-x-auto py-1.5 scrollbar-thin",children:[r.map(F=>e.jsxs("div",{className:H("flex items-center gap-1.5 px-3 py-1.5 rounded-md text-sm whitespace-nowrap transition-colors cursor-pointer","hover:bg-muted",u===F.id?"bg-background shadow-sm border":"text-muted-foreground"),onClick:()=>_t(F.id),children:[F.type==="webui"?e.jsx(Fl,{className:"h-3.5 w-3.5"}):e.jsx(Uu,{className:"h-3.5 w-3.5"}),e.jsx("span",{className:"max-w-[100px] truncate",children:F.label}),e.jsx("span",{className:H("w-1.5 h-1.5 rounded-full",F.isConnected?"bg-green-500":"bg-muted-foreground/50")}),F.id!=="webui-default"&&e.jsx("span",{onClick:He=>Vt(F.id,He),className:"ml-0.5 p-0.5 rounded hover:bg-muted-foreground/20 cursor-pointer",role:"button",tabIndex:0,onKeyDown:He=>{(He.key==="Enter"||He.key===" ")&&(He.preventDefault(),Vt(F.id,He))},children:e.jsx(fl,{className:"h-3 w-3"})})]},F.id)),e.jsx("button",{onClick:Ie,className:"flex items-center gap-1 px-2 py-1.5 rounded-md text-sm text-muted-foreground hover:bg-muted hover:text-foreground transition-colors",title:"新建虚拟身份对话",children:e.jsx(ut,{className:"h-3.5 w-3.5"})})]})})}),e.jsx("div",{className:"shrink-0 border-b bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60",children:e.jsxs("div",{className:"p-3 sm:p-4 max-w-4xl mx-auto",children:[e.jsxs("div",{className:"flex items-center justify-between gap-2",children:[e.jsxs("div",{className:"flex items-center gap-2 sm:gap-3 min-w-0",children:[e.jsx(jr,{className:"h-8 w-8 sm:h-10 sm:w-10 shrink-0",children:e.jsx(vr,{className:"bg-primary/10 text-primary",children:e.jsx(fr,{className:"h-4 w-4 sm:h-5 sm:w-5"})})}),e.jsxs("div",{className:"min-w-0",children:[e.jsx("h1",{className:"text-base sm:text-lg font-semibold truncate",children:h?.sessionInfo.bot_name||"麦麦"}),e.jsx("div",{className:"flex items-center gap-1.5 text-xs text-muted-foreground",children:h?.isConnected?e.jsxs(e.Fragment,{children:[e.jsx(Jy,{className:"h-3 w-3 text-green-500"}),e.jsx("span",{className:"text-green-600 dark:text-green-400",children:"已连接"})]}):j?e.jsxs(e.Fragment,{children:[e.jsx(tt,{className:"h-3 w-3 animate-spin"}),e.jsx("span",{children:"连接中..."})]}):e.jsxs(e.Fragment,{children:[e.jsx(Zy,{className:"h-3 w-3 text-red-500"}),e.jsx("span",{className:"text-red-600 dark:text-red-400",children:"未连接"})]})})]})]}),e.jsxs("div",{className:"flex items-center gap-1 shrink-0",children:[y&&e.jsx(tt,{className:"h-4 w-4 animate-spin text-muted-foreground"}),e.jsx(C,{variant:"ghost",size:"icon",className:"h-8 w-8",onClick:Ee,disabled:j,title:"重新连接",children:e.jsx(At,{className:H("h-4 w-4",j&&"animate-spin")})})]})]}),e.jsx("div",{className:"hidden sm:flex items-center gap-2 mt-2 text-sm text-muted-foreground",children:h?.type==="virtual"&&h.virtualConfig?e.jsxs(e.Fragment,{children:[e.jsx(Uu,{className:"h-3 w-3 text-primary"}),e.jsx("span",{children:"虚拟身份:"}),e.jsx("span",{className:"font-medium text-primary",children:h.virtualConfig.userName}),e.jsxs("span",{className:"text-xs",children:["(",h.virtualConfig.platform,")"]}),h.virtualConfig.groupName&&e.jsxs(e.Fragment,{children:[e.jsx("span",{className:"mx-1",children:"·"}),e.jsxs("span",{className:"text-xs",children:["群:",h.virtualConfig.groupName]})]})]}):e.jsxs(e.Fragment,{children:[e.jsx(oo,{className:"h-3 w-3"}),e.jsx("span",{children:"当前身份:"}),O?e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(ie,{value:D,onChange:F=>V(F.target.value),onKeyDown:F=>{F.key==="Enter"&&Me(),F.key==="Escape"&&re()},className:"h-7 w-32",placeholder:"输入昵称",autoFocus:!0}),e.jsx(C,{size:"sm",variant:"ghost",className:"h-7 px-2",onClick:Me,children:"保存"}),e.jsx(C,{size:"sm",variant:"ghost",className:"h-7 px-2",onClick:re,children:"取消"})]}):e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx("span",{className:"font-medium text-foreground",children:S}),e.jsx(C,{size:"sm",variant:"ghost",className:"h-6 w-6 p-0",onClick:G,title:"修改昵称",children:e.jsx(Wy,{className:"h-3 w-3"})})]})]})})]})}),e.jsx("div",{className:"flex-1 overflow-hidden",children:e.jsx(Ze,{className:"h-full",children:e.jsxs("div",{className:"p-3 sm:p-4 max-w-4xl mx-auto space-y-3 sm:space-y-4",children:[h?.messages.length===0&&!y&&e.jsxs("div",{className:"flex flex-col items-center justify-center py-12 text-muted-foreground",children:[e.jsx(fr,{className:"h-12 w-12 mb-4 opacity-50"}),e.jsxs("p",{className:"text-sm",children:["开始与 ",h?.sessionInfo.bot_name||"麦麦"," 对话吧!"]})]}),h?.messages.map(F=>e.jsxs("div",{className:H("flex gap-2 sm:gap-3",F.type==="user"&&"flex-row-reverse",F.type==="system"&&"justify-center",F.type==="error"&&"justify-center"),children:[F.type==="system"&&e.jsx("div",{className:"text-xs text-muted-foreground bg-muted/50 px-3 py-1 rounded-full max-w-[90%]",children:F.content}),F.type==="error"&&e.jsx("div",{className:"text-xs text-red-600 dark:text-red-400 bg-red-100 dark:bg-red-900/30 px-3 py-1 rounded-full max-w-[90%]",children:F.content}),F.type==="thinking"&&e.jsxs(e.Fragment,{children:[e.jsx(jr,{className:"h-7 w-7 sm:h-8 sm:w-8 shrink-0",children:e.jsx(vr,{className:"bg-primary/10 text-primary",children:e.jsx(fr,{className:"h-3.5 w-3.5 sm:h-4 sm:w-4"})})}),e.jsxs("div",{className:"flex flex-col gap-1 max-w-[75%] sm:max-w-[70%]",children:[e.jsx("div",{className:"flex items-center gap-2 text-[10px] sm:text-xs text-muted-foreground",children:e.jsx("span",{className:"hidden sm:inline",children:F.sender?.name||h?.sessionInfo.bot_name})}),e.jsx("div",{className:"bg-muted rounded-2xl rounded-tl-sm px-4 py-3",children:e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsxs("div",{className:"flex gap-1",children:[e.jsx("span",{className:"w-2 h-2 bg-primary/60 rounded-full animate-bounce",style:{animationDelay:"0ms"}}),e.jsx("span",{className:"w-2 h-2 bg-primary/60 rounded-full animate-bounce",style:{animationDelay:"150ms"}}),e.jsx("span",{className:"w-2 h-2 bg-primary/60 rounded-full animate-bounce",style:{animationDelay:"300ms"}})]}),e.jsx("span",{className:"text-xs text-muted-foreground ml-1",children:"思考中..."})]})})]})]}),(F.type==="user"||F.type==="bot")&&e.jsxs(e.Fragment,{children:[e.jsx(jr,{className:"h-7 w-7 sm:h-8 sm:w-8 shrink-0",children:e.jsx(vr,{className:H("text-xs",F.type==="bot"?"bg-primary/10 text-primary":"bg-secondary text-secondary-foreground"),children:F.type==="bot"?e.jsx(fr,{className:"h-3.5 w-3.5 sm:h-4 sm:w-4"}):e.jsx(oo,{className:"h-3.5 w-3.5 sm:h-4 sm:w-4"})})}),e.jsxs("div",{className:H("flex flex-col gap-1 max-w-[75%] sm:max-w-[70%]",F.type==="user"&&"items-end"),children:[e.jsxs("div",{className:"flex items-center gap-2 text-[10px] sm:text-xs text-muted-foreground",children:[e.jsx("span",{className:"hidden sm:inline",children:F.sender?.name||(F.type==="bot"?h?.sessionInfo.bot_name:S)}),e.jsx("span",{children:pe(F.timestamp)})]}),e.jsx("div",{className:H("rounded-2xl px-3 py-2 text-sm break-words",F.type==="bot"?"bg-muted rounded-tl-sm":"bg-primary text-primary-foreground rounded-tr-sm"),children:e.jsx(vS,{message:F,isBot:F.type==="bot"})})]})]})]},F.id)),e.jsx("div",{ref:L})]})})}),e.jsx("div",{className:"shrink-0 border-t bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60",children:e.jsx("div",{className:"p-3 sm:p-4 max-w-4xl mx-auto",children:e.jsxs("div",{className:"flex gap-2",children:[e.jsx(ie,{value:f,onChange:F=>g(F.target.value),onKeyDown:ls,placeholder:h?.isConnected?"输入消息...":"等待连接...",disabled:!h?.isConnected,className:"flex-1 h-10 sm:h-10"}),e.jsx(C,{onClick:fe,disabled:!h?.isConnected||!f.trim(),size:"icon",className:"h-10 w-10 shrink-0",children:e.jsx(e0,{className:"h-4 w-4"})})]})})})]})}var Nm="Radio",[NS,Oj]=wg(Nm),[yS,wS]=NS(Nm),Dj=m.forwardRef((l,i)=>{const{__scopeRadio:r,name:o,checked:u=!1,required:x,disabled:h,value:f="on",onCheck:g,form:j,...v}=l,[y,b]=m.useState(null),S=nm(i,A=>b(A)),w=m.useRef(!1),O=y?j||!!y.closest("form"):!0;return e.jsxs(yS,{scope:r,checked:u,disabled:h,children:[e.jsx(fo.button,{type:"button",role:"radio","aria-checked":u,"data-state":Bj(u),"data-disabled":h?"":void 0,disabled:h,value:f,...v,ref:S,onClick:Zu(l.onClick,A=>{u||g?.(),O&&(w.current=A.isPropagationStopped(),w.current||A.stopPropagation())})}),O&&e.jsx(Uj,{control:y,bubbles:!w.current,name:o,value:f,checked:u,required:x,disabled:h,form:j,style:{transform:"translateX(-100%)"}})]})});Dj.displayName=Nm;var Rj="RadioIndicator",Lj=m.forwardRef((l,i)=>{const{__scopeRadio:r,forceMount:o,...u}=l,x=wS(Rj,r);return e.jsx(by,{present:o||x.checked,children:e.jsx(fo.span,{"data-state":Bj(x.checked),"data-disabled":x.disabled?"":void 0,...u,ref:i})})});Lj.displayName=Rj;var _S="RadioBubbleInput",Uj=m.forwardRef(({__scopeRadio:l,control:i,checked:r,bubbles:o=!0,...u},x)=>{const h=m.useRef(null),f=nm(h,x),g=Ny(r),j=yy(i);return m.useEffect(()=>{const v=h.current;if(!v)return;const y=window.HTMLInputElement.prototype,S=Object.getOwnPropertyDescriptor(y,"checked").set;if(g!==r&&S){const w=new Event("click",{bubbles:o});S.call(v,r),v.dispatchEvent(w)}},[g,r,o]),e.jsx(fo.input,{type:"radio","aria-hidden":!0,defaultChecked:r,...u,tabIndex:-1,ref:f,style:{...u.style,...j,position:"absolute",pointerEvents:"none",opacity:0,margin:0}})});Uj.displayName=_S;function Bj(l){return l?"checked":"unchecked"}var SS=["ArrowUp","ArrowDown","ArrowLeft","ArrowRight"],_o="RadioGroup",[CS]=wg(_o,[og,Oj]),Hj=og(),$j=Oj(),[kS,TS]=CS(_o),qj=m.forwardRef((l,i)=>{const{__scopeRadioGroup:r,name:o,defaultValue:u,value:x,required:h=!1,disabled:f=!1,orientation:g,dir:j,loop:v=!0,onValueChange:y,...b}=l,S=Hj(r),w=jy(j),[O,A]=vy({prop:x,defaultProp:u??null,onChange:y,caller:_o});return e.jsx(kS,{scope:r,name:o,required:h,disabled:f,value:O,onValueChange:A,children:e.jsx(XN,{asChild:!0,...S,orientation:g,dir:w,loop:v,children:e.jsx(fo.div,{role:"radiogroup","aria-required":h,"aria-orientation":g,"data-disabled":f?"":void 0,dir:w,...b,ref:i})})})});qj.displayName=_o;var Gj="RadioGroupItem",Vj=m.forwardRef((l,i)=>{const{__scopeRadioGroup:r,disabled:o,...u}=l,x=TS(Gj,r),h=x.disabled||o,f=Hj(r),g=$j(r),j=m.useRef(null),v=nm(i,j),y=x.value===u.value,b=m.useRef(!1);return m.useEffect(()=>{const S=O=>{SS.includes(O.key)&&(b.current=!0)},w=()=>b.current=!1;return document.addEventListener("keydown",S),document.addEventListener("keyup",w),()=>{document.removeEventListener("keydown",S),document.removeEventListener("keyup",w)}},[]),e.jsx(PN,{asChild:!0,...f,focusable:!h,active:y,children:e.jsx(Dj,{disabled:h,required:x.required,checked:y,...g,...u,name:x.name,ref:v,onCheck:()=>x.onValueChange(u.value),onKeyDown:Zu(S=>{S.key==="Enter"&&S.preventDefault()}),onFocus:Zu(u.onFocus,()=>{b.current&&j.current?.click()})})})});Vj.displayName=Gj;var ES="RadioGroupIndicator",Fj=m.forwardRef((l,i)=>{const{__scopeRadioGroup:r,...o}=l,u=$j(r);return e.jsx(Lj,{...u,...o,ref:i})});Fj.displayName=ES;var Ij=qj,Qj=Vj,zS=Fj;const Yj=m.forwardRef(({className:l,...i},r)=>e.jsx(Ij,{className:H("grid gap-2",l),...i,ref:r}));Yj.displayName=Ij.displayName;const Kj=m.forwardRef(({className:l,...i},r)=>e.jsx(Qj,{ref:r,className:H("aspect-square h-4 w-4 rounded-full border border-primary text-primary shadow focus:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50",l),...i,children:e.jsx(zS,{className:"flex items-center justify-center",children:e.jsx(s0,{className:"h-2.5 w-2.5 fill-current text-current"})})}));Kj.displayName=Qj.displayName;function MS({question:l,value:i,onChange:r,error:o,disabled:u=!1}){const[x,h]=m.useState(null),f=u||l.readOnly,g=()=>{switch(l.type){case"single":return e.jsx(Yj,{value:i||"",onValueChange:r,disabled:f,className:"space-y-2",children:l.options?.map(j=>e.jsxs("div",{className:"flex items-center space-x-2",children:[e.jsx(Kj,{value:j.value,id:`${l.id}-${j.id}`}),e.jsx(k,{htmlFor:`${l.id}-${j.id}`,className:"cursor-pointer font-normal",children:j.label})]},j.id))});case"multiple":{const j=i||[];return e.jsxs("div",{className:"space-y-2",children:[l.options?.map(v=>e.jsxs("div",{className:"flex items-center space-x-2",children:[e.jsx(jt,{id:`${l.id}-${v.id}`,checked:j.includes(v.value),disabled:f||l.maxSelections!==void 0&&j.length>=l.maxSelections&&!j.includes(v.value),onCheckedChange:y=>{r(y?[...j,v.value]:j.filter(b=>b!==v.value))}}),e.jsx(k,{htmlFor:`${l.id}-${v.id}`,className:"cursor-pointer font-normal",children:v.label})]},v.id)),l.maxSelections&&e.jsxs("p",{className:"text-xs text-muted-foreground",children:["最多选择 ",l.maxSelections," 项"]})]})}case"text":return e.jsx(ie,{value:i||"",onChange:j=>r(j.target.value),placeholder:l.placeholder||"请输入...",disabled:f,readOnly:l.readOnly,maxLength:l.maxLength,className:H(l.readOnly&&"bg-muted cursor-not-allowed")});case"textarea":return e.jsxs("div",{className:"space-y-1",children:[e.jsx(Ys,{value:i||"",onChange:j=>r(j.target.value),placeholder:l.placeholder||"请输入...",disabled:f,readOnly:l.readOnly,maxLength:l.maxLength,rows:4,className:H(l.readOnly&&"bg-muted cursor-not-allowed")}),l.maxLength&&e.jsxs("p",{className:"text-xs text-muted-foreground text-right",children:[(i||"").length," / ",l.maxLength]})]});case"rating":{const j=i||0,v=x!==null?x:j;return e.jsxs("div",{className:"flex items-center gap-1",children:[[1,2,3,4,5].map(y=>e.jsx("button",{type:"button",disabled:f,className:H("p-1 transition-colors focus:outline-none focus:ring-2 focus:ring-ring rounded",f&&"cursor-not-allowed opacity-50"),onMouseEnter:()=>!f&&h(y),onMouseLeave:()=>h(null),onClick:()=>!f&&r(y),children:e.jsx(xl,{className:H("h-6 w-6 transition-colors",y<=v?"fill-yellow-400 text-yellow-400":"text-muted-foreground")})},y)),j>0&&e.jsxs("span",{className:"ml-2 text-sm text-muted-foreground",children:[j," / 5"]})]})}case"scale":{const j=l.min??1,v=l.max??10,y=l.step??1,b=i??j;return e.jsxs("div",{className:"space-y-4",children:[e.jsx(ma,{value:[b],onValueChange:([S])=>r(S),min:j,max:v,step:y,disabled:f}),e.jsxs("div",{className:"flex justify-between text-xs text-muted-foreground",children:[e.jsx("span",{children:l.minLabel||j}),e.jsx("span",{className:"font-medium text-foreground",children:b}),e.jsx("span",{children:l.maxLabel||v})]})]})}case"dropdown":return e.jsxs(Ue,{value:i||"",onValueChange:r,disabled:f,children:[e.jsx(Re,{children:e.jsx(Be,{placeholder:l.placeholder||"请选择..."})}),e.jsx(Le,{children:l.options?.map(j=>e.jsx(ee,{value:j.value,children:j.label},j.id))})]});default:return e.jsx("div",{className:"text-muted-foreground",children:"不支持的问题类型"})}};return e.jsxs("div",{className:"space-y-3",children:[e.jsxs("div",{className:"space-y-1",children:[e.jsxs(k,{className:"text-base font-medium",children:[l.title,l.required&&e.jsx("span",{className:"text-destructive ml-1",children:"*"})]}),l.description&&e.jsx("p",{className:"text-sm text-muted-foreground",children:l.description})]}),g(),o&&e.jsx("p",{className:"text-sm text-destructive",children:o})]})}const Xj="https://maibot-plugin-stats.maibot-webui.workers.dev";function Pj(){const l="maibot_user_id";let i=localStorage.getItem(l);if(!i){const r=Math.random().toString(36).substring(2,10),o=Date.now().toString(36),u=Math.random().toString(36).substring(2,10);i=`fp_${r}_${o}_${u}`,localStorage.setItem(l,i)}return i}async function AS(l,i,r,o){try{const u=o?.userId||Pj(),x={surveyId:l,surveyVersion:i,userId:u,answers:r,submittedAt:new Date().toISOString(),allowMultiple:o?.allowMultiple,metadata:{userAgent:navigator.userAgent,language:navigator.language}},h=await fetch(`${Xj}/survey/submit`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(x)}),f=await h.json();return h.status===429?{success:!1,error:"提交过于频繁,请稍后再试"}:h.status===409?{success:!1,error:f.error||"你已经提交过这份问卷了"}:h.ok?{success:!0,submissionId:f.submissionId,message:f.message}:{success:!1,error:f.error||"提交失败"}}catch(u){return console.error("Error submitting survey:",u),{success:!1,error:"网络错误"}}}async function OS(l,i){try{const r=i||Pj(),o=new URLSearchParams({user_id:r,survey_id:l}),u=await fetch(`${Xj}/survey/check?${o}`);return u.ok?{success:!0,hasSubmitted:(await u.json()).hasSubmitted}:{success:!1,error:(await u.json()).error||"检查失败"}}catch(r){return console.error("Error checking submission:",r),{success:!1,error:"网络错误"}}}function Jj({config:l,initialAnswers:i,onSubmitSuccess:r,onSubmitError:o,showProgress:u=!0,paginateQuestions:x=!1,className:h}){const f=m.useCallback(()=>!i||i.length===0?{}:i.reduce((X,L)=>(X[L.questionId]=L.value,X),{}),[i]),[g,j]=m.useState(()=>f()),[v,y]=m.useState({}),[b,S]=m.useState(0),[w,O]=m.useState(!1),[A,D]=m.useState(!1),[V,z]=m.useState(null),[_,T]=m.useState(null),[$,E]=m.useState(!1),[se,te]=m.useState(!0);m.useEffect(()=>{i&&i.length>0&&j(X=>({...X,...f()}))},[i,f]),m.useEffect(()=>{(async()=>{if(!l.settings?.allowMultiple){const L=await OS(l.id);L.success&&L.hasSubmitted&&E(!0)}te(!1)})()},[l.id,l.settings?.allowMultiple]);const ne=m.useCallback(()=>{const X=new Date;return!(l.settings?.startTime&&new Date(l.settings.startTime)>X||l.settings?.endTime&&new Date(l.settings.endTime){const L=g[X.id];return L==null?!1:Array.isArray(L)?L.length>0:typeof L=="string"?L.trim()!=="":!0}).length,Se=ue/l.questions.length*100,oe=m.useCallback((X,L)=>{j(B=>({...B,[X]:L})),y(B=>{const _e={...B};return delete _e[X],_e})},[]),je=m.useCallback(()=>{const X={};for(const L of l.questions){if(L.required){const B=g[L.id];if(B==null){X[L.id]="此题为必填项";continue}if(Array.isArray(B)&&B.length===0){X[L.id]="请至少选择一项";continue}if(typeof B=="string"&&B.trim()===""){X[L.id]="此题为必填项";continue}}L.minLength&&typeof g[L.id]=="string"&&g[L.id].length{if(!je()){if(x){const X=l.questions.findIndex(L=>v[L.id]);X>=0&&S(X)}return}O(!0),z(null);try{const X=l.questions.filter(B=>g[B.id]!==void 0).map(B=>({questionId:B.id,value:g[B.id]})),L=await AS(l.id,l.version,X,{allowMultiple:l.settings?.allowMultiple});if(L.success&&L.submissionId)D(!0),T(L.submissionId),r?.(L.submissionId);else{const B=L.error||"提交失败";z(B),o?.(B)}}catch(X){const L=X instanceof Error?X.message:"提交失败";z(L),o?.(L)}finally{O(!1)}},[je,x,l,g,v,r,o]),U=m.useCallback(X=>{X>=0&&Xe.jsxs("div",{className:H("p-4 rounded-lg border bg-card",v[X.id]?"border-destructive bg-destructive/5":"border-border"),children:[x&&e.jsxs("div",{className:"text-xs text-muted-foreground mb-2",children:["问题 ",b+1," / ",l.questions.length]}),!x&&e.jsxs("div",{className:"text-xs text-muted-foreground mb-2",children:[L+1,"."]}),e.jsx(MS,{question:X,value:g[X.id],onChange:B=>oe(X.id,B),error:v[X.id],disabled:w})]},X.id)),V&&e.jsxs(sa,{variant:"destructive",children:[e.jsx(Ot,{className:"h-4 w-4"}),e.jsx(ta,{children:V})]}),e.jsx("div",{className:"flex justify-between items-center py-4",children:x?e.jsxs(e.Fragment,{children:[e.jsxs(C,{variant:"outline",onClick:()=>U(b-1),disabled:b===0||w,children:[e.jsx(pl,{className:"h-4 w-4 mr-1"}),"上一题"]}),b===l.questions.length-1?e.jsxs(C,{onClick:be,disabled:w,children:[w&&e.jsx(tt,{className:"h-4 w-4 mr-2 animate-spin"}),"提交问卷"]}):e.jsxs(C,{onClick:()=>U(b+1),disabled:w,children:["下一题",e.jsx(Ya,{className:"h-4 w-4 ml-1"})]})]}):e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"text-sm text-muted-foreground",children:Object.keys(v).length>0&&e.jsxs("span",{className:"text-destructive",children:["还有 ",Object.keys(v).length," 个必填项未完成"]})}),e.jsxs(C,{onClick:be,disabled:w,size:"lg",children:[w&&e.jsx(tt,{className:"h-4 w-4 mr-2 animate-spin"}),"提交问卷"]})]})})]})})]})}const DS={id:"webui-feedback-v1",version:"1.0.0",title:"麦麦 WebUI 使用反馈问卷",description:"感谢您使用麦麦 WebUI!您的反馈将帮助我们不断改进产品体验。",questions:[{id:"webui_version",type:"text",title:"你正在使用的 WebUI 版本",description:"此项由系统自动填写",required:!0,readOnly:!0,placeholder:"自动检测中..."},{id:"ui_design_satisfaction",type:"single",title:"你觉得当前的 WebUI 界面设计如何?",required:!0,options:[{id:"very_satisfied",label:"非常满意",value:"very_satisfied"},{id:"satisfied",label:"满意",value:"satisfied"},{id:"neutral",label:"一般",value:"neutral"},{id:"dissatisfied",label:"不满意",value:"dissatisfied"},{id:"very_dissatisfied",label:"非常不满意",value:"very_dissatisfied"}]},{id:"problems_encountered",type:"multiple",title:"你在使用 WebUI 时遇到过哪些问题?",description:"可多选",required:!0,options:[{id:"lag",label:"界面卡顿",value:"lag"},{id:"incomplete",label:"功能不完整",value:"incomplete"},{id:"complex",label:"操作复杂",value:"complex"},{id:"bugs",label:"存在 Bug",value:"bugs"},{id:"none",label:"没有遇到问题",value:"none"},{id:"other",label:"其他",value:"other"}]},{id:"problems_other",type:"text",title:'如选择"其他",请说明遇到的问题',required:!1,placeholder:"请描述你遇到的其他问题...",maxLength:500},{id:"useful_features",type:"textarea",title:"你觉得哪些功能是最有用的?",required:!0,placeholder:"请分享你认为最有价值的功能...",maxLength:1e3},{id:"feature_requests",type:"textarea",title:"你希望在未来的版本中增加哪些功能?",required:!0,placeholder:"请告诉我们你期望的新功能...",maxLength:1e3},{id:"overall_satisfaction",type:"single",title:"你对麦麦 WebUI 的整体满意度如何?",required:!0,options:[{id:"very_satisfied",label:"非常满意",value:"very_satisfied"},{id:"satisfied",label:"满意",value:"satisfied"},{id:"neutral",label:"一般",value:"neutral"},{id:"dissatisfied",label:"不满意",value:"dissatisfied"},{id:"very_dissatisfied",label:"非常不满意",value:"very_dissatisfied"}]},{id:"would_recommend",type:"single",title:"你愿意推荐麦麦 WebUI 给其他人使用吗?",required:!0,options:[{id:"yes",label:"是",value:"yes"},{id:"no",label:"否",value:"no"}]},{id:"other_suggestions",type:"textarea",title:"其他建议或意见",description:"此项为选填",required:!1,placeholder:"如果你有任何其他想法或建议,请在此分享...",maxLength:2e3}],settings:{allowMultiple:!1,thankYouMessage:"感谢你的反馈!你的意见对我们非常重要,我们会认真考虑每一条建议。"}},RS={id:"maibot-feedback-v1",version:"1.0.0",title:"麦麦使用体验反馈问卷",description:"感谢您使用麦麦!您的反馈将帮助我们打造更好的 AI 伙伴。",questions:[{id:"maibot_version",type:"text",title:"你正在使用的麦麦版本",description:"此项由系统自动填写",required:!0,readOnly:!0,placeholder:"自动检测中..."},{id:"improvement_areas",type:"textarea",title:"你认为麦麦还有哪些部分可以改进?",required:!0,placeholder:"请分享你认为可以改进的方面...",maxLength:1e3},{id:"problems_encountered",type:"multiple",title:"你在使用麦麦时遇到过哪些问题?",description:"可多选",required:!0,options:[{id:"incomplete",label:"功能不完整",value:"incomplete"},{id:"slow_response",label:"响应速度慢",value:"slow_response"},{id:"complex",label:"操作复杂",value:"complex"},{id:"unstable",label:"运行不稳定",value:"unstable"},{id:"config_difficult",label:"配置困难",value:"config_difficult"},{id:"none",label:"没有遇到问题",value:"none"},{id:"other",label:"其他",value:"other"}]},{id:"problems_other",type:"text",title:'如选择"其他",请说明遇到的问题',required:!1,placeholder:"请描述你遇到的其他问题...",maxLength:500},{id:"helpful_features",type:"textarea",title:"你觉得麦麦的哪些功能对你最有帮助?",required:!0,placeholder:"请分享对你最有帮助的功能...",maxLength:1e3},{id:"feature_requests",type:"textarea",title:"你希望在未来的版本中增加哪些功能?",required:!0,placeholder:"请告诉我们你期望的新功能...",maxLength:1e3},{id:"overall_satisfaction",type:"single",title:"你对麦麦的整体满意度如何?",required:!0,options:[{id:"very_satisfied",label:"非常满意",value:"very_satisfied"},{id:"satisfied",label:"满意",value:"satisfied"},{id:"neutral",label:"一般",value:"neutral"},{id:"dissatisfied",label:"不满意",value:"dissatisfied"},{id:"very_dissatisfied",label:"非常不满意",value:"very_dissatisfied"}]},{id:"would_recommend",type:"single",title:"你愿意推荐麦麦给其他人使用吗?",required:!0,options:[{id:"yes",label:"是",value:"yes"},{id:"no",label:"否",value:"no"}]},{id:"other_suggestions",type:"textarea",title:"其他建议或意见",description:"此项为选填",required:!1,placeholder:"如果你有任何其他想法或建议,请在此分享...",maxLength:2e3}],settings:{allowMultiple:!1,thankYouMessage:"感谢你的反馈!你的意见对麦麦的成长非常重要,我们会认真考虑每一条建议。"}};function LS(){const[l,i]=m.useState(null),[r,o]=m.useState(!0);m.useEffect(()=>{const f=JSON.parse(JSON.stringify(DS));i(f),o(!1)},[]);const u=m.useMemo(()=>[{questionId:"webui_version",value:`v${go}`}],[]),x=m.useCallback(f=>{console.log("WebUI Survey submitted:",f)},[]),h=m.useCallback(f=>{console.error("WebUI Survey submission error:",f)},[]);return r?e.jsx("div",{className:"flex items-center justify-center min-h-[400px]",children:e.jsx(tt,{className:"h-8 w-8 animate-spin text-muted-foreground"})}):l?e.jsxs("div",{className:"h-[calc(100vh-4rem)] flex flex-col p-4 sm:p-6",children:[e.jsxs("div",{className:"mb-4 sm:mb-6 shrink-0",children:[e.jsxs("h1",{className:"text-2xl sm:text-3xl font-bold flex items-center gap-2",children:[e.jsx(qg,{className:"h-8 w-8",strokeWidth:2}),"WebUI 使用反馈问卷"]}),e.jsx("p",{className:"text-muted-foreground mt-1 text-sm sm:text-base",children:"感谢您的反馈,帮助我们持续改进产品体验"})]}),e.jsx("div",{className:"flex-1 min-h-0",children:e.jsx(Jj,{config:l,initialAnswers:u,showProgress:!0,paginateQuestions:!1,onSubmitSuccess:x,onSubmitError:h})})]}):e.jsxs("div",{className:"flex flex-col items-center justify-center min-h-[400px] gap-4",children:[e.jsxs(sa,{variant:"destructive",className:"max-w-md",children:[e.jsx(Ot,{className:"h-4 w-4"}),e.jsx(ta,{children:"无法加载问卷配置"})]}),e.jsx(C,{variant:"outline",onClick:()=>window.location.reload(),children:"重试"})]})}function US(){const[l,i]=m.useState(null),[r,o]=m.useState(!0),[u,x]=m.useState("未知版本");m.useEffect(()=>{(async()=>{try{const y=await V0();x(y.version||"未知版本")}catch(y){console.error("Failed to get MaiBot version:",y),x("获取失败")}const v=JSON.parse(JSON.stringify(RS));i(v),o(!1)})()},[]);const h=m.useMemo(()=>[{questionId:"maibot_version",value:u}],[u]),f=m.useCallback(j=>{console.log("MaiBot Survey submitted:",j)},[]),g=m.useCallback(j=>{console.error("MaiBot Survey submission error:",j)},[]);return r?e.jsx("div",{className:"flex items-center justify-center min-h-[400px]",children:e.jsx(tt,{className:"h-8 w-8 animate-spin text-muted-foreground"})}):l?e.jsxs("div",{className:"h-[calc(100vh-4rem)] flex flex-col p-4 sm:p-6",children:[e.jsxs("div",{className:"mb-4 sm:mb-6 shrink-0",children:[e.jsxs("h1",{className:"text-2xl sm:text-3xl font-bold flex items-center gap-2",children:[e.jsx(qg,{className:"h-8 w-8",strokeWidth:2}),"麦麦使用体验反馈问卷"]}),e.jsx("p",{className:"text-muted-foreground mt-1 text-sm sm:text-base",children:"感谢您的反馈,帮助我们打造更好的 AI 伙伴"})]}),e.jsx("div",{className:"flex-1 min-h-0",children:e.jsx(Jj,{config:l,initialAnswers:h,showProgress:!0,paginateQuestions:!1,onSubmitSuccess:f,onSubmitError:g})})]}):e.jsxs("div",{className:"flex flex-col items-center justify-center min-h-[400px] gap-4",children:[e.jsxs(sa,{variant:"destructive",className:"max-w-md",children:[e.jsx(Ot,{className:"h-4 w-4"}),e.jsx(ta,{children:"无法加载问卷配置"})]}),e.jsx(C,{variant:"outline",onClick:()=>window.location.reload(),children:"重试"})]})}function BS(){const l=ka(),[i,r]=m.useState(!0);return m.useEffect(()=>{let o=!1;return(async()=>{try{const x=await om();!o&&!x&&l({to:"/auth"})}catch{o||l({to:"/auth"})}finally{o||r(!1)}})(),()=>{o=!0}},[l]),{checking:i}}async function HS(){return await om()}const $S=gi("pointer-events-none inline-flex select-none items-center gap-1 rounded border bg-muted px-1.5 font-mono font-medium opacity-100",{variants:{size:{sm:"h-5 text-[10px]",default:"h-6 text-xs",lg:"h-7 text-sm"}},defaultVariants:{size:"default"}}),Zj=m.forwardRef(({className:l,size:i,abbrTitle:r,children:o,...u},x)=>e.jsx("kbd",{className:H($S({size:i,className:l})),ref:x,...u,children:r?e.jsx("abbr",{title:r,children:o}):o}));Zj.displayName="Kbd";const qS=[{icon:po,title:"首页",description:"查看仪表板概览",path:"/",category:"概览"},{icon:Aa,title:"麦麦主程序配置",description:"配置麦麦的核心设置",path:"/config/bot",category:"配置"},{icon:Gg,title:"麦麦模型提供商配置",description:"配置模型提供商",path:"/config/modelProvider",category:"配置"},{icon:Vg,title:"麦麦模型配置",description:"配置模型参数",path:"/config/model",category:"配置"},{icon:im,title:"表情包管理",description:"管理麦麦的表情包",path:"/resource/emoji",category:"资源"},{icon:Fl,title:"表达方式管理",description:"管理麦麦的表达方式",path:"/resource/expression",category:"资源"},{icon:Fg,title:"人物信息管理",description:"管理人物信息",path:"/resource/person",category:"资源"},{icon:pi,title:"黑话管理",description:"管理麦麦学习到的黑话和俚语",path:"/resource/jargon",category:"资源"},{icon:t0,title:"统计信息",description:"查看使用统计",path:"/statistics",category:"监控"},{icon:Vl,title:"插件市场",description:"浏览和安装插件",path:"/plugins",category:"扩展"},{icon:rm,title:"日志查看器",description:"查看系统日志",path:"/logs",category:"监控"},{icon:ji,title:"系统设置",description:"配置系统参数",path:"/settings",category:"系统"}];function GS({open:l,onOpenChange:i}){const[r,o]=m.useState(""),[u,x]=m.useState(0),h=ka(),f=qS.filter(v=>v.title.toLowerCase().includes(r.toLowerCase())||v.description.toLowerCase().includes(r.toLowerCase())||v.category.toLowerCase().includes(r.toLowerCase()));m.useEffect(()=>{l&&(o(""),x(0))},[l]);const g=m.useCallback(v=>{h({to:v}),i(!1)},[h,i]),j=m.useCallback(v=>{v.key==="ArrowDown"?(v.preventDefault(),x(y=>(y+1)%f.length)):v.key==="ArrowUp"?(v.preventDefault(),x(y=>(y-1+f.length)%f.length)):v.key==="Enter"&&f[u]&&(v.preventDefault(),g(f[u].path))},[f,u,g]);return e.jsx(Qs,{open:l,onOpenChange:i,children:e.jsxs(qs,{className:"max-w-2xl p-0 gap-0",children:[e.jsxs(Gs,{className:"px-4 pt-4 pb-0",children:[e.jsx(Vs,{className:"sr-only",children:"搜索"}),e.jsxs("div",{className:"relative",children:[e.jsx($t,{className:"absolute left-3 top-1/2 h-5 w-5 -translate-y-1/2 text-muted-foreground"}),e.jsx(ie,{value:r,onChange:v=>{o(v.target.value),x(0)},onKeyDown:j,placeholder:"搜索页面...",className:"h-12 pl-11 text-base border-0 focus-visible:ring-0 shadow-none",autoFocus:!0})]})]}),e.jsx("div",{className:"border-t",children:e.jsx(Ze,{className:"h-[400px]",children:f.length>0?e.jsx("div",{className:"p-2",children:f.map((v,y)=>{const b=v.icon;return e.jsxs("button",{onClick:()=>g(v.path),onMouseEnter:()=>x(y),className:H("w-full flex items-center gap-3 px-3 py-2.5 rounded-md text-left transition-colors",y===u?"bg-accent text-accent-foreground":"hover:bg-accent/50"),children:[e.jsx(b,{className:"h-5 w-5 flex-shrink-0"}),e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsx("div",{className:"font-medium text-sm",children:v.title}),e.jsx("div",{className:"text-xs text-muted-foreground truncate",children:v.description})]}),e.jsx("div",{className:"text-xs text-muted-foreground px-2 py-1 bg-muted rounded",children:v.category})]},v.path)})}):e.jsxs("div",{className:"flex flex-col items-center justify-center py-12 text-center",children:[e.jsx($t,{className:"h-12 w-12 text-muted-foreground/50 mb-4"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:r?"未找到匹配的页面":"输入关键词开始搜索"})]})})}),e.jsx("div",{className:"border-t px-4 py-3 flex items-center justify-between text-xs text-muted-foreground",children:e.jsxs("div",{className:"flex items-center gap-4",children:[e.jsxs("span",{className:"flex items-center gap-1",children:[e.jsx("kbd",{className:"px-1.5 py-0.5 bg-muted rounded border",children:"↑"}),e.jsx("kbd",{className:"px-1.5 py-0.5 bg-muted rounded border",children:"↓"}),"导航"]}),e.jsxs("span",{className:"flex items-center gap-1",children:[e.jsx("kbd",{className:"px-1.5 py-0.5 bg-muted rounded border",children:"Enter"}),"选择"]}),e.jsxs("span",{className:"flex items-center gap-1",children:[e.jsx("kbd",{className:"px-1.5 py-0.5 bg-muted rounded border",children:"Esc"}),"关闭"]})]})})]})})}const VS=_y,FS=Sy,IS=Cy,Wj=m.forwardRef(({className:l,sideOffset:i=4,...r},o)=>e.jsx(wy,{children:e.jsx(_g,{ref:o,sideOffset:i,className:H("z-50 overflow-hidden rounded-md bg-primary px-3 py-1.5 text-xs text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-tooltip-content-transform-origin]",l),...r})}));Wj.displayName=_g.displayName;function QS({children:l}){const{checking:i}=BS(),[r,o]=m.useState(!0),[u,x]=m.useState(!1),[h,f]=m.useState(!1),{theme:g,setTheme:j}=dm(),v=bN();if(m.useEffect(()=>{const O=A=>{(A.metaKey||A.ctrlKey)&&A.key==="k"&&(A.preventDefault(),f(!0))};return window.addEventListener("keydown",O),()=>window.removeEventListener("keydown",O)},[]),i)return e.jsx("div",{className:"flex h-screen items-center justify-center bg-background",children:e.jsx("div",{className:"text-muted-foreground",children:"正在验证登录状态..."})});const y=[{title:"概览",items:[{icon:po,label:"首页",path:"/"}]},{title:"麦麦配置编辑",items:[{icon:Aa,label:"麦麦主程序配置",path:"/config/bot"},{icon:Gg,label:"AI模型厂商配置",path:"/config/modelProvider",tourId:"sidebar-model-provider"},{icon:Vg,label:"模型管理与分配",path:"/config/model",tourId:"sidebar-model-management"},{icon:pp,label:"麦麦适配器配置",path:"/config/adapter"}]},{title:"麦麦资源管理",items:[{icon:im,label:"表情包管理",path:"/resource/emoji"},{icon:Fl,label:"表达方式管理",path:"/resource/expression"},{icon:pi,label:"黑话管理",path:"/resource/jargon"},{icon:Fg,label:"人物信息管理",path:"/resource/person"},{icon:Bg,label:"知识库图谱可视化",path:"/resource/knowledge-graph"}]},{title:"扩展与监控",items:[{icon:Vl,label:"插件市场",path:"/plugins"},{icon:$g,label:"模型分配预设市场",path:"/model-presets"},{icon:pp,label:"插件配置",path:"/plugin-config"},{icon:rm,label:"日志查看器",path:"/logs"},{icon:Fl,label:"本地聊天室",path:"/chat"}]},{title:"系统",items:[{icon:ji,label:"系统设置",path:"/settings"}]}],S=g==="system"?window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light":g,w=async()=>{await U0()};return e.jsx(VS,{delayDuration:300,children:e.jsxs("div",{className:"flex h-screen overflow-hidden",children:[e.jsxs("aside",{className:H("fixed inset-y-0 left-0 z-50 flex flex-col border-r bg-card transition-all duration-300 lg:relative lg:z-0","w-64 lg:w-auto",r?"lg:w-64":"lg:w-16",u?"translate-x-0":"-translate-x-full lg:translate-x-0"),children:[e.jsx("div",{className:"flex h-16 items-center border-b px-4",children:e.jsxs("div",{className:H("relative flex items-center justify-center flex-1 transition-all overflow-hidden","lg:flex-1",!r&&"lg:flex-none lg:w-8"),children:[e.jsxs("div",{className:H("flex items-baseline gap-2",!r&&"lg:hidden"),children:[e.jsx("span",{className:"font-bold text-xl text-primary-gradient whitespace-nowrap",children:"MaiBot WebUI"}),e.jsx("span",{className:"text-xs text-primary/60 whitespace-nowrap",children:rw()})]}),!r&&e.jsx("span",{className:"hidden lg:block font-bold text-primary-gradient text-2xl",children:"M"})]})}),e.jsx(Ze,{className:H("flex-1 overflow-x-hidden",!r&&"lg:w-16"),children:e.jsx("nav",{className:H("p-4",!r&&"lg:p-2 lg:w-16"),children:e.jsx("ul",{className:H("space-y-6",!r&&"lg:space-y-3 lg:w-full"),children:y.map((O,A)=>e.jsxs("li",{children:[e.jsx("div",{className:H("px-3 h-[1.25rem]","mb-2",!r&&"lg:mb-1 lg:invisible"),children:e.jsx("h3",{className:"text-xs font-semibold uppercase tracking-wider text-muted-foreground/60 whitespace-nowrap",children:O.title})}),!r&&A>0&&e.jsx("div",{className:"hidden lg:block mb-2 border-t border-border"}),e.jsx("ul",{className:"space-y-1",children:O.items.map(D=>{const V=v({to:D.path}),z=D.icon,_=e.jsxs(e.Fragment,{children:[V&&e.jsx("div",{className:"absolute left-0 top-1/2 h-8 w-1 -translate-y-1/2 rounded-r-full bg-primary transition-opacity duration-300"}),e.jsxs("div",{className:H("flex items-center transition-all duration-300",r?"gap-3":"gap-3 lg:gap-0"),children:[e.jsx(z,{className:H("h-5 w-5 flex-shrink-0",V&&"text-primary"),strokeWidth:2,fill:"none"}),e.jsx("span",{className:H("text-sm font-medium whitespace-nowrap transition-all duration-300",V&&"font-semibold",r?"opacity-100 max-w-[200px]":"opacity-100 max-w-[200px] lg:opacity-0 lg:max-w-0 lg:overflow-hidden"),children:D.label})]})]});return e.jsx("li",{className:"relative",children:e.jsxs(FS,{children:[e.jsx(IS,{asChild:!0,children:e.jsx(ci,{to:D.path,"data-tour":D.tourId,className:H("relative flex items-center rounded-lg py-2 transition-all duration-300","hover:bg-accent hover:text-accent-foreground",V?"bg-accent text-foreground":"text-muted-foreground hover:text-foreground",r?"px-3":"px-3 lg:px-0 lg:justify-center lg:w-12 lg:mx-auto"),onClick:()=>x(!1),children:_})}),!r&&e.jsx(Wj,{side:"right",className:"hidden lg:block",children:e.jsx("p",{children:D.label})})]})},D.path)})})]},O.title))})})})]}),u&&e.jsx("div",{className:"fixed inset-0 z-40 bg-black/50 lg:hidden",onClick:()=>x(!1)}),e.jsxs("div",{className:"flex flex-1 flex-col overflow-hidden",children:[e.jsxs("header",{className:"flex h-16 items-center justify-between border-b bg-card/80 backdrop-blur-md px-4 sticky top-0 z-10",children:[e.jsxs("div",{className:"flex items-center gap-4",children:[e.jsx("button",{onClick:()=>x(!u),className:"rounded-lg p-2 hover:bg-accent lg:hidden",children:e.jsx(a0,{className:"h-5 w-5"})}),e.jsx("button",{onClick:()=>o(!r),className:"hidden rounded-lg p-2 hover:bg-accent lg:block",title:r?"收起侧边栏":"展开侧边栏",children:e.jsx(pl,{className:H("h-5 w-5 transition-transform",!r&&"rotate-180")})})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsxs("button",{onClick:()=>f(!0),className:"relative hidden md:flex items-center w-64 h-9 pl-9 pr-16 bg-background/50 border rounded-md hover:bg-accent/50 transition-colors text-left",children:[e.jsx($t,{className:"absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground"}),e.jsx("span",{className:"text-sm text-muted-foreground",children:"搜索..."}),e.jsxs(Zj,{size:"sm",className:"absolute right-2 top-1/2 -translate-y-1/2",children:[e.jsx("span",{className:"text-xs",children:"⌘"}),"K"]})]}),e.jsx(GS,{open:h,onOpenChange:f}),e.jsxs(C,{variant:"ghost",size:"sm",onClick:()=>window.open("https://docs.mai-mai.org","_blank"),className:"gap-2",title:"查看麦麦文档",children:[e.jsx(l0,{className:"h-4 w-4"}),e.jsx("span",{className:"hidden sm:inline",children:"麦麦文档"})]}),e.jsx("button",{onClick:O=>{J0(S==="dark"?"light":"dark",j,O)},className:"rounded-lg p-2 hover:bg-accent",title:S==="dark"?"切换到浅色模式":"切换到深色模式",children:S==="dark"?e.jsx(Ag,{className:"h-5 w-5"}):e.jsx(Og,{className:"h-5 w-5"})}),e.jsx("div",{className:"h-6 w-px bg-border"}),e.jsxs(C,{variant:"ghost",size:"sm",onClick:w,className:"gap-2",title:"登出系统",children:[e.jsx(n0,{className:"h-4 w-4"}),e.jsx("span",{className:"hidden sm:inline",children:"登出"})]})]})]}),e.jsx("main",{className:"flex-1 overflow-hidden bg-background",children:l})]})]})})}function YS(l){const i=l.split(` +`).slice(1),r=[];for(const o of i){const u=o.trim();if(!u.startsWith("at "))continue;const x=u.match(/at\s+(?:(.+?)\s+\()?(.+?):(\d+):(\d+)\)?$/);x?r.push({functionName:x[1]||"",fileName:x[2],lineNumber:x[3],columnNumber:x[4],raw:u}):r.push({functionName:"",fileName:"",lineNumber:"",columnNumber:"",raw:u})}return r}function KS({error:l,errorInfo:i}){const[r,o]=m.useState(!0),[u,x]=m.useState(!1),[h,f]=m.useState(!1),g=l.stack?YS(l.stack):[],j=async()=>{const v=` +Error: ${l.name} +Message: ${l.message} + +Stack Trace: +${l.stack||"No stack trace available"} + +Component Stack: +${i?.componentStack||"No component stack available"} + +URL: ${window.location.href} +User Agent: ${navigator.userAgent} +Time: ${new Date().toISOString()} + `.trim();try{await navigator.clipboard.writeText(v),f(!0),setTimeout(()=>f(!1),2e3)}catch(y){console.error("Failed to copy:",y)}};return e.jsxs("div",{className:"space-y-4",children:[e.jsxs(sa,{variant:"destructive",className:"border-red-500/50 bg-red-500/10",children:[e.jsx(Oa,{className:"h-4 w-4"}),e.jsxs(ta,{className:"font-mono text-sm",children:[e.jsxs("span",{className:"font-semibold",children:[l.name,":"]})," ",l.message]})]}),g.length>0&&e.jsxs(Tr,{open:r,onOpenChange:o,children:[e.jsx(Er,{asChild:!0,children:e.jsxs(C,{variant:"ghost",className:"w-full justify-between p-3 h-auto",children:[e.jsxs("span",{className:"font-semibold text-sm flex items-center gap-2",children:[e.jsx(i0,{className:"h-4 w-4"}),"Stack Trace (",g.length," frames)"]}),r?e.jsx(fi,{className:"h-4 w-4"}):e.jsx(Fa,{className:"h-4 w-4"})]})}),e.jsx(zr,{children:e.jsx(Ze,{className:"h-[280px] rounded-md border bg-muted/30",children:e.jsx("div",{className:"p-3 space-y-1",children:g.map((v,y)=>e.jsx("div",{className:"font-mono text-xs p-2 rounded hover:bg-muted/50 transition-colors",children:e.jsxs("div",{className:"flex items-start gap-2",children:[e.jsxs("span",{className:"text-muted-foreground w-6 text-right flex-shrink-0",children:[y+1,"."]}),e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsx("span",{className:"text-primary font-medium",children:v.functionName}),v.fileName&&e.jsxs("div",{className:"text-muted-foreground mt-0.5 break-all",children:[v.fileName,v.lineNumber&&e.jsxs("span",{className:"text-yellow-600 dark:text-yellow-400",children:[":",v.lineNumber,":",v.columnNumber]})]})]})]})},y))})})})]}),i?.componentStack&&e.jsxs(Tr,{open:u,onOpenChange:x,children:[e.jsx(Er,{asChild:!0,children:e.jsxs(C,{variant:"ghost",className:"w-full justify-between p-3 h-auto",children:[e.jsxs("span",{className:"font-semibold text-sm flex items-center gap-2",children:[e.jsx(Oa,{className:"h-4 w-4"}),"Component Stack"]}),u?e.jsx(fi,{className:"h-4 w-4"}):e.jsx(Fa,{className:"h-4 w-4"})]})}),e.jsx(zr,{children:e.jsx(Ze,{className:"h-[200px] rounded-md border bg-muted/30",children:e.jsx("pre",{className:"p-3 font-mono text-xs whitespace-pre-wrap text-muted-foreground",children:i.componentStack})})})]}),e.jsx(C,{variant:"outline",size:"sm",onClick:j,className:"w-full",children:h?e.jsxs(e.Fragment,{children:[e.jsx(ea,{className:"mr-2 h-4 w-4 text-green-500"}),"已复制到剪贴板"]}):e.jsxs(e.Fragment,{children:[e.jsx(co,{className:"mr-2 h-4 w-4"}),"复制错误信息"]})})]})}function ev({error:l,errorInfo:i}){const r=()=>{window.location.href="/"},o=()=>{window.location.reload()};return e.jsx("div",{className:"min-h-screen flex items-center justify-center bg-background p-4",children:e.jsxs(Ve,{className:"w-full max-w-2xl shadow-lg",children:[e.jsxs(rs,{className:"text-center pb-2",children:[e.jsx("div",{className:"mx-auto flex h-16 w-16 items-center justify-center rounded-full bg-red-100 dark:bg-red-900/30 mb-4",children:e.jsx(Oa,{className:"h-8 w-8 text-red-600 dark:text-red-400"})}),e.jsx(cs,{className:"text-2xl font-bold",children:"页面出现了问题"}),e.jsx(st,{className:"text-base mt-2",children:"应用程序遇到了意外错误。您可以尝试刷新页面或返回首页。"})]}),e.jsxs(gs,{className:"space-y-4",children:[e.jsx(KS,{error:l,errorInfo:i}),e.jsxs("div",{className:"flex flex-col sm:flex-row gap-2 pt-2",children:[e.jsxs(C,{onClick:o,className:"flex-1",children:[e.jsx(At,{className:"mr-2 h-4 w-4"}),"刷新页面"]}),e.jsxs(C,{onClick:r,variant:"outline",className:"flex-1",children:[e.jsx(po,{className:"mr-2 h-4 w-4"}),"返回首页"]})]}),e.jsx("p",{className:"text-xs text-center text-muted-foreground pt-2",children:"如果问题持续存在,请将错误信息复制并反馈给开发者"})]})]})})}class XS extends m.Component{constructor(i){super(i),this.state={hasError:!1,error:null,errorInfo:null}}static getDerivedStateFromError(i){return{hasError:!0,error:i}}componentDidCatch(i,r){console.error("ErrorBoundary caught an error:",i,r),this.setState({errorInfo:r})}handleReset=()=>{this.setState({hasError:!1,error:null,errorInfo:null})};render(){return this.state.hasError&&this.state.error?this.props.fallback?this.props.fallback:e.jsx(ev,{error:this.state.error,errorInfo:this.state.errorInfo}):this.props.children}}function sv({error:l}){return e.jsx(ev,{error:l,errorInfo:null})}const Rr=NN({component:()=>e.jsxs(e.Fragment,{children:[e.jsx(Vp,{}),!1]}),beforeLoad:()=>{if(window.location.pathname==="/"&&!HS())throw wN({to:"/auth"})}}),PS=lt({getParentRoute:()=>Rr,path:"/auth",component:ww}),JS=lt({getParentRoute:()=>Rr,path:"/setup",component:Hw}),wt=lt({getParentRoute:()=>Rr,id:"protected",component:()=>e.jsx(QS,{children:e.jsx(Vp,{})}),errorComponent:({error:l})=>e.jsx(sv,{error:l})}),ZS=lt({getParentRoute:()=>wt,path:"/",component:Y0}),WS=lt({getParentRoute:()=>wt,path:"/config/bot",component:b1}),e4=lt({getParentRoute:()=>wt,path:"/config/modelProvider",component:A1}),s4=lt({getParentRoute:()=>wt,path:"/config/model",component:K1}),t4=lt({getParentRoute:()=>wt,path:"/config/adapter",component:g2}),a4=lt({getParentRoute:()=>wt,path:"/resource/emoji",component:$2}),l4=lt({getParentRoute:()=>wt,path:"/resource/expression",component:Z2}),n4=lt({getParentRoute:()=>wt,path:"/resource/person",component:y_}),i4=lt({getParentRoute:()=>wt,path:"/resource/jargon",component:m_}),r4=lt({getParentRoute:()=>wt,path:"/resource/knowledge-graph",component:M_}),c4=lt({getParentRoute:()=>wt,path:"/logs",component:O_}),o4=lt({getParentRoute:()=>wt,path:"/chat",component:bS}),d4=lt({getParentRoute:()=>wt,path:"/plugins",component:lS}),u4=lt({getParentRoute:()=>wt,path:"/model-presets",component:iS}),m4=lt({getParentRoute:()=>wt,path:"/plugin-config",component:oS}),x4=lt({getParentRoute:()=>wt,path:"/plugin-mirrors",component:uS}),h4=lt({getParentRoute:()=>wt,path:"/settings",component:gw}),f4=lt({getParentRoute:()=>wt,path:"/survey/webui-feedback",component:LS}),p4=lt({getParentRoute:()=>wt,path:"/survey/maibot-feedback",component:US}),g4=lt({getParentRoute:()=>Rr,path:"*",component:fj}),j4=Rr.addChildren([PS,JS,wt.addChildren([ZS,WS,e4,s4,t4,a4,l4,i4,n4,r4,d4,u4,m4,x4,c4,o4,h4,f4,p4]),g4]),v4=yN({routeTree:j4,defaultNotFoundComponent:fj,defaultErrorComponent:({error:l})=>e.jsx(sv,{error:l})});function b4({children:l,defaultTheme:i="system",storageKey:r="ui-theme",...o}){const[u,x]=m.useState(()=>localStorage.getItem(r)||i);m.useEffect(()=>{const f=window.document.documentElement;if(f.classList.remove("light","dark"),u==="system"){const g=window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light";f.classList.add(g);return}f.classList.add(u)},[u]),m.useEffect(()=>{const f=localStorage.getItem("accent-color");if(f){const g=document.documentElement,v={blue:{hsl:"221.2 83.2% 53.3%",darkHsl:"217.2 91.2% 59.8%",gradient:null},purple:{hsl:"271 91% 65%",darkHsl:"270 95% 75%",gradient:null},green:{hsl:"142 71% 45%",darkHsl:"142 76% 36%",gradient:null},orange:{hsl:"25 95% 53%",darkHsl:"20 90% 48%",gradient:null},pink:{hsl:"330 81% 60%",darkHsl:"330 85% 70%",gradient:null},red:{hsl:"0 84% 60%",darkHsl:"0 90% 70%",gradient:null},"gradient-sunset":{hsl:"15 95% 60%",darkHsl:"15 95% 65%",gradient:"linear-gradient(135deg, hsl(25 95% 53%) 0%, hsl(330 81% 60%) 100%)"},"gradient-ocean":{hsl:"200 90% 55%",darkHsl:"200 90% 60%",gradient:"linear-gradient(135deg, hsl(221.2 83.2% 53.3%) 0%, hsl(189 94% 43%) 100%)"},"gradient-forest":{hsl:"150 70% 45%",darkHsl:"150 75% 40%",gradient:"linear-gradient(135deg, hsl(142 71% 45%) 0%, hsl(158 64% 52%) 100%)"},"gradient-aurora":{hsl:"310 85% 65%",darkHsl:"310 90% 70%",gradient:"linear-gradient(135deg, hsl(271 91% 65%) 0%, hsl(330 81% 60%) 100%)"},"gradient-fire":{hsl:"15 95% 55%",darkHsl:"15 95% 60%",gradient:"linear-gradient(135deg, hsl(0 84% 60%) 0%, hsl(25 95% 53%) 100%)"},"gradient-twilight":{hsl:"250 90% 60%",darkHsl:"250 95% 65%",gradient:"linear-gradient(135deg, hsl(239 84% 67%) 0%, hsl(271 91% 65%) 100%)"}}[f];v&&(g.style.setProperty("--primary",v.hsl),v.gradient?(g.style.setProperty("--primary-gradient",v.gradient),g.classList.add("has-gradient")):(g.style.removeProperty("--primary-gradient"),g.classList.remove("has-gradient")))}},[]);const h={theme:u,setTheme:f=>{localStorage.setItem(r,f),x(f)}};return e.jsx(oj.Provider,{...o,value:h,children:l})}function N4({children:l,defaultEnabled:i=!0,defaultWavesEnabled:r=!0,storageKey:o="enable-animations",wavesStorageKey:u="enable-waves-background"}){const[x,h]=m.useState(()=>{const v=localStorage.getItem(o);return v!==null?v==="true":i}),[f,g]=m.useState(()=>{const v=localStorage.getItem(u);return v!==null?v==="true":r});m.useEffect(()=>{const v=document.documentElement;x?v.classList.remove("no-animations"):v.classList.add("no-animations"),localStorage.setItem(o,String(x))},[x,o]),m.useEffect(()=>{localStorage.setItem(u,String(f))},[f,u]);const j={enableAnimations:x,setEnableAnimations:h,enableWavesBackground:f,setEnableWavesBackground:g};return e.jsx(dj.Provider,{value:j,children:l})}const y4=ky,tv=m.forwardRef(({className:l,...i},r)=>e.jsx(Sg,{ref:r,className:H("fixed bottom-0 right-0 z-[100] flex max-h-screen w-full flex-col-reverse p-4 sm:max-w-[420px] gap-2",l),...i}));tv.displayName=Sg.displayName;const w4=gi("group pointer-events-auto relative flex w-full items-center justify-between space-x-2 overflow-hidden rounded-md border p-4 pr-6 shadow-lg transition-all data-[swipe=cancel]:translate-x-0 data-[swipe=end]:translate-x-[var(--radix-toast-swipe-end-x)] data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)] data-[swipe=move]:transition-none data-[state=open]:animate-slide-in-from-right data-[state=open]:animate-fade-in data-[state=closed]:animate-slide-out-to-right data-[state=closed]:animate-fade-out data-[swipe=end]:animate-slide-out-to-right",{variants:{variant:{default:"border bg-primary/5 text-foreground backdrop-blur-sm",destructive:"destructive group border-destructive bg-destructive/10 text-destructive-foreground backdrop-blur-sm"}},defaultVariants:{variant:"default"}}),av=m.forwardRef(({className:l,variant:i,...r},o)=>e.jsx(Cg,{ref:o,className:H(w4({variant:i}),l),...r}));av.displayName=Cg.displayName;const _4=m.forwardRef(({className:l,...i},r)=>e.jsx(kg,{ref:r,className:H("inline-flex h-8 shrink-0 items-center justify-center rounded-md border bg-transparent px-3 text-sm font-medium transition-colors hover:bg-secondary focus:outline-none focus:ring-1 focus:ring-ring disabled:pointer-events-none disabled:opacity-50 group-[.destructive]:border-muted/40 group-[.destructive]:hover:border-destructive/30 group-[.destructive]:hover:bg-destructive group-[.destructive]:hover:text-destructive-foreground group-[.destructive]:focus:ring-destructive",l),...i}));_4.displayName=kg.displayName;const lv=m.forwardRef(({className:l,...i},r)=>e.jsx(Tg,{ref:r,className:H("absolute right-1 top-1 rounded-md p-1 text-foreground/50 opacity-0 transition-opacity hover:text-foreground focus:opacity-100 focus:outline-none focus:ring-1 group-hover:opacity-100 group-[.destructive]:text-red-300 group-[.destructive]:hover:text-red-50 group-[.destructive]:focus:ring-red-400 group-[.destructive]:focus:ring-offset-red-600",l),"toast-close":"",...i,children:e.jsx(fl,{className:"h-4 w-4"})}));lv.displayName=Tg.displayName;const nv=m.forwardRef(({className:l,...i},r)=>e.jsx(Eg,{ref:r,className:H("text-sm font-semibold [&+div]:text-xs",l),...i}));nv.displayName=Eg.displayName;const iv=m.forwardRef(({className:l,...i},r)=>e.jsx(zg,{ref:r,className:H("text-sm opacity-90",l),...i}));iv.displayName=zg.displayName;function S4(){const{toasts:l}=Ks();return e.jsxs(y4,{children:[l.map(function({id:i,title:r,description:o,action:u,...x}){return e.jsxs(av,{...x,children:[e.jsxs("div",{className:"grid gap-1",children:[r&&e.jsx(nv,{children:r}),o&&e.jsx(iv,{children:o})]}),u,e.jsx(lv,{})]},i)}),e.jsx(tv,{})]})}L0.createRoot(document.getElementById("root")).render(e.jsx(m.StrictMode,{children:e.jsx(XS,{children:e.jsx(b4,{defaultTheme:"system",children:e.jsx(N4,{children:e.jsxs(C1,{children:[e.jsx(_N,{router:v4}),e.jsx(E1,{}),e.jsx(S4,{})]})})})})})); diff --git a/webui/dist/index.html b/webui/dist/index.html index 19c6ed26..2dfa1343 100644 --- a/webui/dist/index.html +++ b/webui/dist/index.html @@ -4,24 +4,28 @@ + + + + MaiBot Dashboard - + - + + - - +